#define AI_CHECK_WIRELESS 1 #define AI_CHECK_RADIO 2 var/list/ai_list = list() var/list/ai_verbs_default = list( /mob/living/silicon/ai/proc/ai_alerts, /mob/living/silicon/ai/proc/ai_announcement, /mob/living/silicon/ai/proc/ai_call_shuttle, // /mob/living/silicon/ai/proc/ai_recall_shuttle, /mob/living/silicon/ai/proc/ai_camera_track, /mob/living/silicon/ai/proc/ai_camera_list, /mob/living/silicon/ai/proc/ai_goto_location, /mob/living/silicon/ai/proc/ai_remove_location, /mob/living/silicon/ai/proc/ai_hologram_change, /mob/living/silicon/ai/proc/ai_network_change, /mob/living/silicon/ai/proc/ai_roster, /mob/living/silicon/ai/proc/ai_statuschange, /mob/living/silicon/ai/proc/ai_store_location, /mob/living/silicon/ai/proc/ai_checklaws, /mob/living/silicon/ai/proc/control_integrated_radio, /mob/living/silicon/ai/proc/core, /mob/living/silicon/ai/proc/pick_icon, /mob/living/silicon/ai/proc/sensor_mode, /mob/living/silicon/ai/proc/show_laws_verb, /mob/living/silicon/ai/proc/toggle_acceleration, /mob/living/silicon/ai/proc/toggle_camera_light ) //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 // -- TLE density = 1 status_flags = CANSTUN|CANPARALYSE shouldnt_see = list(/obj/effect/rune) var/list/network = list("SS13") var/obj/machinery/camera/camera = null var/list/connected_robots = list() var/aiRestorePowerRoutine = 0 var/viewalerts = 0 var/icon/holo_icon//Default is assigned when AI is created. var/obj/item/device/pda/ai/aiPDA = null var/obj/item/device/multitool/aiMulti = null var/obj/item/device/radio/headset/heads/ai_integrated/aiRadio = null var/custom_sprite = 0 //For our custom sprites //Hud stuff //MALFUNCTION var/datum/AI_Module/module_picker/malf_picker var/processing_time = 100 var/list/datum/AI_Module/current_modules = list() var/fire_res_on_core = 0 var/control_disabled = 0 // Set to 1 to stop AI from interacting via Click() -- TLE 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/obj/machinery/power/apc/malfhack = null var/explosive = 0 //does the AI explode when it dies? var/mob/living/silicon/ai/parent = null var/apc_override = 0 //hack for letting the AI use its APC even when visionless var/camera_light_on = 0 //Defines if the AI toggled the light on the camera it's looking through. var/datum/trackable/track = null var/last_announcement = "" var/datum/announcement/priority/announcement /mob/living/silicon/ai/proc/add_ai_verbs() src.verbs |= ai_verbs_default /mob/living/silicon/ai/proc/remove_ai_verbs() src.verbs -= ai_verbs_default /mob/living/silicon/ai/New(loc, var/datum/ai_laws/L, var/obj/item/device/mmi/B, var/safety = 0) announcement = new() announcement.title = "A.I. Announcement" announcement.announcement_type = "A.I. Announcement" announcement.newscast = 1 var/list/possibleNames = ai_names var/pickedName = null while(!pickedName) pickedName = pick(ai_names) for (var/mob/living/silicon/ai/A in mob_list) if (A.real_name == pickedName && possibleNames.len > 1) //fixing the theoretically possible infinite loop possibleNames -= pickedName pickedName = null aiPDA = new/obj/item/device/pda/ai(src) SetName(pickedName) anchored = 1 canmove = 0 density = 1 loc = loc holo_icon = getHologramIcon(icon('icons/mob/AI.dmi',"holo1")) proc_holder_list = new() if(L) if (istype(L, /datum/ai_laws)) laws = L else laws = new base_law_type aiMulti = new(src) aiRadio = new(src) common_radio = aiRadio aiRadio.myAi = src additional_law_channels += "Binary" additional_law_channels += "Holopad" aiCamera = new/obj/item/device/camera/siliconcam/ai_camera(src) if (istype(loc, /turf)) add_ai_verbs(src) //Languages add_language("Robot Talk", 1) add_language("Galactic Common", 1) add_language("Sol Common", 0) add_language("Sinta'unathi", 0) add_language("Siik'tajr", 0) add_language("Skrellian", 0) add_language("Tradeband", 1) add_language("Gutter", 0) 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. del(src)//Delete AI. return else if (B.brainmob.mind) B.brainmob.mind.transfer_to(src) on_mob_init() spawn(5) new /obj/machinery/ai_powersupply(src) hud_list[HEALTH_HUD] = image('icons/mob/hud.dmi', src, "hudblank") hud_list[STATUS_HUD] = image('icons/mob/hud.dmi', src, "hudblank") hud_list[ID_HUD] = image('icons/mob/hud.dmi', src, "hudblank") hud_list[WANTED_HUD] = image('icons/mob/hud.dmi', src, "hudblank") hud_list[IMPLOYAL_HUD] = image('icons/mob/hud.dmi', src, "hudblank") hud_list[IMPCHEM_HUD] = image('icons/mob/hud.dmi', src, "hudblank") hud_list[IMPTRACK_HUD] = image('icons/mob/hud.dmi', src, "hudblank") hud_list[SPECIALROLE_HUD] = image('icons/mob/hud.dmi', src, "hudblank") ai_list += src ..() return /mob/living/silicon/ai/proc/on_mob_init() src << "You are playing the station's AI. The AI cannot move, but can interact with many objects while viewing them (through cameras)." src << "To look at other parts of the station, click on yourself to get a camera menu." src << "While observing through a camera, you can use most (networked) devices which you can see, such as computers, APCs, intercoms, doors, etc." src << "To use something, simply click on it." src << "Use say :b to speak to your cyborgs through binary. Use say :h to speak from an active holopad." src << "For department channels, use the following say commands:" var/radio_text = "" for(var/i = 1 to common_radio.channels.len) var/channel = common_radio.channels[i] var/key = get_radio_key_from_channel(channel) radio_text += "[key] - [channel]" if(i != common_radio.channels.len) radio_text += ", " src << radio_text if (!(ticker && ticker.mode && (mind in ticker.mode.malf_ai))) show_laws() src << "These laws may be changed by other players, or by you being the traitor." job = "AI" /mob/living/silicon/ai/Del() ai_list -= src ..() /mob/living/silicon/ai/pointed(atom/A as mob|obj|turf in view()) set popup_menu = 0 set src = usr.contents return 0 /mob/living/silicon/ai/proc/system_integrity() return (health-config.health_threshold_dead)/2 // this function shows the health of the pAI in the Status panel /mob/living/silicon/ai/show_system_integrity() // An AI doesn't become inoperable until -100% (or whatever config.health_threshold_dead is set to) if(!src.stat) stat(null, text("System integrity: [system_integrity()]%")) else stat(null, text("Systems nonfunctional")) /mob/living/silicon/ai/proc/SetName(pickedName as text) real_name = pickedName name = pickedName announcement.announcer = pickedName if(eyeobj) eyeobj.name = "[pickedName] (AI Eye)" // Set ai pda name if(aiPDA) aiPDA.ownjob = "AI" aiPDA.owner = pickedName aiPDA.name = pickedName + " (" + aiPDA.ownjob + ")" /* The AI Power supply is a dummy object used for powering the AI since only machinery should be using power. The alternative was to rewrite a bunch of AI code instead here we are. */ /obj/machinery/ai_powersupply name="Power Supply" active_power_usage=50000 // Station AIs use significant amounts of power. This, when combined with charged SMES should mean AI lasts for 1hr without external power. use_power = 2 power_channel = EQUIP var/mob/living/silicon/ai/powered_ai = null invisibility = 100 /obj/machinery/ai_powersupply/New(var/mob/living/silicon/ai/ai=null) powered_ai = ai if(isnull(powered_ai)) Del() loc = powered_ai.loc use_power(1) // Just incase we need to wake up the power system. ..() /obj/machinery/ai_powersupply/process() if(!powered_ai || powered_ai.stat & DEAD) Del() if(!powered_ai.anchored) loc = powered_ai.loc use_power = 0 if(powered_ai.anchored) use_power = 2 /mob/living/silicon/ai/proc/pick_icon() set category = "AI Commands" set name = "Set AI Core Display" if(stat || aiRestorePowerRoutine) return if(!custom_sprite) //Check to see if custom sprite time, checking the appopriate file to change a var var/file = file2text("config/custom_sprites.txt") var/lines = text2list(file, "\n") for(var/line in lines) // split & clean up var/list/Entry = text2list(line, ":") for(var/i = 1 to Entry.len) Entry[i] = trim(Entry[i]) if(Entry.len < 2) continue; if(Entry[1] == src.ckey && Entry[2] == src.real_name) custom_sprite = 1 //They're in the list? Custom sprite time icon = 'icons/mob/custom-synthetic.dmi' //if(icon_state == initial(icon_state)) var/icontype = "" if (custom_sprite == 1) icontype = ("Custom")//automagically selects custom sprite if one is available else icontype = input("Select an icon!", "AI", null, null) in list("Monochrome", "Rainbow", "Blue", "Inverted", "Text", "Smiley", "Angry", "Dorf", "Matrix", "Bliss", "Firewall", "Green", "Red", "Static", "Triumvirate", "Triumvirate Static", "Soviet", "Trapped", "Heartline", "Chatterbox") switch(icontype) if("Custom") icon_state = "[src.ckey]-ai" if("Rainbow") icon_state = "ai-clown" if("Monochrome") icon_state = "ai-mono" if("Inverted") icon_state = "ai-u" if("Firewall") icon_state = "ai-magma" if("Green") icon_state = "ai-wierd" if("Red") icon_state = "ai-red" if("Static") icon_state = "ai-static" if("Text") icon_state = "ai-text" if("Smiley") icon_state = "ai-smiley" if("Matrix") icon_state = "ai-matrix" if("Angry") icon_state = "ai-angryface" if("Dorf") icon_state = "ai-dorf" if("Bliss") icon_state = "ai-bliss" if("Triumvirate") icon_state = "ai-triumvirate" if("Triumvirate Static") icon_state = "ai-triumvirate-malf" if("Soviet") icon_state = "ai-redoctober" if("Trapped") icon_state = "ai-hades" if("Heartline") icon_state = "ai-heartline" if("Chatterbox") icon_state = "ai-president" else icon_state = "ai" //else //usr <<"You can only change your display once!" //return /mob/living/silicon/ai/proc/is_malf() if(ticker.mode.name == "AI malfunction") var/datum/game_mode/malfunction/malf = ticker.mode for (var/datum/mind/malfai in malf.malf_ai) if (mind == malfai) return malf return 0 // displays the malf_ai information if the AI is the malf /mob/living/silicon/ai/show_malf_ai() var/datum/game_mode/malfunction/malf = is_malf() if(malf && malf.apcs >= 3) stat(null, "Time until station control secured: [max(malf.AI_win_timeleft/(malf.apcs/3), 0)] seconds") /mob/living/silicon/ai/proc/ai_alerts() set category = "AI Commands" set name = "Show Alerts" var/dat = "Current Station Alerts\n" dat += "Close

" for (var/cat in alarms) dat += text("[]
\n", cat) var/list/alarmlist = alarms[cat] if (alarmlist.len) for (var/area_name in alarmlist) var/datum/alarm/alarm = alarmlist[area_name] dat += "" var/cameratext = "" if (alarm.cameras) for (var/obj/machinery/camera/I in alarm.cameras) cameratext += text("[][]", (cameratext=="") ? "" : " | ", src, I, I.c_tag) dat += text("-- [] ([])", alarm.area.name, (cameratext)? cameratext : "No Camera") if (alarm.sources.len > 1) dat += text(" - [] sources", alarm.sources.len) dat += "
\n" else dat += "-- All Systems Nominal
\n" dat += "
\n" viewalerts = 1 src << browse(dat, "window=aialerts&can_close=0") // this verb lets the ai see the stations manifest /mob/living/silicon/ai/proc/ai_roster() set category = "AI Commands" set name = "Show Crew Manifest" show_station_manifest() /mob/living/silicon/ai/var/message_cooldown = 0 /mob/living/silicon/ai/proc/ai_announcement() set category = "AI Commands" set name = "Make Station Announcement" if(check_unable(AI_CHECK_WIRELESS | AI_CHECK_RADIO)) return if(message_cooldown) src << "Please allow one minute to pass between announcements." return var/input = stripped_input(usr, "Please write a message to announce to the station crew.", "A.I. Announcement") if(!input) return if(check_unable(AI_CHECK_WIRELESS | AI_CHECK_RADIO)) return announcement.Announce(input) message_cooldown = 1 spawn(600)//One minute cooldown message_cooldown = 0 /mob/living/silicon/ai/proc/ai_call_shuttle() set category = "AI Commands" set name = "Call Emergency Shuttle" if(check_unable(AI_CHECK_WIRELESS)) return var/confirm = alert("Are you sure you want to call the shuttle?", "Confirm Shuttle Call", "Yes", "No") if(check_unable(AI_CHECK_WIRELESS)) return if(confirm == "Yes") call_shuttle_proc(src) // hack to display shuttle timer if(emergency_shuttle.online()) var/obj/machinery/computer/communications/C = locate() in machines if(C) C.post_status("shuttle") /mob/living/silicon/ai/proc/ai_recall_shuttle() set category = "AI Commands" set name = "Recall Emergency Shuttle" if(check_unable(AI_CHECK_WIRELESS)) return var/confirm = alert("Are you sure you want to recall the shuttle?", "Confirm Shuttle Recall", "Yes", "No") if(check_unable(AI_CHECK_WIRELESS)) return if(confirm == "Yes") cancel_call_proc(src) /mob/living/silicon/ai/check_eye(var/mob/user as mob) if (!camera) return null user.reset_view(camera) return 1 /mob/living/silicon/ai/restrained() return 0 /mob/living/silicon/ai/emp_act(severity) if (prob(30)) switch(pick(1,2)) if(1) view_core() if(2) ai_call_shuttle() ..() /mob/living/silicon/ai/Topic(href, href_list) if(usr != src) return if(..()) 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() //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 << "Unable to locate the holopad." 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() if (href_list["track"]) var/mob/target = locate(href_list["track"]) in mob_list if(target && (!istype(target, /mob/living/carbon/human) || html_decode(href_list["trackname"]) == target:get_face_name())) ai_actual_track(target) else src << "\red System error. Cannot locate [html_decode(href_list["trackname"])]." return return /mob/living/silicon/ai/meteorhit(obj/O as obj) for(var/mob/M in viewers(src, null)) M.show_message(text("\red [] has been hit by []", src, O), 1) //Foreach goto(19) if (health > 0) adjustBruteLoss(30) if ((O.icon_state == "flaming")) adjustFireLoss(40) updatehealth() return /mob/living/silicon/ai/reset_view(atom/A) if(camera) camera.SetLuminosity(0) if(istype(A,/obj/machinery/camera)) camera = A ..() if(istype(A,/obj/machinery/camera)) if(camera_light_on) A.SetLuminosity(AI_CAMERA_LUMINOSITY) else A.SetLuminosity(0) /mob/living/silicon/ai/proc/switchCamera(var/obj/machinery/camera/C) 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/triggerAlarm(var/class, area/A, list/cameralist, var/source) if (stat == 2) return 1 ..() var/cameratext = "" for (var/obj/machinery/camera/C in cameralist) cameratext += "[(cameratext == "")? "" : "|"][C.c_tag]" queueAlarm("--- [class] alarm detected in [A.name]! ([(cameratext)? cameratext : "No Camera"])", class) if (viewalerts) ai_alerts() /mob/living/silicon/ai/cancelAlarm(var/class, area/A as area, var/source) var/has_alarm = ..() if (!has_alarm) queueAlarm(text("--- [] alarm in [] has been cleared.", class, A.name), class, 0) if (viewalerts) ai_alerts() return has_alarm /mob/living/silicon/ai/cancel_camera() set category = "AI Commands" set name = "Cancel Camera View" //src.cameraFollow = null src.view_core() //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() var/cameralist[0] if(check_unable()) return var/mob/living/silicon/ai/U = usr for (var/obj/machinery/camera/C in cameranet.cameras) if(!C.can_use()) continue var/list/tempnetwork = difflist(C.network,RESTRICTED_CAMERA_NETWORKS,1) if(tempnetwork.len) for(var/i in tempnetwork) 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 << "\blue Switched to [network] camera network." //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(check_unable(AI_CHECK_WIRELESS)) return set_ai_status_displays(src) 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(check_unable()) return 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) del(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", "carp" ) input = input("Please select a hologram:") as null|anything in icon_list if(input) del(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("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 << "\blue You are already in your Main Core." return apc.malfvacate()*/ //Toggles the luminosity and applies it by re-entereing the camera. /mob/living/silicon/ai/proc/toggle_camera_light() set name = "Toggle Camera Light" set desc = "Toggles the light on the camera the AI is looking through." set category = "AI Commands" if(check_unable()) return camera_light_on = !camera_light_on src << "Camera lights [camera_light_on ? "activated" : "deactivated"]." if(!camera_light_on) if(camera) camera.SetLuminosity(0) camera = null else lightNearbyCamera() // Handled camera lighting, when toggled. // It will get the nearest camera from the eyeobj, lighting it. /mob/living/silicon/ai/proc/lightNearbyCamera() if(camera_light_on && camera_light_on < world.timeofday) if(src.camera) var/obj/machinery/camera/camera = near_range_camera(src.eyeobj) if(camera && src.camera != camera) src.camera.SetLuminosity(0) if(!camera.light_disabled) src.camera = camera src.camera.SetLuminosity(AI_CAMERA_LUMINOSITY) else src.camera = null else if(isnull(camera)) src.camera.SetLuminosity(0) src.camera = null else var/obj/machinery/camera/camera = near_range_camera(src.eyeobj) if(camera && !camera.light_disabled) src.camera = camera src.camera.SetLuminosity(AI_CAMERA_LUMINOSITY) camera_light_on = world.timeofday + 1 * 20 // Update the light every 2 seconds. /mob/living/silicon/ai/attackby(obj/item/weapon/W as obj, mob/user as mob) if(istype(W, /obj/item/device/aicard)) var/obj/item/device/aicard/card = W card.grab_ai(src, user) else if(istype(W, /obj/item/weapon/wrench)) if(anchored) user.visible_message("\blue \The [user] starts to unbolt \the [src] from the plating...") if(!do_after(user,40)) user.visible_message("\blue \The [user] decides not to unbolt \the [src].") return user.visible_message("\blue \The [user] finishes unfastening \the [src]!") anchored = 0 return else user.visible_message("\blue \The [user] starts to bolt \the [src] to the plating...") if(!do_after(user,40)) user.visible_message("\blue \The [user] decides not to bolt \the [src].") return user.visible_message("\blue \The [user] finishes fastening down \the [src]!") anchored = 1 return else return ..() /mob/living/silicon/ai/proc/control_integrated_radio() set name = "Radio Settings" set desc = "Allows you to change settings of your radio." set category = "AI Commands" if(check_unable(AI_CHECK_RADIO)) return src << "Accessing Subspace Transceiver control..." if (src.aiRadio) src.aiRadio.interact(src) /mob/living/silicon/ai/proc/sensor_mode() set name = "Set Sensor Augmentation" set category = "AI Commands" set desc = "Augment visual feed with internal sensor overlays" toggle_sensor_mode() /mob/living/silicon/ai/proc/check_unable(var/flags = 0) if(stat == DEAD) usr << "\red You are dead!" return 1 if((flags & AI_CHECK_WIRELESS) && src.control_disabled) usr << "\red Wireless control is disabled!" return 1 if((flags & AI_CHECK_RADIO) && src.aiRadio.disabledAi) src << "\red System Error - Transceiver Disabled!" return 1 return 0 #undef AI_CHECK_WIRELESS #undef AI_CHECK_RADIO