Merge pull request #12036 from kevinz000/electrochromatic_windows

Electrochromatic (dim-on-demand) windows
This commit is contained in:
Lin
2020-05-02 19:13:29 +00:00
committed by GitHub
9 changed files with 245 additions and 13 deletions

View File

@@ -42,6 +42,13 @@ SUBSYSTEM_DEF(mapping)
var/stat_map_name = "Loading..."
/// Lookup list for random generated IDs.
var/list/random_generated_ids_by_original = list()
/// next id for separating obfuscated ids.
var/obfuscation_next_id = 1
/// "secret" key
var/obfuscation_secret
//dlete dis once #39770 is resolved
/datum/controller/subsystem/mapping/proc/HACK_LoadMapConfig()
if(!config)
@@ -52,6 +59,10 @@ SUBSYSTEM_DEF(mapping)
#endif
stat_map_name = config.map_name
/datum/controller/subsystem/mapping/PreInit()
if(!obfuscation_secret)
obfuscation_secret = md5(GUID()) //HAH! Guess this!
/datum/controller/subsystem/mapping/Initialize(timeofday)
HACK_LoadMapConfig()
if(initialized)
@@ -568,3 +579,15 @@ GLOBAL_LIST_EMPTY(the_station_areas)
LM.load()
if(GLOB.stationroom_landmarks.len)
seedStation() //I'm sure we can trust everyone not to insert a 1x1 rooms which loads a landmark which loads a landmark which loads a la...
/**
* Generates an obfuscated but constant id for an original id for cases where you don't want players codediving for an id.
* WARNING: MAKE SURE PLAYERS ARE NOT ABLE TO ACCESS THIS. To save performance, it's just secret + an incrementing number. Very guessable if you know what the secret is.
*/
/datum/controller/subsystem/mapping/proc/get_obfuscated_id(original, id_type = "GENERAL")
if(!original)
return //no.
var/key = "[original]%[id_type]"
if(random_generated_ids_by_original[key])
return random_generated_ids_by_original[key]
. = random_generated_ids_by_original[key] = "[obfuscation_secret]%[obfuscation_next_id++]"

View File

@@ -260,6 +260,15 @@
subcategory = CAT_TOOL
category = CAT_MISC
/datum/crafting_recipe/electrochromatic_kit
name = "Electrochromatic Kit"
result = /obj/item/electronics/electrochromatic_kit
reqs = list(/obj/item/stack/sheet/metal = 1,
/obj/item/stack/cable_coil = 1)
time = 5
subcategory = CAT_TOOL
category = CAT_MISC
////////////
//Vehicles//
////////////

View File

@@ -16,6 +16,9 @@
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
/obj/machinery/button/Initialize(mapload, ndir = 0, built = 0)
if(istext(id) && mapload)
if(copytext(id, 1, 2) == "!")
id = SSmapping.get_obfuscated_id(id)
. = ..()
if(built)
setDir(ndir)
@@ -260,6 +263,11 @@
req_access = list()
id = 1
/obj/machinery/button/electrochromatic
name = "window dim control"
desc = "Controls linked electrochromatic windows"
device_type = /obj/item/assembly/control/electrochromatic
/obj/item/wallframe/button
name = "button frame"
desc = "Used for building buttons."

View File

@@ -726,13 +726,12 @@
to_chat(usr, "<span class='warning'>A color that dark on an object like this? Surely not...</span>")
return FALSE
target.add_atom_colour(paint_color, WASHABLE_COLOUR_PRIORITY)
if(istype(target, /obj/structure/window))
if(color_hex2num(paint_color) < 255)
target.set_opacity(255)
else
target.set_opacity(initial(target.opacity))
var/obj/structure/window/W = target
W.spraycan_paint(paint_color)
else
target.add_atom_colour(paint_color, WASHABLE_COLOUR_PRIORITY)
. = use_charges(user, 2)
var/fraction = min(1, . / reagents.maximum_volume)

View File

@@ -0,0 +1,14 @@
/obj/item/electronics/electrochromatic_kit
name = "electrochromatic kit"
desc = "A kit for upgrading a window into an electrochromatic one."
/// Electrochromatic ID
var/id
/obj/item/electronics/electrochromatic_kit/attack_self(mob/user)
. = ..()
if(.)
return
var/new_id = input(user, "Set this kit's electrochromatic ID", "Set ID", id) as text|null
if(isnull(new_id))
return
id = new_id

View File

@@ -1,3 +1,18 @@
#define NOT_ELECTROCHROMATIC 0
#define ELECTROCHROMATIC_OFF 1
#define ELECTROCHROMATIC_DIMMED 2
GLOBAL_LIST_EMPTY(electrochromatic_window_lookup)
/proc/do_electrochromatic_toggle(new_status, id)
var/list/windows = GLOB.electrochromatic_window_lookup["[id]"]
if(!windows)
return
var/obj/structure/window/W //define outside for performance because obviously this matters.
for(var/i in windows)
W = i
new_status? W.electrochromatic_dim() : W.electrochromatic_off()
/obj/structure/window
name = "window"
desc = "A window."
@@ -28,8 +43,15 @@
rad_insulation = RAD_VERY_LIGHT_INSULATION
rad_flags = RAD_PROTECT_CONTENTS
/// Electrochromatic status
var/electrochromatic_status = NOT_ELECTROCHROMATIC
/// Electrochromatic ID. Set the first character to ! to replace with a SSmapping generated pseudorandom obfuscated ID for mapping purposes.
var/electrochromatic_id
/obj/structure/window/examine(mob/user)
. = ..()
if(electrochromatic_status != NOT_ELECTROCHROMATIC)
. += "<span class='notice'>The window has electrochromatic circuitry on it.</span>"
if(reinf)
if(anchored && state == WINDOW_SCREWED_TO_FRAME)
. += "<span class='notice'>The window is <b>screwed</b> to the frame.</span>"
@@ -52,6 +74,10 @@
if(reinf && anchored)
state = WINDOW_SCREWED_TO_FRAME
if(mapload && electrochromatic_id)
if(copytext(electrochromatic_id, 1, 2) == "!")
electrochromatic_id = SSmapping.get_obfuscated_id(electrochromatic_id)
ini_dir = dir
air_update_turf(1)
@@ -62,6 +88,12 @@
real_explosion_block = explosion_block
explosion_block = EXPLOSION_BLOCK_PROC
if(electrochromatic_status != NOT_ELECTROCHROMATIC)
var/old = electrochromatic_status
make_electrochromatic()
if(old == ELECTROCHROMATIC_DIMMED)
electrochromatic_dim()
/obj/structure/window/ComponentInitialize()
. = ..()
AddComponent(/datum/component/simple_rotation,ROTATION_ALTCLICK | ROTATION_CLOCKWISE | ROTATION_COUNTERCLOCKWISE | ROTATION_VERBS ,null,CALLBACK(src, .proc/can_be_rotated),CALLBACK(src,.proc/after_rotation))
@@ -177,6 +209,24 @@
to_chat(user, "<span class='warning'>[src] is already in good condition!</span>")
return
if(istype(I, /obj/item/electronics/electrochromatic_kit) && user.a_intent == INTENT_HELP)
var/obj/item/electronics/electrochromatic_kit/K = I
if(electrochromatic_status != NOT_ELECTROCHROMATIC)
to_chat(user, "<span class='warning'>[src] is already electrochromatic!</span>")
return
if(anchored)
to_chat(user, "<span class='warning'>[src] must not be attached to the floor!</span>")
return
if(!K.id)
to_chat(user, "<span class='warning'>[K] has no ID set!</span>")
return
if(!user.temporarilyRemoveItemFromInventory(K))
to_chat(user, "<span class='warning'>[K] is stuck to your hand!</span>")
return
user.visible_message("<span class='notice'>[user] upgrades [src] with [I].</span>", "<span class='notice'>You upgrade [src] with [I].</span>")
make_electrochromatic(K.id)
qdel(K)
if(!(flags_1&NODECONSTRUCT_1))
if(istype(I, /obj/item/screwdriver))
I.play_tool_sound(src, 75)
@@ -224,6 +274,91 @@
air_update_turf(TRUE)
update_nearby_icons()
/obj/structure/window/proc/spraycan_paint(paint_color)
if(color_hex2num(paint_color) < 255)
set_opacity(255)
else
set_opacity(initial(opacity))
add_atom_colour(paint_color, WASHABLE_COLOUR_PRIORITY)
/obj/structure/window/proc/electrochromatic_dim()
if(electrochromatic_status == ELECTROCHROMATIC_DIMMED)
return
electrochromatic_status = ELECTROCHROMATIC_DIMMED
animate(src, color = "#222222", time = 2)
set_opacity(TRUE)
/obj/structure/window/proc/electrochromatic_off()
if(electrochromatic_status == ELECTROCHROMATIC_OFF)
return
electrochromatic_status = ELECTROCHROMATIC_OFF
var/current = color
update_atom_colour()
var/newcolor = color
color = current
animate(src, color = newcolor, time = 2)
/obj/structure/window/proc/remove_electrochromatic()
electrochromatic_off()
electrochromatic_status = NOT_ELECTROCHROMATIC
if(!electrochromatic_id)
return
var/list/L = GLOB.electrochromatic_window_lookup["[electrochromatic_id]"]
if(L)
L -= src
electrochromatic_id = null
/obj/structure/window/vv_edit_var(var_name, var_value)
var/check_status
if(var_name == NAMEOF(src, electrochromatic_id))
if(electrochromatic_id && GLOB.electrochromatic_window_lookup["[electrochromatic_id]"])
GLOB.electrochromatic_window_lookup[electrochromatic_id] -= src
if(var_name == NAMEOF(src, electrochromatic_status))
check_status = TRUE
. = ..() //do this first incase it runtimes.
if(var_name == NAMEOF(src, electrochromatic_id))
if((electrochromatic_status != NOT_ELECTROCHROMATIC) && electrochromatic_id)
LAZYINITLIST(GLOB.electrochromatic_window_lookup[electrochromatic_id])
GLOB.electrochromatic_window_lookup[electrochromatic_id] += src
if(check_status)
if(electrochromatic_status == NOT_ELECTROCHROMATIC)
remove_electrochromatic()
return
else if(electrochromatic_status == ELECTROCHROMATIC_OFF)
if(!electrochromatic_id)
return
else
make_electrochromatic()
electrochromatic_off()
return
else if(electrochromatic_status == ELECTROCHROMATIC_DIMMED)
if(!electrochromatic_id)
return
else
make_electrochromatic()
electrochromatic_dim()
return
else
remove_electrochromatic()
/obj/structure/window/proc/make_electrochromatic(new_id = electrochromatic_id)
remove_electrochromatic()
if(!new_id)
CRASH("Attempted to make electrochromatic with null ID.")
electrochromatic_id = new_id
electrochromatic_status = ELECTROCHROMATIC_OFF
LAZYINITLIST(GLOB.electrochromatic_window_lookup["[electrochromatic_id]"])
GLOB.electrochromatic_window_lookup[electrochromatic_id] |= src
/obj/structure/window/update_atom_colour()
if((electrochromatic_status != ELECTROCHROMATIC_OFF) && (electrochromatic_status != ELECTROCHROMATIC_DIMMED))
return FALSE
. = ..()
if(color && (color_hex2num(color) < 255))
set_opacity(255)
else
set_opacity(FALSE)
/obj/structure/window/proc/check_state(checked_state)
if(state == checked_state)
return TRUE
@@ -263,7 +398,6 @@
if(BURN)
playsound(src, 'sound/items/Welder.ogg', 100, 1)
/obj/structure/window/deconstruct(disassembled = TRUE)
if(QDELETED(src))
return
@@ -272,6 +406,9 @@
if(!(flags_1 & NODECONSTRUCT_1))
for(var/obj/item/shard/debris in spawnDebris(drop_location()))
transfer_fingerprints_to(debris) // transfer fingerprints to shards only
if(electrochromatic_status != NOT_ELECTROCHROMATIC) //eh fine keep your kit.
new /obj/item/electronics/electrochromatic_kit(drop_location())
// Intentionally not setting the ID so you can't decon one to know all of the IDs.
qdel(src)
update_nearby_icons()
@@ -315,9 +452,9 @@
density = FALSE
air_update_turf(1)
update_nearby_icons()
remove_electrochromatic()
return ..()
/obj/structure/window/Move()
var/turf/T = loc
. = ..()
@@ -731,7 +868,6 @@
set_opacity(TRUE)
queue_smooth(src)
/obj/structure/window/paperframe/attackby(obj/item/W, mob/user)
if(W.get_temperature())
fire_act(W.get_temperature())
@@ -749,3 +885,7 @@
return
..()
update_icon()
#undef NOT_ELECTROCHROMATIC
#undef ELECTROCHROMATIC_OFF
#undef ELECTROCHROMATIC_DIMMED

View File

@@ -3,14 +3,35 @@
desc = "A small electronic device able to control a blast door remotely."
icon_state = "control"
attachable = TRUE
var/id = null
var/can_change_id = 0
/// Our ID. Make the first character ! if you want to obfuscate it as a mapper via randomization.
var/id
/// Can the ID be changed if used in hand?
var/can_change_id = FALSE
/// Show ID?
var/show_id = TRUE
var/cooldown = FALSE //Door cooldowns
/obj/item/assembly/control/Initialize(mapload)
if(mapload && id)
if(copytext(id, 1, 2) == "!")
id = SSmapping.get_obfuscated_id(id)
return ..()
/obj/item/assembly/control/examine(mob/user)
. = ..()
if(id)
if(id && show_id)
. += "<span class='notice'>Its channel ID is '[id]'.</span>"
if(can_change_id)
. += "<span class='notice'>Use in hand to change ID.</span>"
/obj/item/assembly/control/attack_self(mob/living/user)
. = ..()
if(!can_change_id)
return
var/new_id
new_id = input(user, "Set ID", "Set ID", show_id? id : null) as text|null
if(!isnull(new_id)) //0/"" is considered !, so check null instead of just !.
id = new_id
/obj/item/assembly/control/activate()
cooldown = TRUE
@@ -22,7 +43,6 @@
INVOKE_ASYNC(M, openclose ? /obj/machinery/door/poddoor.proc/open : /obj/machinery/door/poddoor.proc/close)
addtimer(VARSET_CALLBACK(src, cooldown, FALSE), 10)
/obj/item/assembly/control/airlock
name = "airlock controller"
desc = "A small electronic device able to control an airlock remotely."
@@ -123,7 +143,6 @@
addtimer(VARSET_CALLBACK(src, cooldown, FALSE), 50)
/obj/item/assembly/control/crematorium
name = "crematorium controller"
desc = "An evil-looking remote controller for a crematorium."
@@ -135,3 +154,14 @@
C.cremate(usr)
addtimer(VARSET_CALLBACK(src, cooldown, FALSE), 50)
/obj/item/assembly/control/electrochromatic
name = "electrochromatic window controller"
desc = "Toggles linked electrochromatic windows."
can_change_id = TRUE
/// Stores our status to prevent windows from desyncing.
var/on = FALSE
/obj/item/assembly/control/electrochromatic/activate()
on = !on
do_electrochromatic_toggle(on, id)

View File

@@ -74,3 +74,11 @@
materials = list(/datum/material/glass = 20)
build_path = /obj/item/stock_parts/cell/emergency_light
category = list("initial", "Electronics")
/datum/design/electrochromatic_control
name = "Electrochromatic Control Circuit"
id = "electrochromatic_control_circuit"
build_type = AUTOLATHE
materials = list(/datum/material/iron = 100, /datum/material/glass = 100)
build_path = /obj/item/assembly/control/electrochromatic
category = list("initial", "Electronics")