mirror of
https://github.com/Aurorastation/Aurora.3.git
synced 2026-08-24 13:30:42 +01:00
Adds whiteboards and gives a new UI to barsigns and its subtypes (#22133)
## About PR Sprites made by @KingOfThePing! Adds whiteboards to following areas: - CE and RD office (portable) - Expedition EVA storage (portable) - Intrepid flight deck (portable) - Xenoarcheology presentation room - Engineering breakroom - Kitchen (as an alternative to holo-menu) Whiteboards are also available in cargo console in the recreation tab As an addition whiteboards can be mapped in with preset overlays and written contents This PR also changes sign selection list menu for barsigns and its subtypes with a tgui image menu ## Images <img width="699" height="534" alt="image" src="https://github.com/user-attachments/assets/7b3de94c-76e4-491d-802c-ae9a31501805" /> <details><summary>video sample</summary> <p> https://github.com/user-attachments/assets/24de419c-e155-4623-9d08-0ff6c0b7d228 </p> </details> ### Asset Licenses The following assets that **have not** been created by myself are included in this PR: | Path | Original Author | License | | --- | --- | --- | | icons/obj/whiteboard.dmi & icons/obj/whiteboard_portable.dmi | KingOfThePing | CC BY-SA 3.0 | | sound/effects/whiteboard_scribble_1.ogg, sound/effects/whiteboard_scribble_2.ogg, sound/effects/whiteboard_scribble_3.ogg | freesound_community (https://pixabay.com/sound-effects/film-special-effects-marker-whiteboard-squeak03-83059/) | Pixabay Licence |
This commit is contained in:
@@ -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 <b>Alt Click</b> 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
|
||||
|
||||
@@ -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 <b>pen</b>."
|
||||
. += "You can <b>ALT Click</b> 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 <b>wrench</b>."
|
||||
|
||||
/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 <b>ALT Click</b> 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"
|
||||
Reference in New Issue
Block a user