diff --git a/config.lua b/config.lua index 35ed16d..b7606d7 100644 --- a/config.lua +++ b/config.lua @@ -17,8 +17,8 @@ WELCOME_MSG_TITLE = "[INSERT SERVER OWNER MSG HERE!]" WELCOME_MSG1 = "Rules: Be polite. Ask before changing other players's stuff. Have fun!" WELCOME_MSG2 = "This server is running a custom scenario that changes spawn locations." -OTHER_MSG1 = "Latest updates in this scenario version (0.5.5):" -OTHER_MSG2 = "Regrowth fixes (disabled). Abandoned base removal." +OTHER_MSG1 = "Latest updates in this scenario version:" +OTHER_MSG2 = "0.16 experimental release." -- Optional other messages below: OTHER_MSG3 = "Standard multiplayer spawn allows spawning in far locations." OTHER_MSG4 = "You can be on the main team or your own." @@ -36,40 +36,38 @@ SPAWN_MSG3 = "Resources are spread out far apart but are quite rich." -- These are my specific welcome messages that get used only if I am the user -- that creates the game. -SERVER_OWNER_IS_OARC = true -- This should be false for you, it's just a convenience for me. +SERVER_OWNER_IS_OARC = false -- This should be false for you, it's just a convenience for me. WELCOME_MSG_OARC = "Welcome to Oarc's official server! Join the discord here: discord.gg/TPYxRrS" WELCOME_MSG_TITLE_OARC = "Welcome to Oarc's Server!" -------------------------------------------------------------------------------- -- Module Enables --- These enables are not fully tested! For example, disable separate spawns +-- These enables are not fully tested! For example, disabling separate spawns -- will probably break the frontier rocket silo mode -------------------------------------------------------------------------------- --- Frontier style rocket silo mode -FRONTIER_ROCKET_SILO_MODE = false - -- Separate spawns -- This is the core of the mod. Probably not a good idea to disable it. ENABLE_SEPARATE_SPAWNS = true --- Enable Scenario version of RSO --- You can reconfigure the RSO resource settings in the RSO files if you want to -ENABLE_RSO = false +-- RSO OPTION HAS BEEN REMOVED FOR NOW. USE THE 0.16 MOD. + +-- Frontier style rocket silo mode +FRONTIER_ROCKET_SILO_MODE = false -- Enable Undecorator -- Removes decorative items to reduce save file size. -ENABLE_UNDECORATOR = true +ENABLE_UNDECORATOR = false -- Enable Tags -ENABLE_TAGS = false +ENABLE_TAGS = true -- Enable Long Reach ENABLE_LONGREACH = true -- Enable Autofill -ENABLE_AUTOFILL = false +ENABLE_AUTOFILL = true -- Enable Playerlist ENABLE_PLAYER_LIST = true @@ -87,7 +85,7 @@ ENABLE_POWER_ARMOR_QUICK_START = false -- Enable shared vision between teams (all teams are still COOP) ENABLE_SHARED_TEAM_VISION = true -ENABLE_SHARED_TEAM_RADAR = true +ENABLE_SHARED_TEAM_RADAR = true -- This shares charted chunks. Not active vision. -- Enable map regrowth, see regrowth_map.lua for more info. ENABLE_REGROWTH = false @@ -152,6 +150,11 @@ FAR_MAX_DIST = 300 --125 -- Resource & Spawn Circle Options --------------------------------------- +-- Enable this to have a vanilla style starting spawn for all new spawns. +-- This scenario normally gives you a fixed circle with resources. +-- USE_VANILLA_STARTING_SPAWN = true +-- TODO - Requires pre-allocating spawns... + -- Allow players to choose to spawn with a moat SPAWN_MOAT_CHOICE_ENABLED = true @@ -221,7 +224,7 @@ SPAWN_TREE_OCTAGON_ENABLED = true -- Safe area has no aliens -- +/- this in x and y direction -SAFE_AREA_TILE_DIST = CHUNK_SIZE*12 +SAFE_AREA_TILE_DIST = CHUNK_SIZE*10 -- Warning area has reduced aliens -- +/- this in x and y direction @@ -271,14 +274,14 @@ MIN_ONLINE_TIME = TICKS_PER_MINUTE * MIN_ONLINE_TIME_IN_MINUTES -- Alien Options -------------------------------------------------------------------------------- --- Enable/Disable enemy expansion (Applies to RSO as well!) +-- Enable/Disable enemy expansion ENEMY_EXPANSION = true --- Divide the alien factors by this number to reduce it (or multiply if < 1) -ENEMY_POLLUTION_FACTOR_DIVISOR = 10 -ENEMY_DESTROY_FACTOR_DIVISOR = 10 - - +-- Divide the alien evolution factors by this number to reduce it (or multiply if < 1) +ENEMY_TIME_FACTOR_DISABLE = false -- Set this to true to disable time based evolution completely. +ENEMY_TIME_FACTOR_DIVISOR = 1 +ENEMY_POLLUTION_FACTOR_DIVISOR = 1 +ENEMY_DESTROY_FACTOR_DIVISOR = 1 -------------------------------------------------------------------------------- -- Frontier Rocket Silo Options @@ -309,19 +312,43 @@ RESOURCE_DIST_BONUS = 2 AUTOFILL_TURRET_AMMO_QUANTITY = 10 -------------------------------------------------------------------------------- --- Use rso_config and rso_resource_config for RSO config settings +-- MAP CONFIGURATION OPTIONS +-- Configure these if you are running headless since there is no way to set +-- resources otherwise. -------------------------------------------------------------------------------- --- Don't touch unless you know what you're doing... --- When using RSO, all resources MUST BE SET TO SIZE=NONE! --------------------------------------------------------------------------------- -MAP_SETTINGS_RSO_TERRAIN_SEGMENTATION = "very-low" -- Frequency of water -MAP_SETTINGS_RSO_WATER = "high" -- Size of water patches -MAP_SETTINGS_RSO_PEACEFUL = false -- Peaceful mode for biters/aliens -MAP_SETTINGS_RSO_STARTING_AREA = "very-low" -- Does not affect Oarc spawn sizes. + +-- Set this to true if you are creating the scenario at the cmd line. +CMD_LINE_MAP_GEN = true + +-- Adjust settings here to set your map stuff. +-- "Sizes can be specified as none, very-low, low, normal, high, very-high" +global.clMapGen = {} +global.clMapGen.terrain_segmentation="normal" +global.clMapGen.water="normal" +global.clMapGen.starting_area="normal" +global.clMapGen.peaceful_mode=false +global.clMapGen.seed=nil; +-- These are my go to default vanilla settings, it's not RSO, but it's okay. +global.clMapGen.autoplace_controls = { + ["coal"]={frequency="very-low", size= "normal", richness= "very-high"}, + ["copper-ore"]={frequency= "very-low", size= "normal", richness= "very-high"}, + ["crude-oil"]={frequency= "low", size= "normal", richness= "very-high"}, + ["enemy-base"]={frequency= "low", size= "normal", richness= "normal"}, + ["iron-ore"]={frequency= "very-low", size= "normal", richness= "very-high"}, + ["stone"]={frequency= "very-low", size= "normal", richness= "very-high"}, + ["uranium-ore"]={frequency= "low", size= "normal", richness= "very-high"}, + ["desert"]={frequency= "normal", size= "normal", richness= "normal"}, + ["dirt"]={frequency= "normal", size= "normal", richness= "normal"}, + ["grass"]={frequency= "normal", size= "normal", richness= "normal"}, + ["sand"]={frequency= "normal", size= "normal", richness= "normal"}, + ["trees"]={frequency= "normal", size= "normal", richness= "normal"} +} +-- Cliff defaults are 10 and 10, set both to 0 to turn cliffs off I think? +global.clMapGen.cliff_settings={cliff_elevation_0=100, cliff_elevation_interval=100, name="cliff"} ------------------------------------------------------------------------------- -- DEBUG -------------------------------------------------------------------------------- -- DEBUG prints for me -global.oarcDebugEnabled = false +global.oarcDebugEnabled = true diff --git a/control.lua b/control.lua index e64436d..2e4f546 100644 --- a/control.lua +++ b/control.lua @@ -24,7 +24,6 @@ -- Generic Utility Includes require("locale/oarc_utils") -require("locale/rso/rso_control") require("locale/frontier_silo") require("locale/tag") @@ -93,17 +92,7 @@ script.on_init(function(event) -- Here I create the game surface. I do this so that I don't have to worry -- about the game menu settings and I can now generate a map from the command -- line more easily! - -- - -- If you are using RSO, map settings are ignored and you MUST configure - -- the relevant map settings in config.lua - -- - -- If you disable RSO, the map settings will be set from the ones that you - -- choose from the game GUI when you start a new scenario. - if ENABLE_RSO then - CreateGameSurface(RSO_MODE) - else - CreateGameSurface(VANILLA_MODE) - end + CreateGameSurface() if ENABLE_SEPARATE_SPAWNS then InitSpawnGlobalsAndForces() @@ -125,16 +114,6 @@ script.on_init(function(event) OarcRegrowthInit() end - --If any (not global.) globals are written to at this point, an error will be thrown. - --eg, x = 2 will throw an error because it's not global.x - -- setmetatable(_G, { - -- __newindex = function(_, n) - -- log("Attempt to write to undeclared var " .. n) - -- game.print("Attempt to write to undeclared var " .. n) - -- end - -- }) - -- -- THIS REQUIRES A LOT OF CHANGES TO RSO SOFT MOD... - end) @@ -161,20 +140,17 @@ script.on_event(defines.events.on_chunk_generated, function(event) UndecorateOnChunkGenerate(event) end - if ENABLE_RSO then - RSO_ChunkGenerated(event) - end - if FRONTIER_ROCKET_SILO_MODE then GenerateRocketSiloChunk(event) end - -- This MUST come after RSO generation! - if ENABLE_SEPARATE_SPAWNS then + if ENABLE_SEPARATE_SPAWNS and not USE_VANILLA_STARTING_SPAWN then SeparateSpawnsGenerateChunk(event) end - CreateHoldingPenGenerateChunk(event) + if not ENABLE_DEFAULT_SPAWN then + CreateHoldingPen(event.surface, event.area, 16, false) + end end) @@ -199,6 +175,13 @@ script.on_event(defines.events.on_gui_click, function(event) end) +script.on_event(defines.events.on_gui_checked_state_changed, function (event) + if ENABLE_SEPARATE_SPAWNS then + SpawnOptsGuiOptionsSelect(event) + SpawnCtrlGuiOptionsSelect(event) + end +end) + ---------------------------------------- -- Player Events @@ -207,13 +190,13 @@ script.on_event(defines.events.on_player_joined_game, function(event) PlayerJoinedMessages(event) - if ENABLE_TAGS then - CreateTagGui(event) - end - if ENABLE_PLAYER_LIST then CreatePlayerListGui(event) end + + if ENABLE_TAGS then + CreateTagGui(event) + end end) script.on_event(defines.events.on_player_created, function(event) diff --git a/locale/frontier_silo.lua b/locale/frontier_silo.lua index e214cac..1336edf 100644 --- a/locale/frontier_silo.lua +++ b/locale/frontier_silo.lua @@ -18,7 +18,7 @@ local function CreateRocketSilo(surface, chunkArea, force) 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}} + tiles[i] = {name = "grass-1", position = {global.siloPosition.x+dx, global.siloPosition.y+dy}} i=i+1 end end @@ -68,9 +68,15 @@ function GenerateRocketSiloChunk(event) end end + -- Remove trees/resources inside the spawn area + RemoveInCircle(surface, chunkArea, "tree", global.siloPosition, ENFORCE_LAND_AREA_TILE_DIST+5) + RemoveInCircle(surface, chunkArea, "resource", global.siloPosition, ENFORCE_LAND_AREA_TILE_DIST+5) + RemoveInCircle(surface, chunkArea, "cliff", global.siloPosition, ENFORCE_LAND_AREA_TILE_DIST+5) + RemoveDecorationsArea(surface, chunkArea) + -- Create rocket silo CreateRocketSilo(surface, chunkArea, MAIN_FORCE) - CreateCropCircle(surface, global.siloPosition, chunkArea, 40) + CreateCropOctagon(surface, global.siloPosition, chunkArea, 40) end diff --git a/locale/oarc_utils.lua b/locale/oarc_utils.lua index 17e26dc..b7e142a 100644 --- a/locale/oarc_utils.lua +++ b/locale/oarc_utils.lua @@ -441,7 +441,9 @@ end -- Removes the entity type from the area given function RemoveInArea(surface, area, type) for key, entity in pairs(surface.find_entities_filtered({area=area, type= type})) do - entity.destroy() + if entity.valid and entity and entity.position then + entity.destroy() + end end end @@ -449,8 +451,10 @@ end -- Only if it is within given distance from given position. function RemoveInCircle(surface, area, type, pos, dist) for key, entity in pairs(surface.find_entities_filtered({area=area, type= type})) do - if ((pos.x - entity.position.x)^2 + (pos.y - entity.position.y)^2 < dist^2) then - entity.destroy() + if entity.valid and entity and entity.position then + if ((pos.x - entity.position.x)^2 + (pos.y - entity.position.y)^2 < dist^2) then + entity.destroy() + end end end end @@ -484,23 +488,32 @@ end -- Adjust alien params function ConfigureAlienStartingParams() - game.map_settings.enemy_evolution.time_factor=0 + + -- These are the default values for reference: + -- "time_factor": 0.000004, + -- "destroy_factor": 0.002, + -- "pollution_factor": 0.000015 + if ENEMY_TIME_FACTOR_DISABLE then + game.map_settings.enemy_evolution.time_factor=0 + else + game.map_settings.enemy_evolution.time_factor=game.map_settings.enemy_evolution.time_factor / ENEMY_TIME_FACTOR_DIVISOR + end 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 - game.map_settings.enemy_expansion.min_base_spacing = 10 - game.map_settings.enemy_expansion.max_expansion_distance = 10 + -- game.map_settings.enemy_expansion.min_base_spacing = 10 + -- game.map_settings.enemy_expansion.max_expansion_distance = 10 - game.map_settings.enemy_expansion.settler_group_min_size = 5 - game.map_settings.enemy_expansion.settler_group_max_size = 20 + -- game.map_settings.enemy_expansion.settler_group_min_size = 5 + -- game.map_settings.enemy_expansion.settler_group_max_size = 20 -- game.map_settings.enemy_expansion.friendly_base_influence_radius = 4 -- game.map_settings.enemy_expansion.enemy_building_influence_radius = 4 - game.map_settings.enemy_expansion.min_expansion_cooldown = TICKS_PER_MINUTE*30 - game.map_settings.enemy_expansion.max_expansion_cooldown = TICKS_PER_MINUTE*120 + -- game.map_settings.enemy_expansion.min_expansion_cooldown = TICKS_PER_MINUTE*30 + -- game.map_settings.enemy_expansion.max_expansion_cooldown = TICKS_PER_MINUTE*120 end -- Add Long Reach to Character @@ -532,7 +545,7 @@ local function ExpandPlayerListGui(player) name="playerList-panel", direction = "vertical"} ApplyStyle(scrollFrame, my_player_list_fixed_width_style) - scrollFrame.horizontal_scroll_policy = "never" + scrollFrame.can_scroll_horizontally = false for _,player in pairs(game.connected_players) do local caption_str = player.name.." ["..player.force.name.."]".." ("..formattime_hours_mins(player.online_time)..")" local text = scrollFrame.add{type="label", caption=caption_str, name=player.name.."_plist"} @@ -726,7 +739,7 @@ function AutoFillVehicle(player, vehicle) -- Attempt to transfer some fuel if ((vehicle.name == "car") or (vehicle.name == "tank") or (vehicle.name == "locomotive")) then - TransferItemMultipleTypes(mainInv, vehicle, {"rocket-fuel", "solid-fuel", "coal", "raw-wood"}, 50) + TransferItemMultipleTypes(mainInv, vehicle, {"nuclear-fuel", "rocket-fuel", "solid-fuel", "coal", "raw-wood"}, 50) end -- Attempt to transfer some ammo @@ -760,7 +773,7 @@ function CreateCropCircle(surface, centerPos, chunkArea, tileRadius) -- 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}}) + table.insert(dirtTiles, {name = "grass-1", position ={i,j}}) end end @@ -791,7 +804,7 @@ function CreateCropOctagon(surface, centerPos, chunkArea, tileRadius) -- 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}}) + table.insert(dirtTiles, {name = "grass-1", position ={i,j}}) end end @@ -828,7 +841,7 @@ function CreateMoat(surface, centerPos, chunkArea, tileRadius) -- a clean transition if ((distVar < tileRadSqr-500) and (distVar > tileRadSqr-1000)) then - table.insert(waterTiles, {name = "grass", position ={i,j}}) + table.insert(waterTiles, {name = "grass-1", position ={i,j}}) end end end @@ -941,6 +954,8 @@ function CreateSpawnAreas(surface, chunkArea, spawnPointTable) -- Remove trees/resources inside the spawn area RemoveInCircle(surface, chunkArea, "tree", spawn.pos, ENFORCE_LAND_AREA_TILE_DIST+5) RemoveInCircle(surface, chunkArea, "resource", spawn.pos, ENFORCE_LAND_AREA_TILE_DIST+5) + RemoveInCircle(surface, chunkArea, "cliff", spawn.pos, ENFORCE_LAND_AREA_TILE_DIST+5) + RemoveDecorationsArea(surface, chunkArea) if (SPAWN_TREE_CIRCLE_ENABLED) then CreateCropCircle(surface, spawn.pos, chunkArea, ENFORCE_LAND_AREA_TILE_DIST) @@ -970,73 +985,20 @@ end -------------------------------------------------------------------------------- -- Surface Generation Functions -------------------------------------------------------------------------------- --- To use RSO resources, we have to disable vanilla ore generation -local surface_autoplace_none = { - ["coal"]={ - size="none" - }, - ["copper-ore"]={ - size="none" - }, - ["iron-ore"]={ - size="none" - }, - ["stone"]={ - size="none" - }, - ["uranium-ore"]={ - size="none" - }, - ["crude-oil"]={ - size="none" - }, - ["enemy-base"]={ - size="none" - } -} - -RSO_MODE = 1 -VANILLA_MODE = 2 - -function CreateLobbySurface() - local surface = game.create_surface("Lobby",{width = 1, height = 1}) - surface.set_tiles({{name = "out-of-map",position = {1,1}}}) -end - -function CreateGameSurface(mode) +function CreateGameSurface() local mapSettings = game.surfaces["nauvis"].map_gen_settings - if (mode == RSO_MODE) then - mapSettings.terrain_segmentation=MAP_SETTINGS_RSO_TERRAIN_SEGMENTATION - mapSettings.water=MAP_SETTINGS_RSO_WATER - mapSettings.starting_area=MAP_SETTINGS_RSO_STARTING_AREA - mapSettings.peaceful_mode=MAP_SETTINGS_RSO_PEACEFUL - mapSettings.seed=math.random(999999999); - mapSettings.autoplace_controls = { - ["coal"]={ size="none" }, - ["copper-ore"]={ size="none" }, - ["iron-ore"]={ size="none" }, - ["stone"]={ size="none" }, - ["uranium-ore"]={ size="none" }, - ["crude-oil"]={ size="none" }, - ["enemy-base"]={ size="none" } - } - else - mapSettings.terrain_segmentation="normal" - mapSettings.water="normal" - mapSettings.starting_area="normal" - mapSettings.peaceful_mode=false - mapSettings.seed=math.random(999999999); - mapSettings.autoplace_controls = { - ["coal"]={frequency="very-low", size= "normal", richness= "very-high"}, - ["copper-ore"]={frequency= "very-low", size= "normal", richness= "very-high"}, - ["crude-oil"]={frequency= "low", size= "normal", richness= "very-high"}, - ["enemy-base"]={frequency= "very-low", size= "very-low", richness= "very-low"}, - ["iron-ore"]={frequency= "very-low", size= "normal", richness= "very-high"}, - ["stone"]={frequency= "very-low", size= "normal", richness= "very-high"}, - ["uranium-ore"]={frequency= "low", size= "normal", richness= "very-high"} - } + + if CMD_LINE_MAP_GEN then + mapSettings.terrain_segmentation = global.clMapGen.terrain_segmentation + mapSettings.water = global.clMapGen.water + mapSettings.starting_area = global.clMapGen.starting_area + mapSettings.peaceful_mode = global.clMapGen.peaceful_mode + mapSettings.seed = global.clMapGen.seed + mapSettings.autoplace_controls = global.clMapGen.autoplace_controls + mapSettings.cliff_settings = global.clMapGen.cliff_settings end + local surface = game.create_surface(GAME_SURFACE_NAME,mapSettings) surface.set_tiles({{name = "out-of-map",position = {1,1}}}) end @@ -1053,7 +1015,7 @@ function CreateWall(surface, pos) end end -function CreateHoldingPen(surface, chunkArea) +function CreateHoldingPen(surface, chunkArea, sizeTiles, walls) if (((chunkArea.left_top.x == -32) or (chunkArea.left_top.x == 0)) and ((chunkArea.left_top.y == -32) or (chunkArea.left_top.y == 0))) then @@ -1061,6 +1023,7 @@ function CreateHoldingPen(surface, chunkArea) RemoveAliensInArea(surface, chunkArea) RemoveInArea(surface, chunkArea, "tree") RemoveInArea(surface, chunkArea, "resource") + RemoveInArea(surface, chunkArea, "cliff") -- This loop runs through each tile local grassTiles = {} @@ -1068,26 +1031,34 @@ function CreateHoldingPen(surface, chunkArea) for i=chunkArea.left_top.x,chunkArea.right_bottom.x,1 do for j=chunkArea.left_top.y,chunkArea.right_bottom.y,1 do - -- Fill all area with grass only - table.insert(grassTiles, {name = "grass", position ={i,j}}) + if ((i>-sizeTiles) and (i<(sizeTiles-1)) and (j>-sizeTiles) and (j<(sizeTiles-1))) then - -- Create the spawn box walls - if (j<15 and j>-16) then + -- Fill all area with grass only + table.insert(grassTiles, {name = "grass-1", position ={i,j}}) + + -- Create the spawn box walls + if (j<(sizeTiles-1) and j>-sizeTiles) then + + -- Create horizontal sides of center spawn box + if (((j>-sizeTiles and j<-(sizeTiles-4)) or (j<(sizeTiles-1) and j>(sizeTiles-5))) and (i<(sizeTiles-1) and i>-sizeTiles)) then + if walls then + CreateWall(surface, {i,j}) + else + table.insert(waterTiles, {name = "water", position ={i,j}}) + end + end + + -- Create vertical sides of center spawn box + if ((i>-sizeTiles and i<-(sizeTiles-4)) or (i<(sizeTiles-1) and i>(sizeTiles-5))) then + if walls then + CreateWall(surface, {i,j}) + else + table.insert(waterTiles, {name = "water", position ={i,j}}) + end + end - -- Create horizontal sides of center spawn box - if (((j>-16 and j<-12) or (j<15 and j>11)) and (i<15 and i>-16)) then - -- CreateWall(surface, {i,j}) - table.insert(waterTiles, {name = "water", position ={i,j}}) end - - -- Create vertical sides of center spawn box - if ((i>-16 and i<-12) or (i<15 and i>11)) then - -- CreateWall(surface, {i,j}) - table.insert(waterTiles, {name = "water", position ={i,j}}) - end - end - end end surface.set_tiles(grassTiles) @@ -1095,10 +1066,6 @@ function CreateHoldingPen(surface, chunkArea) end end -function CreateHoldingPenGenerateChunk(event) - CreateHoldingPen(event.surface, event.area) -end - -------------------------------------------------------------------------------- -- EVENT SPECIFIC FUNCTIONS -------------------------------------------------------------------------------- diff --git a/locale/rso/drand.lua b/locale/rso/drand.lua deleted file mode 100644 index 60db0ad..0000000 --- a/locale/rso/drand.lua +++ /dev/null @@ -1,269 +0,0 @@ ---[[------------------------------------ -RandomLua v0.3.1 -Pure Lua Pseudo-Random Numbers Generator -Under the MIT license. -copyright(c) 2011 linux-man ---]]------------------------------------ - -local _M = {} -local mod = math.fmod -local floor = math.floor -local abs = math.abs - -local function normalize(n) --keep numbers at (positive) 32 bits - return n % 0x80000000 -end - -local function bit_and(a, b) - local r = 0 - local m = 0 - for m = 0, 31 do - if (a % 2 == 1) and (b % 2 == 1) then r = r + 2^m end - if a % 2 ~= 0 then a = a - 1 end - if b % 2 ~= 0 then b = b - 1 end - a = a / 2 b = b / 2 - end - return normalize(r) -end - -local function bit_or(a, b) - local r = 0 - local m = 0 - for m = 0, 31 do - if (a % 2 == 1) or (b % 2 == 1) then r = r + 2^m end - if a % 2 ~= 0 then a = a - 1 end - if b % 2 ~= 0 then b = b - 1 end - a = a / 2 b = b / 2 - end - return normalize(r) -end - -local function bit_xor(a, b) - local r = 0 - local m = 0 - for m = 0, 31 do - if a % 2 ~= b % 2 then r = r + 2^m end - if a % 2 ~= 0 then a = a - 1 end - if b % 2 ~= 0 then b = b - 1 end - a = a / 2 b = b / 2 - end - return normalize(r) -end - -local function seed() - --return normalize(tonumber(tostring(os.time()):reverse())) - return normalize(os.time()) -end - ---Mersenne twister -mersenne_twister = {} -mersenne_twister.__index = mersenne_twister - -function mersenne_twister:randomseed(s) - if not s then s = seed() end - self.mt[0] = normalize(s) - for i = 1, 623 do - self.mt[i] = normalize(0x6c078965 * bit_xor(self.mt[i-1], floor(self.mt[i-1] / 0x40000000)) + i) - end -end - -function mersenne_twister:random(a, b) - local y - if self.index == 0 then - for i = 0, 623 do - --y = bit_or(floor(self.mt[i] / 0x80000000) * 0x80000000, self.mt[(i + 1) % 624] % 0x80000000) - y = self.mt[(i + 1) % 624] % 0x80000000 - self.mt[i] = bit_xor(self.mt[(i + 397) % 624], floor(y / 2)) - if y % 2 ~= 0 then self.mt[i] = bit_xor(self.mt[i], 0x9908b0df) end - end - end - y = self.mt[self.index] - y = bit_xor(y, floor(y / 0x800)) - y = bit_xor(y, bit_and(normalize(y * 0x80), 0x9d2c5680)) - y = bit_xor(y, bit_and(normalize(y * 0x8000), 0xefc60000)) - y = bit_xor(y, floor(y / 0x40000)) - self.index = (self.index + 1) % 624 - if not a then return y / 0x80000000 - elseif not b then - if a == 0 then return y - else return 1 + (y % a) - end - else - return a + (y % (b - a + 1)) - end -end - -function _M.twister(s) - local temp = {} - setmetatable(temp, mersenne_twister) - temp.mt = {} - temp.index = 0 - temp:randomseed(s) - return temp -end - ---Linear Congruential Generator -linear_congruential_generator = {} -linear_congruential_generator.__index = linear_congruential_generator - -function linear_congruential_generator:random(a, b) - local y = (self.a * self.x + self.c) % self.m - self.x = y - if not a then return y / 0x10000 - elseif not b then - if a == 0 then return y - else return 1 + (y % a) end - else - return a + (y % (b - a + 1)) - end -end - -function linear_congruential_generator:randomseed(s) - if not s then s = seed() end - self.x = normalize(s) -end - -function _M.lcg(s, r) - local temp = {} - setmetatable(temp, linear_congruential_generator) - temp.a, temp.c, temp.m = 1103515245, 12345, 0x10000 --from Ansi C - if r then - if r == 'nr' then temp.a, temp.c, temp.m = 1664525, 1013904223, 0x10000 --from Numerical Recipes. - elseif r == 'mvc' then temp.a, temp.c, temp.m = 214013, 2531011, 0x10000 end--from MVC - end - temp:randomseed(s) - return temp -end - --- Multiply-with-carry -multiply_with_carry = {} -multiply_with_carry.__index = multiply_with_carry - -function multiply_with_carry:random(a, b) - local m = self.m - local t = self.a * self.x + self.c - local y = t % m - self.x = y - self.c = floor(t / m) - if not a then return y / 0x10000 - elseif not b then - if a == 0 then return y - else return 1 + (y % a) end - else - local diff = 0 - if a == b then return a end - if a < 0 then - diff = abs(a) - a = a + diff - b = b + diff - end - return a + (y % (b - a + 1)) - diff - end -end - -function multiply_with_carry:randomseed(s) - if not s then s = seed() end - self.c = self.ic - self.x = normalize(s) -end - -function _M.mwc(s, r) - local temp = {} - setmetatable(temp, multiply_with_carry) - temp.a, temp.c, temp.m = 1103515245, 12345, 0x10000 --from Ansi C - if r then - if r == 'nr' then temp.a, temp.c, temp.m = 1664525, 1013904223, 0x10000 --from Numerical Recipes. - elseif r == 'mvc' then temp.a, temp.c, temp.m = 214013, 2531011, 0x10000 end--from MVC - end - temp.ic = temp.c - temp:randomseed(s) - return temp -end - -function _M.mwvc(s) - return _M.mwc(s, 'mvc') -end - -local B = 0x10000 - --- rough adaptation of Knuth float generator -function _M.krandom( seedobj, fVal1, fVal2 ) - local ma = seedobj.ma - local seed = seedobj.seed - local mj, mk - if seed < 0 or not ma then - ma = {} - seedobj.ma = ma - mj = normalize( seed ) - mj = mod( mj, B ) - ma[55] = mj - mk = 1 - for i = 1, 54 do - local ii = mod( 21 * i, 55 ) - ma[ii] = mk - mk = mj - mk - if mk < 0 then mk = mk + B end - mj = ma[ii] - end - for k = 1, 4 do - for i = 1, 55 do - ma[i] = ma[i] - ma[ 1 + mod( i + 30, 55) ] - if ma[i] < 0 then ma[i] = ma[i] + B end - end - end - seedobj.inext = 0 - seedobj.inextp = 31 - seedobj.seed = 1 - end -- if - local inext = seedobj.inext - local inextp = seedobj.inextp - inext = inext + 1 - if inext == 56 then inext = 1 end - seedobj.inext = inext - inextp = inextp + 1 - if inextp == 56 then inextp = 1 end - seedobj.inextp = inextp - mj = ma[ inext ] - ma[ inextp ] - if mj < 0 then mj = mj + B end - ma[ inext ] = mj - local temp_rand = mj / B - if fVal2 then - return floor( fVal1 + 0.5 + temp_rand * ( fVal2 - fVal1 ) ) - elseif fVal1 then - return floor( temp_rand * fVal1 ) + 1 - else - return temp_rand - end -end - --- Sys rand -sys_rand = {} -sys_rand.__index = sys_rand -function sys_rand:random(a, b) - local diff = 0 - if a and b and a == b then math.random(); return a end - if a and b then - if a < 0 then - diff = abs(a) - a = a + diff - b = b + diff - end - return math.random(a, b) - diff - end - if a and a == 0 then return floor(math.random() * 0x10000) end - if a then return math.random(a) end - return math.random() -end - -function sys_rand:randomseed(s) - -- ignore - return -end - -function _M.sys_rand(s) - local temp = {} - setmetatable(temp, sys_rand) - return temp -end - -return _M \ No newline at end of file diff --git a/locale/rso/metaball.lua b/locale/rso/metaball.lua deleted file mode 100644 index 09b207c..0000000 --- a/locale/rso/metaball.lua +++ /dev/null @@ -1,104 +0,0 @@ ---[[-- -Metaball implementation for LUA by Dark -For bruteforce usage, nor efficient nor fast - -Force scales to from inf to 1 at R ---]]-- -local _M = {} -local sqrt = math.sqrt -local cos = math.cos -local sin = math.sin -local abs = math.abs -local zero_value = 0x80000000 - ---Classic ball -local MetaBall = {x=0, y=0, radius=0, goo=1, type="MetaBall"} -MetaBall.__index = MetaBall -_M.MetaBall=MetaBall - -function MetaBall:new(x, y, radius, goo) - goo = goo or 1 - return setmetatable({x=x, y=y, radius=radius, goo=goo}, MetaBall) -end - -function MetaBall:force(x, y) - --Calculate force at point x y - local force = sqrt( (x - self.x)^2 + (y - self.y)^2 ) - if force == 0 then return zero_value end - return (self.radius / force)^self.goo -end - ---Ellipse -local MetaEllipse = {x=0, y=0, radius=0, angle=0, x_scale=1, y_scale=1, type="MetaEllipse"} -MetaEllipse.__index = MetaEllipse -_M.MetaEllipse=MetaEllipse - -function MetaEllipse:new(x, y, radius, angle, x_scale, y_scale, goo) - angle = angle or 0 - x_scale = x_scale or 1 - y_scale = y_scale or 1 - goo = goo or 1 - cosa = cos(angle) - sina = sin(angle) - return setmetatable({x=x, y=y, radius=radius, angle=angle, x_scale=x_scale, y_scale=y_scale, goo=goo, cosa=cosa, sina=sina}, MetaEllipse) -end - -function MetaEllipse:force(x, y) - --Calculate force at point x y - local force = sqrt( (( (x - self.x)*self.cosa + (y - self.y)*self.sina )^2)/(self.x_scale) + - (( (y - self.y)*self.cosa - (x - self.x)*self.sina )^2)/(self.y_scale) ) - if force == 0 then return zero_value end - return (self.radius / force)^self.goo -end - ---SquareBalls -local MetaSquare = {x=0, y=0, radius=0, angle=0, x_scale=1, y_scale=1, type="MetaSquare"} -MetaSquare.__index = MetaSquare -_M.MetaSquare=MetaSquare - -function MetaSquare:new(x, y, radius, angle, x_scale, y_scale, goo) - angle = angle or 0 - x_scale = x_scale or 1 - y_scale = y_scale or 1 - goo = goo or 1 - cosa = cos(angle) - sina = sin(angle) - return setmetatable({x=x, y=y, radius=radius, angle=angle, x_scale=x_scale, y_scale=y_scale, goo=goo, cosa=cosa, sina=sina}, MetaSquare) -end - -function MetaSquare:force(x, y) - --Calculate force at point x y - local force = ( abs( (x - self.x)*self.cosa + (y - self.y)*self.sina )/self.x_scale + - abs( (y - self.y)*self.cosa - (x - self.x)*self.sina )/self.y_scale ) - if force == 0 then return zero_value end - return (self.radius / force)^self.goo -end - ---Donuts -local MetaDonut = {x=0, y=0, radius=0, angle=0, x_scale=1, y_scale=1, type="MetaDonut"} -MetaDonut.__index = MetaDonut -_M.MetaDonut=MetaDonut - -function MetaDonut:new(x, y, out_r, int_r, angle, x_scale, y_scale, goo) - angle = angle or 0 - x_scale = x_scale or 1 - y_scale = y_scale or 1 - goo = goo or 1 - cosa = cos(angle) - sina = sin(angle) - if int_r >= out_r then error("int_r >= out_r ("..int_r.." > "..out_r); return; end - local radius = out_r--(out_r - int_r)*0.5 - local radius2 = int_r--(radius2 + radius)*0.5 - return setmetatable({x=x, y=y, radius=radius, radius2=radius2, x_scale=x_scale, y_scale=y_scale, goo=goo, cosa=cosa, sina=sina}, MetaDonut) -end - -function MetaDonut:force(x, y) - --Calculate force at point x y - local force = abs(self.radius - sqrt( (( (x - self.x)*self.cosa + (y - self.y)*self.sina )^2)/(self.x_scale) + - (( (y - self.y)*self.cosa - (x - self.x)*self.sina )^2)/(self.y_scale) )) - if force == 0 then return zero_value end - return (self.radius2 / force)^self.goo - -end - -return _M \ No newline at end of file diff --git a/locale/rso/rso_config.lua b/locale/rso/rso_config.lua deleted file mode 100644 index b61e4b0..0000000 --- a/locale/rso/rso_config.lua +++ /dev/null @@ -1,55 +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 -- 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= 1 -- exponent for richness distance factor calculation -fluid_richness_distance_factor = 0.8 -- exponent for richness distance factor calculation for fluids -size_distance_factor=0.15 -- exponent for size distance factor calculation - -deterministic = false -- 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 - -fluidResourcesFactor = 20 -- temporary factor for calculation of resource %-ages for fluids - -- -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 diff --git a/locale/rso/rso_control.lua b/locale/rso/rso_control.lua deleted file mode 100644 index 4daa04a..0000000 --- a/locale/rso/rso_control.lua +++ /dev/null @@ -1,1406 +0,0 @@ -require("locale/rso/rso_config") -require("util") -require("locale/rso/rso_resource_config") -require("locale/oarc_utils") -require("config") - -local MB=require("locale/rso/metaball") -local drand = require("locale/rso/drand") -local rng = drand.mwvc -if not deterministic then rng = drand.sys_rand end - --- math shortcuts -local floor = math.floor -local abs = math.abs -local cos = math.cos -local sin = math.sin -local pi = math.pi -local max = math.max - -local function round(value) - return math.floor(value + 0.5) -end - -local function debug(str) - if debug_enabled then - game.players[1].print(str) - end -end - --- constants -local CHUNK_SIZE = 32 -local REGION_TILE_SIZE = CHUNK_SIZE*region_size -local MIN_BALL_DISTANCE = CHUNK_SIZE/6 -local P_BALL_SIZE_FACTOR = 0.7 -local N_BALL_SIZE_FACTOR = 0.95 -local NEGATIVE_MODIFICATOR = 123456 - -local meta_shapes = nil - -if use_donut_shapes then - meta_shapes = {MB.MetaEllipse, MB.MetaSquare, MB.MetaDonut} -else - meta_shapes = {MB.MetaEllipse, MB.MetaSquare} -end - --- local globals -local index_is_built = false -local max_allotment = 0 -local rgen = nil -local distance = util.distance -local spawner_probability_edge = 0 -- below this value a biter spawner, above/equal this value a spitter spawner -local invalidResources = {} -local config = nil -local configIndexed = nil - --- map gen settings mapping - -local startingAreaMultiplier = -{ - none = 0, - ["very-low"] = 0.25, - low = 0.5, - normal = 1, - high = 1.5, - ["very-high"] = 2, -} - -local frequencyAllotmentMultiplier = -{ - ["very-low"] = 0.5, - low = 0.75, - normal = 1, - high = 1.5, - ["very-high"] = 2, -} - -local sizeMultiplier = -{ - none = 0, - ["very-low"] = 0.5, - low = 0.75, - normal = 1, - high = 1.25, - ["very-high"] = 1.5, -} - -local richnessMultiplier = -{ - ["very-low"] = 0.125, - low = 0.25, - normal = 1, - high = 2, - ["very-high"] = 4, -} - -local entityFrequencyMultiplier = -{ - ["very-low"] = 0.25, - low = 0.5, - normal = 1, - high = 2, - ["very-high"] = 4, -} - -local entitySizeMultiplier = -{ - none = 0, - ["very-low"] = 0.5, - low = 0.75, - normal = 1, - high = 2, - ["very-high"] = 4, -} - ---[[ HELPER METHODS ]]-- - -local function normalize(n) --keep numbers at (positive) 32 bits - return floor(n) % 0x80000000 -end - -local function bearing(origin, dest) - -- finds relative angle - local xd = dest.x - origin.x - local yd = dest.y - origin.y - return math.atan2(xd, yd); -end - -local function str2num(s) - local num = 0 - for i=1,s:len() do - num=num + (s:byte(i) - 33)*i - end - return num -end - -local function mult_for_pos(pos) - local num = 0 - local x = pos.x - local y = pos.y - - if x == 0 then x = 0.5 end - if y == 0 then y = 0.5 end - if x < 0 then - x = abs(x) + NEGATIVE_MODIFICATOR - end - if y < 0 then - y = abs(y) + NEGATIVE_MODIFICATOR - end - - return drand.lcg(y, 'mvc'):random(0)*drand.lcg(x, 'nr'):random(0) -end - -local function rng_for_reg_pos(pos) - local rgen = rng(normalize(global.seed*mult_for_pos(pos))) - rgen:random() - rgen:random() - rgen:random() - return rgen -end - -local function rng_restricted_angle(restrictions) - local rng = rgen:random() - local x_scale, y_scale - local deformX = rgen:random() * 2 - 1 - local deformY = rgen:random() * 2 - 1 - - if restrictions=='xy' then - y_scale=1.0 + deformY*0.5 - x_scale=1.0 + deformX*0.5 - angle = rng*pi*2 - elseif restrictions=='x' then - y_scale=1.0 + deformY*0.6 - x_scale=1.0 + deformX*0.6 - angle = rng*pi/2 - pi/4 - elseif restrictions=='y' then - y_scale=1.0 + deformY*0.6 - x_scale=1.0 + deformX*0.6 - angle = rng*pi/2 + pi/2 - else - y_scale=1.0 + deformY*0.3 - x_scale=1.0 + deformX*0.3 - angle = rng*pi*2 - end - - return angle, x_scale, y_scale -end - -local function vary_by_percentage(x, p) - return x + (0.5 - rgen:random())*2*x*p -end - - -local function remove_trees(surface, x, y, x_size, y_size ) - local bb={{x - x_size, y - y_size}, {x + x_size, y + y_size}} - for _, entity in pairs(surface.find_entities_filtered{area = bb, type="tree"}) do - if entity.valid then - entity.destroy() - end - end -end - -local function removeDecorations(surface, x, y, width, height ) - local bb={{x, y}, {x + width, y + height}} - for _, entity in pairs(surface.find_entities_filtered{area = bb, type="decorative"}) do - if entity.valid then - entity.destroy() - end - end -end - -local function find_intersection(surface, x, y) - -- try to get position in between of valid chunks by probing map - -- this may breaks determinism of generation, but so far it returned on first if - local gt = surface.get_tile - local restriction = '' - if gt(x + CHUNK_SIZE*2, y + CHUNK_SIZE*2).valid and gt(x - CHUNK_SIZE*2, y - CHUNK_SIZE*2).valid and gt(x + CHUNK_SIZE*2, y - CHUNK_SIZE*2).valid and gt(x - CHUNK_SIZE*2, y + CHUNK_SIZE*2).valid then - restriction = 'xy' - elseif gt(x + CHUNK_SIZE*2, y + CHUNK_SIZE*2).valid and gt(x + CHUNK_SIZE*2, y).valid and gt(x, y + CHUNK_SIZE*2).valid then - x=x + CHUNK_SIZE/2 - y=y + CHUNK_SIZE/2 - restriction = 'xy' - elseif gt(x + CHUNK_SIZE*2, y - CHUNK_SIZE*2).valid and gt(x + CHUNK_SIZE*2, y).valid and gt(x, y - CHUNK_SIZE*2).valid then - x=x + CHUNK_SIZE/2 - y=y - CHUNK_SIZE/2 - restriction = 'xy' - elseif gt(x - CHUNK_SIZE*2, y + CHUNK_SIZE*2).valid and gt(x - CHUNK_SIZE*2, y).valid and gt(x, y + CHUNK_SIZE*2).valid then - x=x - CHUNK_SIZE/2 - y=y + CHUNK_SIZE/2 - restriction = 'xy' - elseif gt(x - CHUNK_SIZE*2, y - CHUNK_SIZE*2).valid and gt(x - CHUNK_SIZE*2, y).valid and gt(x, y - CHUNK_SIZE*2).valid then - x=x - CHUNK_SIZE/2 - y=y - CHUNK_SIZE/2 - restriction = 'xy' - elseif gt(x + CHUNK_SIZE*2, y).valid then - x=x + CHUNK_SIZE/2 - restriction = 'x' - elseif gt(x - CHUNK_SIZE*2, y).valid then - x=x - CHUNK_SIZE/2 - restriction = 'x' - elseif gt(x, y + CHUNK_SIZE*2).valid then - y=y + CHUNK_SIZE/2 - restriction = 'y' - elseif gt(x, y - CHUNK_SIZE*2).valid then - y=y - CHUNK_SIZE/2 - restriction = 'y' - end - return x, y, restriction -end - -local function find_random_chunk(r_x, r_y) - local offset_x=rgen:random(region_size)-1 - local offset_y=rgen:random(region_size)-1 - local c_x=r_x*REGION_TILE_SIZE + offset_x*CHUNK_SIZE - local c_y=r_y*REGION_TILE_SIZE + offset_y*CHUNK_SIZE - return c_x, c_y -end - -local function is_same_region(c_x1, c_y1, c_x2, c_y2) - if not floor(c_x1/REGION_TILE_SIZE) == floor(c_x2/REGION_TILE_SIZE) then - return false - end - if not floor(c_y1/REGION_TILE_SIZE) == floor(c_y2/REGION_TILE_SIZE) then - return false - end - return true -end - -local function find_random_neighbour_chunk(ocx, ocy) - -- somewhat bruteforce and unoptimized - local x_dir = rgen:random(-1,1) - local y_dir = rgen:random(-1,1) - local ncx = ocx + x_dir*CHUNK_SIZE - local ncy = ocy + y_dir*CHUNK_SIZE - if is_same_region(ncx, ncy, ocx, ocy) then - return ncx, ncy - end - - ncx = ocx - x_dir*CHUNK_SIZE - ncy = ocy - y_dir*CHUNK_SIZE - if is_same_region(ncx, ncy, ocx, ocy) then - return ncx, ncy - end - - ncx = ocx - x_dir*CHUNK_SIZE - if is_same_region(ncx, ocy, ocx, ocy) then - return ncx, ocy - end - - ncy = ocy - y_dir*CHUNK_SIZE - if is_same_region(ocx, ncy, ocx, ocy) then - return ocx, ncy - end - - return ocx, ocy -end - -local function isInStartingArea( regionX, regionY ) - - for idx, pos in pairs( global.startingAreas ) do - - local adjustedX = regionX - pos.x / REGION_TILE_SIZE - local adjustedY = regionY - pos.y / REGION_TILE_SIZE - if ((adjustedX * adjustedX + adjustedY * adjustedY) <= starting_area_size * starting_area_size) then - return true - end - end - - return false -end - --- OARC SPECIFIC FUNCTION -- --- Checks if a point is near a spawn area -local function isNearOarcSpawn(pointPos) - - if (global.uniqueSpawns) and (ENFORCE_LAND_AREA_TILE_DIST) then - for name,spawn in pairs(global.uniqueSpawns) do - local clearArea = GetAreaFromPointAndDistance(spawn.pos, - (ENFORCE_LAND_AREA_TILE_DIST+2*CHUNK_SIZE)) - if (CheckIfInArea(pointPos,clearArea)) then - return true - end - end - end - - return false -end - --- modifies the resource size - only used in endless_resource_mode -local function modify_resource_size(resourceName, resourceSize, startingArea) - - if not startingArea then - resourceSize = math.ceil(resourceSize * global_size_mult) - end - - resourceEntity = game.entity_prototypes[resourceName] - if resourceEntity and resourceEntity.infinite_resource then - - newResourceSize = resourceSize * endless_resource_mode_sizeModifier - - -- make sure it's still an integer - newResourceSize = math.ceil(newResourceSize) - -- make sure it's not 0 - if newResourceSize == 0 then newResourceSize = 1 end - return newResourceSize - else - return resourceSize - end -end - ---[[ SPAWN METHODS ]]-- - -local locationOrder = -{ - { x = 0, y = 0 }, - { x = -1, y = 0 }, - { x = 1, y = 0 }, - { x = 0, y = -1 }, - { x = 0, y = 1 }, - { x = -1, y = -1 }, - { x = 1, y = -1 }, - { x = -1, y = 1 }, - { x = 1, y = 1 } -} - ---[[ entity-field ]]-- -local function spawn_resource_ore(surface, rname, pos, size, richness, startingArea, restrictions) - -- blob generator, centered at pos, size controls blob diameter - restrictions = restrictions or '' - debug("Entering spawn_resource_ore "..rname.." at:"..pos.x..","..pos.y.." size:"..size.." richness:"..richness.." isStart:"..tostring(startingArea).." restrictions:"..restrictions) - - size = modify_resource_size(rname, size, startingArea) - local radius = size / 2 -- to radius - - local p_balls={} - local n_balls={} - local MIN_BALL_DISTANCE = math.min(MIN_BALL_DISTANCE, radius/2) - - local maxPradius = 0 - local outside = { xmin = 1e10, xmax = -1e10, ymin = 1e10, ymax = -1e10 } - local inside = { xmin = 1e10, xmax = -1e10, ymin = 1e10, ymax = -1e10 } - - local function adjustRadius(radius, scaleX, scaleY, up) - return radius - end - - local function updateRect(rect, x, y, radius) - rect.xmin = math.min(rect.xmin, x - radius) - rect.xmax = math.max(rect.xmax, x + radius) - rect.ymin = math.min(rect.ymin, y - radius) - rect.ymax = math.max(rect.ymax, y + radius) - end - - local function updateRects(x, y, radius, scaleX, scaleY) - local adjustedRadius = adjustRadius(radius, scaleX, scaleY, true) - local radiusMax = adjustedRadius * 3 -- arbitrary multiplier - needs to be big enough to not cut any metaballs - updateRect(outside, x, y, radiusMax) - updateRect(inside, x, y, adjustedRadius) - end - - local function generate_p_ball() - local angle, x_scale, y_scale, x, y, b_radius, shape - angle, x_scale, y_scale=rng_restricted_angle(restrictions) - local dev = radius / 2 + rgen:random() * radius / 4--math.min(CHUNK_SIZE/3, radius*1.5) - local dev_x, dev_y = pos.x, pos.y - x = rgen:random(-dev, dev)+dev_x - y = rgen:random(-dev, dev)+dev_y - if p_balls[#p_balls] and distance(p_balls[#p_balls], {x=x, y=y}) < MIN_BALL_DISTANCE then - local new_angle = bearing(p_balls[#p_balls], {x=x, y=y}) - debug("Move ball old xy @ "..x..","..y) - x=(cos(new_angle)*MIN_BALL_DISTANCE) + x - y=(sin(new_angle)*MIN_BALL_DISTANCE) + y - debug("Move ball new xy @ "..x..","..y) - end - - if #p_balls == 0 then - b_radius = ( 3 * radius / 4 + rgen:random() * radius / 4) -- * (P_BALL_SIZE_FACTOR^#p_balls) - else - b_radius = ( radius / 4 + rgen:random() * radius / 2) -- * (P_BALL_SIZE_FACTOR^#p_balls) - end - - - if #p_balls > 0 then - local tempRect = table.deepcopy(inside) - updateRect(tempRect, x, y, adjustRadius(b_radius, x_scale, y_scale)) - local rectSize = math.max(tempRect.xmax - tempRect.xmin, tempRect.ymax - tempRect.ymin) - local targetSize = size * 1.25 - debug("Rect size "..rectSize.." targetSize "..targetSize) - if rectSize > targetSize then - local widthLeft = (targetSize - (inside.xmax - inside.xmin)) - local heightLeft = (targetSize - (inside.ymax - inside.ymin)) - local widthMod = math.min(x - inside.xmin, inside.xmax - x) - local heightMod = math.min(y - inside.ymin, inside.ymax - y) - local radiusBackup = b_radius - b_radius = math.min(widthLeft + widthMod, heightLeft + heightMod) - b_radius = adjustRadius(b_radius, x_scale, y_scale, false) - debug("Reduced ball radius from "..radiusBackup.." to "..b_radius.." widthLeft:"..widthLeft.." heightLeft:"..heightLeft.." widthMod:"..widthMod.." heightMod:"..heightMod) - end - end - - if b_radius < 2 and #p_balls == 0 then - b_radius = 2 - end - - if b_radius > 0 then - - maxPradius = math.max(maxPradius, b_radius) - shape = meta_shapes[rgen:random(1,#meta_shapes)] - local radiusText = "" - if shape.type == "MetaDonut" then - local inRadius = b_radius / 4 + b_radius / 2 * rgen:random() - radiusText = " inRadius:"..inRadius - p_balls[#p_balls+1] = shape:new(x, y, b_radius, inRadius, angle, x_scale, y_scale, 1.1) - else - p_balls[#p_balls+1] = shape:new(x, y, b_radius, angle, x_scale, y_scale, 1.1) - end - updateRects(x, y, b_radius, x_scale, y_scale) - - debug("P+Ball "..shape.type.." @ "..x..","..y.." radius: "..b_radius..radiusText.." angle: "..math.deg(angle).." scale: "..x_scale..", "..y_scale) - end - end - - local function generate_n_ball(i) - local angle, x_scale, y_scale, x, y, b_radius, shape - angle, x_scale, y_scale=rng_restricted_angle('xy') - if p_balls[i] then - local new_angle = p_balls[i].angle + pi*rgen:random(0,1) + (rgen:random()-0.5)*pi/2 - local dist = p_balls[i].radius - x=(cos(new_angle)*dist) + p_balls[i].x - y=(sin(new_angle)*dist) + p_balls[i].y - angle = p_balls[i].angle + pi/2 + (rgen:random()-0.5)*pi*2/3 - else - x = rgen:random(-radius, radius)+pos.x - y = rgen:random(-radius, radius)+pos.y - end - - if p_balls[i] then - b_radius = (p_balls[i].radius / 4 + rgen:random() * p_balls[i].radius / 2) -- * (N_BALL_SIZE_FACTOR^#n_balls) - else - b_radius = (radius / 4 + rgen:random() * radius / 2) -- * (N_BALL_SIZE_FACTOR^#n_balls) - end - - if b_radius < 1 then - b_radius = 1 - end - - shape = meta_shapes[rgen:random(1,#meta_shapes)] - local radiusText = "" - if shape.type == "MetaDonut" then - local inRadius = b_radius / 4 + b_radius / 2 * rgen:random() - radiusText = " inRadius:"..inRadius - n_balls[#n_balls+1] = shape:new(x, y, b_radius, inRadius, angle, x_scale, y_scale, 1.15) - else - n_balls[#n_balls+1] = shape:new(x, y, b_radius, angle, x_scale, y_scale, 1.15) - end - -- updateRects(x, y, b_radius, x_scale, y_scale) -- should not be needed here - only positive ball can generate ore - debug("N-Ball "..shape.type.." @ "..x..","..y.." radius: "..b_radius..radiusText.." angle: "..math.deg(angle).." scale: "..x_scale..", "..y_scale) - end - - local function calculate_force(x,y) - local p_force = 0 - local n_force = 0 - for _,ball in ipairs(p_balls) do - p_force = p_force + ball:force(x,y) - end - for _,ball in ipairs(n_balls) do - n_force = n_force + ball:force(x,y) - end - local totalForce = 0 - if p_force > n_force then - totalForce = 1 - 1/(p_force - n_force) - end - --debug("Force at "..x..","..y.." p:"..p_force.." n:"..n_force.." result:"..totalForce) - --return (1 - 1/p_force) - n_force - return totalForce - end - - local max_p_balls = 2 - local min_amount = config[rname].min_amount or min_amount - if restrictions == 'xy' then - max_p_balls = 3 - end - - radius = math.min(radius, 2*CHUNK_SIZE) - - local force - -- generate blobs - for i=1,max_p_balls do - generate_p_ball() - end - - for i=1,rgen:random(1, #p_balls) do - generate_n_ball(i) - end - - - local _total = 0 - local oreLocations = {} - local forceTotal = 0 - - -- fill the map - for y=outside.ymin, outside.ymax do - - for x=outside.xmin, outside.xmax do - force = calculate_force(x, y) - if force > 0 then - oreLocations[#oreLocations + 1] = {x = x, y = y, force = force, valid = false} - forceTotal = forceTotal + force - end - end - end - - local validCount, resOffsetX, resOffsetY, ratio - - for _,locationOffset in ipairs(locationOrder) do - validCount = 0 - resOffsetX = locationOffset.x * CHUNK_SIZE - resOffsetY = locationOffset.y * CHUNK_SIZE - - for _, location in ipairs(oreLocations) do - - local newX = location.x + resOffsetX - local newY = location.y + resOffsetY - location.valid = false - if surface.can_place_entity{name = rname, position = {x = newX,y = newY}} then - location.valid = true - validCount = validCount + 1 - end - end - - ratio = 0 - - if validCount > 0 then - ratio = validCount / #oreLocations - end - - debug("Valid ratio ".. ratio) - - if not useResourceCollisionDetection then - break - end - - if ratio > resourceCollisionDetectionRatio then - break - elseif resourceCollisionFieldSkip then -- in case no valid ratio was found we skip the field completely - validCount = 0 - end - end - - if validCount > 0 then - local rectSize = ((inside.xmax - inside.xmin) + (inside.ymax - inside.ymin)) / 2 - - local sizeMultiplier = rectSize ^ 0.6 - local minSize = richness * 5 * sizeMultiplier - local maxSize = richness * 10 * sizeMultiplier - local approxDepositSize = rgen:random(minSize, maxSize) - - approxDepositSize = approxDepositSize - validCount * min_amount - - if approxDepositSize < 0 then - approxDepositSize = 100 * validCount - end - - local forceFactor = approxDepositSize / forceTotal - - -- don't create very dense resources in starting area - another field will be generated - if startingArea and forceFactor > 4000 then - forceFactor = rgen:random(3000, 4000) - end - - debug( "Force total:"..forceTotal.." sizeMin:"..minSize.." sizeMax:"..maxSize.." factor:"..forceFactor.." location#:"..validCount.." rectSize:"..rectSize.." sizeMultiplier:"..sizeMultiplier) - local richnessMultiplier = global_richness_mult - - if startingArea then - richnessMultiplier = starting_richness_mult - end - - -- infinite ore handling for Angels Ores mod - local infiniteOrePresent = false - local infiniteOreName = "infinite-"..rname - local minimumInfiniteOreAmount = nil - local spawnName = rname - - if game.entity_prototypes[infiniteOreName] then - infiniteOrePresent = true - minimumInfiniteOreAmount = game.entity_prototypes[infiniteOreName].minimum_resource_amount - end - - if startingArea and not infiniteResourceInStartArea then - infiniteOrePresent = false - end - - for _,location in ipairs(oreLocations) do - if location.valid then - - local amount = floor(( forceFactor * location.force + min_amount ) * richnessMultiplier) - - if amount > 1e9 then - amount = 1e9 - end - - _total = _total + amount - - spawnName = rname - if infiniteOrePresent and location.force > infiniteResourceSpawnThreshold then - spawnName = infiniteOreName - if minimumInfiniteOreAmount and amount < minimumInfiniteOreAmount then - amount = minimumInfiniteOreAmount - end - end - - if amount > 0 then - surface.create_entity{name = spawnName, - position = {location.x + resOffsetX,location.y + resOffsetY}, - force = game.forces.neutral, - amount = amount} - end - end - end - - end - - if debug_enabled then - debug("Total amount: ".._total) - debug("Leaving spawn_resource_ore") - end - return _total -end - ---[[ entity-liquid ]]-- -local function spawn_resource_liquid(surface, rname, pos, size, richness, startingArea, restrictions) - restrictions = restrictions or '' - debug("Entering spawn_resource_liquid "..rname.." "..pos.x..","..pos.y.." "..size.." "..richness.." "..tostring(startingArea).." "..restrictions) - local _total = 0 - local max_radius = rgen:random()*CHUNK_SIZE/2 + CHUNK_SIZE - - richness = ( 0.75 + rgen:random() / 2 ) * richness * size - - resourceEntity = game.entity_prototypes[rname] - - - local total_share = 0 - local avg_share = 1/size - local angle = rgen:random()*pi*2 - local saved = 0 - while total_share < 1 do - local new_share = vary_by_percentage(avg_share, 0.25) - if new_share + total_share > 1 then - new_share = 1 - total_share - end - total_share = new_share + total_share - if new_share < avg_share/10 then - -- too small - break - end - local amount = floor(richness*new_share) + saved - - local richnessMultiplier = global_richness_mult - - if startingArea then - richnessMultiplier = starting_richness_mult - end - - --if amount >= game.entity_prototypes[rname].minimum then - if amount >= config[rname].minimum_amount then - saved = 0 - for try=1,5 do - local dist = rgen:random()*(max_radius - max_radius*0.1) - angle = angle + pi/4 + rgen:random()*pi/2 - local x, y = pos.x + cos(angle)*dist, pos.y + sin(angle)*dist - if surface.can_place_entity{name = rname, position = {x,y}} then - debug("@ "..x..","..y.." amount: "..amount.." new_share: "..new_share.." try: "..try) - amount = floor(amount * richnessMultiplier) - - if amount > 1e9 then - amount = 1e9 - end - - _total = _total + amount - - if amount > 0 then - surface.create_entity{name = rname, - position = {x,y}, - force = game.forces.neutral, - amount = amount, - direction = rgen:random(4)} - end - break - elseif not startingArea then -- we don't want to make ultra rich nodes in starting area - failing to make them will add second spawn in different location - entities = surface.find_entities_filtered{area = {{x-2.75, y-2.75}, {x+2.75, y+2.75}}, name=rname} - if entities and #entities > 0 then - _total = _total + amount - for k, ent in pairs(entities) do - ent.amount = ent.amount + floor(amount/#entities) - end - break - end - end - end - else - saved = amount - end - end - debug("Total amount: ".._total) - debug("Leaving spawn_resource_liquid") - return _total -end - -local spawnerTable = nil - -local function initSpawnerTable() - if spawnerTable == nil then - spawnerTable = {} - spawnerTable["biter-spawner"] = game.entity_prototypes["biter-spawner"] ~= nil - spawnerTable["bob-biter-spawner"] = game.entity_prototypes["bob-biter-spawner"] ~= nil - spawnerTable["spitter-spawner"] = game.entity_prototypes["spitter-spawner"] ~= nil - spawnerTable["bob-spitter-spawner"] = game.entity_prototypes["bob-spitter-spawner"] ~= nil - end -end - -local function spawn_entity(surface, ent, r_config, x, y) - if not use_RSO_biter_spawning then return end - local size=rgen:random(r_config.size.min, r_config.size.max) - - local _total = 0 - local r_distance = distance({x=0,y=0},{x=x/REGION_TILE_SIZE,y=y/REGION_TILE_SIZE}) - - local distanceMultiplier = math.min(r_distance^r_config.size_per_region_factor, 5) - if r_config.size_per_region_factor then - size = size*distanceMultiplier - end - - size = size * enemy_base_size_multiplier - - debug("Entering spawn_entity "..ent.." "..x..","..y.." "..size) - - local maxAttemptCount = 5 - local distancePerAttempt = 0.2 - - initSpawnerTable() - - for i=1,size do - for attempt = 1, maxAttemptCount do - local richness=r_config.richness*(r_distance^richness_distance_factor) - local max_d = floor(CHUNK_SIZE*(0.5 + distancePerAttempt*attempt)) - local s_x = x + rgen:random(0, floor(max_d - r_config.clear_range[1])) - max_d/2 + r_config.clear_range[1] - local s_y = y + rgen:random(0, floor(max_d - r_config.clear_range[2])) - max_d/2 + r_config.clear_range[2] - - if surface.get_tile(s_x, s_y).valid then - - remove_trees(surface, s_x, s_y, r_config.clear_range[1], r_config.clear_range[2]) - - local spawnerName = nil - - if spawner_probability_edge > 0 then - - bigSpawnerChance = rgen:random() - - if rgen:random() < spawner_probability_edge then - if ( useBobEntity and bigSpawnerChance > 0.75 ) then - spawnerName = "bob-biter-spawner" - else - spawnerName = "biter-spawner" - end - else - if ( useBobEntity and bigSpawnerChance > 0.75 ) then - spawnerName = "bob-spitter-spawner" - else - spawnerName = "spitter-spawner" - end - end - end - - if spawnerName and spawnerTable[spawnerName] then - if surface.can_place_entity{name=spawnerName, position={s_x, s_y}} then - _total = _total + richness - debug(spawnerName.." @ "..s_x..","..s_y.." placed on "..attempt.." attempt") - - surface.create_entity{name=spawnerName, position={s_x, s_y}, force=game.forces[r_config.force], amount=floor(richness)}--, direction=rgen:random(4) - -- else - -- debug("Entity "..spawnerName.." spawn failed") - break; - else - if attempt == maxAttemptCount then - debug(spawnerName.." @ "..s_x..","..s_y.." failed to spawn") - end - end - else - debug("Entity "..spawnerName.." doesn't exist") - end - end - end - - if r_config.sub_spawn_probability then - local sub_spawn_prob = r_config.sub_spawn_probability*math.min(r_config.sub_spawn_max_distance_factor, r_config.sub_spawn_distance_factor^r_distance) - if rgen:random() < sub_spawn_prob then - for i=1,(rgen:random(r_config.sub_spawn_size.min, r_config.sub_spawn_size.max)*distanceMultiplier) do - local allotment_max = 0 - -- build table - for k,v in pairs(r_config.sub_spawns) do - if not v.min_distance or r_distance > v.min_distance then - local allotment = v.allotment - if v.allotment_distance_factor then - allotment = allotment * (v.allotment_distance_factor^r_distance) - end - v.allotment_range ={min = allotment_max, max = allotment_max + allotment} - allotment_max = allotment_max + allotment - else - v.allotment_range = nil - end - end - local sub_type = rgen:random(0, allotment_max) - for sub_spawn,v in pairs(r_config.sub_spawns) do - if v.allotment_range and sub_type >= v.allotment_range.min and sub_type <= v.allotment_range.max then - for attempt = 1, maxAttemptCount do - local max_d = floor(CHUNK_SIZE*distancePerAttempt*attempt) - s_x = x + rgen:random(max_d) - max_d/2 - s_y = y + rgen:random(max_d) - max_d/2 - remove_trees(surface, s_x, s_y, v.clear_range[1], v.clear_range[2]) - if surface.can_place_entity{name=sub_spawn, position={s_x, s_y}} then - surface.create_entity{name=sub_spawn, position={s_x, s_y}, force=game.forces[r_config.force]}--, direction=rgen:random(4) - debug("Rolled subspawn "..sub_spawn.." @ "..s_x..","..s_x.." after "..attempt.." attempts") - break; - else - if attempt == maxAttemptCount then - debug("Rolling subspawn "..sub_spawn.." @ "..s_x..","..s_x.." failed") - end - end - end - break - end - end - end - end - end - end - debug("Total amount: ".._total) - debug("Leaving spawn_entity") -end - ---[[ EVENT/INIT METHODS ]]-- - -local function spawn_starting_resources( surface, index ) - - if global.startingAreas[index].spawned then return end - if surface.map_gen_settings.starting_area == "none" and not ignoreMapGenSettings then return end -- starting area disabled by map gen - if starting_area_size < 0.1 then return end -- skip spawning if starting area is to small - - local position = global.startingAreas[index] - - rgen = rng_for_reg_pos( position ) - local status = true - for index,v in ipairs(configIndexed) do - if v.starting then - local prob = rgen:random() -- probability that this resource is spawned - debug("starting resource probability rolled "..prob) - if v.starting.probability > 0 and prob <= v.starting.probability then - local total = 0 - local radius = 25 - local min_threshold = 0 - - if v.type == "resource-ore" then - min_threshold = v.starting.richness * rgen:random(5, 10) -- lets make sure that there is at least 10-15 times starting richness ore at start - elseif v.type == "resource-liquid" then - min_threshold = v.starting.richness * 0.5 * v.starting.size - end - - while (radius < 200) and (total < min_threshold) do - local angle = rgen:random() * pi * 2 - local dist = rgen:random() * 30 + radius * 2 - local pos = { x = floor(cos(angle) * dist) + position.x, y = floor(sin(angle) * dist) + position.y } - if v.type == "resource-ore" then - total = total + spawn_resource_ore(surface, v.name, pos, v.starting.size, v.starting.richness, true) - elseif v.type == "resource-liquid" then - total = total + spawn_resource_liquid(surface, v.name, pos, v.starting.size, v.starting.richness, true) - end - radius = radius + 10 - end - if total < min_threshold then - status = false - end - end - end - end - - global.startingAreas[index].spawned = true -end - -local function modifyMinMax(value, mod) - value.min = round( value.min * mod ) - value.max = round( value.max * mod ) -end - -local function prebuild_config_data(surface) - if index_is_built then return false end - - local mapGenSettings = nil - - if not ignoreMapGenSettings then - mapGenSettings = surface.map_gen_settings - end - local autoPlaceSettings = nil - if mapGenSettings then - autoPlaceSettings = mapGenSettings.autoplace_controls - end - - configIndexed = {} - -- build additional indexed array to the associative array - for res_name, res_conf in pairs(config) do - if res_conf.valid then -- only add valid resources - res_conf.name = res_name - - local settingsForResource = nil - local isEntity = (res_conf.type == "entity") - local addResource = true - - local autoplaceName = res_name - - if res_conf.autoplace_name then - autoplaceName = res_conf.autoplace_name - end - - if autoPlaceSettings then - settingsForResource = autoPlaceSettings[autoplaceName] - end - - if settingsForResource then - local allotmentMod = nil - local sizeMod = nil - if isEntity then - allotmentMod = entityFrequencyMultiplier[settingsForResource.frequency] - sizeMod = entitySizeMultiplier[settingsForResource.size] - else - allotmentMod =frequencyAllotmentMultiplier[settingsForResource.frequency] - sizeMod = sizeMultiplier[settingsForResource.size] - end - - local richnessMod = richnessMultiplier[settingsForResource.richness] - - - debug(res_name .. " allotment mod " .. allotmentMod .. " size mod " .. sizeMod .. " richness mod " .. richnessMod ) - - - if allotmentMod then - if isEntity then - res_conf.absolute_probability = res_conf.absolute_probability * allotmentMod - debug("Entity chance modified to "..res_conf.absolute_probability) - else - res_conf.allotment = round( res_conf.allotment * allotmentMod ) - end - end - - if sizeMod ~= nil and sizeMod == 0 then - addResource = false - end - - if sizeMod then - modifyMinMax(res_conf.size, sizeMod) - - if res_conf.starting then - res_conf.starting.size = round( res_conf.starting.size * sizeMod ) - end - - if isEntity then - if res_conf.sub_spawn_size then - modifyMinMax(res_conf.sub_spawn_size, sizeMod) - end - modifyMinMax(res_conf.spawns_per_region, sizeMod) - end - end - - if richnessMod then - if type == "resource-ore" then - res_conf.richness = round( res_conf.richness * richnessMod ) - elseif type == "resource-liquid" then - modifyMinMax(res_conf.richness, richnessMod) - end - - if res_conf.starting then - res_conf.starting.richness = round( res_conf.starting.richness * richnessMod ) - end - end - end - - if addResource then - configIndexed[#configIndexed + 1] = res_conf - if res_conf.multi_resource and multi_resource_active then - local new_list = {} - for sub_res_name, allotment in pairs(res_conf.multi_resource) do - if config[sub_res_name] and config[sub_res_name].valid then - new_list[#new_list+1] = {name = sub_res_name, allotment = allotment} - end - end - table.sort(new_list, function(a, b) return a.name < b.name end) - res_conf.multi_resource = new_list - else - res_conf.multi_resource_chance = nil - end - end - end - end - - table.sort(configIndexed, function(a, b) return a.name < b.name end) - - local pr=0 - for index,v in pairs(config) do - if v.along_resource_probability then - v.along_resource_probability_range={min=pr, max=pr+v.along_resource_probability} - pr=pr+v.along_resource_probability - end - if v.allotment and v.allotment > 0 then - v.allotment_range={min=max_allotment, max=max_allotment+v.allotment} - max_allotment=max_allotment+v.allotment - end - end - - if mapGenSettings and mapGenSettings.starting_area then - local multiplier = startingAreaMultiplier[mapGenSettings.starting_area] - if multiplier ~= nil then - starting_area_size = starting_area_size * multiplier - debug("Starting area "..starting_area_size) - end - end - - index_is_built = true -end - --- set up the probabilty segments from which to roll between for biter and spitter spawners -local function calculate_spawner_ratio() - if (biter_ratio_segment ~= 0 and spitter_ratio_segment ~= 0) and biter_ratio_segment >= 0 and spitter_ratio_segment >= 0 then - spawner_probability_edge=biter_ratio_segment/(biter_ratio_segment+spitter_ratio_segment) -- normalize to between 0 and 1 - end -end - -local function checkConfigForInvalidResources() - --make sure that every resource in the config is actually available. - --call this function, before the auxiliary config is prebuilt! - if index_is_built then return end - - local prototypes = game.entity_prototypes - - for resourceName, resourceConfig in pairs(config) do - if prototypes[resourceName] or resourceConfig.type == "entity" then - resourceConfig.valid = true - else - -- resource was in config, but it doesn't exist in game files anymore - mark it invalid - resourceConfig.valid = false - - table.insert(invalidResources, "Resource not available: " .. resourceName) - debug("Resource not available: " .. resourceName) - end - - if resourceConfig.valid and resourceConfig.type ~= "entity" then - if prototypes[resourceName].autoplace_specification == nil then - resourceConfig.valid = false - debug("Resource "..resourceName.." invalidated - autoplace not present") - end - end - end -end - -local function roll_region(c_x, c_y) - --in what region is this chunk? - local r_x=floor(c_x/REGION_TILE_SIZE) - local r_y=floor(c_y/REGION_TILE_SIZE) - local r_data = nil - - --don't spawn stuff in starting area - if isInStartingArea( c_x/REGION_TILE_SIZE, c_y/REGION_TILE_SIZE ) then - return false - end - - -- Reroll regions every region_size^2 chunk generation calls. - local regrow_rso = false - if (ENABLE_REGROWTH) then - if (global.chunk_regrow.rso_region_roll_counter > (region_size*region_size/2)) then - regrow_rso = true - global.chunk_regrow.rso_region_roll_counter = 0 - else - global.chunk_regrow.rso_region_roll_counter = global.chunk_regrow.rso_region_roll_counter + 1 - end - end - - --if this chunk is the first in its region to be generated - -- or we're hitting a lucky regrowth reroll... - if (not (global.regions[r_x] and global.regions[r_x][r_y]) or regrow_rso) then - - if not global.regions[r_x] then global.regions[r_x] = {} end - global.regions[r_x][r_y]={} - r_data = global.regions[r_x][r_y] - rgen = rng_for_reg_pos{x=r_x,y=r_y} - - local rollCount = math.ceil(#configIndexed / 10) - 1 -- 0 based counter is more convenient here - rollCount = math.min(rollCount, 3) - - for rollNumber = 0,rollCount do - - local resourceChance = absolute_resource_chance - rollNumber * 0.1 - --absolute chance to spawn resource - local abct = rgen:random() - debug("Rolling resource "..abct.." against "..resourceChance.." roll "..rollNumber) - if abct <= resourceChance then - local res_type=rgen:random(1, max_allotment) - for index,v in ipairs(configIndexed) do - if v.allotment_range and ((res_type >= v.allotment_range.min) and (res_type <= v.allotment_range.max)) then - debug("Rolled primary resource "..v.name.." with res_type="..res_type.." @ "..r_x..","..r_y) - local num_spawns=rgen:random(v.spawns_per_region.min, v.spawns_per_region.max) - local last_spawn_coords = {} - local along_ - for i=1,num_spawns do - local c_x, c_y = find_random_chunk(r_x, r_y) - if not r_data[c_x] then r_data[c_x] = {} end - if not r_data[c_x][c_y] then r_data[c_x][c_y] = {} end - local c_data = r_data[c_x][c_y] - c_data[#c_data+1]={v.name, rollNumber} - last_spawn_coords[#last_spawn_coords+1] = {c_x, c_y} - debug("Rolled primary chunk "..v.name.." @ "..c_x.."."..c_y.." reg: "..r_x..","..r_y) - -- Along resource spawn, only once - if i == 1 then - local am_roll = rgen:random() - for index,vv in ipairs(configIndexed) do - if vv.along_resource_probability_range and am_roll >= vv.along_resource_probability_range.min and am_roll <= vv.along_resource_probability_range.max then - c_data = r_data[c_x][c_y] - c_data[#c_data+1]={vv.name, rollNumber} - debug("Rolled along "..vv.name.." @ "..c_x.."."..c_y.." reg: "..r_x..","..r_y) - end - end - end - end - -- roll multiple resources in same region - local deep=0 - while v.multi_resource_chance and rgen:random() <= v.multi_resource_chance*(multi_resource_chance_diminish^deep) do - deep = deep + 1 - local max_allotment = 0 - for index,sub_res in pairs(v.multi_resource) do max_allotment=max_allotment+sub_res.allotment end - - local res_type=rgen:random(1, max_allotment) - local min=0 - for _, sub_res in pairs(v.multi_resource) do - if (res_type >= min) and (res_type <= sub_res.allotment + min) then - local last_coords = last_spawn_coords[rgen:random(1, #last_spawn_coords)] - local c_x, c_y = find_random_neighbour_chunk(last_coords[1], last_coords[2]) -- in same as primary resource chunk - if not r_data[c_x] then r_data[c_x] = {} end - if not r_data[c_x][c_y] then r_data[c_x][c_y] = {} end - local c_data = r_data[c_x][c_y] - c_data[#c_data+1]={sub_res.name, deep} - debug("Rolled multiple "..sub_res.name..":"..deep.." with res_type="..res_type.." @ "..c_x.."."..c_y.." reg: "..r_x.."."..r_y) - break - else - min = min + sub_res.allotment - end - end - end - break - end - end - - end - end - -- roll for absolute_probability - this rolls the enemies - - for index,v in ipairs(configIndexed) do - if v.absolute_probability then - local prob_factor = 1 - if v.probability_distance_factor then - prob_factor = math.min(v.max_probability_distance_factor, v.probability_distance_factor^distance({x=0,y=0},{x=r_x,y=r_y})) - end - local abs_roll = rgen:random() - if abs_roll 10 then - global.startingAreas[1].spawned = true - end - end - - calculate_spawner_ratio() - spawn_starting_resources(surface, 1 ) - - initDone = true - - if surface.map_gen_settings.autoplace_controls["iron-ore"].size ~= "none" then - game.players[1].print("RSO WARNING - VANILLA iron-ore GEN IS NOT DISABLED!") - end - if surface.map_gen_settings.autoplace_controls["copper-ore"].size ~= "none" then - game.players[1].print("RSO WARNING - VANILLA copper-ore GEN IS NOT DISABLED!") - end - if surface.map_gen_settings.autoplace_controls["uranium-ore"].size ~= "none" then - game.players[1].print("RSO WARNING - VANILLA uranium-ore GEN IS NOT DISABLED!") - end - if surface.map_gen_settings.autoplace_controls["crude-oil"].size ~= "none" then - game.players[1].print("RSO WARNING - VANILLA crude-oil GEN IS NOT DISABLED!") - end - if surface.map_gen_settings.autoplace_controls["enemy-base"].size ~= "none" then - game.players[1].print("RSO WARNING - VANILLA enemy-base GEN IS NOT DISABLED!") - end - if surface.map_gen_settings.autoplace_controls["stone"].size ~= "none" then - game.players[1].print("RSO WARNING - VANILLA stone GEN IS NOT DISABLED!") - end - if surface.map_gen_settings.autoplace_controls["coal"].size ~= "none" then - game.players[1].print("RSO WARNING - VANILLA coal GEN IS NOT DISABLED!") - end - end - -end - -function RSO_ChunkGenerated(event) - local c_x = event.area.left_top.x - local c_y = event.area.left_top.y - - RSO_init() - - roll_region(c_x, c_y) - roll_chunk(event.surface, c_x, c_y) -end \ No newline at end of file diff --git a/locale/rso/rso_resource_config.lua b/locale/rso/rso_resource_config.lua deleted file mode 100644 index d465415..0000000 --- a/locale/rso/rso_resource_config.lua +++ /dev/null @@ -1,171 +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=15, max=25}, -- 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=15, max=25}, - 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["uranium-ore"] = { - type="resource-ore", - - allotment=50, - spawns_per_region={min=1, max=1}, - richness=10000, - size={min=15, max=20}, - min_amount=500, - - starting={richness=2000, size=10, probability=1}, - } - - config["crude-oil"] = { - type="resource-liquid", - minimum_amount=10000, - allotment=70, - spawns_per_region={min=1, max=2}, - richness={min=100000, max=200000}, -- richness per resource spawn - size={min=3, max=7}, - - starting={richness=200000, 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 \ No newline at end of file diff --git a/separate_spawns.lua b/separate_spawns.lua index 4a0c401..b92732d 100644 --- a/separate_spawns.lua +++ b/separate_spawns.lua @@ -221,6 +221,7 @@ function ChangePlayerSpawn(player, pos) end function SendPlayerToNewSpawnAndCreateIt(player, spawn, moatEnabled) + -- Send the player to that position player.teleport(spawn, GAME_SURFACE_NAME) GivePlayerStarterItems(player) diff --git a/separate_spawns_guis.lua b/separate_spawns_guis.lua index feb420a..a000ea3 100755 --- a/separate_spawns_guis.lua +++ b/separate_spawns_guis.lua @@ -155,11 +155,8 @@ function DisplaySpawnOptions(player) caption="This is the default spawn behavior of a vanilla game."} sGui.add{name = "normal_spawn_lbl2", type = "label", caption="You join the default team in the center of the map."} - sGui.add{name = "normal_spawn_lbl3", type = "label", - caption="(Back by popular request...)"} ApplyStyle(sGui.normal_spawn_lbl1, my_label_style) ApplyStyle(sGui.normal_spawn_lbl2, my_label_style) - ApplyStyle(sGui.normal_spawn_lbl3, my_label_style) else sGui.add{name = "normal_spawn_lbl1", type = "label", caption="Default spawn is disabled in this mode."} @@ -279,12 +276,26 @@ function DisplaySpawnOptions(player) end +function SpawnOptsGuiOptionsSelect(event) + if not (event and event.element and event.element.valid) then return end + local elemName = event.element.name + + -- This just updates the radio buttons. + if (elemName == "isolated_spawn_main_team_radio") then + event.element.parent.isolated_spawn_new_team_radio.state=false + elseif (elemName == "isolated_spawn_new_team_radio") then + event.element.parent.isolated_spawn_main_team_radio.state=false + end +end + + -- Handle the gui click of the spawn options function SpawnOptsGuiClick(event) if not (event and event.element and event.element.valid) then return end local player = game.players[event.player_index] local elemName = event.element.name + if (player.gui.center.spawn_opts == nil) then return -- Gui event unrelated to this gui. end @@ -311,14 +322,6 @@ function SpawnOptsGuiClick(event) end player.gui.center.spawn_opts.destroy() - -- This just updates the radio buttons. - elseif ((elemName == "isolated_spawn_main_team_radio") or - (elemName == "isolated_spawn_new_team_radio")) then - if (elemName == "isolated_spawn_main_team_radio") then - event.element.parent.isolated_spawn_new_team_radio.state=false - elseif (elemName == "isolated_spawn_new_team_radio") then - event.element.parent.isolated_spawn_main_team_radio.state=false - end else return -- Do nothing, no valid element item was clicked. @@ -329,9 +332,7 @@ function SpawnOptsGuiClick(event) GivePlayerStarterItems(player) ChangePlayerSpawn(player, player.force.get_spawn_position(GAME_SURFACE_NAME)) SendBroadcastMsg(player.name .. " joined the main force!") - ChartArea(player.force, player.position, 4, player.surface) - - + ChartArea(player.force, player.position, 4, player.surface) elseif ((elemName == "isolated_spawn_near") or (elemName == "isolated_spawn_far")) then CreateSpawnCtrlGui(player) @@ -348,45 +349,33 @@ function SpawnOptsGuiClick(event) end end - -- Re-used abandoned spawns... - -- if (#global.unusedSpawns >= 1) then - -- oldSpawn = table.remove(global.unusedSpawns) - -- global.uniqueSpawns[player.name] = oldSpawn - -- player.print("Sorry! You have been assigned to an abandoned base! This is done to keep map size small.") - -- ChangePlayerSpawn(player, oldSpawn.pos) - -- SendPlayerToSpawn(player) - -- GivePlayerStarterItems(player) - -- SendBroadcastMsg(player.name .. " joined an abandoned base!") - -- else + -- Find coordinates of a good place to spawn + if (elemName == "isolated_spawn_far") then + newSpawn = FindUngeneratedCoordinates(FAR_MIN_DIST,FAR_MAX_DIST, player.surface) + elseif (elemName == "isolated_spawn_near") then + newSpawn = FindUngeneratedCoordinates(NEAR_MIN_DIST,NEAR_MAX_DIST, player.surface) + end - -- Find coordinates of a good place to spawn - if (elemName == "isolated_spawn_far") then - newSpawn = FindUngeneratedCoordinates(FAR_MIN_DIST,FAR_MAX_DIST, player.surface) - elseif (elemName == "isolated_spawn_near") then - newSpawn = FindUngeneratedCoordinates(NEAR_MIN_DIST,NEAR_MAX_DIST, player.surface) - end + -- If that fails, find a random map edge in a rand direction. + if ((newSpawn.x == 0) and (newSpawn.x == 0)) then + newSpawn = FindMapEdge(GetRandomVector(), player.surface) + DebugPrint("Resorting to find map edge! x=" .. newSpawn.x .. ",y=" .. newSpawn.y) + end - -- If that fails, find a random map edge in a rand direction. - if ((newSpawn.x == 0) and (newSpawn.x == 0)) then - newSpawn = FindMapEdge(GetRandomVector(), player.surface) - DebugPrint("Resorting to find map edge! x=" .. newSpawn.x .. ",y=" .. newSpawn.y) - end + -- Create that spawn in the global vars + ChangePlayerSpawn(player, newSpawn) + + -- Send the player there + SendPlayerToNewSpawnAndCreateIt(player, newSpawn, moatChoice) + if (elemName == "isolated_spawn_near") then + SendBroadcastMsg(player.name .. " joined the game from a distance!") + elseif (elemName == "isolated_spawn_far") then + SendBroadcastMsg(player.name .. " joined the game from a great distance!") + end - -- Create that spawn in the global vars - ChangePlayerSpawn(player, newSpawn) - - -- Send the player there - SendPlayerToNewSpawnAndCreateIt(player, newSpawn, moatChoice) - if (elemName == "isolated_spawn_near") then - SendBroadcastMsg(player.name .. " joined the game from a distance!") - elseif (elemName == "isolated_spawn_far") then - SendBroadcastMsg(player.name .. " joined the game from a great distance!") - end - - player.print("PLEASE WAIT WHILE YOUR SPAWN POINT IS GENERATED!") - player.print("PLEASE WAIT WHILE YOUR SPAWN POINT IS GENERATED!!") - player.print("PLEASE WAIT WHILE YOUR SPAWN POINT IS GENERATED!!!") - -- end + player.print("PLEASE WAIT WHILE YOUR SPAWN POINT IS GENERATED!") + player.print("PLEASE WAIT WHILE YOUR SPAWN POINT IS GENERATED!!") + player.print("PLEASE WAIT WHILE YOUR SPAWN POINT IS GENERATED!!!") elseif (elemName == "join_other_spawn") then DisplaySharedSpawnOptions(player) @@ -411,7 +400,7 @@ function DisplaySharedSpawnOptions(player) ApplyStyle(shGui, my_fixed_width_style) shGui.style.maximal_width = SPAWN_GUI_MAX_WIDTH shGui.style.maximal_height = SPAWN_GUI_MAX_HEIGHT - shGui.horizontal_scroll_policy = "never" + shGui.can_scroll_horizontally = false for spawnName,sharedSpawn in pairs(global.sharedSpawns) do @@ -520,7 +509,7 @@ function ExpandSpawnCtrlGui(player, tick) name="spwn_ctrl_panel", caption=""} ApplyStyle(spwnCtrls, my_fixed_width_style) spwnCtrls.style.maximal_height = SPAWN_GUI_MAX_HEIGHT - spwnCtrls.horizontal_scroll_policy = "never" + spwnCtrls.can_scroll_horizontally = false if ENABLE_SHARED_SPAWNS then if (global.uniqueSpawns[player.name] ~= nil) then @@ -561,22 +550,12 @@ function ExpandSpawnCtrlGui(player, tick) end -function SpawnCtrlGuiClick(event) +function SpawnCtrlGuiOptionsSelect(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 == "spwn_ctrls") then - ExpandSpawnCtrlGui(player, event.tick) - end - - if (event.element.parent) then - if (event.element.parent.name ~= "spwn_ctrl_panel") then - return - end - end - if (name == "accessToggle") then if event.element.state then if DoesPlayerHaveCustomSpawn(player) then @@ -595,6 +574,23 @@ function SpawnCtrlGuiClick(event) end end end +end + +function SpawnCtrlGuiClick(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 == "spwn_ctrls") then + ExpandSpawnCtrlGui(player, event.tick) + end + + if (event.element.parent) then + if (event.element.parent.name ~= "spwn_ctrl_panel") then + return + end + end -- Sets a new respawn point and resets the cooldown. if (name == "setRespawnLocation") then