diff --git a/code/__DEFINES/dcs/signals/atom/mob/signals_mind.dm b/code/__DEFINES/dcs/signals/atom/mob/signals_mind.dm
new file mode 100644
index 0000000000..2cca5fe18c
--- /dev/null
+++ b/code/__DEFINES/dcs/signals/atom/mob/signals_mind.dm
@@ -0,0 +1,2 @@
+///from mind/transfer_to. Sent after the mind has been transferred to a different body: (mob/previous_body)
+#define COMSIG_MIND_TRANSFERRED "mind_transferred"
diff --git a/code/__DEFINES/dcs/signals/atom/mob/signals_mob.dm b/code/__DEFINES/dcs/signals/atom/mob/signals_mob.dm
index 0271cd6334..dd995ba864 100644
--- a/code/__DEFINES/dcs/signals/atom/mob/signals_mob.dm
+++ b/code/__DEFINES/dcs/signals/atom/mob/signals_mob.dm
@@ -72,9 +72,13 @@
#define COMSIG_MOB_PRE_CLICK "mob_pre_click"
#define COMPONENT_INTERRUPT_CLICK (1<<0)
-///from base of /mob/Login(): ()
+/// From base of /mob/Login(), called when a client logs into this mob: ()
+/// Not to be confused with [COMSIG_MOB_LOGGED_IN]
#define COMSIG_MOB_LOGIN "mob_login"
-///from base of /mob/Logout(): ()
+/// From base of /mob/Login(), called after a client logs into this mob: ()
+/// Not to be confused with [COMSIG_MOB_LOGIN]
+#define COMSIG_MOB_LOGGED_IN "mob_logged_in"
+/// From base of /mob/Logout(): ()
#define COMSIG_MOB_LOGOUT "mob_logout"
//from /mob/proc/on_deafness_gain()
diff --git a/code/__DEFINES/dcs/signals/signals_client.dm b/code/__DEFINES/dcs/signals/signals_client.dm
index 6733e07035..e7e74771fc 100644
--- a/code/__DEFINES/dcs/signals/signals_client.dm
+++ b/code/__DEFINES/dcs/signals/signals_client.dm
@@ -19,8 +19,8 @@
/// Called after one or more verbs are added: (list of verbs added)
#define COMSIG_CLIENT_VERB_REMOVED "client_verb_removed"
-/// Called after a client logs into a mob: (mob)
-#define COMSIG_CLIENT_MOB_LOGIN "client_mob_changed"
+/// Called from /mob/Login() after a client logs into a mob: (mob)
+#define COMSIG_CLIENT_MOB_LOGGED_IN "client_mob_logged_in"
/// Called when something is added to a client's screen : /client/proc/add_to_screen(screen_add)
#define COMSIG_CLIENT_SCREEN_ADD "client_screen_add"
diff --git a/code/__DEFINES/dcs/signals/signals_global.dm b/code/__DEFINES/dcs/signals/signals_global.dm
index 89904c5a1b..825f427695 100644
--- a/code/__DEFINES/dcs/signals/signals_global.dm
+++ b/code/__DEFINES/dcs/signals/signals_global.dm
@@ -34,9 +34,11 @@
#define COMSIG_GLOB_REMOVE_VOTE_BUTTON "!remove_vote_button"
-#define COMSIG_GLOB_CLIENT_LOGIN "!client_login"
+/// Called from /client/New() when a client logs in to the game: (client)
+#define COMSIG_GLOB_CLIENT_LOGGED_IN "!client_logged_in"
-#define COMSIG_GLOB_MOB_LOGIN "!mob_login"
+/// Called from /mob/Login() when a client logs into a mob: (mob)
+#define COMSIG_GLOB_MOB_LOGGED_IN "!mob_logged_in"
///from /datum/controller/subsystem/ticker/PostSetup
#define COMSIG_GLOB_POST_SETUP "!post_setup"
diff --git a/code/__DEFINES/sounds.dm b/code/__DEFINES/sounds.dm
index 6c5d2879f3..13a4468427 100644
--- a/code/__DEFINES/sounds.dm
+++ b/code/__DEFINES/sounds.dm
@@ -61,6 +61,9 @@
#define SOUND_ENVIRONMENT_DIZZY 24
#define SOUND_ENVIRONMENT_PSYCHOTIC 25
+#define SOUND_ECHO_REVERB_ON list(0, 0, 0, 0, 0, 0.0, 0, 0.25, 1.5, 1.0, 0, 1.0, 0, 0.0, 0.0, 0.0, 1.0, 0)
+#define SOUND_ECHO_REVERB_OFF list(0, 0, -10000, -10000, 0, 0.0, 0, 0.25, 1.5, 1.0, 0, 1.0, 0, 0.0, 0.0, 0.0, 1.0, 0) //-10000 to Room & RoomHF makes enviromental reverb effectively inaudible
+
#define AMBIENCE_SHIP 'sound/ambience/shipambience.ogg'
#define AMBIENCE_JUNGLE 'sound/ambience/ambienceLV624.ogg'
#define AMBIENCE_RIVER 'sound/ambience/ambienceriver.ogg'
diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm
index d114aff6b7..18587c0545 100644
--- a/code/_onclick/hud/screen_objects.dm
+++ b/code/_onclick/hud/screen_objects.dm
@@ -59,9 +59,11 @@
/atom/movable/screen/action_button/attack_ghost(mob/dead/observer/user)
return
-/atom/movable/screen/action_button/clicked(mob/user)
+/atom/movable/screen/action_button/clicked(mob/user, list/mods)
if(!user || !source_action)
return TRUE
+ if(source_action.owner != user)
+ return TRUE
if(source_action.can_use_action())
source_action.action_activate()
@@ -97,7 +99,7 @@
icon_state = "hide"
var/hidden = 0
-/atom/movable/screen/action_button/hide_toggle/clicked(mob/user, mods)
+/atom/movable/screen/action_button/hide_toggle/clicked(mob/user, list/mods)
user.hud_used.action_buttons_hidden = !user.hud_used.action_buttons_hidden
hidden = user.hud_used.action_buttons_hidden
if(hidden)
@@ -107,7 +109,7 @@
name = "Hide Buttons"
icon_state = "hide"
user.update_action_buttons()
- return 1
+ return TRUE
/atom/movable/screen/action_button/ghost/minimap/get_button_screen_loc(button_number)
return "SOUTH:6,CENTER+1:24"
@@ -214,7 +216,7 @@
/atom/movable/screen/zone_sel/robot
icon = 'icons/mob/hud/screen1_robot.dmi'
-/atom/movable/screen/clicked(mob/user)
+/atom/movable/screen/clicked(mob/user, list/mods)
if(!user)
return TRUE
diff --git a/code/controllers/subsystem/minimap.dm b/code/controllers/subsystem/minimap.dm
index 1c2a6d3e24..a26d024b17 100644
--- a/code/controllers/subsystem/minimap.dm
+++ b/code/controllers/subsystem/minimap.dm
@@ -717,6 +717,7 @@ SUBSYSTEM_DEF(minimaps)
user.client.register_map_obj(map_holder.map)
ui = new(user, src, "TacticalMap")
ui.open()
+ RegisterSignal(user.mind, COMSIG_MIND_TRANSFERRED, PROC_REF(on_mind_transferred))
/datum/tacmap/drawing/tgui_interact(mob/user, datum/tgui/ui)
var/mob/living/carbon/xenomorph/xeno = user
@@ -755,6 +756,7 @@ SUBSYSTEM_DEF(minimaps)
tacmap_ready_time = SSminimaps.next_fire + 2 SECONDS
addtimer(CALLBACK(src, PROC_REF(on_tacmap_fire), faction), SSminimaps.next_fire - world.time + 1 SECONDS)
user.client.register_map_obj(map_holder.map)
+ RegisterSignal(user.mind, COMSIG_MIND_TRANSFERRED, PROC_REF(on_mind_transferred))
ui = new(user, src, "TacticalMap")
ui.open()
@@ -835,6 +837,9 @@ SUBSYSTEM_DEF(minimaps)
return data
+/datum/tacmap/ui_close(mob/user)
+ UnregisterSignal(user.mind, COMSIG_MIND_TRANSFERRED)
+
/datum/tacmap/drawing/ui_close(mob/user)
. = ..()
action_queue_change = 0
@@ -950,6 +955,11 @@ SUBSYSTEM_DEF(minimaps)
return UI_INTERACTIVE
+// This gets removed when the player changes bodies (i.e. xeno evolution), so re-register it when that happens.
+/datum/tacmap/proc/on_mind_transferred(datum/mind/source, mob/previous_body)
+ SIGNAL_HANDLER
+ source.current.client.register_map_obj(map_holder.map)
+
/datum/tacmap_holder
var/map_ref
var/atom/movable/screen/minimap/map
diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm
index cfe66421c9..d3cb19c40e 100644
--- a/code/controllers/subsystem/ticker.dm
+++ b/code/controllers/subsystem/ticker.dm
@@ -180,7 +180,7 @@ SUBSYSTEM_DEF(ticker)
CHECK_TICK
mode.announce()
if(mode.taskbar_icon)
- RegisterSignal(SSdcs, COMSIG_GLOB_CLIENT_LOGIN, PROC_REF(handle_mode_icon))
+ RegisterSignal(SSdcs, COMSIG_GLOB_CLIENT_LOGGED_IN, PROC_REF(handle_mode_icon))
set_clients_taskbar_icon(mode.taskbar_icon)
if(GLOB.perf_flags & PERF_TOGGLE_LAZYSS)
diff --git a/code/controllers/subsystem/vote.dm b/code/controllers/subsystem/vote.dm
index a56e10636a..34350613ce 100644
--- a/code/controllers/subsystem/vote.dm
+++ b/code/controllers/subsystem/vote.dm
@@ -59,7 +59,7 @@ SUBSYSTEM_DEF(vote)
voting.Cut()
remove_action_buttons()
- UnregisterSignal(SSdcs, COMSIG_GLOB_CLIENT_LOGIN)
+ UnregisterSignal(SSdcs, COMSIG_GLOB_CLIENT_LOGGED_IN)
for(var/c in GLOB.player_list)
update_static_data(c)
@@ -370,7 +370,7 @@ SUBSYSTEM_DEF(vote)
if(send_clients_vote)
C.mob.vote()
- RegisterSignal(SSdcs, COMSIG_GLOB_CLIENT_LOGIN, PROC_REF(handle_client_joining))
+ RegisterSignal(SSdcs, COMSIG_GLOB_CLIENT_LOGGED_IN, PROC_REF(handle_client_joining))
SStgui.update_uis(src)
return TRUE
return FALSE
diff --git a/code/datums/action.dm b/code/datums/action.dm
index 0510a43415..3a597ad262 100644
--- a/code/datums/action.dm
+++ b/code/datums/action.dm
@@ -11,9 +11,9 @@
var/cost = 0 // By default an action has no cost -> will be utilized by skill actions/xeno actions
var/action_flags = 0 // Check out __game.dm for flags
/// Whether the action is hidden from its owner
- /// Useful for when you want to preserve action state while preventing
- /// a mob from using said action
- var/hidden = FALSE
+ var/hidden = FALSE //Preserve action state while preventing mob from using action
+ ///Hide the action from the owner without preventing them from using it (incase of keybind listen_signal)
+ var/player_hidden = FALSE
var/unique = TRUE
/// A signal on the mob that will cause the action to activate
var/listen_signal
@@ -227,7 +227,7 @@
var/atom/movable/screen/action_button/B = A.button
if(reload_screen)
client.add_to_screen(B)
- if(A.hidden)
+ if(A.hidden || A.player_hidden)
B.screen_loc = null
continue
button_number++
diff --git a/code/datums/components/overlay_lighting.dm b/code/datums/components/overlay_lighting.dm
index e14066ffb7..225149ecb4 100644
--- a/code/datums/components/overlay_lighting.dm
+++ b/code/datums/components/overlay_lighting.dm
@@ -199,7 +199,7 @@
get_new_turfs()
-///Adds the luminosity and source for the afected movable atoms to keep track of their visibility.
+///Adds the luminosity and source for the affected movable atoms to keep track of their visibility.
/datum/component/overlay_lighting/proc/add_dynamic_lumi()
LAZYSET(current_holder.affected_movable_lights, src, lumcount_range + 1)
current_holder.underlays += visible_mask
@@ -207,7 +207,7 @@
if(directional)
current_holder.underlays += cone
-///Removes the luminosity and source for the afected movable atoms to keep track of their visibility.
+///Removes the luminosity and source for the affected movable atoms to keep track of their visibility.
/datum/component/overlay_lighting/proc/remove_dynamic_lumi()
LAZYREMOVE(current_holder.affected_movable_lights, src)
current_holder.underlays -= visible_mask
@@ -267,6 +267,9 @@
///Used to determine the new valid current_holder from the parent's loc.
/datum/component/overlay_lighting/proc/check_holder()
var/atom/movable/movable_parent = GET_PARENT
+ if(QDELETED(movable_parent))
+ set_holder(null)
+ return
if(isturf(movable_parent.loc))
set_holder(movable_parent)
return
@@ -275,13 +278,21 @@
set_holder(null)
return
if(isturf(inside.loc))
- set_holder(inside)
+ // storage items block light, also don't be moving into a qdeleted item
+ if(QDELETED(inside) || istype(inside, /obj/item/storage))
+ set_holder(null)
+ else
+ set_holder(inside)
return
set_holder(null)
///Called when the current_holder is qdeleted, to remove the light effect.
/datum/component/overlay_lighting/proc/on_holder_qdel(atom/movable/source, force)
+ SIGNAL_HANDLER
+ if(QDELETED(current_holder))
+ set_holder(null)
+ return
UnregisterSignal(current_holder, list(COMSIG_PARENT_QDELETING, COMSIG_MOVABLE_MOVED))
if(directional)
UnregisterSignal(current_holder, COMSIG_ATOM_DIR_CHANGE)
@@ -290,6 +301,7 @@
///Called when current_holder changes loc.
/datum/component/overlay_lighting/proc/on_holder_moved(atom/movable/source, OldLoc, Dir, Forced)
+ SIGNAL_HANDLER
if(!(overlay_lighting_flags & LIGHTING_ON))
return
make_luminosity_update()
@@ -450,8 +462,7 @@
. = lum_power
lum_power = new_lum_power
var/difference = . - lum_power
- for(var/t in affected_turfs)
- var/turf/lit_turf = t
+ for(var/turf/lit_turf as anything in affected_turfs)
lit_turf.dynamic_lumcount -= difference
///Here we append the behavior associated to changing lum_power.
diff --git a/code/datums/mind.dm b/code/datums/mind.dm
index fe59699fb9..ae6304dbcd 100644
--- a/code/datums/mind.dm
+++ b/code/datums/mind.dm
@@ -32,11 +32,11 @@
msg_admin_niche("[key]/[ckey] has tried to transfer to deleted [new_character].")
return
- SEND_SIGNAL(current.client, COMSIG_CLIENT_MIND_TRANSFER, new_character)
-
+ var/mob/old_current = current
if(current)
current.mind = null //remove ourself from our old body's mind variable
nanomanager.user_transferred(current, new_character) // transfer active NanoUI instances to new user
+ SStgui.on_transfer(current, new_character) // and active TGUI instances
if(key)
if(new_character.key != key)
@@ -66,6 +66,7 @@
continue
player_entity = setup_player_entity(ckey)
+ SEND_SIGNAL(src, COMSIG_MIND_TRANSFERRED, old_current)
SEND_SIGNAL(new_character, COMSIG_MOB_NEW_MIND, current.client)
new_character.refresh_huds(current) //inherit the HUDs from the old body
diff --git a/code/datums/soundOutput.dm b/code/datums/soundOutput.dm
index 85548d6c90..0fddd9b503 100644
--- a/code/datums/soundOutput.dm
+++ b/code/datums/soundOutput.dm
@@ -4,13 +4,25 @@
var/list/soundscape_playlist = list() //Updated on changing areas
var/ambience = null //The file currently being played as ambience
var/status_flags = 0 //For things like ear deafness, psychodelic effects, and other things that change how all sounds behave
- var/list/echo
-/datum/soundOutput/New(client/C)
- if(!C)
+
+ /// Currently applied environmental reverb.
+ VAR_PROTECTED/owner_environment = SOUND_ENVIRONMENT_NONE
+
+/datum/soundOutput/New(client/client)
+ if(!client)
qdel(src)
return
- owner = C
- . = ..()
+ owner = client
+ RegisterSignal(owner.mob, COMSIG_MOVABLE_MOVED, PROC_REF(on_mob_moved))
+ RegisterSignal(owner.mob, COMSIG_MOB_LOGOUT, PROC_REF(on_mob_logout))
+ RegisterSignal(owner, COMSIG_CLIENT_MOB_LOGGED_IN, PROC_REF(on_client_mob_logged_in))
+ return ..()
+
+/datum/soundOutput/Destroy()
+ UnregisterSignal(owner.mob, list(COMSIG_MOVABLE_MOVED, COMSIG_MOB_LOGOUT))
+ UnregisterSignal(owner, COMSIG_CLIENT_MOB_LOGGED_IN)
+ owner = null
+ return ..()
/datum/soundOutput/proc/process_sound(datum/sound_template/T)
var/sound/S = sound(T.file, T.repeat, T.wait)
@@ -24,7 +36,6 @@
S.offset = T.offset
S.pitch = T.pitch
S.status = T.status
- S.echo = T.echo
if(T.x && T.y && T.z)
var/turf/owner_turf = get_turf(owner.mob)
if(owner_turf)
@@ -40,16 +51,12 @@
S.x = T.x - owner_turf.x
S.y = 0
S.z = T.y - owner_turf.y
- var/area/A = owner_turf.loc
- S.environment = A.sound_environment
S.y += T.y_s_offset
S.x += T.x_s_offset
+ S.echo = SOUND_ECHO_REVERB_ON //enable environment reverb for positional sounds
if(owner.mob.ear_deaf > 0)
S.status |= SOUND_MUTE
- if(owner.mob.sound_environment_override != SOUND_ENVIRONMENT_NONE)
- S.environment = owner.mob.sound_environment_override
-
sound_to(owner,S)
/datum/soundOutput/proc/update_ambience(area/target_area, ambience_override, force_update = FALSE)
@@ -86,7 +93,6 @@
S.status = status_flags
if(target_area)
- S.environment = target_area.sound_environment
var/muffle
if(target_area.ceiling_muffle)
switch(target_area.ceiling)
@@ -130,6 +136,51 @@
S.status = SOUND_UPDATE
sound_to(owner, S)
+/// Pulls mob's area's sound_environment and applies if necessary and not overridden.
+/datum/soundOutput/proc/update_area_environment()
+ var/area/owner_area = get_area(owner.mob)
+ var/new_environment = owner_area.sound_environment
+
+ if(owner.mob.sound_environment_override != SOUND_ENVIRONMENT_NONE) //override in effect, can't apply
+ return
+
+ set_owner_environment(new_environment)
+
+/// Pulls mob's sound_environment_override and applies if necessary.
+/datum/soundOutput/proc/update_mob_environment_override()
+ var/new_environment_override = owner.mob.sound_environment_override
+
+ if(new_environment_override == SOUND_ENVIRONMENT_NONE) //revert to area environment
+ update_area_environment()
+ return
+
+ set_owner_environment(new_environment_override)
+
+/// Pushes new_environment to owner and updates owner_environment var.
+/datum/soundOutput/proc/set_owner_environment(new_environment = SOUND_ENVIRONMENT_NONE)
+ if(new_environment ~= src.owner_environment) //no need to change
+ return
+
+ var/sound/sound = sound()
+ sound.environment = new_environment
+ sound_to(owner, sound)
+
+ src.owner_environment = new_environment
+
+/datum/soundOutput/proc/on_mob_moved(datum/source, atom/oldloc, direction, Forced)
+ SIGNAL_HANDLER //COMSIG_MOVABLE_MOVED
+ update_area_environment()
+
+/datum/soundOutput/proc/on_mob_logout(datum/source)
+ SIGNAL_HANDLER //COMSIG_MOB_LOGOUT
+ UnregisterSignal(owner.mob, list(COMSIG_MOVABLE_MOVED, COMSIG_MOB_LOGOUT))
+
+/datum/soundOutput/proc/on_client_mob_logged_in(datum/source, mob/new_mob)
+ SIGNAL_HANDLER //COMSIG_CLIENT_MOB_LOGGED_IN
+ RegisterSignal(owner.mob, COMSIG_MOVABLE_MOVED, PROC_REF(on_mob_moved))
+ RegisterSignal(owner.mob, COMSIG_MOB_LOGOUT, PROC_REF(on_mob_logout))
+ update_mob_environment_override()
+
/client/proc/adjust_volume_prefs(volume_key, prompt = "", channel_update = 0)
volume_preferences[volume_key] = (tgui_input_number(src, prompt, "Volume", volume_preferences[volume_key]*100)) / 100
if(volume_preferences[volume_key] > 1)
diff --git a/code/game/objects/items/devices/radio/headset.dm b/code/game/objects/items/devices/radio/headset.dm
index e6daba29ae..f00ba138ef 100644
--- a/code/game/objects/items/devices/radio/headset.dm
+++ b/code/game/objects/items/devices/radio/headset.dm
@@ -244,7 +244,7 @@
), PROC_REF(turn_on))
wearer = user
RegisterSignal(user, COMSIG_MOB_STAT_SET_ALIVE, PROC_REF(update_minimap_icon))
- RegisterSignal(user, COMSIG_MOB_LOGIN, PROC_REF(add_hud_tracker))
+ RegisterSignal(user, COMSIG_MOB_LOGGED_IN, PROC_REF(add_hud_tracker))
RegisterSignal(user, COMSIG_MOB_DEATH, PROC_REF(update_minimap_icon))
RegisterSignal(user, COMSIG_HUMAN_SET_UNDEFIBBABLE, PROC_REF(update_minimap_icon))
if(headset_hud_on)
@@ -261,7 +261,7 @@
UnregisterSignal(user, list(
COMSIG_LIVING_REJUVENATED,
COMSIG_HUMAN_REVIVED,
- COMSIG_MOB_LOGIN,
+ COMSIG_MOB_LOGGED_IN,
COMSIG_MOB_DEATH,
COMSIG_HUMAN_SET_UNDEFIBBABLE,
COMSIG_MOB_STAT_SET_ALIVE
diff --git a/code/game/sound.dm b/code/game/sound.dm
index f2574975a7..6bee74ba01 100644
--- a/code/game/sound.dm
+++ b/code/game/sound.dm
@@ -1,3 +1,5 @@
+/sound
+ echo = SOUND_ECHO_REVERB_OFF //disable enviroment reverb by default, soundOutput re-enables for positional sounds
/datum/sound_template //Basically a sound datum, but only serves as a way to carry info to soundOutput
//copied sound datum vars
@@ -23,8 +25,6 @@
var/falloff = 1
///Changes the environmental reverb for all 3D sounds until another environment is specified. The default value (-1) specifies no change in environment. A numeric value from 0 to 25 specifies a set of reverb presets for the environment.
var/environment = -1
- ///If set to an 18-element list, this value customizes reverbration settings for this sound only.
- var/list/echo
//custom vars
///The category of this sound for client volume purposes: VOLUME_SFX (Sound effects), VOLUME_AMB (Ambience and Soundscapes) and VOLUME_ADM (Admin sounds and some other stuff)
@@ -59,16 +59,40 @@
* * channel - use this only when you want to force the sound to play on a specific channel
* * status - combined bit flags: SOUND_MUTE, SOUND_PAUSED, SOUND_STREAM, SOUND_UPDATE
* * falloff - max range till sound volume starts dropping as distance increases
- * * echo - customizes reverbration settings for this sound
* * y_s_offset - vertical sound position offset
* * x_s_offset - horizontal sound position offset
*
* Returns selected channel on success, FALSE on failure
*/
-/proc/playsound(atom/source, sound/soundin, vol = 100, vary = FALSE, sound_range, vol_cat = VOLUME_SFX, channel = 0, status, falloff = 1, list/echo, y_s_offset, x_s_offset)
+/proc/playsound(atom/source, sound/soundin, vol = 100, vary = FALSE, sound_range, vol_cat = VOLUME_SFX, channel = 0, status, falloff = 1, y_s_offset, x_s_offset)
if(isarea(source))
error("[source] is an area and is trying to make the sound: [soundin]")
return FALSE
+ var/datum/sound_template/S = new()
+
+ var/sound/SD = soundin
+ if(istype(SD))
+ S.file = SD.file
+ S.wait = SD.wait
+ S.repeat = SD.repeat
+ else
+ S.file = get_sfx(soundin)
+ S.channel = channel ? channel : get_free_channel()
+ S.status = status
+ S.falloff = falloff
+ S.volume = vol
+ S.volume_cat = vol_cat
+ S.y_s_offset = y_s_offset
+ S.x_s_offset = x_s_offset
+ if(vary != FALSE)
+ if(vary > 1)
+ S.frequency = vary
+ else
+ S.frequency = GET_RANDOM_FREQ // Same frequency for everybody
+
+ if(!sound_range)
+ sound_range = floor(0.25*vol) //if no specific range, the max range is equal to a quarter of the volume.
+ S.range = sound_range
var/turf/turf_source = get_turf(source)
if(!turf_source?.z)
@@ -100,7 +124,6 @@
template.frequency = GET_RANDOM_FREQ // Same frequency for everybody
template.status = status
template.falloff = falloff
- template.echo = echo
template.volume_cat = vol_cat
template.range = sound_range || floor(0.25 * vol) //if no specific range, the max range is equal to a quarter of the volume.
@@ -147,13 +170,12 @@
* * vol_cat - the category of this sound for client volume purposes: VOLUME_SFX (Sound effects), VOLUME_AMB (Ambience and Soundscapes), VOLUME_ADM (Admin sounds)
* * channel - use this only when you want to force the sound to play on a specific channel
* * status - combined bit flags: SOUND_MUTE, SOUND_PAUSED, SOUND_STREAM, SOUND_UPDATE
- * * echo - customizes reverbration settings for this sound
* * y_s_offset - vertical sound position offset
* * x_s_offset - horizontal sound position offset
*
* Returns FALSE on failure
*/
-/proc/playsound_client(client/C, sound/soundin, atom/origin, vol = 100, random_freq, vol_cat = VOLUME_SFX, channel = 0, status, list/echo, y_s_offset, x_s_offset)
+/proc/playsound_client(client/C, sound/soundin, atom/origin, vol = 100, random_freq, vol_cat = VOLUME_SFX, channel = 0, status, y_s_offset, x_s_offset)
if(!istype(C) || !C.soundOutput) return FALSE
var/datum/sound_template/template = new()
@@ -179,7 +201,6 @@
if(random_freq)
template.frequency = GET_RANDOM_FREQ
template.status = status
- template.echo = echo
template.volume_cat = vol_cat
var/turf/turf_origin = get_turf(origin)
@@ -206,7 +227,7 @@
*
* Returns FALSE on failure
*/
-/proc/playsound_area(area/A, sound/soundin, vol = 100, channel = 0, status, vol_cat = VOLUME_SFX, list/echo, y_s_offset, x_s_offset)
+/proc/playsound_area(area/A, sound/soundin, vol = 100, channel = 0, status, vol_cat = VOLUME_SFX, y_s_offset, x_s_offset)
if(!isarea(A))
return FALSE
@@ -259,13 +280,12 @@
* * soundin - sound datum ( sound() ), sound file ('mysound.ogg'), or string to get a SFX ("male_warcry")
* * volume - the initial volume of the sound, 0 is no sound at all, 75 is loud queen screech.
* * vol_cat - the category of this sound for client volume purposes: VOLUME_SFX (Sound effects), VOLUME_AMB (Ambience and Soundscapes), VOLUME_ADM (Admin sounds)
- * * echo - customizes reverbration settings for this sound
* * y_s_offset - vertical sound position offset
* * x_s_offset - horizontal sound position offset
*
* Returns selected channel on success, FALSE on failure
*/
-/proc/playsound_z(list/z, sound/soundin, volume = 100, vol_cat = VOLUME_SFX, echo, y_s_offset, x_s_offset)
+/proc/playsound_z(list/z, sound/soundin, volume = 100, vol_cat = VOLUME_SFX, y_s_offset, x_s_offset)
var/datum/sound_template/template = new()
if(istype(soundin))
@@ -286,7 +306,6 @@
template.channel = SOUND_CHANNEL_Z
template.volume = volume
- template.echo = echo
template.volume_cat = vol_cat
template.x_s_offset = x_s_offset
diff --git a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm
index d69833ec5c..8456b92463 100644
--- a/code/modules/client/client_procs.dm
+++ b/code/modules/client/client_procs.dm
@@ -464,7 +464,7 @@ GLOBAL_LIST_INIT(whitelisted_client_procs, list(
view = world_view_size
- SEND_GLOBAL_SIGNAL(COMSIG_GLOB_CLIENT_LOGIN, src)
+ SEND_GLOBAL_SIGNAL(COMSIG_GLOB_CLIENT_LOGGED_IN, src)
//////////////
//DISCONNECT//
@@ -820,3 +820,32 @@ GLOBAL_LIST_INIT(whitelisted_client_procs, list(
xeno_prefix = "XX"
if(!xeno_postfix || xeno_name_ban)
xeno_postfix = ""
+
+/client/verb/action_hide_menu()
+ set name = "Show/Hide Actions"
+ set category = "IC"
+
+ var/mob/user = usr
+
+ var/list/actions_list = list()
+ for(var/datum/action/action as anything in user.actions)
+ var/action_name = action.name
+ if(action.player_hidden)
+ action_name += " (Hidden)"
+ actions_list[action_name] += action
+
+ if(!LAZYLEN(actions_list))
+ to_chat(user, SPAN_WARNING("You have no actions available."))
+ return
+
+ var/selected_action_name = tgui_input_list(user, "Show or hide selected action", "Show/Hide Actions", actions_list, 30 SECONDS)
+ if(!selected_action_name)
+ to_chat(user, SPAN_WARNING("You did not select an action."))
+ return
+
+ var/datum/action/selected_action = actions_list[selected_action_name]
+ selected_action.player_hidden = !selected_action.player_hidden
+ user.update_action_buttons()
+
+ if(!selected_action.player_hidden && selected_action.hidden) //Inform the player that even if they are unhiding it, itll still not be visible
+ to_chat(user, SPAN_NOTICE("[selected_action] is forcefully hidden, bypassing player unhiding."))
diff --git a/code/modules/defenses/sentry_computer.dm b/code/modules/defenses/sentry_computer.dm
index bb6f55d72b..7cb4f7bb84 100644
--- a/code/modules/defenses/sentry_computer.dm
+++ b/code/modules/defenses/sentry_computer.dm
@@ -48,41 +48,18 @@
// Stuff needed to render the map
/// asset name for the game map
- var/map_name
-
- /// camera screen which renders the world
- var/atom/movable/screen/map_view/cam_screen
-
- /// camera screen which shows a blank error
- var/atom/movable/screen/background/cam_background
-
- var/list/cam_plane_masters
+ var/camera_map_name
/obj/item/device/sentry_computer/Initialize(mapload)
. = ..()
if(cell_type)
cell = new cell_type()
cell.charge = cell.maxcharge
- // set up cameras
- map_name = "sentry_computer_[REF(src)]_map"
- cam_screen = new
- cam_screen.name = "screen"
- cam_screen.assigned_map = map_name
- cam_screen.del_on_map_removal = FALSE
- cam_screen.screen_loc = "[map_name]:1,1"
- cam_background = new
- cam_background.assigned_map = map_name
- cam_background.del_on_map_removal = FALSE
-
- cam_plane_masters = list()
- for(var/plane in subtypesof(/atom/movable/screen/plane_master) - /atom/movable/screen/plane_master/blackness)
- var/atom/movable/screen/plane_master/instance = new plane()
- instance.assigned_map = map_name
- instance.del_on_map_removal = FALSE
- if(instance.blend_mode_override)
- instance.blend_mode = instance.blend_mode_override
- instance.screen_loc = "[map_name]:CENTER"
- cam_plane_masters += instance
+
+ RegisterSignal(src, COMSIG_CAMERA_MAPNAME_ASSIGNED, PROC_REF(camera_mapname_update))
+
+ AddComponent(/datum/component/camera_manager)
+ SEND_SIGNAL(src, COMSIG_CAMERA_CLEAR)
faction_group = FACTION_LIST_MARINE
transceiver.forceMove(src)
@@ -94,16 +71,20 @@
/obj/item/device/sentry_computer/Destroy()
. = ..()
+ UnregisterSignal(src, COMSIG_CAMERA_MAPNAME_ASSIGNED)
QDEL_NULL(cell)
- QDEL_NULL(cam_background)
- QDEL_NULL(cam_screen)
QDEL_NULL(transceiver)
QDEL_NULL(voice)
last_camera_turf = null
current = null
registered_tools = null
+ for(var/obj/structure/machinery/defenses/sentry/sentrygun as anything in paired_sentry)
+ unpair_sentry(sentrygun)
paired_sentry = null
+/obj/item/device/sentry_computer/proc/camera_mapname_update(source, value)
+ camera_map_name = value
+
/obj/item/device/sentry_computer/Move(NewLoc, direct)
..()
if(table_setup || open || on)
@@ -232,7 +213,7 @@
for(var/key_id in tool.encryption_keys)
var/datum/weakref/ref = tool.encryption_keys[key_id]
var/obj/item/device/sentry_computer/key_object = ref.resolve()
- key_object.registered_tools -= id
+ key_object?.registered_tools -= id
tool.encryption_keys = list()
to_chat(user, SPAN_NOTICE("Existing encryption keys cleared."))
to_chat(usr, SPAN_NOTICE("You begin encryption key to \the [tool]."))
@@ -321,7 +302,7 @@
if(current == target)
current = null
- update_active_camera()
+ SEND_SIGNAL(src, COMSIG_CAMERA_CLEAR)
/obj/item/device/sentry_computer/ui_status(mob/user, datum/ui_state/state)
. = ..()
@@ -332,19 +313,16 @@
/obj/item/device/sentry_computer/ui_close(mob/user)
-
- // Unregister map objects
- user.client.clear_map(map_name)
+ SEND_SIGNAL(src, COMSIG_CAMERA_UNREGISTER_UI, user)
/obj/item/device/sentry_computer/ui_static_data(mob/user)
. = list()
.["sentry_static"] = list()
- .["mapRef"] = map_name
+ .["mapRef"] = camera_map_name
var/index = 1
- for(var/sentry in paired_sentry)
+ for(var/obj/structure/machinery/defenses/sentry/sentrygun as anything in paired_sentry)
var/list/sentry_holder = list()
- var/obj/structure/machinery/defenses/sentry/sentrygun = sentry
sentry_holder["selection_menu"] = list()
sentry_holder["index"] = index
sentry_holder["name"] = sentrygun.name
@@ -396,13 +374,8 @@
/obj/item/device/sentry_computer/tgui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
- update_active_camera()
if (!ui)
- // Register map objects
- user.client.register_map_obj(cam_background)
- user.client.register_map_obj(cam_screen)
- for(var/plane in cam_plane_masters)
- user.client.register_map_obj(plane)
+ SEND_SIGNAL(src, COMSIG_CAMERA_REGISTER_UI, user)
ui = new(user, src, "SentryGunUI", name)
ui.open()
@@ -426,7 +399,17 @@
if("set-camera")
current = sentry
playsound(src, get_sfx("terminal_button"), 25, FALSE)
- update_active_camera()
+ var/obj/structure/machinery/defenses/sentry/defense = sentry
+ if (defense.has_camera)
+ defense.set_watched_turfs()
+ var/list/turf/visible_turfs = defense.watching_turfs
+ var/list/bbox = get_bbox_of_atoms(visible_turfs)
+ var/center_x = (bbox[3] + bbox[1]) * 0.5
+ var/center_y = (bbox[4] + bbox[2]) * 0.5
+ var/size_x = bbox[3] - bbox[1] + 1
+ var/size_y = bbox[4] - bbox[2] + 1
+ SEND_SIGNAL(src, COMSIG_CAMERA_SET_AREA, center_x, center_y, defense.loc.z, size_x, size_y)
+
return TRUE
if("ping")
playsound(sentry, 'sound/machines/twobeep.ogg', 50, 1)
@@ -439,54 +422,8 @@
if("clear-camera")
current = null
playsound(src, get_sfx("terminal_button"), 25, FALSE)
- update_active_camera()
+ SEND_SIGNAL(src, COMSIG_CAMERA_CLEAR)
return TRUE
if("ui-interact")
playsound(src, get_sfx("terminal_button"), 25, FALSE)
return FALSE
-
-/**
- * Set the displayed camera to the static not-connected.
- */
-/obj/item/device/sentry_computer/proc/show_camera_static()
- cam_screen.vis_contents.Cut()
- last_camera_turf = null
- cam_background.icon_state = "scanline2"
- cam_background.fill_rect(1, 1, 15, 15)
-
-/**
- * Update camera settings and redraw camera on the current variable.
- */
-/obj/item/device/sentry_computer/proc/update_active_camera()
- // Show static if can't use the camera
- if(isnull(current) || !current.has_camera || current.placed != 1)
- show_camera_static()
- return
-
- // Is this camera located in or attached to a living thing, Vehicle or helmet? If so, assume the camera's loc is the living (or non) thing.
- var/cam_location = current
- if(isliving(current.loc) || isVehicle(current.loc))
- cam_location = current.loc
- else if(istype(current.loc, /obj/item/clothing/head/helmet/marine))
- var/obj/item/clothing/head/helmet/marine/helmet = current.loc
- cam_location = helmet.loc
- // If we're not forcing an update for some reason and the cameras are in the same location,
- // we don't need to update anything.
- // Most security cameras will end here as they're not moving.
- if(last_camera_turf == get_turf(cam_location))
- return
-
- // Cameras that get here are moving, and are likely attached to some moving atom such as cyborgs.
- last_camera_turf = get_turf(cam_location)
-
- current.set_watched_turfs()
- var/list/turf/visible_turfs = current.watching_turfs
-
- var/list/bbox = get_bbox_of_atoms(visible_turfs)
- var/size_x = bbox[3] - bbox[1] + 1
- var/size_y = bbox[4] - bbox[2] + 1
- cam_screen.icon = null
- cam_screen.icon_state = "clear"
- cam_screen.vis_contents = visible_turfs
- cam_background.icon_state = "clear"
- cam_background.fill_rect(1, 1, size_x, size_y)
diff --git a/code/modules/escape_menu/escape_menu.dm b/code/modules/escape_menu/escape_menu.dm
index c31234678b..b61bbd5b3f 100644
--- a/code/modules/escape_menu/escape_menu.dm
+++ b/code/modules/escape_menu/escape_menu.dm
@@ -49,7 +49,7 @@ GLOBAL_LIST_EMPTY(escape_menus)
show_page()
RegisterSignal(client, COMSIG_PARENT_QDELETING, PROC_REF(on_client_qdel))
- RegisterSignal(client, COMSIG_CLIENT_MOB_LOGIN, PROC_REF(on_client_mob_login))
+ RegisterSignal(client, COMSIG_CLIENT_MOB_LOGGED_IN, PROC_REF(on_client_mob_login))
if (!isnull(ckey))
GLOB.escape_menus[ckey] = src
diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm
index 409c88388f..cf225caadc 100644
--- a/code/modules/mob/dead/observer/observer.dm
+++ b/code/modules/mob/dead/observer/observer.dm
@@ -32,6 +32,7 @@
plane = GHOST_PLANE
layer = ABOVE_FLY_LAYER
stat = DEAD
+ mob_flags = KNOWS_TECHNOLOGY
var/adminlarva = FALSE
var/ghostvision = TRUE
var/can_reenter_corpse
@@ -189,37 +190,38 @@
clean_observe_target()
/// When the observer target gets a screen, our observer gets a screen minus some game screens we don't want the observer to touch
-/mob/dead/observer/proc/observe_target_screen_add(observe_target_mob_client, add_to_screen)
+/mob/dead/observer/proc/observe_target_screen_add(observe_target_mob_client, screen_add)
SIGNAL_HANDLER
- if(!client)
- return
-
- if(istype(add_to_screen, /atom/movable/screen/action_button))
- return
-
- if(istype(add_to_screen, /atom/movable/screen/fullscreen))
- return
+ var/static/list/excluded_types = typecacheof(list(
+ /atom/movable/screen/fullscreen,
+ /atom/movable/screen/click_catcher,
+ /atom/movable/screen/escape_menu,
+ /atom/movable/screen/buildmode,
+ /obj/effect/detector_blip,
+ ))
- if(istype(add_to_screen, /atom/movable/screen/click_catcher))
+ if(!client)
return
- if(istype(add_to_screen, /atom/movable/screen/escape_menu))
- return
+ // `screen_add` can sometimes be a list, so it's safest to just handle everything as one.
+ var/list/stuff_to_add = (islist(screen_add) ? screen_add : list(screen_add))
- if(istype(add_to_screen, /obj/effect/detector_blip))
- return
+ for(var/item in stuff_to_add)
+ // Ignore anything that's in `excluded_types`.
+ if(is_type_in_typecache(item, excluded_types))
+ continue
- client.add_to_screen(add_to_screen)
+ client.add_to_screen(screen_add)
/// When the observer target loses a screen, our observer loses it as well
-/mob/dead/observer/proc/observe_target_screen_remove(observe_target_mob_client, remove_from_screen)
+/mob/dead/observer/proc/observe_target_screen_remove(observe_target_mob_client, screen_remove)
SIGNAL_HANDLER
if(!client)
return
- client.remove_from_screen(remove_from_screen)
+ client.remove_from_screen(screen_remove)
/// When the observe target ghosts our observer disconnect from their screen updates
/mob/dead/observer/proc/observe_target_ghosting(mob/observer_target_mob)
@@ -236,8 +238,9 @@
if(observe_target_client != new_client)
observe_target_client = new_client
- RegisterSignal(observe_target_client, COMSIG_CLIENT_SCREEN_ADD, PROC_REF(observe_target_screen_add))
- RegisterSignal(observe_target_client, COMSIG_CLIENT_SCREEN_REMOVE, PROC_REF(observe_target_screen_remove))
+ // Override the signal from any previous targets.
+ RegisterSignal(observe_target_client, COMSIG_CLIENT_SCREEN_ADD, PROC_REF(observe_target_screen_add), TRUE)
+ RegisterSignal(observe_target_client, COMSIG_CLIENT_SCREEN_REMOVE, PROC_REF(observe_target_screen_remove), TRUE)
/// When the observe target logs in our observer connect to the new client
/mob/dead/observer/proc/observe_target_login(mob/living/new_character)
@@ -246,8 +249,9 @@
if(observe_target_client != new_character.client)
observe_target_client = new_character.client
- RegisterSignal(observe_target_client, COMSIG_CLIENT_SCREEN_ADD, PROC_REF(observe_target_screen_add))
- RegisterSignal(observe_target_client, COMSIG_CLIENT_SCREEN_REMOVE, PROC_REF(observe_target_screen_remove))
+ // Override the signal from any previous targets.
+ RegisterSignal(observe_target_client, COMSIG_CLIENT_SCREEN_ADD, PROC_REF(observe_target_screen_add), TRUE)
+ RegisterSignal(observe_target_client, COMSIG_CLIENT_SCREEN_REMOVE, PROC_REF(observe_target_screen_remove), TRUE)
///makes the ghost see the target hud and sets the eye at the target.
/mob/dead/observer/proc/do_observe(atom/movable/target)
@@ -257,52 +261,28 @@
ManualFollow(target)
reset_perspective()
- if(!ishuman(target) || !client.prefs?.auto_observe)
+ if(!iscarbon(target) || !client.prefs?.auto_observe)
return
- var/mob/living/carbon/human/human_target = target
-
- client.eye = human_target
-
- if(!human_target.hud_used)
+ var/mob/living/carbon/carbon_target = target
+ if(!carbon_target.hud_used)
return
client.clear_screen()
- LAZYINITLIST(human_target.observers)
- human_target.observers |= src
- human_target.hud_used.show_hud(human_target.hud_used.hud_version, src)
-
- var/list/target_contents = human_target.get_contents()
-
- //Handles any currently open storage containers the target is looking in when we observe
- for(var/obj/item/storage/checked_storage in target_contents)
- if(!(human_target in checked_storage.content_watchers))
- continue
-
- client.add_to_screen(checked_storage.closer)
- client.add_to_screen(checked_storage.contents)
+ client.eye = carbon_target
+ observe_target_mob = carbon_target
- if(checked_storage.storage_slots)
- client.add_to_screen(checked_storage.boxes)
- else
- client.add_to_screen(checked_storage.storage_start)
- client.add_to_screen(checked_storage.storage_continue)
- client.add_to_screen(checked_storage.storage_end)
+ carbon_target.auto_observed(src)
- break
-
- observe_target_mob = human_target
+ RegisterSignal(src, COMSIG_MOVABLE_MOVED, PROC_REF(observer_move_react))
RegisterSignal(observe_target_mob, COMSIG_PARENT_QDELETING, PROC_REF(clean_observe_target))
RegisterSignal(observe_target_mob, COMSIG_MOB_GHOSTIZE, PROC_REF(observe_target_ghosting))
RegisterSignal(observe_target_mob, COMSIG_MOB_NEW_MIND, PROC_REF(observe_target_new_mind))
RegisterSignal(observe_target_mob, COMSIG_MOB_LOGIN, PROC_REF(observe_target_login))
- RegisterSignal(src, COMSIG_MOVABLE_MOVED, PROC_REF(observer_move_react))
-
- if(human_target.client)
- observe_target_client = human_target.client
+ if(observe_target_mob.client)
+ observe_target_client = observe_target_mob.client
RegisterSignal(observe_target_client, COMSIG_CLIENT_SCREEN_ADD, PROC_REF(observe_target_screen_add))
RegisterSignal(observe_target_client, COMSIG_CLIENT_SCREEN_REMOVE, PROC_REF(observe_target_screen_remove))
- return
/mob/dead/observer/reset_perspective(atom/A)
if(observe_target_mob)
@@ -620,7 +600,6 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
return
mind.transfer_to(mind.original, TRUE)
- SStgui.on_transfer(src, mind.current)
qdel(src)
return TRUE
@@ -758,12 +737,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
if(!tx || !ty || !tz)
return
following = null
- spawn(0)
- // To stop the ghost flickering.
- x = tx
- y = ty
- z = tz
- sleep(15)
+ forceMove(locate(tx, ty, tz))
/mob/dead/observer/verb/dead_teleport_mob() //Moves the ghost instead of just changing the ghosts's eye -Nodrak
set category = "Ghost"
diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm
index b63ce0174a..4ea2f35aa6 100644
--- a/code/modules/mob/living/carbon/carbon.dm
+++ b/code/modules/mob/living/carbon/carbon.dm
@@ -416,6 +416,29 @@
"}
show_browser(user, dat, name, "mob[name]")
+/**
+ * Called by [/mob/dead/observer/proc/do_observe] when a carbon mob is observed by a ghost with [/datum/preferences/var/auto_observe] enabled.
+ *
+ * Any HUD changes past this point are handled by [/mob/dead/observer/proc/observe_target_screen_add]
+ * and [/mob/dead/observer/proc/observe_target_screen_remove].
+ *
+ * Override on subtype mobs if they have any extra HUD elements/behaviour.
+ */
+/mob/living/carbon/proc/auto_observed(mob/dead/observer/observer)
+ SHOULD_CALL_PARENT(TRUE)
+
+ LAZYINITLIST(observers)
+ observers |= observer
+ hud_used.show_hud(hud_used.hud_version, observer)
+
+ // Add the player's action buttons (not the actions themselves) to the observer's screen.
+ for(var/datum/action/action as anything in actions)
+ // Skip any hidden ones (of course).
+ if(action.hidden || action.player_hidden)
+ continue
+
+ observer.client.add_to_screen(action.button)
+
//generates realistic-ish pulse output based on preset levels
/mob/living/carbon/proc/get_pulse(method) //method 0 is for hands, 1 is for machines, more accurate
var/temp = 0 //see setup.dm:694
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index dfa646ef80..350bcec3e8 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -313,6 +313,29 @@
"}
show_browser(user, dat, name, "mob[name]")
+/**
+ * Handles any storage containers that the human is looking inside when auto-observed.
+ */
+/mob/living/carbon/human/auto_observed(mob/dead/observer/observer)
+ . = ..()
+
+ // If `src` doesn't have an inventory open.
+ if(!s_active)
+ return
+
+ // Add the storage interface to `observer`'s screen.
+ observer.client.add_to_screen(s_active.closer)
+ observer.client.add_to_screen(s_active.contents)
+
+ // If the storage has a set number of item slots.
+ if(s_active.storage_slots)
+ observer.client.add_to_screen(s_active.boxes)
+ // If the storage instead has a maximum combined item 'weight'.
+ else
+ observer.client.add_to_screen(s_active.storage_start)
+ observer.client.add_to_screen(s_active.storage_continue)
+ observer.client.add_to_screen(s_active.storage_end)
+
// called when something steps onto a human
// this handles mulebots and vehicles
/mob/living/carbon/human/Crossed(atom/movable/AM)
diff --git a/code/modules/mob/living/carbon/xenomorph/Xenomorph.dm b/code/modules/mob/living/carbon/xenomorph/Xenomorph.dm
index a89e2d0444..f27616508d 100644
--- a/code/modules/mob/living/carbon/xenomorph/Xenomorph.dm
+++ b/code/modules/mob/living/carbon/xenomorph/Xenomorph.dm
@@ -797,6 +797,11 @@
var/datum/mob_hud/MH = huds[MOB_HUD_XENO_INFECTION]
MH.add_hud_to(src, src)
+// Transfer any observing players over to the xeno's new body (`target`) on evolve/de-evolve.
+/mob/living/carbon/xenomorph/transfer_observers_to(atom/target)
+ for(var/mob/dead/observer/observer as anything in observers)
+ observer.clean_observe_target()
+ observer.do_observe(target)
/mob/living/carbon/xenomorph/check_improved_pointing()
//xeno leaders get a big arrow and less cooldown
diff --git a/code/modules/mob/living/init_signals.dm b/code/modules/mob/living/init_signals.dm
index a2b92007d9..825fa4dcc9 100644
--- a/code/modules/mob/living/init_signals.dm
+++ b/code/modules/mob/living/init_signals.dm
@@ -26,6 +26,7 @@
if(stat < UNCONSCIOUS)
set_stat(UNCONSCIOUS)
sound_environment_override = SOUND_ENVIRONMENT_PSYCHOTIC
+ client?.soundOutput?.update_mob_environment_override()
/// Called when [TRAIT_KNOCKEDOUT] is removed from the mob.
/mob/living/proc/on_knockedout_trait_loss(datum/source)
@@ -33,6 +34,7 @@
if(stat <= UNCONSCIOUS)
update_stat()
sound_environment_override = SOUND_ENVIRONMENT_NONE
+ client?.soundOutput?.update_mob_environment_override()
/// Called when [TRAIT_IMMOBILIZED] is added to the mob.
/mob/living/proc/on_immobilized_trait_gain(datum/source)
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index 64c8513108..72fd380e58 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -485,12 +485,10 @@
if(CONSCIOUS)
if(stat >= UNCONSCIOUS)
ADD_TRAIT(src, TRAIT_IMMOBILIZED, TRAIT_KNOCKEDOUT)
- sound_environment_override = SOUND_ENVIRONMENT_PSYCHOTIC
add_traits(list(/*TRAIT_HANDS_BLOCKED, */ TRAIT_INCAPACITATED, TRAIT_FLOORED), STAT_TRAIT)
if(UNCONSCIOUS)
if(stat >= UNCONSCIOUS)
ADD_TRAIT(src, TRAIT_IMMOBILIZED, TRAIT_KNOCKEDOUT) //adding trait sources should come before removing to avoid unnecessary updates
- sound_environment_override = SOUND_ENVIRONMENT_PSYCHOTIC
if(DEAD)
SEND_SIGNAL(src, COMSIG_MOB_STAT_SET_ALIVE)
// remove_from_dead_mob_list()
@@ -500,12 +498,10 @@
if(CONSCIOUS)
if(. >= UNCONSCIOUS)
REMOVE_TRAIT(src, TRAIT_IMMOBILIZED, TRAIT_KNOCKEDOUT)
- sound_environment_override = SOUND_ENVIRONMENT_NONE
remove_traits(list(/*TRAIT_HANDS_BLOCKED, */ TRAIT_INCAPACITATED, TRAIT_FLOORED, /*TRAIT_CRITICAL_CONDITION*/), STAT_TRAIT)
if(UNCONSCIOUS)
if(. >= UNCONSCIOUS)
REMOVE_TRAIT(src, TRAIT_IMMOBILIZED, TRAIT_KNOCKEDOUT)
- sound_environment_override = SOUND_ENVIRONMENT_NONE
if(DEAD)
SEND_SIGNAL(src, COMSIG_MOB_STAT_SET_DEAD)
// REMOVE_TRAIT(src, TRAIT_CRITICAL_CONDITION, STAT_TRAIT)
diff --git a/code/modules/mob/login.dm b/code/modules/mob/login.dm
index 775e69dc0b..38157a0673 100644
--- a/code/modules/mob/login.dm
+++ b/code/modules/mob/login.dm
@@ -18,6 +18,8 @@
update_Login_details()
+ SEND_SIGNAL(src, COMSIG_MOB_LOGIN)
+
client.images = null
client.screen = null //remove hud items just in case
if(!hud_used)
@@ -58,6 +60,6 @@
client.init_verbs()
- SEND_GLOBAL_SIGNAL(COMSIG_GLOB_MOB_LOGIN, src)
- SEND_SIGNAL(client, COMSIG_CLIENT_MOB_LOGIN, src)
- SEND_SIGNAL(src, COMSIG_MOB_LOGIN)
+ SEND_GLOBAL_SIGNAL(COMSIG_GLOB_MOB_LOGGED_IN, src)
+ SEND_SIGNAL(client, COMSIG_CLIENT_MOB_LOGGED_IN, src)
+ SEND_SIGNAL(src, COMSIG_MOB_LOGGED_IN)
diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm
index f0e5bc48a8..e2f40506b2 100644
--- a/code/modules/mob/mob_defines.dm
+++ b/code/modules/mob/mob_defines.dm
@@ -28,7 +28,8 @@
I'll make some notes on where certain variable defines should probably go.
Changing this around would probably require a good look-over the pre-existing code.
*/
- var/list/observers //The list of people observing this mob.
+ /// The list of people observing this mob.
+ var/list/mob/dead/observer/observers
var/zone_selected = "chest"
var/use_me = 1 //Allows all mobs to use the me verb by default, will have to manually specify they cannot
@@ -433,4 +434,3 @@
return
src.regenerate_icons()
-
diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm
index 7bda746325..2664c14a8a 100644
--- a/code/modules/mob/mob_helpers.dm
+++ b/code/modules/mob/mob_helpers.dm
@@ -584,7 +584,7 @@ var/global/list/limb_types_by_name = list(
alert_overlay.layer = FLOAT_LAYER
alert_overlay.plane = FLOAT_PLANE
-
+ alert_overlay.underlays.Cut()
screen_alert.overlays += alert_overlay
/mob/proc/reset_lighting_alpha()
diff --git a/code/modules/vehicles/van/van.dm b/code/modules/vehicles/van/van.dm
index 0b99d682c0..3dcc603445 100644
--- a/code/modules/vehicles/van/van.dm
+++ b/code/modules/vehicles/van/van.dm
@@ -82,7 +82,7 @@
icon_state = null
- RegisterSignal(SSdcs, COMSIG_GLOB_MOB_LOGIN, PROC_REF(add_default_image))
+ RegisterSignal(SSdcs, COMSIG_GLOB_MOB_LOGGED_IN, PROC_REF(add_default_image))
for(var/I in GLOB.player_list)
add_default_image(SSdcs, I)
@@ -124,7 +124,7 @@
mobs_under += L
RegisterSignal(L, COMSIG_PARENT_QDELETING, PROC_REF(remove_under_van))
- RegisterSignal(L, COMSIG_MOB_LOGIN, PROC_REF(add_client))
+ RegisterSignal(L, COMSIG_MOB_LOGGED_IN, PROC_REF(add_client))
RegisterSignal(L, COMSIG_MOVABLE_MOVED, PROC_REF(check_under_van))
if(L.client)
@@ -140,7 +140,7 @@
UnregisterSignal(L, list(
COMSIG_PARENT_QDELETING,
- COMSIG_MOB_LOGIN,
+ COMSIG_MOB_LOGGED_IN,
COMSIG_MOVABLE_MOVED,
))
diff --git a/colonialmarines.dme b/colonialmarines.dme
index 37c2468767..73716cf47f 100644
--- a/colonialmarines.dme
+++ b/colonialmarines.dme
@@ -136,6 +136,7 @@
#include "code\__DEFINES\dcs\signals\atom\signals_obj.dm"
#include "code\__DEFINES\dcs\signals\atom\signals_projectile.dm"
#include "code\__DEFINES\dcs\signals\atom\signals_turf.dm"
+#include "code\__DEFINES\dcs\signals\atom\mob\signals_mind.dm"
#include "code\__DEFINES\dcs\signals\atom\mob\signals_mob.dm"
#include "code\__DEFINES\dcs\signals\atom\mob\living\signals_human.dm"
#include "code\__DEFINES\dcs\signals\atom\mob\living\signals_living.dm"
diff --git a/strings/metatips.txt b/strings/metatips.txt
index 17ffd607a7..e0ede9c626 100644
--- a/strings/metatips.txt
+++ b/strings/metatips.txt
@@ -12,6 +12,7 @@ As a mentor, you can become the imaginary friend of a new player to teach them!
You shouldn't ignore what your allies are up to. Sometimes they can be organizing a flank on the radio, sometimes they can be walking up behind you with a buck-loaded shotgun. Either way, it pays to be alert to what they're doing, as much to as what the enemies are.
The Wiki (https://cm-ss13.com/wiki) is a very useful repository of information about the game, such as weapons, equipment, xenomorph castes and their strains. It may not be fully up to date much of the time, but the basics are usually accurate.
As an observer, you may see how much remaining hijack time is left in the status panel.
+As an observer, you can quickly follow someone by ctrl-clicking on their sprite.
You can always AdminHelp with the F1 key to question a member of staff regarding rules or game bugs.
As ghost you are given extra tools for spectating the round: you can jump and follow specific players, get notifications about CAS and OB strikes, can see all health bars, and such.
You can press ESC key to bring up the game pause menu. It allows you change settings, AdminHelp and MentorHelp, and even access the Web Maps of game by clicking at top right.