"
-
+
if(!length(GLOB.loadout_categories[gear_category]))
dat += "No subcategories detected. Something is horribly wrong!"
else
@@ -1808,14 +1517,14 @@ GLOBAL_LIST_EMPTY(preferences_datums)
pref_species = new newtype()
//let's ensure that no weird shit happens on species swapping.
custom_species = null
- if(!pref_species.mutant_bodyparts["body_markings"])
+ if(!parent.can_have_part("body_markings"))
features["body_markings"] = "None"
- if(!pref_species.mutant_bodyparts["mam_body_markings"])
+ if(!parent.can_have_part("mam_body_markings"))
features["mam_body_markings"] = "None"
- if(pref_species.mutant_bodyparts["mam_body_markings"])
+ if(parent.can_have_part("mam_body_markings"))
if(features["mam_body_markings"] == "None")
features["mam_body_markings"] = "Plain"
- if(pref_species.mutant_bodyparts["tail_lizard"])
+ if(parent.can_have_part("tail_lizard"))
features["tail_lizard"] = "Smooth"
if(pref_species.id == "felinid")
features["mam_tail"] = "Cat"
@@ -1927,7 +1636,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
if("mam_tail")
var/list/snowflake_tails_list = list()
for(var/path in GLOB.mam_tails_list)
- var/datum/sprite_accessory/mam_tails/instance = GLOB.mam_tails_list[path]
+ var/datum/sprite_accessory/tails/mam_tails/instance = GLOB.mam_tails_list[path]
if(istype(instance, /datum/sprite_accessory))
var/datum/sprite_accessory/S = instance
if(!show_mismatched_markings && S.recommended_species && !S.recommended_species.Find(pref_species.id))
@@ -1943,7 +1652,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
features["tail_human"] = "None"
features["tail_lizard"] = "None"
- if("meats")
+ if("meat_type")
var/new_meat
new_meat = input(user, "Choose your character's meat type:", "Character Preference") as null|anything in GLOB.meat_types
if(new_meat)
@@ -1952,7 +1661,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
if("snout")
var/list/snowflake_snouts_list = list()
for(var/path in GLOB.snouts_list)
- var/datum/sprite_accessory/mam_snouts/instance = GLOB.snouts_list[path]
+ var/datum/sprite_accessory/snouts/mam_snouts/instance = GLOB.snouts_list[path]
if(istype(instance, /datum/sprite_accessory))
var/datum/sprite_accessory/S = instance
if(!show_mismatched_markings && S.recommended_species && !S.recommended_species.Find(pref_species.id))
@@ -1969,7 +1678,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
if("mam_snouts")
var/list/snowflake_mam_snouts_list = list()
for(var/path in GLOB.mam_snouts_list)
- var/datum/sprite_accessory/mam_snouts/instance = GLOB.mam_snouts_list[path]
+ var/datum/sprite_accessory/snouts/mam_snouts/instance = GLOB.mam_snouts_list[path]
if(istype(instance, /datum/sprite_accessory))
var/datum/sprite_accessory/S = instance
if(!show_mismatched_markings && S.recommended_species && !S.recommended_species.Find(pref_species.id))
@@ -2048,7 +1757,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
if(new_deco_wings)
features["deco_wings"] = new_deco_wings
- if("insect_fluffs")
+ if("insect_fluff")
var/new_insect_fluff
new_insect_fluff = input(user, "Choose your character's wings:", "Character Preference") as null|anything in GLOB.insect_fluffs_list
if(new_insect_fluff)
@@ -2118,7 +1827,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
if("mam_ears")
var/list/snowflake_ears_list = list()
for(var/path in GLOB.mam_ears_list)
- var/datum/sprite_accessory/mam_ears/instance = GLOB.mam_ears_list[path]
+ var/datum/sprite_accessory/ears/mam_ears/instance = GLOB.mam_ears_list[path]
if(istype(instance, /datum/sprite_accessory))
var/datum/sprite_accessory/S = instance
if(!show_mismatched_markings && S.recommended_species && !S.recommended_species.Find(pref_species.id))
@@ -2196,7 +1905,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
if("cock_shape")
var/new_shape
var/list/hockeys = list()
- if(pref_species.mutant_bodyparts["taur"])
+ if(parent.can_have_part("taur"))
var/datum/sprite_accessory/taur/T = GLOB.taur_list[features["taur"]]
for(var/A in GLOB.cock_shapes_list)
var/datum/sprite_accessory/penis/P = GLOB.cock_shapes_list[A]
@@ -2805,10 +2514,10 @@ GLOBAL_LIST_EMPTY(preferences_datums)
character.dna.nameless = character.nameless
character.dna.custom_species = character.custom_species
- if(pref_species.mutant_bodyparts["meat_type"])
+ if((parent && parent.can_have_part("meat_type")) || pref_species.mutant_bodyparts["meat_type"])
character.type_of_meat = GLOB.meat_types[features["meat_type"]]
- if(character.dna.species.mutant_bodyparts["legs"] && (character.dna.features["legs"] == "Digitigrade" || character.dna.features["legs"] == "Avian"))
+ if(((parent && parent.can_have_part("legs")) || pref_species.mutant_bodyparts["legs"]) && (character.dna.features["legs"] == "Digitigrade" || character.dna.features["legs"] == "Avian"))
pref_species.species_traits |= DIGITIGRADE
else
pref_species.species_traits -= DIGITIGRADE
diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm
index dffab645a4..a8183e4940 100644
--- a/code/modules/client/preferences_savefile.dm
+++ b/code/modules/client/preferences_savefile.dm
@@ -5,7 +5,7 @@
// You do not need to raise this if you are adding new values that have sane defaults.
// Only raise this value when changing the meaning/format/name/layout of an existing value
// where you would want the updater procs below to run
-#define SAVEFILE_VERSION_MAX 33
+#define SAVEFILE_VERSION_MAX 35
/*
SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Carn
@@ -200,6 +200,10 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
features["silicon_flavor_text"] = html_encode(features["silicon_flavor_text"])
features["ooc_notes"] = html_encode(features["ooc_notes"])
+ if(current_version < 35)
+ if(S["species"] == "lizard")
+ features["mam_snouts"] = features["snout"]
+
/datum/preferences/proc/load_path(ckey,filename="preferences.sav")
if(!ckey)
return
diff --git a/code/modules/clothing/suits/miscellaneous.dm b/code/modules/clothing/suits/miscellaneous.dm
index 607a8ecb55..6364a9a1c1 100644
--- a/code/modules/clothing/suits/miscellaneous.dm
+++ b/code/modules/clothing/suits/miscellaneous.dm
@@ -543,6 +543,7 @@
cold_protection = HEAD
min_cold_protection_temperature = FIRE_SUIT_MIN_TEMP_PROTECT
flags_inv = HIDEHAIR|HIDEEARS
+ rad_flags = RAD_NO_CONTAMINATE
/obj/item/clothing/suit/hooded/wintercoat/centcom
name = "centcom winter coat"
@@ -1062,4 +1063,4 @@
name = "Samurai outfit"
desc = "An outfit used by traditional japanese warriors."
icon_state = "samurai"
- item_state = "samurai"
\ No newline at end of file
+ item_state = "samurai"
diff --git a/code/modules/events/pirates.dm b/code/modules/events/pirates.dm
index af44b54ed0..9ab5e8d517 100644
--- a/code/modules/events/pirates.dm
+++ b/code/modules/events/pirates.dm
@@ -25,7 +25,7 @@
ship_name = pick(strings(PIRATE_NAMES_FILE, "ship_names"))
/datum/round_event/pirates/announce(fake)
- priority_announce("A report has been downloaded and printed out at all communications consoles.", "Incoming Classified Message", "commandreport") // CITADEL EDIT metabreak
+ priority_announce("A business proposition has been downloaded and printed out at all communication consoles.", "Incoming Business Proposition", "commandreport")
if(fake)
return
threat_message = new
@@ -49,6 +49,7 @@
else
priority_announce("Trying to cheat us? You'll regret this!",sender_override = ship_name)
if(!shuttle_spawned)
+ priority_announce("You won't listen to reason? Then we'll take what's yours or die trying!",sender_override = ship_name)
spawn_shuttle()
/datum/round_event/pirates/start()
@@ -83,8 +84,7 @@
announce_to_ghosts(M)
else
announce_to_ghosts(spawner)
-
- priority_announce("A report has been downloaded and printed out at all communications consoles.", "Incoming Classified Message", "commandreport") //CITADEL EDIT also metabreak here too
+ priority_announce("Unidentified ship detected near the station.")
//Shuttle equipment
diff --git a/code/modules/events/wizard/shuffle.dm b/code/modules/events/wizard/shuffle.dm
index 3b5ea6b20a..18b8c8e21c 100644
--- a/code/modules/events/wizard/shuffle.dm
+++ b/code/modules/events/wizard/shuffle.dm
@@ -94,7 +94,7 @@
shuffle_inplace(mobs)
- var/obj/effect/proc_holder/spell/targeted/mind_transfer/swapper = new /obj/effect/proc_holder/spell/targeted/mind_transfer
+ var/obj/effect/proc_holder/spell/pointed/mind_transfer/swapper = new /obj/effect/proc_holder/spell/pointed/mind_transfer
while(mobs.len > 1)
var/mob/living/carbon/human/H = pick(mobs)
mobs -= H
diff --git a/code/modules/hydroponics/gene_modder.dm b/code/modules/hydroponics/gene_modder.dm
index 4e545c13ee..a0c273613f 100644
--- a/code/modules/hydroponics/gene_modder.dm
+++ b/code/modules/hydroponics/gene_modder.dm
@@ -3,9 +3,9 @@
desc = "An advanced device designed to manipulate plant genetic makeup."
icon = 'icons/obj/hydroponics/equipment.dmi'
icon_state = "dnamod"
- density = TRUE
circuit = /obj/item/circuitboard/machine/plantgenes
- pass_flags = PASSTABLE
+ pass_flags = PASSTABLE | LETPASSTHROW
+ flags_1 = DEFAULT_RICOCHET_1
var/obj/item/seeds/seed
var/obj/item/disk/plantgene/disk
diff --git a/code/modules/hydroponics/grown/cannabis.dm b/code/modules/hydroponics/grown/cannabis.dm
index 621e79fb77..6525ac42d4 100644
--- a/code/modules/hydroponics/grown/cannabis.dm
+++ b/code/modules/hydroponics/grown/cannabis.dm
@@ -14,9 +14,7 @@
icon_dead = "cannabis-dead" // Same for the dead icon
genes = list(/datum/plant_gene/trait/repeated_harvest)
mutatelist = list(/obj/item/seeds/cannabis/rainbow,
- /obj/item/seeds/cannabis/death,
- /obj/item/seeds/cannabis/white,
- /obj/item/seeds/cannabis/ultimate)
+ /obj/item/seeds/cannabis/death)
reagents_add = list(/datum/reagent/drug/space_drugs = 0.15, /datum/reagent/toxin/lipolicide = 0.35) // gives u the munchies
@@ -27,7 +25,7 @@
species = "megacannabis"
plantname = "Rainbow Weed"
product = /obj/item/reagent_containers/food/snacks/grown/cannabis/rainbow
- mutatelist = list()
+ mutatelist = list(/obj/item/seeds/cannabis/ultimate)
reagents_add = list(/datum/reagent/toxin/mindbreaker = 0.15, /datum/reagent/toxin/lipolicide = 0.35)
rarity = 40
@@ -38,7 +36,7 @@
species = "blackcannabis"
plantname = "Deathweed"
product = /obj/item/reagent_containers/food/snacks/grown/cannabis/death
- mutatelist = list()
+ mutatelist = list(/obj/item/seeds/cannabis/white)
reagents_add = list(/datum/reagent/toxin/cyanide = 0.35, /datum/reagent/drug/space_drugs = 0.15, /datum/reagent/toxin/lipolicide = 0.15)
rarity = 40
diff --git a/code/modules/hydroponics/grown/citrus.dm b/code/modules/hydroponics/grown/citrus.dm
index 6ac7bbcfcb..d130d50aa5 100644
--- a/code/modules/hydroponics/grown/citrus.dm
+++ b/code/modules/hydroponics/grown/citrus.dm
@@ -33,26 +33,6 @@
filling_color = "#00FF00"
juice_results = list(/datum/reagent/consumable/limejuice = 0)
-// Electric Lime
-/obj/item/seeds/lime/electric
- name = "pack of electric lime seeds"
- desc = "Electrically sour seeds."
- icon_state = "seed-electriclime"
- species = "electric lime"
- plantname = "Electric Lime Tree"
- growing_icon = 'icons/obj/hydroponics/growing_fruits.dmi'
- icon_grow = "lime-grow"
- icon_dead = "lime-dead"
- icon_harvest = "lime-harvest"
- product = /obj/item/reagent_containers/food/snacks/grown/citrus/lime/electric
- genes = list(/datum/plant_gene/trait/repeated_harvest, /datum/plant_gene/trait/cell_charge, /datum/plant_gene/trait/glow/green)
-
-/obj/item/reagent_containers/food/snacks/grown/citrus/lime/electric
- seed = /obj/item/seeds/lime/electric
- name = "electric lime"
- desc = "It's so sour, you'll be shocked!"
- icon_state = "electriclime"
-
// Orange
/obj/item/seeds/orange
name = "pack of orange seeds"
diff --git a/code/modules/hydroponics/grown/garlic.dm b/code/modules/hydroponics/grown/garlic.dm
index 4184b85008..2cc3f41860 100644
--- a/code/modules/hydroponics/grown/garlic.dm
+++ b/code/modules/hydroponics/grown/garlic.dm
@@ -9,6 +9,9 @@
potency = 25
growthstages = 3
growing_icon = 'icons/obj/hydroponics/growing_vegetables.dmi'
+ icon_grow = "garlic-grow"
+ icon_harvest = "garlic-harvest"
+ icon_dead = "garlic-dead"
reagents_add = list(/datum/reagent/consumable/garlic = 0.15, /datum/reagent/consumable/nutriment = 0.1)
/obj/item/reagent_containers/food/snacks/grown/garlic
diff --git a/code/modules/hydroponics/grown/grass_carpet.dm b/code/modules/hydroponics/grown/grass_carpet.dm
index 3b5159465c..a74850f3be 100644
--- a/code/modules/hydroponics/grown/grass_carpet.dm
+++ b/code/modules/hydroponics/grown/grass_carpet.dm
@@ -51,6 +51,7 @@
icon_grow = "fairygrass-grow"
icon_dead = "fairygrass-dead"
genes = list(/datum/plant_gene/trait/repeated_harvest, /datum/plant_gene/trait/glow/blue)
+ mutatelist = list (/obj/item/seeds/grass/carpet)
reagents_add = list(/datum/reagent/consumable/nutriment = 0.02, /datum/reagent/hydrogen = 0.05, /datum/reagent/drug/space_drugs = 0.15)
/obj/item/reagent_containers/food/snacks/grown/grass/fairy
@@ -99,7 +100,7 @@
species = "carpet"
plantname = "Carpet"
product = /obj/item/reagent_containers/food/snacks/grown/grass/carpet
- mutatelist = list()
+ mutatelist = list(/obj/item/seeds/grass/fairy)
rarity = 10
/obj/item/reagent_containers/food/snacks/grown/grass/carpet
diff --git a/code/modules/hydroponics/grown/tea_coffee.dm b/code/modules/hydroponics/grown/tea_coffee.dm
index de27d1eed7..223b2c7bce 100644
--- a/code/modules/hydroponics/grown/tea_coffee.dm
+++ b/code/modules/hydroponics/grown/tea_coffee.dm
@@ -44,7 +44,7 @@
filling_color = "#4582B4"
grind_results = list(/datum/reagent/toxin/teapowder = 0, /datum/reagent/medicine/salglu_solution = 0)
-// Kitty drugs
+// Catnip
/obj/item/seeds/tea/catnip
name = "pack of catnip seeds"
icon_state = "seed-catnip"
@@ -52,6 +52,9 @@
species = "catnip"
plantname = "Catnip Plant"
growthstages = 3
+ icon_grow = "catnip-grow"
+ icon_harvest = "catnip-harvest"
+ icon_dead = "tea-dead"
product = /obj/item/reagent_containers/food/snacks/grown/tea/catnip
reagents_add = list(/datum/reagent/pax/catnip = 0.1, /datum/reagent/consumable/nutriment/vitamin = 0.06, /datum/reagent/toxin/teapowder = 0.3)
rarity = 50
diff --git a/code/modules/jobs/job_types/_job.dm b/code/modules/jobs/job_types/_job.dm
index bd36218211..1238b37919 100644
--- a/code/modules/jobs/job_types/_job.dm
+++ b/code/modules/jobs/job_types/_job.dm
@@ -46,6 +46,7 @@
var/minimal_player_age = 0
var/outfit = null
+ var/plasma_outfit = null //the outfit given to plasmamen
var/exp_requirements = 0
diff --git a/code/modules/jobs/job_types/atmospheric_technician.dm b/code/modules/jobs/job_types/atmospheric_technician.dm
index 1962b8e8a9..bff56d1d16 100644
--- a/code/modules/jobs/job_types/atmospheric_technician.dm
+++ b/code/modules/jobs/job_types/atmospheric_technician.dm
@@ -12,6 +12,7 @@
exp_type = EXP_TYPE_CREW
outfit = /datum/outfit/job/atmos
+ plasma_outfit = /datum/outfit/plasmaman/atmospherics
access = list(ACCESS_ENGINE, ACCESS_ENGINE_EQUIP, ACCESS_TECH_STORAGE, ACCESS_MAINT_TUNNELS,
ACCESS_EXTERNAL_AIRLOCKS, ACCESS_CONSTRUCTION, ACCESS_ATMOSPHERICS, ACCESS_MINERAL_STOREROOM)
diff --git a/code/modules/jobs/job_types/bartender.dm b/code/modules/jobs/job_types/bartender.dm
index e5cd015460..8290adbbd7 100644
--- a/code/modules/jobs/job_types/bartender.dm
+++ b/code/modules/jobs/job_types/bartender.dm
@@ -11,6 +11,7 @@
exp_type_department = EXP_TYPE_SERVICE // This is so the jobs menu can work properly
outfit = /datum/outfit/job/bartender
+ plasma_outfit = /datum/outfit/plasmaman/bar
access = list(ACCESS_HYDROPONICS, ACCESS_BAR, ACCESS_KITCHEN, ACCESS_MORGUE, ACCESS_WEAPONS, ACCESS_MINERAL_STOREROOM)
minimal_access = list(ACCESS_BAR, ACCESS_MINERAL_STOREROOM)
diff --git a/code/modules/jobs/job_types/botanist.dm b/code/modules/jobs/job_types/botanist.dm
index 65f3e7ca48..4c91f87791 100644
--- a/code/modules/jobs/job_types/botanist.dm
+++ b/code/modules/jobs/job_types/botanist.dm
@@ -10,6 +10,7 @@
selection_color = "#bbe291"
outfit = /datum/outfit/job/botanist
+ plasma_outfit = /datum/outfit/plasmaman/botany
access = list(ACCESS_HYDROPONICS, ACCESS_BAR, ACCESS_KITCHEN, ACCESS_MORGUE, ACCESS_MINERAL_STOREROOM)
minimal_access = list(ACCESS_HYDROPONICS, ACCESS_MORGUE, ACCESS_MINERAL_STOREROOM)
diff --git a/code/modules/jobs/job_types/captain.dm b/code/modules/jobs/job_types/captain.dm
index 3733658c33..047a07062d 100644
--- a/code/modules/jobs/job_types/captain.dm
+++ b/code/modules/jobs/job_types/captain.dm
@@ -17,6 +17,7 @@
outfit = /datum/outfit/job/captain
+ plasma_outfit = /datum/outfit/plasmaman/captain
access = list() //See get_access()
minimal_access = list() //See get_access()
diff --git a/code/modules/jobs/job_types/cargo_technician.dm b/code/modules/jobs/job_types/cargo_technician.dm
index 840af56a0e..1f87a5265d 100644
--- a/code/modules/jobs/job_types/cargo_technician.dm
+++ b/code/modules/jobs/job_types/cargo_technician.dm
@@ -10,6 +10,7 @@
selection_color = "#ca8f55"
outfit = /datum/outfit/job/cargo_tech
+ plasma_outfit = /datum/outfit/plasmaman/cargo
access = list(ACCESS_MAINT_TUNNELS, ACCESS_MAILSORTING, ACCESS_CARGO, ACCESS_CARGO_BOT, ACCESS_MINING,
ACCESS_MINING_STATION, ACCESS_MINERAL_STOREROOM)
diff --git a/code/modules/jobs/job_types/chaplain.dm b/code/modules/jobs/job_types/chaplain.dm
index 5f66519365..a9e891a303 100644
--- a/code/modules/jobs/job_types/chaplain.dm
+++ b/code/modules/jobs/job_types/chaplain.dm
@@ -10,6 +10,7 @@
selection_color = "#dddddd"
outfit = /datum/outfit/job/chaplain
+ plasma_outfit = /datum/outfit/plasmaman/chaplain
access = list(ACCESS_MORGUE, ACCESS_CHAPEL_OFFICE, ACCESS_CREMATORIUM, ACCESS_THEATRE)
minimal_access = list(ACCESS_MORGUE, ACCESS_CHAPEL_OFFICE, ACCESS_CREMATORIUM, ACCESS_THEATRE)
diff --git a/code/modules/jobs/job_types/chemist.dm b/code/modules/jobs/job_types/chemist.dm
index b2699071e3..6d4204d041 100644
--- a/code/modules/jobs/job_types/chemist.dm
+++ b/code/modules/jobs/job_types/chemist.dm
@@ -12,6 +12,7 @@
exp_requirements = 60
outfit = /datum/outfit/job/chemist
+ plasma_outfit = /datum/outfit/plasmaman/chemist
access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_SURGERY, ACCESS_CHEMISTRY, ACCESS_VIROLOGY, ACCESS_GENETICS, ACCESS_CLONING, ACCESS_MINERAL_STOREROOM)
minimal_access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_CHEMISTRY, ACCESS_MINERAL_STOREROOM)
diff --git a/code/modules/jobs/job_types/chief_engineer.dm b/code/modules/jobs/job_types/chief_engineer.dm
index d8df767a9f..18be8c9835 100644
--- a/code/modules/jobs/job_types/chief_engineer.dm
+++ b/code/modules/jobs/job_types/chief_engineer.dm
@@ -17,6 +17,7 @@
exp_type_department = EXP_TYPE_ENGINEERING
outfit = /datum/outfit/job/ce
+ plasma_outfit = /datum/outfit/plasmaman/ce
access = list(ACCESS_ENGINE, ACCESS_ENGINE_EQUIP, ACCESS_TECH_STORAGE, ACCESS_MAINT_TUNNELS,
ACCESS_EXTERNAL_AIRLOCKS, ACCESS_ATMOSPHERICS, ACCESS_EVA,
diff --git a/code/modules/jobs/job_types/chief_medical_officer.dm b/code/modules/jobs/job_types/chief_medical_officer.dm
index 9cbc15ca28..627a7a2ca1 100644
--- a/code/modules/jobs/job_types/chief_medical_officer.dm
+++ b/code/modules/jobs/job_types/chief_medical_officer.dm
@@ -17,6 +17,7 @@
exp_type_department = EXP_TYPE_MEDICAL
outfit = /datum/outfit/job/cmo
+ plasma_outfit = /datum/outfit/plasmaman/cmo
access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_GENETICS, ACCESS_CLONING, ACCESS_HEADS, ACCESS_MINERAL_STOREROOM,
ACCESS_CHEMISTRY, ACCESS_VIROLOGY, ACCESS_CMO, ACCESS_SURGERY, ACCESS_RC_ANNOUNCE,
diff --git a/code/modules/jobs/job_types/clown.dm b/code/modules/jobs/job_types/clown.dm
index 7ad7148614..dc2f60434c 100644
--- a/code/modules/jobs/job_types/clown.dm
+++ b/code/modules/jobs/job_types/clown.dm
@@ -10,6 +10,7 @@
selection_color = "#dddddd"
outfit = /datum/outfit/job/clown
+ plasma_outfit = /datum/outfit/plasmaman/clown
access = list(ACCESS_THEATRE)
minimal_access = list(ACCESS_THEATRE)
diff --git a/code/modules/jobs/job_types/cook.dm b/code/modules/jobs/job_types/cook.dm
index 5a5916cb7e..666ee8f036 100644
--- a/code/modules/jobs/job_types/cook.dm
+++ b/code/modules/jobs/job_types/cook.dm
@@ -11,6 +11,7 @@
var/cooks = 0 //Counts cooks amount
outfit = /datum/outfit/job/cook
+ plasma_outfit = /datum/outfit/plasmaman/chef
access = list(ACCESS_HYDROPONICS, ACCESS_BAR, ACCESS_KITCHEN, ACCESS_MORGUE, ACCESS_MINERAL_STOREROOM)
minimal_access = list(ACCESS_KITCHEN, ACCESS_MORGUE, ACCESS_MINERAL_STOREROOM)
diff --git a/code/modules/jobs/job_types/curator.dm b/code/modules/jobs/job_types/curator.dm
index 47bfd4914a..254fc15bd4 100644
--- a/code/modules/jobs/job_types/curator.dm
+++ b/code/modules/jobs/job_types/curator.dm
@@ -10,6 +10,7 @@
selection_color = "#dddddd"
outfit = /datum/outfit/job/curator
+ plasma_outfit = /datum/outfit/plasmaman/curator
access = list(ACCESS_LIBRARY)
minimal_access = list(ACCESS_LIBRARY, ACCESS_CONSTRUCTION, ACCESS_MINING_STATION)
diff --git a/code/modules/jobs/job_types/detective.dm b/code/modules/jobs/job_types/detective.dm
index 463113f14c..65724765e1 100644
--- a/code/modules/jobs/job_types/detective.dm
+++ b/code/modules/jobs/job_types/detective.dm
@@ -14,6 +14,7 @@
exp_type = EXP_TYPE_CREW
outfit = /datum/outfit/job/detective
+ plasma_outfit = /datum/outfit/plasmaman/detective
access = list(ACCESS_SEC_DOORS, ACCESS_FORENSICS_LOCKERS, ACCESS_MORGUE, ACCESS_MAINT_TUNNELS, ACCESS_COURT, ACCESS_BRIG, ACCESS_WEAPONS, ACCESS_MINERAL_STOREROOM)
minimal_access = list(ACCESS_SEC_DOORS, ACCESS_FORENSICS_LOCKERS, ACCESS_MORGUE, ACCESS_MAINT_TUNNELS, ACCESS_COURT, ACCESS_BRIG, ACCESS_WEAPONS, ACCESS_MINERAL_STOREROOM)
diff --git a/code/modules/jobs/job_types/geneticist.dm b/code/modules/jobs/job_types/geneticist.dm
index a40ca0fca3..5ff1bebfbf 100644
--- a/code/modules/jobs/job_types/geneticist.dm
+++ b/code/modules/jobs/job_types/geneticist.dm
@@ -12,6 +12,7 @@
exp_requirements = 60
outfit = /datum/outfit/job/geneticist
+ plasma_outfit = /datum/outfit/plasmaman/genetics
access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_CHEMISTRY, ACCESS_GENETICS, ACCESS_CLONING, ACCESS_RESEARCH, ACCESS_XENOBIOLOGY, ACCESS_ROBOTICS, ACCESS_MINERAL_STOREROOM, ACCESS_TECH_STORAGE)
minimal_access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_GENETICS, ACCESS_CLONING, ACCESS_RESEARCH, ACCESS_MINERAL_STOREROOM)
diff --git a/code/modules/jobs/job_types/head_of_personnel.dm b/code/modules/jobs/job_types/head_of_personnel.dm
index 8015c19c36..41fb4b99da 100644
--- a/code/modules/jobs/job_types/head_of_personnel.dm
+++ b/code/modules/jobs/job_types/head_of_personnel.dm
@@ -17,6 +17,7 @@
exp_type_department = EXP_TYPE_SERVICE
outfit = /datum/outfit/job/hop
+ plasma_outfit = /datum/outfit/plasmaman/hop
access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_COURT, ACCESS_WEAPONS,
ACCESS_MEDICAL, ACCESS_ENGINE, ACCESS_CHANGE_IDS, ACCESS_AI_UPLOAD, ACCESS_EVA, ACCESS_HEADS,
diff --git a/code/modules/jobs/job_types/head_of_security.dm b/code/modules/jobs/job_types/head_of_security.dm
index 3d7d07d894..cfd8d7f6c0 100644
--- a/code/modules/jobs/job_types/head_of_security.dm
+++ b/code/modules/jobs/job_types/head_of_security.dm
@@ -17,6 +17,8 @@
exp_type_department = EXP_TYPE_SECURITY
outfit = /datum/outfit/job/hos
+ plasma_outfit = /datum/outfit/plasmaman/hos
+
mind_traits = list(TRAIT_LAW_ENFORCEMENT_METABOLISM)
access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_ARMORY, ACCESS_COURT, ACCESS_WEAPONS, ACCESS_ENTER_GENPOP, ACCESS_LEAVE_GENPOP,
diff --git a/code/modules/jobs/job_types/janitor.dm b/code/modules/jobs/job_types/janitor.dm
index 2f6d6f0e32..c62c2e5b26 100644
--- a/code/modules/jobs/job_types/janitor.dm
+++ b/code/modules/jobs/job_types/janitor.dm
@@ -10,6 +10,7 @@
selection_color = "#bbe291"
outfit = /datum/outfit/job/janitor
+ plasma_outfit = /datum/outfit/plasmaman/janitor
access = list(ACCESS_JANITOR, ACCESS_MAINT_TUNNELS, ACCESS_MINERAL_STOREROOM)
minimal_access = list(ACCESS_JANITOR, ACCESS_MAINT_TUNNELS, ACCESS_MINERAL_STOREROOM)
diff --git a/code/modules/jobs/job_types/lawyer.dm b/code/modules/jobs/job_types/lawyer.dm
index 1a7499800b..17c376a5de 100644
--- a/code/modules/jobs/job_types/lawyer.dm
+++ b/code/modules/jobs/job_types/lawyer.dm
@@ -11,6 +11,7 @@
var/lawyers = 0 //Counts lawyer amount
outfit = /datum/outfit/job/lawyer
+ plasma_outfit = /datum/outfit/plasmaman/bar //yes, this is correct, there's no 'lawyer' plasmeme outfit
access = list(ACCESS_LAWYER, ACCESS_COURT, ACCESS_SEC_DOORS)
minimal_access = list(ACCESS_LAWYER, ACCESS_COURT, ACCESS_SEC_DOORS)
diff --git a/code/modules/jobs/job_types/medical_doctor.dm b/code/modules/jobs/job_types/medical_doctor.dm
index 5ec4b83b2f..d6a763acfe 100644
--- a/code/modules/jobs/job_types/medical_doctor.dm
+++ b/code/modules/jobs/job_types/medical_doctor.dm
@@ -10,6 +10,7 @@
selection_color = "#74b5e0"
outfit = /datum/outfit/job/doctor
+ plasma_outfit = /datum/outfit/plasmaman/medical
access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_SURGERY, ACCESS_CHEMISTRY, ACCESS_GENETICS, ACCESS_CLONING, ACCESS_VIROLOGY, ACCESS_MINERAL_STOREROOM)
minimal_access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_SURGERY, ACCESS_CLONING, ACCESS_MINERAL_STOREROOM)
diff --git a/code/modules/jobs/job_types/mime.dm b/code/modules/jobs/job_types/mime.dm
index 4ba2489ab2..e00b3a1e29 100644
--- a/code/modules/jobs/job_types/mime.dm
+++ b/code/modules/jobs/job_types/mime.dm
@@ -10,6 +10,7 @@
selection_color = "#dddddd"
outfit = /datum/outfit/job/mime
+ plasma_outfit = /datum/outfit/plasmaman/mime
access = list(ACCESS_THEATRE)
minimal_access = list(ACCESS_THEATRE)
diff --git a/code/modules/jobs/job_types/research_director.dm b/code/modules/jobs/job_types/research_director.dm
index 7128fbe2c7..33f7df8260 100644
--- a/code/modules/jobs/job_types/research_director.dm
+++ b/code/modules/jobs/job_types/research_director.dm
@@ -17,6 +17,7 @@
exp_type = EXP_TYPE_CREW
outfit = /datum/outfit/job/rd
+ plasma_outfit = /datum/outfit/plasmaman/rd
access = list(ACCESS_RD, ACCESS_HEADS, ACCESS_TOX, ACCESS_GENETICS, ACCESS_MORGUE,
ACCESS_TOX_STORAGE, ACCESS_TELEPORTER, ACCESS_SEC_DOORS,
diff --git a/code/modules/jobs/job_types/roboticist.dm b/code/modules/jobs/job_types/roboticist.dm
index f5ae93bb6a..aa52b353df 100644
--- a/code/modules/jobs/job_types/roboticist.dm
+++ b/code/modules/jobs/job_types/roboticist.dm
@@ -12,6 +12,7 @@
exp_type = EXP_TYPE_CREW
outfit = /datum/outfit/job/roboticist
+ plasma_outfit = /datum/outfit/plasmaman/robotics
access = list(ACCESS_ROBOTICS, ACCESS_TOX, ACCESS_TOX_STORAGE, ACCESS_TECH_STORAGE, ACCESS_MORGUE, ACCESS_RESEARCH, ACCESS_MINERAL_STOREROOM, ACCESS_XENOBIOLOGY, ACCESS_GENETICS)
minimal_access = list(ACCESS_ROBOTICS, ACCESS_TECH_STORAGE, ACCESS_MORGUE, ACCESS_RESEARCH, ACCESS_MINERAL_STOREROOM)
diff --git a/code/modules/jobs/job_types/scientist.dm b/code/modules/jobs/job_types/scientist.dm
index 476f740b9d..a851b333fe 100644
--- a/code/modules/jobs/job_types/scientist.dm
+++ b/code/modules/jobs/job_types/scientist.dm
@@ -12,6 +12,7 @@
exp_type = EXP_TYPE_CREW
outfit = /datum/outfit/job/scientist
+ plasma_outfit = /datum/outfit/plasmaman/science
access = list(ACCESS_ROBOTICS, ACCESS_TOX, ACCESS_TOX_STORAGE, ACCESS_RESEARCH, ACCESS_XENOBIOLOGY, ACCESS_MINERAL_STOREROOM, ACCESS_TECH_STORAGE, ACCESS_GENETICS)
minimal_access = list(ACCESS_TOX, ACCESS_TOX_STORAGE, ACCESS_RESEARCH, ACCESS_XENOBIOLOGY, ACCESS_MINERAL_STOREROOM)
diff --git a/code/modules/jobs/job_types/security_officer.dm b/code/modules/jobs/job_types/security_officer.dm
index 7e71b2d1f4..bc83eb752d 100644
--- a/code/modules/jobs/job_types/security_officer.dm
+++ b/code/modules/jobs/job_types/security_officer.dm
@@ -14,6 +14,7 @@
exp_type = EXP_TYPE_CREW
outfit = /datum/outfit/job/security
+ plasma_outfit = /datum/outfit/plasmaman/security
access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_COURT, ACCESS_MAINT_TUNNELS, ACCESS_MORGUE, ACCESS_WEAPONS, ACCESS_ENTER_GENPOP, ACCESS_LEAVE_GENPOP, ACCESS_FORENSICS_LOCKERS, ACCESS_MINERAL_STOREROOM)
minimal_access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_COURT, ACCESS_WEAPONS, ACCESS_ENTER_GENPOP, ACCESS_LEAVE_GENPOP, ACCESS_MINERAL_STOREROOM) // See /datum/job/officer/get_access()
diff --git a/code/modules/jobs/job_types/shaft_miner.dm b/code/modules/jobs/job_types/shaft_miner.dm
index ebf7ba0f1f..04d3fb53b8 100644
--- a/code/modules/jobs/job_types/shaft_miner.dm
+++ b/code/modules/jobs/job_types/shaft_miner.dm
@@ -12,6 +12,7 @@
outfit = /datum/outfit/job/miner
+ plasma_outfit = /datum/outfit/plasmaman/mining
access = list(ACCESS_MAINT_TUNNELS, ACCESS_MAILSORTING, ACCESS_CARGO, ACCESS_CARGO_BOT, ACCESS_MINING,
ACCESS_MINING_STATION, ACCESS_MINERAL_STOREROOM)
diff --git a/code/modules/jobs/job_types/station_engineer.dm b/code/modules/jobs/job_types/station_engineer.dm
index d3f5db7dbb..2396728ad8 100644
--- a/code/modules/jobs/job_types/station_engineer.dm
+++ b/code/modules/jobs/job_types/station_engineer.dm
@@ -12,6 +12,7 @@
exp_type = EXP_TYPE_CREW
outfit = /datum/outfit/job/engineer
+ plasma_outfit = /datum/outfit/plasmaman/engineering
access = list(ACCESS_ENGINE, ACCESS_ENGINE_EQUIP, ACCESS_TECH_STORAGE, ACCESS_MAINT_TUNNELS,
ACCESS_EXTERNAL_AIRLOCKS, ACCESS_CONSTRUCTION, ACCESS_ATMOSPHERICS, ACCESS_TCOMSAT, ACCESS_MINERAL_STOREROOM)
diff --git a/code/modules/jobs/job_types/virologist.dm b/code/modules/jobs/job_types/virologist.dm
index 790e828931..3e9b3ba06c 100644
--- a/code/modules/jobs/job_types/virologist.dm
+++ b/code/modules/jobs/job_types/virologist.dm
@@ -12,6 +12,7 @@
exp_requirements = 60
outfit = /datum/outfit/job/virologist
+ plasma_outfit = /datum/outfit/plasmaman/viro
access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_SURGERY, ACCESS_CHEMISTRY, ACCESS_VIROLOGY, ACCESS_GENETICS, ACCESS_CLONING, ACCESS_MINERAL_STOREROOM)
minimal_access = list(ACCESS_MEDICAL, ACCESS_VIROLOGY, ACCESS_MINERAL_STOREROOM)
diff --git a/code/modules/jobs/job_types/warden.dm b/code/modules/jobs/job_types/warden.dm
index 22e3f9b0f1..c909342d6f 100644
--- a/code/modules/jobs/job_types/warden.dm
+++ b/code/modules/jobs/job_types/warden.dm
@@ -14,6 +14,7 @@
exp_type = EXP_TYPE_CREW
outfit = /datum/outfit/job/warden
+ plasma_outfit = /datum/outfit/plasmaman/warden
access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_ARMORY, ACCESS_COURT, ACCESS_MAINT_TUNNELS, ACCESS_MORGUE, ACCESS_WEAPONS, ACCESS_ENTER_GENPOP, ACCESS_LEAVE_GENPOP, ACCESS_FORENSICS_LOCKERS, ACCESS_MINERAL_STOREROOM)
minimal_access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_ARMORY, ACCESS_COURT, ACCESS_WEAPONS, ACCESS_ENTER_GENPOP, ACCESS_LEAVE_GENPOP, ACCESS_MINERAL_STOREROOM) // See /datum/job/warden/get_access()
diff --git a/code/modules/mafia/controller.dm b/code/modules/mafia/controller.dm
index 5873decb8f..cd8c382f30 100644
--- a/code/modules/mafia/controller.dm
+++ b/code/modules/mafia/controller.dm
@@ -67,6 +67,8 @@
var/max_player = MAFIA_MAX_PLAYER_COUNT
///Required player count
var/required_player = 5
+ ///Prioritizes clients to have cool antag roles
+ var/low_pop_mode = FALSE
/datum/mafia_controller/New()
. = ..()
@@ -93,7 +95,7 @@
* * setup_list: list of all the datum setups (fancy list of roles) that would work for the game
* * ready_players: list of filtered, sane players (so not playing or disconnected) for the game to put into roles
*/
-/datum/mafia_controller/proc/prepare_game(setup_list,ready_players)
+/datum/mafia_controller/proc/prepare_game(setup_list, ready_players)
var/list/possible_maps = subtypesof(/datum/map_template/mafia)
var/turf/spawn_area = get_turf(locate(/obj/effect/landmark/mafia_game_area) in GLOB.landmarks_list)
@@ -116,18 +118,40 @@
landmarks += possible_spawn
current_setup_text = list()
+
+ var/list/boring_roles = list()
+ var/list/not_boring_roles = list()
+
for(var/rtype in setup_list)
for(var/i in 1 to setup_list[rtype])
- all_roles += new rtype(src)
+ var/datum/mafia_role/role = new rtype(src)
+ all_roles += role
+ if(role.role_type == TOWN_PROTECT || role.role_type == TOWN_INVEST || role.role_type == MAFIA_SPECIAL || role.role_type == MAFIA_REGULAR)
+ not_boring_roles += role
+ else
+ boring_roles += role
var/datum/mafia_role/rp = rtype
current_setup_text += "[initial(rp.name)] x[setup_list[rtype]]"
+
var/list/spawnpoints = landmarks.Copy()
- for(var/datum/mafia_role/role in all_roles)
- role.assigned_landmark = pick_n_take(spawnpoints)
- if(!debug)
+
+ if(length(ready_players) < 7 || low_pop_mode)
+ //do normal assign
+ for(var/datum/mafia_role/role in not_boring_roles)
+ role.assigned_landmark = pick_n_take(spawnpoints)
role.player_key = pick_n_take(ready_players)
- else
- role.player_key = pop(ready_players)
+ //shame!
+ for(var/datum/mafia_role/role in boring_roles)
+ role.assigned_landmark = pick_n_take(spawnpoints)
+ role.player_key = pick_n_take(ready_players)
+
+ else //go run the normal one
+ for(var/datum/mafia_role/role in all_roles)
+ role.assigned_landmark = pick_n_take(spawnpoints)
+ if(!debug)
+ role.player_key = pick_n_take(ready_players)
+ else
+ role.player_key = pop(ready_players)
/datum/mafia_controller/proc/send_message(msg,team)
for(var/datum/mafia_role/R in all_roles)
diff --git a/code/modules/mafia/map_pieces.dm b/code/modules/mafia/map_pieces.dm
index 3459603f3c..3339c596b4 100644
--- a/code/modules/mafia/map_pieces.dm
+++ b/code/modules/mafia/map_pieces.dm
@@ -73,7 +73,7 @@
description = "Vampires and changelings clash to find out who's the superior bloodsucking monster in this creepy castle map."
mappath = "_maps/map_files/Mafia/mafia_gothic.dmm"
-/datum/map_template/mafia/gothic
+/datum/map_template/mafia/reebe
name = "Reebe"
description = "Trouble in Reebe station! Copypaste guranteed by ClockCo™"
- mappath = "_maps/map_files/Mafia/mafia_reebe.dmm"
\ No newline at end of file
+ mappath = "_maps/map_files/Mafia/mafia_reebe.dmm"
diff --git a/code/modules/mining/equipment/kinetic_crusher.dm b/code/modules/mining/equipment/kinetic_crusher.dm
index a09d890f69..a6f456ce6f 100644
--- a/code/modules/mining/equipment/kinetic_crusher.dm
+++ b/code/modules/mining/equipment/kinetic_crusher.dm
@@ -183,7 +183,6 @@
attack_verb = list("stabbed", "diced", "sliced", "cleaved", "chopped", "lacerated", "cut", "jabbed", "punctured")
icon_state = "crusher-glaive"
item_state = "crusher0-glaive"
- item_flags = ITEM_CAN_PARRY
block_parry_data = /datum/block_parry_data/crusherglaive
//ideas: altclick that lets you pummel people with the handguard/handle?
//parrying functionality?
@@ -217,6 +216,16 @@
if(owner.Adjacent(attacker) && (!attacker.anchored || ismegafauna(attacker))) // free backstab, if you perfect parry
attacker.dir = get_dir(owner,attacker)
+/// triggered on wield of two handed item
+/obj/item/kinetic_crusher/glaive/on_wield(obj/item/source, mob/user)
+ wielded = TRUE
+ item_flags |= (ITEM_CAN_PARRY)
+
+/// triggered on unwield of two handed item
+/obj/item/kinetic_crusher/glaive/on_unwield(obj/item/source, mob/user)
+ wielded = FALSE
+ item_flags &= ~(ITEM_CAN_PARRY)
+
/obj/item/kinetic_crusher/glaive/update_icon_state()
item_state = "crusher[wielded]-glaive" // this is not icon_state and not supported by 2hcomponent
diff --git a/code/modules/mob/dead/new_player/sprite_accessories/Citadel_Snowflake.dm b/code/modules/mob/dead/new_player/sprite_accessories/Citadel_Snowflake.dm
index 020776a75f..3c2c850e3c 100644
--- a/code/modules/mob/dead/new_player/sprite_accessories/Citadel_Snowflake.dm
+++ b/code/modules/mob/dead/new_player/sprite_accessories/Citadel_Snowflake.dm
@@ -1,9 +1,9 @@
-/datum/sprite_accessory/mam_tails/shark/datashark
+/datum/sprite_accessory/tails/mam_tails/shark/datashark
name = "DataShark"
icon_state = "datashark"
ckeys_allowed = list("rubyflamewing")
-/datum/sprite_accessory/mam_tails_animated/shark/datashark
+/datum/sprite_accessory/tails_animated/mam_tails_animated/shark/datashark
name = "DataShark"
icon_state = "datashark"
ckeys_allowed = list("rubyflamewing")
@@ -14,19 +14,19 @@
ckeys_allowed = list("rubyflamewing")
//Sabresune
-/datum/sprite_accessory/mam_ears/sabresune
+/datum/sprite_accessory/ears/mam_ears/sabresune
name = "Sabresune"
icon_state = "sabresune"
ckeys_allowed = list("poojawa")
extra = TRUE
extra_color_src = MUTCOLORS3
-/datum/sprite_accessory/mam_tails/sabresune
+/datum/sprite_accessory/tails/mam_tails/sabresune
name = "Sabresune"
icon_state = "sabresune"
ckeys_allowed = list("poojawa")
-/datum/sprite_accessory/mam_tails_animated/sabresune
+/datum/sprite_accessory/tails_animated/mam_tails_animated/sabresune
name = "Sabresune"
icon_state = "sabresune"
ckeys_allowed = list("poojawa")
@@ -37,17 +37,17 @@
ckeys_allowed = list("poojawa")
//Lunasune
-/datum/sprite_accessory/mam_ears/lunasune
+/datum/sprite_accessory/ears/mam_ears/lunasune
name = "lunasune"
icon_state = "lunasune"
ckeys_allowed = list("invader4352")
-/datum/sprite_accessory/mam_tails/lunasune
+/datum/sprite_accessory/tails/mam_tails/lunasune
name = "lunasune"
icon_state = "lunasune"
ckeys_allowed = list("invader4352")
-/datum/sprite_accessory/mam_tails_animated/lunasune
+/datum/sprite_accessory/tails_animated/mam_tails_animated/lunasune
name = "lunasune"
icon_state = "lunasune"
ckeys_allowed = list("invader4352")
diff --git a/code/modules/mob/dead/new_player/sprite_accessories/_sprite_accessories.dm b/code/modules/mob/dead/new_player/sprite_accessories/_sprite_accessories.dm
index 6514cb4f80..4cb8d080ff 100644
--- a/code/modules/mob/dead/new_player/sprite_accessories/_sprite_accessories.dm
+++ b/code/modules/mob/dead/new_player/sprite_accessories/_sprite_accessories.dm
@@ -76,6 +76,9 @@
//For soft-restricting markings to species IDs
var/list/recommended_species
+/datum/sprite_accessory/proc/is_not_visible(var/mob/living/carbon/human/H, var/tauric) //return if the accessory shouldn't be shown
+ return FALSE
+
/datum/sprite_accessory/underwear
icon = 'icons/mob/clothing/underwear.dmi'
var/has_color = FALSE
diff --git a/code/modules/mob/dead/new_player/sprite_accessories/alienpeople.dm b/code/modules/mob/dead/new_player/sprite_accessories/alienpeople.dm
index c8e7aca26d..899bf91081 100644
--- a/code/modules/mob/dead/new_player/sprite_accessories/alienpeople.dm
+++ b/code/modules/mob/dead/new_player/sprite_accessories/alienpeople.dm
@@ -7,6 +7,9 @@
mutant_part_string = "xenodorsal"
relevant_layers = list(BODY_BEHIND_LAYER, BODY_FRONT_LAYER)
+/datum/sprite_accessory/xeno_dorsal/is_not_visible(var/mob/living/carbon/human/H, var/tauric)
+ return (!H.dna.features["xenodorsal"] || H.dna.features["xenodorsal"] == "None" || (H.wear_suit && (H.wear_suit.flags_inv & HIDEJUMPSUIT)))
+
/datum/sprite_accessory/xeno_dorsal/standard
name = "Standard"
icon_state = "standard"
@@ -27,6 +30,9 @@
mutant_part_string = "tail"
relevant_layers = list(BODY_BEHIND_LAYER, BODY_FRONT_LAYER)
+/datum/sprite_accessory/xeno_tail/is_not_visible(var/mob/living/carbon/human/H, var/tauric)
+ return (!H.dna.features["xenotail"] || H.dna.features["xenotail"] == "None" || H.wear_suit && (H.wear_suit.flags_inv & HIDEJUMPSUIT))
+
/datum/sprite_accessory/xeno_tail/none
name = "None"
relevant_layers = null
@@ -43,6 +49,10 @@
mutant_part_string = "xhead"
relevant_layers = list(BODY_ADJ_LAYER)
+/datum/sprite_accessory/xeno_head/is_not_visible(var/mob/living/carbon/human/H, var/tauric)
+ var/obj/item/bodypart/head/HD = H.get_bodypart(BODY_ZONE_HEAD)
+ return (!H.dna.features["xenohead"] || H.dna.features["xenohead"] == "None" || H.head && (H.head.flags_inv & HIDEHAIR) || (H.wear_mask && (H.wear_mask.flags_inv & HIDEHAIR)) || !HD || HD.status == BODYPART_ROBOTIC)
+
/datum/sprite_accessory/xeno_head/standard
name = "Standard"
icon_state = "standard"
diff --git a/code/modules/mob/dead/new_player/sprite_accessories/body_markings.dm b/code/modules/mob/dead/new_player/sprite_accessories/body_markings.dm
index 9950f0d76a..a04838a360 100644
--- a/code/modules/mob/dead/new_player/sprite_accessories/body_markings.dm
+++ b/code/modules/mob/dead/new_player/sprite_accessories/body_markings.dm
@@ -224,6 +224,9 @@
color_src = 0
relevant_layers = list(BODY_FRONT_LAYER)
+/datum/sprite_accessory/insect_fluff/is_not_visible(var/mob/living/carbon/human/H, var/tauric)
+ return (!H.dna.features["insect_fluff"] || H.dna.features["insect_fluff"] == "None" || H.wear_suit && (H.wear_suit.flags_inv & HIDEJUMPSUIT))
+
/datum/sprite_accessory/insect_fluff/none
name = "None"
icon_state = "none"
diff --git a/code/modules/mob/dead/new_player/sprite_accessories/ears.dm b/code/modules/mob/dead/new_player/sprite_accessories/ears.dm
index bc269ccf62..1e6c797364 100644
--- a/code/modules/mob/dead/new_player/sprite_accessories/ears.dm
+++ b/code/modules/mob/dead/new_player/sprite_accessories/ears.dm
@@ -3,6 +3,10 @@
mutant_part_string = "ears"
relevant_layers = list(BODY_BEHIND_LAYER, BODY_ADJ_LAYER, BODY_FRONT_LAYER)
+/datum/sprite_accessory/ears/is_not_visible(var/mob/living/carbon/human/H, var/tauric)
+ var/obj/item/bodypart/head/HD = H.get_bodypart(BODY_ZONE_HEAD)
+ return (!H.dna.features["ears"] || H.dna.features["ears"] == "None" || H.head && (H.head.flags_inv & HIDEEARS) || (H.wear_mask && (H.wear_mask.flags_inv & HIDEEARS)) || !HD || HD.status == BODYPART_ROBOTIC)
+
/datum/sprite_accessory/ears/none
name = "None"
icon_state = "none"
@@ -175,50 +179,54 @@
*************** Furry Ears ****************
*******************************************/
-/datum/sprite_accessory/mam_ears
+/datum/sprite_accessory/ears/mam_ears
icon = 'modular_citadel/icons/mob/mam_ears.dmi'
color_src = MATRIXED
mutant_part_string = "ears"
relevant_layers = list(BODY_BEHIND_LAYER, BODY_ADJ_LAYER, BODY_FRONT_LAYER)
-/datum/sprite_accessory/mam_ears/none
+/datum/sprite_accessory/ears/mam_ears/is_not_visible(var/mob/living/carbon/human/H, var/tauric)
+ var/obj/item/bodypart/head/HD = H.get_bodypart(BODY_ZONE_HEAD)
+ return (!H.dna.features["mam_ears"] || H.dna.features["mam_ears"] == "None" || H.head && (H.head.flags_inv & HIDEEARS) || (H.wear_mask && (H.wear_mask.flags_inv & HIDEEARS)) || !HD || HD.status == BODYPART_ROBOTIC)
+
+/datum/sprite_accessory/ears/mam_ears/none
name = "None"
icon_state = "none"
relevant_layers = null
-/datum/sprite_accessory/mam_ears/axolotl
+/datum/sprite_accessory/ears/mam_ears/axolotl
name = "Axolotl"
icon_state = "axolotl"
-/datum/sprite_accessory/mam_ears/bat
+/datum/sprite_accessory/ears/mam_ears/bat
name = "Bat"
icon_state = "bat"
-/datum/sprite_accessory/mam_ears/bear
+/datum/sprite_accessory/ears/mam_ears/bear
name = "Bear"
icon_state = "bear"
-/datum/sprite_accessory/mam_ears/bigwolf
+/datum/sprite_accessory/ears/mam_ears/bigwolf
name = "Big Wolf"
icon_state = "bigwolf"
-/datum/sprite_accessory/mam_ears/bigwolfinner
+/datum/sprite_accessory/ears/mam_ears/bigwolfinner
name = "Big Wolf (ALT)"
icon_state = "bigwolfinner"
extra = TRUE
extra_color_src = NONE
-/datum/sprite_accessory/mam_ears/bigwolfdark
+/datum/sprite_accessory/ears/mam_ears/bigwolfdark
name = "Dark Big Wolf"
icon_state = "bigwolfdark"
-/datum/sprite_accessory/mam_ears/bigwolfinnerdark
+/datum/sprite_accessory/ears/mam_ears/bigwolfinnerdark
name = "Dark Big Wolf (ALT)"
icon_state = "bigwolfinnerdark"
extra = TRUE
extra_color_src = NONE
-/datum/sprite_accessory/mam_ears/cat
+/datum/sprite_accessory/ears/mam_ears/cat
name = "Cat"
icon_state = "cat"
icon = 'icons/mob/mutant_bodyparts.dmi'
@@ -226,100 +234,100 @@
extra = TRUE
extra_color_src = NONE
-/datum/sprite_accessory/mam_ears/catbig
+/datum/sprite_accessory/ears/mam_ears/catbig
name = "Cat, Big"
icon_state = "catbig"
-/datum/sprite_accessory/mam_ears/cow
+/datum/sprite_accessory/ears/mam_ears/cow
name = "Cow"
icon_state = "cow"
-/datum/sprite_accessory/mam_ears/curled
+/datum/sprite_accessory/ears/mam_ears/curled
name = "Curled Horn"
icon_state = "horn1"
color_src = MUTCOLORS3
-/datum/sprite_accessory/mam_ears/deer
+/datum/sprite_accessory/ears/mam_ears/deer
name = "Deer"
icon_state = "deer"
color_src = MUTCOLORS3
-/datum/sprite_accessory/mam_ears/eevee
+/datum/sprite_accessory/ears/mam_ears/eevee
name = "Eevee"
icon_state = "eevee"
-/datum/sprite_accessory/mam_ears/elf
+/datum/sprite_accessory/ears/mam_ears/elf
name = "Elf"
icon_state = "elf"
color_src = MUTCOLORS3
-/datum/sprite_accessory/mam_ears/elephant
+/datum/sprite_accessory/ears/mam_ears/elephant
name = "Elephant"
icon_state = "elephant"
-/datum/sprite_accessory/mam_ears/fennec
+/datum/sprite_accessory/ears/mam_ears/fennec
name = "Fennec"
icon_state = "fennec"
-/datum/sprite_accessory/mam_ears/fish
+/datum/sprite_accessory/ears/mam_ears/fish
name = "Fish"
icon_state = "fish"
-/datum/sprite_accessory/mam_ears/fox
+/datum/sprite_accessory/ears/mam_ears/fox
name = "Fox"
icon_state = "fox"
-/datum/sprite_accessory/mam_ears/husky
+/datum/sprite_accessory/ears/mam_ears/husky
name = "Husky"
icon_state = "wolf"
-/datum/sprite_accessory/mam_ears/kangaroo
+/datum/sprite_accessory/ears/mam_ears/kangaroo
name = "kangaroo"
icon_state = "kangaroo"
-/datum/sprite_accessory/mam_ears/jellyfish
+/datum/sprite_accessory/ears/mam_ears/jellyfish
name = "Jellyfish"
icon_state = "jellyfish"
color_src = HAIR
-/datum/sprite_accessory/mam_ears/lab
+/datum/sprite_accessory/ears/mam_ears/lab
name = "Dog, Long"
icon_state = "lab"
-/datum/sprite_accessory/mam_ears/murid
+/datum/sprite_accessory/ears/mam_ears/murid
name = "Murid"
icon_state = "murid"
-/datum/sprite_accessory/mam_ears/otie
+/datum/sprite_accessory/ears/mam_ears/otie
name = "Otusian"
icon_state = "otie"
-/datum/sprite_accessory/mam_ears/squirrel
+/datum/sprite_accessory/ears/mam_ears/squirrel
name = "Squirrel"
icon_state = "squirrel"
-/datum/sprite_accessory/mam_ears/pede
+/datum/sprite_accessory/ears/mam_ears/pede
name = "Scolipede"
icon_state = "pede"
-/datum/sprite_accessory/mam_ears/rabbit
+/datum/sprite_accessory/ears/mam_ears/rabbit
name = "Rabbit"
icon_state = "rabbit"
-/datum/sprite_accessory/mam_ears/sergal
+/datum/sprite_accessory/ears/mam_ears/sergal
name = "Sergal"
icon_state = "sergal"
-/datum/sprite_accessory/mam_ears/skunk
+/datum/sprite_accessory/ears/mam_ears/skunk
name = "skunk"
icon_state = "skunk"
-/datum/sprite_accessory/mam_ears/wolf
+/datum/sprite_accessory/ears/mam_ears/wolf
name = "Wolf"
icon_state = "wolf"
-/datum/sprite_accessory/mam_ears/bunny
+/datum/sprite_accessory/ears/mam_ears/bunny
name = "Bunny"
icon_state = "bunny"
diff --git a/code/modules/mob/dead/new_player/sprite_accessories/frills.dm b/code/modules/mob/dead/new_player/sprite_accessories/frills.dm
index 0aaec309a4..18a76df116 100644
--- a/code/modules/mob/dead/new_player/sprite_accessories/frills.dm
+++ b/code/modules/mob/dead/new_player/sprite_accessories/frills.dm
@@ -2,6 +2,10 @@
icon = 'icons/mob/mutant_bodyparts.dmi'
relevant_layers = list(BODY_ADJ_LAYER)
+/datum/sprite_accessory/frills/is_not_visible(var/mob/living/carbon/human/H, var/tauric)
+ var/obj/item/bodypart/head/HD = H.get_bodypart(BODY_ZONE_HEAD)
+ return (!H.dna.features["frills"] || H.dna.features["frills"] == "None" || H.head && (H.head.flags_inv & HIDEEARS) || !HD || HD.status == BODYPART_ROBOTIC)
+
/datum/sprite_accessory/frills/none
name = "None"
icon_state = "none"
diff --git a/code/modules/mob/dead/new_player/sprite_accessories/horns.dm b/code/modules/mob/dead/new_player/sprite_accessories/horns.dm
index b39f48f858..3a65eaebfa 100644
--- a/code/modules/mob/dead/new_player/sprite_accessories/horns.dm
+++ b/code/modules/mob/dead/new_player/sprite_accessories/horns.dm
@@ -3,6 +3,10 @@
color_src = HORNCOLOR
relevant_layers = list(HORNS_LAYER)
+/datum/sprite_accessory/horns/is_not_visible(var/mob/living/carbon/human/H, var/tauric)
+ var/obj/item/bodypart/head/HD = H.get_bodypart(BODY_ZONE_HEAD)
+ return (!H.dna.features["horns"] || H.dna.features["horns"] == "None" || H.head && (H.head.flags_inv & HIDEHAIR) || (H.wear_mask && (H.wear_mask.flags_inv & HIDEHAIR)) || !HD || HD.status == BODYPART_ROBOTIC)
+
/datum/sprite_accessory/horns/none
name = "None"
icon_state = "none"
diff --git a/code/modules/mob/dead/new_player/sprite_accessories/legs_and_taurs.dm b/code/modules/mob/dead/new_player/sprite_accessories/legs_and_taurs.dm
index 2ec6da2da8..d41f5ace22 100644
--- a/code/modules/mob/dead/new_player/sprite_accessories/legs_and_taurs.dm
+++ b/code/modules/mob/dead/new_player/sprite_accessories/legs_and_taurs.dm
@@ -30,6 +30,9 @@
var/alt_taur_mode = NONE //Same as above.
var/hide_legs = USE_QUADRUPED_CLIP_MASK
+/datum/sprite_accessory/taur/is_not_visible(var/mob/living/carbon/human/H, var/tauric)
+ return (!tauric || (H.wear_suit && (H.wear_suit.flags_inv & HIDETAUR)))
+
/datum/sprite_accessory/taur/New()
switch(hide_legs)
if(USE_QUADRUPED_CLIP_MASK)
diff --git a/code/modules/mob/dead/new_player/sprite_accessories/snouts.dm b/code/modules/mob/dead/new_player/sprite_accessories/snouts.dm
index 2c0db56ce4..7319652ebe 100644
--- a/code/modules/mob/dead/new_player/sprite_accessories/snouts.dm
+++ b/code/modules/mob/dead/new_player/sprite_accessories/snouts.dm
@@ -3,6 +3,10 @@
mutant_part_string = "snout"
relevant_layers = list(BODY_ADJ_LAYER, BODY_FRONT_LAYER)
+/datum/sprite_accessory/snouts/is_not_visible(var/mob/living/carbon/human/H, var/tauric)
+ var/obj/item/bodypart/head/HD = H.get_bodypart(BODY_ZONE_HEAD)
+ return ((H.wear_mask && (H.wear_mask.flags_inv & HIDESNOUT)) || (H.head && (H.head.flags_inv & HIDESNOUT)) || !HD || HD.status == BODYPART_ROBOTIC)
+
/datum/sprite_accessory/snouts/sharp
name = "Sharp"
icon_state = "sharp"
@@ -150,136 +154,140 @@
************** Mammal Snouts **************
*******************************************/
-/datum/sprite_accessory/mam_snouts
+/datum/sprite_accessory/snouts/mam_snouts
color_src = MATRIXED
icon = 'modular_citadel/icons/mob/mam_snouts.dmi'
recommended_species = list("mammal", "slimeperson", "insect", "podweak")
mutant_part_string = "snout"
relevant_layers = list(BODY_ADJ_LAYER, BODY_FRONT_LAYER)
-/datum/sprite_accessory/mam_snouts/none
+/datum/sprite_accessory/snouts/mam_snouts/is_not_visible(var/mob/living/carbon/human/H, var/tauric)
+ var/obj/item/bodypart/head/HD = H.get_bodypart(BODY_ZONE_HEAD)
+ return ((H.wear_mask && (H.wear_mask.flags_inv & HIDESNOUT)) || (H.head && (H.head.flags_inv & HIDESNOUT)) || !HD || HD.status == BODYPART_ROBOTIC)
+
+/datum/sprite_accessory/snouts/mam_snouts/none
name = "None"
icon_state = "none"
recommended_species = null
relevant_layers = null
-/datum/sprite_accessory/mam_snouts/bird
+/datum/sprite_accessory/snouts/mam_snouts/bird
name = "Beak"
icon_state = "bird"
-/datum/sprite_accessory/mam_snouts/bigbeak
+/datum/sprite_accessory/snouts/mam_snouts/bigbeak
name = "Big Beak"
icon_state = "bigbeak"
-/datum/sprite_accessory/mam_snouts/bug
+/datum/sprite_accessory/snouts/mam_snouts/bug
name = "Bug"
icon_state = "bug"
color_src = MUTCOLORS
extra2 = TRUE
extra2_color_src = MUTCOLORS3
-/datum/sprite_accessory/mam_snouts/elephant
+/datum/sprite_accessory/snouts/mam_snouts/elephant
name = "Elephant"
icon_state = "elephant"
extra = TRUE
extra_color_src = MUTCOLORS3
-/datum/sprite_accessory/mam_snouts/skulldog
+/datum/sprite_accessory/snouts/mam_snouts/skulldog
name = "Skulldog"
icon_state = "skulldog"
extra = TRUE
extra_color_src = MATRIXED
-/datum/sprite_accessory/mam_snouts/lcanid
+/datum/sprite_accessory/snouts/mam_snouts/lcanid
name = "Mammal, Long"
icon_state = "lcanid"
-/datum/sprite_accessory/mam_snouts/lcanidalt
+/datum/sprite_accessory/snouts/mam_snouts/lcanidalt
name = "Mammal, Long ALT"
icon_state = "lcanidalt"
-/datum/sprite_accessory/mam_snouts/scanid
+/datum/sprite_accessory/snouts/mam_snouts/scanid
name = "Mammal, Short"
icon_state = "scanid"
-/datum/sprite_accessory/mam_snouts/scanidalt
+/datum/sprite_accessory/snouts/mam_snouts/scanidalt
name = "Mammal, Short ALT"
icon_state = "scanidalt"
-/datum/sprite_accessory/mam_snouts/scanidalt2
+/datum/sprite_accessory/snouts/mam_snouts/scanidalt2
name = "Mammal, Short ALT 2"
icon_state = "scanidalt2"
-/datum/sprite_accessory/mam_snouts/wolf
+/datum/sprite_accessory/snouts/mam_snouts/wolf
name = "Mammal, Thick"
icon_state = "wolf"
-/datum/sprite_accessory/mam_snouts/wolfalt
+/datum/sprite_accessory/snouts/mam_snouts/wolfalt
name = "Mammal, Thick ALT"
icon_state = "wolfalt"
-/datum/sprite_accessory/mam_snouts/redpanda
+/datum/sprite_accessory/snouts/mam_snouts/redpanda
name = "WahCoon"
icon_state = "wah"
-/datum/sprite_accessory/mam_snouts/redpandaalt
+/datum/sprite_accessory/snouts/mam_snouts/redpandaalt
name = "WahCoon ALT"
icon_state = "wahalt"
-/datum/sprite_accessory/mam_snouts/rhino
+/datum/sprite_accessory/snouts/mam_snouts/rhino
name = "Horn"
icon_state = "rhino"
extra = TRUE
extra = MUTCOLORS3
-/datum/sprite_accessory/mam_snouts/rodent
+/datum/sprite_accessory/snouts/mam_snouts/rodent
name = "Rodent"
icon_state = "rodent"
-/datum/sprite_accessory/mam_snouts/husky
+/datum/sprite_accessory/snouts/mam_snouts/husky
name = "Husky"
icon_state = "husky"
-/datum/sprite_accessory/mam_snouts/otie
+/datum/sprite_accessory/snouts/mam_snouts/otie
name = "Otie"
icon_state = "otie"
-/datum/sprite_accessory/mam_snouts/pede
+/datum/sprite_accessory/snouts/mam_snouts/pede
name = "Scolipede"
icon_state = "pede"
-/datum/sprite_accessory/mam_snouts/sergal
+/datum/sprite_accessory/snouts/mam_snouts/sergal
name = "Sergal"
icon_state = "sergal"
-/datum/sprite_accessory/mam_snouts/shark
+/datum/sprite_accessory/snouts/mam_snouts/shark
name = "Shark"
icon_state = "shark"
-/datum/sprite_accessory/mam_snouts/hshark
+/datum/sprite_accessory/snouts/mam_snouts/hshark
name = "hShark"
icon_state = "hshark"
-/datum/sprite_accessory/mam_snouts/toucan
+/datum/sprite_accessory/snouts/mam_snouts/toucan
name = "Toucan"
icon_state = "toucan"
-/datum/sprite_accessory/mam_snouts/sharp
+/datum/sprite_accessory/snouts/mam_snouts/sharp
name = "Sharp"
icon_state = "sharp"
color_src = MUTCOLORS
-/datum/sprite_accessory/mam_snouts/round
+/datum/sprite_accessory/snouts/mam_snouts/round
name = "Round"
icon_state = "round"
color_src = MUTCOLORS
-/datum/sprite_accessory/mam_snouts/sharplight
+/datum/sprite_accessory/snouts/mam_snouts/sharplight
name = "Sharp + Light"
icon_state = "sharplight"
color_src = MUTCOLORS
-/datum/sprite_accessory/mam_snouts/roundlight
+/datum/sprite_accessory/snouts/mam_snouts/roundlight
name = "Round + Light"
icon_state = "roundlight"
color_src = MUTCOLORS
@@ -289,109 +297,109 @@
**************** Snouts *******************
*************but higher up*****************/
-/datum/sprite_accessory/mam_snouts/fbird
+/datum/sprite_accessory/snouts/mam_snouts/fbird
name = "Beak (Top)"
icon_state = "fbird"
-/datum/sprite_accessory/mam_snouts/fbigbeak
+/datum/sprite_accessory/snouts/mam_snouts/fbigbeak
name = "Big Beak (Top)"
icon_state = "fbigbeak"
-/datum/sprite_accessory/mam_snouts/fbug
+/datum/sprite_accessory/snouts/mam_snouts/fbug
name = "Bug (Top)"
icon_state = "fbug"
color_src = MUTCOLORS
extra2 = TRUE
extra2_color_src = MUTCOLORS3
-/datum/sprite_accessory/mam_snouts/felephant
+/datum/sprite_accessory/snouts/mam_snouts/felephant
name = "Elephant (Top)"
icon_state = "felephant"
extra = TRUE
extra_color_src = MUTCOLORS3
-/datum/sprite_accessory/mam_snouts/flcanid
+/datum/sprite_accessory/snouts/mam_snouts/flcanid
name = "Mammal, Long (Top)"
icon_state = "flcanid"
-/datum/sprite_accessory/mam_snouts/flcanidalt
+/datum/sprite_accessory/snouts/mam_snouts/flcanidalt
name = "Mammal, Long ALT (Top)"
icon_state = "flcanidalt"
-/datum/sprite_accessory/mam_snouts/fscanid
+/datum/sprite_accessory/snouts/mam_snouts/fscanid
name = "Mammal, Short (Top)"
icon_state = "fscanid"
-/datum/sprite_accessory/mam_snouts/fscanidalt
+/datum/sprite_accessory/snouts/mam_snouts/fscanidalt
name = "Mammal, Short ALT (Top)"
icon_state = "fscanidalt"
-/datum/sprite_accessory/mam_snouts/fscanidalt2
+/datum/sprite_accessory/snouts/mam_snouts/fscanidalt2
name = "Mammal, Short ALT 2 (Top)"
icon_state = "fscanidalt2"
-/datum/sprite_accessory/mam_snouts/fwolf
+/datum/sprite_accessory/snouts/mam_snouts/fwolf
name = "Mammal, Thick (Top)"
icon_state = "fwolf"
-/datum/sprite_accessory/mam_snouts/fwolfalt
+/datum/sprite_accessory/snouts/mam_snouts/fwolfalt
name = "Mammal, Thick ALT (Top)"
icon_state = "fwolfalt"
-/datum/sprite_accessory/mam_snouts/fredpanda
+/datum/sprite_accessory/snouts/mam_snouts/fredpanda
name = "WahCoon (Top)"
icon_state = "fwah"
-/datum/sprite_accessory/mam_snouts/frhino
+/datum/sprite_accessory/snouts/mam_snouts/frhino
name = "Horn (Top)"
icon_state = "frhino"
extra = TRUE
extra = MUTCOLORS3
-/datum/sprite_accessory/mam_snouts/frodent
+/datum/sprite_accessory/snouts/mam_snouts/frodent
name = "Rodent (Top)"
icon_state = "frodent"
-/datum/sprite_accessory/mam_snouts/fhusky
+/datum/sprite_accessory/snouts/mam_snouts/fhusky
name = "Husky (Top)"
icon_state = "fhusky"
-/datum/sprite_accessory/mam_snouts/fotie
+/datum/sprite_accessory/snouts/mam_snouts/fotie
name = "Otie (Top)"
icon_state = "fotie"
-/datum/sprite_accessory/mam_snouts/fpede
+/datum/sprite_accessory/snouts/mam_snouts/fpede
name = "Scolipede (Top)"
icon_state = "fpede"
-/datum/sprite_accessory/mam_snouts/fsergal
+/datum/sprite_accessory/snouts/mam_snouts/fsergal
name = "Sergal (Top)"
icon_state = "fsergal"
-/datum/sprite_accessory/mam_snouts/fshark
+/datum/sprite_accessory/snouts/mam_snouts/fshark
name = "Shark (Top)"
icon_state = "fshark"
-/datum/sprite_accessory/mam_snouts/ftoucan
+/datum/sprite_accessory/snouts/mam_snouts/ftoucan
name = "Toucan (Top)"
icon_state = "ftoucan"
-/datum/sprite_accessory/mam_snouts/fsharp
+/datum/sprite_accessory/snouts/mam_snouts/fsharp
name = "Sharp (Top)"
icon_state = "fsharp"
color_src = MUTCOLORS
-/datum/sprite_accessory/mam_snouts/fround
+/datum/sprite_accessory/snouts/mam_snouts/fround
name = "Round (Top)"
icon_state = "fround"
color_src = MUTCOLORS
-/datum/sprite_accessory/mam_snouts/fsharplight
+/datum/sprite_accessory/snouts/mam_snouts/fsharplight
name = "Sharp + Light (Top)"
icon_state = "fsharplight"
color_src = MUTCOLORS
-/datum/sprite_accessory/mam_snouts/froundlight
+/datum/sprite_accessory/snouts/mam_snouts/froundlight
name = "Round + Light (Top)"
icon_state = "froundlight"
color_src = MUTCOLORS
diff --git a/code/modules/mob/dead/new_player/sprite_accessories/spines.dm b/code/modules/mob/dead/new_player/sprite_accessories/spines.dm
index 54749d5ea9..83415ed375 100644
--- a/code/modules/mob/dead/new_player/sprite_accessories/spines.dm
+++ b/code/modules/mob/dead/new_player/sprite_accessories/spines.dm
@@ -2,10 +2,16 @@
icon = 'icons/mob/mutant_bodyparts.dmi'
relevant_layers = list(BODY_BEHIND_LAYER, BODY_ADJ_LAYER)
+/datum/sprite_accessory/spines/is_not_visible(var/mob/living/carbon/human/H, var/tauric)
+ return (!H.dna.features["spines"] || H.dna.features["spines"] == "None" || H.wear_suit && (H.wear_suit.flags_inv & HIDETAUR))
+
/datum/sprite_accessory/spines_animated
icon = 'icons/mob/mutant_bodyparts.dmi'
relevant_layers = list(BODY_BEHIND_LAYER, BODY_ADJ_LAYER)
+/datum/sprite_accessory/spines_animated/is_not_visible(var/mob/living/carbon/human/H, var/tauric)
+ return ((!H.dna.features["spines"] || H.dna.features["spines"] == "None" || H.wear_suit && (H.wear_suit.flags_inv & HIDETAUR)) || H.dna.species.mutant_bodyparts["tail"])
+
/datum/sprite_accessory/spines/none
name = "None"
icon_state = "none"
diff --git a/code/modules/mob/dead/new_player/sprite_accessories/synthliz.dm b/code/modules/mob/dead/new_player/sprite_accessories/synthliz.dm
index a2884ab944..16531d8f06 100644
--- a/code/modules/mob/dead/new_player/sprite_accessories/synthliz.dm
+++ b/code/modules/mob/dead/new_player/sprite_accessories/synthliz.dm
@@ -1,24 +1,24 @@
//Synth snouts (This is the most important part)
-/datum/sprite_accessory/mam_snouts/synthliz
+/datum/sprite_accessory/snouts/mam_snouts/synthliz
recommended_species = list("synthliz")
icon = 'modular_citadel/icons/mob/synthliz_snouts.dmi'
color_src = MUTCOLORS
name = "Synthetic Lizard - Snout"
icon_state = "synthliz_basic"
-/datum/sprite_accessory/mam_snouts/synthliz/synthliz_under
+/datum/sprite_accessory/snouts/mam_snouts/synthliz/synthliz_under
icon = 'modular_citadel/icons/mob/synthliz_snouts.dmi'
color_src = MATRIXED
name = "Synthetic Lizard - Snout Under"
icon_state = "synthliz_under"
-/datum/sprite_accessory/mam_snouts/synthliz/synthliz_tert
+/datum/sprite_accessory/snouts/mam_snouts/synthliz/synthliz_tert
icon = 'modular_citadel/icons/mob/synthliz_snouts.dmi'
color_src = MATRIXED
name = "Synthetic Lizard - Snout Tertiary"
icon_state = "synthliz_tert"
-/datum/sprite_accessory/mam_snouts/synthliz/synthliz_tertunder
+/datum/sprite_accessory/snouts/mam_snouts/synthliz/synthliz_tertunder
icon = 'modular_citadel/icons/mob/synthliz_snouts.dmi'
color_src = MATRIXED
name = "Synthetic Lizard - Snout Tertiary Under"
@@ -42,14 +42,14 @@
icon_state = "synthlizpecslight"
//Synth tails
-/datum/sprite_accessory/mam_tails/synthliz
+/datum/sprite_accessory/tails/mam_tails/synthliz
recommended_species = list("synthliz")
icon = 'modular_citadel/icons/mob/synthliz_tails.dmi'
color_src = MUTCOLORS
name = "Synthetic Lizard"
icon_state = "synthliz"
-/datum/sprite_accessory/mam_tails_animated/synthliz
+/datum/sprite_accessory/tails_animated/mam_tails_animated/synthliz
recommended_species = list("synthliz")
icon = 'modular_citadel/icons/mob/synthliz_tails.dmi'
color_src = MUTCOLORS
diff --git a/code/modules/mob/dead/new_player/sprite_accessories/tails.dm b/code/modules/mob/dead/new_player/sprite_accessories/tails.dm
index 33dbd7059f..812e0c052c 100644
--- a/code/modules/mob/dead/new_player/sprite_accessories/tails.dm
+++ b/code/modules/mob/dead/new_player/sprite_accessories/tails.dm
@@ -3,6 +3,9 @@
mutant_part_string = "tail"
relevant_layers = list(BODY_BEHIND_LAYER, BODY_FRONT_LAYER)
+/datum/sprite_accessory/tails/is_not_visible(var/mob/living/carbon/human/H, var/tauric)
+ return ((H.wear_suit && (H.wear_suit.flags_inv & HIDETAUR)) || tauric)
+
/datum/sprite_accessory/tails_animated
icon = 'icons/mob/mutant_bodyparts.dmi'
mutant_part_string = "tailwag"
@@ -12,6 +15,9 @@
************* Lizard Tails ****************
*******************************************/
+/datum/sprite_accessory/tails_animated/lizard/is_not_visible(var/mob/living/carbon/human/H, var/tauric)
+ return (((H.wear_suit && (H.wear_suit.flags_inv & HIDETAUR)) || tauric) || H.dna.species.mutant_bodyparts["tail_lizard"])
+
/datum/sprite_accessory/tails/lizard/smooth
name = "Smooth"
icon_state = "smooth"
@@ -98,6 +104,9 @@
icon_state = "none"
relevant_layers = null
+/datum/sprite_accessory/tails_animated/human/is_not_visible(var/mob/living/carbon/human/H, var/tauric)
+ return (((H.wear_suit && (H.wear_suit.flags_inv & HIDETAUR)) || tauric)|| H.dna.species.mutant_bodyparts["tail_human"])
+
/datum/sprite_accessory/tails/human/ailurus
name = "Red Panda"
icon_state = "wah"
@@ -122,22 +131,22 @@
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
color_src = MATRIXED
-/datum/sprite_accessory/mam_tails/batl
+/datum/sprite_accessory/tails/mam_tails/batl
name = "Bat (Long)"
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
icon_state = "batl"
-/datum/sprite_accessory/mam_tails_animated/batl
+/datum/sprite_accessory/tails_animated/mam_tails_animated/batl
name = "Bat (Long)"
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
icon_state = "batl"
-/datum/sprite_accessory/mam_tails/bats
+/datum/sprite_accessory/tails/mam_tails/bats
name = "Bat (Short)"
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
icon_state = "bats"
-/datum/sprite_accessory/mam_tails_animated/bats
+/datum/sprite_accessory/tails_animated/mam_tails_animated/bats
name = "Bat (Short)"
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
icon_state = "bats"
@@ -518,368 +527,371 @@
************** Furry Tails ****************
*******************************************/
-/datum/sprite_accessory/mam_tails
+/datum/sprite_accessory/tails/mam_tails
color_src = MATRIXED
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
recommended_species = list("mammal", "slimeperson", "podweak", "felinid", "insect")
mutant_part_string = "tail"
relevant_layers = list(BODY_BEHIND_LAYER, BODY_FRONT_LAYER)
-/datum/sprite_accessory/mam_tails/none
+/datum/sprite_accessory/tails/mam_tails/none
name = "None"
icon_state = "none"
recommended_species = null
relevant_layers = null
-/datum/sprite_accessory/mam_tails_animated
+/datum/sprite_accessory/tails_animated/mam_tails_animated
color_src = MATRIXED
icon = 'modular_citadel/icons/mob/mam_tails.dmi'
mutant_part_string = "tailwag"
relevant_layers = list(BODY_BEHIND_LAYER, BODY_FRONT_LAYER)
-/datum/sprite_accessory/mam_tails_animated/none
+/datum/sprite_accessory/tails_animated/mam_tails_animated/is_not_visible(var/mob/living/carbon/human/H, var/tauric)
+ return (((H.wear_suit && (H.wear_suit.flags_inv & HIDETAUR)) || tauric) || H.dna.species.mutant_bodyparts["mam_tail"])
+
+/datum/sprite_accessory/tails_animated/mam_tails_animated/none
name = "None"
icon_state = "none"
relevant_layers = null
-/datum/sprite_accessory/mam_tails/ailurus
+/datum/sprite_accessory/tails/mam_tails/ailurus
name = "Red Panda"
icon_state = "wah"
extra = TRUE
-/datum/sprite_accessory/mam_tails_animated/ailurus
+/datum/sprite_accessory/tails_animated/mam_tails_animated/ailurus
name = "Red Panda"
icon_state = "wah"
extra = TRUE
-/datum/sprite_accessory/mam_tails/axolotl
+/datum/sprite_accessory/tails/mam_tails/axolotl
name = "Axolotl"
icon_state = "axolotl"
-/datum/sprite_accessory/mam_tails_animated/axolotl
+/datum/sprite_accessory/tails_animated/mam_tails_animated/axolotl
name = "Axolotl"
icon_state = "axolotl"
-/datum/sprite_accessory/mam_tails/batl
+/datum/sprite_accessory/tails/mam_tails/batl
name = "Bat (Long)"
icon_state = "batl"
-/datum/sprite_accessory/mam_tails_animated/batl
+/datum/sprite_accessory/tails_animated/mam_tails_animated/batl
name = "Bat (Long)"
icon_state = "batl"
-/datum/sprite_accessory/mam_tails/bats
+/datum/sprite_accessory/tails/mam_tails/bats
name = "Bat (Short)"
icon_state = "bats"
-/datum/sprite_accessory/mam_tails_animated/bats
+/datum/sprite_accessory/tails_animated/mam_tails_animated/bats
name = "Bat (Short)"
icon_state = "bats"
-/datum/sprite_accessory/mam_tails/bee
+/datum/sprite_accessory/tails/mam_tails/bee
name = "Bee"
icon_state = "bee"
-/datum/sprite_accessory/mam_tails_animated/bee
+/datum/sprite_accessory/tails_animated/mam_tails_animated/bee
name = "Bee"
icon_state = "bee"
-/datum/sprite_accessory/mam_tails/cat
+/datum/sprite_accessory/tails/mam_tails/cat
name = "Cat"
icon_state = "cat"
color_src = HAIR
-/datum/sprite_accessory/mam_tails_animated/cat
+/datum/sprite_accessory/tails_animated/mam_tails_animated/cat
name = "Cat"
icon_state = "cat"
color_src = HAIR
-/datum/sprite_accessory/mam_tails/catbig
+/datum/sprite_accessory/tails/mam_tails/catbig
name = "Cat, Big"
icon_state = "catbig"
-/datum/sprite_accessory/mam_tails_animated/catbig
+/datum/sprite_accessory/tails_animated/mam_tails_animated/catbig
name = "Cat, Big"
icon_state = "catbig"
-/datum/sprite_accessory/mam_tails/twocat
+/datum/sprite_accessory/tails/mam_tails/twocat
name = "Cat, Double"
icon_state = "twocat"
-/datum/sprite_accessory/mam_tails_animated/twocat
+/datum/sprite_accessory/tails_animated/mam_tails_animated/twocat
name = "Cat, Double"
icon_state = "twocat"
-/datum/sprite_accessory/mam_tails/corvid
+/datum/sprite_accessory/tails/mam_tails/corvid
name = "Corvid"
icon_state = "crow"
-/datum/sprite_accessory/mam_tails_animated/corvid
+/datum/sprite_accessory/tails_animated/mam_tails_animated/corvid
name = "Corvid"
icon_state = "crow"
-/datum/sprite_accessory/mam_tail/cow
+/datum/sprite_accessory/tails/mam_tail/cow
name = "Cow"
icon_state = "cow"
-/datum/sprite_accessory/mam_tails_animated/cow
+/datum/sprite_accessory/tails_animated/mam_tails_animated/cow
name = "Cow"
icon_state = "cow"
-/datum/sprite_accessory/mam_tails/eevee
+/datum/sprite_accessory/tails/mam_tails/eevee
name = "Eevee"
icon_state = "eevee"
-/datum/sprite_accessory/mam_tails_animated/eevee
+/datum/sprite_accessory/tails_animated/mam_tails_animated/eevee
name = "Eevee"
icon_state = "eevee"
-/datum/sprite_accessory/mam_tails/fennec
+/datum/sprite_accessory/tails/mam_tails/fennec
name = "Fennec"
icon_state = "fennec"
-/datum/sprite_accessory/mam_tails_animated/fennec
+/datum/sprite_accessory/tails_animated/mam_tails_animated/fennec
name = "Fennec"
icon_state = "fennec"
-/datum/sprite_accessory/mam_tails/human/fish
+/datum/sprite_accessory/tails/mam_tails/human/fish
name = "Fish"
icon_state = "fish"
-/datum/sprite_accessory/mam_tails_animated/human/fish
+/datum/sprite_accessory/tails_animated/mam_tails_animated/human/fish
name = "Fish"
icon_state = "fish"
-/datum/sprite_accessory/mam_tails/fox
+/datum/sprite_accessory/tails/mam_tails/fox
name = "Fox"
icon_state = "fox"
-/datum/sprite_accessory/mam_tails_animated/fox
+/datum/sprite_accessory/tails_animated/mam_tails_animated/fox
name = "Fox"
icon_state = "fox"
-/datum/sprite_accessory/mam_tails/hawk
+/datum/sprite_accessory/tails/mam_tails/hawk
name = "Hawk"
icon_state = "hawk"
-/datum/sprite_accessory/mam_tails_animated/hawk
+/datum/sprite_accessory/tails_animated/mam_tails_animated/hawk
name = "Hawk"
icon_state = "hawk"
-/datum/sprite_accessory/mam_tails/horse
+/datum/sprite_accessory/tails/mam_tails/horse
name = "Horse"
icon_state = "horse"
color_src = HAIR
-/datum/sprite_accessory/mam_tails_animated/horse
+/datum/sprite_accessory/tails_animated/mam_tails_animated/horse
name = "Horse"
icon_state = "horse"
color_src = HAIR
-/datum/sprite_accessory/mam_tails/husky
+/datum/sprite_accessory/tails/mam_tails/husky
name = "Husky"
icon_state = "husky"
-/datum/sprite_accessory/mam_tails_animated/husky
+/datum/sprite_accessory/tails_animated/mam_tails_animated/husky
name = "Husky"
icon_state = "husky"
-datum/sprite_accessory/mam_tails/insect
+datum/sprite_accessory/tails/mam_tails/insect
name = "Insect"
icon_state = "insect"
-/datum/sprite_accessory/mam_tails_animated/insect
+/datum/sprite_accessory/tails_animated/mam_tails_animated/insect
name = "Insect"
icon_state = "insect"
-/datum/sprite_accessory/mam_tails/kangaroo
+/datum/sprite_accessory/tails/mam_tails/kangaroo
name = "kangaroo"
icon_state = "kangaroo"
-/datum/sprite_accessory/mam_tails_animated/kangaroo
+/datum/sprite_accessory/tails_animated/mam_tails_animated/kangaroo
name = "kangaroo"
icon_state = "kangaroo"
-/datum/sprite_accessory/mam_tails/kitsune
+/datum/sprite_accessory/tails/mam_tails/kitsune
name = "Kitsune"
icon_state = "kitsune"
-/datum/sprite_accessory/mam_tails_animated/kitsune
+/datum/sprite_accessory/tails_animated/mam_tails_animated/kitsune
name = "Kitsune"
icon_state = "kitsune"
-/datum/sprite_accessory/mam_tails/lab
+/datum/sprite_accessory/tails/mam_tails/lab
name = "Lab"
icon_state = "lab"
-/datum/sprite_accessory/mam_tails_animated/lab
+/datum/sprite_accessory/tails_animated/mam_tails_animated/lab
name = "Lab"
icon_state = "lab"
-/datum/sprite_accessory/mam_tails/murid
+/datum/sprite_accessory/tails/mam_tails/murid
name = "Murid"
icon_state = "murid"
-/datum/sprite_accessory/mam_tails_animated/murid
+/datum/sprite_accessory/tails_animated/mam_tails_animated/murid
name = "Murid"
icon_state = "murid"
-/datum/sprite_accessory/mam_tails/otie
+/datum/sprite_accessory/tails/mam_tails/otie
name = "Otusian"
icon_state = "otie"
-/datum/sprite_accessory/mam_tails_animated/otie
+/datum/sprite_accessory/tails_animated/mam_tails_animated/otie
name = "Otusian"
icon_state = "otie"
-/datum/sprite_accessory/mam_tails/orca
+/datum/sprite_accessory/tails/mam_tails/orca
name = "Orca"
icon_state = "orca"
-/datum/sprite_accessory/mam_tails_animated/orca
+/datum/sprite_accessory/tails_animated/mam_tails_animated/orca
name = "Orca"
icon_state = "orca"
-/datum/sprite_accessory/mam_tails/pede
+/datum/sprite_accessory/tails/mam_tails/pede
name = "Scolipede"
icon_state = "pede"
-/datum/sprite_accessory/mam_tails_animated/pede
+/datum/sprite_accessory/tails_animated/mam_tails_animated/pede
name = "Scolipede"
icon_state = "pede"
-/datum/sprite_accessory/mam_tails/rabbit
+/datum/sprite_accessory/tails/mam_tails/rabbit
name = "Rabbit"
icon_state = "rabbit"
-/datum/sprite_accessory/mam_tails_animated/rabbit
+/datum/sprite_accessory/tails_animated/mam_tails_animated/rabbit
name = "Rabbit"
icon_state = "rabbit"
-/datum/sprite_accessory/mam_tails/sergal
+/datum/sprite_accessory/tails/mam_tails/sergal
name = "Sergal"
icon_state = "sergal"
-/datum/sprite_accessory/mam_tails_animated/sergal
+/datum/sprite_accessory/tails_animated/mam_tails_animated/sergal
name = "Sergal"
icon_state = "sergal"
-/datum/sprite_accessory/mam_tails/skunk
+/datum/sprite_accessory/tails/mam_tails/skunk
name = "Skunk"
icon_state = "skunk"
-/datum/sprite_accessory/mam_tails_animated/skunk
+/datum/sprite_accessory/tails_animated/mam_tails_animated/skunk
name = "Skunk"
icon_state = "skunk"
-/datum/sprite_accessory/mam_tails/smooth
+/datum/sprite_accessory/tails/mam_tails/smooth
name = "Smooth"
icon_state = "smooth"
color_src = MUTCOLORS
icon = 'icons/mob/mutant_bodyparts.dmi'
-/datum/sprite_accessory/mam_tails_animated/smooth
+/datum/sprite_accessory/tails_animated/mam_tails_animated/smooth
name = "Smooth"
icon_state = "smooth"
color_src = MUTCOLORS
icon = 'icons/mob/mutant_bodyparts.dmi'
-/datum/sprite_accessory/mam_tails_animated/spikes
+/datum/sprite_accessory/tails_animated/mam_tails_animated/spikes
name = "Spikes"
icon_state = "spikes"
color_src = MUTCOLORS
icon = 'icons/mob/mutant_bodyparts.dmi'
-/datum/sprite_accessory/mam_tails/spikes
+/datum/sprite_accessory/tails/mam_tails/spikes
name = "Spikes"
icon_state = "spikes"
color_src = MUTCOLORS
icon = 'icons/mob/mutant_bodyparts.dmi'
-/datum/sprite_accessory/mam_tails/shark
+/datum/sprite_accessory/tails/mam_tails/shark
name = "Shark"
icon_state = "shark"
-/datum/sprite_accessory/mam_tails_animated/shark
+/datum/sprite_accessory/tails_animated/mam_tails_animated/shark
name = "Shark"
icon_state = "shark"
-/datum/sprite_accessory/mam_tails/shepherd
+/datum/sprite_accessory/tails/mam_tails/shepherd
name = "Shepherd"
icon_state = "shepherd"
-/datum/sprite_accessory/mam_tails_animated/shepherd
+/datum/sprite_accessory/tails_animated/mam_tails_animated/shepherd
name = "Shepherd"
icon_state = "shepherd"
-/datum/sprite_accessory/mam_tails/straighttail
+/datum/sprite_accessory/tails/mam_tails/straighttail
name = "Straight Tail"
icon_state = "straighttail"
-/datum/sprite_accessory/mam_tails_animated/straighttail
+/datum/sprite_accessory/tails_animated/mam_tails_animated/straighttail
name = "Straight Tail"
icon_state = "straighttail"
-/datum/sprite_accessory/mam_tails/squirrel
+/datum/sprite_accessory/tails/mam_tails/squirrel
name = "Squirrel"
icon_state = "squirrel"
-/datum/sprite_accessory/mam_tails_animated/squirrel
+/datum/sprite_accessory/tails_animated/mam_tails_animated/squirrel
name = "Squirrel"
icon_state = "squirrel"
-/datum/sprite_accessory/mam_tails/tamamo_kitsune
+/datum/sprite_accessory/tails/mam_tails/tamamo_kitsune
name = "Tamamo Kitsune Tails"
icon_state = "9sune"
-/datum/sprite_accessory/mam_tails_animated/tamamo_kitsune
+/datum/sprite_accessory/tails_animated/mam_tails_animated/tamamo_kitsune
name = "Tamamo Kitsune Tails"
icon_state = "9sune"
-/datum/sprite_accessory/mam_tails/tentacle
+/datum/sprite_accessory/tails/mam_tails/tentacle
name = "Tentacle"
icon_state = "tentacle"
-/datum/sprite_accessory/mam_tails_animated/tentacle
+/datum/sprite_accessory/tails_animated/mam_tails_animated/tentacle
name = "Tentacle"
icon_state = "tentacle"
-/datum/sprite_accessory/mam_tails/tiger
+/datum/sprite_accessory/tails/mam_tails/tiger
name = "Tiger"
icon_state = "tiger"
-/datum/sprite_accessory/mam_tails_animated/tiger
+/datum/sprite_accessory/tails_animated/mam_tails_animated/tiger
name = "Tiger"
icon_state = "tiger"
-/datum/sprite_accessory/mam_tails/dtiger
+/datum/sprite_accessory/tails/mam_tails/dtiger
name = "Dark Tiger"
icon_state = "dtiger"
color_src = MUTCOLORS
icon = 'icons/mob/mutant_bodyparts.dmi'
-/datum/sprite_accessory/mam_tails_animated/dtiger
+/datum/sprite_accessory/tails_animated/mam_tails_animated/dtiger
name = "Dark Tiger"
icon_state = "dtiger"
color_src = MUTCOLORS
icon = 'icons/mob/mutant_bodyparts.dmi'
-/datum/sprite_accessory/mam_tails/ltiger
+/datum/sprite_accessory/tails/mam_tails/ltiger
name = "Light Tiger"
icon_state = "ltiger"
color_src = MUTCOLORS
icon = 'icons/mob/mutant_bodyparts.dmi'
-/datum/sprite_accessory/mam_tails_animated/ltiger
+/datum/sprite_accessory/tails_animated/mam_tails_animated/ltiger
name = "Light Tiger"
icon_state = "ltiger"
color_src = MUTCOLORS
icon = 'icons/mob/mutant_bodyparts.dmi'
-/datum/sprite_accessory/mam_tails/wolf
+/datum/sprite_accessory/tails/mam_tails/wolf
name = "Wolf"
icon_state = "wolf"
-/datum/sprite_accessory/mam_tails_animated/wolf
+/datum/sprite_accessory/tails_animated/mam_tails_animated/wolf
name = "Wolf"
icon_state = "wolf"
diff --git a/code/modules/mob/dead/new_player/sprite_accessories/undershirt.dm b/code/modules/mob/dead/new_player/sprite_accessories/undershirt.dm
index 73233f3e09..b8282931d2 100644
--- a/code/modules/mob/dead/new_player/sprite_accessories/undershirt.dm
+++ b/code/modules/mob/dead/new_player/sprite_accessories/undershirt.dm
@@ -348,6 +348,12 @@
name = "Cowboy Shirt Shortsleeved Red"
icon_state = "cowboyshirt_reds"
+/datum/sprite_accessory/underwear/top/bra_binder
+ name = "Bra (binder)"
+ icon_state = "bra_binder"
+ has_color = TRUE
-
-
+/datum/sprite_accessory/underwear/top/bra_binder_strapless
+ name = "Bra (binder, strapless)"
+ icon_state = "bra_binder_strapless"
+ has_color = TRUE
diff --git a/code/modules/mob/dead/new_player/sprite_accessories/wings.dm b/code/modules/mob/dead/new_player/sprite_accessories/wings.dm
index 34767a10f1..fb03df88a1 100644
--- a/code/modules/mob/dead/new_player/sprite_accessories/wings.dm
+++ b/code/modules/mob/dead/new_player/sprite_accessories/wings.dm
@@ -5,10 +5,16 @@
icon_state = "none"
relevant_layers = null
+/datum/sprite_accessory/wings/is_not_visible(var/mob/living/carbon/human/H, var/tauric)
+ return (!H.dna.features["wings"] || H.dna.features["wings"] == "None" || (H.wear_suit && (H.wear_suit.flags_inv & HIDEJUMPSUIT) && (!H.wear_suit.species_exception || !is_type_in_list(src, H.wear_suit.species_exception))))
+
/datum/sprite_accessory/wings_open
icon = 'icons/mob/wings.dmi'
relevant_layers = list(BODY_BEHIND_LAYER, BODY_ADJ_LAYER, BODY_FRONT_LAYER)
+/datum/sprite_accessory/wings_open/is_not_visible(var/mob/living/carbon/human/H, var/tauric)
+ return (H.wear_suit && (H.wear_suit.flags_inv & HIDEJUMPSUIT) && (!H.wear_suit.species_exception || !is_type_in_list(src, H.wear_suit.species_exception)) || H.dna.species.mutant_bodyparts["wings"])
+
/datum/sprite_accessory/wings_open/angel
name = "Angel"
icon_state = "angel"
diff --git a/code/modules/mob/inventory.dm b/code/modules/mob/inventory.dm
index caebb9cf10..9ac270bf34 100644
--- a/code/modules/mob/inventory.dm
+++ b/code/modules/mob/inventory.dm
@@ -382,10 +382,20 @@
return 0
-//Outdated but still in use apparently. This should at least be a human proc.
-//Daily reminder to murder this - Remie.
+/**
+ * Used to return a list of equipped items on a mob; does not include held items (use get_all_gear)
+ *
+ * Argument(s):
+ * * Optional - include_pockets (TRUE/FALSE), whether or not to include the pockets and suit storage in the returned list
+ */
+
/mob/living/proc/get_equipped_items(include_pockets = FALSE)
- return
+ var/list/items = list()
+ for(var/obj/item/I in contents)
+ if(I.item_flags & IN_INVENTORY)
+ items += I
+ items -= held_items
+ return items
/mob/living/proc/unequip_everything()
var/list/items = list()
@@ -476,5 +486,19 @@
hand_bodyparts[i] = BP
..() //Don't redraw hands until we have organs for them
+
+//GetAllContents that is reasonable and not stupid
+/mob/living/carbon/proc/get_all_gear()
+ var/list/processing_list = get_equipped_items(include_pockets = TRUE) + held_items
+ listclearnulls(processing_list) // handles empty hands
+ var/i = 0
+ while(i < length(processing_list) )
+ var/atom/A = processing_list[++i]
+ if(SEND_SIGNAL(A, COMSIG_CONTAINS_STORAGE))
+ var/list/item_stuff = list()
+ SEND_SIGNAL(A, COMSIG_TRY_STORAGE_RETURN_INVENTORY, item_stuff)
+ processing_list += item_stuff
+ return processing_list
+
/mob/canReachInto(atom/user, atom/target, list/next, view_only, obj/item/tool)
return ..() && (user == src)
diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm
index de4b7a659f..18501b4ca2 100644
--- a/code/modules/mob/living/carbon/human/human_defense.dm
+++ b/code/modules/mob/living/carbon/human/human_defense.dm
@@ -299,10 +299,10 @@
/mob/living/carbon/human/ex_act(severity, target, origin)
- if(origin && istype(origin, /datum/spacevine_mutation) && isvineimmune(src))
+ if(TRAIT_BOMBIMMUNE in dna.species.species_traits)
return
..()
- if (!severity)
+ if (!severity || QDELETED(src))
return
var/brute_loss = 0
var/burn_loss = 0
diff --git a/code/modules/mob/living/carbon/human/inventory.dm b/code/modules/mob/living/carbon/human/inventory.dm
index 1c776427cf..523369d10a 100644
--- a/code/modules/mob/living/carbon/human/inventory.dm
+++ b/code/modules/mob/living/carbon/human/inventory.dm
@@ -1,31 +1,17 @@
/mob/living/carbon/human/can_equip(obj/item/I, slot, disable_warning = FALSE, bypass_equip_delay_self = FALSE, clothing_check = FALSE, list/return_warning)
return dna.species.can_equip(I, slot, disable_warning, src, bypass_equip_delay_self, clothing_check, return_warning)
+/**
+ * Used to return a list of equipped items on a human mob; does not include held items (use get_all_gear)
+ *
+ * Argument(s):
+ * * Optional - include_pockets (TRUE/FALSE), whether or not to include the pockets and suit storage in the returned list
+ */
+
/mob/living/carbon/human/get_equipped_items(include_pockets = FALSE)
var/list/items = ..()
- if(belt)
- items += belt
- if(ears)
- items += ears
- if(glasses)
- items += glasses
- if(gloves)
- items += gloves
- if(shoes)
- items += shoes
- if(wear_id)
- items += wear_id
- if(wear_suit)
- items += wear_suit
- if(w_uniform)
- items += w_uniform
- if(include_pockets)
- if(l_store)
- items += l_store
- if(r_store)
- items += r_store
- if(s_store)
- items += s_store
+ if(!include_pockets)
+ items -= list(l_store, r_store, s_store)
return items
// Return the item currently in the slot ID
diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm
index 54c3b314b9..230a634e0e 100644
--- a/code/modules/mob/living/carbon/human/species.dm
+++ b/code/modules/mob/living/carbon/human/species.dm
@@ -124,6 +124,9 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
limbs_id = id
..()
+ //update our mutant bodyparts to include unlocked ones
+ mutant_bodyparts += GLOB.unlocked_mutant_parts
+
/proc/generate_selectable_species(clear = FALSE)
if(clear)
GLOB.roundstart_races = list()
@@ -639,106 +642,19 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
if(!mutant_bodyparts)
return
- var/obj/item/bodypart/head/HD = H.get_bodypart(BODY_ZONE_HEAD)
var/tauric = mutant_bodyparts["taur"] && H.dna.features["taur"] && H.dna.features["taur"] != "None"
- if(mutant_bodyparts["tail_lizard"])
- if((H.wear_suit && (H.wear_suit.flags_inv & HIDETAUR)) || tauric)
- bodyparts_to_add -= "tail_lizard"
-
- if(mutant_bodyparts["waggingtail_lizard"])
- if((H.wear_suit && (H.wear_suit.flags_inv & HIDETAUR)) || tauric)
- bodyparts_to_add -= "waggingtail_lizard"
- else if (mutant_bodyparts["tail_lizard"])
- bodyparts_to_add -= "waggingtail_lizard"
-
- if(mutant_bodyparts["tail_human"])
- if((H.wear_suit && (H.wear_suit.flags_inv & HIDETAUR)) || tauric)
- bodyparts_to_add -= "tail_human"
-
- if(mutant_bodyparts["waggingtail_human"])
- if((H.wear_suit && (H.wear_suit.flags_inv & HIDETAUR)) || tauric)
- bodyparts_to_add -= "waggingtail_human"
- else if (mutant_bodyparts["tail_human"])
- bodyparts_to_add -= "waggingtail_human"
-
- if(mutant_bodyparts["spines"])
- if(!H.dna.features["spines"] || H.dna.features["spines"] == "None" || H.wear_suit && (H.wear_suit.flags_inv & HIDETAUR))
- bodyparts_to_add -= "spines"
-
- if(mutant_bodyparts["waggingspines"])
- if(!H.dna.features["spines"] || H.dna.features["spines"] == "None" || H.wear_suit && (H.wear_suit.flags_inv & HIDETAUR))
- bodyparts_to_add -= "waggingspines"
- else if (mutant_bodyparts["tail"])
- bodyparts_to_add -= "waggingspines"
-
- if(mutant_bodyparts["snout"]) //Take a closer look at that snout!
- if((H.wear_mask && (H.wear_mask.flags_inv & HIDESNOUT)) || (H.head && (H.head.flags_inv & HIDESNOUT)) || !HD || HD.status == BODYPART_ROBOTIC)
- bodyparts_to_add -= "snout"
-
- if(mutant_bodyparts["frills"])
- if(!H.dna.features["frills"] || H.dna.features["frills"] == "None" || H.head && (H.head.flags_inv & HIDEEARS) || !HD || HD.status == BODYPART_ROBOTIC)
- bodyparts_to_add -= "frills"
-
- if(mutant_bodyparts["horns"])
- if(!H.dna.features["horns"] || H.dna.features["horns"] == "None" || H.head && (H.head.flags_inv & HIDEHAIR) || (H.wear_mask && (H.wear_mask.flags_inv & HIDEHAIR)) || !HD || HD.status == BODYPART_ROBOTIC)
- bodyparts_to_add -= "horns"
-
- if(mutant_bodyparts["ears"])
- if(!H.dna.features["ears"] || H.dna.features["ears"] == "None" || H.head && (H.head.flags_inv & HIDEEARS) || (H.wear_mask && (H.wear_mask.flags_inv & HIDEEARS)) || !HD || HD.status == BODYPART_ROBOTIC)
- bodyparts_to_add -= "ears"
-
- if(mutant_bodyparts["wings"])
- if(!H.dna.features["wings"] || H.dna.features["wings"] == "None" || (H.wear_suit && (H.wear_suit.flags_inv & HIDEJUMPSUIT) && (!H.wear_suit.species_exception || !is_type_in_list(src, H.wear_suit.species_exception))))
- bodyparts_to_add -= "wings"
-
- if(mutant_bodyparts["wings_open"])
- if(H.wear_suit && (H.wear_suit.flags_inv & HIDEJUMPSUIT) && (!H.wear_suit.species_exception || !is_type_in_list(src, H.wear_suit.species_exception)))
- bodyparts_to_add -= "wings_open"
- else if (mutant_bodyparts["wings"])
- bodyparts_to_add -= "wings_open"
-
- if(mutant_bodyparts["insect_fluff"])
- if(!H.dna.features["insect_fluff"] || H.dna.features["insect_fluff"] == "None" || H.wear_suit && (H.wear_suit.flags_inv & HIDEJUMPSUIT))
- bodyparts_to_add -= "insect_fluff"
-
-//CITADEL EDIT
- //Race specific bodyparts:
- //Xenos
- if(mutant_bodyparts["xenodorsal"])
- if(!H.dna.features["xenodorsal"] || H.dna.features["xenodorsal"] == "None" || (H.wear_suit && (H.wear_suit.flags_inv & HIDEJUMPSUIT)))
- bodyparts_to_add -= "xenodorsal"
- if(mutant_bodyparts["xenohead"])//This is an overlay for different castes using different head crests
- if(!H.dna.features["xenohead"] || H.dna.features["xenohead"] == "None" || H.head && (H.head.flags_inv & HIDEHAIR) || (H.wear_mask && (H.wear_mask.flags_inv & HIDEHAIR)) || !HD || HD.status == BODYPART_ROBOTIC)
- bodyparts_to_add -= "xenohead"
- if(mutant_bodyparts["xenotail"])
- if(!H.dna.features["xenotail"] || H.dna.features["xenotail"] == "None" || H.wear_suit && (H.wear_suit.flags_inv & HIDEJUMPSUIT))
- bodyparts_to_add -= "xenotail"
-
- //Other Races
- if(mutant_bodyparts["mam_tail"])
- if((H.wear_suit && (H.wear_suit.flags_inv & HIDETAUR)) || tauric)
- bodyparts_to_add -= "mam_tail"
-
- if(mutant_bodyparts["mam_waggingtail"])
- if((H.wear_suit && (H.wear_suit.flags_inv & HIDETAUR)) || tauric)
- bodyparts_to_add -= "mam_waggingtail"
- else if (mutant_bodyparts["mam_tail"])
- bodyparts_to_add -= "mam_waggingtail"
-
- if(mutant_bodyparts["mam_ears"])
- if(!H.dna.features["mam_ears"] || H.dna.features["mam_ears"] == "None" || H.head && (H.head.flags_inv & HIDEEARS) || (H.wear_mask && (H.wear_mask.flags_inv & HIDEEARS)) || !HD || HD.status == BODYPART_ROBOTIC)
- bodyparts_to_add -= "mam_ears"
-
- if(mutant_bodyparts["mam_snouts"]) //Take a closer look at that snout!
- if((H.wear_mask && (H.wear_mask.flags_inv & HIDESNOUT)) || (H.head && (H.head.flags_inv & HIDESNOUT)) || !HD || HD.status == BODYPART_ROBOTIC)
- bodyparts_to_add -= "mam_snouts"
-
- if(mutant_bodyparts["taur"])
- if(!tauric || (H.wear_suit && (H.wear_suit.flags_inv & HIDETAUR)))
- bodyparts_to_add -= "taur"
-
-//END EDIT
+ for(var/mutant_part in mutant_bodyparts)
+ var/reference_list = GLOB.mutant_reference_list[mutant_part]
+ if(reference_list)
+ var/datum/sprite_accessory/S
+ var/transformed_part = GLOB.mutant_transform_list[mutant_part]
+ if(transformed_part)
+ S = reference_list[H.dna.features[transformed_part]]
+ else
+ S = reference_list[H.dna.features[mutant_part]]
+ if(!S || S.is_not_visible(H, tauric))
+ bodyparts_to_add -= mutant_part
//Digitigrade legs are stuck in the phantom zone between true limbs and mutant bodyparts. Mainly it just needs more agressive updating than most limbs.
var/update_needed = FALSE
@@ -775,76 +691,22 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
var/list/dna_feature_as_text_string = list()
for(var/bodypart in bodyparts_to_add)
- var/datum/sprite_accessory/S
- switch(bodypart)
- if("tail_lizard")
- S = GLOB.tails_list_lizard[H.dna.features["tail_lizard"]]
- if("waggingtail_lizard")
- S = GLOB.animated_tails_list_lizard[H.dna.features["tail_lizard"]]
- if("tail_human")
- S = GLOB.tails_list_human[H.dna.features["tail_human"]]
- if("waggingtail_human")
- S = GLOB.animated_tails_list_human[H.dna.features["tail_human"]]
- if("spines")
- S = GLOB.spines_list[H.dna.features["spines"]]
- if("waggingspines")
- S = GLOB.animated_spines_list[H.dna.features["spines"]]
- if("snout")
- S = GLOB.snouts_list[H.dna.features["snout"]]
- if("frills")
- S = GLOB.frills_list[H.dna.features["frills"]]
- if("horns")
- S = GLOB.horns_list[H.dna.features["horns"]]
- if("ears")
- S = GLOB.ears_list[H.dna.features["ears"]]
- if("body_markings")
- S = GLOB.body_markings_list[H.dna.features["body_markings"]]
- if("wings")
- S = GLOB.wings_list[H.dna.features["wings"]]
- if("wingsopen")
- S = GLOB.wings_open_list[H.dna.features["wings"]]
- if("deco_wings")
- S = GLOB.deco_wings_list[H.dna.features["deco_wings"]]
- if("legs")
- S = GLOB.legs_list[H.dna.features["legs"]]
- if("insect_wings")
- S = GLOB.insect_wings_list[H.dna.features["insect_wings"]]
- if("insect_fluff")
- S = GLOB.insect_fluffs_list[H.dna.features["insect_fluff"]]
- if("insect_markings")
- S = GLOB.insect_markings_list[H.dna.features["insect_markings"]]
- if("caps")
- S = GLOB.caps_list[H.dna.features["caps"]]
- if("ipc_screen")
- S = GLOB.ipc_screens_list[H.dna.features["ipc_screen"]]
- if("ipc_antenna")
- S = GLOB.ipc_antennas_list[H.dna.features["ipc_antenna"]]
- if("mam_tail")
- S = GLOB.mam_tails_list[H.dna.features["mam_tail"]]
- if("mam_waggingtail")
- S = GLOB.mam_tails_animated_list[H.dna.features["mam_tail"]]
- if("mam_body_markings")
- S = GLOB.mam_body_markings_list[H.dna.features["mam_body_markings"]]
- if("mam_ears")
- S = GLOB.mam_ears_list[H.dna.features["mam_ears"]]
- if("mam_snouts")
- S = GLOB.mam_snouts_list[H.dna.features["mam_snouts"]]
- if("taur")
- S = GLOB.taur_list[H.dna.features["taur"]]
- if("xenodorsal")
- S = GLOB.xeno_dorsal_list[H.dna.features["xenodorsal"]]
- if("xenohead")
- S = GLOB.xeno_head_list[H.dna.features["xenohead"]]
- if("xenotail")
- S = GLOB.xeno_tail_list[H.dna.features["xenotail"]]
+ var/reference_list = GLOB.mutant_reference_list[bodypart]
+ if(reference_list)
+ var/datum/sprite_accessory/S
+ var/transformed_part = GLOB.mutant_transform_list[bodypart]
+ if(transformed_part)
+ S = reference_list[H.dna.features[transformed_part]]
+ else
+ S = reference_list[H.dna.features[bodypart]]
- if(!S || S.icon_state == "none")
- continue
+ if(!S || S.icon_state == "none")
+ continue
- for(var/L in S.relevant_layers)
- LAZYADD(relevant_layers["[L]"], S)
- if(!S.mutant_part_string)
- dna_feature_as_text_string[S] = bodypart
+ for(var/L in S.relevant_layers)
+ LAZYADD(relevant_layers["[L]"], S)
+ if(!S.mutant_part_string)
+ dna_feature_as_text_string[S] = bodypart
var/static/list/layer_text = list(
"[BODY_BEHIND_LAYER]" = "BEHIND",
@@ -2043,17 +1905,8 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
return
/**
-
-
-
* The human species version of [/mob/living/carbon/proc/get_biological_state]. Depends on the HAS_FLESH and HAS_BONE species traits, having bones lets you have bone wounds, having flesh lets you have burn, slash, and piercing wounds
-
-
-
*/
-
-
-
/datum/species/proc/get_biological_state(mob/living/carbon/human/H)
. = BIO_INORGANIC
if(HAS_FLESH in species_traits)
@@ -2069,7 +1922,6 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
if(HAS_TRAIT(H, TRAIT_NOBREATH))
return TRUE
-
/datum/species/proc/handle_environment(datum/gas_mixture/environment, mob/living/carbon/human/H)
if(!environment)
return
@@ -2261,7 +2113,6 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
/datum/species/proc/spec_stun(mob/living/carbon/human/H,amount)
if(H)
stop_wagging_tail(H)
-
. = stunmod * H.physiology.stun_mod * amount
//////////////
diff --git a/code/modules/mob/living/carbon/human/species_types/ethereal.dm b/code/modules/mob/living/carbon/human/species_types/ethereal.dm
index 27338f598f..cd9b3b80c7 100644
--- a/code/modules/mob/living/carbon/human/species_types/ethereal.dm
+++ b/code/modules/mob/living/carbon/human/species_types/ethereal.dm
@@ -14,7 +14,7 @@
brutemod = 1.25 //They're weak to punches
attack_type = BURN //burn bish
damage_overlay_type = "" //We are too cool for regular damage overlays
- species_traits = list(MUTCOLORS, NO_UNDERWEAR, HAIR, HAS_FLESH, HAS_BONE) // i mean i guess they have blood so they can have wounds too
+ species_traits = list(MUTCOLORS, HAIR, HAS_FLESH, HAS_BONE) // i mean i guess they have blood so they can have wounds too
species_language_holder = /datum/language_holder/ethereal
inherent_traits = list(TRAIT_NOHUNGER)
sexes = FALSE
@@ -27,7 +27,7 @@
// Cold temperatures hurt faster as it is harder to move with out the heat energy
bodytemp_cold_damage_limit = (T20C - 10) // about 10c
*/
- hair_color = "fixedmutcolor"
+ hair_color = "mutcolor"
hair_alpha = 140
var/current_color
var/EMPeffect = FALSE
diff --git a/code/modules/mob/living/carbon/human/species_types/jellypeople.dm b/code/modules/mob/living/carbon/human/species_types/jellypeople.dm
index c762a52ffc..49c55f70b3 100644
--- a/code/modules/mob/living/carbon/human/species_types/jellypeople.dm
+++ b/code/modules/mob/living/carbon/human/species_types/jellypeople.dm
@@ -504,7 +504,7 @@
else if (select_alteration == "Ears")
var/list/snowflake_ears_list = list("Normal" = null)
for(var/path in GLOB.mam_ears_list)
- var/datum/sprite_accessory/mam_ears/instance = GLOB.mam_ears_list[path]
+ var/datum/sprite_accessory/ears/mam_ears/instance = GLOB.mam_ears_list[path]
if(istype(instance, /datum/sprite_accessory))
var/datum/sprite_accessory/S = instance
if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(H.client.ckey)))
@@ -518,7 +518,7 @@
else if (select_alteration == "Snout")
var/list/snowflake_snouts_list = list("Normal" = null)
for(var/path in GLOB.mam_snouts_list)
- var/datum/sprite_accessory/mam_snouts/instance = GLOB.mam_snouts_list[path]
+ var/datum/sprite_accessory/snouts/mam_snouts/instance = GLOB.mam_snouts_list[path]
if(istype(instance, /datum/sprite_accessory))
var/datum/sprite_accessory/S = instance
if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(H.client.ckey)))
@@ -549,7 +549,7 @@
else if (select_alteration == "Tail")
var/list/snowflake_tails_list = list("Normal" = null)
for(var/path in GLOB.mam_tails_list)
- var/datum/sprite_accessory/mam_tails/instance = GLOB.mam_tails_list[path]
+ var/datum/sprite_accessory/tails/mam_tails/instance = GLOB.mam_tails_list[path]
if(istype(instance, /datum/sprite_accessory))
var/datum/sprite_accessory/S = instance
if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(H.client.ckey)))
diff --git a/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm b/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm
index d768788e87..4901fad892 100644
--- a/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm
+++ b/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm
@@ -11,7 +11,7 @@
mutanttail = /obj/item/organ/tail/lizard
coldmod = 1.5
heatmod = 0.67
- mutant_bodyparts = list("mcolor" = "0F0", "mcolor2" = "0F0", "mcolor3" = "0F0", "tail_lizard" = "Smooth", "snout" = "Round",
+ mutant_bodyparts = list("mcolor" = "0F0", "mcolor2" = "0F0", "mcolor3" = "0F0", "tail_lizard" = "Smooth", "mam_snouts" = "Round",
"horns" = "None", "frills" = "None", "spines" = "None", "body_markings" = "None",
"legs" = "Digitigrade", "taur" = "None", "deco_wings" = "None")
attack_verb = "slash"
@@ -52,6 +52,7 @@
species_traits = list(MUTCOLORS,EYECOLOR,LIPS,DIGITIGRADE)
inherent_traits = list(TRAIT_CHUNKYFINGERS)
mutantlungs = /obj/item/organ/lungs/ashwalker
+ mutanteyes = /obj/item/organ/eyes/night_vision
burnmod = 0.9
brutemod = 0.9
species_language_holder = /datum/language_holder/lizard/ash
diff --git a/code/modules/mob/living/carbon/human/species_types/plasmamen.dm b/code/modules/mob/living/carbon/human/species_types/plasmamen.dm
index b61e29b685..8c30adb8f9 100644
--- a/code/modules/mob/living/carbon/human/species_types/plasmamen.dm
+++ b/code/modules/mob/living/carbon/human/species_types/plasmamen.dm
@@ -57,89 +57,10 @@
..()
/datum/species/plasmaman/before_equip_job(datum/job/J, mob/living/carbon/human/H, visualsOnly = FALSE)
- var/current_job = J?.title
var/datum/outfit/plasmaman/O = new /datum/outfit/plasmaman
- switch(current_job)
- if("Chaplain")
- O = new /datum/outfit/plasmaman/chaplain
-
- if("Curator")
- O = new /datum/outfit/plasmaman/curator
-
- if("Janitor")
- O = new /datum/outfit/plasmaman/janitor
-
- if("Botanist")
- O = new /datum/outfit/plasmaman/botany
-
- if("Bartender", "Lawyer")
- O = new /datum/outfit/plasmaman/bar
-
- if("Cook")
- O = new /datum/outfit/plasmaman/chef
-
- if("Security Officer")
- O = new /datum/outfit/plasmaman/security
-
- if("Detective")
- O = new /datum/outfit/plasmaman/detective
-
- if("Warden")
- O = new /datum/outfit/plasmaman/warden
-
- if("Cargo Technician", "Quartermaster")
- O = new /datum/outfit/plasmaman/cargo
-
- if("Shaft Miner")
- O = new /datum/outfit/plasmaman/mining
-
- if("Medical Doctor")
- O = new /datum/outfit/plasmaman/medical
-
- if("Chemist")
- O = new /datum/outfit/plasmaman/chemist
-
- if("Geneticist")
- O = new /datum/outfit/plasmaman/genetics
-
- if("Roboticist")
- O = new /datum/outfit/plasmaman/robotics
-
- if("Virologist")
- O = new /datum/outfit/plasmaman/viro
-
- if("Scientist")
- O = new /datum/outfit/plasmaman/science
-
- if("Station Engineer")
- O = new /datum/outfit/plasmaman/engineering
-
- if("Atmospheric Technician")
- O = new /datum/outfit/plasmaman/atmospherics
-
- if("Captain")
- O = new /datum/outfit/plasmaman/captain
-
- if("Head of Personnel")
- O = new /datum/outfit/plasmaman/hop
-
- if("Head of Security")
- O = new /datum/outfit/plasmaman/hos
-
- if("Chief Engineer")
- O = new /datum/outfit/plasmaman/ce
-
- if("Chief Medical Officer")
- O = new /datum/outfit/plasmaman/cmo
-
- if("Research Director")
- O = new /datum/outfit/plasmaman/rd
-
- if("Mime")
- O = new /datum/outfit/plasmaman/mime
-
- if("Clown")
- O = new /datum/outfit/plasmaman/clown
+ if(J)
+ if(J.plasma_outfit)
+ O = new J.plasma_outfit
H.equipOutfit(O, visualsOnly)
H.internal = H.get_item_for_held_index(2)
diff --git a/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm b/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm
index b760af9850..228a69c30f 100644
--- a/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm
+++ b/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm
@@ -82,13 +82,11 @@
M.AddSpell(SW)
shadowwalk = SW
-
/obj/item/organ/brain/nightmare/Remove(special = FALSE)
if(shadowwalk && owner)
owner.RemoveSpell(shadowwalk)
return ..()
-
/obj/item/organ/heart/nightmare
name = "heart of darkness"
desc = "An alien organ that twists and writhes when exposed to light."
diff --git a/code/modules/mob/living/carbon/human/species_types/skeletons.dm b/code/modules/mob/living/carbon/human/species_types/skeletons.dm
index 51d81bd4d3..1b6bef9dc6 100644
--- a/code/modules/mob/living/carbon/human/species_types/skeletons.dm
+++ b/code/modules/mob/living/carbon/human/species_types/skeletons.dm
@@ -5,8 +5,8 @@
blacklisted = 0
sexes = 0
meat = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/skeleton
- species_traits = list(NOBLOOD,NOGENITALS,NOAROUSAL,HAS_BONE)
- inherent_traits = list(TRAIT_NOBREATH,TRAIT_RADIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NOHUNGER,TRAIT_EASYDISMEMBER,TRAIT_LIMBATTACHMENT,TRAIT_FAKEDEATH, TRAIT_CALCIUM_HEALER)
+ species_traits = list(NOBLOOD,NOGENITALS,NOAROUSAL,HAS_BONE,NOTRANSSTING)
+ inherent_traits = list(TRAIT_EASYDISMEMBER,TRAIT_LIMBATTACHMENT,TRAIT_CALCIUM_HEALER)
inherent_biotypes = MOB_UNDEAD|MOB_HUMANOID
mutanttongue = /obj/item/organ/tongue/bone
damage_overlay_type = ""//let's not show bloody wounds or burns over bones.
@@ -19,12 +19,12 @@
/datum/species/skeleton/New()
if(SSevents.holidays && SSevents.holidays[HALLOWEEN]) //skeletons are stronger during the spooky season!
- inherent_traits |= list(TRAIT_RESISTHEAT,TRAIT_RESISTCOLD)
+ inherent_traits |= list(TRAIT_RESISTHEAT, TRAIT_NOBREATH, TRAIT_PIERCEIMMUNE, TRAIT_FAKEDEATH, TRAIT_RESISTCOLD, TRAIT_RADIMMUNE)
brutemod = 1
burnmod = 1
..()
-/datum/species/skeleton/greater/check_roundstart_eligible()
+/datum/species/skeleton/check_roundstart_eligible()
if(SSevents.holidays && SSevents.holidays[HALLOWEEN])
return TRUE
return ..()
diff --git a/code/modules/mob/living/carbon/human/species_types/synthliz.dm b/code/modules/mob/living/carbon/human/species_types/synthliz.dm
index 5ed806b302..173411eaa1 100644
--- a/code/modules/mob/living/carbon/human/species_types/synthliz.dm
+++ b/code/modules/mob/living/carbon/human/species_types/synthliz.dm
@@ -22,4 +22,4 @@
tail_type = "mam_tail"
wagging_type = "mam_waggingtail"
- species_type = "robotic"
\ No newline at end of file
+ species_type = "robotic"
diff --git a/code/modules/mob/living/carbon/human/species_types/synths.dm b/code/modules/mob/living/carbon/human/species_types/synths.dm
index a1a2a33c54..c10521dfd9 100644
--- a/code/modules/mob/living/carbon/human/species_types/synths.dm
+++ b/code/modules/mob/living/carbon/human/species_types/synths.dm
@@ -100,14 +100,12 @@
else
return ..()
-
/datum/species/synth/handle_body(mob/living/carbon/human/H)
if(fake_species)
fake_species.handle_body(H)
else
return ..()
-
/datum/species/synth/handle_mutant_bodyparts(mob/living/carbon/human/H, forced_colour)
if(fake_species)
fake_species.handle_body(H,forced_colour)
diff --git a/code/modules/mob/living/carbon/inventory.dm b/code/modules/mob/living/carbon/inventory.dm
index cc837a490c..50801e1c0d 100644
--- a/code/modules/mob/living/carbon/inventory.dm
+++ b/code/modules/mob/living/carbon/inventory.dm
@@ -117,18 +117,6 @@
if(!QDELETED(src))
update_inv_legcuffed()
-/mob/living/carbon/get_equipped_items(include_pockets = FALSE)
- var/list/items = list()
- if(back)
- items += back
- if(head)
- items += head
- if(wear_mask)
- items += wear_mask
- if(wear_neck)
- items += wear_neck
- return items
-
//handle stuff to update when a mob equips/unequips a mask.
/mob/living/proc/wear_mask_update(obj/item/clothing/C, toggle_off = 1)
update_inv_wear_mask()
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index 0f55d5c408..2a461b5921 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -57,7 +57,7 @@
/mob/living/Bump(atom/A)
if(..()) //we are thrown onto something
return
- if (buckled || now_pushing)
+ if(buckled || now_pushing)
return
if(ismob(A))
var/mob/M = A
diff --git a/code/modules/mob/living/living_active_block.dm b/code/modules/mob/living/living_active_block.dm
index 729e7d3d7a..2493509e16 100644
--- a/code/modules/mob/living/living_active_block.dm
+++ b/code/modules/mob/living/living_active_block.dm
@@ -13,7 +13,7 @@
DelayNextAction(data.block_end_click_cd_add)
return TRUE
-/mob/living/proc/ACTIVE_BLOCK_START(obj/item/I)
+/mob/living/proc/active_block_start(obj/item/I)
if(combat_flags & (COMBAT_FLAG_ACTIVE_BLOCK_STARTING | COMBAT_FLAG_ACTIVE_BLOCKING))
return FALSE
if(!(I in held_items))
@@ -109,7 +109,7 @@
animate(src, pixel_x = get_standard_pixel_x_offset(), pixel_y = get_standard_pixel_y_offset(), time = 2.5, FALSE, SINE_EASING | EASE_IN, ANIMATION_END_NOW)
return
combat_flags &= ~(COMBAT_FLAG_ACTIVE_BLOCK_STARTING)
- ACTIVE_BLOCK_START(I)
+ active_block_start(I)
/**
* Gets the first item we can that can block, but if that fails, default to active held item.COMSIG_ENABLE_COMBAT_MODE
@@ -180,6 +180,12 @@
/// Apply the stamina damage to our user, notice how damage argument is stamina_amount.
/obj/item/proc/active_block_do_stamina_damage(mob/living/owner, atom/object, stamina_amount, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
+ if(istype(object, /obj/item/projectile))
+ var/obj/item/projectile/P = object
+ if(P.stamina)
+ var/blocked = active_block_calculate_final_damage(owner, object, P.stamina, attack_text, attack_type, armour_penetration, attacker, def_zone, final_block_chance, block_return)
+ var/stam = active_block_stamina_cost(owner, object, blocked, attack_text, ATTACK_TYPE_PROJECTILE, armour_penetration, attacker, def_zone, final_block_chance, block_return)
+ stamina_amount += stam
var/datum/block_parry_data/data = get_block_parry_data()
if(iscarbon(owner))
var/mob/living/carbon/C = owner
diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm
index 7c4125fbc6..6b58988c31 100644
--- a/code/modules/mob/living/silicon/robot/robot_modules.dm
+++ b/code/modules/mob/living/silicon/robot/robot_modules.dm
@@ -361,7 +361,8 @@
"Sleek" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "sleekmed"),
"Marina" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "marinamed"),
"Eyebot" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "eyebotmed"),
- "Heavy" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "heavymed")
+ "Heavy" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "heavymed"),
+ "Drake" = image(icon = 'icons/mob/cyborg/drakemech.dmi', icon_state = "drakemedbox")
)
var/list/L = list("Medihound" = "medihound", "Medihound Dark" = "medihounddark", "Vale" = "valemed")
for(var/a in L)
@@ -422,6 +423,13 @@
moduleselect_icon = "medihound"
moduleselect_alternate_icon = 'modular_citadel/icons/ui/screen_cyborg.dmi'
dogborg = TRUE
+ if("Drake")
+ cyborg_base_icon = "drakemed"
+ cyborg_icon_override = 'icons/mob/cyborg/drakemech.dmi'
+ sleeper_overlay = "drakemedsleeper"
+ moduleselect_icon = "medihound"
+ moduleselect_alternate_icon = 'modular_citadel/icons/ui/screen_cyborg.dmi'
+ dogborg = TRUE
else
return FALSE
return ..()
@@ -478,7 +486,8 @@
"Can" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "caneng"),
"Marina" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "marinaeng"),
"Spider" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "spidereng"),
- "Heavy" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "heavyeng")
+ "Heavy" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "heavyeng"),
+ "Drake" = image(icon = 'icons/mob/cyborg/drakemech.dmi', icon_state = "drakeengbox")
)
var/list/L = list("Pup Dozer" = "pupdozer", "Vale" = "valeeng")
for(var/a in L)
@@ -536,6 +545,11 @@
cyborg_icon_override = 'modular_citadel/icons/mob/widerobot.dmi'
sleeper_overlay = "alinasleeper"
dogborg = TRUE
+ if("Drake")
+ cyborg_base_icon = "drakeeng"
+ cyborg_icon_override = 'icons/mob/cyborg/drakemech.dmi'
+ sleeper_overlay = "drakesecsleeper"
+ dogborg = TRUE
else
return FALSE
return ..()
@@ -574,7 +588,8 @@
"Can" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "cansec"),
"Marina" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "marinasec"),
"Spider" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "spidersec"),
- "Heavy" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "heavysec")
+ "Heavy" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "heavysec"),
+ "Drake" = image(icon = 'icons/mob/cyborg/drakemech.dmi', icon_state = "drakesecbox")
)
var/list/L = list("K9" = "k9", "Vale" = "valesec", "K9 Dark" = "k9dark")
for(var/a in L)
@@ -630,6 +645,11 @@
sleeper_overlay = "valesecsleeper"
cyborg_icon_override = 'modular_citadel/icons/mob/widerobot.dmi'
dogborg = TRUE
+ if("Drake")
+ cyborg_base_icon = "drakesec"
+ cyborg_icon_override = 'icons/mob/cyborg/drakemech.dmi'
+ sleeper_overlay = "drakesecsleeper"
+ dogborg = TRUE
else
return FALSE
return ..()
@@ -673,7 +693,8 @@
var/static/list/peace_icons = sortList(list(
"Default" = image(icon = 'icons/mob/robots.dmi', icon_state = "peace"),
"Borgi" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "borgi"),
- "Spider" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "whitespider")
+ "Spider" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "whitespider"),
+ "Drake" = image(icon = 'icons/mob/cyborg/drakemech.dmi', icon_state = "drakepeacebox")
))
var/peace_borg_icon = show_radial_menu(R, R , peace_icons, custom_check = CALLBACK(src, .proc/check_menu, R), radius = 42, require_near = TRUE)
switch(peace_borg_icon)
@@ -689,6 +710,11 @@
hat_offset = INFINITY
cyborg_icon_override = 'modular_citadel/icons/mob/robots.dmi'
has_snowflake_deadsprite = TRUE
+ if("Drake")
+ cyborg_base_icon = "drakepeace"
+ cyborg_icon_override = 'icons/mob/cyborg/drakemech.dmi'
+ sleeper_overlay = "drakepeacesleeper"
+ dogborg = TRUE
else
return FALSE
return ..()
@@ -827,7 +853,8 @@
"(Janitor) Marina" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "marinajan"),
"(Janitor) Sleek" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "sleekjan"),
"(Janitor) Can" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "canjan"),
- "(Janitor) Heavy" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "heavyjan")
+ "(Janitor) Heavy" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "heavyjan"),
+ "(Janitor) Drake" = image(icon = 'icons/mob/cyborg/drakemech.dmi', icon_state = "drakejanitbox")
)
var/list/L = list("(Service) DarkK9" = "k50", "(Service) Vale" = "valeserv", "(Service) ValeDark" = "valeservdark",
"(Janitor) Scrubpuppy" = "scrubpup")
@@ -899,6 +926,11 @@
cyborg_icon_override = 'modular_citadel/icons/mob/widerobot.dmi'
sleeper_overlay = "jsleeper"
dogborg = TRUE
+ if("(Janitor) Drake")
+ cyborg_base_icon = "drakejanit"
+ cyborg_icon_override = 'icons/mob/cyborg/drakemech.dmi'
+ sleeper_overlay = "drakesecsleeper"
+ dogborg = TRUE
else
return FALSE
return ..()
@@ -944,7 +976,8 @@
"Sleek" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "sleekmin"),
"Marina" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "marinamin"),
"Can" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "canmin"),
- "Heavy" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "heavymin")
+ "Heavy" = image(icon = 'modular_citadel/icons/mob/robots.dmi', icon_state = "heavymin"),
+ "Drake" = image(icon = 'icons/mob/cyborg/drakemech.dmi', icon_state = "drakeminebox")
)
var/list/L = list("Blade" = "blade", "Vale" = "valemine")
for(var/a in L)
@@ -988,6 +1021,11 @@
cyborg_icon_override = 'modular_citadel/icons/mob/widerobot.dmi'
sleeper_overlay = "valeminesleeper"
dogborg = TRUE
+ if("Drake")
+ cyborg_base_icon = "drakemine"
+ cyborg_icon_override = 'icons/mob/cyborg/drakemech.dmi'
+ sleeper_overlay = "drakeminesleeper"
+ dogborg = TRUE
else
return FALSE
return ..()
diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm
index 7a9610fb53..c6aee397e4 100644
--- a/code/modules/mob/living/silicon/silicon.dm
+++ b/code/modules/mob/living/silicon/silicon.dm
@@ -430,3 +430,6 @@
/mob/living/silicon/handle_high_gravity(gravity)
return
+
+/mob/living/silicon/rust_heretic_act()
+ adjustBruteLoss(500)
diff --git a/code/modules/mob/living/simple_animal/bot/bot.dm b/code/modules/mob/living/simple_animal/bot/bot.dm
index fe6792b5c2..a1772d9281 100644
--- a/code/modules/mob/living/simple_animal/bot/bot.dm
+++ b/code/modules/mob/living/simple_animal/bot/bot.dm
@@ -1058,3 +1058,6 @@ Pass a positive integer as an argument to override a bot's default speed.
if(I)
I.icon_state = null
path.Cut(1, 2)
+
+/mob/living/silicon/rust_heretic_act()
+ adjustBruteLoss(500)
diff --git a/code/modules/mob/living/simple_animal/bot/cleanbot.dm b/code/modules/mob/living/simple_animal/bot/cleanbot.dm
index 5c83482bde..e7c5644e26 100644
--- a/code/modules/mob/living/simple_animal/bot/cleanbot.dm
+++ b/code/modules/mob/living/simple_animal/bot/cleanbot.dm
@@ -313,7 +313,7 @@
/obj/effect/decal/cleanable/dirt,
/obj/effect/decal/cleanable/insectguts,
/obj/effect/decal/cleanable/semen,
- /obj/effect/decal/cleanable/femcum,
+ /obj/effect/decal/cleanable/semen/femcum,
/obj/effect/decal/cleanable/generic,
/obj/effect/decal/cleanable/glass,,
/obj/effect/decal/cleanable/cobweb,
diff --git a/code/modules/mob/living/simple_animal/eldritch_demons.dm b/code/modules/mob/living/simple_animal/eldritch_demons.dm
new file mode 100644
index 0000000000..dbf62be16d
--- /dev/null
+++ b/code/modules/mob/living/simple_animal/eldritch_demons.dm
@@ -0,0 +1,386 @@
+/mob/living/simple_animal/hostile/eldritch
+ name = "Demon"
+ real_name = "Demon"
+ desc = ""
+ gender = NEUTER
+ mob_biotypes = NONE
+ speak_emote = list("screams")
+ response_help_continuous = "thinks better of touching"
+ response_help_simple = "think better of touching"
+ response_disarm_continuous = "flails at"
+ response_disarm_simple = "flail at"
+ response_harm_continuous = "reaps"
+ response_harm_simple = "tears"
+ speak_chance = 1
+ icon = 'icons/mob/eldritch_mobs.dmi'
+ speed = 0
+ a_intent = INTENT_HARM
+ stop_automated_movement = 1
+ AIStatus = AI_OFF
+ attack_sound = 'sound/weapons/punch1.ogg'
+ see_in_dark = 7
+ lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
+ damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 0, CLONE = 0, STAMINA = 0, OXY = 0)
+ atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
+ minbodytemp = 0
+ maxbodytemp = INFINITY
+ healable = 0
+ movement_type = GROUND
+ pressure_resistance = 100
+ del_on_death = TRUE
+ deathmessage = "implodes into itself"
+ faction = list("heretics")
+ simple_mob_flags = SILENCE_RANGED_MESSAGE
+ ///Innate spells that are supposed to be added when a beast is created
+ var/list/spells_to_add
+
+/mob/living/simple_animal/hostile/eldritch/Initialize()
+ . = ..()
+ add_spells()
+
+/**
+ * Add_spells
+ *
+ * Goes through spells_to_add and adds each spell to the mind.
+ */
+/mob/living/simple_animal/hostile/eldritch/proc/add_spells()
+ for(var/spell in spells_to_add)
+ AddSpell(new spell())
+
+/mob/living/simple_animal/hostile/eldritch/raw_prophet
+ name = "Raw Prophet"
+ real_name = "Raw Prophet"
+ desc = "Abomination made from severed limbs."
+ icon_state = "raw_prophet"
+ status_flags = CANPUSH
+ icon_living = "raw_prophet"
+ melee_damage_lower = 5
+ melee_damage_upper = 10
+ maxHealth = 50
+ health = 50
+ sight = SEE_MOBS|SEE_OBJS|SEE_TURFS
+ spells_to_add = list(/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/shift/ash/long,/obj/effect/proc_holder/spell/pointed/manse_link,/obj/effect/proc_holder/spell/targeted/telepathy/eldritch,/obj/effect/proc_holder/spell/pointed/trigger/blind/eldritch)
+
+ var/list/linked_mobs = list()
+
+/mob/living/simple_animal/hostile/eldritch/raw_prophet/Initialize()
+ . = ..()
+ link_mob(src)
+
+/mob/living/simple_animal/hostile/eldritch/raw_prophet/Login()
+ . = ..()
+ client.change_view(10)
+
+/mob/living/simple_animal/hostile/eldritch/raw_prophet/proc/link_mob(mob/living/mob_linked)
+ if(QDELETED(mob_linked) || mob_linked.stat == DEAD)
+ return FALSE
+ if(HAS_TRAIT(mob_linked, TRAIT_MINDSHIELD)) //mindshield implant, no dice
+ return FALSE
+ if(mob_linked.anti_magic_check(FALSE, FALSE, TRUE, 0))
+ return FALSE
+ if(linked_mobs[mob_linked])
+ return FALSE
+
+ to_chat(mob_linked, "You feel something new enter your sphere of mind, you hear whispers of people far away, screeches of horror and a humming of welcome to [src]'s Mansus Link.")
+ var/datum/action/innate/mansus_speech/action = new(src)
+ linked_mobs[mob_linked] = action
+ action.Grant(mob_linked)
+ RegisterSignal(mob_linked, list(COMSIG_MOB_DEATH, COMSIG_PARENT_QDELETING) , .proc/unlink_mob)
+ return TRUE
+
+/mob/living/simple_animal/hostile/eldritch/raw_prophet/proc/unlink_mob(mob/living/mob_linked)
+ if(!linked_mobs[mob_linked])
+ return
+ UnregisterSignal(mob_linked, list(COMSIG_MOB_DEATH, COMSIG_PARENT_QDELETING))
+ var/datum/action/innate/mansus_speech/action = linked_mobs[mob_linked]
+ action.Remove(mob_linked)
+ qdel(action)
+ to_chat(mob_linked, "Your mind shatters as the [src]'s Mansus Link leaves your mind.")
+ mob_linked.emote("Scream")
+ //micro stun
+ mob_linked.AdjustParalyzed(0.5 SECONDS)
+ linked_mobs -= mob_linked
+
+/mob/living/simple_animal/hostile/eldritch/raw_prophet/death(gibbed)
+ for(var/linked_mob in linked_mobs)
+ unlink_mob(linked_mob)
+ return ..()
+
+/mob/living/simple_animal/hostile/eldritch/armsy
+ name = "Terror of the Night"
+ real_name = "Armsy"
+ desc = "Abomination made from severed limbs."
+ icon_state = "armsy_start"
+ icon_living = "armsy_start"
+ maxHealth = 200
+ health = 200
+ obj_damage = 80
+ melee_damage_lower = 10
+ melee_damage_upper = 15
+ move_resist = MOVE_FORCE_OVERPOWERING+1
+ movement_type = GROUND
+ environment_smash = ENVIRONMENT_SMASH_RWALLS
+ sight = SEE_MOBS
+ spells_to_add = list(/obj/effect/proc_holder/spell/targeted/worm_contract)
+ ranged = TRUE
+ ///Previous segment in the chain
+ var/mob/living/simple_animal/hostile/eldritch/armsy/back
+ ///Next segment in the chain
+ var/mob/living/simple_animal/hostile/eldritch/armsy/front
+ ///Your old location
+ var/oldloc
+ ///Allow / disallow pulling
+ var/allow_pulling = FALSE
+ ///How many arms do we have to eat to expand?
+ var/stacks_to_grow = 2
+ ///Currently eaten arms
+ var/current_stacks = 0
+
+//I tried Initalize but it didnt work, like at all. This proc just wouldnt fire if it was Initalize instead of New
+/mob/living/simple_animal/hostile/eldritch/armsy/Initialize(mapload,spawn_more = TRUE,len = 6)
+ . = ..()
+ if(len < 3)
+ stack_trace("Eldritch Armsy created with invalid len ([len]). Reverting to 3.")
+ len = 3 //code breaks below 3, let's just not allow it.
+ oldloc = loc
+ RegisterSignal(src,COMSIG_MOVABLE_MOVED,.proc/update_chain_links)
+ if(!spawn_more)
+ return
+ allow_pulling = TRUE
+ ///next link
+ var/mob/living/simple_animal/hostile/eldritch/armsy/next
+ ///previous link
+ var/mob/living/simple_animal/hostile/eldritch/armsy/prev
+ ///current link
+ var/mob/living/simple_animal/hostile/eldritch/armsy/current
+ for(var/i in 0 to len)
+ prev = current
+ //i tried using switch, but byond is really fucky and it didnt work as intended. Im sorry
+ if(i == 0)
+ current = new type(drop_location(),FALSE)
+ current.icon_state = "armsy_mid"
+ current.icon_living = "armsy_mid"
+ current.front = src
+ current.AIStatus = AI_OFF
+ back = current
+ else if(i < len)
+ current = new type(drop_location(),FALSE)
+ prev.back = current
+ prev.icon_state = "armsy_mid"
+ prev.icon_living = "armsy_mid"
+ prev.front = next
+ prev.AIStatus = AI_OFF
+ else
+ prev.icon_state = "armsy_end"
+ prev.icon_living = "armsy_end"
+ prev.front = next
+ prev.AIStatus = AI_OFF
+ next = prev
+
+//we are literally a vessel of otherworldly destruction, we bring our own gravity unto this plane
+/mob/living/simple_animal/hostile/eldritch/armsy/has_gravity(turf/T)
+ return TRUE
+
+
+/mob/living/simple_animal/hostile/eldritch/armsy/can_be_pulled()
+ return FALSE
+
+///Updates chain links to force move onto a single tile
+/mob/living/simple_animal/hostile/eldritch/armsy/proc/contract_next_chain_into_single_tile()
+ if(back)
+ back.forceMove(loc)
+ back.contract_next_chain_into_single_tile()
+ return
+
+///Updates the next mob in the chain to move to our last location, fixed the worm if somehow broken.
+/mob/living/simple_animal/hostile/eldritch/armsy/proc/update_chain_links()
+ gib_trail()
+ if(back && back.loc != oldloc)
+ back.Move(oldloc)
+ // self fixing properties if somehow broken
+ if(front && loc != front.oldloc)
+ forceMove(front.oldloc)
+ oldloc = loc
+
+/mob/living/simple_animal/hostile/eldritch/armsy/proc/gib_trail()
+ if(front) // head makes gibs
+ return
+ var/chosen_decal = pick(typesof(/obj/effect/decal/cleanable/blood/tracks))
+ var/obj/effect/decal/cleanable/blood/gibs/decal = new chosen_decal(drop_location())
+ decal.setDir(dir)
+
+/mob/living/simple_animal/hostile/eldritch/armsy/Destroy()
+ if(front)
+ front.icon_state = "armsy_end"
+ front.icon_living = "armsy_end"
+ front.back = null
+ if(back)
+ QDEL_NULL(back) // chain destruction baby
+ return ..()
+
+/mob/living/simple_animal/hostile/eldritch/armsy/BiologicalLife(seconds, times_fired)
+ adjustBruteLoss(-2)
+
+/mob/living/simple_animal/hostile/eldritch/armsy/proc/heal()
+ if(health == maxHealth)
+ if(back)
+ back.heal()
+ return
+ else
+ current_stacks++
+ if(current_stacks >= stacks_to_grow)
+ var/mob/living/simple_animal/hostile/eldritch/armsy/prev = new type(drop_location(),spawn_more = FALSE)
+ icon_state = "armsy_mid"
+ icon_living = "armsy_mid"
+ back = prev
+ prev.icon_state = "armsy_end"
+ prev.icon_living = "armsy_end"
+ prev.front = src
+ prev.AIStatus = AI_OFF
+ current_stacks = 0
+
+ adjustBruteLoss(-maxHealth * 0.5, FALSE)
+ adjustFireLoss(-maxHealth * 0.5 ,FALSE)
+
+
+/mob/living/simple_animal/hostile/eldritch/armsy/Shoot(atom/targeted_atom)
+ target = targeted_atom
+ AttackingTarget()
+
+
+/mob/living/simple_animal/hostile/eldritch/armsy/AttackingTarget()
+ if(istype(target,/obj/item/bodypart/r_arm) || istype(target,/obj/item/bodypart/l_arm))
+ qdel(target)
+ heal()
+ return
+ if(target == back || target == front)
+ return
+ if(back)
+ back.target = target
+ back.AttackingTarget()
+ if(!Adjacent(target))
+ return
+ do_attack_animation(target)
+ //have fun
+ //if(istype(target,/turf/closed/wall))
+ //var/turf/closed/wall = target
+ //wall.ScrapeAway()
+
+
+ if(iscarbon(target))
+ var/mob/living/carbon/C = target
+ if(HAS_TRAIT(C, TRAIT_NODISMEMBER))
+ return
+ var/list/parts = list()
+ for(var/X in C.bodyparts)
+ var/obj/item/bodypart/bodypart = X
+ if(bodypart.body_part != HEAD && bodypart.body_part != CHEST)
+ if(bodypart.dismemberable)
+ parts += bodypart
+ if(length(parts) && prob(10))
+ var/obj/item/bodypart/bodypart = pick(parts)
+ bodypart.dismember()
+
+ return ..()
+
+/mob/living/simple_animal/hostile/eldritch/armsy/prime
+ name = "Lord of the Night"
+ real_name = "Master of Decay"
+ maxHealth = 400
+ health = 400
+ melee_damage_lower = 20
+ melee_damage_upper = 25
+
+/mob/living/simple_animal/hostile/eldritch/armsy/prime/Initialize(mapload,spawn_more = TRUE,len = 9)
+ . = ..()
+ var/matrix/matrix_transformation = matrix()
+ matrix_transformation.Scale(1.4,1.4)
+ transform = matrix_transformation
+
+/mob/living/simple_animal/hostile/eldritch/armsy/primeproc/heal()
+ if(health == maxHealth)
+ if(back)
+ back.heal()
+ return
+ else
+ current_stacks++
+ if(current_stacks >= stacks_to_grow)
+ var/mob/living/simple_animal/hostile/eldritch/armsy/prev = new type(drop_location(),spawn_more = FALSE)
+ icon_state = "armsy_mid"
+ icon_living = "armsy_mid"
+ back = prev
+ prev.icon_state = "armsy_end"
+ prev.icon_living = "armsy_end"
+ prev.front = src
+ prev.AIStatus = AI_OFF
+ current_stacks = 0
+ var/matrix/matrix_transformation = matrix()
+ matrix_transformation.Scale(1.4,1.4)
+ transform = matrix_transformation
+
+ adjustBruteLoss(-maxHealth * 0.5, FALSE)
+ adjustFireLoss(-maxHealth * 0.5 ,FALSE)
+
+
+/mob/living/simple_animal/hostile/eldritch/rust_spirit
+ name = "Rust Walker"
+ real_name = "Rusty"
+ desc = "Incomprehensible abomination actively seeping life out of it's surrounding."
+ icon_state = "rust_walker_s"
+ status_flags = CANPUSH
+ icon_living = "rust_walker_s"
+ maxHealth = 75
+ health = 75
+ melee_damage_lower = 15
+ melee_damage_upper = 20
+ sight = SEE_TURFS
+ spells_to_add = list(/obj/effect/proc_holder/spell/aoe_turf/rust_conversion/small,/obj/effect/proc_holder/spell/aimed/rust_wave/short)
+
+/mob/living/simple_animal/hostile/eldritch/rust_spirit/setDir(newdir, ismousemovement)
+ . = ..()
+ if(newdir == NORTH)
+ icon_state = "rust_walker_n"
+ else if(newdir == SOUTH)
+ icon_state = "rust_walker_s"
+ update_icon()
+
+/mob/living/simple_animal/hostile/eldritch/rust_spirit/Moved()
+ . = ..()
+ playsound(src, 'sound/effects/footstep/rustystep1.ogg', 100, TRUE)
+
+/mob/living/simple_animal/hostile/eldritch/rust_spirit/Life()
+ if(stat == DEAD)
+ return ..()
+ var/turf/T = get_turf(src)
+ if(istype(T,/turf/open/floor/plating/rust))
+ adjustBruteLoss(-3, FALSE)
+ adjustFireLoss(-3, FALSE)
+ return ..()
+
+/mob/living/simple_animal/hostile/eldritch/ash_spirit
+ name = "Ash Man"
+ real_name = "Ashy"
+ desc = "Incomprehensible abomination actively seeping life out of it's surrounding."
+ icon_state = "ash_walker"
+ status_flags = CANPUSH
+ icon_living = "ash_walker"
+ maxHealth = 75
+ health = 75
+ melee_damage_lower = 15
+ melee_damage_upper = 20
+ sight = SEE_TURFS
+ spells_to_add = list(/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/shift/ash,/obj/effect/proc_holder/spell/pointed/cleave/long,/obj/effect/proc_holder/spell/aoe_turf/fire_cascade)
+
+/mob/living/simple_animal/hostile/eldritch/stalker
+ name = "Flesh Stalker"
+ real_name = "Flesh Stalker"
+ desc = "Abomination made from severed limbs."
+ icon_state = "stalker"
+ status_flags = CANPUSH
+ icon_living = "stalker"
+ maxHealth = 150
+ health = 150
+ melee_damage_lower = 15
+ melee_damage_upper = 20
+ sight = SEE_MOBS
+ spells_to_add = list(/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/shift/ash,/obj/effect/proc_holder/spell/targeted/shapeshift/eldritch,/obj/effect/proc_holder/spell/targeted/emplosion/eldritch)
diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm
index 706bcc46f5..be0338a60e 100644
--- a/code/modules/mob/living/simple_animal/simple_animal.dm
+++ b/code/modules/mob/living/simple_animal/simple_animal.dm
@@ -146,6 +146,8 @@
var/bare_wound_bonus = 0
//If the attacks from this are sharp
var/sharpness = SHARP_NONE
+ //Generic flags
+ var/simple_mob_flags = NONE
/mob/living/simple_animal/Initialize()
. = ..()
diff --git a/code/modules/power/supermatter/supermatter.dm b/code/modules/power/supermatter/supermatter.dm
index 8559b8ba45..fd8f900552 100644
--- a/code/modules/power/supermatter/supermatter.dm
+++ b/code/modules/power/supermatter/supermatter.dm
@@ -2,34 +2,54 @@
//Please do not bother them with bugs from this port, however, as it has been modified quite a bit.
//Modifications include removing the world-ending full supermatter variation, and leaving only the shard.
+//Zap constants, speeds up targeting
+
+#define BIKE (COIL + 1)
+#define COIL (ROD + 1)
+#define ROD (LIVING + 1)
+#define LIVING (MACHINERY + 1)
+#define MACHINERY (OBJECT + 1)
+#define OBJECT (LOWEST + 1)
+#define LOWEST (1)
+
#define PLASMA_HEAT_PENALTY 15 // Higher == Bigger heat and waste penalty from having the crystal surrounded by this gas. Negative numbers reduce penalty.
#define OXYGEN_HEAT_PENALTY 1
-#define CO2_HEAT_PENALTY 0.1
#define PLUOXIUM_HEAT_PENALTY -1
#define TRITIUM_HEAT_PENALTY 10
+#define CO2_HEAT_PENALTY 0.1
#define NITROGEN_HEAT_PENALTY -1.5
#define BZ_HEAT_PENALTY 5
+#define H2O_HEAT_PENALTY 8
+//#define FREON_HEAT_PENALTY -10 //very good heat absorbtion and less plasma and o2 generation
+//#define HYDROGEN_HEAT_PENALTY 10 // similar heat penalty as tritium (dangerous)
+
+//All of these get divided by 10-bzcomp * 5 before having 1 added and being multiplied with power to determine rads
+//Keep the negative values here above -10 and we won't get negative rads
#define OXYGEN_TRANSMIT_MODIFIER 1.5 //Higher == Bigger bonus to power generation.
#define PLASMA_TRANSMIT_MODIFIER 4
#define BZ_TRANSMIT_MODIFIER -2
+#define TRITIUM_TRANSMIT_MODIFIER 30 //We divide by 10, so this works out to 3
+#define PLUOXIUM_TRANSMIT_MODIFIER -5 //Should halve the power output
+#define H2O_TRANSMIT_MODIFIER 2
+//#define HYDROGEN_TRANSMIT_MODIFIER 25 //increase the radiation emission, but less than the trit (2.5)
-#define TRITIUM_RADIOACTIVITY_MODIFIER 3 //Higher == Crystal spews out more radiation
-#define BZ_RADIOACTIVITY_MODIFIER 5
-#define PLUOXIUM_RADIOACTIVITY_MODIFIER -2
+#define BZ_RADIOACTIVITY_MODIFIER 5 //Improves the effect of transmit modifiers
#define N2O_HEAT_RESISTANCE 6 //Higher == Gas makes the crystal more resistant against heat damage.
#define PLUOXIUM_HEAT_RESISTANCE 3
+//#define HYDROGEN_HEAT_RESISTANCE 2 // just a bit of heat resistance to spice it up
#define POWERLOSS_INHIBITION_GAS_THRESHOLD 0.20 //Higher == Higher percentage of inhibitor gas needed before the charge inertia chain reaction effect starts.
#define POWERLOSS_INHIBITION_MOLE_THRESHOLD 20 //Higher == More moles of the gas are needed before the charge inertia chain reaction effect starts. //Scales powerloss inhibition down until this amount of moles is reached
#define POWERLOSS_INHIBITION_MOLE_BOOST_THRESHOLD 500 //bonus powerloss inhibition boost if this amount of moles is reached
-#define MOLE_PENALTY_THRESHOLD 1800 //Higher == Shard can absorb more moles before triggering the high mole penalties.
+#define MOLE_PENALTY_THRESHOLD 1800 //Above this value we can get lord singulo and independent mol damage, below it we can heal damage
#define MOLE_HEAT_PENALTY 350 //Heat damage scales around this. Too hot setups with this amount of moles do regular damage, anything above and below is scaled
-#define POWER_PENALTY_THRESHOLD 5000 //Higher == Engine can generate more power before triggering the high power penalties.
-#define SEVERE_POWER_PENALTY_THRESHOLD 7000 //Same as above, but causes more dangerous effects
-#define CRITICAL_POWER_PENALTY_THRESHOLD 12000 //Even more dangerous effects, threshold for tesla delamination
+//Along with damage_penalty_point, makes flux anomalies.
+#define POWER_PENALTY_THRESHOLD 5000 //The cutoff on power properly doing damage, pulling shit around, and delamming into a tesla. Low chance of pyro anomalies, +2 bolts of electricity
+#define SEVERE_POWER_PENALTY_THRESHOLD 7000 //+1 bolt of electricity, allows for gravitational anomalies, and higher chances of pyro anomalies
+#define CRITICAL_POWER_PENALTY_THRESHOLD 9000 //+1 bolt of electricity.
#define HEAT_PENALTY_THRESHOLD 40 //Higher == Crystal safe operational temperature is higher.
#define DAMAGE_HARDCAP 0.002
#define DAMAGE_INCREASE_MULTIPLIER 0.25
@@ -66,6 +86,13 @@
#define SUPERMATTER_COUNTDOWN_TIME 30 SECONDS
+///to prevent accent sounds from layering
+#define SUPERMATTER_ACCENT_SOUND_MIN_COOLDOWN 2 SECONDS
+
+#define DEFAULT_ZAP_ICON_STATE "sm_arc"
+#define SLIGHTLY_CHARGED_ZAP_ICON_STATE "sm_arc_supercharged"
+#define OVER_9000_ZAP_ICON_STATE "sm_arc_dbz_referance" //Witty I know
+
GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
/obj/machinery/power/supermatter_crystal
@@ -76,89 +103,183 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
density = TRUE
anchored = TRUE
flags_1 = PREVENT_CONTENTS_EXPLOSION_1
- var/uid = 1
- var/static/gl_uid = 1
light_range = 4
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF | FREEZE_PROOF
-
critical_machine = TRUE
+ ///The id of our supermatter
+ var/uid = 1
+ ///The amount of supermatters that have been created this round
+ var/static/gl_uid = 1
+ ///Tracks the bolt color we are using
+ var/zap_icon = DEFAULT_ZAP_ICON_STATE
+ ///The portion of the gasmix we're on that we should remove
var/gasefficency = 0.15
-
+ ///Used for changing icon states for diff base sprites
var/base_icon_state = "darkmatter"
+ ///Are we exploding?
var/final_countdown = FALSE
+ ///The amount of damage we have currently
var/damage = 0
+ ///The damage we had before this cycle. Used to limit the damage we can take each cycle, and for safe_alert
var/damage_archived = 0
+ ///Our "Shit is no longer fucked" message. We send it when damage is less then damage_archived
var/safe_alert = "Crystalline hyperstructure returning to safe operating parameters."
+ ///The point at which we should start sending messeges about the damage to the engi channels.
var/warning_point = 50
+ ///The alert we send when we've reached warning_point
var/warning_alert = "Danger! Crystal hyperstructure integrity faltering!"
- var/damage_penalty_point = 550
+ ///The point at which we start sending messages to the common channel
var/emergency_point = 700
+ ///The alert we send when we've reached emergency_point
var/emergency_alert = "CRYSTAL DELAMINATION IMMINENT."
+ ///The point at which we delam
var/explosion_point = 900
+ ///When we pass this amount of damage we start shooting bolts
+ var/damage_penalty_point = 550
- var/emergency_issued = FALSE
-
+ ///A scaling value that affects the severity of explosions.
var/explosion_power = 35
- var/temp_factor = 30
-
- var/lastwarning = 0 // Time in 1/10th of seconds since the last sent warning
+ ///Time in 1/10th of seconds since the last sent warning
+ var/lastwarning = 0
+ ///Refered to as eer on the moniter. This value effects gas output, heat, damage, and radiation.
var/power = 0
-
- var/n2comp = 0 // raw composition of each gas in the chamber, ranges from 0 to 1
-
- var/plasmacomp = 0
- var/o2comp = 0
- var/co2comp = 0
- var/n2ocomp = 0
- var/pluoxiumcomp = 0
- var/tritiumcomp = 0
- var/bzcomp = 0
-
- var/pluoxiumbonus = 0
-
+ ///Determines the rate of positve change in gas comp values
+ var/gas_change_rate = 0.05
+ ///The list of gases we will be interacting with in process_atoms()
+ var/list/gases_we_care_about = list(
+ /datum/gas/oxygen,
+ /datum/gas/water_vapor,
+ /datum/gas/plasma,
+ /datum/gas/carbon_dioxide,
+ /datum/gas/nitrous_oxide,
+ /datum/gas/nitrogen,
+ /datum/gas/pluoxium,
+ /datum/gas/tritium,
+ /datum/gas/bz,
+// /datum/gas/freon,
+// /datum/gas/hydrogen,
+ )
+ ///The list of gases mapped against their current comp. We use this to calculate different values the supermatter uses, like power or heat resistance. It doesn't perfectly match the air around the sm, instead moving up at a rate determined by gas_change_rate per call. Ranges from 0 to 1
+ var/list/gas_comp = list(
+ /datum/gas/oxygen = 0,
+ /datum/gas/water_vapor = 0,
+ /datum/gas/plasma = 0,
+ /datum/gas/carbon_dioxide = 0,
+ /datum/gas/nitrous_oxide = 0,
+ /datum/gas/nitrogen = 0,
+ /datum/gas/pluoxium = 0,
+ /datum/gas/tritium = 0,
+ /datum/gas/bz = 0,
+// /datum/gas/freon = 0,
+// /datum/gas/hydrogen = 0,
+ )
+ ///The list of gases mapped against their transmit values. We use it to determine the effect different gases have on radiation
+ var/list/gas_trans = list(
+ /datum/gas/oxygen = OXYGEN_TRANSMIT_MODIFIER,
+ /datum/gas/water_vapor = H2O_TRANSMIT_MODIFIER,
+ /datum/gas/plasma = PLASMA_TRANSMIT_MODIFIER,
+ /datum/gas/pluoxium = PLUOXIUM_TRANSMIT_MODIFIER,
+ /datum/gas/tritium = TRITIUM_TRANSMIT_MODIFIER,
+ /datum/gas/bz = BZ_TRANSMIT_MODIFIER,
+// /datum/gas/hydrogen = HYDROGEN_TRANSMIT_MODIFIER,
+ )
+ ///The list of gases mapped against their heat penaltys. We use it to determin molar and heat output
+ var/list/gas_heat = list(
+ /datum/gas/oxygen = OXYGEN_HEAT_PENALTY,
+ /datum/gas/water_vapor = H2O_HEAT_PENALTY,
+ /datum/gas/plasma = PLASMA_HEAT_PENALTY,
+ /datum/gas/carbon_dioxide = CO2_HEAT_PENALTY,
+ /datum/gas/nitrogen = NITROGEN_HEAT_PENALTY,
+ /datum/gas/pluoxium = PLUOXIUM_HEAT_PENALTY,
+ /datum/gas/tritium = TRITIUM_HEAT_PENALTY,
+ /datum/gas/bz = BZ_HEAT_PENALTY,
+// /datum/gas/freon = FREON_HEAT_PENALTY,
+// /datum/gas/hydrogen = HYDROGEN_HEAT_PENALTY,
+ )
+ ///The list of gases mapped against their heat resistance. We use it to moderate heat damage.
+ var/list/gas_resist = list(
+ /datum/gas/nitrous_oxide = N2O_HEAT_RESISTANCE,
+ /datum/gas/pluoxium = PLUOXIUM_HEAT_RESISTANCE,
+// /datum/gas/hydrogen = HYDROGEN_HEAT_RESISTANCE,
+ )
+ ///The list of gases mapped against their powermix ratio
+ var/list/gas_powermix = list(
+ /datum/gas/oxygen = 1,
+ /datum/gas/water_vapor = 1,
+ /datum/gas/plasma = 1,
+ /datum/gas/carbon_dioxide = 1,
+ /datum/gas/nitrogen = -1,
+ /datum/gas/pluoxium = -1,
+ /datum/gas/tritium = 1,
+ /datum/gas/bz = 1,
+// /datum/gas/freon = -1,
+// /datum/gas/hydrogen = 1,
+ )
+ ///The last air sample's total molar count, will always be above or equal to 0
var/combined_gas = 0
+ ///Affects the power gain the sm experiances from heat
var/gasmix_power_ratio = 0
+ ///Affects the amount of o2 and plasma the sm outputs, along with the heat it makes.
var/dynamic_heat_modifier = 1
+ ///Affects the amount of damage and minimum point at which the sm takes heat damage
var/dynamic_heat_resistance = 1
+ ///Uses powerloss_dynamic_scaling and combined_gas to lessen the effects of our powerloss functions
var/powerloss_inhibitor = 1
+ ///Based on co2 percentage, slowly moves between 0 and 1. We use it to calc the powerloss_inhibitor
var/powerloss_dynamic_scaling= 0
+ ///Affects the amount of radiation the sm makes. We multiply this with power to find the rads.
var/power_transmission_bonus = 0
+ ///Used to increase or lessen the amount of damage the sm takes from heat based on molar counts.
var/mole_heat_penalty = 0
-
-
+ ///Takes the energy throwing things into the sm generates and slowly turns it into actual power
var/matter_power = 0
+ ///The cutoff for a bolt jumping, grows with heat, lowers with higher mol count,
+ var/zap_cutoff = 1500
+ ///How much the bullets damage should be multiplied by when it is added to the internal variables
+ var/bullet_energy = 2
+ ///How much hallucination should we produce per unit of power?
+ var/hallucination_power = 0.1
- //Temporary values so that we can optimize this
- //How much the bullets damage should be multiplied by when it is added to the internal variables
- var/config_bullet_energy = 2
- //How much of the power is left after processing is finished?
-// var/config_power_reduction_per_tick = 0.5
- //How much hallucination should it produce per unit of power?
- var/config_hallucination_power = 0.1
-
+ ///Our internal radio
var/obj/item/radio/radio
+ ///The key our internal radio uses
var/radio_key = /obj/item/encryptionkey/headset_eng
+ ///The engineering channel
var/engineering_channel = "Engineering"
+ ///The common channel
var/common_channel = null
- //for logging
+ ///Boolean used for logging if we've been powered
var/has_been_powered = FALSE
+ ///Boolean used for logging if we've passed the emergency point
var/has_reached_emergency = FALSE
- // For making hugbox supermatter
- var/takes_damage = TRUE
- var/produces_gas = TRUE
+ ///An effect we show to admins and ghosts the percentage of delam we're at
var/obj/effect/countdown/supermatter/countdown
+ ///Used along with a global var to track if we can give out the sm sliver stealing objective
var/is_main_engine = FALSE
-
+ ///Our soundloop
var/datum/looping_sound/supermatter/soundloop
-
+ ///Can it be moved?
var/moveable = FALSE
+ ///cooldown tracker for accent sounds
+ var/last_accent_sound = 0
+
+ //For making hugbox supermatters
+ ///Disables all methods of taking damage
+ var/takes_damage = TRUE
+ ///Disables the production of gas, and pretty much any handling of it we do.
+ var/produces_gas = TRUE
+ ///Disables power changes
+ var/power_changes = TRUE
+ ///Disables the sm's proccessing totally.
+ var/processes = TRUE
+
/obj/machinery/power/supermatter_crystal/Initialize()
. = ..()
uid = gl_uid++
@@ -174,6 +295,9 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
if(is_main_engine)
GLOB.main_supermatter_engine = src
+ AddElement(/datum/element/bsa_blocker)
+ RegisterSignal(src, COMSIG_ATOM_BSA_BEAM, .proc/call_explode)
+
soundloop = new(list(src), TRUE)
/obj/machinery/power/supermatter_crystal/Destroy()
@@ -184,12 +308,11 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
QDEL_NULL(countdown)
if(is_main_engine && GLOB.main_supermatter_engine == src)
GLOB.main_supermatter_engine = null
- QDEL_NULL(soundloop)
return ..()
/obj/machinery/power/supermatter_crystal/examine(mob/user)
. = ..()
- if (iscarbon(user))
+ if (istype(user, /mob/living/carbon))
var/mob/living/carbon/C = user
if (!istype(C.glasses, /obj/item/clothing/glasses/meson) && (get_dist(user, src) < HALLUCINATION_RANGE(power)))
. += "You get headaches just from looking at it."
@@ -202,16 +325,17 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
if(!air)
return SUPERMATTER_ERROR
- if(get_integrity() < SUPERMATTER_DELAM_PERCENT)
+ var/integrity = get_integrity()
+ if(integrity < SUPERMATTER_DELAM_PERCENT)
return SUPERMATTER_DELAMINATING
- if(get_integrity() < SUPERMATTER_EMERGENCY_PERCENT)
+ if(integrity < SUPERMATTER_EMERGENCY_PERCENT)
return SUPERMATTER_EMERGENCY
- if(get_integrity() < SUPERMATTER_DANGER_PERCENT)
+ if(integrity < SUPERMATTER_DANGER_PERCENT)
return SUPERMATTER_DANGER
- if((get_integrity() < SUPERMATTER_WARNING_PERCENT) || (air.return_temperature() > CRITICAL_TEMPERATURE))
+ if((integrity < SUPERMATTER_WARNING_PERCENT) || (air.return_temperature() > CRITICAL_TEMPERATURE))
return SUPERMATTER_WARNING
if(air.return_temperature() > (CRITICAL_TEMPERATURE * 0.8))
@@ -238,23 +362,26 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
integrity = integrity < 0 ? 0 : integrity
return integrity
+/obj/machinery/power/supermatter_crystal/update_overlays()
+ . = ..()
+ if(final_countdown)
+ . += "casuality_field"
+
/obj/machinery/power/supermatter_crystal/proc/countdown()
set waitfor = FALSE
if(final_countdown) // We're already doing it go away
return
final_countdown = TRUE
-
- var/image/causality_field = image(icon, null, "causality_field")
- add_overlay(causality_field, TRUE)
+ update_icon()
var/speaking = "[emergency_alert] The supermatter has reached critical integrity failure. Emergency causality destabilization field has been activated."
radio.talk_into(src, speaking, common_channel, language = get_selected_language())
for(var/i in SUPERMATTER_COUNTDOWN_TIME to 0 step -10)
if(damage < explosion_point) // Cutting it a bit close there engineers
radio.talk_into(src, "[safe_alert] Failsafe has been disengaged.", common_channel)
- cut_overlay(causality_field, TRUE)
final_countdown = FALSE
+ update_icon()
return
else if((i % 50) != 0 && i > 50) // A message once every 5 seconds until the final 5 seconds which count down individualy
sleep(10)
@@ -287,48 +414,65 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "delam", /datum/mood_event/delam)
if(combined_gas > MOLE_PENALTY_THRESHOLD)
investigate_log("has collapsed into a singularity.", INVESTIGATE_SUPERMATTER)
- if(T)
+ if(T) //If something fucks up we blow anyhow. This fix is 4 years old and none ever said why it's here. help.
var/obj/singularity/S = new(T)
S.energy = 800
S.consume(src)
- else
- investigate_log("has exploded.", INVESTIGATE_SUPERMATTER)
- explosion(get_turf(T), explosion_power * max(gasmix_power_ratio, 0.205) * 0.5 , explosion_power * max(gasmix_power_ratio, 0.205) + 2, explosion_power * max(gasmix_power_ratio, 0.205) + 4 , explosion_power * max(gasmix_power_ratio, 0.205) + 6, 1, 1)
- if(power > POWER_PENALTY_THRESHOLD)
- investigate_log("has spawned additional energy balls.", INVESTIGATE_SUPERMATTER)
+ return //No boom for me sir
+ else if(power > POWER_PENALTY_THRESHOLD)
+ investigate_log("has spawned additional energy balls.", INVESTIGATE_SUPERMATTER)
+ if(T)
var/obj/singularity/energy_ball/E = new(T)
E.energy = power
- qdel(src)
+ investigate_log("has exploded.", INVESTIGATE_SUPERMATTER)
+ //Dear mappers, balance the sm max explosion radius to 17.5, 37, 39, 41
+ explosion(get_turf(T), explosion_power * max(gasmix_power_ratio, 0.205) * 0.5 , explosion_power * max(gasmix_power_ratio, 0.205) + 2, explosion_power * max(gasmix_power_ratio, 0.205) + 4 , explosion_power * max(gasmix_power_ratio, 0.205) + 6, 1, 1)
+ qdel(src)
-/obj/machinery/power/supermatter_crystal/proc/consume_turf(turf/T)
- var/oldtype = T.type
- var/turf/newT = T.ScrapeAway()
- if(newT.type == oldtype)
- return
- playsound(T, 'sound/effects/supermatter.ogg', 50, 1)
- T.visible_message("[T] smacks into [src] and rapidly flashes to ash.",\
- "You hear a loud crack as you are washed with a wave of heat.")
- CALCULATE_ADJACENT_TURFS(T)
+
+//this is here to eat arguments
+/obj/machinery/power/supermatter_crystal/proc/call_explode()
+ explode()
/obj/machinery/power/supermatter_crystal/process_atmos()
+ if(!processes) //Just fuck me up bro
+ return
var/turf/T = loc
- if(isnull(T)) // We have a null turf...something is wrong, stop processing this entity.
+ if(isnull(T))// We have a null turf...something is wrong, stop processing this entity.
return PROCESS_KILL
- if(!istype(T)) //We are in a crate or somewhere that isn't turf, if we return to turf resume processing but for now.
+ if(!istype(T))//We are in a crate or somewhere that isn't turf, if we return to turf resume processing but for now.
return //Yeah just stop.
- if(istype(T, /turf/closed))
- consume_turf(T)
+ if(isclosedturf(T))
+ var/turf/did_it_melt = T.Melt()
+ if(!isclosedturf(did_it_melt)) //In case some joker finds way to place these on indestructible walls
+ visible_message("[src] melts through [T]!")
+ return
+
+ //We vary volume by power, and handle OH FUCK FUSION IN COOLING LOOP noises.
if(power)
- soundloop.volume = min(40, (round(power/100)/50)+1) // 5 +1 volume per 20 power. 2500 power is max
+ soundloop.volume = clamp((50 + (power / 50)), 50, 100)
+ if(damage >= 300)
+ soundloop.mid_sounds = list('sound/machines/sm/loops/delamming.ogg' = 1)
+ else
+ soundloop.mid_sounds = list('sound/machines/sm/loops/calm.ogg' = 1)
+
+ //We play delam/neutral sounds at a rate determined by power and damage
+ if(last_accent_sound < world.time && prob(20))
+ var/aggression = min(((damage / 800) * (power / 2500)), 1.0) * 100
+ if(damage >= 300)
+ playsound(src, "smdelam", max(50, aggression), FALSE, 10)
+ else
+ playsound(src, "smcalm", max(50, aggression), FALSE, 10)
+ var/next_sound = round((100 - aggression) * 5)
+ last_accent_sound = world.time + max(SUPERMATTER_ACCENT_SOUND_MIN_COOLDOWN, next_sound)
//Ok, get the air from the turf
var/datum/gas_mixture/env = T.return_air()
var/datum/gas_mixture/removed
-
if(produces_gas)
//Remove gas from surrounding area
removed = env.remove(gasefficency * env.total_moles())
@@ -336,141 +480,240 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
// Pass all the gas related code an empty gas container
removed = new()
damage_archived = damage
+
+ /********
+ EXPERIMENTAL, HUGBOXY AS HELL CITADEL CHANGES: Even in a vaccum, update gas composition and modifiers.
+ This means that the SM will usually have a very small explosion if it ends up being breached to space,
+ and CO2 tesla delaminations basically require multiple grounding rods to stabilize it long enough to not have it vent.
+ *********/
+
if(!removed || !removed.total_moles() || isspaceturf(T)) //we're in space or there is no gas to process
if(takes_damage)
damage += max((power / 1000) * DAMAGE_INCREASE_MULTIPLIER, 0.1) // always does at least some damage
+ combined_gas = max(0, combined_gas - 0.5) // Slowly wear off.
+ for(var/gasID in gases_we_care_about)
+ gas_comp[gasID] = max(0, gas_comp[gasID] - 0.05) //slowly ramp down
else
if(takes_damage)
//causing damage
+ //Due to DAMAGE_INCREASE_MULTIPLIER, we only deal one 4th of the damage the statements otherwise would cause
+
+ //((((some value between 0.5 and 1 * temp - ((273.15 + 40) * some values between 1 and 10)) * some number between 0.25 and knock your socks off / 150) * 0.25
+ //Heat and mols account for each other, a lot of hot mols are more damaging then a few
+ //Mols start to have a positive effect on damage after 350
damage = max(damage + (max(clamp(removed.total_moles() / 200, 0.5, 1) * removed.return_temperature() - ((T0C + HEAT_PENALTY_THRESHOLD)*dynamic_heat_resistance), 0) * mole_heat_penalty / 150 ) * DAMAGE_INCREASE_MULTIPLIER, 0)
+ //Power only starts affecting damage when it is above 5000
damage = max(damage + (max(power - POWER_PENALTY_THRESHOLD, 0)/500) * DAMAGE_INCREASE_MULTIPLIER, 0)
+ //Molar count only starts affecting damage when it is above 1800
damage = max(damage + (max(combined_gas - MOLE_PENALTY_THRESHOLD, 0)/80) * DAMAGE_INCREASE_MULTIPLIER, 0)
+ //There might be a way to integrate healing and hurting via heat
//healing damage
if(combined_gas < MOLE_PENALTY_THRESHOLD)
- damage = max(damage + (min(removed.return_temperature() - (T0C + HEAT_PENALTY_THRESHOLD), 0) / 150 ), 0)
+ //Only has a net positive effect when the temp is below 313.15, heals up to 2 damage. Psycologists increase this temp min by up to 45
+ damage = max(damage + (min(removed.return_temperature() - (T0C + HEAT_PENALTY_THRESHOLD), 0) / 150), 0)
- //capping damage
- damage = min(damage_archived + (DAMAGE_HARDCAP * explosion_point),damage)
- if(damage > damage_archived && prob(10))
- playsound(get_turf(src), 'sound/effects/empulse.ogg', 50, 1)
+ //caps damage rate
- //calculating gas related values
- combined_gas = max(removed.total_moles(), 0)
+ //Takes the lower number between archived damage + (1.8) and damage
+ //This means we can only deal 1.8 damage per function call
+ damage = min(damage_archived + (DAMAGE_HARDCAP * explosion_point), damage)
- plasmacomp = max(removed.get_moles(/datum/gas/plasma)/combined_gas, 0)
- o2comp = max(removed.get_moles(/datum/gas/oxygen)/combined_gas, 0)
- co2comp = max(removed.get_moles(/datum/gas/carbon_dioxide)/combined_gas, 0)
- tritiumcomp = max(removed.get_moles(/datum/gas/tritium)/combined_gas, 0)
- bzcomp = max(removed.get_moles(/datum/gas/bz)/combined_gas, 0)
+ //calculating gas related values
+ //Wanna know a secret? See that max() to zero? it's used for error checking. If we get a mol count in the negative, we'll get a divide by zero error
+ combined_gas = max(removed.total_moles(), 0)
- pluoxiumcomp = max(removed.get_moles(/datum/gas/pluoxium)/combined_gas, 0)
- n2ocomp = max(removed.get_moles(/datum/gas/nitrous_oxide)/combined_gas, 0)
- n2comp = max(removed.get_moles(/datum/gas/nitrogen)/combined_gas, 0)
+ //This is more error prevention, according to all known laws of atmos, gas_mix.remove() should never make negative mol values.
+ //But this is tg
- if(pluoxiumcomp >= 0.15)
- pluoxiumbonus = 1 //makes pluoxium only work at 15%+
- else
- pluoxiumbonus = 0
+ //Lets get the proportions of the gasses in the mix and then slowly move our comp to that value
+ //Can cause an overestimation of mol count, should stabalize things though.
+ //Prevents huge bursts of gas/heat when a large amount of something is introduced
+ //They range between 0 and 1
+ for(var/gasID in gases_we_care_about)
+ gas_comp[gasID] += clamp(max(removed.get_moles(gasID)/combined_gas, 0) - gas_comp[gasID], -1, gas_change_rate)
- gasmix_power_ratio = min(max(plasmacomp + o2comp + co2comp + tritiumcomp + bzcomp - pluoxiumcomp - n2comp, 0), 1)
+ var/list/heat_mod = gases_we_care_about.Copy()
+ var/list/transit_mod = gases_we_care_about.Copy()
+ var/list/resistance_mod = gases_we_care_about.Copy()
- dynamic_heat_modifier = max((plasmacomp * PLASMA_HEAT_PENALTY) + (o2comp * OXYGEN_HEAT_PENALTY) + (co2comp * CO2_HEAT_PENALTY) + (tritiumcomp * TRITIUM_HEAT_PENALTY) + ((pluoxiumcomp * PLUOXIUM_HEAT_PENALTY) * pluoxiumbonus) + (n2comp * NITROGEN_HEAT_PENALTY) + (bzcomp * BZ_HEAT_PENALTY), 0.5)
- dynamic_heat_resistance = max((n2ocomp * N2O_HEAT_RESISTANCE) + ((pluoxiumcomp * PLUOXIUM_HEAT_RESISTANCE) * pluoxiumbonus), 1)
+ //We're concerned about pluoxium being too easy to abuse at low percents, so we make sure there's a substantial amount.
+ var/pluoxiumbonus = (gas_comp[/datum/gas/pluoxium] >= 0.15) //makes pluoxium only work at 15%+
+ var/h2obonus = 1 - (gas_comp[/datum/gas/water_vapor] * 0.25)//At max this value should be 0.75
+// var/freonbonus = (gas_comp[/datum/gas/freon] <= 0.03) //Let's just yeet power output if this shit is high
- power_transmission_bonus = max((plasmacomp * PLASMA_TRANSMIT_MODIFIER) + (o2comp * OXYGEN_TRANSMIT_MODIFIER) + (bzcomp * BZ_TRANSMIT_MODIFIER), 0)
+ heat_mod[/datum/gas/pluoxium] = pluoxiumbonus
+ transit_mod[/datum/gas/pluoxium] = pluoxiumbonus
+ resistance_mod[/datum/gas/pluoxium] = pluoxiumbonus
- //more moles of gases are harder to heat than fewer, so let's scale heat damage around them
- mole_heat_penalty = max(combined_gas / MOLE_HEAT_PENALTY, 0.25)
+ //No less then zero, and no greater then one, we use this to do explosions and heat to power transfer
+ //Be very careful with modifing this var by large amounts, and for the love of god do not push it past 1
+ gasmix_power_ratio = 0
+ for(var/gasID in gas_powermix)
+ gasmix_power_ratio += gas_comp[gasID] * gas_powermix[gasID]
+ gasmix_power_ratio = clamp(gasmix_power_ratio, 0, 1)
- if (combined_gas > POWERLOSS_INHIBITION_MOLE_THRESHOLD && co2comp > POWERLOSS_INHIBITION_GAS_THRESHOLD)
- powerloss_dynamic_scaling = clamp(powerloss_dynamic_scaling + clamp(co2comp - powerloss_dynamic_scaling, -0.02, 0.02), 0, 1)
- else
- powerloss_dynamic_scaling = clamp(powerloss_dynamic_scaling - 0.05,0, 1)
- powerloss_inhibitor = clamp(1-(powerloss_dynamic_scaling * clamp(combined_gas/POWERLOSS_INHIBITION_MOLE_BOOST_THRESHOLD,1 ,1.5)),0 ,1)
+ //Minimum value of -10, maximum value of 23. Effects plasma and o2 output and the output heat
+ dynamic_heat_modifier = 0
+ for(var/gasID in gas_heat)
+ dynamic_heat_modifier += gas_comp[gasID] * gas_heat[gasID] * (isnull(heat_mod[gasID]) ? 1 : heat_mod[gasID])
+ dynamic_heat_modifier *= h2obonus
+ dynamic_heat_modifier = max(dynamic_heat_modifier, 0.5)
- if(matter_power)
- var/removed_matter = max(matter_power/MATTER_POWER_CONVERSION, 40)
- power = max(power + removed_matter, 0)
- matter_power = max(matter_power - removed_matter, 0)
+ //Value between 1 and 10. Effects the damage heat does to the crystal
+ dynamic_heat_resistance = 0
+ for(var/gasID in gas_resist)
+ dynamic_heat_resistance += gas_comp[gasID] * gas_resist[gasID] * (isnull(resistance_mod[gasID]) ? 1 : resistance_mod[gasID])
+ dynamic_heat_resistance = max(dynamic_heat_resistance, 1)
- var/temp_factor = 50
+ //Value between -5 and 30, used to determine radiation output as it concerns things like collectors.
+ power_transmission_bonus = 0
+ for(var/gasID in gas_trans)
+ power_transmission_bonus += gas_comp[gasID] * gas_trans[gasID] * (isnull(transit_mod[gasID]) ? 1 : transit_mod[gasID])
+ power_transmission_bonus *= h2obonus
- if(gasmix_power_ratio > 0.8)
- // with a perfect gas mix, make the power less based on heat
- icon_state = "[base_icon_state]_glow"
- else
- // in normal mode, base the produced energy around the heat
- temp_factor = 30
- icon_state = base_icon_state
+ //more moles of gases are harder to heat than fewer, so let's scale heat damage around them
+ mole_heat_penalty = max(combined_gas / MOLE_HEAT_PENALTY, 0.25)
- power = max( (removed.return_temperature() * temp_factor / T0C) * gasmix_power_ratio + power, 0) //Total laser power plus an overload
+ //Ramps up or down in increments of 0.02 up to the proportion of co2
+ //Given infinite time, powerloss_dynamic_scaling = co2comp
+ //Some value between 0 and 1
+ if (combined_gas > POWERLOSS_INHIBITION_MOLE_THRESHOLD && gas_comp[/datum/gas/carbon_dioxide] > POWERLOSS_INHIBITION_GAS_THRESHOLD) //If there are more then 20 mols, and more then 20% co2
+ powerloss_dynamic_scaling = clamp(powerloss_dynamic_scaling + clamp(gas_comp[/datum/gas/carbon_dioxide] - powerloss_dynamic_scaling, -0.02, 0.02), 0, 1)
+ else
+ powerloss_dynamic_scaling = clamp(powerloss_dynamic_scaling - 0.05, 0, 1)
+ //Ranges from 0 to 1(1-(value between 0 and 1 * ranges from 1 to 1.5(mol / 500)))
+ //We take the mol count, and scale it to be our inhibitor
+ powerloss_inhibitor = clamp(1-(powerloss_dynamic_scaling * clamp(combined_gas/POWERLOSS_INHIBITION_MOLE_BOOST_THRESHOLD, 1, 1.5)), 0, 1)
- if(prob(50))
- radiation_pulse(src, power * (1 + (tritiumcomp * TRITIUM_RADIOACTIVITY_MODIFIER) + ((pluoxiumcomp * PLUOXIUM_RADIOACTIVITY_MODIFIER) * pluoxiumbonus) * (power_transmission_bonus/(10-(bzcomp * BZ_RADIOACTIVITY_MODIFIER))))) // Rad Modifiers BZ(500%), Tritium(300%), and Pluoxium(-200%)
- if(bzcomp >= 0.4 && prob(30 * bzcomp))
- fire_nuclear_particle() // Start to emit radballs at a maximum of 30% chance per tick
+ //Releases stored power into the general pool
+ //We get this by consuming shit or being scalpeled
+ if(matter_power && power_changes)
+ //We base our removed power off one 10th of the matter_power.
+ var/removed_matter = max(matter_power/MATTER_POWER_CONVERSION, 40)
+ //Adds at least 40 power
+ power = max(power + removed_matter, 0)
+ //Removes at least 40 matter power
+ matter_power = max(matter_power - removed_matter, 0)
- var/device_energy = power * REACTION_POWER_MODIFIER
+ var/temp_factor = 50
+ if(gasmix_power_ratio > 0.8)
+ //with a perfect gas mix, make the power more based on heat
+ icon_state = "[base_icon_state]_glow"
+ else
+ //in normal mode, power is less effected by heat
+ temp_factor = 30
+ icon_state = base_icon_state
- //To figure out how much temperature to add each tick, consider that at one atmosphere's worth
- //of pure oxygen, with all four lasers firing at standard energy and no N2 present, at room temperature
- //that the device energy is around 2140. At that stage, we don't want too much heat to be put out
- //Since the core is effectively "cold"
+ //if there is more pluox and n2 then anything else, we receive no power increase from heat
+ if(power_changes)
+ power = max((removed.return_temperature() * temp_factor / T0C) * gasmix_power_ratio + power, 0)
- //Also keep in mind we are only adding this temperature to (efficiency)% of the one tile the rock
- //is on. An increase of 4*C @ 25% efficiency here results in an increase of 1*C / (#tilesincore) overall.
- removed.set_temperature(removed.return_temperature() + ((device_energy * dynamic_heat_modifier) / THERMAL_RELEASE_MODIFIER))
+ if(prob(50))
+ //(1 + (tritRad + pluoxDampen * bzDampen * o2Rad * plasmaRad / (10 - bzrads))) * freonbonus
+ radiation_pulse(src, power * max(0, (1 + (power_transmission_bonus/(10-(gas_comp[/datum/gas/bz] * BZ_RADIOACTIVITY_MODIFIER)))) * 1))//freonbonus))// RadModBZ(500%)
+ if(gas_comp[/datum/gas/bz] >= 0.4 && prob(30 * gas_comp[/datum/gas/bz]))
+ src.fire_nuclear_particle() // Start to emit radballs at a maximum of 30% chance per tick
- removed.set_temperature(max(0, min(removed.return_temperature(), 2500 * dynamic_heat_modifier)))
+ //Power * 0.55 * a value between 1 and 0.8
+ var/device_energy = power * REACTION_POWER_MODIFIER
- //Calculate how much gas to release
- removed.adjust_moles(/datum/gas/plasma, max((device_energy * dynamic_heat_modifier) / PLASMA_RELEASE_MODIFIER, 0))
+ //To figure out how much temperature to add each tick, consider that at one atmosphere's worth
+ //of pure oxygen, with all four lasers firing at standard energy and no N2 present, at room temperature
+ //that the device energy is around 2140. At that stage, we don't want too much heat to be put out
+ //Since the core is effectively "cold"
- removed.adjust_moles(/datum/gas/oxygen, max(((device_energy + removed.return_temperature() * dynamic_heat_modifier) - T0C) / OXYGEN_RELEASE_MODIFIER, 0))
+ //Also keep in mind we are only adding this temperature to (efficiency)% of the one tile the rock
+ //is on. An increase of 4*C @ 25% efficiency here results in an increase of 1*C / (#tilesincore) overall.
+ //Power * 0.55 * (some value between 1.5 and 23) / 5
+ removed.set_temperature(removed.return_temperature() + ((device_energy * dynamic_heat_modifier) / THERMAL_RELEASE_MODIFIER))
+ //We can only emit so much heat, that being 57500
+ removed.set_temperature(max(0, min(removed.return_temperature(), 2500 * dynamic_heat_modifier)))
- if(produces_gas)
- env.merge(removed)
- air_update_turf()
+ //Calculate how much gas to release
+ //Varies based on power and gas content
+ removed.adjust_moles(/datum/gas/plasma, max((device_energy * dynamic_heat_modifier) / PLASMA_RELEASE_MODIFIER, 0))
+ //Varies based on power, gas content, and heat
+ removed.adjust_moles(/datum/gas/oxygen, max(((device_energy + removed.return_temperature() * dynamic_heat_modifier) - T0C) / OXYGEN_RELEASE_MODIFIER, 0))
- for(var/mob/living/carbon/human/l in fov_viewers(HALLUCINATION_RANGE(power), src)) // If they can see it without mesons on. Bad on them.
+ if(produces_gas)
+ env.merge(removed)
+ air_update_turf()
+
+ /*********
+ END CITADEL CHANGES
+ *********/
+
+ //Makes em go mad and accumulate rads.
+ for(var/mob/living/carbon/human/l in fov_viewers(src, HALLUCINATION_RANGE(power))) // If they can see it without mesons on. Bad on them.
if(!istype(l.glasses, /obj/item/clothing/glasses/meson))
var/D = sqrt(1 / max(1, get_dist(l, src)))
- l.hallucination += power * config_hallucination_power * D
- l.hallucination = clamp(0, 200, l.hallucination)
-
+ l.hallucination += power * hallucination_power * D
+ l.hallucination = clamp(l.hallucination, 0, 200)
for(var/mob/living/l in range(src, round((power / 100) ** 0.25)))
var/rads = (power / 10) * sqrt( 1 / max(get_dist(l, src),1) )
l.rad_act(rads)
- power -= ((power/500)**3) * powerloss_inhibitor
+ //Transitions between one function and another, one we use for the fast inital startup, the other is used to prevent errors with fusion temperatures.
+ //Use of the second function improves the power gain imparted by using co2
+ if(power_changes)
+ power = max(power - min(((power/500)**3) * powerloss_inhibitor, power * 0.83 * powerloss_inhibitor),0)
+ //After this point power is lowered
+ //This wraps around to the begining of the function
+ //Handle high power zaps/anomaly generation
+ if(power > POWER_PENALTY_THRESHOLD || damage > damage_penalty_point) //If the power is above 5000 or if the damage is above 550
+ var/range = 4
+ zap_cutoff = 1500
+ if(removed && removed.return_pressure() > 0 && removed.return_temperature() > 0)
+ //You may be able to freeze the zapstate of the engine with good planning, we'll see
+ zap_cutoff = clamp(3000 - (power * (removed.total_moles()) / 10) / removed.return_temperature(), 350, 3000)//If the core is cold, it's easier to jump, ditto if there are a lot of mols
+ //We should always be able to zap our way out of the default enclosure
+ //See supermatter_zap() for more details
+ range = clamp(power / removed.return_pressure() * 10, 2, 7)
+ var/flags = ZAP_SUPERMATTER_FLAGS
+ var/zap_count = 0
+ //Deal with power zaps
+ switch(power)
+ if(POWER_PENALTY_THRESHOLD to SEVERE_POWER_PENALTY_THRESHOLD)
+ zap_icon = DEFAULT_ZAP_ICON_STATE
+ zap_count = 2
+ if(SEVERE_POWER_PENALTY_THRESHOLD to CRITICAL_POWER_PENALTY_THRESHOLD)
+ zap_icon = SLIGHTLY_CHARGED_ZAP_ICON_STATE
+ //Uncaps the zap damage, it's maxed by the input power
+ //Objects take damage now
+ flags |= (ZAP_MOB_DAMAGE | ZAP_OBJ_DAMAGE)
+ zap_count = 3
+ if(CRITICAL_POWER_PENALTY_THRESHOLD to INFINITY)
+ zap_icon = OVER_9000_ZAP_ICON_STATE
+ //It'll stun more now, and damage will hit harder, gloves are no garentee.
+ //Machines go boom
+ flags |= (ZAP_MOB_STUN | ZAP_MACHINE_EXPLOSIVE | ZAP_MOB_DAMAGE | ZAP_OBJ_DAMAGE)
+ zap_count = 4
+ //Now we deal with damage shit
+ if (damage > damage_penalty_point && prob(20))
+ zap_count += 1
- if(power > POWER_PENALTY_THRESHOLD || damage > damage_penalty_point)
+ if(zap_count >= 1)
+ playsound(src.loc, 'sound/weapons/emitter2.ogg', 100, TRUE, extrarange = 10)
+ for(var/i in 1 to zap_count)
+ supermatter_zap(src, range, clamp(power*2, 4000, 20000), flags)
- if(power > POWER_PENALTY_THRESHOLD)
- playsound(src.loc, 'sound/weapons/emitter2.ogg', 100, 1, extrarange = 10)
- supermatter_zap(src, 5, min(power*2, 20000))
- supermatter_zap(src, 5, min(power*2, 20000))
- if(power > SEVERE_POWER_PENALTY_THRESHOLD)
- supermatter_zap(src, 5, min(power*2, 20000))
- if(power > CRITICAL_POWER_PENALTY_THRESHOLD)
- supermatter_zap(src, 5, min(power*2, 20000))
- else if (damage > damage_penalty_point && prob(20))
- playsound(src.loc, 'sound/weapons/emitter2.ogg', 100, 1, extrarange = 10)
- supermatter_zap(src, 5, clamp(power*2, 4000, 20000))
-
- if(prob(15) && power > POWER_PENALTY_THRESHOLD)
- supermatter_pull(src, power/750)
if(prob(5))
supermatter_anomaly_gen(src, FLUX_ANOMALY, rand(5, 10))
if(power > SEVERE_POWER_PENALTY_THRESHOLD && prob(5) || prob(1))
supermatter_anomaly_gen(src, GRAVITATIONAL_ANOMALY, rand(5, 10))
- if(power > SEVERE_POWER_PENALTY_THRESHOLD && prob(2) || prob(0.3) && power > POWER_PENALTY_THRESHOLD)
+ if((power > SEVERE_POWER_PENALTY_THRESHOLD && prob(2)) || (prob(0.3) && power > POWER_PENALTY_THRESHOLD))
supermatter_anomaly_gen(src, PYRO_ANOMALY, rand(5, 10))
+
+ if(prob(15))
+ supermatter_pull(loc, min(power/850, 3))//850, 1700, 2550
+
+ //Tells the engi team to get their butt in gear
if(damage > warning_point) // while the core is still damaged and it's still worth noting its status
if((REALTIMEOFDAY - lastwarning) / 10 >= WARNING_DELAY)
alarm()
+ //Oh shit it's bad, time to freak out
if(damage > emergency_point)
radio.talk_into(src, "[emergency_alert] Integrity: [get_integrity()]%", common_channel)
lastwarning = REALTIMEOFDAY
@@ -493,7 +736,7 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
if(combined_gas > MOLE_PENALTY_THRESHOLD)
radio.talk_into(src, "Warning: Critical coolant mass reached.", engineering_channel)
-
+ //Boom (Mind blown)
if(damage > explosion_point)
countdown()
@@ -503,16 +746,17 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
var/turf/L = loc
if(!istype(L))
return FALSE
- if(!istype(Proj.firer, /obj/machinery/power/emitter))
+ if(!istype(Proj.firer, /obj/machinery/power/emitter) && power_changes)
investigate_log("has been hit by [Proj] fired by [key_name(Proj.firer)]", INVESTIGATE_SUPERMATTER)
if(Proj.flag != "bullet")
- power += Proj.damage * config_bullet_energy
- if(!has_been_powered)
- investigate_log("has been powered for the first time.", INVESTIGATE_SUPERMATTER)
- message_admins("[src] has been powered for the first time [ADMIN_JMP(src)].")
- has_been_powered = TRUE
+ if(power_changes) //This needs to be here I swear
+ power += Proj.damage * bullet_energy
+ if(!has_been_powered)
+ investigate_log("has been powered for the first time.", INVESTIGATE_SUPERMATTER)
+ message_admins("[src] has been powered for the first time [ADMIN_JMP(src)].")
+ has_been_powered = TRUE
else if(takes_damage)
- matter_power += Proj.damage * config_bullet_energy
+ matter_power += Proj.damage * bullet_energy
return BULLET_ACT_HIT
/obj/machinery/power/supermatter_crystal/singularity_act()
@@ -529,15 +773,15 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
/obj/machinery/power/supermatter_crystal/blob_act(obj/structure/blob/B)
if(B && !isspaceturf(loc)) //does nothing in space
- playsound(get_turf(src), 'sound/effects/supermatter.ogg', 50, 1)
+ playsound(get_turf(src), 'sound/effects/supermatter.ogg', 50, TRUE)
damage += B.obj_integrity * 0.5 //take damage equal to 50% of remaining blob health before it tried to eat us
if(B.obj_integrity > 100)
B.visible_message("\The [B] strikes at \the [src] and flinches away!",\
- "You hear a loud crack as you are washed with a wave of heat.")
+ "You hear a loud crack as you are washed with a wave of heat.")
B.take_damage(100, BURN)
else
B.visible_message("\The [B] strikes at \the [src] and rapidly flashes to ash.",\
- "You hear a loud crack as you are washed with a wave of heat.")
+ "You hear a loud crack as you are washed with a wave of heat.")
Consume(B)
/obj/machinery/power/supermatter_crystal/attack_tk(mob/user)
@@ -546,11 +790,10 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
log_game("[key_name(C)] has been disintegrated by a telekenetic grab on a supermatter crystal.")
to_chat(C, "That was a really dense idea.")
C.visible_message("A bright flare of radiation is seen from [C]'s head, shortly before you hear a sickening sizzling!")
+ C.ghostize()
var/obj/item/organ/brain/rip_u = locate(/obj/item/organ/brain) in C.internal_organs
- rip_u.Remove()
+ rip_u.Remove(C)
qdel(rip_u)
- return
- return ..()
/obj/machinery/power/supermatter_crystal/attack_paw(mob/user)
dust_mob(user, cause = "monkey attack")
@@ -559,9 +802,14 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
dust_mob(user, cause = "alien attack")
/obj/machinery/power/supermatter_crystal/attack_animal(mob/living/simple_animal/S)
+ var/murder
+ if(!S.melee_damage_upper && !S.melee_damage_lower)
+ murder = S.friendly_verb_continuous
+ else
+ murder = S.attack_verb_continuous
dust_mob(S, \
- "[S] unwisely [S.attack_verb_continuous] [src], and [S.p_their()] body burns brilliantly before flashing into ash!", \
- "You unwisely [S.attack_verb_simple] [src], and your vision glows brightly as your body crumbles to dust. Oops.", \
+ "[S] unwisely [murder] [src], and [S.p_their()] body burns brilliantly before flashing into ash!", \
+ "You unwisely touch [src], and your vision glows brightly as your body crumbles to dust. Oops.", \
"simple animal attack")
/obj/machinery/power/supermatter_crystal/attack_robot(mob/user)
@@ -571,65 +819,103 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
/obj/machinery/power/supermatter_crystal/attack_ai(mob/user)
return
-/obj/machinery/power/supermatter_crystal/on_attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags)
+/obj/machinery/power/supermatter_crystal/on_attack_hand(mob/living/user)
. = ..()
- if(.)
- return
dust_mob(user, cause = "hand")
/obj/machinery/power/supermatter_crystal/proc/dust_mob(mob/living/nom, vis_msg, mob_msg, cause)
- if(nom.incorporeal_move || nom.status_flags & GODMODE)
+ if(nom.incorporeal_move || nom.status_flags & GODMODE) //try to keep supermatter sliver's + hemostat's dust conditions in sync with this too
return
if(!vis_msg)
- vis_msg = "[nom] reaches out and touches [src], inducing a resonance... [nom.p_their()] body starts to glow and bursts into flames before flashing into ash"
+ vis_msg = "[nom] reaches out and touches [src], inducing a resonance... [nom.p_their()] body starts to glow and burst into flames before flashing into dust!"
if(!mob_msg)
mob_msg = "You reach out and touch [src]. Everything starts burning and all you can hear is ringing. Your last thought is \"That was not a wise decision.\""
if(!cause)
cause = "contact"
- nom.visible_message(vis_msg, mob_msg, "You hear an unearthly noise as a wave of heat washes over you.")
+ nom.visible_message(vis_msg, mob_msg, "You hear an unearthly noise as a wave of heat washes over you.")
investigate_log("has been attacked ([cause]) by [key_name(nom)]", INVESTIGATE_SUPERMATTER)
- playsound(get_turf(src), 'sound/effects/supermatter.ogg', 50, 1)
+ playsound(get_turf(src), 'sound/effects/supermatter.ogg', 50, TRUE)
Consume(nom)
/obj/machinery/power/supermatter_crystal/attackby(obj/item/W, mob/living/user, params)
if(!istype(W) || (W.item_flags & ABSTRACT) || !istype(user))
return
- if (istype(W, /obj/item/melee/roastingstick))
+ if(istype(W, /obj/item/melee/roastingstick))
return ..()
+ if(istype(W, /obj/item/clothing/mask/cigarette))
+ var/obj/item/clothing/mask/cigarette/cig = W
+ var/clumsy = HAS_TRAIT(user, TRAIT_CLUMSY)
+ if(clumsy)
+ var/which_hand = BODY_ZONE_L_ARM
+ if(!(user.active_hand_index % 2))
+ which_hand = BODY_ZONE_R_ARM
+ var/obj/item/bodypart/dust_arm = user.get_bodypart(which_hand)
+ dust_arm.dismember()
+ user.visible_message("The [W] flashes out of existence on contact with \the [src], resonating with a horrible sound...",\
+ "Oops! The [W] flashes out of existence on contact with \the [src], taking your arm with it! That was clumsy of you!")
+ playsound(src, 'sound/effects/supermatter.ogg', 150, TRUE)
+ Consume(dust_arm)
+ qdel(W)
+ return
+ if(cig.lit || user.a_intent != INTENT_HELP)
+ user.visible_message("A hideous sound echoes as [W] is ashed out on contact with \the [src]. That didn't seem like a good idea...")
+ playsound(src, 'sound/effects/supermatter.ogg', 150, TRUE)
+ Consume(W)
+ radiation_pulse(src, 150, 4)
+ return ..()
+ else
+ cig.light()
+ user.visible_message("As [user] lights \their [W] on \the [src], silence fills the room...",\
+ "Time seems to slow to a crawl as you touch \the [src] with \the [W].\n\The [W] flashes alight with an eerie energy as you nonchalantly lift your hand away from \the [src]. Damn.")
+ playsound(src, 'sound/effects/supermatter.ogg', 50, TRUE)
+ radiation_pulse(src, 50, 3)
+ return
if(istype(W, /obj/item/scalpel/supermatter))
+ var/obj/item/scalpel/supermatter/scalpel = W
to_chat(user, "You carefully begin to scrape \the [src] with \the [W]...")
if(W.use_tool(src, user, 60, volume=100))
- to_chat(user, "You extract a sliver from \the [src]. \The [src] begins to react violently!")
- new /obj/item/nuke_core/supermatter_sliver(drop_location())
- matter_power += 200
+ if (scalpel.usesLeft)
+ to_chat(user, "You extract a sliver from \the [src]. \The [src] begins to react violently!")
+ new /obj/item/nuke_core/supermatter_sliver(drop_location())
+ matter_power += 800
+ scalpel.usesLeft--
+ if (!scalpel.usesLeft)
+ to_chat(user, "A tiny piece of \the [W] falls off, rendering it useless!")
+ else
+ to_chat(user, "You fail to extract a sliver from \The [src]! \the [W] isn't sharp enough anymore.")
else if(user.dropItemToGround(W))
user.visible_message("As [user] touches \the [src] with \a [W], silence fills the room...",\
"You touch \the [src] with \the [W], and everything suddenly goes silent.\n\The [W] flashes into dust as you flinch away from \the [src].",\
- "Everything suddenly goes silent.")
+ "Everything suddenly goes silent.")
investigate_log("has been attacked ([W]) by [key_name(user)]", INVESTIGATE_SUPERMATTER)
Consume(W)
- playsound(get_turf(src), 'sound/effects/supermatter.ogg', 50, 1)
+ playsound(get_turf(src), 'sound/effects/supermatter.ogg', 50, TRUE)
radiation_pulse(src, 150, 4)
+ else if(Adjacent(user)) //if the item is stuck to the person, kill the person too instead of eating just the item.
+ var/vis_msg = "[user] reaches out and touches [src] with [W], inducing a resonance... [W] starts to glow briefly before the light continues up to [user]'s body. [user.p_they(TRUE)] bursts into flames before flashing into dust!"
+ var/mob_msg = "You reach out and touch [src] with [W]. Everything starts burning and all you can hear is ringing. Your last thought is \"That was not a wise decision.\""
+ dust_mob(user, vis_msg, mob_msg)
+
/obj/machinery/power/supermatter_crystal/wrench_act(mob/user, obj/item/tool)
+ ..()
if (moveable)
default_unfasten_wrench(user, tool, time = 20)
return TRUE
/obj/machinery/power/supermatter_crystal/Bumped(atom/movable/AM)
if(isliving(AM))
- AM.visible_message("\The [AM] slams into \the [src] inducing a resonance... [AM.p_their()] body starts to glow and catch flame before flashing into ash.",\
+ AM.visible_message("\The [AM] slams into \the [src] inducing a resonance... [AM.p_their()] body starts to glow and burst into flames before flashing into dust!",\
"You slam into \the [src] as your ears are filled with unearthly ringing. Your last thought is \"Oh, fuck.\"",\
- "You hear an unearthly noise as a wave of heat washes over you.")
+ "You hear an unearthly noise as a wave of heat washes over you.")
else if(isobj(AM) && !iseffect(AM))
AM.visible_message("\The [AM] smacks into \the [src] and rapidly flashes to ash.", null,\
- "You hear a loud crack as you are washed with a wave of heat.")
+ "You hear a loud crack as you are washed with a wave of heat.")
else
return
- playsound(get_turf(src), 'sound/effects/supermatter.ogg', 50, 1)
-
+ playsound(get_turf(src), 'sound/effects/supermatter.ogg', 50, TRUE)
Consume(AM)
/obj/machinery/power/supermatter_crystal/intercept_zImpact(atom/movable/AM, levels)
@@ -645,7 +931,8 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
message_admins("[src] has consumed [key_name_admin(user)] [ADMIN_JMP(src)].")
investigate_log("has consumed [key_name(user)].", INVESTIGATE_SUPERMATTER)
user.dust(force = TRUE)
- matter_power += 200
+ if(power_changes)
+ matter_power += 200
else if(istype(AM, /obj/singularity))
return
else if(isobj(AM))
@@ -656,19 +943,29 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
message_admins("[src] has consumed [AM], [suspicion] [ADMIN_JMP(src)].")
investigate_log("has consumed [AM] - [suspicion].", INVESTIGATE_SUPERMATTER)
qdel(AM)
- if(!iseffect(AM))
+ if(!iseffect(AM) && power_changes)
matter_power += 200
//Some poor sod got eaten, go ahead and irradiate people nearby.
radiation_pulse(src, 3000, 2, TRUE)
- var/list/viewers = fov_viewers(world.view, src)
for(var/mob/living/L in range(10))
investigate_log("has irradiated [key_name(L)] after consuming [AM].", INVESTIGATE_SUPERMATTER)
+ var/list/viewers = fov_viewers(world.view, src)
if(L in viewers)
L.show_message("As \the [src] slowly stops resonating, you find your skin covered in new radiation burns.", MSG_VISUAL,\
"The unearthly ringing subsides and you notice you have new radiation burns.", MSG_AUDIBLE)
else
- L.show_message("You hear an unearthly ringing and notice your skin is covered in fresh radiation burns.", MSG_AUDIBLE)
+ L.show_message("You hear an unearthly ringing and notice your skin is covered in fresh radiation burns.", MSG_AUDIBLE)
+
+/obj/machinery/power/supermatter_crystal/proc/consume_turf(turf/T)
+ var/oldtype = T.type
+ var/turf/newT = T.ScrapeAway()
+ if(newT.type == oldtype)
+ return
+ playsound(T, 'sound/effects/supermatter.ogg', 50, 1)
+ T.visible_message("[T] smacks into [src] and rapidly flashes to ash.",\
+ "You hear a loud crack as you are washed with a wave of heat.")
+ CALCULATE_ADJACENT_TURFS(T)
//Do not blow up our internal radio
/obj/machinery/power/supermatter_crystal/contents_explosion(severity, target)
@@ -685,6 +982,7 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
anchored = FALSE
gasefficency = 0.125
explosion_power = 12
+ layer = ABOVE_MOB_LAYER
moveable = TRUE
/obj/machinery/power/supermatter_crystal/shard/engine
@@ -699,6 +997,8 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
name = "anchored supermatter shard"
takes_damage = FALSE
produces_gas = FALSE
+ power_changes = FALSE
+ processes = FALSE //SHUT IT DOWN
moveable = FALSE
anchored = TRUE
@@ -707,101 +1007,183 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
base_icon_state = "darkmatter"
icon_state = "darkmatter"
-/obj/machinery/power/supermatter_crystal/proc/supermatter_pull(turf/center, pull_range = 10)
- playsound(src.loc, 'sound/weapons/marauder.ogg', 100, 1, extrarange = 7)
- for(var/atom/P in orange(pull_range,center))
- if(ismovable(P))
- var/atom/movable/pulled_object = P
- if(ishuman(P))
- var/mob/living/carbon/human/H = P
- H.apply_effect(40, EFFECT_KNOCKDOWN, 0)
- if(pulled_object && !pulled_object.anchored && !ishuman(P))
- step_towards(pulled_object,center)
- step_towards(pulled_object,center)
- step_towards(pulled_object,center)
- step_towards(pulled_object,center)
+/obj/machinery/power/supermatter_crystal/proc/supermatter_pull(turf/center, pull_range = 3)
+ playsound(center, 'sound/weapons/marauder.ogg', 100, TRUE, extrarange = pull_range - world.view)
+ for(var/atom/movable/P in orange(pull_range,center))
+ if((P.anchored || P.move_resist >= MOVE_FORCE_EXTREMELY_STRONG)) //move resist memes.
+ if(istype(P, /obj/structure/closet))
+ var/obj/structure/closet/toggle = P
+ toggle.open()
+ continue
+ if(ismob(P))
+ var/mob/M = P
+ if(M.mob_negates_gravity())
+ continue //You can't pull someone nailed to the deck
+ step_towards(P,center)
/obj/machinery/power/supermatter_crystal/proc/supermatter_anomaly_gen(turf/anomalycenter, type = FLUX_ANOMALY, anomalyrange = 5)
var/turf/L = pick(orange(anomalyrange, anomalycenter))
if(L)
switch(type)
if(FLUX_ANOMALY)
- var/obj/effect/anomaly/flux/A = new(L, 300)
+ var/obj/effect/anomaly/flux/A = new(L, 300, FALSE)
A.explosive = FALSE
if(GRAVITATIONAL_ANOMALY)
- new /obj/effect/anomaly/grav(L, 250)
+ new /obj/effect/anomaly/grav(L, 250, FALSE)
if(PYRO_ANOMALY)
- new /obj/effect/anomaly/pyro(L, 200)
+ new /obj/effect/anomaly/pyro(L, 200, FALSE)
-/obj/machinery/power/supermatter_crystal/proc/supermatter_zap(atom/zapstart, range = 3, power)
- . = zapstart.dir
- if(power < 1000)
+/obj/machinery/power/supermatter_crystal/proc/supermatter_zap(atom/zapstart = src, range = 5, zap_str = 4000, zap_flags = ZAP_SUPERMATTER_FLAGS, list/targets_hit = list())
+ if(QDELETED(zapstart))
return
+ . = zapstart.dir
+ //If the strength of the zap decays past the cutoff, we stop
+ if(zap_str < zap_cutoff)
+ return
+ var/atom/target
+ var/target_type = LOWEST
+ var/list/arctargets = list()
+ //Making a new copy so additons further down the recursion do not mess with other arcs
+ //Lets put this ourself into the do not hit list, so we don't curve back to hit the same thing twice with one arc
+ for(var/test in oview(zapstart, range))
+ if(!(zap_flags & ZAP_ALLOW_DUPLICATES) && LAZYACCESS(targets_hit, test))
+ continue
- var/target_atom
- var/mob/living/target_mob
- var/obj/machinery/target_machine
- var/obj/structure/target_structure
- var/list/arctargetsmob = list()
- var/list/arctargetsmachine = list()
- var/list/arctargetsstructure = list()
+ if(istype(test, /obj/vehicle/ridden/bicycle/))
+ var/obj/vehicle/ridden/bicycle/bike = test
+ if(!(bike.obj_flags & BEING_SHOCKED) && bike.can_buckle)//God's not on our side cause he hates idiots.
+ if(target_type != BIKE)
+ arctargets = list()
+ arctargets += test
+ target_type = BIKE
- if(prob(20)) //let's not hit all the engineers with every beam and/or segment of the arc
- for(var/mob/living/Z in oview(zapstart, range+2))
- arctargetsmob += Z
- if(arctargetsmob.len)
- var/mob/living/H = pick(arctargetsmob)
- var/atom/A = H
- target_mob = H
- target_atom = A
+ if(target_type > COIL)
+ continue
- else
- for(var/obj/machinery/X in oview(zapstart, range+2))
- arctargetsmachine += X
- if(arctargetsmachine.len)
- var/obj/machinery/M = pick(arctargetsmachine)
- var/atom/A = M
- target_machine = M
- target_atom = A
+ if(istype(test, /obj/machinery/power/tesla_coil/))
+ var/obj/machinery/power/tesla_coil/coil = test
+ if(coil.anchored && !(coil.obj_flags & BEING_SHOCKED) && !coil.panel_open && prob(70))//Diversity of death
+ if(target_type != COIL)
+ arctargets = list()
+ arctargets += test
+ target_type = COIL
- else
- for(var/obj/structure/Y in oview(zapstart, range+2))
- arctargetsstructure += Y
- if(arctargetsstructure.len)
- var/obj/structure/O = pick(arctargetsstructure)
- var/atom/A = O
- target_structure = O
- target_atom = A
+ if(target_type > ROD)
+ continue
- if(target_atom)
- zapstart.Beam(target_atom, icon_state="nzcrentrs_power", time=5)
- var/zapdir = get_dir(zapstart, target_atom)
+ if(istype(test, /obj/machinery/power/grounding_rod/))
+ var/obj/machinery/power/grounding_rod/rod = test
+ //We're adding machine damaging effects, rods need to be surefire
+ if(rod.anchored && !rod.panel_open)
+ if(target_type != ROD)
+ arctargets = list()
+ arctargets += test
+ target_type = ROD
+
+ if(target_type > LIVING)
+ continue
+
+ if(istype(test, /mob/living/))
+ var/mob/living/alive = test
+ if(!(HAS_TRAIT(alive, TRAIT_TESLA_SHOCKIMMUNE)) && !(alive.flags_1 & SHOCKED_1) && alive.stat != DEAD && prob(20))//let's not hit all the engineers with every beam and/or segment of the arc
+ if(target_type != LIVING)
+ arctargets = list()
+ arctargets += test
+ target_type = LIVING
+
+ if(target_type > MACHINERY)
+ continue
+
+ if(istype(test, /obj/machinery/))
+ var/obj/machinery/machine = test
+ if(!(machine.obj_flags & BEING_SHOCKED) && prob(40))
+ if(target_type != MACHINERY)
+ arctargets = list()
+ arctargets += test
+ target_type = MACHINERY
+
+ if(target_type > OBJECT)
+ continue
+
+ if(istype(test, /obj/))
+ var/obj/object = test
+ if(!(object.obj_flags & BEING_SHOCKED))
+ if(target_type != OBJECT)
+ arctargets = list()
+ arctargets += test
+ target_type = OBJECT
+
+ if(arctargets.len)//Pick from our pool
+ target = pick(arctargets)
+
+ if(!QDELETED(target))//If we found something
+ //Do the animation to zap to it from here
+ if(!(zap_flags & ZAP_ALLOW_DUPLICATES))
+ LAZYSET(targets_hit, target, TRUE)
+ zapstart.Beam(target, icon_state=zap_icon, time=5)
+ var/zapdir = get_dir(zapstart, target)
if(zapdir)
. = zapdir
- if(target_mob)
- target_mob.electrocute_act(rand(5,10), "Supermatter Discharge Bolt", 1, SHOCK_NOSTUN)
- if(prob(15))
- supermatter_zap(target_mob, 5, power / 2)
- supermatter_zap(target_mob, 5, power / 2)
- else
- supermatter_zap(target_mob, 5, power / 1.5)
+ //Going boom should be rareish
+ if(prob(80))
+ zap_flags &= ~ZAP_MACHINE_EXPLOSIVE
+ if(target_type == COIL)
+ //In the best situation we can expect this to grow up to 2120kw before a delam/IT'S GONE TOO FAR FRED SHUT IT DOWN
+ //The formula for power gen is zap_str * zap_mod / 2 * capacitor rating, between 1 and 4
+ var/multi = 10
+ switch(power)//Between 7k and 9k it's 20, above that it's 40
+ if(SEVERE_POWER_PENALTY_THRESHOLD to CRITICAL_POWER_PENALTY_THRESHOLD)
+ multi = 20
+ if(CRITICAL_POWER_PENALTY_THRESHOLD to INFINITY)
+ multi = 40
+ target.zap_act(zap_str * multi, zap_flags, list())
+ zap_str /= 3 //Coils should take a lot out of the power of the zap
- else if(target_machine)
- if(prob(15))
- supermatter_zap(target_machine, 5, power / 2)
- supermatter_zap(target_machine, 5, power / 2)
- else
- supermatter_zap(target_machine, 5, power / 1.5)
+ else if(target_type == ROD)
+ //We can expect this to do very little, maybe shock the poor soul buckled to it, but that's all.
+ //This is one of our endpoints, if the bolt hits a grounding rod, it stops jumping
+ target.zap_act(zap_str, zap_flags, list())
+ return
+
+ else if(isliving(target))//If we got a fleshbag on our hands
+ var/mob/living/creature = target
+ creature.set_shocked()
+ addtimer(CALLBACK(creature, /mob/living/proc/reset_shocked), 10)
+ //3 shots a human with no resistance. 2 to crit, one to death. This is at at least 10000 power.
+ //There's no increase after that because the input power is effectivly capped at 10k
+ //Does 1.5 damage at the least
+ var/shock_damage = ((zap_flags & ZAP_MOB_DAMAGE) ? (power / 200) - 10 : rand(5,10))
+ creature.electrocute_act(shock_damage, "Supermatter Discharge Bolt", 1, ((zap_flags & ZAP_MOB_STUN) ? SHOCK_TESLA : SHOCK_NOSTUN))
+ zap_str /= 1.5 //Meatsacks are conductive, makes working in pairs more destructive
- else if(target_structure)
- if(prob(15))
- supermatter_zap(target_structure, 5, power / 2)
- supermatter_zap(target_structure, 5, power / 2)
else
- supermatter_zap(target_structure, 5, power / 1.5)
+ target.zap_act(zap_str, zap_flags, list())
+ zap_str /= 2 // worse then living things, better then coils
+ //This gotdamn variable is a boomer and keeps giving me problems
+ var/turf/T = get_turf(target)
+ var/pressure = 1
+ if(T && T.return_air())
+ pressure = max(1,T.return_air().return_pressure())
+ //We get our range with the strength of the zap and the pressure, the higher the former and the lower the latter the better
+ var/new_range = clamp(zap_str / pressure * 10, 2, 7)
+ var/zap_count = 1
+ if(prob(5))
+ zap_str -= (zap_str/10)
+ zap_count += 1
+ for(var/j in 1 to zap_count)
+ if(zap_count > 1)
+ targets_hit = targets_hit.Copy() //Pass by ref begone
+ supermatter_zap(target, new_range, zap_str, zap_flags, targets_hit)
#undef HALLUCINATION_RANGE
#undef GRAVITATIONAL_ANOMALY
#undef FLUX_ANOMALY
#undef PYRO_ANOMALY
+#undef BIKE
+#undef COIL
+#undef ROD
+#undef LIVING
+#undef MACHINERY
+#undef OBJECT
+#undef LOWEST
diff --git a/code/modules/projectiles/ammunition/ballistic/revolver.dm b/code/modules/projectiles/ammunition/ballistic/revolver.dm
index 693b258e3d..c13a3c953d 100644
--- a/code/modules/projectiles/ammunition/ballistic/revolver.dm
+++ b/code/modules/projectiles/ammunition/ballistic/revolver.dm
@@ -14,9 +14,13 @@
/obj/item/ammo_casing/a357/match
name = ".357 match bullet casing"
desc = "A .357 bullet casing, manufactured to exceedingly high standards."
- caliber = "357"
projectile_type = /obj/item/projectile/bullet/a357/match
+/obj/item/ammo_casing/a357/dumdum
+ name = ".357 DumDum bullet casing"
+ desc = "A .357 bullet casing. Usage of this ammunition will constitute a war crime in your area."
+ projectile_type = /obj/item/projectile/bullet/a357/dumdum
+
// 7.62x38mmR (Nagant Revolver)
/obj/item/ammo_casing/n762
@@ -68,4 +72,4 @@
/obj/item/ammo_casing/c38/dumdum
name = ".38 DumDum bullet casing"
desc = "A .38 DumDum bullet casing."
- projectile_type = /obj/item/projectile/bullet/c38/dumdum
\ No newline at end of file
+ projectile_type = /obj/item/projectile/bullet/c38/dumdum
diff --git a/code/modules/projectiles/boxes_magazines/_box_magazine.dm b/code/modules/projectiles/boxes_magazines/_box_magazine.dm
index 9ea030da99..78ca6e9280 100644
--- a/code/modules/projectiles/boxes_magazines/_box_magazine.dm
+++ b/code/modules/projectiles/boxes_magazines/_box_magazine.dm
@@ -20,6 +20,7 @@
var/caliber
var/multiload = 1
var/start_empty = 0
+ var/load_delay = 0 //how long do we take to load (deciseconds)
var/list/bullet_cost
var/list/base_cost// override this one as well if you override bullet_cost
@@ -75,12 +76,19 @@
return 1
/obj/item/ammo_box/attackby(obj/item/A, mob/user, params, silent = FALSE, replace_spent = 0)
+ if(INTERACTING_WITH(user, src) || INTERACTING_WITH(user, A))
+ to_chat(user, "You're already doing that!")
+ return FALSE
var/num_loaded = 0
if(!can_load(user))
return
if(istype(A, /obj/item/ammo_box))
var/obj/item/ammo_box/AM = A
for(var/obj/item/ammo_casing/AC in AM.stored_ammo)
+ if(load_delay || AM.load_delay)
+ var/loadtime = max(AM.load_delay, load_delay)
+ if(!do_after(user, loadtime, target = src))
+ return FALSE
var/did_load = give_round(AC, replace_spent)
if(did_load)
AM.stored_ammo -= AC
diff --git a/code/modules/projectiles/boxes_magazines/ammo_boxes.dm b/code/modules/projectiles/boxes_magazines/ammo_boxes.dm
index 987efc0404..0b00c89c02 100644
--- a/code/modules/projectiles/boxes_magazines/ammo_boxes.dm
+++ b/code/modules/projectiles/boxes_magazines/ammo_boxes.dm
@@ -16,6 +16,11 @@
name = "speed loader (.357 AP)"
ammo_type = /obj/item/ammo_casing/a357/ap
+/obj/item/ammo_box/a357/dumdum
+ name = "speed loader (.357 DumDum)"
+ desc = "Designed to quickly reload revolvers. Usage of these rounds will constitute a war crime in your area."
+ ammo_type = /obj/item/ammo_casing/a357/dumdum
+
/obj/item/ammo_box/c38
name = "speed loader (.38 rubber)"
desc = "Designed to quickly reload revolvers."
@@ -148,6 +153,8 @@
max_ammo = 4
var/pixeloffsetx = 4
start_empty = TRUE
+ multiload = FALSE
+ load_delay = 6 //6ds
/obj/item/ammo_box/shotgun/update_overlays()
. = ..()
diff --git a/code/modules/projectiles/guns/ballistic.dm b/code/modules/projectiles/guns/ballistic.dm
index fa8099a257..1aefa51a51 100644
--- a/code/modules/projectiles/guns/ballistic.dm
+++ b/code/modules/projectiles/guns/ballistic.dm
@@ -53,6 +53,8 @@
..()
if (istype(A, /obj/item/ammo_box/magazine))
var/obj/item/ammo_box/magazine/AM = A
+ if(AM.load_delay && !do_after(user, AM.load_delay, target = src))
+ return FALSE
if (!magazine && istype(AM, mag_type))
if(user.transferItemToLoc(AM, src))
magazine = AM
diff --git a/code/modules/projectiles/projectile/bullets/revolver.dm b/code/modules/projectiles/projectile/bullets/revolver.dm
index 95d43ba1ce..ec3cadc31a 100644
--- a/code/modules/projectiles/projectile/bullets/revolver.dm
+++ b/code/modules/projectiles/projectile/bullets/revolver.dm
@@ -126,4 +126,15 @@
ricochet_auto_aim_angle = 50
ricochet_auto_aim_range = 6
ricochet_incidence_leeway = 80
- ricochet_decay_chance = 1
\ No newline at end of file
+ ricochet_decay_chance = 1
+
+/obj/item/projectile/bullet/a357/dumdum
+ name = ".357 DumDum bullet" // the warcrime bullet
+ damage = 40
+ armour_penetration = -20
+ wound_bonus = 45
+ bare_wound_bonus = 45
+ sharpness = SHARP_EDGED
+ embedding = list(embed_chance=90, fall_chance=2, jostle_chance=5, ignore_throwspeed_threshold=TRUE, pain_stam_pct=0.4, pain_mult=5, jostle_pain_mult=6, rip_time=10)
+ wound_falloff_tile = -1
+ embed_falloff_tile = -5
diff --git a/code/modules/projectiles/projectile/special/plasma.dm b/code/modules/projectiles/projectile/special/plasma.dm
index 33559fa92c..77509cb574 100644
--- a/code/modules/projectiles/projectile/special/plasma.dm
+++ b/code/modules/projectiles/projectile/special/plasma.dm
@@ -2,7 +2,7 @@
name = "plasma blast"
icon_state = "plasmacutter"
damage_type = BRUTE
- damage = 20
+ damage = 10
range = 4
dismemberment = 20
impact_effect_type = /obj/effect/temp_visual/impact_effect/purple_laser
@@ -32,12 +32,12 @@
return BULLET_ACT_FORCE_PIERCE
/obj/item/projectile/plasma/adv
- damage = 28
+ damage = 14
range = 5
mine_range = 5
/obj/item/projectile/plasma/adv/mech
- damage = 40
+ damage = 20
range = 9
mine_range = 3
@@ -52,4 +52,4 @@
dismemberment = 0
damage = 10
range = 4
- mine_range = 0
\ No newline at end of file
+ mine_range = 0
diff --git a/code/modules/reagents/chemistry/reagents/food_reagents.dm b/code/modules/reagents/chemistry/reagents/food_reagents.dm
index a6e78ae98c..18203f1a4c 100644
--- a/code/modules/reagents/chemistry/reagents/food_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/food_reagents.dm
@@ -132,8 +132,8 @@
"You're covered in boiling oil!")
M.emote("scream")
playsound(M, 'sound/machines/fryer/deep_fryer_emerge.ogg', 25, TRUE)
- var/oil_damage = max((holder.chem_temp / fry_temperature) * 0.33,1) //Damage taken per unit
- M.adjustFireLoss(oil_damage * max(reac_volume,20)) //Damage caps at 20
+ var/oil_damage = min((holder.chem_temp / fry_temperature) * 0.33,1) //Damage taken per unit
+ M.adjustFireLoss(oil_damage * min(reac_volume,20)) //Damage caps at 20
else
..()
return TRUE
diff --git a/code/modules/reagents/chemistry/reagents/other_reagents.dm b/code/modules/reagents/chemistry/reagents/other_reagents.dm
index b6de7b2eab..3433824282 100644
--- a/code/modules/reagents/chemistry/reagents/other_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/other_reagents.dm
@@ -883,7 +883,7 @@
if(istype(O, /obj/item/stack/sheet/metal))
var/obj/item/stack/sheet/metal/M = O
reac_volume = min(reac_volume, M.amount)
- new/obj/item/stack/tile/bronze(get_turf(M), reac_volume)
+ new/obj/item/stack/sheet/bronze(get_turf(M), reac_volume)
M.use(reac_volume)
/datum/reagent/nitrogen
@@ -2218,6 +2218,7 @@
color = "#FFFFFF" // rgb: 255, 255, 255
can_synth = FALSE
nutriment_factor = 0.5 * REAGENTS_METABOLISM
+ var/decal_path = /obj/effect/decal/cleanable/semen
/datum/reagent/consumable/semen/reaction_turf(turf/T, reac_volume)
if(!istype(T))
@@ -2227,7 +2228,7 @@
var/obj/effect/decal/cleanable/semen/S = locate() in T
if(!S)
- S = new(T)
+ S = new decal_path(T)
if(data["blood_DNA"])
S.add_blood_DNA(list(data["blood_DNA"] = data["blood_type"]))
@@ -2251,51 +2252,20 @@
blood_DNA |= S.blood_DNA
return ..()
-/datum/reagent/consumable/femcum
+/datum/reagent/consumable/semen/femcum
name = "Female Ejaculate"
description = "Vaginal lubricant found in most mammals and other animals of similar nature. Where you found this is your own business."
taste_description = "something with a tang" // wew coders who haven't eaten out a girl.
- taste_mult = 2
- data = list("donor"=null,"viruses"=null,"donor_DNA"=null,"blood_type"=null,"resistances"=null,"trace_chem"=null,"mind"=null,"ckey"=null,"gender"=null,"real_name"=null)
- reagent_state = LIQUID
color = "#AAAAAA77"
- can_synth = FALSE
- nutriment_factor = 0.5 * REAGENTS_METABOLISM
+ decal_path = /obj/effect/decal/cleanable/semen/femcum
-/obj/effect/decal/cleanable/femcum
+/obj/effect/decal/cleanable/semen/femcum
name = "female ejaculate"
- desc = null
- gender = PLURAL
- density = 0
- layer = ABOVE_NORMAL_TURF_LAYER
- icon = 'icons/obj/genitals/effects.dmi'
icon_state = "fem1"
random_icon_states = list("fem1", "fem2", "fem3", "fem4")
blood_state = null
bloodiness = null
-/obj/effect/decal/cleanable/femcum/Initialize(mapload)
- . = ..()
- dir = GLOB.cardinals
- add_blood_DNA(list("Non-human DNA" = "A+"))
-
-/obj/effect/decal/cleanable/femcum/replace_decal(obj/effect/decal/cleanable/femcum/F)
- if(F.blood_DNA)
- blood_DNA |= F.blood_DNA
- return ..()
-
-/datum/reagent/consumable/femcum/reaction_turf(turf/T, reac_volume)
- if(!istype(T))
- return
- if(reac_volume < 10)
- return
-
- var/obj/effect/decal/cleanable/femcum/S = locate() in T
- if(!S)
- S = new(T)
- if(data["blood_DNA"])
- S.add_blood_DNA(list(data["blood_DNA"] = data["blood_type"]))
-
/datum/reagent/determination
name = "Determination"
description = "For when you need to push on a little more. Do NOT allow near plants."
@@ -2331,6 +2301,32 @@
M.adjustStaminaLoss(-0.25*REM) // the more wounds, the more stamina regen
..()
+datum/reagent/eldritch
+ name = "Eldritch Essence"
+ description = "Strange liquid that defies the laws of physics"
+ taste_description = "Ag'hsj'saje'sh"
+ color = "#1f8016"
+
+/datum/reagent/eldritch/on_mob_life(mob/living/carbon/M)
+ if(IS_HERETIC(M))
+ M.drowsyness = max(M.drowsyness-5, 0)
+ M.AdjustAllImmobility(-40, FALSE)
+ M.adjustStaminaLoss(-15, FALSE)
+ M.adjustToxLoss(-3, FALSE)
+ M.adjustOxyLoss(-3, FALSE)
+ M.adjustBruteLoss(-3, FALSE)
+ M.adjustFireLoss(-3, FALSE)
+ if(ishuman(M) && M.blood_volume < BLOOD_VOLUME_NORMAL)
+ M.blood_volume += 3
+ else
+ M.adjustOrganLoss(ORGAN_SLOT_BRAIN, 3, 150)
+ M.adjustToxLoss(2, FALSE)
+ M.adjustFireLoss(2, FALSE)
+ M.adjustOxyLoss(2, FALSE)
+ M.adjustBruteLoss(2, FALSE)
+ holder.remove_reagent(type, 1)
+ return TRUE
+
/datum/reagent/cellulose
name = "Cellulose Fibers"
description = "A crystaline polydextrose polymer, plants swear by this stuff."
diff --git a/code/modules/research/nanites/extra_settings/text.dm b/code/modules/research/nanites/extra_settings/text.dm
index 56aa3dd07f..d3cad27bcf 100644
--- a/code/modules/research/nanites/extra_settings/text.dm
+++ b/code/modules/research/nanites/extra_settings/text.dm
@@ -10,6 +10,9 @@
/datum/nanite_extra_setting/text/get_copy()
return new /datum/nanite_extra_setting/text(value)
+/datum/nanite_extra_setting/text/get_value()
+ return html_encode(value)
+
/datum/nanite_extra_setting/text/get_frontend_list(name)
return list(list(
"name" = name,
diff --git a/code/modules/research/nanites/nanite_cloud_controller.dm b/code/modules/research/nanites/nanite_cloud_controller.dm
index 1a0a5dbd4d..44ebe11c29 100644
--- a/code/modules/research/nanites/nanite_cloud_controller.dm
+++ b/code/modules/research/nanites/nanite_cloud_controller.dm
@@ -36,8 +36,9 @@
/obj/machinery/computer/nanite_cloud_controller/proc/eject(mob/living/user)
if(!disk)
return
- if(!istype(user) || !Adjacent(user))// ||!user.put_in_active_hand(disk))
- disk.forceMove(drop_location())
+ disk.forceMove(drop_location())
+ if(istype(user) && user.Adjacent(src))
+ user.put_in_active_hand(disk)
disk = null
/obj/machinery/computer/nanite_cloud_controller/proc/get_backup(cloud_id)
diff --git a/code/modules/research/nanites/nanite_program_hub.dm b/code/modules/research/nanites/nanite_program_hub.dm
index 5a330f7a4f..495c788845 100644
--- a/code/modules/research/nanites/nanite_program_hub.dm
+++ b/code/modules/research/nanites/nanite_program_hub.dm
@@ -53,8 +53,9 @@
/obj/machinery/nanite_program_hub/proc/eject(mob/living/user)
if(!disk)
return
- if(!istype(user) || !Adjacent(user))// || !user.put_in_active_hand(disk))
- disk.forceMove(drop_location())
+ disk.forceMove(drop_location())
+ if(istype(user) && Adjacent(user))
+ user.put_in_active_hand(disk)
disk = null
/obj/machinery/nanite_program_hub/AltClick(mob/user)
diff --git a/code/modules/research/nanites/nanite_programmer.dm b/code/modules/research/nanites/nanite_programmer.dm
index 804f256cf6..b6a2c8b28b 100644
--- a/code/modules/research/nanites/nanite_programmer.dm
+++ b/code/modules/research/nanites/nanite_programmer.dm
@@ -39,8 +39,9 @@
/obj/machinery/nanite_programmer/proc/eject(mob/living/user)
if(!disk)
return
- if(!istype(user) || !Adjacent(user))// || !user.put_in_active_hand(disk))
- disk.forceMove(drop_location())
+ disk.forceMove(drop_location())
+ if(istype(user) && user.Adjacent(src))
+ user.put_in_active_hand(disk)
disk = null
program = null
diff --git a/code/modules/research/nanites/nanite_programs/suppression.dm b/code/modules/research/nanites/nanite_programs/suppression.dm
index 3b0d6d0d06..d2aa243fee 100644
--- a/code/modules/research/nanites/nanite_programs/suppression.dm
+++ b/code/modules/research/nanites/nanite_programs/suppression.dm
@@ -176,7 +176,7 @@
sent_message = message_setting.get_value()
if(host_mob.stat == DEAD)
return
- to_chat(host_mob, "You hear a strange, robotic voice in your head... \"[sent_message]\"")
+ to_chat(host_mob, "You hear a strange, robotic voice in your head... \"[html_encode(sent_message)]\"")
/datum/nanite_program/comm/hallucination
name = "Hallucination"
diff --git a/code/modules/ruins/lavaland_ruin_code.dm b/code/modules/ruins/lavaland_ruin_code.dm
index 45b6939f42..e572f1ee02 100644
--- a/code/modules/ruins/lavaland_ruin_code.dm
+++ b/code/modules/ruins/lavaland_ruin_code.dm
@@ -93,7 +93,7 @@
/obj/item/stack/sheet/mineral/adamantine = /datum/species/golem/adamantine,
/obj/item/stack/sheet/plastic = /datum/species/golem/plastic,
/obj/item/stack/tile/brass = /datum/species/golem/clockwork,
- /obj/item/stack/tile/bronze = /datum/species/golem/bronze,
+ /obj/item/stack/sheet/bronze = /datum/species/golem/bronze,
/obj/item/stack/sheet/cardboard = /datum/species/golem/cardboard,
/obj/item/stack/sheet/leather = /datum/species/golem/leather,
/obj/item/stack/sheet/bone = /datum/species/golem/bone,
diff --git a/code/modules/shuttle/shuttle_creation/shuttle_creator.dm b/code/modules/shuttle/shuttle_creation/shuttle_creator.dm
index f5a11db60f..b3d99f22ab 100644
--- a/code/modules/shuttle/shuttle_creation/shuttle_creator.dm
+++ b/code/modules/shuttle/shuttle_creation/shuttle_creator.dm
@@ -43,6 +43,7 @@ GLOBAL_LIST_EMPTY(custom_shuttle_machines) //Machines that require updating (He
. = ..()
internal_shuttle_creator = new()
internal_shuttle_creator.owner_rsd = src
+ desc += " Attention, the max size of the shuttle is [SHUTTLE_CREATOR_MAX_SIZE]."
overlay_holder = new()
/obj/item/shuttle_creator/Destroy()
@@ -237,13 +238,13 @@ GLOBAL_LIST_EMPTY(custom_shuttle_machines) //Machines that require updating (He
port.register()
- icon_state = "rsd_used"
+ icon_state = "rsd_empty"
//Clear highlights
overlay_holder.clear_highlights()
GLOB.custom_shuttle_count ++
- message_admins("[ADMIN_LOOKUPFLW(user)] created a new shuttle with a [src] at [ADMIN_VERBOSEJMP(user)] ([GLOB.custom_shuttle_count] custom shuttles, limit is [CUSTOM_SHUTTLE_LIMIT])")
- log_game("[key_name(user)] created a new shuttle with a [src] at [AREACOORD(user)] ([GLOB.custom_shuttle_count] custom shuttles, limit is [CUSTOM_SHUTTLE_LIMIT])")
+ message_admins("[ADMIN_LOOKUPFLW(user)] created a new shuttle with a [src] at [ADMIN_VERBOSEJMP(user)] ([GLOB.custom_shuttle_count] custom shuttles)")
+ log_game("[key_name(user)] created a new shuttle with a [src] at [AREACOORD(user)] ([GLOB.custom_shuttle_count] custom shuttles)")
return TRUE
/obj/item/shuttle_creator/proc/create_shuttle_area(mob/user)
@@ -350,7 +351,7 @@ GLOBAL_LIST_EMPTY(custom_shuttle_machines) //Machines that require updating (He
loggedOldArea = get_area(get_turf(user))
loggedTurfs |= turfs
overlay_holder.highlight_area(turfs)
- //TODO READD THIS SHIT: icon_state = "rsd_used"
+ //TODO READD THIS SHIT: icon_state = "rsd_empty"
to_chat(user, "You add the area into the buffer of the [src], you made add more areas or select an airlock to act as a docking port to complete the shuttle.")
return turfs
diff --git a/code/modules/spells/spell.dm b/code/modules/spells/spell.dm
index 57502e2cd5..2272a14612 100644
--- a/code/modules/spells/spell.dm
+++ b/code/modules/spells/spell.dm
@@ -224,7 +224,15 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th
/obj/effect/proc_holder/spell/proc/choose_targets(mob/user = usr) //depends on subtype - /targeted or /aoe_turf
return
-/obj/effect/proc_holder/spell/proc/can_target(mob/living/target)
+/**
+ * can_target: Checks if we are allowed to cast the spell on a target.
+ *
+ * Arguments:
+ * * target The atom that is being targeted by the spell.
+ * * user The mob using the spell.
+ * * silent If the checks should not give any feedback messages.
+ */
+/obj/effect/proc_holder/spell/proc/can_target(atom/target, mob/user, silent = FALSE)
return TRUE
/obj/effect/proc_holder/spell/proc/start_recharge()
@@ -296,6 +304,13 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th
/obj/effect/proc_holder/spell/proc/cast(list/targets,mob/user = usr)
return
+/obj/effect/proc_holder/spell/proc/view_or_range(distance = world.view, center=usr, type="view")
+ switch(type)
+ if("view")
+ . = view(distance,center)
+ if("range")
+ . = range(distance,center)
+
/obj/effect/proc_holder/spell/proc/revert_cast(mob/user = usr) //resets recharge or readds a charge
switch(charge_type)
if("recharge")
@@ -345,7 +360,7 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th
switch(max_targets)
if(0) //unlimited
for(var/mob/living/target in view_or_range(range, user, selection_type))
- if(!can_target(target))
+ if(!can_target(target, user, TRUE))
continue
targets += target
if(1) //single target can be picked
@@ -357,7 +372,7 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th
for(var/mob/living/M in view_or_range(range, user, selection_type))
if(!include_user && user == M)
continue
- if(!can_target(M))
+ if(!can_target(M, user, TRUE))
continue
possible_targets += M
@@ -365,7 +380,7 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th
//Adds a safety check post-input to make sure those targets are actually in range.
var/mob/M
if(!random_target)
- M = input("Choose the target for the spell.", "Targeting") as null|mob in possible_targets
+ M = input("Choose the target for the spell.", "Targeting") as null|mob in sortNames(possible_targets)
else
switch(random_target_priority)
if(TARGET_RANDOM)
@@ -385,7 +400,7 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th
else
var/list/possible_targets = list()
for(var/mob/living/target in view_or_range(range, user, selection_type))
- if(!can_target(target))
+ if(!can_target(target, user, TRUE))
continue
possible_targets += target
for(var/i=1,i<=max_targets,i++)
@@ -411,7 +426,7 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th
var/list/targets = list()
for(var/turf/target in view_or_range(range,user,selection_type))
- if(!can_target(target))
+ if(!can_target(target, user, TRUE))
continue
if(!(target in view_or_range(inner_radius,user,selection_type)))
targets += target
diff --git a/code/modules/spells/spell_types/cone_spells.dm b/code/modules/spells/spell_types/cone_spells.dm
new file mode 100644
index 0000000000..63bae4b7cf
--- /dev/null
+++ b/code/modules/spells/spell_types/cone_spells.dm
@@ -0,0 +1,117 @@
+/obj/effect/proc_holder/spell/cone
+ name = "Cone of Nothing"
+ desc = "Does nothing in a cone! Wow!"
+ school = "evocation"
+ charge_max = 100
+ clothes_req = FALSE
+ invocation = "FUKAN NOTHAN"
+ invocation_type = "shout"
+ sound = 'sound/magic/forcewall.ogg'
+ action_icon_state = "shield"
+ range = -1
+ cooldown_min = 0.5 SECONDS
+ ///This controls how many levels the cone has, increase this value to make a bigger cone.
+ var/cone_levels = 3
+ ///This value determines if the cone penetrates walls.
+ var/respect_density = FALSE
+
+/obj/effect/proc_holder/spell/cone/choose_targets(mob/user = usr)
+ perform(null, user=user)
+
+///This proc creates a list of turfs that are hit by the cone
+/obj/effect/proc_holder/spell/cone/proc/cone_helper(var/turf/starter_turf, var/dir_to_use, var/cone_levels = 3)
+ var/list/turfs_to_return = list()
+ var/turf/turf_to_use = starter_turf
+ var/turf/left_turf
+ var/turf/right_turf
+ var/right_dir
+ var/left_dir
+ switch(dir_to_use)
+ if(NORTH)
+ left_dir = WEST
+ right_dir = EAST
+ if(SOUTH)
+ left_dir = EAST
+ right_dir = WEST
+ if(EAST)
+ left_dir = NORTH
+ right_dir = SOUTH
+ if(WEST)
+ left_dir = SOUTH
+ right_dir = NORTH
+
+
+ for(var/i in 1 to cone_levels)
+ var/list/level_turfs = list()
+ turf_to_use = get_step(turf_to_use, dir_to_use)
+ level_turfs += turf_to_use
+ if(i != 1)
+ left_turf = get_step(turf_to_use, left_dir)
+ level_turfs += left_turf
+ right_turf = get_step(turf_to_use, right_dir)
+ level_turfs += right_turf
+ for(var/left_i in 1 to i -calculate_cone_shape(i))
+ if(left_turf.density && respect_density)
+ break
+ left_turf = get_step(left_turf, left_dir)
+ level_turfs += left_turf
+ for(var/right_i in 1 to i -calculate_cone_shape(i))
+ if(right_turf.density && respect_density)
+ break
+ right_turf = get_step(right_turf, right_dir)
+ level_turfs += right_turf
+ turfs_to_return += list(level_turfs)
+ if(i == cone_levels)
+ continue
+ if(turf_to_use.density && respect_density)
+ break
+ return turfs_to_return
+
+/obj/effect/proc_holder/spell/cone/cast(list/targets,mob/user = usr)
+ var/list/cone_turfs = cone_helper(get_turf(user), user.dir, cone_levels)
+ for(var/list/turf_list in cone_turfs)
+ do_cone_effects(turf_list)
+
+///This proc does obj, mob and turf cone effects on all targets in a list
+/obj/effect/proc_holder/spell/cone/proc/do_cone_effects(list/target_turf_list, level)
+ for(var/target_turf in target_turf_list)
+ if(!target_turf) //if turf is no longer there
+ continue
+ do_turf_cone_effect(target_turf, level)
+ if(isopenturf(target_turf))
+ var/turf/open/open_turf = target_turf
+ for(var/movable_content in open_turf)
+ if(isobj(movable_content))
+ do_obj_cone_effect(movable_content, level)
+ else if(isliving(movable_content))
+ do_mob_cone_effect(movable_content, level)
+
+///This proc deterimines how the spell will affect turfs.
+/obj/effect/proc_holder/spell/cone/proc/do_turf_cone_effect(turf/target_turf, level)
+ return
+
+///This proc deterimines how the spell will affect objects.
+/obj/effect/proc_holder/spell/cone/proc/do_obj_cone_effect(obj/target_obj, level)
+ return
+
+///This proc deterimines how the spell will affect mobs.
+/obj/effect/proc_holder/spell/cone/proc/do_mob_cone_effect(mob/living/target_mob, level)
+ return
+
+///This proc adjusts the cones width depending on the level.
+/obj/effect/proc_holder/spell/cone/proc/calculate_cone_shape(current_level)
+ var/end_taper_start = round(cone_levels * 0.8)
+ if(current_level > end_taper_start)
+ return (current_level % end_taper_start) * 2 //someone more talented and probably come up with a better formula.
+ else
+ return 2
+
+///This type of cone gradually affects each level of the cone instead of affecting the entire area at once.
+/obj/effect/proc_holder/spell/cone/staggered
+
+/obj/effect/proc_holder/spell/cone/staggered/cast(list/targets,mob/user = usr)
+ var/level_counter = 0
+ var/list/cone_turfs = cone_helper(get_turf(user), user.dir, cone_levels)
+ for(var/list/turf_list in cone_turfs)
+ level_counter++
+ addtimer(CALLBACK(src, .proc/do_cone_effects, turf_list, level_counter), 2 * level_counter)
diff --git a/code/modules/spells/spell_types/dumbfire.dm b/code/modules/spells/spell_types/dumbfire.dm
index 6931b4ac31..424c702a31 100644
--- a/code/modules/spells/spell_types/dumbfire.dm
+++ b/code/modules/spells/spell_types/dumbfire.dm
@@ -49,8 +49,8 @@
var/projectile_type = text2path(proj_type)
projectile = new projectile_type(user)
else if(istype(proj_type, /obj/effect/proc_holder/spell))
- projectile = new /obj/effect/proc_holder/spell/targeted/trigger(user)
- var/obj/effect/proc_holder/spell/targeted/trigger/T = projectile
+ projectile = new /obj/effect/proc_holder/spell/pointed/trigger(user)
+ var/obj/effect/proc_holder/spell/pointed/trigger/T = projectile
T.linked_spells += proj_type
else
projectile = new proj_type(user)
diff --git a/code/modules/spells/spell_types/ethereal_jaunt.dm b/code/modules/spells/spell_types/ethereal_jaunt.dm
index 8cf51d45c6..9d91b6534d 100644
--- a/code/modules/spells/spell_types/ethereal_jaunt.dm
+++ b/code/modules/spells/spell_types/ethereal_jaunt.dm
@@ -17,7 +17,7 @@
action_icon_state = "jaunt"
/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/cast(list/targets,mob/user = usr) //magnets, so mostly hardcoded
- playsound(get_turf(user), 'sound/magic/ethereal_enter.ogg', 50, 1, -1)
+ play_sound("enter",user)
for(var/mob/living/target in targets)
INVOKE_ASYNC(src, .proc/do_jaunt, target)
@@ -42,7 +42,7 @@
ADD_TRAIT(target, TRAIT_MOBILITY_NOMOVE, src)
target.update_mobility()
holder.reappearing = 1
- playsound(get_turf(target), 'sound/magic/ethereal_exit.ogg', 50, 1, -1)
+ play_sound("exit",target)
sleep(25 - jaunt_in_time)
new jaunt_in_type(mobloc, holder.dir)
target.setDir(holder.dir)
@@ -63,6 +63,13 @@
steam.set_up(10, 0, mobloc)
steam.start()
+/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/proc/play_sound(type,mob/living/target)
+ switch(type)
+ if("enter")
+ playsound(get_turf(target), 'sound/magic/ethereal_enter.ogg', 50, TRUE, -1)
+ if("exit")
+ playsound(get_turf(target), 'sound/magic/ethereal_exit.ogg', 50, TRUE, -1)
+
/obj/effect/dummy/phased_mob/spell_jaunt
name = "water"
icon = 'icons/effects/effects.dmi'
diff --git a/code/modules/spells/spell_types/mind_transfer.dm b/code/modules/spells/spell_types/mind_transfer.dm
deleted file mode 100644
index d2ef015d1d..0000000000
--- a/code/modules/spells/spell_types/mind_transfer.dm
+++ /dev/null
@@ -1,88 +0,0 @@
-/obj/effect/proc_holder/spell/targeted/mind_transfer
- name = "Mind Transfer"
- desc = "This spell allows the user to switch bodies with a target."
-
- school = "transmutation"
- charge_max = 600
- clothes_req = NONE
- invocation = "GIN'YU CAPAN"
- invocation_type = "whisper"
- range = 1
- cooldown_min = 200 //100 deciseconds reduction per rank
- var/unconscious_amount_caster = 400 //how much the caster is stunned for after the spell
- var/unconscious_amount_victim = 400 //how much the victim is stunned for after the spell
-
- action_icon_state = "mindswap"
-
-/*
-Urist: I don't feel like figuring out how you store object spells so I'm leaving this for you to do.
-Make sure spells that are removed from spell_list are actually removed and deleted when mind transferring.
-Also, you never added distance checking after target is selected. I've went ahead and did that.
-*/
-/obj/effect/proc_holder/spell/targeted/mind_transfer/cast(list/targets, mob/living/user = usr, distanceoverride, silent = FALSE)
- if(!targets.len)
- if(!silent)
- to_chat(user, "No mind found!")
- return
-
- if(targets.len > 1)
- if(!silent)
- to_chat(user, "Too many minds! You're not a hive damnit!")
- return
-
- var/mob/living/target = targets[1]
-
- var/t_He = target.p_they(TRUE)
- var/t_is = target.p_are()
-
- if(!(target in oview(range)) && !distanceoverride)//If they are not in overview after selection. Do note that !() is necessary for in to work because ! takes precedence over it.
- if(!silent)
- to_chat(user, "[t_He] [t_is] too far away!")
- return
-
- if(ismegafauna(target))
- if(!silent)
- to_chat(user, "This creature is too powerful to control!")
- return
-
- if(target.stat == DEAD)
- if(!silent)
- to_chat(user, "You don't particularly want to be dead!")
- return
-
- if(!target.key || !target.mind)
- if(!silent)
- to_chat(user, "[t_He] appear[target.p_s()] to be catatonic! Not even magic can affect [target.p_their()] vacant mind.")
- return
-
- if(user.suiciding)
- if(!silent)
- to_chat(user, "You're killing yourself! You can't concentrate enough to do this!")
- return
-
- var/datum/mind/TM = target.mind
- if(target.anti_magic_check(TRUE, FALSE) || TM.has_antag_datum(/datum/antagonist/wizard) || TM.has_antag_datum(/datum/antagonist/cult) || TM.has_antag_datum(/datum/antagonist/clockcult) || TM.has_antag_datum(/datum/antagonist/changeling) || TM.has_antag_datum(/datum/antagonist/rev) || target.key[1] == "@")
- if(!silent)
- to_chat(user, "[target.p_their(TRUE)] mind is resisting your spell!")
- return
-
- var/mob/living/victim = target//The target of the spell whos body will be transferred to.
- var/mob/living/caster = user//The wizard/whomever doing the body transferring.
-
- //MIND TRANSFER BEGIN
- var/mob/dead/observer/ghost = victim.ghostize(FALSE, TRUE)
- caster.mind.transfer_to(victim)
-
- ghost.mind.transfer_to(caster)
- if(ghost.key)
- ghost.transfer_ckey(caster) //have to transfer the key since the mind was not active
- qdel(ghost)
-
- //MIND TRANSFER END
-
- //Here we knock both mobs out for a time.
- caster.Unconscious(unconscious_amount_caster)
- victim.Unconscious(unconscious_amount_victim)
- SEND_SOUND(caster, sound('sound/magic/mandswap.ogg'))
- SEND_SOUND(victim, sound('sound/magic/mandswap.ogg'))// only the caster and victim hear the sounds, that way no one knows for sure if the swap happened
- return TRUE
diff --git a/code/modules/spells/spell_types/barnyard.dm b/code/modules/spells/spell_types/pointed/barnyard.dm
similarity index 52%
rename from code/modules/spells/spell_types/barnyard.dm
rename to code/modules/spells/spell_types/pointed/barnyard.dm
index 4b972e8030..61e3cf7127 100644
--- a/code/modules/spells/spell_types/barnyard.dm
+++ b/code/modules/spells/spell_types/pointed/barnyard.dm
@@ -1,51 +1,54 @@
-/obj/effect/proc_holder/spell/targeted/barnyardcurse
+/obj/effect/proc_holder/spell/pointed/barnyardcurse
name = "Curse of the Barnyard"
desc = "This spell dooms an unlucky soul to possess the speech and facial attributes of a barnyard animal."
school = "transmutation"
charge_type = "recharge"
charge_max = 150
charge_counter = 0
- clothes_req = NONE
- stat_allowed = 0
+ clothes_req = FALSE
+ stat_allowed = FALSE
invocation = "KN'A FTAGHU, PUCK 'BTHNK!"
invocation_type = "shout"
range = 7
cooldown_min = 30
- selection_type = "range"
- var/list/compatible_mobs = list(/mob/living/carbon/human, /mob/living/carbon/monkey)
-
+ ranged_mousepointer = 'icons/effects/mouse_pointers/barn_target.dmi'
action_icon_state = "barn"
+ active_msg = "You prepare to curse a target..."
+ deactive_msg = "You dispel the curse..."
+ /// List of mobs which are allowed to be a target of the spell
+ var/static/list/compatible_mobs_typecache = typecacheof(list(/mob/living/carbon/human, /mob/living/carbon/monkey))
-/obj/effect/proc_holder/spell/targeted/barnyardcurse/cast(list/targets, mob/user = usr)
+/obj/effect/proc_holder/spell/pointed/barnyardcurse/cast(list/targets, mob/user)
if(!targets.len)
- to_chat(user, "No target found in range.")
- return
+ to_chat(user, "No target found in range!")
+ return FALSE
+ if(!can_target(targets[1], user))
+ return FALSE
var/mob/living/carbon/target = targets[1]
-
- if(!(target.type in compatible_mobs))
- to_chat(user, "You are unable to curse [target]'s head!")
- return
-
- if(!(target in oview(range)))
- to_chat(user, "[target.p_theyre(TRUE)] too far away!")
- return
-
if(target.anti_magic_check())
to_chat(user, "The spell had no effect!")
target.visible_message("[target]'s face bursts into flames, which instantly burst outward, leaving [target] unharmed!", \
- "Your face starts burning up, but the flames are repulsed by your anti-magic protection!")
- return
+ "Your face starts burning up, but the flames are repulsed by your anti-magic protection!")
+ return FALSE
var/list/masks = list(/obj/item/clothing/mask/pig/cursed, /obj/item/clothing/mask/cowmask/cursed, /obj/item/clothing/mask/horsehead/cursed)
-
var/choice = pick(masks)
var/obj/item/clothing/mask/magichead = new choice(get_turf(target))
- magichead.flags_inv = null
+
target.visible_message("[target]'s face bursts into flames, and a barnyard animal's head takes its place!", \
"Your face burns up, and shortly after the fire you realise you have the face of a barnyard animal!")
if(!target.dropItemToGround(target.wear_mask))
qdel(target.wear_mask)
- target.equip_to_slot_if_possible(magichead, SLOT_WEAR_MASK, 1, 1)
-
+ target.equip_to_slot_if_possible(magichead, ITEM_SLOT_MASK, 1, 1)
target.flash_act()
+
+/obj/effect/proc_holder/spell/pointed/barnyardcurse/can_target(atom/target, mob/user, silent)
+ . = ..()
+ if(!.)
+ return FALSE
+ if(!is_type_in_typecache(target, compatible_mobs_typecache))
+ if(!silent)
+ to_chat(user, "You are unable to curse [target]!")
+ return FALSE
+ return TRUE
diff --git a/code/modules/spells/spell_types/pointed/blind.dm b/code/modules/spells/spell_types/pointed/blind.dm
new file mode 100644
index 0000000000..a773c5ad8d
--- /dev/null
+++ b/code/modules/spells/spell_types/pointed/blind.dm
@@ -0,0 +1,35 @@
+/obj/effect/proc_holder/spell/pointed/trigger/blind
+ name = "Blind"
+ desc = "This spell temporarily blinds a single target."
+ school = "transmutation"
+ charge_max = 300
+ clothes_req = FALSE
+ invocation = "STI KALY"
+ invocation_type = "whisper"
+ message = "Your eyes cry out in pain!"
+ cooldown_min = 50 //12 deciseconds reduction per rank
+ starting_spells = list("/obj/effect/proc_holder/spell/targeted/inflict_handler/blind", "/obj/effect/proc_holder/spell/targeted/genetic/blind")
+ ranged_mousepointer = 'icons/effects/mouse_pointers/blind_target.dmi'
+ action_icon_state = "blind"
+ active_msg = "You prepare to blind a target..."
+
+/obj/effect/proc_holder/spell/targeted/inflict_handler/blind
+ amt_eye_blind = 10
+ amt_eye_blurry = 20
+ sound = 'sound/magic/blind.ogg'
+
+/obj/effect/proc_holder/spell/targeted/genetic/blind
+ mutations = list(BLINDMUT)
+ duration = 300
+ charge_max = 400 // needs to be higher than the duration or it'll be permanent
+ sound = 'sound/magic/blind.ogg'
+
+/obj/effect/proc_holder/spell/pointed/trigger/blind/can_target(atom/target, mob/user, silent)
+ . = ..()
+ if(!.)
+ return FALSE
+ if(!isliving(target))
+ if(!silent)
+ to_chat(user, "You can only blind living beings!")
+ return FALSE
+ return TRUE
diff --git a/code/modules/spells/spell_types/pointed/mind_transfer.dm b/code/modules/spells/spell_types/pointed/mind_transfer.dm
new file mode 100644
index 0000000000..28d646f6b6
--- /dev/null
+++ b/code/modules/spells/spell_types/pointed/mind_transfer.dm
@@ -0,0 +1,103 @@
+/obj/effect/proc_holder/spell/pointed/mind_transfer
+ name = "Mind Transfer"
+ desc = "This spell allows the user to switch bodies with a target next to him."
+ school = "transmutation"
+ charge_max = 600
+ clothes_req = FALSE
+ invocation = "GIN'YU CAPAN"
+ invocation_type = "whisper"
+ range = 1
+ cooldown_min = 200 //100 deciseconds reduction per rank
+ ranged_mousepointer = 'icons/effects/mouse_pointers/mindswap_target.dmi'
+ action_icon_state = "mindswap"
+ active_msg = "You prepare to swap minds with a target..."
+ /// For how long is the caster stunned for after the spell
+ var/unconscious_amount_caster = 40 SECONDS
+ /// For how long is the victim stunned for after the spell
+ var/unconscious_amount_victim = 40 SECONDS
+
+/obj/effect/proc_holder/spell/pointed/mind_transfer/cast(list/targets, mob/living/user, silent = FALSE)
+ if(!targets.len)
+ if(!silent)
+ to_chat(user, "No mind found!")
+ return FALSE
+ if(targets.len > 1)
+ if(!silent)
+ to_chat(user, "Too many minds! You're not a hive damnit!")
+ return FALSE
+ if(!can_target(targets[1], user, silent))
+ return FALSE
+
+ var/mob/living/victim = targets[1] //The target of the spell whos body will be transferred to.
+ var/datum/mind/VM = victim.mind
+ if(victim.anti_magic_check(TRUE, FALSE) || VM.has_antag_datum(/datum/antagonist/wizard) || VM.has_antag_datum(/datum/antagonist/cult) || VM.has_antag_datum(/datum/antagonist/changeling) || VM.has_antag_datum(/datum/antagonist/rev) || victim.key[1] == "@")
+ if(!silent)
+ to_chat(user, "[victim.p_their(TRUE)] mind is resisting your spell!")
+ return FALSE
+ if(istype(victim, /mob/living/simple_animal/hostile/guardian))
+ var/mob/living/simple_animal/hostile/guardian/stand = victim
+ if(stand.summoner)
+ victim = stand.summoner
+
+ //You should not be able to enter one of the most powerful side-antags as a fucking wizard.
+ if(istype(victim,/mob/living/simple_animal/slaughter))
+ to_chat(user, "The devilish contract doesn't include the 'mind swappable' package, please try again another lifetime.")
+ return
+
+ //MIND TRANSFER BEGIN
+ var/mob/dead/observer/ghost = victim.ghostize()
+ user.mind.transfer_to(victim)
+
+ ghost.mind.transfer_to(user)
+ if(ghost.key)
+ user.key = ghost.key //have to transfer the key since the mind was not active
+ qdel(ghost)
+ //MIND TRANSFER END
+
+ //Here we knock both mobs out for a time.
+ user.Unconscious(unconscious_amount_caster)
+ victim.Unconscious(unconscious_amount_victim)
+ SEND_SOUND(user, sound('sound/magic/mandswap.ogg'))
+ SEND_SOUND(victim, sound('sound/magic/mandswap.ogg')) // only the caster and victim hear the sounds, that way no one knows for sure if the swap happened
+ return TRUE
+
+/obj/effect/proc_holder/spell/pointed/mind_transfer/can_target(atom/target, mob/user, silent)
+ . = ..()
+ if(!.)
+ return FALSE
+ if(!isliving(target))
+ if(!silent)
+ to_chat(user, "You can only swap minds with living beings!")
+ return FALSE
+ if(user == target)
+ if(!silent)
+ to_chat(user, "You can't swap minds with yourself!")
+ return FALSE
+
+ var/mob/living/victim = target
+ var/t_He = victim.p_they(TRUE)
+
+ if(ismegafauna(victim))
+ if(!silent)
+ to_chat(user, "This creature is too powerful to control!")
+ return FALSE
+ if(victim.stat == DEAD)
+ if(!silent)
+ to_chat(user, "You don't particularly want to be dead!")
+ return FALSE
+ if(!victim.key || !victim.mind)
+ if(!silent)
+ to_chat(user, "[t_He] appear[victim.p_s()] to be catatonic! Not even magic can affect [victim.p_their()] vacant mind.")
+ return FALSE
+ if(user.suiciding)
+ if(!silent)
+ to_chat(user, "You're killing yourself! You can't concentrate enough to do this!")
+ return FALSE
+ if(istype(victim, /mob/living/simple_animal/hostile/guardian))
+ var/mob/living/simple_animal/hostile/guardian/stand = victim
+ if(stand.summoner)
+ if(stand.summoner == user)
+ if(!silent)
+ to_chat(user, "Swapping minds with your own guardian would just put you back into your own head!")
+ return FALSE
+ return TRUE
diff --git a/code/modules/spells/spell_types/pointed/pointed.dm b/code/modules/spells/spell_types/pointed/pointed.dm
new file mode 100644
index 0000000000..7b942dee27
--- /dev/null
+++ b/code/modules/spells/spell_types/pointed/pointed.dm
@@ -0,0 +1,105 @@
+/obj/effect/proc_holder/spell/pointed
+ name = "pointed spell"
+ ranged_mousepointer = 'icons/effects/mouse_pointers/throw_target.dmi'
+ action_icon_state = "projectile"
+ /// Message showing to the spell owner upon deactivating pointed spell.
+ var/deactive_msg = "You dispel the magic..."
+ /// Message showing to the spell owner upon activating pointed spell.
+ var/active_msg = "You prepare to use the spell on a target..."
+ /// Variable dictating if the user is allowed to cast a spell on himself.
+ var/self_castable = FALSE
+ /// Variable dictating if the spell will use turf based aim assist
+ var/aim_assist = TRUE
+
+/obj/effect/proc_holder/spell/pointed/Trigger(mob/user, skip_can_cast = TRUE)
+ if(!istype(user))
+ return
+ var/msg
+ if(!can_cast(user))
+ msg = "You can no longer cast [name]!"
+ remove_ranged_ability(msg)
+ return
+ if(active)
+ msg = "[deactive_msg]"
+ remove_ranged_ability(msg)
+ else
+ msg = "[active_msg] Left-click to activate spell on a target!"
+ add_ranged_ability(user, msg, TRUE)
+ on_activation(user)
+
+/obj/effect/proc_holder/spell/pointed/on_lose(mob/living/user)
+ remove_ranged_ability()
+
+/obj/effect/proc_holder/spell/pointed/remove_ranged_ability(msg)
+ . = ..()
+ on_deactivation(ranged_ability_user)
+
+/obj/effect/proc_holder/spell/pointed/add_ranged_ability(mob/living/user, msg, forced)
+ . = ..()
+ on_activation(user)
+
+/**
+ * on_activation: What happens upon pointed spell activation.
+ *
+ * Arguments:
+ * * user The mob interacting owning the spell.
+ */
+/obj/effect/proc_holder/spell/pointed/proc/on_activation(mob/user)
+ return
+
+/**
+ * on_activation: What happens upon pointed spell deactivation.
+ *
+ * Arguments:
+ * * user The mob interacting owning the spell.
+ */
+/obj/effect/proc_holder/spell/pointed/proc/on_deactivation(mob/user)
+ return
+
+/obj/effect/proc_holder/spell/pointed/update_icon()
+ if(!action)
+ return
+ if(active)
+ action.button_icon_state = "[action_icon_state]1"
+ else
+ action.button_icon_state = "[action_icon_state]"
+ action.UpdateButtonIcon()
+
+/obj/effect/proc_holder/spell/pointed/InterceptClickOn(mob/living/caller, params, atom/target)
+ if(..())
+ return TRUE
+ if(aim_assist && isturf(target))
+ var/list/possible_targets = list()
+ for(var/A in target)
+ if(intercept_check(caller, A, TRUE))
+ possible_targets += A
+ if(possible_targets.len == 1)
+ target = possible_targets[1]
+ if(!intercept_check(caller, target))
+ return TRUE
+ if(!cast_check(FALSE, caller))
+ return TRUE
+ perform(list(target), user = caller)
+ remove_ranged_ability()
+ return TRUE // Do not do any underlying actions after the spell cast
+
+/**
+ * intercept_check: Specific spell checks for InterceptClickOn() targets.
+ *
+ * Arguments:
+ * * user The mob using the ranged spell via intercept.
+ * * target The atom that is being targeted by the spell via intercept.
+ * * silent If the checks should produce not any feedback messages for the user.
+ */
+/obj/effect/proc_holder/spell/pointed/proc/intercept_check(mob/user, atom/target, silent = FALSE)
+ if(!self_castable && target == user)
+ if(!silent)
+ to_chat(user, "You cannot cast the spell on yourself!")
+ return FALSE
+ if(!(target in view_or_range(range, user, selection_type)))
+ if(!silent)
+ to_chat(user, "[target.p_theyre(TRUE)] too far away!")
+ return FALSE
+ if(!can_target(target, user, silent))
+ return FALSE
+ return TRUE
diff --git a/code/modules/spells/spell_types/projectile.dm b/code/modules/spells/spell_types/projectile.dm
index be305520a2..3a8f48cf7c 100644
--- a/code/modules/spells/spell_types/projectile.dm
+++ b/code/modules/spells/spell_types/projectile.dm
@@ -37,8 +37,8 @@
var/projectile_type = text2path(proj_type)
projectile = new projectile_type(user)
if(istype(proj_type, /obj/effect/proc_holder/spell))
- projectile = new /obj/effect/proc_holder/spell/targeted/trigger(user)
- var/obj/effect/proc_holder/spell/targeted/trigger/T = projectile
+ projectile = new /obj/effect/proc_holder/spell/pointed/trigger(user)
+ var/obj/effect/proc_holder/spell/pointed/trigger/T = projectile
T.linked_spells += proj_type
projectile.icon = proj_icon
projectile.icon_state = proj_icon_state
diff --git a/code/modules/spells/spell_types/trigger.dm b/code/modules/spells/spell_types/trigger.dm
index 39cff63d98..df579d9243 100644
--- a/code/modules/spells/spell_types/trigger.dm
+++ b/code/modules/spells/spell_types/trigger.dm
@@ -1,30 +1,26 @@
-/obj/effect/proc_holder/spell/targeted/trigger
+/obj/effect/proc_holder/spell/pointed/trigger
name = "Trigger"
desc = "This spell triggers another spell or a few."
-
var/list/linked_spells = list() //those are just referenced by the trigger spell and are unaffected by it directly
var/list/starting_spells = list() //those are added on New() to contents from default spells and are deleted when the trigger spell is deleted to prevent memory leaks
-/obj/effect/proc_holder/spell/targeted/trigger/Initialize()
+/obj/effect/proc_holder/spell/pointed/trigger/Initialize()
. = ..()
-
for(var/spell in starting_spells)
var/spell_to_add = text2path(spell)
new spell_to_add(src) //should result in adding to contents, needs testing
-/obj/effect/proc_holder/spell/targeted/trigger/Destroy()
+/obj/effect/proc_holder/spell/pointed/trigger/Destroy()
for(var/spell in contents)
qdel(spell)
linked_spells = null
starting_spells = null
return ..()
-/obj/effect/proc_holder/spell/targeted/trigger/cast(list/targets,mob/user = usr)
+/obj/effect/proc_holder/spell/pointed/trigger/cast(list/targets,mob/user = usr)
playMagSound()
for(var/mob/living/target in targets)
for(var/obj/effect/proc_holder/spell/spell in contents)
spell.perform(list(target),0)
for(var/obj/effect/proc_holder/spell/spell in linked_spells)
spell.perform(list(target),0)
-
- return
\ No newline at end of file
diff --git a/code/modules/spells/spell_types/wizard.dm b/code/modules/spells/spell_types/wizard.dm
index 13c47ab9ac..14f359ef81 100644
--- a/code/modules/spells/spell_types/wizard.dm
+++ b/code/modules/spells/spell_types/wizard.dm
@@ -207,40 +207,12 @@
summon_type = list(/mob/living/simple_animal/hostile/netherworld)
cast_sound = 'sound/magic/summonitems_generic.ogg'
-/obj/effect/proc_holder/spell/targeted/trigger/blind
- name = "Blind"
- desc = "This spell temporarily blinds a single person and does not require wizard garb."
-
- school = "transmutation"
- charge_max = 300
- clothes_req = NONE
- invocation = "STI KALY"
- invocation_type = "whisper"
- message = "Your eyes cry out in pain!"
- cooldown_min = 50 //12 deciseconds reduction per rank
-
- starting_spells = list("/obj/effect/proc_holder/spell/targeted/inflict_handler/blind","/obj/effect/proc_holder/spell/targeted/genetic/blind")
-
- action_icon_state = "blind"
-
/obj/effect/proc_holder/spell/aoe_turf/conjure/creature/cult
name = "Summon Creatures (DANGEROUS)"
clothes_req = SPELL_CULT_GARB
charge_max = 5000
summon_amt = 2
-
-
-/obj/effect/proc_holder/spell/targeted/inflict_handler/blind
- amt_eye_blind = 10
- amt_eye_blurry = 20
- sound = 'sound/magic/blind.ogg'
-
-/obj/effect/proc_holder/spell/targeted/genetic/blind
- mutations = list(BLINDMUT)
- duration = 300
- sound = 'sound/magic/blind.ogg'
-
/obj/effect/proc_holder/spell/aoe_turf/repulse
name = "Repulse"
desc = "This spell throws everything around the user away."
diff --git a/code/modules/station_goals/bsa.dm b/code/modules/station_goals/bsa.dm
index 4c3f30a786..472734b74b 100644
--- a/code/modules/station_goals/bsa.dm
+++ b/code/modules/station_goals/bsa.dm
@@ -180,16 +180,37 @@
reload()
/obj/machinery/bsa/full/proc/fire(mob/user, turf/bullseye)
- var/turf/point = get_front_turf()
- for(var/turf/T in getline(get_step(point,dir),get_target_turf()))
- T.ex_act(EXPLODE_DEVASTATE)
- point.Beam(get_target_turf(),icon_state="bsa_beam",time=50,maxdistance = world.maxx) //ZZZAP
-
- message_admins("[ADMIN_LOOKUPFLW(user)] has launched an artillery strike.")
- explosion(bullseye,ex_power,ex_power*2,ex_power*4)
-
reload()
+ var/turf/point = get_front_turf()
+ var/turf/target = get_target_turf()
+ var/atom/movable/blocker
+ for(var/T in getline(get_step(point, dir), target))
+ var/turf/tile = T
+ if(SEND_SIGNAL(tile, COMSIG_ATOM_BSA_BEAM) & COMSIG_ATOM_BLOCKS_BSA_BEAM)
+ blocker = tile
+ else
+ for(var/AM in tile)
+ var/atom/movable/stuff = AM
+ if(SEND_SIGNAL(stuff, COMSIG_ATOM_BSA_BEAM) & COMSIG_ATOM_BLOCKS_BSA_BEAM)
+ blocker = stuff
+ break
+ if(blocker)
+ target = tile
+ break
+ else
+ tile.ex_act(EXPLODE_DEVASTATE)
+ point.Beam(target, icon_state = "bsa_beam", time = 50, maxdistance = world.maxx) //ZZZAP
+ new /obj/effect/temp_visual/bsa_splash(point, dir)
+
+ if(!blocker)
+ message_admins("[ADMIN_LOOKUPFLW(user)] has launched an artillery strike targeting [ADMIN_VERBOSEJMP(bullseye)].")
+ log_game("[key_name(user)] has launched an artillery strike targeting [AREACOORD(bullseye)].")
+ explosion(bullseye, ex_power, ex_power*2, ex_power*4)
+ else
+ message_admins("[ADMIN_LOOKUPFLW(user)] has launched an artillery strike targeting [ADMIN_VERBOSEJMP(bullseye)] but it was blocked by [blocker] at [ADMIN_VERBOSEJMP(target)].")
+ log_game("[key_name(user)] has launched an artillery strike targeting [AREACOORD(bullseye)] but it was blocked by [blocker] at [AREACOORD(target)].")
+
/obj/machinery/bsa/full/proc/reload()
ready = FALSE
use_power(power_used_per_shot)
diff --git a/code/modules/vehicles/_vehicle.dm b/code/modules/vehicles/_vehicle.dm
index ac7fa879f4..12e9f365d0 100644
--- a/code/modules/vehicles/_vehicle.dm
+++ b/code/modules/vehicles/_vehicle.dm
@@ -18,6 +18,7 @@
var/canmove = TRUE
var/emulate_door_bumps = TRUE //when bumping a door try to make occupants bump them to open them.
var/default_driver_move = TRUE //handle driver movement instead of letting something else do it like riding datums.
+ var/enclosed = FALSE // is the rider protected from bullets? assume no
var/list/autogrant_actions_passenger //plain list of typepaths
var/list/autogrant_actions_controller //assoc list "[bitflag]" = list(typepaths)
var/list/mob/occupant_actions //assoc list mob = list(type = action datum assigned to mob)
@@ -166,3 +167,9 @@
if(trailer && .)
var/dir_to_move = get_dir(trailer.loc, newloc)
step(trailer, dir_to_move)
+
+/obj/vehicle/bullet_act(obj/item/projectile/Proj) //wrapper
+ if (!enclosed && length(occupants) && !Proj.force_hit && (Proj.def_zone == BODY_ZONE_HEAD || Proj.def_zone == BODY_ZONE_CHEST)) //allows bullets to hit drivers
+ occupants[1].bullet_act(Proj) // driver dinkage
+ return BULLET_ACT_HIT
+ . = ..()
diff --git a/code/modules/vehicles/sealed.dm b/code/modules/vehicles/sealed.dm
index edaab8b982..28f6b1cca8 100644
--- a/code/modules/vehicles/sealed.dm
+++ b/code/modules/vehicles/sealed.dm
@@ -1,4 +1,5 @@
/obj/vehicle/sealed
+ enclosed = TRUE // you're in a sealed vehicle dont get dinked idiot
var/enter_delay = 20
flags_1 = BLOCK_FACE_ATOM_1
diff --git a/config/game_options.txt b/config/game_options.txt
index 1585d45e6d..a5b0d0b8c4 100644
--- a/config/game_options.txt
+++ b/config/game_options.txt
@@ -116,6 +116,7 @@ CONTINUOUS CHANGELING
CONTINUOUS WIZARD
#CONTINUOUS MONKEY
CONTINUOUS BLOODSUCKER
+CONTINUOUS HERESY
##Note: do not toggle continuous off for these modes, as they have no antagonists and would thus end immediately!
diff --git a/config/spaceRuinBlacklist.txt b/config/spaceRuinBlacklist.txt
index 90682f5bad..969e4135f6 100644
--- a/config/spaceRuinBlacklist.txt
+++ b/config/spaceRuinBlacklist.txt
@@ -52,3 +52,4 @@
#_maps/RandomRuins/SpaceRuins/arcade.dmm
#_maps/RandomRuins/SpaceRuins/spacehermit.dmm
#_maps/RandomRuins/SpaceRuins/advancedlab.dmm
+#_maps/RandomRuins/SpaceRuins/spacediner.dmm
diff --git a/html/changelog.html b/html/changelog.html
index bb5efeaccf..5a0e608cd6 100644
--- a/html/changelog.html
+++ b/html/changelog.html
@@ -50,6 +50,150 @@
-->
+ 21 August 2020
+ LetterN updated:
+
+ - Updates and adds some of the tips
+
+ Putnam3145 updated:
+
+ - added reftracking as a compile flag
+
+ SmArtKar updated:
+
+ - RSD limitation is now 500 tiles
+ - Fixed broken RSD sprites
+ - Removed that shuttle limit
+
+ timothyteakettle updated:
+
+ - two snouts can once again be chosen in customization
+ - lizard snouts work again
+
+
+ 20 August 2020
+ DeltaFire15 updated:
+
+ - The cooking oil damage formula is no longer scuffed.
+ - Changed the clockie help-link to lead to our own wiki.
+
+ Fikou updated:
+
+ - admins can now do html in ahelps properly
+
+ Hatterhat updated:
+
+ - Pirate threats are now announced as "business propositions", and their arrivals are now also announced properly.
+
+ tiramisuapimancer updated:
+
+ - Ethereal hair is now their body color instead of accidentally white
+
+
+ 18 August 2020
+ DeltaFire15 updated:
+
+ - kindle cast time: 15ds -> 25ds
+ - Moved the Belligerent Scripture to where it should be in the code
+
+ Detective-Google updated:
+
+ - glass floors
+ - uncrowbarrable plasma floors tweak:disco inferno's plasma floors can no longer be crowbarred.
+ - ghost cafe has funky fresh art
+ - you can actually remove glass floors now
+ - get_equipped_items is hopefully less gross
+ - plasma cutters are no longer gay
+
+ Hatterhat updated:
+
+ - Slaughter demons (and laughter demons, being a subtype) are MOB_SIZE_LARGE, with one of the more immediate effects being able to mark them with a crusher and backstab them.
+ - The funny blyat men have stumbled upon another surplus of Mosin-Nagants and are starting to pack them into crates again.
+ - Vehicle riders can now, by default, get shot in the face and/or chest.
+ - Adminspawn only .357 DumDum rounds! Because sometimes the other guy just really needs to hurt.
+ - Bluespace beakers now have a chemical window through the side that shows chemical overlays.
+ - Plant DNA manipulators now let you chuck things over them. Or they WOULD, if LETPASSTHROW worked half a damn.
+
+ LetterN updated:
+
+ - uplink implant states
+ - tweaks how role assigning works
+
+ MrJWhit updated:
+
+ - Gives ashwalkers nightvision
+ - Makes tesla blast people, not the environment, to save the server.
+
+ TheObserver-sys updated:
+
+ - moves Garlic sprites from growing.dmi to growing_vegetable.dmi
+ - Removes the unused Electric Lime mutation, it just takes up space with no actual function nor sprites.
+ - Gives Catnip growing sprites
+ - Removes redundant images in growing.dmi
+
+ kiwedespars updated:
+
+ - 10 force to a fucking rubber cock.
+
+ lolman360 updated:
+
+ - shotgun stripper clip nerf. ammoboxes can now accept a load_delay that happens when they attack a magazine, internal or external.
+
+ ported from tg updated:
+
+ - bronze airlocks and windows can now be built
+ - i also tweaked bronze flooring to be cheaper.
+
+ silicons updated:
+
+ - stamina draining projectiles without stamina for their primary damage type now has their stamina damage taken into account for shield blocking, rather than the block being done for free for that.
+
+ timothyteakettle updated:
+
+ - snowflake code tidyup
+ - snowflake code for mutant bodypart selection has been rewritten to be ~14x shorter
+ - meat type and horns can now be selected by any species
+
+
+ 17 August 2020
+ DeltaFire15 updated:
+
+ - Cogscarabs are no longer always Pogscarabs
+
+ Strazyplus updated:
+
+ - Added drakeborgs
+ - Added drakeplushies
+ - added drakeborg sprites
+ - added drakeplushie sprites
+ - changed some code - added drakeplushies to backpack loadout Removed duplicate voresleeper belly sprites from engdrake & jantidrake. [CC BY-NC-SA 3.0](https://creativecommons.org/licenses/by-nc-sa/3.0/)
+ - Added CC BY-NC-SA 3.0 license details to icon/mob/cyborg moved drakeborg.dmi to icon/mob/cyborg
+
+
+ 16 August 2020
+ kiwedespars updated:
+
+ - nerfed hypereut chaplain weapon.
+ - 50% rng blockchance -> 0%
+ - parry made much worse because it's an actual weapon and a roundstart one at that.
+
+ zeroisthebiggay updated:
+
+
+ 15 August 2020
+ LetterN updated:
+
+ - missing anomaly core icons
+ - wrong state. blame the tg vertion i copied
+
+ silicons updated:
+
+ - the 8 rotation limit from clockwork chairs has been removed. please don't abuse this.
+ - ethereals can now wear underwear
+
+
14 August 2020
silicons updated:
@@ -1282,153 +1426,6 @@
- Removed unsavory things from the vent clog event
-
- 19 June 2020
- Bhijn updated:
-
- - Atmos can no longer become completely bricked
-
- Funce updated:
-
- - Square root circuit should now actually work.
-
- SmArtKar updated:
-
- TheSpaghetti updated:
-
- - more insectoid insects
-
- kevinz000 updated:
-
- - bay/polaris style say_emphasis has been added. You can now |italicize| _underline_ and +bold+ your messages.
-
- timothyteakettle updated:
-
- - Adds the brain trauma event, where one player gets a random brain trauma!
- - Adds the wisdom cow event, where the wisdom cow appears on the station!
- - Adds the fake virus event, where people get fake virus symptoms.
- - Adds the stray cargo pod event, where a cargo pod crashes into the station.
- - Adds the fugitives event, where fugitives are loose on the station, and it's the hunters jobs to capture them.
-
-
- 18 June 2020
- Detective-Google updated:
-
- - cog is now less the suck
- - couple little derpy bits
- - malf disk and illegal tech disk moved from ashwalker base (guaranteed) to tendrils (chance based)
-
- SmArtKar updated:
-
- - Ported shuttles from beestation
-
- timothyteakettle updated:
-
- - embeds got reworked, sticky tape was added, more bullets that ricochet also added
- - medbots can now be tipped over
- - added more medbot sounds
-
-
- 17 June 2020
- SmArtKar updated:
-
- - New ID icons
- - Sutures and Meshes
-
- Trilbyspaceclone updated:
-
- - Gin export takes gin now
-
-
- 16 June 2020
- Ghommie updated:
-
- - You can't blink nor use LOOC/AOOC as a petrified statue anymore.
-
- Trilbyspaceclone updated:
-
- - BEPIS decal painter has been moved to venders, replacing it being the flashdark
-
- kevinz000 updated:
-
- - projectile ricochets now use a less hilariously terrible way of being handled and should be easier to w
- - projectile runtime/ricocheting
- - Lobotomy no longer has a 50% chance of giving you a nigh-unremovable trauma, but does 50 brain damage even on success. On failure, it will give you a lobotomy-class trauma.
- - spinesnapping from tackling now only gives a lobotomy class trauma instead of magic.
-
- timothyteakettle updated:
-
- - Food carts now function as intended, allowing the pouring and mixing of drinks.
- - slimes can now change their color using alter form
-
-
- 15 June 2020
- Anturk, kevinz000 updated:
-
- - VV now properly allows access to datums in associative lists
- - SDQL2 printout has been upgraded for the 5th time.
-
- kevinz000 updated:
-
- - plushies now work. credits to timothytea.
- - You can now tape knives to cleanbots
-
- kevinz000 (port from VOREStation) updated:
-
- - Ported zoomba skins for cyborgs.
-
-
- 14 June 2020
- Bhijn updated:
-
- - raw HTML can no longer be used in flavortext
- - Added Lesbian Visibility Day (April 26th)
- - Added Bisexual Visibility Day (September 23rd)
- - Added Coming Out Day! (October 11th)
- - Added Intersex Awareness Day (October 26th)
- - Added Transgender Awareness Week (November 13th - 19th)
- - Added the Transgender Day of Remembrance (November 20th)
- - Added Asexual Awareness Week (Last full week of October, this year it'll be Oct. 25-31)
- - Added the Stonewall Riot Anniversary (June 28)
- - Moth week is now *actually* the last full week of July, instead of the 4th of every weekday + the 5th Sunday.
-
- Floof Ball / Kathrin Morrison / Floof Ball#0798 updated:
-
- - Improvised Pistol + 32 ACP ammo.
- - Improvised Energy Gun. Fires 5 shots of 10 burn damage each. Can be upgraded with a lens made from glassworking and T4 parts for a minor buff.
- - Ammo + gun part loot spawners for mappers.
- - New sprites for Improvised Rifle, the ability to sling the rifle and a sprite for that.
- - New sprites for the Improvised Shotgun and its sling sprite.
- - Improvised shotguns are now two-handed only.
- - Improvised shotguns now only have a much less harsh 0.9* modifier, keeping them two hits to crit with slugs and buckshot. It can no longer be dual-wielded but can still be sawn off for w_class medium (can fit in backpacks).
- - Missing handsaw icons added in.
- - Crafting table cleaned up into sections.
-
- Ghommie updated:
-
- - changed the weak attack message prefix from "inefficiently" to "limply", "feebly" and "saplessly" and lowered the threshold.
- - Fixing old beserker hardsuits having the wrong helmet type.
-
- The0bserver and Stewydeadmike updated:
-
- - Hey, there's a bit of dust in this recipe book! Recipes using peas? How many recipes does this book even have?
- - Adds 6 new food items, and 1 new consumable reagent using all forms of the recently discovered peas. Ask your local botanist and chef for them today!
-
- YakumoChen updated:
-
- - Adds polychrome options to loadout
- - Adds risque polychrome options to Kinkmate vendors
-
- kevinz000 updated:
-
- - emissive blockers can no longer be radioactive.
- - Ghosts can now scan air inside most objects that contain air by clicking on them.
- - Directional blocking has been added, keybound to G. This will reduce a portion of incoming damage if done with eligible items at the cost of stamina damage incurred to the user based on damage blocked as well as while active, as well as in most cases preventing the user from doing any attacks while this is active.
- - Parrying has been added, keybound to F. Timing-based counterattacks, effect heavily dependent on the item, WIP.
- - Disks are now smaller.
-
GoonStation 13 Development Team
diff --git a/html/changelogs/.all_changelog.yml b/html/changelogs/.all_changelog.yml
index e00922cbb3..10477b56d3 100644
--- a/html/changelogs/.all_changelog.yml
+++ b/html/changelogs/.all_changelog.yml
@@ -26914,3 +26914,110 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
2020-08-14:
silicons:
- bugfix: abductors can buy things
+2020-08-15:
+ LetterN:
+ - bugfix: missing anomaly core icons
+ - bugfix: wrong state. blame the tg vertion i copied
+ silicons:
+ - tweak: the 8 rotation limit from clockwork chairs has been removed. please don't
+ abuse this.
+ - tweak: ethereals can now wear underwear
+2020-08-16:
+ kiwedespars:
+ - balance: nerfed hypereut chaplain weapon.
+ - balance: 50% rng blockchance -> 0%
+ - balance: parry made much worse because it's an actual weapon and a roundstart
+ one at that.
+ zeroisthebiggay:
+ - rscadd: tips
+ - rscdel: tips
+2020-08-17:
+ DeltaFire15:
+ - bugfix: Cogscarabs are no longer always Pogscarabs
+ Strazyplus:
+ - rscadd: Added drakeborgs
+ - rscadd: Added drakeplushies
+ - imageadd: added drakeborg sprites
+ - imageadd: added drakeplushie sprites
+ - code_imp: changed some code - added drakeplushies to backpack loadout Removed
+ duplicate voresleeper belly sprites from engdrake & jantidrake. [CC BY-NC-SA
+ 3.0](https://creativecommons.org/licenses/by-nc-sa/3.0/)
+ - rscadd: Added CC BY-NC-SA 3.0 license details to icon/mob/cyborg moved drakeborg.dmi
+ to icon/mob/cyborg
+2020-08-18:
+ DeltaFire15:
+ - balance: 'kindle cast time: 15ds -> 25ds'
+ - tweak: Moved the Belligerent Scripture to where it should be in the code
+ Detective-Google:
+ - rscadd: glass floors
+ - rscadd: uncrowbarrable plasma floors tweak:disco inferno's plasma floors can no
+ longer be crowbarred.
+ - rscadd: ghost cafe has funky fresh art
+ - bugfix: you can actually remove glass floors now
+ - code_imp: get_equipped_items is hopefully less gross
+ - balance: plasma cutters are no longer gay
+ Hatterhat:
+ - balance: Slaughter demons (and laughter demons, being a subtype) are MOB_SIZE_LARGE,
+ with one of the more immediate effects being able to mark them with a crusher
+ and backstab them.
+ - balance: The funny blyat men have stumbled upon another surplus of Mosin-Nagants
+ and are starting to pack them into crates again.
+ - balance: Vehicle riders can now, by default, get shot in the face and/or chest.
+ - rscadd: Adminspawn only .357 DumDum rounds! Because sometimes the other guy just
+ really needs to hurt.
+ - rscadd: Bluespace beakers now have a chemical window through the side that shows
+ chemical overlays.
+ - rscadd: Plant DNA manipulators now let you chuck things over them. Or they WOULD,
+ if LETPASSTHROW worked half a damn.
+ LetterN:
+ - bugfix: uplink implant states
+ - tweak: tweaks how role assigning works
+ MrJWhit:
+ - rscadd: Gives ashwalkers nightvision
+ - balance: Makes tesla blast people, not the environment, to save the server.
+ TheObserver-sys:
+ - bugfix: moves Garlic sprites from growing.dmi to growing_vegetable.dmi
+ - rscdel: Removes the unused Electric Lime mutation, it just takes up space with
+ no actual function nor sprites.
+ - imageadd: Gives Catnip growing sprites
+ - imagedel: Removes redundant images in growing.dmi
+ kiwedespars:
+ - rscadd: 10 force to a fucking rubber cock.
+ lolman360:
+ - balance: shotgun stripper clip nerf. ammoboxes can now accept a load_delay that
+ happens when they attack a magazine, internal or external.
+ ported from tg:
+ - rscadd: bronze airlocks and windows can now be built
+ - balance: i also tweaked bronze flooring to be cheaper.
+ silicons:
+ - tweak: stamina draining projectiles without stamina for their primary damage type
+ now has their stamina damage taken into account for shield blocking, rather
+ than the block being done for free for that.
+ timothyteakettle:
+ - refactor: snowflake code tidyup
+ - refactor: snowflake code for mutant bodypart selection has been rewritten to be
+ ~14x shorter
+ - tweak: meat type and horns can now be selected by any species
+2020-08-20:
+ DeltaFire15:
+ - bugfix: The cooking oil damage formula is no longer scuffed.
+ - tweak: Changed the clockie help-link to lead to our own wiki.
+ Fikou:
+ - admin: admins can now do html in ahelps properly
+ Hatterhat:
+ - balance: Pirate threats are now announced as "business propositions", and their
+ arrivals are now also announced properly.
+ tiramisuapimancer:
+ - bugfix: Ethereal hair is now their body color instead of accidentally white
+2020-08-21:
+ LetterN:
+ - rscadd: Updates and adds some of the tips
+ Putnam3145:
+ - admin: added reftracking as a compile flag
+ SmArtKar:
+ - tweak: RSD limitation is now 500 tiles
+ - bugfix: Fixed broken RSD sprites
+ - config: Removed that shuttle limit
+ timothyteakettle:
+ - bugfix: two snouts can once again be chosen in customization
+ - bugfix: lizard snouts work again
diff --git a/icons/effects/160x160.dmi b/icons/effects/160x160.dmi
index 0a97573a9b..2adedb6c03 100644
Binary files a/icons/effects/160x160.dmi and b/icons/effects/160x160.dmi differ
diff --git a/icons/effects/96x96.dmi b/icons/effects/96x96.dmi
index b60ff97b2b..34f4adf6ce 100644
Binary files a/icons/effects/96x96.dmi and b/icons/effects/96x96.dmi differ
diff --git a/icons/effects/beam.dmi b/icons/effects/beam.dmi
index 0c4784553c..e5bff44ac4 100644
Binary files a/icons/effects/beam.dmi and b/icons/effects/beam.dmi differ
diff --git a/icons/effects/beam_splash.dmi b/icons/effects/beam_splash.dmi
new file mode 100644
index 0000000000..d7deb3e927
Binary files /dev/null and b/icons/effects/beam_splash.dmi differ
diff --git a/icons/effects/effects.dmi b/icons/effects/effects.dmi
index a2fce4678f..52164e1d33 100644
Binary files a/icons/effects/effects.dmi and b/icons/effects/effects.dmi differ
diff --git a/icons/effects/eldritch.dmi b/icons/effects/eldritch.dmi
new file mode 100644
index 0000000000..82549dccf0
Binary files /dev/null and b/icons/effects/eldritch.dmi differ
diff --git a/icons/effects/mouse_pointers/barn_target.dmi b/icons/effects/mouse_pointers/barn_target.dmi
new file mode 100644
index 0000000000..475a2b88b1
Binary files /dev/null and b/icons/effects/mouse_pointers/barn_target.dmi differ
diff --git a/icons/effects/mouse_pointers/blind_target.dmi b/icons/effects/mouse_pointers/blind_target.dmi
new file mode 100644
index 0000000000..1d33fc7a4c
Binary files /dev/null and b/icons/effects/mouse_pointers/blind_target.dmi differ
diff --git a/icons/effects/mouse_pointers/cult_target.dmi b/icons/effects/mouse_pointers/cult_target.dmi
new file mode 100644
index 0000000000..650feb3361
Binary files /dev/null and b/icons/effects/mouse_pointers/cult_target.dmi differ
diff --git a/icons/effects/mouse_pointers/mecha_mouse-disable.dmi b/icons/effects/mouse_pointers/mecha_mouse-disable.dmi
new file mode 100644
index 0000000000..48924c58c2
Binary files /dev/null and b/icons/effects/mouse_pointers/mecha_mouse-disable.dmi differ
diff --git a/icons/effects/mouse_pointers/mecha_mouse.dmi b/icons/effects/mouse_pointers/mecha_mouse.dmi
new file mode 100644
index 0000000000..4b46a44684
Binary files /dev/null and b/icons/effects/mouse_pointers/mecha_mouse.dmi differ
diff --git a/icons/effects/mouse_pointers/mindswap_target.dmi b/icons/effects/mouse_pointers/mindswap_target.dmi
new file mode 100644
index 0000000000..32ccda154d
Binary files /dev/null and b/icons/effects/mouse_pointers/mindswap_target.dmi differ
diff --git a/icons/effects/mouse_pointers/overload_machine_target.dmi b/icons/effects/mouse_pointers/overload_machine_target.dmi
new file mode 100644
index 0000000000..8bc67cdab6
Binary files /dev/null and b/icons/effects/mouse_pointers/overload_machine_target.dmi differ
diff --git a/icons/effects/mouse_pointers/override_machine_target.dmi b/icons/effects/mouse_pointers/override_machine_target.dmi
new file mode 100644
index 0000000000..77dbb4ba32
Binary files /dev/null and b/icons/effects/mouse_pointers/override_machine_target.dmi differ
diff --git a/icons/effects/mouse_pointers/throw_target.dmi b/icons/effects/mouse_pointers/throw_target.dmi
new file mode 100644
index 0000000000..660eafbf2b
Binary files /dev/null and b/icons/effects/mouse_pointers/throw_target.dmi differ
diff --git a/icons/effects/mouse_pointers/wrap_target.dmi b/icons/effects/mouse_pointers/wrap_target.dmi
new file mode 100644
index 0000000000..2e9a338c9e
Binary files /dev/null and b/icons/effects/mouse_pointers/wrap_target.dmi differ
diff --git a/icons/mob/actions/actions_ecult.dmi b/icons/mob/actions/actions_ecult.dmi
new file mode 100644
index 0000000000..0a130f006e
Binary files /dev/null and b/icons/mob/actions/actions_ecult.dmi differ
diff --git a/icons/mob/actions/backgrounds.dmi b/icons/mob/actions/backgrounds.dmi
index 07839588ce..6b983df95a 100644
Binary files a/icons/mob/actions/backgrounds.dmi and b/icons/mob/actions/backgrounds.dmi differ
diff --git a/icons/mob/clothing/head.dmi b/icons/mob/clothing/head.dmi
index 0ad9452994..16571a4aa1 100644
Binary files a/icons/mob/clothing/head.dmi and b/icons/mob/clothing/head.dmi differ
diff --git a/icons/mob/clothing/neck.dmi b/icons/mob/clothing/neck.dmi
index 86dec62a41..7bfecb4158 100644
Binary files a/icons/mob/clothing/neck.dmi and b/icons/mob/clothing/neck.dmi differ
diff --git a/icons/mob/clothing/suit.dmi b/icons/mob/clothing/suit.dmi
index c94e8a46d3..08d276a484 100644
Binary files a/icons/mob/clothing/suit.dmi and b/icons/mob/clothing/suit.dmi differ
diff --git a/icons/mob/clothing/underwear.dmi b/icons/mob/clothing/underwear.dmi
index f0c2cde93d..8cf1144a68 100644
Binary files a/icons/mob/clothing/underwear.dmi and b/icons/mob/clothing/underwear.dmi differ
diff --git a/icons/mob/cyborg/Drakeborg-licensing.txt b/icons/mob/cyborg/Drakeborg-licensing.txt
new file mode 100644
index 0000000000..f2d3ca925c
--- /dev/null
+++ b/icons/mob/cyborg/Drakeborg-licensing.txt
@@ -0,0 +1,69 @@
+Drakeborg & drakeplushies are created by deviantart.com/mizartz
+
+https://creativecommons.org/licenses/by-nc-sa/3.0/
+Attribution-NonCommercial-ShareAlike 3.0 Unported
+
+CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE LEGAL SERVICES. DISTRIBUTION OF THIS LICENSE DOES NOT CREATE AN ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE INFORMATION PROVIDED, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM ITS USE.
+License
+THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED.
+
+BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE MAY BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND CONDITIONS.
+
+1. Definitions
+
+"Adaptation" means a work based upon the Work, or upon the Work and other pre-existing works, such as a translation, adaptation, derivative work, arrangement of music or other alterations of a literary or artistic work, or phonogram or performance and includes cinematographic adaptations or any other form in which the Work may be recast, transformed, or adapted including in any form recognizably derived from the original, except that a work that constitutes a Collection will not be considered an Adaptation for the purpose of this License. For the avoidance of doubt, where the Work is a musical work, performance or phonogram, the synchronization of the Work in timed-relation with a moving image ("synching") will be considered an Adaptation for the purpose of this License.
+"Collection" means a collection of literary or artistic works, such as encyclopedias and anthologies, or performances, phonograms or broadcasts, or other works or subject matter other than works listed in Section 1(g) below, which, by reason of the selection and arrangement of their contents, constitute intellectual creations, in which the Work is included in its entirety in unmodified form along with one or more other contributions, each constituting separate and independent works in themselves, which together are assembled into a collective whole. A work that constitutes a Collection will not be considered an Adaptation (as defined above) for the purposes of this License.
+"Distribute" means to make available to the public the original and copies of the Work or Adaptation, as appropriate, through sale or other transfer of ownership.
+"License Elements" means the following high-level license attributes as selected by Licensor and indicated in the title of this License: Attribution, Noncommercial, ShareAlike.
+"Licensor" means the individual, individuals, entity or entities that offer(s) the Work under the terms of this License.
+"Original Author" means, in the case of a literary or artistic work, the individual, individuals, entity or entities who created the Work or if no individual or entity can be identified, the publisher; and in addition (i) in the case of a performance the actors, singers, musicians, dancers, and other persons who act, sing, deliver, declaim, play in, interpret or otherwise perform literary or artistic works or expressions of folklore; (ii) in the case of a phonogram the producer being the person or legal entity who first fixes the sounds of a performance or other sounds; and, (iii) in the case of broadcasts, the organization that transmits the broadcast.
+"Work" means the literary and/or artistic work offered under the terms of this License including without limitation any production in the literary, scientific and artistic domain, whatever may be the mode or form of its expression including digital form, such as a book, pamphlet and other writing; a lecture, address, sermon or other work of the same nature; a dramatic or dramatico-musical work; a choreographic work or entertainment in dumb show; a musical composition with or without words; a cinematographic work to which are assimilated works expressed by a process analogous to cinematography; a work of drawing, painting, architecture, sculpture, engraving or lithography; a photographic work to which are assimilated works expressed by a process analogous to photography; a work of applied art; an illustration, map, plan, sketch or three-dimensional work relative to geography, topography, architecture or science; a performance; a broadcast; a phonogram; a compilation of data to the extent it is protected as a copyrightable work; or a work performed by a variety or circus performer to the extent it is not otherwise considered a literary or artistic work.
+"You" means an individual or entity exercising rights under this License who has not previously violated the terms of this License with respect to the Work, or who has received express permission from the Licensor to exercise rights under this License despite a previous violation.
+"Publicly Perform" means to perform public recitations of the Work and to communicate to the public those public recitations, by any means or process, including by wire or wireless means or public digital performances; to make available to the public Works in such a way that members of the public may access these Works from a place and at a place individually chosen by them; to perform the Work to the public by any means or process and the communication to the public of the performances of the Work, including by public digital performance; to broadcast and rebroadcast the Work by any means including signs, sounds or images.
+"Reproduce" means to make copies of the Work by any means including without limitation by sound or visual recordings and the right of fixation and reproducing fixations of the Work, including storage of a protected performance or phonogram in digital form or other electronic medium.
+2. Fair Dealing Rights. Nothing in this License is intended to reduce, limit, or restrict any uses free from copyright or rights arising from limitations or exceptions that are provided for in connection with the copyright protection under copyright law or other applicable laws.
+
+3. License Grant. Subject to the terms and conditions of this License, Licensor hereby grants You a worldwide, royalty-free, non-exclusive, perpetual (for the duration of the applicable copyright) license to exercise the rights in the Work as stated below:
+
+to Reproduce the Work, to incorporate the Work into one or more Collections, and to Reproduce the Work as incorporated in the Collections;
+to create and Reproduce Adaptations provided that any such Adaptation, including any translation in any medium, takes reasonable steps to clearly label, demarcate or otherwise identify that changes were made to the original Work. For example, a translation could be marked "The original work was translated from English to Spanish," or a modification could indicate "The original work has been modified.";
+to Distribute and Publicly Perform the Work including as incorporated in Collections; and,
+to Distribute and Publicly Perform Adaptations.
+The above rights may be exercised in all media and formats whether now known or hereafter devised. The above rights include the right to make such modifications as are technically necessary to exercise the rights in other media and formats. Subject to Section 8(f), all rights not expressly granted by Licensor are hereby reserved, including but not limited to the rights described in Section 4(e).
+
+4. Restrictions. The license granted in Section 3 above is expressly made subject to and limited by the following restrictions:
+
+You may Distribute or Publicly Perform the Work only under the terms of this License. You must include a copy of, or the Uniform Resource Identifier (URI) for, this License with every copy of the Work You Distribute or Publicly Perform. You may not offer or impose any terms on the Work that restrict the terms of this License or the ability of the recipient of the Work to exercise the rights granted to that recipient under the terms of the License. You may not sublicense the Work. You must keep intact all notices that refer to this License and to the disclaimer of warranties with every copy of the Work You Distribute or Publicly Perform. When You Distribute or Publicly Perform the Work, You may not impose any effective technological measures on the Work that restrict the ability of a recipient of the Work from You to exercise the rights granted to that recipient under the terms of the License. This Section 4(a) applies to the Work as incorporated in a Collection, but this does not require the Collection apart from the Work itself to be made subject to the terms of this License. If You create a Collection, upon notice from any Licensor You must, to the extent practicable, remove from the Collection any credit as required by Section 4(d), as requested. If You create an Adaptation, upon notice from any Licensor You must, to the extent practicable, remove from the Adaptation any credit as required by Section 4(d), as requested.
+You may Distribute or Publicly Perform an Adaptation only under: (i) the terms of this License; (ii) a later version of this License with the same License Elements as this License; (iii) a Creative Commons jurisdiction license (either this or a later license version) that contains the same License Elements as this License (e.g., Attribution-NonCommercial-ShareAlike 3.0 US) ("Applicable License"). You must include a copy of, or the URI, for Applicable License with every copy of each Adaptation You Distribute or Publicly Perform. You may not offer or impose any terms on the Adaptation that restrict the terms of the Applicable License or the ability of the recipient of the Adaptation to exercise the rights granted to that recipient under the terms of the Applicable License. You must keep intact all notices that refer to the Applicable License and to the disclaimer of warranties with every copy of the Work as included in the Adaptation You Distribute or Publicly Perform. When You Distribute or Publicly Perform the Adaptation, You may not impose any effective technological measures on the Adaptation that restrict the ability of a recipient of the Adaptation from You to exercise the rights granted to that recipient under the terms of the Applicable License. This Section 4(b) applies to the Adaptation as incorporated in a Collection, but this does not require the Collection apart from the Adaptation itself to be made subject to the terms of the Applicable License.
+You may not exercise any of the rights granted to You in Section 3 above in any manner that is primarily intended for or directed toward commercial advantage or private monetary compensation. The exchange of the Work for other copyrighted works by means of digital file-sharing or otherwise shall not be considered to be intended for or directed toward commercial advantage or private monetary compensation, provided there is no payment of any monetary compensation in con-nection with the exchange of copyrighted works.
+If You Distribute, or Publicly Perform the Work or any Adaptations or Collections, You must, unless a request has been made pursuant to Section 4(a), keep intact all copyright notices for the Work and provide, reasonable to the medium or means You are utilizing: (i) the name of the Original Author (or pseudonym, if applicable) if supplied, and/or if the Original Author and/or Licensor designate another party or parties (e.g., a sponsor institute, publishing entity, journal) for attribution ("Attribution Parties") in Licensor's copyright notice, terms of service or by other reasonable means, the name of such party or parties; (ii) the title of the Work if supplied; (iii) to the extent reasonably practicable, the URI, if any, that Licensor specifies to be associated with the Work, unless such URI does not refer to the copyright notice or licensing information for the Work; and, (iv) consistent with Section 3(b), in the case of an Adaptation, a credit identifying the use of the Work in the Adaptation (e.g., "French translation of the Work by Original Author," or "Screenplay based on original Work by Original Author"). The credit required by this Section 4(d) may be implemented in any reasonable manner; provided, however, that in the case of a Adaptation or Collection, at a minimum such credit will appear, if a credit for all contributing authors of the Adaptation or Collection appears, then as part of these credits and in a manner at least as prominent as the credits for the other contributing authors. For the avoidance of doubt, You may only use the credit required by this Section for the purpose of attribution in the manner set out above and, by exercising Your rights under this License, You may not implicitly or explicitly assert or imply any connection with, sponsorship or endorsement by the Original Author, Licensor and/or Attribution Parties, as appropriate, of You or Your use of the Work, without the separate, express prior written permission of the Original Author, Licensor and/or Attribution Parties.
+For the avoidance of doubt:
+
+Non-waivable Compulsory License Schemes. In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme cannot be waived, the Licensor reserves the exclusive right to collect such royalties for any exercise by You of the rights granted under this License;
+Waivable Compulsory License Schemes. In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme can be waived, the Licensor reserves the exclusive right to collect such royalties for any exercise by You of the rights granted under this License if Your exercise of such rights is for a purpose or use which is otherwise than noncommercial as permitted under Section 4(c) and otherwise waives the right to collect royalties through any statutory or compulsory licensing scheme; and,
+Voluntary License Schemes. The Licensor reserves the right to collect royalties, whether individually or, in the event that the Licensor is a member of a collecting society that administers voluntary licensing schemes, via that society, from any exercise by You of the rights granted under this License that is for a purpose or use which is otherwise than noncommercial as permitted under Section 4(c).
+Except as otherwise agreed in writing by the Licensor or as may be otherwise permitted by applicable law, if You Reproduce, Distribute or Publicly Perform the Work either by itself or as part of any Adaptations or Collections, You must not distort, mutilate, modify or take other derogatory action in relation to the Work which would be prejudicial to the Original Author's honor or reputation. Licensor agrees that in those jurisdictions (e.g. Japan), in which any exercise of the right granted in Section 3(b) of this License (the right to make Adaptations) would be deemed to be a distortion, mutilation, modification or other derogatory action prejudicial to the Original Author's honor and reputation, the Licensor will waive or not assert, as appropriate, this Section, to the fullest extent permitted by the applicable national law, to enable You to reasonably exercise Your right under Section 3(b) of this License (right to make Adaptations) but not otherwise.
+5. Representations, Warranties and Disclaimer
+
+UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING AND TO THE FULLEST EXTENT PERMITTED BY APPLICABLE LAW, LICENSOR OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED WARRANTIES, SO THIS EXCLUSION MAY NOT APPLY TO YOU.
+
+6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+
+7. Termination
+
+This License and the rights granted hereunder will terminate automatically upon any breach by You of the terms of this License. Individuals or entities who have received Adaptations or Collections from You under this License, however, will not have their licenses terminated provided such individuals or entities remain in full compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will survive any termination of this License.
+Subject to the above terms and conditions, the license granted here is perpetual (for the duration of the applicable copyright in the Work). Notwithstanding the above, Licensor reserves the right to release the Work under different license terms or to stop distributing the Work at any time; provided, however that any such election will not serve to withdraw this License (or any other license that has been, or is required to be, granted under the terms of this License), and this License will continue in full force and effect unless terminated as stated above.
+8. Miscellaneous
+
+Each time You Distribute or Publicly Perform the Work or a Collection, the Licensor offers to the recipient a license to the Work on the same terms and conditions as the license granted to You under this License.
+Each time You Distribute or Publicly Perform an Adaptation, Licensor offers to the recipient a license to the original Work on the same terms and conditions as the license granted to You under this License.
+If any provision of this License is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this License, and without further action by the parties to this agreement, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.
+No term or provision of this License shall be deemed waived and no breach consented to unless such waiver or consent shall be in writing and signed by the party to be charged with such waiver or consent.
+This License constitutes the entire agreement between the parties with respect to the Work licensed here. There are no understandings, agreements or representations with respect to the Work not specified here. Licensor shall not be bound by any additional provisions that may appear in any communication from You. This License may not be modified without the mutual written agreement of the Licensor and You.
+The rights granted under, and the subject matter referenced, in this License were drafted utilizing the terminology of the Berne Convention for the Protection of Literary and Artistic Works (as amended on September 28, 1979), the Rome Convention of 1961, the WIPO Copyright Treaty of 1996, the WIPO Performances and Phonograms Treaty of 1996 and the Universal Copyright Convention (as revised on July 24, 1971). These rights and subject matter take effect in the relevant jurisdiction in which the License terms are sought to be enforced according to the corresponding provisions of the implementation of those treaty provisions in the applicable national law. If the standard suite of rights granted under applicable copyright law includes additional rights not granted under this License, such additional rights are deemed to be included in the License; this License is not intended to restrict the license of any rights under applicable law.
+Creative Commons Notice
+Creative Commons is not a party to this License, and makes no warranty whatsoever in connection with the Work. Creative Commons will not be liable to You or any party on any legal theory for any damages whatsoever, including without limitation any general, special, incidental or consequential damages arising in connection to this license. Notwithstanding the foregoing two (2) sentences, if Creative Commons has expressly identified itself as the Licensor hereunder, it shall have all rights and obligations of Licensor.
+
+Except for the limited purpose of indicating to the public that the Work is licensed under the CCPL, Creative Commons does not authorize the use by either party of the trademark "Creative Commons" or any related trademark or logo of Creative Commons without the prior written consent of Creative Commons. Any permitted use will be in compliance with Creative Commons' then-current trademark usage guidelines, as may be published on its website or otherwise made available upon request from time to time. For the avoidance of doubt, this trademark restriction does not form part of this License.
+
+Creative Commons may be contacted at https://creativecommons.org/.
\ No newline at end of file
diff --git a/icons/mob/cyborg/drakemech.dmi b/icons/mob/cyborg/drakemech.dmi
new file mode 100644
index 0000000000..6a4845d983
Binary files /dev/null and b/icons/mob/cyborg/drakemech.dmi differ
diff --git a/icons/mob/eldritch_mobs.dmi b/icons/mob/eldritch_mobs.dmi
new file mode 100644
index 0000000000..8a16d53f88
Binary files /dev/null and b/icons/mob/eldritch_mobs.dmi differ
diff --git a/icons/mob/hud.dmi b/icons/mob/hud.dmi
index c6dc7130c7..1d2007fd63 100644
Binary files a/icons/mob/hud.dmi and b/icons/mob/hud.dmi differ
diff --git a/icons/mob/inhands/64x64_lefthand.dmi b/icons/mob/inhands/64x64_lefthand.dmi
index 6b47171066..6dc8d82753 100644
Binary files a/icons/mob/inhands/64x64_lefthand.dmi and b/icons/mob/inhands/64x64_lefthand.dmi differ
diff --git a/icons/mob/inhands/64x64_righthand.dmi b/icons/mob/inhands/64x64_righthand.dmi
index 3750e28906..ca87f74a6f 100644
Binary files a/icons/mob/inhands/64x64_righthand.dmi and b/icons/mob/inhands/64x64_righthand.dmi differ
diff --git a/icons/mob/mob.dmi b/icons/mob/mob.dmi
index de09fb1c63..23f0e2cc13 100644
Binary files a/icons/mob/mob.dmi and b/icons/mob/mob.dmi differ
diff --git a/icons/obj/assemblies/new_assemblies.dmi b/icons/obj/assemblies/new_assemblies.dmi
index 2283b84c43..32eda1eb49 100644
Binary files a/icons/obj/assemblies/new_assemblies.dmi and b/icons/obj/assemblies/new_assemblies.dmi differ
diff --git a/icons/obj/chemical.dmi b/icons/obj/chemical.dmi
index aea15e2e39..cd12f4a457 100644
Binary files a/icons/obj/chemical.dmi and b/icons/obj/chemical.dmi differ
diff --git a/icons/obj/clothing/hats.dmi b/icons/obj/clothing/hats.dmi
index 60304999fa..8fbb2abe1e 100644
Binary files a/icons/obj/clothing/hats.dmi and b/icons/obj/clothing/hats.dmi differ
diff --git a/icons/obj/clothing/suits.dmi b/icons/obj/clothing/suits.dmi
index e8a360bc87..3476b16258 100644
Binary files a/icons/obj/clothing/suits.dmi and b/icons/obj/clothing/suits.dmi differ
diff --git a/icons/obj/decals.dmi b/icons/obj/decals.dmi
index c280ee786f..7dac61a663 100644
Binary files a/icons/obj/decals.dmi and b/icons/obj/decals.dmi differ
diff --git a/icons/obj/eldritch.dmi b/icons/obj/eldritch.dmi
new file mode 100644
index 0000000000..50c2913708
Binary files /dev/null and b/icons/obj/eldritch.dmi differ
diff --git a/icons/obj/hydroponics/growing.dmi b/icons/obj/hydroponics/growing.dmi
index 5415f47528..0866791ed6 100644
Binary files a/icons/obj/hydroponics/growing.dmi and b/icons/obj/hydroponics/growing.dmi differ
diff --git a/icons/obj/hydroponics/growing_vegetables.dmi b/icons/obj/hydroponics/growing_vegetables.dmi
index e174b4fb0b..ce0beb86ce 100644
Binary files a/icons/obj/hydroponics/growing_vegetables.dmi and b/icons/obj/hydroponics/growing_vegetables.dmi differ
diff --git a/icons/obj/license.txt b/icons/obj/license.txt
new file mode 100644
index 0000000000..2e27ba80f2
--- /dev/null
+++ b/icons/obj/license.txt
@@ -0,0 +1,3 @@
+icons/obj/plushies.dmi's icon state of secdrake and meddrake by Mizartz. It has been licensed under the CC BY-NC-SA 3.0 license.
+
+CC BY-NC-SA 3.0 https://creativecommons.org/licenses/by-nc-sa/3.0/
\ No newline at end of file
diff --git a/icons/obj/plushes.dmi b/icons/obj/plushes.dmi
index 11d02a46cc..ac0c338016 100644
Binary files a/icons/obj/plushes.dmi and b/icons/obj/plushes.dmi differ
diff --git a/icons/obj/projectiles.dmi b/icons/obj/projectiles.dmi
index 92e76f78bb..94568b8633 100644
Binary files a/icons/obj/projectiles.dmi and b/icons/obj/projectiles.dmi differ
diff --git a/icons/obj/reagentfillings.dmi b/icons/obj/reagentfillings.dmi
index d7a9a03c41..1ac941bae3 100644
Binary files a/icons/obj/reagentfillings.dmi and b/icons/obj/reagentfillings.dmi differ
diff --git a/icons/turf/floors.dmi b/icons/turf/floors.dmi
index 83dd4f5df8..f2b84bbe03 100644
Binary files a/icons/turf/floors.dmi and b/icons/turf/floors.dmi differ
diff --git a/icons/turf/floors/glass.dmi b/icons/turf/floors/glass.dmi
new file mode 100644
index 0000000000..adf6f57aaa
Binary files /dev/null and b/icons/turf/floors/glass.dmi differ
diff --git a/icons/turf/floors/reinf_glass.dmi b/icons/turf/floors/reinf_glass.dmi
new file mode 100644
index 0000000000..dda99cd07f
Binary files /dev/null and b/icons/turf/floors/reinf_glass.dmi differ
diff --git a/modular_citadel/icons/mob/widerobot.dmi b/modular_citadel/icons/mob/widerobot.dmi
index 50c29bb75f..29eb35c715 100644
Binary files a/modular_citadel/icons/mob/widerobot.dmi and b/modular_citadel/icons/mob/widerobot.dmi differ
diff --git a/sound/ambience/antag/ecult_op.ogg b/sound/ambience/antag/ecult_op.ogg
new file mode 100644
index 0000000000..9944e833a6
Binary files /dev/null and b/sound/ambience/antag/ecult_op.ogg differ
diff --git a/sound/effects/footstep/rustystep1.ogg b/sound/effects/footstep/rustystep1.ogg
new file mode 100644
index 0000000000..bf90d52779
Binary files /dev/null and b/sound/effects/footstep/rustystep1.ogg differ
diff --git a/sound/machines/sm/accent/delam/1.ogg b/sound/machines/sm/accent/delam/1.ogg
new file mode 100644
index 0000000000..75c79f89ab
Binary files /dev/null and b/sound/machines/sm/accent/delam/1.ogg differ
diff --git a/sound/machines/sm/accent/delam/10.ogg b/sound/machines/sm/accent/delam/10.ogg
new file mode 100644
index 0000000000..c87b63b526
Binary files /dev/null and b/sound/machines/sm/accent/delam/10.ogg differ
diff --git a/sound/machines/sm/accent/delam/11.ogg b/sound/machines/sm/accent/delam/11.ogg
new file mode 100644
index 0000000000..c7f678245b
Binary files /dev/null and b/sound/machines/sm/accent/delam/11.ogg differ
diff --git a/sound/machines/sm/accent/delam/12.ogg b/sound/machines/sm/accent/delam/12.ogg
new file mode 100644
index 0000000000..a395942183
Binary files /dev/null and b/sound/machines/sm/accent/delam/12.ogg differ
diff --git a/sound/machines/sm/accent/delam/13.ogg b/sound/machines/sm/accent/delam/13.ogg
new file mode 100644
index 0000000000..934f17947d
Binary files /dev/null and b/sound/machines/sm/accent/delam/13.ogg differ
diff --git a/sound/machines/sm/accent/delam/14.ogg b/sound/machines/sm/accent/delam/14.ogg
new file mode 100644
index 0000000000..4175e5b947
Binary files /dev/null and b/sound/machines/sm/accent/delam/14.ogg differ
diff --git a/sound/machines/sm/accent/delam/15.ogg b/sound/machines/sm/accent/delam/15.ogg
new file mode 100644
index 0000000000..dcf73deb84
Binary files /dev/null and b/sound/machines/sm/accent/delam/15.ogg differ
diff --git a/sound/machines/sm/accent/delam/16.ogg b/sound/machines/sm/accent/delam/16.ogg
new file mode 100644
index 0000000000..20bc19399b
Binary files /dev/null and b/sound/machines/sm/accent/delam/16.ogg differ
diff --git a/sound/machines/sm/accent/delam/17.ogg b/sound/machines/sm/accent/delam/17.ogg
new file mode 100644
index 0000000000..b517fb3d3d
Binary files /dev/null and b/sound/machines/sm/accent/delam/17.ogg differ
diff --git a/sound/machines/sm/accent/delam/18.ogg b/sound/machines/sm/accent/delam/18.ogg
new file mode 100644
index 0000000000..4ef138d27a
Binary files /dev/null and b/sound/machines/sm/accent/delam/18.ogg differ
diff --git a/sound/machines/sm/accent/delam/19.ogg b/sound/machines/sm/accent/delam/19.ogg
new file mode 100644
index 0000000000..f638a6971b
Binary files /dev/null and b/sound/machines/sm/accent/delam/19.ogg differ
diff --git a/sound/machines/sm/accent/delam/2.ogg b/sound/machines/sm/accent/delam/2.ogg
new file mode 100644
index 0000000000..5b480daa2e
Binary files /dev/null and b/sound/machines/sm/accent/delam/2.ogg differ
diff --git a/sound/machines/sm/accent/delam/20.ogg b/sound/machines/sm/accent/delam/20.ogg
new file mode 100644
index 0000000000..6072bc6227
Binary files /dev/null and b/sound/machines/sm/accent/delam/20.ogg differ
diff --git a/sound/machines/sm/accent/delam/21.ogg b/sound/machines/sm/accent/delam/21.ogg
new file mode 100644
index 0000000000..1223dd946d
Binary files /dev/null and b/sound/machines/sm/accent/delam/21.ogg differ
diff --git a/sound/machines/sm/accent/delam/22.ogg b/sound/machines/sm/accent/delam/22.ogg
new file mode 100644
index 0000000000..9ccfb9b55a
Binary files /dev/null and b/sound/machines/sm/accent/delam/22.ogg differ
diff --git a/sound/machines/sm/accent/delam/23.ogg b/sound/machines/sm/accent/delam/23.ogg
new file mode 100644
index 0000000000..6399a8376a
Binary files /dev/null and b/sound/machines/sm/accent/delam/23.ogg differ
diff --git a/sound/machines/sm/accent/delam/24.ogg b/sound/machines/sm/accent/delam/24.ogg
new file mode 100644
index 0000000000..b51d359807
Binary files /dev/null and b/sound/machines/sm/accent/delam/24.ogg differ
diff --git a/sound/machines/sm/accent/delam/25.ogg b/sound/machines/sm/accent/delam/25.ogg
new file mode 100644
index 0000000000..823f22f136
Binary files /dev/null and b/sound/machines/sm/accent/delam/25.ogg differ
diff --git a/sound/machines/sm/accent/delam/26.ogg b/sound/machines/sm/accent/delam/26.ogg
new file mode 100644
index 0000000000..24b2a2f040
Binary files /dev/null and b/sound/machines/sm/accent/delam/26.ogg differ
diff --git a/sound/machines/sm/accent/delam/27.ogg b/sound/machines/sm/accent/delam/27.ogg
new file mode 100644
index 0000000000..4b4b145b7b
Binary files /dev/null and b/sound/machines/sm/accent/delam/27.ogg differ
diff --git a/sound/machines/sm/accent/delam/28.ogg b/sound/machines/sm/accent/delam/28.ogg
new file mode 100644
index 0000000000..7bc71bf0e6
Binary files /dev/null and b/sound/machines/sm/accent/delam/28.ogg differ
diff --git a/sound/machines/sm/accent/delam/29.ogg b/sound/machines/sm/accent/delam/29.ogg
new file mode 100644
index 0000000000..7fec2f271c
Binary files /dev/null and b/sound/machines/sm/accent/delam/29.ogg differ
diff --git a/sound/machines/sm/accent/delam/3.ogg b/sound/machines/sm/accent/delam/3.ogg
new file mode 100644
index 0000000000..5b57cc2707
Binary files /dev/null and b/sound/machines/sm/accent/delam/3.ogg differ
diff --git a/sound/machines/sm/accent/delam/30.ogg b/sound/machines/sm/accent/delam/30.ogg
new file mode 100644
index 0000000000..ed1ec7d89f
Binary files /dev/null and b/sound/machines/sm/accent/delam/30.ogg differ
diff --git a/sound/machines/sm/accent/delam/31.ogg b/sound/machines/sm/accent/delam/31.ogg
new file mode 100644
index 0000000000..0baa82e246
Binary files /dev/null and b/sound/machines/sm/accent/delam/31.ogg differ
diff --git a/sound/machines/sm/accent/delam/32.ogg b/sound/machines/sm/accent/delam/32.ogg
new file mode 100644
index 0000000000..e925b32d67
Binary files /dev/null and b/sound/machines/sm/accent/delam/32.ogg differ
diff --git a/sound/machines/sm/accent/delam/33.ogg b/sound/machines/sm/accent/delam/33.ogg
new file mode 100644
index 0000000000..9ddec0e84a
Binary files /dev/null and b/sound/machines/sm/accent/delam/33.ogg differ
diff --git a/sound/machines/sm/accent/delam/4.ogg b/sound/machines/sm/accent/delam/4.ogg
new file mode 100644
index 0000000000..aa4f4da071
Binary files /dev/null and b/sound/machines/sm/accent/delam/4.ogg differ
diff --git a/sound/machines/sm/accent/delam/5.ogg b/sound/machines/sm/accent/delam/5.ogg
new file mode 100644
index 0000000000..be438f6f15
Binary files /dev/null and b/sound/machines/sm/accent/delam/5.ogg differ
diff --git a/sound/machines/sm/accent/delam/6.ogg b/sound/machines/sm/accent/delam/6.ogg
new file mode 100644
index 0000000000..b89d52a564
Binary files /dev/null and b/sound/machines/sm/accent/delam/6.ogg differ
diff --git a/sound/machines/sm/accent/delam/7.ogg b/sound/machines/sm/accent/delam/7.ogg
new file mode 100644
index 0000000000..3a9cfc62ca
Binary files /dev/null and b/sound/machines/sm/accent/delam/7.ogg differ
diff --git a/sound/machines/sm/accent/delam/8.ogg b/sound/machines/sm/accent/delam/8.ogg
new file mode 100644
index 0000000000..7bc0a727fa
Binary files /dev/null and b/sound/machines/sm/accent/delam/8.ogg differ
diff --git a/sound/machines/sm/accent/delam/9.ogg b/sound/machines/sm/accent/delam/9.ogg
new file mode 100644
index 0000000000..5c1bd37405
Binary files /dev/null and b/sound/machines/sm/accent/delam/9.ogg differ
diff --git a/sound/machines/sm/accent/normal/1.ogg b/sound/machines/sm/accent/normal/1.ogg
new file mode 100644
index 0000000000..e92beed7fe
Binary files /dev/null and b/sound/machines/sm/accent/normal/1.ogg differ
diff --git a/sound/machines/sm/accent/normal/10.ogg b/sound/machines/sm/accent/normal/10.ogg
new file mode 100644
index 0000000000..9efb616f0b
Binary files /dev/null and b/sound/machines/sm/accent/normal/10.ogg differ
diff --git a/sound/machines/sm/accent/normal/11.ogg b/sound/machines/sm/accent/normal/11.ogg
new file mode 100644
index 0000000000..2af0981ef1
Binary files /dev/null and b/sound/machines/sm/accent/normal/11.ogg differ
diff --git a/sound/machines/sm/accent/normal/12.ogg b/sound/machines/sm/accent/normal/12.ogg
new file mode 100644
index 0000000000..2fab78b02d
Binary files /dev/null and b/sound/machines/sm/accent/normal/12.ogg differ
diff --git a/sound/machines/sm/accent/normal/13.ogg b/sound/machines/sm/accent/normal/13.ogg
new file mode 100644
index 0000000000..784e84e4a8
Binary files /dev/null and b/sound/machines/sm/accent/normal/13.ogg differ
diff --git a/sound/machines/sm/accent/normal/14.ogg b/sound/machines/sm/accent/normal/14.ogg
new file mode 100644
index 0000000000..af170394dd
Binary files /dev/null and b/sound/machines/sm/accent/normal/14.ogg differ
diff --git a/sound/machines/sm/accent/normal/15.ogg b/sound/machines/sm/accent/normal/15.ogg
new file mode 100644
index 0000000000..05c88c6b29
Binary files /dev/null and b/sound/machines/sm/accent/normal/15.ogg differ
diff --git a/sound/machines/sm/accent/normal/16.ogg b/sound/machines/sm/accent/normal/16.ogg
new file mode 100644
index 0000000000..46b0e33980
Binary files /dev/null and b/sound/machines/sm/accent/normal/16.ogg differ
diff --git a/sound/machines/sm/accent/normal/17.ogg b/sound/machines/sm/accent/normal/17.ogg
new file mode 100644
index 0000000000..e432b2ee02
Binary files /dev/null and b/sound/machines/sm/accent/normal/17.ogg differ
diff --git a/sound/machines/sm/accent/normal/18.ogg b/sound/machines/sm/accent/normal/18.ogg
new file mode 100644
index 0000000000..1e0e91abc8
Binary files /dev/null and b/sound/machines/sm/accent/normal/18.ogg differ
diff --git a/sound/machines/sm/accent/normal/19.ogg b/sound/machines/sm/accent/normal/19.ogg
new file mode 100644
index 0000000000..31de063e02
Binary files /dev/null and b/sound/machines/sm/accent/normal/19.ogg differ
diff --git a/sound/machines/sm/accent/normal/2.ogg b/sound/machines/sm/accent/normal/2.ogg
new file mode 100644
index 0000000000..05e3c9ff17
Binary files /dev/null and b/sound/machines/sm/accent/normal/2.ogg differ
diff --git a/sound/machines/sm/accent/normal/20.ogg b/sound/machines/sm/accent/normal/20.ogg
new file mode 100644
index 0000000000..36810bd8f1
Binary files /dev/null and b/sound/machines/sm/accent/normal/20.ogg differ
diff --git a/sound/machines/sm/accent/normal/21.ogg b/sound/machines/sm/accent/normal/21.ogg
new file mode 100644
index 0000000000..306e8856e5
Binary files /dev/null and b/sound/machines/sm/accent/normal/21.ogg differ
diff --git a/sound/machines/sm/accent/normal/22.ogg b/sound/machines/sm/accent/normal/22.ogg
new file mode 100644
index 0000000000..38286aa98b
Binary files /dev/null and b/sound/machines/sm/accent/normal/22.ogg differ
diff --git a/sound/machines/sm/accent/normal/23.ogg b/sound/machines/sm/accent/normal/23.ogg
new file mode 100644
index 0000000000..89f85fed91
Binary files /dev/null and b/sound/machines/sm/accent/normal/23.ogg differ
diff --git a/sound/machines/sm/accent/normal/24.ogg b/sound/machines/sm/accent/normal/24.ogg
new file mode 100644
index 0000000000..7c12a3e768
Binary files /dev/null and b/sound/machines/sm/accent/normal/24.ogg differ
diff --git a/sound/machines/sm/accent/normal/25.ogg b/sound/machines/sm/accent/normal/25.ogg
new file mode 100644
index 0000000000..f89175ceb1
Binary files /dev/null and b/sound/machines/sm/accent/normal/25.ogg differ
diff --git a/sound/machines/sm/accent/normal/26.ogg b/sound/machines/sm/accent/normal/26.ogg
new file mode 100644
index 0000000000..9efd1d8ef3
Binary files /dev/null and b/sound/machines/sm/accent/normal/26.ogg differ
diff --git a/sound/machines/sm/accent/normal/27.ogg b/sound/machines/sm/accent/normal/27.ogg
new file mode 100644
index 0000000000..1fb1edbb5a
Binary files /dev/null and b/sound/machines/sm/accent/normal/27.ogg differ
diff --git a/sound/machines/sm/accent/normal/28.ogg b/sound/machines/sm/accent/normal/28.ogg
new file mode 100644
index 0000000000..890c5ea429
Binary files /dev/null and b/sound/machines/sm/accent/normal/28.ogg differ
diff --git a/sound/machines/sm/accent/normal/29.ogg b/sound/machines/sm/accent/normal/29.ogg
new file mode 100644
index 0000000000..cd2aa40714
Binary files /dev/null and b/sound/machines/sm/accent/normal/29.ogg differ
diff --git a/sound/machines/sm/accent/normal/3.ogg b/sound/machines/sm/accent/normal/3.ogg
new file mode 100644
index 0000000000..38de5571a4
Binary files /dev/null and b/sound/machines/sm/accent/normal/3.ogg differ
diff --git a/sound/machines/sm/accent/normal/30.ogg b/sound/machines/sm/accent/normal/30.ogg
new file mode 100644
index 0000000000..87d1782768
Binary files /dev/null and b/sound/machines/sm/accent/normal/30.ogg differ
diff --git a/sound/machines/sm/accent/normal/31.ogg b/sound/machines/sm/accent/normal/31.ogg
new file mode 100644
index 0000000000..9ce3eeb72e
Binary files /dev/null and b/sound/machines/sm/accent/normal/31.ogg differ
diff --git a/sound/machines/sm/accent/normal/32.ogg b/sound/machines/sm/accent/normal/32.ogg
new file mode 100644
index 0000000000..26ca056142
Binary files /dev/null and b/sound/machines/sm/accent/normal/32.ogg differ
diff --git a/sound/machines/sm/accent/normal/33.ogg b/sound/machines/sm/accent/normal/33.ogg
new file mode 100644
index 0000000000..24964c1ce9
Binary files /dev/null and b/sound/machines/sm/accent/normal/33.ogg differ
diff --git a/sound/machines/sm/accent/normal/4.ogg b/sound/machines/sm/accent/normal/4.ogg
new file mode 100644
index 0000000000..2e71e976e8
Binary files /dev/null and b/sound/machines/sm/accent/normal/4.ogg differ
diff --git a/sound/machines/sm/accent/normal/5.ogg b/sound/machines/sm/accent/normal/5.ogg
new file mode 100644
index 0000000000..04852e10f2
Binary files /dev/null and b/sound/machines/sm/accent/normal/5.ogg differ
diff --git a/sound/machines/sm/accent/normal/6.ogg b/sound/machines/sm/accent/normal/6.ogg
new file mode 100644
index 0000000000..bf06c06bbe
Binary files /dev/null and b/sound/machines/sm/accent/normal/6.ogg differ
diff --git a/sound/machines/sm/accent/normal/7.ogg b/sound/machines/sm/accent/normal/7.ogg
new file mode 100644
index 0000000000..d29821701f
Binary files /dev/null and b/sound/machines/sm/accent/normal/7.ogg differ
diff --git a/sound/machines/sm/accent/normal/8.ogg b/sound/machines/sm/accent/normal/8.ogg
new file mode 100644
index 0000000000..0b94b9dbe0
Binary files /dev/null and b/sound/machines/sm/accent/normal/8.ogg differ
diff --git a/sound/machines/sm/accent/normal/9.ogg b/sound/machines/sm/accent/normal/9.ogg
new file mode 100644
index 0000000000..545b038be1
Binary files /dev/null and b/sound/machines/sm/accent/normal/9.ogg differ
diff --git a/sound/machines/sm/loops/calm.ogg b/sound/machines/sm/loops/calm.ogg
new file mode 100644
index 0000000000..cee14fcd13
Binary files /dev/null and b/sound/machines/sm/loops/calm.ogg differ
diff --git a/sound/machines/sm/loops/delamming.ogg b/sound/machines/sm/loops/delamming.ogg
new file mode 100644
index 0000000000..7d79f0e3c4
Binary files /dev/null and b/sound/machines/sm/loops/delamming.ogg differ
diff --git a/sound/machines/sm/supermatter1.ogg b/sound/machines/sm/supermatter1.ogg
index 1860e78800..be5185009e 100644
Binary files a/sound/machines/sm/supermatter1.ogg and b/sound/machines/sm/supermatter1.ogg differ
diff --git a/sound/machines/sm/supermatter2.ogg b/sound/machines/sm/supermatter2.ogg
index fb2d39fe26..5c98d28ed1 100644
Binary files a/sound/machines/sm/supermatter2.ogg and b/sound/machines/sm/supermatter2.ogg differ
diff --git a/sound/machines/sm/supermatter3.ogg b/sound/machines/sm/supermatter3.ogg
index 93ac3d505b..fb8e09166c 100644
Binary files a/sound/machines/sm/supermatter3.ogg and b/sound/machines/sm/supermatter3.ogg differ
diff --git a/sound/music/twilight.ogg b/sound/music/twilight.ogg
new file mode 100644
index 0000000000..74b811b3e5
Binary files /dev/null and b/sound/music/twilight.ogg differ
diff --git a/strings/round_start_sounds.txt b/strings/round_start_sounds.txt
index c67bf6b4a6..177a3ea0a8 100644
--- a/strings/round_start_sounds.txt
+++ b/strings/round_start_sounds.txt
@@ -25,3 +25,4 @@ sound/music/rocketridersprayer.ogg
sound/music/theend.ogg
sound/music/flyinghigh.ogg
sound/music/samsara.ogg
+sound/music/twilight.ogg
\ No newline at end of file
diff --git a/strings/sillytips.txt b/strings/sillytips.txt
index bc59a109f0..e6710de95e 100644
--- a/strings/sillytips.txt
+++ b/strings/sillytips.txt
@@ -25,6 +25,7 @@ This game is older than most of the people playing it.
Do not go gentle into that good night.
Flashbangs can weaken blob tiles, allowing for you and the crew to easily destroy them.
Just the tip?
+You can grab someone by clicking on them with the grab intent, then upgrade the grab by clicking on them once more. An aggressive grab will momentarily stun someone, allow you to place Mekhi on a table by clicking on it, or throw them by toggling on throwing.
Some people are unable to read text on a game where half of it is based on text.
As the Captain, you can use a whetstone to sharpen your fancy fountain pen for extra robustness.
As the Lawyer, you are the last bastion of roleplay-focused jobs. Even the curator got a whip to go fight people with, that sellout!
@@ -43,5 +44,8 @@ Plasma men are a powerful race with many perks! No really, I swear! So what if t
As a Cargo Tech make sure to always buy a tesla to sell back to CC. They love those those. Trust me!
Help.
Maints.
-BZ stops or slows down Lings chem regeneration drastically, make sure to BZ flood the station when lings are confirmed!
Admins always regret meme options in their polls.
+Putting cat ears on securitrons makes them table people and nya. Mekhi isn't a cat, but he still goes on the table, just roll with it.
+As a Changeling, you can live without a head as they are merely vestigal to you, now, finally, you can be a Dullahan without it being Halloween.
+People actually have fictional sex between fictional characters in this game.
+When in doubt, take a break. A long break, preferably. If the game is wearing down your mental state and it's starting to lose any semblance of fun value, go and do something else for a month or two. By the time you come back, everything you liked will have been changed anyways.
diff --git a/strings/tips.txt b/strings/tips.txt
index 043405c7a0..5dc4e1b985 100644
--- a/strings/tips.txt
+++ b/strings/tips.txt
@@ -1,83 +1,91 @@
Where the space map levels connect is randomized every round, but are otherwise kept consistent within rounds. Remember that they are not necessarily bidirectional!
You can catch thrown items by toggling on your throw mode with an empty hand active.
-To crack the safe in the vault, use a stethoscope or explosives on it.
+To crack the safe in the vault, have a stethoscope in one of your hands and fiddle with the tumbler or you can alternatively use several concentrated explosive charges on it. Remember that the latter may result in the contents of the safe becoming a pile of ash.
You can climb onto a table by dragging yourself onto one. This takes time and drops the items in your hands on the table. Clicking on a table that someone else is climbing onto will knock them down.
You can drag other players onto yourself to open the strip menu, letting you remove their equipment or force them to wear something. Note that exosuits or helmets will block your access to the clothing beneath them, and that certain items take longer to strip or put on than others.
Clicking on a windoor rather then bumping into it will keep it open, you can click it again to close it.
You can spray a fire extinguisher, throw items or fire a gun while floating through space to change your direction. Simply fire opposite to where you want to go.
You can change the control scheme by pressing tab. One is WASD, the other is the arrow keys. Keep in mind that hotkeys are also changed with this.
-All vending machines can be hacked to obtain some contraband items from them, and many can be fed with coins to gain access to premium items.
+All vending machines can be hacked to obtain some contraband items from them, and many may charge extra credits to give you premium items.
Firesuits and winter coats offer mild protection from the cold, allowing you to spend longer periods of time near breaches and space than if wearing nothing at all.
Glass shards can be welded to make glass, and metal rods can be welded to make metal. Ores can be welded too, but this takes a lot of fuel.
If you need to drag multiple people either to safety or to space, bring a locker or crate over and stuff them all in before hauling them off.
-You can grab someone by clicking on them with the grab intent, then upgrade the grab by clicking on them once more. An aggressive grab will momentarily stun someone, allow you to place Mekhi on a table by clicking on it, or throw them by toggling on throwing.
+You can grab someone by clicking on them with the grab intent, then upgrade the grab by clicking on them once more. An aggressive grab can temporarily stun someone depending on their luck with resisting out of it, allowing you to slam them on a table by clicking on it, or throw them by toggling on throwing.
Holding alt and left clicking a tile will allow you to see its contents in the top right window pane, which is much faster than right clicking.
The resist button will allow you to resist out of handcuffs, being buckled to a chair or bed, out of locked lockers and more. Whenever you're stuck, try resisting!
You can move an item out of the way by dragging it and then clicking on an adjacent tile with an empty hand.
-You can recolor certain items like jumpsuits and gloves in washing machines by also throwing in a crayon.
+You can recolor certain items like jumpsuits and gloves in washing machines by also throwing in a crayon. For more advanced fashion you can spray items with a spray can to tint its colors. Some items work better than others at displaying their tints, like sterile and paper masks, or darkly colored gloves.
Maintenance is full of equipment that is randomized every round. Look around and see if anything is worth using.
-Some roles cannot be antagonists by default, but antag selection is decided first. For instance, you can set Security Officer to High without affecting your chances of becoming an antag -- the game will just select a different role.
+Some roles cannot be antagonists by default, but antag selection is decided first. For instance, you can set Security Officer to High without affecting your chances of becoming an antag - the game will just assign you to your next preferred role - or in the case that you have no such preferences set, a random role entirely.
There are many places around the station to hide contraband. A few for starters: linen boxes, toilet cisterns, body bags. Experiment to find more!
On all maps, you can use a machine in the vault to deposit space cash for cargo points. Otherwise, use it to steal the station's cash and get out before the alarm goes off.
-As the Captain, you are one of the highest priority targets on the station. Everything from revolutions, to nuclear operatives, to traitors that need to rob you of your unique lasgun or your life are things to worry about.
-As the Captain, always take the nuclear disk and pinpointer with you every shift. It's a good idea to give one of these to another head you can trust with keeping it safe, such as the Head of Security.
+As the Captain, you are one of the highest priority targets on the station. Everything from revolutions looking to thwart your rule, to nuclear operatives seeking the disk, to traitors that need to rob you of your several high value items - or your life are all things to be concerned about.
+As the Captain, always take the nuclear disk and pinpointer with you every shift. It's a good idea to give one of these to another head you can trust with keeping it safe, such as the Head of Personnel.
As the Captain, you have absolute access and control over the station, but this does not mean that being a horrible person won't result in mutiny and a ban.
As the Captain, you have a fancy pen that can be used as a holdout dagger or even as a scalpel in surgery!
As the Captain, you can purchase a new emergency shuttle using a communications console. Some require credits, while others give you credits in exchange. Keep in mind that purchasing dangerous shuttles will incur the ire of your crew.
-As the Chief Medical Officer, your hypospray is like a refillable instant injection syringe that can hold 30 units as opposed to the standard 15.
-As the Chief Medical Officer, coordinate and communicate with your doctors, chemists, and geneticists during a nuclear emergency, blob infestation, or some other crisis to keep people alive and fighting.
-As a Medical Doctor, pester Research for improved surgical tools. They work faster, don't cost much and are typically more deadly.
+As the Chief Medical Officer, your hypospray is like the ones that your Medical Doctors can buy, except it comes in a fancy box that can hold several more hypovials than the standard, and already comes preloaded with specially-made high-capacity hypovials that hold double the reagents the standard ones do.
+As the Chief Medical Officer, coordinate and communicate with your doctors, chemists, and paramedics during a nuclear emergency, blob infestation, or some other crisis to keep people alive and fighting.
+As a Medical Doctor, pester Research for improved surgical tools. They work faster, combine the purposes of several tools in one (scalpel/saw, retractor/hemostat, drill/cautery), and don't cost many materials to boot!
+As a Medical Doctor, the surgical saw and drill are both powerful weapons, the saw is sharp and can slice and dice, while the drill can quickly blind someone if aimed for the eyes. The laser scalpel is an upgraded version producible with Research's aid, and it has the highest force of most common place weapons, while still remaining sharp.
As a Medical Doctor, your belt can hold a full set of surgical tools. Using sterilizine before each attempt during surgery will reduce your failure chance on tricky steps or when using less-than-optimal equipment.
As a Medical Doctor, you can attempt to drain blood from a husk with a syringe to determine the cause. If you can extract blood, it was caused by extreme temperatures or lasers, if there is no blood to extract, you have confirmed the presence of changelings.
As a Medical Doctor, while both heal toxin damage, the difference between charcoal and antitoxin is that charcoal will actively remove all other reagents from one's body, while antitoxin only removes various toxins - but can overdose.
-As a Medical Doctor, you can surgically implant or extract things from people's chests. This can range from putting in a bomb to pulling out an alien larva.
+As a Medical Doctor, you can surgically implant or extract things from people's chests by performing a cavity implant. This could range from inserting a suicide bomb to embedding the nuke disk into the Captain's chest.
+As a Medical Doctor, it's of utmost urgency that you tend to anyone who's been hugged by a facehugger. You only have a couple of minutes from the initial attachment to perform organ manipulation to their chest and remove the rapidly developing alien embryo before it bursts out and immediately kills your patient.
As a Medical Doctor, you must target the correct limb and be on help intent when trying to perform surgery on someone. Using disarm attempt will intentionally fail the surgery step.
-As a Medical Doctor, corpses with the "...and their soul has departed" description no longer have a ghost attached to them and aren't usually revivable or cloneable. However it may prove useful to be creative in your revivification techniques with these bodies.
-As a Medical Doctor, treating plasmamen is not impossible! Salbutamol stops them from suffocating and showers stop them from burning alive. You can even perform surgery on them by doing the procedure on a roller bed under a shower.
+As a Medical Doctor, corpses with the "...and their soul has departed" description no longer have a ghost attached to them and can't be revived. However it may prove useful to be creative in your revivification techniques with these bodies.
+As a Medical Doctor, treating plasmamen is not impossible! Salbutamol and epinephrine stops them from suffocating due to lack of internals and showers stop them from burning alive. You can even perform surgery on them by doing the procedure on a roller bed under a shower.
As a Medical Doctor, you can point your penlight at people to create a medical hologram. This lets them know that you're coming to treat them.
As a Medical Doctor, you can extract implants by holding an empty implant case in your offhand while performing the extraction step.
As a Medical Doctor, clone scanning people will implant them with a health tracker that displays their vitals in the clone records. Useful to check on crew members that didn't activate suit sensors!
-As a Medical Doctor, medical gauze stops bleeding as well as healing 5 brute damage, this even works on the dead! Make sure to always have some gauze on you to stop bleeding before dragging someone.
-As a Chemist, there are dozens of chemicals that can heal, and even more that can cause harm. Experiment!
+As a Medical Doctor, you can deal with patients who have absurd amounts of wounds by putting them in cryo. This will slowly treat all of their wounds simultaneously, but is much slower than direct treatment.
+As a Medical Doctor, Critical Slash wounds are one of the most dangerous conditions someone can have. Apply gauze, epipens, sutures, cauteries, whatever you can, as soon as possible!
+As a Medical Doctor, Saline-Glucose not only acts as a temporary boost to a patient's blood level, it also speeds regeneration! Perfect for drained patients!
+As a Medical Doctor, medical gauze is an incredibly underrated tool. It can be used to entirely halt a limb from bleeding or sling one that's been shattered until it can be given proper attention. This even works on the dead, too! Be sure to stop someone's bleeding whether they're in critical condition or a corpse, as dragging someone whom is bleeding will rapidly deplete them of all their blood.
+As a Chemist, there are dozens of chemicals that can heal, and even more that can cause harm. See which chemicals have the best synergy, both in healing, and in harming. Experiment!
As a Chemist, some chemicals can only be synthesized by heating up the contents in the chemical heater.
As a Chemist, you will be expected to supply crew with certain chemicals. For example, clonexadone and mannitol for the cryo tubes, unstable mutagen and saltpetre for botany as well as healing pills and patches for the front desk.
As a Chemist, you can make 100u bottles from plastic sheets. The ChemMaster can produce infinite 30u glass bottles as well.
+As a Chemist, be sure to stock up some hypovials with useful chemicals for any doctors looking to heal on the go, you can also print out the deluxe hypovials at an autolathe specifically for the CMO's special hypospray.
+As a Chemist, the reagent dartgun, while neutered in its ability to harm - can still be loaded up with morphine for a ghetto sedation weapon, and a quick shot of charcoal can make a slime hybrid regret their life choices in an instant.
As a Geneticist, you can eject someone from cloning early by clicking on the cloner pod with your ID. Note that they will suffer more genetic damage and may lose vital organs from this.
-As a Geneticist, becoming a hulk makes you capable of dealing high melee damage, stunlocking people, and punching through walls. However, you can't fire guns, will lose your hulk status if you take too much damage, and are not considered a human by the AI while you are a hulk.
+As a Geneticist, becoming a hulk makes you capable of dealing high melee damage, becoming immune to most traditional stuns, and punching through walls. However, you can't fire guns, and will lose your hulk status if you take too much damage.
As the Virologist, your viruses can range from healing powers so great that you can heal out of critical status, or diseases so dangerous they can kill the entire crew with airborne spontaneous combustion. Experiment!
As the Virologist, you only require small amounts of vaccine to heal a sick patient. Work with the Chemist to distribute your cures more efficiently.
As the Research Director, you can take AIs out of their cores by loading them into an intelliCard, and then from there into an AI system integrity restorer computer to revive and/or repair them.
As the Research Director, you can lock down cyborgs instead of blowing them up. Then you can have their laws reset or if that doesn't work, safely dismantled.
As the Research Director, you can upgrade your modular console with better computer parts to speed up its functions. This can be useful when using the AI system integrity restorer.
As the Research Director, your console's NTnet monitoring tool can be used to retrieve airlock passkeys, provided that someone used a door remote.
-As a Scientist, you can use the mutation toxin obtained from green slimes to turn yourself into a jelly mutant. Each subspecies has unique features - for example telepathic powers, duplicating bodies or integrating slime extracts!
+As a Scientist, you can use the mutation toxin obtained from green slimes to turn yourself into a jelly mutant. Each subspecies has unique features - for example telepathic powers, duplicating bodies or integrating slime extracts for several unique effects!
As a Scientist, you can maximize the number of uses you get out of a slime by feeding it slime steroid, created from purple slimes, while alive. You can then apply extract enhancer, created from cerulean slimes, on each extract.
-As a Scientist, you can disable anomalies by scanning them with an analyzer, then send a signal on the frequency it gives you with a remote signalling device. This will leave behind an anomaly core, which can be used to construct a Phazon mech, or be used in the destructive analyzer for a 10,000 point bonus!
+As a Scientist, you can disable anomalies by scanning them with an analyzer, and then sending a signal on the frequency it gives you with a remote signalling device. Alternatively, you can print out anomaly defusal tools which can instantly disable an anomaly at the protolathe with some research, both of these methods will leave behind an anomaly core, which can be used to construct a Phazon mech, or be used in the destructive analyzer for a 10,000 point bonus!
As a Scientist, researchable stock parts can seriously improve the efficiency and speed of machines around the station. In some cases, it can even unlock new functions.
As a Scientist, you can generate research points by letting the tachyon-doppler array record increasingly large explosions.
As a Scientist, getting drunk just enough will speed up research. Skol!
As a Scientist, you can get points by placing slime cores into the destructive analyzer! This even works with crossbred slime cores.
-As a Scientist, work with botanists to get different types of seeds, as each type of seed can be used in the destructive analyzer for a small amount of Rnd type points!
+As a Scientist, you can get a minuscule amount of points by sacrificing a packet of seeds from Hydroponics into the destructive analyzer! While each individual one may not yield many points per, you can quite easily amass a very large variety of seeds, which could add up over time for a couple extra minutes shaved off of maxing out RND.
As a Roboticist, keep an ear out for anomaly announcements. If you get your hands on an anomaly core, you can build a Phazon mech!
As a Roboticist, you can repair your cyborgs with a welding tool. If they have taken burn damage from lasers, you can remove their battery, expose the wiring with a screwdriver and replace their wires with a cable coil.
As a Roboticist, you can reset a cyborg's module by cutting and mending the reset wire with a wire cutter.
+As a Roboticist, pay mind when toying with a cyborg's wires. It's best to pulse wires before immediately cutting them, as cutting them right away without knowing what they do may sever them from the AI, or disable their camera.
As a Roboticist, you can greatly help out Shaft Miners by building a Firefighter APLU equipped with a hydraulic clamp and plasma cutter. The mech is ash storm proof and can even walk across lava!
-As a Roboticist, you can augment people with cyborg limbs. Augmented limbs can easily be repaired with cables and welders.
+As a Roboticist, you can augment people with cyborg limbs. Augmented limbs are immune to the vacuum of space and temperatures while they can very easily be repaired with welders (brute) and cable coils (burn).
As a Roboticist, you can use your printer that is linked to the ore silo to teleport mats into your work place!
As a Roboticist, you can upgrade cleanbots with adv mops and brooms to make them faster and better!
-As a Roboticist, you can upgrade medical bots with diamond-tipped syringes, MK.II Hypospray, dispenser-sleeper-chemheater boards to make them inject faster, harder and better chems!
-As the AI, you can click on people's names to look at them. This only works if there are cameras that can see them.
+As a Roboticist, you can upgrade medical bots with diamond-tipped syringes, hyposprays, and chemistry machine boards to make their injections pierce hardsuits, work faster, and inject higher quality medicines!
+As the AI, you can click on people's names when they speak over the radio to jump your eye to them. This only works if there are cameras that can see them and are not wearing anything which would obsfuscate their face or tracking capabilities.
As the AI, you can quickly open and close doors by holding shift while clicking them, bolt them when holding ctrl, and even shock them while holding alt.
-As the AI, you can take pictures with your camera and upload them to newscasters.
-As a Cyborg, choose your module carefully, as only cutting and mending your reset wire will let you repick it. If possible, refrain from choosing a module until a situation that requires one occurs.
-As a Cyborg, you are immune to most forms of stunning, and excel at almost everything far better than humans. However, flashes can easily stunlock you and you cannot do any precision work as you lack hands.
+As the AI, you can take pictures with your camera and upload them to newscasters. Cyborgs also share from this pool of pictures.
+As a Cyborg, choose your module carefully, as only having your reset wire cut and mended by someone capable of manipulation will let you repick it. If possible, refrain from choosing a module until a situation that requires one occurs.
+As a Cyborg, you are immune to most forms of stunning, and excel at almost everything far better than humans. However, flashes and EMPs can easily stunlock you and you fall short in performing any tasks which require hands.
As a Cyborg, you are impervious to fires and heat. If you are rogue, you can release plasma fires everywhere and walk through them without a care in the world!
As a Cyborg, you are extremely vulnerable to EMPs as EMPs both stun you and damage you. The ion rifle in the armory or a traitor with an EMP kit can kill you in seconds.
As a Service Cyborg, your spray can knocks people down. However, it is blocked by gas masks.
-As an Engineering Cyborg, you can attach air alarm/fire alarm/APC frames to walls by placing them on the floor and using a screwdriver on them.
-As a Medical Cyborg, you can fully perform surgery and even augment people. Best of all, they have a 0% failure chance.
-As a Janitor Cyborg, you are the bane of all slaughter demons and even Bubblegum himself. Cleaning up blood stains will severely gimp them.
-As a Janitor Cyborg, you get a fancy bottle of drying agent! If you want to be nice, spray the janitor boots with them to magically upgrade them to absorbent galoshes.
+As an Engineering Cyborg, you can attach air alarm/fire alarm/APC frames to walls by placing them on the floor and using a screwdriver on them. Alternatively, you can use your in-built pseudo-hand manipulator to show those organics who's boss! It can even perform complex tasks such as removing cells from APCs, or inserting plasma canisters into radiation collectors.
+As a Medical Cyborg, you can fully perform surgery and even augment people. Best of all, they have a 0% failure chance, even if done on the floor.
+As a Janitor Cyborg, you are the bane of all slaughter demons and can even foil Bubblegum himself. Cleaning up blood stains will severely gimp them, although the latter may just turn you into robotic paste.
+As a Janitor Cyborg, you get a fancy bottle of drying agent! If you want to be nice, spray the janitor's galoshes with them to magically upgrade them to absorbent galoshes which automatically dry tiles.
As the Chief Engineer, you can rename areas or create entirely new ones using your station blueprints.
As the Chief Engineer, your hardsuit is significantly better than everybody else's. It has the best features of both engineering and atmospherics hardsuits - boasting nigh-invulnerability to radiation and all atmospheric conditions.
As the Chief Engineer, you can spy on and even forge PDA communications with the message monitor console! The key is in your office.
@@ -94,14 +102,14 @@ As an Engineer, you can convert tesla coils into corona analyzers by using a scr
As an Engineer, you can use radiation collectors to generate research points. Load them with a 50/50 oxygen/tritium tank and use a multitool to switch them to research mode.
As an Engineer, don't underestimate the humble P.A.C.M.A.N. generators. With upgraded parts, a couple units working in tandem are sufficient to take over for an exploded engine or shattered solars.
As an Engineer, your departmental protolathe and circuit printer can manufacture the necessary circuit boards and components to build just about anything. Make extra medical machinery everywhere! Build a gibber for security! Set up an array of emitters pointing down the hall! The possibilities are endless!
-As an Engineer, you can pry open secure storage by disabling the engine room APC's main breaker. This is obviously a bad idea if the engine is running.
-Don't forget that Cargo has access to a meteor defense satellite that can be ordered BEFORE meteors hit the station. Any idle Engineers should have this on their to-do list.
-As an Engineer, your RCD can be reloaded with mineral sheets instead of just compressed matter cartridges.
+As an Engineer, you can pry open secure storage by disabling the engine room APC's environmental breaker. This is obviously a bad idea if the engine is running.
+As an Engineer, don't forget that Cargo has access to a meteor defense satellite that can be ordered BEFORE meteors hit the station. Any idle Engineers should have this on their to-do list.
+As an Engineer, your RCD can be reloaded with mineral sheets instead of just compressed matter cartridges. Materials which are combined alloys of other materials (such as reinforced glass and plasteel) provide more matter per sheet to the RCD.
As an Atmospheric Technician, you can unwrench a pipe regardless of the pressures of the gases inside, but if they're too high they can burst out and injure you!
As an Atmospheric Technician, look into replacing your gas pumps with volumetric gas pumps, as those move air in flat numerical amounts, rather than percentages which leave trace gases.
-As an Atmospheric Technician, you are better suited to fighting fires than anyone else. As such, you have access to better firesuits, backpack firefighter tanks, and a completely heat and fire proof rigsuit.
+As an Atmospheric Technician, you are better suited to fighting fires than anyone else. As such, you have access to better firesuits, backpack firefighter tanks, and a completely heat and fire proof hardsuit.
As an Atmospheric Technician, your backpack firefighter tank can launch resin. This resin will extinguish fires and replace any gases with a safe, room-temperature airmix.
-As an Atmospheric Technician, your ATMOS holofan projector blocks gases while allowing objects to pass through. With it, you can quickly contain gas spills, fires and hull breaches. Or, use it to seal a plasmaman cloning room.
+As an Atmospheric Technician, your ATMOS holofan projectors can blocks gases and heat while allowing objects to pass through. With it, you can quickly contain gas spills, fires and hull breaches. Or, use it to create a plasmaman friendly lounge.
As an Atmospheric Technician, burning a plasma/oxygen mix inside the incinerator will not only produce power, but also gases such as tritium and water vapor.
As an Atmospheric Technician, you can change the layer of a pipe by clicking with it on a wrenched pipe or other atmos component of the desired layer.
As an Atmospheric Technician, you can take a few cans worth of N2/N2O and cool it down at local freezers. This is a good idea when dealing with (or preparing for) a supermatter meltdown.
@@ -111,65 +119,70 @@ As the Head of Security, don't let the power go to your head. You may have high
As the Warden, your duty is to be the watchdog of the brig and handler of prisoners when little is happening, and to hand out equipment and weapons to the security officers when a crisis strikes.
As the Warden, keep a close eye on the armory at all times, as it is a favored strike point of nuclear operatives and cocky traitors.
As the Warden, if a prisoner's crimes are heinous enough you can put them in permabrig or the gulag. Make sure to check on them once in a while!
-As the Warden, never underestimate the power of tech slugs! Scattershot fires a cone of weaker lasers, Ion slugs fires EMPs that only effect the tiles they hit, and Pulse slugs fire a singular laser that can one-hit almost any wall!
-As the Warden, you can use a surgical saw on riot shotguns to shorten the barrel, making them able to fit in your backpack.
+As the Warden, never underestimate the power of tech slugs! Scattershot fires a cone of weaker lasers with little damage fall off, Ion slugs fires EMPs that only effect the tiles they hit, and Pulse slugs fire a singular laser that can one-hit almost any wall!
+As the Warden, you can use a surgical saw on riot shotguns to shorten the barrel, making them able to fit in your backpack. Make sure to empty them prior lest you blast yourself in the face!
As the Warden, you can implant criminals you suspect might re-offend with devices that will track their location and allow you to remotely inject them with disabling chemicals.
As the Warden, you can use handcuffs on orange prisoner shoes to turn them into cuffed shoes, forcing prisoners to walk and potentially thwarting an escape.
-As the Warden, tracker implants can be used on sec officers. Doing this will let you track their corpse even without suits, though the implant will biodegrade after 5 minutes.
-As the Warden, cryostasis shotgun darts hold 10u of chemicals that will not react untill it hits someone.
-As the Warden, chemical implants can be loaded with a cocktail of healing or combat chems, perfect for the Hos or other sec officers to use. Be sure to keep a eye on them though, it will not auto inject! EMPs or starvation mite lead to the chemical implant to go off as well.
-As the Warden, tracker implants can be used on sec officers. Doing this will let you be able to message them when telecoms are out, or when you suspect coms are compromised. This is also good against rogue AIs as the prisoner tracker doesn't leave logs or alarms for the AI.
+As the Warden, tracker implants can be used on crewmembers. Doing this will let you track their person even without suit sensors and even instantly teleport to them at the local teleporter, although the implant will biodegrade after 5 minutes if its holder ever expires.
+As the Warden, cryostasis shotgun darts hold 10u of chemicals that will not react until it hits someone.
+As the Warden, chemical implants can be loaded with a cocktail of healing or combat chems, perfect for the HoS or other security officers to make use of in a pinch. Be sure to keep a eye on them though, as they cannot be injected without the prisoner management console! EMPs or starvation might lead to the chemical implant going off preemptively.
+As the Warden, tracker implants can be used on your security officers. Doing this will let you be able to message them when telecomms are out, or when you suspect comms are compromised. This is also good against rogue AIs as the prisoner tracker doesn't leave logs or alarms for the AI.
As a Security Officer, remember that correlation does not equal causation. Someone may have just been at the wrong place at the wrong time!
-As a Security Officer, remember that your belt can hold more then one stun baton.
-As a Security Officer, remember harm battoning someone in the head can deconvert them form a being a rev! This sadly doesn't work against the cult, nor does this protect them from getting reconverted.
-As a Security Officer, remember that you can attach a sec-lite to your taser or your helmet!
+As a Security Officer, remember that your belt can hold more than one stun baton.
+As a Security Officer, remember harm beating someone in the head with a blunt object can deconvert them form a being a revolutionary! This sadly doesn't work against either cult, nor does this protect them from getting reconverted unlike a mindshield implant.
+As a Security Officer, remember that you can attach a seclite to your taser or your helmet!
As a Security Officer, communicate and coordinate with your fellow officers using the security channel (:s) to avoid confusion.
-As a Security Officer, your sechuds or HUDsunglasses can not only see crewmates' job assignments and criminal status, but also if they are mindshield implanted. Use this to your advantage in a revolution to definitively tell who is on your side!
+As a Security Officer, your security HUDglasses can not only see crewmates' job assignments and criminal status, but also if they are mindshield implanted. Use this to your advantage in a revolution to definitively tell who is on your side!
As a Security Officer, mindshield implants can only prevent someone from being turned into a cultist: unlike revolutionaries, it will not de-cult them if they have already been converted.
-As a Security Officer, examining someone while wearing sechuds or HUDsunglasses will let you set their arrest level, which will cause Beepsky and other security bots to chase after them.
-As a Security Officer, you can take out the power cell on your baton to replace it with a better or fully charged one. Just use a screwdriver on your baton to remove the old cell
-As a Security Officer, you can place riot shotguns on your armor, this even works with winter sec coats!
+As a Security Officer, examining someone while wearing your security HUDglasses can allow you to swiftly edit their records and criminal status. Be sure to set someone to WANTED if you can't catch up to them, as it'll alert other officers of who's the bad guy, and cause the little security droids to chase after them for you.
+As a Security Officer, you can take out the power cell on your baton to replace it with a better or fully charged one. Just use a screwdriver on your baton to remove the old cell.
+As a Security Officer, you can just about any firearm on your vest, this even works with other non-standard armor-substitutes like security winter coats!
As the Detective, people leave fingerprints everywhere and on everything. With the exception of white latex, gloves will hide them. All is not lost, however, as gloves leave fibers specific to their kind such as black or nitrile, pointing to a general department.
-As the Detective, you can use your forensics scanner from a distance.
-As the Detective, your revolver can be loaded with .357 ammunition obtained from a hacked autolathe. Firing it has a decent chance to blow up your revolver.
+As the Detective, you can use your forensics scanner from a distance. Use this to scan boxes or other storage containers.
+As the Detective, your revolver can be loaded with .357 ammunition. Use a screwdriver to permanently modify your revolver into using this type of ammunition, be warned however, firing it has a decent chance to cause the revolver to misfire and shoot you in the foot.
As the Lawyer, try to negotiate with the Warden if sentences seem too high for the crime.
-As the Lawyer, you can try to convince the captain and Head of Security to hold trials for prisoners in the courtroom.
+As the Lawyer, you can try to convince the Captain and Head of Security to hold trials for prisoners in the courtroom.
As the Head of Personnel, you are not higher ranking than other heads of staff, even though you are expected to take the Captain's place first should he go missing. If the situation seems too rough for you, consider allowing another head to become temporary Captain.
-As the Head of Personnel, you are just as large a target as the Captain because of the potential power your ID and computer can hand out.
+As the Head of Personnel, you are just as large a target as the Captain because of the potential power your ID and computer can hand out and your comparative vulnerability.
As the Mime, your invisible wall power blocks people as well as projectiles. You can use it in a pinch to delay your pursuer.
-As the Mime, you can use :r and :l to speak through your ventriloquist dummy.
+As the Mime, you can use :r and :l to speak through your ventriloquist dummy. Sadly, this only works if your vow is broken, but at least you don't have to sacrifice your dignity by actually talking.
As the Mime, your oath of silence is your source of power. Breaking it robs you of your powers and of your honor.
+As the Mime, breaking your vow of silence is seen as incredibly dishonorable. Most people will seek to trouble and generally ignore a talking Mime.
As the Clown, if you lose your banana peel, you can still slip people with your PDA! Honk!
As the Clown, eating bananas heals you slightly. Honk!
As the Clown, your Holy Grail is the mineral bananium, which can be given to the Roboticist to build you a fun and robust mech beloved by everyone.
-As the Clown, you can use your stamp on a sheet of cardboard as the first step of making a honkbot. Fun for the whole crew!
-As the Chaplain, your null rod has a lot of functions: it can convert water into holy water, which if spread on the ground prevents wizards from jaunting away, can destroy cultist runes by hitting them, and is a very powerful weapon to boot!
-The Chaplain can bless any container with water by hitting it with their bible. Holy water has a myriad of uses against both cults and large amounts of it are a great contributor to success against them.
-The Chaplain's holy weapon will kill clockwork marauders in two hits.
-As the Chaplain, your bible is also a container that can store small items. Depending on your god, your starting bible may come with a surprise!
-As the Chaplain, you are much more likely to get a response by praying to the gods than most people. To boost your chances, make altars with colorful crayon runes, lit candles, and wire art.
+As the Clown, you can use your stamp on a sheet of flattened cardboard as the first step of making a honkbot. Fun for the whole crew!
+As the Clown, your number one way to win over the crew's favor is by telling jokes and putting forth effort into being comedic. Everyone loves a good clown, but everyone despises a bad one.
+As the Chaplain, your null rod has a lot of functions: while being an incredibly powerful weapon with an array of potential utilities depending upon the skin you chose for it, it also nulls cultist and wizard magic entirely, making you immune to them both and in some cases even harming the caster so long as you keep it in a pocket or in your hands.
+As the Chaplain, you can bless any water container by hitting it with your bible to turn it into holy water. Holy water has a myriad of uses against both cults and large amounts of it are a great contributor to success against them.
+As the Chaplain, your null rod will kill clockwork marauders in two hits while actively hindering their overall combat capabilities just by being nearby to them.
+As the Chaplain, your bible is also a container that can store a singular small item. Depending on your God, your starting bible may come with a surprise!
+As the Chaplain, you are much more likely to get a response by praying to the Gods than most people as your prayers will send a special noise cue directly to them! To further your chances of getting a response even further, pretty up your altar with crayon runes and wire art, and be sure to put a decent amount of effort into your prayers themselves. The Gods don't like lazy bums.
As a Botanist, you can hack the MegaSeed Vendor to get access to more exotic seeds. These seeds can alternatively be ordered from cargo.
As a Botanist, you can mutate the plants growing in your hydroponics trays with unstable mutagen or, as an alternative, crude radioactives from chemistry to get special variations.
-As a Botanist, you should look into increasing the potency of your plants. This increases the size, amount of chemicals, points gained from grinding them in the biogenerator, and lets people know you are a proficient botanist.
-As a Botanist, you can combine production trait chemicals just like a Chemist. Chlorine (blumpkin) + radium and phosphorus (glowshrooms) equals unstable mutagen!
+As a Botanist, you should look into increasing the potency of your plants. This is shown by the size of the plant's sprite, and can increase the amount of chemicals, points gained from grinding them in the biogenerator, and lets people know you are a proficient botanist.
+As a Botanist, you can combine production trait chemicals and mix your own complex chemicals inside of the plants themselves using precursors. Chlorine (blumpkin) + radium and phosphorus (glowshrooms) equals unstable mutagen!
+As a Botanist, earthsblood is an incredibly powerful chemical found in Ambrosia Gaia, it heals all types of damages very rapidly but causes lingering brain damage and has a nasty overdose. You can combine the chemicals from watermelons (water), grass (hydrogen), and cherries (sugar) to mix mannitol in with your earthsblood to completely counteract its main drawback!
+As a Botanist, Ambrosia Gaia is a plant mutated from Ambrosia Deus, which is a plant mutated from Ambrosia Vulgaris. The reagent contained within this plant known as earthsblood can make your trays and soil plots completely self sufficient when a plant containing such reagent is composted into them, meaning they won't need nutrients or water, and they'll automatically kill their own weeds and pests.
As a Cook, you can load your food into snack vending machines.
As a Cook, you can rename your custom made food with a pen.
As a Cook, any food you make will be much healthier than the junk food found in vendors. Having the crew routinely eating from you will provide minor buffs.
-As a Cook, being in the kitchen will make you remember the basics of Close Quarters Cooking. It is highly effective at removing Assistants from your workplace.
+As a Cook, being in the kitchen will make you remember the basics of Close Quarters Cooking (CQC). It is highly effective at removing Assistants from your workplace.
As a Cook, your Kitchenmate can vend out trays that fit on your belt slot. These trays pick up 7 food items at a time and are a quick way to transport large meals.
As a Cook, the advanced roasting stick is used to cook food at a distance, and can be used on SME, singularity, and other objects that cook food normally.
+As a Cook, the deep frier is a tool which can turn very large quantities of seemingly useless objects into food, albeit nutritionally poor and awful tasting food, but hey, food is food.
As the Bartender, the drinks you start with only give you the basics. If you want more advanced mixtures, look into working with chemistry, hydroponics, or even mining for things to grind up and throw in!
-As the Bartender, you can use a circular saw on your shotgun to make it easier to store.
-As a Janitor, if someone steals your janicart, you can instead use your space cleaner spray, grenades, water sprayer, exact bloody revenge or order another from Cargo.
+As the Bartender, you can use a circular saw on your shotgun to make it easier to store. Make sure to empty them prior lest you blast yourself in the face!
+As a Janitor, if someone steals your janicart, you can instead use your spray bottles, soap, and arsenal of slippery objects to exact your bloody revenge.. ..or just order another one from Cargo.
As a Janitor, the trash bag can be used to hold more than trash. Tools, medical equipment, smuggled nuclear disks... You name it!
-As a Janitor, mousetraps can be used to create bombs or booby-trap containers.
-Beware the Curator, for they are not completely defenseless. The curator's whip always disarms people, their laser pointer can blind humans and cyborgs, and can hide items in wirecut books.
+As a Janitor, mousetraps can be used as bomb triggers to booby-trap containers.
+As the Curator, for what it's worth, your toys and position are fairly robust. You can order a claymore, a whip, or a free space suit all at roundstart. The claymore is fairly underwhelming, however the whip is an incredibly robust weapon capable of always disarming, and that space suit is also better than the ones in EVA.
As the Curator, be sure to keep the shelves stocked and the library clean for crew.
As a Cargo Technician, you can hack MULEbots to make them faster, run over people in their way, and even let you ride them!
As a Cargo Technician, you can order contraband items from the supply shuttle console by de-constructing it and using a multitool on the circuit board, the re-assembling it.
As a Cargo Technician, you can earn more cargo points by shipping back crates from maintenance, liquid containers, plasma sheets, rare seeds from hydroponics, and more!
As a Cargo Technician, you get 400 points per packet! Stamp the manifest and sending back the crate will give you 200 points for the paperwork and 200 points for the crate!
-As a Cargo Technician, paperwork is an alternative option to shipping off plasma sheets and other goods. Order Paperwork crates and go into the crafting menu to turn pens and undone paper work into completed grant paper work to get 50 points per sheet!
+As a Cargo Technician, paperwork and glass blowing are alternative options to shipping off plasma sheets and other goods. Order their respective kits and get to work! Paperwork can be done quickly via the crafting menu for a quick buck, while glass blowing is much more lucrative, but may require some more effort and time.
As the Quartermaster, be sure to check the manifests on crates you receive to make sure all the info is correct. If there's a mistake, stamp the manifest DENIED and send it back in a crate with the items untouched for a refund!
As the Quartermaster, you can construct an express supply console that instantly delivers crates by drop pod. The impact will cause a small explosion as well.
As a Shaft Miner, the northern side of Lavaland has a lot more rare minerals than on the south.
@@ -177,25 +190,25 @@ As a Shaft Miner, every monster on Lavaland has a pattern you can exploit to min
As a Shaft Miner, you can harvest goliath plates from goliaths and upgrade your explorer's suit, mining hardsuits as well as Firefighter APLUs with them, greatly reducing incoming melee damage.
As a Shaft Miner, always have a GPS on you, so a fellow miner or cyborg can come to save you if you die.
As a Shaft Miner, you can craft a variety of equipment from the local fauna. Bone axes, lava boats and ash drake armour are just a few of them!
-As a Traitor, the cryptographic sequencer (emag) can not only open doors, but also lockers, crates, APCs and more. It can hack cyborgs, and even cause bots to go berserk. Use it on the right machines, and you can even order more traitor gear or contact the Syndicate. Experiment!
+As a Traitor, the cryptographic sequencer (emag) can not only open lockers, crates, APCs and more. It can also do things like hack cyborgs, and even cause bots to go berserk. Use it on the right machines, and you can even contact the Syndicate. Experiment!
As a Traitor, subverting the AI to serve you can make it an extremely powerful ally. However, be careful of the wording in the laws you give it, as it may use your poorly written laws against you!
As a Traitor, the Captain and the Head of Security are two of the most difficult to kill targets on the station. If either one is your target, plan carefully.
-As a Traitor, you can manufacture and recycle revolver bullets at a hacked autolathe, making the revolver an extremely powerful tool.
+As a Traitor, you can manufacture and recycle revolver bullets at a hacked autolathe, making the revolver an extremely powerful tool if you manage to nab an autolathe for yourself.
As a Traitor, you may sometimes be assigned to hunt other traitors, and in turn be hunted by others.
As a Traitor, the syndicate encryption key is very useful for coordinating plans with your fellow traitors -- or, of course, betraying them.
As a Traitor, plasma can be injected into many things to sabotage them. Power cells, light bulbs, cigars and e-cigs will all explode when used.
As a Nuclear Operative, communication is key! Use :t or :h to speak to your fellow operatives and coordinate an attack plan.
-As a Nuclear Operative, you should look into purchasing a syndicate cyborg, as they can provide heavy fire support, full access, are immune to conventional stuns, and can easily take down the AI.
+As a Nuclear Operative, you should look into purchasing one of the three Syndicate cyborgs in your uplink, as they can provide useful tactical support, function as walking access machines, are immune to conventional stuns, and can easily take down the AI.
As a Nuclear Operative, stick together! While your equipment is robust, your fellow operatives are much better at saving your life: they can drag you away from danger while stunned and provide cover fire.
As a Nuclear Operative, you might end up in a situation where the AI has bolted you into a room. Having some spare C4 in your pocket can save your life.
As a Monkey, you can crawl through air or scrubber vents by alt+left clicking them. You must drop everything you are wearing and holding to do this, however.
As a Monkey, you can still wear a few human items, such as backpacks, gas masks and hats, and still have two free hands.
As the Malfunctioning AI, you can shunt to an APC if the situation gets bad. This disables your doomsday device if it is active.
-As the Malfunctioning AI, you should either order your cyborgs to dismantle the robotics console or blow it up yourself in order to protect them.
+As the Malfunctioning AI, you should either order your cyborgs to dismantle the robotics console or blow it up yourself in order to protect them. Do note that this will prevent you from hacking any cyborg made in the future.
As the Malfunctioning AI, look into flooding the station with plasma fires to kill off large portions of the crew, letting you pick off the remaining few with space suits who escaped.
-Xenomorphs? Science can craft deadly tech shells like pulse slugs and laser scatter shot that are highly effective against any alien threat.
-When fighting aliens, it can be a good idea to turn off the gravity due to the alien's lack of zero-gravity control.
-When fighting xenomorph aliens, consider a shield. Shields can block their pounces and be worn on the back, but beware of neurotoxin.
+Xenomorphs? Any source of burn damage severely harms them. Science can craft deadly tech shells like pulse slugs and laser scatter shot that are highly effective against any alien threat.
+When fighting Aliens, it can be a good idea to turn off the gravity due to the every caste of alien's lack of zero-gravity control, especially Hunters and Drones, which are completely and utterly helpless.
+When fighting Aliens, consider a shield. A raised shield can halt their attempts to slash at you, and their disarms will always remove an item in your hand before knocking you over, always having something in your hand, no matter how small or worthless, can save your life.
As an Alien, your melee prowess is unmatched, but your ranged abilities are sorely lacking. Make use of corners to force a melee confrontation!
As an Alien, you take double damage from all burn attacks, such as lasers, welding tools, and fires. Furthermore, fire can destroy your resin and eggs. Expose areas to space to starve away any flamethrower fires before they can do damage!
As an Alien, resin floors not only regenerate your plasma supply, but also passively heal you. Fight on resin floors to gain a home turf advantage!
@@ -212,6 +225,7 @@ As the Blob, you can produce a Blobbernaut from a factory for 40 resources. Blob
As the Blob, you can expand by clicking, create strong blobs with ctrl-click, rally spores with middle-click, and remove blobs with alt-click. You do not need to have your camera over the tile to do this.
As the Blob, removing strong blobs, resource nodes, factories, and nodes will give you 4, 15, 25, and 25 resources back, respectively.
As the Blob, talking will send a message to all other overminds and all Blobbernauts, allowing you to direct attacks and coordinate.
+As the Blob, always make sure where you land is where you want to be, as it is very unlikely you will be getting too far away from it. Land in key points like the armory or the medical bay to immediately cripple the crew before they even find out you exist. Of course, always take into mind if being immediately discovered may outweight the benefits, and stick to maintenance close to these key points of interest to you.
As a Blobbernaut, you can communicate with overminds and other Blobbernauts via :b.
As a Blobbernaut, your HUD shows your health and the core health of the overmind that created you.
As a Revolutionary, you cannot convert a head of staff or someone who has a mindshield implant, such as a security officer or those they implant. Implants can however be surgically removed, and do not carry over with cloning. Take control of medbay to keep control of conversions!
@@ -220,6 +234,11 @@ As a Revolutionary, cargo can be your best friend or your worst nightmare. In th
As a Revolutionary, your main power comes from how quickly you spread. Convert people as fast as you can and overwhelm the heads of staff before security can arm up.
As a Changeling, the Extract DNA sting counts for your genome absorb objective, but does not let you respec your powers.
As a Changeling, you can absorb someone by strangling them and using the Absorb verb; this gives you the ability to rechoose your powers, the DNA of whoever you absorbed, the memory of the absorbed, and some samples of things the absorbed said.
+As a Changeling, absorbing someone will give you their full memory. This can include things such as a Traitor's uplink, thus absorbing one will allow you to access the Traitor uplink and buy toys for your Changeling self to abuse.
+As a Changeling, absorbing another Changeling will permanently boost your chemical reserve, allow you to pick more abilities, and make the victim unable to revive. Be careful when exposing your identity to other Changelings, as they may be out of those wonderful benefits.
+As a Changeling, BZ gas will dramatically slow down or even halt your natural chemical regeneration, be sure to avoid it at all costs as some lunatics may try and flood portions of the station to deal with you.
+As a Changeling, death is not the end for you! You can revive after two minutes from being dead by triggering your stasis ability, and then waiting for the prompt to resurrect yourself to show up.
+As a Changeling, your Regenerate Limbs power will quickly heal all of your wounds, but they'll still leave scars. Changelings can use Fleshmend to get rid of scars, or you can ingest Carpotoxin to get rid of them like a normal person.
As a Cultist, do not cause too much chaos before your objective is completed. If the shuttle gets called too soon, you may not have enough time to win.
As a Cultist, your team starts off very weak, but if necessary can quickly convert everything they have into raw power. Make sure you have the numbers and equipment to support going loud, or the cult will fall flat on its face.
As a Cultist, the Blood Boil rune will deal massive amounts of brute damage to non-cultists, stamina damage to Ratvarian scum, and some damage to fellow cultists of Nar-Sie nearby, but will create a fire where the rune stands on use.
@@ -239,9 +258,10 @@ You can deconvert Cultists of Nar-Sie and Servants of Ratvar by feeding them lar
Tiles sprayed with holy water will permanently block Servants of Ratvar from teleporting onto them.
As a Wizard, you can turn people to stone, then animate the resulting statue with a staff of animation to create an extremely powerful minion, for all of 5 minutes at least.
As a Wizard, the fireball spell performs very poorly at close range, as it can easily catch you in the blast. It is best used as a form of artillery down long hallways.
-As a Wizard, summoning guns will turn a large portion of the crew against themselves, but will also give everyone anything from a pea shooter to a BFG 9000. Use at your own risk!
+As a Wizard, summoning guns will turn a large portion of the crew against themselves, but will also give everyone anything from a energy pistol to a pulse rifle. Use at your own risk!
As a Wizard, the staff of chaos can fire any type of bolts from the magical wands. This can range from bolts of instant death to healing or reviving someone.
As a Wizard, most spells become unusable if you are not wearing your robe, hat, and sandals.
+As a Wizard, it's advisable that you don't dump all of your limited spell points into solely offensive spells, if you can't defend yourself then you're sure to get dunked.
As an Abductor, you can select where your victims will be sent on the ship control console.
As an Abductor Agent, the combat mode vest has much higher resistance to every kind of weapon, and your helmet prevents the AI from tracking you.
As an Abductor, the baton can cycle between four modes: stun, sleep, cuff and probe.
@@ -260,17 +280,24 @@ As a Drone, you can ping other drones to alert them of areas in the station in n
As a Drone, you can repair yourself by using a screwdriver on yourself and standing still!
As a Ghost, you can see the inside of a container on the ground by clicking on it.
As a Ghost, you can double click on just about anything to follow it. Or just warp around!
+As a Ghost, there's a button in the OOC tab labeled Observe, it lets you see through someone's eyes as if you were the one who's playing them.
As a Devil, you gain power for every three souls you control, however you also become more obvious.
As a Devil, as long as you control at least one other soul, you will automatically resurrect, as long as a banishment ritual is not performed.
At which time a Devil's nameth is spake on the tongue of man, the Devil may appeareth.
You can swap floor tiles by holding a crowbar in one hand and a stack of tiles in the other.
-When hacking doors, cutting and mending the "test light wire" will restore power to the door.
-When hacking, remote singulars pulse when attached to a wire and pinged. This can allow you to hack things or set traps from far away.
+When hacking doors, cutting and mending a "test light wire" will restore power to the door.
When crafting most items, you can either manually combine parts or use the crafting menu.
Suit storage units not only remove blood and dirt from clothing, but also radiation!
Remote devices will work when used through cameras. For example: Bluespace RPEDs and door remotes.
+You can light a cigar on a supermatter crystal.
+Using sticky tape on items can make them stick to people and walls! Be careful, grenades might stick to your hand during the moment of truth!
+In a pinch, stripping yourself naked will give you a sizeable resistance to being tackled. What do you value more, your freedom or your dignity?
+Wearing riot armor makes you significantly more effective at performing tackle takedowns, but will use extra stamina with each leap! It will also significantly protect you from other tackles!
+Epipens contain a powerful coagulant that drastically reduces bleeding on all bleeding wounds. If you don't have time to properly treat someone with lots of slashes or piercings, stick them with a pen to buy some time!
+Anything you can light a cigarette with, you can use to cauterize a bleeding wound. Technically, that includes the supermatter.
+Suit storage units entirely purge radiation from any carbon mob put inside of them when cycling, at the cost of some horrific burns, this is a very effective strategy to clean someone up after they bathed in the engine.
Laser pointers can be upgraded by replacing its micro laser with a better one from RnD! Use a screwdriver on it to remove the old laser. Upgrading the laser pointer gives you better odds of stunning a cyborg, and even blinding people with sunglasses.
-Being out of combat mode makes makes you deal less damage to people and objects when attacking.
-Resting makes you deal less damage to people and objects when attacking.
+Being out of combat mode makes makes you deal less damage to people and objects when attacking. This stacks with the penalty incurred by resting.
+Resting makes you deal less damage to people and objects when attacking. This stacks with the penalty incurred by being out of combat mode.
You do not regenerate as much stamina while in combat mode. Resting (being on the ground) makes you regenerate stamina faster.
Remember to be in combat mode while in combat, as otherwise you will be penalized by taking more incoming damage and dealing less damage to your adversary.
diff --git a/tgstation.dme b/tgstation.dme
index 5ed22d673e..ffc31b1f5e 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -558,6 +558,7 @@
#include "code\datums\elements\_element.dm"
#include "code\datums\elements\art.dm"
#include "code\datums\elements\beauty.dm"
+#include "code\datums\elements\bsa_blocker.dm"
#include "code\datums\elements\cleaning.dm"
#include "code\datums\elements\decal.dm"
#include "code\datums\elements\dusts_on_catatonia.dm"
@@ -728,6 +729,7 @@
#include "code\game\gamemodes\dynamic\dynamic_rulesets_midround.dm"
#include "code\game\gamemodes\dynamic\dynamic_rulesets_roundstart.dm"
#include "code\game\gamemodes\dynamic\dynamic_storytellers.dm"
+#include "code\game\gamemodes\eldritch_cult\eldritch_cult.dm"
#include "code\game\gamemodes\extended\extended.dm"
#include "code\game\gamemodes\gangs\dominator.dm"
#include "code\game\gamemodes\gangs\dominator_countdown.dm"
@@ -1297,6 +1299,7 @@
#include "code\game\turfs\open.dm"
#include "code\game\turfs\turf.dm"
#include "code\game\turfs\openspace\openspace.dm"
+#include "code\game\turfs\openspace\transparent.dm"
#include "code\game\turfs\simulated\chasm.dm"
#include "code\game\turfs\simulated\dirtystation.dm"
#include "code\game\turfs\simulated\floor.dm"
@@ -1392,6 +1395,7 @@
#include "code\modules\admin\view_variables\mark_datum.dm"
#include "code\modules\admin\view_variables\mass_edit_variables.dm"
#include "code\modules\admin\view_variables\modify_variables.dm"
+#include "code\modules\admin\view_variables\reference_tracking.dm"
#include "code\modules\admin\view_variables\topic.dm"
#include "code\modules\admin\view_variables\topic_basic.dm"
#include "code\modules\admin\view_variables\topic_list.dm"
@@ -1599,6 +1603,16 @@
#include "code\modules\antagonists\disease\disease_disease.dm"
#include "code\modules\antagonists\disease\disease_event.dm"
#include "code\modules\antagonists\disease\disease_mob.dm"
+#include "code\modules\antagonists\eldritch_cult\eldritch_antag.dm"
+#include "code\modules\antagonists\eldritch_cult\eldritch_book.dm"
+#include "code\modules\antagonists\eldritch_cult\eldritch_effects.dm"
+#include "code\modules\antagonists\eldritch_cult\eldritch_items.dm"
+#include "code\modules\antagonists\eldritch_cult\eldritch_knowledge.dm"
+#include "code\modules\antagonists\eldritch_cult\eldritch_magic.dm"
+#include "code\modules\antagonists\eldritch_cult\eldritch_monster_antag.dm"
+#include "code\modules\antagonists\eldritch_cult\knowledge\ash_lore.dm"
+#include "code\modules\antagonists\eldritch_cult\knowledge\flesh_lore.dm"
+#include "code\modules\antagonists\eldritch_cult\knowledge\rust_lore.dm"
#include "code\modules\antagonists\ert\ert.dm"
#include "code\modules\antagonists\fugitive\fugitive.dm"
#include "code\modules\antagonists\fugitive\fugitive_outfits.dm"
@@ -2590,6 +2604,7 @@
#include "code\modules\mob\living\simple_animal\constructs.dm"
#include "code\modules\mob\living\simple_animal\corpse.dm"
#include "code\modules\mob\living\simple_animal\damage_procs.dm"
+#include "code\modules\mob\living\simple_animal\eldritch_demons.dm"
#include "code\modules\mob\living\simple_animal\parrot.dm"
#include "code\modules\mob\living\simple_animal\pickle.dm"
#include "code\modules\mob\living\simple_animal\shade.dm"
@@ -3268,9 +3283,9 @@
#include "code\modules\spells\spell.dm"
#include "code\modules\spells\spell_types\aimed.dm"
#include "code\modules\spells\spell_types\area_teleport.dm"
-#include "code\modules\spells\spell_types\barnyard.dm"
#include "code\modules\spells\spell_types\bloodcrawl.dm"
#include "code\modules\spells\spell_types\charge.dm"
+#include "code\modules\spells\spell_types\cone_spells.dm"
#include "code\modules\spells\spell_types\conjure.dm"
#include "code\modules\spells\spell_types\construct_spells.dm"
#include "code\modules\spells\spell_types\curse.dm"
@@ -3289,7 +3304,6 @@
#include "code\modules\spells\spell_types\lichdom.dm"
#include "code\modules\spells\spell_types\lightning.dm"
#include "code\modules\spells\spell_types\mime.dm"
-#include "code\modules\spells\spell_types\mind_transfer.dm"
#include "code\modules\spells\spell_types\projectile.dm"
#include "code\modules\spells\spell_types\rightandwrong.dm"
#include "code\modules\spells\spell_types\rod_form.dm"
@@ -3306,6 +3320,10 @@
#include "code\modules\spells\spell_types\turf_teleport.dm"
#include "code\modules\spells\spell_types\voice_of_god.dm"
#include "code\modules\spells\spell_types\wizard.dm"
+#include "code\modules\spells\spell_types\pointed\barnyard.dm"
+#include "code\modules\spells\spell_types\pointed\blind.dm"
+#include "code\modules\spells\spell_types\pointed\mind_transfer.dm"
+#include "code\modules\spells\spell_types\pointed\pointed.dm"
#include "code\modules\station_goals\bsa.dm"
#include "code\modules\station_goals\dna_vault.dm"
#include "code\modules\station_goals\shield.dm"
|