diff --git a/code/__HELPERS/custom_holoforms.dm b/code/__HELPERS/custom_holoforms.dm
index 0e97314f1f..34b31cc1c7 100644
--- a/code/__HELPERS/custom_holoforms.dm
+++ b/code/__HELPERS/custom_holoforms.dm
@@ -46,17 +46,29 @@
I = getPAIHologramIcon(I)
return I
-//Errors go to user.
-/proc/generate_custom_holoform_from_prefs_safe(datum/preferences/prefs, mob/user)
- if(user)
- if(user.client.prefs.last_custom_holoform > world.time - CUSTOM_HOLOFORM_DELAY)
- to_chat(user, "You are attempting to set your custom holoform too fast!")
- return
- return generate_custom_holoform_from_prefs(prefs, null, null, TRUE, TRUE)
-
//Prompts this client for custom holoform parameters.
/proc/user_interface_custom_holoform(client/C)
var/datum/preferences/target_prefs = C.prefs
+ if(target_prefs.path)
+ var/list/characters = list()
+ var/savefile/S = new /savefile(target_prefs.path)
+ if(S)
+ var/name
+ var/max_save_slots = C.prefs.max_save_slots
+ for(var/i=1, i<=max_save_slots, i++)
+ S.cd = "/character[i]"
+ S["real_name"] >> name
+ if(name)
+ characters[name] = i
+ var/chosen_name = input(C, "Which character do you wish to use as your appearance.") as anything in characters
+ if(chosen_name)
+ if(C.prefs.last_custom_holoform > world.time - CUSTOM_HOLOFORM_DELAY)
+ to_chat(C.mob, "You are attempting to set your custom holoform too fast!")
+ return
+ target_prefs = new(C)
+ if(!target_prefs.load_character(characters[chosen_name], TRUE))
+ target_prefs = C.prefs
+
ASSERT(target_prefs)
//In the future, maybe add custom path allowances a la admin create outfit but for now..
- return generate_custom_holoform_from_prefs_safe(target_prefs, C.mob)
+ return generate_custom_holoform_from_prefs(target_prefs, null, null, TRUE, TRUE)
diff --git a/code/datums/emotes.dm b/code/datums/emotes.dm
index d4b6199187..5683367c55 100644
--- a/code/datums/emotes.dm
+++ b/code/datums/emotes.dm
@@ -144,7 +144,7 @@
var/sound //Sound to play when emote is called
var/vary = FALSE //used for the honk borg emote
var/volume = 50
- mob_type_allowed_typecache = list(/mob/living/brain, /mob/living/silicon)
+ mob_type_allowed_typecache = list(/mob/living/brain, /mob/living/silicon, /mob/camera/aiEye)
/datum/emote/sound/run_emote(mob/user, params)
. = ..()
diff --git a/code/modules/mob/camera/camera.dm b/code/modules/mob/camera/camera.dm
index a381cc512a..99eb638ee0 100644
--- a/code/modules/mob/camera/camera.dm
+++ b/code/modules/mob/camera/camera.dm
@@ -12,6 +12,7 @@
sight = SEE_SELF
move_on_shuttle = FALSE
+
/mob/camera/experience_pressure_difference()
return
@@ -23,5 +24,7 @@
/mob/camera/canUseStorage()
return FALSE
-/mob/camera/emote(act, m_type=1, message = null, intentional = FALSE)
+/mob/camera/emote(act, m_type=1, message = null, intentional = FALSE, forced = FALSE)
+ if(forced)
+ return ..()
return
diff --git a/code/modules/mob/living/emote.dm b/code/modules/mob/living/emote.dm
index ce8bbc5dab..cfebacb977 100644
--- a/code/modules/mob/living/emote.dm
+++ b/code/modules/mob/living/emote.dm
@@ -509,7 +509,7 @@
message = "beeps."
message_param = "beeps at %t."
sound = 'sound/machines/twobeep.ogg'
- mob_type_allowed_typecache = list(/mob/living/brain, /mob/living/silicon, /mob/living/carbon/human)
+ mob_type_allowed_typecache = list(/mob/living/brain, /mob/living/silicon, /mob/living/carbon/human, /mob/camera/aiEye)
/datum/emote/living/circle
key = "circle"
diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm
index 7ce1c1e7cc..fbf2d27c31 100644
--- a/code/modules/mob/living/silicon/ai/ai.dm
+++ b/code/modules/mob/living/silicon/ai/ai.dm
@@ -86,6 +86,7 @@
var/mob/living/silicon/robot/deployed_shell = null //For shell control
var/datum/action/innate/deploy_shell/deploy_action = new
var/datum/action/innate/deploy_last_shell/redeploy_action = new
+ var/datum/action/innate/custom_holoform/custom_holoform = new
var/chnotify = 0
@@ -152,6 +153,7 @@
aicamera = new/obj/item/camera/siliconcam/ai_camera(src)
deploy_action.Grant(src)
+ custom_holoform.Grant(src)
if(isturf(loc))
add_verb(src, list(/mob/living/silicon/ai/proc/ai_network_change, \
@@ -1032,3 +1034,8 @@
qdel(src)
else
return
+
+/mob/living/silicon/ai/emote(act, m_type=1, message = null, intentional = FALSE)
+ if(current && eyeobj)
+ return eyeobj.emote(act, m_type, message, intentional, forced = TRUE)
+ return ..()
diff --git a/code/modules/mob/living/silicon/ai/freelook/eye.dm b/code/modules/mob/living/silicon/ai/freelook/eye.dm
index 8ec39095fb..17de811cdd 100644
--- a/code/modules/mob/living/silicon/ai/freelook/eye.dm
+++ b/code/modules/mob/living/silicon/ai/freelook/eye.dm
@@ -204,3 +204,7 @@
alpha = 100
layer = ABOVE_ALL_MOB_LAYER
plane = GAME_PLANE
+
+/mob/camera/aiEye/emote(act, m_type=1, message = null, intentional = FALSE, forced = FALSE)
+ if(ai?.current)
+ ..()
diff --git a/code/modules/mob/living/silicon/custom_holoform.dm b/code/modules/mob/living/silicon/custom_holoform.dm
index 8ce6e9a29a..e4f7f6780b 100644
--- a/code/modules/mob/living/silicon/custom_holoform.dm
+++ b/code/modules/mob/living/silicon/custom_holoform.dm
@@ -1,28 +1,12 @@
-/mob/living/silicon/verb/clear_custom_holoform()
- set name = "Clear Custom Holoform"
- set desc = "Clear your current custom holoform"
- set category = "OOC"
-
+/mob/living/silicon/proc/attempt_set_custom_holoform()
if(!client.prefs)
to_chat(src, "No preferences datum on your client, contact an admin/coder!")
return
- client.prefs.custom_holoform_icon = null
- client.prefs.cached_holoform_icons = null
- to_chat(src, "Holoform removed.")
-
-/mob/living/silicon/verb/set_custom_holoform()
- set name = "Set Custom Holoform"
- set desc = "Set your custom holoform using your current preferences slot and a specified set of gear."
- set category = "OOC"
-
- if(!client.prefs)
- to_chat(src, "No preferences datum on your client, contact an admin/coder!")
- return
- if(client.prefs.last_custom_holoform > world.time - CUSTOM_HOLOFORM_DELAY)
- to_chat(src, "You are attempting to change custom holoforms too fast!")
var/icon/new_holoform = user_interface_custom_holoform(client)
+ client.prefs.last_custom_holoform = world.time
if(new_holoform)
client.prefs.custom_holoform_icon = new_holoform
client.prefs.cached_holoform_icons = null
- client.prefs.last_custom_holoform = world.time
to_chat(src, "Holoform set.")
+ return TRUE
+ return FALSE
diff --git a/code/modules/mob/living/silicon/pai/pai.dm b/code/modules/mob/living/silicon/pai/pai.dm
index 6d2da187a1..786c121ad6 100644
--- a/code/modules/mob/living/silicon/pai/pai.dm
+++ b/code/modules/mob/living/silicon/pai/pai.dm
@@ -131,6 +131,7 @@
var/datum/action/innate/pai/chassis/AC = new /datum/action/innate/pai/chassis
var/datum/action/innate/pai/rest/AR = new /datum/action/innate/pai/rest
var/datum/action/innate/pai/light/AL = new /datum/action/innate/pai/light
+ var/datum/action/innate/custom_holoform/custom_holoform = new /datum/action/innate/custom_holoform
var/datum/action/language_menu/ALM = new
SW.Grant(src)
@@ -139,6 +140,7 @@
AR.Grant(src)
AL.Grant(src)
ALM.Grant(src)
+ custom_holoform.Grant(src)
emitter_next_use = world.time + 10 SECONDS
/mob/living/silicon/pai/ComponentInitialize()
diff --git a/code/modules/mob/living/silicon/robot/emote.dm b/code/modules/mob/living/silicon/robot/emote.dm
index c532e44ff5..d499c2abae 100644
--- a/code/modules/mob/living/silicon/robot/emote.dm
+++ b/code/modules/mob/living/silicon/robot/emote.dm
@@ -1,9 +1,9 @@
/datum/emote/silicon
- mob_type_allowed_typecache = list(/mob/living/silicon)
+ mob_type_allowed_typecache = list(/mob/living/silicon, /mob/camera/aiEye)
emote_type = EMOTE_AUDIBLE
/datum/emote/sound/silicon
- mob_type_allowed_typecache = list(/mob/living/silicon, /mob/living/carbon/human)
+ mob_type_allowed_typecache = list(/mob/living/silicon, /mob/living/carbon/human, /mob/camera/aiEye)
emote_type = EMOTE_AUDIBLE
var/unrestricted = TRUE
diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm
index 83df3ffba5..7db417b8fa 100644
--- a/code/modules/mob/living/silicon/robot/robot.dm
+++ b/code/modules/mob/living/silicon/robot/robot.dm
@@ -1022,6 +1022,32 @@
R.undeploy()
return TRUE
+/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_state = "custom_holoform"
+ required_mobility_flags = NONE
+
+/datum/action/innate/custom_holoform/Trigger()
+ 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"))
+
+ return TRUE
+
/mob/living/silicon/robot/proc/undeploy()
@@ -1043,6 +1069,8 @@
mainframe.laws.show_laws(mainframe) //Always remind the AI when switching
mainframe = null
+
+
/mob/living/silicon/robot/attack_ai(mob/user)
if(shell && (!connected_ai || connected_ai == user))
var/mob/living/silicon/ai/AI = user
diff --git a/icons/mob/actions/actions_silicon.dmi b/icons/mob/actions/actions_silicon.dmi
index cf3d7a2a95..fa7edf111a 100644
Binary files a/icons/mob/actions/actions_silicon.dmi and b/icons/mob/actions/actions_silicon.dmi differ