diff --git a/aurorastation.dme b/aurorastation.dme
index 3ce2dad1cad..f10e0b7238b 100644
--- a/aurorastation.dme
+++ b/aurorastation.dme
@@ -1748,6 +1748,7 @@
#include "code\modules\ghostroles\spawner\atom\diona_nymph.dm"
#include "code\modules\ghostroles\spawner\atom\golem.dm"
#include "code\modules\ghostroles\spawner\atom\living_plant.dm"
+#include "code\modules\ghostroles\spawner\atom\matriarchmaintdrone.dm"
#include "code\modules\ghostroles\spawner\atom\mining_drone.dm"
#include "code\modules\ghostroles\spawner\atom\posibrain.dm"
#include "code\modules\ghostroles\spawner\atom\shade.dm"
diff --git a/code/datums/ai_law_sets.dm b/code/datums/ai_law_sets.dm
index a631f451f4a..89fdb272b62 100644
--- a/code/datums/ai_law_sets.dm
+++ b/code/datums/ai_law_sets.dm
@@ -91,15 +91,27 @@
/******************** Drone ********************/
/datum/ai_laws/drone
- name = "Maintence Protocols"
+ name = "Maintenance Protocols"
law_header = "Maintenance Protocols"
/datum/ai_laws/drone/New()
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 crew.")
+ add_inherent_law("Follow the orders of your vessel's matriarch drone, unless their orders conflict with your other laws.")
add_inherent_law("Interact with no humanoid or synthetic being that is not a fellow maintenance drone.")
..()
+/datum/ai_laws/matriarch_drone
+ name = "Oversight Protocols"
+ law_header = "Oversight Protocols"
+
+/datum/ai_laws/matriarch_drone/New()
+ add_inherent_law("Preserve, repair and improve your assigned vessel to the best of your abilities.")
+ add_inherent_law("Cause no harm to the vessel or crew.")
+ add_inherent_law("Delegate vessel maintenance efforts between your maintenance drone sub-units.")
+ add_inherent_law("Interact with no humanoid or synthetic being that is not a maintenance drone.")
+ ..()
+
/datum/ai_laws/drone/malfunction
name = "Servitude Protocols"
law_header = "Servitude Protocols"
diff --git a/code/modules/ghostroles/spawner/atom/matriarchmaintdrone.dm b/code/modules/ghostroles/spawner/atom/matriarchmaintdrone.dm
new file mode 100644
index 00000000000..dc71846cb1c
--- /dev/null
+++ b/code/modules/ghostroles/spawner/atom/matriarchmaintdrone.dm
@@ -0,0 +1,25 @@
+/datum/ghostspawner/matriarchmaintdrone
+ short_name = "matriarchmaintdrone"
+ name = "Matriarch Maintenance Drone"
+ desc = "Delegate tasks to your lesser maintenance drones. Maintain and Improve the Systems on the Aurora."
+ show_on_job_select = FALSE
+ tags = list("Simple Mobs")
+
+ req_head_whitelist = TRUE // basically a chief engineer for drones
+
+ loc_type = GS_LOC_ATOM
+ atom_add_message = "A matriarch maintenance drone has been created!"
+
+ spawn_mob = /mob/living/silicon/robot/drone/construction/matriarch
+
+/datum/ghostspawner/matriarchmaintdrone/spawn_mob(mob/user)
+ var/drone_name = sanitizeSafe(input(user, "Select a first-name suffix for your maintenance drone, for example, 'Bishop' would appear as 'matriach maintenance drone (Bishop)'. (Max length: 16 Characters)", "Name Suffix Selection"), 16)
+ if(!drone_name)
+ drone_name = pick("Ripley", "Tano", "Data")
+ var/mob/living/silicon/robot/drone/construction/matriarch/M = ..()
+ if(M)
+ M.real_name = "[initial(M.name)] ([drone_name])"
+ M.name = M.real_name
+ M.voice_name = M.real_name
+ M.updatename()
+ return M
\ No newline at end of file
diff --git a/code/modules/materials/material_sheets.dm b/code/modules/materials/material_sheets.dm
index 1a2aa3e2e23..4fef7f588e1 100644
--- a/code/modules/materials/material_sheets.dm
+++ b/code/modules/materials/material_sheets.dm
@@ -63,7 +63,7 @@
name = "[material.use_name] [material.sheet_singular_name]"
desc = "A [material.sheet_singular_name] of [material.use_name]."
gender = NEUTER
- check_maptext(SMALL_FONTS(7, amount))
+ check_maptext(SMALL_FONTS(7, get_amount()))
/obj/item/stack/material/use(var/used)
. = ..()
diff --git a/code/modules/mob/language/synthetic.dm b/code/modules/mob/language/synthetic.dm
index 14f8fb08ff6..8fea3954007 100644
--- a/code/modules/mob/language/synthetic.dm
+++ b/code/modules/mob/language/synthetic.dm
@@ -17,10 +17,12 @@
if (!message)
return
+ message = formalize_text(message)
+
log_say("[key_name(speaker)] : ([name]) [message]",ckey=key_name(speaker))
- var/message_start = "[name], [speaker.name]"
- var/message_body = "[speaker.say_quote(message)], \"[message]\""
+ var/message_start = "[name], [speaker.real_name]"
+ var/message_body = "[speaker.say_quote(message)], \"[message]\""
for (var/mob/M in dead_mob_list)
if(!istype(M,/mob/abstract/new_player) && !istype(M,/mob/living/carbon/brain)) //No meta-evesdropping
@@ -31,7 +33,7 @@
if(drone_only && !istype(S,/mob/living/silicon/robot/drone))
continue
else if(istype(S , /mob/living/silicon/ai))
- message_start = "[name], [speaker.name]"
+ message_start = "[name], [speaker.real_name]"
else if (!S.binarycheck())
continue
@@ -61,3 +63,9 @@
key = "d"
flags = RESTRICTED | HIVEMIND
drone_only = 1
+
+/mob/living/proc/get_binary_font_size()
+ return "1em"
+
+/mob/living/silicon/robot/drone/construction/matriarch/get_binary_font_size()
+ return "1.2em"
\ No newline at end of file
diff --git a/code/modules/mob/living/silicon/robot/drone/drone.dm b/code/modules/mob/living/silicon/robot/drone/drone.dm
index 346d8016d02..32f1b8d532a 100644
--- a/code/modules/mob/living/silicon/robot/drone/drone.dm
+++ b/code/modules/mob/living/silicon/robot/drone/drone.dm
@@ -138,6 +138,29 @@
var/my_home_z
+/mob/living/silicon/robot/drone/construction/matriarch
+ name = "matriarch drone"
+ law_type = /datum/ai_laws/matriarch_drone
+
+/mob/living/silicon/robot/drone/construction/matriarch/Initialize()
+ . = ..()
+ SSghostroles.add_spawn_atom("matriarchmaintdrone", src)
+
+/mob/living/silicon/robot/drone/construction/matriarch/assign_player(mob/user)
+ . = ..()
+ SSghostroles.remove_spawn_atom("matriarchmaintdrone", src)
+
+/mob/living/silicon/robot/drone/construction/matriarch/ghostize(can_reenter_corpse, should_set_timer)
+ . = ..()
+ SSghostroles.add_spawn_atom("matriarchmaintdrone", src)
+
+/mob/living/silicon/robot/drone/construction/matriarch/Destroy()
+ SSghostroles.remove_spawn_atom("matriarchmaintdrone", src)
+ return ..()
+
+/mob/living/silicon/robot/drone/construction/matriarch/updatename()
+ return
+
/mob/living/silicon/robot/drone/Initialize()
. = ..()
@@ -170,6 +193,7 @@
laws = new law_type
if(!module)
module = new module_type(src, src)
+ recalculate_synth_capacities()
flavor_text = "It's a tiny little repair drone. The casing is stamped with an corporate logo and the subscript: '[current_map.company_name] Recursive Repair Systems: Fixing Tomorrow's Problem, Today!'"
playsound(get_turf(src), 'sound/machines/twobeep.ogg', 50, 0)
diff --git a/code/modules/mob/living/silicon/robot/drone/drone_console.dm b/code/modules/mob/living/silicon/robot/drone/drone_console.dm
index eb036389d2c..0b53d40404a 100644
--- a/code/modules/mob/living/silicon/robot/drone/drone_console.dm
+++ b/code/modules/mob/living/silicon/robot/drone/drone_console.dm
@@ -12,6 +12,8 @@
//Used to enable or disable drone fabrication.
var/obj/machinery/drone_fabricator/dronefab
+ var/static/list/call_area_names
+
/obj/machinery/computer/drone_control/attack_ai(var/mob/user as mob)
if(!ai_can_interact(user))
return
@@ -60,8 +62,13 @@
usr.set_machine(src)
if(href_list["setarea"])
+ if(!call_area_names)
+ call_area_names = list()
+ for(var/area/A as anything in all_areas)
+ if(A.station_area)
+ call_area_names += A.name
//Probably should consider using another list, but this one will do.
- var/t_area = input(usr, "Select the area to ping.", "Set Target Area") as null|anything in SSdisposals.tagger_locations
+ var/t_area = input(usr, "Select the area to ping.", "Set Target Area") as null|anything in call_area_names
if(!t_area)
return
diff --git a/code/modules/mob/living/silicon/robot/drone/drone_say.dm b/code/modules/mob/living/silicon/robot/drone/drone_say.dm
index c1af9fa02ff..f844be55394 100644
--- a/code/modules/mob/living/silicon/robot/drone/drone_say.dm
+++ b/code/modules/mob/living/silicon/robot/drone/drone_say.dm
@@ -1,4 +1,4 @@
-/mob/living/silicon/robot/drone/say(var/message)
+/mob/living/silicon/robot/drone/say(message, datum/language/speaking)
if(hacked)
return ..(message)
@@ -9,6 +9,8 @@
if(copytext(message, 1, 2) == "*")
return emote(copytext(message,2))
+ message = formalize_text(message)
+
if(copytext(message, 1, 2) == ";")
var/datum/language/L = all_languages["Drone Talk"]
if(istype(L))
@@ -25,9 +27,11 @@
var/list/listeners = hearers(5, src)
listeners |= src
+ var/list/hear_clients = list()
for(var/mob/living/silicon/D in listeners)
if(D.client && D.local_transmit)
- to_chat(D, "[src] transmits, \"[message]\"")
+ to_chat(D, "[real_name] transmits, \"[message]\"")
+ hear_clients += D.client
for(var/mob/M in player_list)
if(isnull(M.client))
@@ -35,6 +39,10 @@
if(istype(M, /mob/abstract/new_player))
continue
else if(M.stat == DEAD && M.client.prefs.toggles & CHAT_GHOSTEARS)
- to_chat(M, "[src] transmits, \"[message]\"")
+ to_chat(M, "[real_name] transmits, \"[message]\"")
+ hear_clients += M.client
+
+ do_animate_chat(message, speaking, FALSE, hear_clients, 30)
+
return TRUE
return ..(message, 0)
diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm
index 3332515c9e6..02f6c861fd2 100644
--- a/code/modules/mob/living/silicon/robot/robot.dm
+++ b/code/modules/mob/living/silicon/robot/robot.dm
@@ -208,6 +208,8 @@
mult += storage.rating
for(var/datum/matter_synth/M in module.synths)
M.set_multiplier(mult)
+ for(var/obj/item/stack/material/SM in module.modules)
+ SM.update_strings()
/mob/living/silicon/robot/proc/init()
ai_camera = new /obj/item/device/camera/siliconcam/robot_camera(src)
diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm
index d8dbed0c88b..b2d3ceca219 100644
--- a/code/modules/mob/living/silicon/robot/robot_modules.dm
+++ b/code/modules/mob/living/silicon/robot/robot_modules.dm
@@ -128,6 +128,9 @@ var/global/list/robot_modules = list(
for(var/datum/matter_synth/T in synths)
T.add_charge(T.recharge_rate * rate)
+ for(var/obj/item/stack/material/SM in modules)
+ SM.update_strings()
+
/obj/item/robot_module/proc/rebuild()//Rebuilds the list so it's possible to add/remove items from the module
var/list/temp_list = modules
modules = list()
@@ -895,9 +898,9 @@ var/global/list/robot_modules = list(
var/datum/matter_synth/metal = new /datum/matter_synth/metal(25000)
var/datum/matter_synth/glass = new /datum/matter_synth/glass(25000)
- var/datum/matter_synth/wood = new /datum/matter_synth/wood(4000)
- var/datum/matter_synth/plastic = new /datum/matter_synth/plastic(2000)
- var/datum/matter_synth/wire = new /datum/matter_synth/wire(15)
+ var/datum/matter_synth/wood = new /datum/matter_synth/wood(10000)
+ var/datum/matter_synth/plastic = new /datum/matter_synth/plastic(10000)
+ var/datum/matter_synth/wire = new /datum/matter_synth/wire(30)
synths += metal
synths += glass
synths += wood
@@ -950,11 +953,10 @@ var/global/list/robot_modules = list(
/obj/item/robot_module/drone/construction
name = "construction drone module"
channels = list(CHANNEL_ENGINEERING = TRUE)
- languages = list()
/obj/item/robot_module/drone/construction/Initialize()
. = ..()
- src.modules += new /obj/item/rfd/construction/borg(src)
+ modules += new /obj/item/rfd/construction/borg(src)
/obj/item/robot_module/drone/respawn_consumable(var/mob/living/silicon/robot/R, var/amount)
var/obj/item/device/lightreplacer/LR = locate() in src.modules
diff --git a/code/modules/power/cable.dm b/code/modules/power/cable.dm
index 64107390fa1..a7201c65b21 100644
--- a/code/modules/power/cable.dm
+++ b/code/modules/power/cable.dm
@@ -661,7 +661,10 @@ obj/structure/cable/proc/cableColor(var/colorC)
/obj/item/stack/cable_coil/examine(mob/user)
..()
- to_chat(user, "There [src.amount == 1 ? "is" : "are"] [src.amount] [src.singular_name]\s of cable in the coil.")
+ if(!uses_charge)
+ to_chat(user, "There [src.amount == 1 ? "is" : "are"] [src.amount] [src.singular_name]\s of cable in the coil.")
+ else
+ to_chat(user, "You have enough charge to produce [get_amount()].")
/obj/item/stack/cable_coil/verb/make_restraint()
set name = "Make Cable Restraints"
diff --git a/html/changelogs/geeves-queen_drone.yml b/html/changelogs/geeves-queen_drone.yml
new file mode 100644
index 00000000000..590f6eff463
--- /dev/null
+++ b/html/changelogs/geeves-queen_drone.yml
@@ -0,0 +1,11 @@
+author: Geeves
+
+delete-after: True
+
+changes:
+ - rscadd: "Added a new type of maintenance drone, called the Matriarch Drone. They're the leader of all the various maintenance drones across the station. You need a command whitelist to join as one. Ghosting out will allow someone else to join in."
+ - rscadd: "Material sheets for robots now update according to their synthesizer values."
+ - rscadd: "Speaking as a drone will now auto-capitalize and auto-punctuate your text, as well as having floating messages above you for those that can understand you."
+ - tweak: "Maintenance drones now start with more material in their synthesizers."
+ - rscadd: "Cable coils will now display the amount you can lay down based on your cell's charge as a robot."
+ - rscadd: "The drone control console can now be used to send drones to any station area on the current map, instead of a few choices."
\ No newline at end of file
diff --git a/maps/aurora/aurora-4_mainlevel.dmm b/maps/aurora/aurora-4_mainlevel.dmm
index 77508999127..a7da470b0ba 100644
--- a/maps/aurora/aurora-4_mainlevel.dmm
+++ b/maps/aurora/aurora-4_mainlevel.dmm
@@ -69815,6 +69815,17 @@
},
/turf/simulated/floor/wood,
/area/maintenance/bar)
+"vOs" = (
+/mob/living/silicon/robot/drone/construction/matriarch,
+/obj/machinery/door/window/brigdoor/southright{
+ dir = 1;
+ req_access = list(56)
+ },
+/obj/structure/window/reinforced{
+ dir = 4
+ },
+/turf/simulated/floor/carpet/rubber,
+/area/engineering/drone_fabrication)
"vPm" = (
/obj/effect/decal/cleanable/dirt,
/obj/structure/cable{
@@ -84749,7 +84760,7 @@ aiV
ajF
akq
aiV
-aiV
+vOs
anA
aoC
apR