diff --git a/code/__defines/objects.dm b/code/__defines/objects.dm new file mode 100644 index 0000000000..879bed2cd1 --- /dev/null +++ b/code/__defines/objects.dm @@ -0,0 +1,10 @@ +/* + * Defines used for miscellaneous objects. + * Currently only the home of the Multiool. + */ + +// Multitool Mode Defines. + +#define MULTITOOL_MODE_STANDARD "Standard" +#define MULTITOOL_MODE_INTCIRCUITS "Modular Wiring" +#define MULTITOOL_MODE_DOORHACK "Advanced Jacking" diff --git a/code/game/objects/items/devices/multitool.dm b/code/game/objects/items/devices/multitool.dm index 21d855c674..e6385c751f 100644 --- a/code/game/objects/items/devices/multitool.dm +++ b/code/game/objects/items/devices/multitool.dm @@ -18,20 +18,51 @@ matter = list(DEFAULT_WALL_MATERIAL = 50,"glass" = 20) + var/mode_index = 1 + var/toolmode = MULTITOOL_MODE_STANDARD + var/list/modes = list(MULTITOOL_MODE_STANDARD, MULTITOOL_MODE_INTCIRCUITS) + origin_tech = list(TECH_MAGNET = 1, TECH_ENGINEERING = 1) var/obj/machinery/telecomms/buffer // simple machine buffer for device linkage var/obj/machinery/clonepod/connecting //same for cryopod linkage var/obj/machinery/connectable //Used to connect machinery. + var/weakref_wiring //Used to store weak references for integrated circuitry. This is now the Omnitool. toolspeed = 1 -/obj/item/device/multitool/attack_self(mob/user) - var/clear = alert("Do you want to clear the buffers on the [src]?",, "Yes", "No",) - if(clear == "Yes") - buffer = null - connecting = null - connectable = null +/obj/item/device/multitool/attack_self(mob/living/user) + var/choice = alert("What do you want to do with \the [src]?","Multitool Menu", "Switch Mode", "Clear Buffers", "Cancel") + switch(choice) + if("Cancel") + to_chat(user,"You lower \the [src].") + return + if("Clear Buffers") + to_chat(user,"You clear \the [src]'s memory.") + buffer = null + connecting = null + connectable = null + weakref_wiring = null + accepting_refs = 0 + if(toolmode == MULTITOOL_MODE_INTCIRCUITS) + accepting_refs = 1 + if("Switch Mode") + mode_switch(user) + + update_icon() + + return ..() + +/obj/item/device/multitool/proc/mode_switch(mob/living/user) + if(++mode_index > modes.len) mode_index = 1 + else - ..() + mode_index++ + + toolmode = modes[mode_index] + to_chat(user,"\The [src] is now set to [toolmode].") + + accepting_refs = (toolmode == MULTITOOL_MODE_INTCIRCUITS) + + return /obj/item/device/multitool/cyborg name = "multitool" @@ -44,4 +75,4 @@ icon = 'icons/obj/abductor.dmi' icon_state = "multitool" toolspeed = 0.1 - origin_tech = list(TECH_MAGNET = 5, TECH_ENGINEERING = 5) \ No newline at end of file + origin_tech = list(TECH_MAGNET = 5, TECH_ENGINEERING = 5) diff --git a/code/modules/integrated_electronics/core/assemblies.dm b/code/modules/integrated_electronics/core/assemblies.dm index d236dc9da7..8367e2096a 100644 --- a/code/modules/integrated_electronics/core/assemblies.dm +++ b/code/modules/integrated_electronics/core/assemblies.dm @@ -247,7 +247,7 @@ return TRUE else if(istype(I, /obj/item/integrated_circuit)) - if(!user.unEquip(I)) + if(!user.unEquip(I) && !istype(user, /mob/living/silicon/robot)) //Robots cannot de-equip items in grippers. return FALSE if(add_circuit(I, user)) to_chat(user, "You slide \the [I] inside \the [src].") @@ -323,6 +323,12 @@ if(choice) choice.ask_for_input(user) +/obj/item/device/electronic_assembly/attack_robot(mob/user as mob) + if(Adjacent(user)) + return attack_self(user) + else + return ..() + /obj/item/device/electronic_assembly/emp_act(severity) ..() for(var/atom/movable/AM in contents) diff --git a/code/modules/integrated_electronics/core/assemblies/generic.dm b/code/modules/integrated_electronics/core/assemblies/generic.dm index 8929b69d78..2508f9919d 100644 --- a/code/modules/integrated_electronics/core/assemblies/generic.dm +++ b/code/modules/integrated_electronics/core/assemblies/generic.dm @@ -215,6 +215,8 @@ user.visible_message("\The [user] attaches \the [src] to the wall.", "You attach \the [src] to the wall.", "You hear clicking.") + if(istype(user, /mob/living/silicon/robot)) //Robots cannot unequip/drop items, for Safety Reasons. + forceMove(T) user.drop_item(T) anchored = TRUE on_anchored() diff --git a/code/modules/integrated_electronics/core/integrated_circuit.dm b/code/modules/integrated_electronics/core/integrated_circuit.dm index d612bd7211..5c83c1c399 100644 --- a/code/modules/integrated_electronics/core/integrated_circuit.dm +++ b/code/modules/integrated_electronics/core/integrated_circuit.dm @@ -233,7 +233,7 @@ a creative player the means to solve many problems. Circuits are held inside an else var/datum/integrated_io/io = pin - io.ask_for_pin_data(usr) // The pins themselves will determine how to ask for data, and will validate the data. + io.ask_for_pin_data(usr, held_item) // The pins themselves will determine how to ask for data, and will validate the data. /* if(io.io_type == DATA_CHANNEL) diff --git a/code/modules/integrated_electronics/core/pins.dm b/code/modules/integrated_electronics/core/pins.dm index ef6f0a6dbc..ddc0b06f8a 100644 --- a/code/modules/integrated_electronics/core/pins.dm +++ b/code/modules/integrated_electronics/core/pins.dm @@ -173,7 +173,7 @@ list[]( return !isnull(data) // This proc asks for the data to write, then writes it. -/datum/integrated_io/proc/ask_for_pin_data(mob/user) +/datum/integrated_io/proc/ask_for_pin_data(mob/user, obj/item/I) var/new_data = ask_for_data_type(user) write_data_to_pin(new_data) diff --git a/code/modules/integrated_electronics/core/printer.dm b/code/modules/integrated_electronics/core/printer.dm index fb9bfb5095..c2c70985c5 100644 --- a/code/modules/integrated_electronics/core/printer.dm +++ b/code/modules/integrated_electronics/core/printer.dm @@ -27,6 +27,12 @@ can_clone = TRUE debug = TRUE +/obj/item/device/integrated_circuit_printer/attack_robot(mob/user as mob) + if(Adjacent(user)) + return interact(user) + else + return ..() + /obj/item/device/integrated_circuit_printer/attackby(var/obj/item/O, var/mob/user) if(istype(O,/obj/item/stack/material)) var/obj/item/stack/material/stack = O @@ -146,6 +152,8 @@ return if(!debug) + if(!Adjacent(usr)) + to_chat(usr, "You are too far away from \the [src].") if(metal - cost < 0) to_chat(usr, "You need [cost] metal to build that!.") return 1 diff --git a/code/modules/integrated_electronics/core/special_pins/ref_pin.dm b/code/modules/integrated_electronics/core/special_pins/ref_pin.dm index 461965f254..bde09fdf0e 100644 --- a/code/modules/integrated_electronics/core/special_pins/ref_pin.dm +++ b/code/modules/integrated_electronics/core/special_pins/ref_pin.dm @@ -2,8 +2,15 @@ /datum/integrated_io/ref name = "ref pin" -/datum/integrated_io/ref/ask_for_pin_data(mob/user) // This clears the pin. - write_data_to_pin(null) +/datum/integrated_io/ref/ask_for_pin_data(mob/user, obj/item/I) + if(istype(I, /obj/item/device/multitool)) + var/obj/item/device/multitool/tool = I + write_data_to_pin(tool.weakref_wiring) + else if(istype(I, /obj/item/device/integrated_electronics/debugger)) + var/obj/item/device/integrated_electronics/debugger/tool = I + write_data_to_pin(tool.data_to_write) + else + write_data_to_pin(null) /datum/integrated_io/ref/write_data_to_pin(var/new_data) if(isnull(new_data) || isweakref(new_data)) @@ -11,4 +18,4 @@ holder.on_data_written() /datum/integrated_io/ref/display_pin_type() - return IC_FORMAT_REF \ No newline at end of file + return IC_FORMAT_REF diff --git a/code/modules/integrated_electronics/core/tools.dm b/code/modules/integrated_electronics/core/tools.dm index eb42d92dda..dd270ee326 100644 --- a/code/modules/integrated_electronics/core/tools.dm +++ b/code/modules/integrated_electronics/core/tools.dm @@ -170,6 +170,7 @@ /obj/item/device/multitool + var/accepting_refs var/datum/integrated_io/selected_io = null var/mode = 0 @@ -190,6 +191,10 @@ else if(buffer || connecting || connectable) icon_state = "multitool_tracking_fail" + else if(accepting_refs) + icon_state = "multitool_ref_scan" + else if(weakref_wiring) + icon_state = "multitool_no_camera" else icon_state = "multitool" @@ -239,7 +244,13 @@ io1.holder.interact(user) // This is to update the UI. update_icon() - +/obj/item/device/multitool/afterattack(atom/target, mob/living/user, proximity) + if(accepting_refs && toolmode == MULTITOOL_MODE_INTCIRCUITS && proximity) + weakref_wiring = weakref(target) + visible_message("[user] slides \a [src]'s over \the [target].") + to_chat(user, "You set \the [src]'s memory to a reference to [target.name] \[Ref\]. The ref scanner is \ + now off.") + accepting_refs = 0 diff --git a/code/modules/mob/living/silicon/robot/drone/drone_items.dm b/code/modules/mob/living/silicon/robot/drone/drone_items.dm index 20087b19bb..670087dc51 100644 --- a/code/modules/mob/living/silicon/robot/drone/drone_items.dm +++ b/code/modules/mob/living/silicon/robot/drone/drone_items.dm @@ -3,6 +3,8 @@ /obj/item/weapon/gripper name = "magnetic gripper" desc = "A simple grasping tool specialized in construction and engineering work." + description_info = "Ctrl-Clicking on the gripper will drop whatever it is holding.
\ + Using an object on the gripper will interact with the item inside it, if it exists, instead." icon = 'icons/obj/device.dmi' icon_state = "gripper" @@ -26,6 +28,23 @@ var/force_holder = null // +/obj/item/weapon/gripper/examine(mob/user) + ..() + if(wrapped) + to_chat(user, "\The [src] is holding \the [wrapped].") + wrapped.examine(user) + +/obj/item/weapon/gripper/CtrlClick(mob/user) + drop_item() + return + +/obj/item/weapon/gripper/omni + name = "omni gripper" + desc = "A strange grasping tool that can hold anything a human can, but still maintains the limitations of application its more limited cousins have." + icon_state = "gripper-omni" + + can_hold = list(/obj/item) // Testing and Event gripper. + // VEEEEERY limited version for mining borgs. Basically only for swapping cells and upgrading the drills. /obj/item/weapon/gripper/miner name = "drill maintenance gripper" @@ -84,7 +103,28 @@ /obj/item/weapon/disposable_teleporter/slime, /obj/item/slimepotion, /obj/item/slime_extract, - /obj/item/weapon/reagent_containers/food/snacks/monkeycube, + /obj/item/weapon/reagent_containers/food/snacks/monkeycube + + ) + +/obj/item/weapon/gripper/circuit + name = "circuit assembly gripper" + icon_state = "gripper-circ" + desc = "A complex grasping tool used for working with circuitry." + + can_hold = list( + /obj/item/weapon/cell/device, + /obj/item/device/electronic_assembly, + /obj/item/device/assembly/electronic_assembly, + /obj/item/clothing/under/circuitry, + /obj/item/clothing/gloves/circuitry, + /obj/item/clothing/glasses/circuitry, + /obj/item/clothing/shoes/circuitry, + /obj/item/clothing/head/circuitry, + /obj/item/clothing/ears/circuitry, + /obj/item/clothing/suit/circuitry, + /obj/item/weapon/implant/integrated_circuit, + /obj/item/integrated_circuit ) @@ -178,6 +218,21 @@ return wrapped.attack_self(user) return ..() +/obj/item/weapon/gripper/attackby(var/obj/item/O, var/mob/user) + if(wrapped) // We're interacting with the item inside. If you can hold a cup with 2 fingers and stick a straw in it, you could do that with a gripper and another robotic arm. + wrapped.loc = src.loc + var/resolved = wrapped.attackby(O, user) + if(QDELETED(wrapped) || wrapped.loc != src.loc) //Juuuust in case. + wrapped = null + if(!resolved && wrapped && O) + O.afterattack(wrapped,user,1) + if(QDELETED(wrapped) || wrapped.loc != src.loc) // I don't know of a nicer way to do this. + wrapped = null + if(wrapped) + wrapped.loc = src + return resolved + return ..() + /obj/item/weapon/gripper/verb/drop_item() set name = "Drop Item" @@ -221,10 +276,13 @@ if(QDELETED(wrapped) || wrapped.loc != src.loc) //qdel check here so it doesn't duplicate/spawn ghost items wrapped = null else + wrapped.loc = src.loc //To ensure checks pass. wrapped.attack(M,user) M.attackby(wrapped, user) //attackby reportedly gets procced by being clicked on, at least according to Anewbe. if(QDELETED(wrapped) || wrapped.loc != src.loc) wrapped = null + if(wrapped) //In the event nothing happened to wrapped, go back into the gripper. + wrapped.loc = src return 1 return 0 @@ -249,7 +307,8 @@ wrapped.afterattack(target,user,1) //wrapped's force was set to zero. This resets it to the value it had before. - wrapped.force = force_holder + if(wrapped) + wrapped.force = force_holder force_holder = null //If wrapped was neither deleted nor put into target, put it back into the gripper. if(wrapped && user && (wrapped.loc == user)) @@ -266,6 +325,10 @@ var/obj/item/I = target + if(I.anchored) + to_chat(user,"You are unable to lift \the [I] from \the [I.loc].") + return + //Check if the item is blacklisted. var/grab = 0 for(var/typepath in can_hold) diff --git a/code/modules/mob/living/silicon/robot/robot_modules/station.dm b/code/modules/mob/living/silicon/robot/robot_modules/station.dm index 2416b339ff..eb288f9046 100644 --- a/code/modules/mob/living/silicon/robot/robot_modules/station.dm +++ b/code/modules/mob/living/silicon/robot/robot_modules/station.dm @@ -417,6 +417,7 @@ var/global/list/robot_modules = list( src.modules += new /obj/item/device/analyzer(src) src.modules += new /obj/item/taperoll/engineering(src) src.modules += new /obj/item/weapon/gripper(src) + src.modules += new /obj/item/weapon/gripper/circuit(src) src.modules += new /obj/item/device/lightreplacer(src) src.modules += new /obj/item/device/pipe_painter(src) src.modules += new /obj/item/device/floor_painter(src) @@ -730,6 +731,7 @@ var/global/list/robot_modules = list( ..() src.modules += new /obj/item/weapon/portable_destructive_analyzer(src) src.modules += new /obj/item/weapon/gripper/research(src) + src.modules += new /obj/item/weapon/gripper/circuit(src) src.modules += new /obj/item/weapon/gripper/no_use/organ/robotics(src) src.modules += new /obj/item/weapon/gripper/no_use/mech(src) src.modules += new /obj/item/weapon/gripper/no_use/loader(src) diff --git a/html/changelogs/Mechoid-Grippers.yml b/html/changelogs/Mechoid-Grippers.yml new file mode 100644 index 0000000000..1b4c6f69b3 --- /dev/null +++ b/html/changelogs/Mechoid-Grippers.yml @@ -0,0 +1,13 @@ + +author: Mechoid + +delete-after: True + + +changes: + - rscadd: "Research and Engineering borgs now have 'Circuit Grippers', used for constructing and operating integrated circuit machinery." + - tweak: "Grippers now allow interaction with their contents, by attacking the gripper itself with an item when one is held. I.E., drawing from a beaker with a syringe." + - tweak: "Grippers now show their held item's examine information when examined. Tab information added." + - tweak: "Cyborgs can now interact with integrated circuit printers and machines when adjacent to them." + - tweak: "Multitools now have a menu to switch modes between standard use and integrated circuit reference scanning. Antag multi-tools untouched for now." + - bugfix: "Integrated circuit printer now respects adjacency, if it is not set to debug." diff --git a/icons/obj/device.dmi b/icons/obj/device.dmi index 1b834792bd..6c697f2777 100644 Binary files a/icons/obj/device.dmi and b/icons/obj/device.dmi differ diff --git a/vorestation.dme b/vorestation.dme index 671199425d..f35684c163 100644 --- a/vorestation.dme +++ b/vorestation.dme @@ -54,6 +54,7 @@ #include "code\__defines\mobs.dm" #include "code\__defines\mobs_vr.dm" #include "code\__defines\nifsoft.dm" +#include "code\__defines\objects.dm" #include "code\__defines\planets.dm" #include "code\__defines\process_scheduler.dm" #include "code\__defines\qdel.dm"