diff --git a/Dockerfile b/Dockerfile
index 97d2ccf2e7..4d9443971e 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,5 +1,4 @@
-FROM tgstation/byond:512.1448 as base
-#above version must be the same as the one in dependencies.sh
+FROM tgstation/byond:512.1453 as base
FROM base as build_base
diff --git a/code/__DEFINES/citadel_defines.dm b/code/__DEFINES/citadel_defines.dm
index 7744b24d0f..e5749764e0 100644
--- a/code/__DEFINES/citadel_defines.dm
+++ b/code/__DEFINES/citadel_defines.dm
@@ -128,3 +128,6 @@
//component stuff
#define COMSIG_COMBAT_TOGGLED "combatmode_toggled" //called by combat mode toggle on all equipped items. args: (mob/user, combatmode)
+
+//belly sound pref things
+#define NORMIE_HEARCHECK 4
diff --git a/code/__DEFINES/mobs.dm b/code/__DEFINES/mobs.dm
index b7d467c385..62e1cf1b90 100644
--- a/code/__DEFINES/mobs.dm
+++ b/code/__DEFINES/mobs.dm
@@ -258,3 +258,5 @@
// /obj/item/bodypart on_mob_life() retval flag
#define BODYPART_LIFE_UPDATE_HEALTH (1<<0)
+
+#define HUMAN_FIRE_STACK_ICON_NUM 3
diff --git a/code/__DEFINES/tgs.dm b/code/__DEFINES/tgs.dm
index faa620613c..d24054a24c 100644
--- a/code/__DEFINES/tgs.dm
+++ b/code/__DEFINES/tgs.dm
@@ -10,6 +10,10 @@
//Comment this out once you've filled in the below
#error TGS API unconfigured
+//Uncomment this if you wish to allow the game to interact with TGS 3
+//This will raise the minimum required security level of your game to TGS_SECURITY_TRUSTED due to it utilizing call()()
+//#define TGS_V3_API
+
//Required interfaces (fill in with your codebase equivalent):
//create a global variable named `Name` and set it to `Value`
@@ -47,7 +51,21 @@
#define TGS_EVENT_PORT_SWAP -2 //before a port change is about to happen, extra parameter is new port
#define TGS_EVENT_REBOOT_MODE_CHANGE -1 //before a reboot mode change, extras parameters are the current and new reboot mode enums
-//TODO
+//See the descriptions for these codes here: https://github.com/tgstation/tgstation-server/blob/master/src/Tgstation.Server.Host/Components/EventType.cs
+#define TGS_EVENT_REPO_RESET_ORIGIN 0
+#define TGS_EVENT_REPO_CHECKOUT 1
+#define TGS_EVENT_REPO_FETCH 2
+#define TGS_EVENT_REPO_MERGE_PULL_REQUEST 3
+#define TGS_EVENT_REPO_PRE_SYNCHRONIZE 4
+#define TGS_EVENT_BYOND_INSTALL_START 5
+#define TGS_EVENT_BYOND_INSTALL_FAIL 6
+#define TGS_EVENT_BYOND_ACTIVE_VERSION_CHANGE 7
+#define TGS_EVENT_COMPILE_START 8
+#define TGS_EVENT_COMPILE_CANCELLED 9
+#define TGS_EVENT_COMPILE_FAILURE 10
+#define TGS_EVENT_COMPILE_COMPLETE 11
+#define TGS_EVENT_INSTANCE_AUTO_UPDATE_START 12
+#define TGS_EVENT_REPO_MERGE_CONFLICT 13
//OTHER ENUMS
@@ -74,8 +92,8 @@
/world/proc/TgsInitializationComplete()
return
-//Put this somewhere in /world/Topic(T, Addr, Master, Keys) that is always run before T is modified
-#define TGS_TOPIC var/tgs_topic_return = TgsTopic(T); if(tgs_topic_return) return tgs_topic_return
+//Put this at the start of /world/Topic()
+#define TGS_TOPIC var/tgs_topic_return = TgsTopic(args[1]); if(tgs_topic_return) return tgs_topic_return
//Call this at the beginning of world/Reboot(reason)
/world/proc/TgsReboot()
@@ -177,7 +195,7 @@
//Gets a list of connected tgs_chat_channel
/world/proc/TgsChatChannelInfo()
return
-
+
//Sends a message to connected game chats
//message: The message to send
//channels: optional channels to limit the broadcast to
@@ -201,24 +219,24 @@ The MIT License
Copyright (c) 2017 Jordan Brown
-Permission is hereby granted, free of charge,
-to any person obtaining a copy of this software and
-associated documentation files (the "Software"), to
-deal in the Software without restriction, including
-without limitation the rights to use, copy, modify,
-merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom
-the Software is furnished to do so,
+Permission is hereby granted, free of charge,
+to any person obtaining a copy of this software and
+associated documentation files (the "Software"), to
+deal in the Software without restriction, including
+without limitation the rights to use, copy, modify,
+merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom
+the Software is furnished to do so,
subject to the following conditions:
-The above copyright notice and this permission notice
+The above copyright notice and this permission notice
shall be included in all copies or substantial portions of the Software.
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
-ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
\ No newline at end of file
diff --git a/code/_compile_options.dm b/code/_compile_options.dm
index 67bbe24e38..3ec2510cc7 100644
--- a/code/_compile_options.dm
+++ b/code/_compile_options.dm
@@ -3,6 +3,11 @@
//#define DATUMVAR_DEBUGGING_MODE //Enables the ability to cache datum vars and retrieve later for debugging which vars changed.
+// Comment this out if you are debugging problems that might be obscured by custom error handling in world/Error
+#ifdef DEBUG
+#define USE_CUSTOM_ERROR_HANDLER
+#endif
+
#ifdef TESTING
#define DATUMVAR_DEBUGGING_MODE
diff --git a/code/controllers/subsystem/research.dm b/code/controllers/subsystem/research.dm
index 4aee87a38f..0836678c0a 100644
--- a/code/controllers/subsystem/research.dm
+++ b/code/controllers/subsystem/research.dm
@@ -45,7 +45,7 @@ SUBSYSTEM_DEF(research)
var/list/errored_datums = list()
var/list/point_types = list() //typecache style type = TRUE list
//----------------------------------------------
- var/list/single_server_income = list(TECHWEB_POINT_TYPE_GENERIC = 25) //citadel edit - techwebs nerf
+ var/list/single_server_income = list(TECHWEB_POINT_TYPE_GENERIC = 35) //citadel edit - techwebs nerf
var/multiserver_calculation = FALSE
var/last_income
//^^^^^^^^ ALL OF THESE ARE PER SECOND! ^^^^^^^^
diff --git a/code/datums/mood_events/needs_events.dm b/code/datums/mood_events/needs_events.dm
index c67f4bf160..75b7e6931f 100644
--- a/code/datums/mood_events/needs_events.dm
+++ b/code/datums/mood_events/needs_events.dm
@@ -4,7 +4,7 @@
mood_change = -4
/datum/mood_event/wellfed
- description = "My belly feels round and full.\n"
+ description = "I'm stuffed!\n"
mood_change = 6
/datum/mood_event/fed
diff --git a/code/datums/position_point_vector.dm b/code/datums/position_point_vector.dm
index 7d49db8429..a33d0d2225 100644
--- a/code/datums/position_point_vector.dm
+++ b/code/datums/position_point_vector.dm
@@ -186,8 +186,8 @@
/datum/point/vector/proc/increment(multiplier = 1)
iteration++
- x += mpx * 1
- y += mpy * 1
+ x += mpx * (multiplier)
+ y += mpy * (multiplier)
/datum/point/vector/proc/return_vector_after_increments(amount = 7, multiplier = 1, force_simulate = FALSE)
var/datum/point/vector/v = copy_to()
diff --git a/code/game/data_huds.dm b/code/game/data_huds.dm
index 7a341ad69a..3af43ffb78 100644
--- a/code/game/data_huds.dm
+++ b/code/game/data_huds.dm
@@ -222,7 +222,7 @@
var/icon/I = icon(icon, icon_state, dir)
holder.pixel_y = I.Height() - world.icon_size
holder.icon_state = "hudno_id"
- if(wear_id)
+ if(wear_id?.GetID())
holder.icon_state = "hud[ckey(wear_id.GetJobName())]"
sec_hud_set_security_status()
diff --git a/code/game/gamemodes/objective.dm b/code/game/gamemodes/objective.dm
index 41e429319c..7532d18d06 100644
--- a/code/game/gamemodes/objective.dm
+++ b/code/game/gamemodes/objective.dm
@@ -378,6 +378,8 @@ GLOBAL_LIST_EMPTY(objectives)
for(var/datum/mind/M in owners)
if(considered_alive(M))
return FALSE
+ if(M.current?.suiciding) //killing yourself ISN'T glorious.
+ return FALSE
return TRUE
/datum/objective/nuclear
diff --git a/code/game/machinery/_machinery.dm b/code/game/machinery/_machinery.dm
index 69edfcd5ec..9b5aa96b0b 100644
--- a/code/game/machinery/_machinery.dm
+++ b/code/game/machinery/_machinery.dm
@@ -91,6 +91,7 @@ Class Procs:
verb_yell = "blares"
pressure_resistance = 15
max_integrity = 200
+ layer = BELOW_OBJ_LAYER //keeps shit coming out of the machine from ending up underneath it.
anchored = TRUE
interaction_flags_atom = INTERACT_ATOM_ATTACK_HAND | INTERACT_ATOM_UI_INTERACT
@@ -120,7 +121,7 @@ Class Procs:
armor = list("melee" = 25, "bullet" = 10, "laser" = 10, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 70)
. = ..()
GLOB.machines += src
-
+
if(ispath(circuit, /obj/item/circuitboard))
circuit = new circuit
circuit.apply_default_parts(src)
diff --git a/code/game/machinery/harvester.dm b/code/game/machinery/harvester.dm
index 17f355b5ad..1f40672e05 100644
--- a/code/game/machinery/harvester.dm
+++ b/code/game/machinery/harvester.dm
@@ -131,18 +131,24 @@
playsound(src, 'sound/machines/microwave/microwave-end.ogg', 100, 0)
/obj/machinery/harvester/screwdriver_act(mob/living/user, obj/item/I)
- . = ..()
- if(.)
- return TRUE
- if(!state_open && !occupant)
- if(default_deconstruction_screwdriver(user, "[initial(icon_state)]-o", initial(icon_state), I))
- return
+ . = TRUE
+ if(..())
+ return
+ if(occupant)
+ to_chat(user, "[src] is currently occupied!")
+ return
+ if(state_open)
+ to_chat(user, "[src] must be closed to [panel_open ? "close" : "open"] it's maintenance hatch!")
+ return
+ if(default_deconstruction_screwdriver(user, "[initial(icon_state)]-o", initial(icon_state), I))
+ return
+ return FALSE
/obj/machinery/harvester/crowbar_act(mob/living/user, obj/item/I)
if(default_pry_open(I))
- return
+ return TRUE
if(default_deconstruction_crowbar(I))
- return
+ return TRUE
/obj/machinery/harvester/default_pry_open(obj/item/I) //wew
. = !(state_open || panel_open || (flags_1 & NODECONSTRUCT_1)) && I.tool_behaviour == TOOL_CROWBAR //We removed is_operational() here
@@ -181,4 +187,4 @@
if(state_open)
to_chat(user, "[src] must be closed before harvesting.")
else if(!harvesting)
- to_chat(user, "Alt-click [src] to start harvesting.")
+ to_chat(user, "Alt-click [src] to start harvesting.")
\ No newline at end of file
diff --git a/code/game/objects/items/cards_ids.dm b/code/game/objects/items/cards_ids.dm
index e4967b494d..30b1ca3399 100644
--- a/code/game/objects/items/cards_ids.dm
+++ b/code/game/objects/items/cards_ids.dm
@@ -95,7 +95,33 @@
var/atom/A = target
if(!proximity && prox_check)
return
- A.emag_act(user)
+ //Citadel changes: modular code misfiring, so we're bypassing into main code.
+ if(!uses)
+ user.visible_message("[src] emits a weak spark. It's burnt out!")
+ playsound(src, 'sound/effects/light_flicker.ogg', 100, 1)
+ return
+ else if(uses <= 3)
+ playsound(src, 'sound/effects/light_flicker.ogg', 30, 1) //Tiiiiiiny warning sound to let ya know your emag's almost dead
+
+ if(isturf(A))
+ return
+ if(istype(A,/obj/item/storage/lockbox))
+ A.emag_act(user)
+ uses = max(uses - 1, 0)
+ if(!uses)
+ user.visible_message("[src] fizzles and sparks. It seems like it's out of charges.")
+ playsound(src, 'sound/effects/light_flicker.ogg', 100, 1)
+ if(istype(A,/obj/item/storage))
+ return
+ if(!(isobj(A) || issilicon(A) || isbot(A) || isdrone(A)))
+ return
+ else
+ A.emag_act(user)
+ uses = max(uses - 1, 0)
+ if(!uses)
+ user.visible_message("[src] fizzles and sparks. It seems like it's out of charges.")
+ playsound(src, 'sound/effects/light_flicker.ogg', 100, 1)
+
/obj/item/card/emagfake
desc = "It's a card with a magnetic strip attached to some circuitry. Closer inspection shows that this card is a poorly made replica, with a \"DonkCo\" logo stamped on the back."
diff --git a/code/game/objects/items/devices/dogborg_sleeper.dm b/code/game/objects/items/devices/dogborg_sleeper.dm
index e12344fa53..30a3e5a9a2 100644
--- a/code/game/objects/items/devices/dogborg_sleeper.dm
+++ b/code/game/objects/items/devices/dogborg_sleeper.dm
@@ -13,11 +13,13 @@
var/cleaning = FALSE
var/cleaning_cycles = 10
var/patient_laststat = null
- var/list/injection_chems = list("antitoxin", "epinephrine", "morphine", "salbutamol", "bicaridine", "kelotane")
+ var/list/injection_chems = list("antitoxin", "epinephrine", "salbutamol", "bicaridine", "kelotane")
var/eject_port = "ingestion"
var/escape_in_progress = FALSE
var/message_cooldown
var/breakout_time = 300
+ var/tmp/last_hearcheck = 0
+ var/tmp/list/hearing_mobs
var/list/items_preserved = list()
var/static/list/important_items = typecacheof(list(
/obj/item/hand_tele,
@@ -45,10 +47,16 @@
// Bags are prohibited from this due to the potential explotation of objects, same with brought
-/obj/item/dogborg/sleeper/New()
- ..()
+/obj/item/dogborg/sleeper/Initialize()
+ . = ..()
update_icon()
item_flags |= NOBLUDGEON //No more attack messages
+ START_PROCESSING(SSobj, src)
+
+/obj/item/dogborg/sleeper/Destroy()
+ STOP_PROCESSING(SSobj, src)
+ go_out() //just... sanity I guess, edge case shit
+ return ..()
/obj/item/dogborg/sleeper/Exit(atom/movable/O)
return 0
@@ -59,7 +67,7 @@
return
if(!iscarbon(target))
return
- if(!(target.client && target.client.prefs && target.client.prefs.toggles && (target.client.prefs.toggles & MEDIHOUND_SLEEPER)))
+ if(!target.client || !(target.client.prefs.cit_toggles & MEDIHOUND_SLEEPER))
to_chat(user, "This person is incompatible with our equipment.")
return
if(target.buckled)
@@ -86,7 +94,6 @@
target.forceMove(src)
target.reset_perspective(src)
update_gut()
- START_PROCESSING(SSobj, src)
user.visible_message("[hound.name]'s medical pod lights up and expands as [target.name] slips inside into their [src.name].", "Your medical pod lights up as [target] slips into your [src]. Life support functions engaged.")
message_admins("[key_name(hound)] has sleeper'd [key_name(patient)] as a dogborg. [ADMIN_JMP(src)]")
playsound(hound, 'sound/effects/bin_close.ogg', 100, 1)
@@ -137,7 +144,8 @@
else //You clicked eject with nothing in you, let's just reset stuff to be sure.
items_preserved.Cut()
cleaning = FALSE
- update_gut()
+ update_gut()
+
/obj/item/dogborg/sleeper/attack_self(mob/user)
if(..())
@@ -265,7 +273,6 @@
patient_laststat = null
patient = null
hound.update_icons()
- return
//Gurgleborg process
/obj/item/dogborg/sleeper/proc/clean_cycle()
@@ -274,6 +281,10 @@
if(!(I in contents))
items_preserved -= I
var/list/touchable_items = contents - items_preserved
+ var/sound/prey_digest = sound(get_sfx("digest_prey"))
+ var/sound/prey_death = sound(get_sfx("death_prey"))
+ var/sound/pred_digest = sound(get_sfx("digest_pred"))
+ var/sound/pred_death = sound(get_sfx("death_pred"))
if(cleaning_cycles)
cleaning_cycles--
cleaning = TRUE
@@ -293,10 +304,19 @@
to_chat(hound,"You feel your belly slowly churn around [T], breaking them down into a soft slurry to be used as power for your systems.")
to_chat(T,"You feel [hound]'s belly slowly churn around your form, breaking you down into a soft slurry to be used as power for [hound]'s systems.")
hound.cell.give(30000) //Fueeeeellll
- T.stop_sound_channel(CHANNEL_PRED)
- playsound(get_turf(hound),"death_pred",50,0,-6,0,channel=CHANNEL_PRED,ignore_walls = FALSE)
- T.stop_sound_channel(CHANNEL_PRED)
- T.playsound_local("death_prey",60)
+ if((world.time - NORMIE_HEARCHECK) > last_hearcheck)
+ var/turf/source = get_turf(hound)
+ LAZYCLEARLIST(hearing_mobs)
+ for(var/mob/H in get_hearers_in_view(3, source))
+ if(!H.client || !(H.client.prefs.cit_toggles & DIGESTION_NOISES))
+ continue
+ LAZYADD(hearing_mobs, H)
+ last_hearcheck = world.time
+ for(var/mob/H in hearing_mobs)
+ if(!istype(H.loc, /obj/item/dogborg/sleeper))
+ H.playsound_local(source, null, 45, falloff = 0, S = pred_death)
+ else if(H in contents)
+ H.playsound_local(source, null, 65, falloff = 0, S = prey_death)
for(var/belly in T.vore_organs)
var/obj/belly/B = belly
for(var/atom/movable/thing in B)
@@ -328,15 +348,22 @@
to_chat(hound, "Your [src] is now clean. Ending self-cleaning cycle.")
cleaning = FALSE
update_gut()
- return
//sound effects
- for(var/mob/living/M in contents)
- if(prob(50))
- M.stop_sound_channel(CHANNEL_PRED)
- playsound(get_turf(hound),"digest_pred",35,0,-6,0,channel=CHANNEL_PRED,ignore_walls = FALSE)
- M.stop_sound_channel(CHANNEL_PRED)
- M.playsound_local("digest_prey",60)
+ if(prob(50))
+ if((world.time - NORMIE_HEARCHECK) > last_hearcheck)
+ var/turf/source = get_turf(hound)
+ LAZYCLEARLIST(hearing_mobs)
+ for(var/mob/H in get_hearers_in_view(3, source))
+ if(!H.client || !(H.client.prefs.cit_toggles & DIGESTION_NOISES))
+ continue
+ LAZYADD(hearing_mobs, H)
+ last_hearcheck = world.time
+ for(var/mob/H in hearing_mobs)
+ if(!istype(H.loc, /obj/item/dogborg/sleeper))
+ H.playsound_local(source, null, 45, falloff = 0, S = pred_digest)
+ else if(H in contents)
+ H.playsound_local(source, null, 65, falloff = 0, S = prey_digest)
if(cleaning)
addtimer(CALLBACK(src, .proc/clean_cycle), 50)
@@ -407,7 +434,6 @@
brigman.forceMove(src)
brigman.reset_perspective(src)
update_gut()
- START_PROCESSING(SSobj, src)
user.visible_message("[hound.name]'s mobile brig clunks in series as [brigman] slips inside.", "Your mobile brig groans lightly as [brigman] slips inside.")
playsound(hound, 'sound/effects/bin_close.ogg', 80, 1) // Really don't need ERP sound effects for robots
return
@@ -481,7 +507,6 @@
trashman.forceMove(src)
trashman.reset_perspective(src)
update_gut()
- START_PROCESSING(SSobj, src)
user.visible_message("[hound.name]'s garbage processor groans lightly as [trashman] slips inside.", "Your garbage compactor groans lightly as [trashman] slips inside.")
playsound(hound, 'sound/effects/bin_close.ogg', 80, 1)
return
diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm
index d66d64cde5..a6a6c5f699 100644
--- a/code/game/objects/structures/crates_lockers/closets.dm
+++ b/code/game/objects/structures/crates_lockers/closets.dm
@@ -167,6 +167,10 @@
L.stop_pulling()
else if(istype(AM, /obj/structure/closet))
return
+
+ else if(istype(AM, /obj/effect))
+ return
+
else if(isobj(AM))
if (istype(AM, /obj/item))
var/obj/item/I = AM
diff --git a/code/game/objects/structures/crates_lockers/crates.dm b/code/game/objects/structures/crates_lockers/crates.dm
index df3df8ad14..067b1b0eb1 100644
--- a/code/game/objects/structures/crates_lockers/crates.dm
+++ b/code/game/objects/structures/crates_lockers/crates.dm
@@ -96,6 +96,7 @@
/obj/structure/closet/crate/freezer/blood
name = "blood freezer"
desc = "A freezer containing packs of blood."
+ icon_state = "surgery"
/obj/structure/closet/crate/freezer/blood/PopulateContents()
. = ..()
diff --git a/code/modules/atmospherics/environmental/LINDA_fire.dm b/code/modules/atmospherics/environmental/LINDA_fire.dm
index 9ca822b5ce..f816866070 100644
--- a/code/modules/atmospherics/environmental/LINDA_fire.dm
+++ b/code/modules/atmospherics/environmental/LINDA_fire.dm
@@ -37,7 +37,7 @@
active_hotspot = new /obj/effect/hotspot(src)
active_hotspot.temperature = exposed_temperature
- active_hotspot.volume = exposed_volume
+ active_hotspot.volume = exposed_volume*25
active_hotspot.just_spawned = (current_cycle < SSair.times_fired)
//remove just_spawned protection if no longer processing this cell
diff --git a/code/modules/clothing/shoes/_shoes.dm b/code/modules/clothing/shoes/_shoes.dm
index 61f189e236..00cb2678cd 100644
--- a/code/modules/clothing/shoes/_shoes.dm
+++ b/code/modules/clothing/shoes/_shoes.dm
@@ -54,7 +54,10 @@
if(damaged_clothes)
. += mutable_appearance('icons/effects/item_damage.dmi', "damagedshoe")
if(bloody)
- . += mutable_appearance('icons/effects/blood.dmi', "shoeblood")
+ if(adjusted == NORMAL_STYLE)
+ . += mutable_appearance('icons/effects/blood.dmi', "shoeblood")
+ else
+ . += mutable_appearance('modular_citadel/icons/mob/digishoes.dmi', "shoeblood")
/obj/item/clothing/shoes/equipped(mob/user, slot)
. = ..()
diff --git a/code/modules/clothing/suits/utility.dm b/code/modules/clothing/suits/utility.dm
index 1748813f56..b53ec05dda 100644
--- a/code/modules/clothing/suits/utility.dm
+++ b/code/modules/clothing/suits/utility.dm
@@ -20,6 +20,7 @@
body_parts_covered = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
allowed = list(/obj/item/flashlight, /obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/plasmaman, /obj/item/extinguisher, /obj/item/crowbar)
slowdown = 1
+ armor = list("melee" = 15, "bullet" = 5, "laser" = 20, "energy" = 10, "bomb" = 20, "bio" = 10, "rad" = 20, "fire" = 100, "acid" = 50)
flags_inv = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT
clothing_flags = STOPSPRESSUREDAMAGE | THICKMATERIAL
heat_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
diff --git a/code/modules/events/pirates.dm b/code/modules/events/pirates.dm
index 80b8373887..910e94f680 100644
--- a/code/modules/events/pirates.dm
+++ b/code/modules/events/pirates.dm
@@ -148,6 +148,7 @@
new /obj/item/stack/spacecash/c200(drop_location())
credits_stored -= 200
to_chat(user,"You retrieve the siphoned credits!")
+ credits_stored = 0
/obj/machinery/shuttle_scrambler/proc/send_notification()
diff --git a/code/modules/food_and_drinks/food/snacks_other.dm b/code/modules/food_and_drinks/food/snacks_other.dm
index ecb3cfb2ba..a2f5b06042 100644
--- a/code/modules/food_and_drinks/food/snacks_other.dm
+++ b/code/modules/food_and_drinks/food/snacks_other.dm
@@ -156,7 +156,7 @@
icon_state = "mint"
bitesize = 1
trash = /obj/item/trash/plate
- list_reagents = list("minttoxin" = 1)
+ list_reagents = list("minttoxin" = 2)
filling_color = "#800000"
foodtype = TOXIC | SUGAR
diff --git a/code/modules/food_and_drinks/kitchen_machinery/microwave.dm b/code/modules/food_and_drinks/kitchen_machinery/microwave.dm
index 3bcc8d7659..1445f79aa2 100644
--- a/code/modules/food_and_drinks/kitchen_machinery/microwave.dm
+++ b/code/modules/food_and_drinks/kitchen_machinery/microwave.dm
@@ -10,6 +10,8 @@
active_power_usage = 100
circuit = /obj/item/circuitboard/machine/microwave
pass_flags = PASSTABLE
+ light_color = LIGHT_COLOR_YELLOW
+ light_power = 3
var/operating = FALSE // Is it on?
var/dirty = 0 // = {0..100} Does it need cleaning?
var/broken = 0 // ={0,1,2} How broken is it???
@@ -267,12 +269,14 @@
soundloop.start()
operating = TRUE
icon_state = "mw1"
+ set_light(1.5)
updateUsrDialog()
/obj/machinery/microwave/proc/abort()
operating = FALSE // Turn it off again aferwards
icon_state = "mw"
updateUsrDialog()
+ set_light(0)
soundloop.stop()
/obj/machinery/microwave/proc/stop()
@@ -298,6 +302,7 @@
if(prob(50))
new /obj/item/reagent_containers/food/snacks/badrecipe(src)
qdel(S)
+ set_light(0)
soundloop.stop()
/obj/machinery/microwave/proc/broke()
@@ -310,6 +315,7 @@
flags_1 = null //So you can't add condiments
operating = FALSE // Turn it off again aferwards
updateUsrDialog()
+ set_light(0)
soundloop.stop()
/obj/machinery/microwave/Topic(href, href_list)
diff --git a/code/modules/mining/equipment/explorer_gear.dm b/code/modules/mining/equipment/explorer_gear.dm
index 2c7eaf09ba..d155994379 100644
--- a/code/modules/mining/equipment/explorer_gear.dm
+++ b/code/modules/mining/equipment/explorer_gear.dm
@@ -121,7 +121,7 @@
/****************SEVA Suit and Mask****************/
/obj/item/clothing/suit/hooded/seva
- name = "SEVA suit"
+ name = "SEVA Suit"
desc = "A fire-proof suit for exploring hot environments."
icon_state = "seva"
item_state = "seva"
@@ -135,7 +135,7 @@
resistance_flags = FIRE_PROOF | GOLIATH_WEAKNESS
/obj/item/clothing/head/hooded/seva
- name = "SEVA hood"
+ name = "SEVA Hood"
desc = "A fire-proof hood for exploring hot environments."
icon_state = "seva"
item_state = "seva"
@@ -145,6 +145,19 @@
armor = list("melee" = 10, "bullet" = 10, "laser" = 10, "energy" = 10, "bomb" = 25, "bio" = 50, "rad" = 25, "fire" = 100, "acid" = 25)
resistance_flags = FIRE_PROOF | GOLIATH_WEAKNESS
+/obj/item/clothing/mask/gas/seva
+ name = "SEVA Mask"
+ desc = "A face-covering plate that can be connected to an air supply. Intended for use with the SEVA Suit."
+ icon_state = "seva"
+ clothing_flags = BLOCK_GAS_SMOKE_EFFECT | MASKINTERNALS
+ flags_inv = HIDEEARS|HIDEEYES|HIDEFACE|HIDEFACIALHAIR
+ w_class = WEIGHT_CLASS_NORMAL
+ item_state = "seva"
+ gas_transfer_coefficient = 0.01
+ permeability_coefficient = 0.01
+ flags_cover = MASKCOVERSEYES | MASKCOVERSMOUTH
+ resistance_flags = FIRE_PROOF
+
/****************Exo-Suit and Mask****************/
/obj/item/clothing/suit/hooded/exo
diff --git a/code/modules/mining/equipment/kinetic_crusher.dm b/code/modules/mining/equipment/kinetic_crusher.dm
index 69b1bcaab4..2e695e6772 100644
--- a/code/modules/mining/equipment/kinetic_crusher.dm
+++ b/code/modules/mining/equipment/kinetic_crusher.dm
@@ -73,6 +73,9 @@
/obj/item/twohanded/required/kinetic_crusher/afterattack(atom/target, mob/living/user, proximity_flag, clickparams)
. = ..()
+ if(istype(target, /obj/item/crusher_trophy))
+ var/obj/item/crusher_trophy/T = target
+ T.add_to(src, user)
if(!proximity_flag && charged)//Mark a target, or mine a tile.
var/turf/proj_turf = user.loc
if(!isturf(proj_turf))
diff --git a/code/modules/mining/machine_vending.dm b/code/modules/mining/machine_vending.dm
index 63f7a7e414..64d2eed557 100644
--- a/code/modules/mining/machine_vending.dm
+++ b/code/modules/mining/machine_vending.dm
@@ -310,6 +310,7 @@
new /obj/item/clothing/suit/hooded/exo(drop_location)
if("SEVA suit")
new /obj/item/clothing/suit/hooded/seva(drop_location)
+ new /obj/item/clothing/mask/gas/seva(drop_location)
SSblackbox.record_feedback("tally", "suit_voucher_redeemed", 1, selection)
qdel(voucher)
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm
index 763487f7ed..99615e9543 100644
--- a/code/modules/mob/living/carbon/human/human_defines.dm
+++ b/code/modules/mob/living/carbon/human/human_defines.dm
@@ -53,3 +53,4 @@
var/creamed = FALSE //to use with creampie overlays
var/static/list/can_ride_typecache = typecacheof(list(/mob/living/carbon/human, /mob/living/simple_animal/slime, /mob/living/simple_animal/parrot))
var/lastpuke = 0
+ var/last_fire_update
diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm
index 789a52250c..a50fb4fe79 100644
--- a/code/modules/mob/living/carbon/human/life.dm
+++ b/code/modules/mob/living/carbon/human/life.dm
@@ -122,6 +122,12 @@
///FIRE CODE
/mob/living/carbon/human/handle_fire()
+ if(!last_fire_update)
+ last_fire_update = fire_stacks
+ if((fire_stacks > HUMAN_FIRE_STACK_ICON_NUM && last_fire_update <= HUMAN_FIRE_STACK_ICON_NUM) || (fire_stacks <= HUMAN_FIRE_STACK_ICON_NUM && last_fire_update > HUMAN_FIRE_STACK_ICON_NUM))
+ last_fire_update = fire_stacks
+ update_fire()
+
..()
if(dna)
dna.species.handle_fire(src)
@@ -154,6 +160,7 @@
/mob/living/carbon/human/ExtinguishMob()
if(!dna || !dna.species.ExtinguishMob(src))
+ last_fire_update = null
..()
//END FIRE CODE
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index 6c5f030313..fc3c0cb00e 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -1020,7 +1020,7 @@
client.move_delay = world.time + movement_delay()
lying_prev = lying
if(canmove && !intentionalresting && iscarbon(src) && client && client.prefs && client.prefs.autostand)//CIT CHANGE - adds autostanding as a preference
- resist_a_rest(TRUE)//CIT CHANGE - ditto
+ addtimer(CALLBACK(src, .proc/resist_a_rest, TRUE), 0) //CIT CHANGE - ditto
return canmove
/mob/living/proc/AddAbility(obj/effect/proc_holder/A)
diff --git a/code/modules/reagents/reagent_containers/patch.dm b/code/modules/reagents/reagent_containers/patch.dm
index b11ef878b6..d4111467ba 100644
--- a/code/modules/reagents/reagent_containers/patch.dm
+++ b/code/modules/reagents/reagent_containers/patch.dm
@@ -14,6 +14,8 @@
/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
diff --git a/code/modules/research/designs/medical_designs.dm b/code/modules/research/designs/medical_designs.dm
index 4b28ecd048..ffcb67800f 100644
--- a/code/modules/research/designs/medical_designs.dm
+++ b/code/modules/research/designs/medical_designs.dm
@@ -151,6 +151,16 @@
category = list("Medical Designs")
departmental_flags = DEPARTMENTAL_FLAG_MEDICAL
+/datum/design/holobarrier_med
+ name = "PENLITE holobarrier projector"
+ desc = "PENLITE holobarriers, a device that halts individuals with malicious diseases."
+ build_type = PROTOLATHE
+ build_path = /obj/item/holosign_creator/medical
+ materials = list(MAT_METAL = 500, MAT_GLASS = 500, MAT_SILVER = 100) //a hint of silver since it can troll 2 antags (bad viros and sentient disease)
+ id = "holobarrier_med"
+ category = list("Medical Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_MEDICAL
+
/datum/design/alienscalpel
name = "Alien Scalpel"
desc = "An advanced scalpel obtained through Abductor technology."
@@ -577,12 +587,94 @@
surgery = /datum/surgery/advanced/necrotic_revival
research_icon_state = "surgery_head"
-/datum/design/holobarrier_med
- name = "PENLITE holobarrier projector"
- desc = "PENLITE holobarriers, a device that halts individuals with malicious diseases."
+/////////////////////////////////////////
+////////////Medical Prosthetics//////////
+/////////////////////////////////////////
+
+/datum/design/basic_l_arm
+ name = "Surplus prosthetic left arm"
+ desc = "Basic outdated and fragile prosthetic left arm."
+ id = "basic_l_arm"
build_type = PROTOLATHE
- build_path = /obj/item/holosign_creator/medical
- materials = list(MAT_METAL = 500, MAT_GLASS = 500, MAT_SILVER = 100) //a hint of silver since it can troll 2 antags (bad viros and sentient disease)
- id = "holobarrier_med"
+ materials = list(MAT_METAL = 5000, MAT_GLASS = 2500)
+ construction_time = 20
+ build_path = /obj/item/bodypart/l_arm/robot/surplus
category = list("Medical Designs")
- departmental_flags = DEPARTMENTAL_FLAG_MEDICAL
\ No newline at end of file
+ departmental_flags = DEPARTMENTAL_FLAG_MEDICAL
+
+/datum/design/basic_r_arm
+ name = "Surplus prosthetic right arm"
+ desc = "Basic outdated and fragile prosthetic left arm."
+ id = "basic_r_arm"
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 5000, MAT_GLASS = 2500)
+ construction_time = 20
+ build_path = /obj/item/bodypart/r_arm/robot/surplus
+ category = list("Medical Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_MEDICAL
+
+/datum/design/basic_l_leg
+ name = "Surplus prosthetic left leg"
+ desc = "Basic outdated and fragile prosthetic left leg."
+ id = "basic_l_leg"
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 5000, MAT_GLASS = 2500)
+ construction_time = 20
+ build_path = /obj/item/bodypart/l_leg/robot/surplus
+ category = list("Medical Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_MEDICAL
+
+/datum/design/basic_r_leg
+ name = "Surplus prosthetic right leg"
+ desc = "Basic outdated and fragile prosthetic right leg."
+ id = "basic_r_leg"
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 5000, MAT_GLASS = 2500)
+ construction_time = 20
+ build_path = /obj/item/bodypart/r_leg/robot/surplus
+ category = list("Medical Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_MEDICAL
+
+/datum/design/adv_r_leg
+ name = "Advanced prosthetic right leg"
+ desc = "A renforced prosthetic right leg."
+ id = "adv_r_leg"
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 6000, MAT_GLASS = 3500, MAT_GOLD = 500, MAT_TITANIUM = 800)
+ construction_time = 40
+ build_path = /obj/item/bodypart/r_leg/robot/surplus_upgraded
+ category = list("Medical Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_MEDICAL
+
+/datum/design/adv_l_leg
+ name = "Advanced prosthetic left leg"
+ desc = "A renforced prosthetic left leg."
+ id = "adv_l_leg"
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 6000, MAT_GLASS = 3500, MAT_GOLD = 500, MAT_TITANIUM = 800)
+ construction_time = 40
+ build_path = /obj/item/bodypart/l_leg/robot/surplus_upgraded
+ category = list("Medical Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_MEDICAL
+
+/datum/design/adv_l_arm
+ name = "Advanced prosthetic left arm"
+ desc = "A renforced prosthetic left arm."
+ id = "adv_l_arm"
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 6000, MAT_GLASS = 3500, MAT_GOLD = 500, MAT_TITANIUM = 800)
+ construction_time = 40
+ build_path = /obj/item/bodypart/l_arm/robot/surplus_upgraded
+ category = list("Medical Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_MEDICAL
+
+/datum/design/adv_r_arm
+ name = "Advanced prosthetic right arm"
+ desc = "A renforced prosthetic right arm."
+ id = "adv_r_arm"
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 6000, MAT_GLASS = 3500, MAT_GOLD = 500, MAT_TITANIUM = 800)
+ construction_time = 40
+ build_path = /obj/item/bodypart/r_arm/robot/surplus_upgraded
+ category = list("Medical Designs")
+ departmental_flags = DEPARTMENTAL_FLAG_MEDICAL
diff --git a/code/modules/research/techweb/all_nodes.dm b/code/modules/research/techweb/all_nodes.dm
index 7dcbb6775a..cd01bd1f20 100644
--- a/code/modules/research/techweb/all_nodes.dm
+++ b/code/modules/research/techweb/all_nodes.dm
@@ -71,6 +71,24 @@
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
export_price = 5000
+/datum/techweb_node/surplus_lims
+ id = "surplus_lims"
+ display_name = "Basic Prosthetics"
+ description = "Basic fragile lims for the impaired."
+ prereq_ids = list("biotech")
+ design_ids = list("basic_l_arm", "basic_r_arm", "basic_r_leg", "basic_l_leg")
+ research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 1000) // You can knock them off with a glass shard...
+ export_price = 5000
+
+/datum/techweb_node/advance_lims
+ id = "advance_lims"
+ display_name = "Upgraded Prosthetics"
+ description = "Reinforced prosthetics for the impaired."
+ prereq_ids = list("adv_biotech", "surplus_lims")
+ design_ids = list("adv_l_arm", "adv_r_arm", "adv_r_leg", "adv_l_leg")
+ research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
+ export_price = 5000
+
/////////////////////////Advanced Surgery/////////////////////////
/datum/techweb_node/adv_surgery
id = "adv_surgery"
diff --git a/code/modules/surgery/bodyparts/robot_bodyparts.dm b/code/modules/surgery/bodyparts/robot_bodyparts.dm
index c535ef4a20..ab31d64034 100644
--- a/code/modules/surgery/bodyparts/robot_bodyparts.dm
+++ b/code/modules/surgery/bodyparts/robot_bodyparts.dm
@@ -235,7 +235,7 @@
-
+// Surplus lims
/obj/item/bodypart/l_arm/robot/surplus
name = "surplus prosthetic left arm"
desc = "A skeletal, robotic limb. Outdated and fragile, but it's still better than nothing."
@@ -268,6 +268,38 @@
burn_reduction = 0
max_damage = 20
+// Upgraded Surplus lims
+/obj/item/bodypart/l_arm/robot/surplus_upgraded
+ name = "reinforced surplus prosthetic left arm"
+ desc = "A skeletal, robotic limb. This one is reinforced to provide better protection."
+ icon = 'icons/mob/augmentation/surplus_augments.dmi'
+ brute_reduction = 1
+ burn_reduction = 1
+ max_damage = 30
+
+/obj/item/bodypart/r_arm/robot/surplus_upgraded
+ name = "reinforced surplus prosthetic right arm"
+ desc = "A skeletal, robotic limb. This one is reinforced to provide better protection."
+ icon = 'icons/mob/augmentation/surplus_augments.dmi'
+ brute_reduction = 1
+ burn_reduction = 1
+ max_damage = 30
+
+/obj/item/bodypart/l_leg/robot/surplus_upgraded
+ name = "reinforced surplus prosthetic left leg"
+ desc = "A skeletal, robotic limb. This one is reinforced to provide better protection."
+ icon = 'icons/mob/augmentation/surplus_augments.dmi'
+ brute_reduction = 1
+ burn_reduction = 1
+ max_damage = 30
+
+/obj/item/bodypart/r_leg/robot/surplus_upgraded
+ name = "reinforced surplus prosthetic right leg"
+ desc = "A skeletal, robotic limb. This one is reinforced to provide better protection."
+ icon = 'icons/mob/augmentation/surplus_augments.dmi'
+ brute_reduction = 1
+ burn_reduction = 1
+ max_damage = 30
#undef ROBOTIC_LIGHT_BRUTE_MSG
#undef ROBOTIC_MEDIUM_BRUTE_MSG
diff --git a/dependencies.sh b/dependencies.sh
index 1b61b37c88..644cdd3acc 100644
--- a/dependencies.sh
+++ b/dependencies.sh
@@ -3,11 +3,12 @@
#Project dependencies file
#Final authority on what's required to fully build the project
-#byond version
-#note, this also needs to be changed in the Dockerfile's initial FROM command
-#If someone has an idea for how to set that version within the Dockerfile itself without any other dependencies, feel free to PR it
-export BYOND_MAJOR=512
-export BYOND_MINOR=1448
+# byond version
+# Extracted from the Dockerfile. Change by editing Dockerfile's FROM command.
+LIST=($(sed -n 's/.*byond:\([0-9]\+\)\.\([0-9]\+\).*/\1 \2/p' Dockerfile))
+export BYOND_MAJOR=${LIST[0]}
+export BYOND_MINOR=${LIST[1]}
+unset LIST
#rust_g git tag
export RUST_G_VERSION=0.4.1
diff --git a/html/changelogs/AutoChangeLog-pr-7625.yml b/html/changelogs/AutoChangeLog-pr-7625.yml
new file mode 100644
index 0000000000..a6e72eab8f
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-7625.yml
@@ -0,0 +1,7 @@
+author: "Poojawa"
+delete-after: True
+changes:
+ - refactor: "improved vore sound responsiveness to preference choices."
+ - balance: "removed morphine from Medihound sleeper chemical list"
+ - bugfix: "fixed preference setting being broken"
+ - refactor: "Medihound sleepers are Initialized properly, and icons update correctly now on eject"
diff --git a/html/changelogs/AutoChangeLog-pr-7640.yml b/html/changelogs/AutoChangeLog-pr-7640.yml
new file mode 100644
index 0000000000..7360022b33
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-7640.yml
@@ -0,0 +1,4 @@
+author: "Poojawa"
+delete-after: True
+changes:
+ - balance: "Added sanity checks to emag usage"
diff --git a/html/changelogs/AutoChangeLog-pr-7650.yml b/html/changelogs/AutoChangeLog-pr-7650.yml
new file mode 100644
index 0000000000..ba84b55d33
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-7650.yml
@@ -0,0 +1,4 @@
+author: "deathride58"
+delete-after: True
+changes:
+ - bugfix: "Autostand no longer makes you invulnerable to dropping items when being knocked down with a force greater than 80"
diff --git a/html/changelogs/AutoChangeLog-pr-7652.yml b/html/changelogs/AutoChangeLog-pr-7652.yml
new file mode 100644
index 0000000000..4695db6186
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-7652.yml
@@ -0,0 +1,6 @@
+author: "Toriate"
+delete-after: True
+changes:
+ - imageadd: "All regular crates are now 3/4ths ToriCrates
+iamgeadd: Unused plastic crate sprite added"
+ - rscadd: "Blood freezer crates now have unique sprites."
diff --git a/icons/mob/head.dmi b/icons/mob/head.dmi
index 39726a6ece..45e19bbc39 100644
Binary files a/icons/mob/head.dmi and b/icons/mob/head.dmi differ
diff --git a/icons/mob/mask.dmi b/icons/mob/mask.dmi
index 46b229388d..507f818195 100644
Binary files a/icons/mob/mask.dmi and b/icons/mob/mask.dmi differ
diff --git a/icons/mob/suit.dmi b/icons/mob/suit.dmi
index 4bc07f86f5..fc7c7f9ad0 100644
Binary files a/icons/mob/suit.dmi and b/icons/mob/suit.dmi differ
diff --git a/icons/obj/clothing/hats.dmi b/icons/obj/clothing/hats.dmi
index a9d1398c20..0e5c42c5f7 100644
Binary files a/icons/obj/clothing/hats.dmi and b/icons/obj/clothing/hats.dmi differ
diff --git a/icons/obj/clothing/masks.dmi b/icons/obj/clothing/masks.dmi
index 12dd04004b..fecf761062 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 3737ee694e..d469bbbe22 100644
Binary files a/icons/obj/clothing/suits.dmi and b/icons/obj/clothing/suits.dmi differ
diff --git a/icons/obj/crates.dmi b/icons/obj/crates.dmi
index 508ae18c60..1d7945e3f2 100644
Binary files a/icons/obj/crates.dmi and b/icons/obj/crates.dmi differ
diff --git a/modular_citadel/code/game/objects/ids.dm b/modular_citadel/code/game/objects/ids.dm
index 5d67c18416..89a3c0f0c2 100644
--- a/modular_citadel/code/game/objects/ids.dm
+++ b/modular_citadel/code/game/objects/ids.dm
@@ -81,16 +81,3 @@
to_chat(user, "[ER] has no charges left.")
return
. = ..()
-
-/obj/item/card/emag/afterattack(atom/target, mob/user, proximity)
- if(!uses)
- user.visible_message("[src] emits a weak spark. It's burnt out!")
- playsound(src, 'sound/effects/light_flicker.ogg', 100, 1)
- return
- . = ..()
- uses = max(uses - 1, 0)
- if(!uses)
- user.visible_message("[src] fizzles and sparks. It seems like it's out of charges.")
- playsound(src, 'sound/effects/light_flicker.ogg', 100, 1)
- else if(uses <= 3)
- playsound(src, 'sound/effects/light_flicker.ogg', 30, 1) //Tiiiiiiny warning sound to let ya know your emag's almost dead
diff --git a/modular_citadel/code/modules/admin/chat_commands.dm b/modular_citadel/code/modules/admin/chat_commands.dm
index 9cd25d328c..639077c439 100644
--- a/modular_citadel/code/modules/admin/chat_commands.dm
+++ b/modular_citadel/code/modules/admin/chat_commands.dm
@@ -4,7 +4,7 @@
/datum/tgs_chat_command/wheelofsalt/Run(datum/tgs_chat_user/sender, params)
var/saltresult = "The wheel of salt [pick("clatters","vibrates","clanks","groans","moans","squeaks","emits a[pick(" god-forsaken"," lewd"," creepy"," generic","n orgasmic")] [pick("airhorn","bike horn","trumpet","clown","latex","vore","dog")] noise")] as it spins violently... And it seems the salt of the day is the "
- var/saltprimarysubject = "[pick("combat","medical","grab","furry","wall","orgasm","cat","ERP","lizard","dog","latex","vision cone","atmospherics","table","chem","vore","dogborg","Skylar Lineman","Mekhi Anderson","Peppermint","rework","cum","dick","cockvore")]"
- var/saltsecondarysubject = "[pick("rework","changes","r34","ban","removal","addition","leak","proposal","fanart","introduction","tabling","ERP")]"
+ var/saltprimarysubject = "[pick("combat","medical","grab","furry","wall","orgasm","cat","ERP","lizard","dog","latex","vision cone","atmospherics","table","chem","vore","dogborg","Skylar Lineman","Mekhi Anderson","Peppermint","rework","cum","dick","cockvore","Medihound","sleeper","belly sleeper","door wires","flightsuit","coder privilege","Developer abuse","ban reason","github self merge")]"
+ var/saltsecondarysubject = "[pick("rework","changes","r34","ban","removal","addition","leak","proposal","fanart","introduction","tabling","ERP","bikeshedding","sprites","semen keg","argument")]"
saltresult += "[saltprimarysubject] [saltsecondarysubject]"
return "[saltresult]!"
diff --git a/modular_citadel/code/modules/client/loadout/__donator.dm b/modular_citadel/code/modules/client/loadout/__donator.dm
index 8135532d85..28ff93c05a 100644
--- a/modular_citadel/code/modules/client/loadout/__donator.dm
+++ b/modular_citadel/code/modules/client/loadout/__donator.dm
@@ -331,4 +331,11 @@ datum/gear/darksabresheath
name = "Divine robes"
category = SLOT_W_UNIFORM
path = /obj/item/clothing/under/lunasune
- ckeywhitelist = list("invader4352")
\ No newline at end of file
+ ckeywhitelist = list("invader4352")
+
+/datum/gear/gothcoat
+ name = "Goth Coat"
+ category = SLOT_W_UNIFORM
+ path = /obj/item/clothing/suit/gothcoat
+ ckeywhitelist = list("norko")
+
diff --git a/modular_citadel/code/modules/vore/eating/belly_obj_vr.dm b/modular_citadel/code/modules/vore/eating/belly_obj_vr.dm
index 2ae5308835..1aa8122be5 100644
--- a/modular_citadel/code/modules/vore/eating/belly_obj_vr.dm
+++ b/modular_citadel/code/modules/vore/eating/belly_obj_vr.dm
@@ -48,6 +48,8 @@
var/tmp/list/items_preserved = list() // Stuff that wont digest so we shouldn't process it again.
var/tmp/next_emote = 0 // When we're supposed to print our next emote, as a belly controller tick #
var/tmp/recent_sound = FALSE // Prevent audio spam
+ var/tmp/last_hearcheck = 0
+ var/tmp/list/hearing_mobs
// Don't forget to watch your commas at the end of each line if you change these.
var/list/struggle_messages_outside = list(
@@ -167,7 +169,7 @@
//Sound w/ antispam flag setting
if(!silent && !recent_sound)
for(var/mob/M in get_hearers_in_view(5, get_turf(owner)))
- if(M.client && M.client.prefs.cit_toggles & EATING_NOISES)
+ if(M.client && (M.client.prefs.cit_toggles & EATING_NOISES))
playsound(get_turf(owner),"[src.vore_sound]",50,0,-5,0,ignore_walls = FALSE,channel=CHANNEL_PRED)
recent_sound = TRUE
@@ -200,7 +202,7 @@
AM.forceMove(destination) // Move the belly contents into the same location as belly's owner.
count++
for(var/mob/M in get_hearers_in_view(5, get_turf(owner)))
- if(M.client && M.client.prefs.cit_toggles & EATING_NOISES)
+ if(M.client && (M.client.prefs.cit_toggles & EATING_NOISES))
playsound(get_turf(owner),"[src.release_sound]",50,0,-5,0,ignore_walls = FALSE,channel=CHANNEL_PRED)
if(!silent)
owner.visible_message("[owner] expels everything from their [lowertext(name)]!")
@@ -220,7 +222,7 @@
items_preserved -= M
if(release_sound)
for(var/mob/H in get_hearers_in_view(5, get_turf(owner)))
- if(H.client && H.client.prefs.cit_toggles & EATING_NOISES)
+ if(H.client && (H.client.prefs.cit_toggles & EATING_NOISES))
playsound(get_turf(owner),"[src.release_sound]",50,0,-5,0,ignore_walls = FALSE,channel=CHANNEL_PRED)
if(istype(M,/mob/living))
@@ -296,7 +298,7 @@
target.nom_mob(content, target.owner)
if(!silent)
for(var/mob/M in get_hearers_in_view(5, get_turf(owner)))
- if(M.client && M.client.prefs.cit_toggles & EATING_NOISES)
+ if(M.client && (M.client.prefs.cit_toggles & EATING_NOISES))
playsound(get_turf(owner),"[src.vore_sound]",50,0,-5,0,ignore_walls = FALSE,channel=CHANNEL_PRED)
owner.updateVRPanel()
for(var/mob/living/M in contents)
@@ -510,7 +512,7 @@
if(!silent)
for(var/mob/M in get_hearers_in_view(5, get_turf(owner)))
- if(M.client && M.client.prefs.cit_toggles & EATING_NOISES)
+ if(M.client && (M.client.prefs.cit_toggles & EATING_NOISES))
playsound(get_turf(owner),"struggle_sound",35,0,-5,1,ignore_walls = FALSE,channel=CHANNEL_PRED)
R.stop_sound_channel(CHANNEL_PRED)
var/sound/prey_struggle = sound(get_sfx("prey_struggle"))
diff --git a/modular_citadel/code/modules/vore/eating/bellymodes_vr.dm b/modular_citadel/code/modules/vore/eating/bellymodes_vr.dm
index 8b8781cb02..6c528f75a9 100644
--- a/modular_citadel/code/modules/vore/eating/bellymodes_vr.dm
+++ b/modular_citadel/code/modules/vore/eating/bellymodes_vr.dm
@@ -45,6 +45,9 @@
////////////////////////// Sound vars /////////////////////////////
var/sound/prey_digest = sound(get_sfx("digest_prey"))
var/sound/prey_death = sound(get_sfx("death_prey"))
+ var/sound/pred_digest = sound(get_sfx("digest_pred"))
+ var/sound/pred_death = sound(get_sfx("death_pred"))
+ var/turf/source = get_turf(owner)
///////////////////////////// DM_HOLD /////////////////////////////
@@ -55,12 +58,18 @@
else if(digest_mode == DM_DIGEST)
for (var/mob/living/M in contents)
if(prob(25))
- M.stop_sound_channel(CHANNEL_DIGEST)
- for(var/mob/H in get_hearers_in_view(5, get_turf(owner)))
- if(H.client && H.client.prefs.cit_toggles & DIGESTION_NOISES)
- playsound(get_turf(owner),"digest_pred",50,0,-5,0,ignore_walls = FALSE,channel=CHANNEL_DIGEST)
- M.stop_sound_channel(CHANNEL_DIGEST)
- M.playsound_local(get_turf(M), prey_digest, 45)
+ if((world.time - NORMIE_HEARCHECK) > last_hearcheck)
+ LAZYCLEARLIST(hearing_mobs)
+ for(var/mob/H in get_hearers_in_view(3, source))
+ if(!H.client || !(H.client.prefs.cit_toggles & DIGESTION_NOISES))
+ continue
+ LAZYADD(hearing_mobs, H)
+ last_hearcheck = world.time
+ for(var/mob/H in hearing_mobs)
+ if(!isbelly(H.loc))
+ H.playsound_local(source, null, 45, falloff = 0, S = pred_digest)
+ else if(H in contents)
+ H.playsound_local(source, null, 65, falloff = 0, S = prey_digest)
//Pref protection!
if (!M.digestable || M.absorbed)
@@ -86,13 +95,19 @@
M.visible_message("You watch as [owner]'s form loses its additions.")
owner.nutrition += 400 // so eating dead mobs gives you *something*.
- M.stop_sound_channel(DIGESTION_NOISES)
- for(var/mob/H in get_hearers_in_view(5, get_turf(owner)))
- if(H.client && H.client.prefs.cit_toggles & DIGESTION_NOISES)
- playsound(get_turf(owner),"death_pred",50,0,-5,0,ignore_walls = FALSE,channel=CHANNEL_DIGEST)
- M.stop_sound_channel(DIGESTION_NOISES)
+ if((world.time - NORMIE_HEARCHECK) > last_hearcheck)
+ LAZYCLEARLIST(hearing_mobs)
+ for(var/mob/H in get_hearers_in_view(3, source))
+ if(!H.client || !(H.client.prefs.cit_toggles & DIGESTION_NOISES))
+ continue
+ LAZYADD(hearing_mobs, H)
+ last_hearcheck = world.time
+ for(var/mob/H in hearing_mobs)
+ if(!isbelly(H.loc))
+ H.playsound_local(source, null, 45, falloff = 0, S = pred_death)
+ else if(H in contents)
+ H.playsound_local(source, null, 65, falloff = 0, S = prey_death)
M.stop_sound_channel(CHANNEL_PREYLOOP)
- M.playsound_local(get_turf(M), prey_death, 65)
digestion_death(M)
owner.update_icons()
continue
@@ -115,12 +130,18 @@
if(digest_mode == DM_HEAL)
for (var/mob/living/M in contents)
if(prob(25))
- M.stop_sound_channel(CHANNEL_DIGEST)
- for(var/mob/H in get_hearers_in_view(5, get_turf(owner)))
- if(H.client && H.client.prefs.cit_toggles & DIGESTION_NOISES)
- playsound(get_turf(owner),"digest_pred",50,0,-5,0,ignore_walls = FALSE,channel=CHANNEL_DIGEST)
- M.stop_sound_channel(CHANNEL_DIGEST)
- M.playsound_local(get_turf(M), prey_digest, 65)
+ if((world.time - NORMIE_HEARCHECK) > last_hearcheck)
+ LAZYCLEARLIST(hearing_mobs)
+ for(var/mob/H in get_hearers_in_view(3, source))
+ if(!H.client || !(H.client.prefs.cit_toggles & DIGESTION_NOISES))
+ continue
+ LAZYADD(hearing_mobs, H)
+ last_hearcheck = world.time
+ for(var/mob/H in hearing_mobs)
+ if(!isbelly(H.loc))
+ H.playsound_local(source, null, 45, falloff = 0, S = pred_digest)
+ else if(H in contents)
+ H.playsound_local(source, null, 65, falloff = 0, S = prey_digest)
if(M.stat != DEAD)
if(owner.nutrition >= NUTRITION_LEVEL_STARVING && (M.health < M.maxHealth))
@@ -132,14 +153,19 @@
////////////////////////// DM_NOISY /////////////////////////////////
//for when you just want people to squelch around
if(digest_mode == DM_NOISY)
- for (var/mob/living/M in contents)
- if(prob(35))
- M.stop_sound_channel(CHANNEL_DIGEST)
- for(var/mob/H in get_hearers_in_view(5, get_turf(owner)))
- if(H.client && H.client.prefs.cit_toggles & DIGESTION_NOISES)
- playsound(get_turf(owner),"digest_pred",50,0,-5,0,ignore_walls = FALSE,channel=CHANNEL_DIGEST)
- M.stop_sound_channel(CHANNEL_PRED)
- M.playsound_local(get_turf(M), prey_digest, 65)
+ if(prob(35))
+ if((world.time - NORMIE_HEARCHECK) > last_hearcheck)
+ LAZYCLEARLIST(hearing_mobs)
+ for(var/mob/H in get_hearers_in_view(3, source))
+ if(!H.client || !(H.client.prefs.cit_toggles & DIGESTION_NOISES))
+ continue
+ LAZYADD(hearing_mobs, H)
+ last_hearcheck = world.time
+ for(var/mob/H in hearing_mobs)
+ if(!isbelly(H.loc))
+ H.playsound_local(source, null, 45, falloff = 0, S = pred_digest)
+ else if(H in contents)
+ H.playsound_local(source, null, 65, falloff = 0, S = prey_digest)
//////////////////////////// DM_ABSORB ////////////////////////////
@@ -147,13 +173,19 @@
for (var/mob/living/M in contents)
- if(prob(10)) //Less often than gurgles. People might leave this on forever.
- M.stop_sound_channel(CHANNEL_DIGEST)
- for(var/mob/H in get_hearers_in_view(5, get_turf(owner)))
- if(H.client && H.client.prefs.toggles & DIGESTION_NOISES)
- playsound(get_turf(owner),"digest_pred",50,0,-5,0,ignore_walls = FALSE,channel=CHANNEL_DIGEST)
- M.stop_sound_channel(CHANNEL_PRED)
- M.playsound_local(get_turf(M), prey_digest, 65)
+ if(prob(10))//Less often than gurgles. People might leave this on forever.
+ if((world.time - NORMIE_HEARCHECK) > last_hearcheck)
+ LAZYCLEARLIST(hearing_mobs)
+ for(var/mob/H in get_hearers_in_view(3, source))
+ if(!H.client || !(H.client.prefs.cit_toggles & DIGESTION_NOISES))
+ continue
+ LAZYADD(hearing_mobs, H)
+ last_hearcheck = world.time
+ for(var/mob/H in hearing_mobs)
+ if(!isbelly(H.loc))
+ H.playsound_local(source, null, 45, falloff = 0, S = pred_digest)
+ else if(H in contents)
+ H.playsound_local(source, null, 65, falloff = 0, S = prey_digest)
if(M.absorbed)
continue
@@ -180,12 +212,18 @@
if(digest_mode == DM_DRAGON)
for (var/mob/living/M in contents)
if(prob(55)) //if you're hearing this, you're a vore ho anyway.
- M.stop_sound_channel(CHANNEL_DIGEST)
- for(var/mob/H in get_hearers_in_view(5, get_turf(owner)))
- if(H.client && H.client.prefs.cit_toggles & DIGESTION_NOISES)
- playsound(get_turf(owner),"digest_pred",50,0,-5,0,ignore_walls = FALSE,channel=CHANNEL_DIGEST)
- M.stop_sound_channel(CHANNEL_DIGEST)
- M.playsound_local(get_turf(M), prey_digest, 65)
+ if((world.time - NORMIE_HEARCHECK) > last_hearcheck)
+ LAZYCLEARLIST(hearing_mobs)
+ for(var/mob/H in get_hearers_in_view(3, source))
+ if(!H.client || !(H.client.prefs.cit_toggles & DIGESTION_NOISES))
+ continue
+ LAZYADD(hearing_mobs, H)
+ last_hearcheck = world.time
+ for(var/mob/H in hearing_mobs)
+ if(!isbelly(H.loc))
+ H.playsound_local(source, null, 45, falloff = 0, S = pred_digest)
+ else if(H in contents)
+ H.playsound_local(source, null, 65, falloff = 0, S = prey_digest)
//No digestion protection for megafauna.
@@ -207,13 +245,18 @@
to_chat(owner, "[digest_alert_owner]")
to_chat(M, "[digest_alert_prey]")
M.visible_message("You watch as [owner]'s guts loudly rumble as it finishes off a meal.")
-
- M.stop_sound_channel(CHANNEL_DIGEST)
- for(var/mob/H in get_hearers_in_view(5, get_turf(owner)))
- if(H.client && H.client.prefs.cit_toggles & DIGESTION_NOISES)
- playsound(get_turf(owner),"death_pred",50,0,-5,0,ignore_walls = FALSE,channel=CHANNEL_DIGEST)
- M.stop_sound_channel(CHANNEL_DIGEST)
- M.playsound_local(get_turf(M), prey_death, 65)
+ if((world.time - NORMIE_HEARCHECK) > last_hearcheck)
+ LAZYCLEARLIST(hearing_mobs)
+ for(var/mob/H in get_hearers_in_view(3, source))
+ if(!H.client || !(H.client.prefs.cit_toggles & DIGESTION_NOISES))
+ continue
+ LAZYADD(hearing_mobs, H)
+ last_hearcheck = world.time
+ for(var/mob/H in hearing_mobs)
+ if(!isbelly(H.loc))
+ H.playsound_local(source, null, 45, falloff = 0, S = pred_death)
+ else if(H in contents)
+ H.playsound_local(source, null, 65, falloff = 0, S = prey_death)
M.spill_organs(FALSE,TRUE,TRUE)
M.stop_sound_channel(CHANNEL_PREYLOOP)
digestion_death(M)
diff --git a/modular_citadel/icons/mob/digishoes.dmi b/modular_citadel/icons/mob/digishoes.dmi
index 49988f88f6..a499db6262 100644
Binary files a/modular_citadel/icons/mob/digishoes.dmi and b/modular_citadel/icons/mob/digishoes.dmi differ
diff --git a/modular_citadel/icons/mob/mam_ears.dmi b/modular_citadel/icons/mob/mam_ears.dmi
index 270ecc11de..51ffd28bbc 100644
Binary files a/modular_citadel/icons/mob/mam_ears.dmi and b/modular_citadel/icons/mob/mam_ears.dmi differ
diff --git a/modular_citadel/icons/mob/suit_digi.dmi b/modular_citadel/icons/mob/suit_digi.dmi
index 9fe7a447aa..abaa0d1a42 100644
Binary files a/modular_citadel/icons/mob/suit_digi.dmi and b/modular_citadel/icons/mob/suit_digi.dmi differ
diff --git a/strings/phobia.json b/strings/phobia.json
index 3be9794bf9..3f56751333 100644
--- a/strings/phobia.json
+++ b/strings/phobia.json
@@ -268,5 +268,33 @@
"let go",
"i'll catch you",
"slip"
+ ],
+
+"anime": [
+ "anime",
+ "manga",
+ "baka",
+ "desu",
+ "sugoi",
+ "katana",
+ "weeb",
+ "otaku",
+ "catgirl",
+ "catgirls",
+ "ninja",
+ "uguu",
+ "waifu",
+ "husbando",
+ "best girl",
+ "worst girl",
+ "subs",
+ "dubs",
+ "season two when",
+ "cosplay",
+ "nya",
+ "nyaa",
+ "neet",
+ "ora",
+ "~"
]
-}
+}
\ No newline at end of file
diff --git a/tools/mapmerge2/dmm.py b/tools/mapmerge2/dmm.py
index 421ffb4cd1..1c1f907171 100644
--- a/tools/mapmerge2/dmm.py
+++ b/tools/mapmerge2/dmm.py
@@ -370,7 +370,7 @@ def _parse(map_raw_text):
continue
elif in_comment_line:
continue
- elif char == "\t":
+ elif char in "\r\t":
continue
if char == "/" and not in_quote_block:
@@ -478,6 +478,9 @@ def _parse(map_raw_text):
# grid block
for char in it:
+ if char == "\r":
+ continue
+
if in_coord_block:
if char == ",":
if reading_coord == "x":