diff --git a/code/_onclick/hud/action_button.dm b/code/_onclick/hud/action_button.dm
index 5ce1d3130d..b347a5c55a 100644
--- a/code/_onclick/hud/action_button.dm
+++ b/code/_onclick/hud/action_button.dm
@@ -29,25 +29,31 @@
return ..()
/atom/movable/screen/movable/action_button/proc/can_use(mob/user)
- if (linked_action)
+ if(isobserver(user))
+ var/mob/dead/observer/dead_mob = user
+ if(dead_mob.observetarget) // Observers can only click on action buttons if they're not observing something
+ return FALSE
+
+ if(linked_action)
if(linked_action.viewers[user.hud_used])
return TRUE
return FALSE
- else if (isobserver(user))
- var/mob/dead/observer/O = user
- return !O.observetarget
- else
- return TRUE
+
+ return TRUE
/atom/movable/screen/movable/action_button/Click(location,control,params)
if (!can_use(usr))
return
var/list/modifiers = params2list(params)
- if(modifiers["shift"])
+ if(LAZYACCESS(modifiers, SHIFT_CLICK))
var/datum/hud/our_hud = usr.hud_used
our_hud.position_action(src, SCRN_OBJ_DEFAULT)
return TRUE
+ var/mob/clicker = usr
+ if(!clicker.CheckActionCooldown())
+ return
+ clicker.DelayNextAction(1)
linked_action.Trigger()
return TRUE
@@ -82,7 +88,7 @@
closeToolTip(usr)
return ..()
-/atom/movable/screen/movable/action_button/MouseDrop(over_object)
+/atom/movable/screen/movable/action_button/MouseDrop(atom/over_object, mob/user, src_location, over_location, params)
last_hovored_ref = null
if(!can_use(usr))
return
@@ -107,7 +113,6 @@
our_hud.position_action_relative(src, button)
save_position()
return
- . = ..()
our_hud.position_action(src, screen_loc)
save_position()
@@ -141,6 +146,12 @@
user.client.prefs.action_buttons_screen_locs -= "[name]_[id]"
user.client.prefs.queue_save_pref(1 SECONDS, TRUE)
+/**
+ * This is a silly proc used in hud code code to determine what icon and icon state we should be using
+ * for hud elements (such as action buttons) that don't have their own icon and icon state set.
+ *
+ * It returns a list, which is pretty much just a struct of info
+ */
/datum/hud/proc/get_action_buttons_icons()
. = list()
.["bg_icon"] = ui_style
@@ -153,8 +164,15 @@
var/datum/action/A = X
A.UpdateButtons(status_only)
-//This is the proc used to update all the action buttons.
-/mob/proc/update_action_buttons(reload_screen)
+/**
+ * This proc handles adding all of the mob's actions to their screen
+ *
+ * If you just need to update existing buttons, use [/mob/proc/update_mob_action_buttons]!
+ *
+ * Arguments:
+ * * update_flags - reload_screen - bool, if TRUE, this proc will add the button to the screen of the passed mob as well
+ */
+/mob/proc/update_action_buttons(reload_screen = FALSE)
if(!hud_used || !client)
return
diff --git a/code/datums/action.dm b/code/datums/action.dm
index 4c9099fc72..f7093b1ff6 100644
--- a/code/datums/action.dm
+++ b/code/datums/action.dm
@@ -5,32 +5,50 @@
#define AB_CHECK_ALIVE 16
/datum/action
+ /// The name of the action
var/name = "Generic Action"
+ /// The description of what the action does, shown in button tooltips
var/desc = null
- var/atom/target = null
- var/check_flags = 0
- var/required_mobility_flags = MOBILITY_USE
- var/processing = FALSE
- var/buttontooltipstyle = ""
- var/transparent_when_unavailable = TRUE
+ /// The target the action is attached to. If the target datum is deleted, the action is as well.
+ /// Set in New() via the proc link_to(). PLEASE set a target if you're making an action
+ var/datum/target = null
/// Where any buttons we create should be by default. Accepts screen_loc and location defines
var/default_button_position = SCRN_OBJ_IN_LIST
-
- var/button_icon = 'icons/mob/actions/backgrounds.dmi' //This is the file for the BACKGROUND icon
- var/background_icon_state = ACTION_BUTTON_DEFAULT_BACKGROUND //And this is the state for the background icon
-
- var/icon_icon = 'icons/mob/actions.dmi' //This is the file for the ACTION icon
- var/button_icon_state = "default" //And this is the state for the action icon
+ /// This is who currently owns the action, and most often, this is who is using the action if it is triggered
+ /// This can be the same as "target" but is not ALWAYS the same - this is set and unset with Grant() and Remove()
var/mob/owner
+ /// Flags that will determine of the owner / user of the action can... use the action
+ var/check_flags = NONE
+ var/required_mobility_flags = MOBILITY_USE
+ var/processing = FALSE
+ /// Whether the button becomes transparent when it can't be used, or just reddened
+ var/transparent_when_unavailable = TRUE
///List of all mobs that are viewing our action button -> A unique movable for them to view.
var/list/viewers = list()
+ /// The style the button's tooltips appear to be
+ var/buttontooltipstyle = ""
+
+ /// This is the file for the BACKGROUND underlay icon of the button
+ var/button_icon = 'icons/mob/actions/backgrounds.dmi'
+ /// This is the icon state state for the BACKGROUND underlay icon of the button
+ /// (If set to ACTION_BUTTON_DEFAULT_BACKGROUND, uses the hud's default background)
+ var/background_icon_state = ACTION_BUTTON_DEFAULT_BACKGROUND
+
+ /// This is the file for the icon that appears on the button
+ var/icon_icon = 'icons/mob/actions.dmi'
+ /// This is the icon state for the icon that appears on the button
+ var/button_icon_state = "default"
+
/datum/action/New(Target)
link_to(Target)
/datum/action/proc/link_to(Target)
target = Target
- RegisterSignal(Target, COMSIG_ATOM_UPDATED_ICON, PROC_REF(OnUpdatedIcon))
+ RegisterSignal(Target, COMSIG_PARENT_QDELETING, PROC_REF(clear_ref), override = TRUE)
+
+ if(isatom(Target))
+ RegisterSignal(Target, COMSIG_ATOM_UPDATED_ICON, PROC_REF(OnUpdatedIcon))
/datum/action/Destroy()
if(owner)
@@ -39,23 +57,8 @@
QDEL_LIST_ASSOC_VAL(viewers) // Qdel the buttons in the viewers list **NOT THE HUDS**
return ..()
-/datum/action/proc/Grant(mob/M)
- if(!M)
- Remove(owner)
- return
- if(owner)
- if(owner == M)
- return
- Remove(owner)
- owner = M
- RegisterSignal(owner, COMSIG_PARENT_QDELETING, PROC_REF(clear_ref), override = TRUE)
- // Register some signals based on our check_flags
- // so that our button icon updates when relevant
- if(check_flags & AB_CHECK_CONSCIOUS)
- RegisterSignal(owner, COMSIG_MOB_STATCHANGE, PROC_REF(update_status_on_signal))
-
- GiveAction(M)
-
+/// Signal proc that clears any references based on the owner or target deleting
+/// If the owner's deleted, we will simply remove from them, but if the target's deleted, we will self-delete
/datum/action/proc/clear_ref(datum/ref)
SIGNAL_HANDLER
if(ref == owner)
@@ -63,23 +66,51 @@
if(ref == target)
qdel(src)
-/datum/action/proc/Remove(mob/M)
+/datum/action/proc/Grant(mob/grant_to)
+ if(isnull(grant_to))
+ Remove(owner)
+ return
+ if(grant_to == owner)
+ return // We already have it
+ var/mob/previous_owner = owner
+ owner = grant_to
+ if(!isnull(previous_owner))
+ Remove(previous_owner)
+ RegisterSignal(owner, COMSIG_PARENT_QDELETING, PROC_REF(clear_ref), override = TRUE)
+
+ // Register some signals based on our check_flags
+ // so that our button icon updates when relevant
+ if(check_flags & AB_CHECK_CONSCIOUS)
+ RegisterSignal(owner, COMSIG_MOB_STATCHANGE, PROC_REF(update_status_on_signal))
+
+ GiveAction(grant_to)
+
+/datum/action/proc/Remove(mob/remove_from)
+ SHOULD_CALL_PARENT(TRUE)
+
for(var/datum/hud/hud in viewers)
if(!hud.mymob)
continue
HideFrom(hud.mymob)
- LAZYREMOVE(M.actions, src) // We aren't always properly inserted into the viewers list, gotta make sure that action's cleared
+ LAZYREMOVE(remove_from.actions, src) // We aren't always properly inserted into the viewers list, gotta make sure that action's cleared
viewers = list()
- if(owner)
- UnregisterSignal(owner, list(
- COMSIG_PARENT_QDELETING,
- COMSIG_MOB_STATCHANGE
- ))
- if(target == owner)
- RegisterSignal(target, COMSIG_PARENT_QDELETING, PROC_REF(clear_ref))
+ if(isnull(owner))
+ return
+ UnregisterSignal(owner, COMSIG_PARENT_QDELETING)
+
+ // Clean up our check_flag signals
+ UnregisterSignal(owner, list(
+ COMSIG_MOB_STATCHANGE
+ ))
+
+ if(target == owner)
+ RegisterSignal(target, COMSIG_PARENT_QDELETING, PROC_REF(clear_ref))
+ if(owner == remove_from)
owner = null
+/// Actually triggers the effects of the action.
+/// Called when the on-screen button is clicked, for example.
/datum/action/proc/Trigger()
if(!IsAvailable())
return FALSE
@@ -90,6 +121,10 @@
/datum/action/proc/Process()
return
+/**
+ * Whether our action is currently available to use or not
+ * * silent - If false this is being called to check if we have any messages to show to the owner
+ */
/datum/action/proc/IsAvailable(silent = FALSE)
if(!owner)
return FALSE
@@ -104,9 +139,13 @@
return FALSE
if(check_flags & AB_CHECK_LYING)
if(istype(L) && !CHECK_MOBILITY(L, MOBILITY_STAND))
+ if (!silent)
+ owner.balloon_alert(owner, "must stand up!")
return FALSE
if(check_flags & AB_CHECK_CONSCIOUS)
if(owner.stat)
+ if (!silent)
+ owner.balloon_alert(owner, "unconscious!")
return FALSE
if(check_flags & AB_CHECK_ALIVE)
if(owner.stat == DEAD)
@@ -166,7 +205,8 @@
SIGNAL_HANDLER
UpdateButtons(force = TRUE)
-//Give our action button to the player
+/// Gives our action to the passed viewer.
+/// Puts our action in their actions list and shows them the button.
/datum/action/proc/GiveAction(mob/viewer)
var/datum/hud/our_hud = viewer.hud_used
if(viewers[our_hud]) // Already have a copy of us? go away
@@ -175,7 +215,7 @@
LAZYOR(viewer.actions, src) // Move this in
ShowTo(viewer)
-//Adds our action button to the screen of a player
+/// Adds our action button to the screen of the passed viewer.
/datum/action/proc/ShowTo(mob/viewer)
var/datum/hud/our_hud = viewer.hud_used
if(!our_hud || viewers[our_hud]) // There's no point in this if you have no hud in the first place
@@ -192,7 +232,7 @@
button.load_position(viewer)
viewer.update_action_buttons()
-//Removes our action button from the screen of a player
+/// Removes our action from the passed viewer.
/datum/action/proc/HideFrom(mob/viewer)
var/datum/hud/our_hud = viewer.hud_used
var/atom/movable/screen/movable/action_button/button = viewers[our_hud]
@@ -445,7 +485,8 @@
/datum/action/item_action/toggle/New(Target)
..()
- name = "Toggle [target.name]"
+ var/obj/item/item_target = target
+ name = "Toggle [item_target.name]"
/datum/action/item_action/halt
name = "HALT!"
@@ -473,7 +514,9 @@
/datum/action/item_action/adjust/New(Target)
..()
- name = "Adjust [target.name]"
+ var/obj/item/item_target = target
+ name = "Adjust [item_target.name]"
+
/datum/action/item_action/switch_hud
name = "Switch HUD"
@@ -548,21 +591,31 @@
return ..()
/datum/action/item_action/organ_action
+ name = "Organ Action"
check_flags = AB_CHECK_CONSCIOUS
/datum/action/item_action/organ_action/IsAvailable(silent = FALSE)
- var/obj/item/organ/I = target
- if(!I.owner)
+ var/obj/item/organ/attached_organ = target
+ if(!attached_organ.owner)
return FALSE
return ..()
+/datum/action/item_action/organ_action/toggle
+ name = "Toggle Organ"
+
/datum/action/item_action/organ_action/toggle/New(Target)
..()
- name = "Toggle [target.name]"
+ var/obj/item/organ/organ_target = target
+ name = "Toggle [organ_target.name]"
+
+/datum/action/item_action/organ_action/use
+ name = "Use Organ"
/datum/action/item_action/organ_action/use/New(Target)
..()
- name = "Use [target.name]"
+ var/obj/item/organ/organ_target = target
+ name = "Use [organ_target.name]"
+
/datum/action/item_action/cult_dagger
name = "Draw Blood Rune"
@@ -956,20 +1009,8 @@
/datum/action/item_action/storage_gather_mode
name = "Switch gathering mode"
desc = "Switches the gathering mode of a storage object."
- icon_icon = 'icons/mob/actions/actions_items.dmi'
- button_icon_state = "storage_gather_switch"
-
-/datum/action/item_action/storage_gather_mode/ApplyIcon(atom/movable/screen/movable/action_button/current_button)
- . = ..()
- var/old_layer = target.layer
- var/old_plane = target.plane
- target.layer = FLOAT_LAYER //AAAH
- target.plane = FLOAT_PLANE //^ what that guy said
- current_button.cut_overlays()
- current_button.add_overlay(target)
- target.layer = old_layer
- target.plane = old_plane
- current_button.appearance_cache = target.appearance
+ button_icon = 'icons/mob/actions/actions_items.dmi'
+ background_icon_state = "storage_gather_switch"
/proc/get_action_of_type(mob/M, action_type)
if(!M.actions || !ispath(action_type, /datum/action))
diff --git a/code/datums/elements/polychromic.dm b/code/datums/elements/polychromic.dm
index 79e186ffe9..bc6a6dd1da 100644
--- a/code/datums/elements/polychromic.dm
+++ b/code/datums/elements/polychromic.dm
@@ -204,7 +204,9 @@
check_flags = NONE
/datum/action/item_action/polychromic/ApplyIcon(atom/movable/screen/movable/action_button/current_button, force)
- var/matrix/save_matrix = target.transform
- target.transform = matrix(0.8, 0, 0, 0, 0.8, 0)
+ var/atom/polychromic_thing = target
+
+ var/matrix/save_matrix = polychromic_thing.transform
+ polychromic_thing.transform = matrix(0.8, 0, 0, 0, 0.8, 0)
. = ..()
- target.transform = save_matrix
+ polychromic_thing.transform = save_matrix
diff --git a/code/game/machinery/computer/camera_advanced.dm b/code/game/machinery/computer/camera_advanced.dm
index 95c4a089f3..a34a0ed500 100644
--- a/code/game/machinery/computer/camera_advanced.dm
+++ b/code/game/machinery/computer/camera_advanced.dm
@@ -3,18 +3,23 @@
desc = "Used to access the various cameras on the station."
icon_screen = "cameras"
icon_keyboard = "security_key"
+ light_color = LIGHT_COLOR_RED
+
var/list/z_lock = list() // Lock use to these z levels
var/lock_override = NONE
var/mob/camera/aiEye/remote/eyeobj
var/mob/living/current_user = null
var/list/networks = list("ss13")
- var/datum/action/innate/camera_off/off_action = new
- var/datum/action/innate/camera_jump/jump_action = new
- var/list/actions = list()
- /// Should we suppress the user's view?
- var/should_supress_view_changes = TRUE
+ /// Typepath of the action button we use as "off"
+ /// It's a typepath so subtypes can give it fun new names
+ var/datum/action/innate/camera_off/off_action = /datum/action/innate/camera_off
+ /// Typepath for jumping
+ var/datum/action/innate/camera_jump/jump_action = /datum/action/innate/camera_jump
- light_color = LIGHT_COLOR_RED
+ /// List of all actions to give to a user when they're well, granted actions
+ var/list/actions = list()
+ ///Should we supress any view changes?
+ var/should_supress_view_changes = TRUE
/obj/machinery/computer/camera_advanced/Initialize(mapload)
. = ..()
@@ -31,6 +36,11 @@
if(lock_override & CAMERA_LOCK_REEBE)
z_lock |= SSmapping.levels_by_trait(ZTRAIT_REEBE)
+ if(off_action)
+ actions += new off_action(src)
+ if(jump_action)
+ actions += new jump_action(src)
+
/obj/machinery/computer/camera_advanced/connect_to_shuttle(obj/docking_port/mobile/port, obj/docking_port/stationary/dock, idnum, override=FALSE)
for(var/i in networks)
networks -= i
@@ -47,40 +57,30 @@
eyeobj.origin = src
/obj/machinery/computer/camera_advanced/proc/GrantActions(mob/living/user)
- if(off_action)
- off_action.target = user
- off_action.Grant(user)
- actions += off_action
-
- if(jump_action)
- jump_action.target = user
- jump_action.Grant(user)
- actions += jump_action
+ for(var/datum/action/to_grant as anything in actions)
+ to_grant.Grant(user)
/obj/machinery/proc/remove_eye_control(mob/living/user)
CRASH("[type] does not implement ai eye handling")
/obj/machinery/computer/camera_advanced/remove_eye_control(mob/living/user)
- if(!user)
+ if(isnull(user?.client))
return
- for(var/V in actions)
- var/datum/action/A = V
- A.Remove(user)
- actions.Cut()
- for(var/V in eyeobj.visibleCameraChunks)
- var/datum/camerachunk/C = V
- C.remove(eyeobj)
- if(user.client)
- user.reset_perspective(null)
- if(eyeobj.visible_icon && user.client)
- user.client.images -= eyeobj.user_image
+
+ for(var/datum/action/actions_removed as anything in actions)
+ actions_removed.Remove(user)
+ for(var/datum/camerachunk/camerachunks_gone as anything in eyeobj.visibleCameraChunks)
+ camerachunks_gone.remove(eyeobj)
+
+ user.reset_perspective(null)
+ if(eyeobj.visible_icon)
+ user.client.images -= eyeobj.user_image
+ user.client.view_size.unsupress()
+
eyeobj.eye_user = null
user.remote_control = null
-
current_user = null
- user.unset_machine()
- user.client.view_size.unsupress()
- playsound(src, 'sound/machines/terminal_off.ogg', 25, 0)
+ playsound(src, 'sound/machines/terminal_off.ogg', 25, FALSE)
/obj/machinery/computer/camera_advanced/check_eye(mob/user)
if( (stat & (NOPOWER|BROKEN)) || (!Adjacent(user) && hasSiliconAccessInArea(user)) || user.eye_blind || user.incapacitated() )
@@ -89,8 +89,7 @@
/obj/machinery/computer/camera_advanced/Destroy()
if(current_user)
current_user.unset_machine()
- if(eyeobj)
- qdel(eyeobj)
+ QDEL_NULL(eyeobj)
QDEL_LIST(actions)
return ..()
@@ -153,6 +152,8 @@
return //AIs would need to disable their own camera procs to use the console safely. Bugs happen otherwise.
/obj/machinery/computer/camera_advanced/proc/give_eye_control(mob/user)
+ if(isnull(user?.client))
+ return
GrantActions(user)
current_user = user
eyeobj.eye_user = user
@@ -193,16 +194,19 @@
return eye_user.client
return null
-/mob/camera/aiEye/remote/setLoc(T)
+/mob/camera/aiEye/remote/setLoc(destination)
if(eye_user)
- T = get_turf(T)
- if (T)
- forceMove(T)
+ destination = get_turf(destination)
+ if (destination)
+ abstract_move(destination)
else
moveToNullspace()
+
update_ai_detect_hud()
+
if(use_static != USE_STATIC_NONE)
GLOB.cameranet.visibility(src, GetViewerClient(), null, use_static)
+
if(visible_icon)
if(eye_user.client)
eye_user.client.images -= user_image
@@ -233,12 +237,11 @@
button_icon_state = "camera_off"
/datum/action/innate/camera_off/Activate()
- if(!target || !isliving(target))
+ if(!owner || !isliving(owner))
return
- var/mob/living/C = target
- var/mob/camera/aiEye/remote/remote_eye = C.remote_control
+ var/mob/camera/aiEye/remote/remote_eye = owner.remote_control
var/obj/machinery/computer/camera_advanced/console = remote_eye.origin
- console.remove_eye_control(target)
+ console.remove_eye_control(owner)
/datum/action/innate/camera_jump
name = "Jump To Camera"
@@ -246,16 +249,15 @@
button_icon_state = "camera_jump"
/datum/action/innate/camera_jump/Activate()
- if(!target || !isliving(target))
+ if(!owner || !isliving(owner))
return
- var/mob/living/C = target
- var/mob/camera/aiEye/remote/remote_eye = C.remote_control
+ var/mob/camera/aiEye/remote/remote_eye = owner.remote_control
var/obj/machinery/computer/camera_advanced/origin = remote_eye.origin
var/list/L = list()
- for (var/obj/machinery/camera/cam in GLOB.cameranet.cameras)
- if(origin.z_lock.len && !(cam.z in origin.z_lock))
+ for (var/obj/machinery/camera/cam as anything in GLOB.cameranet.cameras)
+ if(length(origin.z_lock) && !(cam.z in origin.z_lock))
continue
L.Add(cam)
@@ -265,17 +267,23 @@
for (var/obj/machinery/camera/netcam in L)
var/list/tempnetwork = netcam.network & origin.networks
- if (tempnetwork.len)
+ if (length(tempnetwork))
+ if(!netcam.c_tag)
+ continue
T["[netcam.c_tag][netcam.can_use() ? null : " (Deactivated)"]"] = netcam
- playsound(origin, 'sound/machines/terminal_prompt.ogg', 25, 0)
+ playsound(origin, 'sound/machines/terminal_prompt.ogg', 25, FALSE)
var/camera = input("Choose which camera you want to view", "Cameras") as null|anything in T
+ if(isnull(camera))
+ return
+ if(isnull(T[camera]))
+ return
var/obj/machinery/camera/final = T[camera]
- playsound(src, "terminal_type", 25, 0)
+ playsound(src, "terminal_type", 25, FALSE)
if(final)
- playsound(origin, 'sound/machines/terminal_prompt_confirm.ogg', 25, 0)
+ playsound(origin, 'sound/machines/terminal_prompt_confirm.ogg', 25, FALSE)
remote_eye.setLoc(get_turf(final))
- C.overlay_fullscreen("flash", /atom/movable/screen/fullscreen/tiled/flash/static)
- C.clear_fullscreen("flash", 3) //Shorter flash than normal since it's an ~~advanced~~ console!
+ owner.overlay_fullscreen("flash", /atom/movable/screen/fullscreen/tiled/flash/static)
+ owner.clear_fullscreen("flash", 3) //Shorter flash than normal since it's an ~~advanced~~ console!
else
- playsound(origin, 'sound/machines/terminal_prompt_deny.ogg', 25, 0)
+ playsound(origin, 'sound/machines/terminal_prompt_deny.ogg', 25, FALSE)
diff --git a/code/modules/antagonists/cult/cult.dm b/code/modules/antagonists/cult/cult.dm
index f5761f6508..63b82f26ce 100644
--- a/code/modules/antagonists/cult/cult.dm
+++ b/code/modules/antagonists/cult/cult.dm
@@ -254,7 +254,7 @@
/datum/team/cult
name = "Cult"
- var/blood_target
+ var/atom/blood_target
var/image/blood_target_image
var/blood_target_reset_timer
diff --git a/code/modules/antagonists/cult/cult_comms.dm b/code/modules/antagonists/cult/cult_comms.dm
index b81422157c..cd348485f1 100644
--- a/code/modules/antagonists/cult/cult_comms.dm
+++ b/code/modules/antagonists/cult/cult_comms.dm
@@ -363,8 +363,8 @@
addtimer(CALLBACK(owner, TYPE_PROC_REF(/mob, update_action_buttons_icon)), base_cooldown)
C.cult_team.blood_target_image = image('icons/effects/cult_target.dmi', target, "glow", ABOVE_MOB_LAYER)
C.cult_team.blood_target_image.appearance_flags = RESET_COLOR
- C.cult_team.blood_target_image.pixel_x = -target.pixel_x
- C.cult_team.blood_target_image.pixel_y = -target.pixel_y
+ C.cult_team.blood_target_image.pixel_x = -C.cult_team.blood_target.pixel_x
+ C.cult_team.blood_target_image.pixel_y = -C.cult_team.blood_target.pixel_y
SEND_SOUND(owner, sound(pick('sound/hallucinations/over_here2.ogg','sound/hallucinations/over_here3.ogg'),0,1,75))
owner.client.images += C.cult_team.blood_target_image
for(var/datum/mind/B in SSticker.mode.cult)
diff --git a/code/modules/clothing/chameleon.dm b/code/modules/clothing/chameleon.dm
index f26da5db38..b3030b67ec 100644
--- a/code/modules/clothing/chameleon.dm
+++ b/code/modules/clothing/chameleon.dm
@@ -212,13 +212,15 @@
UpdateButtons()
/datum/action/item_action/chameleon/change/proc/update_item(obj/item/picked_item)
- target.name = initial(picked_item.name)
- target.desc = initial(picked_item.desc)
- target.icon_state = initial(picked_item.icon_state)
- if(isitem(target))
- var/obj/item/I = target
+ var/obj/item/chameleon_item = target
+
+ chameleon_item.name = initial(picked_item.name)
+ chameleon_item.desc = initial(picked_item.desc)
+ chameleon_item.icon_state = initial(picked_item.icon_state)
+ if(isitem(chameleon_item))
+ var/obj/item/I = chameleon_item
I.item_state = initial(picked_item.item_state)
- var/obj/item/clothing/CL = target
+ var/obj/item/clothing/CL = chameleon_item
var/obj/item/clothing/PCL = new picked_item
if(istype(CL) && istype(PCL))
CL.flags_cover = PCL.flags_cover
@@ -226,7 +228,7 @@
CL.mutantrace_variation = PCL.mutantrace_variation
CL.mob_overlay_icon = PCL.mob_overlay_icon
qdel(PCL)
- target.icon = initial(picked_item.icon)
+ chameleon_item.icon = initial(picked_item.icon)
/datum/action/item_action/chameleon/change/pda/update_item(obj/item/pda/picked_item)
if(!istype(target, /obj/item/pda))
diff --git a/code/modules/mining/aux_base_camera.dm b/code/modules/mining/aux_base_camera.dm
index 262e776c68..0224ff2769 100644
--- a/code/modules/mining/aux_base_camera.dm
+++ b/code/modules/mining/aux_base_camera.dm
@@ -39,15 +39,15 @@
networks = list("ss13")
var/obj/item/construction/rcd/internal/RCD //Internal RCD. The computer passes user commands to this in order to avoid massive copypaste.
circuit = /obj/item/circuitboard/computer/base_construction
- off_action = new/datum/action/innate/camera_off/base_construction
+ off_action = /datum/action/innate/camera_off/base_construction
jump_action = null
- var/datum/action/innate/aux_base/switch_mode/switch_mode_action = new //Action for switching the RCD's build modes
- var/datum/action/innate/aux_base/build/build_action = new //Action for using the RCD
- var/datum/action/innate/aux_base/airlock_type/airlock_mode_action = new //Action for setting the airlock type
- var/datum/action/innate/aux_base/window_type/window_action = new //Action for setting the window type
- var/datum/action/innate/aux_base/place_fan/fan_action = new //Action for spawning fans
+ var/datum/action/innate/aux_base/switch_mode/switch_mode_action = /datum/action/innate/aux_base/switch_mode //Action for switching the RCD's build modes
+ var/datum/action/innate/aux_base/build/build_action = /datum/action/innate/aux_base/build //Action for using the RCD
+ var/datum/action/innate/aux_base/airlock_type/airlock_mode_action = /datum/action/innate/aux_base/airlock_type //Action for setting the airlock type
+ var/datum/action/innate/aux_base/window_type/window_action = /datum/action/innate/aux_base/window_type //Action for setting the window type
+ var/datum/action/innate/aux_base/place_fan/fan_action = /datum/action/innate/aux_base/place_fan //Action for spawning fans
var/fans_remaining = 0 //Number of fans in stock.
- var/datum/action/innate/aux_base/install_turret/turret_action = new //Action for spawning turrets
+ var/datum/action/innate/aux_base/install_turret/turret_action = /datum/action/innate/aux_base/install_turret //Action for spawning turrets
var/turret_stock = 0 //Turrets in stock
var/obj/machinery/computer/auxillary_base/found_aux_console //Tracker for the Aux base console, so the eye can always find it.
@@ -58,6 +58,9 @@
/obj/machinery/computer/camera_advanced/base_construction/Initialize(mapload)
. = ..()
+
+ populate_actions_list()
+
RCD = new(src)
RCD.console = src
if(mapload) //Map spawned consoles have a filled RCD and stocked special structures
@@ -65,6 +68,20 @@
fans_remaining = 4
turret_stock = 4
+/**
+ * Fill the construction_actios list with actions
+ *
+ * Instantiate each action object that we'll be giving to users of
+ * this console, and put it in the actions list
+ */
+/obj/machinery/computer/camera_advanced/base_construction/proc/populate_actions_list()
+ actions += new switch_mode_action(src)
+ actions += new build_action(src)
+ actions += new airlock_mode_action(src)
+ actions += new window_action(src)
+ actions += new fan_action(src)
+ actions += new turret_action(src)
+
/obj/machinery/computer/camera_advanced/base_construction/CreateEye()
var/spawn_spot
@@ -94,43 +111,12 @@
return ..()
/obj/machinery/computer/camera_advanced/base_construction/GrantActions(mob/living/user)
- ..()
-
- if(switch_mode_action)
- switch_mode_action.target = src
- switch_mode_action.Grant(user)
- actions += switch_mode_action
-
- if(build_action)
- build_action.target = src
- build_action.Grant(user)
- actions += build_action
-
- if(airlock_mode_action)
- airlock_mode_action.target = src
- airlock_mode_action.Grant(user)
- actions += airlock_mode_action
-
- if(window_action)
- window_action.target = src
- window_action.Grant(user)
- actions += window_action
-
- if(fan_action)
- fan_action.target = src
- fan_action.Grant(user)
- actions += fan_action
-
- if(turret_action)
- turret_action.target = src
- turret_action.Grant(user)
- actions += turret_action
-
eyeobj.invisibility = 0 //When the eye is in use, make it visible to players so they know when someone is building.
+ return ..()
/obj/machinery/computer/camera_advanced/base_construction/remove_eye_control(mob/living/user)
- ..()
eyeobj.invisibility = INVISIBILITY_MAXIMUM //Hide the eye when not in use.
+ return ..()
/datum/action/innate/aux_base //Parent aux base action
icon_icon = 'icons/mob/actions/actions_construction.dmi'
diff --git a/code/modules/research/xenobiology/xenobio_camera.dm b/code/modules/research/xenobiology/xenobio_camera.dm
index 1660feedca..8f8508c412 100644
--- a/code/modules/research/xenobiology/xenobio_camera.dm
+++ b/code/modules/research/xenobiology/xenobio_camera.dm
@@ -22,13 +22,13 @@
desc = "A computer used for remotely handling slimes."
networks = list("ss13")
circuit = /obj/item/circuitboard/computer/xenobiology
- var/datum/action/innate/slime_place/slime_place_action
- var/datum/action/innate/slime_pick_up/slime_up_action
- var/datum/action/innate/feed_slime/feed_slime_action
- var/datum/action/innate/monkey_recycle/monkey_recycle_action
- var/datum/action/innate/slime_scan/scan_action
- var/datum/action/innate/feed_potion/potion_action
- var/datum/action/innate/hotkey_help/hotkey_help
+ var/datum/action/innate/slime_place/slime_place_action = /datum/action/innate/slime_place
+ var/datum/action/innate/slime_pick_up/slime_up_action = /datum/action/innate/slime_pick_up
+ var/datum/action/innate/feed_slime/feed_slime_action = /datum/action/innate/feed_slime
+ var/datum/action/innate/monkey_recycle/monkey_recycle_action = /datum/action/innate/monkey_recycle
+ var/datum/action/innate/slime_scan/scan_action = /datum/action/innate/slime_scan
+ var/datum/action/innate/feed_potion/potion_action = /datum/action/innate/feed_potion
+ var/datum/action/innate/hotkey_help/hotkey_help = /datum/action/innate/hotkey_help
var/list/stored_slimes
var/obj/item/slimepotion/slime/current_potion
@@ -43,16 +43,16 @@
/obj/machinery/computer/camera_advanced/xenobio/Initialize(mapload)
. = ..()
- slime_place_action = new
- slime_up_action = new
- feed_slime_action = new
- monkey_recycle_action = new
- scan_action = new
- potion_action = new
- hotkey_help = new
+
+ generate_actions()
+
stored_slimes = list()
RegisterSignal(src, COMSIG_ATOM_CONTENTS_DEL, PROC_REF(on_contents_del))
+/obj/machinery/computer/camera_advanced/xenobio/proc/generate_actions()
+ actions += new scan_action(src)
+ actions += new hotkey_help(src)
+
/obj/machinery/computer/camera_advanced/xenobio/Destroy()
stored_slimes = null
QDEL_NULL(current_potion)
@@ -72,41 +72,6 @@
/obj/machinery/computer/camera_advanced/xenobio/GrantActions(mob/living/user)
..()
- if(slime_up_action && (upgradetier & XENOBIO_UPGRADE_SLIMEBASIC)) //CIT CHANGE - makes slime-related actions require XENOBIO_UPGRADE_SLIMEBASIC
- slime_up_action.target = src
- slime_up_action.Grant(user)
- actions += slime_up_action
-
- if(slime_place_action && (upgradetier & XENOBIO_UPGRADE_SLIMEBASIC)) //CIT CHANGE - makes slime-related actions require XENOBIO_UPGRADE_SLIMEBASIC
- slime_place_action.target = src
- slime_place_action.Grant(user)
- actions += slime_place_action
-
- if(feed_slime_action && (upgradetier & XENOBIO_UPGRADE_MONKEYS)) //CIT CHANGE - makes monkey-related actions require XENOBIO_UPGRADE_MONKEYS
- feed_slime_action.target = src
- feed_slime_action.Grant(user)
- actions += feed_slime_action
-
- if(monkey_recycle_action && (upgradetier & XENOBIO_UPGRADE_MONKEYS)) //CIT CHANGE - makes monkey-related actions require XENOBIO_UPGRADE_MONKEYS
- monkey_recycle_action.target = src
- monkey_recycle_action.Grant(user)
- actions += monkey_recycle_action
-
- if(scan_action)
- scan_action.target = src
- scan_action.Grant(user)
- actions += scan_action
-
- if(potion_action && (upgradetier & XENOBIO_UPGRADE_SLIMEADV)) // CIT CHANGE - makes giving slimes potions via console require XENOBIO_UPGRADE_SLIMEADV
- potion_action.target = src
- potion_action.Grant(user)
- actions += potion_action
-
- if(hotkey_help)
- hotkey_help.target = src
- hotkey_help.Grant(user)
- actions += hotkey_help
-
RegisterSignal(user, COMSIG_XENO_SLIME_CLICK_CTRL, PROC_REF(XenoSlimeClickCtrl))
RegisterSignal(user, COMSIG_XENO_SLIME_CLICK_ALT, PROC_REF(XenoSlimeClickAlt))
RegisterSignal(user, COMSIG_XENO_SLIME_CLICK_SHIFT, PROC_REF(XenoSlimeClickShift))
@@ -139,10 +104,21 @@
else
upgradetier |= I
successfulupgrade = TRUE
+ if(I == XENOBIO_UPGRADE_SLIMEBASIC)
+ actions += new slime_up_action(src)
+ actions += new slime_place_action(src)
if(I == XENOBIO_UPGRADE_SLIMEADV)
+ actions += new potion_action(src)
max_slimes = 10
+ if(I == XENOBIO_UPGRADE_MONKEYS)
+ actions += new feed_slime_action(src)
+ actions += new monkey_recycle_action(src)
if(successfulupgrade)
to_chat(user, "You have successfully upgraded [src] with [O].")
+
+ for(var/datum/action/actions_removed as anything in actions)
+ actions_removed.Remove(current_user)
+ GrantActions(current_user)
else
to_chat(user, "[src] already has the contents of [O] installed!")
return
diff --git a/code/modules/surgery/dental_implant.dm b/code/modules/surgery/dental_implant.dm
index e8d0564c62..b5461da25a 100644
--- a/code/modules/surgery/dental_implant.dm
+++ b/code/modules/surgery/dental_implant.dm
@@ -33,10 +33,11 @@
/datum/action/item_action/hands_free/activate_pill/Trigger()
if(!..())
return FALSE
- to_chat(owner, "You grit your teeth and burst the implanted [target.name]!")
+ var/obj/item/item_target = target
+ to_chat(owner, span_notice("You grit your teeth and burst the implanted [item_target.name]!"))
log_combat(owner, null, "swallowed an implanted pill", target)
- if(target.reagents.total_volume)
- target.reagents.reaction(owner, INGEST)
- target.reagents.trans_to(owner, target.reagents.total_volume, log = "dental pill swallow")
+ if(item_target.reagents.total_volume)
+ item_target.reagents.reaction(owner, INGEST)
+ item_target.reagents.trans_to(owner, item_target.reagents.total_volume, log = "dental pill swallow")
qdel(target)
return TRUE