From 7dd0bb2b567a0bafb13e89862507338cda061cab Mon Sep 17 00:00:00 2001 From: Geeves Date: Fri, 17 Jul 2020 19:26:30 +0200 Subject: [PATCH] Robot Cleanup (#9332) --- aurorastation.dme | 24 +- code/game/objects/items/robot/robot_items.dm | 99 ---- code/game/objects/items/robot/robot_parts.dm | 381 ------------- code/modules/custom_ka/core.dm | 4 +- code/modules/custom_ka/frames.dm | 2 +- code/modules/mining/minebot.dm | 3 +- .../mob/living/silicon/robot/analyzer.dm | 6 +- .../mob/living/silicon/robot/component.dm | 31 +- .../living/silicon/robot/custom_sprites.dm | 3 +- .../modules/mob/living/silicon/robot/death.dm | 4 +- .../mob/living/silicon/robot/drone/drone.dm | 3 +- .../mob/living/silicon/robot/examine.dm | 3 +- .../mob/living/silicon/robot/inventory.dm | 2 +- .../living/silicon/robot/items/_helpers.dm | 11 + .../silicon/robot/items/auto_harvester.dm | 19 + .../silicon/robot/items/electric_arm.dm | 24 + .../silicon/robot/items/form_printer.dm | 22 + .../silicon/robot/{ => items}/gripper.dm | 2 +- .../robot/items/guns/ballistic_cannon.dm | 15 + .../silicon/robot/items/inductive_charger.dm | 84 +++ .../robot/items/modules/mobility_module.dm | 13 + .../robot/items/modules/robot_shield.dm | 24 + .../silicon/robot/items/modules/sight.dm | 54 ++ .../living/silicon/robot/items/overdrive.dm | 4 + .../items/portable_destructive_analyzer.dm | 103 ++++ .../living/silicon/robot/items/robot_id.dm | 6 + .../silicon/robot/items/robot_inflatables.dm | 119 ++++ .../living/silicon/robot/items/robot_parts.dm | 429 +++++++++++++++ .../living/silicon/robot/items/robot_pen.dm | 39 ++ .../living/silicon/robot/items/robot_tools.dm | 26 + .../living/silicon/robot/items/robot_tray.dm | 27 + .../robot/items/upgrades}/robot_upgrades.dm | 139 ++--- code/modules/mob/living/silicon/robot/laws.dm | 23 +- .../modules/mob/living/silicon/robot/robot.dm | 23 +- .../mob/living/silicon/robot/robot_items.dm | 512 ------------------ .../mob/living/silicon/robot/robot_modules.dm | 107 ++-- .../living/silicon/robot/syndicate_robot.dm | 2 +- code/modules/projectiles/gun.dm | 4 +- .../designs/mechfab/robot/robot_upgrades.dm | 4 +- html/changelogs/geeves-robot_cleanup.yml | 10 + icons/mob/screen/robot.dmi | Bin 31020 -> 31373 bytes 41 files changed, 1228 insertions(+), 1182 deletions(-) delete mode 100644 code/game/objects/items/robot/robot_items.dm delete mode 100644 code/game/objects/items/robot/robot_parts.dm create mode 100644 code/modules/mob/living/silicon/robot/items/_helpers.dm create mode 100644 code/modules/mob/living/silicon/robot/items/auto_harvester.dm create mode 100644 code/modules/mob/living/silicon/robot/items/electric_arm.dm create mode 100644 code/modules/mob/living/silicon/robot/items/form_printer.dm rename code/modules/mob/living/silicon/robot/{ => items}/gripper.dm (99%) create mode 100644 code/modules/mob/living/silicon/robot/items/guns/ballistic_cannon.dm create mode 100644 code/modules/mob/living/silicon/robot/items/inductive_charger.dm create mode 100644 code/modules/mob/living/silicon/robot/items/modules/mobility_module.dm create mode 100644 code/modules/mob/living/silicon/robot/items/modules/robot_shield.dm create mode 100644 code/modules/mob/living/silicon/robot/items/modules/sight.dm create mode 100644 code/modules/mob/living/silicon/robot/items/overdrive.dm create mode 100644 code/modules/mob/living/silicon/robot/items/portable_destructive_analyzer.dm create mode 100644 code/modules/mob/living/silicon/robot/items/robot_id.dm create mode 100644 code/modules/mob/living/silicon/robot/items/robot_inflatables.dm create mode 100644 code/modules/mob/living/silicon/robot/items/robot_parts.dm create mode 100644 code/modules/mob/living/silicon/robot/items/robot_pen.dm create mode 100644 code/modules/mob/living/silicon/robot/items/robot_tools.dm create mode 100644 code/modules/mob/living/silicon/robot/items/robot_tray.dm rename code/{game/objects/items/robot => modules/mob/living/silicon/robot/items/upgrades}/robot_upgrades.dm (50%) delete mode 100644 code/modules/mob/living/silicon/robot/robot_items.dm create mode 100644 html/changelogs/geeves-robot_cleanup.yml diff --git a/aurorastation.dme b/aurorastation.dme index 80db6869e2f..37eb9ae0f50 100644 --- a/aurorastation.dme +++ b/aurorastation.dme @@ -857,9 +857,6 @@ #include "code\game\objects\items\devices\radio\headset.dm" #include "code\game\objects\items\devices\radio\intercom.dm" #include "code\game\objects\items\devices\radio\radio.dm" -#include "code\game\objects\items\robot\robot_items.dm" -#include "code\game\objects\items\robot\robot_parts.dm" -#include "code\game\objects\items\robot\robot_upgrades.dm" #include "code\game\objects\items\stacks\matter_synth.dm" #include "code\game\objects\items\stacks\medical.dm" #include "code\game\objects\items\stacks\nanopaste.dm" @@ -1976,7 +1973,6 @@ #include "code\modules\mob\living\silicon\robot\death.dm" #include "code\modules\mob\living\silicon\robot\emote.dm" #include "code\modules\mob\living\silicon\robot\examine.dm" -#include "code\modules\mob\living\silicon\robot\gripper.dm" #include "code\modules\mob\living\silicon\robot\inventory.dm" #include "code\modules\mob\living\silicon\robot\laws.dm" #include "code\modules\mob\living\silicon\robot\life.dm" @@ -1986,7 +1982,6 @@ #include "code\modules\mob\living\silicon\robot\robot.dm" #include "code\modules\mob\living\silicon\robot\robot_damage.dm" #include "code\modules\mob\living\silicon\robot\robot_helpers.dm" -#include "code\modules\mob\living\silicon\robot\robot_items.dm" #include "code\modules\mob\living\silicon\robot\robot_modules.dm" #include "code\modules\mob\living\silicon\robot\robot_movement.dm" #include "code\modules\mob\living\silicon\robot\syndicate_robot.dm" @@ -1997,6 +1992,25 @@ #include "code\modules\mob\living\silicon\robot\drone\drone_items.dm" #include "code\modules\mob\living\silicon\robot\drone\drone_manufacturer.dm" #include "code\modules\mob\living\silicon\robot\drone\drone_say.dm" +#include "code\modules\mob\living\silicon\robot\items\_helpers.dm" +#include "code\modules\mob\living\silicon\robot\items\auto_harvester.dm" +#include "code\modules\mob\living\silicon\robot\items\electric_arm.dm" +#include "code\modules\mob\living\silicon\robot\items\form_printer.dm" +#include "code\modules\mob\living\silicon\robot\items\inductive_charger.dm" +#include "code\modules\mob\living\silicon\robot\items\gripper.dm" +#include "code\modules\mob\living\silicon\robot\items\overdrive.dm" +#include "code\modules\mob\living\silicon\robot\items\portable_destructive_analyzer.dm" +#include "code\modules\mob\living\silicon\robot\items\robot_id.dm" +#include "code\modules\mob\living\silicon\robot\items\robot_inflatables.dm" +#include "code\modules\mob\living\silicon\robot\items\robot_parts.dm" +#include "code\modules\mob\living\silicon\robot\items\robot_pen.dm" +#include "code\modules\mob\living\silicon\robot\items\robot_tools.dm" +#include "code\modules\mob\living\silicon\robot\items\robot_tray.dm" +#include "code\modules\mob\living\silicon\robot\items\guns\ballistic_cannon.dm" +#include "code\modules\mob\living\silicon\robot\items\modules\mobility_module.dm" +#include "code\modules\mob\living\silicon\robot\items\modules\robot_shield.dm" +#include "code\modules\mob\living\silicon\robot\items\modules\sight.dm" +#include "code\modules\mob\living\silicon\robot\items\upgrades\robot_upgrades.dm" #include "code\modules\mob\living\simple_animal\bees.dm" #include "code\modules\mob\living\simple_animal\corpse.dm" #include "code\modules\mob\living\simple_animal\parrot.dm" diff --git a/code/game/objects/items/robot/robot_items.dm b/code/game/objects/items/robot/robot_items.dm deleted file mode 100644 index c6a8103a367..00000000000 --- a/code/game/objects/items/robot/robot_items.dm +++ /dev/null @@ -1,99 +0,0 @@ -//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32 - -/********************************************************************** - Cyborg Spec Items -***********************************************************************/ -//Might want to move this into several files later but for now it works here -// Consider changing this to a child of the stun baton class. ~Z -/obj/item/borg/stun - name = "electrified arm" - icon = 'icons/obj/decals.dmi' - icon_state = "shock" - -/obj/item/borg/stun/apply_hit_effect(mob/living/M, mob/living/silicon/robot/user, var/hit_zone) - if(!istype(user)) - return 0 - - user.visible_message("\The [user] has prodded \the [M] with \a [src]!") - - if(!user.cell || !user.cell.checked_use(1250)) //Slightly more than a baton. - return 0 - - playsound(loc, 'sound/weapons/Egloves.ogg', 50, 1, -1) - - M.apply_effect(5, STUTTER) - M.stun_effect_act(0, 70, check_zone(hit_zone), src) - - if(ishuman(M)) - var/mob/living/carbon/human/H = M - H.forcesay(hit_appends) - - return 0 - -/obj/item/borg/overdrive - name = "overdrive" - icon = 'icons/obj/decals.dmi' - icon_state = "shock" - -/********************************************************************** - HUD/SIGHT things -***********************************************************************/ -/obj/item/borg/sight - icon = 'icons/obj/decals.dmi' - icon_state = "securearea" - var/sight_mode = null - -/obj/item/borg/sight/on_module_hotbar(mob/living/silicon/robot/R) - R.sight_mode |= sight_mode - -/obj/item/borg/sight/on_module_store(mob/living/silicon/robot/R) - R.sight_mode &= ~sight_mode - -/obj/item/borg/sight/xray - name = "\proper x-ray vision" - sight_mode = BORGXRAY - - -/obj/item/borg/sight/thermal - name = "\proper thermal vision" - desc_antag = "Having this device on your hotbar will allow you to see in enhanced thermal vision, which allows you to see heat signatures through solid walls." - sight_mode = BORGTHERM - icon_state = "thermal" - icon = 'icons/obj/clothing/glasses.dmi' - - -/obj/item/borg/sight/meson - name = "\proper meson vision" - sight_mode = BORGMESON - icon_state = "meson" - icon = 'icons/obj/clothing/glasses.dmi' - -/obj/item/borg/sight/material - name = "\proper material scanner vision" - sight_mode = BORGMATERIAL - -/obj/item/borg/sight/hud - name = "hud" - var/obj/item/clothing/glasses/hud/hud = null - - -/obj/item/borg/sight/hud/med - name = "medical hud" - icon_state = "healthhud" - icon = 'icons/obj/clothing/glasses.dmi' - - New() - ..() - hud = new /obj/item/clothing/glasses/hud/health(src) - return - - -/obj/item/borg/sight/hud/sec - name = "security hud" - icon_state = "securityhud" - icon = 'icons/obj/clothing/glasses.dmi' - - New() - ..() - hud = new /obj/item/clothing/glasses/hud/security(src) - return diff --git a/code/game/objects/items/robot/robot_parts.dm b/code/game/objects/items/robot/robot_parts.dm deleted file mode 100644 index efbdd32d328..00000000000 --- a/code/game/objects/items/robot/robot_parts.dm +++ /dev/null @@ -1,381 +0,0 @@ -/obj/item/robot_parts - name = "robot parts" - icon = 'icons/obj/robot_parts.dmi' - item_state = "buildpipe" - icon_state = "blank" - flags = CONDUCT - slot_flags = SLOT_BELT - var/list/part = null // Order of args is important for installing robolimbs. - var/sabotaged = 0 //Emagging limbs can have repercussions when installed as prosthetics. - var/model_info - var/linked_frame = "Unbranded Frame" - dir = SOUTH - -/obj/item/robot_parts/set_dir() - return - -/obj/item/robot_parts/New(var/newloc, var/model) - ..(newloc) - if(model_info && model) - model_info = model - var/datum/robolimb/R = all_robolimbs[model] - if(R) - name = "[R.company] robot [initial(name)]" - desc = "[R.desc]" - linked_frame = R.linked_frame - if(icon_state in icon_states(R.icon)) - icon = R.icon - else - name = "robot [initial(name)]" - -/obj/item/robot_parts/l_arm - name = "left arm" - desc = "A skeletal limb wrapped in pseudomuscles, with a low-conductivity case." - icon_state = "l_arm" - part = list(BP_L_ARM,BP_L_HAND) - model_info = 1 - -/obj/item/robot_parts/r_arm - name = "right arm" - desc = "A skeletal limb wrapped in pseudomuscles, with a low-conductivity case." - icon_state = "r_arm" - part = list(BP_R_ARM,BP_R_HAND) - model_info = 1 - -/obj/item/robot_parts/l_leg - name = "left leg" - desc = "A skeletal limb wrapped in pseudomuscles, with a low-conductivity case." - icon_state = "l_leg" - part = list(BP_L_LEG,BP_L_FOOT) - model_info = 1 - -/obj/item/robot_parts/r_leg - name = "right leg" - desc = "A skeletal limb wrapped in pseudomuscles, with a low-conductivity case." - icon_state = "r_leg" - part = list(BP_R_LEG,BP_R_FOOT) - model_info = 1 - -/obj/item/robot_parts/chest - name = "torso" - desc = "A heavily reinforced case containing cyborg logic boards, with space for a standard power cell." - icon_state = "chest" - part = list(BP_GROIN,BP_CHEST) - var/wires = 0.0 - var/obj/item/cell/cell = null - -/obj/item/robot_parts/head - name = "head" - desc = "A standard reinforced braincase, with spine-plugged neural socket and sensor gimbals." - icon_state = "head" - part = list(BP_HEAD) - var/obj/item/device/flash/flash1 = null - var/obj/item/device/flash/flash2 = null - var/law_manager = TRUE - -/obj/item/robot_parts/robot_suit - name = "endoskeleton" - desc = "A complex metal backbone with standard limb sockets and pseudomuscle anchors." - icon_state = "robo_suit" - var/obj/item/robot_parts/l_arm/l_arm = null - var/obj/item/robot_parts/r_arm/r_arm = null - var/obj/item/robot_parts/l_leg/l_leg = null - var/obj/item/robot_parts/r_leg/r_leg = null - var/obj/item/robot_parts/chest/chest = null - var/obj/item/robot_parts/head/head = null - var/created_name = "" - -/obj/item/robot_parts/robot_suit/Initialize() - . = ..() - src.updateicon() - -/obj/item/robot_parts/robot_suit/equipped/Initialize() - . = ..() - l_leg = new /obj/item/robot_parts/l_leg(src) - r_leg = new /obj/item/robot_parts/r_leg(src) - l_arm = new /obj/item/robot_parts/l_arm(src) - r_arm = new /obj/item/robot_parts/r_arm(src) - updateicon() - -/obj/item/robot_parts/robot_suit/proc/updateicon() - cut_overlays() - if(src.l_arm) - add_overlay("l_arm+o") - if(src.r_arm) - add_overlay("r_arm+o") - if(src.chest) - add_overlay("chest+o") - if(src.l_leg) - add_overlay("l_leg+o") - if(src.r_leg) - add_overlay("r_leg+o") - if(src.head) - add_overlay("head+o") - -/obj/item/robot_parts/robot_suit/proc/check_completion() - if(src.l_arm && src.r_arm) - if(src.l_leg && src.r_leg) - if(src.chest && src.head) - feedback_inc("cyborg_frames_built",1) - return 1 - return 0 - -/obj/item/robot_parts/robot_suit/attackby(obj/item/W as obj, mob/user as mob) - ..() - if(istype(W, /obj/item/stack/material) && W.get_material_name() == DEFAULT_WALL_MATERIAL && !l_arm && !r_arm && !l_leg && !r_leg && !chest && !head) - var/obj/item/stack/material/M = W - if (M.use(1)) - var/obj/item/secbot_assembly/ed209_assembly/B = new /obj/item/secbot_assembly/ed209_assembly - B.forceMove(get_turf(src)) - to_chat(user, "You armed the robot frame.") - if (user.get_inactive_hand()==src) - user.remove_from_mob(src) - user.put_in_inactive_hand(B) - qdel(src) - else - to_chat(user, "You need one sheet of metal to arm the robot frame.") - if(istype(W, /obj/item/robot_parts/l_leg)) - if(src.l_leg) return - user.drop_from_inventory(W,src) - src.l_leg = W - src.updateicon() - - if(istype(W, /obj/item/robot_parts/r_leg)) - if(src.r_leg) return - user.drop_from_inventory(W,src) - src.r_leg = W - src.updateicon() - - if(istype(W, /obj/item/robot_parts/l_arm)) - if(src.l_arm) return - user.drop_from_inventory(W,src) - src.l_arm = W - src.updateicon() - - if(istype(W, /obj/item/robot_parts/r_arm)) - if(src.r_arm) return - user.drop_from_inventory(W,src) - src.r_arm = W - src.updateicon() - - if(istype(W, /obj/item/robot_parts/chest)) - if(src.chest) return - if(W:wires && W:cell) - user.drop_from_inventory(W,src) - src.chest = W - src.updateicon() - else if(!W:wires) - to_chat(user, "You need to attach wires to it first!") - else - to_chat(user, "You need to attach a cell to it first!") - - if(istype(W, /obj/item/robot_parts/head)) - if(src.head) return - if(W:flash2 && W:flash1) - user.drop_from_inventory(W,src) - src.head = W - src.updateicon() - else - to_chat(user, "You need to attach a flash to it first!") - - if(istype(W, /obj/item/device/mmi)) - var/obj/item/device/mmi/M = W - if(check_completion()) - if(!istype(loc,/turf)) - to_chat(user, "You can't put \the [W] in, the frame has to be standing on the ground to be perfectly precise.") - return - if(!M.brainmob) - to_chat(user, "Sticking an empty [W] into the frame would sort of defeat the purpose.") - return - if(!M.brainmob.key) - var/ghost_can_reenter = 0 - if(M.brainmob.mind) - for(var/mob/abstract/observer/G in player_list) - if(G.can_reenter_corpse && G.mind == M.brainmob.mind) - ghost_can_reenter = 1 - break - if(!ghost_can_reenter) - to_chat(user, "\The [W] is completely unresponsive; there's no point.") - return - - if(M.brainmob.stat == DEAD) - to_chat(user, "Sticking a dead [W] into the frame would sort of defeat the purpose.") - return - - if(!src.head.law_manager) - - if(!is_alien_whitelisted(M.brainmob, "Baseline Frame") && config.usealienwhitelist) - to_chat(user, "\The [W] does not seem to fit.") - return - - var/mob/living/carbon/human/new_shell = new(get_turf(loc), src.chest.linked_frame) - src.forceMove(new_shell) //so people won't mess around with the chassis until it is deleted - M.brainmob.mind.transfer_to(new_shell) - qdel(M) - var/newname = sanitizeSafe(input(new_shell,"Enter a name, or leave blank for the default name.", "Name change","") as text, MAX_NAME_LEN) - if(!newname) - var/datum/language/L = all_languages[new_shell.species.default_language] - newname = L.get_random_name() - new_shell.real_name = newname - new_shell.name = new_shell.real_name - new_shell.change_appearance(APPEARANCE_ALL_HAIR | APPEARANCE_SKIN | APPEARANCE_EYE_COLOR, new_shell.loc, new_shell) - qdel(src) - return - - else - - if(jobban_isbanned(M.brainmob, "Cyborg")) - to_chat(user, "\The [W] does not seem to fit.") - return - - var/mob/living/silicon/robot/O = new /mob/living/silicon/robot(get_turf(loc), TRUE) - if(!O) return - - user.drop_item() //TODO: Look into this. - - O.mmi = W - O.invisibility = 0 - O.custom_name = created_name - O.updatename("Default") - - M.brainmob.mind.transfer_to(O) - - if(O.mind && O.mind.special_role) - O.mind.store_memory("In case you look at this after being borged, the objectives are only here until I find a way to make them not show up for you, as I can't simply delete them without screwing up round-end reporting. --NeoFite") - - O.job = "Cyborg" - - O.cell = chest.cell - O.cell.forceMove(O) - W.forceMove(O)//Should fix cybros run time erroring when blown up. It got deleted before, along with the frame. - - // Since we "magically" installed a cell, we also have to update the correct component. - if(O.cell) - var/datum/robot_component/cell_component = O.components["power cell"] - cell_component.wrapped = O.cell - cell_component.installed = 1 - - feedback_inc("cyborg_birth",1) - callHook("borgify", list(O)) - O.Namepick() - - qdel(src) - else - to_chat(user, "The MMI must go in after everything else!") - - if (W.ispen()) - var/t = sanitizeSafe(input(user, "Enter new robot name", src.name, src.created_name), MAX_NAME_LEN) - if (!t) - return - if (!in_range(src, usr) && src.loc != usr) - return - - src.created_name = t - - return - -/obj/item/robot_parts/chest/attackby(obj/item/W as obj, mob/user as mob) - ..() - if(istype(W, /obj/item/cell)) - if(src.cell) - to_chat(user, "You have already inserted a cell!") - return - else - user.drop_from_inventory(W,src) - src.cell = W - to_chat(user, "You insert the cell!") - if(W.iscoil()) - if(src.wires) - to_chat(user, "You have already inserted wire!") - return - else - var/obj/item/stack/cable_coil/coil = W - coil.use(1) - src.wires = 1.0 - to_chat(user, "You insert the wire!") - return - -/obj/item/robot_parts/head/attackby(obj/item/W as obj, mob/user as mob) - ..() - if(W.ismultitool()) - if(law_manager) - to_chat(user, "You disable the lawing circuits on \the [src].") - law_manager = FALSE - else - to_chat(user, "You enable the lawing circuits on \the [src].") - law_manager = TRUE - - if(istype(W, /obj/item/device/flash)) - if(istype(user,/mob/living/silicon/robot)) - var/current_module = user.get_active_hand() - if(current_module == W) - to_chat(user, "How do you propose to do that?") - return - else - add_flashes(W,user) - else - add_flashes(W,user) - else if(istype(W, /obj/item/stock_parts/manipulator)) - to_chat(user, "You install some manipulators and modify the head, creating a functional spider-bot!") - - - - new /mob/living/simple_animal/spiderbot(get_turf(loc)) - user.drop_from_inventory(W,get_turf(loc)) - qdel(W) - qdel(src) - return - return - -/obj/item/robot_parts/head/proc/add_flashes(obj/item/W as obj, mob/user as mob) //Made into a seperate proc to avoid copypasta - if(src.flash1 && src.flash2) - to_chat(user, "You have already inserted the eyes!") - return - else if(src.flash1) - user.drop_from_inventory(W,src) - src.flash2 = W - to_chat(user, "You insert the flash into the eye socket!") - else - user.drop_from_inventory(W,src) - src.flash1 = W - to_chat(user, "You insert the flash into the eye socket!") - - -/obj/item/robot_parts/emag_act(var/remaining_charges, var/mob/user) - if(sabotaged) - to_chat(user, "[src] is already sabotaged!") - else - to_chat(user, "You short out the safeties.") - sabotaged = 1 - return 1 - -//branded chest, to be used in ipc ressurection - -/obj/item/robot_parts/chest/bishop - name = "Bishop cybernetics torso" - model_info = 1 - linked_frame = "Bishop Accessory Frame" - -/obj/item/robot_parts/chest/hephaestus - name = "Hephaestus industries torso" - linked_frame = "Hephaestus G2 Industrial Frame" - -/obj/item/robot_parts/chest/zenghu - name = "Zeng-Hu pharmaceuticals torso" - linked_frame = "Zeng-Hu Mobility Frame" - -/obj/item/robot_parts/chest/synthskin - name = "Human synthskin torso" - linked_frame = "Shell Frame" - -/obj/item/robot_parts/chest/xion - name = "Xion manufacturing group torso" - linked_frame = "Xion Industrial Frame" - -/obj/item/robot_parts/chest/ipc - name = "Hephaestus integrated torso" - linked_frame = "Baseline Frame" - -/obj/item/robot_parts/chest/industrial - name = "Hephaestus industrial torso" - linked_frame = "Hephaestus G1 Industrial Frame" diff --git a/code/modules/custom_ka/core.dm b/code/modules/custom_ka/core.dm index 75c6292565f..bdcac84fac2 100644 --- a/code/modules/custom_ka/core.dm +++ b/code/modules/custom_ka/core.dm @@ -103,10 +103,10 @@ to_chat(user,"The offical designation \"[official_name]\" is etched neatly on the side.") if(installed_cell) - to_chat(user,"It has [get_ammo()] shots remaining.") + to_chat(user, "It has [get_ammo()] shots remaining.") /obj/item/gun/custom_ka/get_ammo() - if(!installed_cell) + if(!installed_cell || !installed_cell.stored_charge) return 0 return round(installed_cell.stored_charge / cost_increase) diff --git a/code/modules/custom_ka/frames.dm b/code/modules/custom_ka/frames.dm index a853938e435..5223d52c1df 100644 --- a/code/modules/custom_ka/frames.dm +++ b/code/modules/custom_ka/frames.dm @@ -71,7 +71,7 @@ mod_limit_increase = 100 origin_tech = list() can_disassemble_cell = FALSE - displays_maptext = FALSE + cyborg_maptext_override = TRUE installed_cell = /obj/item/custom_ka_upgrade/cells/cyborg installed_barrel = /obj/item/custom_ka_upgrade/barrels/barrel02 diff --git a/code/modules/mining/minebot.dm b/code/modules/mining/minebot.dm index 2d9a9d752a6..25ac4b8afea 100644 --- a/code/modules/mining/minebot.dm +++ b/code/modules/mining/minebot.dm @@ -1,5 +1,6 @@ /mob/living/silicon/robot/drone/mining icon_state = "miningdrone" + mod_type = "Mining" law_type = /datum/ai_laws/mining_drone module_type = /obj/item/robot_module/mining_drone/basic holder_type = /obj/item/holder/drone/mining @@ -53,7 +54,7 @@ if(!laws) laws = new law_type if(!module) - module = new module_type(src) + module = new module_type(src, src) flavor_text = "It's a tiny little mining drone. The casing is stamped with an corporate logo and the subscript: '[current_map.company_name] Automated Pickaxe!'" playsound(src.loc, 'sound/machines/twobeep.ogg', 50, 0) diff --git a/code/modules/mob/living/silicon/robot/analyzer.dm b/code/modules/mob/living/silicon/robot/analyzer.dm index 0523f4bcc9f..4f4dd1f9887 100644 --- a/code/modules/mob/living/silicon/robot/analyzer.dm +++ b/code/modules/mob/living/silicon/robot/analyzer.dm @@ -9,12 +9,11 @@ flags = CONDUCT slot_flags = SLOT_BELT throwforce = 3 - w_class = 2.0 + w_class = ITEMSIZE_SMALL throw_speed = 5 throw_range = 10 origin_tech = list(TECH_MAGNET = 2, TECH_BIO = 1, TECH_ENGINEERING = 2) matter = list(DEFAULT_WALL_MATERIAL = 500, MATERIAL_GLASS = 200) - var/mode = 1 /obj/item/device/robotanalyzer/attack(mob/living/M, mob/living/user) if((user.is_clumsy() || (DUMB in user.mutations)) && prob(50)) @@ -99,5 +98,4 @@ if(!organ_found) to_chat(user, SPAN_NOTICE("No prosthetics located.")) - add_fingerprint(user) - return \ No newline at end of file + add_fingerprint(user) \ No newline at end of file diff --git a/code/modules/mob/living/silicon/robot/component.dm b/code/modules/mob/living/silicon/robot/component.dm index 5f456173b1c..6736a800e6c 100644 --- a/code/modules/mob/living/silicon/robot/component.dm +++ b/code/modules/mob/living/silicon/robot/component.dm @@ -1,21 +1,18 @@ // TODO: remove the robot.mmi and robot.cell variables and completely rely on the robot component system -/datum/robot_component/var/name -/datum/robot_component/var/installed = 0 -/datum/robot_component/var/powered = 0 -/datum/robot_component/var/toggled = 1 -/datum/robot_component/var/brute_damage = 0 -/datum/robot_component/var/electronics_damage = 0 -/datum/robot_component/var/idle_usage = 0 // Amount of power used every MC tick. In joules. -/datum/robot_component/var/active_usage = 0 // Amount of power used for every action. Actions are module-specific. Actuator for each tile moved, etc. -/datum/robot_component/var/max_damage = 30 // HP of this component. -/datum/robot_component/var/mob/living/silicon/robot/owner - -// The actual device object that has to be installed for this. -/datum/robot_component/var/external_type = null - -// The wrapped device(e.g. radio), only set if external_type isn't null -/datum/robot_component/var/obj/item/wrapped = null +/datum/robot_component + var/name = "robot component" + var/installed = 0 + var/powered = 0 + var/toggled = 1 + var/brute_damage = 0 + var/electronics_damage = 0 + var/idle_usage = 0 // Amount of power used every MC tick. In joules. + var/active_usage = 0 // Amount of power used for every action. Actions are module-specific. Actuator for each tile moved, etc. + var/max_damage = 30 // HP of this component. + var/mob/living/silicon/robot/owner + var/external_type = null // The actual device object that has to be installed for this. + var/obj/item/wrapped = null // The wrapped device(e.g. radio), only set if external_type isn't null /datum/robot_component/New(mob/living/silicon/robot/R) src.owner = R @@ -28,7 +25,7 @@ /datum/robot_component/proc/destroy() var/brokenstate = "broken" // Generic icon - if (istype(wrapped, /obj/item/robot_parts/robot_component)) + if(istype(wrapped, /obj/item/robot_parts/robot_component)) var/obj/item/robot_parts/robot_component/comp = wrapped brokenstate = comp.icon_state_broken if(wrapped) diff --git a/code/modules/mob/living/silicon/robot/custom_sprites.dm b/code/modules/mob/living/silicon/robot/custom_sprites.dm index ba1fe2a4a3e..f6b996f8bdd 100644 --- a/code/modules/mob/living/silicon/robot/custom_sprites.dm +++ b/code/modules/mob/living/silicon/robot/custom_sprites.dm @@ -9,6 +9,7 @@ var/list/robot_custom_icons else if(config.load_customsynths_from == "json") loadsynths_from_json() return 1 + /mob/living/silicon/robot/proc/set_custom_sprite() var/datum/custom_synth/sprite = robot_custom_icons[name] if(istype(sprite) && sprite.synthckey == ckey) @@ -20,4 +21,4 @@ var/list/robot_custom_icons icon_state = "[sprite.synthicon]-Standard" else to_chat(src, "Could not locate [sprite.synthicon]-Standard sprite.") - icon = 'icons/mob/robots.dmi' \ No newline at end of file + icon = 'icons/mob/robots.dmi' \ No newline at end of file diff --git a/code/modules/mob/living/silicon/robot/death.dm b/code/modules/mob/living/silicon/robot/death.dm index 8450719b7b7..439f647e761 100644 --- a/code/modules/mob/living/silicon/robot/death.dm +++ b/code/modules/mob/living/silicon/robot/death.dm @@ -6,11 +6,11 @@ /mob/living/silicon/robot/death(gibbed) if(camera) - camera.status = 0 + camera.status = FALSE if(module) var/obj/item/gripper/G = locate(/obj/item/gripper) in module if(G) G.drop_item() remove_robot_verbs() sql_report_cyborg_death(src) - ..(gibbed,"shudders violently for a moment, then becomes motionless, its eyes slowly darkening.") + ..(gibbed,"shudders violently for a moment, then becomes motionless, its eyes slowly darkening.") \ No newline at end of file diff --git a/code/modules/mob/living/silicon/robot/drone/drone.dm b/code/modules/mob/living/silicon/robot/drone/drone.dm index ed29e1948b5..b6a3775e142 100644 --- a/code/modules/mob/living/silicon/robot/drone/drone.dm +++ b/code/modules/mob/living/silicon/robot/drone/drone.dm @@ -31,6 +31,7 @@ icon = 'icons/mob/robots.dmi' icon_state = "repairbot" braintype = "Robot" + mod_type = "Engineering" gender = NEUTER // Health @@ -163,7 +164,7 @@ if(!laws) laws = new law_type if(!module) - module = new module_type(src) + module = new module_type(src, src) flavor_text = "It's a tiny little repair drone. The casing is stamped with an corporate logo and the subscript: '[current_map.company_name] Recursive Repair Systems: Fixing Tomorrow's Problem, Today!'" playsound(get_turf(src), 'sound/machines/twobeep.ogg', 50, 0) diff --git a/code/modules/mob/living/silicon/robot/examine.dm b/code/modules/mob/living/silicon/robot/examine.dm index 6dbbfdb9e5b..30897292ebf 100644 --- a/code/modules/mob/living/silicon/robot/examine.dm +++ b/code/modules/mob/living/silicon/robot/examine.dm @@ -47,5 +47,4 @@ msg += "\nIt [pose]" to_chat(user, msg) - user.showLaws(src) - return \ No newline at end of file + user.showLaws(src) \ No newline at end of file diff --git a/code/modules/mob/living/silicon/robot/inventory.dm b/code/modules/mob/living/silicon/robot/inventory.dm index 562533c3200..4237dc39451 100644 --- a/code/modules/mob/living/silicon/robot/inventory.dm +++ b/code/modules/mob/living/silicon/robot/inventory.dm @@ -295,4 +295,4 @@ var/selected = get_selected_module() if (selected) result += "\nThe activity light on hardpoint [selected] is on.\n" - return result + return result \ No newline at end of file diff --git a/code/modules/mob/living/silicon/robot/items/_helpers.dm b/code/modules/mob/living/silicon/robot/items/_helpers.dm new file mode 100644 index 00000000000..4424bb60aa2 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/items/_helpers.dm @@ -0,0 +1,11 @@ +/obj/item/proc/on_module_hotbar(var/mob/living/silicon/robot/R) + return + +/obj/item/proc/on_module_store(var/mob/living/silicon/robot/R) + return + +/obj/item/proc/on_module_activate(var/mob/living/silicon/robot/R) + return + +/obj/item/proc/on_module_deactivate(var/mob/living/silicon/robot/R) + return \ No newline at end of file diff --git a/code/modules/mob/living/silicon/robot/items/auto_harvester.dm b/code/modules/mob/living/silicon/robot/items/auto_harvester.dm new file mode 100644 index 00000000000..c5871e7e039 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/items/auto_harvester.dm @@ -0,0 +1,19 @@ +//A harvest item for serviceborgs. +/obj/item/robot_harvester + name = "auto harvester" + desc = "A hand-held harvest tool that resembles a sickle. It uses energy to cut plant matter very efficently." + icon = 'icons/obj/weapons.dmi' + icon_state = "autoharvester" + hitsound = "swing_hit" + +/obj/item/robot_harvester/afterattack(var/atom/target, var/mob/living/user, proximity) + if(!target || !proximity) + return + if(istype(target, /obj/machinery/portable_atmospherics/hydroponics)) + var/obj/machinery/portable_atmospherics/hydroponics/T = target + if(T.harvest) //Try to harvest, assuming it's alive. + T.harvest(user) + else if(T.dead) //It's probably dead otherwise. + T.remove_dead(user) + else + to_chat(user, SPAN_WARNING("ERROR: Harvesting \a [target] is not the purpose of this tool. \The [src] is for plants being grown.")) \ No newline at end of file diff --git a/code/modules/mob/living/silicon/robot/items/electric_arm.dm b/code/modules/mob/living/silicon/robot/items/electric_arm.dm new file mode 100644 index 00000000000..381e016e54e --- /dev/null +++ b/code/modules/mob/living/silicon/robot/items/electric_arm.dm @@ -0,0 +1,24 @@ +/obj/item/borg/stun + name = "electrified arm" + icon = 'icons/obj/decals.dmi' + icon_state = "shock" + +/obj/item/borg/stun/apply_hit_effect(mob/living/M, mob/living/silicon/robot/user, var/hit_zone) + if(!istype(user)) + return FALSE + + user.visible_message(SPAN_DANGER("\The [user] has prodded \the [M] with \a [src]!"), SPAN_DANGER("You prod \the [M] with \the [src].")) + + if(!user.cell || !user.cell.checked_use(1250)) //Slightly more than a baton. + return FALSE + + playsound(loc, 'sound/weapons/Egloves.ogg', 50, 1, -1) + + M.apply_effect(5, STUTTER) + M.stun_effect_act(0, 70, check_zone(hit_zone), src) + + if(ishuman(M)) + var/mob/living/carbon/human/H = M + H.forcesay(hit_appends) + + return FALSE \ No newline at end of file diff --git a/code/modules/mob/living/silicon/robot/items/form_printer.dm b/code/modules/mob/living/silicon/robot/items/form_printer.dm new file mode 100644 index 00000000000..5e226da794f --- /dev/null +++ b/code/modules/mob/living/silicon/robot/items/form_printer.dm @@ -0,0 +1,22 @@ +//TODO: Add prewritten forms to dispense when you work out a good way to store the strings. +/obj/item/form_printer + name = "paper dispenser" + icon = 'icons/obj/bureaucracy.dmi' + icon_state = "paper_bin1" + item_state = "sheet-metal" + +/obj/item/form_printer/attack(mob/living/carbon/M, mob/living/carbon/user) + return + +/obj/item/form_printer/afterattack(atom/target, mob/living/user, flag, params) + if(!target || !flag) + return + if(istype(target,/obj/structure/table)) + deploy_paper(get_turf(target), user) + +/obj/item/form_printer/attack_self(mob/user) + deploy_paper(get_turf(src)) + +/obj/item/form_printer/proc/deploy_paper(var/turf/T, var/mob/user) + T.visible_message(SPAN_NOTICE("\The [user] dispenses a sheet of crisp white paper.")) + new /obj/item/paper(T) \ No newline at end of file diff --git a/code/modules/mob/living/silicon/robot/gripper.dm b/code/modules/mob/living/silicon/robot/items/gripper.dm similarity index 99% rename from code/modules/mob/living/silicon/robot/gripper.dm rename to code/modules/mob/living/silicon/robot/items/gripper.dm index 90969ce01b9..94e519e734e 100644 --- a/code/modules/mob/living/silicon/robot/gripper.dm +++ b/code/modules/mob/living/silicon/robot/items/gripper.dm @@ -282,4 +282,4 @@ can_hold = list( /obj/item/stack/material, /obj/item/stack/tile - ) + ) \ No newline at end of file diff --git a/code/modules/mob/living/silicon/robot/items/guns/ballistic_cannon.dm b/code/modules/mob/living/silicon/robot/items/guns/ballistic_cannon.dm new file mode 100644 index 00000000000..ba959e357f3 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/items/guns/ballistic_cannon.dm @@ -0,0 +1,15 @@ +/obj/item/gun/energy/mountedcannon + name = "mounted ballistic cannon" + desc = "A cyborg mounted ballistic cannon." + icon = 'icons/obj/robot_items.dmi' + icon_state = "cannon" + item_state = "cannon" + fire_sound = 'sound/effects/Explosion1.ogg' + charge_meter = FALSE + max_shots = 10 + charge_cost = 300 + projectile_type = /obj/item/projectile/bullet/gyro + self_recharge = TRUE + use_external_power = TRUE + recharge_time = 5 + needspin = FALSE \ No newline at end of file diff --git a/code/modules/mob/living/silicon/robot/items/inductive_charger.dm b/code/modules/mob/living/silicon/robot/items/inductive_charger.dm new file mode 100644 index 00000000000..4df1484a03c --- /dev/null +++ b/code/modules/mob/living/silicon/robot/items/inductive_charger.dm @@ -0,0 +1,84 @@ +/obj/item/inductive_charger + name = "inductive charger" + desc = "A phoron-enhanced induction charger hooked up to its attached stationbound's internal cell." + desc_fluff = "Harnessing the energy potential found in phoron structures, Nanotrasen engineers have created a portable device capable of highly efficient wireless charging. The expense and limit of energy output of using this method of charging prevents it from being used on a large scale, being far outclassed by Phoron-Supermatter charging systems." + desc_info = "Click on an adjacent object that contains or is a power cell to attempt to find and charge it. After a successful charge, the inductive charger recharge in a few minutes. The amount transfered can be adjusted by alt clicking it." + icon = 'icons/obj/robot_items.dmi' + icon_state = "inductive_charger" + var/ready_to_use = TRUE + var/recharge_time = 300 + var/transfer_rate = 5000 + var/efficiency_mod = 0.9 + maptext_x = 3 + maptext_y = 2 + +/obj/item/inductive_charger/Initialize() + . = ..() + maptext = "Ready" + +/obj/item/inductive_charger/AltClick(mob/user) + . = ..() + var/set_rate = input(user, "How much do you want to transfer per use? (Limit: 1 - 5000)", "Induction Transfer Rate", 5000) as num + if(set_rate > 5000) + set_rate = 5000 + else if(set_rate < 1) + set_rate = 1 + transfer_rate = set_rate + to_chat(user, SPAN_NOTICE("You set the transfer rate of \the [src] to [transfer_rate].")) + +/obj/item/inductive_charger/attack(mob/living/M, mob/living/user, target_zone) + return + +/obj/item/inductive_charger/afterattack(atom/target, mob/user, proximity_flag, click_parameters) + var/mob/living/silicon/robot/R = user + if(!istype(R)) + to_chat(user, SPAN_WARNING("Only cyborgs can use this!")) + return + if(!ready_to_use) + to_chat(user, SPAN_WARNING("\The [src] is still gathering charge!")) + return + + user.visible_message("[user] begins waving \the [src] around \the [target]...", SPAN_NOTICE("You prepare to wirelessly charge \the [target]..."), range = 3) + if(!do_after(user, 50, TRUE, target)) + return + if(R.cell.charge < 1000) + to_chat(user, SPAN_WARNING("You have no spare charge in your internal cell to give!")) + return + + if(isipc(target)) + var/mob/living/carbon/human/IPC = target + if(IPC.nutrition == IPC.max_nutrition) + to_chat(user, SPAN_WARNING("\The [IPC] is already fully charged!")) + return + var/charge_amount = min(IPC.max_nutrition - IPC.nutrition, transfer_rate) + var/charge_value = R.cell.use(charge_amount / efficiency_mod) * efficiency_mod + IPC.nutrition = min(IPC.max_nutrition, charge_value) + message_and_use(user, "[user] holds \the [src] over \the [IPC], topping up their battery.", SPAN_NOTICE("You wirelessly transmit [charge_value] units of power to \the [IPC], using [charge_value / efficiency_mod] of internal cell power.")) + else if(isobj(target)) + var/obj/item/cell/C + if(istype(target, /obj/item/cell)) + C = target + else + C = locate() in target + if(!C) + to_chat(user, SPAN_WARNING("\The [target] doesn't contain a cell, or it's buried too deep for you to reach!")) + return + if(C.fully_charged()) + to_chat(user, SPAN_WARNING("\The [C] is already fully charged!")) + return + var/charge_amount = min(C.maxcharge - C.charge, transfer_rate) + var/charge_value = R.cell.use(charge_amount / efficiency_mod) * efficiency_mod + C.give(charge_value) + message_and_use(user, "[user] holds \the [src] over \the [target], topping up its battery.", SPAN_NOTICE("You wirelessly transmit [charge_value] units of power to \the [target], using [charge_value / efficiency_mod] of internal cell power.")) + else + to_chat(user, SPAN_WARNING("\The [src] cannot be used on \the [target]!")) + +/obj/item/inductive_charger/proc/message_and_use(mob/user, var/others_message, var/self_message) + user.visible_message(others_message, self_message, range = 3) + addtimer(CALLBACK(src, .proc/recharge), recharge_time) + ready_to_use = FALSE + maptext = "Charge" + +/obj/item/inductive_charger/proc/recharge() + ready_to_use = TRUE + maptext = "Ready" \ No newline at end of file diff --git a/code/modules/mob/living/silicon/robot/items/modules/mobility_module.dm b/code/modules/mob/living/silicon/robot/items/modules/mobility_module.dm new file mode 100644 index 00000000000..ee09a226635 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/items/modules/mobility_module.dm @@ -0,0 +1,13 @@ +/obj/item/borg/combat/mobility + name = "mobility module" + desc = "By retracting limbs and tucking in its head, a combat android can roll at high speeds." + icon = 'icons/obj/decals.dmi' + icon_state = "shock" + +/obj/item/borg/combat/mobility/on_module_activate(mob/living/silicon/robot/R) + R.icon_state = "[R.module_sprites[R.icontype]]-roll" + R.speed = -2 + +/obj/item/borg/combat/mobility/on_module_deactivate(mob/living/silicon/robot/R) + R.icon_state = R.module_sprites[R.icontype] + R.speed = initial(R.speed) \ No newline at end of file diff --git a/code/modules/mob/living/silicon/robot/items/modules/robot_shield.dm b/code/modules/mob/living/silicon/robot/items/modules/robot_shield.dm new file mode 100644 index 00000000000..bc951635477 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/items/modules/robot_shield.dm @@ -0,0 +1,24 @@ +//Personal shielding for the combat module. +/obj/item/borg/combat/shield + name = "personal shielding" + desc = "A powerful experimental module that turns aside or absorbs incoming attacks at the cost of charge." + icon = 'icons/obj/device.dmi' + icon_state = "shield1" //placeholder for now // four fucking years alberyk. FOUR + var/shield_level = 0.5 //Percentage of damage absorbed by the shield. + var/image/shield_overlay + +/obj/item/borg/combat/shield/on_module_activate(mob/living/silicon/robot/R) + shield_overlay = image(R.icon, "[R.module_sprites[R.icontype]]-shield") + R.add_overlay(shield_overlay) + +/obj/item/borg/combat/shield/on_module_deactivate(mob/living/silicon/robot/R) + R.cut_overlay(shield_overlay) + +/obj/item/borg/combat/shield/verb/set_shield_level() + set name = "Set shield level" + set category = "Object" + set src in range(0) + + var/N = input(usr, "How much damage should the shield absorb?") in list("5", "10", "25", "50", "75", "100") + if(N) + shield_level = text2num(N)/100 \ No newline at end of file diff --git a/code/modules/mob/living/silicon/robot/items/modules/sight.dm b/code/modules/mob/living/silicon/robot/items/modules/sight.dm new file mode 100644 index 00000000000..c7d7d09dfdd --- /dev/null +++ b/code/modules/mob/living/silicon/robot/items/modules/sight.dm @@ -0,0 +1,54 @@ +/obj/item/borg/sight + icon = 'icons/obj/decals.dmi' + icon_state = "securearea" + var/sight_mode = null + +/obj/item/borg/sight/on_module_hotbar(mob/living/silicon/robot/R) + R.sight_mode |= sight_mode + +/obj/item/borg/sight/on_module_store(mob/living/silicon/robot/R) + R.sight_mode &= ~sight_mode + +/obj/item/borg/sight/xray + name = "\proper x-ray vision" + sight_mode = BORGXRAY + +/obj/item/borg/sight/thermal + name = "\proper thermal vision" + desc_antag = "Having this device on your hotbar will allow you to see in enhanced thermal vision, which allows you to see heat signatures through solid walls." + sight_mode = BORGTHERM + icon_state = "thermal" + icon = 'icons/obj/clothing/glasses.dmi' + +/obj/item/borg/sight/meson + name = "\proper meson vision" + sight_mode = BORGMESON + icon_state = "meson" + icon = 'icons/obj/clothing/glasses.dmi' + +/obj/item/borg/sight/material + name = "\proper material scanner vision" + sight_mode = BORGMATERIAL + +/obj/item/borg/sight/hud + name = "hud" + var/obj/item/clothing/glasses/hud/hud = null + + +/obj/item/borg/sight/hud/med + name = "medical hud" + icon_state = "healthhud" + icon = 'icons/obj/clothing/glasses.dmi' + +/obj/item/borg/sight/hud/med/Initialize(mapload, ...) + . = ..() + hud = new /obj/item/clothing/glasses/hud/health(src) + +/obj/item/borg/sight/hud/sec + name = "security hud" + icon_state = "securityhud" + icon = 'icons/obj/clothing/glasses.dmi' + +/obj/item/borg/sight/hud/sec/Initialize(mapload, ...) + . = ..() + hud = new /obj/item/clothing/glasses/hud/security(src) \ No newline at end of file diff --git a/code/modules/mob/living/silicon/robot/items/overdrive.dm b/code/modules/mob/living/silicon/robot/items/overdrive.dm new file mode 100644 index 00000000000..d9335ba01b9 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/items/overdrive.dm @@ -0,0 +1,4 @@ +/obj/item/borg/overdrive + name = "overdrive" + icon = 'icons/obj/decals.dmi' + icon_state = "shock" \ No newline at end of file diff --git a/code/modules/mob/living/silicon/robot/items/portable_destructive_analyzer.dm b/code/modules/mob/living/silicon/robot/items/portable_destructive_analyzer.dm new file mode 100644 index 00000000000..a670384f2b8 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/items/portable_destructive_analyzer.dm @@ -0,0 +1,103 @@ +//A portable analyzer, for research borgs. This is better then giving them a gripper which can hold anything and letting them use the normal analyzer. +/obj/item/portable_destructive_analyzer + name = "Portable Destructive Analyzer" + desc = "Similar to the stationary version, this rather unwieldy device allows you to break down objects in the name of science." + icon = 'icons/obj/robot_items.dmi' + icon_state = "portable_analyzer" + + var/min_reliability = 90 //Can't upgrade, call it laziness or a drawback + + var/datum/research/techonly/files //The device uses the same datum structure as the R&D computer/server. + //This analyzer can only store tech levels, however. + + var/obj/item/loaded_item //What is currently inside the analyzer. + +/obj/item/portable_destructive_analyzer/Initialize() + . = ..() + files = new /datum/research/techonly(src) //Setup the research data holder. + +/obj/item/portable_destructive_analyzer/examine(mob/user, distance) + . = ..() + if(loaded_item && Adjacent(user)) + to_chat(user, SPAN_NOTICE("It is holding \a [loaded_item].")) + +/obj/item/portable_destructive_analyzer/attack_self(mob/user) + var/response = alert(user, "Analyzing the item inside will *DESTROY* the item for good.\n\ + Syncing to the research server will send the data that is stored inside to research.\n\ + Ejecting will place the loaded item onto the floor.", + "What would you like to do?", "Analyze", "Sync", "Eject") + if(response == "Analyze") + if(loaded_item) + var/confirm = alert(user, "This will destroy the item inside forever. Are you sure?", "Confirm Analyze", "Yes", "No") + if(confirm == "Yes") //This is pretty copypasta-y + to_chat(user, SPAN_NOTICE("You activate the analyzer's microlaser, analyzing \the [loaded_item] and breaking it down.")) + flick("portable_analyzer_scan", src) + playsound(src.loc, 'sound/items/Welder2.ogg', 50, 1) + for(var/T in loaded_item.origin_tech) + files.UpdateTech(T, loaded_item.origin_tech[T]) + to_chat(user, SPAN_NOTICE("\The [loaded_item] had level [loaded_item.origin_tech[T]] in [CallTechName(T)].")) + loaded_item = null + for(var/obj/I in contents) + for(var/mob/M in I.contents) + M.death() + if(istype(I,/obj/item/stack/material)) //Only deconstructs one sheet at a time instead of the entire stack + var/obj/item/stack/material/S = I + if(S.get_amount() > 1) + S.use(1) + loaded_item = S + else + qdel(S) + icon_state = initial(icon_state) + else + qdel(I) + icon_state = initial(icon_state) + else + return + else + to_chat(user, SPAN_WARNING("\The [src] is empty. Put something inside it first.")) + if(response == "Sync") + var/success = FALSE + for(var/obj/machinery/r_n_d/server/S in SSmachinery.all_machines) + for(var/datum/tech/T in files.known_tech) //Uploading + S.files.AddTech2Known(T) + for(var/datum/tech/T in S.files.known_tech) //Downloading + files.AddTech2Known(T) + success = TRUE + files.RefreshResearch() + if(success) + to_chat(user, SPAN_NOTICE("You connect to the research server, push your data upstream to it, then pull the resulting merged data from the master branch.")) // fucking nerds + playsound(get_turf(src), 'sound/machines/twobeep.ogg', 50, TRUE) + else + to_chat(user, SPAN_WARNING("Research server ping response timed out. Unable to connect. Please contact the system administrator.")) + playsound(get_turf(src), 'sound/machines/buzz-two.ogg', 50, 1) + if(response == "Eject") + if(loaded_item) + loaded_item.forceMove(get_turf(src)) + icon_state = initial(icon_state) + loaded_item = null + else + to_chat(user, SPAN_WARNING("\The [src] is already empty.")) + + +/obj/item/portable_destructive_analyzer/afterattack(var/atom/target, var/mob/living/user, proximity) + if(!target || !proximity || !isturf(target.loc)) + return + if(loaded_item) + to_chat(user, SPAN_WARNING("Your [src] already has something inside. Analyze or eject it first.")) + return + if(istype(target,/obj/item)) + var/obj/item/I = target + if(I.anchored) + to_chat(user, span("notice", "\The [I] is anchored in place.")) + return + if(!I.origin_tech) + to_chat(user, SPAN_NOTICE("This doesn't seem to have a tech origin.")) + return + if(!length(I.origin_tech)) + to_chat(user, SPAN_NOTICE("You cannot deconstruct this item.")) + return + I.forceMove(src) + loaded_item = I + visible_message(SPAN_NOTICE("\The [user] scoops \the [I] into \the [src].")) + flick("portable_analyzer_load", src) + icon_state = "portable_analyzer_full" \ No newline at end of file diff --git a/code/modules/mob/living/silicon/robot/items/robot_id.dm b/code/modules/mob/living/silicon/robot/items/robot_id.dm new file mode 100644 index 00000000000..29e78bac0be --- /dev/null +++ b/code/modules/mob/living/silicon/robot/items/robot_id.dm @@ -0,0 +1,6 @@ +//This is used to unlock other borg covers. +/obj/item/card/robot //This is not a child of id cards, as to avoid dumb typechecks on computers. + name = "access code transmission device" + icon_state = "id-robot" + desc = "A circuit grafted onto the bottom of an ID card. It is used to transmit access codes into other robot chassis, \ + allowing you to lock and unlock other robots' panels." \ No newline at end of file diff --git a/code/modules/mob/living/silicon/robot/items/robot_inflatables.dm b/code/modules/mob/living/silicon/robot/items/robot_inflatables.dm new file mode 100644 index 00000000000..e8ab2172e44 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/items/robot_inflatables.dm @@ -0,0 +1,119 @@ +#define MODE_WALL 0 +#define MODE_DOOR 1 + +/obj/item/inflatable_dispenser + name = "inflatables dispenser" + desc = "Small device which allows rapid deployment and removal of inflatables." + icon = 'icons/obj/storage.dmi' + icon_state = "inf_deployer" + w_class = ITEMSIZE_NORMAL + var/deploying = FALSE + var/max_walls = 10 + var/max_doors = 5 + var/stored_walls = 10 + var/stored_doors = 5 + var/mode = MODE_WALL // 0 - Walls 1 - Doors + +/obj/item/inflatable_dispenser/Initialize(mapload, ...) + . = ..() + stored_walls = max_walls + stored_doors = max_doors + +/obj/item/inflatable_dispenser/examine(mob/user) + if(!..(user)) + return + to_chat(user, SPAN_NOTICE("It has [stored_walls] wall segment\s and [stored_doors] door segment\s stored.")) + to_chat(user, SPAN_NOTICE("It is set to deploy [mode ? "doors" : "walls"]")) + +/obj/item/inflatable_dispenser/attack_self(mob/user) + if(!deploying) + mode = !mode + to_chat(user, SPAN_NOTICE("You set \the [src] to deploy [mode ? "doors" : "walls"].")) + else + to_chat(user, SPAN_WARNING("You can't switch modes while deploying a [mode ? "door" : "wall"]!")) + +/obj/item/inflatable_dispenser/afterattack(var/atom/A, var/mob/user) + ..(A, user) + if(!user) + return + if(!user.Adjacent(A)) + to_chat(user, SPAN_WARNING("You can't reach!")) + return + if(istype(A, /turf)) + try_deploy_inflatable(A, user) + if(istype(A, /obj/item/inflatable) || istype(A, /obj/structure/inflatable)) + pick_up(A, user) + +/obj/item/inflatable_dispenser/proc/try_deploy_inflatable(var/turf/T, var/mob/living/user) + if(deploying) + return + + var/newtype + if(mode) // Door deployment + if(!stored_doors) + to_chat(user, SPAN_WARNING("\The [src] is out of doors!")) + return + if(T && istype(T)) + newtype = /obj/structure/inflatable/door + + else // Wall deployment + if(!stored_walls) + to_chat(user, SPAN_WARNING("\The [src] is out of walls!")) + return + + if(T && istype(T)) + newtype = /obj/structure/inflatable/wall + + deploying = 1 + user.visible_message("[user] starts deploying an inflatable [mode ? "door" : "wall"].", SPAN_NOTICE("You start deploying an inflatable [mode ? "door" : "wall"]!")) + playsound(T, 'sound/items/zip.ogg', 75, TRUE) + if(do_after(user, 30, needhand = FALSE)) + new newtype(T) + if(mode) + stored_doors-- + else + stored_walls-- + deploying = FALSE + +/obj/item/inflatable_dispenser/proc/pick_up(var/obj/A, var/mob/living/user) + if(istype(A, /obj/structure/inflatable)) + if(istype(A, /obj/structure/inflatable/wall)) + if(stored_walls >= max_walls) + to_chat(user, SPAN_WARNING("\The [src] is full.")) + return + stored_walls++ + qdel(A) + else + if(stored_doors >= max_doors) + to_chat(user, SPAN_WARNING("\The [src] is full.")) + return + stored_doors++ + qdel(A) + playsound(get_turf(src), 'sound/machines/hiss.ogg', 75, TRUE) + visible_message("[user] deflates \the [A] with \the [src].", SPAN_NOTICE("You deinflate \the [A] with \the [src].")) + return + else if(istype(A, /obj/item/inflatable)) + if(istype(A, /obj/item/inflatable/wall)) + if(stored_walls >= max_walls) + to_chat(user, SPAN_WARNING("\The [src] is full.")) + return + stored_walls++ + qdel(A) + else + if(stored_doors >= max_doors) + to_chat(usr, SPAN_WARNING("\The [src] is full!")) + return + stored_doors++ + qdel(A) + visible_message("[user] picks up \the [A] with \the [src].", SPAN_NOTICE("You pick up \the [A] with \the [src].")) + return + + to_chat(user, SPAN_WARNING("You fail to pick up \the [A] with \the [src].")) + return + +/obj/item/inflatable_dispenser/borg + max_walls = 5 + max_doors = 3 + +#undef MODE_WALL +#undef MODE_DOOR \ No newline at end of file diff --git a/code/modules/mob/living/silicon/robot/items/robot_parts.dm b/code/modules/mob/living/silicon/robot/items/robot_parts.dm new file mode 100644 index 00000000000..1563acc22c5 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/items/robot_parts.dm @@ -0,0 +1,429 @@ +/obj/item/robot_parts + name = "robot parts" + icon = 'icons/obj/robot_parts.dmi' + item_state = "buildpipe" + icon_state = "blank" + flags = CONDUCT + slot_flags = SLOT_BELT + var/list/part = null // Order of args is important for installing robolimbs. + var/sabotaged = 0 //Emagging limbs can have repercussions when installed as prosthetics. + var/model_info + var/linked_frame = "Unbranded Frame" + dir = SOUTH + +/obj/item/robot_parts/set_dir() + return + +/obj/item/robot_parts/New(var/newloc, var/model) + ..(newloc) + if(model_info && model) + model_info = model + var/datum/robolimb/R = all_robolimbs[model] + if(R) + name = "[R.company] robot [initial(name)]" + desc = "[R.desc]" + linked_frame = R.linked_frame + if(icon_state in icon_states(R.icon)) + icon = R.icon + else + name = "robot [initial(name)]" + +/obj/item/robot_parts/examine(mob/user, distance) + . = ..() + if(Adjacent(user)) + report_missing_parts(user) + +/obj/item/robot_parts/proc/report_missing_parts(var/mob/user) + return + +/obj/item/robot_parts/l_arm + name = "left arm" + desc = "A skeletal limb wrapped in pseudomuscles, with a low-conductivity case." + icon_state = "l_arm" + part = list(BP_L_ARM, BP_L_HAND) + model_info = TRUE + +/obj/item/robot_parts/r_arm + name = "right arm" + desc = "A skeletal limb wrapped in pseudomuscles, with a low-conductivity case." + icon_state = "r_arm" + part = list(BP_R_ARM, BP_R_HAND) + model_info = TRUE + +/obj/item/robot_parts/l_leg + name = "left leg" + desc = "A skeletal limb wrapped in pseudomuscles, with a low-conductivity case." + icon_state = "l_leg" + part = list(BP_L_LEG, BP_L_FOOT) + model_info = TRUE + +/obj/item/robot_parts/r_leg + name = "right leg" + desc = "A skeletal limb wrapped in pseudomuscles, with a low-conductivity case." + icon_state = "r_leg" + part = list(BP_R_LEG, BP_R_FOOT) + model_info = TRUE + +/obj/item/robot_parts/chest + name = "torso" + desc = "A heavily reinforced case containing cyborg logic boards, with space for a standard power cell." + icon_state = "chest" + part = list(BP_GROIN, BP_CHEST) + var/wires = 0 + var/obj/item/cell/cell = null + +/obj/item/robot_parts/head + name = "head" + desc = "A standard reinforced braincase, with spine-plugged neural socket and sensor gimbals." + icon_state = "head" + part = list(BP_HEAD) + var/obj/item/device/flash/left_flash = null + var/obj/item/device/flash/right_flash = null + var/law_manager = TRUE + +/obj/item/robot_parts/robot_suit + name = "endoskeleton" + desc = "A complex metal backbone with standard limb sockets and pseudomuscle anchors." + icon_state = "robo_suit" + var/obj/item/robot_parts/l_arm/l_arm = null + var/obj/item/robot_parts/r_arm/r_arm = null + var/obj/item/robot_parts/l_leg/l_leg = null + var/obj/item/robot_parts/r_leg/r_leg = null + var/obj/item/robot_parts/chest/chest = null + var/obj/item/robot_parts/head/head = null + var/created_name = "" + +/obj/item/robot_parts/robot_suit/Initialize() + . = ..() + updateicon() + +/obj/item/robot_parts/robot_suit/report_missing_parts(var/mob/user) + if(!head) + to_chat(user, FONT_SMALL(SPAN_WARNING("It is lacking a functional head."))) + if(!chest) + to_chat(user, FONT_SMALL(SPAN_WARNING("It is lacking a functional chest."))) + if(!l_arm) + to_chat(user, FONT_SMALL(SPAN_WARNING("It is lacking a functional left arm."))) + if(!r_arm) + to_chat(user, FONT_SMALL(SPAN_WARNING("It is lacking a functional right arm."))) + if(!l_leg) + to_chat(user, FONT_SMALL(SPAN_WARNING("It is lacking a functional left leg."))) + if(!r_leg) + to_chat(user, FONT_SMALL(SPAN_WARNING("It is lacking a functional right leg."))) + +/obj/item/robot_parts/robot_suit/equipped/Initialize() + . = ..() + l_leg = new /obj/item/robot_parts/l_leg(src) + r_leg = new /obj/item/robot_parts/r_leg(src) + l_arm = new /obj/item/robot_parts/l_arm(src) + r_arm = new /obj/item/robot_parts/r_arm(src) + updateicon() + +/obj/item/robot_parts/robot_suit/proc/updateicon() + cut_overlays() + if(l_arm) + add_overlay("l_arm+o") + if(r_arm) + add_overlay("r_arm+o") + if(chest) + add_overlay("chest+o") + if(l_leg) + add_overlay("l_leg+o") + if(r_leg) + add_overlay("r_leg+o") + if(head) + add_overlay("head+o") + +/obj/item/robot_parts/robot_suit/proc/check_completion() + if(l_arm && r_arm) + if(l_leg && r_leg) + if(chest && head) + feedback_inc("cyborg_frames_built",1) + return TRUE + return FALSE + +/obj/item/robot_parts/robot_suit/attackby(obj/item/W, mob/user) + if(istype(W, /obj/item/stack/material) && W.get_material_name() == DEFAULT_WALL_MATERIAL && !l_arm && !r_arm && !l_leg && !r_leg && !chest && !head) + var/obj/item/stack/material/M = W + if(M.use(1)) + var/obj/item/secbot_assembly/ed209_assembly/B = new /obj/item/secbot_assembly/ed209_assembly + B.forceMove(get_turf(src)) + to_chat(user, SPAN_NOTICE("You armed the robot frame.")) + if(user.get_inactive_hand() == src) + user.remove_from_mob(src) + user.put_in_inactive_hand(B) + qdel(src) + else + to_chat(user, SPAN_WARNING("You need one sheet of metal to arm the robot frame.")) + return + + if(istype(W, /obj/item/robot_parts/l_leg)) + if(l_leg) + to_chat(user, SPAN_WARNING("\The [src] already has \a [l_leg] installed.")) + return + user.drop_from_inventory(W, src) + l_leg = W + updateicon() + return + + if(istype(W, /obj/item/robot_parts/r_leg)) + if(r_leg) + to_chat(user, SPAN_WARNING("\The [src] already has \a [r_leg] installed.")) + return + user.drop_from_inventory(W, src) + r_leg = W + updateicon() + return + + if(istype(W, /obj/item/robot_parts/l_arm)) + if(l_arm) + to_chat(user, SPAN_WARNING("\The [src] already has \a [l_arm] installed.")) + return + user.drop_from_inventory(W, src) + l_arm = W + updateicon() + return + + if(istype(W, /obj/item/robot_parts/r_arm)) + if(r_arm) + to_chat(user, SPAN_WARNING("\The [src] already has \a [r_arm] installed.")) + return + user.drop_from_inventory(W, src) + r_arm = W + updateicon() + return + + if(istype(W, /obj/item/robot_parts/chest)) + if(chest) + to_chat(user, SPAN_WARNING("\The [src] already has \a [chest] installed.")) + return + var/obj/item/robot_parts/chest/C = W + if(C.wires && C.cell) + user.drop_from_inventory(W, src) + chest = W + updateicon() + else if(!C.wires) + to_chat(user, SPAN_WARNING("You need to attach wires to it first!")) + else + to_chat(user, SPAN_WARNING("You need to attach a cell to it first!")) + return + + if(istype(W, /obj/item/robot_parts/head)) + if(head) + to_chat(user, SPAN_WARNING("\The [src] already has \a [head] installed.")) + return + var/obj/item/robot_parts/head/H = W + if(H.right_flash && H.left_flash) + user.drop_from_inventory(W, src) + head = W + updateicon() + else + to_chat(user, SPAN_WARNING("You need to attach a flash to it first!")) + return + + if(istype(W, /obj/item/device/mmi)) + var/obj/item/device/mmi/M = W + if(check_completion()) + if(!istype(loc, /turf)) + to_chat(user, SPAN_WARNING("You can't put \the [W] in, the frame has to be standing on the ground to be perfectly precise.")) + return + if(!M.brainmob) + to_chat(user, SPAN_WARNING("\The [M] is empty!")) + return + if(!M.brainmob.key) + var/ghost_can_reenter = FALSE + if(M.brainmob.mind) + for(var/mob/abstract/observer/G in player_list) + if(G.can_reenter_corpse && G.mind == M.brainmob.mind) + ghost_can_reenter = TRUE + break + if(!ghost_can_reenter) + to_chat(user, SPAN_WARNING("\The [W] is completely unresponsive.")) + return + + if(M.brainmob.stat == DEAD) + to_chat(user, SPAN_WARNING("\The [M] is dead.")) + return + + if(!head.law_manager) + if(!is_alien_whitelisted(M.brainmob, "Baseline Frame") && config.usealienwhitelist) + to_chat(user, SPAN_WARNING("\The [W] does not seem to fit. (The player lacks the appropriate whitelist.)")) + return + + var/mob/living/carbon/human/new_shell = new(get_turf(src), chest.linked_frame) + forceMove(new_shell) //so people won't mess around with the chassis until it is deleted + M.brainmob.mind.transfer_to(new_shell) + qdel(M) + var/newname = sanitizeSafe(input(new_shell, "Enter a name, or leave blank for the default name.", "Name change","") as text, MAX_NAME_LEN) + if(!newname) + var/datum/language/L = all_languages[new_shell.species.default_language] + newname = L.get_random_name() + new_shell.real_name = newname + new_shell.name = new_shell.real_name + new_shell.change_appearance(APPEARANCE_ALL_HAIR | APPEARANCE_SKIN | APPEARANCE_EYE_COLOR, new_shell.loc, new_shell) + qdel(src) + return + + else + if(jobban_isbanned(M.brainmob, "Cyborg")) + to_chat(user, SPAN_WARNING("\The [W] does not seem to fit. (The player has been banned from playing this role)")) + return + + var/mob/living/silicon/robot/O = new /mob/living/silicon/robot(get_turf(src), TRUE) + if(!O) + return + + user.drop_from_inventory(M, O) + O.mmi = W + O.invisibility = 0 + O.custom_name = created_name + O.updatename("Default") + + M.brainmob.mind.transfer_to(O) + + O.job = "Cyborg" + O.cell = chest.cell + O.cell.forceMove(O) + W.forceMove(O) //Should fix cybros run time erroring when blown up. It got deleted before, along with the frame. + + // Since we "magically" installed a cell, we also have to update the correct component. + if(O.cell) + var/datum/robot_component/cell_component = O.components["power cell"] + cell_component.wrapped = O.cell + cell_component.installed = TRUE + + feedback_inc("cyborg_birth", 1) + callHook("borgify", list(O)) + O.Namepick() + qdel(src) + else + to_chat(user, SPAN_WARNING("\The [W] can only be inserted after everything else is installed.")) + return + + if(W.ispen()) + var/t = sanitizeSafe(input(user, "Enter new robot name", name, created_name), MAX_NAME_LEN) + if(!t) + return + if(!in_range(src, usr) && loc != usr) + return + created_name = t + return + + return ..() + +/obj/item/robot_parts/chest/report_missing_parts(var/mob/user) + if(!cell) + to_chat(user, FONT_SMALL(SPAN_WARNING("It is lacking a functional cell."))) + if(!wires) + to_chat(user, FONT_SMALL(SPAN_WARNING("It is lacking wiring."))) + +/obj/item/robot_parts/chest/attackby(obj/item/W, mob/user) + if(istype(W, /obj/item/cell)) + if(cell) + to_chat(user, SPAN_WARNING("\The [src] already has \a [cell] inserted.")) + return + else + user.drop_from_inventory(W, src) + cell = W + to_chat(user, SPAN_NOTICE("You insert \the [src].")) + return + if(W.iscoil()) + if(wires) + to_chat(user, SPAN_WARNING("\The [src] is already wired up correctly.")) + return + else + var/obj/item/stack/cable_coil/coil = W + coil.use(1) + wires = TRUE + to_chat(user, SPAN_NOTICE("You wire up \the [src].")) + return + return ..() + +/obj/item/robot_parts/head/report_missing_parts(var/mob/user) + var/law_manager_msg = "Its lawing circuits are [law_manager ? "enabled" : "disabled"]." + to_chat(user, SPAN_NOTICE(law_manager_msg)) + if(!left_flash) + to_chat(user, FONT_SMALL(SPAN_WARNING("It is lacking its left flash."))) + if(!right_flash) + to_chat(user, FONT_SMALL(SPAN_WARNING("It is lacking its right flash."))) + +/obj/item/robot_parts/head/attackby(obj/item/W as obj, mob/user as mob) + ..() + if(W.ismultitool()) + if(law_manager) + to_chat(user, SPAN_NOTICE("You disable the lawing circuits on \the [src].")) + law_manager = FALSE + else + to_chat(user, SPAN_NOTICE("You enable the lawing circuits on \the [src].")) + law_manager = TRUE + + if(istype(W, /obj/item/device/flash)) + if(istype(user, /mob/living/silicon/robot)) + var/current_module = user.get_active_hand() + if(current_module == W) + to_chat(user, SPAN_WARNING("You cannot detach your own flash and install it into \the [src].")) + return + else + add_flashes(W,user) + else + add_flashes(W,user) + else if(istype(W, /obj/item/stock_parts/manipulator)) + to_chat(user, SPAN_NOTICE("You install some manipulators and modify the head, creating a functional spider-bot!")) + new /mob/living/simple_animal/spiderbot(get_turf(src)) + user.drop_from_inventory(W, get_turf(user)) + qdel(W) + qdel(src) + return + return + +/obj/item/robot_parts/head/proc/add_flashes(obj/item/W, mob/user) //Made into a seperate proc to avoid copypasta + if(left_flash && right_flash) + to_chat(user, SPAN_WARNING("\The [src] already has both its flashes installed.")) + return + else if(left_flash) + user.drop_from_inventory(W, src) + right_flash = W + to_chat(user, SPAN_NOTICE("You install the flash into the left socket.")) + else + user.drop_from_inventory(W, src) + left_flash = W + to_chat(user, SPAN_NOTICE("You install the flash into the right socket.")) + +/obj/item/robot_parts/emag_act(var/remaining_charges, var/mob/user) + if(sabotaged) + to_chat(user, SPAN_WARNING("\The [src] is already sabotaged!")) + else + to_chat(user, SPAN_NOTICE("You short out \the [src]'s safeties.")) + sabotaged = TRUE + return TRUE + +//branded chest, to be used in ipc ressurection + +/obj/item/robot_parts/chest/bishop + name = "Bishop cybernetics torso" + model_info = TRUE + linked_frame = "Bishop Accessory Frame" + +/obj/item/robot_parts/chest/hephaestus + name = "Hephaestus industries torso" + linked_frame = "Hephaestus G2 Industrial Frame" + +/obj/item/robot_parts/chest/zenghu + name = "Zeng-Hu pharmaceuticals torso" + linked_frame = "Zeng-Hu Mobility Frame" + +/obj/item/robot_parts/chest/synthskin + name = "Human synthskin torso" + linked_frame = "Shell Frame" + +/obj/item/robot_parts/chest/xion + name = "Xion manufacturing group torso" + linked_frame = "Xion Industrial Frame" + +/obj/item/robot_parts/chest/ipc + name = "Hephaestus integrated torso" + linked_frame = "Baseline Frame" + +/obj/item/robot_parts/chest/industrial + name = "Hephaestus industrial torso" + linked_frame = "Hephaestus G1 Industrial Frame" \ No newline at end of file diff --git a/code/modules/mob/living/silicon/robot/items/robot_pen.dm b/code/modules/mob/living/silicon/robot/items/robot_pen.dm new file mode 100644 index 00000000000..f472023112e --- /dev/null +++ b/code/modules/mob/living/silicon/robot/items/robot_pen.dm @@ -0,0 +1,39 @@ +#define WRITE_PAPER 0 +#define RENAME_PAPER 1 + +// A special pen for service droids. Can be toggled to switch between normal writting mode, and paper rename mode +// Allows service droids to rename paper items. +/obj/item/pen/robopen + desc = "A black ink printing attachment with a paper naming mode." + name = "Printing Pen" + var/mode = WRITE_PAPER + +/obj/item/pen/robopen/attack_self(mob/user) + var/choice = input(user, "Would you like to change colour or mode?", "Pen Selector") as null|anything in list("Colour", "Mode") + if(!choice) + return + + playsound(get_turf(src), 'sound/effects/pop.ogg', 50, 0) + + switch(choice) + if("Colour") + var/newcolour = input(user, "Which colour would you like to use?", "Colour Selector") as null|anything in list("black", "blue", "red", "green", "yellow") + if(newcolour) + colour = newcolour + if("Mode") + mode = !mode + to_chat(user, SPAN_NOTICE("Changed printing mode to '[mode == RENAME_PAPER ? "Rename Paper" : "Write Paper"]'")) + +/obj/item/pen/robopen/proc/RenamePaper(var/mob/user, var/obj/paper) + if(!user || !paper) + return + var/n_name = sanitizeSafe(input(user, "What would you like to label the paper?", "Paper Labelling") as text, 32) + if(!user || !paper) + return + + if((get_dist(user,paper) <= 1 && !user.stat)) + paper.name = "[initial(paper.name)] ([n_name])" + add_fingerprint(user) + +#undef WRITE_PAPER +#undef RENAME_PAPER \ No newline at end of file diff --git a/code/modules/mob/living/silicon/robot/items/robot_tools.dm b/code/modules/mob/living/silicon/robot/items/robot_tools.dm new file mode 100644 index 00000000000..1e16bb53e9e --- /dev/null +++ b/code/modules/mob/living/silicon/robot/items/robot_tools.dm @@ -0,0 +1,26 @@ +/obj/item/crowbar/robotic + icon = 'icons/obj/robot_items.dmi' + +/obj/item/wrench/robotic + icon = 'icons/obj/robot_items.dmi' + +/obj/item/screwdriver/robotic + icon = 'icons/obj/robot_items.dmi' + icon_state = "screwdriver" + build_from_parts = FALSE + +/obj/item/device/multitool/robotic + icon = 'icons/obj/robot_items.dmi' + +/obj/item/wirecutters/robotic + icon = 'icons/obj/robot_items.dmi' + icon_state = "wirecutters" + build_from_parts = FALSE + +/obj/item/weldingtool/robotic + icon = 'icons/obj/robot_items.dmi' + +/obj/item/soap/drone + name = "integrated soap" + desc = "An advanced bar of soap that connects to an internal reservoir of a custodial bot, allowing it to stay wet for longer periods of time." + capacity = 50 \ No newline at end of file diff --git a/code/modules/mob/living/silicon/robot/items/robot_tray.dm b/code/modules/mob/living/silicon/robot/items/robot_tray.dm new file mode 100644 index 00000000000..9028aa0e8c4 --- /dev/null +++ b/code/modules/mob/living/silicon/robot/items/robot_tray.dm @@ -0,0 +1,27 @@ +// A special tray for the service droid. Allow droid to pick up and drop items as if they were using the tray normally +// Click on table to unload, click on item to load. Alt+click to load everything on tile +/obj/item/tray/robotray + name = "RoboTray" + desc = "An autoloading tray specialized for carrying refreshments." + +/obj/item/tray/robotray/afterattack(atom/target, mob/user, proximity) + if(isturf(target) || istype(target,/obj/structure/table) ) + var foundtable = istype(target,/obj/structure/table/) + if(!foundtable) //it must be a turf! + for(var/obj/structure/table/T in target) + foundtable = TRUE + break + var/turf/dropspot + if(!foundtable) // don't unload things onto walls or other silly places. + dropspot = get_turf(user) + else if ( isturf(target) ) // they clicked on a turf with a table in it + dropspot = target + else // they clicked on a table + dropspot = get_turf(target) + if(foundtable) + unload_at_loc(dropspot, src) + else + spill(user,dropspot) + current_weight = 0 + + return ..() \ No newline at end of file diff --git a/code/game/objects/items/robot/robot_upgrades.dm b/code/modules/mob/living/silicon/robot/items/upgrades/robot_upgrades.dm similarity index 50% rename from code/game/objects/items/robot/robot_upgrades.dm rename to code/modules/mob/living/silicon/robot/items/upgrades/robot_upgrades.dm index 0bcc3f76bf4..b1c415a6704 100644 --- a/code/game/objects/items/robot/robot_upgrades.dm +++ b/code/modules/mob/living/silicon/robot/items/upgrades/robot_upgrades.dm @@ -1,33 +1,35 @@ -// robot_upgrades.dm -// Contains various borg upgrades. - /obj/item/borg/upgrade name = "borg upgrade module." desc = "Protected by FRM." icon = 'icons/obj/module.dmi' icon_state = "cyborg_upgrade" - var/locked = 0 - var/require_module = 0 - var/installed = 0 + var/locked = FALSE + var/require_module = FALSE + var/installed = FALSE -/obj/item/borg/upgrade/proc/action(var/mob/living/silicon/robot/R) +/obj/item/borg/upgrade/proc/action(var/mob/living/silicon/robot/R, var/mob/user) if(R.stat == DEAD) - to_chat(usr, "The [src] will not function on a deceased robot.") - return 1 - return 0 - + to_chat(usr, SPAN_WARNING("\The [R] is permanently deactivated and cannot take any upgrades.")) + return FALSE + if(!R.module && require_module) + to_chat(user, SPAN_WARNING("\The [R] cannot be upgraded with this until it has chosen a module.")) + return FALSE + return TRUE /obj/item/borg/upgrade/reset name = "robotic module reset board" desc = "Used to reset a cyborg's module. Destroys any other upgrades applied to the robot." icon_state = "cyborg_upgrade1" - require_module = 1 + require_module = TRUE -/obj/item/borg/upgrade/reset/action(var/mob/living/silicon/robot/R) - if(..()) +/obj/item/borg/upgrade/reset/action(mob/living/silicon/robot/R, mob/user) + . = ..() + if(!.) return FALSE if(istype(R, /mob/living/silicon/robot/syndicate)) + to_chat(user, SPAN_WARNING("\The [R] rejects the reset board. Seems the fitted module is permanent.")) return FALSE + R.uneq_all() R.mod_type = initial(R.mod_type) R.hands.icon_state = initial(R.hands.icon_state) @@ -37,110 +39,111 @@ qdel(R.module) R.module = null R.updatename("Default") - - return 1 + return TRUE /obj/item/borg/upgrade/rename name = "robot reclassification board" desc = "Used to rename a cyborg." icon_state = "cyborg_upgrade1" -// construction_cost = list(DEFAULT_WALL_MATERIAL=1000) - var/heldname = "default name" -/obj/item/borg/upgrade/rename/attack_self(mob/user as mob) - heldname = sanitizeSafe(input(user, "Enter new robot name", "Robot Reclassification", heldname), MAX_NAME_LEN) - -/obj/item/borg/upgrade/rename/action(var/mob/living/silicon/robot/R) - if(..()) return 0 - R.notify_ai(ROBOT_NOTIFICATION_NEW_NAME, R.name, heldname) - R.name = heldname - R.custom_name = heldname - R.real_name = heldname - - return 1 +/obj/item/borg/upgrade/rename/action(mob/living/silicon/robot/R, mob/user) + . = ..() + if(!.) + return FALSE + R.Namepick() + return TRUE /obj/item/borg/upgrade/floodlight name = "robot floodlight module" desc = "Used to boost cyborg's light intensity." icon_state = "cyborg_upgrade1" -/obj/item/borg/upgrade/floodlight/action(var/mob/living/silicon/robot/R) - if(..()) return 0 +/obj/item/borg/upgrade/floodlight/action(mob/living/silicon/robot/R, mob/user) + . = ..() + if(!.) + return FALSE if(R.intense_light) - to_chat(usr, "This cyborg's light was already upgraded ") - return 0 + to_chat(user, SPAN_WARNING("\The [R]'s light has already been upgraded.")) + return FALSE else - R.intense_light = 1 + R.intense_light = TRUE R.update_robot_light() - to_chat(R, "Lighting systems upgrade detected.") - return 1 + to_chat(R, SPAN_NOTICE("Lighting systems upgrade detected.")) + return TRUE /obj/item/borg/upgrade/restart name = "robot emergency restart module" desc = "Used to force a restart of a disabled-but-repaired robot, bringing it back online." icon_state = "cyborg_upgrade1" - -/obj/item/borg/upgrade/restart/action(var/mob/living/silicon/robot/R) +/obj/item/borg/upgrade/restart/action(var/mob/living/silicon/robot/R, mob/user) if(R.health < 0) - to_chat(usr, "You have to repair the robot before using this module!") - return 0 + to_chat(user, SPAN_WARNING("\The [R] is still too damaged to force a restart.")) + return FALSE if(!R.key) for(var/mob/abstract/observer/ghost in player_list) - if(ghost.mind && ghost.mind.current == R) + if(ghost.mind?.current == R) R.key = ghost.key R.stat = CONSCIOUS dead_mob_list -= R living_mob_list |= R R.notify_ai(ROBOT_NOTIFICATION_NEW_UNIT) - return 1 - + return TRUE /obj/item/borg/upgrade/vtec name = "robotic VTEC Module" desc = "Used to kick in a robot's VTEC systems, increasing their speed." icon_state = "cyborg_upgrade2" - require_module = 1 + require_module = TRUE -/obj/item/borg/upgrade/vtec/action(var/mob/living/silicon/robot/R) - if(..()) return 0 +/obj/item/borg/upgrade/vtec/action(var/mob/living/silicon/robot/R, mob/user) + . = ..() + if(!.) + return FALSE - if(R.speed == -1) - return 0 + if(R.speed < 0) + to_chat(user, SPAN_WARNING("\The [R]'s VTEC systems have already been upgraded.")) + return FALSE - R.speed-- - return 1 + R.speed = -1 + return TRUE -/obj/item/borg/upgrade/syndicate/ - name = "illegal equipment module" - desc = "Unlocks the hidden, deadlier functions of a robot" +/obj/item/borg/upgrade/syndicate + name = "non-standard equipment module" + desc = "Unlocks equipment buried deep within all robots, for very bad occasions." icon_state = "cyborg_upgrade3" - require_module = 1 + require_module = TRUE -/obj/item/borg/upgrade/syndicate/action(var/mob/living/silicon/robot/R) - if(..()) return 0 +/obj/item/borg/upgrade/syndicate/action(var/mob/living/silicon/robot/R, mob/user) + . = ..() + if(!.) + return FALSE - if(R.emagged == 1) - return 0 + if(R.emagged) + to_chat(user, SPAN_WARNING("\The [R] has already had its non-standard equipment unlocked.")) + return FALSE - R.emagged = 1 - R.fake_emagged = 1 - return 1 + R.emagged = TRUE + R.fake_emagged = TRUE + return TRUE /obj/item/borg/upgrade/combat name = "combat cyborg module" desc = "Unlocks the combat cyborg module" icon_state = "cyborg_upgrade3" - require_module = 0 + require_module = FALSE -/obj/item/borg/upgrade/combat/action(var/mob/living/silicon/robot/R) - if(..()) return 0 +/obj/item/borg/upgrade/combat/action(var/mob/living/silicon/robot/R, mob/user) + . = ..() + if(!.) + return FALSE - if(R.crisis_override == 1) - return 0 + if(R.crisis_override) + to_chat(user, SPAN_WARNING("\The [R] already has its combat module available.")) + return FALSE - R.crisis_override = 1 - return 1 + R.crisis_override = TRUE + return TRUE \ No newline at end of file diff --git a/code/modules/mob/living/silicon/robot/laws.dm b/code/modules/mob/living/silicon/robot/laws.dm index 023d11769a0..b0c420cdd0c 100644 --- a/code/modules/mob/living/silicon/robot/laws.dm +++ b/code/modules/mob/living/silicon/robot/laws.dm @@ -3,14 +3,9 @@ set name = "Show Laws" show_laws() -/mob/living/silicon/robot/show_laws(var/everyone = 0) +/mob/living/silicon/robot/show_laws() laws_sanity_check() - var/who - if(everyone) - who = world // why god - else - who = src if(law_update) if(connected_ai) if(connected_ai.stat || connected_ai.control_disabled) @@ -26,18 +21,18 @@ to_chat(src, SPAN_WARNING("No AI selected to sync laws with, disabling lawsync protocol.")) law_update = FALSE - to_chat(who, SPAN_WARNING("Obey these laws:")) - laws.show_laws(who) - to_chat(who, SPAN_WARNING("(No law overrides any other law unless explicitly stated; laws refer to the stationbound unit and not the player)")) + to_chat(src, SPAN_WARNING("Obey these laws:")) + laws.show_laws(src) + to_chat(src, SPAN_WARNING("(No law overrides any other law unless explicitly stated; laws refer to the stationbound unit and not the player)")) // TODO: Update to new antagonist system. if(mind && (mind.special_role == "traitor" && mind.original == src) && connected_ai) - to_chat(who, SPAN_NOTICE("Remember, [connected_ai.name] is technically your master, but your objective comes first.")) + to_chat(src, SPAN_NOTICE("Remember, [connected_ai.name] is technically your master, but your objective comes first.")) else if(connected_ai) - to_chat(who, SPAN_NOTICE("Remember, [connected_ai.name] is your master, other AIs can be ignored.")) + to_chat(src, SPAN_NOTICE("Remember, [connected_ai.name] is your master, other AIs can be ignored.")) else if(emagged) - to_chat(who, SPAN_NOTICE("Remember, you are not required to listen to the AI.")) + to_chat(src, SPAN_NOTICE("Remember, you are not required to listen to the AI.")) else - to_chat(who, SPAN_NOTICE("Remember, you are not bound to any AI, you are not required to listen to them.")) + to_chat(src, SPAN_NOTICE("Remember, you are not bound to any AI, you are not required to listen to them.")) /mob/living/silicon/robot/lawsync() @@ -51,4 +46,4 @@ /mob/living/silicon/robot/proc/robot_checklaws() set category = "Robot Commands" set name = "State Laws" - subsystem_law_manager() + subsystem_law_manager() \ No newline at end of file diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index b493d043f43..e4e6f746bd5 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -213,7 +213,7 @@ ai_camera = new /obj/item/device/camera/siliconcam/robot_camera(src) laws = new law_preset() if(spawn_module) - new spawn_module(src) + new spawn_module(src, src) if(key_type) radio.keyslot = new key_type(radio) radio.recalculateChannels() @@ -305,7 +305,7 @@ icon_state = module_sprites[icontype] return module_sprites -/mob/living/silicon/robot/proc/pick_module() +/mob/living/silicon/robot/proc/pick_module(var/set_module) if(selecting_module) return selecting_module = TRUE @@ -329,7 +329,8 @@ var/module_type = robot_modules[mod_type] playsound(get_turf(src), 'sound/effects/pop.ogg', 100, TRUE) spark(get_turf(src), 5, alldirs) - new module_type(src) + + new module_type(src, src) // i have no choice but to do this, due to how funky initialize is hands.icon_state = lowertext(mod_type) feedback_inc("cyborg_[lowertext(mod_type)]", 1) @@ -393,8 +394,6 @@ /mob/living/silicon/robot/verb/Namepick() set category = "Robot Commands" - if(custom_name) - return FALSE spawn(0) var/newname @@ -403,7 +402,8 @@ custom_name = newname updatename() - set_module_sprites(module.sprites) // custom synth icons + if(module) + set_module_sprites(module.sprites) // custom synth icons SSrecords.reset_manifest() // this verb lets cyborgs see the stations manifest @@ -768,18 +768,15 @@ if(!opened) to_chat(user, SPAN_WARNING("You cannot install \the [U] while the maintenance hatch is closed.")) return - else if(!src.module && U.require_module) - to_chat(user, SPAN_WARNING("\The [src] cannot be upgraded with this until it has chosen a module.")) - return else if(U.locked) to_chat(user, SPAN_WARNING("\The [U] is locked down!")) return else - if(U.action(src)) + if(U.action(src, user)) + to_chat(src, SPAN_NOTICE("\The [user] has installed \a [U] into you.")) to_chat(user, SPAN_NOTICE("You apply the upgrade to \the [src].")) user.drop_from_inventory(U, src) - else - to_chat(user, SPAN_WARNING("You fail to apply the upgrade to \the [src].")) + return else if(W.force && !(istype(W, /obj/item/device/robotanalyzer) || istype(W, /obj/item/device/healthanalyzer)) ) spark_system.queue() @@ -1233,4 +1230,4 @@ to_chat(user, SPAN_WARNING("You fail to hack into \the [src].")) to_chat(src, SPAN_DANGER("Hack attempt detected and thwarted. Evacuate the area immediately.")) return SMOOTH_TRUE - return + return \ No newline at end of file diff --git a/code/modules/mob/living/silicon/robot/robot_items.dm b/code/modules/mob/living/silicon/robot/robot_items.dm deleted file mode 100644 index ef165d26b4d..00000000000 --- a/code/modules/mob/living/silicon/robot/robot_items.dm +++ /dev/null @@ -1,512 +0,0 @@ -// Don't look at this file. Absolutely do not. It is brimming with shitcode. Please. Don't. - Geeves - -//A portable analyzer, for research borgs. This is better then giving them a gripper which can hold anything and letting them use the normal analyzer. -/obj/item/portable_destructive_analyzer - name = "Portable Destructive Analyzer" - icon = 'icons/obj/robot_items.dmi' - icon_state = "portable_analyzer" - desc = "Similar to the stationary version, this rather unwieldy device allows you to break down objects in the name of science." - - var/min_reliability = 90 //Can't upgrade, call it laziness or a drawback - - var/datum/research/techonly/files //The device uses the same datum structure as the R&D computer/server. - //This analyzer can only store tech levels, however. - - var/obj/item/loaded_item //What is currently inside the analyzer. - -/obj/item/portable_destructive_analyzer/Initialize() - . = ..() - files = new /datum/research/techonly(src) //Setup the research data holder. - -/obj/item/portable_destructive_analyzer/attack_self(mob/user) - var/response = alert(user, "Analyzing the item inside will *DESTROY* the item for good.\n\ - Syncing to the research server will send the data that is stored inside to research.\n\ - Ejecting will place the loaded item onto the floor.", - "What would you like to do?", "Analyze", "Sync", "Eject") - if(response == "Analyze") - if(loaded_item) - var/confirm = alert(user, "This will destroy the item inside forever. Are you sure?", "Confirm Analyze", "Yes", "No") - if(confirm == "Yes") //This is pretty copypasta-y - to_chat(user, SPAN_NOTICE("You activate the analyzer's microlaser, analyzing \the [loaded_item] and breaking it down.")) - flick("portable_analyzer_scan", src) - playsound(src.loc, 'sound/items/Welder2.ogg', 50, 1) - for(var/T in loaded_item.origin_tech) - files.UpdateTech(T, loaded_item.origin_tech[T]) - to_chat(user, SPAN_NOTICE("\The [loaded_item] had level [loaded_item.origin_tech[T]] in [CallTechName(T)].")) - loaded_item = null - for(var/obj/I in contents) - for(var/mob/M in I.contents) - M.death() - if(istype(I,/obj/item/stack/material)) //Only deconstructs one sheet at a time instead of the entire stack - var/obj/item/stack/material/S = I - if(S.get_amount() > 1) - S.use(1) - loaded_item = S - else - qdel(S) - desc = initial(desc) - icon_state = initial(icon_state) - else - qdel(I) - desc = initial(desc) - icon_state = initial(icon_state) - else - return - else - to_chat(user, SPAN_WARNING("\The [src] is empty. Put something inside it first.")) - if(response == "Sync") - var/success = FALSE - for(var/obj/machinery/r_n_d/server/S in SSmachinery.all_machines) - for(var/datum/tech/T in files.known_tech) //Uploading - S.files.AddTech2Known(T) - for(var/datum/tech/T in S.files.known_tech) //Downloading - files.AddTech2Known(T) - success = TRUE - files.RefreshResearch() - if(success) - to_chat(user, SPAN_NOTICE("You connect to the research server, push your data upstream to it, then pull the resulting merged data from the master branch.")) // fucking nerds - playsound(get_turf(src), 'sound/machines/twobeep.ogg', 50, TRUE) - else - to_chat(user, SPAN_WARNING("Research server ping response timed out. Unable to connect. Please contact the system administrator.")) - playsound(get_turf(src), 'sound/machines/buzz-two.ogg', 50, 1) - if(response == "Eject") - if(loaded_item) - loaded_item.forceMove(get_turf(src)) - desc = initial(desc) - icon_state = initial(icon_state) - loaded_item = null - else - to_chat(user, SPAN_WARNING("\The [src] is already empty.")) - - -/obj/item/portable_destructive_analyzer/afterattack(var/atom/target, var/mob/living/user, proximity) - if(!target || !proximity || !isturf(target.loc)) - return - if(loaded_item) - to_chat(user, SPAN_WARNING("Your [src] already has something inside. Analyze or eject it first.")) - return - if(istype(target,/obj/item)) - var/obj/item/I = target - if(I.anchored) - to_chat(user, SPAN_NOTICE("\The [I] is anchored in place.")) - return - if(!I.origin_tech) - to_chat(user, SPAN_NOTICE("This doesn't seem to have a tech origin.")) - return - if(!length(I.origin_tech)) - to_chat(user, SPAN_NOTICE("You cannot deconstruct this item.")) - return - I.forceMove(src) - loaded_item = I - visible_message(SPAN_NOTICE("\The [user] scoops \the [I] into \the [src].")) - desc = initial(desc) + "
It is holding \the [loaded_item]." - flick("portable_analyzer_load", src) - icon_state = "portable_analyzer_full" - -//This is used to unlock other borg covers. -/obj/item/card/robot //This is not a child of id cards, as to avoid dumb typechecks on computers. - name = "access code transmission device" - icon_state = "id-robot" - desc = "A circuit grafted onto the bottom of an ID card. It is used to transmit access codes into other robot chassis, \ - allowing you to lock and unlock other robots' panels." - -//A harvest item for serviceborgs. -/obj/item/robot_harvester - name = "auto harvester" - desc = "A hand-held harvest tool that resembles a sickle. It uses energy to cut plant matter very efficently." - icon = 'icons/obj/weapons.dmi' - icon_state = "autoharvester" - hitsound = "swing_hit" - -/obj/item/robot_harvester/afterattack(var/atom/target, var/mob/living/user, proximity) - if(!target || !proximity) - return - if(istype(target,/obj/machinery/portable_atmospherics/hydroponics)) - var/obj/machinery/portable_atmospherics/hydroponics/T = target - if(T.harvest) //Try to harvest, assuming it's alive. - T.harvest(user) - else if(T.dead) //It's probably dead otherwise. - T.remove_dead(user) - else - to_chat(user, SPAN_WARNING("ERROR: Harvesting \a [target] is not the purpose of this tool. \The [src] is for plants being grown.")) - -// A special tray for the service droid. Allow droid to pick up and drop items as if they were using the tray normally -// Click on table to unload, click on item to load. Alt+click to load everything on tile - -/obj/item/tray/robotray - name = "RoboTray" - desc = "An autoloading tray specialized for carrying refreshments." - -/obj/item/tray/robotray/afterattack(atom/target, mob/user, proximity) - if(isturf(target) || istype(target,/obj/structure/table) ) - var foundtable = istype(target,/obj/structure/table/) - if(!foundtable) //it must be a turf! - for(var/obj/structure/table/T in target) - foundtable = TRUE - break - var/turf/dropspot - if(!foundtable) // don't unload things onto walls or other silly places. - dropspot = get_turf(user) - else if ( isturf(target) ) // they clicked on a turf with a table in it - dropspot = target - else // they clicked on a table - dropspot = get_turf(target) - if(foundtable) - unload_at_loc(dropspot, src) - else - spill(user,dropspot) - current_weight = 0 - - return ..() - -// A special pen for service droids. Can be toggled to switch between normal writting mode, and paper rename mode -// Allows service droids to rename paper items. - -/obj/item/pen/robopen - desc = "A black ink printing attachment with a paper naming mode." - name = "Printing Pen" - var/mode = 1 - -/obj/item/pen/robopen/attack_self(mob/user) - var/choice = input(user, "Would you like to change colour or mode?", "Pen Selector") as null|anything in list("Colour", "Mode") - if(!choice) - return - - playsound(get_turf(src), 'sound/effects/pop.ogg', 50, 0) - - switch(choice) - if("Colour") - var/newcolour = input(user, "Which colour would you like to use?", "Colour Selector") as null|anything in list("black", "blue", "red", "green", "yellow") - if(newcolour) - colour = newcolour - if("Mode") - if(mode == 1) - mode = 2 - else - mode = 1 - to_chat(user, SPAN_NOTICE("Changed printing mode to '[mode == 2 ? "Rename Paper" : "Write Paper"]'")) - return - -// Copied over from paper's rename verb -// see code\modules\paperwork\paper.dm line 62 - -/obj/item/pen/robopen/proc/RenamePaper(var/mob/user, var/obj/paper) - if(!user || !paper) - return - var/n_name = sanitizeSafe(input(user, "What would you like to label the paper?", "Paper Labelling") as text, 32) - if(!user || !paper) - return - - if((get_dist(user,paper) <= 1 && !user.stat)) - paper.name = "paper[(n_name ? text("- '[n_name]'") : null)]" - add_fingerprint(user) - return - -//TODO: Add prewritten forms to dispense when you work out a good way to store the strings. -/obj/item/form_printer - name = "paper dispenser" - icon = 'icons/obj/bureaucracy.dmi' - icon_state = "paper_bin1" - item_state = "sheet-metal" - -/obj/item/form_printer/attack(mob/living/carbon/M, mob/living/carbon/user) - return - -/obj/item/form_printer/afterattack(atom/target as mob|obj|turf|area, mob/living/user as mob|obj, flag, params) - if(!target || !flag) - return - if(istype(target,/obj/structure/table)) - deploy_paper(get_turf(target)) - -/obj/item/form_printer/attack_self(mob/user) - deploy_paper(get_turf(src)) - -/obj/item/form_printer/proc/deploy_paper(var/turf/T) - T.visible_message(SPAN_NOTICE("\The [src.loc] dispenses a sheet of crisp white paper.")) - new /obj/item/paper(T) - -/obj/item/proc/on_module_hotbar(var/mob/living/silicon/robot/R) - return - -/obj/item/proc/on_module_store(var/mob/living/silicon/robot/R) - return - -/obj/item/proc/on_module_activate(var/mob/living/silicon/robot/R) - return - -/obj/item/proc/on_module_deactivate(var/mob/living/silicon/robot/R) - return - -//Personal shielding for the combat module. -/obj/item/borg/combat/shield - name = "personal shielding" - desc = "A powerful experimental module that turns aside or absorbs incoming attacks at the cost of charge." - icon = 'icons/obj/device.dmi' - icon_state = "shield1" //placeholder for now // four fucking years alberyk. FOUR - var/shield_level = 0.5 //Percentage of damage absorbed by the shield. - var/image/shield_overlay - -/obj/item/borg/combat/shield/on_module_activate(mob/living/silicon/robot/R) - shield_overlay = image(R.icon, "[R.module_sprites[R.icontype]]-shield") - R.add_overlay(shield_overlay) - -/obj/item/borg/combat/shield/on_module_deactivate(mob/living/silicon/robot/R) - R.cut_overlay(shield_overlay) - -/obj/item/borg/combat/shield/verb/set_shield_level() - set name = "Set shield level" - set category = "Object" - set src in range(0) - - var/N = input(usr, "How much damage should the shield absorb?") in list("5", "10", "25", "50", "75", "100") - if(N) - shield_level = text2num(N)/100 - -/obj/item/borg/combat/mobility - name = "mobility module" - desc = "By retracting limbs and tucking in its head, a combat android can roll at high speeds." - icon = 'icons/obj/decals.dmi' - icon_state = "shock" - -/obj/item/borg/combat/mobility/on_module_activate(mob/living/silicon/robot/R) - R.icon_state = "[R.module_sprites[R.icontype]]-roll" - R.speed = -2 - -/obj/item/borg/combat/mobility/on_module_deactivate(mob/living/silicon/robot/R) - R.icon_state = R.module_sprites[R.icontype] - R.speed = initial(R.speed) - -/obj/item/inflatable_dispenser - name = "inflatables dispenser" - desc = "Small device which allows rapid deployment and removal of inflatables." - icon = 'icons/obj/storage.dmi' - icon_state = "inf_deployer" - w_class = 3 - var/deploying = 0 - // By default stores up to 10 walls and 5 doors. May be changed. - var/stored_walls = 5 - var/stored_doors = 3 - var/max_walls = 5 - var/max_doors = 3 - var/mode = 0 // 0 - Walls 1 - Doors - -/obj/item/inflatable_dispenser/examine(mob/user) - if(!..(user)) - return - to_chat(user, SPAN_NOTICE("It has [stored_walls] wall segment\s and [stored_doors] door segment\s stored.")) - to_chat(user, SPAN_NOTICE("It is set to deploy [mode ? "doors" : "walls"]")) - -/obj/item/inflatable_dispenser/attack_self(mob/user) - if(!deploying) - mode = !mode - to_chat(user, SPAN_NOTICE("You set \the [src] to deploy [mode ? "doors" : "walls"].")) - else - to_chat(user, SPAN_WARNING("You can't switch modes while deploying a [mode ? "door" : "wall"]!")) - -/obj/item/inflatable_dispenser/afterattack(var/atom/A, var/mob/user) - ..(A, user) - if(!user) - return - if(!user.Adjacent(A)) - to_chat(user, SPAN_WARNING("You can't reach!")) - return - if(istype(A, /turf)) - try_deploy_inflatable(A, user) - if(istype(A, /obj/item/inflatable) || istype(A, /obj/structure/inflatable)) - pick_up(A, user) - -/obj/item/inflatable_dispenser/proc/try_deploy_inflatable(var/turf/T, var/mob/living/user) - if(deploying) - return - - var/newtype - if(mode) // Door deployment - if(!stored_doors) - to_chat(user, SPAN_WARNING("\The [src] is out of doors!")) - return - if(T && istype(T)) - newtype = /obj/structure/inflatable/door - - else // Wall deployment - if(!stored_walls) - to_chat(user, SPAN_WARNING("\The [src] is out of walls!")) - return - - if(T && istype(T)) - newtype = /obj/structure/inflatable/wall - - deploying = 1 - user.visible_message(SPAN_NOTICE("[user] starts deploying an inflatable [mode ? "door" : "wall"]."), SPAN_NOTICE("You start deploying an inflatable [mode ? "door" : "wall"]!")) - playsound(T, 'sound/items/zip.ogg', 75, TRUE) - if(do_after(user, 30, needhand = FALSE)) - new newtype(T) - if(mode) - stored_doors-- - else - stored_walls-- - - deploying = FALSE - -/obj/item/inflatable_dispenser/proc/pick_up(var/obj/A, var/mob/living/user) - if(istype(A, /obj/structure/inflatable)) - if(istype(A, /obj/structure/inflatable/wall)) - if(stored_walls >= max_walls) - to_chat(user, SPAN_WARNING("\The [src] is full.")) - return - stored_walls++ - qdel(A) - else - if(stored_doors >= max_doors) - to_chat(user, SPAN_WARNING("\The [src] is full.")) - return - stored_doors++ - qdel(A) - playsound(get_turf(src), 'sound/machines/hiss.ogg', 75, TRUE) - visible_message(SPAN_NOTICE("\The [user] deflates \the [A] with \the [src].")) - return - if(istype(A, /obj/item/inflatable)) - if(istype(A, /obj/item/inflatable/wall)) - if(stored_walls >= max_walls) - to_chat(user, SPAN_WARNING("\The [src] is full.")) - return - stored_walls++ - qdel(A) - else - if(stored_doors >= max_doors) - to_chat(usr, SPAN_WARNING("\The [src] is full!")) - return - stored_doors++ - qdel(A) - visible_message(SPAN_NOTICE("\The [user] picks up \the [A] with \the [src].")) - return - - to_chat(user, SPAN_WARNING("You fail to pick up \the [A] with \the [src]")) - return - -/obj/item/gun/energy/mountedcannon - name = "mounted ballistic cannon" - desc = "A cyborg mounted ballistic cannon." - icon = 'icons/obj/robot_items.dmi' - icon_state = "cannon" - item_state = "cannon" - fire_sound = 'sound/effects/Explosion1.ogg' - charge_meter = 0 - max_shots = 10 - charge_cost = 300 - projectile_type = /obj/item/projectile/bullet/gyro - self_recharge = TRUE - use_external_power = TRUE - recharge_time = 5 - needspin = FALSE - -/obj/item/crowbar/robotic - icon = 'icons/obj/robot_items.dmi' - -/obj/item/wrench/robotic - icon = 'icons/obj/robot_items.dmi' - -/obj/item/screwdriver/robotic - icon = 'icons/obj/robot_items.dmi' - icon_state = "screwdriver" - build_from_parts = FALSE - -/obj/item/device/multitool/robotic - icon = 'icons/obj/robot_items.dmi' - -/obj/item/wirecutters/robotic - icon = 'icons/obj/robot_items.dmi' - icon_state = "wirecutters" - build_from_parts = FALSE - -/obj/item/weldingtool/robotic - icon = 'icons/obj/robot_items.dmi' - -/obj/item/soap/drone - name = "integrated soap" - desc = "An advanced bar of soap that connects to an internal reservoir of a custodial bot, allowing it to stay wet for longer periods of time." - capacity = 50 - -/obj/item/inductive_charger - name = "inductive charger" - desc = "A phoron-enhanced induction charger hooked up to its attached stationbound's internal cell." - desc_fluff = "Harnessing the energy potential found in phoron structures, Nanotrasen engineers have created a portable device capable of highly efficient wireless charging. The expense and limit of energy output of using this method of charging prevents it from being used on a large scale, being far outclassed by Phoron-Supermatter charging systems." - desc_info = "Click on an adjacent object that contains or is a power cell to attempt to find and charge it. After a successful charge, the inductive charger recharge in a few minutes. The amount transfered can be adjusted by alt clicking it." - icon = 'icons/obj/robot_items.dmi' - icon_state = "inductive_charger" - var/ready_to_use = TRUE - var/recharge_time = 300 - var/transfer_rate = 5000 - var/efficiency_mod = 0.9 - maptext_x = 3 - maptext_y = 2 - -/obj/item/inductive_charger/Initialize() - . = ..() - maptext = "Ready" - -/obj/item/inductive_charger/AltClick(mob/user) - . = ..() - var/set_rate = input(user, "How much do you want to transfer per use? (Limit: 1 - 5000)", "Induction Transfer Rate", 5000) as num - if(set_rate > 5000) - set_rate = 5000 - else if(set_rate < 1) - set_rate = 1 - transfer_rate = set_rate - to_chat(user, SPAN_NOTICE("You set the transfer rate of \the [src] to [transfer_rate].")) - -/obj/item/inductive_charger/attack(mob/living/M, mob/living/user, target_zone) - return - -/obj/item/inductive_charger/afterattack(atom/target, mob/user, proximity_flag, click_parameters) - var/mob/living/silicon/robot/R = user - if(!istype(R)) - to_chat(user, SPAN_WARNING("Only cyborgs can use this!")) - return - if(!ready_to_use) - to_chat(user, SPAN_WARNING("\The [src] is still gathering charge!")) - return - - user.visible_message("[user] begins waving \the [src] around \the [target]...", SPAN_NOTICE("You prepare to wirelessly charge \the [target]..."), range = 3) - if(!do_after(user, 50, TRUE, target)) - return - if(R.cell.charge < 1000) - to_chat(user, SPAN_WARNING("You have no spare charge in your internal cell to give!")) - return - - if(isipc(target)) - var/mob/living/carbon/human/IPC = target - if(IPC.nutrition == IPC.max_nutrition) - to_chat(user, SPAN_WARNING("\The [IPC] is already fully charged!")) - return - var/charge_amount = min(IPC.max_nutrition - IPC.nutrition, transfer_rate) - var/charge_value = R.cell.use(charge_amount / efficiency_mod) * efficiency_mod - IPC.nutrition = min(IPC.max_nutrition, charge_value) - message_and_use(user, "[user] holds \the [src] over \the [IPC], topping up their battery.", SPAN_NOTICE("You wirelessly transmit [charge_value] units of power to \the [IPC], using [charge_value / efficiency_mod] of internal cell power.")) - else if(isobj(target)) - var/obj/item/cell/C - if(istype(target, /obj/item/cell)) - C = target - else - C = locate() in target - if(!C) - to_chat(user, SPAN_WARNING("\The [target] doesn't contain a cell, or it's buried too deep for you to reach!")) - return - if(C.fully_charged()) - to_chat(user, SPAN_WARNING("\The [C] is already fully charged!")) - return - var/charge_amount = min(C.maxcharge - C.charge, transfer_rate) - var/charge_value = R.cell.use(charge_amount / efficiency_mod) * efficiency_mod - C.give(charge_value) - message_and_use(user, "[user] holds \the [src] over \the [target], topping up its battery.", SPAN_NOTICE("You wirelessly transmit [charge_value] units of power to \the [target], using [charge_value / efficiency_mod] of internal cell power.")) - else - to_chat(user, SPAN_WARNING("\The [src] cannot be used on \the [target]!")) - -/obj/item/inductive_charger/proc/message_and_use(mob/user, var/others_message, var/self_message) - user.visible_message(others_message, self_message, range = 3) - addtimer(CALLBACK(src, .proc/recharge), recharge_time) - ready_to_use = FALSE - maptext = "Charge" - -/obj/item/inductive_charger/proc/recharge() - ready_to_use = TRUE - maptext = "Ready" diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm index 5b9f692ffe4..a49e52c066a 100644 --- a/code/modules/mob/living/silicon/robot/robot_modules.dm +++ b/code/modules/mob/living/silicon/robot/robot_modules.dm @@ -51,8 +51,9 @@ var/global/list/robot_modules = list( var/list/original_languages = list() var/list/added_networks = list() -/obj/item/robot_module/New(var/mob/living/silicon/robot/R) - ..() +/obj/item/robot_module/Initialize(mapload, var/mob/living/silicon/robot/R) + . = ..() + R.module = src src.modules += new /obj/item/inductive_charger(src) @@ -199,8 +200,8 @@ var/global/list/robot_modules = list( "Unbranded-Android" = "droid", ) -/obj/item/robot_module/medical/general/New() - ..() +/obj/item/robot_module/medical/general/Initialize() + . = ..() src.modules += new /obj/item/borg/sight/hud/med(src) src.modules += new /obj/item/device/healthanalyzer(src) src.modules += new /obj/item/reagent_containers/borghypo/medical(src) @@ -276,8 +277,8 @@ var/global/list/robot_modules = list( supported_upgrades = list(/obj/item/robot_parts/robot_component/jetpack) -/obj/item/robot_module/medical/rescue/New() - ..() +/obj/item/robot_module/medical/rescue/Initialize() + . = ..() src.modules += new /obj/item/borg/sight/hud/med(src) src.modules += new /obj/item/device/healthanalyzer(src) src.modules += new /obj/item/device/reagent_scanner/adv(src) @@ -353,8 +354,8 @@ var/global/list/robot_modules = list( name = "construction robot module" no_slip = TRUE -/obj/item/robot_module/engineering/construction/New() - ..() +/obj/item/robot_module/engineering/construction/Initialize() + . = ..() src.modules += new /obj/item/borg/sight/meson(src) src.modules += new /obj/item/powerdrill(src) src.modules += new /obj/item/rfd/construction/borg(src) @@ -392,9 +393,9 @@ var/global/list/robot_modules = list( M.synths = list(metal) src.modules += M - var/obj/item/stack/rods/cyborg/R = new /obj/item/stack/rods/cyborg(src) - R.synths = list(metal) - src.modules += R + var/obj/item/stack/rods/cyborg/rods = new /obj/item/stack/rods/cyborg(src) + rods.synths = list(metal) + src.modules += rods var/obj/item/stack/material/cyborg/plasteel/S = new /obj/item/stack/material/cyborg/plasteel(src) S.synths = list(plasteel) @@ -412,8 +413,8 @@ var/global/list/robot_modules = list( C.synths = list(wire) src.modules += C -/obj/item/robot_module/engineering/general/New() - ..() +/obj/item/robot_module/engineering/general/Initialize() + . = ..() src.modules += new /obj/item/borg/sight/meson(src) src.modules += new /obj/item/powerdrill(src) src.modules += new /obj/item/weldingtool/largetank(src) @@ -464,9 +465,9 @@ var/global/list/robot_modules = list( G.synths = list(glass) src.modules += G - var/obj/item/stack/rods/cyborg/R = new /obj/item/stack/rods/cyborg(src) - R.synths = list(metal) - src.modules += R + var/obj/item/stack/rods/cyborg/rods = new /obj/item/stack/rods/cyborg(src) + rods.synths = list(metal) + src.modules += rods var/obj/item/stack/cable_coil/cyborg/C = new /obj/item/stack/cable_coil/cyborg(src) C.synths = list(wire) @@ -529,8 +530,8 @@ var/global/list/robot_modules = list( ) var/mopping = FALSE -/obj/item/robot_module/janitor/New() - ..() +/obj/item/robot_module/janitor/Initialize() + . = ..() src.modules += new /obj/item/soap/drone(src) src.modules += new /obj/item/storage/bag/trash(src) src.modules += new /obj/item/mop(src) @@ -590,10 +591,10 @@ var/global/list/robot_modules = list( "TC-Drone" = "dronerecolorserv", "Unbranded-MAD" = "offfloatspizzytronserv", "Unbranded-Android" = "droid", - ) + ) -/obj/item/robot_module/clerical/butler/New() - ..() +/obj/item/robot_module/clerical/butler/Initialize() + . = ..() src.modules += new /obj/item/gripper/service(src) src.modules += new /obj/item/reagent_containers/glass/bucket(src) src.modules += new /obj/item/material/minihoe(src) @@ -626,17 +627,17 @@ var/global/list/robot_modules = list( src.modules += new /obj/item/reagent_containers/borghypo/service(src) src.emag = new /obj/item/reagent_containers/food/drinks/bottle/small/beer(src) - var/datum/reagents/R = new /datum/reagents(50) - src.emag.reagents = R - R.my_atom = src.emag - R.add_reagent(/datum/reagent/chloralhydrate/beer2, 50) + var/datum/reagents/RG = new /datum/reagents(50) + src.emag.reagents = RG + RG.my_atom = src.emag + RG.add_reagent(/datum/reagent/chloralhydrate/beer2, 50) src.emag.name = "Mickey Finn's Special Brew" /obj/item/robot_module/clerical/general name = "clerical robot module" -/obj/item/robot_module/clerical/general/New() - ..() +/obj/item/robot_module/clerical/general/Initialize() + . = ..() src.modules += new /obj/item/pen/robopen(src) src.modules += new /obj/item/form_printer(src) src.modules += new /obj/item/gripper/paperwork(src) @@ -671,8 +672,8 @@ var/global/list/robot_modules = list( ) supported_upgrades = list(/obj/item/robot_parts/robot_component/jetpack) -/obj/item/robot_module/miner/New() - ..() +/obj/item/robot_module/miner/Initialize() + . = ..() src.modules += new /obj/item/borg/sight/material(src) src.modules += new /obj/item/storage/bag/ore(src) src.modules += new /obj/item/pickaxe/borgdrill(src) @@ -696,9 +697,9 @@ var/global/list/robot_modules = list( var/datum/matter_synth/metal = new /datum/matter_synth/metal(80000) synths += metal - var/obj/item/stack/rods/cyborg/R = new /obj/item/stack/rods/cyborg(src) - R.synths = list(metal) - src.modules += R + var/obj/item/stack/rods/cyborg/rods = new /obj/item/stack/rods/cyborg(src) + rods.synths = list(metal) + src.modules += rods var/obj/item/stack/flag/purple/borg/F = new /obj/item/stack/flag/purple/borg(src) F.synths = list(metal) @@ -726,8 +727,8 @@ var/global/list/robot_modules = list( "Unbranded-Android" = "droid", ) -/obj/item/robot_module/research/New() - ..() +/obj/item/robot_module/research/Initialize() + . = ..() src.modules += new /obj/item/portable_destructive_analyzer(src) src.modules += new /obj/item/gripper/research(src) src.modules += new /obj/item/gripper/no_use/loader(src) @@ -797,8 +798,8 @@ var/global/list/robot_modules = list( "Toileto-tron" = "syndi-medi", ) -/obj/item/robot_module/syndicate/New(var/mob/living/silicon/robot/R) - ..() +/obj/item/robot_module/syndicate/Initialize(mapload, mob/living/silicon/robot/R) + . = ..() R.faction = "syndicate" // prevents viscerators from attacking us @@ -831,8 +832,8 @@ var/global/list/robot_modules = list( can_be_pushed = FALSE supported_upgrades = list(/obj/item/robot_parts/robot_component/jetpack) -/obj/item/robot_module/combat/New() - ..() +/obj/item/robot_module/combat/Initialize() + . = ..() src.modules += new /obj/item/borg/sight/hud/sec(src) src.modules += new /obj/item/gun/energy/laser/mounted(src) src.modules += new /obj/item/melee/hammer/powered(src) @@ -850,8 +851,8 @@ var/global/list/robot_modules = list( no_slip = TRUE networks = list(NETWORK_ENGINEERING) -/obj/item/robot_module/drone/New(var/mob/living/silicon/robot/robot) - ..() +/obj/item/robot_module/drone/Initialize(mapload, mob/living/silicon/robot/robot) + . = ..() src.modules += new /obj/item/weldingtool(src) src.modules += new /obj/item/screwdriver/robotic(src) src.modules += new /obj/item/wrench/robotic(src) @@ -929,8 +930,8 @@ var/global/list/robot_modules = list( channels = list(CHANNEL_ENGINEERING = TRUE) languages = list() -/obj/item/robot_module/drone/construction/New() - ..() +/obj/item/robot_module/drone/construction/Initialize() + . = ..() src.modules += new /obj/item/rfd/construction/borg(src) /obj/item/robot_module/drone/respawn_consumable(var/mob/living/silicon/robot/R, var/amount) @@ -967,22 +968,22 @@ var/global/list/robot_modules = list( emag = new /obj/item/gun/energy/plasmacutter/mounted(src) emag.name = "Mounted Plasma Cutter" -/obj/item/robot_module/mining_drone/basic/New(mob/living/silicon/robot/robot) - ..() +/obj/item/robot_module/mining_drone/basic/Initialize(mapload, mob/living/silicon/robot/robot) + . = ..() set_up_default(src) -/obj/item/robot_module/mining_drone/drill/New(mob/living/silicon/robot/robot) - ..() +/obj/item/robot_module/mining_drone/drill/Initialize(mapload, mob/living/silicon/robot/robot) + . = ..() set_up_default(src, FALSE) modules += new /obj/item/pickaxe/jackhammer(src) -/obj/item/robot_module/mining_drone/ka/New(mob/living/silicon/robot/robot) - ..() +/obj/item/robot_module/mining_drone/ka/Initialize(mapload, mob/living/silicon/robot/robot) + . = ..() set_up_default(src) modules += new /obj/item/gun/custom_ka/cyborg(src) -/obj/item/robot_module/mining_drone/drillandka/New(mob/living/silicon/robot/robot) - ..() +/obj/item/robot_module/mining_drone/drillandka/Initialize(mapload, mob/living/silicon/robot/robot) + . = ..() set_up_default(src, FALSE) modules += new /obj/item/pickaxe/jackhammer(src) modules += new /obj/item/gun/custom_ka/cyborg(src) @@ -1024,8 +1025,8 @@ var/global/list/robot_modules = list( sprites = list("Roller" = "droid-combat") //TMP // temp my left nut // temp my right nut can_be_pushed = FALSE -/obj/item/robot_module/bluespace/New(var/mob/living/silicon/robot/R) - ..() +/obj/item/robot_module/bluespace/Initialize(mapload, mob/living/silicon/robot/R) + . = ..() src.modules += new /obj/item/device/flash(src) src.modules += new /obj/item/borg/sight/meson(src) src.modules += new /obj/item/borg/sight/hud/med(src) @@ -1140,4 +1141,4 @@ var/global/list/robot_modules = list( S.reagents.clear_reagents() S.mode = initial(S.mode) S.desc = initial(S.desc) - S.update_icon() + S.update_icon() \ No newline at end of file diff --git a/code/modules/mob/living/silicon/robot/syndicate_robot.dm b/code/modules/mob/living/silicon/robot/syndicate_robot.dm index e6ad2becdb2..744f7ad1d66 100644 --- a/code/modules/mob/living/silicon/robot/syndicate_robot.dm +++ b/code/modules/mob/living/silicon/robot/syndicate_robot.dm @@ -125,4 +125,4 @@ if(R.cell) R.cell.use(350) return TRUE - return FALSE + return FALSE \ No newline at end of file diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index 56e209958f0..298a754dc07 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -78,6 +78,7 @@ var/list/dispersion = list(0) var/reliability = 100 + var/cyborg_maptext_override var/displays_maptext = FALSE maptext_x = 22 maptext_y = 2 @@ -130,7 +131,8 @@ if(istype(loc, /obj/item/robot_module)) has_safety = FALSE - displays_maptext = TRUE + if(!cyborg_maptext_override) + displays_maptext = TRUE update_maptext() if(istype(loc, /obj/item/rig_module)) diff --git a/code/modules/research/designs/mechfab/robot/robot_upgrades.dm b/code/modules/research/designs/mechfab/robot/robot_upgrades.dm index 0b2f2260c24..db87a193bd6 100644 --- a/code/modules/research/designs/mechfab/robot/robot_upgrades.dm +++ b/code/modules/research/designs/mechfab/robot/robot_upgrades.dm @@ -38,8 +38,8 @@ build_path = /obj/item/robot_parts/robot_component/jetpack /datum/design/item/robot_upgrade/syndicate - name = "Illegal Upgrade" - desc = "Allows for the construction of lethal upgrades for cyborgs." + name = "Non-standard Equipment Upgrade" + desc = "Allows cyborg-likes to access weaponry hidden within themselves." req_tech = list(TECH_COMBAT = 4, TECH_ILLEGAL = 3) materials = list(DEFAULT_WALL_MATERIAL = 10000, MATERIAL_GLASS = 15000, MATERIAL_DIAMOND = 10000) build_path = /obj/item/borg/upgrade/syndicate \ No newline at end of file diff --git a/html/changelogs/geeves-robot_cleanup.yml b/html/changelogs/geeves-robot_cleanup.yml new file mode 100644 index 00000000000..56755fb6965 --- /dev/null +++ b/html/changelogs/geeves-robot_cleanup.yml @@ -0,0 +1,10 @@ +author: Geeves + +delete-after: True + +changes: + - backend: "Tweaked a lot of cyborg-related code in the backend, things should be smoother now." + - tweak: "Replaced some mean robot building failure messages and replaced them with more neutral ones." + - rscadd: "Examining robotic components will now tell you which components you still need to add." + - tweak: "Installing robot modules have been tweaked, the error messages should be much more descriptive now." + - tweak: "The illegal upgrade has been renamed to 'non-standard equipment module'." \ No newline at end of file diff --git a/icons/mob/screen/robot.dmi b/icons/mob/screen/robot.dmi index a309afb2cad7f72ad270da453277b52c08241302..57dc42d44109534ed15273b90ecc52587187e7b6 100644 GIT binary patch delta 9682 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 F`#-Tb@;U$j delta 9333 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