diff --git a/_maps/RandomRuins/SpaceRuins/derelict2.dmm b/_maps/RandomRuins/SpaceRuins/derelict2.dmm
index c57ac798ac..a20be471f4 100644
--- a/_maps/RandomRuins/SpaceRuins/derelict2.dmm
+++ b/_maps/RandomRuins/SpaceRuins/derelict2.dmm
@@ -64,12 +64,17 @@
/obj/structure/chair{
dir = 4
},
+/obj/item/clothing/under/polychromic/shirt,
+/obj/item/clothing/neck/tie/black,
+/obj/item/clothing/shoes/laceup,
+/obj/item/storage/wallet/random,
+/obj/item/clothing/gloves/color/white,
/obj/effect/decal/remains/human,
/turf/open/floor/plasteel,
/area/ruin/space/has_grav/powered/dinner_for_two)
"n" = (
/obj/structure/table,
-/obj/item/candle{
+/obj/item/candle/infinite{
pixel_y = 5
},
/obj/item/trash/plate{
@@ -84,6 +89,11 @@
/obj/structure/chair{
dir = 8
},
+/obj/item/clothing/under/polychromic/skirt,
+/obj/item/clothing/shoes/laceup,
+/obj/item/clothing/gloves/color/white,
+/obj/item/clothing/glasses/regular,
+/obj/item/lipstick/random,
/obj/effect/decal/remains/human,
/turf/open/floor/plasteel,
/area/ruin/space/has_grav/powered/dinner_for_two)
diff --git a/_maps/map_files/BoxStation/BoxStation.dmm b/_maps/map_files/BoxStation/BoxStation.dmm
index c4da3f1e32..053136a434 100644
--- a/_maps/map_files/BoxStation/BoxStation.dmm
+++ b/_maps/map_files/BoxStation/BoxStation.dmm
@@ -11448,12 +11448,6 @@
},
/turf/open/floor/plasteel,
/area/crew_quarters/fitness)
-"aAq" = (
-/obj/machinery/atmospherics/components/unary/tank/air{
- dir = 8
- },
-/turf/open/floor/plating,
-/area/maintenance/starboard/fore)
"aAr" = (
/obj/structure/closet,
/obj/effect/decal/cleanable/cobweb,
@@ -11963,13 +11957,6 @@
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
/turf/open/floor/plating,
/area/maintenance/starboard/fore)
-"aBD" = (
-/obj/machinery/meter,
-/obj/machinery/atmospherics/pipe/manifold/supply/hidden{
- dir = 8
- },
-/turf/open/floor/plating,
-/area/maintenance/starboard/fore)
"aBE" = (
/obj/item/clothing/under/rank/mailman,
/obj/item/clothing/head/mailman,
@@ -12352,10 +12339,6 @@
/obj/effect/spawner/structure/window/reinforced,
/turf/open/floor/plating,
/area/crew_quarters/fitness)
-"aCx" = (
-/obj/machinery/atmospherics/components/binary/valve,
-/turf/open/floor/plating,
-/area/maintenance/starboard/fore)
"aCy" = (
/obj/effect/decal/cleanable/oil,
/turf/open/floor/plating,
@@ -12961,10 +12944,8 @@
/turf/open/floor/plasteel/freezer,
/area/crew_quarters/toilet)
"aDV" = (
+/obj/machinery/atmospherics/pipe/manifold/supply/hidden,
/obj/machinery/meter,
-/obj/machinery/atmospherics/pipe/simple/supply/hidden{
- dir = 5
- },
/turf/open/floor/plating,
/area/maintenance/starboard/fore)
"aDW" = (
@@ -56758,6 +56739,12 @@
},
/turf/open/floor/wood,
/area/maintenance/bar)
+"gOZ" = (
+/obj/machinery/door/airlock/maintenance{
+ req_access_txt = "12"
+ },
+/turf/open/floor/plating,
+/area/crew_quarters/fitness)
"gWd" = (
/obj/structure/cable{
icon_state = "1-4"
@@ -56878,6 +56865,12 @@
/obj/machinery/rnd/production/techfab/department/cargo,
/turf/open/floor/plasteel,
/area/quartermaster/office)
+"jnR" = (
+/obj/machinery/atmospherics/components/binary/valve{
+ dir = 4
+ },
+/turf/open/floor/plating,
+/area/maintenance/starboard/fore)
"jqv" = (
/obj/structure/chair/wood/normal{
dir = 1
@@ -57260,6 +57253,12 @@
/obj/item/reagent_containers/food/drinks/beer,
/turf/open/floor/plating,
/area/maintenance/starboard/aft)
+"rsp" = (
+/obj/machinery/atmospherics/components/unary/tank/air{
+ dir = 4
+ },
+/turf/open/floor/plating,
+/area/maintenance/starboard/fore)
"rBq" = (
/obj/item/clothing/head/kitty,
/obj/item/clothing/under/maid,
@@ -57561,6 +57560,13 @@
},
/turf/open/floor/wood,
/area/maintenance/bar)
+"vpY" = (
+/obj/machinery/atmospherics/pipe/simple/supply/hidden{
+ dir = 10
+ },
+/obj/machinery/meter,
+/turf/open/floor/plating,
+/area/maintenance/starboard/fore)
"vxh" = (
/obj/structure/table,
/obj/effect/spawner/lootdrop/maintenance{
@@ -96101,12 +96107,12 @@ arj
auB
auB
arj
-arj
+gOZ
arj
anf
anf
-anf
-awD
+rsp
+rsp
alP
aGB
aIf
@@ -96355,14 +96361,14 @@ aaa
aaa
aaf
aaa
-aaa
-aaf
-aaa
-aaa
+gXs
+aoV
alP
-ayf
-aBD
-aCx
+anf
+anf
+anf
+anf
+aDW
aDV
alP
aGL
@@ -96612,15 +96618,15 @@ aaa
aaa
aaf
aaa
-aaa
-aaf
-aaa
-aaa
+gXs
+aoV
alP
-aAq
-aAq
+awD
+anf
+anf
+anf
aCy
-aCG
+jnR
alP
aGL
avI
@@ -96877,7 +96883,7 @@ alP
alP
alP
alP
-aDW
+vpY
aFn
aGP
avI
diff --git a/_maps/map_files/generic/CentCom.dmm b/_maps/map_files/generic/CentCom.dmm
index 14d16fe659..d005f1eb40 100644
--- a/_maps/map_files/generic/CentCom.dmm
+++ b/_maps/map_files/generic/CentCom.dmm
@@ -4696,7 +4696,7 @@
},
/area/abductor_ship)
"lI" = (
-/turf/open/space/transit,
+/turf/open/space/transit/centcom,
/area/space)
"lJ" = (
/obj/machinery/door/airlock/centcom{
@@ -20511,7 +20511,7 @@ fX
fX
fX
fX
-fY
+fX
fX
fX
fX
@@ -21282,7 +21282,7 @@ fX
fX
fX
fX
-fX
+fY
fX
fX
fX
diff --git a/_maps/shuttles/pirate_default.dmm b/_maps/shuttles/pirate_default.dmm
index 91305d2990..445c29241c 100644
--- a/_maps/shuttles/pirate_default.dmm
+++ b/_maps/shuttles/pirate_default.dmm
@@ -91,6 +91,40 @@
"aj" = (
/turf/closed/wall/mineral/plastitanium/nodiagonal,
/area/shuttle/pirate)
+"ak" = (
+/obj/machinery/airalarm/all_access{
+ dir = 4;
+ pixel_x = -24
+ },
+/obj/effect/decal/cleanable/dirt,
+/obj/machinery/light/small{
+ dir = 8
+ },
+/obj/structure/closet/secure_closet/freezer{
+ locked = 0;
+ name = "fridge"
+ },
+/obj/item/storage/box/donkpockets{
+ pixel_x = 2;
+ pixel_y = 3
+ },
+/obj/item/storage/box/donkpockets,
+/obj/item/storage/fancy/donut_box,
+/obj/item/reagent_containers/food/snacks/cookie,
+/obj/item/reagent_containers/food/snacks/cookie{
+ pixel_x = -6;
+ pixel_y = -6
+ },
+/obj/item/reagent_containers/food/snacks/chocolatebar,
+/obj/effect/decal/cleanable/dirt,
+/obj/effect/turf_decal/tile/bar,
+/obj/effect/turf_decal/tile/bar{
+ dir = 1
+ },
+/obj/item/reagent_containers/food/condiment/milk,
+/obj/item/reagent_containers/food/condiment/milk,
+/turf/open/floor/plasteel,
+/area/shuttle/pirate)
"al" = (
/obj/machinery/loot_locator,
/obj/effect/decal/cleanable/dirt,
@@ -622,38 +656,6 @@
/obj/effect/decal/cleanable/dirt,
/turf/open/floor/plasteel,
/area/shuttle/pirate)
-"bw" = (
-/obj/machinery/airalarm/all_access{
- dir = 4;
- pixel_x = -24
- },
-/obj/effect/decal/cleanable/dirt,
-/obj/machinery/light/small{
- dir = 8
- },
-/obj/structure/closet/secure_closet/freezer{
- locked = 0;
- name = "fridge"
- },
-/obj/item/storage/box/donkpockets{
- pixel_x = 2;
- pixel_y = 3
- },
-/obj/item/storage/box/donkpockets,
-/obj/item/storage/fancy/donut_box,
-/obj/item/reagent_containers/food/snacks/cookie,
-/obj/item/reagent_containers/food/snacks/cookie{
- pixel_x = -6;
- pixel_y = -6
- },
-/obj/item/reagent_containers/food/snacks/chocolatebar,
-/obj/effect/decal/cleanable/dirt,
-/obj/effect/turf_decal/tile/bar,
-/obj/effect/turf_decal/tile/bar{
- dir = 1
- },
-/turf/open/floor/plasteel,
-/area/shuttle/pirate)
"bx" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
dir = 4
@@ -1207,7 +1209,7 @@ eA
aa
ap
aw
-bw
+ak
bF
aj
aj
diff --git a/code/__DEFINES/combat.dm b/code/__DEFINES/combat.dm
index af1043f22e..15e8048926 100644
--- a/code/__DEFINES/combat.dm
+++ b/code/__DEFINES/combat.dm
@@ -97,6 +97,20 @@
//the define for visible message range in combat
#define COMBAT_MESSAGE_RANGE 3
+//Shove knockdown lengths (deciseconds)
+#define SHOVE_KNOCKDOWN_SOLID 30
+#define SHOVE_KNOCKDOWN_HUMAN 30
+#define SHOVE_KNOCKDOWN_TABLE 30
+#define SHOVE_KNOCKDOWN_COLLATERAL 10
+//Shove slowdown
+#define SHOVE_SLOWDOWN_ID "shove_slowdown"
+#define SHOVE_SLOWDOWN_LENGTH 30
+#define SHOVE_SLOWDOWN_STRENGTH 0.85 //multiplier
+//Shove disarming item list
+GLOBAL_LIST_INIT(shove_disarming_types, typecacheof(list(
+ /obj/item/gun)))
+
+
//Combat object defines
//Embedded objects
diff --git a/code/__DEFINES/obj_flags.dm b/code/__DEFINES/obj_flags.dm
index 76f66521a7..e6d4fd126b 100644
--- a/code/__DEFINES/obj_flags.dm
+++ b/code/__DEFINES/obj_flags.dm
@@ -25,6 +25,7 @@
#define NOBLUDGEON (1<<7) // when an item has this it produces no "X has been hit by Y with Z" message in the default attackby()
#define NODROP (1<<8) // This flag makes it so that an item literally cannot be removed at all, or at least that's how it should be. Only deleted.
#define ABSTRACT (1<<9) // for all things that are technically items but used for various different stuff
+#define IMMUTABLE_SLOW (1<<10) //When players should not be able to change the slowdown of the item (Speed potions, ect)
// Flags for the clothing_flags var on /obj/item/clothing
diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm
index e8f718e590..d23d0905e9 100644
--- a/code/_onclick/item_attack.dm
+++ b/code/_onclick/item_attack.dm
@@ -167,4 +167,7 @@
attack_message = "[user] has [message_verb] [src][message_hit_area] with [I]!"
visible_message("[attack_message]",\
"[attack_message]", null, COMBAT_MESSAGE_RANGE)
+ if(hit_area == BODY_ZONE_HEAD)
+ if(prob(2))
+ playsound(src, 'sound/weapons/dink.ogg', 30, 1)
return 1
diff --git a/code/controllers/subsystem/timer.dm b/code/controllers/subsystem/timer.dm
index 4b347b2a39..c92db7cd01 100644
--- a/code/controllers/subsystem/timer.dm
+++ b/code/controllers/subsystem/timer.dm
@@ -269,7 +269,7 @@ SUBSYSTEM_DEF(timer)
var/new_bucket_count
var/i = 1
for (i in 1 to length(alltimers))
- var/datum/timedevent/timer = alltimers[1]
+ var/datum/timedevent/timer = alltimers[i]
if (!timer)
continue
diff --git a/code/game/machinery/cloning.dm b/code/game/machinery/cloning.dm
index 7528f83c38..7e75dc8e8e 100644
--- a/code/game/machinery/cloning.dm
+++ b/code/game/machinery/cloning.dm
@@ -227,7 +227,7 @@
if((mob_occupant.stat == DEAD) || (mob_occupant.suiciding) || mob_occupant.hellbound) //Autoeject corpses and suiciding dudes.
connected_message("Clone Rejected: Deceased.")
if(internal_radio)
- SPEAK("The cloning of [mob_occupant.real_name] has been \
+ SPEAK("The cloning has been \
aborted due to unrecoverable tissue failure.")
go_out()
mob_occupant.apply_vore_prefs()
@@ -261,7 +261,7 @@
else if((mob_occupant.cloneloss <= (100 - heal_level)))
connected_message("Cloning Process Complete.")
if(internal_radio)
- SPEAK("The cloning cycle of [mob_occupant.real_name] is complete.")
+ SPEAK("The cloning cycle is complete.")
// If the cloner is upgraded to debugging high levels, sometimes
// organs and limbs can be missing.
@@ -319,7 +319,7 @@
return
else
connected_message("Emergency Ejection")
- SPEAK("An emergency ejection of [clonemind.name] has occurred. Survival not guaranteed.")
+ SPEAK("An emergency ejection of the current clone has occurred. Survival not guaranteed.")
to_chat(user, "You force an emergency ejection. ")
go_out()
mob_occupant.apply_vore_prefs()
@@ -412,7 +412,7 @@
var/mob/living/mob_occupant = occupant
if(mob_occupant && prob(100/(severity*efficiency)))
connected_message(Gibberish("EMP-caused Accidental Ejection", 0))
- SPEAK(Gibberish("Exposure to electromagnetic fields has caused the ejection of [mob_occupant.real_name] prematurely." ,0))
+ SPEAK(Gibberish("Exposure to electromagnetic fields has caused the ejection of, ERROR: John Doe, prematurely." ,0))
mob_occupant.apply_vore_prefs()
go_out()
diff --git a/code/game/objects/effects/effect_system/effects_sparks.dm b/code/game/objects/effects/effect_system/effects_sparks.dm
index 44aab00852..0656d9b3ca 100644
--- a/code/game/objects/effects/effect_system/effects_sparks.dm
+++ b/code/game/objects/effects/effect_system/effects_sparks.dm
@@ -30,20 +30,20 @@
playsound(src, "sparks", 100, TRUE)
var/turf/T = loc
if(isturf(T))
- T.hotspot_expose(300,5)
+ T.hotspot_expose(700,5)
QDEL_IN(src, 20)
/obj/effect/particle_effect/sparks/Destroy()
var/turf/T = loc
if(isturf(T))
- T.hotspot_expose(300,1)
+ T.hotspot_expose(700,1)
return ..()
/obj/effect/particle_effect/sparks/Move()
..()
var/turf/T = loc
if(isturf(T))
- T.hotspot_expose(300,1)
+ T.hotspot_expose(700,1)
/datum/effect_system/spark_spread
effect_type = /obj/effect/particle_effect/sparks
diff --git a/code/game/objects/items/RPD.dm b/code/game/objects/items/RPD.dm
index 1c6cc9cfcb..41ddc22106 100644
--- a/code/game/objects/items/RPD.dm
+++ b/code/game/objects/items/RPD.dm
@@ -187,6 +187,7 @@ GLOBAL_LIST_INIT(transit_tube_recipes, list(
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 50)
resistance_flags = FIRE_PROOF
var/datum/effect_system/spark_spread/spark_system
+ var/effectcooldown
var/working = 0
var/p_dir = NORTH
var/p_flipped = FALSE
@@ -207,7 +208,7 @@ GLOBAL_LIST_INIT(transit_tube_recipes, list(
/obj/item/pipe_dispenser/New()
. = ..()
spark_system = new /datum/effect_system/spark_spread
- spark_system.set_up(5, 0, src)
+ spark_system.set_up(1, 0, src)
spark_system.attach(src)
if(!first_atmos)
first_atmos = GLOB.atmos_pipe_recipes[GLOB.atmos_pipe_recipes[1]][1]
@@ -313,8 +314,9 @@ GLOBAL_LIST_INIT(transit_tube_recipes, list(
else
mode |= n
- if(playeffect)
+ if(playeffect && world.time >= effectcooldown)
spark_system.start()
+ effectcooldown = world.time + 100
playsound(get_turf(src), 'sound/effects/pop.ogg', 50, 0)
/obj/item/pipe_dispenser/pre_attack(atom/A, mob/user)
diff --git a/code/game/objects/items/candle.dm b/code/game/objects/items/candle.dm
index b7a3b0c76c..1165501d9a 100644
--- a/code/game/objects/items/candle.dm
+++ b/code/game/objects/items/candle.dm
@@ -8,72 +8,70 @@
item_state = "candle1"
w_class = WEIGHT_CLASS_TINY
light_color = LIGHT_COLOR_FIRE
+ heat = 1000
var/wax = 1000
var/lit = FALSE
var/infinite = FALSE
var/start_lit = FALSE
- heat = 1000
/obj/item/candle/Initialize()
. = ..()
if(start_lit)
- // No visible message
- light(show_message = FALSE)
+ light()
/obj/item/candle/update_icon()
- var/i
- if(wax>750)
- i = 1
- else if(wax>400)
- i = 2
- else i = 3
- icon_state = "candle[i][lit ? "_lit" : ""]"
-
+ icon_state = "candle[(wax > 400) ? ((wax > 750) ? 1 : 2) : 3][lit ? "_lit" : ""]"
/obj/item/candle/attackby(obj/item/W, mob/user, params)
- ..()
var/msg = W.ignition_effect(src, user)
if(msg)
light(msg)
+ else
+ return ..()
/obj/item/candle/fire_act(exposed_temperature, exposed_volume)
- if(!src.lit)
+ if(!lit)
light() //honk
- ..()
+ return ..()
+
+/obj/item/candle/is_hot()
+ return lit * heat
/obj/item/candle/proc/light(show_message)
- if(!src.lit)
- src.lit = TRUE
- //src.damtype = "fire"
+ if(!lit)
+ lit = TRUE
if(show_message)
usr.visible_message(show_message)
- set_light(CANDLE_LUMINOSITY, 0.8)
+ set_light(CANDLE_LUMINOSITY)
START_PROCESSING(SSobj, src)
update_icon()
+/obj/item/candle/proc/put_out_candle()
+ if(!lit)
+ return
+ lit = FALSE
+ update_icon()
+ set_light(0)
+ return TRUE
+
+/obj/item/candle/extinguish()
+ put_out_candle()
+ return ..()
/obj/item/candle/process()
if(!lit)
- return
+ return PROCESS_KILL
if(!infinite)
wax--
if(!wax)
- new/obj/item/trash/candle(src.loc)
+ new /obj/item/trash/candle(loc)
qdel(src)
update_icon()
open_flame()
/obj/item/candle/attack_self(mob/user)
- if(lit)
- user.visible_message(
- "[user] snuffs [src].")
- lit = FALSE
- update_icon()
- set_light(0)
-
-/obj/item/candle/is_hot()
- return lit * heat
-
+ if(put_out_candle())
+ user.visible_message("[user] snuffs [src].")
/obj/item/candle/infinite
infinite = TRUE
diff --git a/code/game/objects/items/extinguisher.dm b/code/game/objects/items/extinguisher.dm
index a57bf47a2e..e0d6b553fd 100644
--- a/code/game/objects/items/extinguisher.dm
+++ b/code/game/objects/items/extinguisher.dm
@@ -227,7 +227,7 @@
repetition++
addtimer(CALLBACK(src, /obj/item/extinguisher/proc/move_chair, B, movementdirection, repetition), timer_seconds)
-/obj/item/extinguisher/AltClick(mob/user)
+/obj/item/extinguisher/screwdriver_act(mob/user, obj/item/tool)
if(!user.canUseTopic(src, BE_CLOSE, ismonkey(user)))
return
EmptyExtinguisher(user)
@@ -242,3 +242,4 @@
theturf.MakeSlippery(TURF_WET_WATER, min_wet_time = 10 SECONDS, wet_time_to_add = 5 SECONDS)
user.visible_message("[user] empties out \the [src] onto the floor using the release valve.", "You quietly empty out \the [src] using its release valve.")
+
diff --git a/code/game/objects/structures/lattice.dm b/code/game/objects/structures/lattice.dm
index 40435c2000..d6f304653d 100644
--- a/code/game/objects/structures/lattice.dm
+++ b/code/game/objects/structures/lattice.dm
@@ -51,6 +51,20 @@
new /obj/item/stack/rods(get_turf(src), number_of_rods)
qdel(src)
+/obj/structure/lattice/rcd_vals(mob/user, obj/item/construction/rcd/the_rcd)
+ if(the_rcd.mode == RCD_FLOORWALL)
+ return list("mode" = RCD_FLOORWALL, "delay" = 0, "cost" = 2)
+
+/obj/structure/lattice/rcd_act(mob/user, obj/item/construction/rcd/the_rcd, passed_mode)
+ if(passed_mode == RCD_FLOORWALL)
+ to_chat(user, "You build a floor.")
+ var/turf/T = src.loc
+ if(isspaceturf(T))
+ T.PlaceOnTop(/turf/open/floor/plating)
+ qdel(src)
+ return TRUE
+ return FALSE
+
/obj/structure/lattice/singularity_pull(S, current_size)
if(current_size >= STAGE_FOUR)
deconstruct()
diff --git a/code/game/turfs/open.dm b/code/game/turfs/open.dm
index 659a58b2dc..63b5f4b160 100644
--- a/code/game/turfs/open.dm
+++ b/code/game/turfs/open.dm
@@ -245,6 +245,10 @@
return 0
if(C.m_intent == MOVE_INTENT_WALK && (lube&NO_SLIP_WHEN_WALKING))
return 0
+ if(ishuman(C) && (lube&NO_SLIP_WHEN_WALKING))
+ var/mob/living/carbon/human/H = C
+ if(!H.sprinting && H.getStaminaLoss() >= 20)
+ return 0
if(!(lube&SLIDE_ICE))
to_chat(C, "You slipped[ O ? " on the [O.name]" : ""]!")
playsound(C.loc, 'sound/misc/slip.ogg', 50, 1, -3)
diff --git a/code/game/turfs/simulated/floor/plating.dm b/code/game/turfs/simulated/floor/plating.dm
index 9d2adbdfba..e783b8a9a0 100644
--- a/code/game/turfs/simulated/floor/plating.dm
+++ b/code/game/turfs/simulated/floor/plating.dm
@@ -126,6 +126,17 @@
else
to_chat(user, "You hit [src], to no effect!")
+/turf/open/floor/plating/foam/rcd_vals(mob/user, obj/item/construction/rcd/the_rcd)
+ if(the_rcd.mode == RCD_FLOORWALL)
+ return list("mode" = RCD_FLOORWALL, "delay" = 0, "cost" = 1)
+
+/turf/open/floor/plating/foam/rcd_act(mob/user, obj/item/construction/rcd/the_rcd, passed_mode)
+ if(passed_mode == RCD_FLOORWALL)
+ to_chat(user, "You build a floor.")
+ ChangeTurf(/turf/open/floor/plating)
+ return TRUE
+ return FALSE
+
/turf/open/floor/plating/foam/ex_act()
..()
ScrapeAway()
diff --git a/code/game/turfs/space/transit.dm b/code/game/turfs/space/transit.dm
index 7dcf27ce4b..f0f0667c37 100644
--- a/code/game/turfs/space/transit.dm
+++ b/code/game/turfs/space/transit.dm
@@ -41,6 +41,14 @@
/turf/open/space/transit/border/east
dir = EAST
+/turf/open/space/transit/centcom
+ dir = SOUTH
+
+/turf/open/space/transit/centcom/Entered(atom/movable/AM, atom/OldLoc)
+ ..()
+ if(!locate(/obj/structure/lattice) in src)
+ throw_atom(AM)
+
/turf/open/space/transit/border/Entered(atom/movable/AM, atom/OldLoc)
..()
if(!locate(/obj/structure/lattice) in src)
diff --git a/code/modules/VR/vr_sleeper.dm b/code/modules/VR/vr_sleeper.dm
index 7169378179..4e342f6ced 100644
--- a/code/modules/VR/vr_sleeper.dm
+++ b/code/modules/VR/vr_sleeper.dm
@@ -167,6 +167,7 @@
vr_human.undershirt = H.undershirt
vr_human.underwear = H.underwear
vr_human.updateappearance(TRUE, TRUE, TRUE)
+ vr_human.give_genitals(TRUE) //CITADEL ADD
if(outfit)
var/datum/outfit/O = new outfit()
O.equip(vr_human)
@@ -229,4 +230,4 @@
for (var/mob/living/carbon/human/virtual_reality/H in vr_area)
if (H.stat == DEAD && !H.vr_sleeper && !H.real_mind)
qdel(H)
- addtimer(CALLBACK(src, .proc/clean_up), 3 MINUTES)
\ No newline at end of file
+ addtimer(CALLBACK(src, .proc/clean_up), 3 MINUTES)
diff --git a/code/modules/admin/verbs/SDQL2/SDQL_2.dm b/code/modules/admin/verbs/SDQL2/SDQL_2.dm
index 85866d5c51..f5075b57b7 100644
--- a/code/modules/admin/verbs/SDQL2/SDQL_2.dm
+++ b/code/modules/admin/verbs/SDQL2/SDQL_2.dm
@@ -714,7 +714,7 @@ GLOBAL_DATUM_INIT(sdql2_vv_statobj, /obj/effect/statclick/SDQL2_VV_all, new(null
SDQL_print(x, text_list)
if (!isnull(x) && !isnum(x) && L[x] != null)
text_list += " -> "
- SDQL_print(L[L[x]])
+ SDQL_print(L[L[x]], text_list)
text_list += "]
"
else
if(isnull(object))
diff --git a/code/modules/admin/verbs/SDQL2/SDQL_2_wrappers.dm b/code/modules/admin/verbs/SDQL2/SDQL_2_wrappers.dm
index a984e40fee..3056b459d8 100644
--- a/code/modules/admin/verbs/SDQL2/SDQL_2_wrappers.dm
+++ b/code/modules/admin/verbs/SDQL2/SDQL_2_wrappers.dm
@@ -184,6 +184,9 @@
/proc/_list_swap(list/L, Index1, Index2)
L.Swap(Index1, Index2)
+/proc/_list_get(list/L, index)
+ return L[index]
+
/proc/_walk(ref, dir, lag)
walk(ref, dir, lag)
diff --git a/code/modules/admin/verbs/panicbunker.dm b/code/modules/admin/verbs/panicbunker.dm
index 175ab45aeb..ab3aeb4ba5 100644
--- a/code/modules/admin/verbs/panicbunker.dm
+++ b/code/modules/admin/verbs/panicbunker.dm
@@ -22,7 +22,7 @@
to_chat(usr, "The Database is not enabled!")
return
- GLOB.bunker_passthrough |= ckeytobypass
+ GLOB.bunker_passthrough |= ckey(ckeytobypass)
log_admin("[key_name(usr)] has added [ckeytobypass] to the current round's bunker bypass list.")
message_admins("[key_name(usr)] has added [ckeytobypass] to the current round's bunker bypass list.")
@@ -34,7 +34,7 @@
to_chat(usr, "The Database is not enabled!")
return
- GLOB.bunker_passthrough -= ckeytobypass
+ GLOB.bunker_passthrough -= ckey(ckeytobypass)
log_admin("[key_name(usr)] has removed [ckeytobypass] from the current round's bunker bypass list.")
message_admins("[key_name(usr)] has removed [ckeytobypass] from the current round's bunker bypass list.")
diff --git a/code/modules/antagonists/cult/runes.dm b/code/modules/antagonists/cult/runes.dm
index 51c8803cee..f3975851ca 100644
--- a/code/modules/antagonists/cult/runes.dm
+++ b/code/modules/antagonists/cult/runes.dm
@@ -185,6 +185,9 @@ structure_check() searches for nearby cultist structures required for the invoca
color = RUNE_COLOR_OFFER
req_cultists = 1
rune_in_use = FALSE
+ var/mob/living/currentconversionman
+ var/conversiontimeout
+ var/conversionresult
/obj/effect/rune/convert/do_invoke_glow()
return
@@ -241,6 +244,25 @@ structure_check() searches for nearby cultist structures required for the invoca
to_chat(M, "Something is shielding [convertee]'s mind!")
log_game("Offer rune failed - convertee had anti-magic")
return 0
+ to_chat(convertee, "Your blood pulses. Your head throbs. The world goes red. All at once you are aware of a horrible, horrible, truth. The veil of reality has been ripped away \
+ and something evil takes root.")
+ to_chat(convertee, "Do you wish to embrace the Geometer of Blood? Click here to stop resisting the truth. Or you could choose to continue resisting...")
+ currentconversionman = convertee
+ conversiontimeout = world.time + (10 SECONDS)
+ convertee.Stun(100)
+ convertee.add_trait(TRAIT_MUTE, "conversionrune")
+ conversionresult = FALSE
+ while(world.time < conversiontimeout && convertee && !conversionresult)
+ stoplag(1)
+ currentconversionman = null
+ if(!convertee)
+ return FALSE
+ convertee.remove_trait(TRAIT_MUTE, "conversionrune")
+ if(get_turf(convertee) != get_turf(src))
+ return FALSE
+ if(!conversionresult)
+ do_sacrifice(convertee, invokers, TRUE)
+ return FALSE
var/brutedamage = convertee.getBruteLoss()
var/burndamage = convertee.getFireLoss()
if(brutedamage || burndamage)
@@ -252,8 +274,6 @@ structure_check() searches for nearby cultist structures required for the invoca
SSticker.mode.add_cultist(convertee.mind, 1)
new /obj/item/melee/cultblade/dagger(get_turf(src))
convertee.mind.special_role = ROLE_CULTIST
- to_chat(convertee, "Your blood pulses. Your head throbs. The world goes red. All at once you are aware of a horrible, horrible, truth. The veil of reality has been ripped away \
- and something evil takes root.")
to_chat(convertee, "Assist your new compatriots in their dark dealings. Your goal is theirs, and theirs is yours. You serve the Geometer above all else. Bring it back.\
")
if(ishuman(convertee))
@@ -263,7 +283,7 @@ structure_check() searches for nearby cultist structures required for the invoca
H.cultslurring = 0
return 1
-/obj/effect/rune/convert/proc/do_sacrifice(mob/living/sacrificial, list/invokers)
+/obj/effect/rune/convert/proc/do_sacrifice(mob/living/sacrificial, list/invokers, force_a_sac)
var/mob/living/first_invoker = invokers[1]
if(!first_invoker)
return FALSE
@@ -273,7 +293,7 @@ structure_check() searches for nearby cultist structures required for the invoca
var/big_sac = FALSE
- if((((ishuman(sacrificial) || iscyborg(sacrificial)) && sacrificial.stat != DEAD) || C.cult_team.is_sacrifice_target(sacrificial.mind)) && invokers.len < 3)
+ if(!force_a_sac && (((ishuman(sacrificial) || iscyborg(sacrificial)) && sacrificial.stat != DEAD) || C.cult_team.is_sacrifice_target(sacrificial.mind)) && invokers.len < 3)
for(var/M in invokers)
to_chat(M, "[sacrificial] is too greatly linked to the world! You need three acolytes!")
log_game("Offer rune failed - not enough acolytes and target is living or sac target")
@@ -313,6 +333,12 @@ structure_check() searches for nearby cultist structures required for the invoca
sacrificial.gib()
return TRUE
+/obj/effect/rune/convert/Topic(href, href_list)
+ if(href_list["signmeup"])
+ if(currentconversionman == usr)
+ conversionresult = TRUE
+ else
+ to_chat(usr, "Your fate has already been set in stone.")
/obj/effect/rune/empower
@@ -442,9 +468,9 @@ structure_check() searches for nearby cultist structures required for the invoca
//Ritual of Dimensional Rending: Calls forth the avatar of Nar'Sie upon the station.
/obj/effect/rune/narsie
cultist_name = "Nar'Sie"
- cultist_desc = "tears apart dimensional barriers, calling forth the Geometer. Requires 9 invokers."
+ cultist_desc = "tears apart dimensional barriers, calling forth the Geometer. Requires 9 invokers, minus one for every 3 sacrifices."
invocation = "TOK-LYR RQA-NAP G'OLT-ULOFT!!"
- req_cultists = 9
+ req_cultists = 1
icon = 'icons/effects/96x96.dmi'
color = RUNE_COLOR_DARKRED
icon_state = "rune_large"
@@ -471,6 +497,10 @@ structure_check() searches for nearby cultist structures required for the invoca
if(!is_station_level(z))
return
var/mob/living/user = invokers[1]
+ if(invokers.len < 9 - (GLOB.sacrificed.len * 0.35))
+ to_chat(user, "You need at least [(9 - (GLOB.sacrificed.len * 0.35)) - invokers.len] more adjacent cultists to use this rune in such a manner.")
+ fail_invoke()
+ return
var/datum/antagonist/cult/user_antag = user.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
var/datum/objective/eldergod/summon_objective = locate() in user_antag.cult_team.objectives
var/area/place = get_area(src)
diff --git a/code/modules/atmospherics/machinery/components/binary_devices/circulator.dm b/code/modules/atmospherics/machinery/components/binary_devices/circulator.dm
index 6bafba9abc..07ee17a1bd 100644
--- a/code/modules/atmospherics/machinery/components/binary_devices/circulator.dm
+++ b/code/modules/atmospherics/machinery/components/binary_devices/circulator.dm
@@ -61,6 +61,8 @@
//Actually transfer the gas
var/datum/gas_mixture/removed = air2.remove(transfer_moles)
+ removed.react(src)
+
update_parents()
return removed
diff --git a/code/modules/cargo/packs.dm b/code/modules/cargo/packs.dm
index bc7193e5ca..a9972ca2d4 100644
--- a/code/modules/cargo/packs.dm
+++ b/code/modules/cargo/packs.dm
@@ -622,7 +622,7 @@
/datum/supply_pack/security/armory/wt550
- name = "WT-550 Auto Rifle Crate"
+ name = "WT-550 Semi-Auto Rifle Crate"
desc = "Contains two high-powered, semiautomatic rifles chambered in 4.6x30mm. Requires Armory access to open."
cost = 3500
contains = list(/obj/item/gun/ballistic/automatic/wt550,
@@ -630,8 +630,8 @@
crate_name = "auto rifle crate"
/datum/supply_pack/security/armory/wt550ammo
- name = "WT-550 Auto Rifle Ammo Crate"
- desc = "Contains four 20-round magazines for the WT-550 Auto Rifle. Each magazine is designed to facilitate rapid tactical reloads. Requires Armory access to open."
+ name = "WT-550 Semi-Auto SMG Ammo Crate"
+ desc = "Contains four 20-round magazines for the WT-550 Semi-Auto SMG. Each magazine is designed to facilitate rapid tactical reloads. Requires Armory access to open."
cost = 2500
contains = list(/obj/item/ammo_box/magazine/wt550m9,
/obj/item/ammo_box/magazine/wt550m9,
@@ -639,9 +639,9 @@
/obj/item/ammo_box/magazine/wt550m9)
crate_name = "auto rifle ammo crate"
-/datum/supply_pack/security/armory/wt550ammo_nonlethal // Takes around 11 shots to stun crit someone
- name = "WT-550 Auto Rifle Non-Lethal Ammo Crate"
- desc = "Contains four 20-round magazines for the WT-550 Auto Rifle. Each magazine is designed to facilitate rapid tactical reloads. Requires Armory access to open."
+/datum/supply_pack/security/armory/wt550ammo_nonlethal // Takes around 12 shots to stun crit someone
+ name = "WT-550 Semi-Auto SMG Non-Lethal Ammo Crate"
+ desc = "Contains four 20-round magazines for the WT-550 Semi-Auto SMG. Each magazine is designed to facilitate rapid tactical reloads. Requires Armory access to open."
cost = 1500
contains = list(/obj/item/ammo_box/magazine/wt550m9/wtrubber,
/obj/item/ammo_box/magazine/wt550m9/wtrubber,
@@ -650,8 +650,8 @@
crate_name = "auto rifle ammo crate"
/datum/supply_pack/security/armory/wt550ammo_special
- name = "WT-550 Auto Rifle Special Ammo Crate"
- desc = "Contains 2 20-round Armour Piercing and Incendiary magazines for the WT-550 Auto Rifle. Each magazine is designed to facilitate rapid tactical reloads. Requires Armory access to open."
+ name = "WT-550 Semi-Auto SMG Special Ammo Crate"
+ desc = "Contains 2 20-round Armour Piercing and Incendiary magazines for the WT-550 Semi-Auto SMG. Each magazine is designed to facilitate rapid tactical reloads. Requires Armory access to open."
cost = 4500
contains = list(/obj/item/ammo_box/magazine/wt550m9/wtap,
/obj/item/ammo_box/magazine/wt550m9/wtap,
diff --git a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm
index 18f50f03a3..06f23574e1 100644
--- a/code/modules/client/client_procs.dm
+++ b/code/modules/client/client_procs.dm
@@ -499,7 +499,7 @@ GLOBAL_LIST_EMPTY(external_rsc_urls)
qdel(query_client_in_db)
return
if(!query_client_in_db.NextRow())
- if (CONFIG_GET(flag/panic_bunker) && !holder && !GLOB.deadmins[ckey] && !ckey in GLOB.bunker_passthrough)
+ if (CONFIG_GET(flag/panic_bunker) && !holder && !GLOB.deadmins[ckey] && !(ckey in GLOB.bunker_passthrough))
log_access("Failed Login: [key] - New account attempting to connect during panic bunker")
message_admins("Failed Login: [key] - New account attempting to connect during panic bunker")
to_chat(src, "You must first join the Discord to verify your account before joining this server.
To do so, read the rules and post a request in the #station-access-requests channel under the \"Main server\" category in the Discord server linked here: https://discord.gg/E6SQuhz") //CIT CHANGE - makes the panic bunker disconnect message point to the discord
diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm
index 1e65c6ca3f..746d5da60d 100644
--- a/code/modules/clothing/clothing.dm
+++ b/code/modules/clothing/clothing.dm
@@ -24,6 +24,8 @@
var/can_flashlight = 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.
+
var/clothing_flags = NONE
//Var modification - PLEASE be careful with this I know who you are and where you live
diff --git a/code/modules/clothing/head/helmet.dm b/code/modules/clothing/head/helmet.dm
index 7265800c49..ab9ffb9b18 100644
--- a/code/modules/clothing/head/helmet.dm
+++ b/code/modules/clothing/head/helmet.dm
@@ -3,7 +3,7 @@
desc = "Standard Security gear. Protects the head from impacts."
icon_state = "helmet"
item_state = "helmet"
- armor = list("melee" = 35, "bullet" = 30, "laser" = 30,"energy" = 10, "bomb" = 25, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 50)
+ armor = list("melee" = 40, "bullet" = 30, "laser" = 30,"energy" = 10, "bomb" = 25, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 50)
flags_inv = HIDEEARS
cold_protection = HEAD
min_cold_protection_temperature = HELMET_MIN_TEMP_PROTECT
diff --git a/code/modules/clothing/head/jobs.dm b/code/modules/clothing/head/jobs.dm
index ad8fafb872..8b1b1dac25 100644
--- a/code/modules/clothing/head/jobs.dm
+++ b/code/modules/clothing/head/jobs.dm
@@ -139,7 +139,7 @@
name = "security beret"
desc = "A robust beret with the security insignia emblazoned on it. Uses reinforced fabric to offer sufficient protection."
icon_state = "beret_badge"
- armor = list("melee" = 40, "bullet" = 30, "laser" = 30,"energy" = 10, "bomb" = 25, "bio" = 0, "rad" = 0, "fire" = 20, "acid" = 50)
+ armor = list("melee" = 40, "bullet" = 30, "laser" = 30,"energy" = 10, "bomb" = 25, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 50)
strip_delay = 60
dog_fashion = null
@@ -152,7 +152,7 @@
name = "warden's beret"
desc = "A special beret with the Warden's insignia emblazoned on it. For wardens with class."
icon_state = "wardenberet"
- armor = list("melee" = 40, "bullet" = 30, "laser" = 30, "energy" = 10, "bomb" = 25, "bio" = 0, "rad" = 0, "fire" = 30, "acid" = 50)
+ armor = list("melee" = 40, "bullet" = 30, "laser" = 30, "energy" = 10, "bomb" = 25, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 50)
strip_delay = 60
/obj/item/clothing/head/beret/sec/navyofficer
diff --git a/code/modules/clothing/suits/armor.dm b/code/modules/clothing/suits/armor.dm
index 97c9da289b..b10bf39729 100644
--- a/code/modules/clothing/suits/armor.dm
+++ b/code/modules/clothing/suits/armor.dm
@@ -110,13 +110,14 @@
/obj/item/clothing/suit/armor/riot
name = "riot suit"
- desc = "A suit of semi-flexible polycarbonate body armor with heavy padding to protect against melee attacks."
+ desc = "A suit of semi-flexible polycarbonate body armor with heavy padding to protect against melee attacks. Helps the wearer resist shoving in close quarters."
icon_state = "riot"
item_state = "swat_suit"
body_parts_covered = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
cold_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
heat_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
armor = list("melee" = 50, "bullet" = 10, "laser" = 10, "energy" = 10, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 80, "acid" = 80)
+ blocks_shove_knockdown = TRUE
strip_delay = 80
equip_delay_other = 60
diff --git a/code/modules/mining/equipment/kinetic_crusher.dm b/code/modules/mining/equipment/kinetic_crusher.dm
index 2e695e6772..b8195e23d9 100644
--- a/code/modules/mining/equipment/kinetic_crusher.dm
+++ b/code/modules/mining/equipment/kinetic_crusher.dm
@@ -239,10 +239,10 @@
if(ishostile(target))
var/mob/living/simple_animal/hostile/H = target
if(H.ranged) //briefly delay ranged attacks
- if(H.ranged_cooldown_time >= world.time)
- H.ranged_cooldown_time += bonus_value
+ if(H.ranged_cooldown >= world.time)
+ H.ranged_cooldown += bonus_value
else
- H.ranged_cooldown_time = bonus_value + world.time
+ H.ranged_cooldown = bonus_value + world.time
//magmawing watcher
/obj/item/crusher_trophy/blaster_tubes/magma_wing
diff --git a/code/modules/mining/machine_vending.dm b/code/modules/mining/machine_vending.dm
index 1e77a907c6..7276039443 100644
--- a/code/modules/mining/machine_vending.dm
+++ b/code/modules/mining/machine_vending.dm
@@ -11,6 +11,7 @@
var/obj/item/card/id/inserted_id
var/list/prize_list = list( //if you add something to this, please, for the love of god, sort it by price/type. use tabs and not spaces.
new /datum/data/mining_equipment("1 Marker Beacon", /obj/item/stack/marker_beacon, 10),
+ new /datum/data/mining_equipment("50 Point Transfer Card", /obj/item/card/mining_point_card, 50),
new /datum/data/mining_equipment("10 Marker Beacons", /obj/item/stack/marker_beacon/ten, 100),
new /datum/data/mining_equipment("30 Marker Beacons", /obj/item/stack/marker_beacon/thirty, 300),
new /datum/data/mining_equipment("Whiskey", /obj/item/reagent_containers/food/drinks/bottle/whiskey, 100),
@@ -23,7 +24,7 @@
new /datum/data/mining_equipment("Shelter Capsule", /obj/item/survivalcapsule, 400),
new /datum/data/mining_equipment("GAR Meson Scanners", /obj/item/clothing/glasses/meson/gar, 500),
new /datum/data/mining_equipment("Explorer's Webbing", /obj/item/storage/belt/mining, 500),
- new /datum/data/mining_equipment("Point Transfer Card", /obj/item/card/mining_point_card, 500),
+ new /datum/data/mining_equipment("500 Point Transfer Card", /obj/item/card/mining_point_card/mp500, 500),
new /datum/data/mining_equipment("Brute First-Aid Kit", /obj/item/storage/firstaid/brute, 600),
new /datum/data/mining_equipment("Tracking Implant Kit", /obj/item/storage/box/minertracker, 600),
new /datum/data/mining_equipment("Survival Medipen", /obj/item/reagent_containers/hypospray/medipen/survival, 750),
@@ -41,6 +42,9 @@
new /datum/data/mining_equipment("Lazarus Injector", /obj/item/lazarus_injector, 1000),
new /datum/data/mining_equipment("Silver Pickaxe", /obj/item/pickaxe/silver, 1000),
new /datum/data/mining_equipment("Mining Conscription Kit", /obj/item/storage/backpack/duffelbag/mining_conscript, 1000),
+ new /datum/data/mining_equipment("1000 Point Transfer Card", /obj/item/card/mining_point_card/mp1000, 1000),
+ new /datum/data/mining_equipment("1500 Point Transfer Card", /obj/item/card/mining_point_card/mp1500, 1500),
+ new /datum/data/mining_equipment("2000 Point Transfer Card", /obj/item/card/mining_point_card/mp2000, 2000),
new /datum/data/mining_equipment("Jetpack Upgrade", /obj/item/tank/jetpack/suit, 2000),
new /datum/data/mining_equipment("Space Cash", /obj/item/stack/spacecash/c1000, 2000),
new /datum/data/mining_equipment("Mining Hardsuit", /obj/item/clothing/suit/space/hardsuit/mining, 2000),
@@ -245,12 +249,30 @@
w_class = WEIGHT_CLASS_TINY
/**********************Mining Point Card**********************/
-
+//mp = Miner Pointers
+//c = Cash
+//TODO add in cr = Credits for cargo
/obj/item/card/mining_point_card
name = "mining points card"
- desc = "A small card preloaded with mining points. Swipe your ID card over it to transfer the points, then discard."
+ desc = "A small card preloaded with mining points. Swipe your ID card over it to transfer the points, then discard. This one only holds a small 50 points on it."
icon_state = "data_1"
- var/points = 500
+ var/points = 50
+
+/obj/item/card/mining_point_card/mp500
+ desc = "A small card preloaded with 500 mining points. Swipe your ID card over it to transfer the points, then discard."
+ points = 500
+
+/obj/item/card/mining_point_card/mp1000
+ desc = "A small card preloaded with 1000 mining points. Swipe your ID card over it to transfer the points, then discard."
+ points = 1000
+
+/obj/item/card/mining_point_card/mp1500
+ desc = "A small card preloaded with 1500 mining points. Swipe your ID card over it to transfer the points, then discard."
+ points = 1500
+
+/obj/item/card/mining_point_card/mp2000
+ desc = "A small card preloaded with 2000 mining points. Swipe your ID card over it to transfer the points, then discard."
+ points = 2000
/obj/item/card/mining_point_card/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/card/id))
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index 7909b5e71a..fa66daf143 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -495,11 +495,11 @@
/mob/living/carbon/human/proc/canUseHUD()
return !(src.stat || IsKnockdown() || IsStun() || src.restrained())
-/mob/living/carbon/human/can_inject(mob/user, error_msg, target_zone, var/penetrate_thick = 0)
+/mob/living/carbon/human/can_inject(mob/user, error_msg, target_zone, penetrate_thick = FALSE, bypass_immunity = FALSE)
. = 1 // Default to returning true.
if(user && !target_zone)
target_zone = user.zone_selected
- if(has_trait(TRAIT_PIERCEIMMUNE))
+ if(has_trait(TRAIT_PIERCEIMMUNE) && !bypass_immunity)
. = 0
// If targeting the head, see if the head item is thin enough.
// If targeting anything else, see if the wear suit is thin enough.
@@ -892,6 +892,21 @@
. = ..(M,force,check_loc)
stop_pulling()
+/mob/living/carbon/human/proc/is_shove_knockdown_blocked() //If you want to add more things that block shove knockdown, extend this
+ var/list/body_parts = list(head, wear_mask, wear_suit, w_uniform, back, gloves, shoes, belt, s_store, glasses, ears, wear_id) //Everything but pockets. Pockets are l_store and r_store. (if pockets were allowed, putting something armored, gloves or hats for example, would double up on the armor)
+ for(var/bp in body_parts)
+ if(istype(bp, /obj/item/clothing))
+ var/obj/item/clothing/C = bp
+ if(C.blocks_shove_knockdown)
+ return TRUE
+ return FALSE
+
+/mob/living/carbon/human/proc/clear_shove_slowdown()
+ remove_movespeed_modifier(SHOVE_SLOWDOWN_ID)
+ var/active_item = get_active_held_item()
+ if(is_type_in_typecache(active_item, GLOB.shove_disarming_types))
+ visible_message("[src.name] regains their grip on \the [active_item]!", "You regain your grip on \the [active_item]", null, COMBAT_MESSAGE_RANGE)
+
/mob/living/carbon/human/do_after_coefficent()
. = ..()
. *= physiology.do_after_speed
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index 7c0eaacf26..0e67ce7510 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -170,6 +170,9 @@
var/mob/living/L = M
if(L.has_trait(TRAIT_PUSHIMMUNE))
return 1
+ //If they're a human, and they're not in help intent, block pushing
+ if(ishuman(M) && (M.a_intent != INTENT_HELP))
+ return TRUE
//anti-riot equipment is also anti-push
for(var/obj/item/I in M.held_items)
if(!istype(M, /obj/item/clothing))
diff --git a/code/modules/power/cell.dm b/code/modules/power/cell.dm
index a36800c2f9..e43db529b8 100644
--- a/code/modules/power/cell.dm
+++ b/code/modules/power/cell.dm
@@ -192,7 +192,7 @@
/obj/item/stock_parts/cell/secborg
name = "security borg rechargeable D battery"
- maxcharge = 600 //600 max charge / 100 charge per shot = six shots
+ maxcharge = 1750 //35/17/8 disabler/laser/taser shots.
materials = list(MAT_GLASS=40)
/obj/item/stock_parts/cell/secborg/empty/Initialize()
diff --git a/code/modules/power/generator.dm b/code/modules/power/generator.dm
index 8e121dc809..fcc2c6c144 100644
--- a/code/modules/power/generator.dm
+++ b/code/modules/power/generator.dm
@@ -65,7 +65,7 @@
if(delta_temperature > 0 && cold_air_heat_capacity > 0 && hot_air_heat_capacity > 0)
- var/efficiency = 0.45
+ var/efficiency = 0.00025 + (hot_air.reaction_results["fire"]*0.01)
var/energy_transfer = delta_temperature*hot_air_heat_capacity*cold_air_heat_capacity/(hot_air_heat_capacity+cold_air_heat_capacity)
diff --git a/code/modules/power/singularity/emitter.dm b/code/modules/power/singularity/emitter.dm
index 9d2ad4c12a..a04ed08611 100644
--- a/code/modules/power/singularity/emitter.dm
+++ b/code/modules/power/singularity/emitter.dm
@@ -66,7 +66,7 @@
sparks = new
sparks.attach(src)
- sparks.set_up(5, TRUE, src)
+ sparks.set_up(1, TRUE, src)
/obj/machinery/power/emitter/ComponentInitialize()
. = ..()
diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm
index ae6e309507..a7474fd8cb 100644
--- a/code/modules/projectiles/gun.dm
+++ b/code/modules/projectiles/gun.dm
@@ -451,6 +451,8 @@
target.visible_message("[user] pulls the trigger!", "[user] pulls the trigger!")
+ playsound('sound/weapons/dink.ogg', 30, 1)
+
if(chambered && chambered.BB)
chambered.BB.damage *= 5
diff --git a/code/modules/projectiles/guns/ballistic.dm b/code/modules/projectiles/guns/ballistic.dm
index b9a509f33f..157cf1f03f 100644
--- a/code/modules/projectiles/guns/ballistic.dm
+++ b/code/modules/projectiles/guns/ballistic.dm
@@ -161,6 +161,7 @@
var/turf/T = get_turf(user)
process_fire(user, user, FALSE, null, BODY_ZONE_HEAD)
user.visible_message("[user] blows [user.p_their()] brain[user.p_s()] out with [src]!")
+ playsound(src, 'sound/weapons/dink.ogg', 30, 1)
var/turf/target = get_ranged_target_turf(user, turn(user.dir, 180), BRAINS_BLOWN_THROW_RANGE)
B.Remove(user)
B.forceMove(T)
diff --git a/code/modules/projectiles/guns/ballistic/automatic.dm b/code/modules/projectiles/guns/ballistic/automatic.dm
index d1dcdf22d8..8aa8d53726 100644
--- a/code/modules/projectiles/guns/ballistic/automatic.dm
+++ b/code/modules/projectiles/guns/ballistic/automatic.dm
@@ -113,8 +113,8 @@
icon_state = "c20r[magazine ? "-[CEILING(get_ammo(0)/4, 1)*4]" : ""][chambered ? "" : "-e"][suppressed ? "-suppressed" : ""]"
/obj/item/gun/ballistic/automatic/wt550
- name = "security auto rifle"
- desc = "An outdated personal defence weapon. Uses 4.6x30mm rounds and is designated the WT-550 Automatic Rifle."
+ name = "security semi-auto smg"
+ desc = "An outdated personal defence weapon. Uses 4.6x30mm rounds and is designated the WT-550 Semi-Automatic SMG."
icon_state = "wt550"
item_state = "arg"
mag_type = /obj/item/ammo_box/magazine/wt550m9
diff --git a/code/modules/projectiles/guns/energy.dm b/code/modules/projectiles/guns/energy.dm
index 5e3432a149..6060ceba99 100644
--- a/code/modules/projectiles/guns/energy.dm
+++ b/code/modules/projectiles/guns/energy.dm
@@ -184,6 +184,7 @@
if(user.is_holding(src))
user.visible_message("[user] melts [user.p_their()] face off with [src]!")
playsound(loc, fire_sound, 50, 1, -1)
+ playsound(src, 'sound/weapons/dink.ogg', 30, 1)
var/obj/item/ammo_casing/energy/shot = ammo_type[select]
cell.use(shot.e_cost)
update_icon()
diff --git a/code/modules/projectiles/guns/energy/laser.dm b/code/modules/projectiles/guns/energy/laser.dm
index a549e309c8..066b652984 100644
--- a/code/modules/projectiles/guns/energy/laser.dm
+++ b/code/modules/projectiles/guns/energy/laser.dm
@@ -50,7 +50,8 @@
can_charge = FALSE
desc = "An energy-based laser gun that draws power from the cyborg's internal energy cell directly. So this is what freedom looks like?"
selfcharge = EGUN_SELFCHARGE_BORG
- charge_delay = 6
+ cell_type = /obj/item/stock_parts/cell/secborg
+ charge_delay = 3
/obj/item/gun/energy/laser/cyborg/emp_act()
return
diff --git a/code/modules/projectiles/guns/energy/stun.dm b/code/modules/projectiles/guns/energy/stun.dm
index 7368a9fa7b..3733dad9a3 100644
--- a/code/modules/projectiles/guns/energy/stun.dm
+++ b/code/modules/projectiles/guns/energy/stun.dm
@@ -29,7 +29,8 @@
can_flashlight = FALSE
can_charge = FALSE
selfcharge = EGUN_SELFCHARGE_BORG
- charge_delay = 10
+ cell_type = /obj/item/stock_parts/cell/secborg
+ charge_delay = 5
/obj/item/gun/energy/e_gun/advtaser/cyborg/mean
desc = "An integrated hybrid taser that draws directly from a cyborg's power cell."
@@ -49,7 +50,8 @@
desc = "An integrated disabler that draws from a cyborg's power cell. This one contains a limiter to prevent the cyborg's power cell from overheating."
can_charge = FALSE
selfcharge = EGUN_SELFCHARGE_BORG
- charge_delay = 10
+ cell_type = /obj/item/stock_parts/cell/secborg
+ charge_delay = 5
/obj/item/gun/energy/disabler/cyborg/mean
desc = "An integrated disabler that draws from a cyborg's power cell."
diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm
index 267770eb22..1391e9ce42 100644
--- a/code/modules/projectiles/projectile.dm
+++ b/code/modules/projectiles/projectile.dm
@@ -185,6 +185,8 @@
playsound(loc, hitsound, volume, 1, -1)
L.visible_message("[L] is hit by \a [src][organ_hit_text]!", \
"[L] is hit by \a [src][organ_hit_text]!", null, COMBAT_MESSAGE_RANGE)
+ if(def_zone == BODY_ZONE_HEAD)
+ playsound(src, 'sound/weapons/dink.ogg', 30, 1)
L.on_hit(src)
var/reagent_note
diff --git a/code/modules/reagents/chemistry/reagents/drug_reagents.dm b/code/modules/reagents/chemistry/reagents/drug_reagents.dm
index eb3daef393..d77756a649 100644
--- a/code/modules/reagents/chemistry/reagents/drug_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/drug_reagents.dm
@@ -167,10 +167,10 @@
/datum/reagent/drug/methamphetamine/on_mob_add(mob/living/L)
..()
- L.add_trait(TRAIT_GOTTAGOREALLYFAST, id)
+ L.add_trait(TRAIT_IGNORESLOWDOWN, id)
/datum/reagent/drug/methamphetamine/on_mob_delete(mob/living/L)
- L.remove_trait(TRAIT_GOTTAGOREALLYFAST, id)
+ L.remove_trait(TRAIT_IGNORESLOWDOWN, id)
..()
/datum/reagent/drug/methamphetamine/on_mob_life(mob/living/carbon/M)
@@ -180,9 +180,12 @@
M.AdjustStun(-40, 0)
M.AdjustKnockdown(-40, 0)
M.AdjustUnconscious(-40, 0)
- M.adjustStaminaLoss(-2, 0)
+ M.adjustStaminaLoss(-7.5 * REM, 0)
M.Jitter(2)
M.adjustBrainLoss(rand(1,4))
+ if(prob(30))
+ M.confused = max(1, M.confused)
+ M.heal_overall_damage(2, 2)
if(prob(5))
M.emote(pick("twitch", "shiver"))
..()
diff --git a/code/modules/reagents/reagent_containers/patch.dm b/code/modules/reagents/reagent_containers/patch.dm
index d4111467ba..12439c6b2f 100644
--- a/code/modules/reagents/reagent_containers/patch.dm
+++ b/code/modules/reagents/reagent_containers/patch.dm
@@ -14,11 +14,11 @@
/obj/item/reagent_containers/pill/patch/attack(mob/living/L, mob/user)
if(ishuman(L))
var/obj/item/bodypart/affecting = L.get_bodypart(check_zone(user.zone_selected))
- if(!L.can_inject(user, 1, affecting)) //like monkey code, thickmaterial stops patches
- return
if(!affecting)
to_chat(user, "The limb is missing!")
return
+ if(!L.can_inject(user, TRUE, user.zone_selected, FALSE, TRUE)) //stopped by clothing, not by species immunity.
+ return
if(affecting.status != BODYPART_ORGANIC)
to_chat(user, "Medicine won't work on a robotic limb!")
return
diff --git a/code/modules/research/designs/weapon_designs.dm b/code/modules/research/designs/weapon_designs.dm
index 2402967ff3..9b42709fe2 100644
--- a/code/modules/research/designs/weapon_designs.dm
+++ b/code/modules/research/designs/weapon_designs.dm
@@ -218,8 +218,8 @@
//WT550 Mags
/datum/design/mag_oldsmg
- name = "WT-550 Auto Gun Magazine (4.6x30mm)"
- desc = "A 20 round magazine for the out of date security WT-550 Auto Rifle"
+ name = "WT-550 Semi-Auto SMG Magazine (4.6x30mm)"
+ desc = "A 20 round magazine for the out of date security WT-550 Semi-Auto SMG."
id = "mag_oldsmg"
build_type = PROTOLATHE
materials = list(MAT_METAL = 4000)
@@ -228,16 +228,16 @@
departmental_flags = DEPARTMENTAL_FLAG_SECURITY
/datum/design/mag_oldsmg/ap_mag
- name = "WT-550 Auto Gun Armour Piercing Magazine (4.6x30mm AP)"
- desc = "A 20 round armour piercing magazine for the out of date security WT-550 Auto Rifle"
+ name = "WT-550 Semi-Auto SMG Armour Piercing Magazine (4.6x30mm AP)"
+ desc = "A 20 round armour piercing magazine for the out of date security WT-550 Semi-Auto SMG."
id = "mag_oldsmg_ap"
materials = list(MAT_METAL = 6000, MAT_SILVER = 600)
build_path = /obj/item/ammo_box/magazine/wt550m9/wtap
departmental_flags = DEPARTMENTAL_FLAG_SECURITY
/datum/design/mag_oldsmg/ic_mag
- name = "WT-550 Auto Gun Incendiary Magazine (4.6x30mm IC)"
- desc = "A 20 round armour piercing magazine for the out of date security WT-550 Auto Rifle"
+ name = "WT-550 Semi-Auto SMG Incendiary Magazine (4.6x30mm IC)"
+ desc = "A 20 round armour piercing magazine for the out of date security WT-550 Semi-Auto SMG."
id = "mag_oldsmg_ic"
materials = list(MAT_METAL = 6000, MAT_SILVER = 600, MAT_GLASS = 1000)
build_path = /obj/item/ammo_box/magazine/wt550m9/wtic
diff --git a/code/modules/research/xenobiology/crossbreeding/_corecross.dm b/code/modules/research/xenobiology/crossbreeding/__corecross.dm
similarity index 100%
rename from code/modules/research/xenobiology/crossbreeding/_corecross.dm
rename to code/modules/research/xenobiology/crossbreeding/__corecross.dm
diff --git a/code/modules/research/xenobiology/crossbreeding/_clothing.dm b/code/modules/research/xenobiology/crossbreeding/_clothing.dm
new file mode 100644
index 0000000000..016fd95899
--- /dev/null
+++ b/code/modules/research/xenobiology/crossbreeding/_clothing.dm
@@ -0,0 +1,144 @@
+/*
+Slimecrossing Armor
+ Armor added by the slimecrossing system.
+ Collected here for clarity.
+*/
+
+//Rebreather mask - Chilling Blue
+/obj/item/clothing/mask/nobreath
+ name = "rebreather mask"
+ desc = "A transparent mask, resembling a conventional breath mask, but made of bluish slime. Seems to lack any air supply tube, though."
+ icon_state = "slime"
+ item_state = "slime"
+ body_parts_covered = NONE
+ w_class = WEIGHT_CLASS_SMALL
+ gas_transfer_coefficient = 0
+ permeability_coefficient = 0.5
+ flags_cover = MASKCOVERSMOUTH
+ resistance_flags = NONE
+
+/obj/item/clothing/mask/nobreath/equipped(mob/living/carbon/human/user, slot)
+ . = ..()
+ if(slot == SLOT_WEAR_MASK)
+ user.add_trait(TRAIT_NOBREATH, "breathmask_[REF(src)]")
+ user.failed_last_breath = FALSE
+ user.clear_alert("not_enough_oxy")
+ user.apply_status_effect(/datum/status_effect/rebreathing)
+
+/obj/item/clothing/mask/nobreath/dropped(mob/living/carbon/human/user)
+ ..()
+ user.remove_trait(TRAIT_NOBREATH, "breathmask_[REF(src)]")
+ user.remove_status_effect(/datum/status_effect/rebreathing)
+
+/obj/item/clothing/glasses/prism_glasses
+ name = "prism glasses"
+ desc = "The lenses seem to glow slightly, and reflect light into dazzling colors."
+ icon = 'icons/obj/slimecrossing.dmi'
+ icon_state = "prismglasses"
+ actions_types = list(/datum/action/item_action/change_prism_colour, /datum/action/item_action/place_light_prism)
+ var/glasses_color = "#FFFFFF"
+
+/obj/item/clothing/glasses/prism_glasses/item_action_slot_check(slot)
+ if(slot == SLOT_GLASSES)
+ return TRUE
+
+/obj/structure/light_prism
+ name = "light prism"
+ desc = "A shining crystal of semi-solid light. Looks fragile."
+ icon = 'icons/obj/slimecrossing.dmi'
+ icon_state = "lightprism"
+ density = FALSE
+ anchored = TRUE
+ max_integrity = 10
+
+/obj/structure/light_prism/Initialize(mapload, var/newcolor)
+ . = ..()
+ color = newcolor
+ light_color = newcolor
+ set_light(5)
+
+/obj/structure/light_prism/attack_hand(mob/user)
+ to_chat(user, "You dispel [src]")
+ qdel(src)
+
+/datum/action/item_action/change_prism_colour
+ name = "Adjust Prismatic Lens"
+ icon_icon = 'icons/obj/slimecrossing.dmi'
+ button_icon_state = "prismcolor"
+
+/datum/action/item_action/change_prism_colour/Trigger()
+ if(!IsAvailable())
+ return
+ var/obj/item/clothing/glasses/prism_glasses/glasses = target
+ var/new_color = input(owner, "Choose the lens color:", "Color change",glasses.glasses_color) as color|null
+ if(!new_color)
+ return
+ glasses.glasses_color = new_color
+
+/datum/action/item_action/place_light_prism
+ name = "Fabricate Light Prism"
+ icon_icon = 'icons/obj/slimecrossing.dmi'
+ button_icon_state = "lightprism"
+
+/datum/action/item_action/place_light_prism/Trigger()
+ if(!IsAvailable())
+ return
+ var/obj/item/clothing/glasses/prism_glasses/glasses = target
+ if(locate(/obj/structure/light_prism) in get_turf(owner))
+ to_chat(owner, "There isn't enough ambient energy to fabricate another light prism here.")
+ return
+ if(istype(glasses))
+ if(!glasses.glasses_color)
+ to_chat(owner, "The lens is oddly opaque...")
+ return
+ to_chat(owner, "You channel nearby light into a glowing, ethereal prism.")
+ new /obj/structure/light_prism(get_turf(owner), glasses.glasses_color)
+
+/obj/item/clothing/head/peaceflower
+ name = "heroine bud"
+ desc = "An extremely addictive flower, full of peace magic."
+ icon = 'icons/obj/slimecrossing.dmi'
+ icon_state = "peaceflower"
+ item_state = "peaceflower"
+ slot_flags = ITEM_SLOT_HEAD
+ body_parts_covered = NONE
+ dynamic_hair_suffix = ""
+ force = 0
+ throwforce = 0
+ w_class = WEIGHT_CLASS_TINY
+ throw_speed = 1
+ throw_range = 3
+
+/obj/item/clothing/head/peaceflower/equipped(mob/living/carbon/human/user, slot)
+ . = ..()
+ if(slot == SLOT_HEAD)
+ user.add_trait(TRAIT_PACIFISM, "peaceflower_[REF(src)]")
+
+/obj/item/clothing/head/peaceflower/dropped(mob/living/carbon/human/user)
+ ..()
+ user.remove_trait(TRAIT_PACIFISM, "peaceflower_[REF(src)]")
+
+/obj/item/clothing/head/peaceflower/attack_hand(mob/user)
+ if(iscarbon(user))
+ var/mob/living/carbon/C = user
+ if(src == C.head)
+ to_chat(user, "You feel at peace. Why would you want anything else?")
+ return
+ return ..()
+
+/obj/item/clothing/suit/armor/heavy/adamantine
+ name = "adamantine armor"
+ desc = "A full suit of adamantine plate armor. Impressively resistant to damage, but weighs about as much as you do."
+ icon_state = "adamsuit"
+ item_state = "adamsuit"
+ flags_inv = NONE
+ obj_flags = IMMUTABLE_SLOW
+ slowdown = 4
+ var/hit_reflect_chance = 10 // Citadel Change: because 40% chance of bouncing lasers back into peoples faces isn't good.
+ armor = list("melee" = 70, "bullet" = 70, "laser" = 40, "energy" = 40, "bomb" = 80, "bio" = 80, "rad" = 80, "fire" = 70, "acid" = 90) //Citadel Change to avoid immortal Xenobiologists.
+
+/obj/item/clothing/suit/armor/heavy/adamantine/IsReflect(def_zone)
+ if(def_zone in list(BODY_ZONE_CHEST, BODY_ZONE_R_ARM, BODY_ZONE_L_ARM, BODY_ZONE_R_LEG, BODY_ZONE_L_LEG) && prob(hit_reflect_chance))
+ return TRUE
+ else
+ return FALSE
diff --git a/code/modules/research/xenobiology/crossbreeding/_misc.dm b/code/modules/research/xenobiology/crossbreeding/_misc.dm
new file mode 100644
index 0000000000..0784946a37
--- /dev/null
+++ b/code/modules/research/xenobiology/crossbreeding/_misc.dm
@@ -0,0 +1,135 @@
+//Barrier cube - Chilling Grey
+/obj/item/barriercube
+ name = "barrier cube"
+ desc = "A compressed cube of slime. When squeezed, it grows to massive size!"
+ icon = 'icons/obj/slimecrossing.dmi'
+ icon_state = "barriercube"
+ w_class = WEIGHT_CLASS_TINY
+
+/obj/item/barriercube/attack_self(mob/user)
+ if(locate(/obj/structure/barricade/slime) in get_turf(loc))
+ to_chat(user, "You can't fit more than one barrier in the same space!")
+ return
+ to_chat(user, "You squeeze [src].")
+ var/obj/B = new /obj/structure/barricade/slime(get_turf(loc))
+ B.visible_message("[src] suddenly grows into a large, gelatinous barrier!")
+ qdel(src)
+
+//Slime barricade - Chilling Grey
+/obj/structure/barricade/slime
+ name = "gelatinous barrier"
+ desc = "A huge chunk of grey slime. Bullets might get stuck in it."
+ icon = 'icons/obj/slimecrossing.dmi'
+ icon_state = "slimebarrier"
+ proj_pass_rate = 40
+ max_integrity = 60
+
+//Melting Gel Wall - Chilling Metal
+/obj/effect/forcefield/slimewall
+ name = "solidified gel"
+ desc = "A mass of solidified slime gel - completely impenetrable, but it's melting away!"
+ icon = 'icons/obj/slimecrossing.dmi'
+ icon_state = "slimebarrier_thick"
+ CanAtmosPass = ATMOS_PASS_NO
+ opacity = TRUE
+ timeleft = 100
+
+//Rainbow barrier - Chilling Rainbow
+/obj/effect/forcefield/slimewall/rainbow
+ name = "rainbow barrier"
+ desc = "Despite others' urgings, you probably shouldn't taste this."
+ icon_state = "rainbowbarrier"
+
+//Ration pack - Chilling Silver
+/obj/item/reagent_containers/food/snacks/rationpack
+ name = "ration pack"
+ desc = "A square bar that sadly looks like chocolate, packaged in a nondescript grey wrapper. Has saved soldiers' lives before - usually by stopping bullets."
+ icon_state = "rationpack"
+ bitesize = 3
+ junkiness = 15
+ filling_color = "#964B00"
+ tastes = list("cardboard" = 3, "sadness" = 3)
+ foodtype = null //Don't ask what went into them. You're better off not knowing.
+ list_reagents = list("stabilizednutriment" = 10, "nutriment" = 2) //Won't make you fat. Will make you question your sanity.
+
+/obj/item/reagent_containers/food/snacks/rationpack/checkLiked(fraction, mob/M) //Nobody likes rationpacks. Nobody.
+ if(last_check_time + 50 < world.time)
+ if(ishuman(M))
+ var/mob/living/carbon/human/H = M
+ if(H.mind && !H.has_trait(TRAIT_AGEUSIA))
+ to_chat(H,"That didn't taste very good...") //No disgust, though. It's just not good tasting.
+ GET_COMPONENT_FROM(mood, /datum/component/mood, H)
+ if(mood)
+ mood.add_event(null,"gross_food", /datum/mood_event/gross_food)
+ last_check_time = world.time
+ return
+ ..()
+
+//Ice stasis block - Chilling Dark Blue
+/obj/structure/ice_stasis
+ name = "ice block"
+ desc = "A massive block of ice. You can see something vaguely humanoid inside."
+ icon = 'icons/obj/slimecrossing.dmi'
+ icon_state = "frozen"
+ density = TRUE
+ max_integrity = 100
+ armor = list("melee" = 30, "bullet" = 50, "laser" = -50, "energy" = -50, "bomb" = 0, "bio" = 100, "rad" = 100, "fire" = -80, "acid" = 30)
+
+/obj/structure/ice_stasis/Initialize()
+ . = ..()
+ playsound(src, 'sound/magic/ethereal_exit.ogg', 50, 1)
+
+/obj/structure/ice_stasis/Destroy()
+ for(var/atom/movable/M in contents)
+ M.forceMove(loc)
+ playsound(src, 'sound/effects/glassbr3.ogg', 50, 1)
+ return ..()
+
+//Gold capture device - Chilling Gold
+/obj/item/capturedevice
+ name = "gold capture device"
+ desc = "Bluespace technology packed into a roughly egg-shaped device, used to store nonhuman creatures. Can't catch them all, though - it only fits one."
+ w_class = WEIGHT_CLASS_SMALL
+ icon = 'icons/obj/slimecrossing.dmi'
+ icon_state = "capturedevice"
+
+/obj/item/capturedevice/attack(mob/living/M, mob/user)
+ if(length(contents))
+ to_chat(user, "The device already has something inside.")
+ return
+ if(!isanimal(M))
+ to_chat(user, "The capture device only works on simple creatures.")
+ return
+ if(M.mind)
+ to_chat(user, "You offer the device to [M].")
+ if(alert(M, "Would you like to enter [user]'s capture device?", "Gold Capture Device", "Yes", "No") == "Yes")
+ if(user.canUseTopic(src, BE_CLOSE) && user.canUseTopic(M, BE_CLOSE))
+ to_chat(user, "You store [M] in the capture device.")
+ to_chat(M, "The world warps around you, and you're suddenly in an endless void, with a window to the outside floating in front of you.")
+ store(M, user)
+ else
+ to_chat(user, "You were too far away from [M].")
+ to_chat(M, "You were too far away from [user].")
+ else
+ to_chat(user, "[M] refused to enter the device.")
+ return
+ else
+ if(istype(M, /mob/living/simple_animal/hostile) && !("neutral" in M.faction))
+ to_chat(user, "This creature is too aggressive to capture.")
+ return
+ to_chat(user, "You store [M] in the capture device.")
+ store(M)
+
+/obj/item/capturedevice/attack_self(mob/user)
+ if(contents.len)
+ to_chat(user, "You open the capture device!")
+ release()
+ else
+ to_chat(user, "The device is empty...")
+
+/obj/item/capturedevice/proc/store(var/mob/living/M)
+ M.forceMove(src)
+
+/obj/item/capturedevice/proc/release()
+ for(var/atom/movable/M in contents)
+ M.forceMove(get_turf(loc))
diff --git a/code/modules/research/xenobiology/crossbreeding/_mobs.dm b/code/modules/research/xenobiology/crossbreeding/_mobs.dm
new file mode 100644
index 0000000000..57d0a31149
--- /dev/null
+++ b/code/modules/research/xenobiology/crossbreeding/_mobs.dm
@@ -0,0 +1,13 @@
+//Slime corgi - Chilling Pink
+/mob/living/simple_animal/pet/dog/corgi/puppy/slime
+ name = "\improper slime corgi puppy"
+ real_name = "slime corgi puppy"
+ desc = "An unbearably cute pink slime corgi puppy."
+ icon_state = "slime_puppy"
+ icon_living = "slime_puppy"
+ icon_dead = "slime_puppy_dead"
+ nofur = TRUE
+ gold_core_spawnable = NO_SPAWN
+ speak_emote = list("blorbles", "bubbles", "borks")
+ emote_hear = list("bubbles!", "splorts.", "splops!")
+ emote_see = list("gets goop everywhere.", "flops.", "jiggles!")
\ No newline at end of file
diff --git a/code/modules/research/xenobiology/crossbreeding/_status_effects.dm b/code/modules/research/xenobiology/crossbreeding/_status_effects.dm
index f56aa11bae..aba54cfdf3 100644
--- a/code/modules/research/xenobiology/crossbreeding/_status_effects.dm
+++ b/code/modules/research/xenobiology/crossbreeding/_status_effects.dm
@@ -57,6 +57,184 @@
owner.visible_message("[owner]'s gel coating liquefies and dissolves away.",
"Your gel second-skin dissolves!")
+/datum/status_effect/slimerecall
+ id = "slime_recall"
+ duration = -1 //Will be removed by the extract.
+ alert_type = null
+ var/interrupted = FALSE
+ var/mob/target
+ var/icon/bluespace
+ var/datum/weakref/redirect_component
+
+/datum/status_effect/slimerecall/on_apply()
+ redirect_component = WEAKREF(owner.AddComponent(/datum/component/redirect, list(COMSIG_LIVING_RESIST = CALLBACK(src, .proc/resistField))))
+ to_chat(owner, "You feel a sudden tug from an unknown force, and feel a pull to bluespace!")
+ to_chat(owner, "Resist if you wish avoid the force!")
+ bluespace = icon('icons/effects/effects.dmi',"chronofield")
+ owner.add_overlay(bluespace)
+ return ..()
+
+/datum/status_effect/slimerecall/proc/resistField()
+ interrupted = TRUE
+ owner.remove_status_effect(src)
+/datum/status_effect/slimerecall/on_remove()
+ qdel(redirect_component.resolve())
+ redirect_component = null
+ owner.cut_overlay(bluespace)
+ if(interrupted || !ismob(target))
+ to_chat(owner, "The bluespace tug fades away, and you feel that the force has passed you by.")
+ return
+ owner.visible_message("[owner] disappears in a flurry of sparks!",
+ "The unknown force snatches briefly you from reality, and deposits you next to [target]!")
+ do_sparks(3, TRUE, owner)
+ owner.forceMove(target.loc)
+
+/obj/screen/alert/status_effect/freon/stasis
+ desc = "You're frozen inside of a protective ice cube! While inside, you can't do anything, but are immune to harm! Resist to get out."
+
+/datum/status_effect/frozenstasis
+ id = "slime_frozen"
+ status_type = STATUS_EFFECT_UNIQUE
+ duration = -1 //Will remove self when block breaks.
+ alert_type = /obj/screen/alert/status_effect/freon/stasis
+ var/obj/structure/ice_stasis/cube
+ var/datum/weakref/redirect_component
+
+/datum/status_effect/frozenstasis/on_apply()
+ redirect_component = WEAKREF(owner.AddComponent(/datum/component/redirect, list(COMSIG_LIVING_RESIST = CALLBACK(src, .proc/breakCube))))
+ cube = new /obj/structure/ice_stasis(get_turf(owner))
+ owner.forceMove(cube)
+ owner.status_flags |= GODMODE
+ return ..()
+
+/datum/status_effect/frozenstasis/tick()
+ if(!cube || owner.loc != cube)
+ owner.remove_status_effect(src)
+
+/datum/status_effect/frozenstasis/proc/breakCube()
+ owner.remove_status_effect(src)
+
+/datum/status_effect/frozenstasis/on_remove()
+ if(cube)
+ qdel(cube)
+ owner.status_flags &= ~GODMODE
+ qdel(redirect_component.resolve())
+ redirect_component = null
+
+/datum/status_effect/slime_clone
+ id = "slime_cloned"
+ status_type = STATUS_EFFECT_UNIQUE
+ duration = -1
+ alert_type = null
+ var/mob/living/clone
+ var/datum/mind/originalmind //For when the clone gibs.
+
+/datum/status_effect/slime_clone/on_apply()
+ var/typepath = owner.type
+ clone = new typepath(owner.loc)
+ var/mob/living/carbon/O = owner
+ var/mob/living/carbon/C = clone
+ if(istype(C) && istype(O))
+ C.real_name = O.real_name
+ O.dna.transfer_identity(C)
+ C.updateappearance(mutcolor_update=1)
+ if(owner.mind)
+ originalmind = owner.mind
+ owner.mind.transfer_to(clone)
+ clone.apply_status_effect(/datum/status_effect/slime_clone_decay)
+ return ..()
+
+/datum/status_effect/slime_clone/tick()
+ if(!istype(clone) || clone.stat != CONSCIOUS)
+ owner.remove_status_effect(src)
+
+/datum/status_effect/slime_clone/on_remove()
+ if(clone && clone.mind && owner)
+ clone.mind.transfer_to(owner)
+ else
+ if(owner && originalmind)
+ originalmind.transfer_to(owner)
+ if(originalmind.key)
+ owner.ckey = originalmind.key
+ if(clone)
+ clone.unequip_everything()
+ qdel(clone)
+
+/obj/screen/alert/status_effect/clone_decay
+ name = "Clone Decay"
+ desc = "You are simply a construct, and cannot maintain this form forever. You will be returned to your original body if you should fall."
+ icon_state = "slime_clonedecay"
+
+/datum/status_effect/slime_clone_decay
+ id = "slime_clonedecay"
+ status_type = STATUS_EFFECT_UNIQUE
+ duration = -1
+ alert_type = /obj/screen/alert/status_effect/clone_decay
+
+/datum/status_effect/slime_clone_decay/tick()
+ owner.adjustToxLoss(1, 0)
+ owner.adjustOxyLoss(1, 0)
+ owner.adjustBruteLoss(1, 0)
+ owner.adjustFireLoss(1, 0)
+ owner.color = "#007BA7"
+
+/obj/screen/alert/status_effect/bloodchill
+ name = "Bloodchilled"
+ desc = "You feel a shiver down your spine after getting hit with a glob of cold blood. You'll move slower and get frostbite for a while!"
+ icon_state = "bloodchill"
+
+/datum/status_effect/bloodchill
+ id = "bloodchill"
+ duration = 100
+ alert_type = /obj/screen/alert/status_effect/bloodchill
+
+/datum/status_effect/bloodchill/on_apply()
+ owner.add_movespeed_modifier("bloodchilled", TRUE, 100, NONE, override = TRUE, multiplicative_slowdown = 3)
+ return ..()
+
+/datum/status_effect/bloodchill/tick()
+ if(prob(50))
+ owner.adjustFireLoss(2)
+
+/datum/status_effect/bloodchill/on_remove()
+ owner.remove_movespeed_modifier("bloodchilled")
+
+/obj/screen/alert/status_effect/bloodchill
+ name = "Bloodchilled"
+ desc = "You feel a shiver down your spine after getting hit with a glob of cold blood. You'll move slower and get frostbite for a while!"
+ icon_state = "bloodchill"
+
+/datum/status_effect/bonechill
+ id = "bonechill"
+ duration = 80
+ alert_type = /obj/screen/alert/status_effect/bonechill
+
+/datum/status_effect/bonechill/on_apply()
+ owner.add_movespeed_modifier("bonechilled", TRUE, 100, NONE, override = TRUE, multiplicative_slowdown = 3)
+ return ..()
+
+/datum/status_effect/bonechill/tick()
+ if(prob(50))
+ owner.adjustFireLoss(1)
+ owner.Jitter(3)
+ owner.adjust_bodytemperature(-10)
+
+/datum/status_effect/bonechill/on_remove()
+ owner.remove_movespeed_modifier("bonechilled")
+
+/obj/screen/alert/status_effect/bonechill
+ name = "Bonechilled"
+ desc = "You feel a shiver down your spine after hearing the haunting noise of bone rattling. You'll move slower and get frostbite for a while!"
+ icon_state = "bloodchill"
+
+/datum/status_effect/rebreathing
+ id = "rebreathing"
+ duration = -1
+ alert_type = null
+
+datum/status_effect/rebreathing/tick()
+ owner.adjustOxyLoss(-6, 0) //Just a bit more than normal breathing.
+
///////////////////////////////////////////////////////
//////////////////CONSUMING EXTRACTS///////////////////
///////////////////////////////////////////////////////
diff --git a/code/modules/research/xenobiology/crossbreeding/_weapons.dm b/code/modules/research/xenobiology/crossbreeding/_weapons.dm
new file mode 100644
index 0000000000..1138f65105
--- /dev/null
+++ b/code/modules/research/xenobiology/crossbreeding/_weapons.dm
@@ -0,0 +1,45 @@
+//Bloodchiller - Chilling Green
+/obj/item/gun/magic/bloodchill
+ name = "blood chiller"
+ desc = "A horrifying weapon made of your own bone and blood vessels. It shoots slowing globules of your own blood. Ech."
+ icon = 'icons/obj/slimecrossing.dmi'
+ icon_state = "bloodgun"
+ item_state = "bloodgun"
+ lefthand_file = 'icons/mob/inhands/weapons/guns_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/weapons/guns_righthand.dmi'
+ item_flags = ABSTRACT | DROPDEL | NODROP
+ w_class = WEIGHT_CLASS_HUGE
+ force = 5
+ max_charges = 1 //Recharging costs blood.
+ recharge_rate = 1
+ ammo_type = /obj/item/ammo_casing/magic/bloodchill
+ fire_sound = 'sound/effects/attackblob.ogg'
+
+/obj/item/gun/magic/bloodchill/process()
+ charge_tick++
+ if(charge_tick < recharge_rate || charges >= max_charges)
+ return 0
+ charge_tick = 0
+ var/mob/living/M = loc
+ if(istype(M) && M.blood_volume >= 20)
+ charges++
+ M.blood_volume -= 20
+ if(charges == 1)
+ recharge_newshot()
+ return 1
+
+/obj/item/ammo_casing/magic/bloodchill
+ projectile_type = /obj/item/projectile/magic/bloodchill
+
+/obj/item/projectile/magic/bloodchill
+ name = "blood ball"
+ icon_state = "pulse0_bl"
+ damage = 0
+ damage_type = OXY
+ nodamage = 1
+ hitsound = 'sound/effects/splat.ogg'
+
+/obj/item/projectile/magic/bloodchill/on_hit(mob/living/target)
+ . = ..()
+ if(isliving(target))
+ target.apply_status_effect(/datum/status_effect/bloodchill)
\ No newline at end of file
diff --git a/code/modules/research/xenobiology/crossbreeding/chilling.dm b/code/modules/research/xenobiology/crossbreeding/chilling.dm
new file mode 100644
index 0000000000..25dbaa461f
--- /dev/null
+++ b/code/modules/research/xenobiology/crossbreeding/chilling.dm
@@ -0,0 +1,312 @@
+/*
+Chilling extracts:
+ Have a unique, primarily defensive effect when
+ filled with 10u plasma and activated in-hand.
+*/
+/obj/item/slimecross/chilling
+ name = "chilling extract"
+ desc = "It's cold to the touch, as if frozen solid."
+ effect = "chilling"
+ container_type = INJECTABLE | DRAWABLE
+ icon_state = "chilling"
+
+/obj/item/slimecross/chilling/Initialize()
+ . = ..()
+ create_reagents(10)
+
+/obj/item/slimecross/chilling/attack_self(mob/user)
+ if(!reagents.has_reagent("plasma",10))
+ to_chat(user, "This extract needs to be full of plasma to activate!")
+ return
+ reagents.remove_reagent("plasma",10)
+ to_chat(user, "You squeeze the extract, and it absorbs the plasma!")
+ playsound(src, 'sound/effects/bubbles.ogg', 50, 1)
+ playsound(src, 'sound/effects/glassbr1.ogg', 50, 1)
+ do_effect(user)
+
+/obj/item/slimecross/chilling/proc/do_effect(mob/user) //If, for whatever reason, you don't want to delete the extract, don't do ..()
+ qdel(src)
+ return
+
+/obj/item/slimecross/chilling/grey
+ colour = "grey"
+
+/obj/item/slimecross/chilling/grey/do_effect(mob/user)
+ user.visible_message("[src] produces a few small, grey cubes")
+ for(var/i in 1 to 3)
+ new /obj/item/barriercube(get_turf(user))
+ ..()
+
+/obj/item/slimecross/chilling/orange
+ colour = "orange"
+
+/obj/item/slimecross/chilling/orange/do_effect(mob/user)
+ user.visible_message("[src] shatters, and lets out a jet of heat!")
+ for(var/turf/T in orange(get_turf(user),2))
+ if(get_dist(get_turf(user), T) > 1)
+ new /obj/effect/hotspot(T)
+ ..()
+
+/obj/item/slimecross/chilling/purple
+ colour = "purple"
+
+/obj/item/slimecross/chilling/purple/do_effect(mob/user)
+ var/area/A = get_area(get_turf(user))
+ if(A.outdoors)
+ to_chat(user, "[src] can't affect such a large area.")
+ return
+ user.visible_message("[src] shatters, and a healing aura fills the room briefly.")
+ for(var/mob/living/carbon/C in A)
+ C.reagents.add_reagent("regen_jelly",10)
+ ..()
+
+/obj/item/slimecross/chilling/blue
+ colour = "blue"
+
+/obj/item/slimecross/chilling/blue/do_effect(mob/user)
+ user.visible_message("[src] cracks, and spills out a liquid goo, which reforms into a mask!")
+ new /obj/item/clothing/mask/nobreath(get_turf(user))
+ ..()
+
+/obj/item/slimecross/chilling/metal
+ colour = "metal"
+
+/obj/item/slimecross/chilling/metal/do_effect(mob/user)
+ user.visible_message("[src] melts like quicksilver, and surrounds [user] in a wall!")
+ for(var/turf/T in orange(get_turf(user),1))
+ if(get_dist(get_turf(user), T) > 0)
+ new /obj/effect/forcefield/slimewall(T)
+ ..()
+
+/obj/item/slimecross/chilling/yellow
+ colour = "yellow"
+
+/obj/item/slimecross/chilling/yellow/do_effect(mob/user)
+ var/area/A = get_area(get_turf(user))
+ user.visible_message("[src] shatters, and a the air suddenly feels charged for a moment.")
+ for(var/obj/machinery/power/apc/C in A)
+ if(C.cell)
+ C.cell.charge = min(C.cell.charge + C.cell.maxcharge/2, C.cell.maxcharge)
+ ..()
+
+/obj/item/slimecross/chilling/darkpurple
+ colour = "dark purple"
+
+/obj/item/slimecross/chilling/darkpurple/do_effect(mob/user)
+ var/area/A = get_area(get_turf(user))
+ if(A.outdoors)
+ to_chat(user, "[src] can't affect such a large area.")
+ return
+ var/filtered = FALSE
+ for(var/turf/open/T in A)
+ var/datum/gas_mixture/G = T.air
+ if(istype(G))
+ G.assert_gas(/datum/gas/plasma)
+ G.gases[/datum/gas/plasma][MOLES] = 0
+ filtered = TRUE
+ G.garbage_collect()
+ T.air_update_turf()
+ if(filtered)
+ user.visible_message("Cracks spread throughout [src], and some air is sucked in!")
+ else
+ user.visible_message("[src] cracks, but nothing happens.")
+ ..()
+
+/obj/item/slimecross/chilling/darkblue
+ colour = "dark blue"
+
+/obj/item/slimecross/chilling/darkblue/do_effect(mob/user)
+ if(isliving(user))
+ user.visible_message("[src] freezes over [user]'s entire body!")
+ var/mob/living/M = user
+ M.apply_status_effect(/datum/status_effect/frozenstasis)
+ ..()
+
+/obj/item/slimecross/chilling/silver
+ colour = "silver"
+
+/obj/item/slimecross/chilling/silver/do_effect(mob/user)
+ user.visible_message("[src] crumbles into icy powder, leaving behind several emergency food supplies!")
+ var/amount = rand(5, 10)
+ for(var/i in 1 to amount)
+ new /obj/item/reagent_containers/food/snacks/rationpack(get_turf(user))
+ ..()
+
+/obj/item/slimecross/chilling/bluespace
+ colour = "bluespace"
+ var/list/allies = list()
+ var/active = FALSE
+
+/obj/item/slimecross/chilling/bluespace/afterattack(atom/target, mob/user, proximity)
+ if(!proximity || !isliving(target) || active)
+ return
+ if(target in allies)
+ allies -= target
+ to_chat(user, "You unlink [src] with [target].")
+ else
+ allies |= target
+ to_chat(user, "You link [src] with [target].")
+ return
+
+/obj/item/slimecross/chilling/bluespace/do_effect(mob/user)
+ if(allies.len <= 0)
+ to_chat(user, "[src] is not linked to anyone!")
+ return
+ to_chat(user, "You feel [src] pulse as it begins charging bluespace energies...")
+ active = TRUE
+ for(var/mob/living/M in allies)
+ var/datum/status_effect/slimerecall/S = M.apply_status_effect(/datum/status_effect/slimerecall)
+ S.target = user
+ if(do_after(user, 100, target=src))
+ to_chat(user, "[src] shatters as it tears a hole in reality, snatching the linked individuals from the void!")
+ for(var/mob/living/M in allies)
+ var/datum/status_effect/slimerecall/S = M.has_status_effect(/datum/status_effect/slimerecall)
+ M.remove_status_effect(S)
+ else
+ to_chat(user, "[src] falls dark, dissolving into nothing as the energies fade away.")
+ for(var/mob/living/M in allies)
+ var/datum/status_effect/slimerecall/S = M.has_status_effect(/datum/status_effect/slimerecall)
+ if(istype(S))
+ S.interrupted = TRUE
+ M.remove_status_effect(S)
+ ..()
+
+/obj/item/slimecross/chilling/sepia
+ colour = "sepia"
+ var/list/allies = list()
+
+/obj/item/slimecross/chilling/sepia/afterattack(atom/target, mob/user, proximity)
+ if(!proximity || !isliving(target))
+ return
+ if(target in allies)
+ allies -= target
+ to_chat(user, "You unlink [src] with [target].")
+ else
+ allies |= target
+ to_chat(user, "You link [src] with [target].")
+ return
+
+/obj/item/slimecross/chilling/sepia/do_effect(mob/user)
+ user.visible_message("[src] shatters, freezing time itself!")
+ new /obj/effect/timestop(get_turf(user), 2, 300, allies)
+ ..()
+
+/obj/item/slimecross/chilling/cerulean
+ colour = "cerulean"
+
+/obj/item/slimecross/chilling/cerulean/do_effect(mob/user)
+ if(isliving(user))
+ user.visible_message("[src] creaks and shifts into a clone of [user]!")
+ var/mob/living/M = user
+ M.apply_status_effect(/datum/status_effect/slime_clone)
+ ..()
+
+/obj/item/slimecross/chilling/pyrite
+ colour = "pyrite"
+
+/obj/item/slimecross/chilling/pyrite/do_effect(mob/user)
+ user.visible_message("[src] crystallizes into a pair of spectacles!")
+ new /obj/item/clothing/glasses/prism_glasses(get_turf(user))
+ ..()
+
+/obj/item/slimecross/chilling/red
+ colour = "red"
+
+/obj/item/slimecross/chilling/red/do_effect(mob/user)
+ var/slimesfound = FALSE
+ for(var/mob/living/simple_animal/slime/S in view(get_turf(user), 7))
+ slimesfound = TRUE
+ S.docile = TRUE
+ if(slimesfound)
+ user.visible_message("[src] lets out a peaceful ring as it shatters, and nearby slimes seem calm.")
+ else
+ user.visible_message("[src] lets out a peaceful ring as it shatters, but nothing happens...")
+ ..()
+
+/obj/item/slimecross/chilling/green
+ colour = "green"
+
+/obj/item/slimecross/chilling/green/do_effect(mob/user)
+ var/which_hand = "l_hand"
+ if(!(user.active_hand_index % 2))
+ which_hand = "r_hand"
+ var/mob/living/L = user
+ if(!istype(user))
+ return
+ var/obj/item/held = L.get_active_held_item() //This should be itself, but just in case...
+ L.dropItemToGround(held)
+ var/obj/item/gun/magic/bloodchill/gun = new(user)
+ if(!L.put_in_hands(gun))
+ qdel(gun)
+ user.visible_message("[src] flash-freezes [user]'s arm, cracking the flesh horribly!")
+ else
+ user.visible_message("[src] chills and snaps off the front of the bone on [user]'s arm, leaving behind a strange, gun-like structure!")
+ user.emote("scream")
+ L.apply_damage(30,BURN,which_hand)
+ ..()
+
+/obj/item/slimecross/chilling/pink
+ colour = "pink"
+
+/obj/item/slimecross/chilling/pink/do_effect(mob/user)
+ user.visible_message("[src] cracks like an egg, and an adorable puppy comes tumbling out!")
+ new /mob/living/simple_animal/pet/dog/corgi/puppy/slime(get_turf(user))
+ ..()
+
+/obj/item/slimecross/chilling/gold
+ colour = "gold"
+
+/obj/item/slimecross/chilling/gold/do_effect(mob/user)
+ user.visible_message("[src] lets off golden light as it melts and reforms into an egg-like device!")
+ new /obj/item/capturedevice(get_turf(user))
+ ..()
+
+/obj/item/slimecross/chilling/oil
+ colour = "oil"
+
+/obj/item/slimecross/chilling/oil/do_effect(mob/user)
+ user.visible_message("[src] begins to shake with muted intensity!")
+ addtimer(CALLBACK(src, .proc/boom), 50)
+
+/obj/item/slimecross/chilling/oil/proc/boom()
+ explosion(get_turf(src), -1, -1, 3, 10) //Large radius, but mostly light damage.
+ qdel(src)
+
+/obj/item/slimecross/chilling/black
+ colour = "black"
+
+/obj/item/slimecross/chilling/black/do_effect(mob/user)
+ if(ishuman(user))
+ user.visible_message("[src] crystallizes along [user]'s skin, turning into metallic scales!")
+ var/mob/living/carbon/human/H = user
+ H.set_species(/datum/species/golem/random)
+ ..()
+
+/obj/item/slimecross/chilling/lightpink
+ colour = "light pink"
+
+/obj/item/slimecross/chilling/lightpink/do_effect(mob/user)
+ user.visible_message("[src] blooms into a beautiful flower!")
+ new /obj/item/clothing/head/peaceflower(get_turf(user))
+ ..()
+
+/obj/item/slimecross/chilling/adamantine
+ colour = "adamantine"
+
+/obj/item/slimecross/chilling/adamantine/do_effect(mob/user)
+ user.visible_message("[src] creaks and breaks as it shifts into a heavy set of armor!")
+ new /obj/item/clothing/suit/armor/heavy/adamantine(get_turf(user))
+ ..()
+
+/obj/item/slimecross/chilling/rainbow
+ colour = "rainbow"
+
+/obj/item/slimecross/chilling/rainbow/do_effect(mob/user)
+ var/area/area = get_area(user)
+ if(area.outdoors)
+ to_chat(user, "[src] can't affect such a large area.")
+ return
+ user.visible_message("[src] reflects an array of dazzling colors and light, energy rushing to nearby doors!")
+ for(var/obj/machinery/door/airlock/door in area)
+ new /obj/effect/forcefield/slimewall/rainbow(door.loc)
+ return ..()
diff --git a/code/modules/research/xenobiology/xenobiology.dm b/code/modules/research/xenobiology/xenobiology.dm
index 5da091152f..ca12accbed 100644
--- a/code/modules/research/xenobiology/xenobiology.dm
+++ b/code/modules/research/xenobiology/xenobiology.dm
@@ -840,7 +840,7 @@
return
if(isitem(C))
var/obj/item/I = C
- if(I.slowdown <= 0)
+ if(I.slowdown <= 0 || I.obj_flags & IMMUTABLE_SLOW)
to_chat(user, "The [C] can't be made any faster!")
return ..()
I.slowdown = 0
diff --git a/code/modules/surgery/advanced/revival.dm b/code/modules/surgery/advanced/revival.dm
index 085253e4c9..8a791c850b 100644
--- a/code/modules/surgery/advanced/revival.dm
+++ b/code/modules/surgery/advanced/revival.dm
@@ -27,7 +27,7 @@
/datum/surgery_step/revive
name = "repair body"
- implements = list(/obj/item/twohanded/shockpaddles = 100, /obj/item/melee/baton = 75, /obj/item/gun/energy = 60)
+ implements = list(/obj/item/twohanded/shockpaddles = 100, /obj/item/abductor/gizmo = 100, /obj/item/melee/baton = 75, /obj/item/organ/cyberimp/arm/baton = 75, /obj/item/organ/cyberimp/arm/gun/taser = 60, /obj/item/gun/energy/e_gun/advtaser = 60, /obj/item/gun/energy/taser = 60)
time = 120
/datum/surgery_step/revive/tool_check(mob/user, obj/item/tool)
diff --git a/html/changelogs/AutoChangeLog-pr-8056.yml b/html/changelogs/AutoChangeLog-pr-8056.yml
new file mode 100644
index 0000000000..0953743ae4
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8056.yml
@@ -0,0 +1,4 @@
+author: "deathride58"
+delete-after: True
+changes:
+ - balance: "The TEG will now only produce a meaningful amount of power if the hot pipe contains gas that's actively combusting"
diff --git a/html/changelogs/AutoChangeLog-pr-8058.yml b/html/changelogs/AutoChangeLog-pr-8058.yml
new file mode 100644
index 0000000000..a484cc8ce1
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8058.yml
@@ -0,0 +1,4 @@
+author: "deathride58"
+delete-after: True
+changes:
+ - rscadd: "Jogging is no longer treated exactly the same as sprinting for water slips. When you're jogging, you will only slip on water if you have more than 20% staminaloss."
diff --git a/html/changelogs/AutoChangeLog-pr-8070.yml b/html/changelogs/AutoChangeLog-pr-8070.yml
new file mode 100644
index 0000000000..a2ebab9068
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8070.yml
@@ -0,0 +1,5 @@
+author: "deathride58"
+delete-after: True
+changes:
+ - rscadd: "Bloodcult conversions are now consensual. Convertees are given a ten second timer to accept or wait out. This should drastically improve the quality of those that get converted into bloodcult."
+ - rscadd: "All sacrifices now count as a third of a cultist for the end-game narsie summon."
diff --git a/html/changelogs/AutoChangeLog-pr-8080.yml b/html/changelogs/AutoChangeLog-pr-8080.yml
new file mode 100644
index 0000000000..9abd9e6f50
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8080.yml
@@ -0,0 +1,4 @@
+author: "Ghommie"
+delete-after: True
+changes:
+ - balance: "Halved borg energy guns self-recharge delay and increased their cell capacity by 3/4"
diff --git a/html/changelogs/AutoChangeLog-pr-8084.yml b/html/changelogs/AutoChangeLog-pr-8084.yml
new file mode 100644
index 0000000000..fbec9cfe1f
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8084.yml
@@ -0,0 +1,4 @@
+author: "Poojawa"
+delete-after: True
+changes:
+ - tweak: "Clone pods no longer announce the name of the clone"
diff --git a/html/changelogs/AutoChangeLog-pr-8090.yml b/html/changelogs/AutoChangeLog-pr-8090.yml
new file mode 100644
index 0000000000..b314fde12b
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8090.yml
@@ -0,0 +1,5 @@
+author: "deathride58 (Original PR by actioninja)"
+delete-after: True
+changes:
+ - rscadd: "Disarm pushing (combat mode right click in disarm intent) will now actually push mobs away. Knockdowns from disarm pushing are no longer rng based on the target's staminaloss. Knockdowns from disarm pushing now only happen when you push someone into another mob, a table, or a wall. Pushes will now also temporarily stop targets from using firearms, and will disarm the firearm if performed a second time. Pushes still deal staminaloss to standing targets, and won't deal a single ounce of staminaloss to resting targets."
+ - rscdel: "You can no longer displace mobs that are in harm intent by simply walking into them. Mobs that aren't in help intent have to be disarm pushed to actually be moved."
diff --git a/html/changelogs/AutoChangeLog-pr-8091.yml b/html/changelogs/AutoChangeLog-pr-8091.yml
new file mode 100644
index 0000000000..e98b7df89c
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8091.yml
@@ -0,0 +1,5 @@
+author: "deathride58"
+delete-after: True
+changes:
+ - bugfix: "Transit turfs on the centcom z-level now function properly again at keeping mobs within the areas defined by their boundaries."
+ - bugfix: "The title screen is also positioned correctly again."
diff --git a/html/changelogs/AutoChangeLog-pr-8098.yml b/html/changelogs/AutoChangeLog-pr-8098.yml
new file mode 100644
index 0000000000..956b83d223
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8098.yml
@@ -0,0 +1,4 @@
+author: "Coolgat3"
+delete-after: True
+changes:
+ - bugfix: "Made the sec and warden berret offer as much protection like the helmet"
diff --git a/html/changelogs/AutoChangeLog-pr-8104.yml b/html/changelogs/AutoChangeLog-pr-8104.yml
new file mode 100644
index 0000000000..61bf66a0c2
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8104.yml
@@ -0,0 +1,5 @@
+author: "Ghommie"
+delete-after: True
+changes:
+ - bugfix: "Fixes chemical patches always checking the suit slot even if the targetted limb was the head."
+ - bugfix: "Skeleton, nightmare and golem races are once again available to get chemical patches applied onto."
diff --git a/html/changelogs/AutoChangeLog-pr-8108.yml b/html/changelogs/AutoChangeLog-pr-8108.yml
new file mode 100644
index 0000000000..fea83213be
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8108.yml
@@ -0,0 +1,4 @@
+author: "Ghommie"
+delete-after: True
+changes:
+ - rscadd: "Adds two cartons of space milk to the space skellie pirates cutter's fridge."
diff --git a/html/changelogs/AutoChangeLog-pr-8114.yml b/html/changelogs/AutoChangeLog-pr-8114.yml
new file mode 100644
index 0000000000..96e6914e6b
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8114.yml
@@ -0,0 +1,4 @@
+author: "izzyinbox"
+delete-after: True
+changes:
+ - tweak: "lowered the player age for command jobs to 1/3 of their previous setting"
diff --git a/html/changelogs/AutoChangeLog-pr-8119.yml b/html/changelogs/AutoChangeLog-pr-8119.yml
new file mode 100644
index 0000000000..6e282e2a8d
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8119.yml
@@ -0,0 +1,5 @@
+author: "deathride58"
+delete-after: True
+changes:
+ - bugfix: "Sparks and igniters will now actually heat areas rather than cooling them, as was intended."
+ - tweak: "To alleviate some potential complaints, RPDs now have a cooldown before they can create sparks, and both RPDs and emitters produce less sparks."
diff --git a/html/changelogs/AutoChangeLog-pr-8121.yml b/html/changelogs/AutoChangeLog-pr-8121.yml
new file mode 100644
index 0000000000..27ce1ee0a1
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-8121.yml
@@ -0,0 +1,5 @@
+author: "deathride58"
+delete-after: True
+changes:
+ - tweak: "Conversion runes will now mute the victim temporarily while they're deciding whether to convert or be sacrificed."
+ - bugfix: "Conversion runes no longer require a third cultist to sacrifice if the victim refuses conversion"
diff --git a/icons/mob/eyes.dmi b/icons/mob/eyes.dmi
index 4bbe27f09d..aad4718cbd 100644
Binary files a/icons/mob/eyes.dmi and b/icons/mob/eyes.dmi differ
diff --git a/icons/mob/head.dmi b/icons/mob/head.dmi
index 03d6190507..2f39dd5940 100644
Binary files a/icons/mob/head.dmi and b/icons/mob/head.dmi differ
diff --git a/icons/mob/inhands/weapons/guns_lefthand.dmi b/icons/mob/inhands/weapons/guns_lefthand.dmi
index dae3861233..f6ac6ca499 100644
Binary files a/icons/mob/inhands/weapons/guns_lefthand.dmi and b/icons/mob/inhands/weapons/guns_lefthand.dmi differ
diff --git a/icons/mob/inhands/weapons/guns_righthand.dmi b/icons/mob/inhands/weapons/guns_righthand.dmi
index f3d5c42570..504121feba 100644
Binary files a/icons/mob/inhands/weapons/guns_righthand.dmi and b/icons/mob/inhands/weapons/guns_righthand.dmi differ
diff --git a/icons/mob/mask.dmi b/icons/mob/mask.dmi
index 18b323c997..788bfc0447 100644
Binary files a/icons/mob/mask.dmi and b/icons/mob/mask.dmi differ
diff --git a/icons/mob/pets.dmi b/icons/mob/pets.dmi
index d0983a8fab..45b0ab1f04 100644
Binary files a/icons/mob/pets.dmi and b/icons/mob/pets.dmi differ
diff --git a/icons/mob/suit.dmi b/icons/mob/suit.dmi
index 904084adb5..b518157bb5 100644
Binary files a/icons/mob/suit.dmi and b/icons/mob/suit.dmi differ
diff --git a/icons/obj/clothing/masks.dmi b/icons/obj/clothing/masks.dmi
index a474b5f285..a0153b1596 100644
Binary files a/icons/obj/clothing/masks.dmi and b/icons/obj/clothing/masks.dmi differ
diff --git a/icons/obj/clothing/suits.dmi b/icons/obj/clothing/suits.dmi
index 51a5a4e358..8e0359e6b3 100644
Binary files a/icons/obj/clothing/suits.dmi and b/icons/obj/clothing/suits.dmi differ
diff --git a/icons/obj/food/food.dmi b/icons/obj/food/food.dmi
index 7f4e368c6e..9861a2e618 100644
Binary files a/icons/obj/food/food.dmi and b/icons/obj/food/food.dmi differ
diff --git a/icons/obj/slimecrossing.dmi b/icons/obj/slimecrossing.dmi
index 56ccfc21f7..6d74116a18 100644
Binary files a/icons/obj/slimecrossing.dmi and b/icons/obj/slimecrossing.dmi differ
diff --git a/modular_citadel/code/game/objects/items/storage/firstaid.dm b/modular_citadel/code/game/objects/items/storage/firstaid.dm
index 82d7df4a00..6ddf3963dd 100755
--- a/modular_citadel/code/game/objects/items/storage/firstaid.dm
+++ b/modular_citadel/code/game/objects/items/storage/firstaid.dm
@@ -23,7 +23,14 @@
/obj/item/storage/firstaid/o2
icon_state = "oxy"
-
+
+/obj/item/storage/firstaid/radbgone
+ icon_state = "rad"
+
+/obj/item/storage/firstaid/radbgone/Initialize(mapload)
+ . = ..()
+ icon_state = pick("[initial(icon_state)]","[initial(icon_state)]2","[initial(icon_state)]3","[initial(icon_state)]4")
+
/obj/item/storage/firstaid/tactical
icon_state = "tactical"
diff --git a/modular_citadel/code/modules/jobs/job_types/captain.dm b/modular_citadel/code/modules/jobs/job_types/captain.dm
index 7d8d1ac5ca..674cd9d09e 100644
--- a/modular_citadel/code/modules/jobs/job_types/captain.dm
+++ b/modular_citadel/code/modules/jobs/job_types/captain.dm
@@ -1,9 +1,9 @@
/datum/job/captain
- minimal_player_age = 60
+ minimal_player_age = 20
exp_type = EXP_TYPE_COMMAND
/datum/job/hop
- minimal_player_age = 60
+ minimal_player_age = 20
head_announce = list("Service")
exp_type_department = EXP_TYPE_SERVICE
diff --git a/modular_citadel/code/modules/jobs/job_types/engineering.dm b/modular_citadel/code/modules/jobs/job_types/engineering.dm
index f199bbefea..4d6aa4119d 100644
--- a/modular_citadel/code/modules/jobs/job_types/engineering.dm
+++ b/modular_citadel/code/modules/jobs/job_types/engineering.dm
@@ -1,5 +1,5 @@
/datum/job/chief_engineer
- minimal_player_age = 30
+ minimal_player_age = 10
/datum/job/engineer
access = list(ACCESS_ENGINE, ACCESS_ENGINE_EQUIP, ACCESS_TECH_STORAGE, ACCESS_MAINT_TUNNELS,
diff --git a/modular_citadel/code/modules/jobs/job_types/medical.dm b/modular_citadel/code/modules/jobs/job_types/medical.dm
index 31c8b7d3c4..15841ad9d5 100644
--- a/modular_citadel/code/modules/jobs/job_types/medical.dm
+++ b/modular_citadel/code/modules/jobs/job_types/medical.dm
@@ -1,5 +1,5 @@
/datum/job/cmo
- minimal_player_age = 30
+ minimal_player_age = 10
/datum/outfit/job/doctor
backpack_contents = list(/obj/item/storage/hypospraykit/regular)
diff --git a/modular_citadel/code/modules/jobs/job_types/science.dm b/modular_citadel/code/modules/jobs/job_types/science.dm
index 4542e7d099..94272d24a6 100644
--- a/modular_citadel/code/modules/jobs/job_types/science.dm
+++ b/modular_citadel/code/modules/jobs/job_types/science.dm
@@ -1,2 +1,2 @@
/datum/job/rd
- minimal_player_age = 30
\ No newline at end of file
+ minimal_player_age = 10
diff --git a/modular_citadel/code/modules/jobs/job_types/security.dm b/modular_citadel/code/modules/jobs/job_types/security.dm
index 9e59d98d00..de00f2d948 100644
--- a/modular_citadel/code/modules/jobs/job_types/security.dm
+++ b/modular_citadel/code/modules/jobs/job_types/security.dm
@@ -1,5 +1,5 @@
/datum/job/hos
- minimal_player_age = 30
+ minimal_player_age = 10
/datum/outfit/job/warden
- suit_store = /obj/item/gun/energy/pumpaction/defender
\ No newline at end of file
+ suit_store = /obj/item/gun/energy/pumpaction/defender
diff --git a/modular_citadel/code/modules/mob/cit_emotes.dm b/modular_citadel/code/modules/mob/cit_emotes.dm
index 6d6bc77b0b..a314baa852 100644
--- a/modular_citadel/code/modules/mob/cit_emotes.dm
+++ b/modular_citadel/code/modules/mob/cit_emotes.dm
@@ -15,9 +15,12 @@
/datum/emote/living/insult/run_emote(mob/living/user, params)
var/insult_message = ""
+ var/miming = user.mind ? user.mind.miming : 0
if(!user.is_muzzled())
insult_message += pick_list_replacements(INSULTS_FILE, "insult_gen")
message = insult_message
+ else if(miming)
+ message = "creatively gesticulates."
else
message = "muffles something."
. = ..()
@@ -224,4 +227,4 @@
return
user.nextsoundemote = world.time + 7
playsound(user, 'modular_citadel/sound/voice/merp.ogg', 50, 1, -1)
- . = ..()
\ No newline at end of file
+ . = ..()
diff --git a/modular_citadel/code/modules/mob/living/carbon/human/species.dm b/modular_citadel/code/modules/mob/living/carbon/human/species.dm
index 73a50dccf0..d468f34653 100644
--- a/modular_citadel/code/modules/mob/living/carbon/human/species.dm
+++ b/modular_citadel/code/modules/mob/living/carbon/human/species.dm
@@ -44,37 +44,105 @@
if(user.getStaminaLoss() >= STAMINA_SOFTCRIT)
to_chat(user, "You're too exhausted.")
return FALSE
- else if(target.check_block())
- target.visible_message("[target] blocks [user]'s disarm attempt!")
- return 0
+ if(target.check_block())
+ target.visible_message("[target] blocks [user]'s shoving attempt!")
+ return FALSE
if(attacker_style && attacker_style.disarm_act(user,target))
- return 1
+ return TRUE
+ if(user.resting)
+ return FALSE
else
+ if(user == target)
+ return
user.do_attack_animation(target, ATTACK_EFFECT_DISARM)
-
- user.adjustStaminaLossBuffered(4) //CITADEL CHANGE - makes disarmspam cause staminaloss
+ user.adjustStaminaLossBuffered(4)
+ playsound(target, 'sound/weapons/thudswoosh.ogg', 50, TRUE, -1)
if(target.w_uniform)
target.w_uniform.add_fingerprint(user)
- var/randomized_zone = ran_zone(user.zone_selected)
SEND_SIGNAL(target, COMSIG_HUMAN_DISARM_HIT, user, user.zone_selected)
- var/obj/item/bodypart/affecting = target.get_bodypart(randomized_zone)
- if((!target.combatmode && user.combatmode || prob(target.getStaminaLoss()*(user.resting ? 0.25 : 1)*(user.combatmode ? 1 : 0.05))) && !target.resting) //probability depends on staminaloss. it's plausible, but unlikely that you'll be able to push someone over while resting, and pretty rare to successfully push someone outside of combat mode. The few people that even know how to right-click outside of combat mode are a rarity but let's take that into account regardless.
- playsound(target, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
- target.visible_message("[user] [user.combatmode ? "has" : "gently"] pushed [target]!",
- "[user] has pushed [target]!", null, COMBAT_MESSAGE_RANGE)
- target.apply_effect(40, EFFECT_KNOCKDOWN, target.run_armor_check(affecting, "melee", "Your armor prevents your fall!", "Your armor softens your fall!"))
- target.forcesay(GLOB.hit_appends)
- log_combat(user, target, "disarmed", " pushing them to the ground")
- return
+ if(!target.resting)
+ target.adjustStaminaLoss(5)
+
+
+ var/turf/target_oldturf = target.loc
+ var/shove_dir = get_dir(user.loc, target_oldturf)
+ var/turf/target_shove_turf = get_step(target.loc, shove_dir)
+ var/mob/living/carbon/human/target_collateral_human
+ var/obj/structure/table/target_table
+ var/shove_blocked = FALSE //Used to check if a shove is blocked so that if it is knockdown logic can be applied
+
+ //Thank you based whoneedsspace
+ target_collateral_human = locate(/mob/living/carbon/human) in target_shove_turf.contents
+ if(target_collateral_human)
+ shove_blocked = TRUE
+ else
+ target.Move(target_shove_turf, shove_dir)
+ if(get_turf(target) == target_oldturf)
+ target_table = locate(/obj/structure/table) in target_shove_turf.contents
+ shove_blocked = TRUE
+
+ if(shove_blocked && !target.is_shove_knockdown_blocked())
+ var/directional_blocked = FALSE
+ if(shove_dir in GLOB.cardinals) //Directional checks to make sure that we're not shoving through a windoor or something like that
+ var/target_turf = get_turf(target)
+ for(var/obj/O in target_turf)
+ if(O.flags_1 & ON_BORDER_1 && O.dir == shove_dir && O.density)
+ directional_blocked = TRUE
+ break
+ if(target_turf != target_shove_turf) //Make sure that we don't run the exact same check twice on the same tile
+ for(var/obj/O in target_shove_turf)
+ if(O.flags_1 & ON_BORDER_1 && O.dir == turn(shove_dir, 180) && O.density)
+ directional_blocked = TRUE
+ break
+ var/targetatrest = target.resting
+ if(((!target_table && !target_collateral_human) || directional_blocked) && !targetatrest)
+ target.Knockdown(SHOVE_KNOCKDOWN_SOLID)
+ user.visible_message("[user.name] shoves [target.name], knocking them down!",
+ "You shove [target.name], knocking them down!", null, COMBAT_MESSAGE_RANGE)
+ log_combat(user, target, "shoved", "knocking them down")
+ else if(target_table)
+ if(!targetatrest)
+ target.Knockdown(SHOVE_KNOCKDOWN_TABLE)
+ user.visible_message("[user.name] shoves [target.name] onto \the [target_table]!",
+ "You shove [target.name] onto \the [target_table]!", null, COMBAT_MESSAGE_RANGE)
+ target.forceMove(target_shove_turf)
+ log_combat(user, target, "shoved", "onto [target_table]")
+ else if(target_collateral_human && !targetatrest)
+ target.Knockdown(SHOVE_KNOCKDOWN_HUMAN)
+ if(!target_collateral_human.resting)
+ target_collateral_human.Knockdown(SHOVE_KNOCKDOWN_COLLATERAL)
+ user.visible_message("[user.name] shoves [target.name] into [target_collateral_human.name]!",
+ "You shove [target.name] into [target_collateral_human.name]!", null, COMBAT_MESSAGE_RANGE)
+ log_combat(user, target, "shoved", "into [target_collateral_human.name]")
+
+ else
+ user.visible_message("[user.name] shoves [target.name]!",
+ "You shove [target.name]!", null, COMBAT_MESSAGE_RANGE)
+ var/target_held_item = target.get_active_held_item()
+ var/knocked_item = FALSE
+ if(!is_type_in_typecache(target_held_item, GLOB.shove_disarming_types))
+ target_held_item = null
+ if(!target.has_movespeed_modifier(SHOVE_SLOWDOWN_ID))
+ target.add_movespeed_modifier(SHOVE_SLOWDOWN_ID, multiplicative_slowdown = SHOVE_SLOWDOWN_STRENGTH)
+ if(target_held_item)
+ target.visible_message("[target.name]'s grip on \the [target_held_item] loosens!",
+ "Your grip on \the [target_held_item] loosens!", null, COMBAT_MESSAGE_RANGE)
+ addtimer(CALLBACK(target, /mob/living/carbon/human/proc/clear_shove_slowdown), SHOVE_SLOWDOWN_LENGTH)
+ else if(target_held_item)
+ target.dropItemToGround(target_held_item)
+ knocked_item = TRUE
+ target.visible_message("[target.name] drops \the [target_held_item]!!",
+ "You drop \the [target_held_item]!!", null, COMBAT_MESSAGE_RANGE)
+ var/append_message = ""
+ if(target_held_item)
+ if(knocked_item)
+ append_message = "causing them to drop [target_held_item]"
+ else
+ append_message = "loosening their grip on [target_held_item]"
+ log_combat(user, target, "shoved", append_message)
- playsound(target, 'sound/weapons/thudswoosh.ogg', 25, 1, -1)
- target.visible_message("[user] [user.combatmode ? "attempted to push" : "tries to gently push"] [target] over!", \
- "[user] [user.combatmode ? "attempted to push" : "tries to gently push"] [target] over!", null, COMBAT_MESSAGE_RANGE)
- if(!target.resting && !user.resting && user.combatmode)
- target.adjustStaminaLoss(rand(1,5)) //This is the absolute most inefficient way to get someone into soft stamcrit, but if you've got a crowd trying to shove you over, you've no option but to get knocked down and accept fate
- log_combat(user, target, "attempted to disarm push")
////////////////////
/////BODYPARTS/////
diff --git a/modular_citadel/code/modules/research/designs/weapon_designs.dm b/modular_citadel/code/modules/research/designs/weapon_designs.dm
index bdb77170ed..b27cedbcc2 100644
--- a/modular_citadel/code/modules/research/designs/weapon_designs.dm
+++ b/modular_citadel/code/modules/research/designs/weapon_designs.dm
@@ -1,7 +1,7 @@
/datum/design/mag_oldsmg/rubber_mag
- name = "WT-550 Auto Gun rubberbullets Magazine (4.6x30mm rubber)"
- desc = "A 20 round rubber shots magazine for the out of date security WT-550 Auto Rifle"
+ name = "WT-550 Semi-Auto SMG rubberbullets Magazine (4.6x30mm rubber)"
+ desc = "A 20 round rubber shots magazine for the out of date security WT-550 Semi-Auto SMG"
id = "mag_oldsmg_rubber"
materials = list(MAT_METAL = 6000)
build_path = /obj/item/ammo_box/magazine/wt550m9/wtrubber
- departmental_flags = DEPARTMENTAL_FLAG_SECURITY
\ No newline at end of file
+ departmental_flags = DEPARTMENTAL_FLAG_SECURITY
diff --git a/modular_citadel/code/modules/research/designs/weapon_designs/weapon_designs.dm b/modular_citadel/code/modules/research/designs/weapon_designs/weapon_designs.dm
index 0db3bb9b1d..6246b9e24e 100644
--- a/modular_citadel/code/modules/research/designs/weapon_designs/weapon_designs.dm
+++ b/modular_citadel/code/modules/research/designs/weapon_designs/weapon_designs.dm
@@ -1,7 +1,7 @@
/datum/design/mag_oldsmg/tx_mag
- name = "WT-550 Auto Gun Uranium Magazine (4.6x30mm TX)"
- desc = "A 20 round uranium tipped magazine for the out of date security WT-550 Auto Rifle"
+ name = "WT-550 Semi-Auto SMG Uranium Magazine (4.6x30mm TX)"
+ desc = "A 20 round uranium tipped magazine for the out of date security WT-550 Semi-Auto SMG."
id = "mag_oldsmg_tx"
materials = list(MAT_METAL = 6000, MAT_SILVER = 600, MAT_URANIUM = 2000)
build_path = /obj/item/ammo_box/magazine/wt550m9/wttx
- departmental_flags = DEPARTMENTAL_FLAG_SECURITY
\ No newline at end of file
+ departmental_flags = DEPARTMENTAL_FLAG_SECURITY
diff --git a/sound/weapons/dink.ogg b/sound/weapons/dink.ogg
new file mode 100644
index 0000000000..54f3678f79
Binary files /dev/null and b/sound/weapons/dink.ogg differ
diff --git a/tgstation.dme b/tgstation.dme
index 268d4f1ff9..c43b1a7019 100755
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -2528,10 +2528,15 @@
#include "code\modules\research\techweb\all_nodes.dm"
#include "code\modules\research\xenobiology\xenobio_camera.dm"
#include "code\modules\research\xenobiology\xenobiology.dm"
-#include "code\modules\research\xenobiology\crossbreeding\_corecross.dm"
+#include "code\modules\research\xenobiology\crossbreeding\__corecross.dm"
+#include "code\modules\research\xenobiology\crossbreeding\_clothing.dm"
+#include "code\modules\research\xenobiology\crossbreeding\_misc.dm"
+#include "code\modules\research\xenobiology\crossbreeding\_mobs.dm"
#include "code\modules\research\xenobiology\crossbreeding\_status_effects.dm"
+#include "code\modules\research\xenobiology\crossbreeding\_weapons.dm"
#include "code\modules\research\xenobiology\crossbreeding\burning.dm"
#include "code\modules\research\xenobiology\crossbreeding\charged.dm"
+#include "code\modules\research\xenobiology\crossbreeding\chilling.dm"
#include "code\modules\research\xenobiology\crossbreeding\consuming.dm"
#include "code\modules\research\xenobiology\crossbreeding\industrial.dm"
#include "code\modules\research\xenobiology\crossbreeding\prismatic.dm"