"
+ . += "A class [diode.rating] laser diode is installed. It is screwed in place."
/obj/item/laser_pointer/afterattack(atom/target, mob/living/user, flag, params)
. = ..()
@@ -148,9 +148,9 @@
H.Move(targloc)
log_combat(user, H, "moved with a laser pointer",src)
else
- H.visible_message("[H] looks briefly distracted by the light."," You're briefly tempted by the shiny light... ")
+ H.visible_message("[H] looks briefly distracted by the light."," You're briefly tempted by the shiny light... ")
else
- H.visible_message("[H] stares at the light"," You stare at the light... ")
+ H.visible_message("[H] stares at the light"," You stare at the light... ")
//cats!
for(var/mob/living/simple_animal/pet/cat/C in view(1,targloc))
diff --git a/code/game/objects/items/devices/paicard.dm b/code/game/objects/items/devices/paicard.dm
index 99fa8e5b441..7956aa8542b 100644
--- a/code/game/objects/items/devices/paicard.dm
+++ b/code/game/objects/items/devices/paicard.dm
@@ -156,7 +156,7 @@
src.add_overlay("pai-null")
/obj/item/paicard/proc/alertUpdate()
- audible_message("[src] flashes a message across its screen, \"Additional personalities available for download.\"", "[src] vibrates with an alert.")
+ audible_message("[src] flashes a message across its screen, \"Additional personalities available for download.\"", "[src] vibrates with an alert.")
/obj/item/paicard/emp_act(severity)
. = ..()
diff --git a/code/game/objects/items/devices/radio/intercom.dm b/code/game/objects/items/devices/radio/intercom.dm
index e6b7d12f751..ce3b5adc6d1 100644
--- a/code/game/objects/items/devices/radio/intercom.dm
+++ b/code/game/objects/items/devices/radio/intercom.dm
@@ -23,7 +23,7 @@
/obj/item/radio/intercom/ratvar/attackby(obj/item/I, mob/living/user, params)
if(I.tool_behaviour == TOOL_SCREWDRIVER)
- to_chat(user, "[src] is fastened to the wall with [is_servant_of_ratvar(user) ? "replicant alloy" : "some material you've never seen"], and can't be removed.")
+ to_chat(user, "[src] is fastened to the wall with [is_servant_of_ratvar(user) ? "replicant alloy" : "some material you've never seen"], and can't be removed.")
return //no unfastening!
. = ..()
diff --git a/code/game/objects/items/devices/scanners.dm b/code/game/objects/items/devices/scanners.dm
index b44cc15b1b9..26aae058c29 100644
--- a/code/game/objects/items/devices/scanners.dm
+++ b/code/game/objects/items/devices/scanners.dm
@@ -144,8 +144,12 @@ GENE SCANNER
var/mob/living/carbon/human/H = M
if(H.undergoing_cardiac_arrest() && H.stat != DEAD)
to_chat(user, "Subject suffering from heart attack: Apply defibrillation or other electric shock immediately!")
- if(H.undergoing_liver_failure() && H.stat != DEAD)
- to_chat(user, "Subject is suffering from liver failure: Apply Corazone and begin a liver transplant immediately!")
+ //organ failure messages
+ for(var/O in H.internal_organs)
+ var/obj/item/organ/organ = O
+ if(!istype(organ, /obj/item/organ/heart))
+ if(organ.failing)
+ to_chat(user, organ.Assemble_Failure_Message())
to_chat(user, "Analyzing results for [M]:\n\tOverall status: [mob_status]")
@@ -216,11 +220,11 @@ GENE SCANNER
healthy = FALSE
to_chat(user, "\tSubject is deaf.")
else
- if(ears.ear_damage)
- to_chat(user, "\tSubject has [ears.ear_damage > UNHEALING_EAR_DAMAGE? "permanent ": "temporary "]hearing damage.")
+ if(ears.damage)
+ to_chat(user, "\tSubject has [ears.damage > ears.maxHealth ? "permanent ": "temporary "]hearing damage.")
healthy = FALSE
if(ears.deaf)
- to_chat(user, "\tSubject is [ears.ear_damage > UNHEALING_EAR_DAMAGE ? "permanently ": "temporarily "] deaf.")
+ to_chat(user, "\tSubject is [ears.damage > ears.maxHealth ? "permanently ": "temporarily "] deaf.")
healthy = FALSE
if(healthy)
to_chat(user, "\tHealthy.")
@@ -236,13 +240,13 @@ GENE SCANNER
if(HAS_TRAIT(C, TRAIT_NEARSIGHT))
to_chat(user, "\tSubject is nearsighted.")
healthy = FALSE
- if(eyes.eye_damage > 30)
+ if(eyes.damage > 30)
to_chat(user, "\tSubject has severe eye damage.")
healthy = FALSE
- else if(eyes.eye_damage > 20)
+ else if(eyes.damage > 20)
to_chat(user, "\tSubject has significant eye damage.")
healthy = FALSE
- else if(eyes.eye_damage)
+ else if(eyes.damage)
to_chat(user, "\tSubject has minor eye damage.")
healthy = FALSE
if(healthy)
@@ -253,9 +257,10 @@ GENE SCANNER
if(ishuman(M))
var/mob/living/carbon/human/H = M
- var/ldamage = H.return_liver_damage()
- if(ldamage > 10)
- to_chat(user, "\t[ldamage > 45 ? "Severe" : "Minor"] liver damage detected.")
+ for(var/O in H.internal_organs)
+ var/obj/item/organ/organ = O
+ if((organ.damage > organ.low_threshold)&&(!istype(organ, /obj/item/organ/brain)))
+ to_chat(user, "\t[organ.damage > organ.high_threshold ? "Severe" : "Minor"] damaged detected within [organ].")
if(advanced && H.has_dna())
to_chat(user, "\tGenetic Stability: [H.dna.stability]%.")
@@ -632,7 +637,7 @@ GENE SCANNER
to_chat(user, "Growth progress: [T.amount_grown]/[SLIME_EVOLUTION_THRESHOLD]")
if(T.effectmod)
to_chat(user, "Core mutation in progress: [T.effectmod]")
- to_chat(user, "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/grenades/plastic.dm b/code/game/objects/items/grenades/plastic.dm
index 2b60b77c538..9d7d5236f0b 100644
--- a/code/game/objects/items/grenades/plastic.dm
+++ b/code/game/objects/items/grenades/plastic.dm
@@ -116,7 +116,7 @@
message_admins("[ADMIN_LOOKUPFLW(user)] planted [name] on [target.name] at [ADMIN_VERBOSEJMP(target)] with [det_time] second fuse")
log_game("[key_name(user)] planted [name] on [target.name] at [AREACOORD(user)] with a [det_time] second fuse")
- notify_ghosts("[user] has planted \a [src] on [target] with a [det_time] second fuse!", source = target, action = NOTIFY_ORBIT)
+ notify_ghosts("[user] has planted \a [src] on [target] with a [det_time] second fuse!", source = target, action = NOTIFY_ORBIT, header = "Bomb Planted" )
moveToNullspace() //Yep
diff --git a/code/game/objects/items/handcuffs.dm b/code/game/objects/items/handcuffs.dm
index 8defe5ebd2e..fa9de999c30 100644
--- a/code/game/objects/items/handcuffs.dm
+++ b/code/game/objects/items/handcuffs.dm
@@ -35,7 +35,7 @@
throw_speed = 3
throw_range = 5
materials = list(MAT_METAL=500)
- breakouttime = 600 //Deciseconds = 60s = 1 minute
+ breakouttime = 1 MINUTES
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 50)
var/cuffsound = 'sound/weapons/handcuffs.ogg'
var/trashtype = null //for disposable cuffs
@@ -116,7 +116,7 @@
lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi'
materials = list(MAT_METAL=150, MAT_GLASS=75)
- breakouttime = 300 //Deciseconds = 30s
+ breakouttime = 30 SECONDS
cuffsound = 'sound/weapons/cablecuff.ogg'
/obj/item/restraints/handcuffs/cable/Initialize(mapload, param_color)
@@ -165,7 +165,7 @@
/obj/item/restraints/handcuffs/fake
name = "fake handcuffs"
desc = "Fake handcuffs meant for gag purposes."
- breakouttime = 10 //Deciseconds = 1s
+ breakouttime = 1 SECONDS
/obj/item/restraints/handcuffs/cable/attackby(obj/item/I, mob/user, params)
..()
@@ -205,7 +205,7 @@
lefthand_file = 'icons/mob/inhands/equipment/security_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/security_righthand.dmi'
materials = list()
- breakouttime = 450 //Deciseconds = 45s
+ breakouttime = 45 SECONDS
trashtype = /obj/item/restraints/handcuffs/cable/zipties/used
item_color = "white"
@@ -231,7 +231,7 @@
throwforce = 0
w_class = WEIGHT_CLASS_NORMAL
slowdown = 7
- breakouttime = 300 //Deciseconds = 30s = 0.5 minute
+ breakouttime = 30 SECONDS
/obj/item/restraints/legcuffs/beartrap
name = "bear trap"
diff --git a/code/game/objects/items/melee/misc.dm b/code/game/objects/items/melee/misc.dm
index 4ed0ade9e0c..d5614a14518 100644
--- a/code/game/objects/items/melee/misc.dm
+++ b/code/game/objects/items/melee/misc.dm
@@ -76,17 +76,15 @@
final_block_chance = 0 //Don't bring a sword to a gunfight
return ..()
-/obj/item/melee/sabre/on_exit_storage(obj/item/storage/S)
- ..()
- var/obj/item/storage/belt/sabre/B = S
+/obj/item/melee/sabre/on_exit_storage(datum/component/storage/concrete/S)
+ var/obj/item/storage/belt/sabre/B = S.real_location()
if(istype(B))
- playsound(B, 'sound/items/unsheath.ogg', 25, 1)
+ playsound(B, 'sound/items/unsheath.ogg', 25, TRUE)
-/obj/item/melee/sabre/on_enter_storage(obj/item/storage/S)
- ..()
- var/obj/item/storage/belt/sabre/B = S
+/obj/item/melee/sabre/on_enter_storage(datum/component/storage/concrete/S)
+ var/obj/item/storage/belt/sabre/B = S.real_location()
if(istype(B))
- playsound(B, 'sound/items/sheath.ogg', 25, 1)
+ playsound(B, 'sound/items/sheath.ogg', 25, TRUE)
/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!")
@@ -131,27 +129,36 @@
user.death(FALSE)
REMOVE_TRAIT(src, TRAIT_NODROP, SABRE_SUICIDE_TRAIT)
-/obj/item/melee/sabre/bee
- name = "the stinger"
+/obj/item/melee/beesword
+ name = "The Stinger"
desc = "Taken from a giant bee and folded over one thousand times in pure honey. Can sting through anything."
icon = 'icons/obj/items_and_weapons.dmi'
- icon_state = "stinger"
+ icon_state = "beesword"
item_state = "stinger"
lefthand_file = 'icons/mob/inhands/weapons/melee_lefthand.dmi'
righthand_file = 'icons/mob/inhands/weapons/melee_righthand.dmi'
slot_flags = ITEM_SLOT_BELT
+ w_class = WEIGHT_CLASS_BULKY
+ sharpness = IS_SHARP
force = 7
+ throwforce = 10
block_chance = 20
armour_penetration = 85
attack_verb = list("slashed", "stung", "prickled", "poked")
+ hitsound = 'sound/weapons/rapierhit.ogg'
-/obj/item/melee/sabre/bee/afterattack(atom/target, mob/user, proximity = TRUE)
+/obj/item/melee/beesword/afterattack(atom/target, mob/user, proximity = TRUE)
. = ..()
user.changeNext_move(CLICK_CD_RAPID)
if(iscarbon(target))
var/mob/living/carbon/H = target
H.reagents.add_reagent(/datum/reagent/toxin/histamine, 4)
+/obj/item/melee/beesword/suicide_act(mob/living/user)
+ user.visible_message("[user] is stabbing [user.p_them()]self in the throat with [src]! It looks like [user.p_theyre()] trying to commit suicide!")
+ playsound(get_turf(src), hitsound, 75, 1, -1)
+ return TOXLOSS
+
/obj/item/melee/classic_baton
name = "police baton"
desc = "A wooden truncheon for beating criminal scum."
@@ -163,8 +170,69 @@
slot_flags = ITEM_SLOT_BELT
force = 12 //9 hit crit
w_class = WEIGHT_CLASS_NORMAL
- var/cooldown = 0
- var/on = TRUE
+
+ var/cooldown_check = 0 // Used interally, you don't want to modify
+
+ var/cooldown = 40 // Default wait time until can stun again.
+ var/stun_time_carbon = 60 // How long we stun for - 6 seconds.
+ var/stun_time_silicon = 0.60 // Multiplier for stunning silicons; if enabled, is 60% of human stun time.
+ var/affect_silicon = FALSE // Does it stun silicons.
+ var/on_sound // "On" sound, played when switching between able to stun or not.
+ var/on_stun_sound = "sound/effects/woodhit.ogg" // Default path to sound for when we stun.
+ var/stun_animation = FALSE // Do we animate the "hit" when stunning.
+ var/on = TRUE // Are we on or off
+
+ var/on_icon_state // What is our sprite when turned on
+ var/off_icon_state // What is our sprite when turned off
+ var/on_item_state // What is our in-hand sprite when turned on
+ var/force_on // Damage when on - not stunning
+ var/force_off // Damage when off - not stunning
+ var/weight_class_on // What is the new size class when turned on
+
+/obj/item/melee/classic_baton/Initialize()
+ . = ..()
+
+ // Derive stun time from multiplier.
+ stun_time_silicon = stun_time_carbon * stun_time_silicon
+
+// Description for trying to stun when still on cooldown.
+/obj/item/melee/classic_baton/proc/get_wait_description()
+ return
+
+// Description for when turning their baton "on"
+/obj/item/melee/classic_baton/proc/get_on_description()
+ . = list()
+
+ .["local_on"] = "You extend the baton."
+ .["local_off"] = "You collapse the baton."
+
+ return .
+
+// Default message for stunning mob.
+/obj/item/melee/classic_baton/proc/get_stun_description(mob/living/target, mob/living/user)
+ . = list()
+
+ .["visible"] = "[user] has knocked down [target] with [src]!"
+ .["local"] = "[user] has knocked down [target] with [src]!"
+
+ return .
+
+// Default message for stunning a silicon.
+/obj/item/melee/classic_baton/proc/get_silicon_stun_description(mob/living/target, mob/living/user)
+ . = list()
+
+ .["visible"] = "[user] pulses [target]'s sensors with the baton!"
+ .["local"] = "You pulse [target]'s sensors with the baton!"
+
+ return .
+
+// Are we applying any special effects when we stun to carbon
+/obj/item/melee/classic_baton/proc/additional_effects_carbon(mob/living/target, mob/living/user)
+ return
+
+// Are we applying any special effects when we stun to silicon
+/obj/item/melee/classic_baton/proc/additional_effects_silicon(mob/living/target, mob/living/user)
+ return
/obj/item/melee/classic_baton/attack(mob/living/target, mob/living/user)
if(!on)
@@ -172,8 +240,9 @@
add_fingerprint(user)
if((HAS_TRAIT(user, TRAIT_CLUMSY)) && prob(50))
- to_chat(user, "You club yourself over the head.")
- user.Paralyze(60 * force)
+ to_chat(user, "You hit yourself over the head.")
+ user.Paralyze(stun_time_carbon * force)
+ additional_effects_carbon(user) // user is the target here
if(ishuman(user))
var/mob/living/carbon/human/H = user
H.apply_damage(2*force, BRUTE, BODY_ZONE_HEAD)
@@ -181,7 +250,24 @@
user.take_bodypart_damage(2*force)
return
if(iscyborg(target))
- ..()
+ // We don't stun if we're on harm.
+ if (user.a_intent != INTENT_HARM)
+ if (affect_silicon)
+ var/list/desc = get_silicon_stun_description(target, user)
+
+ target.flash_act(affect_silicon = TRUE)
+ target.Paralyze(stun_time_silicon)
+ additional_effects_silicon(target, user)
+
+ user.visible_message(desc["visible"], desc["local"])
+ playsound(get_turf(src), on_stun_sound, 100, TRUE, -1)
+
+ if (stun_animation)
+ user.do_attack_animation(target)
+ else
+ ..()
+ else
+ ..()
return
if(!isliving(target))
return
@@ -191,24 +277,37 @@
if(!iscyborg(target))
return
else
- if(cooldown <= world.time)
+ if(cooldown_check <= world.time)
if(ishuman(target))
var/mob/living/carbon/human/H = target
if (H.check_shields(src, 0, "[user]'s [name]", MELEE_ATTACK))
return
if(check_martial_counter(H, user))
return
- playsound(get_turf(src), 'sound/effects/woodhit.ogg', 75, 1, -1)
- target.Paralyze(60)
+
+ var/list/desc = get_stun_description(target, user)
+
+ if (stun_animation)
+ user.do_attack_animation(target)
+
+ playsound(get_turf(src), on_stun_sound, 75, 1, -1)
+ target.Paralyze(stun_time_carbon)
+ additional_effects_carbon(target, user)
+
log_combat(user, target, "stunned", src)
- src.add_fingerprint(user)
- target.visible_message("[user] has knocked down [target] with [src]!", \
- "[user] has knocked down [target] with [src]!")
+ add_fingerprint(user)
+
+ target.visible_message(desc["visible"], desc["local"])
+
if(!iscarbon(user))
target.LAssailant = null
else
target.LAssailant = user
- cooldown = world.time + 40
+ cooldown_check = world.time + cooldown
+ else
+ var/wait_desc = get_wait_description()
+ if (wait_desc)
+ to_chat(user, wait_desc)
/obj/item/melee/classic_baton/telescopic
name = "telescopic baton"
@@ -223,6 +322,14 @@
item_flags = NONE
force = 0
on = FALSE
+ on_sound = 'sound/weapons/batonextend.ogg'
+
+ on_icon_state = "telebaton_1"
+ off_icon_state = "telebaton_0"
+ on_item_state = "nullrod"
+ force_on = 10
+ force_off = 0
+ weight_class_on = WEIGHT_CLASS_BULKY
/obj/item/melee/classic_baton/telescopic/suicide_act(mob/user)
var/mob/living/carbon/human/H = user
@@ -232,7 +339,7 @@
if(!on)
src.attack_self(user)
else
- playsound(src, 'sound/weapons/batonextend.ogg', 50, 1)
+ playsound(src, on_sound, 50, 1)
add_fingerprint(user)
sleep(3)
if (!QDELETED(H))
@@ -244,25 +351,61 @@
/obj/item/melee/classic_baton/telescopic/attack_self(mob/user)
on = !on
+ var/list/desc = get_on_description()
+
if(on)
- to_chat(user, "You extend the baton.")
- icon_state = "telebaton_1"
- item_state = "nullrod"
- w_class = WEIGHT_CLASS_BULKY //doesnt fit in backpack when its on for balance
- force = 10 //stun baton damage
+ to_chat(user, desc["local_on"])
+ icon_state = on_icon_state
+ item_state = on_item_state
+ w_class = weight_class_on
+ force = force_on
attack_verb = list("smacked", "struck", "cracked", "beaten")
else
- to_chat(user, "You collapse the baton.")
- icon_state = "telebaton_0"
+ to_chat(user, desc["local_off"])
+ icon_state = off_icon_state
item_state = null //no sprite for concealment even when in hand
slot_flags = ITEM_SLOT_BELT
w_class = WEIGHT_CLASS_SMALL
- force = 0 //not so robust now
+ force = force_off
attack_verb = list("hit", "poked")
- playsound(src.loc, 'sound/weapons/batonextend.ogg', 50, 1)
+ playsound(src.loc, on_sound, 50, 1)
add_fingerprint(user)
+/obj/item/melee/classic_baton/telescopic/contractor_baton
+ name = "contractor baton"
+ desc = "A compact, specialised baton assigned to Syndicate contractors. Applies light electrical shocks to targets."
+ icon = 'icons/obj/items_and_weapons.dmi'
+ icon_state = "contractor_baton_0"
+ lefthand_file = 'icons/mob/inhands/weapons/melee_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/weapons/melee_righthand.dmi'
+ item_state = null
+ slot_flags = ITEM_SLOT_BELT
+ w_class = WEIGHT_CLASS_SMALL
+ item_flags = NONE
+ force = 5
+
+ cooldown = 30
+ stun_time_carbon = 85
+ affect_silicon = TRUE
+ on_sound = 'sound/weapons/contractorbatonextend.ogg'
+ on_stun_sound = 'sound/effects/contractorbatonhit.ogg'
+ stun_animation = TRUE
+
+ on_icon_state = "contractor_baton_1"
+ off_icon_state = "contractor_baton_0"
+ on_item_state = "contractor_baton"
+ force_on = 16
+ force_off = 5
+ weight_class_on = WEIGHT_CLASS_NORMAL
+
+/obj/item/melee/classic_baton/telescopic/contractor_baton/get_wait_description()
+ return "The baton is still charging!"
+
+/obj/item/melee/classic_baton/telescopic/contractor_baton/additional_effects_carbon(mob/living/target, mob/living/user)
+ target.Jitter(20)
+ target.stuttering += 20
+
/obj/item/melee/supermatter_sword
name = "supermatter sword"
desc = "In a station full of bad ideas, this might just be the worst."
@@ -444,13 +587,13 @@
add_overlay(sausage)
/obj/item/melee/roastingstick/proc/extend(user)
- to_chat(user, "You extend [src].")
+ to_chat(user, "You extend [src].")
icon_state = "roastingstick_1"
item_state = "nullrod"
w_class = WEIGHT_CLASS_BULKY
/obj/item/melee/roastingstick/proc/retract(user)
- to_chat(user, "You collapse [src].")
+ to_chat(user, "You collapse [src].")
icon_state = "roastingstick_0"
item_state = null
w_class = WEIGHT_CLASS_SMALL
diff --git a/code/game/objects/items/plushes.dm b/code/game/objects/items/plushes.dm
index 421fe1797d5..36d029beec1 100644
--- a/code/game/objects/items/plushes.dm
+++ b/code/game/objects/items/plushes.dm
@@ -465,7 +465,6 @@
desc = "A small stuffed doll of the elder goddess Nar'Sie. Who thought this was a good children's toy?"
icon_state = "narplush"
var/clashing
- var/is_invoker = TRUE
gender = FEMALE //it's canon if the toy is
/obj/item/toy/plush/narplush/Moved()
@@ -474,10 +473,6 @@
if(P && istype(P.loc, /turf/open) && !P.clash_target && !clashing)
P.clash_of_the_plushies(src)
-/obj/item/toy/plush/narplush/hugbox
- desc = "A small stuffed doll of the elder goddess Nar'Sie. Who thought this was a good children's toy? It looks sad."
- is_invoker = FALSE
-
/obj/item/toy/plush/lizardplushie
name = "lizard plushie"
desc = "An adorable stuffed toy that resembles a lizardperson."
diff --git a/code/game/objects/items/robot/robot_items.dm b/code/game/objects/items/robot/robot_items.dm
index d888aa0ce53..9fada67a0c1 100644
--- a/code/game/objects/items/robot/robot_items.dm
+++ b/code/game/objects/items/robot/robot_items.dm
@@ -295,7 +295,7 @@
if(iscyborg(user))
var/mob/living/silicon/robot/R = user
if(!R.cell || R.cell.charge < 1200)
- to_chat(user, "You don't have enough charge to do this!")
+ to_chat(user, "You don't have enough charge to do this!")
return
R.cell.charge -= 1000
if(R.emagged)
diff --git a/code/game/objects/items/sharpener.dm b/code/game/objects/items/sharpener.dm
index b90a5b155a6..c221608024a 100644
--- a/code/game/objects/items/sharpener.dm
+++ b/code/game/objects/items/sharpener.dm
@@ -18,7 +18,7 @@
if(I.force >= max || I.throwforce >= max)//no esword sharpening
to_chat(user, "[I] is much too powerful to sharpen further!")
return
- if(requires_sharpness && !I.sharpness)
+ if(requires_sharpness && !I.is_sharp())
to_chat(user, "You can only sharpen items that are already sharp, such as knives!")
return
if(istype(I, /obj/item/melee/transforming/energy))
diff --git a/code/game/objects/items/stacks/bscrystal.dm b/code/game/objects/items/stacks/bscrystal.dm
index acfc6100d22..7df139201a1 100644
--- a/code/game/objects/items/stacks/bscrystal.dm
+++ b/code/game/objects/items/stacks/bscrystal.dm
@@ -4,6 +4,7 @@
desc = "A glowing bluespace crystal, not much is known about how they work. It looks very delicate."
icon = 'icons/obj/telescience.dmi'
icon_state = "bluespace_crystal"
+ item_color = "cosmos"
singular_name = "bluespace crystal"
w_class = WEIGHT_CLASS_TINY
materials = list(MAT_BLUESPACE=MINERAL_MATERIAL_AMOUNT)
diff --git a/code/game/objects/items/stacks/medical.dm b/code/game/objects/items/stacks/medical.dm
index 782f795e45e..9e777db3f4a 100644
--- a/code/game/objects/items/stacks/medical.dm
+++ b/code/game/objects/items/stacks/medical.dm
@@ -41,9 +41,9 @@
if(affecting.heal_damage(brute, burn))
C.update_damage_overlays()
return TRUE
- to_chat(user, "[C]'s [affecting.name] can not be healed with \the [src].")
+ to_chat(user, "[C]'s [affecting.name] can not be healed with \the [src]!")
return
- to_chat(user, "\The [src] won't work on a robotic limb!")
+ to_chat(user, "\The [src] won't work on a robotic limb!")
/obj/item/stack/medical/bruise_pack
name = "bruise pack"
@@ -58,12 +58,12 @@
/obj/item/stack/medical/bruise_pack/heal(mob/living/M, mob/user)
if(M.stat == DEAD)
- to_chat(user, " [M] is dead. You can not help [M.p_them()]!")
+ to_chat(user, " [M] is dead! You can not help [M.p_them()].")
return
if(isanimal(M))
var/mob/living/simple_animal/critter = M
if (!(critter.healable))
- to_chat(user, " You cannot use \the [src] on [M]!")
+ to_chat(user, " You cannot use \the [src] on [M]!")
return FALSE
else if (critter.health == critter.maxHealth)
to_chat(user, " [M] is at full health.")
@@ -73,7 +73,7 @@
return TRUE
if(iscarbon(M))
return heal_carbon(M, user, heal_brute, 0)
- to_chat(user, "You can't heal [M] with the \the [src]!")
+ to_chat(user, "You can't heal [M] with the \the [src]!")
/obj/item/stack/medical/bruise_pack/suicide_act(mob/user)
user.visible_message("[user] is bludgeoning [user.p_them()]self with [src]! It looks like [user.p_theyre()] trying to commit suicide!")
@@ -96,7 +96,7 @@
H.suppress_bloodloss(stop_bleeding)
to_chat(user, "You stop the bleeding of [M]!")
return TRUE
- to_chat(user, "You can not use \the [src] on [M]!")
+ to_chat(user, "You can not use \the [src] on [M]!")
/obj/item/stack/medical/gauze/attackby(obj/item/I, mob/user, params)
if(I.tool_behaviour == TOOL_WIRECUTTER || I.is_sharp())
@@ -140,11 +140,11 @@
/obj/item/stack/medical/ointment/heal(mob/living/M, mob/user)
if(M.stat == DEAD)
- to_chat(user, " [M] is dead. You can not help [M.p_them()]!")
+ to_chat(user, " [M] is dead! You can not help [M.p_them()].")
return
if(iscarbon(M))
return heal_carbon(M, user, 0, heal_burn)
- to_chat(user, "You can't heal [M] with the \the [src]!")
+ to_chat(user, "You can't heal [M] with the \the [src]!")
/obj/item/stack/medical/ointment/suicide_act(mob/living/user)
user.visible_message("[user] is squeezing \the [src] into [user.p_their()] mouth! [user.p_do(TRUE)]n't [user.p_they()] know that stuff is toxic?")
diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm
index ee100ad42cc..170096e0d12 100644
--- a/code/game/objects/items/stacks/sheets/sheet_types.dm
+++ b/code/game/objects/items/stacks/sheets/sheet_types.dm
@@ -271,6 +271,7 @@ GLOBAL_LIST_INIT(bamboo_recipes, list ( \
* Cloth
*/
GLOBAL_LIST_INIT(cloth_recipes, list ( \
+ new/datum/stack_recipe("white jumpskirt", /obj/item/clothing/under/skirt/color/white, 3), /*Ladies first*/ \
new/datum/stack_recipe("white jumpsuit", /obj/item/clothing/under/color/white, 3), \
new/datum/stack_recipe("white shoes", /obj/item/clothing/shoes/sneakers/white, 2), \
new/datum/stack_recipe("white scarf", /obj/item/clothing/neck/scarf, 1), \
@@ -355,20 +356,53 @@ GLOBAL_LIST_INIT(cloth_recipes, list ( \
/*
* Cardboard
*/
-GLOBAL_LIST_INIT(cardboard_recipes, list ( \
- new/datum/stack_recipe("box", /obj/item/storage/box), \
- new/datum/stack_recipe("light tubes", /obj/item/storage/box/lights/tubes), \
- new/datum/stack_recipe("light bulbs", /obj/item/storage/box/lights/bulbs), \
- new/datum/stack_recipe("mouse traps", /obj/item/storage/box/mousetraps), \
- new/datum/stack_recipe("cardborg suit", /obj/item/clothing/suit/cardborg, 3), \
- new/datum/stack_recipe("cardborg helmet", /obj/item/clothing/head/cardborg), \
- new/datum/stack_recipe("pizza box", /obj/item/pizzabox), \
- new/datum/stack_recipe("donut box", /obj/item/storage/fancy/donut_box), \
- new/datum/stack_recipe("egg box", /obj/item/storage/fancy/egg_box), \
- new/datum/stack_recipe("candle box", /obj/item/storage/fancy/candle_box), \
- new/datum/stack_recipe("folder", /obj/item/folder), \
- new/datum/stack_recipe("large box", /obj/structure/closet/cardboard, 4), \
- new/datum/stack_recipe("cardboard cutout", /obj/item/cardboard_cutout, 5), \
+GLOBAL_LIST_INIT(cardboard_recipes, list ( \
+ new/datum/stack_recipe("box", /obj/item/storage/box), \
+ new/datum/stack_recipe("cardborg suit", /obj/item/clothing/suit/cardborg, 3), \
+ new/datum/stack_recipe("cardborg helmet", /obj/item/clothing/head/cardborg), \
+ new/datum/stack_recipe("large box", /obj/structure/closet/cardboard, 4, one_per_turf = TRUE, on_floor = TRUE), \
+ new/datum/stack_recipe("cardboard cutout", /obj/item/cardboard_cutout, 5), \
+ null, \
+
+ new/datum/stack_recipe("pizza box", /obj/item/pizzabox), \
+ new/datum/stack_recipe("folder", /obj/item/folder), \
+ null, \
+ //TO-DO: Find a proper way to just change the illustration on the box. Code isn't the issue, input is.
+ new/datum/stack_recipe_list("fancy boxes", list(
+ new /datum/stack_recipe("donut box", /obj/item/storage/fancy/donut_box), \
+ new /datum/stack_recipe("egg box", /obj/item/storage/fancy/egg_box), \
+ new /datum/stack_recipe("donk-pockets box", /obj/item/storage/box/donkpockets), \
+ new /datum/stack_recipe("monkey cube box", /obj/item/storage/box/monkeycubes), \
+ null, \
+
+ new /datum/stack_recipe("lethal ammo box", /obj/item/storage/box/lethalshot), \
+ new /datum/stack_recipe("rubber shot ammo box", /obj/item/storage/box/rubbershot), \
+ new /datum/stack_recipe("bean bag ammo box", /obj/item/storage/box/beanbag), \
+ new /datum/stack_recipe("flashbang box", /obj/item/storage/box/flashbangs), \
+ new /datum/stack_recipe("flashes box", /obj/item/storage/box/flashes), \
+ new /datum/stack_recipe("handcuffs box", /obj/item/storage/box/handcuffs), \
+ new /datum/stack_recipe("ID card box", /obj/item/storage/box/ids), \
+ new /datum/stack_recipe("PDA box", /obj/item/storage/box/PDAs), \
+ null, \
+
+ new /datum/stack_recipe("pillbottle box", /obj/item/storage/box/pillbottles), \
+ new /datum/stack_recipe("beaker box", /obj/item/storage/box/beakers), \
+ new /datum/stack_recipe("syringe box", /obj/item/storage/box/syringes), \
+ new /datum/stack_recipe("latex gloves box", /obj/item/storage/box/gloves), \
+ new /datum/stack_recipe("sterile masks box", /obj/item/storage/box/masks), \
+ new /datum/stack_recipe("body bag box", /obj/item/storage/box/bodybags), \
+ new /datum/stack_recipe("perscription glasses box", /obj/item/storage/box/rxglasses), \
+ null, \
+
+ new /datum/stack_recipe("disk box", /obj/item/storage/box/disks), \
+ new /datum/stack_recipe("light tubes box", /obj/item/storage/box/lights/tubes), \
+ new /datum/stack_recipe("light bulbs box", /obj/item/storage/box/lights/bulbs), \
+ new /datum/stack_recipe("mixed lights box", /obj/item/storage/box/lights/mixed), \
+ new /datum/stack_recipe("mouse traps box", /obj/item/storage/box/mousetraps), \
+ new /datum/stack_recipe("candle box", /obj/item/storage/fancy/candle_box)
+ )),
+
+ null, \
))
/obj/item/stack/sheet/cardboard //BubbleWrap //it's cardboard you fuck
diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm
index e06c8b15ba3..bb8bd32bb4f 100644
--- a/code/game/objects/items/stacks/stack.dm
+++ b/code/game/objects/items/stacks/stack.dm
@@ -29,7 +29,7 @@
/obj/item/stack/grind_requirements()
if(is_cyborg)
- to_chat(usr, "[src] is electronically synthesized in your chassis and can't be ground up!")
+ to_chat(usr, "[src] is electronically synthesized in your chassis and can't be ground up!")
return
return TRUE
@@ -355,6 +355,9 @@
. = ..()
/obj/item/stack/AltClick(mob/living/user)
+ . = ..()
+ if(isturf(loc)) // to prevent people that are alt clicking a tile to see its content from getting undesidered pop ups
+ return
if(!istype(user) || !user.canUseTopic(src, BE_CLOSE, ismonkey(user)))
return
if(is_cyborg)
diff --git a/code/game/objects/items/storage/backpack.dm b/code/game/objects/items/storage/backpack.dm
index 80d8a4dc02f..8a49a90a0c8 100644
--- a/code/game/objects/items/storage/backpack.dm
+++ b/code/game/objects/items/storage/backpack.dm
@@ -497,6 +497,31 @@
for(var/i in 1 to 9)
new /obj/item/ammo_box/magazine/smgm45(src)
+/obj/item/storage/backpack/duffelbag/syndie/ammo/dark_gygax
+ desc = "A large duffel bag, packed to the brim with various exosuit ammo."
+
+/obj/item/storage/backpack/duffelbag/syndie/ammo/dark_gygax/PopulateContents()
+ new /obj/item/mecha_ammo/incendiary(src)
+ new /obj/item/mecha_ammo/incendiary(src)
+ new /obj/item/mecha_ammo/incendiary(src)
+ new /obj/item/mecha_ammo/flashbang(src)
+ new /obj/item/mecha_ammo/flashbang(src)
+ new /obj/item/mecha_ammo/flashbang(src)
+
+/obj/item/storage/backpack/duffelbag/syndie/ammo/mauler
+ desc = "A large duffel bag, packed to the brim with various exosuit ammo."
+
+/obj/item/storage/backpack/duffelbag/syndie/ammo/mauler/PopulateContents()
+ new /obj/item/mecha_ammo/lmg(src)
+ new /obj/item/mecha_ammo/lmg(src)
+ new /obj/item/mecha_ammo/lmg(src)
+ new /obj/item/mecha_ammo/scattershot(src)
+ new /obj/item/mecha_ammo/scattershot(src)
+ new /obj/item/mecha_ammo/scattershot(src)
+ new /obj/item/mecha_ammo/missiles_he(src)
+ new /obj/item/mecha_ammo/missiles_he(src)
+ new /obj/item/mecha_ammo/missiles_he(src)
+
/obj/item/storage/backpack/duffelbag/syndie/c20rbundle
desc = "A large duffel bag containing a C-20r, some magazines, and a cheap looking suppressor."
diff --git a/code/game/objects/items/storage/bags.dm b/code/game/objects/items/storage/bags.dm
index c956f95240e..c6429076b4c 100644
--- a/code/game/objects/items/storage/bags.dm
+++ b/code/game/objects/items/storage/bags.dm
@@ -125,8 +125,9 @@
/obj/item/storage/bag/ore/dropped()
. = ..()
- UnregisterSignal(listeningTo, COMSIG_MOVABLE_MOVED)
- listeningTo = null
+ if(listeningTo)
+ UnregisterSignal(listeningTo, COMSIG_MOVABLE_MOVED)
+ listeningTo = null
/obj/item/storage/bag/ore/proc/Pickup_ores(mob/living/user)
var/show_message = FALSE
@@ -344,7 +345,7 @@
STR.max_combined_w_class = 200
STR.max_items = 50
STR.insert_preposition = "in"
- STR.set_holdable(list(/obj/item/reagent_containers/pill, /obj/item/reagent_containers/glass/beaker, /obj/item/reagent_containers/glass/bottle, /obj/item/reagent_containers/medspray, /obj/item/reagent_containers/syringe, /obj/item/reagent_containers/dropper))
+ STR.set_holdable(list(/obj/item/reagent_containers/pill, /obj/item/reagent_containers/glass/beaker, /obj/item/reagent_containers/glass/bottle, /obj/item/reagent_containers/medigel, /obj/item/reagent_containers/syringe, /obj/item/reagent_containers/dropper, /obj/item/reagent_containers/chem_pack))
/*
* Biowaste bag (mostly for xenobiologists)
@@ -365,3 +366,24 @@
STR.max_items = 25
STR.insert_preposition = "in"
STR.set_holdable(list(/obj/item/slime_extract, /obj/item/reagent_containers/syringe, /obj/item/reagent_containers/dropper, /obj/item/reagent_containers/glass/beaker, /obj/item/reagent_containers/glass/bottle, /obj/item/reagent_containers/blood, /obj/item/reagent_containers/hypospray/medipen, /obj/item/reagent_containers/food/snacks/deadmouse, /obj/item/reagent_containers/food/snacks/monkeycube))
+
+/*
+ * Construction bag (for engineering, holds stock parts and electronics)
+ */
+
+/obj/item/storage/bag/construction
+ name = "construction bag"
+ icon = 'icons/obj/tools.dmi'
+ icon_state = "construction_bag"
+ desc = "A bag for storing small construction components."
+ w_class = WEIGHT_CLASS_TINY
+ resistance_flags = FLAMMABLE
+
+/obj/item/storage/bag/construction/ComponentInitialize()
+ . = ..()
+ var/datum/component/storage/STR = GetComponent(/datum/component/storage)
+ STR.max_combined_w_class = 100
+ STR.max_items = 50
+ STR.max_w_class = WEIGHT_CLASS_SMALL
+ STR.insert_preposition = "in"
+ STR.set_holdable(list(/obj/item/stack/ore/bluespace_crystal, /obj/item/assembly, /obj/item/stock_parts, /obj/item/reagent_containers/glass/beaker, /obj/item/stack/cable_coil, /obj/item/circuitboard, /obj/item/electronics))
diff --git a/code/game/objects/items/storage/belt.dm b/code/game/objects/items/storage/belt.dm
index 0c933896a43..46cf069f06b 100644
--- a/code/game/objects/items/storage/belt.dm
+++ b/code/game/objects/items/storage/belt.dm
@@ -71,7 +71,7 @@
new /obj/item/crowbar/power(src)
new /obj/item/weldingtool/experimental(src)//This can be changed if this is too much
new /obj/item/multitool(src)
- new /obj/item/stack/cable_coil(src,30,pick("red","yellow","orange"))
+ new /obj/item/stack/cable_coil(src,MAXCOIL,pick("red","yellow","orange"))
new /obj/item/extinguisher/mini(src)
new /obj/item/analyzer(src)
//much roomier now that we've managed to remove two tools
@@ -83,7 +83,7 @@
new /obj/item/crowbar(src)
new /obj/item/wirecutters(src)
new /obj/item/multitool(src)
- new /obj/item/stack/cable_coil(src,30,pick("red","yellow","orange"))
+ new /obj/item/stack/cable_coil(src,MAXCOIL,pick("red","yellow","orange"))
/obj/item/storage/belt/utility/full/engi/PopulateContents()
new /obj/item/screwdriver(src)
@@ -92,7 +92,7 @@
new /obj/item/crowbar(src)
new /obj/item/wirecutters(src)
new /obj/item/multitool(src)
- new /obj/item/stack/cable_coil(src,30,pick("red","yellow","orange"))
+ new /obj/item/stack/cable_coil(src,MAXCOIL,pick("red","yellow","orange"))
/obj/item/storage/belt/utility/atmostech/PopulateContents()
@@ -111,7 +111,7 @@
new /obj/item/crowbar/brass(src)
new /obj/item/weldingtool/experimental/brass(src)
new /obj/item/multitool(src)
- new /obj/item/stack/cable_coil(src, 30, "yellow")
+ new /obj/item/stack/cable_coil(src, MAXCOIL, "yellow")
/obj/item/storage/belt/medical
name = "medical belt"
@@ -131,7 +131,7 @@
/obj/item/reagent_containers/glass/bottle,
/obj/item/reagent_containers/pill,
/obj/item/reagent_containers/syringe,
- /obj/item/reagent_containers/medspray,
+ /obj/item/reagent_containers/medigel,
/obj/item/lighter,
/obj/item/storage/fancy/cigarettes,
/obj/item/storage/pill_bottle,
@@ -407,7 +407,7 @@
new /obj/item/crowbar/abductor(src)
new /obj/item/wirecutters/abductor(src)
new /obj/item/multitool/abductor(src)
- new /obj/item/stack/cable_coil(src,30,"white")
+ new /obj/item/stack/cable_coil(src,MAXCOIL,"white")
/obj/item/storage/belt/military/army
name = "army belt"
@@ -667,7 +667,7 @@
user.put_in_hands(I)
update_icon()
else
- to_chat(user, "[src] is empty.")
+ to_chat(user, "[src] is empty!")
/obj/item/storage/belt/sabre/update_icon()
icon_state = "sheath"
diff --git a/code/game/objects/items/storage/book.dm b/code/game/objects/items/storage/book.dm
index 09f011ade95..d9c1f31c40d 100644
--- a/code/game/objects/items/storage/book.dm
+++ b/code/game/objects/items/storage/book.dm
@@ -202,11 +202,13 @@ GLOBAL_LIST_INIT(bibleitemstates, list("bible", "koran", "scrapbook", "burning",
SS.release_shades(user)
qdel(SS)
new /obj/item/nullrod/claymore(get_turf(sword))
- user.visible_message("[user] has purified the [sword]!")
+ user.visible_message("[user] has purified [sword]!")
qdel(sword)
else if(istype(A, /obj/item/soulstone) && !iscultist(user))
var/obj/item/soulstone/SS = A
+ if(SS.purified)
+ return
to_chat(user, "You begin to exorcise [SS].")
playsound(src,'sound/hallucinations/veryfar_noise.ogg',40,1)
if(do_after(user, 40, target = SS))
@@ -219,8 +221,8 @@ GLOBAL_LIST_INIT(bibleitemstates, list("bible", "koran", "scrapbook", "burning",
SS.icon_state = "purified_soulstone2"
for(var/mob/living/simple_animal/shade/EX in SS)
EX.icon_state = "ghost1"
- EX.name = "Purified [EX.name]"
- user.visible_message("[user] has purified the [SS]!")
+ EX.name = "Purified [initial(EX.name)]"
+ user.visible_message("[user] has purified [SS]!")
/obj/item/storage/book/bible/booze
desc = "To be applied to the head repeatedly."
diff --git a/code/game/objects/items/storage/boxes.dm b/code/game/objects/items/storage/boxes.dm
index b0850b2954e..dd1ad2cf0bd 100644
--- a/code/game/objects/items/storage/boxes.dm
+++ b/code/game/objects/items/storage/boxes.dm
@@ -246,13 +246,13 @@
new /obj/item/reagent_containers/glass/beaker/noreact(src)
new /obj/item/reagent_containers/glass/beaker/bluespace(src)
-/obj/item/storage/box/medsprays
- name = "box of medical sprayers"
- desc = "A box full of medical sprayers, with unscrewable caps and precision spray heads."
+/obj/item/storage/box/medigels
+ name = "box of medical gels"
+ desc = "A box full of medical gel applicators, with unscrewable caps and precision spray heads."
-/obj/item/storage/box/medsprays/PopulateContents()
+/obj/item/storage/box/medigels/PopulateContents()
for(var/i in 1 to 7)
- new /obj/item/reagent_containers/medspray( src )
+ new /obj/item/reagent_containers/medigel( src )
/obj/item/storage/box/injectors
name = "box of DNA injectors"
@@ -1072,3 +1072,19 @@
/obj/item/stock_parts/micro_laser/quadultra = 3,
/obj/item/stock_parts/matter_bin/bluespace = 3)
generate_items_inside(items_inside,src)
+
+/obj/item/storage/box/dishdrive
+ name = "DIY Dish Drive Kit"
+ desc = "Contains everything you need to build your own Dish Drive!"
+ custom_premium_price = 200
+
+/obj/item/storage/box/dishdrive/PopulateContents()
+ var/static/items_inside = list(
+ /obj/item/stack/sheet/metal/five = 1,
+ /obj/item/stack/cable_coil/five = 1,
+ /obj/item/circuitboard/machine/dish_drive = 1,
+ /obj/item/stack/sheet/glass = 1,
+ /obj/item/stock_parts/manipulator = 1,
+ /obj/item/stock_parts/matter_bin = 2,
+ /obj/item/screwdriver = 1)
+ generate_items_inside(items_inside,src)
\ No newline at end of file
diff --git a/code/game/objects/items/storage/firstaid.dm b/code/game/objects/items/storage/firstaid.dm
index 1212d32009a..08c3ab7ba56 100644
--- a/code/game/objects/items/storage/firstaid.dm
+++ b/code/game/objects/items/storage/firstaid.dm
@@ -92,8 +92,7 @@
if(empty)
return
var/static/items_inside = list(
- /obj/item/reagent_containers/syringe/charcoal = 4,
- /obj/item/storage/pill_bottle/charcoal = 2,
+ /obj/item/reagent_containers/pill/charcoal = 6,
/obj/item/healthanalyzer = 1)
generate_items_inside(items_inside,src)
diff --git a/code/game/objects/items/storage/secure.dm b/code/game/objects/items/storage/secure.dm
index 2e91c68050b..1f21436bc45 100644
--- a/code/game/objects/items/storage/secure.dm
+++ b/code/game/objects/items/storage/secure.dm
@@ -54,7 +54,7 @@
else
l_hacking = 0
else
- to_chat(user, "You must unscrew the service panel before you can pulse the wiring.")
+ to_chat(user, "You must unscrew the service panel before you can pulse the wiring!")
return
//At this point you have exhausted all the special things to do when locked
// ... but it's still locked.
diff --git a/code/game/objects/items/storage/toolbox.dm b/code/game/objects/items/storage/toolbox.dm
index 82bb42d97fd..5ee014306a0 100644
--- a/code/game/objects/items/storage/toolbox.dm
+++ b/code/game/objects/items/storage/toolbox.dm
@@ -131,12 +131,12 @@
new /obj/item/wirecutters(src)
new /obj/item/t_scanner(src)
new /obj/item/crowbar(src)
- new /obj/item/stack/cable_coil(src,30,pickedcolor)
- new /obj/item/stack/cable_coil(src,30,pickedcolor)
+ new /obj/item/stack/cable_coil(src,MAXCOIL,pickedcolor)
+ new /obj/item/stack/cable_coil(src,MAXCOIL,pickedcolor)
if(prob(5))
new /obj/item/clothing/gloves/color/yellow(src)
else
- new /obj/item/stack/cable_coil(src,30,pickedcolor)
+ new /obj/item/stack/cable_coil(src,MAXCOIL,pickedcolor)
/obj/item/storage/toolbox/syndicate
name = "suspicious looking toolbox"
@@ -170,7 +170,7 @@
new /obj/item/wrench(src)
new /obj/item/weldingtool(src)
new /obj/item/crowbar(src)
- new /obj/item/stack/cable_coil(src,30,pickedcolor)
+ new /obj/item/stack/cable_coil(src,MAXCOIL,pickedcolor)
new /obj/item/wirecutters(src)
new /obj/item/multitool(src)
diff --git a/code/game/objects/items/storage/uplink_kits.dm b/code/game/objects/items/storage/uplink_kits.dm
index 1df6d6ae1d2..4944125f28f 100644
--- a/code/game/objects/items/storage/uplink_kits.dm
+++ b/code/game/objects/items/storage/uplink_kits.dm
@@ -178,7 +178,7 @@
new /obj/item/storage/belt/fannypack/yellow(src) // 0 tc
new /obj/item/storage/box/syndie_kit/bee_grenades(src) // 15 tc
new /obj/item/reagent_containers/glass/bottle/beesease(src) // 10 tc?
- new /obj/item/melee/sabre/bee(src) //priceless
+ new /obj/item/melee/beesword(src) //priceless
if("mr_freeze")
new /obj/item/clothing/glasses/cold(src)
@@ -197,7 +197,7 @@
/obj/item/storage/box/syndicate/contract_kit
name = "Contract Kit"
- desc = "Supplied to Syndicate contractors in active mission areas."
+ desc = "Supplied to Syndicate contractors."
icon_state = "syndiebox"
illustration = "writing_syndie"
@@ -218,38 +218,41 @@
Syndicate space suit available to you on the uplink. We also provide your chameleon jumpsuit and mask, both of which can be changed
to any form you need for the moment. The cigarettes are a special blend - it'll heal your injuries slowly overtime.
- The three additional items, apart from the tablet and loadout box, have been randomly selected from what we had available. We hope
- they're useful to you for you mission.
+ Your standard issue contractor baton hits harder than the ones you might be used to, and likely be your go to weapon for kidnapping your
+ targets. The three additional items have been randomly selected from what we had available. We hope they're useful to you for your mission.
Using the tablet
- Open the Syndicate Contract Uplink program.
- - Assign yourself.
- Here, you can accept a contract, and redeem your TC payments from completed contracts.
- The payment number shown in brackets is the bonus you'll recieve when bringing your target alive. You recieve the
other number regardless of if they were alive or dead.
+ - Contracts are completed by bringing the target to designated dropoff, calling for extraction, and putting them
+ inside the pod.
Be careful when accepting a contract. While you'll be able to see the location of the dropoff point, cancelling will make it
unavailable to take on again.
- The tablet can be recharged at any cell charger.
+ The tablet can also be recharged at any cell charger.
Extracting
- Make sure both yourself and your target are at the dropoff.
- - Call the extraction. Stand back from the drop point - it'll be coming down hard.
+ - Call the extraction, and stand back from the drop point.
- If it fails, make sure your target is inside, and there's a free space for the pod to land.
- - Drag your target into the pod.
+ - Grab your target, and drag them into the pod.
Ransoms
We need your target for our own reasons, but we ransom them back to your mission area once their use is served. They will return back
- from where you sent them off from in several minutes time. Don't worry agent, we give you a cut of what we get paid. We pay this into whatever
- ID card you have equipped, on top of the TC payment we give.
"}
+ from where you sent them off from in several minutes time. Don't worry, we give you a cut of what we get paid. We pay this into whatever
+ ID card you have equipped, on top of the TC payment we give.
+
+ Good luck agent.
"}
return ..()
/obj/item/storage/box/syndicate/contractor_loadout/PopulateContents()
- new /obj/item/clothing/head/helmet/space/syndicate/contract/black/red(src)
- new /obj/item/clothing/suit/space/syndicate/contract/black/red(src)
+ new /obj/item/clothing/head/helmet/space/syndicate/contract(src)
+ new /obj/item/clothing/suit/space/syndicate/contract(src)
new /obj/item/clothing/under/chameleon(src)
new /obj/item/clothing/mask/chameleon(src)
new /obj/item/card/id/syndicate(src)
@@ -259,6 +262,7 @@
/obj/item/storage/box/syndicate/contract_kit/PopulateContents()
new /obj/item/modular_computer/tablet/syndicate_contract_uplink/preset/uplink(src)
new /obj/item/storage/box/syndicate/contractor_loadout(src)
+ new /obj/item/melee/classic_baton/telescopic/contractor_baton(src)
// All about 4 TC or less - some nukeops only items, but fit nicely to the theme.
var/list/item_list = list(
diff --git a/code/game/objects/items/twohanded.dm b/code/game/objects/items/twohanded.dm
index 0d4d4dbe844..71ea917e145 100644
--- a/code/game/objects/items/twohanded.dm
+++ b/code/game/objects/items/twohanded.dm
@@ -550,6 +550,8 @@
/obj/item/twohanded/spear/explosive/afterattack(atom/movable/AM, mob/user, proximity)
. = ..()
+ if(!proximity)
+ return
if(wielded)
user.say("[war_cry]", forced="spear warcry")
explosive.forceMove(AM)
@@ -718,7 +720,7 @@
/obj/item/twohanded/pitchfork/demonic/attack(mob/target, mob/living/carbon/human/user)
if(user.mind && user.owns_soul() && !is_devil(user))
- to_chat(user, "[src] burns in your hands.")
+ to_chat(user, "[src] burns in your hands.")
user.apply_damage(rand(force/2, force), BURN, pick(BODY_ZONE_L_ARM, BODY_ZONE_R_ARM))
..()
diff --git a/code/game/objects/obj_defense.dm b/code/game/objects/obj_defense.dm
index 82033e4fce8..ec32da433ca 100644
--- a/code/game/objects/obj_defense.dm
+++ b/code/game/objects/obj_defense.dm
@@ -32,7 +32,7 @@
if(damage_flag)
armor_protection = armor.getRating(damage_flag)
if(armor_protection) //Only apply weak-against-armor/hollowpoint effects if there actually IS armor.
- armor_protection = CLAMP(armor_protection - armour_penetration, 0, 100)
+ armor_protection = CLAMP(armor_protection - armour_penetration, min(armor_protection, 0), 100)
return round(damage_amount * (100 - armor_protection)*0.01, DAMAGE_PRECISION)
//the sound played when the obj is damaged.
diff --git a/code/game/objects/structures/barsigns.dm b/code/game/objects/structures/barsigns.dm
index c15bea20486..20241df7d5b 100644
--- a/code/game/objects/structures/barsigns.dm
+++ b/code/game/objects/structures/barsigns.dm
@@ -69,7 +69,7 @@
to_chat(user, "Access denied.")
return
if(broken)
- to_chat(user, "The controls seem unresponsive.")
+ to_chat(user, "The controls seem unresponsive.")
return
pick_sign(user)
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 a062be09642..a55b80cc6ce 100644
--- a/code/game/objects/structures/crates_lockers/closets/secure/cargo.dm
+++ b/code/game/objects/structures/crates_lockers/closets/secure/cargo.dm
@@ -8,6 +8,7 @@
new /obj/item/clothing/neck/cloak/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 47d7c8e90ae..a4d6770d8a0 100644
--- a/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm
+++ b/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm
@@ -7,6 +7,7 @@
..()
new /obj/item/clothing/neck/cloak/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/hardhat/weldhat/white(src)
new /obj/item/clothing/head/welding(src)
@@ -75,6 +76,7 @@
new /obj/item/clothing/mask/gas(src)
new /obj/item/clothing/glasses/meson/engine(src)
new /obj/item/storage/box/emptysandbags(src)
+ new /obj/item/storage/bag/construction(src)
/obj/structure/closet/secure_closet/atmospherics
diff --git a/code/game/objects/structures/crates_lockers/closets/secure/freezer.dm b/code/game/objects/structures/crates_lockers/closets/secure/freezer.dm
index 612381fd7c2..6607a0e8ea9 100644
--- a/code/game/objects/structures/crates_lockers/closets/secure/freezer.dm
+++ b/code/game/objects/structures/crates_lockers/closets/secure/freezer.dm
@@ -49,6 +49,13 @@
req_access = null
locked = FALSE
+/obj/structure/closet/secure_closet/freezer/gulag_fridge
+ name = "refrigerator"
+
+/obj/structure/closet/secure_closet/freezer/gulag_fridge/PopulateContents()
+ ..()
+ for(var/i in 1 to 3)
+ new /obj/item/reagent_containers/food/drinks/beer/light(src)
/obj/structure/closet/secure_closet/freezer/fridge
name = "refrigerator"
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 12699c37474..7d7824f10dc 100644
--- a/code/game/objects/structures/crates_lockers/closets/secure/medical.dm
+++ b/code/game/objects/structures/crates_lockers/closets/secure/medical.dm
@@ -57,6 +57,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)
@@ -95,8 +96,8 @@
..()
new /obj/item/storage/box/pillbottles(src)
new /obj/item/storage/box/pillbottles(src)
- new /obj/item/storage/box/medsprays(src)
- new /obj/item/storage/box/medsprays(src)
+ new /obj/item/storage/box/medigels(src)
+ new /obj/item/storage/box/medigels(src)
/obj/structure/closet/secure_closet/chemical/heisenberg //contains one of each beaker, syringe etc.
name = "advanced chemical closet"
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 eb10b97bc38..54226a39ee0 100755
--- a/code/game/objects/structures/crates_lockers/closets/secure/scientist.dm
+++ b/code/game/objects/structures/crates_lockers/closets/secure/scientist.dm
@@ -10,8 +10,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 9cf6d015a22..43bef5d92a9 100755
--- a/code/game/objects/structures/crates_lockers/closets/secure/security.dm
+++ b/code/game/objects/structures/crates_lockers/closets/secure/security.dm
@@ -14,6 +14,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)
@@ -43,6 +44,7 @@
..()
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/cartridge/hop(src)
new /obj/item/radio/headset/heads/hop(src)
@@ -75,7 +77,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)
@@ -108,6 +112,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)
@@ -177,10 +182,12 @@
/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/suit/det_suit/noir(src)
@@ -221,6 +228,7 @@
/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
@@ -310,3 +318,17 @@
..()
for(var/i in 1 to 3)
new /obj/item/storage/box/lethalshot(src)
+
+/obj/structure/closet/secure_closet/labor_camp_security
+ name = "labor camp security locker"
+ req_access = list(ACCESS_SECURITY)
+ icon_state = "sec"
+
+/obj/structure/closet/secure_closet/labor_camp_security/PopulateContents()
+ ..()
+ new /obj/item/clothing/suit/armor/vest(src)
+ new /obj/item/clothing/head/helmet/sec(src)
+ new /obj/item/clothing/under/rank/security(src)
+ new /obj/item/clothing/under/rank/security/skirt(src)
+ new /obj/item/clothing/glasses/hud/security/sunglasses(src)
+ new /obj/item/flashlight/seclite(src)
diff --git a/code/game/objects/structures/crates_lockers/closets/wardrobe.dm b/code/game/objects/structures/crates_lockers/closets/wardrobe.dm
index 7717ee539f1..897f4958eca 100644
--- a/code/game/objects/structures/crates_lockers/closets/wardrobe.dm
+++ b/code/game/objects/structures/crates_lockers/closets/wardrobe.dm
@@ -7,6 +7,8 @@
..()
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
@@ -18,6 +20,8 @@
/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
@@ -29,6 +33,8 @@
/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))
@@ -53,6 +59,8 @@
/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)
@@ -68,6 +76,8 @@
/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
@@ -80,6 +90,8 @@
/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)
@@ -94,6 +106,8 @@
/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)
@@ -121,6 +135,8 @@
/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)
@@ -152,16 +168,27 @@
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/displaycase.dm b/code/game/objects/structures/displaycase.dm
index 486bacd38a9..528bc39efd5 100644
--- a/code/game/objects/structures/displaycase.dm
+++ b/code/game/objects/structures/displaycase.dm
@@ -267,33 +267,33 @@
is_locked = !is_locked
to_chat(user, "You [!is_locked ? "un" : ""]lock the case.")
else
- to_chat(user, "The lock is stuck shut!")
+ to_chat(user, "The lock is stuck shut!")
return
if(is_locked)
- to_chat(user, "The case is shut tight with an old fashioned physical lock. Maybe you should ask the curator for the key?")
+ to_chat(user, "The case is shut tight with an old fashioned physical lock. Maybe you should ask the curator for the key?")
return
if(!added_roundstart)
- to_chat(user, "You've already put something new in this case.")
+ to_chat(user, "You've already put something new in this case!")
return
if(is_type_in_typecache(W, GLOB.blacklisted_cargo_types))
- to_chat(user, "The case rejects the [W].")
+ to_chat(user, "The case rejects the [W]!")
return
for(var/a in W.GetAllContents())
if(is_type_in_typecache(a, GLOB.blacklisted_cargo_types))
- to_chat(user, "The case rejects the [W].")
+ to_chat(user, "The case rejects the [W]!")
return
if(user.transferItemToLoc(W, src))
if(showpiece)
- to_chat(user, "You press a button, and [showpiece] descends into the floor of the case.")
+ to_chat(user, "You press a button, and [showpiece] descends into the floor of the case.")
QDEL_NULL(showpiece)
- to_chat(user, "You insert [W] into the case.")
+ to_chat(user, "You insert [W] into the case.")
showpiece = W
added_roundstart = FALSE
update_icon()
@@ -306,9 +306,9 @@
if(chosen_plaque)
if(user.Adjacent(src))
trophy_message = chosen_plaque
- to_chat(user, "You set the plaque's text.")
+ to_chat(user, "You set the plaque's text.")
else
- to_chat(user, "You are too far to set the plaque's text.")
+ to_chat(user, "You are too far to set the plaque's text!")
SSpersistence.SaveTrophy(src)
return TRUE
diff --git a/code/game/objects/structures/fence.dm b/code/game/objects/structures/fence.dm
index cf0a02e949d..195f5ee3688 100644
--- a/code/game/objects/structures/fence.dm
+++ b/code/game/objects/structures/fence.dm
@@ -60,7 +60,7 @@
/obj/structure/fence/attackby(obj/item/W, mob/user)
if(W.tool_behaviour == TOOL_WIRECUTTER)
if(!cuttable)
- to_chat(user, "This section of the fence can't be cut.")
+ to_chat(user, "This section of the fence can't be cut!")
return
if(invulnerable)
to_chat(user, "This fence is too strong to cut through.")
diff --git a/code/game/objects/structures/fireaxe.dm b/code/game/objects/structures/fireaxe.dm
index f29c0899cf6..e8582cf3db0 100644
--- a/code/game/objects/structures/fireaxe.dm
+++ b/code/game/objects/structures/fireaxe.dm
@@ -166,7 +166,7 @@
add_overlay("glass_raised")
/obj/structure/fireaxecabinet/proc/toggle_lock(mob/user)
- to_chat(user, " Resetting circuitry...")
+ to_chat(user, " Resetting circuitry...")
playsound(src, 'sound/machines/locktoggle.ogg', 50, 1)
if(do_after(user, 20, target = src))
to_chat(user, "You [locked ? "disable" : "re-enable"] the locking modules.")
diff --git a/code/game/objects/structures/flora.dm b/code/game/objects/structures/flora.dm
index f786ed3074a..d3bca881865 100644
--- a/code/game/objects/structures/flora.dm
+++ b/code/game/objects/structures/flora.dm
@@ -14,7 +14,7 @@
/obj/structure/flora/tree/attackby(obj/item/W, mob/user, params)
if(log_amount && (!(flags_1 & NODECONSTRUCT_1)))
- if(W.sharpness && W.force > 0)
+ if(W.is_sharp() && W.force > 0)
if(W.hitsound)
playsound(get_turf(src), W.hitsound, 100, 0, 0)
user.visible_message("[user] begins to cut down [src] with [W].","You begin to cut down [src] with [W].", "You hear the sound of sawing.")
diff --git a/code/game/objects/structures/guillotine.dm b/code/game/objects/structures/guillotine.dm
index 7b482584a5a..09492117a4b 100644
--- a/code/game/objects/structures/guillotine.dm
+++ b/code/game/objects/structures/guillotine.dm
@@ -33,6 +33,19 @@
LAZYINITLIST(buckled_mobs)
. = ..()
+/obj/structure/guillotine/attackby(obj/item/I, mob/user)
+ if(istype(I, /obj/item/stack/sheet/plasteel))
+ to_chat(user, "You start repairing the guillotine with the plasteel.")
+ if(blade_sharpness<10)
+ if(do_after(user,100,target=user))
+ blade_sharpness = min(10,blade_sharpness+3)
+ I.use(1)
+ to_chat(user, "You repair the guillotine with the plasteel.")
+ else
+ to_chat(user, "You stop repairing the guillotine with the plasteel.")
+ else
+ to_chat(user, "The guillotine is already fully repaired!")
+
/obj/structure/guillotine/examine(mob/user)
. = ..()
diff --git a/code/game/objects/structures/kitchen_spike.dm b/code/game/objects/structures/kitchen_spike.dm
index e4573320785..23d96f9ed3a 100644
--- a/code/game/objects/structures/kitchen_spike.dm
+++ b/code/game/objects/structures/kitchen_spike.dm
@@ -52,7 +52,7 @@
/obj/structure/kitchenspike/crowbar_act(mob/living/user, obj/item/I)
if(has_buckled_mobs())
- to_chat(user, "You can't do that while something's on the spike!")
+ to_chat(user, "You can't do that while something's on the spike!")
return TRUE
if(I.use_tool(src, user, 20, volume=100))
diff --git a/code/game/objects/structures/watercloset.dm b/code/game/objects/structures/watercloset.dm
index 7ef3817db88..c10f42cc15c 100644
--- a/code/game/objects/structures/watercloset.dm
+++ b/code/game/objects/structures/watercloset.dm
@@ -295,7 +295,7 @@
return
if(istype(O, /obj/item/mop))
- O.reagents.add_reagent("[dispensedreagent]", 5)
+ O.reagents.add_reagent(dispensedreagent, 5)
to_chat(user, "You wet [O] in [src].")
playsound(loc, 'sound/effects/slosh.ogg', 25, 1)
return
diff --git a/code/game/turfs/simulated/wall/mineral_walls.dm b/code/game/turfs/simulated/wall/mineral_walls.dm
index 333146a5462..0d269bce75d 100644
--- a/code/game/turfs/simulated/wall/mineral_walls.dm
+++ b/code/game/turfs/simulated/wall/mineral_walls.dm
@@ -133,7 +133,7 @@
canSmoothWith = list(/turf/closed/wall/mineral/wood, /obj/structure/falsewall/wood, /turf/closed/wall/mineral/wood/nonmetal)
/turf/closed/wall/mineral/wood/attackby(obj/item/W, mob/user)
- if(W.sharpness && W.force)
+ if(W.is_sharp() && W.force)
var/duration = (48/W.force) * 2 //In seconds, for now.
if(istype(W, /obj/item/hatchet) || istype(W, /obj/item/twohanded/fireaxe))
duration /= 4 //Much better with hatchets and axes.
diff --git a/code/game/turfs/space/space.dm b/code/game/turfs/space/space.dm
index 3e2f90c7c94..c2fec73e42a 100644
--- a/code/game/turfs/space/space.dm
+++ b/code/game/turfs/space/space.dm
@@ -26,6 +26,8 @@
/turf/open/space/Initialize()
icon_state = SPACE_ICON_STATE
air = space_gas
+ vis_contents.Cut() //removes inherited overlays
+ visibilityChanged()
if(flags_1 & INITIALIZED_1)
stack_trace("Warning: [src]([type]) initialized multiple times!")
diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm
index 22c1ab84e3e..f83d44977d6 100755
--- a/code/game/turfs/turf.dm
+++ b/code/game/turfs/turf.dm
@@ -536,9 +536,11 @@
/turf/AllowDrop()
return TRUE
-/turf/proc/add_vomit_floor(mob/living/carbon/M, toxvomit = NONE)
+/turf/proc/add_vomit_floor(mob/living/M, toxvomit = NONE)
+
var/obj/effect/decal/cleanable/vomit/V = new /obj/effect/decal/cleanable/vomit(src, M.get_static_viruses())
- // If the vomit combined, apply toxicity and reagents to the old vomit
+
+ //if the vomit combined, apply toxicity and reagents to the old vomit
if (QDELETED(V))
V = locate() in src
if(!V)
@@ -546,10 +548,12 @@
// Make toxins and blazaam vomit look different
if(toxvomit == VOMIT_PURPLE)
V.icon_state = "vomitpurp_[pick(1,4)]"
- else if(toxvomit == VOMIT_TOXIC)
+ else if (toxvomit == VOMIT_TOXIC)
V.icon_state = "vomittox_[pick(1,4)]"
- if(M.reagents)
- clear_reagents_to_vomit_pool(M,V)
+ if (iscarbon(M))
+ var/mob/living/carbon/C = M
+ if(C.reagents)
+ clear_reagents_to_vomit_pool(C,V)
/proc/clear_reagents_to_vomit_pool(mob/living/carbon/M, obj/effect/decal/cleanable/vomit/V)
M.reagents.trans_to(V, M.reagents.total_volume / 10, transfered_by = M)
diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm
index fc932c32312..d078a4f5ec6 100644
--- a/code/modules/admin/admin.dm
+++ b/code/modules/admin/admin.dm
@@ -510,7 +510,7 @@
else
message_admins("[key_name(usr)] set the admin notice.")
log_admin("[key_name(usr)] set the admin notice:\n[new_admin_notice]")
- to_chat(world, "Admin Notice:\n \t [new_admin_notice]")
+ to_chat(world, "Admin Notice:\n \t [new_admin_notice]")
SSblackbox.record_feedback("tally", "admin_verb", 1, "Set Admin Notice") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
GLOB.admin_notice = new_admin_notice
return
diff --git a/code/modules/admin/admin_ranks.dm b/code/modules/admin/admin_ranks.dm
index 7433124e875..1cecaf782c6 100644
--- a/code/modules/admin/admin_ranks.dm
+++ b/code/modules/admin/admin_ranks.dm
@@ -153,7 +153,7 @@ GLOBAL_PROTECT(protected_ranks)
if(!no_update)
sync_ranks_with_db()
else
- var/datum/DBQuery/query_load_admin_ranks = SSdbcore.NewQuery("SELECT rank, flags, exclude_flags, can_edit_flags FROM [format_table_name("admin_ranks")]")
+ var/datum/DBQuery/query_load_admin_ranks = SSdbcore.NewQuery("SELECT `rank`, flags, exclude_flags, can_edit_flags FROM [format_table_name("admin_ranks")]")
if(!query_load_admin_ranks.Execute())
message_admins("Error loading admin ranks from database. Loading from backup.")
log_sql("Error loading admin ranks from database. Loading from backup.")
@@ -232,7 +232,7 @@ GLOBAL_PROTECT(protected_ranks)
while(admins_regex.Find(admins_text))
new /datum/admins(rank_names[admins_regex.group[2]], ckey(admins_regex.group[1]), FALSE, TRUE)
if(!CONFIG_GET(flag/admin_legacy_system) || dbfail)
- var/datum/DBQuery/query_load_admins = SSdbcore.NewQuery("SELECT ckey, rank FROM [format_table_name("admin")] ORDER BY rank")
+ var/datum/DBQuery/query_load_admins = SSdbcore.NewQuery("SELECT ckey, `rank` FROM [format_table_name("admin")] ORDER BY `rank`")
if(!query_load_admins.Execute())
message_admins("Error loading admins from database. Loading from backup.")
log_sql("Error loading admins from database. Loading from backup.")
diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm
index f84d3667b9f..8d0021e9c66 100644
--- a/code/modules/admin/admin_verbs.dm
+++ b/code/modules/admin/admin_verbs.dm
@@ -72,6 +72,7 @@ GLOBAL_PROTECT(admin_verbs_admin)
/client/proc/resetasaycolor,
/client/proc/toggleadminhelpsound,
/client/proc/respawn_character,
+ /client/proc/discord_id_manipulation,
/datum/admins/proc/open_borgopanel
)
GLOBAL_LIST_INIT(admin_verbs_ban, list(/client/proc/unban_panel, /client/proc/ban_panel, /client/proc/stickybanpanel))
diff --git a/code/modules/admin/chat_commands.dm b/code/modules/admin/chat_commands.dm
index b222d0d8a60..e66459e951a 100644
--- a/code/modules/admin/chat_commands.dm
+++ b/code/modules/admin/chat_commands.dm
@@ -75,12 +75,12 @@
GLOBAL_LIST(round_end_notifiees)
-/datum/tgs_chat_command/notify
- name = "notify"
+/datum/tgs_chat_command/endnotify
+ name = "endnotify"
help_text = "Pings the invoker when the round ends"
admin_only = TRUE
-/datum/tgs_chat_command/notify/Run(datum/tgs_chat_user/sender, params)
+/datum/tgs_chat_command/endnotify/Run(datum/tgs_chat_user/sender, params)
if(!SSticker.IsRoundInProgress() && SSticker.HasRoundStarted())
return "[sender.mention], the round has already ended!"
LAZYINITLIST(GLOB.round_end_notifiees)
diff --git a/code/modules/admin/check_antagonists.dm b/code/modules/admin/check_antagonists.dm
index eaf14359ecd..fc7bc11463b 100644
--- a/code/modules/admin/check_antagonists.dm
+++ b/code/modules/admin/check_antagonists.dm
@@ -165,6 +165,8 @@
dat += "If limits past: [SSticker.mode.round_ends_with_antag_death ? "End The Round" : "Continue As Extended"]
"
dat += "End Round Now
"
dat += "[SSticker.delay_end ? "End Round Normally" : "Delay Round End"]
"
+ dat += "Enable/Disable CTF
"
+ dat += "Reboot World
"
dat += "Check Teams"
var/connected_players = GLOB.clients.len
var/lobby_players = 0
diff --git a/code/modules/admin/permissionedit.dm b/code/modules/admin/permissionedit.dm
index c091587d9ba..0c46d543a6a 100644
--- a/code/modules/admin/permissionedit.dm
+++ b/code/modules/admin/permissionedit.dm
@@ -59,7 +59,7 @@
qdel(query_search_admin_logs)
if(action == 2)
output += "Admin ckeys with invalid ranks
"
- var/datum/DBQuery/query_check_admin_errors = SSdbcore.NewQuery("SELECT IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE [format_table_name("player")].ckey = [format_table_name("admin")].ckey), ckey), [format_table_name("admin")].rank FROM [format_table_name("admin")] LEFT JOIN [format_table_name("admin_ranks")] ON [format_table_name("admin_ranks")].rank = [format_table_name("admin")].rank WHERE [format_table_name("admin_ranks")].rank IS NULL")
+ var/datum/DBQuery/query_check_admin_errors = SSdbcore.NewQuery("SELECT IFNULL((SELECT byond_key FROM [format_table_name("player")] WHERE [format_table_name("player")].ckey = [format_table_name("admin")].ckey), ckey), [format_table_name("admin")].`rank` FROM [format_table_name("admin")] LEFT JOIN [format_table_name("admin_ranks")] ON [format_table_name("admin_ranks")].`rank` = [format_table_name("admin")].`rank` WHERE [format_table_name("admin_ranks")].`rank` IS NULL")
if(!query_check_admin_errors.warn_execute())
qdel(query_check_admin_errors)
return
@@ -70,7 +70,7 @@
output += "
"
qdel(query_check_admin_errors)
output += "Unused ranks
"
- var/datum/DBQuery/query_check_unused_rank = SSdbcore.NewQuery("SELECT [format_table_name("admin_ranks")].rank, flags, exclude_flags, can_edit_flags FROM [format_table_name("admin_ranks")] LEFT JOIN [format_table_name("admin")] ON [format_table_name("admin")].rank = [format_table_name("admin_ranks")].rank WHERE [format_table_name("admin")].rank IS NULL")
+ var/datum/DBQuery/query_check_unused_rank = SSdbcore.NewQuery("SELECT [format_table_name("admin_ranks")].`rank`, flags, exclude_flags, can_edit_flags FROM [format_table_name("admin_ranks")] LEFT JOIN [format_table_name("admin")] ON [format_table_name("admin")].`rank` = [format_table_name("admin_ranks")].`rank` WHERE [format_table_name("admin")].`rank` IS NULL")
if(!query_check_unused_rank.warn_execute())
qdel(query_check_unused_rank)
return
@@ -221,7 +221,7 @@
to_chat(usr, "[admin_key] already listed in admin database. Check the Management tab if they don't appear in the list of admins.")
return FALSE
qdel(query_admin_in_db)
- var/datum/DBQuery/query_add_admin = SSdbcore.NewQuery("INSERT INTO [format_table_name("admin")] (ckey, rank) VALUES ('[.]', 'NEW ADMIN')")
+ var/datum/DBQuery/query_add_admin = SSdbcore.NewQuery("INSERT INTO [format_table_name("admin")] (ckey, `rank`) VALUES ('[.]', 'NEW ADMIN')")
if(!query_add_admin.warn_execute())
qdel(query_add_admin)
return FALSE
@@ -303,7 +303,7 @@
new_rank = sanitizeSQL(new_rank)
//if a player was tempminned before having a permanent change made to their rank they won't yet be in the db
var/old_rank
- var/datum/DBQuery/query_admin_in_db = SSdbcore.NewQuery("SELECT rank FROM [format_table_name("admin")] WHERE ckey = '[admin_ckey]'")
+ var/datum/DBQuery/query_admin_in_db = SSdbcore.NewQuery("SELECT `rank` FROM [format_table_name("admin")] WHERE ckey = '[admin_ckey]'")
if(!query_admin_in_db.warn_execute())
qdel(query_admin_in_db)
return
@@ -314,13 +314,13 @@
old_rank = query_admin_in_db.item[1]
qdel(query_admin_in_db)
//similarly if a temp rank is created it won't be in the db if someone is permanently changed to it
- var/datum/DBQuery/query_rank_in_db = SSdbcore.NewQuery("SELECT 1 FROM [format_table_name("admin_ranks")] WHERE rank = '[new_rank]'")
+ var/datum/DBQuery/query_rank_in_db = SSdbcore.NewQuery("SELECT 1 FROM [format_table_name("admin_ranks")] WHERE `rank` = '[new_rank]'")
if(!query_rank_in_db.warn_execute())
qdel(query_rank_in_db)
return
if(!query_rank_in_db.NextRow())
QDEL_NULL(query_rank_in_db)
- var/datum/DBQuery/query_add_rank = SSdbcore.NewQuery("INSERT INTO [format_table_name("admin_ranks")] (rank, flags, exclude_flags, can_edit_flags) VALUES ('[new_rank]', '0', '0', '0')")
+ var/datum/DBQuery/query_add_rank = SSdbcore.NewQuery("INSERT INTO [format_table_name("admin_ranks")] (`rank`, flags, exclude_flags, can_edit_flags) VALUES ('[new_rank]', '0', '0', '0')")
if(!query_add_rank.warn_execute())
qdel(query_add_rank)
return
@@ -331,7 +331,7 @@
return
qdel(query_add_rank_log)
qdel(query_rank_in_db)
- var/datum/DBQuery/query_change_rank = SSdbcore.NewQuery("UPDATE [format_table_name("admin")] SET rank = '[new_rank]' WHERE ckey = '[admin_ckey]'")
+ var/datum/DBQuery/query_change_rank = SSdbcore.NewQuery("UPDATE [format_table_name("admin")] SET `rank` = '[new_rank]' WHERE ckey = '[admin_ckey]'")
if(!query_change_rank.warn_execute())
qdel(query_change_rank)
return
@@ -368,7 +368,7 @@
var/old_flags
var/old_exclude_flags
var/old_can_edit_flags
- var/datum/DBQuery/query_get_rank_flags = SSdbcore.NewQuery("SELECT flags, exclude_flags, can_edit_flags FROM [format_table_name("admin_ranks")] WHERE rank = '[rank_name]'")
+ var/datum/DBQuery/query_get_rank_flags = SSdbcore.NewQuery("SELECT flags, exclude_flags, can_edit_flags FROM [format_table_name("admin_ranks")] WHERE `rank` = '[rank_name]'")
if(!query_get_rank_flags.warn_execute())
qdel(query_get_rank_flags)
return
@@ -377,7 +377,7 @@
old_exclude_flags = text2num(query_get_rank_flags.item[2])
old_can_edit_flags = text2num(query_get_rank_flags.item[3])
qdel(query_get_rank_flags)
- var/datum/DBQuery/query_change_rank_flags = SSdbcore.NewQuery("UPDATE [format_table_name("admin_ranks")] SET flags = '[new_flags]', exclude_flags = '[new_exclude_flags]', can_edit_flags = '[new_can_edit_flags]' WHERE rank = '[rank_name]'")
+ var/datum/DBQuery/query_change_rank_flags = SSdbcore.NewQuery("UPDATE [format_table_name("admin_ranks")] SET flags = '[new_flags]', exclude_flags = '[new_exclude_flags]', can_edit_flags = '[new_can_edit_flags]' WHERE `rank` = '[rank_name]'")
if(!query_change_rank_flags.warn_execute())
qdel(query_change_rank_flags)
return
@@ -434,7 +434,7 @@
to_chat(usr, "Rank deletion not permitted while database rank loading is disabled.")
return
admin_rank = sanitizeSQL(admin_rank)
- var/datum/DBQuery/query_admins_with_rank = SSdbcore.NewQuery("SELECT 1 FROM [format_table_name("admin")] WHERE rank = '[admin_rank]'")
+ var/datum/DBQuery/query_admins_with_rank = SSdbcore.NewQuery("SELECT 1 FROM [format_table_name("admin")] WHERE `rank` = '[admin_rank]'")
if(!query_admins_with_rank.warn_execute())
qdel(query_admins_with_rank)
return
@@ -446,7 +446,7 @@
if(alert("Are you sure you want to remove [admin_rank]?","Confirm Removal","Do it","Cancel") == "Do it")
var/m1 = "[key_name_admin(usr)] removed rank [admin_rank] permanently"
var/m2 = "[key_name(usr)] removed rank [admin_rank] permanently"
- var/datum/DBQuery/query_add_rank = SSdbcore.NewQuery("DELETE FROM [format_table_name("admin_ranks")] WHERE rank = '[admin_rank]'")
+ var/datum/DBQuery/query_add_rank = SSdbcore.NewQuery("DELETE FROM [format_table_name("admin_ranks")] WHERE `rank` = '[admin_rank]'")
if(!query_add_rank.warn_execute())
qdel(query_add_rank)
return
diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm
index cfb5887267a..300e3f0f7b6 100644
--- a/code/modules/admin/topic.dm
+++ b/code/modules/admin/topic.dm
@@ -1790,12 +1790,26 @@
log_query_debug("[usr.key] | [response]")
else if(answer == "no")
log_query_debug("[usr.key] | Reported no server hang")
+
+ else if(href_list["ctf_toggle"])
+ if(!check_rights(R_ADMIN))
+ return
+ toggle_all_ctf(usr)
+ else if(href_list["rebootworld"])
+ if(!check_rights(R_ADMIN))
+ return
+ var/confirm = alert("Are you sure you want to reboot the server?", "Confirm Reboot", "Yes", "No")
+ if(confirm == "No")
+ return
+ if(confirm == "Yes")
+ restart()
+
else if(href_list["check_teams"])
if(!check_rights(R_ADMIN))
return
check_teams()
-
+
else if(href_list["team_command"])
if(!check_rights(R_ADMIN))
return
diff --git a/code/modules/admin/verbs/playsound.dm b/code/modules/admin/verbs/playsound.dm
index 83b0399b214..c47d7dda9d7 100644
--- a/code/modules/admin/verbs/playsound.dm
+++ b/code/modules/admin/verbs/playsound.dm
@@ -76,7 +76,7 @@
to_chat(src, "For youtube-dl shortcuts like ytsearch: please use the appropriate full url from the website.")
return
var/shell_scrubbed_input = shell_url_scrub(web_sound_input)
- var/list/output = world.shelleo("[ytdl] --format \"bestaudio\[ext=mp3]/best\[ext=mp4]\[height<=360]/bestaudio\[ext=m4a]/bestaudio\[ext=aac]\" --dump-single-json --no-playlist -- \"[shell_scrubbed_input]\"")
+ var/list/output = world.shelleo("[ytdl] --geo-bypass --format \"bestaudio\[ext=mp3]/best\[ext=mp4]\[height<=360]/bestaudio\[ext=m4a]/bestaudio\[ext=aac]\" --dump-single-json --no-playlist -- \"[shell_scrubbed_input]\"")
var/errorlevel = output[SHELLEO_ERRORLEVEL]
var/stdout = output[SHELLEO_STDOUT]
var/stderr = output[SHELLEO_STDERR]
diff --git a/code/modules/antagonists/_common/antag_spawner.dm b/code/modules/antagonists/_common/antag_spawner.dm
index c9b23f9be8c..954968365fb 100644
--- a/code/modules/antagonists/_common/antag_spawner.dm
+++ b/code/modules/antagonists/_common/antag_spawner.dm
@@ -237,7 +237,7 @@
/obj/item/antag_spawner/slaughter_demon/attack_self(mob/user)
if(!is_station_level(user.z))
- to_chat(user, "You should probably wait until you reach the station.")
+ to_chat(user, "You should probably wait until you reach the station.")
return
if(used)
return
@@ -253,7 +253,7 @@
playsound(user.loc, 'sound/effects/glassbr1.ogg', 100, 1)
qdel(src)
else
- to_chat(user, "You can't seem to work up the nerve to shatter the bottle. Perhaps you should try again later.")
+ to_chat(user, "You can't seem to work up the nerve to shatter the bottle! Perhaps you should try again later.")
/obj/item/antag_spawner/slaughter_demon/spawn_antag(client/C, turf/T, kind = "", datum/mind/user)
diff --git a/code/modules/antagonists/abductor/equipment/abduction_gear.dm b/code/modules/antagonists/abductor/equipment/abduction_gear.dm
index 149a0f27688..f6dcdb1a0f0 100644
--- a/code/modules/antagonists/abductor/equipment/abduction_gear.dm
+++ b/code/modules/antagonists/abductor/equipment/abduction_gear.dm
@@ -636,6 +636,40 @@ Congratulations! You are now trained for invasive xenobiology research!"}
return // Stops humans from disassembling abductor headsets.
return ..()
+/obj/item/abductor_machine_beacon
+ name = "machine beacon"
+ desc = "A beacon designed to instantly tele-construct abductor machinery."
+ icon = 'icons/obj/abductor.dmi'
+ icon_state = "beacon"
+ w_class = WEIGHT_CLASS_TINY
+ var/obj/machinery/spawned_machine
+
+/obj/item/abductor_machine_beacon/attack_self(mob/user)
+ ..()
+ user.visible_message("[user] places down [src] and activates it.", "You place down [src] and activate it.")
+ user.dropItemToGround(src)
+ playsound(src, 'sound/machines/terminal_alert.ogg', 50)
+ addtimer(CALLBACK(src, .proc/try_spawn_machine), 30)
+
+/obj/item/abductor_machine_beacon/proc/try_spawn_machine()
+ var/viable = FALSE
+ if(isfloorturf(loc))
+ var/turf/T = loc
+ viable = TRUE
+ for(var/obj/thing in T.contents)
+ if(thing.density || ismachinery(thing) || isstructure(thing))
+ viable = FALSE
+ if(viable)
+ playsound(src, 'sound/effects/phasein.ogg', 50, TRUE)
+ var/new_machine = new spawned_machine(loc)
+ visible_message("[new_machine] warps on top of the beacon!")
+ qdel(src)
+ else
+ playsound(src, 'sound/machines/buzz-two.ogg', 50)
+
+/obj/item/abductor_machine_beacon/chem_dispenser
+ name = "beacon - Reagent Synthesizer"
+ spawned_machine = /obj/machinery/chem_dispenser/abductor
/obj/item/scalpel/alien
name = "alien scalpel"
diff --git a/code/modules/antagonists/abductor/equipment/abduction_surgery.dm b/code/modules/antagonists/abductor/equipment/abduction_surgery.dm
index db3bbf1118a..cd8915238d6 100644
--- a/code/modules/antagonists/abductor/equipment/abduction_surgery.dm
+++ b/code/modules/antagonists/abductor/equipment/abduction_surgery.dm
@@ -45,10 +45,10 @@
time = 32
/datum/surgery_step/gland_insert/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
- user.visible_message("[user] starts to insert [tool] into [target].", "You start to insert [tool] into [target]...")
+ user.visible_message("[user] starts to insert [tool] into [target].", "You start to insert [tool] into [target]...")
/datum/surgery_step/gland_insert/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
- user.visible_message("[user] inserts [tool] into [target].", "You insert [tool] into [target].")
+ user.visible_message("[user] inserts [tool] into [target].", "You insert [tool] into [target].")
user.temporarilyRemoveItemFromInventory(tool, TRUE)
var/obj/item/organ/heart/gland/gland = tool
gland.Insert(target, 2)
diff --git a/code/modules/antagonists/abductor/equipment/gland.dm b/code/modules/antagonists/abductor/equipment/gland.dm
index b45cdb996c4..2cc09be061a 100644
--- a/code/modules/antagonists/abductor/equipment/gland.dm
+++ b/code/modules/antagonists/abductor/equipment/gland.dm
@@ -23,7 +23,7 @@
/obj/item/organ/heart/gland/examine(mob/user)
. = ..()
- if(HAS_TRAIT(user, TRAIT_ABDUCTOR_SCIENTIST_TRAINING) || isobserver(user))
+ if((user.mind && HAS_TRAIT(user.mind, TRAIT_ABDUCTOR_SCIENTIST_TRAINING)) || isobserver(user))
. += "It is \a [true_name]."
/obj/item/organ/heart/gland/proc/ownerCheck()
@@ -52,23 +52,25 @@
/obj/item/organ/heart/gland/proc/mind_control(command, mob/living/user)
if(!ownerCheck() || !mind_control_uses || active_mind_control)
- return
+ return FALSE
mind_control_uses--
to_chat(owner, "You suddenly feel an irresistible compulsion to follow an order...")
to_chat(owner, "[command]")
active_mind_control = TRUE
- log_admin("[key_name(user)] sent an abductor mind control message to [key_name(owner)]: [command]")
+ message_admins("[key_name(user)] sent an abductor mind control message to [key_name(owner)]: [command]")
update_gland_hud()
var/obj/screen/alert/mind_control/mind_alert = owner.throw_alert("mind_control", /obj/screen/alert/mind_control)
mind_alert.command = command
addtimer(CALLBACK(src, .proc/clear_mind_control), mind_control_duration)
+ return TRUE
/obj/item/organ/heart/gland/proc/clear_mind_control()
if(!ownerCheck() || !active_mind_control)
- return
+ return FALSE
to_chat(owner, "You feel the compulsion fade, and you completely forget about your previous orders.")
owner.clear_alert("mind_control")
active_mind_control = FALSE
+ return TRUE
/obj/item/organ/heart/gland/Remove(mob/living/carbon/M, special = 0)
active = 0
@@ -151,6 +153,7 @@
icon_state = "mindshock"
mind_control_uses = 1
mind_control_duration = 6000
+ var/list/mob/living/carbon/human/broadcasted_mobs = list()
/obj/item/organ/heart/gland/mindshock/activate()
to_chat(owner, "You get a headache.")
@@ -170,14 +173,71 @@
if(3)
H.hallucination += 60
+/obj/item/organ/heart/gland/mindshock/mind_control(command, mob/living/user)
+ if(!ownerCheck() || !mind_control_uses || active_mind_control)
+ return FALSE
+ mind_control_uses--
+ for(var/mob/M in oview(7, owner))
+ if(!ishuman(M))
+ continue
+ var/mob/living/carbon/human/H = M
+ if(H.stat)
+ continue
+
+ broadcasted_mobs += H
+ to_chat(H, "You suddenly feel an irresistible compulsion to follow an order...")
+ to_chat(H, "[command]")
+
+ message_admins("[key_name(user)] broadcasted an abductor mind control message from [key_name(owner)] to [key_name(H)]: [command]")
+
+ var/obj/screen/alert/mind_control/mind_alert = H.throw_alert("mind_control", /obj/screen/alert/mind_control)
+ mind_alert.command = command
+
+ if(LAZYLEN(broadcasted_mobs))
+ active_mind_control = TRUE
+ addtimer(CALLBACK(src, .proc/clear_mind_control), mind_control_duration)
+
+ update_gland_hud()
+ return TRUE
+
+/obj/item/organ/heart/gland/mindshock/clear_mind_control()
+ if(!active_mind_control || !LAZYLEN(broadcasted_mobs))
+ return FALSE
+ for(var/M in broadcasted_mobs)
+ var/mob/living/carbon/human/H = M
+ to_chat(H, "You feel the compulsion fade, and you completely forget about your previous orders.")
+ H.clear_alert("mind_control")
+ active_mind_control = FALSE
+ return TRUE
+
+/obj/item/organ/heart/gland/access
+ true_name = "anagraphic electro-scrambler"
+ cooldown_low = 600
+ cooldown_high = 1200
+ uses = 1
+ icon_state = "mindshock"
+ mind_control_uses = 3
+ mind_control_duration = 900
+
+/obj/item/organ/heart/gland/access/activate()
+ to_chat(owner, "You feel like a VIP for some reason.")
+ RegisterSignal(owner, COMSIG_MOB_ALLOWED, .proc/free_access)
+
+/obj/item/organ/heart/gland/access/proc/free_access(datum/source, obj/O)
+ return TRUE
+
+/obj/item/organ/heart/gland/access/Remove(mob/living/carbon/M, special = 0)
+ UnregisterSignal(owner, COMSIG_MOB_ALLOWED)
+ ..()
+
/obj/item/organ/heart/gland/pop
- true_name = "anthropmorphic translocator"
+ true_name = "anthropmorphic transmorphosizer"
cooldown_low = 900
cooldown_high = 1800
uses = -1
human_only = TRUE
icon_state = "species"
- mind_control_uses = 5
+ mind_control_uses = 7
mind_control_duration = 300
/obj/item/organ/heart/gland/pop/activate()
@@ -253,6 +313,54 @@
else
owner.gain_trauma_type(BRAIN_TRAUMA_MILD, rand(TRAUMA_RESILIENCE_BASIC, TRAUMA_RESILIENCE_LOBOTOMY))
+/obj/item/organ/heart/gland/quantum
+ true_name = "quantic de-observation matrix"
+ cooldown_low = 150
+ cooldown_high = 150
+ uses = -1
+ icon_state = "emp"
+ mind_control_uses = 2
+ mind_control_duration = 1200
+ var/mob/living/carbon/entangled_mob
+
+/obj/item/organ/heart/gland/quantum/activate()
+ if(entangled_mob)
+ return
+ for(var/mob/M in oview(owner, 7))
+ if(!iscarbon(M))
+ continue
+ entangled_mob = M
+ addtimer(CALLBACK(src, .proc/quantum_swap), rand(600, 2400))
+ return
+
+/obj/item/organ/heart/gland/quantum/proc/quantum_swap()
+ if(QDELETED(entangled_mob))
+ entangled_mob = null
+ return
+ var/turf/T = get_turf(owner)
+ do_teleport(owner, get_turf(entangled_mob),null,TRUE,channel = TELEPORT_CHANNEL_QUANTUM)
+ do_teleport(entangled_mob, T,null,TRUE,channel = TELEPORT_CHANNEL_QUANTUM)
+ to_chat(owner, "You suddenly find yourself somewhere else!")
+ to_chat(entangled_mob, "You suddenly find yourself somewhere else!")
+ if(!active_mind_control) //Do not reset entangled mob while mind control is active
+ entangled_mob = null
+
+/obj/item/organ/heart/gland/quantum/mind_control(command, mob/living/user)
+ if(..())
+ if(entangled_mob && ishuman(entangled_mob) && (entangled_mob.stat < DEAD))
+ to_chat(entangled_mob, "You suddenly feel an irresistible compulsion to follow an order...")
+ to_chat(entangled_mob, "[command]")
+ var/obj/screen/alert/mind_control/mind_alert = entangled_mob.throw_alert("mind_control", /obj/screen/alert/mind_control)
+ mind_alert.command = command
+ message_admins("[key_name(owner)] mirrored an abductor mind control message to [key_name(entangled_mob)]: [command]")
+ update_gland_hud()
+
+/obj/item/organ/heart/gland/quantum/clear_mind_control()
+ if(active_mind_control)
+ to_chat(entangled_mob, "You feel the compulsion fade, and you completely forget about your previous orders.")
+ entangled_mob.clear_alert("mind_control")
+ ..()
+
/obj/item/organ/heart/gland/spiderman
true_name = "araneae cloister accelerator"
cooldown_low = 450
@@ -284,20 +392,41 @@
var/turf/T = owner.drop_location()
new /obj/item/reagent_containers/food/snacks/egg/gland(T)
+
+/obj/item/organ/heart/gland/blood
+ true_name = "pseudonuclear hemo-destabilizer"
+ cooldown_low = 1200
+ cooldown_high = 1800
+ uses = -1
+ icon_state = "egg"
+ lefthand_file = 'icons/mob/inhands/misc/food_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/misc/food_righthand.dmi'
+ mind_control_uses = 3
+ mind_control_duration = 1500
+
+/obj/item/organ/heart/gland/blood/activate()
+ if(!ishuman(owner) || !owner.dna.species)
+ return
+ var/mob/living/carbon/human/H = owner
+ var/datum/species/species = H.dna.species
+ to_chat(H, "You feel your blood heat up for a moment.")
+ species.exotic_blood = get_random_reagent_id()
+
/obj/item/organ/heart/gland/electric
true_name = "electron accumulator/discharger"
cooldown_low = 800
cooldown_high = 1200
+ icon_state = "species"
uses = -1
mind_control_uses = 2
mind_control_duration = 900
/obj/item/organ/heart/gland/electric/Insert(mob/living/carbon/M, special = 0)
..()
- ADD_TRAIT(owner, TRAIT_SHOCKIMMUNE, ORGAN_TRAIT)
+ ADD_TRAIT(owner, TRAIT_SHOCKIMMUNE, "abductor_gland")
/obj/item/organ/heart/gland/electric/Remove(mob/living/carbon/M, special = 0)
- REMOVE_TRAIT(owner, TRAIT_SHOCKIMMUNE, ORGAN_TRAIT)
+ REMOVE_TRAIT(owner, TRAIT_SHOCKIMMUNE, "abductor_gland")
..()
/obj/item/organ/heart/gland/electric/activate()
@@ -315,6 +444,7 @@
cooldown_low = 50
cooldown_high = 50
uses = -1
+ icon_state = "viral"
mind_control_uses = 3
mind_control_duration = 1200
var/list/possible_reagents = list()
@@ -327,13 +457,14 @@
/obj/item/organ/heart/gland/chem/activate()
var/chem_to_add = pick(possible_reagents)
owner.reagents.add_reagent(chem_to_add, 2)
- owner.adjustToxLoss(-2, TRUE, TRUE)
+ owner.adjustToxLoss(-5, TRUE, TRUE)
..()
/obj/item/organ/heart/gland/plasma
true_name = "effluvium sanguine-synonym emitter"
cooldown_low = 1200
cooldown_high = 1800
+ icon_state = "slime"
uses = -1
mind_control_uses = 1
mind_control_duration = 800
diff --git a/code/modules/antagonists/abductor/machinery/console.dm b/code/modules/antagonists/abductor/machinery/console.dm
index 600df81388d..9e3d3b2aec2 100644
--- a/code/modules/antagonists/abductor/machinery/console.dm
+++ b/code/modules/antagonists/abductor/machinery/console.dm
@@ -45,6 +45,7 @@
dat += "Transfer data in exchange for supplies:
"
dat += "Advanced Baton (2 Credits)
"
dat += "Mental Interface Device (2 Credits)
"
+ dat += "Reagent Synthetizer (2 Credits)
"
dat += "Agent Helmet
"
dat += "Agent Vest
"
dat += "Radio Silencer
"
@@ -113,6 +114,8 @@
Dispense(/obj/item/clothing/suit/armor/abductor/vest)
if("mind_device")
Dispense(/obj/item/abductor/mind_device,cost=2)
+ if("chem_dispenser")
+ Dispense(/obj/item/abductor_machine_beacon/chem_dispenser,cost=2)
if("tongue")
Dispense(/obj/item/organ/tongue/abductor)
updateUsrDialog()
diff --git a/code/modules/antagonists/blob/structures/_blob.dm b/code/modules/antagonists/blob/structures/_blob.dm
index e2d84f209a3..c3cd66b181f 100644
--- a/code/modules/antagonists/blob/structures/_blob.dm
+++ b/code/modules/antagonists/blob/structures/_blob.dm
@@ -238,6 +238,7 @@
return ..()
/obj/structure/blob/proc/chemeffectreport(mob/user)
+ RETURN_TYPE(/list)
. = list()
if(overmind)
. += list("Material: [overmind.blobstrain.name].",
@@ -247,6 +248,7 @@
. += "No Material Detected!"
/obj/structure/blob/proc/typereport(mob/user)
+ RETURN_TYPE(/list)
return list("Blob Type: [uppertext(initial(name))]",
"Health: [obj_integrity]/[max_integrity]",
"Effects: [scannerreport()]")
diff --git a/code/modules/antagonists/changeling/changeling.dm b/code/modules/antagonists/changeling/changeling.dm
index c9afed78a22..6677165a920 100644
--- a/code/modules/antagonists/changeling/changeling.dm
+++ b/code/modules/antagonists/changeling/changeling.dm
@@ -63,8 +63,10 @@
var/honorific
if(owner.current.gender == FEMALE)
honorific = "Ms."
- else
+ else if(owner.current.gender == MALE)
honorific = "Mr."
+ else
+ honorific = "Mx."
if(GLOB.possible_changeling_IDs.len)
changelingID = pick(GLOB.possible_changeling_IDs)
GLOB.possible_changeling_IDs -= changelingID
@@ -170,23 +172,23 @@
return
if(absorbedcount < thepower.req_dna)
- to_chat(owner.current, "We lack the energy to evolve this ability!")
+ to_chat(owner.current, "We lack the energy to evolve this ability!")
return
if(has_sting(thepower))
- to_chat(owner.current, "We have already evolved this ability!")
+ to_chat(owner.current, "We have already evolved this ability!")
return
if(thepower.dna_cost < 0)
- to_chat(owner.current, "We cannot evolve this ability.")
+ to_chat(owner.current, "We cannot evolve this ability!")
return
if(geneticpoints < thepower.dna_cost)
- to_chat(owner.current, "We have reached our capacity for abilities.")
+ to_chat(owner.current, "We have reached our capacity for abilities!")
return
if(HAS_TRAIT(owner.current, TRAIT_DEATHCOMA))//To avoid potential exploits by buying new powers while in stasis, which clears your verblist.
- to_chat(owner.current, "We lack the energy to evolve new abilities right now.")
+ to_chat(owner.current, "We lack the energy to evolve new abilities right now!")
return
geneticpoints -= thepower.dna_cost
@@ -195,7 +197,7 @@
/datum/antagonist/changeling/proc/readapt()
if(!ishuman(owner.current))
- to_chat(owner.current, "We can't remove our evolutions in this form!")
+ to_chat(owner.current, "We can't remove our evolutions in this form!")
return
if(canrespec)
to_chat(owner.current, "We have removed our evolutions from this form, and are now ready to readapt.")
@@ -204,7 +206,7 @@
SSblackbox.record_feedback("tally", "changeling_power_purchase", 1, "Readapt")
return 1
else
- to_chat(owner.current, "You lack the power to readapt your evolutions!")
+ to_chat(owner.current, "You lack the power to readapt your evolutions!")
return 0
//Called in life()
diff --git a/code/modules/antagonists/changeling/powers/headcrab.dm b/code/modules/antagonists/changeling/powers/headcrab.dm
index 26b80f8b033..463cdb0591f 100644
--- a/code/modules/antagonists/changeling/powers/headcrab.dm
+++ b/code/modules/antagonists/changeling/powers/headcrab.dm
@@ -20,10 +20,11 @@
explosion(get_turf(user), 0, 0, 2, 0, TRUE)
for(var/mob/living/carbon/human/H in range(2,user))
+ var/obj/item/organ/eyes/eyes = H.getorganslot(ORGAN_SLOT_EYES)
to_chat(H, "You are blinded by a shower of blood!")
H.Stun(20)
H.blur_eyes(20)
- H.adjust_eye_damage(5)
+ eyes.applyOrganDamage(5)
H.confused += 3
for(var/mob/living/silicon/S in range(2,user))
to_chat(S, "Your sensors are disabled by a shower of blood!")
diff --git a/code/modules/antagonists/changeling/powers/mutations.dm b/code/modules/antagonists/changeling/powers/mutations.dm
index 96427b602c2..1ab2a252686 100644
--- a/code/modules/antagonists/changeling/powers/mutations.dm
+++ b/code/modules/antagonists/changeling/powers/mutations.dm
@@ -113,10 +113,10 @@
/datum/action/changeling/suit/sting_action(mob/living/carbon/human/user)
if(!user.canUnEquip(user.wear_suit))
- to_chat(user, "\the [user.wear_suit] is stuck to your body, you cannot grow a [suit_name_simple] over it!")
+ to_chat(user, "\the [user.wear_suit] is stuck to your body, you cannot grow a [suit_name_simple] over it!")
return
if(!user.canUnEquip(user.head))
- to_chat(user, "\the [user.head] is stuck on your head, you cannot grow a [helmet_name_simple] over it!")
+ to_chat(user, "\the [user.head] is stuck on your head, you cannot grow a [helmet_name_simple] over it!")
return
..()
user.dropItemToGround(user.head)
@@ -368,7 +368,7 @@
on_hit(I) //grab the item as if you had hit it directly with the tentacle
return BULLET_ACT_HIT
else
- to_chat(firer, "You can't seem to pry [I] off [C]'s hands!")
+ to_chat(firer, "You can't seem to pry [I] off [C]'s hands!")
return BULLET_ACT_BLOCK
else
to_chat(firer, "[C] has nothing in hand to disarm!")
diff --git a/code/modules/antagonists/changeling/powers/tiny_prick.dm b/code/modules/antagonists/changeling/powers/tiny_prick.dm
index 660d5754929..9b9ffb483ef 100644
--- a/code/modules/antagonists/changeling/powers/tiny_prick.dm
+++ b/code/modules/antagonists/changeling/powers/tiny_prick.dm
@@ -84,7 +84,7 @@
if(!selected_dna)
return
if(NOTRANSSTING in selected_dna.dna.species.species_traits)
- to_chat(user, "That DNA is not compatible with changeling retrovirus!")
+ to_chat(user, "That DNA is not compatible with changeling retrovirus!")
return
..()
diff --git a/code/modules/antagonists/clockcult/clock_effects/servant_blocker.dm b/code/modules/antagonists/clockcult/clock_effects/servant_blocker.dm
index c9351d93554..acca057b8be 100644
--- a/code/modules/antagonists/clockcult/clock_effects/servant_blocker.dm
+++ b/code/modules/antagonists/clockcult/clock_effects/servant_blocker.dm
@@ -21,7 +21,7 @@
var/list/target_contents = M.GetAllContents() + M
for(var/mob/living/L in target_contents)
if(is_servant_of_ratvar(L) && get_dir(M, src) != dir && L.stat != DEAD) //Unless we're on the side the arrow is pointing directly away from, no-go
- to_chat(L, "The space beyond here can't be accessed by you or other servants.")
+ to_chat(L, "The space beyond here can't be accessed by you or other servants!")
return
if(isitem(M))
var/obj/item/I = M
diff --git a/code/modules/antagonists/clockcult/clock_items/wraith_spectacles.dm b/code/modules/antagonists/clockcult/clock_items/wraith_spectacles.dm
index 9d241148b44..a46fbd21249 100644
--- a/code/modules/antagonists/clockcult/clock_items/wraith_spectacles.dm
+++ b/code/modules/antagonists/clockcult/clock_items/wraith_spectacles.dm
@@ -47,11 +47,12 @@
to_chat(H, "You push the spectacles down, but you can't see through the glass.")
/obj/item/clothing/glasses/wraith_spectacles/proc/blind_cultist(mob/living/victim)
+ var/obj/item/organ/eyes/eyes = victim.getorganslot(ORGAN_SLOT_EYES)
if(iscultist(victim))
to_chat(victim, "\"It looks like Nar'Sie's dogs really don't value their eyes.\"")
to_chat(victim, "Your eyes explode with horrific pain!")
victim.emote("scream")
- victim.become_blind(EYE_DAMAGE)
+ eyes.applyOrganDamage(eyes.maxHealth)
victim.adjust_blurriness(30)
victim.adjust_blindness(30)
return TRUE
@@ -138,24 +139,26 @@
var/mob/living/carbon/human/H = owner
var/glasses_right = istype(H.glasses, /obj/item/clothing/glasses/wraith_spectacles)
var/obj/item/clothing/glasses/wraith_spectacles/WS = H.glasses
+ var/obj/item/organ/eyes/eyes = H.getorganslot(ORGAN_SLOT_EYES)
if(glasses_right && !WS.up && !GLOB.ratvar_awakens && !GLOB.ratvar_approaches)
apply_eye_damage(H)
else
if(GLOB.ratvar_awakens)
H.cure_nearsighted(list(EYE_DAMAGE))
H.cure_blind(list(EYE_DAMAGE))
- H.adjust_eye_damage(-eye_damage_done)
+ eyes.applyOrganDamage(-eye_damage_done)
eye_damage_done = 0
else if(prob(50) && eye_damage_done)
- H.adjust_eye_damage(-1)
+ eyes.applyOrganDamage(-1)
eye_damage_done = max(0, eye_damage_done - 1)
if(!eye_damage_done)
qdel(src)
/datum/status_effect/wraith_spectacles/proc/apply_eye_damage(mob/living/carbon/human/H)
+ var/obj/item/organ/eyes/eyes = H.getorganslot(ORGAN_SLOT_EYES)
if(HAS_TRAIT(H, TRAIT_BLIND))
return
- H.adjust_eye_damage(0.5)
+ eyes.applyOrganDamage(0.5)
eye_damage_done += 0.5
if(eye_damage_done >= 20)
H.adjust_blurriness(2)
@@ -166,7 +169,7 @@
if(eye_damage_done >= blind_breakpoint)
if(!HAS_TRAIT(H, TRAIT_BLIND))
to_chat(H, "A piercing white light floods your vision. Suddenly, all goes dark!")
- H.become_blind(EYE_DAMAGE)
+ eyes.applyOrganDamage(eyes.maxHealth)
if(prob(min(20, 5 + eye_damage_done)))
to_chat(H, "Your eyes continue to burn.")
diff --git a/code/modules/antagonists/cult/blood_magic.dm b/code/modules/antagonists/cult/blood_magic.dm
index 8d470c86c2d..c4c7275e15d 100644
--- a/code/modules/antagonists/cult/blood_magic.dm
+++ b/code/modules/antagonists/cult/blood_magic.dm
@@ -728,7 +728,7 @@
to_chat(user,"Your blood rite gains 50 charges from draining [H]'s blood.")
new /obj/effect/temp_visual/cult/sparks(get_turf(H))
else
- to_chat(user,"[H.p_theyre(TRUE)] missing too much blood - you cannot drain [H.p_them()] further!")
+ to_chat(user,"[H.p_theyre(TRUE)] missing too much blood - you cannot drain [H.p_them()] further!")
return
if(isconstruct(target))
var/mob/living/simple_animal/M = target
diff --git a/code/modules/antagonists/cult/cult_items.dm b/code/modules/antagonists/cult/cult_items.dm
index c1b76321cd6..3daa0087b90 100644
--- a/code/modules/antagonists/cult/cult_items.dm
+++ b/code/modules/antagonists/cult/cult_items.dm
@@ -594,7 +594,7 @@
playsound(destination, "sparks", 50, 1)
else
- to_chat(C, "The veil cannot be torn here!")
+ to_chat(C, "The veil cannot be torn here!")
/obj/item/flashlight/flare/culttorch
name = "void torch"
@@ -764,7 +764,6 @@
guns_left = 24
mag_type = /obj/item/ammo_box/magazine/internal/boltaction/enchanted/arcane_barrage/blood
fire_sound = 'sound/magic/wand_teleport.ogg'
- item_flags = NEEDS_PERMIT | NOBLUDGEON | DROPDEL
/obj/item/ammo_box/magazine/internal/boltaction/enchanted/arcane_barrage/blood
@@ -772,10 +771,12 @@
/obj/item/ammo_casing/magic/arcane_barrage/blood
projectile_type = /obj/item/projectile/magic/arcane_barrage/blood
+ firing_effect_type = /obj/effect/temp_visual/cult/sparks
/obj/item/projectile/magic/arcane_barrage/blood
name = "blood bolt"
icon_state = "mini_leaper"
+ nondirectional_sprite = TRUE
damage_type = BRUTE
impact_effect_type = /obj/effect/temp_visual/dir_setting/bloodsplatter
diff --git a/code/modules/antagonists/cult/runes.dm b/code/modules/antagonists/cult/runes.dm
index 30637b7f7aa..f1d1ea22aaf 100644
--- a/code/modules/antagonists/cult/runes.dm
+++ b/code/modules/antagonists/cult/runes.dm
@@ -117,9 +117,6 @@ structure_check() searches for nearby cultist structures required for the invoca
invokers += user
if(req_cultists > 1 || istype(src, /obj/effect/rune/convert))
var/list/things_in_range = range(1, src)
- var/obj/item/toy/plush/narplush/plushsie = locate() in things_in_range
- if(istype(plushsie) && plushsie.is_invoker)
- invokers += plushsie
for(var/mob/living/L in things_in_range)
if(iscultist(L))
if(L == user)
@@ -237,7 +234,7 @@ structure_check() searches for nearby cultist structures required for the invoca
/obj/effect/rune/convert/proc/do_convert(mob/living/convertee, list/invokers)
if(invokers.len < 2)
for(var/M in invokers)
- to_chat(M, "You need at least two invokers to convert [convertee]!")
+ to_chat(M, "You need at least two invokers to convert [convertee]!")
log_game("Offer rune failed - tried conversion with one invoker")
return 0
if(convertee.anti_magic_check(TRUE, TRUE, FALSE, 0)) //Not chargecost because it can be spammed
diff --git a/code/modules/antagonists/devil/devil.dm b/code/modules/antagonists/devil/devil.dm
index 04459050d21..43183dfe408 100644
--- a/code/modules/antagonists/devil/devil.dm
+++ b/code/modules/antagonists/devil/devil.dm
@@ -382,7 +382,7 @@ GLOBAL_LIST_INIT(devil_suffix, list(" the Red", " the Soulless", " the Master",
if(BANISH_WATER)
if(iscarbon(body))
var/mob/living/carbon/H = body
- return H.reagents.has_reagent("holy water")
+ return H.reagents.has_reagent(/datum/reagent/water/holywater)
return 0
if(BANISH_COFFIN)
return (body && istype(body.loc, /obj/structure/closet/crate/coffin))
diff --git a/code/modules/antagonists/disease/disease_disease.dm b/code/modules/antagonists/disease/disease_disease.dm
index 21d03819825..b4b8ac09560 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/disease/disease_mob.dm b/code/modules/antagonists/disease/disease_mob.dm
index 0a6c0a04ab7..d536a0c2a15 100644
--- a/code/modules/antagonists/disease/disease_mob.dm
+++ b/code/modules/antagonists/disease/disease_mob.dm
@@ -152,7 +152,7 @@ the new instance inside the host to be updated to the template's stats.
set_name = "Sentient Virus"
break
if(taken_names[input])
- to_chat(src, "You cannot use the name of such a well-known disease!")
+ to_chat(src, "You cannot use the name of such a well-known disease!")
else
set_name = input
real_name = "[set_name] (Sentient Disease)"
diff --git a/code/modules/antagonists/fugitive/fugitive_ship.dm b/code/modules/antagonists/fugitive/fugitive_ship.dm
index af26ddd5cda..01555cde71a 100644
--- a/code/modules/antagonists/fugitive/fugitive_ship.dm
+++ b/code/modules/antagonists/fugitive/fugitive_ship.dm
@@ -32,7 +32,7 @@
to_chat(fugitive, "You are thrown into a vast void of bluespace, and as you fall further into oblivion the comparatively small entrance to reality gets smaller and smaller until you cannot see it anymore. You have failed to avoid capture.")
fugitive.ghostize(TRUE) //so they cannot suicide, round end stuff.
-/obj/machinery/computer/shuttle/pirate/hunter
+/obj/machinery/computer/shuttle/hunter
name = "shuttle console"
shuttleId = "huntership"
possible_destinations = "huntership_away;huntership_home;huntership_custom"
diff --git a/code/modules/antagonists/hivemind/hivemind.dm b/code/modules/antagonists/hivemind/hivemind.dm
index 743afb918c6..163fb29a196 100644
--- a/code/modules/antagonists/hivemind/hivemind.dm
+++ b/code/modules/antagonists/hivemind/hivemind.dm
@@ -185,6 +185,7 @@
ADD_TRAIT(C, TRAIT_NOLIMBDISABLE, HIVEMIND_ONE_MIND_TRAIT)
ADD_TRAIT(C, TRAIT_NOHUNGER, HIVEMIND_ONE_MIND_TRAIT)
ADD_TRAIT(C, TRAIT_NODISMEMBER, HIVEMIND_ONE_MIND_TRAIT)
+ log_game("[key_name(owner)] has awakened vessels.")
/datum/antagonist/hivemind/proc/go_back_to_sleep()
if(!active_one_mind)
diff --git a/code/modules/antagonists/hivemind/vessel.dm b/code/modules/antagonists/hivemind/vessel.dm
index b9024a5cae2..6b13cbcd589 100644
--- a/code/modules/antagonists/hivemind/vessel.dm
+++ b/code/modules/antagonists/hivemind/vessel.dm
@@ -33,8 +33,9 @@
else
var/datum/objective/brainwashing/obj = new(objective)
vessel.objectives += obj
- var/message = " has been brainwashed with the following objectives: [objective]."
+ var/message = " has been awoken with the following objectives: [objective]."
deadchat_broadcast(message, "[M]", follow_target = M, turf_target = get_turf(M), message_type=DEADCHAT_REGULAR)
+ log_game("[key_name(M)] has been awoken with the following objectives: [objective]")
if(!M.has_antag_datum(/datum/antagonist/hivevessel))
M.add_antag_datum(vessel)
diff --git a/code/modules/antagonists/traitor/datum_traitor.dm b/code/modules/antagonists/traitor/datum_traitor.dm
index 2bf952927ea..cc535c89845 100644
--- a/code/modules/antagonists/traitor/datum_traitor.dm
+++ b/code/modules/antagonists/traitor/datum_traitor.dm
@@ -14,7 +14,7 @@
var/should_equip = TRUE
var/traitor_kind = TRAITOR_HUMAN //Set on initial assignment
var/datum/syndicate_contract/current_contract
- var/list/assigned_contracts = list()
+ var/list/datum/syndicate_contract/assigned_contracts = list()
var/contract_TC_payed_out = 0
var/contract_TC_to_redeem = 0
can_hijack = HIJACK_HIJACKER
@@ -32,17 +32,33 @@
..()
/datum/antagonist/traitor/proc/create_contracts()
- var/contract_generation_quantity = 6
+ // 6 contracts
+ var/list/to_generate = list(
+ CONTRACT_PAYOUT_LARGE,
+ CONTRACT_PAYOUT_MEDIUM,
+ CONTRACT_PAYOUT_SMALL,
+ CONTRACT_PAYOUT_SMALL,
+ CONTRACT_PAYOUT_SMALL,
+ CONTRACT_PAYOUT_SMALL
+ )
+
// We don't want the sum of all the payouts to be under this amount
- var/lowest_TC_threshold = 28
+ var/lowest_TC_threshold = 30
var/total = 0
var/lowest_paying_sum = 0
var/datum/syndicate_contract/lowest_paying_contract
+
+ // Randomise order, so we don't have contracts always in payout order.
+ to_generate = shuffle(to_generate)
- for (var/i = 1; i <= contract_generation_quantity; i++)
- var/datum/syndicate_contract/contract_to_add = new(owner)
+ var/list/assigned_targets = list()
+ // Generate contracts, and find the lowest paying.
+ for (var/i = 1; i <= to_generate.len; i++)
+ var/datum/syndicate_contract/contract_to_add = new(owner, to_generate[i], assigned_targets)
var/contract_payout_total = contract_to_add.contract.payout + contract_to_add.contract.payout_bonus
+
+ assigned_targets.Add(contract_to_add.contract.target)
if (!lowest_paying_contract || (contract_payout_total < lowest_paying_sum))
lowest_paying_sum = contract_payout_total
@@ -394,7 +410,7 @@
if (completed_contracts > 0)
var/pluralCheck = "contract"
- if (completed_contracts > 1)
+ if (completed_contracts > 1)
pluralCheck = "contracts"
result += "
Completed [completed_contracts] [pluralCheck] for a total of \
[tc_total] TC!
"
diff --git a/code/modules/antagonists/traitor/syndicate_contract.dm b/code/modules/antagonists/traitor/syndicate_contract.dm
index c9be1a4f650..fe31513a0fd 100644
--- a/code/modules/antagonists/traitor/syndicate_contract.dm
+++ b/code/modules/antagonists/traitor/syndicate_contract.dm
@@ -6,22 +6,19 @@
var/list/victim_belongings = list()
-/datum/syndicate_contract/New(owner)
- generate(owner)
+/datum/syndicate_contract/New(owner, type, blacklist)
+ generate(owner, type, blacklist)
-/datum/syndicate_contract/proc/generate(owner)
+/datum/syndicate_contract/proc/generate(owner, type, blacklist)
contract.owner = owner
- contract.find_target()
+ contract.find_target(null, blacklist)
- // 50/50 chance of getting at least one very high paying
- // contract.
- // High payout
- if (prob(18))
- contract.payout_bonus = rand(7,10)
- else if (prob(45))
- contract.payout_bonus = rand(1,3)
- else // Medium payout
- contract.payout_bonus = rand(2,6)
+ if (type == CONTRACT_PAYOUT_LARGE)
+ contract.payout_bonus = rand(9,13)
+ else if (type == CONTRACT_PAYOUT_MEDIUM)
+ contract.payout_bonus = rand(6,8)
+ else
+ contract.payout_bonus = rand(2,4)
contract.payout = rand(0, 2)
contract.generate_dropoff()
@@ -77,7 +74,7 @@
empty_pod.stay_after_drop = TRUE
empty_pod.reversing = TRUE
- empty_pod.explosionSize = list(0,0,2,1)
+ empty_pod.explosionSize = list(0,0,0,1)
empty_pod.leavingSound = 'sound/effects/podwoosh.ogg'
new /obj/effect/DPtarget(empty_pod_turf, empty_pod)
@@ -116,6 +113,12 @@
M.transferItemToLoc(W)
victim_belongings.Add(W)
+ var/obj/structure/closet/supplypod/extractionpod/pod = source
+
+ // Handle the pod returning
+ pod.send_up(pod)
+
+ // After pod is sent we start the victim narrative/heal.
handleVictimExperience(M)
// This is slightly delayed because of the sleep calls above to handle the narrative.
@@ -155,6 +158,9 @@
addtimer(CALLBACK(src, .proc/returnVictim, M), (60 * 10) * 5)
if (M.stat != DEAD)
+ // Heal them up - gets them out of crit/soft crit.
+ M.reagents.add_reagent(/datum/reagent/medicine/omnizine, 15)
+
M.flash_act()
M.confused += 10
M.blur_eyes(5)
diff --git a/code/modules/antagonists/wizard/equipment/soulstone.dm b/code/modules/antagonists/wizard/equipment/soulstone.dm
index 8556e889996..eda7430a90b 100644
--- a/code/modules/antagonists/wizard/equipment/soulstone.dm
+++ b/code/modules/antagonists/wizard/equipment/soulstone.dm
@@ -73,6 +73,9 @@
if(iscultist(user))
to_chat(user, "\"Come now, do not capture your bretheren's soul.\"")
return
+ if(purified && iscultist(user))
+ to_chat(user, "Holy magic resides within the stone, you cannot use it.")
+ return
log_combat(user, M, "captured [M.name]'s soul", src)
transfer_soul("VICTIM", M, user)
@@ -85,6 +88,9 @@
user.Unconscious(100)
to_chat(user, "Your body is wracked with debilitating pain!")
return
+ if(purified && iscultist(user))
+ to_chat(user, "Holy magic resides within the stone, you cannot use it.")
+ return
release_shades(user)
/obj/item/soulstone/proc/release_shades(mob/user)
@@ -127,6 +133,9 @@
to_chat(user, "An overwhelming feeling of dread comes over you as you attempt to place the soulstone into the shell. It would be wise to be rid of this quickly.")
user.Dizzy(30)
return
+ if(SS.purified && iscultist(user))
+ to_chat(user, "Holy magic resides within the stone, you cannot use it.")
+ return
SS.transfer_soul("CONSTRUCT",src,user)
SS.was_used()
else
diff --git a/code/modules/antagonists/wizard/equipment/spellbook.dm b/code/modules/antagonists/wizard/equipment/spellbook.dm
index 4d2574342fb..7761c663df8 100644
--- a/code/modules/antagonists/wizard/equipment/spellbook.dm
+++ b/code/modules/antagonists/wizard/equipment/spellbook.dm
@@ -34,7 +34,7 @@
for(var/obj/effect/proc_holder/spell/aspell in user.mind.spell_list)
if(initial(S.name) == initial(aspell.name)) // Not using directly in case it was learned from one spellbook then upgraded in another
if(aspell.spell_level >= aspell.level_max)
- to_chat(user, "This spell cannot be improved further.")
+ to_chat(user, "This spell cannot be improved further!")
return FALSE
else
aspell.name = initial(aspell.name)
@@ -56,7 +56,7 @@
to_chat(user, "You have further improved [aspell.name] into Instant [aspell.name].")
aspell.name = "Instant [aspell.name]"
if(aspell.spell_level >= aspell.level_max)
- to_chat(user, "This spell cannot be strengthened any further.")
+ to_chat(user, "This spell cannot be strengthened any further!")
SSblackbox.record_feedback("nested tally", "wizard_spell_improved", 1, list("[name]", "[aspell.spell_level]"))
return TRUE
//No same spell found - just learn it
@@ -78,7 +78,7 @@
/datum/spellbook_entry/proc/Refund(mob/living/carbon/human/user,obj/item/spellbook/book) //return point value or -1 for failure
var/area/wizard_station/A = GLOB.areas_by_type[/area/wizard_station]
if(!(user in A.contents))
- to_chat(user, "You can only refund spells at the wizard lair")
+ to_chat(user, "You can only refund spells at the wizard lair!")
return -1
if(!S)
S = new spell_type()
diff --git a/code/modules/assembly/health.dm b/code/modules/assembly/health.dm
index b8fccfbea84..5a132f033d4 100644
--- a/code/modules/assembly/health.dm
+++ b/code/modules/assembly/health.dm
@@ -5,13 +5,14 @@
materials = list(MAT_METAL=800, MAT_GLASS=200)
attachable = TRUE
- var/scanning = TRUE
+ var/scanning = FALSE
var/health_scan
var/alarm_health = HEALTH_THRESHOLD_CRIT
/obj/item/assembly/health/examine(mob/user)
. = ..()
- . += "Use a multitool to swap between \"detect death\" mode and \"detect critical state\" mode."
+ . += "Use it in hand to turn it off/on and Alt-click to swap between \"detect death\" mode and \"detect critical state\" mode."
+ . += "[src.scanning ? "The sensor is on and you can see [health_scan] displayed on the screen" : "The sensor is off"]."
/obj/item/assembly/health/activate()
if(!..())
@@ -29,14 +30,13 @@
update_icon()
return secured
-/obj/item/assembly/health/multitool_act(mob/living/user, obj/item/I)
+/obj/item/assembly/health/AltClick(mob/living/user)
if(alarm_health == HEALTH_THRESHOLD_CRIT)
alarm_health = HEALTH_THRESHOLD_DEAD
to_chat(user, "You toggle [src] to \"detect death\" mode.")
else
alarm_health = HEALTH_THRESHOLD_CRIT
to_chat(user, "You toggle [src] to \"detect critical state\" mode.")
- return TRUE
/obj/item/assembly/health/process()
if(!scanning || !secured)
@@ -69,36 +69,7 @@
STOP_PROCESSING(SSobj, src)
return
-/obj/item/assembly/health/ui_interact(mob/user as mob)//TODO: Change this to the wires thingy
+/obj/item/assembly/health/attack_self(mob/user)
. = ..()
- if(!secured)
- user.show_message("The [name] is unsecured!")
- return FALSE
- var/dat = "Health Sensor"
- dat += "
[scanning?"On":"Off"]"
- if(scanning && health_scan)
- dat += "
Health: [health_scan]"
- user << browse(dat, "window=hscan")
- onclose(user, "hscan")
-
-/obj/item/assembly/health/Topic(href, href_list)
- ..()
- if(!ismob(usr))
- return
-
- var/mob/user = usr
-
- if(!user.canUseTopic(src, BE_CLOSE))
- usr << browse(null, "window=hscan")
- onclose(usr, "hscan")
- return
-
- if(href_list["scanning"])
- toggle_scan()
-
- if(href_list["close"])
- usr << browse(null, "window=hscan")
- return
-
- attack_self(user)
- return
+ to_chat(user, "You toggle [src] [src.scanning ? "off" : "on"].")
+ toggle_scan()
diff --git a/code/modules/atmospherics/environmental/LINDA_turf_tile.dm b/code/modules/atmospherics/environmental/LINDA_turf_tile.dm
index e56a5584a2d..330fc0fe925 100644
--- a/code/modules/atmospherics/environmental/LINDA_turf_tile.dm
+++ b/code/modules/atmospherics/environmental/LINDA_turf_tile.dm
@@ -72,11 +72,13 @@
air.copy_from(copy)
/turf/return_air()
+ RETURN_TYPE(/datum/gas_mixture)
var/datum/gas_mixture/GM = new
GM.copy_from_turf(src)
return GM
/turf/open/return_air()
+ RETURN_TYPE(/datum/gas_mixture)
return air
/turf/open/return_analyzable_air()
diff --git a/code/modules/atmospherics/gasmixtures/gas_mixture.dm b/code/modules/atmospherics/gasmixtures/gas_mixture.dm
index 48e507d4599..dc62dc3dd73 100644
--- a/code/modules/atmospherics/gasmixtures/gas_mixture.dm
+++ b/code/modules/atmospherics/gasmixtures/gas_mixture.dm
@@ -266,6 +266,8 @@ GLOBAL_LIST_INIT(gaslist_cache, init_gaslist_cache())
return 1
/datum/gas_mixture/parse_gas_string(gas_string)
+ gas_string = SSair.preprocess_gas_string(gas_string)
+
var/list/gases = src.gases
var/list/gas = params2list(gas_string)
if(gas["TEMP"])
diff --git a/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm b/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm
index d1fcb504fdf..580966c6007 100644
--- a/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm
+++ b/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm
@@ -71,7 +71,7 @@
/obj/machinery/atmospherics/components/unary/cryo_cell/examine(mob/user) //this is leaving out everything but efficiency since they follow the same idea of "better beaker, better results"
. = ..()
if(in_range(user, src) || isobserver(user))
- . += "The status display reads: Efficiency at [efficiency*100]%."
+ . += "The status display reads: Efficiency at [efficiency*100]%."
/obj/machinery/atmospherics/components/unary/cryo_cell/Destroy()
QDEL_NULL(radio)
@@ -326,8 +326,8 @@
update_icon()
return
else if(I.tool_behaviour == TOOL_SCREWDRIVER)
- to_chat(user, "You can't access the maintenance panel while the pod is " \
- + (on ? "active" : (occupant ? "full" : "open")) + ".")
+ to_chat(user, "You can't access the maintenance panel while the pod is " \
+ + (on ? "active" : (occupant ? "full" : "open")) + "!")
return
return ..()
diff --git a/code/modules/atmospherics/machinery/components/unary_devices/thermomachine.dm b/code/modules/atmospherics/machinery/components/unary_devices/thermomachine.dm
index 16bf857de7c..47261e406e2 100644
--- a/code/modules/atmospherics/machinery/components/unary_devices/thermomachine.dm
+++ b/code/modules/atmospherics/machinery/components/unary_devices/thermomachine.dm
@@ -49,6 +49,13 @@
if(showpipe)
add_overlay(getpipeimage(icon, "scrub_cap", initialize_directions))
+/obj/machinery/atmospherics/components/unary/thermomachine/examine(mob/user)
+ . = ..()
+ . += "The thermostat is set to [target_temperature]K ([(T0C-target_temperature)*-1]C)."
+ if(in_range(user, src) || isobserver(user))
+ . += "The status display reads: Efficiency [(heat_capacity/5000)*100]%."
+ . += "Temperature range [min_temperature]K - [max_temperature]K ([(T0C-min_temperature)*-1]C - [(T0C-max_temperature)*-1]C)."
+
/obj/machinery/atmospherics/components/unary/thermomachine/process_atmos()
..()
if(!on || !nodes[1])
@@ -159,6 +166,12 @@
update_icon()
+/obj/machinery/atmospherics/components/unary/thermomachine/CtrlClick(mob/living/user)
+ if(!istype(user) || !user.canUseTopic(src, BE_CLOSE))
+ return
+ on = !on
+ update_icon()
+
/obj/machinery/atmospherics/components/unary/thermomachine/freezer
name = "freezer"
icon_state = "freezer"
@@ -192,6 +205,11 @@
L += M.rating
min_temperature = max(T0C - (initial(min_temperature) + L * 15), TCMB) //73.15K with T1 stock parts
+/obj/machinery/atmospherics/components/unary/thermomachine/freezer/AltClick(mob/living/user)
+ if(!istype(user) || !user.canUseTopic(src, BE_CLOSE))
+ return
+ target_temperature = min_temperature
+
/obj/machinery/atmospherics/components/unary/thermomachine/heater
name = "heater"
icon_state = "heater"
@@ -212,3 +230,8 @@
for(var/obj/item/stock_parts/micro_laser/M in component_parts)
L += M.rating
max_temperature = T20C + (initial(max_temperature) * L) //573.15K with T1 stock parts
+
+/obj/machinery/atmospherics/components/unary/thermomachine/heater/AltClick(mob/living/user)
+ if(!istype(user) || !user.canUseTopic(src, BE_CLOSE))
+ return
+ target_temperature = max_temperature
diff --git a/code/modules/atmospherics/machinery/components/unary_devices/vent_pump.dm b/code/modules/atmospherics/machinery/components/unary_devices/vent_pump.dm
index 5a6bdbf40d7..4189672b142 100644
--- a/code/modules/atmospherics/machinery/components/unary_devices/vent_pump.dm
+++ b/code/modules/atmospherics/machinery/components/unary_devices/vent_pump.dm
@@ -260,6 +260,8 @@
update_icon()
pipe_vision_img = image(src, loc, layer = ABOVE_HUD_LAYER, dir = dir)
pipe_vision_img.plane = ABOVE_HUD_PLANE
+ investigate_log("was [welded ? "welded shut" : "unwelded"] by [key_name(user)]", INVESTIGATE_ATMOS)
+ add_fingerprint(user)
return TRUE
/obj/machinery/atmospherics/components/unary/vent_pump/can_unwrench(mob/user)
diff --git a/code/modules/atmospherics/machinery/components/unary_devices/vent_scrubber.dm b/code/modules/atmospherics/machinery/components/unary_devices/vent_scrubber.dm
index 36f1816e9cc..b474df7f430 100644
--- a/code/modules/atmospherics/machinery/components/unary_devices/vent_scrubber.dm
+++ b/code/modules/atmospherics/machinery/components/unary_devices/vent_scrubber.dm
@@ -276,6 +276,8 @@
update_icon()
pipe_vision_img = image(src, loc, layer = ABOVE_HUD_LAYER, dir = dir)
pipe_vision_img.plane = ABOVE_HUD_PLANE
+ investigate_log("was [welded ? "welded shut" : "unwelded"] by [key_name(user)]", INVESTIGATE_ATMOS)
+ add_fingerprint(user)
return TRUE
/obj/machinery/atmospherics/components/unary/vent_scrubber/can_unwrench(mob/user)
diff --git a/code/modules/atmospherics/machinery/portable/canister.dm b/code/modules/atmospherics/machinery/portable/canister.dm
index 9ddd9db7ebd..6b1a9787782 100644
--- a/code/modules/atmospherics/machinery/portable/canister.dm
+++ b/code/modules/atmospherics/machinery/portable/canister.dm
@@ -299,7 +299,7 @@
if(I.use_tool(src, user, 30, volume=50))
deconstruct(TRUE)
else
- to_chat(user, "You cannot slice [src] apart when it isn't broken.")
+ to_chat(user, "You cannot slice [src] apart when it isn't broken!")
return TRUE
diff --git a/code/modules/atmospherics/machinery/portable/portable_atmospherics.dm b/code/modules/atmospherics/machinery/portable/portable_atmospherics.dm
index a5ee4cb2d8c..985f6762246 100644
--- a/code/modules/atmospherics/machinery/portable/portable_atmospherics.dm
+++ b/code/modules/atmospherics/machinery/portable/portable_atmospherics.dm
@@ -102,8 +102,8 @@
/obj/machinery/portable_atmospherics/examine(mob/user)
. = ..()
if(holding)
- . += {"\The [src] contains [holding]. Alt-click [src] to remove it.
- Click [src] with another gas tank to hot swap [holding]."}
+ . += "\The [src] contains [holding]. Alt-click [src] to remove it."+\
+ "Click [src] with another gas tank to hot swap [holding]."
/obj/machinery/portable_atmospherics/proc/replace_tank(mob/living/user, close_valve, obj/item/tank/new_tank)
if(holding)
diff --git a/code/modules/awaymissions/capture_the_flag.dm b/code/modules/awaymissions/capture_the_flag.dm
index 92c730fbcf6..86a2f3d0bd1 100644
--- a/code/modules/awaymissions/capture_the_flag.dm
+++ b/code/modules/awaymissions/capture_the_flag.dm
@@ -54,10 +54,10 @@
//ATTACK HAND IGNORING PARENT RETURN VALUE
/obj/item/twohanded/ctf/attack_hand(mob/living/user)
if(!is_ctf_target(user) && !anyonecanpickup)
- to_chat(user, "Non players shouldn't be moving the flag!")
+ to_chat(user, "Non-players shouldn't be moving the flag!")
return
if(team in user.faction)
- to_chat(user, "You can't move your own flag!")
+ to_chat(user, "You can't move your own flag!")
return
if(loc == user)
if(!user.dropItemToGround(src))
@@ -227,7 +227,7 @@
return
if(user.ckey in team_members)
if(user.ckey in recently_dead_ckeys)
- to_chat(user, "It must be more than [DisplayTimeText(respawn_cooldown)] from your last death to respawn!")
+ to_chat(user, "It must be more than [DisplayTimeText(respawn_cooldown)] from your last death to respawn!")
return
var/client/new_team_member = user.client
if(user.mind && user.mind.current)
@@ -239,10 +239,10 @@
if(CTF == src || CTF.ctf_enabled == FALSE)
continue
if(user.ckey in CTF.team_members)
- to_chat(user, "No switching teams while the round is going!")
+ to_chat(user, "No switching teams while the round is going!")
return
if(CTF.team_members.len < src.team_members.len)
- to_chat(user, "[src.team] has more team members than [CTF.team]. Try joining [CTF.team] team to even things up.")
+ to_chat(user, "[src.team] has more team members than [CTF.team]! Try joining [CTF.team] team to even things up.")
return
team_members |= user.ckey
var/client/new_team_member = user.client
diff --git a/code/modules/awaymissions/mission_code/snowdin.dm b/code/modules/awaymissions/mission_code/snowdin.dm
index 7df384f2d6d..207ced130a8 100644
--- a/code/modules/awaymissions/mission_code/snowdin.dm
+++ b/code/modules/awaymissions/mission_code/snowdin.dm
@@ -171,7 +171,7 @@
if(C.reagents.total_volume >= C.volume)
to_chat(user, "[C] is full.")
return
- C.reagents.add_reagent("plasma", rand(5, 10))
+ C.reagents.add_reagent(/datum/reagent/toxin/plasma, rand(5, 10))
user.visible_message("[user] scoops some plasma from the [src] with \the [C].", "You scoop out some plasma from the [src] using \the [C].")
/turf/open/lava/plasma/burn_stuff(AM)
diff --git a/code/modules/cargo/bounty_console.dm b/code/modules/cargo/bounty_console.dm
index f8446861c5b..ea98605506d 100644
--- a/code/modules/cargo/bounty_console.dm
+++ b/code/modules/cargo/bounty_console.dm
@@ -23,6 +23,8 @@
/obj/item/paper/bounty_printout/Initialize()
. = ..()
info = "Nanotrasen Cargo Bounties
"
+ update_icon()
+
for(var/datum/bounty/B in GLOB.bounties_list)
if(B.claimed)
continue
diff --git a/code/modules/cargo/exports/gear.dm b/code/modules/cargo/exports/gear.dm
index 125e0f708be..9d3e18df00d 100644
--- a/code/modules/cargo/exports/gear.dm
+++ b/code/modules/cargo/exports/gear.dm
@@ -81,3 +81,19 @@
cost = 100
unit_name = "bomb suit"
export_types = list(/obj/item/clothing/suit/bomb_suit)
+
+/datum/export/gear/lizardboots
+ cost = 350
+ unit_name = "lizard skin boots"
+ export_types = list(/obj/item/clothing/shoes/cowboy/lizard)
+ include_subtypes = FALSE
+
+/datum/export/gear/lizardmasterwork
+ cost = 1000
+ unit_name = "Hugs-the-Feet lizard boots"
+ export_types = list(/obj/item/clothing/shoes/cowboy/lizard/masterwork)
+
+/datum/export/gear/bilton
+ cost = 2500
+ unit_name = "bilton wrangler boots"
+ export_types = list(/obj/item/clothing/shoes/cowboy/fancy)
diff --git a/code/modules/cargo/gondolapod.dm b/code/modules/cargo/gondolapod.dm
index 80301c036d6..beba7d9e8ee 100644
--- a/code/modules/cargo/gondolapod.dm
+++ b/code/modules/cargo/gondolapod.dm
@@ -44,9 +44,9 @@
/mob/living/simple_animal/pet/gondola/gondolapod/examine(mob/user)
. = ..()
if (contents.len)
- . += "It looks like it hasn't made its delivery yet."
+ . += "It looks like it hasn't made its delivery yet."
else
- . += "It looks like it has already made its delivery."
+ . += "It looks like it has already made its delivery."
/mob/living/simple_animal/pet/gondola/gondolapod/verb/check()
set name = "Count Contents"
diff --git a/code/modules/cargo/packs.dm b/code/modules/cargo/packs.dm
index 6e250e27074..fdc61749500 100644
--- a/code/modules/cargo/packs.dm
+++ b/code/modules/cargo/packs.dm
@@ -1217,7 +1217,7 @@
/obj/item/reagent_containers/pill/insulin,
/obj/item/stack/medical/gauze,
/obj/item/storage/box/beakers,
- /obj/item/storage/box/medsprays,
+ /obj/item/storage/box/medigels,
/obj/item/storage/box/syringes,
/obj/item/storage/box/bodybags,
/obj/item/storage/firstaid/regular,
@@ -1249,7 +1249,7 @@
desc = "Do you want to perform surgery, but don't have one of those fancy shmancy degrees? Just get started with this crate containing a medical duffelbag, Sterilizine spray and collapsible roller bed."
cost = 3000
contains = list(/obj/item/storage/backpack/duffelbag/med/surgery,
- /obj/item/reagent_containers/medspray/sterilizine,
+ /obj/item/reagent_containers/medigel/sterilizine,
/obj/item/roller)
crate_name = "surgical supplies crate"
@@ -1577,6 +1577,13 @@
contains = list(/obj/item/vending_refill/assist)
crate_name = "vendomat supply crate"
+/datum/supply_pack/service/emptycrate
+ name = "Empty Crate"
+ desc = "It's an empty crate, for all your storage needs."
+ cost = 700
+ contains = list()
+ crate_name = "crate"
+
//////////////////////////////////////////////////////////////////////////////
//////////////////////////// Organic /////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
@@ -2114,6 +2121,16 @@
contains = list(/obj/item/storage/box/lasertagpins)
crate_name = "laser tag crate"
+/datum/supply_pack/costumes_toys/mech_suits
+ name = "Mech Pilot's Suit Crate"
+ desc = "Suits for piloting big robots. Contains all three colors!"
+ cost = 1500 //state-of-the-art technology doesn't come cheap
+ contains = list(/obj/item/clothing/under/mech_suit,
+ /obj/item/clothing/under/mech_suit/white,
+ /obj/item/clothing/under/mech_suit/blue)
+ crate_name = "mech pilot's suit crate"
+ crate_type = /obj/structure/closet/crate/wooden
+
/datum/supply_pack/costumes_toys/costume_original
name = "Original Costume Crate"
desc = "Reenact Shakespearean plays with this assortment of outfits. Contains eight different costumes!"
diff --git a/code/modules/cargo/supplypod.dm b/code/modules/cargo/supplypod.dm
index 8dd73e72e23..853e17e75c5 100644
--- a/code/modules/cargo/supplypod.dm
+++ b/code/modules/cargo/supplypod.dm
@@ -239,6 +239,10 @@
handleReturningClose(holder, TRUE)
/obj/structure/closet/supplypod/extractionpod/close(atom/movable/holder) //handles closing, and returns pod - deletes itself when returned
+ . = ..()
+ return
+
+/obj/structure/closet/supplypod/extractionpod/proc/send_up(atom/movable/holder)
if (!holder)
holder = src
diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm
index f6d22b41d1f..f37c72d740d 100644
--- a/code/modules/client/preferences.dm
+++ b/code/modules/client/preferences.dm
@@ -72,10 +72,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
var/preferred_ai_core_display = "Blue"
var/prefered_security_department = SEC_DEPT_RANDOM
- //Quirk list
- var/list/positive_quirks = list()
- var/list/negative_quirks = list()
- var/list/neutral_quirks = list()
+ //Quirk list
var/list/all_quirks = list()
//Job preferences 2.0 - indexed by job title , no key or value implies never
@@ -835,7 +832,6 @@ GLOBAL_LIST_EMPTY(preferences_datums)
if(!SSquirks.quirks.len)
dat += "The quirk subsystem hasn't finished initializing, please hold..."
dat += "Done
"
-
else
dat += "Choose quirk setup
"
dat += "Left-click to add or remove quirks. You need negative quirks to have positive ones.
\
@@ -843,7 +839,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
dat += "
Done"
dat += "
"
dat += "
Current quirks: [all_quirks.len ? all_quirks.Join(", ") : "None"]"
- dat += "
[positive_quirks.len] / [MAX_QUIRKS] max positive quirks
\
+ dat += "[GetPositiveQuirkCount()] / [MAX_QUIRKS] max positive quirks
\
Quirk balance remaining: [GetQuirkBalance()]
"
for(var/V in SSquirks.quirks)
var/datum/quirk/T = SSquirks.quirks[V]
@@ -893,6 +889,12 @@ GLOBAL_LIST_EMPTY(preferences_datums)
bal -= initial(T.value)
return bal
+/datum/preferences/proc/GetPositiveQuirkCount()
+ . = 0
+ for(var/q in all_quirks)
+ if(SSquirks.quirk_points[q] > 0)
+ .++
+
/datum/preferences/Topic(href, href_list, hsrc) //yeah, gotta do this I guess..
. = ..()
if(href_list["close"])
@@ -959,42 +961,23 @@ GLOBAL_LIST_EMPTY(preferences_datums)
to_chat(user, "[quirk] is incompatible with [Q].")
return
var/value = SSquirks.quirk_points[quirk]
- if(value == 0)
- if(quirk in neutral_quirks)
- neutral_quirks -= quirk
- all_quirks -= quirk
- else
- neutral_quirks += quirk
- all_quirks += quirk
+ var/balance = GetQuirkBalance()
+ if(quirk in all_quirks)
+ if(balance + value < 0)
+ to_chat(user, "Refunding this would cause you to go below your balance!")
+ return
+ all_quirks -= quirk
else
- var/balance = GetQuirkBalance()
- if(quirk in positive_quirks)
- positive_quirks -= quirk
- all_quirks -= quirk
- else if(quirk in negative_quirks)
- if(balance + value < 0)
- to_chat(user, "Refunding this would cause you to go below your balance!")
- return
- negative_quirks -= quirk
- all_quirks -= quirk
- else if(value > 0)
- if(positive_quirks.len >= MAX_QUIRKS)
- to_chat(user, "You can't have more than [MAX_QUIRKS] positive quirks!")
- return
- if(balance - value < 0)
- to_chat(user, "You don't have enough balance to gain this quirk!")
- return
- positive_quirks += quirk
- all_quirks += quirk
- else
- negative_quirks += quirk
- all_quirks += quirk
+ if(GetPositiveQuirkCount() >= MAX_QUIRKS)
+ to_chat(user, "You can't have more than [MAX_QUIRKS] positive quirks!")
+ return
+ if(balance - value < 0)
+ to_chat(user, "You don't have enough balance to gain this quirk!")
+ return
+ all_quirks += quirk
SetQuirks(user)
if("reset")
all_quirks = list()
- positive_quirks = list()
- negative_quirks = list()
- neutral_quirks = list()
SetQuirks(user)
else
SetQuirks(user)
diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm
index ad50b11c554..10cceb2f741 100644
--- a/code/modules/client/preferences_savefile.dm
+++ b/code/modules/client/preferences_savefile.dm
@@ -327,9 +327,6 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
//Quirks
S["all_quirks"] >> all_quirks
- S["positive_quirks"] >> positive_quirks
- S["negative_quirks"] >> negative_quirks
- S["neutral_quirks"] >> neutral_quirks
//try to fix any outdated data if necessary
if(needs_update >= 0)
@@ -402,9 +399,6 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
job_preferences -= j
all_quirks = SANITIZE_LIST(all_quirks)
- positive_quirks = SANITIZE_LIST(positive_quirks)
- negative_quirks = SANITIZE_LIST(negative_quirks)
- neutral_quirks = SANITIZE_LIST(neutral_quirks)
return TRUE
@@ -464,9 +458,6 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
//Quirks
WRITE_FILE(S["all_quirks"] , all_quirks)
- WRITE_FILE(S["positive_quirks"] , positive_quirks)
- WRITE_FILE(S["negative_quirks"] , negative_quirks)
- WRITE_FILE(S["neutral_quirks"] , neutral_quirks)
return TRUE
diff --git a/code/modules/client/verbs/suicide.dm b/code/modules/client/verbs/suicide.dm
index e08e9c0e483..7f7c7eeaba7 100644
--- a/code/modules/client/verbs/suicide.dm
+++ b/code/modules/client/verbs/suicide.dm
@@ -241,17 +241,17 @@
if(CONSCIOUS)
return TRUE
if(SOFT_CRIT)
- to_chat(src, "You can't commit suicide while in a critical condition!")
+ to_chat(src, "You can't commit suicide while in a critical condition!")
if(UNCONSCIOUS)
- to_chat(src, "You need to be conscious to commit suicide!")
+ to_chat(src, "You need to be conscious to commit suicide!")
if(DEAD)
- to_chat(src, "You're already dead!")
+ to_chat(src, "You're already dead!")
return
/mob/living/carbon/canSuicide()
if(!..())
return
if(!(mobility_flags & MOBILITY_USE)) //just while I finish up the new 'fun' suiciding verb. This is to prevent metagaming via suicide
- to_chat(src, "You can't commit suicide whilst immobile! ((You can type Ghost instead however.))")
+ to_chat(src, "You can't commit suicide whilst immobile! ((You can type Ghost instead however.))")
return
return TRUE
diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm
index 560a8d48966..45611e39b99 100644
--- a/code/modules/clothing/clothing.dm
+++ b/code/modules/clothing/clothing.dm
@@ -20,7 +20,6 @@
var/active_sound = null
var/toggle_cooldown = null
var/cooldown = 0
- var/scan_reagents = 0 //Can the wearer see reagents while it's equipped?
var/blocks_shove_knockdown = FALSE //Whether wearing the clothing item blocks the ability for shove to knock down.
diff --git a/code/modules/clothing/glasses/_glasses.dm b/code/modules/clothing/glasses/_glasses.dm
index c2f8253c426..4ccdc7da0b2 100644
--- a/code/modules/clothing/glasses/_glasses.dm
+++ b/code/modules/clothing/glasses/_glasses.dm
@@ -45,13 +45,14 @@
/obj/item/clothing/glasses/proc/thermal_overload()
if(ishuman(src.loc))
var/mob/living/carbon/human/H = src.loc
+ var/obj/item/organ/eyes/eyes = H.getorganslot(ORGAN_SLOT_EYES)
if(!(HAS_TRAIT(H, TRAIT_BLIND)))
if(H.glasses == src)
to_chat(H, "[src] overloads and blinds you!")
H.flash_act(visual = 1)
H.blind_eyes(3)
H.blur_eyes(5)
- H.adjust_eye_damage(5)
+ eyes.applyOrganDamage(5)
/obj/item/clothing/glasses/meson
name = "optical meson scanner"
@@ -73,6 +74,7 @@
icon_state = "nvgmeson"
item_state = "nvgmeson"
darkness_view = 8
+ flash_protect = -1
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
glass_colour_type = /datum/client_colour/glass_colour/green
@@ -93,7 +95,7 @@
desc = "A pair of snazzy goggles used to protect against chemical spills. Fitted with an analyzer for scanning items and reagents."
icon_state = "purple"
item_state = "glasses"
- scan_reagents = TRUE //You can see reagents while wearing science goggles
+ clothing_flags = SCAN_REAGENTS //You can see reagents while wearing science goggles
actions_types = list(/datum/action/item_action/toggle_research_scanner)
glass_colour_type = /datum/client_colour/glass_colour/purple
resistance_flags = ACID_PROOF
@@ -109,6 +111,7 @@
icon_state = "night"
item_state = "glasses"
darkness_view = 8
+ flash_protect = -1
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
glass_colour_type = /datum/client_colour/glass_colour/green
@@ -197,7 +200,7 @@
/obj/item/clothing/glasses/sunglasses/reagent
name = "beer goggles"
desc = "A pair of sunglasses outfitted with apparatus to scan reagents, as well as providing an innate understanding of liquid viscosity while in motion."
- scan_reagents = TRUE
+ clothing_flags = SCAN_REAGENTS
/obj/item/clothing/glasses/sunglasses/reagent/equipped(mob/user, slot)
. = ..()
@@ -325,7 +328,7 @@
item_state = "glasses"
vision_flags = SEE_MOBS
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_VISIBLE
- flash_protect = 0
+ flash_protect = -1
glass_colour_type = /datum/client_colour/glass_colour/red
/obj/item/clothing/glasses/thermal/emp_act(severity)
@@ -338,12 +341,10 @@
name = "syndicate xray goggles"
desc = "A pair of xray goggles manufactured by the Syndicate."
vision_flags = SEE_TURFS|SEE_MOBS|SEE_OBJS
- flash_protect = -1
/obj/item/clothing/glasses/thermal/syndi //These are now a traitor item, concealed as mesons. -Pete
name = "chameleon thermals"
desc = "A pair of thermal optic goggles with an onboard chameleon generator."
- flash_protect = -1
var/datum/action/item_action/chameleon/change/chameleon_action
@@ -414,9 +415,9 @@
item_state = "godeye"
vision_flags = SEE_TURFS|SEE_MOBS|SEE_OBJS
darkness_view = 8
- scan_reagents = TRUE
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
resistance_flags = LAVA_PROOF | FIRE_PROOF
+ clothing_flags = SCAN_REAGENTS
/obj/item/clothing/glasses/godeye/Initialize()
. = ..()
diff --git a/code/modules/clothing/glasses/hud.dm b/code/modules/clothing/glasses/hud.dm
index 46288796e41..a4b74f3e46f 100644
--- a/code/modules/clothing/glasses/hud.dm
+++ b/code/modules/clothing/glasses/hud.dm
@@ -43,6 +43,7 @@
icon_state = "healthhudnight"
item_state = "glasses"
darkness_view = 8
+ flash_protect = -1
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_VISIBLE
glass_colour_type = /datum/client_colour/glass_colour/green
@@ -68,6 +69,7 @@
icon_state = "diagnostichudnight"
item_state = "glasses"
darkness_view = 8
+ flash_protect = -1
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_VISIBLE
glass_colour_type = /datum/client_colour/glass_colour/green
@@ -129,6 +131,7 @@
desc = "An advanced heads-up display which provides id data and vision in complete darkness."
icon_state = "securityhudnight"
darkness_view = 8
+ flash_protect = -1
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_VISIBLE
glass_colour_type = /datum/client_colour/glass_colour/green
diff --git a/code/modules/clothing/head/jobs.dm b/code/modules/clothing/head/jobs.dm
index 88f5805d70f..d2aef786a27 100644
--- a/code/modules/clothing/head/jobs.dm
+++ b/code/modules/clothing/head/jobs.dm
@@ -93,7 +93,7 @@
to_chat(user, "You slip a candy corn from your hat.")
candy_cooldown = world.time+1200
else
- to_chat(user, "You just took a candy corn! You should wait a couple minutes, lest you burn through your stash.")
+ to_chat(user, "You just took a candy corn! You should wait a couple minutes, lest you burn through your stash.")
//Mime
diff --git a/code/modules/clothing/head/misc.dm b/code/modules/clothing/head/misc.dm
index 6149161c5ee..f6a657c4e10 100644
--- a/code/modules/clothing/head/misc.dm
+++ b/code/modules/clothing/head/misc.dm
@@ -122,6 +122,7 @@
icon_state = "flat_cap"
item_state = "detective"
+
/obj/item/clothing/head/pirate
name = "pirate hat"
desc = "Yarr."
diff --git a/code/modules/clothing/head/misc_special.dm b/code/modules/clothing/head/misc_special.dm
index 3b75de4738a..54bdbc6b25f 100644
--- a/code/modules/clothing/head/misc_special.dm
+++ b/code/modules/clothing/head/misc_special.dm
@@ -271,7 +271,9 @@
/obj/item/clothing/head/foilhat/Initialize(mapload)
. = ..()
if(!warped)
- AddComponent(/datum/component/anti_magic, FALSE, FALSE, TRUE, ITEM_SLOT_HEAD, 6, TRUE, null, CALLBACK(src, .proc/warp_up))
+ AddComponent(/datum/component/anti_magic, FALSE, FALSE, TRUE, ITEM_SLOT_HEAD, 6, TRUE, null, CALLBACK(src, .proc/warp_up))
+ else
+ warp_up()
/obj/item/clothing/head/foilhat/equipped(mob/living/carbon/human/user, slot)
. = ..()
@@ -304,9 +306,7 @@
name = "scorched tinfoil hat"
desc = "A badly warped up hat. Quite unprobable this will still work against any of fictional and contemporary dangers it used to."
warped = TRUE
- var/datum/component/anti_magic/C = GetComponent(/datum/component/anti_magic)
- C.RemoveComponent()
- if(!isliving(loc))
+ if(!isliving(loc) || !paranoia)
return
var/mob/living/target = loc
if(target.get_item_by_slot(SLOT_HEAD) != src)
diff --git a/code/modules/clothing/neck/_neck.dm b/code/modules/clothing/neck/_neck.dm
index 98e7510a7fa..58c070aa412 100644
--- a/code/modules/clothing/neck/_neck.dm
+++ b/code/modules/clothing/neck/_neck.dm
@@ -201,6 +201,7 @@
/obj/item/clothing/neck/petcollar/mob_can_equip(mob/M, mob/equipper, slot, disable_warning = 0)
if(ishuman(M))
return FALSE
+ return ..()
/obj/item/clothing/neck/petcollar/attack_self(mob/user)
tagname = copytext(sanitize(input(user, "Would you like to change the name on the tag?", "Name your new pet", "Spot") as null|text),1,MAX_NAME_LEN)
diff --git a/code/modules/clothing/outfits/plasmaman.dm b/code/modules/clothing/outfits/plasmaman.dm
index 9c2ddd797ea..1c5c309b348 100644
--- a/code/modules/clothing/outfits/plasmaman.dm
+++ b/code/modules/clothing/outfits/plasmaman.dm
@@ -113,4 +113,16 @@
head = /obj/item/clothing/head/helmet/space/plasmaman/atmospherics
uniform = /obj/item/clothing/under/plasmaman/atmospherics
+/datum/outfit/plasmaman/mime
+ name = "Plasmamime"
+ head = /obj/item/clothing/head/helmet/space/plasmaman/mime
+ uniform = /obj/item/clothing/under/plasmaman/mime
+ mask = /obj/item/clothing/mask/gas/mime
+
+/datum/outfit/plasmaman/clown
+ name = "Plasmaclown"
+
+ head = /obj/item/clothing/head/helmet/space/plasmaman/clown
+ uniform = /obj/item/clothing/under/plasmaman/clown
+ mask = /obj/item/clothing/mask/gas/clown_hat
\ No newline at end of file
diff --git a/code/modules/clothing/outfits/standard.dm b/code/modules/clothing/outfits/standard.dm
index cc9cff7f53a..d44c43899aa 100644
--- a/code/modules/clothing/outfits/standard.dm
+++ b/code/modules/clothing/outfits/standard.dm
@@ -369,7 +369,7 @@
/datum/outfit/death_commando
name = "Death Commando"
- uniform = /obj/item/clothing/under/color/green
+ uniform = /obj/item/clothing/under/rank/centcom_commander
suit = /obj/item/clothing/suit/space/hardsuit/deathsquad
shoes = /obj/item/clothing/shoes/combat/swat
gloves = /obj/item/clothing/gloves/combat
diff --git a/code/modules/clothing/shoes/bananashoes.dm b/code/modules/clothing/shoes/bananashoes.dm
index c4d06ea14c3..eb0437cc1c5 100644
--- a/code/modules/clothing/shoes/bananashoes.dm
+++ b/code/modules/clothing/shoes/bananashoes.dm
@@ -35,7 +35,7 @@
if(sheet_amount)
to_chat(user, "You retrieve [sheet_amount] sheets of bananium from the prototype shoes.")
else
- to_chat(user, "You cannot retrieve any bananium from the prototype shoes.")
+ to_chat(user, "You cannot retrieve any bananium from the prototype shoes!")
/obj/item/clothing/shoes/clown_shoes/banana_shoes/examine(mob/user)
. = ..()
diff --git a/code/modules/clothing/shoes/miscellaneous.dm b/code/modules/clothing/shoes/miscellaneous.dm
index b4012081f0d..03ad53f3a08 100644
--- a/code/modules/clothing/shoes/miscellaneous.dm
+++ b/code/modules/clothing/shoes/miscellaneous.dm
@@ -101,7 +101,7 @@
if(!isliving(user))
return
if(user.get_active_held_item() != src)
- to_chat(user, "You must hold the [src] in your hand to do this.")
+ to_chat(user, "You must hold the [src] in your hand to do this!")
return
if (!enabled_waddle)
to_chat(user, "You switch off the waddle dampeners!")
@@ -336,3 +336,85 @@
icon_state = "rus_shoes"
item_state = "rus_shoes"
pocket_storage_component_path = /datum/component/storage/concrete/pockets/shoes
+
+/obj/item/clothing/shoes/cowboy
+ name = "cowboy boots"
+ desc = "A small sticker lets you know they've been inspected for snakes, It is unclear how long ago the inspection took place..."
+ icon_state = "cowboy_brown"
+ permeability_coefficient = 0.05 //these are quite tall
+ pocket_storage_component_path = /datum/component/storage/concrete/pockets/shoes
+ custom_price = 35 //poor assistants cant afford 50 credits
+ var/list/occupants = list()
+ var/max_occupants = 4
+
+/obj/item/clothing/shoes/cowboy/Initialize()
+ . = ..()
+ if(prob(2))
+ var/mob/living/simple_animal/hostile/retaliate/poison/snake/bootsnake = new/mob/living/simple_animal/hostile/retaliate/poison/snake(src)
+ occupants += bootsnake
+
+
+/obj/item/clothing/shoes/cowboy/equipped(mob/living/carbon/user, slot)
+ . = ..()
+ if(slot == SLOT_SHOES)
+ for(var/mob/living/occupant in occupants)
+ occupant.forceMove(user.drop_location())
+ user.visible_message("[user] recoils as something slithers out of [src].", " You feel a sudden stabbing pain in your [pick("foot", "toe", "ankle")]!")
+ user.Knockdown(20) //Is one second paralyze better here? I feel you would fall on your ass in some fashion.
+ user.apply_damage(5, BRUTE, pick(BODY_ZONE_R_LEG, BODY_ZONE_L_LEG))
+ if(istype(occupant, /mob/living/simple_animal/hostile/retaliate/poison))
+ user.reagents.add_reagent(/datum/reagent/toxin, 7)
+ occupants.Cut()
+
+/obj/item/clothing/shoes/cowboy/MouseDrop_T(mob/living/target, mob/living/user)
+ . = ..()
+ if(user.stat || !(user.mobility_flags & MOBILITY_USE) || user.restrained() || !Adjacent(user) || !user.Adjacent(target) || target.stat == DEAD)
+ return
+ if(occupants.len >= max_occupants)
+ to_chat(user, "[src] are full!")
+ return
+ if(istype(target, /mob/living/simple_animal/hostile/retaliate/poison/snake) || istype(target, /mob/living/simple_animal/hostile/headcrab) || istype(target, /mob/living/carbon/alien/larva))
+ occupants += target
+ target.forceMove(src)
+ to_chat(user, "[target] slithers into [src]")
+
+/obj/item/clothing/shoes/cowboy/container_resist(mob/living/user)
+ if(!do_after(user, 10, target = user))
+ return
+ user.forceMove(user.drop_location())
+ occupants -= user
+
+/obj/item/clothing/shoes/cowboy/white
+ name = "white cowboy boots"
+ icon_state = "cowboy_white"
+
+/obj/item/clothing/shoes/cowboy/black
+ name = "black cowboy boots"
+ desc = "You get the feeling someone might have been hanged in these boots."
+ icon_state = "cowboy_black"
+
+/obj/item/clothing/shoes/cowboy/fancy
+ name = "bilton wrangler boots"
+ desc = "A pair of authentic haute couture boots from Japanifornia. You doubt they have ever been close to cattle."
+ icon_state = "cowboy_fancy"
+ permeability_coefficient = 0.08
+
+/obj/item/clothing/shoes/cowboy/lizard
+ name = "lizard skin boots"
+ desc = "You can hear a faint hissing from inside the boots; you hope it is just a mournful ghost."
+ icon_state = "lizardboots_green"
+ armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 40, "acid" = 0) //lizards like to stay warm
+
+/obj/item/clothing/shoes/cowboy/lizard/masterwork
+ name = "\improper Hugs-The-Feet lizard skin boots"
+ desc = "A pair of masterfully crafted lizard skin boots. Finally a good application for the station's most bothersome inhabitants."
+ icon_state = "lizardboots_blue"
+
+/obj/effect/spawner/lootdrop/lizardboots
+ name = "random lizard boot quality"
+ desc = "Which ever gets picked, the lizard race loses"
+ icon = 'icons/obj/clothing/shoes.dmi'
+ icon_state = "lizardboots_green"
+ loot = list(
+ /obj/item/clothing/shoes/cowboy/lizard = 7,
+ /obj/item/clothing/shoes/cowboy/lizard/masterwork = 1)
diff --git a/code/modules/clothing/spacesuits/hardsuit.dm b/code/modules/clothing/spacesuits/hardsuit.dm
index cd8ba56fc53..cd50552f391 100644
--- a/code/modules/clothing/spacesuits/hardsuit.dm
+++ b/code/modules/clothing/spacesuits/hardsuit.dm
@@ -423,7 +423,7 @@
/obj/item/clothing/suit/space/hardsuit/wizard/Initialize()
. = ..()
- AddComponent(/datum/component/anti_magic, TRUE, FALSE, FALSE, null, INFINITY, FALSE)
+ AddComponent(/datum/component/anti_magic, TRUE, FALSE, FALSE, ITEM_SLOT_OCLOTHING, INFINITY, FALSE)
//Medical hardsuit
@@ -435,7 +435,7 @@
item_color = "medical"
flash_protect = 0
armor = list("melee" = 30, "bullet" = 5, "laser" = 10, "energy" = 5, "bomb" = 10, "bio" = 100, "rad" = 60, "fire" = 60, "acid" = 75)
- scan_reagents = TRUE
+ clothing_flags = STOPSPRESSUREDAMAGE | THICKMATERIAL | SCAN_REAGENTS
/obj/item/clothing/suit/space/hardsuit/medical
icon_state = "hardsuit-medical"
@@ -457,7 +457,7 @@
max_heat_protection_temperature = FIRE_SUIT_MAX_TEMP_PROTECT
armor = list("melee" = 30, "bullet" = 5, "laser" = 10, "energy" = 5, "bomb" = 100, "bio" = 100, "rad" = 60, "fire" = 60, "acid" = 80)
var/obj/machinery/doppler_array/integrated/bomb_radar
- scan_reagents = TRUE
+ clothing_flags = STOPSPRESSUREDAMAGE | THICKMATERIAL | SCAN_REAGENTS
actions_types = list(/datum/action/item_action/toggle_helmet_light, /datum/action/item_action/toggle_research_scanner)
/obj/item/clothing/head/helmet/space/hardsuit/rd/Initialize()
diff --git a/code/modules/clothing/spacesuits/miscellaneous.dm b/code/modules/clothing/spacesuits/miscellaneous.dm
index e767c0f2038..1d5b4dbabd3 100644
--- a/code/modules/clothing/spacesuits/miscellaneous.dm
+++ b/code/modules/clothing/spacesuits/miscellaneous.dm
@@ -331,7 +331,7 @@ Contains:
/obj/item/clothing/suit/space/hardsuit/ert/paranormal/Initialize()
. = ..()
- AddComponent(/datum/component/anti_magic, FALSE, FALSE, TRUE)
+ AddComponent(/datum/component/anti_magic, FALSE, FALSE, TRUE, ITEM_SLOT_OCLOTHING)
/obj/item/clothing/suit/space/hardsuit/ert/paranormal
name = "paranormal response team hardsuit"
@@ -344,7 +344,7 @@ Contains:
/obj/item/clothing/suit/space/hardsuit/ert/paranormal/Initialize()
. = ..()
- AddComponent(/datum/component/anti_magic, TRUE, TRUE)
+ AddComponent(/datum/component/anti_magic, TRUE, TRUE, TRUE, ITEM_SLOT_OCLOTHING)
/obj/item/clothing/suit/space/hardsuit/ert/paranormal/inquisitor
name = "inquisitor's hardsuit"
diff --git a/code/modules/clothing/spacesuits/plasmamen.dm b/code/modules/clothing/spacesuits/plasmamen.dm
index ce3e866b1f7..f83352dd3ef 100644
--- a/code/modules/clothing/spacesuits/plasmamen.dm
+++ b/code/modules/clothing/spacesuits/plasmamen.dm
@@ -166,3 +166,15 @@
desc = "A grey helmet bearing a pair of purple stripes, designating the wearer as a janitor."
icon_state = "janitor_envirohelm"
item_state = "janitor_envirohelm"
+
+/obj/item/clothing/head/helmet/space/plasmaman/mime
+ name = "mime envirosuit helmet"
+ desc = "The make-up is painted on, it's a miracle it doesn't chip. It's not very colourful."
+ icon_state = "mime_envirohelm"
+ item_state = "mime_envirohelm"
+
+/obj/item/clothing/head/helmet/space/plasmaman/clown
+ name = "clown envirosuit helmet"
+ desc = "The make-up is painted on, it's a miracle it doesn't chip. 'HONK!'"
+ icon_state = "clown_envirohelm"
+ item_state = "clown_envirohelm"
\ No newline at end of file
diff --git a/code/modules/clothing/spacesuits/syndi.dm b/code/modules/clothing/spacesuits/syndi.dm
index 86e02c861f0..d88e4a1b9db 100644
--- a/code/modules/clothing/spacesuits/syndi.dm
+++ b/code/modules/clothing/spacesuits/syndi.dm
@@ -135,21 +135,21 @@
item_state = "syndicate-black-red"
//Black-red syndicate contract varient
-/obj/item/clothing/head/helmet/space/syndicate/contract/black/red
+/obj/item/clothing/head/helmet/space/syndicate/contract
name = "contractor helmet"
- desc = "A specalised black and red helmet that's quicker, and more compact that it's counterpart. Can be ultra-compressed into even the tightest of spaces."
+ desc = "A specialised black and gold helmet that's quicker, and more compact than its standard Syndicate counterpart. Can be ultra-compressed into even the tightest of spaces."
slowdown = 0.55
w_class = WEIGHT_CLASS_SMALL
- icon_state = "syndicate-helm-black-red"
- item_state = "syndicate-helm-black-red"
+ icon_state = "syndicate-contract-helm"
+ item_state = "syndicate-contract-helm"
-/obj/item/clothing/suit/space/syndicate/contract/black/red
+/obj/item/clothing/suit/space/syndicate/contract
name = "contractor space suit"
- desc = "A specalised black and red space suit that's quicker, and more compact that it's counterpart. Can be ultra-compressed into even the tightest of spaces."
+ desc = "A specialised black and gold space suit that's quicker, and more compact than its standard Syndicate counterpart. Can be ultra-compressed into even the tightest of spaces."
slowdown = 0.55
w_class = WEIGHT_CLASS_SMALL
- icon_state = "syndicate-black-red"
- item_state = "syndicate-black-red"
+ icon_state = "syndicate-contract"
+ item_state = "syndicate-contract"
//Black with yellow/red engineering syndicate space suit
/obj/item/clothing/head/helmet/space/syndicate/black/engie
diff --git a/code/modules/clothing/under/color.dm b/code/modules/clothing/under/color.dm
index c239f48b051..939e8837f6f 100644
--- a/code/modules/clothing/under/color.dm
+++ b/code/modules/clothing/under/color.dm
@@ -1,12 +1,17 @@
/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...
@@ -21,6 +26,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
@@ -35,6 +46,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 +67,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 +92,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,70 +105,137 @@
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!"
icon_state = "rainbow"
item_state = "rainbow"
item_color = "rainbow"
- can_adjust = FALSE
+ can_adjust = FALSE
\ No newline at end of file
diff --git a/code/modules/clothing/under/jobs/Plasmaman/civilian_service.dm b/code/modules/clothing/under/jobs/Plasmaman/civilian_service.dm
index e158816e468..ce36cac8a40 100644
--- a/code/modules/clothing/under/jobs/Plasmaman/civilian_service.dm
+++ b/code/modules/clothing/under/jobs/Plasmaman/civilian_service.dm
@@ -53,4 +53,34 @@
desc = "A green and blue envirosuit designed to protect plasmamen from minor plant-related injuries."
icon_state = "botany_envirosuit"
item_state = "botany_envirosuit"
- item_color = "botany_envirosuit"
\ No newline at end of file
+ item_color = "botany_envirosuit"
+
+
+/obj/item/clothing/under/plasmaman/mime
+ name = "mime envirosuit"
+ desc = "It's not very colourful."
+ icon_state = "mime_envirosuit"
+ item_state = "mime_envirosuit"
+ item_color = "mime_envirosuit"
+
+/obj/item/clothing/under/plasmaman/clown
+ name = "clown envirosuit"
+ desc = "'HONK!'"
+ icon_state = "clown_envirosuit"
+ item_state = "clown_envirosuit"
+ item_color = "clown_envirosuit"
+
+/obj/item/clothing/under/plasmaman/clown/Extinguish(mob/living/carbon/human/H)
+ if(!istype(H))
+ return
+
+ if(H.on_fire)
+ if(extinguishes_left)
+ if(next_extinguish > world.time)
+ return
+ next_extinguish = world.time + extinguish_cooldown
+ extinguishes_left--
+ H.visible_message("[H]'s suit spews out a tonne of space lube!","Your suit spews out a tonne of space lube!")
+ H.ExtinguishMob()
+ new /obj/effect/particle_effect/foam(loc) //Truely terrifying.
+ return 0
\ No newline at end of file
diff --git a/code/modules/clothing/under/jobs/civilian.dm b/code/modules/clothing/under/jobs/civilian.dm
index fe368376c5f..c3b0b60f213 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!'"
@@ -133,6 +191,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"
@@ -141,6 +209,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"
@@ -148,6 +226,15 @@
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"
@@ -158,6 +245,13 @@
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
icon_state = "black_suit_fem"
item_state = "black_suit_fem"
@@ -168,11 +262,25 @@
item_state = "lawyer_red"
item_color = "lawyer_red"
+/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
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."
@@ -182,6 +290,16 @@
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 = "bluesuit"
+ 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"
@@ -191,6 +309,15 @@
can_adjust = TRUE
alt_covers_chest = TRUE
+/obj/item/clothing/under/lawyer/purpsuit/skirt
+ name = "purple suitskirt"
+ icon_state = "lawyer_purp_skirt"
+ item_state = "lawyer_purp"
+ 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!"
@@ -200,6 +327,16 @@
can_adjust = TRUE
alt_covers_chest = TRUE
+/obj/item/clothing/under/lawyer/blacksuit/skirt
+ name = "black suitskirt"
+ desc = "A professional black suitskirt. Nanotrasen Investigation Bureau approved!"
+ icon_state = "reallyblack_suit_skirt"
+ item_state = "bar_suit"
+ item_color = "reallyblack_suit_skirt"
+ body_parts_covered = CHEST|GROIN|ARMS
+ can_adjust = FALSE
+ fitted = FEMALE_UNIFORM_TOP
+
/obj/item/clothing/under/rank/curator
name = "sensible suit"
desc = "It's very... sensible."
@@ -208,6 +345,16 @@
item_color = "red_suit"
can_adjust = FALSE
+/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."
@@ -222,6 +369,16 @@
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"
diff --git a/code/modules/clothing/under/jobs/engineering.dm b/code/modules/clothing/under/jobs/engineering.dm
index be47dbf61fe..2787fbc9363 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"
@@ -33,10 +53,30 @@
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."
name = "roboticist's jumpsuit"
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
\ No newline at end of file
diff --git a/code/modules/clothing/under/jobs/medsci.dm b/code/modules/clothing/under/jobs/medsci.dm
index f0980cae4d0..5fb7bdef02f 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"
@@ -120,3 +199,13 @@
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
\ No newline at end of file
diff --git a/code/modules/clothing/under/jobs/security.dm b/code/modules/clothing/under/jobs/security.dm
index 01b947d5ef3..dade15148fd 100644
--- a/code/modules/clothing/under/jobs/security.dm
+++ b/code/modules/clothing/under/jobs/security.dm
@@ -36,6 +36,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
@@ -57,6 +58,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 +83,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 +101,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,6 +126,16 @@
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."
@@ -109,6 +150,16 @@
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
*/
diff --git a/code/modules/clothing/under/miscellaneous.dm b/code/modules/clothing/under/miscellaneous.dm
index ed644d8da7d..209bc1566be 100644
--- a/code/modules/clothing/under/miscellaneous.dm
+++ b/code/modules/clothing/under/miscellaneous.dm
@@ -30,6 +30,16 @@
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"
@@ -65,6 +75,16 @@
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!'"
@@ -181,6 +201,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 +219,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."
@@ -761,3 +801,26 @@
item_color = "durathread"
can_adjust = FALSE
armor = list("melee" = 10, "laser" = 10, "fire" = 40, "acid" = 10, "bomb" = 5)
+
+/obj/item/clothing/under/mech_suit
+ name = "red mech pilot's suit"
+ desc = "A red mech pilot's suit. Might make your butt look big."
+ icon_state = "red_mech_suit"
+ item_state = "red_mech_suit"
+ body_parts_covered = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
+ cold_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
+ fitted = NO_FEMALE_UNIFORM
+ alternate_worn_layer = GLOVES_LAYER //covers hands but gloves can go over it. This is how these things work in my head.
+ can_adjust = FALSE
+
+/obj/item/clothing/under/mech_suit/white
+ name = "white mech pilot's suit"
+ desc = "A white mech pilot's suit. Very fetching."
+ icon_state = "white_mech_suit"
+ item_state = "white_mech_suit"
+
+/obj/item/clothing/under/mech_suit/blue
+ name = "blue mech pilot's suit"
+ desc = "A blue mech pilot's suit. For the more reluctant mech pilots."
+ icon_state = "blue_mech_suit"
+ item_state = "blue_mech_suit"
diff --git a/code/modules/detectivework/footprints_and_rag.dm b/code/modules/detectivework/footprints_and_rag.dm
index 8be34312e80..2ddca776f95 100644
--- a/code/modules/detectivework/footprints_and_rag.dm
+++ b/code/modules/detectivework/footprints_and_rag.dm
@@ -32,8 +32,7 @@
var/reagentlist = pretty_string_from_reagent_list(reagents)
var/log_object = "containing [reagentlist]"
if(user.a_intent == INTENT_HARM && !C.is_mouth_covered())
- reagents.reaction(C, INGEST)
- reagents.trans_to(C, reagents.total_volume, transfered_by = user)
+ reagents.trans_to(C, reagents.total_volume, transfered_by = user, method = INGEST)
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", src, log_object)
else
diff --git a/code/modules/discord/accountlink.dm b/code/modules/discord/accountlink.dm
new file mode 100644
index 00000000000..df77cc5e422
--- /dev/null
+++ b/code/modules/discord/accountlink.dm
@@ -0,0 +1,45 @@
+// Verb to link discord accounts to BYOND accounts
+/client/verb/linkdiscord()
+ set category = "Special Verbs"
+ set name = "Link Discord Account"
+ set desc = "Link your discord account to your BYOND account."
+
+ // Safety checks
+ if(!CONFIG_GET(flag/sql_enabled))
+ to_chat(src, "This feature requires the SQL backend to be running.")
+ return
+
+ if(!SSdiscord) // SS is still starting
+ to_chat(src, "The server is still starting up. Please wait before attempting to link your account ")
+ return
+
+ if(!SSdiscord.enabled)
+ to_chat(src, "This feature requires the server is running on the TGS toolkit")
+ return
+
+ var/stored_id = SSdiscord.lookup_id(usr.ckey)
+ if(!stored_id) // Account is not linked
+ var/know_how = alert("Do you know how to get a discord user ID? This ID is NOT your discord username and numbers! (Pressing NO will open a guide)","Question","Yes","No","Cancel Linking")
+ if(know_how == "No") // Opens discord support on how to collect IDs
+ src << link("https://support.discordapp.com/hc/en-us/articles/206346498-Where-can-I-find-my-User-Server-Message-ID")
+ if(know_how == "Cancel Linking")
+ return
+ var/entered_id = input("Please enter your Discord ID (18-ish digits)", "Enter Discord ID", null, null) as text|null
+ SSdiscord.account_link_cache[replacetext(lowertext(usr.ckey), " ", "")] = "[entered_id]" // Prepares for TGS-side verification, also fuck spaces
+ alert(usr, "Account link started. Please ping the bot of the server you\'re currently on, follows by \"verify [usr.ckey]\" in the Discord to successfuly verify your account (Example: @Mr_Terry verify [usr.ckey])")
+
+ else // Account is already linked
+ var/choice = alert("You already have the Discord Account [stored_id] linked to [usr.ckey]. Would you like to link a different account?","Already Linked","Yes","No")
+ if(choice == "Yes")
+ var/know_how = alert("Do you know how to get a discord user ID? This ID is NOT your discord username and numbers! (Pressing NO will open a guide)","Question","Yes","No", "Cancel Linking")
+ if(know_how == "No") // Opens discord support on how to collect IDs
+ src << link("https://support.discordapp.com/hc/en-us/articles/206346498-Where-can-I-find-my-User-Server-Message-ID")
+
+ if(know_how == "Cancel Linking")
+ return
+
+ var/entered_id = input("Please enter your Discord ID (18-ish digits)", "Enter Discord ID", null, null) as text|null
+ SSdiscord.account_link_cache[replacetext(lowertext(usr.ckey), " ", "")] = "[entered_id]" // Prepares for TGS-side verification, also fuck spaces
+ alert(usr, "Account link started. Please ping the bot of the server you\'re currently on, followed by \"verify [usr.ckey]\" in the Discord to successfuly verify your account (Example: @Mr_Terry verify [usr.ckey])")
+ // This is so people cant fill the notify list with a fuckload of ckeys
+ SSdiscord.notify_members -= "[stored_id]" // The list uses strings because BYOND cannot handle a 17 digit integer
diff --git a/code/modules/discord/manipulation.dm b/code/modules/discord/manipulation.dm
new file mode 100644
index 00000000000..3280674626e
--- /dev/null
+++ b/code/modules/discord/manipulation.dm
@@ -0,0 +1,36 @@
+// Verb to manipulate IDs and ckeys
+/client/proc/discord_id_manipulation()
+ set name = "Discord Manipulation"
+ set category = "Admin"
+
+ if(!check_rights(R_ADMIN))
+ return
+
+ holder.discord_manipulation()
+
+
+/datum/admins/proc/discord_manipulation()
+ if(!usr.client.holder)
+ return
+
+ if(!SSdiscord.enabled)
+ to_chat(usr, "TGS is not enabled")
+ return
+
+ var/lookup_choice = alert(usr, "Do you wish to lookup account by ID or ckey?", "Lookup Type", "ID", "Ckey", "Cancel")
+ switch(lookup_choice)
+ if("ID")
+ var/lookup_id = input(usr,"Enter Discord ID to lookup ckey") as text
+ var/returned_ckey = SSdiscord.lookup_id(lookup_id)
+ if(returned_ckey)
+ var/unlink_choice = alert(usr, "Discord ID [lookup_id] is linked to Ckey [returned_ckey]. Do you wish to unlink or cancel?", "Account Found", "Unlink", "Cancel")
+ if(unlink_choice == "Unlink")
+ SSdiscord.unlink_account(returned_ckey)
+ else
+ to_chat(usr, "Discord ID [lookup_id] has no associated ckey")
+ if("Ckey")
+ var/lookup_ckey = input(usr,"Enter Ckey to lookup ID") as text
+ var/returned_id = SSdiscord.lookup_id(lookup_ckey)
+ if(returned_id)
+ to_chat(usr, "Ckey [lookup_ckey] is assigned to Discord ID [returned_id]")
+ to_chat(usr, "Discord mention format: <@[returned_id]>") // < and > print < > in HTML without using them as tags
diff --git a/code/modules/discord/tgs_commands.dm b/code/modules/discord/tgs_commands.dm
new file mode 100644
index 00000000000..cb2ff65934c
--- /dev/null
+++ b/code/modules/discord/tgs_commands.dm
@@ -0,0 +1,30 @@
+// Notify
+/datum/tgs_chat_command/notify
+ name = "notify"
+ help_text = "Pings the invoker when the round ends"
+
+/datum/tgs_chat_command/notify/Run(datum/tgs_chat_user/sender, params)
+ for(var/member in SSdiscord.notify_members) // If they are in the list, take them out
+ if(member == "[sender.mention]")
+ SSdiscord.notify_members -= "[SSdiscord.id_clean(sender.mention)]" // The list uses strings because BYOND cannot handle a 17 digit integer
+ return "You will no longer be notified when the server restarts"
+
+ // If we got here, they arent in the list. Chuck 'em in!
+ SSdiscord.notify_members += "[SSdiscord.id_clean(sender.mention)]" // The list uses strings because BYOND cannot handle a 17 digit integer
+ return "You will now be notified when the server restarts"
+
+// Verify
+/datum/tgs_chat_command/verify
+ name = "verify"
+ help_text = "Verifies your discord account and your BYOND account linkage"
+
+/datum/tgs_chat_command/verify/Run(datum/tgs_chat_user/sender, params)
+ var/lowerparams = replacetext(lowertext(params), " ", "") // Fuck spaces
+ if(SSdiscord.account_link_cache[lowerparams]) // First if they are in the list, then if the ckey matches
+ if(SSdiscord.account_link_cache[lowerparams] == "[SSdiscord.id_clean(sender.mention)]") // If the associated ID is the correct one
+ SSdiscord.link_account(lowerparams)
+ return "Successfully linked accounts"
+ else
+ return "That ckey is not associated to this discord account. If someone has used your ID, please inform an administrator"
+ else
+ return "Account not setup for linkage"
diff --git a/code/modules/discord/toggle_notify.dm b/code/modules/discord/toggle_notify.dm
new file mode 100644
index 00000000000..5eb1492f757
--- /dev/null
+++ b/code/modules/discord/toggle_notify.dm
@@ -0,0 +1,34 @@
+// Verb to toggle restart notifications
+/client/verb/notify_restart()
+ set category = "Special Verbs"
+ set name = "Notify Restart"
+ set desc = "Notifies you on Discord when the server restarts."
+
+ // Safety checks
+ if(!CONFIG_GET(flag/sql_enabled))
+ to_chat(src, "This feature requires the SQL backend to be running.")
+ return
+
+ if(!SSdiscord) // SS is still starting
+ to_chat(src, "The server is still starting up. Please wait before attempting to link your account ")
+ return
+
+ if(!SSdiscord.enabled)
+ to_chat(src, "This feature requires the server is running on the TGS toolkit")
+ return
+
+ var/stored_id = SSdiscord.lookup_id(usr.ckey)
+ if(!stored_id) // Account is not linked
+ to_chat(src, "This requires you to link your Discord account with the \"Link Discord Account\" verb.")
+ return
+
+ else // Linked
+ for(var/member in SSdiscord.notify_members) // If they are in the list, take them out
+ if(member == "[stored_id]")
+ SSdiscord.notify_members -= "[stored_id]" // The list uses strings because BYOND cannot handle a 17 digit integer
+ to_chat(src, "You will no longer be notified when the server restarts")
+ return // This is necassary so it doesnt get added again, as it relies on the for loop being unsuccessful to tell us if they are in the list or not
+
+ // If we got here, they arent in the list. Chuck 'em in!
+ to_chat(src, "You will now be notified when the server restarts")
+ SSdiscord.notify_members += "[stored_id]" // The list uses strings because BYOND cannot handle a 17 digit integer
diff --git a/code/modules/events/immovable_rod.dm b/code/modules/events/immovable_rod.dm
index a60978fcbc3..3c6f86406df 100644
--- a/code/modules/events/immovable_rod.dm
+++ b/code/modules/events/immovable_rod.dm
@@ -138,7 +138,7 @@ In my current plan for it, 'solid' will be defined as anything with density == 1
qdel(other)
/obj/effect/immovablerod/proc/penetrate(mob/living/L)
- L.visible_message("[L] is penetrated by an immovable rod!" , "The rod penetrates you!" , "You hear a CLANG!")
+ L.visible_message("[L] is penetrated by an immovable rod!" , "The rod penetrates you!" , "You hear a CLANG!")
if(ishuman(L))
var/mob/living/carbon/human/H = L
H.adjustBruteLoss(160)
diff --git a/code/modules/events/wizard/magicarp.dm b/code/modules/events/wizard/magicarp.dm
index ab23c30e007..cf0e5e1b05b 100644
--- a/code/modules/events/wizard/magicarp.dm
+++ b/code/modules/events/wizard/magicarp.dm
@@ -36,6 +36,7 @@
projectilesound = 'sound/weapons/emitter.ogg'
maxHealth = 50
health = 50
+ random_color = FALSE
var/allowed_projectile_types = list(/obj/item/projectile/magic/change, /obj/item/projectile/magic/animate, /obj/item/projectile/magic/resurrection,
/obj/item/projectile/magic/death, /obj/item/projectile/magic/teleport, /obj/item/projectile/magic/door, /obj/item/projectile/magic/aoe/fireball,
/obj/item/projectile/magic/spellblade, /obj/item/projectile/magic/arcane_barrage)
diff --git a/code/modules/flufftext/Hallucination.dm b/code/modules/flufftext/Hallucination.dm
index 4fff7d9a3cd..68d5246de3c 100644
--- a/code/modules/flufftext/Hallucination.dm
+++ b/code/modules/flufftext/Hallucination.dm
@@ -225,7 +225,7 @@ GLOBAL_LIST_INIT(hallucination_list, list(
update_icon("alienh_pounce")
if(hit_atom == target && target.stat!=DEAD)
target.Paralyze(100)
- target.visible_message("[target] flails around wildly.","[name] pounces on you!")
+ target.visible_message("[target] flails around wildly.","[name] pounces on you!")
/datum/hallucination/xeno_attack
//Xeno crawls from nearby vent,jumps at you, and goes back in
@@ -532,7 +532,7 @@ GLOBAL_LIST_INIT(hallucination_list, list(
A = image('icons/mob/monkey.dmi',H,"monkey1")
A.name = "Monkey ([rand(1,999)])"
if("carp")//Carp
- A = image('icons/mob/animal.dmi',H,"carp")
+ A = image('icons/mob/carp.dmi',H,"carp")
A.name = "Space Carp"
if("corgi")//Corgi
A = image('icons/mob/pets.dmi',H,"corgi")
diff --git a/code/modules/food_and_drinks/drinks/drinks.dm b/code/modules/food_and_drinks/drinks/drinks.dm
index 6e8a34c832f..e71e38b74b5 100644
--- a/code/modules/food_and_drinks/drinks/drinks.dm
+++ b/code/modules/food_and_drinks/drinks/drinks.dm
@@ -205,6 +205,7 @@
spillable = TRUE
resistance_flags = FREEZE_PROOF
isGlass = FALSE
+ foodtype = BREAKFAST
/obj/item/reagent_containers/food/drinks/ice
name = "ice cup"
@@ -321,12 +322,12 @@
icon_state = "orangebox"
name = "orange juice box"
desc = "A great source of vitamins. Stay healthy!"
- foodtype = FRUIT
+ foodtype = FRUIT | BREAKFAST
if(/datum/reagent/consumable/milk)
icon_state = "milkbox"
name = "carton of milk"
desc = "An excellent source of calcium for growing space explorers."
- foodtype = DAIRY
+ foodtype = DAIRY | BREAKFAST
if(/datum/reagent/consumable/applejuice)
icon_state = "juicebox"
name = "apple juice box"
diff --git a/code/modules/food_and_drinks/drinks/drinks/bottle.dm b/code/modules/food_and_drinks/drinks/drinks/bottle.dm
index 9175ee7a4b1..41b46223cd8 100644
--- a/code/modules/food_and_drinks/drinks/drinks/bottle.dm
+++ b/code/modules/food_and_drinks/drinks/drinks/bottle.dm
@@ -338,7 +338,7 @@
righthand_file = 'icons/mob/inhands/equipment/kitchen_righthand.dmi'
isGlass = FALSE
list_reagents = list(/datum/reagent/consumable/orangejuice = 100)
- foodtype = FRUIT
+ foodtype = FRUIT | BREAKFAST
/obj/item/reagent_containers/food/drinks/bottle/cream
name = "milk cream"
diff --git a/code/modules/food_and_drinks/food.dm b/code/modules/food_and_drinks/food.dm
index 132e0008932..d6c8287b823 100644
--- a/code/modules/food_and_drinks/food.dm
+++ b/code/modules/food_and_drinks/food.dm
@@ -5,6 +5,8 @@
/// the parent to the exclusion list in code/__HELPERS/unsorted.dm's
/// get_random_food proc.
////////////////////////////////////////////////////////////////////////////////
+#define STOP_SERVING_BREAKFAST (15 MINUTES)
+
/obj/item/reagent_containers/food
possible_transfer_amounts = list()
volume = 50 //Sets the default container amount for all food items.
@@ -40,4 +42,8 @@
if(foodtype & H.dna.species.toxic_food)
to_chat(H, "You don't feel so good...")
H.adjust_disgust(25 + 30 * fraction)
+ if((foodtype & BREAKFAST) && world.time - SSticker.round_start_time < STOP_SERVING_BREAKFAST)
+ SEND_SIGNAL(H, COMSIG_ADD_MOOD_EVENT, "breakfast", /datum/mood_event/breakfast)
last_check_time = world.time
+
+#undef STOP_SERVING_BREAKFAST
diff --git a/code/modules/food_and_drinks/food/snacks.dm b/code/modules/food_and_drinks/food/snacks.dm
index 8dc3fc67642..4164a22bb7c 100644
--- a/code/modules/food_and_drinks/food/snacks.dm
+++ b/code/modules/food_and_drinks/food/snacks.dm
@@ -86,7 +86,7 @@ All foods are distributed among various categories. Use common sense.
if(!eatverb)
eatverb = pick("bite","chew","nibble","gnaw","gobble","chomp")
if(!reagents.total_volume) //Shouldn't be needed but it checks to see if it has anything left in it.
- to_chat(user, "None of [src] left, oh no!")
+ to_chat(user, "None of [src] left, oh no!")
qdel(src)
return FALSE
if(iscarbon(M))
@@ -99,7 +99,7 @@ All foods are distributed among various categories. Use common sense.
if(M == user) //If you're eating it yourself.
if(junkiness && M.satiety < -150 && M.nutrition > NUTRITION_LEVEL_STARVING + 50 && !HAS_TRAIT(user, TRAIT_VORACIOUS))
- to_chat(M, "You don't feel like eating any more junk food at the moment.")
+ to_chat(M, "You don't feel like eating any more junk food at the moment!")
return FALSE
else if(fullness <= 50)
user.visible_message("[user] hungrily [eatverb]s \the [src], gobbling it down!", "You hungrily [eatverb] \the [src], gobbling it down!")
@@ -141,8 +141,7 @@ All foods are distributed among various categories. Use common sense.
if(reagents.total_volume)
SEND_SIGNAL(src, COMSIG_FOOD_EATEN, M, user)
var/fraction = min(bitesize / reagents.total_volume, 1)
- reagents.reaction(M, INGEST, fraction)
- reagents.trans_to(M, bitesize, transfered_by = user)
+ reagents.trans_to(M, bitesize, transfered_by = user, method = INGEST)
bitecount++
On_Consume(M)
checkLiked(fraction, M)
diff --git a/code/modules/food_and_drinks/food/snacks/meat.dm b/code/modules/food_and_drinks/food/snacks/meat.dm
index 0362b873df6..8712bebf806 100644
--- a/code/modules/food_and_drinks/food/snacks/meat.dm
+++ b/code/modules/food_and_drinks/food/snacks/meat.dm
@@ -267,7 +267,7 @@
bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 1, /datum/reagent/consumable/cooking_oil = 2)
filling_color = "#854817"
tastes = list("bacon" = 1)
- foodtype = MEAT
+ foodtype = MEAT | BREAKFAST
/obj/item/reagent_containers/food/snacks/meat/slab/gondola
name = "gondola meat"
diff --git a/code/modules/food_and_drinks/food/snacks_bread.dm b/code/modules/food_and_drinks/food/snacks_bread.dm
index 82b89556f80..9dc81d55d29 100644
--- a/code/modules/food_and_drinks/food/snacks_bread.dm
+++ b/code/modules/food_and_drinks/food/snacks_bread.dm
@@ -256,17 +256,6 @@
filling_color = color
foodtype |= FRIED
-/obj/item/reagent_containers/food/snacks/butteredtoast
- name = "buttered toast"
- desc = "Butter lightly spread over a piece of toast."
- icon = 'icons/obj/food/food.dmi'
- icon_state = "butteredtoast"
- bitesize = 3
- filling_color = "#FFA500"
- list_reagents = list(/datum/reagent/consumable/nutriment = 4)
- bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 1)
- tastes = list("butter" = 1, "toast" = 1)
-
/obj/item/reagent_containers/food/snacks/butterbiscuit
name = "butter biscuit"
desc = "Well butter my biscuit!"
@@ -276,6 +265,7 @@
list_reagents = list(/datum/reagent/consumable/nutriment = 5)
bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 1)
tastes = list("butter" = 1, "biscuit" = 1)
+ foodtype = GRAIN | BREAKFAST
/obj/item/reagent_containers/food/snacks/butterdog
name = "butterdog"
diff --git a/code/modules/food_and_drinks/food/snacks_egg.dm b/code/modules/food_and_drinks/food/snacks_egg.dm
index 76120013ab1..c4fe3167e9e 100644
--- a/code/modules/food_and_drinks/food/snacks_egg.dm
+++ b/code/modules/food_and_drinks/food/snacks_egg.dm
@@ -50,6 +50,11 @@
to_chat(usr, "You colour [src] with [W].")
icon_state = "egg-[clr]"
item_color = clr
+ else if(istype(W, /obj/item/stamp/clown))
+ var/clowntype = pick("grock", "grimaldi", "rainbow", "chaos", "joker", "sexy", "standard", "bobble", "krusty", "bozo", "pennywise", "ronald", "jacobs", "kelly", "popov", "cluwne")
+ icon_state = "egg-clown-[clowntype]"
+ desc = "An egg that has been decorated with the grotesque, robustable likeness of a clown's face. "
+ to_chat(usr, "You stamp [src] with [W], creating an artistic and not remotely horrifying likeness of clown makeup.")
else
..()
@@ -94,7 +99,7 @@
filling_color = "#FFFFF0"
list_reagents = list(/datum/reagent/consumable/nutriment = 3)
tastes = list("egg" = 4, "salt" = 1, "pepper" = 1)
- foodtype = MEAT | FRIED
+ foodtype = MEAT | FRIED | BREAKFAST
/obj/item/reagent_containers/food/snacks/boiledegg
name = "boiled egg"
@@ -104,7 +109,7 @@
filling_color = "#FFFFF0"
list_reagents = list(/datum/reagent/consumable/nutriment = 2, /datum/reagent/consumable/nutriment/vitamin = 1)
tastes = list("egg" = 1)
- foodtype = MEAT
+ foodtype = MEAT | BREAKFAST
/obj/item/reagent_containers/food/snacks/omelette //FUCK THIS
name = "omelette du fromage"
@@ -116,7 +121,7 @@
bitesize = 1
w_class = WEIGHT_CLASS_NORMAL
tastes = list("egg" = 1, "cheese" = 1)
- foodtype = MEAT
+ foodtype = MEAT | BREAKFAST
/obj/item/reagent_containers/food/snacks/omelette/attackby(obj/item/W, mob/user, params)
if(istype(W, /obj/item/kitchen/fork))
@@ -146,4 +151,4 @@
list_reagents = list(/datum/reagent/consumable/nutriment = 6, /datum/reagent/consumable/nutriment/vitamin = 4)
tastes = list("egg" = 1, "bacon" = 1, "bun" = 1)
- foodtype = MEAT
+ foodtype = MEAT | BREAKFAST
diff --git a/code/modules/food_and_drinks/food/snacks_meat.dm b/code/modules/food_and_drinks/food/snacks_meat.dm
index fb498a8010b..0ec7e4863fc 100644
--- a/code/modules/food_and_drinks/food/snacks_meat.dm
+++ b/code/modules/food_and_drinks/food/snacks_meat.dm
@@ -118,7 +118,7 @@
bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 1)
list_reagents = list(/datum/reagent/consumable/nutriment = 6, /datum/reagent/consumable/nutriment/vitamin = 1)
tastes = list("meat" = 1)
- foodtype = MEAT
+ foodtype = MEAT | BREAKFAST
var/roasted = FALSE
/obj/item/reagent_containers/food/snacks/sausage/Initialize()
diff --git a/code/modules/food_and_drinks/food/snacks_other.dm b/code/modules/food_and_drinks/food/snacks_other.dm
index 1dd037b2bf4..280f30d0006 100644
--- a/code/modules/food_and_drinks/food/snacks_other.dm
+++ b/code/modules/food_and_drinks/food/snacks_other.dm
@@ -540,7 +540,7 @@
list_reagents = list(/datum/reagent/consumable/nutriment = 3, /datum/reagent/consumable/nutriment/vitamin = 2, /datum/reagent/consumable/sodiumchloride = 5)
bonus_reagents = list(/datum/reagent/consumable/sodiumchloride = 10)
tastes = list("bran" = 4, "raisins" = 3, "salt" = 1)
- foodtype = GRAIN | FRUIT
+ foodtype = GRAIN | FRUIT | BREAKFAST
/obj/item/reagent_containers/food/snacks/butter
name = "stick of butter"
diff --git a/code/modules/food_and_drinks/food/snacks_pastry.dm b/code/modules/food_and_drinks/food/snacks_pastry.dm
index db3914a308c..9f2c7fd2cbd 100644
--- a/code/modules/food_and_drinks/food/snacks_pastry.dm
+++ b/code/modules/food_and_drinks/food/snacks_pastry.dm
@@ -11,7 +11,7 @@
list_reagents = list(/datum/reagent/consumable/nutriment = 3, /datum/reagent/consumable/sprinkles = 1, /datum/reagent/consumable/sugar = 2)
filling_color = "#D2691E"
tastes = list("donut" = 1)
- foodtype = JUNKFOOD | GRAIN | FRIED | SUGAR
+ foodtype = JUNKFOOD | GRAIN | FRIED | SUGAR | BREAKFAST
var/frosted_icon = "donut2"
var/is_frosted = FALSE
var/extra_reagent = null
@@ -55,7 +55,7 @@
/obj/item/reagent_containers/food/snacks/donut/chaos/Initialize()
. = ..()
extra_reagent = pick(/datum/reagent/consumable/nutriment, /datum/reagent/consumable/capsaicin, /datum/reagent/consumable/frostoil, /datum/reagent/drug/krokodil, /datum/reagent/toxin/plasma, /datum/reagent/consumable/coco, /datum/reagent/toxin/slimejelly, /datum/reagent/consumable/banana, /datum/reagent/consumable/berryjuice, /datum/reagent/medicine/omnizine)
- reagents.add_reagent("[extra_reagent]", 3)
+ reagents.add_reagent(extra_reagent, 3)
/obj/item/reagent_containers/food/snacks/donut/jelly
name = "jelly donut"
@@ -65,26 +65,26 @@
bonus_reagents = list(/datum/reagent/consumable/sugar = 1, /datum/reagent/consumable/nutriment/vitamin = 1)
extra_reagent = /datum/reagent/consumable/berryjuice
tastes = list("jelly" = 1, "donut" = 3)
- foodtype = JUNKFOOD | GRAIN | FRIED | FRUIT | SUGAR
+ foodtype = JUNKFOOD | GRAIN | FRIED | FRUIT | SUGAR | BREAKFAST
/obj/item/reagent_containers/food/snacks/donut/jelly/Initialize()
. = ..()
if(extra_reagent)
- reagents.add_reagent("[extra_reagent]", 3)
+ reagents.add_reagent(extra_reagent, 3)
/obj/item/reagent_containers/food/snacks/donut/jelly/slimejelly
name = "jelly donut"
desc = "You jelly?"
icon_state = "jdonut1"
extra_reagent = /datum/reagent/toxin/slimejelly
- foodtype = JUNKFOOD | GRAIN | FRIED | TOXIC | SUGAR
+ foodtype = JUNKFOOD | GRAIN | FRIED | TOXIC | SUGAR | BREAKFAST
/obj/item/reagent_containers/food/snacks/donut/jelly/cherryjelly
name = "jelly donut"
desc = "You jelly?"
icon_state = "jdonut1"
extra_reagent = /datum/reagent/consumable/cherryjelly
- foodtype = JUNKFOOD | GRAIN | FRIED | FRUIT
+ foodtype = JUNKFOOD | GRAIN | FRIED | FRUIT | BREAKFAST
/obj/item/reagent_containers/food/snacks/donut/meat
name = "Meat Donut"
@@ -93,7 +93,7 @@
bonus_reagents = list(/datum/reagent/consumable/ketchup = 1)
list_reagents = list(/datum/reagent/consumable/nutriment = 3, /datum/reagent/consumable/ketchup = 2)
tastes = list("meat" = 1)
- foodtype = JUNKFOOD | MEAT | GROSS | FRIED
+ foodtype = JUNKFOOD | MEAT | GROSS | FRIED | BREAKFAST
////////////////////////////////////////////MUFFINS////////////////////////////////////////////
@@ -106,14 +106,14 @@
list_reagents = list(/datum/reagent/consumable/nutriment = 6)
filling_color = "#F4A460"
tastes = list("muffin" = 1)
- foodtype = GRAIN | SUGAR
+ foodtype = GRAIN | SUGAR | BREAKFAST
/obj/item/reagent_containers/food/snacks/muffin/berry
name = "berry muffin"
icon_state = "berrymuffin"
desc = "A delicious and spongy little cake, with berries."
tastes = list("muffin" = 3, "berry" = 1)
- foodtype = GRAIN | FRUIT | SUGAR
+ foodtype = GRAIN | FRUIT | SUGAR | BREAKFAST
/obj/item/reagent_containers/food/snacks/muffin/booberry
name = "booberry muffin"
@@ -121,7 +121,7 @@
alpha = 125
desc = "My stomach is a graveyard! No living being can quench my bloodthirst!"
tastes = list("muffin" = 3, "spookiness" = 1)
- foodtype = GRAIN | FRUIT | SUGAR
+ foodtype = GRAIN | FRUIT | SUGAR | BREAKFAST
/obj/item/reagent_containers/food/snacks/chawanmushi
name = "chawanmushi"
@@ -144,7 +144,7 @@
list_reagents = list(/datum/reagent/consumable/nutriment = 8, /datum/reagent/consumable/nutriment/vitamin = 1)
filling_color = "#D2691E"
tastes = list("waffles" = 1)
- foodtype = GRAIN | SUGAR
+ foodtype = GRAIN | SUGAR | BREAKFAST
/obj/item/reagent_containers/food/snacks/soylentgreen
name = "\improper Soylent Green"
@@ -178,7 +178,7 @@
list_reagents = list(/datum/reagent/consumable/nutriment = 8, /datum/reagent/drug/mushroomhallucinogen = 2, /datum/reagent/consumable/nutriment/vitamin = 2)
filling_color = "#00BFFF"
tastes = list("waffle" = 1, "mushrooms" = 1)
- foodtype = GRAIN | VEGETABLES | TOXIC | SUGAR
+ foodtype = GRAIN | VEGETABLES | TOXIC | SUGAR | BREAKFAST
////////////////////////////////////////////OTHER////////////////////////////////////////////
@@ -384,7 +384,7 @@
list_reagents = list(/datum/reagent/consumable/nutriment = 4, /datum/reagent/consumable/nutriment/vitamin = 1)
filling_color = "#D2691E"
tastes = list("pancakes" = 1)
- foodtype = GRAIN | SUGAR
+ foodtype = GRAIN | SUGAR | BREAKFAST
/obj/item/reagent_containers/food/snacks/pancakes/blueberry
name = "blueberry pancake"
diff --git a/code/modules/food_and_drinks/food/snacks_salad.dm b/code/modules/food_and_drinks/food/snacks_salad.dm
index 4de2500b144..c281c188390 100644
--- a/code/modules/food_and_drinks/food/snacks_salad.dm
+++ b/code/modules/food_and_drinks/food/snacks_salad.dm
@@ -47,7 +47,7 @@
bonus_reagents = list(/datum/reagent/consumable/nutriment = 4, /datum/reagent/consumable/nutriment/vitamin = 4)
list_reagents = list(/datum/reagent/consumable/nutriment = 7, /datum/reagent/consumable/milk = 10, /datum/reagent/consumable/nutriment/vitamin = 2)
tastes = list("oats" = 1, "milk" = 1)
- foodtype = DAIRY | GRAIN
+ foodtype = DAIRY | GRAIN | BREAKFAST
/obj/item/reagent_containers/food/snacks/salad/fruit
name = "fruit salad"
diff --git a/code/modules/food_and_drinks/food/snacks_sandwichtoast.dm b/code/modules/food_and_drinks/food/snacks_sandwichtoast.dm
index 3fe809431ce..a4823be09c6 100644
--- a/code/modules/food_and_drinks/food/snacks_sandwichtoast.dm
+++ b/code/modules/food_and_drinks/food/snacks_sandwichtoast.dm
@@ -81,17 +81,29 @@
trash = /obj/item/trash/plate
bitesize = 3
tastes = list("toast" = 1, "jelly" = 1)
- foodtype = GRAIN
+ foodtype = GRAIN | BREAKFAST
/obj/item/reagent_containers/food/snacks/jelliedtoast/cherry
bonus_reagents = list(/datum/reagent/consumable/cherryjelly = 5, /datum/reagent/consumable/nutriment/vitamin = 2)
list_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/cherryjelly = 5, /datum/reagent/consumable/nutriment/vitamin = 2)
- foodtype = GRAIN | FRUIT | SUGAR
+ foodtype = GRAIN | FRUIT | SUGAR | BREAKFAST
/obj/item/reagent_containers/food/snacks/jelliedtoast/slime
bonus_reagents = list(/datum/reagent/toxin/slimejelly = 5, /datum/reagent/consumable/nutriment/vitamin = 2)
list_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/toxin/slimejelly = 5, /datum/reagent/consumable/nutriment/vitamin = 2)
- foodtype = GRAIN | TOXIC | SUGAR
+ foodtype = GRAIN | TOXIC | SUGAR | BREAKFAST
+
+/obj/item/reagent_containers/food/snacks/butteredtoast
+ name = "buttered toast"
+ desc = "Butter lightly spread over a piece of toast."
+ icon = 'icons/obj/food/food.dmi'
+ icon_state = "butteredtoast"
+ bitesize = 3
+ filling_color = "#FFA500"
+ list_reagents = list(/datum/reagent/consumable/nutriment = 4)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 1)
+ tastes = list("butter" = 1, "toast" = 1)
+ foodtype = GRAIN | BREAKFAST
/obj/item/reagent_containers/food/snacks/twobread
name = "two bread"
diff --git a/code/modules/food_and_drinks/food/snacks_soup.dm b/code/modules/food_and_drinks/food/snacks_soup.dm
index 1002daf9e8f..282f7537a1e 100644
--- a/code/modules/food_and_drinks/food/snacks_soup.dm
+++ b/code/modules/food_and_drinks/food/snacks_soup.dm
@@ -102,8 +102,9 @@
/obj/item/reagent_containers/food/snacks/soup/mystery/Initialize()
. = ..()
extra_reagent = pick(/datum/reagent/consumable/capsaicin, /datum/reagent/consumable/frostoil, /datum/reagent/medicine/omnizine, /datum/reagent/consumable/banana, /datum/reagent/blood, /datum/reagent/toxin/slimejelly, /datum/reagent/toxin, /datum/reagent/consumable/banana, /datum/reagent/carbon, /datum/reagent/medicine/oculine)
- bonus_reagents = list("[extra_reagent]" = 5, /datum/reagent/consumable/nutriment = 6)
- reagents.add_reagent("[extra_reagent]", 5)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 6)
+ bonus_reagents[extra_reagent] = 5
+ reagents.add_reagent(extra_reagent, 5)
/obj/item/reagent_containers/food/snacks/soup/hotchili
name = "hot chili"
diff --git a/code/modules/food_and_drinks/kitchen_machinery/deep_fryer.dm b/code/modules/food_and_drinks/kitchen_machinery/deep_fryer.dm
index 89c01536423..5b4eafc00cd 100644
--- a/code/modules/food_and_drinks/kitchen_machinery/deep_fryer.dm
+++ b/code/modules/food_and_drinks/kitchen_machinery/deep_fryer.dm
@@ -72,7 +72,7 @@ God bless America.
if(frying)
. += "You can make out \a [frying] in the oil."
if(in_range(user, src) || isobserver(user))
- . += "The status display reads: Frying at [fry_speed*100]% speed.
Using [oil_use*10] units of oil per second."
+ . += "The status display reads: Frying at [fry_speed*100]% speed.
Using [oil_use*10] units of oil per second."
/obj/machinery/deepfryer/attackby(obj/item/I, mob/user)
if(istype(I, /obj/item/reagent_containers/pill))
@@ -146,7 +146,7 @@ God bless America.
to_chat(user, "You need a better grip to do that!")
return
var/mob/living/carbon/C = user.pulling
- user.visible_message("[user] dunks [C]'s face in [src]!")
+ user.visible_message("[user] dunks [C]'s face in [src]!")
reagents.reaction(C, TOUCH)
var/permeability = 1 - C.get_permeability_protection(list(HEAD))
C.apply_damage(min(30 * permeability, reagents.total_volume), BURN, BODY_ZONE_HEAD)
diff --git a/code/modules/food_and_drinks/kitchen_machinery/gibber.dm b/code/modules/food_and_drinks/kitchen_machinery/gibber.dm
index fd47abd2b2a..af12485e997 100644
--- a/code/modules/food_and_drinks/kitchen_machinery/gibber.dm
+++ b/code/modules/food_and_drinks/kitchen_machinery/gibber.dm
@@ -33,10 +33,10 @@
/obj/machinery/gibber/examine(mob/user)
. = ..()
if(in_range(user, src) || isobserver(user))
- . += "The status display reads: Outputting [meat_produced] meat slab(s) after [gibtime*0.1] seconds of processing."
+ . += "The status display reads: Outputting [meat_produced] meat slab(s) after [gibtime*0.1] seconds of processing."
for(var/obj/item/stock_parts/manipulator/M in component_parts)
if(M.rating >= 2)
- . += "Gibber has been upgraded to process inorganic materials."
+ . += "Gibber has been upgraded to process inorganic materials."
/obj/machinery/gibber/update_icon()
cut_overlays()
@@ -71,13 +71,13 @@
return
if(!anchored)
- to_chat(user, "[src] cannot be used unless bolted to the ground.")
+ to_chat(user, "[src] cannot be used unless bolted to the ground!")
return
if(user.pulling && user.a_intent == INTENT_GRAB && isliving(user.pulling))
var/mob/living/L = user.pulling
if(!iscarbon(L))
- to_chat(user, "This item is not suitable for the gibber!")
+ to_chat(user, "This item is not suitable for the gibber!")
return
var/mob/living/carbon/C = L
if(C.buckled ||C.has_buckled_mobs())
@@ -87,7 +87,7 @@
if(!ignore_clothing)
for(var/obj/item/I in C.held_items + C.get_equipped_items())
if(!HAS_TRAIT(I, TRAIT_NODROP))
- to_chat(user, "Subject may not have abiotic items on.")
+ to_chat(user, "Subject may not have abiotic items on!")
return
user.visible_message("[user] starts to put [C] into the gibber!")
@@ -139,10 +139,10 @@
if(src.operating)
return
if(!src.occupant)
- visible_message("You hear a loud metallic grinding sound.")
+ audible_message("You hear a loud metallic grinding sound.")
return
use_power(1000)
- visible_message("You hear a loud squelchy grinding sound.")
+ audible_message("You hear a loud squelchy grinding sound.")
playsound(src.loc, 'sound/machines/juicer.ogg', 50, 1)
operating = TRUE
update_icon()
diff --git a/code/modules/food_and_drinks/kitchen_machinery/microwave.dm b/code/modules/food_and_drinks/kitchen_machinery/microwave.dm
index 3dd3a08ecc0..880b3718c30 100644
--- a/code/modules/food_and_drinks/kitchen_machinery/microwave.dm
+++ b/code/modules/food_and_drinks/kitchen_machinery/microwave.dm
@@ -83,9 +83,9 @@
. += "\The [src] is empty."
if(!(stat & (NOPOWER|BROKEN)))
- . += {"The status display reads:\n
- - Capacity: [max_n_of_items] items.\n
- - Cook time reduced by [(efficiency - 1) * 25]%."}
+ . += "The status display reads:\n"+\
+ "- Capacity: [max_n_of_items] items.\n"+\
+ "- Cook time reduced by [(efficiency - 1) * 25]%."
/obj/machinery/microwave/update_icon()
if(broken)
diff --git a/code/modules/food_and_drinks/kitchen_machinery/monkeyrecycler.dm b/code/modules/food_and_drinks/kitchen_machinery/monkeyrecycler.dm
index 5722601ad55..bf8ae8047e5 100644
--- a/code/modules/food_and_drinks/kitchen_machinery/monkeyrecycler.dm
+++ b/code/modules/food_and_drinks/kitchen_machinery/monkeyrecycler.dm
@@ -37,7 +37,7 @@ GLOBAL_LIST_EMPTY(monkey_recyclers)
/obj/machinery/monkey_recycler/examine(mob/user)
. = ..()
if(in_range(user, src) || isobserver(user))
- . += "The status display reads: Producing [cube_production] cubes for every monkey inserted."
+ . += "The status display reads: Producing [cube_production] cubes for every monkey inserted."
/obj/machinery/monkey_recycler/attackby(obj/item/O, mob/user, params)
if(default_deconstruction_screwdriver(user, "grinder_open", "grinder", O))
diff --git a/code/modules/food_and_drinks/kitchen_machinery/processor.dm b/code/modules/food_and_drinks/kitchen_machinery/processor.dm
index e31b9e6eddc..0a0b85adf7c 100644
--- a/code/modules/food_and_drinks/kitchen_machinery/processor.dm
+++ b/code/modules/food_and_drinks/kitchen_machinery/processor.dm
@@ -24,7 +24,7 @@
/obj/machinery/processor/examine(mob/user)
. = ..()
if(in_range(user, src) || isobserver(user))
- . += "The status display reads: Outputting [rating_amount] item(s) at [rating_speed*100]% speed."
+ . += "The status display reads: Outputting [rating_amount] item(s) at [rating_speed*100]% speed."
/obj/machinery/processor/proc/process_food(datum/food_processor_process/recipe, atom/movable/what)
if (recipe.output && loc && !QDELETED(src))
diff --git a/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm b/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm
index 3d636a734a8..9c684a63761 100644
--- a/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm
+++ b/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm
@@ -36,7 +36,7 @@
/obj/machinery/smartfridge/examine(mob/user)
. = ..()
if(in_range(user, src) || isobserver(user))
- . += "The status display reads: This unit can hold a maximum of [max_n_of_items] items."
+ . += "The status display reads: This unit can hold a maximum of [max_n_of_items] items."
/obj/machinery/smartfridge/power_change()
..()
@@ -395,6 +395,15 @@
desc = "A refrigerated storage unit for medicine storage."
/obj/machinery/smartfridge/chemistry/accept_check(obj/item/O)
+ var/static/list/chemfridge_typecache = typecacheof(list(
+ /obj/item/reagent_containers/syringe,
+ /obj/item/reagent_containers/glass/bottle,
+ /obj/item/reagent_containers/glass/beaker,
+ /obj/item/reagent_containers/spray,
+ /obj/item/reagent_containers/medigel,
+ /obj/item/reagent_containers/chem_pack
+ ))
+
if(istype(O, /obj/item/storage/pill_bottle))
if(O.contents.len)
for(var/obj/item/I in O)
@@ -408,7 +417,7 @@
return TRUE
if(!O.reagents || !O.reagents.reagent_list.len) // other empty containers not accepted
return FALSE
- if(istype(O, /obj/item/reagent_containers/syringe) || istype(O, /obj/item/reagent_containers/glass/bottle) || istype(O, /obj/item/reagent_containers/glass/beaker) || istype(O, /obj/item/reagent_containers/spray) || istype(O, /obj/item/reagent_containers/medspray))
+ if(is_type_in_typecache(O, chemfridge_typecache))
return TRUE
return FALSE
diff --git a/code/modules/food_and_drinks/pizzabox.dm b/code/modules/food_and_drinks/pizzabox.dm
index 43446152305..e0838b189f2 100644
--- a/code/modules/food_and_drinks/pizzabox.dm
+++ b/code/modules/food_and_drinks/pizzabox.dm
@@ -187,7 +187,7 @@
update_icon()
return
else if(bomb)
- to_chat(user, "[src] already has a bomb in it!")
+ to_chat(user, "[src] already has a bomb in it!")
else if(istype(I, /obj/item/pen))
if(!open)
if(!user.is_literate())
diff --git a/code/modules/food_and_drinks/recipes/food_mixtures.dm b/code/modules/food_and_drinks/recipes/food_mixtures.dm
index a4236bddf7a..5e510fd3e0c 100644
--- a/code/modules/food_and_drinks/recipes/food_mixtures.dm
+++ b/code/modules/food_and_drinks/recipes/food_mixtures.dm
@@ -177,3 +177,10 @@
new /obj/item/reagent_containers/food/snacks/salad/ricebowl(location)
if(holder && holder.my_atom)
qdel(holder.my_atom)
+
+/datum/chemical_reaction/nutriconversion
+ name = "Nutriment Conversion"
+ id = "nutriconversion"
+ results = list(/datum/reagent/consumable/nutriment/peptides = 0.5)
+ required_reagents = list(/datum/reagent/consumable/nutriment/ = 0.5)
+ required_catalysts = list(/datum/reagent/medicine/metafactor = 0.5)
diff --git a/code/modules/food_and_drinks/recipes/tablecraft/recipes_bread.dm b/code/modules/food_and_drinks/recipes/tablecraft/recipes_bread.dm
index ecbdac571cb..2d0fd2d2903 100644
--- a/code/modules/food_and_drinks/recipes/tablecraft/recipes_bread.dm
+++ b/code/modules/food_and_drinks/recipes/tablecraft/recipes_bread.dm
@@ -75,15 +75,6 @@
result = /obj/item/reagent_containers/food/snacks/store/bread/mimana
subcategory = CAT_BREAD
-/datum/crafting_recipe/food/butteredtoast
- name = "Buttered Toast"
- reqs = list(
- /obj/item/reagent_containers/food/snacks/breadslice/plain = 1,
- /obj/item/reagent_containers/food/snacks/butter = 1
- )
- result = /obj/item/reagent_containers/food/snacks/butteredtoast
- subcategory = CAT_BREAD
-
/datum/crafting_recipe/food/garlicbread
name = "Garlic Bread"
time = 40
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 9e81cc897a7..77babbf6bf2 100644
--- a/code/modules/food_and_drinks/recipes/tablecraft/recipes_misc.dm
+++ b/code/modules/food_and_drinks/recipes/tablecraft/recipes_misc.dm
@@ -125,6 +125,15 @@
result = /obj/item/reagent_containers/food/snacks/jelliedtoast/cherry
subcategory = CAT_MISCFOOD
+/datum/crafting_recipe/food/butteredtoast
+ name = "Buttered Toast"
+ reqs = list(
+ /obj/item/reagent_containers/food/snacks/breadslice/plain = 1,
+ /obj/item/reagent_containers/food/snacks/butter = 1
+ )
+ result = /obj/item/reagent_containers/food/snacks/butteredtoast
+ subcategory = CAT_MISCFOOD
+
/datum/crafting_recipe/food/twobread
name = "Two bread"
reqs = list(
diff --git a/code/modules/games/cas.dm b/code/modules/games/cas.dm
index f5a542839b6..b1240c49ba6 100644
--- a/code/modules/games/cas.dm
+++ b/code/modules/games/cas.dm
@@ -148,7 +148,7 @@
to_chat(user, "You scribble illegibly on [src]!")
return
if(!blank)
- to_chat(user, "You cannot write on that card.")
+ to_chat(user, "You cannot write on that card!")
return
var/cardtext = stripped_input(user, "What do you wish to write on the card?", "Card Writing", "", 50)
if(!cardtext || !user.canUseTopic(src, BE_CLOSE))
diff --git a/code/modules/goonchat/browserOutput.dm b/code/modules/goonchat/browserOutput.dm
index 7ff3ab9206f..faf7bf36855 100644
--- a/code/modules/goonchat/browserOutput.dm
+++ b/code/modules/goonchat/browserOutput.dm
@@ -107,6 +107,8 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("tmp/iconCache.sav")) //Cache of ico
messageQueue = null
sendClientData()
+ syncRegex()
+
//do not convert to to_chat()
SEND_TEXT(owner, "Failed to load fancy chat, reverting to old chat. Certain features won't work.")
@@ -114,6 +116,26 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("tmp/iconCache.sav")) //Cache of ico
winset(owner, "output", "is-visible=false")
winset(owner, "browseroutput", "is-disabled=false;is-visible=true")
+/proc/syncChatRegexes()
+ for (var/user in GLOB.clients)
+ var/client/C = user
+ var/datum/chatOutput/Cchat = C.chatOutput
+ if (Cchat && !Cchat.broken && Cchat.loaded)
+ Cchat.syncRegex()
+
+/datum/chatOutput/proc/syncRegex()
+ var/list/regexes = list()
+
+ if (config.ic_filter_regex)
+ regexes["show_filtered_ic_chat"] = list(
+ config.ic_filter_regex.name,
+ "ig",
+ "$1"
+ )
+
+ if (regexes.len)
+ ehjax_send(data = list("syncRegex" = regexes))
+
/datum/chatOutput/proc/ehjax_send(client/C = owner, window = "browseroutput", data)
if(islist(data))
data = json_encode(data)
diff --git a/code/modules/goonchat/browserassets/js/browserOutput.js b/code/modules/goonchat/browserassets/js/browserOutput.js
index d1c6280b557..f0efcc40d6a 100644
--- a/code/modules/goonchat/browserassets/js/browserOutput.js
+++ b/code/modules/goonchat/browserassets/js/browserOutput.js
@@ -73,6 +73,7 @@ var opts = {
'messageCombining': true,
};
+var replaceRegexes = {};
function clamp(val, min, max) {
return Math.max(min, Math.min(val, max))
@@ -173,6 +174,15 @@ function byondDecode(message) {
return message;
}
+function replaceRegex() {
+ var selectedRegex = replaceRegexes[$(this).attr('replaceRegex')];
+ if (selectedRegex) {
+ var replacedText = $(this).html().replace(selectedRegex[0], selectedRegex[1]);
+ $(this).html(replacedText);
+ }
+ $(this).removeAttr('replaceRegex');
+}
+
//Actually turns the highlight term match into appropriate html
function addHighlightMarkup(match) {
var extra = '';
@@ -366,6 +376,7 @@ function output(message, flag) {
badge = $('', {'class': 'r', 'text': 2});
}
lastmessages.html(message);
+ lastmessages.find('[replaceRegex]').each(replaceRegex);
lastmessages.append(badge);
badge.animate({
"font-size": "0.9em"
@@ -388,6 +399,8 @@ function output(message, flag) {
entry.setAttribute('data-filter', filteredOut);
}
+ $(entry).find('[replaceRegex]').each(replaceRegex);
+
$last_message = trimmed_message;
$messages[0].appendChild(entry);
$(entry).find("img.icon").error(iconError);
@@ -575,6 +588,16 @@ function ehjaxCallback(data) {
$('#adminMusic').prop('src', adminMusic);
$('#adminMusic').trigger("play");
}
+ } else if (data.syncRegex) {
+ for (var i in data.syncRegex) {
+
+ var regexData = data.syncRegex[i];
+ var regexName = regexData[0];
+ var regexFlags = regexData[1];
+ var regexReplaced = regexData[2];
+
+ replaceRegexes[i] = [new RegExp(regexName, regexFlags), regexReplaced];
+ }
}
}
}
diff --git a/code/modules/holodeck/area_copy.dm b/code/modules/holodeck/area_copy.dm
index ace1cdcd2e4..f7cb0bf1021 100644
--- a/code/modules/holodeck/area_copy.dm
+++ b/code/modules/holodeck/area_copy.dm
@@ -5,6 +5,7 @@ GLOBAL_LIST_INIT(duplicate_forbidden_vars,list(
))
/proc/DuplicateObject(atom/original, perfectcopy = TRUE, sameloc, atom/newloc = null, nerf, holoitem)
+ RETURN_TYPE(original.type)
if(!original)
return
var/atom/O
diff --git a/code/modules/hydroponics/biogenerator.dm b/code/modules/hydroponics/biogenerator.dm
index 13e1d2d0337..197beccec87 100644
--- a/code/modules/hydroponics/biogenerator.dm
+++ b/code/modules/hydroponics/biogenerator.dm
@@ -55,7 +55,7 @@
/obj/machinery/biogenerator/examine(mob/user)
. = ..()
if(in_range(user, src) || isobserver(user))
- . += "The status display reads: Productivity at [productivity*100]%.
Matter consumption reduced by [(efficiency*25)-25]%.
Machine can hold up to [max_items] pieces of produce."
+ . += "The status display reads: Productivity at [productivity*100]%.
Matter consumption reduced by [(efficiency*25)-25]%.
Machine can hold up to [max_items] pieces of produce."
/obj/machinery/biogenerator/on_reagent_change(changetype) //When the reagents change, change the icon as well.
update_icon()
diff --git a/code/modules/hydroponics/grown/melon.dm b/code/modules/hydroponics/grown/melon.dm
index 3bebfb5cbd5..cf9bf8ee63d 100644
--- a/code/modules/hydroponics/grown/melon.dm
+++ b/code/modules/hydroponics/grown/melon.dm
@@ -63,7 +63,7 @@
var/uses = 1
if(seed)
uses = round(seed.potency / 20)
- AddComponent(/datum/component/anti_magic, TRUE, TRUE, FALSE, null, uses, TRUE, CALLBACK(src, .proc/block_magic), CALLBACK(src, .proc/expire)) //deliver us from evil o melon god
+ AddComponent(/datum/component/anti_magic, TRUE, TRUE, FALSE, ITEM_SLOT_HANDS, uses, TRUE, CALLBACK(src, .proc/block_magic), CALLBACK(src, .proc/expire)) //deliver us from evil o melon god
/obj/item/reagent_containers/food/snacks/grown/holymelon/proc/block_magic(mob/user, major)
if(major)
diff --git a/code/modules/hydroponics/grown/towercap.dm b/code/modules/hydroponics/grown/towercap.dm
index e5cba0e2087..0389f41d1cc 100644
--- a/code/modules/hydroponics/grown/towercap.dm
+++ b/code/modules/hydroponics/grown/towercap.dm
@@ -50,7 +50,7 @@
/obj/item/reagent_containers/food/snacks/grown/wheat))
/obj/item/grown/log/attackby(obj/item/W, mob/user, params)
- if(W.sharpness)
+ if(W.is_sharp())
user.show_message("You make [plank_name] out of \the [src]!", 1)
var/seed_modifier = 0
if(seed)
@@ -75,7 +75,7 @@
qdel(src)
return
else
- to_chat(usr, "You must dry this first!")
+ to_chat(usr, "You must dry this first!")
else
return ..()
@@ -230,7 +230,7 @@
var/turf/open/O = loc
if(O.air)
var/loc_gases = O.air.gases
- if(loc_gases[/datum/gas/oxygen][MOLES] > 13)
+ if(loc_gases[/datum/gas/oxygen][MOLES] >= 5)
return TRUE
return FALSE
diff --git a/code/modules/hydroponics/hydroponics.dm b/code/modules/hydroponics/hydroponics.dm
index 84253c1a241..54b7f9d168f 100644
--- a/code/modules/hydroponics/hydroponics.dm
+++ b/code/modules/hydroponics/hydroponics.dm
@@ -49,7 +49,7 @@
/obj/machinery/hydroponics/constructable/examine(mob/user)
. = ..()
if(in_range(user, src) || isobserver(user))
- . += "The status display reads: Tray efficiency at [rating*100]%."
+ . += "The status display reads: Tray efficiency at [rating*100]%."
/obj/machinery/hydroponics/Destroy()
@@ -313,8 +313,8 @@
. += "It's empty."
if(!self_sustaining)
- . += {"Water: [waterlevel]/[maxwater].\n
- Nutrient: [nutrilevel]/[maxnutri]."}
+ . += "Water: [waterlevel]/[maxwater].\n"+\
+ "Nutrient: [nutrilevel]/[maxnutri]."
if(self_sufficiency_progress > 0)
var/percent_progress = round(self_sufficiency_progress * 100 / self_sufficiency_req)
. += "Treatment for self-sustenance are [percent_progress]% complete."
@@ -689,7 +689,7 @@
return
if(!reagent_source.reagents.total_volume)
- to_chat(user, "[reagent_source] is empty.")
+ to_chat(user, "[reagent_source] is empty!")
return 1
var/list/trays = list(src)//makes the list just this in cases of syringes and compost etc
@@ -699,6 +699,10 @@
var/transfer_amount
if(istype(reagent_source, /obj/item/reagent_containers/food/snacks) || istype(reagent_source, /obj/item/reagent_containers/pill))
+ if(istype(reagent_source, /obj/item/reagent_containers/food/snacks))
+ var/obj/item/reagent_containers/food/snacks/R = reagent_source
+ if (R.trash)
+ R.generate_trash(get_turf(user))
visi_msg="[user] composts [reagent_source], spreading it through [target]"
transfer_amount = reagent_source.reagents.total_volume
else
diff --git a/code/modules/hydroponics/seed_extractor.dm b/code/modules/hydroponics/seed_extractor.dm
index 710d86a4a7b..9fc59a33a77 100644
--- a/code/modules/hydroponics/seed_extractor.dm
+++ b/code/modules/hydroponics/seed_extractor.dm
@@ -59,7 +59,7 @@
/obj/machinery/seed_extractor/examine(mob/user)
. = ..()
if(in_range(user, src) || isobserver(user))
- . += "The status display reads: Extracting [seed_multiplier] seed(s) per piece of produce.
Machine can store up to [max_seeds]% seeds."
+ . += "The status display reads: Extracting [seed_multiplier] seed(s) per piece of produce.
Machine can store up to [max_seeds]% seeds."
/obj/machinery/seed_extractor/attackby(obj/item/O, mob/user, params)
diff --git a/code/modules/jobs/job_types/scientist.dm b/code/modules/jobs/job_types/scientist.dm
index 050e774070c..075c6e1de68 100644
--- a/code/modules/jobs/job_types/scientist.dm
+++ b/code/modules/jobs/job_types/scientist.dm
@@ -34,3 +34,7 @@
backpack = /obj/item/storage/backpack/science
satchel = /obj/item/storage/backpack/satchel/tox
+/datum/outfit/job/scientist/pre_equip(mob/living/carbon/human/H)
+ ..()
+ if(prob(0.4))
+ neck = /obj/item/clothing/neck/tie/horrible
diff --git a/code/modules/keybindings/bindings_human.dm b/code/modules/keybindings/bindings_human.dm
index 658ca87badf..c404acfcb7c 100644
--- a/code/modules/keybindings/bindings_human.dm
+++ b/code/modules/keybindings/bindings_human.dm
@@ -2,11 +2,13 @@
if(client.keys_held["Shift"])
switch(_key)
if("E") // Put held thing in belt or take out most recent thing from belt
+ if(incapacitated())
+ return
var/obj/item/thing = get_active_held_item()
var/obj/item/equipped_belt = get_item_by_slot(SLOT_BELT)
if(!equipped_belt) // We also let you equip a belt like this
if(!thing)
- to_chat(user, "You have no belt to take something out of.")
+ to_chat(user, "You have no belt to take something out of!")
return
if(equip_to_slot_if_possible(thing, SLOT_BELT))
update_inv_hands()
@@ -15,14 +17,14 @@
if(!thing)
equipped_belt.attack_hand(src)
else
- to_chat(user, "You can't fit anything in.")
+ to_chat(user, "You can't fit anything in!")
return
if(thing) // put thing in belt
if(!SEND_SIGNAL(equipped_belt, COMSIG_TRY_STORAGE_INSERT, thing, user.mob))
- to_chat(user, "You can't fit anything in.")
+ to_chat(user, "You can't fit anything in!")
return
if(!equipped_belt.contents.len) // nothing to take out
- to_chat(user, "There's nothing in your belt to take out.")
+ to_chat(user, "There's nothing in your belt to take out!")
return
var/obj/item/stored = equipped_belt.contents[equipped_belt.contents.len]
if(!stored || stored.on_found(src))
@@ -31,11 +33,13 @@
return
if("B") // Put held thing in backpack or take out most recent thing from backpack
+ if(incapacitated())
+ return
var/obj/item/thing = get_active_held_item()
var/obj/item/equipped_back = get_item_by_slot(SLOT_BACK)
if(!equipped_back) // We also let you equip a backpack like this
if(!thing)
- to_chat(user, "You have no backpack to take something out of.")
+ to_chat(user, "You have no backpack to take something out of!")
return
if(equip_to_slot_if_possible(thing, SLOT_BACK))
update_inv_hands()
@@ -44,18 +48,18 @@
if(!thing)
equipped_back.attack_hand(src)
else
- to_chat(user, "You can't fit anything in.")
+ to_chat(user, "You can't fit anything in!")
return
if(thing) // put thing in backpack
if(!SEND_SIGNAL(equipped_back, COMSIG_TRY_STORAGE_INSERT, thing, user.mob))
- to_chat(user, "You can't fit anything in.")
+ to_chat(user, "You can't fit anything in!")
return
if(!equipped_back.contents.len) // nothing to take out
- to_chat(user, "There's nothing in your backpack to take out.")
+ to_chat(user, "There's nothing in your backpack to take out!")
return
var/obj/item/stored = equipped_back.contents[equipped_back.contents.len]
if(!stored || stored.on_found(src))
return
stored.attack_hand(src) // take out thing from backpack
return
- return ..()
\ No newline at end of file
+ return ..()
diff --git a/code/modules/keybindings/bindings_mob.dm b/code/modules/keybindings/bindings_mob.dm
index 925f3055254..0b7fb66fdde 100644
--- a/code/modules/keybindings/bindings_mob.dm
+++ b/code/modules/keybindings/bindings_mob.dm
@@ -6,7 +6,7 @@
switch(_key)
if("Delete", "H")
if(!pulling)
- to_chat(src, "You are not pulling anything.")
+ to_chat(src, "You are not pulling anything!")
else
stop_pulling()
return
@@ -79,4 +79,4 @@
if("Alt")
toggle_move_intent()
return
- return ..()
\ No newline at end of file
+ return ..()
diff --git a/code/modules/mining/equipment/marker_beacons.dm b/code/modules/mining/equipment/marker_beacons.dm
index 2bbcf153f48..b8c387a1444 100644
--- a/code/modules/mining/equipment/marker_beacons.dm
+++ b/code/modules/mining/equipment/marker_beacons.dm
@@ -37,8 +37,8 @@ GLOBAL_LIST_INIT(marker_beacon_colors, list(
/obj/item/stack/marker_beacon/examine(mob/user)
. = ..()
- . += {"Use in-hand to place a [singular_name].\n
- Alt-click to select a color. Current color is [picked_color]."}
+ . += "Use in-hand to place a [singular_name].\n"+\
+ "Alt-click to select a color. Current color is [picked_color]."
/obj/item/stack/marker_beacon/update_icon()
icon_state = "[initial(icon_state)][lowertext(picked_color)]"
diff --git a/code/modules/mining/fulton.dm b/code/modules/mining/fulton.dm
index eb82914d753..146d0a94495 100644
--- a/code/modules/mining/fulton.dm
+++ b/code/modules/mining/fulton.dm
@@ -41,12 +41,12 @@ GLOBAL_LIST_EMPTY(total_extraction_beacons)
/obj/item/extraction_pack/afterattack(atom/movable/A, mob/living/carbon/human/user, flag, params)
. = ..()
if(!beacon)
- to_chat(user, "[src] is not linked to a beacon, and cannot be used.")
+ to_chat(user, "[src] is not linked to a beacon, and cannot be used!")
return
if(!can_use_indoors)
var/area/area = get_area(A)
if(!area.outdoors)
- to_chat(user, "[src] can only be used on things that are outdoors!")
+ to_chat(user, "[src] can only be used on things that are outdoors!")
return
if(!flag)
return
@@ -54,7 +54,7 @@ GLOBAL_LIST_EMPTY(total_extraction_beacons)
return
else
if(!safe_for_living_creatures && check_for_living_mobs(A))
- to_chat(user, "[src] is not safe for use with living creatures, they wouldn't survive the trip back!")
+ to_chat(user, "[src] is not safe for use with living creatures, they wouldn't survive the trip back!")
return
if(!isturf(A.loc)) // no extracting stuff inside other stuff
return
diff --git a/code/modules/mining/lavaland/ash_flora.dm b/code/modules/mining/lavaland/ash_flora.dm
index 260fe88a53d..2da3df26d7c 100644
--- a/code/modules/mining/lavaland/ash_flora.dm
+++ b/code/modules/mining/lavaland/ash_flora.dm
@@ -58,7 +58,7 @@
harvested = FALSE
/obj/structure/flora/ash/attackby(obj/item/W, mob/user, params)
- if(!harvested && needs_sharp_harvest && W.sharpness)
+ if(!harvested && needs_sharp_harvest && W.is_sharp())
user.visible_message("[user] starts to harvest from [src] with [W].","You begin to harvest from [src] with [W].")
if(do_after(user, harvest_time, target = src))
harvest(user)
diff --git a/code/modules/mining/lavaland/necropolis_chests.dm b/code/modules/mining/lavaland/necropolis_chests.dm
index 2b4ea1bcdf7..71201ebad47 100644
--- a/code/modules/mining/lavaland/necropolis_chests.dm
+++ b/code/modules/mining/lavaland/necropolis_chests.dm
@@ -664,9 +664,9 @@
/obj/item/melee/transforming/cleaving_saw/examine(mob/user)
. = ..()
- . += {"It is [active ? "open, will cleave enemies in a wide arc and deal additional damage to fauna":"closed, and can be used for rapid consecutive attacks that cause fauna to bleed"].\n
- Both modes will build up existing bleed effects, doing a burst of high damage if the bleed is built up high enough.\n
- Transforming it immediately after an attack causes the next attack to come out faster."}
+ . += "It is [active ? "open, will cleave enemies in a wide arc and deal additional damage to fauna":"closed, and can be used for rapid consecutive attacks that cause fauna to bleed"].\n"+\
+ "Both modes will build up existing bleed effects, doing a burst of high damage if the bleed is built up high enough.\n"+\
+ "Transforming it immediately after an attack causes the next attack to come out faster."
/obj/item/melee/transforming/cleaving_saw/suicide_act(mob/user)
user.visible_message("[user] is [active ? "closing [src] on [user.p_their()] neck" : "opening [src] into [user.p_their()] chest"]! It looks like [user.p_theyre()] trying to commit suicide!")
@@ -786,9 +786,9 @@
/obj/item/melee/ghost_sword/attack_self(mob/user)
if(summon_cooldown > world.time)
- to_chat(user, "You just recently called out for aid. You don't want to annoy the spirits.")
+ to_chat(user, "You just recently called out for aid. You don't want to annoy the spirits!")
return
- to_chat(user, "You call out for aid, attempting to summon spirits to your side.")
+ to_chat(user, "You call out for aid, attempting to summon spirits to your side.")
notify_ghosts("[user] is raising [user.p_their()] [src], calling for your help!",
enter_link="(Click to help)",
diff --git a/code/modules/mining/lavaland/ruins/gym.dm b/code/modules/mining/lavaland/ruins/gym.dm
index cf72bccfb19..7e46cbe3cf8 100644
--- a/code/modules/mining/lavaland/ruins/gym.dm
+++ b/code/modules/mining/lavaland/ruins/gym.dm
@@ -34,7 +34,7 @@
if(.)
return
if(obj_flags & IN_USE)
- to_chat(user, "It's already in use - wait a bit.")
+ to_chat(user, "It's already in use - wait a bit!")
return
else
obj_flags |= IN_USE
diff --git a/code/modules/mining/machine_redemption.dm b/code/modules/mining/machine_redemption.dm
index 719d3f75caf..4897bc01dd5 100644
--- a/code/modules/mining/machine_redemption.dm
+++ b/code/modules/mining/machine_redemption.dm
@@ -49,7 +49,7 @@
/obj/machinery/mineral/ore_redemption/examine(mob/user)
. = ..()
if(in_range(user, src) || isobserver(user))
- . += "The status display reads: Smelting [sheet_per_ore] sheet(s) per piece of ore.
Ore pickup speed at [ore_pickup_rate]."
+ . += "The status display reads: Smelting [sheet_per_ore] sheet(s) per piece of ore.
Ore pickup speed at [ore_pickup_rate]."
/obj/machinery/mineral/ore_redemption/proc/smelt_ore(obj/item/stack/ore/O)
var/datum/component/material_container/mat_container = materials.mat_container
diff --git a/code/modules/mining/mine_items.dm b/code/modules/mining/mine_items.dm
index a1ba493d466..f8dca6735f7 100644
--- a/code/modules/mining/mine_items.dm
+++ b/code/modules/mining/mine_items.dm
@@ -82,6 +82,14 @@
return
. = ..()
+/obj/machinery/computer/shuttle/mining/common
+ name = "lavaland shuttle console"
+ desc = "Used to call and send the lavaland shuttle."
+ circuit = /obj/item/circuitboard/computer/mining_shuttle/common
+ shuttleId = "mining_common"
+ possible_destinations = "whiteship_home;lavaland_common_away;landing_zone_dock;mining_public"
+
+
/**********************Mining car (Crate like thing, not the rail car)**************************/
/obj/structure/closet/crate/miningcar
diff --git a/code/modules/mining/minebot.dm b/code/modules/mining/minebot.dm
index 152f13855fa..f57a21374d7 100644
--- a/code/modules/mining/minebot.dm
+++ b/code/modules/mining/minebot.dm
@@ -88,7 +88,7 @@
/mob/living/simple_animal/hostile/mining_drone/welder_act(mob/living/user, obj/item/I)
. = TRUE
if(mode == MINEDRONE_ATTACK)
- to_chat(user, "[src] can't be repaired while in attack mode!")
+ to_chat(user, "[src] can't be repaired while in attack mode!")
return
if(maxHealth == health)
@@ -184,7 +184,7 @@
/mob/living/simple_animal/hostile/mining_drone/proc/DropOre(message = 1)
if(!contents.len)
if(message)
- to_chat(src, "You attempt to dump your stored ore, but you have none.")
+ to_chat(src, "You attempt to dump your stored ore, but you have none!")
return
if(message)
to_chat(src, "You dump your stored ore.")
@@ -277,7 +277,7 @@
/obj/item/mine_bot_upgrade/proc/upgrade_bot(mob/living/simple_animal/hostile/mining_drone/M, mob/user)
if(M.melee_damage_upper != initial(M.melee_damage_upper))
- to_chat(user, "[src] already has a combat upgrade installed!")
+ to_chat(user, "[src] already has a combat upgrade installed!")
return
M.melee_damage_lower += 7
M.melee_damage_upper += 7
@@ -290,7 +290,7 @@
/obj/item/mine_bot_upgrade/health/upgrade_bot(mob/living/simple_animal/hostile/mining_drone/M, mob/user)
if(M.maxHealth != initial(M.maxHealth))
- to_chat(user, "[src] already has reinforced armor!")
+ to_chat(user, "[src] already has reinforced armor!")
return
M.maxHealth += 45
M.updatehealth()
diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm
index dd78d40a2f9..1615cedfbfc 100644
--- a/code/modules/mob/dead/observer/observer.dm
+++ b/code/modules/mob/dead/observer/observer.dm
@@ -18,7 +18,6 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER)
hud_type = /datum/hud/ghost
movement_type = GROUND | FLYING
var/can_reenter_corpse
- var/do_not_resuscitate //determines whether we can switch can_reenter_corpse back off
var/datum/hud/living/carbon/hud = null // hud
var/bootime = 0
var/started_as_observer //This variable is set to 1 when you enter the game as an observer.
@@ -347,18 +346,15 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
if(!client)
return
if(!can_reenter_corpse)
- if(do_not_resuscitate)
- to_chat(src, "You can now re-enter your corpse, and can be cloned.")
- can_reenter_corpse = TRUE
- do_not_resuscitate = FALSE
- return TRUE
- else
- to_chat(usr, "You're already stuck out of your body!")
- return FALSE
+ to_chat(usr, "You're already stuck out of your body!")
+ return FALSE
+
+ var/response = alert(src, "Are you sure you want to prevent (almost) all means of resuscitation? This cannot be undone. ","Are you sure you want to stay dead?","DNR","Save Me")
+ if(response != "DNR")
+ return
can_reenter_corpse = FALSE
- do_not_resuscitate = TRUE
- to_chat(src, "You can now no longer be brought back into your body. You can undo this at any time by using the Do Not Resuscitate verb again.")
+ to_chat(src, "You can no longer be brought back into your body.")
return TRUE
/mob/dead/observer/proc/notify_cloning(var/message, var/sound, var/atom/source, flashwindow = TRUE)
@@ -388,7 +384,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
set name = "Teleport"
set desc= "Teleport to a location"
if(!isobserver(usr))
- to_chat(usr, "Not when you're not dead!")
+ to_chat(usr, "Not when you're not dead!")
return
var/list/filtered = list()
for(var/V in GLOB.sortedAreas)
@@ -405,7 +401,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
L+=T
if(!L || !L.len)
- to_chat(usr, "No area available.")
+ to_chat(usr, "No area available.")
return
usr.forceMove(pick(L))
@@ -829,7 +825,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
if(isobserver(src))
SSpai.recruitWindow(src)
else
- to_chat(usr, "Can't become a pAI candidate while not dead!")
+ to_chat(usr, "Can't become a pAI candidate while not dead!")
/mob/dead/observer/CtrlShiftClick(mob/user)
if(isobserver(user) && check_rights(R_SPAWN))
diff --git a/code/modules/mob/living/bloodcrawl.dm b/code/modules/mob/living/bloodcrawl.dm
index 4273dad86ca..7b37440ca47 100644
--- a/code/modules/mob/living/bloodcrawl.dm
+++ b/code/modules/mob/living/bloodcrawl.dm
@@ -74,7 +74,7 @@
if(victim.stat == CONSCIOUS)
src.visible_message("[victim] kicks free of the blood pool just before entering it!", null, "You hear splashing and struggling.")
- else if(victim.reagents && victim.reagents.has_reagent(/datum/reagent/consumable/ethanol/demonsblood))
+ else if(victim.reagents && victim.reagents.has_reagent(/datum/reagent/consumable/ethanol/demonsblood, needs_metabolizing = TRUE))
visible_message("Something prevents [victim] from entering the pool!", "A strange force is blocking [victim] from entering!", "You hear a splash and a thud.")
else
victim.forceMove(src)
@@ -105,7 +105,7 @@
if(!victim)
return FALSE
- if(victim.reagents && victim.reagents.has_reagent(/datum/reagent/consumable/ethanol/devilskiss))
+ if(victim.reagents && victim.reagents.has_reagent(/datum/reagent/consumable/ethanol/devilskiss, needs_metabolizing = TRUE))
to_chat(src, "AAH! THEIR FLESH! IT BURNS!")
adjustBruteLoss(25) //I can't use adjustHealth() here because bloodcrawl affects /mob/living and adjustHealth() only affects simple mobs
var/found_bloodpool = FALSE
diff --git a/code/modules/mob/living/brain/brain.dm b/code/modules/mob/living/brain/brain.dm
index 37ff6bd4ffc..165960d3d58 100644
--- a/code/modules/mob/living/brain/brain.dm
+++ b/code/modules/mob/living/brain/brain.dm
@@ -103,3 +103,9 @@
if(istype(loc, /obj/item/organ/brain))
var/obj/item/organ/brain/B = loc
. = B.traumas
+
+/mob/living/brain/get_policy_keywords()
+ . = ..()
+
+ if(container)
+ . += "[container.type]"
\ No newline at end of file
diff --git a/code/modules/mob/living/brain/brain_item.dm b/code/modules/mob/living/brain/brain_item.dm
index 0caa7f44004..0583bab6ab5 100644
--- a/code/modules/mob/living/brain/brain_item.dm
+++ b/code/modules/mob/living/brain/brain_item.dm
@@ -24,7 +24,7 @@
if(C.mind && C.mind.has_antag_datum(/datum/antagonist/changeling) && !no_id_transfer) //congrats, you're trapped in a body you don't control
if(brainmob && !(C.stat == DEAD || (HAS_TRAIT(C, TRAIT_DEATHCOMA))))
- to_chat(brainmob, "You can't feel your body! You're still just a brain!")
+ to_chat(brainmob, "You can't feel your body! You're still just a brain!")
forceMove(C)
C.update_hair()
return
diff --git a/code/modules/mob/living/carbon/alien/humanoid/caste/drone.dm b/code/modules/mob/living/carbon/alien/humanoid/caste/drone.dm
index d3ed8a6541a..0caf814b6c6 100644
--- a/code/modules/mob/living/carbon/alien/humanoid/caste/drone.dm
+++ b/code/modules/mob/living/carbon/alien/humanoid/caste/drone.dm
@@ -32,7 +32,7 @@
return 0
if(!isturf(user.loc))
- to_chat(user, "You can't evolve here!")
+ to_chat(user, "You can't evolve here!")
return 0
if(!get_alien_type(/mob/living/carbon/alien/humanoid/royal))
var/mob/living/carbon/alien/humanoid/royal/praetorian/new_xeno = new (user.loc)
@@ -40,4 +40,4 @@
return 1
else
to_chat(user, "We already have a living royal!")
- return 0
\ No newline at end of file
+ return 0
diff --git a/code/modules/mob/living/carbon/alien/humanoid/caste/hunter.dm b/code/modules/mob/living/carbon/alien/humanoid/caste/hunter.dm
index a998d63ec87..7979aced77b 100644
--- a/code/modules/mob/living/carbon/alien/humanoid/caste/hunter.dm
+++ b/code/modules/mob/living/carbon/alien/humanoid/caste/hunter.dm
@@ -69,7 +69,7 @@
if(H.check_shields(src, 0, "the [name]", attack_type = LEAP_ATTACK))
blocked = TRUE
if(!blocked)
- L.visible_message("[src] pounces on [L]!", "[src] pounces on you!")
+ L.visible_message("[src] pounces on [L]!", "[src] pounces on you!")
L.Paralyze(100)
sleep(2)//Runtime prevention (infinite bump() calls on hulks)
step_towards(src,L)
@@ -78,7 +78,7 @@
toggle_leap(0)
else if(hit_atom.density && !hit_atom.CanPass(src))
- visible_message("[src] smashes into [hit_atom]!", "[src] smashes into [hit_atom]!")
+ visible_message("[src] smashes into [hit_atom]!", "[src] smashes into [hit_atom]!")
Paralyze(40, 1, 1)
if(leaping)
diff --git a/code/modules/mob/living/carbon/alien/larva/powers.dm b/code/modules/mob/living/carbon/alien/larva/powers.dm
index 9d5617b3e73..abc3ffd14f9 100644
--- a/code/modules/mob/living/carbon/alien/larva/powers.dm
+++ b/code/modules/mob/living/carbon/alien/larva/powers.dm
@@ -33,7 +33,7 @@
var/mob/living/carbon/alien/larva/L = user
if(L.handcuffed || L.legcuffed) // Cuffing larvas ? Eh ?
- to_chat(user, "You cannot evolve when you are cuffed.")
+ to_chat(user, "You cannot evolve when you are cuffed!")
return
if(L.amount_grown >= L.max_grown) //TODO ~Carn
@@ -59,5 +59,5 @@
L.alien_evolve(new_xeno)
return 0
else
- to_chat(user, "You are not fully grown.")
+ to_chat(user, "You are not fully grown!")
return 0
diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm
index ede9eeef694..0be331d1171 100644
--- a/code/modules/mob/living/carbon/carbon.dm
+++ b/code/modules/mob/living/carbon/carbon.dm
@@ -468,7 +468,7 @@
add_splatter_floor(T)
if(stun)
adjustBruteLoss(3)
- else if(src.reagents.has_reagent(/datum/reagent/consumable/ethanol/blazaam))
+ else if(src.reagents.has_reagent(/datum/reagent/consumable/ethanol/blazaam, needs_metabolizing = TRUE))
if(T)
T.add_vomit_floor(src, VOMIT_PURPLE)
else
@@ -796,9 +796,9 @@
/mob/living/carbon/fully_heal(admin_revive = FALSE)
if(reagents)
reagents.clear_reagents()
- var/obj/item/organ/liver/L = getorganslot(ORGAN_SLOT_LIVER)
- if(L)
- L.damage = 0
+ for(var/O in internal_organs)
+ var/obj/item/organ/organ = O
+ organ.setOrganDamage(0)
var/obj/item/organ/brain/B = getorgan(/obj/item/organ/brain)
if(B)
B.brain_death = FALSE
diff --git a/code/modules/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm
index 902971b3e19..d3af7ea214e 100644
--- a/code/modules/mob/living/carbon/carbon_defense.dm
+++ b/code/modules/mob/living/carbon/carbon_defense.dm
@@ -1,35 +1,24 @@
-
/mob/living/carbon/get_eye_protection()
- var/number = ..()
-
- if(istype(src.head, /obj/item/clothing/head)) //are they wearing something on their head
- var/obj/item/clothing/head/HFP = src.head //if yes gets the flash protection value from that item
- number += HFP.flash_protect
-
- if(istype(src.glasses, /obj/item/clothing/glasses)) //glasses
- var/obj/item/clothing/glasses/GFP = src.glasses
- number += GFP.flash_protect
-
- if(istype(src.wear_mask, /obj/item/clothing/mask)) //mask
- var/obj/item/clothing/mask/MFP = src.wear_mask
- number += MFP.flash_protect
-
+ . = ..()
var/obj/item/organ/eyes/E = getorganslot(ORGAN_SLOT_EYES)
if(!E)
- number = INFINITY //Can't get flashed without eyes
+ return INFINITY //Can't get flashed without eyes
else
- number += E.flash_protect
-
- return number
+ . += E.flash_protect
+ if(isclothing(head)) //Adds head protection
+ . += head.flash_protect
+ if(isclothing(glasses)) //Glasses
+ . += glasses.flash_protect
+ if(isclothing(wear_mask)) //Mask
+ . += wear_mask.flash_protect
/mob/living/carbon/get_ear_protection()
- var/number = ..()
+ . = ..()
var/obj/item/organ/ears/E = getorganslot(ORGAN_SLOT_EARS)
if(!E)
- number = INFINITY
+ return INFINITY
else
- number += E.bang_protect
- return number
+ . += E.bang_protect
/mob/living/carbon/is_mouth_covered(head_only = 0, mask_only = 0)
if( (!mask_only && head && (head.flags_cover & HEADCOVERSMOUTH)) || (!head_only && wear_mask && (wear_mask.flags_cover & MASKCOVERSMOUTH)) )
@@ -312,30 +301,30 @@
if (damage == 1)
to_chat(src, "Your eyes sting a little.")
if(prob(40))
- adjust_eye_damage(1)
+ eyes.applyOrganDamage(1)
else if (damage == 2)
to_chat(src, "Your eyes burn.")
- adjust_eye_damage(rand(2, 4))
+ eyes.applyOrganDamage(rand(2, 4))
else if( damage >= 3)
to_chat(src, "Your eyes itch and burn severely!")
- adjust_eye_damage(rand(12, 16))
+ eyes.applyOrganDamage(rand(12, 16))
- if(eyes.eye_damage > 10)
+ if(eyes.damage > 10)
blind_eyes(damage)
blur_eyes(damage * rand(3, 6))
- if(eyes.eye_damage > 20)
- if(prob(eyes.eye_damage - 20))
+ if(eyes.damage > 20)
+ if(prob(eyes.damage - 20))
if(!HAS_TRAIT(src, TRAIT_NEARSIGHT))
to_chat(src, "Your eyes start to burn badly!")
become_nearsighted(EYE_DAMAGE)
- else if(prob(eyes.eye_damage - 25))
+ else if(prob(eyes.damage - 25))
if(!HAS_TRAIT(src, TRAIT_BLIND))
to_chat(src, "You can't see anything!")
- become_blind(EYE_DAMAGE)
+ eyes.applyOrganDamage(eyes.maxHealth)
else
to_chat(src, "Your eyes are really starting to hurt. This can't be good for you!")
@@ -365,13 +354,13 @@
var/deaf = deafen_pwr * effect_amount
adjustEarDamage(ear_damage,deaf)
- if(ears.ear_damage >= 15)
+ if(ears.damage >= 15)
to_chat(src, "Your ears start to ring badly!")
- if(prob(ears.ear_damage - 5))
+ if(prob(ears.damage - 5))
to_chat(src, "You can't hear anything!")
- ears.ear_damage = min(ears.ear_damage, UNHEALING_EAR_DAMAGE)
+ ears.damage = min(ears.damage, ears.maxHealth)
// you need earmuffs, inacusiate, or replacement
- else if(ears.ear_damage >= 5)
+ else if(ears.damage >= 5)
to_chat(src, "Your ears start to ring!")
SEND_SOUND(src, sound('sound/weapons/flash_ring.ogg',0,1,0,250))
return effect_amount //how soundbanged we are
diff --git a/code/modules/mob/living/carbon/damage_procs.dm b/code/modules/mob/living/carbon/damage_procs.dm
index babd0ec041c..7b3b2fddfaf 100644
--- a/code/modules/mob/living/carbon/damage_procs.dm
+++ b/code/modules/mob/living/carbon/damage_procs.dm
@@ -254,3 +254,28 @@
if(B)
var/adjusted_amount = amount - B.get_brain_damage()
B.adjust_brain_damage(adjusted_amount, null)
+
+/mob/living/carbon/proc/getLiverLoss()
+ . = 0
+ var/obj/item/organ/liver/L = getorganslot(ORGAN_SLOT_LIVER)
+ if(L)
+ . = L.damage
+
+/mob/living/carbon/proc/adjustLiverLoss(amount, check_toxres = TRUE, rev_failure = FALSE)
+ if(status_flags & GODMODE)
+ return 0
+ var/obj/item/organ/liver/L = getorganslot(ORGAN_SLOT_LIVER)
+ if(!L)
+ return
+
+ if(amount < 0 && L.failing && !rev_failure)
+ return 0
+
+ var/adjusted_amount = amount
+
+ if(check_toxres)
+ adjusted_amount *= 100 * L.toxLethality
+
+ L.damage += adjusted_amount
+
+ return adjusted_amount
diff --git a/code/modules/mob/living/carbon/human/death.dm b/code/modules/mob/living/carbon/human/death.dm
index 3a7f39cc956..c32f67f30f3 100644
--- a/code/modules/mob/living/carbon/human/death.dm
+++ b/code/modules/mob/living/carbon/human/death.dm
@@ -38,6 +38,7 @@
if(SSticker.HasRoundStarted())
SSblackbox.ReportDeath(src)
+ log_game("[key_name(src)] has died (BRUTE: [src.getBruteLoss()], BURN: [src.getFireLoss()], TOX: [src.getToxLoss()], OXY: [src.getOxyLoss()], CLONE: [src.getCloneLoss()]) ([AREACOORD(src)])")
if(is_devil(src))
INVOKE_ASYNC(is_devil(src), /datum/antagonist/devil.proc/beginResurrectionCheck, src)
if(is_hivemember(src))
diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm
index 0f070b0ef18..06b19802bb8 100644
--- a/code/modules/mob/living/carbon/human/examine.dm
+++ b/code/modules/mob/living/carbon/human/examine.dm
@@ -224,12 +224,12 @@
if(bleedsuppress)
msg += "[t_He] [t_is] bandaged with something.\n"
else if(bleed_rate)
- if(reagents.has_reagent(/datum/reagent/toxin/heparin))
+ if(reagents.has_reagent(/datum/reagent/toxin/heparin, needs_metabolizing = TRUE))
msg += "[t_He] [t_is] bleeding uncontrollably!\n"
else
msg += "[t_He] [t_is] bleeding!\n"
- if(reagents.has_reagent(/datum/reagent/teslium))
+ if(reagents.has_reagent(/datum/reagent/teslium, needs_metabolizing = TRUE))
msg += "[t_He] [t_is] emitting a gentle blue glow!\n"
if(islist(stun_absorption))
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index 95c7adb2f1a..98b616f722f 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -839,7 +839,7 @@
/mob/living/carbon/human/proc/fireman_carry(mob/living/carbon/target)
if(can_be_firemanned(target))
- visible_message("[src] starts lifting [target] onto their back...",
+ visible_message("[src] starts lifting [target] onto their back...",
"You start lifting [target] onto your back...")
if(do_after(src, 50, TRUE, target))
//Second check to make sure they're still valid to be carried
@@ -848,7 +848,7 @@
return
visible_message("[src] fails to fireman carry [target]!")
else
- to_chat(src, "You can't fireman carry [target] while they're standing!")
+ to_chat(src, "You can't fireman carry [target] while they're standing!")
/mob/living/carbon/human/proc/piggyback(mob/living/carbon/target)
if(can_piggyback(target))
@@ -885,14 +885,14 @@
if(hands_needed || target_hands_needed)
if(hands_needed && !equipped_hands_self)
- src.visible_message("[src] can't get a grip on [target] because their hands are full!",
+ src.visible_message("[src] can't get a grip on [target] because their hands are full!",
"You can't get a grip on [target] because your hands are full!")
return
else if(target_hands_needed && !equipped_hands_target)
target.visible_message("[target] can't get a grip on [src] because their hands are full!",
"You can't get a grip on [src] because your hands are full!")
return
-
+
stop_pulling()
riding_datum.handle_vehicle_layer()
. = ..(target, force, check_loc)
diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm
index 8af0ce6273b..9bc37d02b33 100644
--- a/code/modules/mob/living/carbon/human/human_defense.dm
+++ b/code/modules/mob/living/carbon/human/human_defense.dm
@@ -7,7 +7,7 @@
var/obj/item/bodypart/bp = def_zone
if(bp)
return checkarmor(def_zone, type)
- var/obj/item/bodypart/affecting = get_bodypart(ran_zone(def_zone))
+ var/obj/item/bodypart/affecting = get_bodypart(check_zone(def_zone))
if(affecting)
return checkarmor(affecting, type)
//If a specific bodypart is targetted, check how that bodypart is protected and return the value.
diff --git a/code/modules/mob/living/carbon/human/human_helpers.dm b/code/modules/mob/living/carbon/human/human_helpers.dm
index 438e0e9a215..72950716bd8 100644
--- a/code/modules/mob/living/carbon/human/human_helpers.dm
+++ b/code/modules/mob/living/carbon/human/human_helpers.dm
@@ -152,6 +152,7 @@
return .
/mob/living/carbon/human/proc/get_bank_account()
+ RETURN_TYPE(/datum/bank_account)
var/datum/bank_account/account
var/obj/item/card/id/I = get_idcard()
@@ -163,4 +164,15 @@
/mob/living/carbon/human/get_policy_keywords()
. = ..()
- . += "[dna.species.type]"
\ No newline at end of file
+ . += "[dna.species.type]"
+
+/mob/living/carbon/human/can_see_reagents()
+ . = ..()
+ if(.) //No need to run through all of this if it's already true.
+ return
+ if(isclothing(glasses) && (glasses.clothing_flags & SCAN_REAGENTS))
+ return TRUE
+ if(isclothing(head) && (head.clothing_flags & SCAN_REAGENTS))
+ return TRUE
+ if(isclothing(wear_mask) && (wear_mask.clothing_flags & SCAN_REAGENTS))
+ return TRUE
diff --git a/code/modules/mob/living/carbon/human/inventory.dm b/code/modules/mob/living/carbon/human/inventory.dm
index 7c10ca81461..5a4e2600858 100644
--- a/code/modules/mob/living/carbon/human/inventory.dm
+++ b/code/modules/mob/living/carbon/human/inventory.dm
@@ -189,7 +189,6 @@
if(G.vision_correction)
if(HAS_TRAIT(src, TRAIT_NEARSIGHT))
overlay_fullscreen("nearsighted", /obj/screen/fullscreen/impaired, 1)
- adjust_eye_damage(0)
if(G.vision_flags || G.darkness_view || G.invis_override || G.invis_view || !isnull(G.lighting_alpha))
update_sight()
if(!QDELETED(src))
diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm
index b03ae5fa333..f9807723cbb 100644
--- a/code/modules/mob/living/carbon/human/species.dm
+++ b/code/modules/mob/living/carbon/human/species.dm
@@ -1155,9 +1155,9 @@ GLOBAL_LIST_EMPTY(roundstart_races)
if(we_breathe && we_lung)
user.do_cpr(target)
else if(we_breathe && !we_lung)
- to_chat(user, "You have no lungs to breathe with, so you cannot perform CPR.")
+ to_chat(user, "You have no lungs to breathe with, so you cannot perform CPR!")
else
- to_chat(user, "You do not breathe, so you cannot perform CPR.")
+ to_chat(user, "You do not breathe, so you cannot perform CPR!")
/datum/species/proc/grab(mob/living/carbon/human/user, mob/living/carbon/human/target, datum/martial_art/attacker_style)
if(target.check_block())
diff --git a/code/modules/mob/living/carbon/human/species_types/plasmamen.dm b/code/modules/mob/living/carbon/human/species_types/plasmamen.dm
index e84e8d08d69..39fb44584c5 100644
--- a/code/modules/mob/living/carbon/human/species_types/plasmamen.dm
+++ b/code/modules/mob/living/carbon/human/species_types/plasmamen.dm
@@ -113,18 +113,18 @@
if("Atmospheric Technician")
O = new /datum/outfit/plasmaman/atmospherics
+
+ if("Mime")
+ O = new /datum/outfit/plasmaman/mime
+
+ if("Clown")
+ O = new /datum/outfit/plasmaman/clown
+
H.equipOutfit(O, visualsOnly)
H.internal = H.get_item_for_held_index(2)
H.update_internals_hud_icon(1)
return 0
-/datum/species/plasmaman/qualifies_for_rank(rank, list/features)
- if(rank in GLOB.security_positions)
- return 0
- if(rank == "Clown" || rank == "Mime")//No funny bussiness
- return 0
- return ..()
-
/datum/species/plasmaman/random_name(gender,unique,lastname)
if(unique)
return random_unique_plasmaman_name()
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 3aec4b0211a..eb6ebcea255 100644
--- a/code/modules/mob/living/carbon/human/species_types/vampire.dm
+++ b/code/modules/mob/living/carbon/human/species_types/vampire.dm
@@ -53,7 +53,7 @@
C.dust()
var/area/A = get_area(C)
if(istype(A, /area/chapel))
- to_chat(C, "You don't belong here!")
+ to_chat(C, "You don't belong here!")
C.adjustFireLoss(20)
C.adjust_fire_stacks(6)
C.IgniteMob()
@@ -81,18 +81,18 @@
var/mob/living/carbon/H = owner
var/obj/item/organ/tongue/vampire/V = target
if(V.drain_cooldown >= world.time)
- to_chat(H, "You just drained blood, wait a few seconds.")
+ to_chat(H, "You just drained blood, wait a few seconds!")
return
if(H.pulling && iscarbon(H.pulling))
var/mob/living/carbon/victim = H.pulling
if(H.blood_volume >= BLOOD_VOLUME_MAXIMUM)
- to_chat(H, "You're already full!")
+ to_chat(H, "You're already full!")
return
if(victim.stat == DEAD)
- to_chat(H, "You need a living victim!")
+ to_chat(H, "You need a living victim!")
return
if(!victim.blood_volume || (victim.dna && ((NOBLOOD in victim.dna.species.species_traits) || victim.dna.species.exotic_blood)))
- to_chat(H, "[victim] doesn't have blood!")
+ to_chat(H, "[victim] doesn't have blood!")
return
V.drain_cooldown = world.time + 30
if(victim.anti_magic_check(FALSE, TRUE, FALSE, 0))
@@ -113,7 +113,7 @@
victim.blood_volume = CLAMP(victim.blood_volume - drained_blood, 0, BLOOD_VOLUME_MAXIMUM)
H.blood_volume = CLAMP(H.blood_volume + drained_blood, 0, BLOOD_VOLUME_MAXIMUM)
if(!victim.blood_volume)
- to_chat(H, "You finish off [victim]'s blood supply!")
+ to_chat(H, "You finish off [victim]'s blood supply.")
#undef VAMP_DRAIN_AMOUNT
diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm
index 550563a8c50..81585ecce57 100644
--- a/code/modules/mob/living/carbon/life.dm
+++ b/code/modules/mob/living/carbon/life.dm
@@ -65,7 +65,7 @@
//Second link in a breath chain, calls check_breath()
/mob/living/carbon/proc/breathe()
- if(reagents.has_reagent(/datum/reagent/toxin/lexorin))
+ if(reagents.has_reagent(/datum/reagent/toxin/lexorin, needs_metabolizing = TRUE))
return
if(istype(loc, /obj/machinery/atmospherics/components/unary/cryo_cell))
return
@@ -137,7 +137,7 @@
//CRIT
if(!breath || (breath.total_moles() == 0) || !lungs)
- if(reagents.has_reagent(/datum/reagent/medicine/epinephrine) && lungs)
+ if(reagents.has_reagent(/datum/reagent/medicine/epinephrine, needs_metabolizing = TRUE) && lungs)
return
adjustOxyLoss(1)
@@ -593,16 +593,6 @@ GLOBAL_LIST_INIT(ballmer_windows_me_msg, list("Yo man, what if, we like, uh, put
if(liver && liver.failing)
return TRUE
-/mob/living/carbon/proc/return_liver_damage()
- var/obj/item/organ/liver/liver = getorganslot(ORGAN_SLOT_LIVER)
- if(liver)
- return liver.damage
-
-/mob/living/carbon/proc/applyLiverDamage(var/d)
- var/obj/item/organ/liver/L = getorganslot(ORGAN_SLOT_LIVER)
- if(L)
- L.damage += d
-
/mob/living/carbon/proc/liver_failure()
reagents.end_metabolization(src, keep_liverless = TRUE) //Stops trait-based effects on reagents, to prevent permanent buffs
reagents.metabolize(src, can_overdose=FALSE, liverless = TRUE)
@@ -623,7 +613,7 @@ GLOBAL_LIST_INIT(ballmer_windows_me_msg, list("Yo man, what if, we like, uh, put
BT.on_life()
if(getBrainLoss() >= BRAIN_DAMAGE_DEATH) //rip
- to_chat(src, "The last spark of life in your brain fizzles out...")
+ to_chat(src, "The last spark of life in your brain fizzles out...")
death()
var/obj/item/organ/brain/B = getorganslot(ORGAN_SLOT_BRAIN)
if(B)
diff --git a/code/modules/mob/living/carbon/status_procs.dm b/code/modules/mob/living/carbon/status_procs.dm
index efbb855f2b5..8f8663687e2 100644
--- a/code/modules/mob/living/carbon/status_procs.dm
+++ b/code/modules/mob/living/carbon/status_procs.dm
@@ -1,6 +1,6 @@
//Here are the procs used to modify status effects of a mob.
//The effects include: stun, knockdown, unconscious, sleeping, resting, jitteriness, dizziness, ear damage,
-// eye damage, eye_blind, eye_blurry, druggy, TRAIT_BLIND trait, TRAIT_NEARSIGHT trait, and TRAIT_HUSK trait.
+//eye_blind, eye_blurry, druggy, TRAIT_BLIND trait, TRAIT_NEARSIGHT trait, and TRAIT_HUSK trait.
/mob/living/carbon/IsParalyzed(include_stamcrit = TRUE)
@@ -15,44 +15,6 @@
to_chat(src, "You're too exhausted to keep going...")
stam_paralyzed = TRUE
-/mob/living/carbon/damage_eyes(amount)
- var/obj/item/organ/eyes/eyes = getorganslot(ORGAN_SLOT_EYES)
- if (!eyes)
- return
- if(amount>0)
- eyes.eye_damage = amount
- if(eyes.eye_damage > 20)
- if(eyes.eye_damage > 30)
- overlay_fullscreen("eye_damage", /obj/screen/fullscreen/impaired, 2)
- else
- overlay_fullscreen("eye_damage", /obj/screen/fullscreen/impaired, 1)
-
-/mob/living/carbon/set_eye_damage(amount)
- var/obj/item/organ/eyes/eyes = getorganslot(ORGAN_SLOT_EYES)
- if (!eyes)
- return
- eyes.eye_damage = max(amount,0)
- if(eyes.eye_damage > 20)
- if(eyes.eye_damage > 30)
- overlay_fullscreen("eye_damage", /obj/screen/fullscreen/impaired, 2)
- else
- overlay_fullscreen("eye_damage", /obj/screen/fullscreen/impaired, 1)
- else
- clear_fullscreen("eye_damage")
-
-/mob/living/carbon/adjust_eye_damage(amount)
- var/obj/item/organ/eyes/eyes = getorganslot(ORGAN_SLOT_EYES)
- if (!eyes)
- return
- eyes.eye_damage = max(eyes.eye_damage+amount, 0)
- if(eyes.eye_damage > 20)
- if(eyes.eye_damage > 30)
- overlay_fullscreen("eye_damage", /obj/screen/fullscreen/impaired, 2)
- else
- overlay_fullscreen("eye_damage", /obj/screen/fullscreen/impaired, 1)
- else
- clear_fullscreen("eye_damage")
-
/mob/living/carbon/adjust_drugginess(amount)
druggy = max(druggy+amount, 0)
if(druggy)
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index d3be0b04724..f66de10a8fe 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -299,7 +299,7 @@
var/mob/living/carbon/C = L
if(HAS_TRAIT(src, TRAIT_STRONG_GRABBER))
C.grippedby(src)
-
+
update_pull_movespeed()
set_pull_offsets(M, state)
@@ -436,7 +436,7 @@
set category = "IC"
if(IsSleeping())
- to_chat(src, "You are already sleeping.")
+ to_chat(src, "You are already sleeping!")
return
else
if(alert(src, "You sure you want to sleep for a while?", "Sleep", "Yes", "No") == "Yes")
@@ -455,7 +455,7 @@
if(do_after(src, 10, target = src))
set_resting(FALSE, FALSE)
else
- to_chat(src, "You fail to get up.")
+ to_chat(src, "You fail to get up!")
/mob/living/proc/set_resting(rest, silent = TRUE)
if(!silent)
@@ -491,15 +491,6 @@
/mob/living/is_drawable(mob/user, allowmobs = TRUE)
return (allowmobs && reagents && can_inject(user))
-/mob/living/proc/get_organ_target()
- var/mob/shooter = src
- var/t = shooter.zone_selected
- if ((t in list( BODY_ZONE_PRECISE_EYES, BODY_ZONE_PRECISE_MOUTH )))
- t = BODY_ZONE_HEAD
- var/def_zone = ran_zone(t)
- return def_zone
-
-
/mob/living/proc/updatehealth()
if(status_flags & GODMODE)
return
@@ -556,7 +547,7 @@
set_blindness(0)
set_blurriness(0)
set_dizziness(0)
- set_eye_damage(0)
+
cure_nearsighted()
cure_blind()
cure_husk()
@@ -1306,7 +1297,9 @@
if("eye_blind")
set_blindness(var_value)
if("eye_damage")
- set_eye_damage(var_value)
+ var/obj/item/organ/eyes/E = getorganslot(ORGAN_SLOT_EYES)
+ if(E)
+ E.setOrganDamage(var_value)
if("eye_blurry")
set_blurriness(var_value)
if("maxHealth")
diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm
index 588ee2da21e..858440544e3 100644
--- a/code/modules/mob/living/living_defense.dm
+++ b/code/modules/mob/living/living_defense.dm
@@ -3,7 +3,7 @@
var/armor = getarmor(def_zone, attack_flag)
//the if "armor" check is because this is used for everything on /living, including humans
- if(armor && armour_penetration)
+ if(armor > 0 && armour_penetration)
armor = max(0, armor - armour_penetration)
if(penetrated_text)
to_chat(src, "[penetrated_text]")
@@ -138,7 +138,7 @@
return FALSE
if(user.grab_state >= GRAB_AGGRESSIVE && HAS_TRAIT(user, TRAIT_PACIFISM))
- to_chat(user, "You don't want to risk hurting [src]!")
+ to_chat(user, "You don't want to risk hurting [src]!")
return FALSE
grippedby(user)
@@ -150,7 +150,7 @@
if(ishuman(user))
var/mob/living/carbon/human/H = user
if(H.dna.species.grab_sound)
- sound_to_play = H.dna.species.grab_sound
+ sound_to_play = H.dna.species.grab_sound
playsound(src.loc, sound_to_play, 50, 1, -1)
if(user.grab_state) //only the first upgrade is instantaneous
@@ -168,7 +168,7 @@
if(!user.pulling || user.pulling != src || user.grab_state != old_grab_state)
return 0
if(user.a_intent != INTENT_GRAB)
- to_chat(user, "You must be on grab intent to upgrade your grab further!")
+ to_chat(user, "You must be on grab intent to upgrade your grab further!")
return 0
user.grab_state++
switch(user.grab_state)
@@ -213,7 +213,7 @@
return // can't attack while eating!
if(HAS_TRAIT(src, TRAIT_PACIFISM))
- to_chat(M, "You don't want to hurt anyone!")
+ to_chat(M, "You don't want to hurt anyone!")
return FALSE
if (stat != DEAD)
@@ -230,7 +230,7 @@
return FALSE
else
if(HAS_TRAIT(M, TRAIT_PACIFISM))
- to_chat(M, "You don't want to hurt anyone!")
+ to_chat(M, "You don't want to hurt anyone!")
return FALSE
if(M.attack_sound)
@@ -249,7 +249,7 @@
if (M.a_intent == INTENT_HARM)
if(HAS_TRAIT(M, TRAIT_PACIFISM))
- to_chat(M, "You don't want to hurt anyone!")
+ to_chat(M, "You don't want to hurt anyone!")
return FALSE
if(M.is_muzzled() || M.is_mouth_covered(FALSE, TRUE))
@@ -275,7 +275,7 @@
else
if(HAS_TRAIT(L, TRAIT_PACIFISM))
- to_chat(L, "You don't want to hurt anyone!")
+ to_chat(L, "You don't want to hurt anyone!")
return
L.do_attack_animation(src)
@@ -300,7 +300,7 @@
return FALSE
if("harm")
if(HAS_TRAIT(M, TRAIT_PACIFISM))
- to_chat(M, "You don't want to hurt anyone!")
+ to_chat(M, "You don't want to hurt anyone!")
return FALSE
M.do_attack_animation(src)
return TRUE
diff --git a/code/modules/mob/living/say.dm b/code/modules/mob/living/say.dm
index d7ec44292aa..9c6bdd1ea4b 100644
--- a/code/modules/mob/living/say.dm
+++ b/code/modules/mob/living/say.dm
@@ -88,15 +88,20 @@ GLOBAL_LIST_INIT(department_radio_keys, list(
var/static/list/one_character_prefix = list(MODE_HEADSET = TRUE, MODE_ROBOT = TRUE, MODE_WHISPER = TRUE)
+ var/ic_blocked = FALSE
+ if(client && !forced && config.ic_filter_regex && findtext(message, config.ic_filter_regex))
+ //The filter doesn't act on the sanitized message, but the raw message.
+ ic_blocked = TRUE
+
if(sanitize)
message = trim(copytext(sanitize(message), 1, MAX_MESSAGE_LEN))
if(!message || message == "")
return
- if(GLOB.in_character_filter.len && !forced)
- if(findtext(message, config.ic_filter_regex))
- to_chat(src, "That message contained a word prohibited in IC chat! Consider reviewing the server rules.")
- return
+ if(ic_blocked)
+ //The filter warning message shows the sanitized message though.
+ to_chat(src, "That message contained a word prohibited in IC chat! Consider reviewing the server rules.\n\"[message]\"")
+ return
var/datum/saymode/saymode = SSradio.saymodes[talk_key]
var/message_mode = get_message_mode(message)
diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm
index 15ed13269a5..ce503be9454 100644
--- a/code/modules/mob/living/silicon/ai/ai.dm
+++ b/code/modules/mob/living/silicon/ai/ai.dm
@@ -825,7 +825,7 @@
/mob/living/silicon/ai/can_buckle()
return 0
-/mob/living/silicon/ai/incapacitated(ignore_restraints = FALSE, ignore_grab = FALSE, check_immobilized = FALSE)
+/mob/living/silicon/ai/incapacitated(ignore_restraints = FALSE, ignore_grab = FALSE, check_immobilized = FALSE, ignore_stasis = FALSE)
if(aiRestorePowerRoutine)
return TRUE
return ..()
diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm
index 2f8c630ecd5..728a464c602 100644
--- a/code/modules/mob/living/silicon/robot/robot.dm
+++ b/code/modules/mob/living/silicon/robot/robot.dm
@@ -441,7 +441,7 @@
else if(W.tool_behaviour == TOOL_SCREWDRIVER && opened && cell) // radio
if(shell)
- to_chat(user, "You cannot seem to open the radio compartment") //Prevent AI radio key theft
+ to_chat(user, "You cannot seem to open the radio compartment!") //Prevent AI radio key theft
else if(radio)
radio.attackby(W,user)//Push it to the radio to let it handle everything
else
@@ -450,7 +450,7 @@
else if(W.tool_behaviour == TOOL_WRENCH && opened && !cell) //Deconstruction. The flashes break from the fall, to prevent this from being a ghetto reset module.
if(!lockcharge)
- to_chat(user, "[src]'s bolts spark! Maybe you should lock them down first!")
+ to_chat(user, "[src]'s bolts spark! Maybe you should lock them down first!")
spark_system.start()
return
else
diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm
index da9a15af6e2..32e3bcfd035 100644
--- a/code/modules/mob/living/silicon/robot/robot_modules.dm
+++ b/code/modules/mob/living/silicon/robot/robot_modules.dm
@@ -113,6 +113,10 @@
S.cost = 1
S.source = get_or_create_estorage(/datum/robot_energy_storage/beacon)
+ else if(istype(S, /obj/item/stack/pipe_cleaner_coil))
+ S.cost = 1
+ S.source = get_or_create_estorage(/datum/robot_energy_storage/pipe_cleaner)
+
if(S && S.source)
S.materials = list()
S.is_cyborg = 1
@@ -480,7 +484,8 @@
/obj/item/lighter,
/obj/item/storage/bag/tray,
/obj/item/reagent_containers/borghypo/borgshaker,
- /obj/item/borg/lollipop)
+ /obj/item/borg/lollipop,
+ /obj/item/stack/pipe_cleaner_coil/cyborg)
emag_modules = list(/obj/item/reagent_containers/borghypo/borgshaker/hacked)
ratvar_modules = list(/obj/item/clockwork/slab/cyborg/service,
/obj/item/borg/sight/xray/truesight_lens)
@@ -687,3 +692,8 @@
max_energy = 30
recharge_rate = 1
name = "Marker Beacon Storage"
+
+/datum/robot_energy_storage/pipe_cleaner
+ max_energy = 50
+ recharge_rate = 2
+ name = "Pipe Cleaner Synthesizer"
\ No newline at end of file
diff --git a/code/modules/mob/living/simple_animal/animal_defense.dm b/code/modules/mob/living/simple_animal/animal_defense.dm
index 80f5de8d01d..ef92aabb720 100644
--- a/code/modules/mob/living/simple_animal/animal_defense.dm
+++ b/code/modules/mob/living/simple_animal/animal_defense.dm
@@ -13,7 +13,7 @@
if("harm", "disarm")
if(HAS_TRAIT(M, TRAIT_PACIFISM))
- to_chat(M, "You don't want to hurt [src]!")
+ to_chat(M, "You don't want to hurt [src]!")
return
M.do_attack_animation(src, ATTACK_EFFECT_PUNCH)
visible_message("[M] [response_harm] [src]!",\
@@ -27,7 +27,7 @@
/mob/living/simple_animal/attack_hulk(mob/living/carbon/human/user, does_attack_animation = 0)
if(user.a_intent == INTENT_HARM)
if(HAS_TRAIT(user, TRAIT_PACIFISM))
- to_chat(user, "You don't want to hurt [src]!")
+ to_chat(user, "You don't want to hurt [src]!")
return FALSE
..(user, 1)
playsound(loc, "punch", 25, 1, -1)
diff --git a/code/modules/mob/living/simple_animal/bot/bot.dm b/code/modules/mob/living/simple_animal/bot/bot.dm
index 607926f1668..85dab7a91a0 100644
--- a/code/modules/mob/living/simple_animal/bot/bot.dm
+++ b/code/modules/mob/living/simple_animal/bot/bot.dm
@@ -672,11 +672,11 @@ Pass a positive integer as an argument to override a bot's default speed.
destination = nearest_beacon
//PDA control. Some bots, especially MULEs, may have more parameters.
-/mob/living/simple_animal/bot/proc/bot_control(command, mob/user, turf/user_turf, list/user_access = list())
+/mob/living/simple_animal/bot/proc/bot_control(command, mob/user, list/user_access = list())
if(!on || emagged == 2 || remote_disabled) //Emagged bots do not respect anyone's authority! Bots with their remote controls off cannot get commands.
return TRUE //ACCESS DENIED
if(client)
- bot_control_message(command,user,user_turf,user_access)
+ bot_control_message(command, user)
// process control input
switch(command)
if("patroloff")
@@ -688,7 +688,7 @@ Pass a positive integer as an argument to override a bot's default speed.
if("summon")
bot_reset()
- summon_target = user_turf
+ summon_target = get_turf(user)
if(user_access.len != 0)
access_card.access = user_access + prev_access //Adds the user's access, if any.
mode = BOT_SUMMON
@@ -700,15 +700,14 @@ Pass a positive integer as an argument to override a bot's default speed.
return
//
-/mob/living/simple_animal/bot/proc/bot_control_message(command,user,user_turf,user_access)
+/mob/living/simple_animal/bot/proc/bot_control_message(command, user)
switch(command)
if("patroloff")
to_chat(src, "STOP PATROL")
if("patrolon")
to_chat(src, "START PATROL")
if("summon")
- var/area/a = get_area(user_turf)
- to_chat(src, "PRIORITY ALERT:[user] in [a.name]!")
+ to_chat(src, "PRIORITY ALERT:[user] in [get_area_name(user)]!")
if("stop")
to_chat(src, "STOP!")
diff --git a/code/modules/mob/living/simple_animal/friendly/dog.dm b/code/modules/mob/living/simple_animal/friendly/dog.dm
index 3654eb91df4..cf5cee7be36 100644
--- a/code/modules/mob/living/simple_animal/friendly/dog.dm
+++ b/code/modules/mob/living/simple_animal/friendly/dog.dm
@@ -284,7 +284,7 @@
if(valid)
if(health <= 0)
- to_chat(user, "There is merely a dull, lifeless look in [real_name]'s eyes as you put the [item_to_add] on [p_them()].")
+ to_chat(user, "There is merely a dull, lifeless look in [real_name]'s eyes as you put the [item_to_add] on [p_them()].")
else if(user)
user.visible_message("[user] puts [item_to_add] on [real_name]'s head. [src] looks at [user] and barks once.",
"You put [item_to_add] on [real_name]'s head. [src] gives you a peculiar look, then wags [p_their()] tail once and barks.",
diff --git a/code/modules/mob/living/simple_animal/friendly/pet.dm b/code/modules/mob/living/simple_animal/friendly/pet.dm
index c24dc6857a5..c65c371fbc4 100644
--- a/code/modules/mob/living/simple_animal/friendly/pet.dm
+++ b/code/modules/mob/living/simple_animal/friendly/pet.dm
@@ -24,7 +24,7 @@
fully_replace_character_name(null, "\proper [P.tagname]")
/mob/living/simple_animal/pet/attackby(obj/item/O, mob/user, params)
- if(istype(O, /obj/item/clothing/neck/petcollar) && !pcollar && collar_type)
+ if(istype(O, /obj/item/clothing/neck/petcollar) && !pcollar)
add_collar(O, user)
return
diff --git a/code/modules/mob/living/simple_animal/hostile/bees.dm b/code/modules/mob/living/simple_animal/hostile/bees.dm
index ec1cb385a15..1194e265c0f 100644
--- a/code/modules/mob/living/simple_animal/hostile/bees.dm
+++ b/code/modules/mob/living/simple_animal/hostile/bees.dm
@@ -264,7 +264,7 @@
if(queen && queen.beegent)
qb.queen.assign_reagent(queen.beegent) //Bees use the global singleton instances of reagents, so we don't need to worry about one bee being deleted and her copies losing their reagents.
user.put_in_active_hand(qb)
- user.visible_message("[user] injects [src] with royal bee jelly, causing it to split into two bees, MORE BEES!","You inject [src] with royal bee jelly, causing it to split into two bees, MORE BEES!")
+ user.visible_message("[user] injects [src] with royal bee jelly, causing it to split into two bees, MORE BEES!","You inject [src] with royal bee jelly, causing it to split into two bees, MORE BEES!")
else
to_chat(user, "You don't have enough royal bee jelly to split a bee in two!")
else
diff --git a/code/modules/mob/living/simple_animal/hostile/carp.dm b/code/modules/mob/living/simple_animal/hostile/carp.dm
index 447cbe339d3..9e25a074c44 100644
--- a/code/modules/mob/living/simple_animal/hostile/carp.dm
+++ b/code/modules/mob/living/simple_animal/hostile/carp.dm
@@ -3,9 +3,10 @@
/mob/living/simple_animal/hostile/carp
name = "space carp"
desc = "A ferocious, fang-bearing creature that resembles a fish."
- icon_state = "carp"
- icon_living = "carp"
- icon_dead = "carp_dead"
+ icon = 'icons/mob/carp.dmi'
+ icon_state = "base"
+ icon_living = "base"
+ icon_dead = "base_dead"
icon_gib = "carp_gib"
mob_biotypes = list(MOB_ORGANIC, MOB_BEAST)
speak_chance = 0
@@ -38,12 +39,90 @@
pressure_resistance = 200
gold_core_spawnable = HOSTILE_SPAWN
+ var/random_color = TRUE //if the carp uses random coloring
+ var/rarechance = 1 //chance for rare color variant
+
+ var/static/list/carp_colors = list(\
+ "lightpurple" = "#c3b9f1", \
+ "lightpink" = "#da77a8", \
+ "green" = "#70ff25", \
+ "grape" = "#df0afb", \
+ "swamp" = "#e5e75a", \
+ "turquoise" = "#04e1ed", \
+ "brown" = "#ca805a", \
+ "teal" = "#20e28e", \
+ "lightblue" = "#4d88cc", \
+ "rusty" = "#dd5f34", \
+ "beige" = "#bbaeaf", \
+ "yellow" = "#f3ca4a", \
+ "blue" = "#09bae1", \
+ "palegreen" = "#7ef099", \
+ )
+ var/static/list/carp_colors_rare = list(\
+ "silver" = "#fdfbf3", \
+ )
+
+/mob/living/simple_animal/hostile/carp/Initialize(mapload)
+ . = ..()
+ carp_randomify(rarechance)
+ update_icons()
+
+/mob/living/simple_animal/hostile/carp/proc/carp_randomify(rarechance)
+ if(random_color)
+ var/our_color
+ if(prob(rarechance))
+ our_color = pick(carp_colors_rare)
+ add_atom_colour(carp_colors_rare[our_color], FIXED_COLOUR_PRIORITY)
+ else
+ our_color = pick(carp_colors)
+ add_atom_colour(carp_colors[our_color], FIXED_COLOUR_PRIORITY)
+ add_carp_overlay()
+
+/mob/living/simple_animal/hostile/carp/proc/add_carp_overlay()
+ if(!random_color)
+ return
+ cut_overlays()
+ var/mutable_appearance/base_overlay = mutable_appearance(icon, "base_mouth")
+ base_overlay.appearance_flags = RESET_COLOR
+ add_overlay(base_overlay)
+
+/mob/living/simple_animal/hostile/carp/proc/add_dead_carp_overlay()
+ if(!random_color)
+ return
+ cut_overlays()
+ var/mutable_appearance/base_dead_overlay = mutable_appearance(icon, "base_dead_mouth")
+ base_dead_overlay.appearance_flags = RESET_COLOR
+ add_overlay(base_dead_overlay)
+
+/mob/living/simple_animal/hostile/carp/death(gibbed)
+ . = ..()
+ cut_overlays()
+ if(!random_color || gibbed)
+ return
+ add_dead_carp_overlay()
+
+/mob/living/simple_animal/hostile/carp/revive(full_heal = 0, admin_revive = 0)
+ . = ..()
+ if(.)
+ regenerate_icons()
+
+/mob/living/simple_animal/hostile/carp/regenerate_icons()
+ cut_overlays()
+ if(!random_color)
+ return
+ if(stat != DEAD)
+ add_carp_overlay()
+ else
+ add_dead_carp_overlay()
+ ..()
+
/mob/living/simple_animal/hostile/carp/holocarp
icon_state = "holocarp"
icon_living = "holocarp"
maxbodytemp = INFINITY
gold_core_spawnable = NO_SPAWN
del_on_death = 1
+ random_color = FALSE
/mob/living/simple_animal/hostile/carp/megacarp
icon = 'icons/mob/broadMobs.dmi'
@@ -57,6 +136,7 @@
health = 20
pixel_x = -16
mob_size = MOB_SIZE_LARGE
+ random_color = FALSE
obj_damage = 80
melee_damage_lower = 20
@@ -90,5 +170,6 @@
gold_core_spawnable = NO_SPAWN
faction = list(ROLE_SYNDICATE)
AIStatus = AI_OFF
+ rarechance = 10
#undef REGENERATION_DELAY
diff --git a/code/modules/mob/living/simple_animal/hostile/eyeballs.dm b/code/modules/mob/living/simple_animal/hostile/eyeballs.dm
index 44f7f9c9f87..8f64d88f060 100644
--- a/code/modules/mob/living/simple_animal/hostile/eyeballs.dm
+++ b/code/modules/mob/living/simple_animal/hostile/eyeballs.dm
@@ -1,5 +1,3 @@
-
-
/mob/living/simple_animal/hostile/carp/eyeball
name = "eyeball"
desc = "An odd looking creature, it won't stop staring..."
@@ -26,4 +24,5 @@
movement_type = FLYING
faction = list("spooky")
- del_on_death = 1
\ No newline at end of file
+ del_on_death = 1
+ random_color = FALSE
diff --git a/code/modules/mob/living/simple_animal/hostile/goose.dm b/code/modules/mob/living/simple_animal/hostile/goose.dm
index a0a2073a790..19e9c7c8b30 100644
--- a/code/modules/mob/living/simple_animal/hostile/goose.dm
+++ b/code/modules/mob/living/simple_animal/hostile/goose.dm
@@ -1,7 +1,9 @@
+#define GOOSE_SATIATED 50
+
/mob/living/simple_animal/hostile/retaliate/goose
name = "goose"
desc = "It's loose"
- icon_state = "goose"
+ icon_state = "goose" // sprites by cogwerks from goonstation, used with permission
icon_living = "goose"
icon_dead = "goose_dead"
mob_biotypes = list(MOB_ORGANIC, MOB_BEAST)
@@ -10,7 +12,7 @@
butcher_results = list(/obj/item/reagent_containers/food/snacks/meat = 2)
response_help = "pets"
response_disarm = "gently pushes aside"
- response_harm = "hits"
+ response_harm = "kicks"
emote_taunt = list("hisses")
taunt_chance = 30
speed = 0
@@ -25,33 +27,143 @@
faction = list("neutral")
attack_same = TRUE
gold_core_spawnable = HOSTILE_SPAWN
- var/icon_resting = "goose_sit"
-
-
-/mob/living/simple_animal/hostile/retaliate/goose/toggle_ai(togglestatus)
- . = ..()
- if(!key)
- if(AIStatus != AI_ON)
- set_resting(TRUE)
- else
- set_resting(FALSE)
-
-/mob/living/simple_animal/hostile/retaliate/goose/update_resting()
- . = ..()
- if(resting)
- wander = FALSE
- else
- wander = TRUE
- update_icon()
+ var/random_retaliate = TRUE
+ var/icon_vomit_start = "vomit_start"
+ var/icon_vomit = "vomit"
+ var/icon_vomit_end = "vomit_end"
/mob/living/simple_animal/hostile/retaliate/goose/handle_automated_movement()
. = ..()
- if(prob(5))
+ if(prob(5) && random_retaliate == TRUE)
Retaliate()
-/mob/living/simple_animal/hostile/retaliate/goose/proc/update_icon()
- if(stat != DEAD)
- icon_state = resting ? icon_resting : icon_living
- else
- icon_state = icon_dead
+/mob/living/simple_animal/hostile/retaliate/goose/vomit
+ name = "Birdboat"
+ real_name = "Birdboat"
+ desc = "It's a sick-looking goose, probably ate too much maintenance trash. Best not to move it around too much."
+ gender = MALE
+ response_help = "pets"
+ response_disarm = "gently pushes aside"
+ response_harm = "kicks"
+ gold_core_spawnable = NO_SPAWN
+ random_retaliate = FALSE
+ var/vomiting = FALSE
+ var/vomitCoefficient = 1
+ var/vomitTimeBonus = 0
+ var/datum/action/cooldown/vomit/goosevomit
+/mob/living/simple_animal/hostile/retaliate/goose/vomit/Initialize()
+ . = ..()
+ goosevomit = new
+ goosevomit.Grant(src)
+
+/mob/living/simple_animal/hostile/retaliate/goose/vomit/Destroy()
+ QDEL_NULL(goosevomit)
+ return ..()
+
+/mob/living/simple_animal/hostile/retaliate/goose/vomit/examine(user)
+ . = ..()
+ . += "Somehow, it still looks hungry."
+
+/mob/living/simple_animal/hostile/retaliate/goose/vomit/attacked_by(obj/item/O, mob/user)
+ . = ..()
+ feed(O)
+
+/mob/living/simple_animal/hostile/retaliate/goose/vomit/proc/feed(obj/item/O)
+ var/obj/item/reagent_containers/food/tasty = O
+ if(!istype(O))
+ return
+ if (contents.len > GOOSE_SATIATED)
+ visible_message("[src] looks too full to eat \the [tasty]!")
+ return
+ if (tasty.foodtype & GROSS)
+ visible_message("[src] hungrily gobbles up \the [tasty]!")
+ tasty.forceMove(src)
+ playsound(src,'sound/items/eatfood.ogg', 70, 1)
+ vomitCoefficient += 3
+ vomitTimeBonus += 2
+ else
+ visible_message("[src] refuses to eat \the [tasty].")
+
+/mob/living/simple_animal/hostile/retaliate/goose/vomit/proc/vomit()
+ var/turf/T = get_turf(src)
+ var/obj/item/reagent_containers/food/consumed = locate() in contents //Barf out a single food item from our guts
+ if (prob(50) && consumed)
+ barf_food(consumed)
+ else
+ playsound(T, 'sound/effects/splat.ogg', 50, 1)
+ T.add_vomit_floor(src)
+
+/mob/living/simple_animal/hostile/retaliate/goose/vomit/proc/barf_food(var/atom/A, var/hard = FALSE)
+ if(!istype(A, /obj/item/reagent_containers/food))
+ return
+ var/turf/currentTurf = get_turf(src)
+ var/obj/item/reagent_containers/food/consumed = A
+ consumed.forceMove(currentTurf)
+ var/destination = get_edge_target_turf(currentTurf, pick(GLOB.alldirs)) //Pick a random direction to toss them in
+ var/throwRange = hard ? rand(2,8) : 1
+ consumed.safe_throw_at(destination, throwRange, 2) //Thow the food at a random tile 1 spot away
+ sleep(2)
+ if (QDELETED(src) || QDELETED(consumed))
+ return
+ currentTurf = get_turf(consumed)
+ currentTurf.add_vomit_floor(src)
+ playsound(currentTurf, 'sound/effects/splat.ogg', 50, 1)
+
+/mob/living/simple_animal/hostile/retaliate/goose/vomit/proc/vomit_prestart(duration)
+ flick("vomit_start",src)
+ addtimer(CALLBACK(src, .proc/vomit_start, duration), 13) //13 is the length of the vomit_start animation in gooseloose.dmi
+
+/mob/living/simple_animal/hostile/retaliate/goose/vomit/proc/vomit_start(duration)
+ vomiting = TRUE
+ icon_state = "vomit"
+ vomit()
+ addtimer(CALLBACK(src, .proc/vomit_preend), duration)
+
+/mob/living/simple_animal/hostile/retaliate/goose/vomit/proc/vomit_preend()
+ for (var/obj/item/consumed in contents) //Get rid of any food left in the poor thing
+ barf_food(consumed, TRUE)
+ sleep(1)
+ if (QDELETED(src))
+ return
+ vomit_end()
+
+/mob/living/simple_animal/hostile/retaliate/goose/vomit/proc/vomit_end()
+ flick("vomit_end",src)
+ vomiting = FALSE
+ icon_state = initial(icon_state)
+
+/mob/living/simple_animal/hostile/retaliate/goose/vomit/Moved(oldLoc, dir)
+ . = ..()
+ if(vomiting)
+ vomit() // its supposed to keep vomiting if you move
+ return
+ var/turf/currentTurf = get_turf(src)
+ while (currentTurf == get_turf(src))
+ var/obj/item/reagent_containers/food/tasty = locate() in currentTurf
+ if (tasty)
+ feed(tasty)
+ stoplag(2)
+ if(prob(vomitCoefficient * 0.2))
+ vomit_prestart(vomitTimeBonus + 25)
+ vomitCoefficient = 1
+ vomitTimeBonus = 0
+
+/datum/action/cooldown/vomit
+ name = "Vomit"
+ check_flags = AB_CHECK_CONSCIOUS
+ button_icon_state = "vomit"
+ icon_icon = 'icons/mob/animal.dmi'
+ cooldown_time = 250
+
+/datum/action/cooldown/vomit/Trigger()
+ if(!..())
+ return FALSE
+ if(!istype(owner, /mob/living/simple_animal/hostile/retaliate/goose/vomit))
+ return FALSE
+ var/mob/living/simple_animal/hostile/retaliate/goose/vomit/vomit = owner
+ if(!vomit.vomiting)
+ vomit.vomit_prestart(vomit.vomitTimeBonus + 25)
+ vomit.vomitCoefficient = 1
+ vomit.vomitTimeBonus = 0
+ return TRUE
diff --git a/code/modules/mob/living/simple_animal/hostile/hivebot.dm b/code/modules/mob/living/simple_animal/hostile/hivebot.dm
index 93284fe6664..ee6c69d8ec1 100644
--- a/code/modules/mob/living/simple_animal/hostile/hivebot.dm
+++ b/code/modules/mob/living/simple_animal/hostile/hivebot.dm
@@ -23,11 +23,18 @@
faction = list("hivebot")
check_friendly_fire = 1
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)
+ possible_a_intents = list(INTENT_HELP, INTENT_GRAB, INTENT_DISARM, INTENT_HARM)
minbodytemp = 0
- speak_emote = list("states")
+ verb_say = "states"
+ verb_ask = "queries"
+ verb_exclaim = "declares"
+ verb_yell = "alarms"
+ bubble_icon = "machine"
+ speech_span = SPAN_ROBOT
gold_core_spawnable = HOSTILE_SPAWN
del_on_death = 1
loot = list(/obj/effect/decal/cleanable/robot_debris)
+ var/alert_light
do_footstep = TRUE
@@ -35,6 +42,28 @@
. = ..()
deathmessage = "[src] blows apart!"
+/mob/living/simple_animal/hostile/hivebot/Aggro()
+ . = ..()
+ a_intent_change(INTENT_HARM)
+ if(prob(5))
+ say(pick("INTRUDER DETECTED!", "CODE 7-34.", "101010!!"), forced = type)
+
+/mob/living/simple_animal/hostile/hivebot/LoseAggro()
+ . = ..()
+ a_intent_change(INTENT_HELP)
+
+/mob/living/simple_animal/hostile/hivebot/a_intent_change(input as text)
+ . = ..()
+ update_icons()
+
+/mob/living/simple_animal/hostile/hivebot/update_icons()
+ QDEL_NULL(alert_light)
+ if(a_intent != INTENT_HELP)
+ icon_state = "[initial(icon_state)]_attack"
+ alert_light = mob_light(COLOR_RED_LIGHT, 6, 0.4)
+ else
+ icon_state = initial(icon_state)
+
/mob/living/simple_animal/hostile/hivebot/range
name = "hivebot"
desc = "A smallish robot, this one is armed!"
diff --git a/code/modules/mob/living/simple_animal/hostile/jungle/leaper.dm b/code/modules/mob/living/simple_animal/hostile/jungle/leaper.dm
index b2cf20e6fb8..7cf9d0d4744 100644
--- a/code/modules/mob/living/simple_animal/hostile/jungle/leaper.dm
+++ b/code/modules/mob/living/simple_animal/hostile/jungle/leaper.dm
@@ -42,7 +42,7 @@
..()
if(iscarbon(target))
var/mob/living/carbon/C = target
- C.reagents.add_reagent("leaper_venom", 5)
+ C.reagents.add_reagent(/datum/reagent/toxin/leaper_venom, 5)
return
if(isanimal(target))
var/mob/living/simple_animal/L = target
@@ -96,7 +96,7 @@
L.Paralyze(50)
if(iscarbon(L))
var/mob/living/carbon/C = L
- C.reagents.add_reagent("leaper_venom", 5)
+ C.reagents.add_reagent(/datum/reagent/toxin/leaper_venom, 5)
if(isanimal(L))
var/mob/living/simple_animal/A = L
A.adjustHealth(25)
diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/clown.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/clown.dm
index da3f86ed273..6693c3a7777 100644
--- a/code/modules/mob/living/simple_animal/hostile/retaliate/clown.dm
+++ b/code/modules/mob/living/simple_animal/hostile/retaliate/clown.dm
@@ -163,7 +163,6 @@
response_help = "tries desperately to appease"
response_disarm = "foolishly pushes"
response_harm = "angers"
- access_card = ACCESS_THEATRE
speak = list("HONK", "Honk!", "HAUAUANK!!!", "GUUURRRRAAAHHH!!!")
emote_see = list("honks", "sweats", "grunts")
speak_chance = 5
diff --git a/code/modules/mob/living/simple_animal/hostile/wumborian_fugu.dm b/code/modules/mob/living/simple_animal/hostile/wumborian_fugu.dm
index ec7451dc2ec..24b22d737f0 100644
--- a/code/modules/mob/living/simple_animal/hostile/wumborian_fugu.dm
+++ b/code/modules/mob/living/simple_animal/hostile/wumborian_fugu.dm
@@ -71,13 +71,13 @@
/datum/action/innate/fugu/expand/Activate()
var/mob/living/simple_animal/hostile/asteroid/fugu/F = owner
if(F.wumbo)
- to_chat(F, "YOU'RE ALREADY WUMBO!")
+ to_chat(F, "YOU'RE ALREADY WUMBO!")
return
if(F.inflate_cooldown)
- to_chat(F, "You need time to gather your strength.")
+ to_chat(F, "You need time to gather your strength!")
return
if(F.buffed)
- to_chat(F, "Something is interfering with your growth.")
+ to_chat(F, "Something is interfering with your growth!")
return
F.wumbo = 1
F.icon_state = "Fugu1"
diff --git a/code/modules/mob/living/simple_animal/parrot.dm b/code/modules/mob/living/simple_animal/parrot.dm
index 3b65952be52..bfefd7d1a0d 100644
--- a/code/modules/mob/living/simple_animal/parrot.dm
+++ b/code/modules/mob/living/simple_animal/parrot.dm
@@ -748,7 +748,7 @@
if(!held_item)
if(src == usr) //So that other mobs wont make this message appear when they're bludgeoning you.
- to_chat(src, "You have nothing to drop!")
+ to_chat(src, "You have nothing to drop!")
return 0
@@ -767,11 +767,11 @@
var/obj/item/grenade/G = held_item
G.forceMove(drop_location())
G.prime()
- to_chat(src, "You let go of [held_item]!")
+ to_chat(src, "You let go of [held_item]!")
held_item = null
return 1
- to_chat(src, "You drop [held_item].")
+ to_chat(src, "You drop [held_item].")
held_item.forceMove(drop_location())
held_item = null
diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm
index 37366069a46..25886bf519b 100644
--- a/code/modules/mob/living/simple_animal/simple_animal.dm
+++ b/code/modules/mob/living/simple_animal/simple_animal.dm
@@ -121,6 +121,11 @@
return ..()
+/mob/living/simple_animal/examine(mob/user)
+ . = ..()
+ if(stat == DEAD)
+ . += "Upon closer examination, [p_they()] appear[p_s()] to be dead."
+
/mob/living/simple_animal/initialize_footstep()
if(do_footstep)
..()
diff --git a/code/modules/mob/living/simple_animal/slime/life.dm b/code/modules/mob/living/simple_animal/slime/life.dm
index 0b4da0da557..35f82beeead 100644
--- a/code/modules/mob/living/simple_animal/slime/life.dm
+++ b/code/modules/mob/living/simple_animal/slime/life.dm
@@ -72,7 +72,7 @@
if(Target.Adjacent(src))
Target.attack_slime(src)
- return
+ break
if((Target.mobility_flags & MOBILITY_STAND) && prob(80))
if(Target.client && Target.health >= 20)
diff --git a/code/modules/mob/living/ventcrawling.dm b/code/modules/mob/living/ventcrawling.dm
index bc4d133a70e..09cc3705872 100644
--- a/code/modules/mob/living/ventcrawling.dm
+++ b/code/modules/mob/living/ventcrawling.dm
@@ -9,19 +9,19 @@ GLOBAL_LIST_INIT(ventcrawl_machinery, typecacheof(list(
if(!ventcrawler || !Adjacent(A))
return
if(stat)
- to_chat(src, "You must be conscious to do this!")
+ to_chat(src, "You must be conscious to do this!")
return
if(IsStun() || IsParalyzed())
- to_chat(src, "You can't vent crawl while you're stunned!")
+ to_chat(src, "You can't vent crawl while you're stunned!")
return
if(restrained())
- to_chat(src, "You can't vent crawl while you're restrained!")
+ to_chat(src, "You can't vent crawl while you're restrained!")
return
if(has_buckled_mobs())
- to_chat(src, "You can't vent crawl with other creatures on you!")
+ to_chat(src, "You can't vent crawl with other creatures on you!")
return
if(buckled)
- to_chat(src, "You can't vent crawl while buckled!")
+ to_chat(src, "You can't vent crawl while buckled!")
return
var/obj/machinery/atmospherics/components/unary/vent_found
@@ -123,4 +123,3 @@ GLOBAL_LIST_INIT(ventcrawl_machinery, typecacheof(list(
. = new_loc
remove_ventcrawl()
add_ventcrawl(.)
-
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index 56eb4e0837e..820e6c072e0 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -301,7 +301,7 @@
return
if(is_blind(src))
- to_chat(src, "Something is there but you can't see it.")
+ to_chat(src, "Something is there but you can't see it!")
return
face_atom(A)
@@ -752,26 +752,6 @@
/mob/proc/can_interact_with(atom/A)
return IsAdminGhost(src) || Adjacent(A)
-//Can the mob see reagents inside of containers?
-/mob/proc/can_see_reagents()
- if(stat == DEAD) //Ghosts and such can always see reagents
- return 1
- if(has_unlimited_silicon_privilege) //Silicons can automatically view reagents
- return 1
- if(ishuman(src))
- var/mob/living/carbon/human/H = src
- if(H.head && istype(H.head, /obj/item/clothing))
- var/obj/item/clothing/CL = H.head
- if(CL.scan_reagents)
- return 1
- if(H.wear_mask && H.wear_mask.scan_reagents)
- return 1
- if(H.glasses && istype(H.glasses, /obj/item/clothing))
- var/obj/item/clothing/CL = H.glasses
- if(CL.scan_reagents)
- return 1
- return 0
-
//Can the mob use Topic to interact with machines
/mob/proc/canUseTopic(atom/movable/M, be_close=FALSE, no_dextery=FALSE, no_tk=FALSE)
return
diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm
index 0ac3668c063..1903f49b644 100644
--- a/code/modules/mob/mob_helpers.dm
+++ b/code/modules/mob/mob_helpers.dm
@@ -504,3 +504,7 @@ It's fairly easy to fix if dealing with single letters but not so much with comp
. += mind.special_role //In case there's something special leftover, try to avoid
for(var/datum/antagonist/A in mind.antag_datums)
. += "[A.type]"
+
+//Can the mob see reagents inside of containers?
+/mob/proc/can_see_reagents()
+ return stat == DEAD || has_unlimited_silicon_privilege //Dead guys and silicons can always see reagents
diff --git a/code/modules/mob/status_procs.dm b/code/modules/mob/status_procs.dm
index 86fa6cf8dc5..7a4f72b9b62 100644
--- a/code/modules/mob/status_procs.dm
+++ b/code/modules/mob/status_procs.dm
@@ -18,17 +18,6 @@
/mob/proc/set_dizziness(amount)
dizziness = max(amount, 0)
-/////////////////////////////////// EYE DAMAGE ////////////////////////////////////
-
-/mob/proc/damage_eyes(amount)
- return
-
-/mob/proc/adjust_eye_damage(amount)
- return
-
-/mob/proc/set_eye_damage(amount)
- return
-
/////////////////////////////////// EYE_BLIND ////////////////////////////////////
/mob/proc/blind_eyes(amount)
diff --git a/code/modules/modular_computers/file_system/programs/airestorer.dm b/code/modules/modular_computers/file_system/programs/airestorer.dm
index 1aa292f2479..0575d7b635a 100644
--- a/code/modules/modular_computers/file_system/programs/airestorer.dm
+++ b/code/modules/modular_computers/file_system/programs/airestorer.dm
@@ -44,6 +44,7 @@
if("PRG_beginReconstruction")
if(A && A.health < 100)
restoring = TRUE
+ A.notify_ghost_cloning("Your core files are being restored!", source = computer)
return TRUE
if("PRG_eject")
if(computer.all_components[MC_AI])
diff --git a/code/modules/modular_computers/file_system/programs/antagonist/contract_uplink.dm b/code/modules/modular_computers/file_system/programs/antagonist/contract_uplink.dm
index 830b1d2e4f9..34d71b9e6ac 100644
--- a/code/modules/modular_computers/file_system/programs/antagonist/contract_uplink.dm
+++ b/code/modules/modular_computers/file_system/programs/antagonist/contract_uplink.dm
@@ -42,6 +42,7 @@
// We don't give them more contracts if they somehow assign themselves to a new uplink.
if (!traitor_data.assigned_contracts.len)
traitor_data.create_contracts()
+ user.playsound_local(user, 'sound/effects/contractstartup.ogg', 100, 0)
hard_drive.traitor_data = traitor_data
else
error = "Incorrect login details."
diff --git a/code/modules/ninja/suit/n_suit_verbs/ninja_cost_check.dm b/code/modules/ninja/suit/n_suit_verbs/ninja_cost_check.dm
index 12fea51815f..da0c28346a7 100644
--- a/code/modules/ninja/suit/n_suit_verbs/ninja_cost_check.dm
+++ b/code/modules/ninja/suit/n_suit_verbs/ninja_cost_check.dm
@@ -5,7 +5,7 @@
var/mob/living/carbon/human/H = affecting
var/actualCost = cost*10
if(cost && cell.charge < actualCost)
- to_chat(H, "Not enough energy.")
+ to_chat(H, "Not enough energy!")
return 1
else
//This shit used to be handled individually on every proc.. why even bother with a universal check proc then?
@@ -16,10 +16,10 @@
cancel_stealth()//Get rid of it.
if(N_SMOKE_BOMB)
if(!s_bombs)
- to_chat(H, "There are no more smoke bombs remaining.")
+ to_chat(H, "There are no more smoke bombs remaining!")
return 1
if(N_ADRENALINE)
if(!a_boost)
- to_chat(H, "You do not have any more adrenaline boosters.")
+ to_chat(H, "You do not have any more adrenaline boosters!")
return 1
return (s_coold)//Returns the value of the variable which counts down to zero.
diff --git a/code/modules/ninja/suit/suit.dm b/code/modules/ninja/suit/suit.dm
index fe696984a00..6c46926aeba 100644
--- a/code/modules/ninja/suit/suit.dm
+++ b/code/modules/ninja/suit/suit.dm
@@ -151,10 +151,10 @@ Contents:
. = .()
if(s_initialized)
if(user == affecting)
- . += {"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."}
+ . += "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 4b159557bcc..1e624561ee8 100644
--- a/code/modules/ninja/suit/suit_initialisation.dm
+++ b/code/modules/ninja/suit/suit_initialisation.dm
@@ -1,6 +1,6 @@
/obj/item/clothing/suit/space/space_ninja/proc/toggle_on_off()
if(s_busy)
- to_chat(loc, "ERROR: You cannot use this function at this time.")
+ to_chat(loc, "ERROR: You cannot use this function at this time.")
return FALSE
if(s_initialized)
deinitialize()
diff --git a/code/modules/paperwork/contract.dm b/code/modules/paperwork/contract.dm
index 2f05694f22f..0d6e9459b1d 100644
--- a/code/modules/paperwork/contract.dm
+++ b/code/modules/paperwork/contract.dm
@@ -188,29 +188,29 @@
/obj/item/paper/contract/infernal/proc/attempt_signature(mob/living/carbon/human/user, blood = 0)
if(!user.IsAdvancedToolUser() || !user.is_literate())
- to_chat(user, "You don't know how to read or write.")
+ to_chat(user, "You don't know how to read or write!")
return 0
if(user.mind != target)
- to_chat(user, "Your signature simply slides off the sheet, it seems this contract is not meant for you to sign.")
+ to_chat(user, "Your signature simply slides off the sheet, it seems this contract is not meant for you to sign!")
return 0
if(user.mind.soulOwner == owner)
- to_chat(user, "This devil already owns your soul, you may not sell it to [owner.p_them()] again.")
+ to_chat(user, "This devil already owns your soul, you may not sell it to [owner.p_them()] again!")
return 0
if(signed)
- to_chat(user, "This contract has already been signed. It may not be signed again.")
+ to_chat(user, "This contract has already been signed! It may not be signed again.")
return 0
if(!user.mind.hasSoul)
- to_chat(user, "You do not possess a soul.")
+ to_chat(user, "You do not possess a soul.")
return 0
if(HAS_TRAIT(user, TRAIT_DUMB))
to_chat(user, "You quickly scrawl 'your name' on the contract.")
signIncorrectly()
return 0
if (contractType == CONTRACT_REVIVE)
- to_chat(user, "You are already alive, this contract would do nothing.")
+ to_chat(user, "You are already alive, this contract would do nothing.")
return 0
else
- to_chat(user, "You quickly scrawl your name on the contract")
+ to_chat(user, "You quickly scrawl your name on the contract.")
if(fulfillContract(target.current, blood)<=0)
to_chat(user, "But it seemed to have no effect, perhaps even Hell itself cannot grant this boon?")
return 1
@@ -220,7 +220,7 @@
/obj/item/paper/contract/infernal/revive/attack(mob/M, mob/living/user)
if (target == M.mind && M.stat == DEAD && M.mind.soulOwner == M.mind)
if (cooldown)
- to_chat(user, "Give [M] a chance to think through the contract, don't rush [M.p_them()].")
+ to_chat(user, "Give [M] a chance to think through the contract, don't rush [M.p_them()]!")
return 0
cooldown = TRUE
var/mob/living/carbon/human/H = M
diff --git a/code/modules/paperwork/paper.dm b/code/modules/paperwork/paper.dm
index be01b77ff3e..66048f542a7 100644
--- a/code/modules/paperwork/paper.dm
+++ b/code/modules/paperwork/paper.dm
@@ -291,7 +291,7 @@
user << browse("[name][info_links]
[stamps]", "window=[name]")
return
else
- to_chat(user, "You don't know how to read or write.")
+ to_chat(user, "You don't know how to read or write!")
return
else if(istype(P, /obj/item/stamp))
diff --git a/code/modules/paperwork/paper_cutter.dm b/code/modules/paperwork/paper_cutter.dm
index c53e7429dd6..8c44b298242 100644
--- a/code/modules/paperwork/paper_cutter.dm
+++ b/code/modules/paperwork/paper_cutter.dm
@@ -72,7 +72,7 @@
return
add_fingerprint(user)
if(!storedcutter)
- to_chat(user, "The cutting blade is gone! You can't use [src] now.")
+ to_chat(user, "The cutting blade is gone! You can't use [src] now.")
return
if(!cuttersecured)
diff --git a/code/modules/paperwork/paperplane.dm b/code/modules/paperwork/paperplane.dm
index 69f611980cc..3ddcfd98304 100644
--- a/code/modules/paperwork/paperplane.dm
+++ b/code/modules/paperwork/paperplane.dm
@@ -50,10 +50,12 @@
return ..()
/obj/item/paperplane/suicide_act(mob/living/user)
+ var/obj/item/organ/eyes/eyes = user.getorganslot(ORGAN_SLOT_EYES)
user.Stun(200)
user.visible_message("[user] jams [src] in [user.p_their()] nose. It looks like [user.p_theyre()] trying to commit suicide!")
user.adjust_blurriness(6)
- user.adjust_eye_damage(rand(6,8))
+ if(eyes)
+ eyes.applyOrganDamage(rand(6,8))
sleep(10)
return (BRUTELOSS)
@@ -75,7 +77,7 @@
/obj/item/paperplane/attackby(obj/item/P, mob/living/carbon/human/user, params)
..()
if(istype(P, /obj/item/pen) || istype(P, /obj/item/toy/crayon))
- to_chat(user, "You should unfold [src] before changing it.")
+ to_chat(user, "You should unfold [src] before changing it!")
return
else if(istype(P, /obj/item/stamp)) //we don't randomize stamps on a paperplane
@@ -114,12 +116,13 @@
if(..() || !ishuman(hit_atom))//if the plane is caught or it hits a nonhuman
return
var/mob/living/carbon/human/H = hit_atom
+ var/obj/item/organ/eyes/eyes = H.getorganslot(ORGAN_SLOT_EYES)
if(prob(hit_probability))
if(H.is_eyes_covered())
return
visible_message("\The [src] hits [H] in the eye!")
H.adjust_blurriness(6)
- H.adjust_eye_damage(rand(6,8))
+ eyes.applyOrganDamage(rand(6,8))
H.Paralyze(40)
H.emote("scream")
diff --git a/code/modules/paperwork/photocopier.dm b/code/modules/paperwork/photocopier.dm
index c0e20323cf8..d4cdc8c349e 100644
--- a/code/modules/paperwork/photocopier.dm
+++ b/code/modules/paperwork/photocopier.dm
@@ -187,7 +187,7 @@
/obj/machinery/photocopier/proc/do_insertion(obj/item/O, mob/user)
O.forceMove(src)
- to_chat(user, "You insert [O] into [src].")
+ to_chat(user, "You insert [O] into [src].")
flick("photocopier1", src)
updateUsrDialog()
diff --git a/code/modules/power/cable.dm b/code/modules/power/cable.dm
index cb304a0e9aa..58a1f22a065 100644
--- a/code/modules/power/cable.dm
+++ b/code/modules/power/cable.dm
@@ -15,7 +15,7 @@ GLOBAL_LIST_INIT(wire_node_generating_types, typecacheof(list(/obj/structure/gri
name = "power cable"
desc = "A flexible, superconducting insulated cable for heavy-duty power transfer."
icon = 'icons/obj/power_cond/cable.dmi'
- icon_state = "1-2-4-8"
+ icon_state = "1-2-4-8-node"
level = 1 //is underfloor
layer = WIRE_LAYER //Above hidden pipes, GAS_PIPE_HIDDEN_LAYER
anchored = TRUE
@@ -37,24 +37,35 @@ GLOBAL_LIST_INIT(wire_node_generating_types, typecacheof(list(/obj/structure/gri
var/under_thing = NONE
if(clear_before_updating)
linked_dirs = 0
+ var/obj/machinery/power/search_parent
for(var/obj/machinery/power/P in loc)
if(istype(P, /obj/machinery/power/terminal))
under_thing = UNDER_TERMINAL
+ search_parent = P
break
if(istype(P, /obj/machinery/power/smes))
under_thing = UNDER_SMES
+ search_parent = P
break
for(var/check_dir in GLOB.cardinals)
var/TB = get_step(src, check_dir)
+ //don't link from smes to its terminal
if(under_thing)
- var/search_target
switch(under_thing)
if(UNDER_SMES)
- search_target = /obj/machinery/power/terminal
+ var/obj/machinery/power/terminal/term = locate(/obj/machinery/power/terminal) in TB
+ //Why null or equal to the search parent?
+ //during map init it's possible for a placed smes terminal to not have initialized to the smes yet
+ //but the cable underneath it is ready to link.
+ //I don't believe null is even a valid state for a smes terminal while the game is actually running
+ //So in the rare case that this happens, we also shouldn't connect
+ //This might break.
+ if(term && (!term.master || term.master == search_parent))
+ continue
if(UNDER_TERMINAL)
- search_target = /obj/machinery/power/smes
- if(locate(search_target) in TB)
- continue
+ var/obj/machinery/power/smes/S = locate(/obj/machinery/power/smes) in TB
+ if(S && (!S.terminal || S.terminal == search_parent))
+ continue
var/inverse = turn(check_dir, 180)
for(var/obj/structure/cable/C in TB)
linked_dirs |= check_dir
@@ -272,19 +283,23 @@ GLOBAL_LIST_INIT(wire_node_generating_types, typecacheof(list(/obj/structure/gri
// Powernets handling helpers
//////////////////////////////////////////////
-//if powernetless_only = 1, will only get connections without powernet
-//ignore_dir makes sure that connections coming from that direction are ignored
-/obj/structure/cable/proc/get_connections(powernetless_only = FALSE, ignore_dir = null)
- . = list() // this will be a list of all connected power objects
+/obj/structure/cable/proc/get_cable_connections(powernetless_only, ignore_dir = null)
+ . = list()
var/turf/T
-
for(var/check_dir in GLOB.cardinals)
- if(linked_dirs & check_dir && check_dir != ignore_dir)
+ if((linked_dirs & check_dir) && check_dir != ignore_dir)
T = get_step(src, check_dir)
if(T)
- . |= power_list(T, src, powernetless_only)
+ var/obj/structure/cable/C = locate(/obj/structure/cable) in T
+ if(C)
+ .[C] = check_dir
- . |= power_list(loc, src, powernetless_only) //get on turf matching cables
+/obj/structure/cable/proc/get_machine_connections(powernetless_only)
+ . = list()
+ for(var/obj/machinery/power/P in get_turf(src))
+ if(!powernetless_only || !P.powernet)
+ if(P.anchored)
+ . += P
/obj/structure/cable/proc/auto_propogate_cut_cable(obj/O)
if(O && !QDELETED(O))
@@ -305,38 +320,26 @@ GLOBAL_LIST_INIT(wire_node_generating_types, typecacheof(list(/obj/structure/gri
return
var/turf/T1 = loc
- var/list/P_list
if(!T1)
return
+
+ //clear the powernet of any machines on tile first
+ for(var/obj/machinery/power/P in T1)
+ P.disconnect_from_network()
+
+ var/list/P_list = list()
for(var/dir_check in GLOB.cardinals)
if(linked_dirs & dir_check)
T1 = get_step(T1, dir_check)
- P_list += power_list(T1, src, FALSE, TRUE) // what adjacently joins on to cut cable...
+ P_list += locate(/obj/structure/cable) in T1
- P_list += power_list(loc, src, FALSE, TRUE)//... and on turf
-
-
- if(P_list.len == 0)//if nothing in both list, then the cable was a lone cable, just delete it and its powernet
- powernet.remove_cable(src)
-
- for(var/obj/machinery/power/P in T1)//check if it was powering a machine
- if(!P.connect_to_network()) //can't find a node cable on a the turf to connect to
- P.disconnect_from_network() //remove from current network (and delete powernet)
- return
-
// remove the cut cable from its turf and powernet, so that it doesn't get count in propagate_network worklist
if(remove)
moveToNullspace()
powernet.remove_cable(src) //remove the cut cable from its powernet
- var/first = TRUE
- var/delay = 0
for(var/obj/O in P_list)
- if(first)
- first = FALSE
- continue
- addtimer(CALLBACK(O, .proc/auto_propogate_cut_cable, O), delay) //so we don't rebuild the network X times when singulo/explosion destroys a line of X cables
- delay += 5
+ addtimer(CALLBACK(O, .proc/auto_propogate_cut_cable, O), 0) //so we don't rebuild the network X times when singulo/explosion destroys a line of X cables
///////////////////////////////////////////////
// The cable coil object, used for laying cable
@@ -350,7 +353,7 @@ GLOBAL_LIST_INIT(cable_coil_recipes, list (new/datum/stack_recipe("cable restrai
/obj/item/stack/cable_coil
name = "cable coil"
- custom_price = 15
+ custom_price = 30
gender = NEUTER //That's a cable coil sounds better than that's some cable coils
icon = 'icons/obj/power.dmi'
icon_state = "coil"
diff --git a/code/modules/power/lighting.dm b/code/modules/power/lighting.dm
index 5e22ce6ab28..c00f37cf87a 100644
--- a/code/modules/power/lighting.dm
+++ b/code/modules/power/lighting.dm
@@ -641,7 +641,7 @@
to_chat(H, "You receive some charge from the [fitting].")
stomach.adjust_charge(5)
else
- to_chat(H, "You can't receive charge from the [fitting].")
+ to_chat(H, "You can't receive charge from the [fitting]!")
return
if(H.gloves)
diff --git a/code/modules/power/pipecleaners.dm b/code/modules/power/pipecleaners.dm
index de460951dd7..450741cf57c 100644
--- a/code/modules/power/pipecleaners.dm
+++ b/code/modules/power/pipecleaners.dm
@@ -130,14 +130,8 @@ By design, d1 is the smallest direction and d2 is the highest
// - pipe cleaner coil : merge pipe cleaners
//
/obj/structure/pipe_cleaner/proc/handlecable(obj/item/W, mob/user, params)
- var/turf/T = get_turf(src)
- if(T.intact)
- return
if(W.tool_behaviour == TOOL_WIRECUTTER)
- user.visible_message("[user] cuts the pipe cleaner.", "You cut the pipe cleaner.")
- stored.add_fingerprint(user)
- investigate_log("was cut by [key_name(usr)] in [AREACOORD(src)]", INVESTIGATE_WIRES)
- deconstruct()
+ cut_pipe_cleaner(user)
return
else if(istype(W, /obj/item/stack/pipe_cleaner_coil))
@@ -149,6 +143,12 @@ By design, d1 is the smallest direction and d2 is the highest
add_fingerprint(user)
+/obj/structure/pipe_cleaner/proc/cut_pipe_cleaner(mob/user)
+ user.visible_message("[user] pulls up the pipe cleaner.", "You pull up the pipe cleaner.")
+ stored.add_fingerprint(user)
+ investigate_log("was pulled up by [key_name(usr)] in [AREACOORD(src)]", INVESTIGATE_WIRES)
+ deconstruct()
+
/obj/structure/pipe_cleaner/attackby(obj/item/W, mob/user, params)
handlecable(W, user, params)
@@ -163,6 +163,11 @@ By design, d1 is the smallest direction and d2 is the highest
stored.item_color = colorC
stored.update_icon()
+/obj/structure/pipe_cleaner/AltClick(mob/living/user)
+ if(!user.canUseTopic(src, BE_CLOSE))
+ return
+ cut_pipe_cleaner(user)
+
///////////////////////////////////////////////
// The pipe cleaner coil object, used for laying pipe cleaner
///////////////////////////////////////////////
diff --git a/code/modules/power/port_gen.dm b/code/modules/power/port_gen.dm
index 65051fbb3f8..11997060bdc 100644
--- a/code/modules/power/port_gen.dm
+++ b/code/modules/power/port_gen.dm
@@ -122,7 +122,7 @@
if(anchored)
. += "It is anchored to the ground."
if(in_range(user, src) || isobserver(user))
- . += "The status display reads: Fuel efficiency increased by [(consumption*100)-100]%."
+ . += "The status display reads: Fuel efficiency increased by [(consumption*100)-100]%."
/obj/machinery/power/port_gen/pacman/HasFuel()
if(sheets >= 1 / (time_per_sheet / power_output) - sheet_left)
diff --git a/code/modules/power/power.dm b/code/modules/power/power.dm
index 383261d9e7d..47fd8dbf6b1 100644
--- a/code/modules/power/power.dm
+++ b/code/modules/power/power.dm
@@ -208,70 +208,30 @@
// GLOBAL PROCS for powernets handling
//////////////////////////////////////////
-
-// returns a list of all power-related objects (nodes, cable, junctions) in turf,
-// excluding source, that match the direction d
-// if unmarked==1, only return those with no powernet
-// search_dir is the direction that this is being searched from. null is a valid option.
-/proc/power_list(turf/T, source, unmarked = FALSE, cable_only = FALSE, search_dir = null)
- . = list()
-
- for(var/AM in T)
- if(AM == source)
- continue //we don't want to return source
-
- if(!cable_only && istype(AM, /obj/machinery/power))
- var/obj/machinery/power/P = AM
- if(P.powernet == 0)
- continue // exclude APCs which have powernet=0
-
- if(!unmarked || !P.powernet) //if unmarked=1 we only return things with no powernet
- .[P] = null
-
- else if(istype(AM, /obj/structure/cable))
- var/obj/structure/cable/C = AM
- if(!unmarked || !C.powernet)
- .[C] = turn(search_dir, 180) //invert the searching direction to get the direction connections should be ignored when searching
- return .
-
-
-
-
//remove the old powernet and replace it with a new one throughout the network.
-//use_old_if_found will use an existing powernet and repropogate if it finds it.
-//propogate_after_search will do all the actual powernet application at the end instead of as it goes.
-/proc/propagate_network(obj/O, datum/powernet/PN, use_old_if_found = FALSE, skip_assigned_powernets = FALSE, propogate_after_search = FALSE)
- var/list/worklist = list()
+/proc/propagate_network(obj/structure/cable/C, datum/powernet/PN, skip_assigned_powernets = FALSE)
var/list/found_machines = list()
+ var/list/cables = list()
var/index = 1
- var/obj/P = null
+ var/obj/structure/cable/working_cable
+ var/current_ignore_dir = 128 //Bullshit dir that will never exist in game, but still passes boolean checks
- worklist |= O //start propagating from the passed object
+ cables[C] = current_ignore_dir
- while(index <= worklist.len) //until we've exhausted all power objects
- P = worklist[index] //get the next power object found
+ while(index <= length(cables))
+ working_cable = cables[index]
+ current_ignore_dir = cables[working_cable]
index++
- if( istype(P, /obj/structure/cable))
- var/obj/structure/cable/C = P
- if(C.powernet != PN) //add it to the powernet, if it isn't already there
- if(!propogate_after_search)
- PN.add_cable(C)
- if(C.powernet && use_old_if_found)
- propagate_network(C, C.powernet, FALSE, TRUE, TRUE)
- return
- worklist |= C.get_connections(skip_assigned_powernets, worklist[P]) //get adjacents power objects, with or without a powernet
+ var/list/connections = working_cable.get_cable_connections(skip_assigned_powernets)
+
+ for(var/obj/structure/cable/cable_entry in connections)
+ if(!cables[cable_entry]) //Since it's an associated list, we can just do an access and check it's null before adding; prevents duplicate entries
+ cables[cable_entry] = connections[cable_entry]
- else if(P.anchored && istype(P, /obj/machinery/power))
- var/obj/machinery/power/M = P
- found_machines |= M //we wait until the powernet is fully propagates to connect the machines
-
- else
- continue
-
- if(propogate_after_search)
- for(var/obj/structure/cable/C in worklist)
- PN.add_cable(C)
+ for(var/obj/structure/cable/cable_entry in cables)
+ PN.add_cable(cable_entry)
+ found_machines += cable_entry.get_machine_connections(skip_assigned_powernets)
//now that the powernet is set, connect found machines to it
for(var/obj/machinery/power/PM in found_machines)
diff --git a/code/modules/power/rtg.dm b/code/modules/power/rtg.dm
index 15b950c996e..fef9b902c93 100644
--- a/code/modules/power/rtg.dm
+++ b/code/modules/power/rtg.dm
@@ -39,7 +39,7 @@
/obj/machinery/power/rtg/examine(mob/user)
. = ..()
if(in_range(user, src) || isobserver(user))
- . += "The status display reads: Power generation now at [power_gen*0.001]kW."
+ . += "The status display reads: Power generation now at [power_gen*0.001]kW."
/obj/machinery/power/rtg/attackby(obj/item/I, mob/user, params)
if(default_deconstruction_screwdriver(user, "[initial(icon_state)]-open", initial(icon_state), I))
diff --git a/code/modules/power/singularity/collector.dm b/code/modules/power/singularity/collector.dm
index 0a6811dfd77..d2a90378d47 100644
--- a/code/modules/power/singularity/collector.dm
+++ b/code/modules/power/singularity/collector.dm
@@ -32,6 +32,10 @@
/obj/machinery/power/rad_collector/anchored
anchored = TRUE
+/obj/machinery/power/rad_collector/anchored/delta //Deltastation's engine is shared by engineers and atmos techs
+ desc = "A device which uses Hawking Radiation and plasma to produce power. This model allows access by Atmospheric Technicians."
+ req_access = list(ACCESS_ENGINE_EQUIP, ACCESS_ATMOSPHERICS)
+
/obj/machinery/power/rad_collector/Destroy()
return ..()
diff --git a/code/modules/power/singularity/emitter.dm b/code/modules/power/singularity/emitter.dm
index c7e0e4344e2..2b454ffc18a 100644
--- a/code/modules/power/singularity/emitter.dm
+++ b/code/modules/power/singularity/emitter.dm
@@ -92,7 +92,7 @@
/obj/machinery/power/emitter/examine(mob/user)
. = ..()
if(in_range(user, src) || isobserver(user))
- . += "The status display reads: Emitting one beam each [fire_delay*0.1] seconds.
Power consumption at [active_power_usage]W."
+ . += "The status display reads: Emitting one beam each [fire_delay*0.1] seconds.
Power consumption at [active_power_usage]W."
/obj/machinery/power/emitter/ComponentInitialize()
. = ..()
diff --git a/code/modules/power/singularity/narsie.dm b/code/modules/power/singularity/narsie.dm
index a073997b9d1..4c11cdd9d9e 100644
--- a/code/modules/power/singularity/narsie.dm
+++ b/code/modules/power/singularity/narsie.dm
@@ -188,9 +188,9 @@
to_chat(target, "NAR'SIE HAS LOST INTEREST IN YOU.")
target = food
if(ishuman(target))
- to_chat(target, "NAR'SIE HUNGERS FOR YOUR SOUL.")
+ to_chat(target, "NAR'SIE HUNGERS FOR YOUR SOUL.")
else
- to_chat(target, "NAR'SIE HAS CHOSEN YOU TO LEAD HER TO HER NEXT MEAL.")
+ to_chat(target, "NAR'SIE HAS CHOSEN YOU TO LEAD HER TO HER NEXT MEAL.")
//Wizard narsie
/obj/singularity/narsie/wizard
diff --git a/code/modules/power/supermatter/supermatter.dm b/code/modules/power/supermatter/supermatter.dm
index 4563be4ebf9..691c6083aad 100644
--- a/code/modules/power/supermatter/supermatter.dm
+++ b/code/modules/power/supermatter/supermatter.dm
@@ -611,7 +611,7 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
if (!scalpel.usesLeft)
to_chat(user, "A tiny piece of \the [W] falls off, rendering it useless!")
else
- to_chat(user, "You fail to extract a sliver from \The [src]. \the [W] isn't sharp enough anymore!")
+ to_chat(user, "You fail to extract a sliver from \The [src]! \the [W] isn't sharp enough anymore.")
else if(user.dropItemToGround(W))
user.visible_message("As [user] touches \the [src] with \a [W], silence fills the room...",\
"You touch \the [src] with \the [W], and everything suddenly goes silent.\n\The [W] flashes into dust as you flinch away from \the [src].",\
diff --git a/code/modules/power/tesla/coil.dm b/code/modules/power/tesla/coil.dm
index 7031987151d..fe043c02347 100644
--- a/code/modules/power/tesla/coil.dm
+++ b/code/modules/power/tesla/coil.dm
@@ -43,7 +43,7 @@
/obj/machinery/power/tesla_coil/examine(mob/user)
. = ..()
if(in_range(user, src) || isobserver(user))
- . += "The status display reads: Power generation at [input_power_multiplier*100]%.
Shock interval at [zap_cooldown*0.1] seconds."
+ . += "The status display reads: Power generation at [input_power_multiplier*100]%.
Shock interval at [zap_cooldown*0.1] seconds."
/obj/machinery/power/tesla_coil/on_construction()
if(anchored)
diff --git a/code/modules/power/turbine.dm b/code/modules/power/turbine.dm
index 130f0109934..2f6f68e0afb 100644
--- a/code/modules/power/turbine.dm
+++ b/code/modules/power/turbine.dm
@@ -196,7 +196,7 @@
/obj/machinery/power/turbine/examine(mob/user)
. = ..()
if(in_range(user, src) || isobserver(user))
- . += "The status display reads: Productivity at [productivity*100]%."
+ . += "The status display reads: Productivity at [productivity*100]%."
/obj/machinery/power/turbine/locate_machinery()
if(compressor)
diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm
index b4362d5713e..7c3f041430b 100644
--- a/code/modules/projectiles/gun.dm
+++ b/code/modules/projectiles/gun.dm
@@ -210,7 +210,7 @@
return
if(weapon_weight == WEAPON_HEAVY && user.get_inactive_held_item())
- to_chat(user, "You need both hands free to fire \the [src]!")
+ to_chat(user, "You need both hands free to fire \the [src]!")
return
//DUAL (or more!) WIELDING
@@ -260,7 +260,7 @@
if(chambered && chambered.BB)
if(HAS_TRAIT(user, TRAIT_PACIFISM)) // If the user has the pacifist trait, then they won't be able to fire [src] if the round chambered inside of [src] is lethal.
if(chambered.harmful) // Is the bullet chambered harmful?
- to_chat(user, " [src] is lethally chambered! You don't want to risk harming anyone...")
+ to_chat(user, " [src] is lethally chambered! You don't want to risk harming anyone...")
return
if(randomspread)
sprd = round((rand() - 0.5) * DUALWIELD_PENALTY_EXTRA_MULTIPLIER * (randomized_gun_spread + randomized_bonus_spread))
@@ -309,7 +309,7 @@
if(chambered)
if(HAS_TRAIT(user, TRAIT_PACIFISM)) // If the user has the pacifist trait, then they won't be able to fire [src] if the round chambered inside of [src] is lethal.
if(chambered.harmful) // Is the bullet chambered harmful?
- to_chat(user, " [src] is lethally chambered! You don't want to risk harming anyone...")
+ to_chat(user, " [src] is lethally chambered! You don't want to risk harming anyone...")
return
sprd = round((rand() - 0.5) * DUALWIELD_PENALTY_EXTRA_MULTIPLIER * (randomized_gun_spread + randomized_bonus_spread))
before_firing(target,user)
diff --git a/code/modules/projectiles/guns/ballistic.dm b/code/modules/projectiles/guns/ballistic.dm
index e504825dd43..2f2b016e69a 100644
--- a/code/modules/projectiles/guns/ballistic.dm
+++ b/code/modules/projectiles/guns/ballistic.dm
@@ -54,6 +54,7 @@
var/rack_delay = 5
var/recent_rack = 0
var/tac_reloads = TRUE //Snowflake mechanic no more.
+ var/can_be_sawn_off = FALSE
/obj/item/gun/ballistic/Initialize()
. = ..()
@@ -199,7 +200,7 @@
return chambered
/obj/item/gun/ballistic/attackby(obj/item/A, mob/user, params)
- ..()
+ . = ..()
if (.)
return
if (!internal_magazine && istype(A, /obj/item/ammo_box/magazine))
@@ -232,7 +233,7 @@
to_chat(user, "You can't seem to figure out how to fit [S] on [src]!")
return
if(!user.is_holding(src))
- to_chat(user, "You need be holding [src] to fit [S] to it!")
+ to_chat(user, "You need be holding [src] to fit [S] to it!")
return
if(suppressed)
to_chat(user, "[src] already has a suppressor!")
@@ -241,6 +242,9 @@
to_chat(user, "You screw \the [S] onto \the [src].")
install_suppressor(A)
return
+ if (can_be_sawn_off)
+ if (sawoff(user, A))
+ return
return FALSE
/obj/item/gun/ballistic/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0)
@@ -384,12 +388,24 @@
#undef BRAINS_BLOWN_THROW_SPEED
#undef BRAINS_BLOWN_THROW_RANGE
+GLOBAL_LIST_INIT(gun_saw_types, typecacheof(list(
+ /obj/item/circular_saw,
+ /obj/item/gun/energy/plasmacutter,
+ /obj/item/melee/transforming/energy,
+ /obj/item/twohanded/required/chainsaw,
+ /obj/item/nullrod/claymore/chainsaw_sword,
+ /obj/item/nullrod/chainsaw,
+ /obj/item/mounted_chainsaw)))
-
-/obj/item/gun/ballistic/proc/sawoff(mob/user)
+/obj/item/gun/ballistic/proc/sawoff(mob/user, obj/item/saw)
+ if(!saw.is_sharp() || !is_type_in_typecache(saw, GLOB.gun_saw_types)) //needs to be sharp. Otherwise turned off eswords can cut this.
+ return
if(sawn_off)
to_chat(user, "\The [src] is already shortened!")
return
+ if(bayonet)
+ to_chat(user, "You cannot saw-off \the [src] with \the [bayonet] attached!")
+ return
user.changeNext_move(CLICK_CD_MELEE)
user.visible_message("[user] begins to shorten \the [src].", "You begin to shorten \the [src]...")
diff --git a/code/modules/projectiles/guns/ballistic/laser_gatling.dm b/code/modules/projectiles/guns/ballistic/laser_gatling.dm
index 4f194a5e5fd..8861a1c64e9 100644
--- a/code/modules/projectiles/guns/ballistic/laser_gatling.dm
+++ b/code/modules/projectiles/guns/ballistic/laser_gatling.dm
@@ -137,11 +137,11 @@
ammo_pack.overheat += burst_size
..()
else
- to_chat(user, "The gun's heat sensor locked the trigger to prevent lens damage.")
+ to_chat(user, "The gun's heat sensor locked the trigger to prevent lens damage!")
/obj/item/gun/ballistic/minigun/afterattack(atom/target, mob/living/user, flag, params)
if(!ammo_pack || ammo_pack.loc != user)
- to_chat(user, "You need the backpack power source to fire the gun!")
+ to_chat(user, "You need the backpack power source to fire the gun!")
. = ..()
/obj/item/gun/ballistic/minigun/dropped(mob/living/user)
diff --git a/code/modules/projectiles/guns/ballistic/launchers.dm b/code/modules/projectiles/guns/ballistic/launchers.dm
index 300644cae87..ec18e6cef44 100644
--- a/code/modules/projectiles/guns/ballistic/launchers.dm
+++ b/code/modules/projectiles/guns/ballistic/launchers.dm
@@ -73,7 +73,7 @@
return //too difficult to remove the rocket with TK
/obj/item/gun/ballistic/rocketlauncher/suicide_act(mob/living/user)
- user.visible_message("[user] aims [src] at the ground! It looks like [user.p_theyre()] performing a sick rocket jump!", \
+ user.visible_message("[user] aims [src] at the ground! It looks like [user.p_theyre()] performing a sick rocket jump!", \
"You aim [src] at the ground to perform a bisnasty rocket jump...")
if(can_shoot())
user.notransform = TRUE
diff --git a/code/modules/projectiles/guns/ballistic/revolver.dm b/code/modules/projectiles/guns/ballistic/revolver.dm
index 70a0607709d..4679e31578c 100644
--- a/code/modules/projectiles/guns/ballistic/revolver.dm
+++ b/code/modules/projectiles/guns/ballistic/revolver.dm
@@ -167,7 +167,7 @@
var/spun = FALSE
/obj/item/gun/ballistic/revolver/russian/do_spin()
- ..()
+ . = ..()
spun = TRUE
/obj/item/gun/ballistic/revolver/russian/attackby(obj/item/A, mob/user, params)
diff --git a/code/modules/projectiles/guns/ballistic/rifle.dm b/code/modules/projectiles/guns/ballistic/rifle.dm
index 78b0c9dfb05..047f5906c57 100644
--- a/code/modules/projectiles/guns/ballistic/rifle.dm
+++ b/code/modules/projectiles/guns/ballistic/rifle.dm
@@ -51,6 +51,8 @@ obj/item/gun/ballistic/rifle/attackby(obj/item/A, mob/user, params)
/obj/item/gun/ballistic/rifle/boltaction
name = "\improper Mosin Nagant"
desc = "This piece of junk looks like something that could have been used 700 years ago. It feels slightly moist."
+ sawn_desc = "An extremely sawn-off Mosin Nagant, popularly known as an \"obrez\". There was probably a reason it wasn't manufactured this short to begin with."
+ w_class = WEIGHT_CLASS_BULKY
icon_state = "moistnugget"
item_state = "moistnugget"
slot_flags = 0 //no ITEM_SLOT_BACK sprite, alas
@@ -58,12 +60,26 @@ obj/item/gun/ballistic/rifle/attackby(obj/item/A, mob/user, params)
can_bayonet = TRUE
knife_x_offset = 27
knife_y_offset = 13
+ can_be_sawn_off = TRUE
+
+/obj/item/gun/ballistic/rifle/boltaction/sawoff(mob/user)
+ . = ..()
+ if(.)
+ spread = 36
+ can_bayonet = FALSE
+
+/obj/item/gun/ballistic/rifle/boltaction/blow_up(mob/user)
+ . = 0
+ if(chambered && chambered.BB)
+ process_fire(user, user, FALSE)
+ . = 1
/obj/item/gun/ballistic/rifle/boltaction/enchanted
name = "enchanted bolt action rifle"
desc = "Careful not to lose your head."
var/guns_left = 30
mag_type = /obj/item/ammo_box/magazine/internal/boltaction/enchanted
+ can_be_sawn_off = FALSE
/obj/item/gun/ballistic/rifle/boltaction/enchanted/arcane_barrage
name = "arcane barrage"
@@ -73,7 +89,7 @@ obj/item/gun/ballistic/rifle/attackby(obj/item/A, mob/user, params)
icon_state = "arcane_barrage"
item_state = "arcane_barrage"
can_bayonet = FALSE
- item_flags = NEEDS_PERMIT | DROPDEL
+ item_flags = NEEDS_PERMIT | DROPDEL | ABSTRACT | NOBLUDGEON
flags_1 = NONE
mag_type = /obj/item/ammo_box/magazine/internal/boltaction/enchanted/arcane_barrage
@@ -82,24 +98,24 @@ obj/item/gun/ballistic/rifle/attackby(obj/item/A, mob/user, params)
. = ..()
guns_left = 0
-/obj/item/gun/ballistic/rifle/boltaction/enchanted/proc/discard_gun(mob/user)
- throw_at(pick(oview(7,get_turf(user))),1,1)
- user.visible_message("[user] tosses aside the spent rifle!")
+/obj/item/gun/ballistic/rifle/boltaction/enchanted/proc/discard_gun(mob/living/user)
+ user.throw_item(pick(oview(7,get_turf(user))))
-/obj/item/gun/ballistic/rifle/boltaction/enchanted/arcane_barrage/discard_gun(mob/user)
- return
+/obj/item/gun/ballistic/rifle/boltaction/enchanted/arcane_barrage/discard_gun(mob/living/user)
+ qdel(src)
/obj/item/gun/ballistic/rifle/boltaction/enchanted/attack_self()
return
-/obj/item/gun/ballistic/rifle/boltaction/enchanted/shoot_live_shot(mob/living/user as mob|obj, pointblank = 0, mob/pbtarget = null, message = 1)
- ..()
+/obj/item/gun/ballistic/rifle/boltaction/enchanted/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0)
+ . = ..()
+ if(!.)
+ return
if(guns_left)
- var/obj/item/gun/ballistic/rifle/boltaction/enchanted/GUN = new type
- GUN.guns_left = guns_left - 1
- user.dropItemToGround(src, TRUE)
+ var/obj/item/gun/ballistic/rifle/boltaction/enchanted/gun = new type
+ gun.guns_left = guns_left - 1
+ discard_gun(user)
user.swap_hand()
- user.put_in_hands(GUN)
+ user.put_in_hands(gun)
else
user.dropItemToGround(src, TRUE)
- discard_gun(user)
diff --git a/code/modules/projectiles/guns/ballistic/shotgun.dm b/code/modules/projectiles/guns/ballistic/shotgun.dm
index 520fbd8e940..cf90c353aa9 100644
--- a/code/modules/projectiles/guns/ballistic/shotgun.dm
+++ b/code/modules/projectiles/guns/ballistic/shotgun.dm
@@ -38,15 +38,7 @@
icon_state = "riotshotgun"
mag_type = /obj/item/ammo_box/magazine/internal/shot/riot
sawn_desc = "Come with me if you want to live."
-
-/obj/item/gun/ballistic/shotgun/riot/attackby(obj/item/A, mob/user, params)
- ..()
- if(istype(A, /obj/item/circular_saw) || istype(A, /obj/item/gun/energy/plasmacutter))
- sawoff(user)
- if(istype(A, /obj/item/melee/transforming/energy))
- var/obj/item/melee/transforming/energy/W = A
- if(W.active)
- sawoff(user)
+ can_be_sawn_off = TRUE
// Automatic Shotguns//
@@ -164,21 +156,13 @@
)
semi_auto = TRUE
bolt_type = BOLT_TYPE_NO_BOLT
+ can_be_sawn_off = TRUE
/obj/item/gun/ballistic/shotgun/doublebarrel/AltClick(mob/user)
. = ..()
if(unique_reskin && !current_skin && user.canUseTopic(src, BE_CLOSE, NO_DEXTERY))
reskin_obj(user)
-/obj/item/gun/ballistic/shotgun/doublebarrel/attackby(obj/item/A, mob/user, params)
- ..()
- if(istype(A, /obj/item/melee/transforming/energy))
- var/obj/item/melee/transforming/energy/W = A
- if(W.active)
- sawoff(user)
- if(istype(A, /obj/item/circular_saw) || istype(A, /obj/item/gun/energy/plasmacutter))
- sawoff(user)
-
// IMPROVISED SHOTGUN //
/obj/item/gun/ballistic/shotgun/doublebarrel/improvised
diff --git a/code/modules/projectiles/guns/magic/wand.dm b/code/modules/projectiles/guns/magic/wand.dm
index fc26612a74d..6dcfbde387c 100644
--- a/code/modules/projectiles/guns/magic/wand.dm
+++ b/code/modules/projectiles/guns/magic/wand.dm
@@ -94,14 +94,17 @@
max_charges = 10 //10, 5, 5, 4
/obj/item/gun/magic/wand/resurrection/zap_self(mob/living/user)
+ ..()
+ charges--
+ if(user.anti_magic_check())
+ user.visible_message("[src] has no effect on [user]!")
+ return
user.revive(full_heal = 1)
if(iscarbon(user))
var/mob/living/carbon/C = user
C.regenerate_limbs()
C.regenerate_organs()
to_chat(user, "You feel great!")
- charges--
- ..()
/obj/item/gun/magic/wand/resurrection/debug //for testing
desc = "Is it possible for something to be even more powerful than regular magic? This wand is."
diff --git a/code/modules/projectiles/guns/misc/grenade_launcher.dm b/code/modules/projectiles/guns/misc/grenade_launcher.dm
index dc44a1f4ff0..4bc388a5e70 100644
--- a/code/modules/projectiles/guns/misc/grenade_launcher.dm
+++ b/code/modules/projectiles/guns/misc/grenade_launcher.dm
@@ -26,7 +26,7 @@
to_chat(user, "You put the grenade in the grenade launcher.")
to_chat(user, "[grenades.len] / [max_grenades] Grenades.")
else
- to_chat(usr, "The grenade launcher cannot hold more grenades.")
+ to_chat(usr, "The grenade launcher cannot hold more grenades!")
/obj/item/gun/grenadelauncher/can_shoot()
return grenades.len
diff --git a/code/modules/projectiles/pins.dm b/code/modules/projectiles/pins.dm
index 05d63673066..a5eeebd3616 100644
--- a/code/modules/projectiles/pins.dm
+++ b/code/modules/projectiles/pins.dm
@@ -26,15 +26,15 @@
if(G.pin && (force_replace || G.pin.pin_removeable))
G.pin.forceMove(get_turf(G))
G.pin.gun_remove(user)
- to_chat(user, "You remove [G]'s old pin.")
+ to_chat(user, "You remove [G]'s old pin.")
if(!G.pin)
if(!user.temporarilyRemoveItemFromInventory(src))
return
gun_insert(user, G)
- to_chat(user, "You insert [src] into [G].")
+ to_chat(user, "You insert [src] into [G].")
else
- to_chat(user, "This firearm already has a firing pin installed.")
+ to_chat(user, "This firearm already has a firing pin installed.")
/obj/item/firing_pin/emag_act(mob/user)
if(obj_flags & EMAGGED)
diff --git a/code/modules/projectiles/projectile/special/rocket.dm b/code/modules/projectiles/projectile/special/rocket.dm
index 6f8d1135731..6ff9d45b3fe 100644
--- a/code/modules/projectiles/projectile/special/rocket.dm
+++ b/code/modules/projectiles/projectile/special/rocket.dm
@@ -30,7 +30,7 @@
return BULLET_ACT_HIT
/obj/item/projectile/bullet/a84mm_he
- name ="\improper HE rocket"
+ name ="\improper HE missile"
desc = "Boom."
icon_state = "missile"
damage = 30
@@ -43,3 +43,33 @@
else
explosion(target, 0, 0, 2, 4)
return BULLET_ACT_HIT
+
+/obj/item/projectile/bullet/a84mm_br
+ name ="\improper HE missile"
+ desc = "Boom."
+ icon_state = "missile"
+ damage = 30
+ ricochets_max = 0 //it's a MISSILE
+ var/sturdy = list(
+ /turf/closed,
+ /obj/mecha,
+ /obj/machinery/door/,
+ /obj/machinery/door/poddoor/shutters
+ )
+
+/obj/item/broken_missile
+ name = "\improper broken missile"
+ desc = "A missile that did not detonate. The tail has snapped and it is in no way fit to be used again."
+ icon = 'icons/obj/projectiles.dmi'
+ icon_state = "missile_broken"
+ w_class = WEIGHT_CLASS_TINY
+
+
+/obj/item/projectile/bullet/a84mm_br/on_hit(atom/target, blocked=0)
+ ..()
+ for(var/i in sturdy)
+ if(istype(target, i))
+ explosion(target, 0, 1, 1, 2)
+ return BULLET_ACT_HIT
+ //if(istype(target, /turf/closed) || ismecha(target))
+ new /obj/item/broken_missile(get_turf(src), 1)
\ No newline at end of file
diff --git a/code/modules/reagents/chemistry/holder.dm b/code/modules/reagents/chemistry/holder.dm
index 6afa32d47a4..5b3f0d21f45 100644
--- a/code/modules/reagents/chemistry/holder.dm
+++ b/code/modules/reagents/chemistry/holder.dm
@@ -167,7 +167,7 @@
return master
-/datum/reagents/proc/trans_to(obj/target, amount = 1, multiplier = 1, preserve_data = TRUE, no_react = FALSE, mob/transfered_by, remove_blacklisted = FALSE)
+/datum/reagents/proc/trans_to(obj/target, amount = 1, multiplier = 1, preserve_data = TRUE, no_react = FALSE, mob/transfered_by, remove_blacklisted = FALSE, method = null, show_message = TRUE)
//if preserve_data=0, the reagents data will be lost. Usefull if you use data for some strange stuff and don't want it to be transferred.
var/list/cached_reagents = reagent_list
if(!target || !total_volume)
@@ -201,6 +201,9 @@
if(preserve_data)
trans_data = copy_data(T)
R.add_reagent(T.type, transfer_amount * multiplier, trans_data, chem_temp, no_react = 1) //we only handle reaction after every reagent has been transfered.
+ if(method)
+ R.react_single(T, target_atom, method, part, show_message)
+ T.on_transfer(target_atom, method, transfer_amount * multiplier)
remove_reagent(T.type, transfer_amount)
update_total()
@@ -559,6 +562,31 @@
if("OBJ")
R.reaction_obj(A, R.volume * volume_modifier, show_message)
+/datum/reagents/proc/react_single(datum/reagent/R, atom/A, method = TOUCH, volume_modifier = 1, show_message = TRUE)
+ var/react_type
+ if(isliving(A))
+ react_type = "LIVING"
+ if(method == INGEST)
+ var/mob/living/L = A
+ L.taste(src)
+ else if(isturf(A))
+ react_type = "TURF"
+ else if(isobj(A))
+ react_type = "OBJ"
+ else
+ return
+ switch(react_type)
+ if("LIVING")
+ var/touch_protection = 0
+ if(method == VAPOR)
+ var/mob/living/L = A
+ touch_protection = L.get_permeability_protection()
+ R.reaction_mob(A, method, R.volume * volume_modifier, show_message, touch_protection)
+ if("TURF")
+ R.reaction_turf(A, R.volume * volume_modifier, show_message)
+ if("OBJ")
+ R.reaction_obj(A, R.volume * volume_modifier, show_message)
+
/datum/reagents/proc/holder_full()
if(total_volume >= maximum_volume)
return TRUE
@@ -678,15 +706,19 @@
return FALSE
-/datum/reagents/proc/has_reagent(reagent, amount = -1)
+/datum/reagents/proc/has_reagent(reagent, amount = -1, needs_metabolizing = FALSE)
var/list/cached_reagents = reagent_list
for(var/_reagent in cached_reagents)
var/datum/reagent/R = _reagent
if (R.type == reagent)
if(!amount)
+ if(needs_metabolizing && !R.metabolizing)
+ return 0
return R
else
if(round(R.volume, CHEMICAL_QUANTISATION_LEVEL) >= amount)
+ if(needs_metabolizing && !R.metabolizing)
+ return 0
return R
else
return 0
diff --git a/code/modules/reagents/chemistry/machinery/chem_dispenser.dm b/code/modules/reagents/chemistry/machinery/chem_dispenser.dm
index a3286bf5480..e416c3fb17a 100644
--- a/code/modules/reagents/chemistry/machinery/chem_dispenser.dm
+++ b/code/modules/reagents/chemistry/machinery/chem_dispenser.dm
@@ -99,8 +99,10 @@
if(panel_open)
. += "[src]'s maintenance hatch is open!"
if(in_range(user, src) || isobserver(user))
- . += {"The status display reads:
Recharging [recharge_amount] power units per interval.
Power efficiency increased by
- [round((powerefficiency*1000)-100, 1)]%.
Macro granularity at [macroresolution]u."}
+ . += "The status display reads: \n"+\
+ "Recharging [recharge_amount] power units per interval.\n"+\
+ "Power efficiency increased by [round((powerefficiency*1000)-100, 1)]%.\n"+\
+ "Macro granularity at [macroresolution]u."
/obj/machinery/chem_dispenser/process()
if (recharge_counter >= 4)
@@ -616,3 +618,65 @@
component_parts += new /obj/item/stack/sheet/glass(null)
component_parts += new /obj/item/stock_parts/cell/bluespace(null)
RefreshParts()
+
+/obj/machinery/chem_dispenser/abductor
+ name = "reagent synthesizer"
+ desc = "Synthesizes a variety of reagents using proto-matter."
+ icon = 'icons/obj/abductor.dmi'
+ icon_state = "chem_dispenser"
+ has_panel_overlay = FALSE
+ circuit = /obj/item/circuitboard/machine/chem_dispenser/abductor
+ working_state = null
+ nopower_state = null
+ dispensable_reagents = list(
+ /datum/reagent/aluminium,
+ /datum/reagent/bromine,
+ /datum/reagent/carbon,
+ /datum/reagent/chlorine,
+ /datum/reagent/copper,
+ /datum/reagent/consumable/ethanol,
+ /datum/reagent/fluorine,
+ /datum/reagent/hydrogen,
+ /datum/reagent/iodine,
+ /datum/reagent/iron,
+ /datum/reagent/lithium,
+ /datum/reagent/mercury,
+ /datum/reagent/nitrogen,
+ /datum/reagent/oxygen,
+ /datum/reagent/phosphorus,
+ /datum/reagent/potassium,
+ /datum/reagent/uranium/radium,
+ /datum/reagent/silicon,
+ /datum/reagent/silver,
+ /datum/reagent/sodium,
+ /datum/reagent/stable_plasma,
+ /datum/reagent/consumable/sugar,
+ /datum/reagent/sulfur,
+ /datum/reagent/toxin/acid,
+ /datum/reagent/water,
+ /datum/reagent/fuel,
+ /datum/reagent/acetone,
+ /datum/reagent/ammonia,
+ /datum/reagent/ash,
+ /datum/reagent/diethylamine,
+ /datum/reagent/oil,
+ /datum/reagent/saltpetre,
+ /datum/reagent/medicine/mine_salve,
+ /datum/reagent/medicine/morphine,
+ /datum/reagent/drug/space_drugs,
+ /datum/reagent/toxin,
+ /datum/reagent/toxin/plasma,
+ /datum/reagent/uranium
+ )
+
+/obj/machinery/chem_dispenser/abductor/Initialize()
+ . = ..()
+ component_parts = list()
+ component_parts += new /obj/item/circuitboard/machine/chem_dispenser(null)
+ component_parts += new /obj/item/stock_parts/matter_bin/bluespace(null)
+ component_parts += new /obj/item/stock_parts/matter_bin/bluespace(null)
+ component_parts += new /obj/item/stock_parts/capacitor/quadratic(null)
+ component_parts += new /obj/item/stock_parts/manipulator/femto(null)
+ component_parts += new /obj/item/stack/sheet/glass(null)
+ component_parts += new /obj/item/stock_parts/cell/bluespace(null)
+ RefreshParts()
diff --git a/code/modules/reagents/chemistry/machinery/chem_heater.dm b/code/modules/reagents/chemistry/machinery/chem_heater.dm
index 0fddbb99707..f52203f4b35 100644
--- a/code/modules/reagents/chemistry/machinery/chem_heater.dm
+++ b/code/modules/reagents/chemistry/machinery/chem_heater.dm
@@ -54,7 +54,7 @@
/obj/machinery/chem_heater/examine(mob/user)
. = ..()
if(in_range(user, src) || isobserver(user))
- . += "The status display reads: Heating reagents at [heater_coefficient*1000]% speed."
+ . += "The status display reads: Heating reagents at [heater_coefficient*1000]% speed."
/obj/machinery/chem_heater/process()
..()
diff --git a/code/modules/reagents/chemistry/machinery/reagentgrinder.dm b/code/modules/reagents/chemistry/machinery/reagentgrinder.dm
index bf119e2f58f..364febf0bf8 100644
--- a/code/modules/reagents/chemistry/machinery/reagentgrinder.dm
+++ b/code/modules/reagents/chemistry/machinery/reagentgrinder.dm
@@ -70,8 +70,8 @@
. += "- \A [O.name]."
if(!(stat & (NOPOWER|BROKEN)))
- . += {"The status display reads:\n
- - Grinding reagents at [speed*100]%."}
+ . += "The status display reads:\n"+\
+ "- Grinding reagents at [speed*100]%."
if(beaker)
for(var/datum/reagent/R in beaker.reagents.reagent_list)
. += "- [R.volume] units of [R.name]."
@@ -256,6 +256,7 @@
if(beaker.reagents.total_volume >= beaker.reagents.maximum_volume)
break
var/obj/item/I = i
+ check_trash(I)
if(I.juice_results)
juice_item(I)
@@ -275,6 +276,7 @@
if(beaker.reagents.total_volume >= beaker.reagents.maximum_volume)
break
var/obj/item/I = i
+ check_trash(I)
if(I.grind_results)
grind_item(i, user)
@@ -287,6 +289,12 @@
I.reagents.trans_to(beaker, I.reagents.total_volume, transfered_by = user)
remove_object(I)
+/obj/machinery/reagentgrinder/proc/check_trash(obj/item/I)
+ if (istype(I, /obj/item/reagent_containers/food/snacks))
+ var/obj/item/reagent_containers/food/snacks/R = I
+ if (R.trash)
+ R.generate_trash(get_turf(src))
+
/obj/machinery/reagentgrinder/proc/mix(mob/user)
//For butter and other things that would change upon shaking or mixing
power_change()
diff --git a/code/modules/reagents/chemistry/machinery/smoke_machine.dm b/code/modules/reagents/chemistry/machinery/smoke_machine.dm
index 19b67f15507..259921f43dd 100644
--- a/code/modules/reagents/chemistry/machinery/smoke_machine.dm
+++ b/code/modules/reagents/chemistry/machinery/smoke_machine.dm
@@ -15,7 +15,7 @@
var/setting = 1 // displayed range is 3 * setting
var/max_range = 3 // displayed max range is 3 * max range
-/datum/effect_system/smoke_spread/chem/smoke_machine/set_up(datum/reagents/carry, setting=1, efficiency=10, loc)
+/datum/effect_system/smoke_spread/chem/smoke_machine/set_up(datum/reagents/carry, setting=1, efficiency=10, loc, silent=FALSE)
amount = setting
carry.copy_to(chemholder, 20)
carry.remove_any(amount * 16 / efficiency)
diff --git a/code/modules/reagents/chemistry/reagents.dm b/code/modules/reagents/chemistry/reagents.dm
index e03626ac07f..6bc494809b3 100644
--- a/code/modules/reagents/chemistry/reagents.dm
+++ b/code/modules/reagents/chemistry/reagents.dm
@@ -67,6 +67,10 @@ GLOBAL_LIST_INIT(name2reagent, build_name2reagent())
holder.remove_reagent(type, metabolization_rate * M.metabolism_efficiency) //By default it slowly disappears.
return
+datum/reagent/proc/on_transfer(atom/A, method=TOUCH, volume) //Called after a reagent is transfered
+ return
+
+
// Called when this reagent is first added to a mob
/datum/reagent/proc/on_mob_add(mob/living/L)
return
diff --git a/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm b/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm
index 528fa65783c..0cc76ef40bf 100644
--- a/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm
@@ -44,7 +44,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
C.drunkenness = max((C.drunkenness + (sqrt(volume) * booze_power * ALCOHOL_RATE)), 0) //Volume, power, and server alcohol rate effect how quickly one gets drunk
var/obj/item/organ/liver/L = C.getorganslot(ORGAN_SLOT_LIVER)
if (istype(L))
- C.applyLiverDamage((max(sqrt(volume) * (boozepwr ** ALCOHOL_EXPONENT) * L.alcohol_tolerance, 0))/150)
+ L.applyOrganDamage(((max(sqrt(volume) * (boozepwr ** ALCOHOL_EXPONENT) * L.alcohol_tolerance, 0))/150))
return ..()
/datum/reagent/consumable/ethanol/reaction_obj(obj/O, reac_volume)
@@ -175,24 +175,24 @@ All effects don't start immediately, but rather get worse over time; the rate is
var/obj/item/I = M.get_active_held_item()
if(I)
M.dropItemToGround(I)
- to_chat(M, "Your hands jitter and you drop what you were holding!")
+ to_chat(M, "Your hands jitter and you drop what you were holding!")
M.Jitter(10)
if(prob(7))
to_chat(M, "[pick("You have a really bad headache.", "Your eyes hurt.", "You find it hard to stay still.", "You feel your heart practically beating out of your chest.")]")
if(prob(5) && iscarbon(M))
+ var/obj/item/organ/eyes/eyes = M.getorganslot(ORGAN_SLOT_EYES)
if(HAS_TRAIT(M, TRAIT_BLIND))
- var/obj/item/organ/eyes/eye = M.getorganslot(ORGAN_SLOT_EYES)
- if(istype(eye))
- eye.Remove(M)
- eye.forceMove(get_turf(M))
+ if(istype(eyes))
+ eyes.Remove(M)
+ eyes.forceMove(get_turf(M))
to_chat(M, "You double over in pain as you feel your eyeballs liquify in your head!")
M.emote("scream")
M.adjustBruteLoss(15)
else
to_chat(M, "You scream in terror as you go blind!")
- M.become_blind(EYE_DAMAGE)
+ eyes.applyOrganDamage(eyes.maxHealth)
M.emote("scream")
if(prob(3) && iscarbon(M))
@@ -1628,7 +1628,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
/datum/reagent/consumable/ethanol/alexander/on_mob_life(mob/living/L)
..()
if(mighty_shield && !(mighty_shield in L.contents)) //If you had a shield and lose it, you lose the reagent as well. Otherwise this is just a normal drink.
- L.reagents.del_reagent("alexander")
+ L.reagents.del_reagent(/datum/reagent/consumable/ethanol/alexander)
/datum/reagent/consumable/ethanol/alexander/on_mob_end_metabolize(mob/living/L)
if(mighty_shield)
diff --git a/code/modules/reagents/chemistry/reagents/drink_reagents.dm b/code/modules/reagents/chemistry/reagents/drink_reagents.dm
index 31b499e2804..26a75f1b5aa 100644
--- a/code/modules/reagents/chemistry/reagents/drink_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/drink_reagents.dm
@@ -207,8 +207,8 @@
if(M.getBruteLoss() && prob(20))
M.heal_bodypart_damage(1,0, 0)
. = 1
- if(holder.has_reagent("capsaicin"))
- holder.remove_reagent("capsaicin", 2)
+ if(holder.has_reagent(/datum/reagent/consumable/capsaicin))
+ holder.remove_reagent(/datum/reagent/consumable/capsaicin, 2)
..()
/datum/reagent/consumable/soymilk
@@ -262,8 +262,8 @@
M.AdjustSleeping(-40, FALSE)
//310.15 is the normal bodytemp.
M.adjust_bodytemperature(25 * TEMPERATURE_DAMAGE_COEFFICIENT, 0, BODYTEMP_NORMAL)
- if(holder.has_reagent("frostoil"))
- holder.remove_reagent("frostoil", 5)
+ if(holder.has_reagent(/datum/reagent/consumable/frostoil))
+ holder.remove_reagent(/datum/reagent/consumable/frostoil, 5)
..()
. = 1
@@ -311,7 +311,7 @@
/datum/reagent/consumable/tea/arnold_palmer/on_mob_life(mob/living/carbon/M)
if(prob(5))
- to_chat(M, "[pick("You remember to square your shoulders.","You remember to keep your head down.","You can't decide between squaring your shoulders and keeping your head down.","You remember to relax.","You think about how someday you'll get two strokes off your golf game.")]")
+ to_chat(M, "[pick("You remember to square your shoulders.","You remember to keep your head down.","You can't decide between squaring your shoulders and keeping your head down.","You remember to relax.","You think about how someday you'll get two strokes off your golf game.")]")
..()
. = 1
diff --git a/code/modules/reagents/chemistry/reagents/food_reagents.dm b/code/modules/reagents/chemistry/reagents/food_reagents.dm
index 8c7f6679519..48077b34e67 100755
--- a/code/modules/reagents/chemistry/reagents/food_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/food_reagents.dm
@@ -600,10 +600,10 @@
unprotected = TRUE
if(unprotected)
if(!M.getorganslot(ORGAN_SLOT_EYES)) //can't blind somebody with no eyes
- to_chat(M, "Your eye sockets feel wet.")
+ to_chat(M, "Your eye sockets feel wet.")
else
if(!M.eye_blurry)
- to_chat(M, "Tears well up in your eyes!")
+ to_chat(M, "Tears well up in your eyes!")
M.blind_eyes(2)
M.blur_eyes(5)
..()
@@ -613,7 +613,7 @@
if(M.eye_blurry) //Don't worsen vision if it was otherwise fine
M.blur_eyes(4)
if(prob(10))
- to_chat(M, "Your eyes sting!")
+ to_chat(M, "Your eyes sting!")
M.blind_eyes(2)
@@ -732,6 +732,15 @@
taste_mult = 100
can_synth = FALSE
+/datum/reagent/consumable/nutriment/peptides
+ name = "Peptides"
+ color = "#BBD4D9"
+ taste_description = "mint frosting"
+ description = "These restorative peptides not only speed up wound healing, but are nutrious as well!"
+ nutriment_factor = 10 * REAGENTS_METABOLISM // 33% less than nutriment to reduce weight gain
+ brute_heal = 3
+ burn_heal = 1
+
/datum/reagent/consumable/caramel
name = "Caramel"
description = "Who would have guessed that heating sugar is so delicious?"
diff --git a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm
index 0495bf98a19..1db70d5503d 100644
--- a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm
@@ -215,9 +215,10 @@
//Goon Chems. Ported mainly from Goonstation. Easily mixable (or not so easily) and provide a variety of effects.
/datum/reagent/medicine/silver_sulfadiazine
name = "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."
+ description = "If used in touch-based applications, immediately restores burn wounds as well as restoring more over time. If ingested through other means or overdosed, deals minor toxin damage."
reagent_state = LIQUID
color = "#C8A5DC"
+ overdose_threshold = 45
/datum/reagent/medicine/silver_sulfadiazine/reaction_mob(mob/living/M, method=TOUCH, reac_volume, show_message = 1)
if(iscarbon(M) && M.stat != DEAD)
@@ -238,6 +239,12 @@
..()
. = 1
+/datum/reagent/medicine/silver_sulfadiazine/overdose_process(mob/living/M)
+ M.adjustFireLoss(2.5*REM, 0)
+ M.adjustToxLoss(0.5, 0)
+ ..()
+ . = 1
+
/datum/reagent/medicine/oxandrolone
name = "Oxandrolone"
description = "Stimulates the healing of severe burns. Extremely rapidly heals severe burns and slowly heals minor ones. Overdose will worsen existing burns."
@@ -247,7 +254,7 @@
overdose_threshold = 25
/datum/reagent/medicine/oxandrolone/on_mob_life(mob/living/carbon/M)
- if(M.getFireLoss() > 50)
+ if(M.getFireLoss() > 25)
M.adjustFireLoss(-4*REM, 0) //Twice as effective as silver sulfadiazine for severe burns
else
M.adjustFireLoss(-0.5*REM, 0) //But only a quarter as effective for more minor ones
@@ -262,9 +269,10 @@
/datum/reagent/medicine/styptic_powder
name = "Styptic Powder"
- 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."
+ description = "If used in touch-based applications, immediately restores bruising as well as restoring more over time. If ingested through other means or overdosed, deals minor toxin damage."
reagent_state = LIQUID
color = "#FF9696"
+ overdose_threshold = 45
/datum/reagent/medicine/styptic_powder/reaction_mob(mob/living/M, method=TOUCH, reac_volume, show_message = 1)
if(iscarbon(M) && M.stat != DEAD)
@@ -286,6 +294,12 @@
..()
. = 1
+/datum/reagent/medicine/styptic_powder/overdose_process(mob/living/M)
+ M.adjustBruteLoss(2.5*REM, 0)
+ M.adjustToxLoss(0.5, 0)
+ ..()
+ . = 1
+
/datum/reagent/medicine/salglu_solution
name = "Saline-Glucose Solution"
description = "Has a 33% chance per metabolism cycle to heal brute and burn damage. Can be used as a temporary blood substitute."
@@ -314,11 +328,11 @@
/datum/reagent/medicine/salglu_solution/overdose_process(mob/living/M)
if(prob(3))
- to_chat(M, "You feel salty.")
+ to_chat(M, "You feel salty.")
holder.add_reagent(/datum/reagent/consumable/sodiumchloride, 1)
holder.remove_reagent(/datum/reagent/medicine/salglu_solution, 0.5)
else if(prob(3))
- to_chat(M, "You feel sweet.")
+ to_chat(M, "You feel sweet.")
holder.add_reagent(/datum/reagent/consumable/sugar, 1)
holder.remove_reagent(/datum/reagent/medicine/salglu_solution, 0.5)
if(prob(33))
@@ -398,6 +412,13 @@
M.reagents.remove_reagent(R.type,1)
..()
+/datum/reagent/medicine/charcoal/on_transfer(atom/A, method=TOUCH, volume)
+ if(method == INGEST || !iscarbon(A)) //the atom not the charcoal
+ return
+ A.reagents.remove_reagent(/datum/reagent/medicine/charcoal/, volume) //We really should not be injecting an insoluble granular material.
+ A.reagents.add_reagent(/datum/reagent/carbon, volume) // Its pores would get clogged with gunk anyway.
+ ..()
+
/datum/reagent/medicine/omnizine
name = "Omnizine"
description = "Slowly heals all damage types. Overdose will cause damage in all types instead."
@@ -477,7 +498,7 @@
/datum/reagent/medicine/sal_acid/on_mob_life(mob/living/carbon/M)
- if(M.getBruteLoss() > 50)
+ if(M.getBruteLoss() > 25)
M.adjustBruteLoss(-4*REM, 0) //Twice as effective as styptic powder for severe bruising
else
M.adjustBruteLoss(-0.5*REM, 0) //But only a quarter as effective for more minor ones
@@ -548,7 +569,7 @@
if(prob(20) && iscarbon(M))
var/obj/item/I = M.get_active_held_item()
if(I && M.dropItemToGround(I))
- to_chat(M, "Your hands spaz out and you drop what you were holding!")
+ to_chat(M, "Your hands spaz out and you drop what you were holding!")
M.Jitter(10)
M.AdjustAllImmobility(-20, FALSE)
@@ -714,6 +735,7 @@
var/obj/item/organ/eyes/eyes = M.getorganslot(ORGAN_SLOT_EYES)
if (!eyes)
return
+ eyes.applyOrganDamage(-2)
if(HAS_TRAIT_FROM(M, TRAIT_BLIND, EYE_DAMAGE))
if(prob(20))
to_chat(M, "Your vision slowly returns...")
@@ -728,8 +750,6 @@
else if(M.eye_blind || M.eye_blurry)
M.set_blindness(0)
M.set_blurriness(0)
- else if(eyes.eye_damage > 0)
- M.adjust_eye_damage(-1)
..()
/datum/reagent/medicine/atropine
@@ -1314,5 +1334,148 @@
..()
. = 1
+/datum/reagent/medicine/trophazole
+ name = "Trophazole"
+ description = "Orginally developed as fitness supplement, this chemical accelerates wound healing and if ingested turns nutriment into healing peptides"
+ reagent_state = LIQUID
+ color = "#FFFF6B"
+ overdose_threshold = 20
+
+/datum/reagent/medicine/trophazole/on_mob_life(mob/living/carbon/M)
+ M.adjustBruteLoss(-1.5*REM, 0.) // heals 3 brute & 0.5 burn if taken with food. compared to 2.5 brute from bicard + nutriment
+ ..()
+ . = 1
+
+/datum/reagent/medicine/trophazole/overdose_process(mob/living/M)
+ M.adjustBruteLoss(3*REM, 0)
+ ..()
+ . = 1
+
+/datum/reagent/medicine/trophazole/on_transfer(atom/A, method=INGEST, trans_volume)
+ if(method != INGEST || !iscarbon(A))
+ return
+
+ A.reagents.remove_reagent(/datum/reagent/medicine/trophazole, trans_volume * 0.05)
+ A.reagents.add_reagent(/datum/reagent/medicine/metafactor, trans_volume * 0.25)
+
+ ..()
+
+/datum/reagent/medicine/metafactor
+ name = "Mitogen Metabolism Factor"
+ description = "This enzyme catalyzes the conversion of nutricious food into healing peptides."
+ metabolization_rate = 0.0625 * REAGENTS_METABOLISM //slow metabolism rate so the patient can self heal with food even after the troph has metabolized away for amazing reagent efficency.
+ reagent_state = SOLID
+ color = "#DC605D"
+ overdose_threshold = 10
+
+/datum/reagent/medicine/metafactor/overdose_start(mob/living/carbon/M)
+ metabolization_rate = 2 * REAGENTS_METABOLISM
+
+/datum/reagent/medicine/metafactor/overdose_process(mob/living/carbon/M)
+ if(prob(25))
+ M.vomit()
+ ..()
+
+/datum/reagent/medicine/rhigoxane
+ name = "Rhigoxane"
+ description = "A second generation burn treatment agent exibiting a cooling effect that is especially pronounced when deployed as a spray. It's high halogen content helps extiguish fires."
+ reagent_state = LIQUID
+ color = "#B6D2F2"
+ overdose_threshold = 25
+ reagent_weight = 0.6
+
+/datum/reagent/medicine/rhigoxane/on_mob_life(mob/living/carbon/M)
+ M.adjustFireLoss(-2*REM, 0.)
+ M.adjust_bodytemperature(-20 * TEMPERATURE_DAMAGE_COEFFICIENT, BODYTEMP_NORMAL)
+ ..()
+ . = 1
+
+/datum/reagent/medicine/rhigoxane/reaction_mob(mob/living/carbon/M, method=VAPOR, reac_volume)
+ if(method != VAPOR)
+ return
+
+ M.adjust_bodytemperature(-reac_volume * TEMPERATURE_DAMAGE_COEFFICIENT * 20, 200)
+ M.adjust_fire_stacks(-reac_volume / 2)
+ if(reac_volume >= metabolization_rate)
+ M.ExtinguishMob()
+
+ ..()
+
+/datum/reagent/medicine/rhigoxane/overdose_process(mob/living/carbon/M)
+ M.adjustFireLoss(3*REM, 0.)
+ M.adjust_bodytemperature(-35 * TEMPERATURE_DAMAGE_COEFFICIENT, 50)
+ ..()
+
+/datum/reagent/medicine/thializid
+ name = "Thializid"
+ description = "A potent antidote for intravenous use with a narrow therapeutic index, it is considered an active prodrug of oxalizid."
+ reagent_state = LIQUID
+ color = "#8CDF24" // heavy saturation to make the color blend better
+ metabolization_rate = 0.75 * REAGENTS_METABOLISM
+ overdose_threshold = 6
+ var/conversion_amount
+
+/datum/reagent/medicine/thializid/on_transfer(atom/A, method=INJECT, trans_volume)
+ if(method != INJECT || !iscarbon(A))
+ return
+ var/mob/living/carbon/C = A
+ if(trans_volume >= 0.6) //prevents cheesing with ultralow doses.
+ C.adjustToxLoss(-1.5 * min(2, trans_volume) * REM, 0) //This is to promote iv pole use for that chemotherapy feel.
+ var/obj/item/organ/liver/L = C.internal_organs_slot[ORGAN_SLOT_LIVER]
+ if(L.failing || !L)
+ return
+ conversion_amount = trans_volume * (min(100 -C.getLiverLoss(), 80) / 100) //the more damaged the liver the worse we metabolize.
+ C.reagents.remove_reagent(/datum/reagent/medicine/thializid, conversion_amount)
+ C.reagents.add_reagent(/datum/reagent/medicine/oxalizid, conversion_amount)
+ ..()
+
+/datum/reagent/medicine/thializid/on_mob_life(mob/living/carbon/M)
+ M.adjustLiverLoss(0.8)
+ M.adjustToxLoss(-1*REM, 0)
+ for(var/datum/reagent/toxin/R in M.reagents.reagent_list)
+ M.reagents.remove_reagent(R.type,1)
+
+ ..()
+ . = 1
+
+/datum/reagent/medicine/thializid/overdose_process(mob/living/carbon/M)
+ M.adjustLiverLoss(1.5)
+ M.adjust_disgust(3)
+ M.reagents.add_reagent(/datum/reagent/medicine/oxalizid, 0.225 * REM)
+ ..()
+ . = 1
+
+/datum/reagent/medicine/oxalizid
+ name = "Oxalizid"
+ description = "The active metabolite of thializid. Causes muscle weakness on overdose"
+ reagent_state = LIQUID
+ color = "#DFD54E"
+ metabolization_rate = 0.25 * REAGENTS_METABOLISM
+ overdose_threshold = 25
+ var/datum/brain_trauma/mild/muscle_weakness/U
+
+/datum/reagent/medicine/oxalizid/on_mob_life(mob/living/carbon/M)
+ M.adjustLiverLoss(0.1)
+ M.adjustToxLoss(-1*REM, 0)
+ for(var/datum/reagent/toxin/R in M.reagents.reagent_list)
+ M.reagents.remove_reagent(R.type,1)
+ ..()
+ . = 1
+
+/datum/reagent/medicine/oxalizid/overdose_start(mob/living/carbon/M)
+ U = new()
+ M.gain_trauma(U, TRAUMA_RESILIENCE_ABSOLUTE)
+ ..()
+
+/datum/reagent/medicine/oxalizid/on_mob_delete(mob/living/carbon/M)
+ if(U)
+ QDEL_NULL(U)
+ return ..()
+
+/datum/reagent/medicine/oxalizid/overdose_process(mob/living/carbon/M)
+ M.adjustLiverLoss(1.5)
+ M.adjust_disgust(3)
+ ..()
+ . = 1
#undef PERF_BASE_DAMAGE
diff --git a/code/modules/reagents/chemistry/reagents/other_reagents.dm b/code/modules/reagents/chemistry/reagents/other_reagents.dm
index 28a8f28d390..1f2263764c1 100644
--- a/code/modules/reagents/chemistry/reagents/other_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/other_reagents.dm
@@ -184,6 +184,7 @@
glass_icon_state = "glass_clear"
glass_name = "glass of holy water"
glass_desc = "A glass of holy water."
+ self_consuming = TRUE //divine intervention won't be limited by the lack of a liver
/datum/reagent/water/holywater/on_mob_metabolize(mob/living/L)
..()
diff --git a/code/modules/reagents/chemistry/reagents/pyrotechnic_reagents.dm b/code/modules/reagents/chemistry/reagents/pyrotechnic_reagents.dm
index f16bfec6faa..aa97a629aea 100644
--- a/code/modules/reagents/chemistry/reagents/pyrotechnic_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/pyrotechnic_reagents.dm
@@ -132,6 +132,7 @@
reagent_state = LIQUID
color = "#FA00AF"
taste_description = "burning"
+ self_consuming = TRUE
/datum/reagent/phlogiston/reaction_mob(mob/living/M, method=TOUCH, reac_volume)
M.adjust_fire_stacks(1)
@@ -153,6 +154,7 @@
reagent_state = LIQUID
color = "#FA00AF"
taste_description = "burning"
+ self_consuming = TRUE
/datum/reagent/napalm/on_mob_life(mob/living/carbon/M)
M.adjust_fire_stacks(1)
@@ -169,6 +171,7 @@
color = "#0000DC"
metabolization_rate = 0.5 * REAGENTS_METABOLISM
taste_description = "bitterness"
+ self_consuming = TRUE
/datum/reagent/cryostylane/on_mob_life(mob/living/carbon/M) //TODO: code freezing into an ice cube
@@ -188,6 +191,7 @@
color = "#64FAC8"
metabolization_rate = 0.5 * REAGENTS_METABOLISM
taste_description = "bitterness"
+ self_consuming = TRUE
/datum/reagent/pyrosium/on_mob_life(mob/living/carbon/M)
if(M.reagents.has_reagent(/datum/reagent/oxygen))
@@ -202,6 +206,7 @@
color = "#20324D" //RGB: 32, 50, 77
metabolization_rate = 0.5 * REAGENTS_METABOLISM
taste_description = "charged metal"
+ self_consuming = TRUE
var/shock_timer = 0
/datum/reagent/teslium/on_mob_life(mob/living/carbon/M)
diff --git a/code/modules/reagents/chemistry/reagents/toxin_reagents.dm b/code/modules/reagents/chemistry/reagents/toxin_reagents.dm
index f9bc57ff29a..a7311d77f45 100644
--- a/code/modules/reagents/chemistry/reagents/toxin_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/toxin_reagents.dm
@@ -586,7 +586,7 @@
toxpwr = 0
metabolization_rate = 0.5 * REAGENTS_METABOLISM
-/datum/reagent/toxin/amanitin/on_mob_end_metabolize(mob/living/M)
+/datum/reagent/toxin/amanitin/on_mob_delete(mob/living/M)
var/toxdamage = current_cycle*3*REM
M.log_message("has taken [toxdamage] toxin damage from amanitin toxin", LOG_ATTACK)
M.adjustToxLoss(toxdamage)
diff --git a/code/modules/reagents/chemistry/recipes/medicine.dm b/code/modules/reagents/chemistry/recipes/medicine.dm
index 5465e9e252c..20e57a206b9 100644
--- a/code/modules/reagents/chemistry/recipes/medicine.dm
+++ b/code/modules/reagents/chemistry/recipes/medicine.dm
@@ -209,24 +209,6 @@
results = list(/datum/reagent/medicine/haloperidol = 5)
required_reagents = list(/datum/reagent/chlorine = 1, /datum/reagent/fluorine = 1, /datum/reagent/aluminium = 1, /datum/reagent/medicine/potass_iodide = 1, /datum/reagent/oil = 1)
-/datum/chemical_reaction/bicaridine
- name = "Bicaridine"
- id = /datum/reagent/medicine/bicaridine
- results = list(/datum/reagent/medicine/bicaridine = 3)
- required_reagents = list(/datum/reagent/carbon = 1, /datum/reagent/oxygen = 1, /datum/reagent/consumable/sugar = 1)
-
-/datum/chemical_reaction/kelotane
- name = "Kelotane"
- id = /datum/reagent/medicine/kelotane
- results = list(/datum/reagent/medicine/kelotane = 2)
- required_reagents = list(/datum/reagent/carbon = 1, /datum/reagent/silicon = 1)
-
-/datum/chemical_reaction/antitoxin
- name = "Antitoxin"
- id = /datum/reagent/medicine/antitoxin
- results = list(/datum/reagent/medicine/antitoxin = 3)
- required_reagents = list(/datum/reagent/nitrogen = 1, /datum/reagent/silicon = 1, /datum/reagent/potassium = 1)
-
/datum/chemical_reaction/tricordrazine
name = "Tricordrazine"
id = /datum/reagent/medicine/tricordrazine
@@ -264,3 +246,24 @@
id = /datum/reagent/medicine/psicodine
results = list(/datum/reagent/medicine/psicodine = 5)
required_reagents = list( /datum/reagent/medicine/mannitol = 2, /datum/reagent/water = 2, /datum/reagent/impedrezene = 1)
+
+/datum/chemical_reaction/rhigoxane
+ name = "Rhigoxane"
+ id = /datum/reagent/medicine/rhigoxane
+ results = list(/datum/reagent/medicine/rhigoxane/ = 5)
+ required_reagents = list(/datum/reagent/cryostylane = 3, /datum/reagent/bromine = 1, /datum/reagent/lye = 1)
+ required_temp = 47
+ is_cold_recipe = TRUE
+
+/datum/chemical_reaction/trophazole
+ name = "Trophazole"
+ id = /datum/reagent/medicine/trophazole
+ results = list(/datum/reagent/medicine/trophazole = 4)
+ required_reagents = list(/datum/reagent/copper = 1, /datum/reagent/acetone = 2, /datum/reagent/phosphorus = 1)
+
+/datum/chemical_reaction/thializid
+ name = "Thializid"
+ id = /datum/reagent/medicine/thializid
+ results = list(/datum/reagent/medicine/thializid = 5)
+ required_reagents = list(/datum/reagent/sulfur = 1, /datum/reagent/fluorine = 1, /datum/reagent/toxin = 1, /datum/reagent/nitrous_oxide = 2)
+
diff --git a/code/modules/reagents/reagent_containers/borghydro.dm b/code/modules/reagents/reagent_containers/borghydro.dm
index b166a3c6e8b..9d18293e9f5 100644
--- a/code/modules/reagents/reagent_containers/borghydro.dm
+++ b/code/modules/reagents/reagent_containers/borghydro.dm
@@ -98,17 +98,15 @@ Borg Hypospray
/obj/item/reagent_containers/borghypo/attack(mob/living/carbon/M, mob/user)
var/datum/reagents/R = reagent_list[mode]
if(!R.total_volume)
- to_chat(user, "The injector is empty.")
+ to_chat(user, "The injector is empty!")
return
if(!istype(M))
return
if(R.total_volume && M.can_inject(user, 1, user.zone_selected,bypass_protection))
to_chat(M, "You feel a tiny prick!")
to_chat(user, "You inject [M] with the injector.")
- var/fraction = min(amount_per_transfer_from_this/R.total_volume, 1)
- R.reaction(M, INJECT, fraction)
if(M.reagents)
- var/trans = R.trans_to(M, amount_per_transfer_from_this, transfered_by = user)
+ var/trans = R.trans_to(M, amount_per_transfer_from_this, transfered_by = user, method = INJECT)
to_chat(user, "[trans] unit\s injected. [R.total_volume] unit\s remaining.")
var/list/injected = list()
diff --git a/code/modules/reagents/reagent_containers/bottle.dm b/code/modules/reagents/reagent_containers/bottle.dm
index 2605a0058c9..e59f0e9a8c2 100644
--- a/code/modules/reagents/reagent_containers/bottle.dm
+++ b/code/modules/reagents/reagent_containers/bottle.dm
@@ -143,7 +143,7 @@
/obj/item/reagent_containers/glass/bottle/traitor/Initialize()
. = ..()
extra_reagent = pick(/datum/reagent/toxin/polonium, /datum/reagent/toxin/histamine, /datum/reagent/toxin/formaldehyde, /datum/reagent/toxin/venom, /datum/reagent/toxin/fentanyl, /datum/reagent/toxin/cyanide)
- reagents.add_reagent("[extra_reagent]", 3)
+ reagents.add_reagent(extra_reagent, 3)
/obj/item/reagent_containers/glass/bottle/polonium
name = "polonium bottle"
diff --git a/code/modules/reagents/reagent_containers/chem_pack.dm b/code/modules/reagents/reagent_containers/chem_pack.dm
new file mode 100644
index 00000000000..e8a4c84317b
--- /dev/null
+++ b/code/modules/reagents/reagent_containers/chem_pack.dm
@@ -0,0 +1,51 @@
+/obj/item/reagent_containers/chem_pack
+ name = "intravenous medicine bag"
+ desc = "A plastic pressure bag, or 'chem pack', for IV administration of drugs. It is fitted with a thermosealing strip."
+ icon = 'icons/obj/bloodpack.dmi'
+ icon_state = "chempack"
+ volume = 100
+ reagent_flags = OPENCONTAINER
+ spillable = TRUE
+ obj_flags = UNIQUE_RENAME
+ resistance_flags = ACID_PROOF
+ var/sealed = FALSE
+
+/obj/item/reagent_containers/chem_pack/on_reagent_change(changetype)
+ update_icon()
+
+/obj/item/reagent_containers/chem_pack/update_icon()
+ cut_overlays()
+
+ var/v = min(round(reagents.total_volume / volume * 10), 10)
+ if(v > 0)
+ var/mutable_appearance/filling = mutable_appearance('icons/obj/reagentfillings.dmi', "chempack1")
+ filling.icon_state = "chempack[v]"
+ filling.color = mix_color_from_reagents(reagents.reagent_list)
+ add_overlay(filling)
+
+/obj/item/reagent_containers/chem_pack/AltClick(mob/living/user)
+ if(user.canUseTopic(src, BE_CLOSE, NO_DEXTERY) && !sealed)
+ if(iscarbon(user) && (HAS_TRAIT(user, TRAIT_CLUMSY) && prob(50)))
+ to_chat(user, "Uh... whoops! You accidentally spill the content of the bag onto yourself.")
+ SplashReagents(user)
+ return
+
+ reagents.flags = NONE
+ reagent_flags = DRAWABLE | INJECTABLE //To allow for sabotage or ghetto use.
+ reagents.flags = reagent_flags
+ spillable = FALSE
+ sealed = TRUE
+ to_chat(user, "You seal the bag.")
+
+/obj/item/reagent_containers/chem_pack/examine()
+ . = ..()
+ if(sealed)
+ . += "The bag is sealed shut."
+ else
+ . += "Alt-click to seal it."
+
+
+obj/item/reagent_containers/chem_pack/attack_self(mob/user)
+ if(sealed)
+ return
+ ..()
\ No newline at end of file
diff --git a/code/modules/reagents/reagent_containers/dropper.dm b/code/modules/reagents/reagent_containers/dropper.dm
index cfbb387d89d..1df14015a97 100644
--- a/code/modules/reagents/reagent_containers/dropper.dm
+++ b/code/modules/reagents/reagent_containers/dropper.dm
@@ -37,8 +37,7 @@
if(!safe_thing.reagents)
safe_thing.create_reagents(100)
- reagents.reaction(safe_thing, TOUCH, fraction)
- trans = reagents.trans_to(safe_thing, amount_per_transfer_from_this, transfered_by = user)
+ trans = reagents.trans_to(safe_thing, amount_per_transfer_from_this, transfered_by = user, method = TOUCH)
target.visible_message("[user] tries to squirt something into [target]'s eyes, but fails!", \
"[user] tries to squirt something into [target]'s eyes, but fails!")
@@ -69,7 +68,7 @@
else
if(!target.is_drawable(user, FALSE)) //No drawing from mobs here
- to_chat(user, "You cannot directly remove reagents from [target].")
+ to_chat(user, "You cannot directly remove reagents from [target]!")
return
if(!target.reagents.total_volume)
diff --git a/code/modules/reagents/reagent_containers/glass.dm b/code/modules/reagents/reagent_containers/glass.dm
index efdfd7f3acf..a73ef998e7f 100755
--- a/code/modules/reagents/reagent_containers/glass.dm
+++ b/code/modules/reagents/reagent_containers/glass.dm
@@ -47,9 +47,7 @@
log_combat(user, M, "fed", reagents.log_list())
else
to_chat(user, "You swallow a gulp of [src].")
- var/fraction = min(5/reagents.total_volume, 1)
- reagents.reaction(M, INGEST, fraction)
- addtimer(CALLBACK(reagents, /datum/reagents.proc/trans_to, M, 5), 5)
+ addtimer(CALLBACK(reagents, /datum/reagents.proc/trans_to, M, 5, TRUE, TRUE, FALSE, user, FALSE, INGEST), 5)
playsound(M.loc,'sound/items/drink.ogg', rand(10,50), 1)
/obj/item/reagent_containers/glass/afterattack(obj/target, mob/user, proximity)
@@ -369,9 +367,9 @@
if(istype(I,/obj/item/pestle))
if(grinded)
if(user.getStaminaLoss() > 50)
- to_chat(user, "You are too tired to work!")
+ to_chat(user, "You are too tired to work!")
return
- to_chat(user, "You start grinding...")
+ to_chat(user, "You start grinding...")
if((do_after(user, 25, target = src)) && grinded)
user.adjustStaminaLoss(40)
if(grinded.reagents) //food and pills
@@ -379,28 +377,28 @@
if(grinded.juice_results) //prioritize juicing
grinded.on_juice()
reagents.add_reagent_list(grinded.juice_results)
- to_chat(user, "You juice [grinded] into a fine liquid.")
+ to_chat(user, "You juice [grinded] into a fine liquid.")
QDEL_NULL(grinded)
return
grinded.on_grind()
reagents.add_reagent_list(grinded.grind_results)
- to_chat(user, "You break [grinded] into powder.")
+ to_chat(user, "You break [grinded] into powder.")
QDEL_NULL(grinded)
return
return
else
- to_chat(user, "There is nothing to grind!")
+ to_chat(user, "There is nothing to grind!")
return
if(grinded)
- to_chat(user, "There is something inside already!")
+ to_chat(user, "There is something inside already!")
return
if(I.juice_results || I.grind_results)
I.forceMove(src)
grinded = I
return
- to_chat(user, "You can't grind this!")
+ to_chat(user, "You can't grind this!")
/obj/item/reagent_containers/glass/saline
name = "saline canister"
volume = 5000
- list_reagents = list(/datum/reagent/medicine/salglu_solution = 5000)
\ No newline at end of file
+ list_reagents = list(/datum/reagent/medicine/salglu_solution = 5000)
diff --git a/code/modules/reagents/reagent_containers/hypospray.dm b/code/modules/reagents/reagent_containers/hypospray.dm
index f6aa51c9e25..861bee656ed 100644
--- a/code/modules/reagents/reagent_containers/hypospray.dm
+++ b/code/modules/reagents/reagent_containers/hypospray.dm
@@ -151,7 +151,7 @@
icon_state = "stimpen"
volume = 60
amount_per_transfer_from_this = 30
- list_reagents = list(/datum/reagent/medicine/atropine = 10, /datum/reagent/medicine/epinephrine = 10, /datum/reagent/medicine/salbutamol = 20, /datum/reagent/medicine/spaceacillin = 20)
+ list_reagents = list(/datum/reagent/medicine/atropine = 10, /datum/reagent/medicine/epinephrine = 10, /datum/reagent/medicine/omnizine = 20, /datum/reagent/medicine/perfluorodecalin = 15, /datum/reagent/medicine/spaceacillin = 20)
/obj/item/reagent_containers/hypospray/medipen/survival
name = "survival medipen"
diff --git a/code/modules/reagents/reagent_containers/medspray.dm b/code/modules/reagents/reagent_containers/medigel.dm
similarity index 56%
rename from code/modules/reagents/reagent_containers/medspray.dm
rename to code/modules/reagents/reagent_containers/medigel.dm
index 9335b88af77..4a5f45f6006 100644
--- a/code/modules/reagents/reagent_containers/medspray.dm
+++ b/code/modules/reagents/reagent_containers/medigel.dm
@@ -1,8 +1,8 @@
-/obj/item/reagent_containers/medspray
- name = "medical spray"
- desc = "A medical spray bottle, designed for precision application, with an unscrewable cap."
+/obj/item/reagent_containers/medigel
+ name = "medical gel"
+ desc = "A medical gel applicator bottle, designed for precision application, with an unscrewable cap."
icon = 'icons/obj/chemical.dmi'
- icon_state = "medspray"
+ icon_state = "medigel"
item_state = "spraycan"
lefthand_file = 'icons/mob/inhands/equipment/hydroponics_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/hydroponics_righthand.dmi'
@@ -18,21 +18,21 @@
volume = 60
var/can_fill_from_container = TRUE
var/apply_type = PATCH
- var/apply_method = "spray"
+ var/apply_method = "spray" //the thick gel is sprayed and then dries into patch like film.
var/self_delay = 30
var/squirt_mode = 0
var/squirt_amount = 5
custom_price = 40
-/obj/item/reagent_containers/medspray/attack_self(mob/user)
+/obj/item/reagent_containers/medigel/attack_self(mob/user)
squirt_mode = !squirt_mode
if(squirt_mode)
amount_per_transfer_from_this = squirt_amount
else
amount_per_transfer_from_this = initial(amount_per_transfer_from_this)
- to_chat(user, "You will now apply the medspray's contents in [squirt_mode ? "short bursts":"extended sprays"]. You'll now use [amount_per_transfer_from_this] units per use.")
+ to_chat(user, "You will now apply the medigel's contents in [squirt_mode ? "short bursts":"extended sprays"]. You'll now use [amount_per_transfer_from_this] units per use.")
-/obj/item/reagent_containers/medspray/attack(mob/M, mob/user, def_zone)
+/obj/item/reagent_containers/medigel/attack(mob/M, mob/user, def_zone)
if(!reagents || !reagents.total_volume)
to_chat(user, "[src] is empty!")
return
@@ -62,32 +62,30 @@
else
log_combat(user, M, "applied", src, reagents.log_list())
- playsound(src, 'sound/effects/spray2.ogg', 50, 1, -6)
- var/fraction = min(amount_per_transfer_from_this/reagents.total_volume, 1)
- reagents.reaction(M, apply_type, fraction)
- reagents.trans_to(M, amount_per_transfer_from_this, transfered_by = user)
+ playsound(src, 'sound/effects/spray.ogg', 30, 1, -6)
+ reagents.trans_to(M, amount_per_transfer_from_this, transfered_by = user, method = apply_type)
return
-/obj/item/reagent_containers/medspray/styptic
- name = "medical spray (styptic powder)"
- desc = "A medical spray bottle, designed for precision application, with an unscrewable cap. This one contains styptic powder, for treating cuts and bruises."
- icon_state = "brutespray"
+/obj/item/reagent_containers/medigel/styptic
+ name = "medical gel (styptic powder)"
+ desc = "A medical gel applicator bottle, designed for precision application, with an unscrewable cap. This one contains styptic powder, for treating cuts and bruises."
+ icon_state = "brutegel"
list_reagents = list(/datum/reagent/medicine/styptic_powder = 60)
-/obj/item/reagent_containers/medspray/silver_sulf
- name = "medical spray (silver sulfadiazine)"
- desc = "A medical spray bottle, designed for precision application, with an unscrewable cap. This one contains silver sulfadiazine, useful for treating burns."
- icon_state = "burnspray"
+/obj/item/reagent_containers/medigel/silver_sulf
+ name = "medical gel (silver sulfadiazine)"
+ desc = "A medical gel applicator bottle, designed for precision application, with an unscrewable cap. This one contains silver sulfadiazine, useful for treating burns."
+ icon_state = "burngel"
list_reagents = list(/datum/reagent/medicine/silver_sulfadiazine = 60)
-/obj/item/reagent_containers/medspray/synthflesh
- name = "medical spray (synthflesh)"
- desc = "A medical spray bottle, designed for precision application, with an unscrewable cap. This one contains synthflesh, an apex brute and burn healing agent."
- icon_state = "synthspray"
+/obj/item/reagent_containers/medigel/synthflesh
+ name = "medical gel (synthflesh)"
+ desc = "A medical gel applicator bottle, designed for precision application, with an unscrewable cap. This one contains synthflesh, an apex brute and burn healing agent."
+ icon_state = "synthgel"
list_reagents = list(/datum/reagent/medicine/synthflesh = 60)
custom_price = 80
-/obj/item/reagent_containers/medspray/sterilizine
- name = "sterilizer spray"
- desc = "Spray bottle loaded with non-toxic sterilizer. Useful in preparation for surgery."
+/obj/item/reagent_containers/medigel/sterilizine
+ name = "sterilizer gel"
+ desc = "gel bottle loaded with non-toxic sterilizer. Useful in preparation for surgery."
list_reagents = list(/datum/reagent/space_cleaner/sterilizine = 60)
diff --git a/code/modules/reagents/reagent_containers/pill.dm b/code/modules/reagents/reagent_containers/pill.dm
index 56229fbaa82..28bb1318e72 100644
--- a/code/modules/reagents/reagent_containers/pill.dm
+++ b/code/modules/reagents/reagent_containers/pill.dm
@@ -52,8 +52,7 @@
to_chat(M, "[makes_me_think]")
if(reagents.total_volume)
- reagents.reaction(M, apply_type)
- reagents.trans_to(M, reagents.total_volume, transfered_by = user)
+ reagents.trans_to(M, reagents.total_volume, transfered_by = user, method = apply_type)
qdel(src)
return TRUE
diff --git a/code/modules/reagents/reagent_containers/spray.dm b/code/modules/reagents/reagent_containers/spray.dm
index a1ae4494eb3..376c0ad036a 100644
--- a/code/modules/reagents/reagent_containers/spray.dm
+++ b/code/modules/reagents/reagent_containers/spray.dm
@@ -2,7 +2,7 @@
name = "spray bottle"
desc = "A spray bottle, with an unscrewable top."
icon = 'icons/obj/janitor.dmi'
- icon_state = "cleaner"
+ icon_state = "sprayer_large"
item_state = "cleaner"
lefthand_file = 'icons/mob/inhands/equipment/custodial_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/custodial_righthand.dmi'
@@ -160,6 +160,7 @@
/obj/item/reagent_containers/spray/cleaner
name = "space cleaner"
desc = "BLAM!-brand non-foaming space cleaner!"
+ icon_state = "cleaner"
volume = 100
list_reagents = list(/datum/reagent/space_cleaner = 100)
amount_per_transfer_from_this = 2
@@ -349,3 +350,51 @@
righthand_file = 'icons/mob/inhands/equipment/hydroponics_righthand.dmi'
volume = 100
list_reagents = list(/datum/reagent/toxin/plantbgone = 100)
+
+/obj/item/reagent_containers/spray/syndicate
+ name = "suspicious spray bottle"
+ desc = "A spray bottle, with a high performance plastic nozzle. The color scheme makes you feel slightly uneasy."
+ icon = 'icons/obj/chemical.dmi'
+ icon_state = "sprayer_sus_8"
+ item_state = "sprayer_sus"
+ lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi'
+ spray_range = 4
+ stream_range = 2
+ volume = 100
+ custom_premium_price = 200
+
+/obj/item/reagent_containers/spray/syndicate/Initialize()
+ . = ..()
+ icon_state = pick("sprayer_sus_1", "sprayer_sus_2", "sprayer_sus_3", "sprayer_sus_4", "sprayer_sus_5","sprayer_sus_6", "sprayer_sus_7", "sprayer_sus_8")
+
+/obj/item/reagent_containers/spray/medical
+ name = "medical spray bottle"
+ icon = 'icons/obj/chemical.dmi'
+ icon_state = "sprayer_med_red"
+ item_state = "sprayer_med_red"
+ lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi'
+ volume = 100
+ unique_reskin = list("Red" = "sprayer_med_red",
+ "Yellow" = "sprayer_med_yellow",
+ "Blue" = "sprayer_med_blue")
+
+/obj/item/reagent_containers/spray/medical/AltClick(mob/user)
+ if(unique_reskin && !current_skin && user.canUseTopic(src, BE_CLOSE, NO_DEXTERY))
+ reskin_obj(user)
+
+/obj/item/reagent_containers/spray/medical/reskin_obj(mob/M)
+ ..()
+ switch(icon_state)
+ if("sprayer_med_red")
+ item_state = "sprayer_med_red"
+ if("sprayer_med_yellow")
+ item_state = "sprayer_med_yellow"
+ if("sprayer_med_blue")
+ item_state = "sprayer_med_blue"
+ M.update_inv_hands()
+
+
+
+
diff --git a/code/modules/reagents/reagent_containers/syringes.dm b/code/modules/reagents/reagent_containers/syringes.dm
index c099ae291d4..4fe8ed1b365 100644
--- a/code/modules/reagents/reagent_containers/syringes.dm
+++ b/code/modules/reagents/reagent_containers/syringes.dm
@@ -114,7 +114,7 @@
log_combat(user, target, "attempted to inject", src, addition="which had [contained]")
if(!reagents.total_volume)
- to_chat(user, "[src] is empty.")
+ to_chat(user, "[src] is empty!")
return
if(!L && !target.is_injectable(user)) //only checks on non-living mobs, due to how can_inject() handles
@@ -144,9 +144,7 @@
log_combat(user, L, "injected", src, addition="which had [contained]")
else
L.log_message("injected themselves ([contained]) with [src.name]", LOG_ATTACK, color="orange")
- var/fraction = min(amount_per_transfer_from_this/reagents.total_volume, 1)
- reagents.reaction(L, INJECT, fraction)
- reagents.trans_to(target, amount_per_transfer_from_this, transfered_by = user)
+ reagents.trans_to(target, amount_per_transfer_from_this, transfered_by = user, method = INJECT)
to_chat(user, "You inject [amount_per_transfer_from_this] units of the solution. The syringe now contains [reagents.total_volume] units.")
if (reagents.total_volume <= 0 && mode==SYRINGE_INJECT)
mode = SYRINGE_DRAW
diff --git a/code/modules/recycling/conveyor2.dm b/code/modules/recycling/conveyor2.dm
index 8b02c160de1..53e38db8ecd 100644
--- a/code/modules/recycling/conveyor2.dm
+++ b/code/modules/recycling/conveyor2.dm
@@ -352,7 +352,7 @@ GLOBAL_LIST_EMPTY(conveyors_by_id)
return
var/cdir = get_dir(A, user)
if(A == user.loc)
- to_chat(user, "You cannot place a conveyor belt under yourself.")
+ to_chat(user, "You cannot place a conveyor belt under yourself!")
return
var/obj/machinery/conveyor/C = new/obj/machinery/conveyor(A, cdir, id)
transfer_fingerprints_to(C)
diff --git a/code/modules/research/designs/autolathe_designs.dm b/code/modules/research/designs/autolathe_designs.dm
index 179cae3de03..8b431d4fc1a 100644
--- a/code/modules/research/designs/autolathe_designs.dm
+++ b/code/modules/research/designs/autolathe_designs.dm
@@ -10,7 +10,7 @@
build_path = /obj/item/reagent_containers/glass/bucket
category = list("initial","Tools","Tool Designs")
departmental_flags = DEPARTMENTAL_FLAG_SERVICE
-
+
/datum/design/mop
name = "Mop"
id = "mop"
@@ -139,7 +139,7 @@
materials = list(MAT_METAL = 10, MAT_GLASS = 5)
build_path = /obj/item/stack/cable_coil
category = list("initial","Tools","Tool Designs")
- maxstack = 15
+ maxstack = MAXCOIL
departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING | DEPARTMENTAL_FLAG_SCIENCE
/datum/design/toolbox
diff --git a/code/modules/research/designs/mecha_designs.dm b/code/modules/research/designs/mecha_designs.dm
index 892d32ddd08..09264d95530 100644
--- a/code/modules/research/designs/mecha_designs.dm
+++ b/code/modules/research/designs/mecha_designs.dm
@@ -147,6 +147,17 @@
construction_time = 100
category = list("Exosuit Equipment")
+/datum/design/mech_scattershot_ammo
+ name = "LBX AC 10 Scattershot Ammunition"
+ desc = "Ammunition for the LBX AC 10 exosuit weapon."
+ id = "mech_scattershot_ammo"
+ build_type = PROTOLATHE | MECHFAB
+ build_path = /obj/item/mecha_ammo/scattershot
+ materials = list(MAT_METAL=6000)
+ construction_time = 20
+ category = list("Exosuit Ammunition", "Ammo")
+ departmental_flags = DEPARTMENTAL_FLAG_SECURITY
+
/datum/design/mech_carbine
name = "Exosuit Weapon (FNX-99 \"Hades\" Carbine)"
desc = "Allows for the construction of FNX-99 \"Hades\" Carbine."
@@ -157,6 +168,17 @@
construction_time = 100
category = list("Exosuit Equipment")
+/datum/design/mech_carbine_ammo
+ name = "FNX-99 Carbine Ammunition"
+ desc = "Ammunition for the FNX-99 \"Hades\" Carbine."
+ id = "mech_carbine_ammo"
+ build_type = PROTOLATHE | MECHFAB
+ build_path = /obj/item/mecha_ammo/incendiary
+ materials = list(MAT_METAL=6000)
+ construction_time = 20
+ category = list("Exosuit Ammunition", "Ammo")
+ departmental_flags = DEPARTMENTAL_FLAG_SECURITY
+
/datum/design/mech_ion
name = "Exosuit Weapon (MKIV Ion Heavy Cannon)"
desc = "Allows for the construction of MKIV Ion Heavy Cannon."
@@ -217,16 +239,38 @@
construction_time = 100
category = list("Exosuit Equipment")
+/datum/design/mech_grenade_launcher_ammo
+ name = "SGL-6 Grenade Launcher Ammunition"
+ desc = "Ammunition for the SGL-6 Grenade Launcher."
+ id = "mech_grenade_launcher_ammo"
+ build_type = PROTOLATHE | MECHFAB
+ build_path = /obj/item/mecha_ammo/flashbang
+ materials = list(MAT_METAL=4000,MAT_GOLD=500,MAT_SILVER=500)
+ construction_time = 20
+ category = list("Exosuit Ammunition", "Ammo")
+ departmental_flags = DEPARTMENTAL_FLAG_SECURITY
+
/datum/design/mech_missile_rack
- name = "Exosuit Weapon (SRM-8 Missile Rack)"
- desc = "Allows for the construction of an SRM-8 Missile Rack."
+ name = "Exosuit Weapon (BRM-6 Missile Rack)"
+ desc = "Allows for the construction of an BRM-6 Breaching Missile Rack."
id = "mech_missile_rack"
build_type = MECHFAB
- build_path = /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack
+ build_path = /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/breaching
materials = list(MAT_METAL=22000,MAT_GOLD=6000,MAT_SILVER=8000)
construction_time = 100
category = list("Exosuit Equipment")
+/datum/design/mech_missile_rack_ammo
+ name = "SRM-8 Missile Rack Ammunition"
+ desc = "Ammunition for the SRM-8 Missile Rack."
+ id = "mech_missile_rack_ammo"
+ build_type = PROTOLATHE | MECHFAB
+ build_path = /obj/item/mecha_ammo/missiles_br
+ materials = list(MAT_METAL=8000,MAT_GOLD=500,MAT_SILVER=500)
+ construction_time = 20
+ category = list("Exosuit Ammunition", "Ammo")
+ departmental_flags = DEPARTMENTAL_FLAG_SECURITY
+
/datum/design/clusterbang_launcher
name = "Exosuit Module (SOB-3 Clusterbang Launcher)"
desc = "A weapon that violates the Geneva Convention at 3 rounds per minute"
@@ -237,6 +281,17 @@
construction_time = 100
category = list("Exosuit Equipment")
+/datum/design/clusterbang_launcher_ammo
+ name = "SOB-3 Clusterbang Launcher Ammunition"
+ desc = "Ammunition for the SOB-3 Clusterbang Launcher"
+ id = "clusterbang_launcher_ammo"
+ build_type = PROTOLATHE | MECHFAB
+ build_path = /obj/item/mecha_ammo/clusterbang
+ materials = list(MAT_METAL=6000,MAT_GOLD=1500,MAT_URANIUM=1500)
+ construction_time = 20
+ category = list("Exosuit Ammunition", "Ammo")
+ departmental_flags = DEPARTMENTAL_FLAG_SECURITY
+
/datum/design/mech_wormhole_gen
name = "Exosuit Module (Localized Wormhole Generator)"
desc = "An exosuit module that allows generating of small quasi-stable wormholes."
@@ -357,6 +412,17 @@
construction_time = 100
category = list("Exosuit Equipment")
+/datum/design/mech_lmg_ammo
+ name = "Ultra AC 2 Ammunition"
+ desc = "Ammunition for the Ultra AC 2 LMG"
+ id = "mech_lmg_ammo"
+ build_type = PROTOLATHE | MECHFAB
+ build_path = /obj/item/mecha_ammo/lmg
+ materials = list(MAT_METAL=4000)
+ construction_time = 20
+ category = list("Exosuit Ammunition", "Ammo")
+ departmental_flags = DEPARTMENTAL_FLAG_SECURITY
+
/datum/design/mech_sleeper
name = "Exosuit Medical Equipment (Mounted Sleeper)"
desc = "Equipment for medical exosuits. A mounted sleeper that stabilizes patients and can inject reagents in the exosuit's reserves."
diff --git a/code/modules/research/designs/medical_designs.dm b/code/modules/research/designs/medical_designs.dm
index edacfd13735..ac479486260 100644
--- a/code/modules/research/designs/medical_designs.dm
+++ b/code/modules/research/designs/medical_designs.dm
@@ -182,11 +182,11 @@
category = list("Medical Designs")
departmental_flags = DEPARTMENTAL_FLAG_MEDICAL
-/datum/design/medspray
- name = "Medical Spray"
- desc = "A medical spray bottle, designed for precision application, with an unscrewable cap."
- id = "medspray"
- build_path = /obj/item/reagent_containers/medspray
+/datum/design/medigel
+ name = "Medical Gel"
+ desc = "A medical gel applicator bottle, designed for precision application, with an unscrewable cap."
+ id = "medigel"
+ build_path = /obj/item/reagent_containers/medigel
build_type = PROTOLATHE
materials = list(MAT_METAL = 2500, MAT_GLASS = 500)
category = list("Medical Designs")
@@ -231,6 +231,36 @@
category = list("Tool Designs")
departmental_flags = DEPARTMENTAL_FLAG_MEDICAL | DEPARTMENTAL_FLAG_SCIENCE
+/datum/design/medical_spray_bottle
+ name = "Medical Spray Bottle"
+ desc = "A traditional spray bottle used to generate a fine mist. Not to be confused with a medspray."
+ id = "med_spray_bottle"
+ build_type = PROTOLATHE
+ departmental_flags = DEPARTMENTAL_FLAG_MEDICAL
+ materials = list(MAT_PLASTIC = 2000)
+ build_path = /obj/item/reagent_containers/spray/medical
+ category = list("Medical Designs")
+
+/datum/design/chem_pack
+ name = "Intravenous Medicine Bag"
+ desc = "A plastic pressure bag for IV administration of drugs."
+ id = "chem_pack"
+ build_type = PROTOLATHE
+ departmental_flags = DEPARTMENTAL_FLAG_MEDICAL
+ materials = list(MAT_PLASTIC = 2000)
+ build_path = /obj/item/reagent_containers/chem_pack
+ category = list("Medical Designs")
+
+/datum/design/blood_pack
+ name = "Blood Pack"
+ desc = "Is used to contain blood used for transfusion. Must be attached to an IV drip."
+ id = "blood_pack"
+ build_type = PROTOLATHE
+ departmental_flags = DEPARTMENTAL_FLAG_MEDICAL
+ materials = list(MAT_PLASTIC = 1000)
+ build_path = /obj/item/reagent_containers/blood
+ category = list("Medical Designs")
+
/////////////////////////////////////////
//////////Cybernetic Implants////////////
/////////////////////////////////////////
@@ -548,7 +578,7 @@
name = "Experimental Dissection"
desc = "A surgical procedure which deeply analyzes the biology of a corpse, and automatically adds new findings to the research database."
id = "surgery_exp_dissection"
- surgery = /datum/surgery/advanced/experimental_dissection
+ surgery = /datum/surgery/experimental_dissection
research_icon_state = "surgery_chest"
/datum/design/surgery/lobotomy
@@ -679,3 +709,5 @@
id = "surgery_zombie"
surgery = /datum/surgery/advanced/necrotic_revival
research_icon_state = "surgery_head"
+
+
diff --git a/code/modules/research/experimentor.dm b/code/modules/research/experimentor.dm
index 2fb432cc165..9beff5ae6da 100644
--- a/code/modules/research/experimentor.dm
+++ b/code/modules/research/experimentor.dm
@@ -97,7 +97,7 @@
/obj/machinery/rnd/experimentor/examine(mob/user)
. = ..()
if(in_range(user, src) || isobserver(user))
- . += "The status display reads: Malfunction probability reduced by [badThingCoeff]%.
Cooldown interval between experiments at [resetTime*0.1] seconds."
+ . += "The status display reads: Malfunction probability reduced by [badThingCoeff]%.
Cooldown interval between experiments at [resetTime*0.1] seconds."
/obj/machinery/rnd/experimentor/proc/checkCircumstances(obj/item/O)
//snowflake check to only take "made" bombs
diff --git a/code/modules/research/nanites/nanite_chamber.dm b/code/modules/research/nanites/nanite_chamber.dm
index ff6ab831883..9066552c6ee 100644
--- a/code/modules/research/nanites/nanite_chamber.dm
+++ b/code/modules/research/nanites/nanite_chamber.dm
@@ -32,7 +32,7 @@
/obj/machinery/nanite_chamber/examine(mob/user)
. = ..()
if(in_range(user, src) || isobserver(user))
- . += "The status display reads: Scanning module has been upgraded to level [scan_level]."
+ . += "The status display reads: Scanning module has been upgraded to level [scan_level]."
/obj/machinery/nanite_chamber/proc/set_busy(status, message, working_icon)
busy = status
diff --git a/code/modules/research/nanites/nanite_remote.dm b/code/modules/research/nanites/nanite_remote.dm
index bc50814fb1d..4d255803bc5 100644
--- a/code/modules/research/nanites/nanite_remote.dm
+++ b/code/modules/research/nanites/nanite_remote.dm
@@ -58,18 +58,18 @@
if(REMOTE_MODE_OFF)
return
if(REMOTE_MODE_SELF)
- to_chat(user, "You activate [src], signaling the nanites in your bloodstream.")
+ to_chat(user, "You activate [src], signaling the nanites in your bloodstream.")
signal_mob(user, code, key_name(user))
if(REMOTE_MODE_TARGET)
if(isliving(target) && (get_dist(target, get_turf(src)) <= 7))
- to_chat(user, "You activate [src], signaling the nanites inside [target].")
+ to_chat(user, "You activate [src], signaling the nanites inside [target].")
signal_mob(target, code, key_name(user))
if(REMOTE_MODE_AOE)
- to_chat(user, "You activate [src], signaling the nanites inside every host around you.")
+ to_chat(user, "You activate [src], signaling the nanites inside every host around you.")
for(var/mob/living/L in view(user, 7))
signal_mob(L, code, key_name(user))
if(REMOTE_MODE_RELAY)
- to_chat(user, "You activate [src], signaling all connected relay nanites.")
+ to_chat(user, "You activate [src], signaling all connected relay nanites.")
signal_relay(code, relay_code, key_name(user))
/obj/item/nanite_remote/proc/signal_mob(mob/living/M, code, source)
@@ -177,18 +177,18 @@
if(REMOTE_MODE_OFF)
return
if(REMOTE_MODE_SELF)
- to_chat(user, "You activate [src], signaling the nanites in your bloodstream.")
+ to_chat(user, "You activate [src], signaling the nanites in your bloodstream.")
signal_mob(user, comm_code, comm_message)
if(REMOTE_MODE_TARGET)
if(isliving(target) && (get_dist(target, get_turf(src)) <= 7))
- to_chat(user, "You activate [src], signaling the nanites inside [target].")
+ to_chat(user, "You activate [src], signaling the nanites inside [target].")
signal_mob(target, code, comm_message, key_name(user))
if(REMOTE_MODE_AOE)
- to_chat(user, "You activate [src], signaling the nanites inside every host around you.")
+ to_chat(user, "You activate [src], signaling the nanites inside every host around you.")
for(var/mob/living/L in view(user, 7))
signal_mob(L, code, comm_message, key_name(user))
if(REMOTE_MODE_RELAY)
- to_chat(user, "You activate [src], signaling all connected relay nanites.")
+ to_chat(user, "You activate [src], signaling all connected relay nanites.")
signal_relay(code, relay_code, comm_message, key_name(user))
/obj/item/nanite_remote/comm/signal_mob(mob/living/M, code, source)
diff --git a/code/modules/research/rdconsole.dm b/code/modules/research/rdconsole.dm
index fcbef13cb67..3f6994f044f 100644
--- a/code/modules/research/rdconsole.dm
+++ b/code/modules/research/rdconsole.dm
@@ -117,22 +117,22 @@ Nothing else in the console has ID requirements.
if(istype(D, /obj/item/disk))
if(istype(D, /obj/item/disk/tech_disk))
if(t_disk)
- to_chat(user, "A technology disk is already loaded!")
+ to_chat(user, "A technology disk is already loaded!")
return
if(!user.transferItemToLoc(D, src))
- to_chat(user, "[D] is stuck to your hand!")
+ to_chat(user, "[D] is stuck to your hand!")
return
t_disk = D
else if (istype(D, /obj/item/disk/design_disk))
if(d_disk)
- to_chat(user, "A design disk is already loaded!")
+ to_chat(user, "A design disk is already loaded!")
return
if(!user.transferItemToLoc(D, src))
- to_chat(user, "[D] is stuck to your hand!")
+ to_chat(user, "[D] is stuck to your hand!")
return
d_disk = D
else
- to_chat(user, "Machine cannot accept disks in that format.")
+ to_chat(user, "Machine cannot accept disks in that format.")
return
to_chat(user, "You insert [D] into \the [src]!")
else if(!(linked_destroy && linked_destroy.busy) && !(linked_lathe && linked_lathe.busy) && !(linked_imprinter && linked_imprinter.busy))
@@ -167,7 +167,9 @@ Nothing else in the console has ID requirements.
var/obj/item/card/id/ID = I.GetID()
if(istype(ID))
logname = "User: [ID.registered_name]"
- stored_research.research_logs += "[logname] researched node id [id] with cost [json_encode(price)]."
+ var/i = stored_research.research_logs.len
+ stored_research.research_logs += null
+ stored_research.research_logs[++i] = list(TN.display_name, price["General Research"], logname, "[get_area(src)] ([src.x],[src.y],[src.z])")
return TRUE
else
say("Failed to research node: Internal database error!")
diff --git a/code/modules/research/server.dm b/code/modules/research/server.dm
index 20e05782ef4..7150b655c4c 100644
--- a/code/modules/research/server.dm
+++ b/code/modules/research/server.dm
@@ -2,13 +2,15 @@
name = "\improper R&D Server"
desc = "A computer system running a deep neural network that processes arbitrary information to produce data useable in the development of new technologies. In layman's terms, it makes research points."
icon = 'icons/obj/machines/research.dmi'
- icon_state = "server"
+ icon_state = "RD-server-on"
var/datum/techweb/stored_research
var/heat_health = 100
//Code for point mining here.
var/working = TRUE //temperature should break it.
+ var/research_disabled = FALSE
var/server_id = 0
var/base_mining_income = 2
+ var/current_temp = 0
var/heat_gen = 100
var/heating_power = 40000
var/delay = 5
@@ -19,10 +21,12 @@
/obj/machinery/rnd/server/Initialize()
. = ..()
+ name += " [num2hex(rand(1,65535), -1)]" //gives us a random four-digit hex number as part of the name. Y'know, for fluff.
SSresearch.servers |= src
stored_research = SSresearch.science_tech
var/obj/item/circuitboard/machine/B = new /obj/item/circuitboard/machine/rdserver(null)
B.apply_default_parts(src)
+ current_temp = get_env_temp()
/obj/machinery/rnd/server/Destroy()
SSresearch.servers -= src
@@ -34,11 +38,26 @@
tot_rating += SP.rating
heat_gen /= max(1, tot_rating)
+/obj/machinery/rnd/server/update_icon()
+ if (stat & EMPED || stat & NOPOWER)
+ icon_state = "RD-server-off"
+ return
+ if (research_disabled)
+ icon_state = "RD-server-halt"
+ return
+ icon_state = "RD-server-on"
+
+/obj/machinery/rnd/server/power_change()
+ . = ..()
+ refresh_working()
+ return
+
/obj/machinery/rnd/server/proc/refresh_working()
- if(stat & EMPED)
+ if(stat & EMPED || research_disabled || stat & NOPOWER)
working = FALSE
else
working = TRUE
+ update_icon()
/obj/machinery/rnd/server/emp_act()
. = ..()
@@ -52,14 +71,21 @@
stat &= ~EMPED
refresh_working()
+/obj/machinery/rnd/server/proc/toggle_disable()
+ research_disabled = !research_disabled
+ refresh_working()
+
/obj/machinery/rnd/server/proc/mine()
. = base_mining_income
var/penalty = max((get_env_temp() - temp_tolerance_high), 0) * temp_penalty_coefficient
+ current_temp = get_env_temp()
. = max(. - penalty, 0)
/obj/machinery/rnd/server/proc/get_env_temp()
- var/datum/gas_mixture/environment = loc.return_air()
- return environment.temperature
+ var/turf/L = loc
+ if(isturf(L))
+ return L.temperature
+ return 0
/obj/machinery/rnd/server/proc/produce_heat(heat_amt)
if(!(stat & (NOPOWER|BROKEN))) //Blatently stolen from space heater.
@@ -114,6 +140,7 @@
var/obj/machinery/rnd/server/temp_server
var/list/servers = list()
var/list/consoles = list()
+ req_access = list(ACCESS_RD)
var/badmin = 0
circuit = /obj/item/circuitboard/computer/rdservercontrol
@@ -122,33 +149,46 @@
return
add_fingerprint(usr)
- usr.set_machine(src)
- if(!src.allowed(usr) && !(obj_flags & EMAGGED))
- to_chat(usr, "You do not have the required access level.")
- return
-
- if(href_list["main"])
- screen = 0
+ if (href_list["toggle"])
+ if(allowed(usr) || obj_flags & EMAGGED)
+ var/obj/machinery/rnd/server/S = locate(href_list["toggle"]) in SSresearch.servers
+ S.toggle_disable()
+ else
+ to_chat(usr, "Access Denied.")
updateUsrDialog()
return
/obj/machinery/computer/rdservercontrol/ui_interact(mob/user)
. = ..()
- var/dat = ""
+ var/list/dat = list()
- switch(screen)
- if(0) //Main Menu
- dat += "Connected Servers:
"
+ dat += "Connected Servers:"
+ dat += ""
- for(var/obj/machinery/rnd/server/S in GLOB.machines)
- dat += "[S.name]
"
+ dat += "Research Log"
+ var/datum/techweb/stored_research
+ stored_research = SSresearch.science_tech
+ if(stored_research.research_logs.len)
+ dat += ""
+ dat += "| Entry | Research Name | Cost | Researcher Name | Console Location |
"
+ for(var/i=stored_research.research_logs.len, i>0, i--)
+ dat += "| [i] | "
+ for(var/j in stored_research.research_logs[i])
+ dat += "[j] | "
+ dat +="
"
+ dat += "
"
- //Mining status here
+ else
+ dat += "No history found."
- user << browse("R&D Server Control
[dat]", "window=server_control;size=575x400")
- onclose(user, "server_control")
- return
+ var/datum/browser/popup = new(user, "server_com", src.name, 900, 620)
+ popup.set_content(dat.Join())
+ popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state))
+ popup.open()
/obj/machinery/computer/rdservercontrol/attackby(obj/item/D, mob/user, params)
. = ..()
diff --git a/code/modules/research/techweb/all_nodes.dm b/code/modules/research/techweb/all_nodes.dm
index bacf1a4aed6..138ef7a2892 100644
--- a/code/modules/research/techweb/all_nodes.dm
+++ b/code/modules/research/techweb/all_nodes.dm
@@ -41,7 +41,7 @@
starting_node = TRUE
display_name = "Basic Exosuit Equipment"
description = "Various tools fit for basic mech units"
- design_ids = list("mech_drill", "mech_mscanner", "mech_extinguisher", "mech_cable_layer")
+ design_ids = list("mech_drill", "mech_mscanner", "mech_extinguisher")
/datum/techweb_node/basic_tools
id = "basic_tools"
@@ -56,7 +56,7 @@
display_name = "Biological Technology"
description = "What makes us tick." //the MC, silly!
prereq_ids = list("base")
- design_ids = list("chem_heater", "chem_master", "chem_dispenser", "pandemic", "defibrillator", "defibmount", "operating", "soda_dispenser", "beer_dispenser", "healthanalyzer", "medspray","genescanner")
+ design_ids = list("chem_heater", "chem_master", "chem_dispenser", "pandemic", "defibrillator", "defibmount", "operating", "soda_dispenser", "beer_dispenser", "healthanalyzer", "medigel","genescanner", "med_spray_bottle", "chem_pack", "blood_pack")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
export_price = 5000
@@ -83,7 +83,7 @@
id = "imp_wt_surgery"
display_name = "Improved Wound-Tending Surgery"
description = "Who would have known being more gentle with a hemostat decreases patient pain?"
- prereq_ids = list("adv_biotech")
+ prereq_ids = list("biotech")
design_ids = list("surgery_heal_brute_upgrade","surgery_heal_burn_upgrade")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 1000)
export_price = 1000
@@ -94,7 +94,7 @@
display_name = "Advanced Surgery"
description = "When simple medicine doesn't cut it."
prereq_ids = list("imp_wt_surgery")
- design_ids = list("surgery_lobotomy", "surgery_heal_brute_upgrade_femto","surgery_heal_burn_upgrade_femto","surgery_heal_combo","surgery_exp_dissection")
+ design_ids = list("surgery_lobotomy", "surgery_heal_brute_upgrade_femto","surgery_heal_burn_upgrade_femto","surgery_heal_combo", "surgery_revival")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 1500)
export_price = 4000
@@ -103,7 +103,7 @@
display_name = "Experimental Surgery"
description = "When evolution isn't fast enough."
prereq_ids = list("adv_surgery")
- design_ids = list("surgery_revival","surgery_pacify","surgery_vein_thread","surgery_muscled_veins","surgery_nerve_splice","surgery_nerve_ground","surgery_ligament_hook","surgery_ligament_reinforcement","surgery_viral_bond", "surgery_heal_combo_upgrade")
+ design_ids = list("surgery_pacify","surgery_vein_thread","surgery_muscled_veins","surgery_nerve_splice","surgery_nerve_ground","surgery_ligament_hook","surgery_ligament_reinforcement","surgery_viral_bond", "surgery_heal_combo_upgrade")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 5000)
export_price = 5000
@@ -199,16 +199,25 @@
display_name = "Miniaturized Bluespace Research"
description = "Extreme reduction in space required for bluespace engines, leading to portable bluespace technology."
prereq_ids = list("bluespace_travel", "practical_bluespace", "high_efficiency")
- design_ids = list("bluespace_matter_bin", "femto_mani", "triphasic_scanning", "bag_holding", "quantum_keycard", "wormholeprojector")
+ design_ids = list("bluespace_matter_bin", "femto_mani", "bluespacebodybag", "triphasic_scanning", "quantum_keycard", "wormholeprojector")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 10000)
export_price = 5000
+/datum/techweb_node/advanced_bluespace
+ id = "bluespace_storage"
+ display_name = "Advanced Bluespace Storage"
+ description = "With the use of bluespace we can create even more advanced storage devices than we could have ever done"
+ prereq_ids = list("micro_bluespace", "janitor")
+ design_ids = list("bag_holding")
+ research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 5000)
+ export_price = 3000
+
/datum/techweb_node/practical_bluespace
id = "practical_bluespace"
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","minerbag_holding", "bluespacebeaker", "bluespacesyringe", "bluespacebodybag", "phasic_scanning", "roastingstick", "ore_silo")
+ design_ids = list("bs_rped","minerbag_holding", "bluespacebeaker", "bluespacesyringe", "phasic_scanning", "roastingstick", "ore_silo")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 5000)
export_price = 5000
@@ -750,7 +759,7 @@
display_name = "Exosuit Weapon (LBX AC 10 \"Scattershot\")"
description = "An advanced piece of mech weaponry"
prereq_ids = list("ballistic_weapons")
- design_ids = list("mech_scattershot")
+ design_ids = list("mech_scattershot", "mech_scattershot_ammo")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
export_price = 5000
@@ -759,7 +768,7 @@
display_name = "Exosuit Weapon (FNX-99 \"Hades\" Carbine)"
description = "An advanced piece of mech weaponry"
prereq_ids = list("ballistic_weapons")
- design_ids = list("mech_carbine")
+ design_ids = list("mech_carbine", "mech_carbine_ammo")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
export_price = 5000
@@ -813,16 +822,16 @@
display_name = "Exosuit Weapon (SGL-6 Grenade Launcher)"
description = "An advanced piece of mech weaponry"
prereq_ids = list("explosive_weapons")
- design_ids = list("mech_grenade_launcher")
+ design_ids = list("mech_grenade_launcher", "mech_grenade_launcher_ammo")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
export_price = 5000
/datum/techweb_node/mech_missile_rack
id = "mech_missile_rack"
- display_name = "Exosuit Weapon (SRM-8 Missile Rack)"
+ display_name = "Exosuit Weapon (BRM-6 Missile Rack)"
description = "An advanced piece of mech weaponry"
prereq_ids = list("explosive_weapons")
- design_ids = list("mech_missile_rack")
+ design_ids = list("mech_missile_rack", "mech_missile_rack_ammo")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
export_price = 5000
@@ -831,7 +840,7 @@
display_name = "Exosuit Module (SOB-3 Clusterbang Launcher)"
description = "An advanced piece of mech weaponry"
prereq_ids = list("explosive_weapons")
- design_ids = list("clusterbang_launcher")
+ design_ids = list("clusterbang_launcher", "clusterbang_launcher_ammo")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
export_price = 5000
@@ -858,7 +867,7 @@
display_name = "Exosuit Weapon (\"Ultra AC 2\" LMG)"
description = "An advanced piece of mech weaponry"
prereq_ids = list("ballistic_weapons")
- design_ids = list("mech_lmg")
+ design_ids = list("mech_lmg", "mech_lmg_ammo")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
export_price = 5000
diff --git a/code/modules/research/xenobiology/crossbreeding/consuming.dm b/code/modules/research/xenobiology/crossbreeding/consuming.dm
index f82aaff0d66..4307ef98882 100644
--- a/code/modules/research/xenobiology/crossbreeding/consuming.dm
+++ b/code/modules/research/xenobiology/crossbreeding/consuming.dm
@@ -18,7 +18,7 @@ Consuming extracts:
/obj/item/slimecross/consuming/attackby(obj/item/O, mob/user)
if(istype(O,/obj/item/reagent_containers/food/snacks))
if(last_produced + cooldown > world.time)
- to_chat(user, "[src] is still digesting after its last meal!")
+ to_chat(user, "[src] is still digesting after its last meal!")
return
var/datum/reagent/N = O.reagents.has_reagent(/datum/reagent/consumable/nutriment)
if(N)
diff --git a/code/modules/research/xenobiology/xenobio_camera.dm b/code/modules/research/xenobiology/xenobio_camera.dm
index 80bb1b39e0b..0ad28544497 100644
--- a/code/modules/research/xenobiology/xenobio_camera.dm
+++ b/code/modules/research/xenobiology/xenobio_camera.dm
@@ -105,20 +105,20 @@
potion_action.target = src
potion_action.Grant(user)
actions += potion_action
-
+
if(hotkey_help)
hotkey_help.target = src
hotkey_help.Grant(user)
actions += hotkey_help
- RegisterSignal(user, COMSIG_XENO_SLIME_CLICK_CTRL, .proc/XenoSlimeClickCtrl)
- RegisterSignal(user, COMSIG_XENO_SLIME_CLICK_ALT, .proc/XenoSlimeClickAlt)
- RegisterSignal(user, COMSIG_XENO_SLIME_CLICK_SHIFT, .proc/XenoSlimeClickShift)
- RegisterSignal(user, COMSIG_XENO_TURF_CLICK_SHIFT, .proc/XenoTurfClickShift)
- RegisterSignal(user, COMSIG_XENO_TURF_CLICK_CTRL, .proc/XenoTurfClickCtrl)
+ RegisterSignal(user, COMSIG_XENO_SLIME_CLICK_CTRL, .proc/XenoSlimeClickCtrl)
+ RegisterSignal(user, COMSIG_XENO_SLIME_CLICK_ALT, .proc/XenoSlimeClickAlt)
+ RegisterSignal(user, COMSIG_XENO_SLIME_CLICK_SHIFT, .proc/XenoSlimeClickShift)
+ RegisterSignal(user, COMSIG_XENO_TURF_CLICK_SHIFT, .proc/XenoTurfClickShift)
+ RegisterSignal(user, COMSIG_XENO_TURF_CLICK_CTRL, .proc/XenoTurfClickCtrl)
RegisterSignal(user, COMSIG_XENO_MONKEY_CLICK_CTRL, .proc/XenoMonkeyClickCtrl)
- //Checks for recycler on every interact, prevents issues with load order on certain maps.
+ //Checks for recycler on every interact, prevents issues with load order on certain maps.
if(!connected_recycler)
for(var/obj/machinery/monkey_recycler/recycler in GLOB.monkey_recyclers)
if(get_area(recycler.loc) == get_area(loc))
@@ -126,13 +126,13 @@
connected_recycler.connected += src
/obj/machinery/computer/camera_advanced/xenobio/remove_eye_control(mob/living/user)
- UnregisterSignal(user, COMSIG_XENO_SLIME_CLICK_CTRL)
- UnregisterSignal(user, COMSIG_XENO_SLIME_CLICK_ALT)
- UnregisterSignal(user, COMSIG_XENO_SLIME_CLICK_SHIFT)
- UnregisterSignal(user, COMSIG_XENO_TURF_CLICK_SHIFT)
- UnregisterSignal(user, COMSIG_XENO_TURF_CLICK_CTRL)
- UnregisterSignal(user, COMSIG_XENO_MONKEY_CLICK_CTRL)
- ..()
+ UnregisterSignal(user, COMSIG_XENO_SLIME_CLICK_CTRL)
+ UnregisterSignal(user, COMSIG_XENO_SLIME_CLICK_ALT)
+ UnregisterSignal(user, COMSIG_XENO_SLIME_CLICK_SHIFT)
+ UnregisterSignal(user, COMSIG_XENO_TURF_CLICK_SHIFT)
+ UnregisterSignal(user, COMSIG_XENO_TURF_CLICK_CTRL)
+ UnregisterSignal(user, COMSIG_XENO_MONKEY_CLICK_CTRL)
+ ..()
/obj/machinery/computer/camera_advanced/xenobio/proc/on_contents_del(datum/source, atom/deleted)
if(current_potion == deleted)
@@ -244,8 +244,8 @@
to_chat(owner, "[X] now has [X.monkeys] monkeys stored.")
else
to_chat(owner, "[X] needs to have at least 1 monkey stored. Currently has [X.monkeys] monkeys stored.")
- else
- to_chat(owner, "Target is not near a camera. Cannot proceed.")
+ else
+ to_chat(owner, "Target is not near a camera. Cannot proceed.")
/datum/action/innate/monkey_recycle
@@ -270,7 +270,7 @@
M.visible_message("[M] vanishes as [M.p_theyre()] reclaimed for recycling!")
recycler.use_power(500)
X.monkeys += recycler.cube_production
- X.monkeys = round(X.monkeys, 0.1) //Prevents rounding errors
+ X.monkeys = round(X.monkeys, 0.1) //Prevents rounding errors
qdel(M)
to_chat(owner, "[X] now has [X.monkeys] monkeys available.")
else
@@ -465,6 +465,6 @@
M.visible_message("[M] vanishes as [p_theyre()] reclaimed for recycling!")
X.connected_recycler.use_power(500)
X.monkeys += connected_recycler.cube_production
- X.monkeys = round(X.monkeys, 0.1) //Prevents rounding errors
+ X.monkeys = round(X.monkeys, 0.1) //Prevents rounding errors
qdel(M)
to_chat(C, "[X] now has [X.monkeys] monkeys available.")
diff --git a/code/modules/research/xenobiology/xenobiology.dm b/code/modules/research/xenobiology/xenobiology.dm
index 2e85e2dd442..84082b0b5ba 100644
--- a/code/modules/research/xenobiology/xenobiology.dm
+++ b/code/modules/research/xenobiology/xenobiology.dm
@@ -46,7 +46,7 @@
//Effect when activated by a Luminescent. Separated into a minor and major effect. Returns cooldown in deciseconds.
/obj/item/slime_extract/proc/activate(mob/living/carbon/human/user, datum/species/jelly/luminescent/species, activation_type)
- to_chat(user, "Nothing happened... This slime extract cannot be activated this way.")
+ to_chat(user, "Nothing happened... This slime extract cannot be activated this way.")
return 0
//Core-crossing: Feeding adult slimes extracts to obtain a much more powerful, single extract.
@@ -616,7 +616,7 @@
/obj/item/slimepotion/afterattack(obj/item/reagent_containers/target, mob/user , proximity)
. = ..()
if (istype(target))
- to_chat(user, "You cannot transfer [src] to [target]! It appears the potion must be given directly to a slime to absorb." )
+ to_chat(user, "You cannot transfer [src] to [target]! It appears the potion must be given directly to a slime to absorb." )
return
/obj/item/slimepotion/slime/docility
diff --git a/code/modules/ruins/lavaland_ruin_code.dm b/code/modules/ruins/lavaland_ruin_code.dm
index 333801c398c..71cba60e546 100644
--- a/code/modules/ruins/lavaland_ruin_code.dm
+++ b/code/modules/ruins/lavaland_ruin_code.dm
@@ -89,9 +89,9 @@
new shell_type(get_turf(src), species, user)
qdel(src)
else
- to_chat(user, "You need at least ten sheets to finish a golem.")
+ to_chat(user, "You need at least ten sheets to finish a golem!")
else
- to_chat(user, "You can't build a golem out of this kind of material.")
+ to_chat(user, "You can't build a golem out of this kind of material!")
//made with xenobiology, the golem obeys its creator
/obj/item/golem_shell/servant
@@ -135,7 +135,7 @@
outfit = /datum/outfit/lavaland_syndicate/comms
/obj/effect/mob_spawn/human/lavaland_syndicate/comms/space
- flavour_text = "You are a syndicate agent, assigned to a small listening post station situated near your hated enemy's top secret research facility: Space Station 13. Monitor enemy activity as best you can, and try to keep a low profile. DO NOT abandon the base. Use the communication equipment to provide support to any field agents, and sow disinformation to throw Nanotrasen off your trail. Do not let the base fall into enemy hands!"
+ flavour_text = "You are a syndicate agent, assigned to a small listening post station situated near your hated enemy's top secret research facility: Space Station 13. Monitor enemy activity as best you can, and try to keep a low profile. DO NOT abandon the base. Use the communication equipment to provide support to any field agents, and sow disinformation to throw Nanotrasen off your trail. Do not let the base fall into enemy hands!"
/obj/effect/mob_spawn/human/lavaland_syndicate/comms/space/Initialize()
. = ..()
diff --git a/code/modules/shuttle/shuttle.dm b/code/modules/shuttle/shuttle.dm
index 4dc2a216d9f..02df514908e 100644
--- a/code/modules/shuttle/shuttle.dm
+++ b/code/modules/shuttle/shuttle.dm
@@ -202,7 +202,7 @@
roundstart_template = SSmapping.shuttle_templates[sid]
if(!roundstart_template)
- CRASH("Invalid path ([roundstart_template]) passed to docking port.")
+ CRASH("Invalid path ([sid]/[roundstart_template]) passed to docking port.")
if(roundstart_template)
SSshuttle.action_load(roundstart_template, src)
@@ -786,8 +786,8 @@
current_engines = max(0,current_engines + mod)
if(in_flight())
var/delta_coeff = engine_coeff / old_coeff
- modTimer(delta_coeff)
-
+ modTimer(delta_coeff)
+
/obj/docking_port/mobile/proc/count_engines()
. = 0
for(var/thing in shuttle_areas)
diff --git a/code/modules/shuttle/supply.dm b/code/modules/shuttle/supply.dm
index 528ab23df57..fd84bb12bea 100644
--- a/code/modules/shuttle/supply.dm
+++ b/code/modules/shuttle/supply.dm
@@ -78,7 +78,7 @@ GLOBAL_LIST_INIT(blacklisted_cargo_types, typecacheof(list(
sell()
/obj/docking_port/mobile/supply/proc/buy()
- var/list/miscboxes = list() //miscboxes are combo boxes that contain all small_item orders grouped
+ var/list/obj/miscboxes = list() //miscboxes are combo boxes that contain all small_item orders grouped
var/list/misc_order_num = list() //list of strings of order numbers, so that the manifest can show all orders in a box
var/list/misc_contents = list() //list of lists of items that each box will contain
if(!SSshuttle.shoppinglist.len)
diff --git a/code/modules/spells/spell.dm b/code/modules/spells/spell.dm
index 534f6a3f614..ca6034f8ca6 100644
--- a/code/modules/spells/spell.dm
+++ b/code/modules/spells/spell.dm
@@ -157,7 +157,7 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th
var/turf/T = get_turf(user)
if(is_centcom_level(T.z) && !centcom_cancast) //Certain spells are not allowed on the centcom zlevel
- to_chat(user, "You can't cast this spell here.")
+ to_chat(user, "You can't cast this spell here!")
return FALSE
if(!skipcharge)
@@ -165,7 +165,7 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th
return FALSE
if(user.stat && !stat_allowed)
- to_chat(user, "Not when you're incapacitated.")
+ to_chat(user, "Not when you're incapacitated!")
return FALSE
if(!antimagic_allowed)
@@ -174,11 +174,11 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th
if(isitem(antimagic))
to_chat(user, "[antimagic] is interfering with your magic.")
else
- to_chat(user, "Magic seems to flee from you, you can't gather enough power to cast this spell.")
+ to_chat(user, "Magic seems to flee from you, you can't gather enough power to cast this spell.")
return FALSE
if(!phase_allowed && istype(user.loc, /obj/effect/dummy))
- to_chat(user, "[name] cannot be cast unless you are completely manifested in the material plane.")
+ to_chat(user, "[name] cannot be cast unless you are completely manifested in the material plane!")
return FALSE
if(ishuman(user))
@@ -186,7 +186,7 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th
var/mob/living/carbon/human/H = user
if((invocation_type == "whisper" || invocation_type == "shout") && !H.can_speak_vocal())
- to_chat(user, "You can't get the words out!")
+ to_chat(user, "You can't get the words out!")
return FALSE
var/list/casting_clothes = typecacheof(list(/obj/item/clothing/suit/wizrobe,
@@ -198,24 +198,24 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th
if(clothes_req) //clothes check
if(!is_type_in_typecache(H.wear_suit, casting_clothes))
- to_chat(H, "I don't feel strong enough without my robe.")
+ to_chat(H, "You don't feel strong enough without your robe!")
return FALSE
if(!is_type_in_typecache(H.head, casting_clothes))
- to_chat(H, "I don't feel strong enough without my hat.")
+ to_chat(H, "You don't feel strong enough without your hat!")
return FALSE
if(cult_req) //CULT_REQ CLOTHES CHECK
if(!istype(H.wear_suit, /obj/item/clothing/suit/magusred) && !istype(H.wear_suit, /obj/item/clothing/suit/space/hardsuit/cult))
- to_chat(H, "I don't feel strong enough without my armor.")
+ to_chat(H, "You don't feel strong enough without your armor.")
return FALSE
if(!istype(H.head, /obj/item/clothing/head/magus) && !istype(H.head, /obj/item/clothing/head/helmet/space/hardsuit/cult))
- to_chat(H, "I don't feel strong enough without my helmet.")
+ to_chat(H, "You don't feel strong enough without your helmet.")
return FALSE
else
if(clothes_req || human_req)
- to_chat(user, "This spell can only be cast by humans!")
+ to_chat(user, "This spell can only be cast by humans!")
return FALSE
if(nonabstract_req && (isbrain(user) || ispAI(user)))
- to_chat(user, "This spell can only be cast by physical beings!")
+ to_chat(user, "This spell can only be cast by physical beings!")
return FALSE
@@ -241,7 +241,7 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th
if("charges")
if(!charge_counter)
if(!silent)
- to_chat(user, "[name] has no charges left.")
+ to_chat(user, "[name] has no charges left!")
return FALSE
return TRUE
@@ -267,7 +267,7 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th
. = ..()
START_PROCESSING(SSfastprocess, src)
- still_recharging_msg = "[name] is still recharging."
+ still_recharging_msg = "[name] is still recharging!"
charge_counter = charge_max
/obj/effect/proc_holder/spell/Destroy()
diff --git a/code/modules/spells/spell_types/barnyard.dm b/code/modules/spells/spell_types/barnyard.dm
index 6fe5458e2c9..503932008cb 100644
--- a/code/modules/spells/spell_types/barnyard.dm
+++ b/code/modules/spells/spell_types/barnyard.dm
@@ -18,18 +18,18 @@
/obj/effect/proc_holder/spell/targeted/barnyardcurse/cast(list/targets, mob/user = usr)
if(!targets.len)
- to_chat(user, "No target found in range.")
+ to_chat(user, "No target found in range!")
return
var/mob/living/carbon/target = targets[1]
if(!is_type_in_typecache(target, compatible_mobs_typecache))
- to_chat(user, "You are unable to curse [target]'s head!")
+ to_chat(user, "You are unable to curse [target]'s head!")
return
if(!(target in oview(range)))
- to_chat(user, "[target.p_theyre(TRUE)] too far away!")
+ to_chat(user, "[target.p_theyre(TRUE)] too far away!")
return
if(target.anti_magic_check())
diff --git a/code/modules/spells/spell_types/construct_spells.dm b/code/modules/spells/spell_types/construct_spells.dm
index 5efec52aaa7..44cde8211e6 100644
--- a/code/modules/spells/spell_types/construct_spells.dm
+++ b/code/modules/spells/spell_types/construct_spells.dm
@@ -102,7 +102,7 @@
/obj/effect/proc_holder/spell/aoe_turf/conjure/soulstone/noncult/purified
summon_type = list(/obj/item/soulstone/anybody/purified)
-
+
/obj/effect/proc_holder/spell/targeted/forcewall/cult
name = "Shield"
desc = "This spell creates a temporary forcefield to shield yourself and allies from incoming fire."
@@ -197,14 +197,14 @@
/obj/effect/proc_holder/spell/targeted/abyssal_gaze/cast(list/targets, mob/user = usr)
if(!LAZYLEN(targets))
- to_chat(user, "No target found in range.")
+ to_chat(user, "No target found in range!")
revert_cast()
return
var/mob/living/carbon/target = targets[1]
if(!(target in oview(range)))
- to_chat(user, "[target] is too far away!")
+ to_chat(user, "[target] is too far away!")
revert_cast()
return
@@ -266,7 +266,7 @@
return
if(!(S in oview(range)))
- to_chat(user, "[S] is too far away!")
+ to_chat(user, "[S] is too far away!")
revert_cast()
return
diff --git a/code/modules/spells/spell_types/devil.dm b/code/modules/spells/spell_types/devil.dm
index 9cd6013c450..c0300b378c9 100644
--- a/code/modules/spells/spell_types/devil.dm
+++ b/code/modules/spells/spell_types/devil.dm
@@ -70,7 +70,7 @@
contract = new /obj/item/paper/contract/infernal/friend(C.loc, C.mind, user.mind)
C.put_in_hands(contract)
else
- to_chat(user, "[C] seems to not be sentient. You cannot summon a contract for [C.p_them()].")
+ to_chat(user, "[C] seems to not be sentient. You cannot summon a contract for [C.p_them()].")
/obj/effect/proc_holder/spell/aimed/fireball/hellish
diff --git a/code/modules/spells/spell_types/godhand.dm b/code/modules/spells/spell_types/godhand.dm
index 927bef94ba3..860bd3a80fc 100644
--- a/code/modules/spells/spell_types/godhand.dm
+++ b/code/modules/spells/spell_types/godhand.dm
@@ -54,7 +54,7 @@
if(!proximity || target == user || !ismob(target) || !iscarbon(user) || !(user.mobility_flags & MOBILITY_USE)) //exploding after touching yourself would be bad
return
if(!user.can_speak_vocal())
- to_chat(user, "You can't get the words out!")
+ to_chat(user, "You can't get the words out!")
return
var/mob/M = target
do_sparks(4, FALSE, M.loc)
@@ -96,7 +96,7 @@
to_chat(user, "You can't reach out!")
return
if(!user.can_speak_vocal())
- to_chat(user, "You can't get the words out!")
+ to_chat(user, "You can't get the words out!")
return
var/mob/living/M = target
if(M.anti_magic_check())
diff --git a/code/modules/spells/spell_types/hivemind.dm b/code/modules/spells/spell_types/hivemind.dm
index 6ca1a292e9e..e321a5d7197 100644
--- a/code/modules/spells/spell_types/hivemind.dm
+++ b/code/modules/spells/spell_types/hivemind.dm
@@ -184,6 +184,7 @@
name = "Sensory Shock"
desc = "After a short charging time, we overload the mind of one of our vessels with psionic energy, temporarilly disrupting their sight, hearing, and speech."
charge_max = 600
+ panel = "Hivemind Abilities"
invocation_type = "none"
clothes_req = 0
human_req = 1
@@ -311,7 +312,7 @@
if(!carbon_members.len)
return
if(!user.getBruteLoss() && !user.getFireLoss() && !user.getCloneLoss() && !user.getBrainLoss() && !user.getStaminaLoss())
- to_chat(user, "We cannot heal ourselves any more with this power!")
+ to_chat(user, "We cannot heal ourselves any more with this power!")
revert_cast()
to_chat(user, "We begin siphoning power from our many vessels!")
while(iterations < 7)
@@ -421,11 +422,11 @@
timely = 100
restricted_range = TRUE
if(!do_after(user, timely, FALSE, user))
- to_chat(user, "We fail to assume control of the target.")
+ to_chat(user, "We fail to assume control of the target!")
revert_cast()
return
if(user.z != vessel.z || (restricted_range && get_dist(vessel, user) > 35))
- to_chat(user, "Our vessel is too far away to control.")
+ to_chat(user, "Our vessel is too far away to control!")
revert_cast()
return
for(var/datum/antagonist/hivemind/H in GLOB.antagonists)
@@ -646,7 +647,7 @@
item_state = "hivehand"
lefthand_file = 'icons/mob/inhands/misc/touchspell_lefthand.dmi'
righthand_file = 'icons/mob/inhands/misc/touchspell_righthand.dmi'
-
+
reach = 3
min_reach = -1
item_flags = ABSTRACT | DROPDEL
@@ -670,9 +671,9 @@
user.put_in_hands(W)
to_chat(user, "You make a telekinetic hand!")
else
- to_chat(user,"You cannot make a telekinetic hand while holding something!")
+ to_chat(user,"You cannot make a telekinetic hand while holding something!")
revert_cast()
-
+
/obj/effect/proc_holder/spell/targeted/hive_hack
name = "Network Invasion"
desc = "We probe the mind of an adjacent target and extract valuable information on any enemy hives they may belong to. Takes longer if the target is not in our hive or wearing tinfoil protection."
@@ -697,7 +698,7 @@
var/list/enemies = list()
to_chat(user, "We begin probing [target.name]'s mind!")
- if(!do_after(user,100,0,target))
+ if(do_after(user,100,0,target))
var/foiled = target.anti_magic_check(FALSE, FALSE, TRUE)
if(!in_hive || foiled)
var/timely = !in_hive ? 200 : 100
diff --git a/code/modules/spells/spell_types/lightning.dm b/code/modules/spells/spell_types/lightning.dm
index 432d2aa4026..27d3e6c3a61 100644
--- a/code/modules/spells/spell_types/lightning.dm
+++ b/code/modules/spells/spell_types/lightning.dm
@@ -52,7 +52,7 @@
Snd=sound(null, repeat = 0, wait = 1, channel = Snd.channel) //byond, why you suck?
playsound(get_turf(user),Snd,50,0)// Sorry MrPerson, but the other ways just didn't do it the way i needed to work, this is the only way.
if(get_dist(user,target)>range)
- to_chat(user, "[target.p_theyre(TRUE)] too far away!")
+ to_chat(user, "[target.p_theyre(TRUE)] too far away!")
Reset(user)
return
diff --git a/code/modules/spells/spell_types/mime.dm b/code/modules/spells/spell_types/mime.dm
index 1791b23ea13..099e3a60608 100644
--- a/code/modules/spells/spell_types/mime.dm
+++ b/code/modules/spells/spell_types/mime.dm
@@ -20,7 +20,7 @@
/obj/effect/proc_holder/spell/aoe_turf/conjure/mime_wall/Click()
if(usr && usr.mind)
if(!usr.mind.miming)
- to_chat(usr, "You must dedicate yourself to silence first.")
+ to_chat(usr, "You must dedicate yourself to silence first!")
return
invocation = "[usr.real_name] looks as if a wall is in front of [usr.p_them()]."
else
@@ -49,7 +49,7 @@
/obj/effect/proc_holder/spell/aoe_turf/conjure/mime_chair/Click()
if(usr && usr.mind)
if(!usr.mind.miming)
- to_chat(usr, "You must dedicate yourself to silence first.")
+ to_chat(usr, "You must dedicate yourself to silence first!")
return
invocation = "[usr.real_name] pulls out an invisible chair and sits down."
else
@@ -94,7 +94,7 @@
/obj/effect/proc_holder/spell/aoe_turf/conjure/mime_box/Click()
if(usr && usr.mind)
if(!usr.mind.miming)
- to_chat(usr, "You must dedicate yourself to silence first.")
+ to_chat(usr, "You must dedicate yourself to silence first!")
return
invocation = "[usr.real_name] moves [usr.p_their()] hands in the shape of a cube, pressing a box out of the air."
else
@@ -162,7 +162,7 @@
/obj/effect/proc_holder/spell/targeted/forcewall/mime/Click()
if(usr && usr.mind)
if(!usr.mind.miming)
- to_chat(usr, "You must dedicate yourself to silence first.")
+ to_chat(usr, "You must dedicate yourself to silence first!")
return
invocation = "[usr.real_name] looks as if a blockade is in front of [usr.p_them()]."
else
@@ -199,7 +199,7 @@
return
if(usr && usr.mind)
if(!usr.mind.miming)
- to_chat(usr, "You must dedicate yourself to silence first.")
+ to_chat(usr, "You must dedicate yourself to silence first!")
return
invocation = "[usr.real_name] fires [usr.p_their()] finger gun!"
else
diff --git a/code/modules/spells/spell_types/rod_form.dm b/code/modules/spells/spell_types/rod_form.dm
index 71098de6b01..90b071872eb 100644
--- a/code/modules/spells/spell_types/rod_form.dm
+++ b/code/modules/spells/spell_types/rod_form.dm
@@ -45,8 +45,8 @@
/obj/effect/immovablerod/wizard/penetrate(mob/living/L)
if(L.anti_magic_check())
- L.visible_message("[src] hits [L], but it bounces back, then vanishes!" , "[src] hits you... but it bounces back, then vanishes!" , "You hear a weak, sad, CLANG.")
+ L.visible_message("[src] hits [L], but it bounces back, then vanishes!" , "[src] hits you... but it bounces back, then vanishes!" , "You hear a weak, sad, CLANG.")
qdel(src)
return
- L.visible_message("[L] is penetrated by an immovable rod!" , "The rod penetrates you!" , "You hear a CLANG!")
+ L.visible_message("[L] is penetrated by an immovable rod!" , "The rod penetrates you!" , "You hear a CLANG!")
L.adjustBruteLoss(70 + damage_bonus)
diff --git a/code/modules/station_goals/bsa.dm b/code/modules/station_goals/bsa.dm
index 657b4d05e63..bfc583a309c 100644
--- a/code/modules/station_goals/bsa.dm
+++ b/code/modules/station_goals/bsa.dm
@@ -139,7 +139,7 @@
/obj/machinery/bsa/full/proc/get_front_turf()
switch(dir)
if(WEST)
- return locate(x - 6,y,z)
+ return locate(x - 7,y,z)
if(EAST)
return locate(x + 4,y,z)
return get_turf(src)
@@ -181,6 +181,7 @@
for(var/turf/T in getline(get_step(point,dir),get_target_turf()))
T.ex_act(EXPLODE_DEVASTATE)
point.Beam(get_target_turf(),icon_state="bsa_beam",time=50,maxdistance = world.maxx) //ZZZAP
+ new /obj/effect/temp_visual/bsa_splash(point, dir)
message_admins("[ADMIN_LOOKUPFLW(user)] has launched an artillery strike targeting [ADMIN_VERBOSEJMP(bullseye)].")
log_game("[key_name(user)] has launched an artillery strike targeting [AREACOORD(bullseye)].")
diff --git a/code/modules/surgery/bodyparts/bodyparts.dm b/code/modules/surgery/bodyparts/bodyparts.dm
index 3e00349c829..c54b1cbcf97 100644
--- a/code/modules/surgery/bodyparts/bodyparts.dm
+++ b/code/modules/surgery/bodyparts/bodyparts.dm
@@ -4,6 +4,7 @@
desc = "Why is it detached..."
force = 3
throwforce = 3
+ w_class = WEIGHT_CLASS_SMALL
icon = 'icons/mob/human_parts.dmi'
icon_state = ""
layer = BELOW_MOB_LAYER //so it isn't hidden behind objects when on the floor
@@ -96,7 +97,7 @@
..()
/obj/item/bodypart/attackby(obj/item/W, mob/user, params)
- if(W.sharpness)
+ if(W.is_sharp())
add_fingerprint(user)
if(!contents.len)
to_chat(user, "There is nothing left inside [src]!")
diff --git a/code/modules/surgery/bodyparts/robot_bodyparts.dm b/code/modules/surgery/bodyparts/robot_bodyparts.dm
index 653a638fdf5..29f46041814 100644
--- a/code/modules/surgery/bodyparts/robot_bodyparts.dm
+++ b/code/modules/surgery/bodyparts/robot_bodyparts.dm
@@ -179,8 +179,8 @@
else
. += "It has an empty port for a power cell."
if(wired)
- . += {"Its all wired up[cell ? " and ready for usage" : ""].\n
- You can use wirecutters to remove the wiring."}
+ . += "Its all wired up[cell ? " and ready for usage" : ""].\n"+\
+ "You can use wirecutters to remove the wiring."
else
. += "It has a couple spots that still need to be wired."
diff --git a/code/modules/surgery/advanced/bioware/experimental_dissection.dm b/code/modules/surgery/experimental_dissection.dm
similarity index 94%
rename from code/modules/surgery/advanced/bioware/experimental_dissection.dm
rename to code/modules/surgery/experimental_dissection.dm
index db4759b211f..f4f2b0f91c6 100644
--- a/code/modules/surgery/advanced/bioware/experimental_dissection.dm
+++ b/code/modules/surgery/experimental_dissection.dm
@@ -1,4 +1,4 @@
-/datum/surgery/advanced/experimental_dissection
+/datum/surgery/experimental_dissection
name = "Experimental Dissection"
desc = "A surgical procedure which deeply analyzes the biology of a corpse, and automatically adds new findings to the research database."
steps = list(/datum/surgery_step/incise,
@@ -10,7 +10,7 @@
possible_locs = list(BODY_ZONE_CHEST)
target_mobtypes = list(/mob/living/carbon) //Feel free to dissect devils but they're magic.
-/datum/surgery/advanced/experimental_dissection/can_start(mob/user, mob/living/carbon/target)
+/datum/surgery/experimental_dissection/can_start(mob/user, mob/living/carbon/target)
. = ..()
if(HAS_TRAIT(target, TRAIT_DISSECTED))
return FALSE
@@ -60,4 +60,4 @@
var/obj/item/bodypart/L = target.get_bodypart(BODY_ZONE_CHEST)
target.apply_damage(80, BRUTE, L)
ADD_TRAIT(target, TRAIT_DISSECTED, "surgery")
- return TRUE
+ return TRUE
\ No newline at end of file
diff --git a/code/modules/surgery/eye_surgery.dm b/code/modules/surgery/eye_surgery.dm
index 9f6ba762d91..c52e92bb170 100644
--- a/code/modules/surgery/eye_surgery.dm
+++ b/code/modules/surgery/eye_surgery.dm
@@ -24,6 +24,7 @@
"[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)
+ var/obj/item/organ/eyes/E = target.getorganslot(ORGAN_SLOT_EYES)
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!",
@@ -32,7 +33,7 @@
target.set_blindness(0)
target.cure_nearsighted(list(EYE_DAMAGE))
target.blur_eyes(35) //this will fix itself slowly.
- target.set_eye_damage(0)
+ E.setOrganDamage(0)
return TRUE
/datum/surgery_step/fix_eyes/failure(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
diff --git a/code/modules/surgery/limb_augmentation.dm b/code/modules/surgery/limb_augmentation.dm
index 91b0ce73b4c..e68a67d5384 100644
--- a/code/modules/surgery/limb_augmentation.dm
+++ b/code/modules/surgery/limb_augmentation.dm
@@ -11,7 +11,7 @@
/datum/surgery_step/replace/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
- display_results(user, target, "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)].")
@@ -34,11 +34,11 @@
return -1
L = surgery.operated_bodypart
if(L)
- display_results(user, target, "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)]...")
+ 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
diff --git a/code/modules/surgery/organ_manipulation.dm b/code/modules/surgery/organ_manipulation.dm
index 8c6b731bb3d..57cc10f17b7 100644
--- a/code/modules/surgery/organ_manipulation.dm
+++ b/code/modules/surgery/organ_manipulation.dm
@@ -81,18 +81,18 @@
I = null
if(istype(tool, /obj/item/organ_storage))
if(!tool.contents.len)
- to_chat(user, "There is nothing inside [tool]!")
+ to_chat(user, "There is nothing inside [tool]!")
return -1
I = tool.contents[1]
if(!isorgan(I))
- to_chat(user, "You cannot put [I] into [target]'s [parse_zone(target_zone)]!")
+ to_chat(user, "You cannot put [I] into [target]'s [parse_zone(target_zone)]!")
return -1
tool = I
if(isorgan(tool))
current_type = "insert"
I = tool
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)]!")
+ to_chat(user, "There is no room for [I] in [target]'s [parse_zone(target_zone)]!")
return -1
display_results(user, target, "You begin to insert [tool] into [target]'s [parse_zone(target_zone)]...",
@@ -103,7 +103,7 @@
current_type = "extract"
var/list/organs = target.getorganszone(target_zone)
if(!organs.len)
- to_chat(user, "There are no removable organs in [target]'s [parse_zone(target_zone)]!")
+ to_chat(user, "There are no removable organs in [target]'s [parse_zone(target_zone)]!")
return -1
else
for(var/obj/item/organ/O in organs)
@@ -151,7 +151,7 @@
I.Remove(target)
I.forceMove(get_turf(target))
else
- display_results(user, target, "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/organs/ears.dm b/code/modules/surgery/organs/ears.dm
index 34d0e49b9df..61024765817 100644
--- a/code/modules/surgery/organs/ears.dm
+++ b/code/modules/surgery/organs/ears.dm
@@ -10,10 +10,9 @@
// to hear anything.
var/deaf = 0
- // `ear_damage` measures long term damage to the ears, if too high,
+ // `damage` in this case measures long term damage to the ears, if too high,
// the person will not have either `deaf` or `ear_damage` decrease
// without external aid (earmuffs, drugs)
- var/ear_damage = 0
//Resistance against loud noises
var/bang_protect = 0
@@ -23,17 +22,20 @@
/obj/item/organ/ears/on_life()
if(!iscarbon(owner))
return
+ ..()
var/mob/living/carbon/C = owner
+ if((damage < maxHealth) && failing) //ear damage can be repaired from the failing condition
+ failing = FALSE
// genetic deafness prevents the body from using the ears, even if healthy
if(HAS_TRAIT(C, TRAIT_DEAF))
deaf = max(deaf, 1)
- else if(ear_damage < UNHEALING_EAR_DAMAGE) // if higher than UNHEALING_EAR_DAMAGE, no natural healing occurs.
- ear_damage = max(ear_damage - 0.05, 0)
+ else if(!failing) // if this organ is failing, do not clear deaf stacks.
deaf = max(deaf - 1, 0)
/obj/item/organ/ears/proc/restoreEars()
deaf = 0
- ear_damage = 0
+ damage = 0
+ failing = FALSE
var/mob/living/carbon/C = owner
@@ -41,7 +43,7 @@
deaf = 1
/obj/item/organ/ears/proc/adjustEarDamage(ddmg, ddeaf)
- ear_damage = max(ear_damage + (ddmg*damage_multiplier), 0)
+ damage = max(damage + (ddmg*damage_multiplier), 0)
deaf = max(deaf + (ddeaf*damage_multiplier), 0)
/obj/item/organ/ears/proc/minimumDeafTicks(value)
@@ -116,5 +118,4 @@
name = "tin ears"
desc = "The robust ears of a bronze golem. "
damage_multiplier = 0.1 //STRONK
- bang_protect = 1 //Fear me weaklings.
-
+ bang_protect = 1 //Fear me weaklings.
diff --git a/code/modules/surgery/organs/eyes.dm b/code/modules/surgery/organs/eyes.dm
index 3f477effa31..f701b049c55 100644
--- a/code/modules/surgery/organs/eyes.dm
+++ b/code/modules/surgery/organs/eyes.dm
@@ -8,7 +8,6 @@
var/sight_flags = 0
var/see_in_dark = 2
- var/eye_damage = 0
var/tint = 0
var/eye_color = "" //set to a hex code to override a mob's eye color
var/eye_icon_state = "eyes"
@@ -17,6 +16,10 @@
var/see_invisible = SEE_INVISIBLE_LIVING
var/lighting_alpha
var/no_glasses
+ var/damaged = FALSE //damaged indicates that our eyes are undergoing some level of negative effect
+ maxHealth = 50 //half the normal health max since we go blind at 30, a permanent blindness at 50 therefore makes sense unless medicine is administered
+ high_threshold = 20
+ low_threshold = 10
/obj/item/organ/eyes/Insert(mob/living/carbon/M, special = FALSE, drop_if_replaced = FALSE, initialising)
. = ..()
@@ -44,6 +47,29 @@
M.update_tint()
M.update_sight()
+/obj/item/organ/eyes/on_life()
+ ..()
+ var/mob/living/carbon/C = owner
+ //since we can repair fully damaged eyes, check if healing has occurred
+ if(failing && (damage < maxHealth))
+ failing = FALSE
+ C.cure_blind(EYE_DAMAGE)
+ //various degrees of "oh fuck my eyes", from "point a laser at your eye" to "staring at the Sun" intensities
+ if(damage > 20)
+ damaged = TRUE
+ if(failing)
+ C.become_blind(EYE_DAMAGE)
+ else if(damage > 30)
+ C.overlay_fullscreen("eye_damage", /obj/screen/fullscreen/impaired, 2)
+ else
+ C.overlay_fullscreen("eye_damage", /obj/screen/fullscreen/impaired, 1)
+ //called once since we don't want to keep clearing the screen of eye damage for people who are below 20 damage
+ else if(damaged)
+ damaged = FALSE
+ C.clear_fullscreen("eye_damage")
+ return
+
+
/obj/item/organ/eyes/night_vision
name = "shadow eyes"
desc = "A spooky set of eyes that can see in the dark."
diff --git a/code/modules/surgery/organs/heart.dm b/code/modules/surgery/organs/heart.dm
index 42e24dd55a2..f38cc108862 100644
--- a/code/modules/surgery/organs/heart.dm
+++ b/code/modules/surgery/organs/heart.dm
@@ -49,15 +49,17 @@
return S
/obj/item/organ/heart/on_life()
+ ..()
if(owner.client && beating)
var/sound/slowbeat = sound('sound/health/slowbeat.ogg', repeat = TRUE)
var/sound/fastbeat = sound('sound/health/fastbeat.ogg', repeat = TRUE)
var/mob/living/carbon/H = owner
+
if(H.health <= H.crit_threshold && beat != BEAT_SLOW)
beat = BEAT_SLOW
H.playsound_local(get_turf(H), slowbeat,40,0, channel = CHANNEL_HEARTBEAT)
- to_chat(owner, "You feel your heart slow down...")
+ to_chat(owner, "You feel your heart slow down...")
if(beat == BEAT_SLOW && H.health > H.crit_threshold)
H.stop_sound_channel(CHANNEL_HEARTBEAT)
beat = BEAT_NONE
@@ -101,7 +103,7 @@
var/mob/living/carbon/human/H = owner
if(H.dna && !(NOBLOOD in H.dna.species.species_traits))
H.blood_volume = max(H.blood_volume - blood_loss, 0)
- to_chat(H, "You have to keep pumping your blood!")
+ to_chat(H, "You have to keep pumping your blood!")
if(add_colour)
H.add_client_colour(/datum/client_colour/cursed_heart_blood) //bloody screen so real
add_colour = FALSE
@@ -111,7 +113,7 @@
/obj/item/organ/heart/cursed/Insert(mob/living/carbon/M, special = 0)
..()
if(owner)
- to_chat(owner, "Your heart has been replaced with a cursed one, you have to pump this one manually otherwise you'll die!")
+ to_chat(owner, "Your heart has been replaced with a cursed one, you have to pump this one manually otherwise you'll die!")
/obj/item/organ/heart/cursed/Remove(mob/living/carbon/M, special = 0)
..()
@@ -132,7 +134,7 @@
cursed_heart.last_pump = world.time
playsound(owner,'sound/effects/singlebeat.ogg',40,1)
- to_chat(owner, "Your heart beats.")
+ to_chat(owner, "Your heart beats.")
var/mob/living/carbon/human/H = owner
if(istype(H))
diff --git a/code/modules/surgery/organs/liver.dm b/code/modules/surgery/organs/liver.dm
index 9fc9b76172e..5f82752e977 100755
--- a/code/modules/surgery/organs/liver.dm
+++ b/code/modules/surgery/organs/liver.dm
@@ -9,13 +9,12 @@
zone = BODY_ZONE_CHEST
slot = ORGAN_SLOT_LIVER
desc = "Pairing suggestion: chianti and fava beans."
- var/damage = 0 //liver damage, 0 is no damage, damage=maxHealth causes liver failure
var/alcohol_tolerance = ALCOHOL_RATE//affects how much damage the liver takes from alcohol
- var/failing //is this liver failing?
- var/maxHealth = LIVER_DEFAULT_HEALTH
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
+ maxHealth = LIVER_DEFAULT_HEALTH
+ Unique_Failure_Msg = "Subject is suffering from liver failure: Apply Corazone and begin a liver transplant immediately!"
#define HAS_SILENT_TOXIN 0 //don't provide a feedback message if this is the only toxin present
#define HAS_NO_TOXIN 1
@@ -23,11 +22,9 @@
/obj/item/organ/liver/on_life()
var/mob/living/carbon/C = owner
-
+ ..() //perform general on_life()
if(istype(C))
if(!failing)//can't process reagents with a failing liver
- //slowly heal liver damage
- damage = max(0, damage - 0.1)
var/provide_pain_message = HAS_NO_TOXIN
if(filterToxins && !HAS_TRAIT(owner, TRAIT_TOXINLOVER))
diff --git a/code/modules/surgery/organs/lungs.dm b/code/modules/surgery/organs/lungs.dm
index 47addbb6d0f..2fe1042c3a7 100644
--- a/code/modules/surgery/organs/lungs.dm
+++ b/code/modules/surgery/organs/lungs.dm
@@ -62,7 +62,7 @@
return
if(!breath || (breath.total_moles() == 0))
- if(H.reagents.has_reagent(crit_stabilizing_reagent))
+ if(H.reagents.has_reagent(crit_stabilizing_reagent, needs_metabolizing = TRUE))
return
if(H.health >= H.crit_threshold)
H.adjustOxyLoss(HUMAN_MAX_OXYLOSS)
@@ -288,8 +288,9 @@
//Miasma sickness
if(prob(0.5 * miasma_pp))
- var/datum/disease/advance/miasma_disease = new /datum/disease/advance/random(2,3)
- miasma_disease.name = "Unknown"
+ var/datum/disease/advance/miasma_disease = new /datum/disease/advance/random(min(round(max(miasma_pp/2, 1), 1), 6), min(round(max(miasma_pp, 1), 1), 8))
+ //tl;dr the first argument chooses the smaller of miasma_pp/2 or 6(typical max virus symptoms), the second chooses the smaller of miasma_pp or 8(max virus symptom level) //
+ miasma_disease.name = "Unknown"//^each argument has a minimum of 1 and rounds to the nearest value. Feel free to change the pp scaling I couldn't decide on good numbers for it.
miasma_disease.try_infect(owner)
// Miasma side effects
diff --git a/code/modules/surgery/organs/organ_internal.dm b/code/modules/surgery/organs/organ_internal.dm
index 4452881bcf9..22ad518d406 100644
--- a/code/modules/surgery/organs/organ_internal.dm
+++ b/code/modules/surgery/organs/organ_internal.dm
@@ -1,3 +1,6 @@
+#define STANDARD_ORGAN_THRESHOLD 100
+#define STANDARD_ORGAN_HEALING 0.001
+
/obj/item/organ
name = "organ"
icon = 'icons/obj/surgery.dmi'
@@ -13,7 +16,24 @@
//Was this organ implanted/inserted/etc, if true will not be removed during species change.
var/external = FALSE
var/synthetic = FALSE // To distinguish between organic and synthetic organs
+ var/maxHealth = STANDARD_ORGAN_THRESHOLD
+ var/damage = 0 //total damage this organ has sustained
+ var/failing = FALSE //is this organ failing or not
+ var/healing_factor = STANDARD_ORGAN_HEALING //fraction of maxhealth healed per on_life()
+ var/high_threshold = STANDARD_ORGAN_THRESHOLD * 0.45 //when severe organ damage occurs
+ var/low_threshold = STANDARD_ORGAN_THRESHOLD * 0.1 //when minor organ damage occurs
+ var/Unique_Failure_Msg //certain organs may want unique failure messages for details on how to fix them
+/obj/item/organ/proc/Assemble_Failure_Message() //need to assemble a failure message since we can't have variables be based off of the same object's variables
+ var/name_length
+ //if no unique failure message is set, output the generic one, otherwise give the one we have set
+ if(!Unique_Failure_Msg)
+ name_length = lentext(name)
+ if(name[name_length] == "s") //plural case, done without much sanitization since I don't know any organ that ends with an "s" that isn't plural at the moment
+ Unique_Failure_Msg = "Subject's [name] are too damaged to function, and needs to be replaced or fixed!"
+ else
+ Unique_Failure_Msg = "Subject's [name] is too damaged to function, and needs to be replaced or fixed!"
+ return Unique_Failure_Msg
/obj/item/organ/proc/Insert(mob/living/carbon/M, special = 0, drop_if_replaced = TRUE)
if(!iscarbon(M) || owner == M)
@@ -53,6 +73,14 @@
return
/obj/item/organ/proc/on_life()
+ var/mob/living/carbon/C = owner
+ //if we start to fail, cap our damage and fail the organ
+ if(damage > maxHealth)
+ failing = TRUE
+ damage = maxHealth
+ //repair organ damage if the organ is not failing
+ if((!failing) && C)
+ damage = max(0, damage - (maxHealth * healing_factor) )
return
/obj/item/organ/examine(mob/user)
@@ -101,6 +129,16 @@
/obj/item/organ/item_action_slot_check(slot,mob/user)
return //so we don't grant the organ's action to mobs who pick up the organ.
+/obj/item/organ/proc/applyOrganDamage(var/d) //use for damaging effects
+ damage = max(0, damage + d)
+
+/obj/item/organ/proc/setOrganDamage(var/d) //use mostly for admin heals
+ damage = CLAMP(d, 0 ,maxHealth)
+ if(d >= maxHealth)
+ failing = TRUE
+ else
+ failing = FALSE
+
//Looking for brains?
//Try code/modules/mob/living/carbon/brain/brain_item.dm
@@ -131,4 +169,4 @@
if(!getorganslot(ORGAN_SLOT_EARS))
var/obj/item/organ/ears/ears = new()
- ears.Insert(src)
+ ears.Insert(src)
\ No newline at end of file
diff --git a/code/modules/surgery/organs/stomach.dm b/code/modules/surgery/organs/stomach.dm
index 38c32d5ac1c..a52e99ec152 100755
--- a/code/modules/surgery/organs/stomach.dm
+++ b/code/modules/surgery/organs/stomach.dm
@@ -11,6 +11,7 @@
/obj/item/organ/stomach/on_life()
var/mob/living/carbon/human/H = owner
+ ..()
if(istype(H))
H.dna.species.handle_digestion(H)
handle_disgust(H)
diff --git a/code/modules/surgery/prosthetic_replacement.dm b/code/modules/surgery/prosthetic_replacement.dm
index 8bb4528c165..87de9c82cbd 100644
--- a/code/modules/surgery/prosthetic_replacement.dm
+++ b/code/modules/surgery/prosthetic_replacement.dm
@@ -24,11 +24,11 @@
/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)
- to_chat(user, "There is nothing inside [tool]!")
+ to_chat(user, "There is nothing inside [tool]!")
return -1
var/obj/item/I = tool.contents[1]
if(!isbodypart(I))
- to_chat(user, "[I] cannot be attached!")
+ to_chat(user, "[I] cannot be attached!")
return -1
tool = I
if(istype(tool, /obj/item/bodypart))
@@ -48,7 +48,7 @@
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.
- display_results(user, target, "You begin to replace [target]'s [parse_zone(target_zone)] with [tool]...",
+ 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
@@ -94,4 +94,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/surgery.dm b/code/modules/surgery/surgery.dm
index ed800cf36f0..57903d9b82e 100644
--- a/code/modules/surgery/surgery.dm
+++ b/code/modules/surgery/surgery.dm
@@ -117,6 +117,8 @@
if(locate(/obj/structure/table/optable, T))
propability = 1
+ else if(locate(/obj/machinery/stasis, T))
+ propability = 0.9
else if(locate(/obj/structure/table, T))
propability = 0.8
else if(locate(/obj/structure/bed, T))
diff --git a/code/modules/uplink/uplink_items.dm b/code/modules/uplink/uplink_items.dm
index 7380b9b1949..57aabfa0b44 100644
--- a/code/modules/uplink/uplink_items.dm
+++ b/code/modules/uplink/uplink_items.dm
@@ -201,7 +201,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
desc = "The Syndicate have offered you the chance to become a contractor, take on kidnapping contracts for TC and cash payouts. Upon purchase, \
you'll be granted your own contract uplink embedded within the supplied tablet computer. Additionally, you'll be granted \
standard contractor gear to help with your mission - comes supplied with the tablet, specialised space suit, chameleon jumpsuit and mask, \
- agent card, and three randomly selected low cost items. Includes potentially otherwise unobtainable items."
+ agent card, specialised contractor baton, and three randomly selected low cost items. Can include otherwise unobtainable items."
item = /obj/item/storage/box/syndicate/contract_kit
cost = 20
player_minimum = 20
@@ -487,7 +487,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
name = "Surplus Rifle"
desc = "A horribly outdated bolt action weapon. You've got to be desperate to use this."
item = /obj/item/gun/ballistic/rifle/boltaction
- cost = 2
+ cost = 1
include_modes = list(/datum/game_mode/nuclear)
/datum/uplink_item/dangerous/revolver
@@ -839,6 +839,20 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
cost = 1
include_modes = list(/datum/game_mode/nuclear)
+/datum/uplink_item/ammo/dark_gygax/bag
+ name = "Dark Gygax Ammo Bag"
+ desc = "A duffel bag containing ammo for three full reloads of the incendiary carbine and flash bang launcher that are equipped on a standard Dark Gygax exosuit."
+ item = /obj/item/storage/backpack/duffelbag/syndie/ammo/dark_gygax
+ cost = 4
+ include_modes = list(/datum/game_mode/nuclear)
+
+/datum/uplink_item/ammo/mauler/bag
+ name = "Mauler Ammo Bag"
+ desc = "A duffel bag containing ammo for three full reloads of the LMG, scattershot carbine, and SRM-8 missile laucher that are equipped on a standard Mauler exosuit."
+ item = /obj/item/storage/backpack/duffelbag/syndie/ammo/mauler
+ cost = 6
+ include_modes = list(/datum/game_mode/nuclear)
+
//Grenades and Explosives
/datum/uplink_item/explosives
category = "Grenades and Explosives"
diff --git a/code/modules/vehicles/_vehicle.dm b/code/modules/vehicles/_vehicle.dm
index 7a15c665d51..ff368e18783 100644
--- a/code/modules/vehicles/_vehicle.dm
+++ b/code/modules/vehicles/_vehicle.dm
@@ -61,6 +61,7 @@
.++
/obj/vehicle/proc/return_controllers_with_flag(flag)
+ RETURN_TYPE(/list/mob)
. = list()
for(var/i in occupants)
if(occupants[i] & flag)
diff --git a/code/modules/vehicles/ridden.dm b/code/modules/vehicles/ridden.dm
index 0bd7d19e01e..18ae6b59166 100644
--- a/code/modules/vehicles/ridden.dm
+++ b/code/modules/vehicles/ridden.dm
@@ -43,14 +43,14 @@
inserted_key.forceMove(drop_location())
inserted_key = I
else
- to_chat(user, "[I] seems to be stuck to your hand!")
+ to_chat(user, "[I] seems to be stuck to your hand!")
return
return ..()
/obj/vehicle/ridden/AltClick(mob/user)
if(inserted_key && user.canUseTopic(src, BE_CLOSE, ismonkey(user)))
if(!is_occupant(user))
- to_chat(user, "You must be riding the [src] to remove [src]'s key!")
+ to_chat(user, "You must be riding the [src] to remove [src]'s key!")
return
to_chat(user, "You remove \the [inserted_key] from \the [src].")
inserted_key.forceMove(drop_location())
diff --git a/code/modules/vehicles/sealed.dm b/code/modules/vehicles/sealed.dm
index 53865b9a229..e2d69fed344 100644
--- a/code/modules/vehicles/sealed.dm
+++ b/code/modules/vehicles/sealed.dm
@@ -73,7 +73,7 @@
inserted_key.forceMove(drop_location())
inserted_key = I
else
- to_chat(user, "[I] seems to be stuck to your hand!")
+ to_chat(user, "[I] seems to be stuck to your hand!")
return
return ..()
@@ -82,7 +82,7 @@
to_chat(user, "There is no key in [src]!")
return
if(!is_occupant(user) || !(occupants[user] & VEHICLE_CONTROL_DRIVE))
- to_chat(user, "You must be driving [src] to remove [src]'s key!")
+ to_chat(user, "You must be driving [src] to remove [src]'s key!")
return
to_chat(user, "You remove [inserted_key] from [src].")
inserted_key.forceMove(drop_location())
diff --git a/code/modules/vending/_vending.dm b/code/modules/vending/_vending.dm
index 68f4ebeaf49..9c71dfb40a8 100644
--- a/code/modules/vending/_vending.dm
+++ b/code/modules/vending/_vending.dm
@@ -262,21 +262,21 @@ GLOBAL_LIST_EMPTY(vending_products)
return
if(refill_canister && istype(I, refill_canister))
if (!panel_open)
- to_chat(user, "You should probably unscrew the service panel first.")
+ to_chat(user, "You should probably unscrew the service panel first!")
else if (stat & (BROKEN|NOPOWER))
to_chat(user, "[src] does not respond.")
else
//if the panel is open we attempt to refill the machine
var/obj/item/vending_refill/canister = I
if(canister.get_part_rating() == 0)
- to_chat(user, "[canister] is empty!")
+ to_chat(user, "[canister] is empty!")
else
// instantiate canister if needed
var/transferred = restock(canister)
if(transferred)
to_chat(user, "You loaded [transferred] items in [src].")
else
- to_chat(user, "There's nothing to restock!")
+ to_chat(user, "There's nothing to restock!")
return
if(compartmentLoadAccessCheck(user))
if(canLoadItem(I))
@@ -297,7 +297,7 @@ GLOBAL_LIST_EMPTY(vending_products)
else
denied_items++
if(denied_items)
- to_chat(user, "[src] refuses some items.")
+ to_chat(user, "[src] refuses some items!")
if(loaded)
to_chat(user, "You insert [loaded] dishes into [src]'s chef compartment.")
updateUsrDialog()
@@ -368,8 +368,19 @@ GLOBAL_LIST_EMPTY(vending_products)
dat += "No account on registered ID card!
"
if(onstation && C && C.registered_account)
account = C.registered_account
+ if(vending_machine_input.len)
+ dat += "[input_display_header]
"
+ dat += ""
+ for (var/O in vending_machine_input)
+ if(vending_machine_input[O] > 0)
+ var/N = vending_machine_input[O]
+ dat += "
Dispense "
+ dat += "
[capitalize(O)] ($[default_price]): [N]"
+ dat += "
"
+
dat += {"Select an item
"}
+
if(!product_records.len)
dat += "No product loaded!"
else
@@ -399,15 +410,6 @@ GLOBAL_LIST_EMPTY(vending_products)
dat += "
"
if(onstation && C && C.registered_account)
dat += "Balance: $[account.account_balance]"
- if(vending_machine_input.len)
- dat += "[input_display_header]
"
- dat += ""
- for (var/O in vending_machine_input)
- if(vending_machine_input[O] > 0)
- var/N = vending_machine_input[O]
- dat += "
Dispense "
- dat += "
[capitalize(O)] ($[default_price]): [N]"
- dat += "
"
var/datum/browser/popup = new(user, "vending", (name))
popup.add_stylesheet(get_asset_datum(/datum/asset/spritesheet/vending))
@@ -460,7 +462,7 @@ GLOBAL_LIST_EMPTY(vending_products)
if((href_list["vend"]) && (vend_ready))
if(panel_open)
- to_chat(usr, "The vending machine cannot dispense products while its service panel is open!")
+ to_chat(usr, "The vending machine cannot dispense products while its service panel is open!")
return
vend_ready = 0 //One thing at a time!!
diff --git a/code/modules/vending/autodrobe.dm b/code/modules/vending/autodrobe.dm
index 7bcfeb0efac..1a18c22458d 100644
--- a/code/modules/vending/autodrobe.dm
+++ b/code/modules/vending/autodrobe.dm
@@ -16,6 +16,7 @@
/obj/item/clothing/under/gladiator = 1,
/obj/item/clothing/head/helmet/gladiator = 1,
/obj/item/clothing/under/gimmick/rank/captain/suit = 1,
+ /obj/item/clothing/under/gimmick/rank/captain/suit/skirt = 1,
/obj/item/clothing/head/flatcap = 1,
/obj/item/clothing/suit/toggle/labcoat/mad = 1,
/obj/item/clothing/shoes/jackboots = 1,
@@ -75,6 +76,7 @@
/obj/item/clothing/under/rank/clown/sexy = 1,
/obj/item/clothing/mask/gas/sexymime = 1,
/obj/item/clothing/under/sexymime = 1,
+ /obj/item/clothing/under/rank/mime/skirt = 1,
/obj/item/clothing/mask/rat/bat = 1,
/obj/item/clothing/mask/rat/bee = 1,
/obj/item/clothing/mask/rat/bear = 1,
diff --git a/code/modules/vending/clothesmate.dm b/code/modules/vending/clothesmate.dm
index d73e61c28a0..361b80f7c34 100644
--- a/code/modules/vending/clothesmate.dm
+++ b/code/modules/vending/clothesmate.dm
@@ -68,6 +68,9 @@
/obj/item/clothing/under/skirt/blue = 2,
/obj/item/clothing/under/skirt/red = 2,
/obj/item/clothing/under/skirt/purple = 2,
+ /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/suit/jacket = 2,
/obj/item/clothing/suit/jacket/puffer/vest = 2,
/obj/item/clothing/suit/jacket/puffer = 2,
@@ -98,6 +101,9 @@
/obj/item/clothing/suit/ianshirt = 1,
/obj/item/clothing/shoes/laceup = 2,
/obj/item/clothing/shoes/sandal = 2,
+ /obj/item/clothing/shoes/cowboy = 2,
+ /obj/item/clothing/shoes/cowboy/white = 2,
+ /obj/item/clothing/shoes/cowboy/black = 2,
/obj/item/clothing/suit/jacket/miljacket = 1,
/obj/item/clothing/suit/apron/purple_bartender = 2,
/obj/item/clothing/under/rank/bartender/purple = 2)
diff --git a/code/modules/vending/medical.dm b/code/modules/vending/medical.dm
index d023bc1361a..d71a9ad6bea 100644
--- a/code/modules/vending/medical.dm
+++ b/code/modules/vending/medical.dm
@@ -20,16 +20,16 @@
/obj/item/reagent_containers/glass/bottle/salglu_solution = 3,
/obj/item/reagent_containers/glass/bottle/toxin = 3,
/obj/item/reagent_containers/syringe/antiviral = 6,
- /obj/item/reagent_containers/medspray/styptic = 2,
- /obj/item/reagent_containers/medspray/silver_sulf = 2,
- /obj/item/reagent_containers/medspray/sterilizine = 1,
+ /obj/item/reagent_containers/medigel/styptic = 2,
+ /obj/item/reagent_containers/medigel/silver_sulf = 2,
+ /obj/item/reagent_containers/medigel/sterilizine = 1,
/obj/item/sensor_device = 2,
/obj/item/pinpointer/crew = 2)
contraband = list(/obj/item/reagent_containers/pill/tox = 3,
/obj/item/reagent_containers/pill/morphine = 4,
/obj/item/reagent_containers/pill/charcoal = 6,
/obj/item/storage/box/hug/medical = 1)
- premium = list(/obj/item/reagent_containers/medspray/synthflesh = 2,
+ premium = list(/obj/item/reagent_containers/medigel/synthflesh = 2,
/obj/item/storage/pill_bottle/psicodine = 2,
/obj/item/reagent_containers/hypospray/medipen = 3,
/obj/item/storage/belt/medical = 3,
diff --git a/code/modules/vending/medical_wall.dm b/code/modules/vending/medical_wall.dm
index 089ce4f4ddb..91f7735dda5 100644
--- a/code/modules/vending/medical_wall.dm
+++ b/code/modules/vending/medical_wall.dm
@@ -8,9 +8,9 @@
/obj/item/reagent_containers/pill/patch/styptic = 5,
/obj/item/reagent_containers/pill/patch/silver_sulf = 5,
/obj/item/reagent_containers/pill/charcoal = 2,
- /obj/item/reagent_containers/medspray/styptic = 2,
- /obj/item/reagent_containers/medspray/silver_sulf = 2,
- /obj/item/reagent_containers/medspray/sterilizine = 1)
+ /obj/item/reagent_containers/medigel/styptic = 2,
+ /obj/item/reagent_containers/medigel/silver_sulf = 2,
+ /obj/item/reagent_containers/medigel/sterilizine = 1)
contraband = list(/obj/item/reagent_containers/pill/tox = 2,
/obj/item/reagent_containers/pill/morphine = 2)
armor = list("melee" = 100, "bullet" = 100, "laser" = 100, "energy" = 100, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 50)
@@ -28,4 +28,4 @@
products = list(/obj/item/reagent_containers/syringe = 3,
/obj/item/reagent_containers/pill/patch/styptic = 1,
/obj/item/reagent_containers/pill/patch/silver_sulf = 1,
- /obj/item/reagent_containers/medspray/sterilizine = 1)
+ /obj/item/reagent_containers/medigel/sterilizine = 1)
diff --git a/code/modules/vending/wardrobes.dm b/code/modules/vending/wardrobes.dm
index a5970fed5f1..138f1684b89 100644
--- a/code/modules/vending/wardrobes.dm
+++ b/code/modules/vending/wardrobes.dm
@@ -51,6 +51,7 @@
/obj/item/clothing/suit/hooded/wintercoat/medical = 4,
/obj/item/clothing/under/rank/nursesuit = 4,
/obj/item/clothing/head/nursehat = 4,
+ /obj/item/clothing/under/rank/medical/skirt= 4,
/obj/item/clothing/under/rank/medical/blue = 4,
/obj/item/clothing/under/rank/medical/green = 4,
/obj/item/clothing/under/rank/medical/purple = 4,
@@ -78,6 +79,7 @@
/obj/item/storage/backpack/satchel/eng = 3,
/obj/item/clothing/suit/hooded/wintercoat/engineering = 3,
/obj/item/clothing/under/rank/engineer = 3,
+ /obj/item/clothing/under/rank/engineer/skirt = 3,
/obj/item/clothing/under/rank/engineer/hazard = 3,
/obj/item/clothing/suit/hazardvest = 3,
/obj/item/clothing/shoes/workboots = 3,
@@ -100,6 +102,7 @@
/obj/item/storage/backpack/industrial = 2,
/obj/item/clothing/suit/hooded/wintercoat/engineering/atmos = 3,
/obj/item/clothing/under/rank/atmospheric_technician = 3,
+ /obj/item/clothing/under/rank/atmospheric_technician/skirt = 3,
/obj/item/clothing/shoes/sneakers/black = 3)
refill_canister = /obj/item/vending_refill/wardrobe/atmos_wardrobe
payment_department = ACCOUNT_ENG
@@ -114,6 +117,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 = 3,
+ /obj/item/clothing/under/rank/cargotech/skirt = 3,
/obj/item/clothing/shoes/sneakers/black = 3,
/obj/item/clothing/gloves/fingerless = 3,
/obj/item/clothing/head/soft = 3,
@@ -132,6 +136,7 @@
vend_reply = "Thank you for using the RoboDrobe!"
products = list(/obj/item/clothing/glasses/hud/diagnostic = 2,
/obj/item/clothing/under/rank/roboticist = 2,
+ /obj/item/clothing/under/rank/roboticist/skirt = 2,
/obj/item/clothing/suit/toggle/labcoat = 2,
/obj/item/clothing/shoes/sneakers/black = 2,
/obj/item/clothing/gloves/fingerless = 2,
@@ -153,6 +158,7 @@
/obj/item/storage/backpack/satchel/tox = 3,
/obj/item/clothing/suit/hooded/wintercoat/science = 3,
/obj/item/clothing/under/rank/scientist = 3,
+ /obj/item/clothing/under/rank/scientist/skirt = 3,
/obj/item/clothing/suit/toggle/labcoat/science = 3,
/obj/item/clothing/shoes/sneakers/white = 3,
/obj/item/radio/headset/headset_sci = 3,
@@ -174,6 +180,7 @@
/obj/item/clothing/suit/apron = 2,
/obj/item/clothing/suit/apron/overalls = 3,
/obj/item/clothing/under/rank/hydroponics = 3,
+ /obj/item/clothing/under/rank/hydroponics/skirt = 3,
/obj/item/clothing/mask/bandana = 3,
/obj/item/clothing/accessory/armband/hydro = 3)
refill_canister = /obj/item/vending_refill/wardrobe/hydro_wardrobe
@@ -193,6 +200,9 @@
/obj/item/pen/fourcolor = 1,
/obj/item/pen/fountain = 2,
/obj/item/clothing/accessory/pocketprotector = 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/storage/backpack/satchel/explorer = 1,
/obj/item/clothing/glasses/regular = 2,
/obj/item/clothing/glasses/regular/jamjar = 1,
@@ -213,6 +223,7 @@
/obj/item/clothing/under/sl_suit = 2,
/obj/item/clothing/under/rank/bartender = 2,
/obj/item/clothing/under/rank/bartender/purple = 2,
+ /obj/item/clothing/under/rank/bartender/skirt = 2,
/obj/item/clothing/accessory/waistcoat = 2,
/obj/item/clothing/suit/apron/purple_bartender = 2,
/obj/item/clothing/head/soft/black = 2,
@@ -224,6 +235,7 @@
/obj/item/clothing/glasses/sunglasses/reagent = 1,
/obj/item/clothing/neck/petcollar = 1,
/obj/item/storage/belt/bandolier = 1)
+ premium = list(/obj/item/storage/box/dishdrive = 1)
refill_canister = /obj/item/vending_refill/wardrobe/bar_wardrobe
payment_department = ACCOUNT_SRV
/obj/item/vending_refill/wardrobe/bar_wardrobe
@@ -244,6 +256,7 @@
/obj/item/circuitboard/machine/dish_drive = 1,
/obj/item/clothing/suit/toggle/chef = 1,
/obj/item/clothing/under/rank/chef = 1,
+ /obj/item/clothing/under/rank/chef/skirt = 2,
/obj/item/clothing/head/chefhat = 1,
/obj/item/reagent_containers/glass/rag = 1,
/obj/item/clothing/suit/hooded/wintercoat = 2)
@@ -260,6 +273,7 @@
vend_reply = "Thank you for using the JaniDrobe!"
products = list(/obj/item/clothing/under/rank/janitor = 1,
/obj/item/cartridge/janitor = 1,
+ /obj/item/clothing/under/rank/janitor/skirt = 2,
/obj/item/clothing/gloves/color/black = 1,
/obj/item/clothing/head/soft/purple = 1,
/obj/item/paint/paint_remover = 1,
@@ -286,12 +300,18 @@
vend_reply = "Thank you for using the LawDrobe!"
products = list(/obj/item/clothing/under/lawyer/female = 1,
/obj/item/clothing/under/lawyer/black = 1,
+ /obj/item/clothing/under/lawyer/black/skirt = 1,
/obj/item/clothing/under/lawyer/red = 1,
+ /obj/item/clothing/under/lawyer/red/skirt = 1,
/obj/item/clothing/under/lawyer/bluesuit = 1,
+ /obj/item/clothing/under/lawyer/bluesuit/skirt = 1,
+ /obj/item/clothing/under/lawyer/blue/skirt = 1,
/obj/item/clothing/suit/toggle/lawyer = 1,
/obj/item/clothing/under/lawyer/purpsuit = 1,
+ /obj/item/clothing/under/lawyer/purpsuit/skirt = 1,
/obj/item/clothing/suit/toggle/lawyer/purple = 1,
/obj/item/clothing/under/lawyer/blacksuit = 1,
+ /obj/item/clothing/under/lawyer/blacksuit/skirt = 1,
/obj/item/clothing/suit/toggle/lawyer/black = 1,
/obj/item/clothing/shoes/laceup = 2,
/obj/item/clothing/accessory/lawyers_badge = 2)
@@ -310,6 +330,7 @@
/obj/item/storage/backpack/cultpack = 1,
/obj/item/clothing/accessory/pocketprotector/cosmetology = 1,
/obj/item/clothing/under/rank/chaplain = 1,
+ /obj/item/clothing/under/rank/chaplain/skirt = 2,
/obj/item/clothing/shoes/sneakers/black = 1,
/obj/item/clothing/suit/chaplainsuit/nun = 1,
/obj/item/clothing/head/nun_hood = 1,
@@ -339,11 +360,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 = 2,
+ /obj/item/clothing/under/rank/chemist/skirt = 2,
/obj/item/clothing/shoes/sneakers/white = 2,
/obj/item/clothing/suit/toggle/labcoat/chemist = 2,
/obj/item/storage/backpack/chemistry = 2,
/obj/item/storage/backpack/satchel/chem = 2,
/obj/item/storage/bag/chemistry = 2)
+ contraband = list(/obj/item/reagent_containers/spray/syndicate = 2)
refill_canister = /obj/item/vending_refill/wardrobe/chem_wardrobe
payment_department = ACCOUNT_MED
/obj/item/vending_refill/wardrobe/chem_wardrobe
@@ -356,6 +379,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 = 2,
+ /obj/item/clothing/under/rank/geneticist/skirt = 2,
/obj/item/clothing/shoes/sneakers/white = 2,
/obj/item/clothing/suit/toggle/labcoat/genetics = 2,
/obj/item/storage/backpack/genetics = 2,
@@ -372,6 +396,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 = 2,
+ /obj/item/clothing/under/rank/virologist/skirt = 2,
/obj/item/clothing/shoes/sneakers/white = 2,
/obj/item/clothing/suit/toggle/labcoat/virologist = 2,
/obj/item/clothing/mask/surgical = 2,
diff --git a/config/config.txt b/config/config.txt
index 140860924e6..5b985085f9d 100644
--- a/config/config.txt
+++ b/config/config.txt
@@ -454,7 +454,7 @@ MINUTE_CLICK_LIMIT 400
## If using TGS4, the string option can be set as a chat channel tag to limit the message to channels of that tag type (case-sensitive)
## i.e. CHAT_ANNOUNCE_NEW_GAME chat_channel_tag
-## Send a message with the station name starting a new game
+## Send a message with the station name starting a new game. Also required for the notify function
#CHAT_ANNOUNCE_NEW_GAME
diff --git a/dependencies.sh b/dependencies.sh
index a75940088f6..830da48aff9 100755
--- a/dependencies.sh
+++ b/dependencies.sh
@@ -18,3 +18,6 @@ export BSQL_VERSION=v1.4.0.0
#node version
export NODE_VERSION=8
+
+# PHP version
+export PHP_VERSION=5.6
diff --git a/html/changelog.html b/html/changelog.html
index 1264784148d..da7ffd80579 100644
--- a/html/changelog.html
+++ b/html/changelog.html
@@ -55,6 +55,453 @@
-->
+
05 July 2019
+
Akrilla updated:
+
+ - Contract kit comes with a contractor baton - a unique, lightly electrified weapon to help complete your contracts.
+ - Finalized payment system for contracts; much more balanced for contractors. No more extremely low paying contract sets.
+ - Generated contracts will all have unique targets, no more duplicates.
+ - Extraction droppod explosion has been removed, it'll only damage the tile it lands on.
+ - Extraction pods get sent to the jail immediately again.
+ - Refactored classic_baton code.
+
+
ArcaneMusic updated:
+
+ - NT staff have added new laser focusing rings onto all BSA equipment, so now it looks more like a massive deadly laser, and fires more accurately.
+
+
Atlanta Ned updated:
+
+ - Security can now issue citations! Spot someone committing a minor crime? Fine them for it!
+ - Got a citation? You can view and pay it at any security warrant consoles, located near the brig, your local law office, or the courtroom!
+
+
Fikou updated:
+
+ - Reports say the cult of Nar'Sie has gotten stronger, and can now convert the captain when he doesn't have his mindshield. To prepare against this, the CentCom religious division has trained their special holy people against conversions
+
+
Floyd / Qustinnus updated:
+
+ - The Nanotrasen Physological department has realized that working at a metal deathbox is more stressful than it currently is. Mood has been slightly rebalanced
+
+
Garen updated:
+
+ - Fixes being able to pull from belt/backpack when you are stunned or cuffed.
+
+
Krysonism updated:
+
+ - Trophazole - a new hearty brute medicine.
+ - Rhigoxane -- a new chilly burn medicine.
+ - Thializid - a new high-stakes tox medicine.
+ - The 3 basic trek chems are now unmixable.
+ - IV medicine bags and blood packs are available in the medlathe.
+ - suspicious spray bottles have been added to the chemdrobe contraband compartment.
+ - The medical lathe can now print spray bottles.
+ - Removed the charcoal syringes from the medkits.
+ - There is now slightly less charcoal available roundstart.
+ - Added new spray bottle & iv bag sprites.
+ - trans_to can now react the reagents if you want.
+
+
Lett1 updated:
+
+ - Added a new contraband about free syndicate keys
+
+
Mickyan updated:
+
+ - Coming into contact with -HONK- may have additional effects, do not be alarmed
+ - For safety reasons, the administration of -HONK- may only be performed by trained professionals
+ - Self-application of -HONK- is now forbidden
+
+
RandolfTheMeh updated:
+
+ - Universal Organ Damage variables and procs
+
+
Time-Green updated:
+
+ - Clones no longer have their genetic sequence quantum garble fucked together
+
+
WJohnston updated:
+
+ - Redesigned boxstation's SMES room. It is now part of engineering power storage like it once was instead of being strangely separated from the station.
+
+
XDTM updated:
+
+ - Abductors can now buy a special chem dispenser for 2 points. The machine is delivered as a beacon which can be used when standing on any free tile to spawn it.
+
+
actioninja updated:
+
+ - The sabre sheath properly plays sounds again after who knows how long
+ - smeses no longer link to themselves non-visibly
+ - Add match strike sound.
+ - Fixed a disconnected APC on the meta map satellite.
+ - Added a scrubber to the meta engineering lobby.
+ - cables now actually function again (I'm so sorry)
+
+
bandit updated:
+
+ - Nanotrasen chefs and botanists have finally learned to stop composting or grinding bowls and the like along with the food they come with.
+ - After years of arduous training, Nanotrasen crew can now tell whether an animal is dead by examining it.
+
+
blargety, Onule updated:
+
+ - Added departmental sprites for circuit boards commonly used within a department. For example, a SMES will have a orange base.
+ - Adds 8 new icons for circuit boards, based on department colors.
+ - Reorganizes computer_circuits.dm and machine_circuitboard.dm based on an alphabetical order divided by department.
+
+
granpawalton updated:
+
+ - Breakfast foods such as eggs, donuts, coffee and so on now give a long but weak positive moodie when eaten within 15 minutes of the start of a shift
+
+
nemvar updated:
+
+ - Mobs with negative armor no longer get damage decreased by armor penetration.
+ - Various cosmetic and gameplay related changes to hivebots. Player controlled hivebots can change their look by changing their intent to harm.
+ - Humans now always use the correct value for limb armor.
+ - Negative armor on objects now increases damage taken.
+ - All chainsaws, including the null rod variants, can now be used to saw off guns.
+ - Refactored the visibility of reagents for mobs.
+ - The air injector of the delta station incinerator now works.
+ - Antimagic now gets used up properly
+
+
ninjanomnom updated:
+
+ - Reproductive crossbreed extracts can be fed from the bio bag again
+
+
pireamaineach updated:
+
+ - Added mime envirosuits, nothing special here.
+ - Added clown envirosuits, which release space lube when they extinguish the clown.
+ - Removes code that theoretically limits plasmamen from being clowns and mimes, but actually doesn't.
+ - I guess the roles now spawning with these suits is kind of notable.
+ - Reverts unlisted changes to the grey detective suit from https://github.com/tgstation/tgstation/pull/44776.
+
+
wesoda25 updated:
+
+ - You can no longer infinitely purify a soulstone.
+ - Cultists can't use purified soulstones anymore.
+
+
zxaber updated:
+
+ - The R&D Server Controller console now lists the entire research history, including names of people who researched each item and locations it was done from.
+ - The R&D Server Controller console can now be used to disable the servers if someone makes the RD upset.
+ - Fixed the R&D servers working without power.
+ - R&D server sprites are now slightly animated, and new sprites have been added for when the server is disabled or off.
+
+
+
03 July 2019
+
AcapitalA updated:
+
+ - Night Vision Goggles and certain Thermal Optics are **slightly** more sensitive to bright lights.
+
+
CPTANT updated:
+
+ - Added OD to styptic and sulfur sulfadiazine, consuming too much will give you slight toxin damage on top of slight brute/burn damage.
+ - oxandrolone and salicyclic acid have the threshold for their superior healing capacity lowered.
+
+
Denton updated:
+
+ - Delta: Atmospheric technicians are now able to lock/unlock the SM engine's rad collectors with their IDs.
+ - Donut: Added a missing SciDrobe vending machine to the RnD "Excess Storage" area.
+ - Meta: Fixed the AIsat being connected to the station's power grid by round start. Fixed Medbay intercoms with faulty presets. Removed a duplicate windoor in the cargo bay that kept MULEbots from leaving their area.
+ - Mining station: Fixed unconnected air supply pipes.
+ - Replaced the CentCom admin storage vault door with bomb-proof shutters (require CentCom Captain level access to open). Removed broken intercoms from the wizard shuttle and replaced them with two headsets.
+ - Deleted random duplicate and broken atmos piping in most maps.
+ - Donutstation: The AI chamber SMES is now correctly connected to the AI APC.
+ - CentCom: Made the ERT pod doors and vault shutters bomb proof. Replaced loose CentCom ID cards with a box of IDs.
+
+
Dorsidwarf updated:
+
+ - Nanotrasen washing machines can now extract the raw power of the cosmos from bluespace crystals.
+
+
MadoFrog updated:
+
+ - Red, white, and blue mech pilot jumpsuits now available in the Mech Pilot's Suits Crate, under Costumes & Toys.
+
+
Skoglol updated:
+
+ - 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.
+
+
SpacePrius updated:
+
+ - Added empty boxes.
+ - Fixed bug where hivemind vessel awakening would not be logged.
+ - Fixed bug where awoken hivemind vessel objectives would not be logged.
+ - slightly modified the deadchat text for awakening.
+
+
Tlaltecuhtli updated:
+
+
XDTM updated:
+
+ - Engineering closets now start with a construction bag, which can hold machine components, circuits, electronics, and cable coils.
+
+
actioninja updated:
+
+ - cables are no longer lag generators when being cut
+
+
bandit updated:
+
+ - Nanotrasen's clowns have begun to preserve their images by stamping eggs with their NT-issued clown stamps. This is fine and normal.
+
+
kingofkosmos updated:
+
+ - the russian revolver's chamber can be spun again
+
+
nemvar updated:
+
+ - You can now craft white jumpskirts with cloth.
+
+
nervere updated:
+
+ - There is now a CTF button in the check antags panel.
+ - There is now a Reboot World button in the check antags panel.
+
+
zxaber updated:
+
+ - Dead AI players will now get a notification if they are being restored while outside their body.
+
+
+
30 June 2019
+
Yakumo Chen updated:
+
+ - Nar'Sie plushes have been purged of their heretical stuffing and can't be used to invoke runes any more.
+
+
+
29 June 2019
+
81Denton updated:
+
+ - Incomplete and non-teleport reactive armors can no longer be used to complete the traitor objective.
+
+
AffectedArc07 updated:
+
+ - You can now link your ingame account to your discord account
+ - You can now set notify status ingame, and be notified on discord when a round restarts
+ - There is now an admin panel to lookup IDs to ckeys, and vice versa
+
+
Akrilla updated:
+
+ - Fix bad icon state for bounty console printouts
+ - Contract kit's specialist space suit now has its custom sprite.
+ - Assigning to tablet now plays greeting soundclip.
+
+
AnturK updated:
+
+ - Quirks no longer apply to off-station roundstart antagonists.
+
+
CobbyzzzZzzz updated:
+
+ - Stasis are now the second best option for surgery probability (surgical tables are still number 1)
+
+
JJRcop updated:
+
+ - Stasis lets reagents know processing was stopped, fixing some issues.
+ - Amanitin's damage only triggers when it is completely removed from your system, not when processing stops.
+
+
JJRcop and Bobbahbrown updated:
+
+ - When attempting to say a blocked word in character you will be notified which ones were blocked.
+
+
Krysonism updated:
+
+ - player added items now appear above the standard selection in vending machines.
+
+
MCterra10 updated:
+
+ - database requests for admins no longer fail on MySQL version > 8.0.2
+
+
Mickyan updated:
+
+ - DIY Dish Drive Kit now available at your local bardrobe. Start saving those tips!
+ - The Dish Drive no longer sends reusable items into the disposal bin
+
+
Shaps/Ryll updated:
+
+ - Mosin Nagants are now bulky, but can be sawed off to fit in a bag
+
+
ShizCalev updated:
+
+ - Setting a defibrillator unit on fire will now make it's paddles appear on fire too when pulled out!
+ - Setting defibrillator paddles on fire will now cause the flames to run along it's cables and set the main unit on fire as well.
+
+
Skoglol updated:
+
+ - Heaters/freezers now support ctrl clicking to turn on and alt clicking to min/max target temperature.
+ - Heaters/freezers now shows target temperature and part status on examine.
+
+
Tetr4 updated:
+
+ - Turning a tile with gas effects into space now gets rid of the effects.
+
+
Tlaltecuhtli updated:
+
+ - Health sensor no longer displays a giant window with 1 button on it, instead can change states with alt click and use in hand.
+ - the TB antidotes injectors now actually cure TB and have some omnizine so you dont die from perfluoride
+ - stacks no longer give you a pop up window when you alt click on one on the floor
+
+
Twaticus updated:
+
+ - added department skirts
+ - fixed secskirt dixel
+
+
XDTM updated:
+
+ - Added a new abductor gland that randomizes blood type into a random reagent periodically.
+ - Added a new abductor gland that links to other people, and swaps their position with the owner. Mind control on this gland will affect the linked person.
+ - Added a new abductor gland that grants all access to the owner.
+ - Abductor scientists can now properly see the true name of glands when examining them.
+ - Mind control on mindshock glands now "broadcasts" the mind control, affecting bystanders but not the abductee.
+ - Species gland now has 7 mind control uses, instead of 5 (duration is still 30 seconds).
+ - Viral healing symptoms that are tied to reagents now also require a functioning liver to work.
+ - Holy water, Pyrosium, Cryostilane, Napalm and Phlogiston no longer need a liver to have their effects.
+
+
YPOQ updated:
+
+ - Monkeys can wear collars again
+
+
bobbahbrown updated:
+
+ - Deaths are now logged to the game log.
+
+
kittymaster0 updated:
+
+ - gives scientists a chance to spawn with an awesome tie
+
+
nemvar updated:
+
+ - Replaced most instances where cables referenced their maximum size with a define
+ - Turned off energy weapons can no longer cut down trees, destroy wooden walls, harvest lavaland plants and make planks.
+ - get_eye_protection and get_ear_protection now looks less ugly.
+
+
ninjanomnom updated:
+
+ - Lavaland atmos is no longer a preset gas mixture and varies per round
+ - Bonfire minimum oxygen content has been reduced
+
+
partykp updated:
+
+ - replaced the lower disposal bin in chemistry with a glass table and put half of the top table contents on it (metastation).
+
+
plapatin, sprites by cogwerks and edited by mrdoombringer updated:
+
+
zxaber updated:
+
+ - Mecha ballistics weapons now require ammo created from an Exosuit Fabricator or the Security Protolathe, though they will start with a full magazine and in most cases enough for one full reload. Reloading these weapons no longer chunks your power cell. Clown (and mime) mecha equipment have not changed.
+ - The SRM-8 Missile Launcher has been replaced with the BRM-6 Breaching Missile Launcher in techwebs (Nukie Mauler remains equipped with the SRM-8).
+ - Both Missile Launchers and the Clusterbang Launcher do not have an ammo cache, and cannot be reloaded by the pilot. Once the initial loaded ammo has been spent, you can use the appropriate ammo box to load the weapon directly.
+ - Utility mechs that have a clamp equipped can load ammo from their own cargo hold into other mechs.
+ - Nuke Ops can purchase spare ammo duffel bags for their mecha weapons, should they run low.
+
+
+
27 June 2019
+
Naksu updated:
+
+ - Fixed a couple of map issues in DeltaStation
+
+
actioninja updated:
+
+ - removed mech rcl from the research node so it stops spamming a warning in log
+ - cables now disconnect machines when cut
+ - terminal linking/not linking behavior with smeses has been improved
+ - couple of small mapping fixes
+ - changed cable coils back to 30
+ - changed the box smes room a little to prevent stacking terminals
+ - removed the rpcl from engineering on every map because it's not used for wiring anymore
+
+
+
26 June 2019
+
123chess456 updated:
+
+ - Non-binary changelings will now have the honorific "Mx." instead of "Mr.", reflecting the Syndicate's growing acceptance of non-binary operatives.
+
+
FlufflyCthulu updated:
+
+ - Fixes an issue with clown hulk simple mobs
+
+
Naksu updated:
+
+ - Mining base now has a common area accessible via a new shuttle on the medium-highpop maps, and a security office connecting the gulag and the mining base. Gulag also has functional atmos.
+
+
jcll updated:
+
+
kriskog updated:
+
+ - Space heaters no longer steal focus upon screwdrivering.
+
+
nemvar updated:
+
+ - The enchanted bolt action rifle
+ - Blood barrage has a new projectile icon.
+ - Fixed an arcane barrage runtime
+ - The bee sabre now has it's own suicide and no longer uses the one of the captains rapier.
+ - The bee sabre uses the correct articles and actually has icons now.
+
+
+
25 June 2019
+
Arkatos updated:
+
+ - Action buttons can now be dragged onto each other to swap places
+
+
Arkatos1 updated:
+
+ - Normal carps now spawn with a random color! There might even be some really rare color variant.. try asking Cayenne about it.
+
+
Fikou updated:
+
+ - NEWS REPORT: The latest alien technology allows them to abduct cows instantly, this is a great tragedy for all farm owners, better watch the garden!
+ - Centcom's Death Commando got a paycheck and jumpsuits of quality more similar to the rest of Centcom's staf- KS13 DOESN'T EXIST, THERE IS NO SUCH THING AS A DEATH COMMANDO
+
+
Floyd / Qustinnus updated:
+
+ - the bag of holding now requires a higher level of research to be unlocked as well as janitor tech (trashbags of holding)
+ - the bluespace bodybag is now unlocked with mini BS research
+
+
Jerry Derpington, baldest of the balds updated:
+
+ - Nanotrasen has lost communication to two away mission sites that contained a beach for Nanotrasen employees.
+ - Nanotrasen has been able to locate a new away mission site that ALSO has a beach. Nanotrasen employees will be able to enjoy the beach after all!
+
+
Jgta4444 updated:
+
+ - Dna scanner now correctly calculate its precision coefficient
+
+
Skoglol updated:
+
+ - Slimes should now feed properly again.
+
+
TetraK1 updated:
+
+ - Suiciding with an anomaly core kills you properly
+ - Service borgs get pipe cleaners for wire art
+ - you can altclick to pull up pipe cleaners
+ - Fixed cutting and joining pipe cleaners on floor tiles
+
+
Trilbyspaceclone and nemvar updated:
+
+ - You can now craft more fancy boxes with cardboard.
+
+
XDTM updated:
+
+ - Antimagic items now also properly work when held in hand, instead of only when equipped.
+ - Fixed abductor scientists not being able to perform advanced surgery.
+ - Quantum teleportation now makes pretty rainbow sparks instead of the normal ones.
+ - Non-bluespace teleportation (spells etc.) no longer makes sparks.
+
+
imsxz updated:
+
+ - diseases from miasma now become stronger the more miasma there is in the air
+
+
nemvar updated:
+
+ - Removed all sleepers from escape shuttles and replaced them with stasis units. Some shuttles have gotten surgery and new medical vendors added.
+
+
spookydonut updated:
+
+ - Removes shuttle manipulator.
+
+
23 June 2019
bgobandit updated:
@@ -1431,145 +1878,6 @@
- Gives Janiborgs a paint remover.
- Gives Janiborgs a flyswatter to destroy angry bees and moths with.
-
-
30 April 2019
-
81Denton updated:
-
- - Dead AIs no longer get stuck in place and become movable again.
-
-
Carshalash updated:
-
- - Replaces Pressurized Slime to spray lube instead of water
-
-
PKPenguin321 updated:
-
- - Humans now have a punch damage range of 1-10, up from 0-9
- - The chance to miss a punch now increases the more stamina and brute damage you have
- - The stun duration for a critical punch now scales with how much stamina/brute damage the victim has
- - Punches now deal full stamina damage + half damage in brute (effectively 1.5x damage on all punches, not accounting for stamina regeneration)
- - Kicking (punching a prone person) does full brute damage, never misses, and does 1.5x damage
- - Grabs are now harder to break out of the more stamina/brute damage you have
- - Failing to resist out of a grab will deal a bit of stamina damage to you
- - In all instances above where both stamina and brute damage are considered, brute is weighed 1/2 as heavily as stamina (meaning stamina has more of an effect than brute when it comes to punch-stun duration, miss chance, etc)
-
-
Skoglol updated:
-
- - Offstation AI can no longer interact with other z-levels. Again.
- - Robotics control console can now only blow/lockdown borgs and drones on current z-level.
- - Falsewalls now properly hide pipes and wires.
- - Ninja dash now works in dark areas if you can see in the dark.
- - Blob factories can no longer create more than one blobbernaut at a time.
-
-
SpaceManiac updated:
-
- - Removed a workaround for a compiler bug that has since been fixed.
- - The "draggable" cursor is now shown when folding a closed bodybag.
- - Failing to fold a bodybag because it is open or full now tells you why.
-
-
nemvar updated:
-
- - Fixes bathsalts and beepsky smash transfering their respective brain traumas after cloning.
-
-
-
27 April 2019
-
81Denton updated:
-
- - Pubbystation: Fixed the incinerator's waste to space injector starting powered off.
- - Metastation: You can now pass parts of the AI sat transit tube again.
-
-
DaxDupont updated:
-
- - Clowns now spawn with the proper health
-
-
Mideanon updated:
-
- - Adminordrazine now gives blood back
-
-
MrFluffster updated:
-
- - tweaked the pubby incinerator
-
-
RaveRadbury updated:
-
- - The radio configuration menu for masters of pAI will now toggle properly.
- - pAI HUD appears as it should.
-
-
RaveRadbury, Art by Navi.OS updated:
-
- - pAI Newscaster
- - pAI Camera
- - New pAI HUD
- - unique pAI HUD theme
-
-
TheDreamweaver updated:
-
- - Hilbert's Hotel can no longer be brought inside of itself.
-
-
Zxaber updated:
-
- - Certain small items purchased through cargo now get grouped into a single box.
- - Added single-order options for several existing products in the Cargo Catalog.
- - Added ALPU MK-I Ripley kit to the cargo catalog, under Engineering.
- - Cargo Ripley bounty now requires a MK-II. remove: Removed the Ripley and Odysseus listings in the cargo catalog that were only the control boards and nothing more.
- - Ammo and Medkit listings are now single-pack items, and considered small items that get grouped into single boxes. Price per unit for ammo is unchanged, and for medkits is as close to unchanged as is reasonable.
-
-
actioninja updated:
-
- - Changed the description on ling augmented eyes to be more accurate to their actual functionality
-
-
nemvar updated:
-
- - Heavily nerfs russian surplus gear.
-
-
tralezab updated:
-
- - zombies can eat brains now
-
-
-
25 April 2019
-
RaveRadbury updated:
-
- - pAI's now have the same headset tech as AI. Add and remove keys just like you would with headsets.
- - Service Halls now allow all Service dept. jobs.
-
-
-
24 April 2019
-
Kierany9 updated:
-
- - The hivemind radar's no longer has a minimum range, but has an increased ping time.
- - How power use affects the hivemind radar has been tweaked as to ensure that going loud early is punished more.
-
-
Mickyan updated:
-
- - New quirk: Empath. Gain a better insight on the state of people around you by examining them.
- - New quirk: Friendly. Your hugs are just the best. Keep yourself in a good mood to give the bestest hugs!
-
-
MrDroppodBringer and Time-Green updated:
-
- - Adds the lipid extractor to the service protolathe arsenal
-
-
TetraK1 updated:
-
- - AI integrity restorer no longer drops a free AI core on deconstruction/destruction.
-
-
Tlaltecuhtli updated:
-
- - rubbershot does 66 stamina + 18 damage instead of 150 stamina + 18 damage
- - beanbang does 55 stamina + 5 damge instead of 80 + 5 damage
-
-
Wilchenx updated:
-
- - The modular pc vendor
- - minor entities on meta/pubby/box/delta to make room for said vendor
-
-
actioninja updated:
-
- - Fixed an exploit where incompatible magazine could be tactical reloaded into guns, and then still fire.
-
-
bgobandit updated:
-
- - Examining intercoms/radios shows the frequency they're set to, if you're in range.
-
GoonStation 13 Development Team
diff --git a/html/changelogs/.all_changelog.yml b/html/changelogs/.all_changelog.yml
index bf25a080bdb..a9d401cad63 100644
--- a/html/changelogs/.all_changelog.yml
+++ b/html/changelogs/.all_changelog.yml
@@ -24983,3 +24983,369 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
the box works like a standard inventory box item.'
- tweak: Mime spells are now granted via a spellbook that starts out in the mime's
inventory. Mimes can choose one of these three.
+2019-06-25:
+ Arkatos:
+ - rscadd: Action buttons can now be dragged onto each other to swap places
+ Arkatos1:
+ - imageadd: Normal carps now spawn with a random color! There might even be some
+ really rare color variant.. try asking Cayenne about it.
+ Fikou:
+ - rscadd: 'NEWS REPORT: The latest alien technology allows them to abduct cows instantly,
+ this is a great tragedy for all farm owners, better watch the garden!'
+ - bugfix: Centcom's Death Commando got a paycheck and jumpsuits of quality more
+ similar to the rest of Centcom's staf- KS13 DOESN'T EXIST, THERE IS NO SUCH
+ THING AS A DEATH COMMANDO
+ Floyd / Qustinnus:
+ - balance: the bag of holding now requires a higher level of research to be unlocked
+ as well as janitor tech (trashbags of holding)
+ - balance: the bluespace bodybag is now unlocked with mini BS research
+ Jerry Derpington, baldest of the balds:
+ - rscdel: Nanotrasen has lost communication to two away mission sites that contained
+ a beach for Nanotrasen employees.
+ - rscadd: Nanotrasen has been able to locate a new away mission site that ALSO has
+ a beach. Nanotrasen employees will be able to enjoy the beach after all!
+ Jgta4444:
+ - bugfix: Dna scanner now correctly calculate its precision coefficient
+ Skoglol:
+ - bugfix: Slimes should now feed properly again.
+ TetraK1:
+ - bugfix: Suiciding with an anomaly core kills you properly
+ - rscadd: Service borgs get pipe cleaners for wire art
+ - rscadd: you can altclick to pull up pipe cleaners
+ - bugfix: Fixed cutting and joining pipe cleaners on floor tiles
+ Trilbyspaceclone and nemvar:
+ - rscadd: You can now craft more fancy boxes with cardboard.
+ XDTM:
+ - bugfix: Antimagic items now also properly work when held in hand, instead of only
+ when equipped.
+ - bugfix: Fixed abductor scientists not being able to perform advanced surgery.
+ - tweak: Quantum teleportation now makes pretty rainbow sparks instead of the normal
+ ones.
+ - bugfix: Non-bluespace teleportation (spells etc.) no longer makes sparks.
+ imsxz:
+ - balance: diseases from miasma now become stronger the more miasma there is in
+ the air
+ nemvar:
+ - rscdel: Removed all sleepers from escape shuttles and replaced them with stasis
+ units. Some shuttles have gotten surgery and new medical vendors added.
+ spookydonut:
+ - admin: Removes shuttle manipulator.
+2019-06-26:
+ 123chess456:
+ - rscadd: Non-binary changelings will now have the honorific "Mx." instead of "Mr.",
+ reflecting the Syndicate's growing acceptance of non-binary operatives.
+ FlufflyCthulu:
+ - bugfix: Fixes an issue with clown hulk simple mobs
+ Naksu:
+ - rscadd: Mining base now has a common area accessible via a new shuttle on the
+ medium-highpop maps, and a security office connecting the gulag and the mining
+ base. Gulag also has functional atmos.
+ jcll:
+ - bugfix: added geo-bypass
+ kriskog:
+ - bugfix: Space heaters no longer steal focus upon screwdrivering.
+ nemvar:
+ - bugfix: The enchanted bolt action rifle
+ - imageadd: Blood barrage has a new projectile icon.
+ - code_imp: Fixed an arcane barrage runtime
+ - rscadd: The bee sabre now has it's own suicide and no longer uses the one of the
+ captains rapier.
+ - bugfix: The bee sabre uses the correct articles and actually has icons now.
+2019-06-27:
+ Naksu:
+ - bugfix: Fixed a couple of map issues in DeltaStation
+ actioninja:
+ - bugfix: removed mech rcl from the research node so it stops spamming a warning
+ in log
+ - bugfix: cables now disconnect machines when cut
+ - bugfix: terminal linking/not linking behavior with smeses has been improved
+ - bugfix: couple of small mapping fixes
+ - tweak: changed cable coils back to 30
+ - tweak: changed the box smes room a little to prevent stacking terminals
+ - tweak: removed the rpcl from engineering on every map because it's not used for
+ wiring anymore
+2019-06-29:
+ 81Denton:
+ - bugfix: Incomplete and non-teleport reactive armors can no longer be used to complete
+ the traitor objective.
+ AffectedArc07:
+ - rscadd: You can now link your ingame account to your discord account
+ - rscadd: You can now set notify status ingame, and be notified on discord when
+ a round restarts
+ - admin: There is now an admin panel to lookup IDs to ckeys, and vice versa
+ Akrilla:
+ - bugfix: Fix bad icon state for bounty console printouts
+ - rscadd: Contract kit's specialist space suit now has its custom sprite.
+ - rscadd: Assigning to tablet now plays greeting soundclip.
+ AnturK:
+ - tweak: Quirks no longer apply to off-station roundstart antagonists.
+ CobbyzzzZzzz:
+ - balance: Stasis are now the second best option for surgery probability (surgical
+ tables are still number 1)
+ JJRcop:
+ - bugfix: Stasis lets reagents know processing was stopped, fixing some issues.
+ - tweak: Amanitin's damage only triggers when it is completely removed from your
+ system, not when processing stops.
+ JJRcop and Bobbahbrown:
+ - tweak: When attempting to say a blocked word in character you will be notified
+ which ones were blocked.
+ Krysonism:
+ - tweak: player added items now appear above the standard selection in vending machines.
+ MCterra10:
+ - bugfix: database requests for admins no longer fail on MySQL version > 8.0.2
+ Mickyan:
+ - rscadd: DIY Dish Drive Kit now available at your local bardrobe. Start saving
+ those tips!
+ - tweak: The Dish Drive no longer sends reusable items into the disposal bin
+ Shaps/Ryll:
+ - tweak: Mosin Nagants are now bulky, but can be sawed off to fit in a bag
+ ShizCalev:
+ - bugfix: Setting a defibrillator unit on fire will now make it's paddles appear
+ on fire too when pulled out!
+ - bugfix: Setting defibrillator paddles on fire will now cause the flames to run
+ along it's cables and set the main unit on fire as well.
+ Skoglol:
+ - rscadd: Heaters/freezers now support ctrl clicking to turn on and alt clicking
+ to min/max target temperature.
+ - rscadd: Heaters/freezers now shows target temperature and part status on examine.
+ Tetr4:
+ - bugfix: Turning a tile with gas effects into space now gets rid of the effects.
+ Tlaltecuhtli:
+ - code_imp: Health sensor no longer displays a giant window with 1 button on it,
+ instead can change states with alt click and use in hand.
+ - bugfix: the TB antidotes injectors now actually cure TB and have some omnizine
+ so you dont die from perfluoride
+ - tweak: stacks no longer give you a pop up window when you alt click on one on
+ the floor
+ Twaticus:
+ - rscadd: added department skirts
+ - bugfix: fixed secskirt dixel
+ XDTM:
+ - rscadd: Added a new abductor gland that randomizes blood type into a random reagent
+ periodically.
+ - rscadd: Added a new abductor gland that links to other people, and swaps their
+ position with the owner. Mind control on this gland will affect the linked person.
+ - rscadd: Added a new abductor gland that grants all access to the owner.
+ - bugfix: Abductor scientists can now properly see the true name of glands when
+ examining them.
+ - rscadd: Mind control on mindshock glands now "broadcasts" the mind control, affecting
+ bystanders but not the abductee.
+ - tweak: Species gland now has 7 mind control uses, instead of 5 (duration is still
+ 30 seconds).
+ - bugfix: Viral healing symptoms that are tied to reagents now also require a functioning
+ liver to work.
+ - tweak: Holy water, Pyrosium, Cryostilane, Napalm and Phlogiston no longer need
+ a liver to have their effects.
+ YPOQ:
+ - bugfix: Monkeys can wear collars again
+ bobbahbrown:
+ - tweak: Deaths are now logged to the game log.
+ kittymaster0:
+ - rscadd: gives scientists a chance to spawn with an awesome tie
+ nemvar:
+ - code_imp: Replaced most instances where cables referenced their maximum size with
+ a define
+ - bugfix: Turned off energy weapons can no longer cut down trees, destroy wooden
+ walls, harvest lavaland plants and make planks.
+ - refactor: get_eye_protection and get_ear_protection now looks less ugly.
+ ninjanomnom:
+ - rscadd: Lavaland atmos is no longer a preset gas mixture and varies per round
+ - tweak: Bonfire minimum oxygen content has been reduced
+ partykp:
+ - tweak: replaced the lower disposal bin in chemistry with a glass table and put
+ half of the top table contents on it (metastation).
+ plapatin, sprites by cogwerks and edited by mrdoombringer:
+ - rscadd: vomi/tg/oose
+ zxaber:
+ - balance: Mecha ballistics weapons now require ammo created from an Exosuit Fabricator
+ or the Security Protolathe, though they will start with a full magazine and
+ in most cases enough for one full reload. Reloading these weapons no longer
+ chunks your power cell. Clown (and mime) mecha equipment have not changed.
+ - balance: The SRM-8 Missile Launcher has been replaced with the BRM-6 Breaching
+ Missile Launcher in techwebs (Nukie Mauler remains equipped with the SRM-8).
+ - balance: Both Missile Launchers and the Clusterbang Launcher do not have an ammo
+ cache, and cannot be reloaded by the pilot. Once the initial loaded ammo has
+ been spent, you can use the appropriate ammo box to load the weapon directly.
+ - rscadd: Utility mechs that have a clamp equipped can load ammo from their own
+ cargo hold into other mechs.
+ - rscadd: Nuke Ops can purchase spare ammo duffel bags for their mecha weapons,
+ should they run low.
+2019-06-30:
+ Yakumo Chen:
+ - balance: Nar'Sie plushes have been purged of their heretical stuffing and can't
+ be used to invoke runes any more.
+2019-07-03:
+ AcapitalA:
+ - balance: Night Vision Goggles and certain Thermal Optics are **slightly** more
+ sensitive to bright lights.
+ CPTANT:
+ - balance: Added OD to styptic and sulfur sulfadiazine, consuming too much will
+ give you slight toxin damage on top of slight brute/burn damage.
+ - balance: oxandrolone and salicyclic acid have the threshold for their superior
+ healing capacity lowered.
+ Denton:
+ - tweak: 'Delta: Atmospheric technicians are now able to lock/unlock the SM engine''s
+ rad collectors with their IDs.'
+ - bugfix: 'Donut: Added a missing SciDrobe vending machine to the RnD "Excess Storage"
+ area.'
+ - bugfix: 'Meta: Fixed the AIsat being connected to the station''s power grid by
+ round start. Fixed Medbay intercoms with faulty presets. Removed a duplicate
+ windoor in the cargo bay that kept MULEbots from leaving their area.'
+ - bugfix: 'Mining station: Fixed unconnected air supply pipes.'
+ - bugfix: Replaced the CentCom admin storage vault door with bomb-proof shutters
+ (require CentCom Captain level access to open). Removed broken intercoms from
+ the wizard shuttle and replaced them with two headsets.
+ - bugfix: Deleted random duplicate and broken atmos piping in most maps.
+ - bugfix: 'Donutstation: The AI chamber SMES is now correctly connected to the AI
+ APC.'
+ - tweak: 'CentCom: Made the ERT pod doors and vault shutters bomb proof. Replaced
+ loose CentCom ID cards with a box of IDs.'
+ Dorsidwarf:
+ - rscadd: Nanotrasen washing machines can now extract the raw power of the cosmos
+ from bluespace crystals.
+ MadoFrog:
+ - rscadd: Red, white, and blue mech pilot jumpsuits now available in the Mech Pilot's
+ Suits Crate, under Costumes & Toys.
+ Skoglol:
+ - 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.
+ SpacePrius:
+ - rscadd: Added empty boxes.
+ - bugfix: Fixed bug where hivemind vessel awakening would not be logged.
+ - bugfix: Fixed bug where awoken hivemind vessel objectives would not be logged.
+ - tweak: slightly modified the deadchat text for awakening.
+ Tlaltecuhtli:
+ - tweak: limbs are now small
+ XDTM:
+ - rscadd: Engineering closets now start with a construction bag, which can hold
+ machine components, circuits, electronics, and cable coils.
+ actioninja:
+ - bugfix: cables are no longer lag generators when being cut
+ bandit:
+ - rscadd: Nanotrasen's clowns have begun to preserve their images by stamping eggs
+ with their NT-issued clown stamps. This is fine and normal.
+ kingofkosmos:
+ - bugfix: the russian revolver's chamber can be spun again
+ nemvar:
+ - rscadd: You can now craft white jumpskirts with cloth.
+ nervere:
+ - admin: There is now a CTF button in the check antags panel.
+ - admin: There is now a Reboot World button in the check antags panel.
+ zxaber:
+ - tweak: Dead AI players will now get a notification if they are being restored
+ while outside their body.
+2019-07-05:
+ Akrilla:
+ - rscadd: Contract kit comes with a contractor baton - a unique, lightly electrified
+ weapon to help complete your contracts.
+ - tweak: Finalized payment system for contracts; much more balanced for contractors.
+ No more extremely low paying contract sets.
+ - tweak: Generated contracts will all have unique targets, no more duplicates.
+ - tweak: Extraction droppod explosion has been removed, it'll only damage the tile
+ it lands on.
+ - bugfix: Extraction pods get sent to the jail immediately again.
+ - refactor: Refactored classic_baton code.
+ ArcaneMusic:
+ - tweak: NT staff have added new laser focusing rings onto all BSA equipment, so
+ now it looks more like a massive deadly laser, and fires more accurately.
+ Atlanta Ned:
+ - rscadd: Security can now issue citations! Spot someone committing a minor crime?
+ Fine them for it!
+ - rscadd: Got a citation? You can view and pay it at any security warrant consoles,
+ located near the brig, your local law office, or the courtroom!
+ Fikou:
+ - balance: Reports say the cult of Nar'Sie has gotten stronger, and can now convert
+ the captain when he doesn't have his mindshield. To prepare against this, the
+ CentCom religious division has trained their special holy people against conversions
+ Floyd / Qustinnus:
+ - tweak: The Nanotrasen Physological department has realized that working at a metal
+ deathbox is more stressful than it currently is. Mood has been slightly rebalanced
+ Garen:
+ - bugfix: Fixes being able to pull from belt/backpack when you are stunned or cuffed.
+ Krysonism:
+ - rscadd: Trophazole - a new hearty brute medicine.
+ - rscadd: Rhigoxane -- a new chilly burn medicine.
+ - rscadd: Thializid - a new high-stakes tox medicine.
+ - rscdel: The 3 basic trek chems are now unmixable.
+ - rscadd: IV medicine bags and blood packs are available in the medlathe.
+ - rscadd: suspicious spray bottles have been added to the chemdrobe contraband compartment.
+ - rscadd: The medical lathe can now print spray bottles.
+ - rscdel: Removed the charcoal syringes from the medkits.
+ - balance: There is now slightly less charcoal available roundstart.
+ - imageadd: Added new spray bottle & iv bag sprites.
+ - code_imp: trans_to can now react the reagents if you want.
+ Lett1:
+ - rscadd: Added a new contraband about free syndicate keys
+ Mickyan:
+ - imageadd: Coming into contact with -HONK- may have additional effects, do not
+ be alarmed
+ - tweak: For safety reasons, the administration of -HONK- may only be performed
+ by trained professionals
+ - bugfix: Self-application of -HONK- is now forbidden
+ RandolfTheMeh:
+ - code_imp: Universal Organ Damage variables and procs
+ Time-Green:
+ - bugfix: Clones no longer have their genetic sequence quantum garble fucked together
+ WJohnston:
+ - rscadd: Redesigned boxstation's SMES room. It is now part of engineering power
+ storage like it once was instead of being strangely separated from the station.
+ XDTM:
+ - rscadd: Abductors can now buy a special chem dispenser for 2 points. The machine
+ is delivered as a beacon which can be used when standing on any free tile to
+ spawn it.
+ actioninja:
+ - bugfix: The sabre sheath properly plays sounds again after who knows how long
+ - bugfix: smeses no longer link to themselves non-visibly
+ - soundadd: Add match strike sound.
+ - bugfix: Fixed a disconnected APC on the meta map satellite.
+ - rscadd: Added a scrubber to the meta engineering lobby.
+ - bugfix: cables now actually function again (I'm so sorry)
+ bandit:
+ - bugfix: Nanotrasen chefs and botanists have finally learned to stop composting
+ or grinding bowls and the like along with the food they come with.
+ - bugfix: After years of arduous training, Nanotrasen crew can now tell whether
+ an animal is dead by examining it.
+ blargety, Onule:
+ - rscadd: Added departmental sprites for circuit boards commonly used within a department.
+ For example, a SMES will have a orange base.
+ - imageadd: Adds 8 new icons for circuit boards, based on department colors.
+ - refactor: Reorganizes computer_circuits.dm and machine_circuitboard.dm based on
+ an alphabetical order divided by department.
+ granpawalton:
+ - rscadd: Breakfast foods such as eggs, donuts, coffee and so on now give a long
+ but weak positive moodie when eaten within 15 minutes of the start of a shift
+ nemvar:
+ - bugfix: Mobs with negative armor no longer get damage decreased by armor penetration.
+ - tweak: Various cosmetic and gameplay related changes to hivebots. Player controlled
+ hivebots can change their look by changing their intent to harm.
+ - bugfix: Humans now always use the correct value for limb armor.
+ - bugfix: Negative armor on objects now increases damage taken.
+ - rscadd: All chainsaws, including the null rod variants, can now be used to saw
+ off guns.
+ - code_imp: Refactored the visibility of reagents for mobs.
+ - bugfix: The air injector of the delta station incinerator now works.
+ - bugfix: Antimagic now gets used up properly
+ ninjanomnom:
+ - bugfix: Reproductive crossbreed extracts can be fed from the bio bag again
+ pireamaineach:
+ - rscadd: Added mime envirosuits, nothing special here.
+ - rscadd: Added clown envirosuits, which release space lube when they extinguish
+ the clown.
+ - rscdel: Removes code that theoretically limits plasmamen from being clowns and
+ mimes, but actually doesn't.
+ - tweak: I guess the roles now spawning with these suits is kind of notable.
+ - tweak: Reverts unlisted changes to the grey detective suit from https://github.com/tgstation/tgstation/pull/44776.
+ wesoda25:
+ - bugfix: You can no longer infinitely purify a soulstone.
+ - bugfix: Cultists can't use purified soulstones anymore.
+ zxaber:
+ - rscadd: The R&D Server Controller console now lists the entire research history,
+ including names of people who researched each item and locations it was done
+ from.
+ - rscadd: The R&D Server Controller console can now be used to disable the servers
+ if someone makes the RD upset.
+ - bugfix: Fixed the R&D servers working without power.
+ - imageadd: R&D server sprites are now slightly animated, and new sprites have been
+ added for when the server is disabled or off.
diff --git a/html/changelogs/AutoChangeLog-pr-44654.yml b/html/changelogs/AutoChangeLog-pr-44654.yml
deleted file mode 100644
index 0a9398b93ac..00000000000
--- a/html/changelogs/AutoChangeLog-pr-44654.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "XDTM"
-delete-after: True
-changes:
- - bugfix: "Fixed abductor scientists not being able to perform advanced surgery."
diff --git a/html/changelogs/AutoChangeLog-pr-44655.yml b/html/changelogs/AutoChangeLog-pr-44655.yml
deleted file mode 100644
index c384bb5eb95..00000000000
--- a/html/changelogs/AutoChangeLog-pr-44655.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "spookydonut"
-delete-after: True
-changes:
- - admin: "Removes shuttle manipulator."
diff --git a/html/changelogs/AutoChangeLog-pr-44656.yml b/html/changelogs/AutoChangeLog-pr-44656.yml
deleted file mode 100644
index b03fa8519d2..00000000000
--- a/html/changelogs/AutoChangeLog-pr-44656.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Fikou"
-delete-after: True
-changes:
- - rscadd: "NEWS REPORT: The latest alien technology allows them to abduct cows instantly, this is a great tragedy for all farm owners, better watch the garden!"
diff --git a/html/changelogs/AutoChangeLog-pr-44658.yml b/html/changelogs/AutoChangeLog-pr-44658.yml
deleted file mode 100644
index 491126e3697..00000000000
--- a/html/changelogs/AutoChangeLog-pr-44658.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Arkatos"
-delete-after: True
-changes:
- - rscadd: "Action buttons can now be dragged onto each other to swap places"
diff --git a/html/changelogs/AutoChangeLog-pr-44664.yml b/html/changelogs/AutoChangeLog-pr-44664.yml
deleted file mode 100644
index 96abe2784aa..00000000000
--- a/html/changelogs/AutoChangeLog-pr-44664.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-author: "XDTM"
-delete-after: True
-changes:
- - tweak: "Quantum teleportation now makes pretty rainbow sparks instead of the normal ones."
- - bugfix: "Non-bluespace teleportation (spells etc.) no longer makes sparks."
diff --git a/html/changelogs/AutoChangeLog-pr-44665.yml b/html/changelogs/AutoChangeLog-pr-44665.yml
deleted file mode 100644
index c95f2c93659..00000000000
--- a/html/changelogs/AutoChangeLog-pr-44665.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "nemvar"
-delete-after: True
-changes:
- - rscdel: "Removed all sleepers from escape shuttles and replaced them with stasis units. Some shuttles have gotten surgery and new medical vendors added."
diff --git a/html/changelogs/AutoChangeLog-pr-44673.yml b/html/changelogs/AutoChangeLog-pr-44673.yml
deleted file mode 100644
index a1cdfc0693f..00000000000
--- a/html/changelogs/AutoChangeLog-pr-44673.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-author: "Jerry Derpington, baldest of the balds"
-delete-after: True
-changes:
- - rscdel: "Nanotrasen has lost communication to two away mission sites that contained a beach for Nanotrasen employees."
- - rscadd: "Nanotrasen has been able to locate a new away mission site that ALSO has a beach. Nanotrasen employees will be able to enjoy the beach after all!"
diff --git a/html/changelogs/AutoChangeLog-pr-44704.yml b/html/changelogs/AutoChangeLog-pr-44704.yml
deleted file mode 100644
index 2fa52b43eb5..00000000000
--- a/html/changelogs/AutoChangeLog-pr-44704.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "TetraK1"
-delete-after: True
-changes:
- - bugfix: "Suiciding with an anomaly core kills you properly"
diff --git a/html/changelogs/AutoChangeLog-pr-44857.yml b/html/changelogs/AutoChangeLog-pr-44857.yml
new file mode 100644
index 00000000000..c80a677dbc2
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-44857.yml
@@ -0,0 +1,4 @@
+author: "WJohn"
+delete-after: True
+changes:
+ - balance: "BYOS cost increased from -2500$ to +2500$, and made a bit larger."
diff --git a/html/changelogs/AutoChangeLog-pr-44880.yml b/html/changelogs/AutoChangeLog-pr-44880.yml
new file mode 100644
index 00000000000..ef39004e1bb
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-44880.yml
@@ -0,0 +1,6 @@
+author: "Krysonism"
+delete-after: True
+changes:
+ - rscadd: "Cowboy boots have been added to the Clothesmate."
+ - rscadd: "Lizard skin boots with decent export values have been added to the crafting menu."
+ - rscadd: "Snakes, headslugs and alien larvae can now hide in cowboy boots."
diff --git a/icons/effects/beam.dmi b/icons/effects/beam.dmi
index 07315837334..350d6a55006 100644
Binary files a/icons/effects/beam.dmi and b/icons/effects/beam.dmi differ
diff --git a/icons/effects/beam_splash.dmi b/icons/effects/beam_splash.dmi
new file mode 100644
index 00000000000..d7deb3e9275
Binary files /dev/null and b/icons/effects/beam_splash.dmi differ
diff --git a/icons/mecha/mecha_ammo.dmi b/icons/mecha/mecha_ammo.dmi
new file mode 100644
index 00000000000..63bc38cfa71
Binary files /dev/null and b/icons/mecha/mecha_ammo.dmi differ
diff --git a/icons/mecha/mecha_equipment.dmi b/icons/mecha/mecha_equipment.dmi
index 029fe06342d..e9b6f1a9062 100644
Binary files a/icons/mecha/mecha_equipment.dmi and b/icons/mecha/mecha_equipment.dmi differ
diff --git a/icons/mob/animal.dmi b/icons/mob/animal.dmi
index f7de4b6197e..e551678e5a2 100644
Binary files a/icons/mob/animal.dmi and b/icons/mob/animal.dmi differ
diff --git a/icons/mob/belt.dmi b/icons/mob/belt.dmi
index 5e146226d8d..52b5a533d3f 100644
Binary files a/icons/mob/belt.dmi and b/icons/mob/belt.dmi differ
diff --git a/icons/mob/carp.dmi b/icons/mob/carp.dmi
new file mode 100644
index 00000000000..5b6138ee99a
Binary files /dev/null and b/icons/mob/carp.dmi differ
diff --git a/icons/mob/feet.dmi b/icons/mob/feet.dmi
index db12bc0cd5c..b785527ff7d 100644
Binary files a/icons/mob/feet.dmi and b/icons/mob/feet.dmi differ
diff --git a/icons/mob/head.dmi b/icons/mob/head.dmi
index dbf8f895d64..a6d6b5757ca 100644
Binary files a/icons/mob/head.dmi and b/icons/mob/head.dmi differ
diff --git a/icons/mob/hivebot.dmi b/icons/mob/hivebot.dmi
index ce37adbdfee..a23bff51243 100644
Binary files a/icons/mob/hivebot.dmi and b/icons/mob/hivebot.dmi differ
diff --git a/icons/mob/inhands/equipment/medical_lefthand.dmi b/icons/mob/inhands/equipment/medical_lefthand.dmi
index 60768e3c9ae..3ff20f67cfd 100644
Binary files a/icons/mob/inhands/equipment/medical_lefthand.dmi and b/icons/mob/inhands/equipment/medical_lefthand.dmi differ
diff --git a/icons/mob/inhands/equipment/medical_righthand.dmi b/icons/mob/inhands/equipment/medical_righthand.dmi
index 29d047382b3..a659b8c28c8 100644
Binary files a/icons/mob/inhands/equipment/medical_righthand.dmi and b/icons/mob/inhands/equipment/medical_righthand.dmi differ
diff --git a/icons/mob/inhands/weapons/melee_lefthand.dmi b/icons/mob/inhands/weapons/melee_lefthand.dmi
index 49a9bdbe5b4..50ae2fb1639 100644
Binary files a/icons/mob/inhands/weapons/melee_lefthand.dmi and b/icons/mob/inhands/weapons/melee_lefthand.dmi differ
diff --git a/icons/mob/inhands/weapons/melee_righthand.dmi b/icons/mob/inhands/weapons/melee_righthand.dmi
index d8b51d9f247..24f4e1ab821 100644
Binary files a/icons/mob/inhands/weapons/melee_righthand.dmi and b/icons/mob/inhands/weapons/melee_righthand.dmi differ
diff --git a/icons/mob/screen_gen.dmi b/icons/mob/screen_gen.dmi
index a41a2ac20ac..75911b35aa7 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 70410cc57ea..40d8e5221e0 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 e6f95bd643d..715d1645cd1 100644
Binary files a/icons/mob/uniform.dmi and b/icons/mob/uniform.dmi differ
diff --git a/icons/obj/abductor.dmi b/icons/obj/abductor.dmi
index d8968a107b0..446d813c17f 100644
Binary files a/icons/obj/abductor.dmi and b/icons/obj/abductor.dmi differ
diff --git a/icons/obj/bloodpack.dmi b/icons/obj/bloodpack.dmi
index 3a5b9fd7064..efcf670da59 100644
Binary files a/icons/obj/bloodpack.dmi and b/icons/obj/bloodpack.dmi differ
diff --git a/icons/obj/chemical.dmi b/icons/obj/chemical.dmi
index 6f52f119bad..dfc0d1e5be9 100644
Binary files a/icons/obj/chemical.dmi and b/icons/obj/chemical.dmi differ
diff --git a/icons/obj/clothing/hats.dmi b/icons/obj/clothing/hats.dmi
index 86718f2e02f..75954d87ae7 100644
Binary files a/icons/obj/clothing/hats.dmi and b/icons/obj/clothing/hats.dmi differ
diff --git a/icons/obj/clothing/shoes.dmi b/icons/obj/clothing/shoes.dmi
index 556d18cf28f..0be7d24e18f 100644
Binary files a/icons/obj/clothing/shoes.dmi and b/icons/obj/clothing/shoes.dmi differ
diff --git a/icons/obj/clothing/suits.dmi b/icons/obj/clothing/suits.dmi
index 5f7018851b6..3eef8910bb3 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 e9298bd2fba..b17805abf12 100644
Binary files a/icons/obj/clothing/uniforms.dmi and b/icons/obj/clothing/uniforms.dmi differ
diff --git a/icons/obj/contraband.dmi b/icons/obj/contraband.dmi
index f8d607f5593..af448bc8727 100644
Binary files a/icons/obj/contraband.dmi and b/icons/obj/contraband.dmi differ
diff --git a/icons/obj/food/food.dmi b/icons/obj/food/food.dmi
index 2939b7d786e..4980d31c5f8 100644
Binary files a/icons/obj/food/food.dmi and b/icons/obj/food/food.dmi differ
diff --git a/icons/obj/guns/projectile.dmi b/icons/obj/guns/projectile.dmi
index dda20ef571b..a55c0f813d2 100644
Binary files a/icons/obj/guns/projectile.dmi and b/icons/obj/guns/projectile.dmi differ
diff --git a/icons/obj/items_and_weapons.dmi b/icons/obj/items_and_weapons.dmi
index b56ccb8779a..905e09eb31f 100644
Binary files a/icons/obj/items_and_weapons.dmi and b/icons/obj/items_and_weapons.dmi differ
diff --git a/icons/obj/janitor.dmi b/icons/obj/janitor.dmi
index 610dcfdbbb9..9848482fcfa 100644
Binary files a/icons/obj/janitor.dmi and b/icons/obj/janitor.dmi differ
diff --git a/icons/obj/machines/research.dmi b/icons/obj/machines/research.dmi
index f352b12d14c..730cd7326f6 100644
Binary files a/icons/obj/machines/research.dmi and b/icons/obj/machines/research.dmi differ
diff --git a/icons/obj/module.dmi b/icons/obj/module.dmi
index 037525150e6..c0523d86fe1 100644
Binary files a/icons/obj/module.dmi and b/icons/obj/module.dmi differ
diff --git a/icons/obj/projectiles.dmi b/icons/obj/projectiles.dmi
index 37e791eb427..2b1738566bc 100644
Binary files a/icons/obj/projectiles.dmi and b/icons/obj/projectiles.dmi differ
diff --git a/icons/obj/reagentfillings.dmi b/icons/obj/reagentfillings.dmi
index 1b8dacf36da..fa74d50e519 100644
Binary files a/icons/obj/reagentfillings.dmi and b/icons/obj/reagentfillings.dmi differ
diff --git a/icons/obj/tools.dmi b/icons/obj/tools.dmi
index 1454d17a162..e9b4fbdcd2e 100644
Binary files a/icons/obj/tools.dmi and b/icons/obj/tools.dmi differ
diff --git a/sound/effects/contractorbatonhit.ogg b/sound/effects/contractorbatonhit.ogg
new file mode 100644
index 00000000000..2377267cc71
Binary files /dev/null and b/sound/effects/contractorbatonhit.ogg differ
diff --git a/sound/effects/contractstartup.ogg b/sound/effects/contractstartup.ogg
new file mode 100644
index 00000000000..7d866460507
Binary files /dev/null and b/sound/effects/contractstartup.ogg differ
diff --git a/sound/items/match_strike.ogg b/sound/items/match_strike.ogg
new file mode 100644
index 00000000000..8bf23316e1d
Binary files /dev/null and b/sound/items/match_strike.ogg differ
diff --git a/sound/weapons/contractorbatonextend.ogg b/sound/weapons/contractorbatonextend.ogg
new file mode 100644
index 00000000000..c78281bf1f9
Binary files /dev/null and b/sound/weapons/contractorbatonextend.ogg differ
diff --git a/strings/redpill.json b/strings/redpill.json
index 3f65db73e72..6a2e3d77802 100644
--- a/strings/redpill.json
+++ b/strings/redpill.json
@@ -19,7 +19,7 @@
"Nanotrasen just clones us every shift.",
"There's no biological difference between lizards and humans.",
"Why is there a floor, but no roof?",
- "The universe always ends after we reach Centcomm.",
+ "The universe always ends after we reach CentCom.",
"Everyone is controlled by strings behind a glowing screen",
"Seperation is absolute.",
"It doesn't take much for people to murder their friends.",
diff --git a/tgstation.dme b/tgstation.dme
index 9fef41a5ac8..0962d88e271 100755
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -91,6 +91,7 @@
#include "code\__DEFINES\shuttles.dm"
#include "code\__DEFINES\sight.dm"
#include "code\__DEFINES\sound.dm"
+#include "code\__DEFINES\spaceman_dmm.dm"
#include "code\__DEFINES\stat.dm"
#include "code\__DEFINES\stat_tracking.dm"
#include "code\__DEFINES\status_effects.dm"
@@ -230,6 +231,7 @@
#include "code\controllers\subsystem\communications.dm"
#include "code\controllers\subsystem\dbcore.dm"
#include "code\controllers\subsystem\dcs.dm"
+#include "code\controllers\subsystem\discord.dm"
#include "code\controllers\subsystem\disease.dm"
#include "code\controllers\subsystem\economy.dm"
#include "code\controllers\subsystem\events.dm"
@@ -325,6 +327,8 @@
#include "code\datums\world_topic.dm"
#include "code\datums\actions\beam_rifle.dm"
#include "code\datums\actions\ninja.dm"
+#include "code\datums\atmosphere\_atmosphere.dm"
+#include "code\datums\atmosphere\planetary.dm"
#include "code\datums\brain_damage\brain_trauma.dm"
#include "code\datums\brain_damage\creepy_trauma.dm"
#include "code\datums\brain_damage\hypnosis.dm"
@@ -675,6 +679,7 @@
#include "code\game\machinery\computer\security.dm"
#include "code\game\machinery\computer\station_alert.dm"
#include "code\game\machinery\computer\teleporter.dm"
+#include "code\game\machinery\computer\warrant.dm"
#include "code\game\machinery\doors\airlock.dm"
#include "code\game\machinery\doors\airlock_electronics.dm"
#include "code\game\machinery\doors\airlock_types.dm"
@@ -735,6 +740,7 @@
#include "code\game\mecha\equipment\tools\other_tools.dm"
#include "code\game\mecha\equipment\tools\weapon_bay.dm"
#include "code\game\mecha\equipment\tools\work_tools.dm"
+#include "code\game\mecha\equipment\weapons\mecha_ammo.dm"
#include "code\game\mecha\equipment\weapons\weapons.dm"
#include "code\game\mecha\medical\medical.dm"
#include "code\game\mecha\medical\odysseus.dm"
@@ -1614,6 +1620,10 @@
#include "code\modules\detectivework\evidence.dm"
#include "code\modules\detectivework\footprints_and_rag.dm"
#include "code\modules\detectivework\scanner.dm"
+#include "code\modules\discord\accountlink.dm"
+#include "code\modules\discord\manipulation.dm"
+#include "code\modules\discord\tgs_commands.dm"
+#include "code\modules\discord\toggle_notify.dm"
#include "code\modules\economy\_economy.dm"
#include "code\modules\economy\account.dm"
#include "code\modules\economy\pay_stand.dm"
@@ -2523,10 +2533,11 @@
#include "code\modules\reagents\reagent_containers\blood_pack.dm"
#include "code\modules\reagents\reagent_containers\borghydro.dm"
#include "code\modules\reagents\reagent_containers\bottle.dm"
+#include "code\modules\reagents\reagent_containers\chem_pack.dm"
#include "code\modules\reagents\reagent_containers\dropper.dm"
#include "code\modules\reagents\reagent_containers\glass.dm"
#include "code\modules\reagents\reagent_containers\hypospray.dm"
-#include "code\modules\reagents\reagent_containers\medspray.dm"
+#include "code\modules\reagents\reagent_containers\medigel.dm"
#include "code\modules\reagents\reagent_containers\patch.dm"
#include "code\modules\reagents\reagent_containers\pill.dm"
#include "code\modules\reagents\reagent_containers\spray.dm"
@@ -2713,6 +2724,7 @@
#include "code\modules\surgery\cavity_implant.dm"
#include "code\modules\surgery\core_removal.dm"
#include "code\modules\surgery\dental_implant.dm"
+#include "code\modules\surgery\experimental_dissection.dm"
#include "code\modules\surgery\eye_surgery.dm"
#include "code\modules\surgery\healing.dm"
#include "code\modules\surgery\helpers.dm"
@@ -2736,7 +2748,6 @@
#include "code\modules\surgery\advanced\viral_bonding.dm"
#include "code\modules\surgery\advanced\bioware\bioware.dm"
#include "code\modules\surgery\advanced\bioware\bioware_surgery.dm"
-#include "code\modules\surgery\advanced\bioware\experimental_dissection.dm"
#include "code\modules\surgery\advanced\bioware\ligament_hook.dm"
#include "code\modules\surgery\advanced\bioware\ligament_reinforcement.dm"
#include "code\modules\surgery\advanced\bioware\muscled_veins.dm"
diff --git a/tgui/gulp/css.js b/tgui/gulp/css.js
index bdf149ea723..504ccf4038d 100644
--- a/tgui/gulp/css.js
+++ b/tgui/gulp/css.js
@@ -18,7 +18,7 @@ export function css () {
s.rgba({oldie: true}),
s.plsfilters({oldIE: true}),
s.fontweights,
- f.min ? s.cssnano() : false,
+ ... f.min ? [s.cssnano()] : [],
]))
.pipe(g.bytediff.start())
.pipe(g.if(f.debug, g.sourcemaps.write()))
diff --git a/tools/dmitool/README.txt b/tools/dmitool/README.txt
deleted file mode 100644
index 409ab873c3d..00000000000
--- a/tools/dmitool/README.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-Uses PNGJ: https://code.google.com/p/pngj/.
-
-For help, use "java -jar dmitool.jar help".
-
-Requires Java 7.
\ No newline at end of file
diff --git a/tools/dmitool/build.gradle b/tools/dmitool/build.gradle
deleted file mode 100644
index 2e5fbc5b08e..00000000000
--- a/tools/dmitool/build.gradle
+++ /dev/null
@@ -1,16 +0,0 @@
-apply plugin: 'java'
-
-repositories {
- mavenCentral()
-}
-
-dependencies {
- compile group: 'ar.com.hjg', name: 'pngj', version: '2.1.0'
-}
-
-jar {
- from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
- manifest {
- attributes 'Main-Class': 'dmitool.Main'
- }
-}
\ No newline at end of file
diff --git a/tools/dmitool/dmimerge.sh b/tools/dmitool/dmimerge.sh
deleted file mode 100644
index dbe846fc6a9..00000000000
--- a/tools/dmitool/dmimerge.sh
+++ /dev/null
@@ -1,8 +0,0 @@
-java -jar tools/dmitool/dmitool.jar merge $1 $2 $3 $2
-if [ "$?" -gt 0 ]
-then
- echo "Unable to automatically resolve all icon_state conflicts, please merge manually."
- exit 1
-fi
-
-exit 0
diff --git a/tools/dmitool/dmitool.jar b/tools/dmitool/dmitool.jar
deleted file mode 100644
index 3e99778951d..00000000000
Binary files a/tools/dmitool/dmitool.jar and /dev/null differ
diff --git a/tools/dmitool/dmitool.py b/tools/dmitool/dmitool.py
deleted file mode 100644
index 390f0d745ff..00000000000
--- a/tools/dmitool/dmitool.py
+++ /dev/null
@@ -1,94 +0,0 @@
-""" Python 2.7 wrapper for dmitool.
-"""
-
-import os
-from subprocess import Popen, PIPE
-
-_JAVA_PATH = ["java"]
-_DMITOOL_CMD = ["-jar", "dmitool.jar"]
-
-def _dmitool_call(*dmitool_args, **popen_args):
- return Popen(_JAVA_PATH + _DMITOOL_CMD + [str(arg) for arg in dmitool_args], **popen_args)
-
-def _safe_parse(dict, key, deferred_value):
- try:
- dict[key] = deferred_value()
- except Exception as e:
- print "Could not parse property '%s': %s"%(key, e)
- return e
- return False
-
-def version():
- """ Returns the version as a string. """
- stdout, stderr = _dmitool_call("version", stdout=PIPE).communicate()
- return str(stdout).strip()
-
-def help():
- """ Returns the help text as a string. """
- stdout, stderr = _dmitool_call("help", stdout=PIPE).communicate()
- return str(stdout).strip()
-
-def info(filepath):
- """ Totally not a hack that parses the output from dmitool into a dictionary.
- May break at any moment.
- """
- subproc = _dmitool_call("info", filepath, stdout=PIPE)
- stdout, stderr = subproc.communicate()
-
- result = {}
- data = stdout.split(os.linesep)[1:]
- #for s in data: print s
-
- #parse header line
- if len(data) > 0:
- header = data.pop(0).split(",")
- #don't need to parse states, it's redundant
- _safe_parse(result, "images", lambda: int(header[0].split()[0].strip()))
- _safe_parse(result, "size", lambda: header[2].split()[1].strip())
-
- #parse state information
- states = []
- for item in data:
- if not len(item): continue
-
- stateinfo = {}
- item = item.split(",", 3)
- _safe_parse(stateinfo, "name", lambda: item[0].split()[1].strip(" \""))
- _safe_parse(stateinfo, "dirs", lambda: int(item[1].split()[0].strip()))
- _safe_parse(stateinfo, "frames", lambda: int(item[2].split()[0].strip()))
- if len(item) > 3:
- stateinfo["misc"] = item[3]
-
- states.append(stateinfo)
-
- result["states"] = states
- return result
-
-def extract_state(input_path, output_path, icon_state, direction=None, frame=None):
- """ Extracts an icon state as a png to a given path.
- If provided direction should be a string, one of S, N, E, W, SE, SW, NE, NW.
- If provided frame should be a frame number or a string of two frame number separated by a dash.
- """
- args = ["extract", input_path, icon_state, output_path]
- if direction is not None: args.extend(("direction" , str(direction)))
- if frame is not None: args.extend(("frame" , str(frame)))
- return _dmitool_call(*args)
-
-def import_state(target_path, input_path, icon_state, replace=False, delays=None, rewind=False, loop=None, ismovement=False, direction=None, frame=None):
- """ Inserts an input png given by the input_path into the target_path.
- """
- args = ["import", target_path, icon_state, input_path]
-
- if replace: args.append("nodup")
- if rewind: args.append("rewind")
- if ismovement: args.append("movement")
- if delays: args.extend(("delays", ",".join(delays)))
- if direction is not None: args.extend(("direction", direction))
- if frame is not None: args.extend(("frame", frame))
-
- if loop in ("inf", "infinity"):
- args.append("loop")
- elif loop:
- args.extend(("loopn", loop))
-
- return _dmitool_call(*args)
diff --git a/tools/dmitool/git_merge_installer.bat b/tools/dmitool/git_merge_installer.bat
deleted file mode 100644
index 18ab7c8026a..00000000000
--- a/tools/dmitool/git_merge_installer.bat
+++ /dev/null
@@ -1,6 +0,0 @@
-@echo off
-set tab=
-echo. >> ../../.git/config
-echo [merge "merge-dmi"] >> ../../.git/config
-echo %tab%name = iconfile merge driver >> ../../.git/config
-echo %tab%driver = ./tools/dmitool/dmimerge.sh %%O %%A %%B >> ../../.git/config
diff --git a/tools/dmitool/git_merge_installer.sh b/tools/dmitool/git_merge_installer.sh
deleted file mode 100755
index e0c48823b11..00000000000
--- a/tools/dmitool/git_merge_installer.sh
+++ /dev/null
@@ -1,6 +0,0 @@
-F="../../.git/config"
-
-echo '' >> $F
-echo '[merge "merge-dmi"]' >> $F
-echo ' name = iconfile merge driver' >> $F
-echo ' driver = ./tools/dmitool/dmimerge.sh %O %A %B' >> $F
diff --git a/tools/dmitool/merging.txt b/tools/dmitool/merging.txt
deleted file mode 100644
index d8943efb985..00000000000
--- a/tools/dmitool/merging.txt
+++ /dev/null
@@ -1,14 +0,0 @@
-1. Install java(http://www.java.com/en/download/index.jsp)
-2. Make sure java is in your PATH. To test this, open git bash, and type "java". If it says unknown command, you need to add JAVA/bin to your PATH variable (A guide for this can be found at https://www.java.com/en/download/help/path.xml ).
-
-Merging
-The easiest way to do merging is to install the merge driver. For this, open `-tg-station/.git/config` in a text editor, and paste the following lines to the end of it:
-
-[merge "merge-dmi"]
- name = iconfile merge driver
- driver = ./tools/dmitool/dmimerge.sh %O %A %B
-
-You may optionally instead run git_merge_installer.bat or git_merge_installer.sh which should automatically insert these lines for you at the appropriate location.
-
-After this, merging DMI files should happen automagically unless there are conflicts (an icon_state that both you and someone else changed).
-If there are conflicts, you will unfortunately still be stuck with opening both versions in the editor, and manually resolving the issues with those states.
diff --git a/tools/dmitool/src/main/java/dmitool/DMI.java b/tools/dmitool/src/main/java/dmitool/DMI.java
deleted file mode 100644
index bb560107ae9..00000000000
--- a/tools/dmitool/src/main/java/dmitool/DMI.java
+++ /dev/null
@@ -1,455 +0,0 @@
-package dmitool;
-
-import ar.com.hjg.pngj.ImageInfo;
-import ar.com.hjg.pngj.ImageLineInt;
-import ar.com.hjg.pngj.PngReader;
-import ar.com.hjg.pngj.PngWriter;
-import ar.com.hjg.pngj.PngjInputException;
-import ar.com.hjg.pngj.chunks.PngChunkPLTE;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.ArrayDeque;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.Deque;
-import java.util.HashMap;
-import java.util.List;
-
-public class DMI implements Comparator {
- int w, h;
- List images;
- int totalImages = 0;
- RGBA[] palette;
- boolean isPaletted;
-
- public DMI(int w, int h) {
- this.w = w;
- this.h = h;
- images = new ArrayList<>();
- isPaletted = false;
- palette = null;
- }
-
- public DMI(String f) throws DMIException, FileNotFoundException {
- this(new File(f));
- }
-
- public DMI(File f) throws DMIException, FileNotFoundException {
- if(f.length() == 0) { // Empty .dmi is empty file
- w = 32;
- h = 32;
- images = new ArrayList<>();
- isPaletted = false;
- palette = null;
- return;
- }
- InputStream in = new FileInputStream(f);
- PngReader pngr;
- try {
- pngr = new PngReader(in);
- } catch(PngjInputException pie) {
- throw new DMIException("Bad file format!", pie);
- }
- String descriptor = pngr.getMetadata().getTxtForKey("Description");
- String[] lines = descriptor.split("\n");
-
- if(Main.VERBOSITY > 0) System.out.println("Descriptor has " + lines.length + " lines.");
- if(Main.VERBOSITY > 3) {
- System.out.println("Descriptor:");
- System.out.println(descriptor);
- }
-
- /* length 6 is:
- # BEGIN DMI
- version = 4.0
- state = "state"
- dirs = 1
- frames = 1
- # END DMI
- */
- if(lines.length < 6) throw new DMIException(null, 0, "Descriptor too short!");
-
- if(!"# BEGIN DMI".equals(lines[0])) throw new DMIException(lines, 0, "Expected '# BEGIN DMI'");
- if(!"# END DMI".equals(lines[lines.length-1])) throw new DMIException(lines, lines.length-1, "Expected '# END DMI'");
- if(!"version = 4.0".equals(lines[1])) throw new DMIException(lines, 1, "Unknown version, expected 'version = 4.0'");
-
- this.w = 32;
- this.h = 32;
-
- int i = 2;
-
- if(lines[i].startsWith("\twidth = ")) {
- this.w = Integer.parseInt(lines[2].substring("\twidth = ".length()));
- i++;
- }
- if(lines[i].startsWith("\theight = ")) {
- this.h = Integer.parseInt(lines[3].substring("\theight = ".length()));
- i++;
- }
-
- List states = new ArrayList<>();
-
- while(i < lines.length - 1) {
- long imagesInState = 1;
- if(!lines[i].startsWith("state = \"") || !lines[i].endsWith("\"")) throw new DMIException(lines, i, "Error reading state string");
- String stateName = lines[i].substring("state = \"".length(), lines[i].length()-1);
- i++;
- int dirs = 1;
- int frames = 1;
- float[] delays = null;
- boolean rewind = false;
- int loop = -1;
- String hotspot = null;
- boolean movement = false;
- while(lines[i].startsWith("\t")) {
- if(lines[i].startsWith("\tdirs = ")) {
- dirs = Integer.parseInt(lines[i].substring("\tdirs = ".length()));
- imagesInState *= dirs;
- i++;
- } else if(lines[i].startsWith("\tframes = ")) {
- frames = Integer.parseInt(lines[i].substring("\tframes = ".length()));
- imagesInState *= frames;
- i++;
- } else if(lines[i].startsWith("\tdelay = ")) {
- String delayString = lines[i].substring("\tdelay = ".length());
- String[] delayVals = delayString.split(",");
- delays = new float[delayVals.length];
- for(int d=0; d 0) System.out.println(pal.getNentries() + " palette entries");
-
- palette = new RGBA[pal.getNentries()];
- int[] rgb = new int[3];
- for(int q=0; q 0) System.out.println("Non-paletted image");
- }
-
- int iw = pngr.imgInfo.cols;
- int ih = pngr.imgInfo.rows;
-
- if(totalImages > iw * ih)
- throw new DMIException(null, 0, "Impossible number of images!");
-
- if(Main.VERBOSITY > 0) System.out.println("Image size " + iw+"x"+ih);
- int[][] px = new int[ih][];
-
- for(int y=0; y statesY)
- // this should NEVER happen, we pre-check it
- throw new DMIException(null, 0, "CRITICAL: End of image reached with states to go!");
- }
- }
- if(is.delays != null) {
- if((Main.STRICT && is.delays.length*is.dirs != img.length) || is.delays.length*is.dirs < img.length)
- throw new DMIException(null, 0, "Delay array size mismatch: " + is.delays.length*is.dirs + " vs " + img.length + "!");
- }
- is.images = img;
- }
- }
-
- public IconState getIconState(String name) {
- for(IconState is: images) {
- if(is.name.equals(name)) {
- return is;
- }
- }
- return null;
- }
-
- /**
- * Makes a copy, unless name is null.
- */
- public void addIconState(String name, IconState is) {
- if(name == null) {
- images.add(is);
- totalImages += is.dirs * is.frames;
- } else {
- IconState newState = (IconState)is.clone();
- newState.name = name;
- images.add(newState);
- totalImages += is.dirs * is.frames;
- }
- }
-
- public boolean removeIconState(String name) {
- for(IconState is: images) {
- if(is.name.equals(name)) {
- images.remove(is);
- totalImages -= is.dirs * is.frames;
- return true;
- }
- }
- return false;
- }
-
- public boolean setIconState(IconState is) {
- for(int i=0; i 0) System.out.println("Fixing PNG chunks...");
- out.writeInt(in.readInt());
- out.writeInt(in.readInt());
-
- Deque notZTXT = new ArrayDeque<>();
-
- PNGChunk c = null;
-
- while(c == null || c.type != IEND) {
- c = new PNGChunk(in);
- if(c.type == zTXt && notZTXT != null) {
- PNGChunk cc = null;
- while(cc == null || cc.type != IHDR) {
- cc = notZTXT.pop();
- cc.write(out);
- }
- c.write(out);
- while(notZTXT.size() != 0) {
- PNGChunk pc = notZTXT.pop();
- pc.write(out);
- }
- notZTXT = null;
- } else if(notZTXT != null) {
- notZTXT.add(c);
- } else {
- c.write(out);
- }
- }
- if(Main.VERBOSITY > 0) System.out.println("Chunks fixed.");
- }
-
- @Override public int compare(IconState arg0, IconState arg1) {
- return arg0.name.compareTo(arg1.name);
- }
-
- public void writeDMI(OutputStream os) throws IOException {
- writeDMI(os, false);
- }
- public void writeDMI(OutputStream os, boolean sortStates) throws IOException {
- if(totalImages == 0) { // Empty .dmis are empty files
- os.close();
- return;
- }
-
- // Setup chunk-fix buffer
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
-
- if(sortStates) {
- Collections.sort(images, this);
- }
-
- // Write the dmi into the buffer
- int sx = (int)Math.ceil(Math.sqrt(totalImages));
- int sy = totalImages / sx;
- if(sx*sy < totalImages) {
- sy++;
- }
- if(Main.VERBOSITY > 0) System.out.println("Image size: " + w + "x" + h + "; number of images " + sx + "x" + sy + " (" + totalImages + ")");
- int ix = sx * w;
- int iy = sy * h;
- ImageInfo ii = new ImageInfo(ix, iy, 8, true);
- PngWriter out = new PngWriter(baos, ii);
- out.setCompLevel(9); // Maximum compression
- String description = getDescriptor();
- if(Main.VERBOSITY > 0) System.out.println("Descriptor has " + (description.split("\n").length) + " lines.");
- out.getMetadata().setText("Description", description, true, true);
-
- Image[][] img = new Image[sx][sy];
- {
- int k = 0;
- int r = 0;
- for(IconState is: images) {
- for(Image i: is.images) {
- img[k++][r] = i;
-
- if(k == sx) {
- k = 0;
- r++;
- }
- }
- }
- }
-
- for(int irow=0; irow myIS = new HashMap<>();
- HashMap dmiIS = new HashMap<>();
-
- for(IconState is: images) {
- myIS.put(is.name, is);
- }
- for(IconState is: dmi.images) {
- dmiIS.put(is.name, is);
- }
- if(!myIS.keySet().equals(dmiIS.keySet())) return false;
- for(String s: myIS.keySet()) {
- if(!myIS.get(s).equals(dmiIS.get(s))) return false;
- }
-
- return true;
- }
-}
diff --git a/tools/dmitool/src/main/java/dmitool/DMIDiff.java b/tools/dmitool/src/main/java/dmitool/DMIDiff.java
deleted file mode 100644
index 431d9c1d15a..00000000000
--- a/tools/dmitool/src/main/java/dmitool/DMIDiff.java
+++ /dev/null
@@ -1,194 +0,0 @@
-package dmitool;
-
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-public class DMIDiff {
- Map newIconStates;
- Map modifiedIconStates = new HashMap<>();
- Set removedIconStates;
-
- DMIDiff() {
- newIconStates = new HashMap<>();
- removedIconStates = new HashSet<>();
- }
-
- public DMIDiff(DMI base, DMI mod) {
- if(base.h != mod.h || base.w != mod.w) throw new IllegalArgumentException("Cannot compare non-identically-sized DMIs!");
-
- HashMap baseIS = new HashMap<>();
- for(IconState is: base.images) {
- baseIS.put(is.name, is);
- }
-
- HashMap modIS = new HashMap<>();
- for(IconState is: mod.images) {
- modIS.put(is.name, is);
- }
-
- newIconStates = ((HashMap)modIS.clone());
- for(String s: baseIS.keySet()) {
- newIconStates.remove(s);
- }
-
- removedIconStates = new HashSet<>();
- removedIconStates.addAll(baseIS.keySet());
- removedIconStates.removeAll(modIS.keySet());
-
- Set retainedStates = new HashSet<>();
- retainedStates.addAll(baseIS.keySet());
- retainedStates.retainAll(modIS.keySet());
-
- for(String s: retainedStates) {
- if(!baseIS.get(s).equals(modIS.get(s))) {
- modifiedIconStates.put(s, new IconStateDiff(baseIS.get(s), modIS.get(s)));
- }
- }
- }
- /**
- * ASSUMES NO MERGE CONFLICTS - MERGE DIFFS FIRST.
- */
- public void applyToDMI(DMI dmi) {
- for(String s: removedIconStates) {
- dmi.removeIconState(s);
- }
- for(String s: modifiedIconStates.keySet()) {
- dmi.setIconState(modifiedIconStates.get(s).newState);
- }
- for(String s: newIconStates.keySet()) {
- dmi.addIconState(null, newIconStates.get(s));
- }
- }
-
- /**
- * @param other The diff to merge with
- * @param conflictDMI A DMI to add conflicted icon_states to
- * @param merged An empty DMIDiff to merge into
- * @param aName The log name for this diff
- * @param bName The log name for {@code other}
- * @return A Set containing all icon_states which conflicted, along with what was done in each diff, in the format "icon_state: here|there"; here and there are one of "added", "modified", and "removed"
- */
- public Set mergeDiff(DMIDiff other, DMI conflictDMI, DMIDiff merged, String aName, String bName) {
- HashSet myTouched = new HashSet<>();
- myTouched.addAll(removedIconStates);
- myTouched.addAll(newIconStates.keySet());
- myTouched.addAll(modifiedIconStates.keySet());
-
- HashSet otherTouched = new HashSet<>();
- otherTouched.addAll(other.removedIconStates);
- otherTouched.addAll(other.newIconStates.keySet());
- otherTouched.addAll(other.modifiedIconStates.keySet());
-
- HashSet bothTouched = (HashSet)myTouched.clone();
- bothTouched.retainAll(otherTouched); // this set now contains the list of icon_states that *both* diffs modified, which we'll put in conflictDMI for manual merge (unless they were deletions
-
- if(Main.VERBOSITY > 0) {
- System.out.println("a: " + Arrays.toString(myTouched.toArray()));
- System.out.println("b: " + Arrays.toString(otherTouched.toArray()));
- System.out.println("both: " + Arrays.toString(bothTouched.toArray()));
- }
-
- HashSet whatHappened = new HashSet<>();
-
- for(String s: bothTouched) {
- String here, there;
- if(removedIconStates.contains(s)) {
- here = "removed";
- } else if(newIconStates.containsKey(s)) {
- here = "added";
- } else if(modifiedIconStates.containsKey(s)) {
- here = "modified";
- } else {
- System.out.println("Unknown error; state="+s);
- here = "???";
- }
-
- if(other.removedIconStates.contains(s)) {
- there = "removed";
- } else if(other.newIconStates.containsKey(s)) {
- there = "added";
- } else if(other.modifiedIconStates.containsKey(s)) {
- there = "modified";
- } else {
- System.out.println("Unknown error; state="+s);
- there = "???";
- }
-
- whatHappened.add(s + ": " + here + "|" + there);
- }
-
- // Removals
- for(String s: removedIconStates) {
- if(!bothTouched.contains(s)) {
- merged.removedIconStates.add(s);
- }
- }
- for(String s: other.removedIconStates) {
- if(!bothTouched.contains(s)) {
- merged.removedIconStates.add(s);
- }
- }
-
- // Modifications
- for(String s: modifiedIconStates.keySet()) {
- if(!bothTouched.contains(s)) {
- merged.modifiedIconStates.put(s, modifiedIconStates.get(s));
- } else {
- conflictDMI.addIconState(aName + "|" + s, modifiedIconStates.get(s).newState);
- }
- }
- for(String s: other.modifiedIconStates.keySet()) {
- if(!bothTouched.contains(s)) {
- merged.modifiedIconStates.put(s, other.modifiedIconStates.get(s));
- } else {
- conflictDMI.addIconState(bName + "|" + s, other.modifiedIconStates.get(s).newState);
- }
- }
-
- // Additions
- for(String s: newIconStates.keySet()) {
- if(!bothTouched.contains(s)) {
- merged.newIconStates.put(s, newIconStates.get(s));
- } else {
- conflictDMI.addIconState(aName + s, newIconStates.get(s));
- }
- }
- for(String s: other.newIconStates.keySet()) {
- if(!bothTouched.contains(s)) {
- merged.newIconStates.put(s, other.newIconStates.get(s));
- } else {
- conflictDMI.addIconState(bName + s, other.newIconStates.get(s));
- }
- }
-
- return whatHappened;
- }
-
- @Override public String toString() {
- String s = "";
- String t = "\t";
- String q = "\"";
- String n = "\n";
- if(!removedIconStates.isEmpty()) {
- s += "Removed:\n";
- for(String state: removedIconStates)
- s += t + q + state + q + n;
- }
- if(!modifiedIconStates.isEmpty()) {
- s += "Modified:\n";
- for(String state: modifiedIconStates.keySet())
- s += t + q + state + q + " [" + modifiedIconStates.get(state).toString() + "]\n";
- }
- if(!newIconStates.isEmpty()) {
- s += "Added:\n";
- for(String state: newIconStates.keySet())
- s += t + q + state + q + " " + newIconStates.get(state).infoStr() + n;
- }
- if("".equals(s))
- return "No changes";
- return s;
- }
-}
\ No newline at end of file
diff --git a/tools/dmitool/src/main/java/dmitool/DMIException.java b/tools/dmitool/src/main/java/dmitool/DMIException.java
deleted file mode 100644
index e9293162894..00000000000
--- a/tools/dmitool/src/main/java/dmitool/DMIException.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package dmitool;
-
-public class DMIException extends Exception {
- String[] desc = null;
- int line = 0;
- public DMIException(String[] descriptor, int line, String what) {
- super(what);
- desc = descriptor;
- this.line = line;
- }
- public DMIException(String what) {
- super(what);
- }
- public DMIException(String what, Exception cause) {
- super(what, cause);
- }
-
- @Override public String getMessage() {
- if(desc != null)
- return "\"" + desc[line] + "\" - " + super.getMessage();
-
- return super.getMessage();
- }
-}
\ No newline at end of file
diff --git a/tools/dmitool/src/main/java/dmitool/IconState.java b/tools/dmitool/src/main/java/dmitool/IconState.java
deleted file mode 100644
index a214f5d621a..00000000000
--- a/tools/dmitool/src/main/java/dmitool/IconState.java
+++ /dev/null
@@ -1,281 +0,0 @@
-package dmitool;
-
-import java.util.Arrays;
-import ar.com.hjg.pngj.ImageInfo;
-import ar.com.hjg.pngj.ImageLineInt;
-import ar.com.hjg.pngj.PngWriter;
-import ar.com.hjg.pngj.PngReader;
-import ar.com.hjg.pngj.PngjInputException;
-import java.io.InputStream;
-import java.io.OutputStream;
-
-public class IconState {
- String name;
- int dirs;
- int frames;
- float[] delays;
- Image[] images; // dirs come first
- boolean rewind;
- int loop;
- String hotspot;
- boolean movement;
-
- public String getInfoLine() {
- String extraInfo = "";
- if(rewind) extraInfo += " rewind";
- if(frames != 1) {
- extraInfo += " loop(" + (loop==-1 ? "infinite" : loop) + ")";
- }
- if(hotspot != null) extraInfo += " hotspot('" + hotspot + "')";
- if(movement) extraInfo += " movement";
- if(extraInfo.equals("")) {
- return String.format("state \"%s\", %d dir(s), %d frame(s)", name, dirs, frames);
- } else {
- return String.format("state \"%s\", %d dir(s), %d frame(s),%s", name, dirs, frames, extraInfo);
- }
- }
-
- @Override public IconState clone() {
- IconState is = new IconState(name, dirs, frames, images.clone(), delays==null ? null : delays.clone(), rewind, loop, hotspot, movement);
- is.delays = delays != null ? delays.clone() : null;
- is.rewind = rewind;
-
- return is;
- }
-
- public IconState(String name, int dirs, int frames, Image[] images, float[] delays, boolean rewind, int loop, String hotspot, boolean movement) {
- if(delays != null) {
- if(Main.STRICT && delays.length != frames) {
- throw new IllegalArgumentException("Delays and frames must be the same length!");
- }
- }
- this.name = name;
- this.dirs = dirs;
- this.frames = frames;
- this.images = images;
- this.rewind = rewind;
- this.loop = loop;
- this.hotspot = hotspot;
- this.delays = delays;
- this.movement = movement;
- }
- void setDelays(float[] delays) {
- this.delays = delays;
- }
- void setRewind(boolean b) {
- rewind = b;
- }
- @Override public boolean equals(Object obj) {
- if(obj == this) return true;
- if(!(obj instanceof IconState)) return false;
-
- IconState is = (IconState)obj;
-
- if(!is.name.equals(name)) return false;
- if(is.dirs != dirs) return false;
- if(is.frames != frames) return false;
- if(!Arrays.equals(images, is.images)) return false;
- if(is.rewind != rewind) return false;
- if(is.loop != loop) return false;
- if(!Arrays.equals(delays, is.delays)) return false;
- if(!(is.hotspot == null ? hotspot == null : is.hotspot.equals(hotspot))) return false;
- if(is.movement != movement) return false;
-
- return true;
- }
- public String infoStr() {
- return "[" + frames + " frame(s), " + dirs + " dir(s)]";
- }
- public String getDescriptorFragment() {
- String s = "";
- String q = "\"";
- String n = "\n";
- s += "state = " + q + name + q + n;
- s += "\tdirs = " + dirs + n;
- s += "\tframes = " + frames + n;
- if(delays != null) {
- s += "\tdelay = " + delayArrayToString(delays) + n;
- }
- if(rewind) {
- s += "\trewind = 1\n";
- }
- if(loop != -1) {
- s += "\tloop = " + loop + n;
- }
- if(hotspot != null) {
- s += "\thotspot = " + hotspot + n;
- }
- if(movement) {
- s += "\tmovement = 1\n";
- }
- return s;
- }
-
- private static String delayArrayToString(float[] d) {
- String s = "";
- for(float f: d) {
- s += ","+f;
- }
- return s.substring(1);
- }
-
- /**
- * Dump the state to the given OutputStream in PNG format. Frames will be dumped along the X axis of the image, and directions will be dumped along the Y.
- */
- public void dumpToPNG(OutputStream outS, int minDir, int maxDir, int minFrame, int maxFrame) {
- int totalDirs = maxDir - minDir + 1;
- int totalFrames = maxFrame - minFrame + 1;
-
- int w = images[minDir + minFrame * this.dirs].w;
- int h = images[minDir + minFrame * this.dirs].h;
-
- if(Main.VERBOSITY > 0) System.out.println("Writing " + totalDirs + " dir(s), " + totalFrames + " frame(s), " + totalDirs*totalFrames + " image(s) total.");
- ImageInfo ii = new ImageInfo(totalFrames * w, totalDirs * h, 8, true);
- PngWriter out = new PngWriter(outS, ii);
- out.setCompLevel(9);
-
- Image[][] img = new Image[totalFrames][totalDirs];
- {
- for(int i=0; i= frames)
- throw new IllegalArgumentException("Provided frame is out of range: " + frame);
- if(dir < 0 || dir >= dirs)
- throw new IllegalArgumentException("Provided dir is out of range: " + dir);
-
- images[getIndex(dir, frame)] = splice;
- }
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/tools/dmitool/src/main/java/dmitool/IconStateDiff.java b/tools/dmitool/src/main/java/dmitool/IconStateDiff.java
deleted file mode 100644
index a5d30db7fe0..00000000000
--- a/tools/dmitool/src/main/java/dmitool/IconStateDiff.java
+++ /dev/null
@@ -1,126 +0,0 @@
-package dmitool;
-
-import java.util.HashMap;
-import java.util.HashSet;
-
-public class IconStateDiff {
- static class ISAddress {
- int dir;
- int frame;
-
- public ISAddress(int dir, int frame) {
- this.dir = dir;
- this.frame = frame;
- }
-
- public String infoStr(int maxDir, int maxFrame) {
- if(maxDir == 1 && maxFrame == 1) {
- return "";
- } else if(maxDir == 1) {
- return "{" + frame + "}";
- } else if(maxFrame == 1) {
- return "{" + Main.dirs[dir] + "}";
- } else {
- return "{" + Main.dirs[dir] + " " + frame + "}";
- }
- }
- }
- int oldFrameCount = 0;
- int oldDirectionCount = 0;
- boolean oldRewind = false;
- int oldLoop = -1;
- String oldHotspot = null;
-
- int newFrameCount = 0;
- int newDirectionCount = 0;
- boolean newRewind = false;
- int newLoop = -1;
- String newHotspot = null;
-
- IconState newState;
- HashMap modifiedFrames = new HashMap<>();
- HashMap newFrames = new HashMap<>();
- HashSet removedFrames = new HashSet<>();
-
- public IconStateDiff(IconState base, IconState mod) {
- int maxDir = Math.max(base.dirs, mod.dirs);
- int maxFrame = Math.max(base.frames, mod.frames);
-
- oldFrameCount = base.frames;
- oldDirectionCount = base.dirs;
- oldRewind = base.rewind;
- oldLoop = base.loop;
- oldHotspot = base.hotspot;
-
- newFrameCount = mod.frames;
- newDirectionCount = mod.dirs;
- newRewind = mod.rewind;
- newLoop = mod.loop;
- newHotspot = mod.hotspot;
-
- newState = mod;
-
- Image baseI, modI;
- for(int d=0; d d && base.frames > f) {
- baseI = base.images[f * base.dirs + d];
- } else baseI = null;
- if(mod.dirs > d && mod.frames > f) {
- modI = mod.images[f * mod.dirs + d];
- } else modI = null;
-
- if(baseI == null && modI == null) continue;
-
- if(baseI == null) newFrames.put(new ISAddress(d, f), modI);
- else if(modI == null) removedFrames.add(new ISAddress(d, f));
- else if(!baseI.equals(modI)) {
- modifiedFrames.put(new ISAddress(d, f), modI);
- }
- }
- }
- }
-
- @Override public String toString() {
- String s = "";
- String tmp;
-
- if(newDirectionCount != oldDirectionCount)
- s += " | dirs " + oldDirectionCount + "->" + newDirectionCount;
-
- if(newFrameCount != oldFrameCount)
- s += " | frames " + oldFrameCount + "->" + newFrameCount;
-
- if(newRewind != oldRewind) {
- s += " | rewind " + oldRewind + "->" + newRewind;
- }
-
- if(newLoop != oldLoop) {
- s += " | loop " + oldLoop + "->" + newLoop;
- }
-
- if(newHotspot == null ? oldHotspot != null : !newHotspot.equals(oldHotspot)) {
- s += " | hotspot " + oldHotspot + "->" + newHotspot;
- }
-
- if(!modifiedFrames.isEmpty()) {
- int total_frames = Math.min(oldFrameCount, newFrameCount) * Math.min(oldDirectionCount, newDirectionCount);
- tmp = "";
- for(ISAddress isa: modifiedFrames.keySet()) {
- String str = isa.infoStr(oldDirectionCount, oldFrameCount);
- if(!"".equals(str)) {
- tmp += ", " + str;
- }
- }
- if(!"".equals(tmp)) {
- s += " | modified " + modifiedFrames.size() + " of " + total_frames + ": " + tmp.substring(1);
- } else {
- s += " | modified " + modifiedFrames.size() + " of " + total_frames;
- }
- }
-
- if("".equals(s))
- return "No change";
- return s.substring(3);
- }
-}
\ No newline at end of file
diff --git a/tools/dmitool/src/main/java/dmitool/Image.java b/tools/dmitool/src/main/java/dmitool/Image.java
deleted file mode 100644
index 2ea7ff41920..00000000000
--- a/tools/dmitool/src/main/java/dmitool/Image.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package dmitool;
-
-import java.io.IOException;
-import java.io.OutputStream;
-
-public abstract class Image {
- int w, h;
-
- abstract RGBA getPixel(int x, int y);
-
- public Image(int w, int h) {
- this.w = w;
- this.h = h;
- }
-
- @Override public boolean equals(Object obj) {
- if(obj == this) return true;
- if(!(obj instanceof Image)) return false;
-
- Image im = (Image) obj;
-
- if(w != im.w || h != im.h) return false;
-
- for(int i=0; i argq = new ArrayDeque<>();
- for(String s: args) {
- argq.addLast(s);
- }
- if(argq.size() == 0) {
- System.out.println("No command found; use 'help' for help");
- return;
- }
- String switches = argq.peekFirst();
- if(switches.startsWith("-")) {
- for(char c: switches.substring(1).toCharArray()) {
- switch(c) {
- case 'v': VERBOSITY++; break;
- case 'q': VERBOSITY--; break;
- case 'S': STRICT = true; break;
- }
- }
- argq.pollFirst();
- }
- String op = argq.pollFirst();
-
- switch(op) {
- case "diff": {
- if(argq.size() < 2) {
- System.out.println("Insufficient arguments for command!");
- System.out.println(helpStr);
- return;
- }
- String a = argq.pollFirst();
- String b = argq.pollFirst();
-
- if(VERBOSITY >= 0) System.out.println("Loading " + a);
- DMI dmi = doDMILoad(a);
- if(VERBOSITY >= 0) dmi.printInfo();
-
- if(VERBOSITY >= 0) System.out.println("Loading " + b);
- DMI dmi2 = doDMILoad(b);
- if(VERBOSITY >= 0) dmi2.printInfo();
-
- DMIDiff dmid = new DMIDiff(dmi, dmi2);
- System.out.println(dmid);
- break;
- }
- case "sort": {
- if(argq.size() < 1) {
- System.out.println("Insufficient arguments for command!");
- System.out.println(helpStr);
- return;
- }
- String f = argq.pollFirst();
-
- if(VERBOSITY >= 0) System.out.println("Loading " + f);
- DMI dmi = doDMILoad(f);
- if(VERBOSITY >= 0) dmi.printInfo();
-
- if(VERBOSITY >= 0) System.out.println("Saving " + f);
- dmi.writeDMI(new FileOutputStream(f), true);
- break;
- }
- case "merge": {
- if(argq.size() < 4) {
- System.out.println("Insufficient arguments for command!");
- System.out.println(helpStr);
- return;
- }
- String baseF = argq.pollFirst(),
- aF = argq.pollFirst(),
- bF = argq.pollFirst(),
- mergedF = argq.pollFirst();
- if(VERBOSITY >= 0) System.out.println("Loading " + baseF);
- DMI base = doDMILoad(baseF);
- if(VERBOSITY >= 0) base.printInfo();
-
- if(VERBOSITY >= 0) System.out.println("Loading " + aF);
- DMI aDMI = doDMILoad(aF);
- if(VERBOSITY >= 0) aDMI.printInfo();
-
- if(VERBOSITY >= 0) System.out.println("Loading " + bF);
- DMI bDMI = doDMILoad(bF);
- if(VERBOSITY >= 0) bDMI.printInfo();
-
- DMIDiff aDiff = new DMIDiff(base, aDMI);
- DMIDiff bDiff = new DMIDiff(base, bDMI);
- DMIDiff mergedDiff = new DMIDiff();
- DMI conflictDMI = new DMI(32, 32);
-
- Set cf = aDiff.mergeDiff(bDiff, conflictDMI, mergedDiff, aF, bF);
-
- mergedDiff.applyToDMI(base);
-
- base.writeDMI(new FileOutputStream(mergedF));
-
- if(!cf.isEmpty()) {
- if(VERBOSITY >= 0) for(String s: cf) {
- System.out.println(s);
- }
- conflictDMI.writeDMI(new FileOutputStream(mergedF + ".conflict.dmi"), true);
- System.out.println("Add/modify conflicts placed in '" + mergedF + ".conflict.dmi'");
- System.exit(1); // Git expects non-zero on merge conflict
- } else {
- System.out.println("No conflicts");
- System.exit(0);
- }
- break;
- }
- case "extract": {
- if(argq.size() < 3) {
- System.out.println("Insufficient arguments for command!");
- System.out.println(helpStr);
- return;
- }
- String file = argq.pollFirst(),
- state = argq.pollFirst(),
- outFile = argq.pollFirst();
-
- DMI dmi = doDMILoad(file);
- if(VERBOSITY >= 0) dmi.printInfo();
-
- IconState is = dmi.getIconState(state);
- if(is == null) {
- System.out.println("icon_state '"+state+"' does not exist!");
- return;
- }
- // minDir, Maxdir, minFrame, Maxframe
- int mDir=0, Mdir=is.dirs-1;
- int mFrame=0, Mframe=is.frames-1;
-
- while(argq.size() > 1) {
- String arg = argq.pollFirst();
-
- switch(arg) {
- case "d":
- case "dir":
- case "dirs":
- case "direction":
- case "directions":
- String dString = argq.pollFirst();
- if(dString.contains("-")) {
- String[] splitD = dString.split("-");
- if(splitD.length == 2) {
- mDir = parseDir(splitD[0], is);
- Mdir = parseDir(splitD[1], is);
- } else {
- System.out.println("Illegal dir string: '" + dString + "'!");
- return;
- }
- } else {
- mDir = parseDir(dString, is);
- Mdir = mDir;
- }
- // Invalid value check, warnings are printed in parseDir()
- if(mDir == -1 || Mdir == -1) return;
- if(Mdir < mDir) {
- System.out.println("Maximum dir greater than minimum dir!");
- System.out.println("Textual direction order is S, N, E, W, SE, SW, NE, NW increasing 0 (S) to 7 (NW)");
- return;
- }
- break;
- case "f":
- case "frame":
- case "frames":
- String fString = argq.pollFirst();
- if(fString.contains("-")) {
- String[] splitF = fString.split("-");
- if(splitF.length == 2) {
- mFrame = parseFrame(splitF[0], is);
- Mframe = parseFrame(splitF[1], is);
- } else {
- System.out.println("Illegal frame string: '" + fString + "'!");
- return;
- }
- } else {
- mFrame = parseFrame(fString, is);
- Mframe = mFrame;
- }
- // Invalid value check, warnings are printed in parseFrame()
- if(mFrame == -1 || Mframe == -1) return;
- if(Mframe < mFrame) {
- System.out.println("Maximum frame greater than minimum frame!");
- return;
- }
- break;
- default:
- System.out.println("Unknown argument '" + arg + "' detected, ignoring.");
- }
- }
- if(!argq.isEmpty()) {
- System.out.println("Extra argument '" + argq.pollFirst() + "' detected, ignoring.");
- }
- is.dumpToPNG(new FileOutputStream(outFile), mDir, Mdir, mFrame, Mframe);
- break;
- }
- case "import": {
- if(argq.size() < 3) {
- System.out.println("Insufficient arguments for command!");
- System.out.println(helpStr);
- return;
- }
- String dmiFile = argq.pollFirst(),
- stateName = argq.pollFirst(),
- pngFile = argq.pollFirst();
-
- boolean noDup = false;
- boolean rewind = false;
- int loop = 0;
- boolean movement = false;
- String hotspot = null;
- float[] delays = null;
- String replaceDir = null;
- String replaceFrame = null;
- while(!argq.isEmpty()) {
- String s = argq.pollFirst();
- switch(s.toLowerCase()) {
- case "nodup":
- case "nd":
- case "n":
- noDup = true;
- break;
- case "rewind":
- case "rw":
- case "r":
- rewind = true;
- break;
- case "loop":
- case "lp":
- case "l":
- loop = -1;
- break;
- case "loopn":
- case "lpn":
- case "ln":
- if(!argq.isEmpty()) {
- String loopTimes = argq.pollFirst();
- try {
- loop = Integer.parseInt(loopTimes);
- } catch(NumberFormatException nfe) {
- System.out.println("Illegal number '" + loopTimes + "' as argument to '" + s + "'!");
- return;
- }
- } else {
- System.out.println("Argument '" + s + "' requires a numeric argument following it!");
- return;
- }
- break;
- case "movement":
- case "move":
- case "mov":
- case "m":
- movement = true;
- break;
- case "delays":
- case "delay":
- case "del":
- case "d":
- if(!argq.isEmpty()) {
- String delaysString = argq.pollFirst();
- String[] delaysSplit = delaysString.split(",");
- delays = new float[delaysSplit.length];
- for(int i=0; i= 0) System.out.println("Loading " + dmiFile);
- DMI toImportTo = doDMILoad(dmiFile);
- if(VERBOSITY >= 0) toImportTo.printInfo();
- IconState is = IconState.importFromPNG(toImportTo, new FileInputStream(pngFile), stateName, delays, rewind, loop, hotspot, movement);
-
- //image insertion
- if(replaceDir != null || replaceFrame != null) {
-
- IconState targetIs = toImportTo.getIconState(stateName);
- if(targetIs == null) {
- System.out.println("'direction' or 'frame' specified and no icon state '" + stateName + "' found, aborting!");
- return;
- }
- if(is.images.length == 0) {
- System.out.println("'direction' or 'frame' specified and imported is empty, aborting!");
- return;
- }
-
- if(!noDup) targetIs = targetIs.clone();
-
- int dirToReplace, frameToReplace;
- if(replaceDir != null && replaceFrame != null) {
- frameToReplace = parseFrame(replaceFrame, targetIs);
- dirToReplace = parseDir(replaceDir, targetIs);
- targetIs.insertImage(dirToReplace, frameToReplace, is.images[0]);
- }
- else if(replaceDir != null) {
- dirToReplace = parseDir(replaceDir, targetIs);
- targetIs.insertDir(dirToReplace, is.images);
- }
- else if(replaceFrame != null) {
- frameToReplace = parseFrame(replaceFrame, targetIs);
- targetIs.insertFrame(frameToReplace, is.images);
- }
-
- if(!noDup) toImportTo.addIconState(null, targetIs);
- }
- else {
- if(noDup) {
- if(!toImportTo.setIconState(is)) {
- toImportTo.addIconState(null, is);
- }
- } else {
- toImportTo.addIconState(null, is);
- }
- }
-
- if(VERBOSITY >= 0) toImportTo.printInfo();
-
- if(VERBOSITY >= 0) System.out.println("Saving " + dmiFile);
- toImportTo.writeDMI(new FileOutputStream(dmiFile));
- break;
- }
- case "verify": {
- if(argq.size() < 1) {
- System.out.println("Insufficient arguments for command!");
- System.out.println(helpStr);
- return;
- }
- String vF = argq.pollFirst();
- if(VERBOSITY >= 0) System.out.println("Loading " + vF);
- DMI v = doDMILoad(vF);
- if(VERBOSITY >= 0) v.printInfo();
- break;
- }
- case "info": {
- if(argq.size() < 1) {
- System.out.println("Insufficient arguments for command!");
- System.out.println(helpStr);
- return;
- }
- String infoFile = argq.pollFirst();
- if(VERBOSITY >= 0) System.out.println("Loading " + infoFile);
- DMI info = doDMILoad(infoFile);
- info.printInfo();
- info.printStateList();
- break;
- }
- case "version":
- System.out.println(VERSION);
- return;
- default:
- System.out.println("Command '" + op + "' not found!");
- case "help":
- System.out.println(helpStr);
- break;
- }
- }
-
- static int parseDir(String s, IconState is) {
- try {
- int i = Integer.parseInt(s);
- if(0 <= i && i < is.dirs) {
- return i;
- } else {
- System.out.println("Direction not in valid range [0, "+(is.dirs-1)+"]!");
- return -1;
- }
- } catch(NumberFormatException nfe) {
- for(int q=0; q