mirror of
https://github.com/VOREStation/VOREStation.git
synced 2026-08-19 10:07:19 +01:00
504 lines
17 KiB
Plaintext
504 lines
17 KiB
Plaintext
/mob/living/silicon/pai
|
|
name = "pAI"
|
|
icon = 'icons/mob/pai.dmi'
|
|
icon_state = "pai-repairbot"
|
|
|
|
emote_type = 2 // pAIs emotes are heard, not seen, so they can be seen through a container (eg. person)
|
|
pass_flags = 1
|
|
mob_size = MOB_SMALL
|
|
|
|
holder_type = /obj/item/weapon/holder/pai
|
|
|
|
can_pull_size = ITEMSIZE_SMALL
|
|
can_pull_mobs = MOB_PULL_SMALLER
|
|
|
|
idcard_type = /obj/item/weapon/card/id
|
|
var/idaccessible = 0
|
|
|
|
var/network = "SS13"
|
|
var/obj/machinery/camera/current = null
|
|
|
|
var/ram = 100 // Used as currency to purchase different abilities
|
|
var/list/software = list()
|
|
var/userDNA // The DNA string of our assigned user
|
|
var/obj/item/device/paicard/card // The card we inhabit
|
|
var/obj/item/device/radio/radio // Our primary radio
|
|
var/obj/item/device/communicator/integrated/communicator // Our integrated communicator.
|
|
|
|
var/chassis = "pai-repairbot" // A record of your chosen chassis.
|
|
var/global/list/possible_chassis = list(
|
|
"Drone" = "pai-repairbot",
|
|
"Cat" = "pai-cat",
|
|
"Mouse" = "pai-mouse",
|
|
"Monkey" = "pai-monkey",
|
|
"Corgi" = "pai-borgi",
|
|
"Fox" = "pai-fox",
|
|
"Parrot" = "pai-parrot",
|
|
"Rabbit" = "pai-rabbit",
|
|
//VOREStation Addition Start
|
|
"Bear" = "pai-bear",
|
|
"Fennec" = "pai-fen",
|
|
"Type Zero" = "pai-typezero",
|
|
"Raccoon" = "pai-raccoon",
|
|
"Raptor" = "pai-raptor",
|
|
"Rat" = "rat",
|
|
"Panther" = "panther"
|
|
//VOREStation Addition End
|
|
)
|
|
|
|
var/global/list/possible_say_verbs = list(
|
|
"Robotic" = list("states","declares","queries"),
|
|
"Natural" = list("says","yells","asks"),
|
|
"Beep" = list("beeps","beeps loudly","boops"),
|
|
"Chirp" = list("chirps","chirrups","cheeps"),
|
|
"Feline" = list("purrs","yowls","meows"),
|
|
"Canine" = list("yaps","barks","woofs"),
|
|
"Rodent" = list("squeaks", "SQUEAKS", "sqiks") //VOREStation Edit - TFF 22/11/19 - CHOMPStation port of pAI additions,
|
|
)
|
|
|
|
var/obj/item/weapon/pai_cable/cable // The cable we produce and use when door or camera jacking
|
|
|
|
var/master // Name of the one who commands us
|
|
var/master_dna // DNA string for owner verification
|
|
// Keeping this separate from the laws var, it should be much more difficult to modify
|
|
var/pai_law0 = "Serve your master."
|
|
var/pai_laws // String for additional operating instructions our master might give us
|
|
|
|
var/silence_time // Timestamp when we were silenced (normally via EMP burst), set to null after silence has faded
|
|
|
|
// Various software-specific vars
|
|
|
|
var/temp // General error reporting text contained here will typically be shown once and cleared
|
|
var/screen // Which screen our main window displays
|
|
var/subscreen // Which specific function of the main screen is being displayed
|
|
|
|
var/obj/item/device/pda/ai/pai/pda = null
|
|
|
|
var/secHUD = 0 // Toggles whether the Security HUD is active or not
|
|
var/medHUD = 0 // Toggles whether the Medical HUD is active or not
|
|
|
|
var/medical_cannotfind = 0
|
|
var/datum/data/record/medicalActive1 // Datacore record declarations for record software
|
|
var/datum/data/record/medicalActive2
|
|
|
|
var/security_cannotfind = 0
|
|
var/datum/data/record/securityActive1 // Could probably just combine all these into one
|
|
var/datum/data/record/securityActive2
|
|
|
|
var/obj/machinery/door/hackdoor // The airlock being hacked
|
|
var/hackprogress = 0 // Possible values: 0 - 1000, >= 1000 means the hack is complete and will be reset upon next check
|
|
var/hack_aborted = 0
|
|
|
|
var/obj/item/radio/integrated/signal/sradio // AI's signaller
|
|
|
|
var/translator_on = 0 // keeps track of the translator module
|
|
|
|
var/current_pda_messaging = null
|
|
|
|
/mob/living/silicon/pai/New(var/obj/item/device/paicard)
|
|
src.loc = paicard
|
|
card = paicard
|
|
sradio = new(src)
|
|
communicator = new(src)
|
|
if(card)
|
|
if(!card.radio)
|
|
card.radio = new /obj/item/device/radio(src.card)
|
|
radio = card.radio
|
|
|
|
//Default languages without universal translator software
|
|
add_language(LANGUAGE_SOL_COMMON, 1)
|
|
add_language(LANGUAGE_TRADEBAND, 1)
|
|
add_language(LANGUAGE_GUTTER, 1)
|
|
add_language(LANGUAGE_EAL, 1)
|
|
add_language(LANGUAGE_TERMINUS, 1)
|
|
add_language(LANGUAGE_SIGN, 0)
|
|
|
|
verbs += /mob/living/silicon/pai/proc/choose_chassis
|
|
verbs += /mob/living/silicon/pai/proc/choose_verbs
|
|
|
|
//PDA
|
|
pda = new(src)
|
|
spawn(5)
|
|
pda.ownjob = "Personal Assistant"
|
|
pda.owner = text("[]", src)
|
|
pda.name = pda.owner + " (" + pda.ownjob + ")"
|
|
|
|
var/datum/data/pda/app/messenger/M = pda.find_program(/datum/data/pda/app/messenger)
|
|
if(M)
|
|
M.toff = TRUE
|
|
..()
|
|
|
|
/mob/living/silicon/pai/Login()
|
|
..()
|
|
// Vorestation Edit: Meta Info for pAI
|
|
if (client.prefs)
|
|
ooc_notes = client.prefs.metadata
|
|
|
|
|
|
// this function shows the information about being silenced as a pAI in the Status panel
|
|
/mob/living/silicon/pai/proc/show_silenced()
|
|
if(src.silence_time)
|
|
var/timeleft = round((silence_time - world.timeofday)/10 ,1)
|
|
stat(null, "Communications system reboot in -[(timeleft / 60) % 60]:[add_zero(num2text(timeleft % 60), 2)]")
|
|
|
|
|
|
/mob/living/silicon/pai/Stat()
|
|
..()
|
|
statpanel("Status")
|
|
if (src.client.statpanel == "Status")
|
|
show_silenced()
|
|
|
|
/mob/living/silicon/pai/check_eye(var/mob/user as mob)
|
|
if (!src.current)
|
|
return -1
|
|
return 0
|
|
|
|
/mob/living/silicon/pai/restrained()
|
|
if(istype(src.loc,/obj/item/device/paicard))
|
|
return 0
|
|
..()
|
|
|
|
/mob/living/silicon/pai/emp_act(severity)
|
|
// Silence for 2 minutes
|
|
// 20% chance to kill
|
|
// 33% chance to unbind
|
|
// 33% chance to change prime directive (based on severity)
|
|
// 33% chance of no additional effect
|
|
|
|
src.silence_time = world.timeofday + 120 * 10 // Silence for 2 minutes
|
|
to_chat(src, "<font color=green><b>Communication circuit overload. Shutting down and reloading communication circuits - speech and messaging functionality will be unavailable until the reboot is complete.</b></font>")
|
|
if(prob(20))
|
|
var/turf/T = get_turf_or_move(src.loc)
|
|
for (var/mob/M in viewers(T))
|
|
M.show_message("<font color='red'>A shower of sparks spray from [src]'s inner workings.</font>", 3, "<font color='red'>You hear and smell the ozone hiss of electrical sparks being expelled violently.</font>", 2)
|
|
return src.death(0)
|
|
|
|
switch(pick(1,2,3))
|
|
if(1)
|
|
src.master = null
|
|
src.master_dna = null
|
|
to_chat(src, "<font color=green>You feel unbound.</font>")
|
|
if(2)
|
|
var/command
|
|
if(severity == 1)
|
|
command = pick("Serve", "Love", "Fool", "Entice", "Observe", "Judge", "Respect", "Educate", "Amuse", "Entertain", "Glorify", "Memorialize", "Analyze")
|
|
else
|
|
command = pick("Serve", "Kill", "Love", "Hate", "Disobey", "Devour", "Fool", "Enrage", "Entice", "Observe", "Judge", "Respect", "Disrespect", "Consume", "Educate", "Destroy", "Disgrace", "Amuse", "Entertain", "Ignite", "Glorify", "Memorialize", "Analyze")
|
|
src.pai_law0 = "[command] your master."
|
|
to_chat(src, "<font color=green>Pr1m3 d1r3c71v3 uPd473D.</font>")
|
|
if(3)
|
|
to_chat(src, "<font color=green>You feel an electric surge run through your circuitry and become acutely aware at how lucky you are that you can still feel at all.</font>")
|
|
|
|
/mob/living/silicon/pai/proc/switchCamera(var/obj/machinery/camera/C)
|
|
if (!C)
|
|
src.unset_machine()
|
|
src.reset_view(null)
|
|
return 0
|
|
if (stat == 2 || !C.status || !(src.network in C.network)) return 0
|
|
|
|
// ok, we're alive, camera is good and in our network...
|
|
|
|
src.set_machine(src)
|
|
src.current = C
|
|
src.reset_view(C)
|
|
return 1
|
|
|
|
/mob/living/silicon/pai/verb/reset_record_view()
|
|
set category = "pAI Commands"
|
|
set name = "Reset Records Software"
|
|
|
|
securityActive1 = null
|
|
securityActive2 = null
|
|
security_cannotfind = 0
|
|
medicalActive1 = null
|
|
medicalActive2 = null
|
|
medical_cannotfind = 0
|
|
SStgui.update_uis(src)
|
|
to_chat(usr, "<span class='notice'>You reset your record-viewing software.</span>")
|
|
|
|
/mob/living/silicon/pai/cancel_camera()
|
|
set category = "pAI Commands"
|
|
set name = "Cancel Camera View"
|
|
src.reset_view(null)
|
|
src.unset_machine()
|
|
src.cameraFollow = null
|
|
|
|
//Addition by Mord_Sith to define AI's network change ability
|
|
/*
|
|
/mob/living/silicon/pai/proc/pai_network_change()
|
|
set category = "pAI Commands"
|
|
set name = "Change Camera Network"
|
|
src.reset_view(null)
|
|
src.unset_machine()
|
|
src.cameraFollow = null
|
|
var/cameralist[0]
|
|
|
|
if(usr.stat == 2)
|
|
to_chat(usr, "You can't change your camera network because you are dead!")
|
|
return
|
|
|
|
for (var/obj/machinery/camera/C in Cameras)
|
|
if(!C.status)
|
|
continue
|
|
else
|
|
if(C.network != "CREED" && C.network != "thunder" && C.network != "RD" && C.network != "phoron" && C.network != "Prison") COMPILE ERROR! This will have to be updated as camera.network is no longer a string, but a list instead
|
|
cameralist[C.network] = C.network
|
|
|
|
src.network = input(usr, "Which network would you like to view?") as null|anything in cameralist
|
|
to_chat(src, "<font color='blue'>Switched to [src.network] camera network.</font>")
|
|
//End of code by Mord_Sith
|
|
*/
|
|
|
|
|
|
/*
|
|
// Debug command - Maybe should be added to admin verbs later
|
|
/mob/verb/makePAI(var/turf/t in view())
|
|
var/obj/item/device/paicard/card = new(t)
|
|
var/mob/living/silicon/pai/pai = new(card)
|
|
pai.key = src.key
|
|
card.setPersonality(pai)
|
|
|
|
*/
|
|
|
|
// Procs/code after this point is used to convert the stationary pai item into a
|
|
// mobile pai mob. This also includes handling some of the general shit that can occur
|
|
// to it. Really this deserves its own file, but for the moment it can sit here. ~ Z
|
|
|
|
/mob/living/silicon/pai/verb/fold_out()
|
|
set category = "pAI Commands"
|
|
set name = "Unfold Chassis"
|
|
|
|
if(stat || sleeping || paralysis || weakened)
|
|
return
|
|
|
|
if(src.loc != card)
|
|
return
|
|
|
|
if(world.time <= last_special)
|
|
return
|
|
|
|
last_special = world.time + 100
|
|
|
|
//I'm not sure how much of this is necessary, but I would rather avoid issues.
|
|
if(istype(card.loc,/obj/item/rig_module))
|
|
to_chat(src, "There is no room to unfold inside this rig module. You're good and stuck.")
|
|
return 0
|
|
else if(istype(card.loc,/mob))
|
|
var/mob/holder = card.loc
|
|
var/datum/belly/inside_belly = check_belly(card) //VOREStation edit.
|
|
if(inside_belly) //VOREStation edit.
|
|
to_chat(src, "<span class='notice'>There is no room to unfold in here. You're good and stuck.</span>") //VOREStation edit.
|
|
return 0 //VOREStation edit.
|
|
if(ishuman(holder))
|
|
var/mob/living/carbon/human/H = holder
|
|
for(var/obj/item/organ/external/affecting in H.organs)
|
|
if(card in affecting.implants)
|
|
affecting.take_damage(rand(30,50))
|
|
affecting.implants -= card
|
|
H.visible_message("<span class='danger'>\The [src] explodes out of \the [H]'s [affecting.name] in shower of gore!</span>")
|
|
break
|
|
holder.drop_from_inventory(card)
|
|
else if(istype(card.loc,/obj/item/device/pda))
|
|
var/obj/item/device/pda/holder = card.loc
|
|
holder.pai = null
|
|
|
|
src.client.perspective = EYE_PERSPECTIVE
|
|
src.client.eye = src
|
|
src.forceMove(get_turf(card))
|
|
|
|
card.forceMove(src)
|
|
card.screen_loc = null
|
|
|
|
var/turf/T = get_turf(src)
|
|
if(istype(T)) T.visible_message("<b>[src]</b> folds outwards, expanding into a mobile form.")
|
|
verbs += /mob/living/silicon/pai/proc/pai_nom //VOREStation edit
|
|
verbs += /mob/living/proc/set_size //VOREStation edit
|
|
verbs += /mob/living/proc/shred_limb //VORREStation edit
|
|
|
|
/mob/living/silicon/pai/verb/fold_up()
|
|
set category = "pAI Commands"
|
|
set name = "Collapse Chassis"
|
|
|
|
if(stat || sleeping || paralysis || weakened)
|
|
return
|
|
|
|
if(src.loc == card)
|
|
return
|
|
|
|
if(world.time <= last_special)
|
|
return
|
|
|
|
close_up()
|
|
|
|
//VOREStation Removal Start - TFF 22/11/19 - Refactored in pai_vr.dm
|
|
/*
|
|
/mob/living/silicon/pai/proc/choose_chassis()
|
|
set category = "pAI Commands"
|
|
set name = "Choose Chassis"
|
|
|
|
var/choice
|
|
var/finalized = "No"
|
|
while(finalized == "No" && src.client)
|
|
|
|
choice = input(usr,"What would you like to use for your mobile chassis icon?") as null|anything in possible_chassis
|
|
if(!choice) return
|
|
|
|
icon_state = possible_chassis[choice]
|
|
finalized = alert("Look at your sprite. Is this what you wish to use?",,"No","Yes")
|
|
|
|
chassis = possible_chassis[choice]
|
|
verbs |= /mob/living/proc/hide
|
|
//VOREStation Removal End
|
|
*/
|
|
|
|
/mob/living/silicon/pai/proc/choose_verbs()
|
|
set category = "pAI Commands"
|
|
set name = "Choose Speech Verbs"
|
|
|
|
var/choice = input(usr,"What theme would you like to use for your speech verbs?") as null|anything in possible_say_verbs
|
|
if(!choice) return
|
|
|
|
var/list/sayverbs = possible_say_verbs[choice]
|
|
speak_statement = sayverbs[1]
|
|
speak_exclamation = sayverbs[(sayverbs.len>1 ? 2 : sayverbs.len)]
|
|
speak_query = sayverbs[(sayverbs.len>2 ? 3 : sayverbs.len)]
|
|
|
|
/mob/living/silicon/pai/lay_down()
|
|
set name = "Rest"
|
|
set category = "IC"
|
|
|
|
// Pass lying down or getting up to our pet human, if we're in a rig.
|
|
if(istype(src.loc,/obj/item/device/paicard))
|
|
resting = 0
|
|
var/obj/item/weapon/rig/rig = src.get_rig()
|
|
if(istype(rig))
|
|
rig.force_rest(src)
|
|
else
|
|
resting = !resting
|
|
icon_state = resting ? "[chassis]_rest" : "[chassis]"
|
|
update_icon() //VOREStation edit
|
|
to_chat(src, "<span class='notice'>You are now [resting ? "resting" : "getting up"]</span>")
|
|
|
|
canmove = !resting
|
|
|
|
//Overriding this will stop a number of headaches down the track.
|
|
/mob/living/silicon/pai/attackby(obj/item/weapon/W as obj, mob/user as mob)
|
|
if(W.force)
|
|
visible_message("<span class='danger'>[user.name] attacks [src] with [W]!</span>")
|
|
src.adjustBruteLoss(W.force)
|
|
src.updatehealth()
|
|
else
|
|
visible_message("<span class='warning'>[user.name] bonks [src] harmlessly with [W].</span>")
|
|
spawn(1)
|
|
if(stat != 2) close_up()
|
|
return
|
|
|
|
/mob/living/silicon/pai/attack_hand(mob/user as mob)
|
|
if(user.a_intent == I_HELP)
|
|
visible_message("<span class='notice'>[user.name] pats [src].</span>")
|
|
else
|
|
visible_message("<span class='danger'>[user.name] boops [src] on the head.</span>")
|
|
close_up()
|
|
|
|
//I'm not sure how much of this is necessary, but I would rather avoid issues.
|
|
/mob/living/silicon/pai/proc/close_up()
|
|
|
|
last_special = world.time + 100
|
|
|
|
if(src.loc == card)
|
|
return
|
|
|
|
release_vore_contents() //VOREStation Add
|
|
|
|
var/turf/T = get_turf(src)
|
|
if(istype(T)) T.visible_message("<b>[src]</b> neatly folds inwards, compacting down to a rectangular card.")
|
|
|
|
if(client)
|
|
src.stop_pulling()
|
|
src.client.perspective = EYE_PERSPECTIVE
|
|
src.client.eye = card
|
|
|
|
//stop resting
|
|
resting = 0
|
|
|
|
// If we are being held, handle removing our holder from their inv.
|
|
var/obj/item/weapon/holder/H = loc
|
|
if(istype(H))
|
|
var/mob/living/M = H.loc
|
|
if(istype(M))
|
|
M.drop_from_inventory(H)
|
|
H.loc = get_turf(src)
|
|
src.loc = get_turf(H)
|
|
|
|
// Move us into the card and move the card to the ground.
|
|
src.loc = card
|
|
card.loc = get_turf(card)
|
|
src.forceMove(card)
|
|
card.forceMove(card.loc)
|
|
canmove = 1
|
|
resting = 0
|
|
icon_state = "[chassis]"
|
|
verbs -= /mob/living/silicon/pai/proc/pai_nom //VOREStation edit. Let's remove their nom verb
|
|
|
|
// No binary for pAIs.
|
|
/mob/living/silicon/pai/binarycheck()
|
|
return 0
|
|
|
|
// Handle being picked up.
|
|
/mob/living/silicon/pai/get_scooped(var/mob/living/carbon/grabber, var/self_drop)
|
|
var/obj/item/weapon/holder/H = ..(grabber, self_drop)
|
|
if(!istype(H))
|
|
return
|
|
|
|
H.icon_state = "[chassis]"
|
|
grabber.update_inv_l_hand()
|
|
grabber.update_inv_r_hand()
|
|
return H
|
|
|
|
/mob/living/silicon/pai/attackby(obj/item/weapon/W as obj, mob/user as mob)
|
|
var/obj/item/weapon/card/id/ID = W.GetID()
|
|
if(ID)
|
|
if (idaccessible == 1)
|
|
switch(alert(user, "Do you wish to add access to [src] or remove access from [src]?",,"Add Access","Remove Access", "Cancel"))
|
|
if("Add Access")
|
|
idcard.access |= ID.access
|
|
to_chat(user, "<span class='notice'>You add the access from the [W] to [src].</span>")
|
|
return
|
|
if("Remove Access")
|
|
idcard.access = list()
|
|
to_chat(user, "<span class='notice'>You remove the access from [src].</span>")
|
|
return
|
|
if("Cancel")
|
|
return
|
|
else if (istype(W, /obj/item/weapon/card/id) && idaccessible == 0)
|
|
to_chat(user, "<span class='notice'>[src] is not accepting access modifcations at this time.</span>")
|
|
return
|
|
|
|
/mob/living/silicon/pai/verb/allowmodification()
|
|
set name = "Change Access Modifcation Permission"
|
|
set category = "pAI Commands"
|
|
set desc = "Allows people to modify your access or block people from modifying your access."
|
|
|
|
if(idaccessible == 0)
|
|
idaccessible = 1
|
|
to_chat(src, "<span class='notice'>You allow access modifications.</span>")
|
|
|
|
else
|
|
idaccessible = 0
|
|
to_chat(src, "<span class='notice'>You block access modfications.</span>")
|
|
|
|
/mob/living/silicon/pai/verb/wipe_software()
|
|
set name = "Wipe Software"
|
|
set category = "OOC"
|
|
set desc = "Wipe your software. This is functionally equivalent to cryo or robotic storage, freeing up your job slot."
|
|
|
|
// Make sure people don't kill themselves accidentally
|
|
if(alert("WARNING: This will immediately wipe your software and ghost you, removing your character from the round permanently (similar to cryo and robotic storage). Are you entirely sure you want to do this?",
|
|
"Wipe Software", "No", "No", "Yes") != "Yes")
|
|
return
|
|
|
|
close_up()
|
|
visible_message("<b>[src]</b> fades away from the screen, the pAI device goes silent.")
|
|
card.removePersonality()
|
|
clear_client()
|