diff --git a/modular_chomp/code/modules/mob/living/silicon/robot/drone/drone.dm b/modular_chomp/code/modules/mob/living/silicon/robot/drone/drone.dm
new file mode 100644
index 0000000000..de8d502665
--- /dev/null
+++ b/modular_chomp/code/modules/mob/living/silicon/robot/drone/drone.dm
@@ -0,0 +1,274 @@
+//Modified copy of regula drone folder
+var/list/mob_hat_cache = list()
+/proc/get_hat_icon(var/obj/item/hat, var/offset_x = 0, var/offset_y = 0)
+ var/t_state = hat.icon_state
+ if(LAZYACCESS(hat.item_state_slots, slot_head_str))
+ t_state = hat.item_state_slots[slot_head_str]
+ else if(hat.item_state)
+ t_state = hat.item_state
+ var/key = "[t_state]_[offset_x]_[offset_y]"
+ if(!mob_hat_cache[key]) // Not ideal as there's no guarantee all hat icon_states
+ var/t_icon = INV_HEAD_DEF_ICON // are unique across multiple dmis, but whatever.
+ if(hat.icon_override)
+ t_icon = hat.icon_override
+ else if(LAZYACCESS(hat.item_icons, slot_head_str))
+ t_icon = hat.item_icons[slot_head_str]
+ var/image/I = image(icon = t_icon, icon_state = t_state)
+ I.pixel_x = offset_x
+ I.pixel_y = offset_y
+ mob_hat_cache[key] = I
+ return mob_hat_cache[key]
+
+/mob/living/silicon/robot/drone/New()
+ ..()
+ verbs += /mob/living/proc/ventcrawl
+ verbs += /mob/living/proc/hide
+ remove_language("Robot Talk")
+ add_language("Robot Talk", 0)
+ add_language("Drone Talk", 1)
+ serial_number = rand(0,999)
+
+ //They are unable to be upgraded, so let's give them a bit of a better battery.
+ cell.maxcharge = 10000
+ cell.charge = 10000
+
+ // NO BRAIN.
+ mmi = null
+
+ //We need to screw with their HP a bit. They have around one fifth as much HP as a full borg.
+ for(var/V in components) if(V != "power cell")
+ var/datum/robot_component/C = components[V]
+ C.max_damage = 10
+
+ verbs -= /mob/living/silicon/robot/verb/Namepick
+
+ if(can_pick_shell)
+ var/random = pick(shell_types)
+ icon_state = shell_types[random]
+ shell_accessories = list("[icon_state]-eyes-blue")
+
+ updateicon()
+ updatename()
+
+/mob/living/silicon/robot/drone/updateicon()
+ cut_overlays()
+
+ if(islist(shell_accessories))
+ add_overlay(shell_accessories)
+
+ if(hat) // Let the drones wear hats.
+ add_overlay(get_hat_icon(hat, hat_x_offset, hat_y_offset))
+
+/mob/living/silicon/robot/drone/verb/pick_shell()
+ set name = "Customize Appearance"
+ set category = "Robot Commands"
+
+ if(!can_pick_shell)
+ to_chat(src, "You already selected a shell or this drone type isn't customizable.")
+ return
+
+ var/list/choices = shell_types.Copy()
+
+ if(can_blitz)
+ choices["Blitz"] = "blitzshell"
+
+ var/shell_choice = tgui_input_list(src, "Select a shell. NOTE: You can only do this once during this drone-lifetime.", "Customize Shell", choices)
+ if(!shell_choice)
+ return
+
+ icon_state = choices[shell_choice]
+
+ // If you add more, datumize these. Having 'basically two' is not enough to make me bother though.
+ shell_accessories = null
+ if(icon_state in list("repairbot", "maintbot"))
+ var/eye_color = tgui_input_list(src, "Select eye color:", "Eye Color", list("blue", "red", "orange", "green", "violet"))
+ if(eye_color)
+ LAZYADD(shell_accessories, "[icon_state]-eyes-[eye_color]")
+ if(icon_state == "maintbot")
+ var/armor_color = tgui_input_list(src, "Select plating color:", "Eye Color", list("blue", "red", "orange", "green", "brown"))
+ if(armor_color)
+ LAZYADD(shell_accessories, "[icon_state]-shell-[armor_color]")
+
+ can_pick_shell = FALSE
+ updateicon()
+
+/mob/living/silicon/robot/drone/proc/wear_hat(var/obj/item/new_hat)
+ if(hat)
+ return
+ hat = new_hat
+ new_hat.loc = src
+ updateicon()
+
+//Drones cannot be upgraded with borg modules so we need to catch some items before they get used in ..().
+/mob/living/silicon/robot/drone/attackby(var/obj/item/weapon/W, var/mob/user)
+
+ //Early return handler
+ if(handle_attackby_return(W,user))
+ return
+ if(user.a_intent == "help" && istype(W, /obj/item/clothing/head))
+ equip_hat(W,user)
+ ..()
+
+//Denesting for the above code
+
+/mob/living/silicon/robot/drone/proc/equip_hat(var/obj/item/clothing/head/W, var/mob/user)
+ if(hat)
+ to_chat(user, "\The [src] is already wearing \the [hat].")
+ return
+ user.unEquip(W)
+ wear_hat(W)
+ user.visible_message("\The [user] puts \the [W] on \the [src].")
+ return
+
+/mob/living/silicon/robot/drone/proc/handle_attackby_return(var/obj/item/W, var/mob/user)
+ var/hint
+ if(W.is_crowbar())
+ hint = "\The [src] is hermetically sealed. You can't open the case."
+ else if(istype(W, /obj/item/borg/upgrade/))
+ hint = "\The [src] is not compatible with \the [W]."
+ else if(stat == 2)
+ hint = handle_try_reboot(W,user) //ugly as shit nesting otherwise
+
+ if(hint!="MSG-SKIP")
+ to_chat(usr,hint)
+ return hint //null if we dont handle early return
+
+/mob/living/silicon/robot/drone/proc/handle_try_reboot(var/obj/item/W,var/mob/user)
+ var/datum/gender/TU = gender_datums[user.get_visible_gender()]
+ if(!istype(W, /obj/item/weapon/card/id)&&!istype(W, /obj/item/device/pda))
+ return handle_try_shutdown(user, TU)
+
+ if(!config.allow_drone_spawn || emagged || health < -35) //It's dead, Dave.
+ return "The interface is fried, and a distressing burned smell wafts from the robot's interior. You're not rebooting this one."
+
+ if(!allowed(usr))
+ return "Access denied."
+
+ user.visible_message("\The [user] swipes [TU.his] ID card through \the [src], attempting to reboot it.", ">You swipe your ID card through \the [src], attempting to reboot it.")
+ var/drones = 0
+ for(var/mob/living/silicon/robot/drone/D in player_list)
+ drones++
+ if(drones < config.max_maint_drones)
+ request_player()
+ return "MSG-SKIP"
+
+/mob/living/silicon/robot/drone/proc/handle_try_shutdown(var/mob/user, var/datum/gender/TU)
+ user.visible_message("\The [user] swipes [TU.his] ID card through \the [src], attempting to shut it down.", "You swipe your ID card through \the [src], attempting to shut it down.")
+ if(emagged)
+ return "MSG-SKIP"
+
+ if(allowed(usr))
+ shut_down()
+ return "MSG-SKIP"
+ else
+ return "Access denied."
+
+
+//ATTACKBY HANDLERS END
+
+
+/mob/living/silicon/robot/drone/emag_act(var/remaining_charges, var/mob/user)
+ if(!client || stat == 2)
+ to_chat(user, "There's not much point subverting this heap of junk.")
+ return
+
+ if(emagged)
+ to_chat(src, "\The [user] attempts to load subversive software into you, but your hacked subroutines ignore the attempt.")
+ to_chat(user, "You attempt to subvert [src], but the sequencer has no effect.")
+ return
+
+ to_chat(user, "You swipe the sequencer across [src]'s interface and watch its eyes flicker.")
+
+ to_chat(src, "You feel a sudden burst of malware loaded into your execute-as-root buffer. Your tiny brain methodically parses, loads and executes the script.")
+
+ log_game("[key_name(user)] emagged drone [key_name(src)]. Laws overridden.")
+ var/time = time2text(world.realtime,"hh:mm:ss")
+ lawchanges.Add("[time] : [user.name]([user.key]) emagged [name]([key])")
+
+ emagged = 1
+ lawupdate = 0
+ connected_ai = null
+ clear_supplied_laws()
+ clear_inherent_laws()
+ laws = new /datum/ai_laws/syndicate_override
+ var/datum/gender/TU = gender_datums[user.get_visible_gender()]
+ set_zeroth_law("Only [user.real_name] and people [TU.he] designate[TU.s] as being such are operatives.")
+
+ to_chat(src, "Obey these laws:")
+ laws.show_laws(src)
+ to_chat(src, "ALERT: [user.real_name] is your new master. Obey your new laws and \his commands.")
+ return 1
+
+//DRONE LIFE/DEATH
+
+//For some goddamn reason robots have this hardcoded. Redefining it for our fragile friends here.
+/mob/living/silicon/robot/drone/updatehealth()
+ if(status_flags & GODMODE)
+ health = maxHealth
+ set_stat(CONSCIOUS)
+ return
+ health = maxHealth - (getBruteLoss() + getFireLoss())
+ return
+
+//Easiest to check this here, then check again in the robot proc.
+//Standard robots use config for crit, which is somewhat excessive for these guys.
+//Drones killed by damage will gib.
+/mob/living/silicon/robot/drone/handle_regular_status_updates()
+ var/turf/T = get_turf(src)
+ if(!T || health <= -35 )
+ timeofdeath = world.time
+ death() //Possibly redundant, having trouble making death() cooperate.
+ gib()
+ return
+ ..()
+
+//CONSOLE PROCS
+/mob/living/silicon/robot/drone/proc/law_resync()
+ if(stat == DEAD)
+ return //opting for an early return here to remove unneeded nesting
+ if(emagged)
+ to_chat(src, "You feel something attempting to modify your programming, but your hacked subroutines are unaffected.")
+ else
+ to_chat(src, "A reset-to-factory directive packet filters through your data connection, and you obediently modify your programming to suit it.")
+ full_law_reset()
+ show_laws()
+
+/mob/living/silicon/robot/drone/proc/shut_down()
+ if(stat == DEAD)
+ return //opting for an early return here to remove unneeded nesting
+ if(emagged)
+ to_chat(src, "You feel a system kill order percolate through your tiny brain, but it doesn't seem like a good idea to you.")
+ else
+ to_chat(src, "You feel a system kill order percolate through your tiny brain, and you obediently destroy yourself.")
+ death()
+
+/mob/living/silicon/robot/drone/proc/full_law_reset()
+ clear_supplied_laws(1)
+ clear_inherent_laws(1)
+ clear_ion_laws(1)
+ if(faction == "malf_drone")
+ laws = new /datum/ai_laws/nanotrasen/malfunction
+ foreign_droid = TRUE
+ else
+ laws = new law_type
+
+//Reboot procs.
+
+
+
+/mob/living/silicon/robot/drone/proc/transfer_personality(var/client/player)
+
+ if(!player) return
+
+ src.ckey = player.ckey
+
+ if(player.mob && player.mob.mind)
+ player.mob.mind.transfer_to(src)
+
+ lawupdate = 0
+ to_chat(src, "Systems rebooted. Loading base pattern maintenance protocol...")
+ spawn(3 SECONDS)
+ full_law_reset()
+ to_chat(src,"Loaded.")
+ spawn(4 SECONDS)
+ welcome_drone()
diff --git a/modular_chomp/code/modules/mob/living/silicon/robot/drone/drone_abilities.dm b/modular_chomp/code/modules/mob/living/silicon/robot/drone/drone_abilities.dm
new file mode 100644
index 0000000000..7bc7b148ce
--- /dev/null
+++ b/modular_chomp/code/modules/mob/living/silicon/robot/drone/drone_abilities.dm
@@ -0,0 +1,36 @@
+//Modified copy of regula drone folder
+// DRONE ABILITIES
+/mob/living/silicon/robot/drone/verb/set_mail_tag()
+ set name = "Set Mail Tag"
+ set desc = "Tag yourself for delivery through the disposals system."
+ set category = "Robot Commands"
+
+ var/new_tag = tgui_input_list(usr, "Select the desired destination.", "Set Mail Tag", GLOB.tagger_locations)
+
+ if(!new_tag)
+ mail_destination = ""
+ return
+
+ to_chat(src, "You configure your internal beacon, tagging yourself for delivery to '[new_tag]'.")
+ mail_destination = new_tag
+
+ //Auto flush if we use this verb inside a disposal chute.
+ var/obj/machinery/disposal/D = src.loc
+ if(istype(D))
+ to_chat(src, "\The [D] acknowledges your signal.")
+ D.flush_count = D.flush_every_ticks
+
+ return
+
+/mob/living/silicon/robot/drone/MouseDrop(var/atom/over_object)
+ var/mob/living/carbon/human/H = over_object
+ if(!istype(H) || !Adjacent(H))
+ return ..()
+ if(H.a_intent == "grab" && hat && !(H.l_hand && H.r_hand))
+ H.put_in_hands(hat)
+ H.visible_message("\The [H] removes \the [src]'s [hat].")
+ hat = null
+ updateicon()
+ return
+ else
+ return ..()
\ No newline at end of file
diff --git a/modular_chomp/code/modules/mob/living/silicon/robot/drone/drone_console.dm b/modular_chomp/code/modules/mob/living/silicon/robot/drone/drone_console.dm
new file mode 100644
index 0000000000..acaa73c4eb
--- /dev/null
+++ b/modular_chomp/code/modules/mob/living/silicon/robot/drone/drone_console.dm
@@ -0,0 +1,124 @@
+//Modified copy of regula drone folder
+/obj/machinery/computer/drone_control
+ name = "Maintenance Drone Control"
+ desc = "Used to monitor the station's drone population and the assembler that services them."
+ icon_keyboard = "power_key"
+ icon_screen = "generic" //VOREStation Edit
+ req_access = list(access_engine_equip)
+ circuit = /obj/item/weapon/circuitboard/drone_control
+
+ //Used when pinging drones.
+ var/drone_call_area = "Engineering"
+ //Used to enable or disable drone fabrication.
+ var/obj/machinery/drone_fabricator/dronefab
+
+/obj/machinery/computer/drone_control/attack_ai(var/mob/user as mob)
+ return src.attack_hand(user)
+
+/obj/machinery/computer/drone_control/tgui_status(mob/user)
+ if(!allowed(user))
+ return STATUS_CLOSE
+ return ..()
+
+/obj/machinery/computer/drone_control/attack_hand(var/mob/user as mob)
+ if(..())
+ return
+
+ tgui_interact(user)
+
+/obj/machinery/computer/drone_control/tgui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(!ui)
+ ui = new(user, src, "DroneConsole", name)
+ ui.open()
+
+/obj/machinery/computer/drone_control/tgui_data(mob/user)
+ var/list/data = list()
+
+ var/list/drones = list()
+ for(var/mob/living/silicon/robot/drone/D in mob_list)
+ //VOREStation Edit - multiz lol
+ if(!(D.z in using_map.get_map_levels(z, TRUE, 0)))
+ continue
+ //VOREStation Edit - multiz lol
+ if(D.foreign_droid)
+ continue
+
+ drones.Add(list(list(
+ "name" = D.real_name,
+ "active" = D.stat != 2,
+ "charge" = D.cell.charge,
+ "maxCharge" = D.cell.maxcharge,
+ "loc" = "[get_area(D)]",
+ "ref" = "\ref[D]",
+ )))
+ data["drones"] = drones
+
+ data["fabricator"] = dronefab
+ data["fabPower"] = dronefab?.produce_drones
+
+ data["areas"] = GLOB.tagger_locations
+ data["selected_area"] = "[drone_call_area]"
+
+ return data
+
+/obj/machinery/computer/drone_control/tgui_act(action, params)
+ if(..())
+ return TRUE
+
+ switch(action)
+ if("set_dcall_area")
+ var/t_area = params["area"]
+ if(!t_area || !(t_area in GLOB.tagger_locations))
+ return
+
+ drone_call_area = t_area
+ to_chat(usr, "You set the area selector to [drone_call_area].")
+
+ if("ping")
+ to_chat(usr, "You issue a maintenance request for all active drones, highlighting [drone_call_area].")
+ for(var/mob/living/silicon/robot/drone/D in player_list)
+ if(D.stat == 0)
+ to_chat(D, "-- Maintenance drone presence requested in: [drone_call_area].")
+
+ if("resync")
+ var/mob/living/silicon/robot/drone/D = locate(params["ref"])
+
+ if(D.stat != 2)
+ to_chat(usr, "You issue a law synchronization directive for the drone.")
+ D.law_resync()
+
+ if("shutdown")
+ var/mob/living/silicon/robot/drone/D = locate(params["ref"])
+
+ if(D.stat != 2)
+ to_chat(usr, "You issue a kill command for the unfortunate drone.")
+ message_admins("[key_name_admin(usr)] issued kill order for drone [key_name_admin(D)] from control console.")
+ log_game("[key_name(usr)] issued kill order for [key_name(src)] from control console.")
+ D.shut_down()
+
+ if("search_fab")
+ if(dronefab)
+ return
+
+ for(var/obj/machinery/drone_fabricator/fab in oview(3,src))
+ if(fab.stat & NOPOWER)
+ continue
+
+ dronefab = fab
+ to_chat(usr, "Drone fabricator located.")
+ return
+
+ to_chat(usr, "Unable to locate drone fabricator.")
+
+ if("toggle_fab")
+ if(!dronefab)
+ return
+
+ if(get_dist(src,dronefab) > 3)
+ dronefab = null
+ to_chat(usr, "Unable to locate drone fabricator.")
+ return
+
+ dronefab.produce_drones = !dronefab.produce_drones
+ to_chat(usr, "You [dronefab.produce_drones ? "enable" : "disable"] drone production in the nearby fabricator.")
diff --git a/modular_chomp/code/modules/mob/living/silicon/robot/drone/drone_damage.dm b/modular_chomp/code/modules/mob/living/silicon/robot/drone/drone_damage.dm
new file mode 100644
index 0000000000..6fd363803d
--- /dev/null
+++ b/modular_chomp/code/modules/mob/living/silicon/robot/drone/drone_damage.dm
@@ -0,0 +1,25 @@
+//Modified copy of regula drone folder
+//Redefining some robot procs, since drones can't be repaired and really shouldn't take component damage.
+/mob/living/silicon/robot/drone/take_overall_damage(var/brute = 0, var/burn = 0, var/sharp = FALSE, var/used_weapon = null)
+ bruteloss += brute
+ fireloss += burn
+
+/mob/living/silicon/robot/drone/heal_overall_damage(var/brute, var/burn)
+
+ bruteloss -= brute
+ fireloss -= burn
+
+ if(bruteloss<0) bruteloss = 0
+ if(fireloss<0) fireloss = 0
+
+/mob/living/silicon/robot/drone/take_organ_damage(var/brute = 0, var/burn = 0, var/sharp = FALSE, var/emp = 0)
+ take_overall_damage(brute,burn)
+
+/mob/living/silicon/robot/drone/heal_organ_damage(var/brute, var/burn)
+ heal_overall_damage(brute,burn)
+
+/mob/living/silicon/robot/drone/getFireLoss()
+ return fireloss
+
+/mob/living/silicon/robot/drone/getBruteLoss()
+ return bruteloss
\ No newline at end of file
diff --git a/modular_chomp/code/modules/mob/living/silicon/robot/drone/drone_ghostjoin.dm b/modular_chomp/code/modules/mob/living/silicon/robot/drone/drone_ghostjoin.dm
new file mode 100644
index 0000000000..797b8ab213
--- /dev/null
+++ b/modular_chomp/code/modules/mob/living/silicon/robot/drone/drone_ghostjoin.dm
@@ -0,0 +1,87 @@
+//Triggered by other
+/mob/living/silicon/robot/drone/proc/request_player()
+ for(var/mob/observer/dead/O in player_list)
+ if(jobban_isbanned(O, "Cyborg") || !O.client || !(O.client.prefs.be_special & BE_PAI))
+ continue
+ question(O.client)
+
+/mob/living/silicon/robot/drone/proc/question(var/client/C)
+ spawn(0)
+ if(!C || jobban_isbanned(C,"Cyborg")) return
+ var/response = tgui_alert(C, "Someone is attempting to reboot a maintenance drone. Would you like to play as one?", "Maintenance drone reboot", list("Yes", "No", "Never for this round"))
+ if(!C || ckey)
+ return
+ if(response == "Yes")
+ transfer_personality(C)
+ else if (response == "Never for this round")
+ C.prefs.be_special ^= BE_PAI
+
+//Triggered by self
+/mob/observer/dead/verb/join_as_drone()
+ set category = "Ghost"
+ set name = "Join As Drone"
+ set desc = "If there is a powered, enabled fabricator in the game world with a prepared chassis, join as a maintenance drone."
+
+ if(ticker.current_state < GAME_STATE_PLAYING)
+ to_chat(src, "The game hasn't started yet!")
+ return
+
+ if(!(config.allow_drone_spawn))
+ to_chat(src, "That verb is not currently permitted.")
+ return
+
+ if (!src.stat)
+ return
+
+ if (usr != src)
+ return 0 //something is terribly wrong
+
+ if(jobban_isbanned(src,"Cyborg"))
+ to_chat(usr, "You are banned from playing synthetics and cannot spawn as a drone.")
+ return
+
+ // VOREStation Addition Start
+ if(config.use_age_restriction_for_jobs && isnum(src.client.player_age))
+ var/time_till_play = max(0, 3 - src.client.player_age)
+ if(time_till_play)
+ to_chat(usr, "You have not been playing on the server long enough to join as drone.")
+ return
+ // VOREStation Addition End
+
+ if(!MayRespawn(1))
+ return
+
+ var/deathtime = world.time - src.timeofdeath
+ var/deathtimeminutes = round(deathtime / (1 MINUTE))
+ var/pluralcheck = "minute"
+ if(deathtimeminutes == 0)
+ pluralcheck = ""
+ else if(deathtimeminutes == 1)
+ pluralcheck = " [deathtimeminutes] minute and"
+ else if(deathtimeminutes > 1)
+ pluralcheck = " [deathtimeminutes] minutes and"
+ var/deathtimeseconds = round((deathtime - deathtimeminutes * 1 MINUTE) / 10,1)
+
+ if (deathtime < 5 MINUTES)
+ to_chat(usr, "You have been dead for[pluralcheck] [deathtimeseconds] seconds.")
+ to_chat(usr, "You must wait 5 minutes to respawn as a drone!")
+ return
+
+ var/list/all_fabricators = list()
+ for(var/obj/machinery/drone_fabricator/DF in machines)
+ if(DF.stat & NOPOWER || !DF.produce_drones)
+ continue
+ if(DF.drone_progress >= 100)
+ all_fabricators[DF.fabricator_tag] = DF
+
+ if(!all_fabricators.len)
+ to_chat(src, "There are no available drone spawn points, sorry.")
+ return
+
+ var/choice = tgui_input_list(src, "Which fabricator do you wish to use?", "Fabricator Choice", all_fabricators)
+ if(choice)
+ var/faction
+ if(choice == "Unknown")
+ faction = "malf_drone"
+ var/obj/machinery/drone_fabricator/chosen_fabricator = all_fabricators[choice]
+ chosen_fabricator.create_drone(src.client,faction)
\ No newline at end of file
diff --git a/modular_chomp/code/modules/mob/living/silicon/robot/drone/drone_items.dm b/modular_chomp/code/modules/mob/living/silicon/robot/drone/drone_items.dm
index b8dadbb3a8..54465130be 100644
--- a/modular_chomp/code/modules/mob/living/silicon/robot/drone/drone_items.dm
+++ b/modular_chomp/code/modules/mob/living/silicon/robot/drone/drone_items.dm
@@ -1,3 +1,603 @@
+//Modified copy of regula drone folder
+//Simple borg hand.
+//Limited use.
+/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"
+ flags = NOBLUDGEON
+
+ //Has a list of items that it can hold.
+ var/list/can_hold = list(
+ /obj/item/weapon/cell,
+ /obj/item/weapon/airlock_electronics,
+ /obj/item/weapon/tracker_electronics,
+ /obj/item/weapon/module/power_control,
+ /obj/item/weapon/stock_parts,
+ /obj/item/frame,
+ /obj/item/weapon/camera_assembly,
+ /obj/item/weapon/tank,
+ /obj/item/weapon/circuitboard,
+ /obj/item/weapon/smes_coil,
+ /obj/item/weapon/fuel_assembly,
+ /obj/item/weapon/ore/bluespace_crystal
+ ) // CHOMPEdit - Buffing the gripper to allow bluespace crystal use for telesci building.
+
+ var/obj/item/wrapped = null // Item currently being held.
+
+ var/force_holder = null //
+
+/obj/item/weapon/gripper/examine(mob/user)
+ . = ..()
+ if(wrapped)
+ . += "\The [src] is holding \the [wrapped]."
+ . += wrapped.examine(user)
+
+/obj/item/weapon/gripper/CtrlClick(mob/user)
+ drop_item()
+ return
+
+/obj/item/weapon/gripper/AltClick(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"
+ desc = "A simple grasping tool for the maintenance of heavy drilling machines."
+ icon_state = "gripper-mining"
+
+ can_hold = list(
+ /obj/item/weapon/cell,
+ /obj/item/weapon/stock_parts
+ )
+
+/obj/item/weapon/gripper/security
+ name = "security gripper"
+ desc = "A simple grasping tool for corporate security work."
+ icon_state = "gripper-sec"
+
+ can_hold = list(
+ /obj/item/weapon/paper,
+ /obj/item/weapon/paper_bundle,
+ /obj/item/weapon/pen,
+ /obj/item/weapon/sample,
+ /obj/item/weapon/forensics/sample_kit,
+ /obj/item/device/taperecorder,
+ /obj/item/device/tape,
+ /obj/item/device/uv_light
+ )
+
+/obj/item/weapon/gripper/paperwork
+ name = "paperwork gripper"
+ desc = "A simple grasping tool for clerical work."
+
+ can_hold = list(
+ /obj/item/weapon/clipboard,
+ /obj/item/weapon/paper,
+ /obj/item/weapon/paper_bundle,
+ /obj/item/weapon/card/id,
+ /obj/item/weapon/book,
+ /obj/item/weapon/newspaper
+ )
+
+/obj/item/weapon/gripper/medical
+ name = "medical gripper"
+ desc = "A simple grasping tool for medical work."
+
+ can_hold = list(
+ /obj/item/weapon/reagent_containers/glass,
+ /obj/item/weapon/storage/pill_bottle,
+ /obj/item/weapon/reagent_containers/pill,
+ /obj/item/weapon/reagent_containers/blood,
+ /obj/item/device/nif, //Chompedit Add Nif handling
+ /obj/item/stack/material/phoron,
+ /obj/item/weapon/tank/anesthetic,
+ /obj/item/weapon/disk/body_record //Vorestation Edit: this lets you get an empty sleeve or help someone else
+ )
+
+/obj/item/weapon/gripper/research //A general usage gripper, used for toxins/robotics/xenobio/etc
+ name = "scientific gripper"
+ icon_state = "gripper-sci"
+ desc = "A simple grasping tool suited to assist in a wide array of research applications."
+
+ can_hold = list(
+ /obj/item/weapon/cell,
+ /obj/item/weapon/stock_parts,
+ /obj/item/device/mmi,
+ /obj/item/robot_parts,
+ /obj/item/borg/upgrade,
+ /obj/item/device/flash, //to build borgs,
+ /obj/item/weapon/disk,
+ /obj/item/weapon/circuitboard,
+ /obj/item/weapon/reagent_containers/glass,
+ /obj/item/device/assembly/prox_sensor,
+ /obj/item/device/healthanalyzer, //to build medibots,
+ /obj/item/slime_cube,
+ /obj/item/slime_crystal,
+ /obj/item/weapon/disposable_teleporter/slime,
+ /obj/item/slimepotion,
+ /obj/item/slime_extract,
+ /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
+
+ )
+
+/obj/item/weapon/gripper/service //Used to handle food, drinks, and seeds.
+ name = "service gripper"
+ icon_state = "gripper"
+ desc = "A simple grasping tool used to perform tasks in the service sector, such as handling food, drinks, and seeds."
+
+ can_hold = list(
+ /obj/item/weapon/reagent_containers/glass,
+ /obj/item/weapon/reagent_containers/food,
+ /obj/item/seeds,
+ /obj/item/weapon/grown,
+ /obj/item/trash,
+ /obj/item/weapon/reagent_containers/cooking_container
+ )
+
+/obj/item/weapon/gripper/gravekeeper //Used for handling grave things, flowers, etc.
+ name = "grave gripper"
+ icon_state = "gripper"
+ desc = "A specialized grasping tool used in the preparation and maintenance of graves."
+
+ can_hold = list(
+ /obj/item/seeds,
+ /obj/item/weapon/grown,
+ /obj/item/weapon/material/gravemarker
+ )
+
+/obj/item/weapon/gripper/no_use/organ
+ name = "organ gripper"
+ icon_state = "gripper-flesh"
+ desc = "A specialized grasping tool used to preserve and manipulate organic material."
+
+ can_hold = list(
+ /obj/item/organ,
+ /obj/item/device/nif //NIFs can be slapped in during surgery
+ )
+
+/obj/item/weapon/gripper/no_use/organ/Entered(var/atom/movable/AM)
+ if(istype(AM, /obj/item/organ))
+ var/obj/item/organ/O = AM
+ O.preserved = 1
+ for(var/obj/item/organ/organ in O)
+ organ.preserved = 1
+ ..()
+
+/obj/item/weapon/gripper/no_use/organ/Exited(var/atom/movable/AM)
+ if(istype(AM, /obj/item/organ))
+ var/obj/item/organ/O = AM
+ O.preserved = 0
+ for(var/obj/item/organ/organ in O)
+ organ.preserved = 0
+ ..()
+
+/obj/item/weapon/gripper/no_use/organ/robotics
+ name = "robotics organ gripper"
+ icon_state = "gripper-flesh"
+ desc = "A specialized grasping tool used in robotics work."
+
+ can_hold = list(
+ /obj/item/organ/external,
+ /obj/item/organ/internal/brain, //to insert into MMIs,
+ /obj/item/organ/internal/cell,
+ /obj/item/organ/internal/eyes/robot,
+ /obj/item/device/nif //NIFs can be slapped in during surgery
+ )
+
+/obj/item/weapon/gripper/no_use/mech
+ name = "exosuit gripper"
+ icon_state = "gripper-mech"
+ desc = "A large, heavy-duty grasping tool used in construction of mechs."
+
+ can_hold = list(
+ /obj/item/mecha_parts/part,
+ //obj/item/mecha_parts/micro/part, //VOREStation Edit: Allow construction of micromechs //CHOMPedit commented micromech stuff, because fuck this trash
+ /obj/item/mecha_parts/mecha_equipment,
+ /obj/item/mecha_parts/mecha_tracking,
+ /obj/item/mecha_parts/component
+ )
+
+/obj/item/weapon/gripper/no_use //Used when you want to hold and put items in other things, but not able to 'use' the item
+
+/obj/item/weapon/gripper/no_use/attack_self(mob/user as mob)
+ return
+
+/obj/item/weapon/gripper/no_use/loader //This is used to disallow building with metal.
+ name = "sheet loader"
+ desc = "A specialized loading device, designed to pick up and insert sheets of materials inside machines."
+ icon_state = "gripper-sheet"
+
+ can_hold = list(
+ /obj/item/stack/material
+ )
+
+/obj/item/weapon/gripper/attack_self(mob/user as mob)
+ if(wrapped)
+ 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_gripper_item()
+
+ set name = "Drop Item"
+ set desc = "Release an item from your magnetic gripper."
+ set category = "Robot Commands"
+
+ drop_item()
+
+/obj/item/weapon/gripper/proc/drop_item()
+ if(!wrapped)
+ //There's some weirdness with items being lost inside the arm. Trying to fix all cases. ~Z
+ for(var/obj/item/thing in src.contents)
+ thing.loc = get_turf(src)
+ return
+
+ if(wrapped.loc != src)
+ wrapped = null
+ return
+
+ to_chat(src.loc, "You drop \the [wrapped].")
+ wrapped.loc = get_turf(src)
+ wrapped = null
+ //update_icon()
+
+/obj/item/weapon/gripper/proc/drop_item_nm()
+
+ if(!wrapped)
+ for(var/obj/item/thing in src.contents)
+ thing.loc = get_turf(src)
+ return
+
+ if(wrapped.loc != src)
+ wrapped = null
+ return
+
+ wrapped.loc = get_turf(src)
+ wrapped = null
+ //update_icon()
+
+/obj/item/weapon/gripper/attack(mob/living/carbon/M as mob, mob/living/carbon/user as mob)
+ if(wrapped) //The force of the wrapped obj gets set to zero during the attack() and afterattack().
+ force_holder = wrapped.force
+ wrapped.force = 0.0
+ 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
+
+/obj/item/weapon/gripper/afterattack(var/atom/target, var/mob/living/user, proximity, params)
+
+ if(!proximity)
+ return // This will prevent them using guns at range but adminbuse can add them directly to modules, so eh.
+
+ //There's some weirdness with items being lost inside the arm. Trying to fix all cases. ~Z
+ if(!wrapped)
+ for(var/obj/item/thing in src.contents)
+ wrapped = thing
+ break
+
+ if(wrapped) //Already have an item.
+ //Temporary put wrapped into user so target's attackby() checks pass.
+ wrapped.loc = user
+
+ //Pass the attack on to the target. This might delete/relocate wrapped.
+ var/resolved = target.attackby(wrapped,user)
+ if(!resolved && wrapped && target)
+ wrapped.afterattack(target,user,1)
+
+ //wrapped's force was set to zero. This resets it to the value it had before.
+ 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))
+ wrapped.loc = src
+ else
+ wrapped = null
+ return
+
+ else if(istype(target,/obj/item)) //Check that we're not pocketing a mob.
+
+ //...and that the item is not in a container.
+ if(!isturf(target.loc))
+ return
+
+ 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)
+ if(istype(I,typepath))
+ grab = 1
+ break
+
+ //We can grab the item, finally.
+ if(grab)
+ to_chat(user, "You collect \the [I].")
+ I.loc = src
+ wrapped = I
+ return
+ else
+ to_chat(user, "Your gripper cannot hold \the [target].")
+
+ else if(istype(target,/obj/machinery/power/apc))
+ var/obj/machinery/power/apc/A = target
+ if(A.opened)
+ if(A.cell)
+
+ wrapped = A.cell
+
+ A.cell.add_fingerprint(user)
+ A.cell.update_icon()
+ A.cell.loc = src
+ A.cell = null
+
+ A.charging = 0
+ A.update_icon()
+
+ user.visible_message("[user] removes the power cell from [A]!", "You remove the power cell.")
+
+ else if(istype(target,/mob/living/silicon/robot))
+ var/mob/living/silicon/robot/A = target
+ if(A.opened)
+ if(A.cell)
+
+ wrapped = A.cell
+
+ A.cell.add_fingerprint(user)
+ A.cell.update_icon()
+ A.updateicon()
+ A.cell.loc = src
+ A.cell = null
+
+ user.visible_message("[user] removes the power cell from [A]!", "You remove the power cell.")
+
+//TODO: Matter decompiler.
+/obj/item/weapon/matter_decompiler
+
+ name = "matter decompiler"
+ desc = "Eating trash, bits of glass, or other debris will replenish your stores."
+ icon = 'icons/obj/device.dmi'
+ icon_state = "decompiler"
+
+ //Metal, glass, wood, plastic.
+ var/datum/matter_synth/metal = null
+ var/datum/matter_synth/glass = null
+ var/datum/matter_synth/wood = null
+ var/datum/matter_synth/plastic = null
+
+/obj/item/weapon/matter_decompiler/attack(mob/living/carbon/M as mob, mob/living/carbon/user as mob)
+ return
+
+/obj/item/weapon/matter_decompiler/afterattack(atom/target as mob|obj|turf|area, mob/living/user as mob|obj, proximity, params)
+
+ if(!proximity) return //Not adjacent.
+
+ //We only want to deal with using this on turfs. Specific items aren't important.
+ var/turf/T = get_turf(target)
+ if(!istype(T))
+ return
+
+ //Used to give the right message.
+ var/grabbed_something = 0
+
+ for(var/mob/M in T)
+ if(istype(M,/mob/living/simple_mob/animal/passive/lizard) || istype(M,/mob/living/simple_mob/animal/passive/mouse))
+ src.loc.visible_message("[src.loc] sucks [M] into its decompiler. There's a horrible crunching noise.","It's a bit of a struggle, but you manage to suck [M] into your decompiler. It makes a series of visceral crunching noises.")
+ new/obj/effect/decal/cleanable/blood/splatter(get_turf(src))
+ qdel(M)
+ if(wood)
+ wood.add_charge(2000)
+ if(plastic)
+ plastic.add_charge(2000)
+ return
+
+ else if(istype(M,/mob/living/silicon/robot/drone) && !M.client)
+
+ var/mob/living/silicon/robot/D = src.loc
+
+ if(!istype(D))
+ return
+
+ to_chat(D, "You begin decompiling [M].")
+
+ if(!do_after(D,50))
+ to_chat(D, "You need to remain still while decompiling such a large object.")
+ return
+
+ if(!M || !D) return
+
+ to_chat(D, "You carefully and thoroughly decompile [M], storing as much of its resources as you can within yourself.")
+ qdel(M)
+ new/obj/effect/decal/cleanable/blood/oil(get_turf(src))
+
+ if(metal)
+ metal.add_charge(15000)
+ if(glass)
+ glass.add_charge(15000)
+ if(wood)
+ wood.add_charge(2000)
+ if(plastic)
+ plastic.add_charge(1000)
+ return
+ else
+ continue
+
+ for(var/obj/W in T)
+ //Different classes of items give different commodities.
+ if(istype(W,/obj/item/trash/cigbutt))
+ if(plastic)
+ plastic.add_charge(500)
+ else if(istype(W,/obj/effect/spider/spiderling))
+ if(wood)
+ wood.add_charge(2000)
+ if(plastic)
+ plastic.add_charge(2000)
+ else if(istype(W,/obj/item/weapon/light))
+ var/obj/item/weapon/light/L = W
+ if(L.status >= 2) //In before someone changes the inexplicably local defines. ~ Z
+ if(metal)
+ metal.add_charge(250)
+ if(glass)
+ glass.add_charge(250)
+ else
+ continue
+ else if(istype(W,/obj/effect/decal/remains/robot))
+ if(metal)
+ metal.add_charge(2000)
+ if(plastic)
+ plastic.add_charge(2000)
+ if(glass)
+ glass.add_charge(1000)
+ else if(istype(W,/obj/item/trash))
+ if(metal)
+ metal.add_charge(1000)
+ if(plastic)
+ plastic.add_charge(3000)
+ else if(istype(W,/obj/effect/decal/cleanable/blood/gibs/robot))
+ if(metal)
+ metal.add_charge(2000)
+ if(glass)
+ glass.add_charge(2000)
+ else if(istype(W,/obj/item/ammo_casing))
+ if(metal)
+ metal.add_charge(1000)
+ else if(istype(W,/obj/item/weapon/material/shard/shrapnel))
+ if(metal)
+ metal.add_charge(1000)
+ else if(istype(W,/obj/item/weapon/material/shard))
+ if(glass)
+ glass.add_charge(1000)
+ else if(istype(W,/obj/item/weapon/reagent_containers/food/snacks/grown))
+ if(wood)
+ wood.add_charge(4000)
+ else if(istype(W,/obj/item/pipe))
+ // This allows drones and engiborgs to clear pipe assemblies from floors.
+ else
+ continue
+
+ qdel(W)
+ grabbed_something = 1
+
+ if(grabbed_something)
+ to_chat(user, "You deploy your decompiler and clear out the contents of \the [T].")
+ else
+ to_chat(user, "Nothing on \the [T] is useful to you.")
+ return
+
+//PRETTIER TOOL LIST.
+/mob/living/silicon/robot/drone/installed_modules()
+
+ if(weapon_lock)
+ to_chat(src, "Weapon lock active, unable to use modules! Count:[weaponlock_time]")
+ return
+
+ if(!module)
+ module = new /obj/item/weapon/robot_module/drone(src)
+
+ var/dat = "