/mob/living/silicon/robot name = "Cyborg" real_name = "Cyborg" icon = 'icons/mob/robots.dmi' icon_state = "robot" bubble_icon = "robot" /mob/living/silicon/robot/get_cell() return cell /mob/living/silicon/robot/Initialize(mapload) spark_system = new /datum/effect_system/spark_spread() spark_system.set_up(5, 0, src) spark_system.attach(src) wires = new /datum/wires/robot(src) AddElement(/datum/element/empprotection, EMP_PROTECT_WIRES) // AddElement(/datum/element/ridable, /datum/component/riding/creature/cyborg) RegisterSignal(src, COMSIG_PROCESS_BORGCHARGER_OCCUPANT, .proc/charge) robot_modules_background = new() robot_modules_background.icon_state = "block" robot_modules_background.layer = HUD_LAYER //Objects that appear on screen are on layer ABOVE_HUD_LAYER, UI should be just below it. robot_modules_background.plane = HUD_PLANE inv1 = new /atom/movable/screen/robot/module1() inv2 = new /atom/movable/screen/robot/module2() inv3 = new /atom/movable/screen/robot/module3() previous_health = health if(ispath(cell)) cell = new cell(src) create_modularInterface() if(lawupdate) make_laws() if(!TryConnectToAI()) lawupdate = FALSE radio = new /obj/item/radio/borg(src) if(!scrambledcodes && !builtInCamera) builtInCamera = new (src) builtInCamera.c_tag = real_name builtInCamera.network = list("ss13") builtInCamera.internal_light = FALSE if(wires.is_cut(WIRE_CAMERA)) builtInCamera.status = 0 module = new /obj/item/robot_module(src) module.rebuild_modules() update_icons() . = ..() //If this body is meant to be a borg controlled by the AI player if(shell) make_shell() //MMI stuff. Held togheter by magic. ~Miauw else if(!mmi || !mmi.brainmob) mmi = new (src) mmi.brain = new /obj/item/organ/brain(mmi) mmi.brain.organ_flags |= ORGAN_FROZEN mmi.brain.name = "[real_name]'s brain" mmi.icon_state = "mmi_full" mmi.name = "Man-Machine Interface: [real_name]" mmi.brainmob = new(mmi) mmi.brainmob.name = src.real_name mmi.brainmob.real_name = src.real_name mmi.brainmob.container = mmi INVOKE_ASYNC(src, .proc/updatename) playsound(loc, 'sound/voice/liveagain.ogg', 75, TRUE) aicamera = new/obj/item/camera/siliconcam/robot_camera(src) toner = tonermax diag_hud_set_borgcell() logevent("System brought online.") add_verb(src, /mob/living/proc/lay_down) //CITADEL EDIT gimmie rest verb kthx add_verb(src, /mob/living/silicon/robot/proc/rest_style) /mob/living/silicon/robot/proc/create_modularInterface() if(!modularInterface) modularInterface = new /obj/item/modular_computer/tablet/integrated(src) modularInterface.layer = ABOVE_HUD_PLANE modularInterface.plane = ABOVE_HUD_PLANE //If there's an MMI in the robot, have it ejected when the mob goes away. --NEO /mob/living/silicon/robot/Destroy() var/atom/T = drop_location()//To hopefully prevent run time errors. if(mmi && mind)//Safety for when a cyborg gets dust()ed. Or there is no MMI inside. if(T) mmi.forceMove(T) if(mmi.brainmob) if(mmi.brainmob.stat == DEAD) mmi.brainmob.stat = CONSCIOUS mmi.brainmob.remove_from_dead_mob_list() mmi.brainmob.add_to_alive_mob_list() mind.transfer_to(mmi.brainmob) mmi.update_icon() else to_chat(src, "Oops! Something went very wrong, your MMI was unable to receive your mind. You have been ghosted. Please make a bug report so we can fix this bug.") ghostize() stack_trace("Borg MMI lacked a brainmob") mmi = null if(modularInterface) QDEL_NULL(modularInterface) if(connected_ai) set_connected_ai(null) if(shell) //??? why would you give an ai radio keys? GLOB.available_ai_shells -= src else if(T && istype(radio) && istype(radio.keyslot)) radio.keyslot.forceMove(T) radio.keyslot = null QDEL_NULL(wires) QDEL_NULL(module) QDEL_NULL(eye_lights) QDEL_NULL(inv1) QDEL_NULL(inv2) QDEL_NULL(inv3) cell = null return ..() // /mob/living/silicon/robot/Topic(href, href_list) // . = ..() // //Show alerts window if user clicked on "Show alerts" in chat // if (href_list["showalerts"]) // robot_alerts() /mob/living/silicon/robot/proc/pick_module() if(module.type != /obj/item/robot_module) return if(wires.is_cut(WIRE_RESET_MODULE)) to_chat(src,"ERROR: Module installer reply timeout. Please check internal connections.") return if(!CONFIG_GET(flag/disable_secborg) && GLOB.security_level < CONFIG_GET(number/minimum_secborg_alert)) to_chat(src, "NOTICE: Due to local station regulations, the security cyborg module and its variants are only available during [NUM2SECLEVEL(CONFIG_GET(number/minimum_secborg_alert))] alert and greater.") var/list/modulelist = list("Standard" = /obj/item/robot_module/standard, \ "Engineering" = /obj/item/robot_module/engineering, \ "Medical" = /obj/item/robot_module/medical, \ "Miner" = /obj/item/robot_module/miner, \ "Service" = /obj/item/robot_module/butler) if(!CONFIG_GET(flag/disable_peaceborg)) modulelist["Peacekeeper"] = /obj/item/robot_module/peacekeeper if(BORG_SEC_AVAILABLE) modulelist["Security"] = /obj/item/robot_module/security var/input_module = input("Please, select a module!", "Robot", null, null) as null|anything in sortList(modulelist) if(!input_module || module.type != /obj/item/robot_module) return module.transform_to(modulelist[input_module]) /mob/living/silicon/robot/proc/updatename(client/C) if(shell) return if(!C) C = client var/changed_name = "" if(custom_name) changed_name = custom_name // if(SSticker.anonymousnames) //only robotic renames will allow for anything other than the anonymous one // changed_name = anonymous_ai_name(is_ai = FALSE) if(!changed_name && C && C.prefs.custom_names["cyborg"] != DEFAULT_CYBORG_NAME) apply_pref_name("cyborg", C) return //built in camera handled in proc if(!changed_name) changed_name = get_standard_name() real_name = changed_name name = real_name if(!QDELETED(builtInCamera)) builtInCamera.c_tag = real_name //update the camera name too /mob/living/silicon/robot/proc/get_standard_name() return "[(designation ? "[designation] " : "")][mmi.braintype]-[ident]" /mob/living/silicon/robot/verb/cmd_robot_alerts() set category = "Robot Commands" set name = "Show Alerts" if(usr.stat == DEAD) to_chat(src, "Alert: You are dead.") return //won't work if dead robot_alerts() /mob/living/silicon/robot/proc/robot_alerts() var/dat = "" for (var/cat in alarms) dat += text("[cat]
\n") var/list/L = alarms[cat] if (L.len) for (var/alarm in L) var/list/alm = L[alarm] var/area/A = alm[1] dat += "" dat += text("-- [A.name]") dat += "
\n" else dat += "-- All Systems Nominal
\n" dat += "
\n" var/datum/browser/alerts = new(usr, "robotalerts", "Current Station Alerts", 400, 410) alerts.set_content(dat) alerts.open() /mob/living/silicon/robot/proc/ionpulse() if(!ionpulse_on) return if(cell.charge <= 10) toggle_ionpulse() return cell.charge -= 10 return TRUE /mob/living/silicon/robot/proc/toggle_ionpulse() if(!ionpulse) to_chat(src, "No thrusters are installed!") return if(!ion_trail) ion_trail = new ion_trail.set_up(src) ionpulse_on = !ionpulse_on to_chat(src, "You [ionpulse_on ? null :"de"]activate your ion thrusters.") if(ionpulse_on) ion_trail.start() else ion_trail.stop() if(thruster_button) thruster_button.icon_state = "ionpulse[ionpulse_on]" /mob/living/silicon/robot/get_status_tab_items() . = ..() . += "" if(cell) . += "Charge Left: [cell.charge]/[cell.maxcharge]" else . += text("No Cell Inserted!") if(module) for(var/datum/robot_energy_storage/st in module.storages) . += "[st.name]: [st.energy]/[st.max_energy]" if(connected_ai) . += "Master AI: [connected_ai.name]" /mob/living/silicon/robot/restrained(ignore_grab) . = 0 /mob/living/silicon/robot/triggerAlarm(class, area/A, O, obj/alarmsource) if(alarmsource.z != z) return if(stat == DEAD) 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)) queueAlarm(text("--- [class] alarm detected in [A.name]!"), class) return TRUE /mob/living/silicon/robot/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) return !cleared /mob/living/silicon/robot/can_interact_with(atom/A) if (A == modularInterface) return TRUE //bypass for borg tablets if (low_power_mode) return FALSE var/turf/T0 = get_turf(src) var/turf/T1 = get_turf(A) if (!T0 || ! T1) return FALSE return ISINRANGE(T1.x, T0.x - interaction_range, T0.x + interaction_range) && ISINRANGE(T1.y, T0.y - interaction_range, T0.y + interaction_range) /mob/living/silicon/robot/proc/attempt_welder_repair(obj/item/W, mob/user) if(!W.tool_behaviour == TOOL_WELDER) return if(!getBruteLoss()) to_chat(user, "[src] is already in good condition!") return if(!W.tool_start_check(user, amount=0)) //The welder has 1u of fuel consumed by it's afterattack, so we don't need to worry about taking any away. return user.DelayNextAction(CLICK_CD_MELEE) if(src == user) to_chat(user, "You start fixing yourself...") if(!W.use_tool(src, user, 50)) return adjustBruteLoss(-10) else to_chat(user, "You start fixing [src]...") if(!do_after(user, 30, target = src)) return adjustBruteLoss(-30) updatehealth() add_fingerprint(user) visible_message("[user] has fixed some of the dents on [src].") /mob/living/silicon/robot/proc/attempt_cable_repair(obj/item/stack/cable_coil/W, mob/user) if (getFireLoss() > 0 || getToxLoss() > 0) user.DelayNextAction(CLICK_CD_MELEE) if(src == user) to_chat(user, "You start fixing yourself...") if(!W.use_tool(src, user, 50, 1, skill_gain_mult = TRIVIAL_USE_TOOL_MULT)) to_chat(user, "You need more cable to repair [src]!") return adjustFireLoss(-10) adjustToxLoss(-10) else to_chat(user, "You start fixing [src]...") if(!W.use_tool(src, user, 30, 1)) to_chat(user, "You need more cable to repair [src]!") return adjustFireLoss(-30) adjustToxLoss(-30) updatehealth() user.visible_message("[user] has fixed some of the burnt wires on [src].", "You fix some of the burnt wires on [src].") else to_chat(user, "The wires seem fine, there's no need to fix them.") /mob/living/silicon/robot/attackby(obj/item/W, mob/user, params) if(W.tool_behaviour == TOOL_WELDER && (user.a_intent != INTENT_HARM || user == src)) INVOKE_ASYNC(src, .proc/attempt_welder_repair, W, user) return else if(istype(W, /obj/item/stack/cable_coil) && wiresexposed) INVOKE_ASYNC(src, .proc/attempt_cable_repair, W, user) return else if(W.tool_behaviour == TOOL_CROWBAR) // crowbar means open or close the cover if(opened) to_chat(user, "You close the cover.") opened = 0 update_icons() else if(locked) to_chat(user, "The cover is locked and cannot be opened!") else to_chat(user, "You open the cover.") opened = 1 update_icons() else if(istype(W, /obj/item/stock_parts/cell) && opened) // trying to put a cell inside if(wiresexposed) to_chat(user, "Close the cover first!") else if(cell) to_chat(user, "There is a power cell already installed!") else if(!user.transferItemToLoc(W, src)) return cell = W to_chat(user, "You insert the power cell.") update_icons() diag_hud_set_borgcell() else if(is_wire_tool(W)) if (wiresexposed) wires.interact(user) else to_chat(user, "You can't reach the wiring!") else if(W.tool_behaviour == TOOL_SCREWDRIVER && opened && !cell) // haxing wiresexposed = !wiresexposed to_chat(user, "The wires have been [wiresexposed ? "exposed" : "unexposed"]") update_icons() else if((W.tool_behaviour == TOOL_SCREWDRIVER) && opened && cell) // radio if(shell) to_chat(user, "You cannot seem to open the radio compartment") //Prevent AI radio key theft else if(radio) radio.attackby(W,user)//Push it to the radio to let it handle everything else to_chat(user, "Unable to locate a radio!") update_icons() else if(W.tool_behaviour == TOOL_WRENCH && opened && !cell) //Deconstruction. The flashes break from the fall, to prevent this from being a ghetto reset module. if(!locked_down) to_chat(user, "[src]'s bolts spark! Maybe you should lock them down first!") spark_system.start() return else to_chat(user, "You start to unfasten [src]'s securing bolts...") if(W.use_tool(src, user, 50, volume=50) && !cell) user.visible_message("[user] deconstructs [src]!", "You unfasten the securing bolts, and [src] falls to pieces!") deconstruct() else if(istype(W, /obj/item/aiModule)) var/obj/item/aiModule/MOD = W if(!opened) to_chat(user, "You need access to the robot's insides to do that!") return if(wiresexposed) to_chat(user, "You need to close the wire panel to do that!") return if(!cell) to_chat(user, "You need to install a power cell to do that!") return if(shell) //AI shells always have the laws of the AI to_chat(user, "[src] is controlled remotely! You cannot upload new laws this way!") return if(emagged || (connected_ai && lawupdate)) //Can't be sure which, metagamers emote("buzz-[user.name]") return if(!mind) //A player mind is required for law procs to run antag checks. to_chat(user, "[src] is entirely unresponsive!") return MOD.install(laws, user) //Proc includes a success mesage so we don't need another one return else if(istype(W, /obj/item/encryptionkey/) && opened) if(radio)//sanityyyyyy radio.attackby(W,user)//GTFO, you have your own procs else to_chat(user, "Unable to locate a radio!") else if (istype(W, /obj/item/card/id)||istype(W, /obj/item/pda)) // trying to unlock the interface with an ID card if(emagged)//still allow them to open the cover to_chat(user, "The interface seems slightly damaged.") if(opened) to_chat(user, "You must close the cover to swipe an ID card!") else if(allowed(usr)) locked = !locked to_chat(user, "You [ locked ? "lock" : "unlock"] [src]'s cover.") update_icons() else to_chat(user, "Access denied.") else if(istype(W, /obj/item/borg/upgrade/)) var/obj/item/borg/upgrade/U = W if(!opened) to_chat(user, "You must access the borg's internals!") else if(!src.module && U.require_module) to_chat(user, "The borg must choose a module before it can be upgraded!") else if(U.locked) to_chat(user, "The upgrade is locked and cannot be used yet!") else if(!user.temporarilyRemoveItemFromInventory(U)) return if(U.action(src)) to_chat(user, "You apply the upgrade to [src].") if(U.one_use) U.afterInstall(src) qdel(U) else U.forceMove(src) upgrades += U U.afterInstall(src) else to_chat(user, "Upgrade error.") U.forceMove(drop_location()) else if(istype(W, /obj/item/toner)) if(toner >= tonermax) to_chat(user, "The toner level of [src] is at its highest level possible!") else if(!user.temporarilyRemoveItemFromInventory(W)) return toner = tonermax qdel(W) to_chat(user, "You fill the toner level of [src] to its max capacity.") else return ..() /mob/living/silicon/robot/crowbar_act(mob/living/user, obj/item/I) //TODO: make fucking everything up there in that attackby() proc use the proper tool_act() procs. But honestly, who has time for that? 'cause I know for sure that you, the person reading this, sure as hell doesn't. var/validbreakout = FALSE for(var/obj/item/dogborg/sleeper/S in held_items) if(!LAZYLEN(S.contents)) continue if(!validbreakout) visible_message("[user] wedges [I] into the crevice separating [S] from [src]'s chassis, and begins to pry...", "You wedge [I] into the crevice separating [S] from [src]'s chassis, and begin to pry...") validbreakout = TRUE S.go_out() if(validbreakout) return TRUE return ..() /mob/living/silicon/robot/verb/unlock_own_cover() set category = "Robot Commands" set name = "Unlock Cover" set desc = "Unlocks your own cover if it is locked. You can not lock it again. A human will have to lock it for you." if(stat == DEAD) return //won't work if dead if(locked) switch(alert("You cannot lock your cover again, are you sure?\n (You can still ask for a human to lock it)", "Unlock Own Cover", "Yes", "No")) if("Yes") locked = FALSE update_icons() to_chat(usr, "You unlock your cover.") /mob/living/silicon/robot/proc/allowed(mob/M) //check if it doesn't require any access at all if(check_access(null)) return TRUE if(ishuman(M)) var/mob/living/carbon/human/H = M //if they are holding or wearing a card that has access, that works if(check_access(H.get_active_held_item()) || check_access(H.wear_id)) return TRUE else if(ismonkey(M)) var/mob/living/carbon/monkey/george = M //they can only hold things :( if(isitem(george.get_active_held_item())) return check_access(george.get_active_held_item()) return FALSE /mob/living/silicon/robot/proc/check_access(obj/item/card/id/I) if(!istype(req_access, /list)) //something's very wrong return TRUE var/list/L = req_access if(!L.len) //no requirements return TRUE if(!istype(I, /obj/item/card/id) && isitem(I)) I = I.GetID() if(!I || !I.access) //not ID or no access return FALSE for(var/req in req_access) if(!(req in I.access)) //doesn't have this access return FALSE return TRUE /mob/living/silicon/robot/regenerate_icons() return update_icons() /mob/living/silicon/robot/proc/self_destruct() if(emagged) QDEL_NULL(mmi) explosion(loc,1,2,4,flame_range = 2) else explosion(loc,-1,0,2) gib() /mob/living/silicon/robot/proc/UnlinkSelf() set_connected_ai(null) lawupdate = FALSE locked_down = FALSE scrambledcodes = TRUE //Disconnect it's camera so it's not so easily tracked. if(!QDELETED(builtInCamera)) QDEL_NULL(builtInCamera) // I'm trying to get the Cyborg to not be listed in the camera list // Instead of being listed as "deactivated". The downside is that I'm going // to have to check if every camera is null or not before doing anything, to prevent runtime errors. // I could change the network to null but I don't know what would happen, and it seems too hacky for me. update_mobility() /mob/living/silicon/robot/mode() set name = "Activate Held Object" set category = "IC" set src = usr if(incapacitated()) return var/obj/item/W = get_active_held_item() if(W) W.attack_self(src) /mob/living/silicon/robot/proc/SetLockdown(state = TRUE) // They stay locked down if their wire is cut. if(wires.is_cut(WIRE_LOCKDOWN)) state = TRUE if(state) throw_alert("locked", /atom/movable/screen/alert/locked) else clear_alert("locked") locked_down = state update_mobility() logevent("System lockdown [locked_down?"triggered":"released"].") /mob/living/silicon/robot/proc/SetEmagged(new_state) emagged = new_state module.rebuild_modules() update_icons() if(emagged) throw_alert("hacked", /atom/movable/screen/alert/hacked) else clear_alert("hacked") /** * Handles headlamp smashing * * When called (such as by the shadowperson lighteater's attack), this proc will break the borg's headlamp * and then call toggle_headlamp to disable the light. It also plays a sound effect of glass breaking, and * tells the borg what happened to its chat. Broken lights can be repaired by using a flashlight on the borg. */ /mob/living/silicon/robot/proc/smash_headlamp() if(!lamp_functional) return lamp_functional = FALSE playsound(src, 'sound/effects/glass_step.ogg', 50) toggle_headlamp(TRUE) to_chat(src, "Your headlamp is broken! You'll need a human to help replace it.") /mob/living/silicon/robot/verb/outputlaws() set category = "Robot Commands" set name = "State Laws" if(usr.stat == DEAD) return //won't work if dead checklaws() /mob/living/silicon/robot/verb/set_automatic_say_channel() //Borg version of setting the radio for autosay messages. set name = "Set Auto Announce Mode" set desc = "Modify the default radio setting for stating your laws." set category = "Robot Commands" if(usr.stat == DEAD) return //won't work if dead set_autosay() /** * Handles headlamp toggling, disabling, and color setting. * * The initial if statment is a bit long, but the gist of it is that should the lamp be on AND the update_color * arg be true, we should simply change the color of the lamp but not disable it. Otherwise, should the turn_off * arg be true, the lamp already be enabled, any of the normal reasons the lamp would turn off happen, or the * update_color arg be passed with the lamp not on, we should set the lamp off. The update_color arg is only * ever true when this proc is called from the borg tablet, when the color selection feature is used. * * Arguments: * * arg1 - turn_off, if enabled will force the lamp into an off state (rather than toggling it if possible) * * arg2 - update_color, if enabled, will adjust the behavior of the proc to change the color of the light if it is already on. */ /mob/living/silicon/robot/proc/toggle_headlamp(turn_off = FALSE, update_color = FALSE) //if both lamp is enabled AND the update_color flag is on, keep the lamp on. Otherwise, if anything listed is true, disable the lamp. if(!(update_color && lamp_enabled) && (turn_off || lamp_enabled || update_color || !lamp_functional || stat || low_power_mode)) set_light((lamp_functional && stat != DEAD && lamp_doom) ? lamp_intensity : 0, l_color = COLOR_RED) // set_light_on(lamp_functional && stat != DEAD && lamp_doom) //If the lamp isn't broken and borg isn't dead, doomsday borgs cannot disable their light fully. // set_light_color(COLOR_RED) //This should only matter for doomsday borgs, as any other time the lamp will be off and the color not seen // set_light_range(1) //Again, like above, this only takes effect when the light is forced on by doomsday mode. lamp_enabled = FALSE lampButton.update_icon() update_icons() return set_light(lamp_intensity, l_color = (lamp_doom? COLOR_RED : lamp_color)) // set_light_range(lamp_intensity) // set_light_color(lamp_doom? COLOR_RED : lamp_color) //Red for doomsday killborgs, borg's choice otherwise // set_light_on(TRUE) lamp_enabled = TRUE lampButton.update_icon() update_icons() /mob/living/silicon/robot/proc/deconstruct() // SEND_SIGNAL(src, COMSIG_BORG_SAFE_DECONSTRUCT) var/turf/T = get_turf(src) if (robot_suit) robot_suit.forceMove(T) robot_suit.l_leg.forceMove(T) robot_suit.l_leg = null robot_suit.r_leg.forceMove(T) robot_suit.r_leg = null new /obj/item/stack/cable_coil(T, robot_suit.chest.wired) robot_suit.chest.forceMove(T) robot_suit.chest.wired = FALSE robot_suit.chest = null robot_suit.l_arm.forceMove(T) robot_suit.l_arm = null robot_suit.r_arm.forceMove(T) robot_suit.r_arm = null robot_suit.head.forceMove(T) robot_suit.head.flash1.forceMove(T) robot_suit.head.flash1.burn_out() robot_suit.head.flash1 = null robot_suit.head.flash2.forceMove(T) robot_suit.head.flash2.burn_out() robot_suit.head.flash2 = null robot_suit.head = null robot_suit.update_icon() else new /obj/item/robot_suit(T) new /obj/item/bodypart/l_leg/robot(T) new /obj/item/bodypart/r_leg/robot(T) new /obj/item/stack/cable_coil(T, 1) new /obj/item/bodypart/chest/robot(T) new /obj/item/bodypart/l_arm/robot(T) new /obj/item/bodypart/r_arm/robot(T) new /obj/item/bodypart/head/robot(T) var/b for(b=0, b!=2, b++) var/obj/item/assembly/flash/handheld/F = new /obj/item/assembly/flash/handheld(T) F.burn_out() if (cell) //Sanity check. cell.forceMove(T) cell = null qdel(src) ///This is the subtype that gets created by robot suits. It's needed so that those kind of borgs don't have a useless cell in them /mob/living/silicon/robot/nocell cell = null /mob/living/silicon/robot/modules var/set_module = /obj/item/robot_module /mob/living/silicon/robot/modules/Initialize(mapload) . = ..() module.transform_to(set_module) /mob/living/silicon/robot/modules/standard set_module = /obj/item/robot_module/standard /mob/living/silicon/robot/modules/medical set_module = /obj/item/robot_module/medical /mob/living/silicon/robot/modules/engineering set_module = /obj/item/robot_module/engineering /mob/living/silicon/robot/modules/security set_module = /obj/item/robot_module/security /mob/living/silicon/robot/modules/clown set_module = /obj/item/robot_module/clown /mob/living/silicon/robot/modules/peacekeeper set_module = /obj/item/robot_module/peacekeeper /mob/living/silicon/robot/modules/miner set_module = /obj/item/robot_module/miner /mob/living/silicon/robot/modules/syndicate icon_state = "synd_sec" faction = list(ROLE_SYNDICATE) bubble_icon = "syndibot" req_access = list(ACCESS_SYNDICATE) lawupdate = FALSE scrambledcodes = TRUE // These are rogue borgs. ionpulse = TRUE var/playstyle_string = "You are a Syndicate assault cyborg!
\ You are armed with powerful offensive tools to aid you in your mission: help the operatives secure the nuclear authentication disk. \ Your cyborg LMG will slowly produce ammunition from your power supply, and your operative pinpointer will find and locate fellow nuclear operatives. \ Help the operatives secure the disk at all costs!" set_module = /obj/item/robot_module/syndicate cell = /obj/item/stock_parts/cell/hyper // radio = /obj/item/radio/borg/syndicate /mob/living/silicon/robot/modules/syndicate/Initialize(mapload) . = ..() radio = new /obj/item/radio/borg/syndicate(src) laws = new /datum/ai_laws/syndicate_override() addtimer(CALLBACK(src, .proc/show_playstyle), 5) /mob/living/silicon/robot/modules/syndicate/create_modularInterface() if(!modularInterface) modularInterface = new /obj/item/modular_computer/tablet/integrated/syndicate(src) return ..() /mob/living/silicon/robot/modules/syndicate/proc/show_playstyle() if(playstyle_string) to_chat(src, playstyle_string) /mob/living/silicon/robot/modules/syndicate/ResetModule() return /mob/living/silicon/robot/modules/syndicate/medical icon_state = "synd_medical" playstyle_string = "You are a Syndicate medical cyborg!
\ You are armed with powerful medical tools to aid you in your mission: help the operatives secure the nuclear authentication disk. \ Your hypospray will produce Restorative Nanites, a wonder-drug that will heal most types of bodily damages, including clone and brain damage. It also produces morphine for offense. \ Your defibrillator paddles can revive operatives through their hardsuits, or can be used on harm intent to shock enemies! \ Your energy saw functions as a circular saw, but can be activated to deal more damage, and your operative pinpointer will find and locate fellow nuclear operatives. \ Help the operatives secure the disk at all costs!" set_module = /obj/item/robot_module/syndicate_medical /mob/living/silicon/robot/modules/syndicate/saboteur icon_state = "synd_engi" playstyle_string = "You are a Syndicate saboteur cyborg!
\ You are armed with robust engineering tools to aid you in your mission: help the operatives secure the nuclear authentication disk. \ Your destination tagger will allow you to stealthily traverse the disposal network across the station \ Your welder will allow you to repair the operatives' exosuits, but also yourself and your fellow cyborgs \ Your cyborg chameleon projector allows you to assume the appearance and registered name of a Nanotrasen engineering borg, and undertake covert actions on the station \ Be aware that almost any physical contact or incidental damage will break your camouflage \ Help the operatives secure the disk at all costs!" set_module = /obj/item/robot_module/saboteur /mob/living/silicon/robot/modules/syndicate/spider// used for space ninja and their cyborg hacking special objective bubble_icon = "spider" playstyle_string = "You are a Spider Clan assault cyborg!
\ You are armed with powerful offensive tools to aid you in your mission: obey your ninja masters by any means necessary. \ Your cyborg LMG will slowly produce ammunition from your power supply, and your pinpointer will find and locate fellow members of the Spider Clan." set_module = /obj/item/robot_module/syndicate/spider /mob/living/silicon/robot/modules/syndicate_medical/spider// ditto bubble_icon = "spider" var/playstyle_string = "You are a Spider Clan medical cyborg!
\ You are armed with powerful medical tools to aid you in your mission: obey your ninja masters by any means necessary. \ Your hypospray will produce Restorative Nanites, a wonder-drug that will heal most types of bodily damages, including clone and brain damage. It also produces morphine for offense. \ Your defibrillator paddles can revive allies through their hardsuits, or can be used on harm intent to shock enemies! \ Your energy saw functions as a circular saw, but can be activated to deal more damage, and your pinpointer will find and locate fellow members of the Spider Clan." set_module = /obj/item/robot_module/syndicate_medical/spider /mob/living/silicon/robot/modules/saboteur/spider// ditto bubble_icon = "spider" var/playstyle_string = "You are a Spider Clan saboteur cyborg!
\ You are armed with robust engineering tools to aid you in your mission: obey your ninja masters by any means necessary. \ Your destination tagger will allow you to stealthily traverse the disposal network across the station. \ Your welder will can be used to repair yourself or any allied silicon units, while serving as an impromptu melee weapon. \ Your cyborg chameleon projector allows you to assume the appearance and registered name of a Nanotrasen engineering borg, and undertake covert actions on the station, \ be aware that almost any physical contact or incidental damage will break your camouflage." set_module = /obj/item/robot_module/saboteur/spider /mob/living/silicon/robot/proc/notify_ai(notifytype, oldname, newname) if(!connected_ai) return switch(notifytype) if(NEW_BORG) //New Cyborg to_chat(connected_ai, "

NOTICE - New cyborg connection detected: [name]
") if(NEW_MODULE) //New Module to_chat(connected_ai, "

NOTICE - Cyborg module change detected: [name] has loaded the [designation] module.
") if(RENAME) //New Name to_chat(connected_ai, "

NOTICE - Cyborg reclassification detected: [oldname] is now designated as [newname].
") if(AI_SHELL) //New Shell to_chat(connected_ai, "

NOTICE - New cyborg shell detected: [name]
") if(DISCONNECT) //Tampering with the wires to_chat(connected_ai, "

NOTICE - Remote telemetry lost with [name].
") /mob/living/silicon/robot/canUseTopic(atom/movable/M, be_close=FALSE, no_dextery=FALSE, no_tk=FALSE) if(stat || locked_down || low_power_mode) to_chat(src, "You can't do that right now!") return FALSE if(be_close && !in_range(M, src)) to_chat(src, "You are too far away!") return FALSE return TRUE /mob/living/silicon/robot/updatehealth() ..() // if(!module.breakable_modules) // return /// the current percent health of the robot (-1 to 1) var/percent_hp = health/maxHealth if(health <= previous_health) //if change in health is negative (we're losing hp) if(percent_hp <= 0.5) break_cyborg_slot(3) if(percent_hp <= 0) break_cyborg_slot(2) if(percent_hp <= -0.5) break_cyborg_slot(1) else //if change in health is positive (we're gaining hp) if(percent_hp >= 0.5) repair_cyborg_slot(3) if(percent_hp >= 0) repair_cyborg_slot(2) if(percent_hp >= -0.5) repair_cyborg_slot(1) previous_health = health /mob/living/silicon/robot/update_sight() if(!client) return if(stat == DEAD) sight = (SEE_TURFS|SEE_MOBS|SEE_OBJS) see_in_dark = 8 see_invisible = SEE_INVISIBLE_OBSERVER return see_invisible = initial(see_invisible) see_in_dark = initial(see_in_dark) sight = initial(sight) lighting_alpha = LIGHTING_PLANE_ALPHA_VISIBLE if(client.eye != src) var/atom/A = client.eye if(A.update_remote_sight(src)) //returns 1 if we override all other sight updates. return if(sight_mode & BORGMESON) sight |= SEE_TURFS lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_VISIBLE see_in_dark = 1 if(sight_mode & BORGMATERIAL) sight |= SEE_OBJS lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE see_in_dark = 1 if(sight_mode & BORGXRAY) sight |= (SEE_TURFS|SEE_MOBS|SEE_OBJS) see_invisible = SEE_INVISIBLE_LIVING see_in_dark = 8 if(sight_mode & BORGTHERM) sight |= SEE_MOBS lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_VISIBLE see_invisible = min(see_invisible, SEE_INVISIBLE_LIVING) see_in_dark = 8 if(see_override) see_invisible = see_override sync_lighting_plane_alpha() /mob/living/silicon/robot/update_stat() if(status_flags & GODMODE) return if(stat != DEAD) if(health <= -maxHealth) //die only once death() toggle_headlamp(1) return if(IsUnconscious() || IsStun() || IsKnockdown() || IsParalyzed() || getOxyLoss() > maxHealth * 0.5) stat = UNCONSCIOUS else stat = CONSCIOUS update_mobility() diag_hud_set_status() diag_hud_set_health() diag_hud_set_aishell() update_health_hud() /mob/living/silicon/robot/revive(full_heal = FALSE, admin_revive = FALSE) if(..()) //successfully ressuscitated from death if(!QDELETED(builtInCamera) && !wires.is_cut(WIRE_CAMERA)) builtInCamera.toggle_cam(src,0) if(admin_revive) locked = TRUE notify_ai(NEW_BORG) . = TRUE toggle_headlamp(FALSE, TRUE) //This will reenable borg headlamps if doomsday is currently going on still. /mob/living/silicon/robot/fully_replace_character_name(oldname, newname) ..() if(oldname != real_name) notify_ai(RENAME, oldname, newname) if(!QDELETED(builtInCamera)) builtInCamera.c_tag = real_name custom_name = newname /mob/living/silicon/robot/proc/ResetModule() // SEND_SIGNAL(src, COMSIG_BORG_SAFE_DECONSTRUCT) uneq_all() shown_robot_modules = FALSE if(hud_used) hud_used.update_robot_modules_display() if (hasExpanded) resize = 0.5 hasExpanded = FALSE update_transform() logevent("Chassis configuration has been reset.") module.transform_to(/obj/item/robot_module) // Remove upgrades. for(var/obj/item/borg/upgrade/I in upgrades) I.deactivate(src) I.forceMove(get_turf(src)) upgrades.Cut() vtec = 0 vtec_disabled = FALSE ionpulse = FALSE revert_shell() return 1 /mob/living/silicon/robot/proc/has_module() if(!module || module.type == /obj/item/robot_module) . = FALSE else . = TRUE /mob/living/silicon/robot/proc/update_module_innate() designation = module.name if(hands) hands.icon_state = module.moduleselect_icon //CITADEL CHANGE - allows module select icons to use a different icon file hands.icon = (module.moduleselect_alternate_icon ? module.moduleselect_alternate_icon : initial(hands.icon)) if(module.can_be_pushed) status_flags |= CANPUSH else status_flags &= ~CANPUSH if(module.clean_on_move) AddElement(/datum/element/cleaning) else RemoveElement(/datum/element/cleaning) hat_offset = module.hat_offset magpulse = module.magpulsing INVOKE_ASYNC(src, .proc/updatename) /mob/living/silicon/robot/proc/place_on_head(obj/item/new_hat) if(hat) hat.forceMove(get_turf(src)) hat = new_hat new_hat.forceMove(src) update_icons() /** *Checking Exited() to detect if a hat gets up and walks off. *Drones and pAIs might do this, after all. */ /mob/living/silicon/robot/Exited(atom/A) if(hat && hat == A) hat = null if(!QDELETED(src)) //Don't update icons if we are deleted. update_icons() return ..() ///Use this to add upgrades to robots. It'll register signals for when the upgrade is moved or deleted, if not single use. /mob/living/silicon/robot/proc/add_to_upgrades(obj/item/borg/upgrade/new_upgrade, mob/user) if(new_upgrade in upgrades) return FALSE if(!user.temporarilyRemoveItemFromInventory(new_upgrade)) //calling the upgrade's dropped() proc /before/ we add action buttons return FALSE if(!new_upgrade.action(src, user)) to_chat(user, "Upgrade error.") new_upgrade.forceMove(loc) //gets lost otherwise return FALSE to_chat(user, "You apply the upgrade to [src].") to_chat(src, "----------------\nNew hardware detected...Identified as \"[new_upgrade]\"...Setup complete.\n----------------") if(new_upgrade.one_use) logevent("Firmware [new_upgrade] run successfully.") qdel(new_upgrade) return FALSE upgrades += new_upgrade new_upgrade.forceMove(src) RegisterSignal(new_upgrade, COMSIG_MOVABLE_MOVED, .proc/remove_from_upgrades) RegisterSignal(new_upgrade, COMSIG_PARENT_QDELETING, .proc/on_upgrade_deleted) logevent("Hardware [new_upgrade] installed successfully.") ///Called when an upgrade is moved outside the robot. So don't call this directly, use forceMove etc. /mob/living/silicon/robot/proc/remove_from_upgrades(obj/item/borg/upgrade/old_upgrade) SIGNAL_HANDLER if(loc == src) return old_upgrade.deactivate(src) upgrades -= old_upgrade UnregisterSignal(old_upgrade, list(COMSIG_MOVABLE_MOVED, COMSIG_PARENT_QDELETING)) ///Called when an applied upgrade is deleted. /mob/living/silicon/robot/proc/on_upgrade_deleted(obj/item/borg/upgrade/old_upgrade) SIGNAL_HANDLER if(!QDELETED(src)) old_upgrade.deactivate(src) upgrades -= old_upgrade UnregisterSignal(old_upgrade, list(COMSIG_MOVABLE_MOVED, COMSIG_PARENT_QDELETING)) /** * make_shell: Makes an AI shell out of a cyborg unit * * Arguments: * * board - B.O.R.I.S. module board used for transforming the cyborg into AI shell */ /mob/living/silicon/robot/proc/make_shell(obj/item/borg/upgrade/ai/board) if(!board) upgrades |= new /obj/item/borg/upgrade/ai(src) shell = TRUE braintype = "AI Shell" name = "Empty AI Shell-[ident]" real_name = name GLOB.available_ai_shells |= src if(!QDELETED(builtInCamera)) builtInCamera.c_tag = real_name //update the camera name too diag_hud_set_aishell() notify_ai(AI_SHELL) /** * revert_shell: Reverts AI shell back into a normal cyborg unit */ /mob/living/silicon/robot/proc/revert_shell() if(!shell) return undeploy() for(var/obj/item/borg/upgrade/ai/boris in src) //A player forced reset of a borg would drop the module before this is called, so this is for catching edge cases qdel(boris) shell = FALSE GLOB.available_ai_shells -= src name = "Unformatted Cyborg-[ident]" real_name = name if(!QDELETED(builtInCamera)) builtInCamera.c_tag = real_name diag_hud_set_aishell() /** * deploy_init: Deploys AI unit into AI shell * * Arguments: * * AI - AI unit that initiated the deployment into the AI shell */ /mob/living/silicon/robot/proc/deploy_init(mob/living/silicon/ai/AI) real_name = "[AI.real_name] [designation] Shell-[ident]" name = real_name if(!QDELETED(builtInCamera)) builtInCamera.c_tag = real_name //update the camera name too mainframe = AI deployed = TRUE set_connected_ai(mainframe) mainframe.connected_robots |= src lawupdate = TRUE lawsync() if(radio && AI.radio) //AI keeps all channels, including Syndie if it is a Traitor if(AI.radio.syndie) radio.make_syndie() radio.subspace_transmission = TRUE radio.channels = AI.radio.channels for(var/chan in radio.channels) radio.secure_radio_connections[chan] = add_radio(radio, GLOB.radiochannels[chan]) diag_hud_set_aishell() undeployment_action.Grant(src) /datum/action/innate/undeployment name = "Disconnect from shell" desc = "Stop controlling your shell and resume normal core operations." icon_icon = 'icons/mob/actions/actions_AI.dmi' button_icon_state = "ai_core" required_mobility_flags = NONE /datum/action/innate/undeployment/Trigger() if(!..()) return FALSE var/mob/living/silicon/robot/R = owner R.undeploy() return TRUE /datum/action/innate/custom_holoform name = "Select Custom Holoform" desc = "Select one of your existing avatars to use as a holoform." icon_icon = 'icons/mob/actions/actions_silicon.dmi' button_icon_state = "custom_holoform" required_mobility_flags = NONE /datum/action/innate/custom_holoform/Trigger() if(!..()) return FALSE var/mob/living/silicon/S = owner //if setting the holoform succeeds, attempt to set it as the current holoform for the pAI or AI if(S.attempt_set_custom_holoform()) if(istype(S, /mob/living/silicon/pai)) var/mob/living/silicon/pai/P = S P.chassis = "custom" else if(istype(S, /mob/living/silicon/ai)) var/mob/living/silicon/ai/A = S if(A.client?.prefs?.custom_holoform_icon) A.holo_icon = A.client.prefs.get_filtered_holoform(HOLOFORM_FILTER_AI) else A.holo_icon = getHologramIcon(icon('icons/mob/ai.dmi', "female")) return TRUE /mob/living/silicon/robot/proc/undeploy() if(!deployed || !mind || !mainframe) return mainframe.redeploy_action.Grant(mainframe) mainframe.redeploy_action.last_used_shell = src mind.transfer_to(mainframe) deployed = FALSE mainframe.deployed_shell = null undeployment_action.Remove(src) if(radio) //Return radio to normal radio.recalculateChannels() if(!QDELETED(builtInCamera)) builtInCamera.c_tag = real_name //update the camera name too diag_hud_set_aishell() mainframe.diag_hud_set_deployed() if(mainframe.laws) mainframe.laws.show_laws(mainframe) //Always remind the AI when switching if(mainframe.eyeobj) mainframe.eyeobj.setLoc(loc) mainframe = null /mob/living/silicon/robot/attack_ai(mob/user) if(shell && (!connected_ai || connected_ai == user)) var/mob/living/silicon/ai/AI = user AI.deploy_to_shell(src) /mob/living/silicon/robot/shell shell = TRUE cell = null /mob/living/silicon/robot/MouseDrop_T(mob/living/M, mob/living/user) . = ..() if(!(M in buckled_mobs) && isliving(M)) buckle_mob(M) /mob/living/silicon/robot/buckle_mob(mob/living/M, force = FALSE, check_loc = TRUE) if(!is_type_in_typecache(M, can_ride_typecache)) M.visible_message("[M] really can't seem to mount [src]...") return var/datum/component/riding/riding_datum = LoadComponent(/datum/component/riding/cyborg) if(buckled_mobs) if(buckled_mobs.len >= max_buckled_mobs) return if(M in buckled_mobs) return if(stat || incapacitated()) return if(module && !module.allow_riding) M.visible_message("Unfortunately, [M] just can't seem to hold onto [src]!") return if(iscarbon(M) && !M.incapacitated() && !riding_datum.equip_buckle_inhands(M, 1)) if(M.get_num_arms() <= 0) M.visible_message("[M] can't climb onto [src] because [M.p_they()] don't have any usable arms!") else M.visible_message("[M] can't climb onto [src] because [M.p_their()] hands are full!") return . = ..(M, force, check_loc) /mob/living/silicon/robot/unbuckle_mob(mob/user, force=FALSE) if(iscarbon(user)) var/datum/component/riding/riding_datum = GetComponent(/datum/component/riding) if(istype(riding_datum)) riding_datum.unequip_buckle_inhands(user) riding_datum.restore_position(user) . = ..(user) /mob/living/silicon/robot/resist() . = ..() if(!has_buckled_mobs()) return for(var/i in buckled_mobs) var/mob/unbuckle_me_now = i unbuckle_mob(unbuckle_me_now, FALSE) /mob/living/silicon/robot/proc/TryConnectToAI() set_connected_ai(select_active_ai_with_fewest_borgs(z)) if(connected_ai) lawsync() lawupdate = TRUE return TRUE picturesync() return FALSE /mob/living/silicon/robot/proc/picturesync() if(connected_ai?.aicamera && aicamera) for(var/i in aicamera.stored) connected_ai.aicamera.stored[i] = TRUE for(var/i in connected_ai.aicamera.stored) aicamera.stored[i] = TRUE /mob/living/silicon/robot/proc/charge(datum/source, amount, repairs) if(module) module.respawn_consumable(src, amount * 0.005) if(cell) cell.charge = min(cell.charge + amount, cell.maxcharge) if(repairs) heal_bodypart_damage(repairs, repairs - 1) /mob/living/silicon/robot/proc/rest_style() set name = "Switch Rest Style" set category = "Robot Commands" set desc = "Select your resting pose." sitting = 0 bellyup = 0 var/choice = alert(src, "Select resting pose", "", "Resting", "Sitting", "Belly up") switch(choice) if("Resting") update_icons() return 0 if("Sitting") sitting = 1 if("Belly up") bellyup = 1 update_icons() /mob/living/silicon/robot/verb/viewmanifest() set category = "Robot Commands" set name = "View Crew Manifest" if(usr.stat == DEAD) return //won't work if dead ai_roster() /mob/living/silicon/robot/proc/set_connected_ai(new_ai) if(connected_ai == new_ai) return . = connected_ai connected_ai = new_ai if(.) var/mob/living/silicon/ai/old_ai = . old_ai.connected_robots -= src lamp_doom = FALSE if(connected_ai) connected_ai.connected_robots |= src lamp_doom = connected_ai.doomsday_device ? TRUE : FALSE toggle_headlamp(FALSE, TRUE) /** * Records an IC event log entry in the cyborg's internal tablet. * * Creates an entry in the borglog list of the cyborg's internal tablet, listing the current * in-game time followed by the message given. These logs can be seen by the cyborg in their * BorgUI tablet app. By design, logging fails if the cyborg is dead. * * Arguments: * arg1: a string containing the message to log. */ /mob/living/silicon/robot/proc/logevent(string = "") if(!string) return if(stat == DEAD) //Dead borgs log no longer return if(!modularInterface) stack_trace("Cyborg [src] ( [type] ) was somehow missing their integrated tablet. Please make a bug report.") create_modularInterface() modularInterface.borglog += "[STATION_TIME_TIMESTAMP("hh:mm:ss", world.time)] - [string]" var/datum/computer_file/program/robotact/program = modularInterface.get_robotact() if(program) program.force_full_update() /mob/living/silicon/robot/get_tooltip_data() var/t_He = p_they(TRUE) var/t_is = p_are() . = list() var/borg_type = module ? module : "Default" //This isn't even used normally, but if that ever changes, just uncomment this /* var/obj/item/borg_chameleon/chameleon = locate() in src if(!chameleon) chameleon = locate() in src.module if(chameleon?.active) borg_type = "Engineering" */ . += "[t_He] [t_is] a [borg_type] unit" SEND_SIGNAL(src, COMSIG_PARENT_EXAMINE, usr, .)