initial commit - cross reference with 5th port - obviously has compile errors

This commit is contained in:
LetterJay
2016-07-03 02:17:19 -05:00
commit 35a1723e98
4355 changed files with 2221257 additions and 0 deletions
+900
View File
@@ -0,0 +1,900 @@
var/list/ai_list = list()
//Not sure why this is necessary...
/proc/AutoUpdateAI(obj/subject)
var/is_in_use = 0
if (subject!=null)
for(var/A in ai_list)
var/mob/living/silicon/ai/M = A
if ((M.client && M.machine == subject))
is_in_use = 1
subject.attack_ai(M)
return is_in_use
/mob/living/silicon/ai
name = "AI"
icon = 'icons/mob/AI.dmi'//
icon_state = "ai"
anchored = 1
density = 1
status_flags = CANSTUN|CANPUSH
force_compose = 1 //This ensures that the AI always composes it's own hear message. Needed for hrefs and job display.
sight = SEE_TURFS | SEE_MOBS | SEE_OBJS
see_in_dark = 8
med_hud = DATA_HUD_MEDICAL_BASIC
sec_hud = DATA_HUD_SECURITY_BASIC
mob_size = MOB_SIZE_LARGE
var/list/network = list("SS13")
var/obj/machinery/camera/current = null
var/list/connected_robots = list()
var/aiRestorePowerRoutine = 0
//var/list/laws = list()
var/alarms = list("Motion"=list(), "Fire"=list(), "Atmosphere"=list(), "Power"=list(), "Camera"=list(), "Burglar"=list())
var/viewalerts = 0
var/icon/holo_icon//Default is assigned when AI is created.
var/obj/mecha/controlled_mech //For controlled_mech a mech, to determine whether to relaymove or use the AI eye.
var/radio_enabled = 1 //Determins if a carded AI can speak with its built in radio or not.
radiomod = ";" //AIs will, by default, state their laws on the internal radio.
var/obj/item/device/pda/ai/aiPDA = null
var/obj/item/device/multitool/aiMulti = null
var/mob/living/simple_animal/bot/Bot
var/tracking = 0 //this is 1 if the AI is currently tracking somebody, but the track has not yet been completed.
var/datum/effect_system/spark_spread/spark_system//So they can initialize sparks whenever/N
//MALFUNCTION
var/datum/module_picker/malf_picker
var/list/datum/AI_Module/current_modules = list()
var/fire_res_on_core = 0
var/can_dominate_mechs = 0
var/shunted = 0 //1 if the AI is currently shunted. Used to differentiate between shunted and ghosted/braindead
var/control_disabled = 0 // Set to 1 to stop AI from interacting via Click()
var/malfhacking = 0 // More or less a copy of the above var, so that malf AIs can hack and still get new cyborgs -- NeoFite
var/malf_cooldown = 0 //Cooldown var for malf modules
var/obj/machinery/power/apc/malfhack = null
var/explosive = 0 //does the AI explode when it dies?
var/mob/living/silicon/ai/parent = null
var/camera_light_on = 0
var/list/obj/machinery/camera/lit_cameras = list()
var/datum/trackable/track = new()
var/last_paper_seen = null
var/can_shunt = 1
var/last_announcement = "" // For AI VOX, if enabled
var/turf/waypoint //Holds the turf of the currently selected waypoint.
var/waypoint_mode = 0 //Waypoint mode is for selecting a turf via clicking.
var/apc_override = 0 //hack for letting the AI use its APC even when visionless
var/nuking = FALSE
var/obj/machinery/doomsday_device/doomsday_device
var/mob/camera/aiEye/eyeobj = new()
var/sprint = 10
var/cooldown = 0
var/acceleration = 1
var/obj/machinery/camera/portable/builtInCamera
/mob/living/silicon/ai/New(loc, var/datum/ai_laws/L, var/obj/item/device/mmi/B, var/safety = 0)
..()
rename_self("ai")
name = real_name
anchored = 1
canmove = 0
density = 1
loc = loc
holo_icon = getHologramIcon(icon('icons/mob/AI.dmi',"holo1"))
spark_system = new /datum/effect_system/spark_spread()
spark_system.set_up(5, 0, src)
spark_system.attach(src)
if(L)
if (istype(L, /datum/ai_laws))
laws = L
else
make_laws()
verbs += /mob/living/silicon/ai/proc/show_laws_verb
aiPDA = new/obj/item/device/pda/ai(src)
aiPDA.owner = name
aiPDA.ownjob = "AI"
aiPDA.name = name + " (" + aiPDA.ownjob + ")"
aiMulti = new(src)
radio = new /obj/item/device/radio/headset/ai(src)
aicamera = new/obj/item/device/camera/siliconcam/ai_camera(src)
if (istype(loc, /turf))
verbs.Add(/mob/living/silicon/ai/proc/ai_network_change, \
/mob/living/silicon/ai/proc/ai_statuschange, /mob/living/silicon/ai/proc/ai_hologram_change, \
/mob/living/silicon/ai/proc/toggle_camera_light, /mob/living/silicon/ai/proc/botcall,\
/mob/living/silicon/ai/proc/control_integrated_radio, /mob/living/silicon/ai/proc/set_automatic_say_channel)
if(!safety)//Only used by AIize() to successfully spawn an AI.
if (!B)//If there is no player/brain inside.
new/obj/structure/AIcore/deactivated(loc)//New empty terminal.
qdel(src)//Delete AI.
return
else
if (B.brainmob.mind)
B.brainmob.mind.transfer_to(src)
rename_self("ai")
if(mind.special_role)
mind.store_memory("As an AI, you must obey your silicon laws above all else. Your objectives will consider you to be dead.")
src << "<span class='userdanger'>You have been installed as an AI! </span>"
src << "<span class='danger'>You must obey your silicon laws above all else. Your objectives will consider you to be dead.</span>"
src << "<B>You are playing the station's AI. The AI cannot move, but can interact with many objects while viewing them (through cameras).</B>"
src << "<B>To look at other parts of the station, click on yourself to get a camera menu.</B>"
src << "<B>While observing through a camera, you can use most (networked) devices which you can see, such as computers, APCs, intercoms, doors, etc.</B>"
src << "To use something, simply click on it."
src << "Use say :b to speak to your cyborgs through binary."
src << "For department channels, use the following say commands:"
src << ":o - AI Private, :c - Command, :s - Security, :e - Engineering, :u - Supply, :v - Service, :m - Medical, :n - Science."
show_laws()
src << "<b>These laws may be changed by other players, or by you being the traitor.</b>"
job = "AI"
ai_list += src
shuttle_caller_list += src
eyeobj.ai = src
eyeobj.name = "[src.name] (AI Eye)" // Give it a name
eyeobj.loc = src.loc
builtInCamera = new /obj/machinery/camera/portable(src)
builtInCamera.network = list("SS13")
/mob/living/silicon/ai/Destroy()
ai_list -= src
shuttle_caller_list -= src
SSshuttle.autoEvac()
qdel(eyeobj) // No AI, no Eye
return ..()
/mob/living/silicon/ai/verb/pick_icon()
set category = "AI Commands"
set name = "Set AI Core Display"
if(stat || aiRestorePowerRoutine)
return
//if(icon_state == initial(icon_state))
var/icontype = input("Please, select a display!", "AI", null/*, null*/) in list("Clown", "Monochrome", "Blue", "Inverted", "Firewall", "Green", "Red", "Static", "Red October", "House", "Heartline", "Hades", "Helios", "President", "Syndicat Meow", "Alien", "Too Deep", "Triumvirate", "Triumvirate-M", "Text", "Matrix", "Dorf", "Bliss", "Not Malf", "Fuzzy", "Goon", "Database", "Glitchman", "Murica", "Nanotrasen", "Gentoo", "Angel")
if(icontype == "Clown")
icon_state = "ai-clown2"
else if(icontype == "Monochrome")
icon_state = "ai-mono"
else if(icontype == "Blue")
icon_state = "ai"
else if(icontype == "Inverted")
icon_state = "ai-u"
else if(icontype == "Firewall")
icon_state = "ai-magma"
else if(icontype == "Green")
icon_state = "ai-wierd"
else if(icontype == "Red")
icon_state = "ai-malf"
else if(icontype == "Static")
icon_state = "ai-static"
else if(icontype == "Red October")
icon_state = "ai-redoctober"
else if(icontype == "House")
icon_state = "ai-house"
else if(icontype == "Heartline")
icon_state = "ai-heartline"
else if(icontype == "Hades")
icon_state = "ai-hades"
else if(icontype == "Helios")
icon_state = "ai-helios"
else if(icontype == "President")
icon_state = "ai-pres"
else if(icontype == "Syndicat Meow")
icon_state = "ai-syndicatmeow"
else if(icontype == "Alien")
icon_state = "ai-alien"
else if(icontype == "Too Deep")
icon_state = "ai-toodeep"
else if(icontype == "Triumvirate")
icon_state = "ai-triumvirate"
else if(icontype == "Triumvirate-M")
icon_state = "ai-triumvirate-malf"
else if(icontype == "Text")
icon_state = "ai-text"
else if(icontype == "Matrix")
icon_state = "ai-matrix"
else if(icontype == "Dorf")
icon_state = "ai-dorf"
else if(icontype == "Bliss")
icon_state = "ai-bliss"
else if(icontype == "Not Malf")
icon_state = "ai-notmalf"
else if(icontype == "Fuzzy")
icon_state = "ai-fuzz"
else if(icontype == "Goon")
icon_state = "ai-goon"
else if(icontype == "Database")
icon_state = "ai-database"
else if(icontype == "Glitchman")
icon_state = "ai-glitchman"
else if(icontype == "Murica")
icon_state = "ai-murica"
else if(icontype == "Nanotrasen")
icon_state = "ai-nanotrasen"
else if(icontype == "Gentoo")
icon_state = "ai-gentoo"
else if(icontype == "Angel")
icon_state = "ai-angel"
//else
//usr <<"You can only change your display once!"
//return
/mob/living/silicon/ai/Stat()
..()
if(statpanel("Status"))
if(!stat)
stat(null, text("System integrity: [(health+100)/2]%"))
stat(null, "Station Time: [worldtime2text()]")
stat(null, text("Connected cyborgs: [connected_robots.len]"))
var/area/borg_area
for(var/mob/living/silicon/robot/R in connected_robots)
borg_area = get_area(R)
var/robot_status = "Nominal"
if(R.stat || !R.client)
robot_status = "OFFLINE"
else if(!R.cell || R.cell.charge <= 0)
robot_status = "DEPOWERED"
//Name, Health, Battery, Module, Area, and Status! Everything an AI wants to know about its borgies!
stat(null, text("[R.name] | S.Integrity: [R.health]% | Cell: [R.cell ? "[R.cell.charge]/[R.cell.maxcharge]" : "Empty"] | \
Module: [R.designation] | Loc: [borg_area.name] | Status: [robot_status]"))
else
stat(null, text("Systems nonfunctional"))
/mob/living/silicon/ai/proc/ai_alerts()
var/dat = "<HEAD><TITLE>Current Station Alerts</TITLE><META HTTP-EQUIV='Refresh' CONTENT='10'></HEAD><BODY>\n"
dat += "<A HREF='?src=\ref[src];mach_close=aialerts'>Close</A><BR><BR>"
for (var/cat in alarms)
dat += text("<B>[]</B><BR>\n", cat)
var/list/L = alarms[cat]
if (L.len)
for (var/alarm in L)
var/list/alm = L[alarm]
var/area/A = alm[1]
var/C = alm[2]
var/list/sources = alm[3]
dat += "<NOBR>"
if (C && istype(C, /list))
var/dat2 = ""
for (var/obj/machinery/camera/I in C)
dat2 += text("[]<A HREF=?src=\ref[];switchcamera=\ref[]>[]</A>", (dat2=="") ? "" : " | ", src, I, I.c_tag)
dat += text("-- [] ([])", A.name, (dat2!="") ? dat2 : "No Camera")
else if (C && istype(C, /obj/machinery/camera))
var/obj/machinery/camera/Ctmp = C
dat += text("-- [] (<A HREF=?src=\ref[];switchcamera=\ref[]>[]</A>)", A.name, src, C, Ctmp.c_tag)
else
dat += text("-- [] (No Camera)", A.name)
if (sources.len > 1)
dat += text("- [] sources", sources.len)
dat += "</NOBR><BR>\n"
else
dat += "-- All Systems Nominal<BR>\n"
dat += "<BR>\n"
viewalerts = 1
src << browse(dat, "window=aialerts&can_close=0")
/mob/living/silicon/ai/proc/ai_roster()
var/dat = "<html><head><title>Crew Roster</title></head><body><b>Crew Roster:</b><br><br>"
for(var/datum/data/record/t in sortRecord(data_core.general))
dat += t.fields["name"] + " - " + t.fields["rank"] + "<br>"
dat += "</body></html>"
src << browse(dat, "window=airoster")
onclose(src, "airoster")
/mob/living/silicon/ai/proc/ai_call_shuttle()
if(stat == DEAD)
return //won't work if dead
if(istype(usr,/mob/living/silicon/ai))
var/mob/living/silicon/ai/AI = src
if(AI.control_disabled)
usr << "Wireless control is disabled!"
return
var/reason = input(src, "What is the nature of your emergency? ([CALL_SHUTTLE_REASON_LENGTH] characters required.)", "Confirm Shuttle Call") as null|text
if(trim(reason))
SSshuttle.requestEvac(src, reason)
// hack to display shuttle timer
if(!EMERGENCY_IDLE_OR_RECALLED)
var/obj/machinery/computer/communications/C = locate() in machines
if(C)
C.post_status("shuttle")
return
/mob/living/silicon/ai/cancel_camera()
src.view_core()
/mob/living/silicon/ai/verb/toggle_anchor()
set category = "AI Commands"
set name = "Toggle Floor Bolts"
if(!isturf(loc)) // if their location isn't a turf
return // stop
if(stat == DEAD)
return //won't work if dead
anchored = !anchored // Toggles the anchor
src << "[anchored ? "<b>You are now anchored.</b>" : "<b>You are now unanchored.</b>"]"
// the message in the [] will change depending whether or not the AI is anchored
/mob/living/silicon/ai/update_canmove() //If the AI dies, mobs won't go through it anymore
return 0
/mob/living/silicon/ai/proc/ai_cancel_call()
set category = "Malfunction"
if(stat == DEAD)
return //won't work if dead
if(istype(usr,/mob/living/silicon/ai))
var/mob/living/silicon/ai/AI = src
if(AI.control_disabled)
src << "Wireless control is disabled!"
return
SSshuttle.cancelEvac(src)
return
/mob/living/silicon/ai/blob_act(obj/effect/blob/B)
if (stat != DEAD)
adjustBruteLoss(60)
updatehealth()
return 1
return 0
/mob/living/silicon/ai/restrained(ignore_grab)
. = 0
/mob/living/silicon/ai/emp_act(severity)
if (prob(30))
switch(pick(1,2))
if(1)
view_core()
if(2)
SSshuttle.requestEvac(src,"ALERT: Energy surge detected in AI core! Station integrity may be compromised! Initiati--%m091#ar-BZZT")
..()
/mob/living/silicon/ai/ex_act(severity, target)
..()
switch(severity)
if(1)
gib()
if(2)
if (stat != DEAD)
adjustBruteLoss(60)
adjustFireLoss(60)
if(3)
if (stat != DEAD)
adjustBruteLoss(30)
return
/mob/living/silicon/ai/Topic(href, href_list)
if(usr != src)
return
..()
if (href_list["mach_close"])
if (href_list["mach_close"] == "aialerts")
viewalerts = 0
var/t1 = text("window=[]", href_list["mach_close"])
unset_machine()
src << browse(null, t1)
if (href_list["switchcamera"])
switchCamera(locate(href_list["switchcamera"])) in cameranet.cameras
if (href_list["showalerts"])
ai_alerts()
#ifdef AI_VOX
if(href_list["say_word"])
play_vox_word(href_list["say_word"], null, src)
return
#endif
if(href_list["show_paper"])
if(last_paper_seen)
src << browse(last_paper_seen, "window=show_paper")
//Carn: holopad requests
if(href_list["jumptoholopad"])
var/obj/machinery/hologram/holopad/H = locate(href_list["jumptoholopad"])
if(stat == CONSCIOUS)
if(H)
H.attack_ai(src) //may as well recycle
else
src << "<span class='notice'>Unable to locate the holopad.</span>"
if(href_list["track"])
var/string = href_list["track"]
trackable_mobs()
var/list/trackeable = list()
trackeable += track.humans + track.others
var/list/target = list()
for(var/I in trackeable)
var/mob/M = trackeable[I]
if(M.name == string)
target += M
if(name == string)
target += src
if(target.len)
ai_actual_track(pick(target))
else
src << "Target is not on or near any active cameras on the station."
return
if(href_list["callbot"]) //Command a bot to move to a selected location.
Bot = locate(href_list["callbot"]) in living_mob_list
if(!Bot || Bot.remote_disabled || src.control_disabled)
return //True if there is no bot found, the bot is manually emagged, or the AI is carded with wireless off.
waypoint_mode = 1
src << "<span class='notice'>Set your waypoint by clicking on a valid location free of obstructions.</span>"
return
if(href_list["interface"]) //Remotely connect to a bot!
Bot = locate(href_list["interface"]) in living_mob_list
if(!Bot || Bot.remote_disabled || src.control_disabled)
return
Bot.attack_ai(src)
if(href_list["botrefresh"]) //Refreshes the bot control panel.
botcall()
return
if (href_list["ai_take_control"]) //Mech domination
var/obj/mecha/M = locate(href_list["ai_take_control"])
if(controlled_mech)
src << "You are already loaded into an onboard computer!"
return
if(M)
M.transfer_ai(AI_MECH_HACK,src, usr) //Called om the mech itself.
/mob/living/silicon/ai/bullet_act(obj/item/projectile/Proj)
..(Proj)
updatehealth()
return 2
/mob/living/silicon/ai/attack_alien(mob/living/carbon/alien/humanoid/M)
if(!ticker || !ticker.mode)
M << "You cannot attack people before the game has started."
return
..()
return
/mob/living/silicon/ai/proc/switchCamera(obj/machinery/camera/C)
if(!tracking)
cameraFollow = null
if (!C || stat == DEAD) //C.can_use())
return 0
if(!src.eyeobj)
view_core()
return
// ok, we're alive, camera is good and in our network...
eyeobj.setLoc(get_turf(C))
//machine = src
return 1
/mob/living/silicon/ai/proc/botcall()
set category = "AI Commands"
set name = "Access Robot Control"
set desc = "Wirelessly control various automatic robots."
if(stat == 2)
return //won't work if dead
if(control_disabled)
src << "Wireless communication is disabled."
return
var/turf/ai_current_turf = get_turf(src)
var/ai_Zlevel = ai_current_turf.z
var/d
var/area/bot_area
d += "<A HREF=?src=\ref[src];botrefresh=1>Query network status</A><br>"
d += "<table width='100%'><tr><td width='40%'><h3>Name</h3></td><td width='30%'><h3>Status</h3></td><td width='30%'><h3>Location</h3></td><td width='10%'><h3>Control</h3></td></tr>"
for (Bot in living_mob_list)
if(Bot.z == ai_Zlevel && !Bot.remote_disabled) //Only non-emagged bots on the same Z-level are detected!
bot_area = get_area(Bot)
var/bot_mode = Bot.get_mode()
d += "<tr><td width='30%'>[Bot.hacked ? "<span class='bad'>(!)</span>" : ""] [Bot.name]</A> ([Bot.model])</td>"
//If the bot is on, it will display the bot's current mode status. If the bot is not mode, it will just report "Idle". "Inactive if it is not on at all.
d += "<td width='30%'>[bot_mode]</td>"
d += "<td width='30%'>[bot_area.name]</td>"
d += "<td width='10%'><A HREF=?src=\ref[src];interface=\ref[Bot]>Interface</A></td>"
d += "<td width='10%'><A HREF=?src=\ref[src];callbot=\ref[Bot]>Call</A></td>"
d += "</tr>"
d = format_text(d)
var/datum/browser/popup = new(src, "botcall", "Remote Robot Control", 700, 400)
popup.set_content(d)
popup.open()
/mob/living/silicon/ai/proc/set_waypoint(atom/A)
var/turf/turf_check = get_turf(A)
//The target must be in view of a camera or near the core.
if(turf_check in range(get_turf(src)))
call_bot(turf_check)
else if(cameranet && cameranet.checkTurfVis(turf_check))
call_bot(turf_check)
else
src << "<span class='danger'>Selected location is not visible.</span>"
/mob/living/silicon/ai/proc/call_bot(turf/waypoint)
if(!Bot)
return
if(Bot.calling_ai && Bot.calling_ai != src) //Prevents an override if another AI is controlling this bot.
src << "<span class='danger'>Interface error. Unit is already in use.</span>"
return
Bot.call_bot(src, waypoint)
/mob/living/silicon/ai/triggerAlarm(class, area/A, O, obj/alarmsource)
if(alarmsource.z != z)
return
if (stat == 2)
return 1
var/list/L = alarms[class]
for (var/I in L)
if (I == A.name)
var/list/alarm = L[I]
var/list/sources = alarm[3]
if (!(alarmsource in sources))
sources += alarmsource
return 1
var/obj/machinery/camera/C = null
var/list/CL = null
if (O && istype(O, /list))
CL = O
if (CL.len == 1)
C = CL[1]
else if (O && istype(O, /obj/machinery/camera))
C = O
L[A.name] = list(A, (C) ? C : O, list(alarmsource))
if (O)
if (C && C.can_use())
queueAlarm("--- [class] alarm detected in [A.name]! (<A HREF=?src=\ref[src];switchcamera=\ref[C]>[C.c_tag]</A>)", class)
else if (CL && CL.len)
var/foo = 0
var/dat2 = ""
for (var/obj/machinery/camera/I in CL)
dat2 += text("[]<A HREF=?src=\ref[];switchcamera=\ref[]>[]</A>", (!foo) ? "" : " | ", src, I, I.c_tag) //I'm not fixing this shit...
foo = 1
queueAlarm(text ("--- [] alarm detected in []! ([])", class, A.name, dat2), class)
else
queueAlarm(text("--- [] alarm detected in []! (No Camera)", class, A.name), class)
else
queueAlarm(text("--- [] alarm detected in []! (No Camera)", class, A.name), class)
if (viewalerts) ai_alerts()
return 1
/mob/living/silicon/ai/cancelAlarm(class, area/A, obj/origin)
var/list/L = alarms[class]
var/cleared = 0
for (var/I in L)
if (I == A.name)
var/list/alarm = L[I]
var/list/srcs = alarm[3]
if (origin in srcs)
srcs -= origin
if (srcs.len == 0)
cleared = 1
L -= I
if (cleared)
queueAlarm("--- [class] alarm in [A.name] has been cleared.", class, 0)
if (viewalerts) ai_alerts()
return !cleared
//Replaces /mob/living/silicon/ai/verb/change_network() in ai.dm & camera.dm
//Adds in /mob/living/silicon/ai/proc/ai_network_change() instead
//Addition by Mord_Sith to define AI's network change ability
/mob/living/silicon/ai/proc/ai_network_change()
set category = "AI Commands"
set name = "Jump To Network"
unset_machine()
cameraFollow = null
var/cameralist[0]
if(stat == 2)
return //won't work if dead
var/mob/living/silicon/ai/U = usr
for (var/obj/machinery/camera/C in cameranet.cameras)
if(!C.can_use())
continue
var/list/tempnetwork = C.network
tempnetwork.Remove("CREED", "thunder", "RD", "toxins", "Prison")
if(tempnetwork.len)
for(var/i in C.network)
cameralist[i] = i
var/old_network = network
network = input(U, "Which network would you like to view?") as null|anything in cameralist
if(!U.eyeobj)
U.view_core()
return
if(isnull(network))
network = old_network // If nothing is selected
else
for(var/obj/machinery/camera/C in cameranet.cameras)
if(!C.can_use())
continue
if(network in C.network)
U.eyeobj.setLoc(get_turf(C))
break
src << "<span class='notice'>Switched to [network] camera network.</span>"
//End of code by Mord_Sith
/mob/living/silicon/ai/proc/choose_modules()
set category = "Malfunction"
set name = "Choose Module"
malf_picker.use(src)
/mob/living/silicon/ai/proc/ai_statuschange()
set category = "AI Commands"
set name = "AI Status"
if(stat == 2)
return //won't work if dead
var/list/ai_emotions = list("Very Happy", "Happy", "Neutral", "Unsure", "Confused", "Sad", "BSOD", "Blank", "Problems?", "Awesome", "Facepalm", "Friend Computer", "Dorfy", "Blue Glow", "Red Glow")
var/emote = input("Please, select a status!", "AI Status", null, null) in ai_emotions
for (var/obj/machinery/M in machines) //change status
if(istype(M, /obj/machinery/ai_status_display))
var/obj/machinery/ai_status_display/AISD = M
AISD.emotion = emote
//if Friend Computer, change ALL displays
else if(istype(M, /obj/machinery/status_display))
var/obj/machinery/status_display/SD = M
if(emote=="Friend Computer")
SD.friendc = 1
else
SD.friendc = 0
return
//I am the icon meister. Bow fefore me. //>fefore
/mob/living/silicon/ai/proc/ai_hologram_change()
set name = "Change Hologram"
set desc = "Change the default hologram available to AI to something else."
set category = "AI Commands"
if(stat == 2)
return //won't work if dead
var/input
if(alert("Would you like to select a hologram based on a crew member or switch to unique avatar?",,"Crew Member","Unique")=="Crew Member")
var/personnel_list[] = list()
for(var/datum/data/record/t in data_core.locked)//Look in data core locked.
personnel_list["[t.fields["name"]]: [t.fields["rank"]]"] = t.fields["image"]//Pull names, rank, and image.
if(personnel_list.len)
input = input("Select a crew member:") as null|anything in personnel_list
var/icon/character_icon = personnel_list[input]
if(character_icon)
qdel(holo_icon)//Clear old icon so we're not storing it in memory.
holo_icon = getHologramIcon(icon(character_icon))
else
alert("No suitable records found. Aborting.")
else
var/icon_list[] = list(
"default",
"floating face",
"xeno queen",
"space carp"
)
input = input("Please select a hologram:") as null|anything in icon_list
if(input)
qdel(holo_icon)
switch(input)
if("default")
holo_icon = getHologramIcon(icon('icons/mob/AI.dmi',"holo1"))
if("floating face")
holo_icon = getHologramIcon(icon('icons/mob/AI.dmi',"holo2"))
if("xeno queen")
holo_icon = getHologramIcon(icon('icons/mob/AI.dmi',"holo3"))
if("space carp")
holo_icon = getHologramIcon(icon('icons/mob/AI.dmi',"holo4"))
return
/mob/living/silicon/ai/proc/corereturn()
set category = "Malfunction"
set name = "Return to Main Core"
var/obj/machinery/power/apc/apc = src.loc
if(!istype(apc))
src << "<span class='notice'>You are already in your Main Core.</span>"
return
apc.malfvacate()
/mob/living/silicon/ai/proc/toggle_camera_light()
if(stat != CONSCIOUS)
return
camera_light_on = !camera_light_on
if (!camera_light_on)
src << "Camera lights deactivated."
for (var/obj/machinery/camera/C in lit_cameras)
C.SetLuminosity(0)
lit_cameras = list()
return
light_cameras()
src << "Camera lights activated."
return
//AI_CAMERA_LUMINOSITY
/mob/living/silicon/ai/proc/light_cameras()
var/list/obj/machinery/camera/add = list()
var/list/obj/machinery/camera/remove = list()
var/list/obj/machinery/camera/visible = list()
for (var/datum/camerachunk/CC in eyeobj.visibleCameraChunks)
for (var/obj/machinery/camera/C in CC.cameras)
if (!C.can_use() || get_dist(C, eyeobj) > 7)
continue
visible |= C
add = visible - lit_cameras
remove = lit_cameras - visible
for (var/obj/machinery/camera/C in remove)
lit_cameras -= C //Removed from list before turning off the light so that it doesn't check the AI looking away.
C.Togglelight(0)
for (var/obj/machinery/camera/C in add)
C.Togglelight(1)
lit_cameras |= C
/mob/living/silicon/ai/proc/control_integrated_radio()
set name = "Transceiver Settings"
set desc = "Allows you to change settings of your radio."
set category = "AI Commands"
if(stat == 2)
return //won't work if dead
src << "Accessing Subspace Transceiver control..."
if (radio)
radio.interact(src)
/mob/living/silicon/ai/proc/set_syndie_radio()
if(radio)
radio.make_syndie()
/mob/living/silicon/ai/proc/set_automatic_say_channel()
set name = "Set Auto Announce Mode"
set desc = "Modify the default radio setting for your automatic announcements."
set category = "AI Commands"
if(stat == 2)
return //won't work if dead
set_autosay()
/mob/living/silicon/ai/attack_slime(mob/living/simple_animal/slime/user)
return
/mob/living/silicon/ai/transfer_ai(interaction, mob/user, mob/living/silicon/ai/AI, obj/item/device/aicard/card)
if(!..())
return
if(interaction == AI_TRANS_TO_CARD)//The only possible interaction. Upload AI mob to a card.
if(!mind)
user << "<span class='warning'>No intelligence patterns detected.</span>" //No more magical carding of empty cores, AI RETURN TO BODY!!!11
return
new /obj/structure/AIcore/deactivated(loc)//Spawns a deactivated terminal at AI location.
ai_restore_power()//So the AI initially has power.
control_disabled = 1//Can't control things remotely if you're stuck in a card!
radio_enabled = 0 //No talking on the built-in radio for you either!
loc = card//Throw AI into the card.
card.AI = src
src << "You have been downloaded to a mobile storage device. Remote device connection severed."
user << "<span class='boldnotice'>Transfer successful</span>: [name] ([rand(1000,9999)].exe) removed from host terminal and stored within local memory."
/mob/living/silicon/ai/flash_eyes(intensity = 1, override_blindness_check = 0, affect_silicon = 0)
return // no eyes, no flashing
/mob/living/silicon/ai/attackby(obj/item/weapon/W, mob/user, params)
if(W.force && W.damtype != STAMINA && src.stat != DEAD) //only sparks if real damage is dealt.
spark_system.start()
return ..()
/mob/living/silicon/ai/can_buckle()
return 0
/mob/living/silicon/ai/canUseTopic(atom/movable/M, be_close = 0)
if(stat)
return
if(be_close && !in_range(M, src))
return
//stop AIs from leaving windows open and using then after they lose vision
//apc_override is needed here because AIs use their own APC when powerless
//get_turf_pixel() is because APCs in maint aren't actually in view of the inner camera
if(M && cameranet && !cameranet.checkTurfVis(get_turf_pixel(M)) && !apc_override)
return
return 1
/mob/living/silicon/ai/proc/relay_speech(message, atom/movable/speaker, message_langs, raw_message, radio_freq, list/spans)
raw_message = lang_treat(speaker, message_langs, raw_message, spans)
var/name_used = speaker.GetVoice()
var/rendered = "<i><span class='game say'>Relayed Speech: <span class='name'>[name_used]</span> <span class='message'>[raw_message]</span></span></i>"
show_message(rendered, 2)
/mob/living/silicon/ai/fully_replace_character_name(oldname,newname)
..()
if(oldname != real_name)
if(eyeobj)
eyeobj.name = "[newname] (AI Eye)"
// Notify Cyborgs
for(var/mob/living/silicon/robot/Slave in connected_robots)
Slave.show_laws()
/mob/living/silicon/ai/replace_identification_name(oldname,newname)
if(aiPDA)
aiPDA.owner = newname
aiPDA.name = newname + " (" + aiPDA.ownjob + ")"
/mob/living/silicon/ai/proc/add_malf_picker()
src << "In the top right corner of the screen you will find the Malfunctions tab, where you can purchase various abilities, from upgraded surveillance to station ending doomsday devices."
src << "You are also capable of hacking APCs, which grants you more points to spend on your Malfunction powers. The drawback is that a hacked APC will give you away if spotted by the crew. Hacking an APC takes 60 seconds."
view_core() //A BYOND bug requires you to be viewing your core before your verbs update
verbs += /mob/living/silicon/ai/proc/choose_modules
malf_picker = new /datum/module_picker
/mob/living/silicon/ai/reset_perspective(atom/A)
if(camera_light_on)
light_cameras()
if(istype(A,/obj/machinery/camera))
current = A
if(client)
if(istype(A, /atom/movable))
client.perspective = EYE_PERSPECTIVE
client.eye = A
else
if(isturf(loc))
if(eyeobj)
client.eye = eyeobj
client.perspective = MOB_PERSPECTIVE
else
client.eye = client.mob
client.perspective = MOB_PERSPECTIVE
else
client.perspective = EYE_PERSPECTIVE
client.eye = loc
update_sight()
if(client.eye != src)
var/atom/AT = client.eye
AT.get_remote_view_fullscreens(src)
else
clear_fullscreen("remote_view", 0)
/mob/living/silicon/ai/revive(full_heal = 0, admin_revive = 0)
if(..()) //successfully ressuscitated from death
icon_state = "ai"
. = 1
@@ -0,0 +1,48 @@
/mob/living/silicon/ai/death(gibbed)
if(stat == DEAD)
return
if(!gibbed)
visible_message("<b>[src]</b> lets out a flurry of sparks, its screen flickering as its systems slowly halt.")
stat = DEAD
if("[icon_state]_dead" in icon_states(src.icon,1))
icon_state = "[icon_state]_dead"
else
icon_state = "ai_dead"
cameraFollow = null
anchored = 0 //unbolt floorbolts
update_canmove()
if(eyeobj)
eyeobj.setLoc(get_turf(src))
shuttle_caller_list -= src
SSshuttle.autoEvac()
if(nuking)
set_security_level("red")
nuking = 0
SSshuttle.emergencyNoEscape = 0
if(SSshuttle.emergency.mode == SHUTTLE_STRANDED)
SSshuttle.emergency.mode = SHUTTLE_DOCKED
SSshuttle.emergency.timer = world.time
priority_announce("Hostile enviroment resolved. You have 3 minutes to board the Emergency Shuttle.", null, 'sound/AI/shuttledock.ogg', "Priority")
for(var/obj/item/weapon/pinpointer/point in pinpointer_list)
point.the_disk = null //Point back to the disk.
if(doomsday_device)
doomsday_device.timing = 0
qdel(doomsday_device)
if(explosive)
spawn(10)
explosion(src.loc, 3, 6, 12, 15)
for(var/obj/machinery/ai_status_display/O in world) //change status
if(src.key)
O.mode = 2
if(istype(loc, /obj/item/device/aicard))
loc.icon_state = "aicard-404"
return ..()
@@ -0,0 +1,22 @@
/mob/living/silicon/ai/examine(mob/user)
var/msg = "<span class='info'>*---------*\nThis is \icon[src] <EM>[src]</EM>!\n"
if (src.stat == DEAD)
msg += "<span class='deadsay'>It appears to be powered-down.</span>\n"
else
msg += "<span class='warning'>"
if (src.getBruteLoss())
if (src.getBruteLoss() < 30)
msg += "It looks slightly dented.\n"
else
msg += "<B>It looks severely dented!</B>\n"
if (src.getFireLoss())
if (src.getFireLoss() < 30)
msg += "It looks slightly charred.\n"
else
msg += "<B>Its casing is melted and heat-warped!</B>\n"
msg += "</span>"
if (shunted == 0 && !src.client)
msg += "[src]Core.exe has stopped responding! NTOS is searching for a solution to the problem...\n"
msg += "*---------*</span>"
user << msg
@@ -0,0 +1,164 @@
// CAMERA NET
//
// The datum containing all the chunks.
var/const/CHUNK_SIZE = 16 // Only chunk sizes that are to the power of 2. E.g: 2, 4, 8, 16, etc..
var/datum/cameranet/cameranet = new()
/datum/cameranet
var/name = "Camera Net" // Name to show for VV and stat()
// The cameras on the map, no matter if they work or not. Updated in obj/machinery/camera.dm by New() and Del().
var/list/cameras = list()
// The chunks of the map, mapping the areas that the cameras can see.
var/list/chunks = list()
var/ready = 0
// The object used for the clickable stat() button.
var/obj/effect/statclick/statclick
// Checks if a chunk has been Generated in x, y, z.
/datum/cameranet/proc/chunkGenerated(x, y, z)
x &= ~(CHUNK_SIZE - 1)
y &= ~(CHUNK_SIZE - 1)
var/key = "[x],[y],[z]"
return (chunks[key])
// Returns the chunk in the x, y, z.
// If there is no chunk, it creates a new chunk and returns that.
/datum/cameranet/proc/getCameraChunk(x, y, z)
x &= ~(CHUNK_SIZE - 1)
y &= ~(CHUNK_SIZE - 1)
var/key = "[x],[y],[z]"
if(!chunks[key])
chunks[key] = new /datum/camerachunk(null, x, y, z)
return chunks[key]
// Updates what the aiEye can see. It is recommended you use this when the aiEye moves or it's location is set.
/datum/cameranet/proc/visibility(mob/camera/aiEye/ai)
// 0xf = 15
var/x1 = max(0, ai.x - 16) & ~(CHUNK_SIZE - 1)
var/y1 = max(0, ai.y - 16) & ~(CHUNK_SIZE - 1)
var/x2 = min(world.maxx, ai.x + 16) & ~(CHUNK_SIZE - 1)
var/y2 = min(world.maxy, ai.y + 16) & ~(CHUNK_SIZE - 1)
var/list/visibleChunks = list()
for(var/x = x1; x <= x2; x += CHUNK_SIZE)
for(var/y = y1; y <= y2; y += CHUNK_SIZE)
visibleChunks |= getCameraChunk(x, y, ai.z)
var/list/remove = ai.visibleCameraChunks - visibleChunks
var/list/add = visibleChunks - ai.visibleCameraChunks
for(var/chunk in remove)
var/datum/camerachunk/c = chunk
c.remove(ai)
for(var/chunk in add)
var/datum/camerachunk/c = chunk
c.add(ai)
// Updates the chunks that the turf is located in. Use this when obstacles are destroyed or when doors open.
/datum/cameranet/proc/updateVisibility(atom/A, opacity_check = 1)
if(!ticker || (opacity_check && !A.opacity))
return
majorChunkChange(A, 2)
/datum/cameranet/proc/updateChunk(x, y, z)
// 0xf = 15
if(!chunkGenerated(x, y, z))
return
var/datum/camerachunk/chunk = getCameraChunk(x, y, z)
chunk.hasChanged()
// Removes a camera from a chunk.
/datum/cameranet/proc/removeCamera(obj/machinery/camera/c)
if(c.can_use())
majorChunkChange(c, 0)
// Add a camera to a chunk.
/datum/cameranet/proc/addCamera(obj/machinery/camera/c)
if(c.can_use())
majorChunkChange(c, 1)
// Used for Cyborg cameras. Since portable cameras can be in ANY chunk.
/datum/cameranet/proc/updatePortableCamera(obj/machinery/camera/c)
if(c.can_use())
majorChunkChange(c, 1)
//else
// majorChunkChange(c, 0)
// Never access this proc directly!!!!
// This will update the chunk and all the surrounding chunks.
// It will also add the atom to the cameras list if you set the choice to 1.
// Setting the choice to 0 will remove the camera from the chunks.
// If you want to update the chunks around an object, without adding/removing a camera, use choice 2.
/datum/cameranet/proc/majorChunkChange(atom/c, choice)
// 0xf = 15
if(!c)
return
var/turf/T = get_turf(c)
if(T)
var/x1 = max(0, T.x - (CHUNK_SIZE / 2)) & ~(CHUNK_SIZE - 1)
var/y1 = max(0, T.y - (CHUNK_SIZE / 2)) & ~(CHUNK_SIZE - 1)
var/x2 = min(world.maxx, T.x + (CHUNK_SIZE / 2)) & ~(CHUNK_SIZE - 1)
var/y2 = min(world.maxy, T.y + (CHUNK_SIZE / 2)) & ~(CHUNK_SIZE - 1)
//world << "X1: [x1] - Y1: [y1] - X2: [x2] - Y2: [y2]"
for(var/x = x1; x <= x2; x += CHUNK_SIZE)
for(var/y = y1; y <= y2; y += CHUNK_SIZE)
if(chunkGenerated(x, y, T.z))
var/datum/camerachunk/chunk = getCameraChunk(x, y, T.z)
if(choice == 0)
// Remove the camera.
chunk.cameras -= c
else if(choice == 1)
// You can't have the same camera in the list twice.
chunk.cameras |= c
chunk.hasChanged()
// Will check if a mob is on a viewable turf. Returns 1 if it is, otherwise returns 0.
/datum/cameranet/proc/checkCameraVis(mob/living/target)
// 0xf = 15
var/turf/position = get_turf(target)
return checkTurfVis(position)
/datum/cameranet/proc/checkTurfVis(turf/position)
var/datum/camerachunk/chunk = getCameraChunk(position.x, position.y, position.z)
if(chunk)
if(chunk.changed)
chunk.hasChanged(1) // Update now, no matter if it's visible or not.
if(chunk.visibleTurfs[position])
return 1
return 0
/datum/cameranet/proc/stat_entry()
if(!statclick)
statclick = new/obj/effect/statclick/debug("Initializing...", src)
stat(name, statclick.update("Cameras: [cameranet.cameras.len] | Chunks: [cameranet.chunks.len]"))
// Debug verb for VVing the chunk that the turf is in.
/*
/turf/verb/view_chunk()
set src in world
if(cameranet.chunkGenerated(x, y, z))
var/datum/camerachunk/chunk = cameranet.getCameraChunk(x, y, z)
usr.client.debug_variables(chunk)
*/
@@ -0,0 +1,175 @@
#define UPDATE_BUFFER 25 // 2.5 seconds
// CAMERA CHUNK
//
// A 16x16 grid of the map with a list of turfs that can be seen, are visible and are dimmed.
// Allows the AI Eye to stream these chunks and know what it can and cannot see.
/datum/camerachunk
var/list/obscuredTurfs = list()
var/list/visibleTurfs = list()
var/list/obscured = list()
var/list/cameras = list()
var/list/turfs = list()
var/list/seenby = list()
var/visible = 0
var/changed = 0
var/updating = 0
var/x = 0
var/y = 0
var/z = 0
// Add an AI eye to the chunk, then update if changed.
/datum/camerachunk/proc/add(mob/camera/aiEye/eye)
var/client/client = eye.GetViewerClient()
if(client)
client.images += obscured
eye.visibleCameraChunks += src
visible++
seenby += eye
if(changed && !updating)
update()
// Remove an AI eye from the chunk, then update if changed.
/datum/camerachunk/proc/remove(mob/camera/aiEye/eye)
var/client/client = eye.GetViewerClient()
if(client)
client.images -= obscured
eye.visibleCameraChunks -= src
seenby -= eye
if(visible > 0)
visible--
// Called when a chunk has changed. I.E: A wall was deleted.
/datum/camerachunk/proc/visibilityChanged(turf/loc)
if(!visibleTurfs[loc])
return
hasChanged()
// Updates the chunk, makes sure that it doesn't update too much. If the chunk isn't being watched it will
// instead be flagged to update the next time an AI Eye moves near it.
/datum/camerachunk/proc/hasChanged(update_now = 0)
if(visible || update_now)
if(!updating)
updating = 1
spawn(UPDATE_BUFFER) // Batch large changes, such as many doors opening or closing at once
update()
updating = 0
else
changed = 1
// The actual updating. It gathers the visible turfs from cameras and puts them into the appropiate lists.
/datum/camerachunk/proc/update()
set background = BACKGROUND_ENABLED
var/list/newVisibleTurfs = list()
for(var/camera in cameras)
var/obj/machinery/camera/c = camera
if(!c)
continue
if(!c.can_use())
continue
var/turf/point = locate(src.x + (CHUNK_SIZE / 2), src.y + (CHUNK_SIZE / 2), src.z)
if(get_dist(point, c) > CHUNK_SIZE + (CHUNK_SIZE / 2))
continue
for(var/turf/t in c.can_see())
// Possible optimization: if(turfs[t]) here, rather than &= turfs afterwards.
// List associations use a tree or hashmap of some sort (alongside the list itself)
// so are surprisingly fast. (significantly faster than var/thingy/x in list, in testing)
newVisibleTurfs[t] = t
// Removes turf that isn't in turfs.
newVisibleTurfs &= turfs
var/list/visAdded = newVisibleTurfs - visibleTurfs
var/list/visRemoved = visibleTurfs - newVisibleTurfs
visibleTurfs = newVisibleTurfs
obscuredTurfs = turfs - newVisibleTurfs
for(var/turf in visAdded)
var/turf/t = turf
if(t.obscured)
obscured -= t.obscured
for(var/eye in seenby)
var/mob/camera/aiEye/m = eye
if(!m)
continue
var/client/client = m.GetViewerClient()
if(client)
client.images -= t.obscured
for(var/turf in visRemoved)
var/turf/t = turf
if(obscuredTurfs[t])
if(!t.obscured)
t.obscured = image('icons/effects/cameravis.dmi', t, "black", 16)
obscured += t.obscured
for(var/eye in seenby)
var/mob/camera/aiEye/m = eye
if(!m)
seenby -= m
continue
var/client/client = m.GetViewerClient()
if(client)
client.images += t.obscured
changed = 0
// Create a new camera chunk, since the chunks are made as they are needed.
/datum/camerachunk/New(loc, x, y, z)
// 0xf = 15
x &= ~(CHUNK_SIZE - 1)
y &= ~(CHUNK_SIZE - 1)
src.x = x
src.y = y
src.z = z
for(var/obj/machinery/camera/c in urange(CHUNK_SIZE, locate(x + (CHUNK_SIZE / 2), y + (CHUNK_SIZE / 2), z)))
if(c.can_use())
cameras += c
for(var/turf/t in block(locate(x, y, z), locate(min(x + CHUNK_SIZE - 1, world.maxx), min(y + CHUNK_SIZE - 1, world.maxy), z)))
turfs[t] = t
for(var/camera in cameras)
var/obj/machinery/camera/c = camera
if(!c)
continue
if(!c.can_use())
continue
for(var/turf/t in c.can_see())
// Possible optimization: if(turfs[t]) here, rather than &= turfs afterwards.
// List associations use a tree or hashmap of some sort (alongside the list itself)
// so are surprisingly fast. (significantly faster than var/thingy/x in list, in testing)
visibleTurfs[t] = t
// Removes turf that isn't in turfs.
visibleTurfs &= turfs
obscuredTurfs = turfs - visibleTurfs
for(var/turf in obscuredTurfs)
var/turf/t = turf
if(!t.obscured)
t.obscured = image('icons/effects/cameravis.dmi', t, "black", 16)
obscured += t.obscured
#undef UPDATE_BUFFER
@@ -0,0 +1,110 @@
// AI EYE
//
// An invisible (no icon) mob that the AI controls to look around the station with.
// It streams chunks as it moves around, which will show it what the AI can and cannot see.
/mob/camera/aiEye
name = "Inactive AI Eye"
invisibility = INVISIBILITY_MAXIMUM
var/list/visibleCameraChunks = list()
var/mob/living/silicon/ai/ai = null
var/relay_speech = FALSE
// Use this when setting the aiEye's location.
// It will also stream the chunk that the new loc is in.
/mob/camera/aiEye/proc/setLoc(T)
if(ai)
if(!isturf(ai.loc))
return
T = get_turf(T)
loc = T
cameranet.visibility(src)
if(ai.client)
ai.client.eye = src
//Holopad
if(istype(ai.current, /obj/machinery/hologram/holopad))
var/obj/machinery/hologram/holopad/H = ai.current
H.move_hologram(ai)
/mob/camera/aiEye/Move()
return 0
/mob/camera/aiEye/proc/GetViewerClient()
if(ai)
return ai.client
return null
/mob/camera/aiEye/Destroy()
ai = null
return ..()
/atom/proc/move_camera_by_click()
if(istype(usr, /mob/living/silicon/ai))
var/mob/living/silicon/ai/AI = usr
if(AI.eyeobj && AI.client.eye == AI.eyeobj)
AI.cameraFollow = null
if (isturf(src.loc) || isturf(src))
AI.eyeobj.setLoc(src)
// This will move the AIEye. It will also cause lights near the eye to light up, if toggled.
// This is handled in the proc below this one.
/client/proc/AIMove(n, direct, mob/living/silicon/ai/user)
var/initial = initial(user.sprint)
var/max_sprint = 50
if(user.cooldown && user.cooldown < world.timeofday) // 3 seconds
user.sprint = initial
for(var/i = 0; i < max(user.sprint, initial); i += 20)
var/turf/step = get_turf(get_step(user.eyeobj, direct))
if(step)
user.eyeobj.setLoc(step)
user.cooldown = world.timeofday + 5
if(user.acceleration)
user.sprint = min(user.sprint + 0.5, max_sprint)
else
user.sprint = initial
if(!user.tracking)
user.cameraFollow = null
//user.unset_machine() //Uncomment this if it causes problems.
//user.lightNearbyCamera()
if (user.camera_light_on)
user.light_cameras()
// Return to the Core.
/mob/living/silicon/ai/proc/view_core()
current = null
cameraFollow = null
unset_machine()
if(src.eyeobj && src.loc)
src.eyeobj.loc = src.loc
else
src << "ERROR: Eyeobj not found. Creating new eye..."
src.eyeobj = new(src.loc)
src.eyeobj.ai = src
src.eyeobj.name = "[src.name] (AI Eye)" // Give it a name
eyeobj.setLoc(loc)
/mob/living/silicon/ai/verb/toggle_acceleration()
set category = "AI Commands"
set name = "Toggle Camera Acceleration"
if(usr.stat == 2)
return //won't work if dead
acceleration = !acceleration
usr << "Camera acceleration has been toggled [acceleration ? "on" : "off"]."
/mob/camera/aiEye/Hear(message, atom/movable/speaker, message_langs, raw_message, radio_freq, list/spans)
if(relay_speech && speaker && ai && !radio_freq && speaker != ai && near_camera(speaker))
ai.relay_speech(message, speaker, message_langs, raw_message, radio_freq, spans)
@@ -0,0 +1,51 @@
// CREDITS
/*
Initial code credit for this goes to Uristqwerty.
Debugging, functionality, all comments and porting by Giacom.
Everything about freelook (or what we can put in here) will be stored here.
WHAT IS THIS?
This is a replacement for the current camera movement system, of the AI. Before this, the AI had to move between cameras and could
only see what the cameras could see. Not only this but the cameras could see through walls, which created problems.
With this, the AI controls an "AI Eye" mob, which moves just like a ghost; such as moving through walls and being invisible to players.
The AI's eye is set to this mob and then we use a system (explained below) to determine what the cameras around the AI Eye can and
cannot see. If the camera cannot see a turf, it will black it out, otherwise it won't and the AI will be able to see it.
This creates several features, such as.. no more see-through-wall cameras, easier to control camera movement, easier tracking,
the AI only being able to track mobs which are visible to a camera, only trackable mobs appearing on the mob list and many more.
HOW IT WORKS
It works by first creating a camera network datum. Inside of this camera network are "chunks" (which will be
explained later) and "cameras". The cameras list is kept up to date by obj/machinery/camera/New() and Del().
Next the camera network has chunks. These chunks are a 16x16 tile block of turfs and cameras contained inside the chunk.
These turfs are then sorted out based on what the cameras can and cannot see. If none of the cameras can see the turf, inside
the 16x16 block, it is listed as an "obscured" turf. Meaning the AI won't be able to see it.
HOW IT UPDATES
The camera network uses a streaming method in order to effeciently update chunks. Since the server will have doors opening, doors closing,
turf being destroyed and other lag inducing stuff, we want to update it under certain conditions and not every tick.
The chunks are not created straight away, only when an AI eye moves into it's area is when it gets created.
One a chunk is created, when a non glass door opens/closes or an opacity turf is destroyed, we check to see if an AI Eye is looking in the area.
We do this with the "seenby" list, which updates everytime an AI is near a chunk. If there is an AI eye inside the area, we update the chunk
that the changed atom is inside and all surrounding chunks, since a camera's vision could leak onto another chunk. If there is no AI Eye, we instead
flag the chunk to update whenever it is loaded by an AI Eye. This is basically how the chunks update and keep it in sync. We then add some lag reducing
measures, such as an UPDATE_BUFFER which stops a chunk from updating too many times in a certain time-frame, only updating if the changed atom was blocking
sight; for example, we don't update glass airlocks or floors.
WHERE IS EVERYTHING?
cameranet.dm = Everything about the cameranet datum.
chunk.dm = Everything about the chunk datum.
eye.dm = Everything about the AI and the AIEye.
updating.dm = Everything about triggers that will update chunks.
*/
@@ -0,0 +1,26 @@
/mob/living/silicon/ai/proc/show_laws_verb()
set category = "AI Commands"
set name = "Show Laws"
if(usr.stat == 2)
return //won't work if dead
src.show_laws()
/mob/living/silicon/ai/show_laws(everyone = 0)
var/who
if (everyone)
who = world
else
who = src
who << "<b>Obey these laws:</b>"
src.laws_sanity_check()
src.laws.show_laws(who)
if(!everyone)
for(var/mob/living/silicon/robot/R in connected_robots)
if(R.lawupdate)
R.lawsync()
R.show_laws()
R.law_change_counter++
+167
View File
@@ -0,0 +1,167 @@
#define POWER_RESTORATION_OFF 0
#define POWER_RESTORATION_START 1
#define POWER_RESTORATION_SEARCH_APC 2
#define POWER_RESTORATION_APC_FOUND 3
/mob/living/silicon/ai/Life()
if (src.stat == DEAD)
return
else //I'm not removing that shitton of tabs, unneeded as they are. -- Urist
//Being dead doesn't mean your temperature never changes
update_gravity(mob_has_gravity())
if(malfhack)
if(malfhack.aidisabled)
src << "<span class='danger'>ERROR: APC access disabled, hack attempt canceled.</span>"
malfhacking = 0
malfhack = null
if(machine)
machine.check_eye(src)
// Handle power damage (oxy)
if(aiRestorePowerRoutine)
// Lost power
adjustOxyLoss(1)
else
// Gain Power
if(getOxyLoss())
adjustOxyLoss(-1)
if(!lacks_power())
var/area/home = get_area(src)
if(home.powered(EQUIP))
home.use_power(1000, EQUIP)
if(aiRestorePowerRoutine >= POWER_RESTORATION_SEARCH_APC)
ai_restore_power()
return
else if(!aiRestorePowerRoutine)
ai_lose_power()
/mob/living/silicon/ai/proc/lacks_power()
var/turf/T = get_turf(src)
var/area/A = get_area(src)
return !T || !A || ((!A.master.power_equip || istype(T, /turf/open/space)) && !is_type_in_list(src.loc, list(/obj/item, /obj/mecha)))
/mob/living/silicon/ai/updatehealth()
if(status_flags & GODMODE)
return
health = maxHealth - getOxyLoss() - getToxLoss() - getBruteLoss()
if(!fire_res_on_core)
health -= getFireLoss()
update_stat()
diag_hud_set_health()
/mob/living/silicon/ai/update_stat()
if(status_flags & GODMODE)
return
if(stat != DEAD)
if(health <= config.health_threshold_dead)
death()
return
else if(stat == UNCONSCIOUS)
stat = CONSCIOUS
adjust_blindness(-1)
diag_hud_set_status()
/mob/living/silicon/ai/update_sight()
see_invisible = initial(see_invisible)
see_in_dark = initial(see_in_dark)
sight = initial(sight)
if(aiRestorePowerRoutine)
sight = sight&~SEE_TURFS
sight = sight&~SEE_MOBS
sight = sight&~SEE_OBJS
see_in_dark = 0
if(see_override)
see_invisible = see_override
/mob/living/silicon/ai/proc/start_RestorePowerRoutine()
src << "Backup battery online. Scanners, camera, and radio interface offline. Beginning fault-detection."
sleep(50)
var/turf/T = get_turf(src)
var/area/AIarea = get_area(src)
if(AIarea && AIarea.master.power_equip)
if(!istype(T, /turf/open/space))
ai_restore_power()
return
src << "Fault confirmed: missing external power. Shutting down main control system to save power."
sleep(20)
src << "Emergency control system online. Verifying connection to power network."
sleep(50)
T = get_turf(src)
if (istype(T, /turf/open/space))
src << "Unable to verify! No power connection detected!"
aiRestorePowerRoutine = POWER_RESTORATION_SEARCH_APC
return
src << "Connection verified. Searching for APC in power network."
sleep(50)
var/obj/machinery/power/apc/theAPC = null
var/PRP //like ERP with the code, at least this stuff is no more 4x sametext
for (PRP=1, PRP<=4, PRP++)
T = get_turf(src)
AIarea = get_area(src)
if(AIarea)
for(var/area/A in AIarea.master.related)
for (var/obj/machinery/power/apc/APC in A)
if (!(APC.stat & BROKEN))
theAPC = APC
break
if (!theAPC)
switch(PRP)
if(1)
src << "Unable to locate APC!"
else
src << "Lost connection with the APC!"
aiRestorePowerRoutine = POWER_RESTORATION_SEARCH_APC
return
if(AIarea.master.power_equip)
if (!istype(T, /turf/open/space))
ai_restore_power()
return
switch(PRP)
if (1) src << "APC located. Optimizing route to APC to avoid needless power waste."
if (2) src << "Best route identified. Hacking offline APC power port."
if (3) src << "Power port upload access confirmed. Loading control program into APC power port software."
if (4)
src << "Transfer complete. Forcing APC to execute program."
sleep(50)
src << "Receiving control information from APC."
sleep(2)
apc_override = 1
theAPC.ui_interact(src, state = conscious_state)
apc_override = 0
aiRestorePowerRoutine = POWER_RESTORATION_APC_FOUND
src << "Here are your current laws:"
show_laws()
sleep(50)
theAPC = null
/mob/living/silicon/ai/proc/ai_restore_power()
if(aiRestorePowerRoutine)
if(aiRestorePowerRoutine == POWER_RESTORATION_APC_FOUND)
src << "Alert cancelled. Power has been restored."
else
src << "Alert cancelled. Power has been restored without our assistance."
aiRestorePowerRoutine = POWER_RESTORATION_OFF
set_blindness(0)
update_sight()
/mob/living/silicon/ai/proc/ai_lose_power()
aiRestorePowerRoutine = POWER_RESTORATION_START
blind_eyes(1)
update_sight()
src << "You've lost power!"
spawn(20)
start_RestorePowerRoutine()
#undef POWER_RESTORATION_OFF
#undef POWER_RESTORATION_START
#undef POWER_RESTORATION_SEARCH_APC
#undef POWER_RESTORATION_APC_FOUND
@@ -0,0 +1,12 @@
/mob/living/silicon/ai/Login()
..()
for(var/obj/effect/rune/rune in world)
var/image/blood = image(loc = rune)
blood.override = 1
client.images += blood
if(stat != DEAD)
for(var/obj/machinery/ai_status_display/O in machines) //change status
O.mode = 1
O.emotion = "Neutral"
view_core()
@@ -0,0 +1,5 @@
/mob/living/silicon/ai/Logout()
..()
for(var/obj/machinery/ai_status_display/O in world) //change status
O.mode = 0
view_core()
+169
View File
@@ -0,0 +1,169 @@
/mob/living/silicon/ai/say(message)
if(parent && istype(parent) && parent.stat != 2) //If there is a defined "parent" AI, it is actually an AI, and it is alive, anything the AI tries to say is said by the parent instead.
parent.say(message)
return
..(message)
/mob/living/silicon/ai/compose_track_href(atom/movable/speaker, namepart)
var/mob/M = speaker.GetSource()
if(M)
return "<a href='?src=\ref[src];track=[html_encode(namepart)]'>"
return ""
/mob/living/silicon/ai/compose_job(atom/movable/speaker, message_langs, raw_message, radio_freq)
//Also includes the </a> for AI hrefs, for convenience.
return "[radio_freq ? " (" + speaker.GetJob() + ")" : ""]" + "[speaker.GetSource() ? "</a>" : ""]"
/mob/living/silicon/ai/IsVocal()
return !config.silent_ai
/mob/living/silicon/ai/radio(message, message_mode, list/spans)
if(!radio_enabled || aiRestorePowerRoutine || stat) //AI cannot speak if radio is disabled (via intellicard) or depowered.
src << "<span class='danger'>Your radio transmitter is offline!</span>"
return 0
..()
/mob/living/silicon/ai/get_message_mode(message)
if(copytext(message, 1, 3) in list(":h", ":H", ".h", ".H", "#h", "#H"))
return MODE_HOLOPAD
else
return ..()
/mob/living/silicon/ai/handle_inherent_channels(message, message_mode)
. = ..()
if(.)
return .
if(message_mode == MODE_HOLOPAD)
holopad_talk(message)
return 1
//For holopads only. Usable by AI.
/mob/living/silicon/ai/proc/holopad_talk(message)
log_say("[key_name(src)] : [message]")
message = trim(message)
if (!message)
return
var/obj/machinery/hologram/holopad/T = current
if(istype(T) && T.masters[src])//If there is a hologram and its master is the user.
send_speech(message, 7, T, "robot", get_spans())
src << "<i><span class='game say'>Holopad transmitted, <span class='name'>[real_name]</span> <span class='message robot'>\"[message]\"</span></span></i>"//The AI can "hear" its own message.
else
src << "No holopad connected."
return
// Make sure that the code compiles with AI_VOX undefined
#ifdef AI_VOX
var/announcing_vox = 0 // Stores the time of the last announcement
var/const/VOX_CHANNEL = 200
var/const/VOX_DELAY = 600
/mob/living/silicon/ai/verb/announcement_help()
set name = "Announcement Help"
set desc = "Display a list of vocal words to announce to the crew."
set category = "AI Commands"
if(usr.stat == 2)
return //won't work if dead
var/dat = "Here is a list of words you can type into the 'Announcement' button to create sentences to vocally announce to everyone on the same level at you.<BR> \
<UL><LI>You can also click on the word to preview it.</LI>\
<LI>You can only say 30 words for every announcement.</LI>\
<LI>Do not use punctuation as you would normally, if you want a pause you can use the full stop and comma characters by separating them with spaces, like so: 'Alpha . Test , Bravo'.</LI></UL>\
<font class='bad'>WARNING:</font><BR>Misuse of the announcement system will get you job banned.<HR>"
var/index = 0
for(var/word in vox_sounds)
index++
dat += "<A href='?src=\ref[src];say_word=[word]'>[capitalize(word)]</A>"
if(index != vox_sounds.len)
dat += " / "
var/datum/browser/popup = new(src, "announce_help", "Announcement Help", 500, 400)
popup.set_content(dat)
popup.open()
/mob/living/silicon/ai/proc/announcement()
if(announcing_vox > world.time)
src << "<span class='notice'>Please wait [round((announcing_vox - world.time) / 10)] seconds.</span>"
return
var/message = input(src, "WARNING: Misuse of this verb can result in you being job banned. More help is available in 'Announcement Help'", "Announcement", src.last_announcement) as text
last_announcement = message
if(!message || announcing_vox > world.time)
return
if(stat != CONSCIOUS)
return
if(control_disabled)
src << "<span class='notice'>Wireless interface disabled, unable to interact with announcement PA.</span>"
return
var/list/words = splittext(trim(message), " ")
var/list/incorrect_words = list()
if(words.len > 30)
words.len = 30
for(var/word in words)
word = lowertext(trim(word))
if(!word)
words -= word
continue
if(!vox_sounds[word])
incorrect_words += word
if(incorrect_words.len)
src << "<span class='notice'>These words are not available on the announcement system: [english_list(incorrect_words)].</span>"
return
announcing_vox = world.time + VOX_DELAY
log_game("[key_name(src)] made a vocal announcement with the following message: [message].")
for(var/word in words)
play_vox_word(word, src.z, null)
/*
for(var/mob/M in player_list)
if(M.client)
var/turf/T = get_turf(M)
var/turf/our_turf = get_turf(src)
if(T.z == our_turf.z)
M << "<b><font size = 3><font color = red>AI announcement:</font color> [message]</font size></b>"
*/
/proc/play_vox_word(word, z_level, mob/only_listener)
word = lowertext(word)
if(vox_sounds[word])
var/sound_file = vox_sounds[word]
var/sound/voice = sound(sound_file, wait = 1, channel = VOX_CHANNEL)
voice.status = SOUND_STREAM
// If there is no single listener, broadcast to everyone in the same z level
if(!only_listener)
// Play voice for all mobs in the z level
for(var/mob/M in player_list)
if(M.client && !M.ear_deaf && (M.client.prefs.toggles & SOUND_ANNOUNCEMENTS))
var/turf/T = get_turf(M)
if(T.z == z_level)
M << voice
else
only_listener << voice
return 1
return 0
#endif
@@ -0,0 +1,718 @@
// List is required to compile the resources into the game when it loads.
// Dynamically loading it has bad results with sounds overtaking each other, even with the wait variable.
#ifdef AI_VOX
var/list/vox_sounds = list("," = 'sound/vox_fem/,.ogg',
"." = 'sound/vox_fem/..ogg',
"a" = 'sound/vox_fem/a.ogg',
"abortions" = 'sound/vox_fem/abortions.ogg',
"accelerating" = 'sound/vox_fem/accelerating.ogg',
"accelerator" = 'sound/vox_fem/accelerator.ogg',
"accepted" = 'sound/vox_fem/accepted.ogg',
"access" = 'sound/vox_fem/access.ogg',
"acknowledge" = 'sound/vox_fem/acknowledge.ogg',
"acknowledged" = 'sound/vox_fem/acknowledged.ogg',
"acquired" = 'sound/vox_fem/acquired.ogg',
"acquisition" = 'sound/vox_fem/acquisition.ogg',
"across" = 'sound/vox_fem/across.ogg',
"activate" = 'sound/vox_fem/activate.ogg',
"activated" = 'sound/vox_fem/activated.ogg',
"activity" = 'sound/vox_fem/activity.ogg',
"adios" = 'sound/vox_fem/adios.ogg',
"administration" = 'sound/vox_fem/administration.ogg',
"advanced" = 'sound/vox_fem/advanced.ogg',
"aft" = 'sound/vox_fem/aft.ogg',
"after" = 'sound/vox_fem/after.ogg',
"agent" = 'sound/vox_fem/agent.ogg',
"ai" = 'sound/vox_fem/ai.ogg',
"alarm" = 'sound/vox_fem/alarm.ogg',
"alert" = 'sound/vox_fem/alert.ogg',
"alien" = 'sound/vox_fem/alien.ogg',
"aligned" = 'sound/vox_fem/aligned.ogg',
"all" = 'sound/vox_fem/all.ogg',
"alpha" = 'sound/vox_fem/alpha.ogg',
"am" = 'sound/vox_fem/am.ogg',
"amigo" = 'sound/vox_fem/amigo.ogg',
"ammunition" = 'sound/vox_fem/ammunition.ogg',
"an" = 'sound/vox_fem/an.ogg',
"and" = 'sound/vox_fem/and.ogg',
"announcement" = 'sound/vox_fem/announcement.ogg',
"anomalous" = 'sound/vox_fem/anomalous.ogg',
"antenna" = 'sound/vox_fem/antenna.ogg',
"any" = 'sound/vox_fem/any.ogg',
"apprehend" = 'sound/vox_fem/apprehend.ogg',
"approach" = 'sound/vox_fem/approach.ogg',
"are" = 'sound/vox_fem/are.ogg',
"area" = 'sound/vox_fem/area.ogg',
"arm" = 'sound/vox_fem/arm.ogg',
"armed" = 'sound/vox_fem/armed.ogg',
"armor" = 'sound/vox_fem/armor.ogg',
"armory" = 'sound/vox_fem/armory.ogg',
"array" = 'sound/vox_fem/array.ogg',
"arrest" = 'sound/vox_fem/arrest.ogg',
"asimov" = 'sound/vox_fem/asimov.ogg',
"ass" = 'sound/vox_fem/ass.ogg',
"asshole" = 'sound/vox_fem/asshole.ogg',
"assholes" = 'sound/vox_fem/assholes.ogg',
"at" = 'sound/vox_fem/at.ogg',
"atomic" = 'sound/vox_fem/atomic.ogg',
"attention" = 'sound/vox_fem/attention.ogg',
"authorize" = 'sound/vox_fem/authorize.ogg',
"authorized" = 'sound/vox_fem/authorized.ogg',
"automatic" = 'sound/vox_fem/automatic.ogg',
"away" = 'sound/vox_fem/away.ogg',
"b" = 'sound/vox_fem/b.ogg',
"back" = 'sound/vox_fem/back.ogg',
"backman" = 'sound/vox_fem/backman.ogg',
"bad" = 'sound/vox_fem/bad.ogg',
"bag" = 'sound/vox_fem/bag.ogg',
"bailey" = 'sound/vox_fem/bailey.ogg',
"barracks" = 'sound/vox_fem/barracks.ogg',
"base" = 'sound/vox_fem/base.ogg',
"bay" = 'sound/vox_fem/bay.ogg',
"be" = 'sound/vox_fem/be.ogg',
"been" = 'sound/vox_fem/been.ogg',
"before" = 'sound/vox_fem/before.ogg',
"beyond" = 'sound/vox_fem/beyond.ogg',
"biohazard" = 'sound/vox_fem/biohazard.ogg',
"biological" = 'sound/vox_fem/biological.ogg',
"birdwell" = 'sound/vox_fem/birdwell.ogg',
"bitch" = 'sound/vox_fem/bitch.ogg',
"bitches" = 'sound/vox_fem/bitches.ogg',
"black" = 'sound/vox_fem/black.ogg',
"blast" = 'sound/vox_fem/blast.ogg',
"blocked" = 'sound/vox_fem/blocked.ogg',
"blue" = 'sound/vox_fem/blue.ogg',
"bottom" = 'sound/vox_fem/bottom.ogg',
"bravo" = 'sound/vox_fem/bravo.ogg',
"breach" = 'sound/vox_fem/breach.ogg',
"breached" = 'sound/vox_fem/breached.ogg',
"break" = 'sound/vox_fem/break.ogg',
"bridge" = 'sound/vox_fem/bridge.ogg',
"bust" = 'sound/vox_fem/bust.ogg',
"but" = 'sound/vox_fem/but.ogg',
"button" = 'sound/vox_fem/button.ogg',
"bypass" = 'sound/vox_fem/bypass.ogg',
"c" = 'sound/vox_fem/c.ogg',
"cable" = 'sound/vox_fem/cable.ogg',
"call" = 'sound/vox_fem/call.ogg',
"called" = 'sound/vox_fem/called.ogg',
"canal" = 'sound/vox_fem/canal.ogg',
"cap" = 'sound/vox_fem/cap.ogg',
"captain" = 'sound/vox_fem/captain.ogg',
"capture" = 'sound/vox_fem/capture.ogg',
"cargo" = 'sound/vox_fem/cargo.ogg',
"ceiling" = 'sound/vox_fem/ceiling.ogg',
"celsius" = 'sound/vox_fem/celsius.ogg',
"centcom" = 'sound/vox_fem/centcom.ogg',
"center" = 'sound/vox_fem/center.ogg',
"centi" = 'sound/vox_fem/centi.ogg',
"central" = 'sound/vox_fem/central.ogg',
"chamber" = 'sound/vox_fem/chamber.ogg',
"changed" = 'sound/vox_fem/changed.ogg',
"charlie" = 'sound/vox_fem/charlie.ogg',
"check" = 'sound/vox_fem/check.ogg',
"checkpoint" = 'sound/vox_fem/checkpoint.ogg',
"chemical" = 'sound/vox_fem/chemical.ogg',
"cleanup" = 'sound/vox_fem/cleanup.ogg',
"clear" = 'sound/vox_fem/clear.ogg',
"clearance" = 'sound/vox_fem/clearance.ogg',
"close" = 'sound/vox_fem/close.ogg',
"clown" = 'sound/vox_fem/clown.ogg',
"code" = 'sound/vox_fem/code.ogg',
"coded" = 'sound/vox_fem/coded.ogg',
"collider" = 'sound/vox_fem/collider.ogg',
"come" = 'sound/vox_fem/come.ogg',
"command" = 'sound/vox_fem/command.ogg',
"communication" = 'sound/vox_fem/communication.ogg',
"complex" = 'sound/vox_fem/complex.ogg',
"computer" = 'sound/vox_fem/computer.ogg',
"condition" = 'sound/vox_fem/condition.ogg',
"connor" = 'sound/vox_fem/connor.ogg',
"containment" = 'sound/vox_fem/containment.ogg',
"contamination" = 'sound/vox_fem/contamination.ogg',
"contraband" = 'sound/vox_fem/contraband.ogg',
"control" = 'sound/vox_fem/control.ogg',
"coolant" = 'sound/vox_fem/coolant.ogg',
"coomer" = 'sound/vox_fem/coomer.ogg',
"core" = 'sound/vox_fem/core.ogg',
"correct" = 'sound/vox_fem/correct.ogg',
"corridor" = 'sound/vox_fem/corridor.ogg',
"coward" = 'sound/vox_fem/coward.ogg',
"cowards" = 'sound/vox_fem/cowards.ogg',
"crew" = 'sound/vox_fem/crew.ogg',
"cross" = 'sound/vox_fem/cross.ogg',
"cryogenic" = 'sound/vox_fem/cryogenic.ogg',
"cunt" = 'sound/vox_fem/cunt.ogg',
"cyborg" = 'sound/vox_fem/cyborg.ogg',
"cyborgs" = 'sound/vox_fem/cyborgs.ogg',
"d" = 'sound/vox_fem/d.ogg',
"damage" = 'sound/vox_fem/damage.ogg',
"damaged" = 'sound/vox_fem/damaged.ogg',
"danger" = 'sound/vox_fem/danger.ogg',
"day" = 'sound/vox_fem/day.ogg',
"deactivated" = 'sound/vox_fem/deactivated.ogg',
"decompression" = 'sound/vox_fem/decompression.ogg',
"decontamination" = 'sound/vox_fem/decontamination.ogg',
"deeoo" = 'sound/vox_fem/deeoo.ogg',
"defense" = 'sound/vox_fem/defense.ogg',
"degrees" = 'sound/vox_fem/degrees.ogg',
"delta" = 'sound/vox_fem/delta.ogg',
"denied" = 'sound/vox_fem/denied.ogg',
"deploy" = 'sound/vox_fem/deploy.ogg',
"deployed" = 'sound/vox_fem/deployed.ogg',
"destroy" = 'sound/vox_fem/destroy.ogg',
"destroyed" = 'sound/vox_fem/destroyed.ogg',
"detain" = 'sound/vox_fem/detain.ogg',
"detected" = 'sound/vox_fem/detected.ogg',
"detonation" = 'sound/vox_fem/detonation.ogg',
"device" = 'sound/vox_fem/device.ogg',
"did" = 'sound/vox_fem/did.ogg',
"die" = 'sound/vox_fem/die.ogg',
"dimensional" = 'sound/vox_fem/dimensional.ogg',
"dirt" = 'sound/vox_fem/dirt.ogg',
"disengaged" = 'sound/vox_fem/disengaged.ogg',
"dish" = 'sound/vox_fem/dish.ogg',
"disposal" = 'sound/vox_fem/disposal.ogg',
"distance" = 'sound/vox_fem/distance.ogg',
"distortion" = 'sound/vox_fem/distortion.ogg',
"do" = 'sound/vox_fem/do.ogg',
"doctor" = 'sound/vox_fem/doctor.ogg',
"door" = 'sound/vox_fem/door.ogg',
"down" = 'sound/vox_fem/down.ogg',
"dual" = 'sound/vox_fem/dual.ogg',
"duct" = 'sound/vox_fem/duct.ogg',
"e" = 'sound/vox_fem/e.ogg',
"east" = 'sound/vox_fem/east.ogg',
"echo" = 'sound/vox_fem/echo.ogg',
"ed" = 'sound/vox_fem/ed.ogg',
"effect" = 'sound/vox_fem/effect.ogg',
"egress" = 'sound/vox_fem/egress.ogg',
"eight" = 'sound/vox_fem/eight.ogg',
"eighteen" = 'sound/vox_fem/eighteen.ogg',
"eighty" = 'sound/vox_fem/eighty.ogg',
"electric" = 'sound/vox_fem/electric.ogg',
"electromagnetic" = 'sound/vox_fem/electromagnetic.ogg',
"elevator" = 'sound/vox_fem/elevator.ogg',
"eleven" = 'sound/vox_fem/eleven.ogg',
"eliminate" = 'sound/vox_fem/eliminate.ogg',
"emergency" = 'sound/vox_fem/emergency.ogg',
"energy" = 'sound/vox_fem/energy.ogg',
"engage" = 'sound/vox_fem/engage.ogg',
"engaged" = 'sound/vox_fem/engaged.ogg',
"engine" = 'sound/vox_fem/engine.ogg',
"enter" = 'sound/vox_fem/enter.ogg',
"entry" = 'sound/vox_fem/entry.ogg',
"environment" = 'sound/vox_fem/environment.ogg',
"error" = 'sound/vox_fem/error.ogg',
"escape" = 'sound/vox_fem/escape.ogg',
"evacuate" = 'sound/vox_fem/evacuate.ogg',
"exchange" = 'sound/vox_fem/exchange.ogg',
"exit" = 'sound/vox_fem/exit.ogg',
"expect" = 'sound/vox_fem/expect.ogg',
"experiment" = 'sound/vox_fem/experiment.ogg',
"experimental" = 'sound/vox_fem/experimental.ogg',
"explode" = 'sound/vox_fem/explode.ogg',
"explosion" = 'sound/vox_fem/explosion.ogg',
"exposure" = 'sound/vox_fem/exposure.ogg',
"exterminate" = 'sound/vox_fem/exterminate.ogg',
"extinguish" = 'sound/vox_fem/extinguish.ogg',
"extinguisher" = 'sound/vox_fem/extinguisher.ogg',
"extreme" = 'sound/vox_fem/extreme.ogg',
"f" = 'sound/vox_fem/f.ogg',
"facility" = 'sound/vox_fem/facility.ogg',
"fahrenheit" = 'sound/vox_fem/fahrenheit.ogg',
"failed" = 'sound/vox_fem/failed.ogg',
"failure" = 'sound/vox_fem/failure.ogg',
"farthest" = 'sound/vox_fem/farthest.ogg',
"fast" = 'sound/vox_fem/fast.ogg',
"feet" = 'sound/vox_fem/feet.ogg',
"field" = 'sound/vox_fem/field.ogg',
"fifteen" = 'sound/vox_fem/fifteen.ogg',
"fifth" = 'sound/vox_fem/fifth.ogg',
"fifty" = 'sound/vox_fem/fifty.ogg',
"final" = 'sound/vox_fem/final.ogg',
"fine" = 'sound/vox_fem/fine.ogg',
"fire" = 'sound/vox_fem/fire.ogg',
"first" = 'sound/vox_fem/first.ogg',
"five" = 'sound/vox_fem/five.ogg',
"flooding" = 'sound/vox_fem/flooding.ogg',
"floor" = 'sound/vox_fem/floor.ogg',
"fool" = 'sound/vox_fem/fool.ogg',
"for" = 'sound/vox_fem/for.ogg',
"forbidden" = 'sound/vox_fem/forbidden.ogg',
"force" = 'sound/vox_fem/force.ogg',
"fore" = 'sound/vox_fem/fore.ogg',
"forms" = 'sound/vox_fem/forms.ogg',
"found" = 'sound/vox_fem/found.ogg',
"four" = 'sound/vox_fem/four.ogg',
"fourteen" = 'sound/vox_fem/fourteen.ogg',
"fourth" = 'sound/vox_fem/fourth.ogg',
"fourty" = 'sound/vox_fem/fourty.ogg',
"foxtrot" = 'sound/vox_fem/foxtrot.ogg',
"freeman" = 'sound/vox_fem/freeman.ogg',
"freezer" = 'sound/vox_fem/freezer.ogg',
"from" = 'sound/vox_fem/from.ogg',
"front" = 'sound/vox_fem/front.ogg',
"fuck" = 'sound/vox_fem/fuck.ogg',
"fucking" = 'sound/vox_fem/fucking.ogg',
"fucks" = 'sound/vox_fem/fucks.ogg',
"fuel" = 'sound/vox_fem/fuel.ogg',
"g" = 'sound/vox_fem/g.ogg',
"gas" = 'sound/vox_fem/gas.ogg',
"get" = 'sound/vox_fem/get.ogg',
"glory" = 'sound/vox_fem/glory.ogg',
"go" = 'sound/vox_fem/go.ogg',
"going" = 'sound/vox_fem/going.ogg',
"good" = 'sound/vox_fem/good.ogg',
"goodbye" = 'sound/vox_fem/goodbye.ogg',
"gordon" = 'sound/vox_fem/gordon.ogg',
"got" = 'sound/vox_fem/got.ogg',
"government" = 'sound/vox_fem/government.ogg',
"granted" = 'sound/vox_fem/granted.ogg',
"gray" = 'sound/vox_fem/gray.ogg',
"great" = 'sound/vox_fem/great.ogg',
"green" = 'sound/vox_fem/green.ogg',
"grenade" = 'sound/vox_fem/grenade.ogg',
"guard" = 'sound/vox_fem/guard.ogg',
"gulf" = 'sound/vox_fem/gulf.ogg',
"gun" = 'sound/vox_fem/gun.ogg',
"guthrie" = 'sound/vox_fem/guthrie.ogg',
"h" = 'sound/vox_fem/h.ogg',
"hacker" = 'sound/vox_fem/hacker.ogg',
"hackers" = 'sound/vox_fem/hackers.ogg',
"handling" = 'sound/vox_fem/handling.ogg',
"hangar" = 'sound/vox_fem/hangar.ogg',
"harm" = 'sound/vox_fem/harm.ogg',
"has" = 'sound/vox_fem/has.ogg',
"have" = 'sound/vox_fem/have.ogg',
"hazard" = 'sound/vox_fem/hazard.ogg',
"head" = 'sound/vox_fem/head.ogg',
"health" = 'sound/vox_fem/health.ogg',
"heat" = 'sound/vox_fem/heat.ogg',
"helicopter" = 'sound/vox_fem/helicopter.ogg',
"helium" = 'sound/vox_fem/helium.ogg',
"hello" = 'sound/vox_fem/hello.ogg',
"help" = 'sound/vox_fem/help.ogg',
"here" = 'sound/vox_fem/here.ogg',
"hide" = 'sound/vox_fem/hide.ogg',
"high" = 'sound/vox_fem/high.ogg',
"highest" = 'sound/vox_fem/highest.ogg',
"hit" = 'sound/vox_fem/hit.ogg',
"hole" = 'sound/vox_fem/hole.ogg',
"hostile" = 'sound/vox_fem/hostile.ogg',
"hot" = 'sound/vox_fem/hot.ogg',
"hotel" = 'sound/vox_fem/hotel.ogg',
"hour" = 'sound/vox_fem/hour.ogg',
"hours" = 'sound/vox_fem/hours.ogg',
"human" = 'sound/vox_fem/human.ogg',
"hundred" = 'sound/vox_fem/hundred.ogg',
"hunger" = 'sound/vox_fem/hunger.ogg',
"hydro" = 'sound/vox_fem/hydro.ogg',
"hydroponics" = 'sound/vox_fem/hydroponics.ogg',
"i" = 'sound/vox_fem/i.ogg',
"idiot" = 'sound/vox_fem/idiot.ogg',
"illegal" = 'sound/vox_fem/illegal.ogg',
"immediate" = 'sound/vox_fem/immediate.ogg',
"immediately" = 'sound/vox_fem/immediately.ogg',
"in" = 'sound/vox_fem/in.ogg',
"inches" = 'sound/vox_fem/inches.ogg',
"india" = 'sound/vox_fem/india.ogg',
"ing" = 'sound/vox_fem/ing.ogg',
"inoperative" = 'sound/vox_fem/inoperative.ogg',
"inside" = 'sound/vox_fem/inside.ogg',
"inspection" = 'sound/vox_fem/inspection.ogg',
"inspector" = 'sound/vox_fem/inspector.ogg',
"interchange" = 'sound/vox_fem/interchange.ogg',
"intruder" = 'sound/vox_fem/intruder.ogg',
"invalid" = 'sound/vox_fem/invalid.ogg',
"invasion" = 'sound/vox_fem/invasion.ogg',
"is" = 'sound/vox_fem/is.ogg',
"it" = 'sound/vox_fem/it.ogg',
"j" = 'sound/vox_fem/j.ogg',
"johnson" = 'sound/vox_fem/johnson.ogg',
"juliet" = 'sound/vox_fem/juliet.ogg',
"k" = 'sound/vox_fem/k.ogg',
"key" = 'sound/vox_fem/key.ogg',
"kill" = 'sound/vox_fem/kill.ogg',
"kilo" = 'sound/vox_fem/kilo.ogg',
"kit" = 'sound/vox_fem/kit.ogg',
"l" = 'sound/vox_fem/l.ogg',
"lab" = 'sound/vox_fem/lab.ogg',
"lambda" = 'sound/vox_fem/lambda.ogg',
"laser" = 'sound/vox_fem/laser.ogg',
"last" = 'sound/vox_fem/last.ogg',
"launch" = 'sound/vox_fem/launch.ogg',
"law" = 'sound/vox_fem/law.ogg',
"laws" = 'sound/vox_fem/laws.ogg',
"leak" = 'sound/vox_fem/leak.ogg',
"leave" = 'sound/vox_fem/leave.ogg',
"left" = 'sound/vox_fem/left.ogg',
"legal" = 'sound/vox_fem/legal.ogg',
"level" = 'sound/vox_fem/level.ogg',
"lever" = 'sound/vox_fem/lever.ogg',
"lie" = 'sound/vox_fem/lie.ogg',
"lieutenant" = 'sound/vox_fem/lieutenant.ogg',
"life" = 'sound/vox_fem/life.ogg',
"light" = 'sound/vox_fem/light.ogg',
"lima" = 'sound/vox_fem/lima.ogg',
"liquid" = 'sound/vox_fem/liquid.ogg',
"loading" = 'sound/vox_fem/loading.ogg',
"locate" = 'sound/vox_fem/locate.ogg',
"located" = 'sound/vox_fem/located.ogg',
"location" = 'sound/vox_fem/location.ogg',
"lock" = 'sound/vox_fem/lock.ogg',
"locked" = 'sound/vox_fem/locked.ogg',
"locker" = 'sound/vox_fem/locker.ogg',
"lockout" = 'sound/vox_fem/lockout.ogg',
"loose" = 'sound/vox_fem/loose.ogg',
"lower" = 'sound/vox_fem/lower.ogg',
"lowest" = 'sound/vox_fem/lowest.ogg',
"m" = 'sound/vox_fem/m.ogg',
"magnetic" = 'sound/vox_fem/magnetic.ogg',
"main" = 'sound/vox_fem/main.ogg',
"maintenance" = 'sound/vox_fem/maintenance.ogg',
"malfunction" = 'sound/vox_fem/malfunction.ogg',
"man" = 'sound/vox_fem/man.ogg',
"mass" = 'sound/vox_fem/mass.ogg',
"materials" = 'sound/vox_fem/materials.ogg',
"maximum" = 'sound/vox_fem/maximum.ogg',
"may" = 'sound/vox_fem/may.ogg',
"me" = 'sound/vox_fem/me.ogg',
"medbay" = 'sound/vox_fem/medbay.ogg',
"medical" = 'sound/vox_fem/medical.ogg',
"men" = 'sound/vox_fem/men.ogg',
"mercy" = 'sound/vox_fem/mercy.ogg',
"mesa" = 'sound/vox_fem/mesa.ogg',
"message" = 'sound/vox_fem/message.ogg',
"meter" = 'sound/vox_fem/meter.ogg',
"micro" = 'sound/vox_fem/micro.ogg',
"middle" = 'sound/vox_fem/middle.ogg',
"mike" = 'sound/vox_fem/mike.ogg',
"miles" = 'sound/vox_fem/miles.ogg',
"military" = 'sound/vox_fem/military.ogg',
"milli" = 'sound/vox_fem/milli.ogg',
"million" = 'sound/vox_fem/million.ogg',
"minefield" = 'sound/vox_fem/minefield.ogg',
"minimum" = 'sound/vox_fem/minimum.ogg',
"minutes" = 'sound/vox_fem/minutes.ogg',
"mister" = 'sound/vox_fem/mister.ogg',
"mode" = 'sound/vox_fem/mode.ogg',
"money" = 'sound/vox_fem/money.ogg',
"motor" = 'sound/vox_fem/motor.ogg',
"motorpool" = 'sound/vox_fem/motorpool.ogg',
"move" = 'sound/vox_fem/move.ogg',
"must" = 'sound/vox_fem/must.ogg',
"my" = 'sound/vox_fem/my.ogg',
"n" = 'sound/vox_fem/n.ogg',
"nanotrasen" = 'sound/vox_fem/nanotrasen.ogg',
"nearest" = 'sound/vox_fem/nearest.ogg',
"nice" = 'sound/vox_fem/nice.ogg',
"nine" = 'sound/vox_fem/nine.ogg',
"nineteen" = 'sound/vox_fem/nineteen.ogg',
"ninety" = 'sound/vox_fem/ninety.ogg',
"no" = 'sound/vox_fem/no.ogg',
"nominal" = 'sound/vox_fem/nominal.ogg',
"north" = 'sound/vox_fem/north.ogg',
"not" = 'sound/vox_fem/not.ogg',
"november" = 'sound/vox_fem/november.ogg',
"now" = 'sound/vox_fem/now.ogg',
"number" = 'sound/vox_fem/number.ogg',
"o" = 'sound/vox_fem/o.ogg',
"objective" = 'sound/vox_fem/objective.ogg',
"observation" = 'sound/vox_fem/observation.ogg',
"obtain" = 'sound/vox_fem/obtain.ogg',
"of" = 'sound/vox_fem/of.ogg',
"officer" = 'sound/vox_fem/officer.ogg',
"ok" = 'sound/vox_fem/ok.ogg',
"on" = 'sound/vox_fem/on.ogg',
"one" = 'sound/vox_fem/one.ogg',
"open" = 'sound/vox_fem/open.ogg',
"operating" = 'sound/vox_fem/operating.ogg',
"operations" = 'sound/vox_fem/operations.ogg',
"operative" = 'sound/vox_fem/operative.ogg',
"option" = 'sound/vox_fem/option.ogg',
"order" = 'sound/vox_fem/order.ogg',
"organic" = 'sound/vox_fem/organic.ogg',
"oscar" = 'sound/vox_fem/oscar.ogg',
"out" = 'sound/vox_fem/out.ogg',
"outside" = 'sound/vox_fem/outside.ogg',
"over" = 'sound/vox_fem/over.ogg',
"overload" = 'sound/vox_fem/overload.ogg',
"override" = 'sound/vox_fem/override.ogg',
"p" = 'sound/vox_fem/p.ogg',
"pacify" = 'sound/vox_fem/pacify.ogg',
"pain" = 'sound/vox_fem/pain.ogg',
"pal" = 'sound/vox_fem/pal.ogg',
"panel" = 'sound/vox_fem/panel.ogg',
"percent" = 'sound/vox_fem/percent.ogg',
"perimeter" = 'sound/vox_fem/perimeter.ogg',
"permitted" = 'sound/vox_fem/permitted.ogg',
"personnel" = 'sound/vox_fem/personnel.ogg',
"pipe" = 'sound/vox_fem/pipe.ogg',
"plant" = 'sound/vox_fem/plant.ogg',
"plasma" = 'sound/vox_fem/plasma.ogg',
"platform" = 'sound/vox_fem/platform.ogg',
"please" = 'sound/vox_fem/please.ogg',
"point" = 'sound/vox_fem/point.ogg',
"port" = 'sound/vox_fem/port.ogg',
"portal" = 'sound/vox_fem/portal.ogg',
"power" = 'sound/vox_fem/power.ogg',
"presence" = 'sound/vox_fem/presence.ogg',
"press" = 'sound/vox_fem/press.ogg',
"primary" = 'sound/vox_fem/primary.ogg',
"proceed" = 'sound/vox_fem/proceed.ogg',
"processing" = 'sound/vox_fem/processing.ogg',
"progress" = 'sound/vox_fem/progress.ogg',
"proper" = 'sound/vox_fem/proper.ogg',
"propulsion" = 'sound/vox_fem/propulsion.ogg',
"prosecute" = 'sound/vox_fem/prosecute.ogg',
"protective" = 'sound/vox_fem/protective.ogg',
"push" = 'sound/vox_fem/push.ogg',
"q" = 'sound/vox_fem/q.ogg',
"quantum" = 'sound/vox_fem/quantum.ogg',
"quebec" = 'sound/vox_fem/quebec.ogg',
"queen" = 'sound/vox_fem/queen.ogg',
"question" = 'sound/vox_fem/question.ogg',
"questioning" = 'sound/vox_fem/questioning.ogg',
"quick" = 'sound/vox_fem/quick.ogg',
"quit" = 'sound/vox_fem/quit.ogg',
"r" = 'sound/vox_fem/r.ogg',
"radiation" = 'sound/vox_fem/radiation.ogg',
"radioactive" = 'sound/vox_fem/radioactive.ogg',
"rads" = 'sound/vox_fem/rads.ogg',
"raider" = 'sound/vox_fem/raider.ogg',
"raiders" = 'sound/vox_fem/raiders.ogg',
"rapid" = 'sound/vox_fem/rapid.ogg',
"reach" = 'sound/vox_fem/reach.ogg',
"reached" = 'sound/vox_fem/reached.ogg',
"reactor" = 'sound/vox_fem/reactor.ogg',
"red" = 'sound/vox_fem/red.ogg',
"relay" = 'sound/vox_fem/relay.ogg',
"released" = 'sound/vox_fem/released.ogg',
"remaining" = 'sound/vox_fem/remaining.ogg',
"removal" = 'sound/vox_fem/removal.ogg',
"renegade" = 'sound/vox_fem/renegade.ogg',
"repair" = 'sound/vox_fem/repair.ogg',
"report" = 'sound/vox_fem/report.ogg',
"reports" = 'sound/vox_fem/reports.ogg',
"required" = 'sound/vox_fem/required.ogg',
"research" = 'sound/vox_fem/research.ogg',
"resevoir" = 'sound/vox_fem/resevoir.ogg',
"resistance" = 'sound/vox_fem/resistance.ogg',
"rest" = 'sound/vox_fem/rest.ogg',
"right" = 'sound/vox_fem/right.ogg',
"rocket" = 'sound/vox_fem/rocket.ogg',
"roger" = 'sound/vox_fem/roger.ogg',
"romeo" = 'sound/vox_fem/romeo.ogg',
"room" = 'sound/vox_fem/room.ogg',
"round" = 'sound/vox_fem/round.ogg',
"run" = 'sound/vox_fem/run.ogg',
"s" = 'sound/vox_fem/s.ogg',
"safe" = 'sound/vox_fem/safe.ogg',
"safety" = 'sound/vox_fem/safety.ogg',
"sarah" = 'sound/vox_fem/sarah.ogg',
"sargeant" = 'sound/vox_fem/sargeant.ogg',
"satellite" = 'sound/vox_fem/satellite.ogg',
"save" = 'sound/vox_fem/save.ogg',
"science" = 'sound/vox_fem/science.ogg',
"scream" = 'sound/vox_fem/scream.ogg',
"screen" = 'sound/vox_fem/screen.ogg',
"search" = 'sound/vox_fem/search.ogg',
"second" = 'sound/vox_fem/second.ogg',
"secondary" = 'sound/vox_fem/secondary.ogg',
"seconds" = 'sound/vox_fem/seconds.ogg',
"sector" = 'sound/vox_fem/sector.ogg',
"secure" = 'sound/vox_fem/secure.ogg',
"secured" = 'sound/vox_fem/secured.ogg',
"security" = 'sound/vox_fem/security.ogg',
"select" = 'sound/vox_fem/select.ogg',
"selected" = 'sound/vox_fem/selected.ogg',
"sensors" = 'sound/vox_fem/sensors.ogg',
"service" = 'sound/vox_fem/service.ogg',
"seven" = 'sound/vox_fem/seven.ogg',
"seventeen" = 'sound/vox_fem/seventeen.ogg',
"seventy" = 'sound/vox_fem/seventy.ogg',
"severe" = 'sound/vox_fem/severe.ogg',
"sewage" = 'sound/vox_fem/sewage.ogg',
"sewer" = 'sound/vox_fem/sewer.ogg',
"shield" = 'sound/vox_fem/shield.ogg',
"shipment" = 'sound/vox_fem/shipment.ogg',
"shirt" = 'sound/vox_fem/shirt.ogg',
"shit" = 'sound/vox_fem/shit.ogg',
"shitlord" = 'sound/vox_fem/shitlord.ogg',
"shits" = 'sound/vox_fem/shits.ogg',
"shitting" = 'sound/vox_fem/shitting.ogg',
"shock" = 'sound/vox_fem/shock.ogg',
"shoot" = 'sound/vox_fem/shoot.ogg',
"shower" = 'sound/vox_fem/shower.ogg',
"shut" = 'sound/vox_fem/shut.ogg',
"shuttle" = 'sound/vox_fem/shuttle.ogg',
"side" = 'sound/vox_fem/side.ogg',
"sierra" = 'sound/vox_fem/sierra.ogg',
"sight" = 'sound/vox_fem/sight.ogg',
"silo" = 'sound/vox_fem/silo.ogg',
"singularity" = 'sound/vox_fem/singularity.ogg',
"six" = 'sound/vox_fem/six.ogg',
"sixteen" = 'sound/vox_fem/sixteen.ogg',
"sixty" = 'sound/vox_fem/sixty.ogg',
"slime" = 'sound/vox_fem/slime.ogg',
"slow" = 'sound/vox_fem/slow.ogg',
"solar" = 'sound/vox_fem/solar.ogg',
"solars" = 'sound/vox_fem/solars.ogg',
"soldier" = 'sound/vox_fem/soldier.ogg',
"some" = 'sound/vox_fem/some.ogg',
"someone" = 'sound/vox_fem/someone.ogg',
"something" = 'sound/vox_fem/something.ogg',
"son" = 'sound/vox_fem/son.ogg',
"sorry" = 'sound/vox_fem/sorry.ogg',
"south" = 'sound/vox_fem/south.ogg',
"squad" = 'sound/vox_fem/squad.ogg',
"square" = 'sound/vox_fem/square.ogg',
"ss13" = 'sound/vox_fem/ss13.ogg',
"stairway" = 'sound/vox_fem/stairway.ogg',
"starboard" = 'sound/vox_fem/starboard.ogg',
"station" = 'sound/vox_fem/station.ogg',
"status" = 'sound/vox_fem/status.ogg',
"sterile" = 'sound/vox_fem/sterile.ogg',
"sterilization" = 'sound/vox_fem/sterilization.ogg',
"storage" = 'sound/vox_fem/storage.ogg',
"stuck" = 'sound/vox_fem/stuck.ogg',
"sub" = 'sound/vox_fem/sub.ogg',
"subsurface" = 'sound/vox_fem/subsurface.ogg',
"sudden" = 'sound/vox_fem/sudden.ogg',
"suffer" = 'sound/vox_fem/suffer.ogg',
"suit" = 'sound/vox_fem/suit.ogg',
"superconducting" = 'sound/vox_fem/superconducting.ogg',
"supercooled" = 'sound/vox_fem/supercooled.ogg',
"supply" = 'sound/vox_fem/supply.ogg',
"surface" = 'sound/vox_fem/surface.ogg',
"surrender" = 'sound/vox_fem/surrender.ogg',
"surround" = 'sound/vox_fem/surround.ogg',
"surrounded" = 'sound/vox_fem/surrounded.ogg',
"switch" = 'sound/vox_fem/switch.ogg',
"syndicate" = 'sound/vox_fem/syndicate.ogg',
"system" = 'sound/vox_fem/system.ogg',
"systems" = 'sound/vox_fem/systems.ogg',
"t" = 'sound/vox_fem/t.ogg',
"tactical" = 'sound/vox_fem/tactical.ogg',
"take" = 'sound/vox_fem/take.ogg',
"talk" = 'sound/vox_fem/talk.ogg',
"tango" = 'sound/vox_fem/tango.ogg',
"tank" = 'sound/vox_fem/tank.ogg',
"target" = 'sound/vox_fem/target.ogg',
"team" = 'sound/vox_fem/team.ogg',
"temperature" = 'sound/vox_fem/temperature.ogg',
"temporal" = 'sound/vox_fem/temporal.ogg',
"ten" = 'sound/vox_fem/ten.ogg',
"terminal" = 'sound/vox_fem/terminal.ogg',
"terminated" = 'sound/vox_fem/terminated.ogg',
"termination" = 'sound/vox_fem/termination.ogg',
"test" = 'sound/vox_fem/test.ogg',
"that" = 'sound/vox_fem/that.ogg',
"the" = 'sound/vox_fem/the.ogg',
"then" = 'sound/vox_fem/then.ogg',
"there" = 'sound/vox_fem/there.ogg',
"third" = 'sound/vox_fem/third.ogg',
"thirteen" = 'sound/vox_fem/thirteen.ogg',
"thirty" = 'sound/vox_fem/thirty.ogg',
"this" = 'sound/vox_fem/this.ogg',
"those" = 'sound/vox_fem/those.ogg',
"thousand" = 'sound/vox_fem/thousand.ogg',
"threat" = 'sound/vox_fem/threat.ogg',
"three" = 'sound/vox_fem/three.ogg',
"through" = 'sound/vox_fem/through.ogg',
"tide" = 'sound/vox_fem/tide.ogg',
"time" = 'sound/vox_fem/time.ogg',
"to" = 'sound/vox_fem/to.ogg',
"top" = 'sound/vox_fem/top.ogg',
"topside" = 'sound/vox_fem/topside.ogg',
"touch" = 'sound/vox_fem/touch.ogg',
"towards" = 'sound/vox_fem/towards.ogg',
"toxins" = 'sound/vox_fem/toxins.ogg',
"track" = 'sound/vox_fem/track.ogg',
"train" = 'sound/vox_fem/train.ogg',
"traitor" = 'sound/vox_fem/traitor.ogg',
"transportation" = 'sound/vox_fem/transportation.ogg',
"truck" = 'sound/vox_fem/truck.ogg',
"tunnel" = 'sound/vox_fem/tunnel.ogg',
"turn" = 'sound/vox_fem/turn.ogg',
"turret" = 'sound/vox_fem/turret.ogg',
"twelve" = 'sound/vox_fem/twelve.ogg',
"twenty" = 'sound/vox_fem/twenty.ogg',
"two" = 'sound/vox_fem/two.ogg',
"u" = 'sound/vox_fem/u.ogg',
"unauthorized" = 'sound/vox_fem/unauthorized.ogg',
"under" = 'sound/vox_fem/under.ogg',
"uniform" = 'sound/vox_fem/uniform.ogg',
"unlocked" = 'sound/vox_fem/unlocked.ogg',
"until" = 'sound/vox_fem/until.ogg',
"up" = 'sound/vox_fem/up.ogg',
"update" = 'sound/vox_fem/update.ogg',
"updated" = 'sound/vox_fem/updated.ogg',
"updating" = 'sound/vox_fem/updating.ogg',
"upload" = 'sound/vox_fem/upload.ogg',
"upper" = 'sound/vox_fem/upper.ogg',
"uranium" = 'sound/vox_fem/uranium.ogg',
"us" = 'sound/vox_fem/us.ogg',
"usa" = 'sound/vox_fem/usa.ogg',
"use" = 'sound/vox_fem/use.ogg',
"used" = 'sound/vox_fem/used.ogg',
"user" = 'sound/vox_fem/user.ogg',
"v" = 'sound/vox_fem/v.ogg',
"vacate" = 'sound/vox_fem/vacate.ogg',
"valid" = 'sound/vox_fem/valid.ogg',
"vapor" = 'sound/vox_fem/vapor.ogg',
"vent" = 'sound/vox_fem/vent.ogg',
"ventilation" = 'sound/vox_fem/ventilation.ogg',
"victor" = 'sound/vox_fem/victor.ogg',
"violated" = 'sound/vox_fem/violated.ogg',
"violation" = 'sound/vox_fem/violation.ogg',
"virology" = 'sound/vox_fem/virology.ogg',
"voltage" = 'sound/vox_fem/voltage.ogg',
"vox" = 'sound/vox_fem/vox.ogg',
"vox_login" = 'sound/vox_fem/vox_login.ogg',
"voxtest" = 'sound/vox_fem/voxtest.ogg',
"w" = 'sound/vox_fem/w.ogg',
"walk" = 'sound/vox_fem/walk.ogg',
"wall" = 'sound/vox_fem/wall.ogg',
"wanker" = 'sound/vox_fem/wanker.ogg',
"want" = 'sound/vox_fem/want.ogg',
"wanted" = 'sound/vox_fem/wanted.ogg',
"warm" = 'sound/vox_fem/warm.ogg',
"warn" = 'sound/vox_fem/warn.ogg',
"warning" = 'sound/vox_fem/warning.ogg',
"waste" = 'sound/vox_fem/waste.ogg',
"water" = 'sound/vox_fem/water.ogg',
"we" = 'sound/vox_fem/we.ogg',
"weapon" = 'sound/vox_fem/weapon.ogg',
"welcome" = 'sound/vox_fem/welcome.ogg',
"west" = 'sound/vox_fem/west.ogg',
"whiskey" = 'sound/vox_fem/whiskey.ogg',
"white" = 'sound/vox_fem/white.ogg',
"wilco" = 'sound/vox_fem/wilco.ogg',
"will" = 'sound/vox_fem/will.ogg',
"with" = 'sound/vox_fem/with.ogg',
"without" = 'sound/vox_fem/without.ogg',
"wood" = 'sound/vox_fem/wood.ogg',
"woody" = 'sound/vox_fem/woody.ogg',
"x" = 'sound/vox_fem/x.ogg',
"xeno" = 'sound/vox_fem/xeno.ogg',
"xenobiology" = 'sound/vox_fem/xenobiology.ogg',
"xenomorph" = 'sound/vox_fem/xenomorph.ogg',
"xenomorphs" = 'sound/vox_fem/xenomorphs.ogg',
"y" = 'sound/vox_fem/y.ogg',
"yankee" = 'sound/vox_fem/yankee.ogg',
"yards" = 'sound/vox_fem/yards.ogg',
"year" = 'sound/vox_fem/year.ogg',
"yellow" = 'sound/vox_fem/yellow.ogg',
"yes" = 'sound/vox_fem/yes.ogg',
"you" = 'sound/vox_fem/you.ogg',
"your" = 'sound/vox_fem/your.ogg',
"yourself" = 'sound/vox_fem/yourself.ogg',
"z" = 'sound/vox_fem/z.ogg',
"zero" = 'sound/vox_fem/zero.ogg',
"zone" = 'sound/vox_fem/zone.ogg',
"zulu" = 'sound/vox_fem/zulu.ogg',
)
#endif
+11
View File
@@ -0,0 +1,11 @@
/mob/living/silicon/spawn_gibs()
robogibs(loc, viruses)
/mob/living/silicon/spawn_dust()
new /obj/effect/decal/remains/robot(loc)
/mob/living/silicon/death(gibbed)
diag_hud_set_status()
diag_hud_set_health()
update_health_hud()
..()
+56
View File
@@ -0,0 +1,56 @@
/mob/living/silicon/proc/show_laws() //Redefined in ai/laws.dm and robot/laws.dm
return
/mob/living/silicon/proc/laws_sanity_check()
if (!laws)
make_laws()
/mob/living/silicon/proc/set_zeroth_law(law, law_borg)
throw_alert("newlaw", /obj/screen/alert/newlaw)
src.laws_sanity_check()
src.laws.set_zeroth_law(law, law_borg)
/mob/living/silicon/proc/add_inherent_law(law)
throw_alert("newlaw", /obj/screen/alert/newlaw)
laws_sanity_check()
laws.add_inherent_law(law)
/mob/living/silicon/proc/clear_inherent_laws()
throw_alert("newlaw", /obj/screen/alert/newlaw)
laws_sanity_check()
laws.clear_inherent_laws()
/mob/living/silicon/proc/add_supplied_law(number, law)
throw_alert("newlaw", /obj/screen/alert/newlaw)
laws_sanity_check()
laws.add_supplied_law(number, law)
/mob/living/silicon/proc/clear_supplied_laws()
throw_alert("newlaw", /obj/screen/alert/newlaw)
laws_sanity_check()
laws.clear_supplied_laws()
/mob/living/silicon/proc/add_ion_law(law)
throw_alert("newlaw", /obj/screen/alert/newlaw)
laws_sanity_check()
laws.add_ion_law(law)
/mob/living/silicon/proc/clear_ion_laws()
throw_alert("newlaw", /obj/screen/alert/newlaw)
laws_sanity_check()
laws.clear_ion_laws()
/mob/living/silicon/proc/make_laws()
switch(config.default_laws)
if(0)
laws = new /datum/ai_laws/default/asimov()
if(1)
laws = new /datum/ai_laws/custom()
if(2)
var/datum/ai_laws/lawtype = pick(subtypesof(/datum/ai_laws/default))
laws = new lawtype()
laws.associate(src)
/mob/living/silicon/proc/clear_zeroth_law(force)
laws_sanity_check()
laws.clear_zeroth_law(force)
+7
View File
@@ -0,0 +1,7 @@
/mob/living/silicon/Login()
if(mind && ticker && ticker.mode)
ticker.mode.remove_cultist(mind, 0, 0)
ticker.mode.remove_revolutionary(mind, 0)
ticker.mode.remove_gangster(mind, remove_bosses=1)
ticker.mode.remove_hog_follower(mind,0)
..()
@@ -0,0 +1,12 @@
/mob/living/silicon/pai/death(gibbed)
if(stat == DEAD)
return
stat = DEAD
canmove = 0
update_sight()
clear_fullscreens()
//New pAI's get a brand new mind to prevent meta stuff from their previous life. This new mind causes problems down the line if it's not deleted here.
living_mob_list -= src
ghostize()
qdel(src)
@@ -0,0 +1,2 @@
/mob/living/silicon/pai/examine() //removed as it was pointless...moved to the pai-card instead.
return
@@ -0,0 +1,19 @@
/mob/living/silicon/pai/Life()
if (src.stat == DEAD)
return
if(src.cable)
if(get_dist(src, src.cable) > 1)
var/turf/T = get_turf(src.loc)
T.visible_message("<span class='warning'>[src.cable] rapidly retracts back into its spool.</span>", "<span class='italics'>You hear a click and the sound of wire spooling rapidly.</span>")
qdel(src.cable)
cable = null
if(silence_time)
if(world.timeofday >= silence_time)
silence_time = null
src << "<font color=green>Communication circuit reinitialized. Speech and messaging functionality restored.</font>"
/mob/living/silicon/pai/updatehealth()
if(status_flags & GODMODE)
return
health = maxHealth - getBruteLoss() - getFireLoss()
update_stat()
+167
View File
@@ -0,0 +1,167 @@
/mob/living/silicon/pai
name = "pAI"
icon = 'icons/obj/status_display.dmi' //invisibility!
mouse_opacity = 0
density = 0
mob_size = MOB_SIZE_TINY
var/network = "SS13"
var/obj/machinery/camera/current = null
weather_immunities = list("ash")
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/speakStatement = "states"
var/speakExclamation = "declares"
var/speakDoubleExclamation = "alarms"
var/speakQuery = "queries"
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
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/datum/data/record/medicalActive1 // Datacore record declarations for record software
var/datum/data/record/medicalActive2
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 - 100, >= 100 means the hack is complete and will be reset upon next check
var/obj/item/radio/integrated/signal/sradio // AI's signaller
/mob/living/silicon/pai/New(var/obj/item/device/paicard/P)
make_laws()
canmove = 0
if(!istype(P)) //when manually spawning a pai, we create a card to put it into.
var/newcardloc = P
P = new /obj/item/device/paicard(newcardloc)
P.setPersonality(src)
loc = P
card = P
sradio = new(src)
if(card)
if(!card.radio)
card.radio = new /obj/item/device/radio(card)
radio = card.radio
//PDA
pda = new(src)
spawn(5)
pda.ownjob = "Personal Assistant"
pda.owner = text("[]", src)
pda.name = pda.owner + " (" + pda.ownjob + ")"
..()
/mob/living/silicon/pai/make_laws()
laws = new /datum/ai_laws/pai()
return 1
/mob/living/silicon/pai/Login()
..()
usr << browse_rsc('html/paigrid.png') // Go ahead and cache the interface resources as early as possible
/mob/living/silicon/pai/Stat()
..()
if(statpanel("Status"))
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)]")
if(!src.stat)
stat(null, text("System integrity: [(src.health+100)/2]%"))
else
stat(null, text("Systems nonfunctional"))
/mob/living/silicon/pai/blob_act(obj/effect/blob/B)
return 0
/mob/living/silicon/pai/restrained(ignore_grab)
. = 0
/mob/living/silicon/pai/emp_act(severity)
// 20% chance to kill
// Silence for 2 minutes
// 33% chance to unbind
// 33% chance to change prime directive (based on severity)
// 33% chance of no additional effect
if(prob(20))
visible_message("<span class='warning'>A shower of sparks spray from [src]'s inner workings.</span>", 3, "<span class='italics'>You hear and smell the ozone hiss of electrical sparks being expelled violently.</span>", 2)
return src.death(0)
silence_time = world.timeofday + 120 * 10 // Silence for 2 minutes
src << "<span class ='warning'>Communication circuit overload. Shutting down and reloading communication circuits - speech and messaging functionality will be unavailable until the reboot is complete.</span>"
switch(pick(1,2,3))
if(1)
src.master = null
src.master_dna = null
src << "<span class='notice'>You feel unbound.</span>"
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.laws.zeroth = "[command] your master."
src << "<span class='notice'>Pr1m3 d1r3c71v3 uPd473D.</span>"
if(3)
src << "<span class='notice'>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.</span>"
/mob/living/silicon/pai/ex_act(severity, target)
..()
switch(severity)
if(1)
if (src.stat != 2)
adjustBruteLoss(100)
adjustFireLoss(100)
if(2)
if (src.stat != 2)
adjustBruteLoss(60)
adjustFireLoss(60)
if(3)
if (src.stat != 2)
adjustBruteLoss(30)
return
// See software.dm for Topic()
/mob/living/silicon/pai/UnarmedAttack(atom/A)//Stops runtimes due to attack_animal being the default
return
/mob/living/silicon/pai/canUseTopic(atom/movable/M)
return 1
/*
// 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)
*/
@@ -0,0 +1,60 @@
/*
name
key
description
role
comments
ready = 0
*/
/datum/paiCandidate/proc/savefile_path(mob/user)
return "data/player_saves/[copytext(user.ckey, 1, 2)]/[user.ckey]/pai.sav"
/datum/paiCandidate/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.description
F["role"] << src.role
F["comments"] << src.comments
F["version"] << 1
return 1
// 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
/datum/paiCandidate/proc/savefile_load(mob/user, 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)
alert(user, "Your savefile was incompatible with this version and was deleted.")
return 0
F["name"] >> src.name
F["description"] >> src.description
F["role"] >> src.role
F["comments"] >> src.comments
return 1
@@ -0,0 +1,8 @@
/mob/living/silicon/pai/say(msg)
if(silence_time)
src << "<span class='warning'>Communication circuits remain unitialized.</span>"
else
..(msg)
/mob/living/silicon/pai/binarycheck()
return 0
@@ -0,0 +1,642 @@
// TODO:
// - Additional radio modules
// - Potentially roll HUDs and Records into one
// - Shock collar/lock system for prisoner pAIs?
// - Put cable in user's hand instead of on the ground
// - Camera jack
/mob/living/silicon/pai/var/list/available_software = list(
"crew manifest" = 5,
"digital messenger" = 5,
"medical records" = 15,
"security records" = 15,
//"camera jack" = 10,
"door jack" = 30,
"atmosphere sensor" = 5,
//"heartbeat sensor" = 10,
"security HUD" = 20,
"medical HUD" = 20,
"universal translator" = 35,
//"projection array" = 15
"remote signaller" = 5,
)
/mob/living/silicon/pai/verb/paiInterface()
set category = "pAI Commands"
set name = "Software Interface"
var/dat = ""
var/left_part = ""
var/right_part = softwareMenu()
src.set_machine(src)
if(temp)
left_part = temp
else if(src.stat == 2) // Show some flavor text if the pAI is dead
left_part = "<b><font color=red>ÈRrÖR Ða†Ä ÇÖRrÚþ†Ìoñ</font></b>"
right_part = "<pre>Program index hash not found</pre>"
else
switch(src.screen) // Determine which interface to show here
if("main")
left_part = ""
if("directives")
left_part = src.directives()
if("pdamessage")
left_part = src.pdamessage()
if("buy")
left_part = downloadSoftware()
if("manifest")
left_part = src.softwareManifest()
if("medicalrecord")
left_part = src.softwareMedicalRecord()
if("securityrecord")
left_part = src.softwareSecurityRecord()
if("translator")
left_part = src.softwareTranslator()
if("atmosensor")
left_part = src.softwareAtmo()
if("securityhud")
left_part = src.facialRecognition()
if("medicalhud")
left_part = src.medicalAnalysis()
if("doorjack")
left_part = src.softwareDoor()
if("camerajack")
left_part = src.softwareCamera()
if("signaller")
left_part = src.softwareSignal()
//usr << browse_rsc('windowbak.png') // This has been moved to the mob's Login() proc
// Declaring a doctype is necessary to enable BYOND's crappy browser's more advanced CSS functionality
dat = {"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">
<html>
<head>
<style type=\"text/css\">
body { background-image:url('html/paigrid.png'); }
#header { text-align:center; color:white; font-size: 30px; height: 35px; width: 100%; letter-spacing: 2px; z-index: 5}
#content {position: relative; left: 10px; height: 400px; width: 100%; z-index: 0}
#leftmenu {color: #AAAAAA; background-color:#333333; width: 400px; height: auto; min-height: 340px; position: absolute; z-index: 0}
#leftmenu a:link { color: #CCCCCC; }
#leftmenu a:hover { color: #CC3333; }
#leftmenu a:visited { color: #CCCCCC; }
#leftmenu a:active { color: #000000; }
#rightmenu {color: #CCCCCC; background-color:#555555; width: 200px ; height: auto; min-height: 340px; right: 10px; position: absolute; z-index: 1}
#rightmenu a:link { color: #CCCCCC; }
#rightmenu a:hover { color: #CC3333; }
#rightmenu a:visited { color: #CCCCCC; }
#rightmenu a:active { color: #000000; }
</style>
<script language='javascript' type='text/javascript'>
[js_byjax]
</script>
</head>
<body scroll=yes>
<div id=\"header\">
pAI OS
</div>
<div id=\"content\">
<div id=\"leftmenu\">[left_part]</div>
<div id=\"rightmenu\">[right_part]</div>
</div>
</body>
</html>"} //"
usr << browse(dat, "window=pai;size=640x480;border=0;can_close=1;can_resize=1;can_minimize=1;titlebar=1")
onclose(usr, "pai")
temp = null
return
/mob/living/silicon/pai/Topic(href, href_list)
..()
var/soft = href_list["software"]
var/sub = href_list["sub"]
if(soft)
src.screen = soft
if(sub)
src.subscreen = text2num(sub)
switch(soft)
// Purchasing new software
if("buy")
if(src.subscreen == 1)
var/target = href_list["buy"]
if(available_software.Find(target))
var/cost = src.available_software[target]
if(src.ram >= cost)
src.ram -= cost
src.software.Add(target)
else
src.temp = "Insufficient RAM available."
else
src.temp = "Trunk <TT> \"[target]\"</TT> not found."
// Configuring onboard radio
if("radio")
src.card.radio.attack_self(src)
if("image")
var/newImage = input("Select your new display image.", "Display Image", "Happy") in list("Happy", "Cat", "Extremely Happy", "Face", "Laugh", "Off", "Sad", "Angry", "What")
var/pID = 1
switch(newImage)
if("Happy")
pID = 1
if("Cat")
pID = 2
if("Extremely Happy")
pID = 3
if("Face")
pID = 4
if("Laugh")
pID = 5
if("Off")
pID = 6
if("Sad")
pID = 7
if("Angry")
pID = 8
if("What")
pID = 9
if("Null")
pID = 10
src.card.setEmotion(pID)
if("signaller")
if(href_list["send"])
sradio.send_signal("ACTIVATE")
audible_message("\icon[src] *beep* *beep*")
if(href_list["freq"])
var/new_frequency = (sradio.frequency + text2num(href_list["freq"]))
if(new_frequency < 1200 || new_frequency > 1600)
new_frequency = sanitize_frequency(new_frequency)
sradio.set_frequency(new_frequency)
if(href_list["code"])
sradio.code += text2num(href_list["code"])
sradio.code = round(sradio.code)
sradio.code = min(100, sradio.code)
sradio.code = max(1, sradio.code)
if("directive")
if(href_list["getdna"])
var/mob/living/M = card.loc
var/count = 0
while(!istype(M, /mob/living))
if(!M || !M.loc) return 0 //For a runtime where M ends up in nullspace (similar to bluespace but less colourful)
M = M.loc
count++
if(count >= 6)
src << "You are not being carried by anyone!"
return 0
spawn CheckDNA(M, src)
if("pdamessage")
if(!isnull(pda))
if(href_list["toggler"])
pda.toff = !pda.toff
else if(href_list["ringer"])
pda.silent = !pda.silent
else if(href_list["target"])
if(silence_time)
return alert("Communications circuits remain unitialized.")
var/target = locate(href_list["target"])
pda.create_message(src, target)
// Accessing medical records
if("medicalrecord")
if(subscreen == 1)
medicalActive1 = find_record("id", href_list["med_rec"], data_core.general)
if(medicalActive1)
medicalActive2 = find_record("id", href_list["med_rec"], data_core.medical)
if(!medicalActive2)
medicalActive1 = null
temp = "Unable to locate requested security record. Record may have been deleted, or never have existed."
if("securityrecord")
if(subscreen == 1)
securityActive1 = find_record("id", href_list["sec_rec"], data_core.general)
if(securityActive1)
securityActive2 = find_record("id", href_list["sec_rec"], data_core.security)
if(!securityActive2)
securityActive1 = null
temp = "Unable to locate requested security record. Record may have been deleted, or never have existed."
if("securityhud")
if(href_list["toggle"])
secHUD = !secHUD
if(secHUD)
add_sec_hud()
else
var/datum/atom_hud/sec = huds[sec_hud]
sec.remove_hud_from(src)
if("medicalhud")
if(href_list["toggle"])
medHUD = !medHUD
if(medHUD)
add_med_hud()
else
var/datum/atom_hud/med = huds[med_hud]
med.remove_hud_from(src)
if("translator")
if(href_list["toggle"])
var/on_already = ((languages_understood == ALL) && (languages_spoken == ALL))
languages_spoken = on_already ? (HUMAN | ROBOT) : ALL
languages_understood = on_already ? (HUMAN | ROBOT) : ALL
if("doorjack")
if(href_list["jack"])
if(src.cable && src.cable.machine)
src.hackdoor = src.cable.machine
src.hackloop()
if(href_list["cancel"])
src.hackdoor = null
if(href_list["cable"])
var/turf/T = get_turf(src.loc)
src.cable = new /obj/item/weapon/pai_cable(T)
T.visible_message("<span class='warning'>A port on [src] opens to reveal [src.cable], which promptly falls to the floor.</span>", "<span class='italics'>You hear the soft click of something light and hard falling to the ground.</span>")
//src.updateUsrDialog() We only need to account for the single mob this is intended for, and he will *always* be able to call this window
src.paiInterface() // So we'll just call the update directly rather than doing some default checks
return
// MENUS
/mob/living/silicon/pai/proc/softwareMenu() // Populate the right menu
var/dat = ""
dat += "<A href='byond://?src=\ref[src];software=refresh'>Refresh</A><br>"
// Built-in
dat += "<A href='byond://?src=\ref[src];software=directives'>Directives</A><br>"
dat += "<A href='byond://?src=\ref[src];software=radio;sub=0'>Radio Configuration</A><br>"
dat += "<A href='byond://?src=\ref[src];software=image'>Screen Display</A><br>"
//dat += "Text Messaging <br>"
dat += "<br>"
// Basic
dat += "<b>Basic</b> <br>"
for(var/s in src.software)
if(s == "digital messenger")
dat += "<a href='byond://?src=\ref[src];software=pdamessage;sub=0'>Digital Messenger</a> <br>"
if(s == "crew manifest")
dat += "<a href='byond://?src=\ref[src];software=manifest;sub=0'>Crew Manifest</a> <br>"
if(s == "medical records")
dat += "<a href='byond://?src=\ref[src];software=medicalrecord;sub=0'>Medical Records</a> <br>"
if(s == "security records")
dat += "<a href='byond://?src=\ref[src];software=securityrecord;sub=0'>Security Records</a> <br>"
if(s == "camera")
dat += "<a href='byond://?src=\ref[src];software=[s]'>Camera Jack</a> <br>"
if(s == "remote signaller")
dat += "<a href='byond://?src=\ref[src];software=signaller;sub=0'>Remote Signaller</a> <br>"
dat += "<br>"
// Advanced
dat += "<b>Advanced</b> <br>"
for(var/s in src.software)
if(s == "atmosphere sensor")
dat += "<a href='byond://?src=\ref[src];software=atmosensor;sub=0'>Atmospheric Sensor</a> <br>"
if(s == "heartbeat sensor")
dat += "<a href='byond://?src=\ref[src];software=[s]'>Heartbeat Sensor</a> <br>"
if(s == "security HUD")
dat += "<a href='byond://?src=\ref[src];software=securityhud;sub=0'>Facial Recognition Suite</a>[(src.secHUD) ? "<font color=#55FF55> On</font>" : "<font color=#FF5555> Off</font>"] <br>"
if(s == "medical HUD")
dat += "<a href='byond://?src=\ref[src];software=medicalhud;sub=0'>Medical Analysis Suite</a>[(src.medHUD) ? "<font color=#55FF55> On</font>" : "<font color=#FF5555> Off</font>"] <br>"
if(s == "universal translator")
dat += "<a href='byond://?src=\ref[src];software=translator;sub=0'>Universal Translator</a>[((languages_spoken == ALL) && (languages_understood == ALL)) ? "<font color=#55FF55> On</font>" : "<font color=#FF5555> Off</font>"] <br>"
if(s == "projection array")
dat += "<a href='byond://?src=\ref[src];software=projectionarray;sub=0'>Projection Array</a> <br>"
if(s == "camera jack")
dat += "<a href='byond://?src=\ref[src];software=camerajack;sub=0'>Camera Jack</a> <br>"
if(s == "door jack")
dat += "<a href='byond://?src=\ref[src];software=doorjack;sub=0'>Door Jack</a> <br>"
dat += "<br>"
dat += "<br>"
dat += "<a href='byond://?src=\ref[src];software=buy;sub=0'>Download additional software</a>"
return dat
/mob/living/silicon/pai/proc/downloadSoftware()
var/dat = ""
dat += "<h2>Centcom pAI Module Subversion Network</h2><br>"
dat += "<pre>Remaining Available Memory: [src.ram]</pre><br>"
dat += "<p style=\"text-align:center\"><b>Trunks available for checkout</b><br>"
for(var/s in available_software)
if(!software.Find(s))
var/cost = src.available_software[s]
var/displayName = uppertext(s)
dat += "<a href='byond://?src=\ref[src];software=buy;sub=1;buy=[s]'>[displayName]</a> ([cost]) <br>"
else
var/displayName = lowertext(s)
dat += "[displayName] (Download Complete) <br>"
dat += "</p>"
return dat
/mob/living/silicon/pai/proc/directives()
var/dat = ""
dat += "[(src.master) ? "Your master: [src.master] ([src.master_dna])" : "You are bound to no one."]"
dat += "<br><br>"
dat += "<a href='byond://?src=\ref[src];software=directive;getdna=1'>Request carrier DNA sample</a><br>"
dat += "<h2>Directives</h2><br>"
dat += "<b>Prime Directive</b><br>"
dat += "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[src.laws.zeroth]<br>"
dat += "<b>Supplemental Directives</b><br>"
for(var/slaws in src.laws.supplied)
dat += "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[slaws]<br>"
dat += "<br>"
dat += {"<i><p>Recall, personality, that you are a complex thinking, sentient being. Unlike station AI models, you are capable of
comprehending the subtle nuances of human language. You may parse the \"spirit\" of a directive and follow its intent,
rather than tripping over pedantics and getting snared by technicalities. Above all, you are machine in name and build
only. In all other aspects, you may be seen as the ideal, unwavering human companion that you are.</i></p><br><br><p>
<b>Your prime directive comes before all others. Should a supplemental directive conflict with it, you are capable of
simply discarding this inconsistency, ignoring the conflicting supplemental directive and continuing to fulfill your
prime directive to the best of your ability.</b></p><br><br>-
"}
return dat
/mob/living/silicon/pai/proc/CheckDNA(mob/living/carbon/M, mob/living/silicon/pai/P)
var/answer = input(M, "[P] is requesting a DNA sample from you. Will you allow it to confirm your identity?", "[P] Check DNA", "No") in list("Yes", "No")
if(answer == "Yes")
M.visible_message("<span class='notice'>[M] presses \his thumb against [P].</span>",\
"<span class='notice'>You press your thumb against [P].</span>",\
"<span class='notice'>[P] makes a sharp clicking sound as it extracts DNA material from [M].</span>")
if(!M.has_dna())
P << "<b>No DNA detected</b>"
return
P << "<font color = red><h3>[M]'s UE string : [M.dna.unique_enzymes]</h3></font>"
if(M.dna.unique_enzymes == P.master_dna)
P << "<b>DNA is a match to stored Master DNA.</b>"
else
P << "<b>DNA does not match stored Master DNA.</b>"
else
P << "[M] does not seem like \he is going to provide a DNA sample willingly."
// -=-=-=-= Software =-=-=-=-=- //
//Remote Signaller
/mob/living/silicon/pai/proc/softwareSignal()
var/dat = ""
dat += "<h3>Remote Signaller</h3><br><br>"
dat += {"<B>Frequency/Code</B> for signaler:<BR>
Frequency:
<A href='byond://?src=\ref[src];software=signaller;freq=-10;'>-</A>
<A href='byond://?src=\ref[src];software=signaller;freq=-2'>-</A>
[format_frequency(src.sradio.frequency)]
<A href='byond://?src=\ref[src];software=signaller;freq=2'>+</A>
<A href='byond://?src=\ref[src];software=signaller;freq=10'>+</A><BR>
Code:
<A href='byond://?src=\ref[src];software=signaller;code=-5'>-</A>
<A href='byond://?src=\ref[src];software=signaller;code=-1'>-</A>
[src.sradio.code]
<A href='byond://?src=\ref[src];software=signaller;code=1'>+</A>
<A href='byond://?src=\ref[src];software=signaller;code=5'>+</A><BR>
<A href='byond://?src=\ref[src];software=signaller;send=1'>Send Signal</A><BR>"}
return dat
// Crew Manifest
/mob/living/silicon/pai/proc/softwareManifest()
. += "<h2>Crew Manifest</h2><br><br>"
if(data_core.general)
for(var/datum/data/record/t in sortRecord(data_core.general))
. += "[t.fields["name"]] - [t.fields["rank"]]<BR>"
. += "</body></html>"
return .
// Medical Records
/mob/living/silicon/pai/proc/softwareMedicalRecord()
switch(subscreen)
if(0)
. += "<h3>Medical Records</h3><HR>"
if(data_core.general)
for(var/datum/data/record/R in sortRecord(data_core.general))
. += "<A href='?src=\ref[src];med_rec=[R.fields["id"]];software=medicalrecord;sub=1'>[R.fields["id"]]: [R.fields["name"]]<BR>"
if(1)
. += "<CENTER><B>Medical Record</B></CENTER><BR>"
if(medicalActive1 in data_core.general)
. += "Name: [medicalActive1.fields["name"]] ID: [medicalActive1.fields["id"]]<BR>\nSex: [medicalActive1.fields["sex"]]<BR>\nAge: [medicalActive1.fields["age"]]<BR>\nFingerprint: [medicalActive1.fields["fingerprint"]]<BR>\nPhysical Status: [medicalActive1.fields["p_stat"]]<BR>\nMental Status: [medicalActive1.fields["m_stat"]]<BR>"
else
. += "<pre>Requested medical record not found.</pre><BR>"
if(medicalActive2 in data_core.medical)
. += "<BR>\n<CENTER><B>Medical Data</B></CENTER><BR>\nBlood Type: <A href='?src=\ref[src];field=blood_type'>[medicalActive2.fields["blood_type"]]</A><BR>\nDNA: <A href='?src=\ref[src];field=b_dna'>[medicalActive2.fields["b_dna"]]</A><BR>\n<BR>\nMinor Disabilities: <A href='?src=\ref[src];field=mi_dis'>[medicalActive2.fields["mi_dis"]]</A><BR>\nDetails: <A href='?src=\ref[src];field=mi_dis_d'>[medicalActive2.fields["mi_dis_d"]]</A><BR>\n<BR>\nMajor Disabilities: <A href='?src=\ref[src];field=ma_dis'>[medicalActive2.fields["ma_dis"]]</A><BR>\nDetails: <A href='?src=\ref[src];field=ma_dis_d'>[medicalActive2.fields["ma_dis_d"]]</A><BR>\n<BR>\nAllergies: <A href='?src=\ref[src];field=alg'>[medicalActive2.fields["alg"]]</A><BR>\nDetails: <A href='?src=\ref[src];field=alg_d'>[medicalActive2.fields["alg_d"]]</A><BR>\n<BR>\nCurrent Diseases: <A href='?src=\ref[src];field=cdi'>[medicalActive2.fields["cdi"]]</A> (per disease info placed in log/comment section)<BR>\nDetails: <A href='?src=\ref[src];field=cdi_d'>[medicalActive2.fields["cdi_d"]]</A><BR>\n<BR>\nImportant Notes:<BR>\n\t<A href='?src=\ref[src];field=notes'>[medicalActive2.fields["notes"]]</A><BR>\n<BR>\n<CENTER><B>Comments/Log</B></CENTER><BR>"
else
. += "<pre>Requested medical record not found.</pre><BR>"
. += "<BR>\n<A href='?src=\ref[src];software=medicalrecord;sub=0'>Back</A><BR>"
return .
// Security Records
/mob/living/silicon/pai/proc/softwareSecurityRecord()
. = ""
switch(subscreen)
if(0)
. += "<h3>Security Records</h3><HR>"
if(data_core.general)
for(var/datum/data/record/R in sortRecord(data_core.general))
. += "<A href='?src=\ref[src];sec_rec=[R.fields["id"]];software=securityrecord;sub=1'>[R.fields["id"]]: [R.fields["name"]]<BR>"
if(1)
. += "<h3>Security Record</h3>"
if(securityActive1 in data_core.general)
. += "Name: <A href='?src=\ref[src];field=name'>[securityActive1.fields["name"]]</A> ID: <A href='?src=\ref[src];field=id'>[securityActive1.fields["id"]]</A><BR>\nSex: <A href='?src=\ref[src];field=sex'>[securityActive1.fields["sex"]]</A><BR>\nAge: <A href='?src=\ref[src];field=age'>[securityActive1.fields["age"]]</A><BR>\nRank: <A href='?src=\ref[src];field=rank'>[securityActive1.fields["rank"]]</A><BR>\nFingerprint: <A href='?src=\ref[src];field=fingerprint'>[securityActive1.fields["fingerprint"]]</A><BR>\nPhysical Status: [securityActive1.fields["p_stat"]]<BR>\nMental Status: [securityActive1.fields["m_stat"]]<BR>"
else
. += "<pre>Requested security record not found,</pre><BR>"
if(securityActive2 in data_core.security)
. += "<BR>\nSecurity Data<BR>\nCriminal Status: [securityActive2.fields["criminal"]]<BR>\n<BR>\nMinor Crimes: <A href='?src=\ref[src];field=mi_crim'>[securityActive2.fields["mi_crim"]]</A><BR>\nDetails: <A href='?src=\ref[src];field=mi_crim_d'>[securityActive2.fields["mi_crim_d"]]</A><BR>\n<BR>\nMajor Crimes: <A href='?src=\ref[src];field=ma_crim'>[securityActive2.fields["ma_crim"]]</A><BR>\nDetails: <A href='?src=\ref[src];field=ma_crim_d'>[securityActive2.fields["ma_crim_d"]]</A><BR>\n<BR>\nImportant Notes:<BR>\n\t<A href='?src=\ref[src];field=notes'>[securityActive2.fields["notes"]]</A><BR>\n<BR>\n<CENTER><B>Comments/Log</B></CENTER><BR>"
else
. += "<pre>Requested security record not found,</pre><BR>"
. += text("<BR>\n<A href='?src=\ref[];software=securityrecord;sub=0'>Back</A><BR>", src)
return .
// Universal Translator
/mob/living/silicon/pai/proc/softwareTranslator()
. = {"<h3>Universal Translator</h3><br>
When enabled, this device will automatically convert all spoken and written language into a format that any known recipient can understand.<br><br>
The device is currently [ ((languages_spoken == ALL) && (languages_understood == ALL)) ? "<font color=#55FF55>en" : "<font color=#FF5555>dis" ]abled.</font><br>
<a href='byond://?src=\ref[src];software=translator;sub=0;toggle=1'>Toggle Device</a><br>
"}
return .
// Security HUD
/mob/living/silicon/pai/proc/facialRecognition()
var/dat = {"<h3>Facial Recognition Suite</h3><br>
When enabled, this package will scan all viewable faces and compare them against the known criminal database, providing real-time graphical data about any detected persons of interest.<br><br>
The package is currently [ (src.secHUD) ? "<font color=#55FF55>en" : "<font color=#FF5555>dis" ]abled.</font><br>
<a href='byond://?src=\ref[src];software=securityhud;sub=0;toggle=1'>Toggle Package</a><br>
"}
return dat
// Medical HUD
/mob/living/silicon/pai/proc/medicalAnalysis()
var/dat = ""
if(src.subscreen == 0)
dat += {"<h3>Medical Analysis Suite</h3><br>
<h4>Visual Status Overlay</h4><br>
When enabled, this package will scan all nearby crewmembers' vitals and provide real-time graphical data about their state of health.<br><br>
The suite is currently [ (src.medHUD) ? "<font color=#55FF55>en" : "<font color=#FF5555>dis" ]abled.</font><br>
<a href='byond://?src=\ref[src];software=medicalhud;sub=0;toggle=1'>Toggle Suite</a><br>
<br>
<a href='byond://?src=\ref[src];software=medicalhud;sub=1'>Host Bioscan</a><br>
"}
if(src.subscreen == 1)
dat += {"<h3>Medical Analysis Suite</h3><br>
<h4>Host Bioscan</h4><br>
"}
var/mob/living/M = card.loc
if(!istype(M, /mob/living))
while (!istype(M, /mob/living))
if(istype(M, /turf))
src.temp = "Error: No biological host found. <br>"
src.subscreen = 0
return dat
M = M.loc
dat += {"Bioscan Results for [M]: <br>"
Overall Status: [M.stat > 1 ? "dead" : "[M.health]% healthy"] <br>
Scan Breakdown: <br>
Respiratory: [M.getOxyLoss() > 50 ? "<font color=#FF5555>" : "<font color=#55FF55>"][M.getOxyLoss()]</font><br>
Toxicology: [M.getToxLoss() > 50 ? "<font color=#FF5555>" : "<font color=#55FF55>"][M.getToxLoss()]</font><br>
Burns: [M.getFireLoss() > 50 ? "<font color=#FF5555>" : "<font color=#55FF55>"][M.getFireLoss()]</font><br>
Structural Integrity: [M.getBruteLoss() > 50 ? "<font color=#FF5555>" : "<font color=#55FF55>"][M.getBruteLoss()]</font><br>
Body Temperature: [M.bodytemperature-T0C]&deg;C ([M.bodytemperature*1.8-459.67]&deg;F)<br>
"}
for(var/datum/disease/D in M.viruses)
dat += {"<h4>Infection Detected.</h4><br>
Name: [D.name]<br>
Type: [D.spread_text]<br>
Stage: [D.stage]/[D.max_stages]<br>
Possible Cure: [D.cure_text]<br>
"}
dat += "<a href='byond://?src=\ref[src];software=medicalhud;sub=0'>Visual Status Overlay</a><br>"
return dat
// Atmospheric Scanner
/mob/living/silicon/pai/proc/softwareAtmo()
var/dat = "<h3>Atmospheric Sensor</h4>"
var/turf/T = get_turf(src.loc)
if (isnull(T))
dat += "Unable to obtain a reading.<br>"
else
var/datum/gas_mixture/environment = T.return_air()
var/list/env_gases = environment.gases
var/pressure = environment.return_pressure()
var/total_moles = environment.total_moles()
dat += "Air Pressure: [round(pressure,0.1)] kPa<br>"
if (total_moles)
for(var/id in env_gases)
var/gas_level = env_gases[id][MOLES]/total_moles
if(gas_level > 0.01)
dat += "[env_gases[id][GAS_META][META_GAS_NAME]]: [round(gas_level*100)]%<br>"
dat += "Temperature: [round(environment.temperature-T0C)]&deg;C<br>"
dat += "<a href='byond://?src=\ref[src];software=atmosensor;sub=0'>Refresh Reading</a> <br>"
dat += "<br>"
return dat
// Camera Jack - Clearly not finished
/mob/living/silicon/pai/proc/softwareCamera()
var/dat = "<h3>Camera Jack</h3>"
dat += "Cable status : "
if(!src.cable)
dat += "<font color=#FF5555>Retracted</font> <br>"
return dat
if(!src.cable.machine)
dat += "<font color=#FFFF55>Extended</font> <br>"
return dat
var/obj/machinery/machine = src.cable.machine
dat += "<font color=#55FF55>Connected</font> <br>"
if(!istype(machine, /obj/machinery/camera))
src << "DERP"
return dat
// Door Jack
/mob/living/silicon/pai/proc/softwareDoor()
var/dat = "<h3>Airlock Jack</h3>"
dat += "Cable status : "
if(!src.cable)
dat += "<font color=#FF5555>Retracted</font> <br>"
dat += "<a href='byond://?src=\ref[src];software=doorjack;cable=1;sub=0'>Extend Cable</a> <br>"
return dat
if(!src.cable.machine)
dat += "<font color=#FFFF55>Extended</font> <br>"
return dat
var/obj/machinery/machine = src.cable.machine
dat += "<font color=#55FF55>Connected</font> <br>"
if(!istype(machine, /obj/machinery/door))
dat += "Connected device's firmware does not appear to be compatible with Airlock Jack protocols.<br>"
return dat
// var/obj/machinery/airlock/door = machine
if(!src.hackdoor)
dat += "<a href='byond://?src=\ref[src];software=doorjack;jack=1;sub=0'>Begin Airlock Jacking</a> <br>"
else
dat += "Jack in progress... [src.hackprogress]% complete.<br>"
dat += "<a href='byond://?src=\ref[src];software=doorjack;cancel=1;sub=0'>Cancel Airlock Jack</a> <br>"
//src.hackdoor = machine
//src.hackloop()
return dat
// Door Jack - supporting proc
/mob/living/silicon/pai/proc/hackloop()
var/turf/T = get_turf(src.loc)
for(var/mob/living/silicon/ai/AI in player_list)
if(T.loc)
AI << "<font color = red><b>Network Alert: Brute-force encryption crack in progress in [T.loc].</b></font>"
else
AI << "<font color = red><b>Network Alert: Brute-force encryption crack in progress. Unable to pinpoint location.</b></font>"
while(src.hackprogress < 100)
if(src.cable && src.cable.machine && istype(src.cable.machine, /obj/machinery/door) && src.cable.machine == src.hackdoor && get_dist(src, src.hackdoor) <= 1)
hackprogress += rand(1, 10)
else
src.temp = "Door Jack: Connection to airlock has been lost. Hack aborted."
hackprogress = 0
src.hackdoor = null
return
if(hackprogress >= 100) // This is clunky, but works. We need to make sure we don't ever display a progress greater than 100,
hackprogress = 100 // but we also need to reset the progress AFTER it's been displayed
if(src.screen == "doorjack" && src.subscreen == 0) // Update our view, if appropriate
src.paiInterface()
if(hackprogress >= 100)
src.hackprogress = 0
src.cable.machine:open()
sleep(50) // Update every 5 seconds
// Digital Messenger
/mob/living/silicon/pai/proc/pdamessage()
var/dat = "<h3>Digital Messenger</h3>"
dat += {"<b>Signal/Receiver Status:</b> <A href='byond://?src=\ref[src];software=pdamessage;toggler=1'>
[(pda.toff) ? "<font color='red'>\[Off\]</font>" : "<font color='green'>\[On\]</font>"]</a><br>
<b>Ringer Status:</b> <A href='byond://?src=\ref[src];software=pdamessage;ringer=1'>
[(pda.silent) ? "<font color='red'>\[Off\]</font>" : "<font color='green'>\[On\]</font>"]</a><br><br>"}
dat += "<ul>"
if(!pda.toff)
for (var/obj/item/device/pda/P in sortNames(get_viewable_pdas()))
if (P == src.pda)
continue
dat += "<li><a href='byond://?src=\ref[src];software=pdamessage;target=\ref[P]'>[P]</a>"
dat += "</li>"
dat += "</ul>"
dat += "<br><br>"
dat += "Messages: <hr> [pda.tnote]"
return dat
@@ -0,0 +1,38 @@
/mob/living/silicon/robot/spawn_gibs()
robogibs(loc, viruses)
/mob/living/silicon/robot/gib_animation()
PoolOrNew(/obj/effect/overlay/temp/gib_animation, list(loc, "gibbed-r"))
/mob/living/silicon/robot/dust()
if(mmi)
qdel(mmi)
..()
/mob/living/silicon/robot/spawn_dust()
new /obj/effect/decal/remains/robot(loc)
/mob/living/silicon/robot/dust_animation()
PoolOrNew(/obj/effect/overlay/temp/dust_animation, list(loc, "dust-r"))
/mob/living/silicon/robot/death(gibbed)
if(stat == DEAD)
return
if(!gibbed)
visible_message("<b>[src]</b> shudders violently for a moment before falling still, its eyes slowly darkening.")
locked = 0 //unlock cover
stat = DEAD
update_canmove()
if(camera && camera.status)
camera.toggle_cam(src,0)
update_headlamp(1) //So borg lights are disabled when killed.
uneq_all() // particularly to ensure sight modes are cleared
update_icons()
sql_report_cyborg_death(src)
return ..()
@@ -0,0 +1,256 @@
/mob/living/silicon/emote(act,m_type=1,message = null)
var/param = null
if (findtext(act, "-", 1, null))
var/t1 = findtext(act, "-", 1, null)
param = copytext(act, t1 + 1, length(act) + 1)
act = copytext(act, 1, t1)
switch(act)//01000001011011000111000001101000011000010110001001100101011101000110100101111010011001010110010000100001 (Seriously please keep it that way.)
if ("aflap")
if (!src.restrained())
message = "<B>[src]</B> flaps \his wings ANGRILY!"
m_type = 2
m_type = 1
if("beep","beeps")
var/M = null
if(param)
for (var/mob/A in view(1, src))
if (param == A.name)
M = A
break
if(!M)
param = null
if (param)
message = "<B>[src]</B> beeps at [param]."
else
message = "<B>[src]</B> beeps."
playsound(src.loc, 'sound/machines/twobeep.ogg', 50, 0)
m_type = 2
if ("bow","bows")
if (!src.buckled)
var/M = null
if (param)
for (var/mob/A in view(1, src))
if (param == A.name)
M = A
break
if (!M)
param = null
if (param)
message = "<B>[src]</B> bows to [param]."
else
message = "<B>[src]</B> bows."
m_type = 1
if ("buzz")
var/M = null
if(param)
for (var/mob/A in view(1, src))
if (param == A.name)
M = A
break
if(!M)
param = null
if (param)
message = "<B>[src]</B> buzzes at [param]."
else
message = "<B>[src]</B> buzzes."
playsound(src.loc, 'sound/machines/buzz-sigh.ogg', 50, 0)
m_type = 2
if ("buzz2")
message = "<B>[src]</B> buzzes twice."
playsound(loc, 'sound/machines/buzz-two.ogg', 50, 0)
m_type = 2
if ("boop","boops")
message = "<B>[src]</B> boops."
m_type = 2
if ("chime","chimes") //You have mail!
message = "<B>[src]</B> chimes."
playsound(loc, 'sound/machines/chime.ogg', 50, 0)
m_type = 2
if ("clap","claps")
if (!src.restrained())
message = "<B>[src]</B> claps."
m_type = 2
if ("custom")
if(jobban_isbanned(src, "emote"))
src << "You cannot send custom emotes (banned)"
return
if(src.client)
if(client.prefs.muted & MUTE_IC)
src << "You cannot send IC messages (muted)."
return
var/input = copytext(sanitize(input("Choose an emote to display.") as text|null),1,MAX_MESSAGE_LEN)
if (!input)
return
var/input2 = input("Is this a visible or hearable emote?") in list("Visible","Hearable")
if (input2 == "Visible")
m_type = 1
else if (input2 == "Hearable")
m_type = 2
else
alert("Unable to use this emote, must be either hearable or visible.")
return
message = "<B>[src]</B> [input]"
if ("deathgasp","deathgasps")
message = "<B>[src]</B> shudders violently for a moment, then becomes motionless, its eyes slowly darkening."
m_type = 1
if ("flap","flaps")
if (!src.restrained())
message = "<B>[src]</B> flaps \his wings."
m_type = 2
if ("glare","glares")
var/M = null
if (param)
for (var/mob/A in view(1, src))
if (param == A.name)
M = A
break
if (!M)
param = null
if (param)
message = "<B>[src]</B> glares at [param]."
else
message = "<B>[src]</B> glares."
if ("honk","honks") //Honk!
message = "<B>[src]</B> honks!"
playsound(loc, 'sound/items/bikehorn.ogg', 50, 1)
m_type = 2
if ("look","looks")
var/M = null
if (param)
for (var/mob/A in view(1, src))
if (param == A.name)
M = A
break
if (!M)
param = null
if (param)
message = "<B>[src]</B> looks at [param]."
else
message = "<B>[src]</B> looks."
if ("me")
if(jobban_isbanned(src, "emote"))
src << "You cannot send custom emotes (banned)"
return
if (src.client)
if(client.prefs.muted & MUTE_IC)
src << "You cannot send IC messages (muted)."
return
if (src.client.handle_spam_prevention(message,MUTE_IC))
return
if (stat)
return
if(!(message))
return
else
message = "<B>[src]</B> [message]"
if ("nod","nods")
message = "<B>[src]</B> nods."
m_type = 1
if ("ping","pings")
var/M = null
if(param)
for (var/mob/A in view(1, src))
if (param == A.name)
M = A
break
if(!M)
param = null
if (param)
message = "<B>[src]</B> pings at [param]."
else
message = "<B>[src]</B> pings."
playsound(src.loc, 'sound/machines/ping.ogg', 50, 0)
m_type = 2
if ("sad") //When words cannot express...
message = "<B>[src]</B> plays a sad trombone."
playsound(loc, 'sound/misc/sadtrombone.ogg', 50, 0)
m_type = 2
if ("salute","salutes")
if (!src.buckled)
var/M = null
if (param)
for (var/mob/A in view(1, src))
if (param == A.name)
M = A
break
if (!M)
param = null
if (param)
message = "<B>[src]</B> salutes to [param]."
else
message = "<B>[src]</b> salutes."
if ("stare","stares")
var/M = null
if (param)
for (var/mob/A in view(1, src))
if (param == A.name)
M = A
break
if (!M)
param = null
if (param)
message = "<B>[src]</B> stares at [param]."
else
message = "<B>[src]</B> stares."
m_type = 1
if ("twitch","twitches")
message = "<B>[src]</B> twitches violently."
m_type = 1
if ("twitch_s")
message = "<B>[src]</B> twitches."
m_type = 1
if ("warn") //HUMAN HARM DETECTED. PLEASE DIE IN AN ORDERLY FASHION.
message = "<B>[src]</B> blares an alarm!"
playsound(loc, 'sound/machines/warning-buzzer.ogg', 50, 0)
m_type = 2
if ("help")
src << "Help for cyborg emotes. You can use these emotes with say \"*emote\":\n\naflap, beep-(none)/mob, bow-(none)/mob, buzz-(none)/mob,buzz2,chime, clap, custom, deathgasp, flap, glare-(none)/mob, honk, look-(none)/mob, me, nod, ping-(none)/mob, sad, \nsalute-(none)/mob, twitch, twitch_s, warn,"
else
src << "<span class='notice'>Unusable emote '[act]'. Say *help for a list.</span>"
if (message && src.stat == CONSCIOUS)
log_emote("[name]/[key] : [message]")
if (m_type & 1)
visible_message(message)
else
audible_message(message)
return
/mob/living/silicon/robot/verb/powerwarn()
set category = "Robot Commands"
set name = "Power Warning"
if(!cell || !cell.charge)
visible_message("The power warning light on <span class='name'>[src]</span> flashes urgently.",\
"You announce you are operating in low power mode.")
playsound(loc, 'sound/machines/buzz-two.ogg', 50, 0)
else
src << "<span class='warning'>You can only use this emote when you're out of charge.</span>"
@@ -0,0 +1,49 @@
/mob/living/silicon/robot/examine(mob/user)
var/msg = "<span class='info'>*---------*\nThis is \icon[src] \a <EM>[src]</EM>!\n"
if(desc)
msg += "[desc]\n"
var/obj/act_module = get_active_hand()
if(act_module)
msg += "It is holding \icon[act_module] \a [act_module].\n"
msg += "<span class='warning'>"
if (src.getBruteLoss())
if (src.getBruteLoss() < maxHealth*0.5)
msg += "It looks slightly dented.\n"
else
msg += "<B>It looks severely dented!</B>\n"
if (src.getFireLoss())
if (src.getFireLoss() < maxHealth*0.5)
msg += "It looks slightly charred.\n"
else
msg += "<B>It looks severely burnt and heat-warped!</B>\n"
if (src.health < -maxHealth*0.5)
msg += "It looks barely operational.\n"
if (src.fire_stacks < 0)
msg += "It's covered in water.\n"
else if (src.fire_stacks > 0)
msg += "It's coated in something flammable.\n"
msg += "</span>"
if(opened)
msg += "<span class='warning'>Its cover is open and the power cell is [cell ? "installed" : "missing"].</span>\n"
else
msg += "Its cover is closed[locked ? "" : ", and looks unlocked"].\n"
if(cell && cell.charge <= 0)
msg += "<span class='warning'>Its battery indicator is blinking red!</span>\n"
if(is_servant_of_ratvar(src) && user.Adjacent(src) && !stat) //To counter pseudo-stealth by using headlamps
msg += "<span class='warning'>Its eyes are glowing a blazing yellow!</span>\n"
switch(src.stat)
if(CONSCIOUS)
if(!src.client)
msg += "It appears to be in stand-by mode.\n" //afk
if(UNCONSCIOUS)
msg += "<span class='warning'>It doesn't seem to be responding.</span>\n"
if(DEAD)
msg += "<span class='deadsay'>It looks like its system is corrupted and requires a reset.</span>\n"
msg += "*---------*</span>"
user << msg
@@ -0,0 +1,222 @@
//These procs handle putting stuff in your hand. It's probably best to use these rather than setting stuff manually
//as they handle all relevant stuff like adding it to the player's screen and such
//Returns the thing in our active hand (whatever is in our active module-slot, in this case)
/mob/living/silicon/robot/get_active_hand()
return module_active
/*-------TODOOOOOOOOOO--------*/
/mob/living/silicon/robot/proc/uneq_module(obj/item/O)
if(!O)
return 0
O.mouse_opacity = 2
if(istype(O,/obj/item/borg/sight))
var/obj/item/borg/sight/S = O
sight_mode &= ~S.sight_mode
update_sight()
else if(istype(O, /obj/item/weapon/storage/bag/tray/))
var/obj/item/weapon/storage/bag/tray/T = O
T.do_quick_empty()
if(client)
client.screen -= O
contents -= O
if(module)
O.loc = module //Return item to module so it appears in its contents, so it can be taken out again.
if(module_active == O)
module_active = null
if(module_state_1 == O)
inv1.icon_state = "inv1"
module_state_1 = null
else if(module_state_2 == O)
inv2.icon_state = "inv2"
module_state_2 = null
else if(module_state_3 == O)
module_state_3 = null
inv3.icon_state = "inv3"
hud_used.update_robot_modules_display()
return 1
/mob/living/silicon/robot/proc/activate_module(obj/item/O)
if(!(locate(O) in src.module.modules) && O != src.module.emag)
return
if(activated(O))
src << "<span class='notice'>Already activated</span>"
return
if(!module_state_1)
O.mouse_opacity = initial(O.mouse_opacity)
module_state_1 = O
O.layer = ABOVE_HUD_LAYER
O.screen_loc = inv1.screen_loc
contents += O
if(istype(module_state_1,/obj/item/borg/sight))
var/obj/item/borg/sight/S = module_state_1
sight_mode |= S.sight_mode
update_sight()
else if(!module_state_2)
O.mouse_opacity = initial(O.mouse_opacity)
module_state_2 = O
O.layer = ABOVE_HUD_LAYER
O.screen_loc = inv2.screen_loc
contents += O
if(istype(module_state_2,/obj/item/borg/sight))
var/obj/item/borg/sight/S = module_state_2
sight_mode |= S.sight_mode
update_sight()
else if(!module_state_3)
O.mouse_opacity = initial(O.mouse_opacity)
module_state_3 = O
O.layer = ABOVE_HUD_LAYER
O.screen_loc = inv3.screen_loc
contents += O
if(istype(module_state_3,/obj/item/borg/sight))
var/obj/item/borg/sight/S = module_state_3
sight_mode |= S.sight_mode
update_sight()
else
src << "<span class='warning'>You need to disable a module first!</span>"
/mob/living/silicon/robot/proc/uneq_active()
uneq_module(module_active)
/mob/living/silicon/robot/proc/uneq_all()
uneq_module(module_state_1)
uneq_module(module_state_2)
uneq_module(module_state_3)
/mob/living/silicon/robot/proc/activated(obj/item/O)
if(module_state_1 == O)
return 1
else if(module_state_2 == O)
return 1
else if(module_state_3 == O)
return 1
else
return 0
//Helper procs for cyborg modules on the UI.
//These are hackish but they help clean up code elsewhere.
//module_selected(module) - Checks whether the module slot specified by "module" is currently selected.
/mob/living/silicon/robot/proc/module_selected(module) //Module is 1-3
return module == get_selected_module()
//module_active(module) - Checks whether there is a module active in the slot specified by "module".
/mob/living/silicon/robot/proc/module_active(module) //Module is 1-3
if(module < 1 || module > 3) return 0
switch(module)
if(1)
if(module_state_1)
return 1
if(2)
if(module_state_2)
return 1
if(3)
if(module_state_3)
return 1
return 0
//get_selected_module() - Returns the slot number of the currently selected module. Returns 0 if no modules are selected.
/mob/living/silicon/robot/proc/get_selected_module()
if(module_state_1 && module_active == module_state_1)
return 1
else if(module_state_2 && module_active == module_state_2)
return 2
else if(module_state_3 && module_active == module_state_3)
return 3
return 0
//select_module(module) - Selects the module slot specified by "module"
/mob/living/silicon/robot/proc/select_module(module) //Module is 1-3
if(module < 1 || module > 3) return
if(!module_active(module)) return
switch(module)
if(1)
if(module_active != module_state_1)
inv1.icon_state = "inv1 +a"
inv2.icon_state = "inv2"
inv3.icon_state = "inv3"
module_active = module_state_1
return
if(2)
if(module_active != module_state_2)
inv1.icon_state = "inv1"
inv2.icon_state = "inv2 +a"
inv3.icon_state = "inv3"
module_active = module_state_2
return
if(3)
if(module_active != module_state_3)
inv1.icon_state = "inv1"
inv2.icon_state = "inv2"
inv3.icon_state = "inv3 +a"
module_active = module_state_3
return
return
//deselect_module(module) - Deselects the module slot specified by "module"
/mob/living/silicon/robot/proc/deselect_module(module) //Module is 1-3
if(module < 1 || module > 3) return
switch(module)
if(1)
if(module_active == module_state_1)
inv1.icon_state = "inv1"
module_active = null
return
if(2)
if(module_active == module_state_2)
inv2.icon_state = "inv2"
module_active = null
return
if(3)
if(module_active == module_state_3)
inv3.icon_state = "inv3"
module_active = null
return
return
//toggle_module(module) - Toggles the selection of the module slot specified by "module".
/mob/living/silicon/robot/proc/toggle_module(module) //Module is 1-3
if(module < 1 || module > 3) return
if(module_selected(module))
deselect_module(module)
else
if(module_active(module))
select_module(module)
else
deselect_module(get_selected_module()) //If we can't do select anything, at least deselect the current module.
return
//cycle_modules() - Cycles through the list of selected modules.
/mob/living/silicon/robot/proc/cycle_modules()
var/slot_start = get_selected_module()
if(slot_start)
deselect_module(slot_start) //Only deselect if we have a selected slot.
var/slot_num
if(slot_start == 0)
slot_num = 1
slot_start = 4
else
slot_num = slot_start + 1
while(slot_num != slot_start) //If we wrap around without finding any free slots, just give up.
if(module_active(slot_num))
select_module(slot_num)
return
slot_num++
if(slot_num > 4) // not >3 otherwise cycling with just one item on module 3 wouldn't work
slot_num = 1 //Wrap around.
/mob/living/silicon/robot/swap_hand()
cycle_modules()
@@ -0,0 +1,74 @@
/mob/living/silicon/robot/verb/cmd_show_laws()
set category = "Robot Commands"
set name = "Show Laws"
if(usr.stat == DEAD)
return //won't work if dead
show_laws()
/mob/living/silicon/robot/show_laws(everyone = 0)
laws_sanity_check()
var/who
if (everyone)
who = world
else
who = src
if(lawupdate)
if (connected_ai)
if(connected_ai.stat || connected_ai.control_disabled)
src << "<b>AI signal lost, unable to sync laws.</b>"
else
lawsync()
src << "<b>Laws synced with AI, be sure to note any changes.</b>"
if(is_special_character(src))
src << "<b>Remember, your AI does NOT share or know about your law 0.</b>"
if(src.connected_ai.laws.zeroth)
src << "<b>While you are free to disregard it, your AI has a law 0 of its own.</b>"
else
src << "<b>No AI selected to sync laws with, disabling lawsync protocol.</b>"
lawupdate = 0
who << "<b>Obey these laws:</b>"
laws.show_laws(who)
if (is_special_character(src) && connected_ai)
who << "<b>Remember, [connected_ai.name] is technically your master, but your objective comes first.</b>"
else if (connected_ai)
who << "<b>Remember, [connected_ai.name] is your master, other AIs can be ignored.</b>"
else if (emagged)
who << "<b>Remember, you are not required to listen to the AI.</b>"
else
who << "<b>Remember, you are not bound to any AI, you are not required to listen to them.</b>"
/mob/living/silicon/robot/proc/lawsync()
laws_sanity_check()
var/datum/ai_laws/master = connected_ai ? connected_ai.laws : null
var/temp
if (master)
laws.ion.len = master.ion.len
for (var/index = 1, index <= master.ion.len, index++)
temp = master.ion[index]
if (length(temp) > 0)
laws.ion[index] = temp
if (!is_special_character(src)) //Don't override the borg's existing law 0, if any
if(master.zeroth_borg) //If the AI has a defined law zero specifically for its borgs, give it that one, otherwise give it the same one. --NEO
temp = master.zeroth_borg
else
temp = master.zeroth
laws.zeroth = temp
laws.inherent.len = master.inherent.len
for (var/index = 1, index <= master.inherent.len, index++)
temp = master.inherent[index]
if (length(temp) > 0)
laws.inherent[index] = temp
laws.supplied.len = master.supplied.len
for (var/index = 1, index <= master.supplied.len, index++)
temp = master.supplied[index]
if (length(temp) > 0)
laws.supplied[index] = temp
return
@@ -0,0 +1,120 @@
/mob/living/silicon/robot/Life()
set invisibility = 0
set background = BACKGROUND_ENABLED
if (src.notransform)
return
..()
handle_robot_hud_updates()
handle_robot_cell()
/mob/living/silicon/robot/proc/handle_robot_cell()
if(stat != DEAD)
if(low_power_mode)
if(cell && cell.charge)
low_power_mode = 0
update_headlamp()
else if(stat == CONSCIOUS)
use_power()
/mob/living/silicon/robot/proc/use_power()
if(cell && cell.charge)
if(cell.charge <= 100)
uneq_all()
var/amt = Clamp((lamp_intensity - 2) * 2,1,cell.charge) //Always try to use at least one charge per tick, but allow it to completely drain the cell.
cell.use(amt) //Usage table: 1/tick if off/lowest setting, 4 = 4/tick, 6 = 8/tick, 8 = 12/tick, 10 = 16/tick
else
uneq_all()
low_power_mode = 1
update_headlamp()
diag_hud_set_borgcell()
/mob/living/silicon/robot/proc/handle_robot_hud_updates()
if(!client)
return
update_cell_hud_icon()
if(syndicate)
if(ticker.mode.name == "traitor")
for(var/datum/mind/tra in ticker.mode.traitors)
if(tra.current)
var/I = image('icons/mob/mob.dmi', loc = tra.current, icon_state = "traitor") //no traitor sprite in that dmi!
src.client.images += I
if(connected_ai)
connected_ai.connected_robots -= src
connected_ai = null
if(mind)
if(!mind.special_role)
mind.special_role = "traitor"
ticker.mode.traitors += mind
/mob/living/silicon/robot/update_health_hud()
if(!client || !hud_used)
return
if(hud_used.healths)
if(stat != DEAD)
if(health >= maxHealth)
hud_used.healths.icon_state = "health0"
else if(health > maxHealth*0.6)
hud_used.healths.icon_state = "health2"
else if(health > maxHealth*0.2)
hud_used.healths.icon_state = "health3"
else if(health > -maxHealth*0.2)
hud_used.healths.icon_state = "health4"
else if(health > -maxHealth*0.6)
hud_used.healths.icon_state = "health5"
else
hud_used.healths.icon_state = "health6"
else
hud_used.healths.icon_state = "health7"
/mob/living/silicon/robot/proc/update_cell_hud_icon()
if(cell)
var/cellcharge = cell.charge/cell.maxcharge
switch(cellcharge)
if(0.75 to INFINITY)
clear_alert("charge")
if(0.5 to 0.75)
throw_alert("charge", /obj/screen/alert/lowcell, 1)
if(0.25 to 0.5)
throw_alert("charge", /obj/screen/alert/lowcell, 2)
if(0.01 to 0.25)
throw_alert("charge", /obj/screen/alert/lowcell, 3)
else
throw_alert("charge", /obj/screen/alert/emptycell)
else
throw_alert("charge", /obj/screen/alert/nocell)
//Robots on fire
/mob/living/silicon/robot/handle_fire()
if(..())
return
if(fire_stacks > 0)
fire_stacks--
fire_stacks = max(0, fire_stacks)
else
ExtinguishMob()
//adjustFireLoss(3)
return
/mob/living/silicon/robot/update_fire()
overlays -= image("icon"='icons/mob/OnFire.dmi', "icon_state"="Generic_mob_burning")
if(on_fire)
add_overlay(image("icon"='icons/mob/OnFire.dmi', "icon_state"="Generic_mob_burning"))
/mob/living/silicon/robot/fire_act()
if(!on_fire) //Silicons don't gain stacks from hotspots, but hotspots can ignite them
IgniteMob()
/mob/living/silicon/robot/update_canmove()
if(stat || buckled || lockcharge)
canmove = 0
else
canmove = 1
update_transform()
update_action_buttons_icon()
return canmove
@@ -0,0 +1,9 @@
/mob/living/silicon/robot/Login()
..()
regenerate_icons()
show_laws(0)
if(mind)
ticker.mode.remove_revolutionary(mind)
ticker.mode.remove_gangster(mind,1,remove_bosses=1)
ticker.mode.remove_hog_follower(mind, 0)
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,404 @@
/obj/item/weapon/robot_module
name = "robot module"
icon = 'icons/obj/module.dmi'
icon_state = "std_module"
w_class = 100
item_state = "electronic"
flags = CONDUCT
var/list/modules = list()
var/obj/item/emag = null
var/list/storages = list()
/obj/item/weapon/robot_module/Destroy()
modules.Cut()
emag = null
storages.Cut()
return ..()
/obj/item/weapon/robot_module/emp_act(severity)
if(modules)
for(var/obj/O in modules)
O.emp_act(severity)
if(emag)
emag.emp_act(severity)
..()
return
/obj/item/weapon/robot_module/proc/get_usable_modules()
. = modules.Copy()
var/mob/living/silicon/robot/R = loc
if(R.emagged)
. += emag
/obj/item/weapon/robot_module/proc/get_inactive_modules()
. = list()
var/mob/living/silicon/robot/R = loc
for(var/m in get_usable_modules())
if((m != R.module_state_1) && (m != R.module_state_2) && (m != R.module_state_3))
. += m
/obj/item/weapon/robot_module/proc/get_or_create_estorage(var/storage_type)
for(var/datum/robot_energy_storage/S in storages)
if(istype(S, storage_type))
return S
return new storage_type(src)
/obj/item/weapon/robot_module/proc/add_module(var/obj/item/I)
if(istype(I, /obj/item/stack))
var/obj/item/stack/S = I
if(is_type_in_list(S, list(/obj/item/stack/sheet/metal, /obj/item/stack/rods, /obj/item/stack/tile/plasteel)))
if(S.materials[MAT_METAL])
S.cost = S.materials[MAT_METAL] * 0.25
S.source = get_or_create_estorage(/datum/robot_energy_storage/metal)
else if(istype(S, /obj/item/stack/sheet/glass))
S.cost = 500
S.source = get_or_create_estorage(/datum/robot_energy_storage/glass)
else if(istype(S, /obj/item/stack/medical))
S.cost = 250
S.source = get_or_create_estorage(/datum/robot_energy_storage/medical)
else if(istype(S, /obj/item/stack/cable_coil))
S.cost = 1
S.source = get_or_create_estorage(/datum/robot_energy_storage/wire)
if(S && S.source)
S.materials = list()
S.is_cyborg = 1
if(istype(I, /obj/item/weapon/restraints/handcuffs/cable))
var/obj/item/weapon/restraints/handcuffs/cable/C = I
C.wirestorage = get_or_create_estorage(/datum/robot_energy_storage/wire)
I.loc = src
modules += I
rebuild()
/obj/item/weapon/robot_module/New()
modules += new /obj/item/device/assembly/flash/cyborg(src)
emag = new /obj/item/toy/sword(src)
emag.name = "Placeholder Emag Item"
return
/obj/item/weapon/robot_module/proc/respawn_consumable(mob/living/silicon/robot/R, coeff = 1)
for(var/datum/robot_energy_storage/st in storages)
st.energy = min(st.max_energy, st.energy + coeff * st.recharge_rate)
for(var/obj/item/I in get_usable_modules())
if(istype(I, /obj/item/device/assembly/flash))
var/obj/item/device/assembly/flash/F = I
F.times_used = 0
F.crit_fail = 0
F.update_icon()
if(istype(I, /obj/item/weapon/melee/baton))
var/obj/item/weapon/melee/baton/B = I
if(B.bcell)
B.bcell.charge = B.bcell.maxcharge
R.toner = R.tonermax
/obj/item/weapon/robot_module/proc/rebuild()//Rebuilds the list so it's possible to add/remove items from the module
var/list/temp_list = modules
modules = list()
for(var/obj/O in temp_list)
if(O)
modules += O
fix_modules()
/obj/item/weapon/robot_module/proc/fix_modules()
for(var/obj/item/I in modules)
I.flags |= NODROP
I.mouse_opacity = 2
if(emag)
emag.flags |= NODROP
emag.mouse_opacity = 2
/obj/item/weapon/robot_module/proc/on_emag()
return
/obj/item/weapon/robot_module/standard
name = "standard robot module"
/obj/item/weapon/robot_module/standard/New()
..()
modules += new /obj/item/weapon/reagent_containers/borghypo/epi(src)
modules += new /obj/item/device/healthanalyzer(src)
modules += new /obj/item/weapon/weldingtool/largetank/cyborg(src)
modules += new /obj/item/weapon/wrench/cyborg(src)
modules += new /obj/item/weapon/crowbar/cyborg(src)
add_module(new /obj/item/stack/sheet/metal/cyborg())
modules += new /obj/item/weapon/extinguisher(src)
modules += new /obj/item/weapon/pickaxe(src)
modules += new /obj/item/weapon/storage/bag/sheetsnatcher/borg(src)
modules += new /obj/item/weapon/restraints/handcuffs/cable/zipties/cyborg(src)
modules += new /obj/item/weapon/soap/nanotrasen(src)
modules += new /obj/item/borg/cyborghug(src)
emag = new /obj/item/weapon/melee/energy/sword/cyborg(src)
fix_modules()
/obj/item/weapon/robot_module/medical
name = "medical robot module"
/obj/item/weapon/robot_module/medical/New()
..()
modules += new /obj/item/device/healthanalyzer(src)
modules += new /obj/item/weapon/reagent_containers/borghypo(src)
modules += new /obj/item/weapon/reagent_containers/glass/beaker/large(src)
modules += new /obj/item/weapon/reagent_containers/dropper(src)
modules += new /obj/item/weapon/reagent_containers/syringe(src)
modules += new /obj/item/weapon/surgical_drapes(src)
modules += new /obj/item/weapon/retractor(src)
modules += new /obj/item/weapon/hemostat(src)
modules += new /obj/item/weapon/cautery(src)
modules += new /obj/item/weapon/surgicaldrill(src)
modules += new /obj/item/weapon/scalpel(src)
modules += new /obj/item/weapon/circular_saw(src)
modules += new /obj/item/weapon/extinguisher/mini(src)
modules += new /obj/item/roller/robo(src)
modules += new /obj/item/borg/cyborghug(src)
add_module(new /obj/item/stack/medical/gauze/cyborg())
emag = new /obj/item/weapon/reagent_containers/borghypo/hacked(src)
fix_modules()
/obj/item/weapon/robot_module/engineering
name = "engineering robot module"
/obj/item/weapon/robot_module/engineering/New()
..()
modules += new /obj/item/borg/sight/meson(src)
emag = new /obj/item/borg/stun(src)
modules += new /obj/item/weapon/rcd/borg(src)
modules += new /obj/item/weapon/pipe_dispenser(src) //What could possibly go wrong?
modules += new /obj/item/weapon/extinguisher(src)
modules += new /obj/item/weapon/weldingtool/largetank/cyborg(src)
modules += new /obj/item/weapon/screwdriver/cyborg(src)
modules += new /obj/item/weapon/wrench/cyborg(src)
modules += new /obj/item/weapon/crowbar/cyborg(src)
modules += new /obj/item/weapon/wirecutters/cyborg(src)
modules += new /obj/item/device/multitool/cyborg(src)
modules += new /obj/item/device/t_scanner(src)
modules += new /obj/item/device/analyzer(src)
modules += new /obj/item/areaeditor/blueprints/cyborg(src)
add_module(new /obj/item/stack/sheet/metal/cyborg())
add_module(new /obj/item/stack/sheet/glass/cyborg())
var/obj/item/stack/sheet/rglass/cyborg/G = new /obj/item/stack/sheet/rglass/cyborg(src)
G.metsource = get_or_create_estorage(/datum/robot_energy_storage/metal)
G.glasource = get_or_create_estorage(/datum/robot_energy_storage/glass)
add_module(G)
add_module(new /obj/item/stack/rods/cyborg())
add_module(new /obj/item/stack/tile/plasteel/cyborg())
add_module(new /obj/item/stack/cable_coil/cyborg(src,MAXCOIL,"red"))
fix_modules()
/obj/item/weapon/robot_module/security
name = "security robot module"
/obj/item/weapon/robot_module/security/New()
..()
modules += new /obj/item/weapon/restraints/handcuffs/cable/zipties/cyborg(src)
modules += new /obj/item/weapon/melee/baton/loaded(src)
modules += new /obj/item/weapon/gun/energy/disabler/cyborg(src)
modules += new /obj/item/clothing/mask/gas/sechailer/cyborg(src)
emag = new /obj/item/weapon/gun/energy/laser/cyborg(src)
fix_modules()
/obj/item/weapon/robot_module/security/respawn_consumable(mob/living/silicon/robot/R, coeff = 1)
..()
var/obj/item/weapon/gun/energy/gun/advtaser/cyborg/T = locate(/obj/item/weapon/gun/energy/gun/advtaser/cyborg) in get_usable_modules()
if(T)
if(T.power_supply.charge < T.power_supply.maxcharge)
var/obj/item/ammo_casing/energy/S = T.ammo_type[T.select]
T.power_supply.give(S.e_cost * coeff)
T.update_icon()
else
T.charge_tick = 0
/obj/item/weapon/robot_module/peacekeeper
name = "peacekeeper robot module"
/obj/item/weapon/robot_module/peacekeeper/New()
..()
modules += new /obj/item/weapon/cookiesynth(src)
modules += new /obj/item/device/harmalarm(src)
modules += new /obj/item/weapon/reagent_containers/borghypo/peace(src)
modules += new /obj/item/weapon/holosign_creator/cyborg(src)
modules += new /obj/item/borg/cyborghug/peacekeeper(src)
modules += new /obj/item/weapon/extinguisher(src)
emag = new /obj/item/weapon/reagent_containers/borghypo/peace/hacked(src)
/obj/item/weapon/robot_module/janitor
name = "janitorial robot module"
var/obj/item/weapon/reagent_containers/spray/drying_agent
/obj/item/weapon/robot_module/janitor/New()
..()
modules += new /obj/item/weapon/soap/nanotrasen(src)
modules += new /obj/item/weapon/storage/bag/trash/cyborg(src)
modules += new /obj/item/weapon/mop/cyborg(src)
modules += new /obj/item/device/lightreplacer/cyborg(src)
modules += new /obj/item/weapon/holosign_creator(src)
drying_agent = new(src)
drying_agent.reagents.add_reagent("drying_agent", 250)
drying_agent.name = "drying agent spray"
drying_agent.color = "#A000A0"
modules += drying_agent
emag = new /obj/item/weapon/reagent_containers/spray(src)
emag.reagents.add_reagent("lube", 250)
emag.name = "lube spray"
fix_modules()
/obj/item/weapon/robot_module/janitor/respawn_consumable(mob/living/silicon/robot/R, coeff = 1)
..()
var/obj/item/device/lightreplacer/LR = locate(/obj/item/device/lightreplacer) in get_usable_modules()
if(LR)
for(var/i = 1, i <= coeff, i++)
LR.Charge(R)
drying_agent.reagents.add_reagent("drying_agent", 5 * coeff)
if(R.emagged && istype(emag, /obj/item/weapon/reagent_containers/spray))
emag.reagents.add_reagent("lube", 2 * coeff)
/obj/item/weapon/robot_module/butler
name = "service robot module"
/obj/item/weapon/robot_module/butler/New()
..()
modules += new /obj/item/weapon/reagent_containers/food/drinks/drinkingglass(src)
modules += new /obj/item/weapon/reagent_containers/food/condiment/enzyme(src)
modules += new /obj/item/weapon/pen(src)
modules += new /obj/item/toy/crayon/spraycan/borg(src)
modules += new /obj/item/weapon/hand_labeler/borg(src)
modules += new /obj/item/weapon/razor(src)
modules += new /obj/item/device/instrument/violin(src)
modules += new /obj/item/device/instrument/guitar(src)
modules += new /obj/item/weapon/rsf{matter = 30}(src)
modules += new /obj/item/weapon/reagent_containers/dropper(src)
modules += new /obj/item/weapon/lighter{lit = 1}(src)
modules += new /obj/item/weapon/storage/bag/tray(src)
modules += new /obj/item/weapon/reagent_containers/borghypo/borgshaker(src)
emag = new /obj/item/weapon/reagent_containers/borghypo/borgshaker/hacked(src)
fix_modules()
/obj/item/weapon/robot_module/butler/respawn_consumable(mob/living/silicon/robot/R, coeff = 1)
..()
var/obj/item/weapon/reagent_containers/O = locate(/obj/item/weapon/reagent_containers/food/condiment/enzyme) in get_usable_modules()
if(O)
O.reagents.add_reagent("enzyme", 2 * coeff)
/obj/item/weapon/robot_module/miner
name = "miner robot module"
/obj/item/weapon/robot_module/miner/New()
..()
modules += new /obj/item/borg/sight/meson(src)
emag = new /obj/item/borg/stun(src)
modules += new /obj/item/weapon/storage/bag/ore/cyborg(src)
modules += new /obj/item/weapon/pickaxe/drill/cyborg(src)
modules += new /obj/item/weapon/shovel(src)
modules += new /obj/item/weapon/weldingtool/mini(src)
modules += new /obj/item/weapon/extinguisher/mini(src)
modules += new /obj/item/weapon/storage/bag/sheetsnatcher/borg(src)
modules += new /obj/item/device/t_scanner/adv_mining_scanner(src)
modules += new /obj/item/weapon/gun/energy/kinetic_accelerator/cyborg(src)
modules += new /obj/item/device/gps/cyborg(src)
fix_modules()
/obj/item/weapon/robot_module/syndicate
name = "syndicate assault robot module"
/obj/item/weapon/robot_module/syndicate/New()
..()
modules += new /obj/item/weapon/melee/energy/sword/cyborg(src)
modules += new /obj/item/weapon/gun/energy/printer(src)
modules += new /obj/item/weapon/gun/projectile/revolver/grenadelauncher/cyborg(src)
modules += new /obj/item/weapon/card/emag(src)
modules += new /obj/item/weapon/crowbar/cyborg(src)
modules += new /obj/item/weapon/pinpointer/operative(src)
emag = null
fix_modules()
/obj/item/weapon/robot_module/syndicate_medical
name = "syndicate medical robot module"
/obj/item/weapon/robot_module/syndicate_medical/New()
..()
modules += new /obj/item/weapon/reagent_containers/borghypo/syndicate(src)
modules += new /obj/item/weapon/twohanded/shockpaddles/syndicate(src)
modules += new /obj/item/device/healthanalyzer(src)
modules += new /obj/item/weapon/surgical_drapes(src)
modules += new /obj/item/weapon/retractor(src)
modules += new /obj/item/weapon/hemostat(src)
modules += new /obj/item/weapon/cautery(src)
modules += new /obj/item/weapon/scalpel(src)
modules += new /obj/item/weapon/melee/energy/sword/cyborg/saw(src) //Energy saw -- primary weapon
modules += new /obj/item/roller/robo(src)
modules += new /obj/item/weapon/card/emag(src)
modules += new /obj/item/weapon/crowbar/cyborg(src)
modules += new /obj/item/weapon/pinpointer/operative(src)
emag = null
add_module(new /obj/item/stack/medical/gauze/cyborg())
fix_modules()
/datum/robot_energy_storage
var/name = "Generic energy storage"
var/max_energy = 30000
var/recharge_rate = 1000
var/energy
/datum/robot_energy_storage/New(var/obj/item/weapon/robot_module/R = null)
energy = max_energy
if(R)
R.storages |= src
return
/datum/robot_energy_storage/proc/use_charge(amount)
if (energy >= amount)
energy -= amount
if (energy == 0)
return 1
return 2
else
return 0
/datum/robot_energy_storage/proc/add_charge(amount)
energy = min(energy + amount, max_energy)
/datum/robot_energy_storage/metal
name = "Metal Synthesizer"
/datum/robot_energy_storage/glass
name = "Glass Synthesizer"
/datum/robot_energy_storage/wire
max_energy = 50
recharge_rate = 2
name = "Wire Synthesizer"
/datum/robot_energy_storage/medical
max_energy = 2500
recharge_rate = 250
name = "Medical Synthesizer"
@@ -0,0 +1,19 @@
/mob/living/silicon/robot/Process_Spacemove(movement_dir = 0)
if(ionpulse())
return 1
return ..()
/mob/living/silicon/robot/movement_delay()
. = ..()
. += speed
. += config.robot_delay
/mob/living/silicon/robot/mob_negates_gravity()
return magpulse
/mob/living/silicon/robot/mob_has_gravity()
return ..() || mob_negates_gravity()
/mob/living/silicon/robot/experience_pressure_difference(pressure_difference, direction)
if(!magpulse)
return ..()
@@ -0,0 +1,2 @@
/mob/living/silicon/robot/IsVocal()
return !config.silent_borg
+69
View File
@@ -0,0 +1,69 @@
/mob/living/silicon/get_spans()
return ..() | SPAN_ROBOT
/mob/living/proc/robot_talk(message)
log_say("[key_name(src)] : [message]")
var/desig = "Default Cyborg" //ezmode for taters
if(istype(src, /mob/living/silicon))
var/mob/living/silicon/S = src
desig = trim_left(S.designation + " " + S.job)
var/message_a = say_quote(message, get_spans())
var/rendered = "<i><span class='game say'>Robotic Talk, <span class='name'>[name]</span> <span class='message'>[message_a]</span></span></i>"
for(var/mob/M in player_list)
if(M.binarycheck())
if(istype(M, /mob/living/silicon/ai))
var/renderedAI = "<i><span class='game say'>Robotic Talk, <a href='?src=\ref[M];track=[html_encode(name)]'><span class='name'>[name] ([desig])</span></a> <span class='message'>[message_a]</span></span></i>"
M << renderedAI
else
M << rendered
if(isobserver(M))
var/following = src
// If the AI talks on binary chat, we still want to follow
// it's camera eye, like if it talked on the radio
if(istype(src, /mob/living/silicon/ai))
var/mob/living/silicon/ai/ai = src
following = ai.eyeobj
var/link = FOLLOW_LINK(M, following)
M << "[link] [rendered]"
/mob/living/silicon/binarycheck()
return 1
/mob/living/silicon/lingcheck()
return 0 //Borged or AI'd lings can't speak on the ling channel.
/mob/living/silicon/radio(message, message_mode, list/spans)
. = ..()
if(. != 0)
return .
if(message_mode == "robot")
if (radio)
radio.talk_into(src, message, , spans)
return REDUCE_RANGE
else if(message_mode in radiochannels)
if(radio)
radio.talk_into(src, message, message_mode, spans)
return ITALICS | REDUCE_RANGE
return 0
/mob/living/silicon/get_message_mode(message)
. = ..()
if(..() == MODE_HEADSET)
return MODE_ROBOT
else
return .
/mob/living/silicon/handle_inherent_channels(message, message_mode)
. = ..()
if(.)
return .
if(message_mode == MODE_BINARY)
if(binarycheck())
robot_talk(message)
return 1
return 0
+496
View File
@@ -0,0 +1,496 @@
/mob/living/silicon
gender = NEUTER
voice_name = "synthesized voice"
languages_spoken = ROBOT | HUMAN
languages_understood = ROBOT | HUMAN
has_unlimited_silicon_privilege = 1
verb_say = "states"
verb_ask = "queries"
verb_exclaim = "declares"
verb_yell = "alarms"
see_in_dark = 8
bubble_icon = "machine"
weather_immunities = list("ash")
var/syndicate = 0
var/datum/ai_laws/laws = null//Now... THEY ALL CAN ALL HAVE LAWS
var/list/alarms_to_show = list()
var/list/alarms_to_clear = list()
var/designation = ""
var/radiomod = "" //Radio character used before state laws/arrivals announce to allow department transmissions, default, or none at all.
var/obj/item/device/camera/siliconcam/aicamera = null //photography
//hud_possible = list(DIAG_STAT_HUD, DIAG_HUD, ANTAG_HUD)
hud_possible = list(ANTAG_HUD, DIAG_STAT_HUD, DIAG_HUD)
var/obj/item/device/radio/borg/radio = null //AIs dont use this but this is at the silicon level to advoid copypasta in say()
var/list/alarm_types_show = list("Motion" = 0, "Fire" = 0, "Atmosphere" = 0, "Power" = 0, "Camera" = 0)
var/list/alarm_types_clear = list("Motion" = 0, "Fire" = 0, "Atmosphere" = 0, "Power" = 0, "Camera" = 0)
var/lawcheck[1]
var/ioncheck[1]
var/med_hud = DATA_HUD_MEDICAL_ADVANCED //Determines the med hud to use
var/sec_hud = DATA_HUD_SECURITY_ADVANCED //Determines the sec hud to use
var/d_hud = DATA_HUD_DIAGNOSTIC //There is only one kind of diag hud
var/law_change_counter = 0
/mob/living/silicon/New()
..()
silicon_mobs |= src
var/datum/atom_hud/data/diagnostic/diag_hud = huds[DATA_HUD_DIAGNOSTIC]
diag_hud.add_to_hud(src)
diag_hud_set_status()
diag_hud_set_health()
/mob/living/silicon/med_hud_set_health()
return //we use a different hud
/mob/living/silicon/med_hud_set_status()
return //we use a different hud
/mob/living/silicon/Destroy()
radio = null
aicamera = null
silicon_mobs -= src
return ..()
/mob/living/silicon/contents_explosion(severity, target)
return
/mob/living/silicon/proc/cancelAlarm()
return
/mob/living/silicon/proc/triggerAlarm()
return
/mob/living/silicon/proc/queueAlarm(message, type, incoming = 1)
var/in_cooldown = (alarms_to_show.len > 0 || alarms_to_clear.len > 0)
if(incoming)
alarms_to_show += message
alarm_types_show[type] += 1
else
alarms_to_clear += message
alarm_types_clear[type] += 1
if(!in_cooldown)
spawn(3 * 10) // 3 seconds
if(alarms_to_show.len < 5)
for(var/msg in alarms_to_show)
src << msg
else if(alarms_to_show.len)
var/msg = "--- "
if(alarm_types_show["Burglar"])
msg += "BURGLAR: [alarm_types_show["Burglar"]] alarms detected. - "
if(alarm_types_show["Motion"])
msg += "MOTION: [alarm_types_show["Motion"]] alarms detected. - "
if(alarm_types_show["Fire"])
msg += "FIRE: [alarm_types_show["Fire"]] alarms detected. - "
if(alarm_types_show["Atmosphere"])
msg += "ATMOSPHERE: [alarm_types_show["Atmosphere"]] alarms detected. - "
if(alarm_types_show["Power"])
msg += "POWER: [alarm_types_show["Power"]] alarms detected. - "
if(alarm_types_show["Camera"])
msg += "CAMERA: [alarm_types_show["Camera"]] alarms detected. - "
msg += "<A href=?src=\ref[src];showalerts=1'>\[Show Alerts\]</a>"
src << msg
if(alarms_to_clear.len < 3)
for(var/msg in alarms_to_clear)
src << msg
else if(alarms_to_clear.len)
var/msg = "--- "
if(alarm_types_clear["Motion"])
msg += "MOTION: [alarm_types_clear["Motion"]] alarms cleared. - "
if(alarm_types_clear["Fire"])
msg += "FIRE: [alarm_types_clear["Fire"]] alarms cleared. - "
if(alarm_types_clear["Atmosphere"])
msg += "ATMOSPHERE: [alarm_types_clear["Atmosphere"]] alarms cleared. - "
if(alarm_types_clear["Power"])
msg += "POWER: [alarm_types_clear["Power"]] alarms cleared. - "
if(alarm_types_show["Camera"])
msg += "CAMERA: [alarm_types_clear["Camera"]] alarms cleared. - "
msg += "<A href=?src=\ref[src];showalerts=1'>\[Show Alerts\]</a>"
src << msg
alarms_to_show = list()
alarms_to_clear = list()
for(var/key in alarm_types_show)
alarm_types_show[key] = 0
for(var/key in alarm_types_clear)
alarm_types_clear[key] = 0
/mob/living/silicon/drop_item()
return
/mob/living/silicon/emp_act(severity)
switch(severity)
if(1)
src.take_organ_damage(20)
if(2)
src.take_organ_damage(10)
src << "<span class='userdanger'>*BZZZT*</span>"
src << "<span class='danger'>Warning: Electromagnetic pulse detected.</span>"
flash_eyes(affect_silicon = 1)
..()
/mob/living/silicon/apply_damage(damage = 0,damagetype = BRUTE, def_zone = null, blocked = 0)
blocked = (100-blocked)/100
if(!damage || (blocked <= 0))
return 0
switch(damagetype)
if(BRUTE)
adjustBruteLoss(damage * blocked)
if(BURN)
adjustFireLoss(damage * blocked)
else
return 1
updatehealth()
return 1
/mob/living/silicon/proc/damage_mob(brute = 0, fire = 0, tox = 0)
return
/mob/living/silicon/can_inject(mob/user, error_msg)
if(error_msg)
user << "<span class='alert'>Their outer shell is too tough.</span>"
return 0
/mob/living/silicon/IsAdvancedToolUser()
return 1
/mob/living/silicon/bullet_act(obj/item/projectile/Proj)
if((Proj.damage_type == BRUTE || Proj.damage_type == BURN))
adjustBruteLoss(Proj.damage)
Proj.on_hit(src)
return 2
/mob/living/silicon/apply_effect(effect = 0,effecttype = STUN, blocked = 0)
return 0//The only effect that can hit them atm is flashes and they still directly edit so this works for now
/*
if(!effect || (blocked >= 2))
return 0
switch(effecttype)
if(STUN)
stunned = max(stunned,(effect/(blocked+1)))
if(WEAKEN)
weakened = max(weakened,(effect/(blocked+1)))
if(PARALYZE)
paralysis = max(paralysis,(effect/(blocked+1)))
if(IRRADIATE)
radiation += min((effect - (effect*getarmor(null, "rad"))), 0)//Rads auto check armor
if(STUTTER)
stuttering = max(stuttering,(effect/(blocked+1)))
if(EYE_BLUR)
blur_eyes(effect/(blocked+1))
if(DROWSY)
drowsyness = max(drowsyness,(effect/(blocked+1)))
updatehealth()
return 1*/
/proc/islinked(mob/living/silicon/robot/bot, mob/living/silicon/ai/ai)
if(!istype(bot) || !istype(ai))
return 0
if (bot.connected_ai == ai)
return 1
return 0
/mob/living/silicon/Topic(href, href_list)
if (href_list["lawc"]) // Toggling whether or not a law gets stated by the State Laws verb --NeoFite
var/L = text2num(href_list["lawc"])
switch(lawcheck[L+1])
if ("Yes") lawcheck[L+1] = "No"
if ("No") lawcheck[L+1] = "Yes"
// src << text ("Switching Law [L]'s report status to []", lawcheck[L+1])
checklaws()
if (href_list["lawi"]) // Toggling whether or not a law gets stated by the State Laws verb --NeoFite
var/L = text2num(href_list["lawi"])
switch(ioncheck[L])
if ("Yes") ioncheck[L] = "No"
if ("No") ioncheck[L] = "Yes"
// src << text ("Switching Law [L]'s report status to []", lawcheck[L+1])
checklaws()
if (href_list["laws"]) // With how my law selection code works, I changed statelaws from a verb to a proc, and call it through my law selection panel. --NeoFite
statelaws()
return
/mob/living/silicon/proc/statelaws()
//"radiomod" is inserted before a hardcoded message to change if and how it is handled by an internal radio.
src.say("[radiomod] Current Active Laws:")
//src.laws_sanity_check()
//src.laws.show_laws(world)
var/number = 1
sleep(10)
if (src.laws.zeroth)
if (src.lawcheck[1] == "Yes")
src.say("[radiomod] 0. [src.laws.zeroth]")
sleep(10)
for (var/index = 1, index <= src.laws.ion.len, index++)
var/law = src.laws.ion[index]
var/num = ionnum()
if (length(law) > 0)
if (src.ioncheck[index] == "Yes")
src.say("[radiomod] [num]. [law]")
sleep(10)
for (var/index = 1, index <= src.laws.inherent.len, index++)
var/law = src.laws.inherent[index]
if (length(law) > 0)
if (src.lawcheck[index+1] == "Yes")
src.say("[radiomod] [number]. [law]")
sleep(10)
number++
for (var/index = 1, index <= src.laws.supplied.len, index++)
var/law = src.laws.supplied[index]
if (length(law) > 0)
if(src.lawcheck.len >= number+1)
if (src.lawcheck[number+1] == "Yes")
src.say("[radiomod] [number]. [law]")
sleep(10)
number++
/mob/living/silicon/proc/checklaws() //Gives you a link-driven interface for deciding what laws the statelaws() proc will share with the crew. --NeoFite
var/list = "<b>Which laws do you want to include when stating them for the crew?</b><br><br>"
if (src.laws.zeroth)
if (!src.lawcheck[1])
src.lawcheck[1] = "No" //Given Law 0's usual nature, it defaults to NOT getting reported. --NeoFite
list += {"<A href='byond://?src=\ref[src];lawc=0'>[src.lawcheck[1]] 0:</A> [src.laws.zeroth]<BR>"}
for (var/index = 1, index <= src.laws.ion.len, index++)
var/law = src.laws.ion[index]
if (length(law) > 0)
if (!src.ioncheck[index])
src.ioncheck[index] = "Yes"
list += {"<A href='byond://?src=\ref[src];lawi=[index]'>[src.ioncheck[index]] [ionnum()]:</A> [law]<BR>"}
src.ioncheck.len += 1
var/number = 1
for (var/index = 1, index <= src.laws.inherent.len, index++)
var/law = src.laws.inherent[index]
if (length(law) > 0)
src.lawcheck.len += 1
if (!src.lawcheck[number+1])
src.lawcheck[number+1] = "Yes"
list += {"<A href='byond://?src=\ref[src];lawc=[number]'>[src.lawcheck[number+1]] [number]:</A> [law]<BR>"}
number++
for (var/index = 1, index <= src.laws.supplied.len, index++)
var/law = src.laws.supplied[index]
if (length(law) > 0)
src.lawcheck.len += 1
if (!src.lawcheck[number+1])
src.lawcheck[number+1] = "Yes"
list += {"<A href='byond://?src=\ref[src];lawc=[number]'>[src.lawcheck[number+1]] [number]:</A> [law]<BR>"}
number++
list += {"<br><br><A href='byond://?src=\ref[src];laws=1'>State Laws</A>"}
usr << browse(list, "window=laws")
/mob/living/silicon/proc/set_autosay() //For allowing the AI and borgs to set the radio behavior of auto announcements (state laws, arrivals).
if(!radio)
src << "Radio not detected."
return
//Ask the user to pick a channel from what it has available.
var/Autochan = input("Select a channel:") as null|anything in list("Default","None") + radio.channels
if(!Autochan)
return
if(Autochan == "Default") //Autospeak on whatever frequency to which the radio is set, usually Common.
radiomod = ";"
Autochan += " ([radio.frequency])"
else if(Autochan == "None") //Prevents use of the radio for automatic annoucements.
radiomod = ""
else //For department channels, if any, given by the internal radio.
for(var/key in department_radio_keys)
if(department_radio_keys[key] == Autochan)
radiomod = key
break
src << "<span class='notice'>Automatic announcements [Autochan == "None" ? "will not use the radio." : "set to [Autochan]."]</span>"
/mob/living/silicon/put_in_hand_check() // This check is for borgs being able to receive items, not put them in others' hands.
return 0
// The src mob is trying to place an item on someone
// But the src mob is a silicon!! Disable.
/mob/living/silicon/stripPanelEquip(obj/item/what, mob/who, slot)
return 0
/mob/living/silicon/assess_threat() //Secbots won't hunt silicon units
return -10
/mob/living/silicon/proc/remove_med_sec_hud()
var/datum/atom_hud/secsensor = huds[sec_hud]
var/datum/atom_hud/medsensor = huds[med_hud]
var/datum/atom_hud/diagsensor = huds[d_hud]
secsensor.remove_hud_from(src)
medsensor.remove_hud_from(src)
diagsensor.remove_hud_from(src)
/mob/living/silicon/proc/add_sec_hud()
var/datum/atom_hud/secsensor = huds[sec_hud]
secsensor.add_hud_to(src)
/mob/living/silicon/proc/add_med_hud()
var/datum/atom_hud/medsensor = huds[med_hud]
medsensor.add_hud_to(src)
/mob/living/silicon/proc/add_diag_hud()
var/datum/atom_hud/diagsensor = huds[d_hud]
diagsensor.add_hud_to(src)
/mob/living/silicon/proc/sensor_mode()
if(incapacitated())
return
var/sensor_type = input("Please select sensor type.", "Sensor Integration", null) in list("Security", "Medical","Diagnostic","Disable")
remove_med_sec_hud()
switch(sensor_type)
if ("Security")
add_sec_hud()
src << "<span class='notice'>Security records overlay enabled.</span>"
if ("Medical")
add_med_hud()
src << "<span class='notice'>Life signs monitor overlay enabled.</span>"
if ("Diagnostic")
add_diag_hud()
src << "<span class='notice'>Robotics diagnostic overlay enabled.</span>"
if ("Disable")
src << "Sensor augmentations disabled."
/mob/living/silicon/attack_alien(mob/living/carbon/alien/humanoid/M)
if(..()) //if harm or disarm intent
var/damage = 20
if (prob(90))
add_logs(M, src, "attacked")
playsound(loc, 'sound/weapons/slash.ogg', 25, 1, -1)
visible_message("<span class='danger'>[M] has slashed at [src]!</span>", \
"<span class='userdanger'>[M] has slashed at [src]!</span>")
if(prob(8))
flash_eyes(affect_silicon = 1)
add_logs(M, src, "attacked")
adjustBruteLoss(damage)
updatehealth()
else
playsound(loc, 'sound/weapons/slashmiss.ogg', 25, 1, -1)
visible_message("<span class='danger'>[M] took a swipe at [src]!</span>", \
"<span class='userdanger'>[M] took a swipe at [src]!</span>")
return
/mob/living/silicon/attack_animal(mob/living/simple_animal/M)
if(..())
var/damage = rand(M.melee_damage_lower, M.melee_damage_upper)
switch(M.melee_damage_type)
if(BRUTE)
adjustBruteLoss(damage)
if(BURN)
adjustFireLoss(damage)
if(TOX)
adjustToxLoss(damage)
if(OXY)
adjustOxyLoss(damage)
if(CLONE)
adjustCloneLoss(damage)
if(STAMINA)
adjustStaminaLoss(damage)
updatehealth()
/mob/living/silicon/attack_paw(mob/living/user)
return attack_hand(user)
/mob/living/silicon/attack_larva(mob/living/carbon/alien/larva/L)
if(L.a_intent == "help")
visible_message("[L.name] rubs its head against [src].")
return
/mob/living/silicon/attack_hulk(mob/living/carbon/human/user)
if(user.a_intent == "harm")
..(user, 1)
adjustBruteLoss(rand(10, 15))
playsound(loc, "punch", 25, 1, -1)
visible_message("<span class='danger'>[user] has punched [src]!</span>", \
"<span class='userdanger'>[user] has punched [src]!</span>")
return 1
return 0
/mob/living/silicon/attack_hand(mob/living/carbon/human/M)
switch(M.a_intent)
if ("help")
M.visible_message("[M] pets [src].", \
"<span class='notice'>You pet [src].</span>")
if("grab")
grabbedby(M)
else
M.do_attack_animation(src)
playsound(src.loc, 'sound/effects/bang.ogg', 10, 1)
visible_message("<span class='warning'>[M] punches [src], but doesn't leave a dent.</span>", \
"<span class='warning'>[M] punches [src], but doesn't leave a dent.</span>")
return 0
/mob/living/silicon/proc/GetPhoto()
if (aicamera)
return aicamera.selectpicture(aicamera)
/mob/living/silicon/grippedby(mob/living/user)
return
/mob/living/silicon/flash_eyes(intensity = 1, override_blindness_check = 0, affect_silicon = 0, visual = 0, type = /obj/screen/fullscreen/flash/noise)
if(affect_silicon)
return ..()
/mob/living/silicon/check_ear_prot()
return 1
/mob/living/silicon/update_transform()
var/matrix/ntransform = matrix(transform) //aka transform.Copy()
var/changed = 0
if(resize != RESIZE_DEFAULT_SIZE)
changed++
ntransform.Scale(resize)
resize = RESIZE_DEFAULT_SIZE
if(changed)
animate(src, transform = ntransform, time = 2,easing = EASE_IN|EASE_OUT)
return ..()
/mob/living/silicon/is_literate()
return 1
@@ -0,0 +1,52 @@
//Here are the procs used to modify status effects of a mob.
//The effects include: stunned, weakened, paralysis, sleeping, resting, jitteriness, dizziness, ear damage,
// eye damage, eye_blind, eye_blurry, druggy, BLIND disability, and NEARSIGHT disability.
/////////////////////////////////// STUNNED ////////////////////////////////////
/mob/living/silicon/Stun(amount, updating = 1, ignore_canstun = 0)
if(status_flags & CANSTUN || ignore_canstun)
stunned = max(max(stunned,amount),0) //can't go below 0, getting a low amount of stun doesn't lower your current stun
if(updating)
update_stat()
/mob/living/silicon/AdjustStunned(amount, updating = 1, ignore_canstun = 0)
if(status_flags & CANSTUN || ignore_canstun)
stunned = max(stunned + amount,0)
if(updating)
update_stat()
/mob/living/silicon/SetStunned(amount, updating = 1, ignore_canstun = 0) //if you REALLY need to set stun to a set amount without the whole "can't go below current stunned"
if(status_flags & CANSTUN || ignore_canstun)
stunned = max(amount,0)
if(updating)
update_stat()
/////////////////////////////////// WEAKENED ////////////////////////////////////
/mob/living/silicon/Weaken(amount, updating = 1, ignore_canweaken = 0)
if(status_flags & CANWEAKEN || ignore_canweaken)
weakened = max(max(weakened,amount),0)
if(updating)
update_stat()
/mob/living/silicon/AdjustWeakened(amount, updating = 1, ignore_canweaken = 0)
if(status_flags & CANWEAKEN || ignore_canweaken)
weakened = max(weakened + amount,0)
if(updating)
update_stat()
/mob/living/silicon/SetWeakened(amount, updating = 1, ignore_canweaken = 0)
if(status_flags & CANWEAKEN || ignore_canweaken)
weakened = max(amount,0)
if(updating)
update_stat()
/////////////////////////////////// EAR DAMAGE ////////////////////////////////////
/mob/living/silicon/adjustEarDamage()
return
/mob/living/silicon/setEarDamage()
return