1
0
mirror of https://github.com/Oarcinae/FactorioScenarioMultiplayerSpawn.git synced 2024-12-04 09:43:00 +02:00

Saving my work. The game loads and most of the basics are working but not properly tested yet.

This commit is contained in:
Oarcinae 2024-10-21 13:48:42 -04:00
parent 6d75811639
commit 0d5ec9210e
23 changed files with 198 additions and 133 deletions

View File

@ -17,7 +17,7 @@
-- Check if the OARC mod is loaded. Other than that, it's an empty scenario! -- Check if the OARC mod is loaded. Other than that, it's an empty scenario!
script.on_init(function(event) script.on_init(function(event)
if not game.active_mods["oarc-mod"] then if not script.active_mods["oarc-mod"] then
error("OARC mod not found! This scenario is intended to be run with the OARC mod!") error("OARC mod not found! This scenario is intended to be run with the OARC mod!")
end end
end) end)

View File

@ -167,7 +167,10 @@ end)
---------------------------------------- ----------------------------------------
-- This is not called when the default surface "nauvis" is created as it will always exist! -- This is not called when the default surface "nauvis" is created as it will always exist!
script.on_event(defines.events.on_surface_created, function(event) script.on_event(defines.events.on_surface_created, function(event)
log("Surface created: " .. game.surfaces[event.surface_index].name) local surface = game.surfaces[event.surface_index]
log("Surface created: " .. surface.name)
if (surface.platform) then return end -- WE IGNORE PLATFORMS!
SeparateSpawnsSurfaceCreated(event) SeparateSpawnsSurfaceCreated(event)
RegrowthSurfaceCreated(event) RegrowthSurfaceCreated(event)
end) end)
@ -183,7 +186,7 @@ end)
---------------------------------------- ----------------------------------------
script.on_event(defines.events.on_built_entity, function(event) script.on_event(defines.events.on_built_entity, function(event)
if storage.ocfg.regrowth.enable_regrowth then if storage.ocfg.regrowth.enable_regrowth then
RegrowthMarkAreaSafeGivenTilePos(event.created_entity.surface.name, event.created_entity.position, 2, false) RegrowthMarkAreaSafeGivenTilePos(event.entity.surface.name, event.entity.position, 2, false)
end end
-- For tracking spidertrons... -- For tracking spidertrons...
@ -192,7 +195,7 @@ end)
script.on_event(defines.events.on_robot_built_entity, function (event) script.on_event(defines.events.on_robot_built_entity, function (event)
if storage.ocfg.regrowth.enable_regrowth then if storage.ocfg.regrowth.enable_regrowth then
RegrowthMarkAreaSafeGivenTilePos(event.created_entity.surface.name, event.created_entity.position, 2, false) RegrowthMarkAreaSafeGivenTilePos(event.entity.surface.name, event.entity.position, 2, false)
end end
end) end)

View File

@ -6,14 +6,12 @@ oarc_linked_chest.type="linked-container"
oarc_linked_chest.name="oarc-linked-chest" oarc_linked_chest.name="oarc-linked-chest"
oarc_linked_chest.inventory_type="with_filters_and_bar" oarc_linked_chest.inventory_type="with_filters_and_bar"
oarc_linked_chest.inventory_size=settings.startup["oarc-mod-linked-chest-size"].value --[[@as integer]] oarc_linked_chest.inventory_size=settings.startup["oarc-mod-linked-chest-size"].value --[[@as integer]]
oarc_linked_chest.picture.layers[1].filename = "__oarc-mod__/graphics/oarc-linked-chest.png" oarc_linked_chest.picture.layers[1].filename = "__oarc-mod__/graphics/hr-oarc-linked-chest.png"
oarc_linked_chest.picture.layers[1].hr_version.filename = "__oarc-mod__/graphics/hr-oarc-linked-chest.png"
local oarc_linked_power=table.deepcopy(data.raw["electric-pole"]["small-electric-pole"]) local oarc_linked_power=table.deepcopy(data.raw["electric-pole"]["small-electric-pole"])
oarc_linked_power.name="oarc-linked-power" oarc_linked_power.name="oarc-linked-power"
oarc_linked_power.pictures.layers[1].filename = "__oarc-mod__/graphics/oarc-electric-pole.png" oarc_linked_power.pictures.layers[1].filename = "__oarc-mod__/graphics/hr-oarc-electric-pole.png"
oarc_linked_power.pictures.layers[1].hr_version.filename = "__oarc-mod__/graphics/hr-oarc-electric-pole.png"
data:extend({ data:extend({
{ {
@ -27,4 +25,4 @@ data:extend({
}) })
-- Make coins not hidden -- Make coins not hidden
data.raw["item"]["coin"].flags = {} data.raw["item"]["coin"].hidden = false

View File

@ -78,6 +78,7 @@ Added LuaForce::copy_from() and copy_chart() methods.
------------------------------------------------------------------------------------------------------------------------ ------------------------------------------------------------------------------------------------------------------------
Other Ideas, Not Committed: Other Ideas, Not Committed:
- Look into checking if a force has a chunk visible (for regrowth)
- Add option to spawn on existing chunks (look for chunks with any entities in them, or use regrowth logic) - Add option to spawn on existing chunks (look for chunks with any entities in them, or use regrowth logic)
- Add option for spawn pen to be on a specified surface (not sure this serves any real purpose) - Add option for spawn pen to be on a specified surface (not sure this serves any real purpose)
- Change "search for ungenerated spawn point" to be a "roll" button that the player can re-roll? Maybe it shows on the map in an icon where they might go first? - Change "search for ungenerated spawn point" to be a "roll" button that the player can re-roll? Maybe it shows on the map in an icon where they might go first?

View File

@ -1,24 +1,12 @@
{ {
"_terrain_segmentation_comment": "Inverse of map scale",
"terrain_segmentation": 1,
"_water_comment":
[
"Multiplier for water 'coverage' - higher increases the water level.",
"Water level = 10 * log2(this value)"
],
"water": 1,
"_comment_width+height": "Width and height of map, in tiles; 0 means infinite", "_comment_width+height": "Width and height of map, in tiles; 0 means infinite",
"width": 1, "width": 0,
"height": 1, "height": 0,
"_starting_area_comment": "Multiplier for 'biter free zone radius'", "_starting_area_comment": "Multiplier for 'biter free zone radius'",
"starting_area": 1, "starting_area": 1,
"peaceful_mode": false, "peaceful_mode": false,
"default_enable_all_autoplace_controls": true,
"autoplace_controls": "autoplace_controls":
{ {
@ -28,22 +16,27 @@
"stone" : {"frequency" : 0.20, "richness" : 10.00, "size" : 0.20}, "stone" : {"frequency" : 0.20, "richness" : 10.00, "size" : 0.20},
"uranium-ore" : {"frequency" : 0.20, "richness" : 10.00, "size" : 0.20}, "uranium-ore" : {"frequency" : 0.20, "richness" : 10.00, "size" : 0.20},
"crude-oil" : {"frequency" : 0.20, "richness" : 10.00, "size" : 0.20}, "crude-oil" : {"frequency" : 0.20, "richness" : 10.00, "size" : 0.20},
"trees" : {"frequency" : 0.30, "richness" : 1.50, "size" : 1.00}, "water" : {"frequency": 1, "size": 1},
"enemy-base" : {"frequency" : 0.40, "richness" : 0.50, "size" : 0.50} "trees" : {"frequency": 1, "size": 1},
"enemy-base" : {"frequency": 0.4, "size": 0.5}
}, },
"cliff_settings": "cliff_settings":
{ {
"_name_comment": "Name of the cliff prototype", "_name_comment": "Name of the cliff prototype",
"name": "cliff", "name": "cliff",
"_cliff_elevation_0_comment": "Elevation of first row of cliffs", "_cliff_elevation_0_comment": "Elevation of first row of cliffs",
"cliff_elevation_0": 10, "cliff_elevation_0": 10,
"_cliff_elevation_interval_comment": "Elevation difference between successive rows of cliffs", "_cliff_elevation_interval_comment":
"cliff_elevation_interval": 10, [
"Elevation difference between successive rows of cliffs.",
"_richness_comment": "Multiplier for cliff continuity; 0 will result in no cliffs, 10 will make all cliff rows completely solid", "This is inversely proportional to 'frequency' in the map generation GUI. Specifically, when set from the GUI the value is 40 / frequency."
],
"cliff_elevation_interval": 40,
"_richness_comment": "Called 'cliff continuity' in the map generator GUI. 0 will result in no cliffs, 10 will make all cliff rows completely solid",
"richness": 1 "richness": 1
}, },

View File

@ -1,10 +1,8 @@
{ {
"difficulty_settings": "difficulty_settings":
{ {
"recipe_difficulty": 0, "technology_price_multiplier": 1,
"technology_difficulty": 0, "spoil_time_modifier" : 1
"technology_price_multiplier": 1,
"research_queue_setting": "always"
}, },
"pollution": "pollution":
{ {
@ -21,20 +19,19 @@
"pollution_per_tree_damage": 50, "pollution_per_tree_damage": 50,
"pollution_restored_per_tree_damage": 10, "pollution_restored_per_tree_damage": 10,
"max_pollution_to_restore_trees": 20, "max_pollution_to_restore_trees": 20,
"enemy_attack_pollution_consumption_modifier": 0.5 "enemy_attack_pollution_consumption_modifier": 1
}, },
"enemy_evolution": "enemy_evolution":
{ {
"enabled": true, "enabled": true,
"time_factor": 0.000000, "time_factor": 0.000004,
"destroy_factor": 0.002, "destroy_factor": 0.002,
"pollution_factor": 0.0000002 "pollution_factor": 0.0000009
}, },
"enemy_expansion": "enemy_expansion":
{ {
"enabled": true, "enabled": true,
"min_base_spacing": 3, "max_expansion_distance": 7,
"max_expansion_distance": 10,
"friendly_base_influence_radius": 2, "friendly_base_influence_radius": 2,
"enemy_building_influence_radius": 2, "enemy_building_influence_radius": 2,
"building_coefficient": 0.1, "building_coefficient": 0.1,
@ -45,7 +42,7 @@
"settler_group_min_size": 5, "settler_group_min_size": 5,
"settler_group_max_size": 20, "settler_group_max_size": 20,
"min_expansion_cooldown": 14400, "min_expansion_cooldown": 14400,
"max_expansion_cooldown": 108000 "max_expansion_cooldown": 216000
}, },
"unit_group": "unit_group":
{ {
@ -84,7 +81,7 @@
{ {
"fwd2bwd_ratio": 5, "fwd2bwd_ratio": 5,
"goal_pressure_ratio": 2, "goal_pressure_ratio": 2,
"max_steps_worked_per_tick": 100, "max_steps_worked_per_tick": 1000,
"max_work_done_per_tick": 8000, "max_work_done_per_tick": 8000,
"use_path_cache": true, "use_path_cache": true,
"short_cache_size": 5, "short_cache_size": 5,
@ -111,10 +108,15 @@
"short_request_max_steps": 1000, "short_request_max_steps": 1000,
"short_request_ratio": 0.5, "short_request_ratio": 0.5,
"min_steps_to_check_path_find_termination": 2000, "min_steps_to_check_path_find_termination": 2000,
"start_to_goal_cost_multiplier_to_terminate_path_find": 500.0, "start_to_goal_cost_multiplier_to_terminate_path_find": 2000.0,
"overload_levels": [0, 100, 500], "overload_levels": [0, 100, 500],
"overload_multipliers": [2, 3, 4], "overload_multipliers": [2, 3, 4],
"negative_path_cache_delay_interval": 20 "negative_path_cache_delay_interval": 20
}, },
"asteroids":
{
"spawning_rate" : 1,
"max_ray_portals_expanded_per_tick" : 100
},
"max_failed_behavior_count": 3 "max_failed_behavior_count": 3
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

View File

@ -521,6 +521,8 @@ OCFG = {
-- (Ignore these surfaces completely for spawning and regrowth!) -- (Ignore these surfaces completely for spawning and regrowth!)
---@type table<integer, string> ---@type table<integer, string>
surfaces_blacklist_match = { surfaces_blacklist_match = {
-- Space Age
"platform-",
-- Factorissimo Mod Surfaces -- Factorissimo Mod Surfaces
"factory-power", "factory-power",
"factory-floor", "factory-floor",

View File

@ -126,7 +126,7 @@ function ValidateAndLoadConfig()
if (entry.mod_key ~= "") then if (entry.mod_key ~= "") then
local mod_key = entry.mod_key local mod_key = entry.mod_key
local oarc_key = entry.ocfg_keys local oarc_key = entry.ocfg_keys
local mod_value = game.mod_setting_prototypes[mod_key].default_value local mod_value = prototypes.mod_setting[mod_key].default_value
local oarc_value = GetGlobalOarcConfigUsingKeyTable(oarc_key) local oarc_value = GetGlobalOarcConfigUsingKeyTable(oarc_key)
if (mod_value ~= oarc_value) then if (mod_value ~= oarc_value) then
error("OCFG value does not match mod setting: " .. mod_key .. " = " .. tostring(mod_value) .. " -> " .. serpent.block(oarc_key) .. " = " .. tostring(oarc_value)) error("OCFG value does not match mod setting: " .. mod_key .. " = " .. tostring(mod_value) .. " -> " .. serpent.block(oarc_key) .. " = " .. tostring(oarc_value))

View File

@ -6,8 +6,16 @@
---@return nil ---@return nil
function CreateItemShopTab(tab_container, player) function CreateItemShopTab(tab_container, player)
local player_inv = player.get_main_inventory() if (player.character == nil) then
if (player_inv == nil) then return end AddLabel(tab_container, nil, "Player character not available right now.", my_warning_style)
return
end
local player_inv = player.character.get_main_inventory()
if (player_inv == nil) then
AddLabel(tab_container, nil, "Player main inventory not available right now.", my_warning_style)
return
end
local wallet = player_inv.get_item_count("coin") local wallet = player_inv.get_item_count("coin")
AddLabel(tab_container, AddLabel(tab_container,
@ -29,7 +37,7 @@ function CreateItemShopTab(tab_container, player)
for item_name,item in pairs(section) do for item_name,item in pairs(section) do
-- Validate if item exists -- Validate if item exists
if (not game.item_prototypes[item_name]) then if (not prototypes.item[item_name]) then
log("ERROR: Item not found in storage.ocfg.shop_items: " .. item_name) log("ERROR: Item not found in storage.ocfg.shop_items: " .. item_name)
goto continue goto continue
end end
@ -134,8 +142,24 @@ function DropCoins(surface_index, pos, count, force)
if drop_amount == 0 then return end if drop_amount == 0 then return end
if storage.ocfg.coin_generation.auto_decon_coins then if storage.ocfg.coin_generation.auto_decon_coins then
game.surfaces[surface_index].spill_item_stack(pos, {name="coin", count=math.floor(drop_amount)}, true, force, false) game.surfaces[surface_index].spill_item_stack{
position=pos,
stack={name="coin", count=math.floor(drop_amount)},
enable_looted=true,
force=force,
-- allow_belts?=false,
-- max_radius?=…,
-- use_start_position_on_failure?=false
}
else else
game.surfaces[surface_index].spill_item_stack(pos, {name="coin", count=math.floor(drop_amount)}, true, nil, false) game.surfaces[surface_index].spill_item_stack{
position=pos,
stack={name="coin", count=math.floor(drop_amount)},
enable_looted=true,
force=nil,
-- allow_belts?=false,
-- max_radius?=…,
-- use_start_position_on_failure?=false
}
end end
end end

View File

@ -122,7 +122,7 @@ function PlayerListTabGuiClick(event)
if (tags.setting == "show_location") then if (tags.setting == "show_location") then
local player_name = tags.player_name --[[@as string]] local player_name = tags.player_name --[[@as string]]
local target_player = game.players[player_name] local target_player = game.players[player_name]
player.open_map(target_player.position, 0.05) -- TODO: Update this for spage age! player.set_controller{type = defines.controllers.remote, position = target_player.character.position, surface = target_player.character.surface}
end end
end end

View File

@ -217,7 +217,7 @@ function SettingsControlsTabGuiTextconfirmed(event)
elseif (entry.type == "integer") then elseif (entry.type == "integer") then
local safe_value = GetSafeIntValueForModSetting(value, entry.mod_key) local safe_value = GetSafeIntValueForModSetting(value, entry.mod_key)
if not pcall(function() settings.global[entry.mod_key] = { value = safe_value } end) then if not pcall(function() settings.global[entry.mod_key] = { value = safe_value } end) then
settings.global[entry.mod_key] = { value = game.mod_setting_prototypes[entry.mod_key].default_value } settings.global[entry.mod_key] = { value = prototypes.mod_setting[entry.mod_key].default_value }
log("Error setting value for " .. entry.mod_key .. " to " .. safe_value) log("Error setting value for " .. entry.mod_key .. " to " .. safe_value)
end end
gui_elem.text = tostring(settings.global[entry.mod_key].value) gui_elem.text = tostring(settings.global[entry.mod_key].value)
@ -229,7 +229,7 @@ function SettingsControlsTabGuiTextconfirmed(event)
elseif (entry.type == "double") then elseif (entry.type == "double") then
local safe_value = GetSafeDoubleValueForModSetting(value, entry.mod_key) local safe_value = GetSafeDoubleValueForModSetting(value, entry.mod_key)
if not pcall(function() settings.global[entry.mod_key] = { value = safe_value } end) then if not pcall(function() settings.global[entry.mod_key] = { value = safe_value } end) then
settings.global[entry.mod_key] = { value = game.mod_setting_prototypes[entry.mod_key].default_value } settings.global[entry.mod_key] = { value = prototypes.mod_setting[entry.mod_key].default_value }
log("Error setting value for " .. entry.mod_key .. " to " .. safe_value) log("Error setting value for " .. entry.mod_key .. " to " .. safe_value)
end end
gui_elem.text = string.format("%.2f", settings.global[entry.mod_key].value) gui_elem.text = string.format("%.2f", settings.global[entry.mod_key].value)
@ -272,10 +272,10 @@ end
function GetSafeIntValueForModSetting(input, mod_key) function GetSafeIntValueForModSetting(input, mod_key)
local value_num = tonumber(input) local value_num = tonumber(input)
if not value_num then if not value_num then
value_num = tonumber(game.mod_setting_prototypes[mod_key].default_value) value_num = tonumber(prototypes.mod_setting[mod_key].default_value)
else else
local minimum = game.mod_setting_prototypes[mod_key].minimum_value local minimum = prototypes.mod_setting[mod_key].minimum_value
local maximum = game.mod_setting_prototypes[mod_key].maximum_value local maximum = prototypes.mod_setting[mod_key].maximum_value
if minimum ~= nil then if minimum ~= nil then
value_num = math.max(value_num, minimum) value_num = math.max(value_num, minimum)
end end
@ -294,10 +294,10 @@ end
function GetSafeDoubleValueForModSetting(input, mod_key) function GetSafeDoubleValueForModSetting(input, mod_key)
local value_num = tonumber(input) local value_num = tonumber(input)
if not value_num then if not value_num then
value_num = tonumber(game.mod_setting_prototypes[mod_key].default_value) value_num = tonumber(prototypes.mod_setting[mod_key].default_value)
else else
local minimum = game.mod_setting_prototypes[mod_key].minimum_value local minimum = prototypes.mod_setting[mod_key].minimum_value
local maximum = game.mod_setting_prototypes[mod_key].maximum_value local maximum = prototypes.mod_setting[mod_key].maximum_value
if minimum ~= nil then if minimum ~= nil then
value_num = math.max(value_num, minimum) value_num = math.max(value_num, minimum)
end end
@ -399,8 +399,8 @@ function AddIntegerSetting(tab_container, index, entry, enabled)
local slider = horizontal_flow.add { local slider = horizontal_flow.add {
name = "slider", name = "slider",
type = "slider", type = "slider",
minimum_value = game.mod_setting_prototypes[entry.mod_key].minimum_value, minimum_value = prototypes.mod_setting[entry.mod_key].minimum_value,
maximum_value = game.mod_setting_prototypes[entry.mod_key].maximum_value, maximum_value = prototypes.mod_setting[entry.mod_key].maximum_value,
value = GetGlobalOarcConfigUsingKeyTable(entry.ocfg_keys), value = GetGlobalOarcConfigUsingKeyTable(entry.ocfg_keys),
enabled = enabled, enabled = enabled,
tooltip = { "mod-setting-description."..entry.mod_key }, tooltip = { "mod-setting-description."..entry.mod_key },
@ -447,8 +447,8 @@ function AddDoubleSetting(tab_container, index, entry, enabled)
local slider = horizontal_flow.add { local slider = horizontal_flow.add {
name = "slider", name = "slider",
type = "slider", type = "slider",
minimum_value = game.mod_setting_prototypes[entry.mod_key].minimum_value, minimum_value = prototypes.mod_setting[entry.mod_key].minimum_value,
maximum_value = game.mod_setting_prototypes[entry.mod_key].maximum_value, maximum_value = prototypes.mod_setting[entry.mod_key].maximum_value,
value = GetGlobalOarcConfigUsingKeyTable(entry.ocfg_keys), value = GetGlobalOarcConfigUsingKeyTable(entry.ocfg_keys),
enabled = enabled, enabled = enabled,
tooltip = { "mod-setting-description."..entry.mod_key }, tooltip = { "mod-setting-description."..entry.mod_key },
@ -493,7 +493,7 @@ function AddStringListDropdownSetting(tab_container, index, entry, enabled)
} }
dragger.style.horizontally_stretchable = true dragger.style.horizontally_stretchable = true
local allowed_values = game.mod_setting_prototypes[entry.mod_key].allowed_values --[[@as string[] ]] local allowed_values = prototypes.mod_setting[entry.mod_key].allowed_values --[[@as string[] ]]
local selected_index = 1 local selected_index = 1
for i,v in pairs(allowed_values) do for i,v in pairs(allowed_values) do

View File

@ -301,8 +301,9 @@ function SpawnCtrlTabGuiClick(event)
elseif (tags.setting == "show_location") then elseif (tags.setting == "show_location") then
local surface_name = tags.surface --[[@as string]] local surface_name = tags.surface --[[@as string]]
local position = tags.position --[[@as MapPosition]] local position = tags.position --[[@as MapPosition]]
player.open_map(position, 0.05) -- TODO: Update this for spage age!
player.print({"", { "oarc-spawn-gps-location" }, GetGPStext(surface_name, position)}) player.set_controller{type = defines.controllers.remote, position = position, surface = surface_name}
-- player.print({"", { "oarc-spawn-gps-location" }, GetGPStext(surface_name, position)})
-- Accept or reject pending player join requests to a shared base -- Accept or reject pending player join requests to a shared base
elseif ((tags.setting == "accept_player_request") or (tags.setting == "reject_player_request")) then elseif ((tags.setting == "accept_player_request") or (tags.setting == "reject_player_request")) then

View File

@ -870,7 +870,7 @@ function SurfaceConfigTabGuiElemChanged(event)
return return
end end
if (game.entity_prototypes[new_resource_name].resource_category ~= "basic-solid") then if (prototypes.entity[new_resource_name].resource_category ~= "basic-solid") then
player.print("Resource must be a solid resource! " .. new_resource_name) player.print("Resource must be a solid resource! " .. new_resource_name)
event.element.elem_value = nil event.element.elem_value = nil
return return
@ -918,7 +918,7 @@ function SurfaceConfigTabGuiElemChanged(event)
return return
end end
if (game.entity_prototypes[new_resource_name].resource_category ~= "basic-fluid") then if (prototypes.entity[new_resource_name].resource_category ~= "basic-fluid") then
player.print("Resource must be a fluid resource! " .. new_resource_name) player.print("Resource must be a fluid resource! " .. new_resource_name)
event.element.elem_value = nil event.element.elem_value = nil
return return

View File

@ -12,8 +12,8 @@ function CreateHoldingPenSurface()
---@type MapGenSettings ---@type MapGenSettings
---@diagnostic disable-next-line: missing-fields ---@diagnostic disable-next-line: missing-fields
local map_settings = {} local map_settings = {}
map_settings.terrain_segmentation = "none" -- map_settings.terrain_segmentation = "none"
map_settings.water = "none" -- map_settings.water = "none"
map_settings.starting_area = "none" map_settings.starting_area = "none"
map_settings.peaceful_mode = true map_settings.peaceful_mode = true
map_settings.width = 64 map_settings.width = 64
@ -25,6 +25,7 @@ function CreateHoldingPenSurface()
holding_pen_surface.always_day = true holding_pen_surface.always_day = true
holding_pen_surface.show_clouds = false holding_pen_surface.show_clouds = false
holding_pen_surface.generate_with_lab_tiles = true holding_pen_surface.generate_with_lab_tiles = true
holding_pen_surface.localised_name = {"oarc-holding-pen-surface"}
RenderPermanentGroundText(holding_pen_surface, {x=9,y=-7}, 5, "O", {0.9, 0.7, 0.3, 0.5}, "center") RenderPermanentGroundText(holding_pen_surface, {x=9,y=-7}, 5, "O", {0.9, 0.7, 0.3, 0.5}, "center")
RenderPermanentGroundText(holding_pen_surface, {x=9,y=-4}, 5, "A", {0.9, 0.7, 0.3, 0.5}, "center") RenderPermanentGroundText(holding_pen_surface, {x=9,y=-4}, 5, "A", {0.9, 0.7, 0.3, 0.5}, "center")
@ -93,6 +94,11 @@ function CreateHoldingPenChunks(event)
amount = 90000, amount = 90000,
position = { 0, 9 } position = { 0, 9 }
}) })
-- Create special power pole if sharing is enabled (it will be created later when first requested otherwise)
if (storage.ocfg.gameplay.enable_shared_power) then
InitSharingPowerPoles()
end
end end
end end

View File

@ -238,8 +238,20 @@ function CreateOarcGuiTabsPane(player)
local subhead = inside_frame.add{ local subhead = inside_frame.add{
type="frame", type="frame",
name="sub_header", name="sub_header",
style = "changelog_subheader_frame" style = "subheader_frame"
} }
subhead.style.horizontally_stretchable = true
-- changelog_subheader_frame =
-- {
-- type = "frame_style",
-- parent = "subheader_frame",
-- left_padding = 12,
-- right_padding = 12,
-- top_padding = 4,
-- horizontally_stretchable = "on"
-- }
AddLabel(subhead, nil, {"oarc-gui-tab-header-label"}, "subheader_caption_label") AddLabel(subhead, nil, {"oarc-gui-tab-header-label"}, "subheader_caption_label")
-- TABBED PANE -- TABBED PANE

View File

@ -88,7 +88,7 @@ end
---@param alignment TextAlign? ---@param alignment TextAlign?
---@return nil ---@return nil
function TemporaryHelperText(text, surface, position, ttl, alignment) function TemporaryHelperText(text, surface, position, ttl, alignment)
local rid = rendering.draw_text { text = text, local render_object = rendering.draw_text { text = text,
surface = surface, surface = surface,
target = position, target = position,
color = { 0.7, 0.7, 0.7, 0.7 }, color = { 0.7, 0.7, 0.7, 0.7 },
@ -97,6 +97,7 @@ function TemporaryHelperText(text, surface, position, ttl, alignment)
time_to_live = ttl, time_to_live = ttl,
alignment = alignment, alignment = alignment,
draw_on_ground = false } draw_on_ground = false }
local rid = render_object.id
table.insert(storage.oarc_renders_fadeout, rid) table.insert(storage.oarc_renders_fadeout, rid)
end end
@ -121,12 +122,13 @@ end
function FadeoutRenderOnTick() function FadeoutRenderOnTick()
if (storage.oarc_renders_fadeout and (#storage.oarc_renders_fadeout > 0)) then if (storage.oarc_renders_fadeout and (#storage.oarc_renders_fadeout > 0)) then
for k, rid in pairs(storage.oarc_renders_fadeout) do for k, rid in pairs(storage.oarc_renders_fadeout) do
if (rendering.is_valid(rid)) then local render_object = rendering.get_object_by_id(rid)
local ttl = rendering.get_time_to_live(rid) if (render_object and render_object.valid) then
local ttl = render_object.time_to_live
if ((ttl > 0) and (ttl < 200)) then if ((ttl > 0) and (ttl < 200)) then
local color = rendering.get_color(rid) local color = render_object.color
if (color.a > 0.005) then if (color.a > 0.005) then
rendering.set_color(rid, { r = color.r, g = color.g, b = color.b, a = color.a - 0.005 }) render_object.color = { r = color.r, g = color.g, b = color.b, a = color.a - 0.005 }
end end
end end
else else
@ -372,7 +374,7 @@ end
---@return nil ---@return nil
function OarcsSaferInsert(entity, item_dict) function OarcsSaferInsert(entity, item_dict)
if not (entity and entity.valid and item_dict) then return end if not (entity and entity.valid and item_dict) then return end
local items = game.item_prototypes local items = prototypes.item
local insert = entity.insert local insert = entity.insert
for name, count in pairs(item_dict) do for name, count in pairs(item_dict) do
if items[name] and count > 0 then if items[name] and count > 0 then
@ -389,7 +391,7 @@ end
---@return nil ---@return nil
function OarcsSaferRemove(entity, item_dict) function OarcsSaferRemove(entity, item_dict)
if not (entity and entity.valid and item_dict) then return end if not (entity and entity.valid and item_dict) then return end
local items = game.item_prototypes local items = prototypes.item
local remove = entity.remove_item local remove = entity.remove_item
for name, count in pairs(item_dict) do for name, count in pairs(item_dict) do
if items[name] and count > 0 then if items[name] and count > 0 then
@ -1374,7 +1376,7 @@ function CreateCropCircle(surface, centerPos, chunkArea, tileRadius, fillTile, m
-- Fill in all unexpected water (or force grass) -- Fill in all unexpected water (or force grass)
if (distSqr <= tile_radius_sqr) then if (distSqr <= tile_radius_sqr) then
if (surface.get_tile(i, j).collides_with("water-tile") or if (surface.get_tile(i, j).collides_with("water_tile") or
storage.ocfg.spawn_general.force_grass) then storage.ocfg.spawn_general.force_grass) then
table.insert(dirtTiles, { name = fillTile, position = { i, j } }) table.insert(dirtTiles, { name = fillTile, position = { i, j } })
end end
@ -1442,7 +1444,7 @@ function CreateCropOctagon(surface, centerPos, chunkArea, tileRadius, fillTile,
-- Fill in all unexpected water (or force grass) -- Fill in all unexpected water (or force grass)
if (distVar <= tileRadius) then if (distVar <= tileRadius) then
if (surface.get_tile(i, j).collides_with("water-tile") or if (surface.get_tile(i, j).collides_with("water_tile") or
storage.ocfg.spawn_general.force_grass) then storage.ocfg.spawn_general.force_grass) then
table.insert(dirtTiles, { name = fillTile, position = { i, j } }) table.insert(dirtTiles, { name = fillTile, position = { i, j } })
end end
@ -1511,7 +1513,7 @@ function CreateCropSquare(surface, centerPos, chunkArea, tileRadius, fillTile, m
-- Fill in all unexpected water (or force grass) -- Fill in all unexpected water (or force grass)
if (max_distance <= tileRadius) then if (max_distance <= tileRadius) then
if (surface.get_tile(i, j).collides_with("water-tile") or if (surface.get_tile(i, j).collides_with("water_tile") or
storage.ocfg.spawn_general.force_grass) then storage.ocfg.spawn_general.force_grass) then
table.insert(dirtTiles, { name = fillTile, position = { i, j } }) table.insert(dirtTiles, { name = fillTile, position = { i, j } })
end end

View File

@ -371,7 +371,7 @@ function RegrowthSectorScan(event)
if (storage.rg[surface_name] == nil) then return end if (storage.rg[surface_name] == nil) then return end
---@type integer ---@type integer
local radar_range = event.radar.prototype.max_distance_of_nearby_sector_revealed --TODO: Space age quality might affect this? local radar_range = event.radar.prototype.get_max_distance_of_nearby_sector_revealed(event.radar.quality) --TODO: Space age quality might affect this?
RefreshAreaChunkPosition(surface_name, event.chunk_position, radar_range, 0) RefreshAreaChunkPosition(surface_name, event.chunk_position, radar_range, 0)
end end
@ -694,7 +694,7 @@ function RegrowthOnBuiltEntity(event)
log("Added spidertron to regrowth tracking") log("Added spidertron to regrowth tracking")
if storage.rg.spidertron_chunk_radius == nil then if storage.rg.spidertron_chunk_radius == nil then
storage.rg.spidertron_chunk_radius = game.entity_prototypes["spidertron"].chunk_exploration_radius storage.rg.spidertron_chunk_radius = prototypes.entity["spidertron"].chunk_exploration_radius
end end
end end
end end

View File

@ -236,6 +236,9 @@ end
---@param event EventData.on_player_changed_surface ---@param event EventData.on_player_changed_surface
---@return nil ---@return nil
function SeparateSpawnsPlayerChangedSurface(event) function SeparateSpawnsPlayerChangedSurface(event)
log("SeparateSpawnsPlayerChangedSurface - " .. event.surface_index)
if (not storage.ocfg.gameplay.enable_secondary_spawns) then return end if (not storage.ocfg.gameplay.enable_secondary_spawns) then return end
local player = game.players[event.player_index] local player = game.players[event.player_index]
@ -453,7 +456,7 @@ function SendPlayerToNewSpawnAndCreateIt(delayed_spawn)
} }
-- Create shared power poles -- Create shared power poles
if (ocfg.gameplay.enable_shared_power) then if (ocfg.gameplay.enable_shared_power and delayed_spawn.primary) then
local power_pole_position = { local power_pole_position = {
x = sharing_ref_pos.x + spawn_config.shared_power_pole_position.x_offset, x = sharing_ref_pos.x + spawn_config.shared_power_pole_position.x_offset,
y = sharing_ref_pos.y + spawn_config.shared_power_pole_position.y_offset } y = sharing_ref_pos.y + spawn_config.shared_power_pole_position.y_offset }
@ -461,7 +464,7 @@ function SendPlayerToNewSpawnAndCreateIt(delayed_spawn)
end end
-- Create shared chest -- Create shared chest
if (ocfg.gameplay.enable_shared_chest) then if (ocfg.gameplay.enable_shared_chest and delayed_spawn.primary) then
local chest_position = { local chest_position = {
x = sharing_ref_pos.x + spawn_config.shared_chest_position.x_offset, x = sharing_ref_pos.x + spawn_config.shared_chest_position.x_offset,
y = sharing_ref_pos.y + spawn_config.shared_chest_position.y_offset } y = sharing_ref_pos.y + spawn_config.shared_chest_position.y_offset }
@ -501,7 +504,7 @@ function DisplayWelcomeGroundTextAtSpawn(player, surface, position)
-- Render some welcoming text... -- Render some welcoming text...
local tcolor = { 0.9, 0.7, 0.3, 0.8 } local tcolor = { 0.9, 0.7, 0.3, 0.8 }
local ttl = 2000 local ttl = 2000
local rid1 = rendering.draw_text { text = "Welcome", local render_object_1 = rendering.draw_text { text = "Welcome",
surface = surface, surface = surface,
target = { x = position.x - 21, y = position.y - 15 }, target = { x = position.x - 21, y = position.y - 15 },
color = tcolor, color = tcolor,
@ -514,7 +517,7 @@ function DisplayWelcomeGroundTextAtSpawn(player, surface, position)
-- alignment=center, -- alignment=center,
scale_with_zoom = false, scale_with_zoom = false,
only_in_alt_mode = false } only_in_alt_mode = false }
local rid2 = rendering.draw_text { text = "Home", local render_object_2 = rendering.draw_text { text = "Home",
surface = surface, surface = surface,
target = { x = position.x - 14, y = position.y - 5 }, target = { x = position.x - 14, y = position.y - 5 },
color = tcolor, color = tcolor,
@ -527,6 +530,8 @@ function DisplayWelcomeGroundTextAtSpawn(player, surface, position)
-- alignment=center, -- alignment=center,
scale_with_zoom = false, scale_with_zoom = false,
only_in_alt_mode = false } only_in_alt_mode = false }
local rid1 = render_object_1.id
local rid2 = render_object_2.id
table.insert(storage.oarc_renders_fadeout, rid1) table.insert(storage.oarc_renders_fadeout, rid1)
table.insert(storage.oarc_renders_fadeout, rid2) table.insert(storage.oarc_renders_fadeout, rid2)
@ -1241,15 +1246,16 @@ function QueuePlayerForDelayedSpawn(player_name, surface, spawn_position, moat_e
final_chunk.y = final_chunk.y + spawn_chunk_radius final_chunk.y = final_chunk.y + spawn_chunk_radius
---@type OarcDelayedSpawn ---@type OarcDelayedSpawn
local delayedSpawn = {} local delayed_spawn = {}
delayedSpawn.playerName = player_name delayed_spawn.playerName = player_name
delayedSpawn.surface = surface delayed_spawn.surface = surface
delayedSpawn.position = spawn_position delayed_spawn.position = spawn_position
delayedSpawn.moat = moat_enabled delayed_spawn.moat = moat_enabled
delayedSpawn.delayedTick = game.tick + delay_spawn_seconds * TICKS_PER_SECOND delayed_spawn.delayedTick = game.tick + delay_spawn_seconds * TICKS_PER_SECOND
delayedSpawn.final_chunk_generated = final_chunk delayed_spawn.final_chunk_generated = final_chunk
delayed_spawn.primary = primary
table.insert(storage.delayed_spawns, delayedSpawn) table.insert(storage.delayed_spawns, delayed_spawn)
HideOarcGui(game.players[player_name]) HideOarcGui(game.players[player_name])
DisplayPleaseWaitForSpawnDialog(game.players[player_name], delay_spawn_seconds, game.surfaces[surface], spawn_position) DisplayPleaseWaitForSpawnDialog(game.players[player_name], delay_spawn_seconds, game.surfaces[surface], spawn_position)
@ -1259,7 +1265,7 @@ function QueuePlayerForDelayedSpawn(player_name, surface, spawn_position, moat_e
-- Chart the area to be able to display the minimap while the player waits. -- Chart the area to be able to display the minimap while the player waits.
ChartArea(game.players[player_name].force, ChartArea(game.players[player_name].force,
delayedSpawn.position, delayed_spawn.position,
spawn_chunk_radius, spawn_chunk_radius,
surface surface
) )
@ -1434,7 +1440,6 @@ function CreatePlayerForce(force_name)
new_force = game.create_force(force_name) new_force = game.create_force(force_name)
new_force.share_chart = storage.ocfg.gameplay.enable_shared_team_vision new_force.share_chart = storage.ocfg.gameplay.enable_shared_team_vision
new_force.friendly_fire = storage.ocfg.gameplay.enable_friendly_fire new_force.friendly_fire = storage.ocfg.gameplay.enable_friendly_fire
new_force.research_queue_enabled = true
-- SetCeaseFireBetweenAllPlayerForces() -- SetCeaseFireBetweenAllPlayerForces()
-- SetFriendlyBetweenAllPlayerForces() -- SetFriendlyBetweenAllPlayerForces()
ConfigurePlayerForceRelationships(true, true) ConfigurePlayerForceRelationships(true, true)
@ -1508,7 +1513,15 @@ SPAWN_TEAM_CHOICE = {
---@alias OarcPlayerCooldownsTable table<string, OarcPlayerCooldown> ---@alias OarcPlayerCooldownsTable table<string, OarcPlayerCooldown>
---Temporary data used when spawning a player. Player needs to wait while the area is prepared. ---Temporary data used when spawning a player. Player needs to wait while the area is prepared.
---@alias OarcDelayedSpawn { surface: string, playerName: string, position: MapPosition, moat: boolean, delayedTick: number, final_chunk_generated: ChunkPosition } ---Temporary data used when spawning a player. Player needs to wait while the area is prepared.
---@class OarcDelayedSpawn
---@field surface string The surface on which the player will spawn.
---@field playerName string The name of the player.
---@field position MapPosition The position where the player will spawn.
---@field moat boolean Whether the spawn has a moat or not.
---@field delayedTick number The game tick when the spawn will be ready.
---@field final_chunk_generated ChunkPosition The final chunk position that needs to be generated.
---@field primary boolean Whether this is the primary spawn point for a player, this is the first surface they spawn on. All other spawns are secondary.
---Table of [OarcDelayedSpawn](lua://OarcDelayedSpawn) indexed by player name. ---Table of [OarcDelayedSpawn](lua://OarcDelayedSpawn) indexed by player name.
---@alias OarcDelayedSpawnsTable table<string, OarcDelayedSpawn> ---@alias OarcDelayedSpawnsTable table<string, OarcDelayedSpawn>

View File

@ -58,8 +58,9 @@ function DisplayWelcomeTextGui(player)
local dragger = button_flow.add { local dragger = button_flow.add {
type = "empty-widget", type = "empty-widget",
style = "draggable_space_with_no_left_margin", style = "draggable_space",
} }
dragger.style.left_margin = 0
dragger.style.horizontally_stretchable = true dragger.style.horizontally_stretchable = true
dragger.style.height = 30 dragger.style.height = 30
@ -117,9 +118,19 @@ function CreateSpawnMenuGuiFrame(player)
local subhead = inside_frame.add{ local subhead = inside_frame.add{
type="frame", type="frame",
name="sub_header", name="sub_header",
style = "changelog_subheader_frame" style = "subheader_frame"
} }
subhead.style.height = 46 subhead.style.height = 46
subhead.style.horizontally_stretchable = true
-- changelog_subheader_frame =
-- {
-- type = "frame_style",
-- parent = "subheader_frame",
-- left_padding = 12,
-- right_padding = 12,
-- top_padding = 4,
-- horizontally_stretchable = "on"
-- }
AddLabel(subhead, "warning_lbl1", { "oarc-click-info-btn-help" }, my_note_style) AddLabel(subhead, "warning_lbl1", { "oarc-click-info-btn-help" }, my_note_style)
return inside_frame return inside_frame
@ -956,7 +967,8 @@ function DisplaySharedSpawnJoinWaitMenu(player)
style = "back_button" style = "back_button"
} }
local dragger = button_flow.add{type="empty-widget", style="draggable_space_with_no_right_margin"} local dragger = button_flow.add{type="empty-widget", style="draggable_space"}
dragger.style.right_margin = 0
dragger.style.horizontally_stretchable = true dragger.style.horizontally_stretchable = true
dragger.style.height = 30 dragger.style.height = 30
end end
@ -1009,7 +1021,8 @@ function DisplayBuddySpawnWaitMenu(player)
tooltip = { "oarc-return-to-previous-tooltip" }, tooltip = { "oarc-return-to-previous-tooltip" },
} }
local dragger = button_flow.add{type="empty-widget", style="draggable_space_with_no_right_margin"} local dragger = button_flow.add{type="empty-widget", style="draggable_space"}
dragger.style.right_margin = 0
dragger.style.horizontally_stretchable = true dragger.style.horizontally_stretchable = true
dragger.style.height = 30 dragger.style.height = 30
end end

View File

@ -1,9 +1,22 @@
-- This handles the shared power logic for the Oarc scenario. -- Lets players share electricity via a special power pole and cross surface connections.
-- Won't work too hard on this since 2.0 might change things... -- Also lets players share items via a linked-chest.
X_OFFSET_SHARING_POLE = 10
Y_OFFSET_SHARING_POLE = 0
STARTING_X_OFFSET_SHARING_POLE = -5 function InitSharingPowerPoles()
Y_OFFSET_SHARING_POLE = 20 if storage.shared_power_poles == nil then
---@type LuaEntity[]
storage.shared_power_poles = {}
end
if storage.shared_power_link == nil then
local link_position = { x = X_OFFSET_SHARING_POLE, y = Y_OFFSET_SHARING_POLE }
local link_pole = CreateSpecialPole(game.surfaces[HOLDING_PEN_SURFACE_NAME], link_position)
storage.shared_power_link = link_pole
end
end
---Create and connect a pair of power poles for a new base given surface and position. ---Create and connect a pair of power poles for a new base given surface and position.
---@param surface LuaSurface ---@param surface LuaSurface
@ -16,17 +29,10 @@ function CreateSharedPowerPolePair(surface, position)
storage.shared_power_poles = {} storage.shared_power_poles = {}
end end
--Get an open sharing pole from the holding pen surface if one exists, otherwise create a new one. if storage.shared_power_link == nil then
local hidden_pole = FindSharedPowerPole() local link_position = { x = X_OFFSET_SHARING_POLE, y = Y_OFFSET_SHARING_POLE }
if not hidden_pole then local link_pole = CreateSpecialPole(game.surfaces[HOLDING_PEN_SURFACE_NAME], link_position)
local poles_count = table_size(storage.shared_power_poles) storage.shared_power_link = link_pole
local new_position = { x = poles_count + STARTING_X_OFFSET_SHARING_POLE, y = Y_OFFSET_SHARING_POLE }
hidden_pole = CreateSpecialPole(game.surfaces[HOLDING_PEN_SURFACE_NAME], new_position)
if not hidden_pole then
log("ERROR - Failed to create shared power poles!? " .. serpent.block(position) .. " on " .. surface.name)
return
end
table.insert(storage.shared_power_poles, hidden_pole)
end end
--Create the base pole on the new spawn area surface and connect it to the hidden pole. --Create the base pole on the new spawn area surface and connect it to the hidden pole.
@ -35,7 +41,9 @@ function CreateSharedPowerPolePair(surface, position)
log("ERROR - Failed to create shared power poles!? " .. serpent.block(position) .. " on " .. surface.name) log("ERROR - Failed to create shared power poles!? " .. serpent.block(position) .. " on " .. surface.name)
return return
end end
base_pole.connect_neighbour(hidden_pole) local base_connector = base_pole.get_wire_connector(defines.wire_connector_id.pole_copper, true)
local hidden_connector = storage.shared_power_link.get_wire_connector(defines.wire_connector_id.pole_copper, true)
base_connector.connect_to(hidden_connector, false, defines.wire_origin.script)
TemporaryHelperText( TemporaryHelperText(
{ "oarc-shared-power-pole-helper-txt" }, { "oarc-shared-power-pole-helper-txt" },
@ -46,21 +54,6 @@ function CreateSharedPowerPolePair(surface, position)
) )
end end
---Find the first shared power pole that doesn't exceed the max number of connections.
---@return LuaEntity?
function FindSharedPowerPole()
if storage.shared_power_poles == nil then return nil end
for _,pole in pairs(storage.shared_power_poles) do
-- 5 is the hard coded engine limit and we need to leave one open for the connection to the next hidden pole.
if pole.neighbours["copper"] and table_size(pole.neighbours["copper"]) < 4 then
return pole
end
end
return nil
end
---Creates a special pole on the surface at the given position on the neutral force. ---Creates a special pole on the surface at the given position on the neutral force.
---@param surface LuaSurface ---@param surface LuaSurface
---@param position MapPosition ---@param position MapPosition

View File

@ -1,5 +1,7 @@
scenario-name=OARC scenario-name=OARC
oarc-holding-pen-surface=[img=oarc-mod-sprite-40] New Player Holding Area
description=This mod provides a scenario that overhauls multiplayer spawning.\n[color=red][font=default-bold]Please check out the github page and discord for more information and support.[/font][/color] description=This mod provides a scenario that overhauls multiplayer spawning.\n[color=red][font=default-bold]Please check out the github page and discord for more information and support.[/font][/color]
oarc-scenario-info-warn-msg=This scenario allows players to create their own spawn points far from the center of the map. For more information, click the OARC button in the top left corner. oarc-scenario-info-warn-msg=This scenario allows players to create their own spawn points far from the center of the map. For more information, click the OARC button in the top left corner.