1
0
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:
Oarcinae 2016-12-28 08:33:09 -08:00
parent 8c221f67bf
commit 92b349c9be
10 changed files with 13 additions and 3026 deletions

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "oarc_utils"]
path = locale
url = https://github.com/Oarcinae/FactorioUtils

665
bps.lua
View File

@ -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)

View File

@ -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

View File

@ -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

@ -0,0 +1 @@
Subproject commit 7faacf8eca0d9e08184b5ceefa330d08289f78cb

View File

@ -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

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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
View File

@ -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