diff --git a/aurorastation.dme b/aurorastation.dme
index a8f148a0ceb..36a4ac3d44a 100644
--- a/aurorastation.dme
+++ b/aurorastation.dme
@@ -1496,6 +1496,7 @@
#include "code\game\objects\structures\watercloset.dm"
#include "code\game\objects\structures\weapon_rack.dm"
#include "code\game\objects\structures\weapons_rack.dm"
+#include "code\game\objects\structures\whiteboard.dm"
#include "code\game\objects\structures\windoor_assembly.dm"
#include "code\game\objects\structures\window.dm"
#include "code\game\objects\structures\barricades\_barricade.dm"
diff --git a/code/__DEFINES/sound.dm b/code/__DEFINES/sound.dm
index 33692f821ef..07eaff88630 100644
--- a/code/__DEFINES/sound.dm
+++ b/code/__DEFINES/sound.dm
@@ -183,3 +183,4 @@
#define SFX_TRAY_HIT "tray_hit"
#define SFX_WIELD "wield"
#define SFX_PLASTIC_DRY_FIRE "plastic_dry_fire"
+#define SFX_WHITEBOARD_SCRIBBLE "whiteboard_scribble"
diff --git a/code/game/objects/structures/barsign.dm b/code/game/objects/structures/barsign.dm
index de0f8a0c465..06cb54b0e3e 100644
--- a/code/game/objects/structures/barsign.dm
+++ b/code/game/objects/structures/barsign.dm
@@ -1,3 +1,8 @@
+/// Lists of data passed over to tgui, obtained from numerous singletons. List contains lists of: "display_name", "icon", "icon_name", "singleton_path"
+GLOBAL_LIST_EMPTY(barsign_overlay_cache)
+GLOBAL_LIST_EMPTY(kitchensign_overlay_cache)
+GLOBAL_LIST_EMPTY(marketsign_overlay_cache)
+
/obj/structure/sign/double/barsign
icon = 'icons/obj/barsigns.dmi'
icon_state = "off"
@@ -9,21 +14,86 @@
var/currently_on = FALSE
var/on_icon_state
var/off_icon_state = "off"
+ /// Local reference of the global list associated with this object's singletons.
+ var/list/target_cache = list()
+
+/obj/structure/sign/double/barsign/mechanics_hints(mob/user, distance, is_adjacent)
+ . += ..()
+ . += "You can Alt Click to toggle power of \the [src]."
+
+/obj/structure/sign/double/barsign/Initialize()
+ . = ..()
+ set_overlay_cache()
+
+/obj/structure/sign/double/barsign/proc/get_target_cache()
+ return GLOB.barsign_overlay_cache
+
+/obj/structure/sign/double/barsign/proc/set_overlay_cache()
+ target_cache = get_target_cache()
+
+ if(!length(target_cache))
+ var/list/singleton_instances = GET_SINGLETON_SUBTYPE_MAP(choice_types)
+ for(var/i in singleton_instances)
+ var/singleton/sign/double/bar/S = GET_SINGLETON(i)
+ var/overlay_image = image(icon = icon, icon_state = S.icon_state)
+
+ target_cache.Add(list(list(
+ "display_name" = S.name,
+ "icon" = icon2base64(getFlatIcon(overlay_image, no_anim = TRUE)), // expensive but we only do it once
+ "icon_name" = S.icon_state,
+ "singleton_path" = "[S.type]"
+ )))
/obj/structure/sign/double/barsign/attackby(obj/item/attacking_item, mob/user)
if(cult)
return ..()
var/obj/item/card/id/card = attacking_item.GetID()
if(istype(card))
- if(check_access(card))
- set_sign()
- to_chat(user, SPAN_NOTICE("You change the sign."))
- else
+ if(!check_access(card))
to_chat(user, SPAN_WARNING("Access denied."))
- return
+ return
+ ui_interact(user)
return ..()
+/obj/structure/sign/double/barsign/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(!ui)
+ ui = new(user, src, "OverlayChoice", capitalize_first_letters(name))
+ ui.open()
+
+/obj/structure/sign/double/barsign/ui_static_data(mob/user)
+ var/list/data = list()
+ data["contents"] = target_cache
+ return data
+
+/obj/structure/sign/double/barsign/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
+ . = ..()
+ if(.)
+ return
+
+ var/mob/user = ui.user
+ add_fingerprint(user)
+ switch(action)
+ if("select_overlay")
+ var/choice = params["singleton_path"]
+ INVOKE_ASYNC(src, PROC_REF(set_sign), choice)
+
+ SStgui.close_uis(src)
+
+ . = TRUE
+
+/obj/structure/sign/double/barsign/proc/set_sign(choice)
+ var/singleton/sign/double/chosen_singleton = text2path(choice)
+
+ name = chosen_singleton.name
+ desc = chosen_singleton.desc
+ desc_extended = chosen_singleton.desc_extended
+ icon_state = chosen_singleton.icon_state
+ currently_on = TRUE
+ on_icon_state = icon_state
+ update_icon()
+
/obj/structure/sign/double/barsign/AltClick(mob/user) // Alt-click a sign with an empty hand to power or depower it, if it has the associated "[name]-off" state in the .dmi file.
if(!on_icon_state)
to_chat(user, SPAN_WARNING("The sign is already off!"))
@@ -35,30 +105,7 @@
icon_state = off_icon_state
currently_on = FALSE
-/obj/structure/sign/double/barsign/proc/get_sign_choices()
- var/list/sign_choices = GET_SINGLETON_SUBTYPE_MAP(choice_types)
- return sign_choices
-
-/obj/structure/sign/double/barsign/proc/set_sign()
- var/list/sign_choices = get_sign_choices()
-
- var/list/sign_index = list()
- for(var/sign in sign_choices)
- var/singleton/sign/double/B = GET_SINGLETON(sign)
- sign_index["[B.name]"] = B
-
- var/sign_choice = tgui_input_list(usr, "What should the sign be changed to?", "Bar Sign", sign_index)
- if(!sign_choice)
- return
- var/singleton/sign/double/signselect = sign_index[sign_choice]
-
- name = signselect.name
- desc = signselect.desc
- desc_extended = signselect.desc_extended
- icon_state = signselect.icon_state
- currently_on = TRUE
- on_icon_state = icon_state
- update_icon()
+// ---- Kitchen sign
/obj/structure/sign/double/barsign/kitchensign
icon = 'icons/obj/kitchensigns.dmi'
@@ -66,9 +113,14 @@
req_access = list(ACCESS_GALLEY)
choice_types = /singleton/sign/double/kitchen
+/obj/structure/sign/double/barsign/kitchensign/get_target_cache()
+ return GLOB.kitchensign_overlay_cache
+
/obj/structure/sign/double/barsign/kitchensign/mirrored // Visible from the other end of the sign.
pixel_x = -32
+// ---- Market sign
+
/obj/structure/sign/double/barsign/marketsign
icon = 'icons/obj/marketsigns.dmi'
icon_state = "off"
@@ -76,9 +128,8 @@
req_one_access = list(ACCESS_CARGO, ACCESS_JANITOR, ACCESS_ROBOTICS, ACCESS_MINING, ACCESS_PARAMEDIC, ACCESS_HYDROPONICS, ACCESS_GALLEY, ACCESS_LIBRARY)
choice_types = /singleton/sign/double/market
-/obj/structure/sign/double/barsign/marketsign/set_sign()
- . = ..()
- off_icon_state = "[icon_state]-off"
+/obj/structure/sign/double/barsign/marketsign/get_target_cache()
+ return GLOB.marketsign_overlay_cache
/obj/structure/sign/double/barsign/marketsign/mirrored // Visible from the other end of the sign.
pixel_x = -32
diff --git a/code/game/objects/structures/whiteboard.dm b/code/game/objects/structures/whiteboard.dm
new file mode 100644
index 00000000000..ec92486fa7a
--- /dev/null
+++ b/code/game/objects/structures/whiteboard.dm
@@ -0,0 +1,293 @@
+/// List of data passed over to tgui, obtained from whiteboard singletons. List contains lists of: "display_name", "icon", "icon_name", "singleton_path"
+GLOBAL_LIST_EMPTY(whiteboard_overlay_cache)
+
+// ---- large whiteboard, 64x32
+/obj/structure/whiteboard
+ name = "whiteboard"
+ desc = "A whiteboard in classic design. Often associated with its sibling glassboard, perfect material to draw incomprehensible equations."
+ icon = 'icons/obj/whiteboard.dmi'
+ icon_state = "whiteboard"
+ layer = OBJ_LAYER
+ /// Singleton path to whiteboard overlays.
+ var/overlay_choices_singleton = /singleton/whiteboard
+ /// Written things on the whiteboard.
+ var/written_contents
+ /// Is someone currently drawing things on the whiteboard?
+ var/busy = FALSE
+ /// Used to prevent pixel-shift mechanic spam.
+ var/currently_pixel_shifting = FALSE
+ /// For mapping purposes. Define this as one of the overlay icon_state's name (e.g. overlay_1).
+ var/preset_overlay
+
+/obj/structure/whiteboard/mechanics_hints(mob/user, distance, is_adjacent)
+ . += ..()
+ . += "You can write or edit things on [src] with a pen."
+ . += "You can ALT Click to pixel-shift [src] to the wall. Only works for north direction when wheel brakes are locked!"
+ . += "You can engage/release wheel brakes with the help of a wrench."
+
+/obj/structure/whiteboard/examine(mob/user, distance, is_adjacent, infix, suffix, show_extended)
+ . = ..()
+ if(written_contents)
+ to_chat(user, EXAMINE_BLOCK("It reads: \"[written_contents]\"."))
+
+/obj/structure/whiteboard/Initialize()
+ . = ..()
+ if(!length(GLOB.whiteboard_overlay_cache))
+ var/list/singleton_instances = GET_SINGLETON_SUBTYPE_MAP(overlay_choices_singleton)
+ for(var/i in singleton_instances)
+ var/singleton/whiteboard/S = GET_SINGLETON(i)
+ var/overlay_image = image(icon = icon, icon_state = S.icon_state)
+
+ GLOB.whiteboard_overlay_cache.Add(list(list(
+ "display_name" = S.name,
+ "icon" = icon2base64(getFlatIcon(overlay_image)), // expensive but we only do it once
+ "icon_name" = S.icon_state,
+ "singleton_path" = "[S.type]"
+ )))
+
+ if(preset_overlay)
+ AddOverlays(preset_overlay)
+
+/obj/structure/whiteboard/Move()
+ . = ..()
+ if(has_gravity())
+ playsound(src, 'sound/effects/roll.ogg', 50, 1)
+
+/obj/structure/whiteboard/AltClick(mob/user)
+ if(!anchored)
+ to_chat(user, SPAN_WARNING("You need the wheels locked first in order to secure [src] to a wall!"))
+ return
+
+ if(currently_pixel_shifting)
+ return
+
+ currently_pixel_shifting = TRUE
+ if(!do_after(user, 0.5 SECOND))
+ currently_pixel_shifting = FALSE
+ return
+ currently_pixel_shifting = FALSE
+ animate(src, pixel_y = pixel_y == 0 ? 12 : 0, time = 0.2 SECOND)
+ balloon_alert(user, "shifted")
+
+/obj/structure/whiteboard/attackby(obj/item/attacking_item, mob/user)
+ if(busy)
+ to_chat(user, SPAN_WARNING("Someone is already drawing things on this board!"))
+ return
+
+ var/obj/item/pen/P = attacking_item
+ if(istype(P))
+ to_chat(user, SPAN_NOTICE("You start contemplating what to draw."))
+ handle_drawing(user)
+
+ else if(attacking_item.tool_behaviour == TOOL_WRENCH)
+ animate(src, pixel_y = 0, time = 0.2 SECOND) // if we were pixel-shifted, return to our original state
+ anchored = !anchored
+ attacking_item.play_tool_sound(get_turf(src), 75)
+ balloon_alert(user, "[anchored ? "secure" : "unsecure"]")
+ user.visible_message("[user] [anchored ? "locks" : "unlocks"] [src]'s wheels.", \
+ "You [anchored ? "locked" : "unlocked"] [src]'s wheels.", \
+ "You hear a click.")
+
+ else
+ to_chat(user, SPAN_WARNING("This is the wrong tool to manifest your inland empire, maybe a pen would be more fitting?"))
+
+/obj/structure/whiteboard/proc/handle_drawing(mob/user)
+ busy = TRUE
+ // Text input
+ var/new_written_contents = tgui_input_text(user, "Write your text here", "Whiteboard Contents", default = written_contents, multiline = TRUE)
+ if(new_written_contents == written_contents) // if untouched, cancel it
+ to_chat(user, SPAN_WARNING("You withdraw your pen in thought, [src] remains untouched."))
+ busy = FALSE
+ return
+
+ if(!new_written_contents) //if empty, erase the board
+ to_chat(user, SPAN_NOTICE("You erase the contents on [src]."))
+ ClearOverlays()
+ desc = initial(desc)
+ written_contents = null
+ busy = FALSE
+ return
+
+ written_contents = new_written_contents
+ ui_interact(user)
+
+/obj/structure/whiteboard/proc/finalize_drawing(mob/user, choice)
+ playsound(get_turf(src), SFX_WHITEBOARD_SCRIBBLE, 60, FALSE)
+ if(do_after(user, 2 SECONDS))
+ update_icon(choice)
+ else
+ ClearOverlays()
+ written_contents = null
+
+/obj/structure/whiteboard/update_icon(choice)
+ ClearOverlays()
+ AddOverlays(choice)
+
+// ---- UI code
+
+/obj/structure/whiteboard/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(!ui)
+ ui = new(user, src, "OverlayChoice", capitalize_first_letters(name))
+ ui.open()
+
+/obj/structure/whiteboard/ui_static_data(mob/user)
+ var/list/data = list()
+ data["contents"] = GLOB.whiteboard_overlay_cache
+ return data
+
+/obj/structure/whiteboard/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
+ . = ..()
+ if(.)
+ return
+
+ var/mob/user = ui.user
+ add_fingerprint(user)
+ switch(action)
+ if("select_overlay")
+ var/choice = params["choice"]
+ INVOKE_ASYNC(src, PROC_REF(finalize_drawing), user, choice)
+ busy = FALSE
+
+ SStgui.close_uis(src)
+
+ . = TRUE
+
+/obj/structure/whiteboard/ui_close(mob/user, datum/tgui/ui)
+ . = ..()
+
+ if(busy) // if the ui was closed while we were still busy, it means no overlay were chosen
+ busy = FALSE
+ written_contents = null
+ ClearOverlays()
+ to_chat(user, SPAN_WARNING("You withdraw your pen in thought, [src] remains untouched."))
+
+// ---- Portable whiteboard, 32x32
+/obj/item/portable_whiteboard
+ name = "portable whiteboard"
+ desc = "A compact whiteboard folded into a portable frame, ready to be deployed on any unexpected seminar!"
+ icon = 'icons/obj/whiteboard_portable.dmi'
+ icon_state = "whiteboard_case"
+ item_state = "whiteboard_case"
+ contained_sprite = TRUE
+ force = 18
+ throw_speed = 1
+ throw_range = 4
+ w_class = WEIGHT_CLASS_BULKY
+ attack_verb = list("attacked", "bashed", "battered", "bludgeoned", "whacked")
+ drop_sound = 'sound/items/drop/toolbox.ogg'
+ pickup_sound = 'sound/items/pickup/toolbox.ogg'
+ /// Used to keep track of folding process to prevent spams.
+ var/currently_unfolding = FALSE
+
+/obj/item/portable_whiteboard/mechanics_hints(mob/user, distance, is_adjacent)
+ . += ..()
+ . += "You can ALT Click to deploy [src]. It must be on the floor first!"
+
+/obj/item/portable_whiteboard/AltClick(mob/user)
+ if(loc == user)
+ to_chat(user, SPAN_WARNING("[src] needs to be standing on the floor in order to be unfolded!"))
+ return
+
+ if(currently_unfolding)
+ return
+
+ currently_unfolding = TRUE
+ if(!do_after(user, 3 SECONDS))
+ currently_unfolding = FALSE
+ return
+
+ new /obj/structure/whiteboard/portable(get_turf(src))
+ playsound(get_turf(src), 'sound/items/storage/briefcase.ogg', 50)
+ qdel(src)
+
+/obj/structure/whiteboard/portable
+ name = "portable whiteboard"
+ desc = "A compact whiteboard folded into a portable frame, ready to be deployed on any unexpected seminar!"
+ icon = 'icons/obj/whiteboard_portable.dmi'
+ anchored = FALSE
+ /// Used to keep track of folding process to prevent spams.
+ var/currently_folding = FALSE
+
+/obj/structure/whiteboard/portable/AltClick(mob/user)
+ if(currently_folding)
+ return
+
+ currently_folding = TRUE
+ if(!do_after(user, 3 SECONDS))
+ currently_folding = FALSE
+ return
+
+ new /obj/item/portable_whiteboard(get_turf(src))
+ playsound(get_turf(src), 'sound/items/storage/briefcase.ogg', 50)
+ qdel(src)
+
+/obj/structure/whiteboard/portable/update_icon(choice)
+ ClearOverlays()
+ var/image/overlay_image = image(icon = 'icons/obj/whiteboard.dmi', icon_state = choice)
+ overlay_image.transform *= 0.5
+ overlay_image.pixel_x = -16
+ overlay_image.pixel_y = 2
+ AddOverlays(overlay_image)
+
+// ---- Whiteboard overlay singletons
+
+/singleton/whiteboard
+ var/name = "placeholder"
+ var/icon_state = ""
+
+/singleton/whiteboard/bar_chart
+ name = "Bar chart"
+ icon_state = "overlay_1"
+
+/singleton/whiteboard/pie_chart
+ name = "Pie chart"
+ icon_state = "overlay_2"
+
+/singleton/whiteboard/spacetime_diagram
+ name = "Spacetime diagram"
+ icon_state = "overlay_3"
+
+/singleton/whiteboard/geometric_chart
+ name = "Geometric chart"
+ icon_state = "overlay_4"
+
+/singleton/whiteboard/scribbles
+ name = "Scribbles"
+ icon_state = "overlay_5"
+
+/singleton/whiteboard/gun_diagram
+ name = "Gun diagram"
+ icon_state = "overlay_6"
+
+/singleton/whiteboard/circle_chart
+ name = "Circle chart"
+ icon_state = "overlay_7"
+
+/singleton/whiteboard/display_chart
+ name = "Display chart"
+ icon_state = "overlay_8"
+
+/singleton/whiteboard/todays_menu
+ name = "Today's menu"
+ icon_state = "overlay_9"
+
+/singleton/whiteboard/calculations
+ name = "Calculations"
+ icon_state = "overlay_10"
+
+/singleton/whiteboard/erased_board
+ name = "Erased board"
+ icon_state = "overlay_11"
+
+/singleton/whiteboard/wavelenghth
+ name = "Wavelength"
+ icon_state = "overlay_12"
+
+/singleton/whiteboard/grafitti
+ name = "Grafitti"
+ icon_state = "overlay_13"
+
+/singleton/whiteboard/archeological
+ name = "Archeological"
+ icon_state = "overlay_14"
diff --git a/code/game/sound/sound_keys/sound_keys.dm b/code/game/sound/sound_keys/sound_keys.dm
index e5dc716c81d..a39cc5ba6c1 100644
--- a/code/game/sound/sound_keys/sound_keys.dm
+++ b/code/game/sound/sound_keys/sound_keys.dm
@@ -904,3 +904,11 @@
'sound/effects/creatures/robot_talk_1.ogg',
'sound/effects/creatures/robot_talk_2.ogg'
)
+
+/datum/sound_effect/whiteboard_scribble
+ key = SFX_WHITEBOARD_SCRIBBLE
+ file_paths = list(
+ 'sound/effects/whiteboard_scribble_1.ogg',
+ 'sound/effects/whiteboard_scribble_2.ogg',
+ 'sound/effects/whiteboard_scribble_3.ogg'
+ )
diff --git a/code/modules/cargo/items/recreation.dm b/code/modules/cargo/items/recreation.dm
index efb4f7703c2..e0a16ff59a1 100644
--- a/code/modules/cargo/items/recreation.dm
+++ b/code/modules/cargo/items/recreation.dm
@@ -382,3 +382,31 @@
container_type = "crate"
groupable = TRUE
spawn_amount = 1
+
+/singleton/cargo_item/whiteboard
+ category = "recreation"
+ name = "whiteboard"
+ supplier = "orion"
+ description = "A standard whiteboard."
+ price = 100
+ items = list(
+ /obj/structure/whiteboard
+ )
+ access = 0
+ container_type = "crate"
+ groupable = TRUE
+ spawn_amount = 1
+
+/singleton/cargo_item/whiteboard_portable
+ category = "recreation"
+ name = "portable whiteboard"
+ supplier = "orion"
+ description = "A portable whiteboard, smaller than the standard alternatives."
+ price = 75
+ items = list(
+ /obj/item/portable_whiteboard
+ )
+ access = 0
+ container_type = "crate"
+ groupable = TRUE
+ spawn_amount = 1
diff --git a/html/changelogs/kano-dot-whiteboards.yml b/html/changelogs/kano-dot-whiteboards.yml
new file mode 100644
index 00000000000..1873dbc6d7a
--- /dev/null
+++ b/html/changelogs/kano-dot-whiteboards.yml
@@ -0,0 +1,5 @@
+author: Kano
+delete-after: True
+changes:
+ - rscadd: "Added whiteboards, sprites by KingOfThePing."
+ - qol: "Gave barsigns and its subtypes a tgui menu."
diff --git a/icons/obj/whiteboard.dmi b/icons/obj/whiteboard.dmi
new file mode 100644
index 00000000000..b8dc84dc568
Binary files /dev/null and b/icons/obj/whiteboard.dmi differ
diff --git a/icons/obj/whiteboard_portable.dmi b/icons/obj/whiteboard_portable.dmi
new file mode 100644
index 00000000000..89de8607dff
Binary files /dev/null and b/icons/obj/whiteboard_portable.dmi differ
diff --git a/maps/sccv_horizon/sccv_horizon.dmm b/maps/sccv_horizon/sccv_horizon.dmm
index 0783d2fae05..68508aba07b 100644
--- a/maps/sccv_horizon/sccv_horizon.dmm
+++ b/maps/sccv_horizon/sccv_horizon.dmm
@@ -16742,10 +16742,19 @@
/obj/effect/floor_decal/spline/fancy/wood{
dir = 9
},
-/obj/item/book/manual/excavation,
-/obj/item/book/manual/anomaly_testing,
-/obj/item/book/manual/anomaly_spectroscopy,
/obj/structure/table/reinforced/glass,
+/obj/item/book/manual/excavation{
+ pixel_x = -6;
+ pixel_y = 9
+ },
+/obj/item/book/manual/anomaly_spectroscopy{
+ pixel_x = -6;
+ pixel_y = 6
+ },
+/obj/item/book/manual/anomaly_testing{
+ pixel_x = -6;
+ pixel_y = 3
+ },
/turf/simulated/floor/wood,
/area/horizon/rnd/xenoarch/presentation)
"ciH" = (
@@ -41752,6 +41761,11 @@
/obj/structure/lattice/catwalk/indoor,
/turf/simulated/floor/plating,
/area/horizon/engineering/reactor/indra/smes)
+"fzh" = (
+/obj/effect/floor_decal/corner_wide/yellow/diagonal,
+/obj/structure/whiteboard,
+/turf/simulated/floor/tiled/dark,
+/area/horizon/engineering/break_room)
"fzj" = (
/obj/effect/floor_decal/industrial/warning{
dir = 1
@@ -54439,13 +54453,23 @@
dir = 9
},
/obj/structure/table/steel,
-/obj/item/camera,
-/obj/item/camera,
-/obj/item/camera{
- pixel_y = 4
+/obj/item/portable_whiteboard{
+ pixel_x = 3;
+ pixel_y = 12
},
/obj/item/camera{
- pixel_y = 4
+ pixel_y = 4;
+ pixel_x = -5
+ },
+/obj/item/camera{
+ pixel_y = 4;
+ pixel_x = -5
+ },
+/obj/item/camera{
+ pixel_x = -5
+ },
+/obj/item/camera{
+ pixel_x = -5
},
/turf/simulated/floor/tiled/dark,
/area/horizon/storage/eva)
@@ -66254,13 +66278,13 @@
/turf/simulated/floor/tiled/dark,
/area/horizon/engineering/atmos/storage)
"iMJ" = (
-/obj/structure/railing/mapped,
/obj/machinery/firealarm/east,
/obj/machinery/camera/network/service{
c_tag = "Service - Deck 2 - Mess Hall 3";
dir = 8
},
/obj/random/pottedplant,
+/obj/structure/railing/mapped,
/turf/simulated/floor/lino,
/area/horizon/service/mess_hall)
"iMK" = (
@@ -71905,6 +71929,7 @@
/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{
dir = 5
},
+/obj/structure/whiteboard,
/turf/simulated/floor/wood,
/area/horizon/rnd/xenoarch/presentation)
"jAq" = (
@@ -80595,6 +80620,10 @@
pixel_y = 10;
pixel_x = -8
},
+/obj/item/portable_whiteboard{
+ pixel_x = 2;
+ pixel_y = 1
+ },
/turf/simulated/floor/wood,
/area/horizon/command/heads/rd)
"kFb" = (
@@ -103835,17 +103864,16 @@
/area/horizon/hallway/primary/deck_3/central)
"nLd" = (
/obj/structure/table/reinforced/steel,
-/obj/item/paper_bin{
- pixel_x = 6;
- pixel_y = 18
- },
/obj/item/binoculars/high_power{
- pixel_x = 7;
- pixel_y = 3
+ pixel_x = -5;
+ pixel_y = 11
+ },
+/obj/item/portable_whiteboard{
+ pixel_x = 4
},
/obj/item/flashlight/lamp{
- pixel_y = 1;
- pixel_x = -7
+ pixel_y = -4;
+ pixel_x = -8
},
/turf/simulated/floor/tiled/dark/full,
/area/horizon/shuttle/intrepid/flight_deck)
@@ -117077,6 +117105,9 @@
pixel_x = 9;
pixel_y = 3
},
+/obj/item/portable_whiteboard{
+ pixel_x = -4
+ },
/turf/simulated/floor/carpet,
/area/horizon/command/heads/chief)
"pyY" = (
@@ -128853,6 +128884,7 @@
/obj/item/material/stool/chair/folding/camping,
/obj/item/material/stool/chair/folding/camping,
/obj/item/material/stool/chair/folding/camping,
+/obj/item/wrench,
/turf/simulated/floor/wood,
/area/horizon/rnd/xenoarch/presentation)
"rer" = (
@@ -143886,6 +143918,12 @@
/obj/machinery/alarm/shuttle/north,
/turf/simulated/floor/plating,
/area/horizon/shuttle/intrepid/port_compartment)
+"taA" = (
+/obj/effect/floor_decal/corner/grey/diagonal,
+/obj/structure/whiteboard,
+/obj/effect/floor_decal/industrial/outline/yellow,
+/turf/simulated/floor/tiled/white,
+/area/horizon/service/kitchen)
"taC" = (
/obj/effect/floor_decal/corner/grey/diagonal,
/obj/effect/floor_decal/spline/plain{
@@ -152800,6 +152838,11 @@
},
/turf/simulated/floor/plating,
/area/horizon/maintenance/deck_1/hangar/starboard)
+"ukR" = (
+/obj/effect/floor_decal/corner/grey/diagonal,
+/obj/effect/floor_decal/industrial/outline/yellow,
+/turf/simulated/floor/tiled/white,
+/area/horizon/service/kitchen)
"ukS" = (
/obj/effect/floor_decal/industrial/warning{
dir = 6
@@ -160910,7 +160953,7 @@
pixel_x = 6
},
/obj/item/pen{
- pixel_x = 6;
+ pixel_x = 7;
pixel_y = -13
},
/obj/machinery/firealarm/north,
@@ -160928,6 +160971,10 @@
pixel_x = -6;
pixel_y = -5
},
+/obj/item/paper_bin{
+ pixel_x = 7;
+ pixel_y = -9
+ },
/turf/simulated/floor/tiled/dark/full,
/area/horizon/shuttle/intrepid/flight_deck)
"vpt" = (
@@ -282814,8 +282861,8 @@ pKh
idk
bof
pjB
+cKu
pWB
-hCm
lEF
eSV
eSV
@@ -283071,9 +283118,9 @@ meI
lVj
gVF
pjB
+pjB
uYQ
sCh
-sCh
eSV
eSV
eSV
@@ -283327,9 +283374,9 @@ jis
ixL
cfl
gtv
+taA
woK
-tGt
-hoE
+uYQ
sCh
eSV
eSV
@@ -283584,7 +283631,7 @@ uso
ixL
asc
gtv
-woK
+ukR
woK
tGt
hoE
@@ -347507,7 +347554,7 @@ vxD
aUX
szv
qRj
-fyf
+fzh
bMq
xZa
pAZ
diff --git a/sound/effects/whiteboard_scribble_1.ogg b/sound/effects/whiteboard_scribble_1.ogg
new file mode 100644
index 00000000000..53224fd242d
Binary files /dev/null and b/sound/effects/whiteboard_scribble_1.ogg differ
diff --git a/sound/effects/whiteboard_scribble_2.ogg b/sound/effects/whiteboard_scribble_2.ogg
new file mode 100644
index 00000000000..e1291cf73d9
Binary files /dev/null and b/sound/effects/whiteboard_scribble_2.ogg differ
diff --git a/sound/effects/whiteboard_scribble_3.ogg b/sound/effects/whiteboard_scribble_3.ogg
new file mode 100644
index 00000000000..0375b05b434
Binary files /dev/null and b/sound/effects/whiteboard_scribble_3.ogg differ
diff --git a/tgui/packages/tgui/interfaces/OverlayChoice.tsx b/tgui/packages/tgui/interfaces/OverlayChoice.tsx
new file mode 100644
index 00000000000..2a5b91f3c13
--- /dev/null
+++ b/tgui/packages/tgui/interfaces/OverlayChoice.tsx
@@ -0,0 +1,115 @@
+import { useBackend } from '../backend';
+import { Box, Button, Flex, Section } from '../components';
+import { Window } from '../layouts';
+
+export type IconData = {
+ contents: Item[];
+};
+
+export type Item = {
+ display_name: string;
+ icon?: string | null;
+ icon_name: string;
+ singleton_path: string;
+};
+
+export const OverlayChoice = (props, context) => {
+ const { act, data } = useBackend(context);
+
+ return (
+
+
+
+
+ {data.contents ? : 'No contents loaded.'}
+
+
+
+
+ );
+};
+
+export const ContentsWindow = (props, context) => {
+ const { act, data } = useBackend(context);
+ const { contents } = data;
+
+ return (
+
+ {contents.map((item) => (
+
+
+
+ ))}
+
+ );
+};