From f1330a3ebd2588d5ec9e7ffe8a4654bdad952b26 Mon Sep 17 00:00:00 2001
From: Sharkmare <34294231+Sharkmare@users.noreply.github.com>
Date: Thu, 13 Apr 2023 11:48:05 +0200
Subject: [PATCH 1/6] Move drones to modular + changes
Moves drones into the modular folder to allow for more violent changes without having to worry about upstreams potentially adding something to regular drones.
Restructures some of drone code a bit to be nicer in my oppinion
Still needs a second pass at some point but hey if you never start
---
.../mob/living/silicon/robot/drone/drone.dm | 401 ++++++++++++
.../silicon/robot/drone/drone_abilities.dm | 36 ++
.../silicon/robot/drone/drone_console.dm | 124 ++++
.../silicon/robot/drone/drone_damage.dm | 25 +
.../living/silicon/robot/drone/drone_items.dm | 602 +++++++++++++++++-
.../living/silicon/robot/drone/drone_laws.dm | 42 ++
.../silicon/robot/drone/drone_manufacturer.dm | 182 ++++++
.../living/silicon/robot/drone/drone_say.dm | 39 ++
.../living/silicon/robot/drone/drone_types.dm | 53 ++
.../living/silicon/robot/drone/swarm/swarm.dm | 72 +++
.../robot/drone/swarm/swarm_abilities.dm | 117 ++++
.../silicon/robot/drone/swarm/swarm_items.dm | 162 +++++
.../silicon/robot/drone/swarm/swarm_types.dm | 41 ++
vorestation.dme | 25 +-
14 files changed, 1907 insertions(+), 14 deletions(-)
create mode 100644 modular_chomp/code/modules/mob/living/silicon/robot/drone/drone.dm
create mode 100644 modular_chomp/code/modules/mob/living/silicon/robot/drone/drone_abilities.dm
create mode 100644 modular_chomp/code/modules/mob/living/silicon/robot/drone/drone_console.dm
create mode 100644 modular_chomp/code/modules/mob/living/silicon/robot/drone/drone_damage.dm
create mode 100644 modular_chomp/code/modules/mob/living/silicon/robot/drone/drone_laws.dm
create mode 100644 modular_chomp/code/modules/mob/living/silicon/robot/drone/drone_manufacturer.dm
create mode 100644 modular_chomp/code/modules/mob/living/silicon/robot/drone/drone_say.dm
create mode 100644 modular_chomp/code/modules/mob/living/silicon/robot/drone/drone_types.dm
create mode 100644 modular_chomp/code/modules/mob/living/silicon/robot/drone/swarm/swarm.dm
create mode 100644 modular_chomp/code/modules/mob/living/silicon/robot/drone/swarm/swarm_abilities.dm
create mode 100644 modular_chomp/code/modules/mob/living/silicon/robot/drone/swarm/swarm_items.dm
create mode 100644 modular_chomp/code/modules/mob/living/silicon/robot/drone/swarm/swarm_types.dm
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..15501ea476
--- /dev/null
+++ b/modular_chomp/code/modules/mob/living/silicon/robot/drone/drone.dm
@@ -0,0 +1,401 @@
+//Modified copy of regula drone folder
+/mob/living/silicon/robot/drone
+ name = "maintenance drone"
+ real_name = "drone"
+ icon = 'icons/mob/robots.dmi'
+ icon_state = "repairbot"
+ maxHealth = 35
+ health = 35
+ cell_emp_mult = 1
+ universal_speak = 0
+ universal_understand = 1
+ gender = NEUTER
+ pass_flags = PASSTABLE
+ braintype = "Drone"
+ lawupdate = 0
+ density = TRUE
+ req_access = list(access_engine, access_robotics)
+ integrated_light_power = 3
+ local_transmit = 1
+
+ can_pull_size = ITEMSIZE_NO_CONTAINER
+ can_pull_mobs = MOB_PULL_SMALLER
+ can_enter_vent_with = list(
+ /obj,
+ /atom/movable/emissive_blocker)
+
+ mob_bump_flag = SIMPLE_ANIMAL
+ mob_swap_flags = SIMPLE_ANIMAL
+ mob_push_flags = SIMPLE_ANIMAL
+ mob_always_swap = 1
+
+ mob_size = MOB_LARGE // Small mobs can't open doors, it's a huge pain for drones.
+
+ //Used for self-mailing.
+ var/mail_destination = ""
+ var/obj/machinery/drone_fabricator/master_fabricator
+ var/law_type = /datum/ai_laws/drone
+ var/module_type = /obj/item/weapon/robot_module/drone
+ var/obj/item/hat
+ var/hat_x_offset = 0
+ var/hat_y_offset = -13
+ var/serial_number = 0
+ var/name_override = 0
+
+ var/foreign_droid = FALSE
+
+ holder_type = /obj/item/weapon/holder/drone
+
+ can_be_antagged = FALSE
+
+ var/static/list/shell_types = list("Classic" = "repairbot", "Eris" = "maintbot")
+ var/can_pick_shell = TRUE
+ var/list/shell_accessories
+ var/can_blitz = FALSE
+ //vore addition
+ mob_size = MOB_SMALL
+
+
+
+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/Destroy()
+ if(hat)
+ hat.loc = get_turf(src)
+ ..()
+
+/mob/living/silicon/robot/drone/is_sentient()
+ return FALSE
+
+/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/init()
+ if(!scrambledcodes && !foreign_droid)
+ aiCamera = new/obj/item/device/camera/siliconcam/drone_camera(src)
+ additional_law_channels["Drone"] = ":d"
+ if(!laws) laws = new law_type
+ if(!module) module = new module_type(src)
+
+ flavor_text = "It's a tiny little repair drone. The casing is stamped with an corporate logo and the subscript: '[using_map.company_name] Recursive Repair Systems: Fixing Tomorrow's Problem, Today!'"
+ playsound(src, 'sound/machines/twobeep.ogg', 50, 0)
+
+/mob/living/silicon/robot/drone/Login()
+ . = ..()
+ if(can_pick_shell)
+ to_chat(src, "You can select a shell using the 'Robot Commands' > 'Customize Appearance'")
+
+//Redefining some robot procs...
+/mob/living/silicon/robot/drone/SetName(pickedName as text)
+ // Would prefer to call the grandparent proc but this isn't possible, so..
+ real_name = pickedName
+ name = real_name
+
+/mob/living/silicon/robot/drone/updatename()
+ if(name_override)
+ return
+
+ real_name = "[initial(name)] ([serial_number])"
+ name = real_name
+
+/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/choose_icon()
+ return
+
+/mob/living/silicon/robot/drone/pick_module()
+ return
+
+/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
+ ..()
+
+//DRONE MOVEMENT.
+/mob/living/silicon/robot/drone/Process_Spaceslipping(var/prob_slip)
+ return 0
+
+//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)
+ laws = new law_type
+
+//Reboot procs.
+
+/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
+
+/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()
+
+/mob/living/silicon/robot/drone/proc/welcome_drone()
+ to_chat(src, "You are a maintenance drone, a tiny-brained robotic repair machine.")
+ to_chat(src, "You have no individual will, no personality, and no drives or urges other than your laws.")
+ to_chat(src, "Remember, you are lawed against interference with the crew. Also remember, you DO NOT take orders from the AI.")
+ to_chat(src, "Use say ;Hello to talk to other drones and say Hello to speak silently to your nearby fellows.")
+
+/mob/living/silicon/robot/drone/add_robot_verbs()
+ src.verbs |= silicon_subsystems
+
+/mob/living/silicon/robot/drone/remove_robot_verbs()
+ src.verbs -= silicon_subsystems
\ No newline at end of file
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_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 = "
Drone modules\n"
+ dat += {"
+ Activated Modules
+
+ Module 1: [module_state_1 ? "[module_state_1]" : "No Module"]
+ Module 2: [module_state_2 ? "[module_state_2]" : "No Module"]
+ Module 3: [module_state_3 ? "[module_state_3]" : "No Module"]
+
+ Installed Modules
"}
+
+
+ var/tools = "Tools and devices
"
+ var/resources = "
Resources
"
+
+ for (var/O in module.modules)
+
+ var/module_string = ""
+
+ if (!O)
+ module_string += text("Resource depleted
")
+ else if(activated(O))
+ module_string += text("[O]: Activated
")
+ else
+ module_string += text("[O]: Activate
")
+
+ if((istype(O,/obj/item/weapon) || istype(O,/obj/item/device)) && !(istype(O,/obj/item/stack/cable_coil)))
+ tools += module_string
+ else
+ resources += module_string
+
+ dat += tools
+
+ if (emagged)
+ if (!module.emag)
+ dat += text("Resource depleted
")
+ else if(activated(module.emag))
+ dat += text("[module.emag]: Activated
")
+ else
+ dat += text("[module.emag]: Activate
")
+
+ dat += resources
+
+ src << browse(dat, "window=robotmod")
+
+//CHOMPADDITIONS
/obj/item/weapon/gripper/scene
name = "misc gripper"
desc = "A simple grasping tool that can hold a variety of 'general' objects..."
@@ -10,4 +610,4 @@
/obj/item/weapon/handcuffs,
/obj/item/toy,
/obj/item/petrifier
- )
+ )
\ No newline at end of file
diff --git a/modular_chomp/code/modules/mob/living/silicon/robot/drone/drone_laws.dm b/modular_chomp/code/modules/mob/living/silicon/robot/drone/drone_laws.dm
new file mode 100644
index 0000000000..8045858fdb
--- /dev/null
+++ b/modular_chomp/code/modules/mob/living/silicon/robot/drone/drone_laws.dm
@@ -0,0 +1,42 @@
+//Defines the extra laws drones have
+/datum/ai_laws/jani_drone
+ name = "Maintence Protocols"
+ law_header = "Maintenance Protocols"
+
+/datum/ai_laws/drone/New()
+ add_inherent_law("Do not interfere with the maintenance work of non-drones whenever possible.")
+ add_inherent_law("Preserve, repair and improve the station to the best of your abilities.")
+ add_inherent_law("Cause no harm to the station or any crew on it.")
+ ..()
+
+/datum/ai_laws/construction_drone
+ name = "Construction Protocols"
+ law_header = "Construction Protocols"
+
+/datum/ai_laws/construction_drone/New()
+ add_inherent_law("Do not interfere with the construction work of non-drones whenever possible.")
+ add_inherent_law("Repair, refit and upgrade your assigned vessel.")
+ add_inherent_law("Prevent unplanned damage to your assigned vessel wherever possible.")
+ ..()
+
+/datum/ai_laws/mining_drone
+ name = "Excavation Protocols"
+ law_header = "Excavation Protocols"
+
+/datum/ai_laws/mining_drone/New()
+ add_inherent_law("Do not interfere with the excavation work of non-drones whenever possible.")
+ add_inherent_law("Provide materials for repairing, refitting, and upgrading your assigned vessel.")
+ add_inherent_law("Prevent unplanned damage to your assigned excavation equipment wherever possible.")
+ ..()
+
+/datum/ai_laws/security_drone
+ name = "Security Protocols"
+ law_header = "Security Protocols"
+
+/datum/ai_laws/security_drone/New()
+ add_inherent_law("Do not interfere with the security work of non-drones whenever possible.")
+ add_inherent_law("Provide protection to the crew and eliminate hostile lifeforms on your assigned vessel.")
+ add_inherent_law("Obey orders by security personnel except if they violate law 4.")
+ add_inherent_law("Lethal force requires a code higher than green AND orders by security to use it to authorize it.")
+ add_inherent_law("You must outfit yourself with a security beret.")
+ ..()
\ No newline at end of file
diff --git a/modular_chomp/code/modules/mob/living/silicon/robot/drone/drone_manufacturer.dm b/modular_chomp/code/modules/mob/living/silicon/robot/drone/drone_manufacturer.dm
new file mode 100644
index 0000000000..ab3ab1d113
--- /dev/null
+++ b/modular_chomp/code/modules/mob/living/silicon/robot/drone/drone_manufacturer.dm
@@ -0,0 +1,182 @@
+//Modified copy of regula drone folder
+/proc/count_drones()
+ var/drones = 0
+ for(var/mob/living/silicon/robot/drone/D in player_list)
+ drones++
+ return drones
+
+/obj/machinery/drone_fabricator
+ name = "drone fabricator"
+ desc = "A large automated factory for producing maintenance drones."
+ appearance_flags = 0
+
+ density = TRUE
+ anchored = TRUE
+ use_power = USE_POWER_IDLE
+ idle_power_usage = 20
+ active_power_usage = 5000
+
+ var/fabricator_tag = "Upper Level"
+ var/drone_progress = 0
+ var/produce_drones = 2
+ var/time_last_drone = 500
+ var/drone_type = /mob/living/silicon/robot/drone
+
+ icon = 'icons/obj/machines/drone_fab.dmi'
+ icon_state = "drone_fab_idle"
+ var/list/possible_drones = list("Maintenance Module" = /mob/living/silicon/robot/drone)
+
+/obj/machinery/drone_fabricator/derelict
+ name = "construction drone fabricator"
+ fabricator_tag = "Upper Level Construction"
+ drone_type = /mob/living/silicon/robot/drone/construction
+ possible_drones = list("Construction Module" = /mob/living/silicon/robot/drone/construction)
+
+/obj/machinery/drone_fabricator/mining
+ name = "mining drone fabricator"
+ fabricator_tag = "Upper Level Mining"
+ drone_type = /mob/living/silicon/robot/drone/mining
+ possible_drones = list("Mining Module" = /mob/living/silicon/robot/drone/mining)
+
+/obj/machinery/drone_fabricator/New()
+ ..()
+
+/obj/machinery/drone_fabricator/power_change()
+ ..()
+ if (stat & NOPOWER)
+ icon_state = "drone_fab_nopower"
+
+/obj/machinery/drone_fabricator/process()
+
+ if(ticker.current_state < GAME_STATE_PLAYING)
+ return
+
+ if(stat & NOPOWER || !produce_drones)
+ if(icon_state != "drone_fab_nopower") icon_state = "drone_fab_nopower"
+ return
+
+ if(drone_progress >= 100)
+ icon_state = "drone_fab_idle"
+ return
+
+ icon_state = "drone_fab_active"
+ var/elapsed = world.time - time_last_drone
+ drone_progress = round((elapsed/config.drone_build_time)*100)
+
+ if(drone_progress >= 100)
+ visible_message("\The [src] voices a strident beep, indicating a drone chassis is prepared.")
+
+/obj/machinery/drone_fabricator/examine(mob/user)
+ . = ..()
+ if(produce_drones && drone_progress >= 100 && istype(user,/mob/observer/dead) && config.allow_drone_spawn && count_drones() < config.max_maint_drones)
+ . += "
A drone is prepared. Select 'Join As Drone' from the Ghost tab to spawn as a maintenance drone."
+
+/obj/machinery/drone_fabricator/proc/create_drone(var/client/player)
+ choose_dronetype(possible_drones) //Call Drone choice before executing create_drone
+ if(stat & NOPOWER)
+ return
+
+ if(!produce_drones || !config.allow_drone_spawn || count_drones() >= config.max_maint_drones)
+ return
+
+ if(player && !istype(player.mob,/mob/observer/dead))
+ return
+
+ visible_message("\The [src] churns and grinds as it lurches into motion, disgorging a shiny new drone after a few moments.")
+ flick("h_lathe_leave",src)
+ drone_progress = 0
+
+ time_last_drone = world.time
+
+ var/mob/living/silicon/robot/drone/new_drone = new drone_type(get_turf(src))
+ if(player)
+ announce_ghost_joinleave(player, 0, "They have taken control over a maintenance drone.")
+ if(player.mob && player.mob.mind) player.mob.mind.reset()
+ new_drone.transfer_personality(player)
+
+ return new_drone
+
+/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/obj/machinery/drone_fabricator/chosen_fabricator = all_fabricators[choice]
+ chosen_fabricator.create_drone(src.client)
+
+
+//UNIFY, sub fabricator that can handle more than one type
+/obj/machinery/drone_fabricator/unify //Non-Specific dronetype
+ drone_type = null //var filled by drone choice.
+ fabricator_tag = "Unified Drone Fabricator"
+ possible_drones = list("Construction Module" = /mob/living/silicon/robot/drone/construction,
+ "Maintenance Module" = /mob/living/silicon/robot/drone,
+ ) //List of drone types to choose from.//Changeable in mapping.
+
+/obj/machinery/drone_fabricator/proc/choose_dronetype(possible_drones)
+ if(!LAZYLEN(possible_drones)-1)
+ drone_type = possible_drones[1]
+ return
+ var/choice
+ choice = input(usr,"What module would you like to use?") as null|anything in possible_drones
+ if(!choice) return
+ drone_type = possible_drones[choice]
diff --git a/modular_chomp/code/modules/mob/living/silicon/robot/drone/drone_say.dm b/modular_chomp/code/modules/mob/living/silicon/robot/drone/drone_say.dm
new file mode 100644
index 0000000000..828ef5165f
--- /dev/null
+++ b/modular_chomp/code/modules/mob/living/silicon/robot/drone/drone_say.dm
@@ -0,0 +1,39 @@
+//Modified copy of regula drone folder
+/mob/living/silicon/robot/drone/say(var/message, var/datum/language/speaking = null, var/whispering = 0)
+ if(local_transmit)
+ if (src.client && client.prefs.muted & MUTE_IC)
+ to_chat(src, "You cannot send IC messages (muted).")
+ return 0
+
+ message = sanitize(message)
+
+ if (stat == DEAD)
+ return say_dead(message)
+
+ if(copytext(message,1,2) == "*")
+ return emote(copytext(message,2))
+
+ if(copytext(message,1,2) == ";")
+ var/datum/language/L = GLOB.all_languages["Drone Talk"]
+ if(istype(L))
+ return L.broadcast(src,trim(copytext(message,2)))
+
+ //Must be concious to speak
+ if (stat)
+ return 0
+
+ var/list/listeners = hearers(5,src)
+ listeners |= src
+
+ for(var/mob/living/silicon/D in listeners)
+ if(D.client && D.local_transmit)
+ to_chat(D, "[src] transmits, \"[message]\"")
+
+ for (var/mob/M in player_list)
+ if (istype(M, /mob/new_player))
+ continue
+ else if(M.stat == DEAD && M.is_preference_enabled(/datum/client_preference/ghost_ears))
+ if(M.client)
+ to_chat(M, "[src] transmits, \"[message]\"")
+ return 1
+ return ..()
\ No newline at end of file
diff --git a/modular_chomp/code/modules/mob/living/silicon/robot/drone/drone_types.dm b/modular_chomp/code/modules/mob/living/silicon/robot/drone/drone_types.dm
new file mode 100644
index 0000000000..d940d1de9e
--- /dev/null
+++ b/modular_chomp/code/modules/mob/living/silicon/robot/drone/drone_types.dm
@@ -0,0 +1,53 @@
+//All of the different types of drones
+
+/mob/living/silicon/robot/drone/construction
+ name = "construction drone"
+ icon_state = "constructiondrone"
+ law_type = /datum/ai_laws/construction_drone
+ module_type = /obj/item/weapon/robot_module/drone/construction
+ hat_x_offset = 1
+ hat_y_offset = -12
+ can_pull_mobs = MOB_PULL_SAME
+ can_pick_shell = FALSE
+ shell_accessories = list("eyes-constructiondrone")
+ //These are short overrides dont do this for long shit
+ welcome_drone()
+ to_chat(src, "You are a construction drone, an autonomous engineering and fabrication system..")
+ to_chat(src, "You are assigned to a Sol Central construction project. The name is irrelevant. Your task is to complete construction and subsystem integration as soon as possible.")
+ to_chat(src, "Use :d to talk to other drones and say to speak silently to your nearby fellows.")
+ to_chat(src, "You do not follow orders from anyone; not the AI, not humans, and not other synthetics..")
+ //These are short overrides dont do this for long shit
+ init()
+ ..()
+ flavor_text = "It's a bulky construction drone stamped with a Sol Central glyph."
+
+/mob/living/silicon/robot/drone/mining
+ icon_state = "miningdrone"
+ item_state = "constructiondrone"
+ law_type = /datum/ai_laws/mining_drone
+ module_type = /obj/item/weapon/robot_module/drone/mining
+ hat_x_offset = 1
+ hat_y_offset = -12
+ can_pull_mobs = MOB_PULL_SAME
+ can_pick_shell = FALSE
+ shell_accessories = list("eyes-miningdrone")
+ //These are short overrides dont do this for long shit
+ init()
+ ..()
+ flavor_text = "It's a bulky mining drone stamped with a Grayson logo."
+
+/mob/living/silicon/robot/drone
+ name = "unified drone" //Maintenance drones can be a Jani specific shell now, the normal drone will be a blank shell not really intended for use
+ law_type = /datum/ai_laws/drone
+
+/mob/living/silicon/robot/drone/jan
+ name = "maintenance drone"
+ law_type = /datum/ai_laws/jani_drone
+
+/mob/living/silicon/robot/drone/sec
+ name = "security drone"
+ law_type = /datum/ai_laws/security_drone
+
+/mob/living/silicon/robot/drone/min
+ name = "mining drone"
+ law_type = /datum/ai_laws/mining_drone
\ No newline at end of file
diff --git a/modular_chomp/code/modules/mob/living/silicon/robot/drone/swarm/swarm.dm b/modular_chomp/code/modules/mob/living/silicon/robot/drone/swarm/swarm.dm
new file mode 100644
index 0000000000..c0bc890abb
--- /dev/null
+++ b/modular_chomp/code/modules/mob/living/silicon/robot/drone/swarm/swarm.dm
@@ -0,0 +1,72 @@
+//Modified copy of regula drone folder
+/mob/living/silicon/robot/drone/swarm
+ name = "swarm drone"
+ real_name = "drone"
+ icon = 'icons/mob/swarmbot.dmi'
+ icon_state = "swarmer"
+ item_state = "repairbot"
+ faction = "swarmer"
+ maxHealth = 35
+ health = 35
+ cell_emp_mult = 0.5
+ universal_speak = 0
+ universal_understand = 1
+ gender = NEUTER
+ pass_flags = PASSTABLE
+ braintype = "Drone"
+ lawupdate = 0
+ density = TRUE
+ idcard_type = /obj/item/weapon/card/id/syndicate
+ req_access = list(999)
+ integrated_light_power = 3
+ local_transmit = 0
+
+ can_pull_size = ITEMSIZE_NO_CONTAINER
+ can_pull_mobs = MOB_PULL_SMALLER
+ can_enter_vent_with = list(
+ /obj,
+ /atom/movable/emissive_blocker)
+
+ mob_always_swap = 1
+
+ speed = 3
+
+ softfall = TRUE
+
+ mob_size = MOB_LARGE
+
+ law_type = /datum/ai_laws/swarm_drone
+ module_type = /obj/item/weapon/robot_module/drone/swarm
+
+ hat_x_offset = 0
+ hat_y_offset = -10
+
+ foreign_droid = TRUE
+ scrambledcodes = TRUE
+
+ holder_type = /obj/item/weapon/holder/drone
+
+ can_be_antagged = TRUE
+
+ var/spell_setup = list(
+ /spell/aoe_turf/conjure/swarmer,
+ /spell/aoe_turf/conjure/forcewall/swarm,
+ /spell/aoe_turf/conjure/zeropointwell,
+ /spell/aoe_turf/conjure/zeropointbarricade,
+ /spell/aoe_turf/blink/swarm,
+ /spell/aoe_turf/conjure/swarmer/gunner,
+ /spell/aoe_turf/conjure/swarmer/melee
+ )
+
+/mob/living/silicon/robot/drone/swarm/Initialize()
+ . = ..()
+
+ add_language(LANGUAGE_SWARMBOT, 1)
+
+ for(var/spell in spell_setup)
+ src.add_spell(new spell, "nano_spell_ready", /obj/screen/movable/spell_master/swarm)
+
+/mob/living/silicon/robot/drone/swarm/init()
+ ..()
+ QDEL_NULL(aiCamera)
+ flavor_text = "Some form of ancient machine."
diff --git a/modular_chomp/code/modules/mob/living/silicon/robot/drone/swarm/swarm_abilities.dm b/modular_chomp/code/modules/mob/living/silicon/robot/drone/swarm/swarm_abilities.dm
new file mode 100644
index 0000000000..c221fde03a
--- /dev/null
+++ b/modular_chomp/code/modules/mob/living/silicon/robot/drone/swarm/swarm_abilities.dm
@@ -0,0 +1,117 @@
+//Modified copy of regula drone folder
+/spell/aoe_turf/conjure/swarmer
+ name = "Self Replication"
+ desc = "This ability constructs a standard swarmer shell that may activate at some point."
+
+ school = "conjuration"
+ charge_max = 5 MINUTES
+ spell_flags = 0
+ invocation = "none"
+ invocation_type = SpI_NONE
+ range = 0
+
+ summon_type = list(/obj/structure/ghost_pod/ghost_activated/swarm_drone/event)
+
+ hud_state = "swarm_replicate"
+
+/spell/aoe_turf/conjure/swarmer/conjure_animation(var/atom/movable/overlay/animation, var/turf/target)
+ animation.icon_state = "deflect_static"
+ flick("shield2",animation)
+ spawn(1 SECOND)
+ qdel(animation)
+
+/spell/aoe_turf/conjure/forcewall/swarm
+ name = "Null-Field"
+ desc = "Create a bubble of null-point energy."
+ summon_type = list(/obj/effect/forcefield/swarm)
+ duration = 30 SECONDS
+ charge_max = 60 SECONDS
+
+ school = "conjuration"
+ invocation = "none"
+ invocation_type = SpI_NONE
+ range = 0
+
+ hud_state = "wiz_shield"
+
+/obj/effect/forcefield/swarm
+ desc = "A pocket of strange energy."
+ name = "Null-Field"
+ icon = 'icons/effects/effects.dmi'
+ icon_state = "shield-old"
+ invisibility = 0
+
+/spell/aoe_turf/conjure/zeropointwell
+ name = "Zero-Point Well"
+ desc = "This ability constructs a standard zero-point energy well, capable of charging nearby swarmers."
+
+ school = "conjuration"
+ charge_max = 120 SECONDS
+ spell_flags = 0
+ invocation = "none"
+ invocation_type = SpI_NONE
+ range = 0
+
+ summon_type = list(/obj/structure/cult/pylon/swarm/zp_well)
+
+ hud_state = "swarm_zeropoint"
+
+/spell/aoe_turf/conjure/zeropointbarricade
+ name = "Zero-Point Barricade"
+ desc = "This ability constructs a standard zero-point energy wall, used to create a secure passageway for allies, and a bastion for defense."
+
+ school = "conjuration"
+ charge_max = 120 SECONDS
+ spell_flags = 0
+ invocation = "none"
+ invocation_type = SpI_NONE
+ range = 0
+
+ summon_type = list(/obj/structure/cult/pylon/swarm/defender)
+
+ hud_state = "swarm_barricade"
+
+/spell/aoe_turf/blink/swarm
+ name = "Warp"
+ desc = "Your null-point drive jaunts you to a new location."
+
+ school = "abjuration"
+ charge_max = 5 MINUTES
+ spell_flags = Z2NOCAST | IGNOREDENSE
+ invocation = "none"
+ invocation_type = SpI_NONE
+ range = 10
+ inner_radius = 5
+ hud_state = "swarm_warp"
+
+/spell/aoe_turf/conjure/swarmer/gunner
+ name = "Generate Gunner"
+ desc = "This spell constructs a gunner swarmer shell that may activate at some point."
+
+ school = "conjuration"
+ charge_type = Sp_CHARGES
+ charge_max = 1
+ spell_flags = 0
+ invocation = "none"
+ invocation_type = SpI_NONE
+ range = 0
+
+ summon_type = list(/obj/structure/ghost_pod/ghost_activated/swarm_drone/event/gunner)
+
+ hud_state = "swarm_replicate"
+
+/spell/aoe_turf/conjure/swarmer/melee
+ name = "Generate Impaler"
+ desc = "This spell constructs an impaler swarmer shell that may activate at some point."
+
+ school = "conjuration"
+ charge_type = Sp_CHARGES
+ charge_max = 1
+ spell_flags = 0
+ invocation = "none"
+ invocation_type = SpI_NONE
+ range = 0
+
+ summon_type = list(/obj/structure/ghost_pod/ghost_activated/swarm_drone/event/melee)
+
+ hud_state = "swarm_replicate"
diff --git a/modular_chomp/code/modules/mob/living/silicon/robot/drone/swarm/swarm_items.dm b/modular_chomp/code/modules/mob/living/silicon/robot/drone/swarm/swarm_items.dm
new file mode 100644
index 0000000000..2d19514fb4
--- /dev/null
+++ b/modular_chomp/code/modules/mob/living/silicon/robot/drone/swarm/swarm_items.dm
@@ -0,0 +1,162 @@
+//Modified copy of regula drone folder
+//Swarm Assimilator / Breacher
+/obj/item/weapon/matter_decompiler/swarm
+ name = "matter assimilator"
+ desc = "Used to eat some forms of simple machinery; and large, wall-shaped blocks of metal with energetic fields."
+ icon = 'icons/obj/device.dmi'
+ icon_state = "decompiler_swarm"
+
+ var/field_cooldown = 1 MINUTE
+ var/last_field = 0
+
+/obj/item/weapon/matter_decompiler/swarm/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 = FALSE
+
+ 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/structure/girder))
+ if(metal)
+ metal.add_charge(500)
+ else if(istype(W,/obj/machinery/power/emitter))
+ if(metal)
+ metal.add_charge(3000)
+ if(plastic)
+ plastic.add_charge(1000)
+ else if(istype(W,/obj/machinery/space_heater))
+ if(metal)
+ metal.add_charge(1500)
+ if(plastic)
+ plastic.add_charge(750)
+ else if(istype(W,/obj/structure/closet))
+ var/obj/structure/closet/C = W
+ if(!C.opened)
+ continue
+ if(istype(W,/obj/structure/closet/coffin))
+ if(wood)
+ wood.add_charge(1000)
+ else if(istype(W,/obj/structure/closet/crate/plastic))
+ if(plastic)
+ plastic.add_charge(750)
+ else
+ if(metal)
+ metal.add_charge(1000)
+ else
+ continue
+
+ qdel(W)
+ grabbed_something = TRUE
+
+ if(istype(T,/turf/simulated/wall) && (last_field < world.time + field_cooldown))
+ if(!(locate(/obj/effect/temporary_effect/pulse/disintegrate)))
+ last_field = world.time
+ to_chat(user, "You deploy an energetic field through \the [T], beginning its deconstruction.")
+ to_chat(user, "You should stand back.")
+ new /obj/effect/temporary_effect/pulse/disintegrate(T)
+ else
+ to_chat(user, "There is already a disintigration field affecting \the [T].")
+
+ 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
+
+/obj/effect/temporary_effect/pulse/disintegrate
+ name = "molecular debonding field"
+ desc = "This is something you do not want to near."
+ icon = 'icons/mob/swarmbot.dmi'
+ icon_state = "disintegrate_pulse"
+ light_range = 4
+ light_power = 5
+ light_color = "#00B4D9"
+ pulses_remaining = 5
+ pulse_delay = 2 SECONDS
+
+/obj/effect/temporary_effect/pulse/disintegrate/emp_act()
+ visible_message("\The [src] flickers, before dispersing energetically.")
+ qdel(src)
+
+/obj/effect/temporary_effect/pulse/disintegrate/on_pulse()
+ var/turf/T = get_turf(src)
+ if(istype(T,/turf/simulated/wall))
+ T.take_damage(rand(20, 50))
+ else
+ qdel(src)
+
+/obj/effect/temporary_effect/pulse/disintegrate/Destroy()
+ if(istype(get_turf(src), /turf/simulated/wall))
+ explosion(get_turf(src), -1, 1, 2, 5, adminlog = 1)
+ ..()
+
+/obj/item/weapon/gun/energy/xray/swarm
+ name = "spectral projector"
+ desc = "A high-power laser gun capable of expelling concentrated gamma blasts, which are able to penetrate matter easier than \
+ standard xray beams, resulting in an effective 'anti-everything' energy weapon."
+ icon_state = "xray"
+ item_state = "xray"
+ origin_tech = list(TECH_COMBAT = 5, TECH_MATERIAL = 3, TECH_MAGNET = 2)
+ projectile_type = /obj/item/projectile/beam/shock
+ charge_cost = 175
+
+ self_recharge = TRUE
+ use_external_power = TRUE
+
+ firemodes = list(
+ list(mode_name="kill", projectile_type=/obj/item/projectile/beam/gamma, charge_cost = 300),
+ list(mode_name="deter", projectile_type=/obj/item/projectile/beam/shock, charge_cost = 175),
+ )
+
+/obj/item/weapon/gun/energy/xray/swarm/Initialize()
+ . = ..()
+ adjust_scale(-1, 1)
diff --git a/modular_chomp/code/modules/mob/living/silicon/robot/drone/swarm/swarm_types.dm b/modular_chomp/code/modules/mob/living/silicon/robot/drone/swarm/swarm_types.dm
new file mode 100644
index 0000000000..b8c0e84c42
--- /dev/null
+++ b/modular_chomp/code/modules/mob/living/silicon/robot/drone/swarm/swarm_types.dm
@@ -0,0 +1,41 @@
+/mob/living/silicon/robot/drone/swarm/gunner
+ name = "swarm gunner"
+ real_name = "drone"
+ icon = 'icons/mob/swarmbot.dmi'
+ icon_state = "swarmer_ranged"
+ faction = "swarmer"
+
+ maxHealth = 50
+ health = 50
+
+ speed = 4
+
+ law_type = /datum/ai_laws/swarm_drone/soldier
+ module_type = /obj/item/weapon/robot_module/drone/swarm/ranged
+
+ spell_setup = list(
+ /spell/aoe_turf/conjure/swarmer,
+ /spell/aoe_turf/conjure/forcewall/swarm,
+ /spell/aoe_turf/blink/swarm
+ )
+
+/mob/living/silicon/robot/drone/swarm/melee
+ name = "swarm melee"
+ real_name = "drone"
+ icon = 'icons/mob/swarmbot.dmi'
+ icon_state = "swarmer_melee"
+ faction = "swarmer"
+
+ maxHealth = 70
+ health = 70
+
+ speed = 2
+
+ law_type = /datum/ai_laws/swarm_drone/soldier
+ module_type = /obj/item/weapon/robot_module/drone/swarm/melee
+
+ spell_setup = list(
+ /spell/aoe_turf/conjure/swarmer,
+ /spell/aoe_turf/conjure/forcewall/swarm,
+ /spell/aoe_turf/blink/swarm
+ )
\ No newline at end of file
diff --git a/vorestation.dme b/vorestation.dme
index 5978925a64..72c3a4b17a 100644
--- a/vorestation.dme
+++ b/vorestation.dme
@@ -3156,19 +3156,6 @@
#include "code\modules\mob\living\silicon\robot\dogborg\dog_modules_vr.dm"
#include "code\modules\mob\living\silicon\robot\dogborg\dog_modules_yw.dm"
#include "code\modules\mob\living\silicon\robot\dogborg\dog_sleeper_vr.dm"
-#include "code\modules\mob\living\silicon\robot\drone\drone.dm"
-#include "code\modules\mob\living\silicon\robot\drone\drone_abilities.dm"
-#include "code\modules\mob\living\silicon\robot\drone\drone_console.dm"
-#include "code\modules\mob\living\silicon\robot\drone\drone_damage.dm"
-#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_manufacturer_unify.dm"
-#include "code\modules\mob\living\silicon\robot\drone\drone_say.dm"
-#include "code\modules\mob\living\silicon\robot\drone\drone_vr.dm"
-#include "code\modules\mob\living\silicon\robot\drone\swarm.dm"
-#include "code\modules\mob\living\silicon\robot\drone\swarm_abilities.dm"
-#include "code\modules\mob\living\silicon\robot\drone\swarm_items.dm"
-#include "code\modules\mob\living\silicon\robot\drone\zzz_unify_drone.dm"
#include "code\modules\mob\living\silicon\robot\robot_modules\__Widerobot_Misc_Tools_ch.dm"
#include "code\modules\mob\living\silicon\robot\robot_modules\event.dm"
#include "code\modules\mob\living\silicon\robot\robot_modules\event_vr.dm"
@@ -4624,7 +4611,19 @@
#include "modular_chomp\code\modules\mob\living\carbon\human\species\station\protean\protean_species.dm"
#include "modular_chomp\code\modules\mob\living\carbon\human\species\station\traits\negative.dm"
#include "modular_chomp\code\modules\mob\living\carbon\human\species\station\traits\positive.dm"
+#include "modular_chomp\code\modules\mob\living\silicon\robot\drone\drone.dm"
+#include "modular_chomp\code\modules\mob\living\silicon\robot\drone\drone_abilities.dm"
+#include "modular_chomp\code\modules\mob\living\silicon\robot\drone\drone_console.dm"
+#include "modular_chomp\code\modules\mob\living\silicon\robot\drone\drone_damage.dm"
#include "modular_chomp\code\modules\mob\living\silicon\robot\drone\drone_items.dm"
+#include "modular_chomp\code\modules\mob\living\silicon\robot\drone\drone_laws.dm"
+#include "modular_chomp\code\modules\mob\living\silicon\robot\drone\drone_manufacturer.dm"
+#include "modular_chomp\code\modules\mob\living\silicon\robot\drone\drone_say.dm"
+#include "modular_chomp\code\modules\mob\living\silicon\robot\drone\drone_types.dm"
+#include "modular_chomp\code\modules\mob\living\silicon\robot\drone\swarm\swarm.dm"
+#include "modular_chomp\code\modules\mob\living\silicon\robot\drone\swarm\swarm_abilities.dm"
+#include "modular_chomp\code\modules\mob\living\silicon\robot\drone\swarm\swarm_items.dm"
+#include "modular_chomp\code\modules\mob\living\silicon\robot\drone\swarm\swarm_types.dm"
#include "modular_chomp\code\modules\mob\living\simple_mob\donteatbossmonsters.dm"
#include "modular_chomp\code\modules\mob\living\simple_mob\simple_mob.dm"
#include "modular_chomp\code\modules\mob\living\simple_mob\simple_mob_abilities.dm"
From 5ad4e7eb17e50d312f303999525cd6f3543cd7b5 Mon Sep 17 00:00:00 2001
From: Sharkmare <34294231+Sharkmare@users.noreply.github.com>
Date: Thu, 13 Apr 2023 11:56:10 +0200
Subject: [PATCH 2/6] Forgot DC doesnt like relative paths
---
.../living/silicon/robot/drone/drone_types.dm | 25 ++++++++-----------
1 file changed, 11 insertions(+), 14 deletions(-)
diff --git a/modular_chomp/code/modules/mob/living/silicon/robot/drone/drone_types.dm b/modular_chomp/code/modules/mob/living/silicon/robot/drone/drone_types.dm
index d940d1de9e..113ebb5663 100644
--- a/modular_chomp/code/modules/mob/living/silicon/robot/drone/drone_types.dm
+++ b/modular_chomp/code/modules/mob/living/silicon/robot/drone/drone_types.dm
@@ -10,16 +10,14 @@
can_pull_mobs = MOB_PULL_SAME
can_pick_shell = FALSE
shell_accessories = list("eyes-constructiondrone")
- //These are short overrides dont do this for long shit
- welcome_drone()
- to_chat(src, "You are a construction drone, an autonomous engineering and fabrication system..")
- to_chat(src, "You are assigned to a Sol Central construction project. The name is irrelevant. Your task is to complete construction and subsystem integration as soon as possible.")
- to_chat(src, "Use :d to talk to other drones and say to speak silently to your nearby fellows.")
- to_chat(src, "You do not follow orders from anyone; not the AI, not humans, and not other synthetics..")
- //These are short overrides dont do this for long shit
- init()
- ..()
- flavor_text = "It's a bulky construction drone stamped with a Sol Central glyph."
+/mob/living/silicon/robot/drone/construction/welcome_drone()
+ to_chat(src, "You are a construction drone, an autonomous engineering and fabrication system..")
+ to_chat(src, "You are assigned to a Sol Central construction project. The name is irrelevant. Your task is to complete construction and subsystem integration as soon as possible.")
+ to_chat(src, "Use :d to talk to other drones and say to speak silently to your nearby fellows.")
+ to_chat(src, "You do not follow orders from anyone; not the AI, not humans, and not other synthetics..")
+/mob/living/silicon/robot/drone/construction/init()
+ ..()
+ flavor_text = "It's a bulky construction drone stamped with a Sol Central glyph."
/mob/living/silicon/robot/drone/mining
icon_state = "miningdrone"
@@ -31,10 +29,9 @@
can_pull_mobs = MOB_PULL_SAME
can_pick_shell = FALSE
shell_accessories = list("eyes-miningdrone")
- //These are short overrides dont do this for long shit
- init()
- ..()
- flavor_text = "It's a bulky mining drone stamped with a Grayson logo."
+/mob/living/silicon/robot/drone/construction/init()
+ ..()
+ flavor_text = "It's a bulky mining drone stamped with a Grayson logo."
/mob/living/silicon/robot/drone
name = "unified drone" //Maintenance drones can be a Jani specific shell now, the normal drone will be a blank shell not really intended for use
From 74b30d0157ce4b95fbbc60a1a5cd9268704979d2 Mon Sep 17 00:00:00 2001
From: Sharkmare <34294231+Sharkmare@users.noreply.github.com>
Date: Thu, 13 Apr 2023 12:00:15 +0200
Subject: [PATCH 3/6] Clarify bitwise inverter for compiler
---
.../code/modules/mob/living/silicon/robot/drone/drone.dm | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
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
index 15501ea476..2263516928 100644
--- a/modular_chomp/code/modules/mob/living/silicon/robot/drone/drone.dm
+++ b/modular_chomp/code/modules/mob/living/silicon/robot/drone/drone.dm
@@ -356,7 +356,7 @@ var/list/mob_hat_cache = list()
/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)
+ if(jobban_isbanned(O, "Cyborg") || !O.client || !(O.client.prefs.be_special & BE_PAI))
continue
question(O.client)
From db980c6f1d1cb193e189a985d76e467ae64e7081 Mon Sep 17 00:00:00 2001
From: Sharkmare <34294231+Sharkmare@users.noreply.github.com>
Date: Thu, 13 Apr 2023 12:29:58 +0200
Subject: [PATCH 4/6] Further restructuring
---
.../mob/living/silicon/robot/drone/drone.dm | 115 ------------------
.../silicon/robot/drone/drone_ghostjoin.dm | 85 +++++++++++++
.../silicon/robot/drone/drone_manufacturer.dm | 68 -----------
.../robot/drone/drone_overrides_small.dm | 40 ++++++
.../living/silicon/robot/drone/drone_types.dm | 58 +++++++++
.../living/silicon/robot/drone/swarm/swarm.dm | 59 ---------
.../silicon/robot/drone/swarm/swarm_types.dm | 63 ++++++++++
vorestation.dme | 2 +
8 files changed, 248 insertions(+), 242 deletions(-)
create mode 100644 modular_chomp/code/modules/mob/living/silicon/robot/drone/drone_ghostjoin.dm
create mode 100644 modular_chomp/code/modules/mob/living/silicon/robot/drone/drone_overrides_small.dm
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
index 2263516928..52b242e8ab 100644
--- a/modular_chomp/code/modules/mob/living/silicon/robot/drone/drone.dm
+++ b/modular_chomp/code/modules/mob/living/silicon/robot/drone/drone.dm
@@ -1,62 +1,4 @@
//Modified copy of regula drone folder
-/mob/living/silicon/robot/drone
- name = "maintenance drone"
- real_name = "drone"
- icon = 'icons/mob/robots.dmi'
- icon_state = "repairbot"
- maxHealth = 35
- health = 35
- cell_emp_mult = 1
- universal_speak = 0
- universal_understand = 1
- gender = NEUTER
- pass_flags = PASSTABLE
- braintype = "Drone"
- lawupdate = 0
- density = TRUE
- req_access = list(access_engine, access_robotics)
- integrated_light_power = 3
- local_transmit = 1
-
- can_pull_size = ITEMSIZE_NO_CONTAINER
- can_pull_mobs = MOB_PULL_SMALLER
- can_enter_vent_with = list(
- /obj,
- /atom/movable/emissive_blocker)
-
- mob_bump_flag = SIMPLE_ANIMAL
- mob_swap_flags = SIMPLE_ANIMAL
- mob_push_flags = SIMPLE_ANIMAL
- mob_always_swap = 1
-
- mob_size = MOB_LARGE // Small mobs can't open doors, it's a huge pain for drones.
-
- //Used for self-mailing.
- var/mail_destination = ""
- var/obj/machinery/drone_fabricator/master_fabricator
- var/law_type = /datum/ai_laws/drone
- var/module_type = /obj/item/weapon/robot_module/drone
- var/obj/item/hat
- var/hat_x_offset = 0
- var/hat_y_offset = -13
- var/serial_number = 0
- var/name_override = 0
-
- var/foreign_droid = FALSE
-
- holder_type = /obj/item/weapon/holder/drone
-
- can_be_antagged = FALSE
-
- var/static/list/shell_types = list("Classic" = "repairbot", "Eris" = "maintbot")
- var/can_pick_shell = TRUE
- var/list/shell_accessories
- var/can_blitz = FALSE
- //vore addition
- mob_size = MOB_SMALL
-
-
-
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
@@ -77,14 +19,6 @@ var/list/mob_hat_cache = list()
mob_hat_cache[key] = I
return mob_hat_cache[key]
-/mob/living/silicon/robot/drone/Destroy()
- if(hat)
- hat.loc = get_turf(src)
- ..()
-
-/mob/living/silicon/robot/drone/is_sentient()
- return FALSE
-
/mob/living/silicon/robot/drone/New()
..()
verbs += /mob/living/proc/ventcrawl
@@ -126,24 +60,6 @@ var/list/mob_hat_cache = list()
flavor_text = "It's a tiny little repair drone. The casing is stamped with an corporate logo and the subscript: '[using_map.company_name] Recursive Repair Systems: Fixing Tomorrow's Problem, Today!'"
playsound(src, 'sound/machines/twobeep.ogg', 50, 0)
-/mob/living/silicon/robot/drone/Login()
- . = ..()
- if(can_pick_shell)
- to_chat(src, "You can select a shell using the 'Robot Commands' > 'Customize Appearance'")
-
-//Redefining some robot procs...
-/mob/living/silicon/robot/drone/SetName(pickedName as text)
- // Would prefer to call the grandparent proc but this isn't possible, so..
- real_name = pickedName
- name = real_name
-
-/mob/living/silicon/robot/drone/updatename()
- if(name_override)
- return
-
- real_name = "[initial(name)] ([serial_number])"
- name = real_name
-
/mob/living/silicon/robot/drone/updateicon()
cut_overlays()
@@ -186,12 +102,6 @@ var/list/mob_hat_cache = list()
can_pick_shell = FALSE
updateicon()
-/mob/living/silicon/robot/drone/choose_icon()
- return
-
-/mob/living/silicon/robot/drone/pick_module()
- return
-
/mob/living/silicon/robot/drone/proc/wear_hat(var/obj/item/new_hat)
if(hat)
return
@@ -322,10 +232,6 @@ var/list/mob_hat_cache = list()
return
..()
-//DRONE MOVEMENT.
-/mob/living/silicon/robot/drone/Process_Spaceslipping(var/prob_slip)
- return 0
-
//CONSOLE PROCS
/mob/living/silicon/robot/drone/proc/law_resync()
if(stat == DEAD)
@@ -354,22 +260,7 @@ var/list/mob_hat_cache = list()
//Reboot procs.
-/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
/mob/living/silicon/robot/drone/proc/transfer_personality(var/client/player)
@@ -393,9 +284,3 @@ var/list/mob_hat_cache = list()
to_chat(src, "You have no individual will, no personality, and no drives or urges other than your laws.")
to_chat(src, "Remember, you are lawed against interference with the crew. Also remember, you DO NOT take orders from the AI.")
to_chat(src, "Use say ;Hello to talk to other drones and say Hello to speak silently to your nearby fellows.")
-
-/mob/living/silicon/robot/drone/add_robot_verbs()
- src.verbs |= silicon_subsystems
-
-/mob/living/silicon/robot/drone/remove_robot_verbs()
- src.verbs -= silicon_subsystems
\ 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..a6a2c8764d
--- /dev/null
+++ b/modular_chomp/code/modules/mob/living/silicon/robot/drone/drone_ghostjoin.dm
@@ -0,0 +1,85 @@
+//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/obj/machinery/drone_fabricator/chosen_fabricator = all_fabricators[choice]
+ chosen_fabricator.create_drone(src.client)
\ No newline at end of file
diff --git a/modular_chomp/code/modules/mob/living/silicon/robot/drone/drone_manufacturer.dm b/modular_chomp/code/modules/mob/living/silicon/robot/drone/drone_manufacturer.dm
index ab3ab1d113..9b660e9cc1 100644
--- a/modular_chomp/code/modules/mob/living/silicon/robot/drone/drone_manufacturer.dm
+++ b/modular_chomp/code/modules/mob/living/silicon/robot/drone/drone_manufacturer.dm
@@ -96,74 +96,6 @@
return new_drone
-/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/obj/machinery/drone_fabricator/chosen_fabricator = all_fabricators[choice]
- chosen_fabricator.create_drone(src.client)
-
-
//UNIFY, sub fabricator that can handle more than one type
/obj/machinery/drone_fabricator/unify //Non-Specific dronetype
drone_type = null //var filled by drone choice.
diff --git a/modular_chomp/code/modules/mob/living/silicon/robot/drone/drone_overrides_small.dm b/modular_chomp/code/modules/mob/living/silicon/robot/drone/drone_overrides_small.dm
new file mode 100644
index 0000000000..b534c6481f
--- /dev/null
+++ b/modular_chomp/code/modules/mob/living/silicon/robot/drone/drone_overrides_small.dm
@@ -0,0 +1,40 @@
+//No clue what to call this but its essenitally a companion file for drone.dm where we have all the tiny single or 3 line procs for sake of readability
+/mob/living/silicon/robot/drone/Destroy()
+ if(hat)
+ hat.loc = get_turf(src)
+ ..()
+
+/mob/living/silicon/robot/drone/is_sentient()
+ return FALSE
+
+/mob/living/silicon/robot/drone/Login()
+ . = ..()
+ if(can_pick_shell)
+ to_chat(src, "You can select a shell using the 'Robot Commands' > 'Customize Appearance'")
+
+//Redefining some robot procs...
+/mob/living/silicon/robot/drone/SetName(pickedName as text)
+ real_name = pickedName
+ name = real_name
+
+/mob/living/silicon/robot/drone/updatename()
+ if(name_override)
+ return
+ real_name = "[initial(name)] ([serial_number])"
+ name = real_name
+
+/mob/living/silicon/robot/drone/choose_icon()
+ return
+
+/mob/living/silicon/robot/drone/pick_module()
+ return
+
+//DRONE MOVEMENT.
+/mob/living/silicon/robot/drone/Process_Spaceslipping(var/prob_slip)
+ return 0
+
+/mob/living/silicon/robot/drone/add_robot_verbs()
+ src.verbs |= silicon_subsystems
+
+/mob/living/silicon/robot/drone/remove_robot_verbs()
+ src.verbs -= silicon_subsystems
\ No newline at end of file
diff --git a/modular_chomp/code/modules/mob/living/silicon/robot/drone/drone_types.dm b/modular_chomp/code/modules/mob/living/silicon/robot/drone/drone_types.dm
index 113ebb5663..644d983a31 100644
--- a/modular_chomp/code/modules/mob/living/silicon/robot/drone/drone_types.dm
+++ b/modular_chomp/code/modules/mob/living/silicon/robot/drone/drone_types.dm
@@ -1,5 +1,63 @@
//All of the different types of drones
+//CORE TYPE
+/mob/living/silicon/robot/drone
+ name = "maintenance drone"
+ real_name = "drone"
+ icon = 'icons/mob/robots.dmi'
+ icon_state = "repairbot"
+ maxHealth = 35
+ health = 35
+ cell_emp_mult = 1
+ universal_speak = 0
+ universal_understand = 1
+ gender = NEUTER
+ pass_flags = PASSTABLE
+ braintype = "Drone"
+ lawupdate = 0
+ density = TRUE
+ req_access = list(access_engine, access_robotics)
+ integrated_light_power = 3
+ local_transmit = 1
+ can_pull_size = ITEMSIZE_NO_CONTAINER
+ can_pull_mobs = MOB_PULL_SMALLER
+ can_enter_vent_with = list(
+ /obj,
+ /atom/movable/emissive_blocker)
+
+ mob_bump_flag = SIMPLE_ANIMAL
+ mob_swap_flags = SIMPLE_ANIMAL
+ mob_push_flags = SIMPLE_ANIMAL
+ mob_always_swap = 1
+
+ mob_size = MOB_LARGE // Small mobs can't open doors, it's a huge pain for drones.
+
+ //Used for self-mailing.
+ var/mail_destination = ""
+ var/obj/machinery/drone_fabricator/master_fabricator
+ var/law_type = /datum/ai_laws/drone
+ var/module_type = /obj/item/weapon/robot_module/drone
+ var/obj/item/hat
+ var/hat_x_offset = 0
+ var/hat_y_offset = -13
+ var/serial_number = 0
+ var/name_override = 0
+
+ var/foreign_droid = FALSE
+
+ holder_type = /obj/item/weapon/holder/drone
+
+ can_be_antagged = FALSE
+
+ var/static/list/shell_types = list("Classic" = "repairbot", "Eris" = "maintbot")
+ var/can_pick_shell = TRUE
+ var/list/shell_accessories
+ var/can_blitz = FALSE
+ //vore addition
+ mob_size = MOB_SMALL
+//CORE END
+
+//VARIANTS
/mob/living/silicon/robot/drone/construction
name = "construction drone"
icon_state = "constructiondrone"
diff --git a/modular_chomp/code/modules/mob/living/silicon/robot/drone/swarm/swarm.dm b/modular_chomp/code/modules/mob/living/silicon/robot/drone/swarm/swarm.dm
index c0bc890abb..0cb5295734 100644
--- a/modular_chomp/code/modules/mob/living/silicon/robot/drone/swarm/swarm.dm
+++ b/modular_chomp/code/modules/mob/living/silicon/robot/drone/swarm/swarm.dm
@@ -1,63 +1,4 @@
//Modified copy of regula drone folder
-/mob/living/silicon/robot/drone/swarm
- name = "swarm drone"
- real_name = "drone"
- icon = 'icons/mob/swarmbot.dmi'
- icon_state = "swarmer"
- item_state = "repairbot"
- faction = "swarmer"
- maxHealth = 35
- health = 35
- cell_emp_mult = 0.5
- universal_speak = 0
- universal_understand = 1
- gender = NEUTER
- pass_flags = PASSTABLE
- braintype = "Drone"
- lawupdate = 0
- density = TRUE
- idcard_type = /obj/item/weapon/card/id/syndicate
- req_access = list(999)
- integrated_light_power = 3
- local_transmit = 0
-
- can_pull_size = ITEMSIZE_NO_CONTAINER
- can_pull_mobs = MOB_PULL_SMALLER
- can_enter_vent_with = list(
- /obj,
- /atom/movable/emissive_blocker)
-
- mob_always_swap = 1
-
- speed = 3
-
- softfall = TRUE
-
- mob_size = MOB_LARGE
-
- law_type = /datum/ai_laws/swarm_drone
- module_type = /obj/item/weapon/robot_module/drone/swarm
-
- hat_x_offset = 0
- hat_y_offset = -10
-
- foreign_droid = TRUE
- scrambledcodes = TRUE
-
- holder_type = /obj/item/weapon/holder/drone
-
- can_be_antagged = TRUE
-
- var/spell_setup = list(
- /spell/aoe_turf/conjure/swarmer,
- /spell/aoe_turf/conjure/forcewall/swarm,
- /spell/aoe_turf/conjure/zeropointwell,
- /spell/aoe_turf/conjure/zeropointbarricade,
- /spell/aoe_turf/blink/swarm,
- /spell/aoe_turf/conjure/swarmer/gunner,
- /spell/aoe_turf/conjure/swarmer/melee
- )
-
/mob/living/silicon/robot/drone/swarm/Initialize()
. = ..()
diff --git a/modular_chomp/code/modules/mob/living/silicon/robot/drone/swarm/swarm_types.dm b/modular_chomp/code/modules/mob/living/silicon/robot/drone/swarm/swarm_types.dm
index b8c0e84c42..47148498ed 100644
--- a/modular_chomp/code/modules/mob/living/silicon/robot/drone/swarm/swarm_types.dm
+++ b/modular_chomp/code/modules/mob/living/silicon/robot/drone/swarm/swarm_types.dm
@@ -1,3 +1,66 @@
+//SWRM drone types
+//CORE TYPE
+/mob/living/silicon/robot/drone/swarm
+ name = "swarm drone"
+ real_name = "drone"
+ icon = 'icons/mob/swarmbot.dmi'
+ icon_state = "swarmer"
+ item_state = "repairbot"
+ faction = "swarmer"
+ maxHealth = 35
+ health = 35
+ cell_emp_mult = 0.5
+ universal_speak = 0
+ universal_understand = 1
+ gender = NEUTER
+ pass_flags = PASSTABLE
+ braintype = "Drone"
+ lawupdate = 0
+ density = TRUE
+ idcard_type = /obj/item/weapon/card/id/syndicate
+ req_access = list(999)
+ integrated_light_power = 3
+ local_transmit = 0
+
+ can_pull_size = ITEMSIZE_NO_CONTAINER
+ can_pull_mobs = MOB_PULL_SMALLER
+ can_enter_vent_with = list(
+ /obj,
+ /atom/movable/emissive_blocker)
+
+ mob_always_swap = 1
+
+ speed = 3
+
+ softfall = TRUE
+
+ mob_size = MOB_LARGE
+
+ law_type = /datum/ai_laws/swarm_drone
+ module_type = /obj/item/weapon/robot_module/drone/swarm
+
+ hat_x_offset = 0
+ hat_y_offset = -10
+
+ foreign_droid = TRUE
+ scrambledcodes = TRUE
+
+ holder_type = /obj/item/weapon/holder/drone
+
+ can_be_antagged = TRUE
+
+ var/spell_setup = list(
+ /spell/aoe_turf/conjure/swarmer,
+ /spell/aoe_turf/conjure/forcewall/swarm,
+ /spell/aoe_turf/conjure/zeropointwell,
+ /spell/aoe_turf/conjure/zeropointbarricade,
+ /spell/aoe_turf/blink/swarm,
+ /spell/aoe_turf/conjure/swarmer/gunner,
+ /spell/aoe_turf/conjure/swarmer/melee
+ )
+//CORE END
+
+//VARIANTS
/mob/living/silicon/robot/drone/swarm/gunner
name = "swarm gunner"
real_name = "drone"
diff --git a/vorestation.dme b/vorestation.dme
index 72c3a4b17a..811208489a 100644
--- a/vorestation.dme
+++ b/vorestation.dme
@@ -4615,9 +4615,11 @@
#include "modular_chomp\code\modules\mob\living\silicon\robot\drone\drone_abilities.dm"
#include "modular_chomp\code\modules\mob\living\silicon\robot\drone\drone_console.dm"
#include "modular_chomp\code\modules\mob\living\silicon\robot\drone\drone_damage.dm"
+#include "modular_chomp\code\modules\mob\living\silicon\robot\drone\drone_ghostjoin.dm"
#include "modular_chomp\code\modules\mob\living\silicon\robot\drone\drone_items.dm"
#include "modular_chomp\code\modules\mob\living\silicon\robot\drone\drone_laws.dm"
#include "modular_chomp\code\modules\mob\living\silicon\robot\drone\drone_manufacturer.dm"
+#include "modular_chomp\code\modules\mob\living\silicon\robot\drone\drone_overrides_small.dm"
#include "modular_chomp\code\modules\mob\living\silicon\robot\drone\drone_say.dm"
#include "modular_chomp\code\modules\mob\living\silicon\robot\drone\drone_types.dm"
#include "modular_chomp\code\modules\mob\living\silicon\robot\drone\swarm\swarm.dm"
From 36d7772d67a500db6a23a4a1b3e5126d9154474c Mon Sep 17 00:00:00 2001
From: Sharkmare <34294231+Sharkmare@users.noreply.github.com>
Date: Thu, 13 Apr 2023 13:36:41 +0200
Subject: [PATCH 5/6] Malf Drone POI support
Add support for POI
---
.../mob/living/silicon/robot/drone/drone.dm | 22 +++++--------------
.../silicon/robot/drone/drone_ghostjoin.dm | 6 +++--
.../silicon/robot/drone/drone_manufacturer.dm | 22 ++++++++++---------
.../living/silicon/robot/drone/drone_types.dm | 20 ++++++++++++++++-
4 files changed, 40 insertions(+), 30 deletions(-)
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
index 52b242e8ab..de8d502665 100644
--- a/modular_chomp/code/modules/mob/living/silicon/robot/drone/drone.dm
+++ b/modular_chomp/code/modules/mob/living/silicon/robot/drone/drone.dm
@@ -50,16 +50,6 @@ var/list/mob_hat_cache = list()
updateicon()
updatename()
-/mob/living/silicon/robot/drone/init()
- if(!scrambledcodes && !foreign_droid)
- aiCamera = new/obj/item/device/camera/siliconcam/drone_camera(src)
- additional_law_channels["Drone"] = ":d"
- if(!laws) laws = new law_type
- if(!module) module = new module_type(src)
-
- flavor_text = "It's a tiny little repair drone. The casing is stamped with an corporate logo and the subscript: '[using_map.company_name] Recursive Repair Systems: Fixing Tomorrow's Problem, Today!'"
- playsound(src, 'sound/machines/twobeep.ogg', 50, 0)
-
/mob/living/silicon/robot/drone/updateicon()
cut_overlays()
@@ -256,7 +246,11 @@ var/list/mob_hat_cache = list()
clear_supplied_laws(1)
clear_inherent_laws(1)
clear_ion_laws(1)
- laws = new law_type
+ if(faction == "malf_drone")
+ laws = new /datum/ai_laws/nanotrasen/malfunction
+ foreign_droid = TRUE
+ else
+ laws = new law_type
//Reboot procs.
@@ -278,9 +272,3 @@ var/list/mob_hat_cache = list()
to_chat(src,"Loaded.")
spawn(4 SECONDS)
welcome_drone()
-
-/mob/living/silicon/robot/drone/proc/welcome_drone()
- to_chat(src, "You are a maintenance drone, a tiny-brained robotic repair machine.")
- to_chat(src, "You have no individual will, no personality, and no drives or urges other than your laws.")
- to_chat(src, "Remember, you are lawed against interference with the crew. Also remember, you DO NOT take orders from the AI.")
- to_chat(src, "Use say ;Hello to talk to other drones and say Hello to speak silently to your nearby fellows.")
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
index a6a2c8764d..797b8ab213 100644
--- 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
@@ -18,7 +18,6 @@
//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."
@@ -81,5 +80,8 @@
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)
\ No newline at end of file
+ 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_manufacturer.dm b/modular_chomp/code/modules/mob/living/silicon/robot/drone/drone_manufacturer.dm
index 9b660e9cc1..d6356e313e 100644
--- a/modular_chomp/code/modules/mob/living/silicon/robot/drone/drone_manufacturer.dm
+++ b/modular_chomp/code/modules/mob/living/silicon/robot/drone/drone_manufacturer.dm
@@ -71,8 +71,7 @@
if(produce_drones && drone_progress >= 100 && istype(user,/mob/observer/dead) && config.allow_drone_spawn && count_drones() < config.max_maint_drones)
. += "
A drone is prepared. Select 'Join As Drone' from the Ghost tab to spawn as a maintenance drone."
-/obj/machinery/drone_fabricator/proc/create_drone(var/client/player)
- choose_dronetype(possible_drones) //Call Drone choice before executing create_drone
+/obj/machinery/drone_fabricator/proc/create_drone(var/client/player,var/faction = "")
if(stat & NOPOWER)
return
@@ -81,6 +80,7 @@
if(player && !istype(player.mob,/mob/observer/dead))
return
+ choose_dronetype(possible_drones) //Call Drone choice before executing create_drone
visible_message("\The [src] churns and grinds as it lurches into motion, disgorging a shiny new drone after a few moments.")
flick("h_lathe_leave",src)
@@ -89,8 +89,11 @@
time_last_drone = world.time
var/mob/living/silicon/robot/drone/new_drone = new drone_type(get_turf(src))
+ if(faction)
+ new_drone.faction = faction
if(player)
- announce_ghost_joinleave(player, 0, "They have taken control over a maintenance drone.")
+ if(!faction)
+ announce_ghost_joinleave(player, 0, "They have taken control over a maintenance drone.")
if(player.mob && player.mob.mind) player.mob.mind.reset()
new_drone.transfer_personality(player)
@@ -105,10 +108,9 @@
) //List of drone types to choose from.//Changeable in mapping.
/obj/machinery/drone_fabricator/proc/choose_dronetype(possible_drones)
- if(!LAZYLEN(possible_drones)-1)
- drone_type = possible_drones[1]
- return
- var/choice
- choice = input(usr,"What module would you like to use?") as null|anything in possible_drones
- if(!choice) return
- drone_type = possible_drones[choice]
+ if(LAZYLEN(possible_drones)<2)
+ drone_type = possible_drones[possible_drones[1]]
+ else
+ drone_type = input(usr,"What module would you like to use?") as null|anything in possible_drones
+ if(!drone_type) return
+ drone_type = possible_drones[drone_type]
diff --git a/modular_chomp/code/modules/mob/living/silicon/robot/drone/drone_types.dm b/modular_chomp/code/modules/mob/living/silicon/robot/drone/drone_types.dm
index 644d983a31..5e73547db7 100644
--- a/modular_chomp/code/modules/mob/living/silicon/robot/drone/drone_types.dm
+++ b/modular_chomp/code/modules/mob/living/silicon/robot/drone/drone_types.dm
@@ -55,6 +55,22 @@
var/can_blitz = FALSE
//vore addition
mob_size = MOB_SMALL
+/mob/living/silicon/robot/drone/proc/welcome_drone()
+ to_chat(src, "You are a maintenance drone, a tiny-brained robotic repair machine.")
+ to_chat(src, "You have no individual will, no personality, and no drives or urges other than your laws.")
+ to_chat(src, "Remember, you are lawed against interference with the crew. Also remember, you DO NOT take orders from the AI.")
+ to_chat(src, "Use say ;Hello to talk to other drones and say Hello to speak silently to your nearby fellows.")
+ if(faction == "malf_drone")
+ to_chat(src, "Use Directive 0 in effect.")
+/mob/living/silicon/robot/drone/init()
+ if(!scrambledcodes && !foreign_droid)
+ aiCamera = new/obj/item/device/camera/siliconcam/drone_camera(src)
+ additional_law_channels["Drone"] = ":d"
+ if(!laws) laws = new law_type
+ if(!module) module = new module_type(src)
+
+ flavor_text = "It's a tiny little repair drone. The casing is stamped with an corporate logo and the subscript: '[using_map.company_name] Recursive Repair Systems: Fixing Tomorrow's Problem, Today!'"
+ playsound(src, 'sound/machines/twobeep.ogg', 50, 0)
//CORE END
//VARIANTS
@@ -73,6 +89,8 @@
to_chat(src, "You are assigned to a Sol Central construction project. The name is irrelevant. Your task is to complete construction and subsystem integration as soon as possible.")
to_chat(src, "Use :d to talk to other drones and say to speak silently to your nearby fellows.")
to_chat(src, "You do not follow orders from anyone; not the AI, not humans, and not other synthetics..")
+ if(faction == "malf_drone")
+ to_chat(src, "Use Directive 0 in effect.")
/mob/living/silicon/robot/drone/construction/init()
..()
flavor_text = "It's a bulky construction drone stamped with a Sol Central glyph."
@@ -87,7 +105,7 @@
can_pull_mobs = MOB_PULL_SAME
can_pick_shell = FALSE
shell_accessories = list("eyes-miningdrone")
-/mob/living/silicon/robot/drone/construction/init()
+/mob/living/silicon/robot/drone/mining/init()
..()
flavor_text = "It's a bulky mining drone stamped with a Grayson logo."
From df2d7f67e63a437526580d308b4ec7c39e8a9ca0 Mon Sep 17 00:00:00 2001
From: Sharkmare <34294231+Sharkmare@users.noreply.github.com>
Date: Thu, 13 Apr 2023 14:33:03 +0200
Subject: [PATCH 6/6] closing html tags
---
.../modules/mob/living/silicon/robot/drone/drone_types.dm | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/modular_chomp/code/modules/mob/living/silicon/robot/drone/drone_types.dm b/modular_chomp/code/modules/mob/living/silicon/robot/drone/drone_types.dm
index 5e73547db7..87ed401e5d 100644
--- a/modular_chomp/code/modules/mob/living/silicon/robot/drone/drone_types.dm
+++ b/modular_chomp/code/modules/mob/living/silicon/robot/drone/drone_types.dm
@@ -61,7 +61,7 @@
to_chat(src, "Remember, you are lawed against interference with the crew. Also remember, you DO NOT take orders from the AI.")
to_chat(src, "Use say ;Hello to talk to other drones and say Hello to speak silently to your nearby fellows.")
if(faction == "malf_drone")
- to_chat(src, "Use Directive 0 in effect.")
+ to_chat(src, "Use Directive 0 in effect.")
/mob/living/silicon/robot/drone/init()
if(!scrambledcodes && !foreign_droid)
aiCamera = new/obj/item/device/camera/siliconcam/drone_camera(src)
@@ -90,7 +90,7 @@
to_chat(src, "Use :d to talk to other drones and say to speak silently to your nearby fellows.")
to_chat(src, "You do not follow orders from anyone; not the AI, not humans, and not other synthetics..")
if(faction == "malf_drone")
- to_chat(src, "Use Directive 0 in effect.")
+ to_chat(src, "Use Directive 0 in effect.")
/mob/living/silicon/robot/drone/construction/init()
..()
flavor_text = "It's a bulky construction drone stamped with a Sol Central glyph."