Files
Bubberstation/code/modules/mapping/mapping_helpers.dm
LemonInTheDark 0e904f7032 [MDB IGNORE] Moves non floor turfs off /floor. You can put lattices on lavaland edition (#65504)
About The Pull Request

Alternative to #65354

Ok so like, there was a lot of not floor types on /floor. They didn't actually want any of their parent type's functionality, except maybe reacting to breaking (which was easy to move down) and some other minor stuff.
Part of what we don't want them to have is "plateable" logic.
I should not be able to put floor tiles on the snow and be fine. It's dumb.

Instead, I've moved all non floor types down to a new type, called /misc.

It holds very little logic. Mostly allowing pipes and wires and preventing blob stuff.
It also supports lattice based construction, which is one of the major changes here. I think it makes more sense, and it fixes an assumption in shuttle code that assumed you couldn't place "a new tile" by just hitting some snow with a floor tile.
Oh and lattices don't smooth with asteroid tiles anymore, this looks nicer I think.

Moving on to commits, and minor changes

Changes clf3 to try and burn any turfs it's exposed to, instead of just floors
Moves break_tile down to the turf definition, alongside burn_tile
If you're in basic buildmode and click on anything that's not handled in a targeted way, you just build plating
FUNCTION CHANGE: you can't use cult pylons to convert misc tiles over anymore
Generalizes building floors on top of something into two helper procs on /turf/open, reducing copypasta
Adds a new turf flag, IS_SOLID, that describes if a turf is tangible or not.
Uses this alongside a carpet and open check to replace plating and floor checks in carpet code. This does mean that non iron tiles can be carpeted, but I think that's fine

Moves the /floor update_icon -> update_visuals call to /open
This change is horrificly old, dating back to 8e112f6 but that commit describes nothing about why it was done. Choosing to believe it was a newfriend mistake. Uncomfortable nuking it though, because of just how old it is. Moving down instead

Create a buildable "misc" type off open, moves /dirt onto it
Basically, we want a type we can use to make something support
construction, since that can be a messy bit of logic. Also enough
structure to set things up sanely.

I'm planning on moving most misc turfs onto it, if only because
constructing on a dirt tile with rods should be possible, and the same
applies to most things

Murders captain planet, disentangles /turf/open/floor/grass/snow/basalt

Adds a diggable component that applies the behavior of "digging"
something out from a turf.

Uses it to free the above pain typepath into something a bit more
sensible

The typepaths that aren't actually used by floor tiles are moved onto
/misc

The others are given names that better describe them, and kept in
fancy_floor

Oh and snowshoes don't work on basalt anymore, sorry

Snowed over platings now actually have broken/burned icon states, fixing black holes to nowhere

Misc turfs no longer smooth as floors, so lattices will ignore them

Placing a lattice will no longer scrape the tile it's on

Ok this is a really old one.
I believe this logic is a holdover from kor's baseturf pr
(97990c9)
It used to be that turfs didn't have a concept of "beneath" and instead
just decided what should be under them by induction. This logic of "if
it's being latticed scapeaway to space" made sense then, but has since
been somewhat distorted

We do want to scape away on lattice spawn sometimes, mostly when we're
being destroyed, but not always. We especially don't want to scape away
if someone is just placing a rod, that's dumb.

Adds a path updating script for this change

I've done my best to find all the errors this repathing will pull out, but I may have missed some. I'm sorry.
Why It's Good For The Game

Very old code made better, more consistent turfs for lavaland and icebox, better visuals, minor fix to snowed plating, demon banishment in lattice placement, fixes the icebox mining shuttle not being repairable
Changelog

cl
add: Rather then being tileable with just floor tiles, lavaland turfs, asteroid and snow (among other things) now support lattice -> floor tile construction
fix: Because of the above, you can now properly fix the icebox mining shuttle
refactor: Non floor turfs are no longer typed as floor. This may break things, please yell at me if it does
/cl
2022-03-16 15:55:56 +13:00

651 lines
22 KiB
Plaintext

//Landmarks and other helpers which speed up the mapping process and reduce the number of unique instances/subtypes of items/turf/ect
/obj/effect/baseturf_helper //Set the baseturfs of every turf in the /area/ it is placed.
name = "baseturf editor"
icon = 'icons/effects/mapping_helpers.dmi'
icon_state = ""
var/list/baseturf_to_replace
var/baseturf
plane = POINT_PLANE
/obj/effect/baseturf_helper/Initialize(mapload)
. = ..()
return INITIALIZE_HINT_LATELOAD
/obj/effect/baseturf_helper/LateInitialize()
if(!baseturf_to_replace)
baseturf_to_replace = typecacheof(list(/turf/open/space,/turf/baseturf_bottom))
else if(!length(baseturf_to_replace))
baseturf_to_replace = list(baseturf_to_replace = TRUE)
else if(baseturf_to_replace[baseturf_to_replace[1]] != TRUE) // It's not associative
var/list/formatted = list()
for(var/i in baseturf_to_replace)
formatted[i] = TRUE
baseturf_to_replace = formatted
var/area/our_area = get_area(src)
for(var/i in get_area_turfs(our_area, z))
replace_baseturf(i)
qdel(src)
/obj/effect/baseturf_helper/proc/replace_baseturf(turf/thing)
if(length(thing.baseturfs))
var/list/baseturf_cache = thing.baseturfs.Copy()
for(var/i in baseturf_cache)
if(baseturf_to_replace[i])
baseturf_cache -= i
thing.baseturfs = baseturfs_string_list(baseturf_cache, thing)
if(!baseturf_cache.len)
thing.assemble_baseturfs(baseturf)
else
thing.PlaceOnBottom(null, baseturf)
else if(baseturf_to_replace[thing.baseturfs])
thing.assemble_baseturfs(baseturf)
else
thing.PlaceOnBottom(null, baseturf)
/obj/effect/baseturf_helper/space
name = "space baseturf editor"
baseturf = /turf/open/space
/obj/effect/baseturf_helper/asteroid
name = "asteroid baseturf editor"
baseturf = /turf/open/misc/asteroid
/obj/effect/baseturf_helper/asteroid/airless
name = "asteroid airless baseturf editor"
baseturf = /turf/open/misc/asteroid/airless
/obj/effect/baseturf_helper/asteroid/basalt
name = "asteroid basalt baseturf editor"
baseturf = /turf/open/misc/asteroid/basalt
/obj/effect/baseturf_helper/asteroid/snow
name = "asteroid snow baseturf editor"
baseturf = /turf/open/misc/asteroid/snow
/obj/effect/baseturf_helper/beach/sand
name = "beach sand baseturf editor"
baseturf = /turf/open/misc/beach/sand
/obj/effect/baseturf_helper/beach/water
name = "water baseturf editor"
baseturf = /turf/open/water/beach
/obj/effect/baseturf_helper/lava
name = "lava baseturf editor"
baseturf = /turf/open/lava/smooth
/obj/effect/baseturf_helper/lava_land/surface
name = "lavaland baseturf editor"
baseturf = /turf/open/lava/smooth/lava_land_surface
/obj/effect/mapping_helpers
icon = 'icons/effects/mapping_helpers.dmi'
icon_state = ""
var/late = FALSE
/obj/effect/mapping_helpers/Initialize(mapload)
..()
return late ? INITIALIZE_HINT_LATELOAD : INITIALIZE_HINT_QDEL
//airlock helpers
/obj/effect/mapping_helpers/airlock
layer = DOOR_HELPER_LAYER
/obj/effect/mapping_helpers/airlock/Initialize(mapload)
. = ..()
if(!mapload)
log_mapping("[src] spawned outside of mapload!")
return
var/obj/machinery/door/airlock/airlock = locate(/obj/machinery/door/airlock) in loc
if(!airlock)
log_mapping("[src] failed to find an airlock at [AREACOORD(src)]")
else
payload(airlock)
/obj/effect/mapping_helpers/airlock/proc/payload(obj/machinery/door/airlock/payload)
return
/obj/effect/mapping_helpers/airlock/cyclelink_helper
name = "airlock cyclelink helper"
icon_state = "airlock_cyclelink_helper"
/obj/effect/mapping_helpers/airlock/cyclelink_helper/payload(obj/machinery/door/airlock/airlock)
if(airlock.cyclelinkeddir)
log_mapping("[src] at [AREACOORD(src)] tried to set [airlock] cyclelinkeddir, but it's already set!")
else
airlock.cyclelinkeddir = dir
/obj/effect/mapping_helpers/airlock/cyclelink_helper_multi
name = "airlock multi-cyclelink helper"
icon_state = "airlock_multicyclelink_helper"
var/cycle_id
/obj/effect/mapping_helpers/airlock/cyclelink_helper_multi/payload(obj/machinery/door/airlock/airlock)
if(airlock.closeOtherId)
log_mapping("[src] at [AREACOORD(src)] tried to set [airlock] closeOtherId, but it's already set!")
else
airlock.closeOtherId = cycle_id
/obj/effect/mapping_helpers/airlock/locked
name = "airlock lock helper"
icon_state = "airlock_locked_helper"
/obj/effect/mapping_helpers/airlock/locked/payload(obj/machinery/door/airlock/airlock)
if(airlock.locked)
log_mapping("[src] at [AREACOORD(src)] tried to bolt [airlock] but it's already locked!")
else
airlock.locked = TRUE
/obj/effect/mapping_helpers/airlock/unres
name = "airlock unresctricted side helper"
icon_state = "airlock_unres_helper"
/obj/effect/mapping_helpers/airlock/unres/payload(obj/machinery/door/airlock/airlock)
airlock.unres_sides ^= dir
/obj/effect/mapping_helpers/airlock/abandoned
name = "airlock abandoned helper"
icon_state = "airlock_abandoned"
/obj/effect/mapping_helpers/airlock/abandoned/payload(obj/machinery/door/airlock/airlock)
if(airlock.abandoned)
log_mapping("[src] at [AREACOORD(src)] tried to make [airlock] abandoned but it's already abandoned!")
else
airlock.abandoned = TRUE
/obj/effect/mapping_helpers/airlock/cutaiwire
name = "airlock cut ai wire helper"
icon_state = "airlock_cutaiwire"
/obj/effect/mapping_helpers/airlock/cutaiwire/payload(obj/machinery/door/airlock/airlock)
if(airlock.cutAiWire)
log_mapping("[src] at [AREACOORD(src)] tried to cut the ai wire on [airlock] but it's already cut!")
else
airlock.cutAiWire = TRUE
//needs to do its thing before spawn_rivers() is called
INITIALIZE_IMMEDIATE(/obj/effect/mapping_helpers/no_lava)
/obj/effect/mapping_helpers/no_lava
icon_state = "no_lava"
/obj/effect/mapping_helpers/no_lava/Initialize(mapload)
. = ..()
var/turf/T = get_turf(src)
T.turf_flags |= NO_LAVA_GEN
///Helpers used for injecting stuff into atoms on the map.
/obj/effect/mapping_helpers/atom_injector
name = "Atom Injector"
icon_state = "injector"
late = TRUE
///Will inject into all fitting the criteria if false, otherwise first found.
var/first_match_only = TRUE
///Will inject into atoms of this type.
var/target_type
///Will inject into atoms with this name.
var/target_name
//Late init so everything is likely ready and loaded (no warranty)
/obj/effect/mapping_helpers/atom_injector/LateInitialize()
if(!check_validity())
return
var/turf/target_turf = get_turf(src)
var/matches_found = 0
for(var/atom/atom_on_turf as anything in target_turf.get_all_contents())
if(atom_on_turf == src)
continue
if(target_name && atom_on_turf.name != target_name)
continue
if(target_type && !istype(atom_on_turf, target_type))
continue
inject(atom_on_turf)
matches_found++
if(first_match_only)
qdel(src)
return
if(!matches_found)
stack_trace(generate_stack_trace())
qdel(src)
///Checks if whatever we are trying to inject with is valid
/obj/effect/mapping_helpers/atom_injector/proc/check_validity()
return TRUE
///Injects our stuff into the atom
/obj/effect/mapping_helpers/atom_injector/proc/inject(atom/target)
return
///Generates text for our stack trace
/obj/effect/mapping_helpers/atom_injector/proc/generate_stack_trace()
. = "[name] found no targets at ([x], [y], [z]). First Match Only: [first_match_only ? "true" : "false"] target type: [target_type] | target name: [target_name]"
///This helper applies components to things on the map directly.
/obj/effect/mapping_helpers/atom_injector/component_injector
name = "Component Injector"
icon_state = "component"
///Typepath of the component.
var/component_type
///Arguments for the component.
var/list/component_args = list()
/obj/effect/mapping_helpers/atom_injector/component_injector/check_validity()
if(!ispath(component_type, /datum/component))
CRASH("Wrong component type in [type] - [component_type] is not a component")
return TRUE
/obj/effect/mapping_helpers/atom_injector/component_injector/inject(atom/target)
var/arguments = list(component_type)
arguments += component_args
target._AddComponent(arguments)
/obj/effect/mapping_helpers/atom_injector/component_injector/generate_stack_trace()
. = ..()
. += " | component type: [component_type] | component arguments: [list2params(component_args)]"
///This helper applies elements to things on the map directly.
/obj/effect/mapping_helpers/atom_injector/element_injector
name = "Element Injector"
icon_state = "element"
///Typepath of the element.
var/element_type
///Arguments for the element.
var/list/element_args = list()
/obj/effect/mapping_helpers/atom_injector/element_injector/check_validity()
if(!ispath(element_type, /datum/element))
CRASH("Wrong element type in [type] - [element_type] is not a element")
return TRUE
/obj/effect/mapping_helpers/atom_injector/element_injector/inject(atom/target)
var/arguments = list(element_type)
arguments += element_args
target._AddElement(arguments)
/obj/effect/mapping_helpers/atom_injector/element_injector/generate_stack_trace()
. = ..()
. += " | element type: [element_type] | element arguments: [list2params(element_args)]"
///This helper applies traits to things on the map directly.
/obj/effect/mapping_helpers/atom_injector/trait_injector
name = "Trait Injector"
icon_state = "trait"
///Name of the trait, in the lower-case text (NOT the upper-case define) form.
var/trait_name
/obj/effect/mapping_helpers/atom_injector/trait_injector/check_validity()
if(!istext(trait_name))
CRASH("Wrong trait in [type] - [trait_name] is not a trait")
if(!GLOB.trait_name_map)
GLOB.trait_name_map = generate_trait_name_map()
if(!GLOB.trait_name_map.Find(trait_name))
stack_trace("Possibly wrong trait in [type] - [trait_name] is not a trait in the global trait list")
return TRUE
/obj/effect/mapping_helpers/atom_injector/trait_injector/inject(atom/target)
ADD_TRAIT(target, trait_name, MAPPING_HELPER_TRAIT)
/obj/effect/mapping_helpers/atom_injector/trait_injector/generate_stack_trace()
. = ..()
. += " | trait name: [trait_name]"
///Fetches an external dmi and applies to the target object
/obj/effect/mapping_helpers/atom_injector/custom_icon
name = "Custom Icon Injector"
icon_state = "icon"
///This is the var that will be set with the fetched icon. In case you want to set some secondary icon sheets like inhands and such.
var/target_variable = "icon"
///This should return raw dmi in response to http get request. For example: "https://github.com/tgstation/SS13-sprites/raw/master/mob/medu.dmi?raw=true"
var/icon_url
///The icon file we fetched from the http get request.
var/icon_file
/obj/effect/mapping_helpers/atom_injector/custom_icon/check_validity()
var/static/icon_cache = list()
var/static/query_in_progress = FALSE //We're using a single tmp file so keep it linear.
if(query_in_progress)
UNTIL(!query_in_progress)
if(icon_cache[icon_url])
icon_file = icon_cache[icon_url]
return TRUE
log_asset("Custom Icon Helper fetching dmi from: [icon_url]")
var/datum/http_request/request = new()
var/file_name = "tmp/custom_map_icon.dmi"
request.prepare(RUSTG_HTTP_METHOD_GET, icon_url, "", "", file_name)
query_in_progress = TRUE
request.begin_async()
UNTIL(request.is_complete())
var/datum/http_response/response = request.into_response()
if(response.errored || response.status_code != 200)
query_in_progress = FALSE
CRASH("Failed to fetch mapped custom icon from url [icon_url], code: [response.status_code], error: [response.error]")
var/icon/new_icon = new(file_name)
icon_cache[icon_url] = new_icon
query_in_progress = FALSE
icon_file = new_icon
return TRUE
/obj/effect/mapping_helpers/atom_injector/custom_icon/inject(atom/target)
if(IsAdminAdvancedProcCall())
return
target.vars[target_variable] = icon_file
/obj/effect/mapping_helpers/atom_injector/custom_icon/generate_stack_trace()
. = ..()
. += " | target variable: [target_variable] | icon url: [icon_url]"
///Fetches an external sound and applies to the target object
/obj/effect/mapping_helpers/atom_injector/custom_sound
name = "Custom Sound Injector"
icon_state = "sound"
///This is the var that will be set with the fetched sound.
var/target_variable = "hitsound"
///This should return raw sound in response to http get request. For example: "https://github.com/tgstation/tgstation/blob/master/sound/misc/bang.ogg?raw=true"
var/sound_url
///The sound file we fetched from the http get request.
var/sound_file
/obj/effect/mapping_helpers/atom_injector/custom_sound/check_validity()
var/static/sound_cache = list()
var/static/query_in_progress = FALSE //We're using a single tmp file so keep it linear.
if(query_in_progress)
UNTIL(!query_in_progress)
if(sound_cache[sound_url])
sound_file = sound_cache[sound_url]
return TRUE
log_asset("Custom Sound Helper fetching sound from: [sound_url]")
var/datum/http_request/request = new()
var/file_name = "tmp/custom_map_sound.ogg"
request.prepare(RUSTG_HTTP_METHOD_GET, sound_url, "", "", file_name)
query_in_progress = TRUE
request.begin_async()
UNTIL(request.is_complete())
var/datum/http_response/response = request.into_response()
if(response.errored || response.status_code != 200)
query_in_progress = FALSE
CRASH("Failed to fetch mapped custom sound from url [sound_url], code: [response.status_code], error: [response.error]")
var/sound/new_sound = new(file_name)
sound_cache[sound_url] = new_sound
query_in_progress = FALSE
sound_file = new_sound
return TRUE
/obj/effect/mapping_helpers/atom_injector/custom_sound/inject(atom/target)
if(IsAdminAdvancedProcCall())
return
target.vars[target_variable] = sound_file
/obj/effect/mapping_helpers/atom_injector/custom_sound/generate_stack_trace()
. = ..()
. += " | target variable: [target_variable] | sound url: [sound_url]"
/obj/effect/mapping_helpers/dead_body_placer
name = "Dead Body placer"
late = TRUE
icon_state = "deadbodyplacer"
var/bodycount = 2 //number of bodies to spawn
/obj/effect/mapping_helpers/dead_body_placer/LateInitialize()
var/area/a = get_area(src)
var/list/trays = list()
for (var/i in a.contents)
if (istype(i, /obj/structure/bodycontainer/morgue))
trays += i
if(!trays.len)
log_mapping("[src] at [x],[y] could not find any morgues.")
return
for (var/i = 1 to bodycount)
var/obj/structure/bodycontainer/morgue/j = pick(trays)
var/mob/living/carbon/human/h = new /mob/living/carbon/human(j, 1)
h.death()
for (var/part in h.internal_organs) //randomly remove organs from each body, set those we keep to be in stasis
if (prob(40))
qdel(part)
else
var/obj/item/organ/O = part
O.organ_flags |= ORGAN_FROZEN
j.update_appearance()
qdel(src)
//On Ian's birthday, the hop's office is decorated.
/obj/effect/mapping_helpers/ianbirthday
name = "Ian's Bday Helper"
late = TRUE
icon_state = "iansbdayhelper"
var/balloon_clusters = 2
/obj/effect/mapping_helpers/ianbirthday/LateInitialize()
if(locate(/datum/holiday/ianbirthday) in SSevents.holidays)
birthday()
qdel(src)
/obj/effect/mapping_helpers/ianbirthday/proc/birthday()
var/area/a = get_area(src)
var/list/table = list()//should only be one aka the front desk, but just in case...
var/list/openturfs = list()
//confetti and a corgi balloon! (and some list stuff for more decorations)
for(var/thing in a.contents)
if(istype(thing, /obj/structure/table/reinforced))
table += thing
if(isopenturf(thing))
new /obj/effect/decal/cleanable/confetti(thing)
if(locate(/obj/structure/bed/dogbed/ian) in thing)
new /obj/item/toy/balloon/corgi(thing)
else
openturfs += thing
//cake + knife to cut it!
if(length(table))
var/turf/food_turf = get_turf(pick(table))
new /obj/item/knife/kitchen(food_turf)
var/obj/item/food/cake/birthday/iancake = new(food_turf)
iancake.desc = "Happy birthday, Ian!"
//some balloons! this picks an open turf and pops a few balloons in and around that turf, yay.
for(var/i in 1 to balloon_clusters)
var/turf/clusterspot = pick_n_take(openturfs)
new /obj/item/toy/balloon(clusterspot)
var/balloons_left_to_give = 3 //the amount of balloons around the cluster
var/list/dirs_to_balloon = GLOB.cardinals.Copy()
while(balloons_left_to_give > 0)
balloons_left_to_give--
var/chosen_dir = pick_n_take(dirs_to_balloon)
var/turf/balloonstep = get_step(clusterspot, chosen_dir)
var/placed = FALSE
if(isopenturf(balloonstep))
var/obj/item/toy/balloon/B = new(balloonstep)//this clumps the cluster together
placed = TRUE
if(chosen_dir == NORTH)
B.pixel_y -= 10
if(chosen_dir == SOUTH)
B.pixel_y += 10
if(chosen_dir == EAST)
B.pixel_x -= 10
if(chosen_dir == WEST)
B.pixel_x += 10
if(!placed)
new /obj/item/toy/balloon(clusterspot)
//remind me to add wall decor!
/obj/effect/mapping_helpers/ianbirthday/admin//so admins may birthday any room
name = "generic birthday setup"
icon_state = "bdayhelper"
/obj/effect/mapping_helpers/ianbirthday/admin/LateInitialize()
birthday()
qdel(src)
//Ian, like most dogs, loves a good new years eve party.
/obj/effect/mapping_helpers/iannewyear
name = "Ian's New Years Helper"
late = TRUE
icon_state = "iansnewyrshelper"
/obj/effect/mapping_helpers/iannewyear/LateInitialize()
if(SSevents.holidays && SSevents.holidays[NEW_YEAR])
fireworks()
qdel(src)
/obj/effect/mapping_helpers/iannewyear/proc/fireworks()
var/area/a = get_area(src)
var/list/table = list()//should only be one aka the front desk, but just in case...
var/list/openturfs = list()
for(var/thing in a.contents)
if(istype(thing, /obj/structure/table/reinforced))
table += thing
else if(isopenturf(thing))
if(locate(/obj/structure/bed/dogbed/ian) in thing)
new /obj/item/clothing/head/festive(thing)
var/obj/item/reagent_containers/food/drinks/bottle/champagne/iandrink = new(thing)
iandrink.name = "dog champagne"
iandrink.pixel_y += 8
iandrink.pixel_x += 8
else
openturfs += thing
var/turf/fireworks_turf = get_turf(pick(table))
var/obj/item/storage/box/matches/matchbox = new(fireworks_turf)
matchbox.pixel_y += 8
matchbox.pixel_x -= 3
new /obj/item/storage/box/fireworks/dangerous(fireworks_turf) //dangerous version for extra holiday memes.
//lets mappers place notes on airlocks with custom info or a pre-made note from a path
/obj/effect/mapping_helpers/airlock_note_placer
name = "Airlock Note Placer"
late = TRUE
icon_state = "airlocknoteplacer"
var/note_info //for writing out custom notes without creating an extra paper subtype
var/note_name //custom note name
var/note_path //if you already have something wrote up in a paper subtype, put the path here
/obj/effect/mapping_helpers/airlock_note_placer/LateInitialize()
var/turf/turf = get_turf(src)
if(note_path && !istype(note_path, /obj/item/paper)) //don't put non-paper in the paper slot thank you
log_mapping("[src] at [x],[y] had an improper note_path path, could not place paper note.")
qdel(src)
return
if(locate(/obj/machinery/door/airlock) in turf)
var/obj/machinery/door/airlock/found_airlock = locate(/obj/machinery/door/airlock) in turf
if(note_path)
found_airlock.note = note_path
found_airlock.update_appearance()
qdel(src)
return
if(note_info)
var/obj/item/paper/paper = new /obj/item/paper(src)
if(note_name)
paper.name = note_name
paper.info = "[note_info]"
found_airlock.note = paper
paper.forceMove(found_airlock)
found_airlock.update_appearance()
qdel(src)
return
log_mapping("[src] at [x],[y] had no note_path or note_info, cannot place paper note.")
qdel(src)
return
log_mapping("[src] at [x],[y] could not find an airlock on current turf, cannot place paper note.")
qdel(src)
/**
* ## trapdoor placer!
*
* This places an unlinked trapdoor in the tile its on (so someone with a remote needs to link it up first)
* Admins may spawn this in the round for additional trapdoors if they so desire
* if YOU want to learn more about trapdoors, read about the component at trapdoor.dm
* note: this is not a turf subtype because the trapdoor needs the type of the turf to turn back into
*/
/obj/effect/mapping_helpers/trapdoor_placer
name = "trapdoor placer"
late = TRUE
icon_state = "trapdoor"
/obj/effect/mapping_helpers/trapdoor_placer/LateInitialize()
var/turf/component_target = get_turf(src)
component_target.AddComponent(/datum/component/trapdoor, starts_open = FALSE)
qdel(src)
/obj/effect/mapping_helpers/ztrait_injector
name = "ztrait injector"
icon_state = "ztrait"
late = TRUE
/// List of traits to add to this Z-level.
var/list/traits_to_add = list()
/obj/effect/mapping_helpers/ztrait_injector/LateInitialize()
var/datum/space_level/level = SSmapping.z_list[z]
if(!level || !length(traits_to_add))
return
level.traits |= traits_to_add
SSweather.update_z_level(level) //in case of someone adding a weather for the level, we want SSweather to update for that
/obj/effect/mapping_helpers/circuit_spawner
name = "circuit spawner"
icon_state = "circuit"
/// The shell for the circuit.
var/atom/movable/circuit_shell
/// Capacity of the shell.
var/shell_capacity = SHELL_CAPACITY_VERY_LARGE
/// The url for the json. Example: "https://pastebin.com/raw/eH7VnP9d"
var/json_url
/obj/effect/mapping_helpers/circuit_spawner/Initialize(mapload)
. = ..()
INVOKE_ASYNC(src, .proc/spawn_circuit)
/obj/effect/mapping_helpers/circuit_spawner/proc/spawn_circuit()
var/list/errors = list()
var/obj/item/integrated_circuit/loaded/new_circuit = new(loc)
var/json_data = load_data()
new_circuit.load_circuit_data(json_data, errors)
if(!circuit_shell)
return
circuit_shell = new(loc)
var/datum/component/shell/shell_component = circuit_shell.GetComponent(/datum/component/shell)
if(shell_component)
shell_component.shell_flags |= SHELL_FLAG_CIRCUIT_UNMODIFIABLE|SHELL_FLAG_CIRCUIT_UNREMOVABLE
shell_component.attach_circuit(new_circuit)
else
shell_component = circuit_shell.AddComponent(/datum/component/shell, \
capacity = shell_capacity, \
shell_flags = SHELL_FLAG_CIRCUIT_UNMODIFIABLE|SHELL_FLAG_CIRCUIT_UNREMOVABLE, \
starting_circuit = new_circuit, \
)
/obj/effect/mapping_helpers/circuit_spawner/proc/load_data()
var/static/json_cache = list()
var/static/query_in_progress = FALSE //We're using a single tmp file so keep it linear.
if(query_in_progress)
UNTIL(!query_in_progress)
if(json_cache[json_url])
return json_cache[json_url]
log_asset("Circuit Spawner fetching json from: [json_url]")
var/datum/http_request/request = new()
request.prepare(RUSTG_HTTP_METHOD_GET, json_url, "")
query_in_progress = TRUE
request.begin_async()
UNTIL(request.is_complete())
var/datum/http_response/response = request.into_response()
if(response.errored || response.status_code != 200)
query_in_progress = FALSE
CRASH("Failed to fetch mapped custom json from url [json_url], code: [response.status_code], error: [response.error]")
var/json_data = response["body"]
json_cache[json_url] = json_data
query_in_progress = FALSE
return json_data