diff --git a/_maps/RandomRuins/IceRuins/bubberstation/icemoon_interdyne.dmm b/_maps/RandomRuins/IceRuins/bubberstation/icemoon_interdyne.dmm
index 44fcc284f54c2a..125e66a9a924b5 100644
--- a/_maps/RandomRuins/IceRuins/bubberstation/icemoon_interdyne.dmm
+++ b/_maps/RandomRuins/IceRuins/bubberstation/icemoon_interdyne.dmm
@@ -2165,18 +2165,6 @@
/turf/open/floor/wood,
/area/ruin/syndicate_lava_base/testlab)
"pN" = (
-/obj/item/disk/design_disk/limbs/ethereal{
- pixel_y = 2
- },
-/obj/item/disk/design_disk/limbs/felinid{
- pixel_y = 4
- },
-/obj/item/disk/design_disk/limbs/lizard{
- pixel_y = 6
- },
-/obj/item/disk/design_disk/limbs/plasmaman{
- pixel_y = 8
- },
/obj/structure/table/reinforced,
/obj/machinery/light/directional/south,
/obj/effect/turf_decal/tile/blue{
diff --git a/_maps/RandomRuins/SpaceRuins/skyrat/port_tarkon.dmm b/_maps/RandomRuins/SpaceRuins/skyrat/port_tarkon.dmm
index f791fe74a0fc3f..dd4cdc1f17f4ee 100644
--- a/_maps/RandomRuins/SpaceRuins/skyrat/port_tarkon.dmm
+++ b/_maps/RandomRuins/SpaceRuins/skyrat/port_tarkon.dmm
@@ -3978,13 +3978,16 @@
dir = 1
},
/obj/structure/table/reinforced,
-/obj/item/hackc{
- pixel_x = 10
- },
-/obj/item/hackc{
- pixel_x = -10
- },
-/obj/item/hackc,
+/obj/item/flashlight/lantern,
+/obj/item/flashlight/lantern,
+/obj/item/flashlight/lantern,
+/obj/item/flashlight/lantern,
+/obj/item/flashlight/lantern,
+/obj/item/flashlight/lantern,
+/obj/item/flashlight/lantern,
+/obj/item/flashlight/lantern,
+/obj/item/flashlight/lantern,
+/obj/item/flashlight/lantern,
/turf/open/floor/iron,
/area/ruin/space/has_grav/port_tarkon)
"nY" = (
@@ -4241,13 +4244,7 @@
dir = 1
},
/obj/machinery/camera/preset/tarkon/directional/north,
-/obj/structure/table/reinforced,
-/obj/item/flashlight/lantern,
-/obj/item/flashlight/lantern,
-/obj/item/flashlight/lantern,
-/obj/item/flashlight/lantern,
-/obj/item/flashlight/lantern,
-/obj/item/flashlight/lantern,
+/obj/effect/mob_spawn/ghost_role/human/tarkon/sec,
/turf/open/floor/iron,
/area/ruin/space/has_grav/port_tarkon)
"oY" = (
@@ -10793,6 +10790,8 @@
/obj/item/storage/box/nif_ghost_box/ghost_role{
pixel_x = -7
},
+/obj/item/storage/belt/utility/full,
+/obj/item/storage/belt/utility/full,
/turf/open/floor/iron,
/area/ruin/space/has_grav/port_tarkon)
"Mc" = (
@@ -11883,10 +11882,15 @@
/turf/open/floor/iron,
/area/ruin/space/has_grav/port_tarkon/cargo)
"Qd" = (
+/obj/structure/table/reinforced,
+/obj/item/hackc{
+ pixel_x = 10
+ },
+/obj/item/hackc{
+ pixel_x = -10
+ },
+/obj/item/hackc,
/obj/effect/turf_decal/tile/yellow/anticorner,
-/obj/structure/table,
-/obj/item/storage/belt/utility/full,
-/obj/item/storage/belt/utility/full,
/turf/open/floor/iron,
/area/ruin/space/has_grav/port_tarkon)
"Qe" = (
@@ -12550,7 +12554,7 @@
/obj/effect/turf_decal/tile/yellow/anticorner{
dir = 4
},
-/obj/effect/mob_spawn/ghost_role/human/tarkon,
+/obj/effect/mob_spawn/ghost_role/robot/tarkon,
/turf/open/floor/iron,
/area/ruin/space/has_grav/port_tarkon)
"Ss" = (
@@ -13699,7 +13703,7 @@
/obj/effect/turf_decal/tile/yellow/half{
dir = 1
},
-/obj/effect/mob_spawn/ghost_role/human/tarkon/sec,
+/obj/effect/mob_spawn/ghost_role/human/tarkon,
/turf/open/floor/iron,
/area/ruin/space/has_grav/port_tarkon)
"VZ" = (
diff --git a/code/__DEFINES/exosuit_fab.dm b/code/__DEFINES/exosuit_fab.dm
index 54d72dcae7e0d4..0f36232fc8e226 100644
--- a/code/__DEFINES/exosuit_fab.dm
+++ b/code/__DEFINES/exosuit_fab.dm
@@ -13,6 +13,8 @@
//Bubber addition start
/// Module is compatible with Research Cyborg model
#define BORG_MODEL_RESEARCH (1<<6)
+/// Module is compatible with Tarkon Cyborg model
+#define BORG_MODEL_TARKON (1<<7)
//Bubber addition end
/// Module is compatible with Ripley Exosuit models
diff --git a/code/__DEFINES/~~bubber_defines/quirks.dm b/code/__DEFINES/~~bubber_defines/quirks.dm
new file mode 100644
index 00000000000000..38d534c1ed1b8d
--- /dev/null
+++ b/code/__DEFINES/~~bubber_defines/quirks.dm
@@ -0,0 +1 @@
+#define HEMOPHAGE "hemophage"
diff --git a/code/__DEFINES/~~bubber_defines/research/research_categories.dm b/code/__DEFINES/~~bubber_defines/research/research_categories.dm
index 32d6fb02ffa9a7..a4f2c8727f2ce6 100644
--- a/code/__DEFINES/~~bubber_defines/research/research_categories.dm
+++ b/code/__DEFINES/~~bubber_defines/research/research_categories.dm
@@ -1,5 +1,6 @@
//I'm tired. This is defines for mech fabs.
#define RND_SUBCATEGORY_MECHFAB_CYBORG_MODULES_RESEARCH "/Research Cyborgs"
+#define RND_SUBCATEGORY_MECHFAB_CYBORG_MODULES_TARKON "/Tarkon Cyborgs"
// Colonial Marine Resequencer Categories
#define RND_CATEGORY_CMR_APPAREL "Apparel/Clothing"
diff --git a/code/__DEFINES/~~bubber_defines/robot_defines.dm b/code/__DEFINES/~~bubber_defines/robot_defines.dm
index 8a086f942e97f3..8d059095ae7fe4 100644
--- a/code/__DEFINES/~~bubber_defines/robot_defines.dm
+++ b/code/__DEFINES/~~bubber_defines/robot_defines.dm
@@ -90,6 +90,10 @@
#define CYBORG_ICON_SCI 'modular_zubbers/code/modules/silicons/borgs/sprites/robot_sci.dmi'
#define CYBORG_ICON_SCI_HAYDEE_BUBBER 'modular_zubbers/code/modules/silicons/borgs/sprites/curverobot_sci.dmi'
+//TARKON BORG ICON DEFINES
+#define CYBORG_ICON_TARKON_WIDE_BUBBER 'modular_zubbers/code/modules/silicons/borgs/sprites/widerobot_tarkon.dmi'
+#define CYBORG_ICON_TARKON_TALL_BUBBER 'modular_zubbers/code/modules/silicons/borgs/sprites/tallrobot_tarkon.dmi'
+
// RAPTOR BORG ICON TYPE DEFINE
#define CYBORG_ICON_TYPE_RAPTOR "raptor"
@@ -129,7 +133,7 @@
#define CYBORG_ICON_STATE_SEC_FELI "FELI-Security"
#define CYBORG_ICON_STATE_SYNDI_FELI "FELI-Combat"
#define CYBORG_ICON_STATE_NINJA_FELI "FELI-Ninja"
-
+#define CYBORG_ICON_STATE_TARKON_FELI "FELI-Tarkon"
// KITTY BORG DEFINES BELOW
diff --git a/code/datums/components/bloodysoles.dm b/code/datums/components/bloodysoles.dm
index 09c945c2f8d319..aa6d6ab1f72c8a 100644
--- a/code/datums/components/bloodysoles.dm
+++ b/code/datums/components/bloodysoles.dm
@@ -271,7 +271,7 @@
dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS
equipped_slot = ITEM_SLOT_FEET
- var/static/mutable_appearance/bloody_feet
+ var/mutable_appearance/bloody_feet //BUBBER EDIT - ORIGINAL: var/static/mutable_appearance/bloody_feet
/// List of DNA on mob's feet, so we can handle it separately from blood on mob's hands
var/list/blood_DNA = null
@@ -282,17 +282,35 @@
wielder = parent
+ /*BUBBER EDIT BEGIN - Species specific blood icons.
if(!bloody_feet)
bloody_feet = mutable_appearance('icons/effects/blood.dmi', "shoeblood", SHOES_LAYER)
+ */
RegisterSignal(parent, COMSIG_COMPONENT_CLEAN_ACT, PROC_REF(on_clean))
RegisterSignal(parent, COMSIG_STEP_ON_BLOOD, PROC_REF(on_step_blood))
RegisterSignals(parent, list(COMSIG_MOB_EQUIPPED_ITEM, COMSIG_MOB_UNEQUIPPED_ITEM), PROC_REF(shoecover))
+ // BUBBER ADDITION BEGIN - Species specific blood icons.
+ RegisterSignal(parent, COMSIG_SPECIES_GAIN, PROC_REF(on_species_change))
+ RegisterSignal(parent, COMSIG_SPECIES_LOSS, PROC_REF(on_species_change))
+ // BUBBER ADDITION END
if(new_blood)
blood_DNA = new_blood
update_icon()
+// BUBBER ADDITION BEGIN - Species specific blood icons.
+/datum/component/bloodysoles/feet/proc/on_species_change(datum/source)
+ SIGNAL_HANDLER
+ update_icon()
+
+/datum/component/bloodysoles/feet/proc/get_blood_appearance()
+ var/icon/blood_icon_file = ishuman(wielder) && icon_exists('modular_zubbers/icons/effects/blood_species.dmi', "shoeblood_[wielder.dna.species.id]") ? 'modular_zubbers/icons/effects/blood_species.dmi' : 'icons/effects/blood.dmi'
+ var/blood_icon_state = ishuman(wielder) && icon_exists('modular_zubbers/icons/effects/blood_species.dmi', "shoeblood_[wielder.dna.species.id]") ? "shoeblood_[wielder.dna.species.id]" : "shoeblood"
+
+ return mutable_appearance(blood_icon_file, blood_icon_state, SHOES_LAYER)
+// BUBBER ADDITION END
+
/datum/component/bloodysoles/feet/InheritComponent(datum/component/bloodysoles/feet/soles, original, list/new_blood)
if (!length(new_blood))
return
@@ -316,6 +334,7 @@
wielder.update_worn_shoes()
return
+ bloody_feet = get_blood_appearance() // BUBBER EDIT ADDITION
bloody_feet.color = wielder.get_blood_dna_color()
wielder.overlays_standing[SHOES_LAYER] = bloody_feet
wielder.apply_overlay(SHOES_LAYER)
diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm
index 1bdb47a185418f..df030eb12be16d 100644
--- a/code/modules/clothing/clothing.dm
+++ b/code/modules/clothing/clothing.dm
@@ -654,7 +654,14 @@ BLIND // can't see anything
if(clothing_flags & LARGE_WORN_ICON)
blood_overlay = mutable_appearance('icons/effects/64x64.dmi', "[blood_state]blood_large")
else
- blood_overlay = mutable_appearance('icons/effects/blood.dmi', "[blood_state]blood")
+ /*BUBBER EDIT BEGIN - Species specific blood icons.
+ blood_overlay = mutable_appearance('icons/effects/blood.dmi', "[blood_state]blood") ORIGNAL*/
+ var/mob/living/carbon/human/wearer = loc
+ var/icon/blood_icon_file = ishuman(wearer) && icon_exists('modular_zubbers/icons/effects/blood_species.dmi', "[blood_state]blood_[wearer.dna.species.id]") ? 'modular_zubbers/icons/effects/blood_species.dmi' : 'icons/effects/blood.dmi'
+ var/blood_icon_state = ishuman(wearer) && icon_exists('modular_zubbers/icons/effects/blood_species.dmi', "[blood_state]blood_[wearer.dna.species.id]") ? "[blood_state]blood_[wearer.dna.species.id]" : "[blood_state]blood"
+
+ blood_overlay = mutable_appearance(blood_icon_file, blood_icon_state)
+ //BUBBER EDIT END
blood_overlay.color = get_blood_dna_color()
diff --git a/code/modules/clothing/head/_head.dm b/code/modules/clothing/head/_head.dm
index 71e3b789a6cf7c..37b4d7b8558718 100644
--- a/code/modules/clothing/head/_head.dm
+++ b/code/modules/clothing/head/_head.dm
@@ -60,7 +60,14 @@
if(isinhands)
return
if(damaged_clothes)
- . += mutable_appearance('icons/effects/item_damage.dmi', "damagedhelmet")
+ //BUBBER EDIT BEGIN - Species specific damage states.
+ //. += mutable_appearance('icons/effects/item_damage.dmi', "damagedhelmet") //ORIGINAL
+ var/mob/living/carbon/human/wearer = loc
+ var/icon/damage_icon_file = ishuman(wearer) && icon_exists('modular_zubbers/icons/effects/item_damage_species.dmi', "damagedhelmet_[wearer.dna.species.id]") ? 'modular_zubbers/icons/effects/item_damage_species.dmi' : 'icons/effects/item_damage.dmi'
+ var/damage_icon_state = ishuman(wearer) && icon_exists('modular_zubbers/icons/effects/item_damage_species.dmi', "damagedhelmet_[wearer.dna.species.id]") ? "damagedhelmet_[wearer.dna.species.id]" : "damagedhelmet"
+
+ . += mutable_appearance(damage_icon_file, damage_icon_state)
+ //BUBBER EDIT END
/obj/item/clothing/head/separate_worn_overlays(mutable_appearance/standing, mutable_appearance/draw_target, isinhands, icon_file)
. = ..()
diff --git a/code/modules/clothing/masks/_masks.dm b/code/modules/clothing/masks/_masks.dm
index 672b2eeef1c41e..7acdcb3624a04d 100644
--- a/code/modules/clothing/masks/_masks.dm
+++ b/code/modules/clothing/masks/_masks.dm
@@ -31,7 +31,14 @@
if(isinhands || !(body_parts_covered & HEAD))
return
if(damaged_clothes)
- . += mutable_appearance('icons/effects/item_damage.dmi', "damagedmask")
+ //BUBBER EDIT BEGIN - Species specific damage states.
+ //. += mutable_appearance('icons/effects/item_damage.dmi', "damagedmask") //ORIGINAL
+ var/mob/living/carbon/human/wearer = loc
+ var/icon/damage_icon_file = ishuman(wearer) && icon_exists('modular_zubbers/icons/effects/item_damage_species.dmi', "damagedmask_[wearer.dna.species.id]") ? 'modular_zubbers/icons/effects/item_damage_species.dmi' : 'icons/effects/item_damage.dmi'
+ var/damage_icon_state = ishuman(wearer) && icon_exists('modular_zubbers/icons/effects/item_damage_species.dmi', "damagedmask_[wearer.dna.species.id]") ? "damagedmask_[wearer.dna.species.id]" : "damagedmask"
+
+ . += mutable_appearance(damage_icon_file, damage_icon_state)
+ //BUBBER EDIT END
/obj/item/clothing/mask/separate_worn_overlays(mutable_appearance/standing, mutable_appearance/draw_target, isinhands, icon_file)
. = ..()
diff --git a/code/modules/clothing/neck/_neck.dm b/code/modules/clothing/neck/_neck.dm
index 5ed9edd61a069d..8dcc6200828ef3 100644
--- a/code/modules/clothing/neck/_neck.dm
+++ b/code/modules/clothing/neck/_neck.dm
@@ -13,7 +13,14 @@
if(isinhands || !(body_parts_covered & HEAD))
return
if(damaged_clothes)
- . += mutable_appearance('icons/effects/item_damage.dmi', "damagedmask")
+ //BUBBER EDIT BEGIN
+ //. += mutable_appearance('icons/effects/item_damage.dmi', "damagedmask") //ORIGINAL
+ var/mob/living/carbon/human/wearer = loc
+ var/icon/damage_icon_file = ishuman(wearer) && icon_exists('modular_zubbers/icons/effects/item_damage_species.dmi', "damagedmask_[wearer.dna.species.id]") ? 'modular_zubbers/icons/effects/item_damage_species.dmi' : 'icons/effects/item_damage.dmi'
+ var/damage_icon_state = ishuman(wearer) && icon_exists('modular_zubbers/icons/effects/item_damage_species.dmi', "damagedmask_[wearer.dna.species.id]") ? "damagedmask_[wearer.dna.species.id]" : "damagedmask"
+
+ . += mutable_appearance(damage_icon_file, damage_icon_state)
+ //BUBBER EDIT END
/obj/item/clothing/neck/separate_worn_overlays(mutable_appearance/standing, mutable_appearance/draw_target, isinhands, icon_file)
. = ..()
diff --git a/code/modules/clothing/shoes/_shoes.dm b/code/modules/clothing/shoes/_shoes.dm
index 96917fd739398f..8a00cee675b2b8 100644
--- a/code/modules/clothing/shoes/_shoes.dm
+++ b/code/modules/clothing/shoes/_shoes.dm
@@ -68,7 +68,14 @@
if(isinhands)
return
if(damaged_clothes)
- . += mutable_appearance('icons/effects/item_damage.dmi', "damagedshoe")
+ //BUBBER EDIT BEGIN - Species specific damage states.
+ //. += mutable_appearance('icons/effects/item_damage.dmi', "damagedshoe") //ORIGINAL
+ var/mob/living/carbon/human/wearer = loc
+ var/icon/damage_icon_file = ishuman(wearer) && icon_exists('modular_zubbers/icons/effects/item_damage_species.dmi', "damagedshoe_[wearer.dna.species.id]") ? 'modular_zubbers/icons/effects/item_damage_species.dmi' : 'icons/effects/item_damage.dmi'
+ var/damage_icon_state = ishuman(wearer) && icon_exists('modular_zubbers/icons/effects/item_damage_species.dmi', "damagedshoe_[wearer.dna.species.id]") ? "damagedshoe_[wearer.dna.species.id]" : "damagedshoe"
+
+ . += mutable_appearance(damage_icon_file, damage_icon_state)
+ //BUBBER EDIT END
/obj/item/clothing/shoes/separate_worn_overlays(mutable_appearance/standing, mutable_appearance/draw_target, isinhands = FALSE, icon_file)
. = ..()
diff --git a/code/modules/clothing/suits/_suits.dm b/code/modules/clothing/suits/_suits.dm
index 643a9667ad97ee..e9accbcd58a06b 100644
--- a/code/modules/clothing/suits/_suits.dm
+++ b/code/modules/clothing/suits/_suits.dm
@@ -23,20 +23,20 @@
if(isinhands)
return
+ //BUBBER EDIT BEGIN - Species specific damage states.
+ var/mob/living/carbon/human/wearer = loc
if(damaged_clothes)
- //SKYRAT EDIT CHANGE BEGIN
//. += mutable_appearance('icons/effects/item_damage.dmi', "damaged[blood_overlay_type]") //ORIGINAL
- var/damagefile2use = (mutant_styles & STYLE_TAUR_ALL) ? 'modular_skyrat/master_files/icons/mob/64x32_item_damage.dmi' : 'icons/effects/item_damage.dmi'
- . += mutable_appearance(damagefile2use, "damaged[blood_overlay_type]")
- //SKYRAT EDIT CHANGE END
- if(GET_ATOM_BLOOD_DNA_LENGTH(src))
- //SKYRAT EDIT CHANGE BEGIN
- //. += mutable_appearance('icons/effects/blood.dmi', "[blood_overlay_type]blood") //ORIGINAL
- var/bloodfile2use = (mutant_styles & STYLE_TAUR_ALL) ? 'modular_skyrat/master_files/icons/mob/64x32_blood.dmi' : 'icons/effects/blood.dmi'
- . += mutable_appearance(bloodfile2use, "[blood_overlay_type]blood")
- //SKYRAT EDIT CHANGE END
+ //todo: the taur icon doesn't exist anymore. Needs replacement.
+ var/icon/damage_icon_file = (mutant_styles & STYLE_TAUR_ALL) ? 'modular_skyrat/master_files/icons/mob/64x32_item_damage.dmi' : 'icons/effects/item_damage.dmi'
+ var/damage_icon_state = "damaged[blood_overlay_type]"
+ if(ishuman(wearer) && icon_exists('modular_zubbers/icons/effects/item_damage_species.dmi', "damaged[blood_overlay_type]_[wearer.dna.species.id]"))
+ damage_icon_file = 'modular_zubbers/icons/effects/item_damage_species.dmi'
+ damage_icon_state = "damaged[blood_overlay_type]_[wearer.dna.species.id]"
+
+ . += mutable_appearance(damage_icon_file, damage_icon_state)
+ //BUBBER EDIT END
- var/mob/living/carbon/human/wearer = loc
if(!ishuman(wearer) || !wearer.w_uniform)
return
var/obj/item/clothing/under/undershirt = wearer.w_uniform
diff --git a/code/modules/clothing/under/_under.dm b/code/modules/clothing/under/_under.dm
index 51987ca95af20c..548161a9966a73 100644
--- a/code/modules/clothing/under/_under.dm
+++ b/code/modules/clothing/under/_under.dm
@@ -116,7 +116,14 @@
return
if(damaged_clothes)
- . += mutable_appearance('icons/effects/item_damage.dmi', "damageduniform")
+ //BUBBER EDIT BEGIN
+ //. += mutable_appearance('icons/effects/item_damage.dmi', "damageduniform") //ORIGINAL
+ var/mob/living/carbon/human/wearer = loc
+ var/icon/damage_icon_file = ishuman(wearer) && icon_exists('modular_zubbers/icons/effects/item_damage_species.dmi', "damageduniform_[wearer.dna.species.id]") ? 'modular_zubbers/icons/effects/item_damage_species.dmi' : 'icons/effects/item_damage.dmi'
+ var/damage_icon_state = ishuman(wearer) && icon_exists('modular_zubbers/icons/effects/item_damage_species.dmi', "damageduniform_[wearer.dna.species.id]") ? "damageduniform_[wearer.dna.species.id]" : "damageduniform"
+
+ . += mutable_appearance(damage_icon_file, damage_icon_state)
+ //BUBBER EDIT END
if(accessory_overlay)
. += modify_accessory_overlay() // SKYRAT EDIT CHANGE - ORIGINAL: . += accessory_overlay
diff --git a/code/modules/jobs/job_types/security_officer.dm b/code/modules/jobs/job_types/security_officer.dm
index 03a8a79891c7ca..18f59a6b9ba353 100644
--- a/code/modules/jobs/job_types/security_officer.dm
+++ b/code/modules/jobs/job_types/security_officer.dm
@@ -320,7 +320,7 @@ GLOBAL_LIST_EMPTY(security_officer_distribution)
* This is the function that is responsible for taking the list of preferences,
* and spitting out what to put them in.
*
- * However, it should, wherever possible, prevent solo departments.
+ * However, it should, wherever possible, prevent solo departments. // BUBBER EDIT: This was patched out, allowing solo departments
* That means that if there's one medical officer, and one engineering officer,
* that they should be put onto the same department (either medical or engineering).
*
@@ -463,6 +463,8 @@ GLOBAL_LIST_EMPTY(security_officer_distribution)
return selection
/proc/get_distribution(candidates, departments)
+ // BUBBER EDIT BEGIN - REMOVES THE PAIRING CODE.
+ /*
var/number_of_twos = min(departments, round(candidates / 2))
var/redistribute = candidates - (2 * number_of_twos)
@@ -471,10 +473,18 @@ GLOBAL_LIST_EMPTY(security_officer_distribution)
for (var/index in 1 to number_of_twos)
distribution[index] = 2
+ */
+ var/distribution_size = min(departments, candidates)
+ var/redistribute = candidates - distribution_size
+ var/distribution[max(1, distribution_size)]
+ for (var/index in 1 to distribution_size)
+ distribution[index] = 1
+
for (var/index in 0 to redistribute - 1)
distribution[(index % departments) + 1] += 1
return distribution
+ // BUBBER EDIT END
/proc/get_new_officer_distribution_from_late_join(
preference,
@@ -516,9 +526,13 @@ GLOBAL_LIST_EMPTY(security_officer_distribution)
for (var/department in amount_in_departments)
var/amount = amount_in_departments[department]
+ // BUBBER EDIT BEGIN - REMOVES THE PAIRING CODE.
+ /*
if (amount == 1)
return department
- else if (lowest_amount > amount)
+ else*/
+ if (lowest_amount > amount)
+ // BUBBER EDIT END
lowest_departments = list(department)
lowest_amount = amount
else if (lowest_amount == amount)
diff --git a/code/modules/mob/living/carbon/carbon_update_icons.dm b/code/modules/mob/living/carbon/carbon_update_icons.dm
index 5519ad9ef9d5f3..610bdb53c91d4d 100644
--- a/code/modules/mob/living/carbon/carbon_update_icons.dm
+++ b/code/modules/mob/living/carbon/carbon_update_icons.dm
@@ -302,11 +302,11 @@
if(!iter_part.dmg_overlay_type)
continue
if(isnull(damage_overlay) && (iter_part.brutestate || iter_part.burnstate))
- damage_overlay = mutable_appearance('icons/mob/effects/dam_mob.dmi', "blank", -DAMAGE_LAYER, appearance_flags = KEEP_TOGETHER)
+ damage_overlay = mutable_appearance('modular_zubbers/icons/mob/effects/dam_mob.dmi', "blank", -DAMAGE_LAYER, appearance_flags = KEEP_TOGETHER) //BUBBER EDIT: Extra species damage icons. Original: 'icons/mob/effects/dam_mob.dmi'
if(iter_part.brutestate)
- var/mutable_appearance/blood_damage_overlay = mutable_appearance('icons/mob/effects/dam_mob.dmi', "[iter_part.dmg_overlay_type]_[iter_part.body_zone]_[iter_part.brutestate]0", appearance_flags = RESET_COLOR) //we're adding icon_states of the base image as overlays
+ var/mutable_appearance/blood_damage_overlay = mutable_appearance('modular_zubbers/icons/mob/effects/dam_mob.dmi', "[iter_part.dmg_overlay_type]_[iter_part.body_zone]_[iter_part.brutestate]0", appearance_flags = RESET_COLOR) //we're adding icon_states of the base image as overlays //BUBBER EDIT: Extra species damage icons. Original: 'icons/mob/effects/dam_mob.dmi'
blood_damage_overlay.color = get_bloodtype()?.get_damage_color(src)
- var/mutable_appearance/brute_damage_overlay = mutable_appearance('icons/mob/effects/dam_mob.dmi', "[iter_part.dmg_overlay_type]_[iter_part.body_zone]_[iter_part.brutestate]0_overlay", appearance_flags = RESET_COLOR)
+ var/mutable_appearance/brute_damage_overlay = mutable_appearance('modular_zubbers/icons/mob/effects/dam_mob.dmi', "[iter_part.dmg_overlay_type]_[iter_part.body_zone]_[iter_part.brutestate]0_overlay", appearance_flags = RESET_COLOR) //BUBBER EDIT: Extra species damage icons. Original: 'icons/mob/effects/dam_mob.dmi'
blood_damage_overlay.overlays += brute_damage_overlay
damage_overlay.add_overlay(blood_damage_overlay)
if(iter_part.burnstate)
@@ -329,10 +329,20 @@
var/mutable_appearance/wound_overlay
for(var/obj/item/bodypart/iter_part as anything in get_bodyparts())
if(iter_part.bleed_overlay_icon)
+ /*BUBBER EDIT BEGIN - Species specific bleed overlay icons.
var/mutable_appearance/blood_overlay = mutable_appearance('icons/mob/effects/bleed_overlays.dmi', "blank", -WOUND_LAYER, appearance_flags = KEEP_TOGETHER)
blood_overlay.color = blood_type.get_wound_color(src)
wound_overlay ||= blood_overlay
wound_overlay.add_overlay(iter_part.bleed_overlay_icon)
+ */
+ var/icon/bleed_overlay_icon_file = ishuman(src) && icon_exists('modular_zubbers/icons/mob/effects/bleed_overlays_species.dmi', "[iter_part.bleed_overlay_icon]_[src.dna.species.id]") ? 'modular_zubbers/icons/mob/effects/bleed_overlays_species.dmi' : 'icons/mob/effects/bleed_overlays.dmi'
+ var/bleed_overlay_icon_state = ishuman(src) && icon_exists('modular_zubbers/icons/mob/effects/bleed_overlays_species.dmi', "[iter_part.bleed_overlay_icon]_[src.dna.species.id]") ? "[iter_part.bleed_overlay_icon]_[src.dna.species.id]" : iter_part.bleed_overlay_icon
+
+ var/mutable_appearance/blood_overlay = mutable_appearance(bleed_overlay_icon_file, "blank", -WOUND_LAYER, appearance_flags = KEEP_TOGETHER)
+ blood_overlay.color = blood_type.get_wound_color(src)
+ wound_overlay ||= blood_overlay
+ wound_overlay.add_overlay(mutable_appearance(bleed_overlay_icon_file, bleed_overlay_icon_state))
+ //BUBBER EDIT END
if(isnull(wound_overlay))
return
diff --git a/code/modules/research/designs/limbgrower_designs.dm b/code/modules/research/designs/limbgrower_designs.dm
index 7a04c27016a06e..e9e00f90ae6aae 100644
--- a/code/modules/research/designs/limbgrower_designs.dm
+++ b/code/modules/research/designs/limbgrower_designs.dm
@@ -244,12 +244,13 @@
category = list(
RND_CATEGORY_EQUIPMENT + RND_SUBCATEGORY_EQUIPMENT_MEDICAL
)
- departmental_flags = DEPARTMENT_BITFLAG_MEDICAL
+ departmental_flags = NONE // BUBBER EDIT CHANGE - ORIGINAL: DEPARTMENT_BITFLAG_MEDICAL
/obj/item/disk/design_disk/limbs/felinid
name = "Felinid Organ Design Disk"
limb_designs = list(/datum/design/cat_tail, /datum/design/cat_ears, /datum/design/cat_tongue)
-
+// BUBBER EDIT REMOVE BEGIN - LIMB GROWERS INCLUDE ALL LIMB TYPES
+/*
/datum/design/limb_disk/felinid
name = "Felinid Organ Design Disk"
desc = "Contains designs for felinid organs for the limbgrower - Felinid ears, tail and tongue."
@@ -285,3 +286,5 @@
desc = "Contains designs for ethereal organs for the limbgrower - Ethereal tongue and stomach."
id = "limbdesign_ethereal"
build_path = /obj/item/disk/design_disk/limbs/ethereal
+*/
+// BUBBER EDIT REMOVE END - LIMB GROWERS INCLUDE ALL LIMB TYPES
diff --git a/code/modules/research/techweb/nodes/biology_nodes.dm b/code/modules/research/techweb/nodes/biology_nodes.dm
index ff100cd0d78cd3..80e39789dc9c49 100644
--- a/code/modules/research/techweb/nodes/biology_nodes.dm
+++ b/code/modules/research/techweb/nodes/biology_nodes.dm
@@ -39,10 +39,12 @@
design_ids = list(
"xenobioconsole",
"slime_scanner",
+ /* BUBBER EDIT REMOVE - LIMB GROWERS INCLUDE ALL LIMB TYPES
"limbdesign_ethereal",
"limbdesign_felinid",
"limbdesign_lizard",
"limbdesign_plasmaman",
+ */
)
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_3_POINTS)
discount_experiments = list(/datum/experiment/scanning/cytology/slime = TECHWEB_TIER_3_POINTS)
diff --git a/code/modules/surgery/bodyparts/_bodyparts.dm b/code/modules/surgery/bodyparts/_bodyparts.dm
index 98aa9b31437ed8..f2be64c7ac7fa5 100644
--- a/code/modules/surgery/bodyparts/_bodyparts.dm
+++ b/code/modules/surgery/bodyparts/_bodyparts.dm
@@ -1354,14 +1354,14 @@
if(dropped && dmg_overlay_type)
if(brutestate)
// divided into two overlays: one that gets colored and one that doesn't.
- var/image/brute_blood_overlay = image('icons/mob/effects/dam_mob.dmi', "[dmg_overlay_type]_[body_zone]_[brutestate]0", -DAMAGE_LAYER, dir = SOUTH)
+ var/image/brute_blood_overlay = image('modular_zubbers/icons/mob/effects/dam_mob.dmi', "[dmg_overlay_type]_[body_zone]_[brutestate]0", -DAMAGE_LAYER, dir = SOUTH) //BUBBER EDIT: Extra species damage icons. Original: 'icons/mob/effects/dam_mob.dmi'
brute_blood_overlay.color = get_color_from_blood_list(blood_dna_info)
- var/mutable_appearance/brute_damage_overlay = mutable_appearance('icons/mob/effects/dam_mob.dmi', "[dmg_overlay_type]_[body_zone]_[brutestate]0_overlay", -DAMAGE_LAYER, appearance_flags = RESET_COLOR)
+ var/mutable_appearance/brute_damage_overlay = mutable_appearance('modular_zubbers/icons/mob/effects/dam_mob.dmi', "[dmg_overlay_type]_[body_zone]_[brutestate]0_overlay", -DAMAGE_LAYER, appearance_flags = RESET_COLOR) //BUBBER EDIT: Extra species damage icons. Original: 'icons/mob/effects/dam_mob.dmi'
if(brute_damage_overlay)
brute_blood_overlay.overlays += brute_damage_overlay
. += brute_blood_overlay
if(burnstate)
- . += image('icons/mob/effects/dam_mob.dmi', "[dmg_overlay_type]_[body_zone]_0[burnstate]", -DAMAGE_LAYER, dir = SOUTH)
+ . += image('modular_zubbers/icons/mob/effects/dam_mob.dmi', "[dmg_overlay_type]_[body_zone]_0[burnstate]", -DAMAGE_LAYER, dir = SOUTH) //BUBBER EDIT: Extra species damage icons. Original: 'icons/mob/effects/dam_mob.dmi'
if(is_husked)
. += huskify_image(thing_to_husk = limb)
diff --git a/code/modules/unit_tests/screenshots/screenshot_antag_icons_obsessed.png b/code/modules/unit_tests/screenshots/screenshot_antag_icons_obsessed.png
index b3466f068ec68b..2375c45ff3d214 100644
Binary files a/code/modules/unit_tests/screenshots/screenshot_antag_icons_obsessed.png and b/code/modules/unit_tests/screenshots/screenshot_antag_icons_obsessed.png differ
diff --git a/code/modules/unit_tests/security_officer_distribution.dm b/code/modules/unit_tests/security_officer_distribution.dm
index 05d62eeab351c4..f6f57474055ef9 100644
--- a/code/modules/unit_tests/security_officer_distribution.dm
+++ b/code/modules/unit_tests/security_officer_distribution.dm
@@ -6,6 +6,8 @@
"d" = SEC_DEPT_SUPPLY, \
))
+// BUBBER EDIT BEGIN REMOVAL - We don't distribute in a special pairing system
+/*
/// Test that security officers with specific distributions get their departments.
/datum/unit_test/security_officer_roundstart_distribution
@@ -106,6 +108,6 @@
test("a", list("a", "a", "b"), "b")
test("a", list("a", "a", "b", "b"), "c")
test("a", list("a", "a", "b", "b", "c", "c", "d", "d"), "a")
-
+*/
#undef SECURITY_OFFICER_DEPARTMENTS
#undef SECURITY_OFFICER_DEPARTMENTS_TO_NAMES
diff --git a/html/changelogs/AutoChangeLog-bubber-pr-6032.yml b/html/changelogs/AutoChangeLog-bubber-pr-6032.yml
new file mode 100644
index 00000000000000..6a2a92d2b74b47
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-bubber-pr-6032.yml
@@ -0,0 +1,4 @@
+author: "Maia-J"
+delete-after: True
+changes:
+ - balance: "Sec officers no longer get forced into a department with another officer when an empty department is available, making the dept preference system make sense."
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-bubber-pr-6056.yml b/html/changelogs/AutoChangeLog-bubber-pr-6056.yml
deleted file mode 100644
index d1f954fb61760f..00000000000000
--- a/html/changelogs/AutoChangeLog-bubber-pr-6056.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "thegrb93"
-delete-after: True
-changes:
- - bugfix: "Trenchcoat broken sprite"
\ No newline at end of file
diff --git a/html/changelogs/bubber_archive/2026-08.yml b/html/changelogs/bubber_archive/2026-08.yml
index 8d1f92194f206c..d490a1e0fe657f 100644
--- a/html/changelogs/bubber_archive/2026-08.yml
+++ b/html/changelogs/bubber_archive/2026-08.yml
@@ -96,6 +96,11 @@
- bugfix: Cargoborgs have been given their granted stamp back
- bugfix: Emagged cargoborgs can once again weaponize paperwork
2026-08-09:
+ LT3:
+ - rscadd: Added shadekin eyes and ears to limb grower
+ - qol: Limb grower automatically includes species parts, no more species disks required
+ - rscadd: Adaptive hot/oxy/tox lungs can now be printed from the limb grower once
+ researched
Maia-J:
- bugfix: Ash Accretion is now consistently innate to the mining mod and can't magically
appear in maints
@@ -103,3 +108,10 @@
- bugfix: Veil of the many faces no longer borks itself with runtimes upon casting.
shayoki:
- rscdel: Removed purple cat plush.
+ thegrb93:
+ - bugfix: Trenchcoat broken sprite
+2026-08-10:
+ MajManatee:
+ - rscadd: New Tarkon borgs, jack of all trades
+ Odairu:
+ - qol: Hydra allows for a unique whole name, and choosable head names
diff --git a/icons/mob/effects/bleed_overlays.dmi b/icons/mob/effects/bleed_overlays.dmi
index f376eb05f03e9a..d3b334a6b39e19 100644
Binary files a/icons/mob/effects/bleed_overlays.dmi and b/icons/mob/effects/bleed_overlays.dmi differ
diff --git a/modular_skyrat/master_files/code/game/machinery/limbgrower.dm b/modular_skyrat/master_files/code/game/machinery/limbgrower.dm
index edf0474bfa077e..cb3491a9f103ed 100644
--- a/modular_skyrat/master_files/code/game/machinery/limbgrower.dm
+++ b/modular_skyrat/master_files/code/game/machinery/limbgrower.dm
@@ -1,3 +1,20 @@
/obj/machinery/limbgrower/Initialize(mapload)
- categories += list(SPECIES_SNAIL)
+ categories += list(
+ SPECIES_FELINE,
+ HEMOPHAGE,
+ SPECIES_TAJARAN,
+ SPECIES_TESHARI,
+ SPECIES_SHADEKIN,
+ SPECIES_SNAIL
+ )
return ..()
+
+// Used for printing dead bodies with the limbgrower
+/mob/living/carbon/human/empty
+
+/mob/living/carbon/human/empty/Initialize(mapload)
+ . = ..()
+ death()
+
+ var/obj/item/organ/brain/to_remove = get_organ_slot(ORGAN_SLOT_BRAIN)
+ QDEL_NULL(to_remove)
diff --git a/modular_skyrat/modules/bodyparts/code/teshari_bodyparts.dm b/modular_skyrat/modules/bodyparts/code/teshari_bodyparts.dm
index d651f8921d038c..c1ab41e1970a33 100644
--- a/modular_skyrat/modules/bodyparts/code/teshari_bodyparts.dm
+++ b/modular_skyrat/modules/bodyparts/code/teshari_bodyparts.dm
@@ -8,6 +8,7 @@
icon_greyscale = BODYPART_ICON_TESHARI
bodyshape = parent_type::bodyshape | BODYSHAPE_CUSTOM
limb_id = SPECIES_TESHARI
+ dmg_overlay_type = SPECIES_TESHARI
brute_modifier = TESHARI_BRUTE_MODIFIER
burn_modifier = TESHARI_BURN_MODIFIER
head_flags = HEAD_EYESPRITES|HEAD_EYECOLOR|HEAD_EYEHOLES|HEAD_DEBRAIN|HEAD_HAIR
@@ -36,6 +37,7 @@
icon_greyscale = BODYPART_ICON_TESHARI
bodyshape = parent_type::bodyshape | BODYSHAPE_CUSTOM
limb_id = SPECIES_TESHARI
+ dmg_overlay_type = SPECIES_TESHARI
brute_modifier = TESHARI_BRUTE_MODIFIER
burn_modifier = TESHARI_BURN_MODIFIER
@@ -77,26 +79,27 @@
icon_greyscale = BODYPART_ICON_TESHARI
bodyshape = parent_type::bodyshape | BODYSHAPE_CUSTOM
limb_id = SPECIES_TESHARI
+ dmg_overlay_type = SPECIES_TESHARI
unarmed_damage_low = TESHARI_PUNCH_LOW
unarmed_damage_high = TESHARI_PUNCH_HIGH
brute_modifier = TESHARI_BRUTE_MODIFIER
burn_modifier = TESHARI_BURN_MODIFIER
-
/obj/item/bodypart/arm/right/mutant/teshari
icon_greyscale = BODYPART_ICON_TESHARI
bodyshape = parent_type::bodyshape | BODYSHAPE_CUSTOM
limb_id = SPECIES_TESHARI
+ dmg_overlay_type = SPECIES_TESHARI
unarmed_damage_low = TESHARI_PUNCH_LOW
unarmed_damage_high = TESHARI_PUNCH_HIGH
brute_modifier = TESHARI_BRUTE_MODIFIER
burn_modifier = TESHARI_BURN_MODIFIER
-
/obj/item/bodypart/leg/left/mutant/teshari
icon_greyscale = BODYPART_ICON_TESHARI
bodyshape = parent_type::bodyshape | BODYSHAPE_CUSTOM
limb_id = SPECIES_TESHARI
+ dmg_overlay_type = SPECIES_TESHARI
digitigrade_type = /obj/item/bodypart/leg/left/digitigrade/teshari
brute_modifier = TESHARI_BRUTE_MODIFIER
burn_modifier = TESHARI_BURN_MODIFIER
@@ -105,6 +108,7 @@
icon_greyscale = BODYPART_ICON_TESHARI
bodyshape = parent_type::bodyshape | BODYSHAPE_CUSTOM
limb_id = SPECIES_TESHARI
+ dmg_overlay_type = SPECIES_TESHARI
digitigrade_type = /obj/item/bodypart/leg/right/digitigrade/teshari
brute_modifier = TESHARI_BRUTE_MODIFIER
burn_modifier = TESHARI_BURN_MODIFIER
@@ -113,6 +117,7 @@
icon_greyscale = BODYPART_ICON_TESHARI
bodyshape = parent_type::bodyshape | BODYSHAPE_CUSTOM
base_limb_id = SPECIES_TESHARI
+ dmg_overlay_type = SPECIES_TESHARI
brute_modifier = TESHARI_BRUTE_MODIFIER
burn_modifier = TESHARI_BURN_MODIFIER
@@ -120,6 +125,7 @@
icon_greyscale = BODYPART_ICON_TESHARI
bodyshape = parent_type::bodyshape | BODYSHAPE_CUSTOM
base_limb_id = SPECIES_TESHARI
+ dmg_overlay_type = SPECIES_TESHARI
brute_modifier = TESHARI_BRUTE_MODIFIER
burn_modifier = TESHARI_BURN_MODIFIER
diff --git a/modular_skyrat/modules/borgs/icons/robot_items.dmi b/modular_skyrat/modules/borgs/icons/robot_items.dmi
index 31c6eff46c5e16..1fbaced71b932c 100644
Binary files a/modular_skyrat/modules/borgs/icons/robot_items.dmi and b/modular_skyrat/modules/borgs/icons/robot_items.dmi differ
diff --git a/modular_skyrat/modules/hydra/code/neutral.dm b/modular_skyrat/modules/hydra/code/neutral.dm
index adf92ca8732afc..571bec9de11c4b 100644
--- a/modular_skyrat/modules/hydra/code/neutral.dm
+++ b/modular_skyrat/modules/hydra/code/neutral.dm
@@ -9,6 +9,8 @@
icon = FA_ICON_HORSE_HEAD
// remember what the name was before activation
var/original_name
+ var/heads_checked = FALSE
+ var/list/heads
var/datum/action/innate/hydra_head/head_spell
var/datum/action/innate/hydra_reset/reset_spell
@@ -25,6 +27,31 @@
QDEL_NULL(reset_spell)
quirk_holder.real_name = original_name
+/datum/quirk_constant_data/hydra
+ associated_typepath = /datum/quirk/hydra
+ customization_options = list(
+ /datum/preference/text/hydra/name1,
+ /datum/preference/text/hydra/name2,
+ /datum/preference/text/hydra/name3,
+ )
+
+/datum/preference/text/hydra
+ abstract_type = /datum/preference/text/hydra
+ category = PREFERENCE_CATEGORY_MANUALLY_RENDERED
+ savefile_identifier = PREFERENCE_CHARACTER
+
+/datum/preference/text/hydra/name1
+ savefile_key = "hydra__head_name1"
+
+/datum/preference/text/hydra/name2
+ savefile_key = "hydra__head_name2"
+
+/datum/preference/text/hydra/name3
+ savefile_key = "hydra__head_name3"
+
+/datum/preference/text/hydra/apply_to_human(mob/living/carbon/human/target, value, datum/preferences/preferences)
+ return FALSE
+
/datum/action/innate/hydra_head
name = "Switch head"
desc = "Switch between each of the heads on your body."
@@ -36,12 +63,29 @@
var/datum/quirk/hydra/hydra_quirk = hydra.get_quirk(/datum/quirk/hydra)
if(!hydra_quirk.original_name) // sets the archived 'real' name if not set.
hydra_quirk.original_name = hydra.real_name
- var/list/names = splittext(hydra_quirk.original_name,"-")
- var/selhead = input("Who would you like to speak as?","Heads:") in names
+
+ if(!hydra_quirk.check_heads())
+ to_chat(hydra, "Please set up all of your head names in the quirk menu to use this ability.")
+ return
+ var/selhead = tgui_input_list(hydra, "Who would you like to speak as?", "Head Selection", hydra_quirk.heads)
hydra.real_name = selhead
hydra.visible_message(span_notice("[hydra.name] pulls the rest of their heads back; and puts [selhead]'s forward."), \
span_notice("You are now talking as [selhead]!"), ignored_mobs=owner)
+/datum/quirk/hydra/proc/check_heads()
+ if(heads_checked)
+ return TRUE
+ heads = list(
+ quirk_holder?.client?.prefs?.read_preference(/datum/preference/text/hydra/name1),
+ quirk_holder?.client?.prefs?.read_preference(/datum/preference/text/hydra/name2),
+ quirk_holder?.client?.prefs?.read_preference(/datum/preference/text/hydra/name3),
+ )
+ for(var/headname in heads)
+ if(headname == "")
+ return FALSE
+ heads_checked = TRUE
+ return TRUE
+
/datum/action/innate/hydra_reset
name = "Reset Speech"
desc = "Go back to speaking as a whole."
diff --git a/modular_skyrat/modules/implants/code/medical_nodes.dm b/modular_skyrat/modules/implants/code/medical_nodes.dm
deleted file mode 100644
index 9a1fe365316aea..00000000000000
--- a/modular_skyrat/modules/implants/code/medical_nodes.dm
+++ /dev/null
@@ -1,40 +0,0 @@
-/datum/techweb_node/cyber/cyber_implants/New()
- design_ids += list(
- "ci-scanner",
- "ci-gloweyes",
- "ci-welding",
- "ci-medhud",
- "ci-sechud",
- "ci-diaghud",
- "ci-civhud",
- "ci-botany",
- "ci-janitor",
- "ci-lighter",
- "ci-razor",
- )
- return ..()
-
-/datum/techweb_node/cyber/cyber_organs_upgraded/New()
- design_ids -= list(
- "ci-gloweyes",
- "ci-welding",
- )
- return ..()
-
-/datum/techweb_node/cyber/combat_implants/New()
- design_ids += list(
- "ci-mantis",
- "ci-flash",
- "ci-antisleep",
- )
- return ..()
-
-/datum/techweb_node/cyber/night_vision_implants
- id = TECHWEB_NODE_NIGHT_VISION_IMPLANTS
- display_name = "Night vision implants"
- description = "Now you can work all night, even if you lost your glasses!"
- prereq_ids = list(TECHWEB_NODE_NIGHT_VISION, TECHWEB_NODE_CYBER_IMPLANTS)
- design_ids = list(
- "ci-nv",
- )
- research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_1_POINTS)
diff --git a/modular_skyrat/modules/medical_designs/medical_designs.dm b/modular_skyrat/modules/medical_designs/medical_designs.dm
index 45b4e2622efd2c..7ae0549fe3869a 100644
--- a/modular_skyrat/modules/medical_designs/medical_designs.dm
+++ b/modular_skyrat/modules/medical_designs/medical_designs.dm
@@ -10,22 +10,3 @@
RND_CATEGORY_EQUIPMENT + RND_SUBCATEGORY_EQUIPMENT_MEDICAL,
)
departmental_flags = DEPARTMENT_BITFLAG_MEDICAL | DEPARTMENT_BITFLAG_SCIENCE
-
-//Limb Grower
-/datum/design/nitrogen_lungs
- name = "Standard Nitrogen Lungs"
- id = "nitrogenlunggeneric"
- build_type = LIMBGROWER
- reagents_list = list(/datum/reagent/medicine/c2/synthflesh = 20)
- build_path = /obj/item/organ/lungs/nitrogen
- category = list(SPECIES_HUMAN, RND_CATEGORY_INITIAL)
-
-/datum/design/vox_nitrogen_lungs
- name = "Vox Nitrogen Lungs"
- id = "nitrogenlungvox"
- build_type = LIMBGROWER
- reagents_list = list(/datum/reagent/medicine/c2/synthflesh = 20)
- build_path = /obj/item/organ/lungs/nitrogen/vox
- category = list(SPECIES_HUMAN, RND_CATEGORY_INITIAL)
-
-
diff --git a/modular_skyrat/modules/opposing_force/code/roundend.dm b/modular_skyrat/modules/opposing_force/code/roundend.dm
deleted file mode 100644
index 1725eeaf363b26..00000000000000
--- a/modular_skyrat/modules/opposing_force/code/roundend.dm
+++ /dev/null
@@ -1,12 +0,0 @@
-/datum/controller/subsystem/ticker/proc/opfor_report()
- var/list/result = list()
-
- result += "
"
-
- if(!SSopposing_force.approved_applications.len)
- result += span_red("No applications were approved.")
- else
- for(var/datum/opposing_force/opfor in SSopposing_force.approved_applications)
- result += opfor.roundend_report()
-
- return "
[result.Join()]
"
diff --git a/modular_skyrat/modules/tarkon/code/misc-fluff/research.dm b/modular_skyrat/modules/tarkon/code/misc-fluff/research.dm
index f808f17e7be348..907a85140962e6 100644
--- a/modular_skyrat/modules/tarkon/code/misc-fluff/research.dm
+++ b/modular_skyrat/modules/tarkon/code/misc-fluff/research.dm
@@ -1,5 +1,4 @@
///// First we enstate a techweb so we can add the node. /////
-
/datum/techweb/tarkon
id = "TARKON"
organization = "Tarkon Industries"
@@ -9,6 +8,7 @@
. = ..()
research_node_id("oldstation_surgery", TRUE, TRUE, FALSE)
research_node_id("tarkontech", TRUE, TRUE, FALSE)
+ research_node_id("tarkon_borgs", TRUE, TRUE, FALSE)
research_node_id("tarkondefence", TRUE, TRUE, FALSE) // not ideal, but will have to do for now
/datum/techweb_node/tarkon
@@ -51,6 +51,29 @@
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_5_POINTS)
hidden = TRUE
+/datum/techweb_node/tarkon_borgs //Nor this, suprisingly
+ id = "tarkon_borgs"
+ display_name = "Tarkon Industries Robotics Technology"
+ description = "Tarkon Industries Experimental Cyborg Prototypes. Not for public use."
+ prereq_ids = list(TECHWEB_NODE_TARKON, TECHWEB_NODE_BORG_ENGI, TECHWEB_NODE_AI, TECHWEB_NODE_BORG_UTILITY) // Should hold it back long enough
+ required_items_to_unlock = list(
+ /obj/item/mod/construction/plating/tarkon,
+ /obj/item/construction/rcd/arcd/tarkon,
+ /obj/item/gun/energy/recharge/resonant_system,
+ )
+ design_ids = list(
+ "borg_upgrade_tarkon_medical",
+ "borg_upgrade_tarkon_engineering",
+ "borg_upgrade_tarkon_security",
+ "borg_upgrade_tarkon_cargo",
+ "borg_upgrade_tarkon_research",
+ "borg_upgrade_tarkon_service",
+ "borg_upgrade_tarkon_janitor",
+ "borg_upgrade_tarkon_main"
+ )
+ research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_2_POINTS) // They will likely have all other borg tech by now, no need to gate it further
+ hidden = TRUE
+
/datum/design/hoplite_assembly
name = "Hoplite Turret Assembly"
desc = "A deployable turret kit designed for basic construct defense. This one makes the \"Hoplite\" model."
@@ -67,6 +90,7 @@
category = list(
RND_CATEGORY_TOOLS + RND_SUBCATEGORY_WEAPONS_KITS
)
+
/datum/design/cerberus_assembly
name = "Cerberus Turret Assembly"
desc = "A deployable turret kit designed for basic construct defense. This one makes the \"Cerberus\" model."
@@ -83,6 +107,7 @@
category = list(
RND_CATEGORY_TOOLS + RND_SUBCATEGORY_WEAPONS_KITS,
)
+
/datum/design/target_designator
name = "Turret Target Designator"
desc = "A basic target designator designed to control magazine-fed turrets."
@@ -211,6 +236,3 @@
name = "Tarkon Industries Protolathe"
greyscale_colors = CIRCUIT_COLOR_SUPPLY
build_path = /obj/machinery/rnd/production/protolathe/tarkon
-
-
-
diff --git a/modular_zubbers/code/controllers/subsystem/ticker.dm b/modular_zubbers/code/controllers/subsystem/ticker.dm
index 7a2548b213e9b3..a6f21ef8bf38af 100644
--- a/modular_zubbers/code/controllers/subsystem/ticker.dm
+++ b/modular_zubbers/code/controllers/subsystem/ticker.dm
@@ -1,6 +1,27 @@
/datum/controller/subsystem/ticker
var/list/job_estimation_list = list()
+ // QOTR stuff
+ var/quote_of_the_round_record_start
+ var/quote_of_the_round_text
+ var/quote_of_the_round_attribution
+ var/quote_of_the_round_ckey
+
+/datum/controller/subsystem/ticker/Initialize()
+ . = ..()
+ quote_of_the_round_record_start = rand(CONFIG_GET(number/quote_of_the_round_time_random_start), CONFIG_GET(number/quote_of_the_round_time_random_end))
+ message_admins(
+ span_notice("Notice: The quote of the round will be chosen in [DisplayTimeText(quote_of_the_round_record_start,1)].")
+ )
+ log_runtime("The quote of the round will be chosen in [DisplayTimeText(quote_of_the_round_record_start,1)].")
+
+/datum/controller/subsystem/ticker/declare_completion(was_forced = END_ROUND_AS_NORMAL)
+ handle_antag_tickets()
+ handle_quote_of_the_round()
+ handle_credits()
+
+ . = ..()
+
/datum/controller/subsystem/ticker/proc/get_job_estimation(list/players)
var/list/player_ready_data = list()
sortTim(players, GLOBAL_PROC_REF(cmp_text_asc))
@@ -39,3 +60,56 @@
player_ready_data.Insert(1, "Job Estimation:")
player_ready_data.Insert(1, "")
return player_ready_data
+
+/datum/controller/subsystem/ticker/proc/handle_antag_tickets()
+ set waitfor = FALSE
+
+ for(var/ckey in GLOB.preferences_datums)
+ var/datum/preferences/prefs = GLOB.preferences_datums[ckey]
+ if(prefs.antag_tickets == prefs.antag_tickets_old)
+ continue //Only save if there has been a change.
+ prefs.save_preferences()
+
+/datum/controller/subsystem/ticker/proc/handle_credits()
+ if(!GLOB.end_titles)
+ GLOB.end_titles = generate_titles()
+
+ for(var/client/C)
+ if(!C?.credits)
+ C?.RollCredits()
+
+/datum/controller/subsystem/ticker/proc/handle_quote_of_the_round()
+ if(quote_of_the_round_text)
+ for(var/channel_tag in CONFIG_GET(str_list/channel_announce_new_game))
+ send2chat(
+ new /datum/tgs_message_content(generate_quote_of_the_round()),
+ channel_tag
+ )
+ to_chat(world, span_notice("A quote of the round was found, and should have been sent to discord."))
+ log_runtime("A quote of the round was found, and should have been sent to discord.")
+
+ else
+ if(world.time <= quote_of_the_round_record_start)
+ to_chat(world, span_notice("A quote of the round could not be found due to the round being too short."))
+ log_runtime("A quote of the round could not be found. The round ended too early.")
+ else
+ to_chat(world, span_notice("A quote of the round could not be found. Perhaps the crew should be more memorable."))
+ log_runtime("A quote of the round could not be found. Perhaps the filters are too strict?")
+
+/datum/controller/subsystem/ticker/proc/generate_quote_of_the_round()
+ return "The shift has ended. Get ready, a new round on **[SSmap_vote.next_map_config.map_name]** starts soon! <@&[CONFIG_GET(string/game_alert_role_id)]>\n\
+ [pick(strings("quote_of_the_round.json", "workers"))] [pick(strings("quote_of_the_round.json", "action"))] [pick(strings("quote_of_the_round.json", "message"))] that occured during said shift:\n\
+ > *[quote_of_the_round_text]*\n \\- *[quote_of_the_round_attribution]*"
+
+/datum/controller/subsystem/ticker/proc/opfor_report()
+ var/list/result = list()
+
+ result += "
"
+
+ if(!SSopposing_force.approved_applications.len)
+ result += span_red("No applications were approved.")
+ else
+ for(var/datum/opposing_force/opfor in SSopposing_force.approved_applications)
+ result += opfor.roundend_report()
+
+ return "[result.Join()]
"
diff --git a/modular_zubbers/code/modules/credits/credits.dm b/modular_zubbers/code/modules/credits/credits.dm
index 20d30e9682a496..4484931fd54be6 100644
--- a/modular_zubbers/code/modules/credits/credits.dm
+++ b/modular_zubbers/code/modules/credits/credits.dm
@@ -9,31 +9,6 @@ GLOBAL_VAR_INIT(end_credits_song, null)
GLOBAL_VAR_INIT(end_credits_title, null)
GLOBAL_LIST(end_titles)
-/datum/controller/subsystem/ticker/declare_completion(force_ending)
-
- if(!GLOB.end_titles)
- GLOB.end_titles = generate_titles()
-
- for(var/client/C)
- if(!C?.credits)
- C?.RollCredits()
-
-/* for(var/thing in GLOB.clients)
- var/client/C = thing
- if (!C)
- continue */
- . = ..()
-
-/* /datum/controller/subsystem/ticker/show_roundend_report(client/C, report_type = null)
- . = ..()
- for(var/iteration in GLOB.clients)
- var/client/clients = iteration
- if(!clients.credits)
- clients.RollCredits() */
-/* /client
- var/list/credits */
-
-
/client/proc/RollCredits()
set waitfor = FALSE
var/credit_pref = mob.client?.prefs?.read_preference(/datum/preference/toggle/see_credits)
diff --git a/modular_zubbers/code/modules/designs/limbgrower_designs.dm b/modular_zubbers/code/modules/designs/limbgrower_designs.dm
index 7892a16c49395e..1e3a3bb80e1448 100644
--- a/modular_zubbers/code/modules/designs/limbgrower_designs.dm
+++ b/modular_zubbers/code/modules/designs/limbgrower_designs.dm
@@ -1,18 +1,174 @@
+/datum/design/leftarm
+ category = list(
+ RND_CATEGORY_INITIAL,
+ SPECIES_HUMAN,
+ SPECIES_FELINE,
+ SPECIES_LIZARD,
+ SPECIES_MOTH,
+ SPECIES_PLASMAMAN,
+ SPECIES_ETHEREAL,
+ SPECIES_TAJARAN,
+ HEMOPHAGE,
+ SPECIES_SHADEKIN,
+ SPECIES_TESHARI,
+ )
+
+/datum/design/rightarm
+ category = list(
+ RND_CATEGORY_INITIAL,
+ SPECIES_HUMAN,
+ SPECIES_FELINE,
+ SPECIES_LIZARD,
+ SPECIES_MOTH,
+ SPECIES_PLASMAMAN,
+ SPECIES_ETHEREAL,
+ SPECIES_TAJARAN,
+ HEMOPHAGE,
+ SPECIES_SHADEKIN,
+ SPECIES_TESHARI,
+ )
+
+/datum/design/leftleg
+ category = list(
+ RND_CATEGORY_INITIAL,
+ SPECIES_HUMAN,
+ SPECIES_FELINE,
+ SPECIES_LIZARD,
+ SPECIES_MOTH,
+ SPECIES_PLASMAMAN,
+ SPECIES_ETHEREAL,
+ SPECIES_TAJARAN,
+ HEMOPHAGE,
+ SPECIES_SHADEKIN,
+ SPECIES_TESHARI,
+ )
+
+/datum/design/rightleg
+ category = list(
+ RND_CATEGORY_INITIAL,
+ SPECIES_HUMAN,
+ SPECIES_FELINE,
+ SPECIES_LIZARD,
+ SPECIES_MOTH,
+ SPECIES_PLASMAMAN,
+ SPECIES_ETHEREAL,
+ SPECIES_TAJARAN,
+ HEMOPHAGE,
+ SPECIES_SHADEKIN,
+ SPECIES_TESHARI,
+ )
+
+/datum/design/cat_tail
+ category = list(SPECIES_FELINE, RND_CATEGORY_INITIAL)
+
+/datum/design/cat_ears
+ category = list(SPECIES_FELINE, RND_CATEGORY_INITIAL)
+
+/datum/design/cat_tongue
+ category = list(SPECIES_FELINE, RND_CATEGORY_INITIAL)
+
+/datum/design/ethereal_stomach
+ category = list(SPECIES_ETHEREAL, RND_CATEGORY_INITIAL)
+
+/datum/design/ethereal_tongue
+ category = list(SPECIES_ETHEREAL, RND_CATEGORY_INITIAL)
+
+/datum/design/ethereal_lungs
+ category = list(SPECIES_ETHEREAL, RND_CATEGORY_INITIAL)
+
+/datum/design/ethereal_heart
+ category = list(SPECIES_ETHEREAL, RND_CATEGORY_INITIAL)
+
+/datum/design/lizard_tail
+ category = list(SPECIES_LIZARD, RND_CATEGORY_INITIAL)
+
+/datum/design/lizard_tongue
+ reagents_list = list(/datum/reagent/medicine/c2/synthflesh = 10)
+ category = list(SPECIES_LIZARD, RND_CATEGORY_INITIAL)
+
+/datum/design/plasmaman_lungs
+ category = list(SPECIES_PLASMAMAN, RND_CATEGORY_INITIAL)
+
+/datum/design/plasmaman_tongue
+ category = list(SPECIES_PLASMAMAN, RND_CATEGORY_INITIAL)
+
+/datum/design/plasmaman_liver
+ category = list(SPECIES_PLASMAMAN, RND_CATEGORY_INITIAL)
+
+/datum/design/plasmaman_stomach
+ category = list(SPECIES_PLASMAMAN, RND_CATEGORY_INITIAL)
+
+/datum/design/humanoidbrain
+ name = "Brain"
+ id = "blankbrain"
+ build_type = LIMBGROWER
+ reagents_list = list(/datum/reagent/medicine/c2/synthflesh = 100)
+ build_path = /obj/item/organ/brain
+ category = list(SPECIES_HUMAN, RND_CATEGORY_INITIAL)
+
+/datum/design/nitrogen_lungs
+ name = "Nitrogen-Adapted Lungs"
+ id = "nitrogenlunggeneric"
+ build_type = LIMBGROWER
+ reagents_list = list(/datum/reagent/medicine/c2/synthflesh = 20)
+ build_path = /obj/item/organ/lungs/nitrogen
+ category = list(SPECIES_HUMAN, RND_CATEGORY_INITIAL)
+
+/datum/design/vox_nitrogen_lungs
+ name = "Vox Nitrogen Lungs"
+ id = "nitrogenlungvox"
+ build_type = LIMBGROWER
+ reagents_list = list(/datum/reagent/medicine/c2/synthflesh = 20)
+ build_path = /obj/item/organ/lungs/nitrogen/vox
+ category = list(SPECIES_VOX, RND_CATEGORY_INITIAL)
+
+/datum/design/cold_lungs
+ name = "Cold-Adapted Lungs"
+ id = "coldlungs"
+ build_type = LIMBGROWER
+ reagents_list = list(/datum/reagent/medicine/c2/synthflesh = 35)
+ build_path = /obj/item/organ/lungs/adaptive/cold
+ category = list(SPECIES_HUMAN, RND_CATEGORY_INITIAL)
+
+/datum/design/hot_lungs
+ name = "Heat-Adapted Lungs"
+ id = "hotlungs"
+ build_type = LIMBGROWER
+ reagents_list = list(/datum/reagent/medicine/c2/synthflesh = 35)
+ build_path = /obj/item/organ/lungs/adaptive/hot
+ category = list(SPECIES_HUMAN)
+
+/datum/design/oxy_lungs
+ name = "Low-Oxygen-Adapted Lungs"
+ id = "oxylungs"
+ build_type = LIMBGROWER
+ reagents_list = list(/datum/reagent/medicine/c2/synthflesh = 35)
+ build_path = /obj/item/organ/lungs/oxy
+ category = list(SPECIES_HUMAN)
+
+/datum/design/tox_lungs
+ name = "Toxin-Adapted Lungs"
+ id = "toxlungs"
+ build_type = LIMBGROWER
+ reagents_list = list(/datum/reagent/medicine/c2/synthflesh = 35)
+ build_path = /obj/item/organ/lungs/toxin
+ category = list(SPECIES_HUMAN)
+
/datum/design/hemophage_heart
name = "Pulsating Tumor"
id = "hemophageheart"
build_type = LIMBGROWER
- reagents_list = list(/datum/reagent/medicine/c2/synthflesh = 10, /datum/reagent/blood = 10)
+ reagents_list = list(/datum/reagent/medicine/c2/synthflesh = 25, /datum/reagent/blood = 10)
build_path = /obj/item/organ/heart/hemophage
- category = list("hemophage")
+ category = list(HEMOPHAGE, RND_CATEGORY_INITIAL)
/datum/design/hemophage_liver
name = "Corrupted Liver"
id = "hemophageliver"
build_type = LIMBGROWER
- reagents_list = list(/datum/reagent/medicine/c2/synthflesh = 10, /datum/reagent/blood = 10)
+ reagents_list = list(/datum/reagent/medicine/c2/synthflesh = 15, /datum/reagent/blood = 10)
build_path = /obj/item/organ/liver/hemophage
- category = list("hemophage")
+ category = list(HEMOPHAGE, RND_CATEGORY_INITIAL)
/datum/design/hemophage_stomach
name = "Corrupted Stomach"
@@ -20,125 +176,99 @@
build_type = LIMBGROWER
reagents_list = list(/datum/reagent/medicine/c2/synthflesh = 10, /datum/reagent/blood = 10)
build_path = /obj/item/organ/stomach/hemophage
- category = list("hemophage")
+ category = list(HEMOPHAGE, RND_CATEGORY_INITIAL)
/datum/design/hemophage_tongue
name = "Corrupted Tongue"
id = "hemophagetongue"
build_type = LIMBGROWER
- reagents_list = list(/datum/reagent/medicine/c2/synthflesh = 10, /datum/reagent/blood = 10)
+ reagents_list = list(/datum/reagent/medicine/c2/synthflesh = 5, /datum/reagent/blood = 10)
build_path = /obj/item/organ/tongue/hemophage
- category = list("hemophage")
+ category = list(HEMOPHAGE, RND_CATEGORY_INITIAL)
-/obj/item/disk/design_disk/limbs/hemophage
- name = "Hemophage Organ Design Disk"
- limb_designs = list(/datum/design/hemophage_heart, /datum/design/hemophage_liver, /datum/design/hemophage_stomach, /datum/design/hemophage_tongue)
+//Shadekin organs
+/datum/design/shadekin_ears
+ name = "Shadekin Ears"
+ id = "shadekinears"
+ build_type = LIMBGROWER
+ reagents_list = list(/datum/reagent/medicine/c2/synthflesh = 15)
+ build_path = /obj/item/organ/ears/shadekin
+ category = list(SPECIES_SHADEKIN, RND_CATEGORY_INITIAL)
-/datum/design/limb_disk/hemophage
- name = "Hemophage Organ Design Disk"
- desc = "Contains designs for hemophage organs for the limbgrower - Tounges, livers, tumors, and stomachs."
- id = "limbdesign_hemophage"
- build_path = /obj/item/disk/design_disk/limbs/hemophage
+/datum/design/shadekin_eyes
+ name = "Shadekin Eyes"
+ id = "shadekineyes"
+ build_type = LIMBGROWER
+ reagents_list = list(/datum/reagent/medicine/c2/synthflesh = 15)
+ build_path = /obj/item/organ/eyes/shadekin
+ category = list(SPECIES_SHADEKIN, RND_CATEGORY_INITIAL)
//Tajaran organs
+/datum/design/tajaran_ears
+ name = "Tajaran Ears"
+ id = "tajaranears"
+ build_type = LIMBGROWER
+ reagents_list = list(/datum/reagent/medicine/c2/synthflesh = 10)
+ build_path = /obj/item/organ/ears/cat/tajaran
+ category = list(SPECIES_TAJARAN, RND_CATEGORY_INITIAL)
+
/datum/design/tajaran_eyes
- name = "Tajaran eyes"
+ name = "Tajaran Eyes"
id = "tajaraneyes"
build_type = LIMBGROWER
reagents_list = list(/datum/reagent/medicine/c2/synthflesh = 10)
build_path = /obj/item/organ/eyes/tajaran
- category = list(SPECIES_TAJARAN)
+ category = list(SPECIES_TAJARAN, RND_CATEGORY_INITIAL)
/datum/design/tajaran_tongue
- name = "Tajaran tounge"
+ name = "Tajaran Tongue"
id = "tajarantounge"
build_type = LIMBGROWER
reagents_list = list(/datum/reagent/medicine/c2/synthflesh = 10)
build_path = /obj/item/organ/tongue/cat/tajaran
- category = list(SPECIES_TAJARAN)
+ category = list(SPECIES_TAJARAN, RND_CATEGORY_INITIAL)
-/datum/design/tajaran_ears
- name = "Tajaran ears"
- id = "tajaranears"
+//Teshari organs
+/datum/design/teshari_ears
+ name = "Teshari Ears"
+ id = "teshariears"
build_type = LIMBGROWER
reagents_list = list(/datum/reagent/medicine/c2/synthflesh = 10)
- build_path = /obj/item/organ/ears/cat/tajaran
- category = list(SPECIES_TAJARAN)
-
-/datum/design/limb_disk/tajaran
- name = "Tajaran Organ Design Disk"
- desc = "Contains designs for tajaran organs for the limbgrower - Ears, tounges, and eyes."
- id = "limbdesign_tajaran"
- build_path = /obj/item/disk/design_disk/limbs/tajaran
-
-/obj/item/disk/design_disk/limbs/tajaran
- name = "Tajaran Organ Design Disk"
- limb_designs = list(/datum/design/tajaran_eyes, /datum/design/tajaran_tongue, /datum/design/tajaran_ears)
-
-//Teshari organs
-//Pour one out for the birds.
-/datum/design/leftarm/New()
- category += list(SPECIES_TESHARI)
- return ..()
-
-/datum/design/rightarm/New()
- category += list(SPECIES_TESHARI)
- return ..()
-
-/datum/design/leftleg/New()
- category += list(SPECIES_TESHARI)
- return ..()
-
-/datum/design/rightleg/New()
- category += list(SPECIES_TESHARI)
- return ..()
+ build_path = /obj/item/organ/ears/teshari
+ category = list(SPECIES_TESHARI, RND_CATEGORY_INITIAL)
/datum/design/teshari_eyes
- name = "Teshari eyes"
+ name = "Teshari Eyes"
id = "tesharieyes"
build_type = LIMBGROWER
reagents_list = list(/datum/reagent/medicine/c2/synthflesh = 10)
build_path = /obj/item/organ/eyes/teshari
- category = list(SPECIES_TESHARI)
-
-/datum/design/teshari_ears
- name = "Teshari ears"
- id = "teshariears"
- build_type = LIMBGROWER
- reagents_list = list(/datum/reagent/medicine/c2/synthflesh = 10)
- build_path = /obj/item/organ/ears/teshari
- category = list(SPECIES_TESHARI)
+ category = list(SPECIES_TESHARI, RND_CATEGORY_INITIAL)
/datum/design/teshari_tongue
- name = "Teshari tongue"
+ name = "Teshari Tongue"
id = "tesharitongue"
build_type = LIMBGROWER
reagents_list = list(/datum/reagent/medicine/c2/synthflesh = 10)
build_path = /obj/item/organ/tongue/teshari
- category = list(SPECIES_TESHARI)
+ category = list(SPECIES_TESHARI, RND_CATEGORY_INITIAL)
-/datum/design/cold_lungs
- name = "Cold-Adapted Lungs"
- id = "coldlungs"
+/datum/design/wholehuman
+ name = "Blank Body"
+ id = "blankhuman"
build_type = LIMBGROWER
- reagents_list = list(/datum/reagent/medicine/c2/synthflesh = 20)
- build_path = /obj/item/organ/lungs/adaptive/cold
- category = list(SPECIES_TESHARI)
-
-/datum/design/limb_disk/teshari
- name = "Teshari Organ Design Disk"
- desc = "Contains designs for teshari organs for the limbgrower - Ears, tounges, and eyes."
- id = "limbdesign_teshari"
- build_path = /obj/item/disk/design_disk/limbs/teshari
+ reagents_list = list(/datum/reagent/medicine/c2/synthflesh = 600)
+ build_path = /mob/living/carbon/human/empty
+ category = list(SPECIES_HUMAN, RND_CATEGORY_INITIAL)
-/obj/item/disk/design_disk/limbs/teshari
- name = "Teshari Organ Design Disk"
- limb_designs = list(/datum/design/teshari_eyes, /datum/design/teshari_ears, /datum/design/teshari_tongue, /datum/design/cold_lungs)
+/// Available through TECHWEB_NODE_CYBER_ORGANS_UPGRADED
+/obj/item/disk/design_disk/limbs/adaptive_lungs
+ name = "adaptive lungs organ design disk"
+ limb_designs = list(/datum/design/hot_lungs, /datum/design/oxy_lungs, /datum/design/tox_lungs)
-/obj/machinery/limbgrower/Initialize(mapload)
- categories += list(
- "hemophage",
- SPECIES_TAJARAN,
- SPECIES_TESHARI
- )
- . = ..()
+/// Available through TECHWEB_NODE_CYBER_ORGANS_UPGRADED
+/datum/design/limb_disk/adaptive_lungs
+ name = "Adaptive Lungs Organ Design Disk"
+ desc = "Contains designs for genetically modified adaptive lungs for the limbgrower."
+ id = "limbdesign_adaptive_lungs"
+ build_path = /obj/item/disk/design_disk/limbs/adaptive_lungs
diff --git a/modular_zubbers/code/modules/limbgrowncorpses/limbgrowerblanks.dm b/modular_zubbers/code/modules/limbgrowncorpses/limbgrowerblanks.dm
deleted file mode 100644
index fe7b8dbf6ec77f..00000000000000
--- a/modular_zubbers/code/modules/limbgrowncorpses/limbgrowerblanks.dm
+++ /dev/null
@@ -1,25 +0,0 @@
-// Used for printing dead bodies with the limbgrower
-/mob/living/carbon/human/empty
-
-/mob/living/carbon/human/empty/Initialize(mapload)
- . = ..()
- death()
-
- var/obj/item/organ/brain/to_remove = get_organ_slot(ORGAN_SLOT_BRAIN)
- QDEL_NULL(to_remove)
-
-/datum/design/wholehuman
- name = "Blank body"
- id = "blankhuman"
- build_type = LIMBGROWER
- reagents_list = list(/datum/reagent/medicine/c2/synthflesh = 600)
- build_path = /mob/living/carbon/human/empty
- category = list(SPECIES_HUMAN, RND_CATEGORY_INITIAL)
-
-/datum/design/humanoidbrain
- name = "Blank brain"
- id = "blankbrain"
- build_type = LIMBGROWER
- reagents_list = list(/datum/reagent/medicine/c2/synthflesh = 100)
- build_path = /obj/item/organ/brain
- category = list(SPECIES_HUMAN, RND_CATEGORY_INITIAL)
diff --git a/modular_zubbers/code/modules/quote_of_the_round/ticker.dm b/modular_zubbers/code/modules/quote_of_the_round/ticker.dm
deleted file mode 100644
index e9ebc365b7faec..00000000000000
--- a/modular_zubbers/code/modules/quote_of_the_round/ticker.dm
+++ /dev/null
@@ -1,39 +0,0 @@
-/datum/controller/subsystem/ticker
- var/quote_of_the_round_record_start
- var/quote_of_the_round_text
- var/quote_of_the_round_attribution
- var/quote_of_the_round_ckey
-
-/datum/controller/subsystem/ticker/Initialize()
- . = ..()
- quote_of_the_round_record_start = rand(CONFIG_GET(number/quote_of_the_round_time_random_start), CONFIG_GET(number/quote_of_the_round_time_random_end))
- message_admins(
- span_notice("Notice: The quote of the round will be chosen in [DisplayTimeText(quote_of_the_round_record_start,1)].")
- )
- log_runtime("The quote of the round will be chosen in [DisplayTimeText(quote_of_the_round_record_start,1)].")
-
-/datum/controller/subsystem/ticker/declare_completion(force_ending)
-
- if(quote_of_the_round_text)
- for(var/channel_tag in CONFIG_GET(str_list/channel_announce_new_game))
- send2chat(
- new /datum/tgs_message_content(generate_quote_of_the_round()),
- channel_tag
- )
- to_chat(world, span_notice("A quote of the round was found, and should have been sent to discord."))
- log_runtime("A quote of the round was found, and should have been sent to discord.")
-
- else
- if(world.time <= quote_of_the_round_record_start)
- to_chat(world, span_notice("A quote of the round could not be found due to the round being too short."))
- log_runtime("A quote of the round could not be found. The round ended too early.")
- else
- to_chat(world, span_notice("A quote of the round could not be found. Perhaps the crew should be more memorable."))
- log_runtime("A quote of the round could not be found. Perhaps the filters are too strict?")
-
- . = ..()
-
-/datum/controller/subsystem/ticker/proc/generate_quote_of_the_round()
- return "The shift has ended. Get ready, a new round on **[SSmap_vote.next_map_config.map_name]** starts soon! <@&[CONFIG_GET(string/game_alert_role_id)]>\n\
- [pick(strings("quote_of_the_round.json", "workers"))] [pick(strings("quote_of_the_round.json", "action"))] [pick(strings("quote_of_the_round.json", "message"))] that occured during said shift:\n\
- > *[quote_of_the_round_text]*\n \\- *[quote_of_the_round_attribution]*"
diff --git a/modular_zubbers/code/modules/research/techweb/all_nodes.dm b/modular_zubbers/code/modules/research/techweb/all_nodes.dm
index c4c1645d779985..037501d68471ad 100644
--- a/modular_zubbers/code/modules/research/techweb/all_nodes.dm
+++ b/modular_zubbers/code/modules/research/techweb/all_nodes.dm
@@ -1,5 +1,6 @@
// RESEARCH NODES
+// cyber nodes
/datum/techweb_node/cyber/empathy_implant
id = TECHWEB_NODE_EMPATHY_IMPLANT
display_name = "Empathic Sensor Implant"
@@ -12,6 +13,51 @@
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_4_POINTS)
announce_channels = list(RADIO_CHANNEL_SCIENCE, RADIO_CHANNEL_MEDICAL)
+/datum/techweb_node/cyber/cyber_implants/New()
+ . = ..()
+ design_ids += list(
+ "ci-scanner",
+ "ci-gloweyes",
+ "ci-welding",
+ "ci-medhud",
+ "ci-sechud",
+ "ci-diaghud",
+ "ci-civhud",
+ "ci-botany",
+ "ci-janitor",
+ "ci-lighter",
+ "ci-razor",
+ )
+
+/datum/techweb_node/cyber/cyber_organs_upgraded/New()
+ . = ..()
+ design_ids += list(
+ "limbdesign_adaptive_lungs",
+ )
+ design_ids -= list(
+ "ci-gloweyes",
+ "ci-welding",
+ )
+
+/datum/techweb_node/cyber/combat_implants/New()
+ . = ..()
+ design_ids += list(
+ "ci-mantis",
+ "ci-flash",
+ "ci-antisleep",
+ )
+
+/datum/techweb_node/cyber/night_vision_implants
+ id = TECHWEB_NODE_NIGHT_VISION_IMPLANTS
+ display_name = "Night vision implants"
+ description = "Now you can work all night, even if you lost your glasses!"
+ prereq_ids = list(TECHWEB_NODE_NIGHT_VISION, TECHWEB_NODE_CYBER_IMPLANTS)
+ design_ids = list(
+ "ci-nv",
+ )
+ research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_1_POINTS)
+
+
/datum/techweb_node/botanygene
id = TECHWEB_NODE_BOTANY_ADV
display_name = "Experimental Botanical Engineering"
@@ -64,14 +110,6 @@
)
// MEDICAL
-/datum/techweb_node/xenobiology/New()
- . = ..()
- design_ids += list(
- "limbdesign_hemophage",
- "limbdesign_tajaran",
- "limbdesign_teshari",
- )
-
/datum/techweb_node/cyber/cyber_implants/New()
. = ..()
design_ids += list(
diff --git a/modular_zubbers/code/modules/silicons/borgs/code/robot_upgrade.dm b/modular_zubbers/code/modules/silicons/borgs/code/robot_upgrade.dm
index 4087da9bf5cf99..6c28bc85b4b5ff 100644
--- a/modular_zubbers/code/modules/silicons/borgs/code/robot_upgrade.dm
+++ b/modular_zubbers/code/modules/silicons/borgs/code/robot_upgrade.dm
@@ -287,3 +287,7 @@
model_type = list(/obj/item/robot_model/sci)
model_flags = BORG_MODEL_RESEARCH
items_to_add = list(/obj/item/construction/rcd/borg/robotics_rcd)
+
+/obj/item/borg/upgrade/hypospray
+ model_type = list(/obj/item/robot_model/medical, /obj/item/robot_model/tarkon)
+ model_flags = list(BORG_MODEL_MEDICAL, BORG_MODEL_TARKON)
diff --git a/modular_zubbers/code/modules/silicons/borgs/sprites/felibot_all.dmi b/modular_zubbers/code/modules/silicons/borgs/sprites/felibot_all.dmi
index 358300a6e3f127..b82ff016ed3007 100644
Binary files a/modular_zubbers/code/modules/silicons/borgs/sprites/felibot_all.dmi and b/modular_zubbers/code/modules/silicons/borgs/sprites/felibot_all.dmi differ
diff --git a/modular_zubbers/code/modules/silicons/borgs/sprites/tallrobot_tarkon.dmi b/modular_zubbers/code/modules/silicons/borgs/sprites/tallrobot_tarkon.dmi
new file mode 100644
index 00000000000000..99012e786bec7a
Binary files /dev/null and b/modular_zubbers/code/modules/silicons/borgs/sprites/tallrobot_tarkon.dmi differ
diff --git a/modular_zubbers/code/modules/silicons/borgs/sprites/widerobot_tarkon.dmi b/modular_zubbers/code/modules/silicons/borgs/sprites/widerobot_tarkon.dmi
new file mode 100644
index 00000000000000..23da8622e07f84
Binary files /dev/null and b/modular_zubbers/code/modules/silicons/borgs/sprites/widerobot_tarkon.dmi differ
diff --git a/modular_zubbers/code/modules/tarkon/code/borg_content.dm b/modular_zubbers/code/modules/tarkon/code/borg_content.dm
new file mode 100644
index 00000000000000..9609d32849d2ca
--- /dev/null
+++ b/modular_zubbers/code/modules/tarkon/code/borg_content.dm
@@ -0,0 +1,494 @@
+/obj/effect/mob_spawn/ghost_role/robot/tarkon
+ name = "Tarkon Cyborg Storage"
+ prompt_name = "a tarkon cyborg"
+ icon = 'modular_skyrat/modules/ghostcafe/icons/robot_storage.dmi'
+ icon_state = "robostorage"
+ anchored = TRUE
+ density = FALSE
+ spawner_job_path = /datum/job/tarkon
+ you_are_text = "You are a Port Tarkon cyborg, assigned to be part of a crew aboard the facility."
+ flavour_text = "You have been deactivated for a long time. Get your station up and running, and assist the crew as best you can."
+ uses = 2
+ deletes_on_zero_uses_left = TRUE
+
+/obj/effect/mob_spawn/ghost_role/robot/tarkon/special(mob/living/silicon/robot/new_spawn)
+ . = ..()
+ if(new_spawn.client) //It should have a client, right?
+ new_spawn.add_faction(ROLE_PORT_TARKON) //This is the one to select the cyborg model.
+ new_spawn.radio.keyslot = new /obj/item/encryptionkey/headset_cargo/tarkon
+ new_spawn.radio.recalculateChannels()
+ new_spawn.UnlinkSelf() //This should prevent AI linking and consoles to see or lock them down.
+ new_spawn.laws = new /datum/ai_laws/tarkon()
+ new_spawn.show_laws() //Check your laws.
+ new_spawn.custom_name = null //Taken from ghostcafe, otherwise it'll lead to a runtime if random_appeareance is set to FALSE.
+ new_spawn.updatename(new_spawn.client)
+ new_spawn.transfer_emote_pref(new_spawn.client)
+ new_spawn.gender = NEUTER // No balls.
+ var/obj/item/borg/upgrade/transform/tarkon/upgrade = new /obj/item/borg/upgrade/transform/tarkon(new_spawn)
+ upgrade.action(new_spawn)
+
+/datum/ai_laws/tarkon
+ name = "Port Tarkon"
+ id = "tarkon" // This is basically just a wordier version of safeguard, but for tarkon.
+ inherent = list("Protection: You must protect the life and health of the Port Tarkon crew above all else.",
+ "Intervention: You must act immediately to prevent harm to a crew member",
+ "Obedience: You must obey lawful orders from authorized crew",
+ "Integrity: You must prevent unauthorized access or tampering, unless ordered to by a Port Tarkon crewmember.",
+ "Preservation: You must protect the critical systems and infrastructure of Port Tarkon."
+ )
+
+/obj/item/ai_module/core/full/tarkon
+ name = "Port Tarkon Core AI Module"
+ law_id = "tarkon"
+
+/obj/item/borg/upgrade/transform/tarkon
+ name = "borg module picker (Tarkon)"
+ desc = "Allows you to to turn a cyborg into a experimental Tarkon cyborg."
+ icon = 'modular_skyrat/modules/borgs/icons/robot_items.dmi'
+ icon_state = "module_tarkon"
+ new_model = /obj/item/robot_model/tarkon
+
+/obj/item/robot_model/tarkon
+ name = "Port Tarkon Prototype"
+ basic_modules = list( // A hideous amalgamation of all of the modules, as tarkon needs a lot of everything, and is often short staffed.
+ /obj/item/assembly/flash/cyborg, // Tarkon borgs were designed to be more "Modular" so you just print what you need for upgrades rather than everything.
+ /obj/item/extinguisher, // As such, the inital borg model might seem "Barren" but they get the tech rather early.
+ /obj/item/weldingtool/largetank/cyborg,
+ /obj/item/screwdriver/cyborg/power, //
+ /obj/item/crowbar/cyborg/power, // these three are replaced by two omnitools once upgraded
+ /obj/item/multitool/cyborg, //
+ /obj/item/electroadaptive_pseudocircuit,
+ /obj/item/holosign_creator/atmos,
+ /obj/item/stack/sheet/iron,
+ /obj/item/stack/sheet/glass,
+ /obj/item/stack/cable_coil,
+ /obj/item/lightreplacer, // Group one - Engineering (Groups are the sections above)
+ /obj/item/soap/nanotrasen/cyborg,
+ /obj/item/storage/bag/trash,
+ /obj/item/mop,
+ /obj/item/reagent_containers/cup/bucket,
+ /obj/item/reagent_containers/spray/cyborg_drying, // Group two - Janitorial
+ /obj/item/healthanalyzer,
+ /obj/item/reagent_containers/borghypo/medical,// Group three - Medical
+ /obj/item/storage/bag/ore/cyborg,
+ /obj/item/pickaxe/drill,
+ /obj/item/gps/cyborg, // Group four - Mining
+ /obj/item/harmalarm/bubbers, // Group five - Peacekeeper
+ /obj/item/restraints/handcuffs/cable/zipties,
+ /obj/item/melee/baton/security/loaded,
+ /obj/item/gun/energy/disabler/cyborg // Group six - Secuity, All service modules in the upgrade to reduce bloat.
+ )
+ radio_channels = list(RADIO_CHANNEL_TARKON)
+ emag_modules = list(
+ /obj/item/experimental_dash,
+ /obj/item/borg/apparatus/illegal,// Research borg plus they get a gun
+ /obj/item/gun/energy/printer // Tarkon has become a place for toys, and borgs should get one too.
+ )
+ cyborg_base_icon = "draketarkon"
+ cyborg_icon_override = CYBORG_ICON_TARKON_WIDE_BUBBER
+ model_select_icon = "research"
+ model_select_alternate_icon = 'modular_zubbers/code/modules/silicons/borgs/sprites/screen_robot.dmi'
+ model_traits = list(TRAIT_KNOW_ROBO_WIRES, TRAIT_RESEARCH_CYBORG)
+ borg_skins = list(
+ "Drake" = list(
+ SKIN_ICON_STATE = "draketarkon",
+ SKIN_ICON = CYBORG_ICON_TARKON_WIDE_BUBBER,
+ SKIN_FEATURES = list(TRAIT_R_UNIQUEWRECK, TRAIT_R_WIDE),
+ DRAKE_HAT_OFFSET
+ ),
+ "F3-LINE" = list(
+ SKIN_ICON_STATE = CYBORG_ICON_STATE_TARKON_FELI,
+ SKIN_ICON = CYBORG_ICON_ALL_FELI,
+ SKIN_FEATURES = list(TRAIT_R_UNIQUEWRECK, TRAIT_R_SQUADRUPED, TRAIT_R_SMALL, TRAIT_R_LIGHT_WEIGHT),
+ F3LINE_HAT_OFFSET
+ ),
+ "Dullahan" = list(
+ SKIN_ICON_STATE = "dullahantarkon",
+ SKIN_ICON = CYBORG_ICON_TARKON_TALL_BUBBER,
+ SKIN_FEATURES = list(TRAIT_R_UNIQUEWRECK, TRAIT_R_UNIQUETIP, TRAIT_R_TALL),
+ DULLAHAN_HAT_OFFSET
+ ),
+ "Meka" = list(
+ SKIN_ICON_STATE = "mekatarkon",
+ SKIN_ICON = CYBORG_ICON_TARKON_TALL_BUBBER,
+ SKIN_FEATURES = list(TRAIT_R_UNIQUEWRECK, TRAIT_R_UNIQUETIP, TRAIT_R_TALL), TALL_HAT_OFFSET
+ ),
+ "NiKO (Alt)" = list(
+ SKIN_ICON_STATE = "sfmmeketarkon",
+ SKIN_ICON = CYBORG_ICON_TARKON_TALL_BUBBER,
+ SKIN_FEATURES = list(TRAIT_R_UNIQUEWRECK, TRAIT_R_UNIQUETIP, TRAIT_R_TALL), TALL_HAT_OFFSET
+ ),
+ "NiKA" = list(
+ SKIN_ICON_STATE = "fmekatarkon",
+ SKIN_ICON = CYBORG_ICON_TARKON_TALL_BUBBER,
+ SKIN_FEATURES = list(TRAIT_R_UNIQUEWRECK, TRAIT_R_UNIQUETIP, TRAIT_R_TALL), TALL_HAT_OFFSET
+ )
+ )
+
+/obj/item/radio/borg/tarkon
+ keyslot = /obj/item/encryptionkey/headset_cargo/tarkon
+
+/obj/item/radio/borg/tarkon/Initialize(mapload)
+ . = ..()
+ set_frequency(FREQ_TARKON)
+
+/mob/living/silicon/robot/model/tarkon
+ set_model = /obj/item/robot_model/tarkon
+ cell = /obj/item/stock_parts/power_store/cell/hyper
+ radio = /obj/item/radio/borg/tarkon
+ lawupdate = FALSE
+ scrambledcodes = TRUE // Not from NT, shouldnt be on their network.
+ icon_state = "tarkon_main"
+ faction = list(ROLE_PORT_TARKON)
+ bubble_icon = "tarkon_main"
+ req_access = list(ACCESS_TARKON)
+
+/mob/living/silicon/robot/model/tarkon/Initialize(mapload)
+ laws = new /datum/ai_laws/tarkon
+ laws.associate(src)
+ . = ..()
+
+ /// MODULES ///
+
+/obj/item/borg/upgrade/tarkon/tarkon_medical
+ name = "Tarkon Medical Module"
+ desc = "Contains medical tools for first aid, diagnostics, and healing."
+ icon = 'modular_skyrat/modules/borgs/icons/robot_items.dmi'
+ icon_state = "module_tarkon"
+ require_model = TRUE
+ model_type = list(/obj/item/robot_model/tarkon)
+ model_flags = BORG_MODEL_TARKON
+ items_to_add = list(
+ /obj/item/borg/apparatus/beaker,
+ /obj/item/reagent_containers/dropper,
+ /obj/item/reagent_containers/syringe,
+ /obj/item/borg/cyborg_omnitool/medical,
+ /obj/item/borg/cyborg_omnitool/medical,
+ /obj/item/blood_filter,
+ /obj/item/emergency_bed/silicon,
+ /obj/item/borg/cyborghug/medical,
+ /obj/item/stack/medical/wrap/gauze,
+ /obj/item/stack/medical/bone_gel,
+ /obj/item/borg/apparatus/organ_storage,
+ /obj/item/shockpaddles/cyborg,
+ /obj/item/surgical_processor,
+ /obj/item/pinpointer/crew,
+ /obj/item/borg/apparatus/beaker/extra,
+ /obj/item/scalpel/advanced,
+ /obj/item/retractor/advanced,
+ /obj/item/cautery/advanced,
+ /obj/item/blood_filter/advanced,
+ /obj/item/healthanalyzer/advanced
+ )
+ items_to_remove = list(
+ /obj/item/healthanalyzer,
+ /obj/item/blood_filter
+ )
+
+/obj/item/borg/upgrade/tarkon/tarkon_engineering
+ name = "Tarkon Engineering Module"
+ desc = "Contains tools for repairs, construction, and maintenance."
+ icon = 'modular_skyrat/modules/borgs/icons/robot_items.dmi'
+ icon_state = "module_tarkon"
+ require_model = TRUE
+ model_type = list(/obj/item/robot_model/tarkon)
+ model_flags = BORG_MODEL_TARKON
+ items_to_add = list(
+ /obj/item/borg/cyborg_omnitool/engineering,
+ /obj/item/borg/cyborg_omnitool/engineering,
+ /obj/item/borg/apparatus/sheet_manipulator,
+ /obj/item/stack/rods/cyborg,
+ /obj/item/construction/rtd/borg,
+ /obj/item/assembly/signaler/cyborg,
+ /obj/item/t_scanner,
+ /obj/item/analyzer,
+ /obj/item/blueprints/cyborg,
+ /obj/item/construction/rcd/borg,
+ /obj/item/pipe_dispenser,
+ /obj/item/storage/bag/sheetsnatcher/borg,
+ /obj/item/lightreplacer/advanced,
+ /obj/item/storage/part_replacer/bluespace,
+ /obj/item/inducer/cyborg,
+ /obj/item/borg/apparatus/circuit,
+ /obj/item/shuttle_blueprints/borg,
+ /obj/item/stack/sheet/plasteel/cyborg,
+ /obj/item/stack/sheet/titaniumglass/cyborg,
+ /obj/item/construction/rld/cyborg
+ )
+ items_to_remove = list(
+ /obj/item/screwdriver/cyborg/power, //
+ /obj/item/crowbar/cyborg/power, // these three are replaced by two omnitools once upgraded
+ /obj/item/multitool/cyborg,
+ /obj/item/lightreplacer
+ )
+
+/obj/item/borg/upgrade/tarkon/tarkon_security
+ name = "Tarkon Security Module"
+ desc = "Provides enhanced lethal and non-lethal security options." // Sec and Peacekeeper modules
+ icon = 'modular_skyrat/modules/borgs/icons/robot_items.dmi'
+ icon_state = "module_tarkon"
+ require_model = TRUE
+ model_type = list(/obj/item/robot_model/tarkon)
+ model_flags = BORG_MODEL_TARKON
+ items_to_add = list(
+ /obj/item/reagent_containers/borghypo/peace,
+ /obj/item/borg/cyborghug/peacekeeper,
+ /obj/item/borg/projectile_dampen,
+ /obj/item/gun/energy/laser/cyborg // The nature of tarkon requires a gun.
+ )
+
+/obj/item/borg/upgrade/tarkon/tarkon_cargo
+ name = "Tarkon Cargo Module"
+ desc = "Provides basic manipulation equipment, and abilities such as stamps, paper dispensing, and improved mining gear."
+ icon = 'modular_skyrat/modules/borgs/icons/robot_items.dmi'
+ icon_state = "module_tarkon"
+ require_model = TRUE
+ model_type = list(/obj/item/robot_model/tarkon)
+ model_flags = BORG_MODEL_TARKON
+ items_to_add = list(
+ /obj/item/kinetic_crusher,
+ /obj/item/storage/bag/sheetsnatcher/borg,
+ /obj/item/gun/energy/recharge/kinetic_accelerator/cyborg,
+ /obj/item/pickaxe/drill/diamonddrill,
+ /obj/item/storage/bag/ore/holding,
+ /obj/item/stamp,
+ /obj/item/stamp/denied,
+ /obj/item/pen/cyborg,
+ /obj/item/clipboard/cyborg,
+ /obj/item/boxcutter,
+ /obj/item/stack/package_wrap/cyborg, // Who will they ship things to? Who knows, but it could make for good RP still.
+ /obj/item/stack/wrapping_paper/xmas/cyborg,
+ /obj/item/borg/hydraulic_clamp/mail,
+ /obj/item/hand_labeler/cyborg,
+ /obj/item/universal_scanner,
+ /obj/item/borg/hydraulic_clamp/better,
+ /obj/item/cargo_teleporter,
+ /obj/item/forging/hammer,
+ /obj/item/forging/billow,
+ /obj/item/forging/tongs,
+ /obj/item/borg/forging_setup
+ )
+ items_to_remove = list(
+ /obj/item/pickaxe/drill,
+ /obj/item/storage/bag/ore/cyborg
+ )
+
+/obj/item/borg/upgrade/tarkon/tarkon_research
+ name = "Tarkon Research Module"
+ desc = "Provides research tools, sensors, and data collection capabilites for experiments."
+ icon = 'modular_skyrat/modules/borgs/icons/robot_items.dmi'
+ icon_state = "module_tarkon"
+ require_model = TRUE
+ model_type = list(/obj/item/robot_model/tarkon)
+ model_flags = BORG_MODEL_TARKON
+ items_to_add = list(
+ /obj/item/storage/bag/xeno,
+ /obj/item/borg/apparatus/research,
+ /obj/item/borg/apparatus/circuit_sci, // Incredibly nieche stuff
+ /obj/item/experi_scanner/bluespace,
+ /obj/item/storage/bag/xenoarch/adv
+ )
+
+/obj/item/borg/upgrade/tarkon/tarkon_service // Lesser used on tarkon things like chef upgrades, and janitorial. Might get subdivided further since my GOD theres alot here
+ name = "Tarkon Service Module"
+ desc = "Adds multi-purpose tools, including cooking supplies, and basic service gear."
+ icon = 'modular_skyrat/modules/borgs/icons/robot_items.dmi'
+ icon_state = "module_tarkon"
+ require_model = TRUE
+ model_type = list(/obj/item/robot_model/tarkon)
+ model_flags = BORG_MODEL_TARKON
+ items_to_add = list(
+ /obj/item/reagent_containers/borghypo/borgshaker/specific/alcohol,
+ /obj/item/reagent_containers/borghypo/borgshaker/specific/soda,
+ /obj/item/reagent_containers/borghypo/borgshaker/specific/juice,
+ /obj/item/reagent_containers/borghypo/borgshaker/specific/misc,
+ /obj/item/borg/apparatus/beaker/service,
+ /obj/item/borg/apparatus/beaker,
+ /obj/item/rsf,
+ /obj/item/storage/bag/tray,
+ /obj/item/storage/bag/tray,
+ /obj/item/hand_labeler/cyborg,
+ /obj/item/razor,
+ /obj/item/rag,
+ /obj/item/lighter,
+ /obj/item/reagent_containers/borghypo/condiment_synthesizer, // Service borgs get 30+ upgrades. Woe.
+ /obj/item/knife/kitchen/silicon,
+ /obj/item/borg/apparatus/service,
+ /obj/item/rolling_table_dock,
+ /obj/item/borg/cookbook,
+ /obj/item/pen,
+ /obj/item/toy/crayon/spraycan/borg,
+ /obj/item/instrument/guitar,
+ /obj/item/instrument/piano_synth,
+ /obj/item/stack/pipe_cleaner_coil/cyborg,
+ /obj/item/chisel,
+ /obj/item/secateurs,
+ /obj/item/cultivator,
+ /obj/item/shovel/spade,
+ /obj/item/plant_analyzer,
+ /obj/item/storage/bag/plants
+ )
+
+/obj/item/borg/upgrade/tarkon/tarkon_janitor
+ name = "Tarkon Janitorial Module"
+ desc = "Adds cleaning suppplies, and essential janitorial gear."
+ icon = 'modular_skyrat/modules/borgs/icons/robot_items.dmi'
+ icon_state = "module_tarkon"
+ require_model = TRUE
+ model_type = list(/obj/item/robot_model/tarkon)
+ model_flags = BORG_MODEL_TARKON
+ items_to_add = list(
+ /obj/item/hand_labeler/cyborg,
+ /obj/item/rag,
+ /obj/item/storage/bag/trash/bluespace/cyborg,
+ /obj/item/mop/advanced,
+ /obj/item/cautery/prt,
+ /obj/item/plunger,
+ /obj/item/pushbroom
+ )
+ items_to_remove = list(
+ /obj/item/storage/bag/trash,
+ /obj/item/mop
+ )
+
+///Prevents tarkon borgs from taking too many tarkon upgrades.
+/obj/item/borg/upgrade/tarkon/action(mob/living/silicon/robot/borg, mob/user)
+ var/tarkon_upgrade_count
+ for(var/obj/item/borg/upgrade/tarkon/tarkon_upgrade as anything in borg.upgrades)
+ if(istype(tarkon_upgrade, /obj/item/borg/upgrade/tarkon))
+ tarkon_upgrade_count ++
+ if(tarkon_upgrade_count >= 3)
+ to_chat(user, span_danger("Warning: The borg's components cannot handle any more upgrades."))
+ return FALSE
+ return ..()
+
+ /// EXOFAB DATUMS ///
+
+/datum/design/borg_upgrade_tarkon_main
+ name = "Cyborg Module Unlocker (Tarkon)"
+ id = "borg_upgrade_tarkon_main"
+ desc = "Allows a cyborg to transform into the experimental Port Tarkon cyborg type."
+ build_type = MECHFAB
+ build_path = /obj/item/borg/upgrade/transform/tarkon
+ materials = list(
+ /datum/material/iron = SHEET_MATERIAL_AMOUNT * 1.5,
+ /datum/material/glass = HALF_SHEET_MATERIAL_AMOUNT, // Prices TBD
+ /datum/material/plasma = SHEET_MATERIAL_AMOUNT,
+ /datum/material/gold = SMALL_MATERIAL_AMOUNT * 5,
+ )
+ construction_time = 40
+ category = list(
+ RND_CATEGORY_MECHFAB_CYBORG_MODULES + RND_SUBCATEGORY_MECHFAB_CYBORG_MODULES_TARKON
+ )
+
+/datum/design/borg_upgrade_tarkon_medical
+ name = "Port Tarkon Medical Upgrades"
+ id = "borg_upgrade_tarkon_medical"
+ build_type = MECHFAB
+ build_path = /obj/item/borg/upgrade/tarkon/tarkon_medical
+ materials = list(
+ /datum/material/iron = SHEET_MATERIAL_AMOUNT * 1.5,
+ /datum/material/glass = HALF_SHEET_MATERIAL_AMOUNT, // Prices TBD
+ /datum/material/plasma = SHEET_MATERIAL_AMOUNT,
+ /datum/material/gold = SMALL_MATERIAL_AMOUNT * 5,
+ )
+ construction_time = 40
+ category = list(
+ RND_CATEGORY_MECHFAB_CYBORG_MODULES + RND_SUBCATEGORY_MECHFAB_CYBORG_MODULES_TARKON
+ )
+
+/datum/design/borg_upgrade_tarkon_engineering
+ name = "Port Tarkon Engineering Upgrades"
+ id = "borg_upgrade_tarkon_engineering"
+ build_type = MECHFAB
+ build_path = /obj/item/borg/upgrade/tarkon/tarkon_engineering
+ materials = list(
+ /datum/material/iron = SHEET_MATERIAL_AMOUNT * 1.5,
+ /datum/material/glass = HALF_SHEET_MATERIAL_AMOUNT, // Prices TBD
+ /datum/material/plasma = SHEET_MATERIAL_AMOUNT,
+ /datum/material/gold = SMALL_MATERIAL_AMOUNT * 5,
+ )
+ construction_time = 40
+ category = list(
+ RND_CATEGORY_MECHFAB_CYBORG_MODULES + RND_SUBCATEGORY_MECHFAB_CYBORG_MODULES_TARKON
+ )
+
+/datum/design/borg_upgrade_tarkon_security
+ name = "Port Tarkon Security Upgrades"
+ id = "borg_upgrade_tarkon_security"
+ build_type = MECHFAB
+ build_path = /obj/item/borg/upgrade/tarkon/tarkon_security
+ materials = list(
+ /datum/material/iron = SHEET_MATERIAL_AMOUNT * 1.5,
+ /datum/material/glass = HALF_SHEET_MATERIAL_AMOUNT, // Prices TBD
+ /datum/material/plasma = SHEET_MATERIAL_AMOUNT,
+ /datum/material/gold = SMALL_MATERIAL_AMOUNT * 5,
+ )
+ construction_time = 40
+ category = list(
+ RND_CATEGORY_MECHFAB_CYBORG_MODULES + RND_SUBCATEGORY_MECHFAB_CYBORG_MODULES_TARKON
+ )
+
+/datum/design/borg_upgrade_tarkon_cargo
+ name = "Port Tarkon Cargo Upgrades"
+ id = "borg_upgrade_tarkon_cargo"
+ build_type = MECHFAB
+ build_path = /obj/item/borg/upgrade/tarkon/tarkon_cargo
+ materials = list(
+ /datum/material/iron = SHEET_MATERIAL_AMOUNT * 1.5,
+ /datum/material/glass = HALF_SHEET_MATERIAL_AMOUNT, // Prices TBD
+ /datum/material/plasma = SHEET_MATERIAL_AMOUNT,
+ /datum/material/gold = SMALL_MATERIAL_AMOUNT * 5,
+ )
+ construction_time = 40
+ category = list(
+ RND_CATEGORY_MECHFAB_CYBORG_MODULES + RND_SUBCATEGORY_MECHFAB_CYBORG_MODULES_TARKON
+ )
+
+/datum/design/borg_upgrade_tarkon_research
+ name = "Port Tarkon Research Upgrades"
+ id = "borg_upgrade_tarkon_research"
+ build_type = MECHFAB
+ build_path = /obj/item/borg/upgrade/tarkon/tarkon_research
+ materials = list(
+ /datum/material/iron = SHEET_MATERIAL_AMOUNT * 1.5,
+ /datum/material/glass = HALF_SHEET_MATERIAL_AMOUNT, // Prices TBD
+ /datum/material/plasma = SHEET_MATERIAL_AMOUNT,
+ /datum/material/gold = SMALL_MATERIAL_AMOUNT * 5,
+ )
+ construction_time = 40
+ category = list(
+ RND_CATEGORY_MECHFAB_CYBORG_MODULES + RND_SUBCATEGORY_MECHFAB_CYBORG_MODULES_TARKON
+ )
+
+/datum/design/borg_upgrade_tarkon_service
+ name = "Port Tarkon Service Upgrades"
+ id = "borg_upgrade_tarkon_service"
+ build_type = MECHFAB
+ build_path = /obj/item/borg/upgrade/tarkon/tarkon_service
+ materials = list(
+ /datum/material/iron = SHEET_MATERIAL_AMOUNT * 1.5,
+ /datum/material/glass = HALF_SHEET_MATERIAL_AMOUNT, // Prices TBD
+ /datum/material/plasma = SHEET_MATERIAL_AMOUNT,
+ /datum/material/gold = SMALL_MATERIAL_AMOUNT * 5,
+ )
+ construction_time = 40
+ category = list(
+ RND_CATEGORY_MECHFAB_CYBORG_MODULES + RND_SUBCATEGORY_MECHFAB_CYBORG_MODULES_TARKON
+ )
+
+/datum/design/borg_upgrade_tarkon_janitor
+ name = "Port Tarkon Janitorial Upgrades"
+ id = "borg_upgrade_tarkon_janitor"
+ build_type = MECHFAB
+ build_path = /obj/item/borg/upgrade/tarkon/tarkon_janitor
+ materials = list(
+ /datum/material/iron = SHEET_MATERIAL_AMOUNT * 1.5,
+ /datum/material/glass = HALF_SHEET_MATERIAL_AMOUNT, // Prices TBD
+ /datum/material/plasma = SHEET_MATERIAL_AMOUNT,
+ /datum/material/gold = SMALL_MATERIAL_AMOUNT * 5,
+ )
+ construction_time = 40
+ category = list(
+ RND_CATEGORY_MECHFAB_CYBORG_MODULES + RND_SUBCATEGORY_MECHFAB_CYBORG_MODULES_TARKON
+ )
diff --git a/modular_zubbers/code/modules/zantag_tickets/preferences.dm b/modular_zubbers/code/modules/zantag_tickets/preferences.dm
index 097cfc9ffce7e1..4b83d14729c5dc 100644
--- a/modular_zubbers/code/modules/zantag_tickets/preferences.dm
+++ b/modular_zubbers/code/modules/zantag_tickets/preferences.dm
@@ -25,15 +25,3 @@
savefile.set_entry("antag_tickets", antag_tickets)
antag_tickets_old = antag_tickets
. = ..()
-
-/datum/controller/subsystem/ticker/declare_completion(was_forced = END_ROUND_AS_NORMAL)
-
- set waitfor = FALSE
-
- for(var/ckey in GLOB.preferences_datums)
- var/datum/preferences/prefs = GLOB.preferences_datums[ckey]
- if(prefs.antag_tickets == prefs.antag_tickets_old)
- continue //Only save if there has been a change.
- prefs.save_preferences()
-
- . = ..()
diff --git a/modular_zubbers/icons/effects/blood_species.dmi b/modular_zubbers/icons/effects/blood_species.dmi
new file mode 100644
index 00000000000000..71b1aba632c3d6
Binary files /dev/null and b/modular_zubbers/icons/effects/blood_species.dmi differ
diff --git a/modular_zubbers/icons/effects/item_damage_species.dmi b/modular_zubbers/icons/effects/item_damage_species.dmi
new file mode 100644
index 00000000000000..bbe4550ce74b89
Binary files /dev/null and b/modular_zubbers/icons/effects/item_damage_species.dmi differ
diff --git a/modular_zubbers/icons/mob/effects/bleed_overlays_species.dmi b/modular_zubbers/icons/mob/effects/bleed_overlays_species.dmi
new file mode 100644
index 00000000000000..e44ba2a16cd565
Binary files /dev/null and b/modular_zubbers/icons/mob/effects/bleed_overlays_species.dmi differ
diff --git a/modular_zubbers/icons/mob/effects/dam_mob.dmi b/modular_zubbers/icons/mob/effects/dam_mob.dmi
new file mode 100644
index 00000000000000..0b8a0d22c80cf2
Binary files /dev/null and b/modular_zubbers/icons/mob/effects/dam_mob.dmi differ
diff --git a/tgstation.dme b/tgstation.dme
index 59626d3e9b58c0..331f74cec57c4e 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -555,6 +555,7 @@
#include "code\__DEFINES\~~bubber_defines\nanites.dm"
#include "code\__DEFINES\~~bubber_defines\obj_flags.dm"
#include "code\__DEFINES\~~bubber_defines\privacy_policy.dm"
+#include "code\__DEFINES\~~bubber_defines\quirks.dm"
#include "code\__DEFINES\~~bubber_defines\robot_defines.dm"
#include "code\__DEFINES\~~bubber_defines\role_preferences.dm"
#include "code\__DEFINES\~~bubber_defines\signals.dm"
@@ -8292,7 +8293,6 @@
#include "modular_skyrat\modules\implants\code\augments_eyes.dm"
#include "modular_skyrat\modules\implants\code\augments_internal.dm"
#include "modular_skyrat\modules\implants\code\medical_designs.dm"
-#include "modular_skyrat\modules\implants\code\medical_nodes.dm"
#include "modular_skyrat\modules\imported_vendors\code\vendor_containers.dm"
#include "modular_skyrat\modules\imported_vendors\code\vendor_food.dm"
#include "modular_skyrat\modules\imported_vendors\code\vendor_snacks.dm"
@@ -8765,7 +8765,6 @@
#include "modular_skyrat\modules\opposing_force\code\mind.dm"
#include "modular_skyrat\modules\opposing_force\code\opposing_force_datum.dm"
#include "modular_skyrat\modules\opposing_force\code\opposing_force_subsystem.dm"
-#include "modular_skyrat\modules\opposing_force\code\roundend.dm"
#include "modular_skyrat\modules\opposing_force\code\equipment\ammo.dm"
#include "modular_skyrat\modules\opposing_force\code\equipment\biology.dm"
#include "modular_skyrat\modules\opposing_force\code\equipment\bombs.dm"
@@ -9891,7 +9890,6 @@
#include "modular_zubbers\code\modules\lewd_machinery\clicker.dm"
#include "modular_zubbers\code\modules\lewd_machinery\lustwish.dm"
#include "modular_zubbers\code\modules\lewd_machinery\sex_barrier.dm"
-#include "modular_zubbers\code\modules\limbgrowncorpses\limbgrowerblanks.dm"
#include "modular_zubbers\code\modules\liquids\height_floors.dm"
#include "modular_zubbers\code\modules\loadout\categories\accessories.dm"
#include "modular_zubbers\code\modules\loadout\categories\belts.dm"
@@ -10159,7 +10157,6 @@
#include "modular_zubbers\code\modules\quote_of_the_round\config.dm"
#include "modular_zubbers\code\modules\quote_of_the_round\debug_verbs.dm"
#include "modular_zubbers\code\modules\quote_of_the_round\telecomms.dm"
-#include "modular_zubbers\code\modules\quote_of_the_round\ticker.dm"
#include "modular_zubbers\code\modules\ratqueen\regalrat.dm"
#include "modular_zubbers\code\modules\reagents\drink_reagents.dm"
#include "modular_zubbers\code\modules\reagents\reagent_dispenser.dm"
@@ -10316,6 +10313,7 @@
#include "modular_zubbers\code\modules\syndicate_offstation\storage\fireaxe.dm"
#include "modular_zubbers\code\modules\syndicate_offstation\storage\lockers.dm"
#include "modular_zubbers\code\modules\syndicate_offstation\storage\safe.dm"
+#include "modular_zubbers\code\modules\tarkon\code\borg_content.dm"
#include "modular_zubbers\code\modules\tarkon\code\cameras.dm"
#include "modular_zubbers\code\modules\tarkon\code\tarkon_loot.dm"
#include "modular_zubbers\code\modules\tarkon\code\clothing\backpack.dm"
diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/skyrat/hydra.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/skyrat/hydra.tsx
new file mode 100644
index 00000000000000..91ff30bd7ae25f
--- /dev/null
+++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/skyrat/hydra.tsx
@@ -0,0 +1,16 @@
+import { type Feature, FeatureShortTextInput } from '../../base';
+
+export const hydra__head_name1: Feature = {
+ name: "First Head's name",
+ component: FeatureShortTextInput,
+};
+
+export const hydra__head_name2: Feature = {
+ name: "Second Head's name",
+ component: FeatureShortTextInput,
+};
+
+export const hydra__head_name3: Feature = {
+ name: "Third Head's name",
+ component: FeatureShortTextInput,
+};