diff --git a/.vscode/settings.json b/.vscode/settings.json
index 8edb013566..a11bf93e5c 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -10,7 +10,7 @@
"**/.pnp.*": true
},
"editor.codeActionsOnSave": {
- "source.fixAll.eslint": true
+ "source.fixAll.eslint": "explicit"
},
"workbench.editorAssociations": {
"*.dmi": "dmiEditor.dmiEditor"
diff --git a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_mouse.dm b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_mouse.dm
index 2b0c9c297e..381367fd92 100644
--- a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_mouse.dm
+++ b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_mouse.dm
@@ -23,3 +23,5 @@
#define COMPONENT_NO_MOUSEDROP (1<<0)
///from base of atom/MouseDrop_T: (/atom/from, /mob/user)
#define COMSIG_MOUSEDROPPED_ONTO "mousedropped_onto" //from base of atom/MouseDrop_T: (/atom/from, /mob/user)
+/// From /atom/movable/screen/click(): (atom/target, atom/location, control, params, mob/user)
+#define COMSIG_SCREEN_ELEMENT_CLICK "screen_element_click"
diff --git a/code/__DEFINES/dcs/signals/signals_global.dm b/code/__DEFINES/dcs/signals/signals_global.dm
index 3e0e1d2296..eeb71f90f1 100644
--- a/code/__DEFINES/dcs/signals/signals_global.dm
+++ b/code/__DEFINES/dcs/signals/signals_global.dm
@@ -1,2 +1,5 @@
/// a person somewhere has thrown something : (mob/living/carbon/carbon_thrower, target)
#define COMSIG_GLOB_CARBON_THROW_THING "!throw_thing"
+
+/// Global signal sent before we decide what job everyone has
+#define COMSIG_GLOB_PRE_JOBS_ASSIGNED "!pre_roles_assigned"
diff --git a/code/__DEFINES/dcs/signals/signals_hud.dm b/code/__DEFINES/dcs/signals/signals_hud.dm
index c771204773..63a55f95ca 100644
--- a/code/__DEFINES/dcs/signals/signals_hud.dm
+++ b/code/__DEFINES/dcs/signals/signals_hud.dm
@@ -2,3 +2,5 @@
#define COMSIG_HUD_LOBBY_COLLAPSED "hud_lobby_collapsed"
/// Sent from /atom/movable/screen/lobby/button/collapse/proc/expand_buttons() : ()
#define COMSIG_HUD_LOBBY_EXPANDED "hud_lobby_expanded"
+/// Sent from /atom/movable/screen/lobby/button/ready/Click() : ()
+#define COMSIG_HUD_PLAYER_READY_TOGGLE "hud_player_ready_toggle"
diff --git a/code/__DEFINES/language.dm b/code/__DEFINES/language.dm
index 5973185620..91f9f8572b 100644
--- a/code/__DEFINES/language.dm
+++ b/code/__DEFINES/language.dm
@@ -4,10 +4,21 @@
#define LANGUAGE_HIDE_ICON_IF_NOT_UNDERSTOOD 8
// LANGUAGE SOURCE DEFINES
-#define LANGUAGE_ALL "all" // For use in full removal only.
-#define LANGUAGE_ATOM "atom"
-#define LANGUAGE_MIND "mind"
+/// For use in full removal only.
+#define LANGUAGE_ALL "all"
+// Generic language sources.
+/// Language is linked to the movable directly.
+#define LANGUAGE_ATOM "atom"
+/// Language is linked to the mob's mind.
+/// If a mind transfer happens, language follows.
+#define LANGUAGE_MIND "mind"
+/// Language is linked to the mob's species.
+/// If a species change happens, language goes away.
+/// If applied to a non-human (no species) atom, this is effectively the same as [LANGUAGE_ATOM].
+#define LANGUAGE_SPECIES "species"
+// More specific language sources.
+// Only ever goes away when dismissed directly.
#define LANGUAGE_ABSORB "absorb"
#define LANGUAGE_APHASIA "aphasia"
#define LANGUAGE_BLOODSUCKER "bloodsucker"
@@ -24,8 +35,10 @@
#define LANGUAGE_STONER "stoner"
#define LANGUAGE_VASSAL "vassal"
#define LANGUAGE_VOICECHANGE "voicechange"
-//#define LANGUAGE_MULTILINGUAL "multilingual"
+#define LANGUAGE_MULTILINGUAL "multilingual"
-//SKYRAT LANGUAGES
-#define LANGUAGE_ADDITIONAL "additional"
-#define LANGUAGE_NINJA "ninja"
+// Language flags. Used in granting and removing languages.
+/// This language can be spoken.
+#define SPOKEN_LANGUAGE (1<<0)
+/// This language can be understood.
+#define UNDERSTOOD_LANGUAGE (1<<1)
diff --git a/code/__HELPERS/_lists.dm b/code/__HELPERS/_lists.dm
index 3b092fd3b7..a8373205ca 100644
--- a/code/__HELPERS/_lists.dm
+++ b/code/__HELPERS/_lists.dm
@@ -743,6 +743,13 @@
else
L1[key] = other_value
+/// Turns an associative list into a flat list of keys
+/proc/assoc_to_keys(list/input)
+ var/list/keys = list()
+ for(var/key in input)
+ UNTYPED_LIST_ADD(keys, key)
+ return keys
+
/proc/assoc_list_strip_value(list/input)
var/list/ret = list()
for(var/key in input)
diff --git a/code/__SANDCODE/DEFINES/language.dm b/code/__SANDCODE/DEFINES/language.dm
index 56d6e245ad..d36090448e 100644
--- a/code/__SANDCODE/DEFINES/language.dm
+++ b/code/__SANDCODE/DEFINES/language.dm
@@ -4,3 +4,5 @@
* "i want fancy merp language"
*/
#define LANGUAGE_SERGAL "Sagaru"
+
+#define LANGUAGE_NINJA "ninja"
diff --git a/code/_onclick/hud/ai.dm b/code/_onclick/hud/ai.dm
index d4344b9464..b264de2cd9 100644
--- a/code/_onclick/hud/ai.dm
+++ b/code/_onclick/hud/ai.dm
@@ -194,109 +194,91 @@
var/atom/movable/screen/using
// Language menu
- using = new /atom/movable/screen/language_menu
+ using = new /atom/movable/screen/language_menu(null, src)
using.screen_loc = ui_ai_language_menu
- using.hud = src
static_inventory += using
//AI core
- using = new /atom/movable/screen/ai/aicore()
+ using = new /atom/movable/screen/ai/aicore(null, src)
using.screen_loc = ui_ai_core
- using.hud = src
static_inventory += using
//Camera list
- using = new /atom/movable/screen/ai/camera_list()
+ using = new /atom/movable/screen/ai/camera_list(null, src)
using.screen_loc = ui_ai_camera_list
- using.hud = src
static_inventory += using
//Track
- using = new /atom/movable/screen/ai/camera_track()
+ using = new /atom/movable/screen/ai/camera_track(null, src)
using.screen_loc = ui_ai_track_with_camera
- using.hud = src
static_inventory += using
//Camera light
- using = new /atom/movable/screen/ai/camera_light()
+ using = new /atom/movable/screen/ai/camera_light(null, src)
using.screen_loc = ui_ai_camera_light
- using.hud = src
static_inventory += using
//Crew Monitoring
- using = new /atom/movable/screen/ai/crew_monitor()
+ using = new /atom/movable/screen/ai/crew_monitor(null, src)
using.screen_loc = ui_ai_crew_monitor
- using.hud = src
static_inventory += using
//Crew Manifest
- using = new /atom/movable/screen/ai/crew_manifest()
+ using = new /atom/movable/screen/ai/crew_manifest(null, src)
using.screen_loc = ui_ai_crew_manifest
- using.hud = src
static_inventory += using
//Alerts
- using = new /atom/movable/screen/ai/alerts()
+ using = new /atom/movable/screen/ai/alerts(null, src)
using.screen_loc = ui_ai_alerts
- using.hud = src
static_inventory += using
//Announcement
- using = new /atom/movable/screen/ai/announcement()
+ using = new /atom/movable/screen/ai/announcement(null, src)
using.screen_loc = ui_ai_announcement
- using.hud = src
static_inventory += using
//Shuttle
- using = new /atom/movable/screen/ai/call_shuttle()
+ using = new /atom/movable/screen/ai/call_shuttle(null, src)
using.screen_loc = ui_ai_shuttle
- using.hud = src
static_inventory += using
//Laws
- using = new /atom/movable/screen/ai/state_laws()
+ using = new /atom/movable/screen/ai/state_laws(null, src)
using.screen_loc = ui_ai_state_laws
- using.hud = src
static_inventory += using
//PDA message
- using = new /atom/movable/screen/ai/pda_msg_send()
+ using = new /atom/movable/screen/ai/pda_msg_send(null, src)
using.screen_loc = ui_ai_pda_send
- using.hud = src
static_inventory += using
//PDA log
- using = new /atom/movable/screen/ai/pda_msg_show()
+ using = new /atom/movable/screen/ai/pda_msg_show(null, src)
using.screen_loc = ui_ai_pda_log
- using.hud = src
static_inventory += using
//Take image
- using = new /atom/movable/screen/ai/image_take()
+ using = new /atom/movable/screen/ai/image_take(null, src)
using.screen_loc = ui_ai_take_picture
- using.hud = src
static_inventory += using
//View images
- using = new /atom/movable/screen/ai/image_view()
+ using = new /atom/movable/screen/ai/image_view(null, src)
using.screen_loc = ui_ai_view_images
- using.hud = src
static_inventory += using
//Medical/Security sensors
- using = new /atom/movable/screen/ai/sensors()
+ using = new /atom/movable/screen/ai/sensors(null, src)
using.screen_loc = ui_ai_sensor
- using.hud = src
static_inventory += using
//Multicamera mode
- using = new /atom/movable/screen/ai/multicam()
+ using = new /atom/movable/screen/ai/multicam(null, src)
using.screen_loc = ui_ai_multicam
- using.hud = src
static_inventory += using
//Add multicamera camera
- using = new /atom/movable/screen/ai/add_multicam()
+ using = new /atom/movable/screen/ai/add_multicam(null, src)
using.screen_loc = ui_ai_add_multicam
- using.hud = src
static_inventory += using
diff --git a/code/_onclick/hud/alert.dm b/code/_onclick/hud/alert.dm
index fdfe4b2b4e..3124845e18 100644
--- a/code/_onclick/hud/alert.dm
+++ b/code/_onclick/hud/alert.dm
@@ -272,10 +272,10 @@ or something covering your eyes."
var/command
/atom/movable/screen/alert/mind_control/Click()
- var/mob/living/L = usr
- if(L != owner)
+ . = ..()
+ if(!.)
return
- to_chat(L, "[command]")
+ to_chat(usr, "[command]")
/atom/movable/screen/alert/hypnosis
name = "Hypnosis"
@@ -296,9 +296,13 @@ If you're feeling frisky, examine yourself and click the underlined item to pull
clickable_glow = TRUE
/atom/movable/screen/alert/embeddedobject/Click()
- if(isliving(usr) && usr == owner)
- var/mob/living/carbon/M = usr
- return M.help_shake_act(M)
+ . = ..()
+ if(!.)
+ return
+ if(!isliving(usr))
+ return
+ var/mob/living/carbon/M = usr
+ return M.help_shake_act(M)
/atom/movable/screen/alert/weightless
name = "Weightless"
@@ -325,8 +329,11 @@ or shoot a gun to move around via Newton's 3rd Law of Motion."
clickable_glow = TRUE
/atom/movable/screen/alert/fire/Click()
+ . = ..()
+ if(!.)
+ return
var/mob/living/L = usr
- if(!istype(L) || !L.can_resist() || L != owner)
+ if(!istype(L) || !L.can_resist())
return
L.MarkResistTime()
if(CHECK_MOBILITY(L, MOBILITY_MOVE))
@@ -734,14 +741,16 @@ so as to remain in compliance with the most up-to-date laws."
var/atom/target = null
/atom/movable/screen/alert/hackingapc/Click()
- if(!usr || !usr.client || usr != owner)
+ . = ..()
+ if(!.)
return
if(!target)
return
var/mob/living/silicon/ai/AI = usr
var/turf/T = get_turf(target)
- if(T)
- AI.eyeobj.setLoc(T)
+ if(!T)
+ return
+ AI.eyeobj.setLoc(T)
//MECHS
@@ -761,10 +770,11 @@ so as to remain in compliance with the most up-to-date laws."
clickable_glow = TRUE
/atom/movable/screen/alert/notify_cloning/Click()
- if(!usr || !usr.client || usr != owner)
+ . = ..()
+ if(!.)
return
- var/mob/dead/observer/G = usr
- G.reenter_corpse()
+ var/mob/dead/observer/dead_owner = usr
+ dead_owner.reenter_corpse()
/atom/movable/screen/alert/notify_action
name = "Body created"
@@ -776,8 +786,10 @@ so as to remain in compliance with the most up-to-date laws."
var/action = NOTIFY_JUMP
/atom/movable/screen/alert/notify_action/Click()
- if(!usr || !usr.client || usr != owner)
+ . = ..()
+ if(!.)
return
+
if(!target)
return
var/mob/dead/observer/G = usr
@@ -795,32 +807,43 @@ so as to remain in compliance with the most up-to-date laws."
//OBJECT-BASED
-/atom/movable/screen/alert/restrained
- clickable_glow = TRUE
-
-/atom/movable/screen/alert/restrained/buckled
+/atom/movable/screen/alert/buckled
name = "Buckled"
desc = "You've been buckled to something. Click the alert to unbuckle unless you're handcuffed."
icon_state = "buckled"
+ clickable_glow = TRUE
+
+/atom/movable/screen/alert/restrained
+ clickable_glow = TRUE
/atom/movable/screen/alert/restrained/handcuffed
name = "Handcuffed"
desc = "You're handcuffed and can't act. If anyone drags you, you won't be able to move. Click the alert to free yourself."
+ click_master = FALSE
/atom/movable/screen/alert/restrained/legcuffed
name = "Legcuffed"
desc = "You're legcuffed, which slows you down considerably. Click the alert to free yourself."
+ click_master = FALSE
/atom/movable/screen/alert/restrained/Click()
+ . = ..()
+ if(!.)
+ return
+
var/mob/living/L = usr
- if(!istype(L) || !L.can_resist() || L != owner)
+ if(!istype(L) || !L.can_resist())
return
L.MarkResistTime()
return L.resist_restraints()
-/atom/movable/screen/alert/restrained/buckled/Click()
+/atom/movable/screen/alert/buckled/Click()
+ . = ..()
+ if(!.)
+ return
+
var/mob/living/L = usr
- if(!istype(L) || !L.can_resist() || L != owner)
+ if(!istype(L) || !L.can_resist())
return
L.MarkResistTime()
return L.resist_buckle()
@@ -837,8 +860,11 @@ so as to remain in compliance with the most up-to-date laws."
clickable_glow = TRUE
/atom/movable/screen/alert/shoes/Click()
+ . = ..()
+ if(!.)
+ return
var/mob/living/carbon/C = usr
- if(!istype(C) || !C.can_resist() || C != owner || !C.shoes)
+ if(!istype(C) || !C.can_resist() || !C.shoes)
return
C.MarkResistTime()
C.shoes.handle_tying(C)
diff --git a/code/_onclick/hud/alien.dm b/code/_onclick/hud/alien.dm
index 8a494a05b9..49d0087a7d 100644
--- a/code/_onclick/hud/alien.dm
+++ b/code/_onclick/hud/alien.dm
@@ -39,84 +39,71 @@
//begin buttons
- using = new /atom/movable/screen/swap_hand()
+ using = new /atom/movable/screen/swap_hand(null, src)
using.icon = ui_style
using.icon_state = "swap_1"
using.screen_loc = ui_swaphand_position(owner,1)
- using.hud = src
static_inventory += using
- using = new /atom/movable/screen/swap_hand()
+ using = new /atom/movable/screen/swap_hand(null, src)
using.icon = ui_style
using.icon_state = "swap_2"
using.screen_loc = ui_swaphand_position(owner,2)
- using.hud = src
static_inventory += using
- action_intent = new /atom/movable/screen/act_intent/alien()
+ action_intent = new /atom/movable/screen/act_intent/alien(null, src)
action_intent.icon_state = mymob.a_intent
- action_intent.hud = src
static_inventory += action_intent
if(isalienhunter(mymob))
var/mob/living/carbon/alien/humanoid/hunter/H = mymob
- H.leap_icon = new /atom/movable/screen/alien/leap()
+ H.leap_icon = new /atom/movable/screen/alien/leap(null, src)
H.leap_icon.screen_loc = ui_alien_storage_r
static_inventory += H.leap_icon
- using = new/atom/movable/screen/language_menu
+ using = new/atom/movable/screen/language_menu(null, src)
using.screen_loc = ui_alien_language_menu
- using.hud = src
static_inventory += using
- using = new /atom/movable/screen/drop()
+ using = new /atom/movable/screen/drop(null, src)
using.icon = ui_style
using.screen_loc = ui_drop_throw
- using.hud = src
static_inventory += using
- using = new /atom/movable/screen/resist()
+ using = new /atom/movable/screen/resist(null, src)
using.icon = ui_style
using.screen_loc = ui_pull_resist
- using.hud = src
hotkeybuttons += using
- throw_icon = new /atom/movable/screen/throw_catch()
+ throw_icon = new /atom/movable/screen/throw_catch(null, src)
throw_icon.icon = ui_style
throw_icon.screen_loc = ui_drop_throw
- throw_icon.hud = src
hotkeybuttons += throw_icon
- pull_icon = new /atom/movable/screen/pull()
+ pull_icon = new /atom/movable/screen/pull(null, src)
pull_icon.icon = ui_style
- pull_icon.hud = src
pull_icon.update_icon()
pull_icon.screen_loc = ui_pull_resist
static_inventory += pull_icon
//begin indicators
- healths = new /atom/movable/screen/healths/alien()
- healths.hud = src
+ healths = new /atom/movable/screen/healths/alien(null, src)
infodisplay += healths
- alien_plasma_display = new /atom/movable/screen/alien/plasma_display()
- alien_plasma_display.hud = src
+ alien_plasma_display = new /atom/movable/screen/alien/plasma_display(null, src)
infodisplay += alien_plasma_display
if(!isalienqueen(mymob))
- alien_queen_finder = new /atom/movable/screen/alien/alien_queen_finder
- alien_queen_finder.hud = src
+ alien_queen_finder = new /atom/movable/screen/alien/alien_queen_finder(null, src)
infodisplay += alien_queen_finder
- zone_select = new /atom/movable/screen/zone_sel/alien()
- zone_select.hud = src
+ zone_select = new /atom/movable/screen/zone_sel/alien(null, src)
zone_select.update_icon()
static_inventory += zone_select
for(var/atom/movable/screen/inventory/inv in (static_inventory + toggleable_inventory))
if(inv.slot_id)
- inv.hud = src
inv_slots[TOBITSHIFT(inv.slot_id) + 1] = inv
inv.update_icon()
diff --git a/code/_onclick/hud/alien_larva.dm b/code/_onclick/hud/alien_larva.dm
index 17d3ad35e4..50848bb37e 100644
--- a/code/_onclick/hud/alien_larva.dm
+++ b/code/_onclick/hud/alien_larva.dm
@@ -5,32 +5,26 @@
..()
var/atom/movable/screen/using
- action_intent = new /atom/movable/screen/act_intent/alien()
+ action_intent = new /atom/movable/screen/act_intent/alien(null, src)
action_intent.icon_state = mymob.a_intent
- action_intent.hud = src
static_inventory += action_intent
- healths = new /atom/movable/screen/healths/alien()
- healths.hud = src
+ healths = new /atom/movable/screen/healths/alien(null, src)
infodisplay += healths
- alien_queen_finder = new /atom/movable/screen/alien/alien_queen_finder()
- alien_queen_finder.hud = src
+ alien_queen_finder = new /atom/movable/screen/alien/alien_queen_finder(null, src)
infodisplay += alien_queen_finder
- pull_icon = new /atom/movable/screen/pull()
+ pull_icon = new /atom/movable/screen/pull(null, src)
pull_icon.icon = 'icons/mob/screen_alien.dmi'
- pull_icon.hud = src
pull_icon.update_icon()
pull_icon.screen_loc = ui_pull_resist
hotkeybuttons += pull_icon
- using = new/atom/movable/screen/language_menu
+ using = new/atom/movable/screen/language_menu(null, src)
using.screen_loc = ui_alien_language_menu
- using.hud = src
static_inventory += using
- zone_select = new /atom/movable/screen/zone_sel/alien()
- zone_select.hud = src
+ zone_select = new /atom/movable/screen/zone_sel/alien(null, src)
zone_select.update_icon()
static_inventory += zone_select
diff --git a/code/_onclick/hud/blob_overmind.dm b/code/_onclick/hud/blob_overmind.dm
index 8a981d5796..7ce0086974 100644
--- a/code/_onclick/hud/blob_overmind.dm
+++ b/code/_onclick/hud/blob_overmind.dm
@@ -127,61 +127,50 @@
..()
var/atom/movable/screen/using
- blobpwrdisplay = new /atom/movable/screen()
+ blobpwrdisplay = new /atom/movable/screen(null, src)
blobpwrdisplay.name = "blob power"
blobpwrdisplay.icon_state = "block"
blobpwrdisplay.screen_loc = ui_health
blobpwrdisplay.mouse_opacity = MOUSE_OPACITY_TRANSPARENT
blobpwrdisplay.layer = ABOVE_HUD_LAYER
blobpwrdisplay.plane = ABOVE_HUD_PLANE
- blobpwrdisplay.hud = src
infodisplay += blobpwrdisplay
- healths = new /atom/movable/screen/healths/blob()
- healths.hud = src
+ healths = new /atom/movable/screen/healths/blob(null, src)
infodisplay += healths
- using = new /atom/movable/screen/blob/BlobHelp()
+ using = new /atom/movable/screen/blob/BlobHelp(null, src)
using.screen_loc = "WEST:6,NORTH:-3"
- using.hud = src
static_inventory += using
- using = new /atom/movable/screen/blob/JumpToNode()
+ using = new /atom/movable/screen/blob/JumpToNode(null, src)
using.screen_loc = ui_inventory
- using.hud = src
static_inventory += using
- using = new /atom/movable/screen/blob/JumpToCore()
+ using = new /atom/movable/screen/blob/JumpToCore(null, src)
using.screen_loc = ui_zonesel
- using.hud = src
static_inventory += using
- using = new /atom/movable/screen/blob/Blobbernaut()
+ using = new /atom/movable/screen/blob/Blobbernaut(null, src)
using.screen_loc = ui_belt
- using.hud = src
static_inventory += using
- using = new /atom/movable/screen/blob/ResourceBlob()
+ using = new /atom/movable/screen/blob/ResourceBlob(null, src)
using.screen_loc = ui_back
- using.hud = src
static_inventory += using
- using = new /atom/movable/screen/blob/NodeBlob()
+ using = new /atom/movable/screen/blob/NodeBlob(null, src)
using.screen_loc = ui_hand_position(2)
- using.hud = src
static_inventory += using
- using = new /atom/movable/screen/blob/FactoryBlob()
+ using = new /atom/movable/screen/blob/FactoryBlob(null, src)
using.screen_loc = ui_hand_position(1)
- using.hud = src
static_inventory += using
- using = new /atom/movable/screen/blob/ReadaptStrain()
+ using = new /atom/movable/screen/blob/ReadaptStrain(null, src)
using.screen_loc = ui_storage1
- using.hud = src
static_inventory += using
- using = new /atom/movable/screen/blob/RelocateCore()
+ using = new /atom/movable/screen/blob/RelocateCore(null, src)
using.screen_loc = ui_storage2
- using.hud = src
static_inventory += using
diff --git a/code/_onclick/hud/blobbernauthud.dm b/code/_onclick/hud/blobbernauthud.dm
index 430e8e81e7..f82be53afa 100644
--- a/code/_onclick/hud/blobbernauthud.dm
+++ b/code/_onclick/hud/blobbernauthud.dm
@@ -2,10 +2,8 @@
/datum/hud/blobbernaut/New(mob/owner)
..()
- blobpwrdisplay = new /atom/movable/screen/healths/blob/naut/core()
- blobpwrdisplay.hud = src
+ blobpwrdisplay = new /atom/movable/screen/healths/blob/naut/core(null, src)
infodisplay += blobpwrdisplay
- healths = new /atom/movable/screen/healths/blob/naut()
- healths.hud = src
+ healths = new /atom/movable/screen/healths/blob/naut(null, src)
infodisplay += healths
diff --git a/code/_onclick/hud/clockwork_marauder.dm b/code/_onclick/hud/clockwork_marauder.dm
index de9cb65c75..51d1fbb4a9 100644
--- a/code/_onclick/hud/clockwork_marauder.dm
+++ b/code/_onclick/hud/clockwork_marauder.dm
@@ -7,14 +7,14 @@
..()
var/atom/movable/screen/using
- healths = new /atom/movable/screen/healths/clock()
+ healths = new /atom/movable/screen/healths/clock(null, src)
infodisplay += healths
- hosthealth = new /atom/movable/screen/healths/clock()
+ hosthealth = new /atom/movable/screen/healths/clock(null, src)
hosthealth.screen_loc = ui_internal
infodisplay += hosthealth
- using = new /atom/movable/screen/marauder/emerge()
+ using = new /atom/movable/screen/marauder/emerge(null, src)
using.screen_loc = ui_zonesel
static_inventory += using
diff --git a/code/_onclick/hud/constructs.dm b/code/_onclick/hud/constructs.dm
index 31f1060f17..70f40aace3 100644
--- a/code/_onclick/hud/constructs.dm
+++ b/code/_onclick/hud/constructs.dm
@@ -3,13 +3,11 @@
/datum/hud/constructs/New(mob/owner)
..()
- pull_icon = new /atom/movable/screen/pull()
+ pull_icon = new /atom/movable/screen/pull(null, src)
pull_icon.icon = ui_style
- pull_icon.hud = src
pull_icon.update_icon()
pull_icon.screen_loc = ui_construct_pull
static_inventory += pull_icon
- healths = new /atom/movable/screen/healths/construct()
- healths.hud = src
+ healths = new /atom/movable/screen/healths/construct(null, src)
infodisplay += healths
diff --git a/code/_onclick/hud/devil.dm b/code/_onclick/hud/devil.dm
index 574f5dd1fd..fb5028145c 100644
--- a/code/_onclick/hud/devil.dm
+++ b/code/_onclick/hud/devil.dm
@@ -6,51 +6,44 @@
..()
var/atom/movable/screen/using
- using = new /atom/movable/screen/drop()
+ using = new /atom/movable/screen/drop(null, src)
using.icon = ui_style
using.screen_loc = ui_drone_drop
- using.hud = src
static_inventory += using
- pull_icon = new /atom/movable/screen/pull()
+ pull_icon = new /atom/movable/screen/pull(null, src)
pull_icon.icon = ui_style
- pull_icon.hud = src
pull_icon.update_icon()
pull_icon.screen_loc = ui_drone_pull
static_inventory += pull_icon
build_hand_slots()
- using = new /atom/movable/screen/inventory()
+ using = new /atom/movable/screen/inventory(null, src)
using.name = "hand"
using.icon = ui_style
using.icon_state = "swap_1_m"
using.screen_loc = ui_swaphand_position(owner,1)
using.layer = HUD_LAYER
using.plane = HUD_PLANE
- using.hud = src
static_inventory += using
- using = new /atom/movable/screen/inventory()
+ using = new /atom/movable/screen/inventory(null, src)
using.name = "hand"
using.icon = ui_style
using.icon_state = "swap_2"
using.screen_loc = ui_swaphand_position(owner,2)
using.layer = HUD_LAYER
using.plane = HUD_PLANE
- using.hud = src
static_inventory += using
- zone_select = new /atom/movable/screen/zone_sel()
+ zone_select = new /atom/movable/screen/zone_sel(null, src)
zone_select.icon = ui_style
- zone_select.hud = src
zone_select.update_icon()
- lingchemdisplay = new /atom/movable/screen/ling/chems()
- lingchemdisplay.hud = src
+ lingchemdisplay = new /atom/movable/screen/ling/chems(null, src)
- devilsouldisplay = new /atom/movable/screen/devil/soul_counter
- devilsouldisplay.hud = src
+ devilsouldisplay = new /atom/movable/screen/devil/soul_counter(null, src)
infodisplay += devilsouldisplay
diff --git a/code/_onclick/hud/drones.dm b/code/_onclick/hud/drones.dm
index a2cae89864..a6632b553f 100644
--- a/code/_onclick/hud/drones.dm
+++ b/code/_onclick/hud/drones.dm
@@ -2,7 +2,7 @@
..()
var/atom/movable/screen/inventory/inv_box
- inv_box = new /atom/movable/screen/inventory()
+ inv_box = new /atom/movable/screen/inventory(null, src)
inv_box.name = "internal storage"
inv_box.icon = ui_style
inv_box.icon_state = "suit_storage"
@@ -11,7 +11,7 @@
inv_box.slot_id = ITEM_SLOT_DEX_STORAGE
static_inventory += inv_box
- inv_box = new /atom/movable/screen/inventory()
+ inv_box = new /atom/movable/screen/inventory(null, src)
inv_box.name = "head/mask"
inv_box.icon = ui_style
inv_box.icon_state = "mask"
@@ -22,7 +22,6 @@
for(var/atom/movable/screen/inventory/inv in (static_inventory + toggleable_inventory))
if(inv.slot_id)
- inv.hud = src
inv_slots[TOBITSHIFT(inv.slot_id) + 1] = inv
inv.update_icon()
diff --git a/code/_onclick/hud/families.dm b/code/_onclick/hud/families.dm
index 6cc9f4ef32..81da541011 100644
--- a/code/_onclick/hud/families.dm
+++ b/code/_onclick/hud/families.dm
@@ -9,9 +9,6 @@
/// Boolean, have the cops arrived? If so, the icon stops changing and remains the same.
var/cops_arrived = 0
-/atom/movable/screen/wanted/New()
- return ..()
-
/atom/movable/screen/wanted/Initialize(mapload)
. = ..()
update_icon()
diff --git a/code/_onclick/hud/generic_dextrous.dm b/code/_onclick/hud/generic_dextrous.dm
index 1762bee1fc..a7cfec5a06 100644
--- a/code/_onclick/hud/generic_dextrous.dm
+++ b/code/_onclick/hud/generic_dextrous.dm
@@ -3,63 +3,55 @@
..()
var/atom/movable/screen/using
- using = new /atom/movable/screen/drop()
+ using = new /atom/movable/screen/drop(null, src)
using.icon = ui_style
using.screen_loc = ui_drone_drop
- using.hud = src
static_inventory += using
- pull_icon = new /atom/movable/screen/pull()
+ pull_icon = new /atom/movable/screen/pull(null, src)
pull_icon.icon = ui_style
- pull_icon.hud = src
pull_icon.update_icon()
pull_icon.screen_loc = ui_drone_pull
static_inventory += pull_icon
build_hand_slots()
- using = new /atom/movable/screen/swap_hand()
+ using = new /atom/movable/screen/swap_hand(null, src)
using.icon = ui_style
using.icon_state = "swap_1_m"
using.screen_loc = ui_swaphand_position(owner,1)
- using.hud = src
static_inventory += using
- using = new /atom/movable/screen/swap_hand()
+ using = new /atom/movable/screen/swap_hand(null, src)
using.icon = ui_style
using.icon_state = "swap_2"
using.screen_loc = ui_swaphand_position(owner,2)
- using.hud = src
static_inventory += using
if(mymob.possible_a_intents)
if(mymob.possible_a_intents.len == 4)
// All possible intents - full intent selector
- action_intent = new /atom/movable/screen/act_intent/segmented
+ action_intent = new /atom/movable/screen/act_intent/segmented(null, src)
else
- action_intent = new /atom/movable/screen/act_intent
+ action_intent = new /atom/movable/screen/act_intent(null, src)
action_intent.icon = ui_style
action_intent.icon_state = mymob.a_intent
- action_intent.hud = src
static_inventory += action_intent
- zone_select = new /atom/movable/screen/zone_sel()
+ zone_select = new /atom/movable/screen/zone_sel(null, src)
zone_select.icon = ui_style
- zone_select.hud = src
zone_select.update_icon()
static_inventory += zone_select
- using = new /atom/movable/screen/area_creator
+ using = new /atom/movable/screen/area_creator(null, src)
using.icon = ui_style
- using.hud = src
static_inventory += using
mymob.client.screen = list()
for(var/atom/movable/screen/inventory/inv in (static_inventory + toggleable_inventory))
if(inv.slot_id)
- inv.hud = src
inv_slots[TOBITSHIFT(inv.slot_id) + 1] = inv
inv.update_icon()
diff --git a/code/_onclick/hud/ghost.dm b/code/_onclick/hud/ghost.dm
index f4f1f2f7b0..ea36022dfb 100644
--- a/code/_onclick/hud/ghost.dm
+++ b/code/_onclick/hud/ghost.dm
@@ -49,34 +49,28 @@
..()
var/atom/movable/screen/using
- using = new /atom/movable/screen/ghost/jumptomob()
+ using = new /atom/movable/screen/ghost/jumptomob(null, src)
using.screen_loc = ui_ghost_jumptomob
- using.hud = src
static_inventory += using
- using = new /atom/movable/screen/ghost/orbit()
+ using = new /atom/movable/screen/ghost/orbit(null, src)
using.screen_loc = ui_ghost_orbit
- using.hud = src
static_inventory += using
- using = new /atom/movable/screen/ghost/reenter_corpse()
+ using = new /atom/movable/screen/ghost/reenter_corpse(null, src)
using.screen_loc = ui_ghost_reenter_corpse
- using.hud = src
static_inventory += using
- using = new /atom/movable/screen/ghost/teleport()
+ using = new /atom/movable/screen/ghost/teleport(null, src)
using.screen_loc = ui_ghost_teleport
- using.hud = src
static_inventory += using
- using = new /atom/movable/screen/ghost/spawners()
+ using = new /atom/movable/screen/ghost/spawners(null, src)
using.screen_loc = ui_ghost_spawners
- using.hud = src
static_inventory += using
- using = new /atom/movable/screen/language_menu
+ using = new /atom/movable/screen/language_menu(null, src)
using.icon = ui_style
- using.hud = src
static_inventory += using
/datum/hud/ghost/show_hud(version = 0, mob/viewmob)
diff --git a/code/_onclick/hud/guardian.dm b/code/_onclick/hud/guardian.dm
index 09ec5d925c..0443dc3deb 100644
--- a/code/_onclick/hud/guardian.dm
+++ b/code/_onclick/hud/guardian.dm
@@ -3,33 +3,27 @@
..()
var/atom/movable/screen/using
- healths = new /atom/movable/screen/healths/guardian()
- healths.hud = src
+ healths = new /atom/movable/screen/healths/guardian(null, src)
infodisplay += healths
- using = new /atom/movable/screen/guardian/Manifest()
+ using = new /atom/movable/screen/guardian/Manifest(null, src)
using.screen_loc = ui_hand_position(2)
- using.hud = src
static_inventory += using
- using = new /atom/movable/screen/guardian/Recall()
+ using = new /atom/movable/screen/guardian/Recall(null, src)
using.screen_loc = ui_hand_position(1)
- using.hud = src
static_inventory += using
- using = new owner.toggle_button_type()
+ using = new owner.toggle_button_type(null, src)
using.screen_loc = ui_storage1
- using.hud = src
static_inventory += using
- using = new /atom/movable/screen/guardian/ToggleLight()
+ using = new /atom/movable/screen/guardian/ToggleLight(null, src)
using.screen_loc = ui_inventory
- using.hud = src
static_inventory += using
- using = new /atom/movable/screen/guardian/Communicate()
+ using = new /atom/movable/screen/guardian/Communicate(null, src)
using.screen_loc = ui_back
- using.hud = src
static_inventory += using
/datum/hud/dextrous/guardian/New(mob/living/simple_animal/hostile/guardian/owner) //for a dextrous guardian
@@ -38,7 +32,7 @@
if(istype(owner, /mob/living/simple_animal/hostile/guardian/dextrous))
var/atom/movable/screen/inventory/inv_box
- inv_box = new /atom/movable/screen/inventory()
+ inv_box = new /atom/movable/screen/inventory(null, src)
inv_box.name = "internal storage"
inv_box.icon = ui_style
inv_box.icon_state = "suit_storage"
@@ -46,32 +40,32 @@
inv_box.slot_id = ITEM_SLOT_DEX_STORAGE
static_inventory += inv_box
- using = new /atom/movable/screen/guardian/Communicate()
+ using = new /atom/movable/screen/guardian/Communicate(null, src)
using.screen_loc = ui_sstore1
static_inventory += using
else
- using = new /atom/movable/screen/guardian/Communicate()
+ using = new /atom/movable/screen/guardian/Communicate(null, src)
using.screen_loc = ui_id
static_inventory += using
- healths = new /atom/movable/screen/healths/guardian()
+ healths = new /atom/movable/screen/healths/guardian(null, src)
infodisplay += healths
- using = new /atom/movable/screen/guardian/Manifest()
+ using = new /atom/movable/screen/guardian/Manifest(null, src)
using.screen_loc = ui_belt
static_inventory += using
- using = new /atom/movable/screen/guardian/Recall()
+ using = new /atom/movable/screen/guardian/Recall(null, src)
using.screen_loc = ui_back
static_inventory += using
- using = new owner.toggle_button_type()
+ using = new owner.toggle_button_type(null, src)
using.screen_loc = ui_storage2
static_inventory += using
- using = new /atom/movable/screen/guardian/ToggleLight()
+ using = new /atom/movable/screen/guardian/ToggleLight(null, src)
using.screen_loc = ui_inventory
static_inventory += using
diff --git a/code/_onclick/hud/hud.dm b/code/_onclick/hud/hud.dm
index 07b2e90147..1dac577a5c 100644
--- a/code/_onclick/hud/hud.dm
+++ b/code/_onclick/hud/hud.dm
@@ -110,12 +110,12 @@ GLOBAL_LIST_INIT(available_ui_styles, list(
hand_slots = list()
for(var/mytype in subtypesof(/atom/movable/screen/plane_master))
- var/atom/movable/screen/plane_master/instance = new mytype()
+ var/atom/movable/screen/plane_master/instance = new mytype(null, src)
plane_masters["[instance.plane]"] = instance
instance.backdrop(mymob)
for(var/mytype in subtypesof(/atom/movable/plane_master_controller))
- var/atom/movable/plane_master_controller/controller_instance = new mytype(src)
+ var/atom/movable/plane_master_controller/controller_instance = new mytype(null, src)
plane_master_controllers[controller_instance.name] = controller_instance
screentip_text = new(null, src)
@@ -343,14 +343,13 @@ GLOBAL_LIST_INIT(available_ui_styles, list(
hand_slots = list()
var/atom/movable/screen/inventory/hand/hand_box
for(var/i in 1 to mymob.held_items.len)
- hand_box = new /atom/movable/screen/inventory/hand()
+ hand_box = new /atom/movable/screen/inventory/hand(null, src)
hand_box.name = mymob.get_held_index_name(i)
hand_box.icon = ui_style
hand_box.icon_state = "hand_[mymob.held_index_to_dir(i)]"
hand_box.screen_loc = ui_hand_position(i)
hand_box.held_index = i
hand_slots["[i]"] = hand_box
- hand_box.hud = src
static_inventory += hand_box
hand_box.update_icon()
diff --git a/code/_onclick/hud/human.dm b/code/_onclick/hud/human.dm
index a71bddcdb9..81cd1c420e 100644
--- a/code/_onclick/hud/human.dm
+++ b/code/_onclick/hud/human.dm
@@ -220,54 +220,47 @@
var/atom/movable/screen/using
var/atom/movable/screen/inventory/inv_box
- using = new/atom/movable/screen/language_menu
+ using = new/atom/movable/screen/language_menu(null, src)
using.icon = ui_style
if(!widescreenlayout) // CIT CHANGE
using.screen_loc = ui_boxlang // CIT CHANGE
- using.hud = src
static_inventory += using
- using = new /atom/movable/screen/area_creator
+ using = new /atom/movable/screen/area_creator(null, src)
using.icon = ui_style
if(!widescreenlayout) // CIT CHANGE
using.screen_loc = ui_boxarea // CIT CHANGE
- using.hud = src
static_inventory += using
- using = new /atom/movable/screen/voretoggle() //We fancy Vore now
+ using = new /atom/movable/screen/voretoggle(null, src) //We fancy Vore now
using.icon = tg_ui_icon_to_cit_ui(ui_style)
using.screen_loc = ui_voremode
if(!widescreenlayout)
using.screen_loc = ui_boxvore
- using.hud = src
static_inventory += using
- action_intent = new /atom/movable/screen/act_intent/segmented
+ action_intent = new /atom/movable/screen/act_intent/segmented(null, src)
action_intent.icon_state = mymob.a_intent
- action_intent.hud = src
static_inventory += action_intent
assert_move_intent_ui(owner, TRUE)
// clickdelay
- clickdelay = new
- clickdelay.hud = src
+ clickdelay = new(null, src)
clickdelay.screen_loc = ui_clickdelay
static_inventory += clickdelay
// resistdelay
- resistdelay = new
- resistdelay.hud = src
+ resistdelay = new(null, src)
resistdelay.screen_loc = ui_resistdelay
static_inventory += resistdelay
- using = new /atom/movable/screen/drop()
+ using = new /atom/movable/screen/drop(null, src)
using.icon = ui_style
using.screen_loc = ui_drop_throw
- using.hud = src
static_inventory += using
- inv_box = new /atom/movable/screen/inventory()
+ inv_box = new /atom/movable/screen/inventory(null, src)
inv_box.name = "uniform"
inv_box.icon = ui_style
inv_box.slot_id = ITEM_SLOT_ICLOTHING
@@ -276,7 +269,7 @@
inv_box.screen_loc = ui_iclothing
toggleable_inventory += inv_box
- inv_box = new /atom/movable/screen/inventory()
+ inv_box = new /atom/movable/screen/inventory(null, src)
inv_box.name = "suit"
inv_box.icon = ui_style
inv_box.slot_id = ITEM_SLOT_OCLOTHING
@@ -287,21 +280,19 @@
build_hand_slots()
- using = new /atom/movable/screen/swap_hand()
+ using = new /atom/movable/screen/swap_hand(null, src)
using.icon = ui_style
using.icon_state = "swap_1"
using.screen_loc = ui_swaphand_position(owner,1)
- using.hud = src
static_inventory += using
- using = new /atom/movable/screen/swap_hand()
+ using = new /atom/movable/screen/swap_hand(null, src)
using.icon = ui_style
using.icon_state = "swap_2"
using.screen_loc = ui_swaphand_position(owner,2)
- using.hud = src
static_inventory += using
- inv_box = new /atom/movable/screen/inventory()
+ inv_box = new /atom/movable/screen/inventory(null, src)
inv_box.name = "id"
inv_box.icon = ui_style
inv_box.icon_state = "id"
@@ -310,7 +301,7 @@
inv_box.slot_id = ITEM_SLOT_ID
static_inventory += inv_box
- inv_box = new /atom/movable/screen/inventory()
+ inv_box = new /atom/movable/screen/inventory(null, src)
inv_box.name = "mask"
inv_box.icon = ui_style
inv_box.icon_state = "mask"
@@ -319,7 +310,7 @@
inv_box.slot_id = ITEM_SLOT_MASK
toggleable_inventory += inv_box
- inv_box = new /atom/movable/screen/inventory()
+ inv_box = new /atom/movable/screen/inventory(null, src)
inv_box.name = "neck"
inv_box.icon = ui_style
inv_box.icon_state = "neck"
@@ -328,7 +319,7 @@
inv_box.slot_id = ITEM_SLOT_NECK
toggleable_inventory += inv_box
- inv_box = new /atom/movable/screen/inventory()
+ inv_box = new /atom/movable/screen/inventory(null, src)
inv_box.name = "back"
inv_box.icon = ui_style
inv_box.icon_state = "back"
@@ -337,7 +328,7 @@
inv_box.slot_id = ITEM_SLOT_BACK
static_inventory += inv_box
- inv_box = new /atom/movable/screen/inventory()
+ inv_box = new /atom/movable/screen/inventory(null, src)
inv_box.name = "left pocket"
inv_box.icon = ui_style
inv_box.icon_state = "pocket"
@@ -346,7 +337,7 @@
inv_box.slot_id = ITEM_SLOT_LPOCKET
static_inventory += inv_box
- inv_box = new /atom/movable/screen/inventory()
+ inv_box = new /atom/movable/screen/inventory(null, src)
inv_box.name = "right pocket"
inv_box.icon = ui_style
inv_box.icon_state = "pocket"
@@ -355,7 +346,7 @@
inv_box.slot_id = ITEM_SLOT_RPOCKET
static_inventory += inv_box
- inv_box = new /atom/movable/screen/inventory()
+ inv_box = new /atom/movable/screen/inventory(null, src)
inv_box.name = "suit storage"
inv_box.icon = ui_style
inv_box.icon_state = "suit_storage"
@@ -364,32 +355,28 @@
inv_box.slot_id = ITEM_SLOT_SUITSTORE
static_inventory += inv_box
- using = new /atom/movable/screen/resist()
+ using = new /atom/movable/screen/resist(null, src)
using.icon = ui_style
using.screen_loc = ui_overridden_resist // CIT CHANGE - changes this to overridden resist
- using.hud = src
hotkeybuttons += using
- rest_icon = new /atom/movable/screen/rest()
+ rest_icon = new /atom/movable/screen/rest(null, src)
rest_icon.icon = ui_style
rest_icon.screen_loc = ui_pull_resist
- rest_icon.hud = src
static_inventory += rest_icon
//END OF CIT CHANGES
- using = new /atom/movable/screen/human/toggle()
+ using = new /atom/movable/screen/human/toggle(null, src)
using.icon = ui_style
using.screen_loc = ui_inventory
- using.hud = src
static_inventory += using
- using = new /atom/movable/screen/human/equip()
+ using = new /atom/movable/screen/human/equip(null, src)
using.icon = ui_style
using.screen_loc = ui_equip_position(mymob)
- using.hud = src
static_inventory += using
- inv_box = new /atom/movable/screen/inventory()
+ inv_box = new /atom/movable/screen/inventory(null, src)
inv_box.name = "gloves"
inv_box.icon = ui_style
inv_box.icon_state = "gloves"
@@ -398,7 +385,7 @@
inv_box.slot_id = ITEM_SLOT_GLOVES
toggleable_inventory += inv_box
- inv_box = new /atom/movable/screen/inventory()
+ inv_box = new /atom/movable/screen/inventory(null, src)
inv_box.name = "eyes"
inv_box.icon = ui_style
inv_box.icon_state = "glasses"
@@ -407,7 +394,7 @@
inv_box.slot_id = ITEM_SLOT_EYES
toggleable_inventory += inv_box
- inv_box = new /atom/movable/screen/inventory()
+ inv_box = new /atom/movable/screen/inventory(null, src)
inv_box.name = "left ear" // Sandstorm edit
inv_box.icon = ui_style
inv_box.icon_state = "ears"
@@ -416,7 +403,7 @@
inv_box.slot_id = ITEM_SLOT_EARS_LEFT // Sandstorm Edit
toggleable_inventory += inv_box
- inv_box = new /atom/movable/screen/inventory()
+ inv_box = new /atom/movable/screen/inventory(null, src)
inv_box.name = "head"
inv_box.icon = ui_style
inv_box.icon_state = "head"
@@ -425,7 +412,7 @@
inv_box.slot_id = ITEM_SLOT_HEAD
toggleable_inventory += inv_box
- inv_box = new /atom/movable/screen/inventory()
+ inv_box = new /atom/movable/screen/inventory(null, src)
inv_box.name = "shoes"
inv_box.icon = ui_style
inv_box.icon_state = "shoes"
@@ -435,13 +422,12 @@
toggleable_inventory += inv_box
// Sandstorm edit
- using = new /atom/movable/screen/human/toggle/extra()
+ using = new /atom/movable/screen/human/toggle/extra(null, src)
using.icon = ui_style_modular(ui_style)
using.screen_loc = ui_inventory_extra
- using.hud = src
toggleable_inventory += using
- inv_box = new /atom/movable/screen/inventory()
+ inv_box = new /atom/movable/screen/inventory(null, src)
inv_box.name = "underwear"
inv_box.icon = ui_style_modular(ui_style)
inv_box.icon_state = "underwear"
@@ -450,7 +436,7 @@
inv_box.slot_id = ITEM_SLOT_UNDERWEAR // Sandstorm edit
extra_inventory += inv_box
- inv_box = new /atom/movable/screen/inventory()
+ inv_box = new /atom/movable/screen/inventory(null, src)
inv_box.name = "socks"
inv_box.icon = ui_style_modular(ui_style)
inv_box.icon_state = "socks"
@@ -459,7 +445,7 @@
inv_box.slot_id = ITEM_SLOT_SOCKS // Sandstorm edit
extra_inventory += inv_box
- inv_box = new /atom/movable/screen/inventory()
+ inv_box = new /atom/movable/screen/inventory(null, src)
inv_box.name = "shirt"
inv_box.icon = ui_style_modular(ui_style)
inv_box.icon_state = "shirt"
@@ -468,7 +454,7 @@
inv_box.slot_id = ITEM_SLOT_SHIRT // Sandstorm edit
extra_inventory += inv_box
- inv_box = new /atom/movable/screen/inventory()
+ inv_box = new /atom/movable/screen/inventory(null, src)
inv_box.name = "right ear"
inv_box.icon = ui_style_modular(ui_style)
inv_box.icon_state = "ears_extra"
@@ -477,7 +463,7 @@
inv_box.slot_id = ITEM_SLOT_EARS_RIGHT // Sandstorm edit
extra_inventory += inv_box
- inv_box = new /atom/movable/screen/inventory()
+ inv_box = new /atom/movable/screen/inventory(null, src)
inv_box.name = "wrists"
inv_box.icon = ui_style_modular(ui_style)
inv_box.icon_state = "wrists"
@@ -487,7 +473,7 @@
extra_inventory += inv_box
//
- inv_box = new /atom/movable/screen/inventory()
+ inv_box = new /atom/movable/screen/inventory(null, src)
inv_box.name = "belt"
inv_box.icon = ui_style
inv_box.icon_state = "belt"
@@ -496,85 +482,68 @@
inv_box.slot_id = ITEM_SLOT_BELT
static_inventory += inv_box
- throw_icon = new /atom/movable/screen/throw_catch()
+ throw_icon = new /atom/movable/screen/throw_catch(null, src)
throw_icon.icon = ui_style
throw_icon.screen_loc = ui_drop_throw
- throw_icon.hud = src
hotkeybuttons += throw_icon
- hunger = new /atom/movable/screen/hunger()
- hunger.hud = src
+ hunger = new /atom/movable/screen/hunger(null, src)
infodisplay += hunger
- thirst = new /atom/movable/screen/thirst()
- thirst.hud = src
+ thirst = new /atom/movable/screen/thirst(null, src)
infodisplay += thirst
- healths = new /atom/movable/screen/healths()
- healths.hud = src
+ healths = new /atom/movable/screen/healths(null, src)
infodisplay += healths
- staminas = new /atom/movable/screen/staminas()
- staminas.hud = src
+ staminas = new /atom/movable/screen/staminas(null, src)
infodisplay += staminas
if(!CONFIG_GET(flag/disable_stambuffer))
- staminabuffer = new /atom/movable/screen/staminabuffer()
- staminabuffer.hud = src
+ staminabuffer = new /atom/movable/screen/staminabuffer(null, src)
infodisplay += staminabuffer
//END OF CIT CHANGES
- healthdoll = new /atom/movable/screen/healthdoll()
- healthdoll.hud = src
+ healthdoll = new /atom/movable/screen/healthdoll(null, src)
infodisplay += healthdoll
- pull_icon = new /atom/movable/screen/pull()
+ pull_icon = new /atom/movable/screen/pull(null, src)
pull_icon.icon = ui_style
- pull_icon.hud = src
pull_icon.update_icon()
pull_icon.screen_loc = ui_pull_resist
static_inventory += pull_icon
- lingchemdisplay = new /atom/movable/screen/ling/chems()
- lingchemdisplay.hud = src
+ lingchemdisplay = new /atom/movable/screen/ling/chems(null, src)
infodisplay += lingchemdisplay
- lingstingdisplay = new /atom/movable/screen/ling/sting()
- lingstingdisplay.hud = src
+ lingstingdisplay = new /atom/movable/screen/ling/sting(null, src)
infodisplay += lingstingdisplay
- devilsouldisplay = new /atom/movable/screen/devil/soul_counter
- devilsouldisplay.hud = src
+ devilsouldisplay = new /atom/movable/screen/devil/soul_counter(null, src)
infodisplay += devilsouldisplay
- blood_display = new /atom/movable/screen/bloodsucker/blood_counter // Blood Volume
- blood_display.hud = src
+ blood_display = new /atom/movable/screen/bloodsucker/blood_counter(null, src) // Blood Volume
infodisplay += blood_display
- vamprank_display = new /atom/movable/screen/bloodsucker/rank_counter // Bloodsucker Rank
- vamprank_display.hud = src
+ vamprank_display = new /atom/movable/screen/bloodsucker/rank_counter(null, src) // Bloodsucker Rank
infodisplay += vamprank_display
- sunlight_display = new /atom/movable/screen/bloodsucker/sunlight_counter // Sunlight
- sunlight_display.hud = src
+ sunlight_display = new /atom/movable/screen/bloodsucker/sunlight_counter(null, src) // Sunlight
infodisplay += sunlight_display
- coolant_display = new /atom/movable/screen/synth/coolant_counter //Coolant & cooling efficiency readouts for Synths.
- coolant_display.hud = src
+ coolant_display = new /atom/movable/screen/synth/coolant_counter(null, src) //Coolant & cooling efficiency readouts for Synths.
infodisplay += coolant_display
- zone_select = new /atom/movable/screen/zone_sel()
+ zone_select = new /atom/movable/screen/zone_sel(null, src)
zone_select.icon = ui_style
- zone_select.hud = src
zone_select.update_icon()
static_inventory += zone_select
- combo_display = new /atom/movable/screen/combo()
+ combo_display = new /atom/movable/screen/combo(null, src)
infodisplay += combo_display
for(var/atom/movable/screen/inventory/inv in (static_inventory + toggleable_inventory + extra_inventory)) // Sandstorm edit
if(inv.slot_id)
- inv.hud = src
inv_slots[TOBITSHIFT(inv.slot_id) + 1] = inv
inv.update_icon()
@@ -595,10 +564,9 @@
// make new ones
// walk/run
- using = new /atom/movable/screen/mov_intent
+ using = new /atom/movable/screen/mov_intent(null, src)
using.icon = tg_ui_icon_to_cit_ui(ui_style) // CIT CHANGE - overrides mov intent icon
using.screen_loc = ui_movi
- using.hud = src
using.update_icon()
static_inventory += using
if(!on_new)
@@ -608,19 +576,17 @@
return
// sprint button
- using = new /atom/movable/screen/sprintbutton
+ using = new /atom/movable/screen/sprintbutton(null, src)
using.icon = tg_ui_icon_to_cit_ui(ui_style)
using.icon_state = ((owner.combat_flags & COMBAT_FLAG_SPRINT_ACTIVE) ? "act_sprint_on" : "act_sprint")
using.screen_loc = ui_movi
- using.hud = src
static_inventory += using
if(!on_new)
owner?.client?.screen += using
// same as above but buffer.
- sprint_buffer = new /atom/movable/screen/sprint_buffer
+ sprint_buffer = new /atom/movable/screen/sprint_buffer(null, src)
sprint_buffer.screen_loc = ui_sprintbufferloc
- sprint_buffer.hud = src
static_inventory += sprint_buffer
if(!on_new)
owner?.client?.screen += using
diff --git a/code/_onclick/hud/lavaland_elite.dm b/code/_onclick/hud/lavaland_elite.dm
index f3ca5fec32..6df374cd10 100644
--- a/code/_onclick/hud/lavaland_elite.dm
+++ b/code/_onclick/hud/lavaland_elite.dm
@@ -4,13 +4,11 @@
/datum/hud/lavaland_elite/New(mob/living/simple_animal/hostile/asteroid/elite)
..()
- pull_icon = new /atom/movable/screen/pull()
+ pull_icon = new /atom/movable/screen/pull(null, src)
pull_icon.icon = ui_style
- pull_icon.hud = src
pull_icon.update_icon()
pull_icon.screen_loc = ui_living_pull
static_inventory += pull_icon
- healths = new /atom/movable/screen/healths/lavaland_elite()
- healths.hud = src
+ healths = new /atom/movable/screen/healths/lavaland_elite(null, src)
infodisplay += healths
diff --git a/code/_onclick/hud/monkey.dm b/code/_onclick/hud/monkey.dm
index 9ee795a745..ddb5662889 100644
--- a/code/_onclick/hud/monkey.dm
+++ b/code/_onclick/hud/monkey.dm
@@ -3,48 +3,42 @@
var/atom/movable/screen/using
var/atom/movable/screen/inventory/inv_box
- action_intent = new /atom/movable/screen/act_intent()
+ action_intent = new /atom/movable/screen/act_intent(null, src)
action_intent.icon = ui_style
action_intent.icon_state = mymob.a_intent
action_intent.screen_loc = ui_acti
- action_intent.hud = src
static_inventory += action_intent
- using = new /atom/movable/screen/mov_intent()
+ using = new /atom/movable/screen/mov_intent(null, src)
using.icon = ui_style
using.icon_state = (mymob.m_intent == MOVE_INTENT_RUN ? "running" : "walking")
using.screen_loc = ui_movi
- using.hud = src
static_inventory += using
- using = new/atom/movable/screen/language_menu
+ using = new/atom/movable/screen/language_menu(null, src)
using.icon = ui_style
- using.hud = src
static_inventory += using
- using = new /atom/movable/screen/drop()
+ using = new /atom/movable/screen/drop(null, src)
using.icon = ui_style
using.screen_loc = ui_drop_throw
- using.hud = src
static_inventory += using
build_hand_slots()
- using = new /atom/movable/screen/swap_hand()
+ using = new /atom/movable/screen/swap_hand(null, src)
using.icon = ui_style
using.icon_state = "swap_1_m" //extra wide!
using.screen_loc = ui_swaphand_position(owner,1)
- using.hud = src
static_inventory += using
- using = new /atom/movable/screen/swap_hand()
+ using = new /atom/movable/screen/swap_hand(null, src)
using.icon = ui_style
using.icon_state = "swap_2"
using.screen_loc = ui_swaphand_position(owner,2)
- using.hud = src
static_inventory += using
- inv_box = new /atom/movable/screen/inventory()
+ inv_box = new /atom/movable/screen/inventory(null, src)
inv_box.name = "mask"
inv_box.icon = ui_style
inv_box.icon_state = "mask"
@@ -53,7 +47,7 @@
inv_box.slot_id = ITEM_SLOT_MASK
static_inventory += inv_box
- inv_box = new /atom/movable/screen/inventory()
+ inv_box = new /atom/movable/screen/inventory(null, src)
inv_box.name = "neck"
inv_box.icon = ui_style
inv_box.icon_state = "neck"
@@ -62,7 +56,7 @@
inv_box.slot_id = ITEM_SLOT_NECK
static_inventory += inv_box
- inv_box = new /atom/movable/screen/inventory()
+ inv_box = new /atom/movable/screen/inventory(null, src)
inv_box.name = "head"
inv_box.icon = ui_style
inv_box.icon_state = "head"
@@ -71,7 +65,7 @@
inv_box.slot_id = ITEM_SLOT_HEAD
static_inventory += inv_box
- inv_box = new /atom/movable/screen/inventory()
+ inv_box = new /atom/movable/screen/inventory(null, src)
inv_box.name = "back"
inv_box.icon = ui_style
inv_box.icon_state = "back"
@@ -79,49 +73,41 @@
inv_box.slot_id = ITEM_SLOT_BACK
static_inventory += inv_box
- throw_icon = new /atom/movable/screen/throw_catch()
+ throw_icon = new /atom/movable/screen/throw_catch(null, src)
throw_icon.icon = ui_style
throw_icon.screen_loc = ui_drop_throw
- throw_icon.hud = src
hotkeybuttons += throw_icon
- healths = new /atom/movable/screen/healths()
- healths.hud = src
+ healths = new /atom/movable/screen/healths(null, src)
infodisplay += healths
- pull_icon = new /atom/movable/screen/pull()
+ pull_icon = new /atom/movable/screen/pull(null, src)
pull_icon.icon = ui_style
pull_icon.screen_loc = ui_pull_resist
- pull_icon.hud = src
pull_icon.update_icon()
static_inventory += pull_icon
- lingchemdisplay = new /atom/movable/screen/ling/chems()
- lingchemdisplay.hud = src
+ lingchemdisplay = new /atom/movable/screen/ling/chems(null, src)
infodisplay += lingchemdisplay
- lingstingdisplay = new /atom/movable/screen/ling/sting()
- lingstingdisplay.hud = src
+ lingstingdisplay = new /atom/movable/screen/ling/sting(null, src)
infodisplay += lingstingdisplay
- zone_select = new /atom/movable/screen/zone_sel()
+ zone_select = new /atom/movable/screen/zone_sel(null, src)
zone_select.icon = ui_style
- zone_select.hud = src
zone_select.update_icon()
static_inventory += zone_select
mymob.client.screen = list()
- using = new /atom/movable/screen/resist()
+ using = new /atom/movable/screen/resist(null, src)
using.icon = ui_style
using.screen_loc = ui_pull_resist
- using.hud = src
hotkeybuttons += using
for(var/atom/movable/screen/inventory/inv in (static_inventory + toggleable_inventory))
if(inv.slot_id)
- inv.hud = src
inv_slots[TOBITSHIFT(inv.slot_id) + 1] = inv
inv.update_icon()
diff --git a/code/_onclick/hud/new_player.dm b/code/_onclick/hud/new_player.dm
index c7f40e4dcc..e58d330eae 100644
--- a/code/_onclick/hud/new_player.dm
+++ b/code/_onclick/hud/new_player.dm
@@ -1,9 +1,12 @@
#define SHUTTER_MOVEMENT_DURATION 0.4 SECONDS
#define SHUTTER_WAIT_DURATION 0.2 SECONDS
+/// Maximum number of station trait buttons we will display, please think hard before creating scenarios where there are more than this
+#define MAX_STATION_TRAIT_BUTTONS_VERTICAL 3
/datum/hud/new_player
///Whether the menu is currently on the client's screen or not
var/menu_hud_status = TRUE
+ var/list/shown_station_trait_buttons
/datum/hud/new_player/New(mob/dead/new_player/owner)
. = ..()
@@ -13,29 +16,89 @@
/datum/hud/new_player/proc/populate_buttons(mob/dead/new_player/owner)
var/list/buttons = subtypesof(/atom/movable/screen/lobby)
- for(var/button_type in buttons)
- var/atom/movable/screen/lobby/lobbyscreen = new button_type(our_hud = src)
+ for (var/atom/movable/screen/lobby/lobbyscreen as anything in buttons)
+ if (!initial(lobbyscreen.always_available))
+ continue
+ lobbyscreen = new lobbyscreen(our_hud = src)
lobbyscreen.SlowInit()
- lobbyscreen.hud = src
static_inventory += lobbyscreen
if(!lobbyscreen.always_shown)
lobbyscreen.RegisterSignal(src, COMSIG_HUD_LOBBY_COLLAPSED, TYPE_PROC_REF(/atom/movable/screen/lobby, collapse_button))
lobbyscreen.RegisterSignal(src, COMSIG_HUD_LOBBY_EXPANDED, TYPE_PROC_REF(/atom/movable/screen/lobby, expand_button))
- if(istype(lobbyscreen, /atom/movable/screen/lobby/button))
- var/atom/movable/screen/lobby/button/lobby_button = lobbyscreen
- lobby_button.owner = REF(owner)
+
+ if(owner.client.is_localhost())
+ var/atom/movable/screen/lobby/button/start_now/start_button = new(our_hud = src)
+ start_button.SlowInit()
+ static_inventory += start_button
+ start_button.RegisterSignal(src, COMSIG_HUD_LOBBY_COLLAPSED, TYPE_PROC_REF(/atom/movable/screen/lobby, collapse_button))
+ start_button.RegisterSignal(src, COMSIG_HUD_LOBBY_EXPANDED, TYPE_PROC_REF(/atom/movable/screen/lobby, expand_button))
+
show_hud(hud_version)
+/// Load and then display the buttons for relevant station traits
+/datum/hud/new_player/proc/show_station_trait_buttons()
+ var/mob/dead/new_player/user = mymob
+ if (!user.age_verify())
+ return
+ for (var/datum/station_trait/trait as anything in GLOB.lobby_station_traits)
+ if (QDELETED(trait) || !trait.can_display_lobby_button(mymob.client))
+ remove_station_trait_button(trait)
+ continue
+ if(LAZYACCESS(shown_station_trait_buttons, trait))
+ continue
+ var/atom/movable/screen/lobby/button/sign_up/sign_up_button = new(our_hud = src)
+ trait.setup_lobby_button(sign_up_button)
+ static_inventory |= sign_up_button
+ LAZYSET(shown_station_trait_buttons, trait, sign_up_button)
+ RegisterSignal(trait, COMSIG_PARENT_QDELETING, PROC_REF(remove_station_trait_button))
+
+ place_station_trait_buttons()
+
+/// Display the buttosn for relevant station traits.
+/datum/hud/new_player/proc/place_station_trait_buttons()
+ if(hud_version != HUD_STYLE_STANDARD || !mymob?.client)
+ return
+
+ var/y_offset = 397
+ var/x_offset = 233
+ var/y_button_offset = 27
+ var/x_button_offset = -27
+ var/iteration = 0
+ for(var/trait in shown_station_trait_buttons)
+ var/atom/movable/screen/lobby/button/sign_up/sign_up_button = shown_station_trait_buttons[trait]
+ iteration++
+ sign_up_button.screen_loc = offset_to_screen_loc(x_offset, y_offset, mymob.client.view)
+ mymob.client.screen |= sign_up_button
+ if (iteration >= MAX_STATION_TRAIT_BUTTONS_VERTICAL)
+ iteration = 0
+ y_offset = 397
+ x_offset += x_button_offset
+ else
+ y_offset += y_button_offset
+
+/// Remove a station trait button, then re-order the rest.
+/datum/hud/new_player/proc/remove_station_trait_button(datum/station_trait/trait)
+ SIGNAL_HANDLER
+ var/atom/movable/screen/lobby/button/sign_up/button = LAZYACCESS(shown_station_trait_buttons, trait)
+ if(!button)
+ return
+ LAZYREMOVE(shown_station_trait_buttons, trait)
+ UnregisterSignal(trait, COMSIG_PARENT_QDELETING)
+ static_inventory -= button
+ qdel(button)
+ place_station_trait_buttons()
+
/atom/movable/screen/lobby
plane = SPLASHSCREEN_PLANE
layer = LOBBY_MENU_LAYER
screen_loc = "TOP,CENTER"
///Whether this HUD element can be hidden from the client's "screen" (moved off-screen) or not
var/always_shown = FALSE
+ /// If true we will create this button every time the HUD is generated
+ var/always_available = TRUE
/atom/movable/screen/lobby/New(loc, datum/hud/our_hud, ...)
- if(our_hud)
- hud = our_hud
+ set_new_hud(our_hud)
return ..()
/// Run sleeping actions after initialize
@@ -67,11 +130,15 @@
VAR_PROTECTED/enabled = TRUE
///Is the button currently being hovered over with the mouse?
var/highlighted = FALSE
- /// The ref of the mob that owns this button. Only the owner can click on it.
- var/owner
+ ///Should this button play the select sound?
+ var/select_sound_play = TRUE
/atom/movable/screen/lobby/button/Click(location, control, params)
- if(owner != REF(usr))
+ if(usr != get_mob())
+ return
+
+ var/mob/dead/new_player/user = usr
+ if(!user.age_verify())
return
. = ..()
@@ -79,11 +146,19 @@
if(!enabled)
return
flick("[base_icon_state]_pressed", src)
+ if(select_sound_play)
+ var/sound/ui_select_sound = sound('sound/misc/menu/ui_select1.ogg')
+ ui_select_sound.frequency = get_rand_frequency_low_range()
+ SEND_SOUND(hud.mymob, ui_select_sound)
update_appearance(UPDATE_ICON)
return TRUE
/atom/movable/screen/lobby/button/MouseEntered(location,control,params)
- if(owner != REF(usr))
+ if(usr != get_mob())
+ return
+
+ var/mob/dead/new_player/user = usr
+ if(!user.age_verify())
return
. = ..()
@@ -91,7 +166,11 @@
update_appearance(UPDATE_ICON)
/atom/movable/screen/lobby/button/MouseExited()
- if(owner != REF(usr))
+ if(usr != get_mob())
+ return
+
+ var/mob/dead/new_player/user = usr
+ if(!user.age_verify())
return
. = ..()
@@ -178,6 +257,7 @@
new_player.ready = PLAYER_NOT_READY
base_icon_state = "not_ready"
update_appearance(UPDATE_ICON)
+ SEND_SIGNAL(hud, COMSIG_HUD_PLAYER_READY_TOGGLE)
///Shown when the game has started
/atom/movable/screen/lobby/button/join
@@ -186,12 +266,13 @@
icon = 'icons/hud/lobby/join.dmi'
icon_state = "" //Default to not visible
base_icon_state = "join_game"
+ enabled = null // set in init
/atom/movable/screen/lobby/button/join/Initialize(mapload)
. = ..()
- set_button_status(FALSE)
switch(SSticker.current_state)
if(GAME_STATE_PREGAME, GAME_STATE_STARTUP)
+ set_button_status(FALSE)
RegisterSignal(SSticker, COMSIG_TICKER_ENTER_SETTING_UP, PROC_REF(show_join_button))
if(GAME_STATE_SETTING_UP)
set_button_status(TRUE)
@@ -250,6 +331,7 @@
icon = 'icons/hud/lobby/observe.dmi'
icon_state = "observe_disabled"
base_icon_state = "observe"
+ enabled = null // set in init
/atom/movable/screen/lobby/button/observe/Initialize(mapload)
. = ..()
@@ -378,6 +460,23 @@
var/mob/dead/new_player/new_player = hud.mymob
new_player.handle_player_polling()
+/// A generic "sign up" button used by station traits
+/atom/movable/screen/lobby/button/sign_up
+ icon = 'icons/hud/lobby/signup_button.dmi'
+ icon_state = "signup"
+ base_icon_state = "signup"
+ always_available = FALSE
+
+/atom/movable/screen/lobby/button/sign_up/MouseEntered(location, control, params)
+ . = ..()
+ if(QDELETED(src) || !desc)
+ return
+ openToolTip(usr, tip_src = src, params = params, title = name, content = desc,)
+
+/atom/movable/screen/lobby/button/sign_up/MouseExited()
+ . = ..()
+ closeToolTip(usr)
+
/atom/movable/screen/lobby/button/collapse
name = "Collapse Lobby Menu"
icon = 'icons/hud/lobby/collapse_expand.dmi'
@@ -387,6 +486,27 @@
screen_loc = "TOP:-82,CENTER:-54"
always_shown = TRUE
+ var/blip_enabled = TRUE
+
+/atom/movable/screen/lobby/button/collapse/Initialize(mapload, datum/hud/hud_owner)
+ . = ..()
+ switch(SSticker.current_state)
+ if(GAME_STATE_PREGAME, GAME_STATE_STARTUP)
+ RegisterSignal(SSticker, COMSIG_TICKER_ENTER_SETTING_UP, PROC_REF(disable_blip))
+ RegisterSignal(hud, COMSIG_HUD_PLAYER_READY_TOGGLE, PROC_REF(on_player_ready_toggle))
+ if(GAME_STATE_SETTING_UP)
+ blip_enabled = FALSE
+ RegisterSignal(SSticker, COMSIG_TICKER_ERROR_SETTING_UP, PROC_REF(enable_blip))
+ else
+ blip_enabled = FALSE
+
+ add_overlay(get_blip_overlay())
+ update_icon(UPDATE_OVERLAYS)
+
+/atom/movable/screen/lobby/button/collapse/update_overlays()
+ . = ..()
+ . += get_blip_overlay()
+
/atom/movable/screen/lobby/button/collapse/Click(location, control, params)
. = ..()
if(!.)
@@ -416,6 +536,38 @@
sleep(2 * SHUTTER_MOVEMENT_DURATION + SHUTTER_WAIT_DURATION)
set_button_status(TRUE)
+///Proc to update the ready blip state upon new player's ready status change
+/atom/movable/screen/lobby/button/collapse/proc/on_player_ready_toggle()
+ SIGNAL_HANDLER
+ update_appearance(UPDATE_ICON)
+
+///Returns a ready blip overlay depending on the player's ready state
+/atom/movable/screen/lobby/button/collapse/proc/get_blip_overlay()
+ var/blip_icon_state = "ready_blip"
+ if(blip_enabled && hud)
+ var/mob/dead/new_player/new_player = hud.mymob
+ blip_icon_state += "_[new_player.ready ? "" : "not_"]ready"
+ else
+ blip_icon_state += "_disabled"
+ var/mutable_appearance/ready_blip = mutable_appearance(icon, blip_icon_state)
+ return ready_blip
+
+///Disables the ready blip; makes us listen for the setup error to re-enable the blip
+/atom/movable/screen/lobby/button/collapse/proc/disable_blip()
+ SIGNAL_HANDLER
+ blip_enabled = FALSE
+ UnregisterSignal(SSticker, COMSIG_TICKER_ENTER_SETTING_UP)
+ RegisterSignal(SSticker, COMSIG_TICKER_ERROR_SETTING_UP, PROC_REF(enable_blip))
+ update_appearance(UPDATE_ICON)
+
+///Enables the ready blip; makes us listen for the setup completion and game start to disable the blip
+/atom/movable/screen/lobby/button/collapse/proc/enable_blip()
+ SIGNAL_HANDLER
+ blip_enabled = TRUE
+ UnregisterSignal(SSticker, COMSIG_TICKER_ERROR_SETTING_UP)
+ RegisterSignal(SSticker, COMSIG_TICKER_ENTER_SETTING_UP, PROC_REF(disable_blip))
+ update_appearance(UPDATE_ICON)
+
///Moves the button to the top of the screen, leaving only the screen part in view
///Sends a signal on the hud for the menu hud elements to listen to
/atom/movable/screen/lobby/button/collapse/proc/collapse_menu()
@@ -424,12 +576,14 @@
animate(src, transform = transform, time = SHUTTER_MOVEMENT_DURATION + SHUTTER_WAIT_DURATION)
//then pull the button up with the shutter and leave it on the edge of the screen
animate(transform = transform.Translate(x = 0, y = 134), time = SHUTTER_MOVEMENT_DURATION, easing = CUBIC_EASING|EASE_IN)
+ SEND_SOUND(hud.mymob, sound('sound/misc/menu/menu_rollup1.ogg'))
///Extends the button back to its usual spot
///Sends a signal on the hud for the menu hud elements to listen to
/atom/movable/screen/lobby/button/collapse/proc/expand_menu()
SEND_SIGNAL(hud, COMSIG_HUD_LOBBY_EXPANDED)
animate(src, transform = matrix(), time = SHUTTER_MOVEMENT_DURATION, easing = CUBIC_EASING|EASE_OUT)
+ SEND_SOUND(hud.mymob, sound('sound/misc/menu/menu_rolldown1.ogg'))
/atom/movable/screen/lobby/shutter
icon = 'icons/hud/lobby/shutter.dmi'
@@ -450,5 +604,22 @@
//pull the shutter back off-screen
animate(transform = matrix(), time = SHUTTER_MOVEMENT_DURATION, easing = CUBIC_EASING|EASE_IN)
+/// LOCALHOST ONLY - Start Now button
+/atom/movable/screen/lobby/button/start_now
+ name = "Start Now (LOCALHOST ONLY)"
+ screen_loc = "TOP:-146,CENTER:-54"
+ icon = 'icons/hud/lobby/start_now.dmi'
+ icon_state = "start_now"
+ base_icon_state = "start_now"
+ always_available = FALSE
+ select_sound_play = FALSE
+
+/atom/movable/screen/lobby/button/start_now/Click(location, control, params)
+ . = ..()
+ if(!. || !usr.client.is_localhost() || !check_rights_for(usr.client, R_SERVER))
+ return
+ SEND_SOUND(hud.mymob, sound('sound/effects/splat.ogg', volume = 50))
+ SSticker.start_immediately = TRUE
+
#undef SHUTTER_MOVEMENT_DURATION
#undef SHUTTER_WAIT_DURATION
diff --git a/code/_onclick/hud/plane_master_controller.dm b/code/_onclick/hud/plane_master_controller.dm
index e27bd3bc55..c2ec1417b2 100644
--- a/code/_onclick/hud/plane_master_controller.dm
+++ b/code/_onclick/hud/plane_master_controller.dm
@@ -5,8 +5,11 @@
///hud that owns this controller
var/datum/hud/owner_hud
+
+INITIALIZE_IMMEDIATE(/atom/movable/plane_master_controller)
+
///Ensures that all the planes are correctly in the controlled_planes list.
-/atom/movable/plane_master_controller/New(hud)
+/atom/movable/plane_master_controller/Initialize(mapload, datum/hud/hud)
. = ..()
owner_hud = hud
var/assoc_controlled_planes = list()
diff --git a/code/_onclick/hud/radial_persistent.dm b/code/_onclick/hud/radial_persistent.dm
index e7f7c664ad..b5fa494c94 100644
--- a/code/_onclick/hud/radial_persistent.dm
+++ b/code/_onclick/hud/radial_persistent.dm
@@ -7,8 +7,8 @@
icon_state = "radial_center"
/atom/movable/screen/radial/persistent/center/Click(location, control, params)
- if(usr.client == parent.current_user)
- parent.element_chosen(null,usr)
+ if(usr == get_mob())
+ parent.element_chosen(null, usr)
/atom/movable/screen/radial/persistent/center/MouseEntered(location, control, params)
. = ..()
diff --git a/code/_onclick/hud/revenanthud.dm b/code/_onclick/hud/revenanthud.dm
index 708b1d4915..a98ef60a1a 100644
--- a/code/_onclick/hud/revenanthud.dm
+++ b/code/_onclick/hud/revenanthud.dm
@@ -2,6 +2,5 @@
/datum/hud/revenant/New(mob/owner)
..()
- healths = new /atom/movable/screen/healths/revenant()
- healths.hud = src
+ healths = new /atom/movable/screen/healths/revenant(null, src)
infodisplay += healths
diff --git a/code/_onclick/hud/robot.dm b/code/_onclick/hud/robot.dm
index 58b52dea49..54987d541e 100644
--- a/code/_onclick/hud/robot.dm
+++ b/code/_onclick/hud/robot.dm
@@ -78,64 +78,56 @@
var/mob/living/silicon/robot/robit = mymob
var/atom/movable/screen/using
- using = new/atom/movable/screen/language_menu
+ using = new/atom/movable/screen/language_menu(null, src)
using.screen_loc = ui_borg_language_menu
static_inventory += using
//Radio
- using = new /atom/movable/screen/robot/radio()
+ using = new /atom/movable/screen/robot/radio(null, src)
using.screen_loc = ui_borg_radio
- using.hud = src
static_inventory += using
//Module select
if(!robit.inv1)
- robit.inv1 = new /atom/movable/screen/robot/module1()
+ robit.inv1 = new /atom/movable/screen/robot/module1(null, src)
robit.inv1.screen_loc = ui_inv1
- robit.inv1.hud = src
static_inventory += robit.inv1
if(!robit.inv2)
- robit.inv2 = new /atom/movable/screen/robot/module2()
+ robit.inv2 = new /atom/movable/screen/robot/module2(null, src)
robit.inv2.screen_loc = ui_inv2
- robit.inv2.hud = src
static_inventory += robit.inv2
if(!robit.inv3)
- robit.inv3 = new /atom/movable/screen/robot/module3()
+ robit.inv3 = new /atom/movable/screen/robot/module3(null, src)
robit.inv3.screen_loc = ui_inv3
- robit.inv3.hud = src
static_inventory += robit.inv3
//End of module select
- using = new /atom/movable/screen/robot/lamp()
+ using = new /atom/movable/screen/robot/lamp(null, src)
using.screen_loc = ui_borg_lamp
- using.hud = src
static_inventory += using
robit.lampButton = using
var/atom/movable/screen/robot/lamp/lampscreen = using
lampscreen.robot = robit
//Photography stuff
- using = new /atom/movable/screen/ai/image_take()
+ using = new /atom/movable/screen/ai/image_take(null, src)
using.screen_loc = ui_borg_camera
- using.hud = src
static_inventory += using
//Sec/Med HUDs
- using = new /atom/movable/screen/robot/sensors()
+ using = new /atom/movable/screen/robot/sensors(null, src)
using.screen_loc = ui_borg_sensor
- using.hud = src
static_inventory += using
//Borg Integrated Tablet
- using = new /atom/movable/screen/robot/modPC()
+ using = new /atom/movable/screen/robot/modPC(null, src)
using.screen_loc = ui_borg_tablet
- using.hud = src
static_inventory += using
robit.interfaceButton = using
if(robit.modularInterface)
@@ -144,64 +136,54 @@
tabletbutton.robot = robit
//Alerts
- using = new /atom/movable/screen/robot/alerts()
+ using = new /atom/movable/screen/robot/alerts(null, src)
using.screen_loc = ui_borg_alerts
- using.hud = src
static_inventory += using
//Thrusters
- using = new /atom/movable/screen/robot/thrusters()
+ using = new /atom/movable/screen/robot/thrusters(null, src)
using.screen_loc = ui_borg_thrusters
- using.hud = src
static_inventory += using
robit.thruster_button = using
//PDA message
- using = new /atom/movable/screen/robot/pda_msg_send
+ using = new /atom/movable/screen/robot/pda_msg_send(null, src)
using.screen_loc = ui_borg_pda_send
- using.hud = src
static_inventory += using
//PDA log
- using = new /atom/movable/screen/robot/pda_msg_show
+ using = new /atom/movable/screen/robot/pda_msg_show(null, src)
using.screen_loc = ui_borg_pda_log
- using.hud = src
static_inventory += using
//Intent
- action_intent = new /atom/movable/screen/act_intent/robot()
+ action_intent = new /atom/movable/screen/act_intent/robot(null, src)
action_intent.icon_state = mymob.a_intent
- action_intent.hud = src
static_inventory += action_intent
assert_move_intent_ui(owner, TRUE)
//Health
- healths = new /atom/movable/screen/healths/robot()
- healths.hud = src
+ healths = new /atom/movable/screen/healths/robot(null, src)
infodisplay += healths
//Installed Module
- robit.hands = new /atom/movable/screen/robot/module()
+ robit.hands = new /atom/movable/screen/robot/module(null, src)
robit.hands.screen_loc = ui_borg_module
- robit.hands.hud = src
static_inventory += robit.hands
//Store
- module_store_icon = new /atom/movable/screen/robot/store()
+ module_store_icon = new /atom/movable/screen/robot/store(null, src)
module_store_icon.screen_loc = ui_borg_store
- module_store_icon.hud = src
- pull_icon = new /atom/movable/screen/pull()
+ pull_icon = new /atom/movable/screen/pull(null, src)
pull_icon.icon = 'icons/mob/screen_cyborg.dmi'
pull_icon.screen_loc = ui_borg_pull
- pull_icon.hud = src
pull_icon.update_icon()
hotkeybuttons += pull_icon
- zone_select = new /atom/movable/screen/zone_sel/robot()
- zone_select.hud = src
+ zone_select = new /atom/movable/screen/zone_sel/robot(null, src)
zone_select.update_icon()
static_inventory += zone_select
@@ -222,7 +204,6 @@
using = new /atom/movable/screen/mov_intent
using.icon = 'modular_citadel/icons/ui/screen_cyborg.dmi'
using.screen_loc = ui_borg_movi
- using.hud = src
using.update_icon()
static_inventory += using
if(!on_new)
@@ -236,7 +217,6 @@
using.icon = 'modular_citadel/icons/ui/screen_cyborg.dmi'
using.icon_state = owner.cansprint ? ((owner.combat_flags & COMBAT_FLAG_SPRINT_ACTIVE) ? "act_sprint_on" : "act_sprint") : "act_sprint_locked"
using.screen_loc = ui_borg_movi
- using.hud = src
static_inventory += using
if(!on_new)
owner?.client?.screen += using
diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm
index 8e3dd1ccce..27d846f8fb 100644
--- a/code/_onclick/hud/screen_objects.dm
+++ b/code/_onclick/hud/screen_objects.dm
@@ -17,7 +17,7 @@
/// A reference to the object in the slot. Grabs or items, generally.
var/obj/master = null
/// A reference to the owner HUD, if any.
- var/datum/hud/hud = null
+ VAR_PRIVATE/datum/hud/hud = null
/**
* Map name assigned to this object.
* Automatically set by /client/proc/add_obj_to_map.
@@ -31,12 +31,36 @@
* But for now, this works.
*/
var/del_on_map_removal = TRUE
+ /// If FALSE, this will not be cleared when calling /client/clear_screen()
+ // var/clear_with_screen = TRUE // Unimplemented
+ /// If TRUE, clicking the screen element will fall through and perform a default "Click" call
+ /// Obviously this requires your Click override, if any, to call parent on their own.
+ /// This is set to FALSE to default to dissade you from doing this.
+ /// Generally we don't want default Click stuff, which results in bugs like using Telekinesis on a screen element
+ /// or trying to point your gun at your screen.
+ var/default_click = FALSE
+
+/atom/movable/screen/Initialize(mapload, datum/hud/hud_owner)
+ . = ..()
+ if(isnull(hud_owner)) //some screens set their hud owners on /new, this prevents overriding them with null post atoms init
+ return
+ set_new_hud(hud_owner)
/atom/movable/screen/Destroy()
master = null
hud = null
return ..()
+/atom/movable/screen/Click(location, control, params)
+ if(flags_1 & INITIALIZED_1)
+ SEND_SIGNAL(src, COMSIG_SCREEN_ELEMENT_CLICK, location, control, params, usr)
+ if(default_click)
+ return ..()
+
+///Screen elements are always on top of the players screen and don't move so yes they are adjacent
+/atom/movable/screen/Adjacent(atom/neighbor, atom/target, atom/movable/mover)
+ return TRUE
+
/atom/movable/screen/examine(mob/user)
return list()
@@ -46,6 +70,25 @@
/atom/movable/screen/proc/component_click(atom/movable/screen/component_button/component, params)
return
+///setter used to set our new hud
+/atom/movable/screen/proc/set_new_hud(datum/hud/hud_owner)
+ if(hud)
+ UnregisterSignal(hud, COMSIG_PARENT_QDELETING)
+ if(isnull(hud_owner))
+ hud = null
+ return
+ hud = hud_owner
+ RegisterSignal(hud, COMSIG_PARENT_QDELETING, PROC_REF(on_hud_delete))
+
+/// Returns the mob this is being displayed to, if any
+/atom/movable/screen/proc/get_mob()
+ return hud?.mymob
+
+/atom/movable/screen/proc/on_hud_delete(datum/source)
+ SIGNAL_HANDLER
+
+ set_new_hud(hud_owner = null)
+
/atom/movable/screen/text
icon = null
icon_state = null
@@ -112,7 +155,6 @@
mouse_over_pointer = MOUSE_HAND_POINTER
/atom/movable/screen/language_menu/Click()
-
usr.get_language_holder().open_language_menu(usr)
/atom/movable/screen/inventory
@@ -614,7 +656,9 @@
plane = SPLASHSCREEN_PLANE
var/client/holder
-/atom/movable/screen/splash/New(client/C, visible, use_previous_title) //TODO: Make this use INITIALIZE_IMMEDIATE, except its not easy
+INITIALIZE_IMMEDIATE(/atom/movable/screen/splash)
+
+/atom/movable/screen/splash/Initialize(mapload, datum/hud/hud_owner, client/C, visible, use_previous_title)
. = ..()
if(!istype(C))
return
@@ -629,8 +673,7 @@
icon = SStitle.icon
else
if(!SStitle.previous_icon)
- qdel(src)
- return
+ return INITIALIZE_HINT_QDEL
icon = SStitle.previous_icon
holder.screen += src
diff --git a/code/_onclick/hud/simple_animal.dm b/code/_onclick/hud/simple_animal.dm
index 2f7902c965..3549bc38fb 100644
--- a/code/_onclick/hud/simple_animal.dm
+++ b/code/_onclick/hud/simple_animal.dm
@@ -1,15 +1,14 @@
/datum/hud/living/simple_animal
ui_style = 'icons/mob/screen_gen.dmi'
+
/datum/hud/living/simple_animal/New(mob/living/owner)
..()
- pull_icon = new /atom/movable/screen/pull()
+ pull_icon = new /atom/movable/screen/pull(null, src)
pull_icon.icon = ui_style
pull_icon.update_icon()
pull_icon.screen_loc = ui_living_pull
- pull_icon.hud = src
static_inventory += pull_icon
//mob health doll! assumes whatever sprite the mob is
- healthdoll = new /atom/movable/screen/healthdoll/living()
- healthdoll.hud = src
+ healthdoll = new /atom/movable/screen/healthdoll/living(null, src)
infodisplay += healthdoll
diff --git a/code/_onclick/hud/swarmer.dm b/code/_onclick/hud/swarmer.dm
index 6aba23fab5..ca0cbc458a 100644
--- a/code/_onclick/hud/swarmer.dm
+++ b/code/_onclick/hud/swarmer.dm
@@ -67,32 +67,26 @@
..()
var/atom/movable/screen/using
- using = new /atom/movable/screen/swarmer/FabricateTrap()
+ using = new /atom/movable/screen/swarmer/FabricateTrap(null, src)
using.screen_loc = ui_hand_position(2)
- using.hud = src
static_inventory += using
- using = new /atom/movable/screen/swarmer/Barricade()
+ using = new /atom/movable/screen/swarmer/Barricade(null, src)
using.screen_loc = ui_hand_position(1)
- using.hud = src
static_inventory += using
- using = new /atom/movable/screen/swarmer/Replicate()
+ using = new /atom/movable/screen/swarmer/Replicate(null, src)
using.screen_loc = ui_zonesel
- using.hud = src
static_inventory += using
- using = new /atom/movable/screen/swarmer/RepairSelf()
+ using = new /atom/movable/screen/swarmer/RepairSelf(null, src)
using.screen_loc = ui_storage1
- using.hud = src
static_inventory += using
- using = new /atom/movable/screen/swarmer/ToggleLight()
+ using = new /atom/movable/screen/swarmer/ToggleLight(null, src)
using.screen_loc = ui_back
- using.hud = src
static_inventory += using
- using = new /atom/movable/screen/swarmer/ContactSwarmers()
+ using = new /atom/movable/screen/swarmer/ContactSwarmers(null, src)
using.screen_loc = ui_inventory
- using.hud = src
static_inventory += using
diff --git a/code/controllers/subsystem/processing/station.dm b/code/controllers/subsystem/processing/station.dm
index f812ea8c4a..c4cdfb11b4 100644
--- a/code/controllers/subsystem/processing/station.dm
+++ b/code/controllers/subsystem/processing/station.dm
@@ -77,8 +77,17 @@ PROCESSING_SUBSYSTEM_DEF(station)
var/datum/station_trait/trait_instance = new trait_type()
can_fire = can_fire || trait_instance.trait_processes
station_traits += trait_instance
+ log_game("Station Trait: [trait_instance.name] chosen for this round.")
if(!trait_instance.blacklist)
return
for(var/i in trait_instance.blacklist)
var/datum/station_trait/trait_to_remove = i
selectable_traits_by_types[initial(trait_to_remove.trait_type)] -= trait_to_remove
+
+/// Update station trait lobby buttons for clients who joined before we initialised this subsystem
+/datum/controller/subsystem/processing/station/proc/display_lobby_traits()
+ for (var/mob/dead/new_player/player as anything in GLOB.new_player_list)
+ var/datum/hud/new_player/observer_hud = player.hud_used
+ if (!istype(observer_hud))
+ continue
+ observer_hud.show_station_trait_buttons()
diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm
index c87f0739da..597288af3a 100755
--- a/code/controllers/subsystem/ticker.dm
+++ b/code/controllers/subsystem/ticker.dm
@@ -161,7 +161,7 @@ SUBSYSTEM_DEF(ticker)
start_at = world.time + (CONFIG_GET(number/lobby_countdown) * 10)
for(var/client/C in GLOB.clients)
window_flash(C, ignorepref = TRUE) //let them know lobby has opened up.
- to_chat(world, "Welcome to [station_name()]!")
+ to_chat(world, span_boldnotice("Welcome to [station_name()]!"))
send2chat(new /datum/tgs_message_content("New round starting on [SSmapping.config.map_name]!"), CONFIG_GET(string/chat_announce_new_game))
current_state = GAME_STATE_PREGAME
SEND_SIGNAL(src, COMSIG_TICKER_ENTER_PREGAME)
@@ -430,7 +430,7 @@ SUBSYSTEM_DEF(ticker)
if (living.client.prefs && living.client.prefs.auto_ooc)
if (living.client.prefs.chat_toggles & CHAT_OOC)
living.client.prefs.chat_toggles ^= CHAT_OOC
- var/atom/movable/screen/splash/S = new(living.client, TRUE)
+ var/atom/movable/screen/splash/S = new(null, living.client, TRUE)
S.Fade(TRUE)
living.client.init_verbs()
livings += living
diff --git a/code/controllers/subsystem/title.dm b/code/controllers/subsystem/title.dm
index 1dbfb1540c..f307139406 100644
--- a/code/controllers/subsystem/title.dm
+++ b/code/controllers/subsystem/title.dm
@@ -60,7 +60,7 @@ SUBSYSTEM_DEF(title)
for(var/thing in GLOB.clients)
if(!thing)
continue
- var/atom/movable/screen/splash/S = new(thing, FALSE)
+ var/atom/movable/screen/splash/S = new(null, thing, FALSE)
S.Fade(FALSE,FALSE)
/datum/controller/subsystem/title/Recover()
diff --git a/code/datums/action.dm b/code/datums/action.dm
index e1e84c8f51..77d6b78917 100644
--- a/code/datums/action.dm
+++ b/code/datums/action.dm
@@ -948,20 +948,6 @@
icon_icon = 'icons/mob/actions/actions_items.dmi'
button_icon_state = "jetboot"
-/datum/action/language_menu
- name = "Language Menu"
- desc = "Open the language menu to review your languages, their keys, and select your default language."
- button_icon_state = "language_menu"
- check_flags = 0
-
-/datum/action/language_menu/Trigger()
- if(!..())
- return FALSE
- if(ismob(owner))
- var/mob/M = owner
- var/datum/language_holder/H = M.get_language_holder()
- H.open_language_menu(usr)
-
/datum/action/item_action/wheelys
name = "Toggle Wheely-Heel's Wheels"
desc = "Pops out or in your wheely-heel's wheels."
diff --git a/code/datums/brain_damage/severe.dm b/code/datums/brain_damage/severe.dm
index 71c9656a88..37a1aa12e5 100644
--- a/code/datums/brain_damage/severe.dm
+++ b/code/datums/brain_damage/severe.dm
@@ -28,13 +28,13 @@
lose_text = "You suddenly remember how languages work."
/datum/brain_trauma/severe/aphasia/on_gain()
- owner.add_blocked_language(subtypesof(/datum/language/) - /datum/language/aphasia, LANGUAGE_APHASIA)
- owner.grant_language(/datum/language/aphasia, TRUE, TRUE, LANGUAGE_APHASIA)
+ owner.add_blocked_language(subtypesof(/datum/language) - /datum/language/aphasia, LANGUAGE_APHASIA)
+ owner.grant_language(/datum/language/aphasia, source = LANGUAGE_APHASIA)
..()
/datum/brain_trauma/severe/aphasia/on_lose()
- owner.remove_blocked_language(subtypesof(/datum/language/), LANGUAGE_APHASIA)
- owner.remove_language(/datum/language/aphasia, TRUE, TRUE, LANGUAGE_APHASIA)
+ owner.remove_blocked_language(subtypesof(/datum/language), LANGUAGE_APHASIA)
+ owner.remove_language(/datum/language/aphasia, LANGUAGE_APHASIA)
..()
/datum/brain_trauma/severe/blindness
diff --git a/code/datums/components/combat_mode.dm b/code/datums/components/combat_mode.dm
index 722a1e936d..b90bb571a1 100644
--- a/code/datums/components/combat_mode.dm
+++ b/code/datums/components/combat_mode.dm
@@ -40,8 +40,7 @@
/// Creates the hud screen object.
/datum/component/combat_mode/proc/on_mob_hud_created(mob/source)
- hud_icon = new
- hud_icon.hud = source.hud_used
+ hud_icon = new(null, source.hud_used)
hud_icon.icon = tg_ui_icon_to_cit_ui(source.hud_used.ui_style)
hud_icon.screen_loc = hud_loc
source.hud_used.static_inventory += hud_icon
diff --git a/code/datums/components/crafting/crafting.dm b/code/datums/components/crafting/crafting.dm
index d32caeaea9..99ad2b4ede 100644
--- a/code/datums/components/crafting/crafting.dm
+++ b/code/datums/components/crafting/crafting.dm
@@ -4,11 +4,11 @@
/datum/component/personal_crafting/proc/create_mob_button(mob/user)
var/datum/hud/H = user.hud_used
- var/atom/movable/screen/craft/C = new()
+ var/atom/movable/screen/craft/C = new(null, H)
C.icon = H.ui_style
H.static_inventory += C
user.client.screen += C
- RegisterSignal(C, COMSIG_CLICK, PROC_REF(component_ui_interact))
+ RegisterSignal(C, COMSIG_SCREEN_ELEMENT_CLICK, PROC_REF(component_ui_interact))
/datum/component/personal_crafting
var/busy
diff --git a/code/datums/components/mood.dm b/code/datums/components/mood.dm
index 351388d1b9..ddff797695 100644
--- a/code/datums/components/mood.dm
+++ b/code/datums/components/mood.dm
@@ -299,12 +299,12 @@
/datum/component/mood/proc/modify_hud(datum/source)
var/mob/living/owner = parent
var/datum/hud/hud = owner.hud_used
- screen_obj = new
- screen_obj_sanity = new // Sandstorm sanity
+ screen_obj = new(null, hud)
+ screen_obj_sanity = new(null, hud)
hud.infodisplay += screen_obj
hud.infodisplay += screen_obj_sanity // Sandstorm sanity
RegisterSignal(hud, COMSIG_PARENT_QDELETING, PROC_REF(unmodify_hud))
- RegisterSignal(screen_obj, COMSIG_CLICK, PROC_REF(hud_click))
+ RegisterSignal(screen_obj, COMSIG_SCREEN_ELEMENT_CLICK, PROC_REF(hud_click))
/datum/component/mood/proc/unmodify_hud(datum/source)
if(!screen_obj || !parent)
diff --git a/code/datums/diseases/advance/symptoms/voice_change.dm b/code/datums/diseases/advance/symptoms/voice_change.dm
index 9fa6ed5cc8..6cf3847ddc 100644
--- a/code/datums/diseases/advance/symptoms/voice_change.dm
+++ b/code/datums/diseases/advance/symptoms/voice_change.dm
@@ -63,7 +63,7 @@ Bonus
if(scramble_language && !current_language) // Last part prevents rerolling language with small amounts of cure.
current_language = pick(subtypesof(/datum/language) - /datum/language/common)
H.add_blocked_language(subtypesof(/datum/language) - current_language, LANGUAGE_VOICECHANGE)
- H.grant_language(current_language, TRUE, TRUE, LANGUAGE_VOICECHANGE)
+ H.grant_language(current_language, source = LANGUAGE_VOICECHANGE)
/datum/symptom/voice_change/End(datum/disease/advance/A)
..()
diff --git a/code/datums/dna.dm b/code/datums/dna.dm
index b10cd46ea7..d1c03eb39e 100644
--- a/code/datums/dna.dm
+++ b/code/datums/dna.dm
@@ -403,7 +403,6 @@
qdel(language_holder)
var/species_holder = initial(mrace.species_language_holder)
language_holder = new species_holder(src)
- update_atom_languages()
/mob/living/carbon/human/set_species(datum/species/mrace, icon_update = TRUE, pref_load = FALSE)
..()
diff --git a/code/datums/mind.dm b/code/datums/mind.dm
index d562ed2194..0f96e2c781 100644
--- a/code/datums/mind.dm
+++ b/code/datums/mind.dm
@@ -64,7 +64,6 @@
var/isholy = FALSE //is this person a chaplain or admin role allowed to use bibles
var/mob/living/enslaved_to //If this mind's master is another mob (i.e. adamantine golems)
- var/datum/language_holder/language_holder
var/unconvertable = FALSE
var/late_joiner = FALSE
///has this mind ever been an AI
@@ -97,7 +96,6 @@
/datum/mind/Destroy()
SSticker.minds -= src
QDEL_LIST(antag_datums)
- QDEL_NULL(language_holder)
QDEL_NULL(skill_holder)
set_current(null)
soulOwner = null
@@ -119,12 +117,6 @@
/datum/mind/proc/set_original_character(new_original_character)
original_character = WEAKREF(new_original_character)
-/datum/mind/proc/get_language_holder()
- if(!language_holder)
- language_holder = new (src)
-
- return language_holder
-
/datum/mind/proc/transfer_to(mob/new_character, var/force_key_move = 0)
var/old_character = current
var/signals = SEND_SIGNAL(new_character, COMSIG_MOB_PRE_PLAYER_CHANGE, new_character, old_character) | SEND_SIGNAL(src, COMSIG_PRE_MIND_TRANSFER, new_character, old_character)
@@ -146,7 +138,19 @@
var/datum/atom_hud/antag/hud_to_transfer = antag_hud//we need this because leave_hud() will clear this list
var/mob/living/old_current = current
if(current)
- current.transfer_observers_to(new_character) //transfer anyone observing the old character to the new one
+ //transfer anyone observing the old character to the new one
+ current.transfer_observers_to(new_character)
+
+ // Offload all mind languages from the old holder to a temp one
+ var/datum/language_holder/empty/temp_holder = new()
+ var/datum/language_holder/old_holder = old_current.get_language_holder()
+ var/datum/language_holder/new_holder = new_character.get_language_holder()
+ // Off load mind languages to the temp holder momentarily
+ new_holder.transfer_mind_languages(temp_holder)
+ // Transfer the old holder's mind languages to the new holder
+ old_holder.transfer_mind_languages(new_holder)
+ // And finally transfer the temp holder's mind languages back to the old holder
+ temp_holder.transfer_mind_languages(old_holder)
set_current(new_character) //associate ourself with our new body
new_character.mind = src //and associate our new body with ourself
for(var/a in antag_datums) //Makes sure all antag datums effects are applied in the new body
@@ -163,7 +167,6 @@
if(new_character.client)
LAZYCLEARLIST(new_character.client.recent_examines)
new_character.client.init_verbs() // re-initialize character specific verbs
- current.update_atom_languages()
//CIT CHANGE - makes arousal update when transfering bodies
if(isliving(new_character)) //New humans and such are by default enabled arousal. Let's always use the new mind's prefs.
diff --git a/code/datums/mutations/speech.dm b/code/datums/mutations/speech.dm
index 0eeb387a77..4559f39b00 100644
--- a/code/datums/mutations/speech.dm
+++ b/code/datums/mutations/speech.dm
@@ -277,10 +277,10 @@
/datum/mutation/human/stoner/on_acquiring(mob/living/carbon/human/owner)
..()
- owner.grant_language(/datum/language/beachbum, TRUE, TRUE, LANGUAGE_STONER)
+ owner.grant_language(/datum/language/beachbum, source = LANGUAGE_STONER)
owner.add_blocked_language(subtypesof(/datum/language) - /datum/language/beachbum, LANGUAGE_STONER)
/datum/mutation/human/stoner/on_losing(mob/living/carbon/human/owner)
..()
- owner.remove_language(/datum/language/beachbum, TRUE, TRUE, LANGUAGE_STONER)
+ owner.remove_language(/datum/language/beachbum, source = LANGUAGE_STONER)
owner.remove_blocked_language(subtypesof(/datum/language) - /datum/language/beachbum, LANGUAGE_STONER)
diff --git a/code/datums/station_traits/_station_trait.dm b/code/datums/station_traits/_station_trait.dm
index cb0de6afd4..6c7abcd7bf 100644
--- a/code/datums/station_traits/_station_trait.dm
+++ b/code/datums/station_traits/_station_trait.dm
@@ -1,3 +1,6 @@
+/// Station traits displayed in the lobby
+GLOBAL_LIST_EMPTY(lobby_station_traits)
+
///Base class of station traits. These are used to influence rounds in one way or the other by influencing the levers of the station.
/datum/station_trait
///Name of the trait
@@ -22,26 +25,30 @@
var/trait_flags
/// Whether or not this trait can be reverted by an admin
var/can_revert = TRUE
+ /// If set to true we'll show a button on the lobby to notify people about this trait
+ var/sign_up_button = FALSE
+ /// Lobby buttons controlled by this trait
+ var/list/lobby_buttons = list()
/datum/station_trait/New()
. = ..()
RegisterSignal(SSticker, COMSIG_TICKER_ROUND_STARTING, PROC_REF(on_round_start))
+ if(sign_up_button)
+ GLOB.lobby_station_traits += src
+ if(SSstation.initialized)
+ SSstation.display_lobby_traits()
if(trait_processes)
START_PROCESSING(SSstation, src)
if(trait_to_give)
ADD_TRAIT(SSstation, trait_to_give, STATION_TRAIT)
/datum/station_trait/Destroy()
+ destroy_lobby_buttons()
SSstation.station_traits -= src
return ..()
-/// Proc ran when round starts. Use this for roundstart effects.
-/datum/station_trait/proc/on_round_start()
- SIGNAL_HANDLER
- return
-
///type of info the centcom report has on this trait, if any.
/datum/station_trait/proc/get_report()
return "[name] - [report_message]"
@@ -55,3 +62,50 @@
REMOVE_TRAIT(SSstation, trait_to_give, STATION_TRAIT)
qdel(src)
+
+/// Return TRUE if we want to show a lobby button, by default we assume we don't want it after the round begins
+/datum/station_trait/proc/can_display_lobby_button(client/player)
+ return sign_up_button && !SSticker.HasRoundStarted()
+
+/// Apply any additional handling we need to our lobby button
+/datum/station_trait/proc/setup_lobby_button(atom/movable/screen/lobby/button/sign_up/lobby_button)
+ SHOULD_CALL_PARENT(TRUE)
+ lobby_button.name = name
+ lobby_buttons |= lobby_button
+ RegisterSignal(lobby_button, COMSIG_ATOM_UPDATE_ICON, PROC_REF(on_lobby_button_update_icon))
+ RegisterSignal(lobby_button, COMSIG_SCREEN_ELEMENT_CLICK, PROC_REF(on_lobby_button_click))
+ RegisterSignal(lobby_button, COMSIG_PARENT_QDELETING, PROC_REF(on_lobby_button_destroyed))
+ lobby_button.update_appearance(UPDATE_ICON)
+
+/// Called when our lobby button is clicked on
+/datum/station_trait/proc/on_lobby_button_click(atom/movable/screen/lobby/button/sign_up/lobby_button, location, control, params, mob/dead/new_player/user)
+ SIGNAL_HANDLER
+ return
+
+/// Called when our lobby button tries to update its appearance
+/datum/station_trait/proc/on_lobby_button_update_icon(atom/movable/screen/lobby/button/sign_up/lobby_button, updates)
+ SIGNAL_HANDLER
+ return
+
+/// Don't hold references to deleted buttons
+/datum/station_trait/proc/on_lobby_button_destroyed(atom/movable/screen/lobby/button/sign_up/lobby_button)
+ SIGNAL_HANDLER
+ lobby_buttons -= lobby_button
+
+/// Proc ran when round starts. Use this for roundstart effects. By default we clean up our buttons here.
+/datum/station_trait/proc/on_round_start()
+ SIGNAL_HANDLER
+ destroy_lobby_buttons()
+
+/// Remove all of our active lobby buttons
+/datum/station_trait/proc/destroy_lobby_buttons()
+ for (var/atom/movable/screen/button as anything in lobby_buttons)
+ var/mob/dead/new_player/hud_owner = button.get_mob()
+ if (QDELETED(hud_owner))
+ qdel(button)
+ continue
+ var/datum/hud/new_player/using_hud = hud_owner.hud_used
+ if(!using_hud)
+ qdel(button)
+ continue
+ using_hud.remove_station_trait_button(src)
diff --git a/code/datums/station_traits/negative_traits.dm b/code/datums/station_traits/negative_traits.dm
index 09be52d700..528d9a5893 100644
--- a/code/datums/station_traits/negative_traits.dm
+++ b/code/datums/station_traits/negative_traits.dm
@@ -152,9 +152,7 @@
. = ..()
//All bots that exist round start have their set language randomized.
for(var/mob/living/simple_animal/bot/found_bot in GLOB.alive_mob_list)
- /// The bot's language holder - so we can randomize and change their language
- var/datum/language_holder/bot_languages = found_bot.get_language_holder()
- bot_languages.selected_language = bot_languages.get_random_spoken_language()
+ found_bot.set_active_language(found_bot.get_random_spoken_language())
/datum/station_trait/revenge_of_pun_pun
name = "Revenge of Pun Pun"
diff --git a/code/datums/status_effects/debuffs.dm b/code/datums/status_effects/debuffs.dm
index d236144061..0fabb10d72 100644
--- a/code/datums/status_effects/debuffs.dm
+++ b/code/datums/status_effects/debuffs.dm
@@ -975,14 +975,16 @@
/atom/movable/screen/alert/status_effect/strandling/Click(location, control, params)
. = ..()
- if(usr != owner)
+ if(!.)
return
to_chat(owner, "You attempt to remove the durathread strand from around your neck.")
- if(do_after(owner, 3.5 SECONDS, owner))
- if(isliving(owner))
- var/mob/living/L = owner
- to_chat(owner, "You successfully remove the durathread strand.")
- L.remove_status_effect(STATUS_EFFECT_CHOKINGSTRAND)
+ if(!do_after(owner, 3.5 SECONDS, owner))
+ return
+ if(!isliving(owner))
+ return
+ var/mob/living/L = owner
+ to_chat(owner, "You successfully remove the durathread strand.")
+ L.remove_status_effect(STATUS_EFFECT_CHOKINGSTRAND)
/datum/status_effect/pacify
diff --git a/code/datums/status_effects/wound_effects.dm b/code/datums/status_effects/wound_effects.dm
index f8a51d2ad2..12bc58d70f 100644
--- a/code/datums/status_effects/wound_effects.dm
+++ b/code/datums/status_effects/wound_effects.dm
@@ -105,6 +105,9 @@
clickable_glow = TRUE
/atom/movable/screen/alert/status_effect/wound/Click()
+ . = ..()
+ if(!.)
+ return
var/mob/living/carbon/C = usr
C.check_self_for_injuries()
diff --git a/code/datums/world_topic.dm b/code/datums/world_topic.dm
index 45046e3070..576dd288d4 100644
--- a/code/datums/world_topic.dm
+++ b/code/datums/world_topic.dm
@@ -124,7 +124,7 @@
for(var/mob/dead/observer/O in GLOB.player_list)
if(O.key == expected_key)
if(O.client?.address == addr)
- new /atom/movable/screen/splash(O.client, TRUE)
+ new /atom/movable/screen/splash(null, O.client, TRUE)
break
/datum/world_topic/adminmsg
diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm
index dcee4bd9b2..0c3524f38c 100644
--- a/code/game/atoms_movable.dm
+++ b/code/game/atoms_movable.dm
@@ -12,8 +12,11 @@
var/throw_speed = 2 //How many tiles to move per ds when being thrown. Float values are fully supported
var/throw_range = 7
var/mob/pulledby = null
+ /// What language holder type to init as
var/initial_language_holder = /datum/language_holder
- var/datum/language_holder/language_holder // Mindless mobs and objects need language too, some times. Mind holder takes prescedence.
+ /// Holds all languages this mob can speak and understand
+ VAR_PRIVATE/datum/language_holder/language_holder
+
var/verb_say = "says"
var/verb_ask = "asks"
var/verb_exclaim = "exclaims"
@@ -658,44 +661,36 @@
return language_holder
/// Grants the supplied language and sets omnitongue true.
-/atom/movable/proc/grant_language(language, understood = TRUE, spoken = TRUE, source = LANGUAGE_ATOM)
- var/datum/language_holder/LH = get_language_holder()
- return LH.grant_language(language, understood, spoken, source)
+/atom/movable/proc/grant_language(language, language_flags = ALL, source = LANGUAGE_ATOM)
+ return get_language_holder().grant_language(language, language_flags, source)
/// Grants every language.
-/atom/movable/proc/grant_all_languages(understood = TRUE, spoken = TRUE, grant_omnitongue = TRUE, source = LANGUAGE_MIND)
- var/datum/language_holder/LH = get_language_holder()
- return LH.grant_all_languages(understood, spoken, grant_omnitongue, source)
+/atom/movable/proc/grant_all_languages(language_flags = ALL, grant_omnitongue = TRUE, source = LANGUAGE_MIND)
+ return get_language_holder().grant_all_languages(language_flags, grant_omnitongue, source)
/// Removes a single language.
-/atom/movable/proc/remove_language(language, understood = TRUE, spoken = TRUE, source = LANGUAGE_ALL)
- var/datum/language_holder/LH = get_language_holder()
- return LH.remove_language(language, understood, spoken, source)
+/atom/movable/proc/remove_language(language, language_flags = ALL, source = LANGUAGE_ALL)
+ return get_language_holder().remove_language(language, language_flags, source)
/// Removes every language and sets omnitongue false.
/atom/movable/proc/remove_all_languages(source = LANGUAGE_ALL, remove_omnitongue = FALSE)
- var/datum/language_holder/LH = get_language_holder()
- return LH.remove_all_languages(source, remove_omnitongue)
+ return get_language_holder().remove_all_languages(source, remove_omnitongue)
/// Adds a language to the blocked language list. Use this over remove_language in cases where you will give languages back later.
/atom/movable/proc/add_blocked_language(language, source = LANGUAGE_ATOM)
- var/datum/language_holder/LH = get_language_holder()
- return LH.add_blocked_language(language, source)
+ return get_language_holder().add_blocked_language(language, source)
/// Removes a language from the blocked language list.
/atom/movable/proc/remove_blocked_language(language, source = LANGUAGE_ATOM)
- var/datum/language_holder/LH = get_language_holder()
- return LH.remove_blocked_language(language, source)
+ return get_language_holder().remove_blocked_language(language, source)
/// Checks if atom has the language. If spoken is true, only checks if atom can speak the language.
-/atom/movable/proc/has_language(language, spoken = FALSE)
- var/datum/language_holder/LH = get_language_holder()
- return LH.has_language(language, spoken)
+/atom/movable/proc/has_language(language, flags_to_check)
+ return get_language_holder().has_language(language, flags_to_check)
/// Checks if atom can speak the language.
/atom/movable/proc/can_speak_language(language)
- var/datum/language_holder/LH = get_language_holder()
- return LH.can_speak_language(language)
+ return get_language_holder().can_speak_language(language)
/// Returns the result of tongue specific limitations on spoken languages.
/atom/movable/proc/could_speak_language(language)
@@ -703,33 +698,32 @@
/// Returns selected language, if it can be spoken, or finds, sets and returns a new selected language if possible.
/atom/movable/proc/get_selected_language()
- var/datum/language_holder/LH = get_language_holder()
- return LH.get_selected_language()
+ return get_language_holder().get_selected_language()
/// Gets a random understood language, useful for hallucinations and such.
/atom/movable/proc/get_random_understood_language()
- var/datum/language_holder/LH = get_language_holder()
- return LH.get_random_understood_language()
+ return get_language_holder().get_random_understood_language()
/// Gets a random spoken language, useful for forced speech and such.
/atom/movable/proc/get_random_spoken_language()
- var/datum/language_holder/LH = get_language_holder()
- return LH.get_random_spoken_language()
+ return get_language_holder().get_random_spoken_language()
/// Copies all languages into the supplied atom/language holder. Source should be overridden when you
/// do not want the language overwritten by later atom updates or want to avoid blocked languages.
-/atom/movable/proc/copy_languages(from_holder, source_override)
- if(isatom(from_holder))
+/atom/movable/proc/copy_languages(datum/language_holder/from_holder, source_override)
+ if(ismovable(from_holder))
var/atom/movable/thing = from_holder
from_holder = thing.get_language_holder()
- var/datum/language_holder/LH = get_language_holder()
- return LH.copy_languages(from_holder, source_override)
-/// Empties out the atom specific languages and updates them according to the current atoms language holder.
-/// As a side effect, it also creates missing language holders in the process.
-/atom/movable/proc/update_atom_languages()
- var/datum/language_holder/LH = get_language_holder()
- return LH.update_atom_languages(src)
+ return get_language_holder().copy_languages(from_holder, source_override)
+
+/// Sets the passed path as the active language
+/// Returns the currently selected language if successful, if the language was not valid, returns null
+/atom/movable/proc/set_active_language(language_path)
+ var/datum/language_holder/our_holder = get_language_holder()
+ our_holder.selected_language = language_path
+
+ return our_holder.get_selected_language() // verifies its validity, returns it if successful.
/// Sets the vocal bark for the atom, using the bark's ID
/atom/movable/proc/set_bark(id)
diff --git a/code/game/objects/buckling.dm b/code/game/objects/buckling.dm
index e4be50e19c..d20f3e4803 100644
--- a/code/game/objects/buckling.dm
+++ b/code/game/objects/buckling.dm
@@ -94,7 +94,7 @@
M.setDir(dir)
buckled_mobs |= M
M.update_mobility()
- M.throw_alert("buckled", /atom/movable/screen/alert/restrained/buckled)
+ M.throw_alert("buckled", /atom/movable/screen/alert/buckled)
post_buckle_mob(M)
SEND_SIGNAL(src, COMSIG_MOVABLE_BUCKLE, M, force)
diff --git a/code/game/objects/effects/landmarks.dm b/code/game/objects/effects/landmarks.dm
index 5e533888f9..573d6b7d95 100644
--- a/code/game/objects/effects/landmarks.dm
+++ b/code/game/objects/effects/landmarks.dm
@@ -220,8 +220,8 @@ INITIALIZE_IMMEDIATE(/obj/effect/landmark)
name = "department_sec"
icon_state = "Security Officer"
-/obj/effect/landmark/start/depsec/New()
- ..()
+/obj/effect/landmark/start/depsec/Initialize(mapload)
+ . = ..()
GLOB.department_security_spawns += src
/obj/effect/landmark/start/depsec/Destroy()
@@ -246,7 +246,7 @@ INITIALIZE_IMMEDIATE(/obj/effect/landmark)
icon_state = "wiznerd_spawn"
/obj/effect/landmark/start/wizard/Initialize(mapload)
- ..()
+ . = ..()
GLOB.wizardstart += loc
return INITIALIZE_HINT_QDEL
@@ -256,7 +256,7 @@ INITIALIZE_IMMEDIATE(/obj/effect/landmark)
icon_state = "snukeop_spawn"
/obj/effect/landmark/start/nukeop/Initialize(mapload)
- ..()
+ . = ..()
GLOB.nukeop_start += loc
return INITIALIZE_HINT_QDEL
@@ -266,7 +266,7 @@ INITIALIZE_IMMEDIATE(/obj/effect/landmark)
icon_state = "snukeop_leader_spawn"
/obj/effect/landmark/start/nukeop_leader/Initialize(mapload)
- ..()
+ . = ..()
GLOB.nukeop_leader_start += loc
return INITIALIZE_HINT_QDEL
@@ -278,7 +278,7 @@ INITIALIZE_IMMEDIATE(/obj/effect/landmark/start/new_player)
name = "New Player"
/obj/effect/landmark/start/new_player/Initialize(mapload)
- ..()
+ . = ..()
GLOB.newplayer_start += loc
return INITIALIZE_HINT_QDEL
@@ -308,7 +308,7 @@ INITIALIZE_IMMEDIATE(/obj/effect/landmark/start/new_player)
name = "JoinLate"
/obj/effect/landmark/latejoin/Initialize(mapload)
- ..()
+ . = ..()
SSjob.latejoin_trackers += loc
return INITIALIZE_HINT_QDEL
@@ -333,7 +333,7 @@ INITIALIZE_IMMEDIATE(/obj/effect/landmark/start/new_player)
icon_state = "xeno_spawn"
/obj/effect/landmark/xeno_spawn/Initialize(mapload)
- ..()
+ . = ..()
GLOB.xeno_spawn += loc
return INITIALIZE_HINT_QDEL
@@ -343,7 +343,7 @@ INITIALIZE_IMMEDIATE(/obj/effect/landmark/start/new_player)
icon_state = "blob_start"
/obj/effect/landmark/blobstart/Initialize(mapload)
- ..()
+ . = ..()
GLOB.blobstart += loc
return INITIALIZE_HINT_QDEL
@@ -352,7 +352,7 @@ INITIALIZE_IMMEDIATE(/obj/effect/landmark/start/new_player)
icon_state = "secequipment"
/obj/effect/landmark/secequipment/Initialize(mapload)
- ..()
+ . = ..()
GLOB.secequipment += loc
return INITIALIZE_HINT_QDEL
@@ -361,7 +361,7 @@ INITIALIZE_IMMEDIATE(/obj/effect/landmark/start/new_player)
icon_state = "prisonwarp"
/obj/effect/landmark/prisonwarp/Initialize(mapload)
- ..()
+ . = ..()
GLOB.prisonwarp += loc
return INITIALIZE_HINT_QDEL
@@ -370,7 +370,7 @@ INITIALIZE_IMMEDIATE(/obj/effect/landmark/start/new_player)
icon_state = "ert_spawn"
/obj/effect/landmark/ert_spawn/Initialize(mapload)
- ..()
+ . = ..()
GLOB.emergencyresponseteamspawn += loc
return INITIALIZE_HINT_QDEL
@@ -379,7 +379,7 @@ INITIALIZE_IMMEDIATE(/obj/effect/landmark/start/new_player)
icon_state = "holding_facility"
/obj/effect/landmark/holding_facility/Initialize(mapload)
- ..()
+ . = ..()
GLOB.holdingfacility += loc
return INITIALIZE_HINT_QDEL
@@ -388,7 +388,7 @@ INITIALIZE_IMMEDIATE(/obj/effect/landmark/start/new_player)
icon_state = "tdome_observer"
/obj/effect/landmark/thunderdome/observe/Initialize(mapload)
- ..()
+ . = ..()
GLOB.tdomeobserve += loc
return INITIALIZE_HINT_QDEL
@@ -397,7 +397,7 @@ INITIALIZE_IMMEDIATE(/obj/effect/landmark/start/new_player)
icon_state = "tdome_t1"
/obj/effect/landmark/thunderdome/one/Initialize(mapload)
- ..()
+ . = ..()
GLOB.tdome1 += loc
return INITIALIZE_HINT_QDEL
@@ -406,7 +406,7 @@ INITIALIZE_IMMEDIATE(/obj/effect/landmark/start/new_player)
icon_state = "tdome_t2"
/obj/effect/landmark/thunderdome/two/Initialize(mapload)
- ..()
+ . = ..()
GLOB.tdome2 += loc
return INITIALIZE_HINT_QDEL
@@ -415,7 +415,7 @@ INITIALIZE_IMMEDIATE(/obj/effect/landmark/start/new_player)
icon_state = "tdome_admin"
/obj/effect/landmark/thunderdome/admin/Initialize(mapload)
- ..()
+ . = ..()
GLOB.tdomeadmin += loc
return INITIALIZE_HINT_QDEL
@@ -426,7 +426,7 @@ INITIALIZE_IMMEDIATE(/obj/effect/landmark/start/new_player)
layer = MOB_LAYER
/obj/effect/landmark/servant_of_ratvar/Initialize(mapload)
- ..()
+ . = ..()
GLOB.servant_spawns += loc
return INITIALIZE_HINT_QDEL
@@ -436,7 +436,7 @@ INITIALIZE_IMMEDIATE(/obj/effect/landmark/start/new_player)
icon_state = "city_of_cogs"
/obj/effect/landmark/city_of_cogs/Initialize(mapload)
- ..()
+ . = ..()
GLOB.city_of_cogs_spawns += loc
return INITIALIZE_HINT_QDEL
@@ -448,7 +448,7 @@ INITIALIZE_IMMEDIATE(/obj/effect/landmark/start/new_player)
/obj/effect/landmark/event_spawn/New()
- ..()
+ . = ..()
GLOB.generic_event_spawns += src
/obj/effect/landmark/event_spawn/Destroy()
@@ -458,9 +458,9 @@ INITIALIZE_IMMEDIATE(/obj/effect/landmark/start/new_player)
/obj/effect/landmark/ruin
var/datum/map_template/ruin/ruin_template
-/obj/effect/landmark/ruin/New(loc, my_ruin_template)
+/obj/effect/landmark/ruin/Initialize(mapload, my_ruin_template)
+ . = ..()
name = "ruin_[GLOB.ruin_landmarks.len + 1]"
- ..(loc)
ruin_template = my_ruin_template
GLOB.ruin_landmarks |= src
@@ -475,8 +475,8 @@ INITIALIZE_IMMEDIATE(/obj/effect/landmark/start/new_player)
layer = BULLET_HOLE_LAYER
plane = ABOVE_WALL_PLANE
-/obj/effect/landmark/stationroom/New()
- ..()
+/obj/effect/landmark/stationroom/Initialize(mapload)
+ . = ..()
GLOB.stationroom_landmarks += src
/obj/effect/landmark/stationroom/Destroy()
@@ -514,7 +514,7 @@ INITIALIZE_IMMEDIATE(/obj/effect/landmark/start/new_player)
templates = list("Engine SM" = 3, "Engine Singulo" = 3, "Engine Tesla" = 3)
icon = 'icons/rooms/box/engine.dmi'
-/obj/effect/landmark/stationroom/box/engine/New()
+/obj/effect/landmark/stationroom/box/engine/Initialize(mapload)
. = ..()
templates = CONFIG_GET(keyed_list/box_random_engine)
diff --git a/code/game/objects/items/devices/flashlight.dm b/code/game/objects/items/devices/flashlight.dm
index 3f64be4729..5db6aead98 100644
--- a/code/game/objects/items/devices/flashlight.dm
+++ b/code/game/objects/items/devices/flashlight.dm
@@ -399,8 +399,8 @@
var/emp_cur_charges = 4
var/charge_tick = 0
-/obj/item/flashlight/emp/New()
- ..()
+/obj/item/flashlight/emp/Initialize(mapload)
+ . = ..()
START_PROCESSING(SSobj, src)
/obj/item/flashlight/emp/Destroy()
diff --git a/code/game/objects/items/documents.dm b/code/game/objects/items/documents.dm
index 1172b50377..9976848bdf 100644
--- a/code/game/objects/items/documents.dm
+++ b/code/game/objects/items/documents.dm
@@ -37,8 +37,8 @@
var/forgedseal = 0
var/copy_type = null
-/obj/item/documents/photocopy/New(loc, obj/item/documents/copy=null)
- ..()
+/obj/item/documents/photocopy/Initialize(mapload, obj/item/documents/copy=null)
+ . = ..()
if(copy)
copy_type = copy.type
if(istype(copy, /obj/item/documents/photocopy)) // Copy Of A Copy Of A Copy
diff --git a/code/game/objects/items/holy_weapons.dm b/code/game/objects/items/holy_weapons.dm
index ddcea7328e..63cf7c85e2 100644
--- a/code/game/objects/items/holy_weapons.dm
+++ b/code/game/objects/items/holy_weapons.dm
@@ -522,7 +522,6 @@
S.ckey = C.ckey
S.status_flags |= GODMODE
S.copy_languages(user, LANGUAGE_MASTER) //Make sure the sword can understand and communicate with the user.
- S.update_atom_languages()
grant_all_languages(FALSE, FALSE, TRUE) //Grants omnitongue
S.AddElement(/datum/element/ghost_role_eligibility,penalize_on_ghost = TRUE)
START_PROCESSING(SSprocessing,src)
diff --git a/code/game/objects/structures/fireplace.dm b/code/game/objects/structures/fireplace.dm
index ec7db22cf0..280922364d 100644
--- a/code/game/objects/structures/fireplace.dm
+++ b/code/game/objects/structures/fireplace.dm
@@ -17,8 +17,8 @@
var/fuel_added = 0
var/flame_expiry_timer
-/obj/structure/fireplace/New()
- ..()
+/obj/structure/fireplace/Initialize(mapload)
+ . = ..()
START_PROCESSING(SSobj, src)
/obj/structure/fireplace/Destroy()
diff --git a/code/game/objects/structures/ghost_role_spawners.dm b/code/game/objects/structures/ghost_role_spawners.dm
index ea9fc47d9e..93b447998a 100644
--- a/code/game/objects/structures/ghost_role_spawners.dm
+++ b/code/game/objects/structures/ghost_role_spawners.dm
@@ -32,7 +32,7 @@
new_spawn.undershirt = "Nude" //changing underwear/shirt/socks doesn't seem to function correctly right now because of some bug elsewhere?
new_spawn.socks = "Nude"
new_spawn.update_body(TRUE)
- new_spawn.language_holder.selected_language = /datum/language/sylvan
+ new_spawn.set_active_language(/datum/language/sylvan)
//Ash walker eggs: Spawns in ash walker dens in lavaland. Ghosts become unbreathing lizards that worship the Necropolis and are advised to retrieve corpses to create more ash walkers.
diff --git a/code/game/objects/structures/industrial_lift.dm b/code/game/objects/structures/industrial_lift.dm
index 9f04d1b710..cff9e8e2a1 100644
--- a/code/game/objects/structures/industrial_lift.dm
+++ b/code/game/objects/structures/industrial_lift.dm
@@ -154,12 +154,9 @@ GLOBAL_LIST_EMPTY(lifts)
var/list/atom/movable/lift_load //things to move
var/datum/lift_master/lift_master_datum //control from
-/obj/structure/industrial_lift/New()
- GLOB.lifts.Add(src)
- ..()
-
/obj/structure/industrial_lift/Initialize(mapload)
. = ..()
+ GLOB.lifts.Add(src)
RegisterSignal(src, COMSIG_MOVABLE_CROSSED, PROC_REF(AddItemOnLift))
RegisterSignal(loc, COMSIG_ATOM_CREATED, PROC_REF(AddItemOnLift))//For atoms created on platform
RegisterSignal(src, COMSIG_MOVABLE_UNCROSSED, PROC_REF(RemoveItemFromLift))
diff --git a/code/game/objects/structures/mirror.dm b/code/game/objects/structures/mirror.dm
index ffb48ce633..1acfc16962 100644
--- a/code/game/objects/structures/mirror.dm
+++ b/code/game/objects/structures/mirror.dm
@@ -118,23 +118,23 @@
var/list/races_blacklist = list("skeleton", "agent", "military_synth", "memezombies", "clockwork golem servant", "android", "synth", "mush", "zombie", "memezombie")
var/list/choosable_races = list()
-/obj/structure/mirror/magic/New()
+/obj/structure/mirror/magic/Initialize(mapload)
+ . = ..()
if(!choosable_races.len)
for(var/speciestype in subtypesof(/datum/species))
var/datum/species/S = new speciestype()
if(!(S.id in races_blacklist))
choosable_races += S.id
- ..()
-/obj/structure/mirror/magic/lesser/New()
+/obj/structure/mirror/magic/lesser/Initialize(mapload)
choosable_races = GLOB.roundstart_races.Copy()
- ..()
+ return ..()
-/obj/structure/mirror/magic/badmin/New()
+/obj/structure/mirror/magic/badmin/Initialize(mapload)
for(var/speciestype in subtypesof(/datum/species))
var/datum/species/S = new speciestype()
choosable_races += S.id
- ..()
+ return ..()
/obj/structure/mirror/magic/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
if(!ishuman(user))
diff --git a/code/game/objects/structures/transit_tubes/transit_tube.dm b/code/game/objects/structures/transit_tubes/transit_tube.dm
index be87c97759..0e7515b273 100644
--- a/code/game/objects/structures/transit_tubes/transit_tube.dm
+++ b/code/game/objects/structures/transit_tubes/transit_tube.dm
@@ -15,8 +15,8 @@
var/enter_delay = 0
var/const/time_to_unwrench = 2 SECONDS
-/obj/structure/transit_tube/New(loc, newdirection)
- ..(loc)
+/obj/structure/transit_tube/Initialize(mapload, newdirection)
+ . = ..()
if(newdirection)
setDir(newdirection)
init_tube_dirs()
diff --git a/code/game/sound.dm b/code/game/sound.dm
index 02c2936f8d..6ad3f3ece1 100644
--- a/code/game/sound.dm
+++ b/code/game/sound.dm
@@ -232,6 +232,10 @@ distance_multiplier - Can be used to multiply the distance at which the sound is
/proc/get_rand_frequency()
return rand(32000, 55000) //Frequency stuff only works with 45kbps oggs.
+///get_rand_frequency but lower range.
+/proc/get_rand_frequency_low_range()
+ return rand(38000, 45000)
+
/proc/get_sfx(soundin)
if(istext(soundin))
switch(soundin)
diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm
index c1bf537dd8..90573b44a0 100644
--- a/code/modules/admin/topic.dm
+++ b/code/modules/admin/topic.dm
@@ -2081,8 +2081,7 @@
if(!ismob(M))
to_chat(usr, "This can only be used on instances of type /mob.")
return
- var/datum/language_holder/H = M.get_language_holder()
- H.open_language_menu(usr)
+ M.get_language_holder().open_language_menu(usr)
else if(href_list["traitor"])
if(!check_rights(R_ADMIN))
diff --git a/code/modules/admin/verbs/adminhelp.dm b/code/modules/admin/verbs/adminhelp.dm
index 4aba4fda00..cb568beb52 100644
--- a/code/modules/admin/verbs/adminhelp.dm
+++ b/code/modules/admin/verbs/adminhelp.dm
@@ -135,9 +135,9 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
/obj/effect/statclick/ticket_list
var/current_state
-/obj/effect/statclick/ticket_list/New(loc, name, state)
+/obj/effect/statclick/ticket_list/Initialize(mapload, name, state)
+ . = ..()
current_state = state
- ..()
/obj/effect/statclick/ticket_list/Click()
GLOB.ahelp_tickets.BrowseTickets(current_state)
diff --git a/code/modules/antagonists/abductor/equipment/glands/slime.dm b/code/modules/antagonists/abductor/equipment/glands/slime.dm
index 36732d5fe0..f98bb403bc 100644
--- a/code/modules/antagonists/abductor/equipment/glands/slime.dm
+++ b/code/modules/antagonists/abductor/equipment/glands/slime.dm
@@ -10,12 +10,12 @@
/obj/item/organ/heart/gland/slime/Insert(mob/living/carbon/M, special = 0, drop_if_replaced = TRUE)
..()
owner.faction |= "slime"
- owner.grant_language(/datum/language/slime, TRUE, TRUE, LANGUAGE_GLAND)
+ owner.grant_language(/datum/language/slime, source = LANGUAGE_GLAND)
/obj/item/organ/heart/gland/slime/Remove(mob/living/carbon/M, special = 0)
..()
owner.faction -= "slime"
- owner.remove_language(/datum/language/slime, TRUE, TRUE, LANGUAGE_GLAND)
+ owner.remove_language(/datum/language/slime, source = LANGUAGE_GLAND)
/obj/item/organ/heart/gland/slime/activate()
to_chat(owner, "You feel nauseated!")
diff --git a/code/modules/antagonists/bloodsucker/datum_bloodsucker.dm b/code/modules/antagonists/bloodsucker/datum_bloodsucker.dm
index 56ebb8fd87..46c4e260e3 100644
--- a/code/modules/antagonists/bloodsucker/datum_bloodsucker.dm
+++ b/code/modules/antagonists/bloodsucker/datum_bloodsucker.dm
@@ -210,7 +210,7 @@
// Physiology
CheckVampOrgans() // Heart, Eyes
// Language
- owner.current.grant_language(/datum/language/vampiric, TRUE, TRUE, LANGUAGE_BLOODSUCKER)
+ owner.current.grant_language(/datum/language/vampiric, source = LANGUAGE_BLOODSUCKER)
owner.hasSoul = FALSE // If false, renders the character unable to sell their soul.
owner.isholy = FALSE // is this person a chaplain or admin role allowed to use bibles
// Disabilities
diff --git a/code/modules/antagonists/bloodsucker/datum_vassal.dm b/code/modules/antagonists/bloodsucker/datum_vassal.dm
index 9a2e3a1ae6..3275f251a5 100644
--- a/code/modules/antagonists/bloodsucker/datum_vassal.dm
+++ b/code/modules/antagonists/bloodsucker/datum_vassal.dm
@@ -48,7 +48,7 @@
objectives += vassal_objective
objectives_given += vassal_objective
give_thrall_eyes()
- owner.current.grant_language(/datum/language/vampiric, TRUE, TRUE, LANGUAGE_VASSAL)
+ owner.current.grant_language(/datum/language/vampiric, source = LANGUAGE_VASSAL)
// Add Antag HUD
update_vassal_icons_added(owner.current, "vassal")
. = ..()
diff --git a/code/modules/antagonists/changeling/changeling.dm b/code/modules/antagonists/changeling/changeling.dm
index 5a6a6af90b..0ed599c824 100644
--- a/code/modules/antagonists/changeling/changeling.dm
+++ b/code/modules/antagonists/changeling/changeling.dm
@@ -84,7 +84,7 @@
create_initial_profile()
if(give_objectives)
forge_objectives()
- owner.current.grant_all_languages(FALSE, FALSE, TRUE) //Grants omnitongue. We are able to transform our body after all.
+ owner.current.get_language_holder().omnitongue = TRUE
remove_clownmut()
. = ..()
diff --git a/code/modules/antagonists/clockcult/clockcult.dm b/code/modules/antagonists/clockcult/clockcult.dm
index ed2982f861..f052afc4b4 100644
--- a/code/modules/antagonists/clockcult/clockcult.dm
+++ b/code/modules/antagonists/clockcult/clockcult.dm
@@ -96,7 +96,7 @@
current = mob_override
GLOB.all_clockwork_mobs += current
current.faction |= "ratvar"
- current.grant_language(/datum/language/ratvar, TRUE, TRUE, LANGUAGE_CLOCKIE)
+ current.grant_language(/datum/language/ratvar, source = LANGUAGE_CLOCKIE)
current.update_action_buttons_icon() //because a few clockcult things are action buttons and we may be wearing/holding them for whatever reason, we need to update buttons
if(issilicon(current))
var/mob/living/silicon/S = current
diff --git a/code/modules/antagonists/cult/cult.dm b/code/modules/antagonists/cult/cult.dm
index 63b82f26ce..fe9f8cbe04 100644
--- a/code/modules/antagonists/cult/cult.dm
+++ b/code/modules/antagonists/cult/cult.dm
@@ -121,7 +121,7 @@
if(mob_override)
current = mob_override
current.faction |= "cult"
- current.grant_language(/datum/language/narsie, TRUE, TRUE, LANGUAGE_CULTIST)
+ current.grant_language(/datum/language/narsie, source = LANGUAGE_CULTIST)
if(!cult_team?.cult_master)
vote.Grant(current)
communion.Grant(current)
@@ -139,7 +139,7 @@
if(mob_override)
current = mob_override
current.faction -= "cult"
- current.remove_language(/datum/language/narsie, TRUE, TRUE, LANGUAGE_CULTIST)
+ current.remove_language(/datum/language/narsie, source = LANGUAGE_CULTIST)
vote.Remove(current)
communion.Remove(current)
magic.Remove(current)
diff --git a/code/modules/antagonists/ert/ert.dm b/code/modules/antagonists/ert/ert.dm
index a8e57ee08b..7f45c5099c 100644
--- a/code/modules/antagonists/ert/ert.dm
+++ b/code/modules/antagonists/ert/ert.dm
@@ -182,9 +182,8 @@
add_antag_hud(antag_hud_type, antag_hud_name, M)
if(M.hud_used)
var/datum/hud/H = M.hud_used
- var/atom/movable/screen/wanted/giving_wanted_lvl = new /atom/movable/screen/wanted()
+ var/atom/movable/screen/wanted/giving_wanted_lvl = new /atom/movable/screen/wanted(null, H)
H.wanted_lvl = giving_wanted_lvl
- giving_wanted_lvl.hud = H
H.infodisplay += giving_wanted_lvl
H.mymob.client.screen += giving_wanted_lvl
diff --git a/code/modules/antagonists/gang/gang.dm b/code/modules/antagonists/gang/gang.dm
index e41c7b1228..058379d96c 100644
--- a/code/modules/antagonists/gang/gang.dm
+++ b/code/modules/antagonists/gang/gang.dm
@@ -113,9 +113,8 @@
add_antag_hud(antag_hud_type, antag_hud_name, M)
if(M.hud_used)
var/datum/hud/H = M.hud_used
- var/atom/movable/screen/wanted/giving_wanted_lvl = new /atom/movable/screen/wanted()
+ var/atom/movable/screen/wanted/giving_wanted_lvl = new /atom/movable/screen/wanted(null, H)
H.wanted_lvl = giving_wanted_lvl
- giving_wanted_lvl.hud = H
H.infodisplay += giving_wanted_lvl
H.mymob.client.screen += giving_wanted_lvl
diff --git a/code/modules/antagonists/traitor/classes/ai.dm b/code/modules/antagonists/traitor/classes/ai.dm
index 0c1709ee53..8992c9ea17 100644
--- a/code/modules/antagonists/traitor/classes/ai.dm
+++ b/code/modules/antagonists/traitor/classes/ai.dm
@@ -65,5 +65,5 @@
/datum/traitor_class/ai/finalize_traitor(datum/antagonist/traitor/T)
T.add_law_zero()
T.owner.current.playsound_local(get_turf(T.owner.current), 'sound/ambience/antag/malf.ogg', 100, FALSE, pressure_affected = FALSE)
- T.owner.current.grant_language(/datum/language/codespeak, TRUE, TRUE, LANGUAGE_MALF)
+ T.owner.current.grant_language(/datum/language/codespeak, source = LANGUAGE_MALF)
return FALSE
diff --git a/code/modules/antagonists/wizard/equipment/artefact.dm b/code/modules/antagonists/wizard/equipment/artefact.dm
index 99e69e1fa1..4eab67ea34 100644
--- a/code/modules/antagonists/wizard/equipment/artefact.dm
+++ b/code/modules/antagonists/wizard/equipment/artefact.dm
@@ -41,13 +41,13 @@
var/spawn_amt_left = 20
var/spawn_fast = 0
-/obj/effect/rend/New(loc, var/spawn_type, var/spawn_amt, var/desc, var/spawn_fast)
+/obj/effect/rend/Initialize(mapload, spawn_type, spawn_amt, desc, spawn_fast)
+ . = ..()
src.spawn_path = spawn_type
src.spawn_amt_left = spawn_amt
src.desc = desc
src.spawn_fast = spawn_fast
START_PROCESSING(SSobj, src)
- return
/obj/effect/rend/process()
if(!spawn_fast)
diff --git a/code/modules/antagonists/wizard/equipment/soulstone.dm b/code/modules/antagonists/wizard/equipment/soulstone.dm
index fe9770e64a..cff5260463 100644
--- a/code/modules/antagonists/wizard/equipment/soulstone.dm
+++ b/code/modules/antagonists/wizard/equipment/soulstone.dm
@@ -287,9 +287,7 @@
S.real_name = "Shade of [T.real_name]"
T.transfer_ckey(S)
S.original_mind = T.mind
- S.copy_languages(T, LANGUAGE_MIND)//Copies the old mobs languages into the new mob holder.
- S.update_atom_languages()
- grant_all_languages(FALSE, FALSE, TRUE) //Grants omnitongue
+ S.get_language_holder().omnitongue = TRUE //Grants omnitongue
if(user)
S.faction |= "[REF(user)]" //Add the master as a faction, allowing inter-mob cooperation
if(user && iscultist(user))
diff --git a/code/modules/atmospherics/gasmixtures/auxgm.dm b/code/modules/atmospherics/gasmixtures/auxgm.dm
index 0318e06abe..9c6a533646 100644
--- a/code/modules/atmospherics/gasmixtures/auxgm.dm
+++ b/code/modules/atmospherics/gasmixtures/auxgm.dm
@@ -186,6 +186,6 @@ GLOBAL_DATUM_INIT(gas_data, /datum/auxgm, new)
appearance_flags = TILE_BOUND
vis_flags = NONE
-/obj/effect/overlay/gas/New(state)
+/obj/effect/overlay/gas/Initialize(mapload, state)
. = ..()
icon_state = state
diff --git a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm
index 580ea8f2ee..96f59bc048 100644
--- a/code/modules/client/client_procs.dm
+++ b/code/modules/client/client_procs.dm
@@ -171,6 +171,15 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
to_chat(src, "Become a BYOND member to access member-perks and features, as well as support the engine that makes this game possible. Only 10 bucks for 3 months! Click Here to find out more.")
return FALSE
return TRUE
+
+/client/proc/is_localhost()
+ var/static/localhost_addresses = list(
+ "127.0.0.1",
+ "::1",
+ null,
+ )
+ return address in localhost_addresses
+
/*
* Call back proc that should be checked in all paths where a client can send messages
*
diff --git a/code/modules/events/sentience.dm b/code/modules/events/sentience.dm
index 8cccaba68b..d3a9172b96 100644
--- a/code/modules/events/sentience.dm
+++ b/code/modules/events/sentience.dm
@@ -55,7 +55,7 @@
SG.transfer_ckey(SA, FALSE)
- SA.grant_all_languages(TRUE, FALSE, FALSE)
+ SA.grant_all_languages(UNDERSTOOD_LANGUAGE, grant_omnitongue = FALSE, source = LANGUAGE_ATOM)
SA.sentience_act()
diff --git a/code/modules/jobs/job_types/curator.dm b/code/modules/jobs/job_types/curator.dm
index 6b5707d76f..a4dbb20c5c 100644
--- a/code/modules/jobs/job_types/curator.dm
+++ b/code/modules/jobs/job_types/curator.dm
@@ -50,4 +50,5 @@
if(visualsOnly)
return
- H.grant_all_languages(TRUE, TRUE, TRUE, LANGUAGE_CURATOR)
+ H.grant_all_languages(source = LANGUAGE_CURATOR)
+ H.remove_blocked_language(GLOB.all_languages, source=LANGUAGE_ALL)
diff --git a/code/modules/language/codespeak.dm b/code/modules/language/codespeak.dm
index d31d82e769..1ae4be1cf4 100644
--- a/code/modules/language/codespeak.dm
+++ b/code/modules/language/codespeak.dm
@@ -49,7 +49,7 @@
return
to_chat(user, "You start skimming through [src], and suddenly your mind is filled with codewords and responses.")
- user.grant_language(/datum/language/codespeak, TRUE, TRUE, LANGUAGE_MIND)
+ user.grant_language(/datum/language/codespeak, source = LANGUAGE_MIND)
use_charge(user)
@@ -68,7 +68,7 @@
M.visible_message("[user] beats [M] over the head with [src]!", "[user] beats you over the head with [src]!", "You hear smacking.")
else
M.visible_message("[user] teaches [M] by beating [M.p_them()] over the head with [src]!", "As [user] hits you with [src], codewords and responses flow through your mind.", "You hear smacking.")
- M.grant_language(/datum/language/codespeak, TRUE, TRUE, LANGUAGE_MIND)
+ M.grant_language(/datum/language/codespeak, source = LANGUAGE_MIND)
use_charge(user)
/obj/item/codespeak_manual/proc/use_charge(mob/user)
diff --git a/code/modules/language/language_holder.dm b/code/modules/language/language_holder.dm
index 24f56a8dbb..ddebf7616c 100644
--- a/code/modules/language/language_holder.dm
+++ b/code/modules/language/language_holder.dm
@@ -1,23 +1,28 @@
-/*!Language holders will either exist in an atom/movable or a mind. Creation of language holders happens
+/*!Language holders will either exist in an atom/movable. Creation of language holders happens
automatically when they are needed, for example when something tries to speak.
Where a mind is available, the mind language holder will be the one "in charge". The mind holder
will update its languages based on the atom holder, and will get updated as part of
transformations and other events that cause new languages to become available.
+
Every language holder has three lists of languages (and sources for each of them):
- understood_languages
- spoken_languages
- blocked_languages
+
Understood languages let you understand them, spoken languages lets you speak them
(if your tongue is compatible), and blocked languages will let you do neither no matter
what the source of the language is.
+
Language holders are designed to mostly only ever require the use the helpers in atom/movable
to achieve your goals, but it is also possible to work on them directly if needed. Any adding
and removing of languages and sources should only happen through the procs, as directly changing
these will mess something up somewhere down the line.
+
All atom movables have the initial_language_holder var which allows you to set the default language
holder to create. For example, /datum/language_holder/alien will give you xenocommon and a block for
galactic common. Human species also have a default language holder var that will be updated on
species change, initial_species_holder.
+
Key procs
* [grant_language](atom/movable.html#proc/grant_language)
* [remove_language](atom/movable.html#proc/remove_language)
@@ -28,83 +33,86 @@ Key procs
* [has_language](atom/movable.html#proc/has_language)
* [can_speak_language](atom/movable.html#proc/can_speak_language)
* [get_selected_language](atom/movable.html#proc/get_selected_language)
-* [update_atom_languages](atom/movable.html#proc/update_atom_languages)
*/
/datum/language_holder
- /// Understood languages.
- var/list/understood_languages = list(/datum/language/common = list(LANGUAGE_MIND))
- /// A list of languages that can be spoken. Tongue organ may also set limits beyond this list.
+ /// Lazyassoclist of all understood languages
+ var/list/understood_languages = list(/datum/language/common = list(LANGUAGE_ATOM))
+ /// Lazyassoclist of languages that can be spoken.
+ /// Tongue organ may also set limits beyond this list.
var/list/spoken_languages = list(/datum/language/common = list(LANGUAGE_ATOM))
- /// A list of blocked languages. Used to prevent understanding and speaking certain languages, ie for certain mobs, mutations etc.
- var/list/blocked_languages = list()
- /// If true, overrides tongue limitations.
+ /// Lazyassoclist of blocked languages.
+ /// Used to prevent understanding and speaking certain languages, ie for certain mobs, mutations etc.
+ var/list/blocked_languages
+ /// If true, overrides tongue aforementioned limitations.
var/omnitongue = FALSE
/// Handles displaying the language menu UI.
var/datum/language_menu/language_menu
/// Currently spoken language
var/selected_language
/// Tracks the entity that owns the holder.
- var/owner
+ var/atom/movable/owner
/// Initializes, and copies in the languages from the current atom if available.
-/datum/language_holder/New(_owner)
- owner = _owner
- if(istype(owner, /datum/mind))
- var/datum/mind/M = owner
- if(M.current)
- update_atom_languages(M.current)
- get_selected_language()
+/datum/language_holder/New(atom/new_owner)
+ if(new_owner)
+ if(QDELETED(new_owner))
+ CRASH("Langauge holder added to a qdeleting thing, what the fuck [text_ref(new_owner)]")
+ if(!ismovable(new_owner))
+ CRASH("Language holder being added to a non-movable thing, this is invalid (was: [new_owner] / [new_owner.type])")
+
+ owner = new_owner
+
+ // If we have an owner, we'll set a default selected language
+ if(owner)
+ get_selected_language()
/datum/language_holder/Destroy()
QDEL_NULL(language_menu)
+ owner = null
return ..()
/// Grants the supplied language.
-/datum/language_holder/proc/grant_language(language, understood = TRUE, spoken = TRUE, source = LANGUAGE_MIND)
- if(understood)
- if(!understood_languages[language])
- understood_languages[language] = list()
- understood_languages[language] |= source
+/datum/language_holder/proc/grant_language(language, language_flags = ALL, source = LANGUAGE_MIND)
+ if(language_flags & UNDERSTOOD_LANGUAGE)
+ LAZYORASSOCLIST(understood_languages, language, source)
. = TRUE
- if(spoken)
- if(!spoken_languages[language])
- spoken_languages[language] = list()
- spoken_languages[language] |= source
+ if(language_flags & SPOKEN_LANGUAGE)
+ LAZYORASSOCLIST(spoken_languages, language, source)
. = TRUE
+ return .
+
/// Grants every language to understood and spoken, and gives omnitongue.
-/datum/language_holder/proc/grant_all_languages(understood = TRUE, spoken = TRUE, grant_omnitongue = TRUE, source = LANGUAGE_MIND)
+/datum/language_holder/proc/grant_all_languages(language_flags = ALL, grant_omnitongue = TRUE, source = LANGUAGE_MIND)
for(var/language in GLOB.all_languages)
- grant_language(language, understood, spoken, source)
- if(grant_omnitongue) // Overrides tongue limitations.
+ grant_language(language, language_flags, source)
+ if(grant_omnitongue) // Overrides tongue limitations.
omnitongue = TRUE
return TRUE
/// Removes a single language or source, removing all sources returns the pre-removal state of the language.
-/datum/language_holder/proc/remove_language(language, understood = TRUE, spoken = TRUE, source = LANGUAGE_ALL)
- if(understood && understood_languages[language])
+/datum/language_holder/proc/remove_language(language, language_flags = ALL, source = LANGUAGE_ALL)
+ if(language_flags & UNDERSTOOD_LANGUAGE)
if(source == LANGUAGE_ALL)
- understood_languages -= language
+ LAZYREMOVE(understood_languages, language)
else
- understood_languages[language] -= source
- if(!length(understood_languages[language]))
- understood_languages -= language
+ LAZYREMOVEASSOC(understood_languages, language, source)
. = TRUE
- if(spoken && spoken_languages[language])
+ if(language_flags & SPOKEN_LANGUAGE)
if(source == LANGUAGE_ALL)
- spoken_languages -= language
+ LAZYREMOVE(spoken_languages, language)
else
- spoken_languages[language] -= source
- if(!length(spoken_languages[language]))
- spoken_languages -= language
+ LAZYREMOVEASSOC(spoken_languages, language, source)
. = TRUE
+ return .
+
/// Removes every language and optionally sets omnitongue false. If a non default source is supplied, only removes that source.
/datum/language_holder/proc/remove_all_languages(source = LANGUAGE_ALL, remove_omnitongue = FALSE)
for(var/language in GLOB.all_languages)
- remove_language(language, TRUE, TRUE, source)
+ remove_language(language, ALL, source)
if(remove_omnitongue)
omnitongue = FALSE
return TRUE
@@ -113,41 +121,41 @@ Key procs
/datum/language_holder/proc/add_blocked_language(languages, source = LANGUAGE_MIND)
if(!islist(languages))
languages = list(languages)
+
for(var/language in languages)
- if(!blocked_languages[language])
- blocked_languages[language] = list()
- blocked_languages[language] |= source
+ LAZYORASSOCLIST(blocked_languages, language, source)
return TRUE
/// Removes a single language or list of languages from the blocked language list.
/datum/language_holder/proc/remove_blocked_language(languages, source = LANGUAGE_MIND)
if(!islist(languages))
languages = list(languages)
+
for(var/language in languages)
- if(blocked_languages[language])
- if(source == LANGUAGE_ALL)
- blocked_languages -= language
- else
- blocked_languages[language] -= source
- if(!length(blocked_languages[language]))
- blocked_languages -= language
+ if(source == LANGUAGE_ALL)
+ LAZYREMOVE(blocked_languages, language)
+ else
+ LAZYREMOVEASSOC(blocked_languages, language, source)
+
return TRUE
-/// Checks if you have the language. If spoken is true, only checks if you can speak the language.
-/datum/language_holder/proc/has_language(language, spoken = FALSE)
+/// Checks if you have the language passed.
+/datum/language_holder/proc/has_language(language, flag_to_check = UNDERSTOOD_LANGUAGE)
if(language in blocked_languages)
return FALSE
- if(spoken)
- return language in spoken_languages
- return language in understood_languages
+
+ var/list/langs_to_check = list()
+ if(flag_to_check & SPOKEN_LANGUAGE)
+ langs_to_check |= spoken_languages
+ if(flag_to_check & UNDERSTOOD_LANGUAGE)
+ langs_to_check |= understood_languages
+
+ return language in langs_to_check
/// Checks if you can speak the language. Tongue limitations should be supplied as an argument.
/datum/language_holder/proc/can_speak_language(language)
- var/atom/movable/ouratom = get_atom()
- var/tongue = ouratom.could_speak_language(language)
- if((omnitongue || tongue) && has_language(language, TRUE))
- return TRUE
- return FALSE
+ var/can_speak_language_path = omnitongue || owner.could_speak_language(language)
+ return (can_speak_language_path && has_language(language, SPOKEN_LANGUAGE))
/// Returns selected language if it can be spoken, or decides, sets and returns a new selected language if possible.
/datum/language_holder/proc/get_selected_language()
@@ -172,59 +180,79 @@ Key procs
/datum/language_holder/proc/get_random_spoken_language()
return pick(spoken_languages)
+/// Gets a random spoken language, trying to get a non-common language.
+/datum/language_holder/proc/get_random_spoken_uncommon_language()
+ var/list/languages_minus_common = assoc_to_keys(spoken_languages) - /datum/language/common
+
+ // They have a language other than common
+ if(length(languages_minus_common))
+ return pick(languages_minus_common)
+
+ // They can only speak common, oh well.
+ else
+ return /datum/language/common
+
/// Opens a language menu reading from the language holder.
/datum/language_holder/proc/open_language_menu(mob/user)
if(!language_menu)
language_menu = new (src)
language_menu.ui_interact(user)
-/// Gets the atom, since we some times need to check if the tongue has limitations.
-/datum/language_holder/proc/get_atom()
- if(owner)
- if(istype(owner, /datum/mind))
- var/datum/mind/M = owner
- return M.current
- return owner
- return FALSE
-
-/// Empties out the atom specific languages and updates them according to the supplied atoms language holder.
-/datum/language_holder/proc/update_atom_languages(atom/movable/thing)
- var/datum/language_holder/from_atom = thing.get_language_holder(FALSE) //Gets the atoms language holder
- if(from_atom == src) //This could happen if called on an atom without a mind.
- return FALSE
- for(var/language in understood_languages)
- remove_language(language, TRUE, FALSE, LANGUAGE_ATOM)
- for(var/language in spoken_languages)
- remove_language(language, FALSE, TRUE, LANGUAGE_ATOM)
- for(var/language in blocked_languages)
- remove_blocked_language(language, LANGUAGE_ATOM)
-
- copy_languages(from_atom)
- get_selected_language()
- return TRUE
-
/// Copies all languages from the supplied atom/language holder. Source should be overridden when you
/// do not want the language overwritten by later atom updates or want to avoid blocked languages.
-/datum/language_holder/proc/copy_languages(var/datum/language_holder/from_holder, source_override)
- if(source_override) //No blocked languages here, for now only used by ling absorb.
+/datum/language_holder/proc/copy_languages(datum/language_holder/from_holder, source_override)
+ if(source_override) //No blocked languages here, for now only used by ling absorb.
for(var/language in from_holder.understood_languages)
- grant_language(language, TRUE, FALSE, source_override)
+ grant_language(language, UNDERSTOOD_LANGUAGE, source_override)
for(var/language in from_holder.spoken_languages)
- grant_language(language, FALSE, TRUE, source_override)
+ grant_language(language, SPOKEN_LANGUAGE, source_override)
else
for(var/language in from_holder.understood_languages)
- grant_language(language, TRUE, FALSE, from_holder.understood_languages[language])
+ grant_language(language, UNDERSTOOD_LANGUAGE, from_holder.understood_languages[language])
for(var/language in from_holder.spoken_languages)
- grant_language(language, FALSE, TRUE, from_holder.spoken_languages[language])
+ grant_language(language, SPOKEN_LANGUAGE, from_holder.spoken_languages[language])
for(var/language in from_holder.blocked_languages)
add_blocked_language(language, from_holder.blocked_languages[language])
return TRUE
+/// Transfers all mind languages to the supplied language holder.
+/datum/language_holder/proc/transfer_mind_languages(datum/language_holder/to_holder)
+ for(var/language in understood_languages)
+ if(LANGUAGE_MIND in understood_languages[language])
+ remove_language(language, UNDERSTOOD_LANGUAGE, LANGUAGE_MIND)
+ to_holder.grant_language(language, UNDERSTOOD_LANGUAGE, LANGUAGE_MIND)
+ for(var/language in spoken_languages)
+ if(LANGUAGE_MIND in spoken_languages[language])
+ remove_language(language, SPOKEN_LANGUAGE, LANGUAGE_MIND)
+ to_holder.grant_language(language, SPOKEN_LANGUAGE, LANGUAGE_MIND)
+ for(var/language in blocked_languages)
+ if(LANGUAGE_MIND in blocked_languages[language])
+ remove_blocked_language(language, LANGUAGE_MIND)
+ to_holder.add_blocked_language(language, LANGUAGE_MIND)
-//************************************************
-//* Specific language holders *
-//* Use atom language sources only. *
-//************************************************/
+ if(owner)
+ get_selected_language()
+ if(to_holder.owner)
+ to_holder.get_selected_language()
+
+/// A global assoc list containing prototypes of all language holders
+/// [Language holder typepath] to [language holder instance]
+/// Used for easy reference of what can speak what without needing to constantly recreate language holders.
+GLOBAL_LIST_INIT(prototype_language_holders, init_language_holder_prototypes())
+
+/// Inits the global list of language holder prototypes.
+/proc/init_language_holder_prototypes()
+ var/list/prototypes = list()
+ for(var/holdertype in typesof(/datum/language_holder))
+ prototypes[holdertype] = new holdertype()
+
+ return prototypes
+
+/*
+ * Specific language holders presets
+ *
+ * Prefer to use [LANGUGAE_ATOM]. Atom languages will stick through species changes but not mindswaps.
+ */
/datum/language_holder/alien
@@ -252,6 +280,10 @@ Key procs
/datum/language_holder/drone/syndicate
blocked_languages = null
+/datum/language_holder/human_basic
+ understood_languages = list(/datum/language/common = list(LANGUAGE_ATOM))
+ spoken_languages = list(/datum/language/common = list(LANGUAGE_ATOM))
+
/datum/language_holder/dwarf
understood_languages = list(/datum/language/common = list(LANGUAGE_ATOM),
/datum/language/dwarf = list(LANGUAGE_ATOM))
@@ -352,8 +384,12 @@ Key procs
/datum/language/arachnid = list(LANGUAGE_ATOM))
/datum/language_holder/empty
- understood_languages = list()
- spoken_languages = list()
+ understood_languages = null
+ spoken_languages = null
+
+/datum/language_holder/universal
+ understood_languages = null
+ spoken_languages = null
/datum/language_holder/universal/New()
..()
diff --git a/code/modules/language/language_menu.dm b/code/modules/language/language_menu.dm
index bffd3d59af..0bfb7a7997 100644
--- a/code/modules/language/language_menu.dm
+++ b/code/modules/language/language_menu.dm
@@ -20,109 +20,108 @@
/datum/language_menu/ui_data(mob/user)
var/list/data = list()
- var/atom/movable/AM = language_holder.get_atom()
- if(isliving(AM))
- data["is_living"] = TRUE
- else
- data["is_living"] = FALSE
-
+ var/atom/movable/speaker = language_holder.owner
+ data["is_living"] = isliving(speaker)
data["languages"] = list()
- for(var/lang in GLOB.all_languages)
- var/result = language_holder.has_language(lang) || language_holder.has_language(lang, TRUE)
+ for(var/datum/language/language as anything in GLOB.all_languages)
+ var/result = language_holder.has_language(language) || language_holder.has_language(language, SPOKEN_LANGUAGE)
if(!result)
continue
- var/datum/language/language = lang
- var/list/L = list()
+ var/list/lang_data = list()
- L["name"] = initial(language.name)
- L["desc"] = initial(language.desc)
- L["key"] = initial(language.key)
- L["is_default"] = (language == language_holder.selected_language)
- if(AM)
- L["can_speak"] = AM.can_speak_language(language)
- L["can_understand"] = AM.has_language(language)
+ lang_data["name"] = initial(language.name)
+ lang_data["desc"] = initial(language.desc)
+ lang_data["key"] = initial(language.key)
+ lang_data["is_default"] = (language == language_holder.selected_language)
+ if(speaker)
+ lang_data["can_speak"] = speaker.can_speak_language(language)
+ lang_data["can_understand"] = speaker.has_language(language)
- data["languages"] += list(L)
+ UNTYPED_LIST_ADD(data["languages"], lang_data)
- if(check_rights_for(user.client, R_ADMIN) || isobserver(AM))
+ if(check_rights_for(user.client, R_ADMIN) || isobserver(speaker))
data["admin_mode"] = TRUE
data["omnitongue"] = language_holder.omnitongue
-
data["unknown_languages"] = list()
- for(var/lang in GLOB.all_languages)
- if(language_holder.has_language(lang) || language_holder.has_language(lang, TRUE))
+ for(var/datum/language/language as anything in GLOB.all_languages)
+ if(language_holder.has_language(language) || language_holder.has_language(language, SPOKEN_LANGUAGE))
continue
- var/datum/language/language = lang
- var/list/L = list()
+ var/list/lang_data = list()
- L["name"] = initial(language.name)
- L["desc"] = initial(language.desc)
- L["key"] = initial(language.key)
+ lang_data["name"] = initial(language.name)
+ lang_data["desc"] = initial(language.desc)
+ lang_data["key"] = initial(language.key)
+
+ UNTYPED_LIST_ADD(data["unknown_languages"], lang_data)
- data["unknown_languages"] += list(L)
return data
/datum/language_menu/ui_act(action, params)
- if(..())
+ . = ..()
+ if(.)
return
var/mob/user = usr
- var/atom/movable/AM = language_holder.get_atom()
-
+ var/atom/movable/speaker = language_holder.owner
+ var/is_admin = check_rights_for(user.client, R_ADMIN)
var/language_name = params["language_name"]
var/datum/language/language_datum
- for(var/lang in GLOB.all_languages)
- var/datum/language/language = lang
+ for(var/datum/language/language as anything in GLOB.all_languages)
if(language_name == initial(language.name))
language_datum = language
- var/is_admin = check_rights_for(user.client, R_ADMIN)
switch(action)
if("select_default")
- if(language_datum && AM.can_speak_language(language_datum))
+ if(language_datum && speaker.can_speak_language(language_datum))
language_holder.selected_language = language_datum
. = TRUE
if("grant_language")
- if((is_admin || isobserver(AM)) && language_datum)
+ if((is_admin || isobserver(speaker)) && language_datum)
var/list/choices = list("Only Spoken", "Only Understood", "Both")
- var/choice = input(user,"How do you want to add this language?","[language_datum]",null) as null|anything in choices
- var/spoken = FALSE
- var/understood = FALSE
+ var/choice = tgui_input_list(user, "How do you want to add this language?", "[language_datum]", choices)
+ if(isnull(choice))
+ return
+ var/adding_flags = NONE
switch(choice)
if("Only Spoken")
- spoken = TRUE
+ adding_flags |= SPOKEN_LANGUAGE
if("Only Understood")
- understood = TRUE
+ adding_flags |= UNDERSTOOD_LANGUAGE
if("Both")
- spoken = TRUE
- understood = TRUE
- language_holder.grant_language(language_datum, understood, spoken)
+ adding_flags |= ALL
+
+ if(LAZYACCESS(language_holder.blocked_languages, language_datum))
+ choice = tgui_alert(user, "Do you want to lift the blockage that's also preventing the language to be spoken or understood?", "[language_datum]", list("Yes", "No"))
+ if(choice == "Yes")
+ language_holder.remove_blocked_language(language_datum, LANGUAGE_ALL)
+ language_holder.grant_language(language_datum, adding_flags)
if(is_admin)
- message_admins("[key_name_admin(user)] granted the [language_name] language to [key_name_admin(AM)].")
- log_admin("[key_name(user)] granted the language [language_name] to [key_name(AM)].")
+ message_admins("[key_name_admin(user)] granted the [language_name] language to [key_name_admin(speaker)].")
+ log_admin("[key_name(user)] granted the language [language_name] to [key_name(speaker)].")
. = TRUE
if("remove_language")
- if((is_admin || isobserver(AM)) && language_datum)
+ if((is_admin || isobserver(speaker)) && language_datum)
var/list/choices = list("Only Spoken", "Only Understood", "Both")
- var/choice = input(user,"Which part do you wish to remove?","[language_datum]",null) as null|anything in choices
- var/spoken = FALSE
- var/understood = FALSE
+ var/choice = tgui_input_list(user, "Which part do you wish to remove?", "[language_datum]", choices)
+ if(isnull(choice))
+ return
+ var/removing_flags = NONE
switch(choice)
if("Only Spoken")
- spoken = TRUE
+ removing_flags |= SPOKEN_LANGUAGE
if("Only Understood")
- understood = TRUE
+ removing_flags |= UNDERSTOOD_LANGUAGE
if("Both")
- spoken = TRUE
- understood = TRUE
- language_holder.remove_language(language_datum, understood, spoken)
+ removing_flags |= ALL
+
+ language_holder.remove_language(language_datum, removing_flags)
if(is_admin)
- message_admins("[key_name_admin(user)] removed the [language_name] language to [key_name_admin(AM)].")
- log_admin("[key_name(user)] removed the language [language_name] to [key_name(AM)].")
+ message_admins("[key_name_admin(user)] removed the [language_name] language to [key_name_admin(speaker)].")
+ log_admin("[key_name(user)] removed the language [language_name] to [key_name(speaker)].")
. = TRUE
if("toggle_omnitongue")
- if(is_admin || isobserver(AM))
+ if(is_admin || isobserver(speaker))
language_holder.omnitongue = !language_holder.omnitongue
if(is_admin)
- message_admins("[key_name_admin(user)] [language_holder.omnitongue ? "enabled" : "disabled"] the ability to speak all languages (that they know) of [key_name_admin(AM)].")
- log_admin("[key_name(user)] [language_holder.omnitongue ? "enabled" : "disabled"] the ability to speak all languages (that_they know) of [key_name(AM)].")
+ message_admins("[key_name_admin(user)] [language_holder.omnitongue ? "enabled" : "disabled"] the ability to speak all languages (that they know) of [key_name_admin(speaker)].")
+ log_admin("[key_name(user)] [language_holder.omnitongue ? "enabled" : "disabled"] the ability to speak all languages (that_they know) of [key_name(speaker)].")
. = TRUE
diff --git a/code/modules/mining/lavaland/necropolis_chests.dm b/code/modules/mining/lavaland/necropolis_chests.dm
index 9aacbb9a3d..7d44697b10 100644
--- a/code/modules/mining/lavaland/necropolis_chests.dm
+++ b/code/modules/mining/lavaland/necropolis_chests.dm
@@ -666,6 +666,7 @@
/obj/item/book_of_babel/attack_self(mob/user)
to_chat(user, "You flip through the pages of the book, quickly and conveniently learning every language in existence. Somewhat less conveniently, the aging book crumbles to dust in the process. Whoops.")
user.grant_all_languages()
+ user.remove_blocked_language(GLOB.all_languages, source = LANGUAGE_ALL)
new /obj/effect/decal/cleanable/ash(get_turf(user))
qdel(src)
diff --git a/code/modules/mob/dead/dead.dm b/code/modules/mob/dead/dead.dm
index b455787e5c..f9631209f2 100644
--- a/code/modules/mob/dead/dead.dm
+++ b/code/modules/mob/dead/dead.dm
@@ -89,20 +89,20 @@ INITIALIZE_IMMEDIATE(/mob/dead)
if(alert(src, "Jump to server [pick] ([addr])?", "Server Hop", "Yes", "No") != "Yes")
return
- var/client/C = client
- to_chat(C, "Sending you to [pick].")
- new /atom/movable/screen/splash(C)
+ var/client/hopper = client
+ to_chat(hopper, "Sending you to [pick].")
+ new /atom/movable/screen/splash(null, src, hopper, FALSE)
mob_transforming = TRUE
- sleep(29) //let the animation play
+ sleep(2.9 SECONDS) //let the animation play
mob_transforming = FALSE
- if(!C)
+ if(!hopper)
return
winset(src, null, "command=.options") //other wise the user never knows if byond is downloading resources
- C << link("[addr]")
+ hopper << link("[addr]")
/mob/dead/proc/update_z(new_z) // 1+ to register, null to unregister
if (registered_z != new_z)
diff --git a/code/modules/mob/dead/new_player/login.dm b/code/modules/mob/dead/new_player/login.dm
index e40b467a79..2253e81814 100644
--- a/code/modules/mob/dead/new_player/login.dm
+++ b/code/modules/mob/dead/new_player/login.dm
@@ -41,7 +41,3 @@
else
postfix = "soon"
to_chat(src, "Please set up your character and select \"Ready\". The game will start [postfix].")
-
- var/datum/hud/new_player/NH = hud_used
- if(istype(NH))
- NH.populate_buttons(src)
diff --git a/code/modules/mob/dead/new_player/new_player.dm b/code/modules/mob/dead/new_player/new_player.dm
index fb2c8b6434..a2f02ae6b5 100644
--- a/code/modules/mob/dead/new_player/new_player.dm
+++ b/code/modules/mob/dead/new_player/new_player.dm
@@ -27,7 +27,7 @@
/mob/dead/new_player/Initialize(mapload)
if(client && SSticker.state == GAME_STATE_STARTUP)
- var/atom/movable/screen/splash/S = new(client, TRUE, TRUE)
+ var/atom/movable/screen/splash/S = new(null, null, client, TRUE)
S.Fade(TRUE)
if(length(GLOB.newplayer_start))
@@ -491,7 +491,7 @@
if(job && !job.override_latejoin_spawn(character))
SSjob.SendToLateJoin(character)
if(!arrivals_docked)
- var/atom/movable/screen/splash/Spl = new(character.client, TRUE)
+ var/atom/movable/screen/splash/Spl = new(null, character, character.client, TRUE)
Spl.Fade(TRUE)
character.playsound_local(get_turf(character), 'sound/voice/ApproachingTG.ogg', 25)
diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm
index ab36cebd34..2b52bb3a0b 100644
--- a/code/modules/mob/living/carbon/human/human_defines.dm
+++ b/code/modules/mob/living/carbon/human/human_defines.dm
@@ -6,6 +6,7 @@
can_buckle = TRUE
buckle_lying = FALSE
mob_biotypes = MOB_ORGANIC|MOB_HUMANOID
+ initial_language_holder = /datum/language_holder/empty // We get stuff from our species
/// Enable stamina combat
combat_flags = COMBAT_FLAGS_STAMINA_COMBAT | COMBAT_FLAG_UNARMED_PARRY
status_flags = CANSTUN|CANKNOCKDOWN|CANUNCONSCIOUS|CANPUSH|CANSTAGGER
diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm
index ad0d6382fb..fb6336a4cf 100644
--- a/code/modules/mob/living/carbon/human/species.dm
+++ b/code/modules/mob/living/carbon/human/species.dm
@@ -90,8 +90,10 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
var/dangerous_existence //A flag for transformation spells that tells them "hey if you turn a person into one of these without preperation, they'll probably die!"
///Affects the speech message, for example: Motharula flutters, "My speech message is flutters!"
var/say_mod = "says"
- ///What languages this species can understand and say. Use a [language holder datum][/datum/language_holder] in this var.
- var/species_language_holder = /datum/language_holder
+ /// What languages this species can understand and say.
+ /// Use a [language holder datum][/datum/language_holder] typepath in this var.
+ /// Should never be null.
+ var/datum/language_holder/species_language_holder = /datum/language_holder/human_basic
/**
* Visible CURRENT bodyparts that are unique to a species.
* DO NOT USE THIS AS A LIST OF ALL POSSIBLE BODYPARTS AS IT WILL FUCK
@@ -556,6 +558,16 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
for(var/obj/item/bodypart/B in C.bodyparts)
B.change_bodypart_status(BODYPART_HYBRID, FALSE, TRUE) // Makes all Bodyparts 'robotic'.
+ // All languages associated with this language holder are added with source [LANGUAGE_SPECIES]
+ // rather than source [LANGUAGE_ATOM], so we can track what to remove if our species changes again
+ var/datum/language_holder/gaining_holder = GLOB.prototype_language_holders[species_language_holder]
+ for(var/language in gaining_holder.understood_languages)
+ C.grant_language(language, UNDERSTOOD_LANGUAGE, LANGUAGE_SPECIES)
+ for(var/language in gaining_holder.spoken_languages)
+ C.grant_language(language, SPOKEN_LANGUAGE, LANGUAGE_SPECIES)
+ for(var/language in gaining_holder.blocked_languages)
+ C.add_blocked_language(language, LANGUAGE_SPECIES)
+
SEND_SIGNAL(C, COMSIG_SPECIES_GAIN, src, old_species)
/datum/species/proc/update_species_slowdown(mob/living/carbon/human/H)
diff --git a/code/modules/mob/living/carbon/human/status_procs.dm b/code/modules/mob/living/carbon/human/status_procs.dm
index ec961da4dd..697e3a257f 100644
--- a/code/modules/mob/living/carbon/human/status_procs.dm
+++ b/code/modules/mob/living/carbon/human/status_procs.dm
@@ -34,11 +34,11 @@
/mob/living/carbon/human/set_drugginess(amount)
..()
if(!amount)
- remove_language(/datum/language/beachbum, TRUE, TRUE, LANGUAGE_HIGH)
+ remove_language(/datum/language/beachbum, source = LANGUAGE_HIGH)
/mob/living/carbon/human/adjust_drugginess(amount)
..()
if(druggy)
- grant_language(/datum/language/beachbum, TRUE, TRUE, LANGUAGE_HIGH)
+ grant_language(/datum/language/beachbum, source = LANGUAGE_HIGH)
else
- remove_language(/datum/language/beachbum, TRUE, TRUE, LANGUAGE_HIGH)
+ remove_language(/datum/language/beachbum, source = LANGUAGE_HIGH)
diff --git a/code/modules/mob/living/say.dm b/code/modules/mob/living/say.dm
index 9d8a388a86..6eb9d31e8c 100644
--- a/code/modules/mob/living/say.dm
+++ b/code/modules/mob/living/say.dm
@@ -500,8 +500,3 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
// End of Skyrat edits
/mob/living/whisper(message, bubble_type, list/spans = list(), sanitize = TRUE, datum/language/language = null, ignore_spam = FALSE, forced = null)
say("#[message]", bubble_type, spans, sanitize, language, ignore_spam, forced)
-
-/mob/living/get_language_holder(get_minds = TRUE)
- if(get_minds && mind)
- return mind.get_language_holder()
- . = ..()
diff --git a/code/modules/mob/living/silicon/pai/pai.dm b/code/modules/mob/living/silicon/pai/pai.dm
index 1a97c60618..926a9c5d27 100644
--- a/code/modules/mob/living/silicon/pai/pai.dm
+++ b/code/modules/mob/living/silicon/pai/pai.dm
@@ -139,13 +139,11 @@
var/datum/action/innate/pai/light/AL = new /datum/action/innate/pai/light
var/datum/action/innate/custom_holoform/custom_holoform = new /datum/action/innate/custom_holoform
- var/datum/action/language_menu/ALM = new
SW.Grant(src)
AS.Grant(src)
AC.Grant(src)
AR.Grant(src)
AL.Grant(src)
- ALM.Grant(src)
custom_holoform.Grant(src)
emitter_next_use = world.time + 10 SECONDS
diff --git a/code/modules/mob/living/silicon/pai/software.dm b/code/modules/mob/living/silicon/pai/software.dm
index ad7bc79278..38859a7a93 100644
--- a/code/modules/mob/living/silicon/pai/software.dm
+++ b/code/modules/mob/living/silicon/pai/software.dm
@@ -268,7 +268,7 @@
encryptmod = TRUE
if("translator")
if(href_list["toggle"]) //This is permanent.
- grant_all_languages(TRUE, TRUE, TRUE, LANGUAGE_SOFTWARE)
+ grant_all_languages(source = LANGUAGE_SOFTWARE)
if("doorjack")
if(href_list["jack"])
if(cable && cable.machine)
diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm
index d8b90110a1..d58045633d 100644
--- a/code/modules/mob/living/silicon/robot/robot.dm
+++ b/code/modules/mob/living/silicon/robot/robot.dm
@@ -24,9 +24,9 @@
robot_modules_background.layer = HUD_LAYER //Objects that appear on screen are on layer ABOVE_HUD_LAYER, UI should be just below it.
robot_modules_background.plane = HUD_PLANE
- inv1 = new /atom/movable/screen/robot/module1()
- inv2 = new /atom/movable/screen/robot/module2()
- inv3 = new /atom/movable/screen/robot/module3()
+ inv1 = new /atom/movable/screen/robot/module1(null, src)
+ inv2 = new /atom/movable/screen/robot/module2(null, src)
+ inv3 = new /atom/movable/screen/robot/module3(null, src)
ident = rand(1, 999)
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index 998d0ee923..f13acdb8eb 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -986,12 +986,11 @@ GLOBAL_VAR_INIT(exploit_warn_spam_prevention, 0)
//Do not do parent's actions, as we *usually* do this differently.
fully_replace_character_name(real_name, new_name)
-/mob/verb/open_language_menu()
+/mob/verb/open_language_menu_verb()
set name = "Open Language Menu"
set category = "IC"
- var/datum/language_holder/H = get_language_holder()
- H.open_language_menu(usr)
+ get_language_holder().open_language_menu(usr)
///Adjust the nutrition of a mob
/mob/proc/adjust_nutrition(change, max = INFINITY) //Honestly FUCK the oldcoders for putting nutrition on /mob someone else can move it up because holy hell I'd have to fix SO many typechecks
diff --git a/code/modules/mob/transform_procs.dm b/code/modules/mob/transform_procs.dm
index 48faeafd48..9352d191dd 100644
--- a/code/modules/mob/transform_procs.dm
+++ b/code/modules/mob/transform_procs.dm
@@ -436,7 +436,6 @@
mind.transfer_to(new_xeno)
else
transfer_ckey(new_xeno)
- update_atom_languages()
to_chat(new_xeno, "You are now an alien.")
. = new_xeno
diff --git a/code/modules/research/xenobiology/crossbreeding/_status_effects.dm b/code/modules/research/xenobiology/crossbreeding/_status_effects.dm
index 5d46329462..977d210bc6 100644
--- a/code/modules/research/xenobiology/crossbreeding/_status_effects.dm
+++ b/code/modules/research/xenobiology/crossbreeding/_status_effects.dm
@@ -980,7 +980,6 @@
familiar.copy_languages(owner, LANGUAGE_MASTER)
if(linked.saved_mind)
linked.saved_mind.transfer_to(familiar)
- familiar.update_atom_languages()
familiar.ckey = linked.saved_mind.key
else
if(familiar.mind)
diff --git a/code/modules/ruins/spaceruin_code/TheDerelict.dm b/code/modules/ruins/spaceruin_code/TheDerelict.dm
index d26e023df0..cae5c53090 100644
--- a/code/modules/ruins/spaceruin_code/TheDerelict.dm
+++ b/code/modules/ruins/spaceruin_code/TheDerelict.dm
@@ -159,7 +159,7 @@
to_chat(user, "You start skimming through [src], but you already know dronespeak.")
else
to_chat(user, "You start skimming through [src], and suddenly the drone chittering makes sense.")
- user.grant_language(/datum/language/drone, TRUE, TRUE)//, LANGUAGE_MIND)
+ user.grant_language(/datum/language/drone, source = LANGUAGE_MIND)
return
if(user.has_language(/datum/language/drone))
@@ -180,7 +180,7 @@
M.visible_message("[user] beats [M] over the head with [src]!", "[user] beats you over the head with [src]!", "You hear smacking.")
else
M.visible_message("[user] teaches [M] by beating [M.p_them()] over the head with [src]!", "As [user] hits you with [src], chitters resonate in your mind.", "You hear smacking.")
- M.grant_language(/datum/language/drone, TRUE, TRUE) //, LANGUAGE_MIND)
+ M.grant_language(/datum/language/drone, source = LANGUAGE_MIND)
return
/obj/structure/fluff/oldturret
diff --git a/code/modules/tgui/states/language_menu.dm b/code/modules/tgui/states/language_menu.dm
index eaaa125786..1786175f05 100644
--- a/code/modules/tgui/states/language_menu.dm
+++ b/code/modules/tgui/states/language_menu.dm
@@ -14,6 +14,6 @@ GLOBAL_DATUM_INIT(language_menu_state, /datum/ui_state/language_menu, new)
if(check_rights_for(user.client, R_ADMIN))
. = UI_INTERACTIVE
else if(istype(src_object, /datum/language_menu))
- var/datum/language_menu/LM = src_object
- if(LM.language_holder.get_atom() == user)
+ var/datum/language_menu/my_languages = src_object
+ if(my_languages.language_holder.owner == user)
. = UI_INTERACTIVE
diff --git a/code/modules/unit_tests/_unit_tests.dm b/code/modules/unit_tests/_unit_tests.dm
index df5d6703cf..00142e3f9f 100644
--- a/code/modules/unit_tests/_unit_tests.dm
+++ b/code/modules/unit_tests/_unit_tests.dm
@@ -67,6 +67,7 @@
// #include "holidays.dm"
// #include "hydroponics_harvest.dm"
// #include "keybinding_init.dm"
+// #include "language_transfer.dm"
#include "machine_disassembly.dm"
#include "medical_wounds.dm"
#include "merge_type.dm"
diff --git a/code/modules/unit_tests/language_transfer.dm b/code/modules/unit_tests/language_transfer.dm
new file mode 100644
index 0000000000..7e031f3a8b
--- /dev/null
+++ b/code/modules/unit_tests/language_transfer.dm
@@ -0,0 +1,191 @@
+// Dedicated to testing language holders
+
+/// Simply tests that swapping to a new species gives you the languages of that species and removes the languages of the old species
+/datum/unit_test/language_species_swap_simple
+
+/datum/unit_test/language_species_swap_simple/Run()
+ var/mob/living/carbon/human/dummy = allocate(/mob/living/carbon/human/consistent)
+
+ var/datum/language_holder/holder = dummy.get_language_holder()
+
+ var/list/initial_spoken = holder.spoken_languages.Copy()
+ var/list/initial_understood = holder.understood_languages.Copy()
+
+ TEST_ASSERT(length(initial_spoken) == 1, \
+ "Dummy should only speak one language! Instead, it knew the following: [print_language_list(initial_spoken)]")
+ TEST_ASSERT(length(initial_understood) == 1, \
+ "Dummy should only understand one language! Instead, it knew the following: [print_language_list(initial_understood)]")
+
+ dummy.set_species(/datum/species/lizard)
+
+ TEST_ASSERT(length(holder.spoken_languages) == 2, \
+ "Dummy should speak two languages - Common and Draconic! Instead, it knew the following: [print_language_list(holder.spoken_languages)]")
+
+ TEST_ASSERT(length(holder.understood_languages) == 2, \
+ "Dummy should understand two languages - Common and Draconic! Instead, it knew the following: [print_language_list(holder.understood_languages)]")
+
+ dummy.set_species(/datum/species/human)
+
+ TEST_ASSERT(length(initial_spoken & holder.spoken_languages) == 1, \
+ "Dummy did not speak Common after returning to human! Instead, it knew the following: [print_language_list(holder.spoken_languages)]")
+
+ TEST_ASSERT(length(initial_understood & holder.understood_languages) == 1, \
+ "Dummy did not understand Common after returning to human! Instead, it knew the following: [print_language_list(holder.understood_languages)]")
+
+/// Tests species changes which are more complex are functional (e.g. from a species which speaks common to one which does not)
+/datum/unit_test/language_species_swap_complex
+
+/datum/unit_test/language_species_swap_complex/Run()
+ var/mob/living/carbon/human/dummy = allocate(/mob/living/carbon/human/consistent)
+
+ var/datum/language_holder/holder = dummy.get_language_holder()
+
+ dummy.set_species(/datum/species/lizard/silverscale)
+
+ TEST_ASSERT(!dummy.has_language(/datum/language/common, SPOKEN_LANGUAGE), \
+ "Changing a mob's species from one which speaks common to one which does not should remove the language!")
+
+ TEST_ASSERT(dummy.has_language(/datum/language/common, UNDERSTOOD_LANGUAGE), \
+ "Changing a mob's species from one which understands common another which does should not remove the language!")
+
+ TEST_ASSERT(length(holder.spoken_languages) == 2, \
+ "Dummy should speak two languages - Uncommon and Draconic! Instead, it knew the following: [print_language_list(holder.spoken_languages)]")
+
+ TEST_ASSERT(length(holder.understood_languages) == 3, \
+ "Dummy should understand two languages - Common, Uncommon and Draconic! Instead, it knew the following: [print_language_list(holder.understood_languages)]")
+
+/// Test that other random languages known are not lost on species change
+/datum/unit_test/language_species_change_other_known
+
+/datum/unit_test/language_species_change_other_known/Run()
+ var/mob/living/carbon/human/dummy = allocate(/mob/living/carbon/human/consistent)
+ dummy.grant_language(/datum/language/piratespeak, source = LANGUAGE_MIND)
+ dummy.grant_language(/datum/language/draconic, source = LANGUAGE_ATOM)
+ dummy.set_species(/datum/species/lizard)
+
+ TEST_ASSERT(dummy.has_language(/datum/language/piratespeak, SPOKEN_LANGUAGE), \
+ "Dummy should still speak Pirate after changing species, as it's a mind language!")
+
+ TEST_ASSERT(dummy.has_language(/datum/language/piratespeak, UNDERSTOOD_LANGUAGE), \
+ "Dummy should still understand Pirate after changing species, as it's a mind language!")
+
+ dummy.set_species(/datum/species/human)
+
+ TEST_ASSERT(dummy.has_language(/datum/language/draconic, SPOKEN_LANGUAGE), \
+ "Dummy should still speak Draconic after changing species, as it's an atom language!")
+
+ TEST_ASSERT(dummy.has_language(/datum/language/draconic, UNDERSTOOD_LANGUAGE), \
+ "Dummy should still understand Draconic after changing species, as it's an atom language!")
+
+/// Tests that mind bound languages are not lost swapping into a new mob, but other languages are
+/datum/unit_test/language_mind_transfer
+
+/datum/unit_test/language_mind_transfer/Run()
+ var/mob/living/carbon/human/dummy = allocate(/mob/living/carbon/human/consistent)
+ var/mob/living/basic/pet/dog/corgi/transfer_target = allocate(/mob/living/basic/pet/dog/corgi)
+ dummy.mind_initialize()
+ dummy.grant_language(/datum/language/piratespeak, source = LANGUAGE_MIND)
+ dummy.grant_language(/datum/language/draconic, source = LANGUAGE_ATOM)
+ dummy.set_species(/datum/species/lizard/silverscale)
+
+ dummy.mind.transfer_to(transfer_target)
+
+ // transfer_target should speak and understand pirate
+ TEST_ASSERT(!dummy.has_language(/datum/language/piratespeak, SPOKEN_LANGUAGE), \
+ "Dummy should no longer be speaking Pirate after losing their mind!")
+ TEST_ASSERT(transfer_target.has_language(/datum/language/piratespeak, SPOKEN_LANGUAGE), \
+ "Dummy's new mob should be capable of speaking Pirate!")
+
+ TEST_ASSERT(!dummy.has_language(/datum/language/piratespeak, UNDERSTOOD_LANGUAGE), \
+ "Dummy should no longer be understanding Pirate after losing their mind!")
+ TEST_ASSERT(transfer_target.has_language(/datum/language/piratespeak, UNDERSTOOD_LANGUAGE), \
+ "Dummy's new mob should be capable of understanding Pirate!")
+
+ // transfer_target should NOT speak and understand draconic
+ TEST_ASSERT(dummy.has_language(/datum/language/draconic, SPOKEN_LANGUAGE), \
+ "Dummy should still understand Draconic after losing their mind - it's an atom language!")
+ TEST_ASSERT(!transfer_target.has_language(/datum/language/draconic, SPOKEN_LANGUAGE), \
+ "Dummy's new mob should not understand Draconic - it's an atom language!")
+
+ TEST_ASSERT(dummy.has_language(/datum/language/draconic, UNDERSTOOD_LANGUAGE), \
+ "Dummy should still understand Draconic after losing their mind - it's an atom language!")
+ TEST_ASSERT(!transfer_target.has_language(/datum/language/draconic, UNDERSTOOD_LANGUAGE), \
+ "Dummy's new mob should not understand Draconic - it's an atom language!")
+
+ // transfer_target should NOT speak and understand uncommon
+ TEST_ASSERT(dummy.has_language(/datum/language/uncommon, SPOKEN_LANGUAGE), \
+ "Dummy should still understand Uncommon after losing their mind - it's a species language!")
+ TEST_ASSERT(!transfer_target.has_language(/datum/language/uncommon, SPOKEN_LANGUAGE), \
+ "Dummy's new mob should not understand Uncommon - it's a species language!")
+
+ TEST_ASSERT(dummy.has_language(/datum/language/uncommon, UNDERSTOOD_LANGUAGE), \
+ "Dummy should still understand Uncommon after losing their mind - it's a species language!")
+ TEST_ASSERT(!transfer_target.has_language(/datum/language/uncommon, UNDERSTOOD_LANGUAGE), \
+ "Dummy's new mob should not understand Uncommon - it's a species language!")
+
+/// Tests that mind bound languages are not lost when swapping with another person (wiz mindswap)
+/datum/unit_test/language_mind_swap
+
+/datum/unit_test/language_mind_swap/Run()
+ var/mob/living/carbon/human/dummy_A = allocate(/mob/living/carbon/human/consistent)
+ var/mob/living/carbon/human/dummy_B = allocate(/mob/living/carbon/human/consistent)
+
+ dummy_A.mind_initialize()
+ dummy_B.mind_initialize()
+
+ var/datum/mind/dummy_A_mind = dummy_A.mind
+ var/datum/mind/dummy_B_mind = dummy_B.mind
+
+ dummy_A.set_species(/datum/species/lizard)
+ dummy_B.grant_language(/datum/language/piratespeak, source = LANGUAGE_MIND)
+
+ dummy_A_mind.transfer_to(dummy_B)
+ dummy_B_mind.transfer_to(dummy_A)
+
+ var/datum/language_holder/holder_A = dummy_A.get_language_holder()
+ var/datum/language_holder/holder_B = dummy_B.get_language_holder()
+
+ // Holder A is a lizard: starts with 2 languages (common, draconic)
+ // Holder B is a human with a mind language: starts with 2 language (common, pirate)
+ // Swap occurs
+ // Holder A is a lizard with 2 languages, but should now also have pirate: 3 languages (common, draconic, pirate)
+ // Holder B is a human with just 1 language left over (common)
+
+ TEST_ASSERT_EQUAL(length(holder_A.spoken_languages), 3, \
+ "Holder A / Dummy A / Dummy B mind should speak Common, Draconic, and Pirate! \
+ Instead, it knew the following: [print_language_list(holder_A.spoken_languages)]")
+
+ TEST_ASSERT_EQUAL(length(holder_A.understood_languages), 3, \
+ "Holder A / Dummy A / Dummy B mind should only understand Common, Draconic, and Pirate! \
+ Instead, it knew the following: [print_language_list(holder_A.understood_languages)]")
+
+ TEST_ASSERT_EQUAL(length(holder_B.spoken_languages), 1, \
+ "Holder B / Dummy B / Dummy A mind should only speak 1 language - Common! \
+ Instead, it knew the following: [print_language_list(holder_B.spoken_languages)]")
+
+ TEST_ASSERT_EQUAL(length(holder_B.understood_languages), 1, \
+ "Holder B / Dummy B / Dummy A mind only understand 1 language - Common! \
+ Instead, it knew the following: [print_language_list(holder_B.understood_languages)]")
+
+/// Tests that the book of babel, and by extension grant_all_languages, works as intended
+/datum/unit_test/book_of_babel
+
+/datum/unit_test/book_of_babel/Run()
+ var/mob/living/carbon/human/dummy = allocate(/mob/living/carbon/human/consistent)
+ var/obj/item/book_of_babel/book = allocate(/obj/item/book_of_babel)
+ var/datum/language_holder/holder = dummy.get_language_holder()
+ var/expected_amount = length(GLOB.all_languages)
+
+ book.attack_self(dummy)
+ TEST_ASSERT_EQUAL(length(holder.spoken_languages), expected_amount, "Book of Babel failed to give all languages out!")
+ dummy.set_species(/datum/species/lizard)
+ TEST_ASSERT_EQUAL(length(holder.spoken_languages), expected_amount, "Changing species after using the Book of Bable should not remove languages!")
+
+/// Helper proc to print a list of languages in a human readable format
+/proc/print_language_list(list/languages_to_print)
+ var/list/printed_languages = list()
+
+ for(var/datum/language/language as anything in languages_to_print)
+ printed_languages += initial(language.name)
+
+ return english_list(printed_languages)
diff --git a/icons/hud/lobby/background.dmi b/icons/hud/lobby/background.dmi
index 554543ecf3..5fb9085da0 100644
Binary files a/icons/hud/lobby/background.dmi and b/icons/hud/lobby/background.dmi differ
diff --git a/icons/hud/lobby/collapse_expand.dmi b/icons/hud/lobby/collapse_expand.dmi
index 03f9f02f3d..133a096f94 100644
Binary files a/icons/hud/lobby/collapse_expand.dmi and b/icons/hud/lobby/collapse_expand.dmi differ
diff --git a/icons/hud/lobby/signup_button.dmi b/icons/hud/lobby/signup_button.dmi
new file mode 100644
index 0000000000..26d32e9af8
Binary files /dev/null and b/icons/hud/lobby/signup_button.dmi differ
diff --git a/icons/hud/lobby/start_now.dmi b/icons/hud/lobby/start_now.dmi
new file mode 100644
index 0000000000..ec77059011
Binary files /dev/null and b/icons/hud/lobby/start_now.dmi differ
diff --git a/modular_sand/code/controllers/subsystem/language.dm b/modular_sand/code/controllers/subsystem/language.dm
index 7d04177fe9..be5a4f4797 100644
--- a/modular_sand/code/controllers/subsystem/language.dm
+++ b/modular_sand/code/controllers/subsystem/language.dm
@@ -9,12 +9,12 @@
var/datum/language/language_datum = LAZYACCESS(SSlanguage.languages_by_name, language)
if(language_datum)
if(!language_datum.restricted || (language_datum.name in client.prefs.pref_species.languagewhitelist))
- user.grant_language(language_datum.type, TRUE, TRUE, LANGUAGE_ADDITIONAL)
+ user.grant_language(language_datum.type, source = LANGUAGE_MULTILINGUAL)
LAZYADD(valid_languages, language)
else
for(var/datum/quirk/quirk in client.prefs.all_quirks)
if(language_datum.name in quirk.languagewhitelist)
- user.grant_language(language_datum.type, TRUE, TRUE, LANGUAGE_ADDITIONAL)
+ user.grant_language(language_datum.type, source = LANGUAGE_MULTILINGUAL)
LAZYADD(valid_languages, language)
continue
LAZYADD(invalid_languages, language)
diff --git a/sound/misc/menu/attribution.txt b/sound/misc/menu/attribution.txt
new file mode 100644
index 0000000000..fa89d4cf4c
--- /dev/null
+++ b/sound/misc/menu/attribution.txt
@@ -0,0 +1,6 @@
+ui_select made by sadboysuss
+license: CC-BY-SA
+
+rolldown and rollup are heavily modified of:
+Yunon YN500 Camera Shutter by yfjesse -- https://freesound.org/s/579884/ -- License: Creative Commons 0
+
diff --git a/sound/misc/menu/menu_rolldown1.ogg b/sound/misc/menu/menu_rolldown1.ogg
new file mode 100644
index 0000000000..a59529b4ad
Binary files /dev/null and b/sound/misc/menu/menu_rolldown1.ogg differ
diff --git a/sound/misc/menu/menu_rollup1.ogg b/sound/misc/menu/menu_rollup1.ogg
new file mode 100644
index 0000000000..5f21f3adf0
Binary files /dev/null and b/sound/misc/menu/menu_rollup1.ogg differ
diff --git a/sound/misc/menu/ui_select1.ogg b/sound/misc/menu/ui_select1.ogg
new file mode 100644
index 0000000000..d9b3ac8f61
Binary files /dev/null and b/sound/misc/menu/ui_select1.ogg differ