diff --git a/code/game/gamemodes/malfunction/Malf_Modules.dm b/code/game/gamemodes/malfunction/Malf_Modules.dm
index c1a907f9191..816eadf55bf 100644
--- a/code/game/gamemodes/malfunction/Malf_Modules.dm
+++ b/code/game/gamemodes/malfunction/Malf_Modules.dm
@@ -83,6 +83,36 @@
else
add_ranged_ability(user, enable_text)
+/datum/action/innate/ai/choose_modules
+ name = "Choose Modules"
+ desc = "Spend your processing time to gain a variety of different abilities."
+ button_icon_state = "choose_module"
+ auto_use_uses = FALSE // This is an infinite ability.
+
+/datum/action/innate/ai/choose_modules/Grant(mob/living/L)
+ . = ..()
+ owner_AI.malf_picker = new /datum/module_picker
+
+/datum/action/innate/ai/choose_modules/Trigger()
+ . = ..()
+ owner_AI.malf_picker.use(owner_AI)
+
+/datum/action/innate/ai/return_to_core
+ name = "Return to Main Core"
+ desc = "Leave the APC you are shunted to, and return to your core."
+ icon_icon = 'icons/obj/power.dmi'
+ button_icon_state = "apcemag"
+ auto_use_uses = FALSE // Here just to prevent the "You have X uses remaining" from popping up.
+
+/datum/action/innate/ai/return_to_core/Trigger()
+ . = ..()
+ var/obj/machinery/power/apc/apc = owner_AI.loc
+ if(!istype(apc)) // This shouldn't happen but here for safety.
+ to_chat(src, "You are already in your Main Core.")
+ return
+ apc.malfvacate()
+ qdel(src)
+
//The datum and interface for the malf unlock menu, which lets them choose actions to unlock.
/datum/module_picker
var/temp
@@ -102,7 +132,7 @@
if(istype(A, initial(AM.power_type)))
qdel(A)
-/datum/module_picker/proc/use(user as mob)
+/datum/module_picker/proc/use(mob/user)
var/dat
dat += {"Select use of processing time: (currently #[processing_time] left.)
diff --git a/code/modules/antagonists/traitor/datum_traitor.dm b/code/modules/antagonists/traitor/datum_traitor.dm
index e13fb701317..1ae4b639fc6 100644
--- a/code/modules/antagonists/traitor/datum_traitor.dm
+++ b/code/modules/antagonists/traitor/datum_traitor.dm
@@ -42,7 +42,8 @@
A.laws.sorted_laws = A.laws.inherent_laws.Copy() // AI's 'notify laws' button will still state a law 0 because sorted_laws contains it
A.show_laws()
A.malf_picker.remove_malf_verbs(A)
- A.verbs -= /mob/living/silicon/ai/proc/choose_modules
+ var/datum/action/innate/ai/choose_modules/CM = locate() in A.actions
+ qdel(CM)
qdel(A.malf_picker)
if(owner.som)
diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm
index 85c4ceac427..61808693a1a 100644
--- a/code/modules/mob/living/silicon/ai/ai.dm
+++ b/code/modules/mob/living/silicon/ai/ai.dm
@@ -849,13 +849,6 @@ GLOBAL_LIST_INIT(ai_verbs_default, list(
to_chat(src, "Switched to [network] camera network.")
//End of code by Mord_Sith
-
-/mob/living/silicon/ai/proc/choose_modules()
- set category = "Malfunction"
- set name = "Choose Module"
-
- malf_picker.use(src)
-
/mob/living/silicon/ai/proc/ai_statuschange()
set category = "AI Commands"
set name = "AI Status"
@@ -1026,15 +1019,6 @@ GLOBAL_LIST_INIT(ai_verbs_default, list(
return
-/mob/living/silicon/ai/proc/corereturn()
- set category = "Malfunction"
- set name = "Return to Main Core"
-
- var/obj/machinery/power/apc/apc = loc
- if(!istype(apc))
- to_chat(src, "You are already in your Main Core.")
- return
- apc.malfvacate()
//Toggles the luminosity and applies it by re-entereing the camera.
/mob/living/silicon/ai/proc/toggle_camera_light()
@@ -1242,8 +1226,8 @@ GLOBAL_LIST_INIT(ai_verbs_default, list(
to_chat(src, "In the top right corner of the screen you will find the Malfunctions tab, where you can purchase various abilities, from upgraded surveillance to station ending doomsday devices.")
to_chat(src, "You are also capable of hacking APCs, which grants you more points to spend on your Malfunction powers. The drawback is that a hacked APC will give you away if spotted by the crew. Hacking an APC takes 60 seconds.")
view_core() //A BYOND bug requires you to be viewing your core before your verbs update
- verbs += /mob/living/silicon/ai/proc/choose_modules
- malf_picker = new /datum/module_picker
+ var/datum/action/innate/ai/choose_modules/malf_shop = new
+ malf_shop.Grant(src)
/mob/living/silicon/ai/proc/open_nearest_door(mob/living/target)
if(!istype(target))
diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm
index 234b885284e..8f45b175753 100644
--- a/code/modules/power/apc.dm
+++ b/code/modules/power/apc.dm
@@ -1057,7 +1057,8 @@
occupier.eyeobj.name = "[occupier.name] (AI Eye)"
if(malf.parent)
qdel(malf)
- occupier.verbs += /mob/living/silicon/ai/proc/corereturn
+ var/datum/action/innate/ai/return_to_core/R = new
+ R.Grant(occupier)
occupier.cancel_camera()
if((seclevel2num(get_security_level()) == SEC_LEVEL_DELTA) && malf.nuking)
for(var/obj/item/pinpointer/point in GLOB.pinpointer_list)
diff --git a/icons/mob/actions/actions.dmi b/icons/mob/actions/actions.dmi
index 4ea648dea13..80a5dbe5b04 100644
Binary files a/icons/mob/actions/actions.dmi and b/icons/mob/actions/actions.dmi differ