mirror of
https://github.com/Aurorastation/Aurora.3.git
synced 2026-08-27 06:54:18 +01:00
Exoplanet ruins, away sites, overmap submaps and maploader goodies. (#12933)
This commit is contained in:
@@ -222,6 +222,7 @@
|
||||
#include "code\controllers\subsystems\law.dm"
|
||||
#include "code\controllers\subsystems\lighting.dm"
|
||||
#include "code\controllers\subsystems\machinery.dm"
|
||||
#include "code\controllers\subsystems\mapping.dm"
|
||||
#include "code\controllers\subsystems\materials.dm"
|
||||
#include "code\controllers\subsystems\mob.dm"
|
||||
#include "code\controllers\subsystems\mob_ai.dm"
|
||||
@@ -1963,6 +1964,7 @@
|
||||
#include "code\modules\lighting\lighting_corner.dm"
|
||||
#include "code\modules\lighting\lighting_overlay.dm"
|
||||
#include "code\modules\lighting\lighting_profiler.dm"
|
||||
#include "code\modules\lighting\lighting_setup.dm"
|
||||
#include "code\modules\lighting\lighting_source.dm"
|
||||
#include "code\modules\lighting\lighting_source_sunlight.dm"
|
||||
#include "code\modules\lighting\lighting_turf.dm"
|
||||
@@ -1974,6 +1976,7 @@
|
||||
#include "code\modules\lock\lock_construct.dm"
|
||||
#include "code\modules\makeshift\makeshift_reagents.dm"
|
||||
#include "code\modules\maps\dmm_suite.dm"
|
||||
#include "code\modules\maps\helper_landmarks.dm"
|
||||
#include "code\modules\maps\map_template.dm"
|
||||
#include "code\modules\maps\reader.dm"
|
||||
#include "code\modules\maps\ruins.dm"
|
||||
@@ -2940,6 +2943,9 @@
|
||||
#include "code\modules\spell_system\spells\spell_list\self\generic\rune_write.dm"
|
||||
#include "code\modules\spell_system\spells\spell_list\self\generic\shadow_shroud.dm"
|
||||
#include "code\modules\spell_system\spells\spell_list\self\generic\shift.dm"
|
||||
#include "code\modules\submaps\_submap.dm"
|
||||
#include "code\modules\submaps\submap_archetype.dm"
|
||||
#include "code\modules\submaps\submap_landmark.dm"
|
||||
#include "code\modules\supermatter\setup_supermatter.dm"
|
||||
#include "code\modules\supermatter\supermatter.dm"
|
||||
#include "code\modules\surgery\_defines.dm"
|
||||
@@ -3058,6 +3064,7 @@
|
||||
#include "maps\aurora\code\aurora_lifts.dm"
|
||||
#include "maps\aurora\code\aurora_shuttles.dm"
|
||||
#include "maps\aurora\code\aurora_unittest.dm"
|
||||
#include "maps\away\away_sites.dm"
|
||||
#include "maps\event\code\event.dm"
|
||||
#include "maps\event\odin_departure\code\odin_departure_areas.dm"
|
||||
#include "maps\event\odin_departure\code\odin_depature.dm"
|
||||
@@ -3070,6 +3077,8 @@
|
||||
#include "maps\exodus\code\exodus_shuttles.dm"
|
||||
#include "maps\exodus\code\exodus_unittest.dm"
|
||||
#include "maps\random_ruins\exoplanets\exoplanet_ruins.dm"
|
||||
#include "maps\random_ruins\exoplanets\crashed_pod\crashed_pod.dm"
|
||||
#include "maps\random_ruins\space_ruins\space_ruins.dm"
|
||||
#include "maps\runtime\runtime_overmap.dm"
|
||||
#include "maps\runtime\code\runtime.dm"
|
||||
#include "maps\runtime\code\runtime_lifts.dm"
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#define Clamp(x, low, high) max(low, min(high, x))
|
||||
#define CLAMP01(x) (Clamp(x, 0, 1))
|
||||
#define JOINTEXT(X) jointext(X, null)
|
||||
#define list_find(L, needle, LIMITS...) L.Find(needle, LIMITS)
|
||||
|
||||
#define span(class, text) ("<span class='[class]'>" + text + "</span>")
|
||||
#define SPAN_NOTICE(X) ("<span class='notice'>" + X + "</span>")
|
||||
|
||||
@@ -491,6 +491,6 @@ Define for getting a bitfield of adjacent turfs that meet a condition.
|
||||
#define TEMPLATE_FLAG_SPAWN_GUARANTEED 2 // Makes it ignore away site budget and just spawn (only for away sites)
|
||||
#define TEMPLATE_FLAG_CLEAR_CONTENTS 4 // if it should destroy objects it spawns on top of
|
||||
#define TEMPLATE_FLAG_NO_RUINS 8 // if it should forbid ruins from spawning on top of it
|
||||
#define TEMPLATE_FLAG_NO_RADS 16// Removes all radiation from the template after spawning.
|
||||
|
||||
|
||||
//Ruin map template flags
|
||||
#define TEMPLATE_FLAG_RUIN_STARTS_DISALLOWED 32 // Ruin is not available during spawning unless another ruin permits it.
|
||||
|
||||
@@ -85,3 +85,6 @@
|
||||
|
||||
/proc/cmp_clientcolor_priority(datum/client_color/A, datum/client_color/B)
|
||||
return B.priority - A.priority
|
||||
|
||||
/proc/cmp_ruincost_priority(datum/map_template/ruin/A, datum/map_template/ruin/B)
|
||||
return initial(A.spawn_cost) - initial(B.spawn_cost)
|
||||
|
||||
@@ -50,6 +50,14 @@
|
||||
while (left-- > 0)
|
||||
. = "0[.]"
|
||||
|
||||
// Splits the text of a file at seperator and returns them in a list.
|
||||
/proc/file2list(filename, seperator="\n")
|
||||
return splittext(file2text(filename) || "", seperator)
|
||||
|
||||
//Splits the text of a file at seperator and returns them in a list.
|
||||
/world/proc/file2list(filename, seperator="\n")
|
||||
return splittext(file2text(filename), seperator)
|
||||
|
||||
// Slower then list2text (replaced with jointext), but correctly processes associative lists.
|
||||
proc/tg_list2text(list/list, glue=",")
|
||||
if (!istype(list) || !list.len)
|
||||
@@ -97,10 +105,6 @@ proc/tg_list2text(list/list, glue=",")
|
||||
num_list += text2num(x)
|
||||
return num_list
|
||||
|
||||
// Splits the text of a file at seperator and returns them in a list.
|
||||
/proc/file2list(filename, seperator="\n")
|
||||
return text2list(return_file_text(filename),seperator)
|
||||
|
||||
// Turns a direction into text
|
||||
/proc/num2dir(direction)
|
||||
switch (direction)
|
||||
|
||||
@@ -232,7 +232,7 @@
|
||||
|
||||
/obj/screen/ability/verb_based/activate()
|
||||
if(object_used && verb_to_call)
|
||||
call(object_used,verb_to_call)(arguments_to_use) //TODOMATT: WHY GOD WHY
|
||||
call(object_used,verb_to_call)(arguments_to_use)
|
||||
|
||||
/obj/screen/movable/ability_master/proc/add_verb_ability(var/object_given, var/verb_given, var/name_given, var/ability_icon_given, var/arguments)
|
||||
if(!object_given)
|
||||
|
||||
@@ -379,6 +379,7 @@
|
||||
SearchVar(SSpipenet)
|
||||
SearchVar(SSprocessing)
|
||||
SearchVar(SSshuttle)
|
||||
SearchVar(SSmapping)
|
||||
SearchVar(base_law_type)
|
||||
SearchVar(discord_bot)
|
||||
SearchVar(diseases)
|
||||
|
||||
@@ -46,6 +46,8 @@
|
||||
|
||||
click_catchers = create_click_catcher()
|
||||
|
||||
current_map.build_away_sites()
|
||||
|
||||
current_map.build_exoplanets()
|
||||
|
||||
..(timeofday)
|
||||
|
||||
@@ -212,4 +212,18 @@
|
||||
/datum/controller/subsystem/machinery/ExplosionEnd()
|
||||
wake()
|
||||
|
||||
/datum/controller/subsystem/machinery/proc/setup_atmos_machinery(list/machines)
|
||||
set background = TRUE
|
||||
var/list/atmos_machines = list()
|
||||
for (var/obj/machinery/atmospherics/machine in machines)
|
||||
atmos_machines += machine
|
||||
log_game("Initializing atmos machinery")
|
||||
for (var/obj/machinery/atmospherics/machine as anything in atmos_machines)
|
||||
machine.atmos_init()
|
||||
CHECK_TICK
|
||||
log_game("Initializing pipe networks")
|
||||
for (var/obj/machinery/atmospherics/machine as anything in atmos_machines)
|
||||
machine.build_network()
|
||||
CHECK_TICK
|
||||
|
||||
#undef MACHINERY_GO_TO_NEXT
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
var/datum/controller/subsystem/mapping/SSmapping
|
||||
|
||||
/datum/controller/subsystem/mapping
|
||||
name = "Mapping"
|
||||
init_order = SS_INIT_MISC
|
||||
flags = SS_NO_FIRE
|
||||
|
||||
var/list/map_templates = list()
|
||||
var/list/space_ruins_templates = list()
|
||||
var/list/exoplanet_ruins_templates = list()
|
||||
var/list/away_sites_templates = list()
|
||||
var/list/submaps = list()
|
||||
var/list/submap_archetypes = list()
|
||||
|
||||
/datum/controller/subsystem/mapping/New()
|
||||
NEW_SS_GLOBAL(SSmapping)
|
||||
|
||||
/datum/controller/subsystem/mapping/Initialize(timeofday)
|
||||
// Load templates and build away sites.
|
||||
preloadTemplates()
|
||||
for(var/atype in subtypesof(/decl/submap_archetype))
|
||||
submap_archetypes[atype] = new atype
|
||||
. = ..()
|
||||
|
||||
/datum/controller/subsystem/mapping/Recover()
|
||||
flags |= SS_NO_INIT
|
||||
map_templates = SSmapping.map_templates
|
||||
space_ruins_templates = SSmapping.space_ruins_templates
|
||||
exoplanet_ruins_templates = SSmapping.exoplanet_ruins_templates
|
||||
away_sites_templates = SSmapping.away_sites_templates
|
||||
|
||||
/datum/controller/subsystem/mapping/proc/preloadTemplates(path = "maps/templates/") //see master controller setup
|
||||
var/list/filelist = flist(path)
|
||||
for(var/map in filelist)
|
||||
var/datum/map_template/T = new(path = "[path][map]", rename = "[map]")
|
||||
map_templates[T.name] = T
|
||||
preloadBlacklistableTemplates()
|
||||
|
||||
/datum/controller/subsystem/mapping/proc/preloadBlacklistableTemplates()
|
||||
// Still supporting bans by filename
|
||||
var/list/banned_exoplanet_dmms = generateMapList("config/exoplanet_ruin_blacklist.txt")
|
||||
var/list/banned_space_dmms = generateMapList("config/space_ruin_blacklist.txt")
|
||||
var/list/banned_away_site_dmms = generateMapList("config/away_site_blacklist.txt")
|
||||
|
||||
if (!banned_exoplanet_dmms || !banned_space_dmms || !banned_away_site_dmms)
|
||||
log_admin("One or more map blacklist files are not present in the config directory!")
|
||||
|
||||
var/list/banned_maps = list() + banned_exoplanet_dmms + banned_space_dmms + banned_away_site_dmms
|
||||
|
||||
for(var/item in sortList(subtypesof(/datum/map_template), /proc/cmp_ruincost_priority))
|
||||
var/datum/map_template/map_template_type = item
|
||||
// screen out the abstract subtypes
|
||||
if(!initial(map_template_type.id))
|
||||
continue
|
||||
var/datum/map_template/MT = new map_template_type()
|
||||
|
||||
if (banned_maps)
|
||||
var/mappath = MT.mappath
|
||||
if(list_find(banned_maps, mappath))
|
||||
break
|
||||
|
||||
map_templates[MT.name] = MT
|
||||
|
||||
// This is nasty..
|
||||
if(istype(MT, /datum/map_template/ruin/exoplanet))
|
||||
exoplanet_ruins_templates[MT.name] = MT
|
||||
else if(istype(MT, /datum/map_template/ruin/space))
|
||||
space_ruins_templates[MT.name] = MT
|
||||
else if(istype(MT, /datum/map_template/ruin/away_site))
|
||||
away_sites_templates[MT.name] = MT
|
||||
|
||||
/proc/generateMapList(filename)
|
||||
var/list/potentialMaps = list()
|
||||
var/list/Lines = world.file2list(filename)
|
||||
if(!Lines.len)
|
||||
return
|
||||
for (var/t in Lines)
|
||||
if (!t)
|
||||
continue
|
||||
t = trim(t)
|
||||
if (length(t) == 0)
|
||||
continue
|
||||
else if (copytext(t, 1, 2) == "#")
|
||||
continue
|
||||
var/pos = findtext(t, " ")
|
||||
var/name = null
|
||||
if (pos)
|
||||
name = lowertext(copytext(t, 1, pos))
|
||||
else
|
||||
name = lowertext(t)
|
||||
if (!name)
|
||||
continue
|
||||
potentialMaps.Add(t)
|
||||
return potentialMaps
|
||||
@@ -6,13 +6,19 @@
|
||||
It is clearly a mystery."
|
||||
|
||||
var/spawn_weight = 1
|
||||
var/cost = null
|
||||
var/spawn_cost = 0
|
||||
var/player_cost = 0
|
||||
var/list/sectors = list() //This ruin can only spawn in the sectors in this list.
|
||||
|
||||
var/prefix = null
|
||||
var/suffix = null
|
||||
template_flags = 0 // No duplicates by default
|
||||
|
||||
// !! Currently only implemented for away sites
|
||||
var/list/force_ruins // Listed ruins are always spawned unless disallowed by flags.
|
||||
var/list/allow_ruins // Listed ruins are added to the set of available spawns.
|
||||
var/list/ban_ruins // Listed ruins are removed from the set of available spawns. Beats allowed.
|
||||
|
||||
/datum/map_template/ruin/New()
|
||||
if (suffix)
|
||||
mappath += (prefix + suffix)
|
||||
|
||||
+1
-1
@@ -292,7 +292,7 @@
|
||||
/atom/proc/emag_act(var/remaining_charges, var/mob/user, var/emag_source)
|
||||
return NO_EMAG_ACT
|
||||
|
||||
/atom/proc/fire_act()
|
||||
/atom/proc/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume)
|
||||
return
|
||||
|
||||
/atom/proc/melt()
|
||||
|
||||
@@ -81,8 +81,6 @@
|
||||
if(selected_sound == 'sound/items/AirHorn.ogg' && pay_energy(3800))
|
||||
adjust_instability(49) // Pay for your sins.
|
||||
for(var/mob/living/carbon/M in ohearers(6, T))
|
||||
//if(M.get_ear_protection() >= 2) todomatt: ear protection
|
||||
// continue
|
||||
M.SetSleeping(0)
|
||||
M.stuttering += 20
|
||||
M.ear_deaf += 30
|
||||
|
||||
@@ -16,8 +16,5 @@
|
||||
aspect = ASPECT_BIOMED
|
||||
|
||||
/obj/item/spell/dispel/on_ranged_cast(atom/hit_atom, mob/living/user)
|
||||
//if(isliving(hit_atom) && within_range(hit_atom) && pay_energy(1000)) todomatt: fuck this thinjg
|
||||
// var/mob/living/target = hit_atom
|
||||
// target.remove_modifiers_of_type(/datum/modifier/technomancer)
|
||||
user.adjust_instability(10)
|
||||
qdel(src)
|
||||
@@ -1,35 +0,0 @@
|
||||
// Gambit only spell. Heals everything unconditionally.
|
||||
|
||||
/obj/item/spell/modifier/mend_all
|
||||
name = "mend all"
|
||||
desc = "One function to heal them all."
|
||||
icon_state = "mend_all"
|
||||
cast_methods = CAST_MELEE
|
||||
aspect = ASPECT_BIOMED
|
||||
light_color = "#FF5C5C"
|
||||
modifier_type = /datum/modifier/technomancer/mend_life
|
||||
modifier_duration = 1 MINUTE
|
||||
|
||||
/datum/modifier/technomancer/mend_all
|
||||
name = "mend all"
|
||||
desc = "You feel serene and well rested."
|
||||
mob_overlay_state = "green_sparkles"
|
||||
|
||||
on_created_text = "<span class='warning'>Sparkles begin to appear around you, and all your ills seem to fade away.</span>"
|
||||
on_expired_text = "<span class='notice'>The sparkles have faded, although you feel much healthier than before.</span>"
|
||||
stacks = MODIFIER_STACK_EXTEND
|
||||
|
||||
/datum/modifier/technomancer/mend_all/tick()
|
||||
if(!holder.getBruteLoss() && !holder.getFireLoss() && !holder.getToxLoss() && !holder.getOxyLoss() && !holder.getCloneLoss()) // No point existing if the spell can't heal.
|
||||
stop()
|
||||
return
|
||||
holder.adjustBruteLoss(-4 * spell_power) // Should heal roughly 120 damage over 1 minute, as tick() is run every 2 seconds.
|
||||
holder.adjustFireLoss(-4 * spell_power)
|
||||
holder.adjustToxLoss(-4 * spell_power)
|
||||
holder.adjustOxyLoss(-4 * spell_power)
|
||||
holder.adjustCloneLoss(-2 * spell_power) // 60 cloneloss
|
||||
holder.adjust_instability(1)
|
||||
if(origin)
|
||||
var/mob/living/L = origin.resolve()
|
||||
if(istype(L))
|
||||
L.adjust_instability(1) //TODOMATT: Tick this file and figure this out
|
||||
@@ -39,4 +39,4 @@
|
||||
if(source)
|
||||
var/mob/living/L = source
|
||||
if(istype(L))
|
||||
L.adjust_instability(1) //TODOMATT: Tick this file and figure this out
|
||||
L.adjust_instability(1)
|
||||
@@ -2,6 +2,6 @@
|
||||
var/name
|
||||
var/description
|
||||
var/list/possible_erts = list()
|
||||
var/list/possible_exoplanets = list()
|
||||
var/list/possible_exoplanets = list(/obj/effect/overmap/visitable/sector/exoplanet/snow, /obj/effect/overmap/visitable/sector/exoplanet/desert)
|
||||
var/list/cargo_price_coef = list("nt" = 1, "hpi" = 1, "zhu" = 1, "een" = 1, "get" = 1, "arz" = 1, "blm" = 1,
|
||||
"iac" = 1, "zsc" = 1, "vfc" = 1, "bis" = 1, "xmg" = 1, "npi" = 1) //how much the space sector afffects how expensive is ordering from that cargo supplier
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
/proc/create_all_lighting_overlays()
|
||||
for(var/zlevel = 1 to world.maxz)
|
||||
create_lighting_overlays_zlevel(zlevel)
|
||||
|
||||
/proc/create_lighting_overlays_zlevel(var/zlevel)
|
||||
ASSERT(zlevel)
|
||||
|
||||
for(var/turf/T in block(locate(1, 1, zlevel), locate(world.maxx, world.maxy, zlevel)))
|
||||
if(T.dynamic_lighting)
|
||||
T.lighting_build_overlay()
|
||||
@@ -0,0 +1,32 @@
|
||||
/obj/effect/landmark/map_load_mark
|
||||
name = "map loader landmark"
|
||||
var/list/templates //list of template types to pick from
|
||||
|
||||
//Clears walls
|
||||
/obj/effect/landmark/clear
|
||||
name = "clear turf"
|
||||
icon = 'icons/effects/landmarks.dmi'
|
||||
icon_state = "clear"
|
||||
delete_me = TRUE
|
||||
|
||||
/obj/effect/landmark/clear/Initialize()
|
||||
var/turf/simulated/wall/W = get_turf(src)
|
||||
if(istype(W))
|
||||
W.dismantle_wall(TRUE, TRUE)
|
||||
var/turf/simulated/mineral/M = W
|
||||
if(istype(M))
|
||||
M.GetDrilled()
|
||||
. = ..()
|
||||
|
||||
//Applies fire act to the turf
|
||||
/obj/effect/landmark/scorcher
|
||||
name = "fire"
|
||||
icon = 'icons/effects/landmarks.dmi'
|
||||
icon_state = "fire"
|
||||
var/temp = T0C + 3000
|
||||
|
||||
/obj/effect/landmark/scorcher/Initialize()
|
||||
var/turf/simulated/T = get_turf(src)
|
||||
if(istype(T))
|
||||
T.fire_act(temp)
|
||||
. = ..()
|
||||
@@ -21,52 +21,113 @@
|
||||
name = rename
|
||||
|
||||
/datum/map_template/proc/preload_size(path)
|
||||
var/bounds = maploader.load_map(file(path), 1, 1, 1, cropMap=FALSE, measureOnly=TRUE)
|
||||
if(bounds)
|
||||
width = bounds[MAP_MAXX] // Assumes all templates are rectangular, have a single Z level, and begin at 1,1,1
|
||||
height = bounds[MAP_MAXY]
|
||||
var/list/bounds = list(1.#INF, 1.#INF, 1.#INF, -1.#INF, -1.#INF, -1.#INF)
|
||||
var/z_offset = 1 // needed to calculate z-bounds correctly
|
||||
var/datum/map_load_metadata/M = maploader.load_map(file(path), 1, 1, z_offset, cropMap=FALSE, measureOnly=TRUE)
|
||||
if(M)
|
||||
bounds = extend_bounds_if_needed(bounds, M.bounds)
|
||||
z_offset++
|
||||
else
|
||||
return FALSE
|
||||
width = bounds[MAP_MAXX] - bounds[MAP_MINX] + 1
|
||||
height = bounds[MAP_MAXY] - bounds[MAP_MINX] + 1
|
||||
return bounds
|
||||
|
||||
/datum/map_template/proc/initTemplateBounds(var/list/bounds)
|
||||
var/list/obj/structure/cable/cables = list()
|
||||
var/list/atom/atoms = list()
|
||||
/datum/map_template/proc/load_new_z(var/no_changeturf = TRUE)
|
||||
var/x = round((world.maxx - width)/2)
|
||||
var/y = round((world.maxy - height)/2)
|
||||
var/initial_z = world.maxz + 1
|
||||
|
||||
for(var/L in block(locate(bounds[MAP_MINX], bounds[MAP_MINY], bounds[MAP_MINZ]),
|
||||
locate(bounds[MAP_MAXX], bounds[MAP_MAXY], bounds[MAP_MAXZ])))
|
||||
if (x < 1) x = 1
|
||||
if (y < 1) y = 1
|
||||
|
||||
var/list/bounds = list(1.#INF, 1.#INF, 1.#INF, -1.#INF, -1.#INF, -1.#INF)
|
||||
var/list/atoms_to_initialise = list()
|
||||
var/shuttle_state = pre_init_shuttles()
|
||||
|
||||
var/turf/B = L
|
||||
if (!B.initialized)
|
||||
atoms += B
|
||||
|
||||
if (TURF_IS_DYNAMICALLY_LIT_UNSAFE(B) && !B.lighting_overlay)
|
||||
new /atom/movable/lighting_overlay(B)
|
||||
|
||||
for(var/thing in B)
|
||||
if(istype(thing, /obj/structure/cable))
|
||||
cables += thing
|
||||
|
||||
var/atom/movable/AM = thing
|
||||
if (!AM.initialized)
|
||||
atoms += AM
|
||||
|
||||
SSatoms.InitializeAtoms(atoms)
|
||||
SSmachinery.setup_template_powernets(cables)
|
||||
|
||||
/datum/map_template/proc/load_new_z()
|
||||
var/x = round(world.maxx / 2)
|
||||
var/y = round(world.maxy / 2)
|
||||
|
||||
var/list/bounds = maploader.load_map(file(mappath), x, y, no_changeturf = TRUE)
|
||||
if(!bounds)
|
||||
var/datum/map_load_metadata/M = maploader.load_map(file(mappath), x, y, no_changeturf = no_changeturf)
|
||||
if (M)
|
||||
bounds = extend_bounds_if_needed(bounds, M.bounds)
|
||||
atoms_to_initialise += M.atoms_to_initialise
|
||||
else
|
||||
return FALSE
|
||||
|
||||
for (var/z_index = bounds[MAP_MINZ]; z_index <= bounds[MAP_MAXZ]; z_index++)
|
||||
if (accessibility_weight)
|
||||
current_map.accessible_z_levels[num2text(z_index)] = accessibility_weight
|
||||
if (base_turf_for_zs)
|
||||
current_map.base_turf_by_z[num2text(z_index)] = base_turf_for_zs
|
||||
current_map.player_levels |= z_index
|
||||
|
||||
smooth_zlevel(world.maxz)
|
||||
resort_all_areas()
|
||||
|
||||
//initialize things that are normally initialized after map load
|
||||
initTemplateBounds(bounds)
|
||||
init_atoms(atoms_to_initialise)
|
||||
init_shuttles(shuttle_state)
|
||||
after_load(initial_z)
|
||||
for(var/light_z = initial_z to world.maxz)
|
||||
create_lighting_overlays_zlevel(light_z)
|
||||
log_game("Z-level [name] loaded at [x], [y], [world.maxz]")
|
||||
loaded++
|
||||
|
||||
return locate(world.maxx/2, world.maxy/2, world.maxz)
|
||||
|
||||
/datum/map_template/proc/pre_init_shuttles()
|
||||
. = SSshuttle.block_queue
|
||||
SSshuttle.block_queue = TRUE
|
||||
|
||||
/datum/map_template/proc/init_shuttles(var/pre_init_state)
|
||||
for (var/shuttle_type in shuttles_to_initialise)
|
||||
LAZYADD(SSshuttle.shuttles_to_initialize, shuttle_type) // queue up for init.
|
||||
SSshuttle.block_queue = pre_init_state
|
||||
SSshuttle.clear_init_queue() // We will flush the queue unless there were other blockers, in which case they will do it.
|
||||
|
||||
/datum/map_template/proc/init_atoms(var/list/atoms)
|
||||
if (SSatoms.initialized == INITIALIZATION_INSSATOMS)
|
||||
return // let proper initialisation handle it later
|
||||
|
||||
var/list/turf/turfs = list()
|
||||
var/list/obj/machinery/atmospherics/atmos_machines = list()
|
||||
var/list/obj/machinery/machines = list()
|
||||
var/list/obj/structure/cable/cables = list()
|
||||
|
||||
for(var/atom/A in atoms)
|
||||
if(istype(A, /turf))
|
||||
turfs += A
|
||||
if(istype(A, /obj/structure/cable))
|
||||
cables += A
|
||||
if(istype(A, /obj/machinery/atmospherics))
|
||||
atmos_machines += A
|
||||
if(istype(A, /obj/machinery))
|
||||
machines += A
|
||||
if(istype(A,/obj/effect/landmark/map_load_mark))
|
||||
LAZYADD(subtemplates_to_spawn, A)
|
||||
|
||||
var/notsuspended
|
||||
if(!SSmachinery.suspended)
|
||||
SSmachinery.suspend()
|
||||
notsuspended = TRUE
|
||||
|
||||
SSatoms.InitializeAtoms() // The atoms should have been getting queued there. This flushes the queue.
|
||||
|
||||
SSmachinery.setup_template_powernets(cables)
|
||||
SSmachinery.setup_atmos_machinery(atmos_machines)
|
||||
if(notsuspended)
|
||||
SSmachinery.wake()
|
||||
|
||||
for (var/i in machines)
|
||||
var/obj/machinery/machine = i
|
||||
machine.power_change()
|
||||
|
||||
for (var/i in turfs)
|
||||
var/turf/T = i
|
||||
T.post_change()
|
||||
if(template_flags & TEMPLATE_FLAG_NO_RUINS)
|
||||
T.flags |= TURF_NORUINS
|
||||
if(istype(T,/turf/simulated))
|
||||
var/turf/simulated/sim = T
|
||||
sim.update_air_properties()
|
||||
|
||||
/datum/map_template/proc/load(turf/T, centered = FALSE)
|
||||
if(centered)
|
||||
@@ -78,12 +139,18 @@
|
||||
if(T.y + height > world.maxy)
|
||||
return
|
||||
|
||||
var/list/bounds = maploader.load_map(file(mappath), T.x, T.y, T.z, cropMap=TRUE, no_changeturf = FALSE)
|
||||
if(!bounds)
|
||||
return
|
||||
var/list/atoms_to_initialise = list()
|
||||
var/shuttle_state = pre_init_shuttles()
|
||||
|
||||
var/datum/map_load_metadata/M = maploader.load_map(file(mappath), T.x, T.y, T.z, cropMap=TRUE, no_changeturf = FALSE)
|
||||
if (M)
|
||||
atoms_to_initialise += M.atoms_to_initialise
|
||||
else
|
||||
return FALSE
|
||||
|
||||
//initialize things that are normally initialized after map load
|
||||
initTemplateBounds(bounds)
|
||||
init_atoms(atoms_to_initialise)
|
||||
init_shuttles(shuttle_state)
|
||||
|
||||
log_game("[name] loaded at [T.x], [T.y], [T.z]")
|
||||
return TRUE
|
||||
@@ -95,3 +162,21 @@
|
||||
if(corner)
|
||||
placement = corner
|
||||
return block(placement, locate(placement.x + width-1, placement.y + height-1, placement.z))
|
||||
|
||||
/datum/map_template/proc/extend_bounds_if_needed(var/list/existing_bounds, var/list/new_bounds)
|
||||
var/list/bounds_to_combine = existing_bounds.Copy()
|
||||
for (var/min_bound in list(MAP_MINX, MAP_MINY, MAP_MINZ))
|
||||
bounds_to_combine[min_bound] = min(existing_bounds[min_bound], new_bounds[min_bound])
|
||||
for (var/max_bound in list(MAP_MAXX, MAP_MAXY, MAP_MAXZ))
|
||||
bounds_to_combine[max_bound] = max(existing_bounds[max_bound], new_bounds[max_bound])
|
||||
return bounds_to_combine
|
||||
|
||||
/datum/map_template/proc/after_load(z)
|
||||
for(var/obj/effect/landmark/map_load_mark/mark in subtemplates_to_spawn)
|
||||
subtemplates_to_spawn -= mark
|
||||
if(LAZYLEN(mark.templates))
|
||||
var/template = pick(mark.templates)
|
||||
var/datum/map_template/M = new template()
|
||||
M.load(get_turf(mark), TRUE)
|
||||
qdel(mark)
|
||||
LAZYCLEARLIST(subtemplates_to_spawn)
|
||||
@@ -42,8 +42,7 @@
|
||||
smoothing_iterations = 4
|
||||
land_type = /turf/simulated/floor/exoplanet/desert
|
||||
|
||||
flora_prob = 5
|
||||
flora_diversity = 4
|
||||
flora_prob = 0
|
||||
fauna_types = list(/mob/living/simple_animal/thinbug, /mob/living/simple_animal/tindalos)
|
||||
|
||||
/datum/random_map/noise/exoplanet/desert/get_additional_spawns(var/value, var/turf/T)
|
||||
@@ -52,7 +51,6 @@
|
||||
return
|
||||
var/v = noise2value(value)
|
||||
if(v > 6)
|
||||
T.icon_state = "desert[v-1]"
|
||||
if(prob(10))
|
||||
new/obj/structure/quicksand(T)
|
||||
|
||||
|
||||
@@ -6,6 +6,10 @@
|
||||
var/global/use_preloader = FALSE
|
||||
var/global/dmm_suite/preloader/_preloader = new
|
||||
|
||||
/datum/map_load_metadata
|
||||
var/bounds
|
||||
var/list/atoms_to_initialise
|
||||
|
||||
/dmm_suite
|
||||
// /"([a-zA-Z]+)" = \(((?:.|\n)*?)\)\n(?!\t)|\((\d+),(\d+),(\d+)\) = \{"([a-zA-Z\n]*)"\}/g
|
||||
var/static/regex/dmmRegex = new/regex({""(\[a-zA-Z]+)" = \\(((?:.|\n)*?)\\)\n(?!\t)|\\((\\d+),(\\d+),(\\d+)\\) = \\{"(\[a-zA-Z\n]*)"\\}"}, "g")
|
||||
@@ -60,6 +64,7 @@ var/global/dmm_suite/preloader/_preloader = new
|
||||
var/key_len = 0
|
||||
|
||||
var/stored_index = 1
|
||||
var/list/atoms_to_initialise = list()
|
||||
|
||||
while(dmmRegex.Find(tfile, stored_index))
|
||||
stored_index = dmmRegex.next
|
||||
@@ -156,7 +161,9 @@ var/global/dmm_suite/preloader/_preloader = new
|
||||
if(!no_afterchange || (model_key != space_key))
|
||||
if(!grid_models[model_key])
|
||||
throw EXCEPTION("Undefined model key in DMM.")
|
||||
parse_grid(grid_models[model_key], model_key, xcrd, ycrd, zcrd, no_changeturf || zexpansion)
|
||||
var/datum/grid_load_metadata/M = parse_grid(grid_models[model_key], model_key, xcrd, ycrd, zcrd, no_changeturf || zexpansion)
|
||||
if (M)
|
||||
atoms_to_initialise += M.atoms_to_initialise
|
||||
#ifdef TESTING
|
||||
else
|
||||
++turfsSkipped
|
||||
@@ -179,7 +186,15 @@ var/global/dmm_suite/preloader/_preloader = new
|
||||
var/turf/T = t
|
||||
//we do this after we load everything in. if we don't; we'll have weird atmos bugs regarding atmos adjacent turfs
|
||||
T.post_change(TRUE)
|
||||
return bounds
|
||||
var/datum/map_load_metadata/M = new
|
||||
M.bounds = bounds
|
||||
M.atoms_to_initialise = atoms_to_initialise
|
||||
return M
|
||||
|
||||
/datum/grid_load_metadata
|
||||
var/list/atoms_to_initialise
|
||||
var/list/atoms_to_delete
|
||||
|
||||
|
||||
/**
|
||||
* Fill a given tile with its area/turf/objects/mobs
|
||||
@@ -308,23 +323,35 @@ var/global/dmm_suite/preloader/_preloader = new
|
||||
|
||||
//turn off base new Initialization until the whole thing is loaded
|
||||
SSatoms.map_loader_begin()
|
||||
//since we've switched off autoinitialisation, record atoms to initialise later
|
||||
var/list/atoms_to_initialise = list()
|
||||
|
||||
//instanciate the first /turf
|
||||
var/turf/T
|
||||
if(members[first_turf_index] != /turf/template_noop)
|
||||
T = instance_atom(members[first_turf_index],members_attributes[first_turf_index],crds,no_changeturf)
|
||||
atoms_to_initialise += T
|
||||
|
||||
if(T)
|
||||
//if others /turf are presents, simulates the underlays piling effect
|
||||
index = first_turf_index + 1
|
||||
while(index <= members.len - 1) // Last item is an /area
|
||||
crash_with("Tried to load additional turf at [model_key].")
|
||||
var/underlay = T.appearance
|
||||
T = instance_atom(members[index],members_attributes[index],crds,no_changeturf)//instance new turf
|
||||
T.underlays += underlay
|
||||
index++
|
||||
atoms_to_initialise += T
|
||||
|
||||
//finally instance all remainings objects/mobs
|
||||
for(index in 1 to first_turf_index-1)
|
||||
instance_atom(members[index],members_attributes[index],crds,no_changeturf)
|
||||
atoms_to_initialise += instance_atom(members[index],members_attributes[index],crds,no_changeturf)
|
||||
//Restore initialization to the previous value
|
||||
SSatoms.map_loader_stop()
|
||||
|
||||
var/datum/grid_load_metadata/M = new
|
||||
M.atoms_to_initialise = atoms_to_initialise
|
||||
return M
|
||||
|
||||
////////////////
|
||||
//Helpers procs
|
||||
////////////////
|
||||
|
||||
@@ -18,7 +18,7 @@ var/list/banned_ruin_ids = list()
|
||||
for(var/datum/map_template/ruin/ruin in potentialRuins)
|
||||
if (ruin.id in banned_ruin_ids)
|
||||
continue
|
||||
if(!(SSatlas.current_sector.name in ruin.sectors) && !length(ruin.sectors))
|
||||
if(!(SSatlas.current_sector.name in ruin.sectors))
|
||||
continue
|
||||
available[ruin] = ruin.spawn_weight
|
||||
|
||||
@@ -27,7 +27,7 @@ var/list/banned_ruin_ids = list()
|
||||
|
||||
while (remaining > 0 && length(available))
|
||||
var/datum/map_template/ruin/ruin = pickweight(available)
|
||||
if (ruin.cost > budget)
|
||||
if (ruin.spawn_cost > budget)
|
||||
available -= ruin
|
||||
continue
|
||||
|
||||
@@ -52,12 +52,12 @@ var/list/banned_ruin_ids = list()
|
||||
if (!valid)
|
||||
continue
|
||||
|
||||
log_admin("Ruin \"[ruin.name]\" placed at ([choice.x], [choice.y], [choice.z])")
|
||||
log_admin("Ruin \"[ruin.name]\" placed at ([choice.x], [choice.y], [choice.z])!")
|
||||
|
||||
load_ruin(choice, ruin)
|
||||
selected += ruin
|
||||
if (ruin.cost > 0)
|
||||
remaining -= ruin.cost
|
||||
if (ruin.spawn_cost > 0)
|
||||
remaining -= ruin.spawn_cost
|
||||
if (!(ruin.template_flags & TEMPLATE_FLAG_ALLOW_DUPLICATES))
|
||||
banned_ruin_ids += ruin.id
|
||||
available -= ruin
|
||||
@@ -78,7 +78,7 @@ var/list/banned_ruin_ids = list()
|
||||
var/turf/T = i
|
||||
for(var/mob/living/simple_animal/monster in T)
|
||||
qdel(monster)
|
||||
template.load(central_turf,centered = TRUE)
|
||||
template.load(central_turf, TRUE)
|
||||
var/datum/map_template/ruin = template
|
||||
if(istype(ruin))
|
||||
new /obj/effect/landmark/ruin(central_turf, ruin)
|
||||
|
||||
@@ -152,7 +152,7 @@
|
||||
|
||||
/turf/simulated/floor/exoplanet/desert/Initialize()
|
||||
. = ..()
|
||||
icon_state = "desert[rand(0,5)]"
|
||||
icon_state = "desert[rand(0,4)]"
|
||||
|
||||
//Concrete
|
||||
/turf/simulated/floor/exoplanet/concrete
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
/datum/submap
|
||||
var/name
|
||||
var/pref_name
|
||||
var/decl/submap_archetype/archetype
|
||||
var/associated_z
|
||||
|
||||
/datum/submap/New(var/existing_z)
|
||||
SSmapping.submaps[src] = TRUE
|
||||
associated_z = existing_z
|
||||
|
||||
/datum/submap/Destroy()
|
||||
SSmapping.submaps -= src
|
||||
. = ..()
|
||||
|
||||
/datum/submap/proc/setup_submap(var/decl/submap_archetype/_archetype)
|
||||
|
||||
if(!istype(_archetype))
|
||||
log_game( "Submap error - [name] - null or invalid archetype supplied ([_archetype]).")
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
// Not much point doing this when it has presumably been done already.
|
||||
if(_archetype == archetype)
|
||||
log_game( "Submap error - [name] - submap already set up.")
|
||||
return
|
||||
|
||||
archetype = _archetype
|
||||
if(!pref_name)
|
||||
pref_name = archetype.descriptor
|
||||
|
||||
log_game("Starting submap setup - '[name]', [archetype], [associated_z]z.")
|
||||
|
||||
if(!associated_z)
|
||||
log_game( "Submap error - [name]/[archetype ? archetype.descriptor : "NO ARCHETYPE"] could not find an associated z-level for spawnpoint placement.")
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
var/obj/effect/overmap/visitable/cell = map_sectors["[associated_z]"]
|
||||
if(istype(cell))
|
||||
sync_cell(cell)
|
||||
|
||||
/datum/submap/proc/sync_cell(var/obj/effect/overmap/visitable/cell)
|
||||
name = cell.name
|
||||
|
||||
/datum/submap/proc/available()
|
||||
return TRUE
|
||||
@@ -0,0 +1,15 @@
|
||||
/decl/submap_archetype
|
||||
var/map
|
||||
var/descriptor = "generic ship archetype"
|
||||
|
||||
/decl/submap_archetype/Destroy()
|
||||
if(SSmapping.submap_archetypes[descriptor] == src)
|
||||
SSmapping.submap_archetypes -= descriptor
|
||||
. = ..()
|
||||
|
||||
// Generic ships to populate the list.
|
||||
/decl/submap_archetype/derelict
|
||||
descriptor = "drifting wreck"
|
||||
|
||||
/decl/submap_archetype/abandoned_ship
|
||||
descriptor = "abandoned ship"
|
||||
@@ -0,0 +1,25 @@
|
||||
/obj/effect/submap_landmark
|
||||
icon = 'icons/misc/mark.dmi'
|
||||
invisibility = INVISIBILITY_MAXIMUM
|
||||
anchored = TRUE
|
||||
simulated = FALSE
|
||||
density = FALSE
|
||||
opacity = FALSE
|
||||
|
||||
/obj/effect/submap_landmark/joinable_submap
|
||||
icon_state = "x4"
|
||||
var/archetype
|
||||
var/submap_datum_type = /datum/submap
|
||||
|
||||
/obj/effect/submap_landmark/joinable_submap/Initialize(var/mapload)
|
||||
. = ..(mapload)
|
||||
if(!SSmapping.submaps[name] && SSmapping.submap_archetypes[archetype])
|
||||
var/datum/submap/submap = new submap_datum_type(z)
|
||||
submap.name = name
|
||||
submap.setup_submap(SSmapping.submap_archetypes[archetype])
|
||||
else
|
||||
if(SSmapping.submaps[name])
|
||||
log_debug( "Submap error - mapped landmark is duplicate of existing.")
|
||||
else
|
||||
log_debug( "Submap error - mapped landmark had invalid archetype.")
|
||||
return INITIALIZE_HINT_QDEL
|
||||
@@ -0,0 +1,5 @@
|
||||
#Listing maps here will blacklist them from generating as away sites.
|
||||
#Maps must be the full path to them
|
||||
#SPECIFYING AN INVALID MAP WILL RESULT IN RUNTIMES ON GAME START
|
||||
|
||||
#maps/random_ruins/away_sites/example.dmm
|
||||
@@ -0,0 +1,5 @@
|
||||
#Listing maps here will blacklist them from generating on exoplanets.
|
||||
#Maps must be the full path to them
|
||||
#SPECIFYING AN INVALID MAP WILL RESULT IN RUNTIMES ON GAME START
|
||||
|
||||
#maps/random_ruins/exoplanet_ruins/example.dmm
|
||||
@@ -0,0 +1,6 @@
|
||||
#Listing maps here will blacklist them from generating in space.
|
||||
#Maps must be the full path to them
|
||||
#SPECIFYING AN INVALID MAP WILL RESULT IN RUNTIMES ON GAME START
|
||||
|
||||
#maps/random_ruins/space_ruins/example.dmm
|
||||
maps/random_ruins/exoplanets/crashed_pod/crashed_pod.dmm
|
||||
@@ -0,0 +1,42 @@
|
||||
################################
|
||||
# Example Changelog File
|
||||
#
|
||||
# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb.
|
||||
#
|
||||
# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.)
|
||||
# When it is, any changes listed below will disappear.
|
||||
#
|
||||
# Valid Prefixes:
|
||||
# bugfix
|
||||
# wip (For works in progress)
|
||||
# tweak
|
||||
# soundadd
|
||||
# sounddel
|
||||
# rscadd (general adding of nice things)
|
||||
# rscdel (general deleting of nice things)
|
||||
# imageadd
|
||||
# imagedel
|
||||
# maptweak
|
||||
# spellcheck (typo fixes)
|
||||
# experiment
|
||||
# balance
|
||||
# admin
|
||||
# backend
|
||||
# security
|
||||
# refactor
|
||||
#################################
|
||||
|
||||
# Your name.
|
||||
author: MattAtlas
|
||||
|
||||
# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again.
|
||||
delete-after: True
|
||||
|
||||
# Any changes you've made. See valid prefix list above.
|
||||
# INDENT WITH TWO SPACES. NOT TABS. SPACES.
|
||||
# SCREW THIS UP AND IT WON'T WORK.
|
||||
# Also, all entries are changed into a single [] after a master changelog generation. Just remove the brackets when you add new entries.
|
||||
# Please surround your changes in double quotes ("), as certain characters otherwise screws up compiling. The quotes will not show up in the changelog.
|
||||
changes:
|
||||
- experiment: "Ported Baystation's improvements to the maploader."
|
||||
- experiment: "Ported Baystation's system for Overmap away sites and exoplanet ruin generation."
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 800 B |
@@ -107,6 +107,8 @@
|
||||
|
||||
var/num_exoplanets = 0
|
||||
var/list/planet_size //dimensions of planet zlevel, defaults to world size. Due to how maps are generated, must be (2^n+1) e.g. 17,33,65,129 etc. Map will just round up to those if set to anything other.
|
||||
var/min_offmap_players = 0
|
||||
var/away_site_budget = 0
|
||||
|
||||
/datum/map/New()
|
||||
if(!map_levels)
|
||||
@@ -161,3 +163,93 @@
|
||||
log_debug("Building new exoplanet with type: [exoplanet_type] and size: [planet_size[1]] [planet_size[2]]")
|
||||
var/obj/effect/overmap/visitable/sector/exoplanet/new_planet = new exoplanet_type(null, planet_size[1], planet_size[2])
|
||||
new_planet.build_level()
|
||||
|
||||
/* It is perfectly possible to create loops with TEMPLATE_FLAG_ALLOW_DUPLICATES and force/allow. Don't. */
|
||||
/proc/resolve_site_selection(datum/map_template/ruin/away_site/site, list/selected, list/available, list/unavailable, list/by_type)
|
||||
var/spawn_cost = 0
|
||||
var/player_cost = 0
|
||||
if (site in selected)
|
||||
if (!(site.template_flags & TEMPLATE_FLAG_ALLOW_DUPLICATES))
|
||||
return list(spawn_cost, player_cost)
|
||||
if (!(site.template_flags & TEMPLATE_FLAG_ALLOW_DUPLICATES))
|
||||
available -= site
|
||||
spawn_cost += site.spawn_cost
|
||||
player_cost += site.player_cost
|
||||
selected += site
|
||||
|
||||
for (var/forced_type in site.force_ruins)
|
||||
var/list/costs = resolve_site_selection(by_type[forced_type], selected, available, unavailable, by_type)
|
||||
spawn_cost += costs[1]
|
||||
player_cost += costs[2]
|
||||
|
||||
for (var/banned_type in site.ban_ruins)
|
||||
var/datum/map_template/ruin/away_site/banned = by_type[banned_type]
|
||||
if (banned in unavailable)
|
||||
continue
|
||||
unavailable += banned
|
||||
available -= banned
|
||||
|
||||
for (var/allowed_type in site.allow_ruins)
|
||||
var/datum/map_template/ruin/away_site/allowed = by_type[allowed_type]
|
||||
if (allowed in available)
|
||||
continue
|
||||
if (allowed in unavailable)
|
||||
continue
|
||||
if (allowed in selected)
|
||||
if (!(allowed.template_flags & TEMPLATE_FLAG_ALLOW_DUPLICATES))
|
||||
continue
|
||||
available[allowed] = allowed.spawn_weight
|
||||
|
||||
return list(spawn_cost, player_cost)
|
||||
|
||||
/datum/map/proc/build_away_sites()
|
||||
#ifdef UNIT_TEST
|
||||
log_admin("Unit testing, so not loading away sites")
|
||||
return // don't build away sites during unit testing
|
||||
#else
|
||||
log_admin("Loading away sites...")
|
||||
|
||||
var/list/guaranteed = list()
|
||||
var/list/selected = list()
|
||||
var/list/available = list()
|
||||
var/list/unavailable = list()
|
||||
var/list/by_type = list()
|
||||
|
||||
for (var/site_name in SSmapping.away_sites_templates)
|
||||
var/datum/map_template/ruin/away_site/site = SSmapping.away_sites_templates[site_name]
|
||||
if (site.template_flags & TEMPLATE_FLAG_SPAWN_GUARANTEED)
|
||||
guaranteed += site
|
||||
if ((site.template_flags & TEMPLATE_FLAG_ALLOW_DUPLICATES) && !(site.template_flags & TEMPLATE_FLAG_RUIN_STARTS_DISALLOWED))
|
||||
available[site] = site.spawn_weight
|
||||
else if (!(site.template_flags & TEMPLATE_FLAG_RUIN_STARTS_DISALLOWED))
|
||||
available[site] = site.spawn_weight
|
||||
by_type[site.type] = site
|
||||
|
||||
var/points = away_site_budget
|
||||
var/players = -min_offmap_players
|
||||
for (var/client/C)
|
||||
++players
|
||||
|
||||
for (var/datum/map_template/ruin/away_site/site in guaranteed)
|
||||
var/list/costs = resolve_site_selection(site, selected, available, unavailable, by_type)
|
||||
points -= costs[1]
|
||||
players -= costs[2]
|
||||
|
||||
while (points > 0 && length(available))
|
||||
var/datum/map_template/ruin/away_site/site = pickweight(available)
|
||||
if (site.spawn_cost && site.spawn_cost > points || site.player_cost && site.player_cost > players)
|
||||
unavailable += site
|
||||
available -= site
|
||||
continue
|
||||
var/list/costs = resolve_site_selection(site, selected, available, unavailable, by_type)
|
||||
points -= costs[1]
|
||||
players -= costs[2]
|
||||
|
||||
log_admin("Finished selecting away sites ([english_list(selected)]) for [away_site_budget - points] cost of [away_site_budget] budget.")
|
||||
|
||||
for (var/datum/map_template/template in selected)
|
||||
if (template.load_new_z())
|
||||
log_admin("Loaded away site [template]!")
|
||||
else
|
||||
log_admin("Failed loading away site [template]!")
|
||||
#endif
|
||||
@@ -0,0 +1,53 @@
|
||||
# Away sites
|
||||
|
||||
## What exactly is an away site?
|
||||
|
||||
It's a kind of map template which:
|
||||
* is placed in its own zlevel (or collection of zlevels),
|
||||
* should only get placed once per round,
|
||||
* can be randomly picked to be placed automatically during round setup,
|
||||
* normally has an overmap presence and shuttle landmarks so ships can fly to it.
|
||||
|
||||
### Er, what's a map template?
|
||||
|
||||
It's a datum you can define in the code (`/datum/map_template`) which points at one or more .dmm map files, and allows the game (or admins) to spawn those map files when and where they please, whether that's into an existing zlevel (like decorating exoplanets with ruins), or on a totally fresh one (like an away site!).
|
||||
|
||||
## How do I make away sites?
|
||||
|
||||
tl;dr you make your .dmm files, then you write a new map template datum (`/datum/map_template/ruin/away_site/insert_your_away_site_name_here`).
|
||||
|
||||
BUT HEED MY RUMINATIONS
|
||||
|
||||
## While mapping
|
||||
|
||||
### Don't use map-specific types
|
||||
|
||||
Away maps are expected to work whether you're on the main map, Runtime, or anything else you might want to load as the server's main map. That means your map mustn't use areas, turfs, objects, mobs or datums that are specific to any main map.
|
||||
|
||||
e.g. you can use `/area/space`, or `/turf/simulated/wall`, because neither are specific to a certain map. They live out in the main codebase, are always compiled in, and are available to all maps. But you can't use items that may only be compiled with a certain map, because they only exists when said map is compiled.
|
||||
|
||||
### Don't re-use area types from other maps
|
||||
|
||||
Except for, like, `/area/space`. That one's probably fine.
|
||||
|
||||
(Now that's just areas! Other stuff might be ok. Except very map-specific stuff as noted!)
|
||||
|
||||
Re-using areas is a shortcut, but it's bad for testability, and you can't guarantee that the area you re-use isn't loaded up and in active use on the server - in which case it'll hideously merge together with its brother in terms of stuff like air alarms, APCs, etc. Suddenly your derelict starship is randomly receiving power from another zlevel. Not good. Avoid. Make your own area types!
|
||||
|
||||
### If you're doing multi-z, make a different .dmm file for each zlevel
|
||||
|
||||
Not exactly a technical requirement, but it makes things easier in terms of collaboration. See how it's done with `runtime-1.dmm`, `runtime-2.dmm`, etc.
|
||||
|
||||
## Afterwards (or during, I'm not a cop)
|
||||
|
||||
### Make sure you've got a .dm file for all your stuff
|
||||
|
||||
It's a pretty good place to put all your new types! #include other files here too. This file's going to be the hub of your map's wheel, to cack-hand a metaphor.
|
||||
|
||||
### Make a map template datum there
|
||||
|
||||
The game will read this to learn about your new shiny away sites, including what .dmm files it needs to load, how much it 'costs' to spawn (usually 1, increase for more performance-heavy away sites). Ask devs or read code if unsure..
|
||||
|
||||
### Some of the stuff I put in my map isn't behaving properly!
|
||||
|
||||
The map loader works best when everything it's spawning does all its initialisation work in `Initialize`, instead of in `New`. Most likely your misbehaving thing is doing more initialisation than is healthy in `New`. It's fixable! Often not even that hard. Go talk to a dev.
|
||||
@@ -0,0 +1,5 @@
|
||||
// Hey! Listen! Update \config\away_site_blacklist.txt with your new ruins!
|
||||
|
||||
/datum/map_template/ruin/away_site
|
||||
var/list/generate_mining_by_z
|
||||
prefix = "maps/away/"
|
||||
@@ -0,0 +1,18 @@
|
||||
/datum/map_template/ruin/exoplanet/crashed_pod
|
||||
name = "crashed survival pod" //This map is not very elaborate and is meant to be an example on how to make a ruin.
|
||||
id = "crashed_pod"
|
||||
description = "A crashed survival pod from a destroyed ship."
|
||||
suffix = "crashed_pod/crashed_pod.dmm"
|
||||
template_flags = TEMPLATE_FLAG_CLEAR_CONTENTS | TEMPLATE_FLAG_NO_RUINS | TEMPLATE_FLAG_RUIN_STARTS_DISALLOWED
|
||||
ruin_tags = RUIN_HUMAN|RUIN_WRECK
|
||||
spawn_weight = 0.33
|
||||
|
||||
/decl/submap_archetype/crashed_pod
|
||||
descriptor = "crashed survival pod"
|
||||
|
||||
/datum/submap/crashed_pod/sync_cell(var/obj/effect/overmap/visitable/cell)
|
||||
return
|
||||
|
||||
/area/map_template/crashed_pod
|
||||
name = "Crashed Pod"
|
||||
icon_state = "blue"
|
||||
@@ -0,0 +1,26 @@
|
||||
"a" = (/turf/template_noop,/area/template_noop)
|
||||
"b" = (/turf/template_noop,/area/space)
|
||||
"c" = (/turf/simulated/wall/shuttle/dark,/area/map_template/crashed_pod)
|
||||
"d" = (/obj/structure/bed/stool/chair/shuttle,/turf/simulated/floor/tiled,/area/map_template/crashed_pod)
|
||||
"e" = (/obj/machinery/suit_storage_unit/standard_unit,/turf/simulated/floor/tiled,/area/map_template/crashed_pod)
|
||||
"f" = (/turf/simulated/floor/tiled,/area/map_template/crashed_pod)
|
||||
"g" = (/obj/structure/table/rack,/obj/item/storage/toolbox/emergency,/obj/item/storage/toolbox/emergency,/obj/item/storage/toolbox/emergency,/obj/item/storage/belt/utility,/obj/item/storage/belt/utility,/obj/item/storage/belt/utility,/obj/item/clothing/gloves/yellow,/obj/item/clothing/gloves/yellow,/obj/item/clothing/gloves/yellow,/turf/simulated/floor/tiled,/area/map_template/crashed_pod)
|
||||
"h" = (/obj/structure/closet/toolcloset,/turf/simulated/floor/tiled,/area/map_template/crashed_pod)
|
||||
"i" = (/obj/machinery/power/terminal{dir = 8},/obj/structure/cable{dir = 8},/obj/machinery/power/apc/super{pixel_x = -32},/turf/simulated/floor/tiled,/area/map_template/crashed_pod)
|
||||
"k" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/tiled,/area/map_template/crashed_pod)
|
||||
"l" = (/obj/machinery/power/smes/buildable,/obj/structure/cable{dir = 4},/turf/simulated/floor/tiled,/area/map_template/crashed_pod)
|
||||
"n" = (/obj/machinery/autolathe,/turf/simulated/floor/tiled,/area/map_template/crashed_pod)
|
||||
"o" = (/obj/structure/droppod_door,/turf/simulated/wall/shuttle/dark,/area/map_template/crashed_pod)
|
||||
|
||||
(1,1,1) = {"
|
||||
abbbbbbbbb
|
||||
accccccccb
|
||||
acdddeeecb
|
||||
acffffffcb
|
||||
acgffffhcb
|
||||
acikkkklcb
|
||||
achffffncb
|
||||
achfffffcb
|
||||
accooocccb
|
||||
aaaaaaaaaa
|
||||
"}
|
||||
@@ -1,3 +1,3 @@
|
||||
/datum/map_template/ruin/exoplanet
|
||||
prefix = "maps/random_ruins/exoplanet_ruins/"
|
||||
prefix = "maps/random_ruins/exoplanets/"
|
||||
var/list/ruin_tags
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE
|
||||
"a" = (
|
||||
/turf/simulated/wall/diamond,
|
||||
/area/template_noop)
|
||||
"b" = (
|
||||
/turf/simulated/floor,
|
||||
/area/template_noop)
|
||||
"c" = (
|
||||
/mob/living/simple_animal/passive/corgi,
|
||||
/turf/simulated/floor,
|
||||
/area/template_noop)
|
||||
"d" = (
|
||||
/turf/simulated/open,
|
||||
/area/template_noop)
|
||||
"e" = (
|
||||
/turf/unsimulated/floor/shuttle_ceiling,
|
||||
/area/template_noop)
|
||||
"f" = (
|
||||
/obj/effect/landmark/map_data{
|
||||
height = 3
|
||||
},
|
||||
/turf/unsimulated/floor/shuttle_ceiling,
|
||||
/area/template_noop)
|
||||
|
||||
(1,1,1) = {"
|
||||
a
|
||||
a
|
||||
a
|
||||
a
|
||||
a
|
||||
"}
|
||||
(2,1,1) = {"
|
||||
a
|
||||
b
|
||||
b
|
||||
b
|
||||
a
|
||||
"}
|
||||
(3,1,1) = {"
|
||||
a
|
||||
b
|
||||
c
|
||||
b
|
||||
a
|
||||
"}
|
||||
(4,1,1) = {"
|
||||
a
|
||||
b
|
||||
b
|
||||
b
|
||||
a
|
||||
"}
|
||||
(5,1,1) = {"
|
||||
a
|
||||
a
|
||||
a
|
||||
a
|
||||
a
|
||||
"}
|
||||
|
||||
(1,1,2) = {"
|
||||
a
|
||||
a
|
||||
a
|
||||
a
|
||||
a
|
||||
"}
|
||||
(2,1,2) = {"
|
||||
a
|
||||
d
|
||||
d
|
||||
d
|
||||
a
|
||||
"}
|
||||
(3,1,2) = {"
|
||||
a
|
||||
d
|
||||
d
|
||||
d
|
||||
a
|
||||
"}
|
||||
(4,1,2) = {"
|
||||
a
|
||||
d
|
||||
d
|
||||
d
|
||||
a
|
||||
"}
|
||||
(5,1,2) = {"
|
||||
a
|
||||
a
|
||||
a
|
||||
a
|
||||
a
|
||||
"}
|
||||
|
||||
(1,1,3) = {"
|
||||
e
|
||||
e
|
||||
e
|
||||
e
|
||||
f
|
||||
"}
|
||||
(2,1,3) = {"
|
||||
e
|
||||
e
|
||||
e
|
||||
e
|
||||
e
|
||||
"}
|
||||
(3,1,3) = {"
|
||||
e
|
||||
e
|
||||
e
|
||||
e
|
||||
e
|
||||
"}
|
||||
(4,1,3) = {"
|
||||
e
|
||||
e
|
||||
e
|
||||
e
|
||||
e
|
||||
"}
|
||||
(5,1,3) = {"
|
||||
e
|
||||
e
|
||||
e
|
||||
e
|
||||
e
|
||||
"}
|
||||
@@ -0,0 +1,12 @@
|
||||
// Hey! Listen! Update \config\space_ruin_blacklist.txt with your new ruins!
|
||||
|
||||
/datum/map_template/ruin/space
|
||||
prefix = "maps/random_ruins/space_ruins/"
|
||||
spawn_cost = 1
|
||||
|
||||
/datum/map_template/ruin/space/multi_zas_test
|
||||
name = "Multi-ZAS Test"
|
||||
id = "multi_zas_test"
|
||||
description = "if this has vacuum in it, that's not good!"
|
||||
suffix = "multi_zas_test.dmm"
|
||||
spawn_cost = 1
|
||||
@@ -44,4 +44,6 @@
|
||||
num_exoplanets = 3
|
||||
planet_size = list(65, 65)
|
||||
|
||||
away_site_budget = 3
|
||||
|
||||
map_shuttles = list(/datum/shuttle/autodock/overmap/runtime)
|
||||
|
||||
+65
-10
@@ -2,14 +2,69 @@
|
||||
"b" = (/obj/effect/shuttle_landmark/runtime/transit,/turf/space,/area/space)
|
||||
|
||||
(1,1,1) = {"
|
||||
aaaaaaaaaa
|
||||
aaaaaaaaaa
|
||||
aaaaaaaaaa
|
||||
aaaaaaaaaa
|
||||
aaaaaaaaaa
|
||||
aaaabaaaaa
|
||||
aaaaaaaaaa
|
||||
aaaaaaaaaa
|
||||
aaaaaaaaaa
|
||||
aaaaaaaaaa
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
aaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
"}
|
||||
|
||||
Reference in New Issue
Block a user