mirror of
https://github.com/Oarcinae/FactorioScenarioMultiplayerSpawn.git
synced 2025-01-30 03:38:00 +02:00
Switching over to general utility repo
This commit is contained in:
parent
8c221f67bf
commit
92b349c9be
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
[submodule "oarc_utils"]
|
||||
path = locale
|
||||
url = https://github.com/Oarcinae/FactorioUtils
|
665
bps.lua
665
bps.lua
@ -1,665 +0,0 @@
|
||||
-- bps.lua
|
||||
-- Nov 2016
|
||||
|
||||
-- Modified by Oarc . Taken from 3Ra with permission.
|
||||
|
||||
-- Blueprint String
|
||||
-- A 3Ra Gaming revision
|
||||
-- Original Author: DaveMcW
|
||||
|
||||
local BlueprintString = require "locale/blueprintstring/blueprintstring"
|
||||
BlueprintString.COMPRESS_STRINGS = true
|
||||
BlueprintString.LINE_LENGTH = 120
|
||||
|
||||
-- Initialise player GUI
|
||||
-- @param player
|
||||
local function init_gui(player)
|
||||
if (not player.force.technologies["automated-construction"].researched) then
|
||||
return
|
||||
end
|
||||
|
||||
if (not player.gui.top["blueprint-string-button"]) then
|
||||
player.gui.top.add { type = "button", name = "blueprint-string-button", caption = "BPS" }
|
||||
end
|
||||
end
|
||||
|
||||
-- Initialise map
|
||||
function bps_init()
|
||||
for _, player in pairs(game.players) do
|
||||
init_gui(player)
|
||||
end
|
||||
end
|
||||
|
||||
-- Initialise player
|
||||
-- @param event on_player_joined event
|
||||
function bps_player_joined(event)
|
||||
init_gui(game.players[event.player_index])
|
||||
end
|
||||
|
||||
-- Handle research completion
|
||||
-- @param event on_research_finished event
|
||||
function bps_on_research_finished(event)
|
||||
if (event.research.name == "automated-construction") then
|
||||
for _, player in pairs(game.players) do
|
||||
if (event.research.force.name == player.force.name) then
|
||||
init_gui(player)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Expand player's gui
|
||||
-- @param player target player
|
||||
local function expand_gui(player)
|
||||
local frame = player.gui.left["blueprint-string"]
|
||||
if (frame) then
|
||||
frame.destroy()
|
||||
else
|
||||
frame = player.gui.left.add { type = "frame", name = "blueprint-string" }
|
||||
frame.add { type = "label", caption = { "textbox-caption" } }
|
||||
frame.add { type = "textfield", name = "blueprint-string-text" }
|
||||
frame.add { type = "button", name = "blueprint-string-load", caption = "Load" }
|
||||
frame.add { type = "button", name = "blueprint-string-save", caption = "Save" }
|
||||
frame.add { type = "button", name = "blueprint-string-save-all", caption = "Save All" }
|
||||
frame.add { type = "button", name = "blueprint-string-upgrade", caption = "Upgrade" }
|
||||
end
|
||||
end
|
||||
|
||||
-- Trim string of whitespace
|
||||
-- @param s string
|
||||
-- @return trimmed string
|
||||
local function trim(s)
|
||||
return (s:gsub("^%s*(.-)%s*$", "%1"))
|
||||
end
|
||||
|
||||
-- Get the amount of a certain item type in an inventory
|
||||
-- @param inventory inventory to filter
|
||||
-- @param type type of item to filter
|
||||
-- @return array of items
|
||||
local function filter(inventory, type)
|
||||
local stacks = {}
|
||||
if (inventory) then
|
||||
for i = 1, #inventory do
|
||||
if (inventory[i].valid_for_read and inventory[i].type == type) then
|
||||
stacks[i] = inventory[i]
|
||||
end
|
||||
end
|
||||
end
|
||||
return stacks
|
||||
end
|
||||
|
||||
-- Return the blueprints inside a book
|
||||
-- @param book blueprint book item
|
||||
-- @return array of blueprints
|
||||
local function book_inventory(book)
|
||||
local blueprints = {}
|
||||
local active = book.get_inventory(defines.inventory.item_active)
|
||||
local main = book.get_inventory(defines.inventory.item_main)
|
||||
|
||||
if (active[1].valid_for_read and active[1].type == "blueprint") then
|
||||
blueprints[1] = active[1]
|
||||
end
|
||||
|
||||
for i = 1, #main do
|
||||
if (main[i].valid_for_read and main[i].type == "blueprint") then
|
||||
blueprints[i + 1] = main[i]
|
||||
end
|
||||
end
|
||||
|
||||
return blueprints
|
||||
end
|
||||
|
||||
-- Check if the player is holding a blueprint
|
||||
-- @param player target player
|
||||
-- @return bool player is holding blueprint
|
||||
local function holding_blueprint(player)
|
||||
return (player.cursor_stack.valid_for_read and player.cursor_stack.type == "blueprint")
|
||||
end
|
||||
|
||||
-- Check if the blueprint being held is empty
|
||||
-- @param player target player
|
||||
-- @return bool blueprint is not empty
|
||||
local function holding_valid_blueprint(player)
|
||||
return (holding_blueprint(player) and player.cursor_stack.is_blueprint_setup())
|
||||
end
|
||||
|
||||
-- Check if the player is holding a blueprint book
|
||||
-- @param player target player
|
||||
-- @return bool player is holding book
|
||||
local function holding_book(player)
|
||||
return (player.cursor_stack.valid_for_read and player.cursor_stack.type == "blueprint-book")
|
||||
end
|
||||
|
||||
-- Find a player's empty blueprint or craft one if unavailable
|
||||
-- @param player target player
|
||||
-- @param no_crafting if true then a blueprint will not be crafted, even if one is unavailable
|
||||
-- @return empty blueprint
|
||||
local function find_empty_blueprint(player, no_crafting)
|
||||
if (holding_blueprint(player)) then
|
||||
if (player.cursor_stack.is_blueprint_setup()) then
|
||||
player.cursor_stack.set_blueprint_entities(nil)
|
||||
player.cursor_stack.set_blueprint_tiles(nil)
|
||||
player.cursor_stack.label = ""
|
||||
end
|
||||
return player.cursor_stack
|
||||
end
|
||||
|
||||
local main = player.get_inventory(defines.inventory.player_main)
|
||||
local quickbar = player.get_inventory(defines.inventory.player_quickbar)
|
||||
|
||||
local stacks = filter(quickbar, "blueprint")
|
||||
for i, stack in pairs(filter(main, "blueprint")) do
|
||||
stacks[#quickbar + i] = stack
|
||||
end
|
||||
for _, stack in pairs(stacks) do
|
||||
if (not stack.is_blueprint_setup()) then
|
||||
return stack
|
||||
end
|
||||
end
|
||||
|
||||
if (no_crafting) then
|
||||
return nil
|
||||
end
|
||||
|
||||
-- Craft a new blueprint
|
||||
if (player.can_insert("blueprint") and player.get_item_count("advanced-circuit") >= 1) then
|
||||
player.remove_item { name = "advanced-circuit", count = 1 }
|
||||
if (player.insert("blueprint") == 1) then
|
||||
return find_empty_blueprint(player, true)
|
||||
end
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
-- Find an empty book, or craft one if unavailable
|
||||
-- @param player target player
|
||||
-- @param slots number of slots needed
|
||||
-- @param no_crafting bool to allow crafting or not
|
||||
-- @return empty blueprint book
|
||||
local function find_empty_book(player, slots, no_crafting)
|
||||
if (holding_book(player)) then
|
||||
for _, page in pairs(book_inventory(player.cursor_stack)) do
|
||||
if (page.is_blueprint_setup()) then
|
||||
page.set_blueprint_entities(nil)
|
||||
page.set_blueprint_tiles(nil)
|
||||
page.label = ""
|
||||
end
|
||||
end
|
||||
return player.cursor_stack
|
||||
end
|
||||
|
||||
local advanced_circuits = player.get_item_count("advanced-circuit")
|
||||
local main = player.get_inventory(defines.inventory.player_main)
|
||||
local quickbar = player.get_inventory(defines.inventory.player_quickbar)
|
||||
local first_empty_book = nil
|
||||
local books = filter(quickbar, "blueprint-book")
|
||||
for i, book in pairs(filter(main, "blueprint-book")) do
|
||||
books[#quickbar + i] = book
|
||||
end
|
||||
for _, book in pairs(books) do
|
||||
local empty = true
|
||||
local pages = 0
|
||||
for _, page in pairs(book_inventory(book)) do
|
||||
if (page.is_blueprint_setup()) then
|
||||
empty = false
|
||||
end
|
||||
pages = pages + 1
|
||||
end
|
||||
if (empty) then
|
||||
if (slots <= pages + advanced_circuits) then
|
||||
return book
|
||||
end
|
||||
if (not first_empty_book) then
|
||||
first_empty_book = book
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if (first_empty_book) then
|
||||
-- We can't afford to craft all the blueprints, but at least we have an empty book
|
||||
return first_empty_book
|
||||
end
|
||||
|
||||
if (no_crafting) then
|
||||
return nil
|
||||
end
|
||||
|
||||
-- Craft a new book
|
||||
if (player.can_insert("blueprint-book") and advanced_circuits >= 15 + slots) then
|
||||
player.remove_item { name = "advanced-circuit", count = 15 }
|
||||
if (player.insert("blueprint-book") == 1) then
|
||||
return find_empty_book(player, slots, true)
|
||||
end
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
-- Convert string into blueprint
|
||||
-- @param blueprint empty blueprint that the data will be loaded into
|
||||
-- @param data blueprint data
|
||||
-- @return error if one occurred
|
||||
local function load_blueprint_data(blueprint, data)
|
||||
if (not data.icons or type(data.icons) ~= "table" or #data.icons < 1) then
|
||||
return { "unknown-format" }
|
||||
end
|
||||
|
||||
status, result = pcall(blueprint.set_blueprint_entities, data.entities)
|
||||
if (not status) then
|
||||
blueprint.set_blueprint_entities(nil)
|
||||
return { "blueprint-api-error", result }
|
||||
end
|
||||
|
||||
status, result = pcall(blueprint.set_blueprint_tiles, data.tiles)
|
||||
if (not status) then
|
||||
blueprint.set_blueprint_entities(nil)
|
||||
blueprint.set_blueprint_tiles(nil)
|
||||
return { "blueprint-api-error", result }
|
||||
end
|
||||
|
||||
if (blueprint.is_blueprint_setup()) then
|
||||
status, result = pcall(function() blueprint.blueprint_icons = data.icons end)
|
||||
if (not status) then
|
||||
blueprint.set_blueprint_entities(nil)
|
||||
blueprint.set_blueprint_tiles(nil)
|
||||
return { "blueprint-icon-error", result }
|
||||
end
|
||||
end
|
||||
|
||||
blueprint.label = data.name or ""
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
-- Call the required local functions to load a blueprint
|
||||
-- @param player player that is loading the blueprint
|
||||
local function load_blueprint(player)
|
||||
local textbox = player.gui.left["blueprint-string"]["blueprint-string-text"]
|
||||
local data = trim(textbox.text)
|
||||
if (data == "") then
|
||||
player.print({ "no-string" })
|
||||
return
|
||||
end
|
||||
|
||||
local blueprint_format = BlueprintString.fromString(data)
|
||||
if (not blueprint_format or type(blueprint_format) ~= "table") then
|
||||
textbox.text = ""
|
||||
player.print({ "unknown-format" })
|
||||
return
|
||||
end
|
||||
|
||||
local blueprint = nil
|
||||
local book = nil
|
||||
local active = nil
|
||||
local main = nil
|
||||
if (not blueprint_format.book) then
|
||||
-- Blueprint
|
||||
if (holding_book(player)) then
|
||||
player.print({ "need-blueprint" })
|
||||
return
|
||||
end
|
||||
|
||||
blueprint = find_empty_blueprint(player)
|
||||
if (not blueprint) then
|
||||
player.print({ "no-empty-blueprint" })
|
||||
return
|
||||
end
|
||||
else
|
||||
-- Blueprint Book
|
||||
if (type(blueprint_format.book) ~= "table") then
|
||||
textbox.text = ""
|
||||
player.print({ "unknown-format" })
|
||||
return
|
||||
end
|
||||
|
||||
if (holding_blueprint(player)) then
|
||||
player.print({ "need-blueprint-book" })
|
||||
return
|
||||
end
|
||||
|
||||
local page_count = 0
|
||||
for _, page in pairs(blueprint_format.book) do
|
||||
page_count = page_count + 1
|
||||
end
|
||||
if (page_count < 1) then
|
||||
textbox.text = ""
|
||||
player.print({ "unknown-format" })
|
||||
return
|
||||
end
|
||||
|
||||
local slots = math.min(page_count, game.item_prototypes["blueprint-book"].inventory_size + 1)
|
||||
book = find_empty_book(player, slots)
|
||||
if (not book) then
|
||||
player.print({ "no-empty-blueprint" })
|
||||
return
|
||||
end
|
||||
|
||||
active = book.get_inventory(defines.inventory.item_active)
|
||||
main = book.get_inventory(defines.inventory.item_main)
|
||||
|
||||
local advanced_circuits = slots - active.get_item_count("blueprint") - main.get_item_count("blueprint")
|
||||
if (advanced_circuits > player.get_item_count("advanced-circuit")) then
|
||||
player.print({ "need-advanced-circuit", advanced_circuits })
|
||||
return
|
||||
end
|
||||
|
||||
if (advanced_circuits > 0) then
|
||||
player.remove_item { name = "advanced-circuit", count = advanced_circuits }
|
||||
end
|
||||
|
||||
-- Create the required blueprints
|
||||
if (blueprint_format.book[1]) then
|
||||
active[1].set_stack("blueprint")
|
||||
else
|
||||
active[1].clear()
|
||||
end
|
||||
for i = 1, #main do
|
||||
if (blueprint_format.book[i + 1]) then
|
||||
main[i].set_stack("blueprint")
|
||||
else
|
||||
main[i].clear()
|
||||
end
|
||||
end
|
||||
|
||||
-- If we have extra blueprints, put them back in
|
||||
local extra_blueprints = -advanced_circuits
|
||||
if (extra_blueprints > 0 and not active[1].valid_for_read) then
|
||||
active[1].set_stack("blueprint")
|
||||
extra_blueprints = extra_blueprints - 1
|
||||
end
|
||||
for i = 1, #main do
|
||||
if (extra_blueprints > 0 and not main[i].valid_for_read) then
|
||||
main[i].set_stack("blueprint")
|
||||
extra_blueprints = extra_blueprints - 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
textbox.text = ""
|
||||
|
||||
-- Blueprint
|
||||
if (not book) then
|
||||
local error = load_blueprint_data(blueprint, blueprint_format)
|
||||
if (error) then
|
||||
player.print(error)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
-- Blueprint Book
|
||||
if (blueprint_format.book[1]) then
|
||||
local error = load_blueprint_data(active[1], blueprint_format.book[1])
|
||||
if (error and error[1] ~= "unknown-format") then
|
||||
player.print(error)
|
||||
end
|
||||
end
|
||||
for i = 1, #main do
|
||||
if (blueprint_format.book[i + 1]) then
|
||||
local error = load_blueprint_data(main[i], blueprint_format.book[i + 1])
|
||||
if (error and error[1] ~= "unknown-format") then
|
||||
player.print(error)
|
||||
end
|
||||
end
|
||||
end
|
||||
book.label = blueprint_format.name or ""
|
||||
end
|
||||
|
||||
local duplicate_filenames
|
||||
-- Fix incorrect file name
|
||||
local function fix_filename(player, filename)
|
||||
if (#game.players > 1 and player.name and player.name ~= "") then
|
||||
local name = player.name
|
||||
filename = name .. "-" .. filename
|
||||
end
|
||||
|
||||
filename = filename:gsub("[/\\:*?\"<>|]", "_")
|
||||
|
||||
local lowercase = filename:lower()
|
||||
if (duplicate_filenames[lowercase]) then
|
||||
duplicate_filenames[lowercase] = duplicate_filenames[lowercase] + 1
|
||||
filename = filename .. "-" .. duplicate_filenames[lowercase]
|
||||
else
|
||||
duplicate_filenames[lowercase] = 1
|
||||
end
|
||||
|
||||
return filename
|
||||
end
|
||||
|
||||
local blueprints_saved
|
||||
-- Save blueprint as file
|
||||
local function blueprint_to_file(player, stack, filename)
|
||||
local blueprint_format = {
|
||||
entities = stack.get_blueprint_entities(),
|
||||
tiles = stack.get_blueprint_tiles(),
|
||||
icons = stack.blueprint_icons,
|
||||
name = stack.label,
|
||||
}
|
||||
|
||||
local data = BlueprintString.toString(blueprint_format)
|
||||
filename = fix_filename(player, filename)
|
||||
game.write_file("blueprint-string/" .. filename .. ".txt", data, false, player.index)
|
||||
blueprints_saved = blueprints_saved + 1
|
||||
end
|
||||
|
||||
-- Save blueprint book as file
|
||||
local function book_to_file(player, book, filename)
|
||||
local blueprint_format = { book = {} }
|
||||
|
||||
for position, stack in pairs(book_inventory(book)) do
|
||||
if (stack.is_blueprint_setup()) then
|
||||
blueprint_format.book[position] = {
|
||||
entities = stack.get_blueprint_entities(),
|
||||
tiles = stack.get_blueprint_tiles(),
|
||||
icons = stack.blueprint_icons,
|
||||
name = stack.label,
|
||||
}
|
||||
end
|
||||
end
|
||||
if (book.label) then
|
||||
blueprint_format.name = book.label
|
||||
end
|
||||
|
||||
local data = BlueprintString.toString(blueprint_format)
|
||||
filename = fix_filename(player, filename)
|
||||
game.write_file("blueprint-string/" .. filename .. ".txt", data, false, player.index)
|
||||
blueprints_saved = blueprints_saved + 1
|
||||
end
|
||||
|
||||
local function save_blueprint_as(player, filename)
|
||||
blueprints_saved = 0
|
||||
duplicate_filenames = {}
|
||||
|
||||
if (not holding_valid_blueprint(player) and not holding_book(player)) then
|
||||
player.print({ "no-blueprint-in-hand" })
|
||||
return
|
||||
end
|
||||
|
||||
if (not filename or filename == "") then
|
||||
player.print({ "no-filename" })
|
||||
return
|
||||
end
|
||||
|
||||
filename = filename:sub(1, 100)
|
||||
|
||||
if (player.cursor_stack.type == "blueprint") then
|
||||
blueprint_to_file(player, player.cursor_stack, filename)
|
||||
elseif (player.cursor_stack.type == "blueprint-book") then
|
||||
book_to_file(player, player.cursor_stack, filename)
|
||||
end
|
||||
|
||||
local prompt = player.gui.center["blueprint-string-filename-prompt"]
|
||||
if (prompt) then prompt.destroy() end
|
||||
|
||||
if (blueprints_saved > 0) then
|
||||
player.print({ "blueprint-saved-as", filename })
|
||||
else
|
||||
player.print({ "blueprints-not-saved" })
|
||||
end
|
||||
end
|
||||
|
||||
local function save_blueprint(player)
|
||||
if (not holding_valid_blueprint(player) and not holding_book(player)) then
|
||||
player.print({ "no-blueprint-in-hand" })
|
||||
return
|
||||
end
|
||||
|
||||
if (player.cursor_stack.label) then
|
||||
save_blueprint_as(player, player.cursor_stack.label)
|
||||
else
|
||||
bps_prompt_for_filename(player)
|
||||
end
|
||||
end
|
||||
|
||||
local function save_all(player)
|
||||
blueprints_saved = 0
|
||||
duplicate_filenames = {}
|
||||
|
||||
local main = player.get_inventory(defines.inventory.player_main)
|
||||
local quickbar = player.get_inventory(defines.inventory.player_quickbar)
|
||||
|
||||
for position, stack in pairs(filter(quickbar, "blueprint")) do
|
||||
if (stack.is_blueprint_setup()) then
|
||||
local filename = "toolbar-" .. position
|
||||
if (stack.label) then
|
||||
filename = stack.label
|
||||
end
|
||||
blueprint_to_file(player, stack, filename)
|
||||
end
|
||||
end
|
||||
|
||||
for position, stack in pairs(filter(main, "blueprint")) do
|
||||
if (stack.is_blueprint_setup()) then
|
||||
local filename = "inventory-" .. position
|
||||
if (stack.label) then
|
||||
filename = stack.label
|
||||
end
|
||||
blueprint_to_file(player, stack, filename)
|
||||
end
|
||||
end
|
||||
|
||||
for position, stack in pairs(filter(quickbar, "blueprint-book")) do
|
||||
local filename = "toolbar-" .. position
|
||||
if (stack.label) then
|
||||
filename = stack.label
|
||||
end
|
||||
book_to_file(player, stack, filename)
|
||||
end
|
||||
|
||||
for position, stack in pairs(filter(main, "blueprint-book")) do
|
||||
local filename = "inventory-" .. position
|
||||
if (stack.label) then
|
||||
filename = stack.label
|
||||
end
|
||||
book_to_file(player, stack, filename)
|
||||
end
|
||||
|
||||
if (blueprints_saved > 0) then
|
||||
player.print({ "blueprints-saved", blueprints_saved })
|
||||
else
|
||||
player.print({ "blueprints-not-saved" })
|
||||
end
|
||||
end
|
||||
|
||||
function bps_prompt_for_filename(player)
|
||||
local frame = player.gui.center["blueprint-string-filename-prompt"]
|
||||
if (frame) then
|
||||
frame.destroy()
|
||||
end
|
||||
|
||||
frame = player.gui.center.add { type = "frame", direction = "vertical", name = "blueprint-string-filename-prompt" }
|
||||
local line1 = frame.add { type = "flow", direction = "horizontal" }
|
||||
line1.add { type = "label", caption = { "save-as" } }
|
||||
frame.add { type = "textfield", name = "blueprint-string-filename" }
|
||||
local line2 = frame.add { type = "flow", direction = "horizontal" }
|
||||
line2.add { type = "button", name = "blueprint-string-filename-save", caption = { "save" }, font_color = white }
|
||||
line2.add { type = "button", name = "blueprint-string-filename-cancel", caption = { "cancel" }, font_color = white }
|
||||
end
|
||||
|
||||
-- Check a blueprint for a certain entity
|
||||
-- @param blueprint blueprint to check
|
||||
-- @param entities array of entities to check
|
||||
-- @return bool blueprint contains entity
|
||||
local function contains_entities(blueprint, entities)
|
||||
if not blueprint.entities then
|
||||
return false
|
||||
end
|
||||
|
||||
for _, e in pairs(blueprint.entities) do
|
||||
if entities[e.name] then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
local function upgrade_blueprint(player)
|
||||
if (not holding_valid_blueprint(player)) then
|
||||
player.print({ "no-blueprint-in-hand" })
|
||||
return
|
||||
end
|
||||
local entities = player.cursor_stack.get_blueprint_entities()
|
||||
local tiles = player.cursor_stack.get_blueprint_tiles()
|
||||
|
||||
local offset = { x = -0.5, y = -0.5 }
|
||||
local rail_entities = {}
|
||||
rail_entities["straight-rail"] = true
|
||||
rail_entities["curved-rail"] = true
|
||||
rail_entities["rail-signal"] = true
|
||||
rail_entities["rail-chain-signal"] = true
|
||||
rail_entities["train-stop"] = true
|
||||
rail_entities["smart-train-stop"] = true
|
||||
if contains_entities(entities, rail_entities) then
|
||||
offset = { x = -1, y = -1 }
|
||||
end
|
||||
|
||||
if (entities) then
|
||||
for _, entity in pairs(entities) do
|
||||
entity.position = { x = entity.position.x + offset.x, y = entity.position.y + offset.y }
|
||||
end
|
||||
player.cursor_stack.set_blueprint_entities(entities)
|
||||
end
|
||||
if (tiles) then
|
||||
for _, entity in pairs(tiles) do
|
||||
tile.position = { x = tile.position.x + offset.x, y = tile.position.y + offset.y }
|
||||
end
|
||||
player.cursor_stack.set_blueprint_tiles(tiles)
|
||||
end
|
||||
end
|
||||
|
||||
-- Handle GUI click
|
||||
function bps_on_gui_click(event)
|
||||
if not (event and event.element and event.element.valid) then return end
|
||||
local player = game.players[event.element.player_index]
|
||||
local name = event.element.name
|
||||
if (name == "blueprint-string-load") then
|
||||
load_blueprint(player)
|
||||
elseif (name == "blueprint-string-save-all") then
|
||||
save_all(player)
|
||||
elseif (name == "blueprint-string-save") then
|
||||
save_blueprint(player)
|
||||
elseif (name == "blueprint-string-filename-save") then
|
||||
save_blueprint_as(player, player.gui.center["blueprint-string-filename-prompt"]["blueprint-string-filename"].text)
|
||||
elseif (name == "blueprint-string-filename-cancel") then
|
||||
player.gui.center["blueprint-string-filename-prompt"].destroy()
|
||||
elseif (name == "blueprint-string-button") then
|
||||
expand_gui(player)
|
||||
elseif (name == "blueprint-string-upgrade") then
|
||||
upgrade_blueprint(player)
|
||||
end
|
||||
end
|
||||
|
||||
function bps_on_robot_built_entity(event)
|
||||
local entity = event.created_entity
|
||||
if (entity and entity.type == "assembling-machine" and entity.recipe and not entity.recipe.enabled) then
|
||||
entity.recipe = nil
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- Event.register(-1, bps_init)
|
||||
-- Event.register(defines.events.on_player_created, player_joined)
|
||||
-- Event.register(defines.events.on_research_finished, on_research_finished)
|
||||
-- Event.register(defines.events.on_gui_click, on_gui_click)
|
||||
-- Event.register(defines.events.on_robot_built_entity, on_robot_built_entity)
|
20
control.lua
20
control.lua
@ -24,17 +24,19 @@
|
||||
-- 3. Put mods into their own files where possible (RSO has multiple)
|
||||
|
||||
|
||||
-- My Scenario Includes
|
||||
require("oarc_utils")
|
||||
-- Generic Utility Includes
|
||||
require("locale/oarc_utils")
|
||||
require("locale/rso/rso_control")
|
||||
require("locale/frontier_silo")
|
||||
require("locale/tag")
|
||||
require("locale/bps")
|
||||
|
||||
-- Main Configuration File
|
||||
require("config")
|
||||
|
||||
-- Include Mods
|
||||
-- Scenario Specific Includes
|
||||
require("separate_spawns")
|
||||
require("separate_spawns_guis")
|
||||
require("rso_control")
|
||||
require("frontier_silo")
|
||||
require("tag")
|
||||
require("bps")
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
@ -177,10 +179,6 @@ script.on_event(defines.events.on_player_joined_game, function(event)
|
||||
end)
|
||||
|
||||
script.on_event(defines.events.on_player_created, function(event)
|
||||
if ENABLE_RSO then
|
||||
RSO_PlayerCreated(event)
|
||||
end
|
||||
|
||||
if ENABLE_LONGREACH then
|
||||
GivePlayerLongReach(game.players[event.player_index])
|
||||
end
|
||||
|
@ -1,79 +0,0 @@
|
||||
-- frontier_silo.lua
|
||||
-- Nov 2016
|
||||
|
||||
require("config")
|
||||
require("oarc_utils")
|
||||
|
||||
-- Create a rocket silo
|
||||
local function CreateRocketSilo(surface, chunkArea)
|
||||
if CheckIfInArea(global.siloPosition, chunkArea) then
|
||||
|
||||
-- Delete any entities beneat the silo?
|
||||
for _, entity in pairs(surface.find_entities_filtered{area = {{global.siloPosition.x-5, global.siloPosition.y-6},{global.siloPosition.x+6, global.siloPosition.y+6}}}) do
|
||||
entity.destroy()
|
||||
end
|
||||
|
||||
-- Set tiles below the silo
|
||||
local tiles = {}
|
||||
local i = 1
|
||||
for dx = -6,6 do
|
||||
for dy = -7,6 do
|
||||
tiles[i] = {name = "grass", position = {global.siloPosition.x+dx, global.siloPosition.y+dy}}
|
||||
i=i+1
|
||||
end
|
||||
end
|
||||
surface.set_tiles(tiles, false)
|
||||
tiles = {}
|
||||
i = 1
|
||||
for dx = -5,5 do
|
||||
for dy = -6,5 do
|
||||
tiles[i] = {name = "concrete", position = {global.siloPosition.x+dx, global.siloPosition.y+dy}}
|
||||
i=i+1
|
||||
end
|
||||
end
|
||||
surface.set_tiles(tiles, true)
|
||||
|
||||
-- Create silo and assign to main force
|
||||
local silo = surface.create_entity{name = "rocket-silo", position = {global.siloPosition.x+0.5, global.siloPosition.y}, force = MAIN_FORCE}
|
||||
silo.destructible = false
|
||||
silo.minable = false
|
||||
end
|
||||
end
|
||||
|
||||
-- Remove rocket silo from recipes
|
||||
function RemoveRocketSiloRecipe(event)
|
||||
RemoveRecipe(event, "rocket-silo")
|
||||
end
|
||||
|
||||
-- Generates the rocket silo during chunk generation event
|
||||
-- Includes a crop circle
|
||||
function GenerateRocketSiloChunk(event)
|
||||
local surface = event.surface
|
||||
if surface.name ~= "nauvis" then return end
|
||||
local chunkArea = event.area
|
||||
|
||||
local chunkAreaCenter = {x=chunkArea.left_top.x+(CHUNK_SIZE/2),
|
||||
y=chunkArea.left_top.y+(CHUNK_SIZE/2)}
|
||||
local safeArea = {left_top=
|
||||
{x=global.siloPosition.x-150,
|
||||
y=global.siloPosition.y-150},
|
||||
right_bottom=
|
||||
{x=global.siloPosition.x+150,
|
||||
y=global.siloPosition.y+150}}
|
||||
|
||||
|
||||
-- Clear enemies directly next to the rocket
|
||||
if CheckIfInArea(chunkAreaCenter,safeArea) then
|
||||
for _, entity in pairs(surface.find_entities_filtered{area = chunkArea, force = "enemy"}) do
|
||||
entity.destroy()
|
||||
end
|
||||
end
|
||||
|
||||
-- Create rocket silo
|
||||
CreateRocketSilo(surface, chunkArea)
|
||||
CreateCropCircle(surface, global.siloPosition, chunkArea, 40)
|
||||
end
|
||||
|
||||
function ChartRocketSiloArea(force)
|
||||
force.chart(game.surfaces["nauvis"], {{global.siloPosition.x-(CHUNK_SIZE*2), global.siloPosition.y-(CHUNK_SIZE*2)}, {global.siloPosition.x+(CHUNK_SIZE*2), global.siloPosition.y+(CHUNK_SIZE*2)}})
|
||||
end
|
1
locale
Submodule
1
locale
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 7faacf8eca0d9e08184b5ceefa330d08289f78cb
|
626
oarc_utils.lua
626
oarc_utils.lua
@ -1,626 +0,0 @@
|
||||
-- oarc_utils.lua
|
||||
-- Nov 2016
|
||||
--
|
||||
-- My general purpose utility functions for factorio
|
||||
-- Also contains some constants and gui styles
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Useful constants
|
||||
--------------------------------------------------------------------------------
|
||||
CHUNK_SIZE = 32
|
||||
MAX_FORCES = 64
|
||||
TICKS_PER_SECOND = 60
|
||||
TICKS_PER_MINUTE = TICKS_PER_SECOND * 60
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- GUI Label Styles
|
||||
--------------------------------------------------------------------------------
|
||||
my_fixed_width_style = {
|
||||
minimal_width = 450,
|
||||
maximal_width = 450
|
||||
}
|
||||
my_label_style = {
|
||||
minimal_width = 450,
|
||||
maximal_width = 450,
|
||||
maximal_height = 10,
|
||||
font_color = {r=1,g=1,b=1}
|
||||
}
|
||||
my_note_style = {
|
||||
minimal_width = 450,
|
||||
maximal_height = 10,
|
||||
font = "default-small-semibold",
|
||||
font_color = {r=1,g=0.5,b=0.5}
|
||||
}
|
||||
my_warning_style = {
|
||||
minimal_width = 450,
|
||||
maximal_width = 450,
|
||||
maximal_height = 10,
|
||||
font_color = {r=1,g=0.1,b=0.1}
|
||||
}
|
||||
my_spacer_style = {
|
||||
minimal_width = 450,
|
||||
maximal_width = 450,
|
||||
minimal_height = 20,
|
||||
maximal_height = 20,
|
||||
font_color = {r=0,g=0,b=0}
|
||||
}
|
||||
my_small_button_style = {
|
||||
font = "default-small-semibold"
|
||||
}
|
||||
my_color_red = {r=1,g=0.1,b=0.1}
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- General Helper Functions
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
-- Print debug only to me while testing.
|
||||
-- Should remove this if you are hosting it yourself.
|
||||
function DebugPrint(msg)
|
||||
if ((game.players["Oarc"] ~= nil) and (global.oarcDebugEnabled)) then
|
||||
game.players["Oarc"].print("DEBUG: " .. msg)
|
||||
end
|
||||
end
|
||||
|
||||
-- Prints flying text.
|
||||
-- Color is optional
|
||||
function FlyingText(msg, pos, color)
|
||||
local surface = game.surfaces["nauvis"]
|
||||
if color == nil then
|
||||
surface.create_entity({ name = "flying-text", position = pos, text = msg })
|
||||
else
|
||||
surface.create_entity({ name = "flying-text", position = pos, text = msg, color = color })
|
||||
end
|
||||
end
|
||||
|
||||
-- Broadcast messages
|
||||
function SendBroadcastMsg(msg)
|
||||
for name,player in pairs(game.connected_players) do
|
||||
player.print(msg)
|
||||
end
|
||||
end
|
||||
|
||||
function formattime(ticks)
|
||||
local seconds = ticks / 60
|
||||
local minutes = math.floor((seconds)/60)
|
||||
local seconds = math.floor(seconds - 60*minutes)
|
||||
return string.format("%dm:%02ds", minutes, seconds)
|
||||
end
|
||||
|
||||
-- Simple function to get total number of items in table
|
||||
function TableLength(T)
|
||||
local count = 0
|
||||
for _ in pairs(T) do count = count + 1 end
|
||||
return count
|
||||
end
|
||||
|
||||
-- Chart area for a force
|
||||
function ChartArea(force, position, chunkDist)
|
||||
force.chart(game.surfaces["nauvis"],
|
||||
{{position.x-(CHUNK_SIZE*chunkDist),
|
||||
position.y-(CHUNK_SIZE*chunkDist)},
|
||||
{position.x+(CHUNK_SIZE*chunkDist),
|
||||
position.y+(CHUNK_SIZE*chunkDist)}})
|
||||
end
|
||||
|
||||
-- Give player these default items.
|
||||
function GivePlayerItems(player)
|
||||
player.insert{name="pistol", count=1}
|
||||
player.insert{name="firearm-magazine", count=100}
|
||||
end
|
||||
|
||||
-- Additional starter only items
|
||||
function GivePlayerStarterItems(player)
|
||||
GivePlayerItems(player)
|
||||
player.insert{name="iron-plate", count=8}
|
||||
player.insert{name="burner-mining-drill", count = 1}
|
||||
player.insert{name="stone-furnace", count = 1}
|
||||
end
|
||||
|
||||
-- Check if given position is in area bounding box
|
||||
function CheckIfInArea(point, area)
|
||||
if ((point.x > area.left_top.x) and (point.x < area.right_bottom.x)) then
|
||||
if ((point.y > area.left_top.y) and (point.y < area.right_bottom.y)) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
-- Ceasefire
|
||||
-- All forces are always neutral
|
||||
function SetCeaseFireBetweenAllForces()
|
||||
for name,team in pairs(game.forces) do
|
||||
if name ~= "neutral" and name ~= "enemy" then
|
||||
for x,y in pairs(game.forces) do
|
||||
if x ~= "neutral" and x ~= "enemy" then
|
||||
team.set_cease_fire(x,true)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Undecorator
|
||||
function RemoveDecorationsArea(surface, area)
|
||||
for _, entity in pairs(surface.find_entities_filtered{area = area, type="decorative"}) do
|
||||
entity.destroy()
|
||||
end
|
||||
end
|
||||
|
||||
-- Remove fish
|
||||
function RemoveFish(surface, area)
|
||||
for _, entity in pairs(surface.find_entities_filtered{area = area, type="fish"}) do
|
||||
entity.destroy()
|
||||
end
|
||||
end
|
||||
|
||||
-- Apply a style option to a GUI
|
||||
function ApplyStyle (guiIn, styleIn)
|
||||
for k,v in pairs(styleIn) do
|
||||
guiIn.style[k]=v
|
||||
end
|
||||
end
|
||||
|
||||
-- Get a random 1 or -1
|
||||
function RandomNegPos()
|
||||
if (math.random(0,1) == 1) then
|
||||
return 1
|
||||
else
|
||||
return -1
|
||||
end
|
||||
end
|
||||
|
||||
-- Create a random direction vector to look in
|
||||
function GetRandomVector()
|
||||
local randVec = {x=0,y=0}
|
||||
while ((randVec.x == 0) and (randVec.y == 0)) do
|
||||
randVec.x = math.random(-3,3)
|
||||
randVec.y = math.random(-3,3)
|
||||
end
|
||||
DebugPrint("direction: x=" .. randVec.x .. ", y=" .. randVec.y)
|
||||
return randVec
|
||||
end
|
||||
|
||||
-- Check for ungenerated chunks around a specific chunk
|
||||
-- +/- chunkDist in x and y directions
|
||||
function IsChunkAreaUngenerated(chunkPos, chunkDist)
|
||||
for x=-chunkDist, chunkDist do
|
||||
for y=-chunkDist, chunkDist do
|
||||
local checkPos = {x=chunkPos.x+x,
|
||||
y=chunkPos.y+y}
|
||||
if (game.surfaces["nauvis"].is_chunk_generated(checkPos)) then
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
-- Clear out enemies around an area with a certain distance
|
||||
function ClearNearbyEnemies(player, safeDist)
|
||||
local safeArea = {left_top=
|
||||
{x=player.position.x-safeDist,
|
||||
y=player.position.y-safeDist},
|
||||
right_bottom=
|
||||
{x=player.position.x+safeDist,
|
||||
y=player.position.y+safeDist}}
|
||||
|
||||
for _, entity in pairs(player.surface.find_entities_filtered{area = safeArea, force = "enemy"}) do
|
||||
entity.destroy()
|
||||
end
|
||||
end
|
||||
|
||||
-- Function to find coordinates of ungenerated map area in a given direction
|
||||
-- starting from the center of the map
|
||||
function FindMapEdge(directionVec)
|
||||
local position = {x=0,y=0}
|
||||
local chunkPos = {x=0,y=0}
|
||||
|
||||
-- Keep checking chunks in the direction of the vector
|
||||
while(true) do
|
||||
|
||||
-- Set some absolute limits.
|
||||
if ((math.abs(chunkPos.x) > 1000) or (math.abs(chunkPos.y) > 1000)) then
|
||||
break
|
||||
|
||||
-- If chunk is already generated, keep looking
|
||||
elseif (game.surfaces["nauvis"].is_chunk_generated(chunkPos)) then
|
||||
chunkPos.x = chunkPos.x + directionVec.x
|
||||
chunkPos.y = chunkPos.y + directionVec.y
|
||||
|
||||
-- Found a possible ungenerated area
|
||||
else
|
||||
|
||||
chunkPos.x = chunkPos.x + directionVec.x
|
||||
chunkPos.y = chunkPos.y + directionVec.y
|
||||
|
||||
-- Check there are no generated chunks in a 10x10 area.
|
||||
if IsChunkAreaUngenerated(chunkPos, 5) then
|
||||
position.x = (chunkPos.x*CHUNK_SIZE) + (CHUNK_SIZE/2)
|
||||
position.y = (chunkPos.y*CHUNK_SIZE) + (CHUNK_SIZE/2)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
DebugPrint("spawn: x=" .. position.x .. ", y=" .. position.y)
|
||||
return position
|
||||
end
|
||||
|
||||
-- Find random coordinates within a given distance away
|
||||
-- maxTries is the recursion limit basically.
|
||||
function FindUngeneratedCoordinates(minDistChunks, maxDistChunks)
|
||||
local position = {x=0,y=0}
|
||||
local chunkPos = {x=0,y=0}
|
||||
|
||||
local maxTries = 100
|
||||
local tryCounter = 0
|
||||
|
||||
local minDistSqr = minDistChunks^2
|
||||
local maxDistSqr = maxDistChunks^2
|
||||
|
||||
while(true) do
|
||||
chunkPos.x = math.random(0,maxDistChunks) * RandomNegPos()
|
||||
chunkPos.y = math.random(0,maxDistChunks) * RandomNegPos()
|
||||
|
||||
local distSqrd = chunkPos.x^2 + chunkPos.y^2
|
||||
|
||||
-- Enforce a max number of tries
|
||||
tryCounter = tryCounter + 1
|
||||
if (tryCounter > maxTries) then
|
||||
DebugPrint("FindUngeneratedCoordinates - Max Tries Hit!")
|
||||
break
|
||||
|
||||
-- Check that the distance is within the min,max specified
|
||||
elseif ((distSqrd < minDistSqr) or (distSqrd > maxDistSqr)) then
|
||||
-- Keep searching!
|
||||
|
||||
-- Check there are no generated chunks in a 10x10 area.
|
||||
elseif IsChunkAreaUngenerated(chunkPos, 5) then
|
||||
position.x = (chunkPos.x*CHUNK_SIZE) + (CHUNK_SIZE/2)
|
||||
position.y = (chunkPos.y*CHUNK_SIZE) + (CHUNK_SIZE/2)
|
||||
break -- SUCCESS
|
||||
end
|
||||
end
|
||||
|
||||
DebugPrint("spawn: x=" .. position.x .. ", y=" .. position.y)
|
||||
return position
|
||||
end
|
||||
|
||||
-- Return steel chest entity (or nil)
|
||||
function DropEmptySteelChest(player)
|
||||
local pos = player.surface.find_non_colliding_position("steel-chest", player.position, 15, 1)
|
||||
if not pos then
|
||||
return nil
|
||||
end
|
||||
local grave = player.surface.create_entity{name="steel-chest", position=pos, force="neutral"}
|
||||
return grave
|
||||
end
|
||||
|
||||
-- Gravestone soft mod. With my own modifications/improvements.
|
||||
function DropGravestoneChests(player)
|
||||
|
||||
local grave
|
||||
local count = 0
|
||||
|
||||
-- Use "game.player.cursorstack" to get items in player's hand.
|
||||
|
||||
-- Loop through a players different inventories
|
||||
-- Put it all into the chest
|
||||
-- If the chest is full, create a new chest.
|
||||
for i, id in ipairs{
|
||||
defines.inventory.player_armor,
|
||||
defines.inventory.player_main,
|
||||
defines.inventory.player_quickbar,
|
||||
defines.inventory.player_guns,
|
||||
defines.inventory.player_ammo,
|
||||
defines.inventory.player_tools,
|
||||
defines.inventory.player_trash} do
|
||||
local inv = player.get_inventory(id)
|
||||
if (not inv.is_empty()) then
|
||||
for j = 1, #inv do
|
||||
if inv[j].valid_for_read then
|
||||
|
||||
-- Create a chest when counter is reset
|
||||
if (count == 0) then
|
||||
grave = DropEmptySteelChest(player)
|
||||
if (grave == nil) then
|
||||
player.print("Not able to place a chest nearby! Some items lost!")
|
||||
return
|
||||
end
|
||||
grave_inv = grave.get_inventory(defines.inventory.chest)
|
||||
end
|
||||
count = count + 1
|
||||
|
||||
grave_inv[count].set_stack(inv[j])
|
||||
|
||||
-- Reset counter when chest is full
|
||||
if (count == #grave_inv) then
|
||||
count = 0
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if (grave ~= nil) then
|
||||
player.print("Successfully dropped your items into a chest! Go get them quick!")
|
||||
end
|
||||
end
|
||||
|
||||
-- Enforce a circle of land, also adds trees in a ring around the area.
|
||||
function CreateCropCircle(surface, centerPos, chunkArea, tileRadius)
|
||||
|
||||
local tileRadSqr = tileRadius^2
|
||||
|
||||
local dirtTiles = {}
|
||||
for i=chunkArea.left_top.x,chunkArea.right_bottom.x,1 do
|
||||
for j=chunkArea.left_top.y,chunkArea.right_bottom.y,1 do
|
||||
|
||||
-- This ( X^2 + Y^2 ) is used to calculate if something
|
||||
-- is inside a circle area.
|
||||
local distVar = math.floor((centerPos.x - i)^2 + (centerPos.y - j)^2)
|
||||
|
||||
-- Fill in all unexpected water in a circle
|
||||
if (distVar < tileRadSqr) then
|
||||
if (surface.get_tile(i,j).collides_with("water-tile") or ENABLE_SPAWN_FORCE_GRASS) then
|
||||
table.insert(dirtTiles, {name = "grass", position ={i,j}})
|
||||
end
|
||||
end
|
||||
|
||||
-- Create a circle of trees around the spawn point.
|
||||
if ((distVar < tileRadSqr-200) and
|
||||
(distVar > tileRadSqr-300)) then
|
||||
surface.create_entity({name="tree-01", amount=1, position={i, j}})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
surface.set_tiles(dirtTiles)
|
||||
end
|
||||
|
||||
-- COPIED FROM jvmguy!
|
||||
-- Enforce a square of land, with a tree border
|
||||
-- this is equivalent to the CreateCropCircle code
|
||||
function CreateCropOctagon(surface, centerPos, chunkArea, tileRadius)
|
||||
|
||||
local dirtTiles = {}
|
||||
for i=chunkArea.left_top.x,chunkArea.right_bottom.x,1 do
|
||||
for j=chunkArea.left_top.y,chunkArea.right_bottom.y,1 do
|
||||
|
||||
local distVar1 = math.floor(math.max(math.abs(centerPos.x - i), math.abs(centerPos.y - j)))
|
||||
local distVar2 = math.floor(math.abs(centerPos.x - i) + math.abs(centerPos.y - j))
|
||||
local distVar = math.max(distVar1, distVar2 * 0.707);
|
||||
|
||||
-- Fill in all unexpected water in a circle
|
||||
if (distVar < tileRadius+2) then
|
||||
if (surface.get_tile(i,j).collides_with("water-tile") or ENABLE_SPAWN_FORCE_GRASS) then
|
||||
table.insert(dirtTiles, {name = "grass", position ={i,j}})
|
||||
end
|
||||
end
|
||||
|
||||
-- Create a tree ring
|
||||
if ((distVar < tileRadius) and
|
||||
(distVar > tileRadius-2)) then
|
||||
surface.create_entity({name="tree-01", amount=1, position={i, j}})
|
||||
end
|
||||
end
|
||||
end surface.set_tiles(dirtTiles)
|
||||
end
|
||||
|
||||
function CreateWaterStrip(surface, leftPos, length)
|
||||
local waterTiles = {}
|
||||
for i=0,length,1 do
|
||||
table.insert(waterTiles, {name = "water", position={leftPos.x+i,leftPos.y}})
|
||||
end
|
||||
surface.set_tiles(waterTiles)
|
||||
end
|
||||
|
||||
|
||||
-- Adjust alien params
|
||||
function ConfigureAlienStartingParams()
|
||||
game.map_settings.enemy_evolution.time_factor=0
|
||||
game.map_settings.enemy_evolution.destroy_factor = game.map_settings.enemy_evolution.destroy_factor / ENEMY_DESTROY_FACTOR_DIVISOR
|
||||
game.map_settings.enemy_evolution.pollution_factor = game.map_settings.enemy_evolution.pollution_factor / ENEMY_POLLUTION_FACTOR_DIVISOR
|
||||
game.map_settings.enemy_expansion.enabled = ENEMY_EXPANSION
|
||||
end
|
||||
|
||||
-- Add Long Reach to Character
|
||||
function GivePlayerLongReach(player)
|
||||
player.character.character_build_distance_bonus = BUILD_DIST_BONUS
|
||||
player.character.character_reach_distance_bonus = REACH_DIST_BONUS
|
||||
-- player.character.character_resource_reach_distance_bonus = RESOURCE_DIST_BONUS
|
||||
end
|
||||
|
||||
|
||||
function SetRandomSiloPosition()
|
||||
if (global.siloPosition == nil) then
|
||||
-- Get an X,Y on a circle far away.
|
||||
distX = math.random(0,SILO_CHUNK_DISTANCE_X)
|
||||
distY = RandomNegPos() * math.floor(math.sqrt(SILO_CHUNK_DISTANCE_X^2 - distX^2))
|
||||
distX = RandomNegPos() * distX
|
||||
|
||||
-- Set those values.
|
||||
local siloX = distX*CHUNK_SIZE + CHUNK_SIZE/2
|
||||
local siloY = distY*CHUNK_SIZE + CHUNK_SIZE/2
|
||||
global.siloPosition = {x = siloX, y = siloY}
|
||||
end
|
||||
end
|
||||
|
||||
-- Use preset value
|
||||
function SetFixedSiloPosition()
|
||||
if (global.siloPosition == nil) then
|
||||
global.siloPosition = SILO_POSITION
|
||||
end
|
||||
end
|
||||
|
||||
-- Transfer Items Between Inventory
|
||||
-- Returns the number of items that were successfully transferred.
|
||||
-- Returns -1 if item not available.
|
||||
-- Returns -2 if can't place item into destInv (ERROR)
|
||||
function TransferItems(srcInv, destEntity, itemStack)
|
||||
-- Check if item is in srcInv
|
||||
if (srcInv.get_item_count(itemStack.name) == 0) then
|
||||
return -1
|
||||
end
|
||||
|
||||
-- Check if can insert into destInv
|
||||
if (not destEntity.can_insert(itemStack)) then
|
||||
return -2
|
||||
end
|
||||
|
||||
-- Insert items
|
||||
local itemsRemoved = srcInv.remove(itemStack)
|
||||
itemStack.count = itemsRemoved
|
||||
return destEntity.insert(itemStack)
|
||||
end
|
||||
|
||||
-- Attempts to transfer at least some of one type of item from an array of items.
|
||||
-- Use this to try transferring several items in order
|
||||
-- It returns once it successfully inserts at least some of one type.
|
||||
function TransferItemMultipleTypes(srcInv, destEntity, itemNameArray, itemCount)
|
||||
local ret = 0
|
||||
for _,itemName in pairs(itemNameArray) do
|
||||
ret = TransferItems(srcInv, destEntity, {name=itemName, count=itemCount})
|
||||
if (ret > 0) then
|
||||
return ret -- Return the value succesfully transferred
|
||||
end
|
||||
end
|
||||
return ret -- Return the last error code
|
||||
end
|
||||
|
||||
function AutofillTurret(player, turret)
|
||||
local mainInv = player.get_inventory(defines.inventory.player_main)
|
||||
|
||||
-- Attempt to transfer some ammo
|
||||
local ret = TransferItemMultipleTypes(mainInv, turret, {"piercing-rounds-magazine","firearm-magazine"}, AUTOFILL_TURRET_AMMO_QUANTITY)
|
||||
|
||||
-- Check the result and print the right text to inform the user what happened.
|
||||
if (ret > 0) then
|
||||
-- Inserted ammo successfully
|
||||
-- FlyingText("Inserted ammo x" .. ret, turret.position, my_color_red)
|
||||
elseif (ret == -1) then
|
||||
FlyingText("Out of ammo!", turret.position, my_color_red)
|
||||
elseif (ret == -2) then
|
||||
FlyingText("Autofill ERROR! - Report this bug!", turret.position, my_color_red)
|
||||
end
|
||||
end
|
||||
|
||||
function AutoFillVehicle(player, vehicle)
|
||||
local mainInv = player.get_inventory(defines.inventory.player_main)
|
||||
|
||||
-- Attempt to transfer some fuel
|
||||
if ((vehicle.name == "car") or (vehicle.name == "tank") or (vehicle.name == "diesel-locomotive")) then
|
||||
TransferItemMultipleTypes(mainInv, vehicle, {"raw-wood", "coal", "solid-fuel"}, 50)
|
||||
end
|
||||
|
||||
-- Attempt to transfer some ammo
|
||||
if ((vehicle.name == "car") or (vehicle.name == "tank")) then
|
||||
TransferItemMultipleTypes(mainInv, vehicle, {"piercing-rounds-magazine","firearm-magazine"}, 100)
|
||||
end
|
||||
|
||||
-- Attempt to transfer some tank shells
|
||||
if (vehicle.name == "tank") then
|
||||
TransferItemMultipleTypes(mainInv, vehicle, {"explosive-cannon-shell", "cannon-shell"}, 100)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- EVENT SPECIFIC FUNCTIONS
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
-- Display messages to a user everytime they join
|
||||
function PlayerJoinedMessages(event)
|
||||
local player = game.players[event.player_index]
|
||||
player.print(WELCOME_MSG)
|
||||
player.print(GAME_MODE_MSG)
|
||||
player.print(MODULES_ENABLED)
|
||||
end
|
||||
|
||||
-- Create the gravestone chests for a player when they die
|
||||
function CreateGravestoneChestsOnDeath(event)
|
||||
DropGravestoneChests(game.players[event.player_index])
|
||||
end
|
||||
|
||||
-- Remove decor to save on file size
|
||||
function UndecorateOnChunkGenerate(event)
|
||||
local surface = event.surface
|
||||
local chunkArea = event.area
|
||||
RemoveDecorationsArea(surface, chunkArea)
|
||||
RemoveFish(surface, chunkArea)
|
||||
end
|
||||
|
||||
-- Give player items on respawn
|
||||
-- Intended to be the default behavior when not using separate spawns
|
||||
function PlayerRespawnItems(event)
|
||||
GivePlayerItems(game.players[event.player_index])
|
||||
end
|
||||
|
||||
function PlayerSpawnItems(event)
|
||||
GivePlayerStarterItems(game.players[event.player_index])
|
||||
end
|
||||
|
||||
-- Autofill softmod
|
||||
function Autofill(event)
|
||||
local player = game.players[event.player_index]
|
||||
local eventEntity = event.created_entity
|
||||
|
||||
if (eventEntity.name == "gun-turret") then
|
||||
AutofillTurret(player, eventEntity)
|
||||
end
|
||||
|
||||
if ((eventEntity.name == "car") or (eventEntity.name == "tank") or (eventEntity.name == "diesel-locomotive")) then
|
||||
AutoFillVehicle(player, eventEntity)
|
||||
end
|
||||
end
|
||||
|
||||
-- General purpose event function for removing a particular recipe
|
||||
function RemoveRecipe(event, recipeName)
|
||||
local recipes = event.research.force.recipes
|
||||
if recipes[recipeName] then
|
||||
recipes[recipeName].enabled = false
|
||||
end
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- UNUSED CODE
|
||||
-- Either didn't work, or not used or not tested....
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
|
||||
-- THIS DOES NOT WORK IN SCENARIOS!
|
||||
-- function DisableVanillaResouresAndEnemies()
|
||||
|
||||
-- local map_gen_ctrls = game.surfaces["nauvis"].map_gen_settings.autoplace_controls
|
||||
|
||||
-- map_gen_ctrls["coal"].size = "none"
|
||||
-- map_gen_ctrls["stone"].size = "none"
|
||||
-- map_gen_ctrls["iron-ore"].size = "none"
|
||||
-- map_gen_ctrls["copper-ore"].size = "none"
|
||||
-- map_gen_ctrls["crude-oil"].size = "none"
|
||||
-- map_gen_ctrls["enemy-base"].size = "none"
|
||||
-- end
|
||||
|
||||
|
||||
|
||||
-- Shared vision for other forces? UNTESTED
|
||||
-- function ShareVisionForAllForces()
|
||||
-- for _,f in pairs(game.forces) do
|
||||
-- for _,p in pairs(game.connected_players) do
|
||||
-- if (f.name ~= p.force.name) then
|
||||
-- local visionArea = {left_top=
|
||||
-- {x=p.x-(CHUNK_SIZE*3),
|
||||
-- y=p.y-(CHUNK_SIZE*3)},
|
||||
-- right_bottom=
|
||||
-- {x=p.x+(CHUNK_SIZE*3),
|
||||
-- y=p.y+(CHUNK_SIZE*3)}}
|
||||
-- f.chart(game.surfaces["nauvis"], visionArea)
|
||||
-- end
|
||||
-- end
|
||||
-- end
|
||||
-- end
|
@ -1,52 +0,0 @@
|
||||
debug_enabled = false
|
||||
|
||||
region_size = 10 -- alternative mean to control how further away resources would be, default - 256 tiles or 8 chunks
|
||||
-- each region is region_size*region_size chunks
|
||||
-- each chunk is 32*32 tiles
|
||||
|
||||
use_donut_shapes = false -- setting this to false will remove donuts from possible resource layouts
|
||||
|
||||
starting_area_size = 0.8 -- starting area in regions, safe from random nonsense
|
||||
|
||||
absolute_resource_chance = 0.50 -- chance to spawn an resource in a region
|
||||
starting_richness_mult = 1 -- multiply starting area richness for resources
|
||||
global_richness_mult = 1 -- multiply richness for all resources except starting area
|
||||
global_size_mult = 1 -- multiply size for all ores, doesn't affect starting area
|
||||
|
||||
absolute_enemy_chance = 3 -- chance to spawn enemies per sector (can be more then one base if spawned)
|
||||
enemy_base_size_multiplier = 1 -- all base sizes will be multiplied by this - larger number means bigger bases
|
||||
|
||||
multi_resource_active = false -- global switch for multi resource chances
|
||||
multi_resource_richness_factor = 0.60 -- any additional resource is multiplied by this value times resources-1
|
||||
multi_resource_size_factor = 0.90
|
||||
multi_resource_chance_diminish = 0.6 -- diminishing effect factor on multi_resource_chance
|
||||
|
||||
min_amount=250 -- default value for minimum amount of resource in single pile
|
||||
|
||||
richness_distance_factor=0.9 -- exponent for richness distance factor calculation
|
||||
size_distance_factor=0.15 -- exponent for size distance factor calculation
|
||||
|
||||
deterministic = true -- set to false to use system for all decisions math.random
|
||||
|
||||
-- mode is no longer used by generation process - it autodetects endless resources
|
||||
-- endless_resource_mode = false -- if true, the size of each resource is modified by the following modifier. Use with the endless resources mod.
|
||||
endless_resource_mode_sizeModifier = 0.80
|
||||
|
||||
-- This setting isn't used anywhere in the soft mod version of RSO -- OARC
|
||||
-- Just set it from Oarc's config.lua (look for ENEMY_EXPANSION)
|
||||
-- disableEnemyExpansion = false -- allows for disabling of in-game biter base building
|
||||
|
||||
use_RSO_biter_spawning = true -- enables spawning of biters controlled by RSO mod - less enemies around with more space between bases
|
||||
use_vanilla_biter_spawning = false -- enables using of vanilla spawning
|
||||
|
||||
biter_ratio_segment=3 --the ratio components determining how many biters to spitters will be spawned
|
||||
spitter_ratio_segment=1 --eg. 1 and 1 -> equal number of biters and spitters, 10 and 1 -> 10 times as many biters to spitters
|
||||
|
||||
useEnemiesInPeaceMod = false -- additional override for peace mod detection - when set to true it will spawn enemies normally, needs to have enemies enabled in peace mod
|
||||
|
||||
-- Always leave this setting to true in this soft mod scenario version! -- OARC
|
||||
ignoreMapGenSettings = true -- stops the default behaviour of reading map gen settings
|
||||
|
||||
useResourceCollisionDetection = true -- enables avoidace calculations to reduce ores overlaping of each other
|
||||
resourceCollisionDetectionRatio = 0.8 -- at least this much of ore field needs to be placable to spawn it
|
||||
resourceCollisionFieldSkip = true -- determines if ore field should be skipped completely if placement based on ratio failed
|
1378
rso_control.lua
1378
rso_control.lua
File diff suppressed because it is too large
Load Diff
@ -1,159 +0,0 @@
|
||||
|
||||
local function fillVanillaConfig()
|
||||
|
||||
config["iron-ore"] = {
|
||||
type="resource-ore",
|
||||
|
||||
-- general spawn params
|
||||
allotment=100, -- how common resource is
|
||||
spawns_per_region={min=1, max=1}, --number of chunks
|
||||
richness=10000, -- resource_ore has only one richness value - resource-liquid has min/max
|
||||
|
||||
size={min=20, max=30}, -- rough radius of area, too high value can produce square shaped areas
|
||||
min_amount=350,
|
||||
|
||||
-- resource provided at starting location
|
||||
-- probability: 1 = 100% chance to be in starting area
|
||||
-- 0 = resource is not in starting area
|
||||
starting={richness=8000, size=25, probability=1},
|
||||
|
||||
multi_resource_chance=0.20, -- absolute value
|
||||
multi_resource={
|
||||
["iron-ore"] = 2, -- ["resource_name"] = allotment
|
||||
['copper-ore'] = 4,
|
||||
["coal"] = 4,
|
||||
["stone"] = 4,
|
||||
}
|
||||
}
|
||||
|
||||
config["copper-ore"] = {
|
||||
type="resource-ore",
|
||||
|
||||
allotment=90,
|
||||
spawns_per_region={min=1, max=1},
|
||||
richness=10000,
|
||||
size={min=20, max=30},
|
||||
min_amount=350,
|
||||
|
||||
starting={richness=6000, size=25, probability=1},
|
||||
|
||||
multi_resource_chance=0.20,
|
||||
multi_resource={
|
||||
["iron-ore"] = 4,
|
||||
['copper-ore'] = 2,
|
||||
["coal"] = 4,
|
||||
["stone"] = 4,
|
||||
}
|
||||
}
|
||||
|
||||
config["coal"] = {
|
||||
type="resource-ore",
|
||||
|
||||
allotment=80,
|
||||
|
||||
spawns_per_region={min=1, max=1},
|
||||
size={min=15, max=25},
|
||||
richness=8000,
|
||||
min_amount=350,
|
||||
|
||||
starting={richness=6000, size=20, probability=1},
|
||||
|
||||
multi_resource_chance=0.30,
|
||||
multi_resource={
|
||||
["crude-oil"] = 1,
|
||||
["iron-ore"] = 3,
|
||||
['copper-ore'] = 3,
|
||||
}
|
||||
}
|
||||
|
||||
config["stone"] = {
|
||||
type="resource-ore",
|
||||
|
||||
allotment=60,
|
||||
spawns_per_region={min=1, max=1},
|
||||
richness=6000,
|
||||
size={min=15, max=20},
|
||||
min_amount=250,
|
||||
|
||||
starting={richness=5000, size=16, probability=1},
|
||||
|
||||
multi_resource_chance=0.30,
|
||||
multi_resource={
|
||||
["coal"] = 4,
|
||||
["iron-ore"] = 3,
|
||||
['copper-ore'] = 3,
|
||||
}
|
||||
}
|
||||
|
||||
config["crude-oil"] = {
|
||||
type="resource-liquid",
|
||||
minimum_amount=10000,
|
||||
allotment=70,
|
||||
spawns_per_region={min=1, max=2},
|
||||
richness={min=10000, max=20000}, -- richness per resource spawn
|
||||
size={min=3, max=7},
|
||||
|
||||
starting={richness=20000, size=2, probability=1},
|
||||
|
||||
multi_resource_chance=0.20,
|
||||
multi_resource={
|
||||
["coal"] = 4,
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
local function fillEnemies()
|
||||
|
||||
config["enemy-base"] = {
|
||||
type="entity",
|
||||
force="enemy",
|
||||
clear_range = {6, 6},
|
||||
|
||||
spawns_per_region={min=2,max=4},
|
||||
size={min=2,max=4},
|
||||
size_per_region_factor=1,
|
||||
richness=3,
|
||||
|
||||
absolute_probability=absolute_enemy_chance, -- chance to spawn in region
|
||||
probability_distance_factor=1.1, -- relative increase per region
|
||||
max_probability_distance_factor=3, -- absolute value
|
||||
|
||||
along_resource_probability=0.20, -- chance to spawn in resource chunk anyway, absolute value. Can happen once per resource.
|
||||
|
||||
sub_spawn_probability=0.1, -- chance for this entity to spawn anything from sub_spawns table, absolute value
|
||||
sub_spawn_size={min=1, max=2}, -- in same chunk
|
||||
sub_spawn_distance_factor=1.01,
|
||||
sub_spawn_max_distance_factor=1.5,
|
||||
sub_spawns={
|
||||
["small-worm-turret"]={
|
||||
min_distance=0,
|
||||
allotment=200,
|
||||
allotment_distance_factor=0.99,
|
||||
clear_range = {2, 2},
|
||||
},
|
||||
["medium-worm-turret"]={
|
||||
min_distance=10,
|
||||
allotment=100,
|
||||
allotment_distance_factor=1.01,
|
||||
clear_range = {2, 2},
|
||||
},
|
||||
["big-worm-turret"]={
|
||||
min_distance=20,
|
||||
allotment=100,
|
||||
allotment_distance_factor=1.015,
|
||||
clear_range = {2, 2},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
end
|
||||
|
||||
function loadResourceConfig()
|
||||
|
||||
config={}
|
||||
|
||||
fillVanillaConfig()
|
||||
fillEnemies()
|
||||
|
||||
return config
|
||||
end
|
56
tag.lua
56
tag.lua
@ -1,56 +0,0 @@
|
||||
function CreateTagGui(event)
|
||||
local player = game.players[event.player_index]
|
||||
if player.gui.top.tag == nil then
|
||||
player.gui.top.add{name="tag", type="button", caption="Tag"}
|
||||
end
|
||||
end
|
||||
|
||||
-- Tag list
|
||||
local roles = {
|
||||
{display_name = "[Solo]"},
|
||||
{display_name = "[Mining]"},
|
||||
{display_name = "[Power]"},
|
||||
{display_name = "[Oil]"},
|
||||
{display_name = "[Smelt]"},
|
||||
{display_name = "[Rail]"},
|
||||
{display_name = "[Defense]"},
|
||||
{display_name = "[Circuits]"},
|
||||
{display_name = "[Labs]"},
|
||||
{display_name = "[Logistics]"},
|
||||
{display_name = "[Misc]"},
|
||||
{display_name = "[Aliens]"},
|
||||
{display_name = "[Rocket]"},
|
||||
{display_name = "[AFK]"},
|
||||
{display_name = "Clear"}}
|
||||
|
||||
local function ExpangTagGui(player)
|
||||
local frame = player.gui.left["tag-panel"]
|
||||
if (frame) then
|
||||
frame.destroy()
|
||||
else
|
||||
local frame = player.gui.left.add{type="frame", name="tag-panel", caption="What are you doing:"}
|
||||
for _, role in pairs(roles) do
|
||||
frame.add{type="button", caption=role.display_name, name=role.display_name}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function TagGuiClick(event)
|
||||
if not (event and event.element and event.element.valid) then return end
|
||||
local player = game.players[event.element.player_index]
|
||||
local name = event.element.name
|
||||
|
||||
if (name == "tag") then
|
||||
ExpangTagGui(player)
|
||||
end
|
||||
|
||||
if (name == "Clear") then
|
||||
player.tag = ""
|
||||
return
|
||||
end
|
||||
|
||||
for _, role in pairs(roles) do
|
||||
if (name == role.display_name) then
|
||||
player.tag = role.display_name end
|
||||
end
|
||||
end
|
Loading…
x
Reference in New Issue
Block a user