Progress in core mutation: [T.applied] / [SLIME_EXTRACT_CROSSING_REQUIRED]")
+ to_chat(user, "Progress in core mutation: [T.applied] / [SLIME_EXTRACT_CROSSING_REQUIRED]")
to_chat(user, "========================")
diff --git a/code/game/objects/items/granters.dm b/code/game/objects/items/granters.dm
index 21f6961e5d..71687f0d5a 100644
--- a/code/game/objects/items/granters.dm
+++ b/code/game/objects/items/granters.dm
@@ -1,4 +1,3 @@
-
///books that teach things (intrinsic actions like bar flinging, spells like fireball or smoke, or martial arts)///
/obj/item/book/granter
@@ -13,19 +12,50 @@
/obj/item/book/granter/proc/turn_page(mob/user)
playsound(user, pick('sound/effects/pageturn1.ogg','sound/effects/pageturn2.ogg','sound/effects/pageturn3.ogg'), 30, 1)
if(do_after(user,50, user))
- to_chat(user, "[pick(remarks)]")
+ if(remarks.len)
+ to_chat(user, "[pick(remarks)]")
+ else
+ to_chat(user, "You keep reading...")
return TRUE
return FALSE
/obj/item/book/granter/proc/recoil(mob/user) //nothing so some books can just return
+/obj/item/book/granter/proc/already_known(mob/user)
+ return FALSE
+
+/obj/item/book/granter/proc/on_reading_start(mob/user)
+ to_chat(user, "You start reading [name]...")
+
+/obj/item/book/granter/proc/on_reading_stopped(mob/user)
+ to_chat(user, "You stop reading...")
+
+/obj/item/book/granter/proc/on_reading_finished(mob/user)
+ to_chat(user, "You finish reading [name]!")
+
/obj/item/book/granter/proc/onlearned(mob/user)
used = TRUE
+
/obj/item/book/granter/attack_self(mob/user)
- if(reading == TRUE)
+ if(reading)
to_chat(user, "You're already reading this!")
return FALSE
+ if(already_known(user))
+ return FALSE
+ if(used && oneuse)
+ recoil(user)
+ else
+ on_reading_start(user)
+ reading = TRUE
+ for(var/i=1, i<=pages_to_mastery, i++)
+ if(!turn_page(user))
+ on_reading_stopped()
+ reading = FALSE
+ return
+ if(do_after(user,50, user))
+ on_reading_finished(user)
+ reading = FALSE
return TRUE
///ACTION BUTTONS///
@@ -34,33 +64,23 @@
var/granted_action
var/actionname = "catching bugs" //might not seem needed but this makes it so you can safely name action buttons toggle this or that without it fucking up the granter, also caps
-/obj/item/book/granter/action/attack_self(mob/user)
- . = ..()
- if(!.)
- return
+/obj/item/book/granter/action/already_known(mob/user)
if(!granted_action)
- return
- var/datum/action/G = new granted_action
+ return TRUE
for(var/datum/action/A in user.actions)
- if(A.type == G.type)
+ if(A.type == granted_action)
to_chat(user, "You already know all about [actionname].")
- qdel(G)
- return
- if(used == TRUE && oneuse == TRUE)
- recoil(user)
- else
- to_chat(user, "You start reading about [actionname]...")
- reading = TRUE
- for(var/i=1, i<=pages_to_mastery, i++)
- if(!turn_page(user))
- to_chat(user, "You stop reading...")
- reading = FALSE
- qdel(G)
- return
- if(do_after(user,50, user))
- to_chat(user, "You feel like you've got a good handle on [actionname]!")
- G.Grant(user)
- reading = FALSE
+ return TRUE
+ return FALSE
+
+/obj/item/book/granter/action/on_reading_start(mob/user)
+ to_chat(user, "You start reading about [actionname]...")
+
+/obj/item/book/granter/action/on_reading_finished(mob/user)
+ to_chat(user, "You feel like you've got a good handle on [actionname]!")
+ var/datum/action/G = new granted_action
+ G.Grant(user)
+ onlearned(user)
/obj/item/book/granter/action/drink_fling
granted_action = /datum/action/innate/drink_fling
@@ -120,38 +140,28 @@
var/spell
var/spellname = "conjure bugs"
-/obj/item/book/granter/spell/attack_self(mob/user)
- . = ..()
- if(!.)
- return
+/obj/item/book/granter/spell/already_known(mob/user)
if(!spell)
- return
- var/obj/effect/proc_holder/spell/S = new spell
+ return TRUE
for(var/obj/effect/proc_holder/spell/knownspell in user.mind.spell_list)
- if(knownspell.type == S.type)
+ if(knownspell.type == spell)
if(user.mind)
if(iswizard(user))
- to_chat(user,"You're already far more versed in this spell than this flimsy howto book can provide.")
+ to_chat(user,"You're already far more versed in this spell than this flimsy how-to book can provide.")
else
to_chat(user,"You've already read this one.")
- return
- if(used == TRUE && oneuse == TRUE)
- recoil(user)
- else
- to_chat(user, "You start reading about casting [spellname]...")
- reading = TRUE
- for(var/i=1, i<=pages_to_mastery, i++)
- if(!turn_page(user))
- to_chat(user, "You stop reading...")
- reading = FALSE
- qdel(S)
- return
- if(do_after(user,50, user))
- to_chat(user, "You feel like you've experienced enough to cast [spellname]!")
- user.mind.AddSpell(S)
- user.log_message("learned the spell [spellname] ([S])", LOG_ATTACK, color="orange")
- onlearned(user)
- reading = FALSE
+ return TRUE
+ return FALSE
+
+/obj/item/book/granter/spell/on_reading_start(mob/user)
+ to_chat(user, "You start reading about casting [spellname]...")
+
+/obj/item/book/granter/spell/on_reading_finished(mob/user)
+ to_chat(user, "You feel like you've experienced enough to cast [spellname]!")
+ var/obj/effect/proc_holder/spell/S = new spell
+ user.mind.AddSpell(S)
+ user.log_message("learned the spell [spellname] ([S])", LOG_ATTACK, color="orange")
+ onlearned(user)
/obj/item/book/granter/spell/recoil(mob/user)
user.visible_message("[src] glows in a black light!")
@@ -280,7 +290,8 @@
if(ishuman(user))
to_chat(user,"HORSIE HAS RISEN")
var/obj/item/clothing/magichead = new /obj/item/clothing/mask/horsehead/cursed(user.drop_location())
- user.dropItemToGround(user.wear_mask, TRUE)
+ if(!user.dropItemToGround(user.wear_mask))
+ qdel(user.wear_mask)
user.equip_to_slot_if_possible(magichead, SLOT_WEAR_MASK, TRUE, TRUE)
qdel(src)
else
@@ -327,35 +338,24 @@
var/martialname = "bug jitsu"
var/greet = "You feel like you have mastered the art in breaking code. Nice work, jackass."
-/obj/item/book/granter/martial/attack_self(mob/user)
- . = ..()
- if(!.)
- return
+/obj/item/book/granter/martial/already_known(mob/user)
if(!martial)
- return
+ return TRUE
+ var/datum/martial_art/MA = martial
+ if(user.mind.has_martialart(initial(MA.id)))
+ to_chat(user,"You already know [martialname]!")
+ return TRUE
+ return FALSE
+
+/obj/item/book/granter/martial/on_reading_start(mob/user)
+ to_chat(user, "You start reading about [martialname]...")
+
+/obj/item/book/granter/martial/on_reading_finished(mob/user)
+ to_chat(user, "[greet]")
var/datum/martial_art/MA = new martial
- if(user.mind.martial_art)
- for(var/datum/martial_art/knownmartial in user.mind.martial_art)
- if(knownmartial.type == MA.type)
- to_chat(user,"You already know [martialname]!")
- return
- if(used == TRUE && oneuse == TRUE)
- recoil(user)
- else
- to_chat(user, "You start reading about [martialname]...")
- reading = TRUE
- for(var/i=1, i<=pages_to_mastery, i++)
- if(!turn_page(user))
- to_chat(user, "You stop reading...")
- reading = FALSE
- qdel(MA)
- return
- if(do_after(user,50, user))
- to_chat(user, "[greet]")
- MA.teach(user)
- user.log_message("learned the martial art [martialname] ([MA])", LOG_ATTACK, color="orange")
- onlearned(user)
- reading = FALSE
+ MA.teach(user)
+ user.log_message("learned the martial art [martialname] ([MA])", LOG_ATTACK, color="orange")
+ onlearned(user)
/obj/item/book/granter/martial/cqc
martial = /datum/martial_art/cqc
@@ -416,3 +416,44 @@
icon_state = "blankscroll"
// I did not include mushpunch's grant, it is not a book and the item does it just fine.
+
+
+//Crafting Recipe books
+
+/obj/item/book/granter/crafting_recipe
+ var/list/crafting_recipe_types = list() //Use full /datum/crafting_recipe/what_you_craft
+
+/obj/item/book/granter/crafting_recipe/on_reading_finished(mob/user)
+ . = ..()
+ if(!user.mind)
+ return
+ for(var/crafting_recipe_type in crafting_recipe_types)
+ var/datum/crafting_recipe/R = crafting_recipe_type
+ user.mind.teach_crafting_recipe(crafting_recipe_type)
+ to_chat(user,"You learned how to make [initial(R.name)].")
+
+/obj/item/book/granter/crafting_recipe/cooking_sweets_101 //We start at 101 for 103 and 105
+ name = "Cooking Desserts 101"
+ desc = "A cook book that teaches you some more of the newest desserts. AI approved, and a best seller on Honkplanet."
+ crafting_recipe_types = list(/datum/crafting_recipe/food/mimetart, /datum/crafting_recipe/food/berrytart, /datum/crafting_recipe/food/cocolavatart, /datum/crafting_recipe/food/clowncake, /datum/crafting_recipe/food/vanillacake)
+ icon_state = "cooking_learing_sweets"
+ oneuse = FALSE
+ remarks = list("So that is how icing is made!", "Placing fruit on top? How simple...", "Huh layering cake seems harder then this...", "This book smells like candy", "A clown must have made this page, or they forgot to spell check it before printing...", "Wait, a way to cook slime to be safe?")
+
+//Later content when I have free time - Trilby Date:02-Aug-2019
+
+/obj/item/book/granter/crafting_recipe/under_the_oven //Illegal cook book
+ name = "Under The Oven"
+ desc = "A cook book that teaches you many illegal and fun candys. MALF AI approved, and a best seller on the blackmarket."
+ crafting_recipe_types = list()
+ icon_state = "cooking_learing_illegal"
+ oneuse = FALSE
+ remarks = list()
+
+/obj/item/book/granter/crafting_recipe/coldcooking //IceCream
+ name = "Cooking with Ice"
+ desc = "A cook book that teaches you many old icecream treats."
+ crafting_recipe_types = list()
+ icon_state = "cooking_learing_ice"
+ oneuse = FALSE
+ remarks = list()
\ No newline at end of file
diff --git a/code/game/objects/items/handcuffs.dm b/code/game/objects/items/handcuffs.dm
index 5e19577b46..a306b48385 100644
--- a/code/game/objects/items/handcuffs.dm
+++ b/code/game/objects/items/handcuffs.dm
@@ -26,6 +26,7 @@
gender = PLURAL
icon = 'icons/obj/items_and_weapons.dmi'
icon_state = "handcuff"
+ item_state = "handcuff"
lefthand_file = 'icons/mob/inhands/equipment/security_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/security_righthand.dmi'
flags_1 = CONDUCT_1
@@ -103,7 +104,6 @@
desc = "A pair of restraints fashioned from long strands of flesh."
icon = 'icons/obj/mining.dmi'
icon_state = "sinewcuff"
- item_state = "sinewcuff"
breakouttime = 300 //Deciseconds = 30s
cuffsound = 'sound/weapons/cablecuff.ogg'
@@ -164,14 +164,6 @@
/obj/item/restraints/handcuffs/cable/white
item_color = "white"
-/obj/item/restraints/handcuffs/alien
- icon_state = "handcuffAlien"
-
-/obj/item/restraints/handcuffs/fake
- name = "fake handcuffs"
- desc = "Fake handcuffs meant for gag purposes."
- breakouttime = 10 //Deciseconds = 1s
-
/obj/item/restraints/handcuffs/cable/attackby(obj/item/I, mob/user, params)
..()
if(istype(I, /obj/item/stack/rods))
@@ -206,7 +198,7 @@
/obj/item/restraints/handcuffs/cable/zipties
name = "zipties"
desc = "Plastic, disposable zipties that can be used to restrain temporarily but are destroyed after use."
- icon_state = "cuff"
+ item_state = "zipties"
lefthand_file = 'icons/mob/inhands/equipment/security_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/security_righthand.dmi'
materials = list()
@@ -217,11 +209,25 @@
/obj/item/restraints/handcuffs/cable/zipties/used
desc = "A pair of broken zipties."
icon_state = "cuff_used"
- item_state = "cuff"
/obj/item/restraints/handcuffs/cable/zipties/used/attack()
return
+/obj/item/restraints/handcuffs/alien
+ icon_state = "handcuffAlien"
+
+/obj/item/restraints/handcuffs/fake
+ name = "fake handcuffs"
+ desc = "Fake handcuffs meant for gag purposes."
+ breakouttime = 10 //Deciseconds = 1s
+
+/obj/item/restraints/handcuffs/fake/kinky
+ name = "kinky handcuffs"
+ desc = "Fake handcuffs meant for erotic roleplay."
+ icon = 'modular_citadel/icons/obj/items_and_weapons.dmi'
+ icon_state = "handcuffgag"
+ item_state = "kinkycuff"
+
//Legcuffs
/obj/item/restraints/legcuffs
@@ -230,6 +236,7 @@
gender = PLURAL
icon = 'icons/obj/items_and_weapons.dmi'
icon_state = "handcuff"
+ item_state = "legcuff"
lefthand_file = 'icons/mob/inhands/equipment/security_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/security_righthand.dmi'
flags_1 = CONDUCT_1
diff --git a/code/game/objects/items/his_grace.dm b/code/game/objects/items/his_grace.dm
index 6e977331a6..c6f246ab97 100644
--- a/code/game/objects/items/his_grace.dm
+++ b/code/game/objects/items/his_grace.dm
@@ -14,6 +14,7 @@
icon = 'icons/obj/items_and_weapons.dmi'
w_class = WEIGHT_CLASS_GIGANTIC
force = 12
+ total_mass = TOTAL_MASS_NORMAL_ITEM // average toolbox
attack_verb = list("robusted")
hitsound = 'sound/weapons/smash.ogg'
var/awakened = FALSE
@@ -174,6 +175,7 @@
/obj/item/his_grace/proc/consume(mob/living/meal) //Here's your dinner, Mr. Grace.
if(!meal)
return
+ var/victims = 0
meal.visible_message("[src] swings open and devours [meal]!", "[src] consumes you!")
meal.adjustBruteLoss(200)
playsound(meal, 'sound/misc/desceration-02.ogg', 75, 1)
@@ -185,7 +187,10 @@
bloodthirst = max(LAZYLEN(contents), 1) //Never fully sated, and His hunger will only grow.
else
bloodthirst = HIS_GRACE_CONSUME_OWNER
- if(LAZYLEN(contents) >= victims_needed)
+ for(var/mob/living/C in contents)
+ if(C.mind)
+ victims++
+ if(victims >= victims_needed)
ascend()
update_stats()
diff --git a/code/game/objects/items/holy_weapons.dm b/code/game/objects/items/holy_weapons.dm
index 0e8a9fef9e..ad4384f9f5 100644
--- a/code/game/objects/items/holy_weapons.dm
+++ b/code/game/objects/items/holy_weapons.dm
@@ -285,14 +285,12 @@
hitsound = 'sound/weapons/sear.ogg'
damtype = BURN
attack_verb = list("punched", "cross countered", "pummeled")
-
+ total_mass = TOTAL_MASS_HAND_REPLACEMENT
/obj/item/nullrod/godhand/Initialize()
. = ..()
ADD_TRAIT(src, TRAIT_NODROP, HAND_REPLACEMENT_TRAIT)
-
-
/obj/item/nullrod/staff
icon_state = "godstaff-red"
item_state = "godstaff-red"
@@ -330,6 +328,7 @@
sharpness = IS_SHARP
hitsound = 'sound/weapons/bladeslice.ogg'
attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut")
+ total_mass = TOTAL_MASS_MEDIEVAL_WEAPON
/obj/item/nullrod/claymore/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
if(attack_type == PROJECTILE_ATTACK)
@@ -523,6 +522,7 @@
slot_flags = ITEM_SLOT_BELT
w_class = WEIGHT_CLASS_HUGE
attack_verb = list("smashed", "bashed", "hammered", "crunched")
+ total_mass = TOTAL_MASS_MEDIEVAL_WEAPON
/obj/item/nullrod/chainsaw
name = "chainsaw hand"
@@ -536,6 +536,7 @@
sharpness = IS_SHARP
attack_verb = list("sawed", "torn", "cut", "chopped", "diced")
hitsound = 'sound/weapons/chainsawhit.ogg'
+ total_mass = TOTAL_MASS_HAND_REPLACEMENT
/obj/item/nullrod/chainsaw/Initialize()
. = ..()
@@ -612,6 +613,7 @@
item_flags = ABSTRACT
w_class = WEIGHT_CLASS_HUGE
sharpness = IS_SHARP
+ total_mass = TOTAL_MASS_HAND_REPLACEMENT
/obj/item/nullrod/armblade/Initialize()
. = ..()
@@ -672,6 +674,7 @@
hitsound = 'sound/weapons/bladeslice.ogg'
attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut")
item_flags = SLOWS_WHILE_IN_HAND
+ total_mass = TOTAL_MASS_NORMAL_ITEM
/obj/item/nullrod/tribal_knife/Initialize(mapload)
. = ..()
diff --git a/code/game/objects/items/implants/implant_krav_maga.dm b/code/game/objects/items/implants/implant_krav_maga.dm
index 3a751ecd0e..373658b386 100644
--- a/code/game/objects/items/implants/implant_krav_maga.dm
+++ b/code/game/objects/items/implants/implant_krav_maga.dm
@@ -21,7 +21,7 @@
return
if(!H.mind)
return
- if(istype(H.mind.martial_art, /datum/martial_art/krav_maga))
+ if(H.mind.has_martialart(MARTIALART_KRAVMAGA))
style.remove(H)
else
style.teach(H,1)
diff --git a/code/game/objects/items/implants/implant_stealth.dm b/code/game/objects/items/implants/implant_stealth.dm
index 84f9f5f454..eb58d76d1b 100644
--- a/code/game/objects/items/implants/implant_stealth.dm
+++ b/code/game/objects/items/implants/implant_stealth.dm
@@ -9,6 +9,7 @@
name = "inconspicious box"
desc = "It's so normal that you didn't notice it before."
icon_state = "agentbox"
+ max_integrity = 1
use_mob_movespeed = TRUE
/obj/structure/closet/cardboard/agent/proc/go_invisible()
diff --git a/code/game/objects/items/melee/energy.dm b/code/game/objects/items/melee/energy.dm
index 935d2a007e..d854ab9f5a 100644
--- a/code/game/objects/items/melee/energy.dm
+++ b/code/game/objects/items/melee/energy.dm
@@ -5,9 +5,12 @@
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 30)
resistance_flags = FIRE_PROOF
var/brightness_on = 3
+ total_mass = 0.4 //Survival flashlights typically weigh around 5 ounces.
+
/obj/item/melee/transforming/energy/Initialize()
. = ..()
+ total_mass_on = (total_mass_on ? total_mass_on : (w_class_on * 0.75))
if(active)
set_light(brightness_on)
START_PROCESSING(SSobj, src)
@@ -79,6 +82,7 @@
attack_verb_off = list("attacked", "chopped", "cleaved", "torn", "cut")
attack_verb_on = list()
light_color = "#40ceff"
+ total_mass = null
/obj/item/melee/transforming/energy/axe/suicide_act(mob/user)
user.visible_message("[user] swings [src] towards [user.p_their()] head! It looks like [user.p_theyre()] trying to commit suicide!")
diff --git a/code/game/objects/items/melee/misc.dm b/code/game/objects/items/melee/misc.dm
index 0d45960767..cdb9c146e2 100644
--- a/code/game/objects/items/melee/misc.dm
+++ b/code/game/objects/items/melee/misc.dm
@@ -44,6 +44,7 @@
hitsound = 'sound/weapons/bladeslice.ogg'
attack_verb = list("attacked", "impaled", "stabbed", "sliced", "torn", "ripped", "diced", "cut")
sharpness = IS_SHARP
+ total_mass = TOTAL_MASS_HAND_REPLACEMENT
/obj/item/melee/synthetic_arm_blade/Initialize()
. = ..()
@@ -67,6 +68,7 @@
attack_verb = list("slashed", "cut")
hitsound = 'sound/weapons/rapierhit.ogg'
materials = list(MAT_METAL = 1000)
+ total_mass = 3.4
/obj/item/melee/sabre/Initialize()
. = ..()
@@ -89,6 +91,12 @@
if(istype(B))
playsound(B, 'sound/items/sheath.ogg', 25, 1)
+/obj/item/melee/sabre/get_belt_overlay()
+ return mutable_appearance('icons/obj/clothing/belt_overlays.dmi', "sabre")
+
+/obj/item/melee/sabre/get_worn_belt_overlay(icon_file)
+ return mutable_appearance(icon_file, "-sabre")
+
/obj/item/melee/sabre/suicide_act(mob/living/user)
user.visible_message("[user] is trying to cut off all [user.p_their()] limbs with [src]! it looks like [user.p_theyre()] trying to commit suicide!")
var/i = 0
@@ -147,13 +155,20 @@
flags_1 = CONDUCT_1
obj_flags = UNIQUE_RENAME
w_class = WEIGHT_CLASS_BULKY
- sharpness = IS_SHARP_ACCURATE //It cant be sharpend cook -_-
+ sharpness = IS_SHARP_ACCURATE //It cant be sharpend cook -_-
attack_verb = list("slashed", "cut", "pierces", "pokes")
+ total_mass = 3.4
/obj/item/melee/rapier/Initialize()
. = ..()
AddComponent(/datum/component/butchering, 20, 65, 0)
+/obj/item/melee/rapier/get_belt_overlay()
+ return mutable_appearance('icons/obj/clothing/belt_overlays.dmi', "rapier")
+
+/obj/item/melee/rapier/get_worn_belt_overlay(icon_file)
+ return mutable_appearance(icon_file, "-rapier")
+
/obj/item/melee/classic_baton
name = "police baton"
desc = "A wooden truncheon for beating criminal scum."
@@ -230,6 +245,7 @@
item_flags = NONE
force = 0
on = FALSE
+ total_mass = TOTAL_MASS_SMALL_ITEM
/obj/item/melee/classic_baton/telescopic/suicide_act(mob/user)
var/mob/living/carbon/human/H = user
@@ -390,6 +406,7 @@
var/static/list/ovens
var/on = FALSE
var/datum/beam/beam
+ total_mass = 2.5
/obj/item/melee/roastingstick/Initialize()
. = ..()
diff --git a/code/game/objects/items/melee/transforming.dm b/code/game/objects/items/melee/transforming.dm
index 0d39e6c847..aabb930bb2 100644
--- a/code/game/objects/items/melee/transforming.dm
+++ b/code/game/objects/items/melee/transforming.dm
@@ -13,6 +13,7 @@
var/list/nemesis_factions //Any mob with a faction that exists in this list will take bonus damage/effects
var/w_class_on = WEIGHT_CLASS_BULKY
var/clumsy_check = TRUE
+ var/total_mass_on //Total mass in ounces when transformed. Primarily for balance purposes. Don't think about it too hard.
/obj/item/melee/transforming/Initialize()
. = ..()
@@ -46,6 +47,7 @@
active = !active
if(active)
force = force_on
+ total_mass = total_mass_on
throwforce = throwforce_on
hitsound = hitsound_on
throw_speed = 4
@@ -62,6 +64,7 @@
attack_verb = attack_verb_off
icon_state = initial(icon_state)
w_class = initial(w_class)
+ total_mass = initial(total_mass)
if(is_sharp())
var/datum/component/butchering/BT = LoadComponent(/datum/component/butchering)
BT.butchering_enabled = TRUE
@@ -84,4 +87,4 @@
/obj/item/melee/transforming/proc/clumsy_transform_effect(mob/living/user)
if(clumsy_check && HAS_TRAIT(user, TRAIT_CLUMSY) && prob(50))
to_chat(user, "You accidentally cut yourself with [src], like a doofus!")
- user.take_bodypart_damage(5,5)
+ user.take_bodypart_damage(5,5)
\ No newline at end of file
diff --git a/code/game/objects/items/plushes.dm b/code/game/objects/items/plushes.dm
index b5bb4fa233..40380dfe80 100644
--- a/code/game/objects/items/plushes.dm
+++ b/code/game/objects/items/plushes.dm
@@ -664,6 +664,27 @@
item_state = "box"
attack_verb = list("open", "closed", "packed", "hidden", "rigged", "bombed", "sent", "gave")
+/obj/item/toy/plush/slaggy
+ name = "slag plushie"
+ desc = "A piece of slag with some googly eyes and a drawn on mouth."
+ icon_state = "slaggy"
+ item_state = "slaggy"
+ attack_verb = list("melted", "refined", "stared")
+
+/obj/item/toy/plush/mr_buckety
+ name = "bucket plushie"
+ desc = "A bucket that is missing its handle with some googly eyes and a drawn on mouth."
+ icon_state = "mr_buckety"
+ item_state = "mr_buckety"
+ attack_verb = list("filled", "dumped", "stared")
+
+/obj/item/toy/plush/dr_scanny
+ name = "scanner plushie"
+ desc = "A old outdated scanner that has been modified to have googly eyes, a dawn on mouth and, heart."
+ icon_state = "dr_scanny"
+ item_state = "dr_scanny"
+ attack_verb = list("scanned", "beeped", "stared")
+
/obj/item/toy/plush/borgplushie
name = "robot plushie"
desc = "An adorable stuffed toy of a robot."
diff --git a/code/game/objects/items/scrolls.dm b/code/game/objects/items/scrolls.dm
index 07f6edb828..28a4664a24 100644
--- a/code/game/objects/items/scrolls.dm
+++ b/code/game/objects/items/scrolls.dm
@@ -66,7 +66,8 @@
to_chat(user, "The spell matrix was unable to locate a suitable teleport destination for an unknown reason. Sorry.")
return
- user.forceMove(pick(L))
-
- smoke.start()
- uses--
+ if(do_teleport(user, pick(L), forceMove = TRUE, channel = TELEPORT_CHANNEL_MAGIC, forced = TRUE))
+ smoke.start()
+ uses--
+ else
+ to_chat(user, "The spell matrix was disrupted by something near the destination.")
diff --git a/code/game/objects/items/singularityhammer.dm b/code/game/objects/items/singularityhammer.dm
index 1fe57d151f..b6559c9091 100644
--- a/code/game/objects/items/singularityhammer.dm
+++ b/code/game/objects/items/singularityhammer.dm
@@ -16,6 +16,7 @@
armor = list("melee" = 50, "bullet" = 50, "laser" = 50, "energy" = 0, "bomb" = 50, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 100)
resistance_flags = FIRE_PROOF | ACID_PROOF
force_string = "LORD SINGULOTH HIMSELF"
+ total_mass = TOTAL_MASS_MEDIEVAL_WEAPON
/obj/item/twohanded/singularityhammer/New()
..()
@@ -84,6 +85,7 @@
throwforce = 30
throw_range = 7
w_class = WEIGHT_CLASS_HUGE
+ total_mass = TOTAL_MASS_MEDIEVAL_WEAPON
/obj/item/twohanded/mjollnir/proc/shock(mob/living/target)
target.Stun(60)
diff --git a/code/game/objects/items/stacks/bscrystal.dm b/code/game/objects/items/stacks/bscrystal.dm
index 522e1a1153..49a735af9c 100644
--- a/code/game/objects/items/stacks/bscrystal.dm
+++ b/code/game/objects/items/stacks/bscrystal.dm
@@ -33,7 +33,7 @@
use(1)
/obj/item/stack/ore/bluespace_crystal/proc/blink_mob(mob/living/L)
- do_teleport(L, get_turf(L), blink_range, asoundin = 'sound/effects/phasein.ogg')
+ do_teleport(L, get_turf(L), blink_range, asoundin = 'sound/effects/phasein.ogg', channel = TELEPORT_CHANNEL_BLUESPACE)
/obj/item/stack/ore/bluespace_crystal/throw_impact(atom/hit_atom)
if(!..()) // not caught in mid-air
diff --git a/code/game/objects/items/stacks/medical.dm b/code/game/objects/items/stacks/medical.dm
index 4bb3359c2f..5610cbad9a 100644
--- a/code/game/objects/items/stacks/medical.dm
+++ b/code/game/objects/items/stacks/medical.dm
@@ -18,7 +18,7 @@
/obj/item/stack/medical/attack(mob/living/M, mob/user)
- if(M.stat == DEAD)
+ if(M.stat == DEAD && !stop_bleeding)
var/t_him = "it"
if(M.gender == MALE)
t_him = "him"
diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm
index e1ecf6d14d..8c808d0e5f 100644
--- a/code/game/objects/items/stacks/sheets/sheet_types.dm
+++ b/code/game/objects/items/stacks/sheets/sheet_types.dm
@@ -201,6 +201,7 @@ GLOBAL_LIST_INIT(wood_recipes, list ( \
new/datum/stack_recipe("dresser", /obj/structure/dresser, 10, time = 15, one_per_turf = TRUE, on_floor = TRUE), \
new/datum/stack_recipe("picture frame", /obj/item/wallframe/picture, 1, time = 10),\
new/datum/stack_recipe("display case chassis", /obj/structure/displaycase_chassis, 5, one_per_turf = TRUE, on_floor = TRUE), \
+ new/datum/stack_recipe("loom", /obj/structure/loom, 10, time = 15, one_per_turf = TRUE, on_floor = TRUE), \
new/datum/stack_recipe("wooden buckler", /obj/item/shield/riot/buckler, 20, time = 40), \
new/datum/stack_recipe("apiary", /obj/structure/beebox, 40, time = 50),\
new/datum/stack_recipe("tiki mask", /obj/item/clothing/mask/gas/tiki_mask, 2), \
@@ -248,7 +249,8 @@ GLOBAL_LIST_INIT(cloth_recipes, list ( \
new/datum/stack_recipe("bio bag", /obj/item/storage/bag/bio, 4), \
null, \
new/datum/stack_recipe("improvised gauze", /obj/item/stack/medical/gauze/improvised, 1, 2, 6), \
- new/datum/stack_recipe("rag", /obj/item/reagent_containers/glass/rag, 1), \
+ new/datum/stack_recipe("rag", /obj/item/reagent_containers/rag, 1), \
+ new/datum/stack_recipe("towel", /obj/item/reagent_containers/rag/towel, 3), \
new/datum/stack_recipe("bedsheet", /obj/item/bedsheet, 3), \
new/datum/stack_recipe("empty sandbag", /obj/item/emptysandbag, 4), \
null, \
@@ -277,6 +279,31 @@ GLOBAL_LIST_INIT(cloth_recipes, list ( \
/obj/item/stack/sheet/cloth/ten
amount = 10
+//Durathread fuck slash-asterisk comments
+ GLOBAL_LIST_INIT(durathread_recipes, list ( \
+ new/datum/stack_recipe("durathread jumpsuit", /obj/item/clothing/under/durathread, 4, time = 40),
+ new/datum/stack_recipe("durathread beret", /obj/item/clothing/head/beret/durathread, 2, time = 40), \
+ new/datum/stack_recipe("durathread beanie", /obj/item/clothing/head/beanie/durathread, 2, time = 40), \
+ new/datum/stack_recipe("durathread bandana", /obj/item/clothing/mask/bandana/durathread, 1, time = 25), \
+ ))
+
+/obj/item/stack/sheet/durathread
+ name = "durathread"
+ desc = "A fabric sown from incredibly durable threads, known for its usefulness in armor production."
+ singular_name = "durathread roll"
+ icon_state = "sheet-durathread"
+ item_state = "sheet-cloth"
+ resistance_flags = FLAMMABLE
+ force = 0
+ throwforce = 0
+ merge_type = /obj/item/stack/sheet/durathread
+
+/obj/item/stack/sheet/durathread/Initialize(mapload, new_amount, merge = TRUE)
+ recipes = GLOB.durathread_recipes
+ return ..()
+
+
+
/*
* Cardboard
*/
@@ -414,6 +441,8 @@ GLOBAL_LIST_INIT(brass_recipes, list ( \
new/datum/stack_recipe("brass window - directional", /obj/structure/window/reinforced/clockwork/unanchored, time = 0, on_floor = TRUE, window_checks = TRUE), \
new/datum/stack_recipe("brass window - fulltile", /obj/structure/window/reinforced/clockwork/fulltile/unanchored, 2, time = 0, on_floor = TRUE, window_checks = TRUE), \
new/datum/stack_recipe("brass chair", /obj/structure/chair/brass, 1, time = 0, one_per_turf = TRUE, on_floor = TRUE), \
+ new/datum/stack_recipe("brass bar stool", /obj/structure/chair/stool/bar/brass, 1, time = 0, one_per_turf = TRUE, on_floor = TRUE), \
+ new/datum/stack_recipe("brass stool", /obj/structure/chair/stool/brass, 1, time = 0, one_per_turf = TRUE, on_floor = TRUE), \
new/datum/stack_recipe("brass table frame", /obj/structure/table_frame/brass, 1, time = 5, one_per_turf = TRUE, on_floor = TRUE), \
null,
new/datum/stack_recipe("sender - pressure sensor", /obj/structure/destructible/clockwork/trap/trigger/pressure_sensor, 2, time = 20, one_per_turf = TRUE, on_floor = TRUE), \
@@ -425,7 +454,7 @@ GLOBAL_LIST_INIT(brass_recipes, list ( \
new/datum/stack_recipe("receiver - steam vent", /obj/structure/destructible/clockwork/trap/steam_vent, 3, time = 30, one_per_turf = TRUE, on_floor = TRUE, placement_checks = STACK_CHECK_CARDINALS), \
new/datum/stack_recipe("receiver - power nullifier", /obj/structure/destructible/clockwork/trap/power_nullifier, 5, time = 20, one_per_turf = TRUE, on_floor = TRUE, placement_checks = STACK_CHECK_CARDINALS), \
null,
- new/datum/stack_recipe("brass flask", /obj/item/reagent_containers/food/drinks/holyoil/null), \
+ new/datum/stack_recipe("brass flask", /obj/item/reagent_containers/food/drinks/bottle/holyoil/empty), \
))
@@ -477,6 +506,8 @@ GLOBAL_LIST_INIT(bronze_recipes, list ( \
new/datum/stack_recipe("bronze boots", /obj/item/clothing/shoes/bronze), \
null,
new/datum/stack_recipe("bronze chair", /obj/structure/chair/bronze, 1, time = 0, one_per_turf = TRUE, on_floor = TRUE), \
+ new/datum/stack_recipe("bronze bar stool", /obj/structure/chair/stool/bar/bronze, 1, time = 0, one_per_turf = TRUE, on_floor = TRUE), \
+ new/datum/stack_recipe("bronze stool", /obj/structure/chair/stool/bronze, 1, time = 0, one_per_turf = TRUE, on_floor = TRUE), \
))
/obj/item/stack/tile/bronze
@@ -598,3 +629,29 @@ new /datum/stack_recipe("paper frame door", /obj/structure/mineral_door/paperfra
amount = 20
/obj/item/stack/sheet/paperframes/fifty
amount = 50
+
+
+//durathread and cotton raw
+/obj/item/stack/sheet/cotton
+ name = "raw cotton bundle"
+ desc = "A bundle of raw cotton ready to be spun on the loom."
+ singular_name = "raw cotton ball"
+ icon_state = "sheet-cotton"
+ is_fabric = TRUE
+ resistance_flags = FLAMMABLE
+ force = 0
+ throwforce = 0
+ merge_type = /obj/item/stack/sheet/cotton
+ pull_effort = 30
+ loom_result = /obj/item/stack/sheet/cloth
+
+/obj/item/stack/sheet/cotton/durathread
+ name = "raw durathread bundle"
+ desc = "A bundle of raw durathread ready to be spun on the loom."
+ singular_name = "raw durathread ball"
+ icon_state = "sheet-durathreadraw"
+ merge_type = /obj/item/stack/sheet/cotton/durathread
+ pull_effort = 70
+ loom_result = /obj/item/stack/sheet/durathread
+
+
diff --git a/code/game/objects/items/stacks/sheets/sheets.dm b/code/game/objects/items/stacks/sheets/sheets.dm
index 21b43eba20..908fc88383 100644
--- a/code/game/objects/items/stacks/sheets/sheets.dm
+++ b/code/game/objects/items/stacks/sheets/sheets.dm
@@ -12,4 +12,7 @@
novariants = FALSE
var/perunit = MINERAL_MATERIAL_AMOUNT
var/sheettype = null //this is used for girders in the creation of walls/false walls
- var/point_value = 0 //turn-in value for the gulag stacker - loosely relative to its rarity.
\ No newline at end of file
+ var/point_value = 0 //turn-in value for the gulag stacker - loosely relative to its rarity
+ var/is_fabric = FALSE //is this a valid material for the loom?
+ var/loom_result //result from pulling on the loom
+ var/pull_effort = 0 //amount of delay when pulling on the loom
\ No newline at end of file
diff --git a/code/game/objects/items/storage/backpack.dm b/code/game/objects/items/storage/backpack.dm
index eb71311c96..887b6f5a2e 100644
--- a/code/game/objects/items/storage/backpack.dm
+++ b/code/game/objects/items/storage/backpack.dm
@@ -248,12 +248,13 @@
desc = "A bone satchel fashend with watcher wings and large bones from goliath. Can be worn on the belt."
icon = 'icons/obj/mining.dmi'
icon_state = "goliath_saddle"
- slot_flags = ITEM_SLOT_BACK | ITEM_SLOT_BELT
+ slot_flags = ITEM_SLOT_BACK
/obj/item/storage/backpack/satchel/bone/ComponentInitialize()
. = ..()
GET_COMPONENT(STR, /datum/component/storage)
- STR.max_combined_w_class = 10
+ STR.max_combined_w_class = 20
+ STR.max_items = 15
/obj/item/storage/backpack/satchel/cap
name = "captain's satchel"
@@ -383,6 +384,14 @@
icon_state = "duffel-eng"
item_state = "duffel-eng"
+/obj/item/storage/backpack/duffelbag/durathread
+ name = "durathread duffel bag"
+ desc = "A lightweight duffel bag made out of durathread."
+ icon_state = "duffel-durathread"
+ item_state = "duffel-durathread"
+ resistance_flags = FIRE_PROOF
+ slowdown = 0
+
/obj/item/storage/backpack/duffelbag/drone
name = "drone duffel bag"
desc = "A large duffel bag for holding tools and hats."
@@ -398,6 +407,7 @@
new /obj/item/stack/cable_coil/random(src)
new /obj/item/wirecutters(src)
new /obj/item/multitool(src)
+ new /obj/item/pipe_dispenser(src)
/obj/item/storage/backpack/duffelbag/clown
name = "clown's duffel bag"
diff --git a/code/game/objects/items/storage/belt.dm b/code/game/objects/items/storage/belt.dm
index e3494e36cf..4495e9da14 100755
--- a/code/game/objects/items/storage/belt.dm
+++ b/code/game/objects/items/storage/belt.dm
@@ -10,6 +10,7 @@
attack_verb = list("whipped", "lashed", "disciplined")
max_integrity = 300
var/content_overlays = FALSE //If this is true, the belt will gain overlays based on what it's holding
+ var/worn_overlays = FALSE //worn counterpart of the above.
/obj/item/storage/belt/suicide_act(mob/living/carbon/user)
user.visible_message("[user] begins belting [user.p_them()]self with \the [src]! It looks like [user.p_theyre()] trying to commit suicide!")
@@ -23,6 +24,12 @@
add_overlay(M)
..()
+/obj/item/storage/belt/worn_overlays(isinhands, icon_file)
+ . = ..()
+ if(!isinhands && worn_overlays)
+ for(var/obj/item/I in contents)
+ . += I.get_worn_belt_overlay(icon_file)
+
/obj/item/storage/belt/Initialize()
. = ..()
update_icon()
@@ -424,6 +431,48 @@
GET_COMPONENT(STR, /datum/component/storage)
STR.max_items = 6
+/obj/item/storage/belt/durathread
+ name = "durathread toolbelt"
+ desc = "A toolbelt made out of durathread, it seems resistant enough to hold even big tools like an RCD, it also has higher capacity."
+ icon_state = "webbing-durathread"
+ item_state = "webbing-durathread"
+ resistance_flags = FIRE_PROOF
+
+/obj/item/storage/belt/durathread/ComponentInitialize()
+ . = ..()
+ var/datum/component/storage/STR = GetComponent(/datum/component/storage)
+ STR.max_items = 14
+ STR.max_combined_w_class = 32
+ STR.max_w_class = WEIGHT_CLASS_NORMAL
+ STR.can_hold = typecacheof(list(
+ /obj/item/crowbar,
+ /obj/item/screwdriver,
+ /obj/item/weldingtool,
+ /obj/item/wirecutters,
+ /obj/item/wrench,
+ /obj/item/multitool,
+ /obj/item/flashlight,
+ /obj/item/stack/cable_coil,
+ /obj/item/t_scanner,
+ /obj/item/analyzer,
+ /obj/item/geiger_counter,
+ /obj/item/extinguisher/mini,
+ /obj/item/radio,
+ /obj/item/clothing/gloves,
+ /obj/item/holosign_creator/atmos,
+ /obj/item/holosign_creator/engineering,
+ /obj/item/forcefield_projector,
+ /obj/item/assembly/signaler,
+ /obj/item/lightreplacer,
+ /obj/item/rcd_ammo,
+ /obj/item/construction/rcd,
+ /obj/item/pipe_dispenser,
+ /obj/item/stack/rods,
+ /obj/item/stack/tile/plasteel,
+ /obj/item/grenade/chem_grenade/metalfoam,
+ /obj/item/grenade/chem_grenade/smart_metal_foam
+ ))
+
/obj/item/storage/belt/grenade
name = "grenadier belt"
desc = "A belt for holding grenades."
@@ -517,12 +566,15 @@
/obj/item/grenade/chem_grenade,
/obj/item/lightreplacer,
/obj/item/flashlight,
+ /obj/item/reagent_containers/glass/beaker,
+ /obj/item/reagent_containers/glass/bottle,
/obj/item/reagent_containers/spray,
/obj/item/soap,
/obj/item/holosign_creator,
/obj/item/key/janitor,
/obj/item/clothing/gloves,
/obj/item/melee/flyswatter,
+ /obj/item/paint/paint_remover,
/obj/item/assembly/mousetrap
))
@@ -541,6 +593,22 @@
/obj/item/ammo_casing/shotgun
))
+/obj/item/storage/belt/bandolier/durathread
+ name = "durathread bandolier"
+ desc = "An double stacked bandolier made out of durathread."
+ icon_state = "bandolier-durathread"
+ item_state = "bandolier-durathread"
+ resistance_flags = FIRE_PROOF
+
+/obj/item/storage/belt/bandolier/durathread/ComponentInitialize()
+ . = ..()
+ GET_COMPONENT(STR, /datum/component/storage)
+ STR.max_items = 32
+ STR.display_numerical_stacking = TRUE
+ STR.can_hold = typecacheof(list(
+ /obj/item/ammo_casing
+ ))
+
/obj/item/storage/belt/medolier
name = "medolier"
desc = "A medical bandolier for holding smartdarts."
@@ -653,6 +721,10 @@
icon_state = "sheath"
item_state = "sheath"
w_class = WEIGHT_CLASS_BULKY
+ content_overlays = TRUE
+ worn_overlays = TRUE
+ var/list/fitting_swords = list(/obj/item/melee/sabre, /obj/item/melee/baton/stunsword)
+ var/starting_sword = /obj/item/melee/sabre
/obj/item/storage/belt/sabre/ComponentInitialize()
. = ..()
@@ -660,35 +732,7 @@
STR.max_items = 1
STR.rustle_sound = FALSE
STR.max_w_class = WEIGHT_CLASS_BULKY
- STR.can_hold = typecacheof(list(
- /obj/item/melee/sabre
- ))
-
-/obj/item/storage/belt/sabre/rapier
- name = "rapier sheath"
- desc = "A black, thin sheath that looks to house only a long thin blade. Feels like its made of metal."
- icon_state = "rsheath"
- item_state = "rsheath"
- force = 5
- throwforce = 15
- block_chance = 30
- w_class = WEIGHT_CLASS_BULKY
- attack_verb = list("bashed", "slashes", "prods", "pokes")
-
-/obj/item/storage/belt/sabre/rapier/ComponentInitialize()
- . = ..()
- GET_COMPONENT(STR, /datum/component/storage)
- STR.max_items = 1
- STR.rustle_sound = FALSE
- STR.max_w_class = WEIGHT_CLASS_BULKY
- STR.can_hold = typecacheof(list(
- /obj/item/melee/rapier
- ))
-
-/obj/item/storage/belt/sabre/rapier/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
- if(attack_type == PROJECTILE_ATTACK)
- final_block_chance = 0 //To thin to block bullets
- return ..()
+ STR.can_hold = typecacheof(fitting_swords)
/obj/item/storage/belt/sabre/examine(mob/user)
..()
@@ -707,20 +751,28 @@
to_chat(user, "[src] is empty.")
/obj/item/storage/belt/sabre/update_icon()
- icon_state = initial(icon_state)
- item_state = initial(item_state)
- if(contents.len)
- icon_state += "-sabre"
- item_state += "-sabre"
- if(loc && isliving(loc))
+ . = ..()
+ if(isliving(loc))
var/mob/living/L = loc
L.regenerate_icons()
- ..()
/obj/item/storage/belt/sabre/PopulateContents()
- new /obj/item/melee/sabre(src)
- update_icon()
+ new starting_sword(src)
-/obj/item/storage/belt/sabre/rapier/PopulateContents()
- new /obj/item/melee/rapier(src)
- update_icon()
+/obj/item/storage/belt/sabre/rapier
+ name = "rapier sheath"
+ desc = "A black, thin sheath that looks to house only a long thin blade. Feels like its made of metal."
+ icon_state = "rsheath"
+ item_state = "rsheath"
+ force = 5
+ throwforce = 15
+ block_chance = 30
+ w_class = WEIGHT_CLASS_BULKY
+ attack_verb = list("bashed", "slashes", "prods", "pokes")
+ fitting_swords = list(/obj/item/melee/rapier)
+ starting_sword = /obj/item/melee/rapier
+
+/obj/item/storage/belt/sabre/rapier/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
+ if(attack_type == PROJECTILE_ATTACK)
+ final_block_chance = 0 //To thin to block bullets
+ return ..()
diff --git a/code/game/objects/items/storage/boxes.dm b/code/game/objects/items/storage/boxes.dm
index 4ff63ceeac..903c319644 100644
--- a/code/game/objects/items/storage/boxes.dm
+++ b/code/game/objects/items/storage/boxes.dm
@@ -1131,6 +1131,7 @@
name = "Nanotrasen MRE Ration Kit Menu 0"
desc = "A package containing food suspended in an outdated bluespace pocket which lasts for centuries. If you're lucky you may even be able to enjoy the meal without getting food poisoning."
icon_state = "mre"
+ illustration = null
var/can_expire = TRUE
var/spawner_chance = 2
var/expiration_date
@@ -1184,7 +1185,7 @@
/obj/item/storage/box/mre/menu3
name = "\improper Nanotrasen MRE Ration Kit Menu 3"
- desc = "The holy grail of MREs. This item contains the fabled MRE pizza and a sample of coffee instant type 2. Any NT employee lucky enough to get their hands on one of these is truly blessed."
+ desc = "The holy grail of MREs. This item contains the fabled MRE pizza, spicy nachos and a sample of coffee instant type 2. Any NT employee lucky enough to get their hands on one of these is truly blessed."
icon_state = "menu3"
can_expire = FALSE //always fresh, never expired.
spawner_chance = 1
@@ -1192,7 +1193,42 @@
/obj/item/storage/box/mre/menu3/PopulateContents()
new /obj/item/reagent_containers/food/snacks/pizzaslice/pepperoni(src)
new /obj/item/reagent_containers/food/snacks/breadslice/plain(src)
- new /obj/item/reagent_containers/food/snacks/cheesewedge(src)
+ new /obj/item/reagent_containers/food/snacks/cubannachos(src)
new /obj/item/reagent_containers/food/snacks/grown/chili(src)
new /obj/item/reagent_containers/food/drinks/coffee/type2(src)
new /obj/item/tank/internals/emergency_oxygen(src)
+
+/obj/item/storage/box/mre/menu4
+ name = "\improper Nanotrasen MRE Ration Kit Menu 4"
+
+/obj/item/storage/box/mre/menu4/safe
+ spawner_chance = 0
+ desc = "A package containing food suspended in a bluespace pocket capable of lasting till the end of time."
+ can_expire = FALSE
+
+/obj/item/storage/box/mre/menu4/PopulateContents()
+ if(prob(66))
+ new /obj/item/reagent_containers/food/snacks/salad/boiledrice(src)
+ else
+ new /obj/item/reagent_containers/food/snacks/salad/ricebowl(src)
+ new /obj/item/reagent_containers/food/snacks/burger/tofu(src)
+ new /obj/item/reagent_containers/food/snacks/salad/fruit(src)
+ new /obj/item/reagent_containers/food/snacks/cracker(src)
+ new /obj/item/tank/internals/emergency_oxygen(src)
+
+//Where do I put this?
+/obj/item/secbat
+ name = "Secbat box"
+ desc = "Contained inside is a secbat for use with law enforcement."
+ icon = 'icons/obj/storage.dmi'
+ icon_state = "box"
+ item_state = "syringe_kit"
+ lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi'
+
+/obj/item/secbat/attack_self(mob/user)
+ new /mob/living/simple_animal/hostile/retaliate/bat/secbat(user.loc)
+ to_chat(user, "You open the box, releasing the secbat!")
+ var/obj/item/stack/sheet/cardboard/I = new(user.drop_location())
+ qdel(src)
+ user.put_in_hands(I)
diff --git a/code/game/objects/items/storage/briefcase.dm b/code/game/objects/items/storage/briefcase.dm
index bca13f2a45..ed547bc17d 100644
--- a/code/game/objects/items/storage/briefcase.dm
+++ b/code/game/objects/items/storage/briefcase.dm
@@ -40,9 +40,18 @@
/obj/item/storage/briefcase/lawyer/family
name = "battered briefcase"
- desc = "An old briefcase, this one has seen better days in its time. It's clear they don't make them nowadays as good as they used to. Comes with an added belt clip!"
+ icon_state = "gbriefcase"
+ lefthand_file = 'icons/mob/inhands/equipment/briefcase_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/equipment/briefcase_righthand.dmi'
+ desc = "An old briefcase with a golden trim. It's clear they don't make them as good as they used to. Comes with an added belt clip!"
slot_flags = ITEM_SLOT_BELT
+/obj/item/storage/briefcase/lawyer/family/ComponentInitialize()
+ . = ..()
+ GET_COMPONENT(STR, /datum/component/storage)
+ STR.max_w_class = WEIGHT_CLASS_NORMAL
+ STR.max_combined_w_class = 14
+
/obj/item/storage/briefcase/lawyer/family/PopulateContents()
new /obj/item/stamp/law(src)
new /obj/item/pen/fountain(src)
diff --git a/code/game/objects/items/storage/firstaid.dm b/code/game/objects/items/storage/firstaid.dm
index e9b074d40c..312ef35430 100644
--- a/code/game/objects/items/storage/firstaid.dm
+++ b/code/game/objects/items/storage/firstaid.dm
@@ -1,365 +1,391 @@
-/* First aid storage
- * Contains:
- * First Aid Kits
- * Pill Bottles
- * Dice Pack (in a pill bottle)
- */
-
-/*
- * First Aid Kits
- */
-/obj/item/storage/firstaid
- name = "first-aid kit"
- desc = "It's an emergency medical kit for those serious boo-boos."
- icon_state = "firstaid"
- lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi'
- righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi'
- throw_speed = 3
- throw_range = 7
- var/empty = FALSE
-
-/obj/item/storage/firstaid/regular
- icon_state = "firstaid"
- desc = "A first aid kit with the ability to heal common types of injuries."
-
-/obj/item/storage/firstaid/regular/suicide_act(mob/living/carbon/user)
- user.visible_message("[user] begins giving [user.p_them()]self aids with \the [src]! It looks like [user.p_theyre()] trying to commit suicide!")
- return BRUTELOSS
-
-/obj/item/storage/firstaid/regular/PopulateContents()
- if(empty)
- return
- new /obj/item/stack/medical/gauze(src)
- new /obj/item/stack/medical/bruise_pack(src)
- new /obj/item/stack/medical/bruise_pack(src)
- new /obj/item/stack/medical/ointment(src)
- new /obj/item/stack/medical/ointment(src)
- new /obj/item/reagent_containers/hypospray/medipen(src)
- new /obj/item/healthanalyzer(src)
-
-/obj/item/storage/firstaid/ancient
- icon_state = "firstaid"
- desc = "A first aid kit with the ability to heal common types of injuries."
-
-/obj/item/storage/firstaid/ancient/PopulateContents()
- if(empty)
- return
- new /obj/item/stack/medical/gauze(src)
- new /obj/item/stack/medical/bruise_pack(src)
- new /obj/item/stack/medical/bruise_pack(src)
- new /obj/item/stack/medical/bruise_pack(src)
- new /obj/item/stack/medical/ointment(src)
- new /obj/item/stack/medical/ointment(src)
- new /obj/item/stack/medical/ointment(src)
-
-/obj/item/storage/firstaid/fire
- name = "burn treatment kit"
- desc = "A specialized medical kit for when the toxins lab -spontaneously- burns down."
- icon_state = "ointment"
- item_state = "firstaid-ointment"
-
-/obj/item/storage/firstaid/fire/suicide_act(mob/living/carbon/user)
- user.visible_message("[user] begins rubbing \the [src] against [user.p_them()]self! It looks like [user.p_theyre()] trying to start a fire!")
- return FIRELOSS
-
-/obj/item/storage/firstaid/fire/Initialize(mapload)
- . = ..()
- icon_state = pick("ointment","firefirstaid")
-
-/obj/item/storage/firstaid/fire/PopulateContents()
- if(empty)
- return
- for(var/i in 1 to 3)
- new /obj/item/reagent_containers/pill/patch/silver_sulf(src)
- new /obj/item/reagent_containers/pill/oxandrolone(src)
- new /obj/item/reagent_containers/pill/oxandrolone(src)
- new /obj/item/reagent_containers/hypospray/medipen(src)
- new /obj/item/healthanalyzer(src)
-
-/obj/item/storage/firstaid/toxin
- name = "toxin treatment kit"
- desc = "Used to treat toxic blood content and radiation poisoning."
- icon_state = "antitoxin"
- item_state = "firstaid-toxin"
-
-/obj/item/storage/firstaid/toxin/suicide_act(mob/living/carbon/user)
- user.visible_message("[user] begins licking the lead paint off \the [src]! It looks like [user.p_theyre()] trying to commit suicide!")
- return TOXLOSS
-
-/obj/item/storage/firstaid/toxin/Initialize(mapload)
- . = ..()
- icon_state = pick("antitoxin","antitoxfirstaid","antitoxfirstaid2","antitoxfirstaid3")
-
-/obj/item/storage/firstaid/toxin/PopulateContents()
- if(empty)
- return
- for(var/i in 1 to 4)
- new /obj/item/reagent_containers/syringe/charcoal(src)
- for(var/i in 1 to 2)
- new /obj/item/storage/pill_bottle/charcoal(src)
- new /obj/item/healthanalyzer(src)
-
-/obj/item/storage/firstaid/radbgone
- name = "radiation treatment kit"
- desc = "Used to treat minor toxic blood content and major radiation poisoning."
- icon_state = "antitoxin"
- item_state = "firstaid-toxin"
-
-/obj/item/storage/firstaid/radbgone/suicide_act(mob/living/carbon/user)
- user.visible_message("[user] begins licking the lead paint off \the [src]! It looks like [user.p_theyre()] trying to commit suicide!")
- return TOXLOSS
-
-/obj/item/storage/firstaid/radbgone/PopulateContents()
- if(empty)
- return
- if(prob(50))
- new /obj/item/reagent_containers/pill/mutarad(src)
- if(prob(80))
- new /obj/item/reagent_containers/pill/antirad_plus(src)
- new /obj/item/reagent_containers/syringe/charcoal(src)
- new /obj/item/storage/pill_bottle/charcoal(src)
- new /obj/item/reagent_containers/pill/mutadone(src)
- new /obj/item/reagent_containers/pill/antirad(src)
- new /obj/item/reagent_containers/food/drinks/bottle/vodka(src)
- new /obj/item/healthanalyzer(src)
-
-
-/obj/item/storage/firstaid/o2
- name = "oxygen deprivation treatment kit"
- desc = "A box full of oxygen goodies."
- icon_state = "o2"
- item_state = "firstaid-o2"
-
-/obj/item/storage/firstaid/o2/suicide_act(mob/living/carbon/user)
- user.visible_message("[user] begins hitting [user.p_their()] neck with \the [src]! It looks like [user.p_theyre()] trying to commit suicide!")
- return OXYLOSS
-
-/obj/item/storage/firstaid/o2/PopulateContents()
- if(empty)
- return
- for(var/i in 1 to 4)
- new /obj/item/reagent_containers/pill/salbutamol(src)
- new /obj/item/reagent_containers/hypospray/medipen(src)
- new /obj/item/reagent_containers/hypospray/medipen(src)
- new /obj/item/healthanalyzer(src)
-
-/obj/item/storage/firstaid/brute
- name = "brute trauma treatment kit"
- desc = "A first aid kit for when you get toolboxed."
- icon_state = "brute"
- item_state = "firstaid-brute"
-
-/obj/item/storage/firstaid/brute/suicide_act(mob/living/carbon/user)
- user.visible_message("[user] begins beating [user.p_them()]self over the head with \the [src]! It looks like [user.p_theyre()] trying to commit suicide!")
- return BRUTELOSS
-
-/obj/item/storage/firstaid/brute/PopulateContents()
- if(empty)
- return
- for(var/i in 1 to 4)
- new /obj/item/reagent_containers/pill/patch/styptic(src)
- new /obj/item/stack/medical/gauze(src)
- new /obj/item/stack/medical/gauze(src)
- new /obj/item/healthanalyzer(src)
-
-/obj/item/storage/firstaid/tactical
- name = "combat medical kit"
- desc = "I hope you've got insurance."
- icon_state = "bezerk"
-
-/obj/item/storage/firstaid/tactical/ComponentInitialize()
- . = ..()
- GET_COMPONENT(STR, /datum/component/storage)
- STR.max_w_class = WEIGHT_CLASS_NORMAL
-
-/obj/item/storage/firstaid/tactical/PopulateContents()
- if(empty)
- return
- new /obj/item/stack/medical/gauze(src)
- new /obj/item/defibrillator/compact/combat/loaded(src)
- new /obj/item/reagent_containers/hypospray/combat(src)
- new /obj/item/reagent_containers/pill/patch/styptic(src)
- new /obj/item/reagent_containers/pill/patch/silver_sulf(src)
- new /obj/item/reagent_containers/syringe/lethal/choral(src)
- new /obj/item/clothing/glasses/hud/health/night(src)
-
-/*
- * Pill Bottles
- */
-
-/obj/item/storage/pill_bottle
- name = "pill bottle"
- desc = "It's an airtight container for storing medication."
- icon_state = "pill_canister"
- icon = 'icons/obj/chemical.dmi'
- item_state = "contsolid"
- lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi'
- righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi'
- w_class = WEIGHT_CLASS_SMALL
-
-/obj/item/storage/pill_bottle/ComponentInitialize()
- . = ..()
- GET_COMPONENT(STR, /datum/component/storage)
- STR.allow_quick_gather = TRUE
- STR.click_gather = TRUE
- STR.can_hold = typecacheof(list(/obj/item/reagent_containers/pill, /obj/item/dice))
-
-/obj/item/storage/pill_bottle/suicide_act(mob/user)
- user.visible_message("[user] is trying to get the cap off [src]! It looks like [user.p_theyre()] trying to commit suicide!")
- return (TOXLOSS)
-
-/obj/item/storage/pill_bottle/charcoal
- name = "bottle of charcoal pills"
- desc = "Contains pills used to counter toxins."
-
-/obj/item/storage/pill_bottle/charcoal/PopulateContents()
- for(var/i in 1 to 7)
- new /obj/item/reagent_containers/pill/charcoal(src)
-
-/obj/item/storage/pill_bottle/antirad
- name = "bottle of charcoal pills"
- desc = "Contains pills used to counter radiation poisoning."
-
-/obj/item/storage/pill_bottle/anitrad/PopulateContents()
- for(var/i in 1 to 5)
- new /obj/item/reagent_containers/pill/antirad(src)
-
-/obj/item/storage/pill_bottle/epinephrine
- name = "bottle of epinephrine pills"
- desc = "Contains pills used to stabilize patients."
-
-/obj/item/storage/pill_bottle/epinephrine/PopulateContents()
- for(var/i in 1 to 7)
- new /obj/item/reagent_containers/pill/epinephrine(src)
-
-/obj/item/storage/pill_bottle/mutadone
- name = "bottle of mutadone pills"
- desc = "Contains pills used to treat genetic abnormalities."
-
-/obj/item/storage/pill_bottle/mutadone/PopulateContents()
- for(var/i in 1 to 7)
- new /obj/item/reagent_containers/pill/mutadone(src)
-
-/obj/item/storage/pill_bottle/mannitol
- name = "bottle of mannitol pills"
- desc = "Contains pills used to treat brain damage."
-
-/obj/item/storage/pill_bottle/mannitol/PopulateContents()
- for(var/i in 1 to 7)
- new /obj/item/reagent_containers/pill/mannitol(src)
-
-/obj/item/storage/pill_bottle/stimulant
- name = "bottle of stimulant pills"
- desc = "Guaranteed to give you that extra burst of energy during a long shift!"
-
-/obj/item/storage/pill_bottle/stimulant/PopulateContents()
- for(var/i in 1 to 5)
- new /obj/item/reagent_containers/pill/stimulant(src)
-
-/obj/item/storage/pill_bottle/mining
- name = "bottle of patches"
- desc = "Contains patches used to treat brute and burn damage."
-
-/obj/item/storage/pill_bottle/mining/PopulateContents()
- new /obj/item/reagent_containers/pill/patch/silver_sulf(src)
- for(var/i in 1 to 3)
- new /obj/item/reagent_containers/pill/patch/styptic(src)
-
-/obj/item/storage/pill_bottle/zoom
- name = "suspicious pill bottle"
- desc = "The label is pretty old and almost unreadable, you recognize some chemical compounds."
-
-/obj/item/storage/pill_bottle/zoom/PopulateContents()
- for(var/i in 1 to 5)
- new /obj/item/reagent_containers/pill/zoom(src)
-
-/obj/item/storage/pill_bottle/happy
- name = "suspicious pill bottle"
- desc = "There is a smiley on the top."
-
-/obj/item/storage/pill_bottle/happy/PopulateContents()
- for(var/i in 1 to 5)
- new /obj/item/reagent_containers/pill/happy(src)
-
-/obj/item/storage/pill_bottle/lsd
- name = "suspicious pill bottle"
- desc = "There is a badly drawn thing with the shape of a mushroom."
-
-/obj/item/storage/pill_bottle/lsd/PopulateContents()
- for(var/i in 1 to 5)
- new /obj/item/reagent_containers/pill/lsd(src)
-
-/obj/item/storage/pill_bottle/aranesp
- name = "suspicious pill bottle"
- desc = "The label says 'gotta go fast'."
-
-/obj/item/storage/pill_bottle/aranesp/PopulateContents()
- for(var/i in 1 to 5)
- new /obj/item/reagent_containers/pill/aranesp(src)
-
-/obj/item/storage/pill_bottle/antirad_plus
- name = "anti radiation deluxe pill bottle"
- desc = "The label says 'Med-Co branded pills'."
-
-/obj/item/storage/pill_bottle/antirad_plus/PopulateContents()
- for(var/i in 1 to 7)
- new /obj/item/reagent_containers/pill/antirad_plus(src)
-
-/obj/item/storage/pill_bottle/mutarad
- name = "radiation treatment deluxe pill bottle"
- desc = "The label says 'Med-Co branded pills' and below that 'Contains Mutadone in each pill!`."
-
-/obj/item/storage/pill_bottle/mutarad/PopulateContents()
- for(var/i in 1 to 7)
- new /obj/item/reagent_containers/pill/mutarad(src)
-
-/obj/item/storage/pill_bottle/penis_enlargement
- name = "penis enlargement pills"
- desc = "You want penis enlargement pills?"
-
-/obj/item/storage/pill_bottle/penis_enlargement/PopulateContents()
- for(var/i in 1 to 7)
- new /obj/item/reagent_containers/pill/penis_enlargement(src)
-
-/////////////
-//Organ Box//
-/////////////
-
-/obj/item/storage/belt/organbox
- name = "Organ Storge"
- desc = "A compact box that helps hold massive amounts of implants, organs, and some tools. Has a belt clip for easy carrying"
- w_class = WEIGHT_CLASS_BULKY
- icon = 'icons/obj/mysterybox.dmi'
- icon_state = "organbox_open"
- lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi'
- righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi'
- throw_speed = 1
- throw_range = 1
-
-/obj/item/storage/belt/organbox/ComponentInitialize()
- . = ..()
- GET_COMPONENT(STR, /datum/component/storage)
- STR.max_items = 16
- STR.max_w_class = WEIGHT_CLASS_BULKY
- STR.max_combined_w_class = 20
- STR.can_hold = typecacheof(list(
- /obj/item/storage/pill_bottle,
- /obj/item/reagent_containers/hypospray,
- /obj/item/healthanalyzer,
- /obj/item/reagent_containers/syringe,
- /obj/item/clothing/glasses/hud/health,
- /obj/item/hemostat,
- /obj/item/scalpel,
- /obj/item/retractor,
- /obj/item/cautery,
- /obj/item/surgical_drapes,
- /obj/item/autosurgeon,
- /obj/item/organ,
- /obj/item/implant,
- /obj/item/implantpad,
- /obj/item/implantcase,
- /obj/item/implanter,
- /obj/item/circuitboard/computer/operating,
- /obj/item/stack/sheet/mineral/silver,
- /obj/item/organ_storage
- ))
+
+/* First aid storage
+ * Contains:
+ * First Aid Kits
+ * Pill Bottles
+ * Dice Pack (in a pill bottle)
+ */
+
+/*
+ * First Aid Kits
+ */
+/obj/item/storage/firstaid
+ name = "first-aid kit"
+ desc = "It's an emergency medical kit for those serious boo-boos."
+ icon_state = "firstaid"
+ lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi'
+ throw_speed = 3
+ throw_range = 7
+ var/empty = FALSE
+
+/obj/item/storage/firstaid/regular
+ icon_state = "firstaid"
+ desc = "A first aid kit with the ability to heal common types of injuries."
+
+/obj/item/storage/firstaid/regular/suicide_act(mob/living/carbon/user)
+ user.visible_message("[user] begins giving [user.p_them()]self aids with \the [src]! It looks like [user.p_theyre()] trying to commit suicide!")
+ return BRUTELOSS
+
+/obj/item/storage/firstaid/regular/PopulateContents()
+ if(empty)
+ return
+ new /obj/item/stack/medical/gauze(src)
+ new /obj/item/stack/medical/bruise_pack(src)
+ new /obj/item/stack/medical/bruise_pack(src)
+ new /obj/item/stack/medical/ointment(src)
+ new /obj/item/stack/medical/ointment(src)
+ new /obj/item/reagent_containers/hypospray/medipen(src)
+ new /obj/item/healthanalyzer(src)
+
+/obj/item/storage/firstaid/ancient
+ icon_state = "firstaid"
+ desc = "A first aid kit with the ability to heal common types of injuries."
+
+/obj/item/storage/firstaid/ancient/PopulateContents()
+ if(empty)
+ return
+ new /obj/item/stack/medical/gauze(src)
+ new /obj/item/stack/medical/bruise_pack(src)
+ new /obj/item/stack/medical/bruise_pack(src)
+ new /obj/item/stack/medical/bruise_pack(src)
+ new /obj/item/stack/medical/ointment(src)
+ new /obj/item/stack/medical/ointment(src)
+ new /obj/item/stack/medical/ointment(src)
+
+/obj/item/storage/firstaid/fire
+ name = "burn treatment kit"
+ desc = "A specialized medical kit for when the toxins lab -spontaneously- burns down."
+ icon_state = "ointment"
+ item_state = "firstaid-ointment"
+
+/obj/item/storage/firstaid/fire/suicide_act(mob/living/carbon/user)
+ user.visible_message("[user] begins rubbing \the [src] against [user.p_them()]self! It looks like [user.p_theyre()] trying to start a fire!")
+ return FIRELOSS
+
+/obj/item/storage/firstaid/fire/Initialize(mapload)
+ . = ..()
+ icon_state = pick("ointment","firefirstaid")
+
+/obj/item/storage/firstaid/fire/PopulateContents()
+ if(empty)
+ return
+ for(var/i in 1 to 3)
+ new /obj/item/reagent_containers/pill/patch/silver_sulf(src)
+ new /obj/item/reagent_containers/pill/oxandrolone(src)
+ new /obj/item/reagent_containers/pill/oxandrolone(src)
+ new /obj/item/reagent_containers/hypospray/medipen(src)
+ new /obj/item/healthanalyzer(src)
+
+/obj/item/storage/firstaid/toxin
+ name = "toxin treatment kit"
+ desc = "Used to treat toxic blood content and radiation poisoning."
+ icon_state = "antitoxin"
+ item_state = "firstaid-toxin"
+
+/obj/item/storage/firstaid/toxin/suicide_act(mob/living/carbon/user)
+ user.visible_message("[user] begins licking the lead paint off \the [src]! It looks like [user.p_theyre()] trying to commit suicide!")
+ return TOXLOSS
+
+/obj/item/storage/firstaid/toxin/Initialize(mapload)
+ . = ..()
+ icon_state = pick("antitoxin","antitoxfirstaid","antitoxfirstaid2","antitoxfirstaid3")
+
+/obj/item/storage/firstaid/toxin/PopulateContents()
+ if(empty)
+ return
+ for(var/i in 1 to 4)
+ new /obj/item/reagent_containers/syringe/charcoal(src)
+ for(var/i in 1 to 2)
+ new /obj/item/storage/pill_bottle/charcoal(src)
+ new /obj/item/healthanalyzer(src)
+
+/obj/item/storage/firstaid/radbgone
+ name = "radiation treatment kit"
+ desc = "Used to treat minor toxic blood content and major radiation poisoning."
+ icon_state = "antitoxin"
+ item_state = "firstaid-toxin"
+
+/obj/item/storage/firstaid/radbgone/suicide_act(mob/living/carbon/user)
+ user.visible_message("[user] begins licking the lead paint off \the [src]! It looks like [user.p_theyre()] trying to commit suicide!")
+ return TOXLOSS
+
+/obj/item/storage/firstaid/radbgone/PopulateContents()
+ if(empty)
+ return
+ if(prob(50))
+ new /obj/item/reagent_containers/pill/mutarad(src)
+ if(prob(80))
+ new /obj/item/reagent_containers/pill/antirad_plus(src)
+ new /obj/item/reagent_containers/syringe/charcoal(src)
+ new /obj/item/storage/pill_bottle/charcoal(src)
+ new /obj/item/reagent_containers/pill/mutadone(src)
+ new /obj/item/reagent_containers/pill/antirad(src)
+ new /obj/item/reagent_containers/food/drinks/bottle/vodka(src)
+ new /obj/item/healthanalyzer(src)
+
+
+/obj/item/storage/firstaid/o2
+ name = "oxygen deprivation treatment kit"
+ desc = "A box full of oxygen goodies."
+ icon_state = "o2"
+ item_state = "firstaid-o2"
+
+/obj/item/storage/firstaid/o2/suicide_act(mob/living/carbon/user)
+ user.visible_message("[user] begins hitting [user.p_their()] neck with \the [src]! It looks like [user.p_theyre()] trying to commit suicide!")
+ return OXYLOSS
+
+/obj/item/storage/firstaid/o2/PopulateContents()
+ if(empty)
+ return
+ for(var/i in 1 to 4)
+ new /obj/item/reagent_containers/pill/salbutamol(src)
+ new /obj/item/reagent_containers/hypospray/medipen(src)
+ new /obj/item/reagent_containers/hypospray/medipen(src)
+ new /obj/item/healthanalyzer(src)
+
+/obj/item/storage/firstaid/brute
+ name = "brute trauma treatment kit"
+ desc = "A first aid kit for when you get toolboxed."
+ icon_state = "brute"
+ item_state = "firstaid-brute"
+
+/obj/item/storage/firstaid/brute/suicide_act(mob/living/carbon/user)
+ user.visible_message("[user] begins beating [user.p_them()]self over the head with \the [src]! It looks like [user.p_theyre()] trying to commit suicide!")
+ return BRUTELOSS
+
+/obj/item/storage/firstaid/brute/PopulateContents()
+ if(empty)
+ return
+ for(var/i in 1 to 4)
+ new /obj/item/reagent_containers/pill/patch/styptic(src)
+ new /obj/item/stack/medical/gauze(src)
+ new /obj/item/stack/medical/gauze(src)
+ new /obj/item/healthanalyzer(src)
+
+/obj/item/storage/firstaid/tactical
+ name = "combat medical kit"
+ desc = "I hope you've got insurance."
+ icon_state = "bezerk"
+
+/obj/item/storage/firstaid/tactical/ComponentInitialize()
+ . = ..()
+ GET_COMPONENT(STR, /datum/component/storage)
+ STR.max_w_class = WEIGHT_CLASS_NORMAL
+
+/obj/item/storage/firstaid/tactical/PopulateContents()
+ if(empty)
+ return
+ new /obj/item/stack/medical/gauze(src)
+ new /obj/item/defibrillator/compact/combat/loaded(src)
+ new /obj/item/reagent_containers/hypospray/combat(src)
+ new /obj/item/reagent_containers/pill/patch/styptic(src)
+ new /obj/item/reagent_containers/pill/patch/silver_sulf(src)
+ new /obj/item/reagent_containers/syringe/lethal/choral(src)
+ new /obj/item/clothing/glasses/hud/health/night(src)
+
+/*
+ * Pill Bottles
+ */
+
+/obj/item/storage/pill_bottle
+ name = "pill bottle"
+ desc = "It's an airtight container for storing medication."
+ icon_state = "pill_canister"
+ icon = 'icons/obj/chemical.dmi'
+ item_state = "contsolid"
+ lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi'
+ w_class = WEIGHT_CLASS_SMALL
+
+/obj/item/storage/pill_bottle/ComponentInitialize()
+ . = ..()
+ GET_COMPONENT(STR, /datum/component/storage)
+ STR.allow_quick_gather = TRUE
+ STR.click_gather = TRUE
+ STR.can_hold = typecacheof(list(/obj/item/reagent_containers/pill, /obj/item/dice))
+
+/obj/item/storage/pill_bottle/suicide_act(mob/user)
+ user.visible_message("[user] is trying to get the cap off [src]! It looks like [user.p_theyre()] trying to commit suicide!")
+ return (TOXLOSS)
+
+/obj/item/storage/pill_bottle/charcoal
+ name = "bottle of charcoal pills"
+ desc = "Contains pills used to counter toxins."
+
+/obj/item/storage/pill_bottle/charcoal/PopulateContents()
+ for(var/i in 1 to 7)
+ new /obj/item/reagent_containers/pill/charcoal(src)
+
+/obj/item/storage/pill_bottle/antirad
+ name = "bottle of charcoal pills"
+ desc = "Contains pills used to counter radiation poisoning."
+
+/obj/item/storage/pill_bottle/anitrad/PopulateContents()
+ for(var/i in 1 to 5)
+ new /obj/item/reagent_containers/pill/antirad(src)
+
+/obj/item/storage/pill_bottle/epinephrine
+ name = "bottle of epinephrine pills"
+ desc = "Contains pills used to stabilize patients."
+
+/obj/item/storage/pill_bottle/epinephrine/PopulateContents()
+ for(var/i in 1 to 7)
+ new /obj/item/reagent_containers/pill/epinephrine(src)
+
+/obj/item/storage/pill_bottle/mutadone
+ name = "bottle of mutadone pills"
+ desc = "Contains pills used to treat genetic abnormalities."
+
+/obj/item/storage/pill_bottle/mutadone/PopulateContents()
+ for(var/i in 1 to 7)
+ new /obj/item/reagent_containers/pill/mutadone(src)
+
+/obj/item/storage/pill_bottle/mannitol
+ name = "bottle of mannitol pills"
+ desc = "Contains pills used to treat brain damage."
+
+/obj/item/storage/pill_bottle/mannitol/PopulateContents()
+ for(var/i in 1 to 7)
+ new /obj/item/reagent_containers/pill/mannitol(src)
+
+/obj/item/storage/pill_bottle/stimulant
+ name = "bottle of stimulant pills"
+ desc = "Guaranteed to give you that extra burst of energy during a long shift!"
+
+/obj/item/storage/pill_bottle/stimulant/PopulateContents()
+ for(var/i in 1 to 5)
+ new /obj/item/reagent_containers/pill/stimulant(src)
+
+/obj/item/storage/pill_bottle/mining
+ name = "bottle of patches"
+ desc = "Contains patches used to treat brute and burn damage."
+
+/obj/item/storage/pill_bottle/mining/PopulateContents()
+ new /obj/item/reagent_containers/pill/patch/silver_sulf(src)
+ for(var/i in 1 to 3)
+ new /obj/item/reagent_containers/pill/patch/styptic(src)
+
+/obj/item/storage/pill_bottle/zoom
+ name = "suspicious pill bottle"
+ desc = "The label is pretty old and almost unreadable, you recognize some chemical compounds."
+
+/obj/item/storage/pill_bottle/zoom/PopulateContents()
+ for(var/i in 1 to 5)
+ new /obj/item/reagent_containers/pill/zoom(src)
+
+/obj/item/storage/pill_bottle/happy
+ name = "suspicious pill bottle"
+ desc = "There is a smiley on the top."
+
+/obj/item/storage/pill_bottle/happy/PopulateContents()
+ for(var/i in 1 to 5)
+ new /obj/item/reagent_containers/pill/happy(src)
+
+/obj/item/storage/pill_bottle/lsd
+ name = "suspicious pill bottle"
+ desc = "There is a badly drawn thing with the shape of a mushroom."
+
+/obj/item/storage/pill_bottle/lsd/PopulateContents()
+ for(var/i in 1 to 5)
+ new /obj/item/reagent_containers/pill/lsd(src)
+
+/obj/item/storage/pill_bottle/aranesp
+ name = "suspicious pill bottle"
+ desc = "The label says 'gotta go fast'."
+
+/obj/item/storage/pill_bottle/aranesp/PopulateContents()
+ for(var/i in 1 to 5)
+ new /obj/item/reagent_containers/pill/aranesp(src)
+
+/obj/item/storage/pill_bottle/psicodine
+ name = "bottle of psicodine pills"
+ desc = "Contains pills used to treat mental distress and traumas."
+
+/obj/item/storage/pill_bottle/psicodine/PopulateContents()
+ for(var/i in 1 to 7)
+ new /obj/item/reagent_containers/pill/psicodine(src)
+
+/obj/item/storage/pill_bottle/happiness
+ name = "happiness pill bottle"
+ desc = "The label is long gone, in its place an 'H' written with a marker."
+
+/obj/item/storage/pill_bottle/happiness/PopulateContents()
+ for(var/i in 1 to 5)
+ new /obj/item/reagent_containers/pill/happiness(src)
+
+/obj/item/storage/pill_bottle/antirad_plus
+ name = "anti radiation deluxe pill bottle"
+ desc = "The label says 'Med-Co branded pills'."
+
+/obj/item/storage/pill_bottle/antirad_plus/PopulateContents()
+ for(var/i in 1 to 7)
+ new /obj/item/reagent_containers/pill/antirad_plus(src)
+
+/obj/item/storage/pill_bottle/mutarad
+ name = "radiation treatment deluxe pill bottle"
+ desc = "The label says 'Med-Co branded pills' and below that 'Contains Mutadone in each pill!`."
+
+/obj/item/storage/pill_bottle/mutarad/PopulateContents()
+ for(var/i in 1 to 7)
+ new /obj/item/reagent_containers/pill/mutarad(src)
+
+/obj/item/storage/pill_bottle/penis_enlargement
+ name = "penis enlargement pills"
+ desc = "You want penis enlargement pills?"
+
+/obj/item/storage/pill_bottle/penis_enlargement/PopulateContents()
+ for(var/i in 1 to 7)
+ new /obj/item/reagent_containers/pill/penis_enlargement(src)
+
+/obj/item/storage/pill_bottle/breast_enlargement
+ name = "breast enlargement pills"
+ desc = "Made by Fermichem - They have a woman with breasts larger than she is on them. The warming states not to take more than 10u at a time."
+
+/obj/item/storage/pill_bottle/breast_enlargement/PopulateContents()
+ for(var/i in 1 to 7)
+ new /obj/item/reagent_containers/pill/breast_enlargement(src)
+
+/////////////
+//Organ Box//
+/////////////
+
+/obj/item/storage/belt/organbox
+ name = "Organ Storge"
+ desc = "A compact box that helps hold massive amounts of implants, organs, and some tools. Has a belt clip for easy carrying"
+ w_class = WEIGHT_CLASS_BULKY
+ icon = 'icons/obj/mysterybox.dmi'
+ icon_state = "organbox_open"
+ lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi'
+ throw_speed = 1
+ throw_range = 1
+
+/obj/item/storage/belt/organbox/ComponentInitialize()
+ . = ..()
+ GET_COMPONENT(STR, /datum/component/storage)
+ STR.max_items = 16
+ STR.max_w_class = WEIGHT_CLASS_BULKY
+ STR.max_combined_w_class = 20
+ STR.can_hold = typecacheof(list(
+ /obj/item/storage/pill_bottle,
+ /obj/item/reagent_containers/hypospray,
+ /obj/item/healthanalyzer,
+ /obj/item/reagent_containers/syringe,
+ /obj/item/clothing/glasses/hud/health,
+ /obj/item/hemostat,
+ /obj/item/scalpel,
+ /obj/item/retractor,
+ /obj/item/cautery,
+ /obj/item/surgical_drapes,
+ /obj/item/autosurgeon,
+ /obj/item/organ,
+ /obj/item/implant,
+ /obj/item/implantpad,
+ /obj/item/implantcase,
+ /obj/item/implanter,
+ /obj/item/circuitboard/computer/operating,
+ /obj/item/stack/sheet/mineral/silver,
+ /obj/item/organ_storage
+ ))
+
diff --git a/code/game/objects/items/storage/storage.dm b/code/game/objects/items/storage/storage.dm
index 7c2694016b..b69567a2a5 100644
--- a/code/game/objects/items/storage/storage.dm
+++ b/code/game/objects/items/storage/storage.dm
@@ -16,7 +16,7 @@
AddComponent(component_type)
/obj/item/storage/AllowDrop()
- return TRUE
+ return FALSE
/obj/item/storage/contents_explosion(severity, target)
for(var/atom/A in contents)
diff --git a/code/game/objects/items/storage/uplink_kits.dm b/code/game/objects/items/storage/uplink_kits.dm
index a6a3cea373..6e41527b24 100644
--- a/code/game/objects/items/storage/uplink_kits.dm
+++ b/code/game/objects/items/storage/uplink_kits.dm
@@ -132,7 +132,7 @@
new /obj/item/card/emag(src) // 6 tc
if("ninja") // 40~ tc worth
- new /obj/item/katana(src) // Unique , basicly a better esword. 10 tc?
+ new /obj/item/katana(src) // Unique , basicly a better esword. 10 tc?
new /obj/item/implanter/adrenalin(src) // 8 tc
new /obj/item/throwing_star(src) // ~5 tc for all 6
new /obj/item/throwing_star(src)
@@ -294,6 +294,7 @@
new /obj/item/radio/headset/chameleon(src)
new /obj/item/stamp/chameleon(src)
new /obj/item/pda/chameleon(src)
+ new /obj/item/clothing/neck/cloak/chameleon(src)
//5*(2*4) = 5*8 = 45, 45 damage if you hit one person with all 5 stars.
//Not counting the damage it will do while embedded (2*4 = 8, at 15% chance)
diff --git a/code/game/objects/items/tanks/tanks.dm b/code/game/objects/items/tanks/tanks.dm
index 1245b7de94..d409e40575 100644
--- a/code/game/objects/items/tanks/tanks.dm
+++ b/code/game/objects/items/tanks/tanks.dm
@@ -23,7 +23,7 @@
toggle_internals(user)
/obj/item/tank/proc/toggle_internals(mob/user)
- var/mob/living/carbon/human/H = user
+ var/mob/living/carbon/H = user
if(!istype(H))
return
@@ -33,13 +33,19 @@
H.update_internals_hud_icon(0)
else
if(!H.getorganslot(ORGAN_SLOT_BREATHING_TUBE))
- if(!H.wear_mask)
- to_chat(H, "You need a mask!")
- return
- if(H.wear_mask.mask_adjusted)
- H.wear_mask.adjustmask(H)
- if(!(H.wear_mask.clothing_flags & MASKINTERNALS))
- to_chat(H, "[H.wear_mask] can't use [src]!")
+ var/obj/item/clothing/check
+ var/internals = FALSE
+
+ for(check in GET_INTERNAL_SLOTS(H))
+ if(istype(check, /obj/item/clothing/mask))
+ var/obj/item/clothing/mask/M = check
+ if(M.mask_adjusted)
+ M.adjustmask(H)
+ if(CHECK_BITFIELD(check.clothing_flags, ALLOWINTERNALS))
+ internals = TRUE
+
+ if(!internals)
+ to_chat(H, "You are not wearing an internals mask!")
return
if(H.internal)
diff --git a/code/game/objects/items/teleprod.dm b/code/game/objects/items/teleprod.dm
index 341c85fa1c..40392c19c3 100644
--- a/code/game/objects/items/teleprod.dm
+++ b/code/game/objects/items/teleprod.dm
@@ -10,7 +10,7 @@
. = ..()
if(!. || !istype(M) || M.anchored)
return
- do_teleport(M, get_turf(M), 15)
+ do_teleport(M, get_turf(M), 15, channel = TELEPORT_CHANNEL_BLUESPACE)
/obj/item/melee/baton/cattleprod/teleprod/clowning_around(mob/living/user)
user.visible_message("[user] accidentally hits [user.p_them()]self with [src]!", \
@@ -18,7 +18,7 @@
SEND_SIGNAL(user, COMSIG_LIVING_MINOR_SHOCK)
user.Knockdown(stunforce*3)
playsound(loc, 'sound/weapons/egloves.ogg', 50, 1, -1)
- if(do_teleport(user, get_turf(user), 50))
+ if(do_teleport(user, get_turf(user), 50, channel = TELEPORT_CHANNEL_BLUESPACE))
deductcharge(hitcost)
else
deductcharge(hitcost * 0.25)
diff --git a/code/game/objects/items/tools/crowbar.dm b/code/game/objects/items/tools/crowbar.dm
index 97375221d4..70bfebb799 100644
--- a/code/game/objects/items/tools/crowbar.dm
+++ b/code/game/objects/items/tools/crowbar.dm
@@ -90,4 +90,12 @@
var/obj/item/wirecutters/power/cutjaws = new /obj/item/wirecutters/power(drop_location())
to_chat(user, "You attach the cutting jaws to [src].")
qdel(src)
- user.put_in_active_hand(cutjaws)
\ No newline at end of file
+ user.put_in_active_hand(cutjaws)
+
+/obj/item/crowbar/advanced
+ name = "advanced crowbar"
+ desc = "A scientist's almost successful reproduction of an abductor's crowbar, it uses the same technology combined with a handle that can't quite hold it."
+ icon = 'icons/obj/advancedtools.dmi'
+ usesound = 'sound/weapons/sonic_jackhammer.ogg'
+ icon_state = "crowbar"
+ toolspeed = 0.2
\ No newline at end of file
diff --git a/code/game/objects/items/tools/screwdriver.dm b/code/game/objects/items/tools/screwdriver.dm
index e5808de088..68946f73cd 100644
--- a/code/game/objects/items/tools/screwdriver.dm
+++ b/code/game/objects/items/tools/screwdriver.dm
@@ -141,4 +141,14 @@
name = "powered screwdriver"
desc = "An electrical screwdriver, designed to be both precise and quick."
usesound = 'sound/items/drill_use.ogg'
- toolspeed = 0.5
\ No newline at end of file
+ toolspeed = 0.5
+
+/obj/item/screwdriver/advanced
+ name = "advanced screwdriver"
+ desc = "A classy silver screwdriver with an alien alloy tip, it works almost as well as the real thing."
+ icon = 'icons/obj/advancedtools.dmi'
+ icon_state = "screwdriver_a"
+ item_state = "screwdriver_nuke"
+ usesound = 'sound/items/pshoom.ogg'
+ toolspeed = 0.2
+ random_color = FALSE
\ No newline at end of file
diff --git a/code/game/objects/items/tools/weldingtool.dm b/code/game/objects/items/tools/weldingtool.dm
index 718035a9a5..9b622a14c4 100644
--- a/code/game/objects/items/tools/weldingtool.dm
+++ b/code/game/objects/items/tools/weldingtool.dm
@@ -377,4 +377,18 @@
nextrefueltick = world.time + 10
reagents.add_reagent("welding_fuel", 1)
+/obj/item/weldingtool/advanced
+ name = "advanced welding tool"
+ desc = "A modern welding tool combined with an alien welding tool, it never runs out of fuel and works almost as fast."
+ icon = 'icons/obj/advancedtools.dmi'
+ icon_state = "welder"
+ toolspeed = 0.2
+ light_intensity = 0
+ change_icons = 0
+
+/obj/item/weldingtool/advanced/process()
+ if(get_fuel() <= max_fuel)
+ reagents.add_reagent("welding_fuel", 1)
+ ..()
+
#undef WELDER_FUEL_BURN_INTERVAL
diff --git a/code/game/objects/items/tools/wirecutters.dm b/code/game/objects/items/tools/wirecutters.dm
index 1a35196bd8..527891afdb 100644
--- a/code/game/objects/items/tools/wirecutters.dm
+++ b/code/game/objects/items/tools/wirecutters.dm
@@ -82,7 +82,6 @@
icon = 'icons/obj/abductor.dmi'
icon_state = "cutters"
toolspeed = 0.1
-
random_color = FALSE
/obj/item/wirecutters/cyborg
@@ -126,3 +125,11 @@
return
else
..()
+
+/obj/item/wirecutters/advanced
+ name = "advanced wirecutters"
+ desc = "A set of reproduction alien wirecutters, they have a silver handle with an exceedingly sharp blade."
+ icon = 'icons/obj/advancedtools.dmi'
+ icon_state = "cutters"
+ toolspeed = 0.2
+ random_color = FALSE
\ No newline at end of file
diff --git a/code/game/objects/items/tools/wrench.dm b/code/game/objects/items/tools/wrench.dm
index 4fd99e9adf..8ff960825a 100644
--- a/code/game/objects/items/tools/wrench.dm
+++ b/code/game/objects/items/tools/wrench.dm
@@ -112,4 +112,12 @@
user.dust()
- return OXYLOSS
\ No newline at end of file
+ return OXYLOSS
+
+/obj/item/wrench/advanced
+ name = "advanced wrench"
+ desc = "A wrench that uses the same magnetic technology that abductor tools use, but slightly more ineffeciently."
+ icon = 'icons/obj/advancedtools.dmi'
+ icon_state = "wrench"
+ usesound = 'sound/effects/empulse.ogg'
+ toolspeed = 0.2
\ No newline at end of file
diff --git a/code/game/objects/items/toys.dm b/code/game/objects/items/toys.dm
index 9ac5261e5f..46fabea8b0 100644
--- a/code/game/objects/items/toys.dm
+++ b/code/game/objects/items/toys.dm
@@ -30,6 +30,7 @@
throw_speed = 3
throw_range = 7
force = 0
+ total_mass = TOTAL_MASS_TINY_ITEM
/*
@@ -112,10 +113,6 @@
/obj/item/toy/syndicateballoon
name = "syndicate balloon"
desc = "There is a tag on the back that reads \"FUK NT!11!\"."
- throwforce = 0
- throw_speed = 3
- throw_range = 7
- force = 0
icon = 'icons/obj/items_and_weapons.dmi'
icon_state = "syndballoon"
item_state = "syndballoon"
@@ -225,6 +222,8 @@
w_class = WEIGHT_CLASS_SMALL
attack_verb = list("attacked", "struck", "hit")
var/hacked = FALSE
+ total_mass = 0.4
+ var/total_mass_on = TOTAL_MASS_TOY_SWORD
/obj/item/toy/sword/attack_self(mob/user)
active = !( active )
@@ -274,6 +273,9 @@
else
return ..()
+/obj/item/toy/sword/getweight()
+ return (active ? total_mass_on : total_mass) || w_class *1.25
+
/*
* Foam armblade
*/
@@ -327,12 +329,13 @@
force_unwielded = 0
force_wielded = 0
attack_verb = list("attacked", "struck", "hit")
+ total_mass_on = TOTAL_MASS_TOY_SWORD
/obj/item/twohanded/dualsaber/toy/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
- return 0
+ return FALSE
/obj/item/twohanded/dualsaber/toy/IsReflect()//Stops Toy Dualsabers from reflecting energy projectiles
- return 0
+ return FALSE
/obj/item/toy/katana
name = "replica katana"
@@ -346,6 +349,7 @@
slot_flags = ITEM_SLOT_BELT | ITEM_SLOT_BACK
force = 5
throwforce = 5
+ total_mass = null
w_class = WEIGHT_CLASS_NORMAL
attack_verb = list("attacked", "slashed", "stabbed", "sliced")
hitsound = 'sound/weapons/bladeslice.ogg'
diff --git a/code/game/objects/items/twohanded.dm b/code/game/objects/items/twohanded.dm
index bf63a96f05..781a82513e 100644
--- a/code/game/objects/items/twohanded.dm
+++ b/code/game/objects/items/twohanded.dm
@@ -28,6 +28,8 @@
var/force_wielded = 0
var/wieldsound = null
var/unwieldsound = null
+ var/slowdown_wielded = 0
+ item_flags = SLOWS_WHILE_IN_HAND
/obj/item/twohanded/proc/unwield(mob/living/carbon/user, show_message = TRUE)
if(!wielded || !user)
@@ -55,7 +57,7 @@
var/obj/item/twohanded/offhand/O = user.get_inactive_held_item()
if(O && istype(O))
O.unwield()
- return
+ slowdown -= slowdown_wielded
/obj/item/twohanded/proc/wield(mob/living/carbon/user)
if(wielded)
@@ -85,7 +87,7 @@
O.desc = "Your second grip on [src]."
O.wielded = TRUE
user.put_in_inactive_hand(O)
- return
+ slowdown += slowdown_wielded
/obj/item/twohanded/dropped(mob/user)
. = ..()
@@ -279,6 +281,7 @@
wieldsound = 'sound/weapons/saberon.ogg'
unwieldsound = 'sound/weapons/saberoff.ogg'
hitsound = "swing_hit"
+ var/hitsound_on = 'sound/weapons/blade1.ogg'
armour_penetration = 35
item_color = "green"
light_color = "#00ff00"//green
@@ -290,8 +293,10 @@
var/hacked = FALSE
var/brightness_on = 6 //TWICE AS BRIGHT AS A REGULAR ESWORD
var/list/possible_colors = list("red", "blue", "green", "purple")
- total_mass = 0.375 //Survival flashlights typically weigh around 5 ounces.
- var/total_mass_on = 3.4 //The typical medieval sword, on the other hand, weighs roughly 3 pounds. //Values copied from the regular e-sword
+ var/list/rainbow_colors = list(LIGHT_COLOR_RED, LIGHT_COLOR_GREEN, LIGHT_COLOR_LIGHT_CYAN, LIGHT_COLOR_LAVENDER)
+ var/spinnable = TRUE
+ total_mass = 0.4 //Survival flashlights typically weigh around 5 ounces.
+ var/total_mass_on = 3.4
/obj/item/twohanded/dualsaber/suicide_act(mob/living/carbon/user)
if(wielded)
@@ -353,7 +358,7 @@
if(HAS_TRAIT(user, TRAIT_CLUMSY) && (wielded) && prob(40))
impale(user)
return
- if((wielded) && prob(50))
+ if(spinnable && (wielded) && prob(50))
INVOKE_ASYNC(src, .proc/jedi_spin, user)
/obj/item/twohanded/dualsaber/proc/jedi_spin(mob/living/user)
@@ -406,11 +411,14 @@
/obj/item/twohanded/dualsaber/process()
if(wielded)
if(hacked)
- light_color = pick(LIGHT_COLOR_RED, LIGHT_COLOR_GREEN, LIGHT_COLOR_LIGHT_CYAN, LIGHT_COLOR_LAVENDER)
+ rainbow_process()
open_flame()
else
STOP_PROCESSING(SSobj, src)
+/obj/item/twohanded/dualsaber/proc/rainbow_process()
+ light_color = pick(rainbow_colors)
+
/obj/item/twohanded/dualsaber/IsReflect()
if(wielded)
return 1
@@ -428,7 +436,8 @@
playsound(loc, hitsound, get_clamped_volume(), 1, -1)
add_fingerprint(user)
// Light your candles while spinning around the room
- INVOKE_ASYNC(src, .proc/jedi_spin, user)
+ if(spinnable)
+ INVOKE_ASYNC(src, .proc/jedi_spin, user)
/obj/item/twohanded/dualsaber/green
possible_colors = list("green")
diff --git a/code/game/objects/items/weaponry.dm b/code/game/objects/items/weaponry.dm
index 48681c3d6d..560731edfd 100644
--- a/code/game/objects/items/weaponry.dm
+++ b/code/game/objects/items/weaponry.dm
@@ -69,6 +69,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
max_integrity = 200
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 50)
resistance_flags = FIRE_PROOF
+ total_mass = TOTAL_MASS_MEDIEVAL_WEAPON
/obj/item/claymore/Initialize()
. = ..()
@@ -223,6 +224,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
max_integrity = 200
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 50)
resistance_flags = FIRE_PROOF
+ total_mass = TOTAL_MASS_MEDIEVAL_WEAPON
/obj/item/katana/cursed
slot_flags = null
@@ -431,6 +433,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
sharpness = IS_SHARP
attack_verb = list("sawed", "torn", "cut", "chopped", "diced")
hitsound = 'sound/weapons/chainsawhit.ogg'
+ total_mass = TOTAL_MASS_HAND_REPLACEMENT
/obj/item/mounted_chainsaw/Initialize()
. = ..()
diff --git a/code/game/objects/structures/artstuff.dm b/code/game/objects/structures/artstuff.dm
index b8320c80fb..405e697d3b 100644
--- a/code/game/objects/structures/artstuff.dm
+++ b/code/game/objects/structures/artstuff.dm
@@ -99,7 +99,7 @@ GLOBAL_LIST_INIT(globalBlankCanvases, new(AMT_OF_CANVASES))
return
//Cleaning one pixel with a soap or rag
- if(istype(I, /obj/item/soap) || istype(I, /obj/item/reagent_containers/glass/rag))
+ if(istype(I, /obj/item/soap) || istype(I, /obj/item/reagent_containers/rag))
//Pixel info created only when needed
var/icon/masterpiece = icon(icon,icon_state)
var/thePix = masterpiece.GetPixel(pixX,pixY)
diff --git a/code/game/objects/structures/beds_chairs/chair.dm b/code/game/objects/structures/beds_chairs/chair.dm
index e944eb32da..88d141a9ad 100644
--- a/code/game/objects/structures/beds_chairs/chair.dm
+++ b/code/game/objects/structures/beds_chairs/chair.dm
@@ -317,9 +317,6 @@
new stack_type(get_turf(loc))
qdel(src)
-
-
-
/obj/item/chair/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
if(attack_type == UNARMED_ATTACK && prob(hit_reaction_chance))
owner.visible_message("[owner] fends off [attack_text] with [src]!")
@@ -338,7 +335,6 @@
C.Knockdown(20)
smash(user)
-
/obj/item/chair/stool
name = "stool"
icon_state = "stool_toppled"
@@ -352,6 +348,70 @@
item_state = "stool_bar"
origin_type = /obj/structure/chair/stool/bar
+//////////////////////////
+//Brass & Bronze stools!//
+//////////////////////////
+
+/obj/structure/chair/stool/bar/brass
+ name = "brass bar stool"
+ desc = "A brass bar stool with red silk for a pillow."
+ icon_state = "barbrass"
+ item_chair = /obj/item/chair/stool/bar/brass
+ buildstacktype = /obj/item/stack/tile/brass
+ buildstackamount = 1
+
+/obj/structure/chair/stool/bar/bronze
+ name = "bronze bar stool"
+ desc = "A bronze bar stool with red silk for a pillow."
+ icon_state = "barbrass"
+ item_chair = /obj/item/chair/stool/bar/bronze
+ buildstacktype = /obj/item/stack/tile/bronze
+ buildstackamount = 1
+
+/obj/structure/chair/stool/brass
+ name = "brass stool"
+ desc = "A brass stool with a silk top for comfort."
+ icon_state = "stoolbrass"
+ item_chair = /obj/item/chair/stool/brass
+ buildstacktype = /obj/item/stack/tile/brass
+ buildstackamount = 1
+
+/obj/structure/chair/stool/bronze
+ name = "bronze stool"
+ desc = "A bronze stool with a silk top for comfort."
+ icon_state = "stoolbrass"
+ item_chair = /obj/item/chair/stool/bronze
+ buildstacktype = /obj/item/stack/tile/bronze
+ buildstackamount = 1
+
+/obj/item/chair/stool/brass
+ name = "brass stool"
+ icon_state = "stoolbrass_toppled"
+ item_state = "stoolbrass"
+ origin_type = /obj/structure/chair/stool/brass
+
+/obj/item/chair/stool/bar/brass
+ name = "brass bar stool"
+ icon_state = "barbrass_toppled"
+ item_state = "stoolbrass_bar"
+ origin_type = /obj/structure/chair/stool/bar/brass
+
+/obj/item/chair/stool/bronze
+ name = "bronze stool"
+ icon_state = "stoolbrass_toppled"
+ item_state = "stoolbrass"
+ origin_type = /obj/structure/chair/stool/bronze
+
+/obj/item/chair/stool/bar/bronze
+ name = "bronze bar stool"
+ icon_state = "barbrass_toppled"
+ item_state = "stoolbrass_bar"
+ origin_type = /obj/structure/chair/stool/bar/bronze
+
+/////////////////////////////////
+//End of Brass & Bronze stools!//
+/////////////////////////////////
+
/obj/item/chair/stool/narsie_act()
return //sturdy enough to ignore a god
diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm
index 2c4463928c..f097d2903a 100644
--- a/code/game/objects/structures/crates_lockers/closets.dm
+++ b/code/game/objects/structures/crates_lockers/closets.dm
@@ -1,507 +1,616 @@
-/obj/structure/closet
- name = "closet"
- desc = "It's a basic storage unit."
- icon = 'icons/obj/closet.dmi'
- icon_state = "generic"
- density = TRUE
- layer = BELOW_OBJ_LAYER
- var/icon_door = null
- var/icon_door_override = FALSE //override to have open overlay use icon different to its base's
- var/secure = FALSE //secure locker or not, also used if overriding a non-secure locker with a secure door overlay to add fancy lights
- var/opened = FALSE
- var/welded = FALSE
- var/locked = FALSE
- var/large = TRUE
- var/wall_mounted = 0 //never solid (You can always pass over it)
- max_integrity = 200
- integrity_failure = 50
- armor = list("melee" = 20, "bullet" = 10, "laser" = 10, "energy" = 0, "bomb" = 10, "bio" = 0, "rad" = 0, "fire" = 70, "acid" = 60)
- var/breakout_time = 1200
- var/message_cooldown
- var/can_weld_shut = TRUE
- var/horizontal = FALSE
- var/allow_objects = FALSE
- var/allow_dense = FALSE
- var/dense_when_open = FALSE //if it's dense when open or not
- var/max_mob_size = MOB_SIZE_HUMAN //Biggest mob_size accepted by the container
- var/mob_storage_capacity = 3 // how many human sized mob/living can fit together inside a closet.
- var/storage_capacity = 30 //This is so that someone can't pack hundreds of items in a locker/crate then open it in a populated area to crash clients.
- var/cutting_tool = /obj/item/weldingtool
- var/open_sound = 'sound/machines/click.ogg'
- var/close_sound = 'sound/machines/click.ogg'
- var/material_drop = /obj/item/stack/sheet/metal
- var/material_drop_amount = 2
- var/delivery_icon = "deliverycloset" //which icon to use when packagewrapped. null to be unwrappable.
- var/anchorable = TRUE
- var/icon_welded = "welded"
-
-
-/obj/structure/closet/Initialize(mapload)
- . = ..()
- update_icon()
- PopulateContents()
- if(mapload && !opened) // if closed, any item at the crate's loc is put in the contents
- take_contents()
-
-//USE THIS TO FILL IT, NOT INITIALIZE OR NEW
-/obj/structure/closet/proc/PopulateContents()
- return
-
-/obj/structure/closet/Destroy()
- dump_contents()
- return ..()
-
-/obj/structure/closet/update_icon()
- cut_overlays()
- if(!opened)
- layer = OBJ_LAYER
- if(icon_door)
- add_overlay("[icon_door]_door")
- else
- add_overlay("[icon_state]_door")
- if(welded)
- add_overlay(icon_welded)
- if(secure && !broken)
- if(locked)
- add_overlay("locked")
- else
- add_overlay("unlocked")
-
- else
- layer = BELOW_OBJ_LAYER
- if(icon_door_override)
- add_overlay("[icon_door]_open")
- else
- add_overlay("[icon_state]_open")
-
-/obj/structure/closet/examine(mob/user)
- ..()
- if(welded)
- to_chat(user, "It's welded shut.")
- if(anchored)
- to_chat(user, "It is bolted to the ground.")
- if(opened)
- to_chat(user, "The parts are welded together.")
- else if(secure && !opened)
- to_chat(user, "Alt-click to [locked ? "unlock" : "lock"].")
- if(isliving(user))
- var/mob/living/L = user
- if(HAS_TRAIT(L, TRAIT_SKITTISH))
- to_chat(user, "Ctrl-Shift-click [src] to jump inside.")
-
-/obj/structure/closet/CanPass(atom/movable/mover, turf/target)
- if(wall_mounted)
- return TRUE
- return !density
-
-/obj/structure/closet/proc/can_open(mob/living/user)
- if(welded || locked)
- return FALSE
- var/turf/T = get_turf(src)
- for(var/mob/living/L in T)
- if(L.anchored || horizontal && L.mob_size > MOB_SIZE_TINY && L.density)
- if(user)
- to_chat(user, "There's something large on top of [src], preventing it from opening." )
- return FALSE
- return TRUE
-
-/obj/structure/closet/proc/can_close(mob/living/user)
- var/turf/T = get_turf(src)
- for(var/obj/structure/closet/closet in T)
- if(closet != src && !closet.wall_mounted)
- return FALSE
- for(var/mob/living/L in T)
- if(L.anchored || horizontal && L.mob_size > MOB_SIZE_TINY && L.density)
- if(user)
- to_chat(user, "There's something too large in [src], preventing it from closing.")
- return FALSE
- return TRUE
-
-/obj/structure/closet/proc/dump_contents()
- var/atom/L = drop_location()
- for(var/atom/movable/AM in src)
- AM.forceMove(L)
- if(throwing) // you keep some momentum when getting out of a thrown closet
- step(AM, dir)
- if(throwing)
- throwing.finalize(FALSE)
-
-/obj/structure/closet/proc/take_contents()
- var/atom/L = drop_location()
- for(var/atom/movable/AM in L)
- if(AM != src && insert(AM) == -1) // limit reached
- break
-
-/obj/structure/closet/proc/open(mob/living/user)
- if(opened || !can_open(user))
- return
- playsound(loc, open_sound, 15, 1, -3)
- opened = TRUE
- if(!dense_when_open)
- density = FALSE
- climb_time *= 0.5 //it's faster to climb onto an open thing
- dump_contents()
- update_icon()
- return 1
-
-/obj/structure/closet/proc/insert(atom/movable/AM)
- if(contents.len >= storage_capacity)
- return -1
- if(insertion_allowed(AM))
- AM.forceMove(src)
- return TRUE
- else
- return FALSE
-
-
-/obj/structure/closet/proc/insertion_allowed(atom/movable/AM)
- if(ismob(AM))
- if(!isliving(AM)) //let's not put ghosts or camera mobs inside closets...
- return FALSE
- var/mob/living/L = AM
- if(L.anchored || L.buckled || L.incorporeal_move || L.has_buckled_mobs())
- return FALSE
- if(L.mob_size > MOB_SIZE_TINY) // Tiny mobs are treated as items.
- if(horizontal && L.density)
- return FALSE
- if(L.mob_size > max_mob_size)
- return FALSE
- var/mobs_stored = 0
- for(var/mob/living/M in contents)
- if(++mobs_stored >= mob_storage_capacity)
- return FALSE
- L.stop_pulling()
-
- else if(istype(AM, /obj/structure/closet))
- return FALSE
-
- else if(istype(AM, /obj/effect))
- return FALSE
-
- else if(isobj(AM))
- if((!allow_dense && AM.density) || AM.anchored || AM.has_buckled_mobs())
- return FALSE
- if(isitem(AM) && !HAS_TRAIT(AM, TRAIT_NODROP))
- return TRUE
- else if(!allow_objects && !istype(AM, /obj/effect/dummy/chameleon))
- return FALSE
- else
- return FALSE
-
- return TRUE
-
-/obj/structure/closet/proc/close(mob/living/user)
- if(!opened || !can_close(user))
- return FALSE
- take_contents()
- playsound(loc, close_sound, 15, 1, -3)
- climb_time = initial(climb_time)
- opened = FALSE
- density = TRUE
- update_icon()
- return TRUE
-
-/obj/structure/closet/proc/toggle(mob/living/user)
- if(opened)
- return close(user)
- else
- return open(user)
-
-/obj/structure/closet/deconstruct(disassembled = TRUE)
- if(ispath(material_drop) && material_drop_amount && !(flags_1 & NODECONSTRUCT_1))
- new material_drop(loc, material_drop_amount)
- qdel(src)
-
-/obj/structure/closet/obj_break(damage_flag)
- if(!broken && !(flags_1 & NODECONSTRUCT_1))
- bust_open()
-
-/obj/structure/closet/attackby(obj/item/W, mob/user, params)
- if(user in src)
- return
- if(src.tool_interact(W,user))
- return 1 // No afterattack
- else
- return ..()
-
-/obj/structure/closet/proc/tool_interact(obj/item/W, mob/user)//returns TRUE if attackBy call shouldnt be continued (because tool was used/closet was of wrong type), FALSE if otherwise
- . = TRUE
- if(opened)
- if(istype(W, cutting_tool))
- if(istype(W, /obj/item/weldingtool))
- if(!W.tool_start_check(user, amount=0))
- return
-
- to_chat(user, "You begin cutting \the [src] apart...")
- if(W.use_tool(src, user, 40, volume=50))
- if(!opened)
- return
- user.visible_message("[user] slices apart \the [src].",
- "You cut \the [src] apart with \the [W].",
- "You hear welding.")
- deconstruct(TRUE)
- return
- else // for example cardboard box is cut with wirecutters
- user.visible_message("[user] cut apart \the [src].", \
- "You cut \the [src] apart with \the [W].")
- deconstruct(TRUE)
- return
- if(user.transferItemToLoc(W, drop_location())) // so we put in unlit welder too
- return
- else if(istype(W, /obj/item/weldingtool) && can_weld_shut)
- if(!W.tool_start_check(user, amount=0))
- return
-
- to_chat(user, "You begin [welded ? "unwelding":"welding"] \the [src]...")
- if(W.use_tool(src, user, 40, volume=50))
- if(opened)
- return
- welded = !welded
- after_weld(welded)
- user.visible_message("[user] [welded ? "welds shut" : "unwelded"] \the [src].",
- "You [welded ? "weld" : "unwelded"] \the [src] with \the [W].",
- "You hear welding.")
- update_icon()
- else if(istype(W, /obj/item/wrench) && anchorable)
- if(isinspace() && !anchored)
- return
- setAnchored(!anchored)
- W.play_tool_sound(src, 75)
- user.visible_message("[user] [anchored ? "anchored" : "unanchored"] \the [src] [anchored ? "to" : "from"] the ground.", \
- "You [anchored ? "anchored" : "unanchored"] \the [src] [anchored ? "to" : "from"] the ground.", \
- "You hear a ratchet.")
- else if(user.a_intent != INTENT_HARM && !(W.item_flags & NOBLUDGEON))
- if(W.GetID() || !toggle(user))
- togglelock(user)
- else
- return FALSE
-
-/obj/structure/closet/proc/after_weld(weld_state)
- return
-
-/obj/structure/closet/MouseDrop_T(atom/movable/O, mob/living/user)
- if(!istype(O) || O.anchored || istype(O, /obj/screen))
- return
- if(!istype(user) || user.incapacitated() || user.lying)
- return
- if(!Adjacent(user) || !user.Adjacent(O))
- return
- if(user == O) //try to climb onto it
- return ..()
- if(!opened)
- return
- if(!isturf(O.loc))
- return
-
- var/actuallyismob = 0
- if(isliving(O))
- actuallyismob = 1
- else if(!isitem(O))
- return
- var/turf/T = get_turf(src)
- var/list/targets = list(O, src)
- add_fingerprint(user)
- user.visible_message("[user] [actuallyismob ? "tries to ":""]stuff [O] into [src].", \
- "You [actuallyismob ? "try to ":""]stuff [O] into [src].", \
- "You hear clanging.")
- if(actuallyismob)
- if(do_after_mob(user, targets, 40))
- user.visible_message("[user] stuffs [O] into [src].", \
- "You stuff [O] into [src].", \
- "You hear a loud metal bang.")
- var/mob/living/L = O
- if(!issilicon(L))
- L.Knockdown(40)
- O.forceMove(T)
- close()
- else
- O.forceMove(T)
- return 1
-
-/obj/structure/closet/relaymove(mob/user)
- if(user.stat || !isturf(loc) || !isliving(user))
- return
- if(locked)
- if(message_cooldown <= world.time)
- message_cooldown = world.time + 50
- to_chat(user, "[src]'s door won't budge!")
- return
- container_resist(user)
-
-/obj/structure/closet/attack_hand(mob/user)
- . = ..()
- if(.)
- return
- if(user.lying && get_dist(src, user) > 0)
- return
-
- if(!toggle(user))
- togglelock(user)
-
-/obj/structure/closet/attack_paw(mob/user)
- return attack_hand(user)
-
-/obj/structure/closet/attack_robot(mob/user)
- if(user.Adjacent(src))
- return attack_hand(user)
-
-// tk grab then use on self
-/obj/structure/closet/attack_self_tk(mob/user)
- return attack_hand(user)
-
-/obj/structure/closet/verb/verb_toggleopen()
- set src in oview(1)
- set category = "Object"
- set name = "Toggle Open"
-
- if(!usr.canmove || usr.stat || usr.restrained())
- return
-
- if(iscarbon(usr) || issilicon(usr) || isdrone(usr))
- return attack_hand(usr)
- else
- to_chat(usr, "This mob type can't use this verb.")
-
-// Objects that try to exit a locker by stepping were doing so successfully,
-// and due to an oversight in turf/Enter() were going through walls. That
-// should be independently resolved, but this is also an interesting twist.
-/obj/structure/closet/Exit(atom/movable/AM)
- open()
- if(AM.loc == src)
- return 0
- return 1
-
-/obj/structure/closet/container_resist(mob/living/user)
- if(opened)
- return
- if(ismovableatom(loc))
- user.changeNext_move(CLICK_CD_BREAKOUT)
- user.last_special = world.time + CLICK_CD_BREAKOUT
- var/atom/movable/AM = loc
- AM.relay_container_resist(user, src)
- return
- if(!welded && !locked)
- open()
- return
-
- //okay, so the closet is either welded or locked... resist!!!
- user.changeNext_move(CLICK_CD_BREAKOUT)
- user.last_special = world.time + CLICK_CD_BREAKOUT
- user.visible_message("[src] begins to shake violently!", \
- "You lean on the back of [src] and start pushing the door open... (this will take about [DisplayTimeText(breakout_time)].)", \
- "You hear banging from [src].")
- if(do_after(user,(breakout_time), target = src))
- if(!user || user.stat != CONSCIOUS || user.loc != src || opened || (!locked && !welded) )
- return
- //we check after a while whether there is a point of resisting anymore and whether the user is capable of resisting
- user.visible_message("[user] successfully broke out of [src]!",
- "You successfully break out of [src]!")
- bust_open()
- else
- if(user.loc == src) //so we don't get the message if we resisted multiple times and succeeded.
- to_chat(user, "You fail to break out of [src]!")
-
-/obj/structure/closet/proc/bust_open()
- welded = FALSE //applies to all lockers
- locked = FALSE //applies to critter crates and secure lockers only
- broken = TRUE //applies to secure lockers only
- open()
-
-/obj/structure/closet/AltClick(mob/user)
- ..()
- if(!user.canUseTopic(src, BE_CLOSE) || !isturf(loc))
- return
- if(opened || !secure)
- return
- else
- togglelock(user)
-
-/obj/structure/closet/CtrlShiftClick(mob/living/user)
- if(!HAS_TRAIT(user, TRAIT_SKITTISH))
- return ..()
- if(!user.canUseTopic(src) || !isturf(user.loc))
- return
- dive_into(user)
-
-/obj/structure/closet/proc/togglelock(mob/living/user, silent)
- if(secure && !broken)
- if(allowed(user))
- if(iscarbon(user))
- add_fingerprint(user)
- locked = !locked
- user.visible_message("[user] [locked ? null : "un"]locks [src].",
- "You [locked ? null : "un"]lock [src].")
- update_icon()
- else if(!silent)
- to_chat(user, "Access Denied")
- else if(secure && broken)
- to_chat(user, "\The [src] is broken!")
-
-/obj/structure/closet/emag_act(mob/user)
- if(secure && !broken)
- user.visible_message("Sparks fly from [src]!",
- "You scramble [src]'s lock, breaking it open!",
- "You hear a faint electrical spark.")
- playsound(src, "sparks", 50, 1)
- broken = TRUE
- locked = FALSE
- update_icon()
-
-/obj/structure/closet/get_remote_view_fullscreens(mob/user)
- if(user.stat == DEAD || !(user.sight & (SEEOBJS|SEEMOBS)))
- user.overlay_fullscreen("remote_view", /obj/screen/fullscreen/impaired, 1)
-
-/obj/structure/closet/emp_act(severity)
- . = ..()
- if(. & EMP_PROTECT_SELF)
- return
- if (!(. & EMP_PROTECT_CONTENTS))
- for(var/obj/O in src)
- O.emp_act(severity)
- if(secure && !broken && !(. & EMP_PROTECT_SELF))
- if(prob(50 / severity))
- locked = !locked
- update_icon()
- if(prob(20 / severity) && !opened)
- if(!locked)
- open()
- else
- req_access = list()
- req_access += pick(get_all_accesses())
-
-/obj/structure/closet/contents_explosion(severity, target)
- for(var/atom/A in contents)
- A.ex_act(severity, target)
- CHECK_TICK
-
-/obj/structure/closet/singularity_act()
- dump_contents()
- ..()
-
-/obj/structure/closet/AllowDrop()
- return TRUE
-
-
-/obj/structure/closet/return_temperature()
- return
-
-/obj/structure/closet/proc/dive_into(mob/living/user)
- var/turf/T1 = get_turf(user)
- var/turf/T2 = get_turf(src)
- if(!opened)
- if(locked)
- togglelock(user, TRUE)
- if(!open(user))
- to_chat(user, "It won't budge!")
- return
- step_towards(user, T2)
- T1 = get_turf(user)
- if(T1 == T2)
- user.resting = TRUE //so people can jump into crates without slamming the lid on their head
- if(!close(user))
- to_chat(user, "You can't get [src] to close!")
- user.resting = FALSE
- return
- user.resting = FALSE
- togglelock(user)
- T1.visible_message("[user] dives into [src]!")
+/obj/structure/closet
+ name = "closet"
+ desc = "It's a basic storage unit."
+ icon = 'icons/obj/closet.dmi'
+ icon_state = "generic"
+ density = TRUE
+ layer = BELOW_OBJ_LAYER
+ var/icon_door = null
+ var/icon_door_override = FALSE //override to have open overlay use icon different to its base's
+ var/secure = FALSE //secure locker or not, also used if overriding a non-secure locker with a secure door overlay to add fancy lights
+ var/opened = FALSE
+ var/welded = FALSE
+ var/locked = FALSE
+ var/large = TRUE
+ var/wall_mounted = 0 //never solid (You can always pass over it)
+ max_integrity = 200
+ integrity_failure = 50
+ armor = list("melee" = 20, "bullet" = 10, "laser" = 10, "energy" = 0, "bomb" = 10, "bio" = 0, "rad" = 0, "fire" = 70, "acid" = 60)
+ var/breakout_time = 1200
+ var/message_cooldown
+ var/can_weld_shut = TRUE
+ var/horizontal = FALSE
+ var/allow_objects = FALSE
+ var/allow_dense = FALSE
+ var/dense_when_open = FALSE //if it's dense when open or not
+ var/max_mob_size = MOB_SIZE_HUMAN //Biggest mob_size accepted by the container
+ var/mob_storage_capacity = 3 // how many human sized mob/living can fit together inside a closet.
+ var/storage_capacity = 30 //This is so that someone can't pack hundreds of items in a locker/crate then open it in a populated area to crash clients.
+ var/cutting_tool = /obj/item/weldingtool
+ var/open_sound = 'sound/machines/click.ogg'
+ var/close_sound = 'sound/machines/click.ogg'
+ var/material_drop = /obj/item/stack/sheet/metal
+ var/material_drop_amount = 2
+ var/delivery_icon = "deliverycloset" //which icon to use when packagewrapped. null to be unwrappable.
+ var/anchorable = TRUE
+ var/icon_welded = "welded"
+ var/obj/item/electronics/airlock/lockerelectronics //Installed electronics
+ var/lock_in_use = FALSE //Someone is doing some stuff with the lock here, better not proceed further
+ var/eigen_teleport = FALSE //If the closet leads to Mr Tumnus.
+ var/obj/structure/closet/eigen_target //Where you go to.
+
+
+/obj/structure/closet/Initialize(mapload)
+ . = ..()
+ update_icon()
+ PopulateContents()
+ if(mapload && !opened) // if closed, any item at the crate's loc is put in the contents
+ take_contents()
+ if(secure)
+ lockerelectronics = new(src)
+ lockerelectronics.accesses = req_access
+
+//USE THIS TO FILL IT, NOT INITIALIZE OR NEW
+/obj/structure/closet/proc/PopulateContents()
+ return
+
+/obj/structure/closet/Destroy()
+ dump_contents(override = FALSE)
+ return ..()
+
+/obj/structure/closet/update_icon()
+ cut_overlays()
+ if(opened & icon_door_override)
+ add_overlay("[icon_door]_open")
+ layer = OBJ_LAYER
+ return
+ else if(opened)
+ add_overlay("[icon_state]_open")
+ return
+ if(icon_door)
+ add_overlay("[icon_door]_door")
+ else
+ layer = BELOW_OBJ_LAYER
+ add_overlay("[icon_state]_door")
+ if(welded)
+ add_overlay("welded")
+ if(!secure)
+ return
+ if(broken)
+ add_overlay("off")
+ add_overlay("sparking")
+ else if(locked)
+ add_overlay("locked")
+ else
+ add_overlay("unlocked")
+
+/obj/structure/closet/examine(mob/user)
+ ..()
+ if(welded)
+ to_chat(user, "It's welded shut.")
+ if(anchored)
+ to_chat(user, "It is bolted to the ground.")
+ if(opened)
+ to_chat(user, "The parts are welded together.")
+ else if(secure && !opened)
+ else if(broken)
+ to_chat(user, "The lock is screwed in.")
+ else if(secure)
+ to_chat(user, "Alt-click to [locked ? "unlock" : "lock"].")
+ if(isliving(user))
+ var/mob/living/L = user
+ if(HAS_TRAIT(L, TRAIT_SKITTISH))
+ to_chat(user, "Ctrl-Shift-click [src] to jump inside.")
+
+/obj/structure/closet/CanPass(atom/movable/mover, turf/target)
+ if(wall_mounted)
+ return TRUE
+ return !density
+
+/obj/structure/closet/proc/can_open(mob/living/user)
+ if(welded || locked)
+ return FALSE
+ var/turf/T = get_turf(src)
+ for(var/mob/living/L in T)
+ if(L.anchored || horizontal && L.mob_size > MOB_SIZE_TINY && L.density)
+ if(user)
+ to_chat(user, "There's something large on top of [src], preventing it from opening." )
+ return FALSE
+ return TRUE
+
+/obj/structure/closet/proc/can_close(mob/living/user)
+ var/turf/T = get_turf(src)
+ for(var/obj/structure/closet/closet in T)
+ if(closet != src && !closet.wall_mounted)
+ return FALSE
+ for(var/mob/living/L in T)
+ if(L.anchored || horizontal && L.mob_size > MOB_SIZE_TINY && L.density)
+ if(user)
+ to_chat(user, "There's something too large in [src], preventing it from closing.")
+ return FALSE
+ return TRUE
+
+/obj/structure/closet/proc/can_lock(mob/living/user, var/check_access = TRUE) //set check_access to FALSE if you only need to check if a locker has a functional lock rather than access
+ if(!secure)
+ return FALSE
+ if(broken)
+ to_chat(user, "[src] is broken!")
+ return FALSE
+ if(QDELETED(lockerelectronics) && !locked) //We want to be able to unlock it regardless of electronics, but only lockable with electronics
+ to_chat(user, "[src] is missing locker electronics!")
+ return FALSE
+ if(!check_access)
+ return TRUE
+ if(allowed(user))
+ return TRUE
+ to_chat(user, "Access denied.")
+
+/obj/structure/closet/proc/togglelock(mob/living/user)
+ add_fingerprint(user)
+ if(eigen_target)
+ return
+ if(opened)
+ return
+ if(!can_lock(user))
+ return
+ locked = !locked
+ user.visible_message("[user] [locked ? null : "un"]locks [src].",
+ "You [locked ? null : "un"]lock [src].")
+ update_icon()
+
+/obj/structure/closet/proc/dump_contents(var/override = TRUE) //Override is for not revealing the locker electronics when you open the locker, for example
+ var/atom/L = drop_location()
+ for(var/atom/movable/AM in src)
+ if(AM == lockerelectronics && override)
+ continue
+ AM.forceMove(L)
+ if(throwing) // you keep some momentum when getting out of a thrown closet
+ step(AM, dir)
+ if(throwing)
+ throwing.finalize(FALSE)
+
+/obj/structure/closet/proc/take_contents()
+ var/atom/L = drop_location()
+ for(var/atom/movable/AM in L)
+ if(AM != src && insert(AM) == -1) // limit reached
+ break
+
+/obj/structure/closet/proc/open(mob/living/user)
+ if(opened || !can_open(user))
+ return
+ playsound(loc, open_sound, 15, 1, -3)
+ opened = TRUE
+ if(!dense_when_open)
+ density = FALSE
+ climb_time *= 0.5 //it's faster to climb onto an open thing
+ dump_contents()
+ update_icon()
+ return 1
+
+/obj/structure/closet/proc/insert(atom/movable/AM)
+ if(contents.len >= storage_capacity)
+ return -1
+ if(insertion_allowed(AM))
+ if(eigen_teleport) // For teleporting people with linked lockers.
+ do_teleport(AM, get_turf(eigen_target), 0)
+ if(eigen_target.opened == FALSE)
+ eigen_target.bust_open()
+ else
+ AM.forceMove(src)
+ return TRUE
+ else
+ return FALSE
+
+
+/obj/structure/closet/proc/insertion_allowed(atom/movable/AM)
+ if(ismob(AM))
+ if(!isliving(AM)) //let's not put ghosts or camera mobs inside closets...
+ return FALSE
+ var/mob/living/L = AM
+ if(L.anchored || L.buckled || L.incorporeal_move || L.has_buckled_mobs())
+ return FALSE
+ if(L.mob_size > MOB_SIZE_TINY) // Tiny mobs are treated as items.
+ if(horizontal && L.density)
+ return FALSE
+ if(L.mob_size > max_mob_size)
+ return FALSE
+ var/mobs_stored = 0
+ for(var/mob/living/M in contents)
+ if(++mobs_stored >= mob_storage_capacity)
+ return FALSE
+ L.stop_pulling()
+
+ else if(istype(AM, /obj/structure/closet))
+ return FALSE
+
+ else if(istype(AM, /obj/effect))
+ return FALSE
+
+ else if(isobj(AM))
+ if((!allow_dense && AM.density) || AM.anchored || AM.has_buckled_mobs())
+ return FALSE
+ if(isitem(AM) && !HAS_TRAIT(AM, TRAIT_NODROP))
+ return TRUE
+ else if(!allow_objects && !istype(AM, /obj/effect/dummy/chameleon))
+ return FALSE
+ else
+ return FALSE
+
+ return TRUE
+
+/obj/structure/closet/proc/close(mob/living/user)
+ if(!opened || !can_close(user))
+ return FALSE
+ take_contents()
+ playsound(loc, close_sound, 15, 1, -3)
+ climb_time = initial(climb_time)
+ opened = FALSE
+ density = TRUE
+ update_icon()
+ return TRUE
+
+/obj/structure/closet/proc/toggle(mob/living/user)
+ if(opened)
+ return close(user)
+ else
+ return open(user)
+
+/obj/structure/closet/proc/bust_open()
+ welded = FALSE //applies to all lockers
+ locked = FALSE //applies to critter crates and secure lockers only
+ broken = TRUE //applies to secure lockers only
+ open()
+
+/obj/structure/closet/proc/handle_lock_addition(mob/user, obj/item/electronics/airlock/E)
+ add_fingerprint(user)
+ if(lock_in_use)
+ to_chat(user, "Wait for work on [src] to be done first!")
+ return
+ if(secure)
+ to_chat(user, "This locker already has a lock!")
+ return
+ if(broken)
+ to_chat(user, "Unscrew the broken lock first!")
+ return
+ if(!istype(E))
+ return
+ user.visible_message("[user] begins installing a lock on [src]...","You begin installing a lock on [src]...")
+ lock_in_use = TRUE
+ playsound(loc, 'sound/items/screwdriver.ogg', 50, 1)
+ if(!do_after(user, 60, target = src))
+ lock_in_use = FALSE
+ return
+ lock_in_use = FALSE
+ to_chat(user, "You finish the lock on [src]!")
+ E.forceMove(src)
+ lockerelectronics = E
+ req_access = E.accesses
+ secure = TRUE
+ update_icon()
+ return TRUE
+
+/obj/structure/closet/proc/handle_lock_removal(mob/user, obj/item/screwdriver/S)
+ if(lock_in_use)
+ to_chat(user, "Wait for work on [src] to be done first!")
+ return
+ if(locked)
+ to_chat(user, "Unlock it first!")
+ return
+ if(!secure)
+ to_chat(user, "[src] doesn't have a lock that you can remove!")
+ return
+ if(!istype(S))
+ return
+ var/brokenword = broken ? "broken " : null
+ user.visible_message("[user] begins removing the [brokenword]lock on [src]...","You begin removing the [brokenword]lock on [src]...")
+ playsound(loc, S.usesound, 50, 1)
+ lock_in_use = TRUE
+ if(!do_after(user, 100 * S.toolspeed, target = src))
+ lock_in_use = FALSE
+ return
+ to_chat(user, "You remove the [brokenword]lock from [src]!")
+ if(!QDELETED(lockerelectronics))
+ lockerelectronics.add_fingerprint(user)
+ lockerelectronics.forceMove(user.loc)
+ lockerelectronics = null
+ req_access = null
+ secure = FALSE
+ broken = FALSE
+ locked = FALSE
+ lock_in_use = FALSE
+ update_icon()
+ return TRUE
+
+
+/obj/structure/closet/deconstruct(disassembled = TRUE)
+ if(ispath(material_drop) && material_drop_amount && !(flags_1 & NODECONSTRUCT_1))
+ new material_drop(loc, material_drop_amount)
+ qdel(src)
+
+/obj/structure/closet/obj_break(damage_flag)
+ if(!broken && !(flags_1 & NODECONSTRUCT_1))
+ bust_open()
+
+/obj/structure/closet/attackby(obj/item/W, mob/user, params)
+ if(user in src)
+ return
+ if(src.tool_interact(W,user))
+ return 1 // No afterattack
+ else
+ return ..()
+
+/obj/structure/closet/proc/tool_interact(obj/item/W, mob/user)//returns TRUE if attackBy call shouldnt be continued (because tool was used/closet was of wrong type), FALSE if otherwise
+ . = TRUE
+ if(opened)
+ if(istype(W, cutting_tool))
+ if(istype(W, /obj/item/weldingtool))
+ if(!W.tool_start_check(user, amount=0))
+ return
+
+ to_chat(user, "You begin cutting \the [src] apart...")
+ if(W.use_tool(src, user, 40, volume=50))
+ if(eigen_teleport)
+ to_chat(user, "The unstable nature of \the [src] makes it impossible to cut!")
+ return
+ if(!opened)
+ return
+ user.visible_message("[user] slices apart \the [src].",
+ "You cut \the [src] apart with \the [W].",
+ "You hear welding.")
+ deconstruct(TRUE)
+ return
+ else // for example cardboard box is cut with wirecutters
+ user.visible_message("[user] cut apart \the [src].", \
+ "You cut \the [src] apart with \the [W].")
+ deconstruct(TRUE)
+ return
+ if(user.transferItemToLoc(W, drop_location())) // so we put in unlit welder too
+ return TRUE
+ else if(istype(W, /obj/item/electronics/airlock))
+ handle_lock_addition(user, W)
+ else if(istype(W, /obj/item/screwdriver))
+ handle_lock_removal(user, W)
+ else if(istype(W, /obj/item/weldingtool) && can_weld_shut)
+ if(!W.tool_start_check(user, amount=0))
+ return
+
+ to_chat(user, "You begin [welded ? "unwelding":"welding"] \the [src]...")
+ if(W.use_tool(src, user, 40, volume=50))
+ if(eigen_teleport)
+ to_chat(user, "The unstable nature of \the [src] makes it impossible to weld!")
+ return
+ if(opened)
+ return
+ welded = !welded
+ after_weld(welded)
+ user.visible_message("[user] [welded ? "welds shut" : "unwelds"] \the [src].",
+ "You [welded ? "weld" : "unwelded"] \the [src] with \the [W].",
+ "You hear welding.")
+ update_icon()
+ else if(istype(W, /obj/item/wrench) && anchorable)
+ if(isinspace() && !anchored)
+ return
+ setAnchored(!anchored)
+ W.play_tool_sound(src, 75)
+ user.visible_message("[user] [anchored ? "anchored" : "unanchored"] \the [src] [anchored ? "to" : "from"] the ground.", \
+ "You [anchored ? "anchored" : "unanchored"] \the [src] [anchored ? "to" : "from"] the ground.", \
+ "You hear a ratchet.")
+ else if(user.a_intent != INTENT_HARM && !(W.item_flags & NOBLUDGEON))
+ if(W.GetID() || !toggle(user))
+ togglelock(user)
+ else
+ return FALSE
+
+/obj/structure/closet/proc/after_weld(weld_state)
+ return
+
+/obj/structure/closet/MouseDrop_T(atom/movable/O, mob/living/user)
+ if(!istype(O) || O.anchored || istype(O, /obj/screen))
+ return
+ if(!istype(user) || user.incapacitated() || user.lying)
+ return
+ if(!Adjacent(user) || !user.Adjacent(O))
+ return
+ if(user == O) //try to climb onto it
+ return ..()
+ if(!opened)
+ return
+ if(!isturf(O.loc))
+ return
+
+ var/actuallyismob = 0
+ if(isliving(O))
+ actuallyismob = 1
+ else if(!isitem(O))
+ return
+ var/turf/T = get_turf(src)
+ var/list/targets = list(O, src)
+ add_fingerprint(user)
+ user.visible_message("[user] [actuallyismob ? "tries to ":""]stuff [O] into [src].", \
+ "You [actuallyismob ? "try to ":""]stuff [O] into [src].", \
+ "You hear clanging.")
+ if(actuallyismob)
+ if(do_after_mob(user, targets, 40))
+ user.visible_message("[user] stuffs [O] into [src].", \
+ "You stuff [O] into [src].", \
+ "You hear a loud metal bang.")
+ var/mob/living/L = O
+ if(!issilicon(L))
+ L.Knockdown(40)
+ O.forceMove(T)
+ close()
+ else
+ O.forceMove(T)
+ return 1
+
+/obj/structure/closet/relaymove(mob/user)
+ if(user.stat || !isturf(loc) || !isliving(user))
+ return
+ if(locked)
+ if(message_cooldown <= world.time)
+ message_cooldown = world.time + 50
+ to_chat(user, "[src]'s door won't budge!")
+ return
+ container_resist(user)
+
+/obj/structure/closet/attack_hand(mob/user)
+ . = ..()
+ if(.)
+ return
+ if(user.lying && get_dist(src, user) > 0)
+ return
+
+ if(!toggle(user))
+ togglelock(user)
+
+/obj/structure/closet/attack_paw(mob/user)
+ return attack_hand(user)
+
+/obj/structure/closet/attack_robot(mob/user)
+ if(user.Adjacent(src))
+ return attack_hand(user)
+
+// tk grab then use on self
+/obj/structure/closet/attack_self_tk(mob/user)
+ return attack_hand(user)
+
+/obj/structure/closet/verb/verb_toggleopen()
+ set src in oview(1)
+ set category = "Object"
+ set name = "Toggle Open"
+
+ if(!usr.canmove || usr.stat || usr.restrained())
+ return
+
+ if(iscarbon(usr) || issilicon(usr) || isdrone(usr))
+ return attack_hand(usr)
+ else
+ to_chat(usr, "This mob type can't use this verb.")
+
+// Objects that try to exit a locker by stepping were doing so successfully,
+// and due to an oversight in turf/Enter() were going through walls. That
+// should be independently resolved, but this is also an interesting twist.
+/obj/structure/closet/Exit(atom/movable/AM)
+ open()
+ if(AM.loc == src)
+ return 0
+ return 1
+
+/obj/structure/closet/container_resist(mob/living/user)
+ if(opened)
+ return
+ if(ismovableatom(loc))
+ user.changeNext_move(CLICK_CD_BREAKOUT)
+ user.last_special = world.time + CLICK_CD_BREAKOUT
+ var/atom/movable/AM = loc
+ AM.relay_container_resist(user, src)
+ return
+ if(!welded && !locked)
+ open()
+ return
+
+ //okay, so the closet is either welded or locked... resist!!!
+ user.changeNext_move(CLICK_CD_BREAKOUT)
+ user.last_special = world.time + CLICK_CD_BREAKOUT
+ user.visible_message("[src] begins to shake violently!", \
+ "You lean on the back of [src] and start pushing the door open... (this will take about [DisplayTimeText(breakout_time)].)", \
+ "You hear banging from [src].")
+ if(do_after(user,(breakout_time), target = src))
+ if(!user || user.stat != CONSCIOUS || user.loc != src || opened || (!locked && !welded) )
+ return
+ //we check after a while whether there is a point of resisting anymore and whether the user is capable of resisting
+ user.visible_message("[user] successfully broke out of [src]!",
+ "You successfully break out of [src]!")
+ bust_open()
+ else
+ if(user.loc == src) //so we don't get the message if we resisted multiple times and succeeded.
+ to_chat(user, "You fail to break out of [src]!")
+
+/obj/structure/closet/AltClick(mob/user)
+ ..()
+ if(!user.canUseTopic(src, be_close=TRUE) || !isturf(loc))
+ to_chat(user, "You can't do that right now!")
+ return
+ togglelock(user)
+
+/obj/structure/closet/CtrlShiftClick(mob/living/user)
+ if(!HAS_TRAIT(user, TRAIT_SKITTISH))
+ return ..()
+ if(!user.canUseTopic(src) || !isturf(user.loc))
+ return
+ dive_into(user)
+
+/obj/structure/closet/emag_act(mob/user)
+ if(secure && !broken)
+ user.visible_message("Sparks fly from [src]!",
+ "You scramble [src]'s lock, breaking it open!",
+ "You hear a faint electrical spark.")
+ playsound(src, "sparks", 50, 1)
+ broken = TRUE
+ locked = FALSE
+ if(!QDELETED(lockerelectronics))
+ qdel(lockerelectronics)
+ lockerelectronics = null
+ update_icon()
+
+/obj/structure/closet/get_remote_view_fullscreens(mob/user)
+ if(user.stat == DEAD || !(user.sight & (SEEOBJS|SEEMOBS)))
+ user.overlay_fullscreen("remote_view", /obj/screen/fullscreen/impaired, 1)
+
+/obj/structure/closet/emp_act(severity)
+ . = ..()
+ if(. & EMP_PROTECT_SELF)
+ return
+ if (!(. & EMP_PROTECT_CONTENTS))
+ for(var/obj/O in src)
+ O.emp_act(severity)
+ if(!secure || broken)
+ return ..()
+ if(prob(50 / severity))
+ locked = !locked
+ update_icon()
+ if(prob(20 / severity) && !opened)
+ if(!locked)
+ open()
+ else
+ req_access = list()
+ req_access += pick(get_all_accesses())
+ if(!QDELETED(lockerelectronics))
+ lockerelectronics.accesses = req_access
+
+/obj/structure/closet/contents_explosion(severity, target)
+ for(var/atom/A in contents)
+ A.ex_act(severity, target)
+ CHECK_TICK
+
+/obj/structure/closet/singularity_act()
+ dump_contents()
+ ..()
+
+/obj/structure/closet/AllowDrop()
+ return TRUE
+
+
+/obj/structure/closet/return_temperature()
+ return
+
+/obj/structure/closet/proc/dive_into(mob/living/user)
+ var/turf/T1 = get_turf(user)
+ var/turf/T2 = get_turf(src)
+ if(!opened)
+ if(locked)
+ togglelock(user, TRUE)
+ if(!open(user))
+ to_chat(user, "It won't budge!")
+ return
+ step_towards(user, T2)
+ T1 = get_turf(user)
+ if(T1 == T2)
+ user.resting = TRUE //so people can jump into crates without slamming the lid on their head
+ if(!close(user))
+ to_chat(user, "You can't get [src] to close!")
+ user.resting = FALSE
+ return
+ user.resting = FALSE
+ togglelock(user)
+ T1.visible_message("[user] dives into [src]!")
diff --git a/code/game/objects/structures/crates_lockers/closets/bodybag.dm b/code/game/objects/structures/crates_lockers/closets/bodybag.dm
index 502b23354c..1c34850274 100644
--- a/code/game/objects/structures/crates_lockers/closets/bodybag.dm
+++ b/code/game/objects/structures/crates_lockers/closets/bodybag.dm
@@ -49,6 +49,12 @@
return 1
return 0
+/obj/structure/closet/body_bag/handle_lock_addition()
+ return
+
+/obj/structure/closet/body_bag/handle_lock_removal()
+ return
+
/obj/structure/closet/body_bag/MouseDrop(over_object, src_location, over_location)
. = ..()
if(over_object == usr && Adjacent(usr) && (in_range(src, usr) || usr.contents.Find(src)))
diff --git a/code/game/objects/structures/crates_lockers/closets/cardboardbox.dm b/code/game/objects/structures/crates_lockers/closets/cardboardbox.dm
index 82b0d1a441..aad68b2166 100644
--- a/code/game/objects/structures/crates_lockers/closets/cardboardbox.dm
+++ b/code/game/objects/structures/crates_lockers/closets/cardboardbox.dm
@@ -57,6 +57,11 @@
I.alpha = 0
animate(I, pixel_z = 32, alpha = 255, time = 5, easing = ELASTIC_EASING)
+/obj/structure/closet/cardboard/handle_lock_addition() //Whoever heard of a lockable cardboard box anyway
+ return
+
+/obj/structure/closet/cardboard/handle_lock_removal()
+ return
/obj/structure/closet/cardboard/metal
name = "large metal box"
diff --git a/code/game/objects/structures/crates_lockers/closets/job_closets.dm b/code/game/objects/structures/crates_lockers/closets/job_closets.dm
index 0809edaa71..d2ab9ea6fb 100644
--- a/code/game/objects/structures/crates_lockers/closets/job_closets.dm
+++ b/code/game/objects/structures/crates_lockers/closets/job_closets.dm
@@ -21,8 +21,8 @@
new /obj/item/clothing/head/soft/black(src)
new /obj/item/clothing/shoes/sneakers/black(src)
new /obj/item/clothing/shoes/sneakers/black(src)
- new /obj/item/reagent_containers/glass/rag(src)
- new /obj/item/reagent_containers/glass/rag(src)
+ new /obj/item/reagent_containers/rag(src)
+ new /obj/item/reagent_containers/rag(src)
new /obj/item/storage/box/beanbag(src)
new /obj/item/clothing/suit/armor/vest/alt(src)
new /obj/item/circuitboard/machine/dish_drive(src)
@@ -53,7 +53,7 @@
new /obj/item/clothing/suit/toggle/chef(src)
new /obj/item/clothing/under/rank/chef(src)
new /obj/item/clothing/head/chefhat(src)
- new /obj/item/reagent_containers/glass/rag(src)
+ new /obj/item/reagent_containers/rag(src)
/obj/structure/closet/jcloset
name = "custodial closet"
@@ -358,3 +358,8 @@
new /obj/item/clothing/shoes/workboots/mining(src)
new /obj/item/storage/backpack/satchel/explorer(src)
+/obj/structure/closet/coffin/handle_lock_addition()
+ return
+
+/obj/structure/closet/coffin/handle_lock_removal()
+ return
diff --git a/code/game/objects/structures/crates_lockers/closets/secure/cargo.dm b/code/game/objects/structures/crates_lockers/closets/secure/cargo.dm
index 5a9228e397..18928424c0 100644
--- a/code/game/objects/structures/crates_lockers/closets/secure/cargo.dm
+++ b/code/game/objects/structures/crates_lockers/closets/secure/cargo.dm
@@ -9,6 +9,7 @@
new /obj/item/clothing/head/beret/qm(src)
new /obj/item/storage/lockbox/medal/cargo(src)
new /obj/item/clothing/under/rank/cargo(src)
+ new /obj/item/clothing/under/rank/cargo/skirt(src)
new /obj/item/clothing/shoes/sneakers/brown(src)
new /obj/item/radio/headset/headset_cargo(src)
new /obj/item/clothing/suit/fire/firefighter(src)
diff --git a/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm b/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm
index 0d06276876..167823b9be 100644
--- a/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm
+++ b/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm
@@ -8,6 +8,7 @@
new /obj/item/clothing/neck/cloak/ce(src)
new /obj/item/clothing/head/beret/ce(src)
new /obj/item/clothing/under/rank/chief_engineer(src)
+ new /obj/item/clothing/under/rank/chief_engineer/skirt(src)
new /obj/item/clothing/head/hardhat/white(src)
new /obj/item/clothing/head/welding(src)
new /obj/item/clothing/gloves/color/yellow(src)
diff --git a/code/game/objects/structures/crates_lockers/closets/secure/medical.dm b/code/game/objects/structures/crates_lockers/closets/secure/medical.dm
index 9081cddbe4..0f810225b3 100644
--- a/code/game/objects/structures/crates_lockers/closets/secure/medical.dm
+++ b/code/game/objects/structures/crates_lockers/closets/secure/medical.dm
@@ -61,6 +61,7 @@
new /obj/item/clothing/head/bio_hood/cmo(src)
new /obj/item/clothing/suit/toggle/labcoat/cmo(src)
new /obj/item/clothing/under/rank/chief_medical_officer(src)
+ new /obj/item/clothing/under/rank/chief_medical_officer/skirt(src)
new /obj/item/clothing/shoes/sneakers/brown (src)
new /obj/item/cartridge/cmo(src)
new /obj/item/radio/headset/heads/cmo(src)
diff --git a/code/game/objects/structures/crates_lockers/closets/secure/personal.dm b/code/game/objects/structures/crates_lockers/closets/secure/personal.dm
index eb764fc230..e44d3c9079 100644
--- a/code/game/objects/structures/crates_lockers/closets/secure/personal.dm
+++ b/code/game/objects/structures/crates_lockers/closets/secure/personal.dm
@@ -4,6 +4,18 @@
req_access = list(ACCESS_ALL_PERSONAL_LOCKERS)
var/registered_name = null
+/obj/structure/closet/secure_closet/personal/examine(mob/user)
+ ..()
+ if(registered_name)
+ to_chat(user, "The display reads, \"Owned by [registered_name]\".")
+
+/obj/structure/closet/secure_closet/personal/check_access(obj/item/card/id/I)
+ . = ..()
+ if(!I || !istype(I))
+ return
+ if(registered_name == I.registered_name)
+ return TRUE
+
/obj/structure/closet/secure_closet/personal/PopulateContents()
..()
if(prob(50))
@@ -33,21 +45,21 @@
/obj/structure/closet/secure_closet/personal/attackby(obj/item/W, mob/user, params)
var/obj/item/card/id/I = W.GetID()
- if(istype(I))
- if(broken)
- to_chat(user, "It appears to be broken.")
- return
- if(!I || !I.registered_name)
- return
- if(allowed(user) || !registered_name || (istype(I) && (registered_name == I.registered_name)))
- //they can open all lockers, or nobody owns this, or they own this locker
- locked = !locked
- update_icon()
-
- if(!registered_name)
- registered_name = I.registered_name
- desc = "Owned by [I.registered_name]."
- else
- to_chat(user, "Access Denied.")
- else
+ if(!I || !istype(I))
return ..()
+ if(!can_lock(user, FALSE)) //Can't do anything if there isn't a lock!
+ return
+ if(I.registered_name && !registered_name)
+ to_chat(user, "You claim [src].")
+ registered_name = I.registered_name
+ else
+ ..()
+
+/obj/structure/closet/secure_closet/personal/handle_lock_addition() //If lock construction is successful we don't care what access the electronics had, so we override it
+ if(..())
+ req_access = list(ACCESS_ALL_PERSONAL_LOCKERS)
+ lockerelectronics.accesses = req_access
+
+/obj/structure/closet/secure_closet/personal/handle_lock_removal()
+ if(..())
+ registered_name = null
diff --git a/code/game/objects/structures/crates_lockers/closets/secure/scientist.dm b/code/game/objects/structures/crates_lockers/closets/secure/scientist.dm
index 7fe1247eb7..efcc2aa7ca 100644
--- a/code/game/objects/structures/crates_lockers/closets/secure/scientist.dm
+++ b/code/game/objects/structures/crates_lockers/closets/secure/scientist.dm
@@ -11,8 +11,11 @@
new /obj/item/clothing/head/bio_hood/scientist(src)
new /obj/item/clothing/suit/toggle/labcoat(src)
new /obj/item/clothing/under/rank/research_director(src)
+ new /obj/item/clothing/under/rank/research_director/skirt(src)
new /obj/item/clothing/under/rank/research_director/alt(src)
+ new /obj/item/clothing/under/rank/research_director/alt/skirt(src)
new /obj/item/clothing/under/rank/research_director/turtleneck(src)
+ new /obj/item/clothing/under/rank/research_director/turtleneck/skirt(src)
new /obj/item/clothing/shoes/sneakers/brown(src)
new /obj/item/cartridge/rd(src)
new /obj/item/clothing/gloves/color/latex(src)
diff --git a/code/game/objects/structures/crates_lockers/closets/secure/security.dm b/code/game/objects/structures/crates_lockers/closets/secure/security.dm
index 8c06af91a4..3cb8ceb22b 100644
--- a/code/game/objects/structures/crates_lockers/closets/secure/security.dm
+++ b/code/game/objects/structures/crates_lockers/closets/secure/security.dm
@@ -2,7 +2,6 @@
name = "\proper captain's locker"
req_access = list(ACCESS_CAPTAIN)
icon_state = "cap"
-
/obj/structure/closet/secure_closet/captains/PopulateContents()
..()
new /obj/item/clothing/suit/hooded/wintercoat/captain(src)
@@ -14,6 +13,7 @@
new /obj/item/pet_carrier(src)
new /obj/item/clothing/shoes/sneakers/brown(src)
new /obj/item/clothing/under/rank/captain(src)
+ new /obj/item/clothing/under/rank/captain/skirt(src)
new /obj/item/clothing/suit/armor/vest/capcarapace(src)
new /obj/item/clothing/head/caphat(src)
new /obj/item/clothing/under/captainparade(src)
@@ -34,16 +34,15 @@
new /obj/item/gun/energy/e_gun(src)
new /obj/item/door_remote/captain(src)
new /obj/item/storage/photo_album/Captain(src)
-
/obj/structure/closet/secure_closet/hop
name = "\proper head of personnel's locker"
req_access = list(ACCESS_HOP)
icon_state = "hop"
-
/obj/structure/closet/secure_closet/hop/PopulateContents()
..()
new /obj/item/clothing/neck/cloak/hop(src)
new /obj/item/clothing/under/rank/head_of_personnel(src)
+ new /obj/item/clothing/under/rank/head_of_personnel/skirt(src)
new /obj/item/clothing/head/hopcap(src)
new /obj/item/clothing/head/hopcap/beret(src)
new /obj/item/cartridge/hop(src)
@@ -62,12 +61,10 @@
new /obj/item/door_remote/civillian(src)
new /obj/item/circuitboard/machine/techfab/department/service(src)
new /obj/item/storage/photo_album/HoP(src)
-
/obj/structure/closet/secure_closet/hos
name = "\proper head of security's locker"
req_access = list(ACCESS_HOS)
icon_state = "hos"
-
/obj/structure/closet/secure_closet/hos/PopulateContents()
..()
new /obj/item/clothing/neck/cloak/hos(src)
@@ -77,7 +74,9 @@
new /obj/item/clothing/under/hosparademale(src)
new /obj/item/clothing/suit/armor/vest/leather(src)
new /obj/item/clothing/suit/armor/hos(src)
+ new /obj/item/clothing/under/rank/head_of_security/skirt(src)
new /obj/item/clothing/under/rank/head_of_security/alt(src)
+ new /obj/item/clothing/under/rank/head_of_security/alt/skirt(src)
new /obj/item/clothing/head/HoS(src)
new /obj/item/clothing/glasses/hud/security/sunglasses/eyepatch(src)
new /obj/item/clothing/glasses/hud/security/sunglasses/gars/supergars(src)
@@ -95,12 +94,10 @@
new /obj/item/pinpointer/nuke(src)
new /obj/item/circuitboard/machine/techfab/department/security(src)
new /obj/item/storage/photo_album/HoS(src)
-
/obj/structure/closet/secure_closet/warden
name = "\proper warden's locker"
req_access = list(ACCESS_ARMORY)
icon_state = "warden"
-
/obj/structure/closet/secure_closet/warden/PopulateContents()
..()
new /obj/item/radio/headset/headset_sec(src)
@@ -110,6 +107,7 @@
new /obj/item/clothing/head/beret/sec/navywarden(src)
new /obj/item/clothing/suit/armor/vest/warden/alt(src)
new /obj/item/clothing/under/rank/warden/navyblue(src)
+ new /obj/item/clothing/under/rank/warden/skirt(src)
new /obj/item/clothing/glasses/hud/security/sunglasses(src)
new /obj/item/holosign_creator/security(src)
new /obj/item/clothing/mask/gas/sechailer(src)
@@ -120,12 +118,10 @@
new /obj/item/clothing/gloves/krav_maga/sec(src)
new /obj/item/door_remote/head_of_security(src)
new /obj/item/gun/ballistic/shotgun/automatic/combat/compact(src)
-
/obj/structure/closet/secure_closet/security
name = "security officer's locker"
req_access = list(ACCESS_SECURITY)
icon_state = "sec"
-
/obj/structure/closet/secure_closet/security/PopulateContents()
..()
new /obj/item/clothing/suit/armor/vest(src)
@@ -134,55 +130,45 @@
new /obj/item/radio/headset/headset_sec/alt(src)
new /obj/item/clothing/glasses/hud/security/sunglasses(src)
new /obj/item/flashlight/seclite(src)
-
/obj/structure/closet/secure_closet/security/sec
-
/obj/structure/closet/secure_closet/security/sec/PopulateContents()
..()
new /obj/item/storage/belt/security/full(src)
-
/obj/structure/closet/secure_closet/security/cargo
-
/obj/structure/closet/secure_closet/security/cargo/PopulateContents()
..()
new /obj/item/clothing/accessory/armband/cargo(src)
new /obj/item/encryptionkey/headset_cargo(src)
-
/obj/structure/closet/secure_closet/security/engine
-
/obj/structure/closet/secure_closet/security/engine/PopulateContents()
..()
new /obj/item/clothing/accessory/armband/engine(src)
new /obj/item/encryptionkey/headset_eng(src)
-
/obj/structure/closet/secure_closet/security/science
-
/obj/structure/closet/secure_closet/security/science/PopulateContents()
..()
new /obj/item/clothing/accessory/armband/science(src)
new /obj/item/encryptionkey/headset_sci(src)
-
/obj/structure/closet/secure_closet/security/med
-
/obj/structure/closet/secure_closet/security/med/PopulateContents()
..()
new /obj/item/clothing/accessory/armband/medblue(src)
new /obj/item/encryptionkey/headset_med(src)
-
/obj/structure/closet/secure_closet/detective
name = "\improper detective's cabinet"
req_access = list(ACCESS_FORENSICS_LOCKERS)
icon_state = "cabinet"
resistance_flags = FLAMMABLE
max_integrity = 70
-
/obj/structure/closet/secure_closet/detective/PopulateContents()
..()
new /obj/item/clothing/under/rank/det(src)
+ new /obj/item/clothing/under/rank/det/skirt(src)
new /obj/item/clothing/suit/det_suit(src)
new /obj/item/clothing/head/fedora/det_hat(src)
new /obj/item/clothing/gloves/color/black(src)
new /obj/item/clothing/under/rank/det/grey(src)
+ new /obj/item/clothing/under/rank/det/grey/skirt(src)
new /obj/item/clothing/accessory/waistcoat(src)
new /obj/item/clothing/suit/det_suit/grey(src)
new /obj/item/clothing/head/fedora(src)
@@ -200,33 +186,29 @@
/obj/structure/closet/secure_closet/injection
name = "lethal injections"
req_access = list(ACCESS_HOS)
-
/obj/structure/closet/secure_closet/injection/PopulateContents()
..()
for(var/i in 1 to 5)
new /obj/item/reagent_containers/syringe/lethal/execution(src)
-
/obj/structure/closet/secure_closet/brig
name = "brig locker"
req_access = list(ACCESS_BRIG)
anchored = TRUE
var/id = null
-
/obj/structure/closet/secure_closet/evidence
anchored = TRUE
name = "Secure Evidence Closet"
req_access_txt = "0"
req_one_access_txt = list(ACCESS_ARMORY, ACCESS_FORENSICS_LOCKERS)
-
/obj/structure/closet/secure_closet/brig/PopulateContents()
..()
new /obj/item/clothing/under/rank/prisoner( src )
+ new /obj/item/clothing/under/rank/prisoner/skirt( src )
new /obj/item/clothing/shoes/sneakers/orange( src )
/obj/structure/closet/secure_closet/courtroom
name = "courtroom locker"
req_access = list(ACCESS_COURT)
-
/obj/structure/closet/secure_closet/courtroom/PopulateContents()
..()
new /obj/item/clothing/shoes/sneakers/brown(src)
@@ -236,22 +218,18 @@
new /obj/item/clothing/suit/judgerobe (src)
new /obj/item/clothing/head/powdered_wig (src)
new /obj/item/storage/briefcase(src)
-
/obj/structure/closet/secure_closet/contraband/armory
anchored = TRUE
name = "Contraband Locker"
req_access = list(ACCESS_ARMORY)
-
/obj/structure/closet/secure_closet/contraband/heads
anchored = TRUE
name = "Contraband Locker"
req_access = list(ACCESS_HEADS)
-
/obj/structure/closet/secure_closet/armory1
name = "armory armor locker"
req_access = list(ACCESS_ARMORY)
icon_state = "armory"
-
/obj/structure/closet/secure_closet/armory1/PopulateContents()
..()
new /obj/item/clothing/suit/armor/laserproof(src)
@@ -261,12 +239,10 @@
new /obj/item/clothing/head/helmet/riot(src)
for(var/i in 1 to 3)
new /obj/item/shield/riot(src)
-
/obj/structure/closet/secure_closet/armory2
name = "armory ballistics locker"
req_access = list(ACCESS_ARMORY)
icon_state = "armory"
-
/obj/structure/closet/secure_closet/armory2/PopulateContents()
..()
new /obj/item/storage/box/firingpins(src)
@@ -274,12 +250,10 @@
new /obj/item/storage/box/rubbershot(src)
for(var/i in 1 to 3)
new /obj/item/gun/ballistic/shotgun/riot(src)
-
/obj/structure/closet/secure_closet/armory3
name = "armory energy gun locker"
req_access = list(ACCESS_ARMORY)
icon_state = "armory"
-
/obj/structure/closet/secure_closet/armory3/PopulateContents()
..()
new /obj/item/storage/box/firingpins(src)
@@ -288,24 +262,20 @@
new /obj/item/gun/energy/e_gun(src)
for(var/i in 1 to 3)
new /obj/item/gun/energy/laser(src)
-
/obj/structure/closet/secure_closet/tac
name = "armory tac locker"
req_access = list(ACCESS_ARMORY)
icon_state = "tac"
-
/obj/structure/closet/secure_closet/tac/PopulateContents()
..()
new /obj/item/gun/ballistic/automatic/wt550(src)
new /obj/item/clothing/head/helmet/alt(src)
new /obj/item/clothing/mask/gas/sechailer(src)
new /obj/item/clothing/suit/armor/bulletproof(src)
-
/obj/structure/closet/secure_closet/lethalshots
name = "shotgun lethal rounds"
req_access = list(ACCESS_ARMORY)
icon_state = "tac"
-
/obj/structure/closet/secure_closet/lethalshots/PopulateContents()
..()
for(var/i in 1 to 3)
diff --git a/code/game/objects/structures/crates_lockers/closets/syndicate.dm b/code/game/objects/structures/crates_lockers/closets/syndicate.dm
index f2d32b773e..94d1b03fdb 100644
--- a/code/game/objects/structures/crates_lockers/closets/syndicate.dm
+++ b/code/game/objects/structures/crates_lockers/closets/syndicate.dm
@@ -9,6 +9,7 @@
/obj/structure/closet/syndicate/personal/PopulateContents()
..()
new /obj/item/clothing/under/syndicate(src)
+ new /obj/item/clothing/under/syndicate/skirt(src)
new /obj/item/clothing/shoes/sneakers/black(src)
new /obj/item/radio/headset/syndicate(src)
new /obj/item/ammo_box/magazine/m10mm(src)
diff --git a/code/game/objects/structures/crates_lockers/closets/wardrobe.dm b/code/game/objects/structures/crates_lockers/closets/wardrobe.dm
index 7493603ad4..d83922d708 100644
--- a/code/game/objects/structures/crates_lockers/closets/wardrobe.dm
+++ b/code/game/objects/structures/crates_lockers/closets/wardrobe.dm
@@ -2,33 +2,34 @@
name = "wardrobe"
desc = "It's a storage unit for standard-issue Nanotrasen attire."
icon_door = "blue"
-
/obj/structure/closet/wardrobe/PopulateContents()
..()
for(var/i in 1 to 3)
new /obj/item/clothing/under/color/blue(src)
+ for(var/i in 1 to 3)
+ new /obj/item/clothing/under/skirt/color/blue(src)
for(var/i in 1 to 3)
new /obj/item/clothing/shoes/sneakers/brown(src)
return
-
/obj/structure/closet/wardrobe/pink
name = "pink wardrobe"
icon_door = "pink"
-
/obj/structure/closet/wardrobe/pink/PopulateContents()
for(var/i in 1 to 3)
new /obj/item/clothing/under/color/pink(src)
+ for(var/i in 1 to 3)
+ new /obj/item/clothing/under/skirt/color/pink(src)
for(var/i in 1 to 3)
new /obj/item/clothing/shoes/sneakers/brown(src)
return
-
/obj/structure/closet/wardrobe/black
name = "black wardrobe"
icon_door = "black"
-
/obj/structure/closet/wardrobe/black/PopulateContents()
for(var/i in 1 to 3)
new /obj/item/clothing/under/color/black(src)
+ for(var/i in 1 to 3)
+ new /obj/item/clothing/under/skirt/color/black(src)
if(prob(25))
new /obj/item/clothing/suit/jacket/leather(src)
if(prob(20))
@@ -44,66 +45,60 @@
if(prob(40))
new /obj/item/clothing/mask/bandana/skull(src)
return
-
-
/obj/structure/closet/wardrobe/green
name = "green wardrobe"
icon_door = "green"
-
/obj/structure/closet/wardrobe/green/PopulateContents()
for(var/i in 1 to 3)
new /obj/item/clothing/under/color/green(src)
+ for(var/i in 1 to 3)
+ new /obj/item/clothing/under/skirt/color/green(src)
for(var/i in 1 to 3)
new /obj/item/clothing/shoes/sneakers/black(src)
new /obj/item/clothing/mask/bandana/green(src)
new /obj/item/clothing/mask/bandana/green(src)
return
-
-
/obj/structure/closet/wardrobe/orange
name = "prison wardrobe"
desc = "It's a storage unit for Nanotrasen-regulation prisoner attire."
icon_door = "orange"
-
/obj/structure/closet/wardrobe/orange/PopulateContents()
for(var/i in 1 to 3)
new /obj/item/clothing/under/rank/prisoner(src)
+ for(var/i in 1 to 3)
+ new /obj/item/clothing/under/rank/prisoner/skirt(src)
for(var/i in 1 to 3)
new /obj/item/clothing/shoes/sneakers/orange(src)
return
-
-
/obj/structure/closet/wardrobe/yellow
name = "yellow wardrobe"
icon_door = "yellow"
-
/obj/structure/closet/wardrobe/yellow/PopulateContents()
for(var/i in 1 to 3)
new /obj/item/clothing/under/color/yellow(src)
+ for(var/i in 1 to 3)
+ new /obj/item/clothing/under/skirt/color/yellow(src)
for(var/i in 1 to 3)
new /obj/item/clothing/shoes/sneakers/orange(src)
new /obj/item/clothing/mask/bandana/gold(src)
new /obj/item/clothing/mask/bandana/gold(src)
return
-
-
/obj/structure/closet/wardrobe/white
name = "white wardrobe"
icon_door = "white"
-
/obj/structure/closet/wardrobe/white/PopulateContents()
for(var/i in 1 to 3)
new /obj/item/clothing/under/color/white(src)
+ for(var/i in 1 to 3)
+ new /obj/item/clothing/under/skirt/color/white(src)
for(var/i in 1 to 3)
new /obj/item/clothing/shoes/sneakers/white(src)
for(var/i in 1 to 3)
new /obj/item/clothing/head/soft/mime(src)
return
-
/obj/structure/closet/wardrobe/pjs
name = "pajama wardrobe"
icon_door = "white"
-
/obj/structure/closet/wardrobe/pjs/PopulateContents()
new /obj/item/clothing/under/pj/red(src)
new /obj/item/clothing/under/pj/red(src)
@@ -112,15 +107,14 @@
for(var/i in 1 to 4)
new /obj/item/clothing/shoes/sneakers/white(src)
return
-
-
/obj/structure/closet/wardrobe/grey
name = "grey wardrobe"
icon_door = "grey"
-
/obj/structure/closet/wardrobe/grey/PopulateContents()
for(var/i in 1 to 3)
new /obj/item/clothing/under/color/grey(src)
+ for(var/i in 1 to 3)
+ new /obj/item/clothing/under/skirt/color/grey(src)
for(var/i in 1 to 3)
new /obj/item/clothing/shoes/sneakers/black(src)
for(var/i in 1 to 3)
@@ -140,28 +134,36 @@
if(prob(30))
new /obj/item/clothing/accessory/pocketprotector(src)
return
-
-
/obj/structure/closet/wardrobe/mixed
name = "mixed wardrobe"
icon_door = "mixed"
-
/obj/structure/closet/wardrobe/mixed/PopulateContents()
if(prob(40))
new /obj/item/clothing/suit/jacket(src)
if(prob(40))
new /obj/item/clothing/suit/jacket(src)
new /obj/item/clothing/under/color/white(src)
+ new /obj/item/clothing/under/skirt/color/white(src)
new /obj/item/clothing/under/color/blue(src)
+ new /obj/item/clothing/under/skirt/color/blue(src)
new /obj/item/clothing/under/color/yellow(src)
+ new /obj/item/clothing/under/skirt/color/yellow(src)
new /obj/item/clothing/under/color/green(src)
+ new /obj/item/clothing/under/skirt/color/green(src)
new /obj/item/clothing/under/color/orange(src)
+ new /obj/item/clothing/under/skirt/color/orange(src)
new /obj/item/clothing/under/color/pink(src)
+ new /obj/item/clothing/under/skirt/color/pink(src)
new /obj/item/clothing/under/color/red(src)
+ new /obj/item/clothing/under/skirt/color/red(src)
new /obj/item/clothing/under/color/darkblue(src)
+ new /obj/item/clothing/under/skirt/color/darkblue(src)
new /obj/item/clothing/under/color/teal(src)
+ new /obj/item/clothing/under/skirt/color/teal(src)
new /obj/item/clothing/under/color/lightpurple(src)
+ new /obj/item/clothing/under/skirt/color/lightpurple(src)
new /obj/item/clothing/under/color/green(src)
+ new /obj/item/clothing/under/skirt/color/green(src)
new /obj/item/clothing/mask/bandana/red(src)
new /obj/item/clothing/mask/bandana/red(src)
new /obj/item/clothing/mask/bandana/blue(src)
diff --git a/code/game/objects/structures/crates_lockers/crates.dm b/code/game/objects/structures/crates_lockers/crates.dm
index 067b1b0eb1..6caa7d834b 100644
--- a/code/game/objects/structures/crates_lockers/crates.dm
+++ b/code/game/objects/structures/crates_lockers/crates.dm
@@ -54,6 +54,12 @@
manifest = null
update_icon()
+/obj/structure/closet/crate/handle_lock_addition()
+ return
+
+/obj/structure/closet/crate/handle_lock_removal()
+ return
+
/obj/structure/closet/crate/proc/tear_manifest(mob/user)
to_chat(user, "You tear the manifest off of [src].")
playsound(src, 'sound/items/poster_ripped.ogg', 75, 1)
diff --git a/code/game/objects/structures/dresser.dm b/code/game/objects/structures/dresser.dm
index 461e19adf1..cdca354563 100644
--- a/code/game/objects/structures/dresser.dm
+++ b/code/game/objects/structures/dresser.dm
@@ -79,4 +79,4 @@
var/n_color = input(H, "Choose your [garment_type]'\s color.", "Character Preference", default_color) as color|null
if(!n_color || !H.canUseTopic(src, BE_CLOSE, FALSE, NO_TK))
return default_color
- return n_color
+ return sanitize_hexcolor(n_color)
diff --git a/code/game/objects/structures/femur_breaker.dm b/code/game/objects/structures/femur_breaker.dm
new file mode 100644
index 0000000000..e3002a8fae
--- /dev/null
+++ b/code/game/objects/structures/femur_breaker.dm
@@ -0,0 +1,175 @@
+#define BREAKER_ANIMATION_LENGTH 32
+#define BREAKER_SLAT_RAISED 1
+#define BREAKER_SLAT_MOVING 2
+#define BREAKER_SLAT_DROPPED 3
+#define BREAKER_ACTIVATE_DELAY 30
+#define BREAKER_WRENCH_DELAY 10
+#define BREAKER_ACTION_INUSE 5
+#define BREAKER_ACTION_WRENCH 6
+
+/obj/structure/femur_breaker
+ name = "femur breaker"
+ desc = "A large structure used to break the femurs of traitors and treasonists."
+ icon = 'icons/obj/femur_breaker.dmi'
+ icon_state = "breaker_raised"
+ can_buckle = TRUE
+ anchored = TRUE
+ density = TRUE
+ max_buckled_mobs = 1
+ buckle_lying = TRUE
+ buckle_prevents_pull = TRUE
+ layer = ABOVE_MOB_LAYER
+ var/slat_status = BREAKER_SLAT_RAISED
+ var/current_action = 0 // What's currently happening to the femur breaker
+
+/obj/structure/femur_breaker/examine(mob/user)
+ ..()
+
+ var/msg = ""
+
+ msg += "It is [anchored ? "secured to the floor." : "unsecured."]
"
+
+ if (slat_status == BREAKER_SLAT_RAISED)
+ msg += "The breaker slat is in a neutral position."
+ else
+ msg += "The breaker slat is lowered, and must be raised."
+
+ if (LAZYLEN(buckled_mobs))
+ msg += "
"
+ msg += "Someone appears to be strapped in. You can help them unbuckle, or activate the femur breaker."
+
+ to_chat(user, msg)
+
+ return msg
+
+/obj/structure/femur_breaker/attack_hand(mob/user)
+ add_fingerprint(user)
+
+ // Currently being used
+ if (current_action)
+ return
+
+ switch (slat_status)
+ if (BREAKER_SLAT_MOVING)
+ return
+ if (BREAKER_SLAT_DROPPED)
+ slat_status = BREAKER_SLAT_MOVING
+ icon_state = "breaker_raise"
+ addtimer(CALLBACK(src, .proc/raise_slat), BREAKER_ANIMATION_LENGTH)
+ return
+ if (BREAKER_SLAT_RAISED)
+ if (LAZYLEN(buckled_mobs))
+ if (user.a_intent == INTENT_HARM)
+ user.visible_message("[user] begins to pull the lever!",
+ "You begin to the pull the lever.")
+ current_action = BREAKER_ACTION_INUSE
+
+ if (do_after(user, BREAKER_ACTIVATE_DELAY, target = src) && slat_status == BREAKER_SLAT_RAISED)
+ current_action = 0
+ slat_status = BREAKER_SLAT_MOVING
+ icon_state = "breaker_drop"
+ drop_slat(user)
+ else
+ current_action = 0
+ else
+ var/mob/living/carbon/human/H = buckled_mobs[1]
+
+ if (H)
+ H.regenerate_icons()
+
+ unbuckle_all_mobs()
+ else //HERE
+ slat_status = BREAKER_SLAT_DROPPED
+ icon_state = "breaker_drop"
+
+/obj/structure/femur_breaker/proc/damage_leg(mob/living/carbon/human/H)
+ H.emote("scream")
+ H.apply_damage(150, BRUTE, pick(BODY_ZONE_L_LEG, BODY_ZONE_R_LEG))
+ H.adjustBruteLoss(rand(5,20) + (max(0, H.health))) //Make absolutely sure they end up in crit, so that they can succumb if they wish.
+
+/obj/structure/femur_breaker/proc/raise_slat()
+ slat_status = BREAKER_SLAT_RAISED
+ icon_state = "breaker_raised"
+
+/obj/structure/femur_breaker/proc/drop_slat(mob/user)
+ if (buckled_mobs.len)
+ var/mob/living/carbon/human/H = buckled_mobs[1]
+
+ if (!H)
+ return
+
+ playsound(src, 'sound/effects/femur_breaker.ogg', 100, FALSE)
+ H.Stun(BREAKER_ANIMATION_LENGTH)
+ addtimer(CALLBACK(src, .proc/damage_leg, H), BREAKER_ANIMATION_LENGTH, TIMER_UNIQUE)
+ log_combat(user, H, "femur broke", src)
+
+ slat_status = BREAKER_SLAT_DROPPED
+ icon_state = "breaker"
+
+/obj/structure/femur_breaker/buckle_mob(mob/living/M, force = FALSE, check_loc = TRUE)
+ if (!anchored)
+ to_chat(usr, "The [src] needs to be wrenched to the floor!")
+ return FALSE
+
+ if (!istype(M, /mob/living/carbon/human))
+ to_chat(usr, "It doesn't look like [M.p_they()] can fit into this properly!")
+ return FALSE
+
+ if (slat_status != BREAKER_SLAT_RAISED)
+ to_chat(usr, "The femur breaker must be in its neutral position before buckling someone in!")
+ return FALSE
+
+ return ..(M, force, FALSE)
+
+/obj/structure/femur_breaker/post_buckle_mob(mob/living/M)
+ if (!istype(M, /mob/living/carbon/human))
+ return
+
+ var/mob/living/carbon/human/H = M
+
+ if (H.dna)
+ if (H.dna.species)
+ var/datum/species/S = H.dna.species
+
+ if (!istype(S))
+ unbuckle_all_mobs()
+ else
+ unbuckle_all_mobs()
+ else
+ unbuckle_all_mobs()
+
+ ..()
+
+/obj/structure/femur_breaker/can_be_unfasten_wrench(mob/user, silent)
+ if (LAZYLEN(buckled_mobs))
+ if (!silent)
+ to_chat(user, "Can't unfasten, someone's strapped in!")
+ return FAILED_UNFASTEN
+
+ if (current_action)
+ return FAILED_UNFASTEN
+
+ return ..()
+
+/obj/structure/femur_breaker/wrench_act(mob/living/user, obj/item/I)
+ if (current_action)
+ return
+
+ current_action = BREAKER_ACTION_WRENCH
+
+ if (do_after(user, BREAKER_WRENCH_DELAY, target = src))
+ current_action = 0
+ default_unfasten_wrench(user, I, 0)
+ setDir(SOUTH)
+ return TRUE
+ else
+ current_action = 0
+
+#undef BREAKER_ANIMATION_LENGTH
+#undef BREAKER_SLAT_RAISED
+#undef BREAKER_SLAT_MOVING
+#undef BREAKER_SLAT_DROPPED
+#undef BREAKER_ACTIVATE_DELAY
+#undef BREAKER_WRENCH_DELAY
+#undef BREAKER_ACTION_INUSE
+#undef BREAKER_ACTION_WRENCH
diff --git a/code/game/objects/structures/loom.dm b/code/game/objects/structures/loom.dm
new file mode 100644
index 0000000000..c4e1968e59
--- /dev/null
+++ b/code/game/objects/structures/loom.dm
@@ -0,0 +1,21 @@
+//Loom, turns raw cotton and durathread into their respective fabrics.
+
+/obj/structure/loom
+ name = "loom"
+ desc = "A simple device used to weave cloth and other thread-based fabrics together into usable material."
+ icon = 'icons/obj/hydroponics/equipment.dmi'
+ icon_state = "loom"
+ density = TRUE
+ anchored = TRUE
+
+/obj/structure/loom/attackby(obj/item/stack/sheet/W, mob/user)
+ if(W.is_fabric && W.amount > 1)
+ user.show_message("You start weaving the [W.name] through the loom..", 1)
+ if(W.use_tool(src, user, W.pull_effort))
+ new W.loom_result(drop_location())
+ user.show_message("You weave the [W.name] into a workable fabric.", 1)
+ W.amount = (W.amount - 2)
+ if(W.amount < 1)
+ qdel(W)
+ else
+ user.show_message("You need a valid fabric and at least 2 of said fabric before using this.", 1)
\ No newline at end of file
diff --git a/code/game/objects/structures/watercloset.dm b/code/game/objects/structures/watercloset.dm
index d70838a30b..46db567b10 100644
--- a/code/game/objects/structures/watercloset.dm
+++ b/code/game/objects/structures/watercloset.dm
@@ -537,7 +537,7 @@
if(istype(O, /obj/item/stack/medical/gauze))
var/obj/item/stack/medical/gauze/G = O
- new /obj/item/reagent_containers/glass/rag(src.loc)
+ new /obj/item/reagent_containers/rag(src.loc)
to_chat(user, "You tear off a strip of gauze and make a rag.")
G.use(1)
return
diff --git a/code/game/turfs/open.dm b/code/game/turfs/open.dm
index cff219c63e..f6d234b346 100644
--- a/code/game/turfs/open.dm
+++ b/code/game/turfs/open.dm
@@ -272,7 +272,7 @@
return 0
if(ishuman(C) && (lube&NO_SLIP_WHEN_WALKING))
var/mob/living/carbon/human/H = C
- if(!H.sprinting && H.getStaminaLoss() >= 20)
+ if(!H.sprinting && H.getStaminaLoss() <= 20)
return 0
if(!(lube&SLIDE_ICE))
to_chat(C, "You slipped[ O ? " on the [O.name]" : ""]!")
diff --git a/code/game/world.dm b/code/game/world.dm
index dedf822597..e9c8433006 100644
--- a/code/game/world.dm
+++ b/code/game/world.dm
@@ -137,7 +137,7 @@ GLOBAL_VAR(restart_counter)
// but those are both private, so let's put the commit info in the runtime
// log which is ultimately public.
log_runtime(GLOB.revdata.get_log_message())
-
+
/world/Topic(T, addr, master, key)
TGS_TOPIC //redirect to server tools if necessary
@@ -270,7 +270,8 @@ GLOBAL_VAR(restart_counter)
if (M.client)
n++
- features += "[SSmapping.config.map_name]" //CIT CHANGE - makes the hub entry display the current map
+ if(SSmapping.config) // this just stops the runtime, honk.
+ features += "[SSmapping.config.map_name]" //CIT CHANGE - makes the hub entry display the current map
if(get_security_level())//CIT CHANGE - makes the hub entry show the security level
features += "[get_security_level()] alert"
diff --git a/code/modules/admin/create_mob.dm b/code/modules/admin/create_mob.dm
index fad7410a6a..f66cda42dc 100644
--- a/code/modules/admin/create_mob.dm
+++ b/code/modules/admin/create_mob.dm
@@ -15,9 +15,9 @@
H.real_name = random_unique_name(H.gender)
H.name = H.real_name
H.underwear = random_underwear(H.gender)
- H.undie_color = random_color()
+ H.undie_color = random_short_color()
H.undershirt = random_undershirt(H.gender)
- H.shirt_color = random_color()
+ H.shirt_color = random_short_color()
H.skin_tone = random_skin_tone()
H.hair_style = random_hair_style(H.gender)
H.facial_hair_style = random_facial_hair_style(H.gender)
diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm
index 6fa118ab7f..d881044757 100644
--- a/code/modules/admin/topic.dm
+++ b/code/modules/admin/topic.dm
@@ -1882,14 +1882,14 @@
return
var/mob/M = locate(href_list["CentComReply"])
- usr.client.admin_headset_message(M, "CentCom")
+ usr.client.admin_headset_message(M, RADIO_CHANNEL_CENTCOM)
else if(href_list["SyndicateReply"])
if(!check_rights(R_ADMIN))
return
var/mob/M = locate(href_list["SyndicateReply"])
- usr.client.admin_headset_message(M, "Syndicate")
+ usr.client.admin_headset_message(M, RADIO_CHANNEL_SYNDICATE)
else if(href_list["HeadsetMessage"])
if(!check_rights(R_ADMIN))
diff --git a/code/modules/admin/verbs/adminpm.dm b/code/modules/admin/verbs/adminpm.dm
index 84e5ba4f82..5f3153d90f 100644
--- a/code/modules/admin/verbs/adminpm.dm
+++ b/code/modules/admin/verbs/adminpm.dm
@@ -6,7 +6,7 @@
set category = null
set name = "Admin PM Mob"
if(!holder)
- to_chat(src, "Error: Admin-PM-Context: Only administrators may use this command.")
+ to_chat(src, "Error: Admin-PM-Context: Only administrators may use this command.")
return
if( !ismob(M) || !M.client )
return
@@ -18,7 +18,7 @@
set category = "Admin"
set name = "Admin PM"
if(!holder)
- to_chat(src, "Error: Admin-PM-Panel: Only administrators may use this command.")
+ to_chat(src, "Error: Admin-PM-Panel: Only administrators may use this command.")
return
var/list/client/targets[0]
for(var/client/T)
@@ -37,7 +37,7 @@
/client/proc/cmd_ahelp_reply(whom)
if(prefs.muted & MUTE_ADMINHELP)
- to_chat(src, "Error: Admin-PM: You are unable to use admin PM-s (muted).")
+ to_chat(src, "Error: Admin-PM: You are unable to use admin PM-s (muted).")
return
var/client/C
if(istext(whom))
@@ -48,7 +48,7 @@
C = whom
if(!C)
if(holder)
- to_chat(src, "Error: Admin-PM: Client not found.")
+ to_chat(src, "Error: Admin-PM: Client not found.")
return
var/datum/admin_help/AH = C.current_ticket
@@ -65,12 +65,12 @@
//Fetching a message if needed. src is the sender and C is the target client
/client/proc/cmd_admin_pm(whom, msg)
if(prefs.muted & MUTE_ADMINHELP)
- to_chat(src, "Error: Admin-PM: You are unable to use admin PM-s (muted).")
+ to_chat(src, "Error: Admin-PM: You are unable to use admin PM-s (muted).")
return
if(!holder && !current_ticket) //no ticket? https://www.youtube.com/watch?v=iHSPf6x1Fdo
- to_chat(src, "You can no longer reply to this ticket, please open another one by using the Adminhelp verb if need be.")
- to_chat(src, "Message: [msg]")
+ to_chat(src, "You can no longer reply to this ticket, please open another one by using the Adminhelp verb if need be.")
+ to_chat(src, "Message: [msg]")
return
var/client/recipient
@@ -95,14 +95,14 @@
if(!msg)
return
if(holder)
- to_chat(src, "Error: Use the admin IRC channel, nerd.")
+ to_chat(src, "Error: Use the admin IRC channel, nerd.")
return
else
if(!recipient)
if(holder)
- to_chat(src, "Error: Admin-PM: Client not found.")
+ to_chat(src, "Error: Admin-PM: Client not found.")
if(msg)
to_chat(src, msg)
return
@@ -118,12 +118,12 @@
return
if(prefs.muted & MUTE_ADMINHELP)
- to_chat(src, "Error: Admin-PM: You are unable to use admin PM-s (muted).")
+ to_chat(src, "Error: Admin-PM: You are unable to use admin PM-s (muted).")
return
if(!recipient)
if(holder)
- to_chat(src, "Error: Admin-PM: Client not found.")
+ to_chat(src, "Error: Admin-PM: Client not found.")
else
current_ticket.MessageNoRecipient(msg)
return
@@ -145,15 +145,15 @@
var/keywordparsedmsg = keywords_lookup(msg)
if(irc)
- to_chat(src, "PM to-Admins: [rawmsg]")
+ to_chat(src, "PM to-Admins: [rawmsg]")
var/datum/admin_help/AH = admin_ticket_log(src, "Reply PM from-[key_name(src, TRUE, TRUE)] to IRC: [keywordparsedmsg]")
ircreplyamount--
send2irc("[AH ? "#[AH.id] " : ""]Reply: [ckey]", rawmsg)
else
if(recipient.holder)
if(holder) //both are admins
- to_chat(recipient, "Admin PM from-[key_name(src, recipient, 1)]: [keywordparsedmsg]")
- to_chat(src, "Admin PM to-[key_name(recipient, src, 1)]: [keywordparsedmsg]")
+ to_chat(recipient, "Admin PM from-[key_name(src, recipient, 1)]: [keywordparsedmsg]")
+ to_chat(src, "Admin PM to-[key_name(recipient, src, 1)]: [keywordparsedmsg]")
//omg this is dumb, just fill in both their tickets
var/interaction_message = "PM from-[key_name(src, recipient, 1)] to-[key_name(recipient, src, 1)]: [keywordparsedmsg]"
@@ -162,10 +162,10 @@
admin_ticket_log(recipient, interaction_message)
else //recipient is an admin but sender is not
- var/replymsg = "Reply PM from-[key_name(src, recipient, 1)]: [keywordparsedmsg]"
- admin_ticket_log(src, replymsg)
- to_chat(recipient, replymsg)
- to_chat(src, "PM to-Admins: [msg]")
+ var/replymsg = "Reply PM from-[key_name(src, recipient, 1)]: [keywordparsedmsg]"
+ admin_ticket_log(src, "[replymsg]")
+ to_chat(recipient, "[replymsg]")
+ to_chat(src, "PM to-Admins: [msg]")
//play the receiving admin the adminhelp sound (if they have them enabled)
if(recipient.prefs.toggles & SOUND_ADMINHELP)
@@ -177,11 +177,11 @@
new /datum/admin_help(msg, recipient, TRUE)
to_chat(recipient, "-- Administrator private message --")
- to_chat(recipient, "Admin PM from-[key_name(src, recipient, 0)]: [msg]")
- to_chat(recipient, "Click on the administrator's name to reply.")
- to_chat(src, "Admin PM to-[key_name(recipient, src, 1)]: [msg]")
+ to_chat(recipient, "Admin PM from-[key_name(src, recipient, 0)]: [msg]")
+ to_chat(recipient, "Click on the administrator's name to reply.")
+ to_chat(src, "Admin PM to-[key_name(recipient, src, 1)]: [msg]")
- admin_ticket_log(recipient, "PM From [key_name_admin(src)]: [keywordparsedmsg]")
+ admin_ticket_log(recipient, "PM From [key_name_admin(src)]: [keywordparsedmsg]")
//always play non-admin recipients the adminhelp sound
SEND_SOUND(recipient, sound('sound/effects/adminhelp.ogg'))
@@ -200,20 +200,20 @@
return
else //neither are admins
- to_chat(src, "Error: Admin-PM: Non-admin to non-admin PM communication is forbidden.")
+ to_chat(src, "Error: Admin-PM: Non-admin to non-admin PM communication is forbidden.")
return
if(irc)
log_admin_private("PM: [key_name(src)]->IRC: [rawmsg]")
for(var/client/X in GLOB.admins)
- to_chat(X, "PM: [key_name(src, X, 0)]->IRC: [keywordparsedmsg]")
+ to_chat(X, "PM: [key_name(src, X, 0)]->IRC: [keywordparsedmsg]")
else
window_flash(recipient, ignorepref = TRUE)
log_admin_private("PM: [key_name(src)]->[key_name(recipient)]: [rawmsg]")
//we don't use message_admins here because the sender/receiver might get it too
for(var/client/X in GLOB.admins)
if(X.key!=key && X.key!=recipient.key) //check client/X is an admin and isn't the sender or recipient
- to_chat(X, "PM: [key_name(src, X, 0)]->[key_name(recipient, X, 0)]: [keywordparsedmsg]" )
+ to_chat(X, "PM: [key_name(src, X, 0)]->[key_name(recipient, X, 0)]: [keywordparsedmsg]" )
@@ -296,10 +296,10 @@
msg = emoji_parse(msg)
to_chat(C, "-- Administrator private message --")
- to_chat(C, "Admin PM from-[adminname]: [msg]")
- to_chat(C, "Click on the administrator's name to reply.")
+ to_chat(C, "Admin PM from-[adminname]: [msg]")
+ to_chat(C, "Click on the administrator's name to reply.")
- admin_ticket_log(C, "PM From [irc_tagged]: [msg]")
+ admin_ticket_log(C, "PM From [irc_tagged]: [msg]")
window_flash(C, ignorepref = TRUE)
//always play non-admin recipients the adminhelp sound
diff --git a/code/modules/admin/verbs/borgpanel.dm b/code/modules/admin/verbs/borgpanel.dm
index 6295d4be43..c0445d588d 100644
--- a/code/modules/admin/verbs/borgpanel.dm
+++ b/code/modules/admin/verbs/borgpanel.dm
@@ -62,7 +62,7 @@
.["laws"] = borg.laws ? borg.laws.get_law_list(include_zeroth = TRUE) : list()
.["channels"] = list()
for (var/k in GLOB.radiochannels)
- if (k == "Common")
+ if (k == RADIO_CHANNEL_COMMON)
continue
.["channels"] += list(list("name" = k, "installed" = (k in borg.radio.channels)))
.["cell"] = borg.cell ? list("missing" = FALSE, "maxcharge" = borg.cell.maxcharge, "charge" = borg.cell.charge) : list("missing" = TRUE, "maxcharge" = 1, "charge" = 0)
@@ -164,15 +164,15 @@
if (channel in borg.radio.channels) // We're removing a channel
if (!borg.radio.keyslot) // There's no encryption key. This shouldn't happen but we can cope
borg.radio.channels -= channel
- if (channel == "Syndicate")
+ if (channel == RADIO_CHANNEL_SYNDICATE)
borg.radio.syndie = FALSE
- else if (channel == "CentCom")
+ else if (channel == RADIO_CHANNEL_CENTCOM)
borg.radio.independent = FALSE
else
borg.radio.keyslot.channels -= channel
- if (channel == "Syndicate")
+ if (channel == RADIO_CHANNEL_SYNDICATE)
borg.radio.keyslot.syndie = FALSE
- else if (channel == "CentCom")
+ else if (channel == RADIO_CHANNEL_CENTCOM)
borg.radio.keyslot.independent = FALSE
message_admins("[key_name_admin(user)] removed the [channel] radio channel from [ADMIN_LOOKUPFLW(borg)].")
log_admin("[key_name(user)] removed the [channel] radio channel from [key_name(borg)].")
@@ -180,9 +180,9 @@
if (!borg.radio.keyslot) // Assert that an encryption key exists
borg.radio.keyslot = new (borg.radio)
borg.radio.keyslot.channels[channel] = 1
- if (channel == "Syndicate")
+ if (channel == RADIO_CHANNEL_SYNDICATE)
borg.radio.keyslot.syndie = TRUE
- else if (channel == "CentCom")
+ else if (channel == RADIO_CHANNEL_CENTCOM)
borg.radio.keyslot.independent = TRUE
message_admins("[key_name_admin(user)] added the [channel] radio channel to [ADMIN_LOOKUPFLW(borg)].")
log_admin("[key_name(user)] added the [channel] radio channel to [key_name(borg)].")
diff --git a/code/modules/admin/verbs/randomverbs.dm b/code/modules/admin/verbs/randomverbs.dm
index 3f46e88920..f1d1cd90db 100644
--- a/code/modules/admin/verbs/randomverbs.dm
+++ b/code/modules/admin/verbs/randomverbs.dm
@@ -65,7 +65,7 @@
return
if (!sender)
- sender = input("Who is the message from?", "Sender") as null|anything in list("CentCom","Syndicate")
+ sender = input("Who is the message from?", "Sender") as null|anything in list(RADIO_CHANNEL_CENTCOM,RADIO_CHANNEL_SYNDICATE)
if(!sender)
return
@@ -298,7 +298,7 @@
if(candidates.len)
ckey = input("Pick the player you want to respawn as a xeno.", "Suitable Candidates") as null|anything in candidates
else
- to_chat(usr, "Error: create_xeno(): no suitable candidates.")
+ to_chat(usr, "Error: create_xeno(): no suitable candidates.")
if(!istext(ckey))
return 0
diff --git a/code/modules/antagonists/changeling/changeling.dm b/code/modules/antagonists/changeling/changeling.dm
index a1b9b53fe9..252e2b5cbe 100644
--- a/code/modules/antagonists/changeling/changeling.dm
+++ b/code/modules/antagonists/changeling/changeling.dm
@@ -353,7 +353,7 @@
/datum/antagonist/changeling/greet()
if (you_are_greet)
to_chat(owner.current, "You are [changelingID], a changeling! You have absorbed and taken the form of a human.")
- to_chat(owner.current, "Use say \":g message\" to communicate with your fellow changelings.")
+ to_chat(owner.current, "Use say \"[MODE_TOKEN_CHANGELING] message\" to communicate with your fellow changelings.")
to_chat(owner.current, "You must complete the following tasks:")
owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/ling_aler.ogg', 100, FALSE, pressure_affected = FALSE)
diff --git a/code/modules/antagonists/changeling/powers/hivemind.dm b/code/modules/antagonists/changeling/powers/hivemind.dm
index 1d7382d947..f7718d7708 100644
--- a/code/modules/antagonists/changeling/powers/hivemind.dm
+++ b/code/modules/antagonists/changeling/powers/hivemind.dm
@@ -1,8 +1,8 @@
-//HIVEMIND COMMUNICATION (:g)
+//HIVEMIND COMMUNICATION //MODE_TOKEN_CHANGELING / :g
/obj/effect/proc_holder/changeling/hivemind_comms
name = "Hivemind Communication"
desc = "We tune our senses to the airwaves to allow us to discreetly communicate and exchange DNA with other changelings."
- helptext = "We will be able to talk with other changelings with :g. Exchanged DNA do not count towards absorb objectives."
+ helptext = "We will be able to talk with other changelings with :g. Exchanged DNA do not count towards absorb objectives." //MODE_TOKEN_CHANGELING needs to be manually updated here.
dna_cost = 1
chemical_cost = -1
action_icon = 'icons/mob/actions/actions_xeno.dmi'
@@ -20,7 +20,7 @@
..()
var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
changeling.changeling_speak = 1
- to_chat(user, "Use say \":g message\" to communicate with the other changelings.")
+ to_chat(user, "Use say \"[MODE_TOKEN_CHANGELING] message\" to communicate with the other changelings.")
var/obj/effect/proc_holder/changeling/hivemind_upload/S1 = new
if(!changeling.has_sting(S1))
changeling.purchasedpowers+=S1
diff --git a/code/modules/antagonists/changeling/powers/linglink.dm b/code/modules/antagonists/changeling/powers/linglink.dm
index 70df78e3b4..971c811074 100644
--- a/code/modules/antagonists/changeling/powers/linglink.dm
+++ b/code/modules/antagonists/changeling/powers/linglink.dm
@@ -56,8 +56,8 @@
if(M.lingcheck() == LINGHIVE_LING)
to_chat(M, "We can sense a foreign presence in the hivemind...")
target.mind.linglink = 1
- target.say(":g AAAAARRRRGGGGGHHHHH!!")
- to_chat(target, "You can now communicate in the changeling hivemind, say \":g message\" to communicate!")
+ target.say("[MODE_TOKEN_CHANGELING] AAAAARRRRGGGGGHHHHH!!")
+ to_chat(target, "You can now communicate in the changeling hivemind, say \"[MODE_TOKEN_CHANGELING] message\" to communicate!")
target.reagents.add_reagent("salbutamol", 40) // So they don't choke to death while you interrogate them
sleep(1800)
SSblackbox.record_feedback("nested tally", "changeling_powers", 1, list("[name]", "[i]"))
diff --git a/code/modules/antagonists/changeling/powers/mutations.dm b/code/modules/antagonists/changeling/powers/mutations.dm
index 4e0595362c..c428c56d45 100644
--- a/code/modules/antagonists/changeling/powers/mutations.dm
+++ b/code/modules/antagonists/changeling/powers/mutations.dm
@@ -161,11 +161,13 @@
throwforce = 0 //Just to be on the safe side
throw_range = 0
throw_speed = 0
+ armour_penetration = 20
hitsound = 'sound/weapons/bladeslice.ogg'
attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut")
sharpness = IS_SHARP
var/can_drop = FALSE
var/fake = FALSE
+ total_mass = TOTAL_MASS_HAND_REPLACEMENT
/obj/item/melee/arm_blade/Initialize(mapload,silent,synthetic)
. = ..()
@@ -244,6 +246,7 @@
lefthand_file = 'icons/mob/inhands/antag/changeling_lefthand.dmi'
righthand_file = 'icons/mob/inhands/antag/changeling_righthand.dmi'
item_flags = NEEDS_PERMIT | ABSTRACT | DROPDEL | NOBLUDGEON
+ slot_flags = NONE
flags_1 = NONE
w_class = WEIGHT_CLASS_HUGE
ammo_type = /obj/item/ammo_casing/magic/tentacle
diff --git a/code/modules/antagonists/changeling/powers/strained_muscles.dm b/code/modules/antagonists/changeling/powers/strained_muscles.dm
index baeed8b0b2..bdbd38b92d 100644
--- a/code/modules/antagonists/changeling/powers/strained_muscles.dm
+++ b/code/modules/antagonists/changeling/powers/strained_muscles.dm
@@ -5,7 +5,7 @@
name = "Strained Muscles"
desc = "We evolve the ability to reduce the acid buildup in our muscles, allowing us to move much faster."
helptext = "The strain will make us tired, and we will rapidly become fatigued. Standard weight restrictions, like hardsuits, still apply. Cannot be used in lesser form."
- chemical_cost = 0
+ chemical_cost = 15
dna_cost = 1
req_human = 1
var/stacks = 0 //Increments every 5 seconds; damage increases over time
@@ -15,13 +15,16 @@
action_background_icon_state = "bg_ling"
/obj/effect/proc_holder/changeling/strained_muscles/sting_action(mob/living/carbon/user)
+ var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
active = !active
if(active)
to_chat(user, "Our muscles tense and strengthen.")
+ changeling.chem_recharge_slowdown += 0.5
else
REMOVE_TRAIT(user, TRAIT_GOTTAGOFAST, "changeling_muscles")
to_chat(user, "Our muscles relax.")
- if(stacks >= 10)
+ changeling.chem_recharge_slowdown -= 0.5
+ if(stacks >= 20)
to_chat(user, "We collapse in exhaustion.")
user.Knockdown(60)
user.emote("gasp")
@@ -42,9 +45,9 @@
stacks++
//user.take_bodypart_damage(stacks * 0.03, 0)
- user.staminaloss += stacks * 1.3 //At first the changeling may regenerate stamina fast enough to nullify fatigue, but it will stack
+ user.adjustStaminaLoss(stacks*1.3) //At first the changeling may regenerate stamina fast enough to nullify fatigue, but it will stack
- if(stacks == 11) //Warning message that the stacks are getting too high
+ if(stacks == 10) //Warning message that the stacks are getting too high
to_chat(user, "Our legs are really starting to hurt...")
sleep(40)
diff --git a/code/modules/antagonists/changeling/powers/tiny_prick.dm b/code/modules/antagonists/changeling/powers/tiny_prick.dm
index 5a701d8a96..c58d934d6d 100644
--- a/code/modules/antagonists/changeling/powers/tiny_prick.dm
+++ b/code/modules/antagonists/changeling/powers/tiny_prick.dm
@@ -62,13 +62,13 @@
/obj/effect/proc_holder/changeling/sting/transformation
- name = "Transformation Sting"
- desc = "We silently sting a human, injecting a retrovirus that forces them to transform."
- helptext = "The victim will transform much like a changeling would. Does not provide a warning to others. Mutations will not be transferred, and monkeys will become human. This ability is loud, and might cause our blood to react violently to heat."
+ name = "Temporary Transformation Sting"
+ desc = "We silently sting a human, injecting a chemical that forces them to transform into a chosen being for a limited time. Additional stings extend the duration."
+ helptext = "The victim will transform much like a changeling would for a limited time. Does not provide a warning to others. Mutations will not be transferred, and monkeys will become human. This ability is loud, and might cause our blood to react violently to heat."
sting_icon = "sting_transform"
- chemical_cost = 50
- dna_cost = 3
- loudness = 2
+ chemical_cost = 10
+ dna_cost = 2
+ loudness = 1
var/datum/changelingprofile/selected_dna = null
action_icon = 'icons/mob/actions/actions_changeling.dmi'
action_icon_state = "ling_sting_transform"
@@ -97,19 +97,19 @@
return 1
/obj/effect/proc_holder/changeling/sting/transformation/sting_action(mob/user, mob/target)
- log_combat(user, target, "stung", "transformation sting", " new identity is '[selected_dna.dna.real_name]'")
- var/datum/dna/NewDNA = selected_dna.dna
+
if(ismonkey(target))
to_chat(user, "Our genes cry out as we sting [target.name]!")
var/mob/living/carbon/C = target
. = TRUE
if(istype(C))
- C.real_name = NewDNA.real_name
- NewDNA.transfer_identity(C)
- if(ismonkey(C))
- C.humanize(TR_KEEPITEMS | TR_KEEPIMPLANTS | TR_KEEPORGANS | TR_KEEPDAMAGE | TR_KEEPVIRUS | TR_DEFAULTMSG)
- C.updateappearance(mutcolor_update=1)
+ if(C.reagents.has_reagent("changeling_sting_real"))
+ C.reagents.add_reagent("changeling_sting_real",120)
+ log_combat(user, target, "stung", "transformation sting", ", extending the duration.")
+ else
+ C.reagents.add_reagent("changeling_sting_real",120,list("desired_dna" = selected_dna.dna))
+ log_combat(user, target, "stung", "transformation sting", " new identity is '[selected_dna.dna.real_name]'")
/obj/effect/proc_holder/changeling/sting/false_armblade
@@ -230,24 +230,23 @@
/obj/effect/proc_holder/changeling/sting/LSD
name = "Hallucination Sting"
- desc = "Causes terror in the target."
- helptext = "We evolve the ability to sting a target with a powerful hallucinogenic chemical. The target does not notice they have been stung, and the effect begins after a few seconds."
+ desc = "Causes terror in the target and deals a minor amount of toxin damage."
+ helptext = "We evolve the ability to sting a target with a powerful toxic hallucinogenic chemical. The target does not notice they have been stung, and the effect begins instantaneously. This ability is somewhat loud, and carries a small risk of our blood gaining violent sensitivity to heat."
sting_icon = "sting_lsd"
chemical_cost = 10
dna_cost = 1
+ loudness = 1
action_icon = 'icons/mob/actions/actions_changeling.dmi'
action_icon_state = "ling_sting_lsd"
action_background_icon_state = "bg_ling"
-/obj/effect/proc_holder/changeling/sting/LSD/sting_action(mob/user, mob/living/carbon/target)
+/obj/effect/proc_holder/changeling/sting/LSD/sting_action(mob/user, mob/target)
log_combat(user, target, "stung", "LSD sting")
- addtimer(CALLBACK(src, .proc/hallucination_time, target), rand(100,200))
+ if(target.reagents)
+ target.reagents.add_reagent("regenerative_materia", 5)
+ target.reagents.add_reagent("mindbreaker", 5)
return TRUE
-/obj/effect/proc_holder/changeling/sting/LSD/proc/hallucination_time(mob/living/carbon/target)
- if(target)
- target.hallucination = max(90, target.hallucination)
-
/obj/effect/proc_holder/changeling/sting/cryo
name = "Cryogenic Sting"
desc = "We silently sting a human with a cocktail of chemicals that freeze them."
diff --git a/code/modules/antagonists/clockcult/clock_effects/spatial_gateway.dm b/code/modules/antagonists/clockcult/clock_effects/spatial_gateway.dm
index ea2ec4d6ef..5cf7ab7923 100644
--- a/code/modules/antagonists/clockcult/clock_effects/spatial_gateway.dm
+++ b/code/modules/antagonists/clockcult/clock_effects/spatial_gateway.dm
@@ -133,6 +133,9 @@
return FALSE
if(!uses)
return FALSE
+ if(!do_teleport(A, get_turf(linked_gateway), channel = TELEPORT_CHANNEL_CULT, forced = TRUE))
+ visible_message("[A] bounces off [src]!")
+ return FALSE
if(isliving(A))
var/mob/living/user = A
to_chat(user, "You pass through [src] and appear elsewhere!")
@@ -141,7 +144,6 @@
playsound(linked_gateway, 'sound/effects/empulse.ogg', 50, 1)
transform = matrix() * 1.5
linked_gateway.transform = matrix() * 1.5
- A.forceMove(get_turf(linked_gateway))
if(!no_cost)
uses = max(0, uses - 1)
linked_gateway.uses = max(0, linked_gateway.uses - 1)
diff --git a/code/modules/antagonists/clockcult/clock_helpers/slab_abilities.dm b/code/modules/antagonists/clockcult/clock_helpers/slab_abilities.dm
index 530c4c5662..23caa788d4 100644
--- a/code/modules/antagonists/clockcult/clock_helpers/slab_abilities.dm
+++ b/code/modules/antagonists/clockcult/clock_helpers/slab_abilities.dm
@@ -67,6 +67,7 @@
name = "replicant manacles"
desc = "Heavy manacles made out of freezing-cold metal. It looks like brass, but feels much more solid."
icon_state = "brass_manacles"
+ item_state = "brass_manacles"
item_flags = DROPDEL
/obj/item/restraints/handcuffs/clockwork/dropped(mob/user)
diff --git a/code/modules/antagonists/clockcult/clock_items/clockwork_armor.dm b/code/modules/antagonists/clockcult/clock_items/clockwork_armor.dm
index 54027266e5..0ac96c47f9 100644
--- a/code/modules/antagonists/clockcult/clock_items/clockwork_armor.dm
+++ b/code/modules/antagonists/clockcult/clock_items/clockwork_armor.dm
@@ -69,7 +69,7 @@
heat_protection = CHEST|GROIN|LEGS
resistance_flags = FIRE_PROOF | ACID_PROOF
armor = list("melee" = 60, "bullet" = 70, "laser" = -25, "energy" = 0, "bomb" = 60, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 100)
- allowed = list(/obj/item/clockwork, /obj/item/clothing/glasses/wraith_spectacles, /obj/item/clothing/glasses/judicial_visor, /obj/item/mmi/posibrain/soul_vessel, /obj/item/reagent_containers/food/drinks/holyoil)
+ allowed = list(/obj/item/clockwork, /obj/item/clothing/glasses/wraith_spectacles, /obj/item/clothing/glasses/judicial_visor, /obj/item/mmi/posibrain/soul_vessel, /obj/item/reagent_containers/food/drinks/bottle/holyoil)
/obj/item/clothing/suit/armor/clockwork/Initialize()
. = ..()
diff --git a/code/modules/antagonists/clockcult/clock_scriptures/scripture_drivers.dm b/code/modules/antagonists/clockcult/clock_scriptures/scripture_drivers.dm
index 552a747651..6d6b1fa9d0 100644
--- a/code/modules/antagonists/clockcult/clock_scriptures/scripture_drivers.dm
+++ b/code/modules/antagonists/clockcult/clock_scriptures/scripture_drivers.dm
@@ -27,7 +27,7 @@
to_chat(invoker, "Stargazers can't be built off-station.")
return
return ..()
-
+
//Integration Cog: Creates an integration cog that can be inserted into APCs to passively siphon power.
/datum/clockwork_scripture/create_object/integration_cog
@@ -224,12 +224,14 @@
. = ..()
/datum/clockwork_scripture/abscond/scripture_effects()
- var/take_pulling = invoker.pulling && isliving(invoker.pulling) && get_clockwork_power(ABSCOND_ABDUCTION_COST)
+ var/mob/living/pulled_mob = (invoker.pulling && isliving(invoker.pulling) && get_clockwork_power(ABSCOND_ABDUCTION_COST)) ? invoker.pulling : null
var/turf/T
if(GLOB.ark_of_the_clockwork_justiciar)
T = get_step(GLOB.ark_of_the_clockwork_justiciar, SOUTH)
else
T = get_turf(pick(GLOB.servant_spawns))
+ if(!do_teleport(invoker, T, channel = TELEPORT_CHANNEL_CULT, forced = TRUE))
+ return
invoker.visible_message("[invoker] flickers and phases out of existence!", \
"You feel a dizzying sense of vertigo as you're yanked back to Reebe!")
T.visible_message("[invoker] flickers and phases into existence!")
@@ -237,10 +239,9 @@
playsound(T, 'sound/magic/magic_missile.ogg', 50, TRUE)
do_sparks(5, TRUE, invoker)
do_sparks(5, TRUE, T)
- if(take_pulling)
+ if(pulled_mob && do_teleport(pulled_mob, T, channel = TELEPORT_CHANNEL_CULT, forced = TRUE))
adjust_clockwork_power(-special_power_cost)
- invoker.pulling.forceMove(T)
- invoker.forceMove(T)
+ invoker.start_pulling(pulled_mob) //forcemove resets pulls, so we need to re-pull
if(invoker.client)
animate(invoker.client, color = client_color, time = 25)
diff --git a/code/modules/antagonists/clockcult/clock_structures/ark_of_the_clockwork_justicar.dm b/code/modules/antagonists/clockcult/clock_structures/ark_of_the_clockwork_justicar.dm
index 2b1d9d5f02..56b36d13e6 100644
--- a/code/modules/antagonists/clockcult/clock_structures/ark_of_the_clockwork_justicar.dm
+++ b/code/modules/antagonists/clockcult/clock_structures/ark_of_the_clockwork_justicar.dm
@@ -131,10 +131,8 @@
if(!M || !M.current)
continue
if(isliving(M.current) && M.current.stat != DEAD)
- if(isAI(M.current))
- M.current.forceMove(get_step(get_step(src, NORTH),NORTH)) // AI too fat, must make sure it always ends up a 2 tiles north instead of on the ark.
- else
- M.current.forceMove(get_turf(src))
+ var/turf/t_turf = isAI(M.current) ? get_step(get_step(src, NORTH),NORTH) : get_turf(src) // AI too fat, must make sure it always ends up a 2 tiles north instead of on the ark.
+ do_teleport(M, t_turf, channel = TELEPORT_CHANNEL_CULT, forced = TRUE)
M.current.overlay_fullscreen("flash", /obj/screen/fullscreen/flash)
M.current.clear_fullscreen("flash", 5)
playsound(src, 'sound/magic/clockwork/invoke_general.ogg', 50, FALSE)
diff --git a/code/modules/antagonists/cult/blood_magic.dm b/code/modules/antagonists/cult/blood_magic.dm
index a5fd516a42..1dbae4ca98 100644
--- a/code/modules/antagonists/cult/blood_magic.dm
+++ b/code/modules/antagonists/cult/blood_magic.dm
@@ -490,11 +490,12 @@
to_chat(user, "The target rune is blocked. Attempting to teleport to it would be massively unwise.")
return
uses--
- user.visible_message("Dust flows from [user]'s hand, and [user.p_they()] disappear[user.p_s()] with a sharp crack!", \
- "You speak the words of the talisman and find yourself somewhere else!", "You hear a sharp crack.")
+ var/turf/origin = get_turf(user)
var/mob/living/L = target
- L.forceMove(dest)
- dest.visible_message("There is a boom of outrushing air as something appears above the rune!", null, "You hear a boom.")
+ if(do_teleport(L, dest, channel = TELEPORT_CHANNEL_CULT))
+ origin.visible_message("Dust flows from [user]'s hand, and [user.p_they()] disappear[user.p_s()] with a sharp crack!", \
+ "You speak the words of the talisman and find yourself somewhere else!", "You hear a sharp crack.")
+ dest.visible_message("There is a boom of outrushing air as something appears above the rune!", null, "You hear a boom.")
..()
//Shackles
@@ -654,15 +655,15 @@
if(H.stat == DEAD)
to_chat(user,"Only a revive rune can bring back the dead!")
return
- if(H.blood_volume < BLOOD_VOLUME_SAFE)
- var/restore_blood = BLOOD_VOLUME_SAFE - H.blood_volume
+ if(H.blood_volume < (BLOOD_VOLUME_SAFE*H.blood_ratio))
+ var/restore_blood = (BLOOD_VOLUME_SAFE*H.blood_ratio) - H.blood_volume
if(uses*2 < restore_blood)
H.blood_volume += uses*2
to_chat(user,"You use the last of your blood rites to restore what blood you could!")
uses = 0
return ..()
else
- H.blood_volume = BLOOD_VOLUME_SAFE
+ H.blood_volume = (BLOOD_VOLUME_SAFE*H.blood_ratio)
uses -= round(restore_blood/2)
to_chat(user,"Your blood rites have restored [H == user ? "your" : "[H.p_their()]"] blood to safe levels!")
var/overall_damage = H.getBruteLoss() + H.getFireLoss() + H.getToxLoss() + H.getOxyLoss()
@@ -697,7 +698,7 @@
if(H.cultslurring)
to_chat(user,"[H.p_their(TRUE)] blood has been tainted by an even stronger form of blood magic, it's no use to us like this!")
return
- if(H.blood_volume > BLOOD_VOLUME_SAFE)
+ if(H.blood_volume > (BLOOD_VOLUME_SAFE*H.blood_ratio))
H.blood_volume -= 100
uses += 50
user.Beam(H,icon_state="drainbeam",time=10)
@@ -798,4 +799,4 @@
to_chat(user, "Your hands glow with POWER OVERWHELMING!!!")
else
to_chat(user, "You need a free hand for this rite!")
- qdel(rite)
\ No newline at end of file
+ qdel(rite)
diff --git a/code/modules/antagonists/cult/cult_items.dm b/code/modules/antagonists/cult/cult_items.dm
index 9a17c3270b..25e3663c0b 100644
--- a/code/modules/antagonists/cult/cult_items.dm
+++ b/code/modules/antagonists/cult/cult_items.dm
@@ -105,7 +105,6 @@
inhand_x_dimension = 64
inhand_y_dimension = 64
actions_types = list()
- item_flags = SLOWS_WHILE_IN_HAND
var/datum/action/innate/dash/cult/jaunt
var/datum/action/innate/cult/spin2win/linked_action
var/spinning = FALSE
@@ -568,7 +567,7 @@
var/mob/living/carbon/C = user
if(C.pulling)
var/atom/movable/pulled = C.pulling
- pulled.forceMove(T)
+ do_teleport(pulled, T, channel = TELEPORT_CHANNEL_CULT)
. = pulled
/obj/item/cult_shift/attack_self(mob/user)
@@ -593,13 +592,12 @@
new /obj/effect/temp_visual/dir_setting/cult/phase/out(mobloc, C.dir)
var/atom/movable/pulled = handle_teleport_grab(destination, C)
- C.forceMove(destination)
- if(pulled)
- C.start_pulling(pulled) //forcemove resets pulls, so we need to re-pull
-
- new /obj/effect/temp_visual/dir_setting/cult/phase(destination, C.dir)
- playsound(destination, 'sound/effects/phasein.ogg', 25, 1)
- playsound(destination, "sparks", 50, 1)
+ if(do_teleport(C, destination, channel = TELEPORT_CHANNEL_CULT))
+ if(pulled)
+ C.start_pulling(pulled) //forcemove resets pulls, so we need to re-pull
+ new /obj/effect/temp_visual/dir_setting/cult/phase(destination, C.dir)
+ playsound(destination, 'sound/effects/phasein.ogg', 25, 1)
+ playsound(destination, "sparks", 50, 1)
else
to_chat(C, "The veil cannot be torn here!")
diff --git a/code/modules/antagonists/cult/cult_structures.dm b/code/modules/antagonists/cult/cult_structures.dm
index 64d57c2f94..499d7a861e 100644
--- a/code/modules/antagonists/cult/cult_structures.dm
+++ b/code/modules/antagonists/cult/cult_structures.dm
@@ -188,7 +188,7 @@
var/mob/living/simple_animal/M = L
if(M.health < M.maxHealth)
M.adjustHealth(-3)
- if(ishuman(L) && L.blood_volume < BLOOD_VOLUME_NORMAL)
+ if(ishuman(L) && L.blood_volume < (BLOOD_VOLUME_NORMAL * L.blood_ratio))
L.blood_volume += 1.0
CHECK_TICK
if(last_corrupt <= world.time)
diff --git a/code/modules/antagonists/cult/runes.dm b/code/modules/antagonists/cult/runes.dm
index 7619f489ce..cfb834fd2f 100644
--- a/code/modules/antagonists/cult/runes.dm
+++ b/code/modules/antagonists/cult/runes.dm
@@ -244,13 +244,14 @@ structure_check() searches for nearby cultist structures required for the invoca
to_chat(M, "Something is shielding [convertee]'s mind!")
log_game("Offer rune failed - convertee had anti-magic")
return 0
- to_chat(convertee, "Your blood pulses. Your head throbs. The world goes red. All at once you are aware of a horrible, horrible, truth. The veil of reality has been ripped away \
- and something evil takes root.")
- to_chat(convertee, "Do you wish to embrace the Geometer of Blood? Click here to become a follower of Nar'sie. Or you could choose to continue resisting and suffer a fate worse than death...")
+ to_chat(convertee, "The world goes red. All at once you are aware of an evil, eldritch truth taking roots into your mind.\n\
+ Click here to become a follower of Nar'sie, or suffer a fate worse than death.")
+ INVOKE_ASYNC(src, .proc/optinalert, convertee)
currentconversionman = convertee
- conversiontimeout = world.time + (10 SECONDS)
- convertee.Stun(100)
+ conversiontimeout = world.time + (14 SECONDS)
+ convertee.Stun(140)
ADD_TRAIT(convertee, TRAIT_MUTE, "conversionrune")
+ flash_color(convertee, list("#960000", "#960000", "#960000", rgb(0,0,0)), 50)
conversionresult = FALSE
while(world.time < conversiontimeout && convertee && !conversionresult)
stoplag(1)
@@ -283,6 +284,17 @@ structure_check() searches for nearby cultist structures required for the invoca
H.cultslurring = 0
return 1
+/obj/effect/rune/convert/proc/optinalert(mob/living/convertee)
+ var/alert = alert(convertee, "Will you embrace the Geometer of Blood or perish in futile resistance?", "Choose your own fate", "Join the Blood Cult", "Suffer a horrible demise")
+ if(alert == "Join the Blood Cult")
+ signmeup(convertee)
+
+/obj/effect/rune/convert/proc/signmeup(mob/living/convertee)
+ if(currentconversionman == usr)
+ conversionresult = TRUE
+ else
+ to_chat(usr, "Your fate has already been set in stone.")
+
/obj/effect/rune/convert/proc/do_sacrifice(mob/living/sacrificial, list/invokers, force_a_sac)
var/mob/living/first_invoker = invokers[1]
if(!first_invoker)
@@ -335,11 +347,7 @@ structure_check() searches for nearby cultist structures required for the invoca
/obj/effect/rune/convert/Topic(href, href_list)
if(href_list["signmeup"])
- if(currentconversionman == usr)
- conversionresult = TRUE
- else
- to_chat(usr, "Your fate has already been set in stone.")
-
+ signmeup(usr)
/obj/effect/rune/empower
cultist_name = "Empower"
@@ -414,6 +422,7 @@ structure_check() searches for nearby cultist structures required for the invoca
return
var/movedsomething = FALSE
var/moveuserlater = FALSE
+ var/movesuccess = FALSE
for(var/atom/movable/A in T)
if(ishuman(A))
new /obj/effect/temp_visual/dir_setting/cult/phase/out(T, A.dir)
@@ -424,20 +433,26 @@ structure_check() searches for nearby cultist structures required for the invoca
continue
if(!A.anchored)
movedsomething = TRUE
- A.forceMove(target)
+ if(do_teleport(A, target, forceMove = TRUE, channel = TELEPORT_CHANNEL_CULT))
+ movesuccess = TRUE
if(movedsomething)
..()
- visible_message("There is a sharp crack of inrushing air, and everything above the rune disappears!", null, "You hear a sharp crack.")
- to_chat(user, "You[moveuserlater ? "r vision blurs, and you suddenly appear somewhere else":" send everything above the rune away"].")
if(moveuserlater)
- user.forceMove(target)
+ if(do_teleport(user, target, channel = TELEPORT_CHANNEL_CULT))
+ movesuccess = TRUE
+ if(movesuccess)
+ visible_message("There is a sharp crack of inrushing air, and everything above the rune disappears!", null, "You hear a sharp crack.")
+ to_chat(user, "You[moveuserlater ? "r vision blurs, and you suddenly appear somewhere else":" send everything above the rune away"].")
+ else
+ to_chat(user, "You[moveuserlater ? "r vision blurs briefly, but nothing happens":" try send everything above the rune away, but the teleportation fails"].")
if(is_mining_level(z) && !is_mining_level(target.z)) //No effect if you stay on lavaland
actual_selected_rune.handle_portal("lava")
else
var/area/A = get_area(T)
if(A.map_name == "Space")
actual_selected_rune.handle_portal("space", T)
- target.visible_message("There is a boom of outrushing air as something appears above the rune!", null, "You hear a boom.")
+ if(movesuccess)
+ target.visible_message("There is a boom of outrushing air as something appears above the rune!", null, "You hear a boom.")
else
fail_invoke()
diff --git a/code/modules/antagonists/disease/disease_disease.dm b/code/modules/antagonists/disease/disease_disease.dm
index 21d0381982..b4b8ac0956 100644
--- a/code/modules/antagonists/disease/disease_disease.dm
+++ b/code/modules/antagonists/disease/disease_disease.dm
@@ -51,7 +51,7 @@
if(cures.len)
return
var/list/not_used = advance_cures.Copy()
- cures = list(pick_n_take(not_used), pick_n_take(not_used))
+ cures = list(pick(pick_n_take(not_used)), pick(pick_n_take(not_used)))
// Get the cure name from the cure_id
var/datum/reagent/D1 = GLOB.chemical_reagents_list[cures[1]]
diff --git a/code/modules/antagonists/greybois/greybois.dm b/code/modules/antagonists/greybois/greybois.dm
new file mode 100644
index 0000000000..b5e18045e8
--- /dev/null
+++ b/code/modules/antagonists/greybois/greybois.dm
@@ -0,0 +1,23 @@
+/datum/antagonist/greybois
+ name = "Emergency Assistant"
+ show_name_in_check_antagonists = TRUE
+ show_in_antagpanel = FALSE
+ var/mission = "Assist the station."
+ var/datum/outfit/outfit = /datum/outfit/ert/greybois
+
+/datum/antagonist/greybois/greygod
+ outfit = /datum/outfit/ert/greybois/greygod
+
+/datum/antagonist/greybois/greet()
+ to_chat(owner, "You are an Emergency Assistant.")
+ to_chat(owner, "Central Command is sending you to [station_name()] with the task: [mission]")
+
+/datum/antagonist/greybois/on_gain()
+ equipERT()
+ . = ..()
+
+/datum/antagonist/greybois/proc/equipERT()
+ var/mob/living/carbon/human/H = owner.current
+ if(!istype(H))
+ return
+ H.equipOutfit(outfit)
diff --git a/code/modules/antagonists/nukeop/equipment/nuclear_challenge.dm b/code/modules/antagonists/nukeop/equipment/nuclear_challenge.dm
index c616459bd1..edae8a4240 100644
--- a/code/modules/antagonists/nukeop/equipment/nuclear_challenge.dm
+++ b/code/modules/antagonists/nukeop/equipment/nuclear_challenge.dm
@@ -5,6 +5,7 @@
#define CHALLENGE_SHUTTLE_DELAY 15000 // 25 minutes, so the ops have at least 5 minutes before the shuttle is callable.
GLOBAL_LIST_EMPTY(jam_on_wardec)
+GLOBAL_VAR_INIT(war_declared, FALSE)
/obj/item/nuclear_challenge
name = "Declaration of War (Challenge Mode)"
@@ -61,8 +62,13 @@ GLOBAL_LIST_EMPTY(jam_on_wardec)
for(var/obj/machinery/computer/camera_advanced/shuttle_docker/D in GLOB.jam_on_wardec)
D.jammed = TRUE
+
+ GLOB.war_declared = TRUE
+ var/list/nukeops = get_antag_minds(/datum/antagonist/nukeop)
+ var/actual_players = GLOB.joined_player_list.len - nukeops.len
+
+ new uplink_type(get_turf(user), user.key, CHALLENGE_TELECRYSTALS + CEILING(PLAYER_SCALING * actual_players, 1))
- new uplink_type(get_turf(user), user.key, CHALLENGE_TELECRYSTALS + CEILING(PLAYER_SCALING * GLOB.player_list.len, 1))
CONFIG_SET(number/shuttle_refuel_delay, max(CONFIG_GET(number/shuttle_refuel_delay), CHALLENGE_SHUTTLE_DELAY))
SSblackbox.record_feedback("amount", "nuclear_challenge_mode", 1)
@@ -72,7 +78,10 @@ GLOBAL_LIST_EMPTY(jam_on_wardec)
if(declaring_war)
to_chat(user, "You are already in the process of declaring war! Make your mind up.")
return FALSE
- if(GLOB.player_list.len < CHALLENGE_MIN_PLAYERS)
+
+ var/list/nukeops = get_antag_minds(/datum/antagonist/nukeop)
+ var/actual_players = GLOB.joined_player_list.len - nukeops.len
+ if(actual_players < CHALLENGE_MIN_PLAYERS)
to_chat(user, "The enemy crew is too small to be worth declaring war on.")
return FALSE
if(!user.onSyndieBase())
diff --git a/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm b/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm
index ade5458765..add3c1d9b0 100644
--- a/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm
+++ b/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm
@@ -373,6 +373,11 @@
S.switch_mode_to(TRACK_INFILTRATOR)
countdown.start()
set_security_level("delta")
+
+ if(GLOB.war_declared)
+ var/area/A = get_area(src)
+ priority_announce("Alert: Unexpected increase in radiation levels near [A.name] ([src.x],[src.y],[src.z]). Please send an authorized radiation specialist to investigate.", "Sensory Nuclear Indexer Telemetry Calculation Helper")
+
else
detonation_timer = null
set_security_level(previous_level)
diff --git a/code/modules/antagonists/swarmer/swarmer.dm b/code/modules/antagonists/swarmer/swarmer.dm
index 9fb2c3e2b7..87cee7586d 100644
--- a/code/modules/antagonists/swarmer/swarmer.dm
+++ b/code/modules/antagonists/swarmer/swarmer.dm
@@ -488,7 +488,7 @@
S.set_up(4,0,get_turf(target))
S.start()
playsound(src,'sound/effects/sparks4.ogg',50,1)
- do_teleport(target, F, 0)
+ do_teleport(target, F, 0, channel = TELEPORT_CHANNEL_BLUESPACE)
/mob/living/simple_animal/hostile/swarmer/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = FALSE, tesla_shock = FALSE, illusion = FALSE, stun = TRUE)
if(!tesla_shock)
diff --git a/code/modules/antagonists/traitor/IAA/internal_affairs.dm b/code/modules/antagonists/traitor/IAA/internal_affairs.dm
index 051bf74705..f2e6566e8f 100644
--- a/code/modules/antagonists/traitor/IAA/internal_affairs.dm
+++ b/code/modules/antagonists/traitor/IAA/internal_affairs.dm
@@ -244,10 +244,12 @@
to_chat(owner.current, "Your target has been framed for [crime], and you have been tasked with eliminating them to prevent them defending themselves in court.")
to_chat(owner.current, "Any damage you cause will be a further embarrassment to Nanotrasen, so you have no limits on collateral damage.")
to_chat(owner.current, " You have been provided with a standard uplink to accomplish your task. ")
+ to_chat(owner.current, "By no means reveal that you, or any other NT employees, are undercover agents.")
else
to_chat(owner.current, "Your target is suspected of [crime], and you have been tasked with eliminating them by any means necessary to avoid a costly and embarrassing public trial.")
to_chat(owner.current, "While you have a license to kill, unneeded property damage or loss of employee life will lead to your contract being terminated.")
to_chat(owner.current, "For the sake of plausible deniability, you have been equipped with an array of captured Syndicate weaponry available via uplink.")
+ to_chat(owner.current, "By no means reveal that you, or any other NT employees, are undercover agents.")
to_chat(owner.current, "Finally, watch your back. Your target has friends in high places, and intel suggests someone may have taken out a contract of their own to protect them.")
owner.announce_objectives()
diff --git a/code/modules/antagonists/valentines/valentine.dm b/code/modules/antagonists/valentines/valentine.dm
index 31e69b32c2..21e54374a4 100644
--- a/code/modules/antagonists/valentines/valentine.dm
+++ b/code/modules/antagonists/valentines/valentine.dm
@@ -27,6 +27,7 @@
var/mob/living/L = owner
L.remove_status_effect(STATUS_EFFECT_INLOVE)
+
/datum/antagonist/valentine/greet()
to_chat(owner, "You're on a date with [date.name]! Protect [date.p_them()] at all costs. This takes priority over all other loyalties.")
@@ -42,4 +43,21 @@
if(objectives_complete)
return "[owner.name] protected [owner.p_their()] date"
else
- return "[owner.name] date failed!"
\ No newline at end of file
+ return "[owner.name] date failed!"
+
+//Just so it's distinct, basically.
+/datum/antagonist/valentine/chem/greet()
+ to_chat(owner, "You're in love with [date.name]! Protect [date.p_them()] at all costs. This takes priority over all other loyalties.")
+
+/datum/antagonist/valentine/chem/roundend_report()
+ var/objectives_complete = TRUE
+ if(owner.objectives.len)
+ for(var/datum/objective/objective in owner.objectives)
+ if(!objective.check_completion())
+ objectives_complete = FALSE
+ break
+
+ if(objectives_complete)
+ return "[owner.name] protected [owner.p_their()] love: [date.name]! What a cutie!"
+ else
+ return "[owner.name] date failed!"
diff --git a/code/modules/antagonists/wizard/equipment/artefact.dm b/code/modules/antagonists/wizard/equipment/artefact.dm
index 7cfefd5413..8642484895 100644
--- a/code/modules/antagonists/wizard/equipment/artefact.dm
+++ b/code/modules/antagonists/wizard/equipment/artefact.dm
@@ -385,9 +385,11 @@
/obj/item/warpwhistle/attack_self(mob/living/carbon/user)
if(!istype(user) || on_cooldown)
return
+ var/turf/T = get_turf(user)
+ if(!T)
+ return
on_cooldown = TRUE
last_user = user
- var/turf/T = get_turf(user)
playsound(T,'sound/magic/warpwhistle.ogg', 200, 1)
user.canmove = FALSE
new /obj/effect/temp_visual/tornado(T)
@@ -402,9 +404,15 @@
return
var/breakout = 0
while(breakout < 50)
+ if(!T)
+ end_effect(user)
+ return
var/turf/potential_T = find_safe_turf()
+ if(!potential_T)
+ end_effect(user)
+ return
if(T.z != potential_T.z || abs(get_dist_euclidian(potential_T,T)) > 50 - breakout)
- user.forceMove(potential_T)
+ do_teleport(user, potential_T, channel = TELEPORT_CHANNEL_MAGIC)
user.canmove = 0
T = potential_T
break
diff --git a/code/modules/assembly/flash.dm b/code/modules/assembly/flash.dm
index b1aa63c242..186eb1b024 100644
--- a/code/modules/assembly/flash.dm
+++ b/code/modules/assembly/flash.dm
@@ -12,6 +12,7 @@
crit_fail = FALSE //Is the flash burnt out?
light_color = LIGHT_COLOR_WHITE
light_power = FLASH_LIGHT_POWER
+ var/flashing_overlay = "flash-f"
var/times_used = 0 //Number of times it's been used.
var/burnout_resistance = 0
var/last_used = 0 //last world.time it was used.
@@ -36,8 +37,8 @@
add_overlay("flashburnt")
attached_overlays += "flashburnt"
if(flash)
- add_overlay("flash-f")
- attached_overlays += "flash-f"
+ add_overlay(flashing_overlay)
+ attached_overlays += flashing_overlay
addtimer(CALLBACK(src, .proc/update_icon), 5)
if(holder)
holder.update_icon()
@@ -313,3 +314,50 @@
/obj/item/assembly/flash/shield/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
activate()
return ..()
+
+//ported from tg - check to make sure it can't appear where it's not supposed to.
+/obj/item/assembly/flash/hypnotic
+ desc = "A modified flash device, programmed to emit a sequence of subliminal flashes that can send a vulnerable target into a hypnotic trance."
+ flashing_overlay = "flash-hypno" //I cannot find this icon no matter how hard I look in tg, so I might just make my own.
+ light_color = LIGHT_COLOR_PINK
+ cooldown = 20
+
+/obj/item/assembly/flash/hypnotic/burn_out()
+ return
+
+/obj/item/assembly/flash/hypnotic/flash_carbon(mob/living/carbon/M, mob/user, power = 15, targeted = TRUE, generic_message = FALSE)
+ if(!istype(M))
+ return
+ if(user)
+ log_combat(user, M, "[targeted? "hypno-flashed(targeted)" : "hypno-flashed(AOE)"]", src)
+ else //caused by emp/remote signal
+ M.log_message("was [targeted? "hypno-flashed(targeted)" : "hypno-flashed(AOE)"]",LOG_ATTACK)
+ if(generic_message && M != user)
+ to_chat(M, "[src] emits a soothing light...")
+ if(targeted)
+ if(M.flash_act(1, 1))
+ var/hypnosis = FALSE
+ if(M.hypnosis_vulnerable())
+ hypnosis = TRUE
+ if(user)
+ user.visible_message("[user] blinds [M] with the flash!", "You hypno-flash [M]!")
+
+ if(!hypnosis)
+ to_chat(M, "The light makes you feel oddly relaxed...")
+ M.confused += min(M.confused + 10, 20)
+ M.dizziness += min(M.dizziness + 10, 20)
+ M.drowsyness += min(M.drowsyness + 10, 20)
+ M.apply_status_effect(STATUS_EFFECT_PACIFY, 100)
+ else
+ M.apply_status_effect(/datum/status_effect/trance, 200, TRUE)
+
+ else if(user)
+ user.visible_message("[user] fails to blind [M] with the flash!", "You fail to hypno-flash [M]!")
+ else
+ to_chat(M, "[src] fails to blind you!")
+
+ else if(M.flash_act())
+ to_chat(M, "Such a pretty light...")
+ M.confused += min(M.confused + 4, 20)
+ M.dizziness += min(M.dizziness + 4, 20)
+ M.drowsyness += min(M.drowsyness + 4, 20)
diff --git a/code/modules/atmospherics/gasmixtures/gas_mixture.dm b/code/modules/atmospherics/gasmixtures/gas_mixture.dm
index 9858db2abb..0d9c0730c1 100644
--- a/code/modules/atmospherics/gasmixtures/gas_mixture.dm
+++ b/code/modules/atmospherics/gasmixtures/gas_mixture.dm
@@ -38,8 +38,11 @@ GLOBAL_LIST_INIT(meta_gas_fusions, meta_gas_fusion_list())
for(var/id in cached_gases)
. += cached_gases[id] * cached_gasheats[id]
-/datum/gas_mixture/turf/heat_capacity()
- . = ..()
+/datum/gas_mixture/turf/heat_capacity() // Same as above except vacuums return HEAT_CAPACITY_VACUUM
+ var/list/cached_gases = gases
+ var/list/cached_gasheats = GLOB.meta_gas_specific_heats
+ for(var/id in cached_gases)
+ . += cached_gases[id] * cached_gasheats[id]
if(!.)
. += HEAT_CAPACITY_VACUUM //we want vacuums in turfs to have the same heat capacity as space
@@ -331,22 +334,19 @@ GLOBAL_LIST_INIT(meta_gas_fusions, meta_gas_fusion_list())
/datum/gas_mixture/react(datum/holder)
. = NO_REACTION
var/list/cached_gases = gases
- if(!cached_gases.len)
+ if(!length(cached_gases))
return
- var/possible
+ var/list/reactions = list()
for(var/I in cached_gases)
- if(GLOB.nonreactive_gases[I])
- continue
- possible = TRUE
- break
- if(!possible)
+ reactions += SSair.gas_reactions[I]
+ if(!length(reactions))
return
reaction_results = new
var/temp = temperature
var/ener = THERMAL_ENERGY(src)
reaction_loop:
- for(var/r in SSair.gas_reactions)
+ for(var/r in reactions)
var/datum/gas_reaction/reaction = r
var/list/min_reqs = reaction.min_requirements
@@ -376,14 +376,11 @@ GLOBAL_LIST_INIT(meta_gas_fusions, meta_gas_fusion_list())
continue reaction_loop
//at this point, all requirements for the reaction are satisfied. we can now react()
*/
-
. |= reaction.react(src, holder)
if (. & STOP_REACTIONS)
break
if(.)
GAS_GARBAGE_COLLECT(gases)
- if(temperature < TCMB) //just for safety
- temperature = TCMB
//Takes the amount of the gas you want to PP as an argument
//So I don't have to do some hacky switches/defines/magic strings
diff --git a/code/modules/atmospherics/gasmixtures/gas_types.dm b/code/modules/atmospherics/gasmixtures/gas_types.dm
index d628826b01..19f7bff965 100644
--- a/code/modules/atmospherics/gasmixtures/gas_types.dm
+++ b/code/modules/atmospherics/gasmixtures/gas_types.dm
@@ -78,22 +78,26 @@ GLOBAL_LIST_INIT(nonreactive_gases, typecacheof(list(/datum/gas/oxygen, /datum/g
var/moles_visible = null
var/dangerous = FALSE //currently used by canisters
var/fusion_power = 0 //How much the gas accelerates a fusion reaction
+ var/rarity = 0 // relative rarity compared to other gases, used when setting up the reactions list.
/datum/gas/oxygen
id = "o2"
specific_heat = 20
name = "Oxygen"
+ rarity = 900
/datum/gas/nitrogen
id = "n2"
specific_heat = 20
name = "Nitrogen"
+ rarity = 1000
/datum/gas/carbon_dioxide //what the fuck is this?
id = "co2"
specific_heat = 30
name = "Carbon Dioxide"
fusion_power = 3
+ rarity = 700
/datum/gas/plasma
id = "plasma"
@@ -102,6 +106,7 @@ GLOBAL_LIST_INIT(nonreactive_gases, typecacheof(list(/datum/gas/oxygen, /datum/g
gas_overlay = "plasma"
moles_visible = MOLES_GAS_VISIBLE
dangerous = TRUE
+ rarity = 800
/datum/gas/water_vapor
id = "water_vapor"
@@ -110,6 +115,7 @@ GLOBAL_LIST_INIT(nonreactive_gases, typecacheof(list(/datum/gas/oxygen, /datum/g
gas_overlay = "water_vapor"
moles_visible = MOLES_GAS_VISIBLE
fusion_power = 8
+ rarity = 500
/datum/gas/hypernoblium
id = "nob"
@@ -118,6 +124,7 @@ GLOBAL_LIST_INIT(nonreactive_gases, typecacheof(list(/datum/gas/oxygen, /datum/g
gas_overlay = "freon"
moles_visible = MOLES_GAS_VISIBLE
dangerous = TRUE
+ rarity = 50
/datum/gas/nitrous_oxide
id = "n2o"
@@ -126,6 +133,7 @@ GLOBAL_LIST_INIT(nonreactive_gases, typecacheof(list(/datum/gas/oxygen, /datum/g
gas_overlay = "nitrous_oxide"
moles_visible = MOLES_GAS_VISIBLE * 2
dangerous = TRUE
+ rarity = 600
/datum/gas/nitryl
id = "no2"
@@ -135,6 +143,7 @@ GLOBAL_LIST_INIT(nonreactive_gases, typecacheof(list(/datum/gas/oxygen, /datum/g
moles_visible = MOLES_GAS_VISIBLE
dangerous = TRUE
fusion_power = 15
+ rarity = 100
/datum/gas/tritium
id = "tritium"
@@ -144,6 +153,7 @@ GLOBAL_LIST_INIT(nonreactive_gases, typecacheof(list(/datum/gas/oxygen, /datum/g
moles_visible = MOLES_GAS_VISIBLE
dangerous = TRUE
fusion_power = 1
+ rarity = 300
/datum/gas/bz
id = "bz"
@@ -151,18 +161,21 @@ GLOBAL_LIST_INIT(nonreactive_gases, typecacheof(list(/datum/gas/oxygen, /datum/g
name = "BZ"
dangerous = TRUE
fusion_power = 8
+ rarity = 400
/datum/gas/stimulum
id = "stim"
specific_heat = 5
name = "Stimulum"
fusion_power = 7
+ rarity = 1
/datum/gas/pluoxium
id = "pluox"
specific_heat = 80
name = "Pluoxium"
fusion_power = 10
+ rarity = 200
/datum/gas/miasma
id = "miasma"
@@ -171,6 +184,7 @@ GLOBAL_LIST_INIT(nonreactive_gases, typecacheof(list(/datum/gas/oxygen, /datum/g
name = "Miasma"
gas_overlay = "miasma"
moles_visible = MOLES_GAS_VISIBLE * 60
+ rarity = 250
/obj/effect/overlay/gas
icon = 'icons/effects/atmospherics.dmi'
diff --git a/code/modules/atmospherics/gasmixtures/reactions.dm b/code/modules/atmospherics/gasmixtures/reactions.dm
index ef0a422079..5ad97fb7c8 100644
--- a/code/modules/atmospherics/gasmixtures/reactions.dm
+++ b/code/modules/atmospherics/gasmixtures/reactions.dm
@@ -1,19 +1,36 @@
//All defines used in reactions are located in ..\__DEFINES\reactions.dm
/proc/init_gas_reactions()
- var/list/reaction_types = list()
+ . = list()
+ for(var/type in subtypesof(/datum/gas))
+ .[type] = list()
+
for(var/r in subtypesof(/datum/gas_reaction))
var/datum/gas_reaction/reaction = r
- if(!initial(reaction.exclude))
- reaction_types += reaction
- reaction_types = sortList(reaction_types, /proc/cmp_gas_reactions)
+ if(initial(reaction.exclude))
+ continue
+ reaction = new r
+ var/datum/gas/reaction_key
+ for (var/req in reaction.min_requirements)
+ if (ispath(req))
+ var/datum/gas/req_gas = req
+ if (!reaction_key || initial(reaction_key.rarity) > initial(req_gas.rarity))
+ reaction_key = req_gas
+ .[reaction_key] += list(reaction)
+ sortTim(., /proc/cmp_gas_reactions, TRUE)
- . = list()
- for(var/path in reaction_types)
- . += new path
-
-/proc/cmp_gas_reactions(datum/gas_reaction/a, datum/gas_reaction/b) //sorts in descending order of priority
- return initial(b.priority) - initial(a.priority)
+/proc/cmp_gas_reactions(list/datum/gas_reaction/a, list/datum/gas_reaction/b) // compares lists of reactions by the maximum priority contained within the list
+ if (!length(a) || !length(b))
+ return length(b) - length(a)
+ var/maxa
+ var/maxb
+ for (var/datum/gas_reaction/R in a)
+ if (R.priority > maxa)
+ maxa = R.priority
+ for (var/datum/gas_reaction/R in b)
+ if (R.priority > maxb)
+ maxb = R.priority
+ return maxb - maxa
/datum/gas_reaction
//regarding the requirements lists: the minimum or maximum requirements must be non-zero.
@@ -364,7 +381,7 @@
cached_gases[/datum/gas/nitrous_oxide] -= reaction_efficency
cached_gases[/datum/gas/plasma] -= 2*reaction_efficency
- SSresearch.science_tech.add_point_type(TECHWEB_POINT_TYPE_DEFAULT, (reaction_efficency**0.5)*BZ_RESEARCH_AMOUNT)
+ SSresearch.science_tech.add_point_type(TECHWEB_POINT_TYPE_DEFAULT, (reaction_efficency**0.5)*BZ_RESEARCH_AMOUNT)
if(energy_released > 0)
var/new_heat_capacity = air.heat_capacity()
diff --git a/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm b/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm
index 552b9dbd64..35b30107d8 100644
--- a/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm
+++ b/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm
@@ -27,7 +27,7 @@
var/obj/item/radio/radio
var/radio_key = /obj/item/encryptionkey/headset_med
- var/radio_channel = "Medical"
+ var/radio_channel = RADIO_CHANNEL_MEDICAL
var/running_anim = FALSE
diff --git a/code/modules/awaymissions/capture_the_flag.dm b/code/modules/awaymissions/capture_the_flag.dm
index fcfdd7c455..84f08197b4 100644
--- a/code/modules/awaymissions/capture_the_flag.dm
+++ b/code/modules/awaymissions/capture_the_flag.dm
@@ -24,7 +24,6 @@
armour_penetration = 1000
resistance_flags = INDESTRUCTIBLE
anchored = TRUE
- item_flags = SLOWS_WHILE_IN_HAND
var/team = WHITE_TEAM
var/reset_cooldown = 0
var/anyonecanpickup = TRUE
diff --git a/code/modules/cargo/bounties/engineering.dm b/code/modules/cargo/bounties/engineering.dm
index e10d48f3bf..cf2cd7d93c 100644
--- a/code/modules/cargo/bounties/engineering.dm
+++ b/code/modules/cargo/bounties/engineering.dm
@@ -14,10 +14,10 @@
return FALSE
return T.air_contents.gases[gas_type] >= moles_required
-/datum/bounty/item/engineering/gas/nitryl_tank
- name = "Full Tank of Nitryl"
- description = "The non-human staff of Station 88 has been volunteered to test performance enhancing drugs. Ship them a tank full of Nitryl so they can get started."
- gas_type = /datum/gas/nitryl
+//datum/bounty/item/engineering/gas/nitryl_tank
+// name = "Full Tank of Nitryl"
+// description = "The non-human staff of Station 88 has been volunteered to test performance enhancing drugs. Ship them a tank full of Nitryl so they can get started."
+// gas_type = /datum/gas/nitryl
/datum/bounty/item/engineering/gas/tritium_tank
name = "Full Tank of Tritium"
@@ -37,6 +37,55 @@
required_count = 10 //easy to make
wanted_types = list(/obj/machinery/portable_atmospherics/canister)
+/datum/bounty/item/engineering/microwave
+ name = "Microwaves"
+ description = "Due to a shortage of microwaves, our chefs are incapable of keeping up with our sheer volume of orders. We need at least three microwaves to keep up with our crew's dietary habits."
+ reward = 2000
+ required_count = 3
+ wanted_types = list(/obj/machinery/microwave)
+
+/datum/bounty/item/engineering/hydroponicstrays
+ name = "Hydroponics Tray"
+ description = "The garden has become a hot spot of late, they need a few more hydroponics tray to grow more flowers."
+ reward = 2500
+ required_count = 5
+ wanted_types = list(/obj/machinery/hydroponics)
+
+/datum/bounty/item/engineering/rcd
+ name = "Spare RCD"
+ description = "Construction and repairs to are shuttles are going slowly. As it turns out, we're a little short on RCDs, can you send us a few?"
+ reward = 2500
+ required_count = 3
+ wanted_types = list(/obj/item/construction/rcd)
+
+/datum/bounty/item/engineering/rpd
+ name = "Spare RPD"
+ description = "Our Atmospheric Technicians are still living in the past, relying on stationary pipe dispensers to produce the pipes necessary to accomplish their strenuous tasks. They could use an upgrade. Could you send us some Rapid Pipe Dispensers?"
+ reward = 3000
+ required_count = 3
+ wanted_types = list(/obj/item/pipe_dispenser)
+
+/datum/bounty/item/engineering/heaters
+ name = "Space Heaters"
+ description = "The kitchen freezer was left open and now the whole place is frozen solid! We need a few space heaters to warm it back up before anyone gets hungry."
+ reward = 3000
+ required_count = 5
+ wanted_types = list(/obj/machinery/space_heater)
+
+/datum/bounty/item/engineering/arcadetrail
+ name = "Orion Trail Arcade Games"
+ description = "The staff have nothing to do when off-work. Can you send us some Orion Trail games to play?"
+ reward = 3000
+ required_count = 5
+ wanted_types = list(/obj/machinery/computer/arcade/orion_trail)
+
+/datum/bounty/item/engineering/arcadebattle
+ name = "Battle Arcade Games"
+ description = "The staff have nothing to do when off-work. Can you send us some Battle Arcade games to play?"
+ reward = 3000
+ required_count = 5
+ wanted_types = list(/obj/machinery/computer/arcade/battle)
+
/datum/bounty/item/engineering/energy_ball
name = "Contained Tesla Ball"
description = "Station 24 is being overrun by hordes of angry Mothpeople. They are requesting the ultimate bug zapper."
diff --git a/code/modules/cargo/exports/manifest.dm b/code/modules/cargo/exports/manifest.dm
index 02b060e0bf..d03f5a46ce 100644
--- a/code/modules/cargo/exports/manifest.dm
+++ b/code/modules/cargo/exports/manifest.dm
@@ -81,6 +81,7 @@
/datum/export/paperwork_correct
cost = 150
+ k_elasticity = 0
unit_name = "correct paperwork"
export_types = list(/obj/item/folder/paperwork_correct)
@@ -88,5 +89,6 @@
/datum/export/paperwork_incorrect
cost = -500 // Failed to meet NT standers
+ k_elasticity = 0
unit_name = "returned incorrect paperwork"
export_types = list(/obj/item/folder/paperwork)
diff --git a/code/modules/cargo/packs.dm b/code/modules/cargo/packs.dm
index 46cc1fa93c..1087f1ebb5 100644
--- a/code/modules/cargo/packs.dm
+++ b/code/modules/cargo/packs.dm
@@ -252,6 +252,17 @@
crate_name = "space suit crate"
crate_type = /obj/structure/closet/crate/secure
+/datum/supply_pack/emergency/spacejets
+ name = "Spare EVA Jetpacks"
+ desc = "Contains three EVA grade jectpaks. Requires EVA access to open."
+ cost = 2000
+ access = ACCESS_EVA
+ contains = list(/obj/item/tank/jetpack/carbondioxide/eva,
+ /obj/item/tank/jetpack/carbondioxide/eva,
+ /obj/item/tank/jetpack/carbondioxide/eva)
+ crate_name = "eva jetpacks crate"
+ crate_type = /obj/structure/closet/crate/secure
+
/datum/supply_pack/emergency/specialops
name = "Special Ops Supplies"
desc = "(*!&@#TOO CHEAP FOR THAT NULL_ENTRY, HUH OPERATIVE? WELL, THIS LITTLE ORDER CAN STILL HELP YOU OUT IN A PINCH. CONTAINS A BOX OF FIVE EMP GRENADES, THREE SMOKEBOMBS, AN INCENDIARY GRENADE, AND A \"SLEEPY PEN\" FULL OF NICE TOXINS!#@*$"
@@ -339,15 +350,6 @@
/obj/item/clothing/head/fedora/det_hat)
crate_name = "forensics crate"
-/datum/supply_pack/security/sechardsuit
- name = "Sec Hardsuit"
- desc = "One Sec Hardsuit with a small air tank and mask."
- cost = 3000 // half of SWAT gear for have the armor and half the gear
- contains = list(/obj/item/clothing/suit/space/hardsuit/security,
- /obj/item/tank/internals/air,
- /obj/item/clothing/mask/gas)
- crate_name = "sec hardsuit crate"
-
/datum/supply_pack/security/helmets
name = "Helmets Crate"
desc = "Contains three standard-issue brain buckets. Requires Security access to open."
@@ -366,6 +368,55 @@
/obj/item/gun/energy/laser)
crate_name = "laser crate"
+/datum/supply_pack/security/russianclothing
+ name = "Russian Surplus Clothing"
+ desc = "An old russian crate full of surplus armor that they used to use! Has two sets of bulletproff armor, a few union suits and some warm hats!"
+ contraband = TRUE
+ cost = 5000 // Its basicly sec suits, good boots/gloves
+ contains = list(/obj/item/clothing/suit/security/officer/russian,
+ /obj/item/clothing/suit/security/officer/russian,
+ /obj/item/clothing/shoes/combat,
+ /obj/item/clothing/shoes/combat,
+ /obj/item/clothing/head/ushanka,
+ /obj/item/clothing/head/ushanka,
+ /obj/item/clothing/suit/armor/bulletproof,
+ /obj/item/clothing/suit/armor/bulletproof,
+ /obj/item/clothing/head/helmet/alt,
+ /obj/item/clothing/head/helmet/alt,
+ /obj/item/clothing/gloves/combat,
+ /obj/item/clothing/gloves/combat,
+ /obj/item/clothing/mask/gas,
+ /obj/item/clothing/mask/gas)
+ crate_name = "surplus russian clothing"
+ crate_type = /obj/structure/closet/crate/internals
+
+/datum/supply_pack/security/russianmosin
+ name = "Russian Minutemen Gear"
+ desc = "An old russian Minutemen crate, comes with a full russian outfit, a mosin and a stripper clip."
+ contraband = TRUE
+ access = FALSE
+ cost = 5000 //
+ contains = list(/obj/item/clothing/suit/security/officer/russian,
+ /obj/item/clothing/shoes/combat,
+ /obj/item/clothing/head/ushanka,
+ /obj/item/clothing/suit/armor/bulletproof,
+ /obj/item/clothing/head/helmet/alt,
+ /obj/item/clothing/gloves/combat,
+ /obj/item/clothing/mask/gas,
+ /obj/item/gun/ballistic/shotgun/boltaction,
+ /obj/item/ammo_box/a762)
+ crate_name = "surplus russian gear"
+ crate_type = /obj/structure/closet/crate/internals
+
+/datum/supply_pack/security/sechardsuit
+ name = "Sec Hardsuit"
+ desc = "One Sec Hardsuit with a small air tank and mask."
+ cost = 3000 // half of SWAT gear for have the armor and half the gear
+ contains = list(/obj/item/clothing/suit/space/hardsuit/security,
+ /obj/item/tank/internals/air,
+ /obj/item/clothing/mask/gas)
+ crate_name = "sec hardsuit crate"
+
/datum/supply_pack/security/securitybarriers
name = "Security Barrier Grenades"
desc = "Stem the tide with four Security Barrier grenades. Requires Security access to open."
@@ -430,28 +481,6 @@
/obj/item/melee/baton/loaded)
crate_name = "stun baton crate"
-/datum/supply_pack/security/russianclothing
- name = "Russian Surplus Clothing"
- desc = "An old russian crate full of surplus armor that they used to use! Has two sets of bulletproff armor, a few union suits and some warm hats!"
- contraband = TRUE
- cost = 5000 // Its basicly sec suits, good boots/gloves
- contains = list(/obj/item/clothing/suit/security/officer/russian,
- /obj/item/clothing/suit/security/officer/russian,
- /obj/item/clothing/shoes/combat,
- /obj/item/clothing/shoes/combat,
- /obj/item/clothing/head/ushanka,
- /obj/item/clothing/head/ushanka,
- /obj/item/clothing/suit/armor/bulletproof,
- /obj/item/clothing/suit/armor/bulletproof,
- /obj/item/clothing/head/helmet/alt,
- /obj/item/clothing/head/helmet/alt,
- /obj/item/clothing/gloves/combat,
- /obj/item/clothing/gloves/combat,
- /obj/item/clothing/mask/gas,
- /obj/item/clothing/mask/gas)
- crate_name = "surplus russian clothing"
- crate_type = /obj/structure/closet/crate/internals
-
/datum/supply_pack/security/taser
name = "Taser Crate"
desc = "From the depths of stunbased combat, this order rises above, supreme. Contains three hybrid tasers, capable of firing both electrodes and disabling shots. Requires Security access to open."
@@ -665,6 +694,15 @@
/obj/item/gun/energy/e_gun/stun)
crate_name = "swat taser crate"
+/datum/supply_pack/security/armory/woodstock
+ name = "Classic WoodStock Shotguns Crate"
+ desc = "Contains three rustic, pumpaction shotguns. Requires Armory access to open."
+ cost = 3500
+ contains = list(/obj/item/gun/ballistic/shotgun,
+ /obj/item/gun/ballistic/shotgun,
+ /obj/item/gun/ballistic/shotgun)
+ crate_name = "woodstock shotguns crate"
+
/datum/supply_pack/security/armory/wt550
name = "WT-550 Semi-Auto Rifle Crate"
desc = "Contains two high-powered, semiautomatic rifles chambered in 4.6x30mm. Requires Armory access to open."
@@ -1633,7 +1671,7 @@
/obj/item/caution,
/obj/item/storage/bag/trash,
/obj/item/reagent_containers/spray/cleaner,
- /obj/item/reagent_containers/glass/rag,
+ /obj/item/reagent_containers/rag,
/obj/item/grenade/chem_grenade/cleaner,
/obj/item/grenade/chem_grenade/cleaner,
/obj/item/grenade/chem_grenade/cleaner,
@@ -1661,17 +1699,28 @@
/datum/supply_pack/service/janitor/janpremium
name = "Janitor Premium Supplies"
desc = "Do to the union for better supplies, we have desided to make a deal for you, In this crate you can get a brand new chem, Drying Angent this stuff is the work of slimes or magic! This crate also contains a rag to test out the Drying Angent magic, three wet floor signs, and some spare bottles of ammonia."
- cost = 3000
+ cost = 1750
access = ACCESS_JANITOR
contains = list(/obj/item/caution,
/obj/item/caution,
/obj/item/caution,
- /obj/item/reagent_containers/glass/rag,
+ /obj/item/reagent_containers/rag,
+ /obj/item/reagent_containers/glass/bottle/ammonia,
/obj/item/reagent_containers/glass/bottle/ammonia,
/obj/item/reagent_containers/glass/bottle/ammonia,
/obj/item/reagent_containers/spray/drying_agent)
crate_name = "janitor backpack crate"
+/datum/supply_pack/service/janitor/janpimp
+ name = "Custodial Cruiser"
+ desc = "Clown steal your ride? Assistant lock it in the dorms? Order a new one and get back to cleaning in style!"
+ cost = 3000
+ access = ACCESS_JANITOR
+ contains = list(/obj/vehicle/ridden/janicart,
+ /obj/item/key/janitor)
+ crate_name = "janitor ride crate"
+ crate_type = /obj/structure/closet/crate/large
+
/datum/supply_pack/service/mule
name = "MULEbot Crate"
desc = "Pink-haired Quartermaster not doing her job? Replace her with this tireless worker, today!"
@@ -1968,7 +2017,8 @@
/obj/item/storage/box/mre/menu1/safe,
/obj/item/storage/box/mre/menu2/safe,
/obj/item/storage/box/mre/menu2/safe,
- /obj/item/storage/box/mre/menu3)
+ /obj/item/storage/box/mre/menu3,
+ /obj/item/storage/box/mre/menu4/safe)
crate_name = "MRE crate (emergency rations)"
/datum/supply_pack/organic/pizza
@@ -2195,6 +2245,12 @@
/obj/item/clothing/neck/petcollar)
crate_name = "pug crate"
+/datum/supply_pack/organic/critter/kiwi
+ name = "Space kiwi Crate"
+ cost = 2000
+ contains = list( /mob/living/simple_animal/kiwi)
+ crate_name = "space kiwi crate"
+
/datum/supply_pack/critter/snake
name = "Snake Crate"
desc = "Tired of these MOTHER FUCKING snakes on this MOTHER FUCKING space station? Then this isn't the crate for you. Contains three poisonous snakes."
@@ -2204,6 +2260,17 @@
/mob/living/simple_animal/hostile/retaliate/poison/snake)
crate_name = "snake crate"
+/datum/supply_pack/critter/secbat
+ name = "Security Bat Crate"
+ desc = "Contains five security bats, perfect to Bat-up any security officer."
+ cost = 2500
+ contains = list(/mob/living/simple_animal/hostile/retaliate/bat/secbat,
+ /mob/living/simple_animal/hostile/retaliate/bat/secbat,
+ /mob/living/simple_animal/hostile/retaliate/bat/secbat,
+ /mob/living/simple_animal/hostile/retaliate/bat/secbat,
+ /mob/living/simple_animal/hostile/retaliate/bat/secbat)
+ crate_name = "security bat crate"
+
//////////////////////////////////////////////////////////////////////////////
//////////////////////////// Costumes & Toys /////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
@@ -2561,6 +2628,13 @@
/obj/item/vending_refill/wardrobe/law_wardrobe)
crate_name = "security department supply crate"
+/datum/supply_pack/costumes_toys/kinkmate
+ name = "Kinkmate construction kit"
+ cost = 2000
+ contraband = TRUE
+ contains = list(/obj/item/vending_refill/kink, /obj/item/circuitboard/machine/kinkmate)
+ crate_name = "Kinkmate construction kit"
+
//////////////////////////////////////////////////////////////////////////////
//////////////////////////// Miscellaneous ///////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
@@ -2674,6 +2748,26 @@
crate_type = /obj/structure/closet/crate/wooden
crate_name = "festive wrapping paper crate"
+/datum/supply_pack/misc/paper_work
+ name = "Freelance Paper work"
+ desc = "The Nanotrasen Primary Bureaucratic Database Intelligence (PDBI) reports that the station has not completed its funding and grant paperwork this solar cycle. In order to gain further funding, your station is required to fill out (10) ten of these forms or no additional capital will be disbursed. We have sent you ten copies of the following form and we expect every one to be up to Nanotrasen Standards." // Disbursement. It's not a typo, look it up.
+ cost = 700 // Net of 0 credits
+ contains = list(/obj/item/folder/paperwork,
+ /obj/item/folder/paperwork,
+ /obj/item/folder/paperwork,
+ /obj/item/folder/paperwork,
+ /obj/item/folder/paperwork,
+ /obj/item/folder/paperwork,
+ /obj/item/folder/paperwork,
+ /obj/item/folder/paperwork,
+ /obj/item/folder/paperwork,
+ /obj/item/folder/paperwork,
+ /obj/item/pen/fountain,
+ /obj/item/pen/fountain,
+ /obj/item/pen/fountain,
+ /obj/item/pen/fountain,
+ /obj/item/pen/fountain)
+ crate_name = "Paperwork"
/datum/supply_pack/misc/funeral
name = "Funeral Supply crate"
@@ -2686,18 +2780,11 @@
crate_name = "coffin"
crate_type = /obj/structure/closet/crate/coffin
-/datum/supply_pack/misc/religious_supplies
- name = "Religious Supplies Crate"
- desc = "Keep your local chaplain happy and well-supplied, lest they call down judgement upon your cargo bay. Contains two bottles of holywater, bibles, chaplain robes, and burial garmets."
- cost = 4000 // it costs so much because the Space Church is ran by Space Jews
- contains = list(/obj/item/reagent_containers/food/drinks/bottle/holywater,
- /obj/item/reagent_containers/food/drinks/bottle/holywater,
- /obj/item/storage/book/bible/booze,
- /obj/item/storage/book/bible/booze,
- /obj/item/clothing/suit/hooded/chaplain_hoodie,
- /obj/item/clothing/suit/hooded/chaplain_hoodie
- )
- crate_name = "religious supplies crate"
+/datum/supply_pack/misc/jukebox
+ name = "Jukebox"
+ cost = 35000
+ contains = list(/obj/machinery/jukebox)
+ crate_name = "Jukebox"
/datum/supply_pack/misc/lewd
name = "Lewd Crate" // OwO
@@ -2730,26 +2817,18 @@
crate_name = "deluxe keg"
crate_type = /obj/structure/closet/crate
-/datum/supply_pack/misc/paper_work
- name = "Freelance Paper work"
- desc = "The Nanotrasen Primary Bureaucratic Database Intelligence (PDBI) reports that the station has not completed its funding and grant paperwork this solar cycle. In order to gain further funding, your station is required to fill out (10) ten of these forms or no additional capital will be disbursed. We have sent you ten copies of the following form and we expect every one to be up to Nanotrasen Standards." // Disbursement. It's not a typo, look it up.
- cost = 400 // Net of 0 credits
- contains = list(/obj/item/folder/paperwork,
- /obj/item/folder/paperwork,
- /obj/item/folder/paperwork,
- /obj/item/folder/paperwork,
- /obj/item/folder/paperwork,
- /obj/item/folder/paperwork,
- /obj/item/folder/paperwork,
- /obj/item/folder/paperwork,
- /obj/item/folder/paperwork,
- /obj/item/folder/paperwork,
- /obj/item/pen/fountain,
- /obj/item/pen/fountain,
- /obj/item/pen/fountain,
- /obj/item/pen/fountain,
- /obj/item/pen/fountain)
- crate_name = "Paperwork"
+/datum/supply_pack/misc/religious_supplies
+ name = "Religious Supplies Crate"
+ desc = "Keep your local chaplain happy and well-supplied, lest they call down judgement upon your cargo bay. Contains two bottles of holywater, bibles, chaplain robes, and burial garmets."
+ cost = 4000 // it costs so much because the Space Church is ran by Space Jews
+ contains = list(/obj/item/reagent_containers/food/drinks/bottle/holywater,
+ /obj/item/reagent_containers/food/drinks/bottle/holywater,
+ /obj/item/storage/book/bible/booze,
+ /obj/item/storage/book/bible/booze,
+ /obj/item/clothing/suit/hooded/chaplain_hoodie,
+ /obj/item/clothing/suit/hooded/chaplain_hoodie
+ )
+ crate_name = "religious supplies crate"
/datum/supply_pack/misc/randomised/promiscuous
name = "Promiscuous Organs"
@@ -2775,4 +2854,3 @@
/obj/item/toner,
/obj/item/toner)
crate_name = "toner crate"
-
diff --git a/code/modules/client/darkmode.dm b/code/modules/client/darkmode.dm
new file mode 100644
index 0000000000..9e8d136b3b
--- /dev/null
+++ b/code/modules/client/darkmode.dm
@@ -0,0 +1,117 @@
+//Darkmode preference by Kmc2000//
+
+/*
+This lets you switch chat themes by using winset and CSS loading, you must relog to see this change (or rebuild your browseroutput datum)
+Things to note:
+If you change ANYTHING in interface/skin.dmf you need to change it here:
+Format:
+winset(src, "window as appears in skin.dmf after elem", "var to change = currentvalue;var to change = desired value")
+How this works:
+I've added a function to browseroutput.js which registers a cookie for darkmode and swaps the chat accordingly. You can find the button to do this under the "cog" icon next to the ping button (top right of chat)
+This then swaps the window theme automatically
+Thanks to spacemaniac and mcdonald for help with the JS side of this.
+*/
+
+/client/proc/force_white_theme() //There's no way round it. We're essentially changing the skin by hand. It's painful but it works, and is the way Lummox suggested.
+ //Main windows
+ winset(src, "infowindow", "background-color = [COLOR_DARKMODE_DARKBACKGROUND];background-color = [COLOR_WHITEMODE_DARKBACKGROUND]")
+ winset(src, "infowindow", "text-color = [COLOR_DARKMODE_TEXT];text-color = [COLOR_WHITEMODE_TEXT]")
+ winset(src, "info", "background-color = [COLOR_DARKMODE_BACKGROUND];background-color = [COLOR_WHITEMODE_BACKGROUND]")
+ winset(src, "info", "text-color = [COLOR_DARKMODE_TEXT];text-color = [COLOR_WHITEMODE_TEXT]")
+ winset(src, "browseroutput", "background-color = [COLOR_DARKMODE_BACKGROUND];background-color = [COLOR_DARKMODE_INFO_BUTTONS_BG]")
+ winset(src, "browseroutput", "text-color = [COLOR_DARKMODE_TEXT];text-color = [COLOR_WHITEMODE_TEXT]")
+ winset(src, "outputwindow", "background-color = [COLOR_DARKMODE_BACKGROUND];background-color = [COLOR_WHITEMODE_DARKBACKGROUND]")
+ winset(src, "outputwindow", "text-color = [COLOR_DARKMODE_TEXT];text-color = [COLOR_WHITEMODE_TEXT]")
+ winset(src, "mainwindow", "background-color = [COLOR_DARKMODE_DARKBACKGROUND];background-color = [COLOR_WHITEMODE_DARKBACKGROUND]")
+ winset(src, "split", "background-color = [COLOR_DARKMODE_DARKBACKGROUND];background-color = [COLOR_WHITEMODE_BACKGROUND]")
+ //Buttons
+ winset(src, "changelog", "background-color = [COLOR_DARKMODE_INFO_BUTTONS_BG];background-color = [COLOR_WHITEMODE_INFO_BUTTONS_BG]")
+ winset(src, "changelog", "text-color = [COLOR_DARKMODE_TEXT];text-color = [COLOR_WHITEMODE_TEXT]")
+ winset(src, "rules", "background-color = [COLOR_DARKMODE_INFO_BUTTONS_BG];background-color = [COLOR_WHITEMODE_INFO_BUTTONS_BG]")
+ winset(src, "rules", "text-color = [COLOR_DARKMODE_TEXT];text-color = [COLOR_WHITEMODE_TEXT]")
+ winset(src, "wiki", "background-color = [COLOR_DARKMODE_INFO_BUTTONS_BG];background-color = [COLOR_WHITEMODE_INFO_BUTTONS_BG]")
+ winset(src, "wiki", "text-color = [COLOR_DARKMODE_TEXT];text-color = [COLOR_WHITEMODE_TEXT]")
+ winset(src, "forum", "background-color = [COLOR_DARKMODE_INFO_BUTTONS_BG];background-color = [COLOR_WHITEMODE_INFO_BUTTONS_BG]")
+ winset(src, "forum", "text-color = [COLOR_DARKMODE_TEXT];text-color = [COLOR_WHITEMODE_TEXT]")
+ winset(src, "github", "background-color = [COLOR_DARKMODE_INFO_BUTTONS_BG];background-color = [COLOR_WHITEMODE_INFO_BUTTONS_BG]")
+ winset(src, "github", "text-color = [COLOR_DARKMODE_TEXT];text-color = [COLOR_WHITEMODE_TEXT]")
+ winset(src, "report-issue", "background-color = [COLOR_DARKMODE_ISSUE_BUTTON_BG];background-color = [COLOR_WHITEMODE_ISSUE_BUTTON_BG]")
+ winset(src, "report-issue", "text-color = [COLOR_DARKMODE_TEXT];text-color = [COLOR_WHITEMODE_TEXT]")
+ //Status and verb tabs
+ winset(src, "output", "background-color = [COLOR_DARKMODE_DARKBACKGROUND];background-color = [COLOR_WHITEMODE_BACKGROUND]")
+ winset(src, "output", "text-color = [COLOR_DARKMODE_TEXT];text-color = [COLOR_WHITEMODE_TEXT]")
+ winset(src, "statwindow", "background-color = [COLOR_DARKMODE_BACKGROUND];background-color = [COLOR_WHITEMODE_DARKBACKGROUND]")
+ winset(src, "statwindow", "text-color = #eaeaea;text-color = [COLOR_WHITEMODE_TEXT]")
+ winset(src, "stat", "background-color = [COLOR_DARKMODE_DARKBACKGROUND];background-color = [COLOR_WHITEMODE_BACKGROUND]")
+ winset(src, "stat", "tab-background-color = [COLOR_DARKMODE_BACKGROUND];tab-background-color = [COLOR_WHITEMODE_DARKBACKGROUND]")
+ winset(src, "stat", "text-color = [COLOR_DARKMODE_TEXT];text-color = [COLOR_WHITEMODE_TEXT]")
+ winset(src, "stat", "tab-text-color = [COLOR_DARKMODE_TEXT];tab-text-color = [COLOR_WHITEMODE_TEXT]")
+ winset(src, "stat", "prefix-color = [COLOR_DARKMODE_TEXT];prefix-color = [COLOR_WHITEMODE_TEXT]")
+ winset(src, "stat", "suffix-color = [COLOR_DARKMODE_TEXT];suffix-color = [COLOR_WHITEMODE_TEXT]")
+ //Etc.
+ winset(src, "say", "background-color = [COLOR_DARKMODE_DARKBACKGROUND];background-color = [COLOR_WHITEMODE_DARKBACKGROUND]")
+ winset(src, "say", "text-color = [COLOR_DARKMODE_TEXT];text-color = [COLOR_WHITEMODE_TEXT]")
+ winset(src, "asset_cache_browser", "background-color = [COLOR_DARKMODE_BACKGROUND];background-color = [COLOR_WHITEMODE_DARKBACKGROUND]")
+ winset(src, "asset_cache_browser", "text-color = [COLOR_DARKMODE_TEXT];text-color = [COLOR_WHITEMODE_TEXT]")
+ winset(src, "tooltip", "background-color = [COLOR_DARKMODE_BACKGROUND];background-color = [COLOR_WHITEMODE_BACKGROUND]")
+ winset(src, "tooltip", "text-color = [COLOR_DARKMODE_TEXT];text-color = [COLOR_WHITEMODE_TEXT]")
+
+/client/proc/force_dark_theme() //Inversely, if theyre using white theme and want to swap to the superior dark theme, let's get WINSET() ing
+ //Main windows
+ winset(src, "infowindow", "background-color = [COLOR_WHITEMODE_DARKBACKGROUND];background-color = [COLOR_DARKMODE_DARKBACKGROUND]")
+ winset(src, "infowindow", "text-color = [COLOR_WHITEMODE_TEXT];text-color = [COLOR_DARKMODE_TEXT]")
+ winset(src, "info", "background-color = [COLOR_WHITEMODE_BACKGROUND];background-color = [COLOR_DARKMODE_BACKGROUND]")
+ winset(src, "info", "text-color = [COLOR_WHITEMODE_TEXT];text-color = [COLOR_DARKMODE_TEXT]")
+ winset(src, "browseroutput", "background-color = [COLOR_WHITEMODE_BACKGROUND];background-color = [COLOR_DARKMODE_BACKGROUND]")
+ winset(src, "browseroutput", "text-color = [COLOR_WHITEMODE_TEXT];text-color = [COLOR_DARKMODE_TEXT]")
+ winset(src, "outputwindow", "background-color = [COLOR_WHITEMODE_DARKBACKGROUND];background-color = [COLOR_DARKMODE_BACKGROUND]")
+ winset(src, "outputwindow", "text-color = [COLOR_WHITEMODE_TEXT];text-color = [COLOR_DARKMODE_TEXT]")
+ winset(src, "mainwindow", "background-color = [COLOR_WHITEMODE_DARKBACKGROUND];background-color = [COLOR_DARKMODE_DARKBACKGROUND]")
+ winset(src, "split", "background-color = [COLOR_WHITEMODE_BACKGROUND];background-color = [COLOR_DARKMODE_BACKGROUND]")
+ //Buttons
+ winset(src, "changelog", "background-color = [COLOR_WHITEMODE_INFO_BUTTONS_BG];background-color = [COLOR_DARKMODE_INFO_BUTTONS_BG]")
+ winset(src, "changelog", "text-color = [COLOR_WHITEMODE_TEXT];text-color = [COLOR_DARKMODE_TEXT]")
+ winset(src, "rules", "background-color = [COLOR_WHITEMODE_INFO_BUTTONS_BG];background-color = [COLOR_DARKMODE_INFO_BUTTONS_BG]")
+ winset(src, "rules", "text-color = [COLOR_WHITEMODE_TEXT];text-color = [COLOR_DARKMODE_TEXT]")
+ winset(src, "wiki", "background-color = [COLOR_WHITEMODE_INFO_BUTTONS_BG];background-color = [COLOR_DARKMODE_INFO_BUTTONS_BG]")
+ winset(src, "wiki", "text-color = [COLOR_WHITEMODE_TEXT];text-color = [COLOR_DARKMODE_TEXT]")
+ winset(src, "forum", "background-color = [COLOR_WHITEMODE_INFO_BUTTONS_BG];background-color = [COLOR_DARKMODE_INFO_BUTTONS_BG]")
+ winset(src, "forum", "text-color = [COLOR_WHITEMODE_TEXT];text-color = [COLOR_DARKMODE_TEXT]")
+ winset(src, "github", "background-color = [COLOR_WHITEMODE_INFO_BUTTONS_BG];background-color = [COLOR_DARKMODE_INFO_BUTTONS_BG]")
+ winset(src, "github", "text-color = [COLOR_WHITEMODE_TEXT];text-color = [COLOR_DARKMODE_TEXT]")
+ winset(src, "report-issue", "background-color = [COLOR_WHITEMODE_ISSUE_BUTTON_BG];background-color = [COLOR_DARKMODE_ISSUE_BUTTON_BG]")
+ winset(src, "report-issue", "text-color = [COLOR_WHITEMODE_TEXT];text-color = [COLOR_DARKMODE_TEXT]")
+ //Status and verb tabs
+ winset(src, "output", "background-color = [COLOR_WHITEMODE_DARKBACKGROUND];background-color = [COLOR_DARKMODE_BACKGROUND]")
+ winset(src, "output", "text-color = [COLOR_WHITEMODE_TEXT];text-color = [COLOR_DARKMODE_TEXT]")
+ winset(src, "statwindow", "background-color = [COLOR_WHITEMODE_DARKBACKGROUND];background-color = [COLOR_DARKMODE_DARKBACKGROUND]")
+ winset(src, "statwindow", "text-color = [COLOR_WHITEMODE_TEXT];text-color = [COLOR_DARKMODE_TEXT]")
+ winset(src, "stat", "background-color = [COLOR_WHITEMODE_BACKGROUND];background-color = [COLOR_DARKMODE_DARKBACKGROUND]")
+ winset(src, "stat", "tab-background-color = [COLOR_WHITEMODE_DARKBACKGROUND];tab-background-color = [COLOR_DARKMODE_BACKGROUND]")
+ winset(src, "stat", "text-color = [COLOR_WHITEMODE_TEXT];text-color = [COLOR_DARKMODE_TEXT]")
+ winset(src, "stat", "tab-text-color = [COLOR_WHITEMODE_TEXT];tab-text-color = [COLOR_DARKMODE_TEXT]")
+ winset(src, "stat", "prefix-color = [COLOR_WHITEMODE_TEXT];prefix-color = [COLOR_DARKMODE_TEXT]")
+ winset(src, "stat", "suffix-color = [COLOR_WHITEMODE_TEXT];suffix-color = [COLOR_DARKMODE_TEXT]")
+ //Etc.
+ winset(src, "say", "background-color = [COLOR_WHITEMODE_DARKBACKGROUND];background-color = [COLOR_DARKMODE_BACKGROUND]")
+ winset(src, "say", "text-color = [COLOR_WHITEMODE_TEXT];text-color = [COLOR_DARKMODE_TEXT]")
+ winset(src, "asset_cache_browser", "background-color = [COLOR_WHITEMODE_DARKBACKGROUND];background-color = [COLOR_DARKMODE_BACKGROUND]")
+ winset(src, "asset_cache_browser", "text-color = [COLOR_WHITEMODE_TEXT];text-color = [COLOR_DARKMODE_TEXT]")
+ winset(src, "tooltip", "background-color = [COLOR_WHITEMODE_BACKGROUND];background-color = [COLOR_DARKMODE_BACKGROUND]")
+ winset(src, "tooltip", "text-color = [COLOR_WHITEMODE_TEXT];text-color = [COLOR_DARKMODE_TEXT]")
+
+
+/datum/asset/simple/goonchat
+ verify = FALSE
+ assets = list(
+ "json2.min.js" = 'code/modules/goonchat/browserassets/js/json2.min.js',
+ "errorHandler.js" = 'code/modules/goonchat/browserassets/js/errorHandler.js',
+ "browserOutput.js" = 'code/modules/goonchat/browserassets/js/browserOutput.js',
+ "fontawesome-webfont.eot" = 'tgui/assets/fonts/fontawesome-webfont.eot',
+ "fontawesome-webfont.svg" = 'tgui/assets/fonts/fontawesome-webfont.svg',
+ "fontawesome-webfont.ttf" = 'tgui/assets/fonts/fontawesome-webfont.ttf',
+ "fontawesome-webfont.woff" = 'tgui/assets/fonts/fontawesome-webfont.woff',
+ "font-awesome.css" = 'code/modules/goonchat/browserassets/css/font-awesome.css',
+ "browserOutput.css" = 'code/modules/goonchat/browserassets/css/browserOutput.css',
+ "browserOutput_white.css" = 'code/modules/goonchat/browserassets/css/browserOutput_white.css',
+ )
diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm
index 9e48591361..64a1f48962 100644
--- a/code/modules/client/preferences.dm
+++ b/code/modules/client/preferences.dm
@@ -29,7 +29,8 @@ GLOBAL_LIST_EMPTY(preferences_datums)
//game-preferences
var/lastchangelog = "" //Saved changlog filesize to detect if there was a change
- var/ooccolor = null
+ var/ooccolor = "#c43b23"
+ var/aooccolor = "#ce254f"
var/enable_tips = TRUE
var/tip_delay = 500 //tip delay in milliseconds
@@ -71,12 +72,13 @@ GLOBAL_LIST_EMPTY(preferences_datums)
var/gender = MALE //gender of character (well duh)
var/age = 30 //age of character
var/underwear = "Nude" //underwear type
- var/undie_color = "#FFFFFF"
+ var/undie_color = "FFF"
var/undershirt = "Nude" //undershirt type
- var/shirt_color = "#FFFFFF"
+ var/shirt_color = "FFF"
var/socks = "Nude" //socks type
- var/socks_color = "#FFFFFF"
+ var/socks_color = "FFF"
var/backbag = DBACKPACK //backpack type
+ var/jumpsuit_style = PREF_SUIT //suit/skirt
var/hair_style = "Bald" //Hair type
var/hair_color = "000" //Hair color
var/facial_hair_style = "Shaved" //Face hair type
@@ -142,6 +144,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
"breasts_size" = "C",
"breasts_shape" = "Pair",
"breasts_fluid" = "milk",
+ "breasts_producing" = FALSE,
"has_vag" = FALSE,
"vag_shape" = "Human",
"vag_color" = "fff",
@@ -686,6 +689,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
if(UNDIE_COLORABLE(GLOB.socks_list[socks]))
dat += "Socks Color:[socks_color]"
dat += "Backpack:[backbag]"
+ dat += "Jumpsuit:
[jumpsuit_style]
"
dat += "Uplink Location:[uplink_spawn_loc]"
dat += ""
@@ -740,6 +744,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
dat += " Change
"
dat += "Cup Size:[features["breasts_size"]]"
dat += "Breast Shape:[features["breasts_shape"]]"
+ dat += "Lactates:[features["breasts_producing"] == TRUE ? "Yes" : "No"]"
dat += ""
dat += ""
dat += ""
@@ -774,6 +779,8 @@ GLOBAL_LIST_EMPTY(preferences_datums)
dat += "BYOND Membership Publicity: [(toggles & MEMBER_PUBLIC) ? "Public" : "Hidden"]
"
if(unlock_content || check_rights_for(user.client, R_ADMIN))
dat += "OOC Color: Change
"
+ dat += "Antag OOC Color: Change
"
+
dat += ""
if(user.client.holder)
dat +=""
@@ -791,6 +798,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
dat += "Voracious MediHound sleepers: [(cit_toggles & MEDIHOUND_SLEEPER) ? "Yes" : "No"] "
dat += "Hear Vore Sounds: [(cit_toggles & EATING_NOISES) ? "Yes" : "No"] "
dat += "Hear Vore Digestion Sounds: [(cit_toggles & DIGESTION_NOISES) ? "Yes" : "No"] "
+ dat += "Lewdchem:[lewdchem == TRUE ? "Enabled" : "Disabled"] "
dat += "Widescreen: [widescreenpref ? "Enabled ([CONFIG_GET(string/default_view)])" : "Disabled (15x15)"] "
dat += "Auto stand: [autostand ? "Enabled" : "Disabled"] "
dat += "Screen Shake: [(screenshake==100) ? "Full" : ((screenshake==0) ? "None" : "[screenshake]")] "
@@ -1407,19 +1415,21 @@ GLOBAL_LIST_EMPTY(preferences_datums)
facial_hair_style = random_facial_hair_style(gender)
if("underwear")
underwear = random_underwear(gender)
- undie_color = random_color()
+ undie_color = random_short_color()
if("undershirt")
undershirt = random_undershirt(gender)
- shirt_color = random_color()
+ shirt_color = random_short_color()
if("socks")
socks = random_socks()
- socks_color = random_color()
+ socks_color = random_short_color()
if(BODY_ZONE_PRECISE_EYES)
eye_color = random_eye_color()
if("s_tone")
skin_tone = random_skin_tone()
if("bag")
backbag = pick(GLOB.backbaglist)
+ if("suit")
+ jumpsuit_style = pick(GLOB.jumpsuitlist)
if("all")
random_character()
@@ -1526,7 +1536,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
if("undie_color")
var/n_undie_color = input(user, "Choose your underwear's color.", "Character Preference", undie_color) as color|null
if(n_undie_color)
- undie_color = n_undie_color
+ undie_color = sanitize_hexcolor(n_undie_color)
if("undershirt")
var/new_undershirt = input(user, "Choose your character's undershirt:", "Character Preference") as null|anything in GLOB.undershirt_list
@@ -1536,7 +1546,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
if("shirt_color")
var/n_shirt_color = input(user, "Choose your undershirt's color.", "Character Preference", shirt_color) as color|null
if(n_shirt_color)
- shirt_color = n_shirt_color
+ shirt_color = sanitize_hexcolor(n_shirt_color)
if("socks")
var/new_socks = input(user, "Choose your character's socks:", "Character Preference") as null|anything in GLOB.socks_list
@@ -1546,7 +1556,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
if("socks_color")
var/n_socks_color = input(user, "Choose your socks' color.", "Character Preference", socks_color) as color|null
if(n_socks_color)
- socks_color = n_socks_color
+ socks_color = sanitize_hexcolor(n_socks_color)
if("eyes")
var/new_eyes = input(user, "Choose your character's eye colour:", "Character Preference","#"+eye_color) as color|null
@@ -1951,11 +1961,23 @@ GLOBAL_LIST_EMPTY(preferences_datums)
if(new_ooccolor)
ooccolor = new_ooccolor
+ if("aooccolor")
+ var/new_aooccolor = input(user, "Choose your Antag OOC colour:", "Game Preference",ooccolor) as color|null
+ if(new_aooccolor)
+ aooccolor = new_aooccolor
+
if("bag")
var/new_backbag = input(user, "Choose your character's style of bag:", "Character Preference") as null|anything in GLOB.backbaglist
if(new_backbag)
backbag = new_backbag
+ if("suit")
+ if(jumpsuit_style == PREF_SUIT)
+ jumpsuit_style = PREF_SKIRT
+ else
+ jumpsuit_style = PREF_SUIT
+
+
if("uplink_loc")
var/new_loc = input(user, "Choose your character's traitor uplink spawn location:", "Character Preference") as null|anything in GLOB.uplink_spawn_loc_list
if(new_loc)
@@ -2018,6 +2040,8 @@ GLOBAL_LIST_EMPTY(preferences_datums)
features["genitals_use_skintone"] = !features["genitals_use_skintone"]
if("arousable")
arousable = !arousable
+ if("lewdchem")
+ lewdchem = !lewdchem
if("has_cock")
features["has_cock"] = !features["has_cock"]
if(features["has_cock"] == FALSE)
@@ -2034,6 +2058,10 @@ GLOBAL_LIST_EMPTY(preferences_datums)
features["eggsack_internal"] = !features["eggsack_internal"]
if("has_breasts")
features["has_breasts"] = !features["has_breasts"]
+ if(features["has_breasts"] == FALSE)
+ features["breasts_producing"] = FALSE
+ if("breasts_producing")
+ features["breasts_producing"] = !features["breasts_producing"]
if("has_vag")
features["has_vag"] = !features["has_vag"]
if(features["has_vag"] == FALSE)
@@ -2276,6 +2304,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
character.backbag = backbag
+ character.jumpsuit_style = jumpsuit_style
var/datum/species/chosen_species
if(!roundstart_checks || (pref_species.id in GLOB.roundstart_races))
diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm
index b9c5cb7ef9..7911d92495 100644
--- a/code/modules/client/preferences_savefile.dm
+++ b/code/modules/client/preferences_savefile.dm
@@ -117,6 +117,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
S["widescreenpref"] >> widescreenpref
S["autostand"] >> autostand
S["cit_toggles"] >> cit_toggles
+ S["lewdchem"] >> lewdchem
//try to fix any outdated data if necessary
if(needs_update >= 0)
@@ -211,6 +212,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
WRITE_FILE(S["widescreenpref"], widescreenpref)
WRITE_FILE(S["autostand"], autostand)
WRITE_FILE(S["cit_toggles"], cit_toggles)
+ WRITE_FILE(S["lewdchem"], lewdchem)
return 1
@@ -272,6 +274,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
S["socks"] >> socks
S["socks_color"] >> socks_color
S["backbag"] >> backbag
+ S["jumpsuit_style"] >> jumpsuit_style
S["uplink_loc"] >> uplink_spawn_loc
S["feature_mcolor"] >> features["mcolor"]
S["feature_lizard_tail"] >> features["tail_lizard"]
@@ -346,6 +349,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
S["feature_breasts_shape"] >> features["breasts_shape"]
S["feature_breasts_color"] >> features["breasts_color"]
S["feature_breasts_fluid"] >> features["breasts_fluid"]
+ S["feature_breasts_producing"] >> features["breasts_producing"]
//vagina features
S["feature_has_vag"] >> features["has_vag"]
S["feature_vag_shape"] >> features["vag_shape"]
@@ -406,6 +410,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
eye_color = sanitize_hexcolor(eye_color, 3, 0)
skin_tone = sanitize_inlist(skin_tone, GLOB.skin_tones)
backbag = sanitize_inlist(backbag, GLOB.backbaglist, initial(backbag))
+ jumpsuit_style = sanitize_inlist(jumpsuit_style, GLOB.jumpsuitlist, initial(jumpsuit_style))
uplink_spawn_loc = sanitize_inlist(uplink_spawn_loc, GLOB.uplink_spawn_loc_list, initial(uplink_spawn_loc))
features["mcolor"] = sanitize_hexcolor(features["mcolor"], 3, 0)
features["tail_lizard"] = sanitize_inlist(features["tail_lizard"], GLOB.tails_list_lizard)
@@ -474,7 +479,8 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
WRITE_FILE(S["shirt_color"] , shirt_color)
WRITE_FILE(S["socks"] , socks)
WRITE_FILE(S["socks_color"] , socks_color)
- WRITE_FILE(S["backbag"] , backbag)
+ WRITE_FILE(S["backbag"] , backbag)
+ WRITE_FILE(S["jumpsuit_style"] , jumpsuit_style)
WRITE_FILE(S["uplink_loc"] , uplink_spawn_loc)
WRITE_FILE(S["species"] , pref_species.id)
WRITE_FILE(S["feature_mcolor"] , features["mcolor"])
diff --git a/code/modules/client/verbs/aooc.dm b/code/modules/client/verbs/aooc.dm
index 893501a852..311c22955d 100644
--- a/code/modules/client/verbs/aooc.dm
+++ b/code/modules/client/verbs/aooc.dm
@@ -1,3 +1,6 @@
+GLOBAL_VAR_INIT(AOOC_COLOR, null)//If this is null, use the CSS for OOC. Otherwise, use a custom colour.
+GLOBAL_VAR_INIT(normal_aooc_colour, "#ce254f")
+
/client/verb/aooc(msg as text)
set name = "AOOC"
set desc = "An OOC channel exclusive to antagonists."
@@ -50,7 +53,7 @@
var/keyname = key
if(prefs.unlock_content)
if(prefs.toggles & MEMBER_PUBLIC)
- keyname = "[icon2html('icons/member_content.dmi', world, "blag")][keyname]"
+ keyname = "[icon2html('icons/member_content.dmi', world, "blag")][keyname]"
//The linkify span classes and linkify=TRUE below make ooc text get clickable chat href links if you pass in something resembling a url
var/antaglisting = list()
@@ -74,23 +77,27 @@
else
to_chat(C, "Antag OOC: [keyname][holder.fakekey ? "/([holder.fakekey])" : ""]: [msg]")
else
- to_chat(C, "Antag OOC: [holder.fakekey ? holder.fakekey : key]: [msg]")
+ if(GLOB.AOOC_COLOR)
+ to_chat(C, "Antag OOC: [holder.fakekey ? holder.fakekey : key]: [msg]")
+ else
+ to_chat(C, "Antag OOC: [holder.fakekey ? holder.fakekey : key]: [msg]")
else if(!(key in C.prefs.ignoring))
- to_chat(C, "Antag OOC: [keyname]: [msg]")
-
-GLOBAL_VAR_INIT(antag_ooc_colour, AOOC_COLOR)
+ if(GLOB.AOOC_COLOR)
+ to_chat(C, "Antag OOC: [keyname]: [msg]")
+ else
+ to_chat(C, "Antag OOC: [keyname]: [msg]")
/client/proc/set_aooc(newColor as color)
set name = "Set Antag OOC Color"
set desc = "Modifies antag OOC Color"
set category = "Fun"
- GLOB.antag_ooc_colour = sanitize_ooccolor(newColor)
+ GLOB.AOOC_COLOR = sanitize_ooccolor(newColor)
/client/proc/reset_aooc()
set name = "Reset Antag OOC Color"
set desc = "Returns antag OOC Color to default"
set category = "Fun"
- GLOB.antag_ooc_colour = AOOC_COLOR
+ GLOB.AOOC_COLOR = null
/proc/toggle_aooc(toggle = null)
if(toggle != null) //if we're specifically en/disabling ooc
diff --git a/code/modules/client/verbs/ooc.dm b/code/modules/client/verbs/ooc.dm
index 5df13a1ffe..8a233025a1 100644
--- a/code/modules/client/verbs/ooc.dm
+++ b/code/modules/client/verbs/ooc.dm
@@ -1,3 +1,6 @@
+GLOBAL_VAR_INIT(OOC_COLOR, null)//If this is null, use the CSS for OOC. Otherwise, use a custom colour.
+GLOBAL_VAR_INIT(normal_ooc_colour, "#002eb8")
+
/client/verb/ooc(msg as text)
set name = "OOC" //Gave this shit a shorter name so you only have to time out "ooc" rather than "ooc message" to use it --NeoFite
set category = "OOC"
@@ -66,9 +69,15 @@
else
to_chat(C, "OOC: [keyname][holder.fakekey ? "/([holder.fakekey])" : ""]: [msg]")
else
- to_chat(C, "OOC: [holder.fakekey ? holder.fakekey : key]: [msg]")
+ if(GLOB.OOC_COLOR)
+ to_chat(C, "OOC: [holder.fakekey ? holder.fakekey : key]: [msg]")
+ else
+ to_chat(C, "OOC: [holder.fakekey ? holder.fakekey : key]: [msg]")
else if(!(key in C.prefs.ignoring))
- to_chat(C, "OOC: [keyname]: [msg]")
+ if(GLOB.OOC_COLOR)
+ to_chat(C, "OOC: [keyname]: [msg]")
+ else
+ to_chat(C, "OOC: [keyname]: [msg]")
/proc/toggle_ooc(toggle = null)
if(toggle != null) //if we're specifically en/disabling ooc
@@ -99,19 +108,17 @@
else
GLOB.dooc_allowed = !GLOB.dooc_allowed
-GLOBAL_VAR_INIT(normal_ooc_colour, OOC_COLOR)
-
/client/proc/set_ooc(newColor as color)
set name = "Set Player OOC Color"
set desc = "Modifies player OOC Color"
set category = "Fun"
- GLOB.normal_ooc_colour = sanitize_ooccolor(newColor)
+ GLOB.OOC_COLOR = sanitize_ooccolor(newColor)
/client/proc/reset_ooc()
set name = "Reset Player OOC Color"
set desc = "Returns player OOC Color to default"
set category = "Fun"
- GLOB.normal_ooc_colour = OOC_COLOR
+ GLOB.OOC_COLOR = null
/client/verb/colorooc()
set name = "Set Your OOC Color"
diff --git a/code/modules/clothing/chameleon.dm b/code/modules/clothing/chameleon.dm
index 04a8e17b7b..33a83487fc 100644
--- a/code/modules/clothing/chameleon.dm
+++ b/code/modules/clothing/chameleon.dm
@@ -437,7 +437,7 @@
item_state = "gas_alt"
resistance_flags = NONE
armor = list("melee" = 5, "bullet" = 5, "laser" = 5, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 50)
- clothing_flags = BLOCK_GAS_SMOKE_EFFECT | MASKINTERNALS
+ clothing_flags = BLOCK_GAS_SMOKE_EFFECT | ALLOWINTERNALS
flags_inv = HIDEEARS|HIDEEYES|HIDEFACE|HIDEFACIALHAIR
gas_transfer_coefficient = 0.01
permeability_coefficient = 0.01
@@ -630,3 +630,27 @@
/obj/item/stamp/chameleon/broken/Initialize()
. = ..()
chameleon_action.emp_randomise(INFINITY)
+
+/obj/item/clothing/neck/cloak/chameleon
+ name = "black tie"
+ desc = "A neosilk clip-on tie."
+ icon_state = "blacktie"
+ item_color = "blacktie"
+ resistance_flags = NONE
+ armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 50)
+
+/obj/item/clothing/neck/cloak/chameleon
+ var/datum/action/item_action/chameleon/change/chameleon_action
+
+/obj/item/clothing/neck/cloak/chameleon/Initialize()
+ . = ..()
+ chameleon_action = new(src)
+ chameleon_action.chameleon_type = /obj/item/clothing/neck
+ chameleon_action.chameleon_name = "Cloak"
+ chameleon_action.initialize_disguises()
+
+/obj/item/clothing/neck/cloak/chameleon/emp_act(severity)
+ . = ..()
+ if(. & EMP_PROTECT_SELF)
+ return
+ chameleon_action.emp_randomise()
diff --git a/code/modules/clothing/gloves/_gloves.dm b/code/modules/clothing/gloves/_gloves.dm
index 817fe59dcd..f0c1eeb833 100644
--- a/code/modules/clothing/gloves/_gloves.dm
+++ b/code/modules/clothing/gloves/_gloves.dm
@@ -8,6 +8,7 @@
slot_flags = ITEM_SLOT_GLOVES
attack_verb = list("challenged")
var/transfer_prints = FALSE
+ var/transfer_blood = 0
strip_delay = 20
equip_delay_other = 40
diff --git a/code/modules/clothing/gloves/miscellaneous.dm b/code/modules/clothing/gloves/miscellaneous.dm
index bc36353ac5..cc6d65b74d 100644
--- a/code/modules/clothing/gloves/miscellaneous.dm
+++ b/code/modules/clothing/gloves/miscellaneous.dm
@@ -65,6 +65,9 @@
var/warcry = "AT"
/obj/item/clothing/gloves/rapid/Touch(mob/living/target,proximity = TRUE)
+ if(!istype(target))
+ return
+
var/mob/living/M = loc
if(M.a_intent == INTENT_HARM)
@@ -72,9 +75,33 @@
M.adjustStaminaLoss(-2) //Restore 2/3 of the stamina used assuming empty stam buffer. With proper stamina buffer management, this results in a net gain of +.5 stamina per click.
if(warcry)
M.say("[warcry]", ignore_spam = TRUE, forced = "north star warcry")
+
.= FALSE
+
/obj/item/clothing/gloves/rapid/attack_self(mob/user)
var/input = stripped_input(user,"What do you want your battlecry to be? Max length of 6 characters.", ,"", 7)
if(input)
warcry = input
+
+/obj/item/clothing/gloves/rapid/hug
+ name = "Hugs of the North Star"
+ desc = "Just looking at these fills you with an urge to hug the shit out of people"
+ warcry = "owo" //Shouldn't ever come into play
+
+/obj/item/clothing/gloves/rapid/hug/Touch(mob/living/target,proximity = TRUE)
+ if(!istype(target))
+ return
+
+ var/mob/living/M = loc
+
+ if(M.a_intent == INTENT_HELP)
+ if(target.health >= 0 && !HAS_TRAIT(target, TRAIT_FAKEDEATH)) //Can't hug people who are dying/dead
+ if(target.on_fire || target.lying ) //No spamming extinguishing, helping them up, or other non-hugging/patting help interactions
+ return
+ else
+ M.changeNext_move(CLICK_CD_RAPID)
+ . = FALSE
+
+/obj/item/clothing/gloves/rapid/hug/attack_self(mob/user)
+ return FALSE
\ No newline at end of file
diff --git a/code/modules/clothing/head/beanie.dm b/code/modules/clothing/head/beanie.dm
index bbae5b261f..a5fb04d393 100644
--- a/code/modules/clothing/head/beanie.dm
+++ b/code/modules/clothing/head/beanie.dm
@@ -74,4 +74,13 @@
icon_state = "beaniestripedgreen"
item_color = "beaniestripedgreen"
+/obj/item/clothing/head/beanie/durathread
+ name = "durathread beanie"
+ desc = "A beanie made from durathread, its resilient fibres provide some protection to the wearer."
+ icon_state = "beaniedurathread"
+ item_color = null
+ armor = list("melee" = 25, "bullet" = 10, "laser" = 20,"energy" = 10, "bomb" = 30, "bio" = 15, "rad" = 20, "fire" = 100, "acid" = 50)
+
+
+
//No dog fashion sprites yet :( poor Ian can't be dope like the rest of us yet
\ No newline at end of file
diff --git a/code/modules/clothing/head/helmet.dm b/code/modules/clothing/head/helmet.dm
index f4b4e4a96d..be6e270e45 100644
--- a/code/modules/clothing/head/helmet.dm
+++ b/code/modules/clothing/head/helmet.dm
@@ -336,3 +336,11 @@
for(var/X in actions)
var/datum/action/A = X
A.UpdateButtonIcon()
+
+
+/obj/item/clothing/head/helmet/durathread
+ name = "makeshift helmet"
+ desc = "A hardhat with strips of leather and durathread for additional blunt protection."
+ icon_state = "durathread"
+ item_state = "durathread"
+ armor = list("melee" = 25, "bullet" = 10, "laser" = 20,"energy" = 10, "bomb" = 30, "bio" = 15, "rad" = 20, "fire" = 100, "acid" = 50)
diff --git a/code/modules/clothing/head/jobs.dm b/code/modules/clothing/head/jobs.dm
index 23e1825c3d..298510564c 100644
--- a/code/modules/clothing/head/jobs.dm
+++ b/code/modules/clothing/head/jobs.dm
@@ -279,6 +279,13 @@
desc = "This headwear shows off your Cargonian leadership"
icon_state = "qmberet"
+/obj/item/clothing/head/beret/durathread
+ name = "durathread beret"
+ desc = "A beret made from durathread, its resilient fibres provide some protection to the wearer."
+ icon_state = "beretdurathread"
+ item_color = null
+ armor = list("melee" = 25, "bullet" = 10, "laser" = 20,"energy" = 10, "bomb" = 30, "bio" = 15, "rad" = 20, "fire" = 100, "acid" = 50)
+
#undef DRILL_DEFAULT
#undef DRILL_SHOUTING
#undef DRILL_YELLING
diff --git a/code/modules/clothing/masks/breath.dm b/code/modules/clothing/masks/breath.dm
index ed0ef27174..947aa048c4 100644
--- a/code/modules/clothing/masks/breath.dm
+++ b/code/modules/clothing/masks/breath.dm
@@ -4,8 +4,8 @@
icon_state = "breath"
item_state = "m_mask"
body_parts_covered = 0
- clothing_flags = MASKINTERNALS
- visor_flags = MASKINTERNALS
+ clothing_flags = ALLOWINTERNALS
+ visor_flags = ALLOWINTERNALS
w_class = WEIGHT_CLASS_SMALL
gas_transfer_coefficient = 0.1
permeability_coefficient = 0.5
diff --git a/code/modules/clothing/masks/gasmask.dm b/code/modules/clothing/masks/gasmask.dm
index bcf3064c49..c613d1a91e 100644
--- a/code/modules/clothing/masks/gasmask.dm
+++ b/code/modules/clothing/masks/gasmask.dm
@@ -2,7 +2,7 @@
name = "gas mask"
desc = "A face-covering mask that can be connected to an air supply. While good for concealing your identity, it isn't good for blocking gas flow." //More accurate
icon_state = "gas_alt"
- clothing_flags = BLOCK_GAS_SMOKE_EFFECT | MASKINTERNALS
+ clothing_flags = BLOCK_GAS_SMOKE_EFFECT | ALLOWINTERNALS
flags_inv = HIDEEARS|HIDEEYES|HIDEFACE|HIDEFACIALHAIR|HIDESNOUT
w_class = WEIGHT_CLASS_NORMAL
item_state = "gas_alt"
@@ -59,7 +59,7 @@
/obj/item/clothing/mask/gas/clown_hat
name = "clown wig and mask"
desc = "A true prankster's facial attire. A clown is incomplete without his wig and mask."
- clothing_flags = MASKINTERNALS
+ clothing_flags = ALLOWINTERNALS
icon_state = "clown"
item_state = "clown_hat"
flags_cover = MASKCOVERSEYES
@@ -91,7 +91,7 @@
/obj/item/clothing/mask/gas/sexyclown
name = "sexy-clown wig and mask"
desc = "A feminine clown mask for the dabbling crossdressers or female entertainers."
- clothing_flags = MASKINTERNALS
+ clothing_flags = ALLOWINTERNALS
icon_state = "sexyclown"
item_state = "sexyclown"
flags_cover = MASKCOVERSEYES
@@ -100,7 +100,7 @@
/obj/item/clothing/mask/gas/mime
name = "mime mask"
desc = "The traditional mime's mask. It has an eerie facial posture."
- clothing_flags = MASKINTERNALS
+ clothing_flags = ALLOWINTERNALS
icon_state = "mime"
item_state = "mime"
flags_cover = MASKCOVERSEYES
@@ -132,7 +132,7 @@
/obj/item/clothing/mask/gas/monkeymask
name = "monkey mask"
desc = "A mask used when acting as a monkey."
- clothing_flags = MASKINTERNALS
+ clothing_flags = ALLOWINTERNALS
icon_state = "monkeymask"
item_state = "monkeymask"
flags_cover = MASKCOVERSEYES
@@ -141,7 +141,7 @@
/obj/item/clothing/mask/gas/sexymime
name = "sexy mime mask"
desc = "A traditional female mime's mask."
- clothing_flags = MASKINTERNALS
+ clothing_flags = ALLOWINTERNALS
icon_state = "sexymime"
item_state = "sexymime"
flags_cover = MASKCOVERSEYES
@@ -162,7 +162,7 @@
name = "owl mask"
desc = "Twoooo!"
icon_state = "owl"
- clothing_flags = MASKINTERNALS
+ clothing_flags = ALLOWINTERNALS
flags_cover = MASKCOVERSEYES
resistance_flags = FLAMMABLE
diff --git a/code/modules/clothing/masks/hailer.dm b/code/modules/clothing/masks/hailer.dm
index 8860650fbc..f004f07bf5 100644
--- a/code/modules/clothing/masks/hailer.dm
+++ b/code/modules/clothing/masks/hailer.dm
@@ -7,10 +7,10 @@
actions_types = list(/datum/action/item_action/halt, /datum/action/item_action/adjust)
icon_state = "sechailer"
item_state = "sechailer"
- clothing_flags = BLOCK_GAS_SMOKE_EFFECT | MASKINTERNALS
+ clothing_flags = BLOCK_GAS_SMOKE_EFFECT | ALLOWINTERNALS
flags_inv = HIDEFACIALHAIR|HIDEFACE
w_class = WEIGHT_CLASS_SMALL
- visor_flags = BLOCK_GAS_SMOKE_EFFECT | MASKINTERNALS
+ visor_flags = BLOCK_GAS_SMOKE_EFFECT | ALLOWINTERNALS
visor_flags_inv = HIDEFACE
flags_cover = MASKCOVERSMOUTH
visor_flags_cover = MASKCOVERSMOUTH
diff --git a/code/modules/clothing/masks/miscellaneous.dm b/code/modules/clothing/masks/miscellaneous.dm
index 5dfa7d6047..4b8f16a77f 100644
--- a/code/modules/clothing/masks/miscellaneous.dm
+++ b/code/modules/clothing/masks/miscellaneous.dm
@@ -313,3 +313,9 @@
message = replacetextEx(message,regex(capitalize(key),"g"), "[capitalize(value)]")
message = replacetextEx(message,regex(key,"g"), "[value]")
speech_args[SPEECH_MESSAGE] = trim(message)
+
+/obj/item/clothing/mask/bandana/durathread
+ name = "durathread bandana"
+ desc = "A bandana made from durathread, you wish it would provide some protection to its wearer, but it's far too thin..."
+ icon_state = "banddurathread"
+
diff --git a/code/modules/clothing/outfits/ert.dm b/code/modules/clothing/outfits/ert.dm
index b4310a7f42..86c8f5335f 100644
--- a/code/modules/clothing/outfits/ert.dm
+++ b/code/modules/clothing/outfits/ert.dm
@@ -163,6 +163,34 @@
/obj/item/gun/energy/pulse/pistol/loyalpin=1,\
/obj/item/construction/rcd/combat=1)
+/datum/outfit/ert/greybois
+ name = "Emergency Assistant"
+
+ uniform = /obj/item/clothing/under/color/grey/glorf
+ shoes = /obj/item/clothing/shoes/sneakers/black
+ gloves = /obj/item/clothing/gloves/color/fyellow
+ ears = /obj/item/radio/headset
+ head = /obj/item/clothing/head/soft/grey
+ belt = /obj/item/storage/belt/utility/full
+ back = /obj/item/storage/backpack
+ mask = /obj/item/clothing/mask/gas
+ l_pocket = /obj/item/tank/internals/emergency_oxygen
+ l_hand = /obj/item/storage/toolbox/emergency/old
+ id = /obj/item/card/id
+
+/datum/outfit/ert/greybois/greygod
+ suit = /obj/item/clothing/suit/hazardvest
+ l_hand = /obj/item/storage/toolbox/plastitanium
+ gloves = /obj/item/clothing/gloves/color/yellow
+
+/datum/outfit/ert/greybois/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
+ if(visualsOnly)
+ return
+ var/obj/item/card/id/W = H.wear_id
+ W.registered_name = H.real_name
+ W.assignment = "Assistant"
+ W.access = list(ACCESS_MAINT_TUNNELS,ACCESS_CENT_GENERAL)
+ W.update_label(W.registered_name, W.assignment)
/datum/outfit/centcom_official
name = "CentCom Official"
diff --git a/code/modules/clothing/shoes/miscellaneous.dm b/code/modules/clothing/shoes/miscellaneous.dm
index e6554f6125..4659de3e6a 100644
--- a/code/modules/clothing/shoes/miscellaneous.dm
+++ b/code/modules/clothing/shoes/miscellaneous.dm
@@ -219,17 +219,13 @@
var/atom/target = get_edge_target_turf(user, user.dir) //gets the user's direction
- if (user.throw_at(target, jumpdistance, jumpspeed, spin = FALSE, diagonals_first = TRUE, callback = CALLBACK(src, .proc/hop_end)))
- jumping = TRUE
+ if (user.throw_at(target, jumpdistance, jumpspeed, spin = FALSE, diagonals_first = TRUE))
playsound(src, 'sound/effects/stealthoff.ogg', 50, 1, 1)
+ recharging_time = world.time + recharging_rate
user.visible_message("[usr] dashes forward into the air!")
else
to_chat(user, "Something prevents you from dashing forward!")
-/obj/item/clothing/shoes/bhop/proc/hop_end()
- jumping = FALSE
- recharging_time = world.time + recharging_rate
-
/obj/item/clothing/shoes/singery
name = "yellow performer's boots"
desc = "These boots were made for dancing."
diff --git a/code/modules/clothing/spacesuits/_spacesuits.dm b/code/modules/clothing/spacesuits/_spacesuits.dm
index 9d3918ed84..662a91c80c 100644
--- a/code/modules/clothing/spacesuits/_spacesuits.dm
+++ b/code/modules/clothing/spacesuits/_spacesuits.dm
@@ -4,7 +4,7 @@
name = "space helmet"
icon_state = "spaceold"
desc = "A special helmet with solar UV shielding to protect your eyes from harmful rays."
- clothing_flags = STOPSPRESSUREDAMAGE | THICKMATERIAL
+ clothing_flags = STOPSPRESSUREDAMAGE | THICKMATERIAL | BLOCK_GAS_SMOKE_EFFECT | ALLOWINTERNALS
item_state = "spaceold"
permeability_coefficient = 0.01
armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 100, "rad" = 50, "fire" = 80, "acid" = 70)
diff --git a/code/modules/clothing/suits/_suits.dm b/code/modules/clothing/suits/_suits.dm
index 7346dc9ea9..cf411ef367 100644
--- a/code/modules/clothing/suits/_suits.dm
+++ b/code/modules/clothing/suits/_suits.dm
@@ -28,7 +28,6 @@
H.update_inv_wear_suit()
else if(adjusted == ALT_STYLE)
adjusted = NORMAL_STYLE
- H.update_inv_wear_suit()
if(("taur" in H.dna.species.mutant_bodyparts) && (H.dna.features["taur"] != "None"))
if(H.dna.features["taur"] in list("Naga", "Tentacle"))
diff --git a/code/modules/clothing/suits/armor.dm b/code/modules/clothing/suits/armor.dm
index 5eec159462..0840288eee 100644
--- a/code/modules/clothing/suits/armor.dm
+++ b/code/modules/clothing/suits/armor.dm
@@ -238,3 +238,14 @@
/obj/item/clothing/suit/armor/riot/knight/red
icon_state = "knight_red"
item_state = "knight_red"
+
+/obj/item/clothing/suit/armor/vest/durathread
+ name = "makeshift vest"
+ desc = "A vest made of durathread with strips of leather acting as trauma plates."
+ icon_state = "durathread"
+ item_state = "durathread"
+ strip_delay = 60
+ equip_delay_other = 40
+ max_integrity = 200
+ resistance_flags = FLAMMABLE
+ armor = list("melee" = 20, "bullet" = 10, "laser" = 30, "energy" = 5, "bomb" = 15, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 50)
diff --git a/code/modules/clothing/suits/jobs.dm b/code/modules/clothing/suits/jobs.dm
index bf11d40caf..3c3c8f0e9d 100644
--- a/code/modules/clothing/suits/jobs.dm
+++ b/code/modules/clothing/suits/jobs.dm
@@ -177,3 +177,23 @@
armor = list("melee" = 25, "bullet" = 10, "laser" = 25, "energy" = 10, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 45)
cold_protection = CHEST|ARMS
heat_protection = CHEST|ARMS
+
+
+//Robotocist
+
+/obj/item/clothing/suit/hooded/techpriest
+ name = "techpriest robes"
+ desc = "For those who REALLY love their toasters."
+ icon_state = "techpriest"
+ item_state = "techpriest"
+ body_parts_covered = CHEST|GROIN|LEGS|ARMS
+ hoodtype = /obj/item/clothing/head/hooded/techpriest
+ mutantrace_variation = NO_MUTANTRACE_VARIATION
+
+/obj/item/clothing/head/hooded/techpriest
+ name = "techpriest's hood"
+ desc = "A hood for those who REALLY love their toasters."
+ icon_state = "techpriesthood"
+ item_state = "techpriesthood"
+ body_parts_covered = HEAD
+ flags_inv = HIDEHAIR|HIDEEARS
diff --git a/code/modules/clothing/under/accessories.dm b/code/modules/clothing/under/accessories.dm
index 396bcb4766..6535e40d0d 100644
--- a/code/modules/clothing/under/accessories.dm
+++ b/code/modules/clothing/under/accessories.dm
@@ -354,3 +354,28 @@
item_color = "skull"
above_suit = TRUE
armor = list("melee" = 5, "bullet" = 5, "laser" = 5, "energy" = 5, "bomb" = 20, "bio" = 20, "rad" = 5, "fire" = 0, "acid" = 25)
+
+/////////////////////
+//Synda Accessories//
+/////////////////////
+
+/obj/item/clothing/accessory/padding
+ name = "soft padding"
+ desc = "Some long sheets of padding to help soften the blows of a physical attacks."
+ icon_state = "padding"
+ item_color = "nothing"
+ armor = list("melee" = 15, "bullet" = 10, "laser" = 0, "energy" = 0, "bomb" = 5, "bio" = 0, "rad" = 0, "fire" = -20, "acid" = 45)
+
+/obj/item/clothing/accessory/kevlar
+ name = "kevlar sheets"
+ desc = "Long thin sheets of kevlar to help resist bullets and some physical attacks.."
+ icon_state = "padding"
+ item_color = "nothing"
+ armor = list("melee" = 10, "bullet" = 20, "laser" = 0, "energy" = 0, "bomb" = 10, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 25)
+
+/obj/item/clothing/accessory/plastics
+ name = "underling plastic sheet"
+ desc = "A full body sheet of white plastic to help defuse lasers and energy based weapons."
+ icon_state = "plastics"
+ item_color = "nothing"
+ armor = list("melee" = 0, "bullet" = 0, "laser" = 20, "energy" = 10, "bomb" = 0, "bio" = 30, "rad" = 0, "fire" = 0, "acid" = -40)
diff --git a/code/modules/clothing/under/color.dm b/code/modules/clothing/under/color.dm
index c239f48b05..54264ef9d4 100644
--- a/code/modules/clothing/under/color.dm
+++ b/code/modules/clothing/under/color.dm
@@ -1,12 +1,18 @@
/obj/item/clothing/under/color
desc = "A standard issue colored jumpsuit. Variety is the spice of life!"
+/obj/item/clothing/under/skirt/color
+ body_parts_covered = CHEST|GROIN|ARMS
+ can_adjust = FALSE
+ fitted = FEMALE_UNIFORM_TOP
+
/obj/item/clothing/under/color/random
icon_state = "random_jumpsuit"
/obj/item/clothing/under/color/random/Initialize()
..()
- var/obj/item/clothing/under/color/C = pick(subtypesof(/obj/item/clothing/under/color) - /obj/item/clothing/under/color/random - /obj/item/clothing/under/color/grey/glorf - /obj/item/clothing/under/color/black/ghost)
+ var/obj/item/clothing/under/color/C = pick(subtypesof(/obj/item/clothing/under/color) - subtypesof(/obj/item/clothing/under/skirt/color) - /obj/item/clothing/under/color/random - /obj/item/clothing/under/color/grey/glorf - /obj/item/clothing/under/color/black/ghost)
+
if(ishuman(loc))
var/mob/living/carbon/human/H = loc
H.equip_to_slot_or_del(new C(H), SLOT_W_UNIFORM) //or else you end up with naked assistants running around everywhere...
@@ -14,6 +20,20 @@
new C(loc)
return INITIALIZE_HINT_QDEL
+/obj/item/clothing/under/skirt/color/random
+ icon_state = "random_jumpsuit" //Skirt variant needed
+
+/obj/item/clothing/under/skirt/color/random/Initialize()
+ ..()
+ var/obj/item/clothing/under/skirt/color/C = pick(subtypesof(/obj/item/clothing/under/skirt/color) - /obj/item/clothing/under/skirt/color/random)
+ if(ishuman(loc))
+ var/mob/living/carbon/human/H = loc
+ H.equip_to_slot_or_del(new C(H), SLOT_W_UNIFORM)
+ else
+ new C(loc)
+ return INITIALIZE_HINT_QDEL
+
+
/obj/item/clothing/under/color/black
name = "black jumpsuit"
icon_state = "black"
@@ -21,6 +41,12 @@
item_color = "black"
resistance_flags = NONE
+/obj/item/clothing/under/skirt/color/black
+ name = "black jumpskirt"
+ icon_state = "black_skirt"
+ item_state = "bl_suit"
+ item_color = "black_skirt"
+
/obj/item/clothing/under/color/black/ghost
item_flags = DROPDEL
@@ -28,6 +54,9 @@
. = ..()
ADD_TRAIT(src, TRAIT_NODROP, CULT_TRAIT)
+/obj/item/clothing/under/color/black/ghost/Initialize()
+ . = ..()
+ ADD_TRAIT(src, TRAIT_NODROP, DROPDEL)
/obj/item/clothing/under/color/grey
name = "grey jumpsuit"
desc = "A tasteful grey jumpsuit that reminds you of the good old days."
@@ -35,6 +64,13 @@
item_state = "gy_suit"
item_color = "grey"
+/obj/item/clothing/under/skirt/color/grey
+ name = "grey jumpskirt"
+ desc = "A tasteful grey jumpskirt that reminds you of the good old days."
+ icon_state = "grey_skirt"
+ item_state = "gy_suit"
+ item_color = "grey_skirt"
+
/obj/item/clothing/under/color/grey/glorf
name = "ancient jumpsuit"
desc = "A terribly ragged and frayed grey jumpsuit. It looks like it hasn't been washed in over a decade."
@@ -49,12 +85,24 @@
item_state = "b_suit"
item_color = "blue"
+/obj/item/clothing/under/skirt/color/blue
+ name = "blue jumpskirt"
+ icon_state = "blue_skirt"
+ item_state = "b_suit"
+ item_color = "blue_skirt"
+
/obj/item/clothing/under/color/green
name = "green jumpsuit"
icon_state = "green"
item_state = "g_suit"
item_color = "green"
+/obj/item/clothing/under/skirt/color/green
+ name = "green jumpskirt"
+ icon_state = "green_skirt"
+ item_state = "g_suit"
+ item_color = "green_skirt"
+
/obj/item/clothing/under/color/orange
name = "orange jumpsuit"
desc = "Don't wear this near paranoid security officers."
@@ -62,6 +110,12 @@
item_state = "o_suit"
item_color = "orange"
+/obj/item/clothing/under/skirt/color/orange
+ name = "orange jumpskirt"
+ icon_state = "orange_skirt"
+ item_state = "o_suit"
+ item_color = "orange_skirt"
+
/obj/item/clothing/under/color/pink
name = "pink jumpsuit"
icon_state = "pink"
@@ -69,66 +123,133 @@
item_state = "p_suit"
item_color = "pink"
+/obj/item/clothing/under/skirt/color/pink
+ name = "pink jumpskirt"
+ icon_state = "pink_skirt"
+ item_state = "p_suit"
+ item_color = "pink_skirt"
+
/obj/item/clothing/under/color/red
name = "red jumpsuit"
icon_state = "red"
item_state = "r_suit"
item_color = "red"
+/obj/item/clothing/under/skirt/color/red
+ name = "red jumpskirt"
+ icon_state = "red_skirt"
+ item_state = "r_suit"
+ item_color = "red_skirt"
+
/obj/item/clothing/under/color/white
name = "white jumpsuit"
icon_state = "white"
item_state = "w_suit"
item_color = "white"
+/obj/item/clothing/under/skirt/color/white
+ name = "white jumpskirt"
+ icon_state = "white_skirt"
+ item_state = "w_suit"
+ item_color = "white_skirt"
+
/obj/item/clothing/under/color/yellow
name = "yellow jumpsuit"
icon_state = "yellow"
item_state = "y_suit"
item_color = "yellow"
+/obj/item/clothing/under/skirt/color/yellow
+ name = "yellow jumpskirt"
+ icon_state = "yellow_skirt"
+ item_state = "y_suit"
+ item_color = "yellow_skirt"
+
/obj/item/clothing/under/color/darkblue
name = "darkblue jumpsuit"
icon_state = "darkblue"
item_state = "b_suit"
item_color = "darkblue"
+/obj/item/clothing/under/skirt/color/darkblue
+ name = "darkblue jumpskirt"
+ icon_state = "darkblue_skirt"
+ item_state = "b_suit"
+ item_color = "darkblue_skirt"
+
/obj/item/clothing/under/color/teal
name = "teal jumpsuit"
icon_state = "teal"
item_state = "b_suit"
item_color = "teal"
+/obj/item/clothing/under/skirt/color/teal
+ name = "teal jumpskirt"
+ icon_state = "teal_skirt"
+ item_state = "b_suit"
+ item_color = "teal_skirt"
+
+
/obj/item/clothing/under/color/lightpurple
name = "purple jumpsuit"
icon_state = "lightpurple"
item_state = "p_suit"
item_color = "lightpurple"
+/obj/item/clothing/under/skirt/color/lightpurple
+ name = "lightpurple jumpskirt"
+ icon_state = "lightpurple_skirt"
+ item_state = "p_suit"
+ item_color = "lightpurple_skirt"
+
/obj/item/clothing/under/color/darkgreen
name = "darkgreen jumpsuit"
icon_state = "darkgreen"
item_state = "g_suit"
item_color = "darkgreen"
+/obj/item/clothing/under/skirt/color/darkgreen
+ name = "darkgreen jumpskirt"
+ icon_state = "darkgreen_skirt"
+ item_state = "g_suit"
+ item_color = "darkgreen_skirt"
+
/obj/item/clothing/under/color/lightbrown
name = "lightbrown jumpsuit"
icon_state = "lightbrown"
item_state = "lb_suit"
item_color = "lightbrown"
+/obj/item/clothing/under/skirt/color/lightbrown
+ name = "lightbrown jumpskirt"
+ icon_state = "lightbrown_skirt"
+ item_state = "lb_suit"
+ item_color = "lightbrown_skirt"
+
/obj/item/clothing/under/color/brown
name = "brown jumpsuit"
icon_state = "brown"
item_state = "lb_suit"
item_color = "brown"
+/obj/item/clothing/under/skirt/color/brown
+ name = "brown jumpskirt"
+ icon_state = "brown_skirt"
+ item_state = "lb_suit"
+ item_color = "brown_skirt"
+
/obj/item/clothing/under/color/maroon
name = "maroon jumpsuit"
icon_state = "maroon"
item_state = "r_suit"
item_color = "maroon"
+/obj/item/clothing/under/skirt/color/maroon
+ name = "maroon jumpskirt"
+ icon_state = "maroon_skirt"
+ item_state = "r_suit"
+ item_color = "maroon_skirt"
+
/obj/item/clothing/under/color/rainbow
name = "rainbow jumpsuit"
desc = "A multi-colored jumpsuit!"
@@ -136,3 +257,11 @@
item_state = "rainbow"
item_color = "rainbow"
can_adjust = FALSE
+
+/obj/item/clothing/under/skirt/color/rainbow
+ name = "rainbow jumpskirt"
+ desc = "A multi-colored jumpskirt!"
+ icon_state = "rainbow_skirt"
+ item_state = "rainbow"
+ item_color = "rainbow_skirt"
+ can_adjust = FALSE
diff --git a/code/modules/clothing/under/jobs/civilian.dm b/code/modules/clothing/under/jobs/civilian.dm
index 2288c98b34..c6796d64c9 100644
--- a/code/modules/clothing/under/jobs/civilian.dm
+++ b/code/modules/clothing/under/jobs/civilian.dm
@@ -16,6 +16,16 @@
item_color = "purplebartender"
can_adjust = FALSE
+/obj/item/clothing/under/rank/bartender/skirt
+ name = "bartender's skirt"
+ desc = "It looks like it could use some more flair."
+ icon_state = "barman_skirt"
+ item_state = "bar_suit"
+ item_color = "barman_skirt"
+ body_parts_covered = CHEST|GROIN|ARMS
+ can_adjust = FALSE
+ fitted = FEMALE_UNIFORM_TOP
+
/obj/item/clothing/under/rank/captain //Alright, technically not a 'civilian' but its better then giving a .dm file for a single define.
desc = "It's a blue jumpsuit with some gold markings denoting the rank of \"Captain\"."
name = "captain's jumpsuit"
@@ -25,6 +35,16 @@
sensor_mode = SENSOR_COORDS
random_sensor = FALSE
+/obj/item/clothing/under/rank/captain/skirt
+ name = "captain's jumpskirt"
+ desc = "It's a blue jumpskirt with some gold markings denoting the rank of \"Captain\"."
+ icon_state = "captain_skirt"
+ item_state = "b_suit"
+ item_color = "captain_skirt"
+ body_parts_covered = CHEST|GROIN|ARMS
+ can_adjust = FALSE
+ fitted = FEMALE_UNIFORM_TOP
+
/obj/item/clothing/under/rank/cargo
name = "quartermaster's jumpsuit"
desc = "It's a jumpsuit worn by the quartermaster. It's specially designed to prevent back injuries caused by pushing paper."
@@ -32,6 +52,16 @@
item_state = "lb_suit"
item_color = "qm"
+/obj/item/clothing/under/rank/cargo/skirt
+ name = "quartermaster's jumpskirt"
+ desc = "It's a jumpskirt worn by the quartermaster. It's specially designed to prevent back injuries caused by pushing paper."
+ icon_state = "qm_skirt"
+ item_state = "lb_suit"
+ item_color = "qm_skirt"
+ body_parts_covered = CHEST|GROIN|ARMS
+ can_adjust = FALSE
+ fitted = FEMALE_UNIFORM_TOP
+
/obj/item/clothing/under/rank/cargotech
name = "cargo technician's jumpsuit"
desc = "Shooooorts! They're comfy and easy to wear!"
@@ -42,6 +72,15 @@
mutantrace_variation = MUTANTRACE_VARIATION
alt_covers_chest = TRUE
+/obj/item/clothing/under/rank/cargotech/skirt
+ name = "cargo technician's jumpskirt"
+ desc = "Skiiiiirts! They're comfy and easy to wear"
+ icon_state = "cargo_skirt"
+ item_state = "lb_suit"
+ item_color = "cargo_skirt"
+ body_parts_covered = CHEST|GROIN|ARMS
+ can_adjust = FALSE
+ fitted = FEMALE_UNIFORM_TOP
/obj/item/clothing/under/rank/chaplain
desc = "It's a black jumpsuit, often worn by religious folk."
@@ -51,6 +90,16 @@
item_color = "chapblack"
can_adjust = FALSE
+/obj/item/clothing/under/rank/chaplain/skirt
+ name = "chaplain's jumpskirt"
+ desc = "It's a black jumpskirt, often worn by religious folk."
+ icon_state = "chapblack_skirt"
+ item_state = "bl_suit"
+ item_color = "chapblack_skirt"
+ body_parts_covered = CHEST|GROIN|ARMS
+ can_adjust = FALSE
+ fitted = FEMALE_UNIFORM_TOP
+
/obj/item/clothing/under/rank/chef
name = "cook's suit"
desc = "A suit which is given only to the most hardcore cooks in space."
@@ -58,6 +107,15 @@
item_color = "chef"
alt_covers_chest = TRUE
+/obj/item/clothing/under/rank/chef/skirt
+ name = "cook's skirt"
+ desc = "A skirt which is given only to the most hardcore cooks in space."
+ icon_state = "chef_skirt"
+ item_color = "chef_skirt"
+ body_parts_covered = CHEST|GROIN|ARMS
+ can_adjust = FALSE
+ fitted = FEMALE_UNIFORM_TOP
+
/obj/item/clothing/under/rank/clown
name = "clown suit"
desc = "'HONK!'"
@@ -66,7 +124,6 @@
item_color = "clown"
fitted = FEMALE_UNIFORM_TOP
can_adjust = FALSE
-
/obj/item/clothing/under/rank/blueclown
name = "blue clown suit"
desc = "'BLUE HONK!'"
@@ -130,7 +187,6 @@
/obj/item/clothing/under/rank/clown/Initialize()
. = ..()
AddComponent(/datum/component/squeak, list('sound/items/bikehorn.ogg'=1), 50)
-
/obj/item/clothing/under/rank/head_of_personnel
desc = "It's a jumpsuit worn by someone who works in the position of \"Head of Personnel\"."
name = "head of personnel's jumpsuit"
@@ -139,6 +195,16 @@
item_color = "hop"
can_adjust = FALSE
+/obj/item/clothing/under/rank/head_of_personnel/skirt
+ name = "head of personnel's jumpskirt"
+ desc = "It's a jumpskirt worn by someone who works in the position of \"Head of Personnel\"."
+ icon_state = "hop_skirt"
+ item_state = "b_suit"
+ item_color = "hop_skirt"
+ body_parts_covered = CHEST|GROIN|ARMS
+ can_adjust = FALSE
+ fitted = FEMALE_UNIFORM_TOP
+
/obj/item/clothing/under/rank/hydroponics
desc = "It's a jumpsuit designed to protect against minor plant-related hazards."
name = "botanist's jumpsuit"
@@ -147,6 +213,16 @@
item_color = "hydroponics"
permeability_coefficient = 0.5
+/obj/item/clothing/under/rank/hydroponics/skirt
+ name = "botanist's jumpskirt"
+ desc = "It's a jumpskirt designed to protect against minor plant-related hazards."
+ icon_state = "hydroponics_skirt"
+ item_state = "g_suit"
+ item_color = "hydroponics_skirt"
+ body_parts_covered = CHEST|GROIN|ARMS
+ can_adjust = FALSE
+ fitted = FEMALE_UNIFORM_TOP
+
/obj/item/clothing/under/rank/janitor
desc = "It's the official uniform of the station's janitor. It has minor protection from biohazards."
name = "janitor's jumpsuit"
@@ -154,49 +230,108 @@
item_color = "janitor"
armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 10, "rad" = 0, "fire" = 0, "acid" = 0)
+/obj/item/clothing/under/rank/janitor/skirt
+ name = "janitor's jumpskirt"
+ desc = "It's the official skirt of the station's janitor. It has minor protection from biohazards."
+ icon_state = "janitor_skirt"
+ item_color = "janitor_skirt"
+ body_parts_covered = CHEST|GROIN|ARMS
+ can_adjust = FALSE
+ fitted = FEMALE_UNIFORM_TOP
+
/obj/item/clothing/under/lawyer
desc = "Slick threads."
name = "Lawyer suit"
can_adjust = FALSE
-
/obj/item/clothing/under/lawyer/black
+ name = "lawyer black suit"
icon_state = "lawyer_black"
item_state = "lawyer_black"
item_color = "lawyer_black"
+/obj/item/clothing/under/lawyer/black/skirt
+ name = "lawyer black suitskirt"
+ icon_state = "lawyer_black_skirt"
+ item_state = "lawyer_black"
+ item_color = "lawyer_black_skirt"
+ fitted = FEMALE_UNIFORM_TOP
+
/obj/item/clothing/under/lawyer/female
+ name = "female black suit"
icon_state = "black_suit_fem"
- item_state = "black_suit_fem"
+ item_state = "bl_suit"
item_color = "black_suit_fem"
/obj/item/clothing/under/lawyer/red
+ name = "lawyer red suit"
icon_state = "lawyer_red"
item_state = "lawyer_red"
item_color = "lawyer_red"
+/obj/item/clothing/under/lawyer/female/skirt
+ name = "female black suitskirt"
+ icon_state = "black_suit_fem_skirt"
+ item_state = "bl_suit"
+ item_color = "black_suit_fem_skirt"
+ fitted = FEMALE_UNIFORM_TOP
+
+/obj/item/clothing/under/lawyer/red/skirt
+ name = "lawyer red suitskirt"
+ icon_state = "lawyer_red_skirt"
+ item_state = "lawyer_red"
+ item_color = "lawyer_red_skirt"
+ fitted = FEMALE_UNIFORM_TOP
+
/obj/item/clothing/under/lawyer/blue
+ name = "lawyer blue suit"
icon_state = "lawyer_blue"
item_state = "lawyer_blue"
item_color = "lawyer_blue"
+/obj/item/clothing/under/lawyer/blue/skirt
+ name = "lawyer blue suitskirt"
+ icon_state = "lawyer_blue_skirt"
+ item_state = "lawyer_blue"
+ item_color = "lawyer_blue_skirt"
+ fitted = FEMALE_UNIFORM_TOP
+
/obj/item/clothing/under/lawyer/bluesuit
name = "blue suit"
desc = "A classy suit and tie."
icon_state = "bluesuit"
- item_state = "bluesuit"
+ item_state = "b_suit"
item_color = "bluesuit"
can_adjust = TRUE
alt_covers_chest = TRUE
+/obj/item/clothing/under/lawyer/bluesuit/skirt
+ name = "blue suitskirt"
+ desc = "A classy suitskirt and tie."
+ icon_state = "bluesuit_skirt"
+ item_state = "b_suit"
+ item_color = "bluesuit_skirt"
+ body_parts_covered = CHEST|GROIN|ARMS
+ can_adjust = FALSE
+ fitted = FEMALE_UNIFORM_TOP
+
/obj/item/clothing/under/lawyer/purpsuit
name = "purple suit"
icon_state = "lawyer_purp"
- item_state = "lawyer_purp"
+ item_state = "p_suit"
item_color = "lawyer_purp"
fitted = NO_FEMALE_UNIFORM
can_adjust = TRUE
alt_covers_chest = TRUE
+/obj/item/clothing/under/lawyer/purpsuit/skirt
+ name = "purple suitskirt"
+ icon_state = "lawyer_purp_skirt"
+ item_state = "p_suit"
+ item_color = "lawyer_purp_skirt"
+ body_parts_covered = CHEST|GROIN|ARMS
+ can_adjust = FALSE
+ fitted = FEMALE_UNIFORM_TOP
+
/obj/item/clothing/under/lawyer/blacksuit
name = "black suit"
desc = "A professional black suit. Nanotrasen Investigation Bureau approved!"
@@ -206,6 +341,16 @@
can_adjust = TRUE
alt_covers_chest = TRUE
+/obj/item/clothing/under/lawyer/blacksuit/skirt
+ name = "black suitskirt"
+ desc = "A professional black suit. Nanotrasen Investigation Bureau approved!"
+ icon_state = "blacksuit_skirt"
+ item_state = "bar_suit"
+ item_color = "blacksuit_skirt"
+ can_adjust = FALSE
+ alt_covers_chest = TRUE
+ fitted = FEMALE_UNIFORM_TOP
+
/obj/item/clothing/under/rank/curator
name = "sensible suit"
desc = "It's very... sensible."
@@ -214,6 +359,33 @@
item_color = "red_suit"
can_adjust = FALSE
+/obj/item/clothing/under/lawyer/really_black
+ name = "executive suit"
+ desc = "A formal black suit and red tie, intended for the station's finest."
+ icon_state = "really_black_suit"
+ item_state = "bl_suit"
+ item_color = "really_black_suit"
+
+/obj/item/clothing/under/lawyer/really_black/skirt
+ name = "executive suitskirt"
+ desc = "A formal black suitskirt and red tie, intended for the station's finest."
+ icon_state = "really_black_suit_skirt"
+ item_state = "bl_suit"
+ item_color = "really_black_suit_skirt"
+ body_parts_covered = CHEST|GROIN|ARMS
+ can_adjust = FALSE
+ fitted = FEMALE_UNIFORM_TOP
+
+/obj/item/clothing/under/rank/curator/skirt
+ name = "sensible suitskirt"
+ desc = "It's very... sensible."
+ icon_state = "red_suit_skirt"
+ item_state = "red_suit"
+ item_color = "red_suit_skirt"
+ body_parts_covered = CHEST|GROIN|ARMS
+ can_adjust = FALSE
+ fitted = FEMALE_UNIFORM_TOP
+
/obj/item/clothing/under/rank/curator/treasure_hunter
name = "treasure hunter uniform"
desc = "A rugged uniform suitable for treasure hunting."
@@ -228,13 +400,22 @@
item_state = "mime"
item_color = "mime"
+/obj/item/clothing/under/rank/mime/skirt
+ name = "mime's skirt"
+ desc = "It's not very colourful."
+ icon_state = "mime_skirt"
+ item_state = "mime"
+ item_color = "mime_skirt"
+ body_parts_covered = CHEST|GROIN|ARMS
+ can_adjust = FALSE
+ fitted = FEMALE_UNIFORM_TOP
+
/obj/item/clothing/under/rank/miner
desc = "It's a snappy jumpsuit with a sturdy set of overalls. It is very dirty."
name = "shaft miner's jumpsuit"
icon_state = "miner"
item_state = "miner"
item_color = "miner"
-
/obj/item/clothing/under/rank/miner/lavaland
desc = "A green uniform for operating in hazardous environments."
name = "shaft miner's jumpsuit"
diff --git a/code/modules/clothing/under/jobs/engineering.dm b/code/modules/clothing/under/jobs/engineering.dm
index 4ee0963a64..f65b05c280 100644
--- a/code/modules/clothing/under/jobs/engineering.dm
+++ b/code/modules/clothing/under/jobs/engineering.dm
@@ -8,6 +8,16 @@
armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 10, "fire" = 80, "acid" = 40)
resistance_flags = NONE
+/obj/item/clothing/under/rank/chief_engineer/skirt
+ name = "chief engineer's jumpskirt"
+ desc = "It's a high visibility jumpskirt given to those engineers insane enough to achieve the rank of \"Chief Engineer\". It has minor radiation shielding."
+ icon_state = "chief_skirt"
+ item_state = "gy_suit"
+ item_color = "chief_skirt"
+ body_parts_covered = CHEST|GROIN|ARMS
+ can_adjust = FALSE
+ fitted = FEMALE_UNIFORM_TOP
+
/obj/item/clothing/under/rank/atmospheric_technician
desc = "It's a jumpsuit worn by atmospheric technicians."
name = "atmospheric technician's jumpsuit"
@@ -16,6 +26,16 @@
item_color = "atmos"
resistance_flags = NONE
+/obj/item/clothing/under/rank/atmospheric_technician/skirt
+ name = "atmospheric technician's jumpskirt"
+ desc = "It's a jumpskirt worn by atmospheric technicians."
+ icon_state = "atmos_skirt"
+ item_state = "atmos_suit"
+ item_color = "atmos_skirt"
+ body_parts_covered = CHEST|GROIN|ARMS
+ can_adjust = FALSE
+ fitted = FEMALE_UNIFORM_TOP
+
/obj/item/clothing/under/rank/engineer
desc = "It's an orange high visibility jumpsuit worn by engineers. It has minor radiation shielding."
name = "engineer's jumpsuit"
@@ -24,6 +44,23 @@
item_color = "engine"
armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 10, "fire" = 60, "acid" = 20)
resistance_flags = NONE
+/obj/item/clothing/under/rank/engineer/hazard
+ name = "engineer's hazard jumpsuit"
+ desc = "A high visibility jumpsuit made from heat and radiation resistant materials."
+ icon_state = "hazard"
+ item_state = "suit-orange"
+ item_color = "hazard"
+ alt_covers_chest = TRUE
+
+/obj/item/clothing/under/rank/engineer/skirt
+ name = "engineer's jumpskirt"
+ desc = "It's an orange high visibility jumpskirt worn by engineers."
+ icon_state = "engine_skirt"
+ item_state = "engi_suit"
+ item_color = "engine_skirt"
+ body_parts_covered = CHEST|GROIN|ARMS
+ can_adjust = FALSE
+ fitted = FEMALE_UNIFORM_TOP
/obj/item/clothing/under/rank/roboticist
desc = "It's a slimming black with reinforced seams; great for industrial work."
@@ -31,4 +68,14 @@
icon_state = "robotics"
item_state = "robotics"
item_color = "robotics"
- resistance_flags = NONE
\ No newline at end of file
+ resistance_flags = NONE
+
+/obj/item/clothing/under/rank/roboticist/skirt
+ name = "roboticist's jumpskirt"
+ desc = "It's a slimming black with reinforced seams; great for industrial work."
+ icon_state = "robotics_skirt"
+ item_state = "robotics"
+ item_color = "robotics_skirt"
+ body_parts_covered = CHEST|GROIN|ARMS
+ can_adjust = FALSE
+ fitted = FEMALE_UNIFORM_TOP
diff --git a/code/modules/clothing/under/jobs/medsci.dm b/code/modules/clothing/under/jobs/medsci.dm
index f0980cae4d..7b7a205021 100644
--- a/code/modules/clothing/under/jobs/medsci.dm
+++ b/code/modules/clothing/under/jobs/medsci.dm
@@ -10,6 +10,16 @@
armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 10, "bio" = 10, "rad" = 0, "fire" = 0, "acid" = 35)
can_adjust = FALSE
+/obj/item/clothing/under/rank/research_director/skirt
+ name = "research director's vest suitskirt"
+ desc = "It's a suitskirt worn by those with the know-how to achieve the position of \"Research Director\". Its fabric provides minor protection from biological contaminants."
+ icon_state = "director_skirt"
+ item_state = "lb_suit"
+ item_color = "director_skirt"
+ body_parts_covered = CHEST|GROIN|ARMS
+ can_adjust = FALSE
+ fitted = FEMALE_UNIFORM_TOP
+
/obj/item/clothing/under/rank/research_director/alt
desc = "Maybe you'll engineer your own half-man, half-pig creature some day. Its fabric provides minor protection from biological contaminants."
name = "research director's tan suit"
@@ -20,6 +30,16 @@
can_adjust = TRUE
alt_covers_chest = TRUE
+/obj/item/clothing/under/rank/research_director/alt/skirt
+ name = "research director's tan suitskirt"
+ desc = "Maybe you'll engineer your own half-man, half-pig creature some day. Its fabric provides minor protection from biological contaminants."
+ icon_state = "rdwhimsy_skirt"
+ item_state = "rdwhimsy"
+ item_color = "rdwhimsy_skirt"
+ body_parts_covered = CHEST|GROIN|ARMS
+ can_adjust = FALSE
+ fitted = FEMALE_UNIFORM_TOP
+
/obj/item/clothing/under/rank/research_director/turtleneck
desc = "A dark purple turtleneck and tan khakis, for a director with a superior sense of style."
name = "research director's turtleneck"
@@ -30,6 +50,16 @@
can_adjust = TRUE
alt_covers_chest = TRUE
+/obj/item/clothing/under/rank/research_director/turtleneck/skirt
+ name = "research director's turtleneck skirt"
+ desc = "A dark purple turtleneck and tan khaki skirt, for a director with a superior sense of style."
+ icon_state = "rdturtle_skirt"
+ item_state = "p_suit"
+ item_color = "rdturtle_skirt"
+ body_parts_covered = CHEST|GROIN|ARMS
+ can_adjust = FALSE
+ fitted = FEMALE_UNIFORM_TOP
+
/obj/item/clothing/under/rank/scientist
desc = "It's made of a special fiber that provides minor protection against explosives. It has markings that denote the wearer as a scientist."
name = "scientist's jumpsuit"
@@ -39,6 +69,15 @@
permeability_coefficient = 0.5
armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 10, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 0)
+/obj/item/clothing/under/rank/scientist/skirt
+ name = "scientist's jumpskirt"
+ desc = "It's made of a special fiber that provides minor protection against explosives. It has markings that denote the wearer as a scientist."
+ icon_state = "toxinswhite_skirt"
+ item_state = "w_suit"
+ item_color = "toxinswhite_skirt"
+ body_parts_covered = CHEST|GROIN|ARMS
+ can_adjust = FALSE
+ fitted = FEMALE_UNIFORM_TOP
/obj/item/clothing/under/rank/chemist
desc = "It's made of a special fiber that gives special protection against biohazards. It has a chemist rank stripe on it."
@@ -49,6 +88,16 @@
permeability_coefficient = 0.5
armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 10, "rad" = 0, "fire" = 50, "acid" = 65)
+/obj/item/clothing/under/rank/chemist/skirt
+ name = "chemist's jumpskirt"
+ desc = "It's made of a special fiber that gives special protection against biohazards. It has a chemist rank stripe on it."
+ icon_state = "chemistrywhite_skirt"
+ item_state = "w_suit"
+ item_color = "chemistrywhite_skirt"
+ body_parts_covered = CHEST|GROIN|ARMS
+ can_adjust = FALSE
+ fitted = FEMALE_UNIFORM_TOP
+
/*
* Medical
*/
@@ -61,6 +110,16 @@
permeability_coefficient = 0.5
armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 10, "rad" = 0, "fire" = 0, "acid" = 0)
+/obj/item/clothing/under/rank/chief_medical_officer/skirt
+ name = "chief medical officer's jumpskirt"
+ desc = "It's a jumpskirt worn by those with the experience to be \"Chief Medical Officer\". It provides minor biological protection."
+ icon_state = "cmo_skirt"
+ item_state = "w_suit"
+ item_color = "cmo_skirt"
+ body_parts_covered = CHEST|GROIN|ARMS
+ can_adjust = FALSE
+ fitted = FEMALE_UNIFORM_TOP
+
/obj/item/clothing/under/rank/geneticist
desc = "It's made of a special fiber that gives special protection against biohazards. It has a genetics rank stripe on it."
name = "geneticist's jumpsuit"
@@ -70,6 +129,16 @@
permeability_coefficient = 0.5
armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 10, "rad" = 0, "fire" = 0, "acid" = 0)
+/obj/item/clothing/under/rank/geneticist/skirt
+ name = "geneticist's jumpskirt"
+ desc = "It's made of a special fiber that gives special protection against biohazards. It has a genetics rank stripe on it."
+ icon_state = "geneticswhite_skirt"
+ item_state = "w_suit"
+ item_color = "geneticswhite_skirt"
+ body_parts_covered = CHEST|GROIN|ARMS
+ can_adjust = FALSE
+ fitted = FEMALE_UNIFORM_TOP
+
/obj/item/clothing/under/rank/virologist
desc = "It's made of a special fiber that gives special protection against biohazards. It has a virologist rank stripe on it."
name = "virologist's jumpsuit"
@@ -79,6 +148,16 @@
permeability_coefficient = 0.5
armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 10, "rad" = 0, "fire" = 0, "acid" = 0)
+/obj/item/clothing/under/rank/virologist/skirt
+ name = "virologist's jumpskirt"
+ desc = "It's made of a special fiber that gives special protection against biohazards. It has a virologist rank stripe on it."
+ icon_state = "virologywhite_skirt"
+ item_state = "w_suit"
+ item_color = "virologywhite_skirt"
+ body_parts_covered = CHEST|GROIN|ARMS
+ can_adjust = FALSE
+ fitted = FEMALE_UNIFORM_TOP
+
/obj/item/clothing/under/rank/nursesuit
desc = "It's a jumpsuit commonly worn by nursing staff in the medical department."
name = "nurse's suit"
@@ -90,7 +169,6 @@
body_parts_covered = CHEST|GROIN|ARMS
fitted = NO_FEMALE_UNIFORM
can_adjust = FALSE
-
/obj/item/clothing/under/rank/medical
desc = "It's made of a special fiber that provides minor protection against biohazards. It has a cross on the chest denoting that the wearer is trained medical personnel."
name = "medical doctor's jumpsuit"
@@ -99,24 +177,31 @@
item_color = "medical"
permeability_coefficient = 0.5
armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 10, "rad" = 0, "fire" = 0, "acid" = 0)
-
/obj/item/clothing/under/rank/medical/blue
name = "medical scrubs"
desc = "It's made of a special fiber that provides minor protection against biohazards. This one is in baby blue."
icon_state = "scrubsblue"
item_color = "scrubsblue"
can_adjust = FALSE
-
/obj/item/clothing/under/rank/medical/green
name = "medical scrubs"
desc = "It's made of a special fiber that provides minor protection against biohazards. This one is in dark green."
icon_state = "scrubsgreen"
item_color = "scrubsgreen"
can_adjust = FALSE
-
/obj/item/clothing/under/rank/medical/purple
name = "medical scrubs"
desc = "It's made of a special fiber that provides minor protection against biohazards. This one is in deep purple."
icon_state = "scrubspurple"
item_color = "scrubspurple"
can_adjust = FALSE
+
+/obj/item/clothing/under/rank/medical/skirt
+ name = "medical doctor's jumpskirt"
+ desc = "It's made of a special fiber that provides minor protection against biohazards. It has a cross on the chest denoting that the wearer is trained medical personnel."
+ icon_state = "medical_skirt"
+ item_state = "w_suit"
+ item_color = "medical_skirt"
+ body_parts_covered = CHEST|GROIN|ARMS
+ can_adjust = FALSE
+ fitted = FEMALE_UNIFORM_TOP
diff --git a/code/modules/clothing/under/jobs/security.dm b/code/modules/clothing/under/jobs/security.dm
index 6f9e77b09f..6c00d6969c 100644
--- a/code/modules/clothing/under/jobs/security.dm
+++ b/code/modules/clothing/under/jobs/security.dm
@@ -4,11 +4,9 @@
* Detective
* Navy uniforms
*/
-
/*
* Security
*/
-
/obj/item/clothing/under/rank/security
name = "security jumpsuit"
desc = "A tactical security jumpsuit for officers complete with Nanotrasen belt buckle."
@@ -20,14 +18,12 @@
alt_covers_chest = TRUE
sensor_mode = SENSOR_COORDS
random_sensor = FALSE
-
/obj/item/clothing/under/rank/security/grey
name = "grey security jumpsuit"
desc = "A tactical relic of years past before Nanotrasen decided it was cheaper to dye the suits red instead of washing out the blood."
icon_state = "security"
item_state = "gy_suit"
item_color = "security"
-
/obj/item/clothing/under/rank/security/skirt
name = "security jumpskirt"
desc = "A \"tactical\" security jumpsuit with the legs replaced by a skirt."
@@ -36,6 +32,7 @@
item_color = "secskirt"
body_parts_covered = CHEST|GROIN|ARMS
can_adjust = FALSE //you know now that i think of it if you adjust the skirt and the sprite disappears isn't that just like flashing everyone
+ fitted = FEMALE_UNIFORM_TOP
/obj/item/clothing/under/rank/warden
@@ -49,7 +46,6 @@
alt_covers_chest = TRUE
sensor_mode = 3
random_sensor = FALSE
-
/obj/item/clothing/under/rank/warden/grey
name = "grey security suit"
desc = "A formal relic of years past before Nanotrasen decided it was cheaper to dye the suits red instead of washing out the blood."
@@ -57,6 +53,16 @@
item_state = "gy_suit"
item_color = "warden"
+/obj/item/clothing/under/rank/warden/skirt
+ name = "warden's suitskirt"
+ desc = "A formal security suitskirt for officers complete with Nanotrasen belt buckle."
+ icon_state = "rwarden_skirt"
+ item_state = "r_suit"
+ item_color = "rwarden_skirt"
+ body_parts_covered = CHEST|GROIN|ARMS
+ can_adjust = FALSE
+ fitted = FEMALE_UNIFORM_TOP
+
/*
* Detective
*/
@@ -72,6 +78,16 @@
sensor_mode = 3
random_sensor = FALSE
+/obj/item/clothing/under/rank/det/skirt
+ name = "detective's suitskirt"
+ desc = "Someone who wears this means business."
+ icon_state = "detective_skirt"
+ item_state = "det"
+ item_color = "detective_skirt"
+ body_parts_covered = CHEST|GROIN|ARMS
+ can_adjust = FALSE
+ fitted = FEMALE_UNIFORM_TOP
+
/obj/item/clothing/under/rank/det/grey
name = "noir suit"
desc = "A hard-boiled private investigator's grey suit, complete with tie clip."
@@ -80,6 +96,16 @@
item_color = "greydet"
alt_covers_chest = TRUE
+/obj/item/clothing/under/rank/det/grey/skirt
+ name = "noir suitskirt"
+ desc = "A hard-boiled private investigator's grey suitskirt, complete with tie clip."
+ icon_state = "greydet_skirt"
+ item_state = "greydet"
+ item_color = "greydet_skirt"
+ body_parts_covered = CHEST|GROIN|ARMS
+ can_adjust = FALSE
+ fitted = FEMALE_UNIFORM_TOP
+
/*
* Head of Security
*/
@@ -95,13 +121,22 @@
sensor_mode = 3
random_sensor = FALSE
+/obj/item/clothing/under/rank/head_of_security/skirt
+ name = "head of security's jumpskirt"
+ desc = "A security jumpskirt decorated for those few with the dedication to achieve the position of Head of Security."
+ icon_state = "rhos_skirt"
+ item_state = "r_suit"
+ item_color = "rhos_skirt"
+ body_parts_covered = CHEST|GROIN|ARMS
+ can_adjust = FALSE
+ fitted = FEMALE_UNIFORM_TOP
+
/obj/item/clothing/under/rank/head_of_security/grey
name = "head of security's grey jumpsuit"
desc = "There are old men, and there are bold men, but there are very few old, bold men."
icon_state = "hos"
item_state = "gy_suit"
item_color = "hos"
-
/obj/item/clothing/under/rank/head_of_security/alt
name = "head of security's turtleneck"
desc = "A stylish alternative to the normal head of security jumpsuit, complete with tactical pants."
@@ -109,10 +144,19 @@
item_state = "bl_suit"
item_color = "hosalt"
+/obj/item/clothing/under/rank/head_of_security/alt/skirt
+ name = "head of security's turtleneck skirt"
+ desc = "A stylish alternative to the normal head of security jumpsuit, complete with a tactical skirt."
+ icon_state = "hosalt_skirt"
+ item_state = "bl_suit"
+ item_color = "hosalt_skirt"
+ body_parts_covered = CHEST|GROIN|ARMS
+ can_adjust = FALSE
+ fitted = FEMALE_UNIFORM_TOP
+
/*
* Navy uniforms
*/
-
/obj/item/clothing/under/rank/security/navyblue
name = "security officer's formal uniform"
desc = "The latest in fashionable security outfits."
@@ -120,7 +164,6 @@
item_state = "officerblueclothes"
item_color = "officerblueclothes"
alt_covers_chest = TRUE
-
/obj/item/clothing/under/rank/head_of_security/navyblue
desc = "The insignia on this uniform tells you that this uniform belongs to the Head of Security."
name = "head of security's formal uniform"
@@ -128,7 +171,6 @@
item_state = "hosblueclothes"
item_color = "hosblueclothes"
alt_covers_chest = TRUE
-
/obj/item/clothing/under/rank/warden/navyblue
desc = "The insignia on this uniform tells you that this uniform belongs to the Warden."
name = "warden's formal uniform"
@@ -136,11 +178,9 @@
item_state = "wardenblueclothes"
item_color = "wardenblueclothes"
alt_covers_chest = TRUE
-
/*
*Blueshirt
*/
-
/obj/item/clothing/under/rank/security/blueshirt
name = "blue shirt and tie"
desc = "I'm a little busy right now, Calhoun."
@@ -148,3 +188,13 @@
item_state = "blueshift"
item_color = "blueshift"
can_adjust = FALSE
+/*
+ *Spacepol
+ */
+/obj/item/clothing/under/rank/security/spacepol
+ name = "police uniform"
+ desc = "Space not controlled by megacorporations, planets, or pirates is under the jurisdiction of Spacepol."
+ icon_state = "spacepol"
+ item_state = "spacepol"
+ item_color = "spacepol"
+ can_adjust = FALSE
diff --git a/code/modules/clothing/under/miscellaneous.dm b/code/modules/clothing/under/miscellaneous.dm
index 16848e393a..17ddacb32f 100644
--- a/code/modules/clothing/under/miscellaneous.dm
+++ b/code/modules/clothing/under/miscellaneous.dm
@@ -5,7 +5,6 @@
item_color = "red_pyjamas"
item_state = "w_suit"
can_adjust = FALSE
-
/obj/item/clothing/under/pj/blue
name = "blue pj's"
desc = "Sleepwear."
@@ -13,7 +12,6 @@
item_color = "blue_pyjamas"
item_state = "w_suit"
can_adjust = FALSE
-
/obj/item/clothing/under/patriotsuit
name = "Patriotic Suit"
desc = "Motorcycle not included."
@@ -21,7 +19,6 @@
item_state = "ek"
item_color = "ek"
can_adjust = FALSE
-
/obj/item/clothing/under/scratch
name = "white suit"
desc = "A white suit, suitable for an excellent host."
@@ -30,13 +27,22 @@
item_color = "scratch"
can_adjust = FALSE
+/obj/item/clothing/under/scratch/skirt
+ name = "white suitskirt"
+ desc = "A white suitskirt, suitable for an excellent host."
+ icon_state = "white_suit_skirt"
+ item_state = "scratch"
+ item_color = "white_suit_skirt"
+ body_parts_covered = CHEST|GROIN|ARMS
+ can_adjust = FALSE
+ fitted = FEMALE_UNIFORM_TOP
+
/obj/item/clothing/under/sl_suit
desc = "It's a very amish looking suit."
name = "amish suit"
icon_state = "sl_suit"
item_color = "sl_suit"
can_adjust = FALSE
-
/obj/item/clothing/under/roman
name = "\improper Roman armor"
desc = "Ancient Roman armor. Made of metallic and leather straps."
@@ -46,7 +52,6 @@
can_adjust = FALSE
strip_delay = 100
resistance_flags = NONE
-
/obj/item/clothing/under/waiter
name = "waiter's outfit"
desc = "It's a very smart uniform with a special pocket for tip."
@@ -54,7 +59,6 @@
item_state = "waiter"
item_color = "waiter"
can_adjust = FALSE
-
/obj/item/clothing/under/rank/prisoner
name = "prison jumpsuit"
desc = "It's standardised Nanotrasen prisoner-wear. Its suit sensors are stuck in the \"Fully On\" position."
@@ -65,20 +69,28 @@
sensor_mode = SENSOR_COORDS
random_sensor = FALSE
+/obj/item/clothing/under/rank/prisoner/skirt
+ name = "prison jumpskirt"
+ desc = "It's standardised Nanotrasen prisoner-wear. Its suit sensors are stuck in the \"Fully On\" position."
+ icon_state = "prisoner_skirt"
+ item_state = "o_suit"
+ item_color = "prisoner_skirt"
+ body_parts_covered = CHEST|GROIN|ARMS
+ can_adjust = FALSE
+ fitted = FEMALE_UNIFORM_TOP
+
/obj/item/clothing/under/rank/mailman
name = "mailman's jumpsuit"
desc = "'Special delivery!'"
icon_state = "mailman"
item_state = "b_suit"
item_color = "mailman"
-
/obj/item/clothing/under/rank/psyche
name = "psychedelic jumpsuit"
desc = "Groovy!"
icon_state = "psyche"
item_state = "p_suit"
item_color = "psyche"
-
/obj/item/clothing/under/rank/clown/sexy
name = "sexy-clown suit"
desc = "It makes you look HONKable!"
@@ -86,7 +98,6 @@
item_state = "sexyclown"
item_color = "sexyclown"
can_adjust = FALSE
-
/obj/item/clothing/under/jabroni
name = "Jabroni Outfit"
desc = "The leather club is two sectors down."
@@ -94,7 +105,6 @@
item_state = "darkholme"
item_color = "darkholme"
can_adjust = FALSE
-
/obj/item/clothing/under/rank/vice
name = "vice officer's jumpsuit"
desc = "It's the standard issue pretty-boy outfit, as seen on Holo-Vision."
@@ -102,7 +112,6 @@
item_state = "gy_suit"
item_color = "vice"
can_adjust = FALSE
-
/obj/item/clothing/under/rank/centcom_officer
desc = "It's a jumpsuit worn by CentCom Officers."
name = "\improper CentCom officer's jumpsuit"
@@ -110,14 +119,12 @@
item_state = "g_suit"
item_color = "officer"
alt_covers_chest = TRUE
-
/obj/item/clothing/under/rank/centcom_commander
desc = "It's a jumpsuit worn by CentCom's highest-tier Commanders."
name = "\improper CentCom officer's jumpsuit"
icon_state = "centcom"
item_state = "dg_suit"
item_color = "centcom"
-
/obj/item/clothing/under/space
name = "\improper NASA jumpsuit"
desc = "It has a NASA logo on it and is made of space-proofed materials."
@@ -134,7 +141,6 @@
max_heat_protection_temperature = SPACE_SUIT_MAX_TEMP_PROTECT
can_adjust = FALSE
resistance_flags = NONE
-
/obj/item/clothing/under/acj
name = "administrative cybernetic jumpsuit"
icon_state = "syndicate"
@@ -151,28 +157,24 @@
max_heat_protection_temperature = SPACE_SUIT_MAX_TEMP_PROTECT
can_adjust = FALSE
resistance_flags = FIRE_PROOF | ACID_PROOF
-
/obj/item/clothing/under/owl
name = "owl uniform"
desc = "A soft brown jumpsuit made of synthetic feathers and strong conviction."
icon_state = "owl"
item_color = "owl"
can_adjust = FALSE
-
/obj/item/clothing/under/griffin
name = "griffon uniform"
desc = "A soft brown jumpsuit with a white feather collar made of synthetic feathers and a lust for mayhem."
icon_state = "griffin"
item_color = "griffin"
can_adjust = FALSE
-
/obj/item/clothing/under/cloud
name = "cloud"
desc = "cloud"
icon_state = "cloud"
item_color = "cloud"
can_adjust = FALSE
-
/obj/item/clothing/under/gimmick/rank/captain/suit
name = "captain's suit"
desc = "A green suit and yellow necktie. Exemplifies authority."
@@ -181,6 +183,16 @@
item_color = "green_suit"
can_adjust = FALSE
+/obj/item/clothing/under/gimmick/rank/captain/suit/skirt
+ name = "green suitskirt"
+ desc = "A green suitskirt and yellow necktie. Exemplifies authority."
+ icon_state = "green_suit_skirt"
+ item_state = "dg_suit"
+ item_color = "green_suit_skirt"
+ body_parts_covered = CHEST|GROIN|ARMS
+ can_adjust = FALSE
+ fitted = FEMALE_UNIFORM_TOP
+
/obj/item/clothing/under/gimmick/rank/head_of_personnel/suit
name = "head of personnel's suit"
desc = "A teal suit and yellow necktie. An authoritative yet tacky ensemble."
@@ -189,6 +201,16 @@
item_color = "teal_suit"
can_adjust = FALSE
+/obj/item/clothing/under/gimmick/rank/head_of_personnel/suit/skirt
+ name = "teal suitskirt"
+ desc = "A teal suitskirt and yellow necktie. An authoritative yet tacky ensemble."
+ icon_state = "teal_suit_skirt"
+ item_state = "g_suit"
+ item_color = "teal_suit_skirt"
+ body_parts_covered = CHEST|GROIN|ARMS
+ can_adjust = FALSE
+ fitted = FEMALE_UNIFORM_TOP
+
/obj/item/clothing/under/suit_jacket
name = "black suit"
desc = "A black suit and red tie. Very formal."
@@ -196,21 +218,18 @@
item_state = "bl_suit"
item_color = "black_suit"
can_adjust = FALSE
-
/obj/item/clothing/under/suit_jacket/really_black
name = "executive suit"
desc = "A formal black suit and red tie, intended for the station's finest."
icon_state = "really_black_suit"
item_state = "bl_suit"
- item_color = "black_suit"
-
+ item_color = "really_black_suit"
/obj/item/clothing/under/suit_jacket/female
name = "executive suit"
desc = "A formal trouser suit for women, intended for the station's finest."
icon_state = "black_suit_fem"
item_state = "black_suit_fem"
item_color = "black_suit_fem"
-
/obj/item/clothing/under/suit_jacket/green
name = "green suit"
desc = "A green suit and yellow necktie. Baller."
@@ -218,56 +237,48 @@
item_state = "dg_suit"
item_color = "green_suit"
can_adjust = FALSE
-
/obj/item/clothing/under/suit_jacket/red
name = "red suit"
desc = "A red suit and blue tie. Somewhat formal."
icon_state = "red_suit"
item_state = "r_suit"
item_color = "red_suit"
-
/obj/item/clothing/under/suit_jacket/charcoal
name = "charcoal suit"
desc = "A charcoal suit and red tie. Very professional."
icon_state = "charcoal_suit"
item_state = "charcoal_suit"
item_color = "charcoal_suit"
-
/obj/item/clothing/under/suit_jacket/navy
name = "navy suit"
desc = "A navy suit and red tie, intended for the station's finest."
icon_state = "navy_suit"
item_state = "navy_suit"
item_color = "navy_suit"
-
/obj/item/clothing/under/suit_jacket/burgundy
name = "burgundy suit"
desc = "A burgundy suit and black tie. Somewhat formal."
icon_state = "burgundy_suit"
item_state = "burgundy_suit"
item_color = "burgundy_suit"
-
/obj/item/clothing/under/suit_jacket/checkered
name = "checkered suit"
desc = "That's a very nice suit you have there. Shame if something were to happen to it, eh?"
icon_state = "checkered_suit"
item_state = "checkered_suit"
item_color = "checkered_suit"
-
/obj/item/clothing/under/suit_jacket/tan
name = "tan suit"
desc = "A tan suit with a yellow tie. Smart, but casual."
icon_state = "tan_suit"
item_state = "tan_suit"
item_color = "tan_suit"
-
/obj/item/clothing/under/suit_jacket/white
name = "white suit"
desc = "A white suit and jacket with a blue shirt. You wanna play rough? OKAY!"
icon_state = "white_suit"
item_state = "white_suit"
item_color = "white_suit"
-
/obj/item/clothing/under/burial
name = "burial garments"
desc = "Traditional burial garments from the early 22nd century."
@@ -275,7 +286,6 @@
item_state = "burial"
item_color = "burial"
has_sensor = NO_SENSORS
-
/obj/item/clothing/under/skirt/black
name = "black skirt"
desc = "A black skirt, very fancy!"
@@ -284,7 +294,6 @@
body_parts_covered = CHEST|GROIN|ARMS
fitted = FEMALE_UNIFORM_TOP
can_adjust = FALSE
-
/obj/item/clothing/under/skirt/blue
name = "blue skirt"
desc = "A blue, casual skirt."
@@ -294,7 +303,6 @@
body_parts_covered = CHEST|GROIN|ARMS
fitted = FEMALE_UNIFORM_TOP
can_adjust = FALSE
-
/obj/item/clothing/under/skirt/red
name = "red skirt"
desc = "A red, casual skirt."
@@ -304,7 +312,6 @@
body_parts_covered = CHEST|GROIN|ARMS
fitted = FEMALE_UNIFORM_TOP
can_adjust = FALSE
-
/obj/item/clothing/under/skirt/purple
name = "purple skirt"
desc = "A purple, casual skirt."
@@ -314,8 +321,6 @@
body_parts_covered = CHEST|GROIN|ARMS
fitted = FEMALE_UNIFORM_TOP
can_adjust = FALSE
-
-
/obj/item/clothing/under/schoolgirl
name = "blue schoolgirl uniform"
desc = "It's just like one of my Japanese animes!"
@@ -325,25 +330,21 @@
body_parts_covered = CHEST|GROIN|ARMS
fitted = FEMALE_UNIFORM_TOP
can_adjust = FALSE
-
/obj/item/clothing/under/schoolgirl/red
name = "red schoolgirl uniform"
icon_state = "schoolgirlred"
item_state = "schoolgirlred"
item_color = "schoolgirlred"
-
/obj/item/clothing/under/schoolgirl/green
name = "green schoolgirl uniform"
icon_state = "schoolgirlgreen"
item_state = "schoolgirlgreen"
item_color = "schoolgirlgreen"
-
/obj/item/clothing/under/schoolgirl/orange
name = "orange schoolgirl uniform"
icon_state = "schoolgirlorange"
item_state = "schoolgirlorange"
item_color = "schoolgirlorange"
-
/obj/item/clothing/under/overalls
name = "laborer's overalls"
desc = "A set of durable overalls for getting the job done."
@@ -351,7 +352,6 @@
item_state = "lb_suit"
item_color = "overalls"
can_adjust = FALSE
-
/obj/item/clothing/under/pirate
name = "pirate outfit"
desc = "Yarr."
@@ -359,7 +359,6 @@
item_state = "pirate"
item_color = "pirate"
can_adjust = FALSE
-
/obj/item/clothing/under/soviet
name = "soviet uniform"
desc = "For the Motherland!"
@@ -367,7 +366,6 @@
item_state = "soviet"
item_color = "soviet"
can_adjust = FALSE
-
/obj/item/clothing/under/redcoat
name = "redcoat uniform"
desc = "Looks old."
@@ -375,7 +373,6 @@
item_state = "redcoat"
item_color = "redcoat"
can_adjust = FALSE
-
/obj/item/clothing/under/kilt
name = "kilt"
desc = "Includes shoes and plaid."
@@ -385,7 +382,6 @@
body_parts_covered = CHEST|GROIN|LEGS|FEET
fitted = FEMALE_UNIFORM_TOP
can_adjust = FALSE
-
/obj/item/clothing/under/kilt/highlander
desc = "You're the only one worthy of this kilt."
@@ -402,7 +398,6 @@
body_parts_covered = CHEST|GROIN|LEGS
fitted = FEMALE_UNIFORM_TOP
can_adjust = FALSE
-
/obj/item/clothing/under/gladiator
name = "gladiator uniform"
desc = "Are you not entertained? Is that not why you are here?"
@@ -413,11 +408,9 @@
fitted = NO_FEMALE_UNIFORM
can_adjust = FALSE
resistance_flags = NONE
-
/obj/item/clothing/under/gladiator/ash_walker
desc = "This gladiator uniform appears to be covered in ash and fairly dated."
has_sensor = NO_SENSORS
-
/obj/item/clothing/under/sundress
name = "sundress"
desc = "Makes you want to frolic in a field of daisies."
@@ -427,7 +420,6 @@
body_parts_covered = CHEST|GROIN
fitted = FEMALE_UNIFORM_TOP
can_adjust = FALSE
-
/obj/item/clothing/under/captainparade
name = "captain's parade uniform"
desc = "A captain's luxury-wear, for special occasions."
@@ -435,7 +427,6 @@
item_state = "by_suit"
item_color = "captain_parade"
can_adjust = FALSE
-
/obj/item/clothing/under/hosparademale
name = "head of security's parade uniform"
desc = "A male head of security's luxury-wear, for special occasions."
@@ -443,7 +434,6 @@
item_state = "r_suit"
item_color = "hos_parade_male"
can_adjust = FALSE
-
/obj/item/clothing/under/hosparadefem
name = "head of security's parade uniform"
desc = "A female head of security's luxury-wear, for special occasions."
@@ -452,7 +442,6 @@
item_color = "hos_parade_fem"
fitted = FEMALE_UNIFORM_TOP
can_adjust = FALSE
-
/obj/item/clothing/under/assistantformal
name = "assistant's formal uniform"
desc = "An assistant's formal-wear. Why an assistant needs formal-wear is still unknown."
@@ -460,7 +449,6 @@
item_state = "gy_suit"
item_color = "assistant_formal"
can_adjust = FALSE
-
/obj/item/clothing/under/blacktango
name = "black tango dress"
desc = "Filled with Latin fire."
@@ -469,8 +457,6 @@
item_color = "black_tango"
fitted = FEMALE_UNIFORM_TOP
can_adjust = FALSE
- body_parts_covered = CHEST|GROIN
-
/obj/item/clothing/under/stripeddress
name = "striped dress"
desc = "Fashion in space."
@@ -480,7 +466,6 @@
body_parts_covered = CHEST|GROIN|ARMS
fitted = FEMALE_UNIFORM_FULL
can_adjust = FALSE
-
/obj/item/clothing/under/sailordress
name = "sailor dress"
desc = "Formal wear for a leading lady."
@@ -490,7 +475,6 @@
body_parts_covered = CHEST|GROIN|ARMS
fitted = FEMALE_UNIFORM_TOP
can_adjust = FALSE
-
/obj/item/clothing/under/redeveninggown
name = "red evening gown"
desc = "Fancy dress for space bar singers."
@@ -499,7 +483,6 @@
item_color = "red_evening_gown"
fitted = FEMALE_UNIFORM_TOP
can_adjust = FALSE
-
/obj/item/clothing/under/maid
name = "maid costume"
desc = "Maid in China."
@@ -509,12 +492,10 @@
body_parts_covered = CHEST|GROIN
fitted = FEMALE_UNIFORM_TOP
can_adjust = FALSE
-
/obj/item/clothing/under/maid/Initialize()
. = ..()
var/obj/item/clothing/accessory/maidapron/A = new (src)
attach_accessory(A)
-
/obj/item/clothing/under/janimaid
name = "maid uniform"
desc = "A simple maid uniform for housekeeping."
@@ -524,7 +505,6 @@
body_parts_covered = CHEST|GROIN
fitted = FEMALE_UNIFORM_TOP
can_adjust = FALSE
-
/obj/item/clothing/under/plaid_skirt
name = "red plaid skirt"
desc = "A preppy red skirt with a white blouse."
@@ -534,7 +514,6 @@
fitted = FEMALE_UNIFORM_TOP
can_adjust = TRUE
alt_covers_chest = TRUE
-
/obj/item/clothing/under/plaid_skirt/blue
name = "blue plaid skirt"
desc = "A preppy blue skirt with a white blouse."
@@ -544,7 +523,6 @@
fitted = FEMALE_UNIFORM_TOP
can_adjust = TRUE
alt_covers_chest = TRUE
-
/obj/item/clothing/under/plaid_skirt/purple
name = "purple plaid skirt"
desc = "A preppy purple skirt with a white blouse."
@@ -554,7 +532,6 @@
fitted = FEMALE_UNIFORM_TOP
can_adjust = TRUE
alt_covers_chest = TRUE
-
/obj/item/clothing/under/singery
name = "yellow performer's outfit"
desc = "Just looking at this makes you want to sing."
@@ -565,7 +542,6 @@
fitted = NO_FEMALE_UNIFORM
alternate_worn_layer = ABOVE_SHOES_LAYER
can_adjust = FALSE
-
/obj/item/clothing/under/singerb
name = "blue performer's outfit"
desc = "Just looking at this makes you want to sing."
@@ -576,7 +552,6 @@
alternate_worn_layer = ABOVE_SHOES_LAYER
fitted = FEMALE_UNIFORM_TOP
can_adjust = FALSE
-
/obj/item/clothing/under/plaid_skirt/green
name = "green plaid skirt"
desc = "A preppy green skirt with a white blouse."
@@ -586,17 +561,14 @@
fitted = FEMALE_UNIFORM_TOP
can_adjust = TRUE
alt_covers_chest = TRUE
-
/obj/item/clothing/under/jester
name = "jester suit"
desc = "A jolly dress, well suited to entertain your master, nuncle."
icon_state = "jester"
item_color = "jester"
can_adjust = FALSE
-
/obj/item/clothing/under/jester/alt
icon_state = "jester2"
-
/obj/item/clothing/under/geisha
name = "geisha suit"
desc = "Cute space ninja senpai not included."
@@ -604,14 +576,12 @@
item_color = "geisha"
body_parts_covered = CHEST|GROIN|ARMS
can_adjust = FALSE
-
/obj/item/clothing/under/villain
name = "villain suit"
desc = "A change of wardrobe is necessary if you ever want to catch a real superhero."
icon_state = "villain"
item_color = "villain"
can_adjust = FALSE
-
/obj/item/clothing/under/sailor
name = "sailor suit"
desc = "Skipper's in the wardroom drinkin gin'."
@@ -619,7 +589,6 @@
item_state = "b_suit"
item_color = "sailor"
can_adjust = FALSE
-
/obj/item/clothing/under/plasmaman
name = "plasma envirosuit"
desc = "A special containment suit that allows plasma-based lifeforms to exist safely in an oxygenated environment, and automatically extinguishes them in a crisis. Despite being airtight, it's not spaceworthy."
@@ -633,17 +602,12 @@
var/next_extinguish = 0
var/extinguish_cooldown = 100
var/extinguishes_left = 5
-
-
/obj/item/clothing/under/plasmaman/examine(mob/user)
..()
to_chat(user, "There are [extinguishes_left] extinguisher charges left in this suit.")
-
-
/obj/item/clothing/under/plasmaman/proc/Extinguish(mob/living/carbon/human/H)
if(!istype(H))
return
-
if(H.on_fire)
if(extinguishes_left)
if(next_extinguish > world.time)
@@ -654,7 +618,6 @@
H.ExtinguishMob()
new /obj/effect/particle_effect/water(get_turf(H))
return 0
-
/obj/item/clothing/under/plasmaman/attackby(obj/item/E, mob/user, params)
..()
if (istype(E, /obj/item/extinguisher_refill))
@@ -668,20 +631,17 @@
return
return
return
-
/obj/item/extinguisher_refill
name = "envirosuit extinguisher cartridge"
desc = "A cartridge loaded with a compressed extinguisher mix, used to refill the automatic extinguisher on plasma envirosuits."
icon_state = "plasmarefill"
icon = 'icons/obj/device.dmi'
-
/obj/item/clothing/under/rank/security/navyblue/russian
name = "\improper Russian officer's uniform"
desc = "The latest in fashionable russian outfits."
icon_state = "hostanclothes"
item_state = "hostanclothes"
item_color = "hostanclothes"
-
/obj/item/clothing/under/mummy
name = "mummy wrapping"
desc = "Return the slab or suffer my stale references."
@@ -692,7 +652,6 @@
fitted = NO_FEMALE_UNIFORM
can_adjust = FALSE
resistance_flags = NONE
-
/obj/item/clothing/under/scarecrow
name = "scarecrow clothes"
desc = "Perfect camouflage for hiding in botany."
@@ -703,7 +662,6 @@
fitted = NO_FEMALE_UNIFORM
can_adjust = FALSE
resistance_flags = NONE
-
/obj/item/clothing/under/draculass
name = "draculass coat"
desc = "A dress inspired by the ancient \"Victorian\" era."
@@ -713,8 +671,6 @@
body_parts_covered = CHEST|GROIN|ARMS
fitted = FEMALE_UNIFORM_TOP
can_adjust = FALSE
- mutantrace_variation = NO_MUTANTRACE_VARIATION
-
/obj/item/clothing/under/drfreeze
name = "doctor freeze's jumpsuit"
desc = "A modified scientist jumpsuit to look extra cool."
@@ -722,8 +678,6 @@
item_state = "drfreeze"
item_color = "drfreeze"
can_adjust = FALSE
- mutantrace_variation = NO_MUTANTRACE_VARIATION
-
/obj/item/clothing/under/lobster
name = "foam lobster suit"
desc = "Who beheaded the college mascot?"
@@ -732,8 +686,6 @@
item_color = "lobster"
fitted = NO_FEMALE_UNIFORM
can_adjust = FALSE
- mutantrace_variation = NO_MUTANTRACE_VARIATION
-
/obj/item/clothing/under/gondola
name = "gondola hide suit"
desc = "Now you're cooking."
@@ -741,7 +693,6 @@
item_state = "lb_suit"
item_color = "gondola"
can_adjust = FALSE
-
/obj/item/clothing/under/skeleton
name = "skeleton jumpsuit"
desc = "A black jumpsuit with a white bone pattern printed on it. Spooky!"
@@ -752,10 +703,27 @@
fitted = NO_FEMALE_UNIFORM
can_adjust = FALSE
resistance_flags = NONE
+/obj/item/clothing/under/durathread
+ name = "durathread jumpsuit"
+ desc = "A jumpsuit made from durathread, its resilient fibres provide some protection to the wearer."
+ icon_state = "durathread"
+ item_state = "durathread"
+ item_color = "durathread"
+ can_adjust = FALSE
+ armor = list("melee" = 10, "laser" = 10, "fire" = 40, "acid" = 10, "bomb" = 5)
/obj/item/clothing/under/gear_harness
name = "gear harness"
desc = "A simple, inconspicuous harness replacement for a jumpsuit."
icon_state = "gear_harness"
item_state = "gear_harness" //We dont use golem do to being a item, item without faces making it default to error suit sprites.
- body_parts_covered = CHEST|GROIN
\ No newline at end of file
+ body_parts_covered = CHEST|GROIN
+
+/obj/item/clothing/under/durathread
+ name = "durathread jumpsuit"
+ desc = "A jumpsuit made from durathread, its resilient fibres provide some protection to the wearer."
+ icon_state = "durathread"
+ item_state = "durathread"
+ item_color = "durathread"
+ can_adjust = FALSE
+ armor = list("melee" = 10, "laser" = 10, "fire" = 40, "acid" = 10, "bomb" = 5)
\ No newline at end of file
diff --git a/code/modules/clothing/under/syndicate.dm b/code/modules/clothing/under/syndicate.dm
index 83cab9d992..9893edf248 100644
--- a/code/modules/clothing/under/syndicate.dm
+++ b/code/modules/clothing/under/syndicate.dm
@@ -8,6 +8,17 @@
armor = list("melee" = 10, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 40)
alt_covers_chest = TRUE
+/obj/item/clothing/under/syndicate/skirt
+ name = "tactical skirtleneck"
+ desc = "A non-descript and slightly suspicious looking skirtleneck."
+ icon_state = "syndicate_skirt"
+ item_state = "bl_suit"
+ item_color = "syndicate_skirt"
+ has_sensor = NO_SENSORS
+ armor = list("melee" = 10, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 40)
+ alt_covers_chest = TRUE
+ fitted = FEMALE_UNIFORM_TOP
+
/obj/item/clothing/under/syndicate/tacticool
name = "tacticool turtleneck"
desc = "Just looking at it makes you want to buy an SKS, go into the woods, and -operate-."
@@ -16,6 +27,15 @@
item_color = "tactifool"
armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 40)
+/obj/item/clothing/under/syndicate/tacticool/skirt
+ name = "tacticool skirtleneck"
+ desc = "Just looking at it makes you want to buy an SKS, go into the woods, and -operate-."
+ icon_state = "tactifool_skirt"
+ item_state = "bl_suit"
+ item_color = "tactifool_skirt"
+ armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 40)
+ fitted = FEMALE_UNIFORM_TOP
+
/obj/item/clothing/under/syndicate/sniper
name = "Tactical turtleneck suit"
desc = "A double seamed tactical turtleneck disguised as a civilian grade silk suit. Intended for the most formal operator. The collar is really sharp."
diff --git a/code/modules/crafting/craft.dm b/code/modules/crafting/craft.dm
index 3e96512bb8..0fb46c3e46 100644
--- a/code/modules/crafting/craft.dm
+++ b/code/modules/crafting/craft.dm
@@ -317,6 +317,8 @@
var/list/cant_craft = list()
for(var/rec in GLOB.crafting_recipes)
var/datum/crafting_recipe/R = rec
+ if(!R.always_availible && !(R.type in user?.mind?.learned_recipes)) //User doesn't actually know how to make this.
+ continue
if((R.category != cur_category) || (R.subcategory != cur_subcategory))
continue
if(check_contents(R, surroundings))
@@ -431,3 +433,10 @@
data["tool_text"] = tool_text
return data
+
+//Mind helpers
+
+/datum/mind/proc/teach_crafting_recipe(R)
+ if(!learned_recipes)
+ learned_recipes = list()
+ learned_recipes |= R
\ No newline at end of file
diff --git a/code/modules/crafting/recipes.dm b/code/modules/crafting/recipes.dm
index ca51fec347..2790a8cec7 100644
--- a/code/modules/crafting/recipes.dm
+++ b/code/modules/crafting/recipes.dm
@@ -9,6 +9,7 @@
var/chem_catalysts[] = list() //like tools but for reagents
var/category = CAT_NONE //where it shows up in the crafting UI
var/subcategory = CAT_NONE
+ var/always_availible = TRUE //Set to FALSE if it needs to be learned first.
/datum/crafting_recipe/pin_removal
name = "Pin Removal"
@@ -68,7 +69,7 @@
/datum/crafting_recipe/molotov
name = "Molotov"
result = /obj/item/reagent_containers/food/drinks/bottle/molotov
- reqs = list(/obj/item/reagent_containers/glass/rag = 1,
+ reqs = list(/obj/item/reagent_containers/rag = 1,
/obj/item/reagent_containers/food/drinks/bottle = 1)
parts = list(/obj/item/reagent_containers/food/drinks/bottle = 1)
time = 40
@@ -210,6 +211,12 @@
time = 40
category = CAT_ROBOT
+/datum/crafting_recipe/potatos
+ name = "Potat-OS"
+ reqs = list(/obj/item/stack/cable_coil = 1, /obj/item/stack/rods = 1, /obj/item/reagent_containers/food/snacks/grown/potato = 1, /obj/item/aicard = 1 )
+ result = /obj/item/aicard/potato
+ category = CAT_ROBOT
+
/datum/crafting_recipe/improvised_pneumatic_cannon //Pretty easy to obtain but
name = "Pneumatic Cannon"
result = /obj/item/pneumatic_cannon/ghetto
@@ -454,6 +461,12 @@
/obj/item/bikehorn = 1)
category = CAT_MISC
+/datum/crafting_recipe/toyneb
+ name = "Non-Euplastic Blade"
+ reqs = list(/obj/item/light/tube = 1, /obj/item/stack/cable_coil = 1, /obj/item/stack/sheet/plastic = 4)
+ result = /obj/item/toy/sword/cx
+ category = CAT_MISC
+
/datum/crafting_recipe/chemical_payload
name = "Chemical Payload (C4)"
result = /obj/item/bombcore/chemical
@@ -659,6 +672,15 @@
tools = list(TOOL_SCREWDRIVER, TOOL_WRENCH, TOOL_WELDER)
category = CAT_MISC
+/datum/crafting_recipe/femur_breaker
+ name = "Femur Breaker"
+ result = /obj/structure/femur_breaker
+ time = 150
+ reqs = list(/obj/item/stack/sheet/metal = 20,
+ /obj/item/stack/cable_coil = 30)
+ tools = list(TOOL_SCREWDRIVER, TOOL_WRENCH, TOOL_WELDER)
+ category = CAT_MISC
+
/datum/crafting_recipe/lizardhat
name = "Lizard Cloche Hat"
result = /obj/item/clothing/head/lizard
@@ -873,3 +895,44 @@
time = 150 //It's a gun
category = CAT_WEAPONRY
subcategory = CAT_WEAPON
+
+/datum/crafting_recipe/durathread_duffelbag
+ name = "Durathread Dufflebag"
+ result = /obj/item/storage/backpack/duffelbag/durathread
+ reqs = list(/obj/item/stack/sheet/durathread = 7,
+ /obj/item/stack/sheet/leather = 3)
+ time = 70
+ category = CAT_CLOTHING
+
+/datum/crafting_recipe/durathread_toolbelt
+ name = "Durathread Toolbelt"
+ result = /obj/item/storage/belt/durathread
+ reqs = list(/obj/item/stack/sheet/durathread = 5,
+ /obj/item/stack/sheet/leather = 1)
+ time = 30
+ category = CAT_CLOTHING
+
+/datum/crafting_recipe/durathread_bandolier
+ name = "Durathread Bandolier"
+ result = /obj/item/storage/belt/bandolier/durathread
+ reqs = list(/obj/item/stack/sheet/durathread = 6,
+ /obj/item/stack/sheet/leather = 2)
+ time = 50
+ category = CAT_CLOTHING
+
+ /datum/crafting_recipe/durathread_helmet
+ name = "Makeshift Durathread Helmet"
+ result = /obj/item/clothing/head/helmet/durathread
+ reqs = list(/obj/item/stack/sheet/durathread = 4,
+ /obj/item/stack/sheet/leather = 2)
+ time = 30
+ category = CAT_CLOTHING
+
+/datum/crafting_recipe/durathread_vest
+ name = "Makeshift Durathread Armour"
+ result = /obj/item/clothing/suit/armor/vest/durathread
+ reqs = list(/obj/item/stack/sheet/durathread = 6,
+ /obj/item/stack/sheet/leather = 3)
+ time = 50
+ category = CAT_CLOTHING
+
diff --git a/code/modules/detectivework/footprints_and_rag.dm b/code/modules/detectivework/footprints_and_rag.dm
deleted file mode 100644
index a25bc01b13..0000000000
--- a/code/modules/detectivework/footprints_and_rag.dm
+++ /dev/null
@@ -1,50 +0,0 @@
-
-/mob
- var/bloody_hands = 0
-
-/obj/item/clothing/gloves
- var/transfer_blood = 0
-
-
-/obj/item/reagent_containers/glass/rag
- name = "damp rag"
- desc = "For cleaning up messes, you suppose."
- w_class = WEIGHT_CLASS_TINY
- icon = 'icons/obj/toy.dmi'
- icon_state = "rag"
- item_flags = NOBLUDGEON
- reagent_flags = OPENCONTAINER
- amount_per_transfer_from_this = 5
- possible_transfer_amounts = list()
- volume = 5
- spillable = FALSE
-
-/obj/item/reagent_containers/glass/rag/suicide_act(mob/user)
- user.visible_message("[user] is smothering [user.p_them()]self with [src]! It looks like [user.p_theyre()] trying to commit suicide!")
- return (OXYLOSS)
-
-/obj/item/reagent_containers/glass/rag/afterattack(atom/A as obj|turf|area, mob/user,proximity)
- . = ..()
- if(!proximity)
- return
- if(iscarbon(A) && A.reagents && reagents.total_volume)
- var/mob/living/carbon/C = A
- var/reagentlist = pretty_string_from_reagent_list(reagents)
- var/log_object = "a damp rag containing [reagentlist]"
- if(user.a_intent == INTENT_HARM && !C.is_mouth_covered())
- reagents.reaction(C, INGEST)
- reagents.trans_to(C, reagents.total_volume)
- C.visible_message("[user] has smothered \the [C] with \the [src]!", "[user] has smothered you with \the [src]!", "You hear some struggling and muffled cries of surprise.")
- log_combat(user, C, "smothered", log_object)
- else
- reagents.reaction(C, TOUCH)
- reagents.clear_reagents()
- C.visible_message("[user] has touched \the [C] with \the [src].")
- log_combat(user, C, "touched", log_object)
-
- else if(istype(A) && src in user)
- user.visible_message("[user] starts to wipe down [A] with [src]!", "You start to wipe down [A] with [src]...")
- if(do_after(user,30, target = A))
- user.visible_message("[user] finishes wiping off [A]!", "You finish wiping off [A].")
- SEND_SIGNAL(A, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_MEDIUM)
- return
diff --git a/code/modules/events/holiday/vday.dm b/code/modules/events/holiday/vday.dm
index a4e8b276b5..8f77af58eb 100644
--- a/code/modules/events/holiday/vday.dm
+++ b/code/modules/events/holiday/vday.dm
@@ -41,11 +41,16 @@
else
L.mind.add_antag_datum(/datum/antagonist/heartbreaker)
-/proc/forge_valentines_objective(mob/living/lover,mob/living/date)
+/proc/forge_valentines_objective(mob/living/lover,mob/living/date,var/chemLove = FALSE)
lover.mind.special_role = "valentine"
- var/datum/antagonist/valentine/V = new
- V.date = date.mind
- lover.mind.add_antag_datum(V) //These really should be teams but i can't be assed to incorporate third wheels right now
+ if (chemLove == TRUE)
+ var/datum/antagonist/valentine/chem/V = new //Changes text and EOG check basically.
+ V.date = date.mind
+ lover.mind.add_antag_datum(V)
+ else
+ var/datum/antagonist/valentine/V = new
+ V.date = date.mind
+ lover.mind.add_antag_datum(V) //These really should be teams but i can't be assed to incorporate third wheels right now
/datum/round_event/valentines/announce(fake)
priority_announce("It's Valentine's Day! Give a valentine to that special someone!")
diff --git a/code/modules/events/meteor_wave.dm b/code/modules/events/meteor_wave.dm
index 798bcf82dd..af22ae3b96 100644
--- a/code/modules/events/meteor_wave.dm
+++ b/code/modules/events/meteor_wave.dm
@@ -15,6 +15,12 @@
var/list/wave_type
var/wave_name = "normal"
+/datum/round_event/meteor_wave/setup()
+ announceWhen = 1
+ startWhen = rand(300, 600) //Yeah for SOME REASON this is measured in seconds and not deciseconds???
+ endWhen = startWhen + 60
+
+
/datum/round_event/meteor_wave/New()
..()
if(!wave_type)
@@ -46,7 +52,7 @@
kill()
/datum/round_event/meteor_wave/announce(fake)
- priority_announce("Meteors have been detected on collision course with the station.", "Meteor Alert", 'sound/ai/meteors.ogg')
+ priority_announce("Meteors have been detected on collision course with the station. Estimated time until impact: [round(startWhen/60)] minutes.", "Meteor Alert", 'sound/ai/meteors.ogg')
/datum/round_event/meteor_wave/tick()
if(ISMULTIPLE(activeFor, 3))
diff --git a/code/modules/events/wizard/shuffle.dm b/code/modules/events/wizard/shuffle.dm
index ec253f13c3..7e37429223 100644
--- a/code/modules/events/wizard/shuffle.dm
+++ b/code/modules/events/wizard/shuffle.dm
@@ -27,7 +27,7 @@
for(var/mob/living/carbon/human/H in mobs)
if(!moblocs)
break //locs aren't always unique, so this may come into play
- do_teleport(H, moblocs[moblocs.len])
+ do_teleport(H, moblocs[moblocs.len], channel = TELEPORT_CHANNEL_MAGIC)
moblocs.len -= 1
for(var/mob/living/carbon/human/H in GLOB.alive_mob_list)
diff --git a/code/modules/events/wormholes.dm b/code/modules/events/wormholes.dm
index 412e54878a..bb601b7c82 100644
--- a/code/modules/events/wormholes.dm
+++ b/code/modules/events/wormholes.dm
@@ -63,4 +63,4 @@
hard_target = P.loc
if(!hard_target)
return
- do_teleport(M, hard_target, 1, 1, 0, 0) ///You will appear adjacent to the beacon
+ do_teleport(M, hard_target, 1, 1, 0, 0, channel = TELEPORT_CHANNEL_WORMHOLE) ///You will appear adjacent to the beacon
diff --git a/code/modules/food_and_drinks/drinks/drinks/bottle.dm b/code/modules/food_and_drinks/drinks/drinks/bottle.dm
index f85668d2b8..e72b624ae5 100644
--- a/code/modules/food_and_drinks/drinks/drinks/bottle.dm
+++ b/code/modules/food_and_drinks/drinks/drinks/bottle.dm
@@ -7,11 +7,12 @@
/obj/item/reagent_containers/food/drinks/bottle
amount_per_transfer_from_this = 10
volume = 100
+ force = 15
throwforce = 15
item_state = "broken_beer" //Generic held-item sprite until unique ones are made.
lefthand_file = 'icons/mob/inhands/misc/food_lefthand.dmi'
righthand_file = 'icons/mob/inhands/misc/food_righthand.dmi'
- var/const/duration = 13 //Directly relates to the 'knockdown' duration. Lowered by armor (i.e. helmets)
+ var/knockdown_duration = 13 //Directly relates to the 'knockdown' duration. Lowered by armor (i.e. helmets)
isGlass = TRUE
foodtype = ALCOHOL
@@ -61,46 +62,30 @@
to_chat(user, "You don't want to harm [target]!")
return
- force = 15 //Smashing bottles over someoen's head hurts.
-
var/obj/item/bodypart/affecting = user.zone_selected //Find what the player is aiming at
- var/armor_block = 0 //Get the target's armor values for normal attack damage.
- var/armor_duration = 0 //The more force the bottle has, the longer the duration.
+ var/headarmor = 0 // Target's head armor
+ var/armor_block = min(90, target.run_armor_check(affecting, "melee", null, null,armour_penetration)) // For normal attack damage
- //Calculating duration and calculating damage.
- if(ishuman(target))
+ //If they have a hat/helmet and the user is targeting their head.
+ if(affecting == BODY_ZONE_HEAD)
+ var/obj/item/I = target.get_item_by_slot(SLOT_HEAD)
+ if(I)
+ headarmor = I.armor.melee
- var/mob/living/carbon/human/H = target
- var/headarmor = 0 // Target's head armor
- armor_block = H.run_armor_check(affecting, "melee", null, null,armour_penetration) // For normal attack damage
-
- //If they have a hat/helmet and the user is targeting their head.
- if(istype(H.head, /obj/item/clothing/head) && affecting == BODY_ZONE_HEAD)
- headarmor = H.head.armor.melee
- else
- headarmor = 0
-
- //Calculate the knockdown duration for the target.
- armor_duration = (duration - headarmor) + force
-
- else
- //Only humans can have armor, right?
- armor_block = target.run_armor_check(affecting, "melee")
- if(affecting == BODY_ZONE_HEAD)
- armor_duration = duration + force
+ //Calculate the knockdown duration for the target.
+ var/armor_duration = (knockdown_duration - headarmor) + force
//Apply the damage!
- armor_block = min(90,armor_block)
target.apply_damage(force, BRUTE, affecting, armor_block)
// You are going to knock someone out for longer if they are not wearing a helmet.
var/head_attack_message = ""
- if(affecting == BODY_ZONE_HEAD && istype(target, /mob/living/carbon/))
+ if(affecting == BODY_ZONE_HEAD && iscarbon(target))
head_attack_message = " on the head"
//Knockdown the target for the duration that we calculated and divide it by 5.
if(armor_duration)
- target.apply_effect(min(armor_duration, 200) , EFFECT_KNOCKDOWN) // Never knockdown more than a flash!
+ target.Knockdown(min(armor_duration, 200)) // Never knockdown more than a flash!
//Display an attack message.
if(target != user)
@@ -202,17 +187,18 @@
desc = "A flask of holy water...it's been sitting in the Necropolis a while though."
list_reagents = list("hell_water" = 100)
-/obj/item/reagent_containers/food/drinks/holyoil
+/obj/item/reagent_containers/food/drinks/bottle/holyoil
name = "flask of zelus oil"
- desc = "A brass flask of Zelus oil, a viscous fluid with a scenting of brass - this flask may be sipped or thrown."
+ desc = "A brass flask of Zelus oil, a viscous fluid scenting of brass. Can be thrown to deal damage from afar."
icon_state = "zelusflask"
- list_reagents = list("holyoil" = 30) //Powerfull
+ list_reagents = list("holyoil" = 30)
volume = 30
foodtype = NONE
- force = 12 //Same as a toolbox
+ force = 18
throwforce = 18
+ knockdown_duration = 18
-/obj/item/reagent_containers/food/drinks/holyoil/null
+/obj/item/reagent_containers/food/drinks/bottle/holyoil/empty
list_reagents = list("holyoil" = 0)
/obj/item/reagent_containers/food/drinks/bottle/vermouth
diff --git a/code/modules/food_and_drinks/food/snacks_cake.dm b/code/modules/food_and_drinks/food/snacks_cake.dm
index 1eeea79410..d66cfdd667 100644
--- a/code/modules/food_and_drinks/food/snacks_cake.dm
+++ b/code/modules/food_and_drinks/food/snacks_cake.dm
@@ -17,21 +17,21 @@
foodtype = GRAIN | DAIRY
/obj/item/reagent_containers/food/snacks/store/cake/plain
- name = "vanilla cake"
+ name = "plain cake"
desc = "A plain cake, not a lie."
icon_state = "plaincake"
custom_food_type = /obj/item/reagent_containers/food/snacks/customizable/cake
bonus_reagents = list("nutriment" = 10, "vitamin" = 2)
- tastes = list("vanilla" = 1, "sweetness" = 2,"cake" = 5)
+ tastes = list("sweetness" = 2,"cake" = 5)
foodtype = GRAIN | DAIRY | SUGAR
/obj/item/reagent_containers/food/snacks/cakeslice/plain
- name = "vanilla cake slice"
+ name = "plain cake slice"
desc = "Just a slice of cake, it is enough for everyone."
icon_state = "plaincake_slice"
filling_color = "#FFD700"
customfoodfilling = 1
- tastes = list("vanilla" = 1, "sweetness" = 2,"cake" = 5)
+ tastes = list("sweetness" = 2,"cake" = 5)
foodtype = GRAIN | DAIRY | SUGAR
/obj/item/reagent_containers/food/snacks/store/cake/carrot
@@ -147,7 +147,6 @@
tastes = list("cake" = 5, "sweetness" = 2, "sourness" = 2)
foodtype = GRAIN | DAIRY | FRUIT | SUGAR
-
/obj/item/reagent_containers/food/snacks/store/cake/chocolate
name = "chocolate cake"
desc = "A cake with added chocolate."
@@ -186,7 +185,6 @@
tastes = list("cake" = 5, "sweetness" = 1)
foodtype = GRAIN | DAIRY | JUNKFOOD | SUGAR
-
/obj/item/reagent_containers/food/snacks/store/cake/apple
name = "apple cake"
desc = "A cake centred with Apple."
@@ -248,7 +246,6 @@
/obj/item/reagent_containers/food/snacks/store/cake/bsvc // blackberry strawberries vanilla cake
name = "blackberry and strawberry vanilla cake"
desc = "A plain cake, filled with assortment of blackberries and strawberries!"
- icon = 'modular_citadel/icons/obj/food/cake.dmi'
icon_state = "blackbarry_strawberries_cake_vanilla_cake"
slice_path = /obj/item/reagent_containers/food/snacks/cakeslice/bsvc
bonus_reagents = list("nutriment" = 14, "vitamin" = 4)
@@ -258,7 +255,6 @@
/obj/item/reagent_containers/food/snacks/cakeslice/bsvc
name = "blackberry and strawberry vanilla cake slice"
desc = "Just a slice of cake filled with assortment of blackberries and strawberries!"
- icon = 'modular_citadel/icons/obj/food/cake.dmi'
icon_state = "blackbarry_strawberries_cake_vanilla_slice"
filling_color = "#FFD700"
tastes = list("blackbarry" = 2, "strawberries" = 2, "vanilla" = 2, "sweetness" = 2,"cake" = 3)
@@ -267,7 +263,6 @@
/obj/item/reagent_containers/food/snacks/store/cake/bscc // blackbarry strawberries chocolate cake
name = "blackberry and strawberry chocolate cake"
desc = "A plain cake, filled with assortment of blackberries and strawberries!"
- icon = 'modular_citadel/icons/obj/food/cake.dmi'
icon_state = "blackbarry_strawberries_cake_coco_cake"
slice_path = /obj/item/reagent_containers/food/snacks/cakeslice/bscc
bonus_reagents = list("nutriment" = 14, "vitamin" = 4, "cocoa" = 5)
@@ -277,16 +272,14 @@
/obj/item/reagent_containers/food/snacks/cakeslice/bscc
name = "blackberry and strawberry chocolate cake slice"
desc = "Just a slice of cake filled with assortment of blackberries and strawberries!"
- icon = 'modular_citadel/icons/obj/food/cake.dmi'
icon_state = "blackbarry_strawberries_cake_coco_cake_slice"
filling_color = "#FFD700"
tastes = list("blackberry" = 2, "strawberries" = 2, "chocolate" = 2, "sweetness" = 2,"cake" = 3)
foodtype = GRAIN | DAIRY | FRUIT | SUGAR
-obj/item/reagent_containers/food/snacks/store/cake/holy_cake
+/obj/item/reagent_containers/food/snacks/store/cake/holy_cake
name = "angel food cake"
desc = "A cake made for angels and chaplains alike! Contains holy water."
- icon = 'modular_citadel/icons/obj/food/cake.dmi'
icon_state = "holy_cake"
slice_path = /obj/item/reagent_containers/food/snacks/cakeslice/holy_cake_slice
bonus_reagents = list("nutriment" = 1, "vitamin" = 3, "holy_water" = 10)
@@ -296,7 +289,6 @@ obj/item/reagent_containers/food/snacks/store/cake/holy_cake
/obj/item/reagent_containers/food/snacks/cakeslice/holy_cake_slice
name = "angel food cake slice"
desc = "A slice of heavenly cake."
- icon = 'modular_citadel/icons/obj/food/cake.dmi'
icon_state = "holy_cake_slice"
filling_color = "#00FFFF"
tastes = list("cake" = 5, "sweetness" = 1, "clouds" = 1)
@@ -305,7 +297,6 @@ obj/item/reagent_containers/food/snacks/store/cake/holy_cake
obj/item/reagent_containers/food/snacks/store/cake/pound_cake
name = "pound cake"
desc = "A condensed cake made for filling people up quickly."
- icon = 'modular_citadel/icons/obj/food/cake.dmi'
icon_state = "pound_cake"
slices_num = 7 //Its ment to feed the party
slice_path = /obj/item/reagent_containers/food/snacks/cakeslice/pound_cake_slice
@@ -316,16 +307,14 @@ obj/item/reagent_containers/food/snacks/store/cake/pound_cake
/obj/item/reagent_containers/food/snacks/cakeslice/pound_cake_slice
name = "pound cake slice"
desc = "A slice of condensed cake made for filling people up quickly."
- icon = 'modular_citadel/icons/obj/food/cake.dmi'
icon_state = "pound_cake_slice"
filling_color = "#00FFFF"
tastes = list("cake" = 5, "sweetness" = 5, "batter" = 1)
foodtype = GRAIN | DAIRY | SUGAR | JUNKFOOD
-obj/item/reagent_containers/food/snacks/store/cake/hardware_cake
+/obj/item/reagent_containers/food/snacks/store/cake/hardware_cake
name = "hardware cake"
desc = "A cake that is made with electronic boards and leaks acid..."
- icon = 'modular_citadel/icons/obj/food/cake.dmi'
icon_state = "hardware_cake"
slice_path = /obj/item/reagent_containers/food/snacks/cakeslice/hardware_cake_slice
bonus_reagents = list("sacid" = 15, "oil" = 15)
@@ -335,8 +324,41 @@ obj/item/reagent_containers/food/snacks/store/cake/hardware_cake
/obj/item/reagent_containers/food/snacks/cakeslice/hardware_cake_slice
name = "hardware cake slice"
desc = "A slice of electronic boards and some acid."
- icon = 'modular_citadel/icons/obj/food/cake.dmi'
icon_state = "hardware_cake_slice"
filling_color = "#00FFFF"
tastes = list("acid" = 1, "metal" = 1, "regret" = 10)
foodtype = GRAIN | GROSS
+
+/obj/item/reagent_containers/food/snacks/store/cake/vanilla_cake
+ name = "vanilla cake"
+ desc = "A vanilla frosted cake."
+ icon_state = "vanillacake"
+ slice_path = /obj/item/reagent_containers/food/snacks/cakeslice/vanilla_slice
+ bonus_reagents = list("sugar" = 15, "vanilla" = 15)
+ tastes = list("caje" = 1, "sugar" = 1, "vanilla" = 10)
+ foodtype = GRAIN | SUGAR | DAIRY
+
+/obj/item/reagent_containers/food/snacks/cakeslice/vanilla_slice
+ name = "vanilla cake slice"
+ desc = "A slice of vanilla frosted cake."
+ icon_state = "vanillacake_slice"
+ filling_color = "#00FFFF"
+ tastes = list("cake" = 1, "sugar" = 1, "vanilla" = 10)
+ foodtype = GRAIN | SUGAR | DAIRY
+
+/obj/item/reagent_containers/food/snacks/store/cake/clown_cake
+ name = "clown cake"
+ desc = "A funny cake with a clown face on it."
+ icon_state = "clowncake"
+ slice_path = /obj/item/reagent_containers/food/snacks/cakeslice/clown_slice
+ bonus_reagents = list("sugar" = 15, "laugher" = 15)
+ tastes = list("cake" = 1, "sugar" = 1, "joy" = 10)
+ foodtype = GRAIN | SUGAR | DAIRY
+
+/obj/item/reagent_containers/food/snacks/cakeslice/clown_slice
+ name = "clown cake slice"
+ desc = "A slice of bad jokes, and silly props."
+ icon_state = "clowncake_slice"
+ filling_color = "#00FFFF"
+ tastes = list("cake" = 1, "sugar" = 1, "joy" = 10)
+ foodtype = GRAIN | SUGAR | DAIRY
\ No newline at end of file
diff --git a/code/modules/food_and_drinks/food/snacks_frozen.dm b/code/modules/food_and_drinks/food/snacks_frozen.dm
index febfa527ca..c4f8ccf76b 100644
--- a/code/modules/food_and_drinks/food/snacks_frozen.dm
+++ b/code/modules/food_and_drinks/food/snacks_frozen.dm
@@ -88,7 +88,7 @@
/obj/item/reagent_containers/food/snacks/snowcones/orange
name = "orange flavored snowcone"
- desc = "A mix of different flavors dizzled on a snowball in a paper cup."
+ desc = "A orange flavor dizzled on a snowball in a paper cup."
icon_state = "orange_sc"
list_reagents = list("nutriment" = 1, "orangejuice" = 10)
tastes = list("ice" = 1, "water" = 1, "berries" = 5)
@@ -130,7 +130,7 @@
name = "mixed fruit flavored snowcone"
desc = "A mix of different flavors dizzled on a snowball in a paper cup."
icon_state = "fruitsalad_sc"
- list_reagents = list("nutriment" = 1, "lemonjuice" = 5, "limejuice" = 5, "lemonjuice" = 5, "orangejuice" = 5)
+ list_reagents = list("nutriment" = 1, "limejuice" = 5, "lemonjuice" = 5, "orangejuice" = 5)
tastes = list("ice" = 1, "water" = 1, "fruits" = 25)
foodtype = FRUIT
diff --git a/code/modules/food_and_drinks/food/snacks_other.dm b/code/modules/food_and_drinks/food/snacks_other.dm
index e36efe750b..c4b9451c7f 100644
--- a/code/modules/food_and_drinks/food/snacks_other.dm
+++ b/code/modules/food_and_drinks/food/snacks_other.dm
@@ -573,4 +573,14 @@
name = "Maintenance Peaches"
desc = "I have a mouth and I must eat."
icon_state = "peachcanmaint"
- tastes = list("peaches" = 1, "tin" = 7)
\ No newline at end of file
+ tastes = list("peaches" = 1, "tin" = 7)
+
+/obj/item/reagent_containers/food/snacks/chocolatestrawberry
+ name = "Chocolate dipped strawberries"
+ desc = "A strawberry dipped in a bit of chocolate."
+ icon_state = "chocolatestrawberry"
+ list_reagents = list("sugar" = 5, "nutriment" = 2)
+ filling_color = "#ffdf26"
+ w_class = WEIGHT_CLASS_NORMAL
+ tastes = list("strawberries" = 5, "chocolate" = 3)
+ foodtype = FRUIT | SUGAR
\ No newline at end of file
diff --git a/code/modules/food_and_drinks/food/snacks_pastry.dm b/code/modules/food_and_drinks/food/snacks_pastry.dm
index 238bb4f86a..9b87002738 100644
--- a/code/modules/food_and_drinks/food/snacks_pastry.dm
+++ b/code/modules/food_and_drinks/food/snacks_pastry.dm
@@ -308,7 +308,6 @@
tastes = list("bread" = 1, "egg" = 1, "cheese" = 1)
foodtype = GRAIN | MEAT | DAIRY
-
/obj/item/reagent_containers/food/snacks/sugarcookie
name = "sugar cookie"
desc = "Just like your little sister used to make."
@@ -369,6 +368,16 @@
tastes = list("cake" = 3, "blue cherry" = 1)
foodtype = GRAIN | FRUIT | SUGAR
+/obj/item/reagent_containers/food/snacks/strawberrycupcake
+ name = "Strawberry cupcake"
+ desc = "Strawberry inside a delicious cupcake."
+ icon_state = "strawberrycupcake"
+ bonus_reagents = list("nutriment" = 1, "vitamin" = 3)
+ list_reagents = list("nutriment" = 5, "vitamin" = 1)
+ filling_color = "#F0E68C"
+ tastes = list("cake" = 2, "strawberry" = 1)
+ foodtype = GRAIN | FRUIT | SUGAR
+
/obj/item/reagent_containers/food/snacks/honeybun
name = "honey bun"
desc = "A sticky pastry bun glazed with honey."
diff --git a/code/modules/food_and_drinks/food/snacks_pie.dm b/code/modules/food_and_drinks/food/snacks_pie.dm
index 0b12ee4fcf..be6c11fd68 100644
--- a/code/modules/food_and_drinks/food/snacks_pie.dm
+++ b/code/modules/food_and_drinks/food/snacks_pie.dm
@@ -171,8 +171,6 @@
tastes = list("pie" = 1, "apple" = 1)
foodtype = GRAIN | FRUIT | SUGAR
-
-
/obj/item/reagent_containers/food/snacks/pie/cherrypie
name = "cherry pie"
desc = "Taste so good, make a grown man cry."
@@ -221,6 +219,33 @@
tastes = list("pie" = 1, "grape" = 1)
foodtype = GRAIN | FRUIT | SUGAR
+/obj/item/reagent_containers/food/snacks/pie/mimetart
+ name = "mime tart"
+ desc = "..."
+ icon_state = "mimetart"
+ bonus_reagents = list("nutriment" = 1, "vitamin" = 4, "nothing" = 10)
+ list_reagents = list("nutriment" = 5, "vitamin" = 5)
+ tastes = list("pie" = 1, "nothing" = 1)
+ foodtype = GRAIN
+
+/obj/item/reagent_containers/food/snacks/pie/berrytart
+ name = "berry tart"
+ desc = "A tasty dessert of many different small barries on a thin pie crust."
+ icon_state = "berrytart"
+ bonus_reagents = list("nutriment" = 1, "vitamin" = 4)
+ list_reagents = list("nutriment" = 3, "vitamin" = 5)
+ tastes = list("pie" = 1, "berries" = 2)
+ foodtype = GRAIN | FRUIT
+
+/obj/item/reagent_containers/food/snacks/pie/cocolavatart
+ name = "chocolate lava tart"
+ desc = "A tasty dessert made of chocaloate, with a liquid core."
+ icon_state = "cocolavatart"
+ bonus_reagents = list("nutriment" = 1, "vitamin" = 4)
+ list_reagents = list("nutriment" = 4, "vitamin" = 4)
+ tastes = list("pie" = 1, "grape" = 1)
+ foodtype = GRAIN | SUGAR
+
/obj/item/reagent_containers/food/snacks/pie/blumpkinpie
name = "blumpkin pie"
desc = "An odd blue pie made with toxic blumpkin."
@@ -288,6 +313,14 @@
icon_state = "baklavaslice"
trash = /obj/item/trash/plate
filling_color = "#1E90FF"
- list_reagents = list("nutriment" = 2, "vitamins" = 4)
+ list_reagents = list("nutriment" = 2, "vitamin" = 4)
tastes = list("nuts" = 1, "pie" = 1)
- foodtype = GRAIN
\ No newline at end of file
+ foodtype = GRAIN
+
+/obj/item/reagent_containers/food/snacks/pie/strawberrypie
+ name = "strawberry pie"
+ desc = "A strawberry.pie."
+ icon_state = "strawberrypie"
+ bonus_reagents = list("nutriment" = 6, "vitamin" = 6)
+ tastes = list("strawberry" = 1, "pie" = 1)
+ foodtype = GRAIN | FRUIT | SUGAR
diff --git a/code/modules/food_and_drinks/food/snacks_vend.dm b/code/modules/food_and_drinks/food/snacks_vend.dm
index 317a434040..8f661b868e 100644
--- a/code/modules/food_and_drinks/food/snacks_vend.dm
+++ b/code/modules/food_and_drinks/food/snacks_vend.dm
@@ -7,7 +7,7 @@
desc = "Nougat love it or hate it."
icon_state = "candy"
trash = /obj/item/trash/candy
- list_reagents = list("nutriment" = 1, "sugar" = 3)
+ list_reagents = list("nutriment" = 1, "sugar" = 3, "cocoa" = 3)
junkiness = 25
filling_color = "#D2691E"
tastes = list("candy" = 1)
diff --git a/code/modules/food_and_drinks/recipes/tablecraft/recipes_cake.dm b/code/modules/food_and_drinks/recipes/tablecraft/recipes_cake.dm
index 464b8ce26f..e26d15dbd3 100644
--- a/code/modules/food_and_drinks/recipes/tablecraft/recipes_cake.dm
+++ b/code/modules/food_and_drinks/recipes/tablecraft/recipes_cake.dm
@@ -148,6 +148,27 @@
result = /obj/item/reagent_containers/food/snacks/store/cake/bsvc
subcategory = CAT_CAKE
+/datum/crafting_recipe/food/clowncake
+ name = "clown cake"
+ always_availible = FALSE
+ reqs = list(
+ /obj/item/reagent_containers/food/snacks/store/cake/plain = 1,
+ /obj/item/reagent_containers/food/snacks/sundae = 2,
+ /obj/item/reagent_containers/food/snacks/grown/banana = 5
+ )
+ result = /obj/item/reagent_containers/food/snacks/store/cake/clown_cake
+ subcategory = CAT_CAKE
+
+/datum/crafting_recipe/food/vanillacake
+ name = "vanilla cake"
+ always_availible = FALSE
+ reqs = list(
+ /obj/item/reagent_containers/food/snacks/store/cake/plain = 1,
+ /obj/item/reagent_containers/food/snacks/grown/vanillapod = 2
+ )
+ result = /obj/item/reagent_containers/food/snacks/store/cake/vanilla_cake
+ subcategory = CAT_CAKE
+
/datum/crafting_recipe/food/cak
name = "Living cat/cake hybrid"
reqs = list(
diff --git a/code/modules/food_and_drinks/recipes/tablecraft/recipes_frozen.dm b/code/modules/food_and_drinks/recipes/tablecraft/recipes_frozen.dm
index 08d5716779..73b09df68d 100644
--- a/code/modules/food_and_drinks/recipes/tablecraft/recipes_frozen.dm
+++ b/code/modules/food_and_drinks/recipes/tablecraft/recipes_frozen.dm
@@ -211,7 +211,7 @@
subcategory = CAT_ICE
/datum/crafting_recipe/food/kiwi_sc
- name = "Soda water snowcone"
+ name = "Kiwi snowcone"
reqs = list(
/obj/item/reagent_containers/food/drinks/sillycup = 1,
/obj/item/reagent_containers/food/snacks/egg/kiwiEgg = 1,
diff --git a/code/modules/food_and_drinks/recipes/tablecraft/recipes_misc.dm b/code/modules/food_and_drinks/recipes/tablecraft/recipes_misc.dm
index a6240e5b48..9cf5ea31a0 100644
--- a/code/modules/food_and_drinks/recipes/tablecraft/recipes_misc.dm
+++ b/code/modules/food_and_drinks/recipes/tablecraft/recipes_misc.dm
@@ -258,7 +258,7 @@
subcategory = CAT_MISCFOOD
-/datum/crafting_recipe/food/lizardwine
+/datum/crafting_recipe/lizardwine //not a subtype of /datum/crafting_recipe/food due to a bug where the resulting bottle would contain 100u of lizardwine and 100u of ethanol.
name = "Lizard wine"
time = 40
reqs = list(
@@ -266,6 +266,7 @@
/datum/reagent/consumable/ethanol = 100
)
result = /obj/item/reagent_containers/food/drinks/bottle/lizardwine
+ category = CAT_FOOD
subcategory = CAT_MISCFOOD
@@ -331,3 +332,12 @@
)
result = /obj/item/reagent_containers/food/snacks/riceball
subcategory = CAT_MISCFOOD
+
+/datum/crafting_recipe/food/chocolatestrawberry
+ name = "Chocolate Strawberry"
+ reqs = list(
+ /obj/item/reagent_containers/food/snacks/chocolatebar = 1,
+ /obj/item/reagent_containers/food/snacks/grown/strawberry = 1
+ )
+ result = /obj/item/reagent_containers/food/snacks/chocolatestrawberry
+ subcategory = CAT_MISCFOOD
\ No newline at end of file
diff --git a/code/modules/food_and_drinks/recipes/tablecraft/recipes_pastry.dm b/code/modules/food_and_drinks/recipes/tablecraft/recipes_pastry.dm
index 2246d12df4..931a78212f 100644
--- a/code/modules/food_and_drinks/recipes/tablecraft/recipes_pastry.dm
+++ b/code/modules/food_and_drinks/recipes/tablecraft/recipes_pastry.dm
@@ -325,6 +325,15 @@ datum/crafting_recipe/food/donut/meat
result = /obj/item/reagent_containers/food/snacks/bluecherrycupcake
subcategory = CAT_PASTRY
+/datum/crafting_recipe/food/strawberrycupcake
+ name = "Strawberry cherry cupcake"
+ reqs = list(
+ /obj/item/reagent_containers/food/snacks/pastrybase = 1,
+ /obj/item/reagent_containers/food/snacks/grown/strawberry = 1
+ )
+ result = /obj/item/reagent_containers/food/snacks/strawberrycupcake
+ subcategory = CAT_PASTRY
+
/datum/crafting_recipe/food/honeybun
name = "Honey bun"
reqs = list(
diff --git a/code/modules/food_and_drinks/recipes/tablecraft/recipes_pie.dm b/code/modules/food_and_drinks/recipes/tablecraft/recipes_pie.dm
index 79d761c2e2..81824dc4b8 100644
--- a/code/modules/food_and_drinks/recipes/tablecraft/recipes_pie.dm
+++ b/code/modules/food_and_drinks/recipes/tablecraft/recipes_pie.dm
@@ -160,6 +160,15 @@
result = /obj/item/reagent_containers/food/snacks/pie/frostypie
subcategory = CAT_PIE
+/datum/crafting_recipe/food/strawberrypie
+ name = "Strawberry pie"
+ reqs = list(
+ /obj/item/reagent_containers/food/snacks/pie/plain = 1,
+ /obj/item/reagent_containers/food/snacks/grown/strawberry = 1
+ )
+ result = /obj/item/reagent_containers/food/snacks/pie/strawberrypie
+ subcategory = CAT_PIE
+
/datum/crafting_recipe/food/baklava
name = "Baklava pie"
reqs = list(
@@ -168,4 +177,41 @@
/obj/item/seeds/wheat/oat = 3
)
result = /obj/item/reagent_containers/food/snacks/pie/baklava
+ subcategory = CAT_PIE
+
+/datum/crafting_recipe/food/mimetart
+ name = "Mime tart"
+ always_availible = FALSE
+ reqs = list(
+ /datum/reagent/consumable/milk = 5,
+ /datum/reagent/consumable/sugar = 5,
+ /obj/item/reagent_containers/food/snacks/pie/plain = 1,
+ /datum/reagent/consumable/nothing = 5
+ )
+ result = /obj/item/reagent_containers/food/snacks/pie/mimetart
+ subcategory = CAT_PIE
+
+/datum/crafting_recipe/food/berrytart
+ name = "Berry tart"
+ always_availible = FALSE
+ reqs = list(
+ /datum/reagent/consumable/milk = 5,
+ /datum/reagent/consumable/sugar = 5,
+ /obj/item/reagent_containers/food/snacks/pie/plain = 1,
+ /obj/item/reagent_containers/food/snacks/grown/berries = 3
+ )
+ result = /obj/item/reagent_containers/food/snacks/pie/berrytart
+ subcategory = CAT_PIE
+
+/datum/crafting_recipe/food/cocolavatart
+ name = "Chocolate Lava tart"
+ always_availible = FALSE
+ reqs = list(
+ /datum/reagent/consumable/milk = 5,
+ /datum/reagent/consumable/sugar = 5,
+ /obj/item/reagent_containers/food/snacks/pie/plain = 1,
+ /obj/item/reagent_containers/food/snacks/chocolatebar = 3,
+ /obj/item/slime_extract = 1
+ )
+ result = /obj/item/reagent_containers/food/snacks/pie/cocolavatart
subcategory = CAT_PIE
\ No newline at end of file
diff --git a/code/modules/goonchat/browserOutput.dm b/code/modules/goonchat/browserOutput.dm
index 463df71f71..082f20f524 100644
--- a/code/modules/goonchat/browserOutput.dm
+++ b/code/modules/goonchat/browserOutput.dm
@@ -82,6 +82,12 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("tmp/iconCache.sav")) //Cache of ico
if("setMusicVolume")
data = setMusicVolume(arglist(params))
+ if("swaptodarkmode")
+ swaptodarkmode()
+
+ if("swaptolightmode")
+ swaptolightmode()
+
if(data)
ehjax_send(data = data)
@@ -240,3 +246,10 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("tmp/iconCache.sav")) //Cache of ico
// url_encode it TWICE, this way any UTF-8 characters are able to be decoded by the Javascript.
C << output(url_encode(url_encode(message)), "browseroutput:output")
+
+
+/datum/chatOutput/proc/swaptolightmode() //Dark mode light mode stuff. Yell at KMC if this breaks! (See darkmode.dm for documentation)
+ owner.force_white_theme()
+
+/datum/chatOutput/proc/swaptodarkmode()
+ owner.force_dark_theme()
diff --git a/code/modules/goonchat/browserassets/css/browserOutput.css b/code/modules/goonchat/browserassets/css/browserOutput.css
index cf11b77879..7b942494f4 100644
--- a/code/modules/goonchat/browserassets/css/browserOutput.css
+++ b/code/modules/goonchat/browserassets/css/browserOutput.css
@@ -7,16 +7,20 @@ html, body {
padding: 0;
margin: 0;
height: 100%;
- color: #000000;
+ color: #f0f0f0;
}
body {
- background: #E0E0E0; /*CIT CHANGE - darkens chatbox a lil*/
+ background: #171717;
font-family: Verdana, sans-serif;
font-size: 9pt;
+ font-color: #f0f0f0;
line-height: 1.2;
overflow-x: hidden;
overflow-y: scroll;
- word-wrap: break-word;
+ word-wrap: break-word;
+ scrollbar-face-color:#1A1A1A;
+ scrollbar-track-color:#171717;
+ scrollbar-highlight-color:#171717;
}
em {
@@ -56,9 +60,9 @@ img.icon {
border-radius: 10px;
}
-a {color: #0000ff;}
-a.visited {color: #ff00ff;}
-a:visited {color: #ff00ff;}
+a {color: #397ea5;}
+a.visited {color: #7c00e6;}
+a:visited {color: #7c00e6;}
a.popt {text-decoration: none;}
/*****************************************
@@ -89,21 +93,21 @@ a.popt {text-decoration: none;}
bottom: 0;
right: 0;
padding: 8px;
- background: #ddd;
+ background: #202020;
text-decoration: none;
font-variant: small-caps;
font-size: 1.1em;
font-weight: bold;
- color: #333;
+ color: #a4bad6;
}
-#newMessages:hover {background: #ccc;}
+#newMessages:hover {background: #171717;}
#newMessages i {vertical-align: middle; padding-left: 3px;}
#ping {
position: fixed;
top: 0;
- right: 80px;
+ right: 115px;
width: 45px;
- background: #ddd;
+ background: #202020;
height: 30px;
padding: 8px 0 2px 0;
}
@@ -120,19 +124,19 @@ a.popt {text-decoration: none;}
right: 0;
}
#userBar .subCell {
- background: #ddd;
+ background: #202020;
height: 30px;
padding: 5px 0;
display: block;
- color: #333;
+ color: #a4bad6;
text-decoration: none;
line-height: 28px;
- border-top: 1px solid #b4b4b4;
+ border-top: 1px solid #171717;
}
-#userBar .subCell:hover {background: #ccc;}
+#userBar .subCell:hover {background: #202020;}
#userBar .toggle {
width: 40px;
- background: #ccc;
+ background: #202020;
border-top: 0;
float: right;
text-align: center;
@@ -242,9 +246,9 @@ a.popt {text-decoration: none;}
******************************************/
/* MOTD */
-.motd {color: #638500; font-family: Verdana, sans-serif;}
-.motd h1, .motd h2, .motd h3, .motd h4, .motd h5, .motd h6 {color: #638500; text-decoration: underline;}
-.motd a, .motd a:link, .motd a:visited, .motd a:active, .motd a:hover {color: #638500;}
+.motd {color: #a4bad6; font-family: Verdana, sans-serif;}
+.motd h1, .motd h2, .motd h3, .motd h4, .motd h5, .motd h6 {color: #a4bad6; text-decoration: underline;}
+.motd a, .motd a:link, .motd a:visited, .motd a:active, .motd a:hover {color: #a4bad6;}
/* ADD HERE FOR BOLD */
.bold, .name, .prefix, .ooc, .looc, .adminooc, .admin, .medal, .yell {font-weight: bold;}
@@ -255,88 +259,90 @@ a.popt {text-decoration: none;}
/* OUTPUT COLORS */
.highlight {background: yellow;}
-h1, h2, h3, h4, h5, h6 {color: #0000ff;font-family: Georgia, Verdana, sans-serif;}
-h1.alert, h2.alert {color: #000000;}
+h1, h2, h3, h4, h5, h6 {color: #a4bad6;font-family: Georgia, Verdana, sans-serif;}
+h1.alert, h2.alert {color: #a4bad6;}
em {font-style: normal; font-weight: bold;}
-.ooc { font-weight: bold;}
+.ooc {color: #cca300; font-weight: bold;}
+.antagooc {color: #ce254f; font-weight: bold;}
.adminobserverooc {color: #0099cc; font-weight: bold;}
-.adminooc {color: #700038; font-weight: bold;}
+.adminooc {color: #3d5bc3; font-weight: bold;}
-.adminsay {color: #FF4500; font-weight: bold;}
-.admin {color: #386aff; font-weight: bold;}
+.adminsay {color: #ff4500; font-weight: bold;}
+.admin {color: #5975da; font-weight: bold;}
.name { font-weight: bold;}
.say {}
-.deadsay {color: #5c00e6;}
+.deadsay {color: #e2c1ff;}
.binarysay {color: #20c20e; background-color: #000000; display: block;}
.binarysay a {color: #00ff00;}
.binarysay a:active, .binarysay a:visited {color: #88ff88;}
-.radio {color: #008000;}
-.sciradio {color: #993399;}
-.comradio {color: #948f02;}
-.secradio {color: #a30000;}
-.medradio {color: #337296;}
-.engradio {color: #fb5613;}
-.suppradio {color: #a8732b;}
-.servradio {color: #6eaa2c;}
-.syndradio {color: #6d3f40;}
-.centcomradio {color: #686868;}
-.aiprivradio {color: #ff00ff;}
-.redteamradio {color: #ff0000;}
-.blueteamradio {color: #0000ff;}
+.radio {color: #1ecc43;}
+.sciradio {color: #c68cfa;}
+.comradio {color: #5177ff;}
+.secradio {color: #dd3535;}
+.medradio {color: #57b8f0;}
+.engradio {color: #f37746;}
+.suppradio {color: #b88646;}
+.servradio {color: #6ca729;}
+.syndradio {color: #8f4a4b;}
+.centcomradio {color: #2681a5;}
+.aiprivradio {color: #d65d95;}
+.redteamradio {color: #ff4444;}
+.blueteamradio {color: #3434fd;}
.yell { font-weight: bold;}
-.alert {color: #ff0000;}
-h1.alert, h2.alert {color: #000000;}
+.alert {color: #d82020;}
+h1.alert, h2.alert {color: #99aab5;}
.emote { font-style: italic;}
.selecteddna {color: #ffffff; background-color: #001B1B}
-.attack {color: #ff0000;}
-.disarm {color: #990000;}
-.passive {color: #660000;}
+.attack {color: #e01c1c;}
+.disarm {color: #b42525;}
+.passive {color: #a00f0f;}
-.userdanger {color: #ff0000; font-weight: bold; font-size: 24px;}
-.danger {color: #ff0000;}
-.warning {color: #ff0000; font-style: italic;}
-.alertwarning {color: #FF0000; font-weight: bold}
-.boldwarning {color: #ff0000; font-style: italic; font-weight: bold}
-.announce {color: #228b22; font-weight: bold;}
-.boldannounce {color: #ff0000; font-weight: bold;}
-.greenannounce {color: #00ff00; font-weight: bold;}
+.userdanger {color: #c51e1e; font-weight: bold; font-size: 24px;}
+.danger {color: #c51e1e;}
+.warning {color: #c51e1e; font-style: italic;}
+.alertwarning {color: #FF0000; font-weight: bold}
+.boldwarning {color: #c51e1e; font-style: italic; font-weight: bold}
+.announce {color: #c51e1e; font-weight: bold;}
+.boldannounce {color: #c51e1e; font-weight: bold;}
+.greenannounce {color: #059223; font-weight: bold;}
.rose {color: #ff5050;}
-.info {color: #0000CC;}
-.notice {color: #000099;}
-.boldnotice {color: #000099; font-weight: bold;}
-.adminnotice {color: #0000ff;}
+.info {color: #6685f5;}
+.notice {color: #6685f5;}
+.boldnotice {color: #6685f5; font-weight: bold;}
+.adminnotice {color: #6685f5;}
.adminhelp {color: #ff0000; font-weight: bold;}
-.unconscious {color: #0000ff; font-weight: bold;}
+.unconscious {color: #a4bad6; font-weight: bold;}
.suicide {color: #ff5050; font-style: italic;}
-.green {color: #03ff39;}
-.red {color: #FF0000}
-.blue {color: #215cff}
-.nicegreen {color: #14a833;}
+.red {color: #FF0000}
+.pink {color: #ff70c1;}
+.blue {color: #215cff}
+.green {color: #059223;}
+.nicegreen {color: #059223;}
.userlove {color: #FF1493; font-style: italic; font-weight: bold; text-shadow: 0 0 6px #ff6dbc;}
.love {color: #ff006a; font-style: italic; text-shadow: 0 0 6px #ff6d6d;}
-.shadowling {color: #3b2769;}
-.cult {color: #960000;}
+.shadowling {color: #8e8a99;}
+.cult {color: #aa1c1c;}
-.cultitalic {color: #960000; font-style: italic;}
-.cultbold {color: #960000; font-style: italic; font-weight: bold;}
-.cultboldtalic {color: #960000; font-weight: bold; font-size: 24px;}
+.cultitalic {color: #aa1c1c; font-style: italic;}
+.cultbold {color: #aa1c1c; font-style: italic; font-weight: bold;}
+.cultboldtalic {color: #aa1c1c; font-weight: bold; font-size: 24px;}
-.cultlarge {color: #960000; font-weight: bold; font-size: 24px;}
-.narsie {color: #960000; font-weight: bold; font-size: 120px;}
-.narsiesmall {color: #960000; font-weight: bold; font-size: 48px;}
+.cultlarge {color: #aa1c1c; font-weight: bold; font-size: 24px;}
+.narsie {color: #aa1c1c; font-weight: bold; font-size: 120px;}
+.narsiesmall {color: #aa1c1c; font-weight: bold; font-size: 48px;}
.colossus {color: #7F282A; font-size: 40px;}
-.hierophant {color: #660099; font-weight: bold; font-style: italic;}
-.hierophant_warning {color: #660099; font-style: italic;}
-.purple {color: #5e2d79;}
-.holoparasite {color: #35333a;}
+.hierophant {color: #b441ee; font-weight: bold; font-style: italic;}
+.hierophant_warning {color: #c56bf1; font-style: italic;}
+.purple {color: #9956d3;}
+.holoparasite {color: #88809c;}
.revennotice {color: #1d2953;}
.revenboldnotice {color: #1d2953; font-weight: bold;}
@@ -344,11 +350,11 @@ h1.alert, h2.alert {color: #000000;}
.revenminor {color: #823abb}
.revenwarning {color: #760fbb; font-style: italic;}
.revendanger {color: #760fbb; font-weight: bold; font-size: 24px;}
-.umbra {color: #5000A0;}
-.umbra_emphasis {color: #5000A0; font-weight: bold; font-style: italic;}
-.umbra_large {color: #5000A0; font-size: 24px; font-weight: bold; font-style: italic;}
+.umbra {color: #7c00e6;}
+.umbra_emphasis {color: #7c00e6; font-weight: bold; font-style: italic;}
+.umbra_large {color: #7c00e6; font-size: 24px; font-weight: bold; font-style: italic;}
-.deconversion_message {color: #5000A0; font-size: 24px; font-style: italic;}
+.deconversion_message {color: #a947ff; font-size: 24px; font-style: italic;}
.brass {color: #BE8700;}
.heavy_brass {color: #BE8700; font-weight: bold; font-style: italic;}
@@ -373,17 +379,17 @@ h1.alert, h2.alert {color: #000000;}
.neovgre {color: #6E001A; font-weight: bold; font-style: italic;}
.neovgre_small {color: #6E001A;}
-.newscaster {color: #800000;}
-.ghostalert {color: #5c00e6; font-style: italic; font-weight: bold;}
+.newscaster {color: #c05d5d;}
+.ghostalert {color: #6600ff; font-style: italic; font-weight: bold;}
-.alien {color: #543354;}
-.noticealien {color: #00c000;}
-.alertalien {color: #00c000; font-weight: bold;}
-.changeling {color: #800080; font-style: italic;}
+.alien {color: #855d85;}
+.noticealien {color: #059223;}
+.alertalien {color: #059223; font-weight: bold;}
+.changeling {color: #059223; font-style: italic;}
-.spider {color: #4d004d;}
+.spider {color: #8800ff;}
-.interface {color: #330033;}
+.interface {color: #750e75;}
.sans {font-family: "Comic Sans MS", cursive, sans-serif;}
.papyrus {font-family: "Papyrus", cursive, sans-serif;}
@@ -394,29 +400,54 @@ h1.alert, h2.alert {color: #000000;}
.big {font-size: 24px;}
.reallybig {font-size: 32px;}
.extremelybig {font-size: 40px;}
-.greentext {color: #00FF00; font-size: 24px;}
-.redtext {color: #FF0000; font-size: 24px;}
-.clown {color: #FF69Bf; font-size: 24px; font-family: "Comic Sans MS", cursive, sans-serif; font-weight: bold;}
+.greentext {color: #059223; font-size: 24px;}
+.redtext {color: #c51e1e; font-size: 24px;}
+.clown {color: #ff70c1; font-size: 24px; font-family: "Comic Sans MS", cursive, sans-serif; font-weight: bold;}
.his_grace {color: #15D512; font-family: "Courier New", cursive, sans-serif; font-style: italic;}
+.velvet {color: #660015; font-weight: bold; animation: velvet 5000ms infinite;}
+@keyframes velvet {
+ 0% { color: #400020; }
+ 40% { color: #FF0000; }
+ 50% { color: #FF8888; }
+ 60% { color: #FF0000; }
+ 100% { color: #400020; }
+}
+
+.hypnophrase {color: #202020; font-weight: bold; animation: hypnocolor 1500ms infinite;}
+@keyframes hypnocolor {
+ 0% { color: #202020; }
+ 25% { color: #4b02ac; }
+ 50% { color: #9f41f1; }
+ 75% { color: #541c9c; }
+ 100% { color: #7adbf3; }
+}
+
+.phobia {color: #dd0000; font-weight: bold; animation: phobia 750ms infinite;}
+@keyframes phobia {
+ 0% { color: #f75a5a; }
+ 50% { color: #dd0000; }
+ 100% { color: #f75a5a; }
+}
+
.icon {height: 1em; width: auto;}
.memo {color: #638500; text-align: center;}
.memoedit {text-align: center; font-size: 16px;}
-.abductor {color: #800080; font-style: italic;}
-.mind_control {color: #A00D6F; font-size: 3; font-weight: bold; font-style: italic;}
+.abductor {color: #c204c2; font-style: italic;}
+.mind_control {color: #df3da9; font-size: 3; font-weight: bold; font-style: italic;}
.slime {color: #00CED1;}
.drone {color: #848482;}
.monkey {color: #975032;}
.swarmer {color: #2C75FF;}
.resonate {color: #298F85;}
-.monkeyhive {color: #774704;}
-.monkeylead {color: #774704; font-size: 2;}
+.monkeyhive {color: #a56408;}
+.monkeylead {color: #af6805; font-size: 2;}
.connectionClosed, .fatalError {background: red; color: white; padding: 5px;}
.connectionClosed.restored {background: green;}
-.internal.boldnshit {color: blue; font-weight: bold;}
+.internal.boldnshit {color: #3d5bc3; font-weight: bold;}
/* HELPER CLASSES */
.text-normal {font-weight: normal; font-style: normal;}
diff --git a/code/modules/goonchat/browserassets/css/browserOutput_white.css b/code/modules/goonchat/browserassets/css/browserOutput_white.css
new file mode 100644
index 0000000000..e21185449b
--- /dev/null
+++ b/code/modules/goonchat/browserassets/css/browserOutput_white.css
@@ -0,0 +1,426 @@
+/*****************************************
+*
+* GLOBAL STYLES
+*
+******************************************/
+html, body {
+ padding: 0;
+ margin: 0;
+ height: 100%;
+ color: #000000;
+}
+body {
+ background: #fff;
+ font-family: Verdana, sans-serif;
+ font-size: 9pt;
+ line-height: 1.2;
+ overflow-x: hidden;
+ overflow-y: scroll;
+ word-wrap: break-word;
+}
+
+em {
+ font-style: normal;
+ font-weight: bold;
+}
+
+img {
+ margin: 0;
+ padding: 0;
+ line-height: 1;
+ -ms-interpolation-mode: nearest-neighbor;
+ image-rendering: pixelated;
+}
+img.icon {
+ height: 1em;
+ min-height: 16px;
+ width: auto;
+ vertical-align: bottom;
+}
+
+
+.r:before { /* "repeated" badge class for combined messages */
+ content: 'x';
+}
+.r {
+ display: inline-block;
+ min-width: 0.5em;
+ font-size: 0.7em;
+ padding: 0.2em 0.3em;
+ line-height: 1;
+ color: white;
+ text-align: center;
+ white-space: nowrap;
+ vertical-align: middle;
+ background-color: crimson;
+ border-radius: 10px;
+}
+
+a {color: #0000ff;}
+a.visited {color: #ff00ff;}
+a:visited {color: #ff00ff;}
+a.popt {text-decoration: none;}
+
+/*****************************************
+*
+* OUTPUT NOT RELATED TO ACTUAL MESSAGES
+*
+******************************************/
+#loading {
+ position: fixed;
+ width: 300px;
+ height: 150px;
+ text-align: center;
+ left: 50%;
+ top: 50%;
+ margin: -75px 0 0 -150px;
+}
+#loading i {display: block; padding-bottom: 3px;}
+
+#messages {
+ font-size: 13px;
+ padding: 3px;
+ margin: 0;
+ word-wrap: break-word;
+}
+#newMessages {
+ position: fixed;
+ display: block;
+ bottom: 0;
+ right: 0;
+ padding: 8px;
+ background: #ddd;
+ text-decoration: none;
+ font-variant: small-caps;
+ font-size: 1.1em;
+ font-weight: bold;
+ color: #333;
+}
+#newMessages:hover {background: #ccc;}
+#newMessages i {vertical-align: middle; padding-left: 3px;}
+#ping {
+ position: fixed;
+ top: 0;
+ right: 115px;
+ width: 45px;
+ background: #ddd;
+ height: 30px;
+ padding: 8px 0 2px 0;
+}
+#ping i {display: block; text-align: center;}
+#ping .ms {
+ display: block;
+ text-align: center;
+ font-size: 8pt;
+ padding-top: 2px;
+}
+#userBar {
+ position: fixed;
+ top: 0;
+ right: 0;
+}
+#userBar .subCell {
+ background: #ddd;
+ height: 30px;
+ padding: 5px 0;
+ display: block;
+ color: #333;
+ text-decoration: none;
+ line-height: 28px;
+ border-top: 1px solid #b4b4b4;
+}
+#userBar .subCell:hover {background: #ccc;}
+#userBar .toggle {
+ width: 40px;
+ background: #ccc;
+ border-top: 0;
+ float: right;
+ text-align: center;
+}
+#userBar .sub {clear: both; display: none; width: 160px;}
+#userBar .sub.scroll {overflow-y: scroll;}
+#userBar .sub.subCell {padding: 3px 0 3px 8px; line-height: 30px; font-size: 0.9em; clear: both;}
+#userBar .sub span {
+ display: block;
+ line-height: 30px;
+ float: left;
+}
+#userBar .sub i {
+ display: block;
+ padding: 0 5px;
+ font-size: 1.1em;
+ width: 22px;
+ text-align: center;
+ line-height: 30px;
+ float: right;
+}
+#userBar .sub input {
+ position: absolute;
+ padding: 7px 5px;
+ width: 121px;
+ line-height: 30px;
+ float: left;
+}
+#userBar .topCell {border-top: 0;}
+
+/* POPUPS */
+.popup {
+ position: fixed;
+ top: 50%;
+ left: 50%;
+ background: #ddd;
+}
+.popup .close {
+ position: absolute;
+ background: #aaa;
+ top: 0;
+ right: 0;
+ color: #333;
+ text-decoration: none;
+ z-index: 2;
+ padding: 0 10px;
+ height: 30px;
+ line-height: 30px;
+}
+.popup .close:hover {background: #999;}
+.popup .head {
+ background: #999;
+ color: #ddd;
+ padding: 0 10px;
+ height: 30px;
+ line-height: 30px;
+ text-transform: uppercase;
+ font-size: 0.9em;
+ font-weight: bold;
+ border-bottom: 2px solid green;
+}
+.popup input {border: 1px solid #999; background: #fff; margin: 0; padding: 5px; outline: none; color: #333;}
+.popup input[type=text]:hover, .popup input[type=text]:active, .popup input[type=text]:focus {border-color: green;}
+.popup input[type=submit] {padding: 5px 10px; background: #999; color: #ddd; text-transform: uppercase; font-size: 0.9em; font-weight: bold;}
+.popup input[type=submit]:hover, .popup input[type=submit]:focus, .popup input[type=submit]:active {background: #aaa; cursor: pointer;}
+
+.changeFont {padding: 10px;}
+.changeFont a {display: block; text-decoration: none; padding: 3px; color: #333;}
+.changeFont a:hover {background: #ccc;}
+
+.highlightPopup {padding: 10px; text-align: center;}
+.highlightPopup input[type=text] {display: block; width: 215px; text-align: left; margin-top: 5px;}
+.highlightPopup input.highlightColor {background-color: #FFFF00;}
+.highlightPopup input.highlightTermSubmit {margin-top: 5px;}
+
+/* ADMIN CONTEXT MENU */
+.contextMenu {
+ background-color: #ddd;
+ position: fixed;
+ margin: 2px;
+ width: 150px;
+}
+.contextMenu a {
+ display: block;
+ padding: 2px 5px;
+ text-decoration: none;
+ color: #333;
+}
+
+.contextMenu a:hover {
+ background-color: #ccc;
+}
+
+/* ADMIN FILTER MESSAGES MENU */
+.filterMessages {padding: 5px;}
+.filterMessages div {padding: 2px 0;}
+.filterMessages input {}
+.filterMessages label {}
+
+.icon-stack {height: 1em; line-height: 1em; width: 1em; vertical-align: middle; margin-top: -2px;}
+
+
+/*****************************************
+*
+* OUTPUT ACTUALLY RELATED TO MESSAGES
+*
+******************************************/
+
+/* MOTD */
+.motd {color: #638500; font-family: Verdana, sans-serif;}
+.motd h1, .motd h2, .motd h3, .motd h4, .motd h5, .motd h6 {color: #638500; text-decoration: underline;}
+.motd a, .motd a:link, .motd a:visited, .motd a:active, .motd a:hover {color: #638500;}
+
+/* ADD HERE FOR BOLD */
+.bold, .name, .prefix, .ooc, .looc, .adminooc, .admin, .medal, .yell {font-weight: bold;}
+
+/* ADD HERE FOR ITALIC */
+.italic, .italics, .emote {font-style: italic;}
+
+/* OUTPUT COLORS */
+.highlight {background: yellow;}
+
+h1, h2, h3, h4, h5, h6 {color: #0000ff;font-family: Georgia, Verdana, sans-serif;}
+h1.alert, h2.alert {color: #000000;}
+
+em {font-style: normal; font-weight: bold;}
+
+.ooc {color: #002eb8; font-weight: bold;}
+.antagooc {color: #b8002e; font-weight: bold;}
+.adminobserverooc {color: #0099cc; font-weight: bold;}
+.adminooc {color: #700038; font-weight: bold;}
+
+.adminsay {color: #ff4500; font-weight: bold;}
+.admin {color: #4473ff; font-weight: bold;}
+
+.name { font-weight: bold;}
+
+.say {}
+.deadsay {color: #5c00e6;}
+.binarysay {color: #20c20e; background-color: #000000; display: block;}
+.binarysay a {color: #00ff00;}
+.binarysay a:active, .binarysay a:visited {color: #88ff88;}
+.radio {color: #008000;}
+.sciradio {color: #993399;}
+.comradio {color: #948f02;}
+.secradio {color: #a30000;}
+.medradio {color: #337296;}
+.engradio {color: #fb5613;}
+.suppradio {color: #a8732b;}
+.servradio {color: #6eaa2c;}
+.syndradio {color: #6d3f40;}
+.centcomradio {color: #686868;}
+.aiprivradio {color: #ff00ff;}
+.redteamradio {color: #ff0000;}
+.blueteamradio {color: #0000ff;}
+
+.yell { font-weight: bold;}
+
+.alert {color: #ff0000;}
+h1.alert, h2.alert {color: #000000;}
+
+.emote { font-style: italic;}
+.selecteddna {color: #ffffff; background-color: #001B1B}
+
+.attack {color: #ff0000;}
+.disarm {color: #990000;}
+.passive {color: #660000;}
+
+.userdanger {color: #ff0000; font-weight: bold; font-size: 24px;}
+.danger {color: #ff0000;}
+.warning {color: #ff0000; font-style: italic;}
+.alertwarning {color: #FF0000; font-weight: bold}
+.boldwarning {color: #ff0000; font-style: italic; font-weight: bold}
+.announce {color: #228b22; font-weight: bold;}
+.boldannounce {color: #ff0000; font-weight: bold;}
+.greenannounce {color: #00ff00; font-weight: bold;}
+.rose {color: #ff5050;}
+.info {color: #0000CC;}
+.notice {color: #000099;}
+.boldnotice {color: #000099; font-weight: bold;}
+.adminnotice {color: #0000ff;}
+.adminhelp {color: #ff0000; font-weight: bold;}
+.unconscious {color: #0000ff; font-weight: bold;}
+.suicide {color: #ff5050; font-style: italic;}
+.green {color: #03ff39;}
+.red {color: #FF0000}
+.pink {color: #FF69Bf;}
+.blue {color: #0000FF}
+.nicegreen {color: #14a833;}
+.userlove {color: #FF1493; font-style: italic; font-weight: bold; text-shadow: 0 0 6px #ff6dbc;}
+.love {color: #ff006a; font-style: italic; text-shadow: 0 0 6px #ff6d6d;}
+.shadowling {color: #3b2769;}
+.cult {color: #960000;}
+
+.cultitalic {color: #960000; font-style: italic;}
+.cultbold {color: #960000; font-style: italic; font-weight: bold;}
+.cultboldtalic {color: #960000; font-weight: bold; font-size: 24px;}
+
+.cultlarge {color: #960000; font-weight: bold; font-size: 24px;}
+.narsie {color: #960000; font-weight: bold; font-size: 120px;}
+.narsiesmall {color: #960000; font-weight: bold; font-size: 48px;}
+.colossus {color: #7F282A; font-size: 40px;}
+.hierophant {color: #660099; font-weight: bold; font-style: italic;}
+.hierophant_warning {color: #660099; font-style: italic;}
+.purple {color: #5e2d79;}
+.holoparasite {color: #35333a;}
+
+.revennotice {color: #1d2953;}
+.revenboldnotice {color: #1d2953; font-weight: bold;}
+.revenbignotice {color: #1d2953; font-weight: bold; font-size: 24px;}
+.revenminor {color: #823abb}
+.revenwarning {color: #760fbb; font-style: italic;}
+.revendanger {color: #760fbb; font-weight: bold; font-size: 24px;}
+.umbra {color: #5000A0;}
+.umbra_emphasis {color: #5000A0; font-weight: bold; font-style: italic;}
+.umbra_large {color: #5000A0; font-size: 24px; font-weight: bold; font-style: italic;}
+
+.deconversion_message {color: #5000A0; font-size: 24px; font-style: italic;}
+
+.brass {color: #BE8700;}
+.heavy_brass {color: #BE8700; font-weight: bold; font-style: italic;}
+.large_brass {color: #BE8700; font-size: 24px;}
+.big_brass {color: #BE8700; font-size: 24px; font-weight: bold; font-style: italic;}
+.ratvar {color: #BE8700; font-size: 48px; font-weight: bold; font-style: italic;}
+.alloy {color: #42474D;}
+.heavy_alloy {color: #42474D; font-weight: bold; font-style: italic;}
+.nezbere_large {color: #42474D; font-size: 24px; font-weight: bold; font-style: italic;}
+.nezbere {color: #42474D; font-weight: bold; font-style: italic;}
+.nezbere_small {color: #42474D;}
+.sevtug_large {color: #AF0AAF; font-size: 24px; font-weight: bold; font-style: italic;}
+.sevtug {color: #AF0AAF; font-weight: bold; font-style: italic;}
+.sevtug_small {color: #AF0AAF;}
+.inathneq_large {color: #1E8CE1; font-size: 24px; font-weight: bold; font-style: italic;}
+.inathneq {color: #1E8CE1; font-weight: bold; font-style: italic;}
+.inathneq_small {color: #1E8CE1;}
+.nzcrentr_large {color: #DAAA18; font-size: 24px; font-weight: bold; font-style: italic;}
+.nzcrentr {color: #DAAA18; font-weight: bold; font-style: italic;}
+.nzcrentr_small {color: #DAAA18;}
+.neovgre_large {color: #6E001A; font-size: 24px; font-weight: bold; font-style: italic;}
+.neovgre {color: #6E001A; font-weight: bold; font-style: italic;}
+.neovgre_small {color: #6E001A;}
+
+.newscaster {color: #800000;}
+.ghostalert {color: #5c00e6; font-style: italic; font-weight: bold;}
+
+.alien {color: #543354;}
+.noticealien {color: #00c000;}
+.alertalien {color: #00c000; font-weight: bold;}
+.changeling {color: #800080; font-style: italic;}
+
+.spider {color: #4d004d;}
+
+.interface {color: #330033;}
+
+.sans {font-family: "Comic Sans MS", cursive, sans-serif;}
+.papyrus {font-family: "Papyrus", cursive, sans-serif;}
+.robot {font-family: "Courier New", cursive, sans-serif;}
+
+.command_headset {font-weight: bold; font-size: 24px;}
+.small {font-size: 8px;}
+.big {font-size: 24px;}
+.reallybig {font-size: 32px;}
+.extremelybig {font-size: 40px;}
+.greentext {color: #00FF00; font-size: 24px;}
+.redtext {color: #FF0000; font-size: 24px;}
+.clown {color: #FF69Bf; font-size: 24px; font-family: "Comic Sans MS", cursive, sans-serif; font-weight: bold;}
+.his_grace {color: #15D512; font-family: "Courier New", cursive, sans-serif; font-style: italic;}
+
+.icon {height: 1em; width: auto;}
+
+.memo {color: #638500; text-align: center;}
+.memoedit {text-align: center; font-size: 16px;}
+.abductor {color: #800080; font-style: italic;}
+.mind_control {color: #A00D6F; font-size: 3; font-weight: bold; font-style: italic;}
+.slime {color: #00CED1;}
+.drone {color: #848482;}
+.monkey {color: #975032;}
+.swarmer {color: #2C75FF;}
+.resonate {color: #298F85;}
+
+.monkeyhive {color: #774704;}
+.monkeylead {color: #774704; font-size: 2;}
+
+.connectionClosed, .fatalError {background: red; color: white; padding: 5px;}
+.connectionClosed.restored {background: green;}
+.internal.boldnshit {color: blue; font-weight: bold;}
+
+/* HELPER CLASSES */
+.text-normal {font-weight: normal; font-style: normal;}
+.hidden {display: none; visibility: hidden;}
+
diff --git a/code/modules/goonchat/browserassets/html/browserOutput.html b/code/modules/goonchat/browserassets/html/browserOutput.html
index fe3be9486c..9c6d462a85 100644
--- a/code/modules/goonchat/browserassets/html/browserOutput.html
+++ b/code/modules/goonchat/browserassets/html/browserOutput.html
@@ -5,7 +5,7 @@
-
+
@@ -28,6 +28,9 @@
--ms
+
diff --git a/code/modules/goonchat/browserassets/js/browserOutput.js b/code/modules/goonchat/browserassets/js/browserOutput.js
index 33553d765e..93a498fd06 100644
--- a/code/modules/goonchat/browserassets/js/browserOutput.js
+++ b/code/modules/goonchat/browserassets/js/browserOutput.js
@@ -35,6 +35,7 @@ var opts = {
'wasd': false, //Is the user in wasd mode?
'priorChatHeight': 0, //Thing for height-resizing detection
'restarting': false, //Is the round restarting?
+ 'darkmode':false, //Are we using darkmode? If not WHY ARE YOU LIVING IN 2009???
//Options menu
'selectedSubLoop': null, //Contains the interval loop for closing the selected sub menu
@@ -394,6 +395,19 @@ function toHex(n) {
return "0123456789ABCDEF".charAt((n-n%16)/16) + "0123456789ABCDEF".charAt(n%16);
}
+function swap() { //Swap to darkmode
+ if (opts.darkmode){
+ document.getElementById("sheetofstyles").href = "browserOutput_white.css";
+ opts.darkmode = false;
+ runByond('?_src_=chat&proc=swaptolightmode');
+ } else {
+ document.getElementById("sheetofstyles").href = "browserOutput.css";
+ opts.darkmode = true;
+ runByond('?_src_=chat&proc=swaptodarkmode');
+ }
+ setCookie('darkmode', (opts.darkmode ? 'true' : 'false'), 365);
+}
+
function handleClientData(ckey, ip, compid) {
//byond sends player info to here
var currentData = {'ckey': ckey, 'ip': ip, 'compid': compid};
@@ -601,6 +615,7 @@ $(function() {
'shighlightColor': getCookie('highlightcolor'),
'smusicVolume': getCookie('musicVolume'),
'smessagecombining': getCookie('messagecombining'),
+ 'sdarkmode': getCookie('darkmode'),
};
if (savedConfig.sfontSize) {
@@ -611,6 +626,9 @@ $(function() {
$("body").css('line-height', savedConfig.slineHeight);
internalOutput('Loaded line height setting of: '+savedConfig.slineHeight+'', 'internal');
}
+ if(savedConfig.sdarkmode == 'true'){
+ swap();
+ }
if (savedConfig.spingDisabled) {
if (savedConfig.spingDisabled == 'true') {
opts.pingDisabled = true;
@@ -655,8 +673,6 @@ $(function() {
opts.messageCombining = true;
}
}
-
-
(function() {
var dataCookie = getCookie('connData');
if (dataCookie) {
@@ -823,7 +839,9 @@ $(function() {
$('#toggleOptions').click(function(e) {
handleToggleClick($subOptions, $(this));
});
-
+ $('#darkmodetoggle').click(function(e) {
+ swap();
+ });
$('#toggleAudio').click(function(e) {
handleToggleClick($subAudio, $(this));
});
@@ -895,7 +913,7 @@ $(function() {
$.ajax({
type: 'GET',
- url: 'browserOutput.css',
+ url: 'browserOutput_white.css',
success: function(styleData) {
var blob = new Blob(['Chat Log', $messages.html(), '']);
diff --git a/code/modules/holodeck/holo_effect.dm b/code/modules/holodeck/holo_effect.dm
index fee0b2b7c9..308cec1cbd 100644
--- a/code/modules/holodeck/holo_effect.dm
+++ b/code/modules/holodeck/holo_effect.dm
@@ -78,6 +78,12 @@
// these vars are not really standardized but all would theoretically create stuff on death
for(var/v in list("butcher_results","corpse","weapon1","weapon2","blood_volume") & mob.vars)
mob.vars[v] = null
+ ENABLE_BITFIELD(mob.flags_1, HOLOGRAM_1)
+ if(isliving(mob))
+ var/mob/living/L = mob
+ L.feeding = FALSE
+ L.devourable = FALSE
+ L.digestable = FALSE
return mob
/obj/effect/holodeck_effect/mobspawner/deactivate(var/obj/machinery/computer/holodeck/HC)
@@ -100,7 +106,7 @@
/obj/effect/holodeck_effect/mobspawner/penguin
mobtype = /mob/living/simple_animal/pet/penguin/emperor
-
+
/obj/effect/holodeck_effect/mobspawner/penguin/Initialize()
if(prob(1))
mobtype = /mob/living/simple_animal/pet/penguin/emperor/shamebrero
diff --git a/code/modules/hydroponics/gene_modder.dm b/code/modules/hydroponics/gene_modder.dm
index d6eacfe0e1..79a23014b0 100644
--- a/code/modules/hydroponics/gene_modder.dm
+++ b/code/modules/hydroponics/gene_modder.dm
@@ -69,6 +69,8 @@
if(default_deconstruction_screwdriver(user, "dnamod", "dnamod", I))
update_icon()
return
+ else if(default_unfasten_wrench(user, I))
+ return
if(default_deconstruction_crowbar(I))
return
if(iscyborg(user))
diff --git a/code/modules/hydroponics/grown/berries.dm b/code/modules/hydroponics/grown/berries.dm
index 19abdacf3a..e9ad49eedd 100644
--- a/code/modules/hydroponics/grown/berries.dm
+++ b/code/modules/hydroponics/grown/berries.dm
@@ -215,3 +215,22 @@
filling_color = "#7FFF00"
tastes = list("green grape" = 1)
distill_reagent = "cognac"
+
+// Strawberry
+/obj/item/seeds/strawberry
+ name = "pack of strawberry seeds"
+ desc = "These seeds grow into strawberry vines."
+ icon_state = "seed-strawberry"
+ species = "strawberry"
+ plantname = "Strawberry Vine"
+ product = /obj/item/reagent_containers/food/snacks/grown/strawberry
+ reagents_add = list("vitamin" = 0.07, "nutriment" = 0.1, "sugar" = 0.2)
+ mutatelist = list()
+
+/obj/item/reagent_containers/food/snacks/grown/strawberry
+ seed = /obj/item/seeds/strawberry
+ name = "strawberry"
+ icon_state = "strawberry"
+ filling_color = "#7FFF00"
+ tastes = list("strawberries" = 1)
+ wine_power = 20
diff --git a/code/modules/hydroponics/grown/cotton.dm b/code/modules/hydroponics/grown/cotton.dm
new file mode 100644
index 0000000000..045839d0de
--- /dev/null
+++ b/code/modules/hydroponics/grown/cotton.dm
@@ -0,0 +1,79 @@
+/obj/item/seeds/cotton
+ name = "pack of cotton seeds"
+ desc = "A pack of seeds that'll grow into a cotton plant. Assistants make good free labor if neccesary."
+ icon_state = "seed-cotton"
+ species = "cotton"
+ plantname = "Cotton"
+ icon_harvest = "cotton-harvest"
+ product = /obj/item/grown/cotton
+ lifespan = 35
+ endurance = 25
+ maturation = 15
+ production = 1
+ yield = 2
+ potency = 50
+ growthstages = 3
+ growing_icon = 'icons/obj/hydroponics/growing.dmi'
+ icon_dead = "cotton-dead"
+ mutatelist = list(/obj/item/seeds/cotton/durathread)
+
+/obj/item/grown/cotton
+ seed = /obj/item/seeds/cotton
+ name = "cotton bundle"
+ desc = "A fluffy bundle of cotton."
+ icon_state = "cotton"
+ force = 0
+ throwforce = 0
+ w_class = WEIGHT_CLASS_TINY
+ throw_speed = 2
+ throw_range = 3
+ attack_verb = list("pomfed")
+ var/cotton_type = /obj/item/stack/sheet/cotton
+ var/cotton_name = "raw cotton"
+
+/obj/item/grown/cotton/attack_self(mob/user)
+ user.show_message("You pull some [cotton_name] out of the [name]!", 1)
+ var/seed_modifier = 0
+ if(seed)
+ seed_modifier = round(seed.potency / 25)
+ var/obj/item/stack/cotton = new cotton_type(user.loc, 1 + seed_modifier)
+ var/old_cotton_amount = cotton.amount
+ for(var/obj/item/stack/ST in user.loc)
+ if(ST != cotton && istype(ST, cotton_type) && ST.amount < ST.max_amount)
+ ST.attackby(cotton, user)
+ if(cotton.amount > old_cotton_amount)
+ to_chat(user, "You add the newly-formed [cotton_name] to the stack. It now contains [cotton.amount] [cotton_name].")
+ qdel(src)
+
+//reinforced mutated variant
+/obj/item/seeds/cotton/durathread
+ name = "pack of durathread seeds"
+ desc = "A pack of seeds that'll grow into an extremely durable thread that could easily rival plasteel if woven properly."
+ icon_state = "seed-durathread"
+ species = "durathread"
+ plantname = "Durathread"
+ icon_harvest = "durathread-harvest"
+ product = /obj/item/grown/cotton/durathread
+ lifespan = 80
+ endurance = 50
+ maturation = 15
+ production = 1
+ yield = 2
+ potency = 50
+ growthstages = 3
+ growing_icon = 'icons/obj/hydroponics/growing.dmi'
+ icon_dead = "cotton-dead"
+
+/obj/item/grown/cotton/durathread
+ seed = /obj/item/seeds/cotton/durathread
+ name = "durathread bundle"
+ desc = "A tough bundle of durathread, good luck unraveling this."
+ icon_state = "durathread"
+ force = 5
+ throwforce = 5
+ w_class = WEIGHT_CLASS_NORMAL
+ throw_speed = 2
+ throw_range = 3
+ attack_verb = list("bashed", "battered", "bludgeoned", "whacked")
+ cotton_type = /obj/item/stack/sheet/cotton/durathread
+ cotton_name = "raw durathread"
\ No newline at end of file
diff --git a/code/modules/hydroponics/grown/flowers.dm b/code/modules/hydroponics/grown/flowers.dm
index 4e1718f853..f1aea5706a 100644
--- a/code/modules/hydroponics/grown/flowers.dm
+++ b/code/modules/hydroponics/grown/flowers.dm
@@ -25,6 +25,7 @@
slot_flags = ITEM_SLOT_HEAD
filling_color = "#FF6347"
bitesize_mod = 3
+ tastes = list("sesame seeds" = 1)
foodtype = VEGETABLES | GROSS
distill_reagent = "vermouth"
@@ -43,6 +44,7 @@
name = "lily"
desc = "A beautiful orange flower."
icon_state = "lily"
+ tastes = list("pelts " = 1)
filling_color = "#FFA500"
// Geranium
@@ -61,6 +63,7 @@
desc = "A beautiful blue flower."
icon_state = "geranium"
filling_color = "#008B8B"
+ tastes = list("pelts " = 1)
// Harebell
/obj/item/seeds/harebell
@@ -86,6 +89,7 @@
name = "harebell"
desc = "\"I'll sweeten thy sad grave: thou shalt not lack the flower that's like thy face, pale primrose, nor the azured hare-bell, like thy veins; no, nor the leaf of eglantine, whom not to slander, out-sweeten'd not thy breath.\""
icon_state = "harebell"
+ tastes = list("salt" = 1)
slot_flags = ITEM_SLOT_HEAD
filling_color = "#E6E6FA"
bitesize_mod = 3
@@ -123,6 +127,7 @@
w_class = WEIGHT_CLASS_TINY
throw_speed = 1
throw_range = 3
+ tastes = list("seeds" = 1)
/obj/item/grown/sunflower/attack(mob/M, mob/user)
to_chat(M, " [user] smacks you with a sunflower!FLOWER POWER")
@@ -153,6 +158,7 @@
filling_color = "#E6E6FA"
bitesize_mod = 2
distill_reagent = "absinthe" //It's made from flowers.
+ tastes = list("glowbugs" = 1)
// Novaflower
/obj/item/seeds/sunflower/novaflower
@@ -184,6 +190,7 @@
throw_range = 3
attack_verb = list("roasted", "scorched", "burned")
grind_results = list("capsaicin" = 0, "condensedcapsaicin" = 0)
+ tastes = list("cooked sunflower" = 1)
/obj/item/grown/novaflower/add_juice()
..()
diff --git a/code/modules/hydroponics/grown/tea_coffee.dm b/code/modules/hydroponics/grown/tea_coffee.dm
index fc84617ed8..d9e775acc0 100644
--- a/code/modules/hydroponics/grown/tea_coffee.dm
+++ b/code/modules/hydroponics/grown/tea_coffee.dm
@@ -14,6 +14,7 @@
icon_dead = "tea-dead"
genes = list(/datum/plant_gene/trait/repeated_harvest)
mutatelist = list(/obj/item/seeds/tea/astra)
+ reagents_add = list("teapowder" = 0.1)
/obj/item/reagent_containers/food/snacks/grown/tea
seed = /obj/item/seeds/tea
diff --git a/code/modules/hydroponics/growninedible.dm b/code/modules/hydroponics/growninedible.dm
index 5aeef19b1a..c0e3beaf79 100644
--- a/code/modules/hydroponics/growninedible.dm
+++ b/code/modules/hydroponics/growninedible.dm
@@ -7,6 +7,7 @@
icon = 'icons/obj/hydroponics/harvest.dmi'
resistance_flags = FLAMMABLE
var/obj/item/seeds/seed = null // type path, gets converted to item on New(). It's safe to assume it's always a seed item.
+ var/tastes = list("indescribable" = 1) //Stops runtimes. Grown are un-eatable anyways so if you do then its a bug
/obj/item/grown/Initialize(newloc, obj/item/seeds/new_seed)
. = ..()
diff --git a/code/modules/hydroponics/plant_genes.dm b/code/modules/hydroponics/plant_genes.dm
index 17462c0626..db529e8ffb 100644
--- a/code/modules/hydroponics/plant_genes.dm
+++ b/code/modules/hydroponics/plant_genes.dm
@@ -290,15 +290,15 @@
var/teleport_radius = max(round(G.seed.potency / 10), 1)
var/turf/T = get_turf(target)
new /obj/effect/decal/cleanable/molten_object(T) //Leave a pile of goo behind for dramatic effect...
- do_teleport(target, T, teleport_radius)
+ do_teleport(target, T, teleport_radius, channel = TELEPORT_CHANNEL_BLUESPACE)
/datum/plant_gene/trait/teleport/on_slip(obj/item/reagent_containers/food/snacks/grown/G, mob/living/carbon/C)
var/teleport_radius = max(round(G.seed.potency / 10), 1)
var/turf/T = get_turf(C)
to_chat(C, "You slip through spacetime!")
- do_teleport(C, T, teleport_radius)
+ do_teleport(C, T, teleport_radius, channel = TELEPORT_CHANNEL_BLUESPACE)
if(prob(50))
- do_teleport(G, T, teleport_radius)
+ do_teleport(G, T, teleport_radius, channel = TELEPORT_CHANNEL_BLUESPACE)
else
new /obj/effect/decal/cleanable/molten_object(T) //Leave a pile of goo behind for dramatic effect...
qdel(G)
diff --git a/code/modules/integrated_electronics/core/printer.dm b/code/modules/integrated_electronics/core/printer.dm
index de3ade389f..f0aa10f2da 100644
--- a/code/modules/integrated_electronics/core/printer.dm
+++ b/code/modules/integrated_electronics/core/printer.dm
@@ -193,7 +193,7 @@
else if(ispath(build_type, /obj/item/integrated_circuit))
var/obj/item/integrated_circuit/IC = SScircuit.cached_components[build_type]
cost = IC.materials[MAT_METAL]
- else if(!build_type in SScircuit.circuit_fabricator_recipe_list["Tools"])
+ else if(!(build_type in SScircuit.circuit_fabricator_recipe_list["Tools"]))
return
var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
diff --git a/code/modules/jobs/job_types/assistant.dm b/code/modules/jobs/job_types/assistant.dm
index 65805f73fd..ce6eea97b0 100644
--- a/code/modules/jobs/job_types/assistant.dm
+++ b/code/modules/jobs/job_types/assistant.dm
@@ -30,6 +30,12 @@ Assistant
/datum/outfit/job/assistant/pre_equip(mob/living/carbon/human/H)
..()
if (CONFIG_GET(flag/grey_assistants))
- uniform = /obj/item/clothing/under/color/grey
+ if(H.jumpsuit_style == PREF_SUIT)
+ uniform = /obj/item/clothing/under/color/grey
+ else
+ uniform = /obj/item/clothing/under/skirt/color/grey
else
- uniform = /obj/item/clothing/under/color/random
+ if(H.jumpsuit_style == PREF_SUIT)
+ uniform = /obj/item/clothing/under/color/random
+ else
+ uniform = /obj/item/clothing/under/skirt/color/random
diff --git a/code/modules/jobs/job_types/captain.dm b/code/modules/jobs/job_types/captain.dm
index cd9c914e7a..b3c952f536 100755
--- a/code/modules/jobs/job_types/captain.dm
+++ b/code/modules/jobs/job_types/captain.dm
@@ -21,6 +21,8 @@ Captain
access = list() //See get_access()
minimal_access = list() //See get_access()
+ blacklisted_quirks = list(/datum/quirk/mute, /datum/quirk/brainproblems, /datum/quirk/insanity)
+
/datum/job/captain/get_access()
return get_all_accesses()
@@ -67,7 +69,7 @@ Head of Personnel
flag = HOP
department_head = list("Captain")
department_flag = CIVILIAN
- head_announce = list("Supply", "Service")
+ head_announce = list(RADIO_CHANNEL_SERVICE)
faction = "Station"
total_positions = 1
spawn_positions = 1
@@ -94,6 +96,7 @@ Head of Personnel
ACCESS_THEATRE, ACCESS_CHAPEL_OFFICE, ACCESS_LIBRARY, ACCESS_RESEARCH, ACCESS_MINING, ACCESS_VAULT, ACCESS_MINING_STATION,
ACCESS_HOP, ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_GATEWAY, ACCESS_MINERAL_STOREROOM)
+ blacklisted_quirks = list(/datum/quirk/mute, /datum/quirk/brainproblems, /datum/quirk/prosopagnosia, /datum/quirk/insanity)
/datum/outfit/job/hop
name = "Head of Personnel"
diff --git a/code/modules/jobs/job_types/cargo_service.dm b/code/modules/jobs/job_types/cargo_service.dm
index 22ef2a9211..8e24ece655 100644
--- a/code/modules/jobs/job_types/cargo_service.dm
+++ b/code/modules/jobs/job_types/cargo_service.dm
@@ -6,6 +6,7 @@ Quartermaster
flag = QUARTERMASTER
department_head = list("Head of Personnel")
department_flag = CIVILIAN
+ head_announce = list(RADIO_CHANNEL_SUPPLY)
faction = "Station"
total_positions = 1
spawn_positions = 1
@@ -17,6 +18,8 @@ Quartermaster
access = list(ACCESS_MAINT_TUNNELS, ACCESS_MAILSORTING, ACCESS_CARGO, ACCESS_CARGO_BOT, ACCESS_QM, ACCESS_MINING, ACCESS_MINING_STATION, ACCESS_MINERAL_STOREROOM, ACCESS_VAULT)
minimal_access = list(ACCESS_MAINT_TUNNELS, ACCESS_MAILSORTING, ACCESS_CARGO, ACCESS_CARGO_BOT, ACCESS_QM, ACCESS_MINING, ACCESS_MINING_STATION, ACCESS_MINERAL_STOREROOM, ACCESS_VAULT)
+ blacklisted_quirks = list(/datum/quirk/mute, /datum/quirk/brainproblems, /datum/quirk/insanity)
+
/datum/outfit/job/quartermaster
name = "Quartermaster"
jobtype = /datum/job/qm
@@ -88,9 +91,9 @@ Shaft Miner
gloves = /obj/item/clothing/gloves/color/black
uniform = /obj/item/clothing/under/rank/miner/lavaland
l_pocket = /obj/item/reagent_containers/hypospray/medipen/survival
- r_pocket = /obj/item/flashlight/seclite
+ r_pocket = /obj/item/storage/bag/ore //causes issues if spawned in backpack
backpack_contents = list(
- /obj/item/storage/bag/ore=1,\
+ /obj/item/flashlight/seclite=1,\
/obj/item/kitchen/knife/combat/survival=1,\
/obj/item/mining_voucher=1,\
/obj/item/suit_voucher=1,\
@@ -116,7 +119,7 @@ Shaft Miner
suit_store = /obj/item/tank/internals/oxygen
internals_slot = SLOT_S_STORE
backpack_contents = list(
- /obj/item/storage/bag/ore=1,
+ /obj/item/flashlight/seclite=1,\
/obj/item/kitchen/knife/combat/survival=1,
/obj/item/mining_voucher=1,
/obj/item/t_scanner/adv_mining_scanner/lesser=1,
diff --git a/code/modules/jobs/job_types/engineering.dm b/code/modules/jobs/job_types/engineering.dm
index f28e5f1afc..e65cbab1bd 100644
--- a/code/modules/jobs/job_types/engineering.dm
+++ b/code/modules/jobs/job_types/engineering.dm
@@ -6,7 +6,7 @@ Chief Engineer
flag = CHIEF
department_head = list("Captain")
department_flag = ENGSEC
- head_announce = list("Engineering")
+ head_announce = list(RADIO_CHANNEL_ENGINEERING)
faction = "Station"
total_positions = 1
spawn_positions = 1
@@ -29,6 +29,8 @@ Chief Engineer
ACCESS_HEADS, ACCESS_CONSTRUCTION, ACCESS_SEC_DOORS, ACCESS_MINISAT,
ACCESS_CE, ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_TCOMSAT, ACCESS_MINERAL_STOREROOM)
+ blacklisted_quirks = list(/datum/quirk/mute, /datum/quirk/brainproblems, /datum/quirk/paraplegic, /datum/quirk/insanity)
+
/datum/outfit/job/ce
name = "Chief Engineer"
jobtype = /datum/job/chief_engineer
diff --git a/code/modules/jobs/job_types/job.dm b/code/modules/jobs/job_types/job.dm
index f678700735..9549b6100c 100644
--- a/code/modules/jobs/job_types/job.dm
+++ b/code/modules/jobs/job_types/job.dm
@@ -56,6 +56,8 @@
var/list/mind_traits // Traits added to the mind of the mob assigned this job
+ var/list/blacklisted_quirks //list of quirk typepaths blacklisted.
+
//Only override this proc
//H is usually a human unless an /equip override transformed it
/datum/job/proc/after_spawn(mob/living/H, mob/M, latejoin = FALSE)
@@ -190,6 +192,16 @@
backpack_contents.Insert(1, box) // Box always takes a first slot in backpack
backpack_contents[box] = 1
+ //converts the uniform string into the path we'll wear, whether it's the skirt or regular variant
+ var/holder
+ if(H.jumpsuit_style == PREF_SKIRT)
+ holder = "[uniform]/skirt"
+ if(!text2path(holder))
+ holder = "[uniform]"
+ else
+ holder = "[uniform]"
+ uniform = text2path(holder)
+
/datum/outfit/job/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
if(visualsOnly)
return
diff --git a/code/modules/jobs/job_types/medical.dm b/code/modules/jobs/job_types/medical.dm
index 5a926f490a..9eeb4ab06e 100644
--- a/code/modules/jobs/job_types/medical.dm
+++ b/code/modules/jobs/job_types/medical.dm
@@ -6,7 +6,7 @@ Chief Medical Officer
flag = CMO_JF
department_head = list("Captain")
department_flag = MEDSCI
- head_announce = list("Medical")
+ head_announce = list(RADIO_CHANNEL_MEDICAL)
faction = "Station"
total_positions = 1
spawn_positions = 1
@@ -27,6 +27,8 @@ Chief Medical Officer
ACCESS_CHEMISTRY, ACCESS_VIROLOGY, ACCESS_CMO, ACCESS_SURGERY, ACCESS_RC_ANNOUNCE,
ACCESS_KEYCARD_AUTH, ACCESS_SEC_DOORS, ACCESS_MAINT_TUNNELS)
+ blacklisted_quirks = list(/datum/quirk/mute, /datum/quirk/brainproblems, /datum/quirk/insanity)
+
/datum/outfit/job/cmo
name = "Chief Medical Officer"
jobtype = /datum/job/cmo
@@ -127,6 +129,7 @@ Chemist
backpack = /obj/item/storage/backpack/chemistry
satchel = /obj/item/storage/backpack/satchel/chem
duffelbag = /obj/item/storage/backpack/duffelbag/med
+ l_hand = /obj/item/fermichem/pHbooklet
chameleon_extras = /obj/item/gun/syringe
diff --git a/code/modules/jobs/job_types/science.dm b/code/modules/jobs/job_types/science.dm
index 6a14f204a3..b58f3faa27 100644
--- a/code/modules/jobs/job_types/science.dm
+++ b/code/modules/jobs/job_types/science.dm
@@ -6,7 +6,7 @@ Research Director
flag = RD_JF
department_head = list("Captain")
department_flag = MEDSCI
- head_announce = list("Science")
+ head_announce = list(RADIO_CHANNEL_SCIENCE)
faction = "Station"
total_positions = 1
spawn_positions = 1
@@ -31,6 +31,8 @@ Research Director
ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_GATEWAY, ACCESS_MINERAL_STOREROOM,
ACCESS_TECH_STORAGE, ACCESS_MINISAT, ACCESS_MAINT_TUNNELS, ACCESS_NETWORK)
+ blacklisted_quirks = list(/datum/quirk/mute, /datum/quirk/brainproblems, /datum/quirk/insanity)
+
/datum/outfit/job/rd
name = "Research Director"
jobtype = /datum/job/rd
diff --git a/code/modules/jobs/job_types/security.dm b/code/modules/jobs/job_types/security.dm
index 8d2b9e8681..96cedd89ef 100644
--- a/code/modules/jobs/job_types/security.dm
+++ b/code/modules/jobs/job_types/security.dm
@@ -12,7 +12,7 @@ Head of Security
flag = HOS
department_head = list("Captain")
department_flag = ENGSEC
- head_announce = list("Security")
+ head_announce = list(RADIO_CHANNEL_SECURITY)
faction = "Station"
total_positions = 1
spawn_positions = 1
@@ -37,6 +37,8 @@ Head of Security
mind_traits = list(TRAIT_LAW_ENFORCEMENT_METABOLISM)
+ blacklisted_quirks = list(/datum/quirk/mute, /datum/quirk/brainproblems, /datum/quirk/nonviolent, /datum/quirk/paraplegic, /datum/quirk/insanity)
+
/datum/outfit/job/hos
name = "Head of Security"
jobtype = /datum/job/hos
@@ -95,6 +97,7 @@ Warden
minimal_access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_ARMORY, ACCESS_COURT, ACCESS_WEAPONS, ACCESS_MINERAL_STOREROOM) //SEE /DATUM/JOB/WARDEN/GET_ACCESS()
mind_traits = list(TRAIT_LAW_ENFORCEMENT_METABOLISM)
+ blacklisted_quirks = list(/datum/quirk/mute, /datum/quirk/nonviolent, /datum/quirk/paraplegic)
/datum/job/warden/get_access()
var/list/L = list()
@@ -150,6 +153,7 @@ Detective
minimal_access = list(ACCESS_SEC_DOORS, ACCESS_FORENSICS_LOCKERS, ACCESS_MORGUE, ACCESS_MAINT_TUNNELS, ACCESS_COURT, ACCESS_BRIG, ACCESS_WEAPONS, ACCESS_MINERAL_STOREROOM)
mind_traits = list(TRAIT_LAW_ENFORCEMENT_METABOLISM)
+ blacklisted_quirks = list(/datum/quirk/mute, /datum/quirk/nonviolent, /datum/quirk/paraplegic)
/datum/outfit/job/detective
name = "Detective"
@@ -205,6 +209,7 @@ Security Officer
minimal_access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_COURT, ACCESS_WEAPONS, ACCESS_MINERAL_STOREROOM) //BUT SEE /DATUM/JOB/WARDEN/GET_ACCESS()
mind_traits = list(TRAIT_LAW_ENFORCEMENT_METABOLISM)
+ blacklisted_quirks = list(/datum/quirk/mute, /datum/quirk/nonviolent, /datum/quirk/paraplegic)
/datum/job/officer/get_access()
var/list/L = list()
diff --git a/code/modules/mining/equipment/explorer_gear.dm b/code/modules/mining/equipment/explorer_gear.dm
index 2c35c3148f..23ec02976d 100644
--- a/code/modules/mining/equipment/explorer_gear.dm
+++ b/code/modules/mining/equipment/explorer_gear.dm
@@ -43,7 +43,7 @@
name = "explorer gas mask"
desc = "A military-grade gas mask that can be connected to an air supply."
icon_state = "gas_mining"
- visor_flags = BLOCK_GAS_SMOKE_EFFECT | MASKINTERNALS
+ visor_flags = BLOCK_GAS_SMOKE_EFFECT | ALLOWINTERNALS
visor_flags_inv = HIDEFACIALHAIR
visor_flags_cover = MASKCOVERSMOUTH
actions_types = list(/datum/action/item_action/adjust)
diff --git a/code/modules/mining/lavaland/necropolis_chests.dm b/code/modules/mining/lavaland/necropolis_chests.dm
index abcb6d5911..7add723a06 100644
--- a/code/modules/mining/lavaland/necropolis_chests.dm
+++ b/code/modules/mining/lavaland/necropolis_chests.dm
@@ -641,6 +641,8 @@
nemesis_factions = list("mining", "boss")
var/transform_cooldown
var/swiping = FALSE
+ total_mass = 2.75
+ total_mass_on = 5
/obj/item/melee/transforming/cleaving_saw/examine(mob/user)
..()
diff --git a/code/modules/mining/mine_items.dm b/code/modules/mining/mine_items.dm
index a1ba493d46..0abb1cfa9e 100644
--- a/code/modules/mining/mine_items.dm
+++ b/code/modules/mining/mine_items.dm
@@ -68,6 +68,7 @@
/obj/machinery/computer/shuttle/mining
name = "mining shuttle console"
desc = "Used to call and send the mining shuttle."
+ req_access = list(ACCESS_MINING)
circuit = /obj/item/circuitboard/computer/mining_shuttle
shuttleId = "mining"
possible_destinations = "mining_home;mining_away;landing_zone_dock;mining_public"
diff --git a/code/modules/mob/dead/new_player/new_player.dm b/code/modules/mob/dead/new_player/new_player.dm
index eb9d9dd70b..cf578d0aa1 100644
--- a/code/modules/mob/dead/new_player/new_player.dm
+++ b/code/modules/mob/dead/new_player/new_player.dm
@@ -416,7 +416,7 @@
SSticker.mode.make_antag_chance(humanc)
if(humanc && CONFIG_GET(flag/roundstart_traits))
- SSquirks.AssignQuirks(humanc, humanc.client, TRUE)
+ SSquirks.AssignQuirks(humanc, humanc.client, TRUE, FALSE, job, FALSE)
log_manifest(character.mind.key,character.mind,character,latejoin = TRUE)
@@ -429,7 +429,19 @@
/mob/dead/new_player/proc/LateChoices()
- var/dat = "Round Duration: [DisplayTimeText(world.time - SSticker.round_start_time)] "
+
+ var/level = "green"
+ switch(GLOB.security_level)
+ if(SEC_LEVEL_BLUE)
+ level = "blue"
+ if(SEC_LEVEL_AMBER)
+ level = "amber"
+ if(SEC_LEVEL_RED)
+ level = "red"
+ if(SEC_LEVEL_DELTA)
+ level = "delta"
+
+ var/dat = "Round Duration: [DisplayTimeText(world.time - SSticker.round_start_time)] Alert Level: [capitalize(level)] "
if(SSshuttle.emergency)
switch(SSshuttle.emergency.mode)
diff --git a/code/modules/mob/dead/new_player/preferences_setup.dm b/code/modules/mob/dead/new_player/preferences_setup.dm
index ffe9a800a1..6e91b58506 100644
--- a/code/modules/mob/dead/new_player/preferences_setup.dm
+++ b/code/modules/mob/dead/new_player/preferences_setup.dm
@@ -6,11 +6,11 @@
else
gender = pick(MALE,FEMALE)
underwear = random_underwear(gender)
- undie_color = random_color()
+ undie_color = random_short_color()
undershirt = random_undershirt(gender)
- shirt_color = random_color()
+ shirt_color = random_short_color()
socks = random_socks()
- socks_color = random_color()
+ socks_color = random_short_color()
skin_tone = random_skin_tone()
hair_style = random_hair_style(gender)
facial_hair_style = random_facial_hair_style(gender)
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 bf63ea09d7..fb40563ccf 100644
--- a/code/modules/mob/dead/new_player/sprite_accessories/undershirt.dm
+++ b/code/modules/mob/dead/new_player/sprite_accessories/undershirt.dm
@@ -172,11 +172,13 @@
name = "Tank Top - Midriff"
icon_state = "tank_midriff"
has_color = TRUE
+ gender = FEMALE
/datum/sprite_accessory/underwear/top/tanktop_midriff_alt
name = "Tank Top - Midriff Halterneck"
icon_state = "tank_midriff_alt"
has_color = TRUE
+ gender = FEMALE
/datum/sprite_accessory/underwear/top/tankstripe
name = "Tank Top - Striped"
@@ -190,100 +192,122 @@
name = "Baby-Doll"
icon_state = "babydoll"
has_color = TRUE
+ gender = FEMALE
/datum/sprite_accessory/underwear/top/bra
name = "Bra"
icon_state = "bra"
has_color = TRUE
+ gender = FEMALE
/datum/sprite_accessory/underwear/top/bra_alt
name = "Bra - Alt"
icon_state = "bra_alt"
has_color = TRUE
+ gender = FEMALE
/datum/sprite_accessory/underwear/top/bra_thin
name = "Bra - Thin"
icon_state = "bra_thin"
has_color = TRUE
+ gender = FEMALE
/datum/sprite_accessory/underwear/top/bra_kinky
name = "Bra - Kinky Black"
icon_state = "bra_kinky"
+ gender = FEMALE
/datum/sprite_accessory/underwear/top/bra_freedom
name = "Bra - Freedom"
icon_state = "bra_assblastusa"
+ gender = FEMALE
/datum/sprite_accessory/underwear/top/bra_commie
name = "Bra - Commie"
icon_state = "bra_commie"
+ gender = FEMALE
/datum/sprite_accessory/underwear/top/bra_beekini
name = "Bra - Bee-kini"
icon_state = "bra_bee-kini"
+ gender = FEMALE
/datum/sprite_accessory/underwear/top/bra_uk
name = "Bra - UK"
icon_state = "bra_uk"
+ gender = FEMALE
/datum/sprite_accessory/underwear/top/bra_neko
name = "Bra - Neko"
icon_state = "bra_neko"
has_color = TRUE
+ gender = FEMALE
/datum/sprite_accessory/underwear/top/halterneck_bra
name = "Bra - Halterneck"
icon_state = "halterneck_bra"
has_color = TRUE
+ gender = FEMALE
/datum/sprite_accessory/underwear/top/sports_bra
name = "Bra, Sports"
icon_state = "sports_bra"
has_color = TRUE
+ gender = FEMALE
/datum/sprite_accessory/underwear/top/sports_bra_alt
name = "Bra, Sports - Alt"
icon_state = "sports_bra_alt"
has_color = TRUE
+ gender = FEMALE
/datum/sprite_accessory/underwear/top/bra_strapless
name = "Bra, Strapless"
icon_state = "bra_strapless"
has_color = TRUE
+ gender = FEMALE
/datum/sprite_accessory/underwear/top/bra_strapless_alt
name = "Bra, Strapless - Alt"
icon_state = "bra_blue"
has_color = TRUE
+ gender = FEMALE
/datum/sprite_accessory/underwear/top/striped_bra
name = "Bra - Striped"
icon_state = "striped_bra"
has_color = TRUE
+ gender = FEMALE
/datum/sprite_accessory/underwear/top/fishnet_sleeves
name = "Fishnet - sleeves"
icon_state = "fishnet_sleeves"
+ gender = FEMALE
/datum/sprite_accessory/underwear/top/fishnet_gloves
name = "Fishnet - gloves"
icon_state = "fishnet_gloves"
+ gender = FEMALE
/datum/sprite_accessory/underwear/top/fishnet_base
name = "Fishnet - top"
icon_state = "fishnet_body"
+ gender = FEMALE
/datum/sprite_accessory/underwear/top/swimsuit
name = "Swimsuit Top"
icon_state = "bra_swimming"
has_color = TRUE
+ gender = FEMALE
/datum/sprite_accessory/underwear/top/swimsuit_alt
name = "Swimsuit Top - Strapless"
icon_state = "bra_swimming_alt"
has_color = TRUE
+ gender = FEMALE
/datum/sprite_accessory/underwear/top/tubetop
name = "Tube Top"
icon_state = "tubetop"
- has_color = TRUE
\ No newline at end of file
+ has_color = TRUE
+ gender = FEMALE
\ No newline at end of file
diff --git a/code/modules/mob/dead/new_player/sprite_accessories/underwear.dm b/code/modules/mob/dead/new_player/sprite_accessories/underwear.dm
index 611547ad4e..3356804cb3 100644
--- a/code/modules/mob/dead/new_player/sprite_accessories/underwear.dm
+++ b/code/modules/mob/dead/new_player/sprite_accessories/underwear.dm
@@ -10,45 +10,55 @@
name = "Mankini"
icon_state = "mankini"
has_color = TRUE
+ gender = MALE
/datum/sprite_accessory/underwear/bottom/male_kinky
name = "Jockstrap"
icon_state = "jockstrap"
has_color = TRUE
+ gender = MALE
/datum/sprite_accessory/underwear/bottom/briefs
name = "Briefs"
icon_state = "briefs"
has_color = TRUE
+ gender = MALE
/datum/sprite_accessory/underwear/bottom/boxers
name = "Boxers"
icon_state = "boxers"
has_color = TRUE
+ gender = MALE
/datum/sprite_accessory/underwear/bottom/male_bee
name = "Boxers - Bee"
icon_state = "bee_shorts"
+ gender = MALE
/datum/sprite_accessory/underwear/bottom/male_hearts
name = "Boxers - Heart"
icon_state = "boxers_heart"
+ gender = MALE
/datum/sprite_accessory/underwear/bottom/male_stripe
name = "Boxers - Striped"
icon_state = "boxers_striped"
+ gender = MALE
/datum/sprite_accessory/underwear/bottom/male_commie
name = "Boxers - Striped Communist"
icon_state = "boxers_commie"
+ gender = MALE
/datum/sprite_accessory/underwear/bottom/male_usastripe
name = "Boxers - Striped Freedom"
icon_state = "boxers_assblastusa"
+ gender = MALE
/datum/sprite_accessory/underwear/bottom/male_uk
name = "Boxers - Striped UK"
icon_state = "boxers_uk"
+ gender = MALE
/datum/sprite_accessory/underwear/bottom/boxer_briefs
name = "Boxer Briefs"
@@ -59,60 +69,73 @@
name = "Panties"
icon_state = "panties"
has_color = TRUE
+ gender = FEMALE
/datum/sprite_accessory/underwear/bottom/panties_alt
name = "Panties - Alt"
icon_state = "panties_alt"
has_color = TRUE
+ gender = FEMALE
/datum/sprite_accessory/underwear/bottom/fishnet_lower
name = "Panties - Fishnet"
icon_state = "fishnet_lower"
+ gender = FEMALE
/datum/sprite_accessory/underwear/bottom/female_beekini
name = "Panties - Bee-kini"
icon_state = "panties_bee-kini"
+ gender = FEMALE
/datum/sprite_accessory/underwear/bottom/female_commie
name = "Panties - Commie"
icon_state = "panties_commie"
+ gender = FEMALE
/datum/sprite_accessory/underwear/bottom/female_usastripe
name = "Panties - Freedom"
icon_state = "panties_assblastusa"
+ gender = FEMALE
/datum/sprite_accessory/underwear/bottom/female_kinky
name = "Panties - Kinky Black"
icon_state = "panties_kinky"
+ gender = FEMALE
/datum/sprite_accessory/underwear/bottom/panties_uk
name = "Panties - UK"
icon_state = "panties_uk"
+ gender = FEMALE
/datum/sprite_accessory/underwear/bottom/panties_neko
name = "Panties - Neko"
icon_state = "panties_neko"
has_color = TRUE
+ gender = FEMALE
/datum/sprite_accessory/underwear/bottom/panties_slim
name = "Panties - Slim"
icon_state = "panties_slim"
has_color = TRUE
+ gender = FEMALE
/datum/sprite_accessory/underwear/bottom/striped_panties
name = "Panties - Striped"
icon_state = "striped_panties"
has_color = TRUE
+ gender = FEMALE
/datum/sprite_accessory/underwear/bottom/panties_swimsuit
name = "Panties - Swimsuit"
icon_state = "panties_swimming"
has_color = TRUE
+ gender = FEMALE
/datum/sprite_accessory/underwear/bottom/panties_thin
name = "Panties - Thin"
icon_state = "panties_thin"
has_color = TRUE
+ gender = FEMALE
/datum/sprite_accessory/underwear/bottom/longjon
name = "Long John Bottoms"
@@ -122,23 +145,28 @@
/datum/sprite_accessory/underwear/bottom/swimsuit_red
name = "Swimsuit, One Piece - Red"
icon_state = "swimming_red"
+ gender = FEMALE
/datum/sprite_accessory/underwear/bottom/swimsuit
name = "Swimsuit, One Piece - Black"
icon_state = "swimming_black"
+ gender = FEMALE
/datum/sprite_accessory/underwear/bottom/swimsuit_blue
name = "Swimsuit, One Piece - Striped Blue"
icon_state = "swimming_blue"
+ gender = FEMALE
/datum/sprite_accessory/underwear/bottom/thong
name = "Thong"
icon_state = "thong"
has_color = TRUE
+ gender = FEMALE
/datum/sprite_accessory/underwear/bottom/thong_babydoll
name = "Thong - Alt"
icon_state = "thong_babydoll"
has_color = TRUE
+ gender = FEMALE
diff --git a/code/modules/mob/dead/observer/say.dm b/code/modules/mob/dead/observer/say.dm
index d521ef179f..7eeab05466 100644
--- a/code/modules/mob/dead/observer/say.dm
+++ b/code/modules/mob/dead/observer/say.dm
@@ -4,14 +4,14 @@
return
var/message_mode = get_message_mode(message)
- if(client && (message_mode == "admin" || message_mode == "deadmin"))
+ if(client && (message_mode == MODE_ADMIN || message_mode == MODE_DEADMIN))
message = copytext(message, 3)
if(findtext(message, " ", 1, 2))
message = copytext(message, 2)
- if(message_mode == "admin")
+ if(message_mode == MODE_ADMIN)
client.cmd_admin_say(message)
- else if(message_mode == "deadmin")
+ else if(message_mode == MODE_DEADMIN)
client.dsay(message)
return
diff --git a/code/modules/mob/living/blood.dm b/code/modules/mob/living/blood.dm
index 815184c63d..ca1a961a92 100644
--- a/code/modules/mob/living/blood.dm
+++ b/code/modules/mob/living/blood.dm
@@ -18,10 +18,10 @@
/mob/living/carbon/monkey/handle_blood()
if(bodytemperature >= TCRYO && !(HAS_TRAIT(src, TRAIT_NOCLONE))) //cryosleep or husked people do not pump the blood.
//Blood regeneration if there is some space
- if(blood_volume < BLOOD_VOLUME_NORMAL)
+ if(blood_volume < (BLOOD_VOLUME_NORMAL * blood_ratio))
blood_volume += 0.1 // regenerate blood VERY slowly
- if(blood_volume < BLOOD_VOLUME_OKAY)
- adjustOxyLoss(round((BLOOD_VOLUME_NORMAL - blood_volume) * 0.02, 1))
+ if(blood_volume < (BLOOD_VOLUME_OKAY * blood_ratio))
+ adjustOxyLoss(round(((BLOOD_VOLUME_NORMAL * blood_ratio) - blood_volume) * 0.02, 1))
// Takes care blood loss and regeneration
/mob/living/carbon/human/handle_blood()
@@ -33,7 +33,7 @@
if(bodytemperature >= TCRYO && !(HAS_TRAIT(src, TRAIT_NOCLONE))) //cryosleep or husked people do not pump the blood.
//Blood regeneration if there is some space
- if(blood_volume < BLOOD_VOLUME_NORMAL && !HAS_TRAIT(src, TRAIT_NOHUNGER))
+ if(blood_volume < (BLOOD_VOLUME_NORMAL * blood_ratio) && !HAS_TRAIT(src, TRAIT_NOHUNGER))
var/nutrition_ratio = 0
switch(nutrition)
if(0 to NUTRITION_LEVEL_STARVING)
@@ -46,20 +46,22 @@
nutrition_ratio = 0.8
else
nutrition_ratio = 1
+ if(HAS_TRAIT(src, TRAIT_HIGH_BLOOD))
+ nutrition_ratio *= 1.2
if(satiety > 80)
nutrition_ratio *= 1.25
nutrition = max(0, nutrition - nutrition_ratio * HUNGER_FACTOR)
- blood_volume = min(BLOOD_VOLUME_NORMAL, blood_volume + 0.5 * nutrition_ratio)
+ blood_volume = min((BLOOD_VOLUME_NORMAL * blood_ratio), blood_volume + 0.5 * nutrition_ratio)
//Effects of bloodloss
var/word = pick("dizzy","woozy","faint")
- switch(blood_volume)
+ switch(blood_volume * INVERSE(blood_ratio))
if(BLOOD_VOLUME_OKAY to BLOOD_VOLUME_SAFE)
if(prob(5))
to_chat(src, "You feel [word].")
- adjustOxyLoss(round((BLOOD_VOLUME_NORMAL - blood_volume) * 0.01, 1))
+ adjustOxyLoss(round(((BLOOD_VOLUME_NORMAL * blood_ratio) - blood_volume) * 0.01, 1))
if(BLOOD_VOLUME_BAD to BLOOD_VOLUME_OKAY)
- adjustOxyLoss(round((BLOOD_VOLUME_NORMAL - blood_volume) * 0.02, 1))
+ adjustOxyLoss(round(((BLOOD_VOLUME_NORMAL * blood_ratio) - blood_volume) * 0.02, 1))
if(prob(5))
blur_eyes(6)
to_chat(src, "You feel very [word].")
@@ -111,7 +113,7 @@
blood_volume = initial(blood_volume)
/mob/living/carbon/human/restore_blood()
- blood_volume = BLOOD_VOLUME_NORMAL
+ blood_volume = (BLOOD_VOLUME_NORMAL * blood_ratio)
bleed_rate = 0
/****************************************************
@@ -122,7 +124,7 @@
/mob/living/proc/transfer_blood_to(atom/movable/AM, amount, forced)
if(!blood_volume || !AM.reagents)
return 0
- if(blood_volume < BLOOD_VOLUME_BAD && !forced)
+ if(blood_volume < (BLOOD_VOLUME_BAD * blood_ratio) && !forced)
return 0
if(blood_volume < amount)
@@ -161,7 +163,7 @@
return
/mob/living/carbon/get_blood_data(blood_id)
- if(blood_id == "blood") //actual blood reagent
+ if(blood_id == "blood") //actual blood reagent
var/blood_data = list()
//set the blood data
blood_data["donor"] = src
@@ -204,6 +206,21 @@
if(istype(ling))
blood_data["changeling_loudness"] = ling.loudfactor
return blood_data
+ if(blood_id == "slimejelly") //Just so MKUltra works. Takes the minimum required data. Sishen is testing if this breaks stuff.
+ var/blood_data = list()
+ if(mind)
+ blood_data["mind"] = mind
+ else if(last_mind)
+ blood_data["mind"] = last_mind
+ if(ckey)
+ blood_data["ckey"] = ckey
+ else if(last_mind)
+ blood_data["ckey"] = ckey(last_mind.key)
+ blood_data["gender"] = gender
+ blood_data["real_name"] = real_name
+ return blood_data
+
+
//get the id of the substance this mob use as blood.
/mob/proc/get_blood_id()
@@ -300,3 +317,24 @@
var/obj/effect/decal/cleanable/oil/B = locate() in T.contents
if(!B)
B = new(T)
+
+//This is a terrible way of handling it.
+/mob/living/proc/ResetBloodVol()
+ if(ishuman(src))
+ var/mob/living/carbon/human/H = src
+ if (HAS_TRAIT(src, TRAIT_HIGH_BLOOD))
+ blood_ratio = 1.2
+ H.handle_blood()
+ return
+ blood_ratio = 1
+ H.handle_blood()
+ return
+ blood_ratio = 1
+
+/mob/living/proc/AdjustBloodVol(var/value)
+ if(blood_ratio == value)
+ return
+ blood_ratio = value
+ if(ishuman(src))
+ var/mob/living/carbon/human/H = src
+ H.handle_blood()
diff --git a/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm b/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm
index 8403d533c4..edf0fde83e 100644
--- a/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm
+++ b/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm
@@ -91,7 +91,7 @@
else
return initial(pixel_x)
-/mob/living/carbon/alien/humanoid/get_permeability_protection()
+/mob/living/carbon/alien/humanoid/get_permeability_protection(list/target_zones)
return 0.8
/mob/living/carbon/alien/humanoid/alien_evolve(mob/living/carbon/alien/humanoid/new_xeno)
diff --git a/code/modules/mob/living/carbon/alien/humanoid/update_icons.dm b/code/modules/mob/living/carbon/alien/humanoid/update_icons.dm
index e1a7752e9d..d2788075e2 100644
--- a/code/modules/mob/living/carbon/alien/humanoid/update_icons.dm
+++ b/code/modules/mob/living/carbon/alien/humanoid/update_icons.dm
@@ -59,15 +59,19 @@
/mob/living/carbon/alien/humanoid/update_inv_handcuffed()
remove_overlay(HANDCUFF_LAYER)
- var/cuff_icon = "aliencuff"
- var/dmi_file = 'icons/mob/alien.dmi'
-
- if(mob_size == MOB_SIZE_LARGE)
- cuff_icon = "aliencuff_[caste]"
- dmi_file = 'icons/mob/alienqueen.dmi'
if(handcuffed)
- overlays_standing[HANDCUFF_LAYER] = mutable_appearance(dmi_file, cuff_icon, -HANDCUFF_LAYER)
+ var/cuff_icon = handcuffed.item_state
+ var/dmi_file = 'icons/mob/alien.dmi'
+
+ if(mob_size == MOB_SIZE_LARGE)
+ cuff_icon += "_[caste]"
+ dmi_file = 'icons/mob/alienqueen.dmi'
+
+ var/mutable_appearance/cuffs = mutable_appearance(dmi_file, cuff_icon, -HANDCUFF_LAYER)
+ cuffs.color = handcuffed.color
+
+ overlays_standing[HANDCUFF_LAYER] = cuffs
apply_overlay(HANDCUFF_LAYER)
//Royals have bigger sprites, so inhand things must be handled differently.
diff --git a/code/modules/mob/living/carbon/alien/special/alien_embryo.dm b/code/modules/mob/living/carbon/alien/special/alien_embryo.dm
index 86f1c85d8a..585da978cb 100644
--- a/code/modules/mob/living/carbon/alien/special/alien_embryo.dm
+++ b/code/modules/mob/living/carbon/alien/special/alien_embryo.dm
@@ -63,7 +63,7 @@
-/obj/item/organ/body_egg/alien_embryo/proc/AttemptGrow(gib_on_success=TRUE)
+/obj/item/organ/body_egg/alien_embryo/proc/AttemptGrow(var/kill_on_sucess=TRUE)
if(!owner || bursting)
return
@@ -102,10 +102,12 @@
new_xeno.notransform = 0
new_xeno.invisibility = 0
- if(gib_on_success)
- new_xeno.visible_message("[new_xeno] bursts out of [owner] in a shower of gore!", "You exit [owner], your previous host.", "You hear organic matter ripping and tearing!")
- owner.gib(TRUE)
- else
+ if(kill_on_sucess) //ITS TOO LATE
+ new_xeno.visible_message("[new_xeno] bursts out of [owner]!", "You exit [owner], your previous host.", "You hear organic matter ripping and tearing!")
+ owner.apply_damage(rand(100,300),BRUTE,zone,FALSE) //Random high damage to torso so health sensors don't metagame.
+ owner.spill_organs(TRUE,FALSE,TRUE) //Lets still make the death gruesome and impossible to just simply defib someone.
+ owner.death(FALSE) //Just in case some freak occurance occurs where you somehow survive all your organs being removed from you and the 100-300 brute damage.
+ else //When it is removed via surgery at a late stage, rather than forced.
new_xeno.visible_message("[new_xeno] wriggles out of [owner]!", "You exit [owner], your previous host.")
owner.adjustBruteLoss(40)
owner.cut_overlay(overlay)
diff --git a/code/modules/mob/living/carbon/alien/special/facehugger.dm b/code/modules/mob/living/carbon/alien/special/facehugger.dm
index c2c8904aa1..e66d70f492 100644
--- a/code/modules/mob/living/carbon/alien/special/facehugger.dm
+++ b/code/modules/mob/living/carbon/alien/special/facehugger.dm
@@ -15,7 +15,7 @@
icon_state = "facehugger"
item_state = "facehugger"
w_class = WEIGHT_CLASS_TINY //note: can be picked up by aliens unlike most other items of w_class below 4
- clothing_flags = MASKINTERNALS
+ clothing_flags = ALLOWINTERNALS
throw_range = 5
tint = 3
flags_cover = MASKCOVERSEYES | MASKCOVERSMOUTH
@@ -33,16 +33,18 @@
/obj/item/clothing/mask/facehugger/lamarr
name = "Lamarr"
- sterile = 1
+ sterile = TRUE
/obj/item/clothing/mask/facehugger/dead
icon_state = "facehugger_dead"
item_state = "facehugger_inactive"
+ sterile = TRUE
stat = DEAD
/obj/item/clothing/mask/facehugger/impregnated
icon_state = "facehugger_impregnated"
item_state = "facehugger_impregnated"
+ sterile = TRUE
stat = DEAD
/obj/item/clothing/mask/facehugger/take_damage(damage_amount, damage_type = BRUTE, damage_flag = 0, sound_effect = 1, attack_dir)
diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm
index db7257f0f0..b53655ca7c 100644
--- a/code/modules/mob/living/carbon/carbon.dm
+++ b/code/modules/mob/living/carbon/carbon.dm
@@ -6,6 +6,7 @@
create_reagents(1000)
update_body_parts() //to update the carbon's new bodyparts appearance
GLOB.carbon_list += src
+ blood_volume = (BLOOD_VOLUME_NORMAL * blood_ratio)
/mob/living/carbon/Destroy()
//This must be done first, so the mob ghosts correctly before DNA etc is nulled
@@ -238,7 +239,7 @@
if(href_list["internal"])
var/slot = text2num(href_list["internal"])
var/obj/item/ITEM = get_item_by_slot(slot)
- if(ITEM && istype(ITEM, /obj/item/tank) && wear_mask && (wear_mask.clothing_flags & MASKINTERNALS))
+ if(ITEM && istype(ITEM, /obj/item/tank) && wear_mask && (wear_mask.clothing_flags & ALLOWINTERNALS))
visible_message("[usr] tries to [internal ? "close" : "open"] the valve on [src]'s [ITEM.name].", \
"[usr] tries to [internal ? "close" : "open"] the valve on [src]'s [ITEM.name].")
if(do_mob(usr, src, POCKET_STRIP_DELAY))
@@ -246,7 +247,7 @@
internal = null
update_internals_hud_icon(0)
else if(ITEM && istype(ITEM, /obj/item/tank))
- if((wear_mask && (wear_mask.clothing_flags & MASKINTERNALS)) || getorganslot(ORGAN_SLOT_BREATHING_TUBE))
+ if((wear_mask && (wear_mask.clothing_flags & ALLOWINTERNALS)) || getorganslot(ORGAN_SLOT_BREATHING_TUBE))
internal = ITEM
update_internals_hud_icon(1)
@@ -477,11 +478,13 @@
if(message)
visible_message("[src] throws up all over [p_them()]self!", \
"You throw up all over yourself!")
+ SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "vomit", /datum/mood_event/vomitself)
distance = 0
else
if(message)
visible_message("[src] throws up!", "You throw up!")
-
+ if(!isflyperson(src))
+ SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "vomit", /datum/mood_event/vomit)
if(stun)
Stun(80)
@@ -634,6 +637,18 @@
else
. += INFINITY
+/mob/living/carbon/get_permeability_protection(list/target_zones = list(HANDS,CHEST,GROIN,LEGS,FEET,ARMS,HEAD))
+ var/list/tally = list()
+ for(var/obj/item/I in get_equipped_items())
+ for(var/zone in target_zones)
+ if(I.body_parts_covered & zone)
+ tally["[zone]"] = max(1 - I.permeability_coefficient, target_zones["[zone]"])
+ var/protection = 0
+ for(var/key in tally)
+ protection += tally[key]
+ protection *= INVERSE(target_zones.len)
+ return protection
+
//this handles hud updates
/mob/living/carbon/update_damage_hud()
@@ -687,9 +702,10 @@
clear_fullscreen("critvision")
//Oxygen damage overlay
- if(oxyloss)
+ var/windedup = getOxyLoss() + getStaminaLoss() * 0.2 + stamdamageoverlaytemp
+ if(windedup)
var/severity = 0
- switch(oxyloss)
+ switch(windedup)
if(10 to 20)
severity = 1
if(20 to 25)
@@ -916,3 +932,17 @@
/mob/living/carbon/can_resist()
return bodyparts.len > 2 && ..()
+
+/mob/living/carbon/proc/hypnosis_vulnerable()//unused atm, but added in case
+ if(HAS_TRAIT(src, TRAIT_MINDSHIELD))
+ return FALSE
+ if(hallucinating())
+ return TRUE
+ if(IsSleeping())
+ return TRUE
+ if(HAS_TRAIT(src, TRAIT_DUMB))
+ return TRUE
+ GET_COMPONENT_FROM(mood, /datum/component/mood, src)
+ if(mood)
+ if(mood.sanity < SANITY_UNSTABLE)
+ return TRUE
diff --git a/code/modules/mob/living/carbon/carbon_defines.dm b/code/modules/mob/living/carbon/carbon_defines.dm
index f782289e18..a067be798f 100644
--- a/code/modules/mob/living/carbon/carbon_defines.dm
+++ b/code/modules/mob/living/carbon/carbon_defines.dm
@@ -11,8 +11,8 @@
var/silent = FALSE //Can't talk. Value goes down every life proc. //NOTE TO FUTURE CODERS: DO NOT INITIALIZE NUMERICAL VARS AS NULL OR I WILL MURDER YOU.
var/dreaming = 0 //How many dream images we have left to send
- var/obj/item/handcuffed = null //Whether or not the mob is handcuffed
- var/obj/item/legcuffed = null //Same as handcuffs but for legs. Bear traps use this.
+ var/obj/item/restraints/handcuffed //Whether or not the mob is handcuffed
+ var/obj/item/restraints/legcuffed //Same as handcuffs but for legs. Bear traps use this.
var/disgust = 0
@@ -61,5 +61,6 @@
var/next_hallucination = 0
var/cpr_time = 1 //CPR cooldown.
var/damageoverlaytemp = 0
+ var/stamdamageoverlaytemp = 0
var/drunkenness = 0 //Overall drunkenness - check handle_alcohol() in life.dm for effects
diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm
index 8550a0887f..5b224444e0 100644
--- a/code/modules/mob/living/carbon/human/examine.dm
+++ b/code/modules/mob/living/carbon/human/examine.dm
@@ -247,7 +247,7 @@
if(DISGUST_LEVEL_DISGUSTED to INFINITY)
msg += "[t_He] look[p_s()] extremely disgusted.\n"
- if(blood_volume < BLOOD_VOLUME_SAFE)
+ if(blood_volume < (BLOOD_VOLUME_SAFE*blood_ratio))
msg += "[t_He] [t_has] pale skin.\n"
if(bleedsuppress)
@@ -281,6 +281,13 @@
if(91.01 to INFINITY)
msg += "[t_He] [t_is] a shitfaced, slobbering wreck.\n"
+ if(reagents.has_reagent("astral"))
+ msg += "[t_He] have wild, spacey eyes"
+ if(mind)
+ msg += " and have a strange, abnormal look to them.\n"
+ else
+ msg += " and don't look like they're all there.\n"
+
if(isliving(user))
var/mob/living/L = user
if(src != user && HAS_TRAIT(L, TRAIT_EMPATH) && !appears_dead)
@@ -304,6 +311,13 @@
msg += ""
+ var/obj/item/organ/vocal_cords/Vc = user.getorganslot(ORGAN_SLOT_VOICE)
+ if(Vc)
+ if(istype(Vc, /obj/item/organ/vocal_cords/velvet))
+ if(client?.prefs.lewdchem)
+ msg += "You feel your chords resonate looking at them.\n"
+
+
if(!appears_dead)
if(stat == UNCONSCIOUS)
msg += "[t_He] [t_is]n't responding to anything around [t_him] and seem[p_s()] to be asleep.\n"
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index 57dd1af749..528b55c921 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -623,6 +623,7 @@
facial_hair_style = "Shaved"
hair_style = pick("Bedhead", "Bedhead 2", "Bedhead 3")
underwear = "Nude"
+ undershirt = "Nude"
update_body()
update_hair()
update_genitals()
@@ -811,6 +812,8 @@
for(var/datum/mutation/human/HM in dna.mutations)
if(HM.quality != POSITIVE)
dna.remove_mutation(HM.name)
+ if(blood_volume < (BLOOD_VOLUME_NORMAL*blood_ratio))
+ blood_volume = (BLOOD_VOLUME_NORMAL*blood_ratio)
..()
/mob/living/carbon/human/check_weakness(obj/item/weapon, mob/living/attacker)
@@ -899,12 +902,9 @@
stop_pulling()
/mob/living/carbon/human/proc/is_shove_knockdown_blocked() //If you want to add more things that block shove knockdown, extend this
- var/list/body_parts = list(head, wear_mask, wear_suit, w_uniform, back, gloves, shoes, belt, s_store, glasses, ears, wear_id) //Everything but pockets. Pockets are l_store and r_store. (if pockets were allowed, putting something armored, gloves or hats for example, would double up on the armor)
- for(var/bp in body_parts)
- if(istype(bp, /obj/item/clothing))
- var/obj/item/clothing/C = bp
- if(C.blocks_shove_knockdown)
- return TRUE
+ for(var/obj/item/clothing/C in get_equipped_items()) //doesn't include pockets
+ if(C.blocks_shove_knockdown)
+ return TRUE
return FALSE
/mob/living/carbon/human/proc/clear_shove_slowdown()
diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm
index b42346382f..ff4878aa13 100644
--- a/code/modules/mob/living/carbon/human/human_defense.dm
+++ b/code/modules/mob/living/carbon/human/human_defense.dm
@@ -27,7 +27,7 @@
for(var/bp in body_parts)
if(!bp)
continue
- if(bp && istype(bp , /obj/item/clothing))
+ if(istype(bp, /obj/item/clothing))
var/obj/item/clothing/C = bp
if(C.body_parts_covered & def_zone.body_part)
protection += C.armor.getRating(d_type)
@@ -654,6 +654,7 @@
if(health >= 0)
if(src == M)
+ var/to_send = ""
visible_message("[src] examines [p_them()]self.", \
"You check yourself for injuries.")
@@ -700,53 +701,55 @@
var/no_damage
if(status == "OK" || status == "no damage")
no_damage = TRUE
- to_chat(src, "\t Your [LB.name] [HAS_TRAIT(src, TRAIT_SELF_AWARE) ? "has" : "is"] [status].")
+ to_send += "\t Your [LB.name] [HAS_TRAIT(src, TRAIT_SELF_AWARE) ? "has" : "is"] [status].\n"
for(var/obj/item/I in LB.embedded_objects)
- to_chat(src, "\t There is \a [I] embedded in your [LB.name]!")
+ to_send += "\t There is \a [I] embedded in your [LB.name]!\n"
for(var/t in missing)
- to_chat(src, "Your [parse_zone(t)] is missing!")
+ to_send += "Your [parse_zone(t)] is missing!\n"
if(bleed_rate)
- to_chat(src, "You are bleeding!")
+ to_send += "You are bleeding!\n"
if(getStaminaLoss())
if(getStaminaLoss() > 30)
- to_chat(src, "You're completely exhausted.")
+ to_send += "You're completely exhausted.\n"
else
- to_chat(src, "You feel fatigued.")
+ to_send += "You feel fatigued.\n"
if(HAS_TRAIT(src, TRAIT_SELF_AWARE))
if(toxloss)
if(toxloss > 10)
- to_chat(src, "You feel sick.")
+ to_send += "You feel sick.\n"
else if(toxloss > 20)
- to_chat(src, "You feel nauseated.")
+ to_send += "You feel nauseated.\n"
else if(toxloss > 40)
- to_chat(src, "You feel very unwell!")
+ to_send += "You feel very unwell!\n"
if(oxyloss)
if(oxyloss > 10)
- to_chat(src, "You feel lightheaded.")
+ to_send += "You feel lightheaded.\n"
else if(oxyloss > 20)
- to_chat(src, "Your thinking is clouded and distant.")
+ to_send += "Your thinking is clouded and distant.\n"
else if(oxyloss > 30)
- to_chat(src, "You're choking!")
+ to_send += "You're choking!\n"
switch(nutrition)
if(NUTRITION_LEVEL_FULL to INFINITY)
- to_chat(src, "You're completely stuffed!")
+ to_send += "You're completely stuffed!\n"
if(NUTRITION_LEVEL_WELL_FED to NUTRITION_LEVEL_FULL)
- to_chat(src, "You're well fed!")
+ to_send += "You're well fed!\n"
if(NUTRITION_LEVEL_FED to NUTRITION_LEVEL_WELL_FED)
- to_chat(src, "You're not hungry.")
+ to_send += "You're not hungry.\n"
if(NUTRITION_LEVEL_HUNGRY to NUTRITION_LEVEL_FED)
- to_chat(src, "You could use a bite to eat.")
+ to_send += "You could use a bite to eat.\n"
if(NUTRITION_LEVEL_STARVING to NUTRITION_LEVEL_HUNGRY)
- to_chat(src, "You feel quite hungry.")
+ to_send += "You feel quite hungry.\n"
if(0 to NUTRITION_LEVEL_STARVING)
- to_chat(src, "You're starving!")
+ to_send += "You're starving!\n"
if(roundstart_quirks.len)
- to_chat(src, "You have these quirks: [get_trait_string()].")
+ to_send += "You have these quirks: [get_trait_string()].\n"
+
+ to_chat(src, to_send)
else
if(wear_suit)
wear_suit.add_fingerprint(M)
diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm
index c9d59b84f2..7a0a2d8ad8 100644
--- a/code/modules/mob/living/carbon/human/human_defines.dm
+++ b/code/modules/mob/living/carbon/human/human_defines.dm
@@ -31,6 +31,7 @@
var/socks = "Nude" //Which socks the player wants
var/socks_color = "#FFFFFF"
var/backbag = DBACKPACK //Which backpack type the player has chosen.
+ var/jumpsuit_style = PREF_SUIT //suit/skirt
//Equipment slots
var/obj/item/wear_suit = null
@@ -47,6 +48,7 @@
var/bleedsuppress = 0 //for stopping bloodloss, eventually this will be limb-based like bleeding
var/name_override //For temporary visible name changes
+ var/genital_override = FALSE //Force genitals on things incase of chems
var/nameless = FALSE //For drones of both the insectoid and robotic kind. And other types of nameless critters.
diff --git a/code/modules/mob/living/carbon/human/human_helpers.dm b/code/modules/mob/living/carbon/human/human_helpers.dm
index 0b40d3d26a..b65d62b63b 100644
--- a/code/modules/mob/living/carbon/human/human_helpers.dm
+++ b/code/modules/mob/living/carbon/human/human_helpers.dm
@@ -111,26 +111,6 @@
return ..()
-/mob/living/carbon/human/get_permeability_protection()
- var/list/prot = list("hands"=0, "chest"=0, "groin"=0, "legs"=0, "feet"=0, "arms"=0, "head"=0)
- for(var/obj/item/I in get_equipped_items())
- if(I.body_parts_covered & HANDS)
- prot["hands"] = max(1 - I.permeability_coefficient, prot["hands"])
- if(I.body_parts_covered & CHEST)
- prot["chest"] = max(1 - I.permeability_coefficient, prot["chest"])
- if(I.body_parts_covered & GROIN)
- prot["groin"] = max(1 - I.permeability_coefficient, prot["groin"])
- if(I.body_parts_covered & LEGS)
- prot["legs"] = max(1 - I.permeability_coefficient, prot["legs"])
- if(I.body_parts_covered & FEET)
- prot["feet"] = max(1 - I.permeability_coefficient, prot["feet"])
- if(I.body_parts_covered & ARMS)
- prot["arms"] = max(1 - I.permeability_coefficient, prot["arms"])
- if(I.body_parts_covered & HEAD)
- prot["head"] = max(1 - I.permeability_coefficient, prot["head"])
- var/protection = (prot["head"] + prot["arms"] + prot["feet"] + prot["legs"] + prot["groin"] + prot["chest"] + prot["hands"])/7
- return protection
-
/mob/living/carbon/human/can_use_guns(obj/item/G)
. = ..()
diff --git a/code/modules/mob/living/carbon/human/inventory.dm b/code/modules/mob/living/carbon/human/inventory.dm
index 176d967d52..d35df6b789 100644
--- a/code/modules/mob/living/carbon/human/inventory.dm
+++ b/code/modules/mob/living/carbon/human/inventory.dm
@@ -167,9 +167,9 @@
dropItemToGround(r_store, TRUE) //Again, makes sense for pockets to drop.
if(l_store)
dropItemToGround(l_store, TRUE)
- if(wear_id)
+ if(wear_id && !CHECK_BITFIELD(wear_id.item_flags, NO_UNIFORM_REQUIRED))
dropItemToGround(wear_id)
- if(belt)
+ if(belt && !CHECK_BITFIELD(belt.item_flags, NO_UNIFORM_REQUIRED))
dropItemToGround(belt)
w_uniform = null
update_suit_sensors()
diff --git a/code/modules/mob/living/carbon/human/say.dm b/code/modules/mob/living/carbon/human/say.dm
index 56be62c75e..eee425063d 100644
--- a/code/modules/mob/living/carbon/human/say.dm
+++ b/code/modules/mob/living/carbon/human/say.dm
@@ -53,14 +53,14 @@
if(ears)
var/obj/item/radio/headset/dongle = ears
if(!istype(dongle))
- return 0
+ return FALSE
if(dongle.translate_binary)
- return 1
+ return TRUE
/mob/living/carbon/human/radio(message, message_mode, list/spans, language)
. = ..()
- if(. != 0)
- return .
+ if(.)
+ return
switch(message_mode)
if(MODE_HEADSET)
diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm
index 76d8a10474..9abfc5826f 100644
--- a/code/modules/mob/living/carbon/human/species.dm
+++ b/code/modules/mob/living/carbon/human/species.dm
@@ -500,7 +500,7 @@ GLOBAL_LIST_EMPTY(roundstart_races)
if(B)
var/mutable_appearance/MA = mutable_appearance(B.icon, B.icon_state, -BODY_LAYER)
if(UNDIE_COLORABLE(B))
- MA.color = H.undie_color
+ MA.color = "#[H.undie_color]"
standing += MA
if(H.undershirt)
@@ -516,7 +516,7 @@ GLOBAL_LIST_EMPTY(roundstart_races)
else
MA = mutable_appearance(T.icon, T.icon_state, -BODY_LAYER)
if(UNDIE_COLORABLE(T))
- MA.color = H.shirt_color
+ MA.color = "#[H.shirt_color]"
standing += MA
if(H.socks && H.get_num_legs(FALSE) >= 2)
@@ -529,7 +529,7 @@ GLOBAL_LIST_EMPTY(roundstart_races)
var/digilegs = (DIGITIGRADE in species_traits) ? "_d" : ""
var/mutable_appearance/MA = mutable_appearance(S.icon, "[S.icon_state][digilegs]", -BODY_LAYER)
if(UNDIE_COLORABLE(S))
- MA.color = H.socks_color
+ MA.color = "[H.socks_color]"
standing += MA
if(standing.len)
@@ -1019,13 +1019,12 @@ GLOBAL_LIST_EMPTY(roundstart_races)
if(SLOT_BELT)
if(H.belt)
return FALSE
-
- var/obj/item/bodypart/O = H.get_bodypart(BODY_ZONE_CHEST)
-
- if(!H.w_uniform && !nojumpsuit && (!O || O.status != BODYPART_ROBOTIC))
- if(!disable_warning)
- to_chat(H, "You need a jumpsuit before you can attach this [I.name]!")
- return FALSE
+ if(!CHECK_BITFIELD(I.item_flags, NO_UNIFORM_REQUIRED))
+ var/obj/item/bodypart/O = H.get_bodypart(BODY_ZONE_CHEST)
+ if(!H.w_uniform && !nojumpsuit && (!O || O.status != BODYPART_ROBOTIC))
+ if(!disable_warning)
+ to_chat(H, "You need a jumpsuit before you can attach this [I.name]!")
+ return FALSE
if(!(I.slot_flags & ITEM_SLOT_BELT))
return
return equip_delay_self_check(I, H, bypass_equip_delay_self)
@@ -1062,12 +1061,12 @@ GLOBAL_LIST_EMPTY(roundstart_races)
if(SLOT_WEAR_ID)
if(H.wear_id)
return FALSE
-
- var/obj/item/bodypart/O = H.get_bodypart(BODY_ZONE_CHEST)
- if(!H.w_uniform && !nojumpsuit && (!O || O.status != BODYPART_ROBOTIC))
- if(!disable_warning)
- to_chat(H, "You need a jumpsuit before you can attach this [I.name]!")
- return FALSE
+ if(!CHECK_BITFIELD(I.item_flags, NO_UNIFORM_REQUIRED))
+ var/obj/item/bodypart/O = H.get_bodypart(BODY_ZONE_CHEST)
+ if(!H.w_uniform && !nojumpsuit && (!O || O.status != BODYPART_ROBOTIC))
+ if(!disable_warning)
+ to_chat(H, "You need a jumpsuit before you can attach this [I.name]!")
+ return FALSE
if( !(I.slot_flags & ITEM_SLOT_ID) )
return FALSE
return equip_delay_self_check(I, H, bypass_equip_delay_self)
@@ -1782,6 +1781,7 @@ GLOBAL_LIST_EMPTY(roundstart_races)
if(CLONE)
H.adjustCloneLoss(damage * hit_percent * H.physiology.clone_mod)
if(STAMINA)
+ H.stamdamageoverlaytemp = 20
if(BP)
if(damage > 0 ? BP.receive_damage(0, 0, damage * hit_percent * H.physiology.stamina_mod) : BP.heal_damage(0, 0, abs(damage * hit_percent * H.physiology.stamina_mod), only_robotic = FALSE, only_organic = FALSE))
H.update_stamina()
diff --git a/code/modules/mob/living/carbon/human/species_types/golems.dm b/code/modules/mob/living/carbon/human/species_types/golems.dm
index 2c663b4094..88dd59749c 100644
--- a/code/modules/mob/living/carbon/human/species_types/golems.dm
+++ b/code/modules/mob/living/carbon/human/species_types/golems.dm
@@ -420,7 +420,7 @@
H.visible_message("[H] teleports!", "You destabilize and teleport!")
new /obj/effect/particle_effect/sparks(get_turf(H))
playsound(get_turf(H), "sparks", 50, 1)
- do_teleport(H, get_turf(H), 6, asoundin = 'sound/weapons/emitter2.ogg')
+ do_teleport(H, get_turf(H), 6, asoundin = 'sound/weapons/emitter2.ogg', channel = TELEPORT_CHANNEL_BLUESPACE)
last_teleport = world.time
/datum/species/golem/bluespace/spec_hitby(atom/movable/AM, mob/living/carbon/human/H)
@@ -486,7 +486,7 @@
spark_system.set_up(10, 0, src)
spark_system.attach(H)
spark_system.start()
- do_teleport(H, get_turf(H), 12, asoundin = 'sound/weapons/emitter2.ogg')
+ do_teleport(H, get_turf(H), 12, asoundin = 'sound/weapons/emitter2.ogg', channel = TELEPORT_CHANNEL_BLUESPACE)
last_teleport = world.time
UpdateButtonIcon() //action icon looks unavailable
sleep(cooldown + 5)
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 2b487d4349..66586744fb 100644
--- a/code/modules/mob/living/carbon/human/species_types/jellypeople.dm
+++ b/code/modules/mob/living/carbon/human/species_types/jellypeople.dm
@@ -14,7 +14,8 @@
damage_overlay_type = ""
var/datum/action/innate/regenerate_limbs/regenerate_limbs
var/datum/action/innate/slime_change/slime_change //CIT CHANGE
- liked_food = MEAT
+ liked_food = TOXIC | MEAT
+ toxic_food = null
coldmod = 6 // = 3x cold damage
heatmod = 0.5 // = 1/4x heat damage
burnmod = 0.5 // = 1/2x generic burn damage
@@ -47,14 +48,14 @@
H.adjustBruteLoss(5)
to_chat(H, "You feel empty!")
- if(H.blood_volume < BLOOD_VOLUME_NORMAL)
+ if(H.blood_volume < (BLOOD_VOLUME_NORMAL * H.blood_ratio))
if(H.nutrition >= NUTRITION_LEVEL_STARVING)
H.blood_volume += 3
H.nutrition -= 2.5
- if(H.blood_volume < BLOOD_VOLUME_OKAY)
+ if(H.blood_volume < (BLOOD_VOLUME_OKAY*H.blood_ratio))
if(prob(5))
to_chat(H, "You feel drained!")
- if(H.blood_volume < BLOOD_VOLUME_BAD)
+ if(H.blood_volume < (BLOOD_VOLUME_BAD*H.blood_ratio))
Cannibalize_Body(H)
if(regenerate_limbs)
regenerate_limbs.UpdateButtonIcon()
@@ -86,7 +87,7 @@
var/list/limbs_to_heal = H.get_missing_limbs()
if(limbs_to_heal.len < 1)
return 0
- if(H.blood_volume >= BLOOD_VOLUME_OKAY+40)
+ if(H.blood_volume >= (BLOOD_VOLUME_OKAY*H.blood_ratio)+40)
return 1
return 0
@@ -97,13 +98,13 @@
to_chat(H, "You feel intact enough as it is.")
return
to_chat(H, "You focus intently on your missing [limbs_to_heal.len >= 2 ? "limbs" : "limb"]...")
- if(H.blood_volume >= 40*limbs_to_heal.len+BLOOD_VOLUME_OKAY)
+ if(H.blood_volume >= 40*limbs_to_heal.len+(BLOOD_VOLUME_OKAY*H.blood_ratio))
H.regenerate_limbs()
H.blood_volume -= 40*limbs_to_heal.len
to_chat(H, "...and after a moment you finish reforming!")
return
else if(H.blood_volume >= 40)//We can partially heal some limbs
- while(H.blood_volume >= BLOOD_VOLUME_OKAY+40)
+ while(H.blood_volume >= (BLOOD_VOLUME_OKAY*H.blood_ratio)+40)
var/healed_limb = pick(limbs_to_heal)
H.regenerate_limb(healed_limb)
limbs_to_heal -= healed_limb
@@ -137,7 +138,7 @@
bodies -= C // This means that the other bodies maintain a link
// so if someone mindswapped into them, they'd still be shared.
bodies = null
- C.blood_volume = min(C.blood_volume, BLOOD_VOLUME_NORMAL)
+ C.blood_volume = min(C.blood_volume, (BLOOD_VOLUME_NORMAL*C.blood_ratio))
..()
/datum/species/jelly/slime/on_species_gain(mob/living/carbon/C, datum/species/old_species)
@@ -728,4 +729,4 @@
to_chat(H, "You connect [target]'s mind to your slime link!")
else
to_chat(H, "You can't seem to link [target]'s mind...")
- to_chat(target, "The foreign presence leaves your mind.")
\ No newline at end of file
+ to_chat(target, "The foreign presence leaves your mind.")
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 11a25cea6c..754c48c3bd 100644
--- a/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm
+++ b/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm
@@ -174,6 +174,7 @@
item_flags = ABSTRACT | DROPDEL
w_class = WEIGHT_CLASS_HUGE
sharpness = IS_SHARP
+ total_mass = TOTAL_MASS_HAND_REPLACEMENT
/obj/item/light_eater/Initialize()
. = ..()
diff --git a/code/modules/mob/living/carbon/human/species_types/vampire.dm b/code/modules/mob/living/carbon/human/species_types/vampire.dm
index 4bc3d622ac..53c6f1bd0f 100644
--- a/code/modules/mob/living/carbon/human/species_types/vampire.dm
+++ b/code/modules/mob/living/carbon/human/species_types/vampire.dm
@@ -46,7 +46,7 @@
C.adjustCloneLoss(-4)
return
C.blood_volume -= 0.75
- if(C.blood_volume <= BLOOD_VOLUME_SURVIVE)
+ if(C.blood_volume <= (BLOOD_VOLUME_SURVIVE*C.blood_ratio))
to_chat(C, "You ran out of blood!")
C.dust()
var/area/A = get_area(C)
diff --git a/code/modules/mob/living/carbon/human/status_procs.dm b/code/modules/mob/living/carbon/human/status_procs.dm
index 5c20b0ce75..49121c9409 100644
--- a/code/modules/mob/living/carbon/human/status_procs.dm
+++ b/code/modules/mob/living/carbon/human/status_procs.dm
@@ -3,7 +3,7 @@
amount = dna.species.spec_stun(src,amount)
return ..()
-/mob/living/carbon/human/Knockdown(amount, updating = 1, ignore_canknockdown = 0)
+/mob/living/carbon/human/Knockdown(amount, updating = TRUE, ignore_canknockdown = FALSE, override_hardstun, override_stamdmg)
amount = dna.species.spec_stun(src,amount)
return ..()
diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm
index feb80e8d2c..72ff7e7a60 100644
--- a/code/modules/mob/living/carbon/human/update_icons.dm
+++ b/code/modules/mob/living/carbon/human/update_icons.dm
@@ -288,8 +288,10 @@ There are several things that need to be remembered:
S.alternate_worn_icon = 'modular_citadel/icons/mob/digishoes.dmi'
else
S.alternate_worn_icon = null
-
- overlays_standing[SHOES_LAYER] = shoes.build_worn_icon(state = shoes.icon_state, default_layer = SHOES_LAYER, default_icon_file = ((shoes.alternate_worn_icon) ? shoes.alternate_worn_icon : 'icons/mob/feet.dmi'))
+ var/t_state = shoes.item_state
+ if (!t_state)
+ t_state = shoes.icon_state
+ overlays_standing[SHOES_LAYER] = shoes.build_worn_icon(state = t_state, default_layer = SHOES_LAYER, default_icon_file = ((shoes.alternate_worn_icon) ? shoes.alternate_worn_icon : 'icons/mob/feet.dmi'))
var/mutable_appearance/shoes_overlay = overlays_standing[SHOES_LAYER]
if(OFFSET_SHOES in dna.species.offset_features)
shoes_overlay.pixel_x += dna.species.offset_features[OFFSET_SHOES][1]
@@ -377,13 +379,16 @@ There are several things that need to be remembered:
if(wear_suit)
var/obj/item/clothing/suit/S = wear_suit
+ var/no_taur_thanks = FALSE
+ if(!istype(S))
+ no_taur_thanks = TRUE
wear_suit.screen_loc = ui_oclothing
if(client && hud_used && hud_used.hud_shown)
if(hud_used.inventory_shown)
client.screen += wear_suit
update_observer_view(wear_suit,1)
- if(S.mutantrace_variation) //Just make sure we've got this checked too
+ if(!no_taur_thanks && S.mutantrace_variation) //Just make sure we've got this checked too
if(S.taurmode == NOT_TAURIC && S.adjusted == ALT_STYLE) //are we not a taur, but we have Digitigrade legs? Run this check first, then.
S.alternate_worn_icon = 'modular_citadel/icons/mob/suit_digi.dmi'
else
@@ -404,7 +409,7 @@ There are several things that need to be remembered:
if(OFFSET_SUIT in dna.species.offset_features)
suit_overlay.pixel_x += dna.species.offset_features[OFFSET_SUIT][1]
suit_overlay.pixel_y += dna.species.offset_features[OFFSET_SUIT][2]
- if(S.center)
+ if(!no_taur_thanks && S.center)
suit_overlay = center_image(suit_overlay, S.dimension_x, S.dimension_y)
overlays_standing[SUIT_LAYER] = suit_overlay
update_hair()
@@ -468,14 +473,6 @@ There are several things that need to be remembered:
overlays_standing[BACK_LAYER] = back_overlay
apply_overlay(BACK_LAYER)
-/mob/living/carbon/human/update_inv_legcuffed()
- remove_overlay(LEGCUFF_LAYER)
- clear_alert("legcuffed")
- if(legcuffed)
- overlays_standing[LEGCUFF_LAYER] = mutable_appearance('icons/mob/mob.dmi', "legcuff1", -LEGCUFF_LAYER)
- apply_overlay(LEGCUFF_LAYER)
- throw_alert("legcuffed", /obj/screen/alert/restrained/legcuffed, new_master = src.legcuffed)
-
/proc/wear_female_version(t_color, icon, layer, type)
var/index = t_color
var/icon/female_clothing_icon = GLOB.female_clothing_icons[index]
diff --git a/code/modules/mob/living/carbon/human/whisper.dm b/code/modules/mob/living/carbon/human/whisper.dm
index 65a4c5d33f..51c7ad9d25 100644
--- a/code/modules/mob/living/carbon/human/whisper.dm
+++ b/code/modules/mob/living/carbon/human/whisper.dm
@@ -88,4 +88,4 @@
AM.Hear(rendered, src, language, message, , spans)
if(critical) //Dying words.
- succumb(1)
+ succumb()
diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm
index 9dd55c361e..f0144e022d 100644
--- a/code/modules/mob/living/carbon/life.dm
+++ b/code/modules/mob/living/carbon/life.dm
@@ -4,8 +4,9 @@
if(notransform)
return
- if(damageoverlaytemp)
+ if(damageoverlaytemp || stamdamageoverlaytemp)
damageoverlaytemp = 0
+ stamdamageoverlaytemp = 0
update_damage_hud()
if(stat != DEAD) //Reagent processing needs to come before breathing, to prevent edge cases.
@@ -228,6 +229,9 @@
else if(SA_partialpressure > 0.01)
if(prob(20))
emote(pick("giggle","laugh"))
+ SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "chemical_euphoria", /datum/mood_event/chemical_euphoria)
+ else
+ SEND_SIGNAL(src, COMSIG_CLEAR_MOOD_EVENT, "chemical_euphoria")
//BZ (Facepunch port of their Agent B)
if(breath_gases[/datum/gas/bz])
@@ -304,11 +308,17 @@
return
/mob/living/carbon/proc/get_breath_from_internal(volume_needed)
+ var/obj/item/clothing/check
+ var/internals = FALSE
+
+ for(check in GET_INTERNAL_SLOTS(src))
+ if(CHECK_BITFIELD(check.clothing_flags, ALLOWINTERNALS))
+ internals = TRUE
if(internal)
if(internal.loc != src)
internal = null
update_internals_hud_icon(0)
- else if ((!wear_mask || !(wear_mask.clothing_flags & MASKINTERNALS)) && !getorganslot(ORGAN_SLOT_BREATHING_TUBE))
+ else if (!internals && !getorganslot(ORGAN_SLOT_BREATHING_TUBE))
internal = null
update_internals_hud_icon(0)
else
@@ -526,6 +536,9 @@ GLOBAL_LIST_INIT(ballmer_windows_me_msg, list("Yo man, what if, we like, uh, put
if(jitteriness)
do_jitter_animation(jitteriness)
jitteriness = max(jitteriness - restingpwr, 0)
+ SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "jittery", /datum/mood_event/jittery)
+ else
+ SEND_SIGNAL(src, COMSIG_CLEAR_MOOD_EVENT, "jittery")
if(stuttering)
stuttering = max(stuttering-1, 0)
@@ -611,6 +624,8 @@ GLOBAL_LIST_INIT(ballmer_windows_me_msg, list("Yo man, what if, we like, uh, put
if(drunkenness >= 101)
adjustToxLoss(4) //Let's be honest you shouldn't be alive by now
+ else
+ SEND_SIGNAL(src, COMSIG_CLEAR_MOOD_EVENT, "drunk")
//used in human and monkey handle_environment()
/mob/living/carbon/proc/natural_bodytemperature_stabilization()
diff --git a/code/modules/mob/living/carbon/monkey/monkey.dm b/code/modules/mob/living/carbon/monkey/monkey.dm
index f1a6b58cd1..f9c2e2dd3d 100644
--- a/code/modules/mob/living/carbon/monkey/monkey.dm
+++ b/code/modules/mob/living/carbon/monkey/monkey.dm
@@ -152,15 +152,6 @@
return threatcount
-/mob/living/carbon/monkey/get_permeability_protection()
- var/protection = 0
- if(head)
- protection = 1 - head.permeability_coefficient
- if(wear_mask)
- protection = max(1 - wear_mask.permeability_coefficient, protection)
- protection = protection/7 //the rest of the body isn't covered.
- return protection
-
/mob/living/carbon/monkey/IsVocal()
if(!getorganslot(ORGAN_SLOT_LUNGS))
return 0
diff --git a/code/modules/mob/living/carbon/monkey/update_icons.dm b/code/modules/mob/living/carbon/monkey/update_icons.dm
index 6311776596..e9bb9fc207 100644
--- a/code/modules/mob/living/carbon/monkey/update_icons.dm
+++ b/code/modules/mob/living/carbon/monkey/update_icons.dm
@@ -43,12 +43,15 @@
/mob/living/carbon/monkey/update_inv_legcuffed()
remove_overlay(LEGCUFF_LAYER)
+ clear_alert("legcuffed")
if(legcuffed)
- var/mutable_appearance/legcuff_overlay = mutable_appearance('icons/mob/mob.dmi', "legcuff1", -LEGCUFF_LAYER)
- legcuff_overlay.pixel_y = 8
- overlays_standing[LEGCUFF_LAYER] = legcuff_overlay
- apply_overlay(LEGCUFF_LAYER)
+ var/mutable_appearance/legcuffs = mutable_appearance('icons/mob/restraints.dmi', legcuffed.item_state, -LEGCUFF_LAYER)
+ legcuffs.color = handcuffed.color
+ legcuffs.pixel_y = 8
+ overlays_standing[HANDCUFF_LAYER] = legcuffs
+ apply_overlay(LEGCUFF_LAYER)
+ throw_alert("legcuffed", /obj/screen/alert/restrained/legcuffed, new_master = legcuffed)
//monkey HUD updates for items in our inventory
diff --git a/code/modules/mob/living/carbon/update_icons.dm b/code/modules/mob/living/carbon/update_icons.dm
index 87bf662c4f..5662f25993 100644
--- a/code/modules/mob/living/carbon/update_icons.dm
+++ b/code/modules/mob/living/carbon/update_icons.dm
@@ -176,9 +176,22 @@
/mob/living/carbon/update_inv_handcuffed()
remove_overlay(HANDCUFF_LAYER)
if(handcuffed)
- overlays_standing[HANDCUFF_LAYER] = mutable_appearance('icons/mob/mob.dmi', "handcuff1", -HANDCUFF_LAYER)
+ var/mutable_appearance/cuffs = mutable_appearance('icons/mob/restraints.dmi', handcuffed.item_state, -HANDCUFF_LAYER)
+ cuffs.color = handcuffed.color
+
+ overlays_standing[HANDCUFF_LAYER] = cuffs
apply_overlay(HANDCUFF_LAYER)
+/mob/living/carbon/update_inv_legcuffed()
+ remove_overlay(LEGCUFF_LAYER)
+ clear_alert("legcuffed")
+ if(legcuffed)
+ var/mutable_appearance/legcuffs = mutable_appearance('icons/mob/restraints.dmi', legcuffed.item_state, -LEGCUFF_LAYER)
+ legcuffs.color = legcuffed.color
+
+ overlays_standing[HANDCUFF_LAYER] = legcuffs
+ apply_overlay(LEGCUFF_LAYER)
+ throw_alert("legcuffed", /obj/screen/alert/restrained/legcuffed, new_master = legcuffed)
//mob HUD updates for items in our inventory
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index e052f754ed..9859290f5c 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -318,17 +318,27 @@
visible_message("[src] points at [A].", "You point at [A].")
return TRUE
-/mob/living/verb/succumb(whispered as null)
+/mob/living/verb/succumb()
set name = "Succumb"
set category = "IC"
+ if(src.has_status_effect(/datum/status_effect/chem/enthrall))
+ var/datum/status_effect/chem/enthrall/E = src.has_status_effect(/datum/status_effect/chem/enthrall)
+ if(E.phase < 3)
+ if(HAS_TRAIT(src, TRAIT_MINDSHIELD))
+ to_chat(src, "Your mindshield prevents your mind from giving in!")
+ else if(src.mind.assigned_role in GLOB.command_positions)
+ to_chat(src, "Your dedication to your department prevents you from giving in!")
+ else
+ E.enthrallTally += 20
+ to_chat(src, "You give into [E.master]'s influence.")
if (InCritical())
- log_message("Has [whispered ? "whispered his final words" : "succumbed to death"] while in [InFullCritical() ? "hard":"soft"] critical with [round(health, 0.1)] points of health!", LOG_ATTACK)
+ log_message("Has succumbed to death while in [InFullCritical() ? "hard":"soft"] critical with [round(health, 0.1)] points of health!", LOG_ATTACK)
adjustOxyLoss(health - HEALTH_THRESHOLD_DEAD)
updatehealth()
- if(!whispered)
- to_chat(src, "You have given up life and succumbed to death.")
+ to_chat(src, "You have given up life and succumbed to death.")
death()
+
/mob/living/incapacitated(ignore_restraints, ignore_grab)
if(stat || IsUnconscious() || IsStun() || IsKnockdown() || recoveringstam || (!ignore_restraints && restrained(ignore_grab))) // CIT CHANGE - adds recoveringstam check here
return TRUE
@@ -532,7 +542,7 @@
var/trail_type = getTrail()
if(trail_type)
var/brute_ratio = round(getBruteLoss() / maxHealth, 0.1)
- if(blood_volume && blood_volume > max(BLOOD_VOLUME_NORMAL*(1 - brute_ratio * 0.25), 0))//don't leave trail if blood volume below a threshold
+ if(blood_volume && blood_volume > max((BLOOD_VOLUME_NORMAL*blood_ratio)*(1 - brute_ratio * 0.25), 0))//don't leave trail if blood volume below a threshold
blood_volume = max(blood_volume - max(1, brute_ratio * 2), 0) //that depends on our brute damage.
var/newdir = get_dir(target_turf, start)
if(newdir != direction)
@@ -626,14 +636,15 @@
else if(canmove)
if(on_fire)
resist_fire() //stop, drop, and roll
- else if(resting) //cit change - allows resisting out of resting
+ return
+ if(resting) //cit change - allows resisting out of resting
resist_a_rest() // ditto
- else if(iscarbon(src)) //Citadel Change for embedded removal memes
- var/mob/living/carbon/C = src
- if(!C.handcuffed && !C.legcuffed)
- return TRUE
- else if(last_special <= world.time)
+ return
+ if(resist_embedded()) //Citadel Change for embedded removal memes
+ return
+ if(last_special <= world.time)
resist_restraints() //trying to remove cuffs.
+ return
/mob/proc/resist_grab(moving_resist)
@@ -813,7 +824,7 @@
return 1
//used in datum/reagents/reaction() proc
-/mob/living/proc/get_permeability_protection()
+/mob/living/proc/get_permeability_protection(list/target_zones)
return 0
/mob/living/proc/harvest(mob/living/user) //used for extra objects etc. in butchering
diff --git a/code/modules/mob/living/living_defines.dm b/code/modules/mob/living/living_defines.dm
index 3b0af53866..c24e6ab108 100644
--- a/code/modules/mob/living/living_defines.dm
+++ b/code/modules/mob/living/living_defines.dm
@@ -77,6 +77,7 @@
var/stun_absorption = null //converted to a list of stun absorption sources this mob has when one is added
var/blood_volume = 0 //how much blood the mob has
+ var/blood_ratio = 1 //How much blood the mob needs, in terms of ratio (i.e 1.2 will require BLOOD_VOLUME_NORMAL of 672) DO NOT GO ABOVE 3.55 Well, actually you can but, then they can't get enough blood.
var/obj/effect/proc_holder/ranged_ability //Any ranged ability the mob has, as a click override
var/see_override = 0 //0 for no override, sets see_invisible = see_override in silicon & carbon life process via update_sight()
diff --git a/code/modules/mob/living/say.dm b/code/modules/mob/living/say.dm
index 155ff15d5b..3b045b9eee 100644
--- a/code/modules/mob/living/say.dm
+++ b/code/modules/mob/living/say.dm
@@ -2,61 +2,61 @@ GLOBAL_LIST_INIT(department_radio_prefixes, list(":", "."))
GLOBAL_LIST_INIT(department_radio_keys, list(
// Location
- "r" = "right hand",
- "l" = "left hand",
- "i" = "intercom",
+ MODE_KEY_R_HAND = MODE_R_HAND,
+ MODE_KEY_L_HAND = MODE_L_HAND,
+ MODE_KEY_INTERCOM = MODE_INTERCOM,
// Department
- "h" = "department",
- "c" = "Command",
- "n" = "Science",
- "m" = "Medical",
- "e" = "Engineering",
- "s" = "Security",
- "u" = "Supply",
- "v" = "Service",
+ MODE_KEY_DEPARTMENT = MODE_DEPARTMENT,
+ RADIO_KEY_COMMAND = RADIO_CHANNEL_COMMAND,
+ RADIO_KEY_SCIENCE = RADIO_CHANNEL_SCIENCE,
+ RADIO_KEY_MEDICAL = RADIO_CHANNEL_MEDICAL,
+ RADIO_KEY_ENGINEERING = RADIO_CHANNEL_ENGINEERING,
+ RADIO_KEY_SECURITY = RADIO_CHANNEL_SECURITY,
+ RADIO_KEY_SUPPLY = RADIO_CHANNEL_SUPPLY,
+ RADIO_KEY_SERVICE = RADIO_CHANNEL_SERVICE,
// Faction
- "t" = "Syndicate",
- "y" = "CentCom",
+ RADIO_KEY_SYNDICATE = RADIO_CHANNEL_SYNDICATE,
+ RADIO_KEY_CENTCOM = RADIO_CHANNEL_CENTCOM,
// Admin
- "p" = "admin",
- "d" = "deadmin",
+ MODE_KEY_ADMIN = MODE_ADMIN,
+ MODE_KEY_DEADMIN = MODE_DEADMIN,
// Misc
- "o" = "AI Private", // AI Upload channel
- "x" = "cords", // vocal cords, used by Voice of God
+ RADIO_KEY_AI_PRIVATE = RADIO_CHANNEL_AI_PRIVATE, // AI Upload channel
+ MODE_KEY_VOCALCORDS = MODE_VOCALCORDS, // vocal cords, used by Voice of God
//kinda localization -- rastaf0
//same keys as above, but on russian keyboard layout. This file uses cp1251 as encoding.
// Location
- "ê" = "right hand",
- "ä" = "left hand",
- "ø" = "intercom",
+ "ê" = MODE_R_HAND,
+ "ä" = MODE_L_HAND,
+ "ø" = MODE_INTERCOM,
// Department
- "ð" = "department",
- "ñ" = "Command",
- "ò" = "Science",
- "ü" = "Medical",
- "ó" = "Engineering",
- "û" = "Security",
- "ã" = "Supply",
- "ì" = "Service",
+ "ð" = MODE_DEPARTMENT,
+ "ñ" = RADIO_CHANNEL_COMMAND,
+ "ò" = RADIO_CHANNEL_SCIENCE,
+ "ü" = RADIO_CHANNEL_MEDICAL,
+ "ó" = RADIO_CHANNEL_ENGINEERING,
+ "û" = RADIO_CHANNEL_SECURITY,
+ "ã" = RADIO_CHANNEL_SUPPLY,
+ "ì" = RADIO_CHANNEL_SERVICE,
// Faction
- "å" = "Syndicate",
- "í" = "CentCom",
+ "å" = RADIO_CHANNEL_SYNDICATE,
+ "í" = RADIO_CHANNEL_CENTCOM,
// Admin
- "ç" = "admin",
- "â" = "deadmin",
+ "ç" = MODE_ADMIN,
+ "â" = MODE_ADMIN,
// Misc
- "ù" = "AI Private",
- "÷" = "cords"
+ "ù" = RADIO_CHANNEL_AI_PRIVATE,
+ "÷" = MODE_VOCALCORDS
))
/mob/living/proc/Ellipsis(original_msg, chance = 50, keep_words)
@@ -105,12 +105,12 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
if(findtext(message, " ", 1, 2))
message = copytext(message, 2)
- if(message_mode == "admin")
+ if(message_mode == MODE_ADMIN)
if(client)
client.cmd_admin_say(message)
return
- if(message_mode == "deadmin")
+ if(message_mode == MODE_DEADMIN)
if(client)
client.dsay(message)
return
@@ -211,7 +211,7 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
send_speech(message, message_range, src, bubble_type, spans, language, message_mode)
if(succumbed)
- succumb(1)
+ succumb()
to_chat(src, compose_message(src, language, message, , spans, message_mode))
return 1
@@ -281,6 +281,7 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
AM.Hear(eavesrendered, src, message_language, eavesdropping, , spans, message_mode)
else
AM.Hear(rendered, src, message_language, message, , spans, message_mode)
+ SEND_GLOBAL_SIGNAL(COMSIG_GLOB_LIVING_SAY_SPECIAL, src, message)
//speech bubble
var/list/speech_bubble_recipients = list()
diff --git a/code/modules/mob/living/simple_animal/astral.dm b/code/modules/mob/living/simple_animal/astral.dm
new file mode 100644
index 0000000000..9bac53ef22
--- /dev/null
+++ b/code/modules/mob/living/simple_animal/astral.dm
@@ -0,0 +1,59 @@
+/mob/living/simple_animal/astral
+ name = "Astral projection"
+ desc = "A soul of someone projecting their mind."
+ icon = 'icons/mob/mob.dmi'
+ icon_state = "ghost"
+ icon_living = "ghost"
+ mob_biotypes = list(MOB_SPIRIT)
+ attacktext = "raises the hairs on the neck of"
+ response_harm = "disrupts the concentration of"
+ response_disarm = "wafts"
+ friendly = "communes with"
+ loot = null
+ maxHealth = 10
+ health = 10
+ melee_damage_lower = 0
+ melee_damage_upper = 0
+ obj_damage = 0
+ deathmessage = "disappears as if it was never really there to begin with"
+ incorporeal_move = 1
+ alpha = 50
+ attacktext = "touches the mind of"
+ speak_emote = list("echos")
+ movement_type = FLYING
+ var/pseudo_death = FALSE
+ var/posses_safe = FALSE
+ 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)
+ unsuitable_atmos_damage = 0
+ minbodytemp = 0
+ maxbodytemp = 100000
+
+/mob/living/simple_animal/astral/death()
+ icon_state = "shade_dead"
+ Stun(1000)
+ canmove = 0
+ friendly = "deads at"
+ pseudo_death = TRUE
+ incorporeal_move = 0
+ to_chat(src, "Your astral projection is interrupted and your mind is sent back to your body with a shock!")
+
+/mob/living/simple_animal/astral/ClickOn(var/atom/A, var/params)
+ ..()
+ if(pseudo_death == FALSE)
+ if(isliving(A))
+ if(ishuman(A))
+ var/mob/living/carbon/human/H = A
+ if(H.reagents.has_reagent("astral") && !H.mind)
+ var/datum/reagent/fermi/astral/As = locate(/datum/reagent/fermi/astral) in H.reagents.reagent_list
+ if(As.originalmind == src.mind && As.current_cycle < 10 && H.stat != DEAD) //So you can return to your body.
+ to_chat(src, "The intensity of the astrogen in your body is too much allow you to return to yourself yet!")
+ return
+ to_chat(src, "You astrally possess [H]!")
+ log_game("FERMICHEM: [src] has astrally possessed [A]!")
+ src.mind.transfer_to(H)
+ qdel(src)
+ var/message = html_decode(stripped_input(src, "Enter a message to send to [A]", MAX_MESSAGE_LEN))
+ if(!message)
+ return
+ to_chat(A, "[src] projects into your mind, \"[message]\"")
+ log_game("FERMICHEM: [src] has astrally transmitted [message] into [A]")
diff --git a/code/modules/mob/living/simple_animal/bot/bot.dm b/code/modules/mob/living/simple_animal/bot/bot.dm
index 163ba2163a..8bdeac91ed 100644
--- a/code/modules/mob/living/simple_animal/bot/bot.dm
+++ b/code/modules/mob/living/simple_animal/bot/bot.dm
@@ -61,7 +61,7 @@
var/mob/living/silicon/ai/calling_ai //Links a bot to the AI calling it.
var/obj/item/radio/Radio //The bot's radio, for speaking to people.
var/radio_key = null //which channels can the bot listen to
- var/radio_channel = "Common" //The bot's default radio channel
+ var/radio_channel = RADIO_CHANNEL_COMMON //The bot's default radio channel
var/auto_patrol = 0// set to make bot automatically patrol
var/turf/patrol_target // this is turf to navigate to (location of beacon)
var/turf/summon_target // The turf of a user summoning a bot.
diff --git a/code/modules/mob/living/simple_animal/bot/cleanbot.dm b/code/modules/mob/living/simple_animal/bot/cleanbot.dm
index bc8dd0c3ab..e09eb13886 100644
--- a/code/modules/mob/living/simple_animal/bot/cleanbot.dm
+++ b/code/modules/mob/living/simple_animal/bot/cleanbot.dm
@@ -9,7 +9,7 @@
health = 25
maxHealth = 25
radio_key = /obj/item/encryptionkey/headset_service
- radio_channel = "Service" //Service
+ radio_channel = RADIO_CHANNEL_SERVICE //Service
bot_type = CLEAN_BOT
model = "Cleanbot"
bot_core_type = /obj/machinery/bot_core/cleanbot
@@ -155,7 +155,7 @@
else
shuffle = TRUE //Shuffle the list the next time we scan so we dont both go the same way.
path = list()
-
+
if(!path || path.len == 0) //No path, need a new one
//Try to produce a path to the target, and ignore airlocks to which it has access.
path = get_path_to(src, target.loc, /turf/proc/Distance_cardinal, 0, 30, id=access_card)
diff --git a/code/modules/mob/living/simple_animal/bot/ed209bot.dm b/code/modules/mob/living/simple_animal/bot/ed209bot.dm
index 581711d271..0781c2907a 100644
--- a/code/modules/mob/living/simple_animal/bot/ed209bot.dm
+++ b/code/modules/mob/living/simple_animal/bot/ed209bot.dm
@@ -13,7 +13,7 @@
mob_size = MOB_SIZE_LARGE
radio_key = /obj/item/encryptionkey/headset_sec
- radio_channel = "Security"
+ radio_channel = RADIO_CHANNEL_SECURITY
bot_type = SEC_BOT
model = "ED-209"
bot_core = /obj/machinery/bot_core/secbot
diff --git a/code/modules/mob/living/simple_animal/bot/firebot.dm b/code/modules/mob/living/simple_animal/bot/firebot.dm
index d8c3bca72a..1c2a6393ae 100644
--- a/code/modules/mob/living/simple_animal/bot/firebot.dm
+++ b/code/modules/mob/living/simple_animal/bot/firebot.dm
@@ -16,7 +16,7 @@
spacewalk = TRUE
radio_key = /obj/item/encryptionkey/headset_eng
- radio_channel = "Engineering"
+ radio_channel = RADIO_CHANNEL_ENGINEERING
bot_type = FIRE_BOT
model = "Firebot"
bot_core = /obj/machinery/bot_core/firebot
diff --git a/code/modules/mob/living/simple_animal/bot/floorbot.dm b/code/modules/mob/living/simple_animal/bot/floorbot.dm
index 7e5cfe2110..4709680ad9 100644
--- a/code/modules/mob/living/simple_animal/bot/floorbot.dm
+++ b/code/modules/mob/living/simple_animal/bot/floorbot.dm
@@ -11,7 +11,7 @@
spacewalk = TRUE
radio_key = /obj/item/encryptionkey/headset_eng
- radio_channel = "Engineering"
+ radio_channel = RADIO_CHANNEL_ENGINEERING
bot_type = FLOOR_BOT
model = "Floorbot"
bot_core = /obj/machinery/bot_core/floorbot
diff --git a/code/modules/mob/living/simple_animal/bot/honkbot.dm b/code/modules/mob/living/simple_animal/bot/honkbot.dm
index d586cc694b..e069b46e9d 100644
--- a/code/modules/mob/living/simple_animal/bot/honkbot.dm
+++ b/code/modules/mob/living/simple_animal/bot/honkbot.dm
@@ -11,7 +11,6 @@
pass_flags = PASSMOB
radio_key = /obj/item/encryptionkey/headset_service //doesn't have security key
- radio_channel = "Service" //Doesn't even use the radio anyway.
bot_type = HONK_BOT
model = "Honkbot"
bot_core_type = /obj/machinery/bot_core/honkbot
diff --git a/code/modules/mob/living/simple_animal/bot/medbot.dm b/code/modules/mob/living/simple_animal/bot/medbot.dm
index 5a21d33d5a..5eaaaea175 100644
--- a/code/modules/mob/living/simple_animal/bot/medbot.dm
+++ b/code/modules/mob/living/simple_animal/bot/medbot.dm
@@ -17,7 +17,7 @@
status_flags = (CANPUSH | CANSTUN)
radio_key = /obj/item/encryptionkey/headset_med
- radio_channel = "Medical"
+ radio_channel = RADIO_CHANNEL_MEDICAL
bot_type = MED_BOT
model = "Medibot"
diff --git a/code/modules/mob/living/simple_animal/bot/mulebot.dm b/code/modules/mob/living/simple_animal/bot/mulebot.dm
index c45d435253..2efdf09f24 100644
--- a/code/modules/mob/living/simple_animal/bot/mulebot.dm
+++ b/code/modules/mob/living/simple_animal/bot/mulebot.dm
@@ -23,7 +23,7 @@
mob_size = MOB_SIZE_LARGE
radio_key = /obj/item/encryptionkey/headset_cargo
- radio_channel = "Supply"
+ radio_channel = RADIO_CHANNEL_SUPPLY
bot_type = MULE_BOT
model = "MULE"
diff --git a/code/modules/mob/living/simple_animal/bot/secbot.dm b/code/modules/mob/living/simple_animal/bot/secbot.dm
index fca1f66546..b6ef509d54 100644
--- a/code/modules/mob/living/simple_animal/bot/secbot.dm
+++ b/code/modules/mob/living/simple_animal/bot/secbot.dm
@@ -11,7 +11,7 @@
pass_flags = PASSMOB
radio_key = /obj/item/encryptionkey/secbot //AI Priv + Security
- radio_channel = "Security" //Security channel
+ radio_channel = RADIO_CHANNEL_SECURITY //Security channel
bot_type = SEC_BOT
model = "Securitron"
bot_core_type = /obj/machinery/bot_core/secbot
@@ -61,7 +61,7 @@
/mob/living/simple_animal/bot/secbot/pingsky
name = "Officer Pingsky"
desc = "It's Officer Pingsky! Delegated to satellite guard duty for harbouring anti-human sentiment."
- radio_channel = "AI Private"
+ radio_channel = RADIO_CHANNEL_AI_PRIVATE
/mob/living/simple_animal/bot/secbot/Initialize()
. = ..()
diff --git a/code/modules/mob/living/simple_animal/friendly/cat.dm b/code/modules/mob/living/simple_animal/friendly/cat.dm
index 5e5b486435..3a21a04bf9 100644
--- a/code/modules/mob/living/simple_animal/friendly/cat.dm
+++ b/code/modules/mob/living/simple_animal/friendly/cat.dm
@@ -292,3 +292,31 @@
if(L.a_intent == INTENT_HARM && L.reagents && !stat)
L.reagents.add_reagent("nutriment", 0.4)
L.reagents.add_reagent("vitamin", 0.4)
+
+//Cat made
+/mob/living/simple_animal/pet/cat/custom_cat
+ name = "White cat" //Incase it somehow gets spawned without an ID
+ desc = "A cute white catto!"
+ icon_state = "custom_cat"
+ icon_living = "custom_cat"
+ icon_dead = "custom_cat_dead"
+ gender = FEMALE
+ gold_core_spawnable = NO_SPAWN
+ health = 50 //So people can't instakill it s
+ maxHealth = 50
+ speak = list("Meowrowr!", "Mew!", "Miauen!")
+ speak_emote = list("wigglepurrs", "mewls")
+ emote_hear = list("meows.", "mews.")
+ emote_see = list("looks at you eagerly for pets!", "wiggles enthusiastically.")
+ gold_core_spawnable = NO_SPAWN
+ var/pseudo_death = FALSE
+
+/mob/living/simple_animal/pet/cat/custom_cat/death()
+ if (pseudo_death == TRUE) //secret cat chem
+ icon_state = "custom_cat_dead"
+ Stun(1000)
+ canmove = 0
+ friendly = "deads at"
+ return
+ else
+ ..()
diff --git a/code/modules/mob/living/simple_animal/friendly/drone/extra_drone_types.dm b/code/modules/mob/living/simple_animal/friendly/drone/extra_drone_types.dm
index 807c52ea46..23ac527b2e 100644
--- a/code/modules/mob/living/simple_animal/friendly/drone/extra_drone_types.dm
+++ b/code/modules/mob/living/simple_animal/friendly/drone/extra_drone_types.dm
@@ -222,7 +222,7 @@
if(.)
update_icons()
-/mob/living/simple_animal/drone/cogscarab/Knockdown(amount, updating = 1, ignore_canknockdown = 0)
+/mob/living/simple_animal/drone/cogscarab/Knockdown(amount, updating = TRUE, ignore_canknockdown = FALSE, override_hardstun, override_stamdmg)
. = ..()
if(.)
update_icons()
diff --git a/code/modules/mob/living/simple_animal/guardian/guardian.dm b/code/modules/mob/living/simple_animal/guardian/guardian.dm
index 21bbabbaa0..3fbc0b202b 100644
--- a/code/modules/mob/living/simple_animal/guardian/guardian.dm
+++ b/code/modules/mob/living/simple_animal/guardian/guardian.dm
@@ -43,7 +43,7 @@ GLOBAL_LIST_EMPTY(parasites) //all currently existing/living guardians
var/list/guardian_overlays[GUARDIAN_TOTAL_LAYERS]
var/reset = 0 //if the summoner has reset the guardian already
var/cooldown = 0
- var/mob/living/summoner
+ var/mob/living/carbon/summoner
var/range = 10 //how far from the user the spirit can be
var/toggle_button_type = /obj/screen/guardian/ToggleMode/Inactive //what sort of toggle button the hud uses
var/datum/guardianname/namedatum = new/datum/guardianname()
@@ -149,6 +149,9 @@ GLOBAL_LIST_EMPTY(parasites) //all currently existing/living guardians
death(TRUE)
qdel(src)
snapback()
+ if(HAS_TRAIT(summoner, TRAIT_NODEATH) && (istype(summoner.wear_neck, /obj/item/clothing/neck/necklace/memento_mori)))
+ REMOVE_TRAIT(summoner, TRAIT_NODEATH, "memento_mori")
+ to_chat(summoner,"You feel incredibly vulnerable as the memento mori pulls your life force in one too many directions!")
/mob/living/simple_animal/hostile/guardian/Stat()
..()
diff --git a/code/modules/mob/living/simple_animal/guardian/types/explosive.dm b/code/modules/mob/living/simple_animal/guardian/types/explosive.dm
index 8fb1de18df..ff2f453207 100644
--- a/code/modules/mob/living/simple_animal/guardian/types/explosive.dm
+++ b/code/modules/mob/living/simple_animal/guardian/types/explosive.dm
@@ -22,7 +22,7 @@
var/mob/living/M = target
if(!M.anchored && M != summoner && !hasmatchingsummoner(M))
new /obj/effect/temp_visual/guardian/phase/out(get_turf(M))
- do_teleport(M, M, 10)
+ do_teleport(M, M, 10, channel = TELEPORT_CHANNEL_BLUESPACE)
for(var/mob/living/L in range(1, M))
if(hasmatchingsummoner(L)) //if the summoner matches don't hurt them
continue
diff --git a/code/modules/mob/living/simple_animal/guardian/types/support.dm b/code/modules/mob/living/simple_animal/guardian/types/support.dm
index 8ef70e439f..794683e69f 100644
--- a/code/modules/mob/living/simple_animal/guardian/types/support.dm
+++ b/code/modules/mob/living/simple_animal/guardian/types/support.dm
@@ -142,5 +142,5 @@
L.flash_act()
A.visible_message("[A] disappears in a flash of light!", \
"Your vision is obscured by a flash of light!")
- do_teleport(A, beacon, 0)
+ do_teleport(A, beacon, 0, channel = TELEPORT_CHANNEL_BLUESPACE)
new /obj/effect/temp_visual/guardian/phase(get_turf(A))
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm
index 487e44966d..b43bf2bb51 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm
@@ -747,6 +747,12 @@ Difficulty: Very Hard
/obj/structure/closet/stasis/ex_act()
return
+/obj/structure/closet/stasis/handle_lock_addition()
+ return
+
+/obj/structure/closet/stasis/handle_lock_removal()
+ return
+
/obj/effect/proc_holder/spell/targeted/exit_possession
name = "Exit Possession"
desc = "Exits the body you are possessing."
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm
index 6577553a6a..cca39cfea6 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm
@@ -158,6 +158,8 @@ Difficulty: Normal
else
burst_range = 3
INVOKE_ASYNC(src, .proc/burst, get_turf(src), 0.25) //melee attacks on living mobs cause it to release a fast burst if on cooldown
+ if(L.stat == CONSCIOUS && L.health >= 30)
+ OpenFire()
else
devour(L)
else
@@ -426,6 +428,7 @@ Difficulty: Normal
/mob/living/simple_animal/hostile/megafauna/hierophant/proc/burst(turf/original, spread_speed = 0.5) //release a wave of blasts
playsound(original,'sound/machines/airlockopen.ogg', 200, 1)
var/last_dist = 0
+ var/list/hit_mobs = list() //don't hit people multiple times.
for(var/t in spiral_range_turfs(burst_range, original))
var/turf/T = t
if(!T)
@@ -434,7 +437,7 @@ Difficulty: Normal
if(dist > last_dist)
last_dist = dist
sleep(1 + min(burst_range - last_dist, 12) * spread_speed) //gets faster as it gets further out
- new /obj/effect/temp_visual/hierophant/blast(T, src, FALSE)
+ new /obj/effect/temp_visual/hierophant/blast(T, src, FALSE, hit_mobs)
/mob/living/simple_animal/hostile/megafauna/hierophant/AltClickOn(atom/A) //player control handler(don't give this to a player holy fuck)
if(!istype(A) || get_dist(A, src) <= 2)
@@ -591,8 +594,10 @@ Difficulty: Normal
var/friendly_fire_check = FALSE
var/bursting = FALSE //if we're bursting and need to hit anyone crossing us
-/obj/effect/temp_visual/hierophant/blast/Initialize(mapload, new_caster, friendly_fire)
+/obj/effect/temp_visual/hierophant/blast/Initialize(mapload, new_caster, friendly_fire, list/only_hit_once)
. = ..()
+ if(only_hit_once)
+ hit_things = only_hit_once
friendly_fire_check = friendly_fire
if(new_caster)
hit_things += new_caster
diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/bat.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/bat.dm
index 5cee4ef1b7..cc54ad3bef 100644
--- a/code/modules/mob/living/simple_animal/hostile/retaliate/bat.dm
+++ b/code/modules/mob/living/simple_animal/hostile/retaliate/bat.dm
@@ -38,3 +38,13 @@
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
+/mob/living/simple_animal/hostile/retaliate/bat/secbat
+ name = "Security Bat"
+ icon_state = "secbat"
+ icon_living = "secbat"
+ icon_dead = "secbat_dead"
+ icon_gib = "secbat_dead"
+ desc = "A fruit bat with a tiny little security hat who is ready to inject cuteness into any security operation."
+ emote_see = list("is ready to law down the law.", "flaps about with an air of authority.")
+ response_help = "respects the authority of"
+ gold_core_spawnable = FRIENDLY_SPAWN
diff --git a/code/modules/mob/living/simple_animal/hostile/zombie.dm b/code/modules/mob/living/simple_animal/hostile/zombie.dm
index 21c2d4804a..7d89941687 100644
--- a/code/modules/mob/living/simple_animal/hostile/zombie.dm
+++ b/code/modules/mob/living/simple_animal/hostile/zombie.dm
@@ -55,4 +55,28 @@
/mob/living/simple_animal/hostile/zombie/drop_loot()
. = ..()
corpse.forceMove(drop_location())
- corpse.create()
\ No newline at end of file
+ corpse.create()
+
+/mob/living/simple_animal/hostile/unemployedclone
+ name = "Failed clone"
+ desc = "Somebody failed chemistry."
+ icon = 'icons/mob/human.dmi'
+ icon_state = "husk"
+ icon_living = "husk"
+ icon_dead = "husk"
+ mob_biotypes = list(MOB_ORGANIC, MOB_HUMANOID)
+ speak_chance = 0
+ stat_attack = UNCONSCIOUS //braains
+ maxHealth = 100
+ health = 100
+ harm_intent_damage = 5
+ melee_damage_lower = 21
+ melee_damage_upper = 21
+ attacktext = "bites"
+ attack_sound = 'sound/hallucinations/growl1.ogg'
+ a_intent = INTENT_HARM
+ 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
+ spacewalk = FALSE
+ status_flags = CANPUSH
+ del_on_death = 0
diff --git a/code/modules/mob/living/simple_animal/parrot.dm b/code/modules/mob/living/simple_animal/parrot.dm
index 2397a6e8c1..228dc6a29b 100644
--- a/code/modules/mob/living/simple_animal/parrot.dm
+++ b/code/modules/mob/living/simple_animal/parrot.dm
@@ -241,23 +241,23 @@
clearlist(available_channels)
for(var/ch in headset_to_add.channels)
switch(ch)
- if("Engineering")
- available_channels.Add(":e")
- if("Command")
- available_channels.Add(":c")
- if("Security")
- available_channels.Add(":s")
- if("Science")
- available_channels.Add(":n")
- if("Medical")
- available_channels.Add(":m")
- if("Supply")
- available_channels.Add(":u")
- if("Service")
- available_channels.Add(":v")
+ if(RADIO_CHANNEL_ENGINEERING)
+ available_channels.Add(RADIO_TOKEN_ENGINEERING)
+ if(RADIO_CHANNEL_COMMAND)
+ available_channels.Add(RADIO_TOKEN_COMMAND)
+ if(RADIO_CHANNEL_SECURITY)
+ available_channels.Add(RADIO_TOKEN_SECURITY)
+ if(RADIO_CHANNEL_SCIENCE)
+ available_channels.Add(RADIO_TOKEN_SCIENCE)
+ if(RADIO_CHANNEL_MEDICAL)
+ available_channels.Add(RADIO_TOKEN_MEDICAL)
+ if(RADIO_CHANNEL_SUPPLY)
+ available_channels.Add(RADIO_TOKEN_SUPPLY)
+ if(RADIO_CHANNEL_SERVICE)
+ available_channels.Add(RADIO_TOKEN_SERVICE)
if(headset_to_add.translate_binary)
- available_channels.Add(":b")
+ available_channels.Add(MODE_TOKEN_BINARY)
else
return ..()
diff --git a/code/modules/mob/living/simple_animal/simple_animal_vr.dm b/code/modules/mob/living/simple_animal/simple_animal_vr.dm
index 4d808a11a9..666de9cef0 100644
--- a/code/modules/mob/living/simple_animal/simple_animal_vr.dm
+++ b/code/modules/mob/living/simple_animal/simple_animal_vr.dm
@@ -49,6 +49,8 @@
// Simple animals have only one belly. This creates it (if it isn't already set up)
/mob/living/simple_animal/init_vore()
vore_init = TRUE
+ if(CHECK_BITFIELD(flags_1, HOLOGRAM_1))
+ return
if(vore_organs.len)
return
if(no_vore) //If it can't vore, let's not give it a stomach.
@@ -105,6 +107,9 @@
var/mob/living/carbon/human/user = usr
if(!istype(user) || user.stat) return
+ if(!vore_active)
+ return
+
if(vore_selected.digest_mode == DM_HOLD)
var/confirm = alert(usr, "Enabling digestion on [name] will cause it to digest all stomach contents. Using this to break OOC prefs is against the rules. Digestion will disable itself after 20 minutes.", "Enabling [name]'s Digestion", "Enable", "Cancel")
if(confirm == "Enable")
diff --git a/code/modules/mob/living/status_procs.dm b/code/modules/mob/living/status_procs.dm
index 5006bd2920..0880f7f432 100644
--- a/code/modules/mob/living/status_procs.dm
+++ b/code/modules/mob/living/status_procs.dm
@@ -62,15 +62,15 @@
return K.duration - world.time
return 0
-/mob/living/proc/Knockdown(amount, updating = TRUE, ignore_canknockdown = FALSE) //Can't go below remaining duration
+/mob/living/proc/Knockdown(amount, updating = TRUE, ignore_canknockdown = FALSE, override_hardstun, override_stamdmg) //Can't go below remaining duration
if(((status_flags & CANKNOCKDOWN) && !HAS_TRAIT(src, TRAIT_STUNIMMUNE)) || ignore_canknockdown)
- if(absorb_stun(amount, ignore_canknockdown))
+ if(absorb_stun(isnull(override_hardstun)? amount : override_hardstun, ignore_canknockdown))
return
var/datum/status_effect/incapacitating/knockdown/K = IsKnockdown()
if(K)
- K.duration = max(world.time + amount, K.duration)
- else if(amount > 0)
- K = apply_status_effect(STATUS_EFFECT_KNOCKDOWN, amount, updating)
+ K.duration = max(world.time + (isnull(override_hardstun)? amount : override_hardstun), K.duration)
+ else if((amount || override_hardstun) > 0)
+ K = apply_status_effect(STATUS_EFFECT_KNOCKDOWN, amount, updating, override_hardstun, override_stamdmg)
return K
/mob/living/proc/SetKnockdown(amount, updating = TRUE, ignore_canknockdown = FALSE) //Sets remaining duration
diff --git a/code/modules/mob/living/taste.dm b/code/modules/mob/living/taste.dm
index fec024cebf..282fe0a716 100644
--- a/code/modules/mob/living/taste.dm
+++ b/code/modules/mob/living/taste.dm
@@ -32,4 +32,33 @@
last_taste_time = world.time
last_taste_text = text_output
+//FermiChem - How to check pH of a beaker without a meter/pH paper.
+//Basically checks the pH of the holder and burns your poor tongue if it's too acidic!
+//TRAIT_AGEUSIA players can't taste, unless it's burning them.
+//taking sips of a strongly acidic/alkaline substance will burn your tongue.
+/mob/living/carbon/taste(datum/reagents/from)
+ var/obj/item/organ/tongue/T = getorganslot("tongue")
+ if (!T)
+ return
+ .=..()
+ if ((from.pH > 12.5) || (from.pH < 1.5))
+ to_chat(src, "You taste chemical burns!")
+ T.adjustTongueLoss(src, 4)
+ if(istype(T, /obj/item/organ/tongue/cybernetic))
+ to_chat(src, "Your tongue moves on it's own in response to the liquid.")
+ say("The pH is appropriately [round(from.pH, 1)].")
+ return
+ if (!HAS_TRAIT(src, TRAIT_AGEUSIA)) //I'll let you get away with not having 1 damage.
+ switch(from.pH)
+ if(11.5 to INFINITY)
+ to_chat(src, "You taste a strong alkaline flavour!")
+ T.adjustTongueLoss(src, 1)
+ if(8.5 to 11.5)
+ to_chat(src, "You taste a sort of soapy tone in the mixture.")
+ if(2.5 to 5.5)
+ to_chat(src, "You taste a sort of acid tone in the mixture.")
+ if(-INFINITY to 2.5)
+ to_chat(src, "You taste a strong acidic flavour!")
+ T.adjustTongueLoss(src, 1)
+
#undef DEFAULT_TASTE_SENSITIVITY
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index 7667d9bbff..0be778681c 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -116,19 +116,23 @@
// vision_distance (optional) define how many tiles away the message can be seen.
// ignored_mob (optional) doesn't show any message to a given mob if TRUE.
-/atom/proc/visible_message(message, self_message, blind_message, vision_distance, ignored_mob)
+/atom/proc/visible_message(message, self_message, blind_message, vision_distance, list/ignored_mobs, no_ghosts = FALSE)
var/turf/T = get_turf(src)
if(!T)
return
+ if(!islist(ignored_mobs))
+ ignored_mobs = list(ignored_mobs)
var/range = 7
if(vision_distance)
range = vision_distance
for(var/mob/M in get_hearers_in_view(range, src))
if(!M.client)
continue
- if(M == ignored_mob)
+ if(M in ignored_mobs)
continue
var/msg = message
+ if(isobserver(M) && no_ghosts)
+ continue
if(M == src) //the src always see the main message or self message
if(self_message)
msg = self_message
@@ -155,7 +159,7 @@
// deaf_message (optional) is what deaf people will see.
// hearing_distance (optional) is the range, how many tiles away the message can be heard.
-/mob/audible_message(message, deaf_message, hearing_distance, self_message)
+/mob/audible_message(message, deaf_message, hearing_distance, self_message, no_ghosts = FALSE)
var/range = 7
if(hearing_distance)
range = hearing_distance
@@ -163,6 +167,8 @@
var/msg = message
if(self_message && M==src)
msg = self_message
+ if(no_ghosts && isobserver(M))
+ continue
M.show_message( msg, 2, deaf_message, 1)
// Show a message to all mobs in earshot of this atom
@@ -171,11 +177,13 @@
// deaf_message (optional) is what deaf people will see.
// hearing_distance (optional) is the range, how many tiles away the message can be heard.
-/atom/proc/audible_message(message, deaf_message, hearing_distance)
+/atom/proc/audible_message(message, deaf_message, hearing_distance, no_ghosts = FALSE)
var/range = 7
if(hearing_distance)
range = hearing_distance
for(var/mob/M in get_hearers_in_view(range, src))
+ if(no_ghosts && isobserver(M))
+ continue
M.show_message( message, 2, deaf_message, 1)
/mob/proc/Life()
diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm
index a0126f5fdd..0cb886f11b 100644
--- a/code/modules/mob/mob_defines.dm
+++ b/code/modules/mob/mob_defines.dm
@@ -65,6 +65,7 @@
var/active_hand_index = 1
var/list/held_items = list() //len = number of hands, eg: 2 nulls is 2 empty hands, 1 item and 1 null is 1 full hand and 1 empty hand.
//held_items[active_hand_index] is the actively held item, but please use get_active_held_item() instead, because OOP
+ var/bloody_hands = 0
var/datum/component/storage/active_storage = null//Carbon
diff --git a/code/modules/mob/say_vr.dm b/code/modules/mob/say_vr.dm
index 66444abf91..1fc97c31e4 100644
--- a/code/modules/mob/say_vr.dm
+++ b/code/modules/mob/say_vr.dm
@@ -172,15 +172,11 @@ proc/get_top_level_mob(var/mob/S)
user.log_message(message, INDIVIDUAL_EMOTE_LOG)
message = "[user] " + "[message]"
- for(var/mob/M)
- if(M in list(/mob/living))
- M.show_message(message)
-
if(emote_type == EMOTE_AUDIBLE)
- user.audible_message(message=message,hearing_distance=1)
+ user.audible_message(message=message,hearing_distance=1, no_ghosts = TRUE)
else
- user.visible_message(message=message,self_message=message,vision_distance=1)
- log_emote("[key_name(user)] : [message]")
+ user.visible_message(message=message,self_message=message,vision_distance=1, no_ghosts = TRUE)
+ log_emote("[key_name(user)] : (SUBTLER) [message]")
message = null
diff --git a/code/modules/ninja/suit/n_suit_verbs/ninja_stealth.dm b/code/modules/ninja/suit/n_suit_verbs/ninja_stealth.dm
index 1c3fbd8147..94be922fdf 100644
--- a/code/modules/ninja/suit/n_suit_verbs/ninja_stealth.dm
+++ b/code/modules/ninja/suit/n_suit_verbs/ninja_stealth.dm
@@ -8,33 +8,37 @@ Contents:
/obj/item/clothing/suit/space/space_ninja/proc/toggle_stealth()
- var/mob/living/carbon/human/U = affecting
- if(!U)
+ if(!affecting)
return
if(stealth)
cancel_stealth()
else
if(cell.charge <= 0)
- to_chat(U, "You don't have enough power to enable Stealth!")
+ to_chat(affecting, "You don't have enough power to enable Stealth!")
return
stealth = !stealth
- animate(U, alpha = 50,time = 15)
- U.visible_message("[U.name] vanishes into thin air!", \
+ animate(affecting, alpha = 10,time = 15)
+ affecting.visible_message("[affecting.name] vanishes into thin air!", \
"You are now mostly invisible to normal detection.")
+ RegisterSignal(affecting, list(COMSIG_MOB_ITEM_ATTACK, COMSIG_MOB_ATTACK_RANGED, COMSIG_MOB_ATTACK_HAND, COMSIG_MOB_THROW, COMSIG_PARENT_ATTACKBY), .proc/reduce_stealth)
+ RegisterSignal(affecting, COMSIG_MOVABLE_BUMP, .proc/bumping_stealth)
+/obj/item/clothing/suit/space/space_ninja/proc/reduce_stealth()
+ affecting.alpha = min(affecting.alpha + 30, 80)
+
+/obj/item/clothing/suit/space/space_ninja/proc/bumping_stealth(datum/source, atom/A)
+ if(isliving(A))
+ affecting.alpha = min(affecting.alpha + 15, 80)
/obj/item/clothing/suit/space/space_ninja/proc/cancel_stealth()
- var/mob/living/carbon/human/U = affecting
- if(!U)
- return 0
- if(stealth)
- stealth = !stealth
- animate(U, alpha = 255, time = 15)
- U.visible_message("[U.name] appears from thin air!", \
- "You are now visible.")
- return 1
- return 0
-
+ if(!affecting || !stealth)
+ return FALSE
+ stealth = !stealth
+ UnregisterSignal(affecting, list(COMSIG_MOB_ITEM_ATTACK, COMSIG_MOB_ATTACK_RANGED, COMSIG_MOB_ATTACK_HAND, COMSIG_MOB_THROW, COMSIG_PARENT_ATTACKBY, COMSIG_MOVABLE_BUMP))
+ animate(affecting, alpha = 255, time = 15)
+ affecting.visible_message("[affecting.name] appears from thin air!", \
+ "You are now visible.")
+ return TRUE
/obj/item/clothing/suit/space/space_ninja/proc/stealth()
if(!s_busy)
diff --git a/code/modules/ninja/suit/shoes.dm b/code/modules/ninja/suit/shoes.dm
index 1b935a00de..115b14b63b 100644
--- a/code/modules/ninja/suit/shoes.dm
+++ b/code/modules/ninja/suit/shoes.dm
@@ -1,4 +1,3 @@
-
/obj/item/clothing/shoes/space_ninja
name = "ninja shoes"
desc = "A pair of running shoes. Excellent for running and even better for smashing skulls."
@@ -13,3 +12,12 @@
min_cold_protection_temperature = SHOES_MIN_TEMP_PROTECT
heat_protection = FEET
max_heat_protection_temperature = SHOES_MAX_TEMP_PROTECT
+
+/obj/item/clothing/shoes/space_ninja/equipped(mob/user, slot)
+ . = ..()
+ if(slot == SLOT_SHOES)
+ ADD_TRAIT(user, TRAIT_SILENT_STEP, "ninja_shoes_[REF(src)]")
+
+/obj/item/clothing/shoes/space_ninja/dropped(mob/user)
+ . = ..()
+ REMOVE_TRAIT(user, TRAIT_SILENT_STEP, "ninja_shoes_[REF(src)]")
diff --git a/code/modules/ninja/suit/suit.dm b/code/modules/ninja/suit/suit.dm
index b98ef764c0..ac1ef3b96a 100644
--- a/code/modules/ninja/suit/suit.dm
+++ b/code/modules/ninja/suit/suit.dm
@@ -149,12 +149,11 @@ Contents:
/obj/item/clothing/suit/space/space_ninja/examine(mob/user)
..()
- if(s_initialized)
- if(user == affecting)
- to_chat(user, "All systems operational. Current energy capacity: [DisplayEnergy(cell.charge)].")
- to_chat(user, "The CLOAK-tech device is [stealth?"active":"inactive"].")
- to_chat(user, "There are [s_bombs] smoke bomb\s remaining.")
- to_chat(user, "There are [a_boost] adrenaline booster\s remaining.")
+ if(s_initialized && user == affecting)
+ to_chat(user, "All systems operational. Current energy capacity: [DisplayEnergy(cell.charge)].\n\
+ The CLOAK-tech device is [stealth?"active":"inactive"].\n\
+ There are [s_bombs] smoke bomb\s remaining.\n\
+ There are [a_boost] adrenaline booster\s remaining.")
/obj/item/clothing/suit/space/space_ninja/ui_action_click(mob/user, action)
if(istype(action, /datum/action/item_action/initialize_ninja_suit))
diff --git a/code/modules/ninja/suit/suit_initialisation.dm b/code/modules/ninja/suit/suit_initialisation.dm
index 4b159557bc..3d80282fe7 100644
--- a/code/modules/ninja/suit/suit_initialisation.dm
+++ b/code/modules/ninja/suit/suit_initialisation.dm
@@ -48,7 +48,7 @@
/obj/item/clothing/suit/space/space_ninja/proc/ninitialize_seven(delay, mob/living/carbon/human/U)
to_chat(U, "All systems operational. Welcome to SpiderOS, [U.real_name].")
s_initialized = TRUE
- ntick()
+ START_PROCESSING(SSprocessing, src)
s_busy = FALSE
@@ -91,4 +91,5 @@
unlock_suit()
U.regenerate_icons()
s_initialized = FALSE
+ STOP_PROCESSING(SSprocessing, src)
s_busy = FALSE
diff --git a/code/modules/ninja/suit/suit_process.dm b/code/modules/ninja/suit/suit_process.dm
index 4a89a59f75..850fb837b4 100644
--- a/code/modules/ninja/suit/suit_process.dm
+++ b/code/modules/ninja/suit/suit_process.dm
@@ -1,20 +1,17 @@
-/obj/item/clothing/suit/space/space_ninja/proc/ntick(mob/living/carbon/human/U = affecting)
- //Runs in the background while the suit is initialized.
- //Requires charge or stealth to process.
- spawn while(s_initialized)
- if(!affecting)
- terminate()//Kills the suit and attached objects.
+/obj/item/clothing/suit/space/space_ninja/process()
+ if(!affecting || !s_initialized)
+ return PROCESS_KILL
- else if(cell.charge > 0)
- if(s_coold)
- s_coold--//Checks for ability s_cooldown first.
+ if(cell.charge > 0)
+ if(s_coold)
+ s_coold--//Checks for ability s_cooldown first.
- cell.charge -= s_cost//s_cost is the default energy cost each ntick, usually 5.
- if(stealth)//If stealth is active.
- cell.charge -= s_acost
+ cell.charge -= s_cost//s_cost is the default energy cost each tick, usually 5.
+ if(stealth)//If stealth is active.
+ cell.charge -= s_acost
+ affecting.alpha = max(affecting.alpha - 10, 10)
- else
- cell.charge = 0
+ else
+ cell.charge = 0
+ if(stealth)
cancel_stealth()
-
- sleep(10)//Checks every second.
diff --git a/code/modules/photography/photos/frame.dm b/code/modules/photography/photos/frame.dm
index f379541b9c..6469a1091b 100644
--- a/code/modules/photography/photos/frame.dm
+++ b/code/modules/photography/photos/frame.dm
@@ -46,7 +46,7 @@
/obj/item/wallframe/picture/update_icon()
cut_overlays()
if(displayed)
- add_overlay(getFlatIcon(displayed))
+ add_overlay(image(displayed))
/obj/item/wallframe/picture/after_attach(obj/O)
..()
@@ -148,7 +148,7 @@
/obj/structure/sign/picture_frame/update_icon()
cut_overlays()
if(framed)
- add_overlay(getFlatIcon(framed))
+ add_overlay(image(framed))
/obj/structure/sign/picture_frame/deconstruct(disassembled = TRUE)
if(!(flags_1 & NODECONSTRUCT_1))
diff --git a/code/modules/projectiles/ammunition/caseless/rocket.dm b/code/modules/projectiles/ammunition/caseless/rocket.dm
index 9d6befce53..bc693d96bc 100644
--- a/code/modules/projectiles/ammunition/caseless/rocket.dm
+++ b/code/modules/projectiles/ammunition/caseless/rocket.dm
@@ -9,7 +9,7 @@
name = "\improper PM-9HEDP"
desc = "An 84mm High Explosive Dual Purpose rocket. Pointy end toward mechs."
caliber = "84mm"
- icon_state = "s-casing-live"
+ icon_state = "84mm-hedp"
projectile_type = /obj/item/projectile/bullet/a84mm
/obj/item/ammo_casing/caseless/a75
diff --git a/code/modules/projectiles/ammunition/energy/special.dm b/code/modules/projectiles/ammunition/energy/special.dm
index 0879506036..7b4e0bfa97 100644
--- a/code/modules/projectiles/ammunition/energy/special.dm
+++ b/code/modules/projectiles/ammunition/energy/special.dm
@@ -62,3 +62,8 @@
e_cost = 200
select_name = "stun"
projectile_type = /obj/item/projectile/energy/tesla/revolver
+
+/obj/item/ammo_casing/energy/emitter
+ fire_sound = 'sound/weapons/emitter.ogg'
+ e_cost = 2000 //20,000 is in the cell making this 10 shots before reload
+ projectile_type = /obj/item/projectile/beam/emitter
diff --git a/code/modules/projectiles/boxes_magazines/internal/grenade.dm b/code/modules/projectiles/boxes_magazines/internal/grenade.dm
index 352d1eb951..79a005ee8a 100644
--- a/code/modules/projectiles/boxes_magazines/internal/grenade.dm
+++ b/code/modules/projectiles/boxes_magazines/internal/grenade.dm
@@ -11,7 +11,7 @@
max_ammo = 1
/obj/item/ammo_box/magazine/internal/rocketlauncher
- name = "grenade launcher internal magazine"
+ name = "rocket launcher internal magazine"
ammo_type = /obj/item/ammo_casing/caseless/rocket
caliber = "84mm"
max_ammo = 1
diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm
index 98fd774d63..fb3ed19f82 100644
--- a/code/modules/projectiles/gun.dm
+++ b/code/modules/projectiles/gun.dm
@@ -32,9 +32,10 @@
var/fire_delay = 0 //rate of fire for burst firing and semi auto
var/firing_burst = 0 //Prevent the weapon from firing again while already firing
var/semicd = 0 //cooldown handler
- var/weapon_weight = WEAPON_LIGHT
+ var/weapon_weight = WEAPON_LIGHT //currently only used for inaccuracy
var/spread = 0 //Spread induced by the gun itself.
var/randomspread = 1 //Set to 0 for shotguns. This is used for weapons that don't fire all their bullets at once.
+ var/inaccuracy_modifier = 1
lefthand_file = 'icons/mob/inhands/weapons/guns_lefthand.dmi'
righthand_file = 'icons/mob/inhands/weapons/guns_righthand.dmi'
@@ -538,3 +539,13 @@
if(A == chambered)
chambered = null
update_icon()
+
+/obj/item/gun/proc/getinaccuracy(mob/living/user)
+ if(!iscarbon(user))
+ return FALSE
+ else
+ var/mob/living/carbon/holdingdude = user
+ if(istype(holdingdude) && holdingdude.combatmode)
+ return (max((holdingdude.lastdirchange + weapon_weight * 25) - world.time,0) * inaccuracy_modifier)
+ else
+ return ((weapon_weight * 25) * inaccuracy_modifier)
diff --git a/code/modules/projectiles/guns/ballistic/launchers.dm b/code/modules/projectiles/guns/ballistic/launchers.dm
index eea4e1bc0b..f6356dce99 100644
--- a/code/modules/projectiles/guns/ballistic/launchers.dm
+++ b/code/modules/projectiles/guns/ballistic/launchers.dm
@@ -86,6 +86,7 @@
pin = /obj/item/firing_pin/implant/pindicate
burst_size = 1
fire_delay = 0
+ inaccuracy_modifier = 0.7
casing_ejector = FALSE
weapon_weight = WEAPON_HEAVY
magazine_wording = "rocket"
@@ -108,34 +109,34 @@
/obj/item/gun/ballistic/rocketlauncher/can_shoot()
return chambered?.BB
-/obj/item/gun/ballistic/rocketlauncher/process_chamber()
- if(chambered)
- chambered = null
- if(magazine)
- QDEL_NULL(magazine)
- update_icon()
-
/obj/item/gun/ballistic/rocketlauncher/attack_self_tk(mob/user)
return //too difficult to remove the rocket with TK
/obj/item/gun/ballistic/rocketlauncher/attack_self(mob/living/user)
if(magazine)
- if(chambered)
- chambered.forceMove(magazine)
- magazine.stored_ammo.Insert(1, chambered)
+ var/obj/item/ammo_casing/AC = chambered
+ if(AC)
+ if(!user.put_in_hands(AC))
+ AC.bounce_away(FALSE, NONE)
+ to_chat(user, "You remove \the [AC] from \the [src]!")
+ playsound(src, 'sound/weapons/gun_magazine_remove_full.ogg', 70, TRUE)
chambered = null
else
- stack_trace("Removed [magazine] from [src] without a chambered round")
- magazine.forceMove(drop_location())
- if(user.is_holding(src))
- user.put_in_hands(magazine)
- playsound(src, 'sound/weapons/gun_magazine_remove_full.ogg', 70, TRUE)
- to_chat(user, "You work the [magazine] out from [src].")
- magazine = null
- else
- to_chat(user, "There's no rocket in [src].")
+ to_chat(user, "There's no [magazine_wording] in [src].")
update_icon()
+/obj/item/gun/ballistic/rocketlauncher/attackby(obj/item/A, mob/user, params)
+ if(magazine && istype(A, /obj/item/ammo_casing))
+ if(user.temporarilyRemoveItemFromInventory(A))
+ if(!chambered)
+ to_chat(user, "You load a new [A] into \the [src].")
+ playsound(src, "gun_insert_full_magazine", 70, 1)
+ chamber_round()
+ update_icon()
+ return TRUE
+ else
+ to_chat(user, "You cannot seem to get \the [A] out of your hands!")
+
/obj/item/gun/ballistic/rocketlauncher/update_icon()
icon_state = "[initial(icon_state)]-[chambered ? "1" : "0"]"
diff --git a/code/modules/projectiles/guns/ballistic/shotgun.dm b/code/modules/projectiles/guns/ballistic/shotgun.dm
index bb6a144c93..856dfed78b 100644
--- a/code/modules/projectiles/guns/ballistic/shotgun.dm
+++ b/code/modules/projectiles/guns/ballistic/shotgun.dm
@@ -212,14 +212,41 @@
)
/obj/item/gun/ballistic/shotgun/automatic/combat/compact
- name = "compact combat shotgun"
- desc = "A compact version of the semi automatic combat shotgun. For close encounters."
+ name = "warden's combat shotgun"
+ desc = "A modified version of the semi automatic combat shotgun with a collapsible stock. For close encounters."
icon_state = "cshotgunc"
- mag_type = /obj/item/ammo_box/magazine/internal/shot/com/compact
+ mag_type = /obj/item/ammo_box/magazine/internal/shot/com
w_class = WEIGHT_CLASS_NORMAL
- unique_reskin = list("Tatical" = "cshotgunc",
- "Slick" = "cshotgunc_slick"
- )
+ var/stock = FALSE
+ recoil = 5
+ spread = 2
+
+/obj/item/gun/ballistic/shotgun/automatic/combat/compact/AltClick(mob/living/user)
+ if(!istype(user) || !user.canUseTopic(src, BE_CLOSE, ismonkey(user)))
+ return
+ toggle_stock(user)
+ . = ..()
+
+/obj/item/gun/ballistic/shotgun/automatic/combat/compact/examine(mob/user)
+ ..()
+ to_chat(user, "Alt-click to toggle the stock.")
+
+/obj/item/gun/ballistic/shotgun/automatic/combat/compact/proc/toggle_stock(mob/living/user)
+ stock = !stock
+ if(stock)
+ w_class = WEIGHT_CLASS_HUGE
+ to_chat(user, "You unfold the stock.")
+ recoil = 1
+ spread = 0
+ else
+ w_class = WEIGHT_CLASS_NORMAL
+ to_chat(user, "You fold the stock.")
+ recoil = 5
+ spread = 2
+ update_icon()
+
+/obj/item/gun/ballistic/shotgun/automatic/combat/compact/update_icon()
+ icon_state = "[current_skin ? unique_reskin[current_skin] : "cshotgun"][stock ? "" : "c"]"
//Dual Feed Shotgun
@@ -235,6 +262,7 @@
/obj/item/gun/ballistic/shotgun/automatic/dual_tube/examine(mob/user)
..()
to_chat(user, "Alt-click to pump it.")
+ . = ..()
/obj/item/gun/ballistic/shotgun/automatic/dual_tube/Initialize()
. = ..()
diff --git a/code/modules/projectiles/guns/energy/special.dm b/code/modules/projectiles/guns/energy/special.dm
index 6e2c9dc62a..87bfd578bc 100644
--- a/code/modules/projectiles/guns/energy/special.dm
+++ b/code/modules/projectiles/guns/energy/special.dm
@@ -304,3 +304,22 @@
/obj/item/gun/energy/gravity_gun/security
pin = /obj/item/firing_pin
+
+//Emitter Gun
+
+/obj/item/gun/energy/emitter
+ name = "Emitter Carbine"
+ desc = "A small emitter fitted into a handgun case, do to size constraints and safety it can only shoot about ten times when fully charged."
+ icon_state = "emitter_carbine"
+ force = 12
+ w_class = WEIGHT_CLASS_SMALL
+ cell_type = /obj/item/stock_parts/cell/super
+ ammo_type = list(/obj/item/ammo_casing/energy/emitter)
+
+/obj/item/gun/energy/emitter/update_icon()
+ ..()
+ var/obj/item/ammo_casing/energy/shot = ammo_type[select]
+ if(!QDELETED(cell) && (cell.charge > shot.e_cost))
+ add_overlay("emitter_carbine_empty")
+ else
+ add_overlay("emitter_carbine")
diff --git a/code/modules/projectiles/guns/magic/wand.dm b/code/modules/projectiles/guns/magic/wand.dm
index e3724fdf31..42033d8c88 100644
--- a/code/modules/projectiles/guns/magic/wand.dm
+++ b/code/modules/projectiles/guns/magic/wand.dm
@@ -131,7 +131,7 @@
no_den_usage = 1
/obj/item/gun/magic/wand/teleport/zap_self(mob/living/user)
- if(do_teleport(user, user, 10))
+ if(do_teleport(user, user, 10, channel = TELEPORT_CHANNEL_MAGIC))
var/datum/effect_system/smoke_spread/smoke = new
smoke.set_up(3, user.loc)
smoke.start()
diff --git a/code/modules/projectiles/projectile/energy/net_snare.dm b/code/modules/projectiles/projectile/energy/net_snare.dm
index f5d0607341..c8333a811c 100644
--- a/code/modules/projectiles/projectile/energy/net_snare.dm
+++ b/code/modules/projectiles/projectile/energy/net_snare.dm
@@ -42,10 +42,10 @@
/obj/effect/nettingportal/proc/pop(teletarget)
if(teletarget)
for(var/mob/living/L in get_turf(src))
- do_teleport(L, teletarget, 2)//teleport what's in the tile to the beacon
+ do_teleport(L, teletarget, 2, channel = TELEPORT_CHANNEL_BLUESPACE)//teleport what's in the tile to the beacon
else
for(var/mob/living/L in get_turf(src))
- do_teleport(L, L, 15) //Otherwise it just warps you off somewhere.
+ do_teleport(L, L, 15, channel = TELEPORT_CHANNEL_BLUESPACE) //Otherwise it just warps you off somewhere.
qdel(src)
diff --git a/code/modules/projectiles/projectile/magic.dm b/code/modules/projectiles/projectile/magic.dm
index dee88f176f..5b84608fad 100644
--- a/code/modules/projectiles/projectile/magic.dm
+++ b/code/modules/projectiles/projectile/magic.dm
@@ -67,7 +67,7 @@
teleloc = target.loc
for(var/atom/movable/stuff in teleloc)
if(!stuff.anchored && stuff.loc)
- if(do_teleport(stuff, stuff, 10))
+ if(do_teleport(stuff, stuff, 10, channel = TELEPORT_CHANNEL_MAGIC))
teleammount++
var/datum/effect_system/smoke_spread/smoke = new
smoke.set_up(max(round(4 - teleammount),0), stuff.loc) //Smoke drops off if a lot of stuff is moved for the sake of sanity
diff --git a/code/modules/projectiles/projectile/special/rocket.dm b/code/modules/projectiles/projectile/special/rocket.dm
index a62fa25f7d..e15810c6bb 100644
--- a/code/modules/projectiles/projectile/special/rocket.dm
+++ b/code/modules/projectiles/projectile/special/rocket.dm
@@ -16,6 +16,7 @@
var/anti_armour_damage = 200
armour_penetration = 100
dismemberment = 100
+ ricochets_max = 0
/obj/item/projectile/bullet/a84mm/on_hit(atom/target, blocked = FALSE)
..()
diff --git a/code/modules/reagents/chemistry/holder.dm b/code/modules/reagents/chemistry/holder.dm
index dc86ab4e6c..d1eec39f44 100644
--- a/code/modules/reagents/chemistry/holder.dm
+++ b/code/modules/reagents/chemistry/holder.dm
@@ -1,3 +1,4 @@
+#define CHEMICAL_QUANTISATION_LEVEL 0.0001
/proc/build_chemical_reagent_list()
//Chemical Reagents - Initialises all /datum/reagent into a list indexed by reagent id
@@ -53,10 +54,16 @@
var/maximum_volume = 100
var/atom/my_atom = null
var/chem_temp = 150
+ var/pH = REAGENT_NORMAL_PH//Potential of hydrogen. Edited on adding new reagents, deleting reagents, and during fermi reactions.
+ var/overallPurity = 1
var/last_tick = 1
var/addiction_tick = 1
var/list/datum/reagent/addiction_list = new/list()
var/reagents_holder_flags
+ var/targetVol = 0 //the target volume, i.e. the total amount that can be created during a fermichem reaction.
+ var/reactedVol = 0 //how much of the reagent is reacted during a fermireaction
+ var/fermiIsReacting = FALSE //that prevents multiple reactions from occurring (i.e. add_reagent calls to process_reactions(), this stops any extra reactions.)
+ var/fermiReactID = null //ID of the chem being made during a fermireaction, kept here so it's cache isn't lost between loops/procs.
/datum/reagents/New(maximum=100, new_flags)
maximum_volume = maximum
@@ -89,7 +96,7 @@
var/list/data = list()
for(var/r in reagent_list) //no reagents will be left behind
var/datum/reagent/R = r
- data += "[R.id] ([round(R.volume, 0.1)]u)"
+ data += "[R.id] ([round(R.volume, CHEMICAL_QUANTISATION_LEVEL)]u)"
//Using IDs because SOME chemicals (I'm looking at you, chlorhydrate-beer) have the same names as other chemicals.
return english_list(data)
@@ -121,11 +128,13 @@
/datum/reagents/proc/remove_all(amount = 1)
var/list/cached_reagents = reagent_list
+ if((total_volume - amount) <= 0)//Because this can result in 0, I don't want it to crash.
+ pH = 7
if(total_volume > 0)
var/part = amount / total_volume
for(var/reagent in cached_reagents)
var/datum/reagent/R = reagent
- remove_reagent(R.id, R.volume * part)
+ remove_reagent(R.id, R.volume * part, ignore_pH = TRUE)
update_total()
handle_reactions()
@@ -189,8 +198,11 @@
var/transfer_amount = T.volume * part
if(preserve_data)
trans_data = copy_data(T)
- R.add_reagent(T.id, transfer_amount * multiplier, trans_data, chem_temp, no_react = 1) //we only handle reaction after every reagent has been transfered.
- remove_reagent(T.id, transfer_amount)
+
+
+ R.add_reagent(T.id, transfer_amount * multiplier, trans_data, chem_temp, T.purity, pH, no_react = TRUE, ignore_pH = TRUE) //we only handle reaction after every reagent has been transfered.
+
+ remove_reagent(T.id, transfer_amount, ignore_pH = TRUE)
update_total()
R.update_total()
@@ -249,7 +261,8 @@
if(current_reagent.id == reagent)
if(preserve_data)
trans_data = current_reagent.data
- R.add_reagent(current_reagent.id, amount, trans_data, src.chem_temp)
+ R.add_reagent(current_reagent.id, amount, trans_data, chem_temp, current_reagent.purity, pH, no_react = TRUE)
+
remove_reagent(current_reagent.id, amount, 1)
break
@@ -350,14 +363,21 @@
R.on_update (A)
update_total()
-/datum/reagents/proc/handle_reactions()
+
+/datum/reagents/proc/handle_reactions()//HERE EDIT HERE THE MAIN REACTION
+ if(fermiIsReacting == TRUE)
+ return
+
if(reagents_holder_flags & NO_REACT)
return //Yup, no reactions here. No siree.
+
var/list/cached_reagents = reagent_list
var/list/cached_reactions = GLOB.chemical_reactions_list
var/datum/cached_my_atom = my_atom
- var/reaction_occurred = 0
+ var/reaction_occurred = 0 // checks if reaction, binary variable
+ var/continue_reacting = FALSE //Helps keep track what kind of reaction is occuring; standard or fermi.
+
do
var/list/possible_reactions = list()
reaction_occurred = 0
@@ -382,6 +402,7 @@
var/has_special_react = C.special_react
var/can_special_react = 0
+
for(var/B in cached_required_reagents)
if(!has_reagent(B, cached_required_reagents[B]))
break
@@ -402,7 +423,7 @@
if(!C.required_other)
matching_other = 1
- else if(istype(cached_my_atom, /obj/item/slime_extract))
+ else if(istype(cached_my_atom, /obj/item/slime_extract))//if the object is a slime_extract.
var/obj/item/slime_extract/M = cached_my_atom
if(M.Uses > 0) // added a limit to slime cores -- Muskets requested this
@@ -413,7 +434,7 @@
if(!C.required_other)
matching_other = 1
- if(required_temp == 0 || (is_cold_recipe && chem_temp <= required_temp) || (!is_cold_recipe && chem_temp >= required_temp))
+ if(required_temp == 0 || (is_cold_recipe && chem_temp <= required_temp) || (!is_cold_recipe && chem_temp >= required_temp))//Temperature check!!
meets_temp_requirement = 1
if(!has_special_react || C.check_special_react(src))
@@ -427,53 +448,268 @@
//select the reaction with the most extreme temperature requirements
for(var/V in possible_reactions)
var/datum/chemical_reaction/competitor = V
- if(selected_reaction.is_cold_recipe) //if there are no recipe conflicts, everything in possible_reactions will have this same value for is_cold_reaction. warranty void if assumption not met.
+ if(selected_reaction.is_cold_recipe)
if(competitor.required_temp <= selected_reaction.required_temp)
selected_reaction = competitor
else
- if(competitor.required_temp >= selected_reaction.required_temp)
+ if(competitor.required_temp >= selected_reaction.required_temp) //will return with the hotter reacting first.
selected_reaction = competitor
- var/list/cached_required_reagents = selected_reaction.required_reagents
- var/list/cached_results = selected_reaction.results
+ var/list/cached_required_reagents = selected_reaction.required_reagents//update reagents list
+ var/list/cached_results = selected_reaction.results//resultant chemical list
var/special_react_result = selected_reaction.check_special_react(src)
var/list/multiplier = INFINITY
- for(var/B in cached_required_reagents)
- multiplier = min(multiplier, round(get_reagent_amount(B) / cached_required_reagents[B]))
- for(var/B in cached_required_reagents)
- remove_reagent(B, (multiplier * cached_required_reagents[B]), safety = 1)
+ //Splits reactions into two types; FermiChem is advanced reaction mechanics, Other is default reaction.
+ //FermiChem relies on two additional properties; pH and impurity
+ //Temperature plays into a larger role too.
+ var/datum/chemical_reaction/C = selected_reaction
- for(var/P in selected_reaction.results)
- multiplier = max(multiplier, 1) //this shouldnt happen ...
- SSblackbox.record_feedback("tally", "chemical_reaction", cached_results[P]*multiplier, P)
- add_reagent(P, cached_results[P]*multiplier, null, chem_temp)
+ if (C.FermiChem == TRUE && !continue_reacting)
+ if (chem_temp > C.ExplodeTemp) //This is first to ensure explosions.
+ var/datum/chemical_reaction/fermi/Ferm = selected_reaction
+ fermiIsReacting = FALSE
+ SSblackbox.record_feedback("tally", "fermi_chem", 1, ("[Ferm] explosion"))
+ Ferm.FermiExplode(src, my_atom, volume = total_volume, temp = chem_temp, pH = pH)
+ return 0
- var/list/seen = viewers(4, get_turf(my_atom))
- var/iconhtml = icon2html(cached_my_atom, seen)
- if(cached_my_atom)
- if(!ismob(cached_my_atom)) // No bubbling mobs
- if(selected_reaction.mix_sound)
- playsound(get_turf(cached_my_atom), selected_reaction.mix_sound, 80, 1)
+ for(var/B in cached_required_reagents)
+ multiplier = min(multiplier, round((get_reagent_amount(B) / cached_required_reagents[B]), CHEMICAL_QUANTISATION_LEVEL))
+ for(var/P in selected_reaction.results)
+ targetVol = cached_results[P]*multiplier
- for(var/mob/M in seen)
- to_chat(M, "[iconhtml] [selected_reaction.mix_message]")
+ if( (chem_temp <= C.ExplodeTemp) && (chem_temp >= C.OptimalTempMin))
+ if( (pH >= (C.OptimalpHMin - C.ReactpHLim)) && (pH <= (C.OptimalpHMax + C.ReactpHLim)) )//To prevent pointless reactions
+
+ if (fermiIsReacting == TRUE)
+ return 0
+ else
+ START_PROCESSING(SSprocessing, src)
+ selected_reaction.on_reaction(src, my_atom, multiplier)
+ fermiIsReacting = TRUE
+ fermiReactID = selected_reaction
+ reaction_occurred = 1
+
+ else //It's a little bit of a confusing nest, but esstentially we check if it's a fermireaction, then temperature, then pH. If this is true, the remainer of this handler is run.
+ return 0 //If pH is out of range
+ else
+ return 0 //If not hot enough
+
+ //Standard reaction mechanics:
+ else
+ if (C.FermiChem == TRUE)//Just to make sure
+ return 0
+
+ for(var/B in cached_required_reagents) //
+ multiplier = min(multiplier, round((get_reagent_amount(B) / cached_required_reagents[B]), CHEMICAL_QUANTISATION_LEVEL))
+
+ for(var/B in cached_required_reagents)
+ remove_reagent(B, (multiplier * cached_required_reagents[B]), safety = 1, ignore_pH = TRUE)
+
+ for(var/P in selected_reaction.results)
+ multiplier = max(multiplier, 1) //this shouldnt happen ...
+ SSblackbox.record_feedback("tally", "chemical_reaction", cached_results[P]*multiplier, P)//log
+ add_reagent(P, cached_results[P]*multiplier, null, chem_temp)
+
+
+ var/list/seen = viewers(4, get_turf(my_atom))//Sound and sight checkers
+ var/iconhtml = icon2html(cached_my_atom, seen)
+ if(cached_my_atom)
+ if(!ismob(cached_my_atom)) // No bubbling mobs
+ if(selected_reaction.mix_sound)
+ playsound(get_turf(cached_my_atom), selected_reaction.mix_sound, 80, 1)
- if(istype(cached_my_atom, /obj/item/slime_extract))
- var/obj/item/slime_extract/ME2 = my_atom
- ME2.Uses--
- if(ME2.Uses <= 0) // give the notification that the slime core is dead
for(var/mob/M in seen)
- to_chat(M, "[iconhtml] \The [my_atom]'s power is consumed in the reaction.")
- ME2.name = "used slime extract"
- ME2.desc = "This extract has been used up."
+ to_chat(M, "[iconhtml] [selected_reaction.mix_message]")
- selected_reaction.on_reaction(src, multiplier, special_react_result)
- reaction_occurred = 1
+ if(istype(cached_my_atom, /obj/item/slime_extract))//if there's an extract and it's used up.
+ var/obj/item/slime_extract/ME2 = my_atom
+ ME2.Uses--
+ if(ME2.Uses <= 0) // give the notification that the slime core is dead
+ for(var/mob/M in seen)
+ to_chat(M, "[iconhtml] \The [my_atom]'s power is consumed in the reaction.")
+ ME2.name = "used slime extract"
+ ME2.desc = "This extract has been used up."
+
+ selected_reaction.on_reaction(src, multiplier, special_react_result)
+ reaction_occurred = 1
+ continue_reacting = TRUE
while(reaction_occurred)
update_total()
return 0
+/datum/reagents/process()
+ var/datum/chemical_reaction/fermi/C = fermiReactID
+
+ var/list/cached_required_reagents = C.required_reagents//update reagents list
+ var/list/cached_results = C.results//resultant chemical list
+ var/multiplier = INFINITY
+
+ for(var/B in cached_required_reagents) //
+ multiplier = min(multiplier, round((get_reagent_amount(B) / cached_required_reagents[B]), 0.001))
+ if (multiplier == 0)
+ fermiEnd()
+ return
+ for(var/P in cached_results)
+ targetVol = cached_results[P]*multiplier
+
+ if (fermiIsReacting == FALSE)
+ CRASH("Fermi has refused to stop reacting even though we asked her nicely.")
+
+ if (chem_temp > C.OptimalTempMin && fermiIsReacting == TRUE)//To prevent pointless reactions
+ if( (pH >= (C.OptimalpHMin - C.ReactpHLim)) && (pH <= (C.OptimalpHMax + C.ReactpHLim)) )
+ if (reactedVol < targetVol)
+ reactedVol = fermiReact(fermiReactID, chem_temp, pH, reactedVol, targetVol, cached_required_reagents, cached_results, multiplier)
+ else//Volume is used up
+ fermiEnd()
+ return
+ else//pH is out of range
+ fermiEnd()
+ return
+ else//Temperature is too low, or reaction has stopped.
+ fermiEnd()
+ return
+
+/datum/reagents/proc/fermiEnd()
+ var/datum/chemical_reaction/fermi/C = fermiReactID
+ STOP_PROCESSING(SSprocessing, src)
+ fermiIsReacting = FALSE
+ reactedVol = 0
+ targetVol = 0
+ //pH check, handled at the end to reduce calls.
+ if(istype(my_atom, /obj/item/reagent_containers))
+ var/obj/item/reagent_containers/RC = my_atom
+ RC.pH_check()
+ C.FermiFinish(src, my_atom)
+ handle_reactions()
+ update_total()
+ //Reaction sounds and words
+ playsound(get_turf(my_atom), C.mix_sound, 80, 1)
+ var/list/seen = viewers(5, get_turf(my_atom))
+ var/iconhtml = icon2html(my_atom, seen)
+ for(var/mob/M in seen)
+ to_chat(M, "[iconhtml] [C.mix_message]")
+
+/datum/reagents/proc/fermiReact(selected_reaction, cached_temp, cached_pH, reactedVol, targetVol, cached_required_reagents, cached_results, multiplier)
+ var/datum/chemical_reaction/fermi/C = selected_reaction
+ var/deltaT = 0
+ var/deltapH = 0
+ var/stepChemAmmount = 0
+
+ //get purity from combined beaker reactant purities HERE.
+ var/purity = 1
+
+ //Begin checks
+ //For now, purity is handled elsewhere (on add)
+ //Calculate DeltapH (Deviation of pH from optimal)
+ //Lower range
+ if (cached_pH < C.OptimalpHMin)
+ if (cached_pH < (C.OptimalpHMin - C.ReactpHLim))
+ deltapH = 0
+ return//If outside pH range, no reaction
+ else
+ deltapH = (((cached_pH - (C.OptimalpHMin - C.ReactpHLim))**C.CurveSharppH)/((C.ReactpHLim**C.CurveSharppH)))
+ //Upper range
+ else if (cached_pH > C.OptimalpHMax)
+ if (cached_pH > (C.OptimalpHMax + C.ReactpHLim))
+ deltapH = 0
+ return //If outside pH range, no reaction
+ else
+ deltapH = (((- cached_pH + (C.OptimalpHMax + C.ReactpHLim))**C.CurveSharppH)/(C.ReactpHLim**C.CurveSharppH))//Reverse - to + to prevent math operation failures.
+ //Within mid range
+ else if (cached_pH >= C.OptimalpHMin && cached_pH <= C.OptimalpHMax)
+ deltapH = 1
+ //This should never proc:
+ else
+ WARNING("[my_atom] attempted to determine FermiChem pH for '[C.id]' which broke for some reason! ([usr])")
+
+ //Calculate DeltaT (Deviation of T from optimal)
+ if (cached_temp < C.OptimalTempMax && cached_temp >= C.OptimalTempMin)
+ deltaT = (((cached_temp - C.OptimalTempMin)**C.CurveSharpT)/((C.OptimalTempMax - C.OptimalTempMin)**C.CurveSharpT))
+ else if (cached_temp >= C.OptimalTempMax)
+ deltaT = 1
+ else
+ deltaT = 0
+
+ purity = (deltapH)//set purity equal to pH offset
+
+ //Then adjust purity of result with reagent purity.
+ purity *= reactant_purity(C)
+
+ var/removeChemAmmount //remove factor
+ var/addChemAmmount //add factor
+ //ONLY WORKS FOR ONE PRODUCT AT THE MOMENT
+ //Calculate how much product to make and how much reactant to remove factors..
+ for(var/P in cached_results)
+ //stepChemAmmount = CLAMP(((deltaT * multiplier), 0, ((targetVol - reactedVol)/cached_results[P])) //used to have multipler, now it does
+ stepChemAmmount = (multiplier*cached_results[P])
+ if (stepChemAmmount >= C.RateUpLim)
+ stepChemAmmount = (C.RateUpLim)
+ addChemAmmount = deltaT * stepChemAmmount
+ if (addChemAmmount >= (targetVol - reactedVol))
+ addChemAmmount = (targetVol - reactedVol)
+ if (addChemAmmount < CHEMICAL_QUANTISATION_LEVEL)
+ addChemAmmount = CHEMICAL_QUANTISATION_LEVEL
+ removeChemAmmount = (addChemAmmount/cached_results[P])
+ //This is kept for future bugtesters.
+ //message_admins("Reaction vars: PreReacted: [reactedVol] of [targetVol]. deltaT [deltaT], multiplier [multiplier], Step [stepChemAmmount], uncapped Step [deltaT*(multiplier*cached_results[P])], addChemAmmount [addChemAmmount], removeFactor [removeChemAmmount] Pfactor [cached_results[P]], adding [addChemAmmount]")
+
+ //remove reactants
+ for(var/B in cached_required_reagents)
+ remove_reagent(B, (removeChemAmmount * cached_required_reagents[B]), safety = 1, ignore_pH = TRUE)
+
+ //add product
+ var/TotalStep = 0
+ for(var/P in cached_results)
+ SSblackbox.record_feedback("tally", "chemical_reaction", addChemAmmount, P)//log
+ SSblackbox.record_feedback("tally", "fermi_chem", addChemAmmount, P)
+ add_reagent(P, (addChemAmmount), null, cached_temp, purity)//add reagent function!! I THINK I can do this:
+ TotalStep += addChemAmmount//for multiple products
+ //Above should reduce yeild based on holder purity.
+ //Purity Check
+ for(var/datum/reagent/R in my_atom.reagents.reagent_list)
+ if(P == R.id)
+ if (R.purity < C.PurityMin)//If purity is below the min, blow it up.
+ fermiIsReacting = FALSE
+ SSblackbox.record_feedback("tally", "fermi_chem", 1, ("[P] explosion"))
+ C.FermiExplode(src, my_atom, (reactedVol+targetVol), cached_temp, pH)
+ STOP_PROCESSING(SSprocessing, src)
+ return 0
+
+ C.FermiCreate(src)//proc that calls when step is done
+
+ //Apply pH changes and thermal output of reaction to beaker
+ chem_temp = round(cached_temp + (C.ThermicConstant * addChemAmmount))
+ pH += (C.HIonRelease * addChemAmmount)
+ //keep track of the current reacted amount
+ reactedVol = reactedVol + addChemAmmount
+
+ //Check extremes
+ if (chem_temp > C.ExplodeTemp)
+ //go to explode proc
+ fermiIsReacting = FALSE
+ SSblackbox.record_feedback("tally", "fermi_chem", 1, ("[C] explosions"))
+ C.FermiExplode(src, my_atom, (reactedVol+targetVol), chem_temp, pH)
+ STOP_PROCESSING(SSprocessing, src)
+ return
+
+ //Make sure things are limited.
+ pH = CLAMP(pH, 0, 14)
+
+ //return said amount to compare for next step.
+ return (reactedVol)
+
+//Currently calculates it irrespective of required reagents at the start
+/datum/reagents/proc/reactant_purity(var/datum/chemical_reaction/fermi/C, holder)
+ var/list/cached_reagents = reagent_list
+ var/i = 0
+ var/cachedPurity
+ for(var/datum/reagent/R in my_atom.reagents.reagent_list)
+ if (R in cached_reagents)
+ cachedPurity += R.purity
+ i++
+ return cachedPurity/i
+
/datum/reagents/proc/isolate_reagent(reagent)
var/list/cached_reagents = reagent_list
for(var/_reagent in cached_reagents)
@@ -505,7 +741,7 @@
total_volume = 0
for(var/reagent in cached_reagents)
var/datum/reagent/R = reagent
- if(R.volume < 0.1)
+ if(R.volume < CHEMICAL_QUANTISATION_LEVEL)
del_reagent(R.id)
else
total_volume += R.volume
@@ -517,6 +753,7 @@
for(var/reagent in cached_reagents)
var/datum/reagent/R = reagent
del_reagent(R.id)
+ pH = REAGENT_NORMAL_PH
return 0
/datum/reagents/proc/reaction(atom/A, method = TOUCH, volume_modifier = 1, show_message = 1)
@@ -563,13 +800,17 @@
/datum/reagents/proc/adjust_thermal_energy(J, min_temp = 2.7, max_temp = 1000)
var/S = specific_heat()
- chem_temp = CLAMP(chem_temp + (J / (S * total_volume)), 2.7, 1000)
+ chem_temp = CLAMP(chem_temp + (J / (S * total_volume)), min_temp, max_temp)
+ if(istype(my_atom, /obj/item/reagent_containers))
+ var/obj/item/reagent_containers/RC = my_atom
+ RC.temp_check()
+
+/datum/reagents/proc/add_reagent(reagent, amount, list/data=null, reagtemp = 300, other_purity = 1, other_pH, no_react = 0, ignore_pH = FALSE)
-/datum/reagents/proc/add_reagent(reagent, amount, list/data=null, reagtemp = 300, no_react = 0)
if(!isnum(amount) || !amount)
return FALSE
- if(amount <= 0)
+ if(amount <= CHEMICAL_QUANTISATION_LEVEL)//To prevent small ammount problems.
return FALSE
var/datum/reagent/D = GLOB.chemical_reagents_list[reagent]
@@ -577,6 +818,23 @@
WARNING("[my_atom] attempted to add a reagent called '[reagent]' which doesn't exist. ([usr])")
return FALSE
+ if (D.id == "water" && no_react == FALSE && !istype(my_atom, /obj/item/reagent_containers/food)) //Do like an otter, add acid to water, but also don't blow up botany.
+ if (pH <= 2)
+ SSblackbox.record_feedback("tally", "fermi_chem", 1, "water-acid explosions")
+ var/datum/effect_system/smoke_spread/chem/s = new
+ var/turf/T = get_turf(my_atom)
+ var/datum/reagents/R = new/datum/reagents(3000)
+ R.add_reagent("fermiAcid", amount)
+ for (var/datum/reagent/reagentgas in reagent_list)
+ R.add_reagent(reagentgas, amount/5)
+ remove_reagent(reagentgas, amount/5)
+ s.set_up(R, CLAMP(amount/10, 0, 2), T)
+ s.start()
+ return FALSE
+
+ if(!pH)
+ other_pH = D.pH
+
update_total()
var/cached_total = total_volume
if(cached_total + amount > maximum_volume)
@@ -587,6 +845,10 @@
var/cached_temp = chem_temp
var/list/cached_reagents = reagent_list
+ var/cached_pH = pH
+
+
+
//Equalize temperature - Not using specific_heat() because the new chemical isn't in yet.
var/specific_heat = 0
var/thermal_energy = 0
@@ -597,32 +859,55 @@
specific_heat += D.specific_heat * (amount / new_total)
thermal_energy += D.specific_heat * amount * reagtemp
chem_temp = thermal_energy / (specific_heat * new_total)
- ////
+
+ //cacluate reagent based pH shift.
+ if(ignore_pH == TRUE)
+ pH = ((cached_pH * cached_total)+(other_pH * amount))/(cached_total + amount)//should be right
+ else
+ pH = ((cached_pH * cached_total)+(D.pH * amount))/(cached_total + amount)//should be right
+ if(istype(my_atom, /obj/item/reagent_containers/))
+ var/obj/item/reagent_containers/RC = my_atom
+ RC.pH_check()//checks beaker resilience
//add the reagent to the existing if it exists
for(var/A in cached_reagents)
var/datum/reagent/R = A
- if (R.id == reagent)
+ if (R.id == reagent) //IF MERGING
+ //Add amount and equalize purity
R.volume += amount
+ R.purity = ((R.purity * R.volume) + (other_purity * amount)) /((R.volume + amount)) //This should add the purity to the product
+
update_total()
if(my_atom)
my_atom.on_reagent_change(ADD_REAGENT)
- R.on_merge(data, amount)
+ if(isliving(my_atom))
+ if(R.OnMobMergeCheck == TRUE)//Forces on_mob_add proc when a chem is merged
+ R.on_mob_add(my_atom, amount)
+ //else
+ // R.on_merge(data, amount, my_atom, other_purity)
+ R.on_merge(data, amount, my_atom, other_purity)
if(!no_react)
handle_reactions()
+
return TRUE
+
//otherwise make a new one
var/datum/reagent/R = new D.type(data)
cached_reagents += R
R.holder = src
R.volume = amount
+ R.purity = other_purity
+ R.loc = get_turf(my_atom)
if(data)
R.data = data
R.on_new(data)
+ if(R.addProc == TRUE)//Allows on new without data overhead.
+ R.on_new(pH) //Add more as desired.
+
if(isliving(my_atom))
- R.on_mob_add(my_atom) //Must occur befor it could posibly run on_mob_delete
+ R.on_mob_add(my_atom, amount)
update_total()
if(my_atom)
my_atom.on_reagent_change(ADD_REAGENT)
@@ -630,12 +915,13 @@
handle_reactions()
return TRUE
+
/datum/reagents/proc/add_reagent_list(list/list_reagents, list/data=null) // Like add_reagent but you can enter a list. Format it like this: list("toxin" = 10, "beer" = 15)
for(var/r_id in list_reagents)
var/amt = list_reagents[r_id]
add_reagent(r_id, amt, data)
-/datum/reagents/proc/remove_reagent(reagent, amount, safety)//Added a safety check for the trans_id_to
+/datum/reagents/proc/remove_reagent(reagent, amount, safety, ignore_pH = FALSE)//Added a safety check for the trans_id_to
if(isnull(amount))
amount = 0
@@ -653,6 +939,15 @@
for(var/A in cached_reagents)
var/datum/reagent/R = A
if (R.id == reagent)
+ if((total_volume - amount) <= 0)//Because this can result in 0, I don't want it to crash.
+ pH = 7
+ //In practice this is really confusing and players feel like it randomly melts their beakers, but I'm not sure how else to handle it. We'll see how it goes and I can remove this if it confuses people.
+ else if (ignore_pH == FALSE)
+ //if (((pH > R.pH) && (pH <= 7)) || ((pH < R.pH) && (pH >= 7)))
+ pH = (((pH - R.pH) / total_volume) * amount) + pH
+ if(istype(my_atom, /obj/item/reagent_containers/))
+ var/obj/item/reagent_containers/RC = my_atom
+ RC.pH_check()//checks beaker resilience)
//clamp the removal amount to be between current reagent amount
//and zero, to prevent removing more than the holder has stored
amount = CLAMP(amount, 0, R.volume)
@@ -674,7 +969,7 @@
if(!amount)
return R
else
- if(R.volume >= amount)
+ if(round(R.volume, CHEMICAL_QUANTISATION_LEVEL) >= amount)
return R
else
return 0
@@ -686,7 +981,7 @@
for(var/_reagent in cached_reagents)
var/datum/reagent/R = _reagent
if (R.id == reagent)
- return R.volume
+ return round(R.volume, CHEMICAL_QUANTISATION_LEVEL)
return 0
diff --git a/code/modules/reagents/chemistry/machinery/chem_dispenser.dm b/code/modules/reagents/chemistry/machinery/chem_dispenser.dm
index fa9d60a219..bc998c6657 100644
--- a/code/modules/reagents/chemistry/machinery/chem_dispenser.dm
+++ b/code/modules/reagents/chemistry/machinery/chem_dispenser.dm
@@ -189,10 +189,16 @@
data["beakerCurrentVolume"] = beakerCurrentVolume
data["beakerMaxVolume"] = beaker.volume
data["beakerTransferAmounts"] = beaker.possible_transfer_amounts
+ data["beakerCurrentpH"] = beaker.reagents.pH
+ //pH accuracy
+ for(var/obj/item/stock_parts/capacitor/C in component_parts)
+ data["partRating"]= 10**(C.rating-1)
+
else
data["beakerCurrentVolume"] = null
data["beakerMaxVolume"] = null
data["beakerTransferAmounts"] = null
+ data["beakerCurrentpH"] = null
var/chemicals[0]
var/recipes[0]
diff --git a/code/modules/reagents/chemistry/machinery/chem_heater.dm b/code/modules/reagents/chemistry/machinery/chem_heater.dm
index a17b1e8190..436ee80e7b 100644
--- a/code/modules/reagents/chemistry/machinery/chem_heater.dm
+++ b/code/modules/reagents/chemistry/machinery/chem_heater.dm
@@ -97,13 +97,21 @@
data["isBeakerLoaded"] = beaker ? 1 : 0
data["currentTemp"] = beaker ? beaker.reagents.chem_temp : null
+ data["currentpH"] = beaker ? beaker.reagents.pH : null
data["beakerCurrentVolume"] = beaker ? beaker.reagents.total_volume : null
data["beakerMaxVolume"] = beaker ? beaker.volume : null
+ //purity and pH accuracy
+ for(var/obj/item/stock_parts/micro_laser/M in component_parts)
+ data["partRating"]= 10**(M.rating-1)
+ if(M.rating == 4)
+ data["showPurity"] = 1
+ else
+ data["showPurity"] = 0
var beakerContents[0]
if(beaker)
for(var/datum/reagent/R in beaker.reagents.reagent_list)
- beakerContents.Add(list(list("name" = R.name, "volume" = R.volume))) // list in a list because Byond merges the first list...
+ beakerContents.Add(list(list("name" = R.name, "volume" = R.volume, "purity" = R.purity))) // list in a list because Byond merges the first list...
data["beakerContents"] = beakerContents
return data
diff --git a/code/modules/reagents/chemistry/machinery/chem_master.dm b/code/modules/reagents/chemistry/machinery/chem_master.dm
index 6401a78141..002c54be94 100644
--- a/code/modules/reagents/chemistry/machinery/chem_master.dm
+++ b/code/modules/reagents/chemistry/machinery/chem_master.dm
@@ -21,6 +21,7 @@
var/analyzeVars[0]
var/useramount = 30 // Last used amount
var/list/pillStyles
+ var/fermianalyze //Give more detail on fermireactions on analysis
/obj/machinery/chem_master/Initialize()
create_reagents(100)
@@ -102,12 +103,9 @@
updateUsrDialog()
update_icon()
else if(!condi && istype(I, /obj/item/storage/pill_bottle))
- if(bottle)
- to_chat(user, "A pill bottle is already loaded into [src]!")
- return
if(!user.transferItemToLoc(I, src))
return
- bottle = I
+ replace_pillbottle(user, I)
to_chat(user, "You add [I] into the dispenser slot.")
updateUsrDialog()
else
@@ -131,12 +129,23 @@
update_icon()
return TRUE
-/obj/machinery/chem_master/on_deconstruction()
- replace_beaker(usr)
+/obj/machinery/chem_master/proc/replace_pillbottle(mob/living/user, obj/item/storage/pill_bottle/new_bottle)
if(bottle)
bottle.forceMove(drop_location())
- adjust_item_drop_location(bottle)
+ if(user && Adjacent(user) && !issiliconoradminghost(user))
+ user.put_in_hands(beaker)
+ else
+ adjust_item_drop_location(bottle)
+ if(new_bottle)
+ bottle = new_bottle
+ else
bottle = null
+ update_icon()
+ return TRUE
+
+/obj/machinery/chem_master/on_deconstruction()
+ replace_beaker(usr)
+ replace_pillbottle(usr)
return ..()
/obj/machinery/chem_master/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
@@ -162,6 +171,7 @@
data["condi"] = condi
data["screen"] = screen
data["analyzeVars"] = analyzeVars
+ data["fermianalyze"] = fermianalyze
data["chosenPillStyle"] = chosenPillStyle
data["isPillBottleLoaded"] = bottle ? 1 : 0
if(bottle)
@@ -195,22 +205,21 @@
. = TRUE
if("ejectp")
- if(bottle)
- bottle.forceMove(drop_location())
- adjust_item_drop_location(bottle)
- bottle = null
- . = TRUE
+ replace_pillbottle(usr)
+ . = TRUE
if("transferToBuffer")
if(beaker)
var/id = params["id"]
var/amount = text2num(params["amount"])
if (amount > 0)
+ end_fermi_reaction()
beaker.reagents.trans_id_to(src, id, amount)
. = TRUE
else if (amount == -1) // -1 means custom amount
useramount = input("Enter the Amount you want to transfer:", name, useramount) as num|null
if (useramount > 0)
+ end_fermi_reaction()
beaker.reagents.trans_id_to(src, id, useramount)
. = TRUE
@@ -245,14 +254,14 @@
if(!name || !reagents.total_volume || !src || QDELETED(src) || !usr.canUseTopic(src, !issilicon(usr)))
return
var/obj/item/reagent_containers/pill/P
- var/target_loc = drop_location()
+ var/target_loc = bottle ? bottle : drop_location()
var/drop_threshold = INFINITY
if(bottle)
GET_COMPONENT_FROM(STRB, /datum/component/storage, bottle)
if(STRB)
drop_threshold = STRB.max_items - bottle.contents.len
- for(var/i = 0; i < amount; i++)
+ for(var/i in 1 to amount)
if(i < drop_threshold)
P = new(target_loc)
else
@@ -348,10 +357,10 @@
return
var/amount_full = 0
- var/vol_part = min(reagents.total_volume, 30)
+ var/vol_part = min(reagents.total_volume, 60)
if(text2num(many))
- amount_full = round(reagents.total_volume / 30)
- vol_part = reagents.total_volume % 30
+ amount_full = round(reagents.total_volume / 60)
+ vol_part = reagents.total_volume % 60
var/name = stripped_input(usr, "Name:","Name your hypovial!", (reagents.total_volume ? reagents.get_master_reagent_name() : " "), MAX_NAME_LEN)
if(!name || !reagents.total_volume || !src || QDELETED(src) || !usr.canUseTopic(src, !issilicon(usr)))
return
@@ -361,7 +370,7 @@
P = new/obj/item/reagent_containers/glass/bottle/vial/small(drop_location())
P.name = trim("[name] hypovial")
adjust_item_drop_location(P)
- reagents.trans_to(P, 30)
+ reagents.trans_to(P, 60)
if(vol_part)
P = new/obj/item/reagent_containers/glass/bottle/vial/small(drop_location())
@@ -382,7 +391,14 @@
state = "Gas"
var/const/P = 3 //The number of seconds between life ticks
var/T = initial(R.metabolization_rate) * (60 / P)
- analyzeVars = list("name" = initial(R.name), "state" = state, "color" = initial(R.color), "description" = initial(R.description), "metaRate" = T, "overD" = initial(R.overdose_threshold), "addicD" = initial(R.addiction_threshold))
+ if(istype(R, /datum/reagent/fermi))
+ fermianalyze = TRUE
+ var/datum/chemical_reaction/Rcr = get_chemical_reaction(R.id)
+ var/pHpeakCache = (Rcr.OptimalpHMin + Rcr.OptimalpHMax)/2
+ analyzeVars = list("name" = initial(R.name), "state" = state, "color" = initial(R.color), "description" = initial(R.description), "metaRate" = T, "overD" = initial(R.overdose_threshold), "addicD" = initial(R.addiction_threshold), "purityF" = initial(R.purity), "inverseRatioF" = initial(R.InverseChemVal), "purityE" = initial(Rcr.PurityMin), "minTemp" = initial(Rcr.OptimalTempMin), "maxTemp" = initial(Rcr.OptimalTempMax), "eTemp" = initial(Rcr.ExplodeTemp), "pHpeak" = pHpeakCache)
+ else
+ fermianalyze = FALSE
+ analyzeVars = list("name" = initial(R.name), "state" = state, "color" = initial(R.color), "description" = initial(R.description), "metaRate" = T, "overD" = initial(R.overdose_threshold), "addicD" = initial(R.addiction_threshold))
screen = "analyze"
return
@@ -392,6 +408,9 @@
+/obj/machinery/chem_master/proc/end_fermi_reaction()//Ends any reactions upon moving.
+ if(beaker.reagents.fermiIsReacting)
+ beaker.reagents.fermiEnd()
/obj/machinery/chem_master/proc/isgoodnumber(num)
if(isnum(num))
@@ -432,4 +451,4 @@
condi = TRUE
#undef PILL_STYLE_COUNT
-#undef RANDOM_PILL_STYLE
\ No newline at end of file
+#undef RANDOM_PILL_STYLE
diff --git a/code/modules/reagents/chemistry/reagents.dm b/code/modules/reagents/chemistry/reagents.dm
index 9bfbffd330..c21629ce8f 100644
--- a/code/modules/reagents/chemistry/reagents.dm
+++ b/code/modules/reagents/chemistry/reagents.dm
@@ -33,10 +33,18 @@
var/addiction_stage4_end = 40
var/overdosed = 0 // You fucked up and this is now triggering its overdose effects, purge that shit quick.
var/self_consuming = FALSE
+ //Fermichem vars:
+ var/purity = 1 //How pure a chemical is from 0 - 1.
+ var/addProc = FALSE //If the chemical should force an on_new() call
+ var/turf/loc = null //Should be the creation location!
+ var/pH = 7 //pH of the specific reagent, used for calculating the sum pH of a holder.
+ var/ImpureChem = "fermiTox"// What chemical is metabolised with an inpure reaction
+ var/InverseChemVal = 0.25 // If the impurity is below 0.5, replace ALL of the chem with InverseChem upon metabolising
+ var/InverseChem = "fermiTox"// What chem is metabolised when purity is below InverseChemVal, this shouldn't be made, but if it does, well, I guess I'll know about it.
+ var/DoNotSplit = FALSE // If impurity is handled within the main chem itself
+ var/OnMobMergeCheck = FALSE //Call on_mob_life proc when reagents are merging.
var/metabolizing = FALSE
-
-
-
+ var/invisible = FALSE //Set to true if it doesn't appear on handheld health analyzers.
/datum/reagent/Destroy() // This should only be called by the holder, so it's already handled clearing its references
. = ..()
@@ -61,7 +69,8 @@
/datum/reagent/proc/on_mob_life(mob/living/carbon/M)
current_cycle++
- holder.remove_reagent(src.id, metabolization_rate * M.metabolism_efficiency) //By default it slowly disappears.
+ if(holder)
+ holder.remove_reagent(src.id, metabolization_rate * M.metabolism_efficiency) //By default it slowly disappears.
return
// Called when this reagent is first added to a mob
diff --git a/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm b/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm
index 211fddca26..79b6f96781 100644
--- a/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm
@@ -14,6 +14,7 @@
nutriment_factor = 0
taste_description = "alcohol"
var/boozepwr = 65 //Higher numbers equal higher hardness, higher hardness equals more intense alcohol poisoning
+ pH = 7.33
/*
Boozepwr Chart
@@ -86,6 +87,8 @@ All effects don't start immediately, but rather get worse over time; the rate is
taste_description = "piss water"
glass_name = "glass of beer"
glass_desc = "A freezing pint of beer."
+ pH = 4
+
/datum/reagent/consumable/ethanol/beer/light
name = "Light Beer"
@@ -95,6 +98,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
taste_description = "dish water"
glass_name = "glass of light beer"
glass_desc = "A freezing pint of watery light beer."
+ pH = 5
/datum/reagent/consumable/ethanol/beer/green
name = "Green Beer"
@@ -105,6 +109,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
glass_icon_state = "greenbeerglass"
glass_name = "glass of green beer"
glass_desc = "A freezing pint of green beer. Festive."
+ pH = 6
/datum/reagent/consumable/ethanol/beer/green/on_mob_life(mob/living/carbon/M)
if(M.color != color)
@@ -124,6 +129,8 @@ All effects don't start immediately, but rather get worse over time; the rate is
glass_name = "glass of RR coffee liquor"
glass_desc = "DAMN, THIS THING LOOKS ROBUST!"
shot_glass_icon_state = "shotglasscream"
+ pH = 6
+
/datum/reagent/consumable/ethanol/kahlua/on_mob_life(mob/living/carbon/M)
M.dizziness = max(0,M.dizziness-5)
@@ -145,6 +152,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
glass_name = "glass of whiskey"
glass_desc = "The silky, smokey whiskey goodness inside the glass makes the drink look very classy."
shot_glass_icon_state = "shotglassbrown"
+ pH = 4.5
/datum/reagent/consumable/ethanol/thirteenloko
name = "Thirteen Loko"
@@ -161,6 +169,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
glass_name = "glass of Thirteen Loko"
glass_desc = "This is a glass of Thirteen Loko, it appears to be of the highest quality. The drink, not the glass."
+
/datum/reagent/consumable/ethanol/thirteenloko/on_mob_life(mob/living/carbon/M)
M.drowsyness = max(0,M.drowsyness-7)
M.AdjustSleeping(-40)
@@ -221,6 +230,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
glass_name = "glass of vodka"
glass_desc = "The glass contain wodka. Xynta."
shot_glass_icon_state = "shotglassclear"
+ pH = 8.1
/datum/reagent/consumable/ethanol/vodka/on_mob_life(mob/living/carbon/M)
M.radiation = max(M.radiation-2,0)
@@ -255,6 +265,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
glass_icon_state = "threemileislandglass"
glass_name = "Three Mile Island Ice Tea"
glass_desc = "A glass of this is sure to prevent a meltdown."
+ pH = 3.5
/datum/reagent/consumable/ethanol/threemileisland/on_mob_life(mob/living/carbon/M)
M.set_drugginess(50)
@@ -270,6 +281,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
glass_icon_state = "ginvodkaglass"
glass_name = "glass of gin"
glass_desc = "A crystal clear glass of Griffeater gin."
+ pH = 6.9
/datum/reagent/consumable/ethanol/rum
name = "Rum"
@@ -282,6 +294,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
glass_name = "glass of rum"
glass_desc = "Now you want to Pray for a pirate suit, don't you?"
shot_glass_icon_state = "shotglassbrown"
+ pH = 6.5
/datum/reagent/consumable/ethanol/tequila
name = "Tequila"
@@ -294,6 +307,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
glass_name = "glass of tequila"
glass_desc = "Now all that's missing is the weird colored shades!"
shot_glass_icon_state = "shotglassgold"
+ pH = 4
/datum/reagent/consumable/ethanol/vermouth
name = "Vermouth"
@@ -306,6 +320,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
glass_name = "glass of vermouth"
glass_desc = "You wonder why you're even drinking this straight."
shot_glass_icon_state = "shotglassclear"
+ pH = 3.25
/datum/reagent/consumable/ethanol/wine
name = "Wine"
@@ -318,6 +333,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
glass_name = "glass of wine"
glass_desc = "A very classy looking drink."
shot_glass_icon_state = "shotglassred"
+ pH = 3.45
/datum/reagent/consumable/ethanol/lizardwine
name = "Lizard wine"
@@ -327,6 +343,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
boozepwr = 45
quality = DRINK_FANTASTIC
taste_description = "scaley sweetness"
+ pH = 3
/datum/reagent/consumable/ethanol/grappa
name = "Grappa"
@@ -338,6 +355,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
glass_icon_state = "grappa"
glass_name = "glass of grappa"
glass_desc = "A fine drink originally made to prevent waste by using the leftovers from winemaking."
+ pH = 3.5
/datum/reagent/consumable/ethanol/cognac
name = "Cognac"
@@ -350,6 +368,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
glass_name = "glass of cognac"
glass_desc = "Damn, you feel like some kind of French aristocrat just by holding this."
shot_glass_icon_state = "shotglassbrown"
+ pH = 3.5
/datum/reagent/consumable/ethanol/absinthe
name = "Absinthe"
@@ -395,6 +414,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
glass_icon_state = "aleglass"
glass_name = "glass of ale"
glass_desc = "A freezing pint of delicious Ale."
+ pH = 4.5
/datum/reagent/consumable/ethanol/goldschlager
name = "Goldschlager"
@@ -421,6 +441,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
glass_name = "glass of patron"
glass_desc = "Drinking patron in the bar, with all the subpar ladies."
shot_glass_icon_state = "shotglassclear"
+ pH = 4.5
/datum/reagent/consumable/ethanol/gintonic
name = "Gin and Tonic"
@@ -433,6 +454,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
glass_icon_state = "gintonicglass"
glass_name = "Gin and Tonic"
glass_desc = "A mild but still great cocktail. Drink up, like a true Englishman."
+ pH = 3
/datum/reagent/consumable/ethanol/rum_coke
name = "Rum and Coke"
@@ -445,6 +467,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
glass_icon_state = "whiskeycolaglass"
glass_name = "Rum and Coke"
glass_desc = "The classic go-to of space-fratboys."
+ pH = 4
/datum/reagent/consumable/ethanol/cuba_libre
name = "Cuba Libre"
@@ -458,6 +481,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
glass_name = "Cuba Libre"
glass_desc = "A classic mix of rum, cola, and lime. A favorite of revolutionaries everywhere!"
+
/datum/reagent/consumable/ethanol/cuba_libre/on_mob_life(mob/living/carbon/M)
if(M.mind && M.mind.has_antag_datum(/datum/antagonist/rev)) //Cuba Libre, the traditional drink of revolutions! Heals revolutionaries.
M.adjustBruteLoss(-1, 0)
@@ -504,6 +528,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
glass_name = "Vodka martini"
glass_desc ="A bastardisation of the classic martini. Still great."
+
/datum/reagent/consumable/ethanol/white_russian
name = "White Russian"
id = "whiterussian"
@@ -557,8 +582,8 @@ All effects don't start immediately, but rather get worse over time; the rate is
glass_desc = "Tomato juice, mixed with Vodka and a lil' bit of lime. Tastes like liquid murder."
/datum/reagent/consumable/ethanol/bloody_mary/on_mob_life(mob/living/carbon/C)
- if(C.blood_volume < BLOOD_VOLUME_NORMAL)
- C.blood_volume = min(BLOOD_VOLUME_NORMAL, C.blood_volume + 3) //Bloody Mary quickly restores blood loss.
+ if(C.blood_volume < (BLOOD_VOLUME_NORMAL*C.blood_ratio))
+ C.blood_volume = min((BLOOD_VOLUME_NORMAL*C.blood_ratio), C.blood_volume + 3) //Bloody Mary quickly restores blood loss.
..()
/datum/reagent/consumable/ethanol/brave_bull
@@ -643,6 +668,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
glass_icon_state = "beepskysmashglass"
glass_name = "Beepsky Smash"
glass_desc = "Heavy, hot and strong. Just like the Iron fist of the LAW."
+ pH = 2
overdose_threshold = 40
var/datum/brain_trauma/special/beepsky/B
@@ -1578,6 +1604,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
glass_name = "Bastion Bourbon"
glass_desc = "If you're feeling low, count on the buttery flavor of our own bastion bourbon."
shot_glass_icon_state = "shotglassgreen"
+ pH = 4
/datum/reagent/consumable/ethanol/bastion_bourbon/on_mob_metabolize(mob/living/L)
var/heal_points = 10
@@ -2076,7 +2103,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
/datum/reagent/consumable/ethanol/blazaam/on_mob_life(mob/living/carbon/M)
if(M.drunkenness > 40)
if(stored_teleports)
- do_teleport(M, get_turf(M), rand(1,3))
+ do_teleport(M, get_turf(M), rand(1,3), channel = TELEPORT_CHANNEL_WORMHOLE)
stored_teleports--
if(prob(10))
stored_teleports += rand(2,6)
@@ -2106,6 +2133,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
can_synth = FALSE
var/list/names = list("null fruit" = 1) //Names of the fruits used. Associative list where name is key, value is the percentage of that fruit.
var/list/tastes = list("bad coding" = 1) //List of tastes. See above.
+ pH = 4
/datum/reagent/consumable/ethanol/fruit_wine/on_new(list/data)
names = data["names"]
diff --git a/code/modules/reagents/chemistry/reagents/drink_reagents.dm b/code/modules/reagents/chemistry/reagents/drink_reagents.dm
index 8aa555944a..bfefc073f8 100644
--- a/code/modules/reagents/chemistry/reagents/drink_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/drink_reagents.dm
@@ -168,6 +168,7 @@
/datum/reagent/consumable/laughter/on_mob_life(mob/living/carbon/M)
M.emote("laugh")
+ SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "chemical_laughter", /datum/mood_event/chemical_laughter)
..()
/datum/reagent/consumable/superlaughter
@@ -182,6 +183,7 @@
if(prob(30))
M.visible_message("[M] bursts out into a fit of uncontrollable laughter!", "You burst out in a fit of uncontrollable laughter!")
M.Stun(5)
+ SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "chemical_laughter", /datum/mood_event/chemical_superlaughter)
..()
/datum/reagent/consumable/potato_juice
diff --git a/code/modules/reagents/chemistry/reagents/drug_reagents.dm b/code/modules/reagents/chemistry/reagents/drug_reagents.dm
index a4586dd997..5b06710472 100644
--- a/code/modules/reagents/chemistry/reagents/drug_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/drug_reagents.dm
@@ -15,6 +15,7 @@
description = "An illegal chemical compound used as drug."
color = "#60A584" // rgb: 96, 165, 132
overdose_threshold = 30
+ pH = 9
/datum/reagent/drug/space_drugs/on_mob_life(mob/living/carbon/M)
M.set_drugginess(15)
@@ -44,6 +45,7 @@
addiction_threshold = 30
taste_description = "smoke"
trippy = FALSE
+ pH = 8
/datum/reagent/drug/nicotine/on_mob_life(mob/living/carbon/M)
if(prob(1))
@@ -65,6 +67,7 @@
color = "#FA00C8"
overdose_threshold = 20
addiction_threshold = 10
+ pH = 10
/datum/reagent/drug/crank/on_mob_life(mob/living/carbon/M)
if(prob(5))
@@ -112,6 +115,7 @@
color = "#0064B4"
overdose_threshold = 20
addiction_threshold = 15
+ pH = 9
/datum/reagent/drug/krokodil/on_mob_life(mob/living/carbon/M)
@@ -167,6 +171,7 @@
var/brain_damage = TRUE
var/jitter = TRUE
var/confusion = TRUE
+ pH = 5
/datum/reagent/drug/methamphetamine/on_mob_metabolize(mob/living/L)
..()
@@ -261,6 +266,7 @@
addiction_threshold = 10
taste_description = "salt" // because they're bathsalts?
var/datum/brain_trauma/special/psychotic_brawling/bath_salts/rage
+ pH = 8.2
/datum/reagent/drug/bath_salts/on_mob_metabolize(mob/living/L)
..()
@@ -357,6 +363,7 @@
description = "Amps you up and gets you going, fixes all stamina damage you might have but can cause toxin and oxygen damage."
reagent_state = LIQUID
color = "#78FFF0"
+ pH = 9.2
/datum/reagent/drug/aranesp/on_mob_life(mob/living/carbon/M)
var/high_message = pick("You feel amped up.", "You feel ready.", "You feel like you can push it to the limit.")
@@ -370,6 +377,84 @@
..()
. = 1
+/datum/reagent/drug/happiness
+ name = "Happiness"
+ id = "happiness"
+ description = "Fills you with ecstasic numbness and causes minor brain damage. Highly addictive. If overdosed causes sudden mood swings."
+ reagent_state = LIQUID
+ color = "#FFF378"
+ addiction_threshold = 10
+ overdose_threshold = 20
+ pH = 10.5
+
+/datum/reagent/drug/happiness/on_mob_add(mob/living/L)
+ ..()
+ ADD_TRAIT(L, TRAIT_FEARLESS, id)
+ SEND_SIGNAL(L, COMSIG_ADD_MOOD_EVENT, "happiness_drug", /datum/mood_event/happiness_drug)
+
+/datum/reagent/drug/happiness/on_mob_delete(mob/living/L)
+ REMOVE_TRAIT(L, TRAIT_FEARLESS, id)
+ SEND_SIGNAL(L, COMSIG_CLEAR_MOOD_EVENT, "happiness_drug")
+ ..()
+
+/datum/reagent/drug/happiness/on_mob_life(mob/living/carbon/M)
+ M.jitteriness = 0
+ M.confused = 0
+ M.disgust = 0
+ M.adjustBrainLoss(0.2)
+ ..()
+ . = 1
+
+/datum/reagent/drug/happiness/overdose_process(mob/living/M)
+ if(prob(30))
+ var/reaction = rand(1,3)
+ switch(reaction)
+ if(1)
+ M.emote("laugh")
+ SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "happiness_drug", /datum/mood_event/happiness_drug_good_od)
+ if(2)
+ M.emote("sway")
+ M.Dizzy(25)
+ if(3)
+ M.emote("frown")
+ SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "happiness_drug", /datum/mood_event/happiness_drug_bad_od)
+ M.adjustBrainLoss(0.5)
+ ..()
+ . = 1
+
+/datum/reagent/drug/happiness/addiction_act_stage1(mob/living/M)// all work and no play makes jack a dull boy
+ GET_COMPONENT_FROM(mood, /datum/component/mood, M)
+ mood.setSanity(min(mood.sanity, SANITY_DISTURBED))
+ M.Jitter(5)
+ if(prob(20))
+ M.emote(pick("twitch","laugh","frown"))
+ ..()
+
+/datum/reagent/drug/happiness/addiction_act_stage2(mob/living/M)
+ GET_COMPONENT_FROM(mood, /datum/component/mood, M)
+ mood.setSanity(min(mood.sanity, SANITY_UNSTABLE))
+ M.Jitter(10)
+ if(prob(30))
+ M.emote(pick("twitch","laugh","frown"))
+ ..()
+
+/datum/reagent/drug/happiness/addiction_act_stage3(mob/living/M)
+ GET_COMPONENT_FROM(mood, /datum/component/mood, M)
+ mood.setSanity(min(mood.sanity, SANITY_CRAZY))
+ M.Jitter(15)
+ if(prob(40))
+ M.emote(pick("twitch","laugh","frown"))
+ ..()
+
+/datum/reagent/drug/happiness/addiction_act_stage4(mob/living/carbon/human/M)
+ GET_COMPONENT_FROM(mood, /datum/component/mood, M)
+ mood.setSanity(SANITY_INSANE)
+ M.Jitter(20)
+ if(prob(50))
+ M.emote(pick("twitch","laugh","frown"))
+ ..()
+ . = 1
+
/datum/reagent/drug/skooma
name = "Skooma"
id = "skooma"
@@ -380,6 +465,7 @@
addiction_threshold = 1
addiction_stage3_end = 40
addiction_stage4_end = 240
+ pH = 12.5
/datum/reagent/drug/skooma/on_mob_metabolize(mob/living/L)
. = ..()
@@ -440,4 +526,3 @@
if(prob(40))
M.emote(pick("twitch","drool","moan"))
..()
-
diff --git a/code/modules/reagents/chemistry/reagents/food_reagents.dm b/code/modules/reagents/chemistry/reagents/food_reagents.dm
index 7d0cea0c8f..19aeaeb25e 100644
--- a/code/modules/reagents/chemistry/reagents/food_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/food_reagents.dm
@@ -230,6 +230,7 @@
description = "A special oil that noticably chills the body. Extracted from Icepeppers and slimes."
color = "#8BA6E9" // rgb: 139, 166, 233
taste_description = "mint"
+ pH = 13 //HMM! I wonder
/datum/reagent/consumable/frostoil/on_mob_life(mob/living/carbon/M)
var/cooling = 0
@@ -275,6 +276,7 @@
description = "A chemical agent used for self-defense and in police work."
color = "#B31008" // rgb: 179, 16, 8
taste_description = "scorching agony"
+ pH = 7.4
/datum/reagent/consumable/condensedcapsaicin/reaction_mob(mob/living/M, method=TOUCH, reac_volume)
if(!ishuman(M) && !ismonkey(M))
@@ -321,7 +323,7 @@
victim.blind_eyes(2)
victim.confused = max(M.confused, 3)
victim.damageoverlaytemp = 60
- victim.Knockdown(60, override_stamdmg = min(reac_volume * 3, 15))
+ victim.Knockdown(80, override_hardstun = 0.1, override_stamdmg = min(reac_volume * 3, 15))
return
else if ( eyes_covered ) // Eye cover is better than mouth cover
victim.blur_eyes(3)
@@ -334,7 +336,7 @@
victim.blind_eyes(3)
victim.confused = max(M.confused, 6)
victim.damageoverlaytemp = 75
- victim.Knockdown(100, override_stamdmg = min(reac_volume * 5, 25))
+ victim.Knockdown(80, override_hardstun = 0.1, override_stamdmg = min(reac_volume * 5, 25))
victim.update_damage_hud()
/datum/reagent/consumable/condensedcapsaicin/on_mob_life(mob/living/carbon/M)
@@ -402,6 +404,7 @@
color = "#E700E7" // rgb: 231, 0, 231
metabolization_rate = 0.2 * REAGENTS_METABOLISM
taste_description = "mushroom"
+ pH = 11
/datum/reagent/drug/mushroomhallucinogen/on_mob_life(mob/living/carbon/M)
M.slurring = max(M.slurring,50)
@@ -618,6 +621,7 @@
description = "A blinding substance extracted from certain onions."
color = "#c0c9a0"
taste_description = "bitterness"
+ pH = 5
/datum/reagent/consumable/tearjuice/reaction_mob(mob/living/M, method=TOUCH, reac_volume)
if(!istype(M))
@@ -672,6 +676,7 @@
description = "An ichor, derived from a certain mushroom, makes for a bad time."
color = "#1d043d"
taste_description = "bitter mushroom"
+ pH = 12
/datum/reagent/consumable/entpoly/on_mob_life(mob/living/carbon/M)
if(current_cycle >= 10)
@@ -692,6 +697,7 @@
description = "A stimulating ichor which causes luminescent fungi to grow on the skin. "
color = "#b5a213"
taste_description = "tingling mushroom"
+ pH = 11.2
/datum/reagent/consumable/tinlux/reaction_mob(mob/living/M)
M.set_light(2)
@@ -706,6 +712,7 @@
color = "#d3a308"
nutriment_factor = 3 * REAGENTS_METABOLISM
taste_description = "fruity mushroom"
+ pH = 10.4
/datum/reagent/consumable/vitfro/on_mob_life(mob/living/carbon/M)
if(prob(80))
@@ -721,6 +728,7 @@
nutriment_factor = 5 * REAGENTS_METABOLISM
color = "#eef442" // rgb: 238, 244, 66
taste_description = "mournful honking"
+ pH = 9.2
/datum/reagent/consumable/astrotame
name = "Astrotame"
@@ -750,3 +758,4 @@
quality = FOOD_AMAZING
taste_mult = 100
can_synth = FALSE
+ pH = 6.1
diff --git a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm
index fe70db250d..eb7438aa20 100644
--- a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm
@@ -18,6 +18,7 @@
name = "Leporazine"
id = "leporazine"
description = "Leporazine will effectively regulate a patient's body temperature, ensuring it never leaves safe levels."
+ pH = 8.4
color = "#82b8aa"
/datum/reagent/medicine/leporazine/on_mob_life(mob/living/carbon/M)
@@ -60,6 +61,9 @@
M.SetSleeping(0, 0)
M.jitteriness = 0
M.cure_all_traumas(TRAUMA_RESILIENCE_MAGIC)
+ if(M.blood_volume < (BLOOD_VOLUME_NORMAL*M.blood_ratio))
+ M.blood_volume = (BLOOD_VOLUME_NORMAL*M.blood_ratio)
+
for(var/thing in M.diseases)
var/datum/disease/D = thing
if(D.severity == DISEASE_SEVERITY_POSITIVE)
@@ -79,6 +83,7 @@
id = "synaptizine"
description = "Increases resistance to stuns as well as reducing drowsiness and hallucinations."
color = "#FF00FF"
+ pH = 4
/datum/reagent/medicine/synaptizine/on_mob_life(mob/living/carbon/M)
M.drowsyness = max(M.drowsyness-5, 0)
@@ -98,6 +103,7 @@
id = "synaphydramine"
description = "Reduces drowsiness, hallucinations, and Histamine from body."
color = "#EC536D" // rgb: 236, 83, 109
+ pH = 5.2
/datum/reagent/medicine/synaphydramine/on_mob_life(mob/living/carbon/M)
M.drowsyness = max(M.drowsyness-5, 0)
@@ -116,6 +122,7 @@
id = "inacusiate"
description = "Instantly restores all hearing to the patient, but does not cure deafness."
color = "#6600FF" // rgb: 100, 165, 255
+ pH = 2
/datum/reagent/medicine/inacusiate/on_mob_life(mob/living/carbon/M)
M.restoreEars()
@@ -127,6 +134,7 @@
description = "A chemical mixture with almost magical healing powers. Its main limitation is that the patient's body temperature must be under 270K for it to metabolise correctly."
color = "#0000C8"
taste_description = "sludge"
+ pH = 11
/datum/reagent/medicine/cryoxadone/on_mob_life(mob/living/carbon/M)
var/power = -0.00003 * (M.bodytemperature ** 2) + 3
@@ -148,6 +156,7 @@
color = "#0000C8"
taste_description = "muscle"
metabolization_rate = 1.5 * REAGENTS_METABOLISM
+ pH = 13
/datum/reagent/medicine/clonexadone/on_mob_life(mob/living/carbon/M)
if(M.bodytemperature < T0C)
@@ -163,6 +172,7 @@
description = "A mixture of cryoxadone and slime jelly, that apparently inverses the requirement for its activation."
color = "#f7832a"
taste_description = "spicy jelly"
+ pH = 12
/datum/reagent/medicine/pyroxadone/on_mob_life(mob/living/carbon/M)
if(M.bodytemperature > BODYTEMP_HEAT_DAMAGE_LIMIT)
@@ -194,6 +204,7 @@
color = "#669900" // rgb: 102, 153, 0
overdose_threshold = 30
taste_description = "fish"
+ pH = 12.2
/datum/reagent/medicine/rezadone/on_mob_life(mob/living/carbon/M)
M.setCloneLoss(0) //Rezadone is almost never used in favor of cryoxadone. Hopefully this will change that.
@@ -215,6 +226,7 @@
description = "Spaceacillin will prevent a patient from conventionally spreading any diseases they are currently infected with."
color = "#f2f2f2"
metabolization_rate = 0.1 * REAGENTS_METABOLISM
+ pH = 8.1
//Goon Chems. Ported mainly from Goonstation. Easily mixable (or not so easily) and provide a variety of effects.
/datum/reagent/medicine/silver_sulfadiazine
@@ -222,6 +234,7 @@
id = "silver_sulfadiazine"
description = "If used in touch-based applications, immediately restores burn wounds as well as restoring more over time. If ingested through other means, deals minor toxin damage."
reagent_state = LIQUID
+ pH = 7.2
color = "#ffeac9"
/datum/reagent/medicine/silver_sulfadiazine/reaction_mob(mob/living/M, method=TOUCH, reac_volume, show_message = 1)
@@ -235,6 +248,7 @@
if(show_message)
to_chat(M, "You feel your burns healing! It stings like hell!")
M.emote("scream")
+ SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "painful_medicine", /datum/mood_event/painful_medicine)
..()
/datum/reagent/medicine/silver_sulfadiazine/on_mob_life(mob/living/carbon/M)
@@ -250,6 +264,7 @@
color = "#f7ffa5"
metabolization_rate = 0.5 * REAGENTS_METABOLISM
overdose_threshold = 25
+ pH = 10.7
/datum/reagent/medicine/oxandrolone/on_mob_life(mob/living/carbon/M)
if(M.getFireLoss() > 50)
@@ -271,6 +286,7 @@
description = "If used in touch-based applications, immediately restores bruising as well as restoring more over time. If ingested through other means, deals minor toxin damage."
reagent_state = LIQUID
color = "#FF9696"
+ pH = 6.7
/datum/reagent/medicine/styptic_powder/reaction_mob(mob/living/M, method=TOUCH, reac_volume, show_message = 1)
if(iscarbon(M) && M.stat != DEAD)
@@ -283,6 +299,7 @@
if(show_message)
to_chat(M, "You feel your bruises healing! It stings like hell!")
M.emote("scream")
+ SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "painful_medicine", /datum/mood_event/painful_medicine)
..()
@@ -302,6 +319,7 @@
taste_description = "sweetness and salt"
var/last_added = 0
var/maximum_reachable = BLOOD_VOLUME_NORMAL - 10 //So that normal blood regeneration can continue with salglu active
+ pH = 5.5
/datum/reagent/medicine/salglu_solution/on_mob_life(mob/living/carbon/M)
if(last_added)
@@ -340,6 +358,7 @@
reagent_state = LIQUID
color = "#6D6374"
metabolization_rate = 0.4 * REAGENTS_METABOLISM
+ pH = 2.6
/datum/reagent/medicine/mine_salve/on_mob_life(mob/living/carbon/C)
C.hal_screwyhud = SCREWYHUD_HEALTHY
@@ -378,6 +397,7 @@
description = "Has a 100% chance of instantly healing brute and burn damage. One unit of the chemical will heal one point of damage. Touch application only."
reagent_state = LIQUID
color = "#FFEBEB"
+ pH = 11.5
/datum/reagent/medicine/synthflesh/reaction_mob(mob/living/M, method=TOUCH, reac_volume,show_message = 1)
if(iscarbon(M))
@@ -388,6 +408,7 @@
M.adjustFireLoss(-1.25 * reac_volume)
if(show_message)
to_chat(M, "You feel your burns and bruises healing! It stings like hell!")
+ SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "painful_medicine", /datum/mood_event/painful_medicine)
..()
/datum/reagent/medicine/charcoal
@@ -398,6 +419,7 @@
color = "#000000"
metabolization_rate = 0.5 * REAGENTS_METABOLISM
taste_description = "ash"
+ pH = 5
/datum/reagent/medicine/charcoal/on_mob_life(mob/living/carbon/M)
M.adjustToxLoss(-2*REM, 0)
@@ -415,6 +437,7 @@
color = "#DCDCDC"
metabolization_rate = 0.25 * REAGENTS_METABOLISM
overdose_threshold = 30
+ pH = 2
/datum/reagent/medicine/omnizine/on_mob_life(mob/living/carbon/M)
M.adjustToxLoss(-0.5*REM, 0)
@@ -440,6 +463,7 @@
color = "#19C832"
metabolization_rate = 0.5 * REAGENTS_METABOLISM
taste_description = "acid"
+ pH = 1.5
/datum/reagent/medicine/calomel/on_mob_life(mob/living/carbon/M)
for(var/datum/reagent/R in M.reagents.reagent_list)
@@ -457,6 +481,7 @@
reagent_state = LIQUID
color = "#14FF3C"
metabolization_rate = 2 * REAGENTS_METABOLISM
+ pH = 12 //It's a reducing agent
/datum/reagent/medicine/potass_iodide/on_mob_life(mob/living/carbon/M)
if(M.radiation > 0)
@@ -470,6 +495,7 @@
reagent_state = LIQUID
color = "#003153" // RGB 0, 49, 83
metabolization_rate = 0.5 * REAGENTS_METABOLISM
+ pH = 8.9
/datum/reagent/medicine/prussian_blue/on_mob_life(mob/living/carbon/M)
if(M.radiation > 0)
@@ -483,6 +509,7 @@
reagent_state = LIQUID
color = "#E6FFF0"
metabolization_rate = 0.5 * REAGENTS_METABOLISM
+ pH = 1 //One of the best buffers, NEVERMIND!
var/healtoxinlover = FALSE
/datum/reagent/medicine/pen_acid/on_mob_life(mob/living/carbon/M)
@@ -500,6 +527,7 @@
description = "Reduces massive amounts of radiation and toxin damage while purging other chemicals from the body. Slimepeople friendly!"
color = "#91D865"
healtoxinlover = TRUE
+ pH = 12//invert
/datum/reagent/medicine/sal_acid
name = "Salicyclic Acid"
@@ -509,6 +537,7 @@
color = "#D2D2D2"
metabolization_rate = 0.5 * REAGENTS_METABOLISM
overdose_threshold = 25
+ pH = 2.1
/datum/reagent/medicine/sal_acid/on_mob_life(mob/living/carbon/M)
@@ -532,6 +561,7 @@
reagent_state = LIQUID
color = "#00FFFF"
metabolization_rate = 0.25 * REAGENTS_METABOLISM
+ pH = 2
/datum/reagent/medicine/salbutamol/on_mob_life(mob/living/carbon/M)
M.adjustOxyLoss(-3*REM, 0)
@@ -547,6 +577,7 @@
reagent_state = LIQUID
color = "#FF6464"
metabolization_rate = 0.25 * REAGENTS_METABOLISM
+ pH = 11
/datum/reagent/medicine/perfluorodecalin/on_mob_life(mob/living/carbon/human/M)
M.adjustOxyLoss(-12*REM, 0)
@@ -566,6 +597,7 @@
metabolization_rate = 0.5 * REAGENTS_METABOLISM
overdose_threshold = 45
addiction_threshold = 30
+ pH = 12
/datum/reagent/medicine/ephedrine/on_mob_life(mob/living/carbon/M)
M.AdjustStun(-20, 0)
@@ -620,6 +652,7 @@
reagent_state = LIQUID
color = "#64FFE6"
metabolization_rate = 0.5 * REAGENTS_METABOLISM
+ pH = 11.5
/datum/reagent/medicine/diphenhydramine/on_mob_life(mob/living/carbon/M)
if(prob(10))
@@ -637,6 +670,7 @@
metabolization_rate = 0.5 * REAGENTS_METABOLISM
overdose_threshold = 30
addiction_threshold = 25
+ pH = 8.96
/datum/reagent/medicine/morphine/on_mob_metabolize(mob/living/L)
..()
@@ -705,6 +739,7 @@
color = "#FFFFFF"
metabolization_rate = 0.25 * REAGENTS_METABOLISM
taste_description = "dull toxin"
+ pH = 10
/datum/reagent/medicine/oculine/on_mob_life(mob/living/carbon/M)
var/obj/item/organ/eyes/eyes = M.getorganslot(ORGAN_SLOT_EYES)
@@ -736,6 +771,7 @@
color = "#000000"
metabolization_rate = 0.25 * REAGENTS_METABOLISM
overdose_threshold = 35
+ pH = 12
/datum/reagent/medicine/atropine/on_mob_life(mob/living/carbon/M)
if(M.health < 0)
@@ -765,6 +801,7 @@
color = "#D2FFFA"
metabolization_rate = 0.25 * REAGENTS_METABOLISM
overdose_threshold = 30
+ pH = 10.2
/datum/reagent/medicine/epinephrine/on_mob_life(mob/living/carbon/M)
if(M.health < 0)
@@ -801,6 +838,7 @@
color = "#A0E85E"
metabolization_rate = 0.5 * REAGENTS_METABOLISM
taste_description = "magnets"
+ pH = 0
/datum/reagent/medicine/strange_reagent/reaction_mob(mob/living/carbon/human/M, method=TOUCH, reac_volume)
if(M.stat == DEAD)
@@ -834,6 +872,7 @@
id = "mannitol"
description = "Efficiently restores brain damage."
color = "#DCDCFF"
+ pH = 10.4
/datum/reagent/medicine/mannitol/on_mob_life(mob/living/carbon/C)
C.adjustBrainLoss(-2*REM)
@@ -841,12 +880,26 @@
C.cure_trauma_type(resilience = TRAUMA_RESILIENCE_BASIC)
..()
+/datum/reagent/medicine/neurine
+ name = "Neurine"
+ id = "neurine"
+ description = "Reacts with neural tissue, helping reform damaged connections. Can cure minor traumas."
+ color = "#EEFF8F"
+
+/datum/reagent/medicine/neurine/on_mob_life(mob/living/carbon/C)
+ if(holder.has_reagent("neurotoxin"))
+ holder.remove_reagent("neurotoxin", 5)
+ if(prob(15))
+ C.cure_trauma_type(resilience = TRAUMA_RESILIENCE_BASIC)
+ ..()
+
/datum/reagent/medicine/mutadone
name = "Mutadone"
id = "mutadone"
description = "Removes jitteriness and restores genetic defects."
color = "#5096C8"
taste_description = "acid"
+ pH = 2
/datum/reagent/medicine/mutadone/on_mob_life(mob/living/carbon/M)
M.jitteriness = 0
@@ -861,6 +914,7 @@
description = "Purges alcoholic substance from the patient's body and eliminates its side effects."
color = "#00B4C8"
taste_description = "raw egg"
+ pH = 4
/datum/reagent/medicine/antihol/on_mob_life(mob/living/carbon/M)
M.dizziness = 0
@@ -882,6 +936,7 @@
color = "#78008C"
metabolization_rate = 0.5 * REAGENTS_METABOLISM
overdose_threshold = 60
+ pH = 8.7
/datum/reagent/medicine/stimulants/on_mob_metabolize(mob/living/L)
..()
@@ -919,6 +974,7 @@
reagent_state = LIQUID
color = "#FFFFF0"
metabolization_rate = 0.5 * REAGENTS_METABOLISM
+ pH = 6.7
/datum/reagent/medicine/insulin/on_mob_life(mob/living/carbon/M)
if(M.AdjustSleeping(-20, FALSE))
@@ -934,6 +990,7 @@
reagent_state = LIQUID
color = "#fc2626"
overdose_threshold = 30
+ pH = 5
/datum/reagent/medicine/bicaridine/on_mob_life(mob/living/carbon/M)
M.adjustBruteLoss(-2*REM, 0)
@@ -952,6 +1009,7 @@
reagent_state = LIQUID
color = "#13d2f0"
overdose_threshold = 30
+ pH = 9.7
/datum/reagent/medicine/dexalin/on_mob_life(mob/living/carbon/M)
M.adjustOxyLoss(-2*REM, 0)
@@ -970,6 +1028,7 @@
reagent_state = LIQUID
color = "#ffc400"
overdose_threshold = 30
+ pH = 9
/datum/reagent/medicine/kelotane/on_mob_life(mob/living/carbon/M)
M.adjustFireLoss(-2*REM, 0)
@@ -989,6 +1048,7 @@
color = "#6aff00"
overdose_threshold = 30
taste_description = "a roll of gauze"
+ pH = 10
/datum/reagent/medicine/antitoxin/on_mob_life(mob/living/carbon/M)
M.adjustToxLoss(-2*REM, 0)
@@ -1007,6 +1067,7 @@
id = "inaprovaline"
description = "Stabilizes the breathing of patients. Good for those in critical condition."
reagent_state = LIQUID
+ pH = 8.5
color = "#5dc1f0"
/datum/reagent/medicine/inaprovaline/on_mob_life(mob/living/carbon/M)
@@ -1062,6 +1123,7 @@
description = "Miniature medical robots that swiftly restore bodily damage."
reagent_state = SOLID
color = "#555555"
+ pH = 11
/datum/reagent/medicine/syndicate_nanites/on_mob_life(mob/living/carbon/M)
M.adjustBruteLoss(-5*REM, 0) //A ton of healing - this is a 50 telecrystal investment.
@@ -1075,14 +1137,15 @@
. = 1
/datum/reagent/medicine/neo_jelly
- name = "Neo Jelly"
- id = "neo_jelly"
- description = "Gradually regenerates all types of damage, without harming slime anatomy.Can OD"
- reagent_state = LIQUID
- metabolization_rate = 1 * REAGENTS_METABOLISM
- color = "#91D865"
- overdose_threshold = 30
- taste_description = "jelly"
+ name = "Neo Jelly"
+ id = "neo_jelly"
+ description = "Gradually regenerates all types of damage, without harming slime anatomy.Can OD"
+ reagent_state = LIQUID
+ metabolization_rate = 1 * REAGENTS_METABOLISM
+ color = "#91D865"
+ overdose_threshold = 30
+ taste_description = "jelly"
+ pH = 11.8
/datum/reagent/medicine/neo_jelly/on_mob_life(mob/living/carbon/M)
M.adjustBruteLoss(-1.5*REM, 0)
@@ -1105,6 +1168,7 @@
description = "Ichor from an extremely powerful plant. Great for restoring wounds, but it's a little heavy on the brain."
color = rgb(255, 175, 0)
overdose_threshold = 25
+ pH = 11
/datum/reagent/medicine/earthsblood/on_mob_life(mob/living/carbon/M)
M.adjustBruteLoss(-3 * REM, 0)
@@ -1132,6 +1196,7 @@
reagent_state = LIQUID
color = "#27870a"
metabolization_rate = 0.4 * REAGENTS_METABOLISM
+ pH = 4.3
/datum/reagent/medicine/haloperidol/on_mob_life(mob/living/carbon/M)
for(var/datum/reagent/drug/R in M.reagents.reagent_list)
@@ -1154,6 +1219,7 @@
color = "#a1a1a1"
overdose_threshold = 3 //To prevent people stacking massive amounts of a very strong healing reagent
can_synth = FALSE
+ pH = 14
/datum/reagent/medicine/lavaland_extract/on_mob_life(mob/living/carbon/M)
M.heal_bodypart_damage(5,5)
@@ -1217,6 +1283,7 @@
description = "A medication used to treat pain, fever, and inflammation, along with heart attacks."
color = "#F5F5F5"
self_consuming = TRUE
+ pH = 12.5
/datum/reagent/medicine/corazone/on_mob_metabolize(mob/living/M)
..()
@@ -1249,6 +1316,7 @@
overdose_threshold = 20 // with the random effects this might be awesome or might kill you at less than 10u (extensively tested)
taste_description = "salt" // it actually does taste salty
var/overdose_progress = 0 // to track overdose progress
+ pH = 7.89
/datum/reagent/medicine/modafinil/on_mob_metabolize(mob/living/M)
ADD_TRAIT(M, TRAIT_SLEEPIMMUNE, id)
@@ -1305,3 +1373,38 @@
M.adjustStaminaLoss(1.5*REM, 0)
..()
return TRUE
+
+/datum/reagent/medicine/psicodine
+ name = "Psicodine"
+ id = "psicodine"
+ description = "Suppresses anxiety and other various forms of mental distress. Overdose causes hallucinations and minor toxin damage."
+ reagent_state = LIQUID
+ color = "#07E79E"
+ metabolization_rate = 0.25 * REAGENTS_METABOLISM
+ overdose_threshold = 30
+ pH = 9.12
+
+/datum/reagent/medicine/psicodine/on_mob_add(mob/living/L)
+ ..()
+ ADD_TRAIT(L, TRAIT_FEARLESS, id)
+
+/datum/reagent/medicine/psicodine/on_mob_delete(mob/living/L)
+ REMOVE_TRAIT(L, TRAIT_FEARLESS, id)
+ ..()
+
+/datum/reagent/medicine/psicodine/on_mob_life(mob/living/carbon/M)
+ M.jitteriness = max(0, M.jitteriness-6)
+ M.dizziness = max(0, M.dizziness-6)
+ M.confused = max(0, M.confused-6)
+ M.disgust = max(0, M.disgust-6)
+ GET_COMPONENT_FROM(mood, /datum/component/mood, M)
+ if(mood.sanity <= SANITY_NEUTRAL) // only take effect if in negative sanity and then...
+ mood.setSanity(min(mood.sanity+5, SANITY_NEUTRAL)) // set minimum to prevent unwanted spiking over neutral
+ ..()
+ . = 1
+
+/datum/reagent/medicine/psicodine/overdose_process(mob/living/M)
+ M.hallucination = min(max(0, M.hallucination + 5), 60)
+ M.adjustToxLoss(1, 0)
+ ..()
+ . = 1
diff --git a/code/modules/reagents/chemistry/reagents/other_reagents.dm b/code/modules/reagents/chemistry/reagents/other_reagents.dm
index 42b012d52f..07c9b166ff 100644
--- a/code/modules/reagents/chemistry/reagents/other_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/other_reagents.dm
@@ -10,6 +10,7 @@
glass_name = "glass of tomato juice"
glass_desc = "Are you sure this is tomato juice?"
shot_glass_icon_state = "shotglassred"
+ pH = 7.4
/datum/reagent/blood/reaction_mob(mob/living/L, method=TOUCH, reac_volume)
if(data && data["viruses"])
@@ -95,6 +96,7 @@
description = "You don't even want to think about what's in here."
taste_description = "gross iron"
shot_glass_icon_state = "shotglassred"
+ pH = 7.45
/datum/reagent/vaccine
//data must contain virus type
@@ -195,6 +197,7 @@
glass_icon_state = "glass_clear"
glass_name = "glass of holy water"
glass_desc = "A glass of holy water."
+ pH = 7.5 //God is alkaline
/datum/reagent/water/holywater/on_mob_metabolize(mob/living/L)
..()
@@ -271,6 +274,7 @@
id = "unholywater"
description = "Something that shouldn't exist on this plane of existence."
taste_description = "suffering"
+ pH = 6.5
/datum/reagent/fuel/unholywater/reaction_mob(mob/living/M, method=TOUCH, reac_volume)
if(method == TOUCH || method == VAPOR)
@@ -289,7 +293,7 @@
M.adjustOxyLoss(-2, 0)
M.adjustBruteLoss(-2, 0)
M.adjustFireLoss(-2, 0)
- if(ishuman(M) && M.blood_volume < BLOOD_VOLUME_NORMAL)
+ if(ishuman(M) && M.blood_volume < (BLOOD_VOLUME_NORMAL*M.blood_ratio))
M.blood_volume += 3
else // Will deal about 90 damage when 50 units are thrown
M.adjustBrainLoss(3, 150)
@@ -313,6 +317,7 @@
M.adjustFireLoss(1, 0) //Hence the other damages... ain't I a bastard?
M.adjustBrainLoss(5, 150)
holder.remove_reagent(id, 1)
+ pH = 0.1
/datum/reagent/fuel/holyoil //Its oil
name = "Zelus Oil"
@@ -346,7 +351,7 @@
//We only get 30u to start with...
/datum/reagent/fuel/holyoil/reaction_obj(obj/O, reac_volume)
- . = ..()
+ . = ..()
if(istype(O, /obj/item/stack/sheet/metal))
var/obj/item/stack/sheet/metal/M = O
reac_volume = min(reac_volume, M.amount)
@@ -380,6 +385,7 @@
metabolization_rate = 10 * REAGENTS_METABOLISM // very fast, so it can be applied rapidly. But this changes on an overdose
overdose_threshold = 11 //Slightly more than one un-nozzled spraybottle.
taste_description = "sour oranges"
+ pH = 5
/datum/reagent/spraytan/reaction_mob(mob/living/M, method=TOUCH, reac_volume, show_message = 1)
if(ishuman(M))
@@ -704,6 +710,7 @@
color = "#202040" // rgb: 20, 20, 40
metabolization_rate = 0.25 * REAGENTS_METABOLISM
taste_description = "bitterness"
+ pH = 10
/datum/reagent/serotrotium/on_mob_life(mob/living/carbon/M)
if(ishuman(M))
@@ -718,6 +725,7 @@
reagent_state = GAS
color = "#808080" // rgb: 128, 128, 128
taste_mult = 0 // oderless and tasteless
+ pH = 9.2//It's acutally a huge range and very dependant on the chemistry but pH is basically a made up var in it's implementation anyways
/datum/reagent/oxygen/reaction_obj(obj/O, reac_volume)
if((!O) || (!reac_volume))
@@ -738,6 +746,7 @@
reagent_state = SOLID
color = "#6E3B08" // rgb: 110, 59, 8
taste_description = "metal"
+ pH = 5.5
/datum/reagent/copper/reaction_obj(obj/O, reac_volume)
if(istype(O, /obj/item/stack/sheet/metal))
@@ -754,6 +763,7 @@
color = "#808080" // rgb: 128, 128, 128
taste_mult = 0
+
/datum/reagent/nitrogen/reaction_obj(obj/O, reac_volume)
if((!O) || (!reac_volume))
return 0
@@ -773,6 +783,7 @@
reagent_state = GAS
color = "#808080" // rgb: 128, 128, 128
taste_mult = 0
+ pH = 0.1//Now I'm stuck in a trap of my own design. Maybe I should make -ve pHes? (not 0 so I don't get div/0 errors)
/datum/reagent/potassium
name = "Potassium"
@@ -804,6 +815,7 @@
reagent_state = SOLID
color = "#BF8C00" // rgb: 191, 140, 0
taste_description = "rotten eggs"
+ pH = 4.5
/datum/reagent/carbon
name = "Carbon"
@@ -812,6 +824,7 @@
reagent_state = SOLID
color = "#1C1300" // rgb: 30, 20, 0
taste_description = "sour chalk"
+ pH = 5
/datum/reagent/carbon/reaction_turf(turf/T, reac_volume)
if(!isspaceturf(T))
@@ -826,6 +839,7 @@
reagent_state = GAS
color = "#808080" // rgb: 128, 128, 128
taste_description = "chlorine"
+ pH = 7.4
/datum/reagent/chlorine/on_mob_life(mob/living/carbon/M)
M.take_bodypart_damage(1*REM, 0, 0, 0)
@@ -839,6 +853,7 @@
reagent_state = GAS
color = "#808080" // rgb: 128, 128, 128
taste_description = "acid"
+ pH = 2
/datum/reagent/fluorine/on_mob_life(mob/living/carbon/M)
M.adjustToxLoss(1*REM, 0)
@@ -852,6 +867,7 @@
reagent_state = SOLID
color = "#808080" // rgb: 128, 128, 128
taste_description = "salty metal"
+ pH = 11.6
/datum/reagent/phosphorus
name = "Phosphorus"
@@ -860,6 +876,7 @@
reagent_state = SOLID
color = "#832828" // rgb: 131, 40, 40
taste_description = "vinegar"
+ pH = 6.5
/datum/reagent/lithium
name = "Lithium"
@@ -868,6 +885,7 @@
reagent_state = SOLID
color = "#808080" // rgb: 128, 128, 128
taste_description = "metal"
+ pH = 11.3
/datum/reagent/lithium/on_mob_life(mob/living/carbon/M)
if(M.canmove && !isspaceturf(M.loc))
@@ -882,6 +900,7 @@
description = "Glycerol is a simple polyol compound. Glycerol is sweet-tasting and of low toxicity."
color = "#808080" // rgb: 128, 128, 128
taste_description = "sweetness"
+ pH = 9
/datum/reagent/radium
name = "Radium"
@@ -890,6 +909,7 @@
reagent_state = SOLID
color = "#C7C7C7" // rgb: 199,199,199
taste_description = "the colour blue and regret"
+ pH = 10
/datum/reagent/radium/on_mob_life(mob/living/carbon/M)
M.apply_effect(2*REM/M.metabolism_efficiency,EFFECT_IRRADIATE,0)
@@ -909,6 +929,7 @@
description = "Sterilizes wounds in preparation for surgery."
color = "#e6f1f5" // rgb: 200, 165, 220
taste_description = "bitterness"
+ pH = 10.5
/datum/reagent/space_cleaner/sterilizine/reaction_mob(mob/living/carbon/C, method=TOUCH, reac_volume)
if(method in list(TOUCH, VAPOR, PATCH))
@@ -924,11 +945,12 @@
description = "Pure iron is a metal."
reagent_state = SOLID
taste_description = "iron"
+ pH = 6
color = "#c2391d"
/datum/reagent/iron/on_mob_life(mob/living/carbon/C)
- if(C.blood_volume < BLOOD_VOLUME_NORMAL)
+ if(C.blood_volume < (BLOOD_VOLUME_NORMAL*C.blood_ratio))
C.blood_volume += 0.5
..()
@@ -966,6 +988,7 @@
reagent_state = SOLID
color = "#B8B8C0" // rgb: 184, 184, 192
taste_description = "the inside of a reactor"
+ pH = 4
/datum/reagent/uranium/on_mob_life(mob/living/carbon/M)
M.apply_effect(1/M.metabolism_efficiency,EFFECT_IRRADIATE,0)
@@ -986,10 +1009,11 @@
reagent_state = SOLID
color = "#0000CC"
taste_description = "fizzling blue"
+ pH = 12
/datum/reagent/bluespace/reaction_mob(mob/living/M, method=TOUCH, reac_volume)
if(method == TOUCH || method == VAPOR)
- do_teleport(M, get_turf(M), (reac_volume / 5), asoundin = 'sound/effects/phasein.ogg') //4 tiles per crystal
+ do_teleport(M, get_turf(M), (reac_volume / 5), asoundin = 'sound/effects/phasein.ogg', channel = TELEPORT_CHANNEL_BLUESPACE) //4 tiles per crystal
..()
/datum/reagent/bluespace/on_mob_life(mob/living/carbon/M)
@@ -1001,7 +1025,7 @@
..()
/mob/living/proc/bluespace_shuffle()
- do_teleport(src, get_turf(src), 5, asoundin = 'sound/effects/phasein.ogg')
+ do_teleport(src, get_turf(src), 5, asoundin = 'sound/effects/phasein.ogg', channel = TELEPORT_CHANNEL_BLUESPACE)
/datum/reagent/aluminium
name = "Aluminium"
@@ -1018,6 +1042,7 @@
reagent_state = SOLID
color = "#A8A8A8" // rgb: 168, 168, 168
taste_mult = 0
+ pH = 10
/datum/reagent/fuel
name = "Welding fuel"
@@ -1028,6 +1053,8 @@
glass_icon_state = "dr_gibb_glass"
glass_name = "glass of welder fuel"
glass_desc = "Unless you're an industrial tool, this is probably not safe for consumption."
+ pH = 4
+
/datum/reagent/fuel/reaction_mob(mob/living/M, method=TOUCH, reac_volume)//Splashing people with welding fuel to make them easy to ignite!
if(method == TOUCH || method == VAPOR)
@@ -1046,6 +1073,7 @@
description = "A compound used to clean things. Now with 50% more sodium hypochlorite!"
color = "#A5F0EE" // rgb: 165, 240, 238
taste_description = "sourness"
+ pH = 5.5
/datum/reagent/space_cleaner/reaction_obj(obj/O, reac_volume)
if(istype(O, /obj/effect/decal/cleanable))
@@ -1103,6 +1131,7 @@
description = "A powerful, acidic cleaner sold by Waffle Co. Affects organic matter while leaving other objects unaffected."
metabolization_rate = 1.5 * REAGENTS_METABOLISM
taste_description = "acid"
+ pH = 2
/datum/reagent/space_cleaner/ez_clean/on_mob_life(mob/living/carbon/M)
M.adjustBruteLoss(3.33)
@@ -1123,6 +1152,7 @@
color = "#7529b3" // rgb: 200, 165, 220
metabolization_rate = 1.5 * REAGENTS_METABOLISM
taste_description = "sourness"
+ pH = 11.9
/datum/reagent/cryptobiolin/on_mob_life(mob/living/carbon/M)
M.Dizzy(1)
@@ -1137,6 +1167,7 @@
description = "Impedrezene is a narcotic that impedes one's ability by slowing down the higher brain cell functions."
color = "#587a31" // rgb: 200, 165, 220A
taste_description = "numbness"
+ pH = 9.1
/datum/reagent/impedrezene/on_mob_life(mob/living/carbon/M)
M.jitteriness = max(M.jitteriness-5,0)
@@ -1179,6 +1210,7 @@
color = "#92D17D" // rgb: 146, 209, 125
can_synth = FALSE
taste_description = "slime"
+ pH = 11
/datum/reagent/fungalspores/reaction_mob(mob/living/L, method=TOUCH, reac_volume, show_message = 1, touch_protection = 0)
if(method==PATCH || method==INGEST || method==INJECT || (method == VAPOR && prob(min(reac_volume,100)*(1 - touch_protection))))
@@ -1190,6 +1222,7 @@
description = "A perfluoronated sulfonic acid that forms a foam when mixed with water."
color = "#9E6B38" // rgb: 158, 107, 56
taste_description = "metal"
+ pH = 13
/datum/reagent/foaming_agent// Metal foaming agent. This is lithium hydride. Add other recipes (e.g. LiH + H2O -> LiOH + H2) eventually.
name = "Foaming agent"
@@ -1198,6 +1231,7 @@
reagent_state = SOLID
color = "#664B63" // rgb: 102, 75, 99
taste_description = "metal"
+ pH = 12.5
/datum/reagent/smart_foaming_agent //Smart foaming agent. Functions similarly to metal foam, but conforms to walls.
name = "Smart foaming agent"
@@ -1206,6 +1240,7 @@
reagent_state = SOLID
color = "#664B63" // rgb: 102, 75, 99
taste_description = "metal"
+ pH = 11.8
/datum/reagent/ammonia
name = "Ammonia"
@@ -1214,6 +1249,7 @@
reagent_state = GAS
color = "#404030" // rgb: 64, 64, 48
taste_description = "mordant"
+ pH = 11.6
/datum/reagent/diethylamine
name = "Diethylamine"
@@ -1221,6 +1257,7 @@
description = "A secondary amine, mildly corrosive."
color = "#604030" // rgb: 96, 64, 48
taste_description = "iron"
+ pH = 12
/datum/reagent/carbondioxide
name = "Carbon Dioxide"
@@ -1229,6 +1266,7 @@
description = "A gas commonly produced by burning carbon fuels. You're constantly producing this in your lungs."
color = "#B0B0B0" // rgb : 192, 192, 192
taste_description = "something unknowable"
+ pH = 6
/datum/reagent/carbondioxide/reaction_obj(obj/O, reac_volume)
if((!O) || (!reac_volume))
@@ -1250,6 +1288,7 @@
metabolization_rate = 1.5 * REAGENTS_METABOLISM
color = "#808080"
taste_description = "sweetness"
+ pH = 5.8
/datum/reagent/nitrous_oxide/reaction_obj(obj/O, reac_volume)
if((!O) || (!reac_volume))
@@ -1309,6 +1348,7 @@
metabolization_rate = REAGENTS_METABOLISM
color = "90560B"
taste_description = "burning"
+ pH = 2
/datum/reagent/nitryl/on_mob_metabolize(mob/living/L)
..()
@@ -1342,6 +1382,7 @@
colorname = "red"
color = "#DA0000" // red
random_color_list = list("#DA0000")
+ pH = 0.5
/datum/reagent/colorful_reagent/crayonpowder/orange
name = "Orange Crayon Powder"
@@ -1349,6 +1390,7 @@
colorname = "orange"
color = "#FF9300" // orange
random_color_list = list("#FF9300")
+ pH = 2
/datum/reagent/colorful_reagent/crayonpowder/yellow
name = "Yellow Crayon Powder"
@@ -1356,6 +1398,7 @@
colorname = "yellow"
color = "#FFF200" // yellow
random_color_list = list("#FFF200")
+ pH = 5
/datum/reagent/colorful_reagent/crayonpowder/green
name = "Green Crayon Powder"
@@ -1364,12 +1407,14 @@
color = "#A8E61D" // green
random_color_list = list("#A8E61D")
+
/datum/reagent/colorful_reagent/crayonpowder/blue
name = "Blue Crayon Powder"
id = "bluecrayonpowder"
colorname = "blue"
color = "#00B7EF" // blue
random_color_list = list("#00B7EF")
+ pH = 10
/datum/reagent/colorful_reagent/crayonpowder/purple
name = "Purple Crayon Powder"
@@ -1377,6 +1422,7 @@
colorname = "purple"
color = "#DA00FF" // purple
random_color_list = list("#DA00FF")
+ pH = 13
/datum/reagent/colorful_reagent/crayonpowder/invisible
name = "Invisible Crayon Powder"
@@ -1411,6 +1457,7 @@
color = "#000000" // RBG: 0, 0, 0
var/tox_prob = 0
taste_description = "plant food"
+ pH = 3
/datum/reagent/plantnutriment/on_mob_life(mob/living/carbon/M)
if(prob(tox_prob))
@@ -1424,6 +1471,7 @@
description = "Cheap and extremely common type of plant nutriment."
color = "#376400" // RBG: 50, 100, 0
tox_prob = 10
+ pH = 2
/datum/reagent/plantnutriment/left4zednutriment
name = "Left 4 Zed"
@@ -1431,6 +1479,7 @@
description = "Unstable nutriment that makes plants mutate more often than usual."
color = "#1A1E4D" // RBG: 26, 30, 77
tox_prob = 25
+ pH = 1.5
/datum/reagent/plantnutriment/robustharvestnutriment
name = "Robust Harvest"
@@ -1438,6 +1487,7 @@
description = "Very potent nutriment that prevents plants from mutating."
color = "#9D9D00" // RBG: 157, 157, 0
tox_prob = 15
+ pH = 1
@@ -1465,6 +1515,7 @@
color = "#6b008f"
taste_description = "bitterness"
taste_mult = 1.5
+ pH = 1.5
/datum/reagent/stable_plasma/on_mob_life(mob/living/carbon/C)
C.adjustPlasma(10)
@@ -1477,6 +1528,7 @@
reagent_state = LIQUID
color = "#694600"
taste_description = "metal"
+ pH = 4.5
/datum/reagent/carpet
name = "Carpet"
@@ -1499,14 +1551,16 @@
reagent_state = LIQUID
color = "#b37740"
taste_description = "chemicals"
+ pH = 7.8
/datum/reagent/phenol
name = "Phenol"
id = "phenol"
description = "An aromatic ring of carbon with a hydroxyl group. A useful precursor to some medicines, but has no healing properties on its own."
reagent_state = LIQUID
+ taste_description = "sweet and tarry" //Again, not a strong acid.
+ pH = 5.5
color = "#e6e8ff"
- taste_description = "acid"
/datum/reagent/ash
name = "Ash"
@@ -1515,14 +1569,15 @@
reagent_state = LIQUID
color = "#665c56"
taste_description = "ash"
+ pH = 6.5
/datum/reagent/acetone
name = "Acetone"
id = "acetone"
description = "A slick, slightly carcinogenic liquid. Has a multitude of mundane uses in everyday life."
reagent_state = LIQUID
+ taste_description = "solvent"//It's neutral though..?
color = "#e6e6e6"
- taste_description = "acid"
/datum/reagent/colorful_reagent
name = "Colorful Reagent"
@@ -1612,6 +1667,7 @@
reagent_state = LIQUID
color = "#60A584" // rgb: 96, 165, 132
taste_description = "cool salt"
+ pH = 11.2
/datum/reagent/lye
name = "Lye"
@@ -1619,7 +1675,8 @@
description = "Also known as sodium hydroxide. As a profession making this is somewhat underwhelming."
reagent_state = LIQUID
color = "#FFFFD6" // very very light yellow
- taste_description = "acid"
+ taste_description = "alkali" //who put ACID for NaOH ????
+ pH = 13
/datum/reagent/drying_agent
name = "Drying agent"
@@ -1628,6 +1685,7 @@
reagent_state = LIQUID
color = "#A70FFF"
taste_description = "dryness"
+ pH = 10.7
/datum/reagent/drying_agent/reaction_turf(turf/open/T, reac_volume)
if(istype(T))
@@ -1699,6 +1757,7 @@
description = "Royal Bee Jelly, if injected into a Queen Space Bee said bee will split into two bees."
color = "#00ff80"
taste_description = "strange honey"
+ pH = 3
/datum/reagent/royal_bee_jelly/on_mob_life(mob/living/carbon/M)
if(prob(2))
@@ -1720,6 +1779,7 @@
metabolization_rate = INFINITY
can_synth = FALSE
taste_description = "brains"
+ pH = 0.5
/datum/reagent/romerol/reaction_mob(mob/living/carbon/human/H, method=TOUCH, reac_volume)
// Silently add the zombie infection organ to be activated upon death
@@ -1778,6 +1838,7 @@
description = "the petroleum based components of plastic."
color = "#f7eded"
taste_description = "plastic"
+ pH = 6
/datum/reagent/glitter
name = "generic glitter"
@@ -1820,6 +1881,7 @@
color = "#AAAAAA55"
taste_description = "water"
metabolization_rate = 0.25 * REAGENTS_METABOLISM
+ pH = 15
/datum/reagent/pax/on_mob_metabolize(mob/living/L)
..()
@@ -1908,6 +1970,13 @@
color = "#FAEAFF"
taste_description = "synthetic catnip"
+/datum/reagent/moonsugar/on_mob_life(mob/living/carbon/M)
+ if(prob(20))
+ to_chat(M, "You find yourself unable to supress the desire to meow!")
+ M.emote("nya")
+ ..()
+
+//Kept for legacy, I think it will break everything if you enable it.
/datum/reagent/penis_enlargement
name = "Penis Enlargement"
id = "penis_enlargement"
@@ -1924,3 +1993,41 @@
P.length += added_length
P.update()
..()
+
+/datum/reagent/changeling_string
+ name = "UNKNOWN"
+ id = "changeling_sting_real"
+ description = "404: Chemical not found."
+ metabolization_rate = REAGENTS_METABOLISM
+ color = "#0000FF"
+ can_synth = FALSE
+ var/datum/dna/original_dna
+ var/reagent_ticks = 0
+ invisible = TRUE
+
+/datum/reagent/changeling_string/on_mob_metabolize(mob/living/carbon/C)
+ if(C && C.dna && data["desired_dna"])
+ original_dna = new C.dna.type
+ C.dna.copy_dna(original_dna)
+ var/datum/dna/new_dna = data["desired_dna"]
+ new_dna.copy_dna(C.dna)
+ C.real_name = new_dna.real_name
+ C.updateappearance(mutcolor_update=1)
+ C.update_body()
+ C.domutcheck()
+ C.regenerate_icons()
+ ..()
+
+/datum/reagent/changeling_string/on_mob_end_metabolize(mob/living/carbon/C)
+ if(original_dna)
+ original_dna.copy_dna(C.dna)
+ C.real_name = original_dna.real_name
+ C.updateappearance(mutcolor_update=1)
+ C.update_body()
+ C.domutcheck()
+ C.regenerate_icons()
+ ..()
+
+/datum/reagent/changeling_string/Destroy()
+ qdel(original_dna)
+ return ..()
diff --git a/code/modules/reagents/chemistry/reagents/toxin_reagents.dm b/code/modules/reagents/chemistry/reagents/toxin_reagents.dm
index 6bd165f23e..2848c336e2 100644
--- a/code/modules/reagents/chemistry/reagents/toxin_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/toxin_reagents.dm
@@ -23,6 +23,7 @@
color = "#792300" // rgb: 121, 35, 0
toxpwr = 2.5
taste_description = "mushroom"
+ pH = 13
/datum/reagent/toxin/mutagen
name = "Unstable mutagen"
@@ -32,6 +33,7 @@
toxpwr = 0
taste_description = "slime"
taste_mult = 0.9
+ pH = 2
/datum/reagent/toxin/mutagen/reaction_mob(mob/living/carbon/M, method=TOUCH, reac_volume)
if(!..())
@@ -61,6 +63,7 @@
taste_mult = 1.5
color = "#8228A0"
toxpwr = 3
+ pH = 4
/datum/reagent/toxin/plasma/on_mob_life(mob/living/carbon/C)
if(holder.has_reagent("epinephrine"))
@@ -93,6 +96,7 @@
color = "#7DC3A0"
toxpwr = 0
taste_description = "acid"
+ pH = 1.2
/datum/reagent/toxin/lexorin/on_mob_life(mob/living/carbon/C)
. = TRUE
@@ -115,6 +119,7 @@
toxpwr = 0
taste_description = "slime"
taste_mult = 1.3
+ pH = 10
/datum/reagent/toxin/slimejelly/on_mob_life(mob/living/carbon/M)
if(prob(10))
@@ -133,6 +138,7 @@
color = "#CF3600" // rgb: 207, 54, 0
toxpwr = 0
taste_description = "mint"
+ pH = 8
/datum/reagent/toxin/minttoxin/on_mob_life(mob/living/carbon/M)
if(HAS_TRAIT(M, TRAIT_FAT))
@@ -146,6 +152,7 @@
color = "#003333" // rgb: 0, 51, 51
toxpwr = 2
taste_description = "fish"
+ pH = 12
/datum/reagent/toxin/zombiepowder
name = "Zombie Powder"
@@ -155,6 +162,7 @@
color = "#669900" // rgb: 102, 153, 0
toxpwr = 0.5
taste_description = "death"
+ pH = 13
/datum/reagent/toxin/zombiepowder/on_mob_metabolize(mob/living/L)
..()
@@ -177,6 +185,7 @@
color = "#664700" // rgb: 102, 71, 0
toxpwr = 0.8
taste_description = "death"
+ pH = 14.5
/datum/reagent/toxin/ghoulpowder/on_mob_metabolize(mob/living/L)
..()
@@ -198,6 +207,7 @@
color = "#B31008" // rgb: 139, 166, 233
toxpwr = 0
taste_description = "sourness"
+ pH = 11
/datum/reagent/toxin/mindbreaker/on_mob_life(mob/living/carbon/M)
M.hallucination += 5
@@ -210,6 +220,7 @@
color = "#49002E" // rgb: 73, 0, 46
toxpwr = 1
taste_mult = 1
+ pH = 2
/datum/reagent/toxin/plantbgone/reaction_obj(obj/O, reac_volume)
if(istype(O, /obj/structure/alien/weeds))
@@ -234,6 +245,7 @@
id = "weedkiller"
description = "A harmful toxic mixture to kill weeds. Do not ingest!"
color = "#4B004B" // rgb: 75, 0, 75
+ pH = 3
/datum/reagent/toxin/pestkiller
name = "Pest Killer"
@@ -241,6 +253,7 @@
description = "A harmful toxic mixture to kill pests. Do not ingest!"
color = "#4B004B" // rgb: 75, 0, 75
toxpwr = 1
+ pH = 3.2
/datum/reagent/toxin/pestkiller/reaction_mob(mob/living/M, method=TOUCH, reac_volume)
..()
@@ -254,6 +267,7 @@
description = "A natural toxin produced by blob spores that inhibits vision when ingested."
color = "#9ACD32"
toxpwr = 1
+ pH = 11
/datum/reagent/toxin/spore/on_mob_life(mob/living/carbon/C)
C.damageoverlaytemp = 60
@@ -268,6 +282,7 @@
color = "#9ACD32"
toxpwr = 0.5
taste_description = "burning"
+ pH = 13
/datum/reagent/toxin/spore_burning/on_mob_life(mob/living/carbon/M)
M.adjust_fire_stacks(2)
@@ -282,6 +297,7 @@
color = "#000067" // rgb: 0, 0, 103
toxpwr = 0
metabolization_rate = 1.5 * REAGENTS_METABOLISM
+ pH = 11
/datum/reagent/toxin/chloralhydrate/on_mob_life(mob/living/carbon/M)
switch(current_cycle)
@@ -326,6 +342,7 @@
glass_icon_state = "beerglass"
glass_name = "glass of beer"
glass_desc = "A freezing pint of beer."
+ pH = 2
/datum/reagent/toxin/fakebeer/on_mob_life(mob/living/carbon/M)
switch(current_cycle)
@@ -343,6 +360,7 @@
reagent_state = SOLID
color = "#5B2E0D" // rgb: 91, 46, 13
toxpwr = 0.5
+ pH = 4.2
/datum/reagent/toxin/teapowder
name = "Ground Tea Leaves"
@@ -351,6 +369,7 @@
reagent_state = SOLID
color = "#7F8400" // rgb: 127, 132, 0
toxpwr = 0.5
+ pH = 4.9
/datum/reagent/toxin/mutetoxin //the new zombie powder.
name = "Mute Toxin"
@@ -359,6 +378,7 @@
color = "#F0F8FF" // rgb: 240, 248, 255
toxpwr = 0
taste_description = "silence"
+ pH = 12.2
/datum/reagent/toxin/mutetoxin/on_mob_life(mob/living/carbon/M)
M.silent = max(M.silent, 3)
@@ -816,6 +836,7 @@
var/acidpwr = 10 //the amount of protection removed from the armour
taste_description = "acid"
self_consuming = TRUE
+ pH = 2.75
/datum/reagent/toxin/acid/reaction_mob(mob/living/carbon/C, method=TOUCH, reac_volume)
if(!istype(C))
diff --git a/code/modules/reagents/chemistry/recipes.dm b/code/modules/reagents/chemistry/recipes.dm
index 50006eef62..32155c9b89 100644
--- a/code/modules/reagents/chemistry/recipes.dm
+++ b/code/modules/reagents/chemistry/recipes.dm
@@ -17,6 +17,24 @@
var/mix_message = "The solution begins to bubble." //The message shown to nearby people upon mixing, if applicable
var/mix_sound = 'sound/effects/bubbles.ogg' //The sound played upon mixing, if applicable
+ //FermiChem!
+ var/OptimalTempMin = 200 // Lower area of bell curve for determining heat based rate reactions
+ var/OptimalTempMax = 800 // Upper end for above
+ var/ExplodeTemp = 900 // Temperature at which reaction explodes - If any reaction is this hot, it explodes!
+ var/OptimalpHMin = 5 // Lowest value of pH determining pH a 1 value for pH based rate reactions (Plateu phase)
+ var/OptimalpHMax = 10 // Higest value for above
+ var/ReactpHLim = 3 // How far out pH wil react, giving impurity place (Exponential phase)
+ var/CatalystFact = 0 // How much the catalyst affects the reaction (0 = no catalyst)//Not implemented yet
+ var/CurveSharpT = 2 // How sharp the temperature exponential curve is (to the power of value)
+ var/CurveSharppH = 2 // How sharp the pH exponential curve is (to the power of value)
+ var/ThermicConstant = 1 // Temperature change per 1u produced
+ var/HIonRelease = 0.1 // pH change per 1u reaction
+ var/RateUpLim = 10 // Optimal/max rate possible if all conditions are perfect
+ var/FermiChem = FALSE // If the chemical uses the Fermichem reaction mechanics//If the chemical uses the Fermichem reaction mechanics
+ var/FermiExplode = FALSE // If the chemical explodes in a special way
+ var/PurityMin = 0.15 //If purity is below 0.15, it explodes too. Set to 0 to disable this.
+
+
/datum/chemical_reaction/proc/on_reaction(datum/reagents/holder, created_volume, specialreact)
return
//I recommend you set the result amount to the total volume of all components.
diff --git a/code/modules/reagents/chemistry/recipes/drugs.dm b/code/modules/reagents/chemistry/recipes/drugs.dm
index d91e2af7e9..27b1fe12ee 100644
--- a/code/modules/reagents/chemistry/recipes/drugs.dm
+++ b/code/modules/reagents/chemistry/recipes/drugs.dm
@@ -41,6 +41,13 @@
results = list("aranesp" = 3)
required_reagents = list("epinephrine" = 1, "atropine" = 1, "morphine" = 1)
+/datum/chemical_reaction/happiness
+ name = "Happiness"
+ id = "happiness"
+ results = list("happiness" = 4)
+ required_reagents = list("nitrous_oxide" = 2, "epinephrine" = 1, "ethanol" = 1)
+ required_catalysts = list("plasma" = 5)
+
/datum/chemical_reaction/skooma
name = "skooma"
id = "skooma"
diff --git a/code/modules/reagents/chemistry/recipes/medicine.dm b/code/modules/reagents/chemistry/recipes/medicine.dm
index 727048a12c..59865dd1da 100644
--- a/code/modules/reagents/chemistry/recipes/medicine.dm
+++ b/code/modules/reagents/chemistry/recipes/medicine.dm
@@ -178,6 +178,12 @@
results = list("mutadone" = 3)
required_reagents = list("mutagen" = 1, "acetone" = 1, "bromine" = 1)
+/datum/chemical_reaction/neurine
+ name = "Neurine"
+ id = "neurine"
+ results = list("neurine" = 3)
+ required_reagents = list("mannitol" = 1, "acetone" = 1, "oxygen" = 1)
+
/datum/chemical_reaction/antihol
name = "antihol"
id = "antihol"
@@ -258,3 +264,9 @@
results = list("modafinil" = 5)
required_reagents = list("diethylamine" = 1, "ammonia" = 1, "phenol" = 1, "acetone" = 1, "sacid" = 1)
required_catalysts = list("bromine" = 1) // as close to the real world synthesis as possible
+
+/datum/chemical_reaction/psicodine
+ name = "Psicodine"
+ id = "psicodine"
+ results = list("psicodine" = 5)
+ required_reagents = list( "mannitol" = 2, "water" = 2, "impedrezene" = 1)
diff --git a/code/modules/reagents/chemistry/recipes/others.dm b/code/modules/reagents/chemistry/recipes/others.dm
index bcd08b1853..e34f34675c 100644
--- a/code/modules/reagents/chemistry/recipes/others.dm
+++ b/code/modules/reagents/chemistry/recipes/others.dm
@@ -528,6 +528,16 @@
/datum/chemical_reaction/life/on_reaction(datum/reagents/holder, created_volume)
chemical_mob_spawn(holder, rand(1, round(created_volume, 1)), "Life") // Lol.
+//This is missing, I'm adding it back (see tgwiki). Not sure why we don't have it.
+/datum/chemical_reaction/life_friendly
+ name = "Life (Friendly)"
+ id = "life_friendly"
+ required_reagents = list("strange_reagent" = 1, "synthflesh" = 1, "sugar" = 1)
+ required_temp = 374
+
+/datum/chemical_reaction/life_friendly/on_reaction(datum/reagents/holder, created_volume)
+ chemical_mob_spawn(holder, rand(1, round(created_volume, 1)), "Life (friendly)", FRIENDLY_SPAWN) //Pray for cute cats
+
/datum/chemical_reaction/corgium
name = "corgium"
id = "corgium"
diff --git a/code/modules/reagents/reagent_containers.dm b/code/modules/reagents/reagent_containers.dm
index 13e809f7cb..48abfcb649 100644
--- a/code/modules/reagents/reagent_containers.dm
+++ b/code/modules/reagents/reagent_containers.dm
@@ -1,3 +1,6 @@
+#define PH_WEAK (1 << 0)
+#define TEMP_WEAK (1 << 1)
+
/obj/item/reagent_containers
name = "Container"
desc = "..."
@@ -12,6 +15,8 @@
var/spawned_disease = null
var/disease_amount = 20
var/spillable = FALSE
+ var/beaker_weakness_bitflag = NONE//Bitflag!
+ var/container_HP = 2
/obj/item/reagent_containers/Initialize(mapload, vol)
. = ..()
@@ -123,9 +128,50 @@
reagents.clear_reagents()
+//melts plastic beakers
/obj/item/reagent_containers/microwave_act(obj/machinery/microwave/M)
reagents.expose_temperature(1000)
+ if(beaker_weakness_bitflag & TEMP_WEAK)
+ var/list/seen = viewers(5, get_turf(src))
+ var/iconhtml = icon2html(src, seen)
+ for(var/mob/H in seen)
+ to_chat(H, "[iconhtml] \The [src]'s melts from the temperature!")
+ playsound(get_turf(src), 'sound/FermiChem/heatmelt.ogg', 80, 1)
+ qdel(src)
..()
+//melts plastic beakers
/obj/item/reagent_containers/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume)
- reagents.expose_temperature(exposed_temperature)
\ No newline at end of file
+ reagents.expose_temperature(exposed_temperature)
+ temp_check()
+
+/obj/item/reagent_containers/proc/temp_check()
+ if(beaker_weakness_bitflag & TEMP_WEAK)
+ if(reagents.chem_temp >= 444)//assuming polypropylene
+ var/list/seen = viewers(5, get_turf(src))
+ var/iconhtml = icon2html(src, seen)
+ for(var/mob/M in seen)
+ to_chat(M, "[iconhtml] \The [src]'s melts from the temperature!")
+ playsound(get_turf(src), 'sound/FermiChem/heatmelt.ogg', 80, 1)
+ to_chat(M, "[iconhtml] Have you tried using glass or meta beakers for high temperature reactions? These are immune to temperature effects.")
+ SSblackbox.record_feedback("tally", "fermi_chem", 1, "Times beakers have melted from temperature")
+ qdel(src)
+
+//melts glass beakers
+/obj/item/reagent_containers/proc/pH_check()
+ if(beaker_weakness_bitflag & PH_WEAK)
+ if((reagents.pH < 0.5) || (reagents.pH > 13.5))
+ var/list/seen = viewers(5, get_turf(src))
+ var/iconhtml = icon2html(src, seen)
+ container_HP--
+ if(container_HP <= 0)
+ for(var/mob/M in seen)
+ to_chat(M, "[iconhtml] \The [src]'s melts from the extreme pH!")
+ playsound(get_turf(src), 'sound/FermiChem/acidmelt.ogg', 80, 1)
+ SSblackbox.record_feedback("tally", "fermi_chem", 1, "Times beakers have melted from pH")
+ qdel(src)
+ else
+ for(var/mob/M in seen)
+ to_chat(M, "[iconhtml] \The [src]'s is damaged by the extreme pH and begins to deform!")
+ playsound(get_turf(src), 'sound/FermiChem/bufferadd.ogg', 50, 1)
+ to_chat(M, "[iconhtml] Have you tried using plastic beakers (XL) or metabeakers for high pH reactions? These beakers are immune to pH effects.")
diff --git a/code/modules/reagents/reagent_containers/bottle.dm b/code/modules/reagents/reagent_containers/bottle.dm
index 66befb1bb6..249ed56d20 100644
--- a/code/modules/reagents/reagent_containers/bottle.dm
+++ b/code/modules/reagents/reagent_containers/bottle.dm
@@ -240,7 +240,7 @@
name = "Rhinovirus culture bottle"
desc = "A small bottle. Contains XY-rhinovirus culture in synthblood medium."
spawned_disease = /datum/disease/advance/cold
-
+
/obj/item/reagent_containers/glass/bottle/flu_virion
name = "Flu virion culture bottle"
desc = "A small bottle. Contains H13N1 flu virion culture in synthblood medium."
diff --git a/code/modules/reagents/reagent_containers/glass.dm b/code/modules/reagents/reagent_containers/glass.dm
index 9d10b9356a..014401b72c 100644
--- a/code/modules/reagents/reagent_containers/glass.dm
+++ b/code/modules/reagents/reagent_containers/glass.dm
@@ -6,6 +6,7 @@
reagent_flags = OPENCONTAINER
spillable = TRUE
resistance_flags = ACID_PROOF
+ container_HP = 3
/obj/item/reagent_containers/glass/attack(mob/M, mob/user, obj/target)
@@ -53,7 +54,7 @@
/obj/item/reagent_containers/glass/afterattack(obj/target, mob/user, proximity)
. = ..()
- if((!proximity) || !spillable || !check_allowed_items(target,target_self=1))
+ if((!proximity) || !check_allowed_items(target,target_self=1))
return
if(target.is_refillable()) //Something like a glass. Player probably wants to transfer TO it.
@@ -108,11 +109,13 @@
/obj/item/reagent_containers/glass/beaker
name = "beaker"
- desc = "A beaker. It can hold up to 50 units."
+ desc = "A beaker. It can hold up to 50 units. Unable to withstand extreme pHes"
icon = 'icons/obj/chemical.dmi'
icon_state = "beaker"
item_state = "beaker"
materials = list(MAT_GLASS=500)
+ beaker_weakness_bitflag = PH_WEAK
+ container_HP = 5
/obj/item/reagent_containers/glass/beaker/Initialize()
. = ..()
@@ -152,27 +155,33 @@
/obj/item/reagent_containers/glass/beaker/jar
name = "honey jar"
- desc = "A jar for honey. It can hold up to 50 units of sweet delight."
+ desc = "A jar for honey. It can hold up to 50 units of sweet delight. Unable to withstand reagents of an extreme pH."
icon = 'icons/obj/chemical.dmi'
icon_state = "vapour"
/obj/item/reagent_containers/glass/beaker/large
name = "large beaker"
- desc = "A large beaker. Can hold up to 100 units."
+ desc = "A large beaker. Can hold up to 100 units. Unable to withstand reagents of an extreme pH."
icon_state = "beakerlarge"
materials = list(MAT_GLASS=2500)
volume = 100
amount_per_transfer_from_this = 10
possible_transfer_amounts = list(5,10,15,20,25,30,50,100)
+ container_HP = 6
/obj/item/reagent_containers/glass/beaker/plastic
name = "x-large beaker"
- desc = "An extra-large beaker. Can hold up to 120 units."
+ desc = "An extra-large beaker. Can hold up to 150 units. Is able to resist acid and alkaline solutions, but melts at 444K"
icon_state = "beakerwhite"
materials = list(MAT_GLASS=2500, MAT_PLASTIC=3000)
- volume = 120
+ volume = 150
amount_per_transfer_from_this = 10
- possible_transfer_amounts = list(5,10,15,20,25,30,60,120)
+ possible_transfer_amounts = list(5,10,15,20,25,30,50,100,150)
+
+/obj/item/reagent_containers/glass/beaker/plastic/Initialize()
+ beaker_weakness_bitflag &= ~PH_WEAK
+ beaker_weakness_bitflag |= TEMP_WEAK
+ . = ..()
/obj/item/reagent_containers/glass/beaker/plastic/update_icon()
icon_state = "beakerlarge" // hack to lets us reuse the large beaker reagent fill states
@@ -181,12 +190,16 @@
/obj/item/reagent_containers/glass/beaker/meta
name = "metamaterial beaker"
- desc = "A large beaker. Can hold up to 180 units."
+ desc = "A large beaker. Can hold up to 200 units. Is able to withstand all chemical situations."
icon_state = "beakergold"
materials = list(MAT_GLASS=2500, MAT_PLASTIC=3000, MAT_GOLD=1000, MAT_TITANIUM=1000)
- volume = 180
+ volume = 200
amount_per_transfer_from_this = 10
- possible_transfer_amounts = list(5,10,15,20,25,30,60,120,180)
+ possible_transfer_amounts = list(5,10,15,20,25,30,50,100,200)
+
+/obj/item/reagent_containers/glass/beaker/meta/Initialize()
+ beaker_weakness_bitflag &= ~PH_WEAK
+ . = ..()
/obj/item/reagent_containers/glass/beaker/noreact
name = "cryostasis beaker"
@@ -197,17 +210,24 @@
reagent_flags = OPENCONTAINER | NO_REACT
volume = 50
amount_per_transfer_from_this = 10
+ container_HP = 10//shouldn't be needed
+
+/obj/item/reagent_containers/glass/beaker/noreact/Initialize()
+ beaker_weakness_bitflag &= ~PH_WEAK
+ . = ..()
+ //reagents.set_reacting(FALSE) was this removed in a recent pr?
/obj/item/reagent_containers/glass/beaker/bluespace
name = "bluespace beaker"
desc = "A bluespace beaker, powered by experimental bluespace technology \
and Element Cuban combined with the Compound Pete. Can hold up to \
- 300 units."
+ 300 units. Unable to withstand reagents of an extreme pH."
icon_state = "beakerbluespace"
materials = list(MAT_GLASS=3000)
volume = 300
amount_per_transfer_from_this = 10
possible_transfer_amounts = list(5,10,15,20,25,30,50,100,300)
+ container_HP = 8
/obj/item/reagent_containers/glass/beaker/cryoxadone
list_reagents = list("cryoxadone" = 30)
@@ -264,6 +284,11 @@
SLOT_L_STORE, SLOT_R_STORE,\
SLOT_GENERC_DEXTROUS_STORAGE
)
+ container_HP = 2
+
+/obj/item/reagent_containers/glass/bucket/Initialize()
+ beaker_weakness_bitflag |= TEMP_WEAK
+ . = ..()
/obj/item/reagent_containers/glass/bucket/attackby(obj/O, mob/user, params)
if(istype(O, /obj/item/mop))
@@ -313,6 +338,11 @@
materials = list(MAT_GLASS=0)
volume = 50
amount_per_transfer_from_this = 10
+ container_HP = 2
+
+/obj/item/reagent_containers/glass/beaker/waterbottle/Initialize()
+ beaker_weakness_bitflag |= TEMP_WEAK
+ . = ..()
/obj/item/reagent_containers/glass/beaker/waterbottle/empty
list_reagents = list()
@@ -324,6 +354,7 @@
list_reagents = list("water" = 100)
volume = 100
amount_per_transfer_from_this = 20
+ container_HP = 2
/obj/item/reagent_containers/glass/beaker/waterbottle/large/empty
list_reagents = list()
diff --git a/code/modules/reagents/reagent_containers/pill.dm b/code/modules/reagents/reagent_containers/pill.dm
index 280337e686..38880f669f 100644
--- a/code/modules/reagents/reagent_containers/pill.dm
+++ b/code/modules/reagents/reagent_containers/pill.dm
@@ -1,242 +1,259 @@
-/obj/item/reagent_containers/pill
- name = "pill"
- desc = "A tablet or capsule."
- icon = 'icons/obj/chemical.dmi'
- icon_state = "pill"
- item_state = "pill"
- lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi'
- righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi'
- possible_transfer_amounts = list()
- volume = 50
- grind_results = list()
- var/apply_type = INGEST
- var/apply_method = "swallow"
- var/roundstart = 0
- var/self_delay = 0 //pills are instant, this is because patches inheret their aplication from pills
- var/dissolvable = TRUE
-
-/obj/item/reagent_containers/pill/Initialize()
- . = ..()
- if(!icon_state)
- icon_state = "pill[rand(1,20)]"
- if(reagents.total_volume && roundstart)
- name += " ([reagents.total_volume]u)"
-
-
-/obj/item/reagent_containers/pill/attack_self(mob/user)
- return
-
-
-/obj/item/reagent_containers/pill/attack(mob/M, mob/user, def_zone)
- if(!canconsume(M, user))
- return 0
-
- if(M == user)
- M.visible_message("[user] attempts to [apply_method] [src].")
- if(self_delay)
- if(!do_mob(user, M, self_delay))
- return 0
- to_chat(M, "You [apply_method] [src].")
-
- else
- M.visible_message("[user] attempts to force [M] to [apply_method] [src].", \
- "[user] attempts to force [M] to [apply_method] [src].")
- if(!do_mob(user, M))
- return 0
- M.visible_message("[user] forces [M] to [apply_method] [src].", \
- "[user] forces [M] to [apply_method] [src].")
-
- var/makes_me_think = pick(strings("redpill.json", "redpill_questions"))
- if(icon_state == "pill4" && prob(5)) //you take the red pill - you stay in Wonderland, and I show you how deep the rabbit hole goes
- addtimer(CALLBACK(GLOBAL_PROC, /proc/to_chat, M, "[makes_me_think]"), 50)
-
- log_combat(user, M, "fed", reagents.log_list())
- if(reagents.total_volume)
- reagents.reaction(M, apply_type)
- reagents.trans_to(M, reagents.total_volume)
- qdel(src)
- return 1
-
-
-/obj/item/reagent_containers/pill/afterattack(obj/target, mob/user , proximity)
- . = ..()
- if(!proximity)
- return
- if(!dissolvable || !target.is_refillable())
- return
- if(target.is_drainable() && !target.reagents.total_volume)
- to_chat(user, "[target] is empty! There's nothing to dissolve [src] in.")
- return
-
- if(target.reagents.holder_full())
- to_chat(user, "[target] is full.")
- return
-
- to_chat(user, "You dissolve [src] in [target].")
- for(var/mob/O in viewers(2, user)) //viewers is necessary here because of the small radius
- to_chat(O, "[user] slips something into [target]!")
- reagents.trans_to(target, reagents.total_volume)
- qdel(src)
-
-/obj/item/reagent_containers/pill/tox
- name = "toxins pill"
- desc = "Highly toxic."
- icon_state = "pill5"
- list_reagents = list("toxin" = 50)
- roundstart = 1
-
-/obj/item/reagent_containers/pill/cyanide
- name = "cyanide pill"
- desc = "Don't swallow this."
- icon_state = "pill5"
- list_reagents = list("cyanide" = 50)
- roundstart = 1
-
-/obj/item/reagent_containers/pill/adminordrazine
- name = "adminordrazine pill"
- desc = "It's magic. We don't have to explain it."
- icon_state = "pill16"
- list_reagents = list("adminordrazine" = 50)
- roundstart = 1
-
-/obj/item/reagent_containers/pill/morphine
- name = "morphine pill"
- desc = "Commonly used to treat insomnia."
- icon_state = "pill8"
- list_reagents = list("morphine" = 30)
- roundstart = 1
-
-/obj/item/reagent_containers/pill/stimulant
- name = "stimulant pill"
- desc = "Often taken by overworked employees, athletes, and the inebriated. You'll snap to attention immediately!"
- icon_state = "pill19"
- list_reagents = list("ephedrine" = 10, "antihol" = 10, "coffee" = 30)
- roundstart = 1
-
-/obj/item/reagent_containers/pill/salbutamol
- name = "salbutamol pill"
- desc = "Used to treat oxygen deprivation."
- icon_state = "pill16"
- list_reagents = list("salbutamol" = 30)
- roundstart = 1
-
-/obj/item/reagent_containers/pill/charcoal
- name = "charcoal pill"
- desc = "Neutralizes many common toxins."
- icon_state = "pill17"
- list_reagents = list("charcoal" = 10)
- roundstart = 1
-
-/obj/item/reagent_containers/pill/epinephrine
- name = "epinephrine pill"
- desc = "Used to stabilize patients."
- icon_state = "pill5"
- list_reagents = list("epinephrine" = 15)
- roundstart = 1
-
-/obj/item/reagent_containers/pill/mannitol
- name = "mannitol pill"
- desc = "Used to treat brain damage."
- icon_state = "pill17"
- list_reagents = list("mannitol" = 50)
- roundstart = 1
-
-/obj/item/reagent_containers/pill/mutadone
- name = "mutadone pill"
- desc = "Used to treat genetic damage."
- icon_state = "pill20"
- list_reagents = list("mutadone" = 50)
- roundstart = 1
-
-/obj/item/reagent_containers/pill/salicyclic
- name = "salicylic acid pill"
- desc = "Used to dull pain."
- icon_state = "pill9"
- list_reagents = list("sal_acid" = 24)
- roundstart = 1
-
-/obj/item/reagent_containers/pill/oxandrolone
- name = "oxandrolone pill"
- desc = "Used to stimulate burn healing."
- icon_state = "pill11"
- list_reagents = list("oxandrolone" = 24)
- roundstart = 1
-
-/obj/item/reagent_containers/pill/insulin
- name = "insulin pill"
- desc = "Handles hyperglycaemic coma."
- icon_state = "pill18"
- list_reagents = list("insulin" = 50)
- roundstart = 1
-
-/obj/item/reagent_containers/pill/antirad
- name = "potassium iodide pill"
- desc = "Used to treat radition used to counter radiation poisoning."
- icon_state = "pill18"
- list_reagents = list("potass_iodide" = 50)
- roundstart = 1
-
-/obj/item/reagent_containers/pill/antirad_plus
- name = "prussian blue pill"
- desc = "Used to treat heavy radition poisoning."
- icon = 'modular_citadel/icons/obj/modularpills.dmi'
- icon_state = "prussian_blue"
- list_reagents = list("prussian_blue" = 25, "water" = 10)
- roundstart = 1
-
-/obj/item/reagent_containers/pill/mutarad
- name = "radiation treatment deluxe pill"
- desc = "Used to treat heavy radition poisoning and genetic defects."
- icon = 'modular_citadel/icons/obj/modularpills.dmi'
- icon_state = "anit_rad_fixgene"
- list_reagents = list("prussian_blue" = 15, "potass_iodide" = 15, "mutadone" = 15, "water" = 5)
- roundstart = 1
-
-///////////////////////////////////////// this pill is used only in a legion mob drop
-/obj/item/reagent_containers/pill/shadowtoxin
- name = "black pill"
- desc = "I wouldn't eat this if I were you."
- icon_state = "pill9"
- color = "#454545"
- list_reagents = list("shadowmutationtoxin" = 1)
-//////////////////////////////////////// drugs
-/obj/item/reagent_containers/pill/zoom
- name = "zoom pill"
- list_reagents = list("synaptizine" = 10, "nicotine" = 10, "methamphetamine" = 1)
-
-
-/obj/item/reagent_containers/pill/happy
- name = "happy pill"
- list_reagents = list("sugar" = 10, "space_drugs" = 10)
-
-
-/obj/item/reagent_containers/pill/lsd
- name = "hallucinogen pill"
- list_reagents = list("mushroomhallucinogen" = 15, "mindbreaker" = 15)
-
-
-/obj/item/reagent_containers/pill/aranesp
- name = "speedy pill"
- list_reagents = list("aranesp" = 10)
-
-/obj/item/reagent_containers/pill/floorpill
- name = "floorpill"
- desc = "A strange pill found in the depths of maintenance"
- icon_state = "pill21"
- var/static/list/names = list("maintenance pill","floorpill","mystery pill","suspicious pill","strange pill")
- var/static/list/descs = list("Your feeling is telling you no, but...","Drugs are expensive, you can't afford not to eat any pills that you find."\
- , "Surely, there's no way this could go bad.")
-
-/obj/item/reagent_containers/pill/floorpill/Initialize()
- list_reagents = list(get_random_reagent_id() = rand(10,50))
- . = ..()
- name = pick(names)
- if(prob(20))
- desc = pick(descs)
-
-/obj/item/reagent_containers/pill/get_belt_overlay()
- return mutable_appearance('icons/obj/clothing/belt_overlays.dmi', "pouch")
-
-/obj/item/reagent_containers/pill/penis_enlargement
- name = "penis enlargement pill"
- list_reagents = list("penis_enlargement" = 30)
+/obj/item/reagent_containers/pill
+ name = "pill"
+ desc = "A tablet or capsule."
+ icon = 'icons/obj/chemical.dmi'
+ icon_state = "pill"
+ item_state = "pill"
+ lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi'
+ possible_transfer_amounts = list()
+ volume = 50
+ grind_results = list()
+ var/apply_type = INGEST
+ var/apply_method = "swallow"
+ var/roundstart = 0
+ var/self_delay = 0 //pills are instant, this is because patches inheret their aplication from pills
+ var/dissolvable = TRUE
+
+/obj/item/reagent_containers/pill/Initialize()
+ . = ..()
+ if(!icon_state)
+ icon_state = "pill[rand(1,20)]"
+ if(reagents.total_volume && roundstart)
+ name += " ([reagents.total_volume]u)"
+
+
+/obj/item/reagent_containers/pill/attack_self(mob/user)
+ return
+
+
+/obj/item/reagent_containers/pill/attack(mob/M, mob/user, def_zone)
+ if(!canconsume(M, user))
+ return 0
+
+ if(M == user)
+ M.visible_message("[user] attempts to [apply_method] [src].")
+ if(self_delay)
+ if(!do_mob(user, M, self_delay))
+ return 0
+ to_chat(M, "You [apply_method] [src].")
+
+ else
+ M.visible_message("[user] attempts to force [M] to [apply_method] [src].", \
+ "[user] attempts to force [M] to [apply_method] [src].")
+ if(!do_mob(user, M))
+ return 0
+ M.visible_message("[user] forces [M] to [apply_method] [src].", \
+ "[user] forces [M] to [apply_method] [src].")
+
+ var/makes_me_think = pick(strings("redpill.json", "redpill_questions"))
+ if(icon_state == "pill4" && prob(5)) //you take the red pill - you stay in Wonderland, and I show you how deep the rabbit hole goes
+ addtimer(CALLBACK(GLOBAL_PROC, /proc/to_chat, M, "[makes_me_think]"), 50)
+
+ log_combat(user, M, "fed", reagents.log_list())
+ if(reagents.total_volume)
+ reagents.reaction(M, apply_type)
+ reagents.trans_to(M, reagents.total_volume)
+ qdel(src)
+ return 1
+
+
+/obj/item/reagent_containers/pill/afterattack(obj/target, mob/user , proximity)
+ . = ..()
+ if(!proximity)
+ return
+ if(!dissolvable || !target.is_refillable())
+ return
+ if(target.is_drainable() && !target.reagents.total_volume)
+ to_chat(user, "[target] is empty! There's nothing to dissolve [src] in.")
+ return
+
+ if(target.reagents.holder_full())
+ to_chat(user, "[target] is full.")
+ return
+
+ to_chat(user, "You dissolve [src] in [target].")
+ for(var/mob/O in viewers(2, user)) //viewers is necessary here because of the small radius
+ to_chat(O, "[user] slips something into [target]!")
+ reagents.trans_to(target, reagents.total_volume)
+ qdel(src)
+
+/obj/item/reagent_containers/pill/tox
+ name = "toxins pill"
+ desc = "Highly toxic."
+ icon_state = "pill5"
+ list_reagents = list("toxin" = 50)
+ roundstart = 1
+
+/obj/item/reagent_containers/pill/cyanide
+ name = "cyanide pill"
+ desc = "Don't swallow this."
+ icon_state = "pill5"
+ list_reagents = list("cyanide" = 50)
+ roundstart = 1
+
+/obj/item/reagent_containers/pill/adminordrazine
+ name = "adminordrazine pill"
+ desc = "It's magic. We don't have to explain it."
+ icon_state = "pill16"
+ list_reagents = list("adminordrazine" = 50)
+ roundstart = 1
+
+/obj/item/reagent_containers/pill/morphine
+ name = "morphine pill"
+ desc = "Commonly used to treat insomnia."
+ icon_state = "pill8"
+ list_reagents = list("morphine" = 30)
+ roundstart = 1
+
+/obj/item/reagent_containers/pill/stimulant
+ name = "stimulant pill"
+ desc = "Often taken by overworked employees, athletes, and the inebriated. You'll snap to attention immediately!"
+ icon_state = "pill19"
+ list_reagents = list("ephedrine" = 10, "antihol" = 10, "coffee" = 30)
+ roundstart = 1
+
+/obj/item/reagent_containers/pill/salbutamol
+ name = "salbutamol pill"
+ desc = "Used to treat oxygen deprivation."
+ icon_state = "pill16"
+ list_reagents = list("salbutamol" = 30)
+ roundstart = 1
+
+/obj/item/reagent_containers/pill/charcoal
+ name = "charcoal pill"
+ desc = "Neutralizes many common toxins."
+ icon_state = "pill17"
+ list_reagents = list("charcoal" = 10)
+ roundstart = 1
+
+/obj/item/reagent_containers/pill/epinephrine
+ name = "epinephrine pill"
+ desc = "Used to stabilize patients."
+ icon_state = "pill5"
+ list_reagents = list("epinephrine" = 15)
+ roundstart = 1
+
+/obj/item/reagent_containers/pill/mannitol
+ name = "mannitol pill"
+ desc = "Used to treat brain damage."
+ icon_state = "pill17"
+ list_reagents = list("mannitol" = 50)
+ roundstart = 1
+
+/obj/item/reagent_containers/pill/mutadone
+ name = "mutadone pill"
+ desc = "Used to treat genetic damage."
+ icon_state = "pill20"
+ list_reagents = list("mutadone" = 50)
+ roundstart = 1
+
+/obj/item/reagent_containers/pill/salicyclic
+ name = "salicylic acid pill"
+ desc = "Used to dull pain."
+ icon_state = "pill9"
+ list_reagents = list("sal_acid" = 24)
+ roundstart = 1
+
+/obj/item/reagent_containers/pill/oxandrolone
+ name = "oxandrolone pill"
+ desc = "Used to stimulate burn healing."
+ icon_state = "pill11"
+ list_reagents = list("oxandrolone" = 24)
+ roundstart = 1
+
+/obj/item/reagent_containers/pill/insulin
+ name = "insulin pill"
+ desc = "Handles hyperglycaemic coma."
+ icon_state = "pill18"
+ list_reagents = list("insulin" = 50)
+ roundstart = 1
+
+/obj/item/reagent_containers/pill/psicodine
+ name = "psicodine pill"
+ desc = "Used to treat mental instability and traumas."
+ list_reagents = list("psicodine" = 10)
+ icon_state = "pill22"
+ roundstart = 1
+
+/obj/item/reagent_containers/pill/antirad
+ name = "potassium iodide pill"
+ desc = "Used to treat radition used to counter radiation poisoning."
+ icon_state = "pill18"
+ list_reagents = list("potass_iodide" = 50)
+ roundstart = 1
+
+/obj/item/reagent_containers/pill/antirad_plus
+ name = "prussian blue pill"
+ desc = "Used to treat heavy radition poisoning."
+ icon = 'modular_citadel/icons/obj/modularpills.dmi'
+ icon_state = "prussian_blue"
+ list_reagents = list("prussian_blue" = 25, "water" = 10)
+ roundstart = 1
+
+/obj/item/reagent_containers/pill/mutarad
+ name = "radiation treatment deluxe pill"
+ desc = "Used to treat heavy radition poisoning and genetic defects."
+ icon = 'modular_citadel/icons/obj/modularpills.dmi'
+ icon_state = "anit_rad_fixgene"
+ list_reagents = list("prussian_blue" = 15, "potass_iodide" = 15, "mutadone" = 15, "water" = 5)
+ roundstart = 1
+
+///////////////////////////////////////// this pill is used only in a legion mob drop
+/obj/item/reagent_containers/pill/shadowtoxin
+ name = "black pill"
+ desc = "I wouldn't eat this if I were you."
+ icon_state = "pill9"
+ color = "#454545"
+ list_reagents = list("shadowmutationtoxin" = 1)
+//////////////////////////////////////// drugs
+/obj/item/reagent_containers/pill/zoom
+ name = "zoom pill"
+ list_reagents = list("synaptizine" = 10, "nicotine" = 10, "methamphetamine" = 1)
+
+
+/obj/item/reagent_containers/pill/happy
+ name = "happy pill"
+ list_reagents = list("sugar" = 10, "space_drugs" = 10)
+
+
+/obj/item/reagent_containers/pill/lsd
+ name = "hallucinogen pill"
+ list_reagents = list("mushroomhallucinogen" = 15, "mindbreaker" = 15)
+
+
+/obj/item/reagent_containers/pill/aranesp
+ name = "speedy pill"
+ list_reagents = list("aranesp" = 10)
+
+/obj/item/reagent_containers/pill/happiness
+ name = "happiness pill"
+ desc = "It has a creepy smiling face on it."
+ icon_state = "pill_happy"
+ list_reagents = list("happiness" = 10)
+
+/obj/item/reagent_containers/pill/floorpill
+ name = "floorpill"
+ desc = "A strange pill found in the depths of maintenance"
+ icon_state = "pill21"
+ var/static/list/names = list("maintenance pill","floorpill","mystery pill","suspicious pill","strange pill")
+ var/static/list/descs = list("Your feeling is telling you no, but...","Drugs are expensive, you can't afford not to eat any pills that you find."\
+ , "Surely, there's no way this could go bad.")
+
+/obj/item/reagent_containers/pill/floorpill/Initialize()
+ list_reagents = list(get_random_reagent_id() = rand(10,50))
+ . = ..()
+ name = pick(names)
+ if(prob(20))
+ desc = pick(descs)
+
+/obj/item/reagent_containers/pill/get_belt_overlay()
+ return mutable_appearance('icons/obj/clothing/belt_overlays.dmi', "pouch")
+
+/obj/item/reagent_containers/pill/penis_enlargement
+ name = "penis enlargement pill"
+ list_reagents = list("penis_enlarger" = 10)
+
+/obj/item/reagent_containers/pill/breast_enlargement
+ name = "breast enlargement pill"
+ list_reagents = list("breast_enlarger" = 10)
diff --git a/code/modules/reagents/reagent_containers/rags.dm b/code/modules/reagents/reagent_containers/rags.dm
new file mode 100644
index 0000000000..92a4b155d8
--- /dev/null
+++ b/code/modules/reagents/reagent_containers/rags.dm
@@ -0,0 +1,177 @@
+/obj/item/reagent_containers/rag
+ name = "damp rag"
+ desc = "For cleaning up messes, you suppose."
+ w_class = WEIGHT_CLASS_TINY
+ icon = 'icons/obj/toy.dmi'
+ icon_state = "rag"
+ item_flags = NOBLUDGEON
+ reagent_flags = OPENCONTAINER
+ amount_per_transfer_from_this = 5
+ possible_transfer_amounts = list()
+ volume = 5
+ spillable = FALSE
+ var/wipe_sound
+ var/soak_efficiency = 1
+ var/extinguish_efficiency = 0
+ var/action_speed = 3 SECONDS
+ var/damp_threshold = 0.5
+
+/obj/item/reagent_containers/rag/suicide_act(mob/user)
+ user.visible_message("[user] is smothering [user.p_them()]self with [src]! It looks like [user.p_theyre()] trying to commit suicide!")
+ return (OXYLOSS)
+
+/obj/item/reagent_containers/rag/examine(mob/user)
+ . = ..()
+ if(reagents.total_volume)
+ to_chat(user, "Alt-Click to squeeze the liquids out of it.")
+
+/obj/item/reagent_containers/rag/afterattack(atom/A as obj|turf|area, mob/user,proximity)
+ . = ..()
+ if(!proximity)
+ return
+ if(iscarbon(A) && A.reagents && reagents.total_volume)
+ var/mob/living/carbon/C = A
+ var/reagentlist = pretty_string_from_reagent_list(reagents)
+ var/log_object = "a damp rag containing [reagentlist]"
+ if(user.a_intent == INTENT_HARM && !C.is_mouth_covered())
+ reagents.reaction(C, INGEST)
+ reagents.trans_to(C, 5)
+ C.visible_message("[user] has smothered \the [C] with \the [src]!", "[user] has smothered you with \the [src]!", "You hear some struggling and muffled cries of surprise.")
+ log_combat(user, C, "smothered", log_object)
+ else
+ reagents.reaction(C, TOUCH)
+ reagents.remove_all(5)
+ C.visible_message("[user] has touched \the [C] with \the [src].")
+ log_combat(user, C, "touched", log_object)
+
+ else if(istype(A) && src in user)
+ user.visible_message("[user] starts to wipe down [A] with [src]!", "You start to wipe down [A] with [src]...")
+ if(do_after(user, action_speed, target = A))
+ user.visible_message("[user] finishes wiping off [A]!", "You finish wiping off [A].")
+ SEND_SIGNAL(A, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_MEDIUM)
+ return
+
+/obj/item/reagent_containers/rag/pre_altattackby(mob/living/M, mob/living/user, params)
+ if(istype(M) && user.a_intent == INTENT_HELP)
+ user.changeNext_move(CLICK_CD_MELEE)
+ if(M.on_fire)
+ user.visible_message("\The [user] uses \the [src] to pat out [M == user ? "[user.p_their()]" : "\the [M]'s"] flames!")
+ if(hitsound)
+ playsound(M, hitsound, 25, 1)
+ M.adjust_fire_stacks(-min(extinguish_efficiency, M.fire_stacks))
+ else
+ if(reagents.total_volume > (volume * damp_threshold))
+ to_chat(user, "\The [src] is too drenched to be used to dry [user == M ? "yourself" : "\the [M]"] off.")
+ return TRUE
+ user.visible_message("\The [user] starts drying [M == user ? "[user.p_them()]self" : "\the [M]"] off with \the [src]...")
+ if(do_mob(user, M, action_speed))
+ if(reagents.total_volume > (volume * damp_threshold))
+ return
+ user.visible_message("\The [user] dries [M == user ? "[user.p_them()]self" : "\the [M]"] off with \the [src].")
+ if(wipe_sound)
+ playsound(M, wipe_sound, 25, 1)
+ if(M.fire_stacks)
+ var/minus_plus = M.fire_stacks < 0 ? 1 : -1
+ var/amount = min(abs(M.fire_stacks), soak_efficiency)
+ var/r_id = "fuel"
+ if(M.fire_stacks < 0)
+ r_id = "water"
+ reagents.add_reagent(r_id, amount * 0.3)
+ M.adjust_fire_stacks(minus_plus * amount)
+ M.wash_cream()
+ return TRUE
+ return ..()
+
+/obj/item/reagent_containers/rag/AltClick(mob/user)
+ . = ..()
+ if(reagents.total_volume && user.canUseTopic(src, BE_CLOSE))
+ to_chat(user, "You start squeezing the liquids out of \the [src]...")
+ if(do_after(user, action_speed, TRUE, src))
+ to_chat(user, "You squeeze \the [src] dry.")
+ var/atom/react_loc = get_turf(src)
+ if(ismob(react_loc))
+ react_loc = react_loc.loc
+ if(react_loc)
+ reagents.reaction(react_loc, TOUCH)
+ reagents.clear_reagents()
+
+/obj/item/reagent_containers/rag/towel
+ name = "towel"
+ desc = "A soft cotton towel."
+ icon = 'icons/obj/items_and_weapons.dmi'
+ icon_state = "towel"
+ item_state = "towel"
+ slot_flags = ITEM_SLOT_HEAD | ITEM_SLOT_BELT | ITEM_SLOT_OCLOTHING
+ item_flags = NOBLUDGEON | NO_UNIFORM_REQUIRED //so it can be worn on the belt slot even with no uniform.
+ force = 1
+ w_class = WEIGHT_CLASS_NORMAL
+ attack_verb = list("whipped")
+ hitsound = 'sound/items/towelwhip.ogg'
+ volume = 10
+ total_mass = 2
+ wipe_sound = 'sound/items/towelwipe.ogg'
+ soak_efficiency = 4
+ extinguish_efficiency = 3
+ var/flat_icon = "towel_flat"
+ var/folded_icon = "towel"
+ var/list/possible_colors
+
+/obj/item/reagent_containers/rag/towel/Initialize()
+ . = ..()
+ if(possible_colors)
+ add_atom_colour(pick(possible_colors), FIXED_COLOUR_PRIORITY)
+
+/obj/item/reagent_containers/rag/towel/attack(mob/living/M, mob/living/user)
+ if(user.a_intent == INTENT_HARM)
+ DISABLE_BITFIELD(item_flags, NOBLUDGEON)
+ . = TRUE
+ ..()
+ if(.)
+ ENABLE_BITFIELD(item_flags, NOBLUDGEON)
+
+/obj/item/reagent_containers/rag/towel/equipped(mob/living/user, slot)
+ . = ..()
+ switch(slot)
+ if(SLOT_BELT)
+ body_parts_covered = GROIN|LEGS
+ if(SLOT_WEAR_SUIT)
+ body_parts_covered = CHEST|GROIN|LEGS
+ if(SLOT_HEAD)
+ body_parts_covered = HEAD
+ flags_inv = HIDEHAIR
+
+/obj/item/reagent_containers/rag/towel/dropped(mob/user)
+ . = ..()
+ body_parts_covered = NONE
+ flags_inv = NONE
+
+/obj/item/reagent_containers/rag/towel/attack_self(mob/user)
+ if(!user.CanReach(src) || !user.dropItemToGround(src))
+ return
+ to_chat(user, "You lay out \the [src] flat on the ground.")
+ icon_state = flat_icon
+ layer = BELOW_OBJ_LAYER
+
+/obj/item/reagent_containers/rag/towel/pickup(mob/living/user)
+ . = ..()
+ icon_state = folded_icon
+ layer = initial(layer)
+
+/obj/item/reagent_containers/rag/towel/on_reagent_change(changetype)
+ force = initial(force) + round(reagents.total_volume * 0.5)
+
+/obj/item/reagent_containers/rag/towel/random
+ possible_colors = list("#FF0000","#FF7F00","#FFFF00","#00FF00","#0000FF","#4B0082","#8F00FF")
+
+/obj/item/reagent_containers/rag/towel/syndicate
+ name = "syndicate towel"
+ desc = "Truly a weapon of mass destruction."
+ possible_colors = list("#DD1A1A", "#DB4325", "#E02700")
+ force = 4
+ armour_penetration = 10
+ volume = 20
+ soak_efficiency = 6
+ extinguish_efficiency = 5
+ action_speed = 15
+ damp_threshold = 0.8
+ armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 20, "bio" = 20, "rad" = 20, "fire" = 50, "acid" = 50) //items don't provide armor to wearers unlike clothing yet.
\ No newline at end of file
diff --git a/code/modules/research/designs/comp_board_designs/comp_board_designs_cargo .dm b/code/modules/research/designs/comp_board_designs/comp_board_designs_cargo .dm
index fd548adc76..b11a5ee258 100644
--- a/code/modules/research/designs/comp_board_designs/comp_board_designs_cargo .dm
+++ b/code/modules/research/designs/comp_board_designs/comp_board_designs_cargo .dm
@@ -32,4 +32,12 @@
id = "mining"
build_path = /obj/item/circuitboard/computer/mining
category = list("Computer Boards")
- departmental_flags = DEPARTMENTAL_FLAG_CARGO | DEPARTMENTAL_FLAG_SECURITY
\ No newline at end of file
+ departmental_flags = DEPARTMENTAL_FLAG_CARGO | DEPARTMENTAL_FLAG_SECURITY
+
+/datum/design/board/miningshuttle
+ name = "Computer Design (Mining Shuttle Console)"
+ desc = "Allows for the construction of circuit boards used to build a Mining Shuttle Console."
+ id = "miningshuttle"
+ build_path = /obj/item/circuitboard/computer/mining_shuttle
+ category = list("Computer Boards")
+ departmental_flags = DEPARTMENTAL_FLAG_CARGO
\ No newline at end of file
diff --git a/code/modules/research/designs/medical_designs.dm b/code/modules/research/designs/medical_designs.dm
index 3a7ef68903..33568524cd 100644
--- a/code/modules/research/designs/medical_designs.dm
+++ b/code/modules/research/designs/medical_designs.dm
@@ -554,6 +554,16 @@
category = list("Medical Designs")
departmental_flags = DEPARTMENTAL_FLAG_MEDICAL
+/datum/design/cybernetic_tongue
+ name = "Cybernetic tongue"
+ desc = "A fancy cybernetic tongue."
+ id = "cybernetic_tongue"
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 500, MAT_GLASS = 500)
+ build_path = /obj/item/organ/tongue/cybernetic
+ category = list("Medical Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_MEDICAL
+
/////////////////////
//Adv Surgery Tools//
/////////////////////
diff --git a/code/modules/research/designs/misc_designs.dm b/code/modules/research/designs/misc_designs.dm
index 59df0f6e85..4a6f9625f1 100644
--- a/code/modules/research/designs/misc_designs.dm
+++ b/code/modules/research/designs/misc_designs.dm
@@ -1,4 +1,3 @@
-
/////////////////////////////////////////
/////////////////HUDs////////////////////
/////////////////////////////////////////
@@ -291,6 +290,16 @@
category = list("Equipment")
departmental_flags = DEPARTMENTAL_FLAG_SERVICE
+/datum/design/light_replacer
+ name = "Light Replacer"
+ desc = "A device to automatically replace lights. Refill with working light bulbs."
+ id = "light_replacer"
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 1500, MAT_SILVER = 150, MAT_GLASS = 3000)
+ build_path = /obj/item/lightreplacer
+ category = list("Equipment")
+ departmental_flags = DEPARTMENTAL_FLAG_SERVICE
+
/datum/design/blutrash
name = "Trashbag of Holding"
desc = "An advanced trash bag with bluespace properties; capable of holding a plethora of garbage."
@@ -460,6 +469,16 @@
category = list("Equipment")
departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING
+/datum/design/quantum_keycard
+ name = "Quantum Keycard"
+ desc = "Allows for the construction of a quantum keycard."
+ id = "quantum_keycard"
+ build_type = PROTOLATHE
+ materials = list(MAT_GLASS = 500, MAT_METAL = 500, MAT_SILVER = 500, MAT_BLUESPACE = 1000)
+ build_path = /obj/item/quantum_keycard
+ category = list("Equipment")
+ departmental_flags = DEPARTMENTAL_FLAG_SCIENCE | DEPARTMENTAL_FLAG_ENGINEERING
+
/datum/design/anomaly_neutralizer
name = "Anomaly Neutralizer"
desc = "An advanced tool capable of instantly neutralizing anomalies, designed to capture the fleeting aberrations created by the engine."
@@ -470,6 +489,16 @@
category = list("Equipment")
departmental_flags = DEPARTMENTAL_FLAG_SCIENCE | DEPARTMENTAL_FLAG_ENGINEERING
+/datum/design/pHmeter
+ name = "Chemical Analyser"
+ desc = "A a electrode attached to a small circuit box that will tell you the pH of a solution."
+ id = "pHmeter"
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 1000, MAT_SILVER = 100, MAT_DIAMOND = 100)
+ build_path = /obj/item/fermichem/pHmeter
+ category = list("Equipment")
+ departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE
+
/////////////////////////////////////////
////////////Armour///////////////////////
/////////////////////////////////////////
diff --git a/code/modules/research/designs/power_designs.dm b/code/modules/research/designs/power_designs.dm
index f8122c16e3..1dbd111785 100644
--- a/code/modules/research/designs/power_designs.dm
+++ b/code/modules/research/designs/power_designs.dm
@@ -57,16 +57,6 @@
category = list("Misc","Power Designs")
departmental_flags = DEPARTMENTAL_FLAG_SCIENCE | DEPARTMENTAL_FLAG_ENGINEERING
-/datum/design/light_replacer
- name = "Light Replacer"
- desc = "A device to automatically replace lights. Refill with working light bulbs."
- id = "light_replacer"
- build_type = PROTOLATHE
- materials = list(MAT_METAL = 1500, MAT_SILVER = 150, MAT_GLASS = 3000)
- build_path = /obj/item/lightreplacer
- category = list("Power Designs")
- departmental_flags = DEPARTMENTAL_FLAG_SERVICE
-
/datum/design/inducer
name = "Inducer"
desc = "The NT-75 Electromagnetic Power Inducer can wirelessly induce electric charge in an object, allowing you to recharge power cells without having to remove them."
diff --git a/code/modules/research/experimentor.dm b/code/modules/research/experimentor.dm
index ebd386513e..e56350a280 100644
--- a/code/modules/research/experimentor.dm
+++ b/code/modules/research/experimentor.dm
@@ -651,7 +651,7 @@
if(loc == user && !is_centcom_level(userturf.z)) //Because Nuke Ops bringing this back on their shuttle, then looting the ERT area is 2fun4you!
visible_message("[src] twists and bends, relocating itself!")
throwSmoke(userturf)
- do_teleport(user, userturf, 8, asoundin = 'sound/effects/phasein.ogg')
+ do_teleport(user, userturf, 8, asoundin = 'sound/effects/phasein.ogg', channel = TELEPORT_CHANNEL_BLUESPACE)
throwSmoke(get_turf(user))
warn_admins(user, "Teleport", 0)
diff --git a/code/modules/research/nanites/nanite_program_hub.dm b/code/modules/research/nanites/nanite_program_hub.dm
index 81c5a44527..e33f3d7cd7 100644
--- a/code/modules/research/nanites/nanite_program_hub.dm
+++ b/code/modules/research/nanites/nanite_program_hub.dm
@@ -115,4 +115,10 @@
qdel(disk.program)
disk.program = null
disk.name = initial(disk.name)
- . = TRUE
\ No newline at end of file
+ . = TRUE
+
+
+/obj/machinery/nanite_program_hub/admin/Initialize()
+ . = ..()
+ linked_techweb = SSresearch.admin_tech
+
diff --git a/code/modules/research/nanites/nanite_programs/buffing.dm b/code/modules/research/nanites/nanite_programs/buffing.dm
index c80c5c5d96..be12d06ede 100644
--- a/code/modules/research/nanites/nanite_programs/buffing.dm
+++ b/code/modules/research/nanites/nanite_programs/buffing.dm
@@ -49,14 +49,14 @@
. = ..()
if(ishuman(host_mob))
var/mob/living/carbon/human/H = host_mob
- H.physiology.armor.melee += 50
+ H.physiology.armor.melee += 35
H.physiology.armor.bullet += 35
/datum/nanite_program/hardening/disable_passive_effect()
. = ..()
if(ishuman(host_mob))
var/mob/living/carbon/human/H = host_mob
- H.physiology.armor.melee -= 50
+ H.physiology.armor.melee -= 35
H.physiology.armor.bullet -= 35
/datum/nanite_program/refractive
@@ -69,14 +69,14 @@
. = ..()
if(ishuman(host_mob))
var/mob/living/carbon/human/H = host_mob
- H.physiology.armor.laser += 50
+ H.physiology.armor.laser += 35
H.physiology.armor.energy += 35
/datum/nanite_program/refractive/disable_passive_effect()
. = ..()
if(ishuman(host_mob))
var/mob/living/carbon/human/H = host_mob
- H.physiology.armor.laser -= 50
+ H.physiology.armor.laser -= 35
H.physiology.armor.energy -= 35
/datum/nanite_program/coagulating
@@ -127,4 +127,4 @@
/datum/nanite_program/mindshield/disable_passive_effect()
. = ..()
REMOVE_TRAIT(host_mob, TRAIT_MINDSHIELD, "nanites")
- host_mob.sec_hud_set_implants()
\ No newline at end of file
+ host_mob.sec_hud_set_implants()
diff --git a/code/modules/research/nanites/nanite_programs/healing.dm b/code/modules/research/nanites/nanite_programs/healing.dm
index d3a268047e..8aab7f1e2b 100644
--- a/code/modules/research/nanites/nanite_programs/healing.dm
+++ b/code/modules/research/nanites/nanite_programs/healing.dm
@@ -48,7 +48,7 @@
/datum/nanite_program/purging
name = "Blood Purification"
- desc = "The nanites purge toxins and chemicals from the host's bloodstream."
+ desc = "The nanites purge toxins and chemicals from the host's bloodstream, however it is dangerous to slimepeople biology due to inaccuracy."
use_rate = 1
rogue_types = list(/datum/nanite_program/suffocating, /datum/nanite_program/necrotic)
@@ -93,7 +93,7 @@
/datum/nanite_program/blood_restoring/check_conditions()
if(iscarbon(host_mob))
var/mob/living/carbon/C = host_mob
- if(C.blood_volume >= BLOOD_VOLUME_SAFE)
+ if(C.blood_volume >= (BLOOD_VOLUME_SAFE*C.blood_ratio))
return FALSE
else
return FALSE
@@ -143,7 +143,7 @@
/datum/nanite_program/purging_advanced
name = "Selective Blood Purification"
desc = "The nanites purge toxins and dangerous chemicals from the host's bloodstream, while ignoring beneficial chemicals. \
- The added processing power required to analyze the chemicals severely increases the nanite consumption rate."
+ The added processing power required to analyze the chemicals severely increases the nanite consumption rate. Due to added complexity, it is safe with slimepeople biology."
use_rate = 2
rogue_types = list(/datum/nanite_program/suffocating, /datum/nanite_program/necrotic)
@@ -157,7 +157,7 @@
return ..()
/datum/nanite_program/purging_advanced/active_effect()
- host_mob.adjustToxLoss(-1)
+ host_mob.adjustToxLoss(-1, forced = TRUE)
for(var/datum/reagent/toxin/R in host_mob.reagents.reagent_list)
host_mob.reagents.remove_reagent(R.id,1)
@@ -256,4 +256,3 @@
log_game("[C] has been successfully defibrillated by nanites.")
else
playsound(C, 'sound/machines/defib_failed.ogg', 50, 0)
-
diff --git a/code/modules/research/nanites/nanite_programs/utility.dm b/code/modules/research/nanites/nanite_programs/utility.dm
index 77fb4e1005..44b85e4210 100644
--- a/code/modules/research/nanites/nanite_programs/utility.dm
+++ b/code/modules/research/nanites/nanite_programs/utility.dm
@@ -190,13 +190,13 @@
if(!iscarbon(host_mob))
return FALSE
var/mob/living/carbon/C = host_mob
- if(C.nutrition <= NUTRITION_LEVEL_WELL_FED)
+ if(C.nutrition <= NUTRITION_LEVEL_STARVING)
return FALSE
return ..()
/datum/nanite_program/metabolic_synthesis/active_effect()
host_mob.nutrition -= 0.5
- nanites.adjust_nanites(0.5)
+ nanites.adjust_nanites(src, 0.5)
/datum/nanite_program/triggered/access
name = "Subdermal ID"
diff --git a/code/modules/research/nanites/nanite_programs/weapon.dm b/code/modules/research/nanites/nanite_programs/weapon.dm
index f4914d4af0..4f29398e91 100644
--- a/code/modules/research/nanites/nanite_programs/weapon.dm
+++ b/code/modules/research/nanites/nanite_programs/weapon.dm
@@ -46,13 +46,13 @@
/datum/nanite_program/aggressive_replication
name = "Aggressive Replication"
desc = "Nanites will consume organic matter to improve their replication rate, damaging the host. The efficiency increases with the volume of nanites, requiring 200 to break even."
- use_rate = 1
+ use_rate = 0
rogue_types = list(/datum/nanite_program/necrotic)
/datum/nanite_program/aggressive_replication/active_effect()
- var/extra_regen = round(nanites.nanite_volume / 200, 0.1)
- nanites.adjust_nanites(extra_regen)
- host_mob.adjustBruteLoss(extra_regen / 2, TRUE)
+ var/extra_regen = round(nanites.nanite_volume / 50, 0.1)
+ nanites.adjust_nanites(src, extra_regen)
+ host_mob.adjustBruteLoss(extra_regen / 3, TRUE)
/datum/nanite_program/meltdown
name = "Meltdown"
@@ -89,10 +89,9 @@
/datum/nanite_program/triggered/explosive/proc/boom()
var/nanite_amount = nanites.nanite_volume
- var/dev_range = FLOOR(nanite_amount/200, 1) - 1
var/heavy_range = FLOOR(nanite_amount/100, 1) - 1
var/light_range = FLOOR(nanite_amount/50, 1) - 1
- explosion(host_mob, dev_range, heavy_range, light_range)
+ explosion(host_mob, 0, heavy_range, light_range)
qdel(nanites)
//TODO make it defuse if triggered again
@@ -197,4 +196,4 @@
if(host_mob.mind && host_mob.mind.has_antag_datum(/datum/antagonist/brainwashed))
host_mob.mind.remove_antag_datum(/datum/antagonist/brainwashed)
log_game("[key_name(host_mob)] is no longer brainwashed by nanites.")
- cooldown = world.time + 450
\ No newline at end of file
+ cooldown = world.time + 450
diff --git a/code/modules/research/techweb/all_nodes.dm b/code/modules/research/techweb/all_nodes.dm
index c6487c92f0..9c3a1a4f36 100644
--- a/code/modules/research/techweb/all_nodes.dm
+++ b/code/modules/research/techweb/all_nodes.dm
@@ -69,7 +69,7 @@
display_name = "Advanced Biotechnology"
description = "Advanced Biotechnology"
prereq_ids = list("biotech")
- design_ids = list("piercesyringe", "crewpinpointer", "smoke_machine", "plasmarefiller", "limbgrower", "defibrillator", "meta_beaker", "healthanalyzer_advanced","harvester","holobarrier_med","smartdartgun","medicinalsmartdart")
+ design_ids = list("piercesyringe", "crewpinpointer", "smoke_machine", "plasmarefiller", "limbgrower", "defibrillator", "meta_beaker", "healthanalyzer_advanced","harvester","holobarrier_med","smartdartgun","medicinalsmartdart", "pHmeter")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
export_price = 5000
@@ -221,13 +221,22 @@
//research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 1500)
//export_price = 5000
+/datum/techweb_node/computer_board_gaming
+ id = "computer_board_gaming"
+ display_name = "Games and Toys"
+ description = "For the slackers on the station."
+ prereq_ids = list("comptech")
+ design_ids = list("arcade_battle", "arcade_orion", "slotmachine", "autoylathe")
+ research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 1000)
+ export_price = 5000
+
/////////////////////////Bluespace tech/////////////////////////
/datum/techweb_node/bluespace_basic //Bluespace-memery
id = "bluespace_basic"
display_name = "Basic Bluespace Theory"
description = "Basic studies into the mysterious alternate dimension known as bluespace."
prereq_ids = list("base", "datatheory")
- design_ids = list("beacon", "xenobioconsole", "telesci_gps")
+ design_ids = list("beacon", "xenobioconsole", "telesci_gps", "xenobio_monkeys")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
export_price = 5000
@@ -236,7 +245,7 @@
display_name = "Applied Bluespace Research"
description = "Using bluespace to make things faster and better."
prereq_ids = list("bluespace_basic", "engineering")
- design_ids = list("bs_rped","biobag_holding","minerbag_holding", "bluespacebeaker", "bluespacesyringe", "phasic_scanning", "bluespacesmartdart")
+ design_ids = list("bs_rped","biobag_holding","minerbag_holding", "bluespacebeaker", "bluespacesyringe", "phasic_scanning", "bluespacesmartdart", "xenobio_slimebasic")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 5000)
export_price = 5000
@@ -245,7 +254,7 @@
display_name = "Advanced Bluespace Research"
description = "Deeper understanding of how the Bluespace dimension works"
prereq_ids = list("practical_bluespace", "high_efficiency")
- design_ids = list("bluespace_matter_bin", "femto_mani", "triphasic_scanning", "bluespace_crystal")
+ design_ids = list("bluespace_matter_bin", "femto_mani", "triphasic_scanning", "bluespace_crystal", "xenobio_slimeadv")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 10000)
export_price = 5000
@@ -278,10 +287,10 @@
/datum/techweb_node/bluespace_warping
id = "bluespace_warping"
- display_name = "Bluespace Teleportation tech"
- description = "Traversing through space at an instant with Bluespace."
+ display_name = "Bluespace Travel"
+ description = "Application of Bluespace for static teleportation technology."
prereq_ids = list("adv_power", "adv_bluespace")
- design_ids = list( "tele_station", "tele_hub", "quantumpad", "launchpad", "launchpad_console", "teleconsole", "roastingstick")
+ design_ids = list("tele_station", "tele_hub", "quantumpad", "quantum_keycard", "launchpad", "launchpad_console", "teleconsole", "roastingstick")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
export_price = 5000
@@ -423,7 +432,7 @@
display_name = "Computer Consoles"
description = "Computers and how they work."
prereq_ids = list("datatheory")
- design_ids = list("cargo", "cargorequest", "libraryconsole", "mining", "crewconsole", "rdcamera", "comconsole", "idcardconsole", "seccamera")
+ design_ids = list("cargo", "cargorequest", "libraryconsole", "mining", "miningshuttle", "crewconsole", "rdcamera", "comconsole", "idcardconsole", "seccamera")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2000)
export_price = 5000
@@ -517,7 +526,7 @@
display_name = "Cybernetic Organs"
description = "We have the technology to rebuild him."
prereq_ids = list("adv_biotech")
- design_ids = list("cybernetic_heart", "cybernetic_liver", "cybernetic_liver_u", "cybernetic_lungs", "cybernetic_lungs_u")
+ design_ids = list("cybernetic_heart", "cybernetic_liver", "cybernetic_liver_u", "cybernetic_lungs", "cybernetic_lungs_u", "cybernetic_tongue")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
export_price = 5000
@@ -672,7 +681,7 @@
display_name = "Ballistic Weaponry"
description = "This isn't research.. This is reverse-engineering!"
prereq_ids = list("weaponry")
- design_ids = list("mag_oldsmg", "mag_oldsmg_ap", "mag_oldsmg_ic")
+ design_ids = list("mag_oldsmg", "mag_oldsmg_ap", "mag_oldsmg_ic", "mag_oldsmg_rubber", "mag_oldsmg_tx")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2750)
export_price = 5000
@@ -1049,6 +1058,15 @@
continue
boost_item_paths |= UI.item //allows deconning to unlock.
+/datum/techweb_node/advanced_illegl_ballistics
+ id = "advanced_illegal_ballistics"
+ display_name = "Advanced Illegal Ballistics"
+ description = "Advanced Ballistic for Illegal weaponds."
+ design_ids = list("10mm","10mmap","10mminc","10mmhp","pistolm9mm","m45","bolt_clip")
+ prereq_ids = list("ballistic_weapons","syndicate_basic","explosive_weapons")
+ research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 25000) //This gives sec lethal mags/clips for guns form traitors or space.
+ export_price = 7000
+
//Helpers for debugging/balancing the techweb in its entirety!
/proc/total_techweb_exports()
var/list/datum/techweb_node/processing = list()
diff --git a/code/modules/research/xenobiology/crossbreeding/_status_effects.dm b/code/modules/research/xenobiology/crossbreeding/_status_effects.dm
index ad5bfa27dc..b9e7122d07 100644
--- a/code/modules/research/xenobiology/crossbreeding/_status_effects.dm
+++ b/code/modules/research/xenobiology/crossbreeding/_status_effects.dm
@@ -680,7 +680,7 @@ datum/status_effect/stabilized/blue/on_remove()
if(!F)
F = get_turf(owner)
range = 50
- if(do_teleport(owner, F, range))
+ if(do_teleport(owner, F, range, channel = TELEPORT_CHANNEL_BLUESPACE))
to_chat(owner, "[linked_extract] will take some time to re-align you on the bluespace axis.")
do_sparks(5,FALSE,owner)
owner.apply_status_effect(/datum/status_effect/bluespacestabilization)
diff --git a/code/modules/research/xenobiology/crossbreeding/_weapons.dm b/code/modules/research/xenobiology/crossbreeding/_weapons.dm
index 141e6b1fe1..4753abff97 100644
--- a/code/modules/research/xenobiology/crossbreeding/_weapons.dm
+++ b/code/modules/research/xenobiology/crossbreeding/_weapons.dm
@@ -9,11 +9,13 @@
righthand_file = 'icons/mob/inhands/weapons/guns_righthand.dmi'
item_flags = ABSTRACT | DROPDEL
w_class = WEIGHT_CLASS_HUGE
+ slot_flags = NONE
force = 5
max_charges = 1 //Recharging costs blood.
recharge_rate = 1
ammo_type = /obj/item/ammo_casing/magic/bloodchill
fire_sound = 'sound/effects/attackblob.ogg'
+ total_mass = TOTAL_MASS_HAND_REPLACEMENT
/obj/item/gun/magic/bloodchill/Initialize()
. = ..()
@@ -46,4 +48,4 @@
/obj/item/projectile/magic/bloodchill/on_hit(mob/living/target)
. = ..()
if(isliving(target))
- target.apply_status_effect(/datum/status_effect/bloodchill)
\ No newline at end of file
+ target.apply_status_effect(/datum/status_effect/bloodchill)
diff --git a/code/modules/research/xenobiology/crossbreeding/burning.dm b/code/modules/research/xenobiology/crossbreeding/burning.dm
index 38362e6d64..363331e12d 100644
--- a/code/modules/research/xenobiology/crossbreeding/burning.dm
+++ b/code/modules/research/xenobiology/crossbreeding/burning.dm
@@ -144,7 +144,7 @@ Burning extracts:
user.visible_message("[src] sparks, and lets off a shockwave of bluespace energy!")
for(var/mob/living/L in range(1, get_turf(user)))
if(L != user)
- do_teleport(L, get_turf(L), 6, asoundin = 'sound/effects/phasein.ogg') //Somewhere between the effectiveness of fake and real BS crystal
+ do_teleport(L, get_turf(L), 6, asoundin = 'sound/effects/phasein.ogg', channel = TELEPORT_CHANNEL_BLUESPACE) //Somewhere between the effectiveness of fake and real BS crystal
new /obj/effect/particle_effect/sparks(get_turf(L))
playsound(get_turf(L), "sparks", 50, 1)
..()
diff --git a/code/modules/research/xenobiology/crossbreeding/consuming.dm b/code/modules/research/xenobiology/crossbreeding/consuming.dm
index b51a7b2553..0b2d60da8c 100644
--- a/code/modules/research/xenobiology/crossbreeding/consuming.dm
+++ b/code/modules/research/xenobiology/crossbreeding/consuming.dm
@@ -232,7 +232,7 @@ Consuming extracts:
L.Cut(I,I+1)
if(target)
- do_teleport(M, target, 0, asoundin = 'sound/effects/phasein.ogg')
+ do_teleport(M, target, 0, asoundin = 'sound/effects/phasein.ogg', channel = TELEPORT_CHANNEL_BLUESPACE)
new /obj/effect/particle_effect/sparks(get_turf(M))
playsound(get_turf(M), "sparks", 50, 1)
diff --git a/code/modules/research/xenobiology/xenobiology.dm b/code/modules/research/xenobiology/xenobiology.dm
index ed8317f05e..673c7d9262 100644
--- a/code/modules/research/xenobiology/xenobiology.dm
+++ b/code/modules/research/xenobiology/xenobiology.dm
@@ -494,7 +494,7 @@
to_chat(user, "You feel your body vibrating...")
if(do_after(user, 25, target = user))
to_chat(user, "You teleport!")
- do_teleport(user, get_turf(user), 6, asoundin = 'sound/weapons/emitter2.ogg')
+ do_teleport(user, get_turf(user), 6, asoundin = 'sound/weapons/emitter2.ogg', channel = TELEPORT_CHANNEL_BLUESPACE)
return 300
if(SLIME_ACTIVATE_MAJOR)
@@ -510,7 +510,7 @@
if(teleport_x && teleport_y && teleport_z)
var/turf/T = locate(teleport_x, teleport_y, teleport_z)
to_chat(user, "You snap back to your anchor point!")
- do_teleport(user, T, asoundin = 'sound/weapons/emitter2.ogg')
+ do_teleport(user, T, asoundin = 'sound/weapons/emitter2.ogg', channel = TELEPORT_CHANNEL_BLUESPACE)
return 450
diff --git a/code/modules/shuttle/ferry.dm b/code/modules/shuttle/ferry.dm
index eaa1f36b75..06e38bb3eb 100644
--- a/code/modules/shuttle/ferry.dm
+++ b/code/modules/shuttle/ferry.dm
@@ -37,4 +37,4 @@
return
last_request = world.time
to_chat(usr, "Your request has been received by CentCom.")
- to_chat(GLOB.admins, "FERRY: [ADMIN_LOOKUPFLW(usr)] (Move Ferry) is requesting to move the transport ferry to CentCom.")
+ to_chat(GLOB.admins, "FERRY: [ADMIN_LOOKUPFLW(usr)] (Move Ferry) is requesting to move the transport ferry to CentCom.")
diff --git a/code/modules/shuttle/on_move.dm b/code/modules/shuttle/on_move.dm
index a6904c28cc..dd2d7483e3 100644
--- a/code/modules/shuttle/on_move.dm
+++ b/code/modules/shuttle/on_move.dm
@@ -179,7 +179,7 @@ All ShuttleMove procs go here
for(var/obj/machinery/door/airlock/A in range(1, src)) // includes src
A.shuttledocked = FALSE
A.air_tight = TRUE
- INVOKE_ASYNC(A, /obj/machinery/door/.proc/close)
+ addtimer(CALLBACK(A, /obj/machinery/door/.proc/close), 0)
/obj/machinery/door/airlock/afterShuttleMove(turf/oldT, list/movement_force, shuttle_dir, shuttle_preferred_direction, move_dir, rotation)
. = ..()
diff --git a/code/modules/shuttle/supply.dm b/code/modules/shuttle/supply.dm
index b54fceb3e7..2249f5f10e 100644
--- a/code/modules/shuttle/supply.dm
+++ b/code/modules/shuttle/supply.dm
@@ -60,6 +60,10 @@ GLOBAL_LIST_INIT(blacklisted_cargo_types, typecacheof(list(
for(var/a in T.GetAllContents())
if(is_type_in_typecache(a, GLOB.blacklisted_cargo_types))
return FALSE
+ if(istype(a, /obj/structure/closet))//Prevents eigenlockers from ending up at CC
+ var/obj/structure/closet/c = a
+ if(c.eigen_teleport == TRUE)
+ return FALSE
return TRUE
/obj/docking_port/mobile/supply/request(obj/docking_port/stationary/S)
diff --git a/code/modules/spells/spell_types/area_teleport.dm b/code/modules/spells/spell_types/area_teleport.dm
index ab399f4e2a..7bede9f8be 100644
--- a/code/modules/spells/spell_types/area_teleport.dm
+++ b/code/modules/spells/spell_types/area_teleport.dm
@@ -58,7 +58,7 @@
var/success = 0
while(tempL.len)
attempt = pick(tempL)
- target.Move(attempt)
+ do_teleport(target, attempt, channel = TELEPORT_CHANNEL_MAGIC)
if(get_turf(target) == attempt)
success = 1
break
@@ -66,7 +66,7 @@
tempL.Remove(attempt)
if(!success)
- target.forceMove(L)
+ do_teleport(target, L, forceMove = TRUE, channel = TELEPORT_CHANNEL_MAGIC)
playsound(get_turf(user), sound2, 50,1)
return
diff --git a/code/modules/spells/spell_types/shapeshift.dm b/code/modules/spells/spell_types/shapeshift.dm
index 88c6ce175f..1576c55326 100644
--- a/code/modules/spells/spell_types/shapeshift.dm
+++ b/code/modules/spells/spell_types/shapeshift.dm
@@ -15,7 +15,6 @@
var/die_with_shapeshifted_form = TRUE
var/convert_damage = FALSE //If you want to convert the caster's health to the shift, and vice versa.
var/convert_damage_type = BRUTE //Since simplemobs don't have advanced damagetypes, what to convert damage back into.
-
var/shapeshift_type
var/list/possible_shapes = list(/mob/living/simple_animal/mouse,\
/mob/living/simple_animal/pet/dog/corgi,\
@@ -167,4 +166,4 @@
/datum/soullink/shapeshift/sharerDies(gibbed, mob/living/sharer)
if(source)
- source.shapeDeath(gibbed)
\ No newline at end of file
+ source.shapeDeath(gibbed)
diff --git a/code/modules/spells/spell_types/turf_teleport.dm b/code/modules/spells/spell_types/turf_teleport.dm
index 093285b74d..8a45f2be22 100644
--- a/code/modules/spells/spell_types/turf_teleport.dm
+++ b/code/modules/spells/spell_types/turf_teleport.dm
@@ -40,6 +40,5 @@
if(!picked || !isturf(picked))
return
- if(!target.Move(picked))
- target.forceMove(picked)
- playsound(get_turf(user), sound2, 50,1)
+ if(do_teleport(user, picked, forceMove = TRUE, channel = TELEPORT_CHANNEL_MAGIC))
+ playsound(get_turf(user), sound1, 50,1)
diff --git a/code/modules/station_goals/shield.dm b/code/modules/station_goals/shield.dm
index 98f5534d06..be88d0ecdc 100644
--- a/code/modules/station_goals/shield.dm
+++ b/code/modules/station_goals/shield.dm
@@ -133,6 +133,7 @@
mode = "M-SHIELD"
speed_process = TRUE
var/kill_range = 14
+ density = 0
/obj/machinery/satellite/meteor_shield/sci
name = "\improper Meteor Shield Satellite"
diff --git a/code/modules/surgery/advanced/bioware/nerve_grounding.dm b/code/modules/surgery/advanced/bioware/nerve_grounding.dm
index f4b23c89b1..99902ff6d6 100644
--- a/code/modules/surgery/advanced/bioware/nerve_grounding.dm
+++ b/code/modules/surgery/advanced/bioware/nerve_grounding.dm
@@ -17,10 +17,14 @@
time = 155
/datum/surgery_step/ground_nerves/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
- user.visible_message("[user] starts splicing together [target]'s nerves.", "You start splicing together [target]'s nerves.")
+ display_results(user, target, "You start rerouting [target]'s nerves.",
+ "[user] starts rerouting [target]'s nerves.",
+ "[user] starts manipulating [target]'s nervous system.")
/datum/surgery_step/ground_nerves/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
- user.visible_message("[user] successfully splices [target]'s nervous system!", "You successfully splice [target]'s nervous system!")
+ display_results(user, target, "You successfully reroute [target]'s nervous system!",
+ "[user] successfully reroutes [target]'s nervous system!",
+ "[user] finishes manipulating [target]'s nervous system.")
new /datum/bioware/grounded_nerves(target)
return TRUE
@@ -37,4 +41,4 @@
/datum/bioware/grounded_nerves/on_lose()
..()
- owner.physiology.siemens_coeff = prev_coeff
\ No newline at end of file
+ owner.physiology.siemens_coeff = prev_coeff
diff --git a/code/modules/surgery/advanced/bioware/nerve_splicing.dm b/code/modules/surgery/advanced/bioware/nerve_splicing.dm
index 6192786cc4..e6e66e1b6e 100644
--- a/code/modules/surgery/advanced/bioware/nerve_splicing.dm
+++ b/code/modules/surgery/advanced/bioware/nerve_splicing.dm
@@ -10,17 +10,20 @@
/datum/surgery_step/close)
possible_locs = list(BODY_ZONE_CHEST)
bioware_target = BIOWARE_NERVES
-
/datum/surgery_step/splice_nerves
name = "splice nerves"
accept_hand = TRUE
time = 155
/datum/surgery_step/splice_nerves/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
- user.visible_message("[user] starts splicing together [target]'s nerves.", "You start splicing together [target]'s nerves.")
+ display_results(user, target, "You start splicing together [target]'s nerves.",
+ "[user] starts splicing together [target]'s nerves.",
+ "[user] starts manipulating [target]'s nervous system.")
/datum/surgery_step/splice_nerves/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
- user.visible_message("[user] successfully splices [target]'s nervous system!", "You successfully splice [target]'s nervous system!")
+ display_results(user, target, "You successfully splice [target]'s nervous system!",
+ "[user] successfully splices [target]'s nervous system!",
+ "[user] finishes manipulating [target]'s nervous system.")
new /datum/bioware/spliced_nerves(target)
return TRUE
@@ -28,11 +31,9 @@
name = "Spliced Nerves"
desc = "Nerves are connected to each other multiple times, greatly reducing the impact of stunning effects."
mod_type = BIOWARE_NERVES
-
/datum/bioware/spliced_nerves/on_gain()
..()
owner.physiology.stun_mod *= 0.5
-
/datum/bioware/spliced_nerves/on_lose()
..()
- owner.physiology.stun_mod *= 2
\ No newline at end of file
+ owner.physiology.stun_mod *= 2
diff --git a/code/modules/surgery/advanced/bioware/vein_threading.dm b/code/modules/surgery/advanced/bioware/vein_threading.dm
index 7a03833c51..fc0868c116 100644
--- a/code/modules/surgery/advanced/bioware/vein_threading.dm
+++ b/code/modules/surgery/advanced/bioware/vein_threading.dm
@@ -10,17 +10,20 @@
/datum/surgery_step/close)
possible_locs = list(BODY_ZONE_CHEST)
bioware_target = BIOWARE_CIRCULATION
-
/datum/surgery_step/thread_veins
name = "thread veins"
accept_hand = TRUE
time = 125
/datum/surgery_step/thread_veins/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
- user.visible_message("[user] starts weaving [target]'s circulatory system.", "You start weaving [target]'s circulatory system.")
+ display_results(user, target, "You start weaving [target]'s circulatory system.",
+ "[user] starts weaving [target]'s circulatory system.",
+ "[user] starts manipulating [target]'s circulatory system.")
/datum/surgery_step/thread_veins/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
- user.visible_message("[user] weaves [target]'s circulatory system into a resistant mesh!", "You weave [target]'s circulatory system into a resistant mesh!")
+ display_results(user, target, "You weave [target]'s circulatory system into a resistant mesh!",
+ "[user] weaves [target]'s circulatory system into a resistant mesh!",
+ "[user] finishes manipulating [target]'s circulatory system.")
new /datum/bioware/threaded_veins(target)
return TRUE
@@ -28,11 +31,9 @@
name = "Threaded Veins"
desc = "The circulatory system is woven into a mesh, severely reducing the amount of blood lost from wounds."
mod_type = BIOWARE_CIRCULATION
-
/datum/bioware/threaded_veins/on_gain()
..()
owner.physiology.bleed_mod *= 0.25
-
/datum/bioware/threaded_veins/on_lose()
..()
- owner.physiology.bleed_mod *= 4
\ No newline at end of file
+ owner.physiology.bleed_mod *= 4
diff --git a/code/modules/surgery/advanced/brainwashing.dm b/code/modules/surgery/advanced/brainwashing.dm
index 23783f1bf2..730a912189 100644
--- a/code/modules/surgery/advanced/brainwashing.dm
+++ b/code/modules/surgery/advanced/brainwashing.dm
@@ -2,7 +2,6 @@
name = "Brainwashing Surgery Disk"
desc = "The disk provides instructions on how to impress an order on a brain, making it the primary objective of the patient."
surgeries = list(/datum/surgery/advanced/brainwashing)
-
/datum/surgery/advanced/brainwashing
name = "Brainwashing"
desc = "A surgical procedure which directly implants a directive into the patient's brain, making it their absolute priority. It can be cleared using a mindshield implant."
@@ -13,10 +12,9 @@
/datum/surgery_step/clamp_bleeders,
/datum/surgery_step/brainwash,
/datum/surgery_step/close)
-
+
species = list(/mob/living/carbon/human)
possible_locs = list(BODY_ZONE_HEAD)
-
/datum/surgery/advanced/brainwashing/can_start(mob/user, mob/living/carbon/target)
if(!..())
return FALSE
@@ -24,27 +22,29 @@
if(!B)
return FALSE
return TRUE
-
/datum/surgery_step/brainwash
name = "brainwash"
implements = list(/obj/item/hemostat = 85, TOOL_WIRECUTTER = 50, /obj/item/stack/packageWrap = 35, /obj/item/stack/cable_coil = 15)
time = 200
var/objective
-
/datum/surgery_step/brainwash/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
objective = stripped_input(user, "Choose the objective to imprint on your victim's brain.", "Brainwashing", null, MAX_MESSAGE_LEN)
if(!objective)
return -1
- user.visible_message("[user] begins to tinker with [target]'s brain.", "You begin to brainwash [target]...")
+ display_results(user, target, "You begin to brainwash [target]...",
+ "[user] begins to fix [target]'s brain.",
+ "[user] begins to perform surgery on [target]'s brain.")
/datum/surgery_step/brainwash/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
if(!target.mind)
- user.visible_message("[target] doesn't respond to the brainwashing, as if [target.p_they()] lacked a mind...")
+ to_chat(user, "[target] doesn't respond to the brainwashing, as if [target.p_they()] lacked a mind...")
return FALSE
if(HAS_TRAIT(target, TRAIT_MINDSHIELD))
- user.visible_message("You hear a faint buzzing from a device inside [target]'s brain, and the brainwashing is erased.")
+ to_chat(user, "You hear a faint buzzing from a device inside [target]'s brain, and the brainwashing is erased.")
return FALSE
- user.visible_message("[user] successfully brainwashes [target]!", "You succeed in brainwashing [target].")
+ display_results(user, target, "You succeed in brainwashing [target].",
+ "[user] successfully fixes [target]'s brain!",
+ "[user] completes the surgery on [target]'s brain.")
to_chat(target, "A new compulsion fills your mind... you feel forced to obey it!")
brainwash(target, objective)
message_admins("[ADMIN_LOOKUPFLW(user)] surgically brainwashed [ADMIN_LOOKUPFLW(target)] with the objective '[objective]'.")
@@ -53,8 +53,10 @@
/datum/surgery_step/brainwash/failure(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
if(target.getorganslot(ORGAN_SLOT_BRAIN))
- user.visible_message("[user] damages some brain tissue!", "You bruise some brain tissue!")
+ display_results(user, target, "You screw up, bruising the brain tissue!",
+ "[user] screws up, causing brain damage!",
+ "[user] completes the surgery on [target]'s brain.")
target.adjustBrainLoss(40)
else
user.visible_message("[user] suddenly notices that the brain [user.p_they()] [user.p_were()] working on is not there anymore.", "You suddenly notice that the brain you were working on is not there anymore.")
- return FALSE
\ No newline at end of file
+ return FALSE
diff --git a/code/modules/surgery/advanced/lobotomy.dm b/code/modules/surgery/advanced/lobotomy.dm
index f74346b193..1c09f5f7da 100644
--- a/code/modules/surgery/advanced/lobotomy.dm
+++ b/code/modules/surgery/advanced/lobotomy.dm
@@ -12,7 +12,6 @@
species = list(/mob/living/carbon/human, /mob/living/carbon/monkey)
possible_locs = list(BODY_ZONE_HEAD)
requires_bodypart_type = 0
-
/datum/surgery/advanced/lobotomy/can_start(mob/user, mob/living/carbon/target)
if(!..())
return FALSE
@@ -20,23 +19,25 @@
if(!B)
return FALSE
return TRUE
-
/datum/surgery_step/lobotomize
name = "perform lobotomy"
implements = list(/obj/item/scalpel = 85, /obj/item/melee/transforming/energy/sword = 55, /obj/item/kitchen/knife = 35,
/obj/item/shard = 25, /obj/item = 20)
time = 100
-
/datum/surgery_step/lobotomize/tool_check(mob/user, obj/item/tool)
if(implement_type == /obj/item && !tool.is_sharp())
return FALSE
return TRUE
/datum/surgery_step/lobotomize/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
- user.visible_message("[user] begins to cut a piece of [target]'s brain.", "You begin to cut a piece of [target]'s brain...")
+ display_results(user, target, "You begin to perform a lobotomy on [target]'s brain...",
+ "[user] begins to perform a lobotomy on [target]'s brain.",
+ "[user] begins to perform surgery on [target]'s brain.")
/datum/surgery_step/lobotomize/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
- user.visible_message("[user] successfully lobotomizes [target]!", "You succeed in lobotomizing [target].")
+ display_results(user, target, "You succeed in lobotomizing [target].",
+ "[user] successfully lobotomizes [target]!",
+ "[user] completes the surgery on [target]'s brain.")
target.cure_all_traumas(TRAUMA_RESILIENCE_LOBOTOMY)
if(target.mind && target.mind.has_antag_datum(/datum/antagonist/brainwashed))
target.mind.remove_antag_datum(/datum/antagonist/brainwashed)
@@ -51,7 +52,9 @@
/datum/surgery_step/lobotomize/failure(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
if(target.getorganslot(ORGAN_SLOT_BRAIN))
- user.visible_message("[user] removes the wrong part, causing more damage!", "You remove the wrong part, causing more damage!")
+ display_results(user, target, "You remove the wrong part, causing more damage!",
+ "[user] successfully lobotomizes [target]!",
+ "[user] completes the surgery on [target]'s brain.")
target.adjustBrainLoss(80)
switch(rand(1,3))
if(1)
@@ -62,4 +65,4 @@
target.gain_trauma_type(BRAIN_TRAUMA_SPECIAL, TRAUMA_RESILIENCE_MAGIC)
else
user.visible_message("[user] suddenly notices that the brain [user.p_they()] [user.p_were()] working on is not there anymore.", "You suddenly notice that the brain you were working on is not there anymore.")
- return FALSE
\ No newline at end of file
+ return FALSE
diff --git a/code/modules/surgery/advanced/necrotic_revival.dm b/code/modules/surgery/advanced/necrotic_revival.dm
index a88bb51b31..8c57930252 100644
--- a/code/modules/surgery/advanced/necrotic_revival.dm
+++ b/code/modules/surgery/advanced/necrotic_revival.dm
@@ -7,9 +7,7 @@
/datum/surgery_step/clamp_bleeders,
/datum/surgery_step/bionecrosis,
/datum/surgery_step/close)
-
possible_locs = list(BODY_ZONE_HEAD)
-
/datum/surgery/advanced/necrotic_revival/can_start(mob/user, mob/living/carbon/target)
. = ..()
var/obj/item/organ/zombie_infection/ZI = target.getorganslot(ORGAN_SLOT_ZOMBIE)
@@ -19,16 +17,21 @@
/datum/surgery_step/bionecrosis
name = "start bionecrosis"
implements = list(/obj/item/hemostat = 100, TOOL_SCREWDRIVER = 35, /obj/item/pen = 15)
+ implements = list(/obj/item/reagent_containers/syringe = 100, /obj/item/pen = 30)
time = 50
chems_needed = list("zombiepowder", "rezadone")
require_all_chems = FALSE
/datum/surgery_step/bionecrosis/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
- user.visible_message("[user] begins to stimulate [target]'s brain.", "You begin to stimulate [target]'s brain...")
+ display_results(user, target, "You begin to grow a romerol tumor on [target]'s brain...",
+ "[user] begins to tinker with [target]'s brain...",
+ "[user] begins to perform surgery on [target]'s brain.")
/datum/surgery_step/bionecrosis/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
- user.visible_message("[user] successfully grows a necrotic tumor on [target]'s brain!", "You succeed in growing a necrotic tumor on [target]'s brain.")
+ display_results(user, target, "You succeed in growing a romerol tumor on [target]'s brain.",
+ "[user] successfully grows a romerol tumor on [target]'s brain!",
+ "[user] completes the surgery on [target]'s brain.")
if(!target.getorganslot(ORGAN_SLOT_ZOMBIE))
var/obj/item/organ/zombie_infection/ZI = new()
ZI.Insert(target)
- return TRUE
\ No newline at end of file
+ return TRUE
diff --git a/code/modules/surgery/advanced/pacification.dm b/code/modules/surgery/advanced/pacification.dm
index 15e34d003c..d5585d71a8 100644
--- a/code/modules/surgery/advanced/pacification.dm
+++ b/code/modules/surgery/advanced/pacification.dm
@@ -7,31 +7,34 @@
/datum/surgery_step/clamp_bleeders,
/datum/surgery_step/pacify,
/datum/surgery_step/close)
-
species = list(/mob/living/carbon/human, /mob/living/carbon/monkey)
possible_locs = list(BODY_ZONE_HEAD)
requires_bodypart_type = 0
-
/datum/surgery/advanced/pacify/can_start(mob/user, mob/living/carbon/target)
. = ..()
var/obj/item/organ/brain/B = target.getorganslot(ORGAN_SLOT_BRAIN)
if(!B)
return FALSE
-
/datum/surgery_step/pacify
name = "rewire brain"
implements = list(/obj/item/hemostat = 100, TOOL_SCREWDRIVER = 35, /obj/item/pen = 15)
time = 40
/datum/surgery_step/pacify/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
- user.visible_message("[user] begins to reshape [target]'s brain.", "You begin to reshape [target]'s brain...")
+ display_results(user, target, "You begin to pacify [target]...",
+ "[user] begins to fix [target]'s brain.",
+ "[user] begins to perform surgery on [target]'s brain.")
/datum/surgery_step/pacify/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
- user.visible_message("[user] reshapes [target]'s brain!", "You succeed in reshaping [target]'s brain.")
+ display_results(user, target, "You succeed in neurologically pacifying [target].",
+ "[user] successfully fixes [target]'s brain!",
+ "[user] completes the surgery on [target]'s brain.")
target.gain_trauma(/datum/brain_trauma/severe/pacifism, TRAUMA_RESILIENCE_LOBOTOMY)
return TRUE
/datum/surgery_step/pacify/failure(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
- user.visible_message("[user] reshapes [target]'s brain!", "You screwed up, and rewired [target]'s brain the wrong way around...")
+ display_results(user, target, "You screw up, rewiring [target]'s brain the wrong way around...",
+ "[user] screws up, causing brain damage!",
+ "[user] completes the surgery on [target]'s brain.")
target.gain_trauma_type(BRAIN_TRAUMA_SEVERE, TRAUMA_RESILIENCE_LOBOTOMY)
- return FALSE
\ No newline at end of file
+ return FALSE
diff --git a/code/modules/surgery/advanced/revival.dm b/code/modules/surgery/advanced/revival.dm
index ebda8a04e2..01c30f174a 100644
--- a/code/modules/surgery/advanced/revival.dm
+++ b/code/modules/surgery/advanced/revival.dm
@@ -8,11 +8,9 @@
/datum/surgery_step/incise,
/datum/surgery_step/revive,
/datum/surgery_step/close)
-
species = list(/mob/living/carbon/human, /mob/living/carbon/monkey)
possible_locs = list(BODY_ZONE_HEAD)
requires_bodypart_type = 0
-
/datum/surgery/advanced/revival/can_start(mob/user, mob/living/carbon/target)
if(!..())
return FALSE
@@ -24,12 +22,10 @@
if(!B)
return FALSE
return TRUE
-
/datum/surgery_step/revive
name = "electrically stimulate brain"
implements = list(/obj/item/twohanded/shockpaddles = 100, /obj/item/abductor/gizmo = 100, /obj/item/melee/baton = 75, /obj/item/organ/cyberimp/arm/baton = 75, /obj/item/organ/cyberimp/arm/gun/taser = 60, /obj/item/gun/energy/e_gun/advtaser = 60, /obj/item/gun/energy/taser = 60)
time = 120
-
/datum/surgery_step/revive/tool_check(mob/user, obj/item/tool)
. = TRUE
if(istype(tool, /obj/item/twohanded/shockpaddles))
@@ -51,25 +47,33 @@
return FALSE
/datum/surgery_step/revive/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
- user.visible_message("[user] prepares to shock [target]'s brain with [tool].", "You prepare to give [target]'s brain the spark of life with [tool].")
+ display_results(user, target, "You prepare to give [target]'s brain the spark of life with [tool].",
+ "[user] prepares to shock [target]'s brain with [tool].",
+ "[user] prepares to shock [target]'s brain with [tool].")
target.notify_ghost_cloning("Someone is trying to zap your brain. Re-enter your corpse if you want to be revived!", source = target)
/datum/surgery_step/revive/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
- user.visible_message("[user] send a powerful shock to [target]'s brain with [tool]...", "You successfully shock [target]'s brain with [tool]...")
+ display_results(user, target, "You successfully shock [target]'s brain with [tool]...",
+ "[user] send a powerful shock to [target]'s brain with [tool]...",
+ "[user] send a powerful shock to [target]'s brain with [tool]...")
playsound(get_turf(target), 'sound/magic/lightningbolt.ogg', 50, 1)
target.adjustOxyLoss(-50, 0)
target.updatehealth()
if(target.revive())
user.visible_message("...[target] wakes up, alive and aware!", "IT'S ALIVE!")
+ target.visible_message("...[target] wakes up, alive and aware!")
target.emote("gasp")
target.adjustBrainLoss(50, 199) //MAD SCIENCE
return TRUE
else
user.visible_message("...[target.p_they()] convulses, then lies still.")
+ target.visible_message("...[target.p_they()] convulses, then lies still.")
return FALSE
/datum/surgery_step/revive/failure(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
- user.visible_message("[user] send a powerful shock to [target]'s brain with [tool], but [target.p_they()] doesn't react.", "You shock [target]'s brain with [tool], but [target.p_they()] doesn't react.")
+ display_results(user, target, "You shock [target]'s brain with [tool], but [target.p_they()] doesn't react.",
+ "[user] send a powerful shock to [target]'s brain with [tool], but [target.p_they()] doesn't react.",
+ "[user] send a powerful shock to [target]'s brain with [tool], but [target.p_they()] doesn't react.")
playsound(get_turf(target), 'sound/magic/lightningbolt.ogg', 50, 1)
target.adjustBrainLoss(15, 199)
- return FALSE
\ No newline at end of file
+ return FALSE
diff --git a/code/modules/surgery/advanced/viral_bonding.dm b/code/modules/surgery/advanced/viral_bonding.dm
index 115f8a2eed..b87d5e001c 100644
--- a/code/modules/surgery/advanced/viral_bonding.dm
+++ b/code/modules/surgery/advanced/viral_bonding.dm
@@ -7,17 +7,14 @@
/datum/surgery_step/incise,
/datum/surgery_step/viral_bond,
/datum/surgery_step/close)
-
species = list(/mob/living/carbon/human, /mob/living/carbon/monkey)
possible_locs = list(BODY_ZONE_CHEST)
-
/datum/surgery/advanced/viral_bonding/can_start(mob/user, mob/living/carbon/target)
if(!..())
return FALSE
if(!LAZYLEN(target.diseases))
return FALSE
return TRUE
-
/datum/surgery_step/viral_bond
name = "viral bond"
implements = list(/obj/item/cautery = 100, TOOL_WELDER = 50, /obj/item = 30) // 30% success with any hot item.
@@ -27,15 +24,18 @@
/datum/surgery_step/viral_bond/tool_check(mob/user, obj/item/tool)
if(implement_type == TOOL_WELDER || implement_type == /obj/item)
return tool.is_hot()
-
return TRUE
/datum/surgery_step/viral_bond/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
- user.visible_message("[user] starts heating [target]'s bone marrow with [tool]...", "You start heating [target]'s bone marrow with [tool]...")
+ display_results(user, target, "You start heating [target]'s bone marrow with [tool]...",
+ "[user] starts heating [target]'s bone marrow with [tool]...",
+ "[user] starts heating something in [target]'s chest with [tool]...")
/datum/surgery_step/viral_bond/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
- user.visible_message("[target]'s bone marrow begins pulsing slowly.", "[target]'s bone marrow begins pulsing slowly. The viral bonding is complete.")
+ display_results(user, target, "[target]'s bone marrow begins pulsing slowly. The viral bonding is complete.",
+ "[target]'s bone marrow begins pulsing slowly.",
+ "[user] finishes the operation.")
for(var/X in target.diseases)
var/datum/disease/D = X
D.carrier = TRUE
- return TRUE
\ No newline at end of file
+ return TRUE
diff --git a/code/modules/surgery/amputation.dm b/code/modules/surgery/amputation.dm
index 8465a6d332..01cf6ae112 100644
--- a/code/modules/surgery/amputation.dm
+++ b/code/modules/surgery/amputation.dm
@@ -1,25 +1,25 @@
-
/datum/surgery/amputation
- name = "amputation"
+ name = "Amputation"
steps = list(/datum/surgery_step/incise, /datum/surgery_step/clamp_bleeders, /datum/surgery_step/retract_skin, /datum/surgery_step/saw, /datum/surgery_step/clamp_bleeders, /datum/surgery_step/sever_limb)
species = list(/mob/living/carbon/human, /mob/living/carbon/monkey)
possible_locs = list(BODY_ZONE_R_ARM, BODY_ZONE_L_ARM, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG, BODY_ZONE_HEAD)
requires_bodypart_type = 0
-
-
/datum/surgery_step/sever_limb
name = "sever limb"
implements = list(/obj/item/scalpel = 100, /obj/item/circular_saw = 100, /obj/item/melee/transforming/energy/sword/cyborg/saw = 100, /obj/item/melee/arm_blade = 80, /obj/item/twohanded/required/chainsaw = 80, /obj/item/mounted_chainsaw = 80, /obj/item/twohanded/fireaxe = 50, /obj/item/hatchet = 40, /obj/item/kitchen/knife/butcher = 25)
time = 64
/datum/surgery_step/sever_limb/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
- user.visible_message("[user] begins to sever [target]'s [parse_zone(target_zone)]!", "You begin to sever [target]'s [parse_zone(target_zone)]...")
+ display_results(user, target, "You begin to sever [target]'s [parse_zone(target_zone)]...",
+ "[user] begins to sever [target]'s [parse_zone(target_zone)]!",
+ "[user] begins to sever [target]'s [parse_zone(target_zone)]!")
/datum/surgery_step/sever_limb/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
var/mob/living/carbon/human/L = target
- user.visible_message("[user] severs [L]'s [parse_zone(target_zone)]!", "You sever [L]'s [parse_zone(target_zone)].")
+ display_results(user, target, "You sever [L]'s [parse_zone(target_zone)].",
+ "[user] severs [L]'s [parse_zone(target_zone)]!",
+ "[user] severs [L]'s [parse_zone(target_zone)]!")
if(surgery.operated_bodypart)
var/obj/item/bodypart/target_limb = surgery.operated_bodypart
target_limb.drop_limb()
-
- return 1
\ No newline at end of file
+ return 1
diff --git a/code/modules/surgery/bodyparts/bodyparts.dm b/code/modules/surgery/bodyparts/bodyparts.dm
index a97a133685..81b491e6de 100644
--- a/code/modules/surgery/bodyparts/bodyparts.dm
+++ b/code/modules/surgery/bodyparts/bodyparts.dm
@@ -354,7 +354,8 @@
if("mam_body_markings" in S.default_features)
var/datum/sprite_accessory/Smark
Smark = GLOB.mam_body_markings_list[H.dna.features["mam_body_markings"]]
- body_markings_icon = Smark.icon
+ if(Smark)
+ body_markings_icon = Smark.icon
if(H.dna.features.["mam_body_markings"] != "None")
body_markings = lowertext(H.dna.features.["mam_body_markings"])
auxmarking = lowertext(H.dna.features.["mam_body_markings"])
diff --git a/code/modules/surgery/bodyparts/robot_bodyparts.dm b/code/modules/surgery/bodyparts/robot_bodyparts.dm
index ab31d64034..a3f8b883b4 100644
--- a/code/modules/surgery/bodyparts/robot_bodyparts.dm
+++ b/code/modules/surgery/bodyparts/robot_bodyparts.dm
@@ -20,8 +20,8 @@
icon_state = "borg_l_arm"
status = BODYPART_ROBOTIC
- brute_reduction = 5
- burn_reduction = 4
+ brute_reduction = 2
+ burn_reduction = 1
light_brute_msg = ROBOTIC_LIGHT_BRUTE_MSG
medium_brute_msg = ROBOTIC_MEDIUM_BRUTE_MSG
@@ -41,8 +41,8 @@
icon_state = "borg_r_arm"
status = BODYPART_ROBOTIC
- brute_reduction = 5
- burn_reduction = 4
+ brute_reduction = 2
+ burn_reduction = 1
light_brute_msg = ROBOTIC_LIGHT_BRUTE_MSG
medium_brute_msg = ROBOTIC_MEDIUM_BRUTE_MSG
@@ -62,8 +62,8 @@
icon_state = "borg_l_leg"
status = BODYPART_ROBOTIC
- brute_reduction = 5
- burn_reduction = 4
+ brute_reduction = 2
+ burn_reduction = 1
light_brute_msg = ROBOTIC_LIGHT_BRUTE_MSG
medium_brute_msg = ROBOTIC_MEDIUM_BRUTE_MSG
@@ -83,8 +83,8 @@
icon_state = "borg_r_leg"
status = BODYPART_ROBOTIC
- brute_reduction = 5
- burn_reduction = 4
+ brute_reduction = 2
+ burn_reduction = 1
light_brute_msg = ROBOTIC_LIGHT_BRUTE_MSG
medium_brute_msg = ROBOTIC_MEDIUM_BRUTE_MSG
@@ -103,8 +103,8 @@
icon_state = "borg_chest"
status = BODYPART_ROBOTIC
- brute_reduction = 5
- burn_reduction = 4
+ brute_reduction = 2
+ burn_reduction = 1
light_brute_msg = ROBOTIC_LIGHT_BRUTE_MSG
medium_brute_msg = ROBOTIC_MEDIUM_BRUTE_MSG
@@ -268,38 +268,38 @@
burn_reduction = 0
max_damage = 20
-// Upgraded Surplus lims
+// Upgraded Surplus lims - Better then robotic lims
/obj/item/bodypart/l_arm/robot/surplus_upgraded
name = "reinforced surplus prosthetic left arm"
- desc = "A skeletal, robotic limb. This one is reinforced to provide better protection."
+ desc = "A skeletal, robotic limb. This one is reinforced to provide better protection, and is made of stronger parts."
icon = 'icons/mob/augmentation/surplus_augments.dmi'
- brute_reduction = 1
- burn_reduction = 1
- max_damage = 30
+ brute_reduction = 3
+ burn_reduction = 2
+ max_damage = 55
/obj/item/bodypart/r_arm/robot/surplus_upgraded
name = "reinforced surplus prosthetic right arm"
- desc = "A skeletal, robotic limb. This one is reinforced to provide better protection."
+ desc = "A skeletal, robotic limb. This one is reinforced to provide better protection, and is made of stronger parts."
icon = 'icons/mob/augmentation/surplus_augments.dmi'
- brute_reduction = 1
- burn_reduction = 1
- max_damage = 30
+ brute_reduction = 3
+ burn_reduction = 2
+ max_damage = 55
/obj/item/bodypart/l_leg/robot/surplus_upgraded
name = "reinforced surplus prosthetic left leg"
- desc = "A skeletal, robotic limb. This one is reinforced to provide better protection."
+ desc = "A skeletal, robotic limb. This one is reinforced to provide better protection, and is made of stronger parts."
icon = 'icons/mob/augmentation/surplus_augments.dmi'
- brute_reduction = 1
- burn_reduction = 1
- max_damage = 30
+ brute_reduction = 3
+ burn_reduction = 2
+ max_damage = 55
/obj/item/bodypart/r_leg/robot/surplus_upgraded
name = "reinforced surplus prosthetic right leg"
- desc = "A skeletal, robotic limb. This one is reinforced to provide better protection."
+ desc = "A skeletal, robotic limb. This one is reinforced to provide better protection, and is made of stronger parts."
icon = 'icons/mob/augmentation/surplus_augments.dmi'
- brute_reduction = 1
- burn_reduction = 1
- max_damage = 30
+ brute_reduction = 3
+ burn_reduction = 2
+ max_damage = 55
#undef ROBOTIC_LIGHT_BRUTE_MSG
#undef ROBOTIC_MEDIUM_BRUTE_MSG
diff --git a/code/modules/surgery/brain_surgery.dm b/code/modules/surgery/brain_surgery.dm
index fcd626ad97..e65271576d 100644
--- a/code/modules/surgery/brain_surgery.dm
+++ b/code/modules/surgery/brain_surgery.dm
@@ -1,5 +1,5 @@
/datum/surgery/brain_surgery
- name = "brain surgery"
+ name = "Brain surgery"
steps = list(
/datum/surgery_step/incise,
/datum/surgery_step/retract_skin,
@@ -7,16 +7,13 @@
/datum/surgery_step/clamp_bleeders,
/datum/surgery_step/fix_brain,
/datum/surgery_step/close)
-
species = list(/mob/living/carbon/human, /mob/living/carbon/monkey)
possible_locs = list(BODY_ZONE_HEAD)
requires_bodypart_type = 0
-
/datum/surgery_step/fix_brain
name = "fix brain"
implements = list(/obj/item/hemostat = 85, TOOL_SCREWDRIVER = 35, /obj/item/pen = 15) //don't worry, pouring some alcohol on their open brain will get that chance to 100
time = 120 //long and complicated
-
/datum/surgery/brain_surgery/can_start(mob/user, mob/living/carbon/target)
var/obj/item/organ/brain/B = target.getorganslot(ORGAN_SLOT_BRAIN)
if(!B)
@@ -24,10 +21,14 @@
return TRUE
/datum/surgery_step/fix_brain/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
- user.visible_message("[user] begins to fix [target]'s brain.", "You begin to fix [target]'s brain...")
+ display_results(user, target, "You begin to fix [target]'s brain...",
+ "[user] begins to fix [target]'s brain.",
+ "[user] begins to perform surgery on [target]'s brain.")
/datum/surgery_step/fix_brain/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
- user.visible_message("[user] successfully fixes [target]'s brain!", "You succeed in fixing [target]'s brain.")
+ display_results(user, target, "You succeed in fixing [target]'s brain.",
+ "[user] successfully fixes [target]'s brain!",
+ "[user] completes the surgery on [target]'s brain.")
if(target.mind && target.mind.has_antag_datum(/datum/antagonist/brainwashed))
target.mind.remove_antag_datum(/datum/antagonist/brainwashed)
target.adjustBrainLoss(-60)
@@ -36,9 +37,11 @@
/datum/surgery_step/fix_brain/failure(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
if(target.getorganslot(ORGAN_SLOT_BRAIN))
- user.visible_message("[user] screws up, causing more damage!", "You screw up, causing more damage!")
+ display_results(user, target, "You screw up, causing more damage!",
+ "[user] screws up, causing brain damage!",
+ "[user] completes the surgery on [target]'s brain.")
target.adjustBrainLoss(60)
target.gain_trauma_type(BRAIN_TRAUMA_SEVERE, TRAUMA_RESILIENCE_LOBOTOMY)
else
user.visible_message("[user] suddenly notices that the brain [user.p_they()] [user.p_were()] working on is not there anymore.", "You suddenly notice that the brain you were working on is not there anymore.")
- return FALSE
\ No newline at end of file
+ return FALSE
diff --git a/code/modules/surgery/cavity_implant.dm b/code/modules/surgery/cavity_implant.dm
index 72874e0308..4c65b56962 100644
--- a/code/modules/surgery/cavity_implant.dm
+++ b/code/modules/surgery/cavity_implant.dm
@@ -1,30 +1,32 @@
/datum/surgery/cavity_implant
- name = "cavity implant"
+ name = "Cavity implant"
steps = list(/datum/surgery_step/incise, /datum/surgery_step/clamp_bleeders, /datum/surgery_step/retract_skin, /datum/surgery_step/incise, /datum/surgery_step/handle_cavity, /datum/surgery_step/close)
species = list(/mob/living/carbon/human, /mob/living/carbon/monkey)
possible_locs = list(BODY_ZONE_CHEST)
-
-
//handle cavity
/datum/surgery_step/handle_cavity
name = "implant item"
accept_hand = 1
accept_any_item = 1
+ implements = list(/obj/item = 100)
+ repeatable = TRUE
time = 32
var/obj/item/IC = null
-
+/datum/surgery_step/handle_cavity/tool_check(mob/user, obj/item/tool)
+ if(istype(tool, /obj/item/cautery) || istype(tool, /obj/item/gun/energy/laser))
+ return FALSE
+ return !tool.is_hot()
/datum/surgery_step/handle_cavity/preop(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool, datum/surgery/surgery)
var/obj/item/bodypart/chest/CH = target.get_bodypart(BODY_ZONE_CHEST)
IC = CH.cavity_item
if(tool)
- if(istype(tool, /obj/item/surgical_drapes) || istype(tool, /obj/item/bedsheet))
- var/obj/item/inactive = user.get_inactive_held_item()
- if(istype(inactive, /obj/item/cautery) || istype(inactive, /obj/item/screwdriver) || iscyborg(user))
- attempt_cancel_surgery(surgery, tool, target, user)
- return -1
- user.visible_message("[user] begins to insert [tool] into [target]'s [target_zone].", "You begin to insert [tool] into [target]'s [target_zone]...")
+ display_results(user, target, "You begin to insert [tool] into [target]'s [target_zone]...",
+ "[user] begins to insert [tool] into [target]'s [target_zone].",
+ "[user] begins to insert [tool.w_class > WEIGHT_CLASS_SMALL ? tool : "something"] into [target]'s [target_zone].")
else
- user.visible_message("[user] checks for items in [target]'s [target_zone].", "You check for items in [target]'s [target_zone]...")
+ display_results(user, target, "You check for items in [target]'s [target_zone]...",
+ "[user] checks for items in [target]'s [target_zone].",
+ "[user] looks for something in [target]'s [target_zone].")
/datum/surgery_step/handle_cavity/success(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool, datum/surgery/surgery)
var/obj/item/bodypart/chest/CH = target.get_bodypart(BODY_ZONE_CHEST)
@@ -32,18 +34,18 @@
if(IC || tool.w_class > WEIGHT_CLASS_NORMAL || HAS_TRAIT(tool, TRAIT_NODROP) || istype(tool, /obj/item/organ))
to_chat(user, "You can't seem to fit [tool] in [target]'s [target_zone]!")
return 0
- var/obj/item/electronic_assembly/EA = tool
- if(istype(EA) && EA.combat_circuits && tool.w_class > WEIGHT_CLASS_SMALL)
- to_chat(user, "[tool] is too dangerous to put in [target]'s [target_zone]! Maybe if it was smaller...")
- return 0
else
- user.visible_message("[user] stuffs [tool] into [target]'s [target_zone]!", "You stuff [tool] into [target]'s [target_zone].")
+ display_results(user, target, "You stuff [tool] into [target]'s [target_zone].",
+ "[user] stuffs [tool] into [target]'s [target_zone]!",
+ "[user] stuffs [tool.w_class > WEIGHT_CLASS_SMALL ? tool : "something"] into [target]'s [target_zone].")
user.transferItemToLoc(tool, target, TRUE)
CH.cavity_item = tool
return 1
else
if(IC)
- user.visible_message("[user] pulls [IC] out of [target]'s [target_zone]!", "You pull [IC] out of [target]'s [target_zone].")
+ display_results(user, target, "You pull [IC] out of [target]'s [target_zone].",
+ "[user] pulls [IC] out of [target]'s [target_zone]!",
+ "[user] pulls [IC.w_class > WEIGHT_CLASS_SMALL ? IC : "something"] out of [target]'s [target_zone].")
user.put_in_hands(IC)
CH.cavity_item = null
return 1
diff --git a/code/modules/surgery/core_removal.dm b/code/modules/surgery/core_removal.dm
index 7bf888ab40..6243405f8d 100644
--- a/code/modules/surgery/core_removal.dm
+++ b/code/modules/surgery/core_removal.dm
@@ -1,5 +1,5 @@
/datum/surgery/core_removal
- name = "core removal"
+ name = "Core removal"
steps = list(/datum/surgery_step/incise, /datum/surgery_step/extract_core)
species = list(/mob/living/simple_animal/slime)
possible_locs = list(BODY_ZONE_R_ARM,BODY_ZONE_L_ARM,BODY_ZONE_R_LEG,BODY_ZONE_L_LEG,BODY_ZONE_CHEST,BODY_ZONE_HEAD)
@@ -8,7 +8,6 @@
if(target.stat == DEAD)
return 1
return 0
-
//extract brain
/datum/surgery_step/extract_core
name = "extract core"
@@ -16,13 +15,17 @@
time = 16
/datum/surgery_step/extract_core/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
- user.visible_message("[user] begins to extract a core from [target].", "You begin to extract a core from [target]...")
+ display_results(user, target, "You begin to extract a core from [target]...",
+ "[user] begins to extract a core from [target].",
+ "[user] begins to extract a core from [target].")
/datum/surgery_step/extract_core/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
var/mob/living/simple_animal/slime/slime = target
if(slime.cores > 0)
slime.cores--
- user.visible_message("[user] successfully extracts a core from [target]!", "You successfully extract a core from [target]. [slime.cores] core\s remaining.")
+ display_results(user, target, "You successfully extract a core from [target]. [slime.cores] core\s remaining.",
+ "[user] successfully extracts a core from [target]!",
+ "[user] successfully extracts a core from [target]!")
new slime.coretype(slime.loc)
@@ -33,4 +36,4 @@
return 0
else
to_chat(user, "There aren't any cores left in [target]!")
- return 1
\ No newline at end of file
+ return 1
diff --git a/code/modules/surgery/eye_surgery.dm b/code/modules/surgery/eye_surgery.dm
index a8cb881326..85142e7bb1 100644
--- a/code/modules/surgery/eye_surgery.dm
+++ b/code/modules/surgery/eye_surgery.dm
@@ -1,16 +1,14 @@
/datum/surgery/eye_surgery
- name = "eye surgery"
+ name = "Eye surgery"
steps = list(/datum/surgery_step/incise, /datum/surgery_step/retract_skin, /datum/surgery_step/clamp_bleeders, /datum/surgery_step/fix_eyes, /datum/surgery_step/close)
species = list(/mob/living/carbon/human, /mob/living/carbon/monkey)
possible_locs = list(BODY_ZONE_PRECISE_EYES)
requires_bodypart_type = 0
-
//fix eyes
/datum/surgery_step/fix_eyes
name = "fix eyes"
implements = list(/obj/item/hemostat = 100, TOOL_SCREWDRIVER = 45, /obj/item/pen = 25)
time = 64
-
/datum/surgery/eye_surgery/can_start(mob/user, mob/living/carbon/target)
var/obj/item/organ/eyes/E = target.getorganslot(ORGAN_SLOT_EYES)
if(!E)
@@ -19,10 +17,14 @@
return TRUE
/datum/surgery_step/fix_eyes/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
- user.visible_message("[user] begins to fix [target]'s eyes.", "You begin to fix [target]'s eyes...")
+ display_results(user, target, "You begin to fix [target]'s eyes...",
+ "[user] begins to fix [target]'s eyes.",
+ "[user] begins to perform surgery on [target]'s eyes.")
/datum/surgery_step/fix_eyes/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
- user.visible_message("[user] successfully fixes [target]'s eyes!", "You succeed in fixing [target]'s eyes.")
+ display_results(user, target, "You succeed in fixing [target]'s eyes.",
+ "[user] successfully fixes [target]'s eyes!",
+ "[user] completes the surgery on [target]'s eyes.")
target.cure_blind(list(EYE_DAMAGE))
target.set_blindness(0)
target.cure_nearsighted(list(EYE_DAMAGE))
@@ -32,8 +34,12 @@
/datum/surgery_step/fix_eyes/failure(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
if(target.getorgan(/obj/item/organ/brain))
- user.visible_message("[user] accidentally stabs [target] right in the brain!", "You accidentally stab [target] right in the brain!")
+ display_results(user, target, "You accidentally stab [target] right in the brain!",
+ "[user] accidentally stabs [target] right in the brain!",
+ "[user] accidentally stabs [target] right in the brain!")
target.adjustBrainLoss(70)
else
- user.visible_message("[user] accidentally stabs [target] right in the brain! Or would have, if [target] had a brain.", "You accidentally stab [target] right in the brain! Or would have, if [target] had a brain.")
- return FALSE
\ No newline at end of file
+ display_results(user, target, "You accidentally stab [target] right in the brain! Or would have, if [target] had a brain.",
+ "[user] accidentally stabs [target] right in the brain! Or would have, if [target] had a brain.",
+ "[user] accidentally stabs [target] right in the brain!")
+ return FALSE
diff --git a/code/modules/surgery/helpers.dm b/code/modules/surgery/helpers.dm
index 59440cc3ee..0419a4c73f 100644
--- a/code/modules/surgery/helpers.dm
+++ b/code/modules/surgery/helpers.dm
@@ -65,7 +65,7 @@
if(S.ignore_clothes || get_location_accessible(M, selected_zone))
var/datum/surgery/procedure = new S.type(M, selected_zone, affecting)
- user.visible_message("[user] drapes [I] over [M]'s [parse_zone(selected_zone)] to prepare for \an [procedure.name].", \
+ user.visible_message("[user] drapes [I] over [M]'s [parse_zone(selected_zone)] to prepare for surgery.", \
"You drape [I] over [M]'s [parse_zone(selected_zone)] to prepare for \an [procedure.name].")
log_combat(user, M, "operated on", null, "(OPERATION TYPE: [procedure.name]) (TARGET AREA: [selected_zone])")
@@ -169,4 +169,3 @@
return 0
return 1
-
diff --git a/code/modules/surgery/implant_removal.dm b/code/modules/surgery/implant_removal.dm
index 92c5e05246..05119b365d 100644
--- a/code/modules/surgery/implant_removal.dm
+++ b/code/modules/surgery/implant_removal.dm
@@ -3,27 +3,30 @@
steps = list(/datum/surgery_step/incise, /datum/surgery_step/clamp_bleeders, /datum/surgery_step/retract_skin, /datum/surgery_step/extract_implant, /datum/surgery_step/close)
species = list(/mob/living/carbon/human, /mob/living/carbon/monkey)
possible_locs = list(BODY_ZONE_CHEST)
-
-
//extract implant
/datum/surgery_step/extract_implant
name = "extract implant"
implements = list(/obj/item/hemostat = 100, TOOL_CROWBAR = 65)
time = 64
var/obj/item/implant/I = null
-
/datum/surgery_step/extract_implant/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
for(var/obj/item/O in target.implants)
I = O
break
if(I)
- user.visible_message("[user] begins to extract [I] from [target]'s [target_zone].", "You begin to extract [I] from [target]'s [target_zone]...")
+ display_results(user, target, "You begin to extract [I] from [target]'s [target_zone]...",
+ "[user] begins to extract [I] from [target]'s [target_zone].",
+ "[user] begins to extract something from [target]'s [target_zone].")
else
- user.visible_message("[user] looks for an implant in [target]'s [target_zone].", "You look for an implant in [target]'s [target_zone]...")
+ display_results(user, target, "You look for an implant in [target]'s [target_zone]...",
+ "[user] looks for an implant in [target]'s [target_zone].",
+ "[user] looks for something in [target]'s [target_zone].")
/datum/surgery_step/extract_implant/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
if(I)
- user.visible_message("[user] successfully removes [I] from [target]'s [target_zone]!", "You successfully remove [I] from [target]'s [target_zone].")
+ display_results(user, target, "You successfully remove [I] from [target]'s [target_zone].",
+ "[user] successfully removes [I] from [target]'s [target_zone]!",
+ "[user] successfully removes something from [target]'s [target_zone]!")
I.removed(target)
var/obj/item/implantcase/case
@@ -36,14 +39,15 @@
case.imp = I
I.forceMove(case)
case.update_icon()
- user.visible_message("[user] places [I] into [case]!", "You place [I] into [case].")
+ display_results(user, target, "You place [I] into [case].",
+ "[user] places [I] into [case]!",
+ "[user] places it into [case]!")
else
qdel(I)
else
to_chat(user, "You can't find anything in [target]'s [target_zone]!")
return 1
-
/datum/surgery/implant_removal/mechanic
name = "implant removal"
requires_bodypart_type = BODYPART_ROBOTIC
@@ -53,4 +57,4 @@
/datum/surgery_step/mechanic_unwrench,
/datum/surgery_step/extract_implant,
/datum/surgery_step/mechanic_wrench,
- /datum/surgery_step/mechanic_close)
\ No newline at end of file
+ /datum/surgery_step/mechanic_close)
diff --git a/code/modules/surgery/limb_augmentation.dm b/code/modules/surgery/limb_augmentation.dm
index 46fe262189..7ba8dbc49d 100644
--- a/code/modules/surgery/limb_augmentation.dm
+++ b/code/modules/surgery/limb_augmentation.dm
@@ -1,9 +1,5 @@
-
/////AUGMENTATION SURGERIES//////
-
-
//SURGERY STEPS
-
/datum/surgery_step/replace
name = "sever muscles"
implements = list(/obj/item/scalpel = 100, TOOL_WIRECUTTER = 55)
@@ -11,16 +7,15 @@
/datum/surgery_step/replace/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
- user.visible_message("[user] begins to sever the muscles on [target]'s [parse_zone(user.zone_selected)].", "You begin to sever the muscles on [target]'s [parse_zone(user.zone_selected)]...")
-
+ display_results(user, target, "You begin to sever the muscles on [target]'s [parse_zone(user.zone_selected)]...",
+ "[user] begins to sever the muscles on [target]'s [parse_zone(user.zone_selected)].",
+ "[user] begins an incision on [target]'s [parse_zone(user.zone_selected)].")
/datum/surgery_step/replace_limb
name = "replace limb"
implements = list(/obj/item/bodypart = 100, /obj/item/organ_storage = 100)
time = 32
var/obj/item/bodypart/L = null // L because "limb"
-
-
/datum/surgery_step/replace_limb/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
if(istype(tool, /obj/item/organ_storage) && istype(tool.contents[1], /obj/item/bodypart))
tool = tool.contents[1]
@@ -33,22 +28,20 @@
return -1
L = surgery.operated_bodypart
if(L)
- user.visible_message("[user] begins to augment [target]'s [parse_zone(user.zone_selected)].", "You begin to augment [target]'s [parse_zone(user.zone_selected)]...")
+ display_results(user, target, "You begin to augment [target]'s [parse_zone(user.zone_selected)]...",
+ "[user] begins to augment [target]'s [parse_zone(user.zone_selected)] with [aug].",
+ "[user] begins to augment [target]'s [parse_zone(user.zone_selected)].")
else
user.visible_message("[user] looks for [target]'s [parse_zone(user.zone_selected)].", "You look for [target]'s [parse_zone(user.zone_selected)]...")
-
//ACTUAL SURGERIES
-
/datum/surgery/augmentation
- name = "augmentation"
+ name = "Augmentation"
steps = list(/datum/surgery_step/incise, /datum/surgery_step/clamp_bleeders, /datum/surgery_step/retract_skin, /datum/surgery_step/replace, /datum/surgery_step/saw, /datum/surgery_step/replace_limb)
species = list(/mob/living/carbon/human)
possible_locs = list(BODY_ZONE_R_ARM,BODY_ZONE_L_ARM,BODY_ZONE_R_LEG,BODY_ZONE_L_LEG,BODY_ZONE_CHEST,BODY_ZONE_HEAD)
requires_real_bodypart = TRUE
-
//SURGERY STEP SUCCESSES
-
/datum/surgery_step/replace_limb/success(mob/user, mob/living/carbon/target, target_zone, obj/item/bodypart/tool, datum/surgery/surgery)
if(L)
if(istype(tool, /obj/item/organ_storage))
@@ -58,7 +51,9 @@
tool = tool.contents[1]
if(istype(tool) && user.temporarilyRemoveItemFromInventory(tool))
tool.replace_limb(target, TRUE)
- user.visible_message("[user] successfully augments [target]'s [parse_zone(target_zone)]!", "You successfully augment [target]'s [parse_zone(target_zone)].")
+ display_results(user, target, "You successfully augment [target]'s [parse_zone(target_zone)].",
+ "[user] successfully augments [target]'s [parse_zone(target_zone)] with [tool]!",
+ "[user] successfully augments [target]'s [parse_zone(target_zone)]!")
log_combat(user, target, "augmented", addition="by giving him new [parse_zone(target_zone)] INTENT: [uppertext(user.a_intent)]")
else
to_chat(user, "[target] has no organic [parse_zone(target_zone)] there!")
diff --git a/code/modules/surgery/lipoplasty.dm b/code/modules/surgery/lipoplasty.dm
index 9967eba663..bb297b4604 100644
--- a/code/modules/surgery/lipoplasty.dm
+++ b/code/modules/surgery/lipoplasty.dm
@@ -1,14 +1,11 @@
/datum/surgery/lipoplasty
- name = "lipoplasty"
+ name = "Lipoplasty"
steps = list(/datum/surgery_step/incise, /datum/surgery_step/clamp_bleeders, /datum/surgery_step/cut_fat, /datum/surgery_step/remove_fat, /datum/surgery_step/close)
possible_locs = list(BODY_ZONE_CHEST)
-
/datum/surgery/lipoplasty/can_start(mob/user, mob/living/carbon/target)
if(HAS_TRAIT(target, TRAIT_FAT))
return 1
return 0
-
-
//cut fat
/datum/surgery_step/cut_fat
name = "cut excess fat"
@@ -16,10 +13,14 @@
time = 64
/datum/surgery_step/cut_fat/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
- user.visible_message("[user] begins to cut away [target]'s excess fat.", "You begin to cut away [target]'s excess fat...")
+ display_results(user, target, "You begin to cut away [target]'s excess fat...",
+ "[user] begins to cut away [target]'s excess fat.",
+ "[user] begins to cut [target]'s [target_zone] with [tool].")
/datum/surgery_step/cut_fat/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
- user.visible_message("[user] cuts [target]'s excess fat loose!", "You cut [target]'s excess fat loose.")
+ display_results(user, target, "You cut [target]'s excess fat loose.",
+ "[user] cuts [target]'s excess fat loose!",
+ "[user] finishes the cut on [target]'s [target_zone].")
return 1
//remove fat
@@ -29,25 +30,27 @@
time = 32
/datum/surgery_step/remove_fat/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
- user.visible_message("[user] begins to extract [target]'s loose fat!", "You begin to extract [target]'s loose fat...")
+ display_results(user, target, "You begin to extract [target]'s loose fat...",
+ "[user] begins to extract [target]'s loose fat!",
+ "[user] begins to extract something from [target]'s [target_zone].")
/datum/surgery_step/remove_fat/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
- user.visible_message("[user] extracts [target]'s fat!", "You extract [target]'s fat.")
+ display_results(user, target, "You extract [target]'s fat.",
+ "[user] extracts [target]'s fat!",
+ "[user] extracts [target]'s fat!")
target.overeatduration = 0 //patient is unfatted
var/removednutriment = target.nutrition
target.nutrition = NUTRITION_LEVEL_WELL_FED
removednutriment -= 450 //whatever was removed goes into the meat
var/mob/living/carbon/human/H = target
var/typeofmeat = /obj/item/reagent_containers/food/snacks/meat/slab/human
-
if(H.dna && H.dna.species)
typeofmeat = H.dna.species.meat
-
var/obj/item/reagent_containers/food/snacks/meat/slab/human/newmeat = new typeofmeat
newmeat.name = "fatty meat"
newmeat.desc = "Extremely fatty tissue taken from a patient."
newmeat.subjectname = H.real_name
newmeat.subjectjob = H.job
- newmeat.reagents.add_reagent ("nutriment", (removednutriment / 15)) //To balance with nutriment_factor of nutriment
+ newmeat.reagents.add_reagent (/datum/reagent/consumable/nutriment, (removednutriment / 15)) //To balance with nutriment_factor of nutriment
newmeat.forceMove(target.loc)
- return 1
\ No newline at end of file
+ return 1
diff --git a/code/modules/surgery/mechanic_steps.dm b/code/modules/surgery/mechanic_steps.dm
index 6431770fa9..7d364d9ecf 100644
--- a/code/modules/surgery/mechanic_steps.dm
+++ b/code/modules/surgery/mechanic_steps.dm
@@ -9,15 +9,14 @@
time = 24
/datum/surgery_step/mechanic_open/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
- user.visible_message("[user] begins to unscrew the shell of [target]'s [parse_zone(target_zone)].",
- "You begin to unscrew the shell of [target]'s [parse_zone(target_zone)]...")
+ display_results(user, target, "You begin to unscrew the shell of [target]'s [parse_zone(target_zone)]...",
+ "[user] begins to unscrew the shell of [target]'s [parse_zone(target_zone)].",
+ "[user] begins to unscrew the shell of [target]'s [parse_zone(target_zone)].")
/datum/surgery_step/mechanic_incise/tool_check(mob/user, obj/item/tool)
if(implement_type == /obj/item && !tool.is_sharp())
return FALSE
-
return TRUE
-
//close shell
/datum/surgery_step/mechanic_close
name = "screw shell"
@@ -29,15 +28,14 @@
time = 24
/datum/surgery_step/mechanic_close/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
- user.visible_message("[user] begins to screw the shell of [target]'s [parse_zone(target_zone)].",
- "You begin to screw the shell of [target]'s [parse_zone(target_zone)]...")
+ display_results(user, target, "You begin to screw the shell of [target]'s [parse_zone(target_zone)]...",
+ "[user] begins to screw the shell of [target]'s [parse_zone(target_zone)].",
+ "[user] begins to screw the shell of [target]'s [parse_zone(target_zone)].")
/datum/surgery_step/mechanic_close/tool_check(mob/user, obj/item/tool)
if(implement_type == /obj/item && !tool.is_sharp())
return FALSE
-
return TRUE
-
//prepare electronics
/datum/surgery_step/prepare_electronics
name = "prepare electronics"
@@ -47,8 +45,9 @@
time = 24
/datum/surgery_step/prepare_electronics/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
- user.visible_message("[user] begins to prepare electronics in [target]'s [parse_zone(target_zone)].",
- "You begin to prepare electronics in [target]'s [parse_zone(target_zone)]...")
+ display_results(user, target, "You begin to prepare electronics in [target]'s [parse_zone(target_zone)]...",
+ "[user] begins to prepare electronics in [target]'s [parse_zone(target_zone)].",
+ "[user] begins to prepare electronics in [target]'s [parse_zone(target_zone)].")
//unwrench
/datum/surgery_step/mechanic_unwrench
@@ -59,8 +58,9 @@
time = 24
/datum/surgery_step/mechanic_unwrench/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
- user.visible_message("[user] begins to unwrench some bolts in [target]'s [parse_zone(target_zone)].",
- "You begin to unwrench some bolts in [target]'s [parse_zone(target_zone)]...")
+ display_results(user, target, "You begin to unwrench some bolts in [target]'s [parse_zone(target_zone)]...",
+ "[user] begins to unwrench some bolts in [target]'s [parse_zone(target_zone)].",
+ "[user] begins to unwrench some bolts in [target]'s [parse_zone(target_zone)].")
//wrench
/datum/surgery_step/mechanic_wrench
@@ -71,8 +71,9 @@
time = 24
/datum/surgery_step/mechanic_wrench/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
- user.visible_message("[user] begins to wrench some bolts in [target]'s [parse_zone(target_zone)].",
- "You begin to wrench some bolts in [target]'s [parse_zone(target_zone)]...")
+ display_results(user, target, "You begin to wrench some bolts in [target]'s [parse_zone(target_zone)]...",
+ "[user] begins to wrench some bolts in [target]'s [parse_zone(target_zone)].",
+ "[user] begins to wrench some bolts in [target]'s [parse_zone(target_zone)].")
//open hatch
/datum/surgery_step/open_hatch
@@ -81,5 +82,6 @@
time = 10
/datum/surgery_step/open_hatch/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
- user.visible_message("[user] begins to open the hatch holders in [target]'s [parse_zone(target_zone)].",
- "You begin to open the hatch holders in [target]'s [parse_zone(target_zone)]...")
\ No newline at end of file
+ display_results(user, target, "You begin to open the hatch holders in [target]'s [parse_zone(target_zone)]...",
+ "[user] begins to open the hatch holders in [target]'s [parse_zone(target_zone)].",
+ "[user] begins to open the hatch holders in [target]'s [parse_zone(target_zone)].")
diff --git a/code/modules/surgery/organ_manipulation.dm b/code/modules/surgery/organ_manipulation.dm
index 553de45c60..6bffed7452 100644
--- a/code/modules/surgery/organ_manipulation.dm
+++ b/code/modules/surgery/organ_manipulation.dm
@@ -1,5 +1,5 @@
/datum/surgery/organ_manipulation
- name = "organ manipulation"
+ name = "Organ manipulation"
species = list(/mob/living/carbon/human, /mob/living/carbon/monkey)
possible_locs = list(BODY_ZONE_CHEST, BODY_ZONE_HEAD)
requires_real_bodypart = 1
@@ -13,7 +13,6 @@
//there should be bone fixing
/datum/surgery_step/close
)
-
/datum/surgery/organ_manipulation/soft
possible_locs = list(BODY_ZONE_PRECISE_GROIN, BODY_ZONE_PRECISE_EYES, BODY_ZONE_PRECISE_MOUTH, BODY_ZONE_L_ARM, BODY_ZONE_R_ARM)
steps = list(
@@ -24,9 +23,8 @@
/datum/surgery_step/manipulate_organs,
/datum/surgery_step/close
)
-
/datum/surgery/organ_manipulation/alien
- name = "alien organ manipulation"
+ name = "Alien organ manipulation"
possible_locs = list(BODY_ZONE_CHEST, BODY_ZONE_HEAD, BODY_ZONE_PRECISE_GROIN, BODY_ZONE_PRECISE_EYES, BODY_ZONE_PRECISE_MOUTH, BODY_ZONE_L_ARM, BODY_ZONE_R_ARM)
species = list(/mob/living/carbon/alien/humanoid)
steps = list(
@@ -37,9 +35,8 @@
/datum/surgery_step/manipulate_organs,
/datum/surgery_step/close
)
-
/datum/surgery/organ_manipulation/mechanic
- name = "prosthesis organ manipulation"
+ name = "Prosthesis organ manipulation"
possible_locs = list(BODY_ZONE_CHEST, BODY_ZONE_HEAD)
requires_bodypart_type = BODYPART_ROBOTIC
steps = list(
@@ -51,7 +48,6 @@
/datum/surgery_step/mechanic_wrench,
/datum/surgery_step/mechanic_close
)
-
/datum/surgery/organ_manipulation/mechanic/soft
possible_locs = list(BODY_ZONE_PRECISE_GROIN, BODY_ZONE_PRECISE_EYES, BODY_ZONE_PRECISE_MOUTH, BODY_ZONE_L_ARM, BODY_ZONE_R_ARM)
steps = list(
@@ -61,7 +57,6 @@
/datum/surgery_step/manipulate_organs,
/datum/surgery_step/mechanic_close
)
-
/datum/surgery_step/manipulate_organs
time = 64
name = "manipulate organs"
@@ -70,11 +65,9 @@
var/implements_extract = list(/obj/item/hemostat = 100, TOOL_CROWBAR = 55)
var/current_type
var/obj/item/organ/I = null
-
/datum/surgery_step/manipulate_organs/New()
..()
implements = implements + implements_extract
-
/datum/surgery_step/manipulate_organs/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
I = null
if(istype(tool, /obj/item/organ_storage))
@@ -92,9 +85,9 @@
if(target_zone != I.zone || target.getorganslot(I.slot))
to_chat(user, "There is no room for [I] in [target]'s [parse_zone(target_zone)]!")
return -1
-
- user.visible_message("[user] begins to insert [tool] into [target]'s [parse_zone(target_zone)].",
- "You begin to insert [tool] into [target]'s [parse_zone(target_zone)]...")
+ display_results(user, target, "You begin to insert [tool] into [target]'s [parse_zone(target_zone)]...",
+ "[user] begins to insert [tool] into [target]'s [parse_zone(target_zone)].",
+ "[user] begins to insert something into [target]'s [parse_zone(target_zone)].")
else if(implement_type in implements_extract)
current_type = "extract"
@@ -107,21 +100,20 @@
O.on_find(user)
organs -= O
organs[O.name] = O
-
I = input("Remove which organ?", "Surgery", null, null) as null|anything in organs
if(I && user && target && user.Adjacent(target) && user.get_active_held_item() == tool)
I = organs[I]
if(!I)
return -1
- user.visible_message("[user] begins to extract [I] from [target]'s [parse_zone(target_zone)].",
- "You begin to extract [I] from [target]'s [parse_zone(target_zone)]...")
+ display_results(user, target, "You begin to extract [I] from [target]'s [parse_zone(target_zone)]...",
+ "[user] begins to extract [I] from [target]'s [parse_zone(target_zone)].",
+ "[user] begins to extract something from [target]'s [parse_zone(target_zone)].")
else
return -1
else if(istype(tool, /obj/item/reagent_containers/food/snacks/organ))
to_chat(user, "[tool] was bitten by someone! It's too damaged to use!")
return -1
-
/datum/surgery_step/manipulate_organs/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
if(current_type == "insert")
if(istype(tool, /obj/item/organ_storage))
@@ -134,17 +126,20 @@
I = tool
user.temporarilyRemoveItemFromInventory(I, TRUE)
I.Insert(target)
- user.visible_message("[user] inserts [tool] into [target]'s [parse_zone(target_zone)]!",
- "You insert [tool] into [target]'s [parse_zone(target_zone)].")
+ display_results(user, target, "You insert [tool] into [target]'s [parse_zone(target_zone)].",
+ "[user] inserts [tool] into [target]'s [parse_zone(target_zone)]!",
+ "[user] inserts something into [target]'s [parse_zone(target_zone)]!")
else if(current_type == "extract")
if(I && I.owner == target)
- user.visible_message("[user] successfully extracts [I] from [target]'s [parse_zone(target_zone)]!",
- "You successfully extract [I] from [target]'s [parse_zone(target_zone)].")
+ display_results(user, target, "You successfully extract [I] from [target]'s [parse_zone(target_zone)].",
+ "[user] successfully extracts [I] from [target]'s [parse_zone(target_zone)]!",
+ "[user] successfully extracts something from [target]'s [parse_zone(target_zone)]!")
log_combat(user, target, "surgically removed [I.name] from", addition="INTENT: [uppertext(user.a_intent)]")
I.Remove(target)
I.forceMove(get_turf(target))
else
- user.visible_message("[user] can't seem to extract anything from [target]'s [parse_zone(target_zone)]!",
- "You can't extract anything from [target]'s [parse_zone(target_zone)]!")
+ display_results(user, target, "You can't extract anything from [target]'s [parse_zone(target_zone)]!",
+ "[user] can't seem to extract anything from [target]'s [parse_zone(target_zone)]!",
+ "[user] can't seem to extract anything from [target]'s [parse_zone(target_zone)]!")
return 0
diff --git a/code/modules/surgery/organic_steps.dm b/code/modules/surgery/organic_steps.dm
index 01eb751f39..da03771a27 100644
--- a/code/modules/surgery/organic_steps.dm
+++ b/code/modules/surgery/organic_steps.dm
@@ -1,4 +1,3 @@
-
//make incision
/datum/surgery_step/incise
name = "make incision"
@@ -7,13 +6,22 @@
time = 16
/datum/surgery_step/incise/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
- user.visible_message("[user] begins to make an incision in [target]'s [parse_zone(target_zone)].",
- "You begin to make an incision in [target]'s [parse_zone(target_zone)]...")
+ display_results(user, target, "You begin to make an incision in [target]'s [parse_zone(target_zone)]...",
+ "[user] begins to make an incision in [target]'s [parse_zone(target_zone)].",
+ "[user] begins to make an incision in [target]'s [parse_zone(target_zone)].")
/datum/surgery_step/incise/tool_check(mob/user, obj/item/tool)
if(implement_type == /obj/item && !tool.is_sharp())
return FALSE
-
+ return TRUE
+/datum/surgery_step/incise/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
+ if ishuman(target)
+ var/mob/living/carbon/human/H = target
+ if (!(NOBLOOD in H.dna.species.species_traits))
+ display_results(user, target, "Blood pools around the incision in [H]'s [parse_zone(target_zone)].",
+ "Blood pools around the incision in [H]'s [parse_zone(target_zone)].",
+ "")
+ H.bleed_rate += 3
return TRUE
//clamp bleeders
@@ -23,15 +31,17 @@
time = 24
/datum/surgery_step/clamp_bleeders/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
- user.visible_message("[user] begins to clamp bleeders in [target]'s [parse_zone(target_zone)].",
- "You begin to clamp bleeders in [target]'s [parse_zone(target_zone)]...")
+ display_results(user, target, "You begin to clamp bleeders in [target]'s [parse_zone(target_zone)]...",
+ "[user] begins to clamp bleeders in [target]'s [parse_zone(target_zone)].",
+ "[user] begins to clamp bleeders in [target]'s [parse_zone(target_zone)].")
/datum/surgery_step/clamp_bleeders/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
if(locate(/datum/surgery_step/saw) in surgery.steps)
target.heal_bodypart_damage(20,0)
+ if (ishuman(target))
+ var/mob/living/carbon/human/H = target
+ H.bleed_rate = max( (H.bleed_rate - 3), 0)
return ..()
-
-
//retract skin
/datum/surgery_step/retract_skin
name = "retract skin"
@@ -39,8 +49,9 @@
time = 24
/datum/surgery_step/retract_skin/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
- user.visible_message("[user] begins to retract the skin in [target]'s [parse_zone(target_zone)].",
- "You begin to retract the skin in [target]'s [parse_zone(target_zone)]...")
+ display_results(user, target, "You begin to retract the skin in [target]'s [parse_zone(target_zone)]...",
+ "[user] begins to retract the skin in [target]'s [parse_zone(target_zone)].",
+ "[user] begins to retract the skin in [target]'s [parse_zone(target_zone)].")
@@ -52,22 +63,21 @@
time = 24
/datum/surgery_step/close/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
- user.visible_message("[user] begins to mend the incision in [target]'s [parse_zone(target_zone)].",
- "You begin to mend the incision in [target]'s [parse_zone(target_zone)]...")
+ display_results(user, target, "You begin to mend the incision in [target]'s [parse_zone(target_zone)]...",
+ "[user] begins to mend the incision in [target]'s [parse_zone(target_zone)].",
+ "[user] begins to mend the incision in [target]'s [parse_zone(target_zone)].")
/datum/surgery_step/close/tool_check(mob/user, obj/item/tool)
if(implement_type == TOOL_WELDER || implement_type == /obj/item)
return tool.is_hot()
-
return TRUE
-
/datum/surgery_step/close/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
if(locate(/datum/surgery_step/saw) in surgery.steps)
target.heal_bodypart_damage(45,0)
+ if (ishuman(target))
+ var/mob/living/carbon/human/H = target
+ H.bleed_rate = max( (H.bleed_rate - 3), 0)
return ..()
-
-
-
//saw bone
/datum/surgery_step/saw
name = "saw bone"
@@ -77,13 +87,15 @@
time = 54
/datum/surgery_step/saw/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
- user.visible_message("[user] begins to saw through the bone in [target]'s [parse_zone(target_zone)].",
- "You begin to saw through the bone in [target]'s [parse_zone(target_zone)]...")
+ display_results(user, target, "You begin to saw through the bone in [target]'s [parse_zone(target_zone)]...",
+ "[user] begins to saw through the bone in [target]'s [parse_zone(target_zone)].",
+ "[user] begins to saw through the bone in [target]'s [parse_zone(target_zone)].")
/datum/surgery_step/saw/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
target.apply_damage(50, BRUTE, "[target_zone]")
-
- user.visible_message("[user] saws [target]'s [parse_zone(target_zone)] open!", "You saw [target]'s [parse_zone(target_zone)] open.")
+ display_results(user, target, "You saw [target]'s [parse_zone(target_zone)] open.",
+ "[user] saws [target]'s [parse_zone(target_zone)] open!",
+ "[user] saws [target]'s [parse_zone(target_zone)] open!")
return 1
//drill bone
@@ -93,10 +105,12 @@
time = 30
/datum/surgery_step/drill/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
- user.visible_message("[user] begins to drill into the bone in [target]'s [parse_zone(target_zone)].",
- "You begin to drill into the bone in [target]'s [parse_zone(target_zone)]...")
+ display_results(user, target, "You begin to drill into the bone in [target]'s [parse_zone(target_zone)]...",
+ "[user] begins to drill into the bone in [target]'s [parse_zone(target_zone)].",
+ "[user] begins to drill into the bone in [target]'s [parse_zone(target_zone)].")
/datum/surgery_step/drill/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
- user.visible_message("[user] drills into [target]'s [parse_zone(target_zone)]!",
- "You drill into [target]'s [parse_zone(target_zone)].")
+ display_results(user, target, "You drill into [target]'s [parse_zone(target_zone)].",
+ "[user] drills into [target]'s [parse_zone(target_zone)]!",
+ "[user] drills into [target]'s [parse_zone(target_zone)]!")
return 1
diff --git a/code/modules/surgery/organs/augments_arms.dm b/code/modules/surgery/organs/augments_arms.dm
index cb004ce599..33e62d21e4 100644
--- a/code/modules/surgery/organs/augments_arms.dm
+++ b/code/modules/surgery/organs/augments_arms.dm
@@ -132,7 +132,7 @@
else
var/list/choice_list = list()
for(var/obj/item/I in items_list)
- choice_list[I] = getFlatIcon(I)
+ choice_list[I] = image(I)
var/obj/item/choice = show_radial_menu(owner, owner, choice_list)
if(owner && owner == usr && owner.stat != DEAD && (src in owner.internal_organs) && !holder && (choice in contents))
// This monster sanity check is a nice example of how bad input is.
diff --git a/code/modules/surgery/organs/eyes.dm b/code/modules/surgery/organs/eyes.dm
index 98abb2528a..eeaaaf2a03 100644
--- a/code/modules/surgery/organs/eyes.dm
+++ b/code/modules/surgery/organs/eyes.dm
@@ -169,7 +169,6 @@
var/list/obj/effect/abstract/eye_lighting/eye_lighting
var/obj/effect/abstract/eye_lighting/on_mob
var/image/mob_overlay
- var/datum/component/mobhook
/obj/item/organ/eyes/robotic/glow/Initialize()
. = ..()
@@ -185,7 +184,7 @@
/obj/item/organ/eyes/robotic/glow/proc/terminate_effects()
if(owner && active)
- deactivate()
+ deactivate(TRUE)
active = FALSE
clear_visuals(TRUE)
STOP_PROCESSING(SSfastprocess, src)
@@ -238,26 +237,12 @@
return
deactivate(silent = TRUE)
-/obj/item/organ/eyes/robotic/glow/Insert(mob/living/carbon/M, special = FALSE, drop_if_replaced = FALSE)
- . = ..()
- if (mobhook && mobhook.parent != M)
- QDEL_NULL(mobhook)
- if (!mobhook)
- mobhook = M.AddComponent(/datum/component/redirect, list(COMSIG_ATOM_DIR_CHANGE = CALLBACK(src, .proc/update_visuals)))
-
-/obj/item/organ/eyes/robotic/glow/Remove(mob/living/carbon/M)
- . = ..()
- QDEL_NULL(mobhook)
-
-/obj/item/organ/eyes/robotic/glow/Destroy()
- QDEL_NULL(mobhook) // mobhook is not our component
- return ..()
-
/obj/item/organ/eyes/robotic/glow/proc/activate(silent = FALSE)
start_visuals()
if(!silent)
to_chat(owner, "Your [src] clicks and makes a whining noise, before shooting out a beam of light!")
active = TRUE
+ RegisterSignal(owner, COMSIG_ATOM_DIR_CHANGE, .proc/update_visuals)
cycle_mob_overlay()
/obj/item/organ/eyes/robotic/glow/proc/deactivate(silent = FALSE)
@@ -265,6 +250,7 @@
if(!silent)
to_chat(owner, "Your [src] shuts off!")
active = FALSE
+ UnregisterSignal(owner, COMSIG_ATOM_DIR_CHANGE)
remove_mob_overlay()
/obj/item/organ/eyes/robotic/glow/proc/update_visuals(datum/source, olddir, newdir)
diff --git a/code/modules/surgery/organs/liver.dm b/code/modules/surgery/organs/liver.dm
index f666fc209b..94973a8e10 100755
--- a/code/modules/surgery/organs/liver.dm
+++ b/code/modules/surgery/organs/liver.dm
@@ -1,6 +1,7 @@
#define LIVER_DEFAULT_HEALTH 100 //amount of damage required for liver failure
#define LIVER_DEFAULT_TOX_TOLERANCE 3 //amount of toxins the liver can filter out
#define LIVER_DEFAULT_TOX_LETHALITY 0.01 //lower values lower how harmful toxins are to the liver
+#define LIVER_SWELLING_MOVE_MODIFY "pharma"
/obj/item/organ/liver
name = "liver"
@@ -16,6 +17,8 @@
var/toxTolerance = LIVER_DEFAULT_TOX_TOLERANCE//maximum amount of toxins the liver can just shrug off
var/toxLethality = LIVER_DEFAULT_TOX_LETHALITY//affects how much damage toxins do to the liver
var/filterToxins = TRUE //whether to filter toxins
+ var/swelling = 0
+ var/cachedmoveCalc = 1
/obj/item/organ/liver/on_life()
var/mob/living/carbon/C = owner
@@ -45,11 +48,40 @@
if(damage > maxHealth)//cap liver damage
damage = maxHealth
+ if(swelling >= 10)
+ pharmacokinesis()
+
/obj/item/organ/liver/prepare_eat()
var/obj/S = ..()
S.reagents.add_reagent("iron", 5)
return S
+//Just in case
+/obj/item/organ/liver/Remove(mob/living/carbon/M, special = 0)
+ ..()
+ M.remove_movespeed_modifier(LIVER_SWELLING_MOVE_MODIFY)
+ M.ResetBloodVol() //At the moment, this shouldn't allow application twice. You either have this OR a thirsty ferret.
+ sizeMoveMod(1, M)
+
+//Applies some of the effects to the patient.
+/obj/item/organ/liver/proc/pharmacokinesis()
+ var/moveCalc = 1+((round(swelling) - 9)/3)
+ if(moveCalc == cachedmoveCalc)//reduce calculations
+ return
+ if(prob(5))
+ to_chat(owner, "You feel a stange ache in your side, almost like a sitch. This pain is affecting your movements and making you feel lightheaded.")
+ var/mob/living/carbon/human/H = owner
+ H.add_movespeed_modifier(LIVER_SWELLING_MOVE_MODIFY, TRUE, 100, NONE, override = TRUE, multiplicative_slowdown = moveCalc)
+ H.AdjustBloodVol(moveCalc/3)
+ sizeMoveMod(moveCalc, H)
+
+/obj/item/organ/liver/proc/sizeMoveMod(var/value, mob/living/carbon/human/H)
+ if(cachedmoveCalc == value)
+ return
+ H.next_move_modifier /= cachedmoveCalc
+ H.next_move_modifier *= value
+ cachedmoveCalc = value
+
/obj/item/organ/liver/fly
name = "insectoid liver"
icon_state = "liver-x" //xenomorph liver? It's just a black liver so it fits.
diff --git a/code/modules/surgery/organs/lungs.dm b/code/modules/surgery/organs/lungs.dm
index ef358c48da..cfbb530e69 100644
--- a/code/modules/surgery/organs/lungs.dm
+++ b/code/modules/surgery/organs/lungs.dm
@@ -1,3 +1,5 @@
+#define LUNGS_MAX_HEALTH 300
+
/obj/item/organ/lungs
name = "lungs"
icon_state = "lungs"
@@ -54,8 +56,40 @@
var/crit_stabilizing_reagent = "epinephrine"
+ //health
+ var/maxHealth = LUNGS_MAX_HEALTH
+ var/damage = 0
+
+//TODO: lung health affects lung function
+/obj/item/organ/lungs/proc/adjustLungLoss(damage_mod, mob/living/carbon/M) //damage might be too low atm.
+ if (maxHealth == INFINITY)
+ return
+ if(damage+damage_mod < 0)
+ damage = 0
+ return
+
+ damage += damage_mod
+ if ((damage / maxHealth) > 1)
+ to_chat(M, "You feel your lungs collapse within your chest as you gasp for air, unable to inflate them anymore!")
+ M.emote("gasp")
+ SSblackbox.record_feedback("tally", "fermi_chem", 1, "Lungs lost")
+ qdel(src)
+ else if ((damage / maxHealth) > 0.75)
+ to_chat(M, "It's getting really hard to breathe!!")
+ M.emote("gasp")
+ M.Dizzy(3)
+ else if ((damage / maxHealth) > 0.5)
+ M.Dizzy(2)
+ to_chat(M, "Your chest is really starting to hurt.")
+ M.emote("cough")
+ else if ((damage / maxHealth) > 0.2)
+ to_chat(M, "You feel an ache within your chest.")
+ M.emote("cough")
+ M.Dizzy(1)
/obj/item/organ/lungs/proc/check_breath(datum/gas_mixture/breath, mob/living/carbon/human/H)
+//TODO: add lung damage = less oxygen gains
+ var/breathModifier = (5-(5*(damage/maxHealth)/2)) //range 2.5 - 5
if((H.status_flags & GODMODE))
return
if(HAS_TRAIT(H, TRAIT_NOBREATH))
@@ -124,7 +158,7 @@
else
H.failed_last_breath = FALSE
if(H.health >= H.crit_threshold)
- H.adjustOxyLoss(-5)
+ H.adjustOxyLoss(-breathModifier) //More damaged lungs = slower oxy rate up to a factor of half
gas_breathed = breath_gases[/datum/gas/oxygen]
H.clear_alert("not_enough_oxy")
@@ -153,7 +187,7 @@
else
H.failed_last_breath = FALSE
if(H.health >= H.crit_threshold)
- H.adjustOxyLoss(-5)
+ H.adjustOxyLoss(-breathModifier)
gas_breathed = breath_gases[/datum/gas/nitrogen]
H.clear_alert("nitro")
@@ -190,7 +224,7 @@
else
H.failed_last_breath = FALSE
if(H.health >= H.crit_threshold)
- H.adjustOxyLoss(-5)
+ H.adjustOxyLoss(-breathModifier)
gas_breathed = breath_gases[/datum/gas/carbon_dioxide]
H.clear_alert("not_enough_co2")
@@ -220,7 +254,7 @@
else
H.failed_last_breath = FALSE
if(H.health >= H.crit_threshold)
- H.adjustOxyLoss(-5)
+ H.adjustOxyLoss(-breathModifier)
gas_breathed = breath_gases[/datum/gas/plasma]
H.clear_alert("not_enough_tox")
@@ -244,6 +278,9 @@
else if(SA_pp > 0.01) // There is sleeping gas in their lungs, but only a little, so give them a bit of a warning
if(prob(20))
H.emote(pick("giggle", "laugh"))
+ SEND_SIGNAL(owner, COMSIG_ADD_MOOD_EVENT, "chemical_euphoria", /datum/mood_event/chemical_euphoria)
+ else
+ SEND_SIGNAL(owner, COMSIG_CLEAR_MOOD_EVENT, "chemical_euphoria")
// BZ
@@ -368,10 +405,13 @@
var/cold_modifier = H.dna.species.coldmod
if(breath_temperature < cold_level_3_threshold)
H.apply_damage_type(cold_level_3_damage*cold_modifier, cold_damage_type)
+ adjustLungLoss((cold_level_3_damage*cold_modifier*2), H)
if(breath_temperature > cold_level_3_threshold && breath_temperature < cold_level_2_threshold)
H.apply_damage_type(cold_level_2_damage*cold_modifier, cold_damage_type)
+ adjustLungLoss((cold_level_2_damage*cold_modifier*2), H)
if(breath_temperature > cold_level_2_threshold && breath_temperature < cold_level_1_threshold)
H.apply_damage_type(cold_level_1_damage*cold_modifier, cold_damage_type)
+ adjustLungLoss((cold_level_1_damage*cold_modifier*2), H)
if(breath_temperature < cold_level_1_threshold)
if(prob(20))
to_chat(H, "You feel [cold_message] in your [name]!")
@@ -380,10 +420,13 @@
var/heat_modifier = H.dna.species.heatmod
if(breath_temperature > heat_level_1_threshold && breath_temperature < heat_level_2_threshold)
H.apply_damage_type(heat_level_1_damage*heat_modifier, heat_damage_type)
+ adjustLungLoss((heat_level_1_damage*heat_modifier*2), H)
if(breath_temperature > heat_level_2_threshold && breath_temperature < heat_level_3_threshold)
H.apply_damage_type(heat_level_2_damage*heat_modifier, heat_damage_type)
+ adjustLungLoss((heat_level_2_damage*heat_modifier*2), H)
if(breath_temperature > heat_level_3_threshold)
H.apply_damage_type(heat_level_3_damage*heat_modifier, heat_damage_type)
+ adjustLungLoss((heat_level_3_damage*heat_modifier*2), H)
if(breath_temperature > heat_level_1_threshold)
if(prob(20))
to_chat(H, "You feel [hot_message] in your [name]!")
@@ -402,12 +445,14 @@
safe_oxygen_max = 0 // Like, at all.
safe_toxins_min = 16 //We breath THIS!
safe_toxins_max = 0
+ maxHealth = INFINITY//I don't understand how plamamen work, so I'm not going to try t give them special lungs atm
/obj/item/organ/lungs/cybernetic
name = "cybernetic lungs"
desc = "A cybernetic version of the lungs found in traditional humanoid entities. It functions the same as an organic lung and is merely meant as a replacement."
icon_state = "lungs-c"
synthetic = TRUE
+ maxHealth = 400
/obj/item/organ/lungs/cybernetic/emp_act()
. = ..()
@@ -427,6 +472,7 @@
cold_level_1_threshold = 200
cold_level_2_threshold = 140
cold_level_3_threshold = 100
+ maxHealth = 550
/obj/item/organ/lungs/ashwalker
name = "ash lungs"
@@ -451,6 +497,6 @@
/obj/item/organ/lungs/slime/check_breath(datum/gas_mixture/breath, mob/living/carbon/human/H)
. = ..()
- if (breath.gases[/datum/gas/plasma])
+ if (breath && breath.gases[/datum/gas/plasma])
var/plasma_pp = breath.get_breath_partial_pressure(breath.gases[/datum/gas/plasma])
owner.blood_volume += (0.2 * plasma_pp) // 10/s when breathing literally nothing but plasma, which will suffocate you.
diff --git a/code/modules/surgery/organs/organ_internal.dm b/code/modules/surgery/organs/organ_internal.dm
index b16967b6b0..9f910de9a9 100644
--- a/code/modules/surgery/organs/organ_internal.dm
+++ b/code/modules/surgery/organs/organ_internal.dm
@@ -153,6 +153,17 @@
// if they have no mutant tongues, give them a regular one
T.Insert(src)
+ else
+ var/obj/item/organ/tongue/oT = getorganslot(ORGAN_SLOT_TONGUE)
+ if(oT.name == "fluffy tongue")
+ var/obj/item/organ/tongue/T
+ if(dna && dna.species && dna.species.mutanttongue)
+ T = new dna.species.mutanttongue()
+ else
+ T = new()
+ oT.Remove(src)
+ qdel(oT)
+ T.Insert(src)
if(!getorganslot(ORGAN_SLOT_EYES))
var/obj/item/organ/eyes/E
diff --git a/code/modules/surgery/organs/tongue.dm b/code/modules/surgery/organs/tongue.dm
index ccfc21f878..3eaaa8de92 100644
--- a/code/modules/surgery/organs/tongue.dm
+++ b/code/modules/surgery/organs/tongue.dm
@@ -1,3 +1,5 @@
+#define TONGUE_MAX_HEALTH 60
+
/obj/item/organ/tongue
name = "tongue"
desc = "A fleshy muscle mostly used for lying."
@@ -8,6 +10,8 @@
var/list/languages_possible
var/say_mod = null
var/taste_sensitivity = 15 // lower is more sensitive.
+ var/maxHealth = TONGUE_MAX_HEALTH
+ var/damage = 0
var/modifies_speech = FALSE
var/static/list/languages_possible_base = typecacheof(list(
/datum/language/common,
@@ -27,6 +31,29 @@
/obj/item/organ/tongue/proc/handle_speech(datum/source, list/speech_args)
+/obj/item/organ/tongue/proc/adjustTongueLoss(mob/living/carbon/M, damage_mod)
+ if (maxHealth == "alien")
+ return
+ if (maxHealth == "bone")
+ var/target = M.get_bodypart(BODY_ZONE_HEAD)
+ M.apply_damage(damage_mod, BURN, target)
+ to_chat(M, "The drink burns your skull! Oof, your bones!")
+ return
+ if(damage+damage_mod < 0)
+ damage = 0
+ return
+
+ damage += damage_mod
+ if ((damage / maxHealth) > 1)
+ to_chat(M, "Your tongue is singed beyond recognition, and disintegrates!")
+ SSblackbox.record_feedback("tally", "fermi_chem", 1, "Tongues lost to Fermi")
+ qdel(src)
+ else if ((damage / maxHealth) > 0.85)
+ to_chat(M, "Your tongue feels like it's about to fall out!.")
+ else if ((damage / maxHealth) > 0.5)
+ to_chat(M, "Your tongue is really starting to hurt.")
+
+
/obj/item/organ/tongue/Insert(mob/living/carbon/M, special = 0)
..()
if(say_mod && M.dna && M.dna.species)
@@ -51,6 +78,7 @@
icon_state = "tonguelizard"
say_mod = "hisses"
taste_sensitivity = 10 // combined nose + tongue, extra sensitive
+ maxHealth = 40 //extra sensitivity means tongue is more susceptible to damage
modifies_speech = TRUE
/obj/item/organ/tongue/lizard/handle_speech(datum/source, list/speech_args)
@@ -68,6 +96,7 @@
icon_state = "tonguefly"
say_mod = "buzzes"
taste_sensitivity = 25 // you eat vomit, this is a mercy
+ maxHealth = 80 //years of eatting trash has made your tongue strong
modifies_speech = TRUE
/obj/item/organ/tongue/fly/handle_speech(datum/source, list/speech_args)
@@ -85,6 +114,7 @@
icon_state = "tongueayylmao"
say_mod = "gibbers"
taste_sensitivity = 101 // ayys cannot taste anything.
+ maxHealth = 120 //Ayys probe a lot
modifies_speech = TRUE
/obj/item/organ/tongue/abductor/handle_speech(datum/source, list/speech_args)
@@ -113,6 +143,7 @@
icon_state = "tonguezombie"
say_mod = "moans"
taste_sensitivity = 32
+ maxHealth = 65 //Stop! It's already dead...!
modifies_speech = TRUE
/obj/item/organ/tongue/zombie/handle_speech(datum/source, list/speech_args)
@@ -137,6 +168,7 @@
icon_state = "tonguexeno"
say_mod = "hisses"
taste_sensitivity = 10 // LIZARDS ARE ALIENS CONFIRMED
+ maxHealth = "alien" //Their blood is acid, so, no, though a tongueless xeno might be funny
modifies_speech = TRUE // not really, they just hiss
var/static/list/languages_possible_alien = typecacheof(list(
/datum/language/xenocommon,
@@ -159,6 +191,7 @@
say_mod = "rattles"
attack_verb = list("bitten", "chattered", "chomped", "enamelled", "boned")
taste_sensitivity = 101 // skeletons cannot taste anything
+ maxHealth = "bone" //Take brute damage instead
modifies_speech = TRUE
var/chattering = FALSE
var/phomeme_type = "sans"
@@ -181,6 +214,7 @@
name = "plasma bone \"tongue\""
desc = "Like animated skeletons, Plasmamen vibrate their teeth in order to produce speech."
icon_state = "tongueplasma"
+ maxHealth = "alien"
modifies_speech = FALSE
/obj/item/organ/tongue/robot
@@ -192,6 +226,7 @@
attack_verb = list("beeped", "booped")
modifies_speech = TRUE
taste_sensitivity = 25 // not as good as an organic tongue
+ maxHealth = 100 //RoboTongue!
var/electronics_magic = TRUE
/obj/item/organ/tongue/robot/can_speak_in_language(datum/language/dt)
@@ -200,8 +235,39 @@
/obj/item/organ/tongue/robot/handle_speech(datum/source, list/speech_args)
speech_args[SPEECH_SPANS] |= SPAN_ROBOT
+/obj/item/organ/tongue/fluffy
+ name = "fluffy tongue"
+ desc = "OwO what's this?"
+ icon_state = "tonguefluffy"
+ taste_sensitivity = 10 // extra sensitive and inquisitive uwu
+ maxHealth = 35 //Sensitive tongue!
+ modifies_speech = TRUE
+
+/obj/item/organ/tongue/fluffy/handle_speech(datum/source, list/speech_args)
+ var/message = speech_args[SPEECH_MESSAGE]
+ if(copytext(message, 1, 2) != "*")
+ message = replacetext(message, "ne", "nye")
+ message = replacetext(message, "nu", "nyu")
+ message = replacetext(message, "na", "nya")
+ message = replacetext(message, "no", "nyo")
+ message = replacetext(message, "ove", "uv")
+ message = replacetext(message, "l", "w")
+ message = replacetext(message, "r", "w")
+ message = lowertext(message)
+ speech_args[SPEECH_MESSAGE] = message
+
+/obj/item/organ/tongue/cybernetic
+ name = "cybernetic tongue"
+ desc = "A state of the art robotic tongue that can detect the pH of anything drank."
+ icon_state = "tonguecybernetic"
+ taste_sensitivity = 10
+ maxHealth = 60 //It's robotic!
+
+/obj/item/organ/tongue/cybernetic/handle_speech(datum/source, list/speech_args)
+ speech_args[SPEECH_SPANS] |= SPAN_ROBOT
+
/obj/item/organ/tongue/robot/ipc
name = "positronic voicebox"
say_mod = "beeps"
desc = "A voice synthesizer used by IPCs to smoothly interface with organic lifeforms."
- electronics_magic = FALSE
\ No newline at end of file
+ electronics_magic = FALSE
diff --git a/code/modules/surgery/organs/vocal_cords.dm b/code/modules/surgery/organs/vocal_cords.dm
index 55ead3b5b4..8103224306 100644
--- a/code/modules/surgery/organs/vocal_cords.dm
+++ b/code/modules/surgery/organs/vocal_cords.dm
@@ -3,7 +3,7 @@
#define COOLDOWN_MEME 300
#define COOLDOWN_NONE 100
-/obj/item/organ/vocal_cords //organs that are activated through speech with the :x channel
+/obj/item/organ/vocal_cords //organs that are activated through speech with the :x/MODE_KEY_VOCALCORDS channel
name = "vocal cords"
icon_state = "appendix"
zone = BODY_ZONE_PRECISE_MOUTH
@@ -575,7 +575,7 @@
cooldown = COOLDOWN_MEME
for(var/V in listeners)
var/mob/living/carbon/human/H = V
- if(H.canbearoused && H.has_dna()) // probably a redundant check but for good measure
+ if(H.canbearoused && H.has_dna() && HAS_TRAIT(H, TRAIT_NYMPHO)) // probably a redundant check but for good measure
H.mob_climax(forced_climax=TRUE)
//DAB
@@ -608,6 +608,867 @@
return cooldown
+//////////////////////////////////////
+///////ENTHRAL VELVET CHORDS//////////
+//////////////////////////////////////
+
+//Heavily modified voice of god code
+/obj/item/organ/vocal_cords/velvet
+ name = "Velvet chords"
+ desc = "The voice spoken from these just make you want to drift off, sleep and obey."
+ icon_state = "velvet_chords"
+ actions_types = list(/datum/action/item_action/organ_action/velvet)
+ spans = list("velvet")
+
+/datum/action/item_action/organ_action/velvet
+ name = "Velvet chords"
+ var/obj/item/organ/vocal_cords/velvet/cords = null
+ //icon_icon = 'icons/mob/screen_alert.dmi'
+ //button_icon_state = "velvet_chords"
+ //icon = 'icons/mob/screen_alert.dmi'
+ //icon_state = "in_love"
+
+/datum/action/item_action/organ_action/velvet/New()
+ ..()
+ cords = target
+
+/datum/action/item_action/organ_action/velvet/IsAvailable()
+ return TRUE
+
+/datum/action/item_action/organ_action/velvet/Trigger()
+ . = ..()
+ var/command = input(owner, "Speak in a sultry tone", "Command")
+ if(QDELETED(src) || QDELETED(owner))
+ return
+ if(!command)
+ return
+ owner.say(".x[command]")
+
+/obj/item/organ/vocal_cords/velvet/can_speak_with()
+ return TRUE
+
+/obj/item/organ/vocal_cords/velvet/handle_speech(message) //actually say the message
+ owner.say(message, spans = spans, sanitize = FALSE)
+ velvetspeech(message, owner, 1)
+
+//////////////////////////////////////
+///////////FermiChem//////////////////
+//////////////////////////////////////
+//Removed span_list from input arguments.
+/proc/velvetspeech(message, mob/living/user, base_multiplier = 1, message_admins = FALSE, debug = FALSE)
+
+ if(!user || !user.can_speak() || user.stat)
+ return 0 //no cooldown
+
+ var/log_message = message
+
+ //FIND THRALLS
+ message = lowertext(message)
+ var/mob/living/list/listeners = list()
+ for(var/mob/living/L in get_hearers_in_view(8, user))
+ if(L.can_hear() && !L.anti_magic_check(FALSE, TRUE) && L.stat != DEAD)
+ if(L.has_status_effect(/datum/status_effect/chem/enthrall))//Check to see if they have the status
+ var/datum/status_effect/chem/enthrall/E = L.has_status_effect(/datum/status_effect/chem/enthrall)//Check to see if pet is on cooldown from last command and if the master is right
+ if(E.master != user)
+ continue
+ if(ishuman(L))
+ var/mob/living/carbon/human/H = L
+ if(istype(H.ears, /obj/item/clothing/ears/earmuffs))
+ continue
+
+ if (E.cooldown > 0)//If they're on cooldown you can't give them more commands.
+ continue
+ listeners += L
+
+ if(!listeners.len)
+ return 0
+
+ //POWER CALCULATIONS
+
+ var/power_multiplier = base_multiplier
+
+ // Not sure I want to give extra power to anyone at the moment...? We'll see how it turns out
+ if(user.mind)
+ //Chaplains are very good at indoctrinating
+ if(user.mind.assigned_role == "Chaplain")
+ power_multiplier *= 1.2
+ //Command staff has authority
+ if(user.mind.assigned_role in GLOB.command_positions)
+ power_multiplier *= 1.1
+ //Why are you speaking
+ if(user.mind.assigned_role == "Mime")
+ power_multiplier *= 0.5
+
+ //Cultists are closer to their gods and are better at indoctrinating
+ if(iscultist(user))
+ power_multiplier *= 1.2
+ else if (is_servant_of_ratvar(user))
+ power_multiplier *= 1.2
+ else if (is_devil(user))//The devil is supposed to be seductive, right?
+ power_multiplier *= 1.2
+
+ //range = 0.5 - 1.4~
+ //most cases = 1
+
+ //Try to check if the speaker specified a name or a job to focus on
+ var/list/specific_listeners = list()
+ var/found_string = null
+
+ //Get the proper job titles
+ message = get_full_job_name(message)
+
+ for(var/V in listeners)
+ var/mob/living/L = V
+ if(dd_hasprefix(message, L.real_name))
+ specific_listeners += L //focus on those with the specified name
+ //Cut out the name so it doesn't trigger commands
+ found_string = L.real_name
+ power_multiplier += 0.5
+
+ else if(dd_hasprefix(message, L.first_name()))
+ specific_listeners += L //focus on those with the specified name
+ //Cut out the name so it doesn't trigger commands
+ found_string = L.first_name()
+ power_multiplier += 0.5
+
+ else if(L.mind && L.mind.assigned_role && dd_hasprefix(message, L.mind.assigned_role))
+ specific_listeners += L //focus on those with the specified job
+ //Cut out the job so it doesn't trigger commands
+ found_string = L.mind.assigned_role
+ power_multiplier += 0.25
+
+ if(specific_listeners.len)
+ listeners = specific_listeners
+ //power_multiplier *= (1 + (1/specific_listeners.len)) //Put this is if it becomes OP, power is judged internally on a thrall, so shouldn't be nessicary.
+ message = copytext(message, 0, 1)+copytext(message, 1 + length(found_string), length(message) + 1)//I have no idea what this does
+
+ var/obj/item/organ/tongue/T = user.getorganslot(ORGAN_SLOT_TONGUE)
+ if (T.name == "fluffy tongue") //If you sound hillarious, it's hard to take you seriously. This is a way for other players to combat/reduce their effectiveness.
+ power_multiplier *= 0.75
+
+ if(debug == TRUE)
+ to_chat(world, "[user]'s power is [power_multiplier].")
+
+ //Mixables
+ var/static/regex/enthral_words = regex("relax|obey|love|serve|docile|so easy|ara ara")
+ var/static/regex/reward_words = regex("good boy|good girl|good pet|good job")
+ var/static/regex/punish_words = regex("bad boy|bad girl|bad pet|bad job")
+ //phase 0
+ var/static/regex/saymyname_words = regex("say my name|who am i|whoami")
+ var/static/regex/wakeup_words = regex("revert|awaken|snap") //works
+ //phase1
+ var/static/regex/petstatus_words = regex("how are you|what is your status|are you okay")
+ var/static/regex/silence_words = regex("shut up|silence|be silent|ssh|quiet|hush")
+ var/static/regex/speak_words = regex("talk to me|speak")
+ var/static/regex/antiresist_words = regex("unable to resist|give in")//useful if you think your target is resisting a lot
+ var/static/regex/resist_words = regex("resist|snap out of it|fight")//useful if two enthrallers are fighting
+ var/static/regex/forget_words = regex("forget|muddled|awake and forget")
+ var/static/regex/attract_words = regex("come here|come to me|get over here|attract")
+ //phase 2
+ var/static/regex/orgasm_words = regex("cum|orgasm|climax|squirt|heyo") //wah, lewd
+ var/static/regex/awoo_words = regex("howl|awoo|bark")
+ var/static/regex/nya_words = regex("nya|meow|mewl")
+ var/static/regex/sleep_words = regex("sleep|slumber|rest")
+ var/static/regex/strip_words = regex("strip|derobe|nude")
+ var/static/regex/walk_words = regex("slow down|walk")
+ var/static/regex/run_words = regex("run|speed up")
+ var/static/regex/liedown_words = regex("lie down") //TO ADD
+ var/static/regex/knockdown_words = regex("drop|fall|trip|knockdown|kneel")
+ //phase 3
+ var/static/regex/statecustom_words = regex("state triggers|state your triggers")
+ var/static/regex/custom_words = regex("new trigger|listen to me")
+ var/static/regex/custom_words_words = regex("speak|echo|shock|cum|kneel|strip|trance")//What a descriptive name!
+ var/static/regex/custom_echo = regex("obsess|fills your mind|loop")
+ var/static/regex/instill_words = regex("feel|entice|overwhel")
+ var/static/regex/recognise_words = regex("recognise me|did you miss me?")
+ var/static/regex/objective_words = regex("new objective|obey this command|unable to resist|compulsed")
+ var/static/regex/heal_words = regex("live|heal|survive|mend|life|pets never die")
+ var/static/regex/stun_words = regex("stop|wait|stand still|hold on|halt")
+ var/static/regex/hallucinate_words = regex("get high|hallucinate")
+ var/static/regex/hot_words = regex("heat|hot|hell")
+ var/static/regex/cold_words = regex("cold|cool down|chill|freeze")
+ var/static/regex/getup_words = regex("get up")
+ var/static/regex/pacify_words = regex("more and more docile|complaisant|friendly|pacifist")
+ var/static/regex/charge_words = regex("charge|oorah|attack")
+
+ var/distancelist = list(2,2,1.5,1.3,1.15,1,0.8,0.6,0.5,0.25)
+
+ //CALLBACKS ARE USED FOR MESSAGES BECAUSE SAY IS HANDLED AFTER THE PROCESSING.
+
+ //Tier 1
+ //ENTHRAL mixable (works I think)
+ if(findtext(message, enthral_words))
+ for(var/V in listeners)
+ var/mob/living/L = V
+ var/datum/status_effect/chem/enthrall/E = L.has_status_effect(/datum/status_effect/chem/enthrall)
+ power_multiplier *= distancelist[get_dist(user, V)+1]
+ if(L == user)
+ continue
+ if(length(message))
+ E.enthrallTally += (power_multiplier*(((length(message))/200) + 1)) //encourage players to say more than one word.
+ else
+ E.enthrallTally += power_multiplier*1.25 //thinking about it, I don't know how this can proc
+ if(L.canbearoused)
+ if(L.client?.prefs.lewdchem)
+ addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, L, "[E.enthrallGender] is so nice to listen to."), 5)
+ E.cooldown += 1
+
+ //REWARD mixable works
+ if(findtext(message, reward_words))
+ for(var/V in listeners)
+ var/mob/living/L = V
+ var/datum/status_effect/chem/enthrall/E = L.has_status_effect(/datum/status_effect/chem/enthrall)
+ power_multiplier *= distancelist[get_dist(user, V)+1]
+ if(L == user)
+ continue
+ if (L.client?.prefs.lewdchem)
+ addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, L, "[E.enthrallGender] has praised me!!"), 5)
+ if(HAS_TRAIT(L, TRAIT_NYMPHO))
+ L.adjustArousalLoss(2*power_multiplier)
+ if(HAS_TRAIT(L, TRAIT_MASO))
+ E.enthrallTally -= power_multiplier
+ E.resistanceTally += power_multiplier
+ E.cooldown += 1
+ else
+ addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, L, "I've been praised for doing a good job!"), 5)
+ E.resistanceTally -= power_multiplier
+ E.enthrallTally += power_multiplier
+ var/descmessage = "[(L.client?.prefs.lewdchem?"I feel so happy! I'm a good pet who [E.enthrallGender] loves!":"I did a good job!")]"
+ SEND_SIGNAL(L, COMSIG_ADD_MOOD_EVENT, "enthrallpraise", /datum/mood_event/enthrallpraise, descmessage)
+ E.cooldown += 1
+
+ //PUNISH mixable works
+ else if(findtext(message, punish_words))
+ for(var/V in listeners)
+ var/mob/living/L = V
+ var/datum/status_effect/chem/enthrall/E = L.has_status_effect(/datum/status_effect/chem/enthrall)
+ var/descmessage = "[(L.client?.prefs.lewdchem?"I've failed [E.enthrallGender]... What a bad, bad pet!":"I did a bad job...")]"
+ if(L == user)
+ continue
+ if (L.client?.prefs.lewdchem)
+ if(HAS_TRAIT(L, TRAIT_MASO))
+ L.adjustArousalLoss(3*power_multiplier)
+ descmessage += "And yet, it feels so good..!" //I don't really understand masco, is this the right sort of thing they like?
+ E.enthrallTally += power_multiplier
+ E.resistanceTally -= power_multiplier
+ addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, L, "I've let [E.enthrallGender] down...!"), 5)
+ else
+ addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, L, "I've let [E.enthrallGender] down..."), 5)
+ else
+ addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, L, "I've failed [E.master]..."), 5)
+ E.resistanceTally += power_multiplier
+ E.enthrallTally += power_multiplier
+ E.cooldown += 1
+ SEND_SIGNAL(L, COMSIG_ADD_MOOD_EVENT, "enthrallscold", /datum/mood_event/enthrallscold, descmessage)
+ E.cooldown += 1
+
+
+
+ //teir 0
+ //SAY MY NAME works
+ if((findtext(message, saymyname_words)))
+ for(var/V in listeners)
+ var/mob/living/carbon/C = V
+ var/datum/status_effect/chem/enthrall/E = C.has_status_effect(/datum/status_effect/chem/enthrall)
+ REMOVE_TRAIT(C, TRAIT_MUTE, "enthrall")
+ C.silent = 0
+ if(C.client?.prefs.lewdchem)
+ addtimer(CALLBACK(C, /atom/movable/proc/say, "[E.enthrallGender]"), 5)
+ else
+ addtimer(CALLBACK(C, /atom/movable/proc/say, "[E.master]"), 5)
+
+ //WAKE UP
+ else if((findtext(message, wakeup_words)))
+ for(var/V in listeners)
+ var/mob/living/L = V
+ var/datum/status_effect/chem/enthrall/E = L.has_status_effect(/datum/status_effect/chem/enthrall)
+ L.SetSleeping(0)//Can you hear while asleep?
+ switch(E.phase)
+ if(0)
+ E.phase = 3
+ E.status = null
+ user.emote("snap")
+ if(L.client?.prefs.lewdchem)
+ addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, L, "The snapping of your [E.enthrallGender]'s fingers brings you back to your enthralled state, obedient and ready to serve."), 5)
+ else
+ addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, L, "The snapping of [E.master]'s fingers brings you back to being under their influence."), 5)
+ to_chat(user, "You wake up [L]!")
+
+ //tier 1
+
+ //PETSTATUS i.e. how they are
+ else if((findtext(message, petstatus_words)))
+ for(var/V in listeners)
+ var/mob/living/carbon/human/H = V
+ var/datum/status_effect/chem/enthrall/E = H.has_status_effect(/datum/status_effect/chem/enthrall)
+ REMOVE_TRAIT(H, TRAIT_MUTE, "enthrall")
+ var/speaktrigger = ""
+ //phase
+ switch(E.phase)
+ if(0)
+ continue
+ if(1)
+ addtimer(CALLBACK(H, /atom/movable/proc/say, "I feel happy being with you."), 5)
+ continue
+ if(2)
+ speaktrigger += "[(H.client?.prefs.lewdchem?"I think I'm in love with you... ":"I find you really inspirational, ")]" //'
+ if(3)
+ speaktrigger += "[(H.client?.prefs.lewdchem?"I'm devoted to being your pet":"I'm commited to following your cause!")]! "
+ if(4)
+ speaktrigger += "[(H.client?.prefs.lewdchem?"You are my whole world and all of my being belongs to you, ":"I cannot think of anything else but aiding your cause, ")] "//Redflags!!
+
+ //mood
+ GET_COMPONENT_FROM(mood, /datum/component/mood, H)
+ switch(mood.sanity)
+ if(SANITY_GREAT to INFINITY)
+ speaktrigger += "I'm beyond elated!! " //did you mean byond elated? hohoho
+ if(SANITY_NEUTRAL to SANITY_GREAT)
+ speaktrigger += "I'm really happy! "
+ if(SANITY_DISTURBED to SANITY_NEUTRAL)
+ speaktrigger += "I'm a little sad, "
+ if(SANITY_UNSTABLE to SANITY_DISTURBED)
+ speaktrigger += "I'm really upset, "
+ if(SANITY_CRAZY to SANITY_UNSTABLE)
+ speaktrigger += "I'm about to fall apart without you! "
+ if(SANITY_INSANE to SANITY_CRAZY)
+ speaktrigger += "Hold me, please.. "
+
+ //Withdrawal
+ switch(E.withdrawalTick)
+ if(10 to 36) //denial
+ speaktrigger += "I missed you, "
+ if(36 to 66) //barganing
+ speaktrigger += "I missed you, but I knew you'd come back for me! "
+ if(66 to 90) //anger
+ speaktrigger += "I couldn't take being away from you like that, "
+ if(90 to 140) //depression
+ speaktrigger += "I was so scared you'd never come back, "
+ if(140 to INFINITY) //acceptance
+ speaktrigger += "I'm hurt that you left me like that... I felt so alone... "
+
+ //hunger
+ switch(H.nutrition)
+ if(0 to NUTRITION_LEVEL_STARVING)
+ speaktrigger += "I'm famished, please feed me..! "
+ if(NUTRITION_LEVEL_STARVING to NUTRITION_LEVEL_HUNGRY)
+ speaktrigger += "I'm so hungry... "
+ if(NUTRITION_LEVEL_HUNGRY to NUTRITION_LEVEL_FED)
+ speaktrigger += "I'm hungry, "
+ if(NUTRITION_LEVEL_FED to NUTRITION_LEVEL_WELL_FED)
+ speaktrigger += "I'm sated, "
+ if(NUTRITION_LEVEL_WELL_FED to NUTRITION_LEVEL_FULL)
+ speaktrigger += "I've a full belly! "
+ if(NUTRITION_LEVEL_FULL to INFINITY)
+ speaktrigger += "I'm fat... "
+
+ //health
+ switch(H.health)
+ if(100 to INFINITY)
+ speaktrigger += "I feel fit, "
+ if(80 to 99)
+ speaktrigger += "I ache a little bit, "
+ if(40 to 80)
+ speaktrigger += "I'm really hurt, "
+ if(0 to 40)
+ speaktrigger += "I'm in a lot of pain, help! "
+ if(-INFINITY to 0)
+ speaktrigger += "I'm barely concious and in so much pain, please help me! "
+ //toxin
+ switch(H.getToxLoss())
+ if(10 to 30)
+ speaktrigger += "I feel a bit queasy... "
+ if(30 to 60)
+ speaktrigger += "I feel nauseous... "
+ if(60 to INFINITY)
+ speaktrigger += "My head is pounding and I feel like I'm going to be sick... "
+ //oxygen
+ if (H.getOxyLoss() >= 25)
+ speaktrigger += "I can't breathe! "
+ //blind
+ if (HAS_TRAIT(H, TRAIT_BLIND))
+ speaktrigger += "I can't see! "
+ //deaf..?
+ if (HAS_TRAIT(H, TRAIT_DEAF))//How the heck you managed to get here I have no idea, but just in case!
+ speaktrigger += "I can barely hear you! "
+ //And the brain damage. And the brain damage. And the brain damage. And the brain damage. And the brain damage.
+ switch(H.getBrainLoss())
+ if(20 to 40)
+ speaktrigger += "I have a mild head ache, "
+ if(40 to 80)
+ speaktrigger += "I feel disorentated and confused, "
+ if(80 to 120)
+ speaktrigger += "My head feels like it's about to explode, "
+ if(120 to 160)
+ speaktrigger += "You are the only thing keeping my mind sane, "
+ if(160 to INFINITY)
+ speaktrigger += "I feel like I'm on the brink of losing my mind, "
+
+ //horny
+ if(HAS_TRAIT(H, TRAIT_NYMPHO) && H.canbearoused && H.client?.prefs.lewdchem)
+ switch(H.getArousalLoss())
+ if(40 to 60)
+ speaktrigger += "I'm feeling a little horny, "
+ if(60 to 80)
+ speaktrigger += "I'm feeling horny, "
+ if(80 to INFINITY)
+ speaktrigger += "I'm really, really horny, "
+
+ //collar
+ if(istype(H.wear_neck, /obj/item/clothing/neck/petcollar))
+ speaktrigger += "I love the collar you gave me, "
+ //End
+ if(H.client?.prefs.lewdchem)
+ speaktrigger += "[E.enthrallGender]!"
+ else
+ speaktrigger += "[user.first_name()]!"
+ //say it!
+ addtimer(CALLBACK(H, /atom/movable/proc/say, "[speaktrigger]"), 5)
+ E.cooldown += 1
+
+ //SILENCE
+ else if((findtext(message, silence_words)))
+ for(var/mob/living/carbon/C in listeners)
+ var/datum/status_effect/chem/enthrall/E = C.has_status_effect(/datum/status_effect/chem/enthrall)
+ power_multiplier *= distancelist[get_dist(user, C)+1]
+ if (E.phase >= 3) //If target is fully enthralled,
+ ADD_TRAIT(C, TRAIT_MUTE, "enthrall")
+ else
+ C.silent += ((10 * power_multiplier) * E.phase)
+ addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, C, "You are unable to speak!"), 5)
+ to_chat(user, "You silence [C].")
+ E.cooldown += 3
+
+ //SPEAK
+ else if((findtext(message, speak_words)))//fix
+ for(var/mob/living/carbon/C in listeners)
+ var/datum/status_effect/chem/enthrall/E = C.has_status_effect(/datum/status_effect/chem/enthrall)
+ REMOVE_TRAIT(C, TRAIT_MUTE, "enthrall")
+ C.silent = 0
+ E.cooldown += 3
+ to_chat(user, "You [(C.client?.prefs.lewdchem?"allow [C] to speak again":"encourage [C] to speak again")].")
+
+
+ //Antiresist
+ else if((findtext(message, antiresist_words)))
+ for(var/V in listeners)
+ var/mob/living/L = V
+ var/datum/status_effect/chem/enthrall/E = L.has_status_effect(/datum/status_effect/chem/enthrall)
+ E.status = "Antiresist"
+ addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, L, "Your mind clouds over, as you find yourself unable to resist!"), 5)
+ E.statusStrength = (1 * power_multiplier * E.phase)
+ E.cooldown += 15//Too short? yes, made 15
+ to_chat(user, "You frustrate [L]'s attempts at resisting.")
+
+ //RESIST
+ else if((findtext(message, resist_words)))
+ for(var/mob/living/carbon/C in listeners)
+ var/datum/status_effect/chem/enthrall/E = C.has_status_effect(/datum/status_effect/chem/enthrall)
+ power_multiplier *= distancelist[get_dist(user, C)+1]
+ E.deltaResist += (power_multiplier)
+ E.owner_resist()
+ E.cooldown += 2
+ addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, C, "You are spurred into resisting from [user]'s words!'"), 5)
+ to_chat(user, "You spark resistance in [C].")
+
+ //FORGET (A way to cancel the process)
+ else if((findtext(message, forget_words)))
+ for(var/mob/living/carbon/C in listeners)
+ var/datum/status_effect/chem/enthrall/E = C.has_status_effect(/datum/status_effect/chem/enthrall)
+ if(E.phase == 4)
+ addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, C, "You're unable to forget about [(C.client?.prefs.lewdchem?"the dominating presence of [E.enthrallGender]":"[E.master]")]!"), 5)
+ continue
+ addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, C, "You wake up, forgetting everything that just happened. You must've dozed off..? How embarassing!"), 5)
+ C.Sleeping(50)
+ switch(E.phase)
+ if(1 to 2)
+ E.phase = -1
+ to_chat(C, "You have no recollection of being enthralled by [E.master]!")
+ to_chat(user, "You revert [C] back to their state before enthrallment.")
+ if(3)
+ E.phase = 0
+ E.cooldown = 0
+ if(C.client?.prefs.lewdchem)
+ addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, C, "You revert to yourself before being enthralled by your [E.enthrallGender], with no memory of what happened."), 5)
+ else
+ addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, C, "You revert to who you were before, with no memory of what happened with [E.master]."), 5)
+ to_chat(user, "You put [C] into a sleeper state, ready to turn them back at the snap of your fingers.")
+
+ //ATTRACT
+ else if((findtext(message, attract_words)))
+ for(var/V in listeners)
+ var/mob/living/L = V
+ var/datum/status_effect/chem/enthrall/E = L.has_status_effect(/datum/status_effect/chem/enthrall)
+ L.throw_at(get_step_towards(user,L), 3 * power_multiplier, 1 * power_multiplier)
+ E.cooldown += 3
+ addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, L, "You are drawn towards [user]!"), 5)
+ to_chat(user, "You draw [L] towards you!")
+
+
+ //teir 2
+
+ /* removed for now
+ //ORGASM
+ else if((findtext(message, orgasm_words)))
+ for(var/V in listeners)
+ var/mob/living/carbon/human/H = V
+ var/datum/status_effect/chem/enthrall/E = H.has_status_effect(/datum/status_effect/chem/enthrall)
+ if(E.phase > 1)
+ if(HAS_TRAIT(H, TRAIT_NYMPHO) && H.canbearoused && H.client?.prefs.lewdchem) // probably a redundant check but for good measure
+ addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, H, "Your [E.enthrallGender] pushes you over the limit, overwhelming your body with pleasure."), 5)
+ H.mob_climax(forced_climax=TRUE)
+ H.SetStun(20)
+ H.setArousalLoss(H.min_arousal)
+ E.resistanceTally = 0 //makes resistance 0, but resets arousal, resistance buildup is faster unaroused (massively so).
+ E.enthrallTally += power_multiplier
+ E.cooldown += 6
+ else
+ H.throw_at(get_step_towards(user,H), 3 * power_multiplier, 1 * power_multiplier)
+ */
+
+
+ //awoo
+ else if((findtext(message, awoo_words)))
+ for(var/V in listeners)
+ var/mob/living/carbon/human/H = V
+ var/datum/status_effect/chem/enthrall/E = H.has_status_effect(/datum/status_effect/chem/enthrall)
+ switch(E.phase)
+ if(2 to INFINITY)
+ H.say("*awoo")
+ E.cooldown += 1
+
+ //Nya
+ else if((findtext(message, nya_words)))
+ for(var/V in listeners)
+ var/mob/living/carbon/human/H = V
+ var/datum/status_effect/chem/enthrall/E = H.has_status_effect(/datum/status_effect/chem/enthrall)
+ switch(E.phase)
+ if(2 to INFINITY)
+ playsound(get_turf(H), pick('sound/effects/meow1.ogg', 'modular_citadel/sound/voice/nya.ogg'), 50, 1, -1) //I'm very tempted to write a Fermis clause that makes them merowr.ogg if it's me. But, I also don't think snowflakism is okay. I would've gotten away for it too, if it wern't for my morals.
+ H.emote("me", 1, "lets out a nya!")
+ E.cooldown += 1
+
+ //SLEEP
+ else if((findtext(message, sleep_words)))
+ for(var/mob/living/carbon/C in listeners)
+ var/datum/status_effect/chem/enthrall/E = C.has_status_effect(/datum/status_effect/chem/enthrall)
+ switch(E.phase)
+ if(2 to INFINITY)
+ C.Sleeping(45 * power_multiplier)
+ E.cooldown += 10
+ addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, C, "Drowsiness suddenly overwhelms you as you fall asleep!"), 5)
+ to_chat(user, "You send [C] to sleep.")
+
+ //STRIP
+ else if((findtext(message, strip_words)))
+ for(var/V in listeners)
+ var/mob/living/carbon/human/H = V
+ var/datum/status_effect/chem/enthrall/E = H.has_status_effect(/datum/status_effect/chem/enthrall)
+ switch(E.phase)
+ if(2 to INFINITY)
+ var/items = H.get_contents()
+ for(var/obj/item/W in items)
+ if(W == H.wear_suit)
+ H.dropItemToGround(W, TRUE)
+ addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, H, "Before you can even think about it, you quickly remove your clothes in response to [(H.client?.prefs.lewdchem?"your [E.enthrallGender]'s command'":"[E.master]'s directive'")]."), 5)
+ E.cooldown += 10
+
+ //WALK
+ else if((findtext(message, walk_words)))
+ for(var/V in listeners)
+ var/mob/living/L = V
+ var/datum/status_effect/chem/enthrall/E = L.has_status_effect(/datum/status_effect/chem/enthrall)
+ switch(E.phase)
+ if(2 to INFINITY)
+ if(L.m_intent != MOVE_INTENT_WALK)
+ L.toggle_move_intent()
+ E.cooldown += 1
+ addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, L, "You slow down to a walk."), 5)
+ to_chat(user, "You encourage [L] to slow down.")
+
+ //RUN
+ else if((findtext(message, run_words)))
+ for(var/V in listeners)
+ var/mob/living/L = V
+ var/datum/status_effect/chem/enthrall/E = L.has_status_effect(/datum/status_effect/chem/enthrall)
+ switch(E.phase)
+ if(2 to INFINITY)
+ if(L.m_intent != MOVE_INTENT_RUN)
+ L.toggle_move_intent()
+ E.cooldown += 1
+ addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, L, "You speed up into a jog!"), 5)
+ to_chat(user, "You encourage [L] to pick up the pace!")
+
+ //LIE DOWN
+ else if(findtext(message, liedown_words))
+ for(var/V in listeners)
+ var/mob/living/L = V
+ var/datum/status_effect/chem/enthrall/E = L.has_status_effect(/datum/status_effect/chem/enthrall)
+ switch(E.phase)
+ if(2 to INFINITY)
+ L.lay_down()
+ E.cooldown += 10
+ addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, L, "[(L.client?.prefs.lewdchem?"You eagerly lie down!":"You suddenly lie down!")]"), 5)
+ to_chat(user, "You encourage [L] to lie down.")
+
+ //KNOCKDOWN
+ else if(findtext(message, knockdown_words))
+ for(var/V in listeners)
+ var/mob/living/L = V
+ var/datum/status_effect/chem/enthrall/E = L.has_status_effect(/datum/status_effect/chem/enthrall)
+ switch(E.phase)
+ if(2 to INFINITY)
+ L.Knockdown(30 * power_multiplier * E.phase)
+ E.cooldown += 8
+ addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, L, "You suddenly drop to the ground!"), 5)
+ to_chat(user, "You encourage [L] to drop down to the ground.")
+
+ //tier3
+
+ //STATE TRIGGERS
+ else if((findtext(message, statecustom_words)))//doesn't work
+ for(var/V in listeners)
+ var/mob/living/carbon/C = V
+ var/datum/status_effect/chem/enthrall/E = C.has_status_effect(/datum/status_effect/chem/enthrall)
+ if (E.phase == 3)
+ var/speaktrigger = ""
+ C.emote("me", 1, "whispers something quietly.")
+ if (get_dist(user, C) > 1)//Requires user to be next to their pet.
+ to_chat(user, "You need to be next to your pet to hear them!")
+ continue
+ for (var/trigger in E.customTriggers)
+ speaktrigger += "[trigger], "
+ to_chat(user, "[C] whispers, \"[speaktrigger] are my triggers.\"")//So they don't trigger themselves!
+ addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, C, "You whisper your triggers to [(C.client?.prefs.lewdchem?"Your [E.enthrallGender]":"[E.master]")]."), 5)
+
+
+ //CUSTOM TRIGGERS
+ else if((findtext(message, custom_words)))
+ for(var/V in listeners)
+ var/mob/living/carbon/human/H = V
+ var/datum/status_effect/chem/enthrall/E = H.has_status_effect(/datum/status_effect/chem/enthrall)
+ if(E.phase == 3)
+ if (get_dist(user, H) > 1)//Requires user to be next to their pet.
+ to_chat(user, "You need to be next to your pet to give them a new trigger!")
+ continue
+ else
+ user.emote("me", 1, "puts their hands upon [H.name]'s head and looks deep into their eyes, whispering something to them.")
+ user.SetStun(1000)//Hands are handy, so you have to stay still
+ H.SetStun(1000)
+ if (E.mental_capacity >= 5)
+ var/trigger = html_decode(stripped_input(user, "Enter the trigger phrase", MAX_MESSAGE_LEN))
+ var/custom_words_words_list = list("Speak", "Echo", "Shock", "Cum", "Kneel", "Strip", "Trance", "Cancel")
+ var/trigger2 = input(user, "Pick an effect", "Effects") in custom_words_words_list
+ trigger2 = lowertext(trigger2)
+ if ((findtext(trigger2, custom_words_words)))
+ if (trigger2 == "speak" || trigger2 == "echo")
+ var/trigger3 = html_decode(stripped_input(user, "Enter the phrase spoken. Abusing this to self antag is bannable.", MAX_MESSAGE_LEN))
+ E.customTriggers[trigger] = list(trigger2, trigger3)
+ log_game("FERMICHEM: [H] has been implanted by [user] with [trigger], triggering [trigger2], to send [trigger3].")
+ if(findtext(trigger3, "admin"))
+ message_admins("FERMICHEM: [user] maybe be trying to abuse MKUltra by implanting by [H] with [trigger], triggering [trigger2], to send [trigger3].")
+ else
+ E.customTriggers[trigger] = trigger2
+ log_game("FERMICHEM: [H] has been implanted by [user] with [trigger], triggering [trigger2].")
+ E.mental_capacity -= 5
+ addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, H, "[(H.client?.prefs.lewdchem?"your [E.enthrallGender]":"[E.master]")] whispers you a new trigger."), 5)
+ to_chat(user, "You sucessfully set the trigger word [trigger] in [H]")
+ else
+ to_chat(user, "Your pet looks at you confused, it seems they don't understand that effect!")
+ else
+ to_chat(user, "Your pet looks at you with a vacant blase expression, you don't think you can program anything else into them")
+ user.SetStun(0)
+ H.SetStun(0)
+
+ //CUSTOM ECHO
+ else if((findtext(message, custom_echo)))
+ for(var/V in listeners)
+ var/mob/living/carbon/human/H = V
+ var/datum/status_effect/chem/enthrall/E = H.has_status_effect(/datum/status_effect/chem/enthrall)
+ if(E.phase == 3)
+ if (get_dist(user, H) > 1)//Requires user to be next to their pet.
+ to_chat(user, "You need to be next to your pet to give them a new echophrase!")
+ continue
+ else
+ user.emote("me", 1, "puts their hands upon [H.name]'s head and looks deep into their eyes, whispering something to them.")
+ user.SetStun(1000)//Hands are handy, so you have to stay still
+ H.SetStun(1000)
+ var/trigger = stripped_input(user, "Enter the loop phrase", MAX_MESSAGE_LEN)
+ var/customSpan = list("Notice", "Warning", "Hypnophrase", "Love", "Velvet")
+ var/trigger2 = input(user, "Pick the style", "Style") in customSpan
+ trigger2 = lowertext(trigger2)
+ E.customEcho = trigger
+ E.customSpan = trigger2
+ user.SetStun(0)
+ H.SetStun(0)
+ to_chat(user, "You sucessfully set an echoing phrase in [H]")
+
+ //CUSTOM OBJECTIVE
+ else if((findtext(message, objective_words)))
+ for(var/V in listeners)
+ var/mob/living/carbon/human/H = V
+ var/datum/status_effect/chem/enthrall/E = H.has_status_effect(/datum/status_effect/chem/enthrall)
+ if(E.phase == 3)
+ if (get_dist(user, H) > 1)//Requires user to be next to their pet.
+ to_chat(user, "You need to be next to your pet to give them a new objective!")
+ continue
+ else
+ user.emote("me", 1, "puts their hands upon [H.name]'s head and looks deep into their eyes, whispering something to them.'")
+ user.SetStun(1000)//So you can't run away!
+ H.SetStun(1000)
+ if (E.mental_capacity >= 200)
+ var/datum/objective/brainwashing/objective = stripped_input(user, "Add an objective to give your pet.", MAX_MESSAGE_LEN)
+ if(!LAZYLEN(objective))
+ to_chat(user, "You can't give your pet an objective to do nothing!")
+ continue
+ //Pets don't understand harm
+ objective = replacetext(lowertext(objective), "kill", "hug")
+ objective = replacetext(lowertext(objective), "murder", "cuddle")
+ objective = replacetext(lowertext(objective), "harm", "snuggle")
+ objective = replacetext(lowertext(objective), "decapitate", "headpat")
+ objective = replacetext(lowertext(objective), "strangle", "meow at")
+ objective = replacetext(lowertext(objective), "suicide", "self-love")
+ message_admins("[H] has been implanted by [user] with the objective [objective].")
+ log_game("FERMICHEM: [H] has been implanted by [user] with the objective [objective] via MKUltra.")
+ addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, H, "[(H.client?.prefs.lewdchem?"Your [E.enthrallGender]":"[E.master]")] whispers you a new objective."), 5)
+ brainwash(H, objective)
+ E.mental_capacity -= 200
+ to_chat(user, "You sucessfully give an objective to [H]")
+ else
+ to_chat(user, "Your pet looks at you with a vacant blasé expression, you don't think you can program anything else into them")
+ user.SetStun(0)
+ H.SetStun(0)
+
+ //INSTILL
+ else if((findtext(message, instill_words)))
+ for(var/V in listeners)
+ var/mob/living/carbon/human/H = V
+ var/datum/status_effect/chem/enthrall/E = H.has_status_effect(/datum/status_effect/chem/enthrall)
+ if(E.phase == 3 && H.client?.prefs.lewdchem)
+ var/instill = stripped_input(user, "Instill an emotion in your [(user.client?.prefs.lewdchem?"Your pet":"listener")].", MAX_MESSAGE_LEN)
+ to_chat(H, "[instill]")
+ to_chat(user, "You sucessfully instill a feeling in [H]")
+ log_game("FERMICHEM: [H] has been instilled by [user] with [instill] via MKUltra.")
+ E.cooldown += 1
+
+ //RECOGNISE
+ else if((findtext(message, recognise_words)))
+ for(var/V in listeners)
+ var/mob/living/carbon/human/H = V
+ var/datum/status_effect/chem/enthrall/E = H.has_status_effect(/datum/status_effect/chem/enthrall)
+ if(E.phase > 1)
+ if(user.ckey == E.enthrallID && user.real_name == E.master.real_name)
+ E.master = user
+ addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, H, "[(H.client?.prefs.lewdchem?"You hear the words of your [E.enthrallGender] again!! They're back!!":"You recognise the voice of [E.master].")]"), 5)
+ to_chat(user, "[H] looks at you with sparkling eyes, recognising you!")
+
+ //I dunno how to do state objectives without them revealing they're an antag
+
+ //HEAL (maybe make this nap instead?)
+ else if(findtext(message, heal_words))
+ for(var/V in listeners)
+ var/mob/living/L = V
+ var/datum/status_effect/chem/enthrall/E = L.has_status_effect(/datum/status_effect/chem/enthrall)
+ switch(E.phase)
+ if(3)//Tier 3 only
+ E.status = "heal"
+ E.statusStrength = (5 * power_multiplier)
+ E.cooldown += 5
+ addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, L, "You begin to lick your wounds."), 5)
+ L.Stun(15 * power_multiplier)
+ to_chat(user, "[L] begins to lick their wounds.")
+
+ //STUN
+ else if(findtext(message, stun_words))
+ for(var/V in listeners)
+ var/mob/living/L = V
+ var/datum/status_effect/chem/enthrall/E = L.has_status_effect(/datum/status_effect/chem/enthrall)
+ switch(E.phase)
+ if(3 to INFINITY)
+ L.Stun(40 * power_multiplier)
+ E.cooldown += 8
+ addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, L, "Your muscles freeze up!"), 5)
+ to_chat(user, "You cause [L] to freeze up!")
+
+ //HALLUCINATE
+ else if(findtext(message, hallucinate_words))
+ for(var/V in listeners)
+ var/mob/living/carbon/C = V
+ var/datum/status_effect/chem/enthrall/E = C.has_status_effect(/datum/status_effect/chem/enthrall)
+ switch(E.phase)
+ if(3 to INFINITY)
+ new /datum/hallucination/delusion(C, TRUE, null,150 * power_multiplier,0)
+ to_chat(user, "You send [C] on a trip.")
+
+ //HOT
+ else if(findtext(message, hot_words))
+ for(var/V in listeners)
+ var/mob/living/L = V
+ var/datum/status_effect/chem/enthrall/E = L.has_status_effect(/datum/status_effect/chem/enthrall)
+ switch(E.phase)
+ if(3 to INFINITY)
+ L.adjust_bodytemperature(50 * power_multiplier)//This seems nuts, reduced it, but then it didn't do anything, so I reverted it.
+ addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, L, "You feel your metabolism speed up!"), 5)
+ to_chat(user, "You speed [L]'s metabolism up!")
+
+ //COLD
+ else if(findtext(message, cold_words))
+ for(var/V in listeners)
+ var/mob/living/L = V
+ var/datum/status_effect/chem/enthrall/E = L.has_status_effect(/datum/status_effect/chem/enthrall)
+ switch(E.phase)
+ if(3 to INFINITY)
+ L.adjust_bodytemperature(-50 * power_multiplier)
+ addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, L, "You feel your metabolism slow down!"), 5)
+ to_chat(user, "You slow [L]'s metabolism down!")
+
+ //GET UP
+ else if(findtext(message, getup_words))
+ for(var/V in listeners)
+ var/mob/living/L = V
+ var/datum/status_effect/chem/enthrall/E = L.has_status_effect(/datum/status_effect/chem/enthrall)
+ switch(E.phase)
+ if(3 to INFINITY)//Tier 3 only
+ if(L.resting)
+ L.lay_down() //aka get up
+ L.SetStun(0)
+ L.SetKnockdown(0)
+ L.SetUnconscious(0) //i said get up i don't care if you're being tased
+ E.cooldown += 10 //This could be really strong
+ addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, L, "You jump to your feet from sheer willpower!"), 5)
+ to_chat(user, "You spur [L] to their feet!")
+
+ //PACIFY
+ else if(findtext(message, pacify_words))
+ for(var/V in listeners)
+ var/mob/living/L = V
+ var/datum/status_effect/chem/enthrall/E = L.has_status_effect(/datum/status_effect/chem/enthrall)
+ switch(E.phase)
+ if(3)//Tier 3 only
+ E.status = "pacify"
+ E.cooldown += 10
+ addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, L, "You feel like never hurting anyone ever again."), 5)
+ to_chat(user, "You remove any intent to harm from [L]'s mind.")
+
+ //CHARGE
+ else if(findtext(message, charge_words))
+ for(var/V in listeners)
+ var/mob/living/L = V
+ var/datum/status_effect/chem/enthrall/E = L.has_status_effect(/datum/status_effect/chem/enthrall)
+ switch(E.phase)
+ if(3)//Tier 3 only
+ E.statusStrength = 2* power_multiplier
+ E.status = "charge"
+ E.cooldown += 10
+ to_chat(user, "You rally [L], leading them into a charge!")
+
+ if(message_admins || debug)//Do you want this in?
+ message_admins("[ADMIN_LOOKUPFLW(user)] has said '[log_message]' with a Velvet Voice, affecting [english_list(listeners)], with a power multiplier of [power_multiplier].")
+ log_game("FERMICHEM: [key_name(user)] ckey: [user.key] has said '[log_message]' with a Velvet Voice, affecting [english_list(listeners)], with a power multiplier of [power_multiplier].")
+ SSblackbox.record_feedback("tally", "fermi_chem", 1, "Times people have spoken with a velvet voice")
+ //SSblackbox.record_feedback("tally", "Velvet_voice", 1, log_message) If this is on, it fills the thing up and OOFs the server
+
+ return
+
#undef COOLDOWN_STUN
#undef COOLDOWN_DAMAGE
diff --git a/code/modules/surgery/plastic_surgery.dm b/code/modules/surgery/plastic_surgery.dm
index 54482ade73..39077ae235 100644
--- a/code/modules/surgery/plastic_surgery.dm
+++ b/code/modules/surgery/plastic_surgery.dm
@@ -1,8 +1,7 @@
/datum/surgery/plastic_surgery
- name = "plastic surgery"
+ name = "Plastic surgery"
steps = list(/datum/surgery_step/incise, /datum/surgery_step/retract_skin, /datum/surgery_step/reshape_face, /datum/surgery_step/close)
possible_locs = list(BODY_ZONE_HEAD)
-
//reshape_face
/datum/surgery_step/reshape_face
name = "reshape face"
@@ -10,12 +9,16 @@
time = 64
/datum/surgery_step/reshape_face/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
- user.visible_message("[user] begins to alter [target]'s appearance.", "You begin to alter [target]'s appearance...")
+ display_results(user, target, "You begin to alter [target]'s appearance...",
+ "[user] begins to alter [target]'s appearance.",
+ "[user] begins to make an incision in [target]'s face.")
/datum/surgery_step/reshape_face/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
if(HAS_TRAIT_FROM(target, TRAIT_DISFIGURED, TRAIT_GENERIC))
REMOVE_TRAIT(target, TRAIT_DISFIGURED, TRAIT_GENERIC)
- user.visible_message("[user] successfully restores [target]'s appearance!", "You successfully restore [target]'s appearance.")
+ display_results(user, target, "You successfully restore [target]'s appearance.",
+ "[user] successfully restores [target]'s appearance!",
+ "[user] finishes the operation on [target]'s face.")
else
var/list/names = list()
if(!isabductor(user))
@@ -31,8 +34,18 @@
var/oldname = target.real_name
target.real_name = chosen_name
var/newname = target.real_name //something about how the code handles names required that I use this instead of target.real_name
- user.visible_message("[user] alters [oldname]'s appearance completely, [target.p_they()] is now [newname]!", "You alter [oldname]'s appearance completely, [target.p_they()] is now [newname].")
+ display_results(user, target, "You alter [oldname]'s appearance completely, [target.p_they()] is now [newname].",
+ "[user] alters [oldname]'s appearance completely, [target.p_they()] is now [newname]!",
+ "[user] finishes the operation on [target]'s face.")
if(ishuman(target))
var/mob/living/carbon/human/H = target
H.sec_hud_set_ID()
return 1
+ return TRUE
+
+/datum/surgery_step/reshape_face/failure(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
+ display_results(user, target, "You screw up, leaving [target]'s appearance disfigured!",
+ "[user] screws up, disfiguring [target]'s appearance!",
+ "[user] finishes the operation on [target]'s face.")
+ ADD_TRAIT(target, TRAIT_DISFIGURED, TRAIT_GENERIC)
+ return FALSE
diff --git a/code/modules/surgery/prosthetic_replacement.dm b/code/modules/surgery/prosthetic_replacement.dm
index 9032964ae4..fdceb1fb1f 100644
--- a/code/modules/surgery/prosthetic_replacement.dm
+++ b/code/modules/surgery/prosthetic_replacement.dm
@@ -1,26 +1,21 @@
/datum/surgery/prosthetic_replacement
- name = "prosthetic replacement"
+ name = "Prosthetic replacement"
steps = list(/datum/surgery_step/incise, /datum/surgery_step/clamp_bleeders, /datum/surgery_step/retract_skin, /datum/surgery_step/add_prosthetic)
species = list(/mob/living/carbon/human, /mob/living/carbon/monkey)
possible_locs = list(BODY_ZONE_R_ARM, BODY_ZONE_L_ARM, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG, BODY_ZONE_HEAD)
requires_bodypart = FALSE //need a missing limb
requires_bodypart_type = 0
-
/datum/surgery/prosthetic_replacement/can_start(mob/user, mob/living/carbon/target)
if(!iscarbon(target))
return 0
var/mob/living/carbon/C = target
if(!C.get_bodypart(user.zone_selected)) //can only start if limb is missing
return 1
-
-
-
/datum/surgery_step/add_prosthetic
name = "add prosthetic"
implements = list(/obj/item/bodypart = 100, /obj/item/organ_storage = 100, /obj/item/twohanded/required/chainsaw = 100, /obj/item/melee/synthetic_arm_blade = 100)
time = 32
var/organ_rejection_dam = 0
-
/datum/surgery_step/add_prosthetic/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
if(istype(tool, /obj/item/organ_storage))
if(!tool.contents.len)
@@ -48,16 +43,19 @@
organ_rejection_dam = 30
if(target_zone == BP.body_zone) //so we can't replace a leg with an arm, or a human arm with a monkey arm.
- user.visible_message("[user] begins to replace [target]'s [parse_zone(target_zone)].", "You begin to replace [target]'s [parse_zone(target_zone)]...")
+ display_results(user, target, "You begin to replace [target]'s [parse_zone(target_zone)] with [tool]...",
+ "[user] begins to replace [target]'s [parse_zone(target_zone)] with [tool].",
+ "[user] begins to replace [target]'s [parse_zone(target_zone)].")
else
to_chat(user, "[tool] isn't the right type for [parse_zone(target_zone)].")
return -1
else if(target_zone == BODY_ZONE_L_ARM || target_zone == BODY_ZONE_R_ARM)
- user.visible_message("[user] begins to attach [tool] onto [target].", "You begin to attach [tool] onto [target]...")
+ display_results(user, target, "You begin to attach [tool] onto [target]...",
+ "[user] begins to attach [tool] onto [target]'s [parse_zone(target_zone)].",
+ "[user] begins to attach something onto [target]'s [parse_zone(target_zone)].")
else
to_chat(user, "[tool] must be installed onto an arm.")
return -1
-
/datum/surgery_step/add_prosthetic/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
if(istype(tool, /obj/item/organ_storage))
tool.icon_state = initial(tool.icon_state)
@@ -69,13 +67,17 @@
L.attach_limb(target)
if(organ_rejection_dam)
target.adjustToxLoss(organ_rejection_dam)
- user.visible_message("[user] successfully replaces [target]'s [parse_zone(target_zone)]!", "You succeed in replacing [target]'s [parse_zone(target_zone)].")
+ display_results(user, target, "You succeed in replacing [target]'s [parse_zone(target_zone)].",
+ "[user] successfully replaces [target]'s [parse_zone(target_zone)] with [tool]!",
+ "[user] successfully replaces [target]'s [parse_zone(target_zone)]!")
return 1
else
var/obj/item/bodypart/L = target.newBodyPart(target_zone, FALSE, FALSE)
L.is_pseudopart = TRUE
L.attach_limb(target)
- user.visible_message("[user] finishes attaching [tool]!", "You attach [tool].")
+ display_results(user, target, "You attach [tool].",
+ "[user] finishes attaching [tool]!",
+ "[user] finishes the attachment procedure!")
qdel(tool)
if(istype(tool, /obj/item/twohanded/required/chainsaw))
var/obj/item/mounted_chainsaw/new_arm = new(target)
@@ -85,4 +87,3 @@
var/obj/item/melee/arm_blade/new_arm = new(target,TRUE,TRUE)
target_zone == BODY_ZONE_R_ARM ? target.put_in_r_hand(new_arm) : target.put_in_l_hand(new_arm)
return 1
-
diff --git a/code/modules/surgery/remove_embedded_object.dm b/code/modules/surgery/remove_embedded_object.dm
index 451ae02dac..0c3a3b55a5 100644
--- a/code/modules/surgery/remove_embedded_object.dm
+++ b/code/modules/surgery/remove_embedded_object.dm
@@ -2,23 +2,20 @@
name = "removal of embedded objects"
steps = list(/datum/surgery_step/incise, /datum/surgery_step/clamp_bleeders, /datum/surgery_step/retract_skin, /datum/surgery_step/remove_object)
possible_locs = list(BODY_ZONE_R_ARM,BODY_ZONE_L_ARM,BODY_ZONE_R_LEG,BODY_ZONE_L_LEG,BODY_ZONE_CHEST,BODY_ZONE_HEAD)
-
-
/datum/surgery_step/remove_object
name = "remove embedded objects"
time = 32
accept_hand = 1
var/obj/item/bodypart/L = null
-
-
/datum/surgery_step/remove_object/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
L = surgery.operated_bodypart
if(L)
- user.visible_message("[user] looks for objects embedded in [target]'s [parse_zone(user.zone_selected)].", "You look for objects embedded in [target]'s [parse_zone(user.zone_selected)]...")
+ display_results(user, target, "You look for objects embedded in [target]'s [parse_zone(user.zone_selected)]...",
+ "[user] looks for objects embedded in [target]'s [parse_zone(user.zone_selected)].",
+ "[user] looks for something in [target]'s [parse_zone(user.zone_selected)].")
else
user.visible_message("[user] looks for [target]'s [parse_zone(user.zone_selected)].", "You look for [target]'s [parse_zone(user.zone_selected)]...")
-
/datum/surgery_step/remove_object/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
if(L)
if(ishuman(target))
@@ -33,11 +30,12 @@
SEND_SIGNAL(H, COMSIG_CLEAR_MOOD_EVENT, "embedded")
if(objects > 0)
- user.visible_message("[user] successfully removes [objects] objects from [H]'s [L]!", "You successfully remove [objects] objects from [H]'s [L.name].")
+ display_results(user, target, "You successfully remove [objects] objects from [H]'s [L.name].",
+ "[user] successfully removes [objects] objects from [H]'s [L]!",
+ "[user] successfully removes [objects] objects from [H]'s [L]!")
else
to_chat(user, "You find no objects embedded in [H]'s [L]!")
else
to_chat(user, "You can't find [target]'s [parse_zone(user.zone_selected)], let alone any objects embedded in it!")
-
return 1
diff --git a/code/modules/surgery/surgery_step.dm b/code/modules/surgery/surgery_step.dm
index f670b80167..c5a944fbb2 100644
--- a/code/modules/surgery/surgery_step.dm
+++ b/code/modules/surgery/surgery_step.dm
@@ -2,13 +2,12 @@
var/name
var/list/implements = list() //format is path = probability of success. alternatively
var/implement_type = null //the current type of implement used. This has to be stored, as the actual typepath of the tool may not match the list type.
- var/accept_hand = 0 //does the surgery step require an open hand? If true, ignores implements. Compatible with accept_any_item.
- var/accept_any_item = 0 //does the surgery step accept any item? If true, ignores implements. Compatible with require_hand.
+ var/accept_hand = FALSE //does the surgery step require an open hand? If true, ignores implements. Compatible with accept_any_item.
+ var/accept_any_item = FALSE //does the surgery step accept any item? If true, ignores implements. Compatible with require_hand.
var/time = 10 //how long does the step take?
- var/repeatable = 0 //can this step be repeated? Make shure it isn't last step, or it used in surgery with `can_cancel = 1`. Or surgion will be stuck in the loop
+ var/repeatable = FALSE //can this step be repeated? Make shure it isn't last step, or it used in surgery with `can_cancel = 1`. Or surgion will be stuck in the loop
var/list/chems_needed = list() //list of chems needed to complete the step. Even on success, the step will have no effect if there aren't the chems required in the mob.
var/require_all_chems = TRUE //any on the list or all on the list?
-
/datum/surgery_step/proc/try_op(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery, try_to_fail = FALSE)
var/success = FALSE
if(accept_hand)
@@ -16,104 +15,87 @@
success = TRUE
if(iscyborg(user))
success = TRUE
-
if(accept_any_item)
if(tool && tool_check(user, tool))
success = TRUE
-
else if(tool)
for(var/key in implements)
var/match = FALSE
-
if(ispath(key) && istype(tool, key))
match = TRUE
else if(tool.tool_behaviour == key)
match = TRUE
-
if(match)
implement_type = key
if(tool_check(user, tool))
success = TRUE
break
-
if(success)
if(target_zone == surgery.location)
if(get_location_accessible(target, target_zone) || surgery.ignore_clothes)
- initiate(user, target, target_zone, tool, surgery, try_to_fail)
- return 1
+ return initiate(user, target, target_zone, tool, surgery, try_to_fail)
else
to_chat(user, "You need to expose [target]'s [parse_zone(target_zone)] to perform surgery on it!")
- return 1 //returns 1 so we don't stab the guy in the dick or wherever.
-
+ return TRUE //returns TRUE so we don't stab the guy in the dick or wherever.
if(repeatable)
var/datum/surgery_step/next_step = surgery.get_surgery_next_step()
if(next_step)
surgery.status++
if(next_step.try_op(user, target, user.zone_selected, user.get_active_held_item(), surgery))
- return 1
+ return TRUE
else
surgery.status--
-
- if(iscyborg(user) && user.a_intent != INTENT_HARM) //to save asimov borgs a LOT of heartache
- return 1
-
- return 0
-
-
+ return FALSE
/datum/surgery_step/proc/initiate(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery, try_to_fail = FALSE)
- surgery.step_in_progress = 1
-
+ surgery.step_in_progress = TRUE
var/speed_mod = 1
-
+ var/advance = FALSE
if(preop(user, target, target_zone, tool, surgery) == -1)
- surgery.step_in_progress = 0
- return
-
+ surgery.step_in_progress = FALSE
+ return FALSE
if(tool)
speed_mod = tool.toolspeed
-
if(do_after(user, time * speed_mod, target = target))
- var/advance = 0
var/prob_chance = 100
-
if(implement_type) //this means it isn't a require hand or any item step.
prob_chance = implements[implement_type]
prob_chance *= surgery.get_propability_multiplier()
-
if((prob(prob_chance) || iscyborg(user)) && chem_check(target) && !try_to_fail)
if(success(user, target, target_zone, tool, surgery))
- advance = 1
+ advance = TRUE
else
if(failure(user, target, target_zone, tool, surgery))
- advance = 1
-
+ advance = TRUE
if(advance && !repeatable)
surgery.status++
if(surgery.status > surgery.steps.len)
surgery.complete()
-
- surgery.step_in_progress = 0
+ surgery.step_in_progress = FALSE
+ return advance
/datum/surgery_step/proc/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
- user.visible_message("[user] begins to perform surgery on [target].", "You begin to perform surgery on [target]...")
-
+ display_results(user, target, "You begin to perform surgery on [target]...",
+ "[user] begins to perform surgery on [target].",
+ "[user] begins to perform surgery on [target].")
/datum/surgery_step/proc/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
- user.visible_message("[user] succeeds!", "You succeed.")
- return 1
+ display_results(user, target, "You succeed.",
+ "[user] succeeds!",
+ "[user] finishes.")
+ return TRUE
/datum/surgery_step/proc/failure(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
- user.visible_message("[user] screws up!", "You screw up!")
- return 0
+ display_results(user, target, "You screw up!",
+ "[user] screws up!",
+ "[user] finishes.", TRUE) //By default the patient will notice if the wrong thing has been cut
+ return FALSE
/datum/surgery_step/proc/tool_check(mob/user, obj/item/tool)
- return 1
-
+ return TRUE
/datum/surgery_step/proc/chem_check(mob/living/carbon/target)
if(!LAZYLEN(chems_needed))
return TRUE
-
if(require_all_chems)
. = TRUE
for(var/R in chems_needed)
@@ -124,7 +106,6 @@
for(var/R in chems_needed)
if(target.reagents.has_reagent(R))
return TRUE
-
/datum/surgery_step/proc/get_chem_list()
if(!LAZYLEN(chems_needed))
return
@@ -135,3 +116,11 @@
var/chemname = temp.name
chems += chemname
return english_list(chems, and_text = require_all_chems ? " and " : " or ")
+
+//Replaces visible_message during operations so only people looking over the surgeon can tell what they're doing, allowing for shenanigans.
+/datum/surgery_step/proc/display_results(mob/user, mob/living/carbon/target, self_message, detailed_message, vague_message, target_detailed = FALSE)
+ var/list/detailed_mobs = get_hearers_in_view(1, user) //Only the surgeon and people looking over his shoulder can see the operation clearly
+ if(!target_detailed)
+ detailed_mobs -= target //The patient can't see well what's going on, unless it's something like getting cut
+ user.visible_message(detailed_message, self_message, vision_distance = 1, ignored_mobs = target_detailed ? null : target)
+ user.visible_message(vague_message, "", ignored_mobs = detailed_mobs)
diff --git a/code/modules/uplink/uplink_items.dm b/code/modules/uplink/uplink_items.dm
index 13dcf5a12b..781fdb24f5 100644
--- a/code/modules/uplink/uplink_items.dm
+++ b/code/modules/uplink/uplink_items.dm
@@ -290,6 +290,22 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
/datum/uplink_item/dangerous
category = "Conspicuous and Dangerous Weapons"
+/datum/uplink_item/dangerous/pistol
+ name = "Stechkin Pistol"
+ desc = "A small, easily concealable handgun that uses 10mm auto rounds in 8-round magazines and is compatible \
+ with suppressors."
+ item = /obj/item/gun/ballistic/automatic/pistol
+ cost = 7
+ exclude_modes = list(/datum/game_mode/nuclear/clown_ops)
+
+/datum/uplink_item/dangerous/revolver
+ name = "Syndicate Revolver"
+ desc = "A brutally simple syndicate revolver that fires .357 Magnum rounds and has 7 chambers."
+ item = /obj/item/gun/ballistic/revolver/syndie
+ cost = 13
+ surplus = 50
+ exclude_modes = list(/datum/game_mode/nuclear/clown_ops)
+
/datum/uplink_item/dangerous/rawketlawnchair
name = "84mm Rocket Propelled Grenade Launcher"
desc = "A reusable rocket propelled grenade launcher preloaded with a low-yield 84mm HE round. \
@@ -414,8 +430,8 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
/datum/uplink_item/dangerous/rapier
name = "Rapier"
desc = "A fancy rapier with a diamond tip piercing anything that it comes into contack with. \
- The rapier comes with its own shielf, this is rather noticeable as only the captain is known to carry a shielf. \
- The shielf itself can be used to block melee attacks only. Its also jet black colours."
+ The rapier comes with its own sheath, this is rather noticeable as only the captain is known to carry a sheath. \
+ The sheath itself can be used to block melee attacks only. Its also jet black colours."
item = /obj/item/storage/belt/sabre/rapier
cost = 8
exclude_modes = list(/datum/game_mode/nuclear/clown_ops)
@@ -494,14 +510,6 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
surplus = 25
include_modes = list(/datum/game_mode/nuclear)
-/datum/uplink_item/dangerous/pistol
- name = "Stechkin Pistol"
- desc = "A small, easily concealable handgun that uses 10mm auto rounds in 8-round magazines and is compatible \
- with suppressors."
- item = /obj/item/gun/ballistic/automatic/pistol
- cost = 7
- exclude_modes = list(/datum/game_mode/nuclear/clown_ops)
-
/datum/uplink_item/dangerous/bolt_action
name = "Surplus Rifle"
desc = "A horribly outdated bolt action weapon. You've got to be desperate to use this."
@@ -509,14 +517,6 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
cost = 2
include_modes = list(/datum/game_mode/nuclear)
-/datum/uplink_item/dangerous/revolver
- name = "Syndicate Revolver"
- desc = "A brutally simple Syndicate revolver that fires .357 Magnum rounds and has 7 chambers."
- item = /obj/item/gun/ballistic/revolver/syndie
- cost = 13
- surplus = 50
- exclude_modes = list(/datum/game_mode/nuclear/clown_ops)
-
/datum/uplink_item/dangerous/foamsmg
name = "Toy Submachine Gun"
desc = "A fully-loaded Donksoft bullpup submachine gun that fires riot grade darts with a 20-round magazine."
@@ -563,6 +563,12 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
cost = 13
surplus = 0
+/datum/uplink_item/dangerous/phantomthief
+ name = "Syndicate Mask"
+ desc = "A cheap plastic mask fitted with an adrenaline autoinjector, which can be used by simply tensing your muscles"
+ item = /obj/item/clothing/glasses/phantomthief/syndicate
+ cost = 2
+
/datum/uplink_item/stealthy_weapons/dart_pistol
name = "Dart Pistol"
desc = "A miniaturized version of a normal syringe gun. It is very quiet when fired and can fit into any \
@@ -1263,9 +1269,44 @@ datum/uplink_item/stealthy_weapons/taeclowndo_shoes
//Space Suits and Hardsuits
/datum/uplink_item/suits
- category = "Space Suits and Hardsuits"
+ category = "Space Suits, Hardsuits and Clothing"
surplus = 40
+/datum/uplink_item/suits/turtlenck
+ name = "Tactical Turtleneck"
+ desc = "A slightly armored suit that has no sensor on them, if someone sees you in this hope they think its a fake."
+ item = /obj/item/clothing/under/syndicate
+ cost = 1
+ exclude_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops) //They already get these
+
+/datum/uplink_item/suits/turtlenck_skirt
+ name = "Tactical Skirtleneck"
+ desc = "A slightly armored suit that has no sensor on them, if someone sees you in this hope they think its a fake."
+ item = /obj/item/clothing/under/syndicate/skirt
+ cost = 1
+ exclude_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops) //They already get these
+
+/datum/uplink_item/suits/padding
+ name = "Soft Padding"
+ desc = "Padding to add to a jumpsuit to help against melee and bullets."
+ item = /obj/item/clothing/accessory/padding
+ cost = 2
+ exclude_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops)
+
+/datum/uplink_item/suits/kevlar
+ name = "Kevlar sheets"
+ desc = "Kevlar sheets to add to jumpsuit to help against bullets and melee."
+ item = /obj/item/clothing/accessory/kevlar
+ cost = 2
+ exclude_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops)
+
+/datum/uplink_item/suits/plastic
+ name = "Plastic sheet"
+ desc = "Plastic body sheet to add to a jumpsuit to help against laser and energy harm."
+ item = /obj/item/clothing/accessory/plastics
+ cost = 2
+ exclude_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops)
+
/datum/uplink_item/suits/space_suit
name = "Syndicate Space Suit"
desc = "This red and black Syndicate space suit is less encumbering than Nanotrasen variants, \
@@ -1307,6 +1348,19 @@ datum/uplink_item/stealthy_weapons/taeclowndo_shoes
/datum/uplink_item/device_tools
category = "Devices and Tools"
+/datum/uplink_item/device_tools/emag
+ name = "Cryptographic Sequencer"
+ desc = "The cryptographic sequencer, electromagnetic card, or emag, is a small card that unlocks hidden functions \
+ in electronic devices, subverts intended functions, and easily breaks security mechanisms."
+ item = /obj/item/card/emag
+ cost = 6
+
+/datum/uplink_item/device_tools/emagrecharge
+ name = "Electromagnet Charging Device"
+ desc = "A small device intended for recharging Cryptographic Sequencers. Using it will add five extra charges to the Cryptographic Sequencer."
+ item = /obj/item/emagrecharge
+ cost = 2
+
/datum/uplink_item/device_tools/cutouts
name = "Adaptive Cardboard Cutouts"
desc = "These cardboard cutouts are coated with a thin material that prevents discoloration and makes the images on them appear more lifelike. \
@@ -1375,19 +1429,6 @@ datum/uplink_item/stealthy_weapons/taeclowndo_shoes
cost = 1
exclude_modes = list(/datum/game_mode/nuclear)
-/datum/uplink_item/device_tools/emag
- name = "Cryptographic Sequencer"
- desc = "The cryptographic sequencer, electromagnetic card, or emag, is a small card that unlocks hidden functions \
- in electronic devices, subverts intended functions, and easily breaks security mechanisms."
- item = /obj/item/card/emag
- cost = 6
-
-/datum/uplink_item/device_tools/emagrecharge
- name = "Electromagnet Charging Device"
- desc = "A small device intended for recharging Cryptographic Sequencers. Using it will add five extra charges to the Cryptographic Sequencer."
- item = /obj/item/emagrecharge
- cost = 2
-
/datum/uplink_item/device_tools/fakenucleardisk
name = "Decoy Nuclear Authentication Disk"
desc = "It's just a normal disk. Visually it's identical to the real deal, but it won't hold up under closer scrutiny by the Captain. \
@@ -1418,6 +1459,7 @@ datum/uplink_item/stealthy_weapons/taeclowndo_shoes
desc = "A cheap bottle of one use syndicate brand super glue. \
Use on any item to make it undroppable. \
Be careful not to glue an item you're already holding!"
+ exclude_modes = list(/datum/game_mode/nuclear, /datum/game_mode/nuclear/clown_ops)
item = /obj/item/syndie_glue
cost = 2
@@ -1837,6 +1879,13 @@ datum/uplink_item/stealthy_weapons/taeclowndo_shoes
item = /obj/item/clothing/shoes/clown_shoes/taeclowndo
restricted_roles = list("Clown")
+/datum/uplink_item/role_restricted/emitter_cannon
+ name = "Emitter Cannon"
+ desc = "A small emitter fitted into a gun case, do to size constraints and safety it can only shoot about ten times when fully charged."
+ cost = 5 //Low ammo, and deals same as 10mm but emp-able
+ item = /obj/item/gun/energy/emitter
+ restricted_roles = list("Chief Engineer", "Station Engineer", "Atmospheric Technician")
+
// Pointless
/datum/uplink_item/badass
category = "(Pointless) Badassery"
diff --git a/code/modules/vending/autodrobe.dm b/code/modules/vending/autodrobe.dm
index 5cfa454bd9..a265a4e907 100644
--- a/code/modules/vending/autodrobe.dm
+++ b/code/modules/vending/autodrobe.dm
@@ -63,6 +63,8 @@
/obj/item/clothing/suit/wizrobe/fake = 1,
/obj/item/clothing/head/wizard/fake = 1,
/obj/item/staff = 3,
+ /obj/item/clothing/under/rank/mime/skirt = 1,
+ /obj/item/clothing/under/gimmick/rank/captain/suit/skirt = 1,
/obj/item/clothing/mask/gas/sexyclown = 1,
/obj/item/clothing/under/rank/clown/sexy = 1,
/obj/item/clothing/mask/gas/sexymime = 1,
diff --git a/code/modules/vending/clothesmate.dm b/code/modules/vending/clothesmate.dm
index c31c9a12a2..1497992fe8 100644
--- a/code/modules/vending/clothesmate.dm
+++ b/code/modules/vending/clothesmate.dm
@@ -31,6 +31,9 @@
/obj/item/clothing/under/pants/tan = 4,
/obj/item/clothing/under/pants/track = 3,
/obj/item/clothing/suit/jacket/miljacket = 5,
+ /obj/item/clothing/under/scratch/skirt = 2,
+ /obj/item/clothing/under/gimmick/rank/captain/suit/skirt = 2,
+ /obj/item/clothing/under/gimmick/rank/head_of_personnel/suit/skirt = 2,
/obj/item/clothing/neck/tie/blue = 3,
/obj/item/clothing/neck/tie/red = 3,
/obj/item/clothing/neck/tie/black = 3,
@@ -98,6 +101,7 @@
/obj/item/clothing/suit/apron/purple_bartender = 4,
/obj/item/clothing/under/rank/bartender/purple = 4)
contraband = list(/obj/item/clothing/under/syndicate/tacticool = 3,
+ /obj/item/clothing/under/syndicate/tacticool/skirt = 3,
/obj/item/clothing/mask/balaclava = 3,
/obj/item/clothing/head/ushanka = 3,
/obj/item/clothing/under/soviet = 3,
diff --git a/code/modules/vending/medical.dm b/code/modules/vending/medical.dm
index 523606aa6a..44dca6b257 100644
--- a/code/modules/vending/medical.dm
+++ b/code/modules/vending/medical.dm
@@ -28,7 +28,9 @@
contraband = list(/obj/item/reagent_containers/pill/tox = 3,
/obj/item/reagent_containers/pill/morphine = 4,
/obj/item/reagent_containers/pill/charcoal = 6)
- premium = list(/obj/item/storage/box/hug/medical = 1,
+ premium = list(/obj/item/reagent_containers/medspray/synthflesh = 2,
+ /obj/item/storage/box/hug/medical = 1,
+ /obj/item/storage/pill_bottle/psicodine = 2,
/obj/item/reagent_containers/hypospray/medipen = 3,
/obj/item/storage/belt/medical = 3,
/obj/item/wrench/medical = 1,
diff --git a/code/modules/vending/megaseed.dm b/code/modules/vending/megaseed.dm
index 4594048256..b1b69a8cd2 100644
--- a/code/modules/vending/megaseed.dm
+++ b/code/modules/vending/megaseed.dm
@@ -15,6 +15,7 @@
/obj/item/seeds/chili = 3,
/obj/item/seeds/cocoapod = 3,
/obj/item/seeds/coffee = 3,
+ /obj/item/seeds/cotton = 3,
/obj/item/seeds/corn = 3,
/obj/item/seeds/eggplant = 3,
/obj/item/seeds/grape = 3,
@@ -31,7 +32,9 @@
/obj/item/seeds/replicapod = 3,
/obj/item/seeds/wheat/rice = 3,
/obj/item/seeds/soya = 3,
+ /obj/item/seeds/sugarcane = 3,
/obj/item/seeds/sunflower = 3,
+ /obj/item/seeds/strawberry = 3,
/obj/item/seeds/tea = 3,
/obj/item/seeds/tobacco = 3,
/obj/item/seeds/tomato = 3,
diff --git a/code/modules/vending/security.dm b/code/modules/vending/security.dm
index aaa1cf3b6f..b3b21fe375 100644
--- a/code/modules/vending/security.dm
+++ b/code/modules/vending/security.dm
@@ -12,7 +12,8 @@
/obj/item/reagent_containers/food/snacks/donut = 12,
/obj/item/storage/box/evidence = 6,
/obj/item/flashlight/seclite = 4,
- /obj/item/restraints/legcuffs/bola/energy = 7)
+ /obj/item/restraints/legcuffs/bola/energy = 7,
+ /obj/item/secbat = 5)
contraband = list(/obj/item/clothing/glasses/sunglasses = 2,
/obj/item/storage/fancy/donut_box = 2,
/obj/item/ssword_kit = 1)
diff --git a/code/modules/vending/wardrobes.dm b/code/modules/vending/wardrobes.dm
index 9481d4d086..08ed655297 100644
--- a/code/modules/vending/wardrobes.dm
+++ b/code/modules/vending/wardrobes.dm
@@ -40,6 +40,7 @@
/obj/item/clothing/suit/hooded/wintercoat/medical = 3,
/obj/item/clothing/under/rank/nursesuit = 3,
/obj/item/clothing/head/nursehat = 3,
+ /obj/item/clothing/under/rank/medical/skirt= 5,
/obj/item/clothing/under/rank/medical/blue = 2,
/obj/item/clothing/under/rank/medical/green = 2,
/obj/item/clothing/under/rank/medical/purple = 2,
@@ -67,6 +68,7 @@
/obj/item/storage/backpack/satchel/eng = 3,
/obj/item/clothing/suit/hooded/wintercoat/engineering = 3,
/obj/item/clothing/under/rank/engineer = 5,
+ /obj/item/clothing/under/rank/engineer/skirt = 5,
/obj/item/clothing/suit/hazardvest = 5,
/obj/item/clothing/shoes/workboots = 5,
/obj/item/clothing/head/hardhat = 5)
@@ -87,6 +89,7 @@
/obj/item/storage/backpack/industrial = 3,
/obj/item/clothing/suit/hooded/wintercoat/engineering/atmos = 5,
/obj/item/clothing/under/rank/atmospheric_technician = 5,
+ /obj/item/clothing/under/rank/atmospheric_technician/skirt = 5,
/obj/item/clothing/shoes/sneakers/black = 5)
refill_canister = /obj/item/vending_refill/wardrobe/atmos_wardrobe
@@ -101,6 +104,7 @@
vend_reply = "Thank you for using the CargoDrobe!"
products = list(/obj/item/clothing/suit/hooded/wintercoat/cargo = 3,
/obj/item/clothing/under/rank/cargotech = 5,
+ /obj/item/clothing/under/rank/cargotech/skirt = 5,
/obj/item/clothing/shoes/sneakers/black = 5,
/obj/item/clothing/gloves/fingerless = 5,
/obj/item/clothing/head/soft = 5,
@@ -118,12 +122,14 @@
vend_reply = "Thank you for using the RoboDrobe!"
products = list(/obj/item/clothing/glasses/hud/diagnostic = 3,
/obj/item/clothing/under/rank/roboticist = 3,
+ /obj/item/clothing/under/rank/roboticist/skirt = 3,
/obj/item/clothing/suit/toggle/labcoat = 3,
/obj/item/clothing/shoes/sneakers/black = 3,
/obj/item/clothing/gloves/fingerless = 3,
/obj/item/clothing/head/soft/black = 3,
/obj/item/clothing/mask/bandana/skull = 2)
premium = list(/obj/item/radio/headset/headset_rob = 2) //Cit change
+ contraband = list(/obj/item/clothing/suit/hooded/techpriest = 2)
refill_canister = /obj/item/vending_refill/wardrobe/robo_wardrobe
/obj/item/vending_refill/wardrobe/robo_wardrobe
@@ -140,6 +146,7 @@
/obj/item/storage/backpack/satchel/tox = 3,
/obj/item/clothing/suit/hooded/wintercoat/science = 3,
/obj/item/clothing/under/rank/scientist = 4,
+ /obj/item/clothing/under/rank/scientist/skirt = 4,
/obj/item/clothing/suit/toggle/labcoat/science = 4,
/obj/item/clothing/shoes/sneakers/white = 4,
/obj/item/radio/headset/headset_sci = 4,
@@ -161,6 +168,7 @@
/obj/item/clothing/suit/apron = 3,
/obj/item/clothing/suit/apron/overalls = 5,
/obj/item/clothing/under/rank/hydroponics = 5,
+ /obj/item/clothing/under/rank/hydroponics/skirt = 5,
/obj/item/clothing/mask/bandana = 4)
refill_canister = /obj/item/vending_refill/wardrobe/hydro_wardrobe
@@ -175,6 +183,9 @@
vend_reply = "Thank you for using the CuraDrobe!"
products = list(/obj/item/clothing/head/fedora/curator = 2,
/obj/item/clothing/suit/curator = 2,
+ /obj/item/clothing/under/rank/curator/skirt = 2,
+ /obj/item/clothing/under/gimmick/rank/captain/suit/skirt = 2,
+ /obj/item/clothing/under/gimmick/rank/head_of_personnel/suit/skirt = 2,
/obj/item/clothing/under/rank/curator/treasure_hunter = 2,
/obj/item/clothing/shoes/workboots/mining = 2,
/obj/item/storage/backpack/satchel/explorer = 2,
@@ -194,12 +205,13 @@
/obj/item/radio/headset/headset_srv = 3,
/obj/item/clothing/under/sl_suit = 3,
/obj/item/clothing/under/rank/bartender = 3,
+ /obj/item/clothing/under/rank/bartender/skirt = 2,
/obj/item/clothing/under/rank/bartender/purple = 2,
/obj/item/clothing/accessory/waistcoat = 3,
/obj/item/clothing/suit/apron/purple_bartender = 2,
/obj/item/clothing/head/soft/black = 4,
/obj/item/clothing/shoes/sneakers/black = 4,
- /obj/item/reagent_containers/glass/rag = 4,
+ /obj/item/reagent_containers/rag = 4,
/obj/item/storage/box/beanbag = 1,
/obj/item/clothing/suit/armor/vest/alt = 1,
/obj/item/circuitboard/machine/dish_drive = 1,
@@ -226,8 +238,10 @@
/obj/item/circuitboard/machine/dish_drive = 1,
/obj/item/clothing/suit/toggle/chef = 2,
/obj/item/clothing/under/rank/chef = 2,
+ /obj/item/clothing/under/rank/chef/skirt = 2,
/obj/item/clothing/head/chefhat = 2,
- /obj/item/reagent_containers/glass/rag = 3)
+ /obj/item/reagent_containers/rag = 3,
+ /obj/item/book/granter/crafting_recipe/cooking_sweets_101 = 2)
refill_canister = /obj/item/vending_refill/wardrobe/chef_wardrobe
/obj/item/vending_refill/wardrobe/chef_wardrobe
@@ -240,6 +254,7 @@
product_ads = "Come and get your janitorial clothing, now endorsed by lizard janitors everywhere!"
vend_reply = "Thank you for using the JaniDrobe!"
products = list(/obj/item/clothing/under/rank/janitor = 2,
+ /obj/item/clothing/under/rank/janitor/skirt = 2,
/obj/item/cartridge/janitor = 3,
/obj/item/clothing/gloves/color/black = 2,
/obj/item/clothing/head/soft/purple = 2,
@@ -265,10 +280,19 @@
icon_state = "lawdrobe"
product_ads = "OBJECTION! Get the rule of law for yourself!"
vend_reply = "Thank you for using the LawDrobe!"
- products = list(/obj/item/clothing/under/lawyer/female = 3,
- /obj/item/clothing/under/lawyer/black = 3,
+ products = list(/obj/item/clothing/under/lawyer/bluesuit/skirt = 3,
+ /obj/item/clothing/under/lawyer/purpsuit/skirt = 3,
+ /obj/item/clothing/under/lawyer/blacksuit/skirt = 3,
+ /obj/item/clothing/under/lawyer/female = 3,
+ /obj/item/clothing/under/lawyer/female/skirt = 3,
+ /obj/item/clothing/under/lawyer/really_black = 3,
+ /obj/item/clothing/under/lawyer/really_black/skirt = 3,
+ /obj/item/clothing/under/lawyer/blue = 3,
+ /obj/item/clothing/under/lawyer/blue/skirt = 3,
/obj/item/clothing/under/lawyer/red = 3,
- /obj/item/clothing/under/lawyer/bluesuit = 3,
+ /obj/item/clothing/under/lawyer/red/skirt = 3,
+ /obj/item/clothing/under/lawyer/black = 3,
+ /obj/item/clothing/under/lawyer/black/skirt = 3,
/obj/item/clothing/suit/toggle/lawyer = 3,
/obj/item/clothing/under/lawyer/purpsuit = 3,
/obj/item/clothing/suit/toggle/lawyer/purple = 3,
@@ -291,6 +315,7 @@
/obj/item/storage/backpack/cultpack = 2,
/obj/item/clothing/accessory/pocketprotector/cosmetology = 2,
/obj/item/clothing/under/rank/chaplain = 2,
+ /obj/item/clothing/under/rank/chaplain/skirt = 2,
/obj/item/clothing/shoes/sneakers/black = 2,
/obj/item/clothing/suit/nun = 2,
/obj/item/clothing/head/nun_hood = 2,
@@ -308,11 +333,13 @@
product_ads = "Our clothes are 0.5% more resistant to acid spills! Get yours now!"
vend_reply = "Thank you for using the ChemDrobe!"
products = list(/obj/item/clothing/under/rank/chemist = 3,
+ /obj/item/clothing/under/rank/chemist/skirt = 3,
/obj/item/clothing/shoes/sneakers/white = 3,
/obj/item/clothing/suit/toggle/labcoat/chemist = 3,
/obj/item/storage/backpack/chemistry = 3,
/obj/item/storage/backpack/satchel/chem = 3,
- /obj/item/storage/bag/chemistry = 3)
+ /obj/item/storage/bag/chemistry = 3,
+ /obj/item/fermichem/pHbooklet = 3)//pH indicator)
refill_canister = /obj/item/vending_refill/wardrobe/chem_wardrobe
/obj/item/vending_refill/wardrobe/chem_wardrobe
@@ -325,6 +352,7 @@
product_ads = "Perfect for the mad scientist in you!"
vend_reply = "Thank you for using the GeneDrobe!"
products = list(/obj/item/clothing/under/rank/geneticist = 3,
+ /obj/item/clothing/under/rank/geneticist/skirt = 3,
/obj/item/clothing/shoes/sneakers/white = 3,
/obj/item/clothing/suit/toggle/labcoat/genetics = 3,
/obj/item/storage/backpack/genetics = 3,
@@ -341,6 +369,7 @@
product_ads = " Viruses getting you down? Then upgrade to sterilized clothing today!"
vend_reply = "Thank you for using the ViroDrobe"
products = list(/obj/item/clothing/under/rank/virologist = 3,
+ /obj/item/clothing/under/rank/virologist/skirt = 3,
/obj/item/clothing/shoes/sneakers/white = 3,
/obj/item/clothing/suit/toggle/labcoat/virologist = 3,
/obj/item/clothing/mask/surgical = 3,
diff --git a/code/modules/zombie/items.dm b/code/modules/zombie/items.dm
index 9a2455f56d..ae53f29a55 100644
--- a/code/modules/zombie/items.dm
+++ b/code/modules/zombie/items.dm
@@ -13,6 +13,7 @@
hitsound = 'sound/hallucinations/growl1.ogg'
force = 21 // Just enough to break airlocks with melee attacks
damtype = "brute"
+ total_mass = TOTAL_MASS_HAND_REPLACEMENT
/obj/item/zombie_hand/Initialize()
. = ..()
diff --git a/config/admins.txt b/config/admins.txt
index 27a2178e2c..1fdf480dd3 100644
--- a/config/admins.txt
+++ b/config/admins.txt
@@ -1,11 +1,11 @@
-###############################################################################################
-# Basically, ckey goes first. Rank goes after the "=" #
-# Case is not important for ckey. #
-# Case IS important for the rank. #
-# All punctuation (spaces etc) EXCEPT '-', '_' and '@' will be stripped from rank names. #
-# Ranks can be anything defined in admin_ranks.txt #
-# NOTE: if the rank-name cannot be found in admin_ranks.txt, they will not be adminned! ~Carn #
-# NOTE: syntax was changed to allow hyphenation of ranknames, since spaces are stripped. #
-###############################################################################################
-
-yourckeygoeshere = Host
+###############################################################################################
+# Basically, ckey goes first. Rank goes after the "=" #
+# Case is not important for ckey. #
+# Case IS important for the rank. #
+# All punctuation (spaces etc) EXCEPT '-', '_' and '@' will be stripped from rank names. #
+# Ranks can be anything defined in admin_ranks.txt #
+# NOTE: if the rank-name cannot be found in admin_ranks.txt, they will not be adminned! ~Carn #
+# NOTE: syntax was changed to allow hyphenation of ranknames, since spaces are stripped. #
+###############################################################################################
+
+yourckeygoeshere = Host
\ No newline at end of file
diff --git a/config/spaceRuinBlacklist.txt b/config/spaceRuinBlacklist.txt
index cba9a01e73..deafa47969 100644
--- a/config/spaceRuinBlacklist.txt
+++ b/config/spaceRuinBlacklist.txt
@@ -49,3 +49,4 @@
#_maps/RandomRuins/SpaceRuins/bigape.dmm
#_maps/RandomRuins/SpaceRuins/arcade.dmm
#_maps/RandomRuins/SpaceRuins/spacehermit.dmm
+#_maps/RandomRuins/SpaceRuins/advancedlab.dmm
diff --git a/goon/browserassets/css/browserOutput.css b/goon/browserassets/css/browserOutput.css
new file mode 100644
index 0000000000..58129ac1cb
--- /dev/null
+++ b/goon/browserassets/css/browserOutput.css
@@ -0,0 +1,876 @@
+/*****************************************
+*
+* GLOBAL STYLES
+*
+******************************************/
+html, body {
+ padding: 0;
+ margin: 0;
+ height: 100%;
+ color: #000000;
+}
+body {
+ background: #E0E0E0; /*CIT CHANGE - darkens chatbox a lil*/
+ font-family: Verdana, sans-serif;
+ font-size: 9pt;
+ line-height: 1.2;
+ overflow-x: hidden;
+ overflow-y: scroll;
+ word-wrap: break-word;
+}
+
+em {
+ font-style: normal;
+ font-weight: bold;
+}
+
+img {
+ margin: 0;
+ padding: 0;
+ line-height: 1;
+ -ms-interpolation-mode: nearest-neighbor;
+ image-rendering: pixelated;
+}
+img.icon {
+ height: 1em;
+ min-height: 16px;
+ width: auto;
+ vertical-align: bottom;
+}
+
+
+.r:before { /* "repeated" badge class for combined messages */
+ content: 'x';
+}
+.r {
+ display: inline-block;
+ min-width: 0.5em;
+ font-size: 0.7em;
+ padding: 0.2em 0.3em;
+ line-height: 1;
+ color: white;
+ text-align: center;
+ white-space: nowrap;
+ vertical-align: middle;
+ background-color: crimson;
+ border-radius: 10px;
+}
+
+a {color: #0000ff;}
+a.visited {color: #ff00ff;}
+a:visited {color: #ff00ff;}
+a.popt {text-decoration: none;}
+
+/*****************************************
+*
+* OUTPUT NOT RELATED TO ACTUAL MESSAGES
+*
+******************************************/
+#loading {
+ position: fixed;
+ width: 300px;
+ height: 150px;
+ text-align: center;
+ left: 50%;
+ top: 50%;
+ margin: -75px 0 0 -150px;
+}
+#loading i {display: block; padding-bottom: 3px;}
+
+#messages {
+ font-size: 13px;
+ padding: 3px;
+ margin: 0;
+ word-wrap: break-word;
+}
+#newMessages {
+ position: fixed;
+ display: block;
+ bottom: 0;
+ right: 0;
+ padding: 8px;
+ background: #ddd;
+ text-decoration: none;
+ font-variant: small-caps;
+ font-size: 1.1em;
+ font-weight: bold;
+ color: #333;
+}
+#newMessages:hover {background: #ccc;}
+#newMessages i {vertical-align: middle; padding-left: 3px;}
+#ping {
+ position: fixed;
+ top: 0;
+ right: 80px;
+ width: 45px;
+ background: #ddd;
+ height: 30px;
+ padding: 8px 0 2px 0;
+}
+#ping i {display: block; text-align: center;}
+#ping .ms {
+ display: block;
+ text-align: center;
+ font-size: 8pt;
+ padding-top: 2px;
+}
+#userBar {
+ position: fixed;
+ top: 0;
+ right: 0;
+}
+#userBar .subCell {
+ background: #ddd;
+ height: 30px;
+ padding: 5px 0;
+ display: block;
+ color: #333;
+ text-decoration: none;
+ line-height: 28px;
+ border-top: 1px solid #b4b4b4;
+}
+#userBar .subCell:hover {background: #ccc;}
+#userBar .toggle {
+ width: 40px;
+ background: #ccc;
+ border-top: 0;
+ float: right;
+ text-align: center;
+}
+#userBar .sub {clear: both; display: none; width: 160px;}
+#userBar .sub.scroll {overflow-y: scroll;}
+#userBar .sub.subCell {padding: 3px 0 3px 8px; line-height: 30px; font-size: 0.9em; clear: both;}
+#userBar .sub span {
+ display: block;
+ line-height: 30px;
+ float: left;
+}
+#userBar .sub i {
+ display: block;
+ padding: 0 5px;
+ font-size: 1.1em;
+ width: 22px;
+ text-align: center;
+ line-height: 30px;
+ float: right;
+}
+#userBar .sub input {
+ position: absolute;
+ padding: 7px 5px;
+ width: 121px;
+ line-height: 30px;
+ float: left;
+}
+#userBar .topCell {border-top: 0;}
+
+/* POPUPS */
+.popup {
+ position: fixed;
+ top: 50%;
+ left: 50%;
+ background: #ddd;
+}
+.popup .close {
+ position: absolute;
+ background: #aaa;
+ top: 0;
+ right: 0;
+ color: #333;
+ text-decoration: none;
+ z-index: 2;
+ padding: 0 10px;
+ height: 30px;
+ line-height: 30px;
+}
+.popup .close:hover {background: #999;}
+.popup .head {
+ background: #999;
+ color: #ddd;
+ padding: 0 10px;
+ height: 30px;
+ line-height: 30px;
+ text-transform: uppercase;
+ font-size: 0.9em;
+ font-weight: bold;
+ border-bottom: 2px solid green;
+}
+.popup input {border: 1px solid #999; background: #fff; margin: 0; padding: 5px; outline: none; color: #333;}
+.popup input[type=text]:hover, .popup input[type=text]:active, .popup input[type=text]:focus {border-color: green;}
+.popup input[type=submit] {padding: 5px 10px; background: #999; color: #ddd; text-transform: uppercase; font-size: 0.9em; font-weight: bold;}
+.popup input[type=submit]:hover, .popup input[type=submit]:focus, .popup input[type=submit]:active {background: #aaa; cursor: pointer;}
+
+.changeFont {padding: 10px;}
+.changeFont a {display: block; text-decoration: none; padding: 3px; color: #333;}
+.changeFont a:hover {background: #ccc;}
+
+.highlightPopup {padding: 10px; text-align: center;}
+.highlightPopup input[type=text] {display: block; width: 215px; text-align: left; margin-top: 5px;}
+.highlightPopup input.highlightColor {background-color: #FFFF00;}
+.highlightPopup input.highlightTermSubmit {margin-top: 5px;}
+
+/* ADMIN CONTEXT MENU */
+.contextMenu {
+ background-color: #ddd;
+ position: fixed;
+ margin: 2px;
+ width: 150px;
+}
+.contextMenu a {
+ display: block;
+ padding: 2px 5px;
+ text-decoration: none;
+ color: #333;
+}
+
+.contextMenu a:hover {
+ background-color: #ccc;
+}
+
+/* ADMIN FILTER MESSAGES MENU */
+.filterMessages {padding: 5px;}
+.filterMessages div {padding: 2px 0;}
+.filterMessages input {}
+.filterMessages label {}
+
+.icon-stack {height: 1em; line-height: 1em; width: 1em; vertical-align: middle; margin-top: -2px;}
+
+
+/*****************************************
+*
+* OUTPUT ACTUALLY RELATED TO MESSAGES
+*
+******************************************/
+
+/* MOTD */
+.motd {color: #638500; font-family: Verdana, sans-serif;}
+.motd h1, .motd h2, .motd h3, .motd h4, .motd h5, .motd h6 {color: #638500; text-decoration: underline;}
+.motd a, .motd a:link, .motd a:visited, .motd a:active, .motd a:hover {color: #638500;}
+
+/* ADD HERE FOR BOLD */
+.bold, .name, .prefix, .ooc, .looc, .adminooc, .admin, .medal, .yell {font-weight: bold;}
+
+/* ADD HERE FOR ITALIC */
+.italic, .italics, .emote {font-style: italic;}
+
+/* OUTPUT COLORS */
+.highlight {background: yellow;}
+
+h1, h2, h3, h4, h5, h6 {color: #0000ff;font-family: Georgia, Verdana, sans-serif;}
+h1.alert, h2.alert {color: #000000;}
+
+em {font-style: normal; font-weight: bold;}
+
+.ooc { font-weight: bold;}
+.adminobserverooc {color: #0099cc; font-weight: bold;}
+.adminooc {color: #700038; font-weight: bold;}
+
+.adminobserver {color: #996600; font-weight: bold;}
+.admin {color: #386aff; font-weight: bold;}
+
+.name { font-weight: bold;}
+
+.say {}
+.deadsay {color: #5c00e6;}
+.binarysay {color: #20c20e; background-color: #000000; display: block;}
+.binarysay a {color: #00ff00;}
+.binarysay a:active, .binarysay a:visited {color: #88ff88;}
+.radio {color: #008000;}
+.sciradio {color: #993399;}
+.comradio {color: #948f02;}
+.secradio {color: #a30000;}
+.medradio {color: #337296;}
+.engradio {color: #fb5613;}
+.suppradio {color: #a8732b;}
+.servradio {color: #6eaa2c;}
+.syndradio {color: #6d3f40;}
+.centcomradio {color: #686868;}
+.aiprivradio {color: #ff00ff;}
+.redteamradio {color: #ff0000;}
+.blueteamradio {color: #0000ff;}
+
+.yell { font-weight: bold;}
+
+.alert {color: #ff0000;}
+h1.alert, h2.alert {color: #000000;}
+
+.emote { font-style: italic;}
+.selecteddna {color: #ffffff; background-color: #001B1B}
+
+.attack {color: #ff0000;}
+.disarm {color: #990000;}
+.passive {color: #660000;}
+
+.userdanger {color: #ff0000; font-weight: bold; font-size: 24px;}
+.danger {color: #ff0000;}
+.warning {color: #ff0000; font-style: italic;}
+.boldwarning {color: #ff0000; font-style: italic; font-weight: bold}
+.announce {color: #228b22; font-weight: bold;}
+.boldannounce {color: #ff0000; font-weight: bold;}
+.greenannounce {color: #00ff00; font-weight: bold;}
+.rose {color: #ff5050;}
+.info {color: #0000CC;}
+.notice {color: #000099;}
+.boldnotice {color: #000099; font-weight: bold;}
+.adminnotice {color: #0000ff;}
+.adminhelp {color: #ff0000; font-weight: bold;}
+.unconscious {color: #0000ff; font-weight: bold;}
+.suicide {color: #ff5050; font-style: italic;}
+.green {color: #03ff39;}
+.nicegreen {color: #14a833;}
+.shadowling {color: #3b2769;}
+.cult {color: #960000;}
+
+.cultitalic {color: #960000; font-style: italic;}
+.cultbold {color: #960000; font-style: italic; font-weight: bold;}
+.cultboldtalic {color: #960000; font-weight: bold; font-size: 24px;}
+
+.cultlarge {color: #960000; font-weight: bold; font-size: 24px;}
+.narsie {color: #960000; font-weight: bold; font-size: 120px;}
+.narsiesmall {color: #960000; font-weight: bold; font-size: 48px;}
+.colossus {color: #7F282A; font-size: 40px;}
+.hierophant {color: #660099; font-weight: bold; font-style: italic;}
+.hierophant_warning {color: #660099; font-style: italic;}
+.purple {color: #5e2d79;}
+.holoparasite {color: #35333a;}
+
+.revennotice {color: #1d2953;}
+.revenboldnotice {color: #1d2953; font-weight: bold;}
+.revenbignotice {color: #1d2953; font-weight: bold; font-size: 24px;}
+.revenminor {color: #823abb}
+.revenwarning {color: #760fbb; font-style: italic;}
+.revendanger {color: #760fbb; font-weight: bold; font-size: 24px;}
+.umbra {color: #5000A0;}
+.umbra_emphasis {color: #5000A0; font-weight: bold; font-style: italic;}
+.umbra_large {color: #5000A0; font-size: 24px; font-weight: bold; font-style: italic;}
+
+.deconversion_message {color: #5000A0; font-size: 24px; font-style: italic;}
+
+.brass {color: #BE8700;}
+.heavy_brass {color: #BE8700; font-weight: bold; font-style: italic;}
+.large_brass {color: #BE8700; font-size: 24px;}
+.big_brass {color: #BE8700; font-size: 24px; font-weight: bold; font-style: italic;}
+.ratvar {color: #BE8700; font-size: 48px; font-weight: bold; font-style: italic;}
+.alloy {color: #42474D;}
+.heavy_alloy {color: #42474D; font-weight: bold; font-style: italic;}
+.nezbere_large {color: #42474D; font-size: 24px; font-weight: bold; font-style: italic;}
+.nezbere {color: #42474D; font-weight: bold; font-style: italic;}
+.nezbere_small {color: #42474D;}
+.sevtug_large {color: #AF0AAF; font-size: 24px; font-weight: bold; font-style: italic;}
+.sevtug {color: #AF0AAF; font-weight: bold; font-style: italic;}
+.sevtug_small {color: #AF0AAF;}
+.inathneq_large {color: #1E8CE1; font-size: 24px; font-weight: bold; font-style: italic;}
+.inathneq {color: #1E8CE1; font-weight: bold; font-style: italic;}
+.inathneq_small {color: #1E8CE1;}
+.nzcrentr_large {color: #DAAA18; font-size: 24px; font-weight: bold; font-style: italic;}
+.nzcrentr {color: #DAAA18; font-weight: bold; font-style: italic;}
+.nzcrentr_small {color: #DAAA18;}
+.neovgre_large {color: #6E001A; font-size: 24px; font-weight: bold; font-style: italic;}
+.neovgre {color: #6E001A; font-weight: bold; font-style: italic;}
+.neovgre_small {color: #6E001A;}
+
+.newscaster {color: #800000;}
+.ghostalert {color: #5c00e6; font-style: italic; font-weight: bold;}
+
+.alien {color: #543354;}
+.noticealien {color: #00c000;}
+.alertalien {color: #00c000; font-weight: bold;}
+.changeling {color: #800080; font-style: italic;}
+
+.spider {color: #4d004d;}
+
+.interface {color: #330033;}
+
+.sans {font-family: "Comic Sans MS", cursive, sans-serif;}
+.papyrus {font-family: "Papyrus", cursive, sans-serif;}
+.robot {font-family: "Courier New", cursive, sans-serif;}
+
+.command_headset {font-weight: bold; font-size: 24px;}
+.small {font-size: 8px;}
+.big {font-size: 24px;}
+.reallybig {font-size: 32px;}
+.extremelybig {font-size: 40px;}
+.greentext {color: #00FF00; font-size: 24px;}
+.redtext {color: #FF0000; font-size: 24px;}
+.clown {color: #FF69Bf; font-size: 24px; font-family: "Comic Sans MS", cursive, sans-serif; font-weight: bold;}
+.his_grace {color: #15D512; font-family: "Courier New", cursive, sans-serif; font-style: italic;}
+.velvet {color: #660015; font-weight: bold; animation: velvet 5000ms infinite;}
+@keyframes velvet {
+ 0% { color: #400020; }
+ 40% { color: #FF0000; }
+ 50% { color: #FF8888; }
+ 60% { color: #FF0000; }
+ 100% { color: #400020; }
+}
+
+.hypnophrase {color: #202020; font-weight: bold; animation: hypnocolor 1500ms infinite;}
+@keyframes hypnocolor {
+ 0% { color: #202020; }
+ 25% { color: #4b02ac; }
+ 50% { color: #9f41f1; }
+ 75% { color: #541c9c; }
+ 100% { color: #7adbf3; }
+}
+
+.phobia {color: #dd0000; font-weight: bold; animation: phobia 750ms infinite;}
+@keyframes phobia {
+ 0% { color: #f75a5a; }
+ 50% { color: #dd0000; }
+ 100% { color: #f75a5a; }
+}
+
+.icon {height: 1em; width: auto;}
+
+.memo {color: #638500; text-align: center;}
+.memoedit {text-align: center; font-size: 16px;}
+.abductor {color: #800080; font-style: italic;}
+.mind_control {color: #A00D6F; font-size: 3; font-weight: bold; font-style: italic;}
+.slime {color: #00CED1;}
+.drone {color: #848482;}
+.monkey {color: #975032;}
+.swarmer {color: #2C75FF;}
+.resonate {color: #298F85;}
+
+.monkeyhive {color: #774704;}
+.monkeylead {color: #774704; font-size: 2;}
+
+.connectionClosed, .fatalError {background: red; color: white; padding: 5px;}
+.connectionClosed.restored {background: green;}
+.internal.boldnshit {color: blue; font-weight: bold;}
+
+/* HELPER CLASSES */
+.text-normal {font-weight: normal; font-style: normal;}
+.hidden {display: none; visibility: hidden;}/*****************************************
+*
+* GLOBAL STYLES
+*
+******************************************/
+html, body {
+ padding: 0;
+ margin: 0;
+ height: 100%;
+ color: #000000;
+}
+body {
+ background: #E0E0E0; /*CIT CHANGE - darkens chatbox a lil*/
+ font-family: Verdana, sans-serif;
+ font-size: 9pt;
+ line-height: 1.2;
+ overflow-x: hidden;
+ overflow-y: scroll;
+ word-wrap: break-word;
+}
+
+em {
+ font-style: normal;
+ font-weight: bold;
+}
+
+img {
+ margin: 0;
+ padding: 0;
+ line-height: 1;
+ -ms-interpolation-mode: nearest-neighbor;
+ image-rendering: pixelated;
+}
+img.icon {
+ height: 1em;
+ min-height: 16px;
+ width: auto;
+ vertical-align: bottom;
+}
+
+
+.r:before { /* "repeated" badge class for combined messages */
+ content: 'x';
+}
+.r {
+ display: inline-block;
+ min-width: 0.5em;
+ font-size: 0.7em;
+ padding: 0.2em 0.3em;
+ line-height: 1;
+ color: white;
+ text-align: center;
+ white-space: nowrap;
+ vertical-align: middle;
+ background-color: crimson;
+ border-radius: 10px;
+}
+
+a {color: #0000ff;}
+a.visited {color: #ff00ff;}
+a:visited {color: #ff00ff;}
+a.popt {text-decoration: none;}
+
+/*****************************************
+*
+* OUTPUT NOT RELATED TO ACTUAL MESSAGES
+*
+******************************************/
+#loading {
+ position: fixed;
+ width: 300px;
+ height: 150px;
+ text-align: center;
+ left: 50%;
+ top: 50%;
+ margin: -75px 0 0 -150px;
+}
+#loading i {display: block; padding-bottom: 3px;}
+
+#messages {
+ font-size: 13px;
+ padding: 3px;
+ margin: 0;
+ word-wrap: break-word;
+}
+#newMessages {
+ position: fixed;
+ display: block;
+ bottom: 0;
+ right: 0;
+ padding: 8px;
+ background: #ddd;
+ text-decoration: none;
+ font-variant: small-caps;
+ font-size: 1.1em;
+ font-weight: bold;
+ color: #333;
+}
+#newMessages:hover {background: #ccc;}
+#newMessages i {vertical-align: middle; padding-left: 3px;}
+#ping {
+ position: fixed;
+ top: 0;
+ right: 80px;
+ width: 45px;
+ background: #ddd;
+ height: 30px;
+ padding: 8px 0 2px 0;
+}
+#ping i {display: block; text-align: center;}
+#ping .ms {
+ display: block;
+ text-align: center;
+ font-size: 8pt;
+ padding-top: 2px;
+}
+#userBar {
+ position: fixed;
+ top: 0;
+ right: 0;
+}
+#userBar .subCell {
+ background: #ddd;
+ height: 30px;
+ padding: 5px 0;
+ display: block;
+ color: #333;
+ text-decoration: none;
+ line-height: 28px;
+ border-top: 1px solid #b4b4b4;
+}
+#userBar .subCell:hover {background: #ccc;}
+#userBar .toggle {
+ width: 40px;
+ background: #ccc;
+ border-top: 0;
+ float: right;
+ text-align: center;
+}
+#userBar .sub {clear: both; display: none; width: 160px;}
+#userBar .sub.scroll {overflow-y: scroll;}
+#userBar .sub.subCell {padding: 3px 0 3px 8px; line-height: 30px; font-size: 0.9em; clear: both;}
+#userBar .sub span {
+ display: block;
+ line-height: 30px;
+ float: left;
+}
+#userBar .sub i {
+ display: block;
+ padding: 0 5px;
+ font-size: 1.1em;
+ width: 22px;
+ text-align: center;
+ line-height: 30px;
+ float: right;
+}
+#userBar .sub input {
+ position: absolute;
+ padding: 7px 5px;
+ width: 121px;
+ line-height: 30px;
+ float: left;
+}
+#userBar .topCell {border-top: 0;}
+
+/* POPUPS */
+.popup {
+ position: fixed;
+ top: 50%;
+ left: 50%;
+ background: #ddd;
+}
+.popup .close {
+ position: absolute;
+ background: #aaa;
+ top: 0;
+ right: 0;
+ color: #333;
+ text-decoration: none;
+ z-index: 2;
+ padding: 0 10px;
+ height: 30px;
+ line-height: 30px;
+}
+.popup .close:hover {background: #999;}
+.popup .head {
+ background: #999;
+ color: #ddd;
+ padding: 0 10px;
+ height: 30px;
+ line-height: 30px;
+ text-transform: uppercase;
+ font-size: 0.9em;
+ font-weight: bold;
+ border-bottom: 2px solid green;
+}
+.popup input {border: 1px solid #999; background: #fff; margin: 0; padding: 5px; outline: none; color: #333;}
+.popup input[type=text]:hover, .popup input[type=text]:active, .popup input[type=text]:focus {border-color: green;}
+.popup input[type=submit] {padding: 5px 10px; background: #999; color: #ddd; text-transform: uppercase; font-size: 0.9em; font-weight: bold;}
+.popup input[type=submit]:hover, .popup input[type=submit]:focus, .popup input[type=submit]:active {background: #aaa; cursor: pointer;}
+
+.changeFont {padding: 10px;}
+.changeFont a {display: block; text-decoration: none; padding: 3px; color: #333;}
+.changeFont a:hover {background: #ccc;}
+
+.highlightPopup {padding: 10px; text-align: center;}
+.highlightPopup input[type=text] {display: block; width: 215px; text-align: left; margin-top: 5px;}
+.highlightPopup input.highlightColor {background-color: #FFFF00;}
+.highlightPopup input.highlightTermSubmit {margin-top: 5px;}
+
+/* ADMIN CONTEXT MENU */
+.contextMenu {
+ background-color: #ddd;
+ position: fixed;
+ margin: 2px;
+ width: 150px;
+}
+.contextMenu a {
+ display: block;
+ padding: 2px 5px;
+ text-decoration: none;
+ color: #333;
+}
+
+.contextMenu a:hover {
+ background-color: #ccc;
+}
+
+/* ADMIN FILTER MESSAGES MENU */
+.filterMessages {padding: 5px;}
+.filterMessages div {padding: 2px 0;}
+.filterMessages input {}
+.filterMessages label {}
+
+.icon-stack {height: 1em; line-height: 1em; width: 1em; vertical-align: middle; margin-top: -2px;}
+
+
+/*****************************************
+*
+* OUTPUT ACTUALLY RELATED TO MESSAGES
+*
+******************************************/
+
+/* MOTD */
+.motd {color: #638500; font-family: Verdana, sans-serif;}
+.motd h1, .motd h2, .motd h3, .motd h4, .motd h5, .motd h6 {color: #638500; text-decoration: underline;}
+.motd a, .motd a:link, .motd a:visited, .motd a:active, .motd a:hover {color: #638500;}
+
+/* ADD HERE FOR BOLD */
+.bold, .name, .prefix, .ooc, .looc, .adminooc, .admin, .medal, .yell {font-weight: bold;}
+
+/* ADD HERE FOR ITALIC */
+.italic, .italics, .emote {font-style: italic;}
+
+/* OUTPUT COLORS */
+.highlight {background: yellow;}
+
+h1, h2, h3, h4, h5, h6 {color: #0000ff;font-family: Georgia, Verdana, sans-serif;}
+h1.alert, h2.alert {color: #000000;}
+
+em {font-style: normal; font-weight: bold;}
+
+.ooc { font-weight: bold;}
+.adminobserverooc {color: #0099cc; font-weight: bold;}
+.adminooc {color: #700038; font-weight: bold;}
+
+.adminsay {color: #FF4500; font-weight: bold;}
+.admin {color: #386aff; font-weight: bold;}
+
+.name { font-weight: bold;}
+
+.say {}
+.deadsay {color: #5c00e6;}
+.binarysay {color: #20c20e; background-color: #000000; display: block;}
+.binarysay a {color: #00ff00;}
+.binarysay a:active, .binarysay a:visited {color: #88ff88;}
+.radio {color: #008000;}
+.sciradio {color: #993399;}
+.comradio {color: #948f02;}
+.secradio {color: #a30000;}
+.medradio {color: #337296;}
+.engradio {color: #fb5613;}
+.suppradio {color: #a8732b;}
+.servradio {color: #6eaa2c;}
+.syndradio {color: #6d3f40;}
+.centcomradio {color: #686868;}
+.aiprivradio {color: #ff00ff;}
+.redteamradio {color: #ff0000;}
+.blueteamradio {color: #0000ff;}
+
+.yell { font-weight: bold;}
+
+.alert {color: #ff0000;}
+h1.alert, h2.alert {color: #000000;}
+
+.emote { font-style: italic;}
+.selecteddna {color: #ffffff; background-color: #001B1B}
+
+.attack {color: #ff0000;}
+.disarm {color: #990000;}
+.passive {color: #660000;}
+
+.userdanger {color: #ff0000; font-weight: bold; font-size: 24px;}
+.danger {color: #ff0000;}
+.warning {color: #ff0000; font-style: italic;}
+.boldwarning {color: #ff0000; font-style: italic; font-weight: bold}
+.announce {color: #228b22; font-weight: bold;}
+.boldannounce {color: #ff0000; font-weight: bold;}
+.greenannounce {color: #00ff00; font-weight: bold;}
+.rose {color: #ff5050;}
+.info {color: #0000CC;}
+.notice {color: #000099;}
+.boldnotice {color: #000099; font-weight: bold;}
+.adminnotice {color: #0000ff;}
+.adminhelp {color: #ff0000; font-weight: bold;}
+.unconscious {color: #0000ff; font-weight: bold;}
+.suicide {color: #ff5050; font-style: italic;}
+.green {color: #03ff39;}
+.nicegreen {color: #14a833;}
+.userlove {color: #FF1493; font-style: italic; font-weight: bold; text-shadow: 0 0 6px #ff6dbc;}
+.love {color: #ff006a; font-style: italic; text-shadow: 0 0 6px #ff6d6d;}
+.shadowling {color: #3b2769;}
+.cult {color: #960000;}
+
+.cultitalic {color: #960000; font-style: italic;}
+.cultbold {color: #960000; font-style: italic; font-weight: bold;}
+.cultboldtalic {color: #960000; font-weight: bold; font-size: 24px;}
+
+.cultlarge {color: #960000; font-weight: bold; font-size: 24px;}
+.narsie {color: #960000; font-weight: bold; font-size: 120px;}
+.narsiesmall {color: #960000; font-weight: bold; font-size: 48px;}
+.colossus {color: #7F282A; font-size: 40px;}
+.hierophant {color: #660099; font-weight: bold; font-style: italic;}
+.hierophant_warning {color: #660099; font-style: italic;}
+.purple {color: #5e2d79;}
+.holoparasite {color: #35333a;}
+
+.revennotice {color: #1d2953;}
+.revenboldnotice {color: #1d2953; font-weight: bold;}
+.revenbignotice {color: #1d2953; font-weight: bold; font-size: 24px;}
+.revenminor {color: #823abb}
+.revenwarning {color: #760fbb; font-style: italic;}
+.revendanger {color: #760fbb; font-weight: bold; font-size: 24px;}
+.umbra {color: #5000A0;}
+.umbra_emphasis {color: #5000A0; font-weight: bold; font-style: italic;}
+.umbra_large {color: #5000A0; font-size: 24px; font-weight: bold; font-style: italic;}
+
+.deconversion_message {color: #5000A0; font-size: 24px; font-style: italic;}
+
+.brass {color: #BE8700;}
+.heavy_brass {color: #BE8700; font-weight: bold; font-style: italic;}
+.large_brass {color: #BE8700; font-size: 24px;}
+.big_brass {color: #BE8700; font-size: 24px; font-weight: bold; font-style: italic;}
+.ratvar {color: #BE8700; font-size: 48px; font-weight: bold; font-style: italic;}
+.alloy {color: #42474D;}
+.heavy_alloy {color: #42474D; font-weight: bold; font-style: italic;}
+.nezbere_large {color: #42474D; font-size: 24px; font-weight: bold; font-style: italic;}
+.nezbere {color: #42474D; font-weight: bold; font-style: italic;}
+.nezbere_small {color: #42474D;}
+.sevtug_large {color: #AF0AAF; font-size: 24px; font-weight: bold; font-style: italic;}
+.sevtug {color: #AF0AAF; font-weight: bold; font-style: italic;}
+.sevtug_small {color: #AF0AAF;}
+.inathneq_large {color: #1E8CE1; font-size: 24px; font-weight: bold; font-style: italic;}
+.inathneq {color: #1E8CE1; font-weight: bold; font-style: italic;}
+.inathneq_small {color: #1E8CE1;}
+.nzcrentr_large {color: #DAAA18; font-size: 24px; font-weight: bold; font-style: italic;}
+.nzcrentr {color: #DAAA18; font-weight: bold; font-style: italic;}
+.nzcrentr_small {color: #DAAA18;}
+.neovgre_large {color: #6E001A; font-size: 24px; font-weight: bold; font-style: italic;}
+.neovgre {color: #6E001A; font-weight: bold; font-style: italic;}
+.neovgre_small {color: #6E001A;}
+
+.newscaster {color: #800000;}
+.ghostalert {color: #5c00e6; font-style: italic; font-weight: bold;}
+
+.alien {color: #543354;}
+.noticealien {color: #00c000;}
+.alertalien {color: #00c000; font-weight: bold;}
+.changeling {color: #800080; font-style: italic;}
+
+.spider {color: #4d004d;}
+
+.interface {color: #330033;}
+
+.sans {font-family: "Comic Sans MS", cursive, sans-serif;}
+.papyrus {font-family: "Papyrus", cursive, sans-serif;}
+.robot {font-family: "Courier New", cursive, sans-serif;}
+
+.command_headset {font-weight: bold; font-size: 24px;}
+.small {font-size: 8px;}
+.big {font-size: 24px;}
+.reallybig {font-size: 32px;}
+.extremelybig {font-size: 40px;}
+.greentext {color: #00FF00; font-size: 24px;}
+.redtext {color: #FF0000; font-size: 24px;}
+.clown {color: #FF69Bf; font-size: 24px; font-family: "Comic Sans MS", cursive, sans-serif; font-weight: bold;}
+.hypnophrase {color: #202020; font-weight: bold; animation: hypnocolor 1500ms infinite;}
+@keyframes hypnocolor {
+ 0% { color: #202020; }
+ 25% { color: #4b02ac; }
+ 50% { color: #9f41f1; }
+ 75% { color: #541c9c; }
+ 100% { color: #7adbf3; }
+}
+
+.phobia {color: #dd0000; font-weight: bold; animation: phobia 750ms infinite;}
+@keyframes phobia {
+ 0% { color: #f75a5a; }
+ 50% { color: #dd0000; }
+ 100% { color: #f75a5a; }
+}
+.his_grace {color: #15D512; font-family: "Courier New", cursive, sans-serif; font-style: italic;}
+
+.icon {height: 1em; width: auto;}
+
+.memo {color: #638500; text-align: center;}
+.memoedit {text-align: center; font-size: 16px;}
+.abductor {color: #800080; font-style: italic;}
+.mind_control {color: #A00D6F; font-size: 3; font-weight: bold; font-style: italic;}
+.slime {color: #00CED1;}
+.drone {color: #848482;}
+.monkey {color: #975032;}
+.swarmer {color: #2C75FF;}
+.resonate {color: #298F85;}
+
+.monkeyhive {color: #774704;}
+.monkeylead {color: #774704; font-size: 2;}
+
+.connectionClosed, .fatalError {background: red; color: white; padding: 5px;}
+.connectionClosed.restored {background: green;}
+.internal.boldnshit {color: blue; font-weight: bold;}
+
+/* HELPER CLASSES */
+.text-normal {font-weight: normal; font-style: normal;}
+.hidden {display: none; visibility: hidden;}
diff --git a/html/changelogs/AutoChangeLog-pr-8349.yml b/html/changelogs/AutoChangeLog-pr-8349.yml
new file mode 100644
index 0000000000..de4c08624a
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8349.yml
@@ -0,0 +1,5 @@
+author: "Trilbyspaceclone"
+delete-after: True
+changes:
+ - rscadd: "more bountys"
+ - rscdel: "Nitryl bounty"
diff --git a/html/changelogs/AutoChangeLog-pr-8636.yml b/html/changelogs/AutoChangeLog-pr-8636.yml
new file mode 100644
index 0000000000..3b291661b5
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8636.yml
@@ -0,0 +1,4 @@
+author: "Trilbyspaceclone"
+delete-after: True
+changes:
+ - bugfix: "fixed airless place"
diff --git a/html/changelogs/AutoChangeLog-pr-8660.yml b/html/changelogs/AutoChangeLog-pr-8660.yml
new file mode 100644
index 0000000000..710c4489ea
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8660.yml
@@ -0,0 +1,4 @@
+author: "Trilbyspaceclone"
+delete-after: True
+changes:
+ - code_imp: "Changes some files to be better"
diff --git a/html/changelogs/AutoChangeLog-pr-8673.yml b/html/changelogs/AutoChangeLog-pr-8673.yml
new file mode 100644
index 0000000000..6ff2c7135c
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8673.yml
@@ -0,0 +1,4 @@
+author: "Trilbyspaceclone"
+delete-after: True
+changes:
+ - balance: "As all things are not"
diff --git a/html/changelogs/AutoChangeLog-pr-8763.yml b/html/changelogs/AutoChangeLog-pr-8763.yml
new file mode 100644
index 0000000000..d99b529656
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8763.yml
@@ -0,0 +1,4 @@
+author: "Trilbyspaceclone"
+delete-after: True
+changes:
+ - balance: "bone satchles"
diff --git a/html/changelogs/AutoChangeLog-pr-8774.yml b/html/changelogs/AutoChangeLog-pr-8774.yml
new file mode 100644
index 0000000000..7ba01cc6aa
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8774.yml
@@ -0,0 +1,4 @@
+author: "Sishen1542"
+delete-after: True
+changes:
+ - bugfix: "Removed the human check for cult conversion of captain/chaplain minds."
diff --git a/html/changelogs/AutoChangeLog-pr-8795.yml b/html/changelogs/AutoChangeLog-pr-8795.yml
new file mode 100644
index 0000000000..7fe2250a0b
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8795.yml
@@ -0,0 +1,7 @@
+author: "Sishen1542, original by @zxaber"
+delete-after: True
+changes:
+ - balance: "Utility mechs no longer automatically get beacons."
+ - balance: "Tracking beacons no longer delete themselves when EMPing a mech, and instead have a ten-second cooldown in-between EMPs. They also now do heavy EMP damage rather than light."
+ - balance: "Mechs that take EMP damage lose the use of their weapons and equipment temporarily. Movement and abilities are not effected."
+ - balance: "Mechs taking EMP damage no longer roll for a random malfunction."
diff --git a/html/changelogs/AutoChangeLog-pr-8829.yml b/html/changelogs/AutoChangeLog-pr-8829.yml
new file mode 100644
index 0000000000..6d0dd108dd
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8829.yml
@@ -0,0 +1,5 @@
+author: "BurgerLUA"
+delete-after: True
+changes:
+ - code_imp: "Added a new framework for reagents. Reagents can now have a bool that determines if it can be detected by handheld medical analyzers. Currently only the changeling sting chemical does this."
+ - balance: "Made changeling transformation string last between 10-15 minutes. Lowered the dna cost of changeling sting from 3 dna to 2 dna. Lowered the chemical cost from 50 to 10. Lowered the loudness from 2 to 1. Changeling sting transformation can be removed via high doses of calomel."
diff --git a/html/changelogs/AutoChangeLog-pr-8830.yml b/html/changelogs/AutoChangeLog-pr-8830.yml
new file mode 100644
index 0000000000..e4cb94374b
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8830.yml
@@ -0,0 +1,6 @@
+author: "Ghommie (original PRs by Kmc2000 and actioninja)"
+delete-after: True
+changes:
+ - rscadd: "Added darkmode! You can opt-in to this by clicking the new toggle darkmode button just beside the settings one."
+ - rscadd: "Byond members will now have a new setting for their Antag OOC color, instead of using their OOC one. (Antag OOC still locked under admin discretion though)"
+ - rscdel: "Default black'n'white windows style."
diff --git a/html/changelogs/AutoChangeLog-pr-8881.yml b/html/changelogs/AutoChangeLog-pr-8881.yml
new file mode 100644
index 0000000000..3599d4fa23
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8881.yml
@@ -0,0 +1,4 @@
+author: "Ghommie"
+delete-after: True
+changes:
+ - bugfix: "Fixing baklava pies a bit."
diff --git a/html/changelogs/AutoChangeLog-pr-8898.yml b/html/changelogs/AutoChangeLog-pr-8898.yml
new file mode 100644
index 0000000000..e836d4225e
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8898.yml
@@ -0,0 +1,4 @@
+author: "WhiteHusky"
+delete-after: True
+changes:
+ - tweak: "Checking yourself shouldn't freeze the client anymore."
diff --git a/html/changelogs/AutoChangeLog-pr-8900.yml b/html/changelogs/AutoChangeLog-pr-8900.yml
new file mode 100644
index 0000000000..cbb910c3d5
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8900.yml
@@ -0,0 +1,4 @@
+author: "Seris02"
+delete-after: True
+changes:
+ - rscadd: "Abductor Replication Lab ruin and advanced tools"
diff --git a/html/changelogs/AutoChangeLog-pr-8906.yml b/html/changelogs/AutoChangeLog-pr-8906.yml
new file mode 100644
index 0000000000..c988071f3e
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8906.yml
@@ -0,0 +1,4 @@
+author: "Ghommie"
+delete-after: True
+changes:
+ - tweak: "Sweaters now cover groins too."
diff --git a/html/changelogs/AutoChangeLog-pr-8908.yml b/html/changelogs/AutoChangeLog-pr-8908.yml
new file mode 100644
index 0000000000..d9cbd5abed
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8908.yml
@@ -0,0 +1,5 @@
+author: "Ghommie"
+delete-after: True
+changes:
+ - balance: "Improved the zelus flask to be more viable for bottle smashing than the average barman's selection."
+ - code_imp: "Very slight bottle smashing code clean up, stupid const vars."
diff --git a/html/changelogs/AutoChangeLog-pr-8909.yml b/html/changelogs/AutoChangeLog-pr-8909.yml
new file mode 100644
index 0000000000..bfb1470f71
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8909.yml
@@ -0,0 +1,4 @@
+author: "Ghommie"
+delete-after: True
+changes:
+ - bugfix: "Fixes krav maga gloves, wizard spells knockdowns."
diff --git a/html/changelogs/AutoChangeLog-pr-8912.yml b/html/changelogs/AutoChangeLog-pr-8912.yml
new file mode 100644
index 0000000000..5d5a7c38fc
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8912.yml
@@ -0,0 +1,6 @@
+author: "Ghommie (original PRs by ShizCalev and bobbahbrown)"
+delete-after: True
+changes:
+ - rscadd: "Headsets now dynamically show in their description how to speak on any channels they can use when held or worn."
+ - code_imp: "Radio channels names and keys now use defines."
+ - tweak: "The head arrival announcement will now be broadcast to the supply for the quartermaster."
diff --git a/html/changelogs/AutoChangeLog-pr-8913.yml b/html/changelogs/AutoChangeLog-pr-8913.yml
new file mode 100644
index 0000000000..ccac6aef16
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8913.yml
@@ -0,0 +1,4 @@
+author: "Trilbyspaceclone"
+delete-after: True
+changes:
+ - rscadd: "Added new chairs"
diff --git a/html/changelogs/AutoChangeLog-pr-8915.yml b/html/changelogs/AutoChangeLog-pr-8915.yml
new file mode 100644
index 0000000000..5e3e0e77a9
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8915.yml
@@ -0,0 +1,6 @@
+author: "Ghommie"
+delete-after: True
+changes:
+ - tweak: "Added in an alert pop up to the cult convertees, on top of the older \"click here to become a blood cultist\" chat message."
+ - tweak: "The convertee's screen will now flash red to fit in the aforementioned message's fluff."
+ - spellcheck: "Made said message less verbose."
diff --git a/html/changelogs/AutoChangeLog-pr-8917.yml b/html/changelogs/AutoChangeLog-pr-8917.yml
new file mode 100644
index 0000000000..2b858cad47
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8917.yml
@@ -0,0 +1,4 @@
+author: "Bhijn"
+delete-after: True
+changes:
+ - bugfix: "Warp whistles no longer grant permanent invulnerability and invisibility"
diff --git a/html/changelogs/AutoChangeLog-pr-8920.yml b/html/changelogs/AutoChangeLog-pr-8920.yml
new file mode 100644
index 0000000000..6d3ae3ada4
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8920.yml
@@ -0,0 +1,5 @@
+author: "Ghommie"
+delete-after: True
+changes:
+ - rscadd: "Towels. Crafted with 3 sheets of cloth, they can be worn on head, suit and belt slots even without uniform, or laid flat on the floor. Sprites from Baystation and Aurora Station."
+ - rscadd: "You can combat mode right click people while wielding rags and towels to pat out their flames (to no use for rags) or otherwise drying them out."
diff --git a/html/changelogs/AutoChangeLog-pr-8921.yml b/html/changelogs/AutoChangeLog-pr-8921.yml
new file mode 100644
index 0000000000..9c1c456f7f
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8921.yml
@@ -0,0 +1,4 @@
+author: "Trilbyspaceclone"
+delete-after: True
+changes:
+ - admin: "Bugtesting zone upgrades for easy bug/game testing"
diff --git a/html/changelogs/AutoChangeLog-pr-8922.yml b/html/changelogs/AutoChangeLog-pr-8922.yml
new file mode 100644
index 0000000000..1e641bd424
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8922.yml
@@ -0,0 +1,4 @@
+author: "BurgerBB"
+delete-after: True
+changes:
+ - rscadd: "Gamemode voting results are displayed at the end-round screen."
diff --git a/html/changelogs/AutoChangeLog-pr-8925.yml b/html/changelogs/AutoChangeLog-pr-8925.yml
new file mode 100644
index 0000000000..ddc90eba19
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8925.yml
@@ -0,0 +1,4 @@
+author: "BurgerLUA"
+delete-after: True
+changes:
+ - bugfix: "Fixed autolathe wires not correctly shocking you when pulsed."
diff --git a/html/changelogs/AutoChangeLog-pr-8926.yml b/html/changelogs/AutoChangeLog-pr-8926.yml
new file mode 100644
index 0000000000..762318ab21
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8926.yml
@@ -0,0 +1,4 @@
+author: "Fermis"
+delete-after: True
+changes:
+ - rscadd: "Added the secbat, a box to hold it and the ability to dispense it from the SecTech vendor."
diff --git a/html/changelogs/AutoChangeLog-pr-8927.yml b/html/changelogs/AutoChangeLog-pr-8927.yml
new file mode 100644
index 0000000000..3a87d7652e
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8927.yml
@@ -0,0 +1,5 @@
+author: "Ghommie"
+delete-after: True
+changes:
+ - balance: "toned down the stamina costs of some of the bulkier weapons."
+ - code_imp: "repathed hypereutactic blades to be a subtype of dual sabers. Way less copypasta."
diff --git a/html/changelogs/AutoChangeLog-pr-8929.yml b/html/changelogs/AutoChangeLog-pr-8929.yml
new file mode 100644
index 0000000000..4fed45f1d0
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8929.yml
@@ -0,0 +1,5 @@
+author: "Ghommie"
+delete-after: True
+changes:
+ - bugfix: "Fixing CX Shredder guns not accepting standard flechette mags."
+ - bugfix: "Fixing missing magpistol magazines icon states."
diff --git a/html/changelogs/AutoChangeLog-pr-8931.yml b/html/changelogs/AutoChangeLog-pr-8931.yml
new file mode 100644
index 0000000000..2bde1025db
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8931.yml
@@ -0,0 +1,4 @@
+author: "Trilbyspaceclone"
+delete-after: True
+changes:
+ - rscadd: "more cargo to cargo"
diff --git a/html/changelogs/AutoChangeLog-pr-8933.yml b/html/changelogs/AutoChangeLog-pr-8933.yml
new file mode 100644
index 0000000000..09d318be08
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8933.yml
@@ -0,0 +1,4 @@
+author: "BurgerBB"
+delete-after: True
+changes:
+ - balance: "Cloning no longer gives you positive mutations, but a chance for a negative one. Cloning has a chance to \"scramble\" your visual DNA."
diff --git a/html/changelogs/AutoChangeLog-pr-8934.yml b/html/changelogs/AutoChangeLog-pr-8934.yml
new file mode 100644
index 0000000000..e86e47a45f
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8934.yml
@@ -0,0 +1,4 @@
+author: "Trilbyspaceclone"
+delete-after: True
+changes:
+ - rscadd: "More loadout gear"
diff --git a/html/changelogs/AutoChangeLog-pr-8939.yml b/html/changelogs/AutoChangeLog-pr-8939.yml
new file mode 100644
index 0000000000..6041d66721
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8939.yml
@@ -0,0 +1,9 @@
+author: "Ghommie"
+delete-after: True
+changes:
+ - rscadd: "The syndicate base's bathroom is now fitted with a shower, and a special towel."
+ - bugfix: "Fixed many issues with towels."
+ - tweak: "The dry people off with rags/towels action can only be done if the object is NOT moist with reagents now. Also cleans banana creaming."
+ - rscadd: "Towels deal more damage while soaked with reagents."
+ - rscadd: "You can now squeeze rags/towels with Alt-Click."
+ - rscdel: "deleted an old and crappier towel sprite that got in the way."
diff --git a/html/changelogs/AutoChangeLog-pr-8942.yml b/html/changelogs/AutoChangeLog-pr-8942.yml
new file mode 100644
index 0000000000..a1b80ba839
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8942.yml
@@ -0,0 +1,4 @@
+author: "Chayse"
+delete-after: True
+changes:
+ - tweak: "Changed the Warden's compact combat shotgun to instead be a regular combat shotgun with a foldable stock and penalties for being folded."
diff --git a/html/changelogs/AutoChangeLog-pr-8945.yml b/html/changelogs/AutoChangeLog-pr-8945.yml
new file mode 100644
index 0000000000..afa9bdaa95
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8945.yml
@@ -0,0 +1,4 @@
+author: "Ghommie"
+delete-after: True
+changes:
+ - bugfix: "Fixes Pubby's disposal conveyor belts and lack of a second lawyer spawner."
diff --git a/html/changelogs/AutoChangeLog-pr-8949.yml b/html/changelogs/AutoChangeLog-pr-8949.yml
new file mode 100644
index 0000000000..83560d74f2
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8949.yml
@@ -0,0 +1,4 @@
+author: "Trilbyspaceclone"
+delete-after: True
+changes:
+ - bugfix: "Poojawa power creep"
diff --git a/html/changelogs/AutoChangeLog-pr-8950.yml b/html/changelogs/AutoChangeLog-pr-8950.yml
new file mode 100644
index 0000000000..62b90d2407
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8950.yml
@@ -0,0 +1,4 @@
+author: "Trilbyspaceclone"
+delete-after: True
+changes:
+ - bugfix: "Not my work not my credit"
diff --git a/html/changelogs/AutoChangeLog-pr-8952.yml b/html/changelogs/AutoChangeLog-pr-8952.yml
new file mode 100644
index 0000000000..df2ff22d09
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8952.yml
@@ -0,0 +1,4 @@
+author: "CdrCross"
+delete-after: True
+changes:
+ - rscadd: "Adds the ability for cloning consoles to read and write record lists to the circuit board, and provides a template for giving other machines local circuit board memory."
diff --git a/html/changelogs/AutoChangeLog-pr-8953.yml b/html/changelogs/AutoChangeLog-pr-8953.yml
new file mode 100644
index 0000000000..2128149556
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8953.yml
@@ -0,0 +1,5 @@
+author: "Toriate"
+delete-after: True
+changes:
+ - rscadd: "RPD now has inhands"
+ - imageadd: "New sprites for RCDs and RPDs, inhands included"
diff --git a/html/changelogs/AutoChangeLog-pr-8956.yml b/html/changelogs/AutoChangeLog-pr-8956.yml
new file mode 100644
index 0000000000..d6d33b3bd2
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8956.yml
@@ -0,0 +1,4 @@
+author: "CameronWoof"
+delete-after: True
+changes:
+ - tweak: "Altered the icons for inventory backplates. Sleek! Stylish! New!"
diff --git a/html/changelogs/AutoChangeLog-pr-8958.yml b/html/changelogs/AutoChangeLog-pr-8958.yml
new file mode 100644
index 0000000000..a800b1b218
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8958.yml
@@ -0,0 +1,4 @@
+author: "Trilbyspaceclone"
+delete-after: True
+changes:
+ - rscadd: "Emitter gun"
diff --git a/html/changelogs/AutoChangeLog-pr-8959.yml b/html/changelogs/AutoChangeLog-pr-8959.yml
new file mode 100644
index 0000000000..87ca24462e
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8959.yml
@@ -0,0 +1,4 @@
+author: "Trilbyspaceclone"
+delete-after: True
+changes:
+ - bugfix: "suit storage nulling anti magic item protection"
diff --git a/html/changelogs/AutoChangeLog-pr-8964.yml b/html/changelogs/AutoChangeLog-pr-8964.yml
new file mode 100644
index 0000000000..6675fecc50
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8964.yml
@@ -0,0 +1,5 @@
+author: "Trilbyspaceclone"
+delete-after: True
+changes:
+ - balance: "rebalanced steal goals restrictions"
+ - spellcheck: "fixed a few misleading goals"
diff --git a/html/changelogs/AutoChangeLog-pr-8965.yml b/html/changelogs/AutoChangeLog-pr-8965.yml
new file mode 100644
index 0000000000..138991e507
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8965.yml
@@ -0,0 +1,4 @@
+author: "Trilbyspaceclone"
+delete-after: True
+changes:
+ - bugfix: "ports a fix"
diff --git a/html/changelogs/AutoChangeLog-pr-8966.yml b/html/changelogs/AutoChangeLog-pr-8966.yml
new file mode 100644
index 0000000000..2d63b8356e
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8966.yml
@@ -0,0 +1,4 @@
+author: "Poojawa"
+delete-after: True
+changes:
+ - imageadd: "RCL now show what color is currently in use"
diff --git a/html/changelogs/AutoChangeLog-pr-8968.yml b/html/changelogs/AutoChangeLog-pr-8968.yml
new file mode 100644
index 0000000000..0a0b0e84d0
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8968.yml
@@ -0,0 +1,4 @@
+author: "Trilbyspaceclone"
+delete-after: True
+changes:
+ - bugfix: "oversight in benos"
diff --git a/html/changelogs/AutoChangeLog-pr-8970.yml b/html/changelogs/AutoChangeLog-pr-8970.yml
new file mode 100644
index 0000000000..304c9115dc
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8970.yml
@@ -0,0 +1,6 @@
+author: "original by @randolfthemeh and @twaticus, port by sishen1542"
+delete-after: True
+changes:
+ - rscadd: "jumpskirts"
+ - rscadd: "more jumpskirts"
+ - rscadd: "jumpskirt/suit prefs"
diff --git a/html/changelogs/AutoChangeLog-pr-8971.yml b/html/changelogs/AutoChangeLog-pr-8971.yml
new file mode 100644
index 0000000000..c5b5215ff9
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8971.yml
@@ -0,0 +1,4 @@
+author: "Linzolle"
+delete-after: True
+changes:
+ - tweak: "slime people now enjoy eating toxic food and it will not disgust them"
diff --git a/html/changelogs/AutoChangeLog-pr-8974.yml b/html/changelogs/AutoChangeLog-pr-8974.yml
new file mode 100644
index 0000000000..b71dc88ecd
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8974.yml
@@ -0,0 +1,4 @@
+author: "EgoSumStultus"
+delete-after: True
+changes:
+ - bugfix: "Fixed blood chiller's inhand"
diff --git a/html/changelogs/AutoChangeLog-pr-8976.yml b/html/changelogs/AutoChangeLog-pr-8976.yml
new file mode 100644
index 0000000000..67e7bbc11a
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8976.yml
@@ -0,0 +1,4 @@
+author: "Ghommie"
+delete-after: True
+changes:
+ - bugfix: "combat pushes will now properly stop targets from using firearms, and will disarm the firearm if performed a second time, and also slow down people by 15%, and won't push people on tables blocked by shutters or other dense object anymore."
diff --git a/html/changelogs/AutoChangeLog-pr-8978.yml b/html/changelogs/AutoChangeLog-pr-8978.yml
new file mode 100644
index 0000000000..56e3760e9c
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8978.yml
@@ -0,0 +1,4 @@
+author: "Yakumo Chen"
+delete-after: True
+changes:
+ - balance: "Made stealth implant boxes flimsier"
diff --git a/html/changelogs/AutoChangeLog-pr-8979.yml b/html/changelogs/AutoChangeLog-pr-8979.yml
new file mode 100644
index 0000000000..f826fcd681
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8979.yml
@@ -0,0 +1,4 @@
+author: "Ghommie"
+delete-after: True
+changes:
+ - bugfix: "Fixes CHECK_BITFIELD macro."
diff --git a/html/changelogs/AutoChangeLog-pr-8980.yml b/html/changelogs/AutoChangeLog-pr-8980.yml
new file mode 100644
index 0000000000..caba11ae69
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8980.yml
@@ -0,0 +1,5 @@
+author: "Ghommie"
+delete-after: True
+changes:
+ - bugfix: "Fixes hypovials being unable to transfer out liquids or be refilled by large dispensers like water tanks."
+ - bugfix: "Fixes chem-masters machineries not dispensing newly made pills inside loaded in pill bottles."
diff --git a/html/changelogs/AutoChangeLog-pr-8982.yml b/html/changelogs/AutoChangeLog-pr-8982.yml
new file mode 100644
index 0000000000..8599966d64
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8982.yml
@@ -0,0 +1,6 @@
+author: "Ghommie (original PR by Skoglol)"
+delete-after: True
+changes:
+ - bugfix: "Mining bags will no longer drop ore into backpack."
+ - bugfix: "Mining bags in backpack no longer interferes with other mining bags."
+ - bugfix: "Fixes some storage size circumventions."
diff --git a/html/changelogs/AutoChangeLog-pr-8984.yml b/html/changelogs/AutoChangeLog-pr-8984.yml
new file mode 100644
index 0000000000..31c45cdbc6
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8984.yml
@@ -0,0 +1,4 @@
+author: "Ghommie"
+delete-after: True
+changes:
+ - rscadd: "Stunswords now fit in the captain's sabre sheat."
diff --git a/html/changelogs/AutoChangeLog-pr-8985.yml b/html/changelogs/AutoChangeLog-pr-8985.yml
new file mode 100644
index 0000000000..37aaa4162d
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8985.yml
@@ -0,0 +1,4 @@
+author: "Linzolle"
+delete-after: True
+changes:
+ - bugfix: "hos trenchcloak now properly has a sprite on digi characters"
diff --git a/html/changelogs/AutoChangeLog-pr-8986.yml b/html/changelogs/AutoChangeLog-pr-8986.yml
new file mode 100644
index 0000000000..810631f5f5
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8986.yml
@@ -0,0 +1,6 @@
+author: "Ghommie"
+delete-after: True
+changes:
+ - rscadd: "reworked ninja's stealth mode. Increased invisibility, but engaging in combat, attacking or throwing things, bumping people will temporarily lower it."
+ - rscadd: "Ninja shoes are even stealthier."
+ - code_imp: "cleaned up some 2014 tier processing code horror."
diff --git a/html/changelogs/AutoChangeLog-pr-8988.yml b/html/changelogs/AutoChangeLog-pr-8988.yml
new file mode 100644
index 0000000000..9145d73c01
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8988.yml
@@ -0,0 +1,5 @@
+author: "kiwedespars"
+delete-after: True
+changes:
+ - rscadd: "regenerative materia to hallucination sting"
+ - rscadd: "mindbreaker toxin as an actual chemical to hallucination sting"
diff --git a/html/changelogs/AutoChangeLog-pr-8991.yml b/html/changelogs/AutoChangeLog-pr-8991.yml
new file mode 100644
index 0000000000..138991e507
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8991.yml
@@ -0,0 +1,4 @@
+author: "Trilbyspaceclone"
+delete-after: True
+changes:
+ - bugfix: "ports a fix"
diff --git a/html/changelogs/AutoChangeLog-pr-8992.yml b/html/changelogs/AutoChangeLog-pr-8992.yml
new file mode 100644
index 0000000000..299792fee3
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8992.yml
@@ -0,0 +1,5 @@
+author: "Chayse"
+delete-after: True
+changes:
+ - rscadd: "Assorted space-worthy helmets can now act as masks for internals."
+ - refactor: "Internals code can now check any item with the ALLOWSINTERNALS flag through the GET_INTERNAL_SLOTS define. For now this only checks head and mask slots, since those are the most realistically speaking usable ones."
diff --git a/html/changelogs/AutoChangeLog-pr-8994.yml b/html/changelogs/AutoChangeLog-pr-8994.yml
new file mode 100644
index 0000000000..a3a4fef0b7
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8994.yml
@@ -0,0 +1,4 @@
+author: "Ghommie"
+delete-after: True
+changes:
+ - tweak: "the oxyloss fullscreen overlays now also take in consideration 1/5 of the user stamina loss."
diff --git a/html/changelogs/AutoChangeLog-pr-8995.yml b/html/changelogs/AutoChangeLog-pr-8995.yml
new file mode 100644
index 0000000000..76669d7821
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8995.yml
@@ -0,0 +1,4 @@
+author: "Ghommie"
+delete-after: True
+changes:
+ - rscadd: "When you're jogging, you will only slip on water if you have more than 20% staminaloss, for real this time."
diff --git a/html/changelogs/AutoChangeLog-pr-8996.yml b/html/changelogs/AutoChangeLog-pr-8996.yml
new file mode 100644
index 0000000000..7c631e3301
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8996.yml
@@ -0,0 +1,4 @@
+author: "Ghommie"
+delete-after: True
+changes:
+ - imageadd: "Different cuffs now come with different worn overlays instead of a generic one."
diff --git a/html/changelogs/AutoChangeLog-pr-8998.yml b/html/changelogs/AutoChangeLog-pr-8998.yml
new file mode 100644
index 0000000000..981e746fc9
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8998.yml
@@ -0,0 +1,4 @@
+author: "Ghommie"
+delete-after: True
+changes:
+ - bugfix: "High luminosity eyes can now be properly deactivated and won't illuminate your surroundings again until turned back on."
diff --git a/html/changelogs/AutoChangeLog-pr-8999.yml b/html/changelogs/AutoChangeLog-pr-8999.yml
new file mode 100644
index 0000000000..182e3a8409
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8999.yml
@@ -0,0 +1,4 @@
+author: "BurgerBB"
+delete-after: True
+changes:
+ - balance: "Chestbursters no longer give and remove your brain. They just disembowel and kill you now."
diff --git a/html/changelogs/AutoChangeLog-pr-9000.yml b/html/changelogs/AutoChangeLog-pr-9000.yml
new file mode 100644
index 0000000000..3fa3e8946f
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9000.yml
@@ -0,0 +1,4 @@
+author: "EgoSumStultus"
+delete-after: True
+changes:
+ - bugfix: "FIXED SHIELF"
diff --git a/html/changelogs/AutoChangeLog-pr-9001.yml b/html/changelogs/AutoChangeLog-pr-9001.yml
new file mode 100644
index 0000000000..be2fd2b833
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9001.yml
@@ -0,0 +1,4 @@
+author: "Linzolle"
+delete-after: True
+changes:
+ - rscdel: "duplicate definition of hos and sec skirts"
diff --git a/html/changelogs/AutoChangeLog-pr-9005.yml b/html/changelogs/AutoChangeLog-pr-9005.yml
new file mode 100644
index 0000000000..d65017a00d
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9005.yml
@@ -0,0 +1,4 @@
+author: "Trilbyspaceclone"
+delete-after: True
+changes:
+ - bugfix: "QM rooms not getting Key Aunths"
diff --git a/html/changelogs/AutoChangeLog-pr-9008.yml b/html/changelogs/AutoChangeLog-pr-9008.yml
new file mode 100644
index 0000000000..0c73bc8ae9
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9008.yml
@@ -0,0 +1,4 @@
+author: "Linzolle"
+delete-after: True
+changes:
+ - bugfix: "Krav Maga leg sweep now works properly."
diff --git a/html/changelogs/AutoChangeLog-pr-9009.yml b/html/changelogs/AutoChangeLog-pr-9009.yml
new file mode 100644
index 0000000000..21cf0c8d85
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9009.yml
@@ -0,0 +1,4 @@
+author: "BurgerBB"
+delete-after: True
+changes:
+ - bugfix: "Fixes WarOps miscalculating players."
diff --git a/html/changelogs/AutoChangeLog-pr-9010.yml b/html/changelogs/AutoChangeLog-pr-9010.yml
new file mode 100644
index 0000000000..52aed38e2c
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9010.yml
@@ -0,0 +1,4 @@
+author: "BurgerBB"
+delete-after: True
+changes:
+ - balance: "Activating the nuclear device during war-ops informs the crew of the nuke's position."
diff --git a/html/changelogs/AutoChangeLog-pr-9014.yml b/html/changelogs/AutoChangeLog-pr-9014.yml
new file mode 100644
index 0000000000..f217b64afd
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9014.yml
@@ -0,0 +1,4 @@
+author: "Ghommie"
+delete-after: True
+changes:
+ - bugfix: "Fixes freshly cloned people starting with undershirts. Fixes random characters possibly rolling with undergarments of the opposite gender (Doesn't affect preferences' freedom of choice)."
diff --git a/html/changelogs/AutoChangeLog-pr-9018.yml b/html/changelogs/AutoChangeLog-pr-9018.yml
new file mode 100644
index 0000000000..7acb63b426
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9018.yml
@@ -0,0 +1,12 @@
+author: "Ghommie (original PRs by XDTM, optimumtact, Nichlas0010 and monster860)"
+delete-after: True
+changes:
+ - rscadd: "Added Quantum Keycards, devices that can link to a quantum pad, and can be used on any other quantum pad to teleport to its linked pad.
+spellchecking: Renamed \"Bluespace Teleportation Tech\" tech node to \"Bluespace Travel\"."
+ - tweak: "Moved roasting sticks from the \"Bluespace Travel\" to \"Practical Bluespace\"."
+ - rscadd: "Spraying holy water on tiles will now prevent cult-based teleportation from using them as a destination point."
+ - tweak: "Quantum, wormhole and magic teleportation is no longer disrupted by bags of holding."
+ - bugfix: "You are now also blocked from teleporting IN to no-teleport areas, not just out of them."
+ - tweak: "Quantum teleportation now makes pretty rainbow sparks instead of the normal ones."
+ - bugfix: "Non-bluespace teleportation (spells etc.) no longer makes sparks."
+ - bugfix: "Fixed teleportation deleting mob spawners like golem shells and ashwalker eggs."
diff --git a/html/changelogs/AutoChangeLog-pr-9019.yml b/html/changelogs/AutoChangeLog-pr-9019.yml
new file mode 100644
index 0000000000..8006c134e3
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9019.yml
@@ -0,0 +1,6 @@
+author: "Ghommie"
+delete-after: True
+changes:
+ - balance: "MRE menu 3 has cuban nachos instead of a chili now."
+ - bugfix: "Removed the illustration overlay from MREs, looks pretty weird otherwise."
+ - rscadd: "MRE menu 4, vegetarian."
diff --git a/html/changelogs/AutoChangeLog-pr-9021.yml b/html/changelogs/AutoChangeLog-pr-9021.yml
new file mode 100644
index 0000000000..e8809f1d7e
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9021.yml
@@ -0,0 +1,4 @@
+author: "Ghommie (by Floyd / Qustinnus, Arathian)"
+delete-after: True
+changes:
+ - rscadd: "The robotocist now has robe to show his love for toasters"
diff --git a/html/changelogs/AutoChangeLog-pr-9022.yml b/html/changelogs/AutoChangeLog-pr-9022.yml
new file mode 100644
index 0000000000..4fb48506e4
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9022.yml
@@ -0,0 +1,4 @@
+author: "Ghommie (by nemvar)"
+delete-after: True
+changes:
+ - tweak: "Dwarfs are now more robust."
diff --git a/html/changelogs/AutoChangeLog-pr-9024.yml b/html/changelogs/AutoChangeLog-pr-9024.yml
new file mode 100644
index 0000000000..1d75959c79
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9024.yml
@@ -0,0 +1,4 @@
+author: "Ghommie (by Arkatos)"
+delete-after: True
+changes:
+ - bugfix: "Fixed an issue with a Lizardwine drink crafting, where a final product would contain unwated 100u of Ethanol."
diff --git a/html/changelogs/AutoChangeLog-pr-9026.yml b/html/changelogs/AutoChangeLog-pr-9026.yml
new file mode 100644
index 0000000000..bf8ce9efbe
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9026.yml
@@ -0,0 +1,4 @@
+author: "BurgerBB"
+delete-after: True
+changes:
+ - rscadd: "The alert level is displayed at the job selection screen."
diff --git a/html/changelogs/AutoChangeLog-pr-9030.yml b/html/changelogs/AutoChangeLog-pr-9030.yml
new file mode 100644
index 0000000000..94c797433a
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9030.yml
@@ -0,0 +1,4 @@
+author: "CameronWoof"
+delete-after: True
+changes:
+ - bugfix: "Attaching a beaker that contains water to an IV stand no longer causes a visual glitch"
diff --git a/html/changelogs/AutoChangeLog-pr-9033.yml b/html/changelogs/AutoChangeLog-pr-9033.yml
new file mode 100644
index 0000000000..3e69bc9486
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9033.yml
@@ -0,0 +1,4 @@
+author: "EgoSumStultus"
+delete-after: True
+changes:
+ - bugfix: "fixed magpistol magazine sprites"
diff --git a/html/changelogs/AutoChangeLog-pr-9036.yml b/html/changelogs/AutoChangeLog-pr-9036.yml
new file mode 100644
index 0000000000..afd2882fc3
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9036.yml
@@ -0,0 +1,5 @@
+author: "Linzolle"
+delete-after: True
+changes:
+ - rscadd: "shoes can have a different icon used for their item and mob icons"
+ - bugfix: "combat gloves plus having no mob icon"
diff --git a/html/changelogs/AutoChangeLog-pr-9040.yml b/html/changelogs/AutoChangeLog-pr-9040.yml
new file mode 100644
index 0000000000..33958a2ece
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9040.yml
@@ -0,0 +1,4 @@
+author: "Trilbyspaceclone"
+delete-after: True
+changes:
+ - rscadd: "new books/cooking"
diff --git a/html/changelogs/AutoChangeLog-pr-9042.yml b/html/changelogs/AutoChangeLog-pr-9042.yml
new file mode 100644
index 0000000000..38c4006383
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9042.yml
@@ -0,0 +1,4 @@
+author: "EgoSumStultus"
+delete-after: True
+changes:
+ - rscadd: "Added the Femur Breaker"
diff --git a/html/changelogs/AutoChangeLog-pr-9043.yml b/html/changelogs/AutoChangeLog-pr-9043.yml
new file mode 100644
index 0000000000..14c9331e5b
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9043.yml
@@ -0,0 +1,7 @@
+author: "chef"
+delete-after: True
+changes:
+ - rscadd: "Added main hallway approach to monastery"
+ - rscadd: "Added Maintenance hallway approach, with some maint loot"
+ - tweak: "moved the docking arm for the white ship"
+ - tweak: "changed placement of some grills and windows"
diff --git a/html/changelogs/AutoChangeLog-pr-9044.yml b/html/changelogs/AutoChangeLog-pr-9044.yml
new file mode 100644
index 0000000000..6133ea45e9
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9044.yml
@@ -0,0 +1,7 @@
+author: "Original by Citinited, port by Sishen1542"
+delete-after: True
+changes:
+ - rscadd: "You can now use an airlock electronics on a locker to add a lock, and can screwdriver an unlocked locker to remove its lock."
+ - rscadd: "You can now remove the locks on broken or emagged lockers."
+ - tweak: "Removing the lock from a personal locker now wipes that locker's ID details."
+ - tweak: "Broken lockers have had their appearance changed."
diff --git a/html/changelogs/AutoChangeLog-pr-9045.yml b/html/changelogs/AutoChangeLog-pr-9045.yml
new file mode 100644
index 0000000000..8917707ae3
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9045.yml
@@ -0,0 +1,8 @@
+author: "CameronWoof"
+delete-after: True
+changes:
+ - tweak: "Fluid-producing sexual organs no longer start full"
+ - tweak: "Sexual organ fluid capacity decreased from 50 to 15"
+ - tweak: "Sexual organ production rate decreased from 5u to 0.035u per two seconds."
+ - tweak: "Sexual fluid decals no longer contain reagents"
+ - tweak: "Sexual fluids cannot by synthesized (e.g., by the Odysseus)"
diff --git a/html/changelogs/AutoChangeLog-pr-9046.yml b/html/changelogs/AutoChangeLog-pr-9046.yml
new file mode 100644
index 0000000000..24e7035a88
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9046.yml
@@ -0,0 +1,4 @@
+author: "Sishen1542"
+delete-after: True
+changes:
+ - tweak: "density = 0"
diff --git a/html/changelogs/AutoChangeLog-pr-9050.yml b/html/changelogs/AutoChangeLog-pr-9050.yml
new file mode 100644
index 0000000000..3b12a12f17
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9050.yml
@@ -0,0 +1,4 @@
+author: "Ghommie"
+delete-after: True
+changes:
+ - bugfix: "fixes a few bad touchs on combat mode pushing."
diff --git a/html/changelogs/AutoChangeLog-pr-9052.yml b/html/changelogs/AutoChangeLog-pr-9052.yml
new file mode 100644
index 0000000000..a75b6c51ae
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9052.yml
@@ -0,0 +1,4 @@
+author: "kevinz000"
+delete-after: True
+changes:
+ - balance: "Hierophant now goes sicko mode, but hey, at least you can't be multi-hit by melee waves!"
diff --git a/html/changelogs/AutoChangeLog-pr-9054.yml b/html/changelogs/AutoChangeLog-pr-9054.yml
new file mode 100644
index 0000000000..5952c9ecfd
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9054.yml
@@ -0,0 +1,4 @@
+author: "Sishen1542"
+delete-after: True
+changes:
+ - balance: "hugboxing mining loot"
diff --git a/html/changelogs/AutoChangeLog-pr-9061.yml b/html/changelogs/AutoChangeLog-pr-9061.yml
new file mode 100644
index 0000000000..4fc9d10ba5
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9061.yml
@@ -0,0 +1,5 @@
+author: "deathride58"
+delete-after: True
+changes:
+ - tweak: "The femur breaker now uses `*scream` instead of forced speech. This means that the femur breaker will no longer spam deadchat with \"AAAAAAAAAHHHHHHHHHH!!\""
+ - tweak: "The femur breaker will now guarantee that the victim falls into crit, which will make it harder to perform torture scenes with it since the victim can just succumb."
diff --git a/html/changelogs/AutoChangeLog-pr-9062.yml b/html/changelogs/AutoChangeLog-pr-9062.yml
new file mode 100644
index 0000000000..12102204c3
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9062.yml
@@ -0,0 +1,4 @@
+author: "Trilbyspaceclone"
+delete-after: True
+changes:
+ - spellcheck: "less bad wording in slime"
diff --git a/html/changelogs/AutoChangeLog-pr-9064.yml b/html/changelogs/AutoChangeLog-pr-9064.yml
new file mode 100644
index 0000000000..6e775c1eb4
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9064.yml
@@ -0,0 +1,4 @@
+author: "Cebutris"
+delete-after: True
+changes:
+ - rscadd: "Hugs of the North Star! Get them from the arcades (if you're lucky) and hug your friends at INCREDIBLE hihg speeds!"
diff --git a/html/changelogs/AutoChangeLog-pr-9069.yml b/html/changelogs/AutoChangeLog-pr-9069.yml
new file mode 100644
index 0000000000..0439515dd3
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9069.yml
@@ -0,0 +1,4 @@
+author: "Ghommie"
+delete-after: True
+changes:
+ - bugfix: "Fixes clock cult Abscond scripture not dragging pulled mobs into Reebe. Also fixes blood cult tele runes teleporting you from the source turf to the source turf."
diff --git a/html/changelogs/AutoChangeLog-pr-9070.yml b/html/changelogs/AutoChangeLog-pr-9070.yml
new file mode 100644
index 0000000000..2013550dd2
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9070.yml
@@ -0,0 +1,5 @@
+author: "Linzolle"
+delete-after: True
+changes:
+ - rscadd: "inhands sprite for rainbow knife"
+ - tweak: "colour of highlight on the regular knife when held in the right hand"
diff --git a/html/changelogs/AutoChangeLog-pr-9071.yml b/html/changelogs/AutoChangeLog-pr-9071.yml
new file mode 100644
index 0000000000..40ae43867f
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9071.yml
@@ -0,0 +1,4 @@
+author: "Yakumo Chen"
+delete-after: True
+changes:
+ - balance: "Autocloning now requires tier 4 parts"
diff --git a/html/changelogs/AutoChangeLog-pr-9078.yml b/html/changelogs/AutoChangeLog-pr-9078.yml
new file mode 100644
index 0000000000..2e202ec43a
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9078.yml
@@ -0,0 +1,7 @@
+author: "kappa-sama"
+delete-after: True
+changes:
+ - rscdel: "Removed racism"
+ - tweak: "Teleporter calibration actually matters to all roundstart players"
+ - balance: "Slows down teleportation with the console/hub/teleporter setup if you care for your species."
+ - balance: "Dedicated non-humans can now get hulk without having to become human."
diff --git a/html/changelogs/AutoChangeLog-pr-9079.yml b/html/changelogs/AutoChangeLog-pr-9079.yml
new file mode 100644
index 0000000000..42aa732e16
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9079.yml
@@ -0,0 +1,4 @@
+author: "Sishen1542"
+delete-after: True
+changes:
+ - balance: "ling blade now has 40 armor pen"
diff --git a/html/changelogs/AutoChangeLog-pr-9081.yml b/html/changelogs/AutoChangeLog-pr-9081.yml
new file mode 100644
index 0000000000..c66148e446
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9081.yml
@@ -0,0 +1,4 @@
+author: "BurgerBB"
+delete-after: True
+changes:
+ - balance: "Central Command informs you when a Meteor Storm is about to hit 5 to 10 minutes before it happens."
diff --git a/html/changelogs/AutoChangeLog-pr-9083.yml b/html/changelogs/AutoChangeLog-pr-9083.yml
new file mode 100644
index 0000000000..74b4d95ca3
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9083.yml
@@ -0,0 +1,4 @@
+author: "Trilbyspaceclone"
+delete-after: True
+changes:
+ - rscadd: "strawbarries and such"
diff --git a/html/changelogs/AutoChangeLog-pr-9084.yml b/html/changelogs/AutoChangeLog-pr-9084.yml
new file mode 100644
index 0000000000..c2569d10b4
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9084.yml
@@ -0,0 +1,4 @@
+author: "Ghommie"
+delete-after: True
+changes:
+ - bugfix: "fixes clock cult mass recall."
diff --git a/html/changelogs/AutoChangeLog-pr-9085.yml b/html/changelogs/AutoChangeLog-pr-9085.yml
new file mode 100644
index 0000000000..92f5dc4cf8
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9085.yml
@@ -0,0 +1,4 @@
+author: "Ghommie"
+delete-after: True
+changes:
+ - bugfix: "Fixes underwear colors a bit."
diff --git a/html/changelogs/AutoChangeLog-pr-9097.yml b/html/changelogs/AutoChangeLog-pr-9097.yml
new file mode 100644
index 0000000000..941c0e7b98
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9097.yml
@@ -0,0 +1,4 @@
+author: "lolman360"
+delete-after: True
+changes:
+ - rscadd: "NT has authorized shipments or Cotton to Megaseed Servitors. It's time to start picking, liggers."
diff --git a/html/changelogs/AutoChangeLog-pr-9098.yml b/html/changelogs/AutoChangeLog-pr-9098.yml
new file mode 100644
index 0000000000..6e11eaeb90
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9098.yml
@@ -0,0 +1,4 @@
+author: "Cebutris"
+delete-after: True
+changes:
+ - bugfix: "Tea Aspera now properly contains tea powder"
diff --git a/html/changelogs/AutoChangeLog-pr-9100.yml b/html/changelogs/AutoChangeLog-pr-9100.yml
new file mode 100644
index 0000000000..81141b3b0c
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9100.yml
@@ -0,0 +1,4 @@
+author: "Cebutris"
+delete-after: True
+changes:
+ - tweak: "Breasts no longer lactate by default, lactation is now a preference"
diff --git a/html/changelogs/AutoChangeLog-pr-9101.yml b/html/changelogs/AutoChangeLog-pr-9101.yml
new file mode 100644
index 0000000000..174619dd49
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9101.yml
@@ -0,0 +1,4 @@
+author: "Sishen1542, original by XDTM"
+delete-after: True
+changes:
+ - rscadd: "Surgery steps are now shown in detail only to the surgeon and anyone standing adjacent to them; the patient and people watching from further away get a more vague/ambiguous description."
diff --git a/html/changelogs/AutoChangeLog-pr-9107.yml b/html/changelogs/AutoChangeLog-pr-9107.yml
new file mode 100644
index 0000000000..65a14b9576
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9107.yml
@@ -0,0 +1,4 @@
+author: "Bhijn"
+delete-after: True
+changes:
+ - bugfix: "You can now actually use the resist hotkey to resist out of handcuffs. Woah, revolutionary"
diff --git a/html/changelogs/AutoChangeLog-pr-9113.yml b/html/changelogs/AutoChangeLog-pr-9113.yml
new file mode 100644
index 0000000000..1bdae7cab9
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9113.yml
@@ -0,0 +1,5 @@
+author: "Fermis"
+delete-after: True
+changes:
+ - bugfix: "fixes fermichem reactions for tiny volumes work"
+ - tweak: "makes quantisation level for chemistry finer"
diff --git a/html/changelogs/AutoChangeLog-pr-9115.yml b/html/changelogs/AutoChangeLog-pr-9115.yml
new file mode 100644
index 0000000000..32c3109c43
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9115.yml
@@ -0,0 +1,4 @@
+author: "Thalpy"
+delete-after: True
+changes:
+ - bugfix: "fixes message_admins in SDZF"
diff --git a/html/changelogs/AutoChangeLog-pr-9119.yml b/html/changelogs/AutoChangeLog-pr-9119.yml
new file mode 100644
index 0000000000..756c3edcb2
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9119.yml
@@ -0,0 +1,4 @@
+author: "Linzolle"
+delete-after: True
+changes:
+ - rscadd: "mining shuttle console can now be printed after computer consoles have been researched"
diff --git a/html/changelogs/AutoChangeLog-pr-9126.yml b/html/changelogs/AutoChangeLog-pr-9126.yml
new file mode 100644
index 0000000000..c3e54a8f2d
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9126.yml
@@ -0,0 +1,4 @@
+author: "original by Skoglol, port by sishen1542"
+delete-after: True
+changes:
+ - balance: "Added lots of new virus cures, made cure difficulty scale more consistently. Cures are now picked from a list of possible cures per resistance level, multiple diseases at the same level no longer always share a cure. Looking at you table salt."
diff --git a/html/changelogs/AutoChangeLog-pr-9130.yml b/html/changelogs/AutoChangeLog-pr-9130.yml
new file mode 100644
index 0000000000..f10e72a6ce
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9130.yml
@@ -0,0 +1,9 @@
+author: "Owai-Seek"
+delete-after: True
+changes:
+ - rscadd: "custodial cruiser cargo crate"
+ - tweak: "removed light replacer from power designs and moved to misc designs"
+ - tweak: "added pimpin ride to custodial locator"
+ - tweak: "added additional items to janibelt whitelist"
+ - tweak: "made plant DNA manipulator unwrenchable"
+ - balance: "reduced janitor premium supply costs"
diff --git a/html/changelogs/AutoChangeLog-pr-9133.yml b/html/changelogs/AutoChangeLog-pr-9133.yml
new file mode 100644
index 0000000000..50bfced879
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9133.yml
@@ -0,0 +1,4 @@
+author: "Raptorizer"
+delete-after: True
+changes:
+ - tweak: "Doubled peach spawn rate"
diff --git a/html/changelogs/AutoChangeLog-pr-9134.yml b/html/changelogs/AutoChangeLog-pr-9134.yml
new file mode 100644
index 0000000000..f0be3bdd0a
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9134.yml
@@ -0,0 +1,4 @@
+author: "Arturlang"
+delete-after: True
+changes:
+ - tweak: "Advanced toxin filtration nanites now heal slimes"
diff --git a/html/changelogs/AutoChangeLog-pr-9136.yml b/html/changelogs/AutoChangeLog-pr-9136.yml
new file mode 100644
index 0000000000..7bb9e3ccf2
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9136.yml
@@ -0,0 +1,4 @@
+author: "Sishen1542"
+delete-after: True
+changes:
+ - balance: "rebalances strained muscles"
diff --git a/html/changelogs/AutoChangeLog-pr-9137.yml b/html/changelogs/AutoChangeLog-pr-9137.yml
new file mode 100644
index 0000000000..a61a3dbe6f
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9137.yml
@@ -0,0 +1,5 @@
+author: "Sishen1542"
+delete-after: True
+changes:
+ - rscadd: "added in the assistant response team"
+ - bugfix: "fixed up access on the centcom hangar button"
diff --git a/html/changelogs/AutoChangeLog-pr-9138.yml b/html/changelogs/AutoChangeLog-pr-9138.yml
new file mode 100644
index 0000000000..b78d505c5a
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9138.yml
@@ -0,0 +1,4 @@
+author: "kappa-sama"
+delete-after: True
+changes:
+ - bugfix: "seed"
diff --git a/html/changelogs/AutoChangeLog-pr-9141.yml b/html/changelogs/AutoChangeLog-pr-9141.yml
new file mode 100644
index 0000000000..86230537de
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9141.yml
@@ -0,0 +1,4 @@
+author: "deathride58"
+delete-after: True
+changes:
+ - bugfix: "Fixed another runtime in warp whistles."
diff --git a/html/changelogs/AutoChangeLog-pr-9142.yml b/html/changelogs/AutoChangeLog-pr-9142.yml
new file mode 100644
index 0000000000..75fbfe4155
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9142.yml
@@ -0,0 +1,4 @@
+author: "Trilbyspaceclone"
+delete-after: True
+changes:
+ - tweak: "glue uplinks"
diff --git a/html/changelogs/AutoChangeLog-pr-9145.yml b/html/changelogs/AutoChangeLog-pr-9145.yml
new file mode 100644
index 0000000000..27e5712dd0
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9145.yml
@@ -0,0 +1,4 @@
+author: "Trilbyspaceclone"
+delete-after: True
+changes:
+ - rscadd: "RPDs to drones"
diff --git a/html/changelogs/AutoChangeLog-pr-9149.yml b/html/changelogs/AutoChangeLog-pr-9149.yml
new file mode 100644
index 0000000000..8a10035d1f
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9149.yml
@@ -0,0 +1,4 @@
+author: "Trilbyspaceclone"
+delete-after: True
+changes:
+ - rscadd: "Armor and such"
diff --git a/html/changelogs/AutoChangeLog-pr-9150.yml b/html/changelogs/AutoChangeLog-pr-9150.yml
new file mode 100644
index 0000000000..585ea0a149
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9150.yml
@@ -0,0 +1,5 @@
+author: "Trilbyspaceclone"
+delete-after: True
+changes:
+ - rscadd: "flavor"
+ - bugfix: "maybe a runtime"
diff --git a/html/changelogs/AutoChangeLog-pr-9151.yml b/html/changelogs/AutoChangeLog-pr-9151.yml
new file mode 100644
index 0000000000..ed01c0d137
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9151.yml
@@ -0,0 +1,4 @@
+author: "Trilbyspaceclone"
+delete-after: True
+changes:
+ - rscadd: "chameloen clothing"
diff --git a/html/changelogs/AutoChangeLog-pr-9155.yml b/html/changelogs/AutoChangeLog-pr-9155.yml
new file mode 100644
index 0000000000..ad16ff6276
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9155.yml
@@ -0,0 +1,4 @@
+author: "Poojawa"
+delete-after: True
+changes:
+ - server: "Poly's speech now echos to the chat bot."
diff --git a/html/changelogs/AutoChangeLog-pr-9162.yml b/html/changelogs/AutoChangeLog-pr-9162.yml
new file mode 100644
index 0000000000..a415ce8bbc
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9162.yml
@@ -0,0 +1,5 @@
+author: "Sishen1542"
+delete-after: True
+changes:
+ - balance: "storage tweaks for belt briefcase"
+ - imageadd: "codersprite for belt briefcase"
diff --git a/html/changelogs/AutoChangeLog-pr-9164.yml b/html/changelogs/AutoChangeLog-pr-9164.yml
new file mode 100644
index 0000000000..08d7ccec18
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-9164.yml
@@ -0,0 +1,4 @@
+author: "lolman360"
+delete-after: True
+changes:
+ - imageadd: "missing durathread sprites"
diff --git a/icons/effects/effects.dmi b/icons/effects/effects.dmi
index 29086033c8..e13ce10347 100644
Binary files a/icons/effects/effects.dmi and b/icons/effects/effects.dmi differ
diff --git a/icons/mecha/mecha_mouse-disable.dmi b/icons/mecha/mecha_mouse-disable.dmi
new file mode 100644
index 0000000000..48924c58c2
Binary files /dev/null and b/icons/mecha/mecha_mouse-disable.dmi differ
diff --git a/icons/member_content.dmi b/icons/member_content.dmi
index bb59764627..7744371119 100644
Binary files a/icons/member_content.dmi and b/icons/member_content.dmi differ
diff --git a/icons/mob/accessories.dmi b/icons/mob/accessories.dmi
index 8e3e48230f..68f13c8875 100644
Binary files a/icons/mob/accessories.dmi and b/icons/mob/accessories.dmi differ
diff --git a/icons/mob/actions.dmi b/icons/mob/actions.dmi
index 65b5733ffe..4e23c102ce 100644
Binary files a/icons/mob/actions.dmi and b/icons/mob/actions.dmi differ
diff --git a/icons/mob/alien.dmi b/icons/mob/alien.dmi
index c50351eef3..21238366f1 100644
Binary files a/icons/mob/alien.dmi and b/icons/mob/alien.dmi differ
diff --git a/icons/mob/alienqueen.dmi b/icons/mob/alienqueen.dmi
index 115bd17cb0..1176f43edd 100644
Binary files a/icons/mob/alienqueen.dmi and b/icons/mob/alienqueen.dmi differ
diff --git a/icons/mob/animal.dmi b/icons/mob/animal.dmi
index c98ca98c42..2a85f8a422 100644
Binary files a/icons/mob/animal.dmi and b/icons/mob/animal.dmi differ
diff --git a/icons/mob/back.dmi b/icons/mob/back.dmi
index e3c80708c3..52822ed5be 100644
Binary files a/icons/mob/back.dmi and b/icons/mob/back.dmi differ
diff --git a/icons/mob/belt.dmi b/icons/mob/belt.dmi
index 02fdc52b45..6843bac6bf 100644
Binary files a/icons/mob/belt.dmi and b/icons/mob/belt.dmi differ
diff --git a/icons/mob/custom_w.dmi b/icons/mob/custom_w.dmi
index d974d0ca6c..1b917d9434 100644
Binary files a/icons/mob/custom_w.dmi and b/icons/mob/custom_w.dmi differ
diff --git a/icons/mob/eyes.dmi b/icons/mob/eyes.dmi
index aad4718cbd..6cce82b5f7 100644
Binary files a/icons/mob/eyes.dmi and b/icons/mob/eyes.dmi differ
diff --git a/icons/mob/head.dmi b/icons/mob/head.dmi
index 09d6fe5374..9de3ffae8c 100644
Binary files a/icons/mob/head.dmi and b/icons/mob/head.dmi differ
diff --git a/icons/mob/inhands/equipment/backpack_lefthand.dmi b/icons/mob/inhands/equipment/backpack_lefthand.dmi
index 0e466486c5..3238b98757 100644
Binary files a/icons/mob/inhands/equipment/backpack_lefthand.dmi and b/icons/mob/inhands/equipment/backpack_lefthand.dmi differ
diff --git a/icons/mob/inhands/equipment/backpack_righthand.dmi b/icons/mob/inhands/equipment/backpack_righthand.dmi
index 1c265a4137..a103c1a13f 100644
Binary files a/icons/mob/inhands/equipment/backpack_righthand.dmi and b/icons/mob/inhands/equipment/backpack_righthand.dmi differ
diff --git a/icons/mob/inhands/equipment/belt_lefthand.dmi b/icons/mob/inhands/equipment/belt_lefthand.dmi
index 366493eebd..beac56725a 100644
Binary files a/icons/mob/inhands/equipment/belt_lefthand.dmi and b/icons/mob/inhands/equipment/belt_lefthand.dmi differ
diff --git a/icons/mob/inhands/equipment/belt_righthand.dmi b/icons/mob/inhands/equipment/belt_righthand.dmi
index 81b075f706..da31cc9710 100644
Binary files a/icons/mob/inhands/equipment/belt_righthand.dmi and b/icons/mob/inhands/equipment/belt_righthand.dmi differ
diff --git a/icons/mob/inhands/equipment/briefcase_lefthand.dmi b/icons/mob/inhands/equipment/briefcase_lefthand.dmi
index 08bc3814b0..38aaa98254 100644
Binary files a/icons/mob/inhands/equipment/briefcase_lefthand.dmi and b/icons/mob/inhands/equipment/briefcase_lefthand.dmi differ
diff --git a/icons/mob/inhands/equipment/briefcase_righthand.dmi b/icons/mob/inhands/equipment/briefcase_righthand.dmi
index 5cc42559cd..fbcea4580e 100644
Binary files a/icons/mob/inhands/equipment/briefcase_righthand.dmi and b/icons/mob/inhands/equipment/briefcase_righthand.dmi differ
diff --git a/icons/mob/inhands/equipment/kitchen_lefthand.dmi b/icons/mob/inhands/equipment/kitchen_lefthand.dmi
index 277a7d8f05..93cd988cff 100644
Binary files a/icons/mob/inhands/equipment/kitchen_lefthand.dmi and b/icons/mob/inhands/equipment/kitchen_lefthand.dmi differ
diff --git a/icons/mob/inhands/equipment/kitchen_righthand.dmi b/icons/mob/inhands/equipment/kitchen_righthand.dmi
index 0103bd19b5..075b4c2033 100644
Binary files a/icons/mob/inhands/equipment/kitchen_righthand.dmi and b/icons/mob/inhands/equipment/kitchen_righthand.dmi differ
diff --git a/icons/mob/inhands/equipment/security_lefthand.dmi b/icons/mob/inhands/equipment/security_lefthand.dmi
index 6ccdfba3fc..01f8e2ca27 100644
Binary files a/icons/mob/inhands/equipment/security_lefthand.dmi and b/icons/mob/inhands/equipment/security_lefthand.dmi differ
diff --git a/icons/mob/inhands/equipment/security_righthand.dmi b/icons/mob/inhands/equipment/security_righthand.dmi
index e3f930a13e..d2126fe22f 100644
Binary files a/icons/mob/inhands/equipment/security_righthand.dmi and b/icons/mob/inhands/equipment/security_righthand.dmi differ
diff --git a/icons/mob/inhands/equipment/tools_lefthand.dmi b/icons/mob/inhands/equipment/tools_lefthand.dmi
index 5b497afe53..72b994328d 100644
Binary files a/icons/mob/inhands/equipment/tools_lefthand.dmi and b/icons/mob/inhands/equipment/tools_lefthand.dmi differ
diff --git a/icons/mob/inhands/equipment/tools_righthand.dmi b/icons/mob/inhands/equipment/tools_righthand.dmi
index dbed4c43d2..ef1001c438 100644
Binary files a/icons/mob/inhands/equipment/tools_righthand.dmi and b/icons/mob/inhands/equipment/tools_righthand.dmi differ
diff --git a/icons/mob/inhands/items_lefthand.dmi b/icons/mob/inhands/items_lefthand.dmi
index f1b125eb20..71c453856a 100644
Binary files a/icons/mob/inhands/items_lefthand.dmi and b/icons/mob/inhands/items_lefthand.dmi differ
diff --git a/icons/mob/inhands/items_righthand.dmi b/icons/mob/inhands/items_righthand.dmi
index 7ef316be17..0ca09ad810 100644
Binary files a/icons/mob/inhands/items_righthand.dmi and b/icons/mob/inhands/items_righthand.dmi differ
diff --git a/icons/mob/inhands/weapons/guns_lefthand.dmi b/icons/mob/inhands/weapons/guns_lefthand.dmi
index f6ac6ca499..8978d17237 100644
Binary files a/icons/mob/inhands/weapons/guns_lefthand.dmi and b/icons/mob/inhands/weapons/guns_lefthand.dmi differ
diff --git a/icons/mob/inhands/weapons/guns_righthand.dmi b/icons/mob/inhands/weapons/guns_righthand.dmi
index 504121feba..3f8a876d43 100644
Binary files a/icons/mob/inhands/weapons/guns_righthand.dmi and b/icons/mob/inhands/weapons/guns_righthand.dmi differ
diff --git a/icons/mob/mask.dmi b/icons/mob/mask.dmi
index 5f0b665ff4..019ae09517 100644
Binary files a/icons/mob/mask.dmi and b/icons/mob/mask.dmi differ
diff --git a/icons/mob/mob.dmi b/icons/mob/mob.dmi
index 1649706279..9beedfb417 100644
Binary files a/icons/mob/mob.dmi and b/icons/mob/mob.dmi differ
diff --git a/icons/mob/pets.dmi b/icons/mob/pets.dmi
index fe0146ccc4..10f29f51e4 100644
Binary files a/icons/mob/pets.dmi and b/icons/mob/pets.dmi differ
diff --git a/icons/mob/restraints.dmi b/icons/mob/restraints.dmi
new file mode 100644
index 0000000000..fa7eb43aa3
Binary files /dev/null and b/icons/mob/restraints.dmi differ
diff --git a/icons/mob/screen_gen.dmi b/icons/mob/screen_gen.dmi
index 77450b6ac3..3cd7388378 100644
Binary files a/icons/mob/screen_gen.dmi and b/icons/mob/screen_gen.dmi differ
diff --git a/icons/mob/suit.dmi b/icons/mob/suit.dmi
index 42c32f134a..7ba0ec9604 100644
Binary files a/icons/mob/suit.dmi and b/icons/mob/suit.dmi differ
diff --git a/icons/mob/uniform.dmi b/icons/mob/uniform.dmi
index 3d281606de..43d35d5df5 100644
Binary files a/icons/mob/uniform.dmi and b/icons/mob/uniform.dmi differ
diff --git a/icons/obj/advancedtools.dmi b/icons/obj/advancedtools.dmi
new file mode 100644
index 0000000000..974202dd58
Binary files /dev/null and b/icons/obj/advancedtools.dmi differ
diff --git a/icons/obj/assemblies/new_assemblies.dmi b/icons/obj/assemblies/new_assemblies.dmi
index df9517aeaa..fa0c138d21 100644
Binary files a/icons/obj/assemblies/new_assemblies.dmi and b/icons/obj/assemblies/new_assemblies.dmi differ
diff --git a/icons/obj/chairs.dmi b/icons/obj/chairs.dmi
index 3754ff052c..9e8fb64aba 100644
Binary files a/icons/obj/chairs.dmi and b/icons/obj/chairs.dmi differ
diff --git a/icons/obj/chemical.dmi b/icons/obj/chemical.dmi
index 93daa6149e..b63e9344f1 100644
Binary files a/icons/obj/chemical.dmi and b/icons/obj/chemical.dmi differ
diff --git a/icons/obj/clothing/accessories.dmi b/icons/obj/clothing/accessories.dmi
index c35956687d..c62a88c829 100644
Binary files a/icons/obj/clothing/accessories.dmi and b/icons/obj/clothing/accessories.dmi differ
diff --git a/icons/obj/clothing/belt_overlays.dmi b/icons/obj/clothing/belt_overlays.dmi
index d7bf32d7b1..717937c034 100644
Binary files a/icons/obj/clothing/belt_overlays.dmi and b/icons/obj/clothing/belt_overlays.dmi differ
diff --git a/icons/obj/clothing/belts.dm b/icons/obj/clothing/belts.dm
deleted file mode 100644
index 34c716f5d8..0000000000
Binary files a/icons/obj/clothing/belts.dm and /dev/null differ
diff --git a/icons/obj/clothing/belts.dmi b/icons/obj/clothing/belts.dmi
index 34c716f5d8..e329720cf7 100644
Binary files a/icons/obj/clothing/belts.dmi and b/icons/obj/clothing/belts.dmi differ
diff --git a/icons/obj/clothing/glasses.dmi b/icons/obj/clothing/glasses.dmi
index e7bec8dbe4..2cdf97bd37 100644
Binary files a/icons/obj/clothing/glasses.dmi and b/icons/obj/clothing/glasses.dmi differ
diff --git a/icons/obj/clothing/hats.dmi b/icons/obj/clothing/hats.dmi
index 8256c1fc07..a8ec22c950 100644
Binary files a/icons/obj/clothing/hats.dmi and b/icons/obj/clothing/hats.dmi differ
diff --git a/icons/obj/clothing/masks.dmi b/icons/obj/clothing/masks.dmi
index a0153b1596..4ec45666c4 100644
Binary files a/icons/obj/clothing/masks.dmi and b/icons/obj/clothing/masks.dmi differ
diff --git a/icons/obj/clothing/suits.dmi b/icons/obj/clothing/suits.dmi
index 568adb69b3..88e68eea2d 100644
Binary files a/icons/obj/clothing/suits.dmi and b/icons/obj/clothing/suits.dmi differ
diff --git a/icons/obj/clothing/uniforms.dmi b/icons/obj/clothing/uniforms.dmi
index 3e3a1cefcb..25c9b0eb06 100644
Binary files a/icons/obj/clothing/uniforms.dmi and b/icons/obj/clothing/uniforms.dmi differ
diff --git a/icons/obj/custom.dmi b/icons/obj/custom.dmi
index eb4f5813c8..601e32fb63 100644
Binary files a/icons/obj/custom.dmi and b/icons/obj/custom.dmi differ
diff --git a/icons/obj/device.dmi b/icons/obj/device.dmi
index 55c33e5e83..032b0c27ad 100644
Binary files a/icons/obj/device.dmi and b/icons/obj/device.dmi differ
diff --git a/icons/obj/femur_breaker.dmi b/icons/obj/femur_breaker.dmi
new file mode 100644
index 0000000000..4b36f4b2b8
Binary files /dev/null and b/icons/obj/femur_breaker.dmi differ
diff --git a/icons/obj/food/food.dmi b/icons/obj/food/food.dmi
index 92b5203f5d..6fda702cb3 100644
Binary files a/icons/obj/food/food.dmi and b/icons/obj/food/food.dmi differ
diff --git a/icons/obj/food/piecake.dmi b/icons/obj/food/piecake.dmi
index 57dda21757..df1e61c849 100644
Binary files a/icons/obj/food/piecake.dmi and b/icons/obj/food/piecake.dmi differ
diff --git a/icons/obj/guns/energy.dmi b/icons/obj/guns/energy.dmi
index 4dec451008..a6d5c8a5e1 100644
Binary files a/icons/obj/guns/energy.dmi and b/icons/obj/guns/energy.dmi differ
diff --git a/icons/obj/guns/projectile.dmi b/icons/obj/guns/projectile.dmi
index 7d44d35f55..0ac8ccf566 100644
Binary files a/icons/obj/guns/projectile.dmi and b/icons/obj/guns/projectile.dmi differ
diff --git a/icons/obj/hydroponics/equipment.dmi b/icons/obj/hydroponics/equipment.dmi
index 82dce552a7..dd4d1e1f93 100644
Binary files a/icons/obj/hydroponics/equipment.dmi and b/icons/obj/hydroponics/equipment.dmi differ
diff --git a/icons/obj/hydroponics/growing.dmi b/icons/obj/hydroponics/growing.dmi
index 162c6b047e..e7dee2290d 100644
Binary files a/icons/obj/hydroponics/growing.dmi and b/icons/obj/hydroponics/growing.dmi differ
diff --git a/icons/obj/hydroponics/growing_fruits.dmi b/icons/obj/hydroponics/growing_fruits.dmi
index d309884be0..9b0bc9816b 100644
Binary files a/icons/obj/hydroponics/growing_fruits.dmi and b/icons/obj/hydroponics/growing_fruits.dmi differ
diff --git a/icons/obj/hydroponics/harvest.dmi b/icons/obj/hydroponics/harvest.dmi
index a1ab5b08e5..5ced9cad20 100644
Binary files a/icons/obj/hydroponics/harvest.dmi and b/icons/obj/hydroponics/harvest.dmi differ
diff --git a/icons/obj/hydroponics/seeds.dmi b/icons/obj/hydroponics/seeds.dmi
index 5a2088c332..55a7f60a5c 100644
Binary files a/icons/obj/hydroponics/seeds.dmi and b/icons/obj/hydroponics/seeds.dmi differ
diff --git a/icons/obj/items_and_weapons.dmi b/icons/obj/items_and_weapons.dmi
index 0d68f00c8b..8788567b36 100644
Binary files a/icons/obj/items_and_weapons.dmi and b/icons/obj/items_and_weapons.dmi differ
diff --git a/icons/obj/iv_drip.dmi b/icons/obj/iv_drip.dmi
index 016513245e..f530688da7 100644
Binary files a/icons/obj/iv_drip.dmi and b/icons/obj/iv_drip.dmi differ
diff --git a/icons/obj/library.dmi b/icons/obj/library.dmi
index 140f6a4d9e..f28b8be5c5 100644
Binary files a/icons/obj/library.dmi and b/icons/obj/library.dmi differ
diff --git a/icons/obj/plushes.dmi b/icons/obj/plushes.dmi
index 9048739e0c..b6ca8c178c 100644
Binary files a/icons/obj/plushes.dmi and b/icons/obj/plushes.dmi differ
diff --git a/icons/obj/stack_objects.dmi b/icons/obj/stack_objects.dmi
index 6d2b2b64cd..ac2d42378a 100644
Binary files a/icons/obj/stack_objects.dmi and b/icons/obj/stack_objects.dmi differ
diff --git a/icons/obj/storage.dmi b/icons/obj/storage.dmi
index 2a6ec3955a..e5d61fbfe0 100644
Binary files a/icons/obj/storage.dmi and b/icons/obj/storage.dmi differ
diff --git a/icons/obj/surgery.dmi b/icons/obj/surgery.dmi
index 1a3b344566..eed8ee64e7 100755
Binary files a/icons/obj/surgery.dmi and b/icons/obj/surgery.dmi differ
diff --git a/icons/obj/tools.dmi b/icons/obj/tools.dmi
index cfb36bb3ae..c983201d5f 100644
Binary files a/icons/obj/tools.dmi and b/icons/obj/tools.dmi differ
diff --git a/interface/stylesheet.dm b/interface/stylesheet.dm
index cdf6df2dab..2ecd9f9004 100644
--- a/interface/stylesheet.dm
+++ b/interface/stylesheet.dm
@@ -153,6 +153,30 @@ h1.alert, h2.alert {color: #000000;}
.redtext {color: #FF0000; font-size: 3;}
.clown {color: #FF69Bf; font-size: 3; font-family: "Comic Sans MS", cursive, sans-serif; font-weight: bold;}
.his_grace {color: #15D512; font-family: "Courier New", cursive, sans-serif; font-style: italic;}
+.velvet {color: #660015; font-weight: bold; animation: velvet 5000ms infinite;}
+@keyframes velvet {
+ 0% { color: #400020; }
+ 40% { color: #FF0000; }
+ 50% { color: #FF8888; }
+ 60% { color: #FF0000; }
+ 100% { color: #400020; }
+}
+
+.hypnophrase {color: #3bb5d3; font-weight: bold; animation: hypnocolor 1500ms infinite;}
+@keyframes hypnocolor {
+ 0% { color: #0d0d0d; }
+ 25% { color: #410194; }
+ 50% { color: #7f17d8; }
+ 75% { color: #410194; }
+ 100% { color: #3bb5d3; }
+}
+
+.phobia {color: #dd0000; font-weight: bold; animation: phobia 750ms infinite;}
+ @keyframes phobia {
+ 0% { color: #0d0d0d; }
+ 50% { color: #dd0000; }
+ 100% { color: #0d0d0d; }
+}
.icon {height: 1em; width: auto;}
diff --git a/modular_citadel/code/_onclick/hud/screen_objects.dm b/modular_citadel/code/_onclick/hud/screen_objects.dm
index 511627b81f..3a0eb364cb 100644
--- a/modular_citadel/code/_onclick/hud/screen_objects.dm
+++ b/modular_citadel/code/_onclick/hud/screen_objects.dm
@@ -1,25 +1,3 @@
-/obj/screen/mov_intent
- icon = 'modular_citadel/icons/ui/screen_midnight.dmi'
-
-/obj/screen/sprintbutton
- name = "toggle sprint"
- icon = 'modular_citadel/icons/ui/screen_midnight.dmi'
- icon_state = "act_sprint"
- layer = ABOVE_HUD_LAYER - 0.1
-
-/obj/screen/sprintbutton/Click()
- if(ishuman(usr))
- var/mob/living/carbon/human/H = usr
- H.togglesprint()
-
-/obj/screen/sprintbutton/proc/insert_witty_toggle_joke_here(mob/living/carbon/human/H)
- if(!H)
- return
- if(H.sprinting)
- icon_state = "act_sprint_on"
- else
- icon_state = "act_sprint"
-
/obj/screen/restbutton
name = "rest"
icon = 'modular_citadel/icons/ui/screen_midnight.dmi'
diff --git a/modular_citadel/code/_onclick/hud/sprint.dm b/modular_citadel/code/_onclick/hud/sprint.dm
new file mode 100644
index 0000000000..290fcd368e
--- /dev/null
+++ b/modular_citadel/code/_onclick/hud/sprint.dm
@@ -0,0 +1,41 @@
+/obj/screen/mov_intent
+ icon = 'modular_citadel/icons/ui/screen_midnight.dmi'
+
+/obj/screen/sprintbutton
+ name = "toggle sprint"
+ icon = 'modular_citadel/icons/ui/screen_midnight.dmi'
+ icon_state = "act_sprint"
+ layer = ABOVE_HUD_LAYER - 0.1
+
+/obj/screen/sprintbutton/Click()
+ if(ishuman(usr))
+ var/mob/living/carbon/human/H = usr
+ H.togglesprint()
+
+/obj/screen/sprintbutton/proc/insert_witty_toggle_joke_here(mob/living/carbon/human/H)
+ if(!H)
+ return
+ if(H.sprinting)
+ icon_state = "act_sprint_on"
+ else
+ icon_state = "act_sprint"
+
+//Sprint buffer onscreen code.
+/datum/hud/var/obj/screen/sprint_buffer/sprint_buffer
+
+/obj/screen/sprint_buffer
+ name = "sprint buffer"
+ icon = 'icons/effects/progessbar.dmi'
+ icon_state = "prog_bar_100"
+
+/obj/screen/sprint_buffer/Click()
+ if(isliving(usr))
+ var/mob/living/L = usr
+ to_chat(L, "Your sprint buffer's maximum capacity is [L.sprint_buffer_max]. It is currently at [L.sprint_buffer], regenerating at [L.sprint_buffer_regen_ds * 10] per second. \
+ Sprinting while this is empty will incur a [L.sprint_stamina_cost] stamina cost per tile.")
+
+/obj/screen/sprint_buffer/proc/update_to_mob(mob/living/L)
+ var/amount = 0
+ if(L.sprint_buffer_max > 0)
+ amount = round(CLAMP((L.sprint_buffer / L.sprint_buffer_max) * 100, 0, 100), 5)
+ icon_state = "prog_bar_[amount]"
diff --git a/modular_citadel/code/_onclick/item_attack.dm b/modular_citadel/code/_onclick/item_attack.dm
index dcc9f567e2..80281ee084 100644
--- a/modular_citadel/code/_onclick/item_attack.dm
+++ b/modular_citadel/code/_onclick/item_attack.dm
@@ -17,9 +17,3 @@
/obj/item/proc/altafterattack(atom/target, mob/user, proximity_flag, click_parameters)
return FALSE
-
-/obj/item/proc/getweight()
- if(total_mass)
- return max(total_mass,MIN_MELEE_STAMCOST)
- else
- return w_class*1.25
diff --git a/modular_citadel/code/datums/mood_events/chem_events.dm b/modular_citadel/code/datums/mood_events/chem_events.dm
new file mode 100644
index 0000000000..c496a0fa27
--- /dev/null
+++ b/modular_citadel/code/datums/mood_events/chem_events.dm
@@ -0,0 +1,59 @@
+/datum/mood_event/eigenstate
+ mood_change = -3
+ description = "Where the hell am I? Is this an alternative dimension ?\n"
+
+/datum/mood_event/enthrall
+ mood_change = 5
+
+/datum/mood_event/enthrall/add_effects(message)
+ description = "[message]\n"
+
+/datum/mood_event/enthrallpraise
+ mood_change = 10
+ timeout = 1 MINUTES
+
+/datum/mood_event/enthrallpraise/add_effects(message)
+ description = "[message]\n"
+
+/datum/mood_event/enthrallscold
+ mood_change = -10
+ timeout = 1 MINUTES
+
+/datum/mood_event/enthrallscold/add_effects(message)
+ description = "[message]\n"//aaa I'm not kinky enough for this
+
+/datum/mood_event/enthrallmissing1
+ mood_change = -5
+
+/datum/mood_event/enthrallmissing1/add_effects(message)
+ description = "[message]\n"
+
+/datum/mood_event/enthrallmissing2
+ mood_change = -10
+
+/datum/mood_event/enthrallmissing2/add_effects(message)
+ description = "[message]\n"
+
+/datum/mood_event/enthrallmissing3
+ mood_change = -15
+
+/datum/mood_event/enthrallmissing3/add_effects(message)
+ description = "[message]\n"
+
+/datum/mood_event/enthrallmissing4
+ mood_change = -25
+
+/datum/mood_event/enthrallmissing4/add_effects(message)
+ description = "[message]\n"
+
+/datum/mood_event/InLove
+ mood_change = 10
+
+/datum/mood_event/InLove/add_effects(message)
+ description = "[message]\n"
+
+/datum/mood_event/MissingLove
+ mood_change = -10
+
+/datum/mood_event/MissingLove/add_effects(message)
+ description = "[message]\n"
diff --git a/modular_citadel/code/datums/mood_events/generic_negative_events.dm b/modular_citadel/code/datums/mood_events/generic_negative_events.dm
index c0f2591656..bb04b0b283 100644
--- a/modular_citadel/code/datums/mood_events/generic_negative_events.dm
+++ b/modular_citadel/code/datums/mood_events/generic_negative_events.dm
@@ -3,19 +3,19 @@
/datum/mood_event/plushjack
description = "I have butchered a plush recently.\n"
mood_change = -1
- timeout = 1200
+ timeout = 2 MINUTES
/datum/mood_event/plush_nostuffing
description = "A plush I tried to pet had no stuffing...\n"
mood_change = -1
- timeout = 1200
+ timeout = 2 MINUTES
/datum/mood_event/emptypred
description = "I had to let someone out.\n"
mood_change = -2
- timeout = 600
+ timeout = 1 MINUTES
/datum/mood_event/emptyprey
description = "It feels quite cold out here.\n"
mood_change = -2
- timeout = 600
\ No newline at end of file
+ timeout = 1 MINUTES
diff --git a/modular_citadel/code/datums/mood_events/generic_positive_events.dm b/modular_citadel/code/datums/mood_events/generic_positive_events.dm
index 7b989d7700..ffa661e6e9 100644
--- a/modular_citadel/code/datums/mood_events/generic_positive_events.dm
+++ b/modular_citadel/code/datums/mood_events/generic_positive_events.dm
@@ -3,12 +3,12 @@
/datum/mood_event/headpat
description = "Headpats are nice.\n"
mood_change = 2
- timeout = 1200
+ timeout = 2 MINUTES
/datum/mood_event/hugbox
description = "I hugged a box of hugs recently.\n"
mood_change = 1
- timeout = 1200
+ timeout = 2 MINUTES
/datum/mood_event/plushpet
description = "I pet a plush recently.\n"
diff --git a/modular_citadel/code/datums/mood_events/moodular.dm b/modular_citadel/code/datums/mood_events/moodular.dm
index b53ce417e8..aa87f1b97a 100644
--- a/modular_citadel/code/datums/mood_events/moodular.dm
+++ b/modular_citadel/code/datums/mood_events/moodular.dm
@@ -3,9 +3,7 @@
// box of hugs
/obj/item/storage/box/hug/attack_self(mob/user)
. = ..()
- GET_COMPONENT_FROM(mood, /datum/component/mood, user)
- if(mood)
- mood.add_event("hugbox", /datum/mood_event/hugbox)
+ SEND_SIGNAL(user, COMSIG_ADD_MOOD_EVENT,"hugbox", /datum/mood_event/hugbox)
//Removed headpats here, duplicate code?
@@ -13,25 +11,17 @@
/obj/item/toy/plush/attack_self(mob/user)
. = ..()
if(stuffed || grenade)
- GET_COMPONENT_FROM(mood, /datum/component/mood, user)
- if(mood)
- mood.add_event("plushpet", /datum/mood_event/plushpet)
+ SEND_SIGNAL(user, COMSIG_ADD_MOOD_EVENT,"plushpet", /datum/mood_event/plushpet)
else
- GET_COMPONENT_FROM(mood, /datum/component/mood, user)
- if(mood)
- mood.add_event("plush_nostuffing", /datum/mood_event/plush_nostuffing)
+ SEND_SIGNAL(user, COMSIG_ADD_MOOD_EVENT,"plush_nostuffing", /datum/mood_event/plush_nostuffing)
// Jack the Ripper starring plush
/obj/item/toy/plush/attackby(obj/item/I, mob/living/user, params)
. = ..()
if(I.is_sharp())
if(!grenade)
- GET_COMPONENT_FROM(mood, /datum/component/mood, user)
- if(mood)
- mood.add_event("plushjack", /datum/mood_event/plushjack)
+ SEND_SIGNAL(user, COMSIG_ADD_MOOD_EVENT,"plushjack", /datum/mood_event/plushjack)
// plush playing (plush-on-plush action)
if(istype(I, /obj/item/toy/plush))
- GET_COMPONENT_FROM(mood, /datum/component/mood, user)
- if(mood)
- mood.add_event("plushplay", /datum/mood_event/plushplay)
+ SEND_SIGNAL(user, COMSIG_ADD_MOOD_EVENT,"plushplay", /datum/mood_event/plushplay)
diff --git a/modular_citadel/code/datums/status_effects/chems.dm b/modular_citadel/code/datums/status_effects/chems.dm
new file mode 100644
index 0000000000..4bc83d2af6
--- /dev/null
+++ b/modular_citadel/code/datums/status_effects/chems.dm
@@ -0,0 +1,760 @@
+#define DICK_MOVEMENT_SPEED "hugedick"
+#define BREAST_MOVEMENT_SPEED "megamilk"
+
+/datum/status_effect/chem/SGDF
+ id = "SGDF"
+ var/mob/living/fermi_Clone
+ var/mob/living/original
+ var/datum/mind/originalmind
+ var/status_set = FALSE
+ alert_type = null
+
+/datum/status_effect/chem/SGDF/on_apply()
+ log_game("FERMICHEM: SGDF status appied on [owner], ID: [owner.key]")
+ fermi_Clone = owner
+ return ..()
+
+/datum/status_effect/chem/SGDF/tick()
+ if(!status_set)
+ return ..()
+ if(original.stat == DEAD || original == null || !original)
+ if((fermi_Clone && fermi_Clone.stat != DEAD) || (fermi_Clone == null))
+ if(originalmind)
+ owner.remove_status_effect(src)
+ ..()
+
+/datum/status_effect/chem/SGDF/on_remove(mob/living/carbon/M)
+ log_game("FERMICHEM: SGDF mind shift applied. [owner] is now playing as their clone and should not have memories after their clone split (look up SGDF status applied). ID: [owner.key]")
+ originalmind.transfer_to(fermi_Clone)
+ to_chat(owner, "Lucidity shoots to your previously blank mind as your mind suddenly finishes the cloning process. You marvel for a moment at yourself, as your mind subconciously recollects all your memories up until the point when you cloned yourself. curiously, you find that you memories are blank after you ingested the sythetic serum, leaving you to wonder where the other you is.")
+ to_chat(M, "Lucidity shoots to your previously blank mind as your mind suddenly finishes the cloning process. You marvel for a moment at yourself, as your mind subconciously recollects all your memories up until the point when you cloned yourself. curiously, you find that you memories are blank after you ingested the sythetic serum, leaving you to wonder where the other you is.")
+ fermi_Clone = null
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/datum/status_effect/chem/breast_enlarger
+ id = "breast_enlarger"
+ alert_type = null
+ var/moveCalc = 1
+ var/cachedmoveCalc = 1
+
+/datum/status_effect/chem/breast_enlarger/on_apply(mob/living/carbon/human/H)//Removes clothes, they're too small to contain you. You belong to space now.
+ log_game("FERMICHEM: [owner]'s breasts has reached comical sizes. ID: [owner.key]")
+ var/mob/living/carbon/human/o = owner
+ var/items = o.get_contents()
+ for(var/obj/item/W in items)
+ if(W == o.w_uniform || W == o.wear_suit)
+ o.dropItemToGround(W, TRUE)
+ playsound(o.loc, 'sound/items/poster_ripped.ogg', 50, 1)
+ to_chat(o, "Your clothes give, ripping into peices under the strain of your swelling breasts! Unless you manage to reduce the size of your breasts, there's no way you're going to be able to put anything on over these melons..!")
+ o.visible_message("[o]'s chest suddenly bursts forth, ripping their clothes off!'")
+ else
+ to_chat(o, "Your bountiful bosom is so rich with mass, you seriously doubt you'll be able to fit any clothes over it.")
+ return ..()
+
+/datum/status_effect/chem/breast_enlarger/tick(mob/living/carbon/human/H)//If you try to wear clothes, you fail. Slows you down if you're comically huge
+ var/mob/living/carbon/human/o = owner
+ var/obj/item/organ/genital/breasts/B = o.getorganslot("breasts")
+ moveCalc = 1+((round(B.cached_size) - 9)/3) //Afffects how fast you move, and how often you can click.
+ if(!B)
+ o.remove_movespeed_modifier(BREAST_MOVEMENT_SPEED)
+ sizeMoveMod(1)
+ owner.remove_status_effect(src)
+ var/items = o.get_contents()
+ for(var/obj/item/W in items)
+ if(W == o.w_uniform || W == o.wear_suit)
+ o.dropItemToGround(W, TRUE)
+ playsound(o.loc, 'sound/items/poster_ripped.ogg', 50, 1)
+ to_chat(owner, "Your enormous breasts are way too large to fit anything over them!")
+ if (B.size == "huge")
+ if(prob(1))
+ to_chat(owner, "Your back is feeling sore.")
+ var/target = o.get_bodypart(BODY_ZONE_CHEST)
+ o.apply_damage(0.1, BRUTE, target)
+ if(!B.cached_size == B.breast_values[B.prev_size])
+ o.add_movespeed_modifier(BREAST_MOVEMENT_SPEED, TRUE, 100, NONE, override = TRUE, multiplicative_slowdown = moveCalc)
+ sizeMoveMod(moveCalc)
+ return ..()
+ else if (B.breast_values[B.size] > B.breast_values[B.prev_size])
+ o.add_movespeed_modifier(BREAST_MOVEMENT_SPEED, TRUE, 100, NONE, override = TRUE, multiplicative_slowdown = moveCalc)
+ sizeMoveMod(moveCalc)
+ else if (B.breast_values[B.size] < B.breast_values[B.prev_size])
+ o.add_movespeed_modifier(BREAST_MOVEMENT_SPEED, TRUE, 100, NONE, override = TRUE, multiplicative_slowdown = moveCalc)
+ sizeMoveMod(moveCalc)
+ if((B.cached_size) < 16)
+ switch(round(B.cached_size))
+ if(9)
+ if (B.breast_values[B.prev_size] != B.breast_values[B.size])
+ to_chat(o, "Your expansive chest has become a more managable size, liberating your movements.")
+ if(10 to INFINITY)
+ if (B.breast_values[B.prev_size] != B.breast_values[B.size])
+ to_chat(H, "Your indulgent busom is so substantial, it's affecting your movements!")
+ if(prob(1))
+ to_chat(owner, "Your back is feeling a little sore.")
+ ..()
+
+/datum/status_effect/chem/breast_enlarger/on_remove(mob/living/carbon/M)
+ log_game("FERMICHEM: [owner]'s breasts has reduced to an acceptable size. ID: [owner.key]")
+ owner.remove_movespeed_modifier(BREAST_MOVEMENT_SPEED)
+ sizeMoveMod(1)
+
+/datum/status_effect/chem/breast_enlarger/proc/sizeMoveMod(var/value)
+ if(cachedmoveCalc == value)
+ return
+ owner.next_move_modifier /= cachedmoveCalc
+ owner.next_move_modifier *= value
+ cachedmoveCalc = value
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/datum/status_effect/chem/penis_enlarger
+ id = "penis_enlarger"
+ alert_type = null
+ var/bloodCalc
+ var/moveCalc
+
+/datum/status_effect/chem/penis_enlarger/on_apply(mob/living/carbon/human/H)//Removes clothes, they're too small to contain you. You belong to space now.
+ log_game("FERMICHEM: [owner]'s dick has reached comical sizes. ID: [owner.key]")
+ var/mob/living/carbon/human/o = owner
+ var/items = o.get_contents()
+ if(o.w_uniform || o.wear_suit)
+ to_chat(o, "Your clothes give, ripping into peices under the strain of your swelling pecker! Unless you manage to reduce the size of your emancipated trouser snake, there's no way you're going to be able to put anything on over this girth..!")
+ owner.visible_message("[o]'s schlong suddenly bursts forth, ripping their clothes off!'")
+ else
+ to_chat(o, "Your emancipated trouser snake is so ripe with girth, you seriously doubt you'll be able to fit any clothes over it.")
+ for(var/obj/item/W in items)
+ if(W == o.w_uniform || W == o.wear_suit)
+ o.dropItemToGround(W, TRUE)
+ playsound(o.loc, 'sound/items/poster_ripped.ogg', 50, 1)
+ return ..()
+
+
+/datum/status_effect/chem/penis_enlarger/tick(mob/living/carbon/M)
+ var/mob/living/carbon/human/o = owner
+ var/obj/item/organ/genital/penis/P = o.getorganslot("penis")
+ moveCalc = 1+((round(P.length) - 21)/3) //effects how fast you can move
+ bloodCalc = 1+((round(P.length) - 21)/15) //effects how much blood you need (I didn' bother adding an arousal check because I'm spending too much time on this organ already.)
+ if(!P)
+ o.remove_movespeed_modifier(DICK_MOVEMENT_SPEED)
+ o.ResetBloodVol()
+ owner.remove_status_effect(src)
+ var/items = o.get_contents()
+ for(var/obj/item/W in items)
+ if(W == o.w_uniform || W == o.wear_suit)
+ o.dropItemToGround(W, TRUE)
+ playsound(o.loc, 'sound/items/poster_ripped.ogg', 50, 1)
+ to_chat(owner, "Your enormous package is way to large to fit anything over!")
+ switch(round(P.cached_length))
+ if(21)
+ to_chat(o, "Your rascally willy has become a more managable size, liberating your movements.")
+ o.remove_movespeed_modifier(DICK_MOVEMENT_SPEED)
+ o.AdjustBloodVol(bloodCalc)
+ if(22 to INFINITY)
+ if(prob(2))
+ to_chat(o, "Your indulgent johnson is so substantial, it's taking all your blood and affecting your movements!")
+ o.add_movespeed_modifier(DICK_MOVEMENT_SPEED, TRUE, 100, NONE, override = TRUE, multiplicative_slowdown = moveCalc)
+ o.AdjustBloodVol(bloodCalc)
+ ..()
+
+/datum/status_effect/chem/penis_enlarger/on_remove(mob/living/carbon/human/o)
+ log_game("FERMICHEM: [owner]'s dick has reduced to an acceptable size. ID: [owner.key]")
+ owner.remove_movespeed_modifier(DICK_MOVEMENT_SPEED)
+ owner.ResetBloodVol()
+
+
+/*//////////////////////////////////////////
+ Mind control functions
+///////////////////////////////////////////
+*/
+
+//Preamble
+/*
+/mob/living
+ var/lewd = TRUE
+*/
+
+/mob/living/verb/toggle_lewd()
+ set category = "IC"
+ set name = "Toggle Lewdchem"
+ set desc = "Allows you to toggle if you'd like lewd flavour messages."
+ client.prefs.lewdchem = !(client.prefs.lewdchem)
+ to_chat(usr, "You [(client.prefs.lewdchem?"will":"no longer")] receive lewdchem messages.")
+
+/datum/status_effect/chem/enthrall
+ id = "enthrall"
+ alert_type = null
+ //examine_text TODO
+ var/enthrallTally = 1 //Keeps track of the enthralling process
+ var/resistanceTally = 0 //Keeps track of the resistance
+ var/deltaResist //The total resistance added per resist click
+
+ var/phase = 1 //-1: resisted state, due to be removed.0: sleeper agent, no effects unless triggered 1: initial, 2: 2nd stage - more commands, 3rd: fully enthralled, 4th Mindbroken
+
+ var/status = null //status effects
+ var/statusStrength = 0 //strength of status effect
+
+ var/mob/living/master //Enchanter's person
+ var/enthrallID //Enchanter's ckey
+ var/enthrallGender //Use master or mistress
+
+ var/mental_capacity //Higher it is, lower the cooldown on commands, capacity reduces with resistance.
+ var/datum/weakref/redirect_component //resistance
+
+ var/distancelist = list(2,1.5,1,0.8,0.6,0.5,0.4,0.3,0.2) //Distance multipliers
+
+ var/withdrawal = FALSE //withdrawl
+ var/withdrawalTick = 0 //counts how long withdrawl is going on for
+
+ var/list/customTriggers = list() //the list of custom triggers
+
+ var/cooldown = 0 //cooldown on commands
+ var/cooldownMsg = TRUE //If cooldown message has been sent
+ var/cTriggered = FALSE //If someone is triggered (so they can't trigger themselves with what they say for infinite loops)
+ var/resistGrowth = 0 //Resistance accrues over time
+ var/DistApart = 1 //Distance between master and owner
+ var/tranceTime = 0 //how long trance effects apply on trance status
+
+ var/customEcho //Custom looping text in owner
+ var/customSpan //Custom spans for looping text
+
+/datum/status_effect/chem/enthrall/on_apply()
+ var/mob/living/carbon/M = owner
+ var/datum/reagent/fermi/enthrall/E = locate(/datum/reagent/fermi/enthrall) in M.reagents.reagent_list
+ if(!E)
+ message_admins("WARNING: FermiChem: No master found in thrall, did you bus in the status? You need to set up the vars manually in the chem if it's not reacted/bussed. Someone set up the reaction/status proc incorrectly if not (Don't use donor blood). Console them with a chemcat plush maybe?")
+ owner.remove_status_effect(src)
+ enthrallID = E.creatorID
+ enthrallGender = E.creatorGender
+ master = get_mob_by_key(enthrallID)
+ //if(M.ckey == enthrallID)
+ // owner.remove_status_effect(src)//At the moment, a user can enthrall themselves, toggle this back in if that should be removed.
+ redirect_component = WEAKREF(owner.AddComponent(/datum/component/redirect, list(COMSIG_LIVING_RESIST = CALLBACK(src, .proc/owner_resist)))) //Do resistance calc if resist is pressed#
+ RegisterSignal(owner, COMSIG_MOVABLE_HEAR, .proc/owner_hear)
+ var/obj/item/organ/brain/B = M.getorganslot(ORGAN_SLOT_BRAIN) //It's their brain!
+ mental_capacity = 500 - B.get_brain_damage()
+ var/mob/living/carbon/human/H = owner
+ if(H)//Prefs
+ if(!H.canbearoused)
+ H.client?.prefs.lewdchem = FALSE
+ var/message = "[(owner.client?.prefs.lewdchem?"I am a good pet for [enthrallGender].":"[master] is a really inspirational person!")]"
+ SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "enthrall", /datum/mood_event/enthrall, message)
+ to_chat(owner, "You feel inexplicably drawn towards [master], their words having a demonstrable effect on you. It seems the closer you are to them, the stronger the effect is. However you aren't fully swayed yet and can resist their effects by repeatedly resisting as much as you can!")
+ log_game("FERMICHEM: MKULTRA: Status applied on [owner] ckey: [owner.key] with a master of [master] ckey: [enthrallID].")
+ SSblackbox.record_feedback("tally", "fermi_chem", 1, "Enthrall attempts")
+ return ..()
+
+/datum/status_effect/chem/enthrall/tick()
+ var/mob/living/carbon/M = owner
+
+ //chem calculations
+ if(!owner.reagents.has_reagent("enthrall") && !owner.reagents.has_reagent("enthrallTest"))
+ if (phase < 3 && phase != 0)
+ deltaResist += 3//If you've no chem, then you break out quickly
+ if(prob(5))
+ to_chat(owner, "Your mind starts to restore some of it's clarity as you feel the effects of the drug wain.")
+ if (mental_capacity <= 500 || phase == 4)
+ if (owner.reagents.has_reagent("mannitol"))
+ mental_capacity += 5
+ if (owner.reagents.has_reagent("neurine"))
+ mental_capacity += 10
+
+ //mindshield check
+ if(HAS_TRAIT(M, TRAIT_MINDSHIELD))//If you manage to enrapture a head, wow, GJ. (resisting gives a bigger bonus with a mindshield) From what I can tell, this isn't possible.
+ resistanceTally += 2
+ if(prob(10))
+ to_chat(owner, "You feel lucidity returning to your mind as the mindshield buzzes, attempting to return your brain to normal function.")
+ if(phase == 4)
+ mental_capacity += 5
+
+ //phase specific events
+ switch(phase)
+ if(-1)//fully removed
+ SEND_SIGNAL(M, COMSIG_CLEAR_MOOD_EVENT, "enthrall")
+ log_game("FERMICHEM: MKULTRA: Status REMOVED from [owner] ckey: [owner.key] with a master of [master] ckey: [enthrallID].")
+ owner.remove_status_effect(src)
+ return
+ if(0)// sleeper agent
+ if (cooldown > 0)
+ cooldown -= 1
+ return
+ if(1)//Initial enthrallment
+ if (enthrallTally > 125)
+ phase += 1
+ mental_capacity -= resistanceTally//leftover resistance per step is taken away from mental_capacity.
+ resistanceTally /= 2
+ enthrallTally = 0
+ SSblackbox.record_feedback("tally", "fermi_chem", 1, "Enthralled to state 2")
+ if(owner.client?.prefs.lewdchem)
+ to_chat(owner, "Your conciousness slips, as you sink deeper into trance and servitude.")
+ else
+ to_chat(owner, "Your conciousness slips, as you feel more drawn to following [master].")
+
+ else if (resistanceTally > 125)
+ phase = -1
+ to_chat(owner, "You break free of the influence in your mind, your thoughts suddenly turning lucid!")
+ if(DistApart < 10)
+ to_chat(master, "[(master.client?.prefs.lewdchem?"Your pet":"Your thrall")] seems to have broken free of your enthrallment!")
+ SSblackbox.record_feedback("tally", "fermi_chem", 1, "Thralls broken free")
+ owner.remove_status_effect(src) //If resisted in phase 1, effect is removed.
+ if(prob(10))
+ if(owner.client?.prefs.lewdchem)
+ to_chat(owner, "[pick("It feels so good to listen to [master].", "You can't keep your eyes off [master].", "[master]'s voice is making you feel so sleepy.", "You feel so comfortable with [master]", "[master] is so dominant, it feels right to obey them.")].")
+ if (2) //partially enthralled
+ if(enthrallTally > 200)
+ phase += 1
+ mental_capacity -= resistanceTally//leftover resistance per step is taken away from mental_capacity.
+ enthrallTally = 0
+ resistanceTally /= 2
+ if(owner.client?.prefs.lewdchem)
+ to_chat(owner, "Your mind gives, eagerly obeying and serving [master].")
+ to_chat(owner, "You are now fully enthralled to [master], and eager to follow their commands. However you find that in your intoxicated state you are unable to resort to violence. Equally you are unable to commit suicide, even if ordered to, as you cannot serve your [enthrallGender] in death. ")//If people start using this as an excuse to be violent I'll just make them all pacifists so it's not OP.
+ else
+ to_chat(owner, "You are unable to put up a resistance any longer, and now are under the influence of [master]. However you find that in your intoxicated state you are unable to resort to violence. Equally you are unable to commit suicide, even if ordered to, as you cannot follow [master] in death. ")
+ to_chat(master, "Your [(master.client?.prefs.lewdchem?"pet":"follower")] [owner] appears to have fully fallen under your sway.")
+ log_game("FERMICHEM: MKULTRA: Status on [owner] ckey: [owner.key] has been fully entrhalled (state 3) with a master of [master] ckey: [enthrallID].")
+ SSblackbox.record_feedback("tally", "fermi_chem", 1, "thralls fully enthralled.")
+ else if (resistanceTally > 200)
+ enthrallTally *= 0.5
+ phase -= 1
+ resistanceTally = 0
+ resistGrowth = 0
+ to_chat(owner, "You manage to shake some of the effects from your addled mind, however you can still feel yourself drawn towards [master].")
+ if(prob(10))
+ if(owner.client?.prefs.lewdchem)
+ to_chat(owner, "[pick("It feels so good to listen to [enthrallGender].", "You can't keep your eyes off [enthrallGender].", "[enthrallGender]'s voice is making you feel so sleepy.", "You feel so comfortable with [enthrallGender]", "[enthrallGender] is so dominant, it feels right to obey them.")].")
+ if (3)//fully entranced
+ if ((resistanceTally >= 200 && withdrawalTick >= 150) || (HAS_TRAIT(M, TRAIT_MINDSHIELD) && (resistanceTally >= 100)))
+ enthrallTally = 0
+ phase -= 1
+ resistanceTally = 0
+ resistGrowth = 0
+ to_chat(owner, "The separation from [(owner.client?.prefs.lewdchem?"your [enthrallGender]":"[master]")] sparks a small flame of resistance in yourself, as your mind slowly starts to return to normal.")
+ REMOVE_TRAIT(owner, TRAIT_PACIFISM, "MKUltra")
+ if(prob(1))
+ if(owner.client?.prefs.lewdchem && !customEcho)
+ to_chat(owner, "[pick("I belong to [enthrallGender].", "[enthrallGender] knows whats best for me.", "Obedence is pleasure.", "I exist to serve [enthrallGender].", "[enthrallGender] is so dominant, it feels right to obey them.")].")
+ if (4) //mindbroken
+ if (mental_capacity >= 499 && (owner.getBrainLoss() <=0 || HAS_TRAIT(M, TRAIT_MINDSHIELD)) && !owner.reagents.has_reagent("MKUltra"))
+ phase = 2
+ mental_capacity = 500
+ customTriggers = list()
+ to_chat(owner, "Your mind starts to heal, fixing the damage caused by the massive amounts of chem injected into your system earlier, returning clarity to your mind. Though, you still feel drawn towards [master]'s words...'")
+ M.slurring = 0
+ M.confused = 0
+ resistGrowth = 0
+ else
+ if (cooldown > 0)
+ cooldown -= (0.8 + (mental_capacity/500))
+ cooldownMsg = FALSE
+ else if (cooldownMsg == FALSE)
+ if(DistApart < 10)
+ if(master.client?.prefs.lewdchem)
+ to_chat(master, "Your pet [owner] appears to have finished internalising your last command.")
+ cooldownMsg = TRUE
+ else
+ to_chat(master, "Your thrall [owner] appears to have finished internalising your last command.")
+ cooldownMsg = TRUE
+ if(get_dist(master, owner) > 10)
+ if(prob(10))
+ to_chat(owner, "You feel [(owner.client?.prefs.lewdchem?"a deep NEED to return to your [enthrallGender]":"like you have to return to [master]")].")
+ M.throw_at(get_step_towards(master,owner), 5, 1)
+ return//If you break the mind of someone, you can't use status effects on them.
+
+
+ //distance calculations
+ DistApart = get_dist(master, owner)
+ switch(DistApart)
+ if(0 to 8)//If the enchanter is within range, increase enthrallTally, remove withdrawal subproc and undo withdrawal effects.
+ if(phase <= 2)
+ enthrallTally += distancelist[get_dist(master, owner)+1]
+ if(withdrawalTick > 0)
+ withdrawalTick -= 1
+ //calming effects
+ M.hallucination = max(0, M.hallucination - 5)
+ M.stuttering = max(0, M.stuttering - 5)
+ M.jitteriness = max(0, M.jitteriness - 5)
+ if(owner.getBrainLoss() >=20)
+ owner.adjustBrainLoss(-0.2)
+ if(withdrawal == TRUE)
+ REMOVE_TRAIT(owner, TRAIT_PACIFISM, "MKUltra")
+ SEND_SIGNAL(M, COMSIG_CLEAR_MOOD_EVENT, "EnthMissing1")
+ SEND_SIGNAL(M, COMSIG_CLEAR_MOOD_EVENT, "EnthMissing2")
+ SEND_SIGNAL(M, COMSIG_CLEAR_MOOD_EVENT, "EnthMissing3")
+ SEND_SIGNAL(M, COMSIG_CLEAR_MOOD_EVENT, "EnthMissing4")
+ withdrawal = FALSE
+ if(9 to INFINITY)//If they're not nearby, enable withdrawl effects.
+ withdrawal = TRUE
+
+ //Withdrawal subproc:
+ if (withdrawal == TRUE)//Your minions are really REALLY needy.
+ switch(withdrawalTick)//denial
+ if(5)//To reduce spam
+ to_chat(owner, "You are unable to complete [(owner.client?.prefs.lewdchem?"your [enthrallGender]":"[master]")]'s orders without their presence, and any commands and objectives given to you prior are not in effect until you are back with them.")
+ ADD_TRAIT(owner, TRAIT_PACIFISM, "MKUltra") //IMPORTANT
+ if(10 to 35)//Gives wiggle room, so you're not SUPER needy
+ if(prob(5))
+ to_chat(owner, "You're starting to miss [(owner.client?.prefs.lewdchem?"your [enthrallGender]":"[master]")].")
+ if(prob(5))
+ owner.adjustBrainLoss(0.1)
+ to_chat(owner, "[(owner.client?.prefs.lewdchem?"[enthrallGender]":"[master]")] will surely be back soon") //denial
+ if(36)
+ var/message = "[(owner.client?.prefs.lewdchem?"I feel empty when [enthrallGender]'s not around..":"I miss [master]'s presence")]"
+ SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "EnthMissing1", /datum/mood_event/enthrallmissing1, message)
+ if(37 to 65)//barganing
+ if(prob(10))
+ to_chat(owner, "They are coming back, right...?")
+ owner.adjustBrainLoss(0.5)
+ if(prob(10))
+ if(owner.client?.prefs.lewdchem)
+ to_chat(owner, "I just need to be a good pet for [enthrallGender], they'll surely return if I'm a good pet.")
+ owner.adjustBrainLoss(-1.5)
+ if(66)
+ SEND_SIGNAL(M, COMSIG_CLEAR_MOOD_EVENT, "EnthMissing1")
+ var/message = "[(owner.client?.prefs.lewdchem?"I feel so lost in this complicated world without [enthrallGender]..":"I have to return to [master]!")]"
+ to_chat(owner, "You start to feel really angry about how you're not with [(owner.client?.prefs.lewdchem?"your [enthrallGender]":"[master]")]!")
+ SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "EnthMissing2", /datum/mood_event/enthrallmissing2, message)
+ owner.stuttering += 50
+ owner.jitteriness += 250
+ if(67 to 89) //anger
+ if(prob(10))
+ addtimer(CALLBACK(M, /mob/verb/a_intent_change, INTENT_HARM), 2)
+ addtimer(CALLBACK(M, /mob/proc/click_random_mob), 2)
+ if(owner.client?.prefs.lewdchem)
+ to_chat(owner, "You are overwhelmed with anger at the lack of [enthrallGender]'s presence and suddenly lash out!")
+ else
+ to_chat(owner, "You are overwhelmed with anger and suddenly lash out!")
+ if(90)
+ SEND_SIGNAL(M, COMSIG_CLEAR_MOOD_EVENT, "EnthMissing2")
+ var/message = "[(owner.client?.prefs.lewdchem?"Where are you [enthrallGender]??!":"I need to find [master]!")]"
+ SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "EnthMissing3", /datum/mood_event/enthrallmissing3, message)
+ if(owner.client?.prefs.lewdchem)
+ to_chat(owner, "You need to find your [enthrallGender] at all costs, you can't hold yourself back anymore!")
+ else
+ to_chat(owner, "You need to find [master] at all costs, you can't hold yourself back anymore!")
+ if(91 to 100)//depression
+ if(prob(10))
+ M.gain_trauma_type(BRAIN_TRAUMA_MILD)
+ owner.stuttering += 35
+ owner.jitteriness += 35
+ else if(prob(25))
+ M.hallucination += 10
+ if(101)
+ SEND_SIGNAL(M, COMSIG_CLEAR_MOOD_EVENT, "EnthMissing3")
+ var/message = "[(owner.client?.prefs.lewdchem?"I'm all alone, It's so hard to continute without [enthrallGender]...":"I really need to find [master]!!!")]"
+ SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "EnthMissing4", /datum/mood_event/enthrallmissing4, message)
+ to_chat(owner, "You can hardly find the strength to continue without [(owner.client?.prefs.lewdchem?"your [enthrallGender]":"[master]")].")
+ M.gain_trauma_type(BRAIN_TRAUMA_SEVERE)
+ if(102 to 140) //depression 2, revengeance
+ if(prob(20))
+ owner.Stun(50)
+ owner.emote("cry")//does this exist?
+ if(owner.client?.prefs.lewdchem)
+ to_chat(owner, "You're unable to hold back your tears, suddenly sobbing as the desire to see your [enthrallGender] oncemore overwhelms you.")
+ else
+ to_chat(owner, "You are overwheled with withdrawl from [master].")
+ owner.adjustBrainLoss(1)
+ owner.stuttering += 35
+ owner.jitteriness += 35
+ if(prob(10))//2% chance
+ switch(rand(1,5))//Now let's see what hopefully-not-important part of the brain we cut off
+ if(1 to 3)
+ M.gain_trauma_type(BRAIN_TRAUMA_MILD)
+ if(4)
+ M.gain_trauma_type(BRAIN_TRAUMA_SEVERE)
+ if(5)//0.4% chance
+ M.gain_trauma_type(BRAIN_TRAUMA_SPECIAL)
+ if(prob(5))
+ deltaResist += 5
+ if(140 to INFINITY) //acceptance
+ if(prob(15))
+ deltaResist += 5
+ owner.adjustBrainLoss(-1)
+ if(prob(20))
+ if(owner.client?.prefs.lewdchem)
+ to_chat(owner, "Maybe you'll be okay without your [enthrallGender].")
+ else
+ to_chat(owner, "You feel your mental functions slowly begin to return.")
+ if(prob(5))
+ owner.adjustBrainLoss(1)
+ M.hallucination += 30
+
+ withdrawalTick += 0.5//Enough to leave you with a major brain trauma, but not kill you.
+
+ //Status subproc - statuses given to you from your Master
+ //currently 3 statuses; antiresist -if you press resist, increases your enthrallment instead, HEAL - which slowly heals the pet, CHARGE - which breifly increases speed, PACIFY - makes pet a pacifist, ANTIRESIST - frustrates resist presses.
+ if (status)
+
+ if(status == "Antiresist")
+ if (statusStrength < 0)
+ status = null
+ to_chat(owner, "Your mind feels able to resist oncemore.")
+ else
+ statusStrength -= 1
+
+ else if(status == "heal")
+ if (statusStrength < 0)
+ status = null
+ to_chat(owner, "You finish licking your wounds.")
+ else
+ statusStrength -= 1
+ owner.heal_overall_damage(1, 1, 0, FALSE, FALSE)
+ cooldown += 1 //Cooldown doesn't process till status is done
+
+ else if(status == "charge")
+ ADD_TRAIT(owner, TRAIT_GOTTAGOFAST, "MKUltra")
+ status = "charged"
+ if(master.client?.prefs.lewdchem)
+ to_chat(owner, "Your [enthrallGender]'s order fills you with a burst of speed!")
+ else
+ to_chat(owner, "[master]'s command fills you with a burst of speed!")
+
+ else if (status == "charged")
+ if (statusStrength < 0)
+ status = null
+ REMOVE_TRAIT(owner, TRAIT_GOTTAGOFAST, "MKUltra")
+ owner.Knockdown(50)
+ to_chat(owner, "Your body gives out as the adrenaline in your system runs out.")
+ else
+ statusStrength -= 1
+ cooldown += 1 //Cooldown doesn't process till status is done
+
+ else if (status == "pacify")
+ ADD_TRAIT(owner, TRAIT_PACIFISM, "MKUltraStatus")
+ status = null
+
+ //Truth serum?
+ //adrenals?
+
+ //customEcho
+ if(customEcho && withdrawal == FALSE && owner.client?.prefs.lewdchem)
+ if(prob(2))
+ if(!customSpan) //just in case!
+ customSpan = "notice"
+ to_chat(owner, "[customEcho].")
+
+ //final tidying
+ resistanceTally += deltaResist
+ deltaResist = 0
+ if(cTriggered >= 0)
+ cTriggered -= 1
+ if (cooldown > 0)
+ cooldown -= (0.8 + (mental_capacity/500))
+ cooldownMsg = FALSE
+ else if (cooldownMsg == FALSE)
+ if(DistApart < 10)
+ if(master.client?.prefs.lewdchem)
+ to_chat(master, "Your pet [owner] appears to have finished internalising your last command.")
+ else
+ to_chat(master, "Your thrall [owner] appears to have finished internalising your last command.")
+ cooldownMsg = TRUE
+ cooldown = 0
+ if (tranceTime > 0 && tranceTime != 51) //custom trances only last 50 ticks.
+ tranceTime -= 1
+ else if (tranceTime == 0) //remove trance after.
+ M.cure_trauma_type(/datum/brain_trauma/hypnosis, TRAUMA_RESILIENCE_SURGERY)
+ M.remove_status_effect(/datum/status_effect/trance)
+ tranceTime = 51
+ //..()
+
+//Remove all stuff
+/datum/status_effect/chem/enthrall/on_remove()
+ var/mob/living/carbon/M = owner
+ M.mind.remove_antag_datum(/datum/antagonist/brainwashed)
+ SEND_SIGNAL(M, COMSIG_CLEAR_MOOD_EVENT, "enthrall")
+ SEND_SIGNAL(M, COMSIG_CLEAR_MOOD_EVENT, "enthrallpraise")
+ SEND_SIGNAL(M, COMSIG_CLEAR_MOOD_EVENT, "enthrallscold")
+ SEND_SIGNAL(M, COMSIG_CLEAR_MOOD_EVENT, "EnthMissing1")
+ SEND_SIGNAL(M, COMSIG_CLEAR_MOOD_EVENT, "EnthMissing2")
+ SEND_SIGNAL(M, COMSIG_CLEAR_MOOD_EVENT, "EnthMissing3")
+ SEND_SIGNAL(M, COMSIG_CLEAR_MOOD_EVENT, "EnthMissing4")
+ qdel(redirect_component.resolve())
+ redirect_component = null
+ UnregisterSignal(owner, COMSIG_MOVABLE_HEAR)
+ REMOVE_TRAIT(owner, TRAIT_PACIFISM, "MKUltra")
+ to_chat(owner, "You're now free of [master]'s influence, and fully independent!'")
+ UnregisterSignal(owner, COMSIG_GLOB_LIVING_SAY_SPECIAL)
+
+
+/datum/status_effect/chem/enthrall/proc/owner_hear(var/hearer, message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, message_mode)
+ if(owner.client?.prefs.lewdchem == FALSE)
+ return
+ if (cTriggered > 0)
+ return
+ var/mob/living/carbon/C = owner
+ raw_message = lowertext(raw_message)
+ for (var/trigger in customTriggers)
+ var/cached_trigger = lowertext(trigger)
+ if (findtext(raw_message, cached_trigger))//if trigger1 is the message
+ cTriggered = 5 //Stops triggerparties and as a result, stops servercrashes.
+ log_game("FERMICHEM: MKULTRA: [owner] ckey: [owner.key] has been triggered with [cached_trigger] from [speaker] saying: \"[message]\". (their master being [master] ckey: [enthrallID].)")
+
+ //Speak (Forces player to talk)
+ if (lowertext(customTriggers[trigger][1]) == "speak")//trigger2
+ var/saytext = "Your mouth moves on it's own before you can even catch it."
+ if(HAS_TRAIT(C, TRAIT_NYMPHO))
+ saytext += " You find yourself fully believing in the validity of what you just said and don't think to question it."
+ addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, C, "[saytext]"), 5)
+ addtimer(CALLBACK(C, /atom/movable/proc/say, "[customTriggers[trigger][2]]"), 5)
+ //(C.say(customTriggers[trigger][2]))//trigger3
+ log_game("FERMICHEM: MKULTRA: [owner] ckey: [owner.key] has been forced to say: \"[customTriggers[trigger][2]]\" from previous trigger.")
+
+
+ //Echo (repeats message!) allows customisation, but won't display var calls! Defaults to hypnophrase.
+ else if (lowertext(customTriggers[trigger][1]) == "echo")//trigger2
+ addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, C, "[customTriggers[trigger][2]]"), 5)
+ //(to_chat(owner, "[customTriggers[trigger][2]]"))//trigger3
+
+ //Shocking truth!
+ else if (lowertext(customTriggers[trigger]) == "shock")
+ if (C.canbearoused && C.client?.prefs.lewdchem)
+ C.adjustArousalLoss(5)
+ C.jitteriness += 100
+ C.stuttering += 25
+ C.Knockdown(60)
+ C.Stun(60)
+ to_chat(owner, "Your muscles seize up, then start spasming wildy!")
+
+ //wah intensifies wah-rks
+ else if (lowertext(customTriggers[trigger]) == "cum")//aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ if (HAS_TRAIT(C, TRAIT_NYMPHO) && C.client?.prefs.lewdchem)
+ if (C.getArousalLoss() > 80)
+ C.mob_climax(forced_climax=TRUE)
+ C.SetStun(10)//We got your stun effects in somewhere, Kev.
+ else
+ C.adjustArousalLoss(10)
+ to_chat(C, "You feel a surge of arousal!")
+ else
+ C.throw_at(get_step_towards(speaker,C), 3, 1) //cut this if it's too hard to get working
+
+ //kneel (knockdown)
+ else if (lowertext(customTriggers[trigger]) == "kneel")//as close to kneeling as you can get, I suppose.
+ to_chat(owner, "You drop to the ground unsurreptitiously.")
+ C.lay_down()
+
+ //strip (some) clothes
+ else if (lowertext(customTriggers[trigger]) == "strip")//This wasn't meant to just be a lewd thing oops.
+ var/mob/living/carbon/human/o = owner
+ var/items = o.get_contents()
+ for(var/obj/item/W in items)
+ if(W == o.w_uniform || W == o.wear_suit)
+ o.dropItemToGround(W, TRUE)
+ to_chat(owner,"You feel compelled to strip your clothes.")
+
+ //trance
+ else if (lowertext(customTriggers[trigger]) == "trance")//Maaaybe too strong. Weakened it, only lasts 50 ticks.
+ var/mob/living/carbon/human/o = owner
+ o.apply_status_effect(/datum/status_effect/trance, 200, TRUE)
+ tranceTime = 50
+ log_game("FERMICHEM: MKULTRA: [owner] ckey: [owner.key] has been tranced from previous trigger.")
+
+ return
+
+/datum/status_effect/chem/enthrall/proc/owner_resist()
+ var/mob/living/carbon/M = owner
+ to_chat(owner, "You attempt to fight against [master]'s influence!")
+
+ //Able to resist checks
+ if (status == "Sleeper" || phase == 0)
+ return
+ else if (phase == 4)
+ if(owner.client?.prefs.lewdchem)
+ to_chat(owner, "Your mind is too far gone to even entertain the thought of resisting. Unless you can fix the brain damage, you won't be able to break free of your [enthrallGender]'s control.")
+ else
+ to_chat(owner, "Your brain is too overwhelmed with from the high volume of chemicals in your system, rendering you unable to resist, unless you can fix the brain damage.")
+ return
+ else if (phase == 3 && withdrawal == FALSE)
+ if(owner.client?.prefs.lewdchem)
+ to_chat(owner, "The presence of your [enthrallGender] fully captures the horizon of your mind, removing any thoughts of resistance. If you get split up from them, then you might be able to entertain the idea of resisting.")
+ else
+ to_chat(owner, "You are unable to resist [master] in your current state. If you get split up from them, then you might be able to resist.")
+ return
+ else if (status == "Antiresist")//If ordered to not resist; resisting while ordered to not makes it last longer, and increases the rate in which you are enthralled.
+ if (statusStrength > 0)
+ if(owner.client?.prefs.lewdchem)
+ to_chat(owner, "The order from your [enthrallGender] to give in is conflicting with your attempt to resist, drawing you deeper into trance! You'll have to wait a bit before attemping again, lest your attempts become frustrated again.")
+ else
+ to_chat(owner, "The order from your [master] to give in is conflicting with your attempt to resist. You'll have to wait a bit before attemping again, lest your attempts become frustrated again.")
+ statusStrength += 1
+ enthrallTally += 1
+ return
+ else
+ status = null
+
+ //base resistance
+ if (deltaResist != 0)//So you can't spam it, you get one deltaResistance per tick.
+ deltaResist += 0.1 //Though I commend your spamming efforts.
+ return
+ else
+ deltaResist = 1.8 + resistGrowth
+ resistGrowth += 0.05
+
+ //distance modifer
+ switch(DistApart)
+ if(0)
+ deltaResist *= 0.8
+ if(1 to 8)//If they're far away, increase resistance.
+ deltaResist *= (1+(DistApart/10))
+ if(9 to INFINITY)//If
+ deltaResist *= 2
+
+
+ if(prob(5))
+ M.emote("me",1,"squints, shaking their head for a moment.")//shows that you're trying to resist sometimes
+ deltaResist *= 1.5
+ //nymphomania
+ if (M.canbearoused && HAS_TRAIT(M, TRAIT_NYMPHO))//I'm okay with this being removed.
+ deltaResist*= 0.5-(((2/200)*M.arousalloss)/1)//more aroused you are, the weaker resistance you can give, the less you are, the more you gain. (+/- 0.5)
+
+ //chemical resistance, brain and annaphros are the key to undoing, but the subject has to to be willing to resist.
+ if (owner.reagents.has_reagent("mannitol"))
+ deltaResist *= 1.25
+ if (owner.reagents.has_reagent("neurine"))
+ deltaResist *= 1.5
+ if (!HAS_TRAIT(owner, TRAIT_CROCRIN_IMMUNE) && M.canbearoused)
+ if (owner.reagents.has_reagent("anaphro"))
+ deltaResist *= 1.5
+ if (owner.reagents.has_reagent("anaphro+"))
+ deltaResist *= 2
+ if (owner.reagents.has_reagent("aphro"))
+ deltaResist *= 0.75
+ if (owner.reagents.has_reagent("aphro+"))
+ deltaResist *= 0.5
+
+ //Antag resistance
+ //cultists are already brainwashed by their god
+ if(iscultist(owner))
+ deltaResist *= 1.3
+ else if (is_servant_of_ratvar(owner))
+ deltaResist *= 1.3
+ //antags should be able to resist, so they can do their other objectives. This chem does frustrate them, but they've all the tools to break free when an oportunity presents itself.
+ else if (owner.mind.assigned_role in GLOB.antagonists)
+ deltaResist *= 1.2
+
+ //role resistance
+ //Chaplains are already brainwashed by their god
+ if(owner.mind.assigned_role == "Chaplain")
+ deltaResist *= 1.2
+ //Command staff has authority,
+ if(owner.mind.assigned_role in GLOB.command_positions)
+ deltaResist *= 1.1
+ //Chemists should be familiar with drug effects
+ if(owner.mind.assigned_role == "Chemist")
+ deltaResist *= 1.2
+
+ //Happiness resistance
+ //Your Thralls are like pets, you need to keep them happy.
+ if(owner.nutrition < 300)
+ deltaResist += (300-owner.nutrition)/6
+ if(owner.health < 100)//Harming your thrall will make them rebel harder.
+ deltaResist *= ((120-owner.health)/100)+1
+ //if(owner.mood.mood) //datum/component/mood TO ADD in FERMICHEM 2
+ //Add cold/hot, oxygen, sanity, happiness? (happiness might be moot, since the mood effects are so strong)
+ //Mental health could play a role too in the other direction
+
+ //If you've a collar, you get a sense of pride
+ if(istype(M.wear_neck, /obj/item/clothing/neck/petcollar))
+ deltaResist *= 0.5
+ if(HAS_TRAIT(M, TRAIT_MINDSHIELD))
+ deltaResist += 5//even faster!
+
+ return
diff --git a/modular_citadel/code/datums/traits/negative.dm b/modular_citadel/code/datums/traits/negative.dm
new file mode 100644
index 0000000000..c0cbe57b5a
--- /dev/null
+++ b/modular_citadel/code/datums/traits/negative.dm
@@ -0,0 +1 @@
+// Citadel-specific Negative Traits
diff --git a/modular_citadel/code/datums/traits/neutral.dm b/modular_citadel/code/datums/traits/neutral.dm
index 05aeb27361..197c9b94e1 100644
--- a/modular_citadel/code/datums/traits/neutral.dm
+++ b/modular_citadel/code/datums/traits/neutral.dm
@@ -31,3 +31,13 @@
mob_trait = TRAIT_MASO
gain_text = "You desire to be hurt."
lose_text = "Pain has become less exciting for you."
+
+/datum/quirk/pharmacokinesis //Prevents unwanted organ additions.
+ name = "Acute hepatic pharmacokinesis"
+ desc = "You've a rare genetic disorder that causes Incubus draft and Sucubus milk to be absorbed by your liver instead."
+ value = 0
+ mob_trait = TRAIT_PHARMA
+ lose_text = "Your liver feels different."
+ var/active = FALSE
+ var/power = 0
+ var/cachedmoveCalc = 1
diff --git a/modular_citadel/code/game/machinery/vending.dm b/modular_citadel/code/game/machinery/vending.dm
index 12c29f7d98..2de98a3171 100755
--- a/modular_citadel/code/game/machinery/vending.dm
+++ b/modular_citadel/code/game/machinery/vending.dm
@@ -22,6 +22,7 @@
/obj/item/storage/hypospraykit/toxin = 2,
/obj/item/storage/hypospraykit/o2 = 2,
/obj/item/storage/hypospraykit/brute = 2,
+ /obj/item/storage/hypospraykit/enlarge = 2,
/obj/item/reagent_containers/glass/bottle/vial/small = 5)
/obj/machinery/vending/wardrobe/chap_wardrobe
diff --git a/modular_citadel/code/game/machinery/wishgranter.dm b/modular_citadel/code/game/machinery/wishgranter.dm
index f7c2c57d08..f24062a126 100644
--- a/modular_citadel/code/game/machinery/wishgranter.dm
+++ b/modular_citadel/code/game/machinery/wishgranter.dm
@@ -95,7 +95,7 @@
killwish.grasp_range = 6
killwish.melee_damage_upper = 30
killwish.grasp_chance = 50
- killwish.loot = list(/obj/item/twohanded/hypereutactic)
+ killwish.loot = list(/obj/item/twohanded/dualsaber/hypereutactic)
charges--
insisting = FALSE
if(!charges)
diff --git a/modular_citadel/code/game/objects/items.dm b/modular_citadel/code/game/objects/items.dm
index 337db986b0..c94923f9de 100644
--- a/modular_citadel/code/game/objects/items.dm
+++ b/modular_citadel/code/game/objects/items.dm
@@ -1,6 +1,4 @@
/obj/item
- var/total_mass //Total mass in arbitrary pound-like values. If there's no balance reasons for an item to have otherwise, this var should be the item's weight in pounds.
-
var/list/alternate_screams = list() //REEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
// lazy for screaming.
diff --git a/modular_citadel/code/game/objects/items/handcuffs.dm b/modular_citadel/code/game/objects/items/handcuffs.dm
deleted file mode 100644
index ed5e8a191e..0000000000
--- a/modular_citadel/code/game/objects/items/handcuffs.dm
+++ /dev/null
@@ -1,5 +0,0 @@
-/obj/item/restraints/handcuffs/fake/kinky
- name = "kinky handcuffs"
- desc = "Fake handcuffs meant for erotic roleplay."
- icon = 'modular_citadel/icons/obj/items_and_weapons.dmi'
- icon_state = "handcuffgag"
diff --git a/modular_citadel/code/game/objects/items/melee/energy.dm b/modular_citadel/code/game/objects/items/melee/energy.dm
deleted file mode 100644
index c37f88eacf..0000000000
--- a/modular_citadel/code/game/objects/items/melee/energy.dm
+++ /dev/null
@@ -1,3 +0,0 @@
-/obj/item/melee/transforming/energy/sword
- total_mass = 0.375 //Survival flashlights typically weigh around 5 ounces.
- total_mass_on = 3.4 //The typical medieval sword, on the other hand, weighs roughly 3 pounds.
diff --git a/modular_citadel/code/game/objects/items/melee/eutactic_blades.dm b/modular_citadel/code/game/objects/items/melee/eutactic_blades.dm
index 6e28a3115f..68ab229f0a 100644
--- a/modular_citadel/code/game/objects/items/melee/eutactic_blades.dm
+++ b/modular_citadel/code/game/objects/items/melee/eutactic_blades.dm
@@ -124,7 +124,7 @@
return
else
to_chat(user, "You combine the two light swords, making a single supermassive blade! You're cool.")
- new /obj/item/twohanded/hypereutactic(user.drop_location())
+ new /obj/item/twohanded/dualsaber/hypereutactic(user.drop_location())
qdel(W)
qdel(src)
else
@@ -233,7 +233,7 @@
return
else
to_chat(user, "You combine the two plastic swords, making a single supermassive toy! You're fake-cool.")
- new /obj/item/twohanded/hypereutactic/toy(user.loc)
+ new /obj/item/twohanded/dualsaber/hypereutactic/toy(user.loc)
qdel(W)
qdel(src)
else
@@ -247,7 +247,7 @@
// HYPEREUTACTIC Blades /////////////////////////
/////////////////////////////////////////////////////
-/obj/item/twohanded/hypereutactic
+/obj/item/twohanded/dualsaber/hypereutactic
icon = 'modular_citadel/icons/eutactic/item/hypereutactic.dmi'
icon_state = "hypereutactic"
lefthand_file = 'modular_citadel/icons/eutactic/mob/hypereutactic_left.dmi'
@@ -258,58 +258,29 @@
name = "hypereutactic blade"
desc = "A supermassive weapon envisioned to cleave the very fabric of space and time itself in twain, the hypereutactic blade dynamically flash-forges a hypereutactic crystaline nanostructure capable of passing through most known forms of matter like a hot knife through butter."
force = 7
- throwforce = 5
- throw_speed = 3
- throw_range = 5
- w_class = WEIGHT_CLASS_SMALL
- var/w_class_on = WEIGHT_CLASS_BULKY
force_unwielded = 7
force_wielded = 40
wieldsound = 'sound/weapons/nebon.ogg'
unwieldsound = 'sound/weapons/neboff.ogg'
- hitsound = "swing_hit"
+ hitsound_on = 'sound/weapons/nebhit.ogg'
+ slowdown_wielded = 1
armour_penetration = 60
light_color = "#37FFF7"
+ rainbow_colors = list("#FF0000", "#FFFF00", "#00FF00", "#00FFFF", "#0000FF","#FF00FF", "#3399ff", "#ff9900", "#fb008b", "#9800ff", "#00ffa3", "#ccff00")
attack_verb = list("attacked", "slashed", "stabbed", "sliced", "destroyed", "ripped", "devastated", "shredded")
- block_chance = 75
- max_integrity = 200
- armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 100, acid = 70)
- resistance_flags = FIRE_PROOF
- var/brightness_on = 6 //TWICE AS BRIGHT AS A REGULAR ESWORD
- item_flags = SLOWS_WHILE_IN_HAND
+ spinnable = FALSE
+ total_mass_on = 4
-/obj/item/twohanded/hypereutactic/pre_altattackby(atom/A, mob/living/user, params) //checks if it can do right click memes
+/obj/item/twohanded/dualsaber/hypereutactic/pre_altattackby(atom/A, mob/living/user, params) //checks if it can do right click memes
altafterattack(A, user, TRUE, params)
return TRUE
-/obj/item/twohanded/hypereutactic/altafterattack(atom/target, mob/living/carbon/user, proximity_flag, click_parameters) //does right click memes
+/obj/item/twohanded/dualsaber/hypereutactic/altafterattack(atom/target, mob/living/user, proximity_flag, click_parameters) //does right click memes
if(istype(user))
user.visible_message("[user] points the tip of [src] at [target].", "You point the tip of [src] at [target].")
return TRUE
-/obj/item/twohanded/hypereutactic/wield(mob/living/carbon/M) //Specific wield () hulk checks due to reflection chance for balance issues and switches hitsounds.
- if(M.has_dna())
- if(M.dna.check_mutation(HULK))
- to_chat(M, "You lack the grace to wield this!")
- return
- ..()
- if(wielded)
- sharpness = IS_SHARP
- w_class = w_class_on
- hitsound = 'sound/weapons/nebhit.ogg'
- START_PROCESSING(SSobj, src)
- set_light(brightness_on)
-
-/obj/item/twohanded/hypereutactic/unwield() //Specific unwield () to switch hitsounds.
- sharpness = initial(sharpness)
- w_class = initial(w_class)
- ..()
- hitsound = "swing_hit"
- STOP_PROCESSING(SSobj, src)
- set_light(0)
- slowdown = initial(slowdown)
-
-/obj/item/twohanded/hypereutactic/update_icon()
+/obj/item/twohanded/dualsaber/hypereutactic/update_icon()
var/mutable_appearance/blade_overlay = mutable_appearance('modular_citadel/icons/eutactic/item/hypereutactic.dmi', "hypereutactic_blade")
var/mutable_appearance/gem_overlay = mutable_appearance('modular_citadel/icons/eutactic/item/hypereutactic.dmi', "hypereutactic_gem")
@@ -329,21 +300,21 @@
SEND_SIGNAL(src, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)//blood overlays get weird otherwise, because the sprite changes. (retained from original desword because I have no idea what this is)
-/obj/item/twohanded/hypereutactic/AltClick(mob/living/user)
- if(!in_range(src, user)) //Basic checks to prevent abuse
+/obj/item/twohanded/dualsaber/hypereutactic/AltClick(mob/living/user)
+ if(!user.canUseTopic(src, BE_CLOSE, FALSE) || hacked)
return
if(user.incapacitated() || !istype(user))
to_chat(user, "You can't do that right now!")
return
-
if(alert("Are you sure you want to recolor your blade?", "Confirm Repaint", "Yes", "No") == "Yes")
var/energy_color_input = input(usr,"","Choose Energy Color",light_color) as color|null
- if(energy_color_input)
- light_color = sanitize_hexcolor(energy_color_input, desired_format=6, include_crunch=1)
+ if(!energy_color_input || !user.canUseTopic(src, BE_CLOSE, FALSE) || hacked)
+ return
+ light_color = sanitize_hexcolor(energy_color_input, desired_format=6, include_crunch=1)
update_icon()
update_light()
-/obj/item/twohanded/hypereutactic/worn_overlays(isinhands, icon_file)
+/obj/item/twohanded/dualsaber/hypereutactic/worn_overlays(isinhands, icon_file)
. = ..()
if(isinhands)
var/mutable_appearance/gem_inhand = mutable_appearance(icon_file, "hypereutactic_gem")
@@ -354,70 +325,19 @@
blade_inhand.color = light_color
. += blade_inhand
-/obj/item/twohanded/hypereutactic/examine(mob/user)
+/obj/item/twohanded/dualsaber/hypereutactic/examine(mob/user)
..()
- to_chat(user, "Alt-click to recolor it.")
+ if(!hacked)
+ to_chat(user, "Alt-click to recolor it.")
-////////// stuff beneath this is all taken from the desword //////////// wow very professional such OOP wow
-
-/obj/item/twohanded/hypereutactic/attack(mob/target, mob/living/carbon/human/user)
- if(user.has_dna())
- if(user.dna.check_mutation(HULK))
- to_chat(user, "You grip the blade too hard and accidentally close it!")
- unwield()
- return
- ..()
- if(HAS_TRAIT(user, TRAIT_CLUMSY) && (wielded) && prob(40))
- impale(user)
- return
-
-/obj/item/twohanded/hypereutactic/Destroy()
- STOP_PROCESSING(SSobj, src)
+/obj/item/twohanded/dualsaber/hypereutactic/rainbow_process()
. = ..()
-
-/obj/item/twohanded/hypereutactic/proc/impale(mob/living/user)
- to_chat(user, "You spin around a bit before losing your balance and impaling yourself on [src].")
- if (force_wielded)
- user.take_bodypart_damage(20,25)
- else
- user.adjustStaminaLoss(25)
-
-/obj/item/twohanded/hypereutactic/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
- if(wielded)
- return ..()
- return FALSE
-
-/obj/item/twohanded/hypereutactic/attack_hulk(mob/living/carbon/human/user, does_attack_animation = 0) //In case thats just so happens that it is still activated on the groud, prevents hulk from picking it up
- if(wielded)
- to_chat(user, "You can't pick up such dangerous item with your meaty hands without losing fingers, better not to!")
- return TRUE
-
-/obj/item/twohanded/hypereutactic/process()
- if(wielded)
- open_flame()
- else
- STOP_PROCESSING(SSobj, src)
-
-/obj/item/twohanded/hypereutactic/IsReflect()
- if(wielded)
- return TRUE
-
-/obj/item/twohanded/hypereutactic/ignition_effect(atom/A, mob/user)
- // same as /obj/item/melee/transforming/energy, mostly
- if(!wielded)
- return ""
- var/in_mouth = ""
- if(iscarbon(user))
- var/mob/living/carbon/C = user
- if(C.wear_mask == src)
- in_mouth = ", barely missing their nose"
- . = "[user] swings [user.p_their()] [src][in_mouth]. [user.p_they()] light[user.p_s()] [A] in the process."
- playsound(loc, hitsound, get_clamped_volume(), 1, -1)
- add_fingerprint(user)
+ update_icon()
+ update_light()
////////////////// TOY VERSION /////////////////////////////
-/obj/item/twohanded/hypereutactic/toy
+/obj/item/twohanded/dualsaber/hypereutactic/toy
name = "\improper DX Hyper-Euplastic LightSword"
desc = "A supermassive toy envisioned to cleave the very fabric of space and time itself in twain. Realistic visuals and sounds! Ages 8 and up."
force = 0
@@ -427,11 +347,13 @@
force_unwielded = 0
force_wielded = 0
attack_verb = list("attacked", "struck", "hit")
+ total_mass_on = TOTAL_MASS_TOY_SWORD
+ slowdown_wielded = 0
-/obj/item/twohanded/hypereutactic/toy/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
+/obj/item/twohanded/dualsaber/hypereutactic/toy/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
return FALSE
-/obj/item/twohanded/hypereutactic/toy/IsReflect()//Stops it from reflecting energy projectiles
+/obj/item/twohanded/dualsaber/hypereutactic/toy/IsReflect()//Stops it from reflecting energy projectiles
return FALSE
//////// Tatortot NEB /////////////// (same stats as regular esword)
@@ -455,17 +377,7 @@
//RAINBOW MEMES
-/obj/item/twohanded/hypereutactic/toy/rainbow
+/obj/item/twohanded/dualsaber/hypereutactic/toy/rainbow
name = "\improper Hyper-Euclidean Reciprocating Trigonometric Zweihander"
desc = "A custom-built toy with fancy rainbow lights built-in."
- var/list/rainbow_colors = list("#FF0000", "#FFFF00", "#00FF00", "#00FFFF", "#0000FF","#FF00FF", "#3399ff", "#ff9900", "#fb008b", "#9800ff", "#00ffa3", "#ccff00")
-
-/obj/item/twohanded/hypereutactic/toy/rainbow/process()
- . = ..()
- var/set_color = pick(rainbow_colors)
- light_color = set_color
- update_light()
- update_icon()
-
-/obj/item/twohanded/hypereutactic/toy/rainbow/AltClick(mob/living/user)
- return
+ hacked = TRUE
\ No newline at end of file
diff --git a/modular_citadel/code/game/objects/items/melee/transforming.dm b/modular_citadel/code/game/objects/items/melee/transforming.dm
deleted file mode 100644
index 46610f4e54..0000000000
--- a/modular_citadel/code/game/objects/items/melee/transforming.dm
+++ /dev/null
@@ -1,15 +0,0 @@
-/obj/item/melee/transforming
- var/total_mass_on //Total mass in ounces when transformed. Primarily for balance purposes. Don't think about it too hard.
-
-/obj/item/melee/transforming/getweight()
- if(total_mass && total_mass_on)
- if(active)
- return max(total_mass_on,MIN_MELEE_STAMCOST)
- else
- return max(total_mass,MIN_MELEE_STAMCOST)
- else
- return initial(w_class)*1.25
-
-/obj/item/melee/transforming/cleaving_saw
- total_mass = 2.75
- total_mass_on = 5
diff --git a/modular_citadel/code/game/objects/items/storage/firstaid.dm b/modular_citadel/code/game/objects/items/storage/firstaid.dm
index 6ff1bfbe2c..125330a9b9 100755
--- a/modular_citadel/code/game/objects/items/storage/firstaid.dm
+++ b/modular_citadel/code/game/objects/items/storage/firstaid.dm
@@ -103,6 +103,22 @@
new /obj/item/reagent_containers/glass/bottle/vial/small/preloaded/dexalin(src)
new /obj/item/reagent_containers/glass/bottle/vial/small/preloaded/dexalin(src)
+/obj/item/storage/hypospraykit/enlarge
+ name = "organomegaly trauma hypospray kit"
+ icon_state = "enlarge-mini"
+ item_state = "firstaid-brute"
+
+/obj/item/storage/hypospraykit/enlarge/PopulateContents()
+ if(empty)
+ return
+ new /obj/item/hypospray/mkii/enlarge(src)
+ new /obj/item/reagent_containers/glass/bottle/vial/small/preloaded/breastreduction(src)
+ new /obj/item/reagent_containers/glass/bottle/vial/small/preloaded/breastreduction(src)
+ new /obj/item/reagent_containers/glass/bottle/vial/small/preloaded/breastreduction(src)
+ new /obj/item/reagent_containers/glass/bottle/vial/small/preloaded/penisreduction(src)
+ new /obj/item/reagent_containers/glass/bottle/vial/small/preloaded/penisreduction(src)
+ new /obj/item/reagent_containers/glass/bottle/vial/small/preloaded/penisreduction(src)
+
/obj/item/storage/hypospraykit/brute
name = "brute trauma hypospray kit"
icon_state = "brute-mini"
diff --git a/modular_citadel/code/game/objects/items/stunsword.dm b/modular_citadel/code/game/objects/items/stunsword.dm
index 1262b0018a..7a5398f7d2 100644
--- a/modular_citadel/code/game/objects/items/stunsword.dm
+++ b/modular_citadel/code/game/objects/items/stunsword.dm
@@ -7,6 +7,14 @@
lefthand_file = 'modular_citadel/icons/mob/inhands/stunsword_left.dmi'
righthand_file = 'modular_citadel/icons/mob/inhands/stunsword_right.dmi'
+/obj/item/melee/baton/stunsword/get_belt_overlay()
+ if(istype(loc, /obj/item/storage/belt/sabre))
+ return mutable_appearance('icons/obj/clothing/belt_overlays.dmi', "stunsword")
+ return ..()
+
+/obj/item/melee/baton/stunsword/get_worn_belt_overlay(icon_file)
+ return mutable_appearance(icon_file, "-stunsword")
+
/obj/item/ssword_kit
name = "stunsword kit"
desc = "a modkit for making a stunbaton into a stunsword"
diff --git a/modular_citadel/code/init.dm b/modular_citadel/code/init.dm
index 2c2b5b811f..ce80580af2 100644
--- a/modular_citadel/code/init.dm
+++ b/modular_citadel/code/init.dm
@@ -22,4 +22,4 @@
GLOB.cock_shapes_icons[K] = value.icon_state
init_sprite_accessory_subtypes(/datum/sprite_accessory/vagina, GLOB.vagina_shapes_list)
init_sprite_accessory_subtypes(/datum/sprite_accessory/breasts, GLOB.breasts_shapes_list)
- GLOB.breasts_size_list = list("a","b","c","d","e") //We need the list to choose from initialized, but it's no longer a sprite_accessory thing.
+ //GLOB.breasts_size_list = list("a","b","c","d","e") //We need the list to choose from initialized, but it's no longer a sprite_accessory thing. This is defined twice?
diff --git a/modular_citadel/code/modules/admin/chat_commands.dm b/modular_citadel/code/modules/admin/chat_commands.dm
index 918b1dda5a..39f4158646 100644
--- a/modular_citadel/code/modules/admin/chat_commands.dm
+++ b/modular_citadel/code/modules/admin/chat_commands.dm
@@ -20,3 +20,26 @@
/datum/tgs_chat_command/despacito/Run()
return "https://www.youtube.com/watch?v=kJQP7kiw5Fk"
+
+/datum/tgs_chat_command/poly
+ name = "poly"
+ help_text = "The Lewder, more applicable Poly speak for Citadel Station 13."
+ var/list/speech_buffer
+
+/datum/tgs_chat_command/poly/Run()
+ GenerateSayList() //Has a check in here, but we're gunna sanity it after
+ if(!speech_buffer)
+ return "**BAWWWWWK!** LEAVE THE HEADSET! ***BAWKKKKK!!***"
+
+
+/datum/tgs_chat_command/poly/proc/GenerateSayList()
+ LAZYINITLIST(speech_buffer) //I figure this is just safe to do for everything at this point
+ if(length(speech_buffer)) //Let's not look up the whole json EVERY TIME, just the first time.
+ return "[pick(speech_buffer)]"
+ else
+ var/json_file = file("data/npc_saves/Poly.json")
+ if(!fexists(json_file))
+ return
+ var/list/json = json_decode(file2text(json_file))
+ speech_buffer = json["phrases"]
+ return "[pick(speech_buffer)]"
\ No newline at end of file
diff --git a/modular_citadel/code/modules/arousal/organs/breasts.dm b/modular_citadel/code/modules/arousal/organs/breasts.dm
index 1223f0b616..3df2218766 100644
--- a/modular_citadel/code/modules/arousal/organs/breasts.dm
+++ b/modular_citadel/code/modules/arousal/organs/breasts.dm
@@ -5,20 +5,22 @@
icon = 'modular_citadel/icons/obj/genitals/breasts.dmi'
zone = "chest"
slot = "breasts"
- size = BREASTS_SIZE_DEF
+ w_class = 3
+ size = BREASTS_SIZE_DEF //SHOULD BE A LETTER, starts as a number...???
+ var/cached_size = null //for enlargement SHOULD BE A NUMBER
+ var/prev_size //For flavour texts SHOULD BE A LETTER
+ //var/breast_sizes = list ("a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "huge", "flat")
+ var/breast_values = list ("a" = 1, "b" = 2, "c" = 3, "d" = 4, "e" = 5, "f" = 6, "g" = 7, "h" = 8, "i" = 9, "j" = 10, "k" = 11, "l" = 12, "m" = 13, "n" = 14, "o" = 15, "huge" = 16, "flat" = 0)
+ var/statuscheck = FALSE
fluid_id = "milk"
var/amount = 2
producing = TRUE
- shape = "pair"
+ shape = "Pair"
can_masturbate_with = TRUE
masturbation_verb = "massage"
can_climax = TRUE
fluid_transfer_factor = 0.5
-/obj/item/organ/genital/breasts/Initialize()
- . = ..()
- reagents.add_reagent(fluid_id, fluid_max_volume)
-
/obj/item/organ/genital/breasts/on_life()
if(QDELETED(src))
return
@@ -26,6 +28,14 @@
return
reagents.maximum_volume = fluid_max_volume
if(fluid_id && producing)
+ if(reagents.total_volume == 0) // Apparently, 0.015 gets rounded down to zero and no reagents are created if we don't start it with 0.1 in the tank.
+ fluid_rate = 0.1
+ else
+ fluid_rate = CUM_RATE
+ if(reagents.total_volume >= 5)
+ fluid_mult = 0.5
+ else
+ fluid_mult = 1
generate_milk()
/obj/item/organ/genital/breasts/proc/generate_milk()
@@ -45,10 +55,15 @@
desc = "You see three sets of breasts, running from their chest to their belly."
else
desc = "You see some breasts, they seem to be quite exotic."
- if (size)
- desc += " You estimate that they're [uppertext(size)]-cups."
- else
- desc += " You wouldn't measure them in cup sizes."
+ if(cached_size > 16)
+ desc = "You see [pick("some serious honkers", "a real set of badonkers", "some dobonhonkeros", "massive dohoonkabhankoloos", "two big old tonhongerekoogers", "a couple of giant bonkhonagahoogs", "a pair of humongous hungolomghnonoloughongous")]. Their volume is way beyond cupsize now, measuring in about [round(cached_size)]cm in diameter."
+ else if (!isnum(size))
+ if (size == "flat")
+ desc += " They're very small and flatchested, however."
+ else
+ desc += " You estimate that they're [uppertext(size)]-cups."
+ //string = "breasts_[lowertext(shape)]_[size]-s"
+
if(producing && aroused_state)
desc += " They're leaking [fluid_id]."
var/string
@@ -65,3 +80,57 @@
var/mob/living/carbon/human/H = owner
icon_state = sanitize_text(string)
H.update_genitals()
+
+ icon_state = sanitize_text(string)
+
+
+//Allows breasts to grow and change size, with sprite changes too.
+//maximum wah
+//Comical sizes slow you down in movement and actions.
+//Rediculous sizes makes you more cumbersome.
+//this is far too lewd wah
+
+/obj/item/organ/genital/breasts/update_size()//wah
+
+ if(!ishuman(owner) || !owner)
+ return
+ if(cached_size < 0)//I don't actually know what round() does to negative numbers, so to be safe!!fixed
+ to_chat(owner, "You feel your breasts shrinking away from your body as your chest flattens out.")
+ src.Remove(owner)
+ switch(round(cached_size))
+ if(0) //If flatchested
+ size = "flat"
+ if(owner.has_status_effect(/datum/status_effect/chem/breast_enlarger))
+ owner.remove_status_effect(/datum/status_effect/chem/breast_enlarger)
+ statuscheck = FALSE
+ if(1 to 8) //If modest size
+ size = breast_values[round(cached_size)]
+ if(owner.has_status_effect(/datum/status_effect/chem/breast_enlarger))
+ owner.remove_status_effect(/datum/status_effect/chem/breast_enlarger)
+ statuscheck = FALSE
+ if(9 to 15) //If massive
+ size = breast_values[round(cached_size)]
+ if(!owner.has_status_effect(/datum/status_effect/chem/breast_enlarger))
+ owner.apply_status_effect(/datum/status_effect/chem/breast_enlarger)
+ statuscheck = TRUE
+ if(16 to INFINITY) //if Rediculous
+ size = cached_size
+
+ if(round(cached_size) < 16)//Because byond doesn't count from 0, I have to do this.
+ if (prev_size == 0)
+ prev_size = "flat"
+ if(size == 0)//Bloody byond with it's counting from 1
+ size = "flat"
+ if(isnum(prev_size))
+ prev_size = breast_values[prev_size]
+ if (breast_values[size] > breast_values[prev_size])
+ to_chat(owner, "Your breasts [pick("swell up to", "flourish into", "expand into", "burst forth into", "grow eagerly into", "amplify into")] a [uppertext(size)]-cup.")
+ var/mob/living/carbon/human/H = owner
+ H.Force_update_genitals()
+ else if ((breast_values[size] < breast_values[prev_size]) && (breast_values[size] > 0.5))
+ to_chat(owner, "Your breasts [pick("shrink down to", "decrease into", "diminish into", "deflate into", "shrivel regretfully into", "contracts into")] a [uppertext(size)]-cup.")
+ var/mob/living/carbon/human/H = owner
+ H.Force_update_genitals()
+ prev_size = size
+ else if (cached_size >= 16)
+ size = "huge"
diff --git a/modular_citadel/code/modules/arousal/organs/genitals.dm b/modular_citadel/code/modules/arousal/organs/genitals.dm
index 63d6834409..3abe7ecb1f 100644
--- a/modular_citadel/code/modules/arousal/organs/genitals.dm
+++ b/modular_citadel/code/modules/arousal/organs/genitals.dm
@@ -1,7 +1,7 @@
/obj/item/organ/genital
color = "#fcccb3"
w_class = WEIGHT_CLASS_NORMAL
- var/shape = "human"
+ var/shape = "Human" //Changed to be uppercase, let me know if this breaks everything..!!
var/sensitivity = AROUSAL_START_VALUE
var/list/genital_flags = list()
var/can_masturbate_with = FALSE
@@ -10,7 +10,7 @@
var/fluid_transfer_factor = 0.0 //How much would a partner get in them if they climax using this?
var/size = 2 //can vary between num or text, just used in icon_state strings
var/fluid_id = null
- var/fluid_max_volume = 50
+ var/fluid_max_volume = 15
var/fluid_efficiency = 1
var/fluid_rate = 1
var/fluid_mult = 1
@@ -172,6 +172,8 @@
P.length = dna.features["cock_length"]
P.girth_ratio = dna.features["cock_girth_ratio"]
P.shape = dna.features["cock_shape"]
+ P.prev_length = P.length
+ P.cached_length = P.length
P.update()
/mob/living/carbon/human/proc/give_balls()
@@ -214,8 +216,21 @@
else
B.color = "#[dna.features["breasts_color"]]"
B.size = dna.features["breasts_size"]
+ if(!isnum(B.size))
+ if(B.size == "flat")
+ B.cached_size = 0
+ B.prev_size = 0
+ else if (B.cached_size == "huge")
+ B.prev_size = "huge"
+ else
+ B.cached_size = B.breast_values[B.size]
+ B.prev_size = B.size
+ else
+ B.cached_size = B.size
+ B.prev_size = B.size
B.shape = dna.features["breasts_shape"]
B.fluid_id = dna.features["breasts_fluid"]
+ B.producing = dna.features["breasts_producing"]
B.update()
@@ -256,8 +271,8 @@
switch(layer)
if(GENITALS_BEHIND_LAYER)
return "BEHIND"
- if(GENITALS_ADJ_LAYER)
- return "ADJ"
+ /*if(GENITALS_ADJ_LAYER)
+ return "ADJ"*/
if(GENITALS_FRONT_LAYER)
return "FRONT"
@@ -279,27 +294,65 @@
if(src && !QDELETED(src))
dna.species.handle_genitals(src)
-/datum/species/proc/handle_genitals(mob/living/carbon/human/H)
+//fermichem procs
+/mob/living/carbon/human/proc/Force_update_genitals(mob/living/carbon/human/H) //called in fermiChem
+ dna.species.handle_genitals(src)//should work.
+ //dna.species.handle_breasts(src)
+
+//Checks to see if organs are new on the mob, and changes their colours so that they don't get crazy colours.
+/mob/living/carbon/human/proc/emergent_genital_call()
+ var/organCheck = FALSE
+ var/breastCheck = FALSE
+ var/willyCheck = FALSE
+ if(!canbearoused)
+ ADD_TRAIT(src, TRAIT_PHARMA, "pharma")//Prefs prevent unwanted organs.
+ return
+ for(var/obj/item/organ/O in internal_organs)
+ if(istype(O, /obj/item/organ/genital))
+ organCheck = TRUE
+ if(/obj/item/organ/genital/penis)
+ //dna.features["has_cock"] = TRUE
+ willyCheck = TRUE
+ if(/obj/item/organ/genital/breasts)
+ //dna.features["has_breasts"] = TRUE//Goddamnit get in there.
+ breastCheck = TRUE
+ if(organCheck == FALSE)
+ if(ishuman(src) && dna.species.id == "human")
+ dna.features["genitals_use_skintone"] = TRUE
+ dna.species.use_skintones = TRUE
+ if(MUTCOLORS)
+ if(src.dna.species.fixed_mut_color)
+ dna.features["cock_color"] = "[src.dna.species.fixed_mut_color]"
+ dna.features["breasts_color"] = "[src.dna.species.fixed_mut_color]"
+ return
+ //So people who haven't set stuff up don't get rainbow surprises.
+ dna.features["cock_color"] = "[dna.features["mcolor"]]"
+ dna.features["breasts_color"] = "[dna.features["mcolor"]]"
+ else //If there's a new organ, make it the same colour.
+ if(breastCheck == FALSE)
+ dna.features["breasts_color"] = dna.features["cock_color"]
+ else if (willyCheck == FALSE)
+ dna.features["cock_color"] = dna.features["breasts_color"]
+ return
+
+/datum/species/proc/handle_genitals(mob/living/carbon/human/H)//more like handle sadness
if(!H)//no args
CRASH("H = null")
if(!LAZYLEN(H.internal_organs))//if they have no organs, we're done
return
- if(NOGENITALS in species_traits)//golems and such
+ if((NOGENITALS in species_traits) && (H.genital_override = FALSE))//golems and such - things that shouldn't
return
if(HAS_TRAIT(H, TRAIT_HUSK))
return
-
var/list/genitals_to_add = list()
- var/list/relevant_layers = list(GENITALS_BEHIND_LAYER, GENITALS_ADJ_LAYER, GENITALS_FRONT_LAYER)
+ var/list/relevant_layers = list(GENITALS_BEHIND_LAYER, GENITALS_FRONT_LAYER) //GENITALS_ADJ_LAYER removed
var/list/standing = list()
var/size
var/aroused_state
for(var/L in relevant_layers) //Less hardcode
H.remove_overlay(L)
-
//start scanning for genitals
- //var/list/worn_stuff = H.get_equipped_items()//cache this list so it's not built again
for(var/obj/item/organ/O in H.internal_organs)
if(isgenital(O))
var/obj/item/organ/genital/G = O
@@ -308,7 +361,6 @@
if(G.is_exposed()) //Checks appropriate clothing slot and if it's through_clothes
genitals_to_add += H.getorganslot(G.slot)
//Now we added all genitals that aren't internal and should be rendered
-
//start applying overlays
for(var/layer in relevant_layers)
var/layertext = genitals_layertext(layer)
@@ -326,6 +378,9 @@
if(/obj/item/organ/genital/breasts)
S = GLOB.breasts_shapes_list[G.shape]
+
+
+
if(!S || S.icon_state == "none")
continue
diff --git a/modular_citadel/code/modules/arousal/organs/genitals_sprite_accessories.dm b/modular_citadel/code/modules/arousal/organs/genitals_sprite_accessories.dm
index b913a90fb6..f4af8a40ba 100644
--- a/modular_citadel/code/modules/arousal/organs/genitals_sprite_accessories.dm
+++ b/modular_citadel/code/modules/arousal/organs/genitals_sprite_accessories.dm
@@ -31,6 +31,19 @@
icon_state = "tapered"
name = "Tapered"
+/datum/sprite_accessory/penis/tentacle
+ icon_state = "tentacle"
+ name = "Tentacled"
+
+/datum/sprite_accessory/penis/hemi
+ icon_state = "hemi"
+ name = "Hemi"
+
+/datum/sprite_accessory/penis/hemiknot
+ icon_state = "hemiknot"
+ name = "Knotted Hemi"
+
+
////////////////////////
// Taur cocks go here //
////////////////////////
@@ -111,6 +124,10 @@
icon_state = "furred"
name = "Furred"
+/datum/sprite_accessory/vagina/gaping
+ icon_state = "gaping"
+ name = "Gaping"
+
//BREASTS BE HERE
/datum/sprite_accessory/breasts
icon = 'modular_citadel/icons/obj/genitals/breasts_onmob.dmi'
diff --git a/modular_citadel/code/modules/arousal/organs/penis.dm b/modular_citadel/code/modules/arousal/organs/penis.dm
index b6cb8fa4b2..43a512acf6 100644
--- a/modular_citadel/code/modules/arousal/organs/penis.dm
+++ b/modular_citadel/code/modules/arousal/organs/penis.dm
@@ -12,28 +12,61 @@
size = 2 //arbitrary value derived from length and girth for sprites.
var/length = 6 //inches
var/cached_length //used to detect a change in length
- var/girth = 0
+ var/girth = 4.38
var/girth_ratio = COCK_GIRTH_RATIO_DEF //0.73; check citadel_defines.dm
var/knot_girth_ratio = KNOT_GIRTH_RATIO_DEF
var/list/dickflags = list()
var/list/knotted_types = list("knotted", "barbed, knotted")
+ var/prev_length = 6 //really should be renamed to prev_length
+
+/obj/item/organ/genital/penis/Initialize()
+ . = ..()
+ /* I hate genitals.*/
/obj/item/organ/genital/penis/update_size()
- if(length == cached_length)
+ var/mob/living/carbon/human/o = owner
+ if(!ishuman(o) || !o)
return
- switch(length)
- if(-INFINITY to 5)
+ if(cached_length < 0)//I don't actually know what round() does to negative numbers, so to be safe!!
+ var/obj/item/organ/genital/penis/P = o.getorganslot("penis")
+ to_chat(o, "You feel your tallywacker shrinking away from your body as your groin flattens out!")
+ P.Remove(o)
+ switch(round(cached_length))
+ if(0 to 4) //If modest size
+ length = cached_length
size = 1
- if(5 to 9)
+ if(owner.has_status_effect(/datum/status_effect/chem/penis_enlarger))
+ o.remove_status_effect(/datum/status_effect/chem/penis_enlarger)
+ if(5 to 10) //If modest size
+ length = cached_length
size = 2
- if(15 to INFINITY)
- size = 3//no new sprites for anything larger yet
-/* if(9 to 15)
+ if(owner.has_status_effect(/datum/status_effect/chem/penis_enlarger))
+ o.remove_status_effect(/datum/status_effect/chem/penis_enlarger)
+ if(11 to 20) //If massive
+ length = cached_length
size = 3
- if(15 to INFINITY)
- size = 3*/
- girth = (length * girth_ratio)
- cached_length = length
+ if(owner.has_status_effect(/datum/status_effect/chem/penis_enlarger))
+ o.remove_status_effect(/datum/status_effect/chem/penis_enlarger)
+ if(21 to 35) //If massive and due for large effects
+ length = cached_length
+ size = 3
+ if(!owner.has_status_effect(/datum/status_effect/chem/penis_enlarger))
+ o.apply_status_effect(/datum/status_effect/chem/penis_enlarger)
+ if(36 to INFINITY) //If comical
+ length = cached_length
+ size = 4 //no new sprites for anything larger yet
+ if(!owner.has_status_effect(/datum/status_effect/chem/penis_enlarger))
+ o.apply_status_effect(/datum/status_effect/chem/penis_enlarger)
+
+ if (round(length) > round(prev_length))
+ to_chat(o, "Your [pick(GLOB.gentlemans_organ_names)] [pick("swells up to", "flourishes into", "expands into", "bursts forth into", "grows eagerly into", "amplifys into")] a [uppertext(round(length))] inch penis.")
+ else if ((round(length) < round(prev_length)) && (length > 0.5))
+ to_chat(o, "Your [pick(GLOB.gentlemans_organ_names)] [pick("shrinks down to", "decreases into", "diminishes into", "deflates into", "shrivels regretfully into", "contracts into")] a [uppertext(round(length))] inch penis.")
+ prev_length = length
+ icon_state = sanitize_text("penis_[shape]_[size]")
+ girth = (length * girth_ratio)//Is it just me or is this ludicous, why not make it exponentially decay?
+
+ //I have no idea on how to update sprites and I hate it
/obj/item/organ/genital/penis/update_appearance()
var/string
diff --git a/modular_citadel/code/modules/arousal/organs/testicles.dm b/modular_citadel/code/modules/arousal/organs/testicles.dm
index 1e6b4d62d4..f4ef4b5064 100644
--- a/modular_citadel/code/modules/arousal/organs/testicles.dm
+++ b/modular_citadel/code/modules/arousal/organs/testicles.dm
@@ -16,14 +16,18 @@
can_climax = TRUE
var/sent_full_message = TRUE //defaults to 1 since they're full to start
-/obj/item/organ/genital/testicles/Initialize()
- . = ..()
- reagents.add_reagent(fluid_id, fluid_max_volume)
-
/obj/item/organ/genital/testicles/on_life()
if(QDELETED(src))
return
if(reagents && producing)
+ if(reagents.total_volume == 0) // Apparently, 0.015 gets rounded down to zero and no reagents are created if we don't start it with 0.1 in the tank.
+ fluid_rate = 0.1
+ else
+ fluid_rate = CUM_RATE
+ if(reagents.total_volume >= 5)
+ fluid_mult = 0.5
+ else
+ fluid_mult = 1
generate_cum()
/obj/item/organ/genital/testicles/proc/generate_cum()
diff --git a/modular_citadel/code/modules/arousal/organs/womb.dm b/modular_citadel/code/modules/arousal/organs/womb.dm
index 686d9059a0..3f190b72ac 100644
--- a/modular_citadel/code/modules/arousal/organs/womb.dm
+++ b/modular_citadel/code/modules/arousal/organs/womb.dm
@@ -9,14 +9,18 @@
fluid_id = "femcum"
producing = TRUE
-/obj/item/organ/genital/womb/Initialize()
- . = ..()
- reagents.add_reagent(fluid_id, fluid_max_volume)
-
/obj/item/organ/genital/womb/on_life()
if(QDELETED(src))
return
if(reagents && producing)
+ if(reagents.total_volume == 0) // Apparently, 0.015 gets rounded down to zero and no reagents are created if we don't start it with 0.1 in the tank.
+ fluid_rate = 0.1
+ else
+ fluid_rate = CUM_RATE
+ if(reagents.total_volume >= 5)
+ fluid_mult = 0.5
+ else
+ fluid_mult = 1
generate_femcum()
/obj/item/organ/genital/womb/proc/generate_femcum()
diff --git a/modular_citadel/code/modules/awaymissions/citadel_ghostrole_spawners.dm b/modular_citadel/code/modules/awaymissions/citadel_ghostrole_spawners.dm
index f6991f1d9f..ccbf9a42fe 100644
--- a/modular_citadel/code/modules/awaymissions/citadel_ghostrole_spawners.dm
+++ b/modular_citadel/code/modules/awaymissions/citadel_ghostrole_spawners.dm
@@ -49,7 +49,7 @@
/datum/outfit/lavaknight/captain
name ="Cydonian Knight Captain"
- l_pocket = /obj/item/twohanded/hypereutactic
+ l_pocket = /obj/item/twohanded/dualsaber/hypereutactic
/datum/outfit/lavaknight/captain/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
if(visualsOnly)
diff --git a/modular_citadel/code/modules/client/loadout/__donator.dm b/modular_citadel/code/modules/client/loadout/__donator.dm
index 90172bbf43..cc75e1bff9 100644
--- a/modular_citadel/code/modules/client/loadout/__donator.dm
+++ b/modular_citadel/code/modules/client/loadout/__donator.dm
@@ -220,13 +220,13 @@
/datum/gear/torisword
name = "Rainbow Zweihander"
category = SLOT_IN_BACKPACK
- path = /obj/item/twohanded/hypereutactic/toy/rainbow
+ path = /obj/item/twohanded/dualsaber/hypereutactic/toy/rainbow
ckeywhitelist = list("annoymous35")
/datum/gear/darksabre
name = "Dark Sabre"
category = SLOT_IN_BACKPACK
- path = /obj/item/toy/sword/darksabre
+ path = /obj/item/toy/darksabre
ckeywhitelist = list("inferno707")
datum/gear/darksabresheath
@@ -434,3 +434,17 @@ datum/gear/darksabresheath
category = SLOT_NECK
path = /obj/item/bedsheet/captain
ckeywhitelist = list("tikibomb")
+
+/datum/gear/borgplush
+ name = "Robot Plush"
+ category = SLOT_IN_BACKPACK
+ path = /obj/item/toy/plush/borgplushie
+ ckeywhitelist = list("nicholaiavenicci")
+
+/datum/gear/donorberet
+ name = "Atmos Beret"
+ category = SLOT_HEAD
+ path = /obj/item/clothing/head/blueberet
+ ckeywhitelist = list("foxystalin")
+
+
diff --git a/modular_citadel/code/modules/client/loadout/backpack.dm b/modular_citadel/code/modules/client/loadout/backpack.dm
index bb12fc8ac9..c2713b49be 100644
--- a/modular_citadel/code/modules/client/loadout/backpack.dm
+++ b/modular_citadel/code/modules/client/loadout/backpack.dm
@@ -79,8 +79,24 @@
path = /obj/item/toy/katana
cost = 3
-//datum/gear/lumeyes
-// name = "Luminescent eye auto surgeon"
-// category = SLOT_IN_BACKPACK
-// path = /obj/item/autosurgeon/gloweyes
-// cost = 4
+/datum/gear/box
+ name = "Spare box"
+ category = SLOT_IN_BACKPACK
+ path = /obj/item/storage/box
+ cost = 2
+
+/datum/gear/crowbar
+ name = "Pocket Crowbar"
+ category = SLOT_IN_BACKPACK
+ path = /obj/item/crowbar
+ cost = 2
+
+/datum/gear/tapeplayer
+ name = "Taperecorder"
+ category = SLOT_IN_BACKPACK
+ path = /obj/item/taperecorder
+
+/datum/gear/tape
+ name = "Spare cassette tape"
+ category = SLOT_IN_BACKPACK
+ path = /obj/item/tape/random
\ No newline at end of file
diff --git a/modular_citadel/code/modules/client/preferences.dm b/modular_citadel/code/modules/client/preferences.dm
index dfe419964e..1caa4cfed7 100644
--- a/modular_citadel/code/modules/client/preferences.dm
+++ b/modular_citadel/code/modules/client/preferences.dm
@@ -15,6 +15,7 @@
var/arousable = TRUE
var/widescreenpref = TRUE
var/autostand = TRUE
+ var/lewdchem = TRUE
//vore prefs
var/toggleeatingnoise = TRUE
@@ -53,5 +54,6 @@ datum/preferences/copy_to(mob/living/carbon/human/character, icon_updates = 1)
character.give_genitals(TRUE)
character.flavor_text = features["flavor_text"] //Let's update their flavor_text at least initially
character.canbearoused = arousable
+ character.client?.prefs.lewdchem = lewdchem
if(icon_updates)
character.update_genitals()
diff --git a/modular_citadel/code/modules/client/preferences_savefile.dm b/modular_citadel/code/modules/client/preferences_savefile.dm
index 2921f70684..0a353e3f5d 100644
--- a/modular_citadel/code/modules/client/preferences_savefile.dm
+++ b/modular_citadel/code/modules/client/preferences_savefile.dm
@@ -65,6 +65,7 @@
WRITE_FILE(S["feature_breasts_shape"], features["breasts_shape"])
WRITE_FILE(S["feature_breasts_color"], features["breasts_color"])
WRITE_FILE(S["feature_breasts_fluid"], features["breasts_fluid"])
+ WRITE_FILE(S["feature_breasts_producing"], features["breasts_producing"])
//vagina features
WRITE_FILE(S["feature_has_vag"], features["has_vag"])
WRITE_FILE(S["feature_vag_shape"], features["vag_shape"])
diff --git a/modular_citadel/code/modules/clothing/under/trek_under.dm b/modular_citadel/code/modules/clothing/under/trek_under.dm
index 8e2b94372d..a60f7653c5 100644
--- a/modular_citadel/code/modules/clothing/under/trek_under.dm
+++ b/modular_citadel/code/modules/clothing/under/trek_under.dm
@@ -5,7 +5,8 @@
*//////////////////////////////////////////////////////////////////////////////////
// <3 Nienhaus && Joan.
// I made the Voy and DS9 stuff tho. - Poojy
-
+// Armor lists for even Heads of Staff is Nulled out do round start armor as well most armor going onto the suit itself rather then a armor slot - Trilby
+///////////////////////////////////////////////////////////////////////////////////
/obj/item/clothing/under/rank/trek
@@ -22,7 +23,7 @@
desc = "The uniform worn by command officers in the mid 2260s."
icon_state = "trek_command"
item_state = "trek_command"
- armor = list("melee" = 10, "bullet" = 10, "laser" = 10,"energy" = 10, "bomb" = 0, "bio" = 10, "rad" = 10, "fire" = 0, "acid" = 0) // Considering only staff heads get to pick it
+ armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 0)
/obj/item/clothing/under/rank/trek/engsec
name = "Operations Uniform"
@@ -104,7 +105,7 @@
/obj/item/reagent_containers/glass/bottle/vial,/obj/item/reagent_containers/glass/beaker,
/obj/item/reagent_containers/pill,/obj/item/storage/pill_bottle, /obj/item/restraints/handcuffs,/obj/item/hypospray
)
- armor = list("melee" = 10, "bullet" = 5, "laser" = 5,"energy" = 5, "bomb" = 5, "bio" = 5, "rad" = 10, "fire" = 10, "acid" = 0)
+ armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 0)
/obj/item/clothing/suit/storage/trek/ds9/admiral // Only for adminuz
name = "Admiral Overcoat"
@@ -135,7 +136,6 @@
/obj/item/clothing/suit/storage/fluff/fedcoat
name = "Federation Uniform Jacket"
desc = "A uniform jacket from the United Federation. Set phasers to awesome."
-
icon = 'modular_citadel/icons/obj/clothing/trek_item_icon.dmi'
alternate_worn_icon = 'modular_citadel/icons/mob/clothing/trek_mob_icon.dmi'
icon_state = "fedcoat"
@@ -160,7 +160,7 @@
/obj/item/reagent_containers/glass/beaker,
/obj/item/storage/pill_bottle,
/obj/item/taperecorder)
- armor = list("melee" = 10, "bullet" = 5, "laser" = 5,"energy" = 5, "bomb" = 5, "bio" = 5, "rad" = 10, "fire" = 10, "acid" = 0)
+ armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 0)
var/unbuttoned = 0
verb/toggle()
@@ -214,7 +214,7 @@
/obj/item/reagent_containers/glass/bottle/vial,/obj/item/reagent_containers/glass/beaker,
/obj/item/reagent_containers/pill,/obj/item/storage/pill_bottle, /obj/item/restraints/handcuffs,/obj/item/hypospray
)
- armor = list("melee" = 10, "bullet" = 5, "laser" = 5,"energy" = 5, "bomb" = 5, "bio" = 5, "rad" = 10, "fire" = 10, "acid" = 0)
+ armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 0)
//Variants
/obj/item/clothing/suit/storage/fluff/modernfedcoat/medsci
@@ -231,6 +231,7 @@
/obj/item/clothing/head/caphat/formal/fedcover
name = "Federation Officer's Cap"
+ armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 0)
desc = "An officer's cap that demands discipline from the one who wears it."
icon = 'modular_citadel/icons/obj/clothing/trek_item_icon.dmi'
icon_state = "fedcapofficer"
diff --git a/modular_citadel/code/modules/clothing/under/turtlenecks.dm b/modular_citadel/code/modules/clothing/under/turtlenecks.dm
index f4e1ba8bd9..fd13da11e9 100644
--- a/modular_citadel/code/modules/clothing/under/turtlenecks.dm
+++ b/modular_citadel/code/modules/clothing/under/turtlenecks.dm
@@ -43,8 +43,8 @@
icon_state = "bb_turtle"
item_state = "w_suit"
item_color = "bb_turtle"
- body_parts_covered = CHEST|ARMS
- can_adjust = 1
+ body_parts_covered = CHEST|GROIN|ARMS
+ can_adjust = TRUE
icon = 'modular_citadel/icons/obj/clothing/turtlenecks.dmi'
alternate_worn_icon = 'modular_citadel/icons/mob/citadel/uniforms.dmi'
mutantrace_variation = NO_MUTANTRACE_VARIATION
diff --git a/modular_citadel/code/modules/clothing/under/under.dm b/modular_citadel/code/modules/clothing/under/under.dm
index 1796df01be..dcc6323f62 100644
--- a/modular_citadel/code/modules/clothing/under/under.dm
+++ b/modular_citadel/code/modules/clothing/under/under.dm
@@ -5,26 +5,6 @@
*//////////////////////////////////////////////////////////////////////////////////
-/obj/item/clothing/under/rank/security/skirt
- name = "security skirt"
- desc = "A tactical security skirt for officers complete with Nanotrasen belt buckle."
- icon = 'modular_citadel/icons/obj/clothing/cit_clothes.dmi'
- icon_state = "secskirt"
- alternate_worn_icon = 'modular_citadel/icons/mob/citadel/uniforms.dmi'
- item_state = "r_suit"
- item_color = "secskirt"
- body_parts_covered = CHEST|GROIN|ARMS
-
-/obj/item/clothing/under/rank/head_of_security/skirt
- name = "head of security's skirt"
- desc = "A security skirt decorated for those few with the dedication to achieve the position of Head of Security."
- icon = 'modular_citadel/icons/obj/clothing/cit_clothes.dmi'
- icon_state = "hosskirt"
- alternate_worn_icon = 'modular_citadel/icons/mob/citadel/uniforms.dmi'
- item_state = "gy_suit"
- item_color = "hosskirt"
- body_parts_covered = CHEST|GROIN|ARMS
-
/obj/item/clothing/under/corporateuniform
name = "corporate uniform"
desc = "A comfortable, tight fitting jumpsuit made of premium materials. Not space-proof."
diff --git a/modular_citadel/code/modules/custom_loadout/custom_items.dm b/modular_citadel/code/modules/custom_loadout/custom_items.dm
index 0ce4fbdd78..42363e9e07 100644
--- a/modular_citadel/code/modules/custom_loadout/custom_items.dm
+++ b/modular_citadel/code/modules/custom_loadout/custom_items.dm
@@ -49,7 +49,7 @@
item_color = "steele"
medaltype = "medal-silver"
-/obj/item/toy/sword/darksabre
+/obj/item/toy/darksabre
name = "Kiara's Sabre"
desc = "This blade looks as dangerous as its owner."
icon = 'icons/obj/custom.dmi'
@@ -58,9 +58,13 @@
item_state = "darksabre"
lefthand_file = 'modular_citadel/icons/mob/inhands/stunsword_left.dmi'
righthand_file = 'modular_citadel/icons/mob/inhands/stunsword_right.dmi'
- w_class = WEIGHT_CLASS_SMALL
attack_verb = list("attacked", "struck", "hit")
+/obj/item/toy/darksabre/get_belt_overlay()
+ return mutable_appearance('icons/obj/custom.dmi', "darksheath-darksabre")
+
+/obj/item/toy/darksabre/get_worn_belt_overlay(icon_file)
+ return mutable_appearance(icon_file, "darksheath-darksabre")
/obj/item/storage/belt/sabre/darksabre
name = "Ornate Sheathe"
@@ -69,32 +73,8 @@
alternate_worn_icon = 'icons/mob/custom_w.dmi'
icon_state = "darksheath"
item_state = "darksheath"
- w_class = WEIGHT_CLASS_BULKY
-
-/obj/item/storage/belt/sabre/darksabre/ComponentInitialize()
- . = ..()
- GET_COMPONENT(STR, /datum/component/storage)
- STR.max_items = 1
- STR.rustle_sound = FALSE
- STR.max_w_class = WEIGHT_CLASS_BULKY
- STR.can_hold = typecacheof(list(
- /obj/item/toy/sword/darksabre
- ))
-
-/obj/item/storage/belt/sabre/darksabre/update_icon()
- icon_state = "darksheath"
- item_state = "darksheath"
- if(contents.len)
- icon_state += "-darksabre"
- item_state += "-darksabre"
- if(loc && isliving(loc))
- var/mob/living/L = loc
- L.regenerate_icons()
- ..()
-
-/obj/item/storage/belt/sabre/darksabre/PopulateContents()
- new /obj/item/toy/sword/darksabre(src)
- update_icon()
+ fitting_swords = list(/obj/item/toy/darksabre)
+ starting_sword = /obj/item/toy/darksabre
/obj/item/clothing/suit/armor/vest/darkcarapace
name = "Dark Armor"
@@ -342,31 +322,6 @@
name = "worn pet collar"
desc = "a pet collar that looks well used."
-/obj/item/clothing/neck/petcollar/naomi/examine(mob/user)
- . = ..()
- if(usr.ckey != "technicalmagi")
- to_chat(user, "There's something odd about the it. You probably shouldn't wear it...")//warn people not to wear it if they're not Naomi, lest they become as crazy as she is
-
-/obj/item/clothing/neck/petcollar/naomi/equipped()
- . = ..()
- START_PROCESSING(SSobj, src)
-
-/obj/item/clothing/neck/petcollar/naomi/dropped()
- . = ..()
- STOP_PROCESSING(SSobj, src)
-
-/obj/item/clothing/neck/petcollar/naomi/process()
- var/mob/living/carbon/human/H
- if(ishuman(loc))
- H = loc
- if(!H)
- return
- else if(H.get_item_by_slot(SLOT_NECK) == src)
- if(H.arousalloss < H.max_arousal / 3)
- H.arousalloss = H.max_arousal / 3
- if(prob(5) && H.hallucination < 15)
- H.hallucination += 10
-
/obj/item/clothing/neck/cloak/green
name = "Generic Green Cloak"
desc = "This cloak doesn't seem too special."
@@ -528,3 +483,11 @@
icon = 'icons/obj/custom.dmi'
alternate_worn_icon = 'icons/mob/custom_w.dmi'
mutantrace_variation = NO_MUTANTRACE_VARIATION
+
+/obj/item/clothing/head/blueberet
+ name = "Atmos Beret"
+ desc = "A fitted beret designed to be worn by Atmos Techs."
+ icon_state = "blueberet"
+ item_state = "blueberet"
+ icon = 'icons/obj/custom.dmi'
+ alternate_worn_icon = 'icons/mob/custom_w.dmi'
diff --git a/modular_citadel/code/modules/jobs/job_types/captain.dm b/modular_citadel/code/modules/jobs/job_types/captain.dm
index 674cd9d09e..7135e86507 100644
--- a/modular_citadel/code/modules/jobs/job_types/captain.dm
+++ b/modular_citadel/code/modules/jobs/job_types/captain.dm
@@ -4,7 +4,6 @@
/datum/job/hop
minimal_player_age = 20
- head_announce = list("Service")
exp_type_department = EXP_TYPE_SERVICE
access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_COURT, ACCESS_WEAPONS,
diff --git a/modular_citadel/code/modules/mentor/mentorpm.dm b/modular_citadel/code/modules/mentor/mentorpm.dm
index 34ace6f002..4c9a4766ec 100644
--- a/modular_citadel/code/modules/mentor/mentorpm.dm
+++ b/modular_citadel/code/modules/mentor/mentorpm.dm
@@ -3,7 +3,7 @@
set category = "Mentor"
set name = "Mentor PM"
if(!is_mentor())
- to_chat(src, "Error: Mentor-PM-Panel: Only Mentors and Admins may use this command.")
+ to_chat(src, "Error: Mentor-PM-Panel: Only Mentors and Admins may use this command.")
return
var/list/client/targets[0]
for(var/client/T)
@@ -27,24 +27,24 @@
else if(istype(whom,/client))
C = whom
if(!C)
- if(is_mentor()) to_chat(src, "Error: Mentor-PM: Client not found.")
+ if(is_mentor()) to_chat(src, "Error: Mentor-PM: Client not found.")
else mentorhelp(msg) //Mentor we are replying to left. Mentorhelp instead(check below)
return
if(is_mentor(whom))
- to_chat(GLOB.admins | GLOB.mentors, "[src] has started replying to [whom]'s mhelp.")
+ to_chat(GLOB.admins | GLOB.mentors, "[src] has started replying to [whom]'s mhelp.")
//get message text, limit it's length.and clean/escape html
if(!msg)
msg = input(src,"Message:", "Private message") as text|null
-
+
if(!msg && is_mentor(whom))
- to_chat(GLOB.admins | GLOB.mentors, "[src] has stopped their reply to [whom]'s mhelp.")
+ to_chat(GLOB.admins | GLOB.mentors, "[src] has stopped their reply to [whom]'s mhelp.")
return
if(!C)
if(is_mentor())
- to_chat(src, "Error: Mentor-PM: Client not found.")
+ to_chat(src, "Error: Mentor-PM: Client not found.")
else
mentorhelp(msg) //Mentor we are replying to has vanished, Mentorhelp instead (how the fuck does this work?let's hope it works,shrug)
return
@@ -54,8 +54,8 @@
return
msg = sanitize(copytext(msg,1,MAX_MESSAGE_LEN))
- if(!msg && is_mentor(whom))
- to_chat(GLOB.admins | GLOB.mentors, "[src] has stopped their reply to [whom]'s mhelp.")
+ if(!msg && is_mentor(whom))
+ to_chat(GLOB.admins | GLOB.mentors, "[src] has stopped their reply to [whom]'s mhelp.")
return
log_mentor("Mentor PM: [key_name(src)]->[key_name(C)]: [msg]")
@@ -65,21 +65,21 @@
var/show_char = CONFIG_GET(flag/mentors_mobname_only)
if(C.is_mentor())
if(is_mentor())//both are mentors
- to_chat(C, "Mentor PM from-[key_name_mentor(src, C, 1, 0, 0)]: [msg]")
- to_chat(src, "Mentor PM to-[key_name_mentor(C, C, 1, 0, 0)]: [msg]")
+ to_chat(C, "Mentor PM from-[key_name_mentor(src, C, 1, 0, 0)]: [msg]")
+ to_chat(src, "Mentor PM to-[key_name_mentor(C, C, 1, 0, 0)]: [msg]")
- else //recipient is an mentor but sender is not
- to_chat(C, "Reply PM from-[key_name_mentor(src, C, 1, 0, show_char)]: [msg]")
- to_chat(src, "Mentor PM to-[key_name_mentor(C, C, 1, 0, 0)]: [msg]")
+ else //recipient is a mentor but sender is not
+ to_chat(C, "Reply PM from-[key_name_mentor(src, C, 1, 0, show_char)]: [msg]")
+ to_chat(src, "Mentor PM to-[key_name_mentor(C, C, 1, 0, 0)]: [msg]")
else
- if(is_mentor()) //sender is an mentor but recipient is not.
- to_chat(C, "Mentor PM from-[key_name_mentor(src, C, 1, 0, 0)]: [msg]")
- to_chat(src, "Mentor PM to-[key_name_mentor(C, C, 1, 0, show_char)]: [msg]")
+ if(is_mentor()) //sender is a mentor but recipient is not.
+ to_chat(C, "Mentor PM from-[key_name_mentor(src, C, 1, 0, 0)]: [msg]")
+ to_chat(src, "Mentor PM to-[key_name_mentor(C, C, 1, 0, show_char)]: [msg]")
//we don't use message_Mentors here because the sender/receiver might get it too
var/show_char_sender = !is_mentor() && CONFIG_GET(flag/mentors_mobname_only)
var/show_char_recip = !C.is_mentor() && CONFIG_GET(flag/mentors_mobname_only)
for(var/client/X in GLOB.mentors | GLOB.admins)
if(X.key!=key && X.key!=C.key) //check client/X is an Mentor and isn't the sender or recipient
- to_chat(X, "Mentor PM: [key_name_mentor(src, X, 0, 0, show_char_sender)]->[key_name_mentor(C, X, 0, 0, show_char_recip)]: [msg]") //inform X
+ to_chat(X, "Mentor PM: [key_name_mentor(src, X, 0, 0, show_char_sender)]->[key_name_mentor(C, X, 0, 0, show_char_recip)]: [msg]") //inform X
diff --git a/modular_citadel/code/modules/mob/cit_emotes.dm b/modular_citadel/code/modules/mob/cit_emotes.dm
index aff1739ae4..a34b7b0526 100644
--- a/modular_citadel/code/modules/mob/cit_emotes.dm
+++ b/modular_citadel/code/modules/mob/cit_emotes.dm
@@ -185,22 +185,6 @@
emote_type = EMOTE_AUDIBLE
restraint_check = TRUE
-
-
-/datum/emote/living/dab/run_emote(mob/living/user, params)
- if (ishuman(user))
- var/def_zone = BODY_ZONE_CHEST
- var/luck = (rand(1,100))
- if(luck >= 65)
- user.adjustStaminaLoss(70)
- if(luck >= 80)
- def_zone = pick(BODY_ZONE_L_ARM, BODY_ZONE_R_ARM)
- user.apply_damage(20, BRUTE, def_zone)
- if(luck >= 95)
- user.adjustBrainLoss(100)
- . = ..()
-
-
/datum/emote/living/mothsqueak
key = "msqueak"
key_third_person = "lets out a tiny squeak"
diff --git a/modular_citadel/code/modules/mob/living/carbon/damage_procs.dm b/modular_citadel/code/modules/mob/living/carbon/damage_procs.dm
index c2c581d282..7264d95bae 100644
--- a/modular_citadel/code/modules/mob/living/carbon/damage_procs.dm
+++ b/modular_citadel/code/modules/mob/living/carbon/damage_procs.dm
@@ -18,3 +18,21 @@
if(recoveringstam && amount > 20)
incomingstammult = max(0.01, incomingstammult/(amount*0.05))
return amount
+
+/mob/living/carbon/doSprintLossTiles(tiles)
+ doSprintBufferRegen(FALSE) //first regen.
+ if(sprint_buffer)
+ var/use = min(tiles, sprint_buffer)
+ sprint_buffer -= use
+ tiles -= use
+ update_hud_sprint_bar()
+ if(!tiles) //we had enough, we're done!
+ return
+ adjustStaminaLoss(tiles * sprint_stamina_cost) //use stamina to cover deficit.
+
+/mob/living/carbon/proc/doSprintBufferRegen(updating = TRUE)
+ var/diff = world.time - sprint_buffer_regen_last
+ sprint_buffer_regen_last = world.time
+ sprint_buffer = min(sprint_buffer_max, sprint_buffer + sprint_buffer_regen_ds * diff)
+ if(updating)
+ update_hud_sprint_bar()
diff --git a/modular_citadel/code/modules/mob/living/carbon/human/human.dm b/modular_citadel/code/modules/mob/living/carbon/human/human.dm
index 70bac64825..bb8d4a5f4a 100644
--- a/modular_citadel/code/modules/mob/living/carbon/human/human.dm
+++ b/modular_citadel/code/modules/mob/living/carbon/human/human.dm
@@ -13,18 +13,19 @@
/mob/living/carbon/human/species/xeno
race = /datum/species/xeno
-/mob/living/carbon/human/resist()
- . = ..()
- if(wear_suit && wear_suit.breakouttime)//added in human cuff breakout proc
+/mob/living/proc/resist_embedded()
+ return
+
+/mob/living/carbon/human/resist_embedded()
+ if(handcuffed || legcuffed || (wear_suit && wear_suit.breakouttime))
return
- if(.)
- if(canmove && !on_fire)
- for(var/obj/item/bodypart/L in bodyparts)
- if(istype(L) && L.embedded_objects.len)
- for(var/obj/item/I in L.embedded_objects)
- if(istype(I) && I.w_class >= WEIGHT_CLASS_NORMAL) //minimum weight class to insta-ripout via resist
- remove_embedded_unsafe(L, I, src, 1.5) //forcefully call the remove embedded unsafe proc but with extra pain multiplier. if you want to remove it less painfully, examine and remove it carefully.
- return FALSE //Hands are occupied
+ if(canmove && !on_fire)
+ for(var/obj/item/bodypart/L in bodyparts)
+ if(istype(L) && L.embedded_objects.len)
+ for(var/obj/item/I in L.embedded_objects)
+ if(istype(I) && I.w_class >= WEIGHT_CLASS_NORMAL) //minimum weight class to insta-ripout via resist
+ remove_embedded_unsafe(L, I, src, 1.5) //forcefully call the remove embedded unsafe proc but with extra pain multiplier. if you want to remove it less painfully, examine and remove it carefully.
+ return TRUE //Hands are occupied
return
/mob/living/carbon/human/proc/remove_embedded_unsafe(obj/item/bodypart/L, obj/item/I, mob/user, painmul = 1)
diff --git a/modular_citadel/code/modules/mob/living/carbon/human/human_movement.dm b/modular_citadel/code/modules/mob/living/carbon/human/human_movement.dm
index 2a1c790b2a..409864c900 100644
--- a/modular_citadel/code/modules/mob/living/carbon/human/human_movement.dm
+++ b/modular_citadel/code/modules/mob/living/carbon/human/human_movement.dm
@@ -5,7 +5,7 @@
var/oldpseudoheight = pseudo_z_axis
. = ..()
if(. && sprinting && !(movement_type & FLYING) && canmove && !resting && m_intent == MOVE_INTENT_RUN && has_gravity(loc) && !pulledby)
- adjustStaminaLossBuffered(0.3)
+ doSprintLossTiles(1)
if((oldpseudoheight - pseudo_z_axis) >= 8)
to_chat(src, "You trip off of the elevated surface!")
for(var/obj/item/I in held_items)
diff --git a/modular_citadel/code/modules/mob/living/carbon/human/species.dm b/modular_citadel/code/modules/mob/living/carbon/human/species.dm
index fcc60fbe81..1c7456a8d8 100644
--- a/modular_citadel/code/modules/mob/living/carbon/human/species.dm
+++ b/modular_citadel/code/modules/mob/living/carbon/human/species.dm
@@ -80,10 +80,23 @@
else
target.Move(target_shove_turf, shove_dir)
if(get_turf(target) == target_oldturf)
- target_table = locate(/obj/structure/table) in target_shove_turf.contents
- shove_blocked = TRUE
+ if(target_shove_turf.density)
+ shove_blocked = TRUE
+ else
+ var/thoushallnotpass = FALSE
+ for(var/obj/O in target_shove_turf)
+ if(istype(O, /obj/structure/table))
+ target_table = O
+ else if(!O.CanPass(src, target_shove_turf))
+ shove_blocked = TRUE
+ thoushallnotpass = TRUE
+ if(thoushallnotpass)
+ target_table = null
- if(shove_blocked && !target.is_shove_knockdown_blocked())
+ if(target.is_shove_knockdown_blocked())
+ return
+
+ if(shove_blocked || target_table)
var/directional_blocked = FALSE
if(shove_dir in GLOB.cardinals) //Directional checks to make sure that we're not shoving through a windoor or something like that
var/target_turf = get_turf(target)
diff --git a/modular_citadel/code/modules/mob/living/carbon/human/species_types/jellypeople.dm b/modular_citadel/code/modules/mob/living/carbon/human/species_types/jellypeople.dm
index fa6ded8065..c18303ad84 100644
--- a/modular_citadel/code/modules/mob/living/carbon/human/species_types/jellypeople.dm
+++ b/modular_citadel/code/modules/mob/living/carbon/human/species_types/jellypeople.dm
@@ -15,7 +15,6 @@
say_mod = "says"
hair_color = "mutcolor"
hair_alpha = 160 //a notch brighter so it blends better.
- liked_food = MEAT
coldmod = 3
heatmod = 1
burnmod = 1
diff --git a/modular_citadel/code/modules/mob/living/carbon/life.dm b/modular_citadel/code/modules/mob/living/carbon/life.dm
new file mode 100644
index 0000000000..e94bd75985
--- /dev/null
+++ b/modular_citadel/code/modules/mob/living/carbon/life.dm
@@ -0,0 +1,3 @@
+/mob/living/carbon/Life()
+ . = ..()
+ doSprintBufferRegen()
diff --git a/modular_citadel/code/modules/mob/living/damage_procs.dm b/modular_citadel/code/modules/mob/living/damage_procs.dm
index 8323386eff..ce81c7aae7 100644
--- a/modular_citadel/code/modules/mob/living/damage_procs.dm
+++ b/modular_citadel/code/modules/mob/living/damage_procs.dm
@@ -1,2 +1,5 @@
/mob/living/proc/adjustStaminaLossBuffered(amount, updating_stamina = TRUE, forced = FALSE)
return
+
+/mob/living/proc/doSprintLossTiles(amount)
+ return
diff --git a/modular_citadel/code/modules/mob/living/living.dm b/modular_citadel/code/modules/mob/living/living.dm
index b07b8ed64b..ac79ea7f25 100644
--- a/modular_citadel/code/modules/mob/living/living.dm
+++ b/modular_citadel/code/modules/mob/living/living.dm
@@ -8,6 +8,14 @@
var/intentionalresting = FALSE
var/attemptingcrawl = FALSE
+ //Sprint buffer---
+ var/sprint_buffer = 42 //Tiles
+ var/sprint_buffer_max = 42
+ var/sprint_buffer_regen_ds = 0.3 //Tiles per world.time decisecond
+ var/sprint_buffer_regen_last = 0 //last world.time this was regen'd for math.
+ var/sprint_stamina_cost = 0.55 //stamina loss per tile while insufficient sprint buffer.
+ //---End
+
/mob/living/movement_delay(ignorewalk = 0)
. = ..()
if(resting)
@@ -118,3 +126,7 @@
filters -= CIT_FILTER_STAMINACRIT
update_canmove()
update_health_hud()
+
+/mob/living/proc/update_hud_sprint_bar()
+ if(hud_used && hud_used.sprint_buffer)
+ hud_used.sprint_buffer.update_to_mob(src)
diff --git a/modular_citadel/code/modules/mob/living/status_procs.dm b/modular_citadel/code/modules/mob/living/status_procs.dm
deleted file mode 100644
index 851c7438a7..0000000000
--- a/modular_citadel/code/modules/mob/living/status_procs.dm
+++ /dev/null
@@ -1,10 +0,0 @@
-/mob/living/Knockdown(amount, updating = TRUE, ignore_canknockdown = FALSE, override_hardstun, override_stamdmg) //Can't go below remaining duration
- if(((status_flags & CANKNOCKDOWN) && !HAS_TRAIT(src, TRAIT_STUNIMMUNE)) || ignore_canknockdown)
- if(absorb_stun(isnull(override_hardstun)? amount : override_hardstun, ignore_canknockdown))
- return
- var/datum/status_effect/incapacitating/knockdown/K = IsKnockdown()
- if(K)
- K.duration = max(world.time + (isnull(override_hardstun)? amount : override_hardstun), K.duration)
- else if((amount || override_hardstun) > 0)
- K = apply_status_effect(STATUS_EFFECT_KNOCKDOWN, amount, updating, override_hardstun, override_stamdmg)
- return K
diff --git a/modular_citadel/code/modules/projectiles/gun.dm b/modular_citadel/code/modules/projectiles/gun.dm
index ea8af7c74c..317f68b4c4 100644
--- a/modular_citadel/code/modules/projectiles/gun.dm
+++ b/modular_citadel/code/modules/projectiles/gun.dm
@@ -9,13 +9,3 @@
return 0
else
return ..()
-
-/obj/item/gun/proc/getinaccuracy(mob/living/user)
- if(!iscarbon(user))
- return 0
- else
- var/mob/living/carbon/holdingdude = user
- if(istype(holdingdude) && holdingdude.combatmode)
- return max((holdingdude.lastdirchange + weapon_weight * 25) - world.time,0)
- else
- return weapon_weight * 25
diff --git a/modular_citadel/code/modules/projectiles/guns/ballistic/flechette.dm b/modular_citadel/code/modules/projectiles/guns/ballistic/flechette.dm
deleted file mode 100644
index f70ec76f04..0000000000
--- a/modular_citadel/code/modules/projectiles/guns/ballistic/flechette.dm
+++ /dev/null
@@ -1,117 +0,0 @@
-//////Flechette Launcher//////
-
-///projectiles///
-
-/obj/item/projectile/bullet/cflechetteap //shreds armor
- name = "flechette (armor piercing)"
- damage = 8
- armour_penetration = 80
-
-/obj/item/projectile/bullet/cflechettes //shreds flesh and forces bleeding
- name = "flechette (serrated)"
- damage = 15
- dismemberment = 10
- armour_penetration = -80
-
-/obj/item/projectile/bullet/cflechettes/on_hit(atom/target, blocked = FALSE)
- if((blocked != 100) && iscarbon(target))
- var/mob/living/carbon/C = target
- C.bleed(10)
- return ..()
-
-///ammo casings (CASELESS AMMO CASINGS WOOOOOOOO)///
-
-/obj/item/ammo_casing/caseless/flechetteap
- name = "flechette (armor piercing)"
- desc = "A flechette made with a tungsten alloy."
- projectile_type = /obj/item/projectile/bullet/cflechetteap
- caliber = "flechette"
- throwforce = 1
- throw_speed = 3
-
-/obj/item/ammo_casing/caseless/flechettes
- name = "flechette (serrated)"
- desc = "A serrated flechette made of a special alloy intended to deform drastically upon penetration of human flesh."
- projectile_type = /obj/item/projectile/bullet/cflechettes
- caliber = "flechette"
- throwforce = 2
- throw_speed = 3
- embedding = list("embedded_pain_multiplier" = 0, "embed_chance" = 40, "embedded_fall_chance" = 10)
-
-///magazine///
-
-/obj/item/ammo_box/magazine/flechette
- name = "flechette magazine (armor piercing)"
- icon = 'modular_citadel/icons/obj/guns/cit_guns.dmi'
- icon_state = "flechettemag"
- ammo_type = /obj/item/ammo_casing/caseless/flechetteap
- caliber = "flechette"
- max_ammo = 40
- multiple_sprites = 2
-
-/obj/item/ammo_box/magazine/flechette/s
- name = "flechette magazine (serrated)"
- ammo_type = /obj/item/ammo_casing/caseless/flechettes
-
-///the gun itself///
-
-/obj/item/gun/ballistic/automatic/flechette
- name = "\improper CX Flechette Launcher"
- desc = "A flechette launching machine pistol with an unconventional bullpup frame."
- icon = 'modular_citadel/icons/obj/guns/cit_guns.dmi'
- icon_state = "flechettegun"
- item_state = "gun"
- w_class = WEIGHT_CLASS_NORMAL
- slot_flags = 0
- /obj/item/firing_pin/implant/pindicate
- mag_type = /obj/item/ammo_box/magazine/flechette/
- fire_sound = 'sound/weapons/gunshot_smg.ogg'
- can_suppress = 0
- burst_size = 5
- fire_delay = 1
- casing_ejector = 0
- spread = 10
- recoil = 0.05
-
-/obj/item/gun/ballistic/automatic/flechette/update_icon()
- ..()
- if(magazine)
- cut_overlays()
- add_overlay("flechettegun-magazine")
- else
- cut_overlays()
- icon_state = "[initial(icon_state)][chambered ? "" : "-e"]"
-
-///unique variant///
-
-/obj/item/projectile/bullet/cflechetteshredder
- name = "flechette (shredder)"
- damage = 5
- dismemberment = 40
-
-/obj/item/ammo_casing/caseless/flechetteshredder
- name = "flechette (shredder)"
- desc = "A serrated flechette made of a special alloy that forms a monofilament edge."
- projectile_type = /obj/item/projectile/bullet/cflechettes
-
-/obj/item/ammo_box/magazine/flechette/shredder
- name = "flechette magazine (shredder)"
- icon_state = "shreddermag"
- ammo_type = /obj/item/ammo_casing/caseless/flechetteshredder
-
-/obj/item/gun/ballistic/automatic/flechette/shredder
- name = "\improper CX Shredder"
- desc = "A flechette launching machine pistol made of ultra-light CFRP optimized for firing serrated monofillament flechettes."
- w_class = WEIGHT_CLASS_SMALL
- mag_type = /obj/item/ammo_box/magazine/flechette/shredder
- spread = 15
- recoil = 0.1
-
-/obj/item/gun/ballistic/automatic/flechette/shredder/update_icon()
- ..()
- if(magazine)
- cut_overlays()
- add_overlay("shreddergun-magazine")
- else
- cut_overlays()
- icon_state = "[initial(icon_state)][chambered ? "" : "-e"]"
diff --git a/modular_citadel/code/modules/projectiles/guns/ballistic/magweapon.dm b/modular_citadel/code/modules/projectiles/guns/ballistic/magweapon.dm
index b3af722332..70d3bee5af 100644
--- a/modular_citadel/code/modules/projectiles/guns/ballistic/magweapon.dm
+++ b/modular_citadel/code/modules/projectiles/guns/ballistic/magweapon.dm
@@ -86,7 +86,7 @@
/obj/item/ammo_box/magazine/mmag/small
name = "magpistol magazine (non-lethal disabler)"
icon = 'modular_citadel/icons/obj/guns/cit_guns.dmi'
- icon_state = "nlmagmag"
+ icon_state = "smallmagmag"
ammo_type = /obj/item/ammo_casing/caseless/anlmags
caliber = "mags"
max_ammo = 15
diff --git a/modular_citadel/code/modules/projectiles/guns/ballistic/magweapon_energy.dm b/modular_citadel/code/modules/projectiles/guns/ballistic/magweapon_energy.dm
index 8d08937f55..8786eb6dc9 100644
--- a/modular_citadel/code/modules/projectiles/guns/ballistic/magweapon_energy.dm
+++ b/modular_citadel/code/modules/projectiles/guns/ballistic/magweapon_energy.dm
@@ -56,7 +56,7 @@
/obj/item/ammo_box/magazine/mmag_e/small
name = "magpistol magazine (non-lethal disabler)"
icon = 'modular_citadel/icons/obj/guns/cit_guns.dmi'
- icon_state = "nlmagmag"
+ icon_state = "smallmagmag"
ammo_type = /obj/item/ammo_casing/caseless/mag_e/anlmags
caliber = "mag_e"
max_ammo = 16
diff --git a/modular_citadel/code/modules/projectiles/guns/ballistic/rifles.dm b/modular_citadel/code/modules/projectiles/guns/ballistic/rifles.dm
index 3df77c4951..1e0e0afc87 100644
--- a/modular_citadel/code/modules/projectiles/guns/ballistic/rifles.dm
+++ b/modular_citadel/code/modules/projectiles/guns/ballistic/rifles.dm
@@ -123,8 +123,8 @@
item_state = "gun"
w_class = WEIGHT_CLASS_NORMAL
slot_flags = 0
- /obj/item/firing_pin/implant/pindicate
- mag_type = /obj/item/ammo_box/magazine/flechette/
+ pin = /obj/item/firing_pin/implant/pindicate
+ mag_type = /obj/item/ammo_box/magazine/flechette
fire_sound = 'sound/weapons/gunshot_smg.ogg'
can_suppress = 0
burst_size = 5
@@ -134,12 +134,9 @@
recoil = 0.05
/obj/item/gun/ballistic/automatic/flechette/update_icon()
- ..()
+ cut_overlays()
if(magazine)
- cut_overlays()
add_overlay("flechettegun-magazine")
- else
- cut_overlays()
icon_state = "[initial(icon_state)][chambered ? "" : "-e"]"
///unique variant///
@@ -163,17 +160,13 @@
name = "\improper CX Shredder"
desc = "A flechette launching machine pistol made of ultra-light CFRP optimized for firing serrated monofillament flechettes."
w_class = WEIGHT_CLASS_SMALL
- mag_type = /obj/item/ammo_box/magazine/flechette/shredder
spread = 15
recoil = 0.1
/obj/item/gun/ballistic/automatic/flechette/shredder/update_icon()
- ..()
+ cut_overlays()
if(magazine)
- cut_overlays()
add_overlay("shreddergun-magazine")
- else
- cut_overlays()
icon_state = "[initial(icon_state)][chambered ? "" : "-e"]"
/*/////////////////////////////////////////////////////////////
diff --git a/modular_citadel/code/modules/reagents/chemistry/reagents/MKUltra.dm b/modular_citadel/code/modules/reagents/chemistry/reagents/MKUltra.dm
new file mode 100644
index 0000000000..1508a5d519
--- /dev/null
+++ b/modular_citadel/code/modules/reagents/chemistry/reagents/MKUltra.dm
@@ -0,0 +1,373 @@
+/*
+////////////////////////////////////////
+// MKULTA //
+////////////////////////////////////////
+The magnum opus of FermiChem -
+Long and complicated, I highly recomend you look at the two other files heavily involved in this
+modular_citadel/code/datums/status_effects/chems.dm - handles the subject's reactions
+code/modules/surgery/organs/vocal_cords.dm - handles the enchanter speaking
+
+HOW IT WORKS
+Fermis_Reagent.dm
+There's 3 main ways this chemical works; I'll start off with discussing how it's set up.
+Upon reacting with blood as a catalyst, the blood is used to define who the enthraller is - thus only the creator is/can choose who the master will be. As a side note, you can't adminbus this chem, even admins have to earn it.
+This uses the fermichem only proc; FermiCreate, which is basically the same as On_new, except it doesn't require "data" which is something to do with blood and breaks everything so I said bugger it and made my own proc. It basically sets up vars.
+When it's first made, the creator has to drink some of it, in order to give them the vocal chords needed.
+When it's given to someone, it gives them the status effect and kicks off that side of things. For every metabolism tick, it increases the enthrall tally.
+Finally, if you manage to pump 100u into some poor soul, you overload them, and mindbreak them. Making them your willing, but broken slave. Which can only be reversed by; fixing their brain with mannitol and neurine (100 / 50u respectively) (or less with both),
+
+vocal_cords.dm
+This handles when the enchanter speaks - basically uses code from voice of god, but only for people with the staus effect. Most of the words are self explainitory, and has a smaller range of commands. If you're not sure what one does, it likely affects the enthrall tally, or the resist tally.
+list of commands:
+
+-mixables-
+enthral_words
+reward_words
+punish_words
+0
+saymyname_words
+wakeup_words
+1
+silence_words
+antiresist_words
+resist_words
+forget_words
+attract_words
+orgasm_words
+2
+awoo_words
+nya_words
+sleep_words
+strip_words
+walk_words
+run_words
+knockdown_words
+3
+statecustom_words
+custom_words
+objective_words
+heal_words
+stun_words
+hallucinate_words
+hot_words
+cold_words
+getup_words
+pacify_words
+charge_words
+
+Mixables can be used intersperced with other commands, 0 is commands that work on sleeper against (i.e. players enthralled to state 3, then ordered to wake up and forget, they can be triggered back instantly)
+1 is for players who immediately are injected with the chem - no stuns, only a silence and something that draws them towrds them. This is the best time to try to fight it and you're likely to win by spamming resist, unless the enchantress has plans.
+2 is the seconds stage, which allows removal of clothes, slowdown and light stunning. You can also make them nya and awoo, because cute.
+3 is the finaly state, which allows application of a few status effects (see chem.dm) and allows custom triggers to be installed (kind of like nanites), again, see chem.dm
+In a nutshell, this is the way you enthrall people, by typing messages into chat and managing cooldowns on the stronger words. You have to type words and your message strength is increases with the number of characters - if you type short messages the cooldown will be too much and the other player will overcome the chem.
+I suppose people could spam gdjshogndjoadphgiuaodp but, the truth of this chem is that it mostly allows a casus beli for subs to give in, and everyones a sub on cit (mostly), so if you aujigbnadjgipagdsjk then they might resist harder cause you're a baddie and baddies don't deserve pets.
+Also, the use of this chem as a murder aid is antithetic to it's design, the subject gains bonus resistance if they're hurt or hungry (I'd like to expland this more, I like the idea that you have to look after all of them otherwise they aren't as effective, kind of like tamagachis!). If this becomes a problem, I'll deal with it, I'm not happy with people abusing this chem for an easy murder. (I might make it so you an't strike your pet when health is too low.)
+Additionaly, in lieu of previous statement - the pet is ordered to not kill themselves, even if ordered to.
+
+chem.dm
+oof
+There's a few basic things that have to be understood with this status effect
+1. There is a min loop which calculates the enthrall state of the subject, when the entrall tally is over a certain amount, it will push you up 1 phase.
+0 - Sleeper
+1 - initial
+2 - enthralled
+3 - Fully entranced
+4 - mindbroken
+4 can only be reached via OD, whereas you can increment up from 1 > 2 > 3. 0 is only obtainable on a state 3 pet, and it toggles between the two.
+
+1.5 Chem warfare
+Since this is a chem, it's expected that you will use all of the chemicals at your disposal. Using aphro and aphro+ will weaken the resistance of the subject, while ananphro, anaphro+, mannitol and neurine will strengthen it.
+Additionally, the more aroused you are, the weaker your resistance will be, as a result players immune to aphro and anaphro give a flat bonus to the enthraller.
+using furranium and hatmium on the enchanter weakens their power considerably, because they sound rediculous. "Youwe fweewing wery sweepy uwu" This completely justifies their existance.
+The impure toxin for this chem increases resistance too, so if they're a bad chemist it'll be unlikely they have a good ratio (and as a secret bonus, really good chemists cann purposely make the impure chem, to use either to combat the use of it against them, or as smoke grenades to deal with a large party)
+
+2. There is a resistance proc which occurs whenever the player presses resist. You have to press it a lot, this is intentional. If you're trying to fight the enchanter, then you can't click both. You usually will win if you just mash resist and the enchanter does nothing, so you've got to react.
+Each step futher it becomes harder to resist, in state 2 it's longer, but resisting is still worthwhile. If you're not in state 3, and you've not got MKultra inside of you, you generate resistance very fast. So in some cases the better option will be to stall out any attempts to entrance you.
+At the moment, resistance doesn't affect the commands - mostly because it's a way to tell if a state 3 is trying to resist. But this might change if it gets too hard to fight them off.
+Durign state 3, it's impossible to resist if the enthraller is in your presence (8 tiles), you generate no resistance if so. If they're out of your range, then you start to go into the addiction processed
+As your resistance is tied to your arousal, sometimes your best option is to wah
+
+3. The addition process starts when the enthraller is out of range, it roughtly follows the five stages of grief; denial, anger, bargaining, depression and acceptance.
+What it mostly does makes you sad, hurts your brain, and sometimes you lash out in anger.
+Denial - minor brain damaged
+bargaining - 50:50 chance of brain damage and brain healing
+anger - randomly lashing out and hitting people
+depression - massive mood loss, stuttering, jittering, hallucinations and brain damage
+depression, again - random stunning and crying, brain damage, and resistance
+acceptance - minor brain damage and resistance.
+You can also resist while out of range, but you can only break free of a stange 3 enthrallment by hitting the acceptance phase with a high enough resistance.
+Finally, being near your enthraller reverts the damages caused.
+It is expected that if you intend to break free you'll need to use psicodine and mannitol or you'll end up in a bad, but not dead, state. This gives more work for medical!! Finally the true rational of this complicated chem comes out.
+
+4. Status effects in status effects.
+There's a few commands that give status effects, such as antiresist, which will cause resistance presses to increase the enthrallment instead, theses are called from the vocal chords.
+They're mostly self explainitory; antiresist, charge, pacify and heal. Heals quite weak for obvious reasons. I'd like to add more, maybe some weak adneals with brute/exhaustion costs after the status is over. A truth serum might be neat too.
+State 4 pets don't get status effects.
+
+5. Custom triggers
+Because it wasnt complicated enough already.
+Custom triggers are set by stating a trigger word, which will call a sub proc, which is also defined when the trigger is Called
+The effects avalible at the moment are:
+Speak - forces pet to say a preallocated phrase in response to the trigger
+Echo - sends a message to that player only (i.e. makes them think something)
+Shock - gives them a seizure/zaps them
+You can look this one up yourself - it's what you expect, it's cit
+kneel - gives a short knockdown
+strip - strips jumpsuit only
+objective - gives the pet a new objective. This requires a high ammount of mental capasity - which is determined by how much you resist. If you resist enough during phase 1 and 2, then they can't give you an objective.
+Feel free to add more.
+triggers work when said by ANYONE, not just the enchanter.
+This is only state 3 pets, state 4 pets cannot get custom triggers, you broke them you bully.
+
+7. If you're an antage you get a bonus to resistance AND to enthralling. Thus it can be worth using this on both sides. It shouldn't be hard to resist as an antag. There are futher bonuses to command, Chaplains and chemist.
+If you give your pet a collar then their resistance reduced too.
+(I think thats everything?)
+
+Failstates:
+Blowing up the reaction produces a gas that causes everyone to fall in love with one another.
+
+Creating a chem with a low purity will make you permanently fall in love with someone, and tasked with keeping them safe. If someone else drinks it, you fall for them.
+*/
+
+/datum/reagent/fermi/enthrall
+ name = "MKUltra"
+ id = "enthrall"
+ description = "A forbidden deep red mixture that overwhelms a foreign body with waves of pleasure, intoxicating them into servitude. When taken by the creator, it will enhance the draw of their voice to those affected by it."
+ color = "#660015" // rgb: , 0, 255
+ taste_description = "synthetic chocolate, a base tone of alcohol, and high notes of roses"
+ overdose_threshold = 100 //If this is too easy to get 100u of this, then double it please.
+ DoNotSplit = TRUE
+ metabolization_rate = 0.1//It has to be slow, so there's time for the effect.
+ data = list("creatorID" = null, "creatorGender" = null, "creatorName" = null)
+ var/creatorID //ckey
+ var/creatorGender
+ var/creatorName
+ var/mob/living/creator
+ pH = 10
+ OnMobMergeCheck = TRUE //Procs on_mob_add when merging into a human
+ can_synth = FALSE
+
+
+/datum/reagent/fermi/enthrall/test
+ name = "MKUltraTest"
+ id = "enthrallTest"
+ description = "A forbidden deep red mixture that overwhelms a foreign body with waves of joy, intoxicating them into servitude. When taken by the creator, it will enhance the draw of their voice to those affected by it."
+ data = list("creatorID" = "honkatonkbramblesnatch", "creatorGender" = "Mistress", "creatorName" = "Fermis Yakumo")
+ creatorID = "honkatonkbramblesnatch"//ckey
+ creatorGender = "Mistress"
+ creatorName = "Fermis Yakumo"
+ purity = 1
+ DoNotSplit = TRUE
+
+/datum/reagent/fermi/enthrall/test/on_new()
+ id = "enthrall"
+ ..()
+ creator = get_mob_by_key(creatorID)
+
+/datum/reagent/fermi/enthrall/on_new(list/data)
+ creatorID = data.["creatorID"]
+ creatorGender = data.["creatorGender"]
+ creatorName = data.["creatorName"]
+ creator = get_mob_by_key(creatorID)
+
+/datum/reagent/fermi/enthrall/on_mob_add(mob/living/carbon/M)
+ . = ..()
+ if(!ishuman(M))//Just to make sure screwy stuff doesn't happen.
+ return
+ if(!creatorID)
+ //This happens when the reaction explodes.
+ return
+ if(purity < 0.5)//Impure chems don't function as you expect
+ return
+ var/datum/status_effect/chem/enthrall/E = M.has_status_effect(/datum/status_effect/chem/enthrall)
+ if(E)
+ if(E.enthrallID == M.ckey && creatorID != M.ckey)//If you're enthralled to yourself (from OD) and someone else tries to enthrall you, you become thralled to them instantly.
+ E.enthrallID = creatorID
+ E.enthrallGender = creatorGender
+ E.master = get_mob_by_key(creatorID)
+ to_chat(M, to_chat(M, "Your aldled, plastic, mind bends under the chemical influence of a new [(M.client?.prefs.lewdchem?"master":"leader")]. Your highest priority is now to stay by [creatorName]'s side, following and aiding them at all costs.")) //THIS SHOULD ONLY EVER APPEAR IF YOU MINDBREAK YOURSELF AND THEN GET INJECTED FROM SOMEONE ELSE.
+ log_game("FERMICHEM: Narcissist [M] ckey: [M.key] been rebound to [creatorName], ID: [creatorID]")
+ return
+ if((M.ckey == creatorID) && (creatorName == M.real_name)) //same name AND same player - same instance of the player. (should work for clones?)
+ log_game("FERMICHEM: [M] ckey: [M.key] has been given velvetspeech")
+ var/obj/item/organ/vocal_cords/Vc = M.getorganslot(ORGAN_SLOT_VOICE)
+ var/obj/item/organ/vocal_cords/nVc = new /obj/item/organ/vocal_cords/velvet
+ if(Vc)
+ Vc.Remove(M)
+ nVc.Insert(M)
+ qdel(Vc)
+ to_chat(M, "You feel your vocal chords tingle as your voice comes out in a more sultry tone.")
+ else
+ log_game("FERMICHEM: MKUltra: [creatorName], [creatorID], is enthralling [M.name], [M.ckey]")
+ M.apply_status_effect(/datum/status_effect/chem/enthrall)
+ log_game("FERMICHEM: [M] ckey: [M.key] has taken MKUltra")
+
+/datum/reagent/fermi/enthrall/on_mob_life(mob/living/carbon/M)
+ . = ..()
+ if(purity < 0.5)//DO NOT SPLIT INTO DIFFERENT CHEM: This relies on DoNotSplit - has to be done this way.
+ if(volume < 0.5)//You don't get to escape that easily
+ FallInLove(pick(GLOB.player_list), M)
+ M.reagents.remove_reagent(id, volume)
+
+ if (M.ckey == creatorID && creatorName == M.real_name)//If the creator drinks it, they fall in love randomly. If someone else drinks it, the creator falls in love with them.
+ if(M.has_status_effect(STATUS_EFFECT_INLOVE))//Can't be enthralled when enthralled, so to speak.
+ return
+ var/list/seen = viewers(7, get_turf(M))
+ for(var/victim in seen)
+ if(ishuman(victim))
+ var/mob/living/carbon/V = victim
+ if((V == M) || (!V.client) || (V.stat == DEAD))
+ seen = seen - victim
+ else
+ seen = seen - victim
+
+ if(LAZYLEN(seen))
+ return
+ M.reagents.remove_reagent(id, volume)
+ FallInLove(M, pick(seen))
+ return
+
+ else // If someone else drinks it, the creator falls in love with them!
+ var/mob/living/carbon/C = get_mob_by_key(creatorID)
+ if(M.has_status_effect(STATUS_EFFECT_INLOVE))
+ return
+ if((C in viewers(7, get_turf(M))) && (C.client))
+ M.reagents.remove_reagent(id, volume)
+ FallInLove(C, M)
+ return
+
+ if (M.ckey == creatorID && creatorName == M.real_name)//If you yourself drink it, it supresses the vocal effects, for stealth. NEVERMIND ADD THIS LATER I CAN'T GET IT TO WORK
+ return
+ if(!M.client)
+ metabolization_rate = 0 //Stops powergamers from quitting to avoid affects. but prevents affects on players that don't exist for performance.
+ return
+ if(metabolization_rate == 0)
+ metabolization_rate = 0.1
+ var/datum/status_effect/chem/enthrall/E = M.has_status_effect(/datum/status_effect/chem/enthrall)//If purity is over 5, works as intended
+ if(!E)
+ return
+ else
+ E.enthrallTally += 1
+ ..()
+
+/datum/reagent/fermi/enthrall/overdose_start(mob/living/carbon/M)//I made it so the creator is set to gain the status for someone random.
+ . = ..()
+ metabolization_rate = 1//Mostly to manage brain damage and reduce server stress
+ if (M.ckey == creatorID && creatorName == M.real_name)//If the creator drinks 100u, then you get the status for someone random (They don't have the vocal chords though, so it's limited.)
+ if (!M.has_status_effect(/datum/status_effect/chem/enthrall))
+ to_chat(M, "You are unable to resist your own charms anymore, and become a full blown narcissist.")
+ /*Old way of handling, left in as an option B
+ var/list/seen = viewers(7, get_turf(M))//Sound and sight checkers
+ for(var/mob/living/carbon/victim in seen)
+ if(victim == M)//as much as I want you to fall for beepsky, he doesn't have a ckey
+ seen = seen - victim
+ if(!victim.ckey)
+ seen = seen - victim
+ var/mob/living/carbon/chosen = pick(seen)
+ creatorID = chosen.ckey
+ if (chosen.gender == "female")
+ creatorGender = "Mistress"
+ else
+ creatorGender = "Master"
+ creatorName = chosen.real_name
+ creator = get_mob_by_key(creatorID)
+ */
+ ADD_TRAIT(M, TRAIT_PACIFISM, "MKUltra")
+ var/datum/status_effect/chem/enthrall/E
+ if (!M.has_status_effect(/datum/status_effect/chem/enthrall))
+ M.apply_status_effect(/datum/status_effect/chem/enthrall)
+ E = M.has_status_effect(/datum/status_effect/chem/enthrall)
+ E.enthrallID = creatorID
+ E.enthrallGender = creatorGender
+ E.master = creator
+ else
+ E = M.has_status_effect(/datum/status_effect/chem/enthrall)
+ if(M.client?.prefs.lewdchem)
+ to_chat(M, "Your mind shatters under the volume of the mild altering chem inside of you, breaking all will and thought completely. Instead the only force driving you now is the instinctual desire to obey and follow [creatorName]. Your highest priority is now to stay by their side and protect them at all costs.")
+ else
+ to_chat(M, "The might volume of chemicals in your system overwhelms your mind, and you suddenly agree with what [creatorName] has been saying. Your highest priority is now to stay by their side and protect them at all costs.")
+ log_game("FERMICHEM: [M] ckey: [M.key] has been mindbroken for [creatorName] ckey: [creatorID]")
+ M.slurring = 100
+ M.confused = 100
+ E.phase = 4
+ E.mental_capacity = 0
+ E.customTriggers = list()
+ SSblackbox.record_feedback("tally", "fermi_chem", 1, "Thralls mindbroken")
+
+/datum/reagent/fermi/enthrall/overdose_process(mob/living/carbon/M)
+ M.adjustBrainLoss(0.2)//should be ~30 in total
+ ..()
+
+//Creates a gas cloud when the reaction blows up, causing everyone in it to fall in love with someone/something while it's in their system.
+/datum/reagent/fermi/enthrallExplo//Created in a gas cloud when it explodes
+ name = "MKUltra"
+ id = "enthrallExplo"
+ description = "A forbidden deep red mixture that overwhelms a foreign body with waves of desire, inducing a chemial love for another. Also, how the HECC did you get this?"
+ color = "#2C051A" // rgb: , 0, 255
+ metabolization_rate = 0.1
+ taste_description = "synthetic chocolate, a base tone of alcohol, and high notes of roses."
+ DoNotSplit = TRUE
+ can_synth = FALSE
+ var/mob/living/carbon/love
+
+/datum/reagent/fermi/enthrallExplo/on_mob_life(mob/living/carbon/M)//Love gas, only affects while it's in your system,Gives a positive moodlet if close, gives brain damagea and a negative moodlet if not close enough.
+ if(HAS_TRAIT(M, TRAIT_MINDSHIELD))
+ return ..()
+ if(!M.has_status_effect(STATUS_EFFECT_INLOVE))
+ var/list/seen = viewers(7, get_turf(M))//Sound and sight checkers
+ for(var/victim in seen)
+ if((istype(victim, /mob/living/simple_animal/pet/)) || (victim == M) || (M.stat == DEAD) || (!isliving(victim)))
+ seen = seen - victim
+ if(seen.len == 0)
+ return
+ love = pick(seen)
+ if(!love)
+ return
+ M.apply_status_effect(STATUS_EFFECT_INLOVE, love)
+ to_chat(M, "[(M.client?.prefs.lewdchem?"":"")][(M.client?.prefs.lewdchem?"You develop a sudden crush on [love], your heart beginning to race as you look upon them with new eyes.":"You suddenly feel like making friends with [love].")] You feel strangely drawn towards them.")
+ log_game("FERMICHEM: [M] ckey: [M.key] has temporarily bonded with [love] ckey: [love.key]")
+ SSblackbox.record_feedback("tally", "fermi_chem", 1, "Times people have bonded")
+ else
+ if(get_dist(M, love) < 8)
+ if(HAS_TRAIT(M, TRAIT_NYMPHO)) //Add this back when merged/updated.
+ M.adjustArousalLoss(5)
+ var/message = "[(M.client?.prefs.lewdchem?"I'm next to my crush..! Eee!":"I'm making friends with [love]!")]"
+ SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "InLove", /datum/mood_event/InLove, message)
+ SEND_SIGNAL(M, COMSIG_CLEAR_MOOD_EVENT, "MissingLove")
+ else
+ var/message = "[(M.client?.prefs.lewdchem?"I can't keep my crush off my mind, I need to see them again!":"I really want to make friends with [love]!")]"
+ SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "MissingLove", /datum/mood_event/MissingLove, message)
+ SEND_SIGNAL(M, COMSIG_CLEAR_MOOD_EVENT, "InLove")
+ if(prob(5))
+ M.Stun(10)
+ M.emote("whimper")//does this exist?
+ to_chat(M, "[(M.client?.prefs.lewdchem?"":"")] You're overcome with a desire to see [love].")
+ M.adjustBrainLoss(0.5)//I found out why everyone was so damaged!
+ ..()
+
+/datum/reagent/fermi/enthrallExplo/on_mob_delete(mob/living/carbon/M)
+ if(HAS_TRAIT(M, TRAIT_MINDSHIELD))
+ return ..()
+ M.remove_status_effect(STATUS_EFFECT_INLOVE)
+ SEND_SIGNAL(M, COMSIG_CLEAR_MOOD_EVENT, "InLove")
+ SEND_SIGNAL(M, COMSIG_CLEAR_MOOD_EVENT, "MissingLove")
+ to_chat(M, "[(M.client?.prefs.lewdchem?"":"")]Your feelings for [love] suddenly vanish!")
+ log_game("FERMICHEM: [M] ckey: [M.key] is no longer in temp bond")
+ ..()
+
+/datum/reagent/fermi/proc/FallInLove(mob/living/carbon/Lover, mob/living/carbon/Love)
+ if(Lover.has_status_effect(STATUS_EFFECT_INLOVE))
+ to_chat(Lover, "You are already fully devoted to someone else!")
+ return
+ to_chat(Lover, "[(Lover.client?.prefs.lewdchem?"":"")]You develop a deep and sudden bond with [Love][(Lover.client?.prefs.lewdchem?", your heart beginning to race as your mind filles with thoughts about them.":".")] You are determined to keep them safe and happy, and feel drawn towards them.")
+ if(Lover.mind)
+ Lover.mind.store_memory("You are in love with [Love].")
+ Lover.faction |= "[REF(Love)]"
+ Lover.apply_status_effect(STATUS_EFFECT_INLOVE, Love)
+ forge_valentines_objective(Lover, Love, TRUE)
+ SSblackbox.record_feedback("tally", "fermi_chem", 1, "Times people have become infatuated.")
+ log_game("FERMICHEM: [Lover] ckey: [Lover.key] has been chemically made to fall for [Love] ckey: [Love.key]")
+ return
+
+//For addiction see chem.dm
+//For vocal commands see vocal_cords.dm
diff --git a/modular_citadel/code/modules/reagents/chemistry/reagents/SDGF.dm b/modular_citadel/code/modules/reagents/chemistry/reagents/SDGF.dm
new file mode 100644
index 0000000000..499510b5d4
--- /dev/null
+++ b/modular_citadel/code/modules/reagents/chemistry/reagents/SDGF.dm
@@ -0,0 +1,364 @@
+/*SDGF
+////////////////////////////////////////////////////
+// synthetic-derived growth factor //
+//////////////////////////////////////////////////
+other files that are relivant:
+modular_citadel/code/datums/status_effects/chems.dm - SDGF
+WHAT IT DOES
+
+Several outcomes are possible (in priority order):
+
+Before the chem is even created, there is a risk of the reaction "exploding", which produces an angry teratoma that attacks the player.
+0. Before the chem is activated, the purity is checked, if the purity of the reagent is less than 0.5, then sythetic-derived zombie factor is metabolised instead
+ 0.1 If SDZF is injected, the chem appears to act the same as normal, with nutrition gain, until the end, where it becomes toxic instead, giving a short window of warning to the player
+ 0.1.2 If the player can take pent in time, the player will spawn a hostile teratoma on them (less damaging), if they don't, then a zombie is spawned instead, with a small defence increase propotional to the volume
+ 0.2 If the purity is above 0.5, then the remaining impure volume created SDGFtox instead, which reduces blood volume and causes clone damage
+1.Normal function creates a (another)player controlled clone of the player, which is spawned nude, with damage to the clone
+ 1.1 The remaining volume is transferred to the clone, which heals it over time, thus the player has to make a substantial ammount of the chem in order to produce a healthy clone
+ 1.2 If the player is infected with a zombie tumor, the tumor is transferred to the ghost controlled clone ONLY.
+2. If no player can be found, a brainless clone is created over a long period of time, this body has no controller.
+ 2.1 If the player dies with a clone, then they play as the clone instead. However no memories are retained after splitting.
+3. If there is already a clone, then SDGF heals clone, fire and brute damage slowly. This shouldn't normalise this chem as the de facto clone healing chem, as it will always try to make a ghost clone, and then a brainless clone first.
+4. If there is insuffient volume to complete the cloning process, there are two outcomes
+ 4.1 At lower volumes, the players nutrition and blood is refunded, with light healing
+ 4.2 At higher volumes a stronger heal is applied to the user
+
+IMPORTANT FACTORS TO CONSIDER WHILE BALANCING
+1. The most important factor is the required volume, this is easily edited with the metabolism rate, this chem is HARD TO MAKE, You need to make a lot of it and it's a substantial effort on the players part. There is also a substantial risk; you could spawn a hotile teratoma during the reation, you could damage yourself with clone damage, you could accidentally spawn a zombie... Basically, you've a good chance of killing yourself.
+ 1.1 Additionally, if you're trying to make SDZF purposely, you've no idea if you have or not, and that reaction is even harder to do. Plus, the player has a huge time window to get to medical to deal with it. If you take pent while it's in you, it'll be removed before it can spawn, and only spawns a teratoma if it's late stage.
+2. The rate in which the clone is made, This thing takes time to produce fruits, it slows you down and makes you useless in combat/working. Basically you can't do anything during it. It will only get you killed if you use it in combat, If you do use it and you spawn a player clone, they're gimped for a long time, as they have to heal off the clone damage.
+3. The healing - it's pretty low and a cyropod is more Useful
+4. If you're an antag, you've a 50% chance of making a clone that will help you with your efforts, and you've no idea if they will or not. While clones can't directly harm you and care for you, they can hinder your efforts.
+5. If people are being arses when they're a clone, slap them for it, they are told to NOT bugger around with someone else character, if it gets bad I'll add a blacklist, or do a check to see if you've played X amount of hours.
+ 5.1 Another solution I'm okay with is to rename the clone to [M]'s clone, so it's obvious, this obviously ruins anyone trying to clone themselves to get an alibi however. I'd prefer this to not be the case.
+ 5.2 Additionally, this chem is a soft buff to changelings, which apparently need a buff!
+ 5.3 Other similar things exist already though in the codebase; impostors, split personalites, abductors, ect.
+6. Giving this to someone without concent is against space law and gets you sent to gulag.
+*/
+
+//Clone serum #chemClone
+/datum/reagent/fermi/SDGF //vars, mostly only care about keeping track if there's a player in the clone or not.
+ name = "synthetic-derived growth factor"
+ id = "SDGF"
+ description = "A rapidly diving mass of Embryonic stem cells. These cells are missing a nucleus and quickly replicate a host’s DNA before growing to form an almost perfect clone of the host. In some cases neural replication takes longer, though the underlying reason underneath has yet to be determined."
+ color = "#a502e0" // rgb: 96, 0, 255
+ var/playerClone = FALSE
+ var/unitCheck = FALSE
+ metabolization_rate = 0.5 * REAGENTS_METABOLISM
+ taste_description = "a weird chemical fleshy flavour"
+ //var/datum/status_effect/chem/SDGF/candidates/candies
+ var/list/candies = list()
+ //var/polling = FALSE
+ var/list/result = list()
+ var/list/group = null
+ var/pollStarted = FALSE
+ var/location_created
+ var/startHunger
+ ImpureChem = "SDGFtox"
+ InverseChemVal = 0.5
+ InverseChem = "SDZF"
+ can_synth = TRUE
+
+
+//Main SDGF chemical
+/datum/reagent/fermi/SDGF/on_mob_life(mob/living/carbon/M) //Clones user, then puts a ghost in them! If that fails, makes a braindead clone.
+ //Setup clone
+ switch(current_cycle)
+ if(1)
+ startHunger = M.nutrition
+ if(pollStarted == FALSE)
+ pollStarted = TRUE
+ candies = pollGhostCandidates("Do you want to play as a clone of [M], and do you agree to respect their character and act in a similar manner to them? Do not engage in ERP as them unless you have LOOC permission from them, and ensure it is permission from the original, not a clone.")
+ log_game("FERMICHEM: [M] ckey: [M.key] has taken SDGF, and ghosts have been polled.")
+ if(20 to INFINITY)
+ if(LAZYLEN(candies) && playerClone == FALSE) //If there's candidates, clone the person and put them in there!
+ log_game("FERMICHEM: [M] ckey: [M.key] is creating a clone, controlled by [candies]")
+ to_chat(M, "The cells reach a critical micelle concentration, nucleating rapidly within your body!")
+ var/typepath = M.type
+ var/mob/living/carbon/human/fermi_Gclone = new typepath(M.loc)
+ var/mob/living/carbon/human/SM = fermi_Gclone
+ if(istype(SM) && istype(M))
+ SM.real_name = M.real_name
+ M.dna.transfer_identity(SM)
+ SM.updateappearance(mutcolor_update=1)
+ var/mob/dead/observer/C = pick(candies)
+ message_admins("Ghost candidate found! [C] key [C.key] is becoming a clone of [M] key: [M.key] (They agreed to respect the character they're becoming, and agreed to not ERP without express permission from the original.)")
+ SM.key = C.key
+ SM.mind.enslave_mind_to_creator(M)
+
+ //If they're a zombie, they can try to negate it with this.
+ //I seriously wonder if anyone will ever use this function.
+ if(M.getorganslot(ORGAN_SLOT_ZOMBIE))//sure, it "treats" it, but "you've" still got it. Doesn't always work as well; needs a ghost.
+ var/obj/item/organ/zombie_infection/ZI = M.getorganslot(ORGAN_SLOT_ZOMBIE)
+ ZI.Remove(M)
+ ZI.Insert(SM)
+ log_game("FERMICHEM: [M] ckey: [M.key]'s zombie_infection has been transferred to their clone")
+
+ to_chat(SM, "You feel a strange sensation building in your mind as you realise there's two of you, before you get a chance to think about it, you suddenly split from your old body, and find yourself face to face with your original, a perfect clone of your origin.")
+
+ if(prob(50))
+ to_chat(SM, "While you find your newfound existence strange, you share the same memories as [M.real_name]. However, You find yourself indifferent to the goals you previously had, and take more interest in your newfound independence, but still have an indescribable care for the safety of your original.")
+ log_game("FERMICHEM: [SM] ckey: [SM.key]'s is not bound by [M] ckey [M.key]'s will, and is free to determine their own goals, while respecting and acting as their origin.")
+ else
+ to_chat(SM, "While you find your newfound existence strange, you share the same memories as [M.real_name]. Your mind has not deviated from the tasks you set out to do, and now that there's two of you the tasks should be much easier.")
+ log_game("FERMICHEM: [SM] ckey: [SM.key]'s is bound by [M] ckey [M.key]'s objectives, and is encouraged to help them complete them.")
+
+ to_chat(M, "You feel a strange sensation building in your mind as you realise there's two of you, before you get a chance to think about it, you suddenly split from your old body, and find yourself face to face with yourself.")
+ M.visible_message("[M] suddenly shudders, and splits into two identical twins!")
+ SM.copy_known_languages_from(M, FALSE)
+ playerClone = TRUE
+ M.next_move_modifier = 1
+ M.nutrition -= 500
+
+ //Damage the clone
+ SM.blood_volume = (BLOOD_VOLUME_NORMAL*SM.blood_ratio)/2
+ SM.adjustCloneLoss(60, 0)
+ SM.setBrainLoss(40)
+ SM.nutrition = startHunger/2
+
+ //Transfer remaining reagent to clone. I think around 30u will make a healthy clone, otherwise they'll have clone damage, blood loss, brain damage and hunger.
+ SM.reagents.add_reagent("SDGFheal", volume)
+ M.reagents.remove_reagent(id, volume)
+ log_game("FERMICHEM: [volume]u of SDGFheal has been transferred to the clone")
+ SSblackbox.record_feedback("tally", "fermi_chem", 1, "Sentient clones made")
+ return
+
+ else if(playerClone == FALSE) //No candidates leads to two outcomes; if there's already a braincless clone, it heals the user, as well as being a rare souce of clone healing (thematic!).
+ unitCheck = TRUE
+ if(M.has_status_effect(/datum/status_effect/chem/SGDF)) // Heal the user if they went to all this trouble to make it and can't get a clone, the poor fellow.
+ switch(current_cycle)
+ if(21)
+ to_chat(M, "The cells fail to catalyse around a nucleation event, instead merging with your cells.") //This stuff is hard enough to make to rob a user of some benefit. Shouldn't replace Rezadone as it requires the user to not only risk making a player controlled clone, but also requires them to have split in two (which also requires 30u of SGDF).
+ REMOVE_TRAIT(M, TRAIT_DISFIGURED, TRAIT_GENERIC)
+ log_game("FERMICHEM: [M] ckey: [M.key] is being healed by SDGF")
+ if(22 to INFINITY)
+ M.adjustCloneLoss(-1, 0)
+ M.adjustBruteLoss(-1, 0)
+ M.adjustFireLoss(-1, 0)
+ M.heal_bodypart_damage(1,1)
+ M.reagents.remove_reagent(id, 1)//faster rate of loss.
+ else //If there's no ghosts, but they've made a large amount, then proceed to make flavourful clone, where you become fat and useless until you split.
+ switch(current_cycle)
+ if(21)
+ to_chat(M, "You feel the synethic cells rest uncomfortably within your body as they start to pulse and grow rapidly.")
+ if(22 to 29)
+ M.nutrition = M.nutrition + (M.nutrition/10)
+ if(30)
+ to_chat(M, "You feel the synethic cells grow and expand within yourself, bloating your body outwards.")
+ if(31 to 49)
+ M.nutrition = M.nutrition + (M.nutrition/5)
+ if(50)
+ to_chat(M, "The synthetic cells begin to merge with your body, it feels like your body is made of a viscous water, making your movements difficult.")
+ M.next_move_modifier += 4//If this makes you fast then please fix it, it should make you slow!!
+ //candidates = pollGhostCandidates("Do you want to play as a clone of [M.name] and do you agree to respect their character and act in a similar manner to them? I swear to god if you diddle them I will be very disapointed in you. ", "FermiClone", null, ROLE_SENTIENCE, 300) // see poll_ignore.dm, should allow admins to ban greifers or bullies
+ if(51 to 79)
+ M.nutrition = M.nutrition + (M.nutrition/2)
+ if(80)
+ to_chat(M, "The cells begin to precipitate outwards of your body, you feel like you'll split soon...")
+ if (M.nutrition < 20000)
+ M.nutrition = 20000 //https://www.youtube.com/watch?v=Bj_YLenOlZI
+ if(86)//Upon splitting, you get really hungry and are capable again. Deletes the chem after you're done.
+ M.nutrition = 15//YOU BEST BE EATTING AFTER THIS YOU CUTIE
+ M.next_move_modifier -= 4
+ to_chat(M, "Your body splits away from the cell clone of yourself, leaving you with a drained and hollow feeling inside.")
+
+ //clone
+ var/typepath = M.type
+ var/mob/living/fermi_Clone = new typepath(M.loc)
+ var/mob/living/carbon/C = fermi_Clone
+
+ if(istype(C) && istype(M))
+ C.real_name = M.real_name
+ M.dna.transfer_identity(C, transfer_SE=1)
+ C.updateappearance(mutcolor_update=1)
+ C.apply_status_effect(/datum/status_effect/chem/SGDF)
+ var/datum/status_effect/chem/SGDF/S = C.has_status_effect(/datum/status_effect/chem/SGDF)
+ S.original = M
+ S.originalmind = M.mind
+ S.status_set = TRUE
+
+ log_game("FERMICHEM: [M] ckey: [M.key] has created a mindless clone of themselves")
+ SSblackbox.record_feedback("tally", "fermi_chem", 1, "Braindead clones made")
+ if(87 to INFINITY)
+ M.reagents.remove_reagent(id, volume)//removes SGDF on completion. Has to do it this way because of how i've coded it. If some madlab gets over 1k of SDGF, they can have the clone healing.
+
+
+ ..()
+
+/datum/reagent/fermi/SDGF/on_mob_delete(mob/living/M) //When the chem is removed, a few things can happen, mostly consolation prizes.
+ pollStarted = FALSE
+ if (playerClone == TRUE)//If the player made a clone with it, then thats all they get.
+ playerClone = FALSE
+ return
+ if (M.next_move_modifier == 4 && !M.has_status_effect(/datum/status_effect/chem/SGDF))//checks if they're ingested over 20u of the stuff, but fell short of the required 30u to make a clone.
+ to_chat(M, "You feel the cells begin to merge with your body, unable to reach nucleation, they instead merge with your body, healing any wounds.")
+ M.adjustCloneLoss(-10, 0) //I don't want to make Rezadone obsolete.
+ M.adjustBruteLoss(-25, 0)// Note that this takes a long time to apply and makes you fat and useless when it's in you, I don't think this small burst of healing will be useful considering how long it takes to get there.
+ M.adjustFireLoss(-25, 0)
+ M.blood_volume += 250
+ M.heal_bodypart_damage(1,1)
+ M.next_move_modifier = 1
+ if (M.nutrition < 1500)
+ M.nutrition += 250
+ else if (unitCheck == TRUE && !M.has_status_effect(/datum/status_effect/chem/SGDF))// If they're ingested a little bit (10u minimum), then give them a little healing.
+ unitCheck = FALSE
+ to_chat(M, "the cells fail to hold enough mass to generate a clone, instead diffusing into your system.")
+ M.adjustBruteLoss(-10, 0)
+ M.adjustFireLoss(-10, 0)
+ M.blood_volume += 100
+ M.next_move_modifier = 1
+ if (M.nutrition < 1500)
+ M.nutrition += 500
+
+/datum/reagent/fermi/SDGF/reaction_mob(mob/living/carbon/human/M, method=TOUCH, reac_volume)
+ if(volume<5)
+ M.visible_message("The growth factor froths upon [M]'s body, failing to do anything of note.")
+ return
+ if(M.stat == DEAD)
+ if(M.suiciding || (HAS_TRAIT(M, TRAIT_NOCLONE)) || M.hellbound)
+ M.visible_message("The growth factor inertly sticks to [M]'s body, failing to do anything of note.")
+ return
+ if(!M.mind)
+ M.visible_message("The growth factor shudders, merging with [M]'s body, but is unable to replicate properly.")
+
+ var/bodydamage = (M.getBruteLoss() + M.getFireLoss())
+ var/typepath = M.type
+ volume =- 5
+
+ var/mob/living/carbon/human/fermi_Gclone = new typepath(M.loc)
+ var/mob/living/carbon/human/SM = fermi_Gclone
+ if(istype(SM) && istype(M))
+ SM.real_name = M.real_name
+ M.dna.transfer_identity(SM)
+ SM.updateappearance(mutcolor_update=1)
+ M.mind.transfer_to(SM)
+ M.visible_message("[M]'s body shudders, the growth factor rapidly splitting into a new clone of [M].")
+
+ if(bodydamage>50)
+ SM.adjustOxyLoss(-(bodydamage/10), 0)
+ SM.adjustToxLoss(-(bodydamage/10), 0)
+ SM.blood_volume = (BLOOD_VOLUME_NORMAL*SM.blood_ratio)/1.5
+ SM.adjustCloneLoss((bodydamage/10), 0)
+ SM.setBrainLoss((bodydamage/10))
+ SM.nutrition = 400
+ if(bodydamage>200)
+ SM.gain_trauma_type(BRAIN_TRAUMA_MILD)
+ if(bodydamage>300)
+ var/obj/item/bodypart/l_arm = SM.get_bodypart(BODY_ZONE_L_ARM) //We get the body parts we want this way.
+ var/obj/item/bodypart/r_arm = SM.get_bodypart(BODY_ZONE_R_ARM)
+ l_arm.drop_limb()
+ r_arm.drop_limb()
+ if(bodydamage>400)
+ var/obj/item/bodypart/l_leg = SM.get_bodypart(BODY_ZONE_L_LEG) //We get the body parts we want this way.
+ var/obj/item/bodypart/r_leg = SM.get_bodypart(BODY_ZONE_R_LEG)
+ l_leg.drop_limb()
+ r_leg.drop_limb()
+ if(bodydamage>500)
+ SM.gain_trauma_type(BRAIN_TRAUMA_SEVERE)
+ if(bodydamage>600)
+ var/datum/species/mutation = pick(subtypesof(/datum/species))
+ SM.set_species(mutation)
+
+ //Transfer remaining reagent to clone. I think around 30u will make a healthy clone, otherwise they'll have clone damage, blood loss, brain damage and hunger.
+ SM.reagents.add_reagent("SDGFheal", volume)
+ M.reagents.remove_reagent(id, volume)
+
+ SM.updatehealth()
+ SM.emote("gasp")
+ log_combat(M, M, "SDGF clone-vived", src)
+ ..()
+
+//Unobtainable, used in clone spawn.
+/datum/reagent/fermi/SDGFheal
+ name = "synthetic-derived growth factor"
+ id = "SDGFheal"
+ metabolization_rate = 1
+ can_synth = FALSE
+
+/datum/reagent/fermi/SDGFheal/on_mob_life(mob/living/carbon/M)//Used to heal the clone after splitting, the clone spawns damaged. (i.e. insentivies players to make more than required, so their clone doesn't have to be treated)
+ if(M.blood_volume < (BLOOD_VOLUME_NORMAL*M.blood_ratio))
+ M.blood_volume += 10
+ M.adjustCloneLoss(-2, 0)
+ M.setBrainLoss(-1)
+ M.nutrition += 10
+ ..()
+
+//Unobtainable, used if SDGF is impure but not too impure
+/datum/reagent/fermi/SDGFtox
+ name = "synthetic-derived growth factor"
+ id = "SDGFtox"
+ description = "A chem that makes a certain chemcat angry at you if you're reading this, how did you get this???"//i.e. tell me please, figure it's a good way to get pinged for bugfixes.
+ metabolization_rate = 1
+ can_synth = FALSE
+
+/datum/reagent/fermi/SDGFtox/on_mob_life(mob/living/carbon/M)//Damages the taker if their purity is low. Extended use of impure chemicals will make the original die. (thus can't be spammed unless you've very good)
+ M.blood_volume -= 10
+ M.adjustCloneLoss(2, 0)
+ ..()
+
+//Fail state of SDGF
+/datum/reagent/fermi/SDZF
+ name = "synthetic-derived growth factor"
+ id = "SDZF"
+ description = "A horribly peverse mass of Embryonic stem cells made real by the hands of a failed chemist. This message should never appear, how did you manage to get a hold of this?"
+ color = "#a502e0" // rgb: 96, 0, 255
+ metabolization_rate = 0.5 * REAGENTS_METABOLISM
+ var/startHunger
+ can_synth = TRUE
+
+/datum/reagent/fermi/SDZF/on_mob_life(mob/living/carbon/M) //If you're bad at fermichem, turns your clone into a zombie instead.
+ switch(current_cycle)//Pretends to be normal
+ if(20)
+ to_chat(M, "You feel the synethic cells rest uncomfortably within your body as they start to pulse and grow rapidly.")
+ startHunger = M.nutrition
+ if(21 to 29)
+ M.nutrition = M.nutrition + (M.nutrition/10)
+ if(30)
+ to_chat(M, "You feel the synethic cells grow and expand within yourself, bloating your body outwards.")
+ if(31 to 49)
+ M.nutrition = M.nutrition + (M.nutrition/5)
+ if(50)
+ to_chat(M, "The synethic cells begin to merge with your body, it feels like your body is made of a viscous water, making your movements difficult.")
+ M.next_move_modifier = 4//If this makes you fast then please fix it, it should make you slow!!
+ if(51 to 73)
+ M.nutrition = M.nutrition + (M.nutrition/2)
+ if(74)
+ to_chat(M, "The cells begin to precipitate outwards of your body, but... something is wrong, the sythetic cells are beginnning to rot...")
+ if (M.nutrition < 20000) //whoever knows the maxcap, please let me know, this seems a bit low.
+ M.nutrition = 20000 //https://www.youtube.com/watch?v=Bj_YLenOlZI
+ if(75 to 85)
+ M.adjustToxLoss(1, 0)// the warning!
+
+ if(86)//mean clone time!
+ if (!M.reagents.has_reagent("pen_acid"))//Counterplay is pent.)
+ message_admins("(non-infectious) SDZF: Zombie spawned at [M] [COORD(M)]!")
+ M.nutrition = startHunger - 500//YOU BEST BE RUNNING AWAY AFTER THIS YOU BADDIE
+ M.next_move_modifier = 1
+ to_chat(M, "Your body splits away from the cell clone of yourself, your attempted clone birthing itself violently from you as it begins to shamble around, a terrifying abomination of science.")
+ M.visible_message("[M] suddenly shudders, and splits into a funky smelling copy of themselves!")
+ M.emote("scream")
+ M.adjustToxLoss(30, 0)
+ var/mob/living/simple_animal/hostile/unemployedclone/ZI = new(get_turf(M.loc))
+ ZI.damage_coeff = list(BRUTE = ((1 / volume)**0.25) , BURN = ((1 / volume)**0.1), TOX = 1, CLONE = 1, STAMINA = 0, OXY = 1)
+ ZI.real_name = M.real_name//Give your offspring a big old kiss.
+ ZI.name = M.real_name
+ ZI.desc = "[M]'s clone, gone horribly wrong."
+ log_game("FERMICHEM: [M] ckey: [M.key]'s clone has become a horrifying zombie instead")
+ M.reagents.remove_reagent(id, 20)
+
+ else//easier to deal with
+ to_chat(M, "The pentetic acid seems to have stopped the decay for now, clumping up the cells into a horrifying tumour!")
+ M.nutrition = startHunger - 500
+ var/mob/living/simple_animal/slime/S = new(get_turf(M.loc),"grey") //TODO: replace slime as own simplemob/add tumour slime cores for science/chemistry interplay
+ S.damage_coeff = list(BRUTE = ((1 / volume)**0.1) , BURN = 2, TOX = 1, CLONE = 1, STAMINA = 0, OXY = 1)
+ S.name = "Living teratoma"
+ S.real_name = "Living teratoma"//horrifying!!
+ S.rabid = 1//Make them an angery boi
+ M.reagents.remove_reagent(id, volume)
+ to_chat(M, "A large glob of the tumour suddenly splits itself from your body. You feel grossed out and slimey...")
+ log_game("FERMICHEM: [M] ckey: [M.key]'s clone has become a horrifying teratoma instead")
+ SSblackbox.record_feedback("tally", "fermi_chem", 1, "Zombie clones made!")
+
+ if(87 to INFINITY)
+ M.adjustToxLoss(1, 0)
+ ..()
diff --git a/modular_citadel/code/modules/reagents/chemistry/reagents/astrogen.dm b/modular_citadel/code/modules/reagents/chemistry/reagents/astrogen.dm
new file mode 100644
index 0000000000..d05cfb552e
--- /dev/null
+++ b/modular_citadel/code/modules/reagents/chemistry/reagents/astrogen.dm
@@ -0,0 +1,152 @@
+/*
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// ASTROGEN
+///////////////////////////////////////////////////////////////////////////////////////////////////
+More fun chems!
+When you take it, it spawns a ghost that the player controls. (No access to deadchat)
+This ghost moves pretty quickly and is mostly invisible, but is still visible for people with eyes.
+When it's out of your system, you return back to yourself. It doesn't last long and metabolism of the chem is exponential.
+Addiction is particularlly brutal, it slowly turns you invisible with flavour text, then kills you at a low enough alpha. (i've also added something to prevent geneticists speeding this up)
+There's afairly major catch regarding the death though. I'm not gonna say here, go read the code, it explains it and puts my comments on it in context. I know that anyone reading it without understanding it is going to freak out so, this is my attempt to get you to read it and understand it.
+I'd like to point out from my calculations it'll take about 60-80 minutes to die this way too. Plenty of time to visit me and ask for some pills to quench your addiction.
+*/
+
+
+
+/datum/reagent/fermi/astral // Gives you the ability to astral project for a moment!
+ name = "Astrogen"
+ id = "astral"
+ description = "An opalescent murky liquid that is said to distort your soul from your being."
+ color = "#A080H4" // rgb: , 0, 255
+ taste_description = "your mind"
+ metabolization_rate = 0//Removal is exponential, see code
+ overdose_threshold = 20
+ addiction_threshold = 24.5
+ addiction_stage1_end = 9999//Should never end. There is no escape make your time
+ var/mob/living/carbon/origin
+ var/mob/living/simple_animal/astral/G = null
+ var/datum/mind/originalmind
+ var/antiGenetics = 255
+ var/sleepytime = 0
+ InverseChemVal = 0.25
+ can_synth = FALSE
+
+/datum/action/chem/astral
+ name = "Return to body"
+ var/mob/living/carbon/origin = null
+ var/mob/living/simple_animal/hostile/retaliate/ghost = null
+
+/datum/action/chem/astral/Trigger()
+ ghost.mind.transfer_to(origin)
+ qdel(src)
+
+/datum/reagent/fermi/astral/reaction_turf(turf/T, reac_volume)
+ if(isplatingturf(T) || istype(T, /turf/open/floor/plasteel))
+ var/turf/open/floor/F = T
+ F.PlaceOnTop(/turf/open/floor/fakespace)
+ ..()
+
+/datum/reagent/fermi/astral/reaction_obj(obj/O, reac_volume)
+ if(istype(O, /obj/item/bedsheet))
+ new /obj/item/bedsheet/cosmos(get_turf(O))
+ qdel(O)
+
+
+/datum/reagent/fermi/astral/on_mob_life(mob/living/carbon/M) // Gives you the ability to astral project for a moment!
+ M.alpha = 255
+ if(current_cycle == 0)
+ originalmind = M.mind
+ log_game("FERMICHEM: [M] ckey: [M.key] became an astral ghost")
+ origin = M
+ if (G == null)
+ G = new(get_turf(M.loc))
+ G.name = "[M]'s astral projection"
+ var/datum/action/chem/astral/AS = new(G)
+ AS.origin = M
+ AS.ghost = G
+ if(M.mind)
+ M.mind.transfer_to(G)
+ SSblackbox.record_feedback("tally", "fermi_chem", 1, "Astral projections")
+ if(overdosed)
+ if(prob(50))
+ to_chat(G, "The high conentration of Astrogen in your blood causes you to lapse your concentration for a moment, bringing your projection back to yourself!")
+ do_teleport(G, M.loc)
+ M.reagents.remove_reagent(id, current_cycle/10, FALSE)//exponent
+ sleepytime+=5
+ if(G)//This is a mess because of how slow qdel is, so this is all to stop runtimes.
+ if(G.mind)
+ if(G.stat == DEAD || G.pseudo_death == TRUE)
+ G.mind.transfer_to(M)
+ qdel(G)
+ ..()
+
+/datum/reagent/fermi/astral/on_mob_delete(mob/living/carbon/M)
+ if(!G)
+ if(M.mind)
+ var/mob/living/simple_animal/astral/G = new(get_turf(M.loc))
+ M.mind.transfer_to(G)//Just in case someone else is inside of you, it makes them a ghost and should hopefully bring them home at the end.
+ to_chat(G, "[M]'s conciousness snaps back to them as their astrogen runs out, kicking your projected mind out!'")
+ log_game("FERMICHEM: [M]'s possesser has been booted out into a astral ghost!")
+ originalmind.transfer_to(M)
+ else if(G.mind)
+ G.mind.transfer_to(origin)
+ qdel(G)
+ if(overdosed)
+ to_chat(M, "The high volume of astrogen you just took causes you to black out momentarily as your mind snaps back to your body.")
+ M.Sleeping(sleepytime, 0)
+ antiGenetics = 255
+ if(G)//just in case
+ qdel(G)
+ log_game("FERMICHEM: [M] has astrally returned to their body!")
+ ..()
+
+//Okay so, this might seem a bit too good, but my counterargument is that it'll likely take all round to eventually kill you this way, then you have to be revived without a body. It takes approximately 50-80 minutes to die from this.
+/datum/reagent/fermi/astral/addiction_act_stage1(mob/living/carbon/M)
+ if(addiction_stage < 2)
+ antiGenetics = 255
+ M.alpha = 255 //Antigenetics is to do with stopping geneticists from turning people invisible to kill them.
+ if(prob(70))
+ M.alpha--
+ antiGenetics--
+ switch(antiGenetics)
+ if(245)
+ to_chat(M, "You notice your body starting to disappear, maybe you took too much Astrogen...?")
+ M.alpha--
+ antiGenetics--
+ log_game("FERMICHEM: [M] ckey: [M.key] has become addicted to Astrogen")
+ if(220)
+ to_chat(M, "Your addiction is only getting worse as your body disappears. Maybe you should get some more, and fast?")
+ M.alpha--
+ antiGenetics--
+ if(200)
+ to_chat(M, "You feel a substantial part of your soul flake off into the ethereal world, rendering yourself unclonable.")
+ M.alpha--
+ antiGenetics--
+ ADD_TRAIT(M, TRAIT_NOCLONE, "astral") //So you can't scan yourself, then die, to metacomm. You can only use your memories if you come back as something else.
+ M.hellbound = TRUE
+ if(180)
+ to_chat(M, "You feel fear build up in yourself as more and more of your body and consciousness begins to fade.")
+ M.alpha--
+ antiGenetics--
+ if(120)
+ to_chat(M, "As you lose more and more of yourself, you start to think that maybe shedding your mortality isn't too bad.")
+ M.alpha--
+ antiGenetics--
+ if(80)
+ to_chat(M, "You feel a thrill shoot through your body as what's left of your mind contemplates your forthcoming oblivion.")
+ M.alpha--
+ antiGenetics--
+ if(45)
+ to_chat(M, "The last vestiges of your mind eagerly await your imminent annihilation.")
+ M.alpha--
+ antiGenetics--
+ if(-INFINITY to 30)
+ to_chat(M, "Your body disperses from existence, as you become one with the universe.")
+ to_chat(M, "As your body disappears, your consciousness doesn't. Should you find a way back into the mortal coil, your memories of your previous life remain with you. (At the cost of staying in character while dead. Failure to do this may get you banned from this chem. You are still obligated to follow your directives if you play a midround antag, you do not remember the afterlife IC)")//Legalised IC OOK? I have a suspicion this won't make it past the review. At least it'll be presented as a neat idea! If this is unacceptable how about the player can retain living memories across lives if they die in this way only.
+ deadchat_broadcast("[M] has become one with the universe, meaning that their IC conciousness is continuous in a new life. If they find a way back to life, they are allowed to remember their previous life. Be careful what you say. If they abuse this, bwoink the FUCK outta them.")
+ M.visible_message("[M] suddenly disappears, their body evaporating from existence, freeing [M] from their mortal coil.")
+ message_admins("[M] (ckey: [M.ckey]) has become one with the universe, and have continuous memories thoughout their lives should they find a way to come back to life (such as an inteligence potion, midround antag, ghost role).")
+ SSblackbox.record_feedback("tally", "fermi_chem", 1, "Astral obliterations")
+ qdel(M) //Approx 60minutes till death from initial addiction
+ log_game("FERMICHEM: [M] ckey: [M.key] has been obliterated from Astrogen addiction")
+ ..()
diff --git a/modular_citadel/code/modules/reagents/chemistry/reagents/eigentstasium.dm b/modular_citadel/code/modules/reagents/chemistry/reagents/eigentstasium.dm
new file mode 100644
index 0000000000..bf915d5b6f
--- /dev/null
+++ b/modular_citadel/code/modules/reagents/chemistry/reagents/eigentstasium.dm
@@ -0,0 +1,203 @@
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// EIGENSTASIUM
+///////////////////////////////////////////////////////////////////////////////////////////////////
+//eigenstate Chem
+//Teleports you to chemistry and back
+//OD teleports you randomly around the Station
+//Addiction send you on a wild ride and replaces you with an alternative reality version of yourself.
+//During the process you get really hungry, then your items start teleporting randomly,
+//then alternative versions of yourself are brought in from a different universe and they yell at you.
+//and finally you yourself get teleported to an alternative universe, and character your playing is replaced with said alternative
+
+/datum/reagent/fermi/eigenstate
+ name = "Eigenstasium"
+ id = "eigenstate"
+ description = "A strange mixture formed from a controlled reaction of bluespace with plasma, that causes localised eigenstate fluxuations within the patient"
+ taste_description = "wiggly cosmic dust."
+ color = "#5020F4" // rgb: 50, 20, 255
+ overdose_threshold = 15
+ addiction_threshold = 15
+ metabolization_rate = 1.2 * REAGENTS_METABOLISM
+ addiction_stage2_end = 30
+ addiction_stage3_end = 41
+ addiction_stage4_end = 44 //Incase it's too long
+ data = list("location_created" = null)
+ var/turf/location_created
+ var/obj/effect/overlay/holo_pad_hologram/Eigenstate
+ var/turf/open/location_return = null
+ var/addictCyc3 = 0
+ var/mob/living/carbon/fermi_Tclone = null
+ var/teleBool = FALSE
+ pH = 3.7
+ can_synth = TRUE
+
+/datum/reagent/fermi/eigenstate/on_new(list/data)
+ location_created = data.["location_created"]
+
+//Main functions
+/datum/reagent/fermi/eigenstate/on_mob_life(mob/living/M) //Teleports to chemistry!
+ if(current_cycle == 0)
+ log_game("FERMICHEM: [M] ckey: [M.key] took eigenstasium")
+
+ //make hologram at return point
+ Eigenstate = new(loc)
+ Eigenstate.appearance = M.appearance
+ Eigenstate.alpha = 170
+ Eigenstate.add_atom_colour("#77abff", FIXED_COLOUR_PRIORITY)
+ Eigenstate.mouse_opacity = MOUSE_OPACITY_TRANSPARENT//So you can't click on it.
+ Eigenstate.layer = FLY_LAYER//Above all the other objects/mobs. Or the vast majority of them.
+ Eigenstate.setAnchored(TRUE)//So space wind cannot drag it.
+ Eigenstate.name = "[M]'s' eigenstate"//If someone decides to right click.
+ Eigenstate.set_light(2) //hologram lighting
+
+ location_return = get_turf(M) //sets up return point
+ to_chat(M, "You feel your wavefunction split!")
+ if(purity > 0.9) //Teleports you home if it's pure enough
+ if(!location_created && data) //Just in case
+ location_created = data.["location_created"]
+ log_game("FERMICHEM: [M] ckey: [M.key] returned to [location_created] using eigenstasium")
+ do_sparks(5,FALSE,M)
+ do_teleport(M, location_created, 0, asoundin = 'sound/effects/phasein.ogg')
+ do_sparks(5,FALSE,M)
+ SSblackbox.record_feedback("tally", "fermi_chem", 1, "Pure eigentstate jumps")
+
+
+ if(prob(20))
+ do_sparks(5,FALSE,M)
+ ..()
+
+/datum/reagent/fermi/eigenstate/on_mob_delete(mob/living/M) //returns back to original location
+ do_sparks(5,FALSE,M)
+ to_chat(M, "You feel your wavefunction collapse!")
+ do_teleport(M, location_return, 0, asoundin = 'sound/effects/phasein.ogg') //Teleports home
+ do_sparks(5,FALSE,M)
+ qdel(Eigenstate)
+ ..()
+
+/datum/reagent/fermi/eigenstate/overdose_start(mob/living/M) //Overdose, makes you teleport randomly
+ . = ..()
+ to_chat(M, "Oh god, you feel like your wavefunction is about to tear.")
+ log_game("FERMICHEM: [M] ckey: [M.key] has overdosed on eigenstasium")
+ M.Jitter(20)
+ metabolization_rate += 0.5 //So you're not stuck forever teleporting.
+
+/datum/reagent/fermi/eigenstate/overdose_process(mob/living/M) //Overdose, makes you teleport randomly, probably one of my favourite effects. Sometimes kills you.
+ do_sparks(5,FALSE,M)
+ do_teleport(M, get_turf(M), 10, asoundin = 'sound/effects/phasein.ogg')
+ do_sparks(5,FALSE,M)
+ ..()
+
+//Addiction
+/datum/reagent/fermi/eigenstate/addiction_act_stage1(mob/living/M) //Welcome to Fermis' wild ride.
+ if(addiction_stage == 1)
+ to_chat(M, "Your wavefunction feels like it's been ripped in half. You feel empty inside.")
+ log_game("FERMICHEM: [M] ckey: [M.key] has become addicted to eigenstasium")
+ M.Jitter(10)
+ M.nutrition = M.nutrition - (M.nutrition/15)
+ ..()
+
+/datum/reagent/fermi/eigenstate/addiction_act_stage2(mob/living/M)
+ if(addiction_stage == 11)
+ to_chat(M, "You start to convlse violently as you feel your consciousness split and merge across realities as your possessions fly wildy off your body.")
+ M.Jitter(200)
+ M.Knockdown(200)
+ M.Stun(80)
+ var/items = M.get_contents()
+ if(!LAZYLEN(items))
+ return ..()
+ var/obj/item/I = pick(items)
+ if(istype(I, /obj/item/implant))
+ qdel(I)
+ to_chat(M, "You feel your implant rip itself out of you, sent flying off to another dimention!")
+ else
+ M.dropItemToGround(I, TRUE)
+ do_sparks(5,FALSE,I)
+ do_teleport(I, get_turf(I), 5, no_effects=TRUE);
+ do_sparks(5,FALSE,I)
+ ..()
+
+/datum/reagent/fermi/eigenstate/addiction_act_stage3(mob/living/M)//Pulls multiple copies of the character from alternative realities while teleporting them around!
+ //Clone function - spawns a clone then deletes it - simulates multiple copies of the player teleporting in
+ switch(addictCyc3) //Loops 0 -> 1 -> 2 -> 1 -> 2 -> 1 ...ect.
+ if(0)
+ M.Jitter(100)
+ to_chat(M, "Your eigenstate starts to rip apart, causing a localised collapsed field as you're ripped from alternative universes, trapped around the densisty of the event horizon.")
+ if(1)
+ var/typepath = M.type
+ fermi_Tclone = new typepath(M.loc)
+ var/mob/living/carbon/C = fermi_Tclone
+ fermi_Tclone.appearance = M.appearance
+ C.real_name = M.real_name
+ M.visible_message("[M] collapses in from an alternative reality!")
+ do_teleport(C, get_turf(C), 2, no_effects=TRUE) //teleports clone so it's hard to find the real one!
+ do_sparks(5,FALSE,C)
+ C.emote("spin")
+ M.emote("spin")
+ M.emote("me",1,"flashes into reality suddenly, gasping as they gaze around in a bewildered and highly confused fashion!",TRUE)
+ C.emote("me",1,"[pick("says", "cries", "mewls", "giggles", "shouts", "screams", "gasps", "moans", "whispers", "announces")], \"[pick("Bugger me, whats all this then?", "Hot damn, where is this?", "sacre bleu! Ou suis-je?!", "Yee haw! This is one hell of a hootenanny!", "WHAT IS HAPPENING?!", "Picnic!", "Das ist nicht deutschland. Das ist nicht akzeptabel!!!", "I've come from the future to warn you to not take eigenstasium! Oh no! I'm too late!", "You fool! You took too much eigenstasium! You've doomed us all!", "What...what's with these teleports? It's like one of my Japanese animes...!", "Ik stond op het punt om mehki op tafel te zetten, en nu, waar ben ik?", "This must be the will of Stein's gate.", "Fermichem was a mistake", "This is one hell of a beepsky smash.", "Now neither of us will be virgins!")]\"")
+ if(2)
+ var/mob/living/carbon/C = fermi_Tclone
+ do_sparks(5,FALSE,C)
+ qdel(C) //Deletes CLONE, or at least I hope it is.
+ M.visible_message("[M] is snapped across to a different alternative reality!")
+ addictCyc3 = 0 //counter
+ fermi_Tclone = null
+ addictCyc3++
+ do_teleport(M, get_turf(M), 2, no_effects=TRUE) //Teleports player randomly
+ do_sparks(5,FALSE,M)
+ ..()
+
+/datum/reagent/fermi/eigenstate/addiction_act_stage4(mob/living/M) //Thanks for riding Fermis' wild ride. Mild jitter and player buggery.
+ if(addiction_stage == 42)
+ do_sparks(5,FALSE,M)
+ do_teleport(M, get_turf(M), 2, no_effects=TRUE) //teleports clone so it's hard to find the real one!
+ do_sparks(5,FALSE,M)
+ M.Sleeping(100, 0)
+ M.Jitter(50)
+ M.Knockdown(100)
+ to_chat(M, "You feel your eigenstate settle, snapping an alternative version of yourself into reality. All your previous memories are lost and replaced with the alternative version of yourself. This version of you feels more [pick("affectionate", "happy", "lusty", "radical", "shy", "ambitious", "frank", "voracious", "sensible", "witty")] than your previous self, sent to god knows what universe.")
+ M.emote("me",1,"flashes into reality suddenly, gasping as they gaze around in a bewildered and highly confused fashion!",TRUE)
+ log_game("FERMICHEM: [M] ckey: [M.key] has become an alternative universe version of themselves.")
+ M.reagents.remove_all_type(/datum/reagent, 100, 0, 1)
+ /*
+ for(var/datum/mood_event/Me in M)
+ SEND_SIGNAL(M, COMSIG_CLEAR_MOOD_EVENT, Me) //Why does this not work?
+ */
+ SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "Alternative dimension", /datum/mood_event/eigenstate)
+ SSblackbox.record_feedback("tally", "fermi_chem", 1, "Wild rides ridden")
+
+ if(prob(20))
+ do_sparks(5,FALSE,M)
+ SEND_SIGNAL(M, COMSIG_CLEAR_MOOD_EVENT, "[id]_overdose")//holdover until above fix works
+ ..()
+
+/datum/reagent/fermi/eigenstate/reaction_turf(turf/T, reac_volume)
+ //if(cached_purity < 0.99) To add with next batch of fixes and tweaks.
+ var/obj/structure/closet/First
+ var/obj/structure/closet/Previous
+ for(var/obj/structure/closet/C in T.contents)
+ if(C.eigen_teleport == TRUE)
+ C.visible_message("[C] fizzes, it's already linked to something else!")
+ continue
+ if(!Previous)
+ First = C
+ Previous = C
+ continue
+ C.eigen_teleport = TRUE
+ C.eigen_target = Previous
+ C.color = "#9999FF" //Tint the locker slightly.
+ C.alpha = 200
+ do_sparks(5,FALSE,C)
+ Previous = C
+ if(!First)
+ return
+ if(Previous == First)
+ return
+ First.eigen_teleport = TRUE
+ First.eigen_target = Previous
+ First.color = "#9999FF"
+ First.alpha = 200
+ do_sparks(5,FALSE,First)
+ First.visible_message("The lockers' eigenstates spilt and merge, linking each of their contents together.")
+
+//eigenstate END
diff --git a/modular_citadel/code/modules/reagents/chemistry/reagents/enlargement.dm b/modular_citadel/code/modules/reagents/chemistry/reagents/enlargement.dm
new file mode 100644
index 0000000000..d603f3ba10
--- /dev/null
+++ b/modular_citadel/code/modules/reagents/chemistry/reagents/enlargement.dm
@@ -0,0 +1,365 @@
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// BREAST ENLARGE
+///////////////////////////////////////////////////////////////////////////////////////////////////
+//Other files that are relivant:
+//modular_citadel/code/datums/status_effects/chems.dm
+//modular_citadel/code/modules/arousal/organs/breasts.dm
+
+//breast englargement
+//Honestly the most requested chems
+//I'm not a very kinky person, sorry if it's not great
+//I tried to make it interesting..!!
+
+//Normal function increases your breast size by 0.05, 10units = 1 cup.
+//If you get stupid big, it presses against your clothes, causing brute and oxydamage. Then rips them off.
+//If you keep going, it makes you slower, in speed and action.
+//decreasing your size will return you to normal.
+//(see the status effect in chem.dm)
+//Overdosing on (what is essentially space estrogen) makes you female, removes balls and shrinks your dick.
+//OD is low for a reason. I'd like fermichems to have low ODs, and dangerous ODs, and since this is a meme chem that everyone will rush to make, it'll be a lesson learnt early.
+
+/datum/reagent/fermi/breast_enlarger
+ name = "Succubus milk"
+ id = "breast_enlarger"
+ description = "A volatile collodial mixture derived from milk that encourages mammary production via a potent estrogen mix."
+ color = "#E60584" // rgb: 96, 0, 255
+ taste_description = "a milky ice cream like flavour."
+ overdose_threshold = 17
+ metabolization_rate = 0.25
+ ImpureChem = "BEsmaller" //If you make an inpure chem, it stalls growth
+ InverseChemVal = 0.35
+ InverseChem = "BEsmaller" //At really impure vols, it just becomes 100% inverse
+ can_synth = FALSE
+
+/datum/reagent/fermi/breast_enlarger/on_mob_add(mob/living/carbon/M)
+ . = ..()
+ if(!ishuman(M)) //The monkey clause
+ if(volume >= 15) //To prevent monkey breast farms
+ var/turf/T = get_turf(M)
+ var/obj/item/organ/genital/breasts/B = new /obj/item/organ/genital/breasts(T)
+ var/list/seen = viewers(8, T)
+ for(var/mob/S in seen)
+ to_chat(S, "A pair of breasts suddenly fly out of the [M]!")
+ //var/turf/T2 = pick(turf in view(5, M))
+ var/T2 = get_random_station_turf()
+ M.adjustBruteLoss(25)
+ M.Knockdown(50)
+ M.Stun(50)
+ B.throw_at(T2, 8, 1)
+ M.reagents.remove_reagent(id, volume)
+ return
+ log_game("FERMICHEM: [M] ckey: [M.key] has ingested Sucubus milk")
+ var/mob/living/carbon/human/H = M
+ H.genital_override = TRUE
+ var/obj/item/organ/genital/breasts/B = H.getorganslot("breasts")
+ if(!B)
+ H.emergent_genital_call()
+ return
+ if(!B.size == "huge")
+ var/sizeConv = list("a" = 1, "b" = 2, "c" = 3, "d" = 4, "e" = 5)
+ B.prev_size = B.size
+ B.cached_size = sizeConv[B.size]
+
+/datum/reagent/fermi/breast_enlarger/on_mob_life(mob/living/carbon/M) //Increases breast size
+ if(!ishuman(M))//Just in case
+ return..()
+
+ var/mob/living/carbon/human/H = M
+ var/obj/item/organ/genital/breasts/B = M.getorganslot("breasts")
+ if(!B) //If they don't have breasts, give them breasts.
+
+ //If they have Acute hepatic pharmacokinesis, then route processing though liver.
+ if(HAS_TRAIT(M, TRAIT_PHARMA))
+ var/obj/item/organ/liver/L = M.getorganslot("liver")
+ if(L)
+ L.swelling+= 0.05
+ return..()
+ else
+ M.adjustToxLoss(1)
+ return..()
+
+ //otherwise proceed as normal
+ var/obj/item/organ/genital/breasts/nB = new
+ nB.Insert(M)
+ if(nB)
+ if(M.dna.species.use_skintones && M.dna.features["genitals_use_skintone"])
+ nB.color = skintone2hex(H.skin_tone)
+ else if(M.dna.features["breasts_color"])
+ nB.color = "#[M.dna.features["breasts_color"]]"
+ else
+ nB.color = skintone2hex(H.skin_tone)
+ nB.size = "flat"
+ nB.cached_size = 0
+ nB.prev_size = 0
+ to_chat(M, "Your chest feels warm, tingling with newfound sensitivity.")
+ M.reagents.remove_reagent(id, 5)
+ B = nB
+ //If they have them, increase size. If size is comically big, limit movement and rip clothes.
+ B.cached_size = B.cached_size + 0.05
+ if (B.cached_size >= 8.5 && B.cached_size < 9)
+ if(H.w_uniform || H.wear_suit)
+ var/target = M.get_bodypart(BODY_ZONE_CHEST)
+ to_chat(M, "Your breasts begin to strain against your clothes tightly!")
+ M.adjustOxyLoss(5, 0)
+ M.apply_damage(1, BRUTE, target)
+ B.update()
+ ..()
+
+/datum/reagent/fermi/breast_enlarger/overdose_process(mob/living/carbon/M) //Turns you into a female if male and ODing, doesn't touch nonbinary and object genders.
+
+ //Acute hepatic pharmacokinesis.
+ if(HAS_TRAIT(M, TRAIT_PHARMA))
+ var/obj/item/organ/liver/L = M.getorganslot("liver")
+ L.swelling+= 0.05
+ return ..()
+
+ var/obj/item/organ/genital/penis/P = M.getorganslot("penis")
+ var/obj/item/organ/genital/testicles/T = M.getorganslot("testicles")
+ var/obj/item/organ/genital/vagina/V = M.getorganslot("vagina")
+ var/obj/item/organ/genital/womb/W = M.getorganslot("womb")
+
+ if(M.gender == MALE)
+ M.gender = FEMALE
+ M.visible_message("[M] suddenly looks more feminine!", "You suddenly feel more feminine!")
+
+ if(P)
+ P.cached_length = P.cached_length - 0.05
+ P.update()
+ if(T)
+ T.Remove(M)
+ if(!V)
+ var/obj/item/organ/genital/vagina/nV = new
+ nV.Insert(M)
+ V = nV
+ if(!W)
+ var/obj/item/organ/genital/womb/nW = new
+ nW.Insert(M)
+ W = nW
+ ..()
+
+/datum/reagent/fermi/BEsmaller
+ name = "Modesty milk"
+ id = "BEsmaller"
+ description = "A volatile collodial mixture derived from milk that encourages mammary reduction via a potent estrogen mix."
+ color = "#E60584" // rgb: 96, 0, 255
+ taste_description = "a milky ice cream like flavour."
+ metabolization_rate = 0.25
+ can_synth = FALSE
+
+/datum/reagent/fermi/BEsmaller/on_mob_life(mob/living/carbon/M)
+ var/obj/item/organ/genital/breasts/B = M.getorganslot("breasts")
+ if(!B)
+ //Acute hepatic pharmacokinesis.
+ if(HAS_TRAIT(M, TRAIT_PHARMA))
+ var/obj/item/organ/liver/L = M.getorganslot("liver")
+ L.swelling-= 0.05
+ return ..()
+
+ //otherwise proceed as normal
+ return..()
+ B.cached_size = B.cached_size - 0.05
+ B.update()
+ ..()
+
+/datum/reagent/fermi/BEsmaller_hypo
+ name = "Rectify milk" //Rectify
+ id = "BEsmaller_hypo"
+ color = "#E60584"
+ taste_description = "a milky ice cream like flavour."
+ metabolization_rate = 0.25
+ description = "A medicine used to treat organomegaly in a patient's breasts."
+ var/sizeConv = list("a" = 1, "b" = 2, "c" = 3, "d" = 4, "e" = 5)
+ can_synth = TRUE
+
+/datum/reagent/fermi/BEsmaller_hypo/on_mob_add(mob/living/carbon/M)
+ . = ..()
+ if(!M.getorganslot("vagina"))
+ if(M.dna.features["has_vag"])
+ var/obj/item/organ/genital/vagina/nV = new
+ nV.Insert(M)
+ if(!M.getorganslot("womb"))
+ if(M.dna.features["has_womb"])
+ var/obj/item/organ/genital/womb/nW = new
+ nW.Insert(M)
+
+/datum/reagent/fermi/BEsmaller_hypo/on_mob_life(mob/living/carbon/M)
+ var/obj/item/organ/genital/breasts/B = M.getorganslot("breasts")
+ if(!B)
+ return..()
+ if(!M.dna.features["has_breasts"])//Fast fix for those who don't want it.
+ B.cached_size = B.cached_size - 0.1
+ B.update()
+ else if(B.cached_size > (sizeConv[M.dna.features["breasts_size"]]+0.1))
+ B.cached_size = B.cached_size - 0.05
+ B.update()
+ else if(B.cached_size < (sizeConv[M.dna.features["breasts_size"]])+0.1)
+ B.cached_size = B.cached_size + 0.05
+ B.update()
+ ..()
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// PENIS ENLARGE
+///////////////////////////////////////////////////////////////////////////////////////////////////
+//See breast explanation, it's the same but with taliwhackers
+//instead of slower movement and attacks, it slows you and increases the total blood you need in your system.
+//Since someone else made this in the time it took me to PR it, I merged them.
+/datum/reagent/fermi/penis_enlarger // Due to popular demand...!
+ name = "Incubus draft"
+ id = "penis_enlarger"
+ description = "A volatile collodial mixture derived from various masculine solutions that encourages a larger gentleman's package via a potent testosterone mix, formula derived from a collaboration from Fermichem and Doctor Ronald Hyatt, who is well known for his phallus palace." //The toxic masculinity thing is a joke because I thought it would be funny to include it in the reagents, but I don't think many would find it funny? dumb
+ color = "#888888" // This is greyish..?
+ taste_description = "chinese dragon powder"
+ overdose_threshold = 17 //ODing makes you male and removes female genitals
+ metabolization_rate = 0.5
+ ImpureChem = "PEsmaller" //If you make an inpure chem, it stalls growth
+ InverseChemVal = 0.35
+ InverseChem = "PEsmaller" //At really impure vols, it just becomes 100% inverse and shrinks instead.
+ can_synth = FALSE
+
+/datum/reagent/fermi/penis_enlarger/on_mob_add(mob/living/carbon/M)
+ . = ..()
+ if(!ishuman(M)) //Just monkeying around.
+ if(volume >= 15) //to prevent monkey penis farms
+ var/turf/T = get_turf(M)
+ var/obj/item/organ/genital/penis/P = new /obj/item/organ/genital/penis(T)
+ var/list/seen = viewers(8, T)
+ for(var/mob/S in seen)
+ to_chat(S, "A penis suddenly flies out of the [M]!")
+ var/T2 = get_random_station_turf()
+ M.adjustBruteLoss(25)
+ M.Knockdown(50)
+ M.Stun(50)
+ P.throw_at(T2, 8, 1)
+ M.reagents.remove_reagent(id, volume)
+ return
+ var/mob/living/carbon/human/H = M
+ H.genital_override = TRUE
+ var/obj/item/organ/genital/penis/P = M.getorganslot("penis")
+ if(!P)
+ H.emergent_genital_call()
+ return
+ P.prev_length = P.length
+ P.cached_length = P.length
+
+/datum/reagent/fermi/penis_enlarger/on_mob_life(mob/living/carbon/M) //Increases penis size, 5u = +1 inch.
+ if(!ishuman(M))
+ return
+ var/mob/living/carbon/human/H = M
+ var/obj/item/organ/genital/penis/P = M.getorganslot("penis")
+ if(!P)//They do have a preponderance for escapism, or so I've heard.
+
+ //If they have Acute hepatic pharmacokinesis, then route processing though liver.
+ if(HAS_TRAIT(M, TRAIT_PHARMA))
+ var/obj/item/organ/liver/L = M.getorganslot("liver")
+ if(L)
+ L.swelling+= 0.05
+ return..()
+ else
+ M.adjustToxLoss(1)
+ return..()
+
+ //otherwise proceed as normal
+ var/obj/item/organ/genital/penis/nP = new
+ nP.Insert(M)
+ if(nP)
+ nP.length = 1
+ to_chat(M, "Your groin feels warm, as you feel a newly forming bulge down below.")
+ nP.cached_length = 1
+ nP.prev_length = 1
+ M.reagents.remove_reagent(id, 5)
+ P = nP
+
+ P.cached_length = P.cached_length + 0.1
+ if (P.cached_length >= 20.5 && P.cached_length < 21)
+ if(H.w_uniform || H.wear_suit)
+ var/target = M.get_bodypart(BODY_ZONE_CHEST)
+ to_chat(M, "Your cock begin to strain against your clothes tightly!")
+ M.apply_damage(2.5, BRUTE, target)
+
+ P.update()
+ ..()
+
+/datum/reagent/fermi/penis_enlarger/overdose_process(mob/living/carbon/M) //Turns you into a male if female and ODing, doesn't touch nonbinary and object genders.
+ //Acute hepatic pharmacokinesis.
+ if(HAS_TRAIT(M, TRAIT_PHARMA))
+ var/obj/item/organ/liver/L = M.getorganslot("liver")
+ L.swelling+= 0.05
+ return..()
+
+ var/obj/item/organ/genital/breasts/B = M.getorganslot("breasts")
+ var/obj/item/organ/genital/testicles/T = M.getorganslot("testicles")
+ var/obj/item/organ/genital/vagina/V = M.getorganslot("vagina")
+ var/obj/item/organ/genital/womb/W = M.getorganslot("womb")
+
+ if(M.gender == FEMALE)
+ M.gender = MALE
+ M.visible_message("[M] suddenly looks more masculine!", "You suddenly feel more masculine!")
+
+ if(B)
+ B.cached_size = B.cached_size - 0.05
+ B.update()
+ if(V)
+ V.Remove(M)
+ if(W)
+ W.Remove(M)
+ if(!T)
+ var/obj/item/organ/genital/testicles/nT = new
+ nT.Insert(M)
+ T = nT
+ ..()
+
+/datum/reagent/fermi/PEsmaller // Due to cozmo's request...!
+ name = "Chastity draft"
+ id = "PEsmaller"
+ description = "A volatile collodial mixture derived from various masculine solutions that encourages a smaller gentleman's package via a potent testosterone mix, formula derived from a collaboration from Fermichem and Doctor Ronald Hyatt, who is well known for his phallus palace."
+ color = "#888888" // This is greyish..?
+ taste_description = "chinese dragon powder"
+ metabolization_rate = 0.5
+ can_synth = FALSE
+
+/datum/reagent/fermi/PEsmaller/on_mob_life(mob/living/carbon/M)
+ var/mob/living/carbon/human/H = M
+ var/obj/item/organ/genital/penis/P = H.getorganslot("penis")
+ if(!P)
+ //Acute hepatic pharmacokinesis.
+ if(HAS_TRAIT(M, TRAIT_PHARMA))
+ var/obj/item/organ/liver/L = M.getorganslot("liver")
+ L.swelling-= 0.05
+ return..()
+
+ //otherwise proceed as normal
+ return..()
+ P.cached_length = P.cached_length - 0.1
+ P.update()
+ ..()
+
+/datum/reagent/fermi/PEsmaller_hypo
+ name = "Rectify draft"
+ id = "PEsmaller_hypo"
+ color = "#888888" // This is greyish..?
+ taste_description = "chinese dragon powder"
+ description = "A medicine used to treat organomegaly in a patient's penis."
+ metabolization_rate = 0.5
+ can_synth = TRUE
+
+/datum/reagent/fermi/PEsmaller_hypo/on_mob_add(mob/living/carbon/M)
+ . = ..()
+ if(!M.getorganslot("testicles"))
+ if(M.dna.features["has_balls"])
+ var/obj/item/organ/genital/testicles/nT = new
+ nT.Insert(M)
+
+/datum/reagent/fermi/PEsmaller_hypo/on_mob_life(mob/living/carbon/M)
+ var/obj/item/organ/genital/penis/P = M.getorganslot("penis")
+ if(!P)
+ return ..()
+ if(!M.dna.features["has_cock"])//Fast fix for those who don't want it.
+ P.cached_length = P.cached_length - 0.2
+ P.update()
+ else if(P.cached_length > (M.dna.features["cock_length"]+0.1))
+ P.cached_length = P.cached_length - 0.1
+ P.update()
+ else if(P.cached_length < (M.dna.features["cock_length"]+0.1))
+ P.cached_length = P.cached_length + 0.1
+ P.update()
+ ..()
diff --git a/modular_citadel/code/modules/reagents/chemistry/reagents/fermi_reagents.dm b/modular_citadel/code/modules/reagents/chemistry/reagents/fermi_reagents.dm
new file mode 100644
index 0000000000..275c244a83
--- /dev/null
+++ b/modular_citadel/code/modules/reagents/chemistry/reagents/fermi_reagents.dm
@@ -0,0 +1,462 @@
+ //Fermichem!!
+//Fun chems for all the family
+
+/datum/reagent/fermi
+ name = "Fermi" //This should never exist, but it does so that it can exist in the case of errors..
+ id = "fermi"
+ taste_description = "affection and love!"
+ can_synth = FALSE
+
+//This should process fermichems to find out how pure they are and what effect to do.
+/datum/reagent/fermi/on_mob_add(mob/living/carbon/M, amount)
+ . = ..()
+ if(!M)
+ return
+ if(purity < 0)
+ CRASH("Purity below 0 for chem: [id], Please let Fermis Know!")
+ if (purity == 1 || DoNotSplit == TRUE)
+ log_game("FERMICHEM: [M] ckey: [M.key] has ingested [volume]u of [id]")
+ return
+ else if (InverseChemVal > purity)//Turns all of a added reagent into the inverse chem
+ M.reagents.remove_reagent(id, amount, FALSE)
+ M.reagents.add_reagent(InverseChem, amount, FALSE, other_purity = 1)
+ log_game("FERMICHEM: [M] ckey: [M.key] has ingested [volume]u of [InverseChem]")
+ return
+ else
+ var/impureVol = amount * (1 - purity) //turns impure ratio into impure chem
+ M.reagents.remove_reagent(id, (impureVol), FALSE)
+ M.reagents.add_reagent(ImpureChem, impureVol, FALSE, other_purity = 1)
+ log_game("FERMICHEM: [M] ckey: [M.key] has ingested [volume - impureVol]u of [id]")
+ log_game("FERMICHEM: [M] ckey: [M.key] has ingested [volume]u of [ImpureChem]")
+ return
+
+//When merging two fermichems, see above
+/datum/reagent/fermi/on_merge(data, amount, mob/living/carbon/M, purity)//basically on_mob_add but for merging
+ . = ..()
+ if(!ishuman(M))
+ return
+ if (purity < 0)
+ CRASH("Purity below 0 for chem: [id], Please let Fermis Know!")
+ if (purity == 1 || DoNotSplit == TRUE)
+ log_game("FERMICHEM: [M] ckey: [M.key] has merged [volume]u of [id] in themselves")
+ return
+ else if (InverseChemVal > purity)
+ M.reagents.remove_reagent(id, amount, FALSE)
+ M.reagents.add_reagent(InverseChem, amount, FALSE, other_purity = 1)
+ for(var/datum/reagent/fermi/R in M.reagents.reagent_list)
+ if(R.name == "")
+ R.name = name//Negative effects are hidden
+ log_game("FERMICHEM: [M] ckey: [M.key] has merged [volume]u of [InverseChem]")
+ return
+ else
+ var/impureVol = amount * (1 - purity)
+ M.reagents.remove_reagent(id, impureVol, FALSE)
+ M.reagents.add_reagent(ImpureChem, impureVol, FALSE, other_purity = 1)
+ for(var/datum/reagent/fermi/R in M.reagents.reagent_list)
+ if(R.name == "")
+ R.name = name//Negative effects are hidden
+ log_game("FERMICHEM: [M] ckey: [M.key] has merged [volume - impureVol]u of [id]")
+ log_game("FERMICHEM: [M] ckey: [M.key] has merged [volume]u of [ImpureChem]")
+ return
+
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// HATIMUIM
+///////////////////////////////////////////////////////////////////////////////////////////////////
+//Adds a heat upon your head, and tips their hat
+//Also has a speech alteration effect when the hat is there
+//Increase armour; 1 armour per 10u
+//but if you OD it becomes negative.
+
+
+/datum/reagent/fermi/hatmium //for hatterhat
+ name = "Hat growth serium"
+ id = "hatmium"
+ description = "A strange substance that draws in a hat from the hat dimention."
+ color = "#7c311a" // rgb: , 0, 255
+ taste_description = "like jerky, whiskey and an off aftertaste of a crypt."
+ metabolization_rate = 0.2
+ overdose_threshold = 25
+ DoNotSplit = TRUE
+ pH = 4
+ can_synth = TRUE
+
+
+/datum/reagent/fermi/hatmium/on_mob_add(mob/living/carbon/human/M)
+ . = ..()
+ if(M.head)
+ var/obj/item/W = M.head
+ if(istype(W, /obj/item/clothing/head/hattip))
+ qdel(W)
+ else
+ M.dropItemToGround(W, TRUE)
+ var/hat = new /obj/item/clothing/head/hattip()
+ M.equip_to_slot(hat, SLOT_HEAD, 1, 1)
+
+
+/datum/reagent/fermi/hatmium/on_mob_life(mob/living/carbon/human/M)
+ if(!istype(M.head, /obj/item/clothing/head/hattip))
+ return ..()
+ var/hatArmor = 0
+ if(!overdosed)
+ hatArmor = (purity/10)
+ else
+ hatArmor = - (purity/10)
+ if(hatArmor > 90)
+ return ..()
+ var/obj/item/W = M.head
+ W.armor = W.armor.modifyAllRatings(hatArmor)
+ ..()
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// FURRANIUM
+///////////////////////////////////////////////////////////////////////////////////////////////////
+//OwO whats this?
+//Makes you nya and awoo
+//At a certain amount of time in your system it gives you a fluffy tongue, if pure enough, it's permanent.
+
+/datum/reagent/fermi/furranium
+ name = "Furranium"
+ id = "furranium"
+ description = "OwO whats this?"
+ color = "#f9b9bc" // rgb: , 0, 255
+ taste_description = "dewicious degenyewacy"
+ metabolization_rate = 0.5 * REAGENTS_METABOLISM
+ InverseChemVal = 0
+ var/obj/item/organ/tongue/nT
+ DoNotSplit = TRUE
+ pH = 5
+ var/obj/item/organ/tongue/T
+ can_synth = TRUE
+
+/datum/reagent/fermi/furranium/reaction_mob(mob/living/carbon/human/M, method=INJECT, reac_volume)
+ if(method == INJECT)
+ var/turf/T = get_turf(M)
+ M.adjustOxyLoss(15)
+ M.Knockdown(50)
+ M.Stun(50)
+ M.emote("cough")
+ var/obj/item/toy/plush/P = pick(subtypesof(/obj/item/toy/plush))
+ new P(T)
+ to_chat(M, "You feel a lump form in your throat, as you suddenly cough up what seems to be a hairball?")
+ var/list/seen = viewers(8, T)
+ for(var/mob/S in seen)
+ to_chat(S, "[M] suddenly coughs up a [P.name]!")
+ var/T2 = get_random_station_turf()
+ P.throw_at(T2, 8, 1)
+ ..()
+
+/datum/reagent/fermi/furranium/on_mob_life(mob/living/carbon/M)
+
+ switch(current_cycle)
+ if(1 to 9)
+ if(prob(20))
+ to_chat(M, "Your tongue feels... fluffy")
+ if(10 to 15)
+ if(prob(10))
+ to_chat(M, "You find yourself unable to supress the desire to meow!")
+ M.emote("nya")
+ if(prob(10))
+ to_chat(M, "You find yourself unable to supress the desire to howl!")
+ M.emote("awoo")
+ if(prob(20))
+ var/list/seen = viewers(5, get_turf(M))//Sound and sight checkers
+ for(var/victim in seen)
+ if((istype(victim, /mob/living/simple_animal/pet/)) || (victim == M) || (!isliving(victim)))
+ seen = seen - victim
+ if(LAZYLEN(seen))
+ to_chat(M, "You notice [pick(seen)]'s bulge [pick("OwO!", "uwu!")]")
+ if(16)
+ T = M.getorganslot(ORGAN_SLOT_TONGUE)
+ var/obj/item/organ/tongue/nT = new /obj/item/organ/tongue/fluffy
+ T.Remove(M)
+ nT.Insert(M)
+ T.moveToNullspace()//To valhalla
+ to_chat(M, "Your tongue feels... weally fwuffy!!")
+ if(17 to INFINITY)
+ if(prob(5))
+ to_chat(M, "You find yourself unable to supress the desire to meow!")
+ M.emote("nya")
+ if(prob(5))
+ to_chat(M, "You find yourself unable to supress the desire to howl!")
+ M.emote("awoo")
+ if(prob(5))
+ var/list/seen = viewers(5, get_turf(M))//Sound and sight checkers
+ for(var/victim in seen)
+ if((istype(victim, /mob/living/simple_animal/pet/)) || (victim == M) || (!isliving(victim)))
+ seen = seen - victim
+ if(LAZYLEN(seen))
+ to_chat(M, "You notice [pick(seen)]'s bulge [pick("OwO!", "uwu!")]")
+ ..()
+
+/datum/reagent/fermi/furranium/on_mob_delete(mob/living/carbon/M)
+ if(purity < 1)//Only permanent if you're a good chemist.
+ nT = M.getorganslot(ORGAN_SLOT_TONGUE)
+ nT.Remove(M)
+ qdel(nT)
+ T.Insert(M)
+ to_chat(M, "You feel your tongue.... unfluffify...?")
+ M.say("Pleh!")
+ else
+ log_game("FERMICHEM: [M] ckey: [M.key]'s tongue has been made permanent")
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////
+//Nanite removal
+//Writen by Trilby!! Embellsished a little by me.
+
+/datum/reagent/fermi/nanite_b_gone
+ name = "Naninte bane"
+ id = "nanite_b_gone"
+ description = "A stablised EMP that is highly volatile, shocking small nano machines that will kill them off at a rapid rate in a patient's system."
+ color = "#708f8f"
+ overdose_threshold = 15
+ ImpureChem = "nanite_b_goneTox" //If you make an inpure chem, it stalls growth
+ InverseChemVal = 0.25
+ InverseChem = "nanite_b_goneTox" //At really impure vols, it just becomes 100% inverse
+ taste_description = "what can only be described as licking a battery."
+ pH = 9
+ can_synth = FALSE
+
+/datum/reagent/fermi/nanite_b_gone/on_mob_life(mob/living/carbon/C)
+ //var/component/nanites/N = M.GetComponent(/datum/component/nanites)
+ GET_COMPONENT_FROM(N, /datum/component/nanites, C)
+ if(isnull(N))
+ return ..()
+ N.nanite_volume = -purity//0.5 seems to be the default to me, so it'll neuter them.
+ ..()
+
+/datum/reagent/fermi/nanite_b_gone/overdose_process(mob/living/carbon/C)
+ //var/component/nanites/N = M.GetComponent(/datum/component/nanites)
+ GET_COMPONENT_FROM(N, /datum/component/nanites, C)
+ if(prob(5))
+ to_chat(C, "The residual voltage from the nanites causes you to seize up!")
+ C.electrocute_act(10, (get_turf(C)), 1, FALSE, FALSE, FALSE, TRUE)
+ if(prob(10))
+ //empulse((get_turf(C)), 3, 2)//So the nanites randomize
+ var/atom/T = C
+ T.emp_act(EMP_HEAVY)
+ to_chat(C, "The nanites short circuit within your system!")
+ if(isnull(N))
+ return ..()
+ N.nanite_volume = -2
+ ..()
+
+/datum/reagent/fermi/nanite_b_gone/reaction_obj(obj/O, reac_volume)
+ O.emp_act(EMP_HEAVY)
+
+/datum/reagent/fermi/nanite_b_goneTox
+ name = "Naninte bain"
+ id = "nanite_b_goneTox"
+ description = "Poorly made, and shocks you!"
+ metabolization_rate = 1
+
+//Increases shock events.
+/datum/reagent/fermi/nanite_b_goneTox/on_mob_life(mob/living/carbon/C)//Damages the taker if their purity is low. Extended use of impure chemicals will make the original die. (thus can't be spammed unless you've very good)
+ if(prob(15))
+ to_chat(C, "The residual voltage in your system causes you to seize up!")
+ C.electrocute_act(10, (get_turf(C)), 1, FALSE, FALSE, FALSE, TRUE)
+ if(prob(50))
+ var/atom/T = C
+ T.emp_act(EMP_HEAVY)
+ to_chat(C, "You feel your hair stand on end as you glow brightly for a moment!")
+ ..()
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////
+// MISC FERMICHEM CHEMS FOR SPECIFIC INTERACTIONS ONLY
+///////////////////////////////////////////////////////////////////////////////////////////////
+
+/datum/reagent/fermi/fermiAcid
+ name = "Acid vapour"
+ id = "fermiAcid"
+ description = "Someone didn't do like an otter, and add acid to water."
+ taste_description = "acid burns, ow"
+ color = "#FFFFFF"
+ pH = 0
+ can_synth = FALSE
+
+/datum/reagent/fermi/fermiAcid/reaction_mob(mob/living/carbon/C, method)
+ var/target = C.get_bodypart(BODY_ZONE_CHEST)
+ var/acidstr
+ if(!C.reagents.pH || C.reagents.pH >5)
+ acidstr = 3
+ else
+ acidstr = ((5-C.reagents.pH)*2) //runtime - null.pH ?
+ C.adjustFireLoss(acidstr/2, 0)
+ if((method==VAPOR) && (!C.wear_mask))
+ if(prob(20))
+ to_chat(C, "You can feel your lungs burning!")
+ var/obj/item/organ/lungs/L = C.getorganslot(ORGAN_SLOT_LUNGS)
+ L.adjustLungLoss(acidstr*2, C)
+ C.apply_damage(acidstr/5, BURN, target)
+ C.acid_act(acidstr, volume)
+ ..()
+
+/datum/reagent/fermi/fermiAcid/reaction_obj(obj/O, reac_volume)
+ if(ismob(O.loc)) //handled in human acid_act()
+ return
+ if((holder.pH > 5) || (volume < 0.1)) //Shouldn't happen, but just in case
+ return
+ reac_volume = round(volume,0.1)
+ var/acidstr = (5-holder.pH)*2 //(max is 10)
+ O.acid_act(acidstr, volume)
+ ..()
+
+/datum/reagent/fermi/fermiAcid/reaction_turf(turf/T, reac_volume)
+ if (!istype(T))
+ return
+ reac_volume = round(volume,0.1)
+ var/acidstr = (5-holder.pH)
+ T.acid_act(acidstr, volume)
+ ..()
+
+/datum/reagent/fermi/fermiTest
+ name = "Fermis Test Reagent"
+ id = "fermiTest"
+ description = "You should be really careful with this...! Also, how did you get this?"
+ addProc = TRUE
+ can_synth = FALSE
+
+/datum/reagent/fermi/fermiTest/on_new(datum/reagents/holder)
+ ..()
+ if(LAZYLEN(holder.reagent_list) == 1)
+ return
+ else
+ holder.remove_reagent("fermiTest", volume)//Avoiding recurrsion
+ var/location = get_turf(holder.my_atom)
+ if(purity < 0.34 || purity == 1)
+ var/datum/effect_system/foam_spread/s = new()
+ s.set_up(volume*2, location, holder)
+ s.start()
+ if((purity < 0.67 && purity >= 0.34)|| purity == 1)
+ var/datum/effect_system/smoke_spread/chem/s = new()
+ s.set_up(holder, volume*2, location)
+ s.start()
+ if(purity >= 0.67)
+ for (var/datum/reagent/reagent in holder.reagent_list)
+ if (istype(reagent, /datum/reagent/fermi))
+ var/datum/chemical_reaction/fermi/Ferm = GLOB.chemical_reagents_list[reagent.id]
+ Ferm.FermiExplode(src, holder.my_atom, holder, holder.total_volume, holder.chem_temp, holder.pH)
+ else
+ var/datum/chemical_reaction/Ferm = GLOB.chemical_reagents_list[reagent.id]
+ Ferm.on_reaction(holder, reagent.volume)
+ for(var/mob/M in viewers(8, location))
+ to_chat(M, "The solution reacts dramatically, with a meow!")
+ playsound(get_turf(M), 'modular_citadel/sound/voice/merowr.ogg', 50, 1)
+ holder.clear_reagents()
+
+/datum/reagent/fermi/fermiTox
+ name = "FermiTox"
+ id = "fermiTox"
+ description = "You should be really careful with this...! Also, how did you get this? You shouldn't have this!"
+ data = "merge"
+ color = "FFFFFF"
+ can_synth = FALSE
+
+//I'm concerned this is too weak, but I also don't want deathmixes.
+/datum/reagent/fermi/fermiTox/on_mob_life(mob/living/carbon/C, method)
+ if(C.dna && istype(C.dna.species, /datum/species/jelly))
+ C.adjustToxLoss(-2)
+ else
+ C.adjustToxLoss(2)
+ ..()
+
+/datum/reagent/fermi/acidic_buffer
+ name = "Acidic buffer"
+ id = "acidic_buffer"
+ description = "This reagent will consume itself and move the pH of a beaker towards acidity when added to another."
+ color = "#fbc314"
+ pH = 0
+ can_synth = TRUE
+
+//Consumes self on addition and shifts pH
+/datum/reagent/fermi/acidic_buffer/on_new(datapH)
+ data = datapH
+ if(LAZYLEN(holder.reagent_list) == 1)
+ return
+ holder.pH = ((holder.pH * holder.total_volume)+(pH * (volume)))/(holder.total_volume + (volume))
+ var/list/seen = viewers(5, get_turf(holder))
+ for(var/mob/M in seen)
+ to_chat(M, "The beaker fizzes as the pH changes!")
+ playsound(get_turf(holder.my_atom), 'sound/FermiChem/bufferadd.ogg', 50, 1)
+ holder.remove_reagent(id, volume, ignore_pH = TRUE)
+ ..()
+
+/datum/reagent/fermi/basic_buffer
+ name = "Basic buffer"
+ id = "basic_buffer"
+ description = "This reagent will consume itself and move the pH of a beaker towards alkalinity when added to another."
+ color = "#3853a4"
+ pH = 14
+ can_synth = TRUE
+
+/datum/reagent/fermi/basic_buffer/on_new(datapH)
+ data = datapH
+ if(LAZYLEN(holder.reagent_list) == 1)
+ return
+ holder.pH = ((holder.pH * holder.total_volume)+(pH * (volume)))/(holder.total_volume + (volume))
+ var/list/seen = viewers(5, get_turf(holder))
+ for(var/mob/M in seen)
+ to_chat(M, "The beaker froths as the pH changes!")
+ playsound(get_turf(holder.my_atom), 'sound/FermiChem/bufferadd.ogg', 50, 1)
+ holder.remove_reagent(id, volume, ignore_pH = TRUE)
+ ..()
+
+//Turns you into a cute catto while it's in your system.
+//If you manage to gamble perfectly, makes you have cat ears after you transform back. But really, you shouldn't end up with that with how random it is.
+/datum/reagent/fermi/secretcatchem //Should I hide this from code divers? A secret cit chem?
+ name = "secretcatchem" //an attempt at hiding it
+ id = "secretcatchem"
+ description = "An illegal and hidden chem that turns people into cats. It's said that it's so rare and unstable that having it means you've been blessed."
+ taste_description = "hairballs and cream"
+ color = "#ffc224"
+ var/catshift = FALSE
+ var/mob/living/simple_animal/pet/cat/custom_cat/catto = null
+ can_synth = FALSE
+
+/datum/reagent/fermi/secretcatchem/New()
+ name = "Catbalti[pick("a","u","e","y")]m [pick("apex", "prime", "meow")]"//rename
+
+/datum/reagent/fermi/secretcatchem/on_mob_add(mob/living/carbon/human/H)
+ . = ..()
+ if(purity >= 0.8)//ONLY if purity is high, and given the stuff is random. It's very unlikely to get this to 1. It already requires felind too, so no new functionality there.
+ //exception(al) handler:
+ H.dna.features["ears"] = "Cat"
+ H.dna.features["mam_ears"] = "Cat"
+ H.verb_say = "mewls"
+ catshift = TRUE
+ playsound(get_turf(H), 'modular_citadel/sound/voice/merowr.ogg', 50, 1, -1)
+ to_chat(H, "You suddenly turn into a cat!")
+ catto = new(get_turf(H.loc))
+ H.mind.transfer_to(catto)
+ catto.name = H.name
+ catto.desc = "A cute catto! They remind you of [H] somehow."
+ catto.color = "#[H.dna.features["mcolor"]]"
+ catto.pseudo_death = TRUE
+ H.forceMove(catto)
+ log_game("FERMICHEM: [H] ckey: [H.key] has been made into a cute catto.")
+ SSblackbox.record_feedback("tally", "fermi_chem", 1, "cats")
+ //Just to deal with rascally ghosts
+ //ADD_TRAIT(catto, TRAIT_NODEATH, "catto")//doesn't work
+ //catto.health = 1000 //To simulate fake death, while preventing ghosts escaping.
+
+/datum/reagent/fermi/secretcatchem/on_mob_life(mob/living/carbon/H)
+ if(catto.health <= 0) //So the dead can't ghost
+ if(prob(10))
+ to_chat(H, "You feel your body start to slowly shift back from it's dead form.")
+ else if(prob(5))
+ playsound(get_turf(catto), 'modular_citadel/sound/voice/merowr.ogg', 50, 1, -1)
+ catto.say("lets out a meowrowr!*")
+ ..()
+
+/datum/reagent/fermi/secretcatchem/on_mob_delete(mob/living/carbon/H)
+ var/words = "Your body shifts back to normal."
+ H.forceMove(catto.loc)
+ catto.mind.transfer_to(H)
+ if(catshift == TRUE)
+ words += " ...But wait, are those cat ears?"
+ H.say("*wag")//force update sprites.
+ to_chat(H, "[words]")
+ qdel(catto)
+ log_game("FERMICHEM: [H] ckey: [H.key] has returned to normal")
diff --git a/modular_citadel/code/modules/reagents/chemistry/reagents/healing.dm b/modular_citadel/code/modules/reagents/chemistry/reagents/healing.dm
new file mode 100644
index 0000000000..b717948a20
--- /dev/null
+++ b/modular_citadel/code/modules/reagents/chemistry/reagents/healing.dm
@@ -0,0 +1,95 @@
+/datum/reagent/fermi/yamerol
+ name = "Yamerol"
+ id = "yamerol"
+ description = "For when you've trouble speaking or breathing, just yell YAMEROL! A chem that helps soothe any congestion problems and at high concentrations restores damaged lungs and tongues!"
+ taste_description = "a weird, syrupy flavour, yamero"
+ color = "#68e83a"
+ pH = 8.6
+ overdose_threshold = 35
+ ImpureChem = "yamerol_tox"
+ InverseChemVal = 0.4
+ InverseChem = "yamerol_tox"
+ can_synth = TRUE
+
+/datum/reagent/fermi/yamerol/on_mob_life(mob/living/carbon/C)
+ var/obj/item/organ/tongue/T = C.getorganslot(ORGAN_SLOT_TONGUE)
+ var/obj/item/organ/lungs/L = C.getorganslot(ORGAN_SLOT_LUNGS)
+
+ if(T)
+ T.adjustTongueLoss(C, -2)//Fix the inputs me!
+ if(L)
+ L.adjustLungLoss(-5, C)
+ C.adjustOxyLoss(-2)
+ else
+ C.adjustOxyLoss(-10)
+
+ if(T)
+ if(T.name == "fluffy tongue")
+ var/obj/item/organ/tongue/nT
+ if(C.dna && C.dna.species && C.dna.species.mutanttongue)
+ nT = new C.dna.species.mutanttongue()
+ else
+ nT = new()
+ T.Remove(C)
+ qdel(T)
+ nT.Insert(C)
+ to_chat(C, "You feel your tongue.... unfluffify...?")
+ holder.remove_reagent(src.id, "10")
+ ..()
+
+/datum/reagent/fermi/yamerol/overdose_process(mob/living/carbon/C)
+ var/obj/item/organ/tongue/oT = C.getorganslot(ORGAN_SLOT_TONGUE)
+ if(current_cycle == 1)
+ to_chat(C, "You feel the Yamerol sooth your tongue and lungs.")
+ if(current_cycle > 10)
+ if(!C.getorganslot(ORGAN_SLOT_TONGUE))
+ var/obj/item/organ/tongue/T
+ if(C.dna && C.dna.species && C.dna.species.mutanttongue)
+ T = new C.dna.species.mutanttongue()
+ else
+ T = new()
+ T.Insert(C)
+ to_chat(C, "You feel your tongue reform in your mouth.")
+ holder.remove_reagent(src.id, "10")
+ else
+ if((oT.name == "fluffy tongue") && (purity == 1))
+ var/obj/item/organ/tongue/T
+ if(C.dna && C.dna.species && C.dna.species.mutanttongue)
+ T = new C.dna.species.mutanttongue()
+ else
+ T = new()
+ oT.Remove(C)
+ qdel(oT)
+ T.Insert(C)
+ to_chat(C, "You feel your tongue.... unfluffify...?")
+ holder.remove_reagent(src.id, "10")
+
+ if(!C.getorganslot(ORGAN_SLOT_LUNGS))
+ var/obj/item/organ/lungs/L = new()
+ L.Insert(C)
+ to_chat(C, "You feel your lungs reform in your chest.")
+ holder.remove_reagent(src.id, "10")
+
+ C.adjustOxyLoss(-3)
+ ..()
+
+/datum/reagent/fermi/yamerol_tox
+ name = "Yamerol"
+ id = "yamerol_tox"
+ description = "For when you've trouble speaking or breathing, just yell YAMEROL! A chem that helps soothe any congestion problems and at high concentrations restores damaged lungs and tongues!"
+ taste_description = "a weird, syrupy flavour, yamero"
+ color = "#68e83a"
+ pH = 8.6
+
+/datum/reagent/fermi/yamerol_tox/on_mob_life(mob/living/carbon/C)
+ var/obj/item/organ/tongue/T = C.getorganslot(ORGAN_SLOT_TONGUE)
+ var/obj/item/organ/lungs/L = C.getorganslot(ORGAN_SLOT_LUNGS)
+
+ if(T)
+ T.adjustTongueLoss(C, 1)
+ if(L)
+ L.adjustLungLoss(4, C)
+ C.adjustOxyLoss(3)
+ else
+ C.adjustOxyLoss(10)
+ ..()
diff --git a/modular_citadel/code/modules/reagents/chemistry/recipes/FermiCalc.Py b/modular_citadel/code/modules/reagents/chemistry/recipes/FermiCalc.Py
new file mode 100644
index 0000000000..9ffc057743
--- /dev/null
+++ b/modular_citadel/code/modules/reagents/chemistry/recipes/FermiCalc.Py
@@ -0,0 +1,11 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Fri May 17 05:12:17 2019
+
+@author: Fermi
+"""
+
+import numpy
+import matplotlib as mpl
+import matplotlib.pyplot as plt
+
diff --git a/modular_citadel/code/modules/reagents/chemistry/recipes/fermi.dm b/modular_citadel/code/modules/reagents/chemistry/recipes/fermi.dm
new file mode 100644
index 0000000000..078e1c8a71
--- /dev/null
+++ b/modular_citadel/code/modules/reagents/chemistry/recipes/fermi.dm
@@ -0,0 +1,541 @@
+/datum/chemical_reaction/fermi
+ mix_sound = 'sound/effects/bubbles.ogg'
+
+//Called for every reaction step
+/datum/chemical_reaction/fermi/proc/FermiCreate(holder)
+ return
+
+//Called when reaction STOP_PROCESSING
+/datum/chemical_reaction/fermi/proc/FermiFinish(datum/reagents/holder)
+ return
+
+//Called when temperature is above a certain threshold, or if purity is too low.
+/datum/chemical_reaction/fermi/proc/FermiExplode(datum/reagents, var/atom/my_atom, volume, temp, pH, Exploding = FALSE)
+ if (Exploding == TRUE)
+ return
+
+ if(!pH)//Dunno how things got here without a pH, but just in case
+ pH = 7
+ var/ImpureTot = 0
+ var/turf/T = get_turf(my_atom)
+
+ if(temp>500)//if hot, start a fire
+ switch(temp)
+ if (500 to 750)
+ for(var/turf/turf in range(1,T))
+ new /obj/effect/hotspot(turf)
+
+ if (751 to 1100)
+ for(var/turf/turf in range(2,T))
+ new /obj/effect/hotspot(turf)
+
+ if (1101 to 1500) //If you're crafty
+ for(var/turf/turf in range(3,T))
+ new /obj/effect/hotspot(turf)
+
+ if (1501 to 2500) //requested
+ for(var/turf/turf in range(4,T))
+ new /obj/effect/hotspot(turf)
+
+ if (2501 to 5000)
+ for(var/turf/turf in range(5,T))
+ new /obj/effect/hotspot(turf)
+
+ if (5001 to INFINITY)
+ for(var/turf/turf in range(6,T))
+ new /obj/effect/hotspot(turf)
+
+
+ message_admins("Fermi explosion at [T], with a temperature of [temp], pH of [pH], Impurity tot of [ImpureTot].")
+ log_game("Fermi explosion at [T], with a temperature of [temp], pH of [pH], Impurity tot of [ImpureTot].")
+ var/datum/reagents/R = new/datum/reagents(3000)//Hey, just in case.
+ var/datum/effect_system/smoke_spread/chem/s = new()
+ R.my_atom = my_atom //Give the gas a fingerprint
+
+ for (var/datum/reagent/reagent in my_atom.reagents.reagent_list) //make gas for reagents, has to be done this way, otherwise it never stops Exploding
+ R.add_reagent(reagent.id, reagent.volume/3) //Seems fine? I think I fixed the infinite explosion bug.
+
+ if (reagent.purity < 0.6)
+ ImpureTot = (ImpureTot + (1-reagent.purity)) / 2
+
+ if(pH < 4) //if acidic, make acid spray
+ R.add_reagent("fermiAcid", (volume/3))
+ if(R.reagent_list)
+ s.set_up(R, (volume/5), my_atom)
+ s.start()
+
+ if (pH > 10) //if alkaline, small explosion.
+ var/datum/effect_system/reagents_explosion/e = new()
+ e.set_up(round((volume/30)*(pH-9)), T, 0, 0)
+ e.start()
+
+ if(!ImpureTot == 0) //If impure, v.small emp (0.6 or less)
+ ImpureTot *= volume
+ var/empVol = CLAMP (volume/10, 0, 15)
+ empulse(T, empVol, ImpureTot/10, 1)
+
+ my_atom.reagents.clear_reagents() //just in case
+ return
+
+/datum/chemical_reaction/fermi/eigenstate
+ name = "Eigenstasium"
+ id = "eigenstate"
+ results = list("eigenstate" = 0.1)
+ required_reagents = list("bluespace" = 0.1, "stable_plasma" = 0.1, "sugar" = 0.1)
+ mix_message = "the reaction zaps suddenly!"
+ //FermiChem vars:
+ OptimalTempMin = 350 // Lower area of bell curve for determining heat based rate reactions
+ OptimalTempMax = 600 // Upper end for above
+ ExplodeTemp = 650 //Temperature at which reaction explodes
+ OptimalpHMin = 7 // Lowest value of pH determining pH a 1 value for pH based rate reactions (Plateu phase)
+ OptimalpHMax = 9 // Higest value for above
+ ReactpHLim = 5 // How far out pH wil react, giving impurity place (Exponential phase)
+ CatalystFact = 0 // How much the catalyst affects the reaction (0 = no catalyst)
+ CurveSharpT = 1.5 // How sharp the temperature exponential curve is (to the power of value)
+ CurveSharppH = 3 // How sharp the pH exponential curve is (to the power of value)
+ ThermicConstant = 10 //Temperature change per 1u produced
+ HIonRelease = -0.02 //pH change per 1u reaction
+ RateUpLim = 3 //Optimal/max rate possible if all conditions are perfect
+ FermiChem = TRUE//If the chemical uses the Fermichem reaction mechanics
+ FermiExplode = FALSE //If the chemical explodes in a special way
+ PurityMin = 0.4 //The minimum purity something has to be above, otherwise it explodes.
+
+/datum/chemical_reaction/fermi/eigenstate/FermiFinish(datum/reagents/holder, var/atom/my_atom)//Strange how this doesn't work but the other does.
+ if(!locate(/datum/reagent/fermi/eigenstate) in my_atom.reagents.reagent_list)
+ return
+ var/turf/open/location = get_turf(my_atom)
+ var/datum/reagent/fermi/eigenstate/E = locate(/datum/reagent/fermi/eigenstate) in my_atom.reagents.reagent_list
+ if(location)
+ E.location_created = location
+ E.data.["location_created"] = location
+
+
+//serum
+/datum/chemical_reaction/fermi/SDGF
+ name = "Synthetic-derived growth factor"
+ id = "SDGF"
+ results = list("SDGF" = 0.3)
+ required_reagents = list("stable_plasma" = 0.15, "clonexadone" = 0.15, "uranium" = 0.15, "synthflesh" = 0.15)
+ mix_message = "the reaction gives off a blorble!"
+ required_temp = 1
+ //FermiChem vars:
+ OptimalTempMin = 600 // Lower area of bell curve for determining heat based rate reactions
+ OptimalTempMax = 630 // Upper end for above
+ ExplodeTemp = 635 // Temperature at which reaction explodes
+ OptimalpHMin = 3 // Lowest value of pH determining pH a 1 value for pH based rate reactions (Plateu phase)
+ OptimalpHMax = 3.5 // Higest value for above
+ ReactpHLim = 2 // How far out pH wil react, giving impurity place (Exponential phase)
+ CatalystFact = 0 // How much the catalyst affects the reaction (0 = no catalyst)
+ CurveSharpT = 4 // How sharp the temperature exponential curve is (to the power of value)
+ CurveSharppH = 4 // How sharp the pH exponential curve is (to the power of value)
+ ThermicConstant = -10 // Temperature change per 1u produced
+ HIonRelease = 0.02 // pH change per 1u reaction (inverse for some reason)
+ RateUpLim = 1 // Optimal/max rate possible if all conditions are perfect
+ FermiChem = TRUE // If the chemical uses the Fermichem reaction mechanics
+ FermiExplode = TRUE // If the chemical explodes in a special way
+ PurityMin = 0.2
+
+/datum/chemical_reaction/fermi/SDGF/FermiExplode(datum/reagents, var/atom/my_atom, volume, temp, pH)//Spawns an angery teratoma!
+ var/turf/T = get_turf(my_atom)
+ var/mob/living/simple_animal/slime/S = new(T,"green")
+ S.damage_coeff = list(BRUTE = 0.9 , BURN = 2, TOX = 1, CLONE = 1, STAMINA = 0, OXY = 1)
+ S.name = "Living teratoma"
+ S.real_name = "Living teratoma"
+ S.rabid = 1//Make them an angery boi
+ S.color = "#810010"
+ my_atom.reagents.clear_reagents()
+ var/list/seen = viewers(8, get_turf(my_atom))
+ for(var/mob/M in seen)
+ to_chat(M, "The cells clump up into a horrifying tumour!")
+
+/datum/chemical_reaction/fermi/breast_enlarger
+ name = "Sucubus milk"
+ id = "breast_enlarger"
+ results = list("breast_enlarger" = 0.8)
+ required_reagents = list("salglu_solution" = 0.1, "milk" = 0.1, "synthflesh" = 0.2, "silicon" = 0.3, "aphro" = 0.3)
+ mix_message = "the reaction gives off a mist of milk."
+ //FermiChem vars:
+ OptimalTempMin = 200
+ OptimalTempMax = 800
+ ExplodeTemp = 900
+ OptimalpHMin = 6
+ OptimalpHMax = 10
+ ReactpHLim = 3
+ CatalystFact = 0
+ CurveSharpT = 2
+ CurveSharppH = 1
+ ThermicConstant = 1
+ HIonRelease = -0.1
+ RateUpLim = 5
+ FermiChem = TRUE
+ FermiExplode = TRUE
+ PurityMin = 0.1
+
+/datum/chemical_reaction/fermi/breast_enlarger/FermiFinish(datum/reagents/holder, var/atom/my_atom)
+ var/datum/reagent/fermi/breast_enlarger/BE = locate(/datum/reagent/fermi/breast_enlarger) in my_atom.reagents.reagent_list
+ var/cached_volume = BE.volume
+ if(BE.purity < 0.35)
+ holder.remove_reagent(src.id, cached_volume)
+ holder.add_reagent("BEsmaller", cached_volume)
+
+
+/datum/chemical_reaction/fermi/breast_enlarger/FermiExplode(datum/reagents, var/atom/my_atom, volume, temp, pH)
+ var/obj/item/organ/genital/breasts/B = new /obj/item/organ/genital/breasts(get_turf(my_atom))
+ var/list/seen = viewers(8, get_turf(my_atom))
+ for(var/mob/M in seen)
+ to_chat(M, "The reaction suddenly condenses, creating a pair of breasts!")
+ var/datum/reagent/fermi/breast_enlarger/BE = locate(/datum/reagent/fermi/breast_enlarger) in my_atom.reagents.reagent_list
+ B.size = ((BE.volume * BE.purity) / 10) //half as effective.
+ my_atom.reagents.clear_reagents()
+
+/datum/chemical_reaction/fermi/penis_enlarger
+ name = "Incubus draft"
+ id = "penis_enlarger"
+ results = list("penis_enlarger" = 0.8)
+ required_reagents = list("blood" = 0.5, "synthflesh" = 0.2, "carbon" = 0.2, "aphro" = 0.2, "salglu_solution" = 0.1,)
+ mix_message = "the reaction gives off a spicy mist."
+ //FermiChem vars:
+ OptimalTempMin = 200
+ OptimalTempMax = 800
+ ExplodeTemp = 900
+ OptimalpHMin = 2
+ OptimalpHMax = 6
+ ReactpHLim = 3
+ CatalystFact = 0
+ CurveSharpT = 2
+ CurveSharppH = 1
+ ThermicConstant = 1
+ HIonRelease = 0.1
+ RateUpLim = 5
+ FermiChem = TRUE
+ FermiExplode = TRUE
+ PurityMin = 0.1
+
+/datum/chemical_reaction/fermi/penis_enlarger/FermiExplode(datum/reagents, var/atom/my_atom, volume, temp, pH)
+ var/obj/item/organ/genital/penis/P = new /obj/item/organ/genital/penis(get_turf(my_atom))
+ var/list/seen = viewers(8, get_turf(my_atom))
+ for(var/mob/M in seen)
+ to_chat(M, "The reaction suddenly condenses, creating a penis!")
+ var/datum/reagent/fermi/penis_enlarger/PE = locate(/datum/reagent/fermi/penis_enlarger) in my_atom.reagents.reagent_list
+ P.length = ((PE.volume * PE.purity) / 10)//half as effective.
+ my_atom.reagents.clear_reagents()
+
+/datum/chemical_reaction/fermi/penis_enlarger/FermiFinish(datum/reagents/holder, var/atom/my_atom)
+ var/datum/reagent/fermi/penis_enlarger/PE = locate(/datum/reagent/fermi/penis_enlarger) in my_atom.reagents.reagent_list
+ var/cached_volume = PE.volume
+ if(PE.purity < 0.35)
+ holder.remove_reagent(src.id, cached_volume)
+ holder.add_reagent("PEsmaller", cached_volume)
+
+/datum/chemical_reaction/fermi/astral
+ name = "Astrogen"
+ id = "astral"
+ results = list("astral" = 0.5)
+ required_reagents = list("eigenstate" = 0.1, "plasma" = 0.3, "synaptizine" = 0.1, "aluminium" = 0.5)
+ //FermiChem vars:
+ OptimalTempMin = 700
+ OptimalTempMax = 800
+ ExplodeTemp = 1150
+ OptimalpHMin = 10
+ OptimalpHMax = 13
+ ReactpHLim = 2
+ CatalystFact = 0
+ CurveSharpT = 1
+ CurveSharppH = 1
+ ThermicConstant = 25
+ HIonRelease = 0.02
+ RateUpLim = 15
+ FermiChem = TRUE
+ FermiExplode = TRUE
+ PurityMin = 0.25
+
+
+/datum/chemical_reaction/fermi/enthrall/ //check this
+ name = "MKUltra"
+ id = "enthrall"
+ results = list("enthrall" = 0.5)
+ //required_reagents = list("iron" = 1, "iodine" = 1) Test vars
+ //required_reagents = list("cocoa" = 0.1, "astral" = 0.1, "mindbreaker" = 0.1, "psicodine" = 0.1, "happiness" = 0.1)
+ required_reagents = list("cocoa" = 0.1, "bluespace" = 0.1, "mindbreaker" = 0.1, "psicodine" = 0.1, "happiness" = 0.1) //TEMPORARY UNTIL HEADMINS GIVE THE OKAY FOR MK USE.
+ required_catalysts = list("blood" = 1)
+ mix_message = "the reaction gives off a burgundy plume of smoke!"
+ //FermiChem vars:
+ OptimalTempMin = 780
+ OptimalTempMax = 820
+ ExplodeTemp = 840
+ OptimalpHMin = 12
+ OptimalpHMax = 13
+ ReactpHLim = 2
+ //CatalystFact = 0
+ CurveSharpT = 0.5
+ CurveSharppH = 4
+ ThermicConstant = 15
+ HIonRelease = 0.1
+ RateUpLim = 1
+ FermiChem = TRUE
+ FermiExplode = TRUE
+ PurityMin = 0.2
+
+/datum/chemical_reaction/fermi/enthrall/FermiFinish(datum/reagents/holder, var/atom/my_atom)
+ var/datum/reagent/blood/B = locate(/datum/reagent/blood) in my_atom.reagents.reagent_list
+ var/datum/reagent/fermi/enthrall/E = locate(/datum/reagent/fermi/enthrall) in my_atom.reagents.reagent_list
+ if(!B)
+ return
+ if(!B.data)
+ var/list/seen = viewers(5, get_turf(my_atom))
+ for(var/mob/M in seen)
+ to_chat(M, "The reaction splutters and fails to react properly.") //Just in case
+ E.purity = 0
+ if (B.data.["gender"] == "female")
+ E.data.["creatorGender"] = "Mistress"
+ E.creatorGender = "Mistress"
+ else
+ E.data.["creatorGender"] = "Master"
+ E.creatorGender = "Master"
+ E.data["creatorName"] = B.data.["real_name"]
+ E.creatorName = B.data.["real_name"]
+ E.data.["creatorID"] = B.data.["ckey"]
+ E.creatorID = B.data.["ckey"]
+
+//So slimes can play too.
+/datum/chemical_reaction/fermi/enthrall/slime
+ required_catalysts = list("slimejelly" = 1)
+
+/datum/chemical_reaction/fermi/enthrall/slime/FermiFinish(datum/reagents/holder, var/atom/my_atom)
+ var/datum/reagent/toxin/slimejelly/B = locate(/datum/reagent/toxin/slimejelly) in my_atom.reagents.reagent_list//The one line change.
+ var/datum/reagent/fermi/enthrall/E = locate(/datum/reagent/fermi/enthrall) in my_atom.reagents.reagent_list
+ if(!B.data)
+ var/list/seen = viewers(5, get_turf(my_atom))
+ for(var/mob/M in seen)
+ to_chat(M, "The reaction splutters and fails to react.") //Just in case
+ E.purity = 0
+ if (B.data.["gender"] == "female")
+ E.data.["creatorGender"] = "Mistress"
+ E.creatorGender = "Mistress"
+ else
+ E.data.["creatorGender"] = "Master"
+ E.creatorGender = "Master"
+ E.data["creatorName"] = B.data.["real_name"]
+ E.creatorName = B.data.["real_name"]
+ E.data.["creatorID"] = B.data.["ckey"]
+ E.creatorID = B.data.["ckey"]
+
+/datum/chemical_reaction/fermi/enthrall/FermiExplode(datum/reagents, var/atom/my_atom, volume, temp, pH)
+ var/turf/T = get_turf(my_atom)
+ var/datum/reagents/R = new/datum/reagents(1000)
+ var/datum/effect_system/smoke_spread/chem/s = new()
+ R.add_reagent("enthrallExplo", volume)
+ s.set_up(R, volume/2, T)
+ s.start()
+ my_atom.reagents.clear_reagents()
+
+/datum/chemical_reaction/fermi/hatmium // done
+ name = "Hat growth serum"
+ id = "hatmium"
+ results = list("hatmium" = 0.5)
+ required_reagents = list("ethanol" = 0.1, "nutriment" = 0.3, "cooking_oil" = 0.2, "iron" = 0.1, "gold" = 0.3)
+ //mix_message = ""
+ //FermiChem vars:
+ OptimalTempMin = 500
+ OptimalTempMax = 700
+ ExplodeTemp = 750
+ OptimalpHMin = 2
+ OptimalpHMax = 5
+ ReactpHLim = 3
+ //CatalystFact = 0 //To do 1
+ CurveSharpT = 8
+ CurveSharppH = 0.5
+ ThermicConstant = -2
+ HIonRelease = -0.1
+ RateUpLim = 2
+ FermiChem = TRUE
+ FermiExplode = TRUE
+ PurityMin = 0.5
+
+/datum/chemical_reaction/fermi/hatmium/FermiExplode(src, var/atom/my_atom, volume, temp, pH)
+ var/obj/item/clothing/head/hattip/hat = new /obj/item/clothing/head/hattip(get_turf(my_atom))
+ hat.animate_atom_living()
+ var/list/seen = viewers(8, get_turf(my_atom))
+ for(var/mob/M in seen)
+ to_chat(M, "The makes an off sounding pop, as a hat suddenly climbs out of the beaker!")
+ my_atom.reagents.clear_reagents()
+
+/datum/chemical_reaction/fermi/furranium
+ name = "Furranium"
+ id = "furranium"
+ results = list("furranium" = 0.5)
+ required_reagents = list("aphro" = 0.1, "moonsugar" = 0.1, "silver" = 0.2, "salglu_solution" = 0.1)
+ mix_message = "You think you can hear a howl come from the beaker."
+ //FermiChem vars:
+ OptimalTempMin = 350
+ OptimalTempMax = 600
+ ExplodeTemp = 700
+ OptimalpHMin = 8
+ OptimalpHMax = 10
+ ReactpHLim = 2
+ //CatalystFact = 0 //To do 1
+ CurveSharpT = 2
+ CurveSharppH = 0.5
+ ThermicConstant = -10
+ HIonRelease = -0.1
+ RateUpLim = 2
+ FermiChem = TRUE
+ PurityMin = 0.3
+
+//FOR INSTANT REACTIONS - DO NOT MULTIPLY LIMIT BY 10.
+//There's a weird rounding error or something ugh.
+
+//Nano-b-gone
+/datum/chemical_reaction/fermi/nanite_b_gone//done test
+ name = "Naninte bain"
+ id = "nanite_b_gone"
+ results = list("nanite_b_gone" = 4)
+ required_reagents = list("synthflesh" = 1, "uranium" = 1, "iron" = 1, "salglu_solution" = 1)
+ mix_message = "the reaction gurgles, encapsulating the reagents in flesh before the emp can be set off."
+ required_temp = 450//To force fermireactions before EMP.
+ //FermiChem vars:
+ OptimalTempMin = 500
+ OptimalTempMax = 600
+ ExplodeTemp = 700
+ OptimalpHMin = 6
+ OptimalpHMax = 6.25
+ ReactpHLim = 3
+ //CatalystFact = 0 //To do 1
+ CurveSharpT = 0
+ CurveSharppH = 1
+ ThermicConstant = 5
+ HIonRelease = 0.01
+ RateUpLim = 1
+ FermiChem = TRUE
+
+/datum/chemical_reaction/fermi/acidic_buffer//done test
+ name = "Acetic acid buffer"
+ id = "acidic_buffer"
+ results = list("acidic_buffer" = 2) //acetic acid
+ required_reagents = list("salglu_solution" = 0.2, "ethanol" = 0.6, "oxygen" = 0.6, "water" = 0.6)
+ //FermiChem vars:
+ OptimalTempMin = 250
+ OptimalTempMax = 500
+ ExplodeTemp = 9999 //check to see overflow doesn't happen!
+ OptimalpHMin = 2
+ OptimalpHMax = 6
+ ReactpHLim = 0
+ //CatalystFact = 0 //To do 1
+ CurveSharpT = 4
+ CurveSharppH = 0
+ ThermicConstant = 0
+ HIonRelease = -0.01
+ RateUpLim = 20
+ FermiChem = TRUE
+
+
+/datum/chemical_reaction/fermi/acidic_buffer/FermiFinish(datum/reagents/holder, var/atom/my_atom) //might need this
+ if(!locate(/datum/reagent/fermi/acidic_buffer) in my_atom.reagents.reagent_list)
+ return
+ var/datum/reagent/fermi/acidic_buffer/Fa = locate(/datum/reagent/fermi/acidic_buffer) in my_atom.reagents.reagent_list
+ Fa.data = 0.1//setting it to 0 means byond thinks it's not there.
+
+/datum/chemical_reaction/fermi/basic_buffer//done test
+ name = "Ethyl Ethanoate buffer"
+ id = "basic_buffer"
+ results = list("basic_buffer" = 1.5)
+ required_reagents = list("acidic_buffer" = 0.5, "ethanol" = 0.5, "water" = 0.5)
+ required_catalysts = list("sacid" = 1) //vagely acetic
+ //FermiChem vars:x
+ OptimalTempMin = 250
+ OptimalTempMax = 500
+ ExplodeTemp = 9999 //check to see overflow doesn't happen!
+ OptimalpHMin = 5
+ OptimalpHMax = 12
+ ReactpHLim = 0
+ //CatalystFact = 0 //To do 1
+ CurveSharpT = 4
+ CurveSharppH = 0
+ ThermicConstant = 0
+ HIonRelease = 0.01
+ RateUpLim = 15
+ FermiChem = TRUE
+
+
+/datum/chemical_reaction/fermi/basic_buffer/FermiFinish(datum/reagents/holder, var/atom/my_atom) //might need this
+ if(!locate(/datum/reagent/fermi/basic_buffer) in my_atom.reagents.reagent_list)
+ return
+ var/datum/reagent/fermi/basic_buffer/Fb = locate(/datum/reagent/fermi/basic_buffer) in my_atom.reagents.reagent_list
+ Fb.data = 14
+
+//secretcatchemcode, shh!! Of couse I hide it amongst cats. Though, I moved it with your requests.
+//I'm not trying to be sneaky, I'm trying to keep it a secret!
+//I don't know how to do hidden chems like Aurora
+//ChemReactionVars:
+/datum/chemical_reaction/fermi/secretcatchem //DONE
+ name = "secretcatchem"
+ id = "secretcatchem"
+ results = list("secretcatchem" = 0.5)
+ required_reagents = list("stable_plasma" = 0.1, "sugar" = 0.1, "cream" = 0.1, "clonexadone" = 0.1)//Yes this will make a plushie if you don't lucky guess. It'll eat all your reagents too.
+ required_catalysts = list("SDGF" = 1)
+ required_temp = 600
+ mix_message = "the reaction gives off a meow!"
+ mix_sound = "modular_citadel/sound/voice/merowr.ogg"
+ //FermiChem vars:
+ OptimalTempMin = 650
+ OptimalpHMin = 0
+ ReactpHLim = 2
+ CurveSharpT = 0
+ CurveSharppH = 0
+ ThermicConstant = 0
+ HIonRelease = 0
+ RateUpLim = 0.1
+ FermiChem = TRUE
+ FermiExplode = FALSE
+ PurityMin = 0.2
+
+/datum/chemical_reaction/fermi/secretcatchem/New()
+ //rand doesn't seem to work with n^-e
+ OptimalTempMin += rand(-100, 100)
+ OptimalTempMax = (OptimalTempMin+rand(20, 200))
+ ExplodeTemp = (OptimalTempMax+rand(20, 200))
+ OptimalpHMin += rand(1, 10)
+ OptimalpHMax = (OptimalpHMin + rand(1, 5))
+ ReactpHLim += rand(-1.5, 2.5)
+ CurveSharpT += (rand(1, 500)/100)
+ CurveSharppH += (rand(1, 500)/100)
+ ThermicConstant += rand(-20, 20)
+ HIonRelease += (rand(-25, 25)/100)
+ RateUpLim += (rand(1, 1000)/100)
+ PurityMin += (rand(-1, 1)/10)
+ var/additions = list("aluminium", "silver", "gold", "plasma", "silicon", "uranium", "milk")
+ required_reagents[pick(additions)] = rand(0.1, 0.5)//weird
+
+/datum/chemical_reaction/fermi/secretcatchem/FermiFinish(datum/reagents/holder, var/atom/my_atom)
+ SSblackbox.record_feedback("tally", "catgirlium")//log
+
+/datum/chemical_reaction/fermi/secretcatchem/FermiExplode(datum/reagents, var/atom/my_atom, volume, temp, pH)
+ var/mob/living/simple_animal/pet/cat/custom_cat/catto = new(get_turf(my_atom))
+ var/list/seen = viewers(8, get_turf(my_atom))
+ for(var/mob/M in seen)
+ to_chat(M, "The reaction suddenly gives out a meow, condensing into a chemcat!")//meow!
+ playsound(get_turf(my_atom), 'modular_citadel/sound/voice/merowr.ogg', 50, 1, -1)
+ catto.name = "Chemcat"
+ catto.desc = "A cute chem cat, created by a lot of compicated and confusing chemistry!"
+ catto.color = "#770000"
+ my_atom.reagents.remove_all(5)
+
+/datum/chemical_reaction/fermi/yamerol//done test
+ name = "Yamerol"
+ id = "yamerol"
+ results = list("yamerol" = 1.5)
+ required_reagents = list("perfluorodecalin" = 0.5, "salbutamol" = 0.5, "water" = 0.5)
+ //FermiChem vars:
+ OptimalTempMin = 300
+ OptimalTempMax = 500
+ ExplodeTemp = 800 //check to see overflow doesn't happen!
+ OptimalpHMin = 6.8
+ OptimalpHMax = 7.2
+ ReactpHLim = 4
+ //CatalystFact = 0 //To do 1
+ CurveSharpT = 5
+ CurveSharppH = 0.5
+ ThermicConstant = -15
+ HIonRelease = 0.1
+ RateUpLim = 2
+ FermiChem = TRUE
diff --git a/modular_citadel/code/modules/reagents/objects/clothes.dm b/modular_citadel/code/modules/reagents/objects/clothes.dm
new file mode 100644
index 0000000000..708f1f59f8
--- /dev/null
+++ b/modular_citadel/code/modules/reagents/objects/clothes.dm
@@ -0,0 +1,69 @@
+//Fermiclothes!
+//Clothes made from FermiChem
+
+/obj/item/clothing/head/hattip //I wonder if anyone else has played cryptworlds
+ name = "Sythetic hat"
+ icon = 'icons/obj/clothing/hats.dmi'
+ icon_state = "cowboy"
+ desc = "A sythesized hat, you can't seem to take it off. And tips their hat."
+ armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 0)
+ //item_flags = NODROP //Tips their hat!
+
+/obj/item/clothing/head/hattip/attack_hand(mob/user)
+ if(iscarbon(user))
+ var/mob/living/carbon/C = user
+ if(is_ninja(C))
+ to_chat(C, "Using your superior ninja reflexes, you take the hat off before tipping.")
+ return ..()
+
+ if(src == C.head)
+ C.emote("me",1,"tips their hat.",TRUE)
+ return
+ else
+ user.emote("me",1,"admires such a spiffy hat.",TRUE)
+ return ..()
+
+/obj/item/clothing/head/hattip/MouseDrop(atom/over_object)
+ //You sure do love tipping your hat.
+ if(usr)
+ var/mob/living/carbon/C = usr
+ if(is_ninja(C))
+ to_chat(C, "Using your superior ninja reflexes, you take the hat off before tipping.")
+ return ..()
+
+ if(src == C.head)
+ C.emote("me",1,"tips their hat.",TRUE)
+ return
+ ..()
+
+/obj/item/clothing/head/hattip/equipped(mob/M, slot)
+ . = ..()
+ if (slot == SLOT_HEAD)
+ RegisterSignal(M, COMSIG_MOB_SAY, .proc/handle_speech)
+ else
+ UnregisterSignal(M, COMSIG_MOB_SAY)
+
+/obj/item/clothing/head/hattip/dropped(mob/M)
+ . = ..()
+ UnregisterSignal(M, COMSIG_MOB_SAY)
+
+/obj/item/clothing/head/hattip/proc/handle_speech(datum/source, mob/speech_args)
+ var/message = speech_args[SPEECH_MESSAGE]
+ var/mob/living/carbon/C = get_wearer()//user
+ var/obj/item/organ/tongue/T = C.getorganslot(ORGAN_SLOT_TONGUE)
+ if (T.name == "fluffy tongue")
+ if(prob(0.01))
+ message += "\" and tips their hat. \"swpy's sappin' my chem dispwencer uwu!!"
+ else
+ message += "\" and tips their hat. \"[pick("weehaw!", "bwoy howdy.", "dawn tuutin'.", "weww don't that beat aww.", "whoooowee, wouwd ya wook at that!", "whoooowee! makin' bwacon!", "cweam gwavy!", "yippekeeyah-heeyapeeah-kwayoh!", "mwove 'em uut!", "gwiddy up!")]"
+ speech_args[SPEECH_MESSAGE] = trim(message)
+ return
+ if(prob(0.01))
+ message += "\" and tips their hat. \"Spy's sappin' my chem dispenser!"//How did I not think of this earlier
+ message_admins("I really appreciate all the hard work you put into adminning citadel, I hope you're all having a good day and I hope this hidden and rare message_admins brightens up your day.")
+ else
+ message += "\" and tips their hat. \"[pick("Yeehaw!", "Boy howdy.", "Darn tootin'.", "Well don't that beat all.", "Whoooowee, would ya look at that!", "Whoooowee! Makin' bacon!", "Cream Gravy!", "Yippekeeyah-heeyapeeah-kayoh!", "Move 'em out!", "Giddy up!")]"
+ speech_args[SPEECH_MESSAGE] = trim(message)
+
+/obj/item/clothing/head/hattip/proc/get_wearer()
+ return loc
diff --git a/modular_citadel/code/modules/reagents/objects/items.dm b/modular_citadel/code/modules/reagents/objects/items.dm
new file mode 100644
index 0000000000..02f2db7c1e
--- /dev/null
+++ b/modular_citadel/code/modules/reagents/objects/items.dm
@@ -0,0 +1,147 @@
+/obj/item/fermichem/pHbooklet
+ name = "pH indicator booklet"
+ desc = "A booklet containing paper soaked in universal indicator."
+ icon_state = "pHbooklet"
+ icon = 'modular_citadel/icons/obj/FermiChem.dmi'
+ item_flags = NOBLUDGEON
+ var/numberOfPages = 50
+ resistance_flags = FLAMMABLE
+ w_class = WEIGHT_CLASS_TINY
+
+//A little janky with pockets
+/obj/item/fermichem/pHbooklet/attack_hand(mob/user)
+ if(user.get_held_index_of_item(src))//Does this check pockets too..?
+ if(numberOfPages == 50)
+ icon_state = "pHbookletOpen"
+ if(numberOfPages >= 1)
+ var/obj/item/fermichem/pHpaper/P = new /obj/item/fermichem/pHpaper
+ P.add_fingerprint(user)
+ P.forceMove(user.loc)
+ user.put_in_active_hand(P)
+ to_chat(user, "You take [P] out of \the [src].")
+ numberOfPages--
+ playsound(user.loc, 'sound/items/poster_ripped.ogg', 50, 1)
+ add_fingerprint(user)
+ if(numberOfPages == 0)
+ icon_state = "pHbookletEmpty"
+ return
+ else
+ to_chat(user, "[src] is empty!")
+ add_fingerprint(user)
+ return
+ . = ..()
+ if(. & COMPONENT_NO_INTERACT)
+ return
+ var/I = user.get_active_held_item()
+ if(!I)
+ user.put_in_active_hand(src)
+
+/obj/item/fermichem/pHbooklet/MouseDrop()
+ var/mob/living/user = usr
+ if(numberOfPages >= 1)
+ var/obj/item/fermichem/pHpaper/P = new /obj/item/fermichem/pHpaper
+ P.add_fingerprint(user)
+ P.forceMove(user)
+ user.put_in_active_hand(P)
+ to_chat(user, "You take [P] out of \the [src].")
+ numberOfPages--
+ playsound(user.loc, 'sound/items/poster_ripped.ogg', 50, 1)
+ add_fingerprint(user)
+ if(numberOfPages == 0)
+ icon_state = "pHbookletEmpty"
+ return
+ else
+ to_chat(user, "[src] is empty!")
+ add_fingerprint(user)
+ return
+ ..()
+
+/obj/item/fermichem/pHpaper
+ name = "pH indicator strip"
+ desc = "A piece of paper that will change colour depending on the pH of a solution."
+ icon_state = "pHpaper"
+ icon = 'modular_citadel/icons/obj/FermiChem.dmi'
+ item_flags = NOBLUDGEON
+ color = "#f5c352"
+ var/used = FALSE
+ resistance_flags = FLAMMABLE
+ w_class = WEIGHT_CLASS_TINY
+
+/obj/item/fermichem/pHpaper/afterattack(obj/item/reagent_containers/cont, mob/user, proximity)
+ if(!istype(cont))
+ return
+ if(used == TRUE)
+ to_chat(user, "[user] has already been used!")
+ return
+ if(!LAZYLEN(cont.reagents.reagent_list))
+ return
+ switch(round(cont.reagents.pH, 1))
+ if(14 to INFINITY)
+ color = "#462c83"
+ if(13 to 14)
+ color = "#63459b"
+ if(12 to 13)
+ color = "#5a51a2"
+ if(11 to 12)
+ color = "#3853a4"
+ if(10 to 11)
+ color = "#3f93cf"
+ if(9 to 10)
+ color = "#0bb9b7"
+ if(8 to 9)
+ color = "#23b36e"
+ if(7 to 8)
+ color = "#3aa651"
+ if(6 to 7)
+ color = "#4cb849"
+ if(5 to 6)
+ color = "#b5d335"
+ if(4 to 5)
+ color = "#f7ec1e"
+ if(3 to 4)
+ color = "#fbc314"
+ if(2 to 3)
+ color = "#f26724"
+ if(1 to 2)
+ color = "#ef1d26"
+ if(-INFINITY to 1)
+ color = "#c6040c"
+ desc += " The paper looks to be around a pH of [round(cont.reagents.pH, 1)]"
+ used = TRUE
+
+/obj/item/fermichem/pHmeter
+ name = "Chemistry Analyser"
+ desc = "A a electrode attached to a small circuit box that will tell you the pH of a solution. The screen currently displays nothing."
+ icon_state = "pHmeter"
+ icon = 'modular_citadel/icons/obj/FermiChem.dmi'
+ resistance_flags = FLAMMABLE
+ w_class = WEIGHT_CLASS_TINY
+ var/scanmode = 1
+
+/obj/item/fermichem/pHmeter/attack_self(mob/user)
+ if(!scanmode)
+ to_chat(user, "You switch the chemical analyzer to give a detailed report.")
+ scanmode = 1
+ else
+ to_chat(user, "You switch the chemical analyzer to give a reduced report.")
+ scanmode = 0
+
+/obj/item/fermichem/pHmeter/afterattack(atom/A, mob/user, proximity)
+ . = ..()
+ if(!istype(A, /obj/item/reagent_containers))
+ return
+ var/obj/item/reagent_containers/cont = A
+ if(LAZYLEN(cont.reagents.reagent_list) == null)
+ return
+ var/out_message
+ to_chat(user, "The chemistry meter beeps and displays:")
+ out_message += "Total volume: [round(cont.volume, 0.01)] Total pH: [round(cont.reagents.pH, 0.1)]\n"
+ if(cont.reagents.fermiIsReacting)
+ out_message += "A reaction appears to be occuring currently.\n"
+ out_message += "Chemicals found in the beaker:\n"
+ for(var/datum/reagent/R in cont.reagents.reagent_list)
+ out_message += "[R.volume]u of [R.name], Purity: [R.purity], [(scanmode?"[(R.overdose_threshold?"Overdose: [R.overdose_threshold]u, ":"")][(R.addiction_threshold?"Addiction: [R.addiction_threshold]u, ":"")]Base pH: [R.pH].":".")]\n"
+ if(scanmode)
+ out_message += "Analysis: [R.description]\n"
+ to_chat(user, "[out_message]")
+ desc = "An electrode attached to a small circuit box that will analyse a beaker. It can be toggled to give a reduced or extended report. The screen currently displays [round(cont.reagents.pH, 0.1)]."
diff --git a/modular_citadel/code/modules/reagents/reagent container/hypospraymkii.dm b/modular_citadel/code/modules/reagents/reagent container/hypospraymkii.dm
index bee56cde15..6cd9e1badc 100755
--- a/modular_citadel/code/modules/reagents/reagent container/hypospraymkii.dm
+++ b/modular_citadel/code/modules/reagents/reagent container/hypospraymkii.dm
@@ -50,6 +50,9 @@
/obj/item/hypospray/mkii/tricord
start_vial = /obj/item/reagent_containers/glass/bottle/vial/small/preloaded/tricord
+/obj/item/hypospray/mkii/enlarge
+ spawnwithvial = FALSE
+
/obj/item/hypospray/mkii/CMO
name = "hypospray mk.II deluxe"
allowed_containers = list(/obj/item/reagent_containers/glass/bottle/vial/tiny, /obj/item/reagent_containers/glass/bottle/vial/small, /obj/item/reagent_containers/glass/bottle/vial/large)
diff --git a/modular_citadel/code/modules/reagents/reagent container/hypovial.dm b/modular_citadel/code/modules/reagents/reagent container/hypovial.dm
index 4b7972d0a7..c1e0d6ff01 100755
--- a/modular_citadel/code/modules/reagents/reagent container/hypovial.dm
+++ b/modular_citadel/code/modules/reagents/reagent container/hypovial.dm
@@ -14,7 +14,8 @@
"green hypovial" = "hypovial-a",
"orange hypovial" = "hypovial-k",
"purple hypovial" = "hypovial-p",
- "black hypovial" = "hypovial-t"
+ "black hypovial" = "hypovial-t",
+ "pink hypovial" = "hypovial-pink"
)
always_reskinnable = TRUE
@@ -136,6 +137,16 @@
icon_state = "hypovial"
comes_with = list("tricordrazine" = 30)
+/obj/item/reagent_containers/glass/bottle/vial/small/preloaded/breastreduction
+ name = "pink hypovial (breast treatment)"
+ icon_state = "hypovial-pink"
+ comes_with = list("BEsmaller_hypo" = 30)
+
+/obj/item/reagent_containers/glass/bottle/vial/small/preloaded/penisreduction
+ name = "pink hypovial (penis treatment)"
+ icon_state = "hypovial-pink"
+ comes_with = list("PEsmaller_hypo" = 30)
+
/obj/item/reagent_containers/glass/bottle/vial/large/preloaded/CMO
name = "deluxe hypovial"
icon_state = "hypoviallarge-cmos"
diff --git a/modular_citadel/code/modules/reagents/reagents/cit_reagents.dm b/modular_citadel/code/modules/reagents/reagents/cit_reagents.dm
index ee8268128a..c4c1cff1e7 100644
--- a/modular_citadel/code/modules/reagents/reagents/cit_reagents.dm
+++ b/modular_citadel/code/modules/reagents/reagents/cit_reagents.dm
@@ -8,6 +8,7 @@
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 = "#FFFFFF" // rgb: 255, 255, 255
+ can_synth = FALSE
nutriment_factor = 0.5 * REAGENTS_METABOLISM
/datum/reagent/consumable/semen/reaction_turf(turf/T, reac_volume)
@@ -19,7 +20,6 @@
var/obj/effect/decal/cleanable/semen/S = locate() in T
if(!S)
S = new(T)
- S.reagents.add_reagent("semen", reac_volume)
if(data["blood_DNA"])
S.add_blood_DNA(list(data["blood_DNA"] = data["blood_type"]))
@@ -50,6 +50,7 @@
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
/obj/effect/decal/cleanable/femcum
@@ -82,7 +83,6 @@
var/obj/effect/decal/cleanable/femcum/S = locate() in T
if(!S)
S = new(T)
- S.reagents.add_reagent("femcum", reac_volume)
if(data["blood_DNA"])
S.add_blood_DNA(list(data["blood_DNA"] = data["blood_type"]))
diff --git a/modular_citadel/code/modules/vore/eating/belly_obj_vr.dm b/modular_citadel/code/modules/vore/eating/belly_obj_vr.dm
index 22085d520c..1ad29c1af3 100644
--- a/modular_citadel/code/modules/vore/eating/belly_obj_vr.dm
+++ b/modular_citadel/code/modules/vore/eating/belly_obj_vr.dm
@@ -47,7 +47,7 @@
var/tmp/next_process = 0 // Waiting for this SSbellies times_fired to process again.
var/tmp/list/items_preserved = list() // Stuff that wont digest so we shouldn't process it again.
var/tmp/next_emote = 0 // When we're supposed to print our next emote, as a belly controller tick #
- var/tmp/recent_sound = FALSE // Prevent audio spam
+ var/tmp/recent_sound // Prevent audio spam
var/tmp/last_hearcheck = 0
var/tmp/list/hearing_mobs
@@ -152,11 +152,13 @@
SSbellies.belly_list += src
/obj/belly/Destroy()
- SSbellies.belly_list -= src
if(owner)
- owner.vore_organs -= src
- owner = null
- . = ..()
+ Remove(owner)
+ return ..()
+
+/obj/belly/proc/Remove(mob/living/owner)
+ owner.vore_organs -= src
+ owner = null
// Called whenever an atom enters this belly
/obj/belly/Entered(var/atom/movable/thing,var/atom/OldLoc)
@@ -167,12 +169,13 @@
to_chat(owner,"[thing] slides into your [lowertext(name)].")
//Sound w/ antispam flag setting
- if(is_wet && !recent_sound)
- for(var/mob/M in get_hearers_in_view(2, get_turf(owner)))
- if(M.client && (M.client.prefs.cit_toggles & EATING_NOISES))
- var/sound/devourments = GLOB.vore_sounds[vore_sound]
- playsound(get_turf(owner),devourments,50,0,-5,0,ignore_walls = FALSE,channel=CHANNEL_PRED)
- recent_sound = TRUE
+ if(is_wet && (world.time > recent_sound))
+ var/turf/source = get_turf(owner)
+ var/sound/eating = GLOB.vore_sounds[vore_sound]
+ for(var/mob/living/M in get_hearers_in_view(3, source))
+ if(M.client && M.client.prefs.cit_toggles & EATING_NOISES)
+ SEND_SOUND(M, eating)
+ recent_sound = (world.time + 20 SECONDS)
//Messages if it's a mob
if(isliving(thing))
@@ -187,7 +190,7 @@
var/atom/destination = drop_location()
//Don't bother if we don't have contents
if(!contents.len)
- return 0
+ return FALSE
var/count = 0
for(var/thing in contents)
@@ -206,10 +209,10 @@
SEND_SIGNAL(L, COMSIG_ADD_MOOD_EVENT, "emptyprey", /datum/mood_event/emptyprey)
AM.forceMove(destination) // Move the belly contents into the same location as belly's owner.
count++
- for(var/mob/M in get_hearers_in_view(2, get_turf(owner)))
+ for(var/mob/living/M in get_hearers_in_view(2, get_turf(owner)))
if(M.client && (M.client.prefs.cit_toggles & EATING_NOISES))
var/sound/releasement = GLOB.release_sounds[release_sound]
- playsound(get_turf(owner),releasement,50,0,-5,0,ignore_walls = FALSE,channel=CHANNEL_PRED)
+ SEND_SOUND(M, releasement)
//Clean up our own business
items_preserved.Cut()
@@ -233,10 +236,10 @@
M.forceMove(drop_location()) // Move the belly contents into the same location as belly's owner.
items_preserved -= M
if(!silent)
- for(var/mob/H in get_hearers_in_view(2, get_turf(owner)))
+ for(var/mob/living/H in get_hearers_in_view(2, get_turf(owner)))
if(H.client && (H.client.prefs.cit_toggles & EATING_NOISES))
var/sound/releasement = GLOB.release_sounds[release_sound]
- playsound(get_turf(owner),releasement,50,0,-5,0,ignore_walls = FALSE,channel=CHANNEL_PRED)
+ SEND_SOUND(H, releasement)
if(istype(M,/mob/living))
var/mob/living/ML = M
@@ -285,10 +288,6 @@
SEND_SIGNAL(prey, COMSIG_CLEAR_MOOD_EVENT, "emptyprey", /datum/mood_event/emptyprey)
prey.forceMove(src)
- var/sound/preyloop = sound('sound/vore/prey/loop.ogg', repeat = TRUE)
-
- if(is_wet)
- prey.playsound_local(loc,preyloop,70,0, channel = CHANNEL_PREYLOOP)
owner.updateVRPanel()
@@ -317,10 +316,12 @@
M.cure_blind("belly_[REF(src)]")
target.nom_mob(content, target.owner)
if(!silent)
- for(var/mob/M in get_hearers_in_view(5, get_turf(owner)))
- if(M.client && (M.client.prefs.cit_toggles & EATING_NOISES))
- var/sound/devourments = GLOB.vore_sounds[vore_sound]
- playsound(get_turf(owner),devourments,50,0,-5,0,ignore_walls = FALSE,channel=CHANNEL_PRED)
+ var/turf/source = get_turf(owner)
+ var/sound/eating = GLOB.vore_sounds[vore_sound]
+ for(var/mob/living/M in get_hearers_in_view(3, source))
+ if(M.client && M.client.prefs.cit_toggles & EATING_NOISES)
+ SEND_SOUND(M, eating)
+
owner.updateVRPanel()
for(var/mob/living/M in contents)
M.updateVRPanel()
@@ -524,22 +525,25 @@
struggle_outer_message = "" + struggle_outer_message + ""
struggle_user_message = "" + struggle_user_message + ""
+ var/turf/source = get_turf(owner)
+ var/sound/struggle_snuggle = sound(get_sfx("struggle_sound"))
+ var/sound/struggle_rustle = sound(get_sfx("rustle"))
+
if(is_wet)
- for(var/mob/M in get_hearers_in_view(2, get_turf(owner)))
- if(M.client && (M.client.prefs.cit_toggles & EATING_NOISES))
- playsound(get_turf(owner),"struggle_sound",35,0,-5,1,ignore_walls = FALSE,channel=CHANNEL_PRED)
- R.stop_sound_channel(CHANNEL_PRED)
- var/sound/prey_struggle = sound(get_sfx("prey_struggle"))
- R.playsound_local(get_turf(R),prey_struggle,45,0)
+ for(var/mob/living/M in get_hearers_in_view(3, source))
+ if(M.client && M.client.prefs.cit_toggles & EATING_NOISES)
+ SEND_SOUND(M, struggle_snuggle)
else
- for(var/mob/M in get_hearers_in_view(2, get_turf(owner)))
- if(M.client && (M.client.prefs.cit_toggles & EATING_NOISES))
- playsound(get_turf(owner),"rustle",35,0,-5,1,ignore_walls = FALSE,channel=CHANNEL_PRED)
+ for(var/mob/living/M in get_hearers_in_view(3, source))
+ if(M.client && M.client.prefs.cit_toggles & EATING_NOISES)
+ SEND_SOUND(M, struggle_rustle)
- for(var/mob/M in get_hearers_in_view(3, get_turf(owner)))
+ var/list/watching = hearers(3, owner)
+ for(var/mob/living/M in watching)
if(M.client && (M.client.prefs.cit_toggles & EATING_NOISES)) //Might as well censor the normies here too.
M.show_message(struggle_outer_message, 1) // visible
+
to_chat(R,struggle_user_message)
if(escapable) //If the stomach has escapable enabled.
diff --git a/modular_citadel/code/modules/vore/eating/bellymodes_vr.dm b/modular_citadel/code/modules/vore/eating/bellymodes_vr.dm
index 6b6a3d30cc..da323f02e2 100644
--- a/modular_citadel/code/modules/vore/eating/bellymodes_vr.dm
+++ b/modular_citadel/code/modules/vore/eating/bellymodes_vr.dm
@@ -4,10 +4,16 @@
recent_sound = FALSE
return SSBELLIES_IGNORED
+ if(!owner)
+ qdel(src)
+ SSbellies.belly_list -= src
+ return SSBELLIES_PROCESSED
+
if(loc != owner)
- if(istype(owner))
- loc = owner
+ if(isliving(owner)) //we don't have machine based bellies. (yet :honk:)
+ forceMove(owner)
else
+ SSbellies.belly_list -= src
qdel(src)
return SSBELLIES_PROCESSED
@@ -26,10 +32,13 @@
if(isbelly(M.loc))
if(world.time > M.next_preyloop)
if(is_wet)
+ if(!M.client)
+ continue
M.stop_sound_channel(CHANNEL_PREYLOOP) // sanity just in case
- var/sound/preyloop = sound('sound/vore/prey/loop.ogg', repeat = TRUE)
- M.playsound_local(get_turf(src),preyloop,80,0, channel = CHANNEL_PREYLOOP)
- M.next_preyloop = world.time + 52 SECONDS
+ if(M.client.prefs.cit_toggles & DIGESTION_NOISES)
+ var/sound/preyloop = sound('sound/vore/prey/loop.ogg', repeat = TRUE)
+ M.playsound_local(get_turf(src),preyloop, 80,0, channel = CHANNEL_PREYLOOP)
+ M.next_preyloop = (world.time + 52 SECONDS)
/////////////////////////// Exit Early ////////////////////////////
@@ -63,12 +72,12 @@
if(prob(25))
if((world.time - NORMIE_HEARCHECK) > last_hearcheck)
LAZYCLEARLIST(hearing_mobs)
- for(var/mob/H in get_hearers_in_view(3, source))
+ for(var/mob/living/H in get_hearers_in_view(3, source))
if(!H.client || !(H.client.prefs.cit_toggles & DIGESTION_NOISES))
continue
LAZYADD(hearing_mobs, H)
last_hearcheck = world.time
- for(var/mob/H in hearing_mobs)
+ for(var/mob/living/H in hearing_mobs)
if(!isbelly(H.loc))
H.playsound_local(source, null, 45, falloff = 0, S = pred_digest)
else if(H in contents)
@@ -100,12 +109,12 @@
owner.nutrition += 400 // so eating dead mobs gives you *something*.
if((world.time - NORMIE_HEARCHECK) > last_hearcheck)
LAZYCLEARLIST(hearing_mobs)
- for(var/mob/H in get_hearers_in_view(3, source))
+ for(var/mob/living/H in get_hearers_in_view(3, source))
if(!H.client || !(H.client.prefs.cit_toggles & DIGESTION_NOISES))
continue
LAZYADD(hearing_mobs, H)
last_hearcheck = world.time
- for(var/mob/H in hearing_mobs)
+ for(var/mob/living/H in hearing_mobs)
if(!isbelly(H.loc))
H.playsound_local(source, null, 45, falloff = 0, S = pred_death)
else if(H in contents)
@@ -135,12 +144,12 @@
if(prob(25))
if((world.time - NORMIE_HEARCHECK) > last_hearcheck)
LAZYCLEARLIST(hearing_mobs)
- for(var/mob/H in get_hearers_in_view(3, source))
+ for(var/mob/living/H in get_hearers_in_view(3, source))
if(!H.client || !(H.client.prefs.cit_toggles & DIGESTION_NOISES))
continue
LAZYADD(hearing_mobs, H)
last_hearcheck = world.time
- for(var/mob/H in hearing_mobs)
+ for(var/mob/living/H in hearing_mobs)
if(!isbelly(H.loc))
H.playsound_local(source, null, 45, falloff = 0, S = pred_digest)
else if(H in contents)
@@ -159,12 +168,12 @@
if(prob(35))
if((world.time - NORMIE_HEARCHECK) > last_hearcheck)
LAZYCLEARLIST(hearing_mobs)
- for(var/mob/H in get_hearers_in_view(3, source))
+ for(var/mob/living/H in get_hearers_in_view(3, source))
if(!H.client || !(H.client.prefs.cit_toggles & DIGESTION_NOISES))
continue
LAZYADD(hearing_mobs, H)
last_hearcheck = world.time
- for(var/mob/H in hearing_mobs)
+ for(var/mob/living/H in hearing_mobs)
if(!isbelly(H.loc))
H.playsound_local(source, null, 45, falloff = 0, S = pred_digest)
else if(H in contents)
@@ -179,12 +188,12 @@
if(prob(10))//Less often than gurgles. People might leave this on forever.
if((world.time - NORMIE_HEARCHECK) > last_hearcheck)
LAZYCLEARLIST(hearing_mobs)
- for(var/mob/H in get_hearers_in_view(3, source))
+ for(var/mob/living/H in get_hearers_in_view(3, source))
if(!H.client || !(H.client.prefs.cit_toggles & DIGESTION_NOISES))
continue
LAZYADD(hearing_mobs, H)
last_hearcheck = world.time
- for(var/mob/H in hearing_mobs)
+ for(var/mob/living/H in hearing_mobs)
if(!isbelly(H.loc))
H.playsound_local(source, null, 45, falloff = 0, S = pred_digest)
else if(H in contents)
@@ -221,12 +230,12 @@
if(prob(55)) //if you're hearing this, you're a vore ho anyway.
if((world.time - NORMIE_HEARCHECK) > last_hearcheck)
LAZYCLEARLIST(hearing_mobs)
- for(var/mob/H in get_hearers_in_view(3, source))
+ for(var/mob/living/H in get_hearers_in_view(3, source))
if(!H.client || !(H.client.prefs.cit_toggles & DIGESTION_NOISES))
continue
LAZYADD(hearing_mobs, H)
last_hearcheck = world.time
- for(var/mob/H in hearing_mobs)
+ for(var/mob/living/H in hearing_mobs)
if(!isbelly(H.loc))
H.playsound_local(source, null, 45, falloff = 0, S = pred_digest)
else if(H in contents)
@@ -254,12 +263,12 @@
M.visible_message("You watch as [owner]'s guts loudly rumble as it finishes off a meal.")
if((world.time - NORMIE_HEARCHECK) > last_hearcheck)
LAZYCLEARLIST(hearing_mobs)
- for(var/mob/H in get_hearers_in_view(3, source))
+ for(var/mob/living/H in get_hearers_in_view(3, source))
if(!H.client || !(H.client.prefs.cit_toggles & DIGESTION_NOISES))
continue
LAZYADD(hearing_mobs, H)
last_hearcheck = world.time
- for(var/mob/H in hearing_mobs)
+ for(var/mob/living/H in hearing_mobs)
if(!isbelly(H.loc))
H.playsound_local(source, null, 45, falloff = 0, S = pred_death)
else if(H in contents)
diff --git a/modular_citadel/code/modules/vore/eating/living_vr.dm b/modular_citadel/code/modules/vore/eating/living_vr.dm
index a8a77895c8..d9adde04d1 100644
--- a/modular_citadel/code/modules/vore/eating/living_vr.dm
+++ b/modular_citadel/code/modules/vore/eating/living_vr.dm
@@ -60,18 +60,6 @@
B.can_taste = 1
return TRUE
-/*
-// Hide vore organs in contents
-//
-/datum/proc/view_variables_filter_contents(list/L)
- return 0
-
-/mob/living/view_variables_filter_contents(list/L)
- . = ..()
- var/len_before = L.len
- L -= vore_organs
- . += len_before - L.len*/
-
// Handle being clicked, perhaps with something to devour
//
@@ -121,21 +109,12 @@
/mob/living/proc/feed_grabbed_to_self(var/mob/living/user, var/mob/living/prey)
var/belly = user.vore_selected
return perform_the_nom(user, prey, user, belly)
-/*
-/mob/living/proc/eat_held_mob(var/mob/living/user, var/mob/living/prey, var/mob/living/pred)
- var/belly
- if(user != pred)
- belly = input("Choose Belly") in pred.vore_organs
- else
- belly = pred.vore_selected
- return perform_the_nom(user, prey, pred, belly)*/
/mob/living/proc/feed_self_to_grabbed(var/mob/living/user, var/mob/living/pred)
var/belly = input("Choose Belly") in pred.vore_organs
return perform_the_nom(user, user, pred, belly)
/mob/living/proc/feed_grabbed_to_other(var/mob/living/user, var/mob/living/prey, var/mob/living/pred)
-// return//disabled until I can make that toggle work
var/belly = input("Choose Belly") in pred.vore_organs
return perform_the_nom(user, prey, pred, belly)
@@ -182,9 +161,13 @@
// If we got this far, nom successful! Announce it!
user.visible_message(success_msg)
- for(var/mob/M in get_hearers_in_view(5, get_turf(user)))
+
+ // incredibly contentious eating noises time
+ var/turf/source = get_turf(user)
+ var/sound/eating = GLOB.vore_sounds[belly.vore_sound]
+ for(var/mob/living/M in get_hearers_in_view(3, source))
if(M.client && M.client.prefs.cit_toggles & EATING_NOISES)
- playsound(get_turf(user),"[belly.vore_sound]",50,0,-5,0,ignore_walls = FALSE,channel=CHANNEL_PRED)
+ SEND_SOUND(M, eating)
// Actually shove prey into the belly.
belly.nom_mob(prey, user)
@@ -214,41 +197,7 @@
//
//End vore code.
-/*
- //Handle case: /obj/item/holder
- if(/obj/item/holder/micro)
- var/obj/item/holder/H = I
- if(!isliving(user)) return 0 // Return 0 to continue upper procs
- var/mob/living/attacker = user // Typecast to living
-
- if (is_vore_predator(src))
- for (var/mob/living/M in H.contents)
- attacker.eat_held_mob(attacker, M, src)
- return 1 //Return 1 to exit upper procs
- else
- log_attack("[attacker] attempted to feed [H.contents] to [src] ([src.type]) but it failed.")
-
- // I just can't imagine this not being complained about
- //Handle case: /obj/item/radio/beacon
- if(/obj/item/radio/beacon)
- var/confirm = alert(user, "[src == user ? "Eat the beacon?" : "Feed the beacon to [src]?"]", "Confirmation", "Yes!", "Cancel")
- if(confirm == "Yes!")
- var/bellychoice = input("Which belly?","Select A Belly") in src.vore_organs
- var/datum/belly/B = src.vore_organs[bellychoice]
- src.visible_message("[user] is trying to stuff a beacon into [src]'s [bellychoice]!","[user] is trying to stuff a beacon into you!")
- if(do_after(user,30,src))
- user.drop_item()
- I.loc = src
- B.internal_contents += I
- src.visible_message("[src] is fed the beacon!","You're fed the beacon!")
- playsound(get_turf(src), B.vore_sound,50,0,-6,0)
- return 1
- else
- return 1 //You don't get to hit someone 'later'
-
- return 0
-*/
//
// Our custom resist catches for /mob/living
@@ -272,7 +221,7 @@
if(isbelly(loc))
src.stop_sound_channel(CHANNEL_PREYLOOP) // sanity just in case
var/sound/preyloop = sound('sound/vore/prey/loop.ogg', repeat = TRUE)
- src.playsound_local(get_turf(src),preyloop,80,0, channel = CHANNEL_PREYLOOP)
+ SEND_SOUND(src, preyloop)
else
to_chat(src, "You aren't inside anything, you clod.")
diff --git a/modular_citadel/code/modules/vore/eating/vorepanel_vr.dm b/modular_citadel/code/modules/vore/eating/vorepanel_vr.dm
index 6f484e7a51..ae7da895a6 100644
--- a/modular_citadel/code/modules/vore/eating/vorepanel_vr.dm
+++ b/modular_citadel/code/modules/vore/eating/vorepanel_vr.dm
@@ -57,7 +57,7 @@
/datum/vore_look/proc/gen_vui(var/mob/living/user)
var/dat
dat += "Remember to toggle the vore mode, it's to the left of your combat toggle. Open mouth means you're voracious! "
- dat += "Remember that your prey is blind, use audible mode subtle messages to communicate to them with posts! "
+ dat += "Remember that the prey is blind, use audible mode subtle messages to communicate to them with posts! "
dat += " "
var/atom/userloc = user.loc
if (isbelly(userloc))
@@ -554,7 +554,7 @@
if(href_list["b_releasesoundtest"])
var/sound/releasetest = GLOB.release_sounds[selected.release_sound]
if(releasetest)
- user << releasetest
+ SEND_SOUND(user, releasetest)
if(href_list["b_sound"])
var/choice = input(user,"Currently set to [selected.vore_sound]","Select Sound") as null|anything in GLOB.vore_sounds
@@ -567,7 +567,7 @@
if(href_list["b_soundtest"])
var/sound/voretest = GLOB.vore_sounds[selected.vore_sound]
if(voretest)
- user << voretest
+ SEND_SOUND(user, voretest)
if(href_list["b_tastes"])
selected.can_taste = !selected.can_taste
diff --git a/modular_citadel/icons/firstaid.dmi b/modular_citadel/icons/firstaid.dmi
index 693f5a2fa4..e7ac378222 100644
Binary files a/modular_citadel/icons/firstaid.dmi and b/modular_citadel/icons/firstaid.dmi differ
diff --git a/modular_citadel/icons/mob/muzzled_helmet.dmi b/modular_citadel/icons/mob/muzzled_helmet.dmi
index e321f8ae47..a318f394f8 100644
Binary files a/modular_citadel/icons/mob/muzzled_helmet.dmi and b/modular_citadel/icons/mob/muzzled_helmet.dmi differ
diff --git a/modular_citadel/icons/mob/suit_digi.dmi b/modular_citadel/icons/mob/suit_digi.dmi
index 1f1f506d9f..eba761ff79 100644
Binary files a/modular_citadel/icons/mob/suit_digi.dmi and b/modular_citadel/icons/mob/suit_digi.dmi differ
diff --git a/modular_citadel/icons/mob/uniform_digi.dmi b/modular_citadel/icons/mob/uniform_digi.dmi
index 5ff291f400..aea900d110 100644
Binary files a/modular_citadel/icons/mob/uniform_digi.dmi and b/modular_citadel/icons/mob/uniform_digi.dmi differ
diff --git a/modular_citadel/icons/obj/FermiChem.dmi b/modular_citadel/icons/obj/FermiChem.dmi
new file mode 100644
index 0000000000..de7a86d574
Binary files /dev/null and b/modular_citadel/icons/obj/FermiChem.dmi differ
diff --git a/modular_citadel/icons/obj/food/cake.dmi b/modular_citadel/icons/obj/food/cake.dmi
deleted file mode 100644
index 840bfe714d..0000000000
Binary files a/modular_citadel/icons/obj/food/cake.dmi and /dev/null differ
diff --git a/modular_citadel/icons/obj/genitals/breasts.dmi b/modular_citadel/icons/obj/genitals/breasts.dmi
index 8c76891396..d70207ee69 100644
Binary files a/modular_citadel/icons/obj/genitals/breasts.dmi and b/modular_citadel/icons/obj/genitals/breasts.dmi differ
diff --git a/modular_citadel/icons/obj/genitals/breasts_onmob.dmi b/modular_citadel/icons/obj/genitals/breasts_onmob.dmi
index c4b75b1172..371041b6f4 100644
Binary files a/modular_citadel/icons/obj/genitals/breasts_onmob.dmi and b/modular_citadel/icons/obj/genitals/breasts_onmob.dmi differ
diff --git a/modular_citadel/icons/obj/genitals/penis.dmi b/modular_citadel/icons/obj/genitals/penis.dmi
index 397fa335e5..517758b248 100644
Binary files a/modular_citadel/icons/obj/genitals/penis.dmi and b/modular_citadel/icons/obj/genitals/penis.dmi differ
diff --git a/modular_citadel/icons/obj/genitals/penis_onmob.dmi b/modular_citadel/icons/obj/genitals/penis_onmob.dmi
index 434f171e22..416965415d 100644
Binary files a/modular_citadel/icons/obj/genitals/penis_onmob.dmi and b/modular_citadel/icons/obj/genitals/penis_onmob.dmi differ
diff --git a/modular_citadel/icons/obj/genitals/taur_penis_onmob.dmi b/modular_citadel/icons/obj/genitals/taur_penis_onmob.dmi
index 3debbd0047..ae2339e2e0 100644
Binary files a/modular_citadel/icons/obj/genitals/taur_penis_onmob.dmi and b/modular_citadel/icons/obj/genitals/taur_penis_onmob.dmi differ
diff --git a/modular_citadel/icons/obj/genitals/vagina_onmob.dmi b/modular_citadel/icons/obj/genitals/vagina_onmob.dmi
index c4cf891eac..ab71b22e3b 100644
Binary files a/modular_citadel/icons/obj/genitals/vagina_onmob.dmi and b/modular_citadel/icons/obj/genitals/vagina_onmob.dmi differ
diff --git a/modular_citadel/icons/obj/guns/cit_guns.dmi b/modular_citadel/icons/obj/guns/cit_guns.dmi
index cc04fbcb14..bd48d8edbd 100644
Binary files a/modular_citadel/icons/obj/guns/cit_guns.dmi and b/modular_citadel/icons/obj/guns/cit_guns.dmi differ
diff --git a/modular_citadel/icons/obj/vial.dmi b/modular_citadel/icons/obj/vial.dmi
index bc282ab1d3..8d1fefe470 100755
Binary files a/modular_citadel/icons/obj/vial.dmi and b/modular_citadel/icons/obj/vial.dmi differ
diff --git a/modular_citadel/interface/skin.dmf b/modular_citadel/interface/skin.dmf
index e4531a24ea..c5b5138609 100644
--- a/modular_citadel/interface/skin.dmf
+++ b/modular_citadel/interface/skin.dmf
@@ -54,7 +54,7 @@ window "mainwindow"
size = 640x440
anchor1 = none
anchor2 = none
- background-color = #272727
+ background-color = #eeeeee
is-default = true
saved-params = "pos;size;is-minimized;is-maximized"
icon = 'icons\\ss13_64.png'
@@ -66,7 +66,7 @@ window "mainwindow"
size = 637x440
anchor1 = 0,0
anchor2 = 100,100
- background-color = #272727
+ background-color = #eeeeee
saved-params = "splitter"
left = "mapwindow"
right = "infowindow"
@@ -78,7 +78,7 @@ window "mainwindow"
size = 200x200
anchor1 = none
anchor2 = none
- background-color = #272727
+ background-color = #ffffff
is-visible = false
saved-params = ""
elem "tooltip"
@@ -87,7 +87,7 @@ window "mainwindow"
size = 999x999
anchor1 = none
anchor2 = none
- background-color = #272727
+ background-color = #ffffff
is-visible = false
saved-params = ""
@@ -98,7 +98,6 @@ window "mapwindow"
size = 640x480
anchor1 = none
anchor2 = none
- background-color = #272727
saved-params = "pos;size;is-minimized;is-maximized"
is-pane = true
elem "map"
@@ -120,7 +119,7 @@ window "infowindow"
size = 640x480
anchor1 = none
anchor2 = none
- background-color = #272727
+ background-color = #eeeeee
saved-params = "pos;size;is-minimized;is-maximized"
is-pane = true
elem "info"
@@ -129,7 +128,6 @@ window "infowindow"
size = 640x445
anchor1 = 0,0
anchor2 = 100,100
- background-color = #272727
saved-params = "splitter"
left = "statwindow"
right = "outputwindow"
@@ -140,8 +138,7 @@ window "infowindow"
size = 104x20
anchor1 = 3,0
anchor2 = 19,0
- text-color = #ffffff
- background-color = #40628a
+ background-color = #90b3dd
saved-params = "is-checked"
text = "Changelog"
command = "changelog"
@@ -151,8 +148,7 @@ window "infowindow"
size = 100x20
anchor1 = 19,0
anchor2 = 34,0
- text-color = #ffffff
- background-color = #40628a
+ background-color = #90b3dd
saved-params = "is-checked"
text = "Rules"
command = "rules"
@@ -162,8 +158,7 @@ window "infowindow"
size = 100x20
anchor1 = 34,0
anchor2 = 50,0
- text-color = #ffffff
- background-color = #40628a
+ background-color = #90b3dd
saved-params = "is-checked"
text = "Wiki"
command = "wiki"
@@ -173,8 +168,7 @@ window "infowindow"
size = 100x20
anchor1 = 50,0
anchor2 = 66,0
- text-color = #ffffff
- background-color = #40628a
+ background-color = #90b3dd
saved-params = "is-checked"
text = "Forum"
command = "forum"
@@ -184,8 +178,7 @@ window "infowindow"
size = 100x20
anchor1 = 66,0
anchor2 = 81,0
- text-color = #ffffff
- background-color = #40628a
+ background-color = #90b3dd
saved-params = "is-checked"
text = "GitHub"
command = "github"
@@ -196,8 +189,7 @@ window "infowindow"
anchor1 = 81,0
anchor2 = 97,0
font-size = 8
- text-color = #ffffff
- background-color = #40628a
+ background-color = #ef7f7f
saved-params = "is-checked"
text = "Report Issue"
command = "report-issue"
@@ -209,7 +201,7 @@ window "outputwindow"
size = 640x480
anchor1 = none
anchor2 = none
- background-color = #272727
+ background-color = #eeeeee
saved-params = "pos;size;is-minimized;is-maximized"
titlebar = false
statusbar = false
@@ -223,9 +215,9 @@ window "outputwindow"
size = 595x20
anchor1 = 0,100
anchor2 = 100,100
- font-size = 10
background-color = #d3b5b5
is-default = true
+ border = sunken
saved-params = "command"
elem "say"
type = BUTTON
@@ -233,8 +225,7 @@ window "outputwindow"
size = 37x20
anchor1 = 100,100
anchor2 = none
- text-color = #ffffff
- background-color = #272727
+ background-color = #eeeeee
saved-params = "is-checked"
text = "Chat"
command = ".winset \"say.is-checked=true ? input.command=\"!say \\\"\" : input.command=\""
@@ -246,7 +237,7 @@ window "outputwindow"
size = 640x456
anchor1 = 0,0
anchor2 = 100,100
- background-color = #272727
+ background-color = #ffffff
is-visible = false
is-disabled = true
saved-params = ""
@@ -257,8 +248,6 @@ window "outputwindow"
size = 640x456
anchor1 = 0,0
anchor2 = 100,100
- text-color = #40628a
- background-color = #272727
is-default = true
saved-params = ""
@@ -269,7 +258,7 @@ window "statwindow"
size = 640x480
anchor1 = none
anchor2 = none
- background-color = #272727
+ background-color = #eeeeee
saved-params = "pos;size;is-minimized;is-maximized"
is-pane = true
elem "stat"
@@ -278,14 +267,9 @@ window "statwindow"
size = 640x480
anchor1 = 0,0
anchor2 = 100,100
- text-color = #ffffff
- background-color = #383838
is-default = true
saved-params = ""
- tab-text-color = #ffffff
- tab-background-color = #272727
- prefix-color = #ebebeb
- suffix-color = #ebebeb
+ tab-background-color = #eeeeee
window "preferences_window"
elem "preferences_window"
@@ -294,7 +278,6 @@ window "preferences_window"
size = 1280x1000
anchor1 = none
anchor2 = none
- background-color = none
is-visible = false
saved-params = "pos;size;is-minimized;is-maximized"
statusbar = false
@@ -304,7 +287,6 @@ window "preferences_window"
size = 960x1000
anchor1 = 0,0
anchor2 = 75,100
- background-color = none
saved-params = ""
elem "character_preview_map"
type = MAP
diff --git a/sound/FermiChem/SoundSources.txt b/sound/FermiChem/SoundSources.txt
new file mode 100644
index 0000000000..bd45f866f5
--- /dev/null
+++ b/sound/FermiChem/SoundSources.txt
@@ -0,0 +1,10 @@
+heatmelt.ogg - from https://freesound.org/people/toiletrolltube/sounds/181483/
+ from https://freesound.org/people/MrVasLuk/sounds/304619/
+ from https://freesound.org/people/Benboncan/sounds/74899/
+ from bubbles2.ogg
+heatacid.ogg - from https://freesound.org/people/klankbeeld/sounds/233697/
+ from bubbles2.ogg
+ from fuse.ogg
+bufferadd.ogg- https://freesound.org/people/toiletrolltube/sounds/181483/
+
+Work is licensed under the Creative Commons and Attribution License.
\ No newline at end of file
diff --git a/sound/FermiChem/acidmelt.ogg b/sound/FermiChem/acidmelt.ogg
new file mode 100644
index 0000000000..bef257be55
Binary files /dev/null and b/sound/FermiChem/acidmelt.ogg differ
diff --git a/sound/FermiChem/bufferadd.ogg b/sound/FermiChem/bufferadd.ogg
new file mode 100644
index 0000000000..31bc440425
Binary files /dev/null and b/sound/FermiChem/bufferadd.ogg differ
diff --git a/sound/FermiChem/heatmelt.ogg b/sound/FermiChem/heatmelt.ogg
new file mode 100644
index 0000000000..87dab3a18f
Binary files /dev/null and b/sound/FermiChem/heatmelt.ogg differ
diff --git a/sound/effects/femur_breaker.ogg b/sound/effects/femur_breaker.ogg
new file mode 100644
index 0000000000..140dc0477e
Binary files /dev/null and b/sound/effects/femur_breaker.ogg differ
diff --git a/sound/items/towelwhip.ogg b/sound/items/towelwhip.ogg
new file mode 100644
index 0000000000..49dab750a8
Binary files /dev/null and b/sound/items/towelwhip.ogg differ
diff --git a/sound/items/towelwipe.ogg b/sound/items/towelwipe.ogg
new file mode 100644
index 0000000000..2bee55c38d
Binary files /dev/null and b/sound/items/towelwipe.ogg differ
diff --git a/tgstation.dme b/tgstation.dme
index 0146e6a37e..3a2722492d 100755
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -62,6 +62,7 @@
#include "code\__DEFINES\maths.dm"
#include "code\__DEFINES\MC.dm"
#include "code\__DEFINES\medal.dm"
+#include "code\__DEFINES\melee.dm"
#include "code\__DEFINES\menu.dm"
#include "code\__DEFINES\misc.dm"
#include "code\__DEFINES\mobs.dm"
@@ -274,6 +275,7 @@
#include "code\controllers\subsystem\vore.dm"
#include "code\controllers\subsystem\vote.dm"
#include "code\controllers\subsystem\weather.dm"
+#include "code\controllers\subsystem\processing\chemistry.dm"
#include "code\controllers\subsystem\processing\circuit.dm"
#include "code\controllers\subsystem\processing\fastprocess.dm"
#include "code\controllers\subsystem\processing\fields.dm"
@@ -327,6 +329,7 @@
#include "code\datums\actions\beam_rifle.dm"
#include "code\datums\actions\ninja.dm"
#include "code\datums\brain_damage\brain_trauma.dm"
+#include "code\datums\brain_damage\hypnosis.dm"
#include "code\datums\brain_damage\imaginary_friend.dm"
#include "code\datums\brain_damage\mild.dm"
#include "code\datums\brain_damage\phobia.dm"
@@ -426,6 +429,7 @@
#include "code\datums\diseases\advance\symptoms\headache.dm"
#include "code\datums\diseases\advance\symptoms\heal.dm"
#include "code\datums\diseases\advance\symptoms\itching.dm"
+#include "code\datums\diseases\advance\symptoms\nanites.dm"
#include "code\datums\diseases\advance\symptoms\narcolepsy.dm"
#include "code\datums\diseases\advance\symptoms\oxygen.dm"
#include "code\datums\diseases\advance\symptoms\sensory.dm"
@@ -861,6 +865,7 @@
#include "code\game\objects\items\devices\pipe_painter.dm"
#include "code\game\objects\items\devices\powersink.dm"
#include "code\game\objects\items\devices\pressureplates.dm"
+#include "code\game\objects\items\devices\quantum_keycard.dm"
#include "code\game\objects\items\devices\reverse_bear_trap.dm"
#include "code\game\objects\items\devices\scanners.dm"
#include "code\game\objects\items\devices\sensor_device.dm"
@@ -968,6 +973,7 @@
#include "code\game\objects\structures\electricchair.dm"
#include "code\game\objects\structures\extinguisher.dm"
#include "code\game\objects\structures\false_walls.dm"
+#include "code\game\objects\structures\femur_breaker.dm"
#include "code\game\objects\structures\fence.dm"
#include "code\game\objects\structures\fireaxe.dm"
#include "code\game\objects\structures\fireplace.dm"
@@ -986,6 +992,7 @@
#include "code\game\objects\structures\ladders.dm"
#include "code\game\objects\structures\lattice.dm"
#include "code\game\objects\structures\life_candle.dm"
+#include "code\game\objects\structures\loom.dm"
#include "code\game\objects\structures\manned_turret.dm"
#include "code\game\objects\structures\memorial.dm"
#include "code\game\objects\structures\mineral_doors.dm"
@@ -1276,6 +1283,7 @@
#include "code\modules\antagonists\disease\disease_mob.dm"
#include "code\modules\antagonists\ert\ert.dm"
#include "code\modules\antagonists\greentext\greentext.dm"
+#include "code\modules\antagonists\greybois\greybois.dm"
#include "code\modules\antagonists\highlander\highlander.dm"
#include "code\modules\antagonists\monkey\monkey.dm"
#include "code\modules\antagonists\morph\morph.dm"
@@ -1453,6 +1461,7 @@
#include "code\modules\client\client_colour.dm"
#include "code\modules\client\client_defines.dm"
#include "code\modules\client\client_procs.dm"
+#include "code\modules\client\darkmode.dm"
#include "code\modules\client\message.dm"
#include "code\modules\client\player_details.dm"
#include "code\modules\client\preferences.dm"
@@ -1546,7 +1555,6 @@
#include "code\modules\crafting\recipes.dm"
#include "code\modules\detectivework\detective_work.dm"
#include "code\modules\detectivework\evidence.dm"
-#include "code\modules\detectivework\footprints_and_rag.dm"
#include "code\modules\detectivework\scanner.dm"
#include "code\modules\emoji\emoji_parse.dm"
#include "code\modules\error_handler\error_handler.dm"
@@ -1712,6 +1720,7 @@
#include "code\modules\hydroponics\grown\citrus.dm"
#include "code\modules\hydroponics\grown\cocoa_vanilla.dm"
#include "code\modules\hydroponics\grown\corn.dm"
+#include "code\modules\hydroponics\grown\cotton.dm"
#include "code\modules\hydroponics\grown\eggplant.dm"
#include "code\modules\hydroponics\grown\flowers.dm"
#include "code\modules\hydroponics\grown\grass_carpet.dm"
@@ -2081,6 +2090,7 @@
#include "code\modules\mob\living\silicon\robot\robot_movement.dm"
#include "code\modules\mob\living\silicon\robot\say.dm"
#include "code\modules\mob\living\simple_animal\animal_defense.dm"
+#include "code\modules\mob\living\simple_animal\astral.dm"
#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"
@@ -2499,6 +2509,7 @@
#include "code\modules\reagents\reagent_containers\medspray.dm"
#include "code\modules\reagents\reagent_containers\patch.dm"
#include "code\modules\reagents\reagent_containers\pill.dm"
+#include "code\modules\reagents\reagent_containers\rags.dm"
#include "code\modules\reagents\reagent_containers\spray.dm"
#include "code\modules\reagents\reagent_containers\syringes.dm"
#include "code\modules\recycling\conveyor2.dm"
@@ -2830,6 +2841,7 @@
#include "modular_citadel\code\_onclick\item_attack.dm"
#include "modular_citadel\code\_onclick\other_mobs.dm"
#include "modular_citadel\code\_onclick\hud\screen_objects.dm"
+#include "modular_citadel\code\_onclick\hud\sprint.dm"
#include "modular_citadel\code\_onclick\hud\stamina.dm"
#include "modular_citadel\code\controllers\configuration\entries\general.dm"
#include "modular_citadel\code\controllers\subsystem\job.dm"
@@ -2837,11 +2849,14 @@
#include "modular_citadel\code\datums\components\material_container.dm"
#include "modular_citadel\code\datums\components\phantomthief.dm"
#include "modular_citadel\code\datums\components\souldeath.dm"
+#include "modular_citadel\code\datums\mood_events\chem_events.dm"
#include "modular_citadel\code\datums\mood_events\generic_negative_events.dm"
#include "modular_citadel\code\datums\mood_events\generic_positive_events.dm"
#include "modular_citadel\code\datums\mood_events\moodular.dm"
#include "modular_citadel\code\datums\mutations\hulk.dm"
+#include "modular_citadel\code\datums\status_effects\chems.dm"
#include "modular_citadel\code\datums\status_effects\debuffs.dm"
+#include "modular_citadel\code\datums\traits\negative.dm"
#include "modular_citadel\code\datums\traits\neutral.dm"
#include "modular_citadel\code\datums\wires\airlock.dm"
#include "modular_citadel\code\datums\wires\autoylathe.dm"
@@ -2880,7 +2895,6 @@
#include "modular_citadel\code\game\objects\effects\temporary_visuals\projectiles\tracer.dm"
#include "modular_citadel\code\game\objects\items\balls.dm"
#include "modular_citadel\code\game\objects\items\boombox.dm"
-#include "modular_citadel\code\game\objects\items\handcuffs.dm"
#include "modular_citadel\code\game\objects\items\holy_weapons.dm"
#include "modular_citadel\code\game\objects\items\honk.dm"
#include "modular_citadel\code\game\objects\items\meat.dm"
@@ -2891,10 +2905,8 @@
#include "modular_citadel\code\game\objects\items\devices\radio\encryptionkey.dm"
#include "modular_citadel\code\game\objects\items\devices\radio\headset.dm"
#include "modular_citadel\code\game\objects\items\devices\radio\shockcollar.dm"
-#include "modular_citadel\code\game\objects\items\melee\energy.dm"
#include "modular_citadel\code\game\objects\items\melee\eutactic_blades.dm"
#include "modular_citadel\code\game\objects\items\melee\misc.dm"
-#include "modular_citadel\code\game\objects\items\melee\transforming.dm"
#include "modular_citadel\code\game\objects\items\robot\robot_upgrades.dm"
#include "modular_citadel\code\game\objects\items\storage\firstaid.dm"
#include "modular_citadel\code\game\objects\structures\tables_racks.dm"
@@ -2922,7 +2934,6 @@
#include "modular_citadel\code\modules\arousal\toys\dildos.dm"
#include "modular_citadel\code\modules\awaymissions\citadel_ghostrole_spawners.dm"
#include "modular_citadel\code\modules\cargo\console.dm"
-#include "modular_citadel\code\modules\cargo\packs.dm"
#include "modular_citadel\code\modules\client\client_defines.dm"
#include "modular_citadel\code\modules\client\client_procs.dm"
#include "modular_citadel\code\modules\client\preferences.dm"
@@ -2956,7 +2967,6 @@
#include "modular_citadel\code\modules\clothing\under\trek_under.dm"
#include "modular_citadel\code\modules\clothing\under\turtlenecks.dm"
#include "modular_citadel\code\modules\clothing\under\under.dm"
-#include "modular_citadel\code\modules\crafting\recipes.dm"
#include "modular_citadel\code\modules\custom_loadout\custom_items.dm"
#include "modular_citadel\code\modules\custom_loadout\load_to_mob.dm"
#include "modular_citadel\code\modules\custom_loadout\read_from_file.dm"
@@ -2981,16 +2991,15 @@
#include "modular_citadel\code\modules\mentor\mentorhelp.dm"
#include "modular_citadel\code\modules\mentor\mentorpm.dm"
#include "modular_citadel\code\modules\mentor\mentorsay.dm"
-#include "modular_citadel\code\modules\mining\mine_items.dm"
#include "modular_citadel\code\modules\mining\mining_ruins.dm"
#include "modular_citadel\code\modules\mob\cit_emotes.dm"
#include "modular_citadel\code\modules\mob\mob.dm"
#include "modular_citadel\code\modules\mob\dead\new_player\sprite_accessories.dm"
#include "modular_citadel\code\modules\mob\living\damage_procs.dm"
#include "modular_citadel\code\modules\mob\living\living.dm"
-#include "modular_citadel\code\modules\mob\living\status_procs.dm"
#include "modular_citadel\code\modules\mob\living\carbon\carbon.dm"
#include "modular_citadel\code\modules\mob\living\carbon\damage_procs.dm"
+#include "modular_citadel\code\modules\mob\living\carbon\life.dm"
#include "modular_citadel\code\modules\mob\living\carbon\reindex_screams.dm"
#include "modular_citadel\code\modules\mob\living\carbon\human\human.dm"
#include "modular_citadel\code\modules\mob\living\carbon\human\human_defense.dm"
@@ -3017,7 +3026,6 @@
#include "modular_citadel\code\modules\projectiles\bullets\bullets\smg.dm"
#include "modular_citadel\code\modules\projectiles\guns\pumpenergy.dm"
#include "modular_citadel\code\modules\projectiles\guns\toys.dm"
-#include "modular_citadel\code\modules\projectiles\guns\ballistic\flechette.dm"
#include "modular_citadel\code\modules\projectiles\guns\ballistic\handguns.dm"
#include "modular_citadel\code\modules\projectiles\guns\ballistic\magweapon.dm"
#include "modular_citadel\code\modules\projectiles\guns\ballistic\magweapon_energy.dm"
@@ -3028,7 +3036,17 @@
#include "modular_citadel\code\modules\projectiles\guns\energy\laser.dm"
#include "modular_citadel\code\modules\projectiles\projectile\energy.dm"
#include "modular_citadel\code\modules\projectiles\projectiles\reusable.dm"
+#include "modular_citadel\code\modules\reagents\chemistry\reagents\astrogen.dm"
+#include "modular_citadel\code\modules\reagents\chemistry\reagents\eigentstasium.dm"
+#include "modular_citadel\code\modules\reagents\chemistry\reagents\enlargement.dm"
+#include "modular_citadel\code\modules\reagents\chemistry\reagents\fermi_reagents.dm"
+#include "modular_citadel\code\modules\reagents\chemistry\reagents\healing.dm"
+#include "modular_citadel\code\modules\reagents\chemistry\reagents\MKUltra.dm"
#include "modular_citadel\code\modules\reagents\chemistry\reagents\other_reagents.dm"
+#include "modular_citadel\code\modules\reagents\chemistry\reagents\SDGF.dm"
+#include "modular_citadel\code\modules\reagents\chemistry\recipes\fermi.dm"
+#include "modular_citadel\code\modules\reagents\objects\clothes.dm"
+#include "modular_citadel\code\modules\reagents\objects\items.dm"
#include "modular_citadel\code\modules\reagents\reagent container\cit_kegs.dm"
#include "modular_citadel\code\modules\reagents\reagent container\hypospraymkii.dm"
#include "modular_citadel\code\modules\reagents\reagent container\hypovial.dm"
@@ -3040,7 +3058,6 @@
#include "modular_citadel\code\modules\research\designs\xenobio_designs.dm"
#include "modular_citadel\code\modules\research\designs\weapon_designs\weapon_designs.dm"
#include "modular_citadel\code\modules\research\techweb\_techweb.dm"
-#include "modular_citadel\code\modules\research\techweb\all_nodes.dm"
#include "modular_citadel\code\modules\research\xenobiology\xenobio_camera.dm"
#include "modular_citadel\code\modules\vehicles\secway.dm"
#include "modular_citadel\code\modules\vore\hook-defs_vr.dm"
diff --git a/tgui/assets/tgui.css b/tgui/assets/tgui.css
index 256b53c106..c73fc2adfa 100644
--- a/tgui/assets/tgui.css
+++ b/tgui/assets/tgui.css
@@ -1 +1 @@
-@charset "utf-8";body,html{box-sizing:border-box;height:100%;margin:0}html{overflow:hidden;cursor:default}body{overflow:auto;font-family:Verdana,Geneva,sans-serif;font-size:12px;color:#fff;background-color:#2a2a2a;background-image:linear-gradient(180deg,#2a2a2a 0,#202020);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr="#ff2a2a2a",endColorstr="#ff202020",GradientType=0)}*,:after,:before{box-sizing:inherit}h1,h2,h3,h4{display:inline-block;margin:0;padding:6px 0}h1{font-size:18px}h2{font-size:16px}h3{font-size:14px}h4{font-size:12px}body.clockwork{background:linear-gradient(180deg,#b18b25 0,#5f380e);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr="#ffb18b25",endColorstr="#ff5f380e",GradientType=0)}body.clockwork .normal{color:#b18b25}body.clockwork .good{color:#cfba47}body.clockwork .average{color:#896b19}body.clockwork .bad{color:#5f380e}body.clockwork .highlight{color:#b18b25}body.clockwork main{display:block;margin-top:32px;padding:2px 6px 0}body.clockwork hr{height:2px;background-color:#b18b25;border:none}body.clockwork .hidden{display:none}body.clockwork .bar .barText,body.clockwork span.button{color:#b18b25;font-size:12px;font-weight:400;font-style:normal;text-decoration:none}body.clockwork .bold{font-weight:700}body.clockwork .italic{font-style:italic}body.clockwork [unselectable=on]{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}body.clockwork div[data-tooltip],body.clockwork span[data-tooltip]{position:relative}body.clockwork div[data-tooltip]:after,body.clockwork span[data-tooltip]:after{position:absolute;display:block;z-index:2;width:250px;padding:10px;-ms-transform:translateX(-50%);transform:translateX(-50%);visibility:hidden;opacity:0;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";white-space:normal;text-align:left;content:attr(data-tooltip);transition:all .5s;border:1px solid #170800;background-color:#2d1400}body.clockwork div[data-tooltip]:hover:after,body.clockwork span[data-tooltip]:hover:after{visibility:visible;opacity:1;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=100)"}body.clockwork div[data-tooltip].tooltip-top:after,body.clockwork span[data-tooltip].tooltip-top:after{bottom:100%;left:50%;-ms-transform:translateX(-50%) translateY(8px);transform:translateX(-50%) translateY(8px)}body.clockwork div[data-tooltip].tooltip-top:hover:after,body.clockwork span[data-tooltip].tooltip-top:hover:after{-ms-transform:translateX(-50%) translateY(-8px);transform:translateX(-50%) translateY(-8px)}body.clockwork div[data-tooltip].tooltip-bottom:after,body.clockwork span[data-tooltip].tooltip-bottom:after{top:100%;left:50%;-ms-transform:translateX(-50%) translateY(-8px);transform:translateX(-50%) translateY(-8px)}body.clockwork div[data-tooltip].tooltip-bottom:hover:after,body.clockwork span[data-tooltip].tooltip-bottom:hover:after{-ms-transform:translateX(-50%) translateY(8px);transform:translateX(-50%) translateY(8px)}body.clockwork div[data-tooltip].tooltip-left:after,body.clockwork span[data-tooltip].tooltip-left:after{top:50%;right:100%;-ms-transform:translateX(8px) translateY(-50%);transform:translateX(8px) translateY(-50%)}body.clockwork div[data-tooltip].tooltip-left:hover:after,body.clockwork span[data-tooltip].tooltip-left:hover:after{-ms-transform:translateX(-8px) translateY(-50%);transform:translateX(-8px) translateY(-50%)}body.clockwork div[data-tooltip].tooltip-right:after,body.clockwork span[data-tooltip].tooltip-right:after{top:50%;left:100%;-ms-transform:translateX(-8px) translateY(-50%);transform:translateX(-8px) translateY(-50%)}body.clockwork div[data-tooltip].tooltip-right:hover:after,body.clockwork span[data-tooltip].tooltip-right:hover:after{-ms-transform:translateX(8px) translateY(-50%);transform:translateX(8px) translateY(-50%)}body.clockwork .bar{display:inline-block;position:relative;vertical-align:middle;width:100%;height:20px;line-height:17px;padding:1px;border:1px solid #170800;background:#2d1400}body.clockwork .bar .barText{position:absolute;top:0;right:3px}body.clockwork .bar .barFill{display:block;height:100%;transition:background-color 1s;background-color:#b18b25}body.clockwork .bar .barFill.good{background-color:#cfba47}body.clockwork .bar .barFill.average{background-color:#896b19}body.clockwork .bar .barFill.bad{background-color:#5f380e}body.clockwork span.button{display:inline-block;vertical-align:middle;min-height:20px;line-height:17px;padding:0 5px;white-space:nowrap;border:1px solid #170800}body.clockwork span.button .fa{padding-right:2px}body.clockwork span.button.normal{transition:background-color .5s;background-color:#5f380e}body.clockwork span.button.normal.active:focus,body.clockwork span.button.normal.active:hover{transition:background-color .25s;background-color:#704211;outline:0}body.clockwork span.button.disabled{transition:background-color .5s;background-color:#2d1400}body.clockwork span.button.disabled.active:focus,body.clockwork span.button.disabled.active:hover{transition:background-color .25s;background-color:#441e00;outline:0}body.clockwork span.button.selected{transition:background-color .5s;background-color:#cfba47}body.clockwork span.button.selected.active:focus,body.clockwork span.button.selected.active:hover{transition:background-color .25s;background-color:#d1bd50;outline:0}body.clockwork span.button.toggle{transition:background-color .5s;background-color:#cfba47}body.clockwork span.button.toggle.active:focus,body.clockwork span.button.toggle.active:hover{transition:background-color .25s;background-color:#d1bd50;outline:0}body.clockwork span.button.caution{transition:background-color .5s;background-color:#be6209}body.clockwork span.button.caution.active:focus,body.clockwork span.button.caution.active:hover{transition:background-color .25s;background-color:#cd6a0a;outline:0}body.clockwork span.button.danger{transition:background-color .5s;background-color:#9a9d00}body.clockwork span.button.danger.active:focus,body.clockwork span.button.danger.active:hover{transition:background-color .25s;background-color:#abaf00;outline:0}body.clockwork span.button.gridable{width:125px;margin:2px 0}body.clockwork span.button.gridable.center{text-align:center;width:75px}body.clockwork span.button+span:not(.button),body.clockwork span:not(.button)+span.button{margin-left:5px}body.clockwork div.display{width:100%;padding:4px;margin:6px 0;background-color:#2d1400;-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorStr=#e62d1400,endColorStr=#e62d1400)";filter:progid:DXImageTransform.Microsoft.gradient(startColorStr=#e62d1400,endColorStr=#e62d1400);background-color:rgba(45,20,0,.9);box-shadow:inset 0 0 5px rgba(0,0,0,.3)}body.clockwork div.display.tabular{padding:0;margin:0}body.clockwork div.display header,body.clockwork div.subdisplay header{display:block;position:relative;width:100%;padding:0 4px;margin-bottom:6px;color:#cfba47;border-bottom:2px solid #b18b25}body.clockwork div.display header .buttonRight,body.clockwork div.subdisplay header .buttonRight{position:absolute;bottom:6px;right:4px}body.clockwork div.display article,body.clockwork div.subdisplay article{display:table;width:100%;border-collapse:collapse}body.clockwork input{display:inline-block;vertical-align:middle;height:20px;line-height:17px;padding:0 5px;white-space:nowrap;color:#b18b25;background-color:#cfba47;border:1px solid #272727}body.clockwork input.number{width:35px}body.clockwork input:-ms-input-placeholder{color:#999}body.clockwork input::placeholder{color:#999}body.clockwork input::-ms-clear{display:none}body.clockwork svg.linegraph{overflow:hidden}body.clockwork div.notice{margin:8px 0;padding:4px;box-shadow:none;color:#2d1400;font-weight:700;font-style:italic;background-color:#000;background-image:repeating-linear-gradient(-45deg,#000,#000 10px,#170800 0,#170800 20px)}body.clockwork div.notice .label{color:#2d1400}body.clockwork div.notice .content:only-of-type{padding:0}body.clockwork div.notice hr{background-color:#896b19}body.clockwork div.resize{position:fixed;bottom:0;right:0;width:0;height:0;border-style:solid;border-width:0 0 45px 45px;border-color:transparent transparent #5f380e;-ms-transform:rotate(1turn);transform:rotate(1turn)}body.clockwork section .cell,body.clockwork section .content,body.clockwork section .label,body.clockwork section .line,body.nanotrasen section .cell,body.nanotrasen section .content,body.nanotrasen section .label,body.nanotrasen section .line,body.syndicate section .cell,body.syndicate section .content,body.syndicate section .label,body.syndicate section .line{display:table-cell;margin:0;text-align:left;vertical-align:middle;padding:3px 2px}body.clockwork section{display:table-row;width:100%}body.clockwork section:not(:first-child){padding-top:4px}body.clockwork section.candystripe:nth-child(2n){background-color:#000;-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorStr=#33000000,endColorStr=#33000000)";filter:progid:DXImageTransform.Microsoft.gradient(startColorStr=#33000000,endColorStr=#33000000);background-color:rgba(0,0,0,.2)}body.clockwork section .label{width:1%;padding-right:32px;white-space:nowrap;color:#b18b25}body.clockwork section .content:not(:last-child){padding-right:16px}body.clockwork section .line{width:100%}body.clockwork section .cell:not(:first-child){text-align:center;padding-top:0}body.clockwork section .cell span.button{width:75px}body.clockwork section:not(:last-child){padding-right:4px}body.clockwork div.subdisplay{width:100%;margin:0}body.clockwork header.titlebar .close,body.clockwork header.titlebar .minimize{display:inline-block;position:relative;padding:7px;margin:-7px;color:#cfba47}body.clockwork header.titlebar .close:hover,body.clockwork header.titlebar .minimize:hover{color:#d1bd50}body.clockwork header.titlebar{position:fixed;z-index:1;top:0;left:0;width:100%;height:32px;background-color:#5f380e;border-bottom:1px solid #170800;box-shadow:0 3px 3px rgba(0,0,0,.1)}body.clockwork header.titlebar .statusicon{position:absolute;top:4px;left:12px;transition:color .5s}body.clockwork header.titlebar .title{position:absolute;top:6px;left:46px;color:#cfba47;font-size:16px;white-space:nowrap}body.clockwork header.titlebar .minimize{position:absolute;top:6px;right:46px}body.clockwork header.titlebar .close{position:absolute;top:4px;right:12px}body.nanotrasen{background:url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+DQo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmVyc2lvbj0iMS4wIiB2aWV3Qm94PSIwIDAgNDI1IDIwMCIgb3BhY2l0eT0iLjMzIj4NCiAgPHBhdGggZD0ibSAxNzguMDAzOTksMC4wMzg2OSAtNzEuMjAzOTMsMCBhIDYuNzYxMzQyMiw2LjAyNTU0OTUgMCAwIDAgLTYuNzYxMzQsNi4wMjU1NSBsIDAsMTg3Ljg3MTQ3IGEgNi43NjEzNDIyLDYuMDI1NTQ5NSAwIDAgMCA2Ljc2MTM0LDYuMDI1NTQgbCA1My4xMDcyLDAgYSA2Ljc2MTM0MjIsNi4wMjU1NDk1IDAgMCAwIDYuNzYxMzUsLTYuMDI1NTQgbCAwLC0xMDEuNTQ0MDE4IDcyLjIxNjI4LDEwNC42OTkzOTggYSA2Ljc2MTM0MjIsNi4wMjU1NDk1IDAgMCAwIDUuNzYwMTUsMi44NzAxNiBsIDczLjU1NDg3LDAgYSA2Ljc2MTM0MjIsNi4wMjU1NDk1IDAgMCAwIDYuNzYxMzUsLTYuMDI1NTQgbCAwLC0xODcuODcxNDcgYSA2Ljc2MTM0MjIsNi4wMjU1NDk1IDAgMCAwIC02Ljc2MTM1LC02LjAyNTU1IGwgLTU0LjcxNjQ0LDAgYSA2Ljc2MTM0MjIsNi4wMjU1NDk1IDAgMCAwIC02Ljc2MTMzLDYuMDI1NTUgbCAwLDEwMi42MTkzNSBMIDE4My43NjQxMywyLjkwODg2IGEgNi43NjEzNDIyLDYuMDI1NTQ5NSAwIDAgMCAtNS43NjAxNCwtMi44NzAxNyB6IiAvPg0KICA8cGF0aCBkPSJNIDQuODQ0NjMzMywyMi4xMDg3NSBBIDEzLjQxMjAzOSwxMi41MDE4NDIgMCAwIDEgMTMuNDc3NTg4LDAuMDM5MjQgbCA2Ni4xMTgzMTUsMCBhIDUuMzY0ODE1OCw1LjAwMDczNyAwIDAgMSA1LjM2NDgyMyw1LjAwMDczIGwgMCw3OS44NzkzMSB6IiAvPg0KICA8cGF0aCBkPSJtIDQyMC4xNTUzNSwxNzcuODkxMTkgYSAxMy40MTIwMzgsMTIuNTAxODQyIDAgMCAxIC04LjYzMjk1LDIyLjA2OTUxIGwgLTY2LjExODMyLDAgYSA1LjM2NDgxNTIsNS4wMDA3MzcgMCAwIDEgLTUuMzY0ODIsLTUuMDAwNzQgbCAwLC03OS44NzkzMSB6IiAvPg0KPC9zdmc+DQo8IS0tIFRoaXMgd29yayBpcyBsaWNlbnNlZCB1bmRlciBhIENyZWF0aXZlIENvbW1vbnMgQXR0cmlidXRpb24tU2hhcmVBbGlrZSA0LjAgSW50ZXJuYXRpb25hbCBMaWNlbnNlLiAtLT4NCjwhLS0gaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbGljZW5zZXMvYnktc2EvNC4wLyAtLT4NCg==") no-repeat fixed 50%/70% 70%,linear-gradient(180deg,#2a2a2a 0,#202020);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr="#ff2a2a2a",endColorstr="#ff202020",GradientType=0)}body.nanotrasen .normal{color:#40628a}body.nanotrasen .good{color:#537d29}body.nanotrasen .average{color:#be6209}body.nanotrasen .bad{color:#b00e0e}body.nanotrasen .highlight{color:#8ba5c4}body.nanotrasen main{display:block;margin-top:32px;padding:2px 6px 0}body.nanotrasen hr{height:2px;background-color:#40628a;border:none}body.nanotrasen .hidden{display:none}body.nanotrasen .bar .barText,body.nanotrasen span.button{color:#fff;font-size:12px;font-weight:400;font-style:normal;text-decoration:none}body.nanotrasen .bold{font-weight:700}body.nanotrasen .italic{font-style:italic}body.nanotrasen [unselectable=on]{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}body.nanotrasen div[data-tooltip],body.nanotrasen span[data-tooltip]{position:relative}body.nanotrasen div[data-tooltip]:after,body.nanotrasen span[data-tooltip]:after{position:absolute;display:block;z-index:2;width:250px;padding:10px;-ms-transform:translateX(-50%);transform:translateX(-50%);visibility:hidden;opacity:0;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";white-space:normal;text-align:left;content:attr(data-tooltip);transition:all .5s;border:1px solid #272727;background-color:#363636}body.nanotrasen div[data-tooltip]:hover:after,body.nanotrasen span[data-tooltip]:hover:after{visibility:visible;opacity:1;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=100)"}body.nanotrasen div[data-tooltip].tooltip-top:after,body.nanotrasen span[data-tooltip].tooltip-top:after{bottom:100%;left:50%;-ms-transform:translateX(-50%) translateY(8px);transform:translateX(-50%) translateY(8px)}body.nanotrasen div[data-tooltip].tooltip-top:hover:after,body.nanotrasen span[data-tooltip].tooltip-top:hover:after{-ms-transform:translateX(-50%) translateY(-8px);transform:translateX(-50%) translateY(-8px)}body.nanotrasen div[data-tooltip].tooltip-bottom:after,body.nanotrasen span[data-tooltip].tooltip-bottom:after{top:100%;left:50%;-ms-transform:translateX(-50%) translateY(-8px);transform:translateX(-50%) translateY(-8px)}body.nanotrasen div[data-tooltip].tooltip-bottom:hover:after,body.nanotrasen span[data-tooltip].tooltip-bottom:hover:after{-ms-transform:translateX(-50%) translateY(8px);transform:translateX(-50%) translateY(8px)}body.nanotrasen div[data-tooltip].tooltip-left:after,body.nanotrasen span[data-tooltip].tooltip-left:after{top:50%;right:100%;-ms-transform:translateX(8px) translateY(-50%);transform:translateX(8px) translateY(-50%)}body.nanotrasen div[data-tooltip].tooltip-left:hover:after,body.nanotrasen span[data-tooltip].tooltip-left:hover:after{-ms-transform:translateX(-8px) translateY(-50%);transform:translateX(-8px) translateY(-50%)}body.nanotrasen div[data-tooltip].tooltip-right:after,body.nanotrasen span[data-tooltip].tooltip-right:after{top:50%;left:100%;-ms-transform:translateX(-8px) translateY(-50%);transform:translateX(-8px) translateY(-50%)}body.nanotrasen div[data-tooltip].tooltip-right:hover:after,body.nanotrasen span[data-tooltip].tooltip-right:hover:after{-ms-transform:translateX(8px) translateY(-50%);transform:translateX(8px) translateY(-50%)}body.nanotrasen .bar{display:inline-block;position:relative;vertical-align:middle;width:100%;height:20px;line-height:17px;padding:1px;border:1px solid #40628a;background:#272727}body.nanotrasen .bar .barText{position:absolute;top:0;right:3px}body.nanotrasen .bar .barFill{display:block;height:100%;transition:background-color 1s;background-color:#40628a}body.nanotrasen .bar .barFill.good{background-color:#537d29}body.nanotrasen .bar .barFill.average{background-color:#be6209}body.nanotrasen .bar .barFill.bad{background-color:#b00e0e}body.nanotrasen span.button{display:inline-block;vertical-align:middle;min-height:20px;line-height:17px;padding:0 5px;white-space:nowrap;border:1px solid #272727}body.nanotrasen span.button .fa{padding-right:2px}body.nanotrasen span.button.normal{transition:background-color .5s;background-color:#40628a}body.nanotrasen span.button.normal.active:focus,body.nanotrasen span.button.normal.active:hover{transition:background-color .25s;background-color:#4f78aa;outline:0}body.nanotrasen span.button.disabled{transition:background-color .5s;background-color:#999}body.nanotrasen span.button.disabled.active:focus,body.nanotrasen span.button.disabled.active:hover{transition:background-color .25s;background-color:#a8a8a8;outline:0}body.nanotrasen span.button.selected{transition:background-color .5s;background-color:#2f943c}body.nanotrasen span.button.selected.active:focus,body.nanotrasen span.button.selected.active:hover{transition:background-color .25s;background-color:#3ab84b;outline:0}body.nanotrasen span.button.toggle{transition:background-color .5s;background-color:#2f943c}body.nanotrasen span.button.toggle.active:focus,body.nanotrasen span.button.toggle.active:hover{transition:background-color .25s;background-color:#3ab84b;outline:0}body.nanotrasen span.button.caution{transition:background-color .5s;background-color:#9a9d00}body.nanotrasen span.button.caution.active:focus,body.nanotrasen span.button.caution.active:hover{transition:background-color .25s;background-color:#ced200;outline:0}body.nanotrasen span.button.danger{transition:background-color .5s;background-color:#9d0808}body.nanotrasen span.button.danger.active:focus,body.nanotrasen span.button.danger.active:hover{transition:background-color .25s;background-color:#ce0b0b;outline:0}body.nanotrasen span.button.gridable{width:125px;margin:2px 0}body.nanotrasen span.button.gridable.center{text-align:center;width:75px}body.nanotrasen span.button+span:not(.button),body.nanotrasen span:not(.button)+span.button{margin-left:5px}body.nanotrasen div.display{width:100%;padding:4px;margin:6px 0;background-color:#000;-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorStr=#54000000,endColorStr=#54000000)";filter:progid:DXImageTransform.Microsoft.gradient(startColorStr=#54000000,endColorStr=#54000000);background-color:rgba(0,0,0,.33);box-shadow:inset 0 0 5px rgba(0,0,0,.5)}body.nanotrasen div.display.tabular{padding:0;margin:0}body.nanotrasen div.display header,body.nanotrasen div.subdisplay header{display:block;position:relative;width:100%;padding:0 4px;margin-bottom:6px;color:#fff;border-bottom:2px solid #40628a}body.nanotrasen div.display header .buttonRight,body.nanotrasen div.subdisplay header .buttonRight{position:absolute;bottom:6px;right:4px}body.nanotrasen div.display article,body.nanotrasen div.subdisplay article{display:table;width:100%;border-collapse:collapse}body.nanotrasen input{display:inline-block;vertical-align:middle;height:20px;line-height:17px;padding:0 5px;white-space:nowrap;color:#000;background-color:#fff;border:1px solid #272727}body.nanotrasen input.number{width:35px}body.nanotrasen input:-ms-input-placeholder{color:#999}body.nanotrasen input::placeholder{color:#999}body.nanotrasen input::-ms-clear{display:none}body.nanotrasen svg.linegraph{overflow:hidden}body.nanotrasen div.notice{margin:8px 0;padding:4px;box-shadow:none;color:#000;font-weight:700;font-style:italic;background-color:#bb9b68;background-image:repeating-linear-gradient(-45deg,#bb9b68,#bb9b68 10px,#b1905d 0,#b1905d 20px)}body.nanotrasen div.notice .label{color:#000}body.nanotrasen div.notice .content:only-of-type{padding:0}body.nanotrasen div.notice hr{background-color:#272727}body.nanotrasen div.resize{position:fixed;bottom:0;right:0;width:0;height:0;border-style:solid;border-width:0 0 45px 45px;border-color:transparent transparent #363636;-ms-transform:rotate(1turn);transform:rotate(1turn)}body.nanotrasen section .cell,body.nanotrasen section .content,body.nanotrasen section .label,body.nanotrasen section .line,body.syndicate section .cell,body.syndicate section .content,body.syndicate section .label,body.syndicate section .line{display:table-cell;margin:0;text-align:left;vertical-align:middle;padding:3px 2px}body.nanotrasen section{display:table-row;width:100%}body.nanotrasen section:not(:first-child){padding-top:4px}body.nanotrasen section.candystripe:nth-child(2n){background-color:#000;-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorStr=#33000000,endColorStr=#33000000)";filter:progid:DXImageTransform.Microsoft.gradient(startColorStr=#33000000,endColorStr=#33000000);background-color:rgba(0,0,0,.2)}body.nanotrasen section .label{width:1%;padding-right:32px;white-space:nowrap;color:#8ba5c4}body.nanotrasen section .content:not(:last-child){padding-right:16px}body.nanotrasen section .line{width:100%}body.nanotrasen section .cell:not(:first-child){text-align:center;padding-top:0}body.nanotrasen section .cell span.button{width:75px}body.nanotrasen section:not(:last-child){padding-right:4px}body.nanotrasen div.subdisplay{width:100%;margin:0}body.nanotrasen header.titlebar .close,body.nanotrasen header.titlebar .minimize{display:inline-block;position:relative;padding:7px;margin:-7px;color:#8ba5c4}body.nanotrasen header.titlebar .close:hover,body.nanotrasen header.titlebar .minimize:hover{color:#9cb2cd}body.nanotrasen header.titlebar{position:fixed;z-index:1;top:0;left:0;width:100%;height:32px;background-color:#363636;border-bottom:1px solid #161616;box-shadow:0 3px 3px rgba(0,0,0,.1)}body.nanotrasen header.titlebar .statusicon{position:absolute;top:4px;left:12px;transition:color .5s}body.nanotrasen header.titlebar .title{position:absolute;top:6px;left:46px;color:#8ba5c4;font-size:16px;white-space:nowrap}body.nanotrasen header.titlebar .minimize{position:absolute;top:6px;right:46px}body.nanotrasen header.titlebar .close{position:absolute;top:4px;right:12px}body.syndicate{background:url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+DQo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmVyc2lvbj0iMS4wIiB2aWV3Qm94PSIwIDAgMjAwIDI4OS43NDIiIG9wYWNpdHk9Ii4zMyI+DQogIDxwYXRoIGQ9Im0gOTMuNTM3Njc3LDAgYyAtMTguMTEzMTI1LDAgLTM0LjIyMDEzMywzLjExMTY0IC00OC4zMjM0ODQsOS4zMzQzNyAtMTMuOTY1MDkyLDYuMjIxNjcgLTI0LjYxMjQ0MiwxNS4wNzExNCAtMzEuOTQwNjUxLDI2LjU0NzEgLTcuMTg5OTM5OCwxMS4zMzc4OSAtMTAuMzAxMjI2NiwyNC43NDkxMSAtMTAuMzAxMjI2Niw0MC4yMzQ3OCAwLDEwLjY0NjYyIDIuNzI1MDAyNiwyMC40NjQ2NSA4LjE3NTExMTYsMjkuNDUyNTggNS42MTUyNzcsOC45ODY4NiAxNC4wMzgyNzcsMTcuMzUyMDQgMjUuMjY4ODIxLDI1LjA5NDM2IDExLjIzMDU0NCw3LjYwNTMxIDI2LjUwNzQyMSwxNS40MTgzNSA0NS44MzA1MTQsMjMuNDM3ODIgMTkuOTgzNzQ4LDguMjk1NTcgMzQuODQ4ODQ4LDE1LjU1NDcxIDQ0LjU5Mjk5OCwyMS43NzYzOCA5Ljc0NDE0LDYuMjIyNzMgMTYuNzYxNywxMi44NTg1IDIxLjA1NTcyLDE5LjkwOTUxIDQuMjk0MDQsNy4wNTIwOCA2LjQ0MTkzLDE1Ljc2NDA4IDYuNDQxOTMsMjYuMTM0NTkgMCwxNi4xNzcwMiAtNS4yMDE5NiwyOC40ODIyMiAtMTUuNjA2NzMsMzYuOTE2ODIgLTEwLjIzOTYsOC40MzQ3IC0yNS4wMjIwMywxMi42NTIzIC00NC4zNDUxNjksMTIuNjUyMyAtMTQuMDM4MTcxLDAgLTI1LjUxNTI0NywtMS42NTk0IC0zNC40MzM2MTgsLTQuOTc3NyAtOC45MTgzNywtMy40NTY2IC0xNi4xODU1NzIsLTguNzExMyAtMjEuODAwODM5LC0xNS43NjMzIC01LjYxNTI3NywtNy4wNTIxIC0xMC4wNzQ3OTUsLTE2LjY2MDg4IC0xMy4zNzc4OTksLTI4LjgyODEyIGwgLTI0Ljc3MzE2MjYyOTM5NDUsMCAwLDU2LjgyNjMyIEMgMzMuODU2NzY5LDI4Ni4wNzYwMSA2My43NDkwNCwyODkuNzQyMDEgODkuNjc4MzgzLDI4OS43NDIwMSBjIDE2LjAyMDAyNywwIDMwLjcxOTc4NywtMS4zODI3IDQ0LjA5NzMzNywtNC4xNDc5IDEzLjU0MjcyLC0yLjkwNDMgMjUuMTA0MSwtNy40Njc2IDM0LjY4MzA5LC0xMy42ODkzIDkuNzQ0MTMsLTYuMzU5NyAxNy4zNDA0MiwtMTQuNTE5NSAyMi43OTA1MiwtMjQuNDc0OCA1LjQ1MDEsLTEwLjA5MzMyIDguMTc1MTEsLTIyLjM5OTU5IDguMTc1MTEsLTM2LjkxNjgyIDAsLTEyLjk5NzY0IC0zLjMwMjEsLTI0LjMzNTM5IC05LjkwODI5LC0zNC4wMTQ2IC02LjQ0MTA1LC05LjgxNzI1IC0xNS41MjU0NSwtMTguNTI3MDcgLTI3LjI1MTQ2LC0yNi4xMzEzMyAtMTEuNTYwODUsLTcuNjA0MjcgLTI3LjkxMDgzLC0xNS44MzE0MiAtNDkuMDUwNjYsLTI0LjY4MDIyIC0xNy41MDY0NCwtNy4xOTAxMiAtMzAuNzE5NjY4LC0xMy42ODk0OCAtMzkuNjM4MDM4LC0xOS40OTcwMSAtOC45MTgzNzEsLTUuODA3NTIgLTE4LjYwNzQ3NCwtMTIuNDM0MDkgLTI0LjA5NjUyNCwtMTguODc0MTcgLTUuNDI2MDQzLC02LjM2NjE2IC05LjY1ODgyNiwtMTUuMDcwMDMgLTkuNjU4ODI2LC0yNC44ODcyOSAwLC05LjI2NDAxIDIuMDc1NDE0LC0xNy4yMTM0NSA2LjIyMzQ1NCwtMjMuODUwMzMgMTEuMDk4Mjk4LC0xNC4zOTc0OCA0MS4yODY2MzgsLTEuNzk1MDcgNDUuMDc1NjA5LDI0LjM0NzYyIDQuODM5MzkyLDYuNzc0OTEgOC44NDkzNSwxNi4yNDcyOSAxMi4wMjk1MTUsMjguNDE1NiBsIDIwLjUzMjM0LDAgMCwtNTUuOTk5NjcgYyAtNC40NzgyNSwtNS45MjQ0OCAtOS45NTQ4OCwtMTAuNjMyMjIgLTE1LjkwODM3LC0xNC4zNzQxMSAxLjY0MDU1LDAuNDc5MDUgMy4xOTAzOSwxLjAyMzc2IDQuNjM4NjUsMS42NDAyNCA2LjQ5ODYxLDIuNjI2MDcgMTIuMTY3OTMsNy4zMjc0NyAxNy4wMDczLDE0LjEwMzQ1IDQuODM5MzksNi43NzQ5MSA4Ljg0OTM1LDE2LjI0NTY3IDEyLjAyOTUyLDI4LjQxMzk3IDAsMCA4LjQ4MTI4LC0wLjEyODk0IDguNDg5NzgsLTAuMDAyIDAuNDE3NzYsNi40MTQ5NCAtMS43NTMzOSw5LjQ1Mjg2IC00LjEyMzQyLDEyLjU2MTA0IC0yLjQxNzQsMy4xNjk3OCAtNS4xNDQ4Niw2Ljc4OTczIC00LjAwMjc4LDEzLjAwMjkgMS41MDc4Niw4LjIwMzE4IDEwLjE4MzU0LDEwLjU5NjQyIDE0LjYyMTk0LDkuMzExNTQgLTMuMzE4NDIsLTAuNDk5MTEgLTUuMzE4NTUsLTEuNzQ5NDggLTUuMzE4NTUsLTEuNzQ5NDggMCwwIDEuODc2NDYsMC45OTg2OCA1LjY1MTE3LC0xLjM1OTgxIC0zLjI3Njk1LDAuOTU1NzEgLTEwLjcwNTI5LC0wLjc5NzM4IC0xMS44MDEyNSwtNi43NjMxMyAtMC45NTc1MiwtNS4yMDg2MSAwLjk0NjU0LC03LjI5NTE0IDMuNDAxMTMsLTEwLjUxNDgyIDIuNDU0NjIsLTMuMjE5NjggNS4yODQyNiwtNi45NTgzMSA0LjY4NDMsLTE0LjQ4ODI0IGwgMC4wMDMsMC4wMDIgOC45MjY3NiwwIDAsLTU1Ljk5OTY3IGMgLTE1LjA3MTI1LC0zLjg3MTY4IC0yNy42NTMxNCwtNi4zNjA0MiAtMzcuNzQ2NzEsLTcuNDY1ODYgLTkuOTU1MzEsLTEuMTA3NTUgLTIwLjE4ODIzLC0xLjY1OTgxIC0zMC42OTY2MTMsLTEuNjU5ODEgeiBtIDcwLjMyMTYwMywxNy4zMDg5MyAwLjIzODA1LDQwLjMwNDkgYyAxLjMxODA4LDEuMjI2NjYgMi40Mzk2NSwyLjI3ODE1IDMuMzQwODEsMy4xMDYwMiA0LjgzOTM5LDYuNzc0OTEgOC44NDkzNCwxNi4yNDU2NiAxMi4wMjk1MSwyOC40MTM5NyBsIDIwLjUzMjM0LDAgMCwtNTUuOTk5NjcgYyAtNi42NzczMSwtNC41OTM4MSAtMTkuODM2NDMsLTEwLjQ3MzA5IC0zNi4xNDA3MSwtMTUuODI1MjIgeiBtIC0yOC4xMjA0OSw1LjYwNTUxIDguNTY0NzksMTcuNzE2NTUgYyAtMTEuOTcwMzcsLTYuNDY2OTcgLTEzLjg0Njc4LC05LjcxNzI2IC04LjU2NDc5LC0xNy43MTY1NSB6IG0gMjIuNzk3MDUsMCBjIDIuNzcxNSw3Ljk5OTI5IDEuNzg3NDEsMTEuMjQ5NTggLTQuNDkzNTQsMTcuNzE2NTUgbCA0LjQ5MzU0LC0xNy43MTY1NSB6IG0gMTUuMjIxOTUsMjQuMDA4NDggOC41NjQ3OSwxNy43MTY1NSBjIC0xMS45NzAzOCwtNi40NjY5NyAtMTMuODQ2NzksLTkuNzE3MjYgLTguNTY0NzksLTE3LjcxNjU1IHogbSAyMi43OTcwNCwwIGMgMi43NzE1LDcuOTk5MjkgMS43ODc0MSwxMS4yNDk1OCAtNC40OTM1NCwxNy43MTY1NSBsIDQuNDkzNTQsLTE3LjcxNjU1IHogbSAtOTkuMTEzODQsMi4yMDc2NCA4LjU2NDc5LDE3LjcxNjU1IGMgLTExLjk3MDM4MiwtNi40NjY5NyAtMTMuODQ2NzgyLC05LjcxNzI2IC04LjU2NDc5LC0xNy43MTY1NSB6IG0gMjIuNzk1NDIsMCBjIDIuNzcxNSw3Ljk5OTI5IDEuNzg3NDEsMTEuMjQ5NTggLTQuNDkzNTQsMTcuNzE2NTUgbCA0LjQ5MzU0LC0xNy43MTY1NSB6IiAvPg0KPC9zdmc+DQo8IS0tIFRoaXMgd29yayBpcyBsaWNlbnNlZCB1bmRlciBhIENyZWF0aXZlIENvbW1vbnMgQXR0cmlidXRpb24tU2hhcmVBbGlrZSA0LjAgSW50ZXJuYXRpb25hbCBMaWNlbnNlLiAtLT4NCjwhLS0gaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbGljZW5zZXMvYnktc2EvNC4wLyAtLT4NCg==") no-repeat fixed 50%/70% 70%,linear-gradient(180deg,#750000 0,#340404);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr="#ff750000",endColorstr="#ff340404",GradientType=0)}body.syndicate .normal{color:#40628a}body.syndicate .good{color:#73e573}body.syndicate .average{color:#be6209}body.syndicate .bad{color:#b00e0e}body.syndicate .highlight{color:#000}body.syndicate main{display:block;margin-top:32px;padding:2px 6px 0}body.syndicate hr{height:2px;background-color:#272727;border:none}body.syndicate .hidden{display:none}body.syndicate .bar .barText,body.syndicate span.button{color:#fff;font-size:12px;font-weight:400;font-style:normal;text-decoration:none}body.syndicate .bold{font-weight:700}body.syndicate .italic{font-style:italic}body.syndicate [unselectable=on]{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}body.syndicate div[data-tooltip],body.syndicate span[data-tooltip]{position:relative}body.syndicate div[data-tooltip]:after,body.syndicate span[data-tooltip]:after{position:absolute;display:block;z-index:2;width:250px;padding:10px;-ms-transform:translateX(-50%);transform:translateX(-50%);visibility:hidden;opacity:0;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";white-space:normal;text-align:left;content:attr(data-tooltip);transition:all .5s;border:1px solid #272727;background-color:#363636}body.syndicate div[data-tooltip]:hover:after,body.syndicate span[data-tooltip]:hover:after{visibility:visible;opacity:1;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=100)"}body.syndicate div[data-tooltip].tooltip-top:after,body.syndicate span[data-tooltip].tooltip-top:after{bottom:100%;left:50%;-ms-transform:translateX(-50%) translateY(8px);transform:translateX(-50%) translateY(8px)}body.syndicate div[data-tooltip].tooltip-top:hover:after,body.syndicate span[data-tooltip].tooltip-top:hover:after{-ms-transform:translateX(-50%) translateY(-8px);transform:translateX(-50%) translateY(-8px)}body.syndicate div[data-tooltip].tooltip-bottom:after,body.syndicate span[data-tooltip].tooltip-bottom:after{top:100%;left:50%;-ms-transform:translateX(-50%) translateY(-8px);transform:translateX(-50%) translateY(-8px)}body.syndicate div[data-tooltip].tooltip-bottom:hover:after,body.syndicate span[data-tooltip].tooltip-bottom:hover:after{-ms-transform:translateX(-50%) translateY(8px);transform:translateX(-50%) translateY(8px)}body.syndicate div[data-tooltip].tooltip-left:after,body.syndicate span[data-tooltip].tooltip-left:after{top:50%;right:100%;-ms-transform:translateX(8px) translateY(-50%);transform:translateX(8px) translateY(-50%)}body.syndicate div[data-tooltip].tooltip-left:hover:after,body.syndicate span[data-tooltip].tooltip-left:hover:after{-ms-transform:translateX(-8px) translateY(-50%);transform:translateX(-8px) translateY(-50%)}body.syndicate div[data-tooltip].tooltip-right:after,body.syndicate span[data-tooltip].tooltip-right:after{top:50%;left:100%;-ms-transform:translateX(-8px) translateY(-50%);transform:translateX(-8px) translateY(-50%)}body.syndicate div[data-tooltip].tooltip-right:hover:after,body.syndicate span[data-tooltip].tooltip-right:hover:after{-ms-transform:translateX(8px) translateY(-50%);transform:translateX(8px) translateY(-50%)}body.syndicate .bar{display:inline-block;position:relative;vertical-align:middle;width:100%;height:20px;line-height:17px;padding:1px;border:1px solid #000;background:#272727}body.syndicate .bar .barText{position:absolute;top:0;right:3px}body.syndicate .bar .barFill{display:block;height:100%;transition:background-color 1s;background-color:#000}body.syndicate .bar .barFill.good{background-color:#73e573}body.syndicate .bar .barFill.average{background-color:#be6209}body.syndicate .bar .barFill.bad{background-color:#b00e0e}body.syndicate span.button{display:inline-block;vertical-align:middle;min-height:20px;line-height:17px;padding:0 5px;white-space:nowrap;border:1px solid #272727}body.syndicate span.button .fa{padding-right:2px}body.syndicate span.button.normal{transition:background-color .5s;background-color:#397439}body.syndicate span.button.normal.active:focus,body.syndicate span.button.normal.active:hover{transition:background-color .25s;background-color:#4a964a;outline:0}body.syndicate span.button.disabled{transition:background-color .5s;background-color:#363636}body.syndicate span.button.disabled.active:focus,body.syndicate span.button.disabled.active:hover{transition:background-color .25s;background-color:#545454;outline:0}body.syndicate span.button.selected{transition:background-color .5s;background-color:#9d0808}body.syndicate span.button.selected.active:focus,body.syndicate span.button.selected.active:hover{transition:background-color .25s;background-color:#ce0b0b;outline:0}body.syndicate span.button.toggle{transition:background-color .5s;background-color:#9d0808}body.syndicate span.button.toggle.active:focus,body.syndicate span.button.toggle.active:hover{transition:background-color .25s;background-color:#ce0b0b;outline:0}body.syndicate span.button.caution{transition:background-color .5s;background-color:#be6209}body.syndicate span.button.caution.active:focus,body.syndicate span.button.caution.active:hover{transition:background-color .25s;background-color:#eb790b;outline:0}body.syndicate span.button.danger{transition:background-color .5s;background-color:#9a9d00}body.syndicate span.button.danger.active:focus,body.syndicate span.button.danger.active:hover{transition:background-color .25s;background-color:#ced200;outline:0}body.syndicate span.button.gridable{width:125px;margin:2px 0}body.syndicate span.button.gridable.center{text-align:center;width:75px}body.syndicate span.button+span:not(.button),body.syndicate span:not(.button)+span.button{margin-left:5px}body.syndicate div.display{width:100%;padding:4px;margin:6px 0;background-color:#000;-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorStr=#80000000,endColorStr=#80000000)";filter:progid:DXImageTransform.Microsoft.gradient(startColorStr=#80000000,endColorStr=#80000000);background-color:rgba(0,0,0,.5);box-shadow:inset 0 0 5px rgba(0,0,0,.75)}body.syndicate div.display.tabular{padding:0;margin:0}body.syndicate div.display header,body.syndicate div.subdisplay header{display:block;position:relative;width:100%;padding:0 4px;margin-bottom:6px;color:#fff;border-bottom:2px solid #272727}body.syndicate div.display header .buttonRight,body.syndicate div.subdisplay header .buttonRight{position:absolute;bottom:6px;right:4px}body.syndicate div.display article,body.syndicate div.subdisplay article{display:table;width:100%;border-collapse:collapse}body.syndicate input{display:inline-block;vertical-align:middle;height:20px;line-height:17px;padding:0 5px;white-space:nowrap;color:#fff;background-color:#9d0808;border:1px solid #272727}body.syndicate input.number{width:35px}body.syndicate input:-ms-input-placeholder{color:#999}body.syndicate input::placeholder{color:#999}body.syndicate input::-ms-clear{display:none}body.syndicate svg.linegraph{overflow:hidden}body.syndicate div.notice{margin:8px 0;padding:4px;box-shadow:none;color:#000;font-weight:700;font-style:italic;background-color:#750000;background-image:repeating-linear-gradient(-45deg,#750000,#750000 10px,#910101 0,#910101 20px)}body.syndicate div.notice .label{color:#000}body.syndicate div.notice .content:only-of-type{padding:0}body.syndicate div.notice hr{background-color:#272727}body.syndicate div.resize{position:fixed;bottom:0;right:0;width:0;height:0;border-style:solid;border-width:0 0 45px 45px;border-color:transparent transparent #363636;-ms-transform:rotate(1turn);transform:rotate(1turn)}body.syndicate section .cell,body.syndicate section .content,body.syndicate section .label,body.syndicate section .line{display:table-cell;margin:0;text-align:left;vertical-align:middle;padding:3px 2px}body.syndicate section{display:table-row;width:100%}body.syndicate section:not(:first-child){padding-top:4px}body.syndicate section.candystripe:nth-child(2n){background-color:#000;-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorStr=#33000000,endColorStr=#33000000)";filter:progid:DXImageTransform.Microsoft.gradient(startColorStr=#33000000,endColorStr=#33000000);background-color:rgba(0,0,0,.2)}body.syndicate section .label{width:1%;padding-right:32px;white-space:nowrap;color:#fff}body.syndicate section .content:not(:last-child){padding-right:16px}body.syndicate section .line{width:100%}body.syndicate section .cell:not(:first-child){text-align:center;padding-top:0}body.syndicate section .cell span.button{width:75px}body.syndicate section:not(:last-child){padding-right:4px}body.syndicate div.subdisplay{width:100%;margin:0}body.syndicate header.titlebar .close,body.syndicate header.titlebar .minimize{display:inline-block;position:relative;padding:7px;margin:-7px;color:#e74242}body.syndicate header.titlebar .close:hover,body.syndicate header.titlebar .minimize:hover{color:#eb5e5e}body.syndicate header.titlebar{position:fixed;z-index:1;top:0;left:0;width:100%;height:32px;background-color:#363636;border-bottom:1px solid #161616;box-shadow:0 3px 3px rgba(0,0,0,.1)}body.syndicate header.titlebar .statusicon{position:absolute;top:4px;left:12px;transition:color .5s}body.syndicate header.titlebar .title{position:absolute;top:6px;left:46px;color:#e74242;font-size:16px;white-space:nowrap}body.syndicate header.titlebar .minimize{position:absolute;top:6px;right:46px}body.syndicate header.titlebar .close{position:absolute;top:4px;right:12px}.no-icons header.titlebar .statusicon{font-size:20px}.no-icons header.titlebar .statusicon:after{content:"O"}.no-icons header.titlebar .minimize{top:-2px;font-size:20px}.no-icons header.titlebar .minimize:after{content:"—"}.no-icons header.titlebar .close{font-size:20px}.no-icons header.titlebar .close:after{content:"X"}
\ No newline at end of file
+@charset "utf-8";body,html{box-sizing:border-box;height:100%;margin:0}html{overflow:hidden;cursor:default}body{overflow:auto;font-family:Verdana,Geneva,sans-serif;font-size:12px;color:#fff;background-color:#2a2a2a;background-image:linear-gradient(180deg,#2a2a2a 0,#202020);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr="#ff2a2a2a",endColorstr="#ff202020",GradientType=0)}*,:after,:before{box-sizing:inherit}h1,h2,h3,h4{display:inline-block;margin:0;padding:6px 0}h1{font-size:18px}h2{font-size:16px}h3{font-size:14px}h4{font-size:12px}body.clockwork{background:linear-gradient(180deg,#b18b25 0,#5f380e);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr="#ffb18b25",endColorstr="#ff5f380e",GradientType=0)}body.clockwork .normal{color:#b18b25}body.clockwork .good{color:#cfba47}body.clockwork .average{color:#896b19}body.clockwork .bad{color:#5f380e}body.clockwork .highlight{color:#b18b25}body.clockwork main{display:block;margin-top:32px;padding:2px 6px 0}body.clockwork hr{height:2px;background-color:#b18b25;border:none}body.clockwork .hidden{display:none}body.clockwork .bar .barText,body.clockwork span.button{color:#b18b25;font-size:12px;font-weight:400;font-style:normal;text-decoration:none}body.clockwork .bold{font-weight:700}body.clockwork .italic{font-style:italic}body.clockwork [unselectable=on]{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}body.clockwork div[data-tooltip],body.clockwork span[data-tooltip]{position:relative}body.clockwork div[data-tooltip]:after,body.clockwork span[data-tooltip]:after{position:absolute;display:block;z-index:2;width:250px;padding:10px;-ms-transform:translateX(-50%);transform:translateX(-50%);visibility:hidden;opacity:0;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";white-space:normal;text-align:left;content:attr(data-tooltip);transition:all .5s;border:1px solid #170800;background-color:#2d1400}body.clockwork div[data-tooltip]:hover:after,body.clockwork span[data-tooltip]:hover:after{visibility:visible;opacity:1;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=100)"}body.clockwork div[data-tooltip].tooltip-top:after,body.clockwork span[data-tooltip].tooltip-top:after{bottom:100%;left:50%;-ms-transform:translateX(-50%) translateY(8px);transform:translateX(-50%) translateY(8px)}body.clockwork div[data-tooltip].tooltip-top:hover:after,body.clockwork span[data-tooltip].tooltip-top:hover:after{-ms-transform:translateX(-50%) translateY(-8px);transform:translateX(-50%) translateY(-8px)}body.clockwork div[data-tooltip].tooltip-bottom:after,body.clockwork span[data-tooltip].tooltip-bottom:after{top:100%;left:50%;-ms-transform:translateX(-50%) translateY(-8px);transform:translateX(-50%) translateY(-8px)}body.clockwork div[data-tooltip].tooltip-bottom:hover:after,body.clockwork span[data-tooltip].tooltip-bottom:hover:after{-ms-transform:translateX(-50%) translateY(8px);transform:translateX(-50%) translateY(8px)}body.clockwork div[data-tooltip].tooltip-left:after,body.clockwork span[data-tooltip].tooltip-left:after{top:50%;right:100%;-ms-transform:translateX(8px) translateY(-50%);transform:translateX(8px) translateY(-50%)}body.clockwork div[data-tooltip].tooltip-left:hover:after,body.clockwork span[data-tooltip].tooltip-left:hover:after{-ms-transform:translateX(-8px) translateY(-50%);transform:translateX(-8px) translateY(-50%)}body.clockwork div[data-tooltip].tooltip-right:after,body.clockwork span[data-tooltip].tooltip-right:after{top:50%;left:100%;-ms-transform:translateX(-8px) translateY(-50%);transform:translateX(-8px) translateY(-50%)}body.clockwork div[data-tooltip].tooltip-right:hover:after,body.clockwork span[data-tooltip].tooltip-right:hover:after{-ms-transform:translateX(8px) translateY(-50%);transform:translateX(8px) translateY(-50%)}body.clockwork .bar{display:inline-block;position:relative;vertical-align:middle;width:100%;height:20px;line-height:17px;padding:1px;border:1px solid #170800;background:#2d1400}body.clockwork .bar .barText{position:absolute;top:0;right:3px}body.clockwork .bar .barFill{display:block;height:100%;transition:background-color 1s;background-color:#b18b25}body.clockwork .bar .barFill.good{background-color:#cfba47}body.clockwork .bar .barFill.average{background-color:#896b19}body.clockwork .bar .barFill.bad{background-color:#5f380e}body.clockwork span.button{display:inline-block;vertical-align:middle;min-height:20px;line-height:17px;padding:0 5px;white-space:nowrap;border:1px solid #170800}body.clockwork span.button .fa{padding-right:2px}body.clockwork span.button.normal{transition:background-color .5s;background-color:#5f380e}body.clockwork span.button.normal.active:focus,body.clockwork span.button.normal.active:hover{transition:background-color .25s;background-color:#704211;outline:0}body.clockwork span.button.disabled{transition:background-color .5s;background-color:#2d1400}body.clockwork span.button.disabled.active:focus,body.clockwork span.button.disabled.active:hover{transition:background-color .25s;background-color:#441e00;outline:0}body.clockwork span.button.selected{transition:background-color .5s;background-color:#cfba47}body.clockwork span.button.selected.active:focus,body.clockwork span.button.selected.active:hover{transition:background-color .25s;background-color:#d1bd50;outline:0}body.clockwork span.button.toggle{transition:background-color .5s;background-color:#cfba47}body.clockwork span.button.toggle.active:focus,body.clockwork span.button.toggle.active:hover{transition:background-color .25s;background-color:#d1bd50;outline:0}body.clockwork span.button.caution{transition:background-color .5s;background-color:#be6209}body.clockwork span.button.caution.active:focus,body.clockwork span.button.caution.active:hover{transition:background-color .25s;background-color:#cd6a0a;outline:0}body.clockwork span.button.danger{transition:background-color .5s;background-color:#9a9d00}body.clockwork span.button.danger.active:focus,body.clockwork span.button.danger.active:hover{transition:background-color .25s;background-color:#abaf00;outline:0}body.clockwork span.button.gridable{width:125px;margin:2px 0}body.clockwork span.button.gridable.center{text-align:center;width:75px}body.clockwork span.button+span:not(.button),body.clockwork span:not(.button)+span.button{margin-left:5px}body.clockwork div.display{width:100%;padding:4px;margin:6px 0;background-color:#2d1400;-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorStr=#e62d1400,endColorStr=#e62d1400)";filter:progid:DXImageTransform.Microsoft.gradient(startColorStr=#e62d1400,endColorStr=#e62d1400);background-color:rgba(45,20,0,.9);box-shadow:inset 0 0 5px rgba(0,0,0,.3)}body.clockwork div.display.tabular{padding:0;margin:0}body.clockwork div.display header,body.clockwork div.subdisplay header{display:block;position:relative;width:100%;padding:0 4px;margin-bottom:6px;color:#cfba47;border-bottom:2px solid #b18b25}body.clockwork div.display header .buttonRight,body.clockwork div.subdisplay header .buttonRight{position:absolute;bottom:6px;right:4px}body.clockwork div.display article,body.clockwork div.subdisplay article{display:table;width:100%;border-collapse:collapse}body.clockwork input{display:inline-block;vertical-align:middle;height:20px;line-height:17px;padding:0 5px;white-space:nowrap;color:#b18b25;background-color:#cfba47;border:1px solid #272727}body.clockwork input.number{width:35px}body.clockwork input:-ms-input-placeholder{color:#999}body.clockwork input::placeholder{color:#999}body.clockwork input::-ms-clear{display:none}body.clockwork svg.linegraph{overflow:hidden}body.clockwork div.notice{margin:8px 0;padding:4px;box-shadow:none;color:#2d1400;font-weight:700;font-style:italic;background-color:#000;background-image:repeating-linear-gradient(-45deg,#000,#000 10px,#170800 0,#170800 20px)}body.clockwork div.notice .label{color:#2d1400}body.clockwork div.notice .content:only-of-type{padding:0}body.clockwork div.notice hr{background-color:#896b19}body.clockwork div.resize{position:fixed;bottom:0;right:0;width:0;height:0;border-style:solid;border-width:0 0 45px 45px;border-color:transparent transparent #5f380e;-ms-transform:rotate(1turn);transform:rotate(1turn)}body.clockwork section .cell,body.clockwork section .content,body.clockwork section .label,body.clockwork section .line,body.nanotrasen section .cell,body.nanotrasen section .content,body.nanotrasen section .label,body.nanotrasen section .line,body.syndicate section .cell,body.syndicate section .content,body.syndicate section .label,body.syndicate section .line{display:table-cell;margin:0;text-align:left;vertical-align:middle;padding:3px 2px}body.clockwork section{display:table-row;width:100%}body.clockwork section:not(:first-child){padding-top:4px}body.clockwork section.candystripe:nth-child(2n){background-color:#000;-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorStr=#33000000,endColorStr=#33000000)";filter:progid:DXImageTransform.Microsoft.gradient(startColorStr=#33000000,endColorStr=#33000000);background-color:rgba(0,0,0,.2)}body.clockwork section .label{width:1%;padding-right:32px;white-space:nowrap;color:#b18b25}body.clockwork section .content:not(:last-child){padding-right:16px}body.clockwork section .line{width:100%}body.clockwork section .cell:not(:first-child){text-align:center;padding-top:0}body.clockwork section .cell span.button{width:75px}body.clockwork section:not(:last-child){padding-right:4px}body.clockwork div.subdisplay{width:100%;margin:0}body.clockwork header.titlebar .close,body.clockwork header.titlebar .minimize{display:inline-block;position:relative;padding:7px;margin:-7px;color:#cfba47}body.clockwork header.titlebar .close:hover,body.clockwork header.titlebar .minimize:hover{color:#d1bd50}body.clockwork header.titlebar{position:fixed;z-index:1;top:0;left:0;width:100%;height:32px;background-color:#5f380e;border-bottom:1px solid #170800;box-shadow:0 3px 3px rgba(0,0,0,.1)}body.clockwork header.titlebar .statusicon{position:absolute;top:4px;left:12px;transition:color .5s}body.clockwork header.titlebar .title{position:absolute;top:6px;left:46px;color:#cfba47;font-size:16px;white-space:nowrap}body.clockwork header.titlebar .minimize{position:absolute;top:6px;right:46px}body.clockwork header.titlebar .close{position:absolute;top:4px;right:12px}body.nanotrasen{background:url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2ZXJzaW9uPSIxLjAiIHZpZXdCb3g9IjAgMCA0MjUgMjAwIiBvcGFjaXR5PSIuMzMiPgogIDxwYXRoIGQ9Im0gMTc4LjAwMzk5LDAuMDM4NjkgLTcxLjIwMzkzLDAgYSA2Ljc2MTM0MjIsNi4wMjU1NDk1IDAgMCAwIC02Ljc2MTM0LDYuMDI1NTUgbCAwLDE4Ny44NzE0NyBhIDYuNzYxMzQyMiw2LjAyNTU0OTUgMCAwIDAgNi43NjEzNCw2LjAyNTU0IGwgNTMuMTA3MiwwIGEgNi43NjEzNDIyLDYuMDI1NTQ5NSAwIDAgMCA2Ljc2MTM1LC02LjAyNTU0IGwgMCwtMTAxLjU0NDAxOCA3Mi4yMTYyOCwxMDQuNjk5Mzk4IGEgNi43NjEzNDIyLDYuMDI1NTQ5NSAwIDAgMCA1Ljc2MDE1LDIuODcwMTYgbCA3My41NTQ4NywwIGEgNi43NjEzNDIyLDYuMDI1NTQ5NSAwIDAgMCA2Ljc2MTM1LC02LjAyNTU0IGwgMCwtMTg3Ljg3MTQ3IGEgNi43NjEzNDIyLDYuMDI1NTQ5NSAwIDAgMCAtNi43NjEzNSwtNi4wMjU1NSBsIC01NC43MTY0NCwwIGEgNi43NjEzNDIyLDYuMDI1NTQ5NSAwIDAgMCAtNi43NjEzMyw2LjAyNTU1IGwgMCwxMDIuNjE5MzUgTCAxODMuNzY0MTMsMi45MDg4NiBhIDYuNzYxMzQyMiw2LjAyNTU0OTUgMCAwIDAgLTUuNzYwMTQsLTIuODcwMTcgeiIgLz4KICA8cGF0aCBkPSJNIDQuODQ0NjMzMywyMi4xMDg3NSBBIDEzLjQxMjAzOSwxMi41MDE4NDIgMCAwIDEgMTMuNDc3NTg4LDAuMDM5MjQgbCA2Ni4xMTgzMTUsMCBhIDUuMzY0ODE1OCw1LjAwMDczNyAwIDAgMSA1LjM2NDgyMyw1LjAwMDczIGwgMCw3OS44NzkzMSB6IiAvPgogIDxwYXRoIGQ9Im0gNDIwLjE1NTM1LDE3Ny44OTExOSBhIDEzLjQxMjAzOCwxMi41MDE4NDIgMCAwIDEgLTguNjMyOTUsMjIuMDY5NTEgbCAtNjYuMTE4MzIsMCBhIDUuMzY0ODE1Miw1LjAwMDczNyAwIDAgMSAtNS4zNjQ4MiwtNS4wMDA3NCBsIDAsLTc5Ljg3OTMxIHoiIC8+Cjwvc3ZnPgo8IS0tIFRoaXMgd29yayBpcyBsaWNlbnNlZCB1bmRlciBhIENyZWF0aXZlIENvbW1vbnMgQXR0cmlidXRpb24tU2hhcmVBbGlrZSA0LjAgSW50ZXJuYXRpb25hbCBMaWNlbnNlLiAtLT4KPCEtLSBodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9saWNlbnNlcy9ieS1zYS80LjAvIC0tPgo=") no-repeat fixed 50%/70% 70%,linear-gradient(180deg,#2a2a2a 0,#202020);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr="#ff2a2a2a",endColorstr="#ff202020",GradientType=0)}body.nanotrasen .normal{color:#40628a}body.nanotrasen .good{color:#537d29}body.nanotrasen .average{color:#be6209}body.nanotrasen .bad{color:#b00e0e}body.nanotrasen .highlight{color:#8ba5c4}body.nanotrasen main{display:block;margin-top:32px;padding:2px 6px 0}body.nanotrasen hr{height:2px;background-color:#40628a;border:none}body.nanotrasen .hidden{display:none}body.nanotrasen .bar .barText,body.nanotrasen span.button{color:#fff;font-size:12px;font-weight:400;font-style:normal;text-decoration:none}body.nanotrasen .bold{font-weight:700}body.nanotrasen .italic{font-style:italic}body.nanotrasen [unselectable=on]{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}body.nanotrasen div[data-tooltip],body.nanotrasen span[data-tooltip]{position:relative}body.nanotrasen div[data-tooltip]:after,body.nanotrasen span[data-tooltip]:after{position:absolute;display:block;z-index:2;width:250px;padding:10px;-ms-transform:translateX(-50%);transform:translateX(-50%);visibility:hidden;opacity:0;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";white-space:normal;text-align:left;content:attr(data-tooltip);transition:all .5s;border:1px solid #272727;background-color:#363636}body.nanotrasen div[data-tooltip]:hover:after,body.nanotrasen span[data-tooltip]:hover:after{visibility:visible;opacity:1;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=100)"}body.nanotrasen div[data-tooltip].tooltip-top:after,body.nanotrasen span[data-tooltip].tooltip-top:after{bottom:100%;left:50%;-ms-transform:translateX(-50%) translateY(8px);transform:translateX(-50%) translateY(8px)}body.nanotrasen div[data-tooltip].tooltip-top:hover:after,body.nanotrasen span[data-tooltip].tooltip-top:hover:after{-ms-transform:translateX(-50%) translateY(-8px);transform:translateX(-50%) translateY(-8px)}body.nanotrasen div[data-tooltip].tooltip-bottom:after,body.nanotrasen span[data-tooltip].tooltip-bottom:after{top:100%;left:50%;-ms-transform:translateX(-50%) translateY(-8px);transform:translateX(-50%) translateY(-8px)}body.nanotrasen div[data-tooltip].tooltip-bottom:hover:after,body.nanotrasen span[data-tooltip].tooltip-bottom:hover:after{-ms-transform:translateX(-50%) translateY(8px);transform:translateX(-50%) translateY(8px)}body.nanotrasen div[data-tooltip].tooltip-left:after,body.nanotrasen span[data-tooltip].tooltip-left:after{top:50%;right:100%;-ms-transform:translateX(8px) translateY(-50%);transform:translateX(8px) translateY(-50%)}body.nanotrasen div[data-tooltip].tooltip-left:hover:after,body.nanotrasen span[data-tooltip].tooltip-left:hover:after{-ms-transform:translateX(-8px) translateY(-50%);transform:translateX(-8px) translateY(-50%)}body.nanotrasen div[data-tooltip].tooltip-right:after,body.nanotrasen span[data-tooltip].tooltip-right:after{top:50%;left:100%;-ms-transform:translateX(-8px) translateY(-50%);transform:translateX(-8px) translateY(-50%)}body.nanotrasen div[data-tooltip].tooltip-right:hover:after,body.nanotrasen span[data-tooltip].tooltip-right:hover:after{-ms-transform:translateX(8px) translateY(-50%);transform:translateX(8px) translateY(-50%)}body.nanotrasen .bar{display:inline-block;position:relative;vertical-align:middle;width:100%;height:20px;line-height:17px;padding:1px;border:1px solid #40628a;background:#272727}body.nanotrasen .bar .barText{position:absolute;top:0;right:3px}body.nanotrasen .bar .barFill{display:block;height:100%;transition:background-color 1s;background-color:#40628a}body.nanotrasen .bar .barFill.good{background-color:#537d29}body.nanotrasen .bar .barFill.average{background-color:#be6209}body.nanotrasen .bar .barFill.bad{background-color:#b00e0e}body.nanotrasen span.button{display:inline-block;vertical-align:middle;min-height:20px;line-height:17px;padding:0 5px;white-space:nowrap;border:1px solid #272727}body.nanotrasen span.button .fa{padding-right:2px}body.nanotrasen span.button.normal{transition:background-color .5s;background-color:#40628a}body.nanotrasen span.button.normal.active:focus,body.nanotrasen span.button.normal.active:hover{transition:background-color .25s;background-color:#4f78aa;outline:0}body.nanotrasen span.button.disabled{transition:background-color .5s;background-color:#999}body.nanotrasen span.button.disabled.active:focus,body.nanotrasen span.button.disabled.active:hover{transition:background-color .25s;background-color:#a8a8a8;outline:0}body.nanotrasen span.button.selected{transition:background-color .5s;background-color:#2f943c}body.nanotrasen span.button.selected.active:focus,body.nanotrasen span.button.selected.active:hover{transition:background-color .25s;background-color:#3ab84b;outline:0}body.nanotrasen span.button.toggle{transition:background-color .5s;background-color:#2f943c}body.nanotrasen span.button.toggle.active:focus,body.nanotrasen span.button.toggle.active:hover{transition:background-color .25s;background-color:#3ab84b;outline:0}body.nanotrasen span.button.caution{transition:background-color .5s;background-color:#9a9d00}body.nanotrasen span.button.caution.active:focus,body.nanotrasen span.button.caution.active:hover{transition:background-color .25s;background-color:#ced200;outline:0}body.nanotrasen span.button.danger{transition:background-color .5s;background-color:#9d0808}body.nanotrasen span.button.danger.active:focus,body.nanotrasen span.button.danger.active:hover{transition:background-color .25s;background-color:#ce0b0b;outline:0}body.nanotrasen span.button.gridable{width:125px;margin:2px 0}body.nanotrasen span.button.gridable.center{text-align:center;width:75px}body.nanotrasen span.button+span:not(.button),body.nanotrasen span:not(.button)+span.button{margin-left:5px}body.nanotrasen div.display{width:100%;padding:4px;margin:6px 0;background-color:#000;-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorStr=#54000000,endColorStr=#54000000)";filter:progid:DXImageTransform.Microsoft.gradient(startColorStr=#54000000,endColorStr=#54000000);background-color:rgba(0,0,0,.33);box-shadow:inset 0 0 5px rgba(0,0,0,.5)}body.nanotrasen div.display.tabular{padding:0;margin:0}body.nanotrasen div.display header,body.nanotrasen div.subdisplay header{display:block;position:relative;width:100%;padding:0 4px;margin-bottom:6px;color:#fff;border-bottom:2px solid #40628a}body.nanotrasen div.display header .buttonRight,body.nanotrasen div.subdisplay header .buttonRight{position:absolute;bottom:6px;right:4px}body.nanotrasen div.display article,body.nanotrasen div.subdisplay article{display:table;width:100%;border-collapse:collapse}body.nanotrasen input{display:inline-block;vertical-align:middle;height:20px;line-height:17px;padding:0 5px;white-space:nowrap;color:#000;background-color:#fff;border:1px solid #272727}body.nanotrasen input.number{width:35px}body.nanotrasen input:-ms-input-placeholder{color:#999}body.nanotrasen input::placeholder{color:#999}body.nanotrasen input::-ms-clear{display:none}body.nanotrasen svg.linegraph{overflow:hidden}body.nanotrasen div.notice{margin:8px 0;padding:4px;box-shadow:none;color:#000;font-weight:700;font-style:italic;background-color:#bb9b68;background-image:repeating-linear-gradient(-45deg,#bb9b68,#bb9b68 10px,#b1905d 0,#b1905d 20px)}body.nanotrasen div.notice .label{color:#000}body.nanotrasen div.notice .content:only-of-type{padding:0}body.nanotrasen div.notice hr{background-color:#272727}body.nanotrasen div.resize{position:fixed;bottom:0;right:0;width:0;height:0;border-style:solid;border-width:0 0 45px 45px;border-color:transparent transparent #363636;-ms-transform:rotate(1turn);transform:rotate(1turn)}body.nanotrasen section .cell,body.nanotrasen section .content,body.nanotrasen section .label,body.nanotrasen section .line,body.syndicate section .cell,body.syndicate section .content,body.syndicate section .label,body.syndicate section .line{display:table-cell;margin:0;text-align:left;vertical-align:middle;padding:3px 2px}body.nanotrasen section{display:table-row;width:100%}body.nanotrasen section:not(:first-child){padding-top:4px}body.nanotrasen section.candystripe:nth-child(2n){background-color:#000;-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorStr=#33000000,endColorStr=#33000000)";filter:progid:DXImageTransform.Microsoft.gradient(startColorStr=#33000000,endColorStr=#33000000);background-color:rgba(0,0,0,.2)}body.nanotrasen section .label{width:1%;padding-right:32px;white-space:nowrap;color:#8ba5c4}body.nanotrasen section .content:not(:last-child){padding-right:16px}body.nanotrasen section .line{width:100%}body.nanotrasen section .cell:not(:first-child){text-align:center;padding-top:0}body.nanotrasen section .cell span.button{width:75px}body.nanotrasen section:not(:last-child){padding-right:4px}body.nanotrasen div.subdisplay{width:100%;margin:0}body.nanotrasen header.titlebar .close,body.nanotrasen header.titlebar .minimize{display:inline-block;position:relative;padding:7px;margin:-7px;color:#8ba5c4}body.nanotrasen header.titlebar .close:hover,body.nanotrasen header.titlebar .minimize:hover{color:#9cb2cd}body.nanotrasen header.titlebar{position:fixed;z-index:1;top:0;left:0;width:100%;height:32px;background-color:#363636;border-bottom:1px solid #161616;box-shadow:0 3px 3px rgba(0,0,0,.1)}body.nanotrasen header.titlebar .statusicon{position:absolute;top:4px;left:12px;transition:color .5s}body.nanotrasen header.titlebar .title{position:absolute;top:6px;left:46px;color:#8ba5c4;font-size:16px;white-space:nowrap}body.nanotrasen header.titlebar .minimize{position:absolute;top:6px;right:46px}body.nanotrasen header.titlebar .close{position:absolute;top:4px;right:12px}body.syndicate{background:url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2ZXJzaW9uPSIxLjAiIHZpZXdCb3g9IjAgMCAyMDAgMjg5Ljc0MiIgb3BhY2l0eT0iLjMzIj4KICA8cGF0aCBkPSJtIDkzLjUzNzY3NywwIGMgLTE4LjExMzEyNSwwIC0zNC4yMjAxMzMsMy4xMTE2NCAtNDguMzIzNDg0LDkuMzM0MzcgLTEzLjk2NTA5Miw2LjIyMTY3IC0yNC42MTI0NDIsMTUuMDcxMTQgLTMxLjk0MDY1MSwyNi41NDcxIC03LjE4OTkzOTgsMTEuMzM3ODkgLTEwLjMwMTIyNjYsMjQuNzQ5MTEgLTEwLjMwMTIyNjYsNDAuMjM0NzggMCwxMC42NDY2MiAyLjcyNTAwMjYsMjAuNDY0NjUgOC4xNzUxMTE2LDI5LjQ1MjU4IDUuNjE1Mjc3LDguOTg2ODYgMTQuMDM4Mjc3LDE3LjM1MjA0IDI1LjI2ODgyMSwyNS4wOTQzNiAxMS4yMzA1NDQsNy42MDUzMSAyNi41MDc0MjEsMTUuNDE4MzUgNDUuODMwNTE0LDIzLjQzNzgyIDE5Ljk4Mzc0OCw4LjI5NTU3IDM0Ljg0ODg0OCwxNS41NTQ3MSA0NC41OTI5OTgsMjEuNzc2MzggOS43NDQxNCw2LjIyMjczIDE2Ljc2MTcsMTIuODU4NSAyMS4wNTU3MiwxOS45MDk1MSA0LjI5NDA0LDcuMDUyMDggNi40NDE5MywxNS43NjQwOCA2LjQ0MTkzLDI2LjEzNDU5IDAsMTYuMTc3MDIgLTUuMjAxOTYsMjguNDgyMjIgLTE1LjYwNjczLDM2LjkxNjgyIC0xMC4yMzk2LDguNDM0NyAtMjUuMDIyMDMsMTIuNjUyMyAtNDQuMzQ1MTY5LDEyLjY1MjMgLTE0LjAzODE3MSwwIC0yNS41MTUyNDcsLTEuNjU5NCAtMzQuNDMzNjE4LC00Ljk3NzcgLTguOTE4MzcsLTMuNDU2NiAtMTYuMTg1NTcyLC04LjcxMTMgLTIxLjgwMDgzOSwtMTUuNzYzMyAtNS42MTUyNzcsLTcuMDUyMSAtMTAuMDc0Nzk1LC0xNi42NjA4OCAtMTMuMzc3ODk5LC0yOC44MjgxMiBsIC0yNC43NzMxNjI2MjkzOTQ1LDAgMCw1Ni44MjYzMiBDIDMzLjg1Njc2OSwyODYuMDc2MDEgNjMuNzQ5MDQsMjg5Ljc0MjAxIDg5LjY3ODM4MywyODkuNzQyMDEgYyAxNi4wMjAwMjcsMCAzMC43MTk3ODcsLTEuMzgyNyA0NC4wOTczMzcsLTQuMTQ3OSAxMy41NDI3MiwtMi45MDQzIDI1LjEwNDEsLTcuNDY3NiAzNC42ODMwOSwtMTMuNjg5MyA5Ljc0NDEzLC02LjM1OTcgMTcuMzQwNDIsLTE0LjUxOTUgMjIuNzkwNTIsLTI0LjQ3NDggNS40NTAxLC0xMC4wOTMzMiA4LjE3NTExLC0yMi4zOTk1OSA4LjE3NTExLC0zNi45MTY4MiAwLC0xMi45OTc2NCAtMy4zMDIxLC0yNC4zMzUzOSAtOS45MDgyOSwtMzQuMDE0NiAtNi40NDEwNSwtOS44MTcyNSAtMTUuNTI1NDUsLTE4LjUyNzA3IC0yNy4yNTE0NiwtMjYuMTMxMzMgLTExLjU2MDg1LC03LjYwNDI3IC0yNy45MTA4MywtMTUuODMxNDIgLTQ5LjA1MDY2LC0yNC42ODAyMiAtMTcuNTA2NDQsLTcuMTkwMTIgLTMwLjcxOTY2OCwtMTMuNjg5NDggLTM5LjYzODAzOCwtMTkuNDk3MDEgLTguOTE4MzcxLC01LjgwNzUyIC0xOC42MDc0NzQsLTEyLjQzNDA5IC0yNC4wOTY1MjQsLTE4Ljg3NDE3IC01LjQyNjA0MywtNi4zNjYxNiAtOS42NTg4MjYsLTE1LjA3MDAzIC05LjY1ODgyNiwtMjQuODg3MjkgMCwtOS4yNjQwMSAyLjA3NTQxNCwtMTcuMjEzNDUgNi4yMjM0NTQsLTIzLjg1MDMzIDExLjA5ODI5OCwtMTQuMzk3NDggNDEuMjg2NjM4LC0xLjc5NTA3IDQ1LjA3NTYwOSwyNC4zNDc2MiA0LjgzOTM5Miw2Ljc3NDkxIDguODQ5MzUsMTYuMjQ3MjkgMTIuMDI5NTE1LDI4LjQxNTYgbCAyMC41MzIzNCwwIDAsLTU1Ljk5OTY3IGMgLTQuNDc4MjUsLTUuOTI0NDggLTkuOTU0ODgsLTEwLjYzMjIyIC0xNS45MDgzNywtMTQuMzc0MTEgMS42NDA1NSwwLjQ3OTA1IDMuMTkwMzksMS4wMjM3NiA0LjYzODY1LDEuNjQwMjQgNi40OTg2MSwyLjYyNjA3IDEyLjE2NzkzLDcuMzI3NDcgMTcuMDA3MywxNC4xMDM0NSA0LjgzOTM5LDYuNzc0OTEgOC44NDkzNSwxNi4yNDU2NyAxMi4wMjk1MiwyOC40MTM5NyAwLDAgOC40ODEyOCwtMC4xMjg5NCA4LjQ4OTc4LC0wLjAwMiAwLjQxNzc2LDYuNDE0OTQgLTEuNzUzMzksOS40NTI4NiAtNC4xMjM0MiwxMi41NjEwNCAtMi40MTc0LDMuMTY5NzggLTUuMTQ0ODYsNi43ODk3MyAtNC4wMDI3OCwxMy4wMDI5IDEuNTA3ODYsOC4yMDMxOCAxMC4xODM1NCwxMC41OTY0MiAxNC42MjE5NCw5LjMxMTU0IC0zLjMxODQyLC0wLjQ5OTExIC01LjMxODU1LC0xLjc0OTQ4IC01LjMxODU1LC0xLjc0OTQ4IDAsMCAxLjg3NjQ2LDAuOTk4NjggNS42NTExNywtMS4zNTk4MSAtMy4yNzY5NSwwLjk1NTcxIC0xMC43MDUyOSwtMC43OTczOCAtMTEuODAxMjUsLTYuNzYzMTMgLTAuOTU3NTIsLTUuMjA4NjEgMC45NDY1NCwtNy4yOTUxNCAzLjQwMTEzLC0xMC41MTQ4MiAyLjQ1NDYyLC0zLjIxOTY4IDUuMjg0MjYsLTYuOTU4MzEgNC42ODQzLC0xNC40ODgyNCBsIDAuMDAzLDAuMDAyIDguOTI2NzYsMCAwLC01NS45OTk2NyBjIC0xNS4wNzEyNSwtMy44NzE2OCAtMjcuNjUzMTQsLTYuMzYwNDIgLTM3Ljc0NjcxLC03LjQ2NTg2IC05Ljk1NTMxLC0xLjEwNzU1IC0yMC4xODgyMywtMS42NTk4MSAtMzAuNjk2NjEzLC0xLjY1OTgxIHogbSA3MC4zMjE2MDMsMTcuMzA4OTMgMC4yMzgwNSw0MC4zMDQ5IGMgMS4zMTgwOCwxLjIyNjY2IDIuNDM5NjUsMi4yNzgxNSAzLjM0MDgxLDMuMTA2MDIgNC44MzkzOSw2Ljc3NDkxIDguODQ5MzQsMTYuMjQ1NjYgMTIuMDI5NTEsMjguNDEzOTcgbCAyMC41MzIzNCwwIDAsLTU1Ljk5OTY3IGMgLTYuNjc3MzEsLTQuNTkzODEgLTE5LjgzNjQzLC0xMC40NzMwOSAtMzYuMTQwNzEsLTE1LjgyNTIyIHogbSAtMjguMTIwNDksNS42MDU1MSA4LjU2NDc5LDE3LjcxNjU1IGMgLTExLjk3MDM3LC02LjQ2Njk3IC0xMy44NDY3OCwtOS43MTcyNiAtOC41NjQ3OSwtMTcuNzE2NTUgeiBtIDIyLjc5NzA1LDAgYyAyLjc3MTUsNy45OTkyOSAxLjc4NzQxLDExLjI0OTU4IC00LjQ5MzU0LDE3LjcxNjU1IGwgNC40OTM1NCwtMTcuNzE2NTUgeiBtIDE1LjIyMTk1LDI0LjAwODQ4IDguNTY0NzksMTcuNzE2NTUgYyAtMTEuOTcwMzgsLTYuNDY2OTcgLTEzLjg0Njc5LC05LjcxNzI2IC04LjU2NDc5LC0xNy43MTY1NSB6IG0gMjIuNzk3MDQsMCBjIDIuNzcxNSw3Ljk5OTI5IDEuNzg3NDEsMTEuMjQ5NTggLTQuNDkzNTQsMTcuNzE2NTUgbCA0LjQ5MzU0LC0xNy43MTY1NSB6IG0gLTk5LjExMzg0LDIuMjA3NjQgOC41NjQ3OSwxNy43MTY1NSBjIC0xMS45NzAzODIsLTYuNDY2OTcgLTEzLjg0Njc4MiwtOS43MTcyNiAtOC41NjQ3OSwtMTcuNzE2NTUgeiBtIDIyLjc5NTQyLDAgYyAyLjc3MTUsNy45OTkyOSAxLjc4NzQxLDExLjI0OTU4IC00LjQ5MzU0LDE3LjcxNjU1IGwgNC40OTM1NCwtMTcuNzE2NTUgeiIgLz4KPC9zdmc+CjwhLS0gVGhpcyB3b3JrIGlzIGxpY2Vuc2VkIHVuZGVyIGEgQ3JlYXRpdmUgQ29tbW9ucyBBdHRyaWJ1dGlvbi1TaGFyZUFsaWtlIDQuMCBJbnRlcm5hdGlvbmFsIExpY2Vuc2UuIC0tPgo8IS0tIGh0dHA6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL2xpY2Vuc2VzL2J5LXNhLzQuMC8gLS0+Cg==") no-repeat fixed 50%/70% 70%,linear-gradient(180deg,#750000 0,#340404);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr="#ff750000",endColorstr="#ff340404",GradientType=0)}body.syndicate .normal{color:#40628a}body.syndicate .good{color:#73e573}body.syndicate .average{color:#be6209}body.syndicate .bad{color:#b00e0e}body.syndicate .highlight{color:#000}body.syndicate main{display:block;margin-top:32px;padding:2px 6px 0}body.syndicate hr{height:2px;background-color:#272727;border:none}body.syndicate .hidden{display:none}body.syndicate .bar .barText,body.syndicate span.button{color:#fff;font-size:12px;font-weight:400;font-style:normal;text-decoration:none}body.syndicate .bold{font-weight:700}body.syndicate .italic{font-style:italic}body.syndicate [unselectable=on]{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}body.syndicate div[data-tooltip],body.syndicate span[data-tooltip]{position:relative}body.syndicate div[data-tooltip]:after,body.syndicate span[data-tooltip]:after{position:absolute;display:block;z-index:2;width:250px;padding:10px;-ms-transform:translateX(-50%);transform:translateX(-50%);visibility:hidden;opacity:0;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";white-space:normal;text-align:left;content:attr(data-tooltip);transition:all .5s;border:1px solid #272727;background-color:#363636}body.syndicate div[data-tooltip]:hover:after,body.syndicate span[data-tooltip]:hover:after{visibility:visible;opacity:1;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=100)"}body.syndicate div[data-tooltip].tooltip-top:after,body.syndicate span[data-tooltip].tooltip-top:after{bottom:100%;left:50%;-ms-transform:translateX(-50%) translateY(8px);transform:translateX(-50%) translateY(8px)}body.syndicate div[data-tooltip].tooltip-top:hover:after,body.syndicate span[data-tooltip].tooltip-top:hover:after{-ms-transform:translateX(-50%) translateY(-8px);transform:translateX(-50%) translateY(-8px)}body.syndicate div[data-tooltip].tooltip-bottom:after,body.syndicate span[data-tooltip].tooltip-bottom:after{top:100%;left:50%;-ms-transform:translateX(-50%) translateY(-8px);transform:translateX(-50%) translateY(-8px)}body.syndicate div[data-tooltip].tooltip-bottom:hover:after,body.syndicate span[data-tooltip].tooltip-bottom:hover:after{-ms-transform:translateX(-50%) translateY(8px);transform:translateX(-50%) translateY(8px)}body.syndicate div[data-tooltip].tooltip-left:after,body.syndicate span[data-tooltip].tooltip-left:after{top:50%;right:100%;-ms-transform:translateX(8px) translateY(-50%);transform:translateX(8px) translateY(-50%)}body.syndicate div[data-tooltip].tooltip-left:hover:after,body.syndicate span[data-tooltip].tooltip-left:hover:after{-ms-transform:translateX(-8px) translateY(-50%);transform:translateX(-8px) translateY(-50%)}body.syndicate div[data-tooltip].tooltip-right:after,body.syndicate span[data-tooltip].tooltip-right:after{top:50%;left:100%;-ms-transform:translateX(-8px) translateY(-50%);transform:translateX(-8px) translateY(-50%)}body.syndicate div[data-tooltip].tooltip-right:hover:after,body.syndicate span[data-tooltip].tooltip-right:hover:after{-ms-transform:translateX(8px) translateY(-50%);transform:translateX(8px) translateY(-50%)}body.syndicate .bar{display:inline-block;position:relative;vertical-align:middle;width:100%;height:20px;line-height:17px;padding:1px;border:1px solid #000;background:#272727}body.syndicate .bar .barText{position:absolute;top:0;right:3px}body.syndicate .bar .barFill{display:block;height:100%;transition:background-color 1s;background-color:#000}body.syndicate .bar .barFill.good{background-color:#73e573}body.syndicate .bar .barFill.average{background-color:#be6209}body.syndicate .bar .barFill.bad{background-color:#b00e0e}body.syndicate span.button{display:inline-block;vertical-align:middle;min-height:20px;line-height:17px;padding:0 5px;white-space:nowrap;border:1px solid #272727}body.syndicate span.button .fa{padding-right:2px}body.syndicate span.button.normal{transition:background-color .5s;background-color:#397439}body.syndicate span.button.normal.active:focus,body.syndicate span.button.normal.active:hover{transition:background-color .25s;background-color:#4a964a;outline:0}body.syndicate span.button.disabled{transition:background-color .5s;background-color:#363636}body.syndicate span.button.disabled.active:focus,body.syndicate span.button.disabled.active:hover{transition:background-color .25s;background-color:#545454;outline:0}body.syndicate span.button.selected{transition:background-color .5s;background-color:#9d0808}body.syndicate span.button.selected.active:focus,body.syndicate span.button.selected.active:hover{transition:background-color .25s;background-color:#ce0b0b;outline:0}body.syndicate span.button.toggle{transition:background-color .5s;background-color:#9d0808}body.syndicate span.button.toggle.active:focus,body.syndicate span.button.toggle.active:hover{transition:background-color .25s;background-color:#ce0b0b;outline:0}body.syndicate span.button.caution{transition:background-color .5s;background-color:#be6209}body.syndicate span.button.caution.active:focus,body.syndicate span.button.caution.active:hover{transition:background-color .25s;background-color:#eb790b;outline:0}body.syndicate span.button.danger{transition:background-color .5s;background-color:#9a9d00}body.syndicate span.button.danger.active:focus,body.syndicate span.button.danger.active:hover{transition:background-color .25s;background-color:#ced200;outline:0}body.syndicate span.button.gridable{width:125px;margin:2px 0}body.syndicate span.button.gridable.center{text-align:center;width:75px}body.syndicate span.button+span:not(.button),body.syndicate span:not(.button)+span.button{margin-left:5px}body.syndicate div.display{width:100%;padding:4px;margin:6px 0;background-color:#000;-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorStr=#80000000,endColorStr=#80000000)";filter:progid:DXImageTransform.Microsoft.gradient(startColorStr=#80000000,endColorStr=#80000000);background-color:rgba(0,0,0,.5);box-shadow:inset 0 0 5px rgba(0,0,0,.75)}body.syndicate div.display.tabular{padding:0;margin:0}body.syndicate div.display header,body.syndicate div.subdisplay header{display:block;position:relative;width:100%;padding:0 4px;margin-bottom:6px;color:#fff;border-bottom:2px solid #272727}body.syndicate div.display header .buttonRight,body.syndicate div.subdisplay header .buttonRight{position:absolute;bottom:6px;right:4px}body.syndicate div.display article,body.syndicate div.subdisplay article{display:table;width:100%;border-collapse:collapse}body.syndicate input{display:inline-block;vertical-align:middle;height:20px;line-height:17px;padding:0 5px;white-space:nowrap;color:#fff;background-color:#9d0808;border:1px solid #272727}body.syndicate input.number{width:35px}body.syndicate input:-ms-input-placeholder{color:#999}body.syndicate input::placeholder{color:#999}body.syndicate input::-ms-clear{display:none}body.syndicate svg.linegraph{overflow:hidden}body.syndicate div.notice{margin:8px 0;padding:4px;box-shadow:none;color:#000;font-weight:700;font-style:italic;background-color:#750000;background-image:repeating-linear-gradient(-45deg,#750000,#750000 10px,#910101 0,#910101 20px)}body.syndicate div.notice .label{color:#000}body.syndicate div.notice .content:only-of-type{padding:0}body.syndicate div.notice hr{background-color:#272727}body.syndicate div.resize{position:fixed;bottom:0;right:0;width:0;height:0;border-style:solid;border-width:0 0 45px 45px;border-color:transparent transparent #363636;-ms-transform:rotate(1turn);transform:rotate(1turn)}body.syndicate section .cell,body.syndicate section .content,body.syndicate section .label,body.syndicate section .line{display:table-cell;margin:0;text-align:left;vertical-align:middle;padding:3px 2px}body.syndicate section{display:table-row;width:100%}body.syndicate section:not(:first-child){padding-top:4px}body.syndicate section.candystripe:nth-child(2n){background-color:#000;-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorStr=#33000000,endColorStr=#33000000)";filter:progid:DXImageTransform.Microsoft.gradient(startColorStr=#33000000,endColorStr=#33000000);background-color:rgba(0,0,0,.2)}body.syndicate section .label{width:1%;padding-right:32px;white-space:nowrap;color:#fff}body.syndicate section .content:not(:last-child){padding-right:16px}body.syndicate section .line{width:100%}body.syndicate section .cell:not(:first-child){text-align:center;padding-top:0}body.syndicate section .cell span.button{width:75px}body.syndicate section:not(:last-child){padding-right:4px}body.syndicate div.subdisplay{width:100%;margin:0}body.syndicate header.titlebar .close,body.syndicate header.titlebar .minimize{display:inline-block;position:relative;padding:7px;margin:-7px;color:#e74242}body.syndicate header.titlebar .close:hover,body.syndicate header.titlebar .minimize:hover{color:#eb5e5e}body.syndicate header.titlebar{position:fixed;z-index:1;top:0;left:0;width:100%;height:32px;background-color:#363636;border-bottom:1px solid #161616;box-shadow:0 3px 3px rgba(0,0,0,.1)}body.syndicate header.titlebar .statusicon{position:absolute;top:4px;left:12px;transition:color .5s}body.syndicate header.titlebar .title{position:absolute;top:6px;left:46px;color:#e74242;font-size:16px;white-space:nowrap}body.syndicate header.titlebar .minimize{position:absolute;top:6px;right:46px}body.syndicate header.titlebar .close{position:absolute;top:4px;right:12px}.no-icons header.titlebar .statusicon{font-size:20px}.no-icons header.titlebar .statusicon:after{content:"O"}.no-icons header.titlebar .minimize{top:-2px;font-size:20px}.no-icons header.titlebar .minimize:after{content:"—"}.no-icons header.titlebar .close{font-size:20px}.no-icons header.titlebar .close:after{content:"X"}
\ No newline at end of file
diff --git a/tgui/assets/tgui.js b/tgui/assets/tgui.js
index e91ad75f5b..7390505564 100644
--- a/tgui/assets/tgui.js
+++ b/tgui/assets/tgui.js
@@ -1,21 +1,21 @@
require=function(){function t(e,n,a){function r(o,s){if(!n[o]){if(!e[o]){var p="function"==typeof require&&require;if(!s&&p)return p(o,!0);if(i)return i(o,!0);var u=Error("Cannot find module '"+o+"'");throw u.code="MODULE_NOT_FOUND",u}var c=n[o]={exports:{}};e[o][0].call(c.exports,function(t){var n=e[o][1][t];return r(n||t)},c,c.exports,t,e,n,a)}return n[o].exports}for(var i="function"==typeof require&&require,o=0;o=0;--a){var r=this.tryEntries[a],i=r.completion;if("root"===r.tryLoc)return e("end");if(r.tryLoc<=this.prev){var o=b.call(r,"catchLoc"),s=b.call(r,"finallyLoc");if(o&&s){if(this.prev=0;--n){var a=this.tryEntries[n];if(a.tryLoc<=this.prev&&b.call(a,"finallyLoc")&&this.prev=0;--e){var n=this.tryEntries[e];if(n.finallyLoc===t)return this.complete(n.completion,n.afterLoc),d(n),O}},"catch":function(t){for(var e=this.tryEntries.length-1;e>=0;--e){var n=this.tryEntries[e];if(n.tryLoc===t){var a=n.completion;if("throw"===a.type){var r=a.arg;d(n)}return r}}throw Error("illegal catch attempt")},delegateYield:function(t,e,n){return this.delegate={iterator:h(t),resultName:e,nextLoc:n},"next"===this.method&&(this.arg=g),O}}}("object"==typeof t?t:"object"==typeof window?window:"object"==typeof self?self:this)}).call(this,void 0!==t?t:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{}],3:[function(t,e,n){t(129),e.exports=t(24).RegExp.escape},{129:129,24:24}],4:[function(t,e,n){e.exports=function(t){if("function"!=typeof t)throw TypeError(t+" is not a function!");return t}},{}],5:[function(t,e,n){var a=t(19);e.exports=function(t,e){if("number"!=typeof t&&"Number"!=a(t))throw TypeError(e);return+t}},{19:19}],6:[function(t,e,n){var a=t(127)("unscopables"),r=Array.prototype;void 0==r[a]&&t(43)(r,a,{}),e.exports=function(t){r[a][t]=!0}},{127:127,43:43}],7:[function(t,e,n){e.exports=function(t,e,n,a){if(!(t instanceof e)||void 0!==a&&a in t)throw TypeError(n+": incorrect invocation!");return t}},{}],8:[function(t,e,n){var a=t(52);e.exports=function(t){if(!a(t))throw TypeError(t+" is not an object!");return t}},{52:52}],9:[function(t,e,n){"use strict";var a=t(117),r=t(112),i=t(116);e.exports=[].copyWithin||function(t,e){var n=a(this),o=i(n.length),s=r(t,o),p=r(e,o),u=arguments.length>2?arguments[2]:void 0,c=Math.min((void 0===u?o:r(u,o))-p,o-s),l=1;for(s>p&&p+c>s&&(l=-1,p+=c-1,s+=c-1);c-- >0;)p in n?n[s]=n[p]:delete n[s],s+=l,p+=l;return n}},{112:112,116:116,117:117}],10:[function(t,e,n){"use strict";var a=t(117),r=t(112),i=t(116);e.exports=function(t){for(var e=a(this),n=i(e.length),o=arguments.length,s=r(o>1?arguments[1]:void 0,n),p=o>2?arguments[2]:void 0,u=void 0===p?n:r(p,n);u>s;)e[s++]=t;return e}},{112:112,116:116,117:117}],11:[function(t,e,n){var a=t(40);e.exports=function(t,e){var n=[];return a(t,!1,n.push,n,e),n}},{40:40}],12:[function(t,e,n){var a=t(115),r=t(116),i=t(112);e.exports=function(t){return function(e,n,o){var s,p=a(e),u=r(p.length),c=i(o,u);if(t&&n!=n){for(;u>c;)if(s=p[c++],s!=s)return!0}else for(;u>c;c++)if((t||c in p)&&p[c]===n)return t||c||0;return!t&&-1}}},{112:112,115:115,116:116}],13:[function(t,e,n){var a=t(26),r=t(48),i=t(117),o=t(116),s=t(16);e.exports=function(t,e){var n=1==t,p=2==t,u=3==t,c=4==t,l=6==t,d=5==t||l,f=e||s;return function(e,s,h){for(var m,g,v=i(e),b=r(v),y=a(s,h,3),_=o(b.length),x=0,w=n?f(e,_):p?f(e,0):void 0;_>x;x++)if((d||x in b)&&(m=b[x],g=y(m,x,v),t))if(n)w[x]=g;else if(g)switch(t){case 3:return!0;case 5:return m;case 6:return x;case 2:w.push(m)}else if(c)return!1;return l?-1:u||c?c:w}}},{116:116,117:117,16:16,26:26,48:48}],14:[function(t,e,n){var a=t(4),r=t(117),i=t(48),o=t(116);e.exports=function(t,e,n,s,p){a(e);var u=r(t),c=i(u),l=o(u.length),d=p?l-1:0,f=p?-1:1;if(2>n)for(;;){if(d in c){s=c[d],d+=f;break}if(d+=f,p?0>d:d>=l)throw TypeError("Reduce of empty array with no initial value")}for(;p?d>=0:l>d;d+=f)d in c&&(s=e(s,c[d],d,u));return s}},{116:116,117:117,4:4,48:48}],15:[function(t,e,n){var a=t(52),r=t(50),i=t(127)("species");e.exports=function(t){var e;return r(t)&&(e=t.constructor,"function"!=typeof e||e!==Array&&!r(e.prototype)||(e=void 0),a(e)&&(e=e[i],null===e&&(e=void 0))),void 0===e?Array:e}},{127:127,50:50,52:52}],16:[function(t,e,n){var a=t(15);e.exports=function(t,e){return new(a(t))(e)}},{15:15}],17:[function(t,e,n){"use strict";var a=t(4),r=t(52),i=t(47),o=[].slice,s={},p=function(t,e,n){if(!(e in s)){for(var a=[],r=0;e>r;r++)a[r]="a["+r+"]";s[e]=Function("F,a","return new F("+a.join(",")+")")}return s[e](t,n)};e.exports=Function.bind||function(t){var e=a(this),n=o.call(arguments,1),s=function(){var a=n.concat(o.call(arguments));return this instanceof s?p(e,a.length,a):i(e,a,t)};return r(e.prototype)&&(s.prototype=e.prototype),s}},{4:4,47:47,52:52}],18:[function(t,e,n){var a=t(19),r=t(127)("toStringTag"),i="Arguments"==a(function(){return arguments}()),o=function(t,e){try{return t[e]}catch(n){}};e.exports=function(t){var e,n,s;return void 0===t?"Undefined":null===t?"Null":"string"==typeof(n=o(e=Object(t),r))?n:i?a(e):"Object"==(s=a(e))&&"function"==typeof e.callee?"Arguments":s}},{127:127,19:19}],19:[function(t,e,n){var a={}.toString;e.exports=function(t){return a.call(t).slice(8,-1)}},{}],20:[function(t,e,n){"use strict";var a=t(72).f,r=t(71),i=t(91),o=t(26),s=t(7),p=t(40),u=t(56),c=t(58),l=t(98),d=t(30),f=t(66).fastKey,h=t(124),m=d?"_s":"size",g=function(t,e){var n,a=f(e);if("F"!==a)return t._i[a];for(n=t._f;n;n=n.n)if(n.k==e)return n};e.exports={getConstructor:function(t,e,n,u){var c=t(function(t,a){s(t,c,e,"_i"),t._t=e,t._i=r(null),t._f=void 0,t._l=void 0,t[m]=0,void 0!=a&&p(a,n,t[u],t)});return i(c.prototype,{clear:function(){for(var t=h(this,e),n=t._i,a=t._f;a;a=a.n)a.r=!0,a.p&&(a.p=a.p.n=void 0),delete n[a.i];t._f=t._l=void 0,t[m]=0},"delete":function(t){var n=h(this,e),a=g(n,t);if(a){var r=a.n,i=a.p;delete n._i[a.i],a.r=!0,i&&(i.n=r),r&&(r.p=i),n._f==a&&(n._f=r),n._l==a&&(n._l=i),n[m]--}return!!a},forEach:function(t){h(this,e);for(var n,a=o(t,arguments.length>1?arguments[1]:void 0,3);n=n?n.n:this._f;)for(a(n.v,n.k,this);n&&n.r;)n=n.p},has:function(t){return!!g(h(this,e),t)}}),d&&a(c.prototype,"size",{get:function(){return h(this,e)[m]}}),c},def:function(t,e,n){var a,r,i=g(t,e);return i?i.v=n:(t._l=i={i:r=f(e,!0),k:e,v:n,p:a=t._l,n:void 0,r:!1},t._f||(t._f=i),a&&(a.n=i),t[m]++,"F"!==r&&(t._i[r]=i)),t},getEntry:g,setStrong:function(t,e,n){u(t,e,function(t,n){this._t=h(t,e),this._k=n,this._l=void 0},function(){for(var t=this,e=t._k,n=t._l;n&&n.r;)n=n.p;return t._t&&(t._l=n=n?n.n:t._t._f)?"keys"==e?c(0,n.k):"values"==e?c(0,n.v):c(0,[n.k,n.v]):(t._t=void 0,c(1))},n?"entries":"values",!n,!0),l(e)}}},{124:124,26:26,30:30,40:40,56:56,58:58,66:66,7:7,71:71,72:72,91:91,98:98}],21:[function(t,e,n){var a=t(18),r=t(11);e.exports=function(t){return function(){if(a(this)!=t)throw TypeError(t+"#toJSON isn't generic");return r(this)}}},{11:11,18:18}],22:[function(t,e,n){"use strict";var a=t(91),r=t(66).getWeak,i=t(8),o=t(52),s=t(7),p=t(40),u=t(13),c=t(42),l=t(124),d=u(5),f=u(6),h=0,m=function(t){return t._l||(t._l=new g)},g=function(){this.a=[]},v=function(t,e){return d(t.a,function(t){return t[0]===e})};g.prototype={get:function(t){var e=v(this,t);return e?e[1]:void 0},has:function(t){return!!v(this,t)},set:function(t,e){var n=v(this,t);n?n[1]=e:this.a.push([t,e])},"delete":function(t){var e=f(this.a,function(e){return e[0]===t});return~e&&this.a.splice(e,1),!!~e}},e.exports={getConstructor:function(t,e,n,i){var u=t(function(t,a){s(t,u,e,"_i"),t._t=e,t._i=h++,t._l=void 0,void 0!=a&&p(a,n,t[i],t)});return a(u.prototype,{"delete":function(t){if(!o(t))return!1;var n=r(t);return n===!0?m(l(this,e))["delete"](t):n&&c(n,this._i)&&delete n[this._i]},has:function(t){if(!o(t))return!1;var n=r(t);return n===!0?m(l(this,e)).has(t):n&&c(n,this._i)}}),u},def:function(t,e,n){var a=r(i(e),!0);return a===!0?m(t).set(e,n):a[t._i]=n,t},ufstore:m}},{124:124,13:13,40:40,42:42,52:52,66:66,7:7,8:8,91:91}],23:[function(t,e,n){"use strict";var a=t(41),r=t(34),i=t(92),o=t(91),s=t(66),p=t(40),u=t(7),c=t(52),l=t(36),d=t(57),f=t(99),h=t(46);e.exports=function(t,e,n,m,g,v){var b=a[t],y=b,_=g?"set":"add",x=y&&y.prototype,w={},k=function(t){var e=x[t];i(x,t,"delete"==t?function(t){return v&&!c(t)?!1:e.call(this,0===t?0:t)}:"has"==t?function(t){return v&&!c(t)?!1:e.call(this,0===t?0:t)}:"get"==t?function(t){return v&&!c(t)?void 0:e.call(this,0===t?0:t)}:"add"==t?function(t){return e.call(this,0===t?0:t),this}:function(t,n){return e.call(this,0===t?0:t,n),this})};if("function"==typeof y&&(v||x.forEach&&!l(function(){(new y).entries().next()}))){var S=new y,E=S[_](v?{}:-0,1)!=S,C=l(function(){S.has(1)}),P=d(function(t){new y(t)}),A=!v&&l(function(){for(var t=new y,e=5;e--;)t[_](e,e);return!t.has(-0)});P||(y=e(function(e,n){u(e,y,t);var a=h(new b,e,y);return void 0!=n&&p(n,g,a[_],a),a}),y.prototype=x,x.constructor=y),(C||A)&&(k("delete"),k("has"),g&&k("get")),(A||E)&&k(_),v&&x.clear&&delete x.clear}else y=m.getConstructor(e,t,g,_),o(y.prototype,n),s.NEED=!0;return f(y,t),w[t]=y,r(r.G+r.W+r.F*(y!=b),w),v||m.setStrong(y,t,g),y}},{34:34,36:36,40:40,41:41,46:46,52:52,57:57,66:66,7:7,91:91,92:92,99:99}],24:[function(t,e,n){var a=e.exports={version:"2.5.6"};"number"==typeof __e&&(__e=a)},{}],25:[function(t,e,n){"use strict";var a=t(72),r=t(90);e.exports=function(t,e,n){e in t?a.f(t,e,r(0,n)):t[e]=n}},{72:72,90:90}],26:[function(t,e,n){var a=t(4);e.exports=function(t,e,n){if(a(t),void 0===e)return t;switch(n){case 1:return function(n){return t.call(e,n)};case 2:return function(n,a){return t.call(e,n,a)};case 3:return function(n,a,r){return t.call(e,n,a,r)}}return function(){return t.apply(e,arguments)}}},{4:4}],27:[function(t,e,n){"use strict";var a=t(36),r=Date.prototype.getTime,i=Date.prototype.toISOString,o=function(t){return t>9?t:"0"+t};e.exports=a(function(){return"0385-07-25T07:06:39.999Z"!=i.call(new Date(-5e13-1))})||!a(function(){i.call(new Date(NaN))})?function(){if(!isFinite(r.call(this)))throw RangeError("Invalid time value");var t=this,e=t.getUTCFullYear(),n=t.getUTCMilliseconds(),a=0>e?"-":e>9999?"+":"";return a+("00000"+Math.abs(e)).slice(a?-6:-4)+"-"+o(t.getUTCMonth()+1)+"-"+o(t.getUTCDate())+"T"+o(t.getUTCHours())+":"+o(t.getUTCMinutes())+":"+o(t.getUTCSeconds())+"."+(n>99?n:"0"+o(n))+"Z"}:i},{36:36}],28:[function(t,e,n){"use strict";var a=t(8),r=t(118),i="number";e.exports=function(t){if("string"!==t&&t!==i&&"default"!==t)throw TypeError("Incorrect hint");return r(a(this),t!=i)}},{118:118,8:8}],29:[function(t,e,n){e.exports=function(t){if(void 0==t)throw TypeError("Can't call method on "+t);return t}},{}],30:[function(t,e,n){e.exports=!t(36)(function(){return 7!=Object.defineProperty({},"a",{get:function(){return 7}}).a})},{36:36}],31:[function(t,e,n){var a=t(52),r=t(41).document,i=a(r)&&a(r.createElement);e.exports=function(t){return i?r.createElement(t):{}}},{41:41,52:52}],32:[function(t,e,n){e.exports="constructor,hasOwnProperty,isPrototypeOf,propertyIsEnumerable,toLocaleString,toString,valueOf".split(",")},{}],33:[function(t,e,n){var a=t(81),r=t(78),i=t(82);e.exports=function(t){var e=a(t),n=r.f;if(n)for(var o,s=n(t),p=i.f,u=0;s.length>u;)p.call(t,o=s[u++])&&e.push(o);return e}},{78:78,81:81,82:82}],34:[function(t,e,n){var a=t(41),r=t(24),i=t(43),o=t(92),s=t(26),p="prototype",u=function(t,e,n){var c,l,d,f,h=t&u.F,m=t&u.G,g=t&u.S,v=t&u.P,b=t&u.B,y=m?a:g?a[e]||(a[e]={}):(a[e]||{})[p],_=m?r:r[e]||(r[e]={}),x=_[p]||(_[p]={});m&&(n=e);for(c in n)l=!h&&y&&void 0!==y[c],d=(l?y:n)[c],f=b&&l?s(d,a):v&&"function"==typeof d?s(Function.call,d):d,y&&o(y,c,d,t&u.U),_[c]!=d&&i(_,c,f),v&&x[c]!=d&&(x[c]=d)};a.core=r,u.F=1,u.G=2,u.S=4,u.P=8,u.B=16,u.W=32,u.U=64,u.R=128,e.exports=u},{24:24,26:26,41:41,43:43,92:92}],35:[function(t,e,n){var a=t(127)("match");e.exports=function(t){var e=/./;try{"/./"[t](e)}catch(n){try{return e[a]=!1,!"/./"[t](e)}catch(r){}}return!0}},{127:127}],36:[function(t,e,n){e.exports=function(t){try{return!!t()}catch(e){return!0}}},{}],37:[function(t,e,n){"use strict";var a=t(43),r=t(92),i=t(36),o=t(29),s=t(127);e.exports=function(t,e,n){var p=s(t),u=n(o,p,""[t]),c=u[0],l=u[1];i(function(){var e={};return e[p]=function(){return 7},7!=""[t](e)})&&(r(String.prototype,t,c),a(RegExp.prototype,p,2==e?function(t,e){return l.call(t,this,e)}:function(t){return l.call(t,this)}))}},{127:127,29:29,36:36,43:43,92:92}],38:[function(t,e,n){"use strict";var a=t(8);e.exports=function(){var t=a(this),e="";return t.global&&(e+="g"),t.ignoreCase&&(e+="i"),t.multiline&&(e+="m"),t.unicode&&(e+="u"),t.sticky&&(e+="y"),e}},{8:8}],39:[function(t,e,n){"use strict";function a(t,e,n,u,c,l,d,f){for(var h,m,g=c,v=0,b=d?s(d,f,3):!1;u>v;){if(v in n){if(h=b?b(n[v],v,e):n[v],m=!1,i(h)&&(m=h[p],m=void 0!==m?!!m:r(h)),m&&l>0)g=a(t,e,h,o(h.length),g,l-1)-1;else{if(g>=9007199254740991)throw TypeError();t[g]=h}g++}v++}return g}var r=t(50),i=t(52),o=t(116),s=t(26),p=t(127)("isConcatSpreadable");e.exports=a},{116:116,127:127,26:26,50:50,52:52}],40:[function(t,e,n){var a=t(26),r=t(54),i=t(49),o=t(8),s=t(116),p=t(128),u={},c={},n=e.exports=function(t,e,n,l,d){var f,h,m,g,v=d?function(){return t}:p(t),b=a(n,l,e?2:1),y=0;if("function"!=typeof v)throw TypeError(t+" is not iterable!");if(i(v)){for(f=s(t.length);f>y;y++)if(g=e?b(o(h=t[y])[0],h[1]):b(t[y]),g===u||g===c)return g}else for(m=v.call(t);!(h=m.next()).done;)if(g=r(m,b,h.value,e),g===u||g===c)return g};n.BREAK=u,n.RETURN=c},{116:116,128:128,26:26,49:49,54:54,8:8}],41:[function(t,e,n){var a=e.exports="undefined"!=typeof window&&window.Math==Math?window:"undefined"!=typeof self&&self.Math==Math?self:Function("return this")();"number"==typeof __g&&(__g=a)},{}],42:[function(t,e,n){var a={}.hasOwnProperty;e.exports=function(t,e){return a.call(t,e)}},{}],43:[function(t,e,n){var a=t(72),r=t(90);e.exports=t(30)?function(t,e,n){return a.f(t,e,r(1,n))}:function(t,e,n){return t[e]=n,t}},{30:30,72:72,90:90}],44:[function(t,e,n){var a=t(41).document;e.exports=a&&a.documentElement},{41:41}],45:[function(t,e,n){e.exports=!t(30)&&!t(36)(function(){return 7!=Object.defineProperty(t(31)("div"),"a",{get:function(){return 7}}).a})},{30:30,31:31,36:36}],46:[function(t,e,n){var a=t(52),r=t(97).set;e.exports=function(t,e,n){var i,o=e.constructor;return o!==n&&"function"==typeof o&&(i=o.prototype)!==n.prototype&&a(i)&&r&&r(t,i),t}},{52:52,97:97}],47:[function(t,e,n){e.exports=function(t,e,n){var a=void 0===n;switch(e.length){case 0:return a?t():t.call(n);case 1:return a?t(e[0]):t.call(n,e[0]);case 2:return a?t(e[0],e[1]):t.call(n,e[0],e[1]);case 3:return a?t(e[0],e[1],e[2]):t.call(n,e[0],e[1],e[2]);case 4:return a?t(e[0],e[1],e[2],e[3]):t.call(n,e[0],e[1],e[2],e[3])}return t.apply(n,e)}},{}],48:[function(t,e,n){var a=t(19);e.exports=Object("z").propertyIsEnumerable(0)?Object:function(t){return"String"==a(t)?t.split(""):Object(t)}},{19:19}],49:[function(t,e,n){var a=t(59),r=t(127)("iterator"),i=Array.prototype;e.exports=function(t){return void 0!==t&&(a.Array===t||i[r]===t)}},{127:127,59:59}],50:[function(t,e,n){var a=t(19);e.exports=Array.isArray||function(t){return"Array"==a(t)}},{19:19}],51:[function(t,e,n){var a=t(52),r=Math.floor;e.exports=function(t){return!a(t)&&isFinite(t)&&r(t)===t}},{52:52}],52:[function(t,e,n){e.exports=function(t){return"object"==typeof t?null!==t:"function"==typeof t}},{}],53:[function(t,e,n){var a=t(52),r=t(19),i=t(127)("match");e.exports=function(t){var e;return a(t)&&(void 0!==(e=t[i])?!!e:"RegExp"==r(t))}},{127:127,19:19,52:52}],54:[function(t,e,n){var a=t(8);e.exports=function(t,e,n,r){try{return r?e(a(n)[0],n[1]):e(n)}catch(i){var o=t["return"];throw void 0!==o&&a(o.call(t)),i}}},{8:8}],55:[function(t,e,n){"use strict";var a=t(71),r=t(90),i=t(99),o={};t(43)(o,t(127)("iterator"),function(){return this}),e.exports=function(t,e,n){t.prototype=a(o,{next:r(1,n)}),i(t,e+" Iterator")}},{127:127,43:43,71:71,90:90,99:99}],56:[function(t,e,n){"use strict";var a=t(60),r=t(34),i=t(92),o=t(43),s=t(59),p=t(55),u=t(99),c=t(79),l=t(127)("iterator"),d=!([].keys&&"next"in[].keys()),f="@@iterator",h="keys",m="values",g=function(){return this};e.exports=function(t,e,n,v,b,y,_){p(n,e,v);var x,w,k,S=function(t){if(!d&&t in A)return A[t];switch(t){case h:return function(){return new n(this,t)};case m:return function(){return new n(this,t)}}return function(){return new n(this,t)}},E=e+" Iterator",C=b==m,P=!1,A=t.prototype,O=A[l]||A[f]||b&&A[b],T=O||S(b),R=b?C?S("entries"):T:void 0,M="Array"==e?A.entries||O:O;if(M&&(k=c(M.call(new t)),k!==Object.prototype&&k.next&&(u(k,E,!0),a||"function"==typeof k[l]||o(k,l,g))),C&&O&&O.name!==m&&(P=!0,T=function(){return O.call(this)}),a&&!_||!d&&!P&&A[l]||o(A,l,T),s[e]=T,s[E]=g,b)if(x={values:C?T:S(m),keys:y?T:S(h),entries:R},_)for(w in x)w in A||i(A,w,x[w]);else r(r.P+r.F*(d||P),e,x);return x}},{127:127,34:34,43:43,55:55,59:59,60:60,79:79,92:92,99:99}],57:[function(t,e,n){var a=t(127)("iterator"),r=!1;try{var i=[7][a]();i["return"]=function(){r=!0},Array.from(i,function(){throw 2})}catch(o){}e.exports=function(t,e){if(!e&&!r)return!1;var n=!1;try{var i=[7],o=i[a]();o.next=function(){return{done:n=!0}},i[a]=function(){return o},t(i)}catch(s){}return n}},{127:127}],58:[function(t,e,n){e.exports=function(t,e){return{value:e,done:!!t}}},{}],59:[function(t,e,n){e.exports={}},{}],60:[function(t,e,n){e.exports=!1},{}],61:[function(t,e,n){var a=Math.expm1;e.exports=!a||a(10)>22025.465794806718||a(10)<22025.465794806718||-2e-17!=a(-2e-17)?function(t){return 0==(t=+t)?t:t>-1e-6&&1e-6>t?t+t*t/2:Math.exp(t)-1}:a},{}],62:[function(t,e,n){var a=t(65),r=Math.pow,i=r(2,-52),o=r(2,-23),s=r(2,127)*(2-o),p=r(2,-126),u=function(t){return t+1/i-1/i};e.exports=Math.fround||function(t){var e,n,r=Math.abs(t),c=a(t);return p>r?c*u(r/p/o)*p*o:(e=(1+o/i)*r,n=e-(e-r),n>s||n!=n?c*(1/0):c*n)}},{65:65}],63:[function(t,e,n){e.exports=Math.log1p||function(t){return(t=+t)>-1e-8&&1e-8>t?t-t*t/2:Math.log(1+t)}},{}],64:[function(t,e,n){e.exports=Math.scale||function(t,e,n,a,r){return 0===arguments.length||t!=t||e!=e||n!=n||a!=a||r!=r?NaN:t===1/0||t===-(1/0)?t:(t-e)*(r-a)/(n-e)+a}},{}],65:[function(t,e,n){e.exports=Math.sign||function(t){return 0==(t=+t)||t!=t?t:0>t?-1:1}},{}],66:[function(t,e,n){var a=t(122)("meta"),r=t(52),i=t(42),o=t(72).f,s=0,p=Object.isExtensible||function(){return!0},u=!t(36)(function(){return p(Object.preventExtensions({}))}),c=function(t){o(t,a,{value:{i:"O"+ ++s,w:{}}})},l=function(t,e){if(!r(t))return"symbol"==typeof t?t:("string"==typeof t?"S":"P")+t;if(!i(t,a)){if(!p(t))return"F";if(!e)return"E";c(t)}return t[a].i},d=function(t,e){if(!i(t,a)){if(!p(t))return!0;if(!e)return!1;c(t)}return t[a].w},f=function(t){return u&&h.NEED&&p(t)&&!i(t,a)&&c(t),t},h=e.exports={KEY:a,NEED:!1,fastKey:l,getWeak:d,onFreeze:f}},{122:122,36:36,42:42,52:52,72:72}],67:[function(t,e,n){var a=t(159),r=t(34),i=t(101)("metadata"),o=i.store||(i.store=new(t(265))),s=function(t,e,n){var r=o.get(t);if(!r){if(!n)return;o.set(t,r=new a)}var i=r.get(e);if(!i){if(!n)return;r.set(e,i=new a)}return i},p=function(t,e,n){var a=s(e,n,!1);return void 0===a?!1:a.has(t)},u=function(t,e,n){var a=s(e,n,!1);return void 0===a?void 0:a.get(t)},c=function(t,e,n,a){s(n,a,!0).set(t,e)},l=function(t,e){var n=s(t,e,!1),a=[];return n&&n.forEach(function(t,e){a.push(e)}),a},d=function(t){return void 0===t||"symbol"==typeof t?t:t+""},f=function(t){r(r.S,"Reflect",t)};e.exports={store:o,map:s,has:p,get:u,set:c,keys:l,key:d,exp:f}},{101:101,159:159,265:265,34:34}],68:[function(t,e,n){var a=t(41),r=t(111).set,i=a.MutationObserver||a.WebKitMutationObserver,o=a.process,s=a.Promise,p="process"==t(19)(o);e.exports=function(){var t,e,n,u=function(){var a,r;for(p&&(a=o.domain)&&a.exit();t;){r=t.fn,t=t.next;try{r()}catch(i){throw t?n():e=void 0,i}}e=void 0,a&&a.enter()};if(p)n=function(){o.nextTick(u)};else if(!i||a.navigator&&a.navigator.standalone)if(s&&s.resolve){var c=s.resolve(void 0);n=function(){c.then(u)}}else n=function(){r.call(a,u)};else{var l=!0,d=document.createTextNode("");new i(u).observe(d,{characterData:!0}),n=function(){d.data=l=!l}}return function(a){var r={fn:a,next:void 0};e&&(e.next=r),t||(t=r,n()),e=r}}},{111:111,19:19,41:41}],69:[function(t,e,n){"use strict";function a(t){var e,n;this.promise=new t(function(t,a){if(void 0!==e||void 0!==n)throw TypeError("Bad Promise constructor");e=t,n=a}),this.resolve=r(e),this.reject=r(n)}var r=t(4);e.exports.f=function(t){return new a(t)}},{4:4}],70:[function(t,e,n){"use strict";var a=t(81),r=t(78),i=t(82),o=t(117),s=t(48),p=Object.assign;e.exports=!p||t(36)(function(){var t={},e={},n=Symbol(),a="abcdefghijklmnopqrst";return t[n]=7,a.split("").forEach(function(t){e[t]=t}),7!=p({},t)[n]||Object.keys(p({},e)).join("")!=a})?function(t,e){for(var n=o(t),p=arguments.length,u=1,c=r.f,l=i.f;p>u;)for(var d,f=s(arguments[u++]),h=c?a(f).concat(c(f)):a(f),m=h.length,g=0;m>g;)l.call(f,d=h[g++])&&(n[d]=f[d]);return n}:p},{117:117,36:36,48:48,78:78,81:81,82:82}],71:[function(t,e,n){var a=t(8),r=t(73),i=t(32),o=t(100)("IE_PROTO"),s=function(){},p="prototype",u=function(){var e,n=t(31)("iframe"),a=i.length,r="<",o=">";for(n.style.display="none",t(44).appendChild(n),n.src="javascript:",e=n.contentWindow.document,e.open(),e.write(r+"script"+o+"document.F=Object"+r+"/script"+o),e.close(),u=e.F;a--;)delete u[p][i[a]];return u()};e.exports=Object.create||function(t,e){var n;return null!==t?(s[p]=a(t),n=new s,s[p]=null,n[o]=t):n=u(),void 0===e?n:r(n,e)}},{100:100,31:31,32:32,44:44,73:73,8:8}],72:[function(t,e,n){var a=t(8),r=t(45),i=t(118),o=Object.defineProperty;n.f=t(30)?Object.defineProperty:function(t,e,n){if(a(t),e=i(e,!0),a(n),r)try{return o(t,e,n)}catch(s){}if("get"in n||"set"in n)throw TypeError("Accessors not supported!");return"value"in n&&(t[e]=n.value),t}},{118:118,30:30,45:45,8:8}],73:[function(t,e,n){var a=t(72),r=t(8),i=t(81);e.exports=t(30)?Object.defineProperties:function(t,e){r(t);for(var n,o=i(e),s=o.length,p=0;s>p;)a.f(t,n=o[p++],e[n]);return t}},{30:30,72:72,8:8,81:81}],74:[function(t,e,n){"use strict";e.exports=t(60)||!t(36)(function(){var e=Math.random();__defineSetter__.call(null,e,function(){}),delete t(41)[e]})},{36:36,41:41,60:60}],75:[function(t,e,n){var a=t(82),r=t(90),i=t(115),o=t(118),s=t(42),p=t(45),u=Object.getOwnPropertyDescriptor;n.f=t(30)?u:function(t,e){if(t=i(t),e=o(e,!0),p)try{return u(t,e)}catch(n){}return s(t,e)?r(!a.f.call(t,e),t[e]):void 0}},{115:115,118:118,30:30,42:42,45:45,82:82,90:90}],76:[function(t,e,n){var a=t(115),r=t(77).f,i={}.toString,o="object"==typeof window&&window&&Object.getOwnPropertyNames?Object.getOwnPropertyNames(window):[],s=function(t){try{return r(t)}catch(e){return o.slice()}};e.exports.f=function(t){return o&&"[object Window]"==i.call(t)?s(t):r(a(t))}},{115:115,77:77}],77:[function(t,e,n){var a=t(80),r=t(32).concat("length","prototype");n.f=Object.getOwnPropertyNames||function(t){return a(t,r)}},{32:32,80:80}],78:[function(t,e,n){n.f=Object.getOwnPropertySymbols},{}],79:[function(t,e,n){var a=t(42),r=t(117),i=t(100)("IE_PROTO"),o=Object.prototype;e.exports=Object.getPrototypeOf||function(t){return t=r(t),a(t,i)?t[i]:"function"==typeof t.constructor&&t instanceof t.constructor?t.constructor.prototype:t instanceof Object?o:null}},{100:100,117:117,42:42}],80:[function(t,e,n){var a=t(42),r=t(115),i=t(12)(!1),o=t(100)("IE_PROTO");e.exports=function(t,e){var n,s=r(t),p=0,u=[];for(n in s)n!=o&&a(s,n)&&u.push(n);for(;e.length>p;)a(s,n=e[p++])&&(~i(u,n)||u.push(n));return u}},{100:100,115:115,12:12,42:42}],81:[function(t,e,n){var a=t(80),r=t(32);e.exports=Object.keys||function(t){return a(t,r)}},{32:32,80:80}],82:[function(t,e,n){n.f={}.propertyIsEnumerable},{}],83:[function(t,e,n){var a=t(34),r=t(24),i=t(36);e.exports=function(t,e){var n=(r.Object||{})[t]||Object[t],o={};o[t]=e(n),a(a.S+a.F*i(function(){n(1)}),"Object",o)}},{24:24,34:34,36:36}],84:[function(t,e,n){var a=t(81),r=t(115),i=t(82).f;e.exports=function(t){return function(e){for(var n,o=r(e),s=a(o),p=s.length,u=0,c=[];p>u;)i.call(o,n=s[u++])&&c.push(t?[n,o[n]]:o[n]);return c}}},{115:115,81:81,82:82}],85:[function(t,e,n){var a=t(77),r=t(78),i=t(8),o=t(41).Reflect;e.exports=o&&o.ownKeys||function(t){var e=a.f(i(t)),n=r.f;return n?e.concat(n(t)):e}},{41:41,77:77,78:78,8:8}],86:[function(t,e,n){var a=t(41).parseFloat,r=t(109).trim;e.exports=1/a(t(110)+"-0")!==-(1/0)?function(t){var e=r(t+"",3),n=a(e);return 0===n&&"-"==e.charAt(0)?-0:n}:a},{109:109,110:110,41:41}],87:[function(t,e,n){var a=t(41).parseInt,r=t(109).trim,i=t(110),o=/^[-+]?0[xX]/;e.exports=8!==a(i+"08")||22!==a(i+"0x16")?function(t,e){var n=r(t+"",3);return a(n,e>>>0||(o.test(n)?16:10))}:a},{109:109,110:110,41:41}],88:[function(t,e,n){e.exports=function(t){try{return{e:!1,v:t()}}catch(e){return{e:!0,v:e}}}},{}],89:[function(t,e,n){var a=t(8),r=t(52),i=t(69);e.exports=function(t,e){if(a(t),r(e)&&e.constructor===t)return e;var n=i.f(t),o=n.resolve;return o(e),n.promise}},{52:52,69:69,8:8}],90:[function(t,e,n){e.exports=function(t,e){return{enumerable:!(1&t),configurable:!(2&t),writable:!(4&t),value:e}}},{}],91:[function(t,e,n){var a=t(92);e.exports=function(t,e,n){for(var r in e)a(t,r,e[r],n);return t}},{92:92}],92:[function(t,e,n){var a=t(41),r=t(43),i=t(42),o=t(122)("src"),s="toString",p=Function[s],u=(""+p).split(s);t(24).inspectSource=function(t){return p.call(t)},(e.exports=function(t,e,n,s){var p="function"==typeof n;p&&(i(n,"name")||r(n,"name",e)),t[e]!==n&&(p&&(i(n,o)||r(n,o,t[e]?""+t[e]:u.join(e+""))),t===a?t[e]=n:s?t[e]?t[e]=n:r(t,e,n):(delete t[e],r(t,e,n)))})(Function.prototype,s,function(){
-return"function"==typeof this&&this[o]||p.call(this)})},{122:122,24:24,41:41,42:42,43:43}],93:[function(t,e,n){e.exports=function(t,e){var n=e===Object(e)?function(t){return e[t]}:e;return function(e){return(e+"").replace(t,n)}}},{}],94:[function(t,e,n){e.exports=Object.is||function(t,e){return t===e?0!==t||1/t===1/e:t!=t&&e!=e}},{}],95:[function(t,e,n){"use strict";var a=t(34),r=t(4),i=t(26),o=t(40);e.exports=function(t){a(a.S,t,{from:function(t){var e,n,a,s,p=arguments[1];return r(this),e=void 0!==p,e&&r(p),void 0==t?new this:(n=[],e?(a=0,s=i(p,arguments[2],2),o(t,!1,function(t){n.push(s(t,a++))})):o(t,!1,n.push,n),new this(n))}})}},{26:26,34:34,4:4,40:40}],96:[function(t,e,n){"use strict";var a=t(34);e.exports=function(t){a(a.S,t,{of:function(){for(var t=arguments.length,e=Array(t);t--;)e[t]=arguments[t];return new this(e)}})}},{34:34}],97:[function(t,e,n){var a=t(52),r=t(8),i=function(t,e){if(r(t),!a(e)&&null!==e)throw TypeError(e+": can't set as prototype!")};e.exports={set:Object.setPrototypeOf||("__proto__"in{}?function(e,n,a){try{a=t(26)(Function.call,t(75).f(Object.prototype,"__proto__").set,2),a(e,[]),n=!(e instanceof Array)}catch(r){n=!0}return function(t,e){return i(t,e),n?t.__proto__=e:a(t,e),t}}({},!1):void 0),check:i}},{26:26,52:52,75:75,8:8}],98:[function(t,e,n){"use strict";var a=t(41),r=t(72),i=t(30),o=t(127)("species");e.exports=function(t){var e=a[t];i&&e&&!e[o]&&r.f(e,o,{configurable:!0,get:function(){return this}})}},{127:127,30:30,41:41,72:72}],99:[function(t,e,n){var a=t(72).f,r=t(42),i=t(127)("toStringTag");e.exports=function(t,e,n){t&&!r(t=n?t:t.prototype,i)&&a(t,i,{configurable:!0,value:e})}},{127:127,42:42,72:72}],100:[function(t,e,n){var a=t(101)("keys"),r=t(122);e.exports=function(t){return a[t]||(a[t]=r(t))}},{101:101,122:122}],101:[function(t,e,n){var a=t(24),r=t(41),i="__core-js_shared__",o=r[i]||(r[i]={});(e.exports=function(t,e){return o[t]||(o[t]=void 0!==e?e:{})})("versions",[]).push({version:a.version,mode:t(60)?"pure":"global",copyright:"© 2018 Denis Pushkarev (zloirock.ru)"})},{24:24,41:41,60:60}],102:[function(t,e,n){var a=t(8),r=t(4),i=t(127)("species");e.exports=function(t,e){var n,o=a(t).constructor;return void 0===o||void 0==(n=a(o)[i])?e:r(n)}},{127:127,4:4,8:8}],103:[function(t,e,n){"use strict";var a=t(36);e.exports=function(t,e){return!!t&&a(function(){e?t.call(null,function(){},1):t.call(null)})}},{36:36}],104:[function(t,e,n){var a=t(114),r=t(29);e.exports=function(t){return function(e,n){var i,o,s=r(e)+"",p=a(n),u=s.length;return 0>p||p>=u?t?"":void 0:(i=s.charCodeAt(p),55296>i||i>56319||p+1===u||(o=s.charCodeAt(p+1))<56320||o>57343?t?s.charAt(p):i:t?s.slice(p,p+2):(i-55296<<10)+(o-56320)+65536)}}},{114:114,29:29}],105:[function(t,e,n){var a=t(53),r=t(29);e.exports=function(t,e,n){if(a(e))throw TypeError("String#"+n+" doesn't accept regex!");return r(t)+""}},{29:29,53:53}],106:[function(t,e,n){var a=t(34),r=t(36),i=t(29),o=/"/g,s=function(t,e,n,a){var r=i(t)+"",s="<"+e;return""!==n&&(s+=" "+n+'="'+(a+"").replace(o,""")+'"'),s+">"+r+""+e+">"};e.exports=function(t,e){var n={};n[t]=e(s),a(a.P+a.F*r(function(){var e=""[t]('"');return e!==e.toLowerCase()||e.split('"').length>3}),"String",n)}},{29:29,34:34,36:36}],107:[function(t,e,n){var a=t(116),r=t(108),i=t(29);e.exports=function(t,e,n,o){var s=i(t)+"",p=s.length,u=void 0===n?" ":n+"",c=a(e);if(p>=c||""==u)return s;var l=c-p,d=r.call(u,Math.ceil(l/u.length));return d.length>l&&(d=d.slice(0,l)),o?d+s:s+d}},{108:108,116:116,29:29}],108:[function(t,e,n){"use strict";var a=t(114),r=t(29);e.exports=function(t){var e=r(this)+"",n="",i=a(t);if(0>i||i==1/0)throw RangeError("Count can't be negative");for(;i>0;(i>>>=1)&&(e+=e))1&i&&(n+=e);return n}},{114:114,29:29}],109:[function(t,e,n){var a=t(34),r=t(29),i=t(36),o=t(110),s="["+o+"]",p="
",u=RegExp("^"+s+s+"*"),c=RegExp(s+s+"*$"),l=function(t,e,n){var r={},s=i(function(){return!!o[t]()||p[t]()!=p}),u=r[t]=s?e(d):o[t];n&&(r[n]=u),a(a.P+a.F*s,"String",r)},d=l.trim=function(t,e){return t=r(t)+"",1&e&&(t=t.replace(u,"")),2&e&&(t=t.replace(c,"")),t};e.exports=l},{110:110,29:29,34:34,36:36}],110:[function(t,e,n){e.exports=" \n\x0B\f\r \u2028\u2029\ufeff"},{}],111:[function(t,e,n){var a,r,i,o=t(26),s=t(47),p=t(44),u=t(31),c=t(41),l=c.process,d=c.setImmediate,f=c.clearImmediate,h=c.MessageChannel,m=c.Dispatch,g=0,v={},b="onreadystatechange",y=function(){var t=+this;if(v.hasOwnProperty(t)){var e=v[t];delete v[t],e()}},_=function(t){y.call(t.data)};d&&f||(d=function(t){for(var e=[],n=1;arguments.length>n;)e.push(arguments[n++]);return v[++g]=function(){s("function"==typeof t?t:Function(t),e)},a(g),g},f=function(t){delete v[t]},"process"==t(19)(l)?a=function(t){l.nextTick(o(y,t,1))}:m&&m.now?a=function(t){m.now(o(y,t,1))}:h?(r=new h,i=r.port2,r.port1.onmessage=_,a=o(i.postMessage,i,1)):c.addEventListener&&"function"==typeof postMessage&&!c.importScripts?(a=function(t){c.postMessage(t+"","*")},c.addEventListener("message",_,!1)):a=b in u("script")?function(t){p.appendChild(u("script"))[b]=function(){p.removeChild(this),y.call(t)}}:function(t){setTimeout(o(y,t,1),0)}),e.exports={set:d,clear:f}},{19:19,26:26,31:31,41:41,44:44,47:47}],112:[function(t,e,n){var a=t(114),r=Math.max,i=Math.min;e.exports=function(t,e){return t=a(t),0>t?r(t+e,0):i(t,e)}},{114:114}],113:[function(t,e,n){var a=t(114),r=t(116);e.exports=function(t){if(void 0===t)return 0;var e=a(t),n=r(e);if(e!==n)throw RangeError("Wrong length!");return n}},{114:114,116:116}],114:[function(t,e,n){var a=Math.ceil,r=Math.floor;e.exports=function(t){return isNaN(t=+t)?0:(t>0?r:a)(t)}},{}],115:[function(t,e,n){var a=t(48),r=t(29);e.exports=function(t){return a(r(t))}},{29:29,48:48}],116:[function(t,e,n){var a=t(114),r=Math.min;e.exports=function(t){return t>0?r(a(t),9007199254740991):0}},{114:114}],117:[function(t,e,n){var a=t(29);e.exports=function(t){return Object(a(t))}},{29:29}],118:[function(t,e,n){var a=t(52);e.exports=function(t,e){if(!a(t))return t;var n,r;if(e&&"function"==typeof(n=t.toString)&&!a(r=n.call(t)))return r;if("function"==typeof(n=t.valueOf)&&!a(r=n.call(t)))return r;if(!e&&"function"==typeof(n=t.toString)&&!a(r=n.call(t)))return r;throw TypeError("Can't convert object to primitive value")}},{52:52}],119:[function(t,e,n){"use strict";if(t(30)){var a=t(60),r=t(41),i=t(36),o=t(34),s=t(121),p=t(120),u=t(26),c=t(7),l=t(90),d=t(43),f=t(91),h=t(114),m=t(116),g=t(113),v=t(112),b=t(118),y=t(42),_=t(18),x=t(52),w=t(117),k=t(49),S=t(71),E=t(79),C=t(77).f,P=t(128),A=t(122),O=t(127),T=t(13),R=t(12),M=t(102),L=t(140),j=t(59),D=t(57),N=t(98),F=t(10),I=t(9),B=t(72),q=t(75),U=B.f,V=q.f,G=r.RangeError,z=r.TypeError,W=r.Uint8Array,H="ArrayBuffer",K="Shared"+H,Q="BYTES_PER_ELEMENT",Y="prototype",$=Array[Y],J=p.ArrayBuffer,X=p.DataView,Z=T(0),tt=T(2),et=T(3),nt=T(4),at=T(5),rt=T(6),it=R(!0),ot=R(!1),st=L.values,pt=L.keys,ut=L.entries,ct=$.lastIndexOf,lt=$.reduce,dt=$.reduceRight,ft=$.join,ht=$.sort,mt=$.slice,gt=$.toString,vt=$.toLocaleString,bt=O("iterator"),yt=O("toStringTag"),_t=A("typed_constructor"),xt=A("def_constructor"),wt=s.CONSTR,kt=s.TYPED,St=s.VIEW,Et="Wrong length!",Ct=T(1,function(t,e){return Rt(M(t,t[xt]),e)}),Pt=i(function(){return 1===new W(new Uint16Array([1]).buffer)[0]}),At=!!W&&!!W[Y].set&&i(function(){new W(1).set({})}),Ot=function(t,e){var n=h(t);if(0>n||n%e)throw G("Wrong offset!");return n},Tt=function(t){if(x(t)&&kt in t)return t;throw z(t+" is not a typed array!")},Rt=function(t,e){if(!(x(t)&&_t in t))throw z("It is not a typed array constructor!");return new t(e)},Mt=function(t,e){return Lt(M(t,t[xt]),e)},Lt=function(t,e){for(var n=0,a=e.length,r=Rt(t,a);a>n;)r[n]=e[n++];return r},jt=function(t,e,n){U(t,e,{get:function(){return this._d[n]}})},Dt=function(t){var e,n,a,r,i,o,s=w(t),p=arguments.length,c=p>1?arguments[1]:void 0,l=void 0!==c,d=P(s);if(void 0!=d&&!k(d)){for(o=d.call(s),a=[],e=0;!(i=o.next()).done;e++)a.push(i.value);s=a}for(l&&p>2&&(c=u(c,arguments[2],2)),e=0,n=m(s.length),r=Rt(this,n);n>e;e++)r[e]=l?c(s[e],e):s[e];return r},Nt=function(){for(var t=0,e=arguments.length,n=Rt(this,e);e>t;)n[t]=arguments[t++];return n},Ft=!!W&&i(function(){vt.call(new W(1))}),It=function(){return vt.apply(Ft?mt.call(Tt(this)):Tt(this),arguments)},Bt={copyWithin:function(t,e){return I.call(Tt(this),t,e,arguments.length>2?arguments[2]:void 0)},every:function(t){return nt(Tt(this),t,arguments.length>1?arguments[1]:void 0)},fill:function(t){return F.apply(Tt(this),arguments)},filter:function(t){return Mt(this,tt(Tt(this),t,arguments.length>1?arguments[1]:void 0))},find:function(t){return at(Tt(this),t,arguments.length>1?arguments[1]:void 0)},findIndex:function(t){return rt(Tt(this),t,arguments.length>1?arguments[1]:void 0)},forEach:function(t){Z(Tt(this),t,arguments.length>1?arguments[1]:void 0)},indexOf:function(t){return ot(Tt(this),t,arguments.length>1?arguments[1]:void 0)},includes:function(t){return it(Tt(this),t,arguments.length>1?arguments[1]:void 0)},join:function(t){return ft.apply(Tt(this),arguments)},lastIndexOf:function(t){return ct.apply(Tt(this),arguments)},map:function(t){return Ct(Tt(this),t,arguments.length>1?arguments[1]:void 0)},reduce:function(t){return lt.apply(Tt(this),arguments)},reduceRight:function(t){return dt.apply(Tt(this),arguments)},reverse:function(){for(var t,e=this,n=Tt(e).length,a=Math.floor(n/2),r=0;a>r;)t=e[r],e[r++]=e[--n],e[n]=t;return e},some:function(t){return et(Tt(this),t,arguments.length>1?arguments[1]:void 0)},sort:function(t){return ht.call(Tt(this),t)},subarray:function(t,e){var n=Tt(this),a=n.length,r=v(t,a);return new(M(n,n[xt]))(n.buffer,n.byteOffset+r*n.BYTES_PER_ELEMENT,m((void 0===e?a:v(e,a))-r))}},qt=function(t,e){return Mt(this,mt.call(Tt(this),t,e))},Ut=function(t){Tt(this);var e=Ot(arguments[1],1),n=this.length,a=w(t),r=m(a.length),i=0;if(r+e>n)throw G(Et);for(;r>i;)this[e+i]=a[i++]},Vt={entries:function(){return ut.call(Tt(this))},keys:function(){return pt.call(Tt(this))},values:function(){return st.call(Tt(this))}},Gt=function(t,e){return x(t)&&t[kt]&&"symbol"!=typeof e&&e in t&&+e+""==e+""},zt=function(t,e){return Gt(t,e=b(e,!0))?l(2,t[e]):V(t,e)},Wt=function(t,e,n){return!(Gt(t,e=b(e,!0))&&x(n)&&y(n,"value"))||y(n,"get")||y(n,"set")||n.configurable||y(n,"writable")&&!n.writable||y(n,"enumerable")&&!n.enumerable?U(t,e,n):(t[e]=n.value,t)};wt||(q.f=zt,B.f=Wt),o(o.S+o.F*!wt,"Object",{getOwnPropertyDescriptor:zt,defineProperty:Wt}),i(function(){gt.call({})})&&(gt=vt=function(){return ft.call(this)});var Ht=f({},Bt);f(Ht,Vt),d(Ht,bt,Vt.values),f(Ht,{slice:qt,set:Ut,constructor:function(){},toString:gt,toLocaleString:It}),jt(Ht,"buffer","b"),jt(Ht,"byteOffset","o"),jt(Ht,"byteLength","l"),jt(Ht,"length","e"),U(Ht,yt,{get:function(){return this[kt]}}),e.exports=function(t,e,n,p){p=!!p;var u=t+(p?"Clamped":"")+"Array",l="get"+t,f="set"+t,h=r[u],v=h||{},b=h&&E(h),y=!h||!s.ABV,w={},k=h&&h[Y],P=function(t,n){var a=t._d;return a.v[l](n*e+a.o,Pt)},A=function(t,n,a){var r=t._d;p&&(a=(a=Math.round(a))<0?0:a>255?255:255&a),r.v[f](n*e+r.o,a,Pt)},O=function(t,e){U(t,e,{get:function(){return P(this,e)},set:function(t){return A(this,e,t)},enumerable:!0})};y?(h=n(function(t,n,a,r){c(t,h,u,"_d");var i,o,s,p,l=0,f=0;if(x(n)){if(!(n instanceof J||(p=_(n))==H||p==K))return kt in n?Lt(h,n):Dt.call(h,n);i=n,f=Ot(a,e);var v=n.byteLength;if(void 0===r){if(v%e)throw G(Et);if(o=v-f,0>o)throw G(Et)}else if(o=m(r)*e,o+f>v)throw G(Et);s=o/e}else s=g(n),o=s*e,i=new J(o);for(d(t,"_d",{b:i,o:f,l:o,e:s,v:new X(i)});s>l;)O(t,l++)}),k=h[Y]=S(Ht),d(k,"constructor",h)):i(function(){h(1)})&&i(function(){new h(-1)})&&D(function(t){new h,new h(null),new h(1.5),new h(t)},!0)||(h=n(function(t,n,a,r){c(t,h,u);var i;return x(n)?n instanceof J||(i=_(n))==H||i==K?void 0!==r?new v(n,Ot(a,e),r):void 0!==a?new v(n,Ot(a,e)):new v(n):kt in n?Lt(h,n):Dt.call(h,n):new v(g(n))}),Z(b!==Function.prototype?C(v).concat(C(b)):C(v),function(t){t in h||d(h,t,v[t])}),h[Y]=k,a||(k.constructor=h));var T=k[bt],R=!!T&&("values"==T.name||void 0==T.name),M=Vt.values;d(h,_t,!0),d(k,kt,u),d(k,St,!0),d(k,xt,h),(p?new h(1)[yt]==u:yt in k)||U(k,yt,{get:function(){return u}}),w[u]=h,o(o.G+o.W+o.F*(h!=v),w),o(o.S,u,{BYTES_PER_ELEMENT:e}),o(o.S+o.F*i(function(){v.of.call(h,1)}),u,{from:Dt,of:Nt}),Q in k||d(k,Q,e),o(o.P,u,Bt),N(u),o(o.P+o.F*At,u,{set:Ut}),o(o.P+o.F*!R,u,Vt),a||k.toString==gt||(k.toString=gt),o(o.P+o.F*i(function(){new h(1).slice()}),u,{slice:qt}),o(o.P+o.F*(i(function(){return[1,2].toLocaleString()!=new h([1,2]).toLocaleString()})||!i(function(){k.toLocaleString.call([1,2])})),u,{toLocaleString:It}),j[u]=R?T:M,a||R||d(k,bt,M)}}else e.exports=function(){}},{10:10,102:102,112:112,113:113,114:114,116:116,117:117,118:118,12:12,120:120,121:121,122:122,127:127,128:128,13:13,140:140,18:18,26:26,30:30,34:34,36:36,41:41,42:42,43:43,49:49,52:52,57:57,59:59,60:60,7:7,71:71,72:72,75:75,77:77,79:79,9:9,90:90,91:91,98:98}],120:[function(t,e,n){"use strict";function a(t,e,n){var a,r,i,o=Array(n),s=8*n-e-1,p=(1<>1,c=23===e?U(2,-24)-U(2,-77):0,l=0,d=0>t||0===t&&0>1/t?1:0;for(t=q(t),t!=t||t===I?(r=t!=t?1:0,a=p):(a=V(G(t)/z),t*(i=U(2,-a))<1&&(a--,i*=2),t+=a+u>=1?c/i:c*U(2,1-u),t*i>=2&&(a++,i/=2),a+u>=p?(r=0,a=p):a+u>=1?(r=(t*i-1)*U(2,e),a+=u):(r=t*U(2,u-1)*U(2,e),a=0));e>=8;o[l++]=255&r,r/=256,e-=8);for(a=a<0;o[l++]=255&a,a/=256,s-=8);return o[--l]|=128*d,o}function r(t,e,n){var a,r=8*n-e-1,i=(1<>1,s=r-7,p=n-1,u=t[p--],c=127&u;for(u>>=7;s>0;c=256*c+t[p],p--,s-=8);for(a=c&(1<<-s)-1,c>>=-s,s+=e;s>0;a=256*a+t[p],p--,s-=8);if(0===c)c=1-o;else{if(c===i)return a?NaN:u?-I:I;a+=U(2,e),c-=o}return(u?-1:1)*a*U(2,c-e)}function i(t){return t[3]<<24|t[2]<<16|t[1]<<8|t[0]}function o(t){return[255&t]}function s(t){return[255&t,t>>8&255]}function p(t){return[255&t,t>>8&255,t>>16&255,t>>24&255]}function u(t){return a(t,52,8)}function c(t){return a(t,23,4)}function l(t,e,n){C(t[R],e,{get:function(){return this[n]}})}function d(t,e,n,a){var r=+n,i=S(r);if(i+e>t[Y])throw F(L);var o=t[Q]._b,s=i+t[$],p=o.slice(s,s+e);return a?p:p.reverse()}function f(t,e,n,a,r,i){var o=+n,s=S(o);if(s+e>t[Y])throw F(L);for(var p=t[Q]._b,u=s+t[$],c=a(+r),l=0;e>l;l++)p[u+l]=c[i?l:e-l-1]}var h=t(41),m=t(30),g=t(60),v=t(121),b=t(43),y=t(91),_=t(36),x=t(7),w=t(114),k=t(116),S=t(113),E=t(77).f,C=t(72).f,P=t(10),A=t(99),O="ArrayBuffer",T="DataView",R="prototype",M="Wrong length!",L="Wrong index!",j=h[O],D=h[T],N=h.Math,F=h.RangeError,I=h.Infinity,B=j,q=N.abs,U=N.pow,V=N.floor,G=N.log,z=N.LN2,W="buffer",H="byteLength",K="byteOffset",Q=m?"_b":W,Y=m?"_l":H,$=m?"_o":K;if(v.ABV){if(!_(function(){j(1)})||!_(function(){new j(-1)})||_(function(){return new j,new j(1.5),new j(NaN),j.name!=O})){j=function(t){return x(this,j),new B(S(t))};for(var J,X=j[R]=B[R],Z=E(B),tt=0;Z.length>tt;)(J=Z[tt++])in j||b(j,J,B[J]);g||(X.constructor=j)}var et=new D(new j(2)),nt=D[R].setInt8;et.setInt8(0,2147483648),et.setInt8(1,2147483649),(et.getInt8(0)||!et.getInt8(1))&&y(D[R],{setInt8:function(t,e){nt.call(this,t,e<<24>>24)},setUint8:function(t,e){nt.call(this,t,e<<24>>24)}},!0)}else j=function(t){x(this,j,O);var e=S(t);this._b=P.call(Array(e),0),this[Y]=e},D=function(t,e,n){x(this,D,T),x(t,j,T);var a=t[Y],r=w(e);if(0>r||r>a)throw F("Wrong offset!");if(n=void 0===n?a-r:k(n),r+n>a)throw F(M);this[Q]=t,this[$]=r,this[Y]=n},m&&(l(j,H,"_l"),l(D,W,"_b"),l(D,H,"_l"),l(D,K,"_o")),y(D[R],{getInt8:function(t){return d(this,1,t)[0]<<24>>24},getUint8:function(t){return d(this,1,t)[0]},getInt16:function(t){var e=d(this,2,t,arguments[1]);return(e[1]<<8|e[0])<<16>>16},getUint16:function(t){var e=d(this,2,t,arguments[1]);return e[1]<<8|e[0]},getInt32:function(t){return i(d(this,4,t,arguments[1]))},getUint32:function(t){return i(d(this,4,t,arguments[1]))>>>0},getFloat32:function(t){return r(d(this,4,t,arguments[1]),23,4)},getFloat64:function(t){return r(d(this,8,t,arguments[1]),52,8)},setInt8:function(t,e){f(this,1,t,o,e)},setUint8:function(t,e){f(this,1,t,o,e)},setInt16:function(t,e){f(this,2,t,s,e,arguments[2])},setUint16:function(t,e){f(this,2,t,s,e,arguments[2])},setInt32:function(t,e){f(this,4,t,p,e,arguments[2])},setUint32:function(t,e){f(this,4,t,p,e,arguments[2])},setFloat32:function(t,e){f(this,4,t,c,e,arguments[2])},setFloat64:function(t,e){f(this,8,t,u,e,arguments[2])}});A(j,O),A(D,T),b(D[R],v.VIEW,!0),n[O]=j,n[T]=D},{10:10,113:113,114:114,116:116,121:121,30:30,36:36,41:41,43:43,60:60,7:7,72:72,77:77,91:91,99:99}],121:[function(t,e,n){for(var a,r=t(41),i=t(43),o=t(122),s=o("typed_array"),p=o("view"),u=!(!r.ArrayBuffer||!r.DataView),c=u,l=0,d=9,f="Int8Array,Uint8Array,Uint8ClampedArray,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array".split(",");d>l;)(a=r[f[l++]])?(i(a.prototype,s,!0),i(a.prototype,p,!0)):c=!1;e.exports={ABV:u,CONSTR:c,TYPED:s,VIEW:p}},{122:122,41:41,43:43}],122:[function(t,e,n){var a=0,r=Math.random();e.exports=function(t){return"Symbol(".concat(void 0===t?"":t,")_",(++a+r).toString(36))}},{}],123:[function(t,e,n){var a=t(41),r=a.navigator;e.exports=r&&r.userAgent||""},{41:41}],124:[function(t,e,n){var a=t(52);e.exports=function(t,e){if(!a(t)||t._t!==e)throw TypeError("Incompatible receiver, "+e+" required!");return t}},{52:52}],125:[function(t,e,n){var a=t(41),r=t(24),i=t(60),o=t(126),s=t(72).f;e.exports=function(t){var e=r.Symbol||(r.Symbol=i?{}:a.Symbol||{});"_"==t.charAt(0)||t in e||s(e,t,{value:o.f(t)})}},{126:126,24:24,41:41,60:60,72:72}],126:[function(t,e,n){n.f=t(127)},{127:127}],127:[function(t,e,n){var a=t(101)("wks"),r=t(122),i=t(41).Symbol,o="function"==typeof i,s=e.exports=function(t){return a[t]||(a[t]=o&&i[t]||(o?i:r)("Symbol."+t))};s.store=a},{101:101,122:122,41:41}],128:[function(t,e,n){var a=t(18),r=t(127)("iterator"),i=t(59);e.exports=t(24).getIteratorMethod=function(t){return void 0!=t?t[r]||t["@@iterator"]||i[a(t)]:void 0}},{127:127,18:18,24:24,59:59}],129:[function(t,e,n){var a=t(34),r=t(93)(/[\\^$*+?.()|[\]{}]/g,"\\$&");a(a.S,"RegExp",{escape:function(t){return r(t)}})},{34:34,93:93}],130:[function(t,e,n){var a=t(34);a(a.P,"Array",{copyWithin:t(9)}),t(6)("copyWithin")},{34:34,6:6,9:9}],131:[function(t,e,n){"use strict";var a=t(34),r=t(13)(4);a(a.P+a.F*!t(103)([].every,!0),"Array",{every:function(t){return r(this,t,arguments[1])}})},{103:103,13:13,34:34}],132:[function(t,e,n){var a=t(34);a(a.P,"Array",{fill:t(10)}),t(6)("fill")},{10:10,34:34,6:6}],133:[function(t,e,n){"use strict";var a=t(34),r=t(13)(2);a(a.P+a.F*!t(103)([].filter,!0),"Array",{filter:function(t){return r(this,t,arguments[1])}})},{103:103,13:13,34:34}],134:[function(t,e,n){"use strict";var a=t(34),r=t(13)(6),i="findIndex",o=!0;i in[]&&Array(1)[i](function(){o=!1}),a(a.P+a.F*o,"Array",{findIndex:function(t){return r(this,t,arguments.length>1?arguments[1]:void 0)}}),t(6)(i)},{13:13,34:34,6:6}],135:[function(t,e,n){"use strict";var a=t(34),r=t(13)(5),i="find",o=!0;i in[]&&Array(1)[i](function(){o=!1}),a(a.P+a.F*o,"Array",{find:function(t){return r(this,t,arguments.length>1?arguments[1]:void 0)}}),t(6)(i)},{13:13,34:34,6:6}],136:[function(t,e,n){"use strict";var a=t(34),r=t(13)(0),i=t(103)([].forEach,!0);a(a.P+a.F*!i,"Array",{forEach:function(t){return r(this,t,arguments[1])}})},{103:103,13:13,34:34}],137:[function(t,e,n){"use strict";var a=t(26),r=t(34),i=t(117),o=t(54),s=t(49),p=t(116),u=t(25),c=t(128);r(r.S+r.F*!t(57)(function(t){Array.from(t)}),"Array",{from:function(t){var e,n,r,l,d=i(t),f="function"==typeof this?this:Array,h=arguments.length,m=h>1?arguments[1]:void 0,g=void 0!==m,v=0,b=c(d);if(g&&(m=a(m,h>2?arguments[2]:void 0,2)),void 0==b||f==Array&&s(b))for(e=p(d.length),n=new f(e);e>v;v++)u(n,v,g?m(d[v],v):d[v]);else for(l=b.call(d),n=new f;!(r=l.next()).done;v++)u(n,v,g?o(l,m,[r.value,v],!0):r.value);return n.length=v,n}})},{116:116,117:117,128:128,25:25,26:26,34:34,49:49,54:54,57:57}],138:[function(t,e,n){"use strict";var a=t(34),r=t(12)(!1),i=[].indexOf,o=!!i&&1/[1].indexOf(1,-0)<0;a(a.P+a.F*(o||!t(103)(i)),"Array",{indexOf:function(t){return o?i.apply(this,arguments)||0:r(this,t,arguments[1])}})},{103:103,12:12,34:34}],139:[function(t,e,n){var a=t(34);a(a.S,"Array",{isArray:t(50)})},{34:34,50:50}],140:[function(t,e,n){"use strict";var a=t(6),r=t(58),i=t(59),o=t(115);e.exports=t(56)(Array,"Array",function(t,e){this._t=o(t),this._i=0,this._k=e},function(){var t=this._t,e=this._k,n=this._i++;return!t||n>=t.length?(this._t=void 0,r(1)):"keys"==e?r(0,n):"values"==e?r(0,t[n]):r(0,[n,t[n]])},"values"),i.Arguments=i.Array,a("keys"),a("values"),a("entries")},{115:115,56:56,58:58,59:59,6:6}],141:[function(t,e,n){"use strict";var a=t(34),r=t(115),i=[].join;a(a.P+a.F*(t(48)!=Object||!t(103)(i)),"Array",{join:function(t){return i.call(r(this),void 0===t?",":t)}})},{103:103,115:115,34:34,48:48}],142:[function(t,e,n){"use strict";var a=t(34),r=t(115),i=t(114),o=t(116),s=[].lastIndexOf,p=!!s&&1/[1].lastIndexOf(1,-0)<0;a(a.P+a.F*(p||!t(103)(s)),"Array",{lastIndexOf:function(t){if(p)return s.apply(this,arguments)||0;var e=r(this),n=o(e.length),a=n-1;for(arguments.length>1&&(a=Math.min(a,i(arguments[1]))),0>a&&(a=n+a);a>=0;a--)if(a in e&&e[a]===t)return a||0;return-1}})},{103:103,114:114,115:115,116:116,34:34}],143:[function(t,e,n){"use strict";var a=t(34),r=t(13)(1);a(a.P+a.F*!t(103)([].map,!0),"Array",{map:function(t){return r(this,t,arguments[1])}})},{103:103,13:13,34:34}],144:[function(t,e,n){"use strict";var a=t(34),r=t(25);a(a.S+a.F*t(36)(function(){function t(){}return!(Array.of.call(t)instanceof t)}),"Array",{of:function(){for(var t=0,e=arguments.length,n=new("function"==typeof this?this:Array)(e);e>t;)r(n,t,arguments[t++]);return n.length=e,n}})},{25:25,34:34,36:36}],145:[function(t,e,n){"use strict";var a=t(34),r=t(14);a(a.P+a.F*!t(103)([].reduceRight,!0),"Array",{reduceRight:function(t){return r(this,t,arguments.length,arguments[1],!0)}})},{103:103,14:14,34:34}],146:[function(t,e,n){"use strict";var a=t(34),r=t(14);a(a.P+a.F*!t(103)([].reduce,!0),"Array",{reduce:function(t){return r(this,t,arguments.length,arguments[1],!1)}})},{103:103,14:14,34:34}],147:[function(t,e,n){"use strict";var a=t(34),r=t(44),i=t(19),o=t(112),s=t(116),p=[].slice;a(a.P+a.F*t(36)(function(){r&&p.call(r)}),"Array",{slice:function(t,e){var n=s(this.length),a=i(this);if(e=void 0===e?n:e,"Array"==a)return p.call(this,t,e);for(var r=o(t,n),u=o(e,n),c=s(u-r),l=Array(c),d=0;c>d;d++)l[d]="String"==a?this.charAt(r+d):this[r+d];return l}})},{112:112,116:116,19:19,34:34,36:36,44:44}],148:[function(t,e,n){"use strict";var a=t(34),r=t(13)(3);a(a.P+a.F*!t(103)([].some,!0),"Array",{some:function(t){return r(this,t,arguments[1])}})},{103:103,13:13,34:34}],149:[function(t,e,n){"use strict";var a=t(34),r=t(4),i=t(117),o=t(36),s=[].sort,p=[1,2,3];a(a.P+a.F*(o(function(){p.sort(void 0)})||!o(function(){p.sort(null)})||!t(103)(s)),"Array",{sort:function(t){return void 0===t?s.call(i(this)):s.call(i(this),r(t))}})},{103:103,117:117,34:34,36:36,4:4}],150:[function(t,e,n){t(98)("Array")},{98:98}],151:[function(t,e,n){var a=t(34);a(a.S,"Date",{now:function(){return(new Date).getTime()}})},{34:34}],152:[function(t,e,n){var a=t(34),r=t(27);a(a.P+a.F*(Date.prototype.toISOString!==r),"Date",{toISOString:r})},{27:27,34:34}],153:[function(t,e,n){"use strict";var a=t(34),r=t(117),i=t(118);a(a.P+a.F*t(36)(function(){return null!==new Date(NaN).toJSON()||1!==Date.prototype.toJSON.call({toISOString:function(){return 1}})}),"Date",{toJSON:function(t){var e=r(this),n=i(e);return"number"!=typeof n||isFinite(n)?e.toISOString():null}})},{117:117,118:118,34:34,36:36}],154:[function(t,e,n){var a=t(127)("toPrimitive"),r=Date.prototype;a in r||t(43)(r,a,t(28))},{127:127,28:28,43:43}],155:[function(t,e,n){var a=Date.prototype,r="Invalid Date",i="toString",o=a[i],s=a.getTime;new Date(NaN)+""!=r&&t(92)(a,i,function(){var t=s.call(this);return t===t?o.call(this):r})},{92:92}],156:[function(t,e,n){var a=t(34);a(a.P,"Function",{bind:t(17)})},{17:17,34:34}],157:[function(t,e,n){"use strict";var a=t(52),r=t(79),i=t(127)("hasInstance"),o=Function.prototype;i in o||t(72).f(o,i,{value:function(t){if("function"!=typeof this||!a(t))return!1;if(!a(this.prototype))return t instanceof this;for(;t=r(t);)if(this.prototype===t)return!0;return!1}})},{127:127,52:52,72:72,79:79}],158:[function(t,e,n){var a=t(72).f,r=Function.prototype,i=/^\s*function ([^ (]*)/,o="name";o in r||t(30)&&a(r,o,{configurable:!0,get:function(){try{return(""+this).match(i)[1]}catch(t){return""}}})},{30:30,72:72}],159:[function(t,e,n){"use strict";var a=t(20),r=t(124),i="Map";e.exports=t(23)(i,function(t){return function(){return t(this,arguments.length>0?arguments[0]:void 0)}},{get:function(t){var e=a.getEntry(r(this,i),t);return e&&e.v},set:function(t,e){return a.def(r(this,i),0===t?0:t,e)}},a,!0)},{124:124,20:20,23:23}],160:[function(t,e,n){var a=t(34),r=t(63),i=Math.sqrt,o=Math.acosh;a(a.S+a.F*!(o&&710==Math.floor(o(Number.MAX_VALUE))&&o(1/0)==1/0),"Math",{acosh:function(t){return(t=+t)<1?NaN:t>94906265.62425156?Math.log(t)+Math.LN2:r(t-1+i(t-1)*i(t+1))}})},{34:34,63:63}],161:[function(t,e,n){function a(t){return isFinite(t=+t)&&0!=t?0>t?-a(-t):Math.log(t+Math.sqrt(t*t+1)):t}var r=t(34),i=Math.asinh;r(r.S+r.F*!(i&&1/i(0)>0),"Math",{asinh:a})},{34:34}],162:[function(t,e,n){var a=t(34),r=Math.atanh;a(a.S+a.F*!(r&&1/r(-0)<0),"Math",{atanh:function(t){return 0==(t=+t)?t:Math.log((1+t)/(1-t))/2}})},{34:34}],163:[function(t,e,n){var a=t(34),r=t(65);a(a.S,"Math",{cbrt:function(t){return r(t=+t)*Math.pow(Math.abs(t),1/3)}})},{34:34,65:65}],164:[function(t,e,n){var a=t(34);a(a.S,"Math",{clz32:function(t){return(t>>>=0)?31-Math.floor(Math.log(t+.5)*Math.LOG2E):32}})},{34:34}],165:[function(t,e,n){var a=t(34),r=Math.exp;a(a.S,"Math",{cosh:function(t){return(r(t=+t)+r(-t))/2}})},{34:34}],166:[function(t,e,n){var a=t(34),r=t(61);a(a.S+a.F*(r!=Math.expm1),"Math",{expm1:r})},{34:34,61:61}],167:[function(t,e,n){var a=t(34);a(a.S,"Math",{fround:t(62)})},{34:34,62:62}],168:[function(t,e,n){var a=t(34),r=Math.abs;a(a.S,"Math",{hypot:function(t,e){for(var n,a,i=0,o=0,s=arguments.length,p=0;s>o;)n=r(arguments[o++]),n>p?(a=p/n,i=i*a*a+1,p=n):n>0?(a=n/p,i+=a*a):i+=n;return p===1/0?1/0:p*Math.sqrt(i)}})},{34:34}],169:[function(t,e,n){var a=t(34),r=Math.imul;a(a.S+a.F*t(36)(function(){return-5!=r(4294967295,5)||2!=r.length}),"Math",{imul:function(t,e){var n=65535,a=+t,r=+e,i=n&a,o=n&r;return 0|i*o+((n&a>>>16)*o+i*(n&r>>>16)<<16>>>0)}})},{34:34,36:36}],170:[function(t,e,n){var a=t(34);a(a.S,"Math",{log10:function(t){return Math.log(t)*Math.LOG10E}})},{34:34}],171:[function(t,e,n){var a=t(34);a(a.S,"Math",{log1p:t(63)})},{34:34,63:63}],172:[function(t,e,n){var a=t(34);a(a.S,"Math",{log2:function(t){return Math.log(t)/Math.LN2}})},{34:34}],173:[function(t,e,n){var a=t(34);a(a.S,"Math",{sign:t(65)})},{34:34,65:65}],174:[function(t,e,n){var a=t(34),r=t(61),i=Math.exp;a(a.S+a.F*t(36)(function(){return-2e-17!=!Math.sinh(-2e-17)}),"Math",{sinh:function(t){return Math.abs(t=+t)<1?(r(t)-r(-t))/2:(i(t-1)-i(-t-1))*(Math.E/2)}})},{34:34,36:36,61:61}],175:[function(t,e,n){var a=t(34),r=t(61),i=Math.exp;a(a.S,"Math",{tanh:function(t){var e=r(t=+t),n=r(-t);return e==1/0?1:n==1/0?-1:(e-n)/(i(t)+i(-t))}})},{34:34,61:61}],176:[function(t,e,n){var a=t(34);a(a.S,"Math",{trunc:function(t){return(t>0?Math.floor:Math.ceil)(t)}})},{34:34}],177:[function(t,e,n){"use strict";var a=t(41),r=t(42),i=t(19),o=t(46),s=t(118),p=t(36),u=t(77).f,c=t(75).f,l=t(72).f,d=t(109).trim,f="Number",h=a[f],m=h,g=h.prototype,v=i(t(71)(g))==f,b="trim"in String.prototype,y=function(t){var e=s(t,!1);if("string"==typeof e&&e.length>2){e=b?e.trim():d(e,3);var n,a,r,i=e.charCodeAt(0);if(43===i||45===i){if(n=e.charCodeAt(2),88===n||120===n)return NaN}else if(48===i){switch(e.charCodeAt(1)){case 66:case 98:a=2,r=49;break;case 79:case 111:a=8,r=55;break;default:return+e}for(var o,p=e.slice(2),u=0,c=p.length;c>u;u++)if(o=p.charCodeAt(u),48>o||o>r)return NaN;return parseInt(p,a)}}return+e};if(!h(" 0o1")||!h("0b1")||h("+0x1")){h=function(t){var e=arguments.length<1?0:t,n=this;return n instanceof h&&(v?p(function(){g.valueOf.call(n)}):i(n)!=f)?o(new m(y(e)),n,h):y(e)};for(var _,x=t(30)?u(m):"MAX_VALUE,MIN_VALUE,NaN,NEGATIVE_INFINITY,POSITIVE_INFINITY,EPSILON,isFinite,isInteger,isNaN,isSafeInteger,MAX_SAFE_INTEGER,MIN_SAFE_INTEGER,parseFloat,parseInt,isInteger".split(","),w=0;x.length>w;w++)r(m,_=x[w])&&!r(h,_)&&l(h,_,c(m,_));h.prototype=g,g.constructor=h,t(92)(a,f,h)}},{109:109,118:118,19:19,30:30,36:36,41:41,42:42,46:46,71:71,72:72,75:75,77:77,92:92}],178:[function(t,e,n){var a=t(34);a(a.S,"Number",{EPSILON:Math.pow(2,-52)})},{34:34}],179:[function(t,e,n){var a=t(34),r=t(41).isFinite;a(a.S,"Number",{isFinite:function(t){return"number"==typeof t&&r(t)}})},{34:34,41:41}],180:[function(t,e,n){var a=t(34);a(a.S,"Number",{isInteger:t(51)})},{34:34,51:51}],181:[function(t,e,n){var a=t(34);a(a.S,"Number",{isNaN:function(t){return t!=t}})},{34:34}],182:[function(t,e,n){var a=t(34),r=t(51),i=Math.abs;a(a.S,"Number",{isSafeInteger:function(t){return r(t)&&i(t)<=9007199254740991}})},{34:34,51:51}],183:[function(t,e,n){var a=t(34);a(a.S,"Number",{MAX_SAFE_INTEGER:9007199254740991})},{34:34}],184:[function(t,e,n){var a=t(34);a(a.S,"Number",{MIN_SAFE_INTEGER:-9007199254740991})},{34:34}],185:[function(t,e,n){var a=t(34),r=t(86);a(a.S+a.F*(Number.parseFloat!=r),"Number",{parseFloat:r})},{34:34,86:86}],186:[function(t,e,n){var a=t(34),r=t(87);a(a.S+a.F*(Number.parseInt!=r),"Number",{parseInt:r})},{34:34,87:87}],187:[function(t,e,n){"use strict";var a=t(34),r=t(114),i=t(5),o=t(108),s=1..toFixed,p=Math.floor,u=[0,0,0,0,0,0],c="Number.toFixed: incorrect invocation!",l="0",d=function(t,e){for(var n=-1,a=e;++n<6;)a+=t*u[n],u[n]=a%1e7,a=p(a/1e7)},f=function(t){for(var e=6,n=0;--e>=0;)n+=u[e],u[e]=p(n/t),n=n%t*1e7},h=function(){for(var t=6,e="";--t>=0;)if(""!==e||0===t||0!==u[t]){var n=u[t]+"";e=""===e?n:e+o.call(l,7-n.length)+n}return e},m=function(t,e,n){return 0===e?n:e%2===1?m(t,e-1,n*t):m(t*t,e/2,n)},g=function(t){for(var e=0,n=t;n>=4096;)e+=12,n/=4096;for(;n>=2;)e+=1,n/=2;return e};a(a.P+a.F*(!!s&&("0.000"!==8e-5.toFixed(3)||"1"!==.9.toFixed(0)||"1.25"!==1.255.toFixed(2)||"1000000000000000128"!==0xde0b6b3a7640080.toFixed(0))||!t(36)(function(){s.call({})})),"Number",{toFixed:function(t){var e,n,a,s,p=i(this,c),u=r(t),v="",b=l;if(0>u||u>20)throw RangeError(c);if(p!=p)return"NaN";if(-1e21>=p||p>=1e21)return p+"";if(0>p&&(v="-",p=-p),p>1e-21)if(e=g(p*m(2,69,1))-69,n=0>e?p*m(2,-e,1):p/m(2,e,1),n*=4503599627370496,e=52-e,e>0){for(d(0,n),a=u;a>=7;)d(1e7,0),a-=7;for(d(m(10,a,1),0),a=e-1;a>=23;)f(1<<23),a-=23;f(1<0?(s=b.length,b=v+(u>=s?"0."+o.call(l,u-s)+b:b.slice(0,s-u)+"."+b.slice(s-u))):b=v+b,b}})},{108:108,114:114,34:34,36:36,5:5}],188:[function(t,e,n){"use strict";var a=t(34),r=t(36),i=t(5),o=1..toPrecision;a(a.P+a.F*(r(function(){return"1"!==o.call(1,void 0)})||!r(function(){o.call({})})),"Number",{toPrecision:function(t){var e=i(this,"Number#toPrecision: incorrect invocation!");return void 0===t?o.call(e):o.call(e,t)}})},{34:34,36:36,5:5}],189:[function(t,e,n){var a=t(34);a(a.S+a.F,"Object",{assign:t(70)})},{34:34,70:70}],190:[function(t,e,n){var a=t(34);a(a.S,"Object",{create:t(71)})},{34:34,71:71}],191:[function(t,e,n){var a=t(34);a(a.S+a.F*!t(30),"Object",{defineProperties:t(73)})},{30:30,34:34,73:73}],192:[function(t,e,n){var a=t(34);a(a.S+a.F*!t(30),"Object",{defineProperty:t(72).f})},{30:30,34:34,72:72}],193:[function(t,e,n){var a=t(52),r=t(66).onFreeze;t(83)("freeze",function(t){return function(e){return t&&a(e)?t(r(e)):e}})},{52:52,66:66,83:83}],194:[function(t,e,n){var a=t(115),r=t(75).f;t(83)("getOwnPropertyDescriptor",function(){return function(t,e){return r(a(t),e)}})},{115:115,75:75,83:83}],195:[function(t,e,n){t(83)("getOwnPropertyNames",function(){return t(76).f})},{76:76,83:83}],196:[function(t,e,n){var a=t(117),r=t(79);t(83)("getPrototypeOf",function(){return function(t){return r(a(t))}})},{117:117,79:79,83:83}],197:[function(t,e,n){var a=t(52);t(83)("isExtensible",function(t){return function(e){return a(e)?t?t(e):!0:!1}});
-},{52:52,83:83}],198:[function(t,e,n){var a=t(52);t(83)("isFrozen",function(t){return function(e){return a(e)?t?t(e):!1:!0}})},{52:52,83:83}],199:[function(t,e,n){var a=t(52);t(83)("isSealed",function(t){return function(e){return a(e)?t?t(e):!1:!0}})},{52:52,83:83}],200:[function(t,e,n){var a=t(34);a(a.S,"Object",{is:t(94)})},{34:34,94:94}],201:[function(t,e,n){var a=t(117),r=t(81);t(83)("keys",function(){return function(t){return r(a(t))}})},{117:117,81:81,83:83}],202:[function(t,e,n){var a=t(52),r=t(66).onFreeze;t(83)("preventExtensions",function(t){return function(e){return t&&a(e)?t(r(e)):e}})},{52:52,66:66,83:83}],203:[function(t,e,n){var a=t(52),r=t(66).onFreeze;t(83)("seal",function(t){return function(e){return t&&a(e)?t(r(e)):e}})},{52:52,66:66,83:83}],204:[function(t,e,n){var a=t(34);a(a.S,"Object",{setPrototypeOf:t(97).set})},{34:34,97:97}],205:[function(t,e,n){"use strict";var a=t(18),r={};r[t(127)("toStringTag")]="z",r+""!="[object z]"&&t(92)(Object.prototype,"toString",function(){return"[object "+a(this)+"]"},!0)},{127:127,18:18,92:92}],206:[function(t,e,n){var a=t(34),r=t(86);a(a.G+a.F*(parseFloat!=r),{parseFloat:r})},{34:34,86:86}],207:[function(t,e,n){var a=t(34),r=t(87);a(a.G+a.F*(parseInt!=r),{parseInt:r})},{34:34,87:87}],208:[function(t,e,n){"use strict";var a,r,i,o,s=t(60),p=t(41),u=t(26),c=t(18),l=t(34),d=t(52),f=t(4),h=t(7),m=t(40),g=t(102),v=t(111).set,b=t(68)(),y=t(69),_=t(88),x=t(123),w=t(89),k="Promise",S=p.TypeError,E=p.process,C=E&&E.versions,P=C&&C.v8||"",A=p[k],O="process"==c(E),T=function(){},R=r=y.f,M=!!function(){try{var e=A.resolve(1),n=(e.constructor={})[t(127)("species")]=function(t){t(T,T)};return(O||"function"==typeof PromiseRejectionEvent)&&e.then(T)instanceof n&&0!==P.indexOf("6.6")&&-1===x.indexOf("Chrome/66")}catch(a){}}(),L=function(t){var e;return d(t)&&"function"==typeof(e=t.then)?e:!1},j=function(t,e){if(!t._n){t._n=!0;var n=t._c;b(function(){for(var a=t._v,r=1==t._s,i=0,o=function(e){var n,i,o,s=r?e.ok:e.fail,p=e.resolve,u=e.reject,c=e.domain;try{s?(r||(2==t._h&&F(t),t._h=1),s===!0?n=a:(c&&c.enter(),n=s(a),c&&(c.exit(),o=!0)),n===e.promise?u(S("Promise-chain cycle")):(i=L(n))?i.call(n,p,u):p(n)):u(a)}catch(l){c&&!o&&c.exit(),u(l)}};n.length>i;)o(n[i++]);t._c=[],t._n=!1,e&&!t._h&&D(t)})}},D=function(t){v.call(p,function(){var e,n,a,r=t._v,i=N(t);if(i&&(e=_(function(){O?E.emit("unhandledRejection",r,t):(n=p.onunhandledrejection)?n({promise:t,reason:r}):(a=p.console)&&a.error&&a.error("Unhandled promise rejection",r)}),t._h=O||N(t)?2:1),t._a=void 0,i&&e.e)throw e.v})},N=function(t){return 1!==t._h&&0===(t._a||t._c).length},F=function(t){v.call(p,function(){var e;O?E.emit("rejectionHandled",t):(e=p.onrejectionhandled)&&e({promise:t,reason:t._v})})},I=function(t){var e=this;e._d||(e._d=!0,e=e._w||e,e._v=t,e._s=2,e._a||(e._a=e._c.slice()),j(e,!0))},B=function(t){var e,n=this;if(!n._d){n._d=!0,n=n._w||n;try{if(n===t)throw S("Promise can't be resolved itself");(e=L(t))?b(function(){var a={_w:n,_d:!1};try{e.call(t,u(B,a,1),u(I,a,1))}catch(r){I.call(a,r)}}):(n._v=t,n._s=1,j(n,!1))}catch(a){I.call({_w:n,_d:!1},a)}}};M||(A=function(t){h(this,A,k,"_h"),f(t),a.call(this);try{t(u(B,this,1),u(I,this,1))}catch(e){I.call(this,e)}},a=function(t){this._c=[],this._a=void 0,this._s=0,this._d=!1,this._v=void 0,this._h=0,this._n=!1},a.prototype=t(91)(A.prototype,{then:function(t,e){var n=R(g(this,A));return n.ok="function"==typeof t?t:!0,n.fail="function"==typeof e&&e,n.domain=O?E.domain:void 0,this._c.push(n),this._a&&this._a.push(n),this._s&&j(this,!1),n.promise},"catch":function(t){return this.then(void 0,t)}}),i=function(){var t=new a;this.promise=t,this.resolve=u(B,t,1),this.reject=u(I,t,1)},y.f=R=function(t){return t===A||t===o?new i(t):r(t)}),l(l.G+l.W+l.F*!M,{Promise:A}),t(99)(A,k),t(98)(k),o=t(24)[k],l(l.S+l.F*!M,k,{reject:function(t){var e=R(this),n=e.reject;return n(t),e.promise}}),l(l.S+l.F*(s||!M),k,{resolve:function(t){return w(s&&this===o?A:this,t)}}),l(l.S+l.F*!(M&&t(57)(function(t){A.all(t)["catch"](T)})),k,{all:function(t){var e=this,n=R(e),a=n.resolve,r=n.reject,i=_(function(){var n=[],i=0,o=1;m(t,!1,function(t){var s=i++,p=!1;n.push(void 0),o++,e.resolve(t).then(function(t){p||(p=!0,n[s]=t,--o||a(n))},r)}),--o||a(n)});return i.e&&r(i.v),n.promise},race:function(t){var e=this,n=R(e),a=n.reject,r=_(function(){m(t,!1,function(t){e.resolve(t).then(n.resolve,a)})});return r.e&&a(r.v),n.promise}})},{102:102,111:111,123:123,127:127,18:18,24:24,26:26,34:34,4:4,40:40,41:41,52:52,57:57,60:60,68:68,69:69,7:7,88:88,89:89,91:91,98:98,99:99}],209:[function(t,e,n){var a=t(34),r=t(4),i=t(8),o=(t(41).Reflect||{}).apply,s=Function.apply;a(a.S+a.F*!t(36)(function(){o(function(){})}),"Reflect",{apply:function(t,e,n){var a=r(t),p=i(n);return o?o(a,e,p):s.call(a,e,p)}})},{34:34,36:36,4:4,41:41,8:8}],210:[function(t,e,n){var a=t(34),r=t(71),i=t(4),o=t(8),s=t(52),p=t(36),u=t(17),c=(t(41).Reflect||{}).construct,l=p(function(){function t(){}return!(c(function(){},[],t)instanceof t)}),d=!p(function(){c(function(){})});a(a.S+a.F*(l||d),"Reflect",{construct:function(t,e){i(t),o(e);var n=arguments.length<3?t:i(arguments[2]);if(d&&!l)return c(t,e,n);if(t==n){switch(e.length){case 0:return new t;case 1:return new t(e[0]);case 2:return new t(e[0],e[1]);case 3:return new t(e[0],e[1],e[2]);case 4:return new t(e[0],e[1],e[2],e[3])}var a=[null];return a.push.apply(a,e),new(u.apply(t,a))}var p=n.prototype,f=r(s(p)?p:Object.prototype),h=Function.apply.call(t,f,e);return s(h)?h:f}})},{17:17,34:34,36:36,4:4,41:41,52:52,71:71,8:8}],211:[function(t,e,n){var a=t(72),r=t(34),i=t(8),o=t(118);r(r.S+r.F*t(36)(function(){Reflect.defineProperty(a.f({},1,{value:1}),1,{value:2})}),"Reflect",{defineProperty:function(t,e,n){i(t),e=o(e,!0),i(n);try{return a.f(t,e,n),!0}catch(r){return!1}}})},{118:118,34:34,36:36,72:72,8:8}],212:[function(t,e,n){var a=t(34),r=t(75).f,i=t(8);a(a.S,"Reflect",{deleteProperty:function(t,e){var n=r(i(t),e);return n&&!n.configurable?!1:delete t[e]}})},{34:34,75:75,8:8}],213:[function(t,e,n){"use strict";var a=t(34),r=t(8),i=function(t){this._t=r(t),this._i=0;var e,n=this._k=[];for(e in t)n.push(e)};t(55)(i,"Object",function(){var t,e=this,n=e._k;do if(e._i>=n.length)return{value:void 0,done:!0};while(!((t=n[e._i++])in e._t));return{value:t,done:!1}}),a(a.S,"Reflect",{enumerate:function(t){return new i(t)}})},{34:34,55:55,8:8}],214:[function(t,e,n){var a=t(75),r=t(34),i=t(8);r(r.S,"Reflect",{getOwnPropertyDescriptor:function(t,e){return a.f(i(t),e)}})},{34:34,75:75,8:8}],215:[function(t,e,n){var a=t(34),r=t(79),i=t(8);a(a.S,"Reflect",{getPrototypeOf:function(t){return r(i(t))}})},{34:34,79:79,8:8}],216:[function(t,e,n){function a(t,e){var n,s,c=arguments.length<3?t:arguments[2];return u(t)===c?t[e]:(n=r.f(t,e))?o(n,"value")?n.value:void 0!==n.get?n.get.call(c):void 0:p(s=i(t))?a(s,e,c):void 0}var r=t(75),i=t(79),o=t(42),s=t(34),p=t(52),u=t(8);s(s.S,"Reflect",{get:a})},{34:34,42:42,52:52,75:75,79:79,8:8}],217:[function(t,e,n){var a=t(34);a(a.S,"Reflect",{has:function(t,e){return e in t}})},{34:34}],218:[function(t,e,n){var a=t(34),r=t(8),i=Object.isExtensible;a(a.S,"Reflect",{isExtensible:function(t){return r(t),i?i(t):!0}})},{34:34,8:8}],219:[function(t,e,n){var a=t(34);a(a.S,"Reflect",{ownKeys:t(85)})},{34:34,85:85}],220:[function(t,e,n){var a=t(34),r=t(8),i=Object.preventExtensions;a(a.S,"Reflect",{preventExtensions:function(t){r(t);try{return i&&i(t),!0}catch(e){return!1}}})},{34:34,8:8}],221:[function(t,e,n){var a=t(34),r=t(97);r&&a(a.S,"Reflect",{setPrototypeOf:function(t,e){r.check(t,e);try{return r.set(t,e),!0}catch(n){return!1}}})},{34:34,97:97}],222:[function(t,e,n){function a(t,e,n){var p,d,f=arguments.length<4?t:arguments[3],h=i.f(c(t),e);if(!h){if(l(d=o(t)))return a(d,e,n,f);h=u(0)}if(s(h,"value")){if(h.writable===!1||!l(f))return!1;if(p=i.f(f,e)){if(p.get||p.set||p.writable===!1)return!1;p.value=n,r.f(f,e,p)}else r.f(f,e,u(0,n));return!0}return void 0===h.set?!1:(h.set.call(f,n),!0)}var r=t(72),i=t(75),o=t(79),s=t(42),p=t(34),u=t(90),c=t(8),l=t(52);p(p.S,"Reflect",{set:a})},{34:34,42:42,52:52,72:72,75:75,79:79,8:8,90:90}],223:[function(t,e,n){var a=t(41),r=t(46),i=t(72).f,o=t(77).f,s=t(53),p=t(38),u=a.RegExp,c=u,l=u.prototype,d=/a/g,f=/a/g,h=new u(d)!==d;if(t(30)&&(!h||t(36)(function(){return f[t(127)("match")]=!1,u(d)!=d||u(f)==f||"/a/i"!=u(d,"i")}))){u=function(t,e){var n=this instanceof u,a=s(t),i=void 0===e;return!n&&a&&t.constructor===u&&i?t:r(h?new c(a&&!i?t.source:t,e):c((a=t instanceof u)?t.source:t,a&&i?p.call(t):e),n?this:l,u)};for(var m=(function(t){t in u||i(u,t,{configurable:!0,get:function(){return c[t]},set:function(e){c[t]=e}})}),g=o(c),v=0;g.length>v;)m(g[v++]);l.constructor=u,u.prototype=l,t(92)(a,"RegExp",u)}t(98)("RegExp")},{127:127,30:30,36:36,38:38,41:41,46:46,53:53,72:72,77:77,92:92,98:98}],224:[function(t,e,n){t(30)&&"g"!=/./g.flags&&t(72).f(RegExp.prototype,"flags",{configurable:!0,get:t(38)})},{30:30,38:38,72:72}],225:[function(t,e,n){t(37)("match",1,function(t,e,n){return[function(n){"use strict";var a=t(this),r=void 0==n?void 0:n[e];return void 0!==r?r.call(n,a):RegExp(n)[e](a+"")},n]})},{37:37}],226:[function(t,e,n){t(37)("replace",2,function(t,e,n){return[function(a,r){"use strict";var i=t(this),o=void 0==a?void 0:a[e];return void 0!==o?o.call(a,i,r):n.call(i+"",a,r)},n]})},{37:37}],227:[function(t,e,n){t(37)("search",1,function(t,e,n){return[function(n){"use strict";var a=t(this),r=void 0==n?void 0:n[e];return void 0!==r?r.call(n,a):RegExp(n)[e](a+"")},n]})},{37:37}],228:[function(t,e,n){t(37)("split",2,function(e,n,a){"use strict";var r=t(53),i=a,o=[].push,s="split",p="length",u="lastIndex";if("c"=="abbc"[s](/(b)*/)[1]||4!="test"[s](/(?:)/,-1)[p]||2!="ab"[s](/(?:ab)*/)[p]||4!="."[s](/(.?)(.?)/)[p]||"."[s](/()()/)[p]>1||""[s](/.?/)[p]){var c=void 0===/()??/.exec("")[1];a=function(t,e){var n=this+"";if(void 0===t&&0===e)return[];if(!r(t))return i.call(n,t,e);var a,s,l,d,f,h=[],m=(t.ignoreCase?"i":"")+(t.multiline?"m":"")+(t.unicode?"u":"")+(t.sticky?"y":""),g=0,v=void 0===e?4294967295:e>>>0,b=RegExp(t.source,m+"g");for(c||(a=RegExp("^"+b.source+"$(?!\\s)",m));(s=b.exec(n))&&(l=s.index+s[0][p],!(l>g&&(h.push(n.slice(g,s.index)),!c&&s[p]>1&&s[0].replace(a,function(){for(f=1;f1&&s.index=v)));)b[u]===s.index&&b[u]++;return g===n[p]?(d||!b.test(""))&&h.push(""):h.push(n.slice(g)),h[p]>v?h.slice(0,v):h}}else"0"[s](void 0,0)[p]&&(a=function(t,e){return void 0===t&&0===e?[]:i.call(this,t,e)});return[function(t,r){var i=e(this),o=void 0==t?void 0:t[n];return void 0!==o?o.call(t,i,r):a.call(i+"",t,r)},a]})},{37:37,53:53}],229:[function(t,e,n){"use strict";t(224);var a=t(8),r=t(38),i=t(30),o="toString",s=/./[o],p=function(e){t(92)(RegExp.prototype,o,e,!0)};t(36)(function(){return"/a/b"!=s.call({source:"a",flags:"b"})})?p(function(){var t=a(this);return"/".concat(t.source,"/","flags"in t?t.flags:!i&&t instanceof RegExp?r.call(t):void 0)}):s.name!=o&&p(function(){return s.call(this)})},{224:224,30:30,36:36,38:38,8:8,92:92}],230:[function(t,e,n){"use strict";var a=t(20),r=t(124),i="Set";e.exports=t(23)(i,function(t){return function(){return t(this,arguments.length>0?arguments[0]:void 0)}},{add:function(t){return a.def(r(this,i),t=0===t?0:t,t)}},a)},{124:124,20:20,23:23}],231:[function(t,e,n){"use strict";t(106)("anchor",function(t){return function(e){return t(this,"a","name",e)}})},{106:106}],232:[function(t,e,n){"use strict";t(106)("big",function(t){return function(){return t(this,"big","","")}})},{106:106}],233:[function(t,e,n){"use strict";t(106)("blink",function(t){return function(){return t(this,"blink","","")}})},{106:106}],234:[function(t,e,n){"use strict";t(106)("bold",function(t){return function(){return t(this,"b","","")}})},{106:106}],235:[function(t,e,n){"use strict";var a=t(34),r=t(104)(!1);a(a.P,"String",{codePointAt:function(t){return r(this,t)}})},{104:104,34:34}],236:[function(t,e,n){"use strict";var a=t(34),r=t(116),i=t(105),o="endsWith",s=""[o];a(a.P+a.F*t(35)(o),"String",{endsWith:function(t){var e=i(this,t,o),n=arguments.length>1?arguments[1]:void 0,a=r(e.length),p=void 0===n?a:Math.min(r(n),a),u=t+"";return s?s.call(e,u,p):e.slice(p-u.length,p)===u}})},{105:105,116:116,34:34,35:35}],237:[function(t,e,n){"use strict";t(106)("fixed",function(t){return function(){return t(this,"tt","","")}})},{106:106}],238:[function(t,e,n){"use strict";t(106)("fontcolor",function(t){return function(e){return t(this,"font","color",e)}})},{106:106}],239:[function(t,e,n){"use strict";t(106)("fontsize",function(t){return function(e){return t(this,"font","size",e)}})},{106:106}],240:[function(t,e,n){var a=t(34),r=t(112),i=String.fromCharCode,o=String.fromCodePoint;a(a.S+a.F*(!!o&&1!=o.length),"String",{fromCodePoint:function(t){for(var e,n=[],a=arguments.length,o=0;a>o;){if(e=+arguments[o++],r(e,1114111)!==e)throw RangeError(e+" is not a valid code point");n.push(65536>e?i(e):i(((e-=65536)>>10)+55296,e%1024+56320))}return n.join("")}})},{112:112,34:34}],241:[function(t,e,n){"use strict";var a=t(34),r=t(105),i="includes";a(a.P+a.F*t(35)(i),"String",{includes:function(t){return!!~r(this,t,i).indexOf(t,arguments.length>1?arguments[1]:void 0)}})},{105:105,34:34,35:35}],242:[function(t,e,n){"use strict";t(106)("italics",function(t){return function(){return t(this,"i","","")}})},{106:106}],243:[function(t,e,n){"use strict";var a=t(104)(!0);t(56)(String,"String",function(t){this._t=t+"",this._i=0},function(){var t,e=this._t,n=this._i;return n>=e.length?{value:void 0,done:!0}:(t=a(e,n),this._i+=t.length,{value:t,done:!1})})},{104:104,56:56}],244:[function(t,e,n){"use strict";t(106)("link",function(t){return function(e){return t(this,"a","href",e)}})},{106:106}],245:[function(t,e,n){var a=t(34),r=t(115),i=t(116);a(a.S,"String",{raw:function(t){for(var e=r(t.raw),n=i(e.length),a=arguments.length,o=[],s=0;n>s;)o.push(e[s++]+""),a>s&&o.push(arguments[s]+"");return o.join("")}})},{115:115,116:116,34:34}],246:[function(t,e,n){var a=t(34);a(a.P,"String",{repeat:t(108)})},{108:108,34:34}],247:[function(t,e,n){"use strict";t(106)("small",function(t){return function(){return t(this,"small","","")}})},{106:106}],248:[function(t,e,n){"use strict";var a=t(34),r=t(116),i=t(105),o="startsWith",s=""[o];a(a.P+a.F*t(35)(o),"String",{startsWith:function(t){var e=i(this,t,o),n=r(Math.min(arguments.length>1?arguments[1]:void 0,e.length)),a=t+"";return s?s.call(e,a,n):e.slice(n,n+a.length)===a}})},{105:105,116:116,34:34,35:35}],249:[function(t,e,n){"use strict";t(106)("strike",function(t){return function(){return t(this,"strike","","")}})},{106:106}],250:[function(t,e,n){"use strict";t(106)("sub",function(t){return function(){return t(this,"sub","","")}})},{106:106}],251:[function(t,e,n){"use strict";t(106)("sup",function(t){return function(){return t(this,"sup","","")}})},{106:106}],252:[function(t,e,n){"use strict";t(109)("trim",function(t){return function(){return t(this,3)}})},{109:109}],253:[function(t,e,n){"use strict";var a=t(41),r=t(42),i=t(30),o=t(34),s=t(92),p=t(66).KEY,u=t(36),c=t(101),l=t(99),d=t(122),f=t(127),h=t(126),m=t(125),g=t(33),v=t(50),b=t(8),y=t(52),_=t(115),x=t(118),w=t(90),k=t(71),S=t(76),E=t(75),C=t(72),P=t(81),A=E.f,O=C.f,T=S.f,R=a.Symbol,M=a.JSON,L=M&&M.stringify,j="prototype",D=f("_hidden"),N=f("toPrimitive"),F={}.propertyIsEnumerable,I=c("symbol-registry"),B=c("symbols"),q=c("op-symbols"),U=Object[j],V="function"==typeof R,G=a.QObject,z=!G||!G[j]||!G[j].findChild,W=i&&u(function(){return 7!=k(O({},"a",{get:function(){return O(this,"a",{value:7}).a}})).a})?function(t,e,n){var a=A(U,e);a&&delete U[e],O(t,e,n),a&&t!==U&&O(U,e,a)}:O,H=function(t){var e=B[t]=k(R[j]);return e._k=t,e},K=V&&"symbol"==typeof R.iterator?function(t){return"symbol"==typeof t}:function(t){return t instanceof R},Q=function(t,e,n){return t===U&&Q(q,e,n),b(t),e=x(e,!0),b(n),r(B,e)?(n.enumerable?(r(t,D)&&t[D][e]&&(t[D][e]=!1),n=k(n,{enumerable:w(0,!1)})):(r(t,D)||O(t,D,w(1,{})),t[D][e]=!0),W(t,e,n)):O(t,e,n)},Y=function(t,e){b(t);for(var n,a=g(e=_(e)),r=0,i=a.length;i>r;)Q(t,n=a[r++],e[n]);return t},$=function(t,e){return void 0===e?k(t):Y(k(t),e)},J=function(t){var e=F.call(this,t=x(t,!0));return this===U&&r(B,t)&&!r(q,t)?!1:e||!r(this,t)||!r(B,t)||r(this,D)&&this[D][t]?e:!0},X=function(t,e){if(t=_(t),e=x(e,!0),t!==U||!r(B,e)||r(q,e)){var n=A(t,e);return!n||!r(B,e)||r(t,D)&&t[D][e]||(n.enumerable=!0),n}},Z=function(t){for(var e,n=T(_(t)),a=[],i=0;n.length>i;)r(B,e=n[i++])||e==D||e==p||a.push(e);return a},tt=function(t){for(var e,n=t===U,a=T(n?q:_(t)),i=[],o=0;a.length>o;)r(B,e=a[o++])&&(n?r(U,e):!0)&&i.push(B[e]);return i};V||(R=function(){if(this instanceof R)throw TypeError("Symbol is not a constructor!");var t=d(arguments.length>0?arguments[0]:void 0),e=function(n){this===U&&e.call(q,n),r(this,D)&&r(this[D],t)&&(this[D][t]=!1),W(this,t,w(1,n))};return i&&z&&W(U,t,{configurable:!0,set:e}),H(t)},s(R[j],"toString",function(){return this._k}),E.f=X,C.f=Q,t(77).f=S.f=Z,t(82).f=J,t(78).f=tt,i&&!t(60)&&s(U,"propertyIsEnumerable",J,!0),h.f=function(t){return H(f(t))}),o(o.G+o.W+o.F*!V,{Symbol:R});for(var et="hasInstance,isConcatSpreadable,iterator,match,replace,search,species,split,toPrimitive,toStringTag,unscopables".split(","),nt=0;et.length>nt;)f(et[nt++]);for(var at=P(f.store),rt=0;at.length>rt;)m(at[rt++]);o(o.S+o.F*!V,"Symbol",{"for":function(t){return r(I,t+="")?I[t]:I[t]=R(t)},keyFor:function(t){if(!K(t))throw TypeError(t+" is not a symbol!");for(var e in I)if(I[e]===t)return e},useSetter:function(){z=!0},useSimple:function(){z=!1}}),o(o.S+o.F*!V,"Object",{create:$,defineProperty:Q,defineProperties:Y,getOwnPropertyDescriptor:X,getOwnPropertyNames:Z,getOwnPropertySymbols:tt}),M&&o(o.S+o.F*(!V||u(function(){var t=R();return"[null]"!=L([t])||"{}"!=L({a:t})||"{}"!=L(Object(t))})),"JSON",{stringify:function(t){for(var e,n,a=[t],r=1;arguments.length>r;)a.push(arguments[r++]);return n=e=a[1],!y(e)&&void 0===t||K(t)?void 0:(v(e)||(e=function(t,e){return"function"==typeof n&&(e=n.call(this,t,e)),K(e)?void 0:e}),a[1]=e,L.apply(M,a))}}),R[j][N]||t(43)(R[j],N,R[j].valueOf),l(R,"Symbol"),l(Math,"Math",!0),l(a.JSON,"JSON",!0)},{101:101,115:115,118:118,122:122,125:125,126:126,127:127,30:30,33:33,34:34,36:36,41:41,42:42,43:43,50:50,52:52,60:60,66:66,71:71,72:72,75:75,76:76,77:77,78:78,8:8,81:81,82:82,90:90,92:92,99:99}],254:[function(t,e,n){"use strict";var a=t(34),r=t(121),i=t(120),o=t(8),s=t(112),p=t(116),u=t(52),c=t(41).ArrayBuffer,l=t(102),d=i.ArrayBuffer,f=i.DataView,h=r.ABV&&c.isView,m=d.prototype.slice,g=r.VIEW,v="ArrayBuffer";a(a.G+a.W+a.F*(c!==d),{ArrayBuffer:d}),a(a.S+a.F*!r.CONSTR,v,{isView:function(t){return h&&h(t)||u(t)&&g in t}}),a(a.P+a.U+a.F*t(36)(function(){return!new d(2).slice(1,void 0).byteLength}),v,{slice:function(t,e){if(void 0!==m&&void 0===e)return m.call(o(this),t);for(var n=o(this).byteLength,a=s(t,n),r=s(void 0===e?n:e,n),i=new(l(this,d))(p(r-a)),u=new f(this),c=new f(i),h=0;r>a;)c.setUint8(h++,u.getUint8(a++));return i}}),t(98)(v)},{102:102,112:112,116:116,120:120,121:121,34:34,36:36,41:41,52:52,8:8,98:98}],255:[function(t,e,n){var a=t(34);a(a.G+a.W+a.F*!t(121).ABV,{DataView:t(120).DataView})},{120:120,121:121,34:34}],256:[function(t,e,n){t(119)("Float32",4,function(t){return function(e,n,a){return t(this,e,n,a)}})},{119:119}],257:[function(t,e,n){t(119)("Float64",8,function(t){return function(e,n,a){return t(this,e,n,a)}})},{119:119}],258:[function(t,e,n){t(119)("Int16",2,function(t){return function(e,n,a){return t(this,e,n,a)}})},{119:119}],259:[function(t,e,n){t(119)("Int32",4,function(t){return function(e,n,a){return t(this,e,n,a)}})},{119:119}],260:[function(t,e,n){t(119)("Int8",1,function(t){return function(e,n,a){return t(this,e,n,a)}})},{119:119}],261:[function(t,e,n){t(119)("Uint16",2,function(t){return function(e,n,a){return t(this,e,n,a)}})},{119:119}],262:[function(t,e,n){t(119)("Uint32",4,function(t){return function(e,n,a){return t(this,e,n,a)}})},{119:119}],263:[function(t,e,n){t(119)("Uint8",1,function(t){return function(e,n,a){return t(this,e,n,a)}})},{119:119}],264:[function(t,e,n){t(119)("Uint8",1,function(t){return function(e,n,a){return t(this,e,n,a)}},!0)},{119:119}],265:[function(t,e,n){"use strict";var a,r=t(13)(0),i=t(92),o=t(66),s=t(70),p=t(22),u=t(52),c=t(36),l=t(124),d="WeakMap",f=o.getWeak,h=Object.isExtensible,m=p.ufstore,g={},v=function(t){return function(){return t(this,arguments.length>0?arguments[0]:void 0)}},b={get:function(t){if(u(t)){var e=f(t);return e===!0?m(l(this,d)).get(t):e?e[this._i]:void 0}},set:function(t,e){return p.def(l(this,d),t,e)}},y=e.exports=t(23)(d,v,b,p,!0,!0);c(function(){return 7!=(new y).set((Object.freeze||Object)(g),7).get(g)})&&(a=p.getConstructor(v,d),s(a.prototype,b),o.NEED=!0,r(["delete","has","get","set"],function(t){var e=y.prototype,n=e[t];i(e,t,function(e,r){if(u(e)&&!h(e)){this._f||(this._f=new a);var i=this._f[t](e,r);return"set"==t?this:i}return n.call(this,e,r)})}))},{124:124,13:13,22:22,23:23,36:36,52:52,66:66,70:70,92:92}],266:[function(t,e,n){"use strict";var a=t(22),r=t(124),i="WeakSet";t(23)(i,function(t){return function(){return t(this,arguments.length>0?arguments[0]:void 0)}},{add:function(t){return a.def(r(this,i),t,!0)}},a,!1,!0)},{124:124,22:22,23:23}],267:[function(t,e,n){"use strict";var a=t(34),r=t(39),i=t(117),o=t(116),s=t(4),p=t(16);a(a.P,"Array",{flatMap:function(t){var e,n,a=i(this);return s(t),e=o(a.length),n=p(a,0),r(n,a,a,e,0,1,t,arguments[1]),n}}),t(6)("flatMap")},{116:116,117:117,16:16,34:34,39:39,4:4,6:6}],268:[function(t,e,n){"use strict";var a=t(34),r=t(39),i=t(117),o=t(116),s=t(114),p=t(16);a(a.P,"Array",{flatten:function(){var t=arguments[0],e=i(this),n=o(e.length),a=p(e,0);return r(a,e,e,n,0,void 0===t?1:s(t)),a}}),t(6)("flatten")},{114:114,116:116,117:117,16:16,34:34,39:39,6:6}],269:[function(t,e,n){"use strict";var a=t(34),r=t(12)(!0);a(a.P,"Array",{includes:function(t){return r(this,t,arguments.length>1?arguments[1]:void 0)}}),t(6)("includes")},{12:12,34:34,6:6}],270:[function(t,e,n){var a=t(34),r=t(68)(),i=t(41).process,o="process"==t(19)(i);a(a.G,{asap:function(t){var e=o&&i.domain;r(e?e.bind(t):t)}})},{19:19,34:34,41:41,68:68}],271:[function(t,e,n){var a=t(34),r=t(19);a(a.S,"Error",{isError:function(t){return"Error"===r(t)}})},{19:19,34:34}],272:[function(t,e,n){var a=t(34);a(a.G,{global:t(41)})},{34:34,41:41}],273:[function(t,e,n){t(95)("Map")},{95:95}],274:[function(t,e,n){t(96)("Map")},{96:96}],275:[function(t,e,n){var a=t(34);a(a.P+a.R,"Map",{toJSON:t(21)("Map")})},{21:21,34:34}],276:[function(t,e,n){var a=t(34);a(a.S,"Math",{clamp:function(t,e,n){return Math.min(n,Math.max(e,t))}})},{34:34}],277:[function(t,e,n){var a=t(34);a(a.S,"Math",{DEG_PER_RAD:Math.PI/180})},{34:34}],278:[function(t,e,n){var a=t(34),r=180/Math.PI;a(a.S,"Math",{degrees:function(t){return t*r}})},{34:34}],279:[function(t,e,n){var a=t(34),r=t(64),i=t(62);a(a.S,"Math",{fscale:function(t,e,n,a,o){return i(r(t,e,n,a,o))}})},{34:34,62:62,64:64}],280:[function(t,e,n){var a=t(34);a(a.S,"Math",{iaddh:function(t,e,n,a){var r=t>>>0,i=e>>>0,o=n>>>0;return i+(a>>>0)+((r&o|(r|o)&~(r+o>>>0))>>>31)|0}})},{34:34}],281:[function(t,e,n){var a=t(34);a(a.S,"Math",{imulh:function(t,e){var n=65535,a=+t,r=+e,i=a&n,o=r&n,s=a>>16,p=r>>16,u=(s*o>>>0)+(i*o>>>16);return s*p+(u>>16)+((i*p>>>0)+(u&n)>>16)}})},{34:34}],282:[function(t,e,n){var a=t(34);a(a.S,"Math",{isubh:function(t,e,n,a){var r=t>>>0,i=e>>>0,o=n>>>0;return i-(a>>>0)-((~r&o|~(r^o)&r-o>>>0)>>>31)|0}})},{34:34}],283:[function(t,e,n){var a=t(34);a(a.S,"Math",{RAD_PER_DEG:180/Math.PI})},{34:34}],284:[function(t,e,n){var a=t(34),r=Math.PI/180;a(a.S,"Math",{radians:function(t){return t*r}})},{34:34}],285:[function(t,e,n){var a=t(34);a(a.S,"Math",{scale:t(64)})},{34:34,64:64}],286:[function(t,e,n){var a=t(34);a(a.S,"Math",{signbit:function(t){return(t=+t)!=t?t:0==t?1/t==1/0:t>0}})},{34:34}],287:[function(t,e,n){var a=t(34);a(a.S,"Math",{umulh:function(t,e){var n=65535,a=+t,r=+e,i=a&n,o=r&n,s=a>>>16,p=r>>>16,u=(s*o>>>0)+(i*o>>>16);return s*p+(u>>>16)+((i*p>>>0)+(u&n)>>>16)}})},{34:34}],288:[function(t,e,n){"use strict";var a=t(34),r=t(117),i=t(4),o=t(72);t(30)&&a(a.P+t(74),"Object",{__defineGetter__:function(t,e){o.f(r(this),t,{get:i(e),enumerable:!0,configurable:!0})}})},{117:117,30:30,34:34,4:4,72:72,74:74}],289:[function(t,e,n){"use strict";var a=t(34),r=t(117),i=t(4),o=t(72);t(30)&&a(a.P+t(74),"Object",{__defineSetter__:function(t,e){o.f(r(this),t,{set:i(e),enumerable:!0,configurable:!0})}})},{117:117,30:30,34:34,4:4,72:72,74:74}],290:[function(t,e,n){var a=t(34),r=t(84)(!0);a(a.S,"Object",{entries:function(t){return r(t)}})},{34:34,84:84}],291:[function(t,e,n){var a=t(34),r=t(85),i=t(115),o=t(75),s=t(25);a(a.S,"Object",{getOwnPropertyDescriptors:function(t){for(var e,n,a=i(t),p=o.f,u=r(a),c={},l=0;u.length>l;)n=p(a,e=u[l++]),void 0!==n&&s(c,e,n);return c}})},{115:115,25:25,34:34,75:75,85:85}],292:[function(t,e,n){"use strict";var a=t(34),r=t(117),i=t(118),o=t(79),s=t(75).f;t(30)&&a(a.P+t(74),"Object",{__lookupGetter__:function(t){var e,n=r(this),a=i(t,!0);do if(e=s(n,a))return e.get;while(n=o(n))}})},{117:117,118:118,30:30,34:34,74:74,75:75,79:79}],293:[function(t,e,n){"use strict";var a=t(34),r=t(117),i=t(118),o=t(79),s=t(75).f;t(30)&&a(a.P+t(74),"Object",{__lookupSetter__:function(t){var e,n=r(this),a=i(t,!0);do if(e=s(n,a))return e.set;while(n=o(n))}})},{117:117,118:118,30:30,34:34,74:74,75:75,79:79}],294:[function(t,e,n){var a=t(34),r=t(84)(!1);a(a.S,"Object",{values:function(t){return r(t)}})},{34:34,84:84}],295:[function(t,e,n){"use strict";var a=t(34),r=t(41),i=t(24),o=t(68)(),s=t(127)("observable"),p=t(4),u=t(8),c=t(7),l=t(91),d=t(43),f=t(40),h=f.RETURN,m=function(t){return null==t?void 0:p(t)},g=function(t){var e=t._c;e&&(t._c=void 0,e())},v=function(t){return void 0===t._o},b=function(t){v(t)||(t._o=void 0,g(t))},y=function(t,e){u(t),this._c=void 0,this._o=t,t=new _(this);try{var n=e(t),a=n;null!=n&&("function"==typeof n.unsubscribe?n=function(){a.unsubscribe()}:p(n),this._c=n)}catch(r){return void t.error(r)}v(this)&&g(this)};y.prototype=l({},{unsubscribe:function(){b(this)}});var _=function(t){this._s=t};_.prototype=l({},{next:function(t){var e=this._s;if(!v(e)){var n=e._o;try{var a=m(n.next);if(a)return a.call(n,t)}catch(r){try{b(e)}finally{throw r}}}},error:function(t){var e=this._s;if(v(e))throw t;var n=e._o;e._o=void 0;try{var a=m(n.error);if(!a)throw t;t=a.call(n,t)}catch(r){try{g(e)}finally{throw r}}return g(e),t},complete:function(t){var e=this._s;if(!v(e)){var n=e._o;e._o=void 0;try{var a=m(n.complete);t=a?a.call(n,t):void 0}catch(r){try{g(e)}finally{throw r}}return g(e),t}}});var x=function(t){c(this,x,"Observable","_f")._f=p(t)};l(x.prototype,{subscribe:function(t){return new y(t,this._f)},forEach:function(t){var e=this;return new(i.Promise||r.Promise)(function(n,a){p(t);var r=e.subscribe({next:function(e){try{return t(e)}catch(n){a(n),r.unsubscribe()}},error:a,complete:n})})}}),l(x,{from:function(t){var e="function"==typeof this?this:x,n=m(u(t)[s]);if(n){var a=u(n.call(t));return a.constructor===e?a:new e(function(t){return a.subscribe(t)})}return new e(function(e){var n=!1;return o(function(){if(!n){try{if(f(t,!1,function(t){return e.next(t),n?h:void 0})===h)return}catch(a){if(n)throw a;return void e.error(a)}e.complete()}}),function(){n=!0}})},of:function(){for(var t=0,e=arguments.length,n=Array(e);e>t;)n[t]=arguments[t++];return new("function"==typeof this?this:x)(function(t){var e=!1;return o(function(){if(!e){for(var a=0;a1?arguments[1]:void 0,!1)}})},{107:107,123:123,34:34}],313:[function(t,e,n){"use strict";var a=t(34),r=t(107),i=t(123);a(a.P+a.F*/Version\/10\.\d+(\.\d+)? Safari\//.test(i),"String",{padStart:function(t){return r(this,t,arguments.length>1?arguments[1]:void 0,!0)}})},{107:107,123:123,34:34}],314:[function(t,e,n){"use strict";t(109)("trimLeft",function(t){return function(){return t(this,1)}},"trimStart")},{109:109}],315:[function(t,e,n){"use strict";t(109)("trimRight",function(t){return function(){return t(this,2)}},"trimEnd")},{109:109}],316:[function(t,e,n){t(125)("asyncIterator")},{125:125}],317:[function(t,e,n){t(125)("observable")},{125:125}],318:[function(t,e,n){var a=t(34);a(a.S,"System",{global:t(41)
-})},{34:34,41:41}],319:[function(t,e,n){t(95)("WeakMap")},{95:95}],320:[function(t,e,n){t(96)("WeakMap")},{96:96}],321:[function(t,e,n){t(95)("WeakSet")},{95:95}],322:[function(t,e,n){t(96)("WeakSet")},{96:96}],323:[function(t,e,n){for(var a=t(140),r=t(81),i=t(92),o=t(41),s=t(43),p=t(59),u=t(127),c=u("iterator"),l=u("toStringTag"),d=p.Array,f={CSSRuleList:!0,CSSStyleDeclaration:!1,CSSValueList:!1,ClientRectList:!1,DOMRectList:!1,DOMStringList:!1,DOMTokenList:!0,DataTransferItemList:!1,FileList:!1,HTMLAllCollection:!1,HTMLCollection:!1,HTMLFormElement:!1,HTMLSelectElement:!1,MediaList:!0,MimeTypeArray:!1,NamedNodeMap:!1,NodeList:!0,PaintRequestList:!1,Plugin:!1,PluginArray:!1,SVGLengthList:!1,SVGNumberList:!1,SVGPathSegList:!1,SVGPointList:!1,SVGStringList:!1,SVGTransformList:!1,SourceBufferList:!1,StyleSheetList:!0,TextTrackCueList:!1,TextTrackList:!1,TouchList:!1},h=r(f),m=0;m2,r=a?o.call(arguments,2):!1;return t(a?function(){("function"==typeof e?e:Function(e)).apply(this,r)}:e,n)}};r(r.G+r.B+r.F*s,{setTimeout:p(a.setTimeout),setInterval:p(a.setInterval)})},{123:123,34:34,41:41}],326:[function(t,e,n){t(253),t(190),t(192),t(191),t(194),t(196),t(201),t(195),t(193),t(203),t(202),t(198),t(199),t(197),t(189),t(200),t(204),t(205),t(156),t(158),t(157),t(207),t(206),t(177),t(187),t(188),t(178),t(179),t(180),t(181),t(182),t(183),t(184),t(185),t(186),t(160),t(161),t(162),t(163),t(164),t(165),t(166),t(167),t(168),t(169),t(170),t(171),t(172),t(173),t(174),t(175),t(176),t(240),t(245),t(252),t(243),t(235),t(236),t(241),t(246),t(248),t(231),t(232),t(233),t(234),t(237),t(238),t(239),t(242),t(244),t(247),t(249),t(250),t(251),t(151),t(153),t(152),t(155),t(154),t(139),t(137),t(144),t(141),t(147),t(149),t(136),t(143),t(133),t(148),t(131),t(146),t(145),t(138),t(142),t(130),t(132),t(135),t(134),t(150),t(140),t(223),t(229),t(224),t(225),t(226),t(227),t(228),t(208),t(159),t(230),t(265),t(266),t(254),t(255),t(260),t(263),t(264),t(258),t(261),t(259),t(262),t(256),t(257),t(209),t(210),t(211),t(212),t(213),t(216),t(214),t(215),t(217),t(218),t(219),t(220),t(222),t(221),t(269),t(267),t(268),t(310),t(313),t(312),t(314),t(315),t(311),t(316),t(317),t(291),t(294),t(290),t(288),t(289),t(292),t(293),t(275),t(309),t(274),t(308),t(320),t(322),t(273),t(307),t(319),t(321),t(272),t(318),t(271),t(276),t(277),t(278),t(279),t(280),t(282),t(281),t(283),t(284),t(285),t(287),t(286),t(296),t(297),t(298),t(299),t(301),t(300),t(303),t(302),t(304),t(305),t(306),t(270),t(295),t(325),t(324),t(323),e.exports=t(24)},{130:130,131:131,132:132,133:133,134:134,135:135,136:136,137:137,138:138,139:139,140:140,141:141,142:142,143:143,144:144,145:145,146:146,147:147,148:148,149:149,150:150,151:151,152:152,153:153,154:154,155:155,156:156,157:157,158:158,159:159,160:160,161:161,162:162,163:163,164:164,165:165,166:166,167:167,168:168,169:169,170:170,171:171,172:172,173:173,174:174,175:175,176:176,177:177,178:178,179:179,180:180,181:181,182:182,183:183,184:184,185:185,186:186,187:187,188:188,189:189,190:190,191:191,192:192,193:193,194:194,195:195,196:196,197:197,198:198,199:199,200:200,201:201,202:202,203:203,204:204,205:205,206:206,207:207,208:208,209:209,210:210,211:211,212:212,213:213,214:214,215:215,216:216,217:217,218:218,219:219,220:220,221:221,222:222,223:223,224:224,225:225,226:226,227:227,228:228,229:229,230:230,231:231,232:232,233:233,234:234,235:235,236:236,237:237,238:238,239:239,24:24,240:240,241:241,242:242,243:243,244:244,245:245,246:246,247:247,248:248,249:249,250:250,251:251,252:252,253:253,254:254,255:255,256:256,257:257,258:258,259:259,260:260,261:261,262:262,263:263,264:264,265:265,266:266,267:267,268:268,269:269,270:270,271:271,272:272,273:273,274:274,275:275,276:276,277:277,278:278,279:279,280:280,281:281,282:282,283:283,284:284,285:285,286:286,287:287,288:288,289:289,290:290,291:291,292:292,293:293,294:294,295:295,296:296,297:297,298:298,299:299,300:300,301:301,302:302,303:303,304:304,305:305,306:306,307:307,308:308,309:309,310:310,311:311,312:312,313:313,314:314,315:315,316:316,317:317,318:318,319:319,320:320,321:321,322:322,323:323,324:324,325:325}],327:[function(t,e,n){!function(t){"use strict";function e(){return c.createDocumentFragment()}function n(t){return c.createElement(t)}function a(t){if(1===t.length)return r(t[0]);for(var n=e(),a=B.call(t),i=0;i-1}}([].indexOf||function(t){for(q=this.length;q--&&this[q]!==t;);return q}),item:function(t){return this[t]||null},remove:function(){for(var t,e=0;e=p?e(i):document.fonts.load(u(i,i.family),s).then(function(e){1<=e.length?t(i):setTimeout(d,25)},function(){e(i)})};d()}else n(function(){function n(){var e;(e=-1!=g&&-1!=v||-1!=g&&-1!=b||-1!=v&&-1!=b)&&((e=g!=v&&g!=b&&v!=b)||(null===l&&(e=/AppleWebKit\/([0-9]+)(?:\.([0-9]+))/.exec(window.navigator.userAgent),l=!!e&&(536>parseInt(e[1],10)||536===parseInt(e[1],10)&&11>=parseInt(e[2],10))),e=l&&(g==y&&v==y&&b==y||g==_&&v==_&&b==_||g==x&&v==x&&b==x)),e=!e),e&&(null!==w.parentNode&&w.parentNode.removeChild(w),clearTimeout(k),t(i))}function d(){if((new Date).getTime()-c>=p)null!==w.parentNode&&w.parentNode.removeChild(w),e(i);else{var t=document.hidden;(!0===t||void 0===t)&&(g=f.a.offsetWidth,v=h.a.offsetWidth,b=m.a.offsetWidth,n()),k=setTimeout(d,50)}}var f=new a(s),h=new a(s),m=new a(s),g=-1,v=-1,b=-1,y=-1,_=-1,x=-1,w=document.createElement("div"),k=0;w.dir="ltr",r(f,u(i,"sans-serif")),r(h,u(i,"serif")),r(m,u(i,"monospace")),w.appendChild(f.a),w.appendChild(h.a),w.appendChild(m.a),document.body.appendChild(w),y=f.a.offsetWidth,_=h.a.offsetWidth,x=m.a.offsetWidth,d(),o(f,function(t){g=t,n()}),r(f,u(i,'"'+i.family+'",sans-serif')),o(h,function(t){v=t,n()}),r(h,u(i,'"'+i.family+'",serif')),o(m,function(t){b=t,n()}),r(m,u(i,'"'+i.family+'",monospace'))})})},window.FontFaceObserver=s,window.FontFaceObserver.prototype.check=s.prototype.a,void 0!==e&&(e.exports=window.FontFaceObserver)}()},{}],330:[function(t,e,n){!function(t,n){function a(t,e){var n=t.createElement("p"),a=t.getElementsByTagName("head")[0]||t.documentElement;return n.innerHTML="x",a.insertBefore(n.lastChild,a.firstChild)}function r(){var t=_.elements;return"string"==typeof t?t.split(" "):t}function i(t,e){var n=_.elements;"string"!=typeof n&&(n=n.join(" ")),"string"!=typeof t&&(t=t.join(" ")),_.elements=n+" "+t,c(e)}function o(t){var e=y[t[v]];return e||(e={},b++,t[v]=b,y[b]=e),e}function s(t,e,a){if(e||(e=n),d)return e.createElement(t);a||(a=o(e));var r;return r=a.cache[t]?a.cache[t].cloneNode():g.test(t)?(a.cache[t]=a.createElem(t)).cloneNode():a.createElem(t),!r.canHaveChildren||m.test(t)||r.tagUrn?r:a.frag.appendChild(r)}function p(t,e){if(t||(t=n),d)return t.createDocumentFragment();e=e||o(t);for(var a=e.frag.cloneNode(),i=0,s=r(),p=s.length;p>i;i++)a.createElement(s[i]);return a}function u(t,e){e.cache||(e.cache={},e.createElem=t.createElement,e.createFrag=t.createDocumentFragment,e.frag=e.createFrag()),t.createElement=function(n){return _.shivMethods?s(n,t,e):e.createElem(n)},t.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+r().join().replace(/[\w\-:]+/g,function(t){return e.createElem(t),e.frag.createElement(t),'c("'+t+'")'})+");return n}")(_,e.frag)}function c(t){t||(t=n);var e=o(t);return!_.shivCSS||l||e.hasCSS||(e.hasCSS=!!a(t,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),d||u(t,e),t}var l,d,f="3.7.3-pre",h=t.html5||{},m=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,g=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,v="_html5shiv",b=0,y={};!function(){try{var t=n.createElement("a");t.innerHTML="",l="hidden"in t,d=1==t.childNodes.length||function(){n.createElement("a");var t=n.createDocumentFragment();return void 0===t.cloneNode||void 0===t.createDocumentFragment||void 0===t.createElement}()}catch(e){l=!0,d=!0}}();var _={elements:h.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:f,shivCSS:h.shivCSS!==!1,supportsUnknownElements:d,shivMethods:h.shivMethods!==!1,type:"default",shivDocument:c,createElement:s,createDocumentFragment:p,addElements:i};t.html5=_,c(n),"object"==typeof e&&e.exports&&(e.exports=_)}("undefined"!=typeof window?window:this,document)},{}],331:[function(t,e,n){(function(t){(function(t){!function(t){function e(t,e,n,a){for(var i,o,s=n.slice(),p=r(e,t),u=0,c=s.length;c>u&&(i=s[u],"object"==typeof i?"function"==typeof i.handleEvent&&i.handleEvent(p):i.call(t,p),!p.stoppedImmediatePropagation);u++);return o=!p.stoppedPropagation,a&&o&&t.parentNode?t.parentNode.dispatchEvent(p):!p.defaultPrevented}function n(t,e){return{configurable:!0,get:t,set:e}}function a(t,e,a){var r=y(e||t,a);v(t,"textContent",n(function(){return r.get.call(this)},function(t){r.set.call(this,t)}))}function r(t,e){return t.currentTarget=e,t.eventPhase=t.target===t.currentTarget?2:3,t}function i(t,e){for(var n=t.length;n--&&t[n]!==e;);return n}function o(){if("BR"===this.tagName)return"\n";for(var t=this.firstChild,e=[];t;)8!==t.nodeType&&7!==t.nodeType&&e.push(t.textContent),t=t.nextSibling;return e.join("")}function s(t){var e=document.createEvent("Event");e.initEvent("input",!0,!0),(t.srcElement||t.fromElement||document).dispatchEvent(e)}function p(t){!f&&S.test(document.readyState)&&(f=!f,document.detachEvent(h,p),t=document.createEvent("Event"),t.initEvent(m,!0,!0),document.dispatchEvent(t))}function u(t){return function(){return P[t]||document.body&&document.body[t]||0}}function c(t){for(var e;e=this.lastChild;)this.removeChild(e);null!=t&&this.appendChild(document.createTextNode(t))}function l(e,n){return n||(n=t.event),n.target||(n.target=n.srcElement||n.fromElement||document),n.timeStamp||(n.timeStamp=(new Date).getTime()),n}if(!document.createEvent){var d=!0,f=!1,h="onreadystatechange",m="DOMContentLoaded",g="__IE8__"+Math.random(),v=Object.defineProperty||function(t,e,n){t[e]=n.value},b=Object.defineProperties||function(e,n){for(var a in n)if(_.call(n,a))try{v(e,a,n[a])}catch(r){t.console&&console.log(a+" failed on object:",e,r.message)}},y=Object.getOwnPropertyDescriptor,_=Object.prototype.hasOwnProperty,x=t.Element.prototype,w=t.Text.prototype,k=/^[a-z]+$/,S=/loaded|complete/,E={},C=document.createElement("div"),P=document.documentElement,A=P.removeAttribute,O=P.setAttribute,T=function(t){return{enumerable:!0,writable:!0,configurable:!0,value:t}};a(t.HTMLCommentElement.prototype,x,"nodeValue"),a(t.HTMLScriptElement.prototype,null,"text"),a(w,null,"nodeValue"),a(t.HTMLTitleElement.prototype,null,"text"),v(t.HTMLStyleElement.prototype,"textContent",function(t){return n(function(){return t.get.call(this.styleSheet)},function(e){t.set.call(this.styleSheet,e)})}(y(t.CSSStyleSheet.prototype,"cssText")));var R=/\b\s*alpha\s*\(\s*opacity\s*=\s*(\d+)\s*\)/;v(t.CSSStyleDeclaration.prototype,"opacity",{get:function(){var t=this.filter.match(R);return t?""+t[1]/100:""},set:function(t){this.zoom=1;var e=!1;t=1>t?" alpha(opacity="+Math.round(100*t)+")":"",this.filter=this.filter.replace(R,function(){return e=!0,t}),!e&&t&&(this.filter+=t)}}),b(x,{textContent:{get:o,set:c},firstElementChild:{get:function(){for(var t=this.childNodes||[],e=0,n=t.length;n>e;e++)if(1==t[e].nodeType)return t[e]}},lastElementChild:{get:function(){for(var t=this.childNodes||[],e=t.length;e--;)if(1==t[e].nodeType)return t[e]}},oninput:{get:function(){return this._oninput||null},set:function(t){this._oninput&&(this.removeEventListener("input",this._oninput),this._oninput=t,t&&this.addEventListener("input",t))}},previousElementSibling:{get:function(){for(var t=this.previousSibling;t&&1!=t.nodeType;)t=t.previousSibling;return t}},nextElementSibling:{get:function(){for(var t=this.nextSibling;t&&1!=t.nodeType;)t=t.nextSibling;return t}},childElementCount:{get:function(){for(var t=0,e=this.childNodes||[],n=e.length;n--;t+=1==e[n].nodeType);return t}},addEventListener:T(function(t,n,a){if("function"==typeof n||"object"==typeof n){var r,o,p=this,u="on"+t,c=p[g]||v(p,g,{value:{}})[g],d=c[u]||(c[u]={}),f=d.h||(d.h=[]);if(!_.call(d,"w")){if(d.w=function(t){return t[g]||e(p,l(p,t),f,!1)},!_.call(E,u))if(k.test(t)){try{r=document.createEventObject(),r[g]=!0,9!=p.nodeType&&(null==p.parentNode&&C.appendChild(p),(o=p.getAttribute(u))&&A.call(p,u)),p.fireEvent(u,r),E[u]=!0}catch(h){for(E[u]=!1;C.hasChildNodes();)C.removeChild(C.firstChild)}null!=o&&O.call(p,u,o)}else E[u]=!1;(d.n=E[u])&&p.attachEvent(u,d.w)}i(f,n)<0&&f[a?"unshift":"push"](n),"input"===t&&p.attachEvent("onkeyup",s)}}),dispatchEvent:T(function(t){var n,a=this,r="on"+t.type,i=a[g],o=i&&i[r],s=!!o;return t.target||(t.target=a),s?o.n?a.fireEvent(r,t):e(a,t,o.h,!0):(n=a.parentNode)?n.dispatchEvent(t):!0,!t.defaultPrevented}),removeEventListener:T(function(t,e,n){if("function"==typeof e||"object"==typeof e){var a=this,r="on"+t,o=a[g],s=o&&o[r],p=s&&s.h,u=p?i(p,e):-1;u>-1&&p.splice(u,1)}})}),b(w,{addEventListener:T(x.addEventListener),dispatchEvent:T(x.dispatchEvent),removeEventListener:T(x.removeEventListener)}),b(t.XMLHttpRequest.prototype,{addEventListener:T(function(t,e,n){var a=this,r="on"+t,o=a[g]||v(a,g,{value:{}})[g],s=o[r]||(o[r]={}),p=s.h||(s.h=[]);i(p,e)<0&&(a[r]||(a[r]=function(){var e=document.createEvent("Event");e.initEvent(t,!0,!0),a.dispatchEvent(e)}),p[n?"unshift":"push"](e))}),dispatchEvent:T(function(t){var n=this,a="on"+t.type,r=n[g],i=r&&r[a],o=!!i;return o&&(i.n?n.fireEvent(a,t):e(n,t,i.h,!0))}),removeEventListener:T(x.removeEventListener)});var M=y(Event.prototype,"button").get;b(t.Event.prototype,{bubbles:T(!0),cancelable:T(!0),preventDefault:T(function(){this.cancelable&&(this.returnValue=!1)}),stopPropagation:T(function(){this.stoppedPropagation=!0,this.cancelBubble=!0}),stopImmediatePropagation:T(function(){this.stoppedImmediatePropagation=!0,this.stopPropagation()}),initEvent:T(function(t,e,n){this.type=t,this.bubbles=!!e,this.cancelable=!!n,this.bubbles||this.stopPropagation()}),pageX:{get:function(){return this._pageX||(this._pageX=this.clientX+t.scrollX-(P.clientLeft||0))}},pageY:{get:function(){return this._pageY||(this._pageY=this.clientY+t.scrollY-(P.clientTop||0))}},which:{get:function(){return this.keyCode?this.keyCode:isNaN(this.button)?void 0:this.button+1}},charCode:{get:function(){return this.keyCode&&"keypress"==this.type?this.keyCode:0}},buttons:{get:function(){return M.call(this)}},button:{get:function(){var t=this.buttons;return 1&t?0:2&t?2:4&t?1:void 0}},defaultPrevented:{get:function(){var t,e=this.returnValue;return!(e===t||e)}},relatedTarget:{get:function(){var t=this.type;return"mouseover"===t?this.fromElement:"mouseout"===t?this.toElement:null}}}),b(t.HTMLDocument.prototype,{defaultView:{get:function(){return this.parentWindow}},textContent:{get:function(){return 11===this.nodeType?o.call(this):null},set:function(t){11===this.nodeType&&c.call(this,t)}},addEventListener:T(function(e,n,a){var r=this;x.addEventListener.call(r,e,n,a),d&&e===m&&!S.test(r.readyState)&&(d=!1,r.attachEvent(h,p),t==top&&!function i(t){try{r.documentElement.doScroll("left"),p()}catch(e){setTimeout(i,50)}}())}),dispatchEvent:T(x.dispatchEvent),removeEventListener:T(x.removeEventListener),createEvent:T(function(t){var e;if("Event"!==t)throw Error("unsupported "+t);return e=document.createEventObject(),e.timeStamp=(new Date).getTime(),e})}),b(t.Window.prototype,{getComputedStyle:T(function(){function t(t){this._=t}function e(){}var n=/^(?:[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|))(?!px)[a-z%]+$/,a=/^(top|right|bottom|left)$/,r=/\-([a-z])/g,i=function(t,e){return e.toUpperCase()};return t.prototype.getPropertyValue=function(t){var e,o,s,p=this._,u=p.style,c=p.currentStyle,l=p.runtimeStyle;return"opacity"==t?u.opacity||"1":(t=("float"===t?"style-float":t).replace(r,i),e=c?c[t]:u[t],n.test(e)&&!a.test(t)&&(o=u.left,s=l&&l.left,s&&(l.left=c.left),u.left="fontSize"===t?"1em":e,e=u.pixelLeft+"px",u.left=o,s&&(l.left=s)),null==e?e:e+""||"auto")},e.prototype.getPropertyValue=function(){return null},function(n,a){return a?new e(n):new t(n)}}()),addEventListener:T(function(n,a,r){var o,s=t,p="on"+n;s[p]||(s[p]=function(t){return e(s,l(s,t),o,!1)&&void 0}),o=s[p][g]||(s[p][g]=[]),i(o,a)<0&&o[r?"unshift":"push"](a)}),dispatchEvent:T(function(e){var n=t["on"+e.type];return n?n.call(t,e)!==!1&&!e.defaultPrevented:!0}),removeEventListener:T(function(e,n,a){var r="on"+e,o=(t[r]||Object)[g],s=o?i(o,n):-1;s>-1&&o.splice(s,1)}),pageXOffset:{get:u("scrollLeft")},pageYOffset:{get:u("scrollTop")},scrollX:{get:u("scrollLeft")},scrollY:{get:u("scrollTop")},innerWidth:{get:u("clientWidth")},innerHeight:{get:u("clientHeight")}}),t.HTMLElement=t.Element,function(t,e,n){for(n=0;na;a++)e.appendChild(n[a].cloneNode(!0));return e},n.cloneRange=function(){var t=new e;return t._start=this._start,t._end=this._end,t},n.deleteContents=function(){for(var e=this._start.parentNode,n=t(this._start,this._end),a=0,r=n.length;r>a;a++)e.removeChild(n[a])},n.extractContents=function(){for(var e=this._start.ownerDocument.createDocumentFragment(),n=t(this._start,this._end),a=0,r=n.length;r>a;a++)e.appendChild(n[a]);return e},n.setEndAfter=function(t){this._end=t},n.setEndBefore=function(t){this._end=t.previousSibling},n.setStartAfter=function(t){this._start=t.nextSibling},n.setStartBefore=function(t){this._start=t}}}()}}(this.window||t)}).call(this,void 0!==t?t:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{}],332:[function(t,e,n){"use strict";function a(t){return t&&t.__esModule?t:{"default":t}}function r(t){if(Array.isArray(t)){for(var e=0,n=Array(t.length);e=s)return(0,p["default"])({points:n});for(var l=1;s-1>=l;l++)i.push((0,u.times)(a,(0,u.minus)(n[l],n[l-1])));for(var d=[(0,u.plus)(n[0],c(i[0],i[1]))],l=1;s-2>=l;l++)d.push((0,u.minus)(n[l],(0,u.average)([i[l],i[l-1]])));d.push((0,u.minus)(n[s-1],c(i[s-2],i[s-3])));var f=d[0],h=d[1],m=n[0],g=n[1],v=(e=(0,o["default"])()).moveto.apply(e,r(m)).curveto(f[0],f[1],h[0],h[1],g[0],g[1]);return{path:(0,u.range)(2,s).reduce(function(t,e){var a=d[e],r=n[e];return t.smoothcurveto(a[0],a[1],r[0],r[1])},v),centroid:(0,u.average)(n)}},e.exports=n["default"]},{335:335,336:336,337:337}],333:[function(t,e,n){"use strict";function a(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(n,"__esModule",{value:!0});var r=function(){function t(t,e){var n=[],a=!0,r=!1,i=void 0;try{for(var o,s=t[Symbol.iterator]();!(a=(o=s.next()).done)&&(n.push(o.value),!e||n.length!==e);a=!0);}catch(p){r=!0,i=p}finally{try{!a&&s["return"]&&s["return"]()}finally{if(r)throw i}}return n}return function(e,n){if(Array.isArray(e))return e;if(Symbol.iterator in Object(e))return t(e,n);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}(),i=t(334),o=a(i),s=t(335),p=1e-5,u=function(t,e){var n=t.map(e),a=n.sort(function(t,e){var n=r(t,2),a=n[0],i=(n[1],r(e,2)),o=i[0];i[1];return a-o}),i=a.length,o=a[0][0],u=a[i-1][0],c=(0,s.minBy)(a,function(t){return t[1]}),l=(0,s.maxBy)(a,function(t){return t[1]});return o==u&&(u+=p),c==l&&(l+=p),{points:a,xmin:o,xmax:u,ymin:c,ymax:l}};n["default"]=function(t){var e=t.data,n=t.xaccessor,a=t.yaccessor,i=t.width,p=t.height,c=t.closed,l=t.min,d=t.max;n||(n=function(t){var e=r(t,2),n=e[0];e[1];return n}),a||(a=function(t){var e=r(t,2),n=(e[0],e[1]);return n});var f=function(t){return[n(t),a(t)]},h=e.map(function(t){return u(t,f)}),m=(0,s.minBy)(h,function(t){return t.xmin}),g=(0,s.maxBy)(h,function(t){return t.xmax}),v=null==l?(0,s.minBy)(h,function(t){return t.ymin}):l,b=null==d?(0,s.maxBy)(h,function(t){return t.ymax}):d;c&&(v=Math.min(v,0),b=Math.max(b,0));var y=c?0:v,_=(0,o["default"])([m,g],[0,i]),x=(0,o["default"])([v,b],[p,0]),w=function(t){var e=r(t,2),n=e[0],a=e[1];return[_(n),x(a)]};return{arranged:h,scale:w,xscale:_,yscale:x,base:y}},e.exports=n["default"]},{334:334,335:335}],334:[function(t,e,n){"use strict";Object.defineProperty(n,"__esModule",{value:!0});var a=function(){function t(t,e){var n=[],a=!0,r=!1,i=void 0;try{for(var o,s=t[Symbol.iterator]();!(a=(o=s.next()).done)&&(n.push(o.value),!e||n.length!==e);a=!0);}catch(p){r=!0,i=p}finally{try{!a&&s["return"]&&s["return"]()}finally{if(r)throw i}}return n}return function(e,n){if(Array.isArray(e))return e;if(Symbol.iterator in Object(e))return t(e,n);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}(),r=function i(t,e){var n=a(t,2),r=n[0],o=n[1],s=a(e,2),p=s[0],u=s[1],c=function(t){return p+(u-p)*(t-r)/(o-r)};return c.inverse=function(){return i([p,u],[r,o])},c};n["default"]=r,e.exports=n["default"]},{}],335:[function(t,e,n){"use strict";Object.defineProperty(n,"__esModule",{value:!0});var a=function(){function t(t,e){var n=[],a=!0,r=!1,i=void 0;try{for(var o,s=t[Symbol.iterator]();!(a=(o=s.next()).done)&&(n.push(o.value),!e||n.length!==e);a=!0);}catch(p){r=!0,i=p}finally{try{!a&&s["return"]&&s["return"]()}finally{if(r)throw i}}return n}return function(e,n){if(Array.isArray(e))return e;if(Symbol.iterator in Object(e))return t(e,n);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}(),r=function(t){return t.reduce(function(t,e){return t+e},0)},i=function(t){return t.reduce(function(t,e){return Math.min(t,e)})},o=function(t){return t.reduce(function(t,e){return Math.max(t,e)})},s=function(t,e){return t.reduce(function(t,n){return t+e(n)},0)},p=function(t,e){return t.reduce(function(t,n){return Math.min(t,e(n))},1/0)},u=function(t,e){return t.reduce(function(t,n){return Math.max(t,e(n))},-(1/0))},c=function(t,e){var n=a(t,2),r=n[0],i=n[1],o=a(e,2),s=o[0],p=o[1];return[r+s,i+p]},l=function(t,e){var n=a(t,2),r=n[0],i=n[1],o=a(e,2),s=o[0],p=o[1];return[r-s,i-p]},d=function(t,e){var n=a(e,2),r=n[0],i=n[1];return[t*r,t*i]},f=function(t){var e=a(t,2),n=e[0],r=e[1];return Math.sqrt(n*n+r*r)},h=function(t){return t.reduce(c,[0,0])},m=function(t){return d(1/t.length,t.reduce(c))},g=function(t,e){return d(t,[Math.sin(e),-Math.cos(e)])},v=function(t,e){var n=t||{};for(var a in n){var r=n[a];e[a]=r(e.index,e.item,e.group)}return e},b=function(t,e,n){for(var a=[],r=t;e>r;r++)a.push(r);return n&&a.push(e),a},y=function(t,e){var n=[],a=!0,r=!1,i=void 0;try{for(var o,s=Object.keys(t)[Symbol.iterator]();!(a=(o=s.next()).done);a=!0){var p=o.value,u=t[p];n.push(e(p,u))}}catch(c){r=!0,i=c}finally{
-try{!a&&s["return"]&&s["return"]()}finally{if(r)throw i}}return n},_=function(t){return y(t,function(t,e){return[t,e]})},x=function(t){return t};n.sum=r,n.min=i,n.max=o,n.sumBy=s,n.minBy=p,n.maxBy=u,n.plus=c,n.minus=l,n.times=d,n.id=x,n.length=f,n.sumVectors=h,n.average=m,n.onCircle=g,n.enhance=v,n.range=b,n.mapObject=y,n.pairs=_,n["default"]={sum:r,min:i,max:o,sumBy:s,minBy:p,maxBy:u,plus:c,minus:l,times:d,id:x,length:f,sumVectors:h,average:m,onCircle:g,enhance:v,range:b,mapObject:y,pairs:_}},{}],336:[function(t,e,n){"use strict";Object.defineProperty(n,"__esModule",{value:!0});var a=function(){function t(t,e){var n=[],a=!0,r=!1,i=void 0;try{for(var o,s=t[Symbol.iterator]();!(a=(o=s.next()).done)&&(n.push(o.value),!e||n.length!==e);a=!0);}catch(p){r=!0,i=p}finally{try{!a&&s["return"]&&s["return"]()}finally{if(r)throw i}}return n}return function(e,n){if(Array.isArray(e))return e;if(Symbol.iterator in Object(e))return t(e,n);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}(),r=function i(t){var e=t||[],n=function(t,e){var n=t.slice(0,t.length);return n.push(e),n},r=function(t,e){var n=a(t,2),r=n[0],i=n[1],o=a(e,2),s=o[0],p=o[1];return r===s&&i===p},o=function(t,e){for(var n=t.length;"0"===t.charAt(n-1);)n-=1;return"."===t.charAt(n-1)&&(n-=1),t.substr(0,n)},s=function(t,e){var n=t.toFixed(e);return o(n)},p=function(t){var e=t.command,n=t.params,a=n.map(function(t){return s(t,6)});return e+" "+a.join(" ")},u=function(t,e){var n=t.command,r=t.params,i=a(e,2),o=i[0],s=i[1];switch(n){case"M":return[r[0],r[1]];case"L":return[r[0],r[1]];case"H":return[r[0],s];case"V":return[o,r[0]];case"Z":return null;case"C":return[r[4],r[5]];case"S":return[r[2],r[3]];case"Q":return[r[2],r[3]];case"T":return[r[0],r[1]];case"A":return[r[5],r[6]]}},c=function(t,e){return function(n){var a="object"==typeof n?t.map(function(t){return n[t]}):arguments;return e.apply(null,a)}},l=function(t){return i(n(e,t))};return{moveto:c(["x","y"],function(t,e){return l({command:"M",params:[t,e]})}),lineto:c(["x","y"],function(t,e){return l({command:"L",params:[t,e]})}),hlineto:c(["x"],function(t){return l({command:"H",params:[t]})}),vlineto:c(["y"],function(t){return l({command:"V",params:[t]})}),closepath:function(){return l({command:"Z",params:[]})},curveto:c(["x1","y1","x2","y2","x","y"],function(t,e,n,a,r,i){return l({command:"C",params:[t,e,n,a,r,i]})}),smoothcurveto:c(["x2","y2","x","y"],function(t,e,n,a){return l({command:"S",params:[t,e,n,a]})}),qcurveto:c(["x1","y1","x","y"],function(t,e,n,a){return l({command:"Q",params:[t,e,n,a]})}),smoothqcurveto:c(["x","y"],function(t,e){return l({command:"T",params:[t,e]})}),arc:c(["rx","ry","xrot","largeArcFlag","sweepFlag","x","y"],function(t,e,n,a,r,i,o){return l({command:"A",params:[t,e,n,a,r,i,o]})}),print:function(){return e.map(p).join(" ")},points:function(){var t=[],n=[0,0],a=!0,r=!1,i=void 0;try{for(var o,s=e[Symbol.iterator]();!(a=(o=s.next()).done);a=!0){var p=o.value,c=u(p,n);n=c,c&&t.push(c)}}catch(l){r=!0,i=l}finally{try{!a&&s["return"]&&s["return"]()}finally{if(r)throw i}}return t},instructions:function(){return e.slice(0,e.length)},connect:function(t){var e=this.points(),n=e[e.length-1],a=t.points()[0],o=t.instructions().slice(1);return r(n,a)||o.unshift({command:"L",params:a}),i(this.instructions().concat(o))}}};n["default"]=function(){return r()},e.exports=n["default"]},{}],337:[function(t,e,n){"use strict";function a(t){return t&&t.__esModule?t:{"default":t}}function r(t){if(Array.isArray(t)){for(var e=0,n=Array(t.length);e1?e-1:0),a=1;e>a;a++)n[a-1]=arguments[a];for(var r,i;i=n.shift();)for(r in i)Mo.call(i,r)&&(t[r]=i[r]);return t}function r(t){for(var e=arguments.length,n=Array(e>1?e-1:0),a=1;e>a;a++)n[a-1]=arguments[a];return n.forEach(function(e){for(var n in e)!e.hasOwnProperty(n)||n in t||(t[n]=e[n])}),t}function i(t){return"[object Array]"===Lo.call(t)}function o(t){return jo.test(Lo.call(t))}function s(t,e){return null===t&&null===e?!0:"object"==typeof t||"object"==typeof e?!1:t===e}function p(t){return!isNaN(parseFloat(t))&&isFinite(t)}function u(t){return t&&"[object Object]"===Lo.call(t)}function c(t,e){return t.replace(/%s/g,function(){return e.shift()})}function l(t){for(var e=arguments.length,n=Array(e>1?e-1:0),a=1;e>a;a++)n[a-1]=arguments[a];throw t=c(t,n),Error(t)}function d(){Mg.DEBUG&&Oo.apply(null,arguments)}function f(t){for(var e=arguments.length,n=Array(e>1?e-1:0),a=1;e>a;a++)n[a-1]=arguments[a];t=c(t,n),To(t,n)}function h(t){for(var e=arguments.length,n=Array(e>1?e-1:0),a=1;e>a;a++)n[a-1]=arguments[a];t=c(t,n),Do[t]||(Do[t]=!0,To(t,n))}function m(){Mg.DEBUG&&f.apply(null,arguments)}function g(){Mg.DEBUG&&h.apply(null,arguments)}function v(t,e,n){var a=b(t,e,n);return a?a[t][n]:null}function b(t,e,n){for(;e;){if(n in e[t])return e;if(e.isolated)return null;e=e.parent}}function y(t){return function(){return t}}function _(t){var e,n,a,r,i,o;for(e=t.split("."),(n=zo[e.length])||(n=x(e.length)),i=[],a=function(t,n){return t?"*":e[n]},r=n.length;r--;)o=n[r].map(a).join("."),i.hasOwnProperty(o)||(i.push(o),i[o]=!0);return i}function x(t){var e,n,a,r,i,o,s,p,u="";if(!zo[t]){for(a=[];u.length=i;i+=1){for(n=i.toString(2);n.lengtho;o++)p.push(r(n[o]));a[i]=p}zo[t]=a}return zo[t]}function w(t,e,n,a){var r=t[e];if(!r||!r.equalsOrStartsWith(a)&&r.equalsOrStartsWith(n))return t[e]=r?r.replace(n,a):a,!0}function k(t){var e=t.slice(2);return"i"===t[1]&&p(e)?+e:e}function S(t){return null==t?t:(Ko.hasOwnProperty(t)||(Ko[t]=new Qo(t)),Ko[t])}function E(t,e){function n(e,n){var a,r,o;return n.isRoot?o=[].concat(Object.keys(t.viewmodel.data),Object.keys(t.viewmodel.mappings),Object.keys(t.viewmodel.computations)):(a=t.viewmodel.wrapped[n.str],r=a?a.get():t.viewmodel.get(n),o=r?Object.keys(r):null),o&&o.forEach(function(t){"_ractive"===t&&i(r)||e.push(n.join(t))}),e}var a,r,o;for(a=e.str.split("."),o=[$o];r=a.shift();)"*"===r?o=o.reduce(n,[]):o[0]===$o?o[0]=S(r):o=o.map(C(r));return o}function C(t){return function(e){return e.join(t)}}function P(t){return t?t.replace(Wo,".$1"):""}function A(t,e,n){if("string"!=typeof e||!p(n))throw Error("Bad arguments");var a=void 0,r=void 0;if(/\*/.test(e))return r={},E(t,S(P(e))).forEach(function(e){var a=t.viewmodel.get(e);if(!p(a))throw Error(Xo);r[e.str]=a+n}),t.set(r);if(a=t.get(e),!p(a))throw Error(Xo);return t.set(e,+a+n)}function O(t,e){return Jo(this,t,void 0===e?1:+e)}function T(t){this.event=t,this.method="on"+t,this.deprecate=as[t]}function R(t,e){var n=t.indexOf(e);-1===n&&t.push(e)}function M(t,e){for(var n=0,a=t.length;a>n;n++)if(t[n]==e)return!0;return!1}function L(t,e){var n;if(!i(t)||!i(e))return!1;if(t.length!==e.length)return!1;for(n=t.length;n--;)if(t[n]!==e[n])return!1;return!0}function j(t){return"string"==typeof t?[t]:void 0===t?[]:t}function D(t){return t[t.length-1]}function N(t,e){var n=t.indexOf(e);-1!==n&&t.splice(n,1)}function F(t){for(var e=[],n=t.length;n--;)e[n]=t[n];return e}function I(t){setTimeout(t,0)}function B(t,e){return function(){for(var n;n=t.shift();)n(e)}}function q(t,e,n,a){var r;if(e===t)throw new TypeError("A promise's fulfillment handler cannot return the same promise");if(e instanceof rs)e.then(n,a);else if(!e||"object"!=typeof e&&"function"!=typeof e)n(e);else{try{r=e.then}catch(i){return void a(i)}if("function"==typeof r){var o,s,p;s=function(e){o||(o=!0,q(t,e,n,a))},p=function(t){o||(o=!0,a(t))};try{r.call(e,s,p)}catch(i){if(!o)return a(i),void(o=!0)}}else n(e)}}function U(t,e,n){var a;return e=P(e),"~/"===e.substr(0,2)?(a=S(e.substring(2)),z(t,a.firstKey,n)):"."===e[0]?(a=V(cs(n),e),a&&z(t,a.firstKey,n)):a=G(t,S(e),n),a}function V(t,e){var n;if(void 0!=t&&"string"!=typeof t&&(t=t.str),"."===e)return S(t);if(n=t?t.split("."):[],"../"===e.substr(0,3)){for(;"../"===e.substr(0,3);){if(!n.length)throw Error('Could not resolve reference - too many "../" prefixes');n.pop(),e=e.substring(3)}return n.push(e),S(n.join("."))}return S(t?t+e.replace(/^\.\//,"."):e.replace(/^\.\/?/,""))}function G(t,e,n,a){var r,i,o,s,p;if(e.isRoot)return e;for(i=e.firstKey;n;)if(r=n.context,n=n.parent,r&&(s=!0,o=t.viewmodel.get(r),o&&("object"==typeof o||"function"==typeof o)&&i in o))return r.join(e.str);return W(t.viewmodel,i)?e:t.parent&&!t.isolated&&(s=!0,n=t.component.parentFragment,i=S(i),p=G(t.parent,i,n,!0))?(t.viewmodel.map(i,{origin:t.parent.viewmodel,keypath:p}),e):a||s?void 0:(t.viewmodel.set(e,void 0),e)}function z(t,e){var n;!t.parent||t.isolated||W(t.viewmodel,e)||(e=S(e),(n=G(t.parent,e,t.component.parentFragment,!0))&&t.viewmodel.map(e,{origin:t.parent.viewmodel,keypath:n}))}function W(t,e){return""===e||e in t.data||e in t.computations||e in t.mappings}function H(t){t.teardown()}function K(t){t.unbind()}function Q(t){t.unrender()}function Y(t){t.cancel()}function $(t){t.detach()}function J(t){t.detachNodes()}function X(t){!t.ready||t.outros.length||t.outroChildren||(t.outrosComplete||(t.parent?t.parent.decrementOutros(t):t.detachNodes(),t.outrosComplete=!0),t.intros.length||t.totalChildren||("function"==typeof t.callback&&t.callback(),t.parent&&t.parent.decrementTotal()))}function Z(){for(var t,e,n;fs.ractives.length;)e=fs.ractives.pop(),n=e.viewmodel.applyChanges(),n&&vs.fire(e,n);for(tt(),t=0;t=0;i--)r=t._subs[e[i]],r&&(s=vt(t,r,n,a)&&s);if(Gs.dequeue(t),t.parent&&s){if(o&&t.component){var p=t.component.name+"."+e[e.length-1];e=S(p).wildcardMatches(),n&&(n.component=t)}gt(t.parent,e,n,a)}}function vt(t,e,n,a){var r=null,i=!1;n&&!n._noArg&&(a=[n].concat(a)),e=e.slice();for(var o=0,s=e.length;s>o;o+=1)e[o].apply(t,a)===!1&&(i=!0);return n&&!n._noArg&&i&&(r=n.original)&&(r.preventDefault&&r.preventDefault(),r.stopPropagation&&r.stopPropagation()),!i}function bt(t){var e={args:Array.prototype.slice.call(arguments,1)};zs(this,t,e)}function yt(t){var e;return t=S(P(t)),e=this.viewmodel.get(t,Ks),void 0===e&&this.parent&&!this.isolated&&ls(this,t.str,this.component.parentFragment)&&(e=this.viewmodel.get(t)),e}function _t(e,n){if(!this.fragment.rendered)throw Error("The API has changed - you must call `ractive.render(target[, anchor])` to render your Ractive instance. Once rendered you can use `ractive.insert()`.");if(e=t(e),n=t(n)||null,!e)throw Error("You must specify a valid target to insert into");e.insertBefore(this.detach(),n),this.el=e,(e.__ractive_instances__||(e.__ractive_instances__=[])).push(this),this.detached=null,xt(this)}function xt(t){Ys.fire(t),t.findAllComponents("*").forEach(function(t){xt(t.instance)})}function wt(t,e,n){var a,r;return t=S(P(t)),a=this.viewmodel.get(t),i(a)&&i(e)?(r=bs.start(this,!0),this.viewmodel.merge(t,a,e,n),bs.end(),r):this.set(t,e,n&&n.complete)}function kt(t,e){var n,a;return n=E(t,e),a={},n.forEach(function(e){a[e.str]=t.get(e.str)}),a}function St(t,e,n,a){var r,i,o;e=S(P(e)),a=a||cp,e.isPattern?(r=new pp(t,e,n,a),t.viewmodel.patternObservers.push(r),i=!0):r=new Zs(t,e,n,a),r.init(a.init),t.viewmodel.register(e,r,i?"patternObservers":"observers"),r.ready=!0;var s={cancel:function(){var n;o||(i?(n=t.viewmodel.patternObservers.indexOf(r),t.viewmodel.patternObservers.splice(n,1),t.viewmodel.unregister(e,r,"patternObservers")):t.viewmodel.unregister(e,r,"observers"),o=!0)}};return t._observers.push(s),s}function Et(t,e,n){var a,r,i,o;if(u(t)){n=e,r=t,a=[];for(t in r)r.hasOwnProperty(t)&&(e=r[t],a.push(this.observe(t,e,n)));return{cancel:function(){for(;a.length;)a.pop().cancel()}}}if("function"==typeof t)return n=e,e=t,t="",up(this,t,e,n);if(i=t.split(" "),1===i.length)return up(this,t,e,n);for(a=[],o=i.length;o--;)t=i[o],t&&a.push(up(this,t,e,n));return{cancel:function(){for(;a.length;)a.pop().cancel()}}}function Ct(t,e,n){var a=this.observe(t,function(){e.apply(this,arguments),a.cancel()},{init:!1,defer:n&&n.defer});return a}function Pt(t,e){var n,a=this;if(t)n=t.split(" ").map(fp).filter(hp),n.forEach(function(t){var n,r;(n=a._subs[t])&&(e?(r=n.indexOf(e),-1!==r&&n.splice(r,1)):a._subs[t]=[])});else for(t in this._subs)delete this._subs[t];return this}function At(t,e){var n,a,r,i=this;if("object"==typeof t){n=[];for(a in t)t.hasOwnProperty(a)&&n.push(this.on(a,t[a]));return{cancel:function(){for(var t;t=n.pop();)t.cancel()}}}return r=t.split(" ").map(fp).filter(hp),r.forEach(function(t){(i._subs[t]||(i._subs[t]=[])).push(e)}),{cancel:function(){return i.off(t,e)}}}function Ot(t,e){var n=this.on(t,function(){e.apply(this,arguments),n.cancel()});return n}function Tt(t,e,n){var a,r,i,o,s,p,u=[];if(a=Rt(t,e,n),!a)return null;for(r=t.length,s=a.length-2-a[1],i=Math.min(r,a[0]),o=i+a[1],p=0;i>p;p+=1)u.push(p);for(;o>p;p+=1)u.push(-1);for(;r>p;p+=1)u.push(p+s);return 0!==s?u.touchedFrom=a[0]:u.touchedFrom=t.length,u}function Rt(t,e,n){switch(e){case"splice":for(void 0!==n[0]&&n[0]<0&&(n[0]=t.length+Math.max(n[0],-t.length));n.length<2;)n.push(0);return n[1]=Math.min(n[1],t.length-n[0]),n;case"sort":case"reverse":return null;case"pop":return t.length?[t.length-1,1]:[0,0];case"push":return[t.length,0].concat(n);case"shift":return[0,t.length?1:0];case"unshift":return[0,0].concat(n)}}function Mt(e,n){var a,r,i,o=this;if(i=this.transitionsEnabled,this.noIntro&&(this.transitionsEnabled=!1),a=bs.start(this,!0),bs.scheduleTask(function(){return Rp.fire(o)},!0),this.fragment.rendered)throw Error("You cannot call ractive.render() on an already rendered instance! Call ractive.unrender() first");if(e=t(e)||this.el,n=t(n)||this.anchor,this.el=e,this.anchor=n,!this.append&&e){var s=e.__ractive_instances__;s&&s.length&&Lt(s),e.innerHTML=""}return this.cssId&&Op.apply(),e&&((r=e.__ractive_instances__)?r.push(this):e.__ractive_instances__=[this],n?e.insertBefore(this.fragment.render(),n):e.appendChild(this.fragment.render())),bs.end(),this.transitionsEnabled=i,a.then(function(){return Mp.fire(o)})}function Lt(t){t.splice(0,t.length).forEach(H)}function jt(t,e){for(var n=t.slice(),a=e.length;a--;)~n.indexOf(e[a])||n.push(e[a]);return n}function Dt(t,e){var n,a,r;return a='[data-ractive-css~="{'+e+'}"]',r=function(t){var e,n,r,i,o,s,p,u=[];for(e=[];n=Ip.exec(t);)e.push({str:n[0],base:n[1],modifiers:n[2]});for(i=e.map(Ft),p=e.length;p--;)s=i.slice(),r=e[p],s[p]=r.base+a+r.modifiers||"",o=i.slice(),o[p]=a+" "+o[p],u.push(s.join(" "),o.join(" "));return u.join(", ")},n=qp.test(t)?t.replace(qp,a):t.replace(Fp,"").replace(Np,function(t,e){var n,a;return Bp.test(e)?t:(n=e.split(",").map(Nt),a=n.map(r).join(", ")+" ",t.replace(e,a))})}function Nt(t){return t.trim?t.trim():t.replace(/^\s+/,"").replace(/\s+$/,"")}function Ft(t){return t.str}function It(t){t&&t.constructor!==Object&&("function"==typeof t||("object"!=typeof t?l("data option must be an object or a function, `"+t+"` is not valid"):m("If supplied, options.data should be a plain JavaScript object - using a non-POJO as the root object may work, but is discouraged")))}function Bt(t,e){It(e);var n="function"==typeof t,a="function"==typeof e;return e||n||(e={}),n||a?function(){var r=a?qt(e,this):e,i=n?qt(t,this):t;return Ut(r,i)}:Ut(e,t)}function qt(t,e){var n=t.call(e);if(n)return"object"!=typeof n&&l("Data function must return an object"),n.constructor!==Object&&g("Data function returned something other than a plain JavaScript object. This might work, but is strongly discouraged"),n}function Ut(t,e){if(t&&e){for(var n in e)n in t||(t[n]=e[n]);return t}return t||e}function Vt(t){var e=So(Qp);return e.parse=function(e,n){return Gt(e,n||t)},e}function Gt(t,e){if(!Hp)throw Error("Missing Ractive.parse - cannot parse template. Either preparse or use the version that includes the parser");return Hp(t,e||this.options)}function zt(t,e){var n;if(!Xi){if(e&&e.noThrow)return;throw Error("Cannot retrieve template #"+t+" as Ractive is not running in a browser.")}if(Wt(t)&&(t=t.substring(1)),!(n=document.getElementById(t))){if(e&&e.noThrow)return;throw Error("Could not find template element with id #"+t)}if("SCRIPT"!==n.tagName.toUpperCase()){if(e&&e.noThrow)return;throw Error("Template element with id #"+t+", must be a |