diff --git a/code/datums/components/forensics.dm b/code/datums/components/forensics.dm
index 1950b8b664..76baa057cc 100644
--- a/code/datums/components/forensics.dm
+++ b/code/datums/components/forensics.dm
@@ -1,4 +1,5 @@
/datum/component/forensics
+ dupe_mode = COMPONENT_DUPE_UNIQUE
var/list/fingerprints //assoc print = print
var/list/hiddenprints //assoc ckey = realname/gloves/ckey
var/list/blood_DNA //assoc dna = bloodtype
diff --git a/code/game/gamemodes/blob/overmind.dm b/code/game/gamemodes/blob/overmind.dm
index f65c9ca768..a37a8d5c22 100644
--- a/code/game/gamemodes/blob/overmind.dm
+++ b/code/game/gamemodes/blob/overmind.dm
@@ -58,12 +58,21 @@ GLOBAL_LIST_EMPTY(blob_nodes)
/mob/camera/blob/proc/validate_location()
var/turf/T = get_turf(src)
- var/area/A = get_area(T)
- if(((A && !A.blob_allowed) || !T || !is_station_level(T.z)) && LAZYLEN(GLOB.blobstart))
- T = get_turf(pick(GLOB.blobstart))
+ if(!is_valid_turf(T) && LAZYLEN(GLOB.blobstart))
+ var/list/blobstarts = shuffle(GLOB.blobstart)
+ for(var/_T in blobstarts)
+ if(is_valid_turf(_T))
+ T = _T
+ break
if(!T)
CRASH("No blobspawnpoints and blob spawned in nullspace.")
forceMove(T)
+
+/mob/camera/blob/proc/is_valid_turf(turf/T)
+ var/area/A = get_area(T)
+ if((A && !A.blob_allowed) || !T || !is_station_level(T.z) || isspaceturf(T))
+ return FALSE
+ return TRUE
/mob/camera/blob/Life()
if(!blob_core)
@@ -246,4 +255,4 @@ GLOBAL_LIST_EMPTY(blob_nodes)
. = ..()
var/datum/antagonist/blob/B = mind.has_antag_datum(/datum/antagonist/blob)
if(!B)
- mind.add_antag_datum(/datum/antagonist/blob)
\ No newline at end of file
+ mind.add_antag_datum(/datum/antagonist/blob)
diff --git a/code/game/gamemodes/clock_cult/clock_structures/ark_of_the_clockwork_justicar.dm b/code/game/gamemodes/clock_cult/clock_structures/ark_of_the_clockwork_justicar.dm
index 21d1159541..36a74ec62b 100644
--- a/code/game/gamemodes/clock_cult/clock_structures/ark_of_the_clockwork_justicar.dm
+++ b/code/game/gamemodes/clock_cult/clock_structures/ark_of_the_clockwork_justicar.dm
@@ -1,5 +1,11 @@
#define ARK_GRACE_PERIOD 300 //In seconds, how long the crew has before the Ark truly "begins"
+/proc/clockwork_ark_active() //A helper proc so the Ark doesn't have to be typecast every time it's checked; returns null if there is no Ark and its active var otherwise
+ var/obj/structure/destructible/clockwork/massive/celestial_gateway/G = GLOB.ark_of_the_clockwork_justiciar
+ if(!G)
+ return
+ return G.active
+
//The gateway to Reebe, from which Ratvar emerges.
/obj/structure/destructible/clockwork/massive/celestial_gateway
name = "\improper Ark of the Clockwork Justicar"
@@ -63,7 +69,7 @@
/obj/structure/destructible/clockwork/massive/celestial_gateway/proc/cry_havoc()
visible_message("[src] shudders and roars to life, its parts beginning to whirr and screech!")
- hierophant_message("The Ark is activating! Get back to the base!")
+ hierophant_message("The Ark is activating! You will be transported there soon!")
for(var/mob/M in GLOB.player_list)
if(is_servant_of_ratvar(M) || isobserver(M) || M.z == z)
M.playsound_local(M, 'sound/magic/clockwork/ark_activation_sequence.ogg', 30, FALSE, pressure_affected = FALSE)
@@ -86,6 +92,8 @@
var/datum/stack_recipe/R = V
if(R.title == "wall gear")
R.time *= 2 //Building walls becomes slower when the Ark activates
+ mass_recall()
+ recalls_remaining++ //So it doesn't use up a charge
/obj/structure/destructible/clockwork/massive/celestial_gateway/proc/open_portal(turf/T)
new/obj/effect/clockwork/city_of_cogs_rift(T)
@@ -261,6 +269,12 @@
if(!step_away(O, src, 2) || get_dist(O, src) < 2)
O.take_damage(50, BURN, "bomb")
O.update_icon()
+ for(var/V in GLOB.player_list)
+ var/mob/M = V
+ if(is_servant_of_ratvar(M) && M.z != z)
+ M.forceMove(get_step(src, SOUTH))
+ M.overlay_fullscreen("flash", /obj/screen/fullscreen/flash)
+ M.clear_fullscreen("flash", 5)
if(grace_period)
grace_period--
return
diff --git a/code/game/gamemodes/wizard/soulstone.dm b/code/game/gamemodes/wizard/soulstone.dm
index 8b80b9ab69..bea6d41685 100644
--- a/code/game/gamemodes/wizard/soulstone.dm
+++ b/code/game/gamemodes/wizard/soulstone.dm
@@ -11,11 +11,11 @@
slot_flags = SLOT_BELT
var/usability = 0
- var/reusable = TRUE
+ var/old_shard = FALSE
var/spent = FALSE
/obj/item/device/soulstone/proc/was_used()
- if(!reusable)
+ if(old_shard)
spent = TRUE
name = "dull [name]"
desc = "A fragment of the legendary treasure known simply as \
@@ -27,7 +27,7 @@
/obj/item/device/soulstone/anybody/chaplain
name = "mysterious old shard"
- reusable = FALSE
+ old_shard = TRUE
/obj/item/device/soulstone/pickup(mob/living/user)
..()
@@ -38,7 +38,10 @@
/obj/item/device/soulstone/examine(mob/user)
..()
if(usability || iscultist(user) || iswizard(user) || isobserver(user))
- to_chat(user, "A soulstone, used to capture souls, either from unconscious or sleeping humans or from freed shades.")
+ if (old_shard)
+ to_chat(user, "A soulstone, used to capture a soul, either from dead humans or from freed shades.")
+ else
+ to_chat(user, "A soulstone, used to capture souls, either from unconscious or sleeping humans or from freed shades.")
to_chat(user, "The captured soul can be placed into a construct shell to produce a construct, or released from the stone as a shade.")
if(spent)
to_chat(user, "This shard is spent; it is now just a creepy rock.")
@@ -151,7 +154,7 @@
if(contents.len)
to_chat(user, "Capture failed!: The soulstone is full! Free an existing soul to make room.")
else
- if(T.stat != CONSCIOUS)
+ if((!old_shard && T.stat != CONSCIOUS) || (old_shard && T.stat == DEAD))
if(T.client == null)
to_chat(user, "Capture failed!: The soul has already fled its mortal frame. You attempt to bring it back...")
getCultGhost(T,user)
diff --git a/code/game/machinery/computer/camera_advanced.dm b/code/game/machinery/computer/camera_advanced.dm
index c90b6152d0..7c790f63de 100644
--- a/code/game/machinery/computer/camera_advanced.dm
+++ b/code/game/machinery/computer/camera_advanced.dm
@@ -283,6 +283,9 @@
if(!is_servant_of_ratvar(user))
to_chat(user, "[src]'s keys are in a language foreign to you, and you don't understand anything on its screen.")
return
+ if(clockwork_ark_active())
+ to_chat(user, "The Ark is active, and [src] has shut down.")
+ return
. = ..()
/datum/action/innate/servant_warp
diff --git a/code/game/machinery/computer/communications.dm b/code/game/machinery/computer/communications.dm
index 689c702840..9823df5fc8 100755
--- a/code/game/machinery/computer/communications.dm
+++ b/code/game/machinery/computer/communications.dm
@@ -130,7 +130,6 @@
if(authenticated==2)
playsound(src, 'sound/machines/terminal_prompt.ogg', 50, 0)
make_announcement(usr)
- deadchat_broadcast("[usr.name] made an priority announcement.", usr)
if("crossserver")
if(authenticated==2)
@@ -702,6 +701,7 @@
if(!input || !user.canUseTopic(src))
return
SScommunications.make_announcement(user, is_silicon, input)
+ deadchat_broadcast("[user.name] made an priority announcement.", user)
/obj/machinery/computer/communications/proc/post_status(command, data1, data2)
diff --git a/code/game/objects/effects/decals/decal.dm b/code/game/objects/effects/decals/decal.dm
index f04484c8a3..06c3b9a689 100644
--- a/code/game/objects/effects/decals/decal.dm
+++ b/code/game/objects/effects/decals/decal.dm
@@ -3,6 +3,14 @@
anchored = TRUE
resistance_flags = FIRE_PROOF | UNACIDABLE | ACID_PROOF
+/obj/effect/decal/Initialize()
+ . = ..()
+ if(!isturf(loc) || NeverShouldHaveComeHere(loc))
+ return INITIALIZE_HINT_QDEL
+
+/obj/effect/decal/proc/NeverShouldHaveComeHere(turf/T)
+ return isspaceturf(T) || isclosedturf(T) || islava(T) || istype(T, /turf/open/water) || ischasm(T)
+
/obj/effect/decal/ex_act(severity, target)
qdel(src)
@@ -12,7 +20,7 @@
/obj/effect/decal/HandleTurfChange(turf/T)
..()
- if(T == loc && (isspaceturf(T) || isclosedturf(T) || islava(T) || istype(T, /turf/open/water) || ischasm(T)))
+ if(T == loc && NeverShouldHaveComeHere(T))
qdel(src)
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/code/game/objects/items/stacks/bscrystal.dm b/code/game/objects/items/stacks/bscrystal.dm
index 978966706e..b7df34ca08 100644
--- a/code/game/objects/items/stacks/bscrystal.dm
+++ b/code/game/objects/items/stacks/bscrystal.dm
@@ -9,7 +9,7 @@
points = 50
var/blink_range = 8 // The teleport range when crushed/thrown at someone.
refined_type = /obj/item/stack/sheet/bluespace_crystal
- grind_results = list("bluespace" = 2)
+ grind_results = list("bluespace" = 20)
/obj/item/ore/bluespace_crystal/refined
name = "refined bluespace crystal"
@@ -49,7 +49,7 @@
blink_range = 4 // Not as good as the organic stuff!
points = 0 //nice try
refined_type = null
- grind_results = list("bluespace" = 1, "silicon" = 2)
+ grind_results = list("bluespace" = 10, "silicon" = 20)
//Polycrystals, aka stacks
/obj/item/stack/sheet/bluespace_crystal
@@ -60,7 +60,7 @@
materials = list(MAT_BLUESPACE=MINERAL_MATERIAL_AMOUNT)
attack_verb = list("bluespace polybashed", "bluespace polybattered", "bluespace polybludgeoned", "bluespace polythrashed", "bluespace polysmashed")
novariants = TRUE
- grind_results = list("bluespace" = 2)
+ grind_results = list("bluespace" = 20)
var/crystal_type = /obj/item/ore/bluespace_crystal/refined
/obj/item/stack/sheet/bluespace_crystal/attack_self(mob/user)// to prevent the construction menu from ever happening
diff --git a/code/game/objects/items/stacks/medical.dm b/code/game/objects/items/stacks/medical.dm
index 7a0f85a8f2..7ebf623218 100644
--- a/code/game/objects/items/stacks/medical.dm
+++ b/code/game/objects/items/stacks/medical.dm
@@ -111,7 +111,7 @@
righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi'
heal_brute = 40
self_delay = 20
- grind_results = list("styptic_powder" = 1)
+ grind_results = list("styptic_powder" = 10)
/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!")
@@ -148,4 +148,4 @@
righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi'
heal_burn = 40
self_delay = 20
- grind_results = list("silver_sulfadiazine" = 1)
+ grind_results = list("silver_sulfadiazine" = 10)
diff --git a/code/game/objects/items/stacks/sheets/glass.dm b/code/game/objects/items/stacks/sheets/glass.dm
index 8cc6a60efa..15cfc12773 100644
--- a/code/game/objects/items/stacks/sheets/glass.dm
+++ b/code/game/objects/items/stacks/sheets/glass.dm
@@ -22,7 +22,7 @@ GLOBAL_LIST_INIT(glass_recipes, list ( \
armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 50, acid = 100)
resistance_flags = ACID_PROOF
merge_type = /obj/item/stack/sheet/glass
- grind_results = list("silicon" = 1)
+ grind_results = list("silicon" = 20)
/obj/item/stack/sheet/glass/cyborg
materials = list()
@@ -80,7 +80,7 @@ GLOBAL_LIST_INIT(pglass_recipes, list ( \
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 75, "acid" = 100)
resistance_flags = ACID_PROOF
merge_type = /obj/item/stack/sheet/plasmaglass
- grind_results = list("silicon" = 1, "plasma" = 1)
+ grind_results = list("silicon" = 20, "plasma" = 10)
/obj/item/stack/sheet/plasmaglass/fifty
amount = 50
@@ -130,7 +130,7 @@ GLOBAL_LIST_INIT(reinforced_glass_recipes, list ( \
armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 70, acid = 100)
resistance_flags = ACID_PROOF
merge_type = /obj/item/stack/sheet/rglass
- grind_results = list("silicon" = 1, "iron" = 1)
+ grind_results = list("silicon" = 20, "iron" = 10)
/obj/item/stack/sheet/rglass/attackby(obj/item/W, mob/user, params)
add_fingerprint(user)
@@ -171,7 +171,7 @@ GLOBAL_LIST_INIT(prglass_recipes, list ( \
armor = list("melee" = 20, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 80, "acid" = 100)
resistance_flags = ACID_PROOF
merge_type = /obj/item/stack/sheet/plasmarglass
- grind_results = list("silicon" = 1, "plasma" = 1, "iron" = 1)
+ grind_results = list("silicon" = 20, "plasma" = 10, "iron" = 10)
/obj/item/stack/sheet/plasmarglass/Initialize(mapload, new_amount, merge = TRUE)
recipes = GLOB.prglass_recipes
diff --git a/code/game/objects/items/stacks/sheets/light.dm b/code/game/objects/items/stacks/sheets/light.dm
index 051d8326b8..b4482a72db 100644
--- a/code/game/objects/items/stacks/sheets/light.dm
+++ b/code/game/objects/items/stacks/sheets/light.dm
@@ -11,7 +11,7 @@
throw_range = 7
flags_1 = CONDUCT_1
max_amount = 60
- grind_results = list("silicon" = 1, "copper" = 1)
+ grind_results = list("silicon" = 20, "copper" = 5)
/obj/item/stack/light_w/attackby(obj/item/O, mob/user, params)
diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm
index c3d1d5160b..b57199cb12 100644
--- a/code/game/objects/items/stacks/sheets/sheet_types.dm
+++ b/code/game/objects/items/stacks/sheets/sheet_types.dm
@@ -330,7 +330,7 @@ GLOBAL_LIST_INIT(runed_metal_recipes, list ( \
sheettype = "runed"
merge_type = /obj/item/stack/sheet/runed_metal
novariants = TRUE
- grind_results = list("iron" = 0.5, "blood" = 1.5)
+ grind_results = list("iron" = 5, "blood" = 15)
/obj/item/stack/sheet/runed_metal/ratvar_act()
new /obj/item/stack/tile/brass(loc, amount)
@@ -394,7 +394,7 @@ GLOBAL_LIST_INIT(brass_recipes, list ( \
throw_range = 3
turf_type = /turf/open/floor/clockwork
novariants = FALSE
- grind_results = list("iron" = 0.5, "teslium" = 1.5)
+ grind_results = list("iron" = 5, "teslium" = 15)
/obj/item/stack/tile/brass/narsie_act()
new /obj/item/stack/sheet/runed_metal(loc, amount)
@@ -445,7 +445,7 @@ GLOBAL_LIST_INIT(brass_recipes, list ( \
w_class = WEIGHT_CLASS_NORMAL
throw_speed = 1
throw_range = 3
- grind_results = list("carbon" = 1)
+ grind_results = list("carbon" = 10)
GLOBAL_LIST_INIT(plastic_recipes, list(
new /datum/stack_recipe("plastic flaps", /obj/structure/plasticflaps, 5, one_per_turf = TRUE, on_floor = TRUE, time = 40), \
diff --git a/code/game/objects/structures/safe.dm b/code/game/objects/structures/safe.dm
index 550c89d1ae..616d290610 100644
--- a/code/game/objects/structures/safe.dm
+++ b/code/game/objects/structures/safe.dm
@@ -55,8 +55,8 @@ FLOOR SAFES
if(tumbler_1_pos == tumbler_1_open && tumbler_2_pos == tumbler_2_open)
if(user)
visible_message("[pick("Spring", "Sprang", "Sproing", "Clunk", "Krunk")]!")
- return 1
- return 0
+ return TRUE
+ return FALSE
/obj/structure/safe/proc/decrement(num)
@@ -83,7 +83,7 @@ FLOOR SAFES
/obj/structure/safe/attack_hand(mob/user)
user.set_machine(src)
var/dat = "
"
- dat += "[open ? "Close" : "Open"] [src] | - [dial * 5] +"
+ dat += "[open ? "Close" : "Open"] [src] | - [dial] +"
if(open)
dat += ""
for(var/i = contents.len, i>=1, i--)
@@ -101,9 +101,9 @@ FLOOR SAFES
if(!user.canUseTopic(src))
return
- var/canhear = 0
+ var/canhear = FALSE
if(user.is_holding_item_of_type(/obj/item/clothing/neck/stethoscope))
- canhear = 1
+ canhear = TRUE
if(href_list["open"])
if(check_unlocked())
diff --git a/code/modules/atmospherics/gasmixtures/gas_mixture.dm b/code/modules/atmospherics/gasmixtures/gas_mixture.dm
index dd6e4ffe71..007aad331a 100644
--- a/code/modules/atmospherics/gasmixtures/gas_mixture.dm
+++ b/code/modules/atmospherics/gasmixtures/gas_mixture.dm
@@ -22,18 +22,16 @@ GLOBAL_LIST_INIT(gaslist_cache, init_gaslist_cache())
/datum/gas_mixture
var/list/gases
- var/temperature //kelvins
- var/tmp/temperature_archived
- var/volume //liters
- var/last_share
+ var/temperature = 0 //kelvins
+ var/tmp/temperature_archived = 0
+ var/volume = CELL_VOLUME //liters
+ var/last_share = 0
var/list/reaction_results
-/datum/gas_mixture/New(volume = CELL_VOLUME)
+/datum/gas_mixture/New(volume)
gases = new
- temperature = 0
- temperature_archived = 0
- src.volume = volume
- last_share = 0
+ if (!isnull(volume))
+ src.volume = volume
reaction_results = new
//listmos procs
diff --git a/code/modules/atmospherics/machinery/atmosmachinery.dm b/code/modules/atmospherics/machinery/atmosmachinery.dm
index 2a5d792a1b..5ba74d59d9 100644
--- a/code/modules/atmospherics/machinery/atmosmachinery.dm
+++ b/code/modules/atmospherics/machinery/atmosmachinery.dm
@@ -301,7 +301,8 @@ Pipelines + Other Objects -> Pipe network
#define VENT_SOUND_DELAY 30
/obj/machinery/atmospherics/relaymove(mob/living/user, direction)
- if(!(direction & initialize_directions)) //cant go this way.
+ direction &= initialize_directions
+ if(!direction || !(direction in GLOB.cardinals)) //cant go this way.
return
if(user in buckled_mobs)// fixes buckle ventcrawl edgecase fuck bug
@@ -322,13 +323,12 @@ Pipelines + Other Objects -> Pipe network
if(world.time - user.last_played_vent > VENT_SOUND_DELAY)
user.last_played_vent = world.time
playsound(src, 'sound/machines/ventcrawl.ogg', 50, 1, -3)
- else
- if((direction & initialize_directions) || is_type_in_typecache(src, GLOB.ventcrawl_machinery) && can_crawl_through()) //if we move in a way the pipe can connect, but doesn't - or we're in a vent
- user.forceMove(loc)
- user.visible_message("You hear something squeezing through the ducts...","You climb out the ventilation system.")
- user.canmove = 0
- spawn(1)
- user.canmove = 1
+ else if(is_type_in_typecache(src, GLOB.ventcrawl_machinery) && can_crawl_through()) //if we move in a way the pipe can connect, but doesn't - or we're in a vent
+ user.forceMove(loc)
+ user.visible_message("You hear something squeezing through the ducts...","You climb out the ventilation system.")
+
+ user.canmove = FALSE
+ addtimer(VARSET_CALLBACK(user, canmove, TRUE), 1)
/obj/machinery/atmospherics/AltClick(mob/living/L)
diff --git a/code/modules/mob/inventory.dm b/code/modules/mob/inventory.dm
index 486a918c06..cc89f700dc 100644
--- a/code/modules/mob/inventory.dm
+++ b/code/modules/mob/inventory.dm
@@ -205,8 +205,26 @@
/mob/proc/put_in_hands(obj/item/I, del_on_fail = FALSE)
if(!I)
return FALSE
+
+ // If the item is a stack and we're already holding a stack then merge
+ if (istype(I, /obj/item/stack))
+ var/obj/item/stack/I_stack = I
+ var/obj/item/stack/active_stack = get_active_held_item()
+
+ if (istype(active_stack) && istype(I_stack, active_stack.merge_type))
+ if (I_stack.merge(active_stack))
+ to_chat(usr, "Your [active_stack.name] stack now contains [active_stack.get_amount()] [active_stack.singular_name]\s.")
+ return TRUE
+ else
+ var/obj/item/stack/inactive_stack = get_inactive_held_item()
+ if (istype(inactive_stack) && istype(I_stack, inactive_stack.merge_type))
+ if (I_stack.merge(inactive_stack))
+ to_chat(usr, "Your [inactive_stack.name] stack now contains [inactive_stack.get_amount()] [inactive_stack.singular_name]\s.")
+ return TRUE
+
if(put_in_active_hand(I))
return TRUE
+
var/hand = get_empty_held_index_for_side("l")
if(!hand)
hand = get_empty_held_index_for_side("r")
diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm
index e70e6af439..5254c6aa0e 100644
--- a/code/modules/mob/living/carbon/human/life.dm
+++ b/code/modules/mob/living/carbon/human/life.dm
@@ -386,12 +386,22 @@ All effects don't start immediately, but rather get worse over time; the rate is
81-90: Extremely high alcohol content - light brain damage, passing out
91-100: Dangerously toxic - swift death
*/
-
+#define BALLMER_POINTS 5
+GLOBAL_LIST_INIT(ballmer_good_msg, list("Hey guys, what if we rolled out a bluespace wiring system so mice can't destroy the powergrid anymore?",
+ "Hear me out here. What if, and this is just a theory, we made R&D controllable from our PDAs?",
+ "I'm thinking we should roll out a git repository for our research under the AGPLv3 license so that we can share it among the other stations freely.",
+ "I dunno about you guys, but IDs and PDAs being separate is clunky as fuck. Maybe we should merge them into a chip in our arms? That way they can't be stolen easily.",
+ "Why the fuck aren't we just making every pair of shoes into galoshes? We have the technology."))
+GLOBAL_LIST_INIT(ballmer_windows_me_msg, list("Yo man, what if, we like, uh, put a webserver that's automatically turned on with default admin passwords into every PDA?",
+ "So like, you know how we separate our codebase from the master copy that runs on our consumer boxes? What if we merged the two and undid the separation between codebase and server?",
+ "Dude, radical idea: H.O.N.K mechs but with no bananium required.",
+ "Best idea ever: Disposal pipes instead of hallways."))
/mob/living/carbon/human/handle_status_effects()
..()
+
+
if(drunkenness)
drunkenness = max(drunkenness - (drunkenness * 0.04), 0)
-
if(drunkenness >= 6)
if(prob(25))
slurring += 2
@@ -399,7 +409,22 @@ All effects don't start immediately, but rather get worse over time; the rate is
if(drunkenness >= 11 && slurring < 5)
slurring += 1.2
-
+ if(mind && (mind.assigned_role == "Scientist" || mind.assigned_role == "Research Director"))
+ if(SSresearch.science_tech)
+ if(drunkenness >= 12.9 && drunkenness <= 13.8)
+ drunkenness = round(drunkenness, 0.01)
+ var/ballmer_percent = 0
+ if(drunkenness == 13.35) // why run math if I dont have to
+ ballmer_percent = 1
+ else
+ ballmer_percent = (-abs(drunkenness - 13.35) / 0.9) + 1
+ if(prob(5))
+ say(pick(GLOB.ballmer_good_msg))
+ SSresearch.science_tech.research_points += (BALLMER_POINTS * ballmer_percent)
+ if(drunkenness > 26) // by this point you're into windows ME territory
+ if(prob(5))
+ SSresearch.science_tech.research_points -= BALLMER_POINTS
+ say(pick(GLOB.ballmer_windows_me_msg))
if(drunkenness >= 41)
if(prob(25))
confused += 2
diff --git a/code/modules/research/designs/autolathe_designs.dm b/code/modules/research/designs/autolathe_designs.dm
index 8542660343..b656b6c21c 100644
--- a/code/modules/research/designs/autolathe_designs.dm
+++ b/code/modules/research/designs/autolathe_designs.dm
@@ -807,6 +807,15 @@
build_path = /obj/item/stock_parts/cell/emergency_light
category = list("initial", "Electronics")
+/datum/design/packageWrap
+ name = "Package Wrapping"
+ id = "packagewrap"
+ build_type = AUTOLATHE
+ materials = list(MAT_METAL = 200, MAT_GLASS = 200)
+ build_path = /obj/item/stack/packageWrap
+ category = list("initial", "Misc")
+ maxstack = 30
+
/datum/design/holodisk
name = "Holodisk"
id = "holodisk"
diff --git a/code/modules/spells/spell_types/touch_attacks.dm b/code/modules/spells/spell_types/touch_attacks.dm
index 4a2f54e1f5..2000d8daea 100644
--- a/code/modules/spells/spell_types/touch_attacks.dm
+++ b/code/modules/spells/spell_types/touch_attacks.dm
@@ -24,9 +24,7 @@
stoplag(1)
/obj/effect/proc_holder/spell/targeted/touch/can_cast(mob/user = usr)
- if(attached_hand)
- return TRUE
- return ..()
+ return ..() && attached_hand
/obj/effect/proc_holder/spell/targeted/touch/proc/ChargeHand(mob/living/carbon/user)
attached_hand = new hand_path(src)
diff --git a/code/modules/uplink/uplink_purchase_log.dm b/code/modules/uplink/uplink_purchase_log.dm
index 5ec462d237..a8b1083999 100644
--- a/code/modules/uplink/uplink_purchase_log.dm
+++ b/code/modules/uplink/uplink_purchase_log.dm
@@ -20,6 +20,8 @@ GLOBAL_LIST(uplink_purchase_logs_by_key) //assoc key = /datum/uplink_purchase_lo
/datum/uplink_purchase_log/Destroy()
purchase_log = null
parent = null
+ if(GLOB.uplink_purchase_logs_by_key[owner] == src)
+ GLOB.uplink_purchase_logs_by_key -= owner
return ..()
/datum/uplink_purchase_log/proc/MergeWithAndDel(datum/uplink_purchase_log/other)
diff --git a/code/modules/vehicles/ridden.dm b/code/modules/vehicles/ridden.dm
index 32975e1e0f..5690bb1ad4 100644
--- a/code/modules/vehicles/ridden.dm
+++ b/code/modules/vehicles/ridden.dm
@@ -1,76 +1,71 @@
-/obj/vehicle/ridden
- name = "ridden vehicle"
- can_buckle = TRUE
- max_buckled_mobs = 1
- buckle_lying = FALSE
- default_driver_move = FALSE
- var/legs_required = 2
- var/arms_requires = 0 //why not?
-
-/obj/vehicle/ridden/Initialize()
- . = ..()
- LoadComponent(/datum/component/riding)
-
-/obj/vehicle/ridden/examine(mob/user)
- . = ..()
- to_chat(user, "Put a key inside it by clicking it with the key. If there's a key inside, you can remove it via Alt-Click!")
-
-/obj/vehicle/ridden/generate_action_type(actiontype)
- var/datum/action/vehicle/ridden/A = ..()
- . = A
- if(istype(A))
- A.vehicle_ridden_target = src
-
-/obj/vehicle/ridden/post_unbuckle_mob(mob/living/M)
- remove_occupant(M)
- return ..()
-
-/obj/vehicle/ridden/post_buckle_mob(mob/living/M)
- add_occupant(M)
- return ..()
-
-/obj/vehicle/ridden/attackby(obj/item/I, mob/user, params)
- if(key_type && !is_key(inserted_key) && is_key(I))
- if(user.transferItemToLoc(I, src))
- to_chat(user, "You insert \the [I] into \the [src].")
- if(inserted_key) //just in case there's an invalid key
- inserted_key.forceMove(drop_location())
- inserted_key = I
- else
- to_chat(user, "[I] seems to be stuck to your hand!")
- return
- return ..()
-
-/obj/vehicle/ridden/AltClick(mob/user)
- if(user.Adjacent(src) && inserted_key)
- if(!is_occupant(user))
- 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())
- user.put_in_hands(inserted_key)
- inserted_key = null
- return ..()
-
-/obj/vehicle/ridden/driver_move(mob/user, direction)
- if(key_type && !is_key(inserted_key))
- to_chat(user, "[src] has no key inserted!")
- return FALSE
- var/datum/component/riding/R = GetComponent(/datum/component/riding)
- R.handle_ride(user, direction)
- return ..()
-
-/obj/vehicle/ridden/user_buckle_mob(mob/living/M, mob/user, check_loc = TRUE)
- if(user.incapacitated())
- return
- for(var/atom/movable/A in get_turf(src))
- if(A.density)
- if(A != src && A != M)
- return
- M.forceMove(get_turf(src))
- . = ..()
-
-/obj/vehicle/ridden/buckle_mob(mob/living/M, force = FALSE, check_loc = TRUE)
- if(!force && occupant_amount() >= max_occupants)
- return FALSE
- return ..()
+/obj/vehicle/ridden
+ name = "ridden vehicle"
+ can_buckle = TRUE
+ max_buckled_mobs = 1
+ buckle_lying = FALSE
+ default_driver_move = FALSE
+ var/legs_required = 2
+ var/arms_requires = 0 //why not?
+
+/obj/vehicle/ridden/Initialize()
+ . = ..()
+ LoadComponent(/datum/component/riding)
+
+/obj/vehicle/ridden/examine(mob/user)
+ . = ..()
+ to_chat(user, "Put a key inside it by clicking it with the key. If there's a key inside, you can remove it via Alt-Click!")
+
+/obj/vehicle/ridden/generate_action_type(actiontype)
+ var/datum/action/vehicle/ridden/A = ..()
+ . = A
+ if(istype(A))
+ A.vehicle_ridden_target = src
+
+/obj/vehicle/ridden/post_unbuckle_mob(mob/living/M)
+ remove_occupant(M)
+ return ..()
+
+/obj/vehicle/ridden/post_buckle_mob(mob/living/M)
+ add_occupant(M)
+ return ..()
+
+/obj/vehicle/ridden/attackby(obj/item/I, mob/user, params)
+ if(key_type && !is_key(inserted_key) && is_key(I))
+ if(user.transferItemToLoc(I, src))
+ to_chat(user, "You insert \the [I] into \the [src].")
+ if(inserted_key) //just in case there's an invalid key
+ inserted_key.forceMove(drop_location())
+ inserted_key = I
+ else
+ to_chat(user, "[I] seems to be stuck to your hand!")
+ return
+ return ..()
+
+/obj/vehicle/ridden/AltClick(mob/user)
+ if(user.Adjacent(src) && inserted_key)
+ if(!is_occupant(user))
+ 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())
+ user.put_in_hands(inserted_key)
+ inserted_key = null
+ return ..()
+
+/obj/vehicle/ridden/driver_move(mob/user, direction)
+ if(key_type && !is_key(inserted_key))
+ to_chat(user, "[src] has no key inserted!")
+ return FALSE
+ var/datum/component/riding/R = GetComponent(/datum/component/riding)
+ R.handle_ride(user, direction)
+ return ..()
+
+/obj/vehicle/ridden/user_buckle_mob(mob/living/M, mob/user, check_loc = TRUE)
+ if(!in_range(user, src) || !in_range(M, src))
+ return FALSE
+ . = ..(M, user, FALSE)
+
+/obj/vehicle/ridden/buckle_mob(mob/living/M, force = FALSE, check_loc = TRUE)
+ if(!force && occupant_amount() >= max_occupants)
+ return FALSE
+ return ..()
diff --git a/config/config.txt b/config/config.txt
index e43b38b568..b934ddab41 100644
--- a/config/config.txt
+++ b/config/config.txt
@@ -51,7 +51,8 @@ BAN_LEGACY_SYSTEM
## Unhash this to enable playtime requirements for head jobs.
#USE_EXP_RESTRICTIONS_HEADS
## Unhash this to override head jobs' playtime requirements with this number of hours.
-#USE_EXP_RESTRICTIONS_HEADS_HOURS 15
+## Leave this commented out to use the values defined in the job datums. Values in the datums are stored as minutes.
+#USE_EXP_RESTRICTIONS_HEADS_HOURS 3
## Unhash this to change head jobs' playtime requirements so that they're based on department playtime, rather than crew playtime.
#USE_EXP_RESTRICTIONS_HEADS_DEPARTMENT
## Unhash this to enable playtime requirements for certain non-head jobs, like Engineer and Scientist.
diff --git a/html/changelogs/AutoChangeLog-pr-4695.yml b/html/changelogs/AutoChangeLog-pr-4695.yml
new file mode 100644
index 0000000000..295f470c19
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-4695.yml
@@ -0,0 +1,4 @@
+author: "CitadelStationBot"
+delete-after: True
+changes:
+ - config: "The default config for head of staff exp override is closer to the actual default with no override."
diff --git a/html/changelogs/AutoChangeLog-pr-4696.yml b/html/changelogs/AutoChangeLog-pr-4696.yml
new file mode 100644
index 0000000000..94a6abdc2d
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-4696.yml
@@ -0,0 +1,4 @@
+author: "CitadelStationBot"
+delete-after: True
+changes:
+ - bugfix: "Lavaboats no longer set you on fire."
diff --git a/html/changelogs/AutoChangeLog-pr-4698.yml b/html/changelogs/AutoChangeLog-pr-4698.yml
new file mode 100644
index 0000000000..f36c090b6b
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-4698.yml
@@ -0,0 +1,4 @@
+author: "CitadelStationBot"
+delete-after: True
+changes:
+ - bugfix: "Decals will no longer spawn where they don't belong"
diff --git a/html/changelogs/AutoChangeLog-pr-4699.yml b/html/changelogs/AutoChangeLog-pr-4699.yml
new file mode 100644
index 0000000000..f527d04673
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-4699.yml
@@ -0,0 +1,4 @@
+author: "CitadelStationBot"
+delete-after: True
+changes:
+ - bugfix: "comms consoles no longer announce in deadchat announcements if they were cooling down and unsuccessful."
diff --git a/html/changelogs/AutoChangeLog-pr-4703.yml b/html/changelogs/AutoChangeLog-pr-4703.yml
new file mode 100644
index 0000000000..84caef07bb
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-4703.yml
@@ -0,0 +1,4 @@
+author: "MrDoomBringer"
+delete-after: True
+changes:
+ - rscadd: "Advances in NanoTrasen's wrapping department have resulted in the easy creation of package wrap from all station autolathes!"
diff --git a/html/changelogs/AutoChangeLog-pr-4705.yml b/html/changelogs/AutoChangeLog-pr-4705.yml
new file mode 100644
index 0000000000..b244a9b202
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-4705.yml
@@ -0,0 +1,4 @@
+author: "Xhuis"
+delete-after: True
+changes:
+ - balance: "Servants are now teleported to the Ark when it activates, and cannot leave Reebe afterwards."
diff --git a/html/changelogs/AutoChangeLog-pr-4706.yml b/html/changelogs/AutoChangeLog-pr-4706.yml
new file mode 100644
index 0000000000..ec2df28b7b
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-4706.yml
@@ -0,0 +1,4 @@
+author: "JohnGinnane"
+delete-after: True
+changes:
+ - rscadd: "Newly crafted stacks are merged with held stacks of the same type."
diff --git a/html/changelogs/AutoChangeLog-pr-4707.yml b/html/changelogs/AutoChangeLog-pr-4707.yml
new file mode 100644
index 0000000000..fbb5baaee4
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-4707.yml
@@ -0,0 +1,4 @@
+author: "Iamgoofball"
+delete-after: True
+changes:
+ - bugfix: "Booze now properly reflects programming speed."
diff --git a/html/changelogs/AutoChangeLog-pr-4709.yml b/html/changelogs/AutoChangeLog-pr-4709.yml
new file mode 100644
index 0000000000..77fc189587
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-4709.yml
@@ -0,0 +1,4 @@
+author: "ninjanomnom"
+delete-after: True
+changes:
+ - bugfix: "Moving diagonally in pipes should no longer eject you from the pipe."
diff --git a/html/changelogs/AutoChangeLog-pr-4712.yml b/html/changelogs/AutoChangeLog-pr-4712.yml
new file mode 100644
index 0000000000..2be6df57e5
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-4712.yml
@@ -0,0 +1,4 @@
+author: "More Robust Than You"
+delete-after: True
+changes:
+ - bugfix: "Blob Overminds should no longer to be able to spawn on ANY space tile"
diff --git a/html/changelogs/AutoChangeLog-pr-4714.yml b/html/changelogs/AutoChangeLog-pr-4714.yml
new file mode 100644
index 0000000000..f68222ddd1
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-4714.yml
@@ -0,0 +1,5 @@
+author: "Dax Dupont"
+delete-after: True
+changes:
+ - balance: "The chaplain's soul stone now requires death instead of (soft) crit."
+ - bugfix: "The examine text now properly states that it can only capture a single soul."
diff --git a/strings/clockwork_cult_changelog.txt b/strings/clockwork_cult_changelog.txt
index b5d2ca10e3..5e6beedf2e 100644
--- a/strings/clockwork_cult_changelog.txt
+++ b/strings/clockwork_cult_changelog.txt
@@ -1,7 +1,6 @@
-Added the Eminence, a leader role that servants can become by interacting with the new eminence spire structure in Reebe.
-Scripture has been re-colored in the slab interface to show its niche at a glance.
-Added traps, including the brass skewer and steam vent.
-Added trap triggers, including the pressure sensor, lever, and repeater.
-Traps and trap triggers can be linked by using your clockwork slab on them. Traps chained to each other will cause those traps to activate as well.
-You can instantly remove traps you misplace by using a wrench on them.
-Mending Mantra has been removed.
\ No newline at end of file
+When revived by a vitality matrix, servants will gain a 1-minute debuff that prevents revival again.
+Vitality matrices must now be placed at least one tile apart.
+Servants are now teleported to and locked on Reebe once the Ark starts.
+Cyborgs are now damaged by brass skewers.
+Vitality matrices no longer work on buckled mobs (including skewered ones.)
+Pressure sensors have much less health.
\ No newline at end of file
diff --git a/tgui/reload.bat b/tgui/reload.bat
index 3113036e62..c59d502f36 100644
--- a/tgui/reload.bat
+++ b/tgui/reload.bat
@@ -1,9 +1,8 @@
@echo off
REM Get the documents folder from the registry.
-for /f "tokens=3* delims= " %%a in (
- 'reg query "HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders" /v "Personal"'
-) do (
- set documents=%%a %%b
+@echo off
+for /f "tokens=3*" %%p in ('REG QUERY "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders" /v Personal') do (
+ set DocumentsFolder=%%p
)
REM Copy assets to the BYOND cache
-cmd /c copy assets\* "%documents%\BYOND\cache" /y
+cmd /c copy assets\* "%DocumentsFolder%\BYOND\cache" /y