mirror of
https://github.com/Oarcinae/FactorioScenarioMultiplayerSpawn.git
synced 2024-12-12 10:13:58 +02:00
Fix for text line issues. Better support for larger spawn size areas. Minor text changes. Tweaking of resources and difficulty.
This commit is contained in:
parent
5ddb5b2dee
commit
8221e3928c
25
config.lua
25
config.lua
@ -18,7 +18,7 @@ WELCOME_MSG1 = "Rules: Be polite. Ask before changing other players's stuff. Hav
|
||||
WELCOME_MSG2 = "This server is running a custom scenario that changes spawn locations."
|
||||
|
||||
OTHER_MSG1 = "Latest updates in this scenario version:"
|
||||
OTHER_MSG2 = "0.16 experimental release. New spawning permissions and buddy spawns."
|
||||
OTHER_MSG2 = "0.16 experimental release. Tweaks to fix spawn issues / text / difficulty."
|
||||
-- Optional other messages below:
|
||||
OTHER_MSG3 = "This scenario gives you or your friends your own starting area."
|
||||
OTHER_MSG4 = "You can be on the main team or your own. All teams are friendly."
|
||||
@ -76,6 +76,7 @@ ENABLE_AUTOFILL = true
|
||||
|
||||
-- Enable Playerlist
|
||||
ENABLE_PLAYER_LIST = true
|
||||
PLAYER_LIST_OFFLINE_PLAYERS = true -- List offline players as well.
|
||||
|
||||
-- Enable Gravestone Chests
|
||||
ENABLE_GRAVESTONE_ON_DEATH = false
|
||||
@ -92,7 +93,9 @@ ENABLE_POWER_ARMOR_QUICK_START = false
|
||||
ENABLE_SHARED_TEAM_VISION = true
|
||||
|
||||
-- Enable map regrowth, see regrowth_map.lua for more info.
|
||||
-- I'm not a fan of this anymore, but it helps keep the map size down
|
||||
ENABLE_REGROWTH = false
|
||||
|
||||
-- If you have regrowth enabled, this should also be enabled.
|
||||
-- It removes bases for players that join and leave the game quickly.
|
||||
-- This can also be used without enabling regrowth.
|
||||
@ -161,10 +164,12 @@ FAR_MAX_DIST = 300
|
||||
|
||||
-- Allow players to choose to spawn with a moat
|
||||
SPAWN_MOAT_CHOICE_ENABLED = true
|
||||
-- If you change the spawn area size, you might have to adjust this as well
|
||||
MOAT_SIZE_MODIFIER = 1
|
||||
|
||||
-- Create a circle of land area for the spawn
|
||||
-- This is the radius (I think?) in TILES.
|
||||
ENFORCE_LAND_AREA_TILE_DIST = 48
|
||||
-- If you make this much bigger than a few chunks, good luck.
|
||||
ENFORCE_LAND_AREA_TILE_DIST = CHUNK_SIZE*1.8
|
||||
|
||||
-- Location of water strip (horizontal)
|
||||
WATER_SPAWN_OFFSET_X = -4
|
||||
@ -224,6 +229,7 @@ ENABLE_SPAWN_FORCE_GRASS = true
|
||||
SPAWN_TREE_CIRCLE_ENABLED = true
|
||||
|
||||
-- Set this to true for the spawn area to be surrounded by an octagon of trees
|
||||
-- I don't recommend using this with moatsm
|
||||
SPAWN_TREE_OCTAGON_ENABLED = true
|
||||
|
||||
---------------------------------------
|
||||
@ -239,7 +245,7 @@ SAFE_AREA_TILE_DIST = CHUNK_SIZE*5
|
||||
WARNING_AREA_TILE_DIST = CHUNK_SIZE*10
|
||||
|
||||
-- 1 : X (spawners alive : spawners destroyed) in this area
|
||||
WARN_AREA_REDUCTION_RATIO = 5
|
||||
WARN_AREA_REDUCTION_RATIO = 10
|
||||
|
||||
|
||||
---------------------------------------
|
||||
@ -283,7 +289,7 @@ MIN_ONLINE_TIME = TICKS_PER_MINUTE * MIN_ONLINE_TIME_IN_MINUTES
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
-- Enable/Disable enemy expansion
|
||||
ENEMY_EXPANSION = false
|
||||
ENEMY_EXPANSION = true
|
||||
|
||||
-- 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.
|
||||
@ -370,10 +376,10 @@ global.clMapGen.autoplace_controls = {
|
||||
["stone"]={frequency= "very-low", size= "low", richness= "high"},
|
||||
["uranium-ore"]={frequency= "low", size= "low", richness= "high"},
|
||||
|
||||
["desert"]={frequency= "normal", size= "normal", richness= "normal"},
|
||||
["dirt"]={frequency= "normal", size= "normal", richness= "normal"},
|
||||
["desert"]={frequency= "low", size= "low", richness= "normal"},
|
||||
["dirt"]={frequency= "low", size= "low", richness= "normal"},
|
||||
["grass"]={frequency= "normal", size= "normal", richness= "normal"},
|
||||
["sand"]={frequency= "normal", size= "normal", richness= "normal"},
|
||||
["sand"]={frequency= "low", size= "low", 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?
|
||||
@ -387,12 +393,11 @@ global.clMapGen.cliff_settings={cliff_elevation_0=10, cliff_elevation_interval=1
|
||||
ENABLE_ANTI_GRIEFING = false
|
||||
|
||||
-- Makes blueprint ghosts dissapear if they have been placed longer than this
|
||||
GHOST_TIME_TO_LIVE = 3 * TICKS_PER_MINUTE -- set to 0 for infinite ghost life
|
||||
GHOST_TIME_TO_LIVE = 0 * TICKS_PER_MINUTE -- set to 0 for infinite ghost life
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- DEBUG / Custom stuff
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
OARC_DIFFICULTY_CUSTOM = false
|
||||
|
||||
-- DEBUG prints for me
|
||||
|
@ -135,7 +135,7 @@ function GenerateRocketSiloChunk(event)
|
||||
RemoveDecorationsArea(surface, chunkArea)
|
||||
|
||||
-- Create rocket silo
|
||||
CreateCropOctagon(surface, siloPos, chunkArea, 40)
|
||||
CreateCropOctagon(surface, siloPos, chunkArea, CHUNK_SIZE*2)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -27,14 +27,14 @@ my_fixed_width_style = {
|
||||
my_label_style = {
|
||||
minimal_width = 450,
|
||||
maximal_width = 450,
|
||||
maximal_height = 10,
|
||||
-- maximal_height = 10,
|
||||
font_color = {r=1,g=1,b=1},
|
||||
top_padding = 0,
|
||||
bottom_padding = 0
|
||||
}
|
||||
my_note_style = {
|
||||
minimal_width = 450,
|
||||
maximal_height = 10,
|
||||
-- maximal_height = 10,
|
||||
font = "default-small-semibold",
|
||||
font_color = {r=1,g=0.5,b=0.5},
|
||||
top_padding = 0,
|
||||
@ -43,7 +43,7 @@ my_note_style = {
|
||||
my_warning_style = {
|
||||
minimal_width = 450,
|
||||
maximal_width = 450,
|
||||
maximal_height = 10,
|
||||
-- maximal_height = 10,
|
||||
font_color = {r=1,g=0.1,b=0.1},
|
||||
top_padding = 0,
|
||||
bottom_padding = 0
|
||||
@ -52,7 +52,7 @@ my_spacer_style = {
|
||||
minimal_width = 450,
|
||||
maximal_width = 450,
|
||||
minimal_height = 20,
|
||||
maximal_height = 20,
|
||||
-- maximal_height = 20,
|
||||
font_color = {r=0,g=0,b=0},
|
||||
top_padding = 0,
|
||||
bottom_padding = 0
|
||||
@ -71,30 +71,38 @@ my_player_list_admin_style = {
|
||||
minimal_width = 200,
|
||||
top_padding = 0,
|
||||
bottom_padding = 0,
|
||||
maximal_height = 15
|
||||
-- maximal_height = 15
|
||||
}
|
||||
my_player_list_style = {
|
||||
font = "default-semibold",
|
||||
minimal_width = 200,
|
||||
top_padding = 0,
|
||||
bottom_padding = 0,
|
||||
maximal_height = 15
|
||||
-- maximal_height = 15
|
||||
}
|
||||
my_player_list_offline_style = {
|
||||
-- font = "default-semibold",
|
||||
font_color = {r=0.5,g=0.5,b=0.5},
|
||||
minimal_width = 200,
|
||||
top_padding = 0,
|
||||
bottom_padding = 0,
|
||||
-- maximal_height = 15
|
||||
}
|
||||
my_player_list_style_spacer = {
|
||||
maximal_height = 15
|
||||
-- maximal_height = 15
|
||||
}
|
||||
my_color_red = {r=1,g=0.1,b=0.1}
|
||||
|
||||
my_longer_label_style = {
|
||||
maximal_width = 600,
|
||||
maximal_height = 10,
|
||||
-- maximal_height = 10,
|
||||
font_color = {r=1,g=1,b=1},
|
||||
top_padding = 0,
|
||||
bottom_padding = 0
|
||||
}
|
||||
my_longer_warning_style = {
|
||||
maximal_width = 600,
|
||||
maximal_height = 10,
|
||||
-- maximal_height = 10,
|
||||
font_color = {r=1,g=0.1,b=0.1},
|
||||
top_padding = 0,
|
||||
bottom_padding = 0
|
||||
@ -714,6 +722,15 @@ local function ExpandPlayerListGui(player)
|
||||
ApplyStyle(text, my_player_list_style)
|
||||
end
|
||||
end
|
||||
if (PLAYER_LIST_OFFLINE_PLAYERS) then
|
||||
for _,player in pairs(game.players) do
|
||||
if (not player.connected) then
|
||||
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"}
|
||||
ApplyStyle(text, my_player_list_offline_style)
|
||||
end
|
||||
end
|
||||
end
|
||||
local spacer = scrollFrame.add{type="label", caption=" ", name="plist_spacer_plist"}
|
||||
ApplyStyle(spacer, my_player_list_style_spacer)
|
||||
end
|
||||
@ -788,7 +805,7 @@ function DropGravestoneChests(player)
|
||||
|
||||
local inv = player.get_inventory(id)
|
||||
|
||||
if (not inv.is_empty()) then
|
||||
if ((#inv > 0) and not inv.is_empty()) then
|
||||
for j = 1, #inv do
|
||||
if inv[j].valid_for_read then
|
||||
|
||||
@ -926,8 +943,8 @@ function CreateCropCircle(surface, centerPos, chunkArea, tileRadius)
|
||||
|
||||
-- Create a circle of trees around the spawn point.
|
||||
if ((distVar < tileRadSqr-200) and
|
||||
(distVar > tileRadSqr-300)) then
|
||||
surface.create_entity({name="tree-01", amount=1, position={i, j}})
|
||||
(distVar > tileRadSqr-400)) then
|
||||
surface.create_entity({name="tree-02", amount=1, position={i, j}})
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -946,7 +963,7 @@ function CreateCropOctagon(surface, centerPos, chunkArea, tileRadius)
|
||||
|
||||
local distVar1 = math.floor(math.max(math.abs(centerPos.x - i), math.abs(centerPos.y - j)))
|
||||
local distVar2 = math.floor(math.abs(centerPos.x - i) + math.abs(centerPos.y - j))
|
||||
local distVar = math.max(distVar1, distVar2 * 0.707);
|
||||
local distVar = math.max(distVar1*1.1, distVar2 * 0.707*1.1);
|
||||
|
||||
-- Fill in all unexpected water in a circle
|
||||
if (distVar < tileRadius+2) then
|
||||
@ -979,15 +996,15 @@ function CreateMoat(surface, centerPos, chunkArea, tileRadius)
|
||||
local distVar = math.floor((centerPos.x - i)^2 + (centerPos.y - j)^2)
|
||||
|
||||
-- Create a circle of water
|
||||
if ((distVar < tileRadSqr+400) and
|
||||
(distVar > tileRadSqr-500)) then
|
||||
if ((distVar < tileRadSqr+(2000*MOAT_SIZE_MODIFIER)) and
|
||||
(distVar > tileRadSqr)) then
|
||||
table.insert(waterTiles, {name = "water", position ={i,j}})
|
||||
end
|
||||
|
||||
-- Enforce land inside the edges of the circle to make sure it's
|
||||
-- a clean transition
|
||||
if ((distVar < tileRadSqr-500) and
|
||||
(distVar > tileRadSqr-1000)) then
|
||||
if ((distVar <= tileRadSqr) and
|
||||
(distVar > tileRadSqr-10000)) then
|
||||
table.insert(waterTiles, {name = "grass-1", position ={i,j}})
|
||||
end
|
||||
end
|
||||
@ -1008,6 +1025,9 @@ end
|
||||
-- Function to generate a resource patch, of a certain size/amount at a pos.
|
||||
function GenerateResourcePatch(surface, resourceName, diameter, pos, amount)
|
||||
local midPoint = math.floor(diameter/2)
|
||||
if (diameter == 0) then
|
||||
return
|
||||
end
|
||||
for y=0, diameter do
|
||||
for x=0, diameter do
|
||||
if (not ENABLE_RESOURCE_SHAPE_CIRCLE or ((x-midPoint)^2 + (y-midPoint)^2 < midPoint^2)) then
|
||||
@ -1116,7 +1136,7 @@ function SetupAndClearSpawnAreas(surface, chunkArea, spawnPointTable)
|
||||
end
|
||||
if (SPAWN_MOAT_CHOICE_ENABLED) then
|
||||
if (spawn.moat) then
|
||||
CreateMoat(surface, spawn.pos, chunkArea, ENFORCE_LAND_AREA_TILE_DIST+10)
|
||||
CreateMoat(surface, spawn.pos, chunkArea, ENFORCE_LAND_AREA_TILE_DIST)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1,6 +1,6 @@
|
||||
debug_enabled = false
|
||||
|
||||
region_size = 8 -- alternative mean to control how further away resources would be, default - 256 tiles or 8 chunks
|
||||
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
|
||||
|
||||
@ -8,7 +8,7 @@ use_donut_shapes = false -- setting this to false will remove donuts from possi
|
||||
|
||||
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
|
||||
absolute_resource_chance = 0.40 -- 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
|
||||
@ -23,9 +23,9 @@ multi_resource_chance_diminish = 0.6 -- diminishing effect factor on multi_resou
|
||||
|
||||
min_amount=250 -- default value for minimum amount of resource in single pile
|
||||
|
||||
richness_distance_factor= 0.5 -- exponent for richness distance factor calculation
|
||||
richness_distance_factor= 0.8 -- 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
|
||||
size_distance_factor=0.3 -- exponent for size distance factor calculation
|
||||
|
||||
deterministic = true -- set to false to use system for all decisions math.random
|
||||
|
||||
|
@ -321,7 +321,7 @@ function OarcRegrowthOnTick()
|
||||
-- Send a broadcast warning before it happens.
|
||||
if ((game.tick % REGROWTH_CLEANING_INTERVAL_TICKS) == REGROWTH_CLEANING_INTERVAL_TICKS-601) then
|
||||
if (#global.chunk_regrow.removal_list > 100) then
|
||||
SendBroadcastMsg("Map cleanup in 10 seconds...")
|
||||
SendBroadcastMsg("Map cleanup in 10 seconds, if you don't want to lose what you found drop a powered radar on it!")
|
||||
end
|
||||
end
|
||||
|
||||
@ -329,7 +329,7 @@ function OarcRegrowthOnTick()
|
||||
if ((game.tick % REGROWTH_CLEANING_INTERVAL_TICKS) == REGROWTH_CLEANING_INTERVAL_TICKS-1) then
|
||||
if (#global.chunk_regrow.removal_list > 100) then
|
||||
OarcRegrowthRemoveAllChunks()
|
||||
SendBroadcastMsg("Map cleanup done...")
|
||||
SendBroadcastMsg("Map cleanup done, sorry for your loss.")
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -340,10 +340,10 @@ end
|
||||
function OarcRegrowthForceRemovalOnTick()
|
||||
-- Catch force remove flag
|
||||
if (game.tick == global.chunk_regrow.force_removal_flag+60) then
|
||||
SendBroadcastMsg("Map cleanup in 10 seconds...")
|
||||
SendBroadcastMsg("Map cleanup in 10 seconds, if you don't want to lose what you found drop a powered radar on it!")
|
||||
end
|
||||
if (game.tick == global.chunk_regrow.force_removal_flag+660) then
|
||||
OarcRegrowthRemoveAllChunks()
|
||||
SendBroadcastMsg("Map cleanup done...")
|
||||
SendBroadcastMsg("Map cleanup done, sorry for your loss.")
|
||||
end
|
||||
end
|
@ -267,12 +267,14 @@ function QueuePlayerForDelayedSpawn(playerName, spawn, moatEnabled)
|
||||
if ((spawn.x ~= 0) and (spawn.y ~= 0)) then
|
||||
global.uniqueSpawns[playerName] = {pos=spawn,moat=moatEnabled}
|
||||
|
||||
game.players[playerName].print("Generating your spawn now, please wait a few seconds...")
|
||||
local delay_spawn_seconds = 5*(math.ceil(ENFORCE_LAND_AREA_TILE_DIST/CHUNK_SIZE))
|
||||
|
||||
game.players[playerName].print("Generating your spawn now, please wait a few for " .. delay_spawn_seconds .. " seconds...")
|
||||
game.players[playerName].surface.request_to_generate_chunks(spawn, 4)
|
||||
delayedTick = game.tick + 10*TICKS_PER_SECOND
|
||||
delayedTick = game.tick + delay_spawn_seconds*TICKS_PER_SECOND
|
||||
table.insert(global.delayedSpawns, {playerName=playerName, spawn=spawn, moatEnabled=moatEnabled, delayedTick=delayedTick})
|
||||
|
||||
DisplayPleaseWaitForSpawnDialog(game.players[playerName])
|
||||
DisplayPleaseWaitForSpawnDialog(game.players[playerName], delay_spawn_seconds)
|
||||
|
||||
else
|
||||
DebugPrint("THIS SHOULD NOT EVER HAPPEN! Spawn failed!")
|
||||
@ -320,6 +322,9 @@ function SendPlayerToNewSpawnAndCreateIt(playerName, spawn, moatEnabled)
|
||||
game.players[playerName].teleport(spawn, GAME_SURFACE_NAME)
|
||||
GivePlayerStarterItems(game.players[playerName])
|
||||
|
||||
-- Chart the area.
|
||||
ChartArea(game.players[playerName].force, game.players[playerName].position, math.ceil(ENFORCE_LAND_AREA_TILE_DIST/CHUNK_SIZE), game.players[playerName].surface)
|
||||
|
||||
if (game.players[playerName].gui.center.wait_for_spawn_dialog ~= nil) then
|
||||
game.players[playerName].gui.center.wait_for_spawn_dialog.destroy()
|
||||
end
|
||||
|
@ -5,8 +5,8 @@
|
||||
|
||||
require("separate_spawns")
|
||||
|
||||
local SPAWN_GUI_MAX_WIDTH = 550
|
||||
local SPAWN_GUI_MAX_HEIGHT = 800
|
||||
local SPAWN_GUI_MAX_WIDTH = 1000
|
||||
local SPAWN_GUI_MAX_HEIGHT = 1000
|
||||
|
||||
-- Use this for testing shared spawns...
|
||||
-- local sharedSpawnExample1 = {openAccess=true,
|
||||
@ -142,10 +142,10 @@ function DisplaySpawnOptions(player)
|
||||
-- Warnings and explanations...
|
||||
sGui.add{name = "warning_lbl1", type = "label",
|
||||
caption="This is your ONLY chance to choose a spawn option. Choose carefully..."}
|
||||
sGui.add{name = "warning_spacer", type = "label",
|
||||
caption=" "}
|
||||
-- sGui.add{name = "warning_spacer", type = "label",
|
||||
-- caption=" "}
|
||||
ApplyStyle(sGui.warning_lbl1, my_warning_style)
|
||||
ApplyStyle(sGui.warning_spacer, my_spacer_style)
|
||||
-- ApplyStyle(sGui.warning_spacer, my_spacer_style)
|
||||
|
||||
sGui.add{name = "spawn_msg_lbl1", type = "label",
|
||||
caption=SPAWN_MSG1}
|
||||
@ -266,11 +266,15 @@ function DisplaySpawnOptions(player)
|
||||
|
||||
-- New awesome buddy spawning system
|
||||
if ENABLE_SHARED_SPAWNS and ENABLE_BUDDY_SPAWN then
|
||||
sGui.add{name = "buddy_spawn_msg_spacer", type = "label",
|
||||
caption="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"}
|
||||
ApplyStyle(sGui.buddy_spawn_msg_spacer, my_spacer_style)
|
||||
|
||||
sGui.add{name = "buddy_spawn",
|
||||
type = "button",
|
||||
caption="Buddy Spawn"}
|
||||
sGui.add{name = "buddy_spawn_lbl1", type = "label",
|
||||
caption="You spawn next to a buddy of your choosing."}
|
||||
caption="Buddy System requires 2 players in this menu at the same time, you spawn beside each other."}
|
||||
end
|
||||
|
||||
-- Some final notes
|
||||
@ -375,7 +379,7 @@ function SpawnOptsGuiClick(event)
|
||||
GivePlayerStarterItems(player)
|
||||
ChangePlayerSpawn(player, player.force.get_spawn_position(GAME_SURFACE_NAME))
|
||||
SendBroadcastMsg(player.name .. " is joining the main force!")
|
||||
ChartArea(player.force, player.position, 4, player.surface)
|
||||
ChartArea(player.force, player.position, math.ceil(ENFORCE_LAND_AREA_TILE_DIST/CHUNK_SIZE), player.surface)
|
||||
-- Create the button at the top left for setting respawn point and sharing base.
|
||||
CreateSpawnCtrlGui(player)
|
||||
|
||||
@ -1347,7 +1351,7 @@ function BuddySpawnRequestMenuClick(event)
|
||||
end
|
||||
|
||||
|
||||
function DisplayPleaseWaitForSpawnDialog(player)
|
||||
function DisplayPleaseWaitForSpawnDialog(player, delay_seconds)
|
||||
|
||||
player.gui.center.add{name = "wait_for_spawn_dialog",
|
||||
type = "frame",
|
||||
@ -1362,7 +1366,7 @@ function DisplayPleaseWaitForSpawnDialog(player)
|
||||
pleaseWaitGui.add{name = "warning_lbl1", type = "label",
|
||||
caption="Your spawn is being created now."}
|
||||
pleaseWaitGui.add{name = "warning_lbl2", type = "label",
|
||||
caption="You will be teleported there in a few seconds!"}
|
||||
caption="You will be teleported there in "..delay_seconds.." seconds!"}
|
||||
pleaseWaitGui.add{name = "warning_lbl3", type = "label",
|
||||
caption="Please standby..."}
|
||||
pleaseWaitGui.add{name = "warning_spacer", type = "label",
|
||||
|
Loading…
Reference in New Issue
Block a user