initial commit - cross reference with 5th port - obviously has compile errors
This commit is contained in:
@@ -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++
|
||||
|
||||
@@ -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()
|
||||
@@ -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
|
||||
@@ -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()
|
||||
..()
|
||||
@@ -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)
|
||||
@@ -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()
|
||||
@@ -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 += " [src.laws.zeroth]<br>"
|
||||
dat += "<b>Supplemental Directives</b><br>"
|
||||
for(var/slaws in src.laws.supplied)
|
||||
dat += " [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]°C ([M.bodytemperature*1.8-459.67]°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)]°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
|
||||
@@ -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
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user