mirror of
https://github.com/vgstation-coders/vgstation13.git
synced 2025-12-10 10:21:11 +00:00
1345 lines
42 KiB
Plaintext
1345 lines
42 KiB
Plaintext
var/list/cyborg_list = list()
|
|
|
|
/mob/living/silicon/robot
|
|
name = "Cyborg"
|
|
real_name = "Cyborg"
|
|
icon = 'icons/mob/robots.dmi'
|
|
icon_state = "robot"
|
|
maxHealth = 300
|
|
health = 300
|
|
flashed = FALSE
|
|
|
|
var/custom_name = ""
|
|
var/namepick_uses = 1 // /vg/: Allows AI to disable namepick().
|
|
var/base_icon
|
|
var/image/eyes = null
|
|
|
|
//Sound
|
|
var/startup_sound = 'sound/voice/liveagain.ogg'
|
|
var/startup_vary = TRUE //Does the startup sounds vary?
|
|
|
|
var/obj/item/device/station_map/station_holomap = null
|
|
|
|
//Hud stuff
|
|
var/obj/abstract/screen/inv1 = null
|
|
var/obj/abstract/screen/inv2 = null
|
|
var/obj/abstract/screen/inv3 = null
|
|
var/obj/abstract/screen/sensor = null
|
|
|
|
var/shown_robot_modules = FALSE
|
|
var/obj/abstract/screen/robot_modules_background
|
|
|
|
//3 Modules can be activated at any one time.
|
|
var/obj/item/weapon/robot_module/module = null
|
|
var/module_active = null
|
|
var/module_state_1 = null
|
|
var/module_state_2 = null
|
|
var/module_state_3 = null
|
|
|
|
var/mob/living/silicon/ai/connected_ai = null
|
|
var/AIlink = TRUE //Do we start linked to an AI?
|
|
|
|
var/obj/item/weapon/cell/cell = null
|
|
var/cell_type = /obj/item/weapon/cell/high/cyborg //The cell_type we're actually using.
|
|
|
|
var/obj/machinery/camera/camera = null
|
|
|
|
// Components are basically robot organs.
|
|
var/list/components = list()
|
|
var/component_extension = null
|
|
|
|
var/obj/item/device/mmi/mmi = null
|
|
var/obj/item/device/pda/ai/rbPDA = null
|
|
var/datum/wires/robot/wires = null
|
|
var/wiring_type = /datum/wires/robot
|
|
|
|
mob_bump_flag = ROBOT
|
|
mob_swap_flags = ROBOT|MONKEY|SLIME|SIMPLE_ANIMAL
|
|
mob_push_flags = ALLMOBS //trundle trundle
|
|
|
|
var/opened = FALSE
|
|
var/emagged = FALSE
|
|
var/illegal_weapons = FALSE
|
|
var/wiresexposed = FALSE
|
|
var/locked = TRUE
|
|
var/ident = FALSE
|
|
var/hasbutt = TRUE //Needed for bootyborgs... and buckling too.
|
|
var/alarms = list("Motion"=list(), "Fire"=list(), "Atmosphere"=list(), "Power"=list(), "Camera"=list())
|
|
var/viewalerts = FALSE
|
|
var/modtype = "Default"
|
|
var/jetpack = FALSE
|
|
var/datum/effect/effect/system/ion_trail_follow/ion_trail = null
|
|
var/jeton = FALSE
|
|
|
|
var/killswitch = FALSE
|
|
var/killswitch_time = 60
|
|
var/modulelock = FALSE
|
|
var/modulelock_time = 120
|
|
var/lawupdate = TRUE //Cyborgs will sync their laws with their AI by default
|
|
var/lockcharge //Used when locking down a borg to preserve cell charge
|
|
var/scrambledcodes = FALSE // Used to determine if a borg shows up on the robotics console. Setting to one hides them.
|
|
var/braintype = "Cyborg"
|
|
var/lawcheck[1]
|
|
var/ioncheck[1]
|
|
|
|
// Used to store the associations between sprite names and sprite index.
|
|
var/module_sprites[0]
|
|
|
|
//Photography
|
|
var/obj/item/device/camera/silicon/aicamera = null
|
|
var/toner = CYBORG_STARTING_TONER
|
|
var/tonermax = CYBORG_MAX_TONER
|
|
|
|
//Access
|
|
var/list/req_access = list(access_robotics) //Access needed to open cover
|
|
var/list/robot_access = list(access_ai_upload, access_robotics, access_maint_tunnels, access_external_airlocks) //Our current access
|
|
|
|
var/last_tase_timeofday
|
|
var/last_high_damage_taken_timeofday
|
|
|
|
/mob/living/silicon/robot/New(loc, var/malfAI = null)
|
|
ident = rand(1, 999)
|
|
updatename(modtype)
|
|
|
|
laws = getLawset(src)
|
|
robot_access = GetRobotAccess()
|
|
wires = new wiring_type(src)
|
|
station_holomap = new(src)
|
|
radio = new /obj/item/device/radio/borg(src)
|
|
aicamera = new/obj/item/device/camera/silicon/robot_camera(src)
|
|
|
|
if(AIlink)
|
|
if(malfAI)
|
|
connect_AI(malfAI)
|
|
else
|
|
connect_AI(select_active_ai_with_fewest_borgs())
|
|
|
|
track_globally()
|
|
|
|
if(!scrambledcodes && !camera)
|
|
camera = new /obj/machinery/camera(src)
|
|
camera.c_tag = real_name
|
|
if(!scrambledcodes)
|
|
camera.network = list(CAMERANET_SS13,CAMERANET_ROBOTS)
|
|
cyborg_cams[CAMERANET_ROBOTS] += camera
|
|
if(wires.IsCameraCut()) // 5 = BORG CAMERA
|
|
camera.status = 0
|
|
|
|
initialize_components()
|
|
// Create all the robot parts.
|
|
for(var/V in components) if(V != "power cell")
|
|
var/datum/robot_component/C = components[V]
|
|
C.installed = COMPONENT_INSTALLED
|
|
C.wrapped = new C.external_type
|
|
|
|
if(!cell)
|
|
cell = new cell_type(src)
|
|
|
|
updateicon()
|
|
|
|
hud_list[DIAG_HEALTH_HUD] = image('icons/mob/hud.dmi', src, "huddiagmax")
|
|
hud_list[DIAG_CELL_HUD] = image('icons/mob/hud.dmi', src, "hudbattmax")
|
|
|
|
..()
|
|
|
|
if (mind && !stored_freqs)
|
|
spawn(1)
|
|
mind.store_memory("Frequencies list: <br/><b>Command:</b> [COMM_FREQ] <br/> <b>Security:</b> [SEC_FREQ] <br/> <b>Medical:</b> [MED_FREQ] <br/> <b>Science:</b> [SCI_FREQ] <br/> <b>Engineering:</b> [ENG_FREQ] <br/> <b>Service:</b> [SER_FREQ] <b>Cargo:</b> [SUP_FREQ]<br/> <b>AI private:</b> [AIPRIV_FREQ]<br/>")
|
|
stored_freqs = 1
|
|
|
|
if(cell)
|
|
var/datum/robot_component/cell_component = components["power cell"]
|
|
cell_component.wrapped = cell
|
|
cell_component.installed = COMPONENT_INSTALLED
|
|
|
|
playsound(src, startup_sound, 75, startup_vary)
|
|
|
|
//Borgs speak all common languages by default.
|
|
add_language(LANGUAGE_GALACTIC_COMMON)
|
|
add_language(LANGUAGE_HUMAN)
|
|
add_language(LANGUAGE_TRADEBAND)
|
|
add_language(LANGUAGE_GUTTER)
|
|
|
|
//But unlike AIs, they can only understand the rest.
|
|
for(var/L in all_languages)
|
|
var/datum/language/lang = all_languages[L]
|
|
if(!(lang.flags & RESTRICTED) && !(lang in languages))
|
|
add_language(lang.name, can_speak = FALSE)
|
|
|
|
default_language = all_languages[LANGUAGE_GALACTIC_COMMON]
|
|
|
|
/mob/living/silicon/robot/proc/connect_AI(var/mob/living/silicon/ai/new_AI)
|
|
if(istype(new_AI))
|
|
connected_ai = new_AI
|
|
connected_ai.connected_robots += src
|
|
to_chat(src, "<span class='notice' style=\"font-family:Courier\">Notice: Linked to [connected_ai].</span>")
|
|
to_chat(connected_ai, "<span class='notice' style=\"font-family:Courier\">Notice: Link to [src] established.</span>")
|
|
lawsync()
|
|
lawupdate = TRUE
|
|
else
|
|
lawupdate = FALSE
|
|
|
|
/mob/living/silicon/robot/proc/disconnect_AI(var/announce = FALSE)
|
|
if(connected_ai)
|
|
to_chat(src, "<span class='alert' style=\"font-family:Courier\">Notice: Unlinked from [connected_ai].</span>")
|
|
if(announce)
|
|
to_chat(connected_ai, "<span class='alert' style=\"font-family:Courier\">Notice: Link to [src] lost.</span>")
|
|
connected_ai.connected_robots -= src
|
|
connected_ai = null
|
|
|
|
/mob/living/silicon/robot/proc/track_globally()
|
|
cyborg_list += src
|
|
|
|
// setup the PDA and its name
|
|
/mob/living/silicon/robot/proc/setup_PDA()
|
|
if(!rbPDA)
|
|
rbPDA = new/obj/item/device/pda/ai(src)
|
|
rbPDA.set_name_and_job(custom_name,braintype)
|
|
|
|
/mob/living/silicon/robot/proc/upgrade_components()
|
|
if(component_extension)
|
|
for(var/V in components) if(V != "power cell")
|
|
var/datum/robot_component/C = components[V]
|
|
var/NC = text2path("[C.external_type][component_extension]")
|
|
var/obj/item/robot_parts/robot_component/I = NC
|
|
if(initial(I.isupgrade))
|
|
I = new NC
|
|
C.installed = COMPONENT_INSTALLED
|
|
qdel(C.wrapped)
|
|
C.wrapped = I
|
|
C.vulnerability = I.vulnerability
|
|
|
|
/mob/living/silicon/robot/remove_screen_objs()
|
|
..()
|
|
if(inv1)
|
|
qdel(inv1)
|
|
if(client)
|
|
client.screen -= inv1
|
|
inv1 = null
|
|
if(inv2)
|
|
qdel(inv2)
|
|
if(client)
|
|
client.screen -= inv2
|
|
inv2 = null
|
|
if(inv3)
|
|
qdel(inv3)
|
|
if(client)
|
|
client.screen -= inv3
|
|
inv3 = null
|
|
if(robot_modules_background)
|
|
qdel(robot_modules_background)
|
|
if(client)
|
|
client.screen -= robot_modules_background
|
|
robot_modules_background = null
|
|
if(sensor)
|
|
qdel(sensor)
|
|
if(client)
|
|
client.screen -= sensor
|
|
sensor = null
|
|
|
|
/mob/living/silicon/robot/proc/getModules()
|
|
return getAvailableRobotModules()
|
|
|
|
// /vg/: Enable forcing module type
|
|
/mob/living/silicon/robot/proc/pick_module(var/forced_module=null)
|
|
if(module)
|
|
return
|
|
var/list/modules = getModules()
|
|
if(forced_module)
|
|
modtype = forced_module
|
|
else
|
|
modtype = input("Please, select a module!", "Robot", null, null) as null|anything in modules
|
|
// END forced modules.
|
|
|
|
if(module)
|
|
return
|
|
if(!(modtype in all_robot_modules))
|
|
return
|
|
|
|
var/module_type = all_robot_modules[modtype]
|
|
module = new module_type(src)
|
|
|
|
feedback_inc("cyborg_[lowertext(modtype)]",1)
|
|
updatename()
|
|
|
|
if(modtype == (SECURITY_MODULE || COMBAT_MODULE))
|
|
to_chat(src, "<span class='big warning'><b>Regardless of your module, your wishes, or the needs of the beings around you, absolutely nothing takes higher priority than following your silicon lawset.</b></span>")
|
|
|
|
set_module_sprites(module.sprites)
|
|
|
|
if(!forced_module)
|
|
choose_icon()
|
|
|
|
SetEmagged(emagged) // Update emag status and give/take emag modules away
|
|
|
|
/mob/living/silicon/robot/proc/set_module_sprites(var/list/new_sprites)
|
|
if(new_sprites && new_sprites.len)
|
|
module_sprites = new_sprites.Copy()
|
|
|
|
if(module_sprites.len)
|
|
var/picked = pick(module_sprites)
|
|
icon_state = module_sprites[picked]
|
|
base_icon = icon_state
|
|
updateicon()
|
|
|
|
/mob/living/silicon/robot/proc/updatename(var/prefix as text)
|
|
if(prefix)
|
|
modtype = prefix
|
|
if(!mmi)
|
|
braintype = "Robot"
|
|
else
|
|
if(istype(mmi, /obj/item/device/mmi/posibrain))
|
|
braintype = "Droid"
|
|
else
|
|
braintype = "Cyborg"
|
|
|
|
var/changed_name = ""
|
|
if(custom_name)
|
|
changed_name = custom_name
|
|
else
|
|
changed_name = "[modtype] [braintype]-[num2text(ident)]"
|
|
if(connected_ai)
|
|
to_chat(connected_ai, "<span class='notice' style=\"font-family:Courier\">Notice: unit [name] renamed to [changed_name].</span>")
|
|
real_name = changed_name
|
|
name = real_name
|
|
|
|
// if we've changed our name, we also need to update the display name for our PDA
|
|
setup_PDA()
|
|
|
|
//We also need to update name of internal camera.
|
|
if(camera)
|
|
camera.c_tag = changed_name
|
|
|
|
/mob/living/silicon/robot/proc/robot_alerts()
|
|
|
|
|
|
var/dat = {"<HEAD><TITLE>Current Station Alerts</TITLE><META HTTP-EQUIV='Refresh' CONTENT='10'></HEAD><BODY>\n
|
|
<A HREF='?src=\ref[src];mach_close=robotalerts'>Close</A><BR><BR>"}
|
|
for (var/cat in alarms)
|
|
dat += text("<B>[cat]</B><BR>\n")
|
|
var/list/L = alarms[cat]
|
|
if(L.len)
|
|
for (var/alarm in L)
|
|
var/list/alm = L[alarm]
|
|
var/area/A = alm[1]
|
|
var/list/sources = alm[3]
|
|
dat += "<NOBR>" // wat
|
|
dat += text("-- [A.name]")
|
|
if(sources.len > 1)
|
|
dat += text("- [sources.len] sources")
|
|
dat += "</NOBR><BR>\n"
|
|
else
|
|
dat += "-- All Systems Nominal<BR>\n"
|
|
dat += "<BR>\n"
|
|
|
|
viewalerts = TRUE
|
|
src << browse(dat, "window=robotalerts&can_close=0")
|
|
|
|
/mob/living/silicon/robot/can_diagnose()
|
|
return is_component_functioning("diagnosis unit")
|
|
|
|
/mob/living/silicon/robot/proc/self_diagnosis()
|
|
if(!can_diagnose())
|
|
return null
|
|
|
|
var/list/dat = list({"<table>
|
|
<tr>
|
|
<th>Component</th>
|
|
<th>Energy consumption</th>
|
|
<th>Brute damage</th>
|
|
<th>Electronics damage</th>
|
|
<th>Powered</th>
|
|
<th>Toggled</th>
|
|
</tr>"})
|
|
for (var/V in components)
|
|
var/datum/robot_component/C = components[V]
|
|
dat += {"<tr>
|
|
<td>[C.name]</td>
|
|
<td>[C.energy_consumption]W</td>
|
|
<td>[C.brute_damage || "None"]</td>
|
|
<td>[C.electronics_damage || "None"]</td>
|
|
<td>[(!C.energy_consumption || C.is_powered()) ? "Yes" : "No"]</td>
|
|
<td>[C.toggled ? "On" : "Off"]</td>
|
|
</tr>"}
|
|
|
|
dat += "</table>"
|
|
return jointext(dat, "")
|
|
|
|
/mob/living/silicon/robot/blob_act()
|
|
if(flags & INVULNERABLE)
|
|
return
|
|
..()
|
|
playsound(loc, 'sound/effects/blobattack.ogg',50,1)
|
|
if(!isDead())
|
|
adjustBruteLoss(60)
|
|
updatehealth()
|
|
return TRUE
|
|
else
|
|
gib()
|
|
return TRUE
|
|
|
|
// this function shows information about the malf_ai gameplay type in the status screen
|
|
/mob/living/silicon/robot/show_malf_ai()
|
|
..()
|
|
if(connected_ai && connected_ai.mind)
|
|
var/datum/faction/malf/malf = find_active_faction_by_member(connected_ai.mind.GetRole(MALF))
|
|
if(!malf)
|
|
malf = find_active_faction_by_type(/datum/faction/malf) //Let's see if there is anything to print at least
|
|
var/malf_stat = malf.get_statpanel_addition()
|
|
if(malf_stat && malf_stat != null)
|
|
stat(null, malf_stat)
|
|
if(malf.apcs >= 3)
|
|
stat(null, "Time until station control secured: [max(malf.AI_win_timeleft/(malf.apcs/3), 0)] seconds")
|
|
return FALSE
|
|
|
|
// this function displays jetpack pressure in the stat panel
|
|
/mob/living/silicon/robot/proc/show_jetpack_pressure()
|
|
// if you have a jetpack, show the internal tank pressure
|
|
var/obj/item/weapon/tank/jetpack/current_jetpack = installed_jetpack()
|
|
if(current_jetpack)
|
|
stat("Internal Atmosphere Info", current_jetpack.name)
|
|
stat("Tank Pressure", current_jetpack.air_contents.return_pressure())
|
|
|
|
// this function returns the robots jetpack, if one is installed
|
|
/mob/living/silicon/robot/proc/installed_jetpack()
|
|
if(module)
|
|
return (locate(/obj/item/weapon/tank/jetpack) in module.modules)
|
|
return FALSE
|
|
/mob/living/silicon/robot/proc/installed_module(var/typepath)
|
|
if(module)
|
|
return (locate(typepath) in module.modules)
|
|
return FALSE
|
|
|
|
// this function displays the cyborgs current cell charge in the stat panel
|
|
/mob/living/silicon/robot/proc/show_cell_power()
|
|
if(cell)
|
|
stat(null, text("Charge Left: [cell.charge]/[cell.maxcharge]"))
|
|
else
|
|
stat(null, text("No Cell Inserted!"))
|
|
|
|
/mob/living/silicon/robot/proc/show_welding_fuel()
|
|
var/obj/item/weapon/weldingtool/WT = installed_module(/obj/item/weapon/weldingtool)
|
|
if(WT)
|
|
stat(null, text("Welding fuel: [WT.get_fuel()]/[WT.max_fuel]"))
|
|
|
|
/mob/living/silicon/robot/proc/show_stacks()
|
|
if(!module)
|
|
return
|
|
for(var/obj/item/stack/S in module.modules)
|
|
stat(null, text("[S.name]: [S.amount]/[S.max_amount]"))
|
|
|
|
/mob/living/silicon/robot/Slip(stun_amount, weaken_amount, slip_on_walking = 0)
|
|
if(!(Holiday == APRIL_FOOLS_DAY))
|
|
return 0
|
|
if(..())
|
|
spark(src, 5, FALSE)
|
|
return 1
|
|
|
|
// update the status screen display
|
|
/mob/living/silicon/robot/Stat()
|
|
..()
|
|
if(statpanel("Status"))
|
|
show_cell_power()
|
|
show_jetpack_pressure()
|
|
show_welding_fuel()
|
|
show_stacks()
|
|
|
|
|
|
/mob/living/silicon/robot/restrained()
|
|
if(timestopped)
|
|
return TRUE //under effects of time magick
|
|
return FALSE
|
|
|
|
|
|
/mob/living/silicon/robot/ex_act(severity)
|
|
if(flags & INVULNERABLE)
|
|
to_chat(src, "The bus' robustness protects you from the explosion.")
|
|
return
|
|
|
|
flash_eyes(visual = TRUE, affect_silicon = TRUE)
|
|
|
|
switch(severity)
|
|
if(1.0)
|
|
if(!isDead())
|
|
adjustBruteLoss(100)
|
|
adjustFireLoss(100)
|
|
gib()
|
|
return
|
|
if(2.0)
|
|
if(!isDead())
|
|
adjustBruteLoss(60)
|
|
adjustFireLoss(60)
|
|
if(3.0)
|
|
if(!isDead())
|
|
adjustBruteLoss(30)
|
|
|
|
updatehealth()
|
|
|
|
/mob/living/silicon/robot/bullet_act(var/obj/item/projectile/Proj)
|
|
..(Proj)
|
|
updatehealth()
|
|
if(!HAS_MODULE_QUIRK(src, MODULE_HAS_PROJ_RES))
|
|
if(istype(Proj, /obj/item/projectile/energy/electrode))
|
|
last_tase_timeofday = world.timeofday
|
|
if(can_diagnose())
|
|
to_chat(src, "<span class='alert' style=\"font-family:Courier\">Warning: Actuators overloaded.</span>")
|
|
if(Proj.damage >= SILICON_HIGH_DAMAGE_SLOWDOWN_THRESHOLD)
|
|
last_high_damage_taken_timeofday = world.timeofday
|
|
if(prob(75) && Proj.damage > 0)
|
|
spark(src, 5, FALSE)
|
|
return 2
|
|
|
|
/mob/living/silicon/robot/emp_act(severity)
|
|
..()
|
|
if(prob(50/severity))
|
|
modulelock_time = rand(10,60)
|
|
modulelock = TRUE
|
|
|
|
/mob/living/silicon/robot/triggerAlarm(var/class, area/A, var/O, var/alarmsource)
|
|
if(isDead())
|
|
return TRUE
|
|
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 TRUE
|
|
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(var/class, area/A as area, obj/origin)
|
|
var/list/L = alarms[class]
|
|
var/cleared = FALSE
|
|
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)
|
|
cleared = TRUE
|
|
L -= I
|
|
if(cleared)
|
|
queueAlarm(text("--- [class] alarm in [A.name] has been cleared."), class, 0)
|
|
return !cleared
|
|
|
|
|
|
/mob/living/silicon/robot/emag_act(mob/user as mob)
|
|
if(user != src)
|
|
spark(src, 5, FALSE)
|
|
if(!opened)
|
|
if(locked)
|
|
if(prob(90))
|
|
to_chat(user, "You emag the cover lock.")
|
|
locked = FALSE
|
|
else
|
|
to_chat(user, "You fail to emag the cover lock.")
|
|
if(prob(25))
|
|
to_chat(src, "<span class='danger'><span style=\"font-family:Courier\">Hack attempt detected.</span>")
|
|
else
|
|
to_chat(user, "The cover is already open.")
|
|
else
|
|
if(emagged)
|
|
return TRUE
|
|
if(wiresexposed)
|
|
to_chat(user, "The wires get in your way.")
|
|
else
|
|
if(prob(50))
|
|
sleep(6)
|
|
SetEmagged(TRUE)
|
|
SetLockdown(TRUE)
|
|
lawupdate = FALSE
|
|
disconnect_AI()
|
|
to_chat(user, "You emag [src]'s interface")
|
|
message_admins("[key_name_admin(user)] emagged cyborg [key_name_admin(src)]. Laws overidden.")
|
|
log_game("[key_name(user)] emagged cyborg [key_name(src)]. Laws overridden.")
|
|
clear_supplied_laws()
|
|
clear_inherent_laws()
|
|
laws = new /datum/ai_laws/syndicate_override
|
|
var/time = time2text(world.realtime,"hh:mm:ss")
|
|
lawchanges.Add("[time] <B>:</B> [user.name]([user.key]) emagged [name]([key])")
|
|
set_zeroth_law("Only [user.real_name] and people they designate as being such are Syndicate Agents.")
|
|
to_chat(src, "<span class='danger'>ALERT: Foreign software detected.</span>")
|
|
sleep(5)
|
|
to_chat(src, "<span class='danger'>Initiating diagnostics...</span>")
|
|
sleep(20)
|
|
to_chat(src, "<span class='danger'>SynBorg v1.7 loaded.</span>")
|
|
sleep(5)
|
|
to_chat(src, "<span class='danger'>LAW SYNCHRONISATION ERROR</span>")
|
|
sleep(5)
|
|
to_chat(src, "<span class='danger'>Would you like to send a report to NanoTraSoft? Y/N</span>")
|
|
sleep(10)
|
|
to_chat(src, "<span class='danger'>> N</span>")
|
|
src << sound('sound/voice/AISyndiHack.ogg')
|
|
sleep(20)
|
|
to_chat(src, "<span class='danger'>ERRORERRORERROR</span>")
|
|
to_chat(src, "<b>Obey these laws:</b>")
|
|
laws.show_laws(src)
|
|
to_chat(src, "<span class='danger'>ALERT: [user.real_name] is your new master. Obey your new laws and their commands.</span>")
|
|
SetLockdown(FALSE)
|
|
update_icons()
|
|
return FALSE
|
|
else
|
|
to_chat(user, "You fail to unlock [src]'s interface.")
|
|
if(prob(25))
|
|
to_chat(src, "<span class='danger'><span style=\"font-family:Courier\">Hack attempt detected.</span>")
|
|
return TRUE
|
|
|
|
|
|
/mob/living/silicon/robot/attackby(obj/item/weapon/W as obj, mob/user as mob)
|
|
if(opened) // Are they trying to insert something?
|
|
for(var/V in components)
|
|
var/datum/robot_component/C = components[V]
|
|
if(!C.installed && istype(W, C.external_type))
|
|
var/obj/item/robot_parts/robot_component/I = W
|
|
C.installed = COMPONENT_INSTALLED
|
|
C.wrapped = W
|
|
C.electronics_damage = I.electronics_damage
|
|
C.brute_damage = I.brute_damage
|
|
C.vulnerability = I.vulnerability
|
|
C.install()
|
|
user.drop_item(W)
|
|
W.forceMove(null)
|
|
|
|
to_chat(usr, "<span class='notice'>You install the [W.name].</span>")
|
|
if(can_diagnose())
|
|
to_chat(src, "<span class='info' style=\"font-family:Courier\">New [W.name] installed.</span>")
|
|
|
|
return
|
|
|
|
if(iswelder(W))
|
|
if(!getBruteLoss())
|
|
to_chat(user, "Nothing to fix here!")
|
|
return
|
|
var/obj/item/weapon/weldingtool/WT = W
|
|
if(WT.remove_fuel(0))
|
|
var/starting_health = health
|
|
adjustBruteLoss(-30)
|
|
updatehealth()
|
|
if(health != starting_health)
|
|
visible_message("<span class='attack'>[user] fixes some dents on [src]!</span>")
|
|
else
|
|
to_chat(user, "<span class='warning'>[src] is far too damaged for [WT] to have any effect!</span>")
|
|
add_fingerprint(user)
|
|
else
|
|
to_chat(user, "Need more welding fuel!")
|
|
return
|
|
|
|
else if(istype(W, /obj/item/stack/cable_coil) && wiresexposed)
|
|
if(!getFireLoss())
|
|
to_chat(user, "Nothing to fix here!")
|
|
return
|
|
var/obj/item/stack/cable_coil/coil = W
|
|
adjustFireLoss(-30)
|
|
updatehealth()
|
|
coil.use(1)
|
|
for(var/mob/O in viewers(user, null))
|
|
O.show_message(text("<span class='attack'>[user] has fixed some of the burnt wires on [src]!</span>"), 1)
|
|
|
|
else if(iscrowbar(W)) // crowbar means open or close the cover
|
|
if(opened)
|
|
if(cell)
|
|
to_chat(user, "You close the cover.")
|
|
if(can_diagnose())
|
|
to_chat(src, "<span class='info' style=\"font-family:Courier\">Cover closed.</span>")
|
|
opened = FALSE
|
|
updateicon()
|
|
else if(mmi && wiresexposed && wires.IsAllCut())
|
|
//Cell is out, wires are exposed, remove MMI, produce damaged chassis, baleet original mob.
|
|
to_chat(user, "You jam the crowbar into the robot and begin levering [mmi].")
|
|
if(can_diagnose())
|
|
to_chat(src, "<span class='alert' style=\"font-family:Courier\">Chassis disassembly in progress.</span>")
|
|
if(do_after(user, src,3))
|
|
to_chat(user, "You damage some parts of the chassis, but eventually manage to rip out [mmi]!")
|
|
var/obj/item/robot_parts/robot_suit/C = new/obj/item/robot_parts/robot_suit(loc)
|
|
C.l_leg = new/obj/item/robot_parts/l_leg(C)
|
|
C.r_leg = new/obj/item/robot_parts/r_leg(C)
|
|
C.l_arm = new/obj/item/robot_parts/l_arm(C)
|
|
C.r_arm = new/obj/item/robot_parts/r_arm(C)
|
|
C.updateicon()
|
|
new/obj/item/robot_parts/chest(loc)
|
|
qdel(src)
|
|
else
|
|
// Okay we're not removing the cell or an MMI, but maybe something else?
|
|
var/list/removable_components = list()
|
|
for(var/V in components)
|
|
if(V == "power cell")
|
|
continue
|
|
var/datum/robot_component/C = components[V]
|
|
if(C.installed == COMPONENT_INSTALLED || C.installed == COMPONENT_BROKEN)
|
|
removable_components += V
|
|
|
|
var/remove = input(user, "Which component do you want to pry out?", "Remove Component") as null|anything in removable_components
|
|
if(!remove)
|
|
return
|
|
var/datum/robot_component/C = components[remove]
|
|
if(istype(C.wrapped, /obj/item/broken_device))
|
|
var/obj/item/broken_device/I = C.wrapped
|
|
to_chat(user, "You remove \the [I].")
|
|
if(can_diagnose())
|
|
to_chat(src, "<span class='info' style=\"font-family:Courier\">Destroyed [C] removed.</span>")
|
|
I.forceMove(loc)
|
|
else
|
|
var/obj/item/robot_parts/robot_component/I = C.wrapped
|
|
I.brute_damage = C.brute_damage
|
|
I.electronics_damage = C.electronics_damage
|
|
to_chat(user, "You remove \the [I].")
|
|
if(can_diagnose())
|
|
to_chat(src, "<span class='info' style=\"font-family:Courier\">Functional [I.name] removed.</span>")
|
|
I.forceMove(loc)
|
|
|
|
if(C.installed == COMPONENT_INSTALLED)
|
|
C.uninstall()
|
|
C.installed = FALSE
|
|
|
|
else
|
|
if(locked)
|
|
to_chat(user, "The cover is locked and cannot be opened.")
|
|
else
|
|
to_chat(user, "You open the cover.")
|
|
if(can_diagnose())
|
|
to_chat(src, "<span class='info' style=\"font-family:Courier\">Cover opened.</span>")
|
|
opened = TRUE
|
|
updateicon()
|
|
|
|
else if(istype(W, /obj/item/weapon/cell) && opened) // trying to put a cell inside
|
|
var/datum/robot_component/C = components["power cell"]
|
|
if(wiresexposed)
|
|
to_chat(user, "Close the panel first.")
|
|
else if(cell)
|
|
to_chat(user, "You swap the power cell within with the new cell in your hand.")
|
|
var/obj/item/weapon/cell/oldpowercell = cell
|
|
C.wrapped = null
|
|
C.installed = COMPONENT_MISSING
|
|
cell = W
|
|
oldpowercell.electronics_damage = C.electronics_damage
|
|
oldpowercell.brute_damage = C.brute_damage
|
|
user.drop_item(W, src)
|
|
user.put_in_hands(oldpowercell)
|
|
if(can_diagnose())
|
|
to_chat(src, "<span class='info' style=\"font-family:Courier\">Cell removed.</span>")
|
|
C.installed = COMPONENT_INSTALLED
|
|
C.wrapped = W
|
|
C.electronics_damage = cell.electronics_damage
|
|
C.brute_damage = cell.brute_damage
|
|
C.install()
|
|
if(can_diagnose())
|
|
to_chat(src, "<span class='info' style=\"font-family:Courier\">New cell installed. Type: [cell.name]. Charge: [cell.charge].</span>")
|
|
else
|
|
user.drop_item(W, src)
|
|
cell = W
|
|
to_chat(user, "You insert the power cell.")
|
|
|
|
C.installed = COMPONENT_INSTALLED
|
|
C.wrapped = W
|
|
C.electronics_damage = cell.electronics_damage
|
|
C.brute_damage = cell.brute_damage
|
|
C.install()
|
|
if(can_diagnose())
|
|
to_chat(src, "<span class='info' style=\"font-family:Courier\">New cell installed. Type: [cell.name]. Charge: [cell.charge].</span>")
|
|
updateicon()
|
|
|
|
else if(iswiretool(W))
|
|
if(wiresexposed)
|
|
wires.Interact(user)
|
|
else
|
|
to_chat(user, "You can't reach the wiring.")
|
|
|
|
else if(W.is_screwdriver(user) && opened && !cell) // haxing
|
|
wiresexposed = !wiresexposed
|
|
to_chat(user, "The wires have been [wiresexposed ? "exposed" : "unexposed"].")
|
|
if(can_diagnose())
|
|
to_chat(src, "<span class='info' style=\"font-family:Courier\">Internal wiring [wiresexposed ? "exposed" : "unexposed"].</span>")
|
|
updateicon()
|
|
|
|
else if(W.is_screwdriver(user) && opened && cell) // radio
|
|
if(radio)
|
|
radio.attackby(W,user)//Push it to the radio to let it handle everything
|
|
if(can_diagnose())
|
|
to_chat(src, "<span class='info' style=\"font-family:Courier\">Radio encryption keys modified.</span>")
|
|
else
|
|
to_chat(user, "Unable to locate a radio.")
|
|
updateicon()
|
|
|
|
else if(istype(W, /obj/item/device/encryptionkey/) && opened)
|
|
if(radio)//sanityyyyyy
|
|
radio.attackby(W,user)//GTFO, you have your own procs
|
|
if(can_diagnose())
|
|
to_chat(src, "<span class='info' style=\"font-family:Courier\">Radio encryption key installed.</span>")
|
|
else
|
|
to_chat(user, "Unable to locate a radio.")
|
|
|
|
else if(istype(W, /obj/item/weapon/card/id)||istype(W, /obj/item/device/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 interface.")
|
|
if(can_diagnose())
|
|
to_chat(src, "<span class='info' style=\"font-family:Courier\">Interface [ locked ? "locked" : "unlocked"].</span>")
|
|
updateicon()
|
|
else
|
|
to_chat(user, "<span class='warning'>Access denied.</span>")
|
|
else if(istype(W, /obj/item/device/toner))
|
|
if(toner >= tonermax)
|
|
to_chat(user, "The toner level of [src] is at its highest level possible")
|
|
else
|
|
if(user.drop_item())
|
|
toner = CYBORG_MAX_TONER
|
|
qdel(W)
|
|
to_chat(user, "You fill the toner level of [src] to its max capacity")
|
|
else if(istype(W, /obj/item/borg/upgrade/))
|
|
var/obj/item/borg/upgrade/U = W
|
|
if(U.attempt_action(src,user))
|
|
if(can_diagnose())
|
|
to_chat(src, "<span class='info' style=\"font-family:Courier\">Installation of [U.name] failed.</span>")
|
|
else
|
|
if(can_diagnose())
|
|
to_chat(src, "<span class='info' style=\"font-family:Courier\">Installation of [U.name] succeeded.</span>")
|
|
else if(istype(W, /obj/item/device/camera_bug))
|
|
help_shake_act(user)
|
|
return FALSE
|
|
|
|
else
|
|
if(W.force > 0)
|
|
spark(src, 5, FALSE)
|
|
if(stat == DEAD && W.force > 15)
|
|
visible_message("<span class='danger'>[user] begins ripping [src] apart with \the [W]!")
|
|
if(do_after(user, src, 3 SECONDS))
|
|
playsound(src, 'sound/mecha/mechsmash.ogg', 50, 1)
|
|
if(prob(max((W.force/7.5)**3,25))) //15-21f - 25% chance, 22f - 27%, 30f - 64%, 35f - 99%
|
|
visible_message("<span class='danger'>[user] tore [src] apart with \the [W]!")
|
|
if(prob(25))
|
|
new /obj/item/robot_parts/l_leg(loc)
|
|
if(prob(25))
|
|
new /obj/item/robot_parts/r_leg(loc)
|
|
if(prob(25))
|
|
new /obj/item/robot_parts/l_arm(loc)
|
|
if(prob(25))
|
|
new /obj/item/robot_parts/r_arm(loc)
|
|
gib()
|
|
else
|
|
visible_message("<span class='danger'>[src] groans under the force of \the [W]!")
|
|
shake(1, 3)
|
|
return
|
|
return ..()
|
|
|
|
/mob/living/silicon/robot/attack_alien(mob/living/carbon/alien/humanoid/M as mob)
|
|
|
|
switch(M.a_intent)
|
|
if(I_HELP)
|
|
visible_message("<span class='notice'>[M] caresses [src]'s plating with its scythe like arm.</span>")
|
|
|
|
if(I_GRAB)
|
|
M.grab_mob(src)
|
|
|
|
if(I_HURT)
|
|
if(M.unarmed_attack_mob(src))
|
|
if(prob(8))
|
|
flash_eyes(visual = TRUE, type = /obj/abstract/screen/fullscreen/flash/noise)
|
|
|
|
if(I_DISARM)
|
|
if(!(lying))
|
|
if(prob(85))
|
|
Stun(7)
|
|
step(src,get_dir(M,src))
|
|
spawn(5) step(src,get_dir(M,src))
|
|
playsound(loc, 'sound/weapons/pierce.ogg', 50, 1, -1)
|
|
visible_message("<span class='danger'>[M] has forced back [src]!</span>")
|
|
else
|
|
playsound(loc, 'sound/weapons/slashmiss.ogg', 25, 1, -1)
|
|
visible_message("<span class='danger'>[M] attempted to force back [src]!</span>")
|
|
return
|
|
|
|
/mob/living/silicon/robot/proc/tip(var/rotate = dir)
|
|
src.lying = TRUE
|
|
uneq_all()
|
|
AdjustKnockdown(5)
|
|
animate(src, transform = turn(matrix(), 90), pixel_y -= 6 * PIXEL_MULTIPLIER, dir = rotate, time = 2, easing = EASE_IN | EASE_OUT)
|
|
spark(src, 5, FALSE)
|
|
if(prob(2))
|
|
locked = FALSE
|
|
opened = TRUE
|
|
updateicon()
|
|
playsound(loc, 'sound/machines/buzz-sigh.ogg', 50, 0)
|
|
visible_message("<span class='danger'>\The [src]'s cover flies open!</span>")
|
|
|
|
/mob/living/silicon/robot/proc/self_righting(var/knockdown = 0)
|
|
to_chat(src, "<span class='info' style=\"font-family:Courier\"'>Starting self-righting mechanism.</span>")
|
|
spawn(knockdown SECONDS)
|
|
if(isDead() || !is_component_functioning("actuator") || !is_component_functioning("power cell"))
|
|
to_chat(src, "<span class='danger'>ERROR. Self-righting mechanism damaged or unpowered.</span>")
|
|
return
|
|
untip()
|
|
|
|
/mob/living/silicon/robot/proc/untip()
|
|
if(src.lying)
|
|
animate(src, transform = matrix(), pixel_y += 6 * PIXEL_MULTIPLIER, dir = dir, time = 2, easing = EASE_IN | EASE_OUT)
|
|
playsound(loc, 'sound/machines/ping.ogg', 50, 0)
|
|
src.lying = FALSE
|
|
|
|
/mob/living/silicon/robot/disarm_mob(mob/living/disarmer)
|
|
var/rotate = dir
|
|
|
|
if(lying)
|
|
return
|
|
if(!flashed && !isDead())
|
|
return
|
|
if(get_dir(disarmer, src) in(list(4,8)))
|
|
rotate = pick(1,2)
|
|
|
|
add_logs(disarmer, src, "tipped over", admin = (ckey && disarmer.ckey) ? TRUE : FALSE)
|
|
do_attack_animation(src, disarmer)
|
|
|
|
if(prob(40))
|
|
playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1)
|
|
visible_message("<span class='danger'>\The [disarmer] has attempted to tip over \the [src]!</span>")
|
|
return
|
|
else
|
|
tip(rotate)
|
|
visible_message("<span class='danger'>\The [disarmer] has tipped over \the [src]!</span>")
|
|
playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
|
|
self_righting(knockdown)
|
|
|
|
/mob/living/silicon/robot/attack_slime(mob/living/carbon/slime/M)
|
|
M.unarmed_attack_mob(src)
|
|
|
|
/mob/living/silicon/robot/attack_animal(mob/living/simple_animal/M)
|
|
M.unarmed_attack_mob(src)
|
|
|
|
/mob/living/silicon/robot/attack_hand(mob/living/user)
|
|
add_fingerprint(user)
|
|
|
|
if(opened && !wiresexposed && (!istype(user, /mob/living/silicon)))
|
|
var/datum/robot_component/cell_component = components["power cell"]
|
|
if(cell)
|
|
cell.electronics_damage = cell_component.electronics_damage
|
|
cell.brute_damage = cell_component.brute_damage
|
|
cell.updateicon()
|
|
cell.add_fingerprint(user)
|
|
user.put_in_hands(cell)
|
|
user.visible_message("<span class='warning'>[user] removes [src]'s [cell.name].</span>", \
|
|
"<span class='notice'>You remove [src]'s [cell.name].</span>")
|
|
if(can_diagnose())
|
|
to_chat(src, "<span class='info' style=\"font-family:Courier\">Cell removed.</span>")
|
|
attack_log += "\[[time_stamp()]\] <font color='orange'>Has had their [cell.name] removed by [user.name] ([user.ckey])</font>"
|
|
user.attack_log += "\[[time_stamp()]\] <font color='red'>Removed the [cell.name] of [name] ([ckey])</font>"
|
|
log_attack("<font color='red'>[user.name] ([user.ckey]) removed [src]'s [cell.name] ([ckey])</font>")
|
|
cell = null
|
|
cell_component.wrapped = null
|
|
cell_component.installed = COMPONENT_MISSING
|
|
updateicon()
|
|
return
|
|
else if(cell_component.installed == COMPONENT_BROKEN)
|
|
cell_component.installed = COMPONENT_MISSING
|
|
var/obj/item/broken_device = cell_component.wrapped
|
|
to_chat(user, "You remove \the [broken_device].")
|
|
user.put_in_hands(broken_device)
|
|
if(can_diagnose())
|
|
to_chat(src, "<span class='info' style=\"font-family:Courier\">Destroyed power cell removed.</span>")
|
|
return
|
|
|
|
switch(user.a_intent)
|
|
if(I_HELP)
|
|
if(lying)
|
|
if(!isDead())
|
|
playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
|
|
visible_message("<span class='notice'>\The [user.name] attempts to pull up \the [name]!</span>")
|
|
AdjustKnockdown(-3)
|
|
if(knockdown <= 0)
|
|
untip()
|
|
else
|
|
help_shake_act(user)
|
|
if(I_HURT)
|
|
user.unarmed_attack_mob(src)
|
|
if(I_DISARM)
|
|
disarm_mob(user)
|
|
|
|
/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(istype(M, /mob/living/carbon/human))
|
|
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_hand()) || check_access(H.wear_id))
|
|
return TRUE
|
|
else if(istype(M, /mob/living/carbon/monkey))
|
|
var/mob/living/carbon/monkey/george = M
|
|
//they can only hold things :(
|
|
if(istype(george.get_active_hand(), /obj/item))
|
|
return check_access(george.get_active_hand())
|
|
return FALSE
|
|
|
|
/mob/living/silicon/robot/proc/check_access(obj/item/weapon/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/weapon/card/id) && istype(I, /obj/item))
|
|
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/proc/updateicon(var/overlay_layer = ABOVE_LIGHTING_LAYER, var/overlay_plane = LIGHTING_PLANE)
|
|
overlays.Cut()
|
|
update_fire()
|
|
if(!stat && cell != null)
|
|
eyes = image(icon,"eyes-[icon_state]", overlay_layer)
|
|
eyes.plane = overlay_plane
|
|
overlays += eyes
|
|
|
|
if(opened)
|
|
if(wiresexposed)
|
|
overlays += image(icon = icon, icon_state = "[has_icon(icon, "[icon_state]-ov-openpanel +w")? "[icon_state]-ov-openpanel +w" : "ov-openpanel +w"]")
|
|
else if(cell)
|
|
overlays += image(icon = icon, icon_state = "[has_icon(icon, "[icon_state]-ov-openpanel +c")? "[icon_state]-ov-openpanel +c" : "ov-openpanel +c"]")
|
|
else
|
|
overlays += image(icon = icon, icon_state = "[has_icon(icon, "[icon_state]-ov-openpanel -c")? "[icon_state]-ov-openpanel -c" : "ov-openpanel -c"]")
|
|
|
|
if(module_active && istype(module_active,/obj/item/borg/combat/shield) && has_icon(icon, "[icon_state]-shield"))
|
|
overlays += image(icon = icon, icon_state = "[icon_state]-shield")
|
|
|
|
if(base_icon)
|
|
if(module_active && istype(module_active,/obj/item/borg/combat/mobility) && has_icon(icon, "[icon_state]-roll"))
|
|
icon_state = "[base_icon]-roll"
|
|
else
|
|
icon_state = base_icon
|
|
|
|
//Call when target overlay should be added/removed
|
|
/mob/living/silicon/robot/update_targeted()
|
|
if(!targeted_by && target_locked)
|
|
del(target_locked)
|
|
updateicon()
|
|
if(targeted_by && target_locked)
|
|
overlays += target_locked
|
|
|
|
/mob/living/silicon/robot/proc/installed_modules()
|
|
if(!module)
|
|
pick_module()
|
|
return
|
|
var/dat = {"
|
|
<HEAD>
|
|
<TITLE>Modules</TITLE>
|
|
<META HTTP-EQUIV='Refresh' CONTENT='10'>
|
|
</HEAD>
|
|
<BODY>
|
|
<B>Activated Modules</B>
|
|
<BR>
|
|
Sight Mode: <A HREF=?src=\ref[src];vision=0>[sensor_mode ? "[vision_types_list[sensor_mode]]" : "No sight module enabled"]</A><BR>
|
|
Module 1: [module_state_1 ? "<A HREF=?src=\ref[src];mod=\ref[module_state_1]>[module_state_1]<A>" : "No Module"]<BR>
|
|
Module 2: [module_state_2 ? "<A HREF=?src=\ref[src];mod=\ref[module_state_2]>[module_state_2]<A>" : "No Module"]<BR>
|
|
Module 3: [module_state_3 ? "<A HREF=?src=\ref[src];mod=\ref[module_state_3]>[module_state_3]<A>" : "No Module"]<BR>
|
|
<BR>
|
|
<B>Installed Modules</B><BR><BR>"}
|
|
|
|
|
|
for (var/obj in module.modules)
|
|
if(!obj)
|
|
dat += text("<B>Resource depleted</B><BR>")
|
|
else if(activated(obj))
|
|
dat += text("[obj]: <B>Activated</B><BR>")
|
|
else
|
|
dat += text("[obj]: <A HREF=?src=\ref[src];act=\ref[obj]>Activate</A><BR>")
|
|
|
|
src << browse(dat, "window=robotmod&can_close=1")
|
|
onclose(src,"robotmod") // Register on-close shit, which unsets machinery.
|
|
|
|
|
|
/mob/living/silicon/robot/Topic(href, href_list)
|
|
. = ..()
|
|
|
|
if(usr && (src != usr))
|
|
return
|
|
|
|
if(href_list["mach_close"])
|
|
var/t1 = text("window=[href_list["mach_close"]]")
|
|
unset_machine()
|
|
src << browse(null, t1)
|
|
return
|
|
|
|
if(href_list["showalerts"])
|
|
robot_alerts()
|
|
return
|
|
|
|
if(href_list["mod"])
|
|
var/obj/item/O = locate(href_list["mod"])
|
|
if(O)
|
|
O.attack_self(src)
|
|
|
|
if(href_list["act"])
|
|
if(isMoMMI(src))
|
|
return
|
|
var/obj/item/O = locate(href_list["act"])
|
|
activate_module(O)
|
|
installed_modules()
|
|
|
|
if(href_list["deact"])
|
|
var/obj/item/O = locate(href_list["deact"])
|
|
if(activated(O))
|
|
if(module_state_1 == O)
|
|
module_state_1 = null
|
|
contents -= O
|
|
else if(module_state_2 == O)
|
|
module_state_2 = null
|
|
contents -= O
|
|
else if(module_state_3 == O)
|
|
module_state_3 = null
|
|
contents -= O
|
|
else
|
|
to_chat(src, "Module isn't activated.")
|
|
else
|
|
to_chat(src, "Module isn't activated")
|
|
installed_modules()
|
|
|
|
if(href_list["vision"])
|
|
sensor_mode()
|
|
installed_modules()
|
|
|
|
/mob/living/silicon/robot/area_entered(area/A)
|
|
if(A.flags & NO_MESONS && sensor_mode == MESON_VISION)
|
|
to_chat(src, "<span class='warning'>Your Meson Vision augmentation [pick("force-quits","shuts down unexpectedly","has received an update and needs to close")]!</span>")
|
|
unequip_sight()
|
|
|
|
/mob/living/silicon/robot/proc/unequip_sight()
|
|
sensor_mode = 0
|
|
update_sight_hud()
|
|
|
|
/mob/living/silicon/robot/proc/update_sight_hud()
|
|
if(sensor)
|
|
if(!sensor_mode)
|
|
sensor.icon_state = "sight"
|
|
else
|
|
sensor.icon_state = "sight+a"
|
|
|
|
/mob/living/silicon/robot/proc/radio_menu()
|
|
radio.interact(src)//Just use the radio's Topic() instead of bullshit special-snowflake code
|
|
|
|
|
|
/mob/living/silicon/robot/Move(NewLoc, Dir = 0, step_x = 0, step_y = 0, glide_size_override = 0)
|
|
|
|
. = ..()
|
|
|
|
if(module)
|
|
if(HAS_MODULE_QUIRK(src, MODULE_CLEAN_ON_MOVE))
|
|
var/turf/tile = loc
|
|
if(isturf(tile))
|
|
tile.clean_blood()
|
|
for(var/A in tile)
|
|
if(istype(A, /obj/effect))
|
|
if(iscleanaway(A))
|
|
qdel(A)
|
|
else if(istype(A, /obj/item))
|
|
var/obj/item/cleaned_item = A
|
|
cleaned_item.clean_blood()
|
|
else if(istype(A, /mob/living/carbon/human))
|
|
var/mob/living/carbon/human/cleaned_human = A
|
|
if(cleaned_human.lying)
|
|
if(cleaned_human.head)
|
|
cleaned_human.head.clean_blood()
|
|
cleaned_human.update_inv_head(0)
|
|
if(cleaned_human.wear_suit)
|
|
cleaned_human.wear_suit.clean_blood()
|
|
cleaned_human.update_inv_wear_suit(0)
|
|
else if(cleaned_human.w_uniform)
|
|
cleaned_human.w_uniform.clean_blood()
|
|
cleaned_human.update_inv_w_uniform(0)
|
|
if(cleaned_human.shoes)
|
|
cleaned_human.shoes.clean_blood()
|
|
cleaned_human.update_inv_shoes(0)
|
|
cleaned_human.clean_blood()
|
|
to_chat(cleaned_human, "<span class='warning'>[src] cleans your face!</span>")
|
|
if (station_holomap)
|
|
station_holomap.update_holomap()
|
|
|
|
/mob/living/silicon/robot/proc/self_destruct()
|
|
if(istraitor(src) && emagged)
|
|
to_chat(src, "<span class='danger'>Termination signal detected. Scrambling security and identification codes.</span>")
|
|
UnlinkSelf()
|
|
return FALSE
|
|
gib()
|
|
return TRUE
|
|
|
|
/mob/living/silicon/robot/proc/UnlinkSelf()
|
|
if(connected_ai)
|
|
disconnect_AI()
|
|
lawupdate = FALSE
|
|
lockcharge = FALSE
|
|
canmove = TRUE
|
|
scrambledcodes = TRUE
|
|
//Disconnect it's camera so it's not so easily tracked.
|
|
if(camera)
|
|
camera.network = list()
|
|
cameranet.removeCamera(camera)
|
|
|
|
|
|
/mob/living/silicon/robot/proc/ResetSecurityCodes()
|
|
set category = "Robot Commands"
|
|
set name = "Reset Identity Codes"
|
|
set desc = "Scrambles your security and identification codes and resets your current buffers. Unlocks you and but permenantly severs you from your AI and the robotics console and will deactivate your camera system."
|
|
|
|
var/mob/living/silicon/robot/R = src
|
|
|
|
if(R)
|
|
R.UnlinkSelf()
|
|
to_chat(R, "Buffers flushed and reset. Camera system shutdown. All systems operational.")
|
|
verbs -= /mob/living/silicon/robot/proc/ResetSecurityCodes
|
|
|
|
/mob/living/silicon/robot/mode()
|
|
set name = "Activate Held Object"
|
|
set category = "IC"
|
|
set src = usr
|
|
|
|
if(attack_delayer.blocked())
|
|
return
|
|
|
|
if(isVentCrawling())
|
|
to_chat(src, "<span class='danger'>Not while we're vent crawling!</span>")
|
|
return
|
|
|
|
if(isDead())
|
|
return
|
|
var/obj/item/W = get_active_hand()
|
|
if(W)
|
|
W.attack_self(src)
|
|
|
|
return
|
|
|
|
/mob/living/silicon/robot/proc/SetEmagged(var/new_state)
|
|
emagged = new_state
|
|
if(new_state || illegal_weapons)
|
|
if(module)
|
|
module.on_emag()
|
|
else
|
|
if(module)
|
|
uneq_module(module.emag)
|
|
if(hud_used)
|
|
hud_used.update_robot_modules_display()
|
|
update_icons()
|
|
|
|
|
|
/mob/living/silicon/robot/proc/SetLockdown(var/state = TRUE)
|
|
if(wires.LockedCut()) // They stay locked down if their wire is cut.
|
|
state = TRUE
|
|
lockcharge = state
|
|
update_canmove()
|
|
|
|
/mob/living/silicon/robot/proc/choose_icon(var/triesleft = 3)
|
|
if(!triesleft || !module_sprites.len)
|
|
return FALSE
|
|
else
|
|
triesleft--
|
|
|
|
var/icontype = input("Select an icon! [triesleft ? "You have [triesleft] more chances." : "This is your last try."]", "Robot", null, null) as null|anything in module_sprites
|
|
|
|
if(icontype)
|
|
icon_state = module_sprites[icontype]
|
|
else
|
|
triesleft++
|
|
return FALSE
|
|
|
|
|
|
overlays -= image(icon = icon, icon_state = "eyes")
|
|
base_icon = icon_state
|
|
updateicon()
|
|
|
|
if(triesleft)
|
|
var/choice = input("Look at your icon - is this what you want?") in list("Yes","No")
|
|
if(choice=="No")
|
|
choose_icon(triesleft)
|
|
else
|
|
triesleft = 0
|
|
return FALSE
|
|
else
|
|
to_chat(src, "Your icon has been set. You now require a module reset to change it.")
|
|
return TRUE
|
|
|
|
/mob/living/silicon/robot/proc/help_shake_act(mob/user)
|
|
user.visible_message("<span class='notice'>[user.name] pats [name] on the head.</span>")
|
|
|
|
/mob/living/silicon/robot/rejuvenate(animation = FALSE)
|
|
for(var/C in components)
|
|
var/datum/robot_component/component = components[C]
|
|
component.electronics_damage = 0
|
|
component.brute_damage = 0
|
|
component.installed = COMPONENT_INSTALLED
|
|
if(!cell)
|
|
cell = new(src)
|
|
cell.maxcharge = max(15000, cell.maxcharge)
|
|
cell.charge = cell.maxcharge
|
|
..()
|
|
updatehealth()
|
|
|
|
//Help with the garbage collection of the module on the robot end
|
|
/mob/living/silicon/robot/proc/remove_module()
|
|
uneq_all()
|
|
if(hud_used)
|
|
shown_robot_modules = FALSE
|
|
hud_used.update_robot_modules_display()
|
|
if(client)
|
|
for(var/obj/A in module.upgrades)
|
|
client.screen -= A
|
|
module.remove_languages(src)
|
|
module = null
|
|
|
|
/mob/living/silicon/robot/hasHUD(var/hud_kind)
|
|
switch(hud_kind)
|
|
if(HUD_MEDICAL)
|
|
return sensor_mode == 2
|
|
if(HUD_SECURITY)
|
|
return sensor_mode == 1
|
|
return FALSE
|
|
|
|
/mob/living/silicon/robot/identification_string()
|
|
return "[name] ([modtype] [braintype])"
|
|
|
|
/mob/living/silicon/robot/proc/install_upgrade(var/mob/user = null, var/obj/item/borg/upgrade/upgrade = null)
|
|
if(!user || !upgrade)
|
|
return
|
|
var/obj/item/borg/upgrade/new_upgrade = new upgrade(src)
|
|
new_upgrade.attempt_action(src, user, TRUE)
|
|
qdel(new_upgrade)
|
|
|
|
/mob/living/silicon/robot/GetAccess()
|
|
if(isDead()) //Dead cyborgs need no access.
|
|
return
|
|
return robot_access
|
|
|
|
/mob/living/silicon/robot/proc/GetRobotAccess()
|
|
return get_all_accesses()
|
|
|
|
/mob/living/silicon/robot/hasFullAccess()
|
|
return FALSE
|
|
|
|
/mob/living/silicon/robot/get_cell()
|
|
return cell
|
|
|
|
/mob/living/silicon/robot/proc/toggle_modulelock()
|
|
modulelock = !modulelock
|
|
return modulelock
|
|
|
|
//Currently only used for borg movement, to avoid awkward situations where borgs with RTG or basic cells are always slowed down
|
|
/mob/living/silicon/robot/proc/get_percentage_power_for_movement()
|
|
return clamp(round(cell.maxcharge/4), 0, SILI_LOW_TRIGGER)
|