diff --git a/code/game/objects/items/devices/paicard.dm b/code/game/objects/items/devices/paicard.dm
index 23d7452f3d..0a73ea74c6 100644
--- a/code/game/objects/items/devices/paicard.dm
+++ b/code/game/objects/items/devices/paicard.dm
@@ -16,6 +16,7 @@ GLOBAL_LIST_BOILERPLATE(all_pai_cards, /obj/item/device/paicard)
var/mob/living/silicon/pai/pai
var/image/screen_layer
var/screen_color = "#00ff0d"
+ var/last_notify = 0
/obj/item/device/paicard/relaymove(var/mob/user, var/direction)
if(user.stat || user.stunned)
@@ -44,26 +45,52 @@ GLOBAL_LIST_BOILERPLATE(all_pai_cards, /obj/item/device/paicard)
if(choice == "No")
return ..()
- var/pai_name = input(user, "Choose your character's name", "Character Name") as text
- var/actual_pai_name = sanitize_name(pai_name, ,1)
- if(isnull(actual_pai_name))
- return ..()
-
+ choice = tgui_alert(user, "Do you want to load your pAI data?", "Load", list("Yes", "No"))
+ var/actual_pai_name
var/turf/location = get_turf(src)
- if(istype(src , /obj/item/device/paicard/typeb))
- var/obj/item/device/paicard/typeb/card = new(location)
- var/mob/living/silicon/pai/new_pai = new(card)
- new_pai.key = user.key
- card.setPersonality(new_pai)
- new_pai.SetName(actual_pai_name)
- else
- var/obj/item/device/paicard/card = new(location)
- var/mob/living/silicon/pai/new_pai = new(card)
- new_pai.key = user.key
- card.setPersonality(new_pai)
- new_pai.SetName(actual_pai_name)
+ if(choice == "No")
+ var/pai_name = input(user, "Choose your character's name", "Character Name") as text
+ actual_pai_name = sanitize_name(pai_name, ,1)
+ if(isnull(actual_pai_name))
+ return ..()
+ if(istype(src , /obj/item/device/paicard/typeb))
+ var/obj/item/device/paicard/typeb/card = new(location)
+ var/mob/living/silicon/pai/new_pai = new(card)
+ new_pai.key = user.key
+ card.setPersonality(new_pai)
+ new_pai.SetName(actual_pai_name)
+ else
+ var/obj/item/device/paicard/card = new(location)
+ var/mob/living/silicon/pai/new_pai = new(card)
+ new_pai.key = user.key
+ card.setPersonality(new_pai)
+ new_pai.SetName(actual_pai_name)
+
+ if(choice == "Yes")
+ if(istype(src , /obj/item/device/paicard/typeb))
+ var/obj/item/device/paicard/typeb/card = new(location)
+ var/mob/living/silicon/pai/new_pai = new(card)
+ new_pai.key = user.key
+ card.setPersonality(new_pai)
+ if(!new_pai.savefile_load(new_pai))
+ var/pai_name = input(new_pai, "Choose your character's name", "Character Name") as text
+ actual_pai_name = sanitize_name(pai_name, ,1)
+ if(isnull(actual_pai_name))
+ return ..()
+ else
+ var/obj/item/device/paicard/card = new(location)
+ var/mob/living/silicon/pai/new_pai = new(card)
+ new_pai.key = user.key
+ card.setPersonality(new_pai)
+ if(!new_pai.savefile_load(new_pai))
+ var/pai_name = input(new_pai, "Choose your character's name", "Character Name") as text
+ actual_pai_name = sanitize_name(pai_name, ,1)
+ if(isnull(actual_pai_name))
+ return ..()
+
qdel(src)
return ..()
+
// VOREStation Edit End
/obj/item/device/paicard/attack_self(mob/user)
@@ -352,9 +379,11 @@ GLOBAL_LIST_BOILERPLATE(all_pai_cards, /obj/item/device/paicard)
current_emotion = emotion
/obj/item/device/paicard/proc/alertUpdate()
- var/turf/T = get_turf_or_move(src.loc)
- for (var/mob/M in viewers(T))
- M.show_message("\The [src] flashes a message across its screen, \"Additional personalities available for download.\"", 3, "\The [src] bleeps electronically.", 2)
+ if(pai)
+ return
+ if(last_notify == 0 || (5 MINUTES <= world.time - last_notify))
+ audible_message("\The [src] flashes a message across its screen, \"Additional personalities available for download.\"", hearing_distance = world.view, runemessage = "bleeps!")
+ last_notify = world.time
/obj/item/device/paicard/emp_act(severity)
for(var/mob/M in src)
diff --git a/code/modules/admin/admin_verb_lists_vr.dm b/code/modules/admin/admin_verb_lists_vr.dm
index 9f4d81120c..b871c3315b 100644
--- a/code/modules/admin/admin_verb_lists_vr.dm
+++ b/code/modules/admin/admin_verb_lists_vr.dm
@@ -112,7 +112,7 @@ var/list/admin_verbs_admin = list(
/client/proc/change_human_appearance_self, // Allows the human-based mob itself change its basic appearance ,
/client/proc/change_security_level,
/client/proc/view_chemical_reaction_logs,
- /client/proc/makePAI,
+ /client/proc/makepAI,
/client/proc/toggle_debug_logs,
/client/proc/toggle_attack_logs,
/datum/admins/proc/paralyze_mob,
@@ -519,7 +519,7 @@ var/list/admin_verbs_event_manager = list(
/client/proc/change_human_appearance_admin, // Allows an admin to change the basic appearance of human-based mobs ,
/client/proc/change_human_appearance_self, // Allows the human-based mob itself change its basic appearance ,
/client/proc/change_security_level,
- /client/proc/makePAI,
+ /client/proc/makepAI,
/client/proc/toggle_debug_logs,
/client/proc/toggle_attack_logs,
/datum/admins/proc/paralyze_mob,
diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm
index 8b0baa5967..40635bb7fe 100644
--- a/code/modules/admin/verbs/debug.dm
+++ b/code/modules/admin/verbs/debug.dm
@@ -129,31 +129,35 @@
M.Animalize()
-/client/proc/makepAI(var/turf/T in mob_list)
+/client/proc/makepAI()
set category = "Fun"
set name = "Make pAI"
- set desc = "Specify a location to spawn a pAI device, then specify a key to play that pAI"
+ set desc = "Spawn someone in as a pAI!"
+ if(!check_rights(R_ADMIN|R_EVENT|R_DEBUG))
+ return
+ var/turf/T = get_turf(mob)
var/list/available = list()
for(var/mob/C in mob_list)
- if(C.key)
+ if(C.key && isobserver(C))
available.Add(C)
var/mob/choice = tgui_input_list(usr, "Choose a player to play the pAI", "Spawn pAI", available)
if(!choice)
return 0
- if(!istype(choice, /mob/observer/dead))
- var/confirm = tgui_alert(usr, "[choice.key] isn't ghosting right now. Are you sure you want to yank them out of them out of their body and place them in this pAI?", "Spawn pAI Confirmation", list("No", "Yes"))
- if(confirm != "Yes")
- return 0
- var/obj/item/device/paicard/card = new(T)
+ var/obj/item/device/paicard/typeb/card = new(T)
var/mob/living/silicon/pai/pai = new(card)
- pai.name = sanitizeSafe(input(choice, "Enter your pAI name:", "pAI Name", "Personal AI") as text)
pai.real_name = pai.name
pai.key = choice.key
card.setPersonality(pai)
+ if(tgui_alert(pai, "Do you want to load your pAI data?", "Load", list("Yes", "No")) == "Yes")
+ pai.savefile_load(pai)
+ else
+ pai.name = sanitizeSafe(input(pai, "Enter your pAI name:", "pAI Name", "Personal AI") as text)
+ card.setPersonality(pai)
for(var/datum/paiCandidate/candidate in paiController.pai_candidates)
if(candidate.key == choice.key)
paiController.pai_candidates.Remove(candidate)
+ log_admin("made a pAI with key=[pai.key] at ([T.x],[T.y],[T.z])")
feedback_add_details("admin_verb","MPAI") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/client/proc/cmd_admin_alienize(var/mob/M in mob_list)
diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm
index 2d991e7290..f642131278 100644
--- a/code/modules/mob/dead/observer/observer.dm
+++ b/code/modules/mob/dead/observer/observer.dm
@@ -984,8 +984,8 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
var/obj/item/device/paicard/PP = p
if(PP.pai == null)
count++
- PP.icon = 'icons/obj/pda_vr.dmi' // VOREStation Edit
PP.add_overlay("pai-ghostalert")
+ PP.alertUpdate()
spawn(54)
PP.cut_overlays()
to_chat(usr,"Flashing the displays of [count] unoccupied PAIs.")
diff --git a/code/modules/mob/living/silicon/pai/examine.dm b/code/modules/mob/living/silicon/pai/examine.dm
index b6890470c9..9c009dcf6f 100644
--- a/code/modules/mob/living/silicon/pai/examine.dm
+++ b/code/modules/mob/living/silicon/pai/examine.dm
@@ -9,16 +9,10 @@
// VOREStation Edit: Start
. += attempt_vr(src,"examine_bellies",args) //VOREStation Edit
- if(ooc_notes)
- . += "OOC Notes: \[View\]"
- // VOREStation Edit: End
-
- . += "*---------*"
-
if(print_flavor_text()) . += "\n[print_flavor_text()]\n"
-
+ // VOREStation Edit: End
+ . += "*---------*"
if (pose)
if(!findtext(pose, regex("\[.?!]$"))) // Will be zero if the last character is not a member of [.?!]
pose = addtext(pose,".") //Makes sure all emotes end with a period.
. += "
It is [pose]" //Extra
intentional
-
\ No newline at end of file
diff --git a/code/modules/mob/living/silicon/pai/pai.dm b/code/modules/mob/living/silicon/pai/pai.dm
index 9c82783928..7187b245aa 100644
--- a/code/modules/mob/living/silicon/pai/pai.dm
+++ b/code/modules/mob/living/silicon/pai/pai.dm
@@ -286,6 +286,7 @@
if(istype(T)) T.visible_message("[src] folds outwards, expanding into a mobile form.")
verbs |= /mob/living/silicon/pai/proc/pai_nom
verbs |= /mob/living/proc/vertical_nom
+ update_icon()
/mob/living/silicon/pai/verb/fold_up()
set category = "pAI Commands"
diff --git a/code/modules/mob/living/silicon/pai/pai_vr.dm b/code/modules/mob/living/silicon/pai/pai_vr.dm
index f8eef7b8fe..6c36c82419 100644
--- a/code/modules/mob/living/silicon/pai/pai_vr.dm
+++ b/code/modules/mob/living/silicon/pai/pai_vr.dm
@@ -213,4 +213,64 @@
if(FEMALE)
t_him = "her"
visible_message("\The [src] hugs [A] to make [t_him] feel better!", \
- "You hug [A] to make [t_him] feel better!")
\ No newline at end of file
+ "You hug [A] to make [t_him] feel better!")
+
+/mob/living/silicon/pai/proc/savefile_path(mob/user)
+ return "data/player_saves/[copytext(user.ckey, 1, 2)]/[user.ckey]/pai.sav"
+
+/mob/living/silicon/pai/proc/savefile_save(mob/user)
+ if(IsGuestKey(user.key))
+ return 0
+
+ var/savefile/F = new /savefile(src.savefile_path(user))
+
+
+ F["name"] << src.name
+ F["description"] << src.flavor_text
+ F["eyecolor"] << src.eye_color
+ F["chassis"] << src.chassis
+ F["emotion"] << src.card.current_emotion
+ F["version"] << 1
+
+ return 1
+
+/mob/living/silicon/pai/proc/savefile_load(mob/user, var/silent = 1)
+ if (IsGuestKey(user.key))
+ return 0
+
+ var/path = savefile_path(user)
+
+ if (!fexists(path))
+ return 0
+
+ var/savefile/F = new /savefile(path)
+
+ if(!F) return //Not everyone has a pai savefile.
+
+ var/version = null
+ F["version"] >> version
+
+ if (isnull(version) || version != 1)
+ fdel(path)
+ if (!silent)
+ tgui_alert_async(user, "Your savefile was incompatible with this version and was deleted.")
+ return 0
+ var/ourname
+ var/ouremotion
+ F["name"] >> ourname
+ SetName(ourname)
+ F["description"] >> flavor_text
+ F["eyecolor"] >> eye_color
+ F["chassis"] >> chassis
+ F["emotion"] >> ouremotion
+ card.screen_color = eye_color
+ if(ouremotion)
+ card.setEmotion(ouremotion)
+ update_icon()
+ return 1
+
+/mob/living/silicon/pai/verb/save_pai_to_slot()
+ set category = "pAI Commands"
+ set name = "Save Configuration"
+ savefile_save(src)
+ to_chat(src, "[name] configuration saved to global pAI settings.")
diff --git a/code/modules/mob/living/silicon/pai/personality.dm b/code/modules/mob/living/silicon/pai/personality.dm
index 73ae49dcb7..de2b8fa202 100644
--- a/code/modules/mob/living/silicon/pai/personality.dm
+++ b/code/modules/mob/living/silicon/pai/personality.dm
@@ -57,4 +57,8 @@
F["description"] >> src.description
F["role"] >> src.role
F["comments"] >> src.comments
+ F["eyecolor"] >> src.eye_color
+ F["chassis"] >> src.chassis
+ F["emotion"] >> src.ouremotion
+
return 1
diff --git a/code/modules/mob/living/silicon/pai/recruit.dm b/code/modules/mob/living/silicon/pai/recruit.dm
index ffd817d9c4..9b5afc434b 100644
--- a/code/modules/mob/living/silicon/pai/recruit.dm
+++ b/code/modules/mob/living/silicon/pai/recruit.dm
@@ -11,7 +11,9 @@ var/datum/paiController/paiController // Global handler for pAI candidates
var/role
var/comments
var/ready = 0
-
+ var/chassis
+ var/ouremotion
+ var/eye_color
/hook/startup/proc/paiControllerSetup()
paiController = new /datum/paiController()
@@ -33,14 +35,23 @@ var/datum/paiController/paiController // Global handler for pAI candidates
return
if(istype(card,/obj/item/device/paicard) && istype(candidate,/datum/paiCandidate))
var/mob/living/silicon/pai/pai = new(card)
- if(!candidate.name)
- pai.name = pick(ninja_names)
- else
- pai.name = candidate.name
- pai.real_name = pai.name
pai.key = candidate.key
-
card.setPersonality(pai)
+ if(!candidate.name)
+ pai.SetName(pick(ninja_names))
+ else
+ pai.SetName(candidate.name)
+ if(candidate.description)
+ pai.flavor_text = candidate.description
+ if(candidate.eye_color)
+ pai.eye_color = candidate.eye_color
+ card.screen_color = pai.eye_color
+ if(candidate.chassis)
+ pai.chassis = candidate.chassis
+ if(candidate.ouremotion)
+ card.setEmotion(candidate.ouremotion)
+ pai.update_icon()
+ pai.real_name = pai.name
card.looking_for_personality = 0
if(pai.mind) update_antag_icons(pai.mind)
@@ -210,7 +221,7 @@ var/datum/paiController/paiController // Global handler for pAI candidates