diff --git a/baystation12.dme b/baystation12.dme index 79074cacbc..2202d4f384 100644 --- a/baystation12.dme +++ b/baystation12.dme @@ -43,6 +43,7 @@ #include "code\_onclick\item_attack.dm" #include "code\_onclick\observer.dm" #include "code\_onclick\other_mobs.dm" +#include "code\_onclick\rig.dm" #include "code\_onclick\telekinesis.dm" #include "code\_onclick\hud\_defines.dm" #include "code\_onclick\hud\alien_larva.dm" @@ -1007,6 +1008,7 @@ #include "code\modules\food\recipes_microwave.dm" #include "code\modules\games\cards.dm" #include "code\modules\genetics\side_effects.dm" +#include "code\modules\ghosttrap\trap.dm" #include "code\modules\holodeck\HolodeckControl.dm" #include "code\modules\holodeck\HolodeckObjects.dm" #include "code\modules\holodeck\HolodeckPrograms.dm" @@ -1334,8 +1336,8 @@ #include "code\modules\nano\modules\power_monitor.dm" #include "code\modules\nano\modules\rcon.dm" #include "code\modules\organs\blood.dm" +#include "code\modules\organs\misc.dm" #include "code\modules\organs\organ.dm" -#include "code\modules\organs\organ_alien.dm" #include "code\modules\organs\organ_external.dm" #include "code\modules\organs\organ_icon.dm" #include "code\modules\organs\organ_internal.dm" @@ -1343,6 +1345,11 @@ #include "code\modules\organs\pain.dm" #include "code\modules\organs\robolimbs.dm" #include "code\modules\organs\wound.dm" +#include "code\modules\organs\subtypes\diona.dm" +#include "code\modules\organs\subtypes\machine.dm" +#include "code\modules\organs\subtypes\standard.dm" +#include "code\modules\organs\subtypes\unbreakable.dm" +#include "code\modules\organs\subtypes\xenos.dm" #include "code\modules\overmap\_defines.dm" #include "code\modules\overmap\sectors.dm" #include "code\modules\overmap\ships\ship.dm" @@ -1645,16 +1652,14 @@ #include "code\modules\spells\targeted\projectile\projectile.dm" #include "code\modules\supermatter\supermatter.dm" #include "code\modules\surgery\bones.dm" -#include "code\modules\surgery\brainrepair.dm" #include "code\modules\surgery\encased.dm" -#include "code\modules\surgery\eye.dm" #include "code\modules\surgery\face.dm" #include "code\modules\surgery\generic.dm" -#include "code\modules\surgery\headreattach.dm" #include "code\modules\surgery\implant.dm" +#include "code\modules\surgery\limb_reattach.dm" #include "code\modules\surgery\organs_internal.dm" #include "code\modules\surgery\other.dm" -#include "code\modules\surgery\robolimbs.dm" +#include "code\modules\surgery\robotics.dm" #include "code\modules\surgery\slimes.dm" #include "code\modules\surgery\surgery.dm" #include "code\modules\tables\flipping.dm" diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm index b8caa45399..7307927ac0 100644 --- a/code/_onclick/click.dm +++ b/code/_onclick/click.dm @@ -229,17 +229,6 @@ /mob/living/carbon/MiddleClickOn(var/atom/A) swap_hand() -/mob/living/carbon/human/MiddleClickOn(var/atom/A) - - if(back) - var/obj/item/weapon/rig/rig = back - if(istype(rig) && rig.selected_module) - if(world.time <= next_move) return - next_move = world.time + 8 - rig.selected_module.engage(A) - return - - swap_hand() // In case of use break glass /* diff --git a/code/_onclick/other_mobs.dm b/code/_onclick/other_mobs.dm index 477fb04b7a..179a470fc6 100644 --- a/code/_onclick/other_mobs.dm +++ b/code/_onclick/other_mobs.dm @@ -97,8 +97,6 @@ if (powerlevel > 0 && !istype(A, /mob/living/carbon/slime)) if(ishuman(M)) var/mob/living/carbon/human/H = M - if(H.species.flags & IS_SYNTHETIC) - return stunprob *= H.species.siemens_coefficient diff --git a/code/_onclick/rig.dm b/code/_onclick/rig.dm new file mode 100644 index 0000000000..ad9346ec15 --- /dev/null +++ b/code/_onclick/rig.dm @@ -0,0 +1,63 @@ + +#define MIDDLE_CLICK 0 +#define ALT_CLICK 1 +#define CTRL_CLICK 2 +#define MAX_HARDSUIT_CLICK_MODE 2 + +/client + var/hardsuit_click_mode = MIDDLE_CLICK + +/client/verb/toggle_hardsuit_mode() + set name = "Toggle Hardsuit Activation Mode" + set desc = "Switch between hardsuit activation modes." + set category = "OOC" + + hardsuit_click_mode++ + if(hardsuit_click_mode > MAX_HARDSUIT_CLICK_MODE) + hardsuit_click_mode = 0 + + switch(hardsuit_click_mode) + if(MIDDLE_CLICK) + src << "Hardsuit activation mode set to middle-click." + if(ALT_CLICK) + src << "Hardsuit activation mode set to alt-click." + if(CTRL_CLICK) + src << "Hardsuit activation mode set to control-click." + else + // should never get here, but just in case: + soft_assert(0, "Bad hardsuit click mode: [hardsuit_click_mode] - expected 0 to [MAX_HARDSUIT_CLICK_MODE]") + src << "Somehow you bugged the system. Setting your hardsuit mode to middle-click." + hardsuit_click_mode = MIDDLE_CLICK + +/mob/living/carbon/human/MiddleClickOn(atom/A) + if(client && client.hardsuit_click_mode == MIDDLE_CLICK) + if(HardsuitClickOn(A)) + return + ..() + +/mob/living/carbon/human/AltClickOn(atom/A) + if(client && client.hardsuit_click_mode == ALT_CLICK) + if(HardsuitClickOn(A)) + return + ..() + +/mob/living/carbon/human/CtrlClickOn(atom/A) + if(client && client.hardsuit_click_mode == CTRL_CLICK) + if(HardsuitClickOn(A)) + return + ..() + +/mob/living/carbon/human/proc/HardsuitClickOn(atom/A) + if(back) + var/obj/item/weapon/rig/rig = back + if(istype(rig) && rig.selected_module) + if(world.time <= next_move) return 1 + next_move = world.time + 8 + rig.selected_module.engage(A) + return 1 + return 0 + +#undef MIDDLE_CLICK +#undef ALT_CLICK +#undef CTRL_CLICK +#undef MAX_HARDSUIT_CLICK_MODE diff --git a/code/datums/disease.dm b/code/datums/disease.dm index 398dc73bbb..606acdef99 100644 --- a/code/datums/disease.dm +++ b/code/datums/disease.dm @@ -53,14 +53,15 @@ var/list/diseases = typesof(/datum/disease) - /datum/disease // if hidden[2] is true, then virus is hidden from PANDEMIC machine /datum/disease/proc/stage_act() + + // Some species are immune to viruses entirely. + if(affected_mob && istype(affected_mob, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = affected_mob + if(H.species.virus_immune) + cure() + return age++ var/cure_present = has_cure() - //world << "[cure_present]" - - if(carrier&&!cure_present) - //world << "[affected_mob] is carrier" - return - spread = (cure_present?"Remissive":initial_spread) if(stage > max_stages) stage = max_stages @@ -126,7 +127,7 @@ var/list/diseases = typesof(/datum/disease) - /datum/disease source = affected_mob else //no source and no mob affected. Rogue disease. Break return - + if(affected_mob.reagents != null) if(affected_mob) if(affected_mob.reagents.has_reagent("spaceacillin")) diff --git a/code/game/antagonist/alien/borer.dm b/code/game/antagonist/alien/borer.dm index 9fe4226e5b..bd436ceaf8 100644 --- a/code/game/antagonist/alien/borer.dm +++ b/code/game/antagonist/alien/borer.dm @@ -33,7 +33,10 @@ var/datum/antagonist/xenos/borer/borers /datum/antagonist/xenos/borer/proc/get_hosts() var/list/possible_hosts = list() for(var/mob/living/carbon/human/H in mob_list) - if(H.stat != 2 && !(H.species.flags & IS_SYNTHETIC) && !H.has_brain_worms()) + var/obj/item/organ/external/head/head = H.get_organ("head") + if(head.status & ORGAN_ROBOT) + continue + if(H.stat != DEAD && !H.has_brain_worms()) possible_hosts |= H return possible_hosts diff --git a/code/game/jobs/job/job.dm b/code/game/jobs/job/job.dm index ba40b09e44..99aab0eb08 100644 --- a/code/game/jobs/job/job.dm +++ b/code/game/jobs/job/job.dm @@ -23,6 +23,10 @@ /datum/job/proc/equip(var/mob/living/carbon/human/H) return 1 +// overrideable separately so AIs/borgs can have cardborg hats without unneccessary new()/del() +/datum/job/proc/equip_preview(mob/living/carbon/human/H) + return equip(H) + /datum/job/proc/get_access() if(!config || config.jobs_have_minimal_access) return src.minimal_access.Copy() diff --git a/code/game/jobs/job/silicon.dm b/code/game/jobs/job/silicon.dm index 11d8f70a12..8889f238dd 100644 --- a/code/game/jobs/job/silicon.dm +++ b/code/game/jobs/job/silicon.dm @@ -17,6 +17,9 @@ /datum/job/ai/is_position_available() return (empty_playable_ai_cores.len != 0) +/datum/job/ai/equip_preview(mob/living/carbon/human/H) + H.equip_to_slot_or_del(new /obj/item/clothing/suit/straight_jacket(H), slot_wear_suit) + H.equip_to_slot_or_del(new /obj/item/clothing/head/cardborg(H), slot_head) /datum/job/cyborg title = "Cyborg" @@ -32,4 +35,8 @@ equip(var/mob/living/carbon/human/H) if(!H) return 0 - return 1 \ No newline at end of file + return 1 + +/datum/job/cyborg/equip_preview(mob/living/carbon/human/H) + H.equip_to_slot_or_del(new /obj/item/clothing/suit/cardborg(H), slot_wear_suit) + H.equip_to_slot_or_del(new /obj/item/clothing/head/cardborg(H), slot_head) diff --git a/code/game/machinery/adv_med.dm b/code/game/machinery/adv_med.dm index 8c6be59f71..645bfa5bcc 100644 --- a/code/game/machinery/adv_med.dm +++ b/code/game/machinery/adv_med.dm @@ -390,7 +390,8 @@ infected = "Acute Infection++:" if (INFECTION_LEVEL_THREE to INFINITY) infected = "Septic:" - + if(e.rejecting) + infected += "(being rejected)" if (e.implants.len) var/unknown_body = 0 for(var/I in e.implants) @@ -406,7 +407,7 @@ if(!(e.status & ORGAN_DESTROYED)) dat += "[e.name][e.burn_dam][e.brute_dam][robot][bled][AN][splint][open][infected][imp][internal_bleeding][lung_ruptured]" else - dat += "[e.name]--Not Found" + dat += "[e.name]--Not [e.is_stump() ? "Found" : "Attached Completely"]" dat += "" for(var/obj/item/organ/i in occ["internal_organs"]) @@ -431,6 +432,8 @@ infection = "Acute Infection+:" if (INFECTION_LEVEL_TWO + 300 to INFINITY) infection = "Acute Infection++:" + if(i.rejecting) + infection += "(being rejected)" dat += "" dat += "[i.name]N/A[i.damage][infection]:[mech]" diff --git a/code/game/machinery/computer/robot.dm b/code/game/machinery/computer/robot.dm index 84a6b7730c..d0d72fc53f 100644 --- a/code/game/machinery/computer/robot.dm +++ b/code/game/machinery/computer/robot.dm @@ -1,5 +1,3 @@ -//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:31 - /obj/machinery/computer/robotics name = "robotics control console" desc = "Used to remotely lockdown or detonate linked cyborgs." @@ -9,218 +7,205 @@ req_access = list(access_robotics) circuit = "/obj/item/weapon/circuitboard/robotics" - var/id = 0.0 - var/temp = null - var/status = 0 - var/timeleft = 60 - var/stop = 0.0 - var/screen = 0 // 0 - Main Menu, 1 - Cyborg Status, 2 - Kill 'em All! -- In text - + var/safety = 1 /obj/machinery/computer/robotics/attack_ai(var/mob/user as mob) - return src.attack_hand(user) + ui_interact(user) /obj/machinery/computer/robotics/attack_hand(var/mob/user as mob) - if(..()) - return - if (src.z > 6) - user << "\red Unable to establish a connection: \black You're too far away from the station!" - return - user.set_machine(src) - var/dat - if (src.temp) - dat = "[src.temp]

Clear Screen" - else - if(screen == 0) - dat += "

Cyborg Control Console


" - dat += "1. Cyborg Status
" - dat += "2. Emergency Full Destruct
" - if(screen == 1) - for(var/mob/living/silicon/robot/R in mob_list) - if(istype(R, /mob/living/silicon/robot/drone)) - continue //There's a specific console for drones. - if(istype(user, /mob/living/silicon/ai)) - if (R.connected_ai != user) - continue - if(istype(user, /mob/living/silicon/robot)) - if (R != user) - continue - if(R.scrambledcodes) - continue + ui_interact(user) - dat += "[R.name] |" - if(R.stat) - dat += " Not Responding |" - else if (!R.canmove) - dat += " Locked Down |" - else - dat += " Operating Normally |" - if (!R.canmove) - else if(R.cell) - dat += " Battery Installed ([R.cell.charge]/[R.cell.maxcharge]) |" - else - dat += " No Cell Installed |" - if(R.module) - dat += " Module Installed ([R.module.name]) |" - else - dat += " No Module Installed |" - if(R.connected_ai) - dat += " Slaved to [R.connected_ai.name] |" - else - dat += " Independent from AI |" - if (istype(user, /mob/living/silicon)) - if((user.mind.special_role && user.mind.original == user) && !R.emagged) - dat += "(Hack) " - dat += "([R.canmove ? "Lockdown" : "Release"]) " - dat += "(Destroy)" - dat += "
" - dat += "(Return to Main Menu)
" - if(screen == 2) - if(!src.status) - dat += {"
Emergency Robot Self-Destruct
\nStatus: Off
- \n
- \nCountdown: [src.timeleft]/60 \[Reset\]
- \n
- \nStart Sequence
- \n
- \nClose"} - else - dat = {"Emergency Robot Self-Destruct
\nStatus: Activated
- \n
- \nCountdown: [src.timeleft]/60 \[Reset\]
- \n
\nStop Sequence
- \n
- \nClose"} - dat += "(Return to Main Menu)
" +/obj/machinery/computer/robotics/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + var/data[0] + data["robots"] = get_cyborgs(user) + data["safety"] = safety + // Also applies for cyborgs. Hides the manual self-destruct button. + data["is_ai"] = user.isSilicon() - user << browse(dat, "window=computer;size=400x500") - onclose(user, "computer") - return + + ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "robot_control.tmpl", "Robotic Control Console", 400, 500) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) /obj/machinery/computer/robotics/Topic(href, href_list) if(..()) - return 1 - if ((usr.contents.Find(src) || (in_range(src, usr) && istype(src.loc, /turf))) || (istype(usr, /mob/living/silicon))) - usr.set_machine(src) + return + var/mob/user = usr + if(!src.allowed(user)) + user << "Access Denied" + return - if (href_list["eject"]) - src.temp = {"Destroy Robots?
-
\[Swipe ID to initiate destruction sequence\]
- Cancel"} - - else if (href_list["eject2"]) - var/obj/item/weapon/card/id/I = usr.get_active_hand() - if (istype(I, /obj/item/device/pda)) - var/obj/item/device/pda/pda = I - I = pda.id - if (istype(I)) - if(src.check_access(I)) - if (!status) - message_admins("\blue [key_name_admin(usr)] has initiated the global cyborg killswitch!") - log_game("\blue [key_name(usr)] has initiated the global cyborg killswitch!") - src.status = 1 - src.start_sequence() - src.temp = null - - else - usr << "\red Access Denied." - - else if (href_list["stop"]) - src.temp = {" - Stop Robot Destruction Sequence?
-
Yes
- No"} - - else if (href_list["stop2"]) - src.stop = 1 - src.temp = null - src.status = 0 - - else if (href_list["reset"]) - src.timeleft = 60 - - else if (href_list["temp"]) - src.temp = null - else if (href_list["screen"]) - switch(href_list["screen"]) - if("0") - screen = 0 - if("1") - screen = 1 - if("2") - screen = 2 - else if (href_list["killbot"]) - if(src.allowed(usr)) - var/mob/living/silicon/robot/R = locate(href_list["killbot"]) - if(R) - var/choice = input("Are you certain you wish to detonate [R.name]?") in list("Confirm", "Abort") - if(choice == "Confirm") - if(R && istype(R)) - if(R.mind && R.mind.special_role && R.emagged) - R << "Extreme danger. Termination codes detected. Scrambling security codes and automatic AI unlink triggered." - R.ResetSecurityCodes() - - else - message_admins("\blue [key_name_admin(usr)] detonated [R.name]!") - log_game("\blue [key_name_admin(usr)] detonated [R.name]!") - R.self_destruct() - else - usr << "\red Access Denied." - - else if (href_list["stopbot"]) - if(src.allowed(usr)) - var/mob/living/silicon/robot/R = locate(href_list["stopbot"]) - if(R && istype(R)) // Extra sancheck because of input var references - var/choice = input("Are you certain you wish to [R.canmove ? "lock down" : "release"] [R.name]?") in list("Confirm", "Abort") - if(choice == "Confirm") - if(R && istype(R)) - message_admins("\blue [key_name_admin(usr)] [R.canmove ? "locked down" : "released"] [R.name]!") - log_game("[key_name(usr)] [R.canmove ? "locked down" : "released"] [R.name]!") - R.canmove = !R.canmove - if (R.lockcharge) - // R.cell.charge = R.lockcharge - R.lockcharge = !R.lockcharge - R << "Your lockdown has been lifted!" - else - R.lockcharge = !R.lockcharge - // R.cell.charge = 0 - R << "You have been locked down!" - - else - usr << "\red Access Denied." - - else if (href_list["magbot"]) - if(src.allowed(usr)) - var/mob/living/silicon/robot/R = locate(href_list["magbot"]) - - // whatever weirdness this is supposed to be, but that is how the href gets added, so here it is again - if(istype(R) && istype(usr, /mob/living/silicon) && usr.mind.special_role && (usr.mind.original == usr) && !R.emagged) - - var/choice = input("Are you certain you wish to hack [R.name]?") in list("Confirm", "Abort") - if(choice == "Confirm") - if(R && istype(R)) -// message_admins("\blue [key_name_admin(usr)] emagged [R.name] using robotic console!") - log_game("[key_name(usr)] emagged [R.name] using robotic console!") - R.emagged = 1 - if(R.mind.special_role) - R.verbs += /mob/living/silicon/robot/proc/ResetSecurityCodes - - src.add_fingerprint(usr) - src.updateUsrDialog() - return - -/obj/machinery/computer/robotics/proc/start_sequence() - - do - if(src.stop) - src.stop = 0 + // Destroys the cyborg + if(href_list["detonate"]) + var/mob/living/silicon/robot/target = get_cyborg_by_name(href_list["detonate"]) + if(!target || !istype(target)) return - src.timeleft-- - sleep(10) - while(src.timeleft) + if(user.isMobAI() && (target.connected_ai != user)) + user << "Access Denied. This robot is not linked to you." + return + // Cyborgs may blow up themselves via the console + if(isrobot(user) && user != target) + user << "Access Denied." + return + var/choice = input("Really detonate [target.name]?") in list ("Yes", "No") + if(choice != "Yes") + return + if(!target || !istype(target)) + return + + // Antagonistic cyborgs? Left here for downstream + if(target.mind && target.mind.special_role && target.emagged) + target << "Extreme danger. Termination codes detected. Scrambling security codes and automatic AI unlink triggered." + target.ResetSecurityCodes() + else + message_admins("\blue [key_name_admin(usr)] detonated [target.name]!") + log_game("\blue [key_name_admin(usr)] detonated [target.name]!") + target << "Self-destruct command received." + spawn(10) + target.self_destruct() + + + + // Locks or unlocks the cyborg + else if (href_list["lockdown"]) + var/mob/living/silicon/robot/target = get_cyborg_by_name(href_list["lockdown"]) + if(!target || !istype(target)) + return + + if(user.isMobAI() && (target.connected_ai != user)) + user << "Access Denied. This robot is not linked to you." + return + + if(isrobot(user)) + user << "Access Denied." + return + + var/choice = input("Really [target.lockcharge ? "unlock" : "lockdown"] [target.name] ?") in list ("Yes", "No") + if(choice != "Yes") + return + + if(!target || !istype(target)) + return + + message_admins("\blue [key_name_admin(usr)] [target.canmove ? "locked down" : "released"] [target.name]!") + log_game("[key_name(usr)] [target.canmove ? "locked down" : "released"] [target.name]!") + target.canmove = !target.canmove + if (target.lockcharge) + target.lockcharge = !target.lockcharge + target << "Your lockdown has been lifted!" + else + target.lockcharge = !target.lockcharge + target << "You have been locked down!" + + // Remotely hacks the cyborg. Only antag AIs can do this and only to linked cyborgs. + else if (href_list["hack"]) + var/mob/living/silicon/robot/target = get_cyborg_by_name(href_list["hack"]) + if(!target || !istype(target)) + return + + // Antag AI checks + if(!istype(user, /mob/living/silicon/ai) || !(user.mind.special_role && user.mind.original == user)) + user << "Access Denied" + return + + if(target.emagged) + user << "Robot is already hacked." + return + + var/choice = input("Really hack [target.name]? This cannot be undone.") in list("Yes", "No") + if(choice != "Yes") + return + + if(!target || !istype(target)) + return + + message_admins("\blue [key_name_admin(usr)] emagged [target.name] using robotic console!") + log_game("[key_name(usr)] emagged [target.name] using robotic console!") + target.emagged = 1 + target << "Failsafe protocols overriden. New tools available." + + // Arms the emergency self-destruct system + else if(href_list["arm"]) + if(istype(user, /mob/living/silicon)) + user << "Access Denied" + return + + safety = !safety + user << "You [safety ? "disarm" : "arm"] the emergency self destruct" + + // Destroys all accessible cyborgs if safety is disabled + else if(href_list["nuke"]) + if(istype(user, /mob/living/silicon)) + user << "Access Denied" + return + if(safety) + user << "Self-destruct aborted - safety active" + return + + message_admins("\blue [key_name_admin(usr)] detonated all cyborgs!") + log_game("[key_name(usr)] detonated all cyborgs!") + + for(var/mob/living/silicon/robot/R in mob_list) + if(istype(R, /mob/living/silicon/robot/drone)) + continue + // Ignore antagonistic cyborgs + if(R.scrambledcodes) + continue + R << "Self-destruct command received." + spawn(10) + R.self_destruct() + + +// Proc: get_cyborgs() +// Parameters: 1 (operator - mob which is operating the console.) +// Description: Returns NanoUI-friendly list of accessible cyborgs. +/obj/machinery/computer/robotics/proc/get_cyborgs(var/mob/operator) + var/list/robots = list() for(var/mob/living/silicon/robot/R in mob_list) - if(!R.scrambledcodes && !istype(R, /mob/living/silicon/robot/drone)) - R.self_destruct() + // Ignore drones + if(istype(R, /mob/living/silicon/robot/drone)) + continue + // Ignore antagonistic cyborgs + if(R.scrambledcodes) + continue - return + var/list/robot = list() + robot["name"] = R.name + if(R.stat) + robot["status"] = "Not Responding" + else if (!R.canmove) + robot["status"] = "Lockdown" + else + robot["status"] = "Operational" + + if(R.cell) + robot["cell"] = 1 + robot["cell_capacity"] = R.cell.maxcharge + robot["cell_current"] = R.cell.charge + robot["cell_percentage"] = round(R.cell.percent()) + else + robot["cell"] = 0 + + robot["module"] = R.module ? R.module.name : "None" + robot["master_ai"] = R.connected_ai ? R.connected_ai.name : "None" + robot["hackable"] = 0 + // Antag AIs know whether linked cyborgs are hacked or not. + if(operator && istype(operator, /mob/living/silicon/ai) && (R.connected_ai == operator) && (operator.mind.special_role && operator.mind.original == operator)) + robot["hacked"] = R.emagged ? 1 : 0 + robot["hackable"] = R.emagged? 0 : 1 + robots.Add(list(robot)) + return robots + +// Proc: get_cyborg_by_name() +// Parameters: 1 (name - Cyborg we are trying to find) +// Description: Helper proc for finding cyborg by name +/obj/machinery/computer/robotics/proc/get_cyborg_by_name(var/name) + if (!name) + return + for(var/mob/living/silicon/robot/R in mob_list) + if(R.name == name) + return R diff --git a/code/game/machinery/iv_drip.dm b/code/game/machinery/iv_drip.dm index 99a2dc6607..6a82c2bf5c 100644 --- a/code/game/machinery/iv_drip.dm +++ b/code/game/machinery/iv_drip.dm @@ -106,7 +106,7 @@ if(NOCLONE in T.mutations) return - if(T.species && T.species.flags & NO_BLOOD) + if(T.species.flags & NO_BLOOD) return // If the human is losing too much blood, beep. diff --git a/code/game/machinery/rechargestation.dm b/code/game/machinery/rechargestation.dm index d41ab317d9..98cc92380c 100644 --- a/code/game/machinery/rechargestation.dm +++ b/code/game/machinery/rechargestation.dm @@ -176,8 +176,11 @@ R.adjustBruteLoss(-1) if(wire_rate && R.getFireLoss()) R.adjustFireLoss(-1) - else - update_use_power(1) + else if(istype(occupant, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = occupant + if(!isnull(H.internal_organs_by_name["cell"]) && H.nutrition < 450) + H.nutrition = min(H.nutrition+10, 450) + update_use_power(1) /obj/machinery/recharge_station/proc/go_out() if(!(occupant)) @@ -209,30 +212,42 @@ if(!user) return - if(!(istype(user, /mob/living/silicon/robot))) + var/can_accept_user + if(istype(user, /mob/living/silicon/robot)) + + var/mob/living/silicon/robot/R = user + + if(R.stat == 2) + //Whoever had it so that a borg with a dead cell can't enter this thing should be shot. --NEO + return + if(occupant) + R << "The cell is already occupied!" + return + if(!R.cell) + R << "Without a powercell, you can't be recharged." + //Make sure they actually HAVE a cell, now that they can get in while powerless. --NEO + return + can_accept_user = 1 + + else if(istype(user, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = user + if(!isnull(H.internal_organs_by_name["cell"])) + can_accept_user = 1 + + if(!can_accept_user) user << "Only non-organics may enter the recharger!" return - var/mob/living/silicon/robot/R = user - if(R.stat == 2) - //Whoever had it so that a borg with a dead cell can't enter this thing should be shot. --NEO - return - if(occupant) - R << "The cell is already occupied!" - return - if(!R.cell) - R << "Without a powercell, you can't be recharged." - //Make sure they actually HAVE a cell, now that they can get in while powerless. --NEO - return - R.stop_pulling() - if(R.client) - R.client.perspective = EYE_PERSPECTIVE - R.client.eye = src - R.loc = src - occupant = R + + user.stop_pulling() + if(user.client) + user.client.perspective = EYE_PERSPECTIVE + user.client.eye = src + user.loc = src + occupant = user /*for(var/obj/O in src) O.loc = loc*/ - add_fingerprint(R) + add_fingerprint(user) build_icon() update_use_power(1) return diff --git a/code/game/objects/items/devices/scanners.dm b/code/game/objects/items/devices/scanners.dm index 6e2697657c..4c576e0446 100644 --- a/code/game/objects/items/devices/scanners.dm +++ b/code/game/objects/items/devices/scanners.dm @@ -93,7 +93,7 @@ REAGENT SCANNER return user.visible_message(" [user] has analyzed [M]'s vitals."," You have analyzed [M]'s vitals.") - if (!istype(M, /mob/living/carbon) || (ishuman(M) && (M:species.flags & IS_SYNTHETIC))) + if (!istype(M, /mob/living/carbon) || ishuman(M)) //these sensors are designed for organic life user.show_message("\blue Analyzing Results for ERROR:\n\t Overall Status: ERROR") user.show_message("\t Key: Suffocation/Toxin/Burns/Brute", 1) diff --git a/code/game/objects/items/robot/robot_parts.dm b/code/game/objects/items/robot/robot_parts.dm index 563df642ef..8529e6db2e 100644 --- a/code/game/objects/items/robot/robot_parts.dm +++ b/code/game/objects/items/robot/robot_parts.dm @@ -68,6 +68,7 @@ name = "torso" desc = "A heavily reinforced case containing cyborg logic boards, with space for a standard power cell." icon_state = "chest" + part = list("groin","chest") construction_time = 350 construction_cost = list(DEFAULT_WALL_MATERIAL=40000) var/wires = 0.0 @@ -77,6 +78,7 @@ name = "head" desc = "A standard reinforced braincase, with spine-plugged neural socket and sensor gimbals." icon_state = "head" + part = list("head") construction_time = 350 construction_cost = list(DEFAULT_WALL_MATERIAL=25000) var/obj/item/device/flash/flash1 = null diff --git a/code/game/objects/items/weapons/cigs_lighters.dm b/code/game/objects/items/weapons/cigs_lighters.dm index 7328b88d78..a9ca4b8dc0 100644 --- a/code/game/objects/items/weapons/cigs_lighters.dm +++ b/code/game/objects/items/weapons/cigs_lighters.dm @@ -106,14 +106,9 @@ CIGARETTE PACKETS ARE IN FANCY.DM if(location) location.hotspot_expose(700, 5) if(reagents && reagents.total_volume) // check if it has any reagents at all - if(iscarbon(loc)) - var/mob/living/carbon/C = loc - if (src == C.wear_mask) // if it's in the human/monkey mouth, transfer reagents to the mob - if(istype(C, /mob/living/carbon/human)) - var/mob/living/carbon/human/H = C - if(H.species.flags & IS_SYNTHETIC) - return - + if(ishuman(loc)) + var/mob/living/carbon/human/C = loc + if (src == C.wear_mask && C.check_has_mouth()) // if it's in the human/monkey mouth, transfer reagents to the mob reagents.trans_to_mob(C, REM, CHEM_INGEST, 0.2) // Most of it is not inhaled... balance reasons. else // else just remove some of the reagents reagents.remove_any(REM) diff --git a/code/game/objects/items/weapons/grenades/chem_grenade.dm b/code/game/objects/items/weapons/grenades/chem_grenade.dm index 9f2add5541..6d5ea444cb 100644 --- a/code/game/objects/items/weapons/grenades/chem_grenade.dm +++ b/code/game/objects/items/weapons/grenades/chem_grenade.dm @@ -254,7 +254,7 @@ var/obj/item/weapon/reagent_containers/glass/beaker/B1 = new(src) var/obj/item/weapon/reagent_containers/glass/beaker/B2 = new(src) - B1.reagents.add_reagent("fluorosurfactant", 40) + B1.reagents.add_reagent("surfactant", 40) B2.reagents.add_reagent("water", 40) B2.reagents.add_reagent("cleaner", 10) diff --git a/code/game/objects/items/weapons/material/shards.dm b/code/game/objects/items/weapons/material/shards.dm index 6c2eb7ced3..cf7ebba2b4 100644 --- a/code/game/objects/items/weapons/material/shards.dm +++ b/code/game/objects/items/weapons/material/shards.dm @@ -67,7 +67,7 @@ if(ishuman(M)) var/mob/living/carbon/human/H = M - if(H.species.flags & IS_SYNTHETIC || (H.species.siemens_coefficient<0.5)) //Thick skin. + if(H.species.siemens_coefficient<0.5) //Thick skin. return if( !H.shoes && ( !H.wear_suit || !(H.wear_suit.body_parts_covered & FEET) ) ) diff --git a/code/game/objects/items/weapons/storage/boxes.dm b/code/game/objects/items/weapons/storage/boxes.dm index 0f8cbcc10f..61968c7692 100644 --- a/code/game/objects/items/weapons/storage/boxes.dm +++ b/code/game/objects/items/weapons/storage/boxes.dm @@ -628,3 +628,15 @@ new /obj/item/weapon/light/tube(src) for(var/i = 0; i < 7; i++) new /obj/item/weapon/light/bulb(src) + +/obj/item/weapon/storage/box/freezer + name = "portable freezer" + desc = "This nifty shock-resistant device will keep your 'groceries' nice and non-spoiled." + icon = 'icons/obj/storage.dmi' + icon_state = "portafreezer" + item_state = "medicalpack" + storage_slots=7 + max_w_class = 3 + can_hold = list(/obj/item/organ, /obj/item/weapon/reagent_containers/food, /obj/item/weapon/reagent_containers/glass) + max_storage_space = 21 + use_to_pickup = 1 // for picking up broken bulbs, not that most people will try \ No newline at end of file diff --git a/code/game/objects/items/weapons/tools.dm b/code/game/objects/items/weapons/tools.dm index 0f57ee3197..2bf69d31e7 100644 --- a/code/game/objects/items/weapons/tools.dm +++ b/code/game/objects/items/weapons/tools.dm @@ -81,7 +81,8 @@ return /obj/item/weapon/screwdriver/attack(mob/living/carbon/M as mob, mob/living/carbon/user as mob) - if(!istype(M)) return ..() + if(!istype(M) || user.a_intent == "help") + return ..() if(user.zone_sel.selecting != "eyes" && user.zone_sel.selecting != "head") return ..() if((CLUMSY in user.mutations) && prob(50)) @@ -329,8 +330,6 @@ var/obj/item/organ/eyes/E = H.internal_organs_by_name["eyes"] if(!E) return - if(H.species.flags & IS_SYNTHETIC) - return switch(safety) if(1) usr << "\red Your eyes sting a little." @@ -427,16 +426,12 @@ if(!(S.status & ORGAN_ROBOT) || user.a_intent != I_HELP) return ..() - if(istype(M,/mob/living/carbon/human)) - var/mob/living/carbon/human/H = M - if(H.species.flags & IS_SYNTHETIC) - if(M == user) - user << "\red You can't repair damage to your own body - it's against OH&S." - return - if(S.brute_dam) - S.heal_damage(15,0,0,1) - user.visible_message("\red \The [user] patches some dents on \the [M]'s [S.name] with \the [src].") + if(S.brute_dam < ROBOLIMB_SELF_REPAIR_CAP) + S.heal_damage(15,0,0,1) + user.visible_message("\red \The [user] patches some dents on \the [M]'s [S.name] with \the [src].") + else + user << "\red The damage is far too severe to patch over externally." return else user << "Nothing to fix!" diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index fcbd890263..0848c17a11 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -634,10 +634,6 @@ datum/preferences dat += "
Has a variety of eye colours." if(current_species.flags & IS_PLANT) dat += "
Has a plantlike physiology." - if(current_species.flags & IS_SYNTHETIC) - dat += "
Is machine-based." - if(current_species.flags & REGENERATES_LIMBS) - dat += "
Has a plantlike physiology." dat += "" dat += "" dat += "

" diff --git a/code/modules/ghosttrap/trap.dm b/code/modules/ghosttrap/trap.dm new file mode 100644 index 0000000000..dd53c1a389 --- /dev/null +++ b/code/modules/ghosttrap/trap.dm @@ -0,0 +1,114 @@ +// This system is used to grab a ghost from observers with the required preferences and +// lack of bans set. See posibrain.dm for an example of how they are called/used. ~Z + +var/list/ghost_traps + +proc/get_ghost_trap(var/trap_key) + if(!ghost_traps) + populate_ghost_traps() + return ghost_traps[trap_key] + +proc/populate_ghost_traps() + ghost_traps = list() + for(var/traptype in typesof(/datum/ghosttrap)) + var/datum/ghosttrap/G = new traptype + ghost_traps[G.object] = G + +/datum/ghosttrap + var/object = "positronic brain" + var/list/ban_checks = list("AI","Cyborg") + var/pref_check = BE_AI + var/ghost_trap_message = "They are occupying a positronic brain now." + var/ghost_trap_role = "Positronic Brain" + +// Check for bans, proper atom types, etc. +/datum/ghosttrap/proc/assess_candidate(var/mob/dead/observer/candidate) + if(!istype(candidate) || !candidate.client || !candidate.ckey) + return 0 + if(!candidate.MayRespawn()) + candidate << "You have made use of the AntagHUD and hence cannot enter play as \a [object]." + return 0 + if(islist(ban_checks)) + for(var/bantype in ban_checks) + if(jobban_isbanned(candidate, "[bantype]")) + candidate << "You are banned from one or more required roles and hence cannot enter play as \a [object]." + return 0 + return 1 + +// Print a message to all ghosts with the right prefs/lack of bans. +/datum/ghosttrap/proc/request_player(var/mob/target, var/request_string) + if(!target) + return + for(var/mob/dead/observer/O in player_list) + if(!O.MayRespawn()) + continue + if(islist(ban_checks)) + for(var/bantype in ban_checks) + if(jobban_isbanned(O, "[bantype]")) + continue + if(pref_check && !(O.client.prefs.be_special & pref_check)) + continue + if(O.client) + O << "[request_string]Click here if you wish to play as this option." + +// Handles a response to request_player(). +/datum/ghosttrap/Topic(href, href_list) + if(..()) + return 1 + if(href_list["candidate"] && href_list["target"]) + var/mob/dead/observer/candidate = locate(href_list["candidate"]) // BYOND magic. + var/mob/target = locate(href_list["target"]) // So much BYOND magic. + if(!target || !candidate) + return + if(candidate == usr && assess_candidate(candidate) && !target.ckey) + transfer_personality(candidate,target) + return 1 + +// Shunts the ckey/mind into the target mob. +/datum/ghosttrap/proc/transfer_personality(var/mob/candidate, var/mob/target) + if(!assess_candidate(candidate)) + return 0 + target.ckey = candidate.ckey + if(target.mind) + target.mind.assigned_role = "[ghost_trap_role]" + announce_ghost_joinleave(candidate, 0, "[ghost_trap_message]") + welcome_candidate(target) + set_new_name(target) + return 1 + +// Fluff! +/datum/ghosttrap/proc/welcome_candidate(var/mob/target) + target << "You are a positronic brain, brought into existence on [station_name()]." + target << "As a synthetic intelligence, you answer to all crewmembers, as well as the AI." + target << "Remember, the purpose of your existence is to serve the crew and the station. Above all else, do no harm." + target << "Use say :b to speak to other artificial intelligences." + var/turf/T = get_turf(target) + T.visible_message("\The [src] chimes quietly.") + var/obj/item/device/mmi/digital/posibrain/P = target.loc + if(!istype(P)) //wat + return + P.searching = 0 + P.name = "positronic brain ([P.brainmob.name])" + P.icon_state = "posibrain-occupied" + +// Allows people to set their own name. May or may not need to be removed for posibrains if people are dumbasses. +/datum/ghosttrap/proc/set_new_name(var/mob/target) + var/newname = sanitizeSafe(input(target,"Enter a name, or leave blank for the default name.", "Name change","") as text, MAX_NAME_LEN) + if (newname != "") + target.real_name = newname + target.name = target.real_name + +// Doona pods and walking mushrooms. +/datum/ghosttrap/plant + object = "living plant" + ban_checks = list("Dionaea") + pref_check = BE_PLANT + ghost_trap_message = "They are occupying a living plant now." + ghost_trap_role = "Plant" + +/datum/ghosttrap/plant/welcome_candidate(var/mob/target) + target << "