/mob/living/silicon/robot name = "Cyborg" real_name = "Cyborg" icon = 'icons/mob/robots.dmi' icon_state = "robot" maxHealth = 100 health = 100 bubble_icon = "robot" designation = "Default" //used for displaying the prefix & getting the current module of cyborg has_limbs = 1 hud_type = /datum/hud/robot var/custom_name = "" var/braintype = "Cyborg" var/obj/item/robot_suit/robot_suit = null //Used for deconstruction to remember what the borg was constructed out of.. var/obj/item/mmi/mmi = null var/shell = FALSE var/deployed = FALSE var/mob/living/silicon/ai/mainframe = null var/datum/action/innate/undeployment/undeployment_action = new //Hud stuff var/obj/screen/inv1 = null var/obj/screen/inv2 = null var/obj/screen/inv3 = null var/obj/screen/lamp_button = null var/obj/screen/thruster_button = null var/obj/screen/hands = null var/shown_robot_modules = 0 //Used to determine whether they have the module menu shown or not var/obj/screen/robot_modules_background //3 Modules can be activated at any one time. var/obj/item/robot_module/module = null var/obj/item/module_active = null held_items = list(null, null, null) //we use held_items for the module holding, because that makes sense to do! var/mutable_appearance/eye_lights var/mob/living/silicon/ai/connected_ai = null var/obj/item/stock_parts/cell/cell = null var/opened = 0 var/emagged = FALSE var/emag_cooldown = 0 var/wiresexposed = 0 var/ident = 0 var/locked = TRUE var/list/req_access = list(ACCESS_ROBOTICS) var/alarms = list("Motion"=list(), "Fire"=list(), "Atmosphere"=list(), "Power"=list(), "Camera"=list(), "Burglar"=list()) var/speed = 0 // VTEC speed boost. var/magpulse = FALSE // Magboot-like effect. var/ionpulse = FALSE // Jetpack-like effect. var/ionpulse_on = FALSE // Jetpack-like effect. var/datum/effect_system/trail_follow/ion/ion_trail // Ionpulse effect. var/low_power_mode = 0 //whether the robot has no charge left. var/datum/effect_system/spark_spread/spark_system // So they can initialize sparks whenever/N var/lawupdate = 1 //Cyborgs will sync their laws with their AI by default var/scrambledcodes = 0 // Used to determine if a borg shows up on the robotics console. Setting to one hides them. var/lockcharge //Boolean of whether the borg is locked down or not var/toner = 0 var/tonermax = 40 var/lamp_max = 10 //Maximum brightness of a borg lamp. Set as a var for easy adjusting. var/lamp_intensity = 0 //Luminosity of the headlamp. 0 is off. Higher settings than the minimum require power. light_color = "#FFCC66" light_power = 0.8 var/lamp_cooldown = 0 //Flag for if the lamp is on cooldown after being forcibly disabled. var/sight_mode = 0 hud_possible = list(ANTAG_HUD, DIAG_STAT_HUD, DIAG_HUD, DIAG_BATT_HUD, DIAG_TRACK_HUD) var/list/upgrades = list() var/hasExpanded = FALSE var/obj/item/hat var/hat_offset = -3 var/list/equippable_hats = list(/obj/item/clothing/head/caphat, /obj/item/clothing/head/hardhat, /obj/item/clothing/head/centhat, /obj/item/clothing/head/HoS, /obj/item/clothing/head/beret, /obj/item/clothing/head/kitty, /obj/item/clothing/head/hopcap, /obj/item/clothing/head/wizard, /obj/item/clothing/head/nursehat, /obj/item/clothing/head/sombrero, /obj/item/clothing/head/helmet/chaplain/witchunter_hat, /obj/item/clothing/head/soft/, //All baseball caps /obj/item/clothing/head/that, //top hat /obj/item/clothing/head/collectable/tophat, //Not sure where this one is found, but it looks the same so might as well include /obj/item/clothing/mask/bandana/, //All bandanas (which only work in hat mode) /obj/item/clothing/head/fedora, /obj/item/clothing/head/beanie/, //All beanies /obj/item/clothing/ears/headphones, /obj/item/clothing/head/helmet/skull, /obj/item/clothing/head/crown/fancy) can_buckle = TRUE buckle_lying = FALSE var/static/list/can_ride_typecache = typecacheof(/mob/living/carbon/human) /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) AddComponent(/datum/component/empprotection, EMP_PROTECT_WIRES) 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 ident = rand(1, 999) if(!cell) cell = new /obj/item/stock_parts/cell/high(src) 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.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 updatename() equippable_hats = typecacheof(equippable_hats) playsound(loc, 'sound/voice/liveagain.ogg', 75, 1) aicamera = new/obj/item/camera/siliconcam/robot_camera(src) toner = tonermax diag_hud_set_borgcell() verbs += /mob/living/proc/lay_down //CITADEL EDIT gimmie rest verb kthx //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 GLOB.dead_mob_list -= mmi.brainmob GLOB.alive_mob_list += mmi.brainmob 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 //CITADEL EDIT: Cyborgs drop encryption keys on destroy if(istype(radio) && istype(radio.keyslot)) radio.keyslot.forceMove(T) radio.keyslot = null //END CITADEL EDIT if(connected_ai) connected_ai.connected_robots -= src if(shell) GLOB.available_ai_shells -= src else if(T && istype(radio) && istype(radio.keyslot)) radio.keyslot.forceMove(T) radio.keyslot = null qdel(wires) qdel(module) qdel(eye_lights) wires = null module = null eye_lights = null cell = null return ..() /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 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, \ "Janitor" = /obj/item/robot_module/janitor, \ "Service" = /obj/item/robot_module/butler) if(!CONFIG_GET(flag/disable_peaceborg)) modulelist["Peacekeeper"] = /obj/item/robot_module/peacekeeper if(!CONFIG_GET(flag/disable_secborg)) modulelist["Security"] = /obj/item/robot_module/security modulelist += get_cit_modules() //Citadel change - adds Citadel's borg modules. var/input_module = input("Please, select a module!", "Robot", null, null) as null|anything in 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(changed_name == "" && C && C.prefs.custom_names["cyborg"] != DEFAULT_CYBORG_NAME) if(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/Stat() ..() if(statpanel("Status")) if(cell) stat("Charge Left:", "[cell.charge]/[cell.maxcharge]") else stat(null, text("No Cell Inserted!")) if(module) for(var/datum/robot_energy_storage/st in module.storages) stat("[st.name]:", "[st.energy]/[st.max_energy]") if(connected_ai) stat("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 1 /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 (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/attackby(obj/item/W, mob/user, params) if(istype(W, /obj/item/weldingtool) && (user.a_intent != INTENT_HARM || user == src)) user.changeNext_move(CLICK_CD_MELEE) 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 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].") return else if(istype(W, /obj/item/stack/cable_coil) && wiresexposed) user.changeNext_move(CLICK_CD_MELEE) var/obj/item/stack/cable_coil/coil = W if (getFireLoss() > 0 || getToxLoss() > 0) if(src == user && coil.use(1)) to_chat(user, "You start fixing yourself...") if(!do_after(user, 50, target = src)) return adjustFireLoss(-10) adjustToxLoss(-10) if (coil.use(1)) to_chat(user, "You start fixing [src]...") if(!do_after(user, 30, target = 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, "You need more cable to repair [src]!") else to_chat(user, "The wires seem fine, there's no need to fix them.") else if(istype(W, /obj/item/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(istype(W, /obj/item/screwdriver) && opened && !cell) // haxing wiresexposed = !wiresexposed to_chat(user, "The wires have been [wiresexposed ? "exposed" : "unexposed"]") update_icons() else if(istype(W, /obj/item/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(istype(W, /obj/item/wrench) && opened && !cell) //Deconstruction. The flashes break from the fall, to prevent this from being a ghetto reset module. if(!lockcharge) 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) qdel(U) else U.forceMove(src) upgrades += U 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 if(istype(W, /obj/item/flashlight)) if(!opened) to_chat(user, "You need to open the panel to repair the headlamp!") else if(lamp_cooldown <= world.time) to_chat(user, "The headlamp is already functional!") else if(!user.temporarilyRemoveItemFromInventory(W)) to_chat(user, "[W] seems to be stuck to your hand. You'll have to find a different light.") return lamp_cooldown = 0 qdel(W) to_chat(user, "You replace the headlamp bulbs.") else 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 1 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 1 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 0 /mob/living/silicon/robot/proc/check_access(obj/item/card/id/I) if(!istype(req_access, /list)) //something's very wrong return 1 var/list/L = req_access if(!L.len) //no requirements return 1 if(!istype(I, /obj/item/card/id) && isitem(I)) I = I.GetID() if(!I || !I.access) //not ID or no access return 0 for(var/req in req_access) if(!(req in I.access)) //doesn't have this access return 0 return 1 /mob/living/silicon/robot/regenerate_icons() return update_icons() /mob/living/silicon/robot/update_icons() cut_overlays() icon_state = module.cyborg_base_icon //Citadel changes start here - Allows modules to use different icon files, and allows modules to specify a pixel offset icon = (module.cyborg_icon_override ? module.cyborg_icon_override : initial(icon)) if(laser) add_overlay("laser")//Is this even used??? - Yes borg/inventory.dm if(disabler) add_overlay("disabler")//ditto if(sleeper_g && module.sleeper_overlay) add_overlay("[module.sleeper_overlay]_g[sleeper_nv ? "_nv" : ""]") if(sleeper_r && module.sleeper_overlay) add_overlay("[module.sleeper_overlay]_r[sleeper_nv ? "_nv" : ""]") if(module.dogborg == TRUE) if(resting) cut_overlays() icon_state = "[module.cyborg_base_icon]-rest" else icon_state = "[module.cyborg_base_icon]" if(stat == DEAD && module.has_snowflake_deadsprite) icon_state = "[module.cyborg_base_icon]-wreck" if(module.cyborg_pixel_offset) pixel_x = module.cyborg_pixel_offset //End of citadel changes if(module.cyborg_base_icon == "robot") icon = 'icons/mob/robots.dmi' pixel_x = initial(pixel_x) if(stat != DEAD && !(IsUnconscious() || IsStun() || IsKnockdown() || low_power_mode)) //Not dead, not stunned. if(!eye_lights) eye_lights = new() if(lamp_intensity > 2) eye_lights.icon_state = "[module.special_light_key ? "[module.special_light_key]":"[module.cyborg_base_icon]"]_l" else eye_lights.icon_state = "[module.special_light_key ? "[module.special_light_key]":"[module.cyborg_base_icon]"]_e[is_servant_of_ratvar(src) ? "_r" : ""]" eye_lights.icon = icon add_overlay(eye_lights) if(opened) if(wiresexposed) add_overlay("ov-opencover +w") else if(cell) add_overlay("ov-opencover +c") else add_overlay("ov-opencover -c") if(hat) var/mutable_appearance/head_overlay = hat.build_worn_icon(state = hat.icon_state, default_layer = 20, default_icon_file = 'icons/mob/head.dmi') head_overlay.pixel_y += hat_offset add_overlay(head_overlay) update_fire() /mob/living/silicon/robot/proc/self_destruct() if(emagged) if(mmi) qdel(mmi) explosion(src.loc,1,2,4,flame_range = 2) else explosion(src.loc,-1,0,2) gib() /mob/living/silicon/robot/proc/UnlinkSelf() if(src.connected_ai) connected_ai.connected_robots -= src src.connected_ai = null lawupdate = 0 lockcharge = 0 canmove = 1 scrambledcodes = 1 //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. /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 = 1) // They stay locked down if their wire is cut. if(wires.is_cut(WIRE_LOCKDOWN)) state = 1 if(state) throw_alert("locked", /obj/screen/alert/locked) else clear_alert("locked") lockcharge = state update_canmove() /mob/living/silicon/robot/proc/SetEmagged(new_state) emagged = new_state module.rebuild_modules() update_icons() if(emagged) throw_alert("hacked", /obj/screen/alert/hacked) else clear_alert("hacked") /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() /mob/living/silicon/robot/proc/control_headlamp() if(stat || lamp_cooldown > world.time || low_power_mode) to_chat(src, "This function is currently offline.") return //Some sort of magical "modulo" thing which somehow increments lamp power by 2, until it hits the max and resets to 0. lamp_intensity = (lamp_intensity+2) % (lamp_max+2) to_chat(src, "[lamp_intensity ? "Headlamp power set to Level [lamp_intensity/2]" : "Headlamp disabled."]") update_headlamp() /mob/living/silicon/robot/proc/update_headlamp(var/turn_off = 0, var/cooldown = 100) set_light(0) if(lamp_intensity && (turn_off || stat || low_power_mode)) to_chat(src, "Your headlamp has been deactivated.") lamp_intensity = 0 lamp_cooldown = world.time + cooldown else set_light(lamp_intensity) if(lamp_button) lamp_button.icon_state = "lamp[lamp_intensity]" update_icons() /mob/living/silicon/robot/proc/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 = 0 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.updateicon() 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) /mob/living/silicon/robot/modules var/set_module = null /mob/living/silicon/robot/modules/Initialize() . = ..() 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/janitor set_module = /obj/item/robot_module/janitor /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 /mob/living/silicon/robot/modules/syndicate/Initialize() . = ..() cell = new /obj/item/stock_parts/cell/hyper(src, 25000) 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/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/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) if(stat || lockcharge || 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(health < maxHealth*0.5) //Gradual break down of modules as more damage is sustained if(uneq_module(held_items[3])) playsound(loc, 'sound/machines/warning-buzzer.ogg', 50, 1, 1) audible_message("[src] sounds an alarm! \"SYSTEM ERROR: Module 3 OFFLINE.\"") to_chat(src, "SYSTEM ERROR: Module 3 OFFLINE.") if(health < 0) if(uneq_module(held_items[2])) audible_message("[src] sounds an alarm! \"SYSTEM ERROR: Module 2 OFFLINE.\"") to_chat(src, "SYSTEM ERROR: Module 2 OFFLINE.") playsound(loc, 'sound/machines/warning-buzzer.ogg', 60, 1, 1) if(health < -maxHealth*0.5) if(uneq_module(held_items[1])) audible_message("[src] sounds an alarm! \"CRITICAL ERROR: All modules OFFLINE.\"") to_chat(src, "CRITICAL ERROR: All modules OFFLINE.") playsound(loc, 'sound/machines/warning-buzzer.ogg', 75, 1, 1) /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_INVISIBLE 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 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() return if(IsUnconscious() || IsStun() || IsKnockdown() || getOxyLoss() > maxHealth*0.5) if(stat == CONSCIOUS) stat = UNCONSCIOUS blind_eyes(1) update_canmove() update_headlamp() else if(stat == UNCONSCIOUS) stat = CONSCIOUS adjust_blindness(-1) update_canmove() update_headlamp() diag_hud_set_status() diag_hud_set_health() diag_hud_set_aishell() update_health_hud() /mob/living/silicon/robot/revive(full_heal = 0, admin_revive = 0) if(..()) //successfully ressuscitated from death if(!QDELETED(builtInCamera) && !wires.is_cut(WIRE_CAMERA)) builtInCamera.toggle_cam(src,0) update_headlamp() if(admin_revive) locked = TRUE notify_ai(NEW_BORG) . = 1 /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() uneq_all() shown_robot_modules = FALSE if(hud_used) hud_used.update_robot_modules_display() if (hasExpanded) resize = 0.5 hasExpanded = FALSE update_transform() 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() speed = 0 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 hands.icon = (module.moduleselect_alternate_icon ? module.moduleselect_alternate_icon : initial(hands.icon)) //CITADEL CHANGE - allows module select icons to use a different icon file if(module.can_be_pushed) status_flags |= CANPUSH else status_flags &= ~CANPUSH if(module.clean_on_move) AddComponent(/datum/component/cleaning) else qdel(GetComponent(/datum/component/cleaning)) hat_offset = module.hat_offset magpulse = module.magpulsing 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() /mob/living/silicon/robot/proc/make_shell(var/obj/item/borg/upgrade/ai/board) if(!board) upgrades |= new /obj/item/borg/upgrade/ai(src) shell = TRUE braintype = "AI Shell" name = "[designation] AI Shell [rand(100,999)]" 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) /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 [rand(100,999)]" real_name = name if(!QDELETED(builtInCamera)) builtInCamera.c_tag = real_name diag_hud_set_aishell() /mob/living/silicon/robot/proc/deploy_init(var/mob/living/silicon/ai/AI) real_name = "[AI.real_name] shell [rand(100, 999)] - [designation]" //Randomizing the name so it shows up separately in the shells list name = real_name if(!QDELETED(builtInCamera)) builtInCamera.c_tag = real_name //update the camera name too mainframe = AI deployed = TRUE 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" /datum/action/innate/undeployment/Trigger() if(!..()) return FALSE var/mob/living/silicon/robot/R = owner R.undeploy() 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 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 /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) return if(incapacitated()) return if(M.incapacitated()) return if(module) if(!module.allow_riding) M.visible_message("Unfortunately, [M] just can't seem to hold onto [src]!") return if(iscarbon(M) && (!riding_datum.equip_buckle_inhands(M, 1))) 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)) GET_COMPONENT(riding_datum, /datum/component/riding) if(istype(riding_datum)) riding_datum.unequip_buckle_inhands(user) riding_datum.restore_position(user) . = ..(user) /mob/living/silicon/robot/proc/TryConnectToAI() connected_ai = select_active_ai_with_fewest_borgs() if(connected_ai) connected_ai.connected_robots += src lawsync() lawupdate = 1 return TRUE picturesync() return FALSE /mob/living/silicon/robot/proc/picturesync() if(connected_ai && 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