[MIRROR] General pAI code improvements [MDB IGNORE] (#10683)

* General pAI code improvements

* Feex

Co-authored-by: John Willard <53777086+JohnFulpWillard@users.noreply.github.com>
Co-authored-by: GoldenAlpharex <58045821+GoldenAlpharex@users.noreply.github.com>
This commit is contained in:
SkyratBot
2022-01-16 17:40:00 +00:00
committed by GitHub
co-authored by John Willard GoldenAlpharex
parent d7f0071902
commit 32bc9a96b6
17 changed files with 303 additions and 341 deletions
+1
View File
@@ -39,6 +39,7 @@
//Silicon
#define JOB_AI "AI"
#define JOB_CYBORG "Cyborg"
#define JOB_PERSONAL_AI "Personal AI"
//Security
#define JOB_WARDEN "Warden"
#define JOB_DETECTIVE "Detective"
-2
View File
@@ -1,2 +0,0 @@
/// Total percent required to hack a door.
#define HACK_COMPLETE 100
+1 -1
View File
@@ -44,7 +44,7 @@ GLOBAL_LIST_INIT(poll_ignore_desc, list(
POLL_IGNORE_CONTRACTOR_SUPPORT = "Contractor Support Unit",
POLL_IGNORE_ACADEMY_WIZARD = "Academy Wizard Defender",
POLL_IGNORE_CORTICAL_BORER = "Cortical Borer",
POLL_IGNORE_PAI = "Personal AI"
POLL_IGNORE_PAI = JOB_PERSONAL_AI,
))
//Skyrat Edit Stop: Cortical Borer
GLOBAL_LIST_INIT(poll_ignore, init_poll_ignore())
+2 -2
View File
@@ -144,8 +144,8 @@
return SECONDARY_ATTACK_CALL_NORMAL
/obj/attackby(obj/item/I, mob/living/user, params)
return ..() || ((obj_flags & CAN_BE_HIT) && I.attack_atom(src, user, params))
/obj/attackby(obj/item/attacking_item, mob/user, params)
return ..() || ((obj_flags & CAN_BE_HIT) && attacking_item.attack_atom(src, user, params))
/mob/living/attackby(obj/item/attacking_item, mob/living/user, params)
if(..())
+18 -15
View File
@@ -9,7 +9,9 @@
w_class = WEIGHT_CLASS_SMALL
slot_flags = ITEM_SLOT_BELT
custom_premium_price = PAYCHECK_HARD * 1.25
///don't spam alert messages.
resistance_flags = FIRE_PROOF | ACID_PROOF | INDESTRUCTIBLE
/// Spam alert prevention
var/alert_cooldown
/// If the pAIcard is slotted in a PDA
var/slotted = FALSE
@@ -17,7 +19,6 @@
var/mob/living/silicon/pai/pai
///what emotion icon we have. handled in /mob/living/silicon/pai/Topic()
var/emotion_icon = "off"
resistance_flags = FIRE_PROOF | ACID_PROOF | INDESTRUCTIBLE
/obj/item/paicard/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!"))
@@ -102,16 +103,16 @@
break
if(isnull(candidate))
return FALSE
if(src.pai)
if(pai)
return FALSE
if(SSpai.check_ready(candidate) != candidate)
return FALSE
/// The newly downloaded pAI personality
var/mob/living/silicon/pai/pai = new(src)
pai.name = candidate.name || pick(GLOB.ninja_names)
pai.real_name = pai.name
pai.key = candidate.key
src.setPersonality(pai)
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.key
setPersonality(new_pai)
SSpai.candidates -= candidate
if("fix_speech")
to_chat(pai, span_notice("Your owner has corrected your speech modulation!"))
@@ -159,13 +160,15 @@
to_chat(pai, span_notice("Your owner has [transmit_holder ? "enabled" : "disabled"] your [transmitting ? "outgoing" : "incoming"] radio transmissions!"))
if("wipe_pai")
var/confirm = tgui_alert(usr, "Are you certain you wish to delete the current personality? This action cannot be undone.", "Personality Wipe", list("Yes", "No"))
if(confirm == "Yes")
if(pai)
to_chat(pai, span_warning("You feel yourself slipping away from reality."))
to_chat(pai, span_danger("Byte by byte you lose your sense of self."))
to_chat(pai, span_userdanger("Your mental faculties leave you."))
to_chat(pai, span_rose("oblivion... "))
qdel(pai)
if(confirm != "Yes")
return
if(!pai)
return
to_chat(pai, span_warning("You feel yourself slipping away from reality."))
to_chat(pai, span_danger("Byte by byte you lose your sense of self."))
to_chat(pai, span_userdanger("Your mental faculties leave you."))
to_chat(pai, span_rose("oblivion... "))
qdel(pai)
return
// WIRE_SIGNAL = 1
+24 -27
View File
@@ -439,16 +439,13 @@
else
. += span_notice("It cannot be modified or attached.")
/obj/item/radio/attackby(obj/item/W, mob/user, params)
/obj/item/radio/screwdriver_act(mob/living/user, obj/item/tool)
add_fingerprint(user)
if(W.tool_behaviour == TOOL_SCREWDRIVER)
unscrewed = !unscrewed
if(unscrewed)
to_chat(user, span_notice("The radio can now be attached and modified!"))
else
to_chat(user, span_notice("The radio can no longer be modified or attached!"))
unscrewed = !unscrewed
if(unscrewed)
to_chat(user, span_notice("The radio can now be attached and modified!"))
else
return ..()
to_chat(user, span_notice("The radio can no longer be modified or attached!"))
/obj/item/radio/emp_act(severity)
. = ..()
@@ -508,36 +505,36 @@
. = ..()
set_frequency(FREQ_SYNDICATE)
/obj/item/radio/borg/attackby(obj/item/W, mob/user, params)
/obj/item/radio/borg/screwdriver_act(mob/living/user, obj/item/tool)
if(!keyslot)
to_chat(user, span_warning("This radio doesn't have any encryption keys!"))
return
if(W.tool_behaviour == TOOL_SCREWDRIVER)
if(keyslot)
for(var/ch_name in channels)
SSradio.remove_object(src, GLOB.radiochannels[ch_name])
secure_radio_connections[ch_name] = null
for(var/ch_name in channels)
SSradio.remove_object(src, GLOB.radiochannels[ch_name])
secure_radio_connections[ch_name] = null
if(keyslot)
var/turf/user_turf = get_turf(user)
if(user_turf)
keyslot.forceMove(user_turf)
keyslot = null
if(keyslot)
var/turf/T = get_turf(user)
if(T)
keyslot.forceMove(T)
keyslot = null
recalculateChannels()
to_chat(user, span_notice("You pop out the encryption key in the radio."))
return ..()
recalculateChannels()
to_chat(user, span_notice("You pop out the encryption key in the radio."))
/obj/item/radio/borg/attackby(obj/item/attacking_item, mob/user, params)
else
to_chat(user, span_warning("This radio doesn't have any encryption keys!"))
else if(istype(W, /obj/item/encryptionkey/))
if(istype(attacking_item, /obj/item/encryptionkey))
if(keyslot)
to_chat(user, span_warning("The radio can't hold another key!"))
return
if(!keyslot)
if(!user.transferItemToLoc(W, src))
if(!user.transferItemToLoc(attacking_item, src))
return
keyslot = W
keyslot = attacking_item
recalculateChannels()
+1 -1
View File
@@ -6,7 +6,7 @@
item_flags = NOBLUDGEON
var/obj/machinery/machine //what machine we're currently hacking.
/obj/item/pai_cable/machine/Destroy()
/obj/item/pai_cable/Destroy()
machine = null
return ..()
+1 -1
View File
@@ -225,7 +225,7 @@ INITIALIZE_IMMEDIATE(/atom/movable/virtualspeaker)
var/mob/living/silicon/robot/B = M
job = "[B.designation] Cyborg"
else if(istype(M, /mob/living/silicon/pai)) // Personal AI (pAI)
job = "Personal AI"
job = JOB_PERSONAL_AI
else if(isobj(M)) // Cold, emotionless machines
job = "Machine"
else // Unidentifiable mob
@@ -0,0 +1,10 @@
/mob/living/silicon/pai/Login()
. = ..()
if(!. || !client)
return FALSE
client.perspective = EYE_PERSPECTIVE
if(holoform)
client.eye = src
else
client.eye = card
+106 -184
View File
@@ -1,6 +1,9 @@
/mob/living/silicon/pai
name = "pAI"
icon = 'icons/mob/pai.dmi'
held_lh = 'icons/mob/pai_item_lh.dmi'
held_rh = 'icons/mob/pai_item_rh.dmi'
head_icon = 'icons/mob/pai_item_head.dmi'
icon_state = "repairbot"
mouse_opacity = MOUSE_OPACITY_ICON
density = FALSE
@@ -16,74 +19,78 @@
pull_force = 0
move_resist = 0
worn_slot_flags = ITEM_SLOT_HEAD
held_lh = 'icons/mob/pai_item_lh.dmi'
held_rh = 'icons/mob/pai_item_rh.dmi'
head_icon = 'icons/mob/pai_item_head.dmi'
radio = /obj/item/radio/headset/silicon/pai
can_buckle_to = FALSE
mobility_flags = MOBILITY_FLAGS_REST_CAPABLE_DEFAULT
var/network = "ss13"
var/obj/machinery/camera/current = null
/// The card we inhabit
var/obj/item/paicard/card
/// Used as currency to purchase different abilities
var/ram = 100
/// Installed software on the pAI
var/list/software = list()
/// current user's DNA
var/userDNA
/// The card we inhabit
var/obj/item/paicard/card
/// Are we hacking a door?
var/hacking = FALSE
/// The progress for hacking
var/datum/progressbar/hackbar
/// The strength of the internal flashlight
var/brightness_power = 5
/// Changes the display to syndi if true
var/emagged = FALSE
var/speakStatement = "states"
var/speakExclamation = "declares"
var/speakDoubleExclamation = "alarms"
var/speakQuery = "queries"
/// The cable we produce when hacking a door
var/obj/item/pai_cable/hacking_cable
/// Name of the one who commands us
var/master
/// DNA string for owner verification
var/master_dna
/// Whether we are currently holoformed
var/holoform = FALSE
/// Whether the pAI can enter holoform or not
var/canholo = TRUE
/// Whether this pAI can transmit radio messages
var/can_transmit = TRUE
/// Whether this pAI can recieve radio messages
var/can_receive = TRUE
// Various software-specific vars
// Various software-specific vars
/// Toggles whether the Security HUD is active or not
var/secHUD = FALSE
/// Toggles whether the Medical HUD is active or not
var/medHUD = FALSE
/// Toggles whether the pAI can hold encryption keys or not
var/encryptmod = FALSE
/// Toggles whether universal translator has been activated. Cannot be reversed
var/languages_granted = FALSE
/// The airlock being hacked
var/obj/machinery/door/hackdoor
/// Possible values: 0 - 100, >= 100 means the hack is complete and will be reset upon next check
var/hackprogress = 0
// Software
/// Atmospheric analyzer
var/obj/item/analyzer/atmos_analyzer
/// AI's signaler
var/obj/item/assembly/signaler/internal/signaler
/// Synthesizer
/// pAI Synthesizer
var/obj/item/instrument/piano_synth/internal_instrument
/// pAI Newscaster
var/obj/machinery/newscaster
/// pAI healthanalyzer
var/obj/item/healthanalyzer/hostscan
/// Internal pAI GPS, enabled if pAI downloads GPS software, and then uses it.
var/obj/item/gps/pai/internal_gps = null
var/obj/item/gps/pai/internal_gps
/// The cable we produce when hacking a door
var/obj/item/pai_cable/hacking_cable
var/encryptmod = FALSE
var/holoform = FALSE
var/canholo = TRUE
var/can_transmit = TRUE
var/can_receive = TRUE
/// The current chasis that will appear when in holoform
var/chassis = "repairbot"
var/list/possible_chassis = list("cat" = TRUE, "mouse" = TRUE, "monkey" = TRUE, "corgi" = FALSE, "fox" = FALSE, "repairbot" = TRUE, "rabbit" = TRUE, "bat" = FALSE, "butterfly" = FALSE, "hawk" = FALSE, "lizard" = FALSE, "duffel" = TRUE) //assoc value is whether it can be picked up.
/// List of all possible chasises. TRUE means the pAI can be picked up in this chasis.
var/list/possible_chassis = list(
"cat" = TRUE,
"mouse" = TRUE,
"monkey" = TRUE,
"corgi" = FALSE,
"fox" = FALSE,
"repairbot" = TRUE,
"rabbit" = TRUE,
"bat" = FALSE,
"butterfly" = FALSE,
"hawk" = FALSE,
"lizard" = FALSE,
"duffel" = TRUE,
)
var/emitterhealth = 20
var/emittermaxhealth = 20
@@ -92,62 +99,68 @@
var/emitteroverloadcd = 100
var/emittersemicd = FALSE
var/overload_ventcrawl = 0
var/overload_bulletblock = 0 //Why is this a good idea?
var/overload_maxhealth = 0
var/silent = FALSE
var/brightness_power = 5
/// Bool that determines if the pAI can refresh medical/security records.
var/refresh_spam = FALSE
/// Cached list for medical records to send as static data
var/list/medical_records = list()
/// Cached list for security records to send as static data
var/list/security_records = list()
var/list/available_software = list(
"crew manifest" = 5,
"digital messenger" = 5,
"atmosphere sensor" = 5,
"photography module" = 5,
"camera zoom" = 10,
"printer module" = 10,
"remote signaler" = 10,
"medical records" = 10,
"security records" = 10,
"host scan" = 10,
"medical HUD" = 20,
"security HUD" = 20,
"loudness booster" = 20,
"newscaster" = 20,
"door jack" = 25,
"encryption keys" = 25,
"internal gps" = 35,
"universal translator" = 35,
)
/mob/living/silicon/pai/add_sensors() //pAIs have to buy their HUDs
return
/mob/living/silicon/pai/handle_atom_del(atom/A)
if(A == hacking_cable)
/mob/living/silicon/pai/handle_atom_del(atom/deleting_atom)
if(deleting_atom == hacking_cable)
hacking_cable = null
if(!QDELETED(card))
card.update_appearance()
if(A == atmos_analyzer)
if(deleting_atom == atmos_analyzer)
atmos_analyzer = null
if(A == internal_instrument)
if(deleting_atom == internal_instrument)
internal_instrument = null
if(A == newscaster)
if(deleting_atom == newscaster)
newscaster = null
if(A == signaler)
if(deleting_atom == signaler)
signaler = null
if(A == hostscan)
if(deleting_atom == hostscan)
hostscan = null
if(A == internal_gps)
if(deleting_atom == internal_gps)
internal_gps = null
return ..()
/mob/living/silicon/pai/Destroy()
QDEL_NULL(atmos_analyzer)
QDEL_NULL(internal_instrument)
QDEL_NULL(hacking_cable)
QDEL_NULL(newscaster)
QDEL_NULL(signaler)
QDEL_NULL(hostscan)
QDEL_NULL(internal_gps)
if(!QDELETED(card) && loc != card)
card.forceMove(drop_location())
card.pai = null //these are otherwise handled by paicard/handle_atom_del()
card.emotion_icon = initial(card.emotion_icon)
card.update_appearance()
GLOB.pai_list -= src
return ..()
/mob/living/silicon/pai/Initialize(mapload)
var/obj/item/paicard/P = loc
var/obj/item/paicard/pai_card = loc
START_PROCESSING(SSfastprocess, src)
GLOB.pai_list += src
make_laws()
if(!istype(P)) //when manually spawning a pai, we create a card to put it into.
var/newcardloc = P
P = new /obj/item/paicard(newcardloc)
P.setPersonality(src)
forceMove(P)
card = P
job = "Personal AI"
if(!istype(pai_card)) //when manually spawning a pai, we create a card to put it into.
var/newcardloc = pai_card
pai_card = new /obj/item/paicard(newcardloc)
pai_card.setPersonality(src)
forceMove(pai_card)
card = pai_card
job = JOB_PERSONAL_AI
atmos_analyzer = new /obj/item/analyzer(src)
signaler = new /obj/item/assembly/signaler/internal(src)
hostscan = new /obj/item/healthanalyzer(src)
@@ -167,57 +180,37 @@
ADD_TRAIT(src, TRAIT_IMMOBILIZED, PAI_FOLDED)
ADD_TRAIT(src, TRAIT_HANDS_BLOCKED, PAI_FOLDED)
/mob/living/silicon/pai/Destroy()
QDEL_NULL(atmos_analyzer)
QDEL_NULL(internal_instrument)
QDEL_NULL(hacking_cable)
QDEL_NULL(newscaster)
QDEL_NULL(signaler)
QDEL_NULL(hostscan)
QDEL_NULL(internal_gps)
if(!QDELETED(card) && loc != card)
card.forceMove(drop_location())
card.pai = null //these are otherwise handled by paicard/handle_atom_del()
card.emotion_icon = initial(card.emotion_icon)
card.update_appearance()
GLOB.pai_list -= src
return ..()
/mob/living/silicon/pai/proc/pdaconfig()
//PDA
aiPDA = new/obj/item/pda/ai(src)
aiPDA = new /obj/item/pda/ai(src)
aiPDA.owner = real_name
aiPDA.ownjob = "pAI Messenger"
aiPDA.name = real_name + " (" + aiPDA.ownjob + ")"
/mob/living/silicon/pai/proc/process_hack(delta_time, times_fired)
if(hacking_cable?.machine && istype(hacking_cable.machine, /obj/machinery/door) && hacking_cable.machine == hackdoor && get_dist(src, hackdoor) <= 1)
hackprogress = clamp(hackprogress + (2 * delta_time), 0, HACK_COMPLETE)
hackbar.update(hackprogress)
else
to_chat(src, span_notice("Door Jack: Connection to airlock has been lost. Hack aborted."))
hackprogress = 0
hacking = FALSE
hackdoor = null
hackbar.end_progress()
QDEL_NULL(hackbar)
QDEL_NULL(hacking_cable)
if(!QDELETED(card))
card.update_appearance()
return
if(hackprogress >= HACK_COMPLETE)
hackprogress = 0
hacking = FALSE
hackbar.end_progress()
var/obj/machinery/door/door = hacking_cable.machine
door.open()
QDEL_NULL(hackbar)
QDEL_NULL(hacking_cable)
aiPDA.name = "[real_name] ([aiPDA.ownjob])"
/mob/living/silicon/pai/make_laws()
laws = new /datum/ai_laws/pai()
return TRUE
/mob/living/silicon/pai/Login()
. = ..()
if(!. || !client)
return FALSE
client.perspective = EYE_PERSPECTIVE
if(holoform)
client.eye = src
else
client.eye = card
/mob/living/silicon/pai/get_status_tab_items()
. += ..()
if(!stat)
. += text("Emitter Integrity: [emitterhealth * (100/emittermaxhealth)]")
. += text("Emitter Integrity: [emitterhealth * (100 / emittermaxhealth)]")
else
. += text("Systems nonfunctional")
@@ -236,65 +229,6 @@
if(delold)
qdel(src)
/datum/action/innate/pai
name = "PAI Action"
icon_icon = 'icons/mob/actions/actions_silicon.dmi'
var/mob/living/silicon/pai/P
/datum/action/innate/pai/Trigger()
if(!ispAI(owner))
return 0
P = owner
/datum/action/innate/pai/software
name = "Software Interface"
button_icon_state = "pai"
background_icon_state = "bg_tech"
/datum/action/innate/pai/software/Trigger()
..()
P.ui_act()
/datum/action/innate/pai/shell
name = "Toggle Holoform"
button_icon_state = "pai_holoform"
background_icon_state = "bg_tech"
/datum/action/innate/pai/shell/Trigger()
..()
if(P.holoform)
P.fold_in(0)
else
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/rest
name = "Rest"
button_icon_state = "pai_rest"
background_icon_state = "bg_tech"
/datum/action/innate/pai/rest/Trigger()
..()
P.toggle_resting()
/datum/action/innate/pai/light
name = "Toggle Integrated Lights"
icon_icon = 'icons/mob/actions/actions_spells.dmi'
button_icon_state = "emp"
background_icon_state = "bg_tech"
/datum/action/innate/pai/light/Trigger()
..()
P.toggle_integrated_light()
/mob/living/silicon/pai/Process_Spacemove(movement_dir = 0)
. = ..()
if(!.)
@@ -307,21 +241,6 @@
. = ..()
. += "A personal AI in holochassis mode. Its master ID string seems to be [master]."
/mob/living/silicon/pai/Life(delta_time = SSMOBS_DT, times_fired)
. = ..()
if(QDELETED(src) || stat == DEAD)
return
if(hacking_cable)
if(get_dist(src, hacking_cable) > 1)
var/turf/T = get_turf(src)
T.visible_message(span_warning("[hacking_cable] rapidly retracts back into its spool."), span_hear("You hear a click and the sound of wire spooling rapidly."))
QDEL_NULL(hacking_cable)
if(!QDELETED(card))
card.update_appearance()
else if(hacking)
process_hack(delta_time, times_fired)
silent = max(silent - (0.5 * delta_time), 0)
/mob/living/silicon/pai/updatehealth()
if(status_flags & GODMODE)
return
@@ -337,8 +256,11 @@
return ..()
/obj/item/paicard/screwdriver_act(mob/living/user, obj/item/tool)
return pai.radio.screwdriver_act(user, tool)
/obj/item/paicard/attackby(obj/item/used, mob/user, params)
if(pai && (istype(used, /obj/item/encryptionkey) || used.tool_behaviour == TOOL_SCREWDRIVER))
if(pai && istype(used, /obj/item/encryptionkey))
if(!pai.encryptmod)
to_chat(user, span_alert("Encryption Key ports not configured."))
return
@@ -0,0 +1,58 @@
/datum/action/innate/pai
name = "PAI Action"
icon_icon = 'icons/mob/actions/actions_silicon.dmi'
var/mob/living/silicon/pai/pai_owner
/datum/action/innate/pai/Trigger()
if(!ispAI(owner))
return FALSE
pai_owner = owner
/datum/action/innate/pai/software
name = "Software Interface"
button_icon_state = "pai"
background_icon_state = "bg_tech"
/datum/action/innate/pai/software/Trigger()
..()
pai_owner.ui_act()
/datum/action/innate/pai/shell
name = "Toggle Holoform"
button_icon_state = "pai_holoform"
background_icon_state = "bg_tech"
/datum/action/innate/pai/shell/Trigger()
..()
if(pai_owner.holoform)
pai_owner.fold_in(0)
else
pai_owner.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()
..()
pai_owner.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()
..()
pai_owner.toggle_resting()
/datum/action/innate/pai/light
name = "Toggle Integrated Lights"
icon_icon = 'icons/mob/actions/actions_spells.dmi'
button_icon_state = "emp"
background_icon_state = "bg_tech"
/datum/action/innate/pai/light/Trigger()
..()
pai_owner.toggle_integrated_light()
@@ -6,9 +6,8 @@
. = ..()
if(. & EMP_PROTECT_SELF)
return
take_holo_damage(50/severity)
Paralyze(400/severity)
silent = max(20/severity, silent)
take_holo_damage(50 / severity)
Stun(400 / severity)
if(holoform)
fold_in(force = TRUE)
//Need more effects that aren't instadeath or permanent law corruption.
@@ -41,19 +40,20 @@
Paralyze(200)
/mob/living/silicon/pai/attack_hand(mob/living/carbon/human/user, list/modifiers)
if(user.combat_mode)
user.do_attack_animation(src)
if (user.name == master)
visible_message(span_notice("Responding to its master's touch, [src] disengages its holochassis emitter, rapidly losing coherence."))
if(do_after(user, 1 SECONDS, TRUE, src))
fold_in()
if(user.put_in_hands(card))
user.visible_message(span_notice("[user] promptly scoops up [user.p_their()] pAI's card."))
else
visible_message(span_danger("[user] stomps on [src]!."))
take_holo_damage(2)
else
if(!user.combat_mode)
visible_message(span_notice("[user] gently pats [src] on the head, eliciting an off-putting buzzing from its holographic field."))
return
user.do_attack_animation(src)
if(user.name != master)
visible_message(span_danger("[user] stomps on [src]!."))
take_holo_damage(2)
return
visible_message(span_notice("Responding to its master's touch, [src] disengages its holochassis emitter, rapidly losing coherence."))
if(!do_after(user, 1 SECONDS, TRUE, src))
return
fold_in()
if(user.put_in_hands(card))
user.visible_message(span_notice("[user] promptly scoops up [user.p_their()] pAI's card."))
/mob/living/silicon/pai/bullet_act(obj/projectile/Proj)
if(Proj.stun)
@@ -61,14 +61,15 @@
src.visible_message(span_warning("The electrically-charged projectile disrupts [src]'s holomatrix, forcing [src] to fold in!"))
. = ..(Proj)
/mob/living/silicon/pai/IgniteMob(mob/living/silicon/pai/P)
return FALSE //No we're not flammable
/mob/living/silicon/pai/IgniteMob()
fire_stacks = 0
. = ..()
/mob/living/silicon/pai/proc/take_holo_damage(amount)
emitterhealth = clamp((emitterhealth - amount), -50, emittermaxhealth)
if(emitterhealth < 0)
fold_in(force = TRUE)
if (amount > 0)
if(amount > 0)
to_chat(src, span_userdanger("The impact degrades your holochassis!"))
return amount
@@ -1,8 +1,2 @@
/mob/living/silicon/pai/say(message, bubble_type, list/spans = list(), sanitize = TRUE, datum/language/language = null, ignore_spam = FALSE, forced = null, filterproof = null)
if(silent)
to_chat(src, span_warning("Communication circuits remain uninitialized."))
else
..()
/mob/living/silicon/pai/binarycheck()
return radio?.translate_binary
@@ -1,11 +1,11 @@
/*
name
key
description
role
comments
ready = 0
*/
/**
* name
* key
* description
* role
* comments
* ready = TRUE
*/
/datum/pai_candidate/proc/savefile_path(mob/user)
return "data/player_saves/[user.ckey[1]]/[user.ckey]/pai.sav"
@@ -24,17 +24,17 @@
// loads the savefile corresponding to the mob's ckey
// if silent=true, report incompatible savefiles
// returns 1 if loaded (or file was incompatible)
// returns 0 if savefile did not exist
// returns TRUE if loaded (or file was incompatible)
// returns FALSE if savefile did not exist
/datum/pai_candidate/proc/savefile_load(mob/user, silent = TRUE)
if (is_guest_key(user.key))
return 0
return FALSE
var/path = savefile_path(user)
if (!fexists(path))
return 0
return FALSE
var/savefile/F = new /savefile(path)
@@ -48,9 +48,9 @@
fdel(path)
if (!silent)
tgui_alert(user, "Your savefile was incompatible with this version and was deleted.")
return 0
return FALSE
F["name"] >> src.name
F["description"] >> src.description
F["comments"] >> src.comments
return 1
return TRUE
+44 -67
View File
@@ -1,35 +1,3 @@
/mob/living/silicon/pai/var/list/available_software = list(
//Nightvision
//T-Ray
//radiation eyes
//chem goggs
//mesons
"crew manifest" = 5,
"digital messenger" = 5,
"atmosphere sensor" = 5,
"photography module" = 5,
"camera zoom" = 10,
"printer module" = 10,
"remote signaler" = 10,
"medical records" = 10,
"security records" = 10,
"host scan" = 10,
"medical HUD" = 20,
"security HUD" = 20,
"loudness booster" = 20,
"newscaster" = 20,
"door jack" = 25,
"encryption keys" = 25,
"internal gps" = 35,
"universal translator" = 35
)
/// Bool that determines if the pAI can refresh medical/security records.
/mob/living/silicon/pai/var/refresh_spam = FALSE
/// Cached list for medical records to send as static data
/mob/living/silicon/pai/var/list/medical_records = list()
/// Cached list for security records to send as static data
/mob/living/silicon/pai/var/list/security_records = list()
// Opens TGUI interface
/mob/living/silicon/pai/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
@@ -124,10 +92,8 @@
if("door_jack")
if(params["jack"] == "jack")
if(hacking_cable?.machine)
hackdoor = hacking_cable.machine
hackloop()
hack_door()
if(params["jack"] == "cancel")
hackdoor = null
QDEL_NULL(hacking_cable)
if(params["jack"] == "cable")
extendcable()
@@ -213,20 +179,20 @@
return
to_chat(pai, span_notice("Requesting a DNA sample."))
var/confirm = tgui_alert(master, "[pai] is requesting a DNA sample from you. Will you allow it to confirm your identity?", "Checking DNA", list("Yes", "No"))
if(confirm == "Yes")
master.visible_message(span_notice("[master] presses [master.p_their()] thumb against [pai]."),\
span_notice("You press your thumb against [pai]."),\
span_notice("[pai] makes a sharp clicking sound as it extracts DNA material from [master]."))
if(!master.has_dna())
to_chat(pai, "<b>No DNA detected.</b>")
return
to_chat(pai, "<font color = red><h3>[master]'s UE string : [master.dna.unique_enzymes]</h3></font>")
if(master.dna.unique_enzymes == pai.master_dna)
to_chat(pai, "<b>DNA is a match to stored Master DNA.</b>")
else
to_chat(pai, "<b>DNA does not match stored Master DNA.</b>")
else
if(confirm != "Yes")
to_chat(pai, span_warning("[master] does not seem like [master.p_theyre()] going to provide a DNA sample willingly."))
return
master.visible_message(span_notice("[master] presses [master.p_their()] thumb against [pai]."),\
span_notice("You press your thumb against [pai]."),\
span_notice("[pai] makes a sharp clicking sound as it extracts DNA material from [master]."))
if(!master.has_dna())
to_chat(pai, "<b>No DNA detected.</b>")
return
to_chat(pai, "<font color = red><h3>[master]'s UE string : [master.dna.unique_enzymes]</h3></font>")
if(master.dna.unique_enzymes == pai.master_dna)
to_chat(pai, span_bold("DNA is a match to stored Master DNA."))
else
to_chat(pai, span_bold("DNA does not match stored Master DNA."))
/**
* Host scan supporting proc
@@ -253,35 +219,46 @@
/mob/living/silicon/pai/proc/extendcable()
QDEL_NULL(hacking_cable) //clear any old cables
hacking_cable = new
var/transfered_to_mob
if(isliving(card.loc))
var/mob/living/hacker = card.loc
if(hacker.put_in_hands(hacking_cable))
transfered_to_mob = TRUE
hacker.visible_message(span_warning("A port on [src] opens to reveal \a [hacking_cable], which you quickly grab hold of."), span_hear("You hear the soft click of something light and manage to catch hold of [hacking_cable]."))
if(!transfered_to_mob)
hacking_cable.forceMove(drop_location())
hacking_cable.visible_message(span_warning("A port on [src] opens to reveal \a [hacking_cable], which promptly falls to the floor."), span_hear("You hear the soft click of something light and hard falling to the ground."))
if(!isliving(card.loc))
return
var/mob/living/hacker = card.loc
if(hacker.put_in_hands(hacking_cable))
hacker.visible_message(span_warning("A port on [src] opens to reveal \a [hacking_cable], which you quickly grab hold of."), span_hear("You hear the soft click of something light and manage to catch hold of [hacking_cable]."))
return
hacking_cable.forceMove(drop_location())
hacking_cable.visible_message(span_warning("A port on [src] opens to reveal \a [hacking_cable], which promptly falls to the floor."), span_hear("You hear the soft click of something light and hard falling to the ground."))
/**
* Door jacking supporting proc
*
* This begins the hacking process on a door.
* Mostly, this gives UI feedback, while the "hack"
* is handled inside pai.dm itself.
* This will, after alerting any AIs on station, begin to hack open a door.
* After a 10 second timer, the door will crack open, provided they don't move out of the way.
*/
/mob/living/silicon/pai/proc/hackloop()
/mob/living/silicon/pai/proc/hack_door()
var/turf/turf = get_turf(src)
playsound(src, 'sound/machines/airlock_alien_prying.ogg', 50, TRUE)
to_chat(usr, span_boldnotice("You begin overriding the airlock security protocols."))
for(var/mob/living/silicon/ai/AI in GLOB.player_list)
for(var/mob/living/silicon/ai/all_ais in GLOB.player_list)
if(!all_ais.stat)
continue
if(turf.loc)
to_chat(AI, "<font color = red><b>Network Alert: Brute-force security override in progress in [turf.loc].</b></font>")
to_chat(all_ais, span_boldannounce("Network Alert: Brute-force security override in progress in [turf.loc]."))
else
to_chat(AI, "<font color = red><b>Network Alert: Brute-force security override in progress. Unable to pinpoint location.</b></font>")
if(!hackbar)
hackbar = new(src, HACK_COMPLETE, hacking_cable.machine)
hacking = TRUE
to_chat(all_ais, span_boldannounce("Network Alert: Brute-force security override in progress. Unable to pinpoint location."))
//Now begin hacking
if(!do_after(src, 10 SECONDS, hacking_cable.machine, timed_action_flags = NONE, progress = TRUE))
to_chat(src, span_notice("Door Jack: Connection to airlock has been lost. Hack aborted."))
hacking_cable.visible_message(
span_warning("[hacking_cable] rapidly retracts back into its spool."),\
span_hear("You hear a click and the sound of wire spooling rapidly."))
QDEL_NULL(hacking_cable)
if(!QDELETED(card))
card.update_appearance()
return
var/obj/machinery/door/door = hacking_cable.machine
door.open()
QDEL_NULL(hacking_cable)
/**
* Proc that switches whether a pAI can refresh
@@ -82,7 +82,7 @@ GLOBAL_LIST_INIT(blacklisted_borg_hats, typecacheof(list( //Hats that don't real
if(shell)
to_chat(user, span_warning("You cannot seem to open the radio compartment!")) //Prevent AI radio key theft
else if(radio)
radio.attackby(W,user)//Push it to the radio to let it handle everything
radio.screwdriver_act(user, W)//Push it to the radio to let it handle everything
else
to_chat(user, span_warning("Unable to locate a radio!"))
update_icons()
@@ -159,7 +159,7 @@ GLOBAL_LIST_INIT(blacklisted_borg_hats, typecacheof(list( //Hats that don't real
MOD.install(laws, user) //Proc includes a success mesage so we don't need another one
return
if(istype(W, /obj/item/encryptionkey/) && opened)
if(istype(W, /obj/item/encryptionkey) && opened)
if(radio)//sanityyyyyy
radio.attackby(W,user)//GTFO, you have your own procs
else
+2 -1
View File
@@ -111,7 +111,6 @@
#include "code\__DEFINES\networks.dm"
#include "code\__DEFINES\nitrile.dm"
#include "code\__DEFINES\obj_flags.dm"
#include "code\__DEFINES\pai.dm"
#include "code\__DEFINES\pinpointers.dm"
#include "code\__DEFINES\pipe_construction.dm"
#include "code\__DEFINES\plumbing.dm"
@@ -3149,7 +3148,9 @@
#include "code\modules\mob\living\silicon\ai\freelook\chunk.dm"
#include "code\modules\mob\living\silicon\ai\freelook\eye.dm"
#include "code\modules\mob\living\silicon\pai\death.dm"
#include "code\modules\mob\living\silicon\pai\login.dm"
#include "code\modules\mob\living\silicon\pai\pai.dm"
#include "code\modules\mob\living\silicon\pai\pai_actions.dm"
#include "code\modules\mob\living\silicon\pai\pai_defense.dm"
#include "code\modules\mob\living\silicon\pai\pai_say.dm"
#include "code\modules\mob\living\silicon\pai\pai_shell.dm"