/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)
ADD_TRAIT(src, TRAIT_CAN_STRIP, INNATE_TRAIT)
AddComponent(/datum/component/tippable, \
tip_time = 3 SECONDS, \
untip_time = 2 SECONDS, \
self_right_time = 60 SECONDS, \
post_tipped_callback = CALLBACK(src, .proc/after_tip_over), \
post_untipped_callback = CALLBACK(src, .proc/after_righted), \
roleplay_friendly = TRUE, \
roleplay_emotes = list(/datum/emote/living/human/buzz, /datum/emote/living/human/buzz2, /datum/emote/living/human/beep, /datum/emote/living/human/beep2), \
roleplay_callback = CALLBACK(src, .proc/untip_roleplay)) // SKYRAT EDIT CHANGE
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)
RegisterSignal(src, COMSIG_LIGHT_EATER_ACT, .proc/on_light_eater)
robot_modules_background = new()
robot_modules_background.icon_state = "block"
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()
ident = rand(1, 999)
previous_health = health
if(ispath(cell))
cell = new cell(src)
create_modularInterface()
model = new /obj/item/robot_model(src)
model.rebuild_modules()
if(lawupdate)
make_laws()
for (var/law in laws.inherent)
lawcheck += law
if(!TryConnectToAI())
lawupdate = FALSE
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
update_icons()
. = ..()
//If this body is meant to be a borg controlled by the AI player
if(shell)
make_shell()
else
//MMI stuff. Held togheter by magic. ~Miauw
if(!mmi?.brainmob)
mmi = new (src)
mmi.brain = new /obj/item/organ/internal/brain(mmi)
mmi.brain.organ_flags |= ORGAN_FROZEN
mmi.brain.name = "[real_name]'s brain"
mmi.name = "[initial(mmi.name)]: [real_name]"
mmi.set_brainmob(new /mob/living/brain(mmi))
mmi.brainmob.name = src.real_name
mmi.brainmob.real_name = src.real_name
mmi.brainmob.container = mmi
mmi.update_appearance()
setup_default_name()
aicamera = new/obj/item/camera/siliconcam/robot_camera(src)
toner = tonermax
diag_hud_set_borgcell()
logevent("System brought online.")
alert_control = new(src, list(ALARM_ATMOS, ALARM_FIRE, ALARM_POWER, ALARM_CAMERA, ALARM_BURGLAR, ALARM_MOTION), list(z))
RegisterSignal(alert_control.listener, COMSIG_ALARM_LISTENER_TRIGGERED, .proc/alarm_triggered)
RegisterSignal(alert_control.listener, COMSIG_ALARM_LISTENER_CLEARED, .proc/alarm_cleared)
alert_control.listener.RegisterSignal(src, COMSIG_LIVING_DEATH, /datum/alarm_listener/proc/prevent_alarm_changes)
alert_control.listener.RegisterSignal(src, COMSIG_LIVING_REVIVE, /datum/alarm_listener/proc/allow_alarm_changes)
/mob/living/silicon/robot/model/syndicate/Initialize(mapload)
. = ..()
laws = new /datum/ai_laws/syndicate_override()
addtimer(CALLBACK(src, .proc/show_playstyle), 5)
/mob/living/silicon/robot/model/syndicate/create_modularInterface()
if(!modularInterface)
modularInterface = new /obj/item/modular_computer/tablet/integrated/syndicate(src)
modularInterface.saved_identification = real_name
modularInterface.saved_job = "Cyborg"
return ..()
/**
* Sets the tablet theme and icon
*
* These variables are based on if the borg is a syndicate type or is emagged. This gets used in model change code
* and also borg emag code.
*/
/mob/living/silicon/robot/proc/set_modularInterface_theme()
if(istype(model, /obj/item/robot_model/syndicate) || emagged)
modularInterface.device_theme = "syndicate"
modularInterface.icon_state = "tablet-silicon-syndicate"
modularInterface.icon_state_powered = "tablet-silicon-syndicate"
modularInterface.icon_state_unpowered = "tablet-silicon-syndicate"
else
modularInterface.device_theme = "ntos"
modularInterface.icon_state = "tablet-silicon"
modularInterface.icon_state_powered = "tablet-silicon"
modularInterface.icon_state_unpowered = "tablet-silicon"
modularInterface.update_icon()
//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.set_stat(CONSCIOUS)
mind.transfer_to(mmi.brainmob)
mmi.update_appearance()
else
to_chat(src, span_boldannounce("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)
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(model)
QDEL_NULL(eye_lights)
QDEL_NULL(inv1)
QDEL_NULL(inv2)
QDEL_NULL(inv3)
QDEL_NULL(hands)
QDEL_NULL(spark_system)
QDEL_NULL(alert_control)
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"])
alert_control.ui_interact(src)
// SKYRAT EDIT ADDITION -- Customization
if(href_list["lookup_info"])
tgui.holder = src
tgui.ui_interact(usr) //datum has a tgui component, here we open the window
// SKYRAT EDIT END
/mob/living/silicon/robot/get_cell()
return cell
/mob/living/silicon/robot/proc/pick_model()
if(model.type != /obj/item/robot_model)
return
if(wires.is_cut(WIRE_RESET_MODEL))
to_chat(src,span_userdanger("ERROR: Model installer reply timeout. Please check internal connections."))
return
if(lockcharge == TRUE)
to_chat(src,span_userdanger("ERROR: Lockdown is engaged. Please disengage lockdown to pick module."))
return
// SKYRAT EDIT START - Making the cyborg model list static to reduce how many times it's generated.
if(!length(GLOB.cyborg_model_list))
GLOB.cyborg_model_list = list(
"Engineering" = /obj/item/robot_model/engineering,
"Medical" = /obj/item/robot_model/medical,
"Cargo" = /obj/item/robot_model/cargo,
"Miner" = /obj/item/robot_model/miner,
"Janitor" = /obj/item/robot_model/janitor,
"Service" = /obj/item/robot_model/service,
)
if(!CONFIG_GET(flag/disable_peaceborg))
GLOB.cyborg_model_list["Peacekeeper"] = /obj/item/robot_model/peacekeeper
if(!CONFIG_GET(flag/disable_secborg))
GLOB.cyborg_model_list["Security"] = /obj/item/robot_model/security
for(var/model in GLOB.cyborg_model_list)
// Creating the lists here since we know all the model icons will need them right after.
GLOB.cyborg_all_models_icon_list[model] = list()
// Create radial menu for choosing borg model
if(!length(GLOB.cyborg_base_models_icon_list))
for(var/option in GLOB.cyborg_model_list)
var/obj/item/robot_model/model = GLOB.cyborg_model_list[option]
var/model_icon = initial(model.cyborg_base_icon)
GLOB.cyborg_base_models_icon_list[option] = image(icon = 'modular_skyrat/master_files/icons/mob/robots.dmi', icon_state = model_icon) // SKYRAT EDIT - CARGO BORGS - ORIGINAL: model_icons[option] = image(icon = 'icons/mob/robots.dmi', icon_state = model_icon)
// SKYRAT EDIT END
var/input_model = show_radial_menu(src, src, GLOB.cyborg_base_models_icon_list, radius = 42)
if(!input_model || model.type != /obj/item/robot_model)
return
model.transform_to(GLOB.cyborg_model_list[input_model])
/// Used to setup the a basic and (somewhat) unique name for the robot.
/mob/living/silicon/robot/proc/setup_default_name()
var/new_name
if(GLOB.current_anonymous_theme) //only robotic renames will allow for anything other than the anonymous one
new_name = GLOB.current_anonymous_theme.anonymous_ai_name(FALSE)
else if(custom_name)
new_name = custom_name
else
new_name = get_standard_name()
if(new_name != real_name)
fully_replace_character_name(real_name, new_name)
/// Updates the borg name taking the client preferences into account.
/mob/living/silicon/robot/proc/updatename(client/pref_source)
if(shell)
return
if(!pref_source)
pref_source = client
var/changed_name = ""
if(GLOB.current_anonymous_theme) //only robotic renames will allow for anything other than the anonymous one
changed_name = GLOB.current_anonymous_theme.anonymous_ai_name(FALSE)
else if(custom_name)
changed_name = custom_name
else if(pref_source && pref_source.prefs.read_preference(/datum/preference/name/cyborg) != DEFAULT_CYBORG_NAME)
apply_pref_name(/datum/preference/name/cyborg, pref_source)
return //built in camera handled in proc
else
changed_name = get_standard_name()
fully_replace_character_name(real_name, changed_name)
/mob/living/silicon/robot/proc/get_standard_name()
return "[(designation ? "[designation] " : "")][mmi.braintype]-[ident]"
/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, span_notice("No thrusters are installed!"))
return
if(!ion_trail)
ion_trail = new
ion_trail.set_up(src)
ionpulse_on = !ionpulse_on
to_chat(src, span_notice("You [ionpulse_on ? null :"de"]activate your ion thrusters."))
if(ionpulse_on)
ion_trail.start()
else
ion_trail.stop()
/mob/living/silicon/robot/get_status_tab_items()
. = ..()
. += ""
if(cell)
. += "Charge Left: [cell.charge]/[cell.maxcharge]"
else
. += "No Cell Inserted!"
if(model)
for(var/datum/robot_energy_storage/st in model.storages)
. += "[st.name]: [st.energy]/[st.max_energy]"
if(connected_ai)
. += "Master AI: [connected_ai.name]"
/mob/living/silicon/robot/proc/alarm_triggered(datum/source, alarm_type, area/source_area)
SIGNAL_HANDLER
queueAlarm("--- [alarm_type] alarm detected in [source_area.name]!", alarm_type)
/mob/living/silicon/robot/proc/alarm_cleared(datum/source, alarm_type, area/source_area)
SIGNAL_HANDLER
queueAlarm("--- [alarm_type] alarm in [source_area.name] has been cleared.", alarm_type, FALSE)
/mob/living/silicon/robot/can_interact_with(atom/A)
if (A == modularInterface)
return TRUE //bypass for borg tablets
if (low_power_mode)
return FALSE
return ..()
/mob/living/silicon/robot/proc/after_tip_over(mob/user)
if(hat)
hat.forceMove(drop_location())
unbuckle_all_mobs()
///For any special cases for robots after being righted.
/mob/living/silicon/robot/proc/after_righted(mob/user)
return
/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(isalien(M))
var/mob/living/carbon/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/update_icons()
cut_overlays()
SSvis_overlays.remove_vis_overlay(src, managed_vis_overlays)
icon_state = model.cyborg_base_icon
if(stat != DEAD && !(HAS_TRAIT(src, TRAIT_KNOCKEDOUT) || IsStun() || IsParalyzed() || low_power_mode)) //Not dead, not stunned.
if(!eye_lights)
eye_lights = new()
if(lamp_enabled || lamp_doom)
eye_lights.icon_state = "[model.special_light_key ? "[model.special_light_key]":"[model.cyborg_base_icon]"]_l"
eye_lights.color = lamp_doom? COLOR_RED : lamp_color
eye_lights.plane = ABOVE_LIGHTING_PLANE //glowy eyes
else
eye_lights.icon_state = "[model.special_light_key ? "[model.special_light_key]":"[model.cyborg_base_icon]"]_e"
eye_lights.color = COLOR_WHITE
eye_lights.plane = ABOVE_GAME_PLANE
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(default_layer = 20, default_icon_file = 'icons/mob/clothing/head.dmi')
head_overlay.pixel_y += hat_offset
add_overlay(head_overlay)
update_fire()
/mob/living/silicon/robot/proc/self_destruct(mob/usr)
var/turf/groundzero = get_turf(src)
message_admins(span_notice("[ADMIN_LOOKUPFLW(usr)] detonated [key_name_admin(src, client)] at [ADMIN_VERBOSEJMP(groundzero)]!"))
log_game("[key_name(usr)] detonated [key_name(src)]!")
log_combat(usr, src, "detonated cyborg")
log_silicon("CYBORG: [key_name(src)] has been detonated by [key_name(usr)].")
if(connected_ai)
to_chat(connected_ai, "
[span_alert("ALERT - Cyborg detonation detected: [name]")]
")
if(emagged)
QDEL_NULL(mmi)
explosion(src, devastation_range = 1, heavy_impact_range = 2, light_impact_range = 4, flame_range = 2)
else
explosion(src, devastation_range = -1, light_impact_range = 2)
gib()
/mob/living/silicon/robot/proc/UnlinkSelf()
set_connected_ai(null)
lawupdate = FALSE
set_lockcharge(FALSE)
scrambledcodes = TRUE
log_silicon("CYBORG: [key_name(src)] has been unlinked from an AI.")
//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
return ..()
/mob/living/silicon/robot/execute_mode()
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(ALERT_HACKED, /atom/movable/screen/alert/locked)
else
clear_alert(ALERT_HACKED)
set_lockcharge(state)
///Reports the event of the change in value of the lockcharge variable.
/mob/living/silicon/robot/proc/set_lockcharge(new_lockcharge)
if(new_lockcharge == lockcharge)
return
. = lockcharge
lockcharge = new_lockcharge
if(lockcharge)
if(!.)
ADD_TRAIT(src, TRAIT_IMMOBILIZED, LOCKED_BORG_TRAIT)
else if(.)
REMOVE_TRAIT(src, TRAIT_IMMOBILIZED, LOCKED_BORG_TRAIT)
logevent("System lockdown [lockcharge?"triggered":"released"].")
/mob/living/silicon/robot/proc/SetEmagged(new_state)
emagged = new_state
model.rebuild_modules()
update_icons()
if(emagged)
throw_alert(ALERT_HACKED, /atom/movable/screen/alert/hacked)
else
clear_alert(ALERT_HACKED)
set_modularInterface_theme()
/// Special handling for getting hit with a light eater
/mob/living/silicon/robot/proc/on_light_eater(mob/living/silicon/robot/source, datum/light_eater)
SIGNAL_HANDLER
if(lamp_enabled)
smash_headlamp()
return COMPONENT_BLOCK_LIGHT_EATER
/**
* 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, span_danger("Your headlamp is broken! You'll need a human to help replace it."))
/**
* 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_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_appearance()
update_icons()
return
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_appearance()
update_icons()
/mob/living/silicon/robot/proc/deconstruct()
SEND_SIGNAL(src, COMSIG_BORG_SAFE_DECONSTRUCT)
if(shell)
undeploy()
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_appearance()
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/proc/notify_ai(notifytype, oldname, newname)
if(!connected_ai)
return
switch(notifytype)
if(AI_NOTIFICATION_NEW_BORG) //New Cyborg
to_chat(connected_ai, "
[span_notice("NOTICE - New cyborg connection detected: [name]")]
")
if(AI_NOTIFICATION_NEW_MODEL) //New Model
to_chat(connected_ai, "
[span_notice("NOTICE - Cyborg model change detected: [name] has loaded the [designation] model.")]
")
if(AI_NOTIFICATION_CYBORG_RENAMED) //New Name
to_chat(connected_ai, "
[span_notice("NOTICE - Cyborg reclassification detected: [oldname] is now designated as [newname].")]
")
if(AI_NOTIFICATION_AI_SHELL) //New Shell
to_chat(connected_ai, "
[span_notice("NOTICE - New cyborg shell detected: [name]")]
")
if(AI_NOTIFICATION_CYBORG_DISCONNECTED) //Tampering with the wires
to_chat(connected_ai, "
[span_notice("NOTICE - Remote telemetry lost with [name].")]
")
/mob/living/silicon/robot/canUseTopic(atom/movable/M, be_close=FALSE, no_dexterity=FALSE, no_tk=FALSE, need_hands = FALSE, floor_okay=FALSE)
if(lockcharge || low_power_mode)
to_chat(src, span_warning("You can't do that right now!"))
return FALSE
return ..()
/mob/living/silicon/robot/updatehealth()
..()
if(!model.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)
if(SSmapping.level_trait(z, ZTRAIT_NOXRAY))
sight = null
else if(is_secret_level(z))
sight = initial(sight)
else
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
if(SSmapping.level_trait(z, ZTRAIT_NOXRAY))
sight = null
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(HAS_TRAIT(src, TRAIT_KNOCKEDOUT) || IsStun() || IsKnockdown() || IsParalyzed())
set_stat(UNCONSCIOUS)
else
set_stat(CONSCIOUS)
diag_hud_set_status()
diag_hud_set_health()
diag_hud_set_aishell()
update_health_hud()
update_icons() //Updates eye_light overlay
/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(AI_NOTIFICATION_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(!.)
return
notify_ai(AI_NOTIFICATION_CYBORG_RENAMED, oldname, newname)
if(!QDELETED(builtInCamera))
builtInCamera.c_tag = real_name
modularInterface.saved_identification = real_name
custom_name = newname
/mob/living/silicon/robot/proc/ResetModel()
SEND_SIGNAL(src, COMSIG_BORG_SAFE_DECONSTRUCT)
uneq_all()
shown_robot_modules = FALSE
for(var/obj/item/storage/bag in model.contents) // drop all of the items that may be stored by the cyborg
for(var/obj/item in bag)
item.forceMove(drop_location())
if(hud_used)
hud_used.update_robot_modules_display()
if (hasExpanded)
//resize = 0.5 //ORIGINAL
resize = 0.8 //SKYRAT EDIT CHANGE - CYBORG
hasExpanded = FALSE
update_transform()
//SKYRAT EDIT ADDITION BEGIN - CYBORG
if (hasShrunk)
hasShrunk = FALSE
resize = (4/3)
update_transform()
hasAffection = FALSE //Just so they can get the affection modules back if they want them.
//SKYRAT EDIT ADDITION END
logevent("Chassis model has been reset.")
log_silicon("CYBORG: [key_name(src)] has reset their cyborg model.")
model.transform_to(/obj/item/robot_model)
// Remove upgrades.
for(var/obj/item/borg/upgrade/I in upgrades)
I.forceMove(get_turf(src))
ionpulse = FALSE
revert_shell()
return TRUE
/mob/living/silicon/robot/model/syndicate/ResetModel()
return
/mob/living/silicon/robot/proc/has_model()
if(!model || model.type == /obj/item/robot_model)
. = FALSE
else
. = TRUE
/mob/living/silicon/robot/proc/update_module_innate()
designation = model.name
if(hands)
hands.icon_state = model.model_select_icon
REMOVE_TRAITS_IN(src, MODEL_TRAIT)
if(model.model_traits)
for(var/trait in model.model_traits)
ADD_TRAIT(src, trait, MODEL_TRAIT)
hat_offset = model.hat_offset
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/movable/gone, direction)
if(hat && hat == gone)
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, span_danger("Upgrade error."))
new_upgrade.forceMove(loc) //gets lost otherwise
return FALSE
to_chat(user, span_notice("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()
/**
* 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"
/datum/action/innate/undeployment/Trigger(trigger_flags)
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
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/mouse_buckle_handling(mob/living/M, mob/living/user)
//Don't try buckling on INTENT_HARM so that silicons can search people's inventories without loading them
if(can_buckle && isliving(user) && isliving(M) && !(M in buckled_mobs) && ((user != src) || (!combat_mode)))
return user_buckle_mob(M, user, check_loc = FALSE)
/mob/living/silicon/robot/buckle_mob(mob/living/M, force = FALSE, check_loc = TRUE, buckle_mob_flags= RIDER_NEEDS_ARM)
if(!is_type_in_typecache(M, can_ride_typecache))
M.visible_message(span_warning("[M] really can't seem to mount [src]..."))
return
if(stat || incapacitated())
return
if(model && !model.allow_riding)
M.visible_message(span_boldwarning("Unfortunately, [M] just can't seem to hold onto [src]!"))
return
buckle_mob_flags= RIDER_NEEDS_ARM // just in case
return ..()
/mob/living/silicon/robot/execute_resist()
. = ..()
if(!has_buckled_mobs())
return
for(var/mob/unbuckle_me_now as anything in buckled_mobs)
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)
SIGNAL_HANDLER
if(model)
model.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/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)
/mob/living/silicon/robot/get_exp_list(minutes)
. = ..()
var/datum/job/cyborg/cyborg_job_ref = SSjob.GetJobType(/datum/job/cyborg)
.[cyborg_job_ref.title] = minutes
/mob/living/silicon/robot/proc/untip_roleplay()
to_chat(src, span_notice("Your frustration has empowered you! You can now right yourself faster!"))
/mob/living/silicon/robot/update_fire_overlay(stacks, on_fire, last_icon_state, suffix = "")
var/fire_icon = "generic_fire[suffix]"
if(!GLOB.fire_appearances[fire_icon])
var/mutable_appearance/new_fire_overlay = mutable_appearance('icons/mob/onfire.dmi', fire_icon, -FIRE_LAYER)
new_fire_overlay.appearance_flags = RESET_COLOR
GLOB.fire_appearances[fire_icon] = new_fire_overlay
if(stacks && on_fire)
if(last_icon_state == fire_icon)
return last_icon_state
add_overlay(GLOB.fire_appearances[fire_icon])
return fire_icon
if(!last_icon_state)
return last_icon_state
cut_overlay(GLOB.fire_appearances[fire_icon])
return null
/// Draw power from the robot
/mob/living/silicon/robot/proc/draw_power(power_to_draw)
cell?.use(power_to_draw)