diff --git a/code/__DEFINES/actions.dm b/code/__DEFINES/actions.dm
new file mode 100644
index 000000000000..7818244e5257
--- /dev/null
+++ b/code/__DEFINES/actions.dm
@@ -0,0 +1,36 @@
+///Action button checks if user is restrained
+#define AB_CHECK_RESTRAINED (1<<0)
+///Action button checks if user is stunned
+#define AB_CHECK_STUN (1<<1)
+///Action button checks if user is resting
+#define AB_CHECK_LYING (1<<2)
+///Action button checks if user is conscious
+#define AB_CHECK_CONSCIOUS (1<<3)
+
+/*
+DEFINE_BITFIELD(check_flags, list(
+ "CHECK IF RESTRAINED" = AB_CHECK_RESTRAINED,
+ "CHECK IF STUNNED" = AB_CHECK_STUN,
+ "CHECK IF LYING DOWN" = AB_CHECK_LYING,
+ "CHECK IF CONSCIOUS" = AB_CHECK_CONSCIOUS,
+)) */
+
+///Action button triggered with right click
+#define TRIGGER_SECONDARY_ACTION (1<<0)
+///Action triggered to ignore any availability checks
+#define TRIGGER_FORCE_AVAILABLE (1<<1)
+
+#define ACTION_BUTTON_DEFAULT_BACKGROUND "_use_ui_default_background"
+
+#define UPDATE_BUTTON_NAME (1<<0)
+#define UPDATE_BUTTON_ICON (1<<1)
+#define UPDATE_BUTTON_BACKGROUND (1<<2)
+#define UPDATE_BUTTON_OVERLAY (1<<3)
+#define UPDATE_BUTTON_STATUS (1<<4)
+
+/// Takes in a typepath of a `/datum/action` and adds it to `src`.
+/// Only useful if you want to add the action and never desire to reference it again ever.
+#define GRANT_ACTION(typepath) do {\
+ var/datum/action/_ability = new typepath(src);\
+ _ability.Grant(src);\
+} while (FALSE)
diff --git a/code/__DEFINES/dcs/signals.dm b/code/__DEFINES/dcs/signals.dm
index f216a416c5cc..4f55d7dfb80a 100644
--- a/code/__DEFINES/dcs/signals.dm
+++ b/code/__DEFINES/dcs/signals.dm
@@ -459,97 +459,6 @@
/// from /obj/machinery/power/supermatter_crystal/process_atmos(); when the SM sounds an audible alarm
#define COMSIG_SUPERMATTER_DELAM_ALARM "sm_delam_alarm"
-// /obj/item signals
-#define COMSIG_ITEM_ATTACK "item_attack" //from base of obj/item/attack(): (/mob/living/target, /mob/living/user)
-#define COMSIG_ITEM_ATTACK_SELF "item_attack_self" //from base of obj/item/attack_self(): (/mob)
- #define COMPONENT_NO_INTERACT 1
-#define COMSIG_ITEM_ATTACK_OBJ "item_attack_obj" //from base of obj/item/attack_obj(): (/obj, /mob)
- #define COMPONENT_NO_ATTACK_OBJ 1
-#define COMSIG_ITEM_PRE_ATTACK "item_pre_attack" //from base of obj/item/pre_attack(): (atom/target, mob/user, params)
- #define COMPONENT_NO_ATTACK 1
-#define COMSIG_ITEM_AFTERATTACK "item_afterattack" //from base of obj/item/afterattack(): (atom/target, mob/user, params)
-#define COMSIG_ITEM_ALT_AFTERATTACK "item_alt_afterattack" //from base of obj/item/altafterattack(): (atom/target, mob/user, proximity, params)
-#define COMSIG_ITEM_EQUIPPED "item_equip" //from base of obj/item/equipped(): (/mob/equipper, slot)
-/// A mob has just unequipped an item.
-#define COMSIG_MOB_UNEQUIPPED_ITEM "mob_unequipped_item"
- // Do not grant actions on equip.
- #define COMPONENT_NO_GRANT_ACTIONS 1
-#define COMSIG_ITEM_DROPPED "item_drop" //from base of obj/item/dropped(): (mob/user)
- // relocated, tell inventory procs if those called this that the item isn't available anymore.
- #define COMPONENT_DROPPED_RELOCATION 1
-#define COMSIG_ITEM_PICKUP "item_pickup" //from base of obj/item/pickup(): (/mob/taker)
-#define COMSIG_ITEM_ATTACK_ZONE "item_attack_zone" //from base of mob/living/carbon/attacked_by(): (mob/living/carbon/target, mob/living/user, hit_zone)
-#define COMSIG_ITEM_IMBUE_SOUL "item_imbue_soul" //return a truthy value to prevent ensouling, checked in /obj/effect/proc_holder/spell/targeted/lichdom/cast(): (mob/user)
-#define COMSIG_ITEM_HIT_REACT "item_hit_react" //from base of obj/item/hit_reaction(): (list/args)
-#define COMSIG_ITEM_WEARERCROSSED "wearer_crossed" //called on item when crossed by something (): (/atom/movable)
-#define COMSIG_ITEM_SHARPEN_ACT "sharpen_act" //from base of item/sharpener/attackby(): (amount, max)
- #define COMPONENT_BLOCK_SHARPEN_APPLIED 1
- #define COMPONENT_BLOCK_SHARPEN_BLOCKED 2
- #define COMPONENT_BLOCK_SHARPEN_ALREADY 4
- #define COMPONENT_BLOCK_SHARPEN_MAXED 8
-#define COMSIG_ITEM_MICROWAVE_ACT "microwave_act" //called on item when microwaved (): (obj/machinery/microwave/M)
-
-// /obj/item signals for economy
-#define COMSIG_ITEM_SOLD "item_sold" //called when an item is sold by the exports subsystem
-#define COMSIG_STRUCTURE_UNWRAPPED "structure_unwrapped" //called when a wrapped up structure is opened by hand
-#define COMSIG_ITEM_UNWRAPPED "item_unwrapped" //called when a wrapped up item is opened by hand
- #define COMSIG_ITEM_SPLIT_VALUE 1
-#define COMSIG_ITEM_SPLIT_PROFIT "item_split_profits" //Called when getting the item's exact ratio for cargo's profit.
-
-#define COMSIG_ITEM_WORN_OVERLAYS "item_worn_overlays" //from base of obj/item/worn_overlays(): (isinhands, icon_file, used_state, style_flags, list/overlays)
-#define COMSIG_ARMOR_PLATED "armor_plated" //called when an armor plate is successfully applied to an object
-// THE FOLLOWING TWO BLOCKS SHOULD RETURN BLOCK FLAGS AS DEFINED IN __DEFINES/combat.dm!
-#define COMSIG_ITEM_CHECK_BLOCK "check_block" //from base of obj/item/check_block(): (mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
-#define COMSIG_ITEM_RUN_BLOCK "run_block" //from base of obj/item/run_block(): (mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
-// Item mouse siganls
-#define COMSIG_ITEM_MOUSE_EXIT "item_mouse_exit" //from base of obj/item/MouseExited(): (location, control, params)
-#define COMSIG_ITEM_MOUSE_ENTER "item_mouse_enter" //from base of obj/item/MouseEntered(): (location, control, params)
-#define COMSIG_ITEM_DECONSTRUCTOR_DEEPSCAN "deconstructor_deepscan" //Called by deconstructive analyzers deepscanning an item: (obj/machinery/rnd/destructive_analyzer/analyzer_machine, mob/user, list/information_list)
-#define COMSIG_ITEM_DISABLE_EMBED "item_disable_embed" ///from [/obj/item/proc/disableEmbedding]:
-#define COMSIG_MINE_TRIGGERED "minegoboom" ///from [/obj/effect/mine/proc/triggermine]:
- // Uncovered information
- #define COMPONENT_DEEPSCAN_UNCOVERED_INFORMATION 1
-///Called when an item is being offered, from [/obj/item/proc/on_offered(mob/living/carbon/offerer)]
-#define COMSIG_ITEM_OFFERING "item_offering"
- ///Interrupts the offer proc
- #define COMPONENT_OFFER_INTERRUPT (1<<0)
-///Called when an someone tries accepting an offered item, from [/obj/item/proc/on_offer_taken(mob/living/carbon/offer, mob/living/carbon/taker)]
-#define COMSIG_ITEM_OFFER_TAKEN "item_offer_taken"
- ///Interrupts the offer acceptance
- #define COMPONENT_OFFER_TAKE_INTERRUPT (1<<0)
-///from [/obj/structure/closet/supplypod/proc/endlaunch]:
-#define COMSIG_SUPPLYPOD_LANDED "supplypodgoboom"
-
-// /obj/item/grenade signals
-#define COMSIG_GRENADE_PRIME "grenade_prime" //called in /obj/item/gun/process_fire (user, target, params, zone_override)
-#define COMSIG_GRENADE_ARMED "grenade_armed" //called in /obj/item/gun/process_fire (user, target, params, zone_override)
-
-// /obj/item/clothing signals
-#define COMSIG_SHOES_STEP_ACTION "shoes_step_action" //from base of obj/item/clothing/shoes/proc/step_action(): ()
-#define COMSIG_SUIT_MADE_HELMET "suit_made_helmet" //from base of obj/item/clothing/suit/MakeHelmet(): (helmet)
-
-// /obj/item/implant signals
-#define COMSIG_IMPLANT_ACTIVATED "implant_activated" //from base of /obj/item/implant/proc/activate(): ()
-#define COMSIG_IMPLANT_IMPLANTING "implant_implanting" //from base of /obj/item/implant/proc/implant(): (list/args)
- #define COMPONENT_STOP_IMPLANTING 1
-#define COMSIG_IMPLANT_OTHER "implant_other" //called on already installed implants when a new one is being added in /obj/item/implant/proc/implant(): (list/args, obj/item/implant/new_implant)
- //#define COMPONENT_STOP_IMPLANTING 1 //The name makes sense for both
- #define COMPONENT_DELETE_NEW_IMPLANT 2
- #define COMPONENT_DELETE_OLD_IMPLANT 4
-#define COMSIG_IMPLANT_EXISTING_UPLINK "implant_uplink_exists" //called on implants being implanted into someone with an uplink implant: (datum/component/uplink)
- //This uses all return values of COMSIG_IMPLANT_OTHER
-#define COMSIG_IMPLANT_REMOVING "implant_removing" //from base of /obj/item/implant/proc/removed() (list/args)
-
-// /obj/item/pda signals
-#define COMSIG_PDA_CHANGE_RINGTONE "pda_change_ringtone" //called on pda when the user changes the ringtone: (mob/living/user, new_ringtone)
- #define COMPONENT_STOP_RINGTONE_CHANGE 1
-
-// /obj/item/radio signals
-#define COMSIG_RADIO_NEW_FREQUENCY "radio_new_frequency" //called from base of /obj/item/radio/proc/set_frequency(): (list/args)
-
-// /obj/item/pen signals
-#define COMSIG_PEN_ROTATED "pen_rotated" //called after rotation in /obj/item/pen/attack_self(): (rotation, mob/living/carbon/user)
-
// /obj/item/projectile signals (sent to the firer)
#define COMSIG_PROJECTILE_SELF_ON_HIT "projectile_self_on_hit" ///from base of /obj/item/projectile/proc/on_hit(): (atom/movable/firer, atom/target, Angle, hit_limb)
#define COMSIG_PROJECTILE_ON_HIT "projectile_on_hit" ///from base of /obj/item/projectile/proc/on_hit(): (atom/movable/firer, atom/target, Angle, hit_limb)
@@ -680,10 +589,6 @@
// /datum/component/squeak signals
#define COMSIG_CROSS_SQUEAKED "cross_squeaked" // sent when a squeak component squeaks from crossing something, to delay anything else crossing that might squeak to prevent ear hurt.
-// /datum/action signals
-#define COMSIG_ACTION_TRIGGER "action_trigger" //from base of datum/action/proc/Trigger(): (datum/action)
- #define COMPONENT_ACTION_BLOCK_TRIGGER 1
-
//Xenobio hotkeys
#define COMSIG_XENO_SLIME_CLICK_CTRL "xeno_slime_click_ctrl" //from slime CtrlClickOn(): (/mob)
#define COMSIG_XENO_SLIME_CLICK_ALT "xeno_slime_click_alt" //from slime AltClickOn(): (/mob)
diff --git a/code/__DEFINES/dcs/signals/signals_action.dm b/code/__DEFINES/dcs/signals/signals_action.dm
index 62eccf282397..c6e042a0581d 100644
--- a/code/__DEFINES/dcs/signals/signals_action.dm
+++ b/code/__DEFINES/dcs/signals/signals_action.dm
@@ -1,6 +1,53 @@
+// Action signals
+
+///from base of datum/action/proc/Trigger(): (datum/action)
+#define COMSIG_ACTION_TRIGGER "action_trigger"
+ // Return to block the trigger from occurring
+ #define COMPONENT_ACTION_BLOCK_TRIGGER (1<<0)
+/// From /datum/action/Grant(): (mob/grant_to)
+#define COMSIG_ACTION_GRANTED "action_grant"
+/// From /datum/action/Grant(): (datum/action)
+#define COMSIG_MOB_GRANTED_ACTION "mob_action_grant"
+/// From /datum/action/Remove(): (mob/removed_from)
+#define COMSIG_ACTION_REMOVED "action_removed"
+/// From /datum/action/Remove(): (datum/action)
+#define COMSIG_MOB_REMOVED_ACTION "mob_action_removed"
+/// From /datum/action/apply_button_overlay()
+#define COMSIG_ACTION_OVERLAY_APPLY "action_overlay_applied"
+
+// Cooldown action signals
+
/// From base of /datum/action/cooldown/proc/PreActivate(), sent to the action owner: (datum/action/cooldown/activated)
#define COMSIG_MOB_ABILITY_STARTED "mob_ability_base_started"
/// Return to block the ability from starting / activating
#define COMPONENT_BLOCK_ABILITY_START (1<<0)
/// From base of /datum/action/cooldown/proc/PreActivate(), sent to the action owner: (datum/action/cooldown/finished)
#define COMSIG_MOB_ABILITY_FINISHED "mob_ability_base_finished"
+
+/// From base of /datum/action/cooldown/proc/set_statpanel_format(): (list/stat_panel_data)
+#define COMSIG_ACTION_SET_STATPANEL "ability_set_statpanel"
+
+// Specific cooldown action signals
+
+/// From base of /datum/action/cooldown/mob_cooldown/blood_warp/proc/blood_warp(): ()
+#define COMSIG_BLOOD_WARP "mob_ability_blood_warp"
+/// From base of /datum/action/cooldown/mob_cooldown/charge/proc/do_charge(): ()
+#define COMSIG_STARTED_CHARGE "mob_ability_charge_started"
+/// From base of /datum/action/cooldown/mob_cooldown/charge/proc/do_charge(): ()
+#define COMSIG_FINISHED_CHARGE "mob_ability_charge_finished"
+/// From base of /datum/action/cooldown/mob_cooldown/lava_swoop/proc/swoop_attack(): ()
+#define COMSIG_SWOOP_INVULNERABILITY_STARTED "mob_swoop_invulnerability_started"
+/// From base of /datum/action/cooldown/mob_cooldown/lava_swoop/proc/swoop_attack(): ()
+#define COMSIG_LAVA_ARENA_FAILED "mob_lava_arena_failed"
+
+/// From /datum/action/vehicle/sealed/mecha/mech_toggle_safeties/proc/update_action_icon(): ()
+#define COMSIG_MECH_SAFETIES_TOGGLE "mech_safeties_toggle"
+
+/// From /datum/action/cooldown/mob_cooldown/assume_form/proc/assume_appearances(), sent to the action owner: (atom/movable/target)
+#define COMSIG_ACTION_DISGUISED_APPEARANCE "mob_ability_disguise_appearance"
+
+/// From /datum/action/cooldown/manual_heart/Activate(): ()
+#define COMSIG_HEART_MANUAL_PULSE "heart_manual_pulse"
+
+/// From /datum/action/cooldown/mob_cooldown/capture_photo/Activate():
+#define COMSIG_ACTION_PHOTO_CAPTURED "action_photo_captured"
diff --git a/code/__DEFINES/dcs/signals/signals_object.dm b/code/__DEFINES/dcs/signals/signals_object.dm
new file mode 100644
index 000000000000..ce0436eebfd9
--- /dev/null
+++ b/code/__DEFINES/dcs/signals/signals_object.dm
@@ -0,0 +1,96 @@
+// /obj/item signals
+#define COMSIG_ITEM_ATTACK "item_attack" //from base of obj/item/attack(): (/mob/living/target, /mob/living/user)
+#define COMSIG_ITEM_ATTACK_SELF "item_attack_self" //from base of obj/item/attack_self(): (/mob)
+ #define COMPONENT_NO_INTERACT 1
+#define COMSIG_ITEM_ATTACK_OBJ "item_attack_obj" //from base of obj/item/attack_obj(): (/obj, /mob)
+ #define COMPONENT_NO_ATTACK_OBJ 1
+#define COMSIG_ITEM_PRE_ATTACK "item_pre_attack" //from base of obj/item/pre_attack(): (atom/target, mob/user, params)
+ #define COMPONENT_NO_ATTACK 1
+#define COMSIG_ITEM_AFTERATTACK "item_afterattack" //from base of obj/item/afterattack(): (atom/target, mob/user, params)
+#define COMSIG_ITEM_ALT_AFTERATTACK "item_alt_afterattack" //from base of obj/item/altafterattack(): (atom/target, mob/user, proximity, params)
+#define COMSIG_ITEM_EQUIPPED "item_equip" //from base of obj/item/equipped(): (/mob/equipper, slot)
+/// A mob has just unequipped an item.
+#define COMSIG_MOB_UNEQUIPPED_ITEM "mob_unequipped_item"
+ // Do not grant actions on equip.
+ #define COMPONENT_NO_GRANT_ACTIONS 1
+#define COMSIG_ITEM_DROPPED "item_drop" //from base of obj/item/dropped(): (mob/user)
+ // relocated, tell inventory procs if those called this that the item isn't available anymore.
+ #define COMPONENT_DROPPED_RELOCATION 1
+#define COMSIG_ITEM_PICKUP "item_pickup" //from base of obj/item/pickup(): (/mob/taker)
+
+/// Sent from obj/item/item_action_slot_check(): (mob/user, datum/action, slot)
+#define COMSIG_ITEM_UI_ACTION_SLOT_CHECKED "item_action_slot_checked"
+ /// Return to prevent the default behavior (attack_selfing) from occurring.
+ #define COMPONENT_ITEM_ACTION_SLOT_INVALID (1<<0)
+
+#define COMSIG_ITEM_ATTACK_ZONE "item_attack_zone" //from base of mob/living/carbon/attacked_by(): (mob/living/carbon/target, mob/living/user, hit_zone)
+#define COMSIG_ITEM_IMBUE_SOUL "item_imbue_soul" //return a truthy value to prevent ensouling, checked in /obj/effect/proc_holder/spell/targeted/lichdom/cast(): (mob/user)
+#define COMSIG_ITEM_HIT_REACT "item_hit_react" //from base of obj/item/hit_reaction(): (list/args)
+#define COMSIG_ITEM_WEARERCROSSED "wearer_crossed" //called on item when crossed by something (): (/atom/movable)
+#define COMSIG_ITEM_SHARPEN_ACT "sharpen_act" //from base of item/sharpener/attackby(): (amount, max)
+ #define COMPONENT_BLOCK_SHARPEN_APPLIED 1
+ #define COMPONENT_BLOCK_SHARPEN_BLOCKED 2
+ #define COMPONENT_BLOCK_SHARPEN_ALREADY 4
+ #define COMPONENT_BLOCK_SHARPEN_MAXED 8
+#define COMSIG_ITEM_MICROWAVE_ACT "microwave_act" //called on item when microwaved (): (obj/machinery/microwave/M)
+
+// /obj/item signals for economy
+#define COMSIG_ITEM_SOLD "item_sold" //called when an item is sold by the exports subsystem
+#define COMSIG_STRUCTURE_UNWRAPPED "structure_unwrapped" //called when a wrapped up structure is opened by hand
+#define COMSIG_ITEM_UNWRAPPED "item_unwrapped" //called when a wrapped up item is opened by hand
+ #define COMSIG_ITEM_SPLIT_VALUE 1
+#define COMSIG_ITEM_SPLIT_PROFIT "item_split_profits" //Called when getting the item's exact ratio for cargo's profit.
+
+#define COMSIG_ITEM_WORN_OVERLAYS "item_worn_overlays" //from base of obj/item/worn_overlays(): (isinhands, icon_file, used_state, style_flags, list/overlays)
+#define COMSIG_ARMOR_PLATED "armor_plated" //called when an armor plate is successfully applied to an object
+// THE FOLLOWING TWO BLOCKS SHOULD RETURN BLOCK FLAGS AS DEFINED IN __DEFINES/combat.dm!
+#define COMSIG_ITEM_CHECK_BLOCK "check_block" //from base of obj/item/check_block(): (mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
+#define COMSIG_ITEM_RUN_BLOCK "run_block" //from base of obj/item/run_block(): (mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
+// Item mouse siganls
+#define COMSIG_ITEM_MOUSE_EXIT "item_mouse_exit" //from base of obj/item/MouseExited(): (location, control, params)
+#define COMSIG_ITEM_MOUSE_ENTER "item_mouse_enter" //from base of obj/item/MouseEntered(): (location, control, params)
+#define COMSIG_ITEM_DECONSTRUCTOR_DEEPSCAN "deconstructor_deepscan" //Called by deconstructive analyzers deepscanning an item: (obj/machinery/rnd/destructive_analyzer/analyzer_machine, mob/user, list/information_list)
+#define COMSIG_ITEM_DISABLE_EMBED "item_disable_embed" ///from [/obj/item/proc/disableEmbedding]:
+#define COMSIG_MINE_TRIGGERED "minegoboom" ///from [/obj/effect/mine/proc/triggermine]:
+ // Uncovered information
+ #define COMPONENT_DEEPSCAN_UNCOVERED_INFORMATION 1
+///Called when an item is being offered, from [/obj/item/proc/on_offered(mob/living/carbon/offerer)]
+#define COMSIG_ITEM_OFFERING "item_offering"
+ ///Interrupts the offer proc
+ #define COMPONENT_OFFER_INTERRUPT (1<<0)
+///Called when an someone tries accepting an offered item, from [/obj/item/proc/on_offer_taken(mob/living/carbon/offer, mob/living/carbon/taker)]
+#define COMSIG_ITEM_OFFER_TAKEN "item_offer_taken"
+ ///Interrupts the offer acceptance
+ #define COMPONENT_OFFER_TAKE_INTERRUPT (1<<0)
+///from [/obj/structure/closet/supplypod/proc/endlaunch]:
+#define COMSIG_SUPPLYPOD_LANDED "supplypodgoboom"
+
+// /obj/item/grenade signals
+#define COMSIG_GRENADE_PRIME "grenade_prime" //called in /obj/item/gun/process_fire (user, target, params, zone_override)
+#define COMSIG_GRENADE_ARMED "grenade_armed" //called in /obj/item/gun/process_fire (user, target, params, zone_override)
+
+// /obj/item/clothing signals
+#define COMSIG_SHOES_STEP_ACTION "shoes_step_action" //from base of obj/item/clothing/shoes/proc/step_action(): ()
+#define COMSIG_SUIT_MADE_HELMET "suit_made_helmet" //from base of obj/item/clothing/suit/MakeHelmet(): (helmet)
+
+// /obj/item/implant signals
+#define COMSIG_IMPLANT_ACTIVATED "implant_activated" //from base of /obj/item/implant/proc/activate(): ()
+#define COMSIG_IMPLANT_IMPLANTING "implant_implanting" //from base of /obj/item/implant/proc/implant(): (list/args)
+ #define COMPONENT_STOP_IMPLANTING 1
+#define COMSIG_IMPLANT_OTHER "implant_other" //called on already installed implants when a new one is being added in /obj/item/implant/proc/implant(): (list/args, obj/item/implant/new_implant)
+ //#define COMPONENT_STOP_IMPLANTING 1 //The name makes sense for both
+ #define COMPONENT_DELETE_NEW_IMPLANT 2
+ #define COMPONENT_DELETE_OLD_IMPLANT 4
+#define COMSIG_IMPLANT_EXISTING_UPLINK "implant_uplink_exists" //called on implants being implanted into someone with an uplink implant: (datum/component/uplink)
+ //This uses all return values of COMSIG_IMPLANT_OTHER
+#define COMSIG_IMPLANT_REMOVING "implant_removing" //from base of /obj/item/implant/proc/removed() (list/args)
+
+// /obj/item/pda signals
+#define COMSIG_PDA_CHANGE_RINGTONE "pda_change_ringtone" //called on pda when the user changes the ringtone: (mob/living/user, new_ringtone)
+ #define COMPONENT_STOP_RINGTONE_CHANGE 1
+
+// /obj/item/radio signals
+#define COMSIG_RADIO_NEW_FREQUENCY "radio_new_frequency" //called from base of /obj/item/radio/proc/set_frequency(): (list/args)
+
+// /obj/item/pen signals
+#define COMSIG_PEN_ROTATED "pen_rotated" //called after rotation in /obj/item/pen/attack_self(): (rotation, mob/living/carbon/user)
diff --git a/code/__DEFINES/sight.dm b/code/__DEFINES/sight.dm
index 5cac2900823b..875625f9935e 100644
--- a/code/__DEFINES/sight.dm
+++ b/code/__DEFINES/sight.dm
@@ -1,3 +1,5 @@
+#define INVISIBILITY_NONE 0
+
#define SEE_INVISIBLE_MINIMUM 5
#define INVISIBILITY_LIGHTING 20
diff --git a/code/__DEFINES/spans.dm b/code/__DEFINES/spans.dm
index b6b633d91a5d..33a64697fee8 100644
--- a/code/__DEFINES/spans.dm
+++ b/code/__DEFINES/spans.dm
@@ -56,8 +56,10 @@
#define span_icon(str) ("" + str + "")
#define span_info(str) ("" + str + "")
#define span_interface(str) ("" + str + "")
+#define span_italics(str) ("" + str + "")
#define span_looc(str) ("" + str + "")
+#define span_love(str) ("" + str + "")
#define span_medal(str) ("" + str + "")
#define span_medradio(str) ("" + str + "")
#define span_memo(str) ("" + str + "")
diff --git a/code/__HELPERS/roundend.dm b/code/__HELPERS/roundend.dm
index 95e36ba1a5ad..044ff7512e5b 100644
--- a/code/__HELPERS/roundend.dm
+++ b/code/__HELPERS/roundend.dm
@@ -662,12 +662,18 @@
/datum/action/report
name = "Show roundend report"
button_icon_state = "round_end"
+ check_flags = NONE
+ required_mobility_flags = NONE
-/datum/action/report/Trigger()
+/datum/action/report/Trigger(trigger_flags)
+ . = ..()
+ if(!.)
+ return FALSE
if(owner && GLOB.common_report && SSticker.current_state == GAME_STATE_FINISHED)
SSticker.show_roundend_report(owner.client)
+ return TRUE
-/datum/action/report/IsAvailable()
+/datum/action/report/IsAvailable(feedback)
return TRUE
/datum/action/report/Topic(href,href_list)
diff --git a/code/_onclick/hud/action_button.dm b/code/_onclick/hud/action_button.dm
index cb88f56dcb1a..1fd89899a655 100644
--- a/code/_onclick/hud/action_button.dm
+++ b/code/_onclick/hud/action_button.dm
@@ -1,5 +1,3 @@
-#define ACTION_BUTTON_DEFAULT_BACKGROUND "default"
-
/atom/movable/screen/movable/action_button
var/datum/action/linked_action
var/datum/hud/our_hud
@@ -7,9 +5,13 @@
screen_loc = null
mouse_over_pointer = MOUSE_HAND_POINTER
- var/button_icon_state
- var/appearance_cache
+ /// The icon state of our active overlay, used to prevent re-applying identical overlays
+ var/active_overlay_icon_state
+ /// The icon state of our active underlay, used to prevent re-applying identical underlays
+ var/active_underlay_icon_state
+ /// The overlay we have overtop our button
var/mutable_appearance/button_overlay
+
/// Where we are currently placed on the hud. SCRN_OBJ_DEFAULT asks the linked action what it thinks
var/location = SCRN_OBJ_DEFAULT
/// A unique bitflag, combined with the name of our linked action this lets us persistently remember any user changes to our position
@@ -17,6 +19,8 @@
/// A weakref of the last thing we hovered over
/// God I hate how dragging works
var/datum/weakref/last_hovored_ref
+ /// overlay for keybind maptext
+ var/mutable_appearance/keybind_maptext
/atom/movable/screen/movable/action_button/Destroy()
if(our_hud)
@@ -44,20 +48,33 @@
/atom/movable/screen/movable/action_button/Click(location,control,params)
if (!can_use(usr))
- return
+ return FALSE
var/list/modifiers = params2list(params)
+ /* if(LAZYACCESS(modifiers, ALT_CLICK))
+ begin_creating_bind(usr)
+ return TRUE */
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())
+ if(!usr.CheckActionCooldown())
return
- clicker.DelayNextAction(1)
- linked_action.Trigger()
+ usr.DelayNextAction(1)
+ var/trigger_flags
+ if(LAZYACCESS(modifiers, RIGHT_CLICK))
+ trigger_flags |= TRIGGER_SECONDARY_ACTION
+ linked_action.Trigger(trigger_flags = trigger_flags)
return TRUE
+/* /atom/movable/screen/movable/action_button/proc/begin_creating_bind(mob/user)
+ if(!isnull(linked_action.full_key))
+ linked_action.full_key = null
+ linked_action.update_button_status(src)
+ return
+ linked_action.full_key = tgui_input_keycombo(user, "Please bind a key for this action.")
+ linked_action.update_button_status(src) */
+
// Entered and Exited won't fire while you're dragging something, because you're still "holding" it
// Very much byond logic, but I want nice behavior, so we fake it with drag
/atom/movable/screen/movable/action_button/MouseDrag(atom/over_object, atom/src_location, atom/over_location, src_control, over_control, params)
@@ -77,11 +94,8 @@
if(old_object)
old_object.MouseExited(over_location, over_control, params)
- if(QDELETED(over_location))
- last_hovored_ref = null
- return
last_hovored_ref = WEAKREF(over_object)
- over_object.MouseEntered(over_location, over_control, params)
+ over_object?.MouseEntered(over_location, over_control, params)
/atom/movable/screen/movable/action_button/MouseEntered(location, control, params)
. = ..()
@@ -96,30 +110,37 @@
last_hovored_ref = null
if(!can_use(usr))
return
+
var/datum/hud/our_hud = usr.hud_used
if(over_object == src)
our_hud.hide_landings()
return
+
if(istype(over_object, /atom/movable/screen/action_landing))
var/atom/movable/screen/action_landing/reserve = over_object
reserve.hit_by(src)
- our_hud.hide_landings()
save_position()
+ our_hud.hide_landings()
return
- our_hud.hide_landings()
if(istype(over_object, /atom/movable/screen/button_palette) || istype(over_object, /atom/movable/screen/palette_scroll))
our_hud.position_action(src, SCRN_OBJ_IN_PALETTE)
save_position()
+ our_hud.hide_landings()
return
+
if(istype(over_object, /atom/movable/screen/movable/action_button))
var/atom/movable/screen/movable/action_button/button = over_object
our_hud.position_action_relative(src, button)
save_position()
+ our_hud.hide_landings()
return
+
. = ..()
+
our_hud.position_action(src, screen_loc)
save_position()
+ our_hud.hide_landings()
/atom/movable/screen/movable/action_button/proc/save_position()
var/mob/user = our_hud.mymob
@@ -151,6 +172,15 @@
user.client.prefs.action_buttons_screen_locs -= "[name]_[id]"
user.client.prefs.queue_save_pref(1 SECONDS, TRUE)
+/atom/movable/screen/movable/action_button/proc/update_keybind_maptext(key)
+ cut_overlay(keybind_maptext)
+ if(!key)
+ return
+ keybind_maptext = new
+ keybind_maptext.maptext = MAPTEXT("[key]")
+ keybind_maptext.transform = keybind_maptext.transform.Translate(-4, length(key) > 1 ? -6 : 2) //with modifiers, its placed lower so cooldown is visible
+ add_overlay(keybind_maptext)
+
/**
* 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.
@@ -161,13 +191,18 @@
. = list()
.["bg_icon"] = ui_style
.["bg_state"] = "template"
+ .["bg_state_active"] = "template_active"
-//see human and alien hud for specific implementations.
-
-/mob/proc/update_action_buttons_icon(status_only = FALSE)
- for(var/X in actions)
- var/datum/action/A = X
- A.UpdateButtons(status_only)
+/**
+ * Updates all action buttons this mob has.
+ *
+ * Arguments:
+ * * update_flags - Which flags of the action should we update
+ * * force - Force buttons update even if the given button icon state has not changed
+ */
+/mob/proc/update_mob_action_buttons(update_flags = ALL, force = FALSE)
+ for(var/datum/action/current_action as anything in actions)
+ current_action.build_all_button_icons(update_flags, force)
/**
* This proc handles adding all of the mob's actions to their screen
@@ -186,7 +221,7 @@
for(var/datum/action/action as anything in actions)
var/atom/movable/screen/movable/action_button/button = action.viewers[hud_used]
- action.UpdateButtons()
+ action.build_all_button_icons()
if(reload_screen)
client.screen += button
@@ -195,6 +230,48 @@
// This holds the logic for the palette buttons
hud_used.palette_actions.refresh_actions()
+/**
+ * Show (most) of the another mob's action buttons to this mob
+ *
+ * Used for observers viewing another mob's screen
+ */
+/mob/proc/show_other_mob_action_buttons(mob/take_from)
+ if(!hud_used || !client)
+ return
+
+ for(var/datum/action/action as anything in take_from.actions)
+ if(!action.show_to_observers || !action.owner_has_control)
+ continue
+ action.GiveAction(src)
+ RegisterSignal(take_from, COMSIG_MOB_GRANTED_ACTION, PROC_REF(on_observing_action_granted))
+ RegisterSignal(take_from, COMSIG_MOB_REMOVED_ACTION, PROC_REF(on_observing_action_removed))
+
+/**
+ * Hide another mob's action buttons from this mob
+ *
+ * Used for observers viewing another mob's screen
+ */
+/mob/proc/hide_other_mob_action_buttons(mob/take_from)
+ for(var/datum/action/action as anything in take_from.actions)
+ action.HideFrom(src)
+ UnregisterSignal(take_from, list(COMSIG_MOB_GRANTED_ACTION, COMSIG_MOB_REMOVED_ACTION))
+
+/// Signal proc for [COMSIG_MOB_GRANTED_ACTION] - If we're viewing another mob's action buttons,
+/// we need to update with any newly added buttons granted to the mob.
+/mob/proc/on_observing_action_granted(mob/living/source, datum/action/action)
+ SIGNAL_HANDLER
+
+ if(!action.show_to_observers || !action.owner_has_control)
+ return
+ action.GiveAction(src)
+
+/// Signal proc for [COMSIG_MOB_REMOVED_ACTION] - If we're viewing another mob's action buttons,
+/// we need to update with any removed buttons from the mob.
+/mob/proc/on_observing_action_removed(mob/living/source, datum/action/action)
+ SIGNAL_HANDLER
+
+ action.HideFrom(src)
+
/atom/movable/screen/button_palette
desc = "Drag buttons to move them
Shift-click any button to reset it
Alt-click this to reset all buttons"
icon = 'icons/hud/64x16_actions.dmi'
@@ -220,6 +297,7 @@
/atom/movable/screen/button_palette/proc/set_hud(datum/hud/our_hud)
src.our_hud = our_hud
refresh_owner()
+ disable_landing() // If our hud already has elements, don't force hide us
/atom/movable/screen/button_palette/update_name(updates)
. = ..()
@@ -241,6 +319,21 @@
icon_state = "[ui_name]_palette"
+/atom/movable/screen/button_palette/proc/activate_landing()
+ // Reveal ourselves to the user
+ invisibility = INVISIBILITY_NONE
+
+/atom/movable/screen/button_palette/proc/disable_landing()
+ // If we have no elements in the palette, hide your ugly self please
+ if (!length(our_hud.palette_actions?.actions) && !length(our_hud.floating_actions))
+ invisibility = INVISIBILITY_ABSTRACT
+
+/atom/movable/screen/button_palette/proc/update_state()
+ if (length(our_hud.floating_actions))
+ activate_landing()
+ else
+ disable_landing()
+
/atom/movable/screen/button_palette/MouseEntered(location, control, params)
. = ..()
if(QDELETED(src))
diff --git a/code/_onclick/hud/hud.dm b/code/_onclick/hud/hud.dm
index bda691dcc9d3..95a305f25e9a 100644
--- a/code/_onclick/hud/hud.dm
+++ b/code/_onclick/hud/hud.dm
@@ -134,10 +134,13 @@ GLOBAL_LIST_INIT(available_ui_styles, list(
QDEL_NULL(module_store_icon)
QDEL_LIST(static_inventory)
+ // all already deleted by static inventory clear
inv_slots.Cut()
action_intent = null
zone_select = null
pull_icon = null
+ rest_icon = null
+ hand_slots.Cut()
QDEL_LIST(toggleable_inventory)
QDEL_LIST(hotkeybuttons)
@@ -255,6 +258,7 @@ GLOBAL_LIST_INIT(available_ui_styles, list(
show_hud(hud_version, M)
else if (viewmob.hud_used)
viewmob.hud_used.plane_masters_update()
+ viewmob.show_other_mob_action_buttons(mymob)
screenmob.reload_rendering()
@@ -369,6 +373,7 @@ GLOBAL_LIST_INIT(available_ui_styles, list(
floating_actions += button
button.screen_loc = position
position = SCRN_OBJ_FLOATING
+ toggle_palette.update_state()
button.location = position
@@ -387,6 +392,7 @@ GLOBAL_LIST_INIT(available_ui_styles, list(
position_action(button, button.linked_action.default_button_position)
return
button.screen_loc = get_valid_screen_location(relative_to.screen_loc, world.icon_size, our_client.view_size.getView()) // Asks for a location adjacent to our button that won't overflow the map
+ toggle_palette.update_state()
button.location = relative_to.location
@@ -396,6 +402,7 @@ GLOBAL_LIST_INIT(available_ui_styles, list(
if(SCRN_OBJ_DEFAULT) // Invalid
CRASH("We just tried to hide an action buttion that somehow has the default position as its location, you done fucked up")
if(SCRN_OBJ_FLOATING)
+ toggle_palette.update_state()
floating_actions -= button
if(SCRN_OBJ_IN_LIST)
listed_actions.remove_action(button)
@@ -407,11 +414,13 @@ GLOBAL_LIST_INIT(available_ui_styles, list(
/datum/hud/proc/generate_landings(atom/movable/screen/movable/action_button/button)
listed_actions.generate_landing()
palette_actions.generate_landing()
+ toggle_palette.activate_landing()
/// Clears all currently visible landings
/datum/hud/proc/hide_landings()
listed_actions.clear_landing()
palette_actions.clear_landing()
+ toggle_palette.disable_landing()
// Updates any existing "owned" visuals, ensures they continue to be visible
/datum/hud/proc/update_our_owner()
@@ -429,7 +438,7 @@ GLOBAL_LIST_INIT(available_ui_styles, list(
listed_actions.check_against_view()
palette_actions.check_against_view()
for(var/atom/movable/screen/movable/action_button/floating_button as anything in floating_actions)
- var/list/current_offsets = screen_loc_to_offset(floating_button.screen_loc)
+ var/list/current_offsets = screen_loc_to_offset(floating_button.screen_loc, our_view)
// We set the view arg here, so the output will be properly hemm'd in by our new view
floating_button.screen_loc = offset_to_screen_loc(current_offsets[1], current_offsets[2], view = our_view)
@@ -442,7 +451,6 @@ GLOBAL_LIST_INIT(available_ui_styles, list(
var/atom/movable/screen/movable/action_button/button = action.viewers[src]
if(!button)
action.ShowTo(mymob)
- button = action.viewers[src]
else
position_action(button, button.location)
@@ -655,4 +663,4 @@ GLOBAL_LIST_INIT(available_ui_styles, list(
/datum/action_group/listed/refresh_actions()
. = ..()
- owner?.palette_actions.refresh_actions() // We effect them, so we gotta refresh em
+ owner.palette_actions.refresh_actions() // We effect them, so we gotta refresh em
diff --git a/code/_onclick/hud/new_player.dm b/code/_onclick/hud/new_player.dm
index f1e12bccdd72..533953c2cbd7 100644
--- a/code/_onclick/hud/new_player.dm
+++ b/code/_onclick/hud/new_player.dm
@@ -620,6 +620,8 @@
return
SEND_SOUND(hud.mymob, sound('sound/effects/splat.ogg', volume = 50))
SSticker.start_immediately = TRUE
+ if(SSticker.current_state == GAME_STATE_STARTUP)
+ to_chat(usr, span_admin("The server is still setting up, but the round will be started as soon as possible."))
#undef SHUTTER_MOVEMENT_DURATION
#undef SHUTTER_WAIT_DURATION
diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm
index ace6303c031e..32fc116306dd 100644
--- a/code/_onclick/hud/screen_objects.dm
+++ b/code/_onclick/hud/screen_objects.dm
@@ -218,7 +218,7 @@
var/image/item_overlay = image(holding)
item_overlay.alpha = 92
- if(!holding.mob_can_equip(user, slot_id, disable_warning = TRUE, bypass_equip_delay_self = TRUE))
+ if(!holding.mob_can_equip(user, user, slot_id, disable_warning = TRUE, bypass_equip_delay_self = TRUE))
item_overlay.color = "#FF0000"
else
item_overlay.color = "#00ff00"
@@ -596,7 +596,7 @@
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
/atom/movable/screen/healths/clock
- icon = 'icons/mob/actions.dmi'
+ icon = 'icons/hud/actions.dmi'
icon_state = "bg_clock"
screen_loc = ui_health
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
@@ -608,7 +608,7 @@
/atom/movable/screen/healths/revenant
name = "essence"
- icon = 'icons/mob/actions.dmi'
+ icon = 'icons/hud/actions.dmi'
icon_state = "bg_revenant"
screen_loc = ui_health
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
diff --git a/code/controllers/subsystem/augury.dm b/code/controllers/subsystem/augury.dm
index f7a7c667184e..1de0cf67ca52 100644
--- a/code/controllers/subsystem/augury.dm
+++ b/code/controllers/subsystem/augury.dm
@@ -56,9 +56,8 @@ SUBSYSTEM_DEF(augury)
/datum/action/innate/augury
name = "Auto Follow Debris"
- icon_icon = 'icons/obj/meteor.dmi'
+ button_icon = 'icons/obj/meteor.dmi'
button_icon_state = "flaming"
- background_icon_state = ACTION_BUTTON_DEFAULT_BACKGROUND
/datum/action/innate/augury/Destroy()
if(owner)
@@ -67,19 +66,10 @@ SUBSYSTEM_DEF(augury)
/datum/action/innate/augury/Activate()
SSaugury.watchers += owner
- to_chat(owner, "You are now auto-following debris.")
+ to_chat(owner, span_notice("You are now auto-following debris."))
active = TRUE
- UpdateButtons()
/datum/action/innate/augury/Deactivate()
SSaugury.watchers -= owner
- to_chat(owner, "You are no longer auto-following debris.")
+ to_chat(owner, span_notice("You are no longer auto-following debris."))
active = FALSE
- UpdateButtons()
-
-/datum/action/innate/augury/UpdateButton(atom/movable/screen/movable/action_button/button, status_only = FALSE, force)
- ..()
- if(active)
- button.icon_state = "template_active"
- else
- button.icon_state = "template"
diff --git a/code/controllers/subsystem/vote.dm b/code/controllers/subsystem/vote.dm
index abcc7319aa5a..149d66008b86 100644
--- a/code/controllers/subsystem/vote.dm
+++ b/code/controllers/subsystem/vote.dm
@@ -728,14 +728,21 @@ SUBSYSTEM_DEF(vote)
/datum/action/vote
name = "Vote!"
button_icon_state = "vote"
+ check_flags = NONE
+ required_mobility_flags = NONE
-/datum/action/vote/Trigger()
- if(owner)
- owner.vote()
- remove_from_client()
- Remove(owner)
+/datum/action/vote/Trigger(trigger_flags)
+ . = ..()
+ if(!.)
+ return FALSE
+ if(!owner)
+ return FALSE
+ owner.vote()
+ remove_from_client()
+ Remove(owner)
+ return TRUE
-/datum/action/vote/IsAvailable(silent = FALSE)
+/datum/action/vote/IsAvailable(feedback = TRUE)
return TRUE
/datum/action/vote/proc/remove_from_client()
diff --git a/code/datums/action.dm b/code/datums/action.dm
index a4bd371c1e53..d01dad3f8222 100644
--- a/code/datums/action.dm
+++ b/code/datums/action.dm
@@ -1,9 +1,8 @@
-#define AB_CHECK_RESTRAINED 1
-#define AB_CHECK_STUN 2
-#define AB_CHECK_LYING 4
-#define AB_CHECK_CONSCIOUS 8
-#define AB_CHECK_ALIVE 16
-
+/**
+ * # Action system
+ *
+ * A simple base for an modular behavior attached to atom or datum.
+ */
/datum/action
/// The name of the action
var/name = "Generic Action"
@@ -17,6 +16,8 @@
/// 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
+ /// If False, the owner of this action does not get a hud and cannot activate it on their own
+ var/owner_has_control = TRUE
/// 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
@@ -25,21 +26,36 @@
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()
+ /// If TRUE, this action button will be shown to observers / other mobs who view from this action's owner's eyes.
+ /// Used in [/mob/proc/show_other_mob_action_buttons]
+ var/show_to_observers = TRUE
/// 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'
+ var/background_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'
+ var/button_icon = 'icons/hud/actions.dmi'
/// This is the icon state for the icon that appears on the button
var/button_icon_state = "default"
- var/button_overlay_state
+
+ /// This is the file for any FOREGROUND overlay icons on the button (such as borders)
+ var/overlay_icon = 'icons/mob/actions/backgrounds.dmi'
+ /// This is the icon state for any FOREGROUND overlay icons on the button (such as borders)
+ var/overlay_icon_state
+
+ /// full key we are bound to
+ var/full_key
+
+ /// Toggles whether this action is usable or not
+ var/action_disabled = FALSE
+ /// Can this action be shared with our rider?
+ var/can_be_shared = TRUE
/datum/action/New(Target)
link_to(Target)
@@ -77,12 +93,16 @@
owner = grant_to
if(!isnull(previous_owner))
Remove(previous_owner)
+ SEND_SIGNAL(src, COMSIG_ACTION_GRANTED, owner)
+ SEND_SIGNAL(owner, COMSIG_MOB_GRANTED_ACTION, src)
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))
+ if(check_flags & AB_CHECK_LYING)
+ RegisterSignal(owner, COMSIG_LIVING_RESTING, PROC_REF(update_status_on_signal))
GiveAction(grant_to)
@@ -102,7 +122,8 @@
// Clean up our check_flag signals
UnregisterSignal(owner, list(
- COMSIG_MOB_STATCHANGE
+ COMSIG_LIVING_RESTING,
+ COMSIG_MOB_STATCHANGE,
))
if(target == owner)
@@ -112,8 +133,8 @@
/// Actually triggers the effects of the action.
/// Called when the on-screen button is clicked, for example.
-/datum/action/proc/Trigger()
- if(!IsAvailable())
+/datum/action/proc/Trigger(trigger_flags)
+ if(!(trigger_flags & TRIGGER_FORCE_AVAILABLE) && !IsAvailable(feedback = TRUE))
return FALSE
if(SEND_SIGNAL(src, COMSIG_ACTION_TRIGGER, target) & COMPONENT_ACTION_BLOCK_TRIGGER)
return FALSE
@@ -124,92 +145,180 @@
/**
* 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
+ * * feedback - If true this is being called to check if we have any messages to show to the owner
*/
-/datum/action/proc/IsAvailable(silent = FALSE)
+/datum/action/proc/IsAvailable(feedback = FALSE)
if(!owner)
return FALSE
+ if(action_disabled)
+ return FALSE
var/mob/living/L = owner
if(istype(L) && !CHECK_ALL_MOBILITY(L, required_mobility_flags))
return FALSE
- if(check_flags & AB_CHECK_RESTRAINED)
- if(owner.restrained())
- return FALSE
+ if(check_flags & AB_CHECK_RESTRAINED && owner.restrained())
+ if (feedback)
+ owner.balloon_alert(owner, "restrained!")
+ return FALSE
if(check_flags & AB_CHECK_STUN)
if(istype(L) && !CHECK_MOBILITY(L, MOBILITY_USE))
return FALSE
if(check_flags & AB_CHECK_LYING)
if(istype(L) && !CHECK_MOBILITY(L, MOBILITY_STAND))
- if (!silent)
+ if (feedback)
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)
- return FALSE
+ if(check_flags & AB_CHECK_CONSCIOUS && owner.stat != CONSCIOUS)
+ if (feedback)
+ switch(owner.stat)
+ if(SOFT_CRIT)
+ owner.balloon_alert(owner, "soft crit!")
+ if(UNCONSCIOUS)
+ owner.balloon_alert(owner, "unconscious!")
+ if(DEAD)
+ owner.balloon_alert(owner, "dead!")
+ return FALSE
return TRUE
-/datum/action/proc/UpdateButtons(status_only, force)
- for(var/datum/hud/hud in viewers)
- var/atom/movable/screen/movable/button = viewers[hud]
- UpdateButton(button, status_only, force)
+/// Builds / updates all buttons we have shared or given out
+/datum/action/proc/build_all_button_icons(update_flags = ALL, force)
+ for(var/datum/hud/hud as anything in viewers)
+ build_button_icon(viewers[hud], update_flags, force)
-/datum/action/proc/UpdateButton(atom/movable/screen/movable/action_button/button, status_only = FALSE, force = FALSE)
+/**
+ * Builds the icon of the button.
+ *
+ * Concept:
+ * - Underlay (Background icon)
+ * - Icon (button icon)
+ * - Maptext
+ * - Overlay (Background border)
+ *
+ * button - which button we are modifying the icon of
+ * force - whether we're forcing a full update
+ */
+/datum/action/proc/build_button_icon(atom/movable/screen/movable/action_button/button, update_flags = ALL, force = FALSE)
if(!button)
return
- if(!status_only)
- button.name = name
+
+ if(update_flags & UPDATE_BUTTON_NAME)
+ update_button_name(button, force)
+
+ if(update_flags & UPDATE_BUTTON_BACKGROUND)
+ apply_button_background(button, force)
+
+ if(update_flags & UPDATE_BUTTON_ICON)
+ apply_button_icon(button, force)
+
+ if(update_flags & UPDATE_BUTTON_OVERLAY)
+ apply_button_overlay(button, force)
+
+ if(update_flags & UPDATE_BUTTON_STATUS)
+ update_button_status(button, force)
+
+/**
+ * Updates the name and description of the button to match our action name and discription.
+ *
+ * current_button - what button are we editing?
+ * force - whether an update is forced regardless of existing status
+ */
+/datum/action/proc/update_button_name(atom/movable/screen/movable/action_button/button, force = FALSE)
+ button.name = name
+ if(desc)
button.desc = desc
- if(owner?.hud_used && background_icon_state == ACTION_BUTTON_DEFAULT_BACKGROUND)
- var/list/settings = owner.hud_used.get_action_buttons_icons()
- if(button.icon != settings["bg_icon"])
- button.icon = settings["bg_icon"]
- if(button.icon_state != settings["bg_state"])
- button.icon_state = settings["bg_state"]
- else
- if(button.icon != button_icon)
- button.icon = button_icon
- if(button.icon_state != background_icon_state)
- button.icon_state = background_icon_state
- ApplyIcon(button, force)
+/**
+ * Creates the background underlay for the button
+ *
+ * current_button - what button are we editing?
+ * force - whether an update is forced regardless of existing status
+ */
+/datum/action/proc/apply_button_background(atom/movable/screen/movable/action_button/current_button, force = FALSE)
+ if(!background_icon || !background_icon_state || (current_button.active_underlay_icon_state == background_icon_state && !force))
+ return
- if(button_overlay_state)
- button.cut_overlay(button.button_overlay)
- button.button_overlay = mutable_appearance(icon = 'icons/mob/actions.dmi', icon_state = button_overlay_state)
- button.add_overlay(button.button_overlay)
+ // What icons we use for our background
+ var/list/icon_settings = list(
+ // The icon file
+ "bg_icon" = background_icon,
+ // The icon state, if is_action_active() returns FALSE
+ "bg_state" = background_icon_state,
+ // The icon state, if is_action_active() returns TRUE
+ "bg_state_active" = background_icon_state,
+ )
- if(!IsAvailable(TRUE))
- button.color = transparent_when_unavailable ? rgb(128,0,0,128) : rgb(128,0,0)
- else
- button.color = rgb(255,255,255,255)
- return TRUE
+ // If background_icon_state is ACTION_BUTTON_DEFAULT_BACKGROUND instead use our hud's action button scheme
+ if(background_icon_state == ACTION_BUTTON_DEFAULT_BACKGROUND && owner?.hud_used)
+ icon_settings = owner.hud_used.get_action_buttons_icons()
+
+ // Determine which icon to use
+ var/used_icon_key = is_action_active(current_button) ? "bg_state_active" : "bg_state"
-/datum/action/proc/ApplyIcon(atom/movable/screen/movable/action_button/current_button, force = FALSE)
- if(icon_icon && button_icon_state && ((current_button.button_icon_state != button_icon_state) || force))
- current_button.cut_overlays()
- current_button.add_overlay(mutable_appearance(icon_icon, button_icon_state))
- current_button.button_icon_state = button_icon_state
+ // Make the underlay
+ current_button.underlays.Cut()
+ current_button.underlays += image(icon = icon_settings["bg_icon"], icon_state = icon_settings[used_icon_key])
+ current_button.active_underlay_icon_state = icon_settings[used_icon_key]
+
+/**
+ * Applies our button icon and icon state to the button
+ *
+ * current_button - what button are we editing?
+ * force - whether an update is forced regardless of existing status
+ */
+/datum/action/proc/apply_button_icon(atom/movable/screen/movable/action_button/current_button, force = FALSE)
+ if(!button_icon || !button_icon_state || (current_button.icon_state == button_icon_state && !force))
+ return
+
+ current_button.icon = button_icon
+ current_button.icon_state = button_icon_state
+
+/**
+ * Applies any overlays to our button
+ *
+ * current_button - what button are we editing?
+ * force - whether an update is forced regardless of existing status
+ */
+/datum/action/proc/apply_button_overlay(atom/movable/screen/movable/action_button/current_button, force = FALSE)
+
+ SEND_SIGNAL(src, COMSIG_ACTION_OVERLAY_APPLY, current_button, force)
+
+ if(!overlay_icon || !overlay_icon_state || (current_button.active_overlay_icon_state == overlay_icon_state && !force))
+ return
+
+ current_button.cut_overlay(current_button.button_overlay)
+ current_button.button_overlay = mutable_appearance(icon = overlay_icon, icon_state = overlay_icon_state)
+ current_button.add_overlay(current_button.button_overlay)
+ current_button.active_overlay_icon_state = overlay_icon_state
+
+/**
+ * Any other miscellaneous "status" updates within the action button is handled here,
+ * such as redding out when unavailable or modifying maptext.
+ *
+ * current_button - what button are we editing?
+ * force - whether an update is forced regardless of existing status
+ */
+/datum/action/proc/update_button_status(atom/movable/screen/movable/action_button/current_button, force = FALSE)
+ current_button.update_keybind_maptext(full_key)
+ if(IsAvailable())
+ current_button.color = rgb(255,255,255,255)
+ else
+ current_button.color = transparent_when_unavailable ? rgb(128,0,0,128) : rgb(128,0,0)
/datum/action/ghost
- icon_icon = 'icons/mob/mob.dmi'
+ button_icon = 'icons/mob/mob.dmi'
button_icon_state = "ghost"
name = "Ghostize"
desc = "Turn into a ghost and freely come back to your body."
-/datum/action/ghost/Trigger()
+/datum/action/ghost/Trigger(trigger_flags)
if(!..())
return FALSE
var/mob/M = target
M.ghostize(can_reenter_corpse = TRUE, voluntary = TRUE)
+ return TRUE
/datum/action/proc/OnUpdatedIcon()
SIGNAL_HANDLER
- UpdateButtons(force = TRUE)
+ build_all_button_icons(force = TRUE)
/// Gives our action to the passed viewer.
/// Puts our action in their actions list and shows them the button.
@@ -227,7 +336,7 @@
if(!our_hud || viewers[our_hud]) // There's no point in this if you have no hud in the first place
return
- var/atom/movable/screen/movable/action_button/button = CreateButton()
+ var/atom/movable/screen/movable/action_button/button = create_button()
SetId(button, viewer)
button.our_hud = our_hud
@@ -246,12 +355,10 @@
if(button)
qdel(button)
-/datum/action/proc/CreateButton()
+/datum/action/proc/create_button()
var/atom/movable/screen/movable/action_button/button = new()
button.linked_action = src
- button.actiontooltipstyle = buttontooltipstyle
- if(desc)
- button.desc = desc
+ build_button_icon(button, ALL, TRUE)
return button
/datum/action/proc/SetId(atom/movable/screen/movable/action_button/our_button, mob/owner)
@@ -271,81 +378,78 @@
our_button.id = bitflag
return
+/// Updates our buttons if our target's icon was updated
+/datum/action/proc/on_target_icon_update(datum/source, updates, updated)
+ SIGNAL_HANDLER
+
+ var/update_flag = NONE
+ var/forced = FALSE
+ if(updates & UPDATE_ICON_STATE)
+ update_flag |= UPDATE_BUTTON_ICON
+ forced = TRUE
+ if(updates & UPDATE_OVERLAYS)
+ update_flag |= UPDATE_BUTTON_OVERLAY
+ forced = TRUE
+ if(updates & (UPDATE_NAME|UPDATE_DESC))
+ update_flag |= UPDATE_BUTTON_NAME
+ // Status is not relevant, and background is not relevant. Neither will change
+
+ // Force the update if an icon state or overlay change was done
+ build_all_button_icons(update_flag, forced)
+
/// A general use signal proc that reacts to an event and updates JUST our button's status
/datum/action/proc/update_status_on_signal(datum/source, new_stat, old_stat)
SIGNAL_HANDLER
- UpdateButton(status_only = TRUE)
-//Presets for item actions
-/datum/action/item_action
- check_flags = AB_CHECK_RESTRAINED|AB_CHECK_STUN|AB_CHECK_LYING|AB_CHECK_CONSCIOUS
- button_icon_state = null
- // If you want to override the normal icon being the item
- // then change this to an icon state
+ build_all_button_icons(UPDATE_BUTTON_STATUS)
-/datum/action/item_action/New(Target)
- ..()
- var/obj/item/I = target
- LAZYINITLIST(I.actions)
- I.actions += src
-
-/datum/action/item_action/Destroy()
- var/obj/item/I = target
- I.actions -= src
- UNSETEMPTY(I.actions)
- return ..()
+/// Signal proc for COMSIG_MIND_TRANSFERRED - for minds, transfers our action to our new mob on mind transfer
+/datum/action/proc/on_target_mind_swapped(datum/mind/source, mob/old_current)
+ SIGNAL_HANDLER
-/datum/action/item_action/Trigger(trigger_flags)
- . = ..()
- if(!.)
- return FALSE
- if(target)
- var/obj/item/I = target
- I.ui_action_click(owner, src)
- return TRUE
+ // Grant() calls Remove() from the existing owner so we're covered on that
+ Grant(source.current)
-/datum/action/item_action/ApplyIcon(atom/movable/screen/movable/action_button/current_button, force)
- var/obj/item/item_target = target
- if(button_icon && button_icon_state)
- // If set, use the custom icon that we set instead
- // of the item appearence
- ..()
- else if((target && current_button.appearance_cache != item_target.appearance) || force) //replace with /ref comparison if this is not valid.
- var/old_layer = item_target.layer
- var/old_plane = item_target.plane
- item_target.layer = FLOAT_LAYER //AAAH
- item_target.plane = FLOAT_PLANE //^ what that guy said
- current_button.filters = null
- current_button.cut_overlays()
- current_button.add_overlay(item_target)
- item_target.layer = old_layer
- item_target.plane = old_plane
- current_button.appearance_cache = item_target.appearance
+/// Checks if our action is actively selected. Used for selecting icons primarily.
+/datum/action/proc/is_action_active(atom/movable/screen/movable/action_button/current_button)
+ return FALSE
+
+/datum/action/proc/keydown(mob/source, key, client/client, full_key)
+ SIGNAL_HANDLER
+ if(isnull(full_key) || full_key != src.full_key)
+ return
+ if(istype(source))
+ if(!source.CheckActionCooldown())
+ return
+ else
+ source.DelayNextAction(1)
+ INVOKE_ASYNC(src, PROC_REF(Trigger))
/datum/action/item_action/toggle_light
name = "Toggle Light"
-/datum/action/item_action/toggle_light/pda/Trigger(trigger_flags)
- if(istype(target, /obj/item/pda))
- var/obj/item/pda/P = target
- return P.toggle_light(owner)
+/datum/action/item_action/toggle_light/pda/do_effect(trigger_flags)
+ var/obj/item/pda/P = target
+ if(!istype(P))
+ return FALSE
+ return P.toggle_light(owner)
/datum/action/item_action/toggle_hood
name = "Toggle Hood"
/datum/action/item_action/toggle_firemode
- icon_icon = 'icons/mob/actions/actions_items.dmi'
+ button_icon = 'icons/mob/actions/actions_items.dmi'
button_icon_state = "fireselect_no"
name = "Toggle Firemode"
/datum/action/item_action/rcl_col
name = "Change Cable Color"
- icon_icon = 'icons/mob/actions/actions_items.dmi'
+ button_icon = 'icons/mob/actions/actions_items.dmi'
button_icon_state = "rcl_rainbow"
/datum/action/item_action/rcl_gui
name = "Toggle Fast Wiring Gui"
- icon_icon = 'icons/mob/actions/actions_items.dmi'
+ button_icon = 'icons/mob/actions/actions_items.dmi'
button_icon_state = "rcl_gui"
/datum/action/item_action/startchainsaw
@@ -369,16 +473,11 @@
/datum/action/item_action/set_internals
name = "Set Internals"
default_button_position = SCRN_OBJ_INSERT_FIRST
- button_overlay_state = "ab_goldborder"
+ overlay_icon_state = "ab_goldborder"
-/datum/action/item_action/set_internals/UpdateButton(atom/movable/screen/movable/action_button/button, status_only = FALSE, force)
- if(!..()) // no button available
- return
- if(!iscarbon(owner))
- return
- var/mob/living/carbon/C = owner
- if(target == C.internal)
- button.icon_state = "template_active"
+/datum/action/item_action/set_internals/is_action_active(atom/movable/screen/movable/action_button/current_button)
+ var/mob/living/carbon/carbon_owner = owner
+ return istype(carbon_owner) && target == carbon_owner.internal
/datum/action/item_action/pick_color
name = "Choose A Color"
@@ -395,67 +494,69 @@
/datum/action/item_action/toggle_welding_screen
name = "Toggle Welding Screen"
-/datum/action/item_action/toggle_welding_screen/Trigger()
+/datum/action/item_action/toggle_welding_screen/do_effect(trigger_flags)
var/obj/item/clothing/head/hardhat/weldhat/H = target
- if(istype(H))
- H.toggle_welding_screen(owner)
+ if(!istype(H))
+ return FALSE
+ H.toggle_welding_screen(owner)
+ return TRUE
/datum/action/item_action/toggle_welding_screen/plasmaman
-/datum/action/item_action/toggle_welding_screen/plasmaman/Trigger()
+/datum/action/item_action/toggle_welding_screen/plasmaman/do_effect(trigger_flags)
var/obj/item/clothing/head/helmet/space/plasmaman/H = target
- if(istype(H))
- H.toggle_welding_screen(owner)
+ if(!istype(H))
+ return FALSE
+ H.toggle_welding_screen(owner)
+ return TRUE
/datum/action/item_action/toggle_headphones
name = "Toggle Headphones"
desc = "UNTZ UNTZ UNTZ"
-/datum/action/item_action/toggle_headphones/Trigger()
+/datum/action/item_action/toggle_headphones/do_effect(trigger_flags)
var/obj/item/clothing/ears/headphones/H = target
- if(istype(H))
- H.toggle(owner)
+ if(!istype(H))
+ return FALSE
+ H.toggle(owner)
+ return TRUE
/datum/action/item_action/toggle_unfriendly_fire
name = "Toggle Friendly Fire \[ON\]"
desc = "Toggles if the club's blasts cause friendly fire."
- icon_icon = 'icons/mob/actions/actions_items.dmi'
+ button_icon = 'icons/mob/actions/actions_items.dmi'
button_icon_state = "vortex_ff_on"
-/datum/action/item_action/toggle_unfriendly_fire/Trigger()
- if(..())
- UpdateButtons()
+/datum/action/item_action/toggle_unfriendly_fire/update_button_name(atom/movable/screen/movable/action_button/button, force)
+ var/obj/item/hierophant_club/club = target
+ name = "Toggle Friendly Fire [club.friendly_fire_check ? "\[OFF\]" : "\[ON\]"]"
+ return ..()
-/datum/action/item_action/toggle_unfriendly_fire/UpdateButton(atom/movable/screen/movable/action_button/button, status_only = FALSE, force)
- if(istype(target, /obj/item/hierophant_club))
- var/obj/item/hierophant_club/H = target
- if(H.friendly_fire_check)
- button_icon_state = "vortex_ff_off"
- name = "Toggle Friendly Fire \[OFF\]"
- else
- button_icon_state = "vortex_ff_on"
- name = "Toggle Friendly Fire \[ON\]"
- ..()
+/datum/action/item_action/toggle_unfriendly_fire/apply_button_icon(atom/movable/screen/movable/action_button/current_button, force)
+ var/obj/item/hierophant_club/club = target
+ button_icon_state = club.friendly_fire_check ? "vortex_ff_off" : "vortex_ff_on"
+ return ..()
/datum/action/item_action/vortex_recall
name = "Vortex Recall"
desc = "Recall yourself, and anyone nearby, to an attuned hierophant beacon at any time.
If the beacon is still attached, will detach it."
- icon_icon = 'icons/mob/actions/actions_items.dmi'
+ button_icon = 'icons/mob/actions/actions_items.dmi'
button_icon_state = "vortex_recall"
-/datum/action/item_action/vortex_recall/IsAvailable(silent = FALSE)
- if(istype(target, /obj/item/hierophant_club))
- var/obj/item/hierophant_club/H = target
- if(H.teleporting)
- return FALSE
+/datum/action/item_action/vortex_recall/IsAvailable(feedback = TRUE)
+ if(!istype(target, /obj/item/hierophant_club))
+ return FALSE
+ var/obj/item/hierophant_club/teleport_stick = target
+ if(teleport_stick.teleporting)
+ return FALSE
return ..()
/datum/action/item_action/clock
- icon_icon = 'icons/mob/actions/actions_clockcult.dmi'
+ button_icon = 'icons/mob/actions/actions_clockcult.dmi'
background_icon_state = "bg_clock"
buttontooltipstyle = "clockcult"
-/datum/action/item_action/clock/IsAvailable(silent = FALSE)
+/datum/action/item_action/clock/IsAvailable(feedback = TRUE)
if(!is_servant_of_ratvar(owner))
return FALSE
return ..()
@@ -464,13 +565,14 @@
name = "Create Judicial Marker"
desc = "Allows you to create a stunning Judicial Marker at any location in view. Click again to disable."
-/datum/action/item_action/clock/toggle_visor/IsAvailable(silent = FALSE)
+/datum/action/item_action/clock/toggle_visor/IsAvailable(feedback = TRUE)
if(!is_servant_of_ratvar(owner))
return FALSE
- if(istype(target, /obj/item/clothing/glasses/judicial_visor))
- var/obj/item/clothing/glasses/judicial_visor/V = target
- if(V.recharging)
- return FALSE
+ if(!istype(target, /obj/item/clothing/glasses/judicial_visor))
+ return FALSE
+ var/obj/item/clothing/glasses/judicial_visor/goggles = target
+ if(goggles.recharging)
+ return FALSE
return ..()
/datum/action/item_action/clock/hierophant
@@ -507,16 +609,13 @@
/datum/action/item_action/nano_picket_sign
name = "Retext Nano Picket Sign"
- var/obj/item/picket_sign/S
-
-/datum/action/item_action/nano_picket_sign/New(Target)
- ..()
- if(istype(Target, /obj/item/picket_sign))
- S = Target
-/datum/action/item_action/nano_picket_sign/Trigger()
- if(istype(S))
- S.retext(owner)
+/datum/action/item_action/nano_picket_sign/do_effect(trigger_flags)
+ if(!istype(target, /obj/item/picket_sign))
+ return FALSE
+ var/obj/item/picket_sign/sign = target
+ sign.retext(owner)
+ return TRUE
/datum/action/item_action/adjust
@@ -544,7 +643,7 @@
/datum/action/item_action/jetpack_stabilization
name = "Toggle Jetpack Stabilization"
-/datum/action/item_action/jetpack_stabilization/IsAvailable(silent = FALSE)
+/datum/action/item_action/jetpack_stabilization/IsAvailable(feedback = TRUE)
var/obj/item/tank/jetpack/J = target
if(!istype(J) || !J.on)
return FALSE
@@ -567,19 +666,20 @@
/datum/action/item_action/toggle_research_scanner
name = "Toggle Research Scanner"
- icon_icon = 'icons/mob/actions/actions_items.dmi'
+ button_icon = 'icons/mob/actions/actions_items.dmi'
button_icon_state = "scan_mode"
var/active = FALSE
-/datum/action/item_action/toggle_research_scanner/Trigger()
- if(IsAvailable())
- active = !active
- if(active)
- owner.research_scanner++
- else
- owner.research_scanner--
- to_chat(owner, "[target] research scanner has been [active ? "activated" : "deactivated"].")
- return TRUE
+/datum/action/item_action/toggle_research_scanner/do_effect(trigger_flags)
+ if(!IsAvailable(feedback = TRUE))
+ return FALSE
+ active = !active
+ if(active)
+ owner.research_scanner++
+ else
+ owner.research_scanner--
+ to_chat(owner, span_notice("[target] research scanner has been [active ? "activated" : "deactivated"]."))
+ return TRUE
/datum/action/item_action/toggle_research_scanner/Remove(mob/M)
if(owner && active)
@@ -591,18 +691,18 @@
name = "Use Instrument"
desc = "Use the instrument specified"
-/datum/action/item_action/instrument/Trigger()
- if(istype(target, /obj/item/instrument))
- var/obj/item/instrument/I = target
- I.interact(usr)
- return
- return ..()
+/datum/action/item_action/instrument/do_effect(trigger_flags)
+ if(!istype(target, /obj/item/instrument))
+ return FALSE
+ var/obj/item/instrument/instrument = target
+ instrument.interact(usr)
+ return TRUE
/datum/action/item_action/organ_action
name = "Organ Action"
check_flags = AB_CHECK_CONSCIOUS
-/datum/action/item_action/organ_action/IsAvailable(silent = FALSE)
+/datum/action/item_action/organ_action/IsAvailable(feedback)
var/obj/item/organ/attached_organ = target
if(!attached_organ.owner)
return FALSE
@@ -628,30 +728,41 @@
/datum/action/item_action/cult_dagger
name = "Draw Blood Rune"
desc = "Use the ritual dagger to create a powerful blood rune"
- icon_icon = 'icons/mob/actions/actions_cult.dmi'
+ button_icon = 'icons/mob/actions/actions_cult.dmi'
button_icon_state = "draw"
buttontooltipstyle = "cult"
background_icon_state = "bg_demon"
default_button_position = "6:157,4:-2"
-/datum/action/item_action/cult_dagger/Grant(mob/M)
- if(!iscultist(M))
- Remove(owner)
+/datum/action/item_action/cult_dagger/Grant(mob/grant_to)
+ if(!grant_to?.mind.has_antag_datum(grant_to, /datum/antagonist/cult))
return
+
return ..()
-/datum/action/item_action/cult_dagger/Trigger()
- for(var/obj/item/H in owner.held_items) //In case we were already holding another dagger
- if(istype(H, /obj/item/melee/cultblade/dagger))
- H.attack_self(owner)
- return
- var/obj/item/I = target
- if(owner.can_equip(I, ITEM_SLOT_HANDS))
- owner.temporarilyRemoveItemFromInventory(I)
- owner.put_in_hands(I)
- I.attack_self(owner)
+/datum/action/item_action/cult_dagger/do_effect(trigger_flags)
+ if(!isliving(owner))
+ to_chat(owner, span_warning("You lack the necessary living force for this action."))
+ return FALSE
+
+ var/obj/item/target_item = target
+ var/mob/living/living_owner = owner
+ if(target in owner.held_items)
+ target_item.attack_self(owner)
+ return TRUE
+
+ if(owner.can_equip(target_item, ITEM_SLOT_HANDS))
+ owner.temporarilyRemoveItemFromInventory(target_item)
+ owner.put_in_hands(target_item)
+ target_item.attack_self(owner)
+ return TRUE
+
+ if (living_owner.get_num_arms())
+ to_chat(living_owner, span_warning("You don't have any usable hands!"))
else
- to_chat(owner, "Your hands are full!")
+ to_chat(living_owner, span_warning("Your hands are full!"))
+ return FALSE
+
//MGS Box
/datum/action/item_action/agent_box
@@ -659,85 +770,88 @@
desc = "Find inner peace, here, in the box."
check_flags = AB_CHECK_RESTRAINED|AB_CHECK_STUN|AB_CHECK_CONSCIOUS
background_icon_state = "bg_agent"
- icon_icon = 'icons/mob/actions/actions_items.dmi'
+ button_icon = 'icons/mob/actions/actions_items.dmi'
button_icon_state = "deploy_box"
- var/cooldown = 0
var/boxtype = /obj/structure/closet/cardboard/agent
+ COOLDOWN_DECLARE(box_cooldown)
//Handles open and closing the box
-/datum/action/item_action/agent_box/Trigger()
+/datum/action/item_action/agent_box/do_effect(trigger_flags)
. = ..()
if(!.)
return FALSE
if(istype(owner.loc, /obj/structure/closet/cardboard/agent))
var/obj/structure/closet/cardboard/agent/box = owner.loc
- owner.playsound_local(box, 'sound/misc/box_deploy.ogg', 50, TRUE)
- box.open()
- return
+ if(box.open())
+ owner.playsound_local(box, 'sound/misc/box_deploy.ogg', 50, TRUE)
+ return FALSE
//Box closing from here on out.
if(!isturf(owner.loc)) //Don't let the player use this to escape mechs/welded closets.
- to_chat(owner, "You need more space to activate this implant.")
- return
- if(cooldown < world.time - 100)
- var/box = new boxtype(owner.drop_location())
- owner.forceMove(box)
- cooldown = world.time
- owner.playsound_local(box, 'sound/misc/box_deploy.ogg', 50, TRUE)
+ to_chat(owner, span_warning("You need more space to activate this implant."))
+ return FALSE
+ if(!COOLDOWN_FINISHED(src, box_cooldown))
+ return FALSE
+ COOLDOWN_START(src, box_cooldown, 10 SECONDS)
+ var/box = new boxtype(owner.drop_location())
+ owner.forceMove(box)
+ owner.playsound_local(box, 'sound/misc/box_deploy.ogg', 50, TRUE)
/datum/action/item_action/removeAPCs
name = "Relinquish APC"
desc = "Let go of an APC, relinquish control back to the station."
- icon_icon = 'icons/obj/implants.dmi'
+ button_icon = 'icons/obj/implants.dmi'
button_icon_state = "hijackx"
-/datum/action/item_action/removeAPCs/Trigger()
+/datum/action/item_action/removeAPCs/do_effect(trigger_flags)
var/list/areas = list()
for (var/area/a in owner.siliconaccessareas)
areas[a.name] = a
var/removeAPC = input("Select an APC to remove:","Remove APC Control",1) as null|anything in areas
if (!removeAPC)
- return
+ return FALSE
var/area/area = areas[removeAPC]
var/obj/machinery/power/apc/apc = area.get_apc()
if (!apc || !(area in owner.siliconaccessareas))
- return
+ return FALSE
apc.hijacker = null
apc.update_icon()
apc.set_hijacked_lighting()
owner.toggleSiliconAccessArea(area)
+ return TRUE
/datum/action/item_action/accessAPCs
name = "Access APC Interface"
desc = "Open the APC's interface."
- icon_icon = 'icons/obj/implants.dmi'
+ button_icon = 'icons/obj/implants.dmi'
button_icon_state = "hijacky"
-/datum/action/item_action/accessAPCs/Trigger()
+/datum/action/item_action/accessAPCs/do_effect(trigger_flags)
var/list/areas = list()
for (var/area/a in owner.siliconaccessareas)
areas[a.name] = a
var/accessAPC = input("Select an APC to access:","Access APC Interface",1) as null|anything in areas
if (!accessAPC)
- return
+ return FALSE
var/area/area = areas[accessAPC]
var/obj/machinery/power/apc/apc = area.get_apc()
if (!apc || !(area in owner.siliconaccessareas))
- return
+ return FALSE
apc.ui_interact(owner)
+ return TRUE
/datum/action/item_action/stealthmodetoggle
name = "Toggle Stealth Mode"
desc = "Toggles the stealth mode on the hijack implant."
- icon_icon = 'icons/obj/implants.dmi'
+ button_icon = 'icons/obj/implants.dmi'
button_icon_state = "hijackz"
-/datum/action/item_action/stealthmodetoggle/Trigger()
+/datum/action/item_action/stealthmodetoggle/do_effect(trigger_flags)
var/obj/item/implant/hijack/H = target
if (!istype(H))
- return
+ return FALSE
if (H.stealthcooldown > world.time)
- to_chat(owner,"The hijack implant's stealth mode toggle is still rebooting!")
- return
+ to_chat(owner, span_warning("The hijack implant's stealth mode toggle is still rebooting!"))
+ return FALSE
H.stealthmode = !H.stealthmode
for (var/area/area in H.imp_in.siliconaccessareas)
var/obj/machinery/power/apc/apc = area.get_apc()
@@ -746,7 +860,8 @@
apc.update_icon()
H.stealthcooldown = world.time + 15 SECONDS
H.toggle_eyes()
- to_chat(owner,"You toggle the hijack implant's stealthmode [H.stealthmode ? "on" : "off"].")
+ to_chat(owner, span_notice("You toggle the hijack implant's stealthmode [H.stealthmode ? "on" : "off"]."))
+ return TRUE
/datum/action/item_action/flash
name = "Flash"
@@ -762,7 +877,7 @@
S.action = src
name = S.name
desc = S.desc
- icon_icon = S.action_icon
+ button_icon = S.action_icon
button_icon_state = S.action_icon_state
background_icon_state = S.action_background_icon_state
@@ -771,193 +886,57 @@
S.action = null
return ..()
-/datum/action/spell_action/Trigger()
- if(!..())
+/datum/action/spell_action/Trigger(trigger_flags)
+ . = ..()
+ if(!.)
return FALSE
- if(target)
- var/obj/effect/proc_holder/S = target
- S.Trigger(usr)
- return TRUE
+ if(!target)
+ return FALSE
+ var/obj/effect/proc_holder/S = target
+ return S.Trigger(usr)
-/datum/action/spell_action/IsAvailable(silent = FALSE)
+/datum/action/spell_action/IsAvailable(feedback = TRUE)
if(!target)
return FALSE
return TRUE
/datum/action/spell_action/spell
-/datum/action/spell_action/spell/IsAvailable(silent = FALSE)
+/datum/action/spell_action/spell/IsAvailable(feedback = TRUE)
if(!target)
return FALSE
var/obj/effect/proc_holder/spell/S = target
if(owner)
- return S.can_cast(owner, FALSE, silent)
+ return S.can_cast(owner, FALSE, feedback)
return FALSE
/datum/action/spell_action/alien
-/datum/action/spell_action/alien/IsAvailable(silent = FALSE)
+/datum/action/spell_action/alien/IsAvailable(feedback = TRUE)
if(!target)
return FALSE
var/obj/effect/proc_holder/alien/ab = target
if(owner)
- return ab.cost_check(ab.check_turf,owner,silent)
+ return ab.cost_check(ab.check_turf,owner, feedback)
return FALSE
-
-
-//Preset for general and toggled actions
-/datum/action/innate
- check_flags = NONE
- required_mobility_flags = NONE
- var/active = 0
-
-/datum/action/innate/Trigger()
- if(!..())
- return FALSE
- if(!active)
- Activate()
- else
- Deactivate()
- return TRUE
-
-/datum/action/innate/proc/Activate()
- return
-
-/datum/action/innate/proc/Deactivate()
- return
-
-//Preset for an action with a cooldown
-
-/datum/action/cooldown
- check_flags = 0
- transparent_when_unavailable = FALSE
- // The default cooldown applied when StartCooldown() is called
- var/cooldown_time = 0
- // The actual next time this ability can be used
- var/next_use_time = 0
- // Whether or not you want the cooldown for the ability to display in text form
- var/text_cooldown = TRUE
- // Setting for intercepting clicks before activating the ability
- var/click_to_activate = FALSE
- // Shares cooldowns with other cooldown abilities of the same value, not active if null
- var/shared_cooldown
-
-/datum/action/cooldown/CreateButton()
- var/atom/movable/screen/movable/action_button/button = ..()
- button.maptext = ""
- button.maptext_x = 8
- button.maptext_y = 0
- button.maptext_width = 24
- button.maptext_height = 12
- return button
-
-/datum/action/cooldown/IsAvailable()
- return ..() && (next_use_time <= world.time)
-
-/// Starts a cooldown time to be shared with similar abilities, will use default cooldown time if an override is not specified
-/datum/action/cooldown/proc/StartCooldown(override_cooldown_time)
- if(shared_cooldown)
- for(var/datum/action/cooldown/shared_ability in owner.actions - src)
- if(shared_cooldown == shared_ability.shared_cooldown)
- if(isnum(override_cooldown_time))
- shared_ability.StartCooldownSelf(override_cooldown_time)
- else
- shared_ability.StartCooldownSelf(cooldown_time)
- StartCooldownSelf(override_cooldown_time)
-
-/// Starts a cooldown time for this ability only, will use default cooldown time if an override is not specified
-/datum/action/cooldown/proc/StartCooldownSelf(override_cooldown_time)
- if(isnum(override_cooldown_time))
- next_use_time = world.time + override_cooldown_time
- else
- next_use_time = world.time + cooldown_time
- UpdateButtons()
- START_PROCESSING(SSfastprocess, src)
-
-/datum/action/cooldown/Trigger(trigger_flags, atom/target)
- . = ..()
- if(!.)
- return
- if(!owner)
- return FALSE
- if(click_to_activate)
- if(target)
- // For automatic / mob handling
- return InterceptClickOn(owner, null, target)
- if(owner.click_intercept == src)
- owner.click_intercept = null
- else
- owner.click_intercept = src
- for(var/datum/action/cooldown/ability in owner.actions)
- ability.UpdateButtons()
- return TRUE
- return PreActivate(owner)
-
-/// Intercepts client owner clicks to activate the ability
-/datum/action/cooldown/proc/InterceptClickOn(mob/living/caller, params, atom/target)
- if(!IsAvailable())
- return FALSE
- if(!target)
- return FALSE
- PreActivate(target)
- caller.click_intercept = null
- return TRUE
-
-/// For signal calling
-/datum/action/cooldown/proc/PreActivate(atom/target)
- if(SEND_SIGNAL(owner, COMSIG_MOB_ABILITY_STARTED, src) & COMPONENT_BLOCK_ABILITY_START)
- return
- . = Activate(target)
- SEND_SIGNAL(owner, COMSIG_MOB_ABILITY_FINISHED, src)
-
-/// To be implemented by subtypes
-/datum/action/cooldown/proc/Activate(atom/target)
- return
-
-/datum/action/cooldown/UpdateButton(atom/movable/screen/movable/action_button/button, status_only = FALSE, force = FALSE)
- . = ..()
- if(!button)
- return
- var/time_left = max(next_use_time - world.time, 0)
- if(text_cooldown)
- button.maptext = MAPTEXT("[round(time_left/10, 0.1)]")
- if(!owner || time_left == 0)
- button.maptext = ""
- if(IsAvailable() && owner.click_intercept == src)
- button.color = COLOR_GREEN
-
-/datum/action/cooldown/process()
- var/time_left = max(next_use_time - world.time, 0)
- if(!owner || time_left == 0)
- STOP_PROCESSING(SSfastprocess, src)
- UpdateButtons()
-
-/datum/action/cooldown/Grant(mob/M)
- ..()
- if(!owner)
- return
- UpdateButtons()
- if(next_use_time > world.time)
- START_PROCESSING(SSfastprocess, src)
-
//surf_ss13
/datum/action/item_action/bhop
name = "Activate Jump Boots"
desc = "Activates the jump boot's internal propulsion system, allowing the user to dash over 4-wide gaps."
- icon_icon = 'icons/mob/actions/actions_items.dmi'
+ button_icon = 'icons/mob/actions/actions_items.dmi'
button_icon_state = "jetboot"
/datum/action/item_action/wheelys
name = "Toggle Wheely-Heel's Wheels"
desc = "Pops out or in your wheely-heel's wheels."
- icon_icon = 'icons/mob/actions/actions_items.dmi'
+ button_icon = 'icons/mob/actions/actions_items.dmi'
button_icon_state = "wheelys"
/datum/action/item_action/kindleKicks
name = "Activate Kindle Kicks"
desc = "Kick you feet together, activating the lights in your Kindle Kicks."
- icon_icon = 'icons/mob/actions/actions_items.dmi'
+ button_icon = 'icons/mob/actions/actions_items.dmi'
button_icon_state = "kindleKicks"
//Small sprites
@@ -987,8 +966,10 @@
/datum/action/small_sprite/megafauna/legion
small_icon_state = "mega_legion"
-/datum/action/small_sprite/Trigger()
- ..()
+/datum/action/small_sprite/Trigger(trigger_flags)
+ . = ..()
+ if(!.)
+ return FALSE
if(!small)
var/image/I = image(icon = small_icon, icon_state = small_icon_state, loc = owner)
I.override = TRUE
@@ -999,11 +980,12 @@
else
owner.remove_alt_appearance("smallsprite")
small = FALSE
+ return TRUE
/datum/action/item_action/storage_gather_mode
name = "Switch gathering mode"
desc = "Switches the gathering mode of a storage object."
- button_icon = 'icons/mob/actions/actions_items.dmi'
+ background_icon = 'icons/mob/actions/actions_items.dmi'
background_icon_state = "storage_gather_switch"
/proc/get_action_of_type(mob/M, action_type)
diff --git a/code/datums/actions/beam_rifle.dm b/code/datums/actions/beam_rifle.dm
index 3af5d13690d0..23e19d5832d7 100644
--- a/code/datums/actions/beam_rifle.dm
+++ b/code/datums/actions/beam_rifle.dm
@@ -1,12 +1,12 @@
/datum/action/item_action/zoom_speed_action
name = "Toggle Zooming Speed"
- icon_icon = 'icons/mob/actions/actions_spells.dmi'
+ button_icon = 'icons/mob/actions/actions_spells.dmi'
button_icon_state = "projectile"
background_icon_state = "bg_tech"
/datum/action/item_action/zoom_lock_action
name = "Switch Zoom Mode"
- icon_icon = 'icons/mob/actions/actions_items.dmi'
+ button_icon = 'icons/mob/actions/actions_items.dmi'
button_icon_state = "zoom_mode"
background_icon_state = "bg_tech"
diff --git a/code/datums/actions/cooldown_action.dm b/code/datums/actions/cooldown_action.dm
new file mode 100644
index 000000000000..d590fa3bc035
--- /dev/null
+++ b/code/datums/actions/cooldown_action.dm
@@ -0,0 +1,153 @@
+#define COOLDOWN_NO_DISPLAY_TIME (180 SECONDS)
+
+/// Preset for an action with a cooldown
+/datum/action/cooldown
+ check_flags = 0
+ transparent_when_unavailable = FALSE
+ /// The default cooldown applied when StartCooldown() is called
+ var/cooldown_time = 0
+ /// The actual next time this ability can be used
+ var/next_use_time = 0
+ /// Whether or not you want the cooldown for the ability to display in text form
+ var/text_cooldown = TRUE
+ /// Significant figures to round cooldown to
+ var/cooldown_rounding = 0.1
+ /// Setting for intercepting clicks before activating the ability
+ var/click_to_activate = FALSE
+ /// Shares cooldowns with other cooldown abilities of the same value, not active if null
+ var/shared_cooldown
+ /// The base icon_state of this action's background
+ var/base_background_icon_state
+ /// The icon state the background uses when active
+ var/active_background_icon_state
+ /// The base icon_state of the overlay we apply
+ var/base_overlay_icon_state
+ /// The active icon_state of the overlay we apply
+ var/active_overlay_icon_state
+ /// The base icon state of the spell's button icon, used for editing the icon "off"
+ var/base_icon_state
+ /// The active icon state of the spell's button icon, used for editing the icon "on"
+ var/active_icon_state
+
+/datum/action/cooldown/create_button()
+ var/atom/movable/screen/movable/action_button/button = ..()
+ button.maptext = ""
+ button.maptext_x = 8
+ button.maptext_y = 0
+ button.maptext_width = 24
+ button.maptext_height = 12
+ return button
+
+/datum/action/cooldown/update_button_status(atom/movable/screen/movable/action_button/button, force = FALSE)
+ . = ..()
+ var/time_left = max(next_use_time - world.time, 0)
+ if(!text_cooldown || !owner || time_left == 0 || time_left >= COOLDOWN_NO_DISPLAY_TIME)
+ button.maptext = ""
+ else
+ if (cooldown_rounding > 0)
+ button.maptext = MAPTEXT_TINY_UNICODE("[round(time_left/10, cooldown_rounding)]")
+ else
+ button.maptext = MAPTEXT_TINY_UNICODE("[round(time_left/10)]")
+
+ if(!IsAvailable() || !is_action_active(button))
+ return
+ // If we don't change the icon state, or don't apply a special overlay,
+ if(active_background_icon_state || active_icon_state || active_overlay_icon_state)
+ return
+ // ...we need to show it's active somehow. So, make it greeeen
+ button.color = COLOR_GREEN
+
+/datum/action/cooldown/apply_button_background(atom/movable/screen/movable/action_button/current_button, force)
+ if(active_background_icon_state)
+ background_icon_state = is_action_active(current_button) ? active_background_icon_state : base_background_icon_state
+ return ..()
+
+/datum/action/cooldown/apply_button_icon(atom/movable/screen/movable/action_button/current_button, force)
+ if(active_icon_state)
+ button_icon_state = is_action_active(current_button) ? active_icon_state : base_icon_state
+ return ..()
+
+/datum/action/cooldown/apply_button_overlay(atom/movable/screen/movable/action_button/current_button, force)
+ if(active_overlay_icon_state)
+ overlay_icon_state = is_action_active(current_button) ? active_overlay_icon_state : base_overlay_icon_state
+ return ..()
+
+/datum/action/cooldown/is_action_active(atom/movable/screen/movable/action_button/current_button)
+ return click_to_activate && current_button.our_hud?.mymob?.click_intercept == src
+
+/datum/action/cooldown/IsAvailable(feedback = FALSE)
+ return ..() && (next_use_time <= world.time)
+
+/// Starts a cooldown time to be shared with similar abilities, will use default cooldown time if an override is not specified
+/datum/action/cooldown/proc/StartCooldown(override_cooldown_time)
+ if(shared_cooldown)
+ for(var/datum/action/cooldown/shared_ability in owner.actions - src)
+ if(shared_cooldown == shared_ability.shared_cooldown)
+ if(isnum(override_cooldown_time))
+ shared_ability.StartCooldownSelf(override_cooldown_time)
+ else
+ shared_ability.StartCooldownSelf(cooldown_time)
+ StartCooldownSelf(override_cooldown_time)
+
+/// Starts a cooldown time for this ability only, will use default cooldown time if an override is not specified
+/datum/action/cooldown/proc/StartCooldownSelf(override_cooldown_time)
+ if(isnum(override_cooldown_time))
+ next_use_time = world.time + override_cooldown_time
+ else
+ next_use_time = world.time + cooldown_time
+ build_all_button_icons()
+ START_PROCESSING(SSfastprocess, src)
+
+/datum/action/cooldown/Trigger(trigger_flags, atom/target)
+ . = ..()
+ if(!.)
+ return
+ if(!owner)
+ return FALSE
+ if(click_to_activate)
+ if(target)
+ // For automatic / mob handling
+ return InterceptClickOn(owner, null, target)
+ if(owner.click_intercept == src)
+ owner.click_intercept = null
+ else
+ owner.click_intercept = src
+ for(var/datum/action/cooldown/ability in owner.actions)
+ ability.build_all_button_icons()
+ return TRUE
+ return PreActivate(owner)
+
+/// Intercepts client owner clicks to activate the ability
+/datum/action/cooldown/proc/InterceptClickOn(mob/living/caller, params, atom/target)
+ if(!IsAvailable(feedback = TRUE))
+ return FALSE
+ if(!target)
+ return FALSE
+ PreActivate(target)
+ caller.click_intercept = null
+ return TRUE
+
+/// For signal calling
+/datum/action/cooldown/proc/PreActivate(atom/target)
+ if(SEND_SIGNAL(owner, COMSIG_MOB_ABILITY_STARTED, src) & COMPONENT_BLOCK_ABILITY_START)
+ return
+ . = Activate(target)
+ SEND_SIGNAL(owner, COMSIG_MOB_ABILITY_FINISHED, src)
+
+/// To be implemented by subtypes
+/datum/action/cooldown/proc/Activate(atom/target)
+ return
+
+/datum/action/cooldown/process()
+ var/time_left = max(next_use_time - world.time, 0)
+ if(!owner || time_left == 0)
+ STOP_PROCESSING(SSfastprocess, src)
+ build_all_button_icons()
+
+/datum/action/cooldown/Grant(mob/M)
+ ..()
+ if(!owner)
+ return
+ build_all_button_icons()
+ if(next_use_time > world.time)
+ START_PROCESSING(SSfastprocess, src)
diff --git a/code/datums/actions/flightsuit.dm b/code/datums/actions/flightsuit.dm
index 205b72cfae23..b5c67a105958 100644
--- a/code/datums/actions/flightsuit.dm
+++ b/code/datums/actions/flightsuit.dm
@@ -1,117 +1,126 @@
/datum/action/item_action/flightsuit
- icon_icon = 'icons/mob/actions/actions_flightsuit.dmi'
+ button_icon = 'icons/mob/actions/actions_flightsuit.dmi'
/datum/action/item_action/flightsuit/toggle_boots
name = "Toggle Boots"
button_icon_state = "flightsuit_shoes"
background_icon_state = "bg_tech"
-/datum/action/item_action/flightsuit/toggle_boots/Trigger()
+/datum/action/item_action/flightsuit/toggle_boots/do_effect(trigger_flags)
var/obj/item/clothing/suit/space/hardsuit/flightsuit/FS = target
- if(istype(FS))
- FS.deployedshoes? FS.retract_flightshoes() : FS.extend_flightshoes()
- return ..()
+ if(!istype(FS))
+ return FALSE
+ FS.deployedshoes? FS.retract_flightshoes() : FS.extend_flightshoes()
+ return TRUE
/datum/action/item_action/flightsuit/toggle_helmet
name = "Toggle Helmet"
button_icon_state = "flightsuit_helmet"
background_icon_state = "bg_tech"
-/datum/action/item_action/flightsuit/toggle_helmet/Trigger()
+/datum/action/item_action/flightsuit/toggle_helmet/do_effect(trigger_flags)
var/obj/item/clothing/suit/space/hardsuit/flightsuit/FS = target
- if(istype(FS))
- FS.ToggleHelmet()
- return ..()
+ if(!istype(FS))
+ return FALSE
+ FS.ToggleHelmet()
/datum/action/item_action/flightsuit/toggle_flightpack
name = "Toggle Flightpack"
button_icon_state = "flightsuit_pack"
background_icon_state = "bg_tech"
-/datum/action/item_action/flightsuit/toggle_flightpack/Trigger()
+/datum/action/item_action/flightsuit/toggle_flightpack/do_effect(trigger_flags)
var/obj/item/clothing/suit/space/hardsuit/flightsuit/FS = target
- if(istype(FS))
- FS.deployedpack? FS.retract_flightpack() : FS.extend_flightpack()
- return ..()
+ if(!istype(FS))
+ return FALSE
+ FS.deployedpack? FS.retract_flightpack() : FS.extend_flightpack()
+ return TRUE
/datum/action/item_action/flightsuit/lock_suit
name = "Lock Suit"
button_icon_state = "flightsuit_lock"
background_icon_state = "bg_tech"
-/datum/action/item_action/flightsuit/lock_suit/Trigger()
+/datum/action/item_action/flightsuit/lock_suit/do_effect(trigger_flags)
var/obj/item/clothing/suit/space/hardsuit/flightsuit/FS = target
- if(istype(FS))
- FS.locked? FS.unlock_suit(owner) : FS.lock_suit(owner)
- return ..()
+ if(!istype(FS))
+ return FALSE
+ FS.locked? FS.unlock_suit(owner) : FS.lock_suit(owner)
+ return TRUE
/datum/action/item_action/flightpack
- icon_icon = 'icons/mob/actions/actions_flightsuit.dmi'
+ button_icon = 'icons/mob/actions/actions_flightsuit.dmi'
/datum/action/item_action/flightpack/toggle_flight
name = "Toggle Flight"
button_icon_state = "flightpack_fly"
background_icon_state = "bg_tech_blue"
-/datum/action/item_action/flightpack/toggle_flight/Trigger()
+/datum/action/item_action/flightpack/toggle_flight/do_effect(trigger_flags)
var/obj/item/flightpack/F = target
- if(istype(F))
- F.flight? F.disable_flight() : F.enable_flight()
- return ..()
+ if(!istype(F))
+ return FALSE
+ F.flight? F.disable_flight() : F.enable_flight()
+ return TRUE
/datum/action/item_action/flightpack/engage_boosters
name = "Toggle Boosters"
button_icon_state = "flightpack_boost"
background_icon_state = "bg_tech_blue"
-/datum/action/item_action/flightpack/engage_boosters/Trigger()
+/datum/action/item_action/flightpack/engage_boosters/do_effect(trigger_flags)
var/obj/item/flightpack/F = target
- if(istype(F))
- F.boost? F.deactivate_booster() : F.activate_booster()
- return ..()
+ if(!istype(F))
+ return FALSE
+ F.boost? F.deactivate_booster() : F.activate_booster()
+ return TRUE
/datum/action/item_action/flightpack/toggle_stabilizers
name = "Toggle Stabilizers"
button_icon_state = "flightpack_stabilizer"
background_icon_state = "bg_tech_blue"
-/datum/action/item_action/flightpack/toggle_stabilizers/Trigger()
+/datum/action/item_action/flightpack/toggle_stabilizers/do_effect(trigger_flags)
var/obj/item/flightpack/F = target
- if(istype(F))
- F.stabilizer? F.disable_stabilizers() : F.enable_stabilizers()
- return ..()
+ if(!istype(F))
+ return FALSE
+ F.stabilizer? F.disable_stabilizers() : F.enable_stabilizers()
+ return TRUE
/datum/action/item_action/flightpack/change_power
name = "Flight Power Setting"
button_icon_state = "flightpack_power"
background_icon_state = "bg_tech_blue"
-/datum/action/item_action/flightpack/change_power/Trigger()
+/datum/action/item_action/flightpack/change_power/do_effect(trigger_flags)
var/obj/item/flightpack/F = target
- if(istype(F))
- F.cycle_power()
- return ..()
+ if(!istype(F))
+ return FALSE
+ F.cycle_power()
+ return TRUE
/datum/action/item_action/flightpack/toggle_airbrake
name = "Toggle Airbrake"
button_icon_state = "flightpack_airbrake"
background_icon_state = "bg_tech_blue"
-/datum/action/item_action/flightpack/toggle_airbrake/Trigger()
+/datum/action/item_action/flightpack/toggle_airbrake/do_effect(trigger_flags)
var/obj/item/flightpack/F = target
- if(istype(F))
- F.brake? F.disable_airbrake() : F.enable_airbrake()
- return ..()
+ if(!istype(F))
+ return FALSE
+ F.brake? F.disable_airbrake() : F.enable_airbrake()
+ return TRUE
/datum/action/item_action/flightpack/zoom
name = "Helmet Smart Zoom"
- icon_icon = 'icons/mob/actions.dmi'
+ button_icon = 'icons/mob/actions.dmi'
background_icon_state = "bg_tech_blue"
- icon_icon = 'icons/mob/actions/actions_items.dmi'
+ button_icon = 'icons/mob/actions/actions_items.dmi'
button_icon_state = "sniper_zoom"
-/datum/action/item_action/flightpack/zoom/Trigger()
+/datum/action/item_action/flightpack/zoom/do_effect(trigger_flags)
var/obj/item/clothing/head/helmet/space/hardsuit/flightsuit/FH = target
- if(istype(FH))
+ if(!istype(FH))
+ return FALSE
FH.toggle_zoom(owner)
- return ..()
+ return TRUE
diff --git a/code/datums/actions/innate_action.dm b/code/datums/actions/innate_action.dm
new file mode 100644
index 000000000000..c7ff4830a434
--- /dev/null
+++ b/code/datums/actions/innate_action.dm
@@ -0,0 +1,28 @@
+//Preset for general and toggled actions
+/datum/action/innate
+ check_flags = NONE
+ required_mobility_flags = NONE
+ /// Whether we're active or not, if we're a innate - toggle action.
+ var/active = FALSE
+
+/datum/action/innate/Trigger(trigger_flags)
+ if(!..())
+ return FALSE
+ var/active_status = active
+ if(active_status)
+ Deactivate()
+ else
+ Activate()
+
+ if(active != active_status)
+ build_all_button_icons(UPDATE_BUTTON_STATUS)
+ return TRUE
+
+/datum/action/innate/is_action_active(atom/movable/screen/movable/action_button/current_button)
+ return active
+
+/datum/action/innate/proc/Activate()
+ return
+
+/datum/action/innate/proc/Deactivate()
+ return
diff --git a/code/datums/actions/item_action.dm b/code/datums/actions/item_action.dm
new file mode 100644
index 000000000000..5ba78f1da81c
--- /dev/null
+++ b/code/datums/actions/item_action.dm
@@ -0,0 +1,37 @@
+//Presets for item actions
+/datum/action/item_action
+ name = "Item Action"
+ check_flags = AB_CHECK_RESTRAINED|AB_CHECK_STUN|AB_CHECK_CONSCIOUS
+ button_icon_state = null
+
+/datum/action/item_action/New(Target)
+ . = ..()
+
+ // If our button state is null, use the target's icon instead
+ if(target && isnull(button_icon_state))
+ AddComponent(/datum/component/action_item_overlay, target)
+
+/datum/action/item_action/vv_edit_var(var_name, var_value)
+ . = ..()
+ if(!. || !target)
+ return
+
+ if(var_name == NAMEOF(src, button_icon_state))
+ // If someone vv's our icon either add or remove the component
+ if(isnull(var_name))
+ AddComponent(/datum/component/action_item_overlay, target)
+ else
+ qdel(GetComponent(/datum/component/action_item_overlay))
+
+/datum/action/item_action/Trigger(trigger_flags)
+ . = ..()
+ if(!.)
+ return FALSE
+ return do_effect(trigger_flags)
+
+/datum/action/item_action/proc/do_effect(trigger_flags)
+ if(!target)
+ return FALSE
+ var/obj/item/item_target = target
+ item_target.ui_action_click(owner, src)
+ return TRUE
diff --git a/code/datums/brain_damage/imaginary_friend.dm b/code/datums/brain_damage/imaginary_friend.dm
index 38e187845198..7197211c22bb 100644
--- a/code/datums/brain_damage/imaginary_friend.dm
+++ b/code/datums/brain_damage/imaginary_friend.dm
@@ -200,7 +200,7 @@
/datum/action/innate/imaginary_join
name = "Join"
desc = "Join your owner, following them from inside their mind."
- icon_icon = 'icons/mob/actions/actions_minor_antag.dmi'
+ button_icon = 'icons/mob/actions/actions_minor_antag.dmi'
background_icon_state = "bg_revenant"
button_icon_state = "join"
@@ -211,7 +211,7 @@
/datum/action/innate/imaginary_hide
name = "Hide"
desc = "Hide yourself from your owner's sight."
- icon_icon = 'icons/mob/actions/actions_minor_antag.dmi'
+ button_icon = 'icons/mob/actions/actions_minor_antag.dmi'
background_icon_state = "bg_revenant"
button_icon_state = "hide"
@@ -225,7 +225,7 @@
name = "Hide"
desc = "Hide yourself from your owner's sight."
button_icon_state = "hide"
- UpdateButtons()
+ build_all_button_icons()
/datum/action/innate/imaginary_hide/Activate()
var/mob/camera/imaginary_friend/I = owner
diff --git a/code/datums/components/action_item_overlay.dm b/code/datums/components/action_item_overlay.dm
new file mode 100644
index 000000000000..80478aa9ca42
--- /dev/null
+++ b/code/datums/components/action_item_overlay.dm
@@ -0,0 +1,79 @@
+/**
+ * Apply to an action to allow it to take an item
+ * and apply it as an overlay of the action button
+ */
+/datum/component/action_item_overlay
+ /// Weakref to what item the component uses to apply as an overlay.
+ var/datum/weakref/item_ref
+ /// Callback that dictates what item the component uses to apply as an overlay.
+ var/datum/callback/item_callback
+
+ /// The appearance of the item we've applied
+ var/mutable_appearance/item_appearance
+
+/datum/component/action_item_overlay/Initialize(atom/movable/item, datum/callback/item_callback)
+ if(!istype(parent, /datum/action))
+ return COMPONENT_INCOMPATIBLE
+
+ ASSERT(isnull(item) || istype(item))
+
+ if(!item && !item_callback)
+ stack_trace("[type] created without a reference item or an item callback - one or the other is required.")
+ return COMPONENT_INCOMPATIBLE
+
+ src.item_ref = WEAKREF(item)
+ src.item_callback = item_callback
+
+/datum/component/action_item_overlay/Destroy(force)
+ item_ref = null
+ item_callback = null
+ item_appearance = null
+ return ..()
+
+/datum/component/action_item_overlay/RegisterWithParent()
+ RegisterSignal(parent, COMSIG_ACTION_OVERLAY_APPLY, PROC_REF(on_overlays_applied))
+
+ var/datum/action/parent_action = parent
+ parent_action.build_all_button_icons(UPDATE_BUTTON_OVERLAY)
+
+/datum/component/action_item_overlay/UnregisterFromParent()
+ UnregisterSignal(parent, COMSIG_ACTION_OVERLAY_APPLY)
+
+ // If we're being unregistered / deleted but our parent is sticking around,
+ // force an overlay update to get rid of our item appearance
+ if(!QDELING(parent))
+ var/datum/action/parent_action = parent
+ parent_action.build_all_button_icons(UPDATE_BUTTON_OVERLAY)
+
+/// Signal proc for [COMSIG_ACTION_OVERLAY_APPLY], applies the item appearance if possible.
+/datum/component/action_item_overlay/proc/on_overlays_applied(datum/action/source, atom/movable/screen/movable/action_button/current_button, force)
+ SIGNAL_HANDLER
+
+ // We're in the middle of being removed / deleted, remove our associated overlay
+ if(QDELING(src))
+ if(item_appearance)
+ current_button.cut_overlay(item_appearance)
+ item_appearance = null
+ return
+
+ var/atom/movable/muse = item_callback?.Invoke() || item_ref?.resolve()
+ if(!istype(muse))
+ if(item_appearance) // New item does not exist but we have an old appearance
+ current_button.cut_overlay(item_appearance)
+ item_appearance = null
+ return
+
+ if(item_appearance)
+ // For caching purposes, we will try not to update if we don't need to
+ if(!force && item_appearance.icon == muse.icon && item_appearance.icon_state == muse.icon_state)
+ return
+ current_button.cut_overlay(item_appearance)
+
+ var/mutable_appearance/muse_appearance = new(muse.appearance)
+ muse_appearance.plane = FLOAT_PLANE
+ muse_appearance.layer = FLOAT_LAYER
+ muse_appearance.pixel_x = 0
+ muse_appearance.pixel_y = 0
+
+ current_button.add_overlay(muse_appearance)
+ item_appearance = muse_appearance
diff --git a/code/datums/components/dullahan.dm b/code/datums/components/dullahan.dm
index 0d1b8fe21957..596e9af3cba6 100644
--- a/code/datums/components/dullahan.dm
+++ b/code/datums/components/dullahan.dm
@@ -151,8 +151,10 @@
name = "Toggle Perspective"
desc = "Switch between seeing normally from your head, or blindly from your body."
-/datum/action/item_action/organ_action/dullahan/Trigger()
+/datum/action/item_action/organ_action/dullahan/do_effect(trigger_flags)
. = ..()
+ if(!.)
+ return
var/mob/living/carbon/human/H = owner
var/obj/item/organ/eyes/E = owner.getorganslot(ORGAN_SLOT_EYES)
if(E)
@@ -162,13 +164,14 @@
E.tint = INFINITY
var/datum/component/dullahan/D = H.GetComponent(/datum/component/dullahan)
- if(D)
- D.update_vision_perspective()
+ if(!D)
+ return FALSE
+ return D.update_vision_perspective()
/datum/component/dullahan/proc/update_vision_perspective()
var/mob/living/carbon/human/H = parent
if(!H)
- return .
+ return FALSE
var/obj/item/organ/eyes/eyes = H.getorganslot(ORGAN_SLOT_EYES)
if(eyes)
H.update_tint()
@@ -176,6 +179,7 @@
H.reset_perspective(H)
else
H.reset_perspective(dullahan_head)
+ return TRUE
/datum/component/dullahan/Destroy()
UnregisterSignal(parent, COMSIG_LIVING_REGENERATE_LIMBS)
diff --git a/code/datums/components/storage/storage.dm b/code/datums/components/storage/storage.dm
index cde8a09e8a6e..91b252a68b6b 100644
--- a/code/datums/components/storage/storage.dm
+++ b/code/datums/components/storage/storage.dm
@@ -133,7 +133,7 @@
if(!isitem(parent) || !allow_quick_gather)
return
var/obj/item/I = parent
- modeswitch_action = new(I)
+ modeswitch_action = I.add_item_action(/datum/action/item_action/storage_gather_mode)
RegisterSignal(modeswitch_action, COMSIG_ACTION_TRIGGER, PROC_REF(action_trigger))
if(I.obj_flags & IN_INVENTORY)
var/mob/M = I.loc
diff --git a/code/datums/dash_weapon.dm b/code/datums/dash_weapon.dm
index adf7b72c1129..cd37ac5dc191 100644
--- a/code/datums/dash_weapon.dm
+++ b/code/datums/dash_weapon.dm
@@ -1,7 +1,7 @@
/datum/action/innate/dash
name = "Dash"
desc = "Teleport to the targeted location."
- icon_icon = 'icons/mob/actions/actions_items.dmi'
+ button_icon = 'icons/mob/actions/actions_items.dmi'
button_icon_state = "jetboot"
var/current_charges = 1
var/max_charges = 1
@@ -17,7 +17,7 @@
. = ..()
dashing_item = dasher
-/datum/action/innate/dash/IsAvailable(silent = FALSE)
+/datum/action/innate/dash/IsAvailable(feedback = TRUE)
if(current_charges > 0)
return TRUE
else
@@ -27,7 +27,7 @@
dashing_item.attack_self(owner) //Used to toggle dash behavior in the dashing item
/datum/action/innate/dash/proc/Teleport(mob/user, atom/target)
- if(!IsAvailable())
+ if(!IsAvailable(feedback = TRUE))
return
var/turf/T = get_turf(target)
if(target in view(user.client.view, user))
@@ -36,12 +36,12 @@
var/obj/spot2 = new phasein(get_turf(user), user.dir)
spot1.Beam(spot2,beam_effect,time=20)
current_charges--
- owner.update_action_buttons_icon()
+ owner.update_mob_action_buttons()
addtimer(CALLBACK(src, PROC_REF(charge)), charge_rate)
/datum/action/innate/dash/proc/charge()
current_charges = clamp(current_charges + 1, 0, max_charges)
- owner.update_action_buttons_icon()
+ owner.update_mob_action_buttons()
if(recharge_sound)
playsound(dashing_item, recharge_sound, 50, 1)
to_chat(owner, "[src] now has [current_charges]/[max_charges] charges.")
diff --git a/code/datums/elements/polychromic.dm b/code/datums/elements/polychromic.dm
index bc6a6dd1da33..18cfac99f887 100644
--- a/code/datums/elements/polychromic.dm
+++ b/code/datums/elements/polychromic.dm
@@ -41,8 +41,9 @@
RegisterSignal(A, COMSIG_ATOM_UPDATE_OVERLAYS, PROC_REF(apply_overlays))
if(_flags & POLYCHROMIC_ALTCLICK)
- RegisterSignal(A, COMSIG_PARENT_EXAMINE, PROC_REF(on_examine))
+ RegisterSignal(A, COMSIG_ATOM_REQUESTING_CONTEXT_FROM_ITEM, PROC_REF(on_requesting_context_from_item))
RegisterSignal(A, COMSIG_CLICK_ALT, PROC_REF(set_color))
+ RegisterSignal(A, COMSIG_PARENT_EXAMINE, PROC_REF(on_examine))
if(!overlays_names && names) //generate
overlays_names = names
@@ -77,7 +78,7 @@
if(P)
actions_by_atom -= A
qdel(P)
- UnregisterSignal(A, list(COMSIG_PARENT_EXAMINE, COMSIG_CLICK_ALT, COMSIG_ATOM_UPDATE_OVERLAYS, COMSIG_ITEM_EQUIPPED, COMSIG_ITEM_DROPPED, COMSIG_ITEM_WORN_OVERLAYS, COMSIG_SUIT_MADE_HELMET))
+ UnregisterSignal(A, list(COMSIG_ATOM_REQUESTING_CONTEXT_FROM_ITEM, COMSIG_ATOM_UPDATE_OVERLAYS, COMSIG_CLICK_ALT, COMSIG_PARENT_EXAMINE, COMSIG_ITEM_EQUIPPED, COMSIG_ITEM_DROPPED, COMSIG_ITEM_WORN_OVERLAYS, COMSIG_SUIT_MADE_HELMET))
if(isitem(A))
var/obj/item/clothing/head/H = helmet_by_suit[A]
if(H)
@@ -161,9 +162,21 @@
/datum/element/polychromic/proc/activate_action(datum/action/source, atom/target)
set_color(target, source.owner)
+ return COMPONENT_ACTION_BLOCK_TRIGGER
/datum/element/polychromic/proc/on_examine(atom/source, mob/user, list/examine_list)
- examine_list += "Alt-click to recolor it."
+ examine_list += span_notice("Alt-click to recolor it.")
+
+/datum/element/polychromic/proc/on_requesting_context_from_item(
+ obj/source,
+ list/context,
+ obj/item/held_item,
+ mob/living/user,
+)
+ SIGNAL_HANDLER
+
+ LAZYSET(context[SCREENTIP_CONTEXT_ALT_LMB], INTENT_ANY, "Modify [source]'\s Colors")
+ return CONTEXTUAL_SCREENTIP_SET
/datum/element/polychromic/proc/connect_helmet(atom/I, var/applycolor)
if(isitem(I))
@@ -203,7 +216,7 @@
button_icon_state = null
check_flags = NONE
-/datum/action/item_action/polychromic/ApplyIcon(atom/movable/screen/movable/action_button/current_button, force)
+/datum/action/item_action/polychromic/apply_button_icon(atom/movable/screen/movable/action_button/current_button, force = FALSE)
var/atom/polychromic_thing = target
var/matrix/save_matrix = polychromic_thing.transform
diff --git a/code/datums/holocall.dm b/code/datums/holocall.dm
index bb033c10c9f2..ac627bc3f341 100644
--- a/code/datums/holocall.dm
+++ b/code/datums/holocall.dm
@@ -198,7 +198,7 @@
/datum/action/innate/end_holocall
name = "End Holocall"
- icon_icon = 'icons/mob/actions/actions_silicon.dmi'
+ button_icon = 'icons/mob/actions/actions_silicon.dmi'
button_icon_state = "camera_off"
var/datum/holocall/hcall
diff --git a/code/datums/martial/krav_maga.dm b/code/datums/martial/krav_maga.dm
index d91e802a8aa6..dac11a0e86b3 100644
--- a/code/datums/martial/krav_maga.dm
+++ b/code/datums/martial/krav_maga.dm
@@ -8,63 +8,90 @@
/datum/action/neck_chop
name = "Neck Chop - Injures the neck, stopping the victim from speaking for a while."
- icon_icon = 'icons/mob/actions/actions_items.dmi'
+ button_icon = 'icons/mob/actions/actions_items.dmi'
button_icon_state = "neckchop"
-/datum/action/neck_chop/Trigger()
- if(owner.incapacitated())
- to_chat(owner, "You can't use [name] while you're incapacitated.")
- return
+/datum/action/neck_chop/Trigger(trigger_flags)
+ . = ..()
+ if(!.)
+ return FALSE
var/mob/living/carbon/human/H = owner
if (H.mind.martial_art.streak == "neck_chop")
owner.visible_message("[owner] assumes a neutral stance.", "Your next attack is cleared.")
H.mind.martial_art.streak = ""
else
- if(HAS_TRAIT(H, TRAIT_PACIFISM))
- to_chat(H, "You don't want to harm other people!")
- return
owner.visible_message("[owner] assumes the Neck Chop stance!", "Your next attack will be a Neck Chop.")
H.mind.martial_art.streak = "neck_chop"
+ return TRUE
+
+/datum/action/neck_chop/IsAvailable(feedback)
+ if(owner.incapacitated())
+ if(feedback)
+ to_chat(owner, "You can't use [name] while you're incapacitated.")
+ return FALSE
+ if(HAS_TRAIT(owner, TRAIT_PACIFISM))
+ if(feedback)
+ to_chat(owner, "You don't want to harm other people!")
+ return FALSE
+ return ..()
/datum/action/leg_sweep
name = "Leg Sweep - Trips the victim, knocking them down for a brief moment."
- icon_icon = 'icons/mob/actions/actions_items.dmi'
+ button_icon = 'icons/mob/actions/actions_items.dmi'
button_icon_state = "legsweep"
-/datum/action/leg_sweep/Trigger()
- if(owner.incapacitated())
- to_chat(owner, "You can't use [name] while you're incapacitated.")
- return
+/datum/action/leg_sweep/Trigger(trigger_flags)
+ . = ..()
+ if(!.)
+ return FALSE
var/mob/living/carbon/human/H = owner
if (H.mind.martial_art.streak == "leg_sweep")
owner.visible_message("[owner] assumes a neutral stance.", "Your next attack is cleared.")
H.mind.martial_art.streak = ""
else
- if(HAS_TRAIT(H, TRAIT_PACIFISM))
- to_chat(H, "You don't want to harm other people!")
- return
owner.visible_message("[owner] assumes the Leg Sweep stance!", "Your next attack will be a Leg Sweep.")
H.mind.martial_art.streak = "leg_sweep"
+ return TRUE
+
+/datum/action/leg_sweep/IsAvailable(feedback)
+ if(owner.incapacitated())
+ if(feedback)
+ to_chat(owner, "You can't use [name] while you're incapacitated.")
+ return FALSE
+ if(HAS_TRAIT(owner, TRAIT_PACIFISM))
+ if(feedback)
+ to_chat(owner, "You don't want to harm other people!")
+ return FALSE
+ return ..()
/datum/action/lung_punch//referred to internally as 'quick choke'
name = "Lung Punch - Delivers a strong punch just above the victim's abdomen, constraining the lungs. The victim will be unable to breathe for a short time."
- icon_icon = 'icons/mob/actions/actions_items.dmi'
+ button_icon = 'icons/mob/actions/actions_items.dmi'
button_icon_state = "lungpunch"
-/datum/action/lung_punch/Trigger()
- if(owner.incapacitated())
- to_chat(owner, "You can't use [name] while you're incapacitated.")
- return
+/datum/action/lung_punch/Trigger(trigger_flags)
+ . = ..()
+ if(!.)
+ return FALSE
var/mob/living/carbon/human/H = owner
if (H.mind.martial_art.streak == "quick_choke")
owner.visible_message("[owner] assumes a neutral stance.", "Your next attack is cleared.")
H.mind.martial_art.streak = ""
else
- if(HAS_TRAIT(H, TRAIT_PACIFISM))
- to_chat(H, "You don't want to harm other people!")
- return
owner.visible_message("[owner] assumes the Lung Punch stance!", "Your next attack will be a Lung Punch.")
H.mind.martial_art.streak = "quick_choke"//internal name for lung punch
+ return TRUE
+
+/datum/action/lung_punch/IsAvailable(feedback)
+ if(owner.incapacitated())
+ if(feedback)
+ to_chat(owner, "You can't use [name] while you're incapacitated.")
+ return FALSE
+ if(HAS_TRAIT(owner, TRAIT_PACIFISM))
+ if(feedback)
+ to_chat(owner, "You don't want to harm other people!")
+ return FALSE
+ return ..()
/datum/martial_art/krav_maga/teach(mob/living/carbon/human/H,make_temporary=0)
if(..())
diff --git a/code/datums/martial/rising_bass.dm b/code/datums/martial/rising_bass.dm
index 87c0d42a2975..d36cead055f4 100644
--- a/code/datums/martial/rising_bass.dm
+++ b/code/datums/martial/rising_bass.dm
@@ -41,24 +41,33 @@
/datum/action/risingbassmove
name = ""
- icon_icon = 'icons/mob/actions/actions_items.dmi'
+ button_icon = 'icons/mob/actions/actions_items.dmi'
button_icon_state = ""
var/movestreak = ""
-/datum/action/risingbassmove/Trigger()
- if(owner.incapacitated())
- to_chat(owner, "You can't use [name] while you're incapacitated.")
- return
+/datum/action/risingbassmove/Trigger(trigger_flags)
+ . = ..()
+ if(!.)
+ return FALSE
var/mob/living/carbon/human/H = owner
if (H.mind.martial_art.streak == "[movestreak]")
H.mind.martial_art.streak = ""
to_chat(H,"You relax your muscles and return to a neutral position.")
else
- if(HAS_TRAIT(H, TRAIT_PACIFISM))
- to_chat(H, "You don't want to harm other people!")
- return
to_chat(H,"You get ready to use the [name] maneuver!")
H.mind.martial_art.streak = "[movestreak]"
+ return TRUE
+
+/datum/action/risingbassmove/IsAvailable(feedback)
+ if(owner.incapacitated())
+ if(feedback)
+ to_chat(owner, "You can't use [name] while you're incapacitated.")
+ return FALSE
+ if(HAS_TRAIT(owner, TRAIT_PACIFISM))
+ if(feedback)
+ to_chat(owner, "You don't want to harm other people!")
+ return FALSE
+ return ..()
/datum/action/risingbassmove/sidekick
name = "Side Kick"
diff --git a/code/datums/martial/wrestling.dm b/code/datums/martial/wrestling.dm
index b56c891820e6..8a175707f497 100644
--- a/code/datums/martial/wrestling.dm
+++ b/code/datums/martial/wrestling.dm
@@ -47,77 +47,121 @@
name = "Slam (Cinch) - Slam a grappled opponent into the floor."
button_icon_state = "wrassle_slam"
-/datum/action/slam/Trigger()
- if(owner.incapacitated())
- to_chat(owner, "You can't WRESTLE while you're OUT FOR THE COUNT.")
- return
- if(HAS_TRAIT(owner, TRAIT_PACIFISM))
- to_chat(owner, "You are too HIPPIE to WRESTLE other living beings!")
- return
- owner.visible_message("[owner] prepares to BODY SLAM!", "Your next attack will be a BODY SLAM.")
+/datum/action/slam/Trigger(trigger_flags)
+ . = ..()
+ if(!.)
+ return FALSE
+ owner.visible_message(span_danger("[owner] prepares to BODY SLAM!"), "Your next attack will be a BODY SLAM.")
var/mob/living/carbon/human/H = owner
H.mind.martial_art.streak = "slam"
+ return TRUE
+
+/datum/action/slam/IsAvailable(feedback)
+ if(owner.incapacitated())
+ if(feedback)
+ to_chat(owner, span_warning("You can't WRESTLE while you're OUT FOR THE COUNT."))
+ return FALSE
+ if(HAS_TRAIT(owner, TRAIT_PACIFISM))
+ if(feedback)
+ to_chat(owner, span_warning("You are too HIPPIE to WRESTLE other living beings!"))
+ return FALSE
+ return ..()
/datum/action/throw_wrassle
name = "Throw (Cinch) - Spin a cinched opponent around and throw them."
button_icon_state = "wrassle_throw"
-/datum/action/throw_wrassle/Trigger()
- if(owner.incapacitated())
- to_chat(owner, "You can't WRESTLE while you're OUT FOR THE COUNT.")
- return
- if(HAS_TRAIT(owner, TRAIT_PACIFISM))
- to_chat(owner, "You are too HIPPIE to WRESTLE other living beings!")
- return
- owner.visible_message("[owner] prepares to THROW!", "Your next attack will be a THROW.")
+/datum/action/throw_wrassle/Trigger(trigger_flags)
+ . = ..()
+ if(!.)
+ return FALSE
+ owner.visible_message(span_danger("[owner] prepares to THROW!"), "Your next attack will be a THROW.")
var/mob/living/carbon/human/H = owner
H.mind.martial_art.streak = "throw"
+ return TRUE
+
+/datum/action/throw_wrassle/IsAvailable(feedback)
+ if(owner.incapacitated())
+ if(feedback)
+ to_chat(owner, span_warning("You can't WRESTLE while you're OUT FOR THE COUNT."))
+ return FALSE
+ if(HAS_TRAIT(owner, TRAIT_PACIFISM))
+ if(feedback)
+ to_chat(owner, span_warning("You are too HIPPIE to WRESTLE other living beings!"))
+ return FALSE
+ return ..()
/datum/action/kick
name = "Kick - A powerful kick, sends people flying away from you. Also useful for escaping from bad situations."
button_icon_state = "wrassle_kick"
-/datum/action/kick/Trigger()
- if(owner.incapacitated())
- to_chat(owner, "You can't WRESTLE while you're OUT FOR THE COUNT.")
- return
- if(HAS_TRAIT(owner, TRAIT_PACIFISM))
- to_chat(owner, "You are too HIPPIE to WRESTLE other living beings!")
- return
- owner.visible_message("[owner] prepares to KICK!", "Your next attack will be a KICK.")
+/datum/action/kick/Trigger(trigger_flags)
+ . = ..()
+ if(!.)
+ return FALSE
+ owner.visible_message(span_danger("[owner] prepares to KICK!"), "Your next attack will be a KICK.")
var/mob/living/carbon/human/H = owner
H.mind.martial_art.streak = "kick"
+ return TRUE
+
+/datum/action/kick/IsAvailable(feedback)
+ if(owner.incapacitated())
+ if(feedback)
+ to_chat(owner, span_warning("You can't WRESTLE while you're OUT FOR THE COUNT."))
+ return FALSE
+ if(HAS_TRAIT(owner, TRAIT_PACIFISM))
+ if(feedback)
+ to_chat(owner, span_warning("You are too HIPPIE to WRESTLE other living beings!"))
+ return FALSE
+ return ..()
/datum/action/strike
name = "Strike - Hit a neaby opponent with a quick attack."
button_icon_state = "wrassle_strike"
-/datum/action/strike/Trigger()
- if(owner.incapacitated())
- to_chat(owner, "You can't WRESTLE while you're OUT FOR THE COUNT.")
- return
- if(HAS_TRAIT(owner, TRAIT_PACIFISM))
- to_chat(owner, "You are too HIPPIE to WRESTLE other living beings!")
- return
- owner.visible_message("[owner] prepares to STRIKE!", "Your next attack will be a STRIKE.")
+/datum/action/strike/Trigger(trigger_flags)
+ . = ..()
+ if(!.)
+ return FALSE
+ owner.visible_message(span_danger("[owner] prepares to STRIKE!"), "Your next attack will be a STRIKE.")
var/mob/living/carbon/human/H = owner
H.mind.martial_art.streak = "strike"
+ return TRUE
+
+/datum/action/strike/IsAvailable(feedback)
+ if(owner.incapacitated())
+ if(feedback)
+ to_chat(owner, span_warning("You can't WRESTLE while you're OUT FOR THE COUNT."))
+ return FALSE
+ if(HAS_TRAIT(owner, TRAIT_PACIFISM))
+ if(feedback)
+ to_chat(owner, span_warning("You are too HIPPIE to WRESTLE other living beings!"))
+ return FALSE
+ return ..()
/datum/action/drop
name = "Drop - Smash down onto an opponent."
button_icon_state = "wrassle_drop"
-/datum/action/drop/Trigger()
- if(owner.incapacitated())
- to_chat(owner, "You can't WRESTLE while you're OUT FOR THE COUNT.")
- return
- if(HAS_TRAIT(owner, TRAIT_PACIFISM))
- to_chat(owner, "You are too HIPPIE to WRESTLE other living beings!")
- return
- owner.visible_message("[owner] prepares to LEG DROP!", "Your next attack will be a LEG DROP.")
+/datum/action/drop/Trigger(trigger_flags)
+ . = ..()
+ if(!.)
+ return FALSE
+ owner.visible_message(span_danger("[owner] prepares to LEG DROP!"), "Your next attack will be a LEG DROP.")
var/mob/living/carbon/human/H = owner
H.mind.martial_art.streak = "drop"
+/datum/action/drop/IsAvailable(feedback)
+ if(owner.incapacitated())
+ if(feedback)
+ to_chat(owner, span_warning("You can't WRESTLE while you're OUT FOR THE COUNT."))
+ return FALSE
+ if(HAS_TRAIT(owner, TRAIT_PACIFISM))
+ if(feedback)
+ to_chat(owner, span_warning("You are too HIPPIE to WRESTLE other living beings!"))
+ return FALSE
+ return ..()
+
/datum/martial_art/wrestling/teach(mob/living/carbon/human/H,make_temporary=0)
if(..())
to_chat(H, "SNAP INTO A THIN TIM!")
@@ -473,8 +517,8 @@
if(A.pulling == D || A == D) // don't stun grab yoursel
return FALSE
A.start_pulling(D)
- D.visible_message("[A] gets [D] in a cinch!", \
- "[A] gets [D] in a cinch!")
+ D.visible_message(span_danger("[A] gets [D] in a cinch!"), \
+ span_userdanger("[A] gets [D] in a cinch!"))
D.Stun(rand(60,100))
log_combat(A, D, "cinched")
return TRUE
diff --git a/code/datums/mutations/actions.dm b/code/datums/mutations/actions.dm
index 37da0c80bf49..4c0f31f04ef2 100644
--- a/code/datums/mutations/actions.dm
+++ b/code/datums/mutations/actions.dm
@@ -492,7 +492,7 @@
..()
/datum/action/innate/send_chems
- icon_icon = 'icons/mob/actions/actions_genetic.dmi'
+ button_icon = 'icons/mob/actions/actions_genetic.dmi'
background_icon_state = "bg_spell"
check_flags = AB_CHECK_CONSCIOUS
button_icon_state = "spikechemswap"
diff --git a/code/datums/outfit.dm b/code/datums/outfit.dm
index 4c17874f97c6..03e63425a3bb 100755
--- a/code/datums/outfit.dm
+++ b/code/datums/outfit.dm
@@ -223,7 +223,7 @@
apply_fingerprints(H)
if(internals_slot)
H.internal = H.get_item_by_slot(internals_slot)
- H.update_action_buttons_icon()
+ H.update_mob_action_buttons()
if(implants)
for(var/implant_type in implants)
var/obj/item/implant/I = new implant_type(H)
diff --git a/code/game/gamemodes/objective_items.dm b/code/game/gamemodes/objective_items.dm
index 2a64f690380c..5f0c601f757d 100644
--- a/code/game/gamemodes/objective_items.dm
+++ b/code/game/gamemodes/objective_items.dm
@@ -168,7 +168,7 @@
excludefromjob = list("Research Director","Scientist", "Roboticist")
/datum/objective_item/steal/slime/check_special_completion(obj/item/slime_extract/E)
- if(E.Uses > 0)
+ if(E.extract_uses > 0)
return TRUE
return FALSE
diff --git a/code/game/machinery/computer/camera_advanced.dm b/code/game/machinery/computer/camera_advanced.dm
index 5395dd6feeac..683c018de2a2 100644
--- a/code/game/machinery/computer/camera_advanced.dm
+++ b/code/game/machinery/computer/camera_advanced.dm
@@ -234,7 +234,7 @@
/datum/action/innate/camera_off
name = "End Camera View"
- icon_icon = 'icons/mob/actions/actions_silicon.dmi'
+ button_icon = 'icons/mob/actions/actions_silicon.dmi'
button_icon_state = "camera_off"
/datum/action/innate/camera_off/Activate()
@@ -246,7 +246,7 @@
/datum/action/innate/camera_jump
name = "Jump To Camera"
- icon_icon = 'icons/mob/actions/actions_silicon.dmi'
+ button_icon = 'icons/mob/actions/actions_silicon.dmi'
button_icon_state = "camera_jump"
/datum/action/innate/camera_jump/Activate()
diff --git a/code/game/machinery/launch_pad.dm b/code/game/machinery/launch_pad.dm
index d113aa0fadbc..6a313c203b75 100644
--- a/code/game/machinery/launch_pad.dm
+++ b/code/game/machinery/launch_pad.dm
@@ -39,7 +39,7 @@
MA.plane = 0
holder.appearance = MA
update_indicator()
-
+
/obj/machinery/launchpad/Destroy()
qdel(hud_list[DIAG_LAUNCHPAD_HUD])
return ..()
diff --git a/code/game/machinery/porta_turret/portable_turret.dm b/code/game/machinery/porta_turret/portable_turret.dm
index 2536c9078f31..fa0ae181673b 100644
--- a/code/game/machinery/porta_turret/portable_turret.dm
+++ b/code/game/machinery/porta_turret/portable_turret.dm
@@ -673,25 +673,33 @@ DEFINE_BITFIELD(turret_flags, list(
/datum/action/turret_toggle
name = "Toggle Mode"
- icon_icon = 'icons/mob/actions/actions_mecha.dmi'
+ button_icon = 'icons/mob/actions/actions_mecha.dmi'
button_icon_state = "mech_cycle_equip_off"
-/datum/action/turret_toggle/Trigger()
+/datum/action/turret_toggle/Trigger(trigger_flags)
+ . = ..()
+ if(!.)
+ return FALSE
var/obj/machinery/porta_turret/P = target
if(!istype(P))
- return
+ return FALSE
P.setState(P.on,!P.mode)
+ return TRUE
/datum/action/turret_quit
name = "Release Control"
- icon_icon = 'icons/mob/actions/actions_mecha.dmi'
+ button_icon = 'icons/mob/actions/actions_mecha.dmi'
button_icon_state = "mech_eject"
-/datum/action/turret_quit/Trigger()
+/datum/action/turret_quit/Trigger(trigger_flags)
+ . = ..()
+ if(!.)
+ return FALSE
var/obj/machinery/porta_turret/P = target
if(!istype(P))
- return
+ return FALSE
P.remove_control(FALSE)
+ return TRUE
/obj/machinery/porta_turret/proc/give_control(mob/A)
if(manual_control || !can_interact(A))
diff --git a/code/game/machinery/syndicatebomb.dm b/code/game/machinery/syndicatebomb.dm
index d9b110e8c4f7..1091a289bfa4 100644
--- a/code/game/machinery/syndicatebomb.dm
+++ b/code/game/machinery/syndicatebomb.dm
@@ -415,7 +415,7 @@
reactants += G.reagents
for(var/obj/item/slime_extract/S in beakers)
- if(S.Uses)
+ if(S.extract_uses)
for(var/obj/item/reagent_containers/glass/G in beakers)
G.reagents.trans_to(S, G.reagents.total_volume)
diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index 0a11ae69da8f..d4ca6a18b1f3 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -86,8 +86,12 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb
var/max_heat_protection_temperature //Set this variable to determine up to which temperature (IN KELVIN) the item protects against heat damage. Keep at null to disable protection. Only protects areas set by heat_protection flags
var/min_cold_protection_temperature //Set this variable to determine down to which temperature (IN KELVIN) the item protects against cold damage. 0 is NOT an acceptable number due to if(varname) tests!! Keep at null to disable protection. Only protects areas set by cold_protection flags
- var/list/actions //list of /datum/action's that this item has.
- var/list/actions_types //list of paths of action datums to give to the item on New().
+ ///list of /datum/action's that this item has.
+ var/list/datum/action/actions
+ ///list of paths of action datums to give to the item on New().
+ var/list/actions_types
+ ///Slot flags in which this item grants actions. If null, defaults to the item's slot flags (so actions are granted when worn)
+ var/action_slots = null
//Since any item can now be a piece of clothing, this has to be put here so all items share it.
var/flags_inv //This flag is used to determine when items in someone's inventory cover others. IE helmets making it so you can't see glasses, etc.
@@ -185,7 +189,7 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb
. = ..()
for(var/path in actions_types)
- new path(src)
+ add_item_action(path)
actions_types = null
if(force_string)
@@ -213,8 +217,11 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb
if(ismob(loc))
var/mob/m = loc
m.temporarilyRemoveItemFromInventory(src, TRUE)
- for(var/X in actions)
- qdel(X)
+
+ // Handle cleaning up our actions list
+ for(var/datum/action/action as anything in actions)
+ remove_item_action(action)
+
return ..()
/obj/item/ComponentInitialize()
@@ -237,6 +244,50 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb
if(sharpness && force > 5) //give sharp objects butchering functionality, for consistency
AddComponent(/datum/component/butchering, 80 * toolspeed)
+/// Called when an action associated with our item is deleted
+/obj/item/proc/on_action_deleted(datum/source)
+ SIGNAL_HANDLER
+
+ if(!(source in actions))
+ CRASH("An action ([source.type]) was deleted that was associated with an item ([src]), but was not found in the item's actions list.")
+
+ LAZYREMOVE(actions, source)
+
+/// Adds an item action to our list of item actions.
+/// Item actions are actions linked to our item, that are granted to mobs who equip us.
+/// This also ensures that the actions are properly tracked in the actions list and removed if they're deleted.
+/// Can be be passed a typepath of an action or an instance of an action.
+/obj/item/proc/add_item_action(action_or_action_type)
+
+ var/datum/action/action
+ if(ispath(action_or_action_type, /datum/action))
+ action = new action_or_action_type(src)
+ else if(istype(action_or_action_type, /datum/action))
+ action = action_or_action_type
+ else
+ CRASH("item add_item_action got a type or instance of something that wasn't an action.")
+
+ LAZYADD(actions, action)
+ RegisterSignal(action, COMSIG_PARENT_QDELETING, PROC_REF(on_action_deleted))
+ grant_action_to_bearer(action)
+ return action
+
+/// Grant the action to anyone who has this item equipped to an appropriate slot
+/obj/item/proc/grant_action_to_bearer(datum/action/action)
+ if(!ismob(loc))
+ return
+ var/mob/holder = loc
+ give_item_action(action, holder, holder.get_slot_by_item(src))
+
+/// Removes an instance of an action from our list of item actions.
+/obj/item/proc/remove_item_action(datum/action/action)
+ if(!action)
+ return
+
+ UnregisterSignal(action, COMSIG_PARENT_QDELETING)
+ LAZYREMOVE(actions, action)
+ qdel(action)
+
/obj/item/proc/check_allowed_items(atom/target, not_inside, target_self)
if(((src in target) && !target_self) || (!isturf(target.loc) && !isturf(target) && not_inside))
return FALSE
@@ -567,10 +618,26 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb
. = list()
SEND_SIGNAL(src, COMSIG_ITEM_WORN_OVERLAYS, isinhands, icon_file, used_state, style_flags, .)
-//sometimes we only want to grant the item's action if it's equipped in a specific slot.
-/obj/item/proc/item_action_slot_check(slot, mob/user, datum/action/A)
- if(slot == ITEM_SLOT_BACKPACK || slot == ITEM_SLOT_LEGCUFFED) //these aren't true slots, so avoid granting actions there
+/// Gives one of our item actions to a mob, when equipped to a certain slot
+/obj/item/proc/give_item_action(datum/action/action, mob/to_who, slot)
+ // Some items only give their actions buttons when in a specific slot.
+ if(!item_action_slot_check(slot, to_who, action) || SEND_SIGNAL(src, COMSIG_ITEM_UI_ACTION_SLOT_CHECKED, to_who, action, slot) & COMPONENT_ITEM_ACTION_SLOT_INVALID)
+ // There is a chance we still have our item action currently,
+ // and are moving it from a "valid slot" to an "invalid slot".
+ // So call Remove() here regardless, even if excessive.
+ action.Remove(to_who)
+ return
+
+ action.Grant(to_who)
+
+/// Sometimes we only want to grant the item's action if it's equipped in a specific slot.
+/obj/item/proc/item_action_slot_check(slot, mob/user, datum/action/action)
+ if(slot & (ITEM_SLOT_BACKPACK|ITEM_SLOT_LEGCUFFED)) //these aren't true slots, so avoid granting actions there
return FALSE
+ if(!isnull(action_slots))
+ return (slot & action_slots)
+ else if (slot_flags)
+ return (slot & slot_flags)
return TRUE
//the mob M is attempting to equip this item into the slot passed through as 'slot'. return TRUE if it can do this and 0 if it can't.
@@ -1284,7 +1351,7 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb
*/
/obj/item/proc/update_action_buttons(status_only = FALSE, force = FALSE)
for(var/datum/action/current_action as anything in actions)
- current_action.UpdateButtons(status_only, force)
+ current_action.build_all_button_icons(status_only, force)
/// Special stuff you want to do when an outfit equips this item.
/obj/item/proc/on_outfit_equip(mob/living/carbon/human/outfit_wearer, visuals_only, item_slot)
diff --git a/code/game/objects/items/cards_ids.dm b/code/game/objects/items/cards_ids.dm
index fac44ddf5447..a88775da9abe 100644
--- a/code/game/objects/items/cards_ids.dm
+++ b/code/game/objects/items/cards_ids.dm
@@ -450,12 +450,13 @@
/obj/item/card/id/syndicate
name = "agent card"
access = list(ACCESS_MAINT_TUNNELS, ACCESS_SYNDICATE)
+ action_slots = ALL
var/anyone = FALSE //Can anyone forge the ID or just syndicate?
var/forged = FALSE //have we set a custom name and job assignment, or will we use what we're given when we chameleon change?
/obj/item/card/id/syndicate/Initialize(mapload)
. = ..()
- var/datum/action/item_action/chameleon/change/chameleon_action = new(src)
+ var/datum/action/item_action/chameleon/change/chameleon_action = add_item_action(/datum/action/item_action/chameleon/change)
chameleon_action.chameleon_type = /obj/item/card/id
chameleon_action.chameleon_name = "ID Card"
chameleon_action.initialize_disguises()
diff --git a/code/game/objects/items/defib.dm b/code/game/objects/items/defib.dm
index a154b8a638ca..8c9498a035a1 100644
--- a/code/game/objects/items/defib.dm
+++ b/code/game/objects/items/defib.dm
@@ -191,7 +191,7 @@
update_power()
for(var/X in actions)
var/datum/action/A = X
- A.UpdateButtons()
+ A.build_all_button_icons()
/obj/item/defibrillator/proc/make_paddles()
if(!combat)
diff --git a/code/game/objects/items/devices/PDA/PDA.dm b/code/game/objects/items/devices/PDA/PDA.dm
index 5cd8d8dc3f88..fde9eaf7031f 100644
--- a/code/game/objects/items/devices/PDA/PDA.dm
+++ b/code/game/objects/items/devices/PDA/PDA.dm
@@ -30,6 +30,7 @@ GLOBAL_LIST_EMPTY(PDAs)
w_class = WEIGHT_CLASS_TINY
slot_flags = ITEM_SLOT_ID | ITEM_SLOT_BELT
actions_types = list(/datum/action/item_action/toggle_light/pda)
+ action_slots = ALL
armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 100, ACID = 100)
resistance_flags = FIRE_PROOF | ACID_PROOF
diff --git a/code/game/objects/items/devices/flashlight.dm b/code/game/objects/items/devices/flashlight.dm
index 5db6aead987f..d64e8ac769c8 100644
--- a/code/game/objects/items/devices/flashlight.dm
+++ b/code/game/objects/items/devices/flashlight.dm
@@ -12,6 +12,7 @@
slot_flags = ITEM_SLOT_BELT
custom_materials = list(/datum/material/iron=50, /datum/material/glass=20)
actions_types = list(/datum/action/item_action/toggle_light)
+ action_slots = ALL
var/on = FALSE
var/brightness_on = 4 //range of light when on
var/flashlight_power = 0.8 //strength of the light when on
@@ -40,7 +41,7 @@
playsound(src, on ? 'sound/weapons/magin.ogg' : 'sound/weapons/magout.ogg', 40, TRUE)
for(var/X in actions)
var/datum/action/A = X
- A.UpdateButtons()
+ A.build_all_button_icons()
return TRUE
/obj/item/flashlight/DoRevenantThrowEffects(atom/target)
@@ -514,6 +515,10 @@
/obj/item/flashlight/glowstick/proc/activate()
if(!on)
on = TRUE
+ var/datum/action/toggle = locate(/datum/action/item_action/toggle_light) in actions
+ // No sense having a toggle light action that we don't use eh?
+ if(toggle)
+ remove_item_action(toggle)
START_PROCESSING(SSobj, src)
/obj/item/flashlight/glowstick/red
diff --git a/code/game/objects/items/devices/multitool.dm b/code/game/objects/items/devices/multitool.dm
index 577ec39486c5..af4bb94a2177 100644
--- a/code/game/objects/items/devices/multitool.dm
+++ b/code/game/objects/items/devices/multitool.dm
@@ -136,7 +136,7 @@
. = ..()
START_PROCESSING(SSobj, src)
eye = new /mob/camera/aiEye/remote/ai_detector()
- toggle_action = new /datum/action/item_action/toggle_multitool(src)
+ toggle_action = add_item_action(/datum/action/item_action/toggle_multitool)
/obj/item/multitool/ai_detect/Destroy()
STOP_PROCESSING(SSobj, src)
@@ -236,12 +236,14 @@
name = "Toggle AI detector HUD"
check_flags = NONE
-/datum/action/item_action/toggle_multitool/Trigger()
- if(!..())
+/datum/action/item_action/toggle_multitool/do_effect(trigger_flags)
+ . = ..()
+ if(!.)
+ return
+ if(!istype(target, /obj/item/multitool/ai_detect))
return FALSE
- if(target)
- var/obj/item/multitool/ai_detect/M = target
- M.toggle_hud(owner)
+ var/obj/item/multitool/ai_detect/M = target
+ M.toggle_hud(owner)
return TRUE
/obj/item/multitool/cyborg
diff --git a/code/game/objects/items/granters.dm b/code/game/objects/items/granters.dm
index 801befc9c608..cd554b70dc18 100644
--- a/code/game/objects/items/granters.dm
+++ b/code/game/objects/items/granters.dm
@@ -129,12 +129,12 @@
/datum/action/innate/drink_fling/Activate()
button_icon_state = "drinkfling_on"
active = TRUE
- UpdateButtons()
+ build_all_button_icons()
/datum/action/innate/drink_fling/Deactivate()
button_icon_state = "drinkfling_off"
active = FALSE
- UpdateButtons()
+ build_all_button_icons()
/obj/item/book/granter/action/origami
granted_action = /datum/action/innate/origami
@@ -155,13 +155,13 @@
to_chat(owner, "You will now fold origami planes.")
button_icon_state = "origami_on"
active = TRUE
- UpdateButtons()
+ build_all_button_icons()
/datum/action/innate/origami/Deactivate()
to_chat(owner, "You will no longer fold origami planes.")
button_icon_state = "origami_off"
active = FALSE
- UpdateButtons()
+ build_all_button_icons()
///SPELLS///
diff --git a/code/game/objects/items/grenades/chem_grenade.dm b/code/game/objects/items/grenades/chem_grenade.dm
index 7a834122b658..69b75c39fe60 100644
--- a/code/game/objects/items/grenades/chem_grenade.dm
+++ b/code/game/objects/items/grenades/chem_grenade.dm
@@ -220,7 +220,7 @@
return FALSE
for(var/obj/item/slime_extract/S in beakers)
- if(S.Uses)
+ if(S.extract_uses)
for(var/obj/item/reagent_containers/glass/G in beakers)
G.reagents.trans_to(S, G.reagents.total_volume)
diff --git a/code/game/objects/items/grenades/grenade.dm b/code/game/objects/items/grenades/grenade.dm
index a7d55fa2e456..ebd0f371e791 100644
--- a/code/game/objects/items/grenades/grenade.dm
+++ b/code/game/objects/items/grenades/grenade.dm
@@ -11,6 +11,7 @@
throw_range = 7
flags_1 = CONDUCT_1
slot_flags = ITEM_SLOT_BELT
+ action_slots = ALL
resistance_flags = FLAMMABLE
max_integrity = 40
var/active = 0
diff --git a/code/game/objects/items/implants/implant_mindshield.dm b/code/game/objects/items/implants/implant_mindshield.dm
index 14a49c1a00f3..0b2f9ae77f19 100644
--- a/code/game/objects/items/implants/implant_mindshield.dm
+++ b/code/game/objects/items/implants/implant_mindshield.dm
@@ -1,6 +1,7 @@
/obj/item/implant/mindshield
name = "mindshield implant"
desc = "Protects against brainwashing."
+ actions_types = null
activated = 0
/obj/item/implant/mindshield/get_data()
diff --git a/code/game/objects/items/melee/misc.dm b/code/game/objects/items/melee/misc.dm
index 5d57c9ee69c0..375ced916f7d 100644
--- a/code/game/objects/items/melee/misc.dm
+++ b/code/game/objects/items/melee/misc.dm
@@ -16,6 +16,7 @@
righthand_file = 'icons/mob/inhands/weapons/melee_righthand.dmi'
flags_1 = CONDUCT_1
slot_flags = ITEM_SLOT_BELT
+ action_slots = ALL
force = 14
throwforce = 10
wound_bonus = 15
diff --git a/code/game/objects/items/robot/robot_upgrades.dm b/code/game/objects/items/robot/robot_upgrades.dm
index b4917c2500c2..b3b7b373f546 100644
--- a/code/game/objects/items/robot/robot_upgrades.dm
+++ b/code/game/objects/items/robot/robot_upgrades.dm
@@ -355,7 +355,7 @@
return FALSE
icon_state = "selfrepair_off"
- toggle_action = new /datum/action/item_action/toggle(src)
+ toggle_action = add_item_action(/datum/action/item_action/toggle)
toggle_action.Grant(R)
/obj/item/borg/upgrade/selfrepair/deactivate(mob/living/silicon/robot/R, user = usr)
@@ -705,7 +705,7 @@
/obj/effect/proc_holder/silicon/cyborg/vtecControl
name = "vTec Control"
desc = "Allows finer-grained control of the vTec speed boost."
- action_icon = 'icons/mob/actions.dmi'
+ action_icon = 'icons/hud/actions.dmi'
action_icon_state = "Chevron_State_0"
var/currentState = 0
@@ -725,6 +725,6 @@
user.vtec = initial(user.vtec) - maxReduction * 1
action.button_icon_state = "Chevron_State_[currentState]"
- action.UpdateButtons()
+ action.build_all_button_icons()
return TRUE
diff --git a/code/game/objects/items/storage/_storage.dm b/code/game/objects/items/storage/_storage.dm
index cbaa1775eb0d..145983e0ad1a 100644
--- a/code/game/objects/items/storage/_storage.dm
+++ b/code/game/objects/items/storage/_storage.dm
@@ -3,6 +3,7 @@
name = "storage"
icon = 'icons/obj/storage.dmi'
w_class = WEIGHT_CLASS_NORMAL
+ action_slots = ALL
var/component_type = /datum/component/storage/concrete
/obj/item/storage/get_dumping_location(obj/item/storage/source,mob/user)
diff --git a/code/game/objects/items/tanks/jetpack.dm b/code/game/objects/items/tanks/jetpack.dm
index a091993ff1aa..a8979729bcc4 100644
--- a/code/game/objects/items/tanks/jetpack.dm
+++ b/code/game/objects/items/tanks/jetpack.dm
@@ -50,7 +50,7 @@
to_chat(user, "You turn the jetpack off.")
for(var/X in actions)
var/datum/action/A = X
- A.UpdateButtons()
+ A.build_all_button_icons()
/obj/item/tank/jetpack/proc/turn_on(mob/user)
on = TRUE
diff --git a/code/game/objects/items/tanks/tanks.dm b/code/game/objects/items/tanks/tanks.dm
index 0380c2d5acf1..4f6dce99705f 100644
--- a/code/game/objects/items/tanks/tanks.dm
+++ b/code/game/objects/items/tanks/tanks.dm
@@ -15,6 +15,7 @@
throw_range = 4
custom_materials = list(/datum/material/iron = 500)
actions_types = list(/datum/action/item_action/set_internals)
+ action_slots = ALL
armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 10, BIO = 0, RAD = 0, FIRE = 80, ACID = 30)
var/datum/gas_mixture/air_contents = null
var/distribute_pressure = ONE_ATMOSPHERE
@@ -59,7 +60,7 @@
else
to_chat(H, "You open [src] valve.")
H.internal = src
- H.update_action_buttons_icon()
+ H.update_mob_action_buttons()
/obj/item/tank/Initialize(mapload)
diff --git a/code/game/objects/structures/bedsheet_bin.dm b/code/game/objects/structures/bedsheet_bin.dm
index 2c3b0545f81b..52e3bb8bc9f5 100644
--- a/code/game/objects/structures/bedsheet_bin.dm
+++ b/code/game/objects/structures/bedsheet_bin.dm
@@ -467,7 +467,7 @@ GLOBAL_LIST_INIT(double_bedsheets, list(/obj/item/bedsheet/double,
/obj/item/bedsheet/chameleon/New()
..()
- chameleon_action = new(src)
+ chameleon_action = add_item_action(/datum/action/item_action/chameleon/change)
chameleon_action.chameleon_type = /obj/item/bedsheet
chameleon_action.chameleon_name = "Bedsheet"
chameleon_action.chameleon_blacklist = typecacheof(list(/obj/item/bedsheet/chameleon, /obj/item/bedsheet/random, /obj/item/bedsheet/unlockable), only_root_path = FALSE)
diff --git a/code/game/objects/structures/ghost_role_spawners.dm b/code/game/objects/structures/ghost_role_spawners.dm
index c8fea2de4a66..2d8a8eb3b131 100644
--- a/code/game/objects/structures/ghost_role_spawners.dm
+++ b/code/game/objects/structures/ghost_role_spawners.dm
@@ -113,7 +113,7 @@
to_chat(new_spawn, "You can expand the weather proof area provided by your shelters by using the 'New Area' key near the bottom right of your HUD.")
to_chat(new_spawn, "Dragging injured ashwalkers to the tentacle or using the sleep verb next to it youself causes the body to remade whole after a short delay!")
else
- to_chat(new_spawn, "You have been born outside of your natural home! Whether you decide to return home, or make due with your new home is your own decision.")
+ to_chat(new_spawn, span_userdanger("You have been born outside of your natural home! Whether you decide to return home, or make due with your new home is your own decision."))
//Ash walkers on birth understand how to make bone bows, bone arrows and ashen arrows
@@ -247,7 +247,7 @@
if(transfer_choice != "Yes" || QDELETED(src) || uses <= 0 || !user.canUseTopic(src, BE_CLOSE, NO_DEXTERY, NO_TK))
return
log_game("[key_name(user)] golem-swapped into [src]")
- user.visible_message("A faint light leaves [user], moving to [src] and animating it!","You leave your old body behind, and transfer into [src]!")
+ user.visible_message(span_notice("A faint light leaves [user], moving to [src] and animating it!"),span_notice("You leave your old body behind, and transfer into [src]!"))
show_flavour = FALSE
create(ckey = user.ckey,name = user.real_name)
user.death()
@@ -477,7 +477,7 @@
id.registered_name = L.real_name
id.update_label()
else
- to_chat(L, "Your owner is already dead! You will soon perish.")
+ to_chat(L, span_userdanger("Your owner is already dead! You will soon perish."))
addtimer(CALLBACK(L, TYPE_PROC_REF(/mob, dust), 150)) //Give em a few seconds as a mercy.
/datum/outfit/demonic_friend
@@ -666,24 +666,24 @@
if(.)
return
if(user.mind.has_antag_datum(/datum/antagonist/pirate))
- to_chat(user, "Your shipmate sails within their dreams for now. Perhaps they may wake up eventually.")
+ to_chat(user, span_notice("Your shipmate sails within their dreams for now. Perhaps they may wake up eventually."))
else
- to_chat(user, "If you want to kill the pirate off, something to pry open the sleeper might be the best way to do it.")
+ to_chat(user, span_notice("If you want to kill the pirate off, something to pry open the sleeper might be the best way to do it."))
/obj/effect/mob_spawn/human/pirate/attackby(obj/item/W, mob/user, params)
if(W.tool_behaviour == TOOL_CROWBAR && user.a_intent != INTENT_HARM)
if(user.mind.has_antag_datum(/datum/antagonist/pirate))
- to_chat(user,"Why would you want to do that to your shipmate? That'd kill them.")
+ to_chat(user,span_warning("Why would you want to do that to your shipmate? That'd kill them."))
return
- user.visible_message("[user] start to pry open [src]...",
- "You start to pry open [src]...",
- "You hear prying...")
+ user.visible_message(span_warning("[user] start to pry open [src]..."),
+ span_notice("You start to pry open [src]..."),
+ span_italics("You hear prying..."))
W.play_tool_sound(src)
if(do_after(user, 100*W.toolspeed, target = src))
- user.visible_message("[user] pries open [src], disrupting the sleep of the pirate within and killing them.",
- "You pry open [src], disrupting the sleep of the pirate within and killing them.",
- "You hear prying, followed by the death rattling of bones.")
+ user.visible_message(span_warning("[user] pries open [src], disrupting the sleep of the pirate within and killing them."),
+ span_notice("You pry open [src], disrupting the sleep of the pirate within and killing them."),
+ span_italics("You hear prying, followed by the death rattling of bones."))
log_game("[key_name(user)] has successfully pried open [src] and disabled a space pirate spawner.")
W.play_tool_sound(src)
playsound(src.loc, 'modular_citadel/sound/voice/scream_skeleton.ogg', 50, 1, 4, 1.2)
@@ -746,27 +746,28 @@
banType = ROLE_GHOSTCAFE
/datum/action/toggle_dead_chat_mob
- icon_icon = 'icons/mob/mob.dmi'
+ button_icon = 'icons/mob/mob.dmi'
button_icon_state = "ghost"
name = "Toggle deadchat"
desc = "Turn off or on your ability to hear ghosts."
-/datum/action/toggle_dead_chat_mob/Trigger()
- if(!..())
+/datum/action/toggle_dead_chat_mob/Trigger(trigger_flags)
+ . = ..()
+ if(!.)
return FALSE
var/mob/M = target
if(HAS_TRAIT_FROM(M,TRAIT_SIXTHSENSE,GHOSTROLE_TRAIT))
REMOVE_TRAIT(M,TRAIT_SIXTHSENSE,GHOSTROLE_TRAIT)
- to_chat(M,"You're no longer hearing deadchat.")
+ to_chat(M,span_notice("You're no longer hearing deadchat."))
else
ADD_TRAIT(M,TRAIT_SIXTHSENSE,GHOSTROLE_TRAIT)
- to_chat(M,"You're once again longer hearing deadchat.")
-
+ to_chat(M,span_notice("You're once again longer hearing deadchat."))
+ return TRUE
/datum/action/disguise
name = "Disguise"
button_icon_state = "ling_transform"
- icon_icon = 'icons/mob/actions/actions_changeling.dmi'
+ button_icon = 'icons/mob/actions/actions_changeling.dmi'
background_icon_state = "bg_mime"
var/currently_disguised = FALSE
var/static/list/mob_blacklist = typecacheof(list(
@@ -798,36 +799,44 @@
))
-/datum/action/disguise/Trigger()
+/datum/action/disguise/Trigger(trigger_flags)
+ . = ..()
+ if(!.)
+ return FALSE
var/mob/living/carbon/human/H = owner
- if(!currently_disguised)
- var/user_object_type = input(H, "Disguising as OBJECT or MOB?") as null|anything in list("OBJECT", "MOB")
- if(user_object_type)
- var/search_term = stripped_input(H, "Enter the search term")
- if(search_term)
- var/list_to_search
- if(user_object_type == "MOB")
- list_to_search = subtypesof(/mob) - mob_blacklist
- else
- list_to_search = subtypesof(/obj)
- var/list/filtered_results = list()
- for(var/some_search_item in list_to_search)
- if(findtext("[some_search_item]", search_term))
- filtered_results += some_search_item
- if(!length(filtered_results))
- to_chat(H, "Nothing matched your search query!")
- else
- var/disguise_selection = input("Select item to disguise as") as null|anything in filtered_results
- if(disguise_selection)
- var/atom/disguise_item = disguise_selection
- var/image/I = image(icon = initial(disguise_item.icon), icon_state = initial(disguise_item.icon_state), loc = H)
- I.override = TRUE
- I.layer = ABOVE_MOB_LAYER
- H.add_alt_appearance(/datum/atom_hud/alternate_appearance/basic/everyone, "ghost_cafe_disguise", I)
- currently_disguised = TRUE
- else
+ if(currently_disguised)
H.remove_alt_appearance("ghost_cafe_disguise")
currently_disguised = FALSE
+ return TRUE
+ else
+ var/user_object_type = input(H, "Disguising as OBJECT or MOB?") as null|anything in list("OBJECT", "MOB")
+ if(!user_object_type)
+ return FALSE
+ var/search_term = stripped_input(H, "Enter the search term")
+ if(!search_term)
+ return FALSE
+ var/list_to_search
+ if(user_object_type == "MOB")
+ list_to_search = subtypesof(/mob) - mob_blacklist
+ else
+ list_to_search = subtypesof(/obj)
+ var/list/filtered_results = list()
+ for(var/some_search_item in list_to_search)
+ if(findtext("[some_search_item]", search_term))
+ filtered_results += some_search_item
+ if(!length(filtered_results))
+ to_chat(H, "Nothing matched your search query!")
+ return FALSE
+ var/disguise_selection = input("Select item to disguise as") as null|anything in filtered_results
+ if(!disguise_selection)
+ return FALSE
+ var/atom/disguise_item = disguise_selection
+ var/image/I = image(icon = initial(disguise_item.icon), icon_state = initial(disguise_item.icon_state), loc = H)
+ I.override = TRUE
+ I.layer = ABOVE_MOB_LAYER
+ H.add_alt_appearance(/datum/atom_hud/alternate_appearance/basic/everyone, "ghost_cafe_disguise", I)
+ currently_disguised = TRUE
+ return TRUE
/obj/effect/mob_spawn/human/ghostcafe/special(mob/living/carbon/human/new_spawn)
if(new_spawn.client)
@@ -844,7 +853,7 @@
ADD_TRAIT(new_spawn, TRAIT_SIXTHSENSE, GHOSTROLE_TRAIT)
ADD_TRAIT(new_spawn, TRAIT_EXEMPT_HEALTH_EVENTS, GHOSTROLE_TRAIT)
ADD_TRAIT(new_spawn, TRAIT_NO_MIDROUND_ANTAG, GHOSTROLE_TRAIT) //The mob can't be made into a random antag, they are still eligible for ghost roles popups.
- to_chat(new_spawn,"Ghosting is free!")
+ to_chat(new_spawn,span_boldwarning("Ghosting is free!"))
var/datum/action/toggle_dead_chat_mob/D = new(new_spawn)
D.Grant(new_spawn)
var/datum/action/disguise/disguise_action = new(new_spawn)
diff --git a/code/modules/VR/vr_mob.dm b/code/modules/VR/vr_mob.dm
index 5f2caffc76da..97e3c8fed7df 100644
--- a/code/modules/VR/vr_mob.dm
+++ b/code/modules/VR/vr_mob.dm
@@ -35,10 +35,10 @@
/datum/action/quit_vr
name = "Quit Virtual Reality"
- icon_icon = 'icons/mob/actions/actions_vr.dmi'
+ button_icon = 'icons/mob/actions/actions_vr.dmi'
button_icon_state = "logout"
-/datum/action/quit_vr/Trigger() //this merely a trigger for /datum/component/virtual_reality
+/datum/action/quit_vr/Trigger(trigger_flags) //this merely a trigger for /datum/component/virtual_reality
. = ..()
if(.) //The component was not there to block the trigger.
Remove(owner)
diff --git a/code/modules/antagonists/_common/antag_datum.dm b/code/modules/antagonists/_common/antag_datum.dm
index 9f3556dbb6f0..7b2c08043964 100644
--- a/code/modules/antagonists/_common/antag_datum.dm
+++ b/code/modules/antagonists/_common/antag_datum.dm
@@ -523,11 +523,16 @@ GLOBAL_LIST_EMPTY(antagonists)
src.antag_datum = antag_datum
name += " [antag_datum.name]"
-/datum/action/antag_info/Trigger()
- if(antag_datum)
- antag_datum.ui_interact(owner)
+/datum/action/antag_info/Trigger(trigger_flags)
+ . = ..()
+ if(!.)
+ return FALSE
+ if(!antag_datum)
+ return FALSE
+ antag_datum.ui_interact(owner)
+ return TRUE
-/datum/action/antag_info/IsAvailable()
+/datum/action/antag_info/IsAvailable(feedback)
return TRUE
///Clears change requests from deleted objectives to avoid broken references.
diff --git a/code/modules/antagonists/abductor/equipment/abduction_gear.dm b/code/modules/antagonists/abductor/equipment/abduction_gear.dm
index 7506ae897504..e00042bedd69 100644
--- a/code/modules/antagonists/abductor/equipment/abduction_gear.dm
+++ b/code/modules/antagonists/abductor/equipment/abduction_gear.dm
@@ -59,7 +59,7 @@
H.update_inv_wear_suit()
for(var/X in actions)
var/datum/action/A = X
- A.UpdateButtons()
+ A.build_all_button_icons()
/obj/item/clothing/suit/armor/abductor/vest/item_action_slot_check(slot, mob/user, datum/action/A)
if(slot == ITEM_SLOT_OCLOTHING) //we only give the mob the ability to activate the vest if he's actually wearing it.
@@ -441,6 +441,7 @@
force = 7
w_class = WEIGHT_CLASS_NORMAL
actions_types = list(/datum/action/item_action/toggle_mode)
+ action_slots = ALL
/obj/item/abductor/baton/ComponentInitialize()
. = ..()
diff --git a/code/modules/antagonists/abductor/machinery/camera.dm b/code/modules/antagonists/abductor/machinery/camera.dm
index 4fb6bf56459c..6f7a10664a06 100644
--- a/code/modules/antagonists/abductor/machinery/camera.dm
+++ b/code/modules/antagonists/abductor/machinery/camera.dm
@@ -24,7 +24,7 @@
/obj/machinery/computer/camera_advanced/abductor/Initialize(mapload)
. = ..()
-
+
if(tele_in_action)
actions += new tele_in_action(src)
if(tele_out_action)
@@ -43,7 +43,7 @@
/datum/action/innate/teleport_in
name = "Send To"
- icon_icon = 'icons/mob/actions/actions_minor_antag.dmi'
+ button_icon = 'icons/mob/actions/actions_minor_antag.dmi'
button_icon_state = "beam_down"
/datum/action/innate/teleport_in/Activate()
@@ -57,7 +57,7 @@
/datum/action/innate/teleport_out
name = "Retrieve"
- icon_icon = 'icons/mob/actions/actions_minor_antag.dmi'
+ button_icon = 'icons/mob/actions/actions_minor_antag.dmi'
button_icon_state = "beam_up"
/datum/action/innate/teleport_out/Activate()
@@ -69,7 +69,7 @@
/datum/action/innate/teleport_self
name = "Send Self"
- icon_icon = 'icons/mob/actions/actions_minor_antag.dmi'
+ button_icon = 'icons/mob/actions/actions_minor_antag.dmi'
button_icon_state = "beam_down"
/datum/action/innate/teleport_self/Activate()
@@ -83,7 +83,7 @@
/datum/action/innate/vest_mode_swap
name = "Switch Vest Mode"
- icon_icon = 'icons/mob/actions/actions_minor_antag.dmi'
+ button_icon = 'icons/mob/actions/actions_minor_antag.dmi'
button_icon_state = "vest_mode"
/datum/action/innate/vest_mode_swap/Activate()
@@ -95,7 +95,7 @@
/datum/action/innate/vest_disguise_swap
name = "Switch Vest Disguise"
- icon_icon = 'icons/mob/actions/actions_minor_antag.dmi'
+ button_icon = 'icons/mob/actions/actions_minor_antag.dmi'
button_icon_state = "vest_disguise"
/datum/action/innate/vest_disguise_swap/Activate()
@@ -106,7 +106,7 @@
/datum/action/innate/set_droppoint
name = "Set Experiment Release Point"
- icon_icon = 'icons/mob/actions/actions_minor_antag.dmi'
+ button_icon = 'icons/mob/actions/actions_minor_antag.dmi'
button_icon_state = "set_drop"
/datum/action/innate/set_droppoint/Activate()
diff --git a/code/modules/antagonists/blob/blob.dm b/code/modules/antagonists/blob/blob.dm
index c449bd301220..c5e659dfbca5 100644
--- a/code/modules/antagonists/blob/blob.dm
+++ b/code/modules/antagonists/blob/blob.dm
@@ -51,7 +51,7 @@
/datum/action/innate/blobpop
name = "Pop"
desc = "Unleash the blob"
- icon_icon = 'icons/mob/blob.dmi'
+ button_icon = 'icons/mob/blob.dmi'
button_icon_state = "blob"
/datum/action/innate/blobpop/Activate()
diff --git a/code/modules/antagonists/bloodsucker/bloodsucker_powers.dm b/code/modules/antagonists/bloodsucker/bloodsucker_powers.dm
index dc16ecef1e23..9cb68f70669b 100644
--- a/code/modules/antagonists/bloodsucker/bloodsucker_powers.dm
+++ b/code/modules/antagonists/bloodsucker/bloodsucker_powers.dm
@@ -3,7 +3,7 @@
desc = "A vampiric gift."
button_icon = 'icons/mob/actions/bloodsucker.dmi' //This is the file for the BACKGROUND icon
background_icon_state = "vamp_power_off" //And this is the state for the background icon
- icon_icon = 'icons/mob/actions/bloodsucker.dmi' //This is the file for the ACTION icon
+ button_icon = 'icons/mob/actions/bloodsucker.dmi' //This is the file for the ACTION icon
button_icon_state = "power_feed" //And this is the state for the action icon
buttontooltipstyle = "cult"
transparent_when_unavailable = TRUE
@@ -51,17 +51,17 @@
// spells.dm /add_ranged_ability() <--- How we take over the mouse click to use a power on a target.
// TODO: Refactor this to use /Activate().
-/datum/action/cooldown/bloodsucker/Trigger()
+/datum/action/cooldown/bloodsucker/Trigger(trigger_flags)
// Active? DEACTIVATE AND END!
if(active && CheckCanDeactivate(TRUE))
DeactivatePower()
- return
+ return FALSE
if(!CheckCanPayCost(TRUE) || !CheckCanUse(TRUE))
- return
+ return FALSE
PayCost()
if(amToggle)
active = !active
- UpdateButtons()
+ build_all_button_icons()
if(!amToggle || !active)
StartCooldown() // Must come AFTER UpdateButton(), otherwise icon will revert.
ActivatePower() // NOTE: ActivatePower() freezes this power in place until it ends.
@@ -69,6 +69,7 @@
DeactivatePower()
if(amSingleUse)
RemoveAfterUse()
+ return TRUE
/datum/action/cooldown/bloodsucker/proc/CheckCanPayCost(display_error)
if(!owner || !owner.mind)
@@ -82,7 +83,7 @@
var/mob/living/L = owner
if(L.blood_volume < bloodcost)
if(display_error)
- to_chat(owner, "You need at least [bloodcost] blood to activate [name]")
+ to_chat(owner, span_warning("You need at least [bloodcost] blood to activate [name]"))
return FALSE
return TRUE
@@ -92,12 +93,12 @@
// Torpor?
if(!can_use_in_torpor && HAS_TRAIT(owner, TRAIT_DEATHCOMA))
if(display_error)
- to_chat(owner, "Not while you're in Torpor.")
+ to_chat(owner, span_warning("Not while you're in Torpor."))
return FALSE
// Stake?
if(!can_be_staked && owner.AmStaked())
if(display_error)
- to_chat(owner, "You have a stake in your chest! Your powers are useless.")
+ to_chat(owner, span_warning("You have a stake in your chest! Your powers are useless."))
return FALSE
if(istype(owner.get_item_by_slot(ITEM_SLOT_NECK), /obj/item/clothing/neck/garlic_necklace))
if(display_error)
@@ -105,35 +106,36 @@
return FALSE
if(owner.reagents?.has_reagent(/datum/reagent/consumable/garlic))
if(display_error)
- to_chat(owner, "Garlic in your blood is interfering with your powers!")
+ to_chat(owner, span_warning("Garlic in your blood is interfering with your powers!"))
return FALSE
if(must_be_concious)
if(owner.stat != CONSCIOUS)
if(display_error)
- to_chat(owner, "You can't do this while you are unconcious!")
+ to_chat(owner, span_warning("You can't do this while you are unconcious!"))
return FALSE
// Incap?
if(must_be_capacitated)
var/mob/living/L = owner
if (L.incapacitated(TRUE, TRUE) || !CHECK_MOBILITY(L, MOBILITY_STAND) && !can_be_immobilized)
if(display_error)
- to_chat(owner, "Not while you're incapacitated!")
+ to_chat(owner, span_warning("Not while you're incapacitated!"))
return FALSE
// Constant Cost (out of blood)
if(warn_constant_cost)
var/mob/living/L = owner
if(L.blood_volume <= 0)
if(display_error)
- to_chat(owner, "You don't have the blood to upkeep [src].")
+ to_chat(owner, span_warning("You don't have the blood to upkeep [src]."))
return FALSE
return TRUE
/datum/action/cooldown/bloodsucker/proc/CheckCanDeactivate(display_error)
return TRUE
-/datum/action/cooldown/bloodsucker/UpdateButton(atom/movable/screen/movable/action_button/button, status_only = FALSE, force = FALSE)
- background_icon_state = active? background_icon_state_on : background_icon_state_off
- ..()//UpdateButton()
+/datum/action/cooldown/bloodsucker/apply_button_background(atom/movable/screen/movable/action_button/current_button, force)
+ if(active_background_icon_state)
+ background_icon_state = is_action_active(current_button) ? active_background_icon_state : base_background_icon_state
+ return ..()
/datum/action/cooldown/bloodsucker/proc/PayCost()
// owner for actions is the mob, not mind.
@@ -146,7 +148,7 @@
/datum/action/cooldown/bloodsucker/proc/DeactivatePower(mob/living/user = owner, mob/living/target)
active = FALSE
- UpdateButtons()
+ build_all_button_icons()
StartCooldown()
/datum/action/cooldown/bloodsucker/proc/ContinueActive(mob/living/user, mob/living/target) // Used by loops to make sure this power can stay active.
@@ -182,15 +184,15 @@
// TODO: Refactor this to use /Activate() and click_to_activate = TRUE.
// Click power: Begin Aim
-/datum/action/cooldown/bloodsucker/targeted/Trigger()
+/datum/action/cooldown/bloodsucker/targeted/Trigger(trigger_flags)
if(active && CheckCanDeactivate(TRUE))
DeactivateRangedAbility()
DeactivatePower()
- return
+ return FALSE
if(!CheckCanPayCost(TRUE) || !CheckCanUse(TRUE))
- return
+ return FALSE
active = !active
- UpdateButtons()
+ build_all_button_icons()
// Create & Link Targeting Proc
var/mob/living/L = owner
if(L.ranged_ability)
@@ -198,7 +200,8 @@
bs_proc_holder.add_ranged_ability(L)
if(message_Trigger != "")
- to_chat(owner, "[message_Trigger]")
+ to_chat(owner, span_announce("[message_Trigger]"))
+ return TRUE
/datum/action/cooldown/bloodsucker/targeted/CheckCanUse(display_error)
. = ..()
@@ -211,7 +214,7 @@
/datum/action/cooldown/bloodsucker/targeted/DeactivatePower(mob/living/user = owner, mob/living/target)
// Don't run ..(), we don't want to engage the cooldown until we USE this power!
active = FALSE
- UpdateButtons()
+ build_all_button_icons()
/datum/action/cooldown/bloodsucker/targeted/proc/DeactivateRangedAbility()
// Only Turned off when CLICK is disabled...aka, when you successfully clicked (or
@@ -226,7 +229,7 @@
// Out of Range
if(!(A in view(target_range, owner)))
if(display_error && target_range > 1) // Only warn for range if it's greater than 1. Brawn doesn't need to announce itself.
- to_chat(owner, "Your target is out of range.")
+ to_chat(owner, span_warning("Your target is out of range."))
return FALSE
return istype(A)
diff --git a/code/modules/antagonists/bloodsucker/datum_hunter.dm b/code/modules/antagonists/bloodsucker/datum_hunter.dm
index 9c862fe42a3d..bb3505233d1f 100644
--- a/code/modules/antagonists/bloodsucker/datum_hunter.dm
+++ b/code/modules/antagonists/bloodsucker/datum_hunter.dm
@@ -171,7 +171,7 @@
desc = "Take a moment to look for clues of any nearby monsters.
These creatures are slippery, and often look like the crew."
button_icon = 'icons/mob/actions/bloodsucker.dmi' //This is the file for the BACKGROUND icon
background_icon_state = "vamp_power_off" //And this is the state for the background icon
- icon_icon = 'icons/mob/actions/bloodsucker.dmi' //This is the file for the ACTION icon
+ button_icon = 'icons/mob/actions/bloodsucker.dmi' //This is the file for the ACTION icon
button_icon_state = "power_hunter" //And this is the state for the action icon
amToggle = FALSE // Action-Related
cooldown = 300 // 10 ticks, 1 second.
diff --git a/code/modules/antagonists/changeling/cellular_emporium.dm b/code/modules/antagonists/changeling/cellular_emporium.dm
index 3e48fca317d9..e50fa0cf449e 100644
--- a/code/modules/antagonists/changeling/cellular_emporium.dm
+++ b/code/modules/antagonists/changeling/cellular_emporium.dm
@@ -73,7 +73,7 @@
/datum/action/innate/cellular_emporium
name = "Cellular Emporium"
- icon_icon = 'icons/obj/drinks.dmi'
+ button_icon = 'icons/obj/drinks.dmi'
button_icon_state = "changelingsting"
background_icon_state = "bg_changeling"
var/datum/cellular_emporium/cellular_emporium
diff --git a/code/modules/antagonists/changeling/changeling_power.dm b/code/modules/antagonists/changeling/changeling_power.dm
index 8f481285620e..3a7165c020f9 100644
--- a/code/modules/antagonists/changeling/changeling_power.dm
+++ b/code/modules/antagonists/changeling/changeling_power.dm
@@ -5,7 +5,7 @@
/datum/action/changeling
name = "Prototype Sting - Debug button, ahelp this"
background_icon_state = "bg_changeling"
- icon_icon = 'icons/mob/actions/actions_changeling.dmi'
+ button_icon = 'icons/mob/actions/actions_changeling.dmi'
var/needs_button = TRUE//for passive abilities like hivemind that dont need a button
var/helptext = "" // Details
var/chemical_cost = 0 // negative chemical cost is for passive abilities (chemical glands)
@@ -30,11 +30,12 @@ the same goes for Remove(). if you override Remove(), call parent or else your p
if(needs_button)
Grant(user)//how powers are added rather than the checks in mob.dm
-/datum/action/changeling/Trigger()
+/datum/action/changeling/Trigger(trigger_flags)
var/mob/user = owner
if(!user || !user.mind || !user.mind.has_antag_datum(/datum/antagonist/changeling))
- return
+ return FALSE
try_to_sting(user)
+ return TRUE
/datum/action/changeling/proc/try_to_sting(mob/user, mob/target)
if(!can_sting(user, target))
diff --git a/code/modules/antagonists/changeling/powers/fakedeath.dm b/code/modules/antagonists/changeling/powers/fakedeath.dm
index 8bbbc423a11a..d2cc99b1a869 100644
--- a/code/modules/antagonists/changeling/powers/fakedeath.dm
+++ b/code/modules/antagonists/changeling/powers/fakedeath.dm
@@ -44,7 +44,7 @@
name = "Reviving Stasis"
desc = "We fall into a stasis, allowing us to regenerate and trick our enemies. Costs 15 chemicals."
button_icon_state = "fake_death"
- UpdateButtons()
+ build_all_button_icons()
chemical_cost = 15
to_chat(user, "We have revived ourselves.")
@@ -56,7 +56,7 @@
name = "Revive"
desc = "We arise once more."
button_icon_state = "revive"
- UpdateButtons()
+ build_all_button_icons()
chemical_cost = 0
revive_ready = TRUE
diff --git a/code/modules/antagonists/changeling/powers/pheromone_receptors.dm b/code/modules/antagonists/changeling/powers/pheromone_receptors.dm
index 9d7eb8744d76..57e3a6b716da 100644
--- a/code/modules/antagonists/changeling/powers/pheromone_receptors.dm
+++ b/code/modules/antagonists/changeling/powers/pheromone_receptors.dm
@@ -7,7 +7,7 @@
name = "Pheromone Receptors"
desc = "We attune our senses to track other changelings by scent. The closer they are, the easier we can find them."
helptext = "We will know the general direction of nearby changelings, with closer scents being stronger. Our chemical generation is slowed while this is active."
- icon_icon = 'icons/mob/actions/actions_spells.dmi'
+ button_icon = 'icons/mob/actions/actions_spells.dmi'
button_icon_state = "nose"
chemical_cost = 0 //Reduces regain rate while active.
dna_cost = 2
diff --git a/code/modules/antagonists/changeling/powers/tiny_prick.dm b/code/modules/antagonists/changeling/powers/tiny_prick.dm
index 514d6ed6f680..489d7616affc 100644
--- a/code/modules/antagonists/changeling/powers/tiny_prick.dm
+++ b/code/modules/antagonists/changeling/powers/tiny_prick.dm
@@ -3,21 +3,21 @@
desc = "Stabby stabby"
var/sting_icon = null
-/datum/action/changeling/sting/Trigger()
+/datum/action/changeling/sting/Trigger(trigger_flags)
var/mob/user = owner
if(!user || !user.mind)
- return
+ return FALSE
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
if(!changeling)
- return
+ return FALSE
if(!changeling.chosen_sting)
set_sting(user)
else
unset_sting(user)
- return
+ return TRUE
/datum/action/changeling/sting/proc/set_sting(mob/user)
- to_chat(user, "We prepare our sting, use Alt+click or click the middle mouse button on a target to sting them.")
+ to_chat(user, span_notice("We prepare our sting, use Alt+click or click the middle mouse button on a target to sting them."))
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
changeling.chosen_sting = src
@@ -25,7 +25,7 @@
user.hud_used.lingstingdisplay.invisibility = 0
/datum/action/changeling/sting/proc/unset_sting(mob/user)
- to_chat(user, "We retract our sting, we can't sting anyone for now.")
+ to_chat(user, span_warning("We retract our sting, we can't sting anyone for now."))
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
changeling.chosen_sting = null
@@ -58,9 +58,9 @@
/datum/action/changeling/sting/sting_feedback(mob/user, mob/target)
if(!target)
return
- to_chat(user, "We stealthily sting [target.name].")
+ to_chat(user, span_notice("We stealthily sting [target.name]."))
if(target.mind && target.mind.has_antag_datum(/datum/antagonist/changeling))
- to_chat(target, "You feel a tiny prick.")
+ to_chat(target, span_warning("You feel a tiny prick."))
return TRUE
@@ -75,31 +75,31 @@
loudness = 1
var/datum/changelingprofile/selected_dna = null
-/datum/action/changeling/sting/transformation/Trigger()
+/datum/action/changeling/sting/transformation/Trigger(trigger_flags)
var/mob/user = owner
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
if(changeling.chosen_sting)
unset_sting(user)
- return
+ return FALSE
selected_dna = changeling.select_dna()
if(!selected_dna)
- return
+ return FALSE
if(NOTRANSSTING in selected_dna.dna.species.species_traits)
- to_chat(user, "That DNA is not compatible with changeling retrovirus!")
- return
- ..()
+ to_chat(user, span_notice("That DNA is not compatible with changeling retrovirus!"))
+ return FALSE
+ return ..()
/datum/action/changeling/sting/transformation/can_sting(mob/user, mob/living/carbon/target)
if(!..())
return
if((HAS_TRAIT(target, TRAIT_HUSK)) || !iscarbon(target) || (NOTRANSSTING in target.dna.species.species_traits))
- to_chat(user, "Our sting appears ineffective against its DNA.")
+ to_chat(user, span_warning("Our sting appears ineffective against its DNA."))
return FALSE
return TRUE
/datum/action/changeling/sting/transformation/sting_action(mob/user, mob/target)
if(ismonkey(target))
- to_chat(user, "Our genes cry out as we sting [target.name]!")
+ to_chat(user, span_notice("Our genes cry out as we sting [target.name]!"))
var/mob/living/carbon/C = target
. = TRUE
@@ -132,7 +132,7 @@
if(isliving(target))
var/mob/living/L = target
if((HAS_TRAIT(L, TRAIT_HUSK)) || !L.has_dna())
- to_chat(user, "Our sting appears ineffective against its DNA.")
+ to_chat(user, span_warning("Our sting appears ineffective against its DNA."))
return FALSE
return TRUE
@@ -141,15 +141,15 @@
var/obj/item/held = target.get_active_held_item()
if(held && !target.dropItemToGround(held))
- to_chat(user, "[held] is stuck to [target.p_their()] hand, you cannot grow a false armblade over it!")
+ to_chat(user, span_warning("[held] is stuck to [target.p_their()] hand, you cannot grow a false armblade over it!"))
return
if(ismonkey(target))
- to_chat(user, "Our genes cry out as we sting [target.name]!")
+ to_chat(user, span_notice("Our genes cry out as we sting [target.name]!"))
var/obj/item/melee/arm_blade/false/blade = new(target,1)
target.put_in_hands(blade)
- target.visible_message("A grotesque blade forms around [target.name]\'s arm!", "Your arm twists and mutates, transforming into a horrific monstrosity!", "You hear organic matter ripping and tearing!")
+ target.visible_message(span_warning("A grotesque blade forms around [target.name]\'s arm!"), span_userdanger("Your arm twists and mutates, transforming into a horrific monstrosity!"), span_italics("You hear organic matter ripping and tearing!"))
playsound(target, 'sound/effects/blobattack.ogg', 30, 1)
addtimer(CALLBACK(src, PROC_REF(remove_fake), target, blade), 600)
@@ -157,9 +157,9 @@
/datum/action/changeling/sting/false_armblade/proc/remove_fake(mob/target, obj/item/melee/arm_blade/false/blade)
playsound(target, 'sound/effects/blobattack.ogg', 30, 1)
- target.visible_message("With a sickening crunch, \
- [target] reforms [target.p_their()] [blade.name] into an arm!",
- "[blade] reforms back to normal.",
+ target.visible_message(span_warning("With a sickening crunch, \
+ [target] reforms [target.p_their()] [blade.name] into an arm!"),
+ span_warning("[blade] reforms back to normal."),
"Your eyes burn horrifically!")
+ to_chat(target, span_danger("Your eyes burn horrifically!"))
target.become_nearsighted(EYE_DAMAGE)
target.blind_eyes(20)
target.blur_eyes(40)
diff --git a/code/modules/antagonists/clockcult/clock_helpers/hierophant_network.dm b/code/modules/antagonists/clockcult/clock_helpers/hierophant_network.dm
index 0c01dc0963a9..e59ebe40e4b0 100644
--- a/code/modules/antagonists/clockcult/clock_helpers/hierophant_network.dm
+++ b/code/modules/antagonists/clockcult/clock_helpers/hierophant_network.dm
@@ -26,7 +26,7 @@
/datum/action/innate/hierophant
name = "Hierophant Network"
desc = "Allows you to communicate with other Servants."
- icon_icon = 'icons/mob/actions/actions_clockcult.dmi'
+ button_icon = 'icons/mob/actions/actions_clockcult.dmi'
button_icon_state = "hierophant"
background_icon_state = "bg_clock"
check_flags = AB_CHECK_RESTRAINED|AB_CHECK_STUN|AB_CHECK_CONSCIOUS
@@ -35,14 +35,14 @@
var/span_for_name = "heavy_brass"
var/span_for_message = "brass"
-/datum/action/innate/hierophant/IsAvailable(silent = FALSE)
+/datum/action/innate/hierophant/IsAvailable(feedback = TRUE)
if(!is_servant_of_ratvar(owner))
return FALSE
return ..()
/datum/action/innate/hierophant/Activate()
var/input = stripped_input(usr, "Please enter a message to send to other servants.", "Hierophant Network", "")
- if(!input || !IsAvailable())
+ if(!input || !IsAvailable(feedback = TRUE))
return
if(ishuman(owner))
clockwork_say(owner, "[text2ratvar("Servants, hear my words: [input]")]", TRUE)
diff --git a/code/modules/antagonists/clockcult/clock_items/clock_weapons/_call_weapon.dm b/code/modules/antagonists/clockcult/clock_items/clock_weapons/_call_weapon.dm
index 04d8dc951844..0db98281b710 100644
--- a/code/modules/antagonists/clockcult/clock_items/clock_weapons/_call_weapon.dm
+++ b/code/modules/antagonists/clockcult/clock_items/clock_weapons/_call_weapon.dm
@@ -3,7 +3,7 @@
/datum/action/innate/call_weapon
name = "Call Weapon"
desc = "This definitely shouldn't exist."
- icon_icon = 'icons/mob/actions/actions_clockcult.dmi'
+ button_icon = 'icons/mob/actions/actions_clockcult.dmi'
button_icon_state = "ratvarian_spear"
background_icon_state = "bg_clock"
check_flags = AB_CHECK_RESTRAINED|AB_CHECK_STUN|AB_CHECK_CONSCIOUS
@@ -12,7 +12,7 @@
var/obj/item/clockwork/weapon/weapon_type //The type of weapon to create
var/obj/item/clockwork/weapon/weapon
-/datum/action/innate/call_weapon/IsAvailable(silent = FALSE)
+/datum/action/innate/call_weapon/IsAvailable(feedback = TRUE)
if(!is_servant_of_ratvar(owner))
qdel(src)
return
@@ -39,11 +39,11 @@
owner.visible_message("A [weapon.name] materializes in [owner]'s hands!", "You call forth your [weapon.name]!")
weapon.forceMove(get_turf(owner))
owner.put_in_hands(weapon)
- owner.update_action_buttons_icon()
+ owner.update_mob_action_buttons()
return TRUE
/datum/action/innate/call_weapon/proc/weapon_reset(cooldown_time)
cooldown = world.time + cooldown_time
- addtimer(CALLBACK(owner, TYPE_PROC_REF(/mob, update_action_buttons_icon)), cooldown_time)
- owner.update_action_buttons_icon()
+ addtimer(CALLBACK(owner, TYPE_PROC_REF(/mob, update_mob_action_buttons)), cooldown_time)
+ owner.update_mob_action_buttons()
QDEL_NULL(weapon)
diff --git a/code/modules/antagonists/clockcult/clock_items/clockwork_slab.dm b/code/modules/antagonists/clockcult/clock_items/clockwork_slab.dm
index 96380d7882e0..1d5cc29775fa 100644
--- a/code/modules/antagonists/clockcult/clock_items/clockwork_slab.dm
+++ b/code/modules/antagonists/clockcult/clock_items/clockwork_slab.dm
@@ -405,12 +405,12 @@
for(var/i in 1 to quickbound.len)
if(!quickbound[i])
continue
- var/datum/action/item_action/clock/quickbind/Q = new /datum/action/item_action/clock/quickbind(src)
+ var/datum/action/item_action/clock/quickbind/Q = add_item_action(/datum/action/item_action/clock/quickbind)
Q.scripture_index = i
var/datum/clockwork_scripture/quickbind_slot = GLOB.all_scripture[quickbound[i]]
Q.name = "[quickbind_slot.name] ([Q.scripture_index])"
Q.desc = quickbind_slot.quickbind_desc
Q.button_icon_state = quickbind_slot.name
- Q.UpdateButtons()
+ Q.build_all_button_icons()
if(isliving(loc))
Q.Grant(loc)
diff --git a/code/modules/antagonists/clockcult/clock_items/judicial_visor.dm b/code/modules/antagonists/clockcult/clock_items/judicial_visor.dm
index 542361bdf664..6a2cb6194d1a 100644
--- a/code/modules/antagonists/clockcult/clock_items/judicial_visor.dm
+++ b/code/modules/antagonists/clockcult/clock_items/judicial_visor.dm
@@ -73,7 +73,7 @@
var/mob/living/L = loc
active = change_to
icon_state = "judicial_visor_[active]"
- L.update_action_buttons_icon()
+ L.update_mob_action_buttons()
L.update_inv_glasses()
if(!is_servant_of_ratvar(L) || L.stat)
return FALSE
@@ -95,7 +95,7 @@
active = FALSE
icon_state = "judicial_visor_[active]"
if(user)
- user.update_action_buttons_icon()
+ user.update_mob_action_buttons()
user.update_inv_glasses()
/obj/effect/proc_holder/judicial_visor
@@ -137,7 +137,7 @@
var/turf/targetturf = get_turf(target)
new/obj/effect/clockwork/judicial_marker(targetturf, ranged_ability_user)
log_combat(ranged_ability_user, targetturf, "created a judicial marker")
- ranged_ability_user.update_action_buttons_icon()
+ ranged_ability_user.update_mob_action_buttons()
ranged_ability_user.update_inv_glasses()
addtimer(CALLBACK(visor, TYPE_PROC_REF(/obj/item/clothing/glasses/judicial_visor, recharge_visor), ranged_ability_user), GLOB.ratvar_awakens ? visor.recharge_cooldown*0.1 : visor.recharge_cooldown)//Cooldown is reduced by 10x if Ratvar is up
remove_ranged_ability()
diff --git a/code/modules/antagonists/clockcult/clock_mobs/_eminence.dm b/code/modules/antagonists/clockcult/clock_mobs/_eminence.dm
index 9a626f4f797b..1bc27973512d 100644
--- a/code/modules/antagonists/clockcult/clock_mobs/_eminence.dm
+++ b/code/modules/antagonists/clockcult/clock_mobs/_eminence.dm
@@ -231,11 +231,11 @@
/datum/action/innate/eminence
name = "Eminence Action"
desc = "You shouldn't see this. File a bug report!"
- icon_icon = 'icons/mob/actions/actions_clockcult.dmi'
+ button_icon = 'icons/mob/actions/actions_clockcult.dmi'
background_icon_state = "bg_clock"
buttontooltipstyle = "clockcult"
-/datum/action/innate/eminence/IsAvailable(silent = FALSE)
+/datum/action/innate/eminence/IsAvailable(feedback = TRUE)
if(!iseminence(owner))
qdel(src)
return
@@ -323,7 +323,7 @@
desc = "Initiates a mass recall, warping all servants to the Ark after a short delay. This can only be used once."
button_icon_state = "Spatial Gateway"
-/datum/action/innate/eminence/mass_recall/IsAvailable(silent = FALSE)
+/datum/action/innate/eminence/mass_recall/IsAvailable(feedback = TRUE)
. = ..()
if(.)
var/obj/structure/destructible/clockwork/massive/celestial_gateway/G = GLOB.ark_of_the_clockwork_justiciar
diff --git a/code/modules/antagonists/clockcult/clock_mobs/clockwork_guardian.dm b/code/modules/antagonists/clockcult/clock_mobs/clockwork_guardian.dm
index 44139c6ab9c3..c6be20288a25 100644
--- a/code/modules/antagonists/clockcult/clock_mobs/clockwork_guardian.dm
+++ b/code/modules/antagonists/clockcult/clock_mobs/clockwork_guardian.dm
@@ -381,12 +381,14 @@
var/list/defend_phrases = list("Defend me", "Come forth", "Assist me", "Protect me", "Give aid", "Help me")
var/list/return_phrases = list("Return", "Return to me", "Your job is done", "You have served", "Come back", "Retreat")
-/datum/action/innate/summon_guardian/IsAvailable()
+/datum/action/innate/summon_guardian/IsAvailable(feedback)
if(!linked_guardian)
return FALSE
if(isliving(owner))
var/mob/living/L = owner
if(!L.can_speak_vocal() || L.stat)
+ if(feedback)
+ L.balloon_alert(L, "can't speak!")
return FALSE
return ..()
@@ -409,7 +411,7 @@
buttontooltipstyle = "clockcult"
var/mob/living/simple_animal/hostile/clockwork/guardian/linked_guardian
-/datum/action/innate/linked_minds/IsAvailable()
+/datum/action/innate/linked_minds/IsAvailable(feedback)
if(!linked_guardian)
return FALSE
return ..()
diff --git a/code/modules/antagonists/clockcult/clock_scriptures/scripture_scripts.dm b/code/modules/antagonists/clockcult/clock_scriptures/scripture_scripts.dm
index 5d5aa95e47a0..8780f86e3c2b 100644
--- a/code/modules/antagonists/clockcult/clock_scriptures/scripture_scripts.dm
+++ b/code/modules/antagonists/clockcult/clock_scriptures/scripture_scripts.dm
@@ -174,7 +174,7 @@
/datum/action/innate/clockwork_armaments
name = "Clockwork Armaments"
desc = "Outfits you in a full set of Ratvarian armor."
- icon_icon = 'icons/mob/actions/actions_clockcult.dmi'
+ button_icon = 'icons/mob/actions/actions_clockcult.dmi'
button_icon_state = "clockwork_armor"
background_icon_state = "bg_clock"
check_flags = AB_CHECK_RESTRAINED|AB_CHECK_STUN|AB_CHECK_CONSCIOUS
@@ -190,7 +190,7 @@
/obj/item/clothing/head/helmet/space,
/obj/item/clothing/shoes/magboots)) //replace this only if ratvar is up
-/datum/action/innate/clockwork_armaments/IsAvailable(silent = FALSE)
+/datum/action/innate/clockwork_armaments/IsAvailable(feedback = TRUE)
if(!is_servant_of_ratvar(owner))
qdel(src)
return
@@ -216,8 +216,8 @@
owner.visible_message("Strange armor appears on [owner]!", "A bright shimmer runs down your body, equipping you with Ratvarian armor.")
playsound(owner, 'sound/magic/clockwork/fellowship_armory.ogg', 15 * do_message, TRUE) //get sound loudness based on how much we equipped
cooldown = CLOCKWORK_ARMOR_COOLDOWN + world.time
- owner.update_action_buttons_icon()
- addtimer(CALLBACK(owner, TYPE_PROC_REF(/mob, update_action_buttons_icon)), CLOCKWORK_ARMOR_COOLDOWN)
+ owner.update_mob_action_buttons()
+ addtimer(CALLBACK(owner, TYPE_PROC_REF(/mob, update_mob_action_buttons)), CLOCKWORK_ARMOR_COOLDOWN)
return TRUE
/datum/action/innate/clockwork_armaments/proc/remove_item_if_better(obj/item/I, mob/user)
diff --git a/code/modules/antagonists/clockcult/clockcult.dm b/code/modules/antagonists/clockcult/clockcult.dm
index f052afc4b49b..3e77da250195 100644
--- a/code/modules/antagonists/clockcult/clockcult.dm
+++ b/code/modules/antagonists/clockcult/clockcult.dm
@@ -97,7 +97,7 @@
GLOB.all_clockwork_mobs += current
current.faction |= "ratvar"
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
+ current.update_mob_action_buttons() //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
if(iscyborg(S))
@@ -171,7 +171,7 @@
var/mob/living/silicon/robot/R = temp_owner
R.module.rebuild_modules()
if(temp_owner)
- temp_owner.update_action_buttons_icon() //because a few clockcult things are action buttons and we may be wearing/holding them, we need to update buttons
+ temp_owner.update_mob_action_buttons() //because a few clockcult things are action buttons and we may be wearing/holding them, we need to update buttons
temp_owner.cut_overlays()
temp_owner.regenerate_icons()
diff --git a/code/modules/antagonists/cult/blood_magic.dm b/code/modules/antagonists/cult/blood_magic.dm
index d4ff89084c5f..5ac256c2fb12 100644
--- a/code/modules/antagonists/cult/blood_magic.dm
+++ b/code/modules/antagonists/cult/blood_magic.dm
@@ -12,7 +12,7 @@
qdel(X)
..()
-/datum/action/innate/cult/blood_magic/IsAvailable(silent = FALSE)
+/datum/action/innate/cult/blood_magic/IsAvailable(feedback = TRUE)
if(!iscultist(owner))
return FALSE
return ..()
@@ -119,7 +119,7 @@
hand_magic = null
..()
-/datum/action/innate/cult/blood_spell/IsAvailable(silent = FALSE)
+/datum/action/innate/cult/blood_spell/IsAvailable(feedback = TRUE)
if(!iscultist(owner) || owner.incapacitated() || !charges)
return FALSE
return ..()
@@ -274,7 +274,7 @@
attached_action.charges--
attached_action.desc = attached_action.base_desc
attached_action.desc += "
Has [attached_action.charges] use\s remaining."
- attached_action.UpdateButtons()
+ attached_action.build_all_button_icons()
if(attached_action.charges <= 0)
remove_ranged_ability("You have exhausted the spell's power!")
qdel(src)
@@ -326,7 +326,7 @@
qdel(src)
desc = base_desc
desc += "
Has [charges] use\s remaining."
- UpdateButtons()
+ build_all_button_icons()
/datum/action/innate/cult/blood_spell/manipulation
name = "Blood Rites"
@@ -374,7 +374,7 @@
source.charges = uses
source.desc = source.base_desc
source.desc += "
Has [uses] use\s remaining."
- source.UpdateButtons()
+ source.build_all_button_icons()
..()
/obj/item/melee/blood_magic/attack_self(mob/living/user)
@@ -401,7 +401,7 @@
else if(source)
source.desc = source.base_desc
source.desc += "
Has [uses] use\s remaining."
- source.UpdateButtons()
+ source.build_all_button_icons()
//Stun
/obj/item/melee/blood_magic/stun
diff --git a/code/modules/antagonists/cult/cult.dm b/code/modules/antagonists/cult/cult.dm
index fe9f8cbe040a..6ea222811d5d 100644
--- a/code/modules/antagonists/cult/cult.dm
+++ b/code/modules/antagonists/cult/cult.dm
@@ -223,7 +223,7 @@
reckoning.Grant(current)
bloodmark.Grant(current)
throwing.Grant(current)
- current.update_action_buttons_icon()
+ current.update_mob_action_buttons()
current.apply_status_effect(/datum/status_effect/cult_master)
if(cult_team?.cult_risen)
cult_team.rise(current)
@@ -238,7 +238,7 @@
reckoning.Remove(current)
bloodmark.Remove(current)
throwing.Remove(current)
- current.update_action_buttons_icon()
+ current.update_mob_action_buttons()
current.remove_status_effect(/datum/status_effect/cult_master)
if(ishuman(current))
diff --git a/code/modules/antagonists/cult/cult_comms.dm b/code/modules/antagonists/cult/cult_comms.dm
index cd348485f10a..6da75fe053cf 100644
--- a/code/modules/antagonists/cult/cult_comms.dm
+++ b/code/modules/antagonists/cult/cult_comms.dm
@@ -1,12 +1,12 @@
// Contains cult communion, guide, and cult master abilities
/datum/action/innate/cult
- icon_icon = 'icons/mob/actions/actions_cult.dmi'
+ button_icon = 'icons/mob/actions/actions_cult.dmi'
background_icon_state = "bg_demon"
buttontooltipstyle = "cult"
check_flags = AB_CHECK_RESTRAINED|AB_CHECK_STUN|AB_CHECK_CONSCIOUS
-/datum/action/innate/cult/IsAvailable(silent = FALSE)
+/datum/action/innate/cult/IsAvailable(feedback = TRUE)
if(!iscultist(owner))
return FALSE
return ..()
@@ -18,7 +18,7 @@
/datum/action/innate/cult/comm/Activate()
var/input = stripped_input(usr, "Please choose a message to tell to the other acolytes.", "Voice of Blood", "")
- if(!input || !IsAvailable())
+ if(!input || !IsAvailable(feedback = TRUE))
return
cultist_commune(usr, input)
@@ -51,7 +51,7 @@
name = "Spiritual Communion"
desc = "Conveys a message from the spirit realm that all cultists can hear."
-/datum/action/innate/cult/comm/spirit/IsAvailable(silent = FALSE)
+/datum/action/innate/cult/comm/spirit/IsAvailable(feedback = TRUE)
if(iscultist(owner.mind.current))
return TRUE
@@ -72,7 +72,7 @@
name = "Assert Leadership"
button_icon_state = "cultvote"
-/datum/action/innate/cult/mastervote/IsAvailable(silent = FALSE)
+/datum/action/innate/cult/mastervote/IsAvailable(feedback = TRUE)
var/datum/antagonist/cult/C = owner.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
if(!C?.cult_team || C.cult_team.cult_vote_called || !ishuman(owner))
return FALSE
@@ -80,10 +80,10 @@
/datum/action/innate/cult/mastervote/Activate()
var/choice = alert(owner, "The mantle of leadership is heavy. Success in this role requires an expert level of communication and experience. Are you sure?",, "Yes", "No")
- if(choice == "Yes" && IsAvailable())
+ if(choice == "Yes" && IsAvailable(feedback = TRUE))
var/datum/antagonist/cult/C = owner.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
if(!C.cult_team)
- to_chat(owner, "Do you not already lead yourself?")
+ to_chat(owner, span_cultbold("Do you not already lead yourself?"))
return
pollCultists(owner,C.cult_team)
@@ -94,7 +94,7 @@
team.cult_vote_called = TRUE //somebody's trying to be a master, make sure we don't let anyone else try
for(var/datum/mind/B in team.members)
if(B.current)
- B.current.update_action_buttons_icon()
+ B.current.update_mob_action_buttons()
if(!B.current.incapacitated())
SEND_SOUND(B.current, 'sound/hallucinations/im_here1.ogg')
to_chat(B.current, "Acolyte [Nominee] has asserted that [Nominee.p_theyre()] worthy of leading the cult. A vote will be called shortly.")
@@ -109,7 +109,7 @@
team.cult_vote_called = FALSE
for(var/datum/mind/B in team.members)
if(B.current)
- B.current.update_action_buttons_icon()
+ B.current.update_mob_action_buttons()
if(!B.current.incapacitated())
to_chat(B.current,"[Nominee] has died in the process of attempting to win the cult's support!")
return FALSE
@@ -117,7 +117,7 @@
team.cult_vote_called = FALSE
for(var/datum/mind/B in team.members)
if(B.current)
- B.current.update_action_buttons_icon()
+ B.current.update_mob_action_buttons()
if(!B.current.incapacitated())
to_chat(B.current,"[Nominee] has gone catatonic in the process of attempting to win the cult's support!")
return FALSE
@@ -125,7 +125,7 @@
team.cult_vote_called = FALSE
for(var/datum/mind/B in team.members)
if(B.current)
- B.current.update_action_buttons_icon()
+ B.current.update_mob_action_buttons()
if(!B.current.incapacitated())
to_chat(B.current, "[Nominee] could not win the cult's support and shall continue to serve as an acolyte.")
return FALSE
@@ -140,7 +140,7 @@
to_chat(B.current,"[Nominee] has won the cult's support and is now their master. Follow [Nominee.p_their()] orders to the best of your ability!")
return TRUE
-/datum/action/innate/cult/master/IsAvailable(silent = FALSE)
+/datum/action/innate/cult/master/IsAvailable(feedback = TRUE)
if(!owner.mind || !owner.mind.has_antag_datum(/datum/antagonist/cult/master) || GLOB.cult_narsie)
return FALSE
return ..()
@@ -226,9 +226,9 @@
CM.attached_action = src
..()
-/datum/action/innate/cult/master/cultmark/IsAvailable(silent = FALSE)
+/datum/action/innate/cult/master/cultmark/IsAvailable(feedback = TRUE)
if(cooldown > world.time)
- if(!CM.active && !silent)
+ if(!CM.active && feedback)
to_chat(owner, "You need to wait [DisplayTimeText(cooldown - world.time)] before you can mark another target!")
return FALSE
return ..()
@@ -278,7 +278,7 @@
C.cult_team.blood_target = target
var/area/A = get_area(target)
attached_action.cooldown = world.time + attached_action.base_cooldown
- addtimer(CALLBACK(attached_action.owner, TYPE_PROC_REF(/mob, update_action_buttons_icon)), attached_action.base_cooldown)
+ addtimer(CALLBACK(attached_action.owner, TYPE_PROC_REF(/mob, update_mob_action_buttons)), attached_action.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
@@ -288,7 +288,7 @@
to_chat(B.current, "[ranged_ability_user] has marked [C.cult_team.blood_target] in the [A.name] as the cult's top priority, get there immediately!")
SEND_SOUND(B.current, sound(pick('sound/hallucinations/over_here2.ogg','sound/hallucinations/over_here3.ogg'),0,1,75))
B.current.client.images += C.cult_team.blood_target_image
- attached_action.owner.update_action_buttons_icon()
+ attached_action.owner.update_mob_action_buttons()
remove_ranged_ability("The marking rite is complete! It will last for 90 seconds.")
C.cult_team.blood_target_reset_timer = addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(reset_blood_target),C.cult_team), 900, TIMER_STOPPABLE)
return TRUE
@@ -308,7 +308,7 @@
name = "Mark a Blood Target for the Cult"
desc = "Marks a target for the entire cult to track."
-/datum/action/innate/cult/master/cultmark/ghost/IsAvailable(silent = FALSE)
+/datum/action/innate/cult/master/cultmark/ghost/IsAvailable(feedback = TRUE)
if(istype(owner, /mob/dead/observer) && iscultist(owner.mind.current))
return TRUE
else
@@ -322,7 +322,7 @@
var/cooldown = 0
var/base_cooldown = 600
-/datum/action/innate/cult/ghostmark/IsAvailable(silent = FALSE)
+/datum/action/innate/cult/ghostmark/IsAvailable(feedback = TRUE)
if(istype(owner, /mob/dead/observer) && iscultist(owner.mind.current))
return TRUE
else
@@ -333,7 +333,7 @@
name = "Blood Mark your Target"
desc = "Marks whatever you are orbitting - for the entire cult to track."
button_icon_state = "cult_mark"
- owner.update_action_buttons_icon()
+ owner.update_mob_action_buttons()
SEND_SOUND(owner, 'sound/magic/enter_blood.ogg')
to_chat(owner,"Your previous mark is gone - you are now ready to create a new blood mark.")
@@ -360,7 +360,7 @@
C.cult_team.blood_target = target
var/area/A = get_area(target)
cooldown = world.time + base_cooldown
- addtimer(CALLBACK(owner, TYPE_PROC_REF(/mob, update_action_buttons_icon)), base_cooldown)
+ addtimer(CALLBACK(owner, TYPE_PROC_REF(/mob, update_mob_action_buttons)), 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 = -C.cult_team.blood_target.pixel_x
@@ -376,7 +376,7 @@
name = "Clear the Blood Mark"
desc = "Remove the Blood Mark you previously set."
button_icon_state = "emp"
- owner.update_action_buttons_icon()
+ owner.update_mob_action_buttons()
C.cult_team.blood_target_reset_timer = addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(reset_blood_target),C.cult_team), base_cooldown, TIMER_STOPPABLE)
addtimer(CALLBACK(src, PROC_REF(reset_button)), base_cooldown)
@@ -388,7 +388,7 @@
/datum/action/innate/cult/master/pulse
name = "Eldritch Pulse"
desc = "Seize upon a fellow cultist or cult structure and teleport it to a nearby location."
- icon_icon = 'icons/mob/actions/actions_spells.dmi'
+ button_icon = 'icons/mob/actions/actions_spells.dmi'
button_icon_state = "arcane_barrage"
var/obj/effect/proc_holder/pulse/PM
var/cooldown = 0
@@ -401,11 +401,11 @@
PM.attached_action = src
..()
-/datum/action/innate/cult/master/pulse/IsAvailable(silent = FALSE)
+/datum/action/innate/cult/master/pulse/IsAvailable(feedback = TRUE)
if(!owner.mind || !owner.mind.has_antag_datum(/datum/antagonist/cult/master))
return FALSE
if(cooldown > world.time)
- if(!PM.active && !silent)
+ if(!PM.active && feedback)
to_chat(owner, "You need to wait [DisplayTimeText(cooldown - world.time)] before you can pulse again!")
return FALSE
return ..()
@@ -467,5 +467,5 @@
attached_action.throwing = FALSE
attached_action.cooldown = world.time + attached_action.base_cooldown
remove_ranged_ability("A pulse of blood magic surges through you as you shift [attached_action.throwee] through time and space.")
- caller.update_action_buttons_icon()
- addtimer(CALLBACK(caller, TYPE_PROC_REF(/mob, update_action_buttons_icon)), attached_action.base_cooldown)
+ caller.update_mob_action_buttons()
+ addtimer(CALLBACK(caller, TYPE_PROC_REF(/mob, update_mob_action_buttons)), attached_action.base_cooldown)
diff --git a/code/modules/antagonists/cult/cult_items.dm b/code/modules/antagonists/cult/cult_items.dm
index 878fe4a443f6..0b71a28093b5 100644
--- a/code/modules/antagonists/cult/cult_items.dm
+++ b/code/modules/antagonists/cult/cult_items.dm
@@ -222,7 +222,7 @@
/datum/action/innate/dash/cult
name = "Rend the Veil"
desc = "Use the sword to shear open the flimsy fabric of this reality and teleport to your target."
- icon_icon = 'icons/mob/actions/actions_cult.dmi'
+ button_icon = 'icons/mob/actions/actions_cult.dmi'
button_icon_state = "phaseshift"
dash_sound = 'sound/magic/enter_blood.ogg'
recharge_sound = 'sound/magic/exit_blood.ogg'
@@ -230,7 +230,7 @@
phasein = /obj/effect/temp_visual/dir_setting/cult/phase
phaseout = /obj/effect/temp_visual/dir_setting/cult/phase/out
-/datum/action/innate/dash/cult/IsAvailable(silent = FALSE)
+/datum/action/innate/dash/cult/IsAvailable(feedback = TRUE)
if(iscultist(owner) && current_charges)
return TRUE
else
@@ -250,7 +250,7 @@
sword = bastard
holder = user
-/datum/action/innate/cult/spin2win/IsAvailable(silent = FALSE)
+/datum/action/innate/cult/spin2win/IsAvailable(feedback = TRUE)
if(iscultist(holder) && cooldown <= world.time)
return TRUE
else
@@ -264,14 +264,14 @@
sword.block_chance = 100
sword.slowdown += 1.5
addtimer(CALLBACK(src, PROC_REF(stop_spinning)), 50)
- holder.update_action_buttons_icon()
+ holder.update_mob_action_buttons()
/datum/action/innate/cult/spin2win/proc/stop_spinning()
sword.spinning = FALSE
sword.block_chance = 50
sword.slowdown -= 1.5
sleep(sword.spin_cooldown)
- holder.update_action_buttons_icon()
+ holder.update_mob_action_buttons()
/obj/item/restraints/legcuffs/bola/cult
name = "\improper Nar'Sien bola"
diff --git a/code/modules/antagonists/cult/rune_spawn_action.dm b/code/modules/antagonists/cult/rune_spawn_action.dm
index fd3c704849b1..47498c9f9f53 100644
--- a/code/modules/antagonists/cult/rune_spawn_action.dm
+++ b/code/modules/antagonists/cult/rune_spawn_action.dm
@@ -14,7 +14,7 @@
var/obj/effect/temp_visual/cult/rune_spawn/rune_center_type
var/rune_color
-/datum/action/innate/cult/create_rune/IsAvailable(silent = FALSE)
+/datum/action/innate/cult/create_rune/IsAvailable(feedback = TRUE)
if(!rune_type || cooldown > world.time)
return FALSE
return ..()
@@ -56,8 +56,8 @@
R4 = new rune_center_type(T, scribe_time, rune_color)
cooldown = base_cooldown + world.time
- owner.update_action_buttons_icon()
- addtimer(CALLBACK(owner, TYPE_PROC_REF(/mob, update_action_buttons_icon)), base_cooldown)
+ owner.update_mob_action_buttons()
+ addtimer(CALLBACK(owner, TYPE_PROC_REF(/mob, update_mob_action_buttons)), base_cooldown)
var/list/health
if(damage_interrupt && isliving(owner))
var/mob/living/L = owner
@@ -78,7 +78,7 @@
if(R4)
qdel(R4)
cooldown = 0
- owner.update_action_buttons_icon()
+ owner.update_mob_action_buttons()
//teleport rune
/datum/action/innate/cult/create_rune/tele
diff --git a/code/modules/antagonists/disease/disease_abilities.dm b/code/modules/antagonists/disease/disease_abilities.dm
index 0b5258dd5049..7a50c5fea4fd 100644
--- a/code/modules/antagonists/disease/disease_abilities.dm
+++ b/code/modules/antagonists/disease/disease_abilities.dm
@@ -164,7 +164,7 @@ new /datum/disease_ability/symptom/powerful/youth
/datum/action/cooldown/disease_cough
name = "Cough"
- icon_icon = 'icons/mob/actions/actions_minor_antag.dmi'
+ button_icon = 'icons/mob/actions/actions_minor_antag.dmi'
button_icon_state = "cough"
desc = "Force the host you are following to cough with extra force, spreading your infection to those within two meters of your host even if your transmissibility is low.
Cooldown: 10 seconds"
cooldown_time = 100
@@ -194,7 +194,7 @@ new /datum/disease_ability/symptom/powerful/youth
/datum/action/cooldown/disease_sneeze
name = "Sneeze"
- icon_icon = 'icons/mob/actions/actions_minor_antag.dmi'
+ button_icon = 'icons/mob/actions/actions_minor_antag.dmi'
button_icon_state = "sneeze"
desc = "Force the host you are following to sneeze with extra force, spreading your infection to any victims in a 4 meter cone in front of your host even if your transmissibility is low.
Cooldown: 20 seconds"
cooldown_time = 200
@@ -228,7 +228,7 @@ new /datum/disease_ability/symptom/powerful/youth
/datum/action/cooldown/disease_infect
name = "Secrete Infection"
- icon_icon = 'icons/mob/actions/actions_minor_antag.dmi'
+ button_icon = 'icons/mob/actions/actions_minor_antag.dmi'
button_icon_state = "infect"
desc = "Cause the host you are following to excrete an infective substance from their pores, causing all objects touching their skin to transmit your infection to anyone who touches them for the next 30 seconds.
Cooldown: 40 seconds"
cooldown_time = 400
diff --git a/code/modules/antagonists/disease/disease_mob.dm b/code/modules/antagonists/disease/disease_mob.dm
index ea538c93ba52..5337fc20fac5 100644
--- a/code/modules/antagonists/disease/disease_mob.dm
+++ b/code/modules/antagonists/disease/disease_mob.dm
@@ -403,7 +403,7 @@ the new instance inside the host to be updated to the template's stats.
/datum/action/innate/disease_adapt
name = "Adaptation Menu"
- icon_icon = 'icons/mob/actions/actions_minor_antag.dmi'
+ button_icon = 'icons/mob/actions/actions_minor_antag.dmi'
button_icon_state = "disease_menu"
/datum/action/innate/disease_adapt/Activate()
diff --git a/code/modules/antagonists/eldritch_cult/eldritch_items.dm b/code/modules/antagonists/eldritch_cult/eldritch_items.dm
index 58e0193de583..a34b786d3c16 100644
--- a/code/modules/antagonists/eldritch_cult/eldritch_items.dm
+++ b/code/modules/antagonists/eldritch_cult/eldritch_items.dm
@@ -371,7 +371,7 @@
desc = "Destroys all runes that were drawn by this blade."
background_icon_state = "bg_ecult"
button_icon_state = "rune_break"
- icon_icon = 'icons/mob/actions/actions_ecult.dmi'
+ button_icon = 'icons/mob/actions/actions_ecult.dmi'
check_flags = AB_CHECK_CONSCIOUS
///Reference to the rune knife it is inside of
var/obj/item/melee/rune_knife/sword
diff --git a/code/modules/antagonists/eldritch_cult/eldritch_magic.dm b/code/modules/antagonists/eldritch_cult/eldritch_magic.dm
index 9dc1d3f995c6..ce47257611e3 100644
--- a/code/modules/antagonists/eldritch_cult/eldritch_magic.dm
+++ b/code/modules/antagonists/eldritch_cult/eldritch_magic.dm
@@ -608,7 +608,7 @@
name = "Mansus Link"
desc = "Send a psychic message to everyone connected to your Mansus Net."
button_icon_state = "link_speech"
- icon_icon = 'icons/mob/actions/actions_slime.dmi'
+ button_icon = 'icons/mob/actions/actions_slime.dmi'
background_icon_state = "bg_ecult"
var/mob/living/simple_animal/hostile/eldritch/raw_prophet/originator
diff --git a/code/modules/antagonists/gang/gang.dm b/code/modules/antagonists/gang/gang.dm
index 058379d96c6f..af9ec4259332 100644
--- a/code/modules/antagonists/gang/gang.dm
+++ b/code/modules/antagonists/gang/gang.dm
@@ -220,7 +220,7 @@
desc = "Teach new recruits the Secret Handshake to join."
check_flags = AB_CHECK_CONSCIOUS
button_icon_state = "recruit"
- icon_icon = 'icons/obj/gang/actions.dmi'
+ button_icon = 'icons/obj/gang/actions.dmi'
cooldown_time = 300
/// The family antagonist datum of the "owner" of this action.
var/datum/antagonist/gang/my_gang_datum
diff --git a/code/modules/antagonists/revenant/revenant.dm b/code/modules/antagonists/revenant/revenant.dm
index e81d7f236909..c461fc5f6d8a 100644
--- a/code/modules/antagonists/revenant/revenant.dm
+++ b/code/modules/antagonists/revenant/revenant.dm
@@ -132,7 +132,7 @@
to_chat(src, "You can move again!")
if(essence_regenerating && !inhibited && essence < essence_regen_cap) //While inhibited, essence will not regenerate
essence = min(essence_regen_cap, essence+essence_regen_amount)
- update_action_buttons_icon() //because we update something required by our spells in life, we need to update our buttons
+ update_mob_action_buttons() //because we update something required by our spells in life, we need to update our buttons
update_spooky_icon()
update_health_hud()
@@ -200,12 +200,12 @@
"As \the [W] passes through you, you feel your essence draining away!")
adjustBruteLoss(25) //hella effective
inhibited = TRUE
- update_action_buttons_icon()
+ update_mob_action_buttons()
addtimer(CALLBACK(src, PROC_REF(reset_inhibit)), 30)
/mob/living/simple_animal/revenant/proc/reset_inhibit()
inhibited = FALSE
- update_action_buttons_icon()
+ update_mob_action_buttons()
/mob/living/simple_animal/revenant/adjustHealth(amount, updating_health = TRUE, forced = FALSE)
if(!forced && !revealed)
@@ -314,7 +314,7 @@
if(essence_excess < essence_cost)
return FALSE
essence_excess -= essence_cost
- update_action_buttons_icon()
+ update_mob_action_buttons()
return TRUE
/mob/living/simple_animal/revenant/proc/change_essence_amount(essence_amt, silent = FALSE, source = null)
@@ -327,7 +327,7 @@
if(essence_amt > 0)
essence_accumulated = max(0, essence_accumulated+essence_amt)
essence_excess = max(0, essence_excess+essence_amt)
- update_action_buttons_icon()
+ update_mob_action_buttons()
if(!silent)
if(essence_amt > 0)
to_chat(src, "Gained [essence_amt]E[source ? " from [source]":""].")
diff --git a/code/modules/antagonists/revenant/revenant_abilities.dm b/code/modules/antagonists/revenant/revenant_abilities.dm
index 3eea2d9ad845..e22bc768fdf6 100644
--- a/code/modules/antagonists/revenant/revenant_abilities.dm
+++ b/code/modules/antagonists/revenant/revenant_abilities.dm
@@ -138,7 +138,7 @@
else
name = "[initial(name)] ([cast_amount]E)"
-/obj/effect/proc_holder/spell/aoe_turf/revenant/can_cast(mob/living/simple_animal/revenant/user = usr, skipcharge = FALSE, silent = FALSE)
+/obj/effect/proc_holder/spell/aoe_turf/revenant/can_cast(mob/living/simple_animal/revenant/user = usr, skipcharge = FALSE, feedback = TRUE)
if(charge_counter < charge_max)
return FALSE
if(!istype(user)) //Badmins, no. Badmins, don't do it.
@@ -176,7 +176,7 @@
user.reveal(reveal)
user.stun(stun)
if(action)
- action.UpdateButtons()
+ action.build_all_button_icons()
return TRUE
//Overload Light: Breaks a light that's online and sends out lightning bolts to all nearby people.
diff --git a/code/modules/antagonists/slaughter/slaughter.dm b/code/modules/antagonists/slaughter/slaughter.dm
index 802d9eb5eab7..39316f134465 100644
--- a/code/modules/antagonists/slaughter/slaughter.dm
+++ b/code/modules/antagonists/slaughter/slaughter.dm
@@ -82,7 +82,7 @@
/datum/action/cooldown/slam
name = "Slaughter Slam"
desc = "Launch enemies and break bones in one strike."
- icon_icon = 'icons/mob/actions/actions_minor_antag.dmi'
+ button_icon = 'icons/mob/actions/actions_minor_antag.dmi'
background_icon_state = "bg_demon"
button_icon_state = "slam"
cooldown_time = 45 SECONDS
diff --git a/code/modules/antagonists/traitor/equipment/Malf_Modules.dm b/code/modules/antagonists/traitor/equipment/Malf_Modules.dm
index 44e70ebb3405..4c68d7fde1c0 100644
--- a/code/modules/antagonists/traitor/equipment/Malf_Modules.dm
+++ b/code/modules/antagonists/traitor/equipment/Malf_Modules.dm
@@ -23,7 +23,7 @@ GLOBAL_LIST_INIT(blacklisted_malf_machines, typecacheof(list(
name = "AI Action"
desc = "You aren't entirely sure what this does, but it's very beepy and boopy."
background_icon_state = "bg_tech_blue"
- icon_icon = 'icons/mob/actions/actions_AI.dmi'
+ button_icon = 'icons/mob/actions/actions_AI.dmi'
check_flags = AB_CHECK_CONSCIOUS //can't doomsday if dead.
var/mob/living/silicon/ai/owner_AI //The owner AI, so we don't have to typecast every time
var/uses //If we have multiple uses of the same power
@@ -43,28 +43,29 @@ GLOBAL_LIST_INIT(blacklisted_malf_machines, typecacheof(list(
else
owner_AI = owner
-/datum/action/innate/ai/IsAvailable(silent = FALSE)
+/datum/action/innate/ai/IsAvailable(feedback = TRUE)
. = ..()
if(owner_AI && owner_AI.malf_cooldown > world.time)
return FALSE
-/datum/action/innate/ai/Trigger()
+/datum/action/innate/ai/Trigger(trigger_flags)
. = ..()
if(auto_use_uses)
adjust_uses(-1)
if(cooldown_period)
owner_AI.malf_cooldown = world.time + cooldown_period
+ return TRUE
/datum/action/innate/ai/proc/adjust_uses(amt, silent)
uses += amt
if(uses)
if(!silent)
- to_chat(owner, "[name] now has [uses] use[uses > 1 ? "s" : ""] remaining.")
+ to_chat(owner, span_notice("[name] now has [uses] use[uses > 1 ? "s" : ""] remaining."))
desc = "[initial(desc)] It has [uses] use\s remaining."
- UpdateButtons()
+ build_all_button_icons()
return
if(initial(uses) > 1) //no need to tell 'em if it was one-use anyway!
- to_chat(owner, "[name] has run out of uses!")
+ to_chat(owner, span_warning("[name] has run out of uses!"))
qdel(src)
@@ -88,12 +89,12 @@ GLOBAL_LIST_INIT(blacklisted_malf_machines, typecacheof(list(
uses += amt
if(uses)
if(!silent)
- to_chat(owner, "[name] now has [uses] use[uses > 1 ? "s" : ""] remaining.")
+ to_chat(owner, span_notice("[name] now has [uses] use[uses > 1 ? "s" : ""] remaining."))
desc = "[initial(desc)] It has [uses] use\s remaining."
- UpdateButtons()
+ build_all_button_icons()
return
if(initial(uses) > 1) //no need to tell 'em if it was one-use anyway!
- to_chat(owner, "[name] has run out of uses!")
+ to_chat(owner, span_warning("[name] has run out of uses!"))
Remove(owner)
QDEL_IN(src, 100) //let any active timers on us finish up
@@ -107,8 +108,8 @@ GLOBAL_LIST_INIT(blacklisted_malf_machines, typecacheof(list(
//The actual ranged proc holder.
/obj/effect/proc_holder/ranged_ai
- var/enable_text = "Hello World!" //Appears when the user activates the ability
- var/disable_text = "Goodbye Cruel World!" //Context clues!
+ var/enable_text = span_notice("Hello World!") //Appears when the user activates the ability
+ var/disable_text = span_danger("Goodbye Cruel World!") //Context clues!
var/datum/action/innate/ai/ranged/attached_action
/obj/effect/proc_holder/ranged_ai/Destroy()
@@ -166,7 +167,7 @@ GLOBAL_LIST_INIT(blacklisted_malf_machines, typecacheof(list(
var/mob/living/silicon/ai/A = usr
if(A.stat == DEAD)
- to_chat(A, "You are already dead!")
+ to_chat(A, span_warning("You are already dead!"))
return
for(var/datum/AI_Module/AM in possible_modules)
@@ -201,7 +202,7 @@ GLOBAL_LIST_INIT(blacklisted_malf_machines, typecacheof(list(
else //Adding uses to an existing module
action.uses += initial(action.uses)
action.desc = "[initial(action.desc)] It has [action.uses] use\s remaining."
- action.UpdateButtons()
+ action.build_all_button_icons()
temp = "Additional use[action.uses > 1 ? "s" : ""] added to [action.name]!"
processing_time -= AM.cost
@@ -222,7 +223,7 @@ GLOBAL_LIST_INIT(blacklisted_malf_machines, typecacheof(list(
var/power_type = /datum/action/innate/ai //If the module gives an active ability, use this. Mutually exclusive with upgrade.
var/upgrade //If the module gives a passive upgrade, use this. Mutually exclusive with power_type.
- var/unlock_text = "Hello World!" //Text shown when an ability is unlocked
+ var/unlock_text = span_notice("Hello World!") //Text shown when an ability is unlocked
var/unlock_sound //Sound played when an ability is unlocked
/datum/AI_Module/proc/upgrade(mob/living/silicon/ai/AI) //Apply upgrades!
@@ -240,7 +241,7 @@ GLOBAL_LIST_INIT(blacklisted_malf_machines, typecacheof(list(
cost = 130
one_purchase = TRUE
power_type = /datum/action/innate/ai/nuke_station
- unlock_text = "You slowly, carefully, establish a connection with the on-station self-destruct. You can now activate it at any time."
+ unlock_text = span_notice("You slowly, carefully, establish a connection with the on-station self-destruct. You can now activate it at any time.")
/datum/action/innate/ai/nuke_station
name = "Doomsday Device"
@@ -251,7 +252,7 @@ GLOBAL_LIST_INIT(blacklisted_malf_machines, typecacheof(list(
/datum/action/innate/ai/nuke_station/Activate()
var/turf/T = get_turf(owner)
if(!istype(T) || !is_station_level(T.z))
- to_chat(owner, "You cannot activate the doomsday device while off-station!")
+ to_chat(owner, span_warning("You cannot activate the doomsday device while off-station!"))
return
if(alert(owner, "Send arming signal? (true = arm, false = cancel)", "purge_all_life()", "confirm = TRUE;", "confirm = FALSE;") != "confirm = TRUE;")
return
@@ -275,13 +276,13 @@ GLOBAL_LIST_INIT(blacklisted_malf_machines, typecacheof(list(
if(QDELETED(owner) || owner.stat == DEAD)
return
owner.playsound_local(owner, 'sound/misc/bloblarm.ogg', 50, 0)
- to_chat(owner, "!!! UNAUTHORIZED SELF-DESTRUCT ACCESS !!!")
- to_chat(owner, "This is a class-3 security violation. This incident will be reported to Central Command.")
+ to_chat(owner, span_userdanger("!!! UNAUTHORIZED SELF-DESTRUCT ACCESS !!!"))
+ to_chat(owner, span_boldannounce("This is a class-3 security violation. This incident will be reported to Central Command."))
for(var/i in 1 to 3)
sleep(20)
if(QDELETED(owner) || owner.stat == DEAD)
return
- to_chat(owner, "Sending security report to Central Command.....[rand(0, 9) + (rand(20, 30) * i)]%")
+ to_chat(owner, span_boldannounce("Sending security report to Central Command.....[rand(0, 9) + (rand(20, 30) * i)]%"))
sleep(3)
if(QDELETED(owner) || owner.stat == DEAD)
return
@@ -290,12 +291,12 @@ GLOBAL_LIST_INIT(blacklisted_malf_machines, typecacheof(list(
sleep(30)
if(QDELETED(owner) || owner.stat == DEAD)
return
- to_chat(owner, "Credentials accepted. Welcome, akjv9c88asdf12nb.")
+ to_chat(owner, span_boldnotice("Credentials accepted. Welcome, akjv9c88asdf12nb."))
owner.playsound_local(owner, 'sound/misc/server-ready.ogg', 50, 0)
sleep(5)
if(QDELETED(owner) || owner.stat == DEAD)
return
- to_chat(owner, "Arm self-destruct device? (Y/N)")
+ to_chat(owner, span_boldnotice("Arm self-destruct device? (Y/N)"))
owner.playsound_local(owner, 'sound/misc/compiler-stage1.ogg', 50, 0)
sleep(20)
if(QDELETED(owner) || owner.stat == DEAD)
@@ -304,7 +305,7 @@ GLOBAL_LIST_INIT(blacklisted_malf_machines, typecacheof(list(
sleep(15)
if(QDELETED(owner) || owner.stat == DEAD)
return
- to_chat(owner, "Confirm arming of self-destruct device? (Y/N)")
+ to_chat(owner, span_boldnotice("Confirm arming of self-destruct device? (Y/N)"))
owner.playsound_local(owner, 'sound/misc/compiler-stage2.ogg', 50, 0)
sleep(10)
if(QDELETED(owner) || owner.stat == DEAD)
@@ -313,7 +314,7 @@ GLOBAL_LIST_INIT(blacklisted_malf_machines, typecacheof(list(
sleep(rand(15, 25))
if(QDELETED(owner) || owner.stat == DEAD)
return
- to_chat(owner, "Please repeat password to confirm.")
+ to_chat(owner, span_boldnotice("Please repeat password to confirm."))
owner.playsound_local(owner, 'sound/misc/compiler-stage2.ogg', 50, 0)
sleep(14)
if(QDELETED(owner) || owner.stat == DEAD)
@@ -322,14 +323,14 @@ GLOBAL_LIST_INIT(blacklisted_malf_machines, typecacheof(list(
sleep(40)
if(QDELETED(owner) || owner.stat == DEAD)
return
- to_chat(owner, "Credentials accepted. Transmitting arming signal...")
+ to_chat(owner, span_boldnotice("Credentials accepted. Transmitting arming signal..."))
owner.playsound_local(owner, 'sound/misc/server-ready.ogg', 50, 0)
sleep(30)
if(QDELETED(owner) || owner.stat == DEAD)
return
if(istype(owner.loc, /obj/item/aicard))
- to_chat(owner, "Error: Signal transmission failed. Reason: Lost connection to network.")
- to_chat(owner, "You can't activate the doomsday device while inside an intelliCard!")
+ to_chat(owner, span_boldnotice("Error: Signal transmission failed. Reason: Lost connection to network."))
+ to_chat(owner, span_warning("You can't activate the doomsday device while inside an intelliCard!"))
return
priority_announce("Hostile runtimes detected in all station systems, please deactivate your AI to prevent possible damage to its morality core.", "Anomaly Alert", "aimalf")
set_security_level("delta")
@@ -409,7 +410,7 @@ GLOBAL_LIST_INIT(blacklisted_malf_machines, typecacheof(list(
continue
if(issilicon(L))
continue
- to_chat(L, "The blast wave from [src] tears you atom from atom!")
+ to_chat(L, span_userdanger("The blast wave from [src] tears you atom from atom!"))
L.dust()
to_chat(world, "The AI cleansed the station of life with the doomsday device!")
SSticker.force_ending = 1
@@ -422,7 +423,7 @@ GLOBAL_LIST_INIT(blacklisted_malf_machines, typecacheof(list(
description = "Improves the power and health of all AI turrets. This effect is permanent."
cost = 30
upgrade = TRUE
- unlock_text = "You establish a power diversion to your turrets, upgrading their health and damage."
+ unlock_text = span_notice("You establish a power diversion to your turrets, upgrading their health and damage.")
unlock_sound = 'sound/items/rped.ogg'
/datum/AI_Module/large/upgrade_turrets/upgrade(mob/living/silicon/ai/AI)
@@ -441,7 +442,7 @@ GLOBAL_LIST_INIT(blacklisted_malf_machines, typecacheof(list(
cost = 30
one_purchase = TRUE
power_type = /datum/action/innate/ai/lockdown
- unlock_text = "You upload a sleeper trojan into the door control systems. You can send a signal to set it off at any time."
+ unlock_text = span_notice("You upload a sleeper trojan into the door control systems. You can send a signal to set it off at any time.")
unlock_sound = 'sound/machines/boltsdown.ogg'
/datum/action/innate/ai/lockdown
@@ -462,7 +463,7 @@ GLOBAL_LIST_INIT(blacklisted_malf_machines, typecacheof(list(
C.post_status("alert", "lockdown")
minor_announce("Hostile runtime detected in door controllers. Isolation lockdown protocols are now in effect. Please remain calm.","Network Alert:", TRUE)
- to_chat(owner, "Lockdown initiated. Network reset in 90 seconds.")
+ to_chat(owner, span_danger("Lockdown initiated. Network reset in 90 seconds."))
addtimer(CALLBACK(GLOBAL_PROC, PROC_REF(minor_announce),
"Automatic system reboot complete. Have a secure day.",
"Network reset:"), 900)
@@ -476,7 +477,7 @@ GLOBAL_LIST_INIT(blacklisted_malf_machines, typecacheof(list(
cost = 25
one_purchase = TRUE
power_type = /datum/action/innate/ai/destroy_rcds
- unlock_text = "After some improvisation, you rig your onboard radio to be able to send a signal to detonate all RCDs."
+ unlock_text = span_notice("After some improvisation, you rig your onboard radio to be able to send a signal to detonate all RCDs.")
unlock_sound = 'sound/items/timer.ogg'
/datum/action/innate/ai/destroy_rcds
@@ -491,7 +492,7 @@ GLOBAL_LIST_INIT(blacklisted_malf_machines, typecacheof(list(
if(!istype(I, /obj/item/construction/rcd/borg)) //Ensures that cyborg RCDs are spared.
var/obj/item/construction/rcd/RCD = I
RCD.detonate_pulse()
- to_chat(owner, "RCD detonation pulse emitted.")
+ to_chat(owner, span_danger("RCD detonation pulse emitted."))
owner.playsound_local(owner, 'sound/machines/twobeep.ogg', 50, 0)
@@ -503,7 +504,7 @@ GLOBAL_LIST_INIT(blacklisted_malf_machines, typecacheof(list(
Do not allow the mech to leave the station's vicinity or allow it to be destroyed."
cost = 30
upgrade = TRUE
- unlock_text = "Virus package compiled. Select a target mech at any time. You must remain on the station at all times. Loss of signal will result in total system lockout."
+ unlock_text = span_notice("Virus package compiled. Select a target mech at any time. You must remain on the station at all times. Loss of signal will result in total system lockout.")
unlock_sound = 'sound/mecha/nominal.ogg'
/datum/AI_Module/large/mecha_domination/upgrade(mob/living/silicon/ai/AI)
@@ -519,7 +520,7 @@ GLOBAL_LIST_INIT(blacklisted_malf_machines, typecacheof(list(
one_purchase = TRUE
cost = 25
power_type = /datum/action/innate/ai/break_fire_alarms
- unlock_text = "You replace the thermal sensing capabilities of all fire alarms with a manual override, allowing you to turn them off at will."
+ unlock_text = span_notice("You replace the thermal sensing capabilities of all fire alarms with a manual override, allowing you to turn them off at will.")
unlock_sound = 'goon/sound/machinery/firealarm.ogg'
/datum/action/innate/ai/break_fire_alarms
@@ -534,7 +535,7 @@ GLOBAL_LIST_INIT(blacklisted_malf_machines, typecacheof(list(
continue
F.obj_flags |= EMAGGED
F.update_icon()
- to_chat(owner, "All thermal sensors on the station have been disabled. Fire alerts will no longer be recognized.")
+ to_chat(owner, span_notice("All thermal sensors on the station have been disabled. Fire alerts will no longer be recognized."))
owner.playsound_local(owner, 'sound/machines/terminal_off.ogg', 50, 0)
@@ -547,7 +548,7 @@ GLOBAL_LIST_INIT(blacklisted_malf_machines, typecacheof(list(
one_purchase = TRUE
cost = 50
power_type = /datum/action/innate/ai/break_air_alarms
- unlock_text = "You remove the safety overrides on all air alarms, but you leave the confirm prompts open. You can hit 'Yes' at any time... you bastard."
+ unlock_text = span_notice("You remove the safety overrides on all air alarms, but you leave the confirm prompts open. You can hit 'Yes' at any time... you bastard.")
unlock_sound = 'sound/effects/space_wind.ogg'
/datum/action/innate/ai/break_air_alarms
@@ -561,7 +562,7 @@ GLOBAL_LIST_INIT(blacklisted_malf_machines, typecacheof(list(
if(!is_station_level(AA.z))
continue
AA.obj_flags |= EMAGGED
- to_chat(owner, "All air alarm safeties on the station have been overridden. Air alarms may now use the Flood environmental mode.")
+ to_chat(owner, span_notice("All air alarm safeties on the station have been overridden. Air alarms may now use the Flood environmental mode."))
owner.playsound_local(owner, 'sound/machines/terminal_off.ogg', 50, 0)
@@ -572,7 +573,7 @@ GLOBAL_LIST_INIT(blacklisted_malf_machines, typecacheof(list(
description = "Overheats an electrical machine, causing a small explosion and destroying it. Two uses per purchase."
cost = 20
power_type = /datum/action/innate/ai/ranged/overload_machine
- unlock_text = "You enable the ability for the station's APCs to direct intense energy into machinery."
+ unlock_text = span_notice("You enable the ability for the station's APCs to direct intense energy into machinery.")
unlock_sound = 'sound/effects/comfyfire.ogg' //definitely not comfy, but it's the closest sound to "roaring fire" we have
/datum/action/innate/ai/ranged/overload_machine
@@ -594,8 +595,8 @@ GLOBAL_LIST_INIT(blacklisted_malf_machines, typecacheof(list(
/obj/effect/proc_holder/ranged_ai/overload_machine
active = FALSE
ranged_mousepointer = 'icons/effects/overload_machine_target.dmi'
- enable_text = "You tap into the station's powernet. Click on a machine to detonate it, or use the ability again to cancel."
- disable_text = "You release your hold on the powernet."
+ enable_text = span_notice("You tap into the station's powernet. Click on a machine to detonate it, or use the ability again to cancel.")
+ disable_text = span_notice("You release your hold on the powernet.")
/obj/effect/proc_holder/ranged_ai/overload_machine/InterceptClickOn(mob/living/caller, params, obj/machinery/target)
if(..())
@@ -604,16 +605,16 @@ GLOBAL_LIST_INIT(blacklisted_malf_machines, typecacheof(list(
remove_ranged_ability()
return
if(!istype(target))
- to_chat(ranged_ability_user, "You can only overload machines!")
+ to_chat(ranged_ability_user, span_warning("You can only overload machines!"))
return
if(is_type_in_typecache(target, GLOB.blacklisted_malf_machines))
- to_chat(ranged_ability_user, "You cannot overload that device!")
+ to_chat(ranged_ability_user, span_warning("You cannot overload that device!"))
return
ranged_ability_user.playsound_local(ranged_ability_user, "sparks", 50, 0)
attached_action.adjust_uses(-1)
- target.audible_message("You hear a loud electrical buzzing sound coming from [target]!")
+ target.audible_message(span_userdanger("You hear a loud electrical buzzing sound coming from [target]!"))
addtimer(CALLBACK(attached_action, TYPE_PROC_REF(/datum/action/innate/ai/ranged/overload_machine, detonate_machine), target), 50) //kaboom!
- remove_ranged_ability("Overcharging machine...")
+ remove_ranged_ability(span_danger("Overcharging machine..."))
return TRUE
@@ -624,7 +625,7 @@ GLOBAL_LIST_INIT(blacklisted_malf_machines, typecacheof(list(
description = "Overrides a machine's programming, causing it to rise up and attack everyone except other machines. Four uses."
cost = 30
power_type = /datum/action/innate/ai/ranged/override_machine
- unlock_text = "You procure a virus from the Space Dark Web and distribute it to the station's machines."
+ unlock_text = span_notice("You procure a virus from the Space Dark Web and distribute it to the station's machines.")
unlock_sound = 'sound/machines/airlock_alien_prying.ogg'
/datum/action/innate/ai/ranged/override_machine
@@ -641,8 +642,8 @@ GLOBAL_LIST_INIT(blacklisted_malf_machines, typecacheof(list(
/obj/effect/proc_holder/ranged_ai/override_machine
active = FALSE
ranged_mousepointer = 'icons/effects/override_machine_target.dmi'
- enable_text = "You tap into the station's powernet. Click on a machine to animate it, or use the ability again to cancel."
- disable_text = "You release your hold on the powernet."
+ enable_text = span_notice("You tap into the station's powernet. Click on a machine to animate it, or use the ability again to cancel.")
+ disable_text = span_notice("You release your hold on the powernet.")
/obj/effect/proc_holder/ranged_ai/override_machine/InterceptClickOn(mob/living/caller, params, obj/machinery/target)
if(..())
@@ -651,16 +652,16 @@ GLOBAL_LIST_INIT(blacklisted_malf_machines, typecacheof(list(
remove_ranged_ability()
return
if(!istype(target))
- to_chat(ranged_ability_user, "You can only animate machines!")
+ to_chat(ranged_ability_user, span_warning("You can only animate machines!"))
return
if(!target.can_be_overridden() || is_type_in_typecache(target, GLOB.blacklisted_malf_machines))
- to_chat(ranged_ability_user, "That machine can't be overridden!")
+ to_chat(ranged_ability_user, span_warning("That machine can't be overridden!"))
return
ranged_ability_user.playsound_local(ranged_ability_user, 'sound/misc/interference.ogg', 50, 0)
attached_action.adjust_uses(-1)
- target.audible_message("You hear a loud electrical buzzing sound coming from [target]!")
+ target.audible_message(span_userdanger("You hear a loud electrical buzzing sound coming from [target]!"))
addtimer(CALLBACK(attached_action, TYPE_PROC_REF(/datum/action/innate/ai/ranged/override_machine, animate_machine), target), 50) //kabeep!
- remove_ranged_ability("Sending override signal...")
+ remove_ranged_ability(span_danger("Sending override signal..."))
return TRUE
@@ -672,7 +673,7 @@ GLOBAL_LIST_INIT(blacklisted_malf_machines, typecacheof(list(
cost = 100
one_purchase = TRUE
power_type = /datum/action/innate/ai/place_transformer
- unlock_text = "You make contact with Space Amazon and request a robotics factory for delivery."
+ unlock_text = span_notice("You make contact with Space Amazon and request a robotics factory for delivery.")
unlock_sound = 'sound/machines/ping.ogg'
/datum/action/innate/ai/place_transformer
@@ -704,7 +705,7 @@ GLOBAL_LIST_INIT(blacklisted_malf_machines, typecacheof(list(
conveyor.masterAI = owner
playsound(T, 'sound/effects/phasein.ogg', 100, 1)
owner_AI.can_shunt = FALSE
- to_chat(owner, "You are no longer able to shunt your core to APCs.")
+ to_chat(owner, span_warning("You are no longer able to shunt your core to APCs."))
adjust_uses(-1)
/mob/living/silicon/ai/proc/remove_transformer_image(client/C, image/I, turf/T)
@@ -736,7 +737,7 @@ GLOBAL_LIST_INIT(blacklisted_malf_machines, typecacheof(list(
I.icon_state = "[success ? "green" : "red"]Overlay" //greenOverlay and redOverlay for success and failure respectively
addtimer(CALLBACK(src, PROC_REF(remove_transformer_image), client, I, T), 30)
if(!success)
- to_chat(src, "[alert_msg]")
+ to_chat(src, span_warning("[alert_msg]"))
return success
@@ -747,7 +748,7 @@ GLOBAL_LIST_INIT(blacklisted_malf_machines, typecacheof(list(
description = "Attempts to overload the lighting circuits on the station, destroying some bulbs. Three uses."
cost = 15
power_type = /datum/action/innate/ai/blackout
- unlock_text = "You hook into the powernet and route bonus power towards the station's lighting."
+ unlock_text = span_notice("You hook into the powernet and route bonus power towards the station's lighting.")
unlock_sound = "sparks"
/datum/action/innate/ai/blackout
@@ -767,13 +768,13 @@ GLOBAL_LIST_INIT(blacklisted_malf_machines, typecacheof(list(
apc.overload_lighting()
else
apc.overload++
- to_chat(owner, "Overcurrent applied to the powernet.")
+ to_chat(owner, span_notice("Overcurrent applied to the powernet."))
owner.playsound_local(owner, "sparks", 50, 0)
adjust_uses(-1)
if(QDELETED(src) || uses) //Not sure if not having src here would cause a runtime, so it's here to be safe
return
desc = "[initial(desc)] It has [uses] use\s remaining."
- UpdateButtons()
+ build_all_button_icons()
//Disable Emergency Lights
/datum/AI_Module/small/emergency_lights
@@ -783,7 +784,7 @@ GLOBAL_LIST_INIT(blacklisted_malf_machines, typecacheof(list(
cost = 10
one_purchase = TRUE
power_type = /datum/action/innate/ai/emergency_lights
- unlock_text = "You hook into the powernet and locate the connections between light fixtures and their fallbacks."
+ unlock_text = span_notice("You hook into the powernet and locate the connections between light fixtures and their fallbacks.")
unlock_sound = "sparks"
/datum/action/innate/ai/emergency_lights
@@ -798,7 +799,7 @@ GLOBAL_LIST_INIT(blacklisted_malf_machines, typecacheof(list(
L.no_emergency = TRUE
INVOKE_ASYNC(L, TYPE_PROC_REF(/obj/machinery/light, update), FALSE)
CHECK_TICK
- to_chat(owner, "Emergency light connections severed.")
+ to_chat(owner, span_notice("Emergency light connections severed."))
owner.playsound_local(owner, 'sound/effects/light_flicker.ogg', 50, FALSE)
@@ -810,7 +811,7 @@ GLOBAL_LIST_INIT(blacklisted_malf_machines, typecacheof(list(
cost = 10
one_purchase = TRUE
power_type = /datum/action/innate/ai/reactivate_cameras
- unlock_text = "You deploy nanomachines to the cameranet."
+ unlock_text = span_notice("You deploy nanomachines to the cameranet.")
unlock_sound = 'sound/items/wirecutter.ogg'
/datum/action/innate/ai/reactivate_cameras
@@ -836,13 +837,13 @@ GLOBAL_LIST_INIT(blacklisted_malf_machines, typecacheof(list(
C.view_range = initial(C.view_range)
fixed_cameras++
uses-- //Not adjust_uses() so it doesn't automatically delete or show a message
- to_chat(owner, "Diagnostic complete! Cameras reactivated: [fixed_cameras]. Reactivations remaining: [uses].")
+ to_chat(owner, span_notice("Diagnostic complete! Cameras reactivated: [fixed_cameras]. Reactivations remaining: [uses]."))
owner.playsound_local(owner, 'sound/items/wirecutter.ogg', 50, 0)
adjust_uses(0, TRUE) //Checks the uses remaining
if(QDELETED(src) || !uses) //Not sure if not having src here would cause a runtime, so it's here to be safe
return
desc = "[initial(desc)] It has [uses] use\s remaining."
- UpdateButtons()
+ build_all_button_icons()
//Upgrade Camera Network: EMP-proofs all cameras, in addition to giving them X-ray vision.
/datum/AI_Module/large/upgrade_cameras
@@ -853,7 +854,7 @@ GLOBAL_LIST_INIT(blacklisted_malf_machines, typecacheof(list(
one_purchase = TRUE
cost = 35 //Decent price for omniscience!
upgrade = TRUE
- unlock_text = "OTA firmware distribution complete! Cameras upgraded: CAMSUPGRADED. Light amplification system online."
+ unlock_text = span_notice("OTA firmware distribution complete! Cameras upgraded: CAMSUPGRADED. Light amplification system online.")
unlock_sound = 'sound/items/rped.ogg'
/datum/AI_Module/large/upgrade_cameras/upgrade(mob/living/silicon/ai/AI)
@@ -888,7 +889,7 @@ GLOBAL_LIST_INIT(blacklisted_malf_machines, typecacheof(list(
cost = 30
one_purchase = TRUE
upgrade = TRUE
- unlock_text = "OTA firmware distribution complete! Cameras upgraded: Enhanced surveillance package online."
+ unlock_text = span_notice("OTA firmware distribution complete! Cameras upgraded: Enhanced surveillance package online.")
unlock_sound = 'sound/items/rped.ogg'
/datum/AI_Module/large/eavesdrop/upgrade(mob/living/silicon/ai/AI)
diff --git a/code/modules/clothing/chameleon.dm b/code/modules/clothing/chameleon.dm
index b3030b67ecba..1bd0b759b162 100644
--- a/code/modules/clothing/chameleon.dm
+++ b/code/modules/clothing/chameleon.dm
@@ -2,13 +2,13 @@
/datum/action/item_action/chameleon/drone/randomise
name = "Randomise Headgear"
- icon_icon = 'icons/mob/actions/actions_items.dmi'
+ button_icon = 'icons/mob/actions/actions_items.dmi'
button_icon_state = "random"
-/datum/action/item_action/chameleon/drone/randomise/Trigger()
- if(!IsAvailable())
+/datum/action/item_action/chameleon/drone/randomise/do_effect(trigger_flags)
+ . = ..()
+ if(!.)
return
-
// Damn our lack of abstract interfeces
if (istype(target, /obj/item/clothing/head/chameleon/drone))
var/obj/item/clothing/head/chameleon/drone/X = target
@@ -22,7 +22,7 @@
/datum/action/item_action/chameleon/drone/togglehatmask
name = "Toggle Headgear Mode"
- icon_icon = 'icons/mob/actions/actions_silicon.dmi'
+ button_icon = 'icons/mob/actions/actions_silicon.dmi'
/datum/action/item_action/chameleon/drone/togglehatmask/New()
..()
@@ -32,19 +32,17 @@
if (istype(target, /obj/item/clothing/mask/chameleon/drone))
button_icon_state = "drone_camogear_mask"
-/datum/action/item_action/chameleon/drone/togglehatmask/Trigger()
- if(!IsAvailable())
+/datum/action/item_action/chameleon/drone/togglehatmask/do_effect(trigger_flags)
+ . = ..()
+ if(!.)
return
-
// No point making the code more complicated if no non-drone
// is ever going to use one of these
- var/mob/living/simple_animal/drone/D
+ var/mob/living/simple_animal/drone/D = owner
- if(istype(owner, /mob/living/simple_animal/drone))
- D = owner
- else
- return
+ if(!istype(owner, /mob/living/simple_animal/drone))
+ return FALSE
// The drone unEquip() proc sets head to null after dropping
// an item, so we need to keep a reference to our old headgear
@@ -58,13 +56,13 @@
new_headgear = new /obj/item/clothing/head/chameleon/drone()
else
to_chat(owner, "You shouldn't be able to toggle a camogear helmetmask if you're not wearing it")
- if(new_headgear)
- // Force drop the item in the headslot, even though
- // it's TRAIT_NODROP
- D.dropItemToGround(target, TRUE)
- qdel(old_headgear)
- // where is `ITEM_SLOT_HEAD` defined? WHO KNOWS
- D.equip_to_slot(new_headgear, ITEM_SLOT_HEAD)
+ return FALSE
+ // Force drop the item in the headslot, even though
+ // it's TRAIT_NODROP
+ D.dropItemToGround(target, TRUE)
+ qdel(old_headgear)
+ // where is `ITEM_SLOT_HEAD` defined? WHO KNOWS
+ D.equip_to_slot(new_headgear, ITEM_SLOT_HEAD)
return TRUE
@@ -87,14 +85,17 @@
sortTim(standard_outfit_options, GLOBAL_PROC_REF(cmp_text_asc))
outfit_options = standard_outfit_options
-/datum/action/chameleon_outfit/Trigger()
+/datum/action/chameleon_outfit/Trigger(trigger_flags)
+ . = ..()
+ if(!.)
+ return FALSE
return select_outfit(owner)
/datum/action/chameleon_outfit/proc/select_outfit(mob/user)
- if(!user || !IsAvailable())
+ if(!user || !IsAvailable(feedback = TRUE))
return FALSE
var/selected = input("Select outfit to change into", "Chameleon Outfit") as null|anything in outfit_options
- if(!IsAvailable() || QDELETED(src) || QDELETED(user))
+ if(!IsAvailable(feedback = TRUE) || QDELETED(src) || QDELETED(user))
return FALSE
var/outfit_type = outfit_options[selected]
if(!outfit_type)
@@ -163,7 +164,7 @@
/datum/action/item_action/chameleon/change/proc/initialize_disguises()
name = "Change [chameleon_name] Appearance"
- UpdateButtons()
+ build_all_button_icons()
chameleon_blacklist |= typecacheof(target.type)
for(var/V in typesof(chameleon_type))
@@ -180,11 +181,11 @@
var/picked_name
picked_name = input("Select [chameleon_name] to change into", "Chameleon [chameleon_name]", picked_name) as null|anything in chameleon_list
if(!picked_name)
- return
+ return FALSE
picked_item = chameleon_list[picked_name]
if(!picked_item)
- return
- update_look(user, picked_item)
+ return FALSE
+ return update_look(user, picked_item)
/datum/action/item_action/chameleon/change/proc/random_look(mob/user)
var/picked_name = pick(chameleon_list)
@@ -201,15 +202,17 @@
update_item(chameleon_list[picked_name])
/datum/action/item_action/chameleon/change/proc/update_look(mob/user, obj/item/picked_item)
- if(isliving(user))
- var/mob/living/C = user
- if(C.stat != CONSCIOUS)
- return
+ if(!isliving(user))
+ return FALSE
+ var/mob/living/C = user
+ if(C.stat != CONSCIOUS)
+ return FALSE
- update_item(picked_item)
- var/obj/item/thing = target
- thing.update_slot_icon()
- UpdateButtons()
+ update_item(picked_item)
+ var/obj/item/thing = target
+ thing.update_slot_icon()
+ build_all_button_icons()
+ return TRUE
/datum/action/item_action/chameleon/change/proc/update_item(obj/item/picked_item)
var/obj/item/chameleon_item = target
@@ -231,8 +234,11 @@
chameleon_item.icon = initial(picked_item.icon)
/datum/action/item_action/chameleon/change/pda/update_item(obj/item/pda/picked_item)
+ . = ..()
+ if(!.)
+ return
if(!istype(target, /obj/item/pda))
- return ..()
+ return
var/obj/item/pda/P = target
P.name = initial(picked_item.name)
P.desc = initial(picked_item.desc)
@@ -242,10 +248,7 @@
P.set_new_overlays()
P.update_icon()
-/datum/action/item_action/chameleon/change/Trigger()
- if(!IsAvailable())
- return
-
+/datum/action/item_action/chameleon/change/do_effect(trigger_flags)
select_look(owner)
return TRUE
@@ -293,7 +296,7 @@ CHAMELEON_CLOTHING_DEFINE(/obj/item/clothing/under/chameleon)
/obj/item/clothing/under/chameleon/Initialize(mapload)
. = ..()
- chameleon_action = new(src)
+ chameleon_action = add_item_action(/datum/action/item_action/chameleon/change)
chameleon_action.chameleon_type = /obj/item/clothing/under
chameleon_action.chameleon_name = "Jumpsuit"
chameleon_action.chameleon_blacklist = typecacheof(list(/obj/item/clothing/under, /obj/item/clothing/under/color, /obj/item/clothing/under/rank, /obj/item/clothing/under/changeling), only_root_path = TRUE)
@@ -322,7 +325,7 @@ CHAMELEON_CLOTHING_DEFINE(/obj/item/clothing/suit/chameleon)
/obj/item/clothing/suit/chameleon/Initialize(mapload)
. = ..()
- chameleon_action = new(src)
+ chameleon_action = add_item_action(/datum/action/item_action/chameleon/change)
chameleon_action.chameleon_type = /obj/item/clothing/suit
chameleon_action.chameleon_name = "Suit"
chameleon_action.chameleon_blacklist = typecacheof(list(/obj/item/clothing/suit/armor/abductor, /obj/item/clothing/suit/changeling), only_root_path = TRUE)
@@ -350,7 +353,7 @@ CHAMELEON_CLOTHING_DEFINE(/obj/item/clothing/glasses/chameleon)
/obj/item/clothing/glasses/chameleon/Initialize(mapload)
. = ..()
- chameleon_action = new(src)
+ chameleon_action = add_item_action(/datum/action/item_action/chameleon/change)
chameleon_action.chameleon_type = /obj/item/clothing/glasses
chameleon_action.chameleon_name = "Glasses"
chameleon_action.chameleon_blacklist = typecacheof(/obj/item/clothing/glasses/changeling, only_root_path = TRUE)
@@ -382,7 +385,7 @@ CHAMELEON_CLOTHING_DEFINE(/obj/item/clothing/gloves/chameleon/insulated)
/obj/item/clothing/gloves/chameleon/Initialize(mapload)
. = ..()
- chameleon_action = new(src)
+ chameleon_action = add_item_action(/datum/action/item_action/chameleon/change)
chameleon_action.chameleon_type = /obj/item/clothing/gloves
chameleon_action.chameleon_name = "Gloves"
chameleon_action.chameleon_blacklist = typecacheof(list(/obj/item/clothing/gloves, /obj/item/clothing/gloves/color, /obj/item/clothing/gloves/changeling), only_root_path = TRUE)
@@ -410,7 +413,7 @@ CHAMELEON_CLOTHING_DEFINE(/obj/item/clothing/head/chameleon)
/obj/item/clothing/head/chameleon/Initialize(mapload)
. = ..()
- chameleon_action = new(src)
+ chameleon_action = add_item_action(/datum/action/item_action/chameleon/change)
chameleon_action.chameleon_type = /obj/item/clothing/head
chameleon_action.chameleon_name = "Hat"
chameleon_action.chameleon_blacklist = typecacheof(/obj/item/clothing/head/changeling, only_root_path = TRUE)
@@ -436,10 +439,10 @@ CHAMELEON_CLOTHING_DEFINE(/obj/item/clothing/head/chameleon)
. = ..()
ADD_TRAIT(src, TRAIT_NODROP, ABSTRACT_ITEM_TRAIT)
chameleon_action.random_look()
- var/datum/action/item_action/chameleon/drone/togglehatmask/togglehatmask_action = new(src)
- togglehatmask_action.UpdateButtons()
- var/datum/action/item_action/chameleon/drone/randomise/randomise_action = new(src)
- randomise_action.UpdateButtons()
+ var/datum/action/item_action/chameleon/drone/togglehatmask/togglehatmask_action = add_item_action(/datum/action/item_action/chameleon/drone/togglehatmask)
+ togglehatmask_action.build_all_button_icons()
+ var/datum/action/item_action/chameleon/drone/randomise/randomise_action = add_item_action(/datum/action/item_action/chameleon/drone/randomise)
+ randomise_action.build_all_button_icons()
CHAMELEON_CLOTHING_DEFINE(/obj/item/clothing/mask/chameleon)
name = "gas mask"
@@ -460,7 +463,7 @@ CHAMELEON_CLOTHING_DEFINE(/obj/item/clothing/mask/chameleon)
/obj/item/clothing/mask/chameleon/Initialize(mapload)
. = ..()
- chameleon_action = new(src)
+ chameleon_action = add_item_action(/datum/action/item_action/chameleon/change)
chameleon_action.chameleon_type = /obj/item/clothing/mask
chameleon_action.chameleon_name = "Mask"
chameleon_action.chameleon_blacklist = typecacheof(/obj/item/clothing/mask/changeling, only_root_path = TRUE)
@@ -490,10 +493,10 @@ CHAMELEON_CLOTHING_DEFINE(/obj/item/clothing/mask/chameleon)
. = ..()
ADD_TRAIT(src, TRAIT_NODROP, ABSTRACT_ITEM_TRAIT)
chameleon_action.random_look()
- var/datum/action/item_action/chameleon/drone/togglehatmask/togglehatmask_action = new(src)
- togglehatmask_action.UpdateButtons()
- var/datum/action/item_action/chameleon/drone/randomise/randomise_action = new(src)
- randomise_action.UpdateButtons()
+ var/datum/action/item_action/chameleon/drone/togglehatmask/togglehatmask_action = add_item_action(/datum/action/item_action/chameleon/drone/togglehatmask)
+ togglehatmask_action.build_all_button_icons()
+ var/datum/action/item_action/chameleon/drone/randomise/randomise_action = add_item_action(/datum/action/item_action/chameleon/drone/randomise)
+ randomise_action.build_all_button_icons()
/obj/item/clothing/mask/chameleon/drone/attack_self(mob/user)
to_chat(user, "[src] does not have a voice changer.")
@@ -511,7 +514,7 @@ CHAMELEON_CLOTHING_DEFINE(/obj/item/clothing/shoes/chameleon)
/obj/item/clothing/shoes/chameleon/Initialize(mapload)
. = ..()
- chameleon_action = new(src)
+ chameleon_action = add_item_action(/datum/action/item_action/chameleon/change)
chameleon_action.chameleon_type = /obj/item/clothing/shoes
chameleon_action.chameleon_name = "Shoes"
chameleon_action.chameleon_blacklist = typecacheof(/obj/item/clothing/shoes/changeling, only_root_path = TRUE)
@@ -539,7 +542,7 @@ CHAMELEON_CLOTHING_DEFINE(/obj/item/storage/backpack/chameleon)
/obj/item/storage/backpack/chameleon/Initialize(mapload)
. = ..()
- chameleon_action = new(src)
+ chameleon_action = add_item_action(/datum/action/item_action/chameleon/change)
chameleon_action.chameleon_type = /obj/item/storage/backpack
chameleon_action.chameleon_name = "Backpack"
chameleon_action.initialize_disguises()
@@ -562,7 +565,7 @@ CHAMELEON_CLOTHING_DEFINE(/obj/item/storage/belt/chameleon)
/obj/item/storage/belt/chameleon/Initialize(mapload)
. = ..()
- chameleon_action = new(src)
+ chameleon_action = add_item_action(/datum/action/item_action/chameleon/change)
chameleon_action.chameleon_type = /obj/item/storage/belt
chameleon_action.chameleon_name = "Belt"
chameleon_action.initialize_disguises()
@@ -588,7 +591,7 @@ CHAMELEON_CLOTHING_DEFINE(/obj/item/radio/headset/chameleon)
/obj/item/radio/headset/chameleon/Initialize(mapload)
. = ..()
- chameleon_action = new(src)
+ chameleon_action = add_item_action(/datum/action/item_action/chameleon/change)
chameleon_action.chameleon_type = /obj/item/radio/headset
chameleon_action.chameleon_name = "Headset"
chameleon_action.initialize_disguises()
@@ -609,7 +612,7 @@ CHAMELEON_CLOTHING_DEFINE(/obj/item/pda/chameleon)
/obj/item/pda/chameleon/Initialize(mapload)
. = ..()
- chameleon_action = new(src)
+ chameleon_action = add_item_action(/datum/action/item_action/chameleon/change)
chameleon_action.chameleon_type = /obj/item/pda
chameleon_action.chameleon_name = "PDA"
chameleon_action.chameleon_blacklist = typecacheof(list(/obj/item/pda/heads, /obj/item/pda/ai, /obj/item/pda/ai/pai), only_root_path = TRUE)
@@ -630,7 +633,7 @@ CHAMELEON_CLOTHING_DEFINE(/obj/item/stamp/chameleon)
/obj/item/stamp/chameleon/Initialize(mapload)
. = ..()
- chameleon_action = new(src)
+ chameleon_action = add_item_action(/datum/action/item_action/chameleon/change)
chameleon_action.chameleon_type = /obj/item/stamp
chameleon_action.chameleon_name = "Stamp"
chameleon_action.initialize_disguises()
@@ -652,7 +655,7 @@ CHAMELEON_CLOTHING_DEFINE(/obj/item/clothing/neck/cloak/chameleon)
/obj/item/clothing/neck/cloak/chameleon/Initialize(mapload)
. = ..()
- chameleon_action = new(src)
+ chameleon_action = add_item_action(/datum/action/item_action/chameleon/change)
chameleon_action.chameleon_type = /obj/item/clothing/neck
chameleon_action.chameleon_name = "Cloak"
chameleon_action.initialize_disguises()
diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm
index e3f4e5213e22..6e34b8af1a40 100644
--- a/code/modules/clothing/clothing.dm
+++ b/code/modules/clothing/clothing.dm
@@ -402,7 +402,7 @@ BLIND // can't see anything
C.head_update(src, forced = 1)
for(var/X in actions)
var/datum/action/A = X
- A.UpdateButtons()
+ A.build_all_button_icons()
return TRUE
/obj/item/clothing/proc/visor_toggling() //handles all the actual toggling of flags
diff --git a/code/modules/clothing/glasses/_glasses.dm b/code/modules/clothing/glasses/_glasses.dm
index 11e22ed5a88d..c99a2fb317e4 100644
--- a/code/modules/clothing/glasses/_glasses.dm
+++ b/code/modules/clothing/glasses/_glasses.dm
@@ -432,7 +432,7 @@
/obj/item/clothing/glasses/thermal/syndi/New()
..()
- chameleon_action = new(src)
+ chameleon_action = add_item_action(/datum/action/item_action/chameleon/change)
chameleon_action.chameleon_type = /obj/item/clothing/glasses
chameleon_action.chameleon_name = "Glasses"
chameleon_action.chameleon_blacklist = typecacheof(/obj/item/clothing/glasses/changeling, only_root_path = TRUE)
diff --git a/code/modules/clothing/glasses/engine_goggles.dm b/code/modules/clothing/glasses/engine_goggles.dm
index 395eeaeaa666..42e5d0cef83f 100644
--- a/code/modules/clothing/glasses/engine_goggles.dm
+++ b/code/modules/clothing/glasses/engine_goggles.dm
@@ -62,7 +62,7 @@
update_icon()
for(var/X in actions)
var/datum/action/A = X
- A.UpdateButtons()
+ A.build_all_button_icons()
/obj/item/clothing/glasses/meson/engine/attack_self(mob/user)
toggle_mode(user, TRUE)
diff --git a/code/modules/clothing/glasses/hud.dm b/code/modules/clothing/glasses/hud.dm
index 733fc0195cb1..6c1bbf0952ac 100644
--- a/code/modules/clothing/glasses/hud.dm
+++ b/code/modules/clothing/glasses/hud.dm
@@ -163,7 +163,7 @@
/obj/item/clothing/glasses/hud/security/chameleon/New()
..()
- chameleon_action = new(src)
+ chameleon_action = add_item_action(/datum/action/item_action/chameleon/change)
chameleon_action.chameleon_type = /obj/item/clothing/glasses
chameleon_action.chameleon_name = "Glasses"
chameleon_action.chameleon_blacklist = typecacheof(/obj/item/clothing/glasses/changeling, only_root_path = TRUE)
diff --git a/code/modules/clothing/head/helmet.dm b/code/modules/clothing/head/helmet.dm
index 4f370866b371..c75a5e74a1fe 100644
--- a/code/modules/clothing/head/helmet.dm
+++ b/code/modules/clothing/head/helmet.dm
@@ -23,7 +23,7 @@
/obj/item/clothing/head/helmet/Initialize(mapload)
. = ..()
if(attached_light)
- alight = new(src)
+ alight = add_item_action(/datum/action/item_action/toggle_helmet_flashlight)
/obj/item/clothing/head/helmet/ComponentInitialize()
. = ..()
@@ -389,7 +389,7 @@
set_light(0)
for(var/X in actions)
var/datum/action/A = X
- A.UpdateButtons()
+ A.build_all_button_icons()
/obj/item/clothing/head/helmet/durathread
name = "makeshift helmet"
diff --git a/code/modules/clothing/masks/_masks.dm b/code/modules/clothing/masks/_masks.dm
index bc4fc4fe2375..2deb76da770a 100644
--- a/code/modules/clothing/masks/_masks.dm
+++ b/code/modules/clothing/masks/_masks.dm
@@ -75,7 +75,7 @@
if(!just_flavor)
to_chat(user, "You push \the [src] [mask_adjusted ? "out of the way" : "back into place"].")
user.wear_mask_update(src, toggle_off = mask_adjusted)
- user.update_action_buttons_icon() //when mask is adjusted out, we update all buttons icon so the user's potential internal tank correctly shows as off.
+ user.update_mob_action_buttons() //when mask is adjusted out, we update all buttons icon so the user's potential internal tank correctly shows as off.
else
to_chat(usr, "You adjust [src], it will now [mask_adjusted ? "not" : ""] obscure your identity while worn.")
return TRUE
diff --git a/code/modules/clothing/masks/gasmask.dm b/code/modules/clothing/masks/gasmask.dm
index 1c9b15b39889..d6b44eea671c 100644
--- a/code/modules/clothing/masks/gasmask.dm
+++ b/code/modules/clothing/masks/gasmask.dm
@@ -115,7 +115,7 @@
user.update_inv_wear_mask()
for(var/X in actions)
var/datum/action/A = X
- A.UpdateButtons()
+ A.build_all_button_icons()
to_chat(user, "Your Clown Mask has now morphed into [choice], all praise the Honkmother!")
return TRUE
@@ -181,7 +181,7 @@
user.update_inv_wear_mask()
for(var/X in actions)
var/datum/action/A = X
- A.UpdateButtons()
+ A.build_all_button_icons()
to_chat(user, "Your Mime Mask has now morphed into [choice]!")
return TRUE
@@ -274,7 +274,7 @@
user.update_inv_wear_mask()
for(var/X in actions)
var/datum/action/A = X
- A.UpdateButtons()
+ A.build_all_button_icons()
to_chat(M, "The Tiki Mask has now changed into the [choice] Mask!")
return TRUE
diff --git a/code/modules/clothing/masks/miscellaneous.dm b/code/modules/clothing/masks/miscellaneous.dm
index 9f837654a022..8c1a8ad9f54c 100644
--- a/code/modules/clothing/masks/miscellaneous.dm
+++ b/code/modules/clothing/masks/miscellaneous.dm
@@ -109,7 +109,7 @@
user.update_inv_wear_mask()
for(var/X in actions)
var/datum/action/A = X
- A.UpdateButtons()
+ A.build_all_button_icons()
to_chat(user, "Your Joy mask now has a [choice] Emotion!")
return TRUE
@@ -475,6 +475,6 @@
user.update_inv_wear_mask()
for(var/X in actions)
var/datum/action/A = X
- A.UpdateButtons()
+ A.build_all_button_icons()
to_chat(user, "Your paper mask now has a [choice] symbol!")
return TRUE
diff --git a/code/modules/clothing/shoes/magboots.dm b/code/modules/clothing/shoes/magboots.dm
index 304a4a3545f6..9cedf6983102 100644
--- a/code/modules/clothing/shoes/magboots.dm
+++ b/code/modules/clothing/shoes/magboots.dm
@@ -36,7 +36,7 @@
user.update_gravity(user.has_gravity())
for(var/X in actions)
var/datum/action/A = X
- A.UpdateButtons()
+ A.build_all_button_icons()
/obj/item/clothing/shoes/magboots/negates_gravity()
return clothing_flags & NOSLIP
diff --git a/code/modules/clothing/spacesuits/chronosuit.dm b/code/modules/clothing/spacesuits/chronosuit.dm
index 9e387dab3f68..df420feefe9f 100644
--- a/code/modules/clothing/spacesuits/chronosuit.dm
+++ b/code/modules/clothing/spacesuits/chronosuit.dm
@@ -91,7 +91,7 @@
if(camera)
camera.remove_target_ui()
camera.forceMove(user)
- teleport_now.UpdateButtons()
+ teleport_now.build_all_button_icons()
/obj/item/clothing/suit/space/chronos/proc/chronowalk(atom/location)
var/mob/living/carbon/human/user = src.loc
@@ -105,7 +105,7 @@
if(camera)
camera.remove_target_ui()
- teleport_now.UpdateButtons()
+ teleport_now.build_all_button_icons()
var/list/nonsafe_slots = list(ITEM_SLOT_BELT, ITEM_SLOT_BACK)
var/list/exposed = list()
@@ -312,16 +312,16 @@
/datum/action/innate/chrono_teleport
name = "Teleport Now"
- icon_icon = 'icons/mob/actions/actions_minor_antag.dmi'
+ button_icon = 'icons/mob/actions/actions_minor_antag.dmi'
button_icon_state = "chrono_phase"
check_flags = AB_CHECK_CONSCIOUS //|AB_CHECK_INSIDE
var/obj/item/clothing/suit/space/chronos/chronosuit = null
-/datum/action/innate/chrono_teleport/IsAvailable(silent = FALSE)
+/datum/action/innate/chrono_teleport/IsAvailable(feedback = TRUE)
return (chronosuit && chronosuit.activated && chronosuit.camera && !chronosuit.teleporting)
/datum/action/innate/chrono_teleport/Activate()
- if(!IsAvailable())
+ if(!IsAvailable(feedback = TRUE))
return
if(chronosuit.camera)
chronosuit.chronowalk(chronosuit.camera)
diff --git a/code/modules/clothing/spacesuits/hardsuit.dm b/code/modules/clothing/spacesuits/hardsuit.dm
index e6ed9c3d5115..c6c7b7036152 100644
--- a/code/modules/clothing/spacesuits/hardsuit.dm
+++ b/code/modules/clothing/spacesuits/hardsuit.dm
@@ -345,7 +345,7 @@
C.head_update(src, forced = 1)
for(var/X in actions)
var/datum/action/A = X
- A.UpdateButtons()
+ A.build_all_button_icons()
/obj/item/clothing/head/helmet/space/hardsuit/syndi/proc/toggle_hardsuit_mode(mob/user) //Helmet Toggles Suit Mode
if(linkedsuit)
@@ -937,7 +937,7 @@
set_light(0)
for(var/X in actions)
var/datum/action/A = X
- A.UpdateButtons()
+ A.build_all_button_icons()
/obj/item/clothing/head/helmet/space/hardsuit/lavaknight/update_overlays()
. = ..()
diff --git a/code/modules/clothing/suits/toggles.dm b/code/modules/clothing/suits/toggles.dm
index 9fc51b82871c..217b79d1475f 100644
--- a/code/modules/clothing/suits/toggles.dm
+++ b/code/modules/clothing/suits/toggles.dm
@@ -139,7 +139,7 @@
usr.update_inv_wear_suit()
for(var/X in actions)
var/datum/action/A = X
- A.UpdateButtons()
+ A.build_all_button_icons()
/obj/item/clothing/suit/toggle/examine(mob/user)
. = ..()
diff --git a/code/modules/clothing/suits/wiz_robe.dm b/code/modules/clothing/suits/wiz_robe.dm
index ebc590185cce..553d7ad6d252 100644
--- a/code/modules/clothing/suits/wiz_robe.dm
+++ b/code/modules/clothing/suits/wiz_robe.dm
@@ -175,7 +175,7 @@
/datum/action/item_action/stickmen
name = "Summon Stick Minions"
desc = "Allows you to summon faithful stickmen allies to aide you in battle."
- icon_icon = 'icons/mob/actions/actions_minor_antag.dmi'
+ button_icon = 'icons/mob/actions/actions_minor_antag.dmi'
button_icon_state = "art_summon"
var/ready = TRUE
var/list/summoned_stickmen = list()
@@ -222,7 +222,7 @@
. = ..()
UnregisterSignal(M, COMSIG_MOB_POINTED)
-/datum/action/item_action/stickmen/Trigger()
+/datum/action/item_action/stickmen/do_effect(trigger_flags)
. = ..()
if(!.)
return
@@ -249,6 +249,7 @@
RegisterSignal(S, COMSIG_PARENT_QDELETING, PROC_REF(remove_from_list))
ready = FALSE
addtimer(CALLBACK(src, PROC_REF(ready_again)), cooldown)
+ return TRUE
/datum/action/item_action/stickmen/proc/remove_from_list(datum/source, forced)
summoned_stickmen -= source
diff --git a/code/modules/detectivework/scanner.dm b/code/modules/detectivework/scanner.dm
index 8d09b73f864d..ed23d3620c2d 100644
--- a/code/modules/detectivework/scanner.dm
+++ b/code/modules/detectivework/scanner.dm
@@ -24,10 +24,15 @@
/datum/action/item_action/displayDetectiveScanResults
name = "Display Forensic Scanner Results"
-/datum/action/item_action/displayDetectiveScanResults/Trigger()
+/datum/action/item_action/displayDetectiveScanResults/do_effect(trigger_flags)
+ . = ..()
+ if(!.)
+ return
var/obj/item/detective_scanner/scanner = target
- if(istype(scanner))
- scanner.displayDetectiveScanResults(usr)
+ if(!istype(scanner))
+ return FALSE
+ scanner.displayDetectiveScanResults(usr)
+ return TRUE
/obj/item/detective_scanner/attack_self(mob/user)
if(log.len && !scanning)
diff --git a/code/modules/instruments/instruments/item.dm b/code/modules/instruments/instruments/item.dm
index 4c496212c84e..752ae4020134 100644
--- a/code/modules/instruments/instruments/item.dm
+++ b/code/modules/instruments/instruments/item.dm
@@ -227,6 +227,7 @@
force = 5
w_class = WEIGHT_CLASS_SMALL
actions_types = list(/datum/action/item_action/instrument)
+ action_slots = ALL
/obj/item/instrument/harmonica/proc/handle_speech(datum/source, list/speech_args)
if(song.playing && ismob(loc))
diff --git a/code/modules/mafia/controller.dm b/code/modules/mafia/controller.dm
index 0b94af15a784..ace7bcc2db18 100644
--- a/code/modules/mafia/controller.dm
+++ b/code/modules/mafia/controller.dm
@@ -1001,7 +1001,7 @@
/datum/action/innate/mafia_panel
name = "Mafia Panel"
desc = "Use this to play."
- icon_icon = 'icons/obj/mafia.dmi'
+ button_icon = 'icons/obj/mafia.dmi'
button_icon_state = "board"
var/datum/mafia_controller/parent
diff --git a/code/modules/mining/aux_base_camera.dm b/code/modules/mining/aux_base_camera.dm
index f4f91fe139f9..aabd6c1aac71 100644
--- a/code/modules/mining/aux_base_camera.dm
+++ b/code/modules/mining/aux_base_camera.dm
@@ -119,7 +119,7 @@
return ..()
/datum/action/innate/aux_base //Parent aux base action
- icon_icon = 'icons/mob/actions/actions_construction.dmi'
+ button_icon = 'icons/mob/actions/actions_construction.dmi'
var/mob/camera/aiEye/remote/base_construction/remote_eye //Console's eye mob
var/obj/machinery/computer/camera_advanced/base_construction/B //Console itself
diff --git a/code/modules/mining/equipment/kinetic_crusher.dm b/code/modules/mining/equipment/kinetic_crusher.dm
index 6da752f17dcb..d01492783757 100644
--- a/code/modules/mining/equipment/kinetic_crusher.dm
+++ b/code/modules/mining/equipment/kinetic_crusher.dm
@@ -19,6 +19,7 @@
attack_verb = list("smashed", "crushed", "cleaved", "chopped", "pulped")
sharpness = SHARP_EDGED
actions_types = list(/datum/action/item_action/toggle_light)
+ action_slots = ALL
obj_flags = UNIQUE_RENAME
var/list/trophies = list()
var/charged = TRUE
diff --git a/code/modules/mining/lavaland/necropolis_chests.dm b/code/modules/mining/lavaland/necropolis_chests.dm
index 0475b7075ae9..05d8a51bd430 100644
--- a/code/modules/mining/lavaland/necropolis_chests.dm
+++ b/code/modules/mining/lavaland/necropolis_chests.dm
@@ -321,22 +321,24 @@
return ..()
/obj/item/clothing/neck/necklace/memento_mori/proc/memento(mob/living/carbon/human/user)
- to_chat(user, "You feel your life being drained by the pendant...")
- if(do_after(user, 40, target = user))
- to_chat(user, "Your lifeforce is now linked to the pendant! You feel like removing it would kill you, and yet you instinctively know that until then, you won't die.")
- ADD_TRAIT(user, TRAIT_NODEATH, "memento_mori")
- ADD_TRAIT(user, TRAIT_NOHARDCRIT, "memento_mori")
- ADD_TRAIT(user, TRAIT_NOCRITDAMAGE, "memento_mori")
- icon_state = "memento_mori_active"
- active_owner = user
+ to_chat(user, span_warning("You feel your life being drained by the pendant..."))
+ if(!do_after(user, 40, target = user))
+ return FALSE
+ to_chat(user, span_notice("Your lifeforce is now linked to the pendant! You feel like removing it would kill you, and yet you instinctively know that until then, you won't die."))
+ ADD_TRAIT(user, TRAIT_NODEATH, "memento_mori")
+ ADD_TRAIT(user, TRAIT_NOHARDCRIT, "memento_mori")
+ ADD_TRAIT(user, TRAIT_NOCRITDAMAGE, "memento_mori")
+ icon_state = "memento_mori_active"
+ active_owner = user
+ return TRUE
/obj/item/clothing/neck/necklace/memento_mori/proc/mori()
icon_state = "memento_mori"
if(!active_owner)
- return
+ return FALSE
var/mob/living/carbon/human/H = active_owner //to avoid infinite looping when dust unequips the pendant
active_owner = null
- to_chat(H, "You feel your life rapidly slipping away from you!")
+ to_chat(H, span_userdanger("You feel your life rapidly slipping away from you!"))
H.dust(TRUE, TRUE)
/datum/action/item_action/hands_free/memento_mori
@@ -344,15 +346,23 @@
name = "Memento Mori"
desc = "Bind your life to the pendant."
-/datum/action/item_action/hands_free/memento_mori/Trigger()
+/datum/action/item_action/hands_free/memento_mori/do_effect(trigger_flags)
+ . = ..()
+ if(!.)
+ return
var/obj/item/clothing/neck/necklace/memento_mori/MM = target
+ if(!istype(MM))
+ return FALSE
+
if(!MM.active_owner)
- if(ishuman(owner))
- MM.memento(owner)
+ if(!ishuman(owner))
+ return FALSE
+ . = MM.memento(owner)
else
- to_chat(owner, "You try to free your lifeforce from the pendant...")
- if(do_after(owner, 40, target = owner))
- MM.mori()
+ to_chat(owner, span_warning("You try to free your lifeforce from the pendant..."))
+ if(!do_after(owner, 40, target = owner))
+ return FALSE
+ . = MM.mori()
//Wisp Lantern
/obj/item/wisp_lantern
@@ -1272,6 +1282,7 @@
attack_verb = list("clubbed", "beat", "pummeled")
hitsound = 'sound/weapons/sonic_jackhammer.ogg'
actions_types = list(/datum/action/item_action/vortex_recall, /datum/action/item_action/toggle_unfriendly_fire)
+ action_slots = ALL
var/cooldown_time = 20 //how long the cooldown between non-melee ranged attacks is
var/chaser_cooldown = 81 //how long the cooldown between firing chasers at mobs is
var/chaser_timer = 0 //what our current chaser cooldown is
@@ -1377,7 +1388,7 @@
playsound(T,'sound/magic/blind.ogg', 200, 1, -4)
new /obj/effect/temp_visual/hierophant/telegraph/teleport(T, user)
beacon = new/obj/effect/hierophant(T)
- user.update_action_buttons_icon()
+ user.update_mob_action_buttons()
user.visible_message("[user] places a strange machine beneath [user.p_their()] feet!", \
"You detach the hierophant beacon, allowing you to teleport yourself and any allies to it at any time!\n\
You can remove the beacon to place it again by striking it with the club.")
@@ -1397,7 +1408,7 @@
to_chat(user, "You don't have enough space to teleport from here!")
return
teleporting = TRUE //start channel
- user.update_action_buttons_icon()
+ user.update_mob_action_buttons()
user.visible_message("[user] starts to glow faintly...")
timer = world.time + 50
INVOKE_ASYNC(src, PROC_REF(prepare_icon_update))
@@ -1410,7 +1421,7 @@
if(is_blocked_turf(T, TRUE))
teleporting = FALSE
to_chat(user, "The beacon is blocked by something, preventing teleportation!")
- user.update_action_buttons_icon()
+ user.update_mob_action_buttons()
timer = world.time
INVOKE_ASYNC(src, PROC_REF(prepare_icon_update))
beacon.icon_state = "hierophant_tele_off"
@@ -1422,7 +1433,7 @@
if(!do_after(user, 3, target = user) || !user || !beacon || QDELETED(beacon)) //no walking away shitlord
teleporting = FALSE
if(user)
- user.update_action_buttons_icon()
+ user.update_mob_action_buttons()
timer = world.time
INVOKE_ASYNC(src, PROC_REF(prepare_icon_update))
if(beacon)
@@ -1431,7 +1442,7 @@
if(is_blocked_turf(T, TRUE))
teleporting = FALSE
to_chat(user, "The beacon is blocked by something, preventing teleportation!")
- user.update_action_buttons_icon()
+ user.update_mob_action_buttons()
timer = world.time
INVOKE_ASYNC(src, PROC_REF(prepare_icon_update))
beacon.icon_state = "hierophant_tele_off"
@@ -1459,7 +1470,7 @@
beacon.icon_state = "hierophant_tele_off"
teleporting = FALSE
if(user)
- user.update_action_buttons_icon()
+ user.update_mob_action_buttons()
/obj/item/hierophant_club/proc/teleport_mob(turf/source, mob/M, turf/target, mob/user)
var/turf/turf_to_teleport_to = get_step(target, get_dir(source, M)) //get position relative to caster
diff --git a/code/modules/mining/minebot.dm b/code/modules/mining/minebot.dm
index 75b647809a4f..fbc95ad4a823 100644
--- a/code/modules/mining/minebot.dm
+++ b/code/modules/mining/minebot.dm
@@ -224,7 +224,7 @@
/datum/action/innate/minedrone
check_flags = AB_CHECK_CONSCIOUS
- icon_icon = 'icons/mob/actions/actions_mecha.dmi'
+ button_icon = 'icons/mob/actions/actions_mecha.dmi'
background_icon_state = "bg_default"
/datum/action/innate/minedrone/toggle_light
diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm
index 3899e788df5b..9d04f7043c61 100644
--- a/code/modules/mob/dead/observer/observer.dm
+++ b/code/modules/mob/dead/observer/observer.dm
@@ -860,16 +860,23 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
/mob/dead/observer/reset_perspective(atom/A)
if(client)
if(ismob(client.eye) && (client.eye != src))
- var/mob/target = client.eye
- observetarget = null
- if(target.observers)
- target.observers -= src
- UNSETEMPTY(target.observers)
+ cleanup_observe()
if(..())
if(hud_used)
client.screen = list()
hud_used.show_hud(hud_used.hud_version)
+/mob/dead/observer/proc/cleanup_observe()
+ if(isnull(observetarget))
+ return
+ var/mob/target = observetarget
+ observetarget = null
+ client?.perspective = initial(client.perspective)
+ sight = initial(sight)
+ if(target)
+ hide_other_mob_action_buttons(target)
+ LAZYREMOVE(target.observers, src)
+
/mob/dead/observer/verb/observe()
set name = "Observe"
set category = "OOC"
diff --git a/code/modules/mob/living/carbon/alien/humanoid/alien_powers.dm b/code/modules/mob/living/carbon/alien/humanoid/alien_powers.dm
index bcb6c9b2969f..b4c78f9a4259 100644
--- a/code/modules/mob/living/carbon/alien/humanoid/alien_powers.dm
+++ b/code/modules/mob/living/carbon/alien/humanoid/alien_powers.dm
@@ -39,18 +39,18 @@ Doesn't work on other aliens/AI.*/
if(plasma_cost > 0)
return "[plasma_cost]"
-/obj/effect/proc_holder/alien/proc/cost_check(check_turf = FALSE, mob/living/carbon/user, silent = FALSE)
+/obj/effect/proc_holder/alien/proc/cost_check(check_turf = FALSE, mob/living/carbon/user, feedback = TRUE)
if(user.stat)
- if(!silent)
- to_chat(user, "You must be conscious to do this.")
+ if(feedback)
+ to_chat(user, span_noticealien("You must be conscious to do this."))
return FALSE
if(user.getPlasma() < plasma_cost)
- if(!silent)
- to_chat(user, "Not enough plasma stored.")
+ if(feedback)
+ to_chat(user, span_noticealien("Not enough plasma stored."))
return FALSE
if(check_turf && (!isturf(user.loc) || isspaceturf(user.loc)))
- if(!silent)
- to_chat(user, "Bad place for a garden!")
+ if(feedback)
+ to_chat(user, span_noticealien("Bad place for a garden!"))
return FALSE
return TRUE
@@ -73,7 +73,7 @@ Doesn't work on other aliens/AI.*/
if(locate(/obj/structure/alien/weeds/node) in get_turf(user))
to_chat(user, "There's already a weed node here.")
return FALSE
- user.visible_message("[user] has planted some alien weeds!")
+ user.visible_message(span_noticealien("[user] has planted some alien weeds!"))
new/obj/structure/alien/weeds/node(user.loc)
return TRUE
@@ -201,7 +201,7 @@ Doesn't work on other aliens/AI.*/
/obj/effect/proc_holder/alien/neurotoxin/update_icon()
. = ..()
action.button_icon_state = "alien_neurotoxin_[active]"
- action.UpdateButtons()
+ action.build_all_button_icons()
/obj/effect/proc_holder/alien/neurotoxin/InterceptClickOn(mob/living/caller, params, atom/target)
if(..())
@@ -334,7 +334,7 @@ Doesn't work on other aliens/AI.*/
for(var/X in abilities)
var/obj/effect/proc_holder/alien/APH = X
if(APH.has_action)
- APH.action.UpdateButtons()
+ APH.action.build_all_button_icons()
return TRUE
/mob/living/carbon/alien/adjustPlasma(amount)
diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm
index 47c9c61e343e..4b2f0cfa9f1d 100644
--- a/code/modules/mob/living/carbon/carbon.dm
+++ b/code/modules/mob/living/carbon/carbon.dm
@@ -831,7 +831,7 @@
else
clear_alert("handcuffed")
SEND_SIGNAL(src, COMSIG_CLEAR_MOOD_EVENT, "handcuffed")
- update_action_buttons_icon() //some of our action buttons might be unusable when we're handcuffed.
+ update_mob_action_buttons() //some of our action buttons might be unusable when we're handcuffed.
update_inv_handcuffed()
update_hud_handcuffed()
diff --git a/code/modules/mob/living/carbon/human/innate_abilities/blobform.dm b/code/modules/mob/living/carbon/human/innate_abilities/blobform.dm
index 177444503b9e..a0ed1600f600 100644
--- a/code/modules/mob/living/carbon/human/innate_abilities/blobform.dm
+++ b/code/modules/mob/living/carbon/human/innate_abilities/blobform.dm
@@ -3,7 +3,7 @@
name = "Puddle Transformation"
check_flags = AB_CHECK_CONSCIOUS
button_icon_state = "slimepuddle"
- icon_icon = 'icons/mob/actions/actions_slime.dmi'
+ button_icon = 'icons/mob/actions/actions_slime.dmi'
background_icon_state = "bg_alien"
required_mobility_flags = MOBILITY_STAND
var/is_puddle = FALSE
@@ -18,10 +18,12 @@
var/transforming = FALSE
var/last_use
-/datum/action/innate/ability/slime_blobform/IsAvailable()
+/datum/action/innate/ability/slime_blobform/IsAvailable(feedback)
if(!transforming)
return ..()
else
+ if(feedback)
+ owner.balloon_alert(owner, "busy!")
return FALSE
/datum/action/innate/ability/slime_blobform/Remove(mob/M)
@@ -36,8 +38,8 @@
if(HAS_TRAIT(I, TRAIT_NODROP))
to_chat(owner, "There's something stuck to your hand, stopping you from transforming!")
return
- if(IsAvailable())
- UpdateButtons()
+ if(IsAvailable(TRUE))
+ build_all_button_icons()
var/mutcolor = owner.get_ability_property(INNATE_ABILITY_SLIME_BLOBFORM, PROPERTY_BLOBFORM_COLOR) || ("#" + H.dna.features["mcolor"])
if(!is_puddle)
if(CHECK_MOBILITY(H, MOBILITY_USE)) //if we can use items, we can turn into a puddle
@@ -78,7 +80,7 @@
owner.update_antag_overlays()
transforming = FALSE
- UpdateButtons()
+ build_all_button_icons()
else
detransform()
else
@@ -109,4 +111,4 @@
squeak.RemoveComponent()
H.regenerate_icons()
transforming = FALSE
- UpdateButtons()
+ build_all_button_icons()
diff --git a/code/modules/mob/living/carbon/human/innate_abilities/coiling.dm b/code/modules/mob/living/carbon/human/innate_abilities/coiling.dm
index 4df77a489b20..448f9e25df69 100644
--- a/code/modules/mob/living/carbon/human/innate_abilities/coiling.dm
+++ b/code/modules/mob/living/carbon/human/innate_abilities/coiling.dm
@@ -3,7 +3,7 @@
name = "Coil Grabbed Mob"
check_flags = AB_CHECK_CONSCIOUS
button_icon_state = "coil_icon"
- icon_icon = 'icons/mob/actions/actions_snake.dmi'
+ button_icon = 'icons/mob/actions/actions_snake.dmi'
background_icon_state = "bg_alien"
required_mobility_flags = MOBILITY_STAND
var/currently_coiling = FALSE
@@ -12,7 +12,7 @@
/datum/action/innate/ability/coiling/Activate()
// make sure they meet the mobility/check flags
- if(IsAvailable())
+ if(IsAvailable(feedback = TRUE))
// check that the user has grabbed someone and they are not currently coiling someone
if(ishuman(owner.pulling) && !currently_coiling)
coil_mob(owner.pulling)
diff --git a/code/modules/mob/living/carbon/human/innate_abilities/customization.dm b/code/modules/mob/living/carbon/human/innate_abilities/customization.dm
index 621dc58650f2..45766f4613c5 100644
--- a/code/modules/mob/living/carbon/human/innate_abilities/customization.dm
+++ b/code/modules/mob/living/carbon/human/innate_abilities/customization.dm
@@ -2,7 +2,7 @@
name = "Alter Form"
check_flags = AB_CHECK_CONSCIOUS
button_icon_state = "alter_form" //placeholder
- icon_icon = 'modular_citadel/icons/mob/actions/actions_slime.dmi'
+ button_icon = 'modular_citadel/icons/mob/actions/actions_slime.dmi'
background_icon_state = "bg_alien"
/datum/action/innate/ability/humanoid_customization/Activate()
@@ -116,7 +116,7 @@
if(new_snout)
H.dna.features["mam_snouts"] = new_snout
H.update_body()
-
+
else if (select_alteration == "Wings")
var/new_color = input(owner, "Choose your wing color:", "Race change","#"+H.dna.features["wings_color"]) as color|null
if(new_color)
diff --git a/code/modules/mob/living/carbon/human/innate_abilities/limb_regeneration.dm b/code/modules/mob/living/carbon/human/innate_abilities/limb_regeneration.dm
index 71b15bda2d5e..2519076d49e2 100644
--- a/code/modules/mob/living/carbon/human/innate_abilities/limb_regeneration.dm
+++ b/code/modules/mob/living/carbon/human/innate_abilities/limb_regeneration.dm
@@ -3,11 +3,11 @@
name = "Regenerate Limbs"
check_flags = AB_CHECK_CONSCIOUS
button_icon_state = "slimeheal"
- icon_icon = 'icons/mob/actions/actions_slime.dmi'
+ button_icon = 'icons/mob/actions/actions_slime.dmi'
background_icon_state = "bg_alien"
required_mobility_flags = NONE
-/datum/action/innate/ability/limb_regrowth/IsAvailable(silent = FALSE)
+/datum/action/innate/ability/limb_regrowth/IsAvailable(feedback = TRUE)
if(..())
var/mob/living/carbon/human/H = owner
var/list/limbs_to_heal = H.get_missing_limbs()
diff --git a/code/modules/mob/living/carbon/human/inventory.dm b/code/modules/mob/living/carbon/human/inventory.dm
index 29866459d82d..73eafc4c4ea9 100644
--- a/code/modules/mob/living/carbon/human/inventory.dm
+++ b/code/modules/mob/living/carbon/human/inventory.dm
@@ -53,6 +53,49 @@
return s_store
return null
+/mob/living/carbon/human/get_slot_by_item(obj/item/looking_for)
+ if(looking_for == belt)
+ return ITEM_SLOT_BELT
+
+ if(looking_for == wear_id)
+ return ITEM_SLOT_ID
+
+ if(looking_for == ears)
+ return ITEM_SLOT_EARS
+
+ if(looking_for == glasses)
+ return ITEM_SLOT_EYES
+
+ if(looking_for == gloves)
+ return ITEM_SLOT_GLOVES
+
+ if(looking_for == head)
+ return ITEM_SLOT_HEAD
+
+ if(looking_for == shoes)
+ return ITEM_SLOT_FEET
+
+ if(looking_for == wear_suit)
+ return ITEM_SLOT_OCLOTHING
+
+ var/obj/item/clothing/under/look_at = w_uniform
+ if(look_at)
+ if(looking_for == look_at)
+ return ITEM_SLOT_ICLOTHING
+ if(istype(look_at) && looking_for == look_at.attached_accessory)
+ return ITEM_SLOT_ACCESSORY
+
+ if(looking_for == r_store)
+ return ITEM_SLOT_RPOCKET
+
+ if(looking_for == l_store)
+ return ITEM_SLOT_LPOCKET
+
+ if(looking_for == s_store)
+ return ITEM_SLOT_SUITSTORE
+
+ return ..()
+
/mob/living/carbon/human/proc/get_all_slots()
. = get_head_slots() | get_body_slots()
@@ -133,7 +176,7 @@
update_inv_w_uniform()
if(wear_suit.breakouttime) //when equipping a straightjacket
stop_pulling() //can't pull if restrained
- update_action_buttons_icon() //certain action buttons will no longer be usable.
+ update_mob_action_buttons() //certain action buttons will no longer be usable.
update_inv_wear_suit()
if(ITEM_SLOT_ICLOTHING)
w_uniform = I
@@ -180,7 +223,7 @@
dropItemToGround(s_store, TRUE) //It makes no sense for your suit storage to stay on you if you drop your suit.
if(wear_suit.breakouttime) //when unequipping a straightjacket
drop_all_held_items() //suit is restraining
- update_action_buttons_icon() //certain action buttons may be usable again.
+ update_mob_action_buttons() //certain action buttons may be usable again.
wear_suit = null
if(!QDELETED(src)) //no need to update we're getting deleted anyway
if(I.flags_inv & HIDEJUMPSUIT)
diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm
index e50978e9c0b3..0fd8b3a67ca9 100644
--- a/code/modules/mob/living/carbon/human/species.dm
+++ b/code/modules/mob/living/carbon/human/species.dm
@@ -2650,7 +2650,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
/datum/action/innate/flight
name = "Toggle Flight"
check_flags = AB_CHECK_CONSCIOUS|AB_CHECK_STUN
- icon_icon = 'icons/mob/actions/actions_items.dmi'
+ button_icon = 'icons/mob/actions/actions_items.dmi'
button_icon_state = "flight"
/datum/action/innate/flight/Activate()
diff --git a/code/modules/mob/living/carbon/human/species_types/arachnid.dm b/code/modules/mob/living/carbon/human/species_types/arachnid.dm
index fabd9072c8db..11a522493728 100644
--- a/code/modules/mob/living/carbon/human/species_types/arachnid.dm
+++ b/code/modules/mob/living/carbon/human/species_types/arachnid.dm
@@ -62,13 +62,13 @@
/datum/action/innate/spin_web
name = "Spin Web"
check_flags = AB_CHECK_RESTRAINED|AB_CHECK_STUN|AB_CHECK_CONSCIOUS
- icon_icon = 'icons/mob/actions/actions_animal.dmi'
+ button_icon = 'icons/mob/actions/actions_animal.dmi'
button_icon_state = "lay_web"
/datum/action/innate/spin_cocoon
name = "Spin Cocoon"
check_flags = AB_CHECK_RESTRAINED|AB_CHECK_STUN|AB_CHECK_CONSCIOUS
- icon_icon = 'icons/mob/actions/actions_animal.dmi'
+ button_icon = 'icons/mob/actions/actions_animal.dmi'
button_icon_state = "wrap_0"
/datum/action/innate/spin_web/Activate()
diff --git a/code/modules/mob/living/carbon/human/species_types/golems.dm b/code/modules/mob/living/carbon/human/species_types/golems.dm
index 5ca140cab48d..37adc57f194d 100644
--- a/code/modules/mob/living/carbon/human/species_types/golems.dm
+++ b/code/modules/mob/living/carbon/human/species_types/golems.dm
@@ -456,11 +456,11 @@
name = "Unstable Teleport"
check_flags = AB_CHECK_CONSCIOUS
button_icon_state = "jaunt"
- icon_icon = 'icons/mob/actions/actions_spells.dmi'
+ button_icon = 'icons/mob/actions/actions_spells.dmi'
var/cooldown = 150
var/last_teleport = 0
-/datum/action/innate/unstable_teleport/IsAvailable(silent = FALSE)
+/datum/action/innate/unstable_teleport/IsAvailable(feedback = TRUE)
if(..())
if(world.time > last_teleport + cooldown)
return TRUE
@@ -480,9 +480,9 @@
spark_system.start()
do_teleport(H, get_turf(H), 12, asoundin = 'sound/weapons/emitter2.ogg', channel = TELEPORT_CHANNEL_BLUESPACE)
last_teleport = world.time
- UpdateButtons() //action icon looks unavailable
+ build_all_button_icons() //action icon looks unavailable
//action icon looks available again
- addtimer(CALLBACK(src, PROC_REF(UpdateButtons)), cooldown + 5)
+ addtimer(CALLBACK(src, PROC_REF(build_all_button_icons)), cooldown + 5)
//honk
@@ -991,7 +991,7 @@
name = "Bone Chill"
desc = "Rattle your bones and strike fear into your enemies!"
check_flags = AB_CHECK_CONSCIOUS
- icon_icon = 'icons/mob/actions/actions_spells.dmi'
+ button_icon = 'icons/mob/actions/actions_spells.dmi'
button_icon_state = "bonechill"
var/cooldown = 600
var/last_use
diff --git a/code/modules/mob/living/carbon/human/species_types/ipc.dm b/code/modules/mob/living/carbon/human/species_types/ipc.dm
index f6749dde0617..5e3fae09eddc 100644
--- a/code/modules/mob/living/carbon/human/species_types/ipc.dm
+++ b/code/modules/mob/living/carbon/human/species_types/ipc.dm
@@ -58,7 +58,7 @@
/datum/action/innate/monitor_change
name = "Screen Change"
check_flags = AB_CHECK_CONSCIOUS
- icon_icon = 'icons/mob/actions/actions_silicon.dmi'
+ button_icon = 'icons/mob/actions/actions_silicon.dmi'
button_icon_state = "drone_vision"
/datum/action/innate/monitor_change/Activate()
diff --git a/code/modules/mob/living/carbon/human/species_types/jellypeople.dm b/code/modules/mob/living/carbon/human/species_types/jellypeople.dm
index 550789a0666f..10651b357fc7 100644
--- a/code/modules/mob/living/carbon/human/species_types/jellypeople.dm
+++ b/code/modules/mob/living/carbon/human/species_types/jellypeople.dm
@@ -82,7 +82,7 @@
var/datum/action/innate/ability/regrowth = H.ability_actions[INNATE_ABILITY_LIMB_REGROWTH]
if(regrowth)
- regrowth.UpdateButtons()
+ regrowth.build_all_button_icons()
return FALSE // to let living/handle_blood know that the species is handling blood instead
@@ -176,10 +176,10 @@
name = "Split Body"
check_flags = AB_CHECK_CONSCIOUS
button_icon_state = "slimesplit"
- icon_icon = 'icons/mob/actions/actions_slime.dmi'
+ button_icon = 'icons/mob/actions/actions_slime.dmi'
background_icon_state = "bg_alien"
-/datum/action/innate/split_body/IsAvailable(silent = FALSE)
+/datum/action/innate/split_body/IsAvailable(feedback = TRUE)
if(..())
var/mob/living/carbon/human/H = owner
if(H.blood_volume >= BLOOD_VOLUME_SLIME_SPLIT)
@@ -256,7 +256,7 @@
name = "Swap Body"
check_flags = NONE
button_icon_state = "slimeswap"
- icon_icon = 'icons/mob/actions/actions_slime.dmi'
+ button_icon = 'icons/mob/actions/actions_slime.dmi'
background_icon_state = "bg_alien"
/datum/action/innate/swap_body/Activate()
@@ -438,48 +438,55 @@
name = "Luminescent Slime Entity"
id = SPECIES_SLIME_LUMI
say_mod = "says"
+ /// How strong is our glow
var/glow_intensity = LUMINESCENT_DEFAULT_GLOW
+ /// Internal dummy used to glow (very cool)
var/obj/effect/dummy/luminescent_glow/glow
+ /// The slime extract we currently have integrated
var/obj/item/slime_extract/current_extract
- var/datum/action/innate/integrate_extract/integrate_extract
- var/datum/action/innate/use_extract/extract_minor
- var/datum/action/innate/use_extract/major/extract_major
- var/extract_cooldown = 0
+ /// A list of all luminescent related actions we have
+ var/list/luminescent_actions
+ /// The cooldown of us using exteracts
+ COOLDOWN_DECLARE(extract_cooldown)
+
+//Species datums don't normally implement destroy, but JELLIES SUCK ASS OUT OF A STEEL STRAW and have to i guess
+/datum/species/jelly/luminescent/Destroy(force)
+ current_extract = null
+ QDEL_NULL(glow)
+ QDEL_LIST(luminescent_actions)
+ return ..()
-/datum/species/jelly/luminescent/on_species_loss(mob/living/carbon/C)
+/datum/species/jelly/luminescent/on_species_gain(mob/living/carbon/new_jellyperson, datum/species/old_species)
..()
+ glow = new(new_jellyperson)
+ update_glow(new_jellyperson)
+
+ luminescent_actions = list()
+
+ var/datum/action/innate/integrate_extract/integrate_extract = new(src)
+ integrate_extract.Grant(new_jellyperson)
+ luminescent_actions += integrate_extract
+
+ var/datum/action/innate/use_extract/extract_minor = new(src)
+ extract_minor.Grant(new_jellyperson)
+ luminescent_actions += extract_minor
+
+ var/datum/action/innate/use_extract/major/extract_major = new(src)
+ extract_major.Grant(new_jellyperson)
+ luminescent_actions += extract_major
+
+/datum/species/jelly/luminescent/on_species_loss(mob/living/carbon/C)
+ . = ..()
if(current_extract)
current_extract.forceMove(C.drop_location())
current_extract = null
- qdel(glow)
- if(integrate_extract)
- integrate_extract.Remove(C)
- if(extract_minor)
- extract_minor.Remove(C)
- if(extract_major)
- extract_major.Remove(C)
-
-/datum/species/jelly/luminescent/on_species_gain(mob/living/carbon/C, datum/species/old_species)
- ..()
- glow = new(C)
- update_glow(C)
- integrate_extract = new(src)
- integrate_extract.Grant(C)
- extract_minor = new(src)
- extract_minor.Grant(C)
- extract_major = new(src)
- extract_major.Grant(C)
-
-/datum/species/jelly/luminescent/proc/update_slime_actions()
- integrate_extract.update_name()
- integrate_extract.UpdateButtons()
- extract_minor.UpdateButtons()
- extract_major.UpdateButtons()
-
-/datum/species/jelly/luminescent/proc/update_glow(mob/living/carbon/C, intensity)
+ QDEL_NULL(glow)
+ QDEL_NULL_LIST(luminescent_actions)
+
+/datum/species/jelly/luminescent/proc/update_glow(mob/living/carbon/human/glowie, intensity)
if(intensity)
glow_intensity = intensity
- glow.set_light(glow_intensity, glow_intensity, C.dna.features["mcolor"])
+ glow.set_light(glow_intensity, glow_intensity, glowie.dna.features["mcolor"])
/obj/effect/dummy/luminescent_glow
name = "luminescent glow"
@@ -498,98 +505,110 @@
desc = "Eat a slime extract to use its properties."
check_flags = AB_CHECK_CONSCIOUS
button_icon_state = "slimeconsume"
- icon_icon = 'icons/mob/actions/actions_slime.dmi'
+ button_icon = 'icons/mob/actions/actions_slime.dmi'
background_icon_state = "bg_alien"
- var/datum/species/jelly/luminescent/species
-/datum/action/innate/integrate_extract/New(_species)
- ..()
- species = _species
+/datum/action/innate/integrate_extract/New(Target)
+ . = ..()
+ AddComponent(/datum/component/action_item_overlay, item_callback = CALLBACK(src, PROC_REF(locate_extract)))
-/datum/action/innate/integrate_extract/proc/update_name()
- if(!species || !species.current_extract)
+/// Callback for /datum/component/action_item_overlay to find the slime extract from within the species
+/datum/action/innate/integrate_extract/proc/locate_extract()
+ var/datum/species/jelly/luminescent/species = target
+ if(!istype(species))
+ return null
+
+ return species.current_extract
+
+/datum/action/innate/integrate_extract/update_button_name(atom/movable/screen/movable/action_button/button, force = FALSE)
+ var/datum/species/jelly/luminescent/species = target
+ if(!istype(species) || !species.current_extract)
name = "Integrate Extract"
desc = "Eat a slime extract to use its properties."
else
name = "Eject Extract"
desc = "Eject your current slime extract."
-/datum/action/innate/integrate_extract/UpdateButton(atom/movable/screen/movable/action_button/button, status_only, force)
- if(!species || !species.current_extract)
+ return ..()
+
+/datum/action/innate/integrate_extract/apply_button_icon(atom/movable/screen/movable/action_button/current_button, force)
+ var/datum/species/jelly/luminescent/species = target
+ if(!istype(species) || !species.current_extract)
button_icon_state = "slimeconsume"
else
button_icon_state = "slimeeject"
- ..()
-/datum/action/innate/integrate_extract/ApplyIcon(atom/movable/screen/movable/action_button/current_button, force)
- ..(current_button, TRUE)
- if(species && species.current_extract)
- current_button.add_overlay(mutable_appearance(species.current_extract.icon, species.current_extract.icon_state))
+ return ..()
/datum/action/innate/integrate_extract/Activate()
- var/mob/living/carbon/human/H = owner
- if(!is_species(H, /datum/species/jelly/luminescent) || !species)
+ var/mob/living/carbon/human/human_owner = owner
+ var/datum/species/jelly/luminescent/species = target
+ if(!istype(species))
return
- CHECK_DNA_AND_SPECIES(H)
if(species.current_extract)
- var/obj/item/slime_extract/S = species.current_extract
- if(!H.put_in_active_hand(S))
- S.forceMove(H.drop_location())
+ var/obj/item/slime_extract/to_remove = species.current_extract
+ if(!human_owner.put_in_active_hand(to_remove))
+ to_remove.forceMove(human_owner.drop_location())
+
species.current_extract = null
- to_chat(H, "You eject [S].")
- species.update_slime_actions()
+ human_owner.balloon_alert(human_owner, "[to_remove.name] ejected")
+
else
- var/obj/item/I = H.get_active_held_item()
- if(istype(I, /obj/item/slime_extract))
- var/obj/item/slime_extract/S = I
- if(!S.Uses)
- to_chat(H, "[I] is spent! You cannot integrate it.")
- return
- if(!H.temporarilyRemoveItemFromInventory(S))
- return
- S.forceMove(H)
- species.current_extract = S
- to_chat(H, "You consume [I], and you feel it pulse within you...")
- species.update_slime_actions()
- else
- to_chat(H, "You need to hold an unused slime extract in your active hand!")
+ var/obj/item/slime_extract/to_integrate = human_owner.get_active_held_item()
+ if(!istype(to_integrate) || to_integrate.extract_uses <= 0)
+ human_owner.balloon_alert(human_owner, "need an unused slime extract!")
+ return
+ if(!human_owner.temporarilyRemoveItemFromInventory(to_integrate))
+ return
+ to_integrate.forceMove(human_owner)
+ species.current_extract = to_integrate
+ human_owner.balloon_alert(human_owner, "[to_integrate.name] consumed")
+
+ for(var/datum/action/to_update as anything in species.luminescent_actions)
+ to_update.build_all_button_icons()
/datum/action/innate/use_extract
name = "Extract Minor Activation"
desc = "Pulse the slime extract with energized jelly to activate it."
check_flags = AB_CHECK_CONSCIOUS
button_icon_state = "slimeuse1"
- icon_icon = 'icons/mob/actions/actions_slime.dmi'
+ button_icon = 'icons/mob/actions/actions_slime.dmi'
background_icon_state = "bg_alien"
+ overlay_icon_state = "bg_alien_border"
var/activation_type = SLIME_ACTIVATE_MINOR
- var/datum/species/jelly/luminescent/species
-/datum/action/innate/use_extract/New(_species)
- ..()
- species = _species
+/datum/action/innate/use_extract/New(Target)
+ . = ..()
+ AddComponent(/datum/component/action_item_overlay, item_callback = CALLBACK(src, PROC_REF(locate_extract)))
-/datum/action/innate/use_extract/IsAvailable(silent = FALSE)
- if(..())
- if(species && species.current_extract && (world.time > species.extract_cooldown))
- return TRUE
- return FALSE
+/// Callback for /datum/component/action_item_overlay to find the slime extract from within the species
+/datum/action/innate/use_extract/proc/locate_extract()
+ var/datum/species/jelly/luminescent/species = target
+ if(!istype(species))
+ return null
+
+ return species.current_extract
+
+/datum/action/innate/use_extract/IsAvailable(feedback = FALSE)
+ . = ..()
+ if(!.)
+ return
-/datum/action/innate/use_extract/ApplyIcon(atom/movable/screen/movable/action_button/current_button, force)
- ..(current_button, TRUE)
- if(species && species.current_extract)
- current_button.add_overlay(mutable_appearance(species.current_extract.icon, species.current_extract.icon_state))
+ var/datum/species/jelly/luminescent/species = target
+ if(istype(species) && species.current_extract && (COOLDOWN_FINISHED(species, extract_cooldown)))
+ return TRUE
+ return FALSE
/datum/action/innate/use_extract/Activate()
- var/mob/living/carbon/human/H = owner
- if(!is_species(H, /datum/species/jelly/luminescent) || !species)
+ var/mob/living/carbon/human/human_owner = owner
+ var/datum/species/jelly/luminescent/species = human_owner.dna?.species
+ if(!istype(species) || !species.current_extract)
return
- CHECK_DNA_AND_SPECIES(H)
- if(species.current_extract)
- species.extract_cooldown = world.time + 100
- var/cooldown = species.current_extract.activate(H, species, activation_type)
- species.extract_cooldown = world.time + cooldown
+ COOLDOWN_START(species, extract_cooldown, 10 SECONDS)
+ var/after_use_cooldown = species.current_extract.activate(human_owner, species, activation_type)
+ COOLDOWN_START(species, extract_cooldown, after_use_cooldown)
/datum/action/innate/use_extract/major
name = "Extract Major Activation"
@@ -664,7 +683,7 @@
name = "Slimelink"
desc = "Send a psychic message to everyone connected to your slime link."
button_icon_state = "link_speech"
- icon_icon = 'icons/mob/actions/actions_slime.dmi'
+ button_icon = 'icons/mob/actions/actions_slime.dmi'
background_icon_state = "bg_alien"
var/datum/species/jelly/stargazer/species
@@ -702,7 +721,7 @@
name = "Send Thought"
desc = "Send a private psychic message to someone you can see."
button_icon_state = "send_mind"
- icon_icon = 'icons/mob/actions/actions_slime.dmi'
+ button_icon = 'icons/mob/actions/actions_slime.dmi'
background_icon_state = "bg_alien"
/datum/action/innate/project_thought/Activate()
@@ -741,7 +760,7 @@
name = "Link Minds"
desc = "Link someone's mind to your Slime Link, allowing them to communicate telepathically with other linked minds."
button_icon_state = "mindlink"
- icon_icon = 'icons/mob/actions/actions_slime.dmi'
+ button_icon = 'icons/mob/actions/actions_slime.dmi'
background_icon_state = "bg_alien"
var/datum/species/jelly/stargazer/species
diff --git a/code/modules/mob/living/carbon/human/species_types/vampire.dm b/code/modules/mob/living/carbon/human/species_types/vampire.dm
index 3e54a4e63872..429ce5d2d34b 100644
--- a/code/modules/mob/living/carbon/human/species_types/vampire.dm
+++ b/code/modules/mob/living/carbon/human/species_types/vampire.dm
@@ -62,7 +62,7 @@
var/area/A = get_area(C)
if(istype(A, /area/service/chapel) && C.mind?.assigned_role != "Chaplain")
- to_chat(C, "You don't belong here!")
+ to_chat(C, span_danger("You don't belong here!"))
C.adjustFireLoss(5)
C.adjust_fire_stacks(6)
C.IgniteMob()
@@ -79,47 +79,51 @@
name = "Drain Victim"
desc = "Leech blood from any carbon victim you are passively grabbing."
-/datum/action/item_action/organ_action/vampire/Trigger()
+/datum/action/item_action/organ_action/vampire/do_effect(trigger_flags)
. = ..()
- if(iscarbon(owner))
- var/mob/living/carbon/H = owner
- var/obj/item/organ/tongue/vampire/V = target
- if(V.drain_cooldown >= world.time)
- to_chat(H, "You just drained blood, wait a few seconds.")
- return
- if(H.pulling && iscarbon(H.pulling))
- var/mob/living/carbon/victim = H.pulling
- if(H.blood_volume >= BLOOD_VOLUME_MAXIMUM)
- to_chat(H, "You're already full!")
- return
- //This checks whether or not they are wearing a garlic clove on their neck
- if(!blood_sucking_checks(victim, TRUE, FALSE))
- return
- if(victim.stat == DEAD)
- to_chat(H, "You need a living victim!")
- return
- if(!victim.blood_volume || (victim.dna && ((NOBLOOD in victim.dna.species.species_traits) || victim.dna.species.exotic_blood)))
- to_chat(H, "[victim] doesn't have blood!")
- return
- V.drain_cooldown = world.time + 30
- if(victim.anti_magic_check(FALSE, TRUE, FALSE, 0))
- to_chat(victim, "[H] tries to bite you, but stops before touching you!")
- to_chat(H, "[victim] is blessed! You stop just in time to avoid catching fire.")
- return
- //Here we check now for both the garlic cloves on the neck and for blood in the victims bloodstream.
- if(!blood_sucking_checks(victim, TRUE, TRUE))
- return
- if(!do_after(H, 30, target = victim))
- return
- var/blood_volume_difference = BLOOD_VOLUME_MAXIMUM - H.blood_volume //How much capacity we have left to absorb blood
- var/drained_blood = min(victim.blood_volume, VAMP_DRAIN_AMOUNT, blood_volume_difference)
- to_chat(victim, "[H] is draining your blood!")
- to_chat(H, "You drain some blood!")
- playsound(H, 'sound/items/drink.ogg', 30, 1, -2)
- victim.blood_volume = clamp(victim.blood_volume - drained_blood, 0, BLOOD_VOLUME_MAXIMUM)
- H.blood_volume = clamp(H.blood_volume + drained_blood, 0, BLOOD_VOLUME_MAXIMUM)
- if(!victim.blood_volume)
- to_chat(H, "You finish off [victim]'s blood supply!")
+ if(!.)
+ return
+ if(!iscarbon(owner))
+ return FALSE
+ var/mob/living/carbon/H = owner
+ var/obj/item/organ/tongue/vampire/V = target
+ if(V.drain_cooldown >= world.time)
+ to_chat(H, span_notice("You just drained blood, wait a few seconds."))
+ return FALSE
+ if(H.pulling && iscarbon(H.pulling))
+ var/mob/living/carbon/victim = H.pulling
+ if(H.blood_volume >= BLOOD_VOLUME_MAXIMUM)
+ to_chat(H, span_notice("You're already full!"))
+ return FALSE
+ //This checks whether or not they are wearing a garlic clove on their neck
+ if(!blood_sucking_checks(victim, TRUE, FALSE))
+ return FALSE
+ if(victim.stat == DEAD)
+ to_chat(H, span_notice("You need a living victim!"))
+ return FALSE
+ if(!victim.blood_volume || (victim.dna && ((NOBLOOD in victim.dna.species.species_traits) || victim.dna.species.exotic_blood)))
+ to_chat(H, span_notice("[victim] doesn't have blood!"))
+ return FALSE
+ V.drain_cooldown = world.time + 30
+ if(victim.anti_magic_check(FALSE, TRUE, FALSE, 0))
+ to_chat(victim, span_warning("[H] tries to bite you, but stops before touching you!"))
+ to_chat(H, span_warning("[victim] is blessed! You stop just in time to avoid catching fire."))
+ return FALSE
+ //Here we check now for both the garlic cloves on the neck and for blood in the victims bloodstream.
+ if(!blood_sucking_checks(victim, TRUE, TRUE))
+ return FALSE
+ if(!do_after(H, 30, target = victim))
+ return FALSE
+ var/blood_volume_difference = BLOOD_VOLUME_MAXIMUM - H.blood_volume //How much capacity we have left to absorb blood
+ var/drained_blood = min(victim.blood_volume, VAMP_DRAIN_AMOUNT, blood_volume_difference)
+ to_chat(victim, span_danger("[H] is draining your blood!"))
+ to_chat(H, span_notice("You drain some blood!"))
+ playsound(H, 'sound/items/drink.ogg', 30, 1, -2)
+ victim.blood_volume = clamp(victim.blood_volume - drained_blood, 0, BLOOD_VOLUME_MAXIMUM)
+ H.blood_volume = clamp(H.blood_volume + drained_blood, 0, BLOOD_VOLUME_MAXIMUM)
+ if(!victim.blood_volume)
+ to_chat(H, span_warning("You finish off [victim]'s blood supply!"))
+ return TRUE
#undef VAMP_DRAIN_AMOUNT
@@ -140,11 +144,15 @@
name = "Check Blood Level"
desc = "Check how much blood you have remaining."
-/datum/action/item_action/organ_action/vampire_heart/Trigger()
+/datum/action/item_action/organ_action/vampire_heart/do_effect(trigger_flags)
. = ..()
- if(iscarbon(owner))
- var/mob/living/carbon/H = owner
- to_chat(H, "Current blood level: [H.blood_volume]/[BLOOD_VOLUME_MAXIMUM].")
+ if(!.)
+ return
+ if(!iscarbon(owner))
+ return FALSE
+ var/mob/living/carbon/H = owner
+ to_chat(H, span_notice("Current blood level: [H.blood_volume]/[BLOOD_VOLUME_MAXIMUM]."))
+ return TRUE
/obj/effect/proc_holder/spell/targeted/shapeshift/bat
name = "Bat Form"
@@ -159,11 +167,11 @@
/obj/effect/proc_holder/spell/targeted/shapeshift/bat/Shapeshift(mob/living/caster) //cit change
var/obj/shapeshift_holder/H = locate() in caster
if(H)
- to_chat(caster, "You're already shapeshifted!")
+ to_chat(caster, span_warning("You're already shapeshifted!"))
return
if(!ishuman(caster))
- to_chat(caster, "You need to be humanoid to be able to do this!")
+ to_chat(caster, span_warning("You need to be humanoid to be able to do this!"))
return
var/mob/living/carbon/human/human_caster = caster
@@ -184,11 +192,11 @@
/obj/effect/proc_holder/spell/targeted/shapeshift/bat/cast(list/targets, mob/user = usr)
if(!(locate(/obj/shapeshift_holder) in targets[1]))
if(!ishuman(user))
- to_chat(user, "You need to be humanoid to be able to do this!")
+ to_chat(user, span_warning("You need to be humanoid to be able to do this!"))
return
var/mob/living/carbon/human/human_user = user
if(!(human_user.dna?.species?.id == SPECIES_VAMPIRE))
- to_chat(user, "You don't seem to be able to shapeshift..")
+ to_chat(user, span_warning("You don't seem to be able to shapeshift.."))
return
return ..()
diff --git a/code/modules/mob/living/carbon/inventory.dm b/code/modules/mob/living/carbon/inventory.dm
index 2422528d2113..4e4f71f96325 100644
--- a/code/modules/mob/living/carbon/inventory.dm
+++ b/code/modules/mob/living/carbon/inventory.dm
@@ -14,6 +14,30 @@
return legcuffed
return null
+/mob/living/carbon/get_slot_by_item(obj/item/looking_for)
+ if(looking_for == back)
+ return ITEM_SLOT_BACK
+
+ if(back && (looking_for in back))
+ return ITEM_SLOT_BACKPACK
+
+ if(looking_for == wear_mask)
+ return ITEM_SLOT_MASK
+
+ if(looking_for == wear_neck)
+ return ITEM_SLOT_NECK
+
+ if(looking_for == head)
+ return ITEM_SLOT_HEAD
+
+ if(looking_for == handcuffed)
+ return ITEM_SLOT_HANDCUFFED
+
+ if(looking_for == legcuffed)
+ return ITEM_SLOT_LEGCUFFED
+
+ return ..()
+
/mob/living/carbon/proc/equip_in_one_of_slots(obj/item/I, list/slots, qdel_on_fail = 1, critical = FALSE)
for(var/slot in slots)
if(equip_to_slot_if_possible(I, slots[slot], qdel_on_fail = 0, disable_warning = TRUE))
diff --git a/code/modules/mob/living/death.dm b/code/modules/mob/living/death.dm
index aaf9bf0a7a3a..dcc247bcdd82 100644
--- a/code/modules/mob/living/death.dm
+++ b/code/modules/mob/living/death.dm
@@ -78,7 +78,7 @@
blind_eyes(1)
reset_perspective(null)
reload_fullscreen()
- update_action_buttons_icon()
+ update_mob_action_buttons()
update_damage_hud()
update_health_hud()
update_mobility()
diff --git a/code/modules/mob/living/living_mobility.dm b/code/modules/mob/living/living_mobility.dm
index 155f1dbc892b..c1d6b4feea7e 100644
--- a/code/modules/mob/living/living_mobility.dm
+++ b/code/modules/mob/living/living_mobility.dm
@@ -9,8 +9,7 @@
resting = new_resting
if(!silent)
to_chat(src, "You are now [resting? "resting" : "getting up"].")
- if(resting == 1)
- SEND_SIGNAL(src, COMSIG_LIVING_RESTING)
+ SEND_SIGNAL(src, COMSIG_LIVING_RESTING, resting)
update_resting(updating)
/mob/living/proc/update_resting(update_mobility = TRUE)
diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm
index b4f9b4a8eef2..f8135ec29a29 100644
--- a/code/modules/mob/living/silicon/ai/ai.dm
+++ b/code/modules/mob/living/silicon/ai/ai.dm
@@ -132,8 +132,8 @@
target_ai.mind.transfer_to(src)
if(mind.special_role)
mind.store_memory("As an AI, you must obey your silicon laws above all else. Your objectives will consider you to be dead.")
- to_chat(src, "You have been installed as an AI! ")
- to_chat(src, "You must obey your silicon laws above all else. Your objectives will consider you to be dead.")
+ to_chat(src, span_userdanger("You have been installed as an AI! "))
+ to_chat(src, span_danger("You must obey your silicon laws above all else. Your objectives will consider you to be dead."))
if(!mind.has_ever_been_ai)
mind.has_ever_been_ai = TRUE
@@ -285,7 +285,7 @@
/mob/living/silicon/ai/proc/ai_call_shuttle()
if(control_disabled)
- to_chat(usr, "Wireless control is disabled!")
+ to_chat(usr, span_warning("Wireless control is disabled!"))
return
var/reason = input(src, "What is the nature of your emergency? ([CALL_SHUTTLE_REASON_LENGTH] characters required.)", "Confirm Shuttle Call") as null|text
@@ -398,7 +398,7 @@
/mob/living/silicon/ai/proc/ai_cancel_call()
set category = "Malfunction"
if(control_disabled)
- to_chat(src, "Wireless control is disabled!")
+ to_chat(src, span_warning("Wireless control is disabled!"))
return
SSshuttle.cancelEvac(src)
@@ -431,7 +431,7 @@
if(H)
H.attack_ai(src) //may as well recycle
else
- to_chat(src, "Unable to locate the holopad.")
+ to_chat(src, span_notice("Unable to locate the holopad."))
if(href_list["track"])
var/string = href_list["track"]
trackable_mobs()
@@ -590,7 +590,7 @@
if(network in C.network)
U.eyeobj.setLoc(get_turf(C))
break
- to_chat(src, "Switched to the \"[uppertext(network)]\" camera network.")
+ to_chat(src, span_notice("Switched to the \"[uppertext(network)]\" camera network."))
//End of code by Mord_Sith
@@ -711,7 +711,7 @@
var/obj/machinery/power/apc/apc = src.loc
if(!istype(apc))
- to_chat(src, "You are already in your Main Core.")
+ to_chat(src, span_notice("You are already in your Main Core."))
return
apc.malfvacate()
@@ -783,11 +783,11 @@
return
if(interaction == AI_TRANS_TO_CARD)//The only possible interaction. Upload AI mob to a card.
if(!can_be_carded)
- to_chat(user, "Transfer failed.")
+ to_chat(user, span_boldwarning("Transfer failed."))
return
disconnect_shell() //If the AI is controlling a borg, force the player back to core!
if(!mind)
- to_chat(user, "No intelligence patterns detected." )
+ to_chat(user, span_warning("No intelligence patterns detected."))
return
ShutOffDoomsdayDevice()
var/obj/structure/ai_core/new_core = new /obj/structure/ai_core/deactivated(loc, posibrain_inside)//Spawns a deactivated terminal at AI location.
@@ -811,10 +811,10 @@
/mob/living/silicon/ai/canUseTopic(atom/movable/M, be_close=FALSE, no_dextery=FALSE, no_tk=FALSE)
if(control_disabled || incapacitated())
- to_chat(src, "You can't do that right now!")
+ to_chat(src, span_warning("You can't do that right now!"))
return FALSE
if(be_close && !in_range(M, src))
- to_chat(src, "You are too far away!")
+ to_chat(src, span_warning("You are too far away!"))
return FALSE
return can_see(M) //stop AIs from leaving windows open and using then after they lose vision
@@ -915,10 +915,10 @@
clear_alert("hackingapc")
if(!istype(apc) || QDELETED(apc) || apc.machine_stat & BROKEN)
- to_chat(src, "Hack aborted. The designated APC no longer exists on the power network.")
+ to_chat(src, span_danger("Hack aborted. The designated APC no longer exists on the power network."))
playsound(get_turf(src), 'sound/machines/buzz-two.ogg', 50, TRUE, ignore_walls = FALSE)
else if(apc.aidisabled)
- to_chat(src, "Hack aborted. \The [apc] is no longer responding to our systems.")
+ to_chat(src, span_danger("Hack aborted. \The [apc] is no longer responding to our systems."))
playsound(get_turf(src), 'sound/machines/buzz-sigh.ogg', 50, TRUE, ignore_walls = FALSE)
else
malf_picker.processing_time += 10
@@ -939,7 +939,7 @@
if(incapacitated())
return
if(control_disabled)
- to_chat(src, "Wireless networking module is offline.")
+ to_chat(src, span_warning("Wireless networking module is offline."))
return
var/list/possible = list()
@@ -968,30 +968,38 @@
/datum/action/innate/deploy_shell
name = "Deploy to AI Shell"
desc = "Wirelessly control a specialized cyborg shell."
- icon_icon = 'icons/mob/actions/actions_AI.dmi'
+ button_icon = 'icons/mob/actions/actions_AI.dmi'
button_icon_state = "ai_shell"
-/datum/action/innate/deploy_shell/Trigger()
+/datum/action/innate/deploy_shell/Trigger(trigger_flags)
+ . = ..()
+ if(!.)
+ return FALSE
var/mob/living/silicon/ai/AI = owner
if(!AI)
- return
+ return FALSE
AI.deploy_to_shell()
+ return TRUE
/datum/action/innate/deploy_last_shell
name = "Reconnect to shell"
desc = "Reconnect to the most recently used AI shell."
- icon_icon = 'icons/mob/actions/actions_AI.dmi'
+ button_icon = 'icons/mob/actions/actions_AI.dmi'
button_icon_state = "ai_last_shell"
var/mob/living/silicon/robot/last_used_shell
-/datum/action/innate/deploy_last_shell/Trigger()
+/datum/action/innate/deploy_last_shell/Trigger(trigger_flags)
+ . = ..()
+ if(!.)
+ return FALSE
if(!owner)
- return
+ return FALSE
if(last_used_shell)
var/mob/living/silicon/ai/AI = owner
AI.deploy_to_shell(last_used_shell)
else
Remove(owner) //If the last shell is blown, destroy it.
+ return TRUE
/datum/action/innate/deploy_last_shell/Destroy()
last_used_shell = null
@@ -999,7 +1007,7 @@
/mob/living/silicon/ai/proc/disconnect_shell()
if(deployed_shell) //Forcibly call back AI in event of things such as damage, EMP or power loss.
- to_chat(src, "Your remote connection has been reset!")
+ to_chat(src, span_danger("Your remote connection has been reset!"))
deployed_shell.undeploy()
diag_hud_set_deployed()
diff --git a/code/modules/mob/living/silicon/pai/pai.dm b/code/modules/mob/living/silicon/pai/pai.dm
index 99c3eda3ebe0..66062c85e6cc 100644
--- a/code/modules/mob/living/silicon/pai/pai.dm
+++ b/code/modules/mob/living/silicon/pai/pai.dm
@@ -215,7 +215,7 @@
/mob/living/silicon/pai/canUseTopic(atom/movable/M, be_close=FALSE, no_dextery=FALSE, no_tk=FALSE)
if(be_close && !in_range(M, src))
- to_chat(src, "You are too far away!")
+ to_chat(src, span_warning("You are too far away!"))
return FALSE
return TRUE
@@ -230,62 +230,79 @@
/datum/action/innate/pai
name = "PAI Action"
- icon_icon = 'icons/mob/actions/actions_silicon.dmi'
+ button_icon = 'icons/mob/actions/actions_silicon.dmi'
var/mob/living/silicon/pai/P
-/datum/action/innate/pai/Trigger()
+/datum/action/innate/pai/Trigger(trigger_flags)
+ . = ..()
+ if(!.)
+ return FALSE
if(!ispAI(owner))
return FALSE
P = owner
+ return TRUE
/datum/action/innate/pai/software
name = "Software Interface"
button_icon_state = "pai"
background_icon_state = "bg_tech"
-/datum/action/innate/pai/software/Trigger()
- ..()
+/datum/action/innate/pai/software/Trigger(trigger_flags)
+ . = ..()
+ if(!.)
+ return FALSE
P.paiInterface()
+ return TRUE
/datum/action/innate/pai/shell
name = "Toggle Holoform"
button_icon_state = "pai_holoform"
background_icon_state = "bg_tech"
-/datum/action/innate/pai/shell/Trigger()
- ..()
+/datum/action/innate/pai/shell/Trigger(trigger_flags)
+ . = ..()
+ if(!.)
+ return FALSE
if(P.holoform)
- P.fold_in(FALSE)
+ . = P.fold_in(FALSE)
else
- P.fold_out()
+ . = P.fold_out()
/datum/action/innate/pai/chassis
name = "Holochassis Appearance Composite"
button_icon_state = "pai_chassis"
background_icon_state = "bg_tech"
-/datum/action/innate/pai/chassis/Trigger()
- ..()
- P.choose_chassis()
+/datum/action/innate/pai/chassis/Trigger(trigger_flags)
+ . = ..()
+ if(!.)
+ return FALSE
+ return P.choose_chassis()
/datum/action/innate/pai/rest
name = "Rest"
button_icon_state = "pai_rest"
background_icon_state = "bg_tech"
-/datum/action/innate/pai/rest/Trigger()
- ..()
+/datum/action/innate/pai/rest/Trigger(trigger_flags)
+ . = ..()
+ if(!.)
+ return FALSE
P.lay_down()
+ return TRUE
/datum/action/innate/pai/light
name = "Toggle Integrated Lights"
- icon_icon = 'icons/mob/actions/actions_spells.dmi'
+ button_icon = 'icons/mob/actions/actions_spells.dmi'
button_icon_state = "emp"
background_icon_state = "bg_tech"
-/datum/action/innate/pai/light/Trigger()
- ..()
+/datum/action/innate/pai/light/Trigger(trigger_flags)
+ . = ..()
+ if(!.)
+ return FALSE
P.toggle_integrated_light()
+ return TRUE
/mob/living/silicon/pai/Process_Spacemove(movement_dir = 0)
. = ..()
@@ -304,7 +321,7 @@
if(cable)
if(get_dist(src, cable) > 1)
var/turf/T = get_turf(src.loc)
- T.visible_message("[src.cable] rapidly retracts back into its spool.", "You hear a click and the sound of wire spooling rapidly.")
+ T.visible_message(span_warning("[src.cable] rapidly retracts back into its spool."), span_italics("You hear a click and the sound of wire spooling rapidly."))
qdel(src.cable)
cable = null
@@ -335,17 +352,17 @@
/obj/item/paicard/attack_ghost(mob/dead/observer/user)
if(pai)
- to_chat(user, "This pAI is already in use!")
+ to_chat(user, span_warning("This pAI is already in use!"))
return
var/area/A = get_area(get_turf(src))
if(A.type in SSpai.restricted_areas) // set in subsystem/pai.dm on initialize of the subsystem
- to_chat(user, "You can't download yourself into a restricted area!")
+ to_chat(user, span_warning("You can't download yourself into a restricted area!"))
return
var/pai_name = reject_bad_name(stripped_input(usr, "Enter a name for your pAI", "pAI Name", user.name, MAX_NAME_LEN), TRUE)
if(!pai_name)
- to_chat(user, "Entered name is not valid.")
+ to_chat(user, span_warning("Entered name is not valid."))
return
var/mob/living/silicon/pai/new_pai = new(src)
@@ -361,8 +378,8 @@
. = ..()
if(!pai)
return
- to_chat(user, "You override [pai]'s directive system, clearing its master string and supplied directive.")
- to_chat(pai, "Warning: System override detected, check directive sub-system for any changes.'")
+ to_chat(user, span_notice("You override [pai]'s directive system, clearing its master string and supplied directive."))
+ to_chat(pai, span_danger("Warning: System override detected, check directive sub-system for any changes.'"))
log_game("[key_name(user)] emagged [key_name(pai)], wiping their master DNA and supplemental directive.")
pai.master = null
pai.master_dna = null
@@ -372,12 +389,12 @@
if(radio_short_timerid)
deltimer(radio_short_timerid)
radio_short = TRUE
- to_chat(src, "Your radio shorts out!")
+ to_chat(src, span_danger("Your radio shorts out!"))
radio_short_timerid = addtimer(CALLBACK(src, PROC_REF(unshort_radio)), radio_short_cooldown, flags = TIMER_STOPPABLE)
/mob/living/silicon/pai/proc/unshort_radio()
radio_short = FALSE
- to_chat(src, "You feel your radio is operational once more.")
+ to_chat(src, span_danger("You feel your radio is operational once more."))
if(radio_short_timerid)
deltimer(radio_short_timerid)
diff --git a/code/modules/mob/living/silicon/pai/pai_shell.dm b/code/modules/mob/living/silicon/pai/pai_shell.dm
index 63fb82082fad..499788433b2e 100644
--- a/code/modules/mob/living/silicon/pai/pai_shell.dm
+++ b/code/modules/mob/living/silicon/pai/pai_shell.dm
@@ -101,6 +101,7 @@
if(possible_chassis[chassis])
AddElement(/datum/element/mob_holder, chassis, 'icons/mob/pai_item_head.dmi', 'icons/mob/pai_item_rh.dmi', 'icons/mob/pai_item_lh.dmi', ITEM_SLOT_HEAD)
to_chat(src, "You switch your holochassis projection composite to [chassis]")
+ return TRUE
/mob/living/silicon/pai/lay_down()
. = ..()
diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm
index a47cc1d18137..c6cefff9e63a 100644
--- a/code/modules/mob/living/silicon/robot/robot.dm
+++ b/code/modules/mob/living/silicon/robot/robot.dm
@@ -118,7 +118,7 @@
mind.transfer_to(mmi.brainmob)
mmi.update_icon()
else
- to_chat(src, "Oops! Something went very wrong, your MMI was unable to receive your mind. You have been ghosted. Please make a bug report so we can fix this bug.")
+ to_chat(src, span_boldannounce("Oops! Something went very wrong, your MMI was unable to receive your mind. You have been ghosted. Please make a bug report so we can fix this bug."))
ghostize()
stack_trace("Borg MMI lacked a brainmob")
mmi = null
@@ -153,11 +153,11 @@
return
if(wires.is_cut(WIRE_RESET_MODULE))
- to_chat(src,"ERROR: Module installer reply timeout. Please check internal connections.")
+ to_chat(src,span_userdanger("ERROR: Module installer reply timeout. Please check internal connections."))
return
if(!CONFIG_GET(flag/disable_secborg) && GLOB.security_level < CONFIG_GET(number/minimum_secborg_alert))
- to_chat(src, "NOTICE: Due to local station regulations, the security cyborg module and its variants are only available during [NUM2SECLEVEL(CONFIG_GET(number/minimum_secborg_alert))] alert and greater.")
+ to_chat(src, span_notice("NOTICE: Due to local station regulations, the security cyborg module and its variants are only available during [NUM2SECLEVEL(CONFIG_GET(number/minimum_secborg_alert))] alert and greater."))
var/list/modulelist = list("Standard" = /obj/item/robot_module/standard, \
"Engineering" = /obj/item/robot_module/engineering, \
@@ -204,7 +204,7 @@
set category = "Robot Commands"
set name = "Show Alerts"
if(usr.stat == DEAD)
- to_chat(src, "Alert: You are dead.")
+ to_chat(src, span_userdanger("Alert: You are dead."))
return //won't work if dead
alert_control.ui_interact(src)
@@ -221,7 +221,7 @@
/mob/living/silicon/robot/proc/toggle_ionpulse()
if(!ionpulse)
- to_chat(src, "No thrusters are installed!")
+ to_chat(src, span_notice("No thrusters are installed!"))
return
if(!ion_trail)
@@ -229,7 +229,7 @@
ion_trail.set_up(src)
ionpulse_on = !ionpulse_on
- to_chat(src, "You [ionpulse_on ? null :"de"]activate your ion thrusters.")
+ to_chat(src, span_notice("You [ionpulse_on ? null :"de"]activate your ion thrusters."))
if(ionpulse_on)
ion_trail.start()
else
@@ -419,7 +419,7 @@
if(!LAZYLEN(S.contents))
continue
if(!validbreakout)
- visible_message("[user] wedges [I] into the crevice separating [S] from [src]'s chassis, and begins to pry...", "You wedge [I] into the crevice separating [S] from [src]'s chassis, and begin to pry...")
+ visible_message(span_notice("[user] wedges [I] into the crevice separating [S] from [src]'s chassis, and begins to pry..."), span_notice("You wedge [I] into the crevice separating [S] from [src]'s chassis, and begin to pry..."))
validbreakout = TRUE
S.go_out()
if(validbreakout)
@@ -437,7 +437,7 @@
if("Yes")
locked = FALSE
update_icons()
- to_chat(usr, "You unlock your cover.")
+ to_chat(usr, span_notice("You unlock your cover."))
/mob/living/silicon/robot/proc/allowed(mob/M)
//check if it doesn't require any access at all
@@ -545,7 +545,7 @@
lamp_functional = FALSE
playsound(src, 'sound/effects/glass_step.ogg', 50)
toggle_headlamp(TRUE)
- to_chat(src, "Your headlamp is broken! You'll need a human to help replace it.")
+ to_chat(src, span_danger("Your headlamp is broken! You'll need a human to help replace it."))
/mob/living/silicon/robot/verb/outputlaws()
@@ -771,10 +771,10 @@
/mob/living/silicon/robot/canUseTopic(atom/movable/M, be_close=FALSE, no_dextery=FALSE, no_tk=FALSE)
if(stat || locked_down || low_power_mode)
- to_chat(src, "You can't do that right now!")
+ to_chat(src, span_warning("You can't do that right now!"))
return FALSE
if(be_close && !in_range(M, src))
- to_chat(src, "You are too far away!")
+ to_chat(src, span_warning("You are too far away!"))
return FALSE
return TRUE
@@ -1090,12 +1090,13 @@
/datum/action/innate/undeployment
name = "Disconnect from shell"
desc = "Stop controlling your shell and resume normal core operations."
- icon_icon = 'icons/mob/actions/actions_AI.dmi'
+ button_icon = 'icons/mob/actions/actions_AI.dmi'
button_icon_state = "ai_core"
required_mobility_flags = NONE
-/datum/action/innate/undeployment/Trigger()
- if(!..())
+/datum/action/innate/undeployment/Trigger(trigger_flags)
+ . = ..()
+ if(!.)
return FALSE
var/mob/living/silicon/robot/R = owner
@@ -1105,26 +1106,27 @@
/datum/action/innate/custom_holoform
name = "Select Custom Holoform"
desc = "Select one of your existing avatars to use as a holoform."
- icon_icon = 'icons/mob/actions/actions_silicon.dmi'
+ button_icon = 'icons/mob/actions/actions_silicon.dmi'
button_icon_state = "custom_holoform"
required_mobility_flags = NONE
-/datum/action/innate/custom_holoform/Trigger()
+/datum/action/innate/custom_holoform/Trigger(trigger_flags)
if(!..())
return FALSE
var/mob/living/silicon/S = owner
//if setting the holoform succeeds, attempt to set it as the current holoform for the pAI or AI
- if(S.attempt_set_custom_holoform())
- if(istype(S, /mob/living/silicon/pai))
- var/mob/living/silicon/pai/P = S
- P.chassis = "custom"
- else if(istype(S, /mob/living/silicon/ai))
- var/mob/living/silicon/ai/A = S
- if(A.client?.prefs?.custom_holoform_icon)
- A.holo_icon = A.client.prefs.get_filtered_holoform(HOLOFORM_FILTER_AI)
- else
- A.holo_icon = getHologramIcon(icon('icons/mob/ai.dmi', "female"))
+ if(!S.attempt_set_custom_holoform())
+ return FALSE
+ if(istype(S, /mob/living/silicon/pai))
+ var/mob/living/silicon/pai/P = S
+ P.chassis = "custom"
+ else if(istype(S, /mob/living/silicon/ai))
+ var/mob/living/silicon/ai/A = S
+ if(A.client?.prefs?.custom_holoform_icon)
+ A.holo_icon = A.client.prefs.get_filtered_holoform(HOLOFORM_FILTER_AI)
+ else
+ A.holo_icon = getHologramIcon(icon('icons/mob/ai.dmi', "female"))
return TRUE
@@ -1167,7 +1169,7 @@
/mob/living/silicon/robot/buckle_mob(mob/living/M, force = FALSE, check_loc = TRUE)
if(!is_type_in_typecache(M, can_ride_typecache))
- M.visible_message("[M] really can't seem to mount [src]...")
+ M.visible_message(span_warning("[M] really can't seem to mount [src]..."))
return
var/datum/component/riding/riding_datum = LoadComponent(/datum/component/riding/cyborg)
@@ -1180,13 +1182,13 @@
if(stat || incapacitated())
return
if(module && !module.allow_riding)
- M.visible_message("Unfortunately, [M] just can't seem to hold onto [src]!")
+ M.visible_message(span_boldwarning("Unfortunately, [M] just can't seem to hold onto [src]!"))
return
if(iscarbon(M) && !M.incapacitated() && !riding_datum.equip_buckle_inhands(M, 1))
if(M.get_num_arms() <= 0)
- M.visible_message("[M] can't climb onto [src] because [M.p_they()] don't have any usable arms!")
+ M.visible_message(span_boldwarning("[M] can't climb onto [src] because [M.p_they()] don't have any usable arms!"))
else
- M.visible_message("[M] can't climb onto [src] because [M.p_their()] hands are full!")
+ M.visible_message(span_boldwarning("[M] can't climb onto [src] because [M.p_their()] hands are full!"))
return
. = ..(M, force, check_loc)
diff --git a/code/modules/mob/living/silicon/robot/robot_mobility.dm b/code/modules/mob/living/silicon/robot/robot_mobility.dm
index c5863b523f0f..dc8dc42611a1 100644
--- a/code/modules/mob/living/silicon/robot/robot_mobility.dm
+++ b/code/modules/mob/living/silicon/robot/robot_mobility.dm
@@ -10,6 +10,6 @@
newflags |= MOBILITY_FLAGS_ANY_INTERACTION
mobility_flags = newflags
update_transform()
- update_action_buttons_icon()
+ update_mob_action_buttons()
update_icons()
return mobility_flags
diff --git a/code/modules/mob/living/simple_animal/constructs.dm b/code/modules/mob/living/simple_animal/constructs.dm
index 0a84d5afc892..ba92f018df2d 100644
--- a/code/modules/mob/living/simple_animal/constructs.dm
+++ b/code/modules/mob/living/simple_animal/constructs.dm
@@ -432,7 +432,7 @@
/datum/action/innate/seek_prey
name = "Seek the Harvest"
desc = "None can hide from Nar'Sie, activate to track a survivor attempting to flee the red harvest!"
- icon_icon = 'icons/mob/actions/actions_cult.dmi'
+ button_icon = 'icons/mob/actions/actions_cult.dmi'
background_icon_state = "bg_demon"
buttontooltipstyle = "cult"
button_icon_state = "cult_mark"
diff --git a/code/modules/mob/living/simple_animal/friendly/drone/inventory.dm b/code/modules/mob/living/simple_animal/friendly/drone/inventory.dm
index c956e19a857a..aed1cc33f880 100644
--- a/code/modules/mob/living/simple_animal/friendly/drone/inventory.dm
+++ b/code/modules/mob/living/simple_animal/friendly/drone/inventory.dm
@@ -42,6 +42,12 @@
return internal_storage
return ..()
+/mob/living/simple_animal/drone/get_slot_by_item(obj/item/looking_for)
+ if(internal_storage == looking_for)
+ return ITEM_SLOT_DEX_STORAGE
+ if(head == looking_for)
+ return ITEM_SLOT_HEAD
+ return ..()
/mob/living/simple_animal/drone/equip_to_slot(obj/item/I, slot)
if(!slot)
diff --git a/code/modules/mob/living/simple_animal/hostile/bosses/boss.dm b/code/modules/mob/living/simple_animal/hostile/bosses/boss.dm
index 88f25eb5cee0..500bc237ebc4 100644
--- a/code/modules/mob/living/simple_animal/hostile/bosses/boss.dm
+++ b/code/modules/mob/living/simple_animal/hostile/bosses/boss.dm
@@ -59,7 +59,7 @@
. = ..()
boss = null
-/datum/action/boss/IsAvailable(silent = FALSE)
+/datum/action/boss/IsAvailable(feedback = TRUE)
. = ..()
if(!.)
return
@@ -72,14 +72,16 @@
if(!boss.client && needs_target && !boss.target)
return FALSE
-/datum/action/boss/Trigger()
+/datum/action/boss/Trigger(trigger_flags)
. = ..()
if(!.)
- return
+ return FALSE
if(!boss.atb.spend(boss_cost))
return FALSE
- if(say_when_triggered)
- boss.say(say_when_triggered, forced = "boss action")
+ if(!say_when_triggered)
+ return FALSE
+ boss.say(say_when_triggered, forced = "boss action")
+ return TRUE
//Example:
/*
@@ -143,7 +145,7 @@
var/datum/action/boss/AB = ab
if(!boss.client && (!AB.req_statuses || (boss.AIStatus in AB.req_statuses)) && prob(AB.usage_probability) && AB.Trigger())
break
- AB.UpdateButtons(TRUE)
+ AB.build_all_button_icons()
/datum/boss_active_timed_battle/Destroy()
diff --git a/code/modules/mob/living/simple_animal/hostile/bosses/paperwizard.dm b/code/modules/mob/living/simple_animal/hostile/bosses/paperwizard.dm
index 82a6b837e00f..ba2ca18a02a9 100644
--- a/code/modules/mob/living/simple_animal/hostile/bosses/paperwizard.dm
+++ b/code/modules/mob/living/simple_animal/hostile/bosses/paperwizard.dm
@@ -30,7 +30,7 @@
//Lets the wizard summon his art to fight for him
/datum/action/boss/wizard_summon_minions
name = "Summon Minions"
- icon_icon = 'icons/mob/actions/actions_minor_antag.dmi'
+ button_icon = 'icons/mob/actions/actions_minor_antag.dmi'
button_icon_state = "art_summon"
usage_probability = 20
boss_cost = 30
@@ -42,10 +42,10 @@
var/maximum_stickmen = 6
var/stickmen_to_summon = 3
-/datum/action/boss/wizard_summon_minions/Trigger()
+/datum/action/boss/wizard_summon_minions/Trigger(trigger_flags)
. =..()
if(!.)
- return
+ return FALSE
var/to_summon = stickmen_to_summon
var/current_len = length(summoned_minions)
if(current_len > maximum_stickmen - stickmen_to_summon)
@@ -71,6 +71,7 @@
S.faction = boss.faction
RegisterSignal(S, COMSIG_PARENT_QDELETING, PROC_REF(remove_from_list))
summoned_minions += S
+ return TRUE
/datum/action/boss/wizard_summon_minions/proc/remove_from_list(datum/source, forced)
summoned_minions -= source
@@ -81,7 +82,7 @@
//Hitting the wizard himself destroys all decoys
/datum/action/boss/wizard_mimic
name = "Craft Mimicry"
- icon_icon = 'icons/mob/actions/actions_minor_antag.dmi'
+ button_icon = 'icons/mob/actions/actions_minor_antag.dmi'
button_icon_state = "mimic_summon"
usage_probability = 30
boss_cost = 40
@@ -89,10 +90,10 @@
req_statuses = list(AI_ON)
say_when_triggered = ""
-/datum/action/boss/wizard_mimic/Trigger()
+/datum/action/boss/wizard_mimic/Trigger(trigger_flags)
. = ..()
if(!.)
- return
+ return FALSE
var/mob/living/target
if(!boss.client) //AI's target
target = boss.target
@@ -102,6 +103,7 @@
target = pick(threats)
else
to_chat(owner, "There is no potential foe of different faction around to attack")
+ return FALSE
if(target)
var/mob/living/simple_animal/hostile/boss/paper_wizard/wiz = boss
var/directions = GLOB.cardinals.Copy()
@@ -114,8 +116,10 @@
wiz.forceMove(get_step(target,pick_n_take(directions)))
wiz.minimum_distance = 1 //so he doesn't run away and ruin everything
wiz.retreat_distance = 0
+ return TRUE
else
boss.atb.refund(boss_cost)
+ return FALSE
/mob/living/simple_animal/hostile/boss/paper_wizard/copy
desc = "'Tis a ruse!"
diff --git a/code/modules/mob/living/simple_animal/hostile/giant_spider.dm b/code/modules/mob/living/simple_animal/hostile/giant_spider.dm
index c4a389cd2c8f..e271a6922f69 100644
--- a/code/modules/mob/living/simple_animal/hostile/giant_spider.dm
+++ b/code/modules/mob/living/simple_animal/hostile/giant_spider.dm
@@ -77,8 +77,8 @@
/mob/living/simple_animal/hostile/poison/giant_spider/Login()
..()
if(directive)
- to_chat(src, "Your mother left you a directive! Follow it at all costs.")
- to_chat(src, "[directive]")
+ to_chat(src, span_notice("Your mother left you a directive! Follow it at all costs."))
+ to_chat(src, span_spider("[directive]"))
/mob/living/simple_animal/hostile/poison/giant_spider/attack_ghost(mob/user)
. = ..()
@@ -97,7 +97,7 @@
if(spider_ask == "No" || !src || QDELETED(src))
return TRUE
if(key)
- to_chat(user, "Someone else already took this spider.")
+ to_chat(user, span_notice("Someone else already took this spider."))
return TRUE
user.transfer_ckey(src, FALSE)
return TRUE
@@ -313,19 +313,19 @@
/mob/living/simple_animal/hostile/poison/giant_spider/nurse/proc/cocoon()
if(stat != DEAD && cocoon_target && !cocoon_target.anchored)
if(cocoon_target == src)
- to_chat(src, "You can't wrap yourself!")
+ to_chat(src, span_warning("You can't wrap yourself!"))
return
if(istype(cocoon_target, /mob/living/simple_animal/hostile/poison/giant_spider))
- to_chat(src, "You can't wrap other spiders!")
+ to_chat(src, span_warning("You can't wrap other spiders!"))
return
if(!Adjacent(cocoon_target))
- to_chat(src, "You can't reach [cocoon_target]!")
+ to_chat(src, span_warning("You can't reach [cocoon_target]!"))
return
if(busy == SPINNING_COCOON)
- to_chat(src, "You're already spinning a cocoon!")
+ to_chat(src, span_warning("You're already spinning a cocoon!"))
return //we're already doing this, don't cancel out or anything
busy = SPINNING_COCOON
- visible_message("[src] begins to secrete a sticky substance around [cocoon_target].","You begin wrapping [cocoon_target] into a cocoon.")
+ visible_message(span_notice("[src] begins to secrete a sticky substance around [cocoon_target]."),span_notice("You begin wrapping [cocoon_target] into a cocoon."))
stop_automated_movement = TRUE
walk(src,0)
if(do_after(src, 50, target = cocoon_target))
@@ -336,11 +336,11 @@
if(L.blood_volume && (L.stat != DEAD || !consumed_mobs[L.tag])) //if they're not dead, you can consume them anyway
consumed_mobs[L.tag] = TRUE
fed++
- lay_eggs.UpdateButtons(TRUE)
- visible_message("[src] sticks a proboscis into [L] and sucks a viscous substance out.","You suck the nutriment out of [L], feeding you enough to lay a cluster of eggs.")
+ lay_eggs.build_all_button_icons()
+ visible_message(span_danger("[src] sticks a proboscis into [L] and sucks a viscous substance out."),span_notice("You suck the nutriment out of [L], feeding you enough to lay a cluster of eggs."))
L.death() //you just ate them, they're dead.
else
- to_chat(src, "[L] cannot sate your hunger!")
+ to_chat(src, span_warning("[L] cannot sate your hunger!"))
cocoon_target.forceMove(C)
if(cocoon_target.density || ismob(cocoon_target))
@@ -350,7 +350,7 @@
stop_automated_movement = FALSE
/datum/action/innate/spider
- icon_icon = 'icons/mob/actions/actions_animal.dmi'
+ button_icon = 'icons/mob/actions/actions_animal.dmi'
background_icon_state = "bg_alien"
/datum/action/innate/spider/lay_web
@@ -371,12 +371,12 @@
var/obj/structure/spider/stickyweb/W = locate() in T
var/obj/structure/arachnid/W2 = locate() in T
if(W || W2)
- to_chat(S, "There's already a web here!")
+ to_chat(S, span_warning("There's already a web here!"))
return
if(S.busy != SPINNING_WEB)
S.busy = SPINNING_WEB
- S.visible_message("[S] begins to secrete a sticky substance.","You begin to lay a web.")
+ S.visible_message(span_notice("[S] begins to secrete a sticky substance."),span_notice("You begin to lay a web."))
S.stop_automated_movement = TRUE
if(do_after(S, 40, target = T))
if(S.busy == SPINNING_WEB && S.loc == T)
@@ -384,7 +384,7 @@
S.busy = SPIDER_IDLE
S.stop_automated_movement = FALSE
else
- to_chat(S, "You're already spinning a web!")
+ to_chat(S, span_warning("You're already spinning a web!"))
/obj/effect/proc_holder/wrap
name = "Wrap"
@@ -403,7 +403,7 @@
/obj/effect/proc_holder/wrap/update_icon()
. = ..()
action.button_icon_state = "wrap_[active]"
- action.UpdateButtons()
+ action.build_all_button_icons()
/obj/effect/proc_holder/wrap/Trigger(mob/living/simple_animal/hostile/poison/giant_spider/nurse/user)
if(!istype(user))
@@ -414,10 +414,10 @@
/obj/effect/proc_holder/wrap/proc/activate(mob/living/user)
var/message
if(active)
- message = "You no longer prepare to wrap something in a cocoon."
+ message = span_notice("You no longer prepare to wrap something in a cocoon.")
remove_ranged_ability(message)
else
- message = "You prepare to wrap something in a cocoon. Left-click your target to start wrapping!"
+ message = span_notice("You prepare to wrap something in a cocoon. Left-click your target to start wrapping!")
add_ranged_ability(user, message, TRUE)
return TRUE
@@ -448,7 +448,7 @@
check_flags = AB_CHECK_CONSCIOUS
button_icon_state = "lay_eggs"
-/datum/action/innate/spider/lay_eggs/IsAvailable(silent = FALSE)
+/datum/action/innate/spider/lay_eggs/IsAvailable(feedback = TRUE)
if(..())
if(!istype(owner, /mob/living/simple_animal/hostile/poison/giant_spider/nurse))
return FALSE
@@ -464,12 +464,12 @@
var/obj/structure/spider/eggcluster/E = locate() in get_turf(S)
if(E)
- to_chat(S, "There is already a cluster of eggs here!")
+ to_chat(S, span_warning("There is already a cluster of eggs here!"))
else if(!S.fed)
- to_chat(S, "You are too hungry to do this!")
+ to_chat(S, span_warning("You are too hungry to do this!"))
else if(S.busy != LAYING_EGGS)
S.busy = LAYING_EGGS
- S.visible_message("[S] begins to lay a cluster of eggs.","You begin to lay a cluster of eggs.")
+ S.visible_message(span_notice("[S] begins to lay a cluster of eggs."),span_notice("You begin to lay a cluster of eggs."))
S.stop_automated_movement = TRUE
if(do_after(S, 50, target = get_turf(S)))
if(S.busy == LAYING_EGGS)
@@ -483,7 +483,7 @@
C.poison_per_bite = S.poison_per_bite
C.faction = S.faction.Copy()
S.fed--
- UpdateButtons(TRUE)
+ build_all_button_icons()
S.busy = SPIDER_IDLE
S.stop_automated_movement = FALSE
@@ -512,14 +512,17 @@
desc = "Send a command to all living spiders."
button_icon_state = "command"
-/datum/action/innate/spider/comm/IsAvailable(silent = FALSE)
+/datum/action/innate/spider/comm/IsAvailable(feedback = TRUE)
if(!istype(owner, /mob/living/simple_animal/hostile/poison/giant_spider/nurse/midwife))
return FALSE
return TRUE
-/datum/action/innate/spider/comm/Trigger()
+/datum/action/innate/spider/comm/Trigger(trigger_flags)
+ . = ..()
+ if(!.)
+ return FALSE
var/input = stripped_input(owner, "Input a command for your legions to follow.", "Command", "")
- if(QDELETED(src) || !input || !IsAvailable())
+ if(QDELETED(src) || !input || !IsAvailable(feedback = TRUE))
return FALSE
spider_command(owner, input)
return TRUE
@@ -528,7 +531,7 @@
if(!message)
return
var/my_message
- my_message = "Command from [user]: [message]"
+ my_message = span_spider("Command from [user]: [message]")
for(var/mob/living/simple_animal/hostile/poison/giant_spider/M in GLOB.spidermobs)
to_chat(M, my_message)
for(var/M in GLOB.dead_mob_list)
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner.dm
index 8b657fc72943..decbee69d3c0 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner.dm
@@ -64,21 +64,21 @@ Difficulty: Medium
/datum/action/innate/megafauna_attack/dash
name = "Dash To Target"
- icon_icon = 'icons/mob/actions/actions_items.dmi'
+ button_icon = 'icons/mob/actions/actions_items.dmi'
button_icon_state = "sniper_zoom"
chosen_message = "You are now dashing to your target."
chosen_attack_num = 1
/datum/action/innate/megafauna_attack/kinetic_accelerator
name = "Fire Kinetic Accelerator"
- icon_icon = 'icons/obj/guns/energy.dmi'
+ button_icon = 'icons/obj/guns/energy.dmi'
button_icon_state = "kineticgun"
chosen_message = "You are now shooting your kinetic accelerator."
chosen_attack_num = 2
/datum/action/innate/megafauna_attack/transform_weapon
name = "Transform Weapon"
- icon_icon = 'icons/obj/lavaland/artefacts.dmi'
+ button_icon = 'icons/obj/lavaland/artefacts.dmi'
button_icon_state = "cleaving_saw"
chosen_message = "You are now transforming your weapon."
chosen_attack_num = 3
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/demonic_frost_miner.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/demonic_frost_miner.dm
index f3ba99864616..e2247f6ee3dc 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/demonic_frost_miner.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/demonic_frost_miner.dm
@@ -55,21 +55,21 @@ Difficulty: Extremely Hard
/datum/action/innate/megafauna_attack/frost_orbs
name = "Fire Frost Orbs"
- icon_icon = 'icons/mob/actions/actions_items.dmi'
+ button_icon = 'icons/mob/actions/actions_items.dmi'
button_icon_state = "sniper_zoom"
chosen_message = "You are now sending out frost orbs to track in on a target."
chosen_attack_num = 1
/datum/action/innate/megafauna_attack/snowball_machine_gun
name = "Fire Snowball Machine Gun"
- icon_icon = 'icons/obj/guns/energy.dmi'
+ button_icon = 'icons/obj/guns/energy.dmi'
button_icon_state = "kineticgun"
chosen_message = "You are now firing a snowball machine gun at a target."
chosen_attack_num = 2
/datum/action/innate/megafauna_attack/ice_shotgun
name = "Fire Ice Shotgun"
- icon_icon = 'icons/obj/guns/projectile.dmi'
+ button_icon = 'icons/obj/guns/projectile.dmi'
button_icon_state = "shotgun"
chosen_message = "You are now firing shotgun ice blasts."
chosen_attack_num = 3
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm
index 8111dbb36615..549a73b1df28 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm
@@ -695,7 +695,7 @@ Difficulty: Normal
new /obj/effect/temp_visual/hierophant/telegraph/teleport(get_turf(src), user)
to_chat(user, "You collect [src], reattaching it to the club!")
H.beacon = null
- user.update_action_buttons_icon()
+ user.update_mob_action_buttons()
qdel(src)
else
H.timer = world.time
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/megafauna.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/megafauna.dm
index 64566abb9d53..adb571f84176 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/megafauna.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/megafauna.dm
@@ -179,7 +179,7 @@
/datum/action/innate/megafauna_attack
name = "Megafauna Attack"
- icon_icon = 'icons/mob/actions/actions_animal.dmi'
+ button_icon = 'icons/mob/actions/actions_animal.dmi'
button_icon_state = ""
var/mob/living/simple_animal/hostile/megafauna/M
var/chosen_message
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/wendigo.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/wendigo.dm
index aada6229303b..3d121470c2dd 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/wendigo.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/wendigo.dm
@@ -51,21 +51,21 @@ Difficulty: Hard
/datum/action/innate/megafauna_attack/heavy_stomp
name = "Heavy Stomp"
- icon_icon = 'icons/mob/actions/actions_items.dmi'
+ button_icon = 'icons/mob/actions/actions_items.dmi'
button_icon_state = "sniper_zoom"
chosen_message = "You are now stomping the ground around you."
chosen_attack_num = 1
/datum/action/innate/megafauna_attack/teleport
name = "Teleport"
- icon_icon = 'icons/effects/bubblegum.dmi'
+ button_icon = 'icons/effects/bubblegum.dmi'
button_icon_state = "smack ya one"
chosen_message = "You are now teleporting at the target you click on."
chosen_attack_num = 2
/datum/action/innate/megafauna_attack/disorienting_scream
name = "Disorienting Scream"
- icon_icon = 'icons/turf/walls/wall.dmi'
+ button_icon = 'icons/turf/walls/wall.dmi'
button_icon_state = "wall"
chosen_message = "You are now screeching, disorienting targets around you."
chosen_attack_num = 3
diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/elite.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/elite.dm
index bd9790733706..0183de23a213 100644
--- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/elite.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/elites/elite.dm
@@ -73,13 +73,13 @@ While using this makes the system rely on OnFire, it still gives options for tim
/datum/action/innate/elite_attack
name = "Elite Attack"
- icon_icon = 'icons/mob/actions/actions_elites.dmi'
+ button_icon = 'icons/mob/actions/actions_elites.dmi'
button_icon_state = ""
background_icon_state = "bg_default"
var/chosen_message
var/chosen_attack_num = 0
-/datum/action/innate/elite_attack/CreateButton()
+/datum/action/innate/elite_attack/create_button()
var/atom/movable/screen/movable/action_button/button = ..()
button.maptext = ""
button.maptext_x = 8
@@ -93,20 +93,19 @@ While using this makes the system rely on OnFire, it still gives options for tim
STOP_PROCESSING(SSfastprocess, src)
qdel(src)
return
- UpdateButtons()
+ build_all_button_icons(UPDATE_BUTTON_STATUS)
-/datum/action/innate/elite_attack/UpdateButton(atom/movable/screen/movable/action_button/button, status_only = FALSE, force = FALSE)
- . = ..()
- if(!.)
- return
- if(status_only)
- return
+/datum/action/innate/elite_attack/update_button_status(atom/movable/screen/movable/action_button/button, force = FALSE)
var/mob/living/simple_animal/hostile/asteroid/elite/elite_owner = owner
+ if(!istype(owner))
+ button.maptext = ""
+ return
+
var/timeleft = max(elite_owner.ranged_cooldown - world.time, 0)
if(timeleft == 0)
button.maptext = ""
else
- button.maptext = "[round(timeleft/10, 0.1)]"
+ button.maptext = MAPTEXT("[round(timeleft/10, 0.1)]")
/datum/action/innate/elite_attack/Grant(mob/living/L)
if(istype(L, /mob/living/simple_animal/hostile/asteroid/elite))
diff --git a/code/modules/mob/living/simple_animal/hostile/plaguerat.dm b/code/modules/mob/living/simple_animal/hostile/plaguerat.dm
index 88118d179b9f..2cd78f2fd040 100644
--- a/code/modules/mob/living/simple_animal/hostile/plaguerat.dm
+++ b/code/modules/mob/living/simple_animal/hostile/plaguerat.dm
@@ -162,7 +162,7 @@ GLOBAL_LIST_EMPTY(plague_rats)
/datum/action/cooldown/scavenge
name = "Scavenge"
desc = "Spread the plague, scavenge for trash and fresh meat to reproduce."
- icon_icon = 'icons/mob/actions/actions_animal.dmi'
+ button_icon = 'icons/mob/actions/actions_animal.dmi'
background_icon_state = "bg_clock"
button_icon_state = "coffer"
cooldown_time = 50
diff --git a/code/modules/mob/living/simple_animal/hostile/regalrat.dm b/code/modules/mob/living/simple_animal/hostile/regalrat.dm
index 87c7d0519bb6..6efad3c0ec5d 100644
--- a/code/modules/mob/living/simple_animal/hostile/regalrat.dm
+++ b/code/modules/mob/living/simple_animal/hostile/regalrat.dm
@@ -83,7 +83,7 @@
/datum/action/cooldown/coffer
name = "Fill Coffers"
desc = "Your newly granted regality and poise let you scavenge for lost junk, but more importantly, cheese."
- icon_icon = 'icons/mob/actions/actions_animal.dmi'
+ button_icon = 'icons/mob/actions/actions_animal.dmi'
background_icon_state = "bg_clock"
button_icon_state = "coffer"
cooldown_time = 50
@@ -125,7 +125,7 @@
/datum/action/cooldown/riot
name = "Raise Army"
desc = "Raise an army out of the hordes of mice and pests crawling around the maintenance shafts."
- icon_icon = 'icons/mob/actions/actions_animal.dmi'
+ button_icon = 'icons/mob/actions/actions_animal.dmi'
button_icon_state = "riot"
background_icon_state = "bg_clock"
cooldown_time = 80
diff --git a/code/modules/mob/living/simple_animal/hostile/space_dragon.dm b/code/modules/mob/living/simple_animal/hostile/space_dragon.dm
index 2f0c42bf77f8..a4c96648961e 100644
--- a/code/modules/mob/living/simple_animal/hostile/space_dragon.dm
+++ b/code/modules/mob/living/simple_animal/hostile/space_dragon.dm
@@ -488,7 +488,7 @@
name = "Summon Rift"
desc = "Summon a rift to bring forth a horde of space carp."
background_icon_state = "bg_default"
- icon_icon = 'icons/mob/actions/actions_space_dragon.dmi'
+ button_icon = 'icons/mob/actions/actions_space_dragon.dmi'
button_icon_state = "carp_rift"
/datum/action/innate/summon_rift/Activate()
diff --git a/code/modules/mob/living/simple_animal/hostile/wumborian_fugu.dm b/code/modules/mob/living/simple_animal/hostile/wumborian_fugu.dm
index 62d989a31e26..118fb67ea71e 100644
--- a/code/modules/mob/living/simple_animal/hostile/wumborian_fugu.dm
+++ b/code/modules/mob/living/simple_animal/hostile/wumborian_fugu.dm
@@ -65,7 +65,7 @@
E.Activate()
/datum/action/innate/fugu
- icon_icon = 'icons/mob/actions/actions_animal.dmi'
+ button_icon = 'icons/mob/actions/actions_animal.dmi'
/datum/action/innate/fugu/expand
name = "Inflate"
diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm
index c7e753744c95..a616fd17c7ac 100644
--- a/code/modules/mob/living/simple_animal/simple_animal.dm
+++ b/code/modules/mob/living/simple_animal/simple_animal.dm
@@ -484,7 +484,7 @@
if(!CHECK_MOBILITY(src, MOBILITY_MOVE)) // !(mobility_flags & MOBILITY_MOVE)
walk(src, 0) //stop mid walk
update_transform()
- update_action_buttons_icon()
+ update_mob_action_buttons()
return mobility_flags
/mob/living/simple_animal/update_transform(do_animate)
diff --git a/code/modules/mob/living/simple_animal/slime/life.dm b/code/modules/mob/living/simple_animal/slime/life.dm
index 8e66ae14e34a..b98f82a312f0 100644
--- a/code/modules/mob/living/simple_animal/slime/life.dm
+++ b/code/modules/mob/living/simple_animal/slime/life.dm
@@ -249,7 +249,7 @@
else if (nutrition >= get_grow_nutrition() && amount_grown < SLIME_EVOLUTION_THRESHOLD)
adjust_nutrition(-20)
amount_grown++
- update_action_buttons_icon()
+ update_mob_action_buttons()
if(amount_grown >= SLIME_EVOLUTION_THRESHOLD && !buckled && !Target && !ckey)
if(is_adult)
diff --git a/code/modules/mob/living/simple_animal/slime/powers.dm b/code/modules/mob/living/simple_animal/slime/powers.dm
index 3624c00e6dbf..975bbe8ae370 100644
--- a/code/modules/mob/living/simple_animal/slime/powers.dm
+++ b/code/modules/mob/living/simple_animal/slime/powers.dm
@@ -7,11 +7,11 @@
/datum/action/innate/slime
check_flags = AB_CHECK_CONSCIOUS
- icon_icon = 'icons/mob/actions/actions_slime.dmi'
+ button_icon = 'icons/mob/actions/actions_slime.dmi'
background_icon_state = "bg_alien"
var/needs_growth = NO_GROWTH_NEEDED
-/datum/action/innate/slime/IsAvailable(silent = FALSE)
+/datum/action/innate/slime/IsAvailable(feedback = TRUE)
if(..())
var/mob/living/simple_animal/slime/S = owner
if(needs_growth == GROWTH_NEEDED)
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index d700de554a83..1eed683a50f9 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -234,9 +234,19 @@
if(self_message)
show_message(self_message, MSG_AUDIBLE, deaf_message, MSG_VISUAL)
+///Get the item on the mob in the storage slot identified by the id passed in
/mob/proc/get_item_by_slot(slot_id)
return null
+/// Gets what slot the item on the mob is held in.
+/// Returns null if the item isn't in any slots on our mob.
+/// Does not check if the passed item is null, which may result in unexpected outcoms.
+/mob/proc/get_slot_by_item(obj/item/looking_for)
+ if(looking_for in held_items)
+ return ITEM_SLOT_HANDS
+
+ return null
+
/mob/proc/restrained(ignore_grab)
return
diff --git a/code/modules/mod/mod_actions.dm b/code/modules/mod/mod_actions.dm
index ee28771ef108..9cad31912bd0 100644
--- a/code/modules/mod/mod_actions.dm
+++ b/code/modules/mod/mod_actions.dm
@@ -1,8 +1,7 @@
/datum/action/item_action/mod
background_icon_state = "bg_tech_blue"
- icon_icon = 'icons/mob/actions/actions_mod.dmi'
+ button_icon = 'icons/mob/actions/actions_mod.dmi'
check_flags = AB_CHECK_CONSCIOUS
- var/obj/item/mod/control/mod
/// Whether this action is intended for the AI. Stuff breaks a lot if this is done differently.
var/ai_action = FALSE
@@ -12,10 +11,10 @@
qdel(src)
return
if(ai_action)
- background_icon_state = "bg_tech"
+ background_icon_state = ACTION_BUTTON_DEFAULT_BACKGROUND
/datum/action/item_action/mod/Grant(mob/user)
- mod = target
+ var/obj/item/mod/control/mod = target
if(ai_action && user != mod.ai)
return
else if(!ai_action && user == mod.ai)
@@ -23,15 +22,15 @@
return ..()
/datum/action/item_action/mod/Remove(mob/user)
+ var/obj/item/mod/control/mod = target
if(ai_action && mod && user != mod.ai)
return
else if(!ai_action && mod && user == mod.ai)
return
return ..()
-/datum/action/item_action/mod/Trigger(trigger_flags)
- if(!IsAvailable())
- return FALSE
+/datum/action/item_action/mod/do_effect(trigger_flags)
+ var/obj/item/mod/control/mod = target
if(mod.malfunctioning && prob(75))
mod.balloon_alert(usr, "button malfunctions!")
return FALSE
@@ -42,11 +41,12 @@
desc = "Deploy/Conceal a part of the MODsuit."
button_icon_state = "deploy"
-/datum/action/item_action/mod/deploy/Trigger()
- if(!IsAvailable())
- return FALSE
+/datum/action/item_action/mod/deploy/do_effect(trigger_flags)
+ . = ..()
+ if(!.)
+ return
+ var/obj/item/mod/control/mod = target
mod.choose_deploy(usr)
- return TRUE
/datum/action/item_action/mod/deploy/ai
ai_action = TRUE
@@ -56,11 +56,12 @@
desc = "Activate/Deactivate the MODsuit."
button_icon_state = "activate"
-/datum/action/item_action/mod/activate/Trigger()
- if(!IsAvailable())
- return FALSE
+/datum/action/item_action/mod/activate/do_effect(trigger_flags)
+ . = ..()
+ if(!.)
+ return
+ var/obj/item/mod/control/mod = target
mod.toggle_activate(usr)
- return TRUE
/datum/action/item_action/mod/activate/ai
ai_action = TRUE
@@ -70,11 +71,12 @@
desc = "Toggle a MODsuit module."
button_icon_state = "module"
-/datum/action/item_action/mod/module/Trigger()
- if(!IsAvailable())
- return FALSE
+/datum/action/item_action/mod/module/do_effect(trigger_flags)
+ . = ..()
+ if(!.)
+ return
+ var/obj/item/mod/control/mod = target
mod.quick_module(usr)
- return TRUE
/datum/action/item_action/mod/module/ai
ai_action = TRUE
@@ -84,11 +86,12 @@
desc = "Open the MODsuit's panel."
button_icon_state = "panel"
-/datum/action/item_action/mod/panel/Trigger()
- if(!IsAvailable())
- return FALSE
+/datum/action/item_action/mod/panel/do_effect(trigger_flags)
+ . = ..()
+ if(!.)
+ return
+ var/obj/item/mod/control/mod = target
mod.ui_interact(usr)
- return TRUE
/datum/action/item_action/mod/panel/ai
ai_action = TRUE
diff --git a/code/modules/mod/mod_control.dm b/code/modules/mod/mod_control.dm
index 40f7fa1a932c..4dc33aa222e7 100644
--- a/code/modules/mod/mod_control.dm
+++ b/code/modules/mod/mod_control.dm
@@ -431,7 +431,7 @@
/obj/item/mod/control/proc/quick_module(mob/user)
if(!length(modules))
- return
+ return FALSE
var/list/display_names = list()
var/list/items = list()
for(var/obj/item/mod/module/module as anything in modules)
@@ -441,15 +441,16 @@
var/image/module_image = image(icon = module.icon, icon_state = module.icon_state)
items += list(module.name = module_image)
if(!length(items))
- return
+ return FALSE
var/pick = show_radial_menu(user, src, items, custom_check = FALSE, require_near = TRUE)
if(!pick)
- return
+ return FALSE
var/module_reference = display_names[pick]
var/obj/item/mod/module/selected_module = locate(module_reference) in modules
if(!istype(selected_module) || user.incapacitated())
- return
+ return FALSE
selected_module.on_select()
+ return TRUE
/obj/item/mod/control/proc/set_mod_color(new_color)
var/list/all_parts = mod_parts + src
diff --git a/code/modules/ninja/suit/ninja_equipment_actions/ninja_adrenaline.dm b/code/modules/ninja/suit/ninja_equipment_actions/ninja_adrenaline.dm
index 4dc9e738ecca..1202b4aec53c 100644
--- a/code/modules/ninja/suit/ninja_equipment_actions/ninja_adrenaline.dm
+++ b/code/modules/ninja/suit/ninja_equipment_actions/ninja_adrenaline.dm
@@ -6,7 +6,7 @@
name = "Adrenaline Boost"
desc = "Inject a secret chemical that will counteract all movement-impairing effect."
button_icon_state = "adrenal"
- icon_icon = 'icons/obj/implants.dmi'
+ button_icon = 'icons/obj/implants.dmi'
required_mobility_flags = NONE
/**
diff --git a/code/modules/ninja/suit/ninja_equipment_actions/ninja_empulse.dm b/code/modules/ninja/suit/ninja_equipment_actions/ninja_empulse.dm
index ea2341a13235..8e75dbcb89a9 100644
--- a/code/modules/ninja/suit/ninja_equipment_actions/ninja_empulse.dm
+++ b/code/modules/ninja/suit/ninja_equipment_actions/ninja_empulse.dm
@@ -4,7 +4,7 @@
name = "EM Burst (50E)"
desc = "Disable any nearby technology with an electro-magnetic pulse."
button_icon_state = "emp"
- icon_icon = 'icons/mob/actions/actions_spells.dmi'
+ button_icon = 'icons/mob/actions/actions_spells.dmi'
/**
* Proc called to allow the ninja to EMP the nearby area.
diff --git a/code/modules/ninja/suit/ninja_equipment_actions/ninja_glove_toggle.dm b/code/modules/ninja/suit/ninja_equipment_actions/ninja_glove_toggle.dm
index ec5bf078a550..0888a763fb17 100644
--- a/code/modules/ninja/suit/ninja_equipment_actions/ninja_glove_toggle.dm
+++ b/code/modules/ninja/suit/ninja_equipment_actions/ninja_glove_toggle.dm
@@ -2,7 +2,7 @@
name = "Toggle interaction"
desc = "Switch between normal interaction and drain mode."
button_icon_state = "s-ninjan"
- icon_icon = 'icons/obj/clothing/gloves.dmi'
+ button_icon = 'icons/obj/clothing/gloves.dmi'
/**
* Proc called to toggle the ninja glove's special abilities.
diff --git a/code/modules/ninja/suit/ninja_equipment_actions/ninja_net.dm b/code/modules/ninja/suit/ninja_equipment_actions/ninja_net.dm
index ab52f3e01809..6a74095f7fe5 100644
--- a/code/modules/ninja/suit/ninja_equipment_actions/ninja_net.dm
+++ b/code/modules/ninja/suit/ninja_equipment_actions/ninja_net.dm
@@ -2,7 +2,7 @@
name = "Energy Net (40E)"
desc = "Captures a fallen opponent in a net of energy."
button_icon_state = "energynet"
- icon_icon = 'icons/effects/effects.dmi'
+ button_icon = 'icons/effects/effects.dmi'
/**
* Proc called to ensnare a person in a energy net.
diff --git a/code/modules/ninja/suit/ninja_equipment_actions/ninja_stars.dm b/code/modules/ninja/suit/ninja_equipment_actions/ninja_stars.dm
index ef897d5bb9d0..f6ad28750504 100644
--- a/code/modules/ninja/suit/ninja_equipment_actions/ninja_stars.dm
+++ b/code/modules/ninja/suit/ninja_equipment_actions/ninja_stars.dm
@@ -2,7 +2,7 @@
name = "Create Throwing Stars (1E)"
desc = "Creates a throwing star in your hand, if possible."
button_icon_state = "throwingstar"
- icon_icon = 'icons/obj/items_and_weapons.dmi'
+ button_icon = 'icons/obj/items_and_weapons.dmi'
/**
* Proc called to create a ninja star in the ninja's hands.
diff --git a/code/modules/ninja/suit/ninja_equipment_actions/ninja_status_read.dm b/code/modules/ninja/suit/ninja_equipment_actions/ninja_status_read.dm
index 33e6b1ae26e2..1a18fce22d43 100644
--- a/code/modules/ninja/suit/ninja_equipment_actions/ninja_status_read.dm
+++ b/code/modules/ninja/suit/ninja_equipment_actions/ninja_status_read.dm
@@ -3,5 +3,5 @@
name = "Status Readout"
desc = "Gives a detailed readout about your current status."
button_icon_state = "health"
- icon_icon = 'icons/obj/device.dmi'
+ button_icon = 'icons/obj/device.dmi'
var/action_background_icon_state = "bg_default_on"
diff --git a/code/modules/ninja/suit/ninja_equipment_actions/ninja_stealth.dm b/code/modules/ninja/suit/ninja_equipment_actions/ninja_stealth.dm
index 079f0c53e941..73e1e5c1e394 100644
--- a/code/modules/ninja/suit/ninja_equipment_actions/ninja_stealth.dm
+++ b/code/modules/ninja/suit/ninja_equipment_actions/ninja_stealth.dm
@@ -2,7 +2,7 @@
name = "Toggle Stealth"
desc = "Toggles stealth mode on and off."
button_icon_state = "ninja_cloak"
- icon_icon = 'icons/mob/actions/actions_minor_antag.dmi'
+ button_icon = 'icons/mob/actions/actions_minor_antag.dmi'
/**
* Proc called to toggle ninja stealth.
diff --git a/code/modules/ninja/suit/ninja_equipment_actions/ninja_sword_recall.dm b/code/modules/ninja/suit/ninja_equipment_actions/ninja_sword_recall.dm
index dd6ca61f881f..37a8dc1e4843 100644
--- a/code/modules/ninja/suit/ninja_equipment_actions/ninja_sword_recall.dm
+++ b/code/modules/ninja/suit/ninja_equipment_actions/ninja_sword_recall.dm
@@ -2,7 +2,7 @@
name = "Recall Energy Katana (Variable Cost)"
desc = "Teleports the Energy Katana linked to this suit to its wearer, cost based on distance."
button_icon_state = "energy_katana"
- icon_icon = 'icons/obj/items_and_weapons.dmi'
+ button_icon = 'icons/obj/items_and_weapons.dmi'
/**
* Proc called to recall the ninja's sword.
diff --git a/code/modules/power/singularity/emitter.dm b/code/modules/power/singularity/emitter.dm
index 24b6cf71c128..151ddb6def24 100644
--- a/code/modules/power/singularity/emitter.dm
+++ b/code/modules/power/singularity/emitter.dm
@@ -426,7 +426,7 @@
for(var/obj/item/I in U.held_items)
if(istype(I, /obj/item/turret_control))
qdel(I)
- UpdateButtons()
+ build_all_button_icons()
return
else
playsound(PE,'sound/mecha/mechmove01.ogg', 50, TRUE)
@@ -443,7 +443,7 @@
else //Entries in the list should only ever be items or null, so if it's not an item, we can assume it's an empty hand
var/obj/item/turret_control/TC = new /obj/item/turret_control()
U.put_in_hands(TC)
- UpdateButtons()
+ build_all_button_icons()
/obj/item/turret_control
diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm
index f8f8182a2883..c0dc454dde3a 100644
--- a/code/modules/projectiles/gun.dm
+++ b/code/modules/projectiles/gun.dm
@@ -19,6 +19,8 @@
item_flags = NEEDS_PERMIT
attack_verb = list("struck", "hit", "bashed")
attack_speed = CLICK_CD_RANGE
+ action_slots = ALL
+
var/ranged_attack_speed = CLICK_CD_RANGE
var/melee_attack_speed = CLICK_CD_MELEE
@@ -142,7 +144,7 @@
if(fire_select_modes.len > 1)
firemode_action = new(src)
firemode_action.button_icon_state = "fireselect_[fire_select]"
- firemode_action.UpdateButtons()
+ firemode_action.build_all_button_icons()
/obj/item/gun/ComponentInitialize()
. = ..()
@@ -219,7 +221,7 @@
playsound(user, 'sound/weapons/empty.ogg', 100, TRUE)
update_appearance()
firemode_action.button_icon_state = "fireselect_[fire_select]"
- firemode_action.UpdateButtons()
+ firemode_action.build_all_button_icons()
return TRUE
/obj/item/gun/equipped(mob/living/user, slot)
@@ -670,7 +672,7 @@
update_icon()
for(var/X in actions)
var/datum/action/A = X
- A.UpdateButtons()
+ A.build_all_button_icons()
/obj/item/gun/update_overlays()
. = ..()
@@ -751,20 +753,24 @@
/datum/action/item_action/toggle_scope_zoom
name = "Toggle Scope"
- icon_icon = 'icons/mob/actions/actions_items.dmi'
+ button_icon = 'icons/mob/actions/actions_items.dmi'
button_icon_state = "sniper_zoom"
-/datum/action/item_action/toggle_scope_zoom/IsAvailable(silent = FALSE)
+/datum/action/item_action/toggle_scope_zoom/IsAvailable(feedback = TRUE)
. = ..()
if(!. && owner)
var/obj/item/gun/G = target
G.zoom(owner, owner.dir, FALSE)
-/datum/action/item_action/toggle_scope_zoom/Trigger()
+/datum/action/item_action/toggle_scope_zoom/do_effect(trigger_flags)
. = ..()
- if(.)
- var/obj/item/gun/G = target
- G.zoom(owner, owner.dir)
+ if(!.)
+ return
+ var/obj/item/gun/G = target
+ if(!istype(G))
+ return FALSE
+ G.zoom(owner, owner.dir)
+ return TRUE
/datum/action/item_action/toggle_scope_zoom/Remove(mob/living/L)
var/obj/item/gun/G = target
diff --git a/code/modules/projectiles/guns/magic/motivation.dm b/code/modules/projectiles/guns/magic/motivation.dm
index db4c222619e4..774ff21dcdd1 100644
--- a/code/modules/projectiles/guns/magic/motivation.dm
+++ b/code/modules/projectiles/guns/magic/motivation.dm
@@ -34,14 +34,18 @@
//action button to toggle judgement cuts on/off
/datum/action/judgement_cut
name = "Judgement Cut - Allows Motivation to slash at a longer distance."
- icon_icon = 'icons/obj/projectiles.dmi'
+ button_icon = 'icons/obj/projectiles.dmi'
button_icon_state = "judgement_fire"
var/judgement_toggled = TRUE
//lets the user know that you toggled them on/off
-/datum/action/judgement_cut/Trigger()
+/datum/action/judgement_cut/Trigger(trigger_flags)
+ . = ..()
+ if(!.)
+ return FALSE
judgement_toggled = !judgement_toggled
to_chat(owner, "You [judgement_toggled ? "enable" : "disable"] Judgement Cuts with Motivation.")
+ return TRUE
//Prevents "firing" the judgement cuts if toggled off and lets the user know
/obj/item/gun/magic/staff/motivation/can_trigger_gun(mob/living/user)
diff --git a/code/modules/projectiles/guns/misc/beam_rifle.dm b/code/modules/projectiles/guns/misc/beam_rifle.dm
index 4548719a20b3..7f9dd7a89b6c 100644
--- a/code/modules/projectiles/guns/misc/beam_rifle.dm
+++ b/code/modules/projectiles/guns/misc/beam_rifle.dm
@@ -174,7 +174,7 @@
fire_delay = delay
current_tracers = list()
START_PROCESSING(SSfastprocess, src)
- zoom_lock_action = new(src)
+ zoom_lock_action = add_item_action(/datum/action/item_action/zoom_lock_action)
/obj/item/gun/energy/beam_rifle/Destroy()
STOP_PROCESSING(SSfastprocess, src)
diff --git a/code/modules/projectiles/guns/misc/chameleon.dm b/code/modules/projectiles/guns/misc/chameleon.dm
index 428de747f768..f4791f88da1e 100644
--- a/code/modules/projectiles/guns/misc/chameleon.dm
+++ b/code/modules/projectiles/guns/misc/chameleon.dm
@@ -27,7 +27,7 @@
/obj/item/gun/energy/laser/chameleon/Initialize(mapload)
. = ..()
- chameleon_action = new(src)
+ chameleon_action = add_item_action(/datum/action/item_action/chameleon/change/gun)
chameleon_action.chameleon_type = /obj/item/gun
chameleon_action.chameleon_name = "Gun"
chameleon_action.chameleon_blacklist = typecacheof(/obj/item/gun/magic, ignore_root_path = FALSE)
diff --git a/code/modules/reagents/chemistry/holder.dm b/code/modules/reagents/chemistry/holder.dm
index 312f3caace66..8fdb91c40522 100644
--- a/code/modules/reagents/chemistry/holder.dm
+++ b/code/modules/reagents/chemistry/holder.dm
@@ -515,7 +515,7 @@
else if(istype(cached_my_atom, /obj/item/slime_extract))//if the object is a slime_extract.
var/obj/item/slime_extract/M = cached_my_atom
- if(M.Uses > 0) // added a limit to slime cores -- Muskets requested this
+ if(M.extract_uses > 0) // added a limit to slime cores -- Muskets requested this
matching_other = 1
else
if(!C.required_container)
@@ -608,8 +608,8 @@
if(istype(cached_my_atom, /obj/item/slime_extract))//if there's an extract and it's used up.
var/obj/item/slime_extract/ME2 = my_atom
- ME2.Uses--
- if(ME2.Uses <= 0) // give the notification that the slime core is dead
+ ME2.extract_uses--
+ if(ME2.extract_uses <= 0) // give the notification that the slime core is dead
for(var/mob/M in seen)
to_chat(M, "[iconhtml] \The [my_atom]'s power is consumed in the reaction.")
ME2.name = "used slime extract"
diff --git a/code/modules/reagents/chemistry/recipes/slime_extracts.dm b/code/modules/reagents/chemistry/recipes/slime_extracts.dm
index 45d0df55802e..4b0abd82044a 100644
--- a/code/modules/reagents/chemistry/recipes/slime_extracts.dm
+++ b/code/modules/reagents/chemistry/recipes/slime_extracts.dm
@@ -12,7 +12,7 @@
/datum/chemical_reaction/slime/proc/delete_extract(datum/reagents/holder)
var/obj/item/slime_extract/M = holder.my_atom
- if(M.Uses <= 0 && !results.len) //if the slime doesn't output chemicals
+ if(M.extract_uses <= 0 && !results.len) //if the slime doesn't output chemicals
qdel(M)
//Grey
@@ -579,7 +579,7 @@
var/turf/T = get_turf(holder.my_atom)
new /obj/effect/timestop(T, null, null, null)
if(istype(extract))
- if(extract.Uses > 0)
+ if(extract.extract_uses > 0)
var/mob/lastheld = get_mob_by_key(holder.my_atom.fingerprintslast)
if(lastheld && !lastheld.equip_to_slot_if_possible(extract, ITEM_SLOT_HANDS, disable_warning = TRUE))
extract.forceMove(get_turf(lastheld))
diff --git a/code/modules/research/nanites/nanite_programs/utility.dm b/code/modules/research/nanites/nanite_programs/utility.dm
index 5dc258fad45c..997977f7853e 100644
--- a/code/modules/research/nanites/nanite_programs/utility.dm
+++ b/code/modules/research/nanites/nanite_programs/utility.dm
@@ -337,7 +337,7 @@
/datum/action/innate/nanite_button
name = "Button"
- icon_icon = 'icons/mob/actions/actions_items.dmi'
+ button_icon = 'icons/mob/actions/actions_items.dmi'
check_flags = AB_CHECK_RESTRAINED|AB_CHECK_STUN|AB_CHECK_CONSCIOUS
button_icon_state = "nanite_power"
var/datum/nanite_program/dermal_button/program
diff --git a/code/modules/research/xenobiology/crossbreeding/_clothing.dm b/code/modules/research/xenobiology/crossbreeding/_clothing.dm
index 640aa6d49057..a2d5154c2248 100644
--- a/code/modules/research/xenobiology/crossbreeding/_clothing.dm
+++ b/code/modules/research/xenobiology/crossbreeding/_clothing.dm
@@ -58,41 +58,48 @@ Slimecrossing Armor
set_light(5)
/obj/structure/light_prism/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
- to_chat(user, "You dispel [src]")
+ to_chat(user, span_notice("You dispel [src]"))
qdel(src)
/datum/action/item_action/change_prism_colour
name = "Adjust Prismatic Lens"
- icon_icon = 'icons/obj/slimecrossing.dmi'
+ button_icon = 'icons/obj/slimecrossing.dmi'
button_icon_state = "prismcolor"
-/datum/action/item_action/change_prism_colour/Trigger()
- if(!IsAvailable())
+/datum/action/item_action/change_prism_colour/do_effect(trigger_flags)
+ . = ..()
+ if(!.)
return
var/obj/item/clothing/glasses/prism_glasses/glasses = target
+ if(!istype(glasses))
+ return FALSE
var/new_color = input(owner, "Choose the lens color:", "Color change",glasses.glasses_color) as color|null
if(!new_color)
- return
+ return FALSE
glasses.glasses_color = new_color
+ return TRUE
/datum/action/item_action/place_light_prism
name = "Fabricate Light Prism"
- icon_icon = 'icons/obj/slimecrossing.dmi'
+ button_icon = 'icons/obj/slimecrossing.dmi'
button_icon_state = "lightprism"
-/datum/action/item_action/place_light_prism/Trigger()
- if(!IsAvailable())
+/datum/action/item_action/place_light_prism/do_effect(trigger_flags)
+ . = ..()
+ if(!.)
return
var/obj/item/clothing/glasses/prism_glasses/glasses = target
if(locate(/obj/structure/light_prism) in get_turf(owner))
- to_chat(owner, "There isn't enough ambient energy to fabricate another light prism here.")
- return
- if(istype(glasses))
- if(!glasses.glasses_color)
- to_chat(owner, "The lens is oddly opaque...")
- return
- to_chat(owner, "You channel nearby light into a glowing, ethereal prism.")
- new /obj/structure/light_prism(get_turf(owner), glasses.glasses_color)
+ to_chat(owner, span_warning("There isn't enough ambient energy to fabricate another light prism here."))
+ return FALSE
+ if(!istype(glasses))
+ return FALSE
+ if(!glasses.glasses_color)
+ to_chat(owner, span_warning("The lens is oddly opaque..."))
+ return FALSE
+ to_chat(owner, span_notice("You channel nearby light into a glowing, ethereal prism."))
+ new /obj/structure/light_prism(get_turf(owner), glasses.glasses_color)
+ return TRUE
/obj/item/clothing/head/peaceflower
name = "heroine bud"
@@ -122,7 +129,7 @@ Slimecrossing Armor
if(iscarbon(user))
var/mob/living/carbon/C = user
if(src == C.head)
- to_chat(user, "You feel at peace. Why would you want anything else?")
+ to_chat(user, span_warning("You feel at peace. Why would you want anything else?"))
return
return ..()
diff --git a/code/modules/research/xenobiology/crossbreeding/burning.dm b/code/modules/research/xenobiology/crossbreeding/burning.dm
index cc2df99785d5..d4ae79a0f363 100644
--- a/code/modules/research/xenobiology/crossbreeding/burning.dm
+++ b/code/modules/research/xenobiology/crossbreeding/burning.dm
@@ -394,7 +394,7 @@ Burning extracts:
return
var/path = S.type
var/obj/item/slime_extract/C = new path(get_turf(target))
- C.Uses = S.Uses
+ C.extract_uses = S.extract_uses
to_chat(user, "You pour the potion onto [target], and the fluid solidifies into a copy of it!")
qdel(src)
return
diff --git a/code/modules/research/xenobiology/crossbreeding/recurring.dm b/code/modules/research/xenobiology/crossbreeding/recurring.dm
index 43898018823a..6625c5bda0d7 100644
--- a/code/modules/research/xenobiology/crossbreeding/recurring.dm
+++ b/code/modules/research/xenobiology/crossbreeding/recurring.dm
@@ -29,10 +29,10 @@ Recurring extracts:
/obj/item/slimecross/recurring/process()
if(cooldown > 0)
cooldown--
- else if(extract.Uses < 10 && extract.Uses > 0)
- extract.Uses++
+ else if(extract.extract_uses < 10 && extract.extract_uses > 0)
+ extract.extract_uses++
cooldown = max_cooldown
- else if(extract.Uses <= 0)
+ else if(extract.extract_uses <= 0)
extract.visible_message("The light inside [extract] flickers and dies out.")
extract.desc = "A tiny, inert core, bleeding dark, cerulean-colored goo."
extract.icon_state = "prismatic"
diff --git a/code/modules/research/xenobiology/xenobio_camera.dm b/code/modules/research/xenobiology/xenobio_camera.dm
index ee8975600080..90da0f205ad9 100644
--- a/code/modules/research/xenobiology/xenobio_camera.dm
+++ b/code/modules/research/xenobiology/xenobio_camera.dm
@@ -162,7 +162,7 @@
/datum/action/innate/slime_place
name = "Place Slimes"
- icon_icon = 'icons/mob/actions/actions_silicon.dmi'
+ button_icon = 'icons/mob/actions/actions_silicon.dmi'
button_icon_state = "slime_down"
/datum/action/innate/slime_place/Activate()
@@ -181,7 +181,7 @@
/datum/action/innate/slime_pick_up
name = "Pick up Slime"
- icon_icon = 'icons/mob/actions/actions_silicon.dmi'
+ button_icon = 'icons/mob/actions/actions_silicon.dmi'
button_icon_state = "slime_up"
/datum/action/innate/slime_pick_up/Activate()
@@ -206,7 +206,7 @@
/datum/action/innate/feed_slime
name = "Feed Slimes"
- icon_icon = 'icons/mob/actions/actions_silicon.dmi'
+ button_icon = 'icons/mob/actions/actions_silicon.dmi'
button_icon_state = "monkey_down"
/datum/action/innate/feed_slime/Activate()
@@ -230,7 +230,7 @@
/datum/action/innate/monkey_recycle
name = "Recycle Monkeys"
- icon_icon = 'icons/mob/actions/actions_silicon.dmi'
+ button_icon = 'icons/mob/actions/actions_silicon.dmi'
button_icon_state = "monkey_up"
/datum/action/innate/monkey_recycle/Activate()
@@ -250,7 +250,7 @@
/datum/action/innate/slime_scan
name = "Scan Slime"
- icon_icon = 'icons/mob/actions/actions_silicon.dmi'
+ button_icon = 'icons/mob/actions/actions_silicon.dmi'
button_icon_state = "slime_scan"
/datum/action/innate/slime_scan/Activate()
@@ -266,7 +266,7 @@
/datum/action/innate/feed_potion
name = "Apply Potion"
- icon_icon = 'icons/mob/actions/actions_silicon.dmi'
+ button_icon = 'icons/mob/actions/actions_silicon.dmi'
button_icon_state = "slime_potion"
/datum/action/innate/feed_potion/Activate()
@@ -321,7 +321,7 @@
/datum/action/innate/hotkey_help
name = "Hotkey Help"
- icon_icon = 'icons/mob/actions/actions_silicon.dmi'
+ button_icon = 'icons/mob/actions/actions_silicon.dmi'
button_icon_state = "hotkey_help"
/datum/action/innate/hotkey_help/Activate()
diff --git a/code/modules/research/xenobiology/xenobiology.dm b/code/modules/research/xenobiology/xenobiology.dm
index e81b55db00fb..32c87a529e7b 100644
--- a/code/modules/research/xenobiology/xenobiology.dm
+++ b/code/modules/research/xenobiology/xenobiology.dm
@@ -11,7 +11,7 @@
throw_speed = 3
throw_range = 6
grind_results = list()
- var/Uses = 1 // uses before it goes inert
+ var/extract_uses = 1 // uses before it goes inert
var/qdel_timer = null // deletion timer, for delayed reactions
var/effectmod
var/list/activate_reagents = list() //Reagents required for activation
@@ -19,20 +19,20 @@
/obj/item/slime_extract/examine(mob/user)
. = ..()
- if(Uses > 1)
- . += "It has [Uses] uses remaining."
+ if(extract_uses > 1)
+ . += "It has [extract_uses] uses remaining."
/obj/item/slime_extract/attackby(obj/item/O, mob/user)
if(istype(O, /obj/item/slimepotion/enhancer))
- if(Uses >= 5 || recurring)
+ if(extract_uses >= 5 || recurring)
to_chat(user, "You cannot enhance this extract further!")
return ..()
if(O.type == /obj/item/slimepotion/enhancer) //Seriously, why is this defined here...?
to_chat(user, "You apply the enhancer to the slime extract. It may now be reused one more time.")
- Uses++
+ extract_uses++
if(O.type == /obj/item/slimepotion/enhancer/max)
to_chat(user, "You dump the maximizer on the slime extract. It can now be used a total of 5 times!")
- Uses = 5
+ extract_uses = 5
qdel(O)
..()
@@ -41,7 +41,7 @@
create_reagents(100, INJECTABLE | DRAWABLE)
/obj/item/slime_extract/on_grind()
- if(Uses)
+ if(extract_uses)
grind_results[/datum/reagent/toxin/slimejelly] = 20
//Effect when activated by a Luminescent. Separated into a minor and major effect. Returns cooldown in deciseconds.
diff --git a/code/modules/ruins/spaceruin_code/hilbertshotel.dm b/code/modules/ruins/spaceruin_code/hilbertshotel.dm
index 84ceb3ae01ca..cdd7444917f5 100644
--- a/code/modules/ruins/spaceruin_code/hilbertshotel.dm
+++ b/code/modules/ruins/spaceruin_code/hilbertshotel.dm
@@ -317,12 +317,15 @@ GLOBAL_VAR_INIT(hhmysteryRoomNumber, 1337)
desc = "Stop looking through the bluespace peephole."
button_icon_state = "cancel_peephole"
-/datum/action/peepholeCancel/Trigger()
+/datum/action/peepholeCancel/Trigger(trigger_flags)
. = ..()
+ if(!.)
+ return FALSE
to_chat(owner, "You move away from the peephole.")
owner.reset_perspective()
owner.clear_fullscreen("remote_view", 0)
qdel(src)
+ return TRUE
/area/hilbertshotel
name = "Hilbert's Hotel Room"
diff --git a/code/modules/shuttle/navigation_computer.dm b/code/modules/shuttle/navigation_computer.dm
index 6a290c3c844c..9335b24f0183 100644
--- a/code/modules/shuttle/navigation_computer.dm
+++ b/code/modules/shuttle/navigation_computer.dm
@@ -320,7 +320,7 @@
/datum/action/innate/shuttledocker_rotate
name = "Rotate"
- icon_icon = 'icons/mob/actions/actions_mecha.dmi'
+ button_icon = 'icons/mob/actions/actions_mecha.dmi'
button_icon_state = "mech_cycle_equip_off"
/datum/action/innate/shuttledocker_rotate/Activate()
@@ -332,7 +332,7 @@
/datum/action/innate/shuttledocker_place
name = "Place"
- icon_icon = 'icons/mob/actions/actions_mecha.dmi'
+ button_icon = 'icons/mob/actions/actions_mecha.dmi'
button_icon_state = "mech_zoom_off"
/datum/action/innate/shuttledocker_place/Activate()
diff --git a/code/modules/shuttle/shuttle_creation/shuttle_creator_actions.dm b/code/modules/shuttle/shuttle_creation/shuttle_creator_actions.dm
index 486e45d25019..a1049c19244c 100644
--- a/code/modules/shuttle/shuttle_creation/shuttle_creator_actions.dm
+++ b/code/modules/shuttle/shuttle_creation/shuttle_creator_actions.dm
@@ -1,6 +1,6 @@
//============ Actions ============
/datum/action/innate/shuttle_creator
- icon_icon = 'icons/mob/actions/actions_shuttle.dmi'
+ button_icon = 'icons/mob/actions/actions_shuttle.dmi'
var/mob/camera/aiEye/remote/shuttle_creation/remote_eye
var/obj/item/shuttle_creator/shuttle_creator
diff --git a/code/modules/spells/spell.dm b/code/modules/spells/spell.dm
index 28cb9ac36c8c..c90a471852a4 100644
--- a/code/modules/spells/spell.dm
+++ b/code/modules/spells/spell.dm
@@ -165,19 +165,19 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th
if("holdervar")
adjust_var(user, holder_var_type, holder_var_amount)
if(action)
- action.UpdateButtons()
+ action.build_all_button_icons()
return TRUE
-/obj/effect/proc_holder/spell/proc/charge_check(mob/user, silent = FALSE)
+/obj/effect/proc_holder/spell/proc/charge_check(mob/user, feedback = TRUE)
switch(charge_type)
if("recharge")
if(charge_counter < charge_max)
- if(!silent)
+ if(feedback)
to_chat(user, still_recharging_msg)
return FALSE
if("charges")
if(!charge_counter)
- if(!silent)
+ if(feedback)
to_chat(user, "[name] has no charges left.")
return FALSE
return TRUE
@@ -243,7 +243,7 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th
if(recharging && charge_type == "recharge" && (charge_counter < charge_max))
charge_counter += 2 //processes 5 times per second instead of 10.
if(charge_counter >= charge_max)
- action.UpdateButtons()
+ action.build_all_button_icons()
charge_counter = charge_max
recharging = FALSE
@@ -259,7 +259,7 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th
cast(targets,user=user)
after_cast(targets)
if(action)
- action.UpdateButtons()
+ action.build_all_button_icons()
/obj/effect/proc_holder/spell/proc/before_cast(list/targets)
if(overlay)
@@ -321,7 +321,7 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th
if("holdervar")
adjust_var(user, holder_var_type, -holder_var_amount)
if(action)
- action.UpdateButtons()
+ action.build_all_button_icons()
/obj/effect/proc_holder/spell/proc/adjust_var(mob/living/target = usr, type, amount) //handles the adjustment of the var when the spell is used. has some hardcoded types
if (!istype(target))
@@ -439,7 +439,7 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th
perform(targets,user=user)
/obj/effect/proc_holder/spell/proc/UpdateButton(atom/movable/screen/movable/action_button/button, status_only, force)
- action.UpdateButtons(status_only, force)
+ action.build_all_button_icons(status_only, force)
/obj/effect/proc_holder/spell/targeted/proc/los_check(mob/A,mob/B)
//Checks for obstacles from A to B
@@ -453,40 +453,40 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th
qdel(dummy)
return TRUE
-/obj/effect/proc_holder/spell/proc/can_cast(mob/user = usr, skipcharge = FALSE, silent = FALSE)
+/obj/effect/proc_holder/spell/proc/can_cast(mob/user = usr, skipcharge = FALSE, feedback = TRUE)
var/magic_flags = SEND_SIGNAL(user, COMSIG_MOB_SPELL_CAN_CAST, src)
if(magic_flags & SPELL_SKIP_ALL_REQS)
return TRUE
if(player_lock ? (!user.mind || !(src in user.mind.spell_list) && !(src in user.mob_spell_list)) : !(src in user.mob_spell_list))
- if(!silent)
+ if(feedback)
to_chat(user, "You shouldn't have this spell! Something's wrong.")
return FALSE
if(!centcom_cancast && !(magic_flags & SPELL_SKIP_CENTCOM)) //Certain spells are not allowed on the centcom zlevel
var/turf/T = get_turf(user)
if(is_centcom_level(T.z))
- if(!silent)
+ if(feedback)
to_chat(user, "You can't cast this spell here.")
return FALSE
- if(!skipcharge && !charge_check(user, silent))
+ if(!skipcharge && !charge_check(user, feedback))
return FALSE
if(user.stat && !stat_allowed && !(magic_flags & SPELL_SKIP_STAT))
- if(!silent)
+ if(feedback)
to_chat(user, "Not when you're incapacitated.")
return FALSE
if(!phase_allowed && istype(user.loc, /obj/effect/dummy))
- if(!silent)
+ if(feedback)
to_chat(user, "[name] cannot be cast unless you are completely manifested in the material plane.")
return FALSE
if(clothes_req && !(magic_flags & SPELL_SKIP_CLOTHES))
var/met_requirements = magic_flags & (clothes_req)
if(met_requirements != clothes_req)
- if(!silent)
+ if(feedback)
var/the_many_hats = met_requirements & (clothes_req & (SPELL_WIZARD_HAT|SPELL_CULT_HELMET))
var/the_many_suits = met_requirements & (clothes_req & (SPELL_WIZARD_ROBE|SPELL_CULT_ARMOR))
var/without_hat_robe = the_many_suits ? "a proper headwear" : the_many_hats ? "a proper suit" : "proper garments"
@@ -500,12 +500,12 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th
if(!(magic_flags & SPELL_SKIP_VOCAL) && (invocation_type in list("whisper", "shout")) && isliving(user))
var/mob/living/L = user
if(!L.can_speak_vocal())
- if(!silent)
+ if(feedback)
to_chat(L, "You can't get the words out!")
return FALSE
if(!(magic_flags & SPELL_SKIP_MOBTYPE) && ((mobs_whitelist && !mobs_whitelist[user.type]) || (mobs_blacklist && mobs_blacklist[user.type])))
- if(!silent)
+ if(feedback)
to_chat(user, "This spell can't be casted in this current form!")
return FALSE
return TRUE
diff --git a/code/modules/spells/spell_types/aimed.dm b/code/modules/spells/spell_types/aimed.dm
index 9e68862ff416..61d0ca043a93 100644
--- a/code/modules/spells/spell_types/aimed.dm
+++ b/code/modules/spells/spell_types/aimed.dm
@@ -44,7 +44,7 @@
if(!action)
return
action.button_icon_state = "[base_icon_state][active]"
- action.UpdateButtons()
+ action.build_all_button_icons()
/obj/effect/proc_holder/spell/aimed/InterceptClickOn(mob/living/caller, params, atom/target)
if(..())
diff --git a/code/modules/spells/spell_types/cluwnecurse.dm b/code/modules/spells/spell_types/cluwnecurse.dm
index 2da87b9e5055..86f2c3502723 100644
--- a/code/modules/spells/spell_types/cluwnecurse.dm
+++ b/code/modules/spells/spell_types/cluwnecurse.dm
@@ -33,4 +33,4 @@
/datum/action/spell_action/New(Target)
..()
var/obj/effect/proc_holder/spell/S = Target
- icon_icon = S.action_icon
+ button_icon = S.action_icon
diff --git a/code/modules/spells/spell_types/pointed/pointed.dm b/code/modules/spells/spell_types/pointed/pointed.dm
index f69cbfca7050..bc667b773ebe 100644
--- a/code/modules/spells/spell_types/pointed/pointed.dm
+++ b/code/modules/spells/spell_types/pointed/pointed.dm
@@ -64,7 +64,7 @@
action.button_icon_state = "[action_icon_state]1"
else
action.button_icon_state = "[action_icon_state]"
- action.UpdateButtons()
+ action.build_all_button_icons()
/obj/effect/proc_holder/spell/pointed/InterceptClickOn(mob/living/caller, params, atom/target)
if(..())
diff --git a/code/modules/spells/spell_types/taeclowndo.dm b/code/modules/spells/spell_types/taeclowndo.dm
index 701392775591..318920ca5530 100644
--- a/code/modules/spells/spell_types/taeclowndo.dm
+++ b/code/modules/spells/spell_types/taeclowndo.dm
@@ -55,7 +55,7 @@
else
action.button_icon_state = action_icon_state
- action.UpdateButtons()
+ action.build_all_button_icons()
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
/obj/effect/proc_holder/spell/targeted/touch/megahonk
diff --git a/code/modules/spells/spell_types/touch_attacks.dm b/code/modules/spells/spell_types/touch_attacks.dm
index 4f0ac2964f70..84091f26da40 100644
--- a/code/modules/spells/spell_types/touch_attacks.dm
+++ b/code/modules/spells/spell_types/touch_attacks.dm
@@ -18,7 +18,7 @@
//Start recharging.
attached_hand = null
recharging = TRUE
- action.UpdateButtons()
+ action.build_all_button_icons()
/obj/effect/proc_holder/spell/targeted/touch/cast(list/targets,mob/user = usr)
if(!QDELETED(attached_hand))
diff --git a/code/modules/spells/spell_types/voice_of_god.dm b/code/modules/spells/spell_types/voice_of_god.dm
index fa41b59c0d17..390c011cf7cb 100644
--- a/code/modules/spells/spell_types/voice_of_god.dm
+++ b/code/modules/spells/spell_types/voice_of_god.dm
@@ -14,10 +14,10 @@
var/list/spans = list("colossus","yell")
var/speech_sound = 'sound/magic/clockwork/invoke_general.ogg'
-/obj/effect/proc_holder/spell/voice_of_god/can_cast(mob/user = usr, skipcharge = FALSE, silent = TRUE)
+/obj/effect/proc_holder/spell/voice_of_god/can_cast(mob/user = usr, skipcharge = FALSE, feedback = TRUE)
if(!user.can_speak())
- if(!silent)
- to_chat(user, "You are unable to speak!")
+ if(feedback)
+ to_chat(user, span_warning("You are unable to speak!"))
return FALSE
return TRUE
diff --git a/code/modules/surgery/dental_implant.dm b/code/modules/surgery/dental_implant.dm
index b5461da25adc..1f02f8880661 100644
--- a/code/modules/surgery/dental_implant.dm
+++ b/code/modules/surgery/dental_implant.dm
@@ -18,9 +18,9 @@
user.transferItemToLoc(tool, target, TRUE)
- var/datum/action/item_action/hands_free/activate_pill/pill_action = new(tool)
+ var/datum/action/item_action/hands_free/activate_pill/pill_action = tool.add_item_action(/datum/action/item_action/hands_free/activate_pill)
pill_action.name = "Activate [tool.name]"
- pill_action.UpdateButtons()
+ pill_action.build_all_button_icons()
pill_action.target = tool
pill_action.Grant(target) //The pill never actually goes in an inventory slot, so the owner doesn't inherit actions from it
@@ -30,10 +30,13 @@
/datum/action/item_action/hands_free/activate_pill
name = "Activate Pill"
-/datum/action/item_action/hands_free/activate_pill/Trigger()
- if(!..())
- return FALSE
+/datum/action/item_action/hands_free/activate_pill/do_effect(trigger_flags)
+ . = ..()
+ if(!.)
+ return
var/obj/item/item_target = target
+ if(!istype(item_target))
+ return FALSE
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(item_target.reagents.total_volume)
diff --git a/code/modules/surgery/organs/heart.dm b/code/modules/surgery/organs/heart.dm
index d7ae2b73e462..bf865b27dc35 100644
--- a/code/modules/surgery/organs/heart.dm
+++ b/code/modules/surgery/organs/heart.dm
@@ -8,10 +8,10 @@
healing_factor = STANDARD_ORGAN_HEALING
decay_factor = 2 * STANDARD_ORGAN_DECAY
- low_threshold_passed = "Prickles of pain appear then die out from within your chest..."
- high_threshold_passed = "Something inside your chest hurts, and the pain isn't subsiding. You notice yourself breathing far faster than before."
- now_fixed = "Your heart begins to beat again."
- high_threshold_cleared = "The pain in your chest has died down, and your breathing becomes more relaxed."
+ low_threshold_passed = span_info("Prickles of pain appear then die out from within your chest...")
+ high_threshold_passed = span_warning("Something inside your chest hurts, and the pain isn't subsiding. You notice yourself breathing far faster than before.")
+ now_fixed = span_info("Your heart begins to beat again.")
+ high_threshold_cleared = span_info("The pain in your chest has died down, and your breathing becomes more relaxed.")
// Heart attack code is in code/modules/mob/living/carbon/human/life.dm
var/beating = 1
@@ -41,8 +41,8 @@
/obj/item/organ/heart/attack_self(mob/user)
..()
if(!beating)
- user.visible_message("[user] squeezes [src] to \
- make it beat again!","You squeeze [src] to make it beat again!")
+ user.visible_message(span_notice("[user] squeezes [src] to make it beat again!"),
+ span_notice("You squeeze [src] to make it beat again!"))
Restart()
addtimer(CALLBACK(src, PROC_REF(stop_if_unowned)), 80)
@@ -59,7 +59,7 @@
/obj/item/organ/heart/proc/HeartStrengthMessage()
if(beating)
return "a healthy"
- return "an unstable"
+ return span_danger("an unstable")
/obj/item/organ/heart/OnEatFrom(eater, feeder)
. = ..()
@@ -93,7 +93,7 @@
if(organ_flags & ORGAN_FAILING) //heart broke, stopped beating, death imminent
if(owner.stat == CONSCIOUS)
- owner.visible_message("[owner] clutches at [owner.p_their()] chest as if [owner.p_their()] heart is stopping!")
+ owner.visible_message(span_userdanger("[owner] clutches at [owner.p_their()] chest as if [owner.p_their()] heart is stopping!"))
owner.set_heartattack(TRUE)
failed = TRUE
@@ -162,34 +162,39 @@
return ..()
/datum/action/item_action/organ_action/cursed_heart
- check_flags = AB_CHECK_ALIVE //We wanna be able to do this always, else thisll just stupidly kill whoever has it
+ check_flags = AB_CHECK_CONSCIOUS //We wanna be able to do this always, else thisll just stupidly kill whoever has it
required_mobility_flags = NONE
name = "Pump your blood"
//You are now brea- pumping blood manually
-/datum/action/item_action/organ_action/cursed_heart/Trigger()
+/datum/action/item_action/organ_action/cursed_heart/do_effect(trigger_flags)
. = ..()
- if(. && istype(target, /obj/item/organ/heart/cursed))
- var/obj/item/organ/heart/cursed/cursed_heart = target
-
- if(world.time < (cursed_heart.last_pump + (cursed_heart.pump_delay-10))) //no spam
- to_chat(owner, "Too soon!")
- return
-
- cursed_heart.last_pump = world.time
- playsound(owner,'sound/effects/singlebeat.ogg',40,1)
- to_chat(owner, "Your heart beats.")
-
- var/mob/living/carbon/human/H = owner
- if(istype(H))
- if(H.dna && !(NOBLOOD in H.dna.species.species_traits))
- if(H.blood_volume < BLOOD_VOLUME_NORMAL) //We don't need to go too high, otherwise we get annoying messages.
- H.blood_volume = min(H.blood_volume + cursed_heart.blood_loss * 0.5, BLOOD_VOLUME_MAXIMUM)
- H.remove_client_colour(/datum/client_colour/cursed_heart_blood)
- cursed_heart.add_colour = TRUE
- H.adjustBruteLoss(-cursed_heart.heal_brute)
- H.adjustFireLoss(-cursed_heart.heal_burn)
- H.adjustOxyLoss(-cursed_heart.heal_oxy)
+ if(!.)
+ return
+ var/obj/item/organ/heart/cursed/cursed_heart = target
+ if(!istype(cursed_heart))
+ return FALSE
+
+ if(world.time < (cursed_heart.last_pump + (cursed_heart.pump_delay-10))) //no spam
+ to_chat(owner, span_userdanger("Too soon!"))
+ return FALSE
+
+ cursed_heart.last_pump = world.time
+ playsound(owner,'sound/effects/singlebeat.ogg',40,1)
+ to_chat(owner, span_notice("Your heart beats."))
+
+ var/mob/living/carbon/human/H = owner
+ if(!istype(H))
+ return FALSE
+ if(H.dna && !(NOBLOOD in H.dna.species.species_traits))
+ if(H.blood_volume < BLOOD_VOLUME_NORMAL) //We don't need to go too high, otherwise we get annoying messages.
+ H.blood_volume = min(H.blood_volume + cursed_heart.blood_loss * 0.5, BLOOD_VOLUME_MAXIMUM)
+ H.remove_client_colour(/datum/client_colour/cursed_heart_blood)
+ cursed_heart.add_colour = TRUE
+ H.adjustBruteLoss(-cursed_heart.heal_brute)
+ H.adjustFireLoss(-cursed_heart.heal_burn)
+ H.adjustOxyLoss(-cursed_heart.heal_oxy)
+ return TRUE
/datum/client_colour/cursed_heart_blood
@@ -242,8 +247,8 @@
if(prob(severity/emp_vulnerability)) //Chance of permanent effects
organ_flags |= ORGAN_SYNTHETIC_EMP //Starts organ faliure - gonna need replacing soon.
Stop()
- owner.visible_message("[owner] clutches at [owner.p_their()] chest as if [owner.p_their()] heart is stopping!", \
- "You feel a terrible pain in your chest, as if your heart has stopped!")
+ owner.visible_message(span_danger("[owner] clutches at [owner.p_their()] chest as if [owner.p_their()] heart is stopping!"), \
+ span_userdanger("You feel a terrible pain in your chest, as if your heart has stopped!"))
addtimer(CALLBACK(src, PROC_REF(Restart)), 10 SECONDS)
/obj/item/organ/heart/cybernetic/on_life(delta_time, times_fired)
@@ -274,7 +279,7 @@
. = ..()
if(. && owner.health < 5 && world.time > min_next_adrenaline)
min_next_adrenaline = world.time + rand(250, 600) //anywhere from 4.5 to 10 minutes
- to_chat(owner, "You feel yourself dying, but you refuse to give up!")
+ to_chat(owner, span_userdanger("You feel yourself dying, but you refuse to give up!"))
owner.heal_overall_damage(15, 15)
if(owner.reagents.get_reagent_amount(/datum/reagent/medicine/ephedrine) < 20)
owner.reagents.add_reagent(/datum/reagent/medicine/ephedrine, 10)
diff --git a/code/modules/surgery/organs/vocal_cords.dm b/code/modules/surgery/organs/vocal_cords.dm
index 7cb8ce9538a5..554c4c6792a7 100644
--- a/code/modules/surgery/organs/vocal_cords.dm
+++ b/code/modules/surgery/organs/vocal_cords.dm
@@ -43,16 +43,18 @@
icon_state = "adamantine_cords"
decay_factor = 0
-/datum/action/item_action/organ_action/use/adamantine_vocal_cords/Trigger()
- if(!IsAvailable())
+/datum/action/item_action/organ_action/use/adamantine_vocal_cords/do_effect(trigger_flags)
+ . = ..()
+ if(!.)
return
var/message = input(owner, "Resonate a message to all nearby golems.", "Resonate")
if(QDELETED(src) || QDELETED(owner) || !message)
- return
+ return FALSE
owner.say(".x[message]")
+ return TRUE
/obj/item/organ/vocal_cords/adamantine/handle_speech(message)
- var/msg = "[owner.real_name] resonates, \"[message]\""
+ var/msg = span_resonate("[span_name(owner.real_name)] resonates, \"[message]\"")
for(var/m in GLOB.player_list)
if(iscarbon(m))
var/mob/living/carbon/C = m
@@ -82,8 +84,10 @@
..()
cords = target
-/datum/action/item_action/organ_action/colossus/IsAvailable(silent = FALSE)
+/datum/action/item_action/organ_action/colossus/IsAvailable(feedback)
if(world.time < cords.next_command)
+ if(feedback)
+ to_chat(owner, span_notice("You must wait [DisplayTimeText(cords.next_command - world.time)] before Speaking again."))
return FALSE
if(!owner)
return FALSE
@@ -94,27 +98,26 @@
return FALSE
return TRUE
-/datum/action/item_action/organ_action/colossus/Trigger()
+/datum/action/item_action/organ_action/colossus/do_effect(trigger_flags)
. = ..()
- if(!IsAvailable())
- if(world.time < cords.next_command)
- to_chat(owner, "You must wait [DisplayTimeText(cords.next_command - world.time)] before Speaking again.")
+ if(!.)
return
var/command = input(owner, "Speak with the Voice of God", "Command")
if(QDELETED(src) || QDELETED(owner))
- return
+ return FALSE
if(!command)
- return
+ return FALSE
owner.say(".x[command]")
+ return TRUE
/obj/item/organ/vocal_cords/colossus/can_speak_with()
if(world.time < next_command)
- to_chat(owner, "You must wait [DisplayTimeText(next_command - world.time)] before Speaking again.")
+ to_chat(owner, span_notice("You must wait [DisplayTimeText(next_command - world.time)] before Speaking again."))
return FALSE
if(!owner)
return FALSE
if(!owner.can_speak())
- to_chat(owner, "You are unable to speak!")
+ to_chat(owner, span_warning("You are unable to speak!"))
return FALSE
return TRUE
@@ -639,17 +642,20 @@
..()
cords = target
-/datum/action/item_action/organ_action/velvet/IsAvailable(silent = FALSE)
+/datum/action/item_action/organ_action/velvet/IsAvailable(feedback = TRUE)
return TRUE
-/datum/action/item_action/organ_action/velvet/Trigger()
+/datum/action/item_action/organ_action/velvet/do_effect(trigger_flags)
. = ..()
+ if(!.)
+ return
var/command = input(owner, "Speak in a sultry tone", "Command")
if(QDELETED(src) || QDELETED(owner))
- return
+ return FALSE
if(!command)
- return
+ return FALSE
owner.say(".x[command]")
+ return TRUE
/obj/item/organ/vocal_cords/velvet/can_speak_with()
return TRUE
@@ -814,7 +820,7 @@
else
E.enthrallTally += power_multiplier*1.25 //thinking about it, I don't know how this can proc
if(E.lewd)
- addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), L, "[E.enthrallGender] is so nice to listen to."), 5)
+ addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), L, span_nicegreen("[E.enthrallGender] is so nice to listen to.")), 5)
E.cooldown += 1
//REWARD mixable works
@@ -826,16 +832,16 @@
if(L == user)
continue
if (E.lewd)
- addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), L, "[E.enthrallGender] has praised me!!"), 5)
+ addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), L, span_love("[E.enthrallGender] has praised me!!")), 5)
if(HAS_TRAIT(L, TRAIT_MASO))
E.enthrallTally -= power_multiplier
E.resistanceTally += power_multiplier
E.cooldown += 1
else
- addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), L, "I've been praised for doing a good job!"), 5)
+ addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), L, span_nicegreen("I've been praised for doing a good job!")), 5)
E.resistanceTally -= power_multiplier
E.enthrallTally += power_multiplier
- var/descmessage = "[(E.lewd?"I feel so happy! I'm a good pet who [E.enthrallGender] loves!":"I did a good job!")]"
+ var/descmessage = span_love("[(E.lewd?"I feel so happy! I'm a good pet who [E.enthrallGender] loves!":"I did a good job!")]")
SEND_SIGNAL(L, COMSIG_ADD_MOOD_EVENT, "enthrallpraise", /datum/mood_event/enthrallpraise, descmessage)
E.cooldown += 1
@@ -855,11 +861,11 @@
descmessage += "And yet, it feels so good..!" //I don't really understand masco, is this the right sort of thing they like?
E.enthrallTally += power_multiplier
E.resistanceTally -= power_multiplier
- addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), L, "I've let [E.enthrallGender] down...!"), 5)
+ addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), L, span_love("I've let [E.enthrallGender] down...!")), 5)
else
- addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), L, "I've let [E.enthrallGender] down..."), 5)
+ addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), L, span_warning("I've let [E.enthrallGender] down...")), 5)
else
- addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), L, "I've failed [E.master]..."), 5)
+ addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), L, span_warning("I've failed [E.master]...")), 5)
E.resistanceTally += power_multiplier
E.enthrallTally += power_multiplier
E.cooldown += 1
@@ -896,7 +902,7 @@
addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), L, "The snapping of your [E.enthrallGender]'s fingers brings you back to your enthralled state, obedient and ready to serve."), 5)
else
addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), L, "The snapping of [E.master]'s fingers brings you back to being under their influence."), 5)
- to_chat(user, "You wake up [L]!")
+ to_chat(user, span_notice("You wake up [L]!"))
//tier 1
@@ -1028,8 +1034,8 @@
ADD_TRAIT(C, TRAIT_MUTE, "enthrall")
else
C.silent += ((10 * power_multiplier) * E.phase)
- addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), C, "You are unable to speak!"), 5)
- to_chat(user, "You silence [C].")
+ addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), C, span_notice("You are unable to speak!")), 5)
+ to_chat(user, span_notice("You silence [C]."))
E.cooldown += 3
//SPEAK
@@ -1039,7 +1045,7 @@
REMOVE_TRAIT(C, TRAIT_MUTE, "enthrall")
C.silent = 0
E.cooldown += 3
- to_chat(user, "You [(E.lewd?"allow [C] to speak again":"encourage [C] to speak again")].")
+ to_chat(user, span_notice("You [(E.lewd?"allow [C] to speak again":"encourage [C] to speak again")]."))
//Antiresist
@@ -1051,7 +1057,7 @@
addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), L, "Your mind clouds over, as you find yourself unable to resist!"), 5)
E.statusStrength = (1 * power_multiplier * E.phase)
E.cooldown += 15//Too short? yes, made 15
- to_chat(user, "You frustrate [L]'s attempts at resisting.")
+ to_chat(user, span_notice("You frustrate [L]'s attempts at resisting."))
//RESIST
else if((findtext(message, resist_words)))
@@ -1061,23 +1067,23 @@
E.deltaResist += (power_multiplier)
E.owner_resist()
E.cooldown += 2
- addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), C, "You are spurred into resisting from [user]'s words!'"), 5)
- to_chat(user, "You spark resistance in [C].")
+ addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), C, span_notice("You are spurred into resisting from [user]'s words!'")), 5)
+ to_chat(user, span_notice("You spark resistance in [C]."))
//FORGET (A way to cancel the process)
else if((findtext(message, forget_words)))
for(var/mob/living/carbon/C in listeners)
var/datum/status_effect/chem/enthrall/E = C.has_status_effect(/datum/status_effect/chem/enthrall)
if(E.phase == 4)
- addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), C, "You're unable to forget about [(E.lewd?"the dominating presence of [E.enthrallGender]":"[E.master]")]!"), 5)
+ addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), C, span_warning("You're unable to forget about [(E.lewd?"the dominating presence of [E.enthrallGender]":"[E.master]")]!")), 5)
continue
- addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), C, "You wake up, forgetting everything that just happened. You must've dozed off..? How embarassing!"), 5)
+ addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), C, span_warning("You wake up, forgetting everything that just happened. You must've dozed off..? How embarassing!")), 5)
C.Sleeping(50)
switch(E.phase)
if(1 to 2)
E.phase = -1
to_chat(C, "You have no recollection of being enthralled by [E.master]!")
- to_chat(user, "You revert [C] back to their state before enthrallment.")
+ to_chat(user, span_notice("You revert [C] back to their state before enthrallment."))
if(3)
E.phase = 0
E.cooldown = 0
@@ -1085,7 +1091,7 @@
addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), C, "You revert to yourself before being enthralled by your [E.enthrallGender], with no memory of what happened."), 5)
else
addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), C, "You revert to who you were before, with no memory of what happened with [E.master]."), 5)
- to_chat(user, "You put [C] into a sleeper state, ready to turn them back at the snap of your fingers.")
+ to_chat(user, span_notice("You put [C] into a sleeper state, ready to turn them back at the snap of your fingers."))
//ATTRACT
else if((findtext(message, attract_words)))
@@ -1094,8 +1100,8 @@
var/datum/status_effect/chem/enthrall/E = L.has_status_effect(/datum/status_effect/chem/enthrall)
L.throw_at(get_step_towards(user,L), 3 * power_multiplier, 1 * power_multiplier)
E.cooldown += 3
- addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), L, "You are drawn towards [user]!"), 5)
- to_chat(user, "You draw [L] towards you!")
+ addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), L, span_notice("You are drawn towards [user]!")), 5)
+ to_chat(user, span_notice("You draw [L] towards you!"))
//awoo
else if((findtext(message, awoo_words)))
@@ -1142,8 +1148,8 @@
if(L.m_intent != MOVE_INTENT_WALK)
L.toggle_move_intent()
E.cooldown += 1
- addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), L, "You slow down to a walk."), 5)
- to_chat(user, "You encourage [L] to slow down.")
+ addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), L, span_notice("You slow down to a walk.")), 5)
+ to_chat(user, span_notice("You encourage [L] to slow down."))
//RUN
else if((findtext(message, run_words)))
@@ -1155,8 +1161,8 @@
if(L.m_intent != MOVE_INTENT_RUN)
L.toggle_move_intent()
E.cooldown += 1
- addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), L, "You speed up into a jog!"), 5)
- to_chat(user, "You encourage [L] to pick up the pace!")
+ addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), L, span_notice("You speed up into a jog!")), 5)
+ to_chat(user, span_notice("You encourage [L] to pick up the pace!"))
//LIE DOWN
else if(findtext(message, liedown_words))
@@ -1168,7 +1174,7 @@
L.lay_down()
E.cooldown += 10
addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), L, "[(E.lewd?"You eagerly lie down!":"You suddenly lie down!")]"), 5)
- to_chat(user, "You encourage [L] to lie down.")
+ to_chat(user, span_notice("You encourage [L] to lie down."))
//KNOCKDOWN
else if(findtext(message, knockdown_words))
@@ -1179,8 +1185,8 @@
if(2 to INFINITY)
L.DefaultCombatKnockdown(30 * power_multiplier * E.phase)
E.cooldown += 8
- addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), L, "You suddenly drop to the ground!"), 5)
- to_chat(user, "You encourage [L] to drop down to the ground.")
+ addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), L, span_notice("You suddenly drop to the ground!")), 5)
+ to_chat(user, span_notice("You encourage [L] to drop down to the ground."))
//tier3
@@ -1193,12 +1199,12 @@
var/speaktrigger = ""
C.emote("me", EMOTE_VISIBLE, "whispers something quietly.")
if (get_dist(user, C) > 1)//Requires user to be next to their pet.
- to_chat(user, "You need to be next to your pet to hear them!")
+ to_chat(user, span_warning("You need to be next to your pet to hear them!"))
continue
for (var/trigger in E.customTriggers)
speaktrigger += "[trigger], "
to_chat(user, "[C] whispers, \"[speaktrigger] are my triggers.\"")//So they don't trigger themselves!
- addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), C, "You whisper your triggers to [(E.lewd?"Your [E.enthrallGender]":"[E.master]")]."), 5)
+ addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), C, span_notice("You whisper your triggers to [(E.lewd?"Your [E.enthrallGender]":"[E.master]")].")), 5)
//CUSTOM TRIGGERS
@@ -1208,10 +1214,10 @@
var/datum/status_effect/chem/enthrall/E = H.has_status_effect(/datum/status_effect/chem/enthrall)
if(E.phase == 3)
if (get_dist(user, H) > 1)//Requires user to be next to their pet.
- to_chat(user, "You need to be next to your pet to give them a new trigger!")
+ to_chat(user, span_warning("You need to be next to your pet to give them a new trigger!"))
continue
if(!E.lewd)
- to_chat(user, "[H] seems incapable of being implanted with triggers.")
+ to_chat(user, span_warning("[H] seems incapable of being implanted with triggers."))
continue
else
user.emote("me", EMOTE_VISIBLE, "puts their hands upon [H.name]'s head and looks deep into their eyes, whispering something to them.")
@@ -1233,12 +1239,12 @@
E.customTriggers[trigger] = trigger2
log_reagent("FERMICHEM: [H] has been implanted by [user] with [trigger], triggering [trigger2].")
E.mental_capacity -= 5
- addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), H, "[(E.lewd?"your [E.enthrallGender]":"[E.master]")] whispers you a new trigger."), 5)
- to_chat(user, "You sucessfully set the trigger word [trigger] in [H]")
+ addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), H, span_notice("[(E.lewd?"your [E.enthrallGender]":"[E.master]")] whispers you a new trigger.")), 5)
+ to_chat(user, span_notice("You sucessfully set the trigger word [trigger] in [H]"))
else
- to_chat(user, "Your pet looks at you confused, it seems they don't understand that effect!")
+ to_chat(user, span_warning("Your pet looks at you confused, it seems they don't understand that effect!"))
else
- to_chat(user, "Your pet looks at you with a vacant blase expression, you don't think you can program anything else into them")
+ to_chat(user, span_warning("Your pet looks at you with a vacant blase expression, you don't think you can program anything else into them"))
user.SetStun(0)
H.SetStun(0)
@@ -1249,10 +1255,10 @@
var/datum/status_effect/chem/enthrall/E = H.has_status_effect(/datum/status_effect/chem/enthrall)
if(E.phase == 3)
if (get_dist(user, H) > 1)//Requires user to be next to their pet.
- to_chat(user, "You need to be next to your pet to give them a new echophrase!")
+ to_chat(user, span_warning("You need to be next to your pet to give them a new echophrase!"))
continue
if(!E.lewd)
- to_chat(user, "[H] seems incapable of being implanted with an echoing phrase.")
+ to_chat(user, span_warning("[H] seems incapable of being implanted with an echoing phrase."))
continue
else
user.emote("me", EMOTE_VISIBLE, "puts their hands upon [H.name]'s head and looks deep into their eyes, whispering something to them.")
@@ -1266,7 +1272,7 @@
E.customSpan = trigger2
user.SetStun(0)
H.SetStun(0)
- to_chat(user, "You sucessfully set an echoing phrase in [H]")
+ to_chat(user, span_notice("You sucessfully set an echoing phrase in [H]"))
//CUSTOM OBJECTIVE
else if((findtext(message, objective_words)))
@@ -1275,7 +1281,7 @@
var/datum/status_effect/chem/enthrall/E = H.has_status_effect(/datum/status_effect/chem/enthrall)
if(E.phase == 3)
if (get_dist(user, H) > 1)//Requires user to be next to their pet.
- to_chat(user, "You need to be next to your pet to give them a new objective!")
+ to_chat(user, span_warning("You need to be next to your pet to give them a new objective!"))
continue
else
user.emote("me", EMOTE_VISIBLE, "puts their hands upon [H.name]'s head and looks deep into their eyes, whispering something to them.'")
@@ -1284,7 +1290,7 @@
if (E.mental_capacity >= 200)
var/datum/objective/brainwashing/objective = stripped_input(user, "Add an objective to give your pet.", MAX_MESSAGE_LEN)
if(!LAZYLEN(objective))
- to_chat(user, "You can't give your pet an objective to do nothing!")
+ to_chat(user, span_warning("You can't give your pet an objective to do nothing!"))
continue
//Pets don't understand harm
objective = replacetext(lowertext(objective), "kill", "hug")
@@ -1295,12 +1301,12 @@
objective = replacetext(lowertext(objective), "suicide", "self-love")
message_admins("[H] has been implanted by [user] with the objective [objective].")
log_reagent("FERMICHEM: [H] has been implanted by [user] with the objective [objective] via MKUltra.")
- addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), H, "[(E.lewd?"Your [E.enthrallGender]":"[E.master]")] whispers you a new objective."), 5)
+ addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), H, span_notice("[(E.lewd?"Your [E.enthrallGender]":"[E.master]")] whispers you a new objective.")), 5)
brainwash(H, objective)
E.mental_capacity -= 200
- to_chat(user, "You sucessfully give an objective to [H]")
+ to_chat(user, span_notice("You sucessfully give an objective to [H]"))
else
- to_chat(user, "Your pet looks at you with a vacant blasé expression, you don't think you can program anything else into them")
+ to_chat(user, span_warning("Your pet looks at you with a vacant blasé expression, you don't think you can program anything else into them"))
user.SetStun(0)
H.SetStun(0)
@@ -1312,7 +1318,7 @@
if(E.phase >= 3 && E.lewd)
var/instill = stripped_input(user, "Instill an emotion in [H].", MAX_MESSAGE_LEN)
to_chat(H, "[instill]")
- to_chat(user, "You sucessfully instill a feeling in [H]")
+ to_chat(user, span_notice("You sucessfully instill a feeling in [H]"))
log_reagent("FERMICHEM: [H] has been instilled by [user] with [instill] via MKUltra.")
E.cooldown += 1
@@ -1324,8 +1330,8 @@
if(E.phase > 1)
if(user.ckey == E.enthrallID && user.real_name == E.master.real_name)
E.master = user
- to_chat(H, "[(E.lewd?"You hear the words of your [E.enthrallGender] again!! They're back!!":"You recognise the voice of [E.master].")]")
- to_chat(user, "[H] looks at you with sparkling eyes, recognising you!")
+ to_chat(H, span_nicegreen("[(E.lewd?"You hear the words of your [E.enthrallGender] again!! They're back!!":"You recognise the voice of [E.master].")]"))
+ to_chat(user, span_notice("[H] looks at you with sparkling eyes, recognising you!"))
//I dunno how to do state objectives without them revealing they're an antag
@@ -1339,9 +1345,9 @@
E.status = "heal"
E.statusStrength = (5 * power_multiplier)
E.cooldown += 5
- addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), L, "You begin to lick your wounds."), 5)
+ addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), L, span_notice("You begin to lick your wounds.")), 5)
L.Stun(15 * power_multiplier)
- to_chat(user, "[L] begins to lick their wounds.")
+ to_chat(user, span_notice("[L] begins to lick their wounds."))
//STUN
else if(findtext(message, stun_words))
@@ -1352,8 +1358,8 @@
if(3 to INFINITY)
L.Stun(40 * power_multiplier)
E.cooldown += 8
- addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), L, "Your muscles freeze up!"), 5)
- to_chat(user, "You cause [L] to freeze up!")
+ addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), L, span_notice("Your muscles freeze up!")), 5)
+ to_chat(user, span_notice("You cause [L] to freeze up!"))
//HALLUCINATE
else if(findtext(message, hallucinate_words))
@@ -1363,7 +1369,7 @@
switch(E.phase)
if(3 to INFINITY)
new /datum/hallucination/delusion(C, TRUE, null,150 * power_multiplier,0)
- to_chat(user, "You send [C] on a trip.")
+ to_chat(user, span_notice("You send [C] on a trip."))
//HOT
else if(findtext(message, hot_words))
@@ -1373,8 +1379,8 @@
switch(E.phase)
if(3 to INFINITY)
L.adjust_bodytemperature(50 * power_multiplier)//This seems nuts, reduced it, but then it didn't do anything, so I reverted it.
- addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), L, "You feel your metabolism speed up!"), 5)
- to_chat(user, "You speed [L]'s metabolism up!")
+ addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), L, span_notice("You feel your metabolism speed up!")), 5)
+ to_chat(user, span_notice("You speed [L]'s metabolism up!"))
//COLD
else if(findtext(message, cold_words))
@@ -1384,8 +1390,8 @@
switch(E.phase)
if(3 to INFINITY)
L.adjust_bodytemperature(-50 * power_multiplier)
- addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), L, "You feel your metabolism slow down!"), 5)
- to_chat(user, "You slow [L]'s metabolism down!")
+ addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), L, span_notice("You feel your metabolism slow down!")), 5)
+ to_chat(user, span_notice("You slow [L]'s metabolism down!"))
//GET UP
else if(findtext(message, getup_words))
@@ -1398,8 +1404,8 @@
L.SetAllImmobility(0)
L.SetUnconscious(0) //i said get up i don't care if you're being tased
E.cooldown += 10 //This could be really strong
- addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), L, "You jump to your feet from sheer willpower!"), 5)
- to_chat(user, "You spur [L] to their feet!")
+ addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), L, span_notice("You jump to your feet from sheer willpower!")), 5)
+ to_chat(user, span_notice("You spur [L] to their feet!"))
//PACIFY
else if(findtext(message, pacify_words))
@@ -1410,8 +1416,8 @@
if(3)//Tier 3 only
E.status = "pacify"
E.cooldown += 10
- addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), L, "You feel like never hurting anyone ever again."), 5)
- to_chat(user, "You remove any intent to harm from [L]'s mind.")
+ addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), L, span_notice("You feel like never hurting anyone ever again.")), 5)
+ to_chat(user, span_notice("You remove any intent to harm from [L]'s mind."))
//CHARGE
else if(findtext(message, charge_words))
@@ -1423,7 +1429,7 @@
E.statusStrength = 2* power_multiplier
E.status = "charge"
E.cooldown += 10
- to_chat(user, "You rally [L], leading them into a charge!")
+ to_chat(user, span_notice("You rally [L], leading them into a charge!"))
if(message_admins || debug)//Do you want this in?
message_admins("[ADMIN_LOOKUPFLW(user)] has said '[log_message]' with a Velvet Voice, affecting [english_list(listeners)], with a power multiplier of [power_multiplier].")
diff --git a/code/modules/vehicles/mecha/combat/durand.dm b/code/modules/vehicles/mecha/combat/durand.dm
index d351300764d9..01b2f75e0a0a 100644
--- a/code/modules/vehicles/mecha/combat/durand.dm
+++ b/code/modules/vehicles/mecha/combat/durand.dm
@@ -194,7 +194,7 @@ own integrity back to max. Shield is automatically dropped if we run out of powe
for(var/occupant in chassis.occupants)
var/datum/action/button = chassis.occupant_actions[occupant][/datum/action/vehicle/sealed/mecha/mech_defense_mode]
button.button_icon_state = "mech_defense_mode_[chassis.defense_mode ? "on" : "off"]"
- button.UpdateButtons()
+ button.build_all_button_icons()
set_light(light_range, light_power, light_color)
diff --git a/code/modules/vehicles/mecha/mecha_actions.dm b/code/modules/vehicles/mecha/mecha_actions.dm
index 976ffea40a65..c7ead102907e 100644
--- a/code/modules/vehicles/mecha/mecha_actions.dm
+++ b/code/modules/vehicles/mecha/mecha_actions.dm
@@ -8,7 +8,7 @@
/datum/action/vehicle/sealed/mecha
- icon_icon = 'icons/mob/actions/actions_mecha.dmi'
+ button_icon = 'icons/mob/actions/actions_mecha.dmi'
var/obj/vehicle/sealed/mecha/chassis
/datum/action/vehicle/sealed/mecha/Destroy()
@@ -19,33 +19,44 @@
name = "Eject From Mech"
button_icon_state = "mech_eject"
-/datum/action/vehicle/sealed/mecha/mech_eject/Trigger()
+/datum/action/vehicle/sealed/mecha/mech_eject/Trigger(trigger_flags)
+ . = ..()
+ if(!.)
+ return FALSE
if(!owner)
- return
+ return FALSE
if(!chassis || !(owner in chassis.occupants))
- return
+ return FALSE
chassis.container_resist(owner)
+ return TRUE
/datum/action/vehicle/sealed/mecha/mech_toggle_internals
name = "Toggle Internal Airtank Usage"
button_icon_state = "mech_internals_off"
-/datum/action/vehicle/sealed/mecha/mech_toggle_internals/Trigger()
+/datum/action/vehicle/sealed/mecha/mech_toggle_internals/Trigger(trigger_flags)
+ . = ..()
+ if(!.)
+ return FALSE
if(!owner || !chassis || !(owner in chassis.occupants))
- return
+ return FALSE
chassis.use_internal_tank = !chassis.use_internal_tank
button_icon_state = "mech_internals_[chassis.use_internal_tank ? "on" : "off"]"
to_chat(chassis.occupants, "[icon2html(chassis, owner)]Now taking air from [chassis.use_internal_tank?"internal airtank":"environment"].")
chassis.log_message("Now taking air from [chassis.use_internal_tank?"internal airtank":"environment"].", LOG_MECHA)
- UpdateButtons()
+ build_all_button_icons()
+ return TRUE
/datum/action/vehicle/sealed/mecha/mech_cycle_equip
name = "Cycle Equipment"
button_icon_state = "mech_cycle_equip_off"
-/datum/action/vehicle/sealed/mecha/mech_cycle_equip/Trigger()
+/datum/action/vehicle/sealed/mecha/mech_cycle_equip/Trigger(trigger_flags)
+ . = ..()
+ if(!.)
+ return FALSE
if(!owner || !chassis || !(owner in chassis.occupants))
- return
+ return FALSE
var/list/available_equipment = list()
for(var/e in chassis.equipment)
@@ -55,14 +66,14 @@
if(available_equipment.len == 0)
to_chat(owner, "[icon2html(chassis, owner)]No equipment available!")
- return
+ return FALSE
if(!chassis.selected)
chassis.selected = available_equipment[1]
to_chat(owner, "[icon2html(chassis, owner)]You select [chassis.selected].")
send_byjax(chassis.occupants,"exosuit.browser","eq_list",chassis.get_equipment_list())
button_icon_state = "mech_cycle_equip_on"
- UpdateButtons()
- return
+ build_all_button_icons()
+ return TRUE
var/number = 0
for(var/equipment in available_equipment)
number++
@@ -77,20 +88,23 @@
to_chat(owner, "[icon2html(chassis, owner)]You switch to [chassis.selected].")
button_icon_state = "mech_cycle_equip_on"
send_byjax(chassis.occupants,"exosuit.browser","eq_list",chassis.get_equipment_list())
- UpdateButtons()
- return
+ build_all_button_icons()
+ return TRUE
/datum/action/vehicle/sealed/mecha/mech_toggle_lights
name = "Toggle Lights"
button_icon_state = "mech_lights_off"
-/datum/action/vehicle/sealed/mecha/mech_toggle_lights/Trigger()
+/datum/action/vehicle/sealed/mecha/mech_toggle_lights/Trigger(trigger_flags)
+ . = ..()
+ if(!.)
+ return FALSE
if(!owner || !chassis || !(owner in chassis.occupants))
- return
+ return FALSE
if(!(chassis.mecha_flags & HAS_LIGHTS))
to_chat(owner, "This mechs lights are destroyed!")
- return
+ return FALSE
chassis.mecha_flags ^= LIGHTS_ON
if(chassis.mecha_flags & LIGHTS_ON)
button_icon_state = "mech_lights_on"
@@ -100,28 +114,36 @@
chassis.set_light(0)
to_chat(owner, "[icon2html(chassis, owner)]Toggled lights [(chassis.mecha_flags & LIGHTS_ON)?"on":"off"].")
chassis.log_message("Toggled lights [(chassis.mecha_flags & LIGHTS_ON)?"on":"off"].", LOG_MECHA)
- UpdateButtons()
+ build_all_button_icons()
+ return TRUE
/datum/action/vehicle/sealed/mecha/mech_view_stats
name = "View Stats"
button_icon_state = "mech_view_stats"
-/datum/action/vehicle/sealed/mecha/mech_view_stats/Trigger()
+/datum/action/vehicle/sealed/mecha/mech_view_stats/Trigger(trigger_flags)
+ . = ..()
+ if(!.)
+ return FALSE
if(!owner || !chassis || !(owner in chassis.occupants))
- return
+ return FALSE
var/datum/browser/popup = new(owner , "exosuit")
popup.set_content(chassis.get_stats_html(owner))
popup.open()
-
+ return TRUE
/datum/action/vehicle/sealed/mecha/strafe
name = "Toggle Strafing. Disabled when Alt is held."
button_icon_state = "strafe"
-/datum/action/vehicle/sealed/mecha/strafe/Trigger()
+/datum/action/vehicle/sealed/mecha/strafe/Trigger(trigger_flags)
+ . = ..()
+ if(!.)
+ return FALSE
if(!owner || !chassis || !(owner in chassis.occupants))
- return
+ return FALSE
chassis.toggle_strafe()
+ return TRUE
/obj/vehicle/sealed/mecha/AltClick(mob/living/user)
if(!(user in occupants) || !user.canUseTopic(src))
@@ -140,7 +162,7 @@
for(var/occupant in occupants)
var/datum/action/action = LAZYACCESSASSOC(occupant_actions, occupant, /datum/action/vehicle/sealed/mecha/strafe)
- action?.UpdateButtons()
+ action?.build_all_button_icons()
//////////////////////////////////////// Specific Ability Actions ///////////////////////////////////////////////
//Need to be granted by the mech type, Not default abilities.
@@ -149,16 +171,23 @@
name = "Toggle an energy shield that blocks all attacks from the faced direction at a heavy power cost."
button_icon_state = "mech_defense_mode_off"
-/datum/action/vehicle/sealed/mecha/mech_defense_mode/Trigger(forced_state = FALSE)
+/datum/action/vehicle/sealed/mecha/mech_defense_mode/Trigger(trigger_flags, forced_state = FALSE)
+ . = ..()
+ if(!.)
+ return FALSE
SEND_SIGNAL(chassis, COMSIG_MECHA_ACTION_TRIGGER, owner, args) //Signal sent to the mech, to be handed to the shield. See durand.dm for more details
+ return TRUE
/datum/action/vehicle/sealed/mecha/mech_overload_mode
name = "Toggle leg actuators overload"
button_icon_state = "mech_overload_off"
-/datum/action/vehicle/sealed/mecha/mech_overload_mode/Trigger(forced_state = null)
+/datum/action/vehicle/sealed/mecha/mech_overload_mode/Trigger(trigger_flags, forced_state = null)
+ . = ..()
+ if(!.)
+ return FALSE
if(!owner || !chassis || !(owner in chassis.occupants))
- return
+ return FALSE
if(!isnull(forced_state))
chassis.leg_overload_mode = forced_state
else
@@ -176,47 +205,60 @@
chassis.movedelay = initial(chassis.movedelay)
chassis.step_energy_drain = chassis.normal_step_energy_drain
to_chat(owner, "[icon2html(chassis, owner)]You disable leg actuators overload.")
- UpdateButtons()
+ build_all_button_icons()
+ return TRUE
/datum/action/vehicle/sealed/mecha/mech_smoke
name = "Smoke"
button_icon_state = "mech_smoke"
-/datum/action/vehicle/sealed/mecha/mech_smoke/Trigger()
+/datum/action/vehicle/sealed/mecha/mech_smoke/Trigger(trigger_flags)
+ . = ..()
+ if(!.)
+ return FALSE
if(!owner || !chassis || !(owner in chassis.occupants))
- return
+ return FALSE
if(!TIMER_COOLDOWN_CHECK(src, COOLDOWN_MECHA_SMOKE) && chassis.smoke_charges>0)
chassis.smoke_system.start()
chassis.smoke_charges--
TIMER_COOLDOWN_START(src, COOLDOWN_MECHA_SMOKE, chassis.smoke_cooldown)
+ return TRUE
/datum/action/vehicle/sealed/mecha/mech_zoom
name = "Zoom"
button_icon_state = "mech_zoom_off"
-/datum/action/vehicle/sealed/mecha/mech_zoom/Trigger()
+/datum/action/vehicle/sealed/mecha/mech_zoom/Trigger(trigger_flags)
+ . = ..()
+ if(!.)
+ return FALSE
if(!owner || !chassis || !(owner in chassis.occupants))
- return
- if(owner.client)
- chassis.zoom_mode = !chassis.zoom_mode
- button_icon_state = "mech_zoom_[chassis.zoom_mode ? "on" : "off"]"
- chassis.log_message("Toggled zoom mode.", LOG_MECHA)
- to_chat(owner, "[icon2html(chassis, owner)]Zoom mode [chassis.zoom_mode?"en":"dis"]abled.")
- if(chassis.zoom_mode)
- owner.client.view_size.setTo(4.5)
- SEND_SOUND(owner, sound('sound/mecha/imag_enh.ogg',volume=50))
- else
- owner.client.view_size.resetToDefault() //Let's not let this stack shall we?
- UpdateButtons()
+ return FALSE
+ if(!owner.client)
+ return FALSE
+ chassis.zoom_mode = !chassis.zoom_mode
+ button_icon_state = "mech_zoom_[chassis.zoom_mode ? "on" : "off"]"
+ chassis.log_message("Toggled zoom mode.", LOG_MECHA)
+ to_chat(owner, "[icon2html(chassis, owner)]Zoom mode [chassis.zoom_mode?"en":"dis"]abled.")
+ if(chassis.zoom_mode)
+ owner.client.view_size.setTo(4.5)
+ SEND_SOUND(owner, sound('sound/mecha/imag_enh.ogg',volume=50))
+ else
+ owner.client.view_size.resetToDefault() //Let's not let this stack shall we?
+ build_all_button_icons()
+ return TRUE
/datum/action/vehicle/sealed/mecha/mech_switch_damtype
name = "Reconfigure arm microtool arrays"
button_icon_state = "mech_damtype_brute"
-/datum/action/vehicle/sealed/mecha/mech_switch_damtype/Trigger()
+/datum/action/vehicle/sealed/mecha/mech_switch_damtype/Trigger(trigger_flags)
+ . = ..()
+ if(!.)
+ return FALSE
if(!owner || !chassis || !(owner in chassis.occupants))
- return
+ return FALSE
var/new_damtype
switch(chassis.damtype)
if("tox")
@@ -231,26 +273,30 @@
chassis.damtype = new_damtype
button_icon_state = "mech_damtype_[new_damtype]"
playsound(chassis, 'sound/mecha/mechmove01.ogg', 50, TRUE)
- UpdateButtons()
+ build_all_button_icons()
+ return TRUE
///swap seats, for two person mecha
/datum/action/vehicle/sealed/mecha/swap_seat
name = "Switch Seats"
button_icon_state = "mech_seat_swap"
-/datum/action/vehicle/sealed/mecha/swap_seat/Trigger()
+/datum/action/vehicle/sealed/mecha/swap_seat/Trigger(trigger_flags)
+ . = ..()
+ if(!.)
+ return FALSE
if(!owner || !chassis || !(owner in chassis.occupants))
- return
+ return FALSE
if(chassis.occupants.len == chassis.max_occupants)
to_chat(owner, "The other seat is occupied!")
- return
+ return FALSE
var/list/drivers = chassis.return_drivers()
to_chat(owner, "Switching seats...")
chassis.is_currently_ejecting = TRUE
if(!do_after(owner, chassis.has_gravity() ? chassis.exit_delay : 0 , target = chassis))
chassis.is_currently_ejecting = FALSE
- return
+ return FALSE
chassis.is_currently_ejecting = FALSE
if(owner in drivers)
to_chat(owner, "You shift to the gunner seat!")
@@ -261,15 +307,20 @@
chassis.remove_control_flags(owner, VEHICLE_CONTROL_MELEE|VEHICLE_CONTROL_EQUIPMENT)
chassis.add_control_flags(owner, VEHICLE_CONTROL_DRIVE|VEHICLE_CONTROL_SETTINGS)
chassis.update_icon_state()
+ return TRUE
/datum/action/vehicle/sealed/mecha/mech_toggle_phasing
name = "Toggle Phasing"
button_icon_state = "mech_phasing_off"
-/datum/action/vehicle/sealed/mecha/mech_toggle_phasing/Trigger()
+/datum/action/vehicle/sealed/mecha/mech_toggle_phasing/Trigger(trigger_flags)
+ . = ..()
+ if(!.)
+ return FALSE
if(!owner || !chassis || !(owner in chassis.occupants))
- return
+ return FALSE
chassis.phasing = !chassis.phasing
button_icon_state = "mech_phasing_[chassis.phasing ? "on" : "off"]"
to_chat(owner, "[icon2html(chassis, owner)]En":"#f00\">Dis"]abled phasing.")
- UpdateButtons()
+ build_all_button_icons()
+ return TRUE
diff --git a/code/modules/vehicles/vehicle_actions.dm b/code/modules/vehicles/vehicle_actions.dm
index 28d469d5189a..725e50cc86b6 100644
--- a/code/modules/vehicles/vehicle_actions.dm
+++ b/code/modules/vehicles/vehicle_actions.dm
@@ -93,7 +93,7 @@
/datum/action/vehicle
check_flags = AB_CHECK_RESTRAINED | AB_CHECK_STUN | AB_CHECK_CONSCIOUS
- icon_icon = 'icons/mob/actions/actions_vehicle.dmi'
+ button_icon = 'icons/mob/actions/actions_vehicle.dmi'
button_icon_state = "vehicle_eject"
var/obj/vehicle/vehicle_target
@@ -105,9 +105,14 @@
desc = "Climb out of your vehicle!"
button_icon_state = "car_eject"
-/datum/action/vehicle/sealed/climb_out/Trigger()
- if(..() && istype(vehicle_entered_target))
- vehicle_entered_target.mob_try_exit(owner, owner)
+/datum/action/vehicle/sealed/climb_out/Trigger(trigger_flags)
+ . = ..()
+ if(!.)
+ return FALSE
+ if(!istype(vehicle_entered_target))
+ return FALSE
+ vehicle_entered_target.mob_try_exit(owner, owner)
+ return TRUE
/datum/action/vehicle/ridden
var/obj/vehicle/ridden/vehicle_ridden_target
@@ -117,8 +122,12 @@
desc = "Take your key out of the vehicle's ignition"
button_icon_state = "car_removekey"
-/datum/action/vehicle/sealed/remove_key/Trigger()
+/datum/action/vehicle/sealed/remove_key/Trigger(trigger_flags)
+ . = ..()
+ if(!.)
+ return FALSE
vehicle_entered_target.remove_key(owner)
+ return TRUE
//CLOWN CAR ACTION DATUMS
/datum/action/vehicle/sealed/horn
@@ -127,48 +136,63 @@
button_icon_state = "car_horn"
var/hornsound = 'sound/items/carhorn.ogg'
-/datum/action/vehicle/sealed/horn/Trigger()
+/datum/action/vehicle/sealed/horn/Trigger(trigger_flags)
+ . = ..()
+ if(!.)
+ return FALSE
if(TIMER_COOLDOWN_CHECK(src, COOLDOWN_CAR_HONK))
- return
+ return FALSE
TIMER_COOLDOWN_START(src, COOLDOWN_CAR_HONK, 2 SECONDS)
vehicle_entered_target.visible_message(span_danger("[vehicle_entered_target] loudly honks!"))
to_chat(owner, span_notice("You press [vehicle_entered_target]'s horn."))
if(istype(vehicle_target.inserted_key, /obj/item/bikehorn))
vehicle_target.inserted_key.attack_self(owner) //The bikehorn plays a sound instead
- return
+ return FALSE
playsound(vehicle_entered_target, hornsound, 75)
+ return TRUE
/datum/action/vehicle/sealed/dump_kidnapped_mobs
name = "Dump Kidnapped Mobs"
desc = "Dump all objects and people in your car on the floor."
button_icon_state = "car_dump"
-/datum/action/vehicle/sealed/dump_kidnapped_mobs/Trigger()
+/datum/action/vehicle/sealed/dump_kidnapped_mobs/Trigger(trigger_flags)
+ . = ..()
+ if(!.)
+ return FALSE
vehicle_entered_target.visible_message(span_danger("[vehicle_entered_target] starts dumping the people inside of it."))
vehicle_entered_target.dump_specific_mobs(VEHICLE_CONTROL_KIDNAPPED)
+ return TRUE
/datum/action/vehicle/sealed/roll_the_dice
name = "Press Colorful Button"
desc = "Press one of those colorful buttons on your display panel!"
button_icon_state = "car_rtd"
-/datum/action/vehicle/sealed/roll_the_dice/Trigger()
+/datum/action/vehicle/sealed/roll_the_dice/Trigger(trigger_flags)
+ . = ..()
+ if(!.)
+ return FALSE
if(!istype(vehicle_entered_target, /obj/vehicle/sealed/car/clowncar))
- return
+ return FALSE
var/obj/vehicle/sealed/car/clowncar/C = vehicle_entered_target
C.roll_the_dice(owner)
+ return TRUE
/datum/action/vehicle/sealed/cannon
name = "Toggle Siege Mode"
desc = "Destroy them with their own fodder!"
button_icon_state = "car_cannon"
-/datum/action/vehicle/sealed/cannon/Trigger()
+/datum/action/vehicle/sealed/cannon/Trigger(trigger_flags)
+ . = ..()
+ if(!.)
+ return FALSE
if(!istype(vehicle_entered_target, /obj/vehicle/sealed/car/clowncar))
- return
+ return FALSE
var/obj/vehicle/sealed/car/clowncar/C = vehicle_entered_target
C.toggle_cannon(owner)
-
+ return TRUE
/datum/action/vehicle/sealed/thank
name = "Thank the Clown Car Driver"
@@ -177,55 +201,63 @@
COOLDOWN_DECLARE(thank_time_cooldown)
-/datum/action/vehicle/sealed/thank/Trigger()
+/datum/action/vehicle/sealed/thank/Trigger(trigger_flags)
+ . = ..()
+ if(!.)
+ return FALSE
if(!istype(vehicle_entered_target, /obj/vehicle/sealed/car/clowncar))
- return
+ return FALSE
if(!COOLDOWN_FINISHED(src, thank_time_cooldown))
- return
+ return FALSE
COOLDOWN_START(src, thank_time_cooldown, 6 SECONDS)
var/obj/vehicle/sealed/car/clowncar/clown_car = vehicle_entered_target
var/mob/living/carbon/human/clown = pick(clown_car.return_drivers())
if(!clown)
- return
+ return FALSE
owner.say("Thank you for the fun ride, [clown.name]!")
clown_car.increment_thanks_counter()
-
+ return TRUE
/datum/action/vehicle/ridden/scooter/skateboard/ollie
name = "Ollie"
desc = "Get some air! Land on a table to do a gnarly grind."
button_icon_state = "skateboard_ollie"
///Cooldown to next jump
- var/next_ollie
-
-/datum/action/vehicle/ridden/scooter/skateboard/ollie/Trigger()
- if(world.time > next_ollie)
- var/obj/vehicle/ridden/scooter/skateboard/V = vehicle_target
- if (V.grinding)
- return
- var/mob/living/L = owner
- var/turf/landing_turf = get_step(V.loc, V.dir)
- L.adjustStaminaLoss(V.instability*2)
- if (L.getStaminaLoss() >= 100)
- playsound(src, 'sound/effects/bang.ogg', 20, TRUE)
- V.unbuckle_mob(L)
- L.throw_at(landing_turf, 2, 2)
- L.Knockdown(40)
- V.visible_message("[L] misses the landing and falls on [L.p_their()] face!")
- else
- L.spin(4, 1)
- animate(L, pixel_y = -6, time = 4)
- animate(V, pixel_y = -6, time = 3)
- playsound(V, 'sound/vehicles/skateboard_ollie.ogg', 50, TRUE)
- passtable_on(L, VEHICLE_TRAIT)
- V.pass_flags |= PASSTABLE
- L.Move(landing_turf, vehicle_target.dir)
- passtable_off(L, VEHICLE_TRAIT)
- V.pass_flags &= ~PASSTABLE
- if((locate(/obj/structure/table) in V.loc.contents) || (locate(/obj/structure/fluff/railing) in V.loc.contents))
- if(locate(/obj/structure/fluff/railing) in V.loc.contents)
- L.client.give_award(/datum/award/achievement/misc/tram_surfer, L)
- V.grinding = TRUE
- V.icon_state = "[V.board_icon]-grind"
- addtimer(CALLBACK(V, TYPE_PROC_REF(/obj/vehicle/ridden/scooter/skateboard, grind)), 2)
- next_ollie = world.time + 5
+ COOLDOWN_DECLARE(next_ollie)
+
+/datum/action/vehicle/ridden/scooter/skateboard/ollie/Trigger(trigger_flags)
+ . = ..()
+ if(!.)
+ return FALSE
+ if(!COOLDOWN_FINISHED(src, next_ollie))
+ return FALSE
+ var/obj/vehicle/ridden/scooter/skateboard/V = vehicle_target
+ if (V.grinding)
+ return FALSE
+ var/mob/living/L = owner
+ var/turf/landing_turf = get_step(V.loc, V.dir)
+ L.adjustStaminaLoss(V.instability*2)
+ if (L.getStaminaLoss() >= 100)
+ playsound(src, 'sound/effects/bang.ogg', 20, TRUE)
+ V.unbuckle_mob(L)
+ L.throw_at(landing_turf, 2, 2)
+ L.Knockdown(40)
+ V.visible_message("[L] misses the landing and falls on [L.p_their()] face!")
+ else
+ L.spin(4, 1)
+ animate(L, pixel_y = -6, time = 4)
+ animate(V, pixel_y = -6, time = 3)
+ playsound(V, 'sound/vehicles/skateboard_ollie.ogg', 50, TRUE)
+ passtable_on(L, VEHICLE_TRAIT)
+ V.pass_flags |= PASSTABLE
+ L.Move(landing_turf, vehicle_target.dir)
+ passtable_off(L, VEHICLE_TRAIT)
+ V.pass_flags &= ~PASSTABLE
+ if((locate(/obj/structure/table) in V.loc.contents) || (locate(/obj/structure/fluff/railing) in V.loc.contents))
+ if(locate(/obj/structure/fluff/railing) in V.loc.contents)
+ L.client.give_award(/datum/award/achievement/misc/tram_surfer, L)
+ V.grinding = TRUE
+ V.icon_state = "[V.board_icon]-grind"
+ addtimer(CALLBACK(V, TYPE_PROC_REF(/obj/vehicle/ridden/scooter/skateboard, grind)), 2)
+ COOLDOWN_START(src, next_ollie, 0.5 SECONDS)
+ return TRUE
diff --git a/code/modules/wiremod/shell/brain_computer_interface.dm b/code/modules/wiremod/shell/brain_computer_interface.dm
index 4bed63c734a0..8ef10b53f93b 100644
--- a/code/modules/wiremod/shell/brain_computer_interface.dm
+++ b/code/modules/wiremod/shell/brain_computer_interface.dm
@@ -133,7 +133,7 @@
/datum/action/innate/bci_action
name = "Action"
- icon_icon = 'icons/mob/actions/actions_items.dmi'
+ button_icon = 'icons/mob/actions/actions_items.dmi'
check_flags = AB_CHECK_CONSCIOUS
button_icon_state = "bci_power"
@@ -278,7 +278,7 @@
/datum/action/innate/bci_charge_action
name = "Check BCI Charge"
check_flags = NONE
- icon_icon = 'icons/obj/power.dmi'
+ button_icon = 'icons/obj/power.dmi'
button_icon_state = "cell"
var/obj/item/circuit_component/bci_core/circuit_component
diff --git a/icons/mob/actions.dmi b/icons/hud/actions.dmi
similarity index 100%
rename from icons/mob/actions.dmi
rename to icons/hud/actions.dmi
diff --git a/modular_citadel/code/modules/clothing/neck.dm b/modular_citadel/code/modules/clothing/neck.dm
index 9507e65e0e53..f1c74d6b83b2 100644
--- a/modular_citadel/code/modules/clothing/neck.dm
+++ b/modular_citadel/code/modules/clothing/neck.dm
@@ -13,11 +13,15 @@
var/toggled = FALSE
var/obj/effect/heart/heart
-/datum/action/item_action/zanderlocket/Trigger()
+/datum/action/item_action/zanderlocket/do_effect(trigger_flags)
+ . = ..()
+ if(!.)
+ return
new/obj/effect/temp_visual/souldeath(owner.loc, owner)
playsound(owner, 'sound/misc/souldeath.ogg', 100, FALSE)
+ return TRUE
/obj/item/clothing/neck/undertale/Initialize(mapload)
- ..()
+ . = ..()
AddComponent(/datum/component/souldeath/neck)
diff --git a/modular_citadel/code/modules/reagents/chemistry/reagents/astrogen.dm b/modular_citadel/code/modules/reagents/chemistry/reagents/astrogen.dm
index 2be1a97873f1..1f99a95dab71 100644
--- a/modular_citadel/code/modules/reagents/chemistry/reagents/astrogen.dm
+++ b/modular_citadel/code/modules/reagents/chemistry/reagents/astrogen.dm
@@ -37,18 +37,22 @@ I'd like to point out from my calculations it'll take about 60-80 minutes to die
var/mob/living/carbon/origin
var/datum/mind/originalmind
-/datum/action/chem/astral/Trigger()
+/datum/action/chem/astral/Trigger(trigger_flags)
+ . = ..()
+ if(!.)
+ return FALSE
if(origin.mind && origin.mind != originalmind)
- to_chat(originalmind.current, "There's a foreign presence in your body blocking your return!")
- return ..()
+ to_chat(originalmind.current, span_warning("There's a foreign presence in your body blocking your return!"))
+ return FALSE
if(origin.reagents.has_reagent(/datum/reagent/fermi/astral) )
var/datum/reagent/fermi/astral/As = locate(/datum/reagent/fermi/astral) in origin.reagents.reagent_list
if(As.current_cycle < 10)
- to_chat(originalmind.current, "The intensity of the astrogen in your body is too much allow you to return to yourself yet!")
- return ..()
+ to_chat(originalmind.current, span_warning("The intensity of the astrogen in your body is too much allow you to return to yourself yet!"))
+ return FALSE
originalmind.transfer_to(origin)
if(origin.mind == originalmind)
qdel(src)
+ return TRUE
/datum/reagent/fermi/astral/reaction_turf(turf/T, reac_volume)
@@ -88,7 +92,7 @@ I'd like to point out from my calculations it'll take about 60-80 minutes to die
if(overdosed)
if(prob(50))
- to_chat(G, "The high conentration of Astrogen in your blood causes you to lapse your concentration for a moment, bringing your projection back to yourself!")
+ to_chat(G, span_warning("The high conentration of Astrogen in your blood causes you to lapse your concentration for a moment, bringing your projection back to yourself!"))
do_teleport(G, M.loc)
metabolization_rate = current_cycle/10 //exponential
sleepytime+=5
@@ -107,12 +111,12 @@ I'd like to point out from my calculations it'll take about 60-80 minutes to die
if(M.mind) //Just in case someone else is inside of you, it makes them a ghost and should hopefully bring them home at the end.
var/mob/living/simple_animal/astral/G2 = new(get_turf(M))
M.mind.transfer_to(G2)
- to_chat(G2, "[M]'s conciousness snaps back to them as [M.p_their()] astrogen runs out, kicking your projected mind out!'")
+ to_chat(G2, span_warning("[M]'s conciousness snaps back to them as [M.p_their()] astrogen runs out, kicking your projected mind out!'"))
log_reagent("FERMICHEM: [G2.mind.name] has been booted out of [M] as their original mind came back as the Astrogen reagent ran out!")
G.mind.transfer_to(origin)
qdel(G)
if(overdosed)
- to_chat(M, "The high volume of astrogen you just took causes you to black out momentarily as your mind snaps back to your body.")
+ to_chat(M, span_warning("The high volume of astrogen you just took causes you to black out momentarily as your mind snaps back to your body."))
M.Sleeping(sleepytime, 0)
antiGenetics = 255
log_reagent("FERMICHEM: [M] has astrally returned to their body!")
@@ -130,39 +134,39 @@ I'd like to point out from my calculations it'll take about 60-80 minutes to die
antiGenetics--
switch(antiGenetics)
if(245)
- to_chat(M, "You notice your body starting to disappear, maybe you took too much Astrogen...?")
+ to_chat(M, span_warning("You notice your body starting to disappear, maybe you took too much Astrogen...?"))
M.alpha--
antiGenetics--
log_reagent("FERMICHEM: [M] ckey: [M.key] has become addicted to Astrogen")
if(220)
- to_chat(M, "Your addiction is only getting worse as your body disappears. Maybe you should get some more, and fast?")
+ to_chat(M, span_notice("Your addiction is only getting worse as your body disappears. Maybe you should get some more, and fast?"))
M.alpha--
antiGenetics--
if(200)
- to_chat(M, "You feel a substantial part of your soul flake off into the ethereal world, rendering yourself unclonable.")
+ to_chat(M, span_notice("You feel a substantial part of your soul flake off into the ethereal world, rendering yourself unclonable."))
M.alpha--
antiGenetics--
ADD_TRAIT(M, TRAIT_NOCLONE, "astral") //So you can't scan yourself, then die, to metacomm. You can only use your memories if you come back as something else.
M.hellbound = TRUE
if(180)
- to_chat(M, "You feel fear build up in yourself as more and more of your body and consciousness begins to fade.")
+ to_chat(M, span_notice("You feel fear build up in yourself as more and more of your body and consciousness begins to fade."))
M.alpha--
antiGenetics--
if(120)
- to_chat(M, "As you lose more and more of yourself, you start to think that maybe shedding your mortality isn't too bad.")
+ to_chat(M, span_notice("As you lose more and more of yourself, you start to think that maybe shedding your mortality isn't too bad."))
M.alpha--
antiGenetics--
if(80)
- to_chat(M, "You feel a thrill shoot through your body as what's left of your mind contemplates your forthcoming oblivion.")
+ to_chat(M, span_notice("You feel a thrill shoot through your body as what's left of your mind contemplates your forthcoming oblivion."))
M.alpha--
antiGenetics--
if(45)
- to_chat(M, "The last vestiges of your mind eagerly await your imminent annihilation.")
+ to_chat(M, span_warning("The last vestiges of your mind eagerly await your imminent annihilation."))
M.alpha--
antiGenetics--
if(-INFINITY to 30)
- to_chat(M, "Your body disperses from existence, as you become one with the universe.")
- to_chat(M, "As your body disappears, your consciousness doesn't. Should you find a way back into the mortal coil, your memories of your previous life remain with you. (At the cost of staying in character while dead. Failure to do this may get you banned from this chem. You are still obligated to follow your directives if you play a midround antag, you do not remember the afterlife IC)")//Legalised IC OOK? I have a suspicion this won't make it past the review. At least it'll be presented as a neat idea! If this is unacceptable how about the player can retain living memories across lives if they die in this way only.
+ to_chat(M, span_warning("Your body disperses from existence, as you become one with the universe."))
+ to_chat(M, span_userdanger("As your body disappears, your consciousness doesn't. Should you find a way back into the mortal coil, your memories of your previous life remain with you. (At the cost of staying in character while dead. Failure to do this may get you banned from this chem. You are still obligated to follow your directives if you play a midround antag, you do not remember the afterlife IC)"))//Legalised IC OOK? I have a suspicion this won't make it past the review. At least it'll be presented as a neat idea! If this is unacceptable how about the player can retain living memories across lives if they die in this way only.
deadchat_broadcast(" has become one with the universe, meaning that their IC conciousness is continuous in a new life. If they find a way back to life, they are allowed to remember their previous life. Be careful what you say. If they abuse this, bwoink the FUCK outta them.", "[M]", M, message_type=DEADCHAT_ANNOUNCEMENT)
M.visible_message("[M] suddenly disappears, their body evaporating from existence, freeing [M] from their mortal coil.")
message_admins("[M] (ckey: [M.ckey]) has become one with the universe, and have continuous memories thoughout their lives should they find a way to come back to life (such as an inteligence potion, midround antag, ghost role).")
diff --git a/tgstation.dme b/tgstation.dme
index 14b128e4c816..4967e20e4b8f 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -26,6 +26,7 @@
#include "code\__DEFINES\_tick.dm"
#include "code\__DEFINES\access.dm"
#include "code\__DEFINES\achievements.dm"
+#include "code\__DEFINES\actions.dm"
#include "code\__DEFINES\actionspeed_modifiers.dm"
#include "code\__DEFINES\admin.dm"
#include "code\__DEFINES\alarm.dm"
@@ -168,6 +169,7 @@
#include "code\__DEFINES\dcs\signals\signals_global.dm"
#include "code\__DEFINES\dcs\signals\signals_hud.dm"
#include "code\__DEFINES\dcs\signals\signals_medical.dm"
+#include "code\__DEFINES\dcs\signals\signals_object.dm"
#include "code\__DEFINES\dcs\signals\signals_mod.dm"
#include "code\__DEFINES\dcs\signals\signals_painting.dm"
#include "code\__DEFINES\dcs\signals\signals_reagent.dm"
@@ -524,6 +526,9 @@
#include "code\datums\achievements\misc_achievements.dm"
#include "code\datums\achievements\misc_scores.dm"
#include "code\datums\achievements\skill_achievements.dm"
+#include "code\datums\actions\cooldown_action.dm"
+#include "code\datums\actions\innate_action.dm"
+#include "code\datums\actions\item_action.dm"
#include "code\datums\actions\beam_rifle.dm"
#include "code\datums\announcers\_announcer.dm"
#include "code\datums\announcers\default_announcer.dm"
@@ -543,6 +548,7 @@
#include "code\datums\changelog\changelog.dm"
#include "code\datums\components\_component.dm"
#include "code\datums\components\acid.dm"
+#include "code\datums\components\action_item_overlay.dm"
#include "code\datums\components\activity.dm"
#include "code\datums\components\anti_magic.dm"
#include "code\datums\components\area_sound_manager.dm"
diff --git a/tools/build/build.js b/tools/build/build.js
index f8d3a9a7dd7e..c3946dcbe06c 100755
--- a/tools/build/build.js
+++ b/tools/build/build.js
@@ -61,6 +61,7 @@ export const DmTarget = new Juke.Target({
'html/**',
'icons/**',
'interface/**',
+ 'modular_citadel/**',
`${DME_NAME}.dme`,
],
outputs: [