mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-01-10 08:54:15 +00:00
* ONLY SKYRAT CHANGES * ACTUALLY SKYRAT CHANGES * yolo, revert later * Update alternate_byond_versions.txt Co-authored-by: AnturK <AnturK@users.noreply.github.com>
262 lines
7.5 KiB
Plaintext
262 lines
7.5 KiB
Plaintext
/obj/item/pai_card
|
|
custom_premium_price = PAYCHECK_COMMAND * 1.25
|
|
desc = "Downloads personal AI assistants to accompany its owner or others."
|
|
icon = 'icons/obj/aicards.dmi'
|
|
icon_state = "pai"
|
|
inhand_icon_state = "electronic"
|
|
lefthand_file = 'icons/mob/inhands/items/devices_lefthand.dmi'
|
|
name = "personal AI device"
|
|
resistance_flags = FIRE_PROOF | ACID_PROOF | INDESTRUCTIBLE
|
|
righthand_file = 'icons/mob/inhands/items/devices_righthand.dmi'
|
|
slot_flags = ITEM_SLOT_BELT
|
|
w_class = WEIGHT_CLASS_SMALL
|
|
worn_icon_state = "electronic"
|
|
|
|
/// Spam alert prevention
|
|
var/alert_cooldown
|
|
/// The emotion icon displayed.
|
|
var/emotion_icon = "off"
|
|
/// Any pAI personalities inserted
|
|
var/mob/living/silicon/pai/pai
|
|
/// Prevents a crew member from hitting "request pAI" repeatedly
|
|
var/request_spam = FALSE
|
|
|
|
/obj/item/pai_card/attackby(obj/item/used, mob/user, params)
|
|
if(pai && istype(used, /obj/item/encryptionkey))
|
|
if(!pai.encrypt_mod)
|
|
to_chat(user, span_alert("Encryption Key ports not configured."))
|
|
return
|
|
user.set_machine(src)
|
|
pai.radio.attackby(used, user, params)
|
|
to_chat(user, span_notice("You insert [used] into the [src]."))
|
|
return
|
|
return ..()
|
|
|
|
/obj/item/pai_card/attack_self(mob/user)
|
|
if(!in_range(src, user))
|
|
return
|
|
user.set_machine(src)
|
|
ui_interact(user)
|
|
|
|
/obj/item/pai_card/Destroy()
|
|
//Will stop people throwing friend pAIs into the singularity so they can respawn
|
|
SSpai.pai_card_list.Remove(src)
|
|
if(!QDELETED(pai))
|
|
QDEL_NULL(pai)
|
|
return ..()
|
|
|
|
/obj/item/pai_card/emag_act(mob/user)
|
|
if(pai)
|
|
pai.handle_emag(user)
|
|
|
|
/obj/item/pai_card/emp_act(severity)
|
|
. = ..()
|
|
if (. & EMP_PROTECT_SELF)
|
|
return
|
|
if(pai && !pai.holoform)
|
|
pai.emp_act(severity)
|
|
|
|
/obj/item/pai_card/handle_atom_del(atom/thing)
|
|
if(thing == pai) //double check /mob/living/silicon/pai/Destroy() if you change these.
|
|
pai = null
|
|
emotion_icon = initial(emotion_icon)
|
|
update_appearance()
|
|
return ..()
|
|
|
|
/obj/item/pai_card/Initialize(mapload)
|
|
. = ..()
|
|
update_appearance()
|
|
SSpai.pai_card_list += src
|
|
|
|
/obj/item/pai_card/suicide_act(mob/living/user)
|
|
user.visible_message(span_suicide("[user] is staring sadly at [src]! [user.p_they()] can't keep living without real human intimacy!"))
|
|
return OXYLOSS
|
|
|
|
/obj/item/pai_card/update_overlays()
|
|
. = ..()
|
|
. += "pai-[emotion_icon]"
|
|
if(pai?.hacking_cable)
|
|
. += "[initial(icon_state)]-connector"
|
|
|
|
/obj/item/pai_card/vv_edit_var(vname, vval)
|
|
. = ..()
|
|
if(vname == NAMEOF(src, emotion_icon))
|
|
update_appearance()
|
|
|
|
/obj/item/pai_card/ui_interact(mob/user, datum/tgui/ui)
|
|
. = ..()
|
|
ui = SStgui.try_update_ui(user, src, ui)
|
|
if(!ui)
|
|
ui = new(user, src, "PaiCard")
|
|
ui.open()
|
|
|
|
/obj/item/pai_card/ui_status(mob/user)
|
|
if(user in get_nested_locs(src))
|
|
return UI_INTERACTIVE
|
|
return ..()
|
|
|
|
/obj/item/pai_card/ui_data(mob/user)
|
|
. = ..()
|
|
var/list/data = list()
|
|
if(!pai)
|
|
data["candidates"] = pool_candidates() || list()
|
|
return data
|
|
data["pai"] = list(
|
|
can_holo = pai.can_holo,
|
|
dna = pai.master_dna,
|
|
emagged = pai.emagged,
|
|
laws = pai.laws.supplied,
|
|
master = pai.master_name,
|
|
name = pai.name,
|
|
transmit = pai.can_transmit,
|
|
receive = pai.can_receive,
|
|
)
|
|
return data
|
|
|
|
/obj/item/pai_card/ui_act(action, list/params, datum/tgui/ui)
|
|
. = ..()
|
|
if(.)
|
|
return TRUE
|
|
// Actions that don't require a pAI
|
|
if(action == "download")
|
|
download_candidate(usr, params["ckey"])
|
|
return TRUE
|
|
if(action == "request")
|
|
find_pai(usr)
|
|
return TRUE
|
|
// pAI specific actions.
|
|
if(!pai)
|
|
return FALSE
|
|
switch(action)
|
|
if("fix_speech")
|
|
pai.fix_speech()
|
|
return TRUE
|
|
if("reset_software")
|
|
pai.reset_software()
|
|
return TRUE
|
|
if("set_dna")
|
|
pai.set_dna(usr)
|
|
return TRUE
|
|
if("set_laws")
|
|
pai.set_laws(usr)
|
|
return TRUE
|
|
if("toggle_holo")
|
|
pai.toggle_holo()
|
|
return TRUE
|
|
if("toggle_radio")
|
|
pai.toggle_radio(params["option"])
|
|
return TRUE
|
|
if("wipe_pai")
|
|
pai.wipe_pai(usr)
|
|
ui.close()
|
|
return TRUE
|
|
return FALSE
|
|
|
|
/** Flashes the pai card screen */
|
|
/obj/item/pai_card/proc/add_alert()
|
|
if(pai)
|
|
return
|
|
add_overlay(
|
|
list(mutable_appearance(icon, "[initial(icon_state)]-alert"),
|
|
emissive_appearance(icon, "[initial(icon_state)]-alert", src, alpha = src.alpha)))
|
|
|
|
/** Removes any overlays */
|
|
/obj/item/pai_card/proc/remove_alert()
|
|
if(pai)
|
|
return
|
|
cut_overlays()
|
|
|
|
/** Alerts pAI cards that someone has submitted candidacy */
|
|
/obj/item/pai_card/proc/alert_update()
|
|
if(!COOLDOWN_FINISHED(src, alert_cooldown))
|
|
return
|
|
COOLDOWN_START(src, alert_cooldown, 5 SECONDS)
|
|
add_alert()
|
|
addtimer(CALLBACK(src, PROC_REF(remove_alert)), 5 SECONDS)
|
|
playsound(src, 'sound/machines/ping.ogg', 30, TRUE)
|
|
visible_message(span_notice("[src] flashes a message across its screen: New personalities available for download!"), blind_message = span_notice("[src] vibrates with an alert."))
|
|
|
|
/**
|
|
* Downloads a candidate from the list and removes them from SSpai.candidates
|
|
*
|
|
* @param {string} ckey The ckey of the candidate to download
|
|
*
|
|
* @returns {boolean} - TRUE if the candidate was downloaded, FALSE if not
|
|
*/
|
|
/obj/item/pai_card/proc/download_candidate(mob/user, ckey)
|
|
if(pai)
|
|
return FALSE
|
|
var/datum/pai_candidate/candidate = SSpai.candidates[ckey]
|
|
if(!candidate?.check_ready())
|
|
balloon_alert(user, "download interrupted")
|
|
return FALSE
|
|
var/mob/living/silicon/pai/new_pai = new(src)
|
|
new_pai.name = candidate.name || pick(GLOB.ninja_names)
|
|
new_pai.real_name = new_pai.name
|
|
new_pai.key = candidate.ckey
|
|
set_personality(new_pai)
|
|
SSpai.candidates -= ckey
|
|
return TRUE
|
|
|
|
/**
|
|
* Pings ghosts to announce that someone is requesting a pAI
|
|
*
|
|
* @param {mob} user - The user who is requesting a pAI
|
|
*
|
|
* @returns {boolean} - TRUE if the pAI was requested, FALSE if not
|
|
*/
|
|
/obj/item/pai_card/proc/find_pai(mob/user)
|
|
if(pai)
|
|
return FALSE
|
|
if(!(GLOB.ghost_role_flags & GHOSTROLE_SILICONS))
|
|
balloon_alert(user, "unavailable: NT blacklisted")
|
|
return FALSE
|
|
if(request_spam)
|
|
balloon_alert(user, "request sent too recently")
|
|
return FALSE
|
|
request_spam = TRUE
|
|
playsound(src, 'sound/machines/ping.ogg', 20, TRUE)
|
|
balloon_alert(user, "pAI assistance requested")
|
|
var/mutable_appearance/alert_overlay = mutable_appearance('icons/obj/aicards.dmi', "pai")
|
|
notify_ghosts("[user] is requesting a pAI companion! Use the pAI button to submit yourself as one.", source = user, alert_overlay = alert_overlay, action = NOTIFY_ORBIT, flashwindow = FALSE, header = "pAI Request!", ignore_key = POLL_IGNORE_PAI)
|
|
addtimer(VARSET_CALLBACK(src, request_spam, FALSE), PAI_SPAM_TIME, TIMER_UNIQUE | TIMER_STOPPABLE | TIMER_CLIENT_TIME | TIMER_DELETE_ME)
|
|
return TRUE
|
|
|
|
/**
|
|
* Gathers a list of candidates to display in the download candidate
|
|
* window. If the candidate isn't marked ready, ie they have not
|
|
* pressed submit, they will be skipped over.
|
|
*
|
|
* @returns - An array of candidate objects.
|
|
*/
|
|
/obj/item/pai_card/proc/pool_candidates()
|
|
var/list/candidates = list()
|
|
if(pai || !length(SSpai?.candidates))
|
|
return candidates
|
|
for(var/key in SSpai.candidates)
|
|
var/datum/pai_candidate/candidate = SSpai.candidates[key]
|
|
if(!candidate?.check_ready())
|
|
continue
|
|
candidates += list(list(
|
|
ckey = candidate.ckey,
|
|
comments = candidate.comments,
|
|
description = candidate.description,
|
|
name = candidate.name,
|
|
))
|
|
return candidates
|
|
|
|
/**
|
|
* Sets the personality on the current pai_card
|
|
*
|
|
* @param {silicon/pai} downloaded - The new pAI to load into the card.
|
|
*/
|
|
/obj/item/pai_card/proc/set_personality(mob/living/silicon/pai/downloaded)
|
|
if(pai)
|
|
return FALSE
|
|
pai = downloaded
|
|
emotion_icon = "null"
|
|
update_appearance()
|
|
playsound(src, 'sound/effects/pai_boot.ogg', 50, TRUE, -1)
|
|
audible_message("[src] plays a cheerful startup noise!")
|
|
return TRUE
|