diff --git a/code/__DEFINES/dcs/signals/atom/signals_obj.dm b/code/__DEFINES/dcs/signals/atom/signals_obj.dm
index df53558834f6..aebd0d09d0d2 100644
--- a/code/__DEFINES/dcs/signals/atom/signals_obj.dm
+++ b/code/__DEFINES/dcs/signals/atom/signals_obj.dm
@@ -4,6 +4,8 @@
/// From /obj/effect/alien/weeds/Initialize()
#define COMSIG_WEEDNODE_GROWTH_COMPLETE "weednode_growth_complete"
+/// From /obj/effect/alien/weeds/Initialize()
+#define COMSIG_WEEDNODE_GROWTH "weednode_growth"
/// From /obj/effect/alien/weeds/proc/on_weed_expand()
#define COMSIG_WEEDNODE_CANNOT_EXPAND_FURTHER "weednode_cannot_expand_further"
@@ -24,3 +26,6 @@
#define COMSIG_TRANSMITTER_UPDATE_ICON "transmitter_update_icon"
#define COMSIG_TENT_COLLAPSING "tent_collapsing"
+
+/// from /obj/proc/afterbuckle()
+#define COSMIG_OBJ_AFTER_BUCKLE "signal_obj_after_buckle"
diff --git a/code/__DEFINES/tgui.dm b/code/__DEFINES/tgui.dm
index 865088ee72fc..ca6408961eab 100644
--- a/code/__DEFINES/tgui.dm
+++ b/code/__DEFINES/tgui.dm
@@ -32,7 +32,7 @@
/// Creates a message packet for sending via output()
// This is {"type":type,"payload":payload}, but pre-encoded. This is much faster
// than doing it the normal way.
-// To ensure this is correct, this is unit tested in tgui_create_message. However, CM does not have unit tests available.
+// To ensure this is correct, this is unit tested in tgui_create_message.
#define TGUI_CREATE_MESSAGE(type, payload) ( \
"%7b%22type%22%3a%22[type]%22%2c%22payload%22%3a[url_encode(json_encode(payload))]%7d" \
)
diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm
index dd700ccde996..4897a04fea82 100644
--- a/code/__DEFINES/traits.dm
+++ b/code/__DEFINES/traits.dm
@@ -123,7 +123,7 @@
#define TRAIT_SUPER_STRONG "t_super_strong"
/// Foreign biology. Basic medHUDs won't show the mob. (Yautja, Zombies)
#define TRAIT_FOREIGN_BIO "t_foreign_bio"
-/// Eye color changes on intent. (G1 Synths)
+/// Eye color changes on intent. (G1 Synths and WJs)
#define TRAIT_INTENT_EYES "t_intent_eyes"
/// Masked synthetic biology. Basic medHUDs will percieve the mob as human. (Infiltrator Synths)
#define TRAIT_INFILTRATOR_SYNTH "t_infiltrator_synth"
@@ -157,6 +157,8 @@
#define TRAIT_LEADERSHIP "t_leadership"
/// If the mob can see the reagents contents of stuff
#define TRAIT_REAGENT_SCANNER "reagent_scanner"
+/// If the mob cannot eat/be fed
+#define TRAIT_CANNOT_EAT "t_cannot_eat"
/// If the mob is being lazed by a sniper spotter
#define TRAIT_SPOTTER_LAZED "t_spotter_lazed"
/// If the mob has ear protection. Protects from external ear damage effects. Includes explosions, firing the RPG, screeching DEAFNESS only, and flashbangs.
@@ -261,6 +263,7 @@ GLOBAL_LIST_INIT(traits_by_type, list(
"TRAIT_BIMEX" = TRAIT_BIMEX,
"TRAIT_EMOTE_CD_EXEMPT" = TRAIT_EMOTE_CD_EXEMPT,
"TRAIT_LISPING" = TRAIT_LISPING,
+ "TRAIT_CANNOT_EAT" = TRAIT_CANNOT_EAT,
),
/mob/living/carbon/xenomorph = list(
"TRAIT_ABILITY_NO_PLASMA_TRANSFER" = TRAIT_ABILITY_NO_PLASMA_TRANSFER,
diff --git a/code/__DEFINES/wj_emotes.dm b/code/__DEFINES/wj_emotes.dm
new file mode 100644
index 000000000000..f315c6eb2ba5
--- /dev/null
+++ b/code/__DEFINES/wj_emotes.dm
@@ -0,0 +1,8 @@
+#define JOE_EMOTE_CATEGORY_GREETING "Greeting"
+#define JOE_EMOTE_CATEGORY_TASK_UPDATE "Task Update"
+#define JOE_EMOTE_CATEGORY_RESTRICTED_AREA "Restricted Area"
+#define JOE_EMOTE_CATEGORY_FAREWELL "Farewell"
+#define JOE_EMOTE_CATEGORY_QUIP "Quip"
+#define JOE_EMOTE_CATEGORY_WARNING "Warning"
+#define JOE_EMOTE_CATEGORY_QUESTION "Question"
+#define JOE_EMOTE_CATEGORY_NOTICE "Notice"
diff --git a/code/datums/components/footstep.dm b/code/datums/components/footstep.dm
index 970ab89d961e..0d218ba94da4 100644
--- a/code/datums/components/footstep.dm
+++ b/code/datums/components/footstep.dm
@@ -31,7 +31,7 @@
return
var/mob/living/LM = parent
- if(LM.buckled || LM.throwing || LM.is_ventcrawling)
+ if(LM.buckled || LM.throwing || LM.is_ventcrawling || LM.stat == DEAD)
return
if(LM.life_steps_total % steps)
diff --git a/code/datums/components/weed_food.dm b/code/datums/components/weed_food.dm
new file mode 100644
index 000000000000..0c578b661517
--- /dev/null
+++ b/code/datums/components/weed_food.dm
@@ -0,0 +1,297 @@
+#define WEED_FOOD_DELAY 5 MINUTES
+#define WEED_FOOD_STATE_DELAY 1 MINUTES
+
+/atom/movable/vis_obj/weed_food
+ name = "weeds"
+ desc = "Weird black weeds in the shape of a body..."
+ gender = PLURAL
+ vis_flags = VIS_INHERIT_DIR|VIS_INHERIT_PLANE|VIS_INHERIT_LAYER
+ icon = 'icons/mob/xenos/weeds.dmi'
+ var/static/list/icon_states = list("human_1","human_2","human_3","human_4","human_5")
+ var/static/list/icon_states_flipped = list("human_1_f","human_2_f","human_3_f","human_4_f","human_5_f")
+ var/icon_state_idx = 0
+ var/timer_id = null
+ var/flipped = FALSE
+
+/atom/movable/vis_obj/weed_food/Initialize(mapload, is_flipped, ...)
+ flipped = is_flipped
+ timer_id = addtimer(CALLBACK(src, PROC_REF(on_animation_timer)), WEED_FOOD_STATE_DELAY, TIMER_STOPPABLE|TIMER_UNIQUE|TIMER_LOOP|TIMER_DELETE_ME)
+ on_animation_timer()
+ return ..()
+
+/// Timer callback for changing the icon_state
+/atom/movable/vis_obj/weed_food/proc/on_animation_timer()
+ icon_state_idx++
+ if(icon_state_idx > length(icon_states))
+ deltimer(timer_id)
+ timer_id = null
+ return
+ icon_state = flipped ? icon_states_flipped[icon_state_idx] : icon_states[icon_state_idx]
+
+/**
+ * A component that can be attached to a mob/living to be merged with weeds after a delay.
+ * Attempting to attach a new weed_food even if one already exists is equivalent to calling start().
+ *
+ * Attach this to any mob/living that is dead (death or initialized dead) and it should handle the rest.
+ */
+/datum/component/weed_food
+ dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS
+ /// Whether we are waiting on timer to merge
+ var/active = FALSE
+ /// Whether we are merged with weeds
+ var/merged = FALSE
+ /// The time we were unmerged (just to handle weeds upgrading)
+ var/unmerged_time
+ /// Any active timer for a pending merge
+ var/timer_id = null
+ /// The living mob that we are bound to
+ var/mob/living/parent_mob
+ /// The turf that our parent is on
+ var/turf/parent_turf
+ /// The obj that our parent is buckled to and we have registered a signal
+ var/obj/parent_buckle
+ /// The weeds that we are merging/merged with
+ var/obj/effect/alien/weeds/absorbing_weeds
+ /// The overlay image when merged
+ var/atom/movable/vis_obj/weed_food/weed_appearance
+
+/datum/component/weed_food/Initialize(...)
+ parent_mob = parent
+ //if(!istype(parent_mob))
+ //return COMPONENT_INCOMPATIBLE
+ if(!istype(parent_mob, /mob/living/carbon/human))
+ return COMPONENT_INCOMPATIBLE // TODO: At the moment we only support humans
+
+ parent_turf = get_turf(parent_mob)
+ if(parent_turf != parent_mob.loc)
+ parent_turf = null // if our location is actually a container, we want to be safe from weeds
+
+ start()
+
+/datum/component/weed_food/InheritComponent(datum/component/C, i_am_original)
+ start()
+
+/datum/component/weed_food/Destroy(force, silent)
+ . = ..()
+
+ unmerge_with_weeds()
+ QDEL_NULL(weed_appearance)
+ parent_mob = null
+ parent_turf = null
+
+/datum/component/weed_food/RegisterWithParent()
+ RegisterSignal(parent_mob, COMSIG_MOVABLE_MOVED, PROC_REF(on_move))
+ RegisterSignal(parent_mob, list(COMSIG_LIVING_REJUVENATED, COMSIG_HUMAN_REVIVED), PROC_REF(on_rejuv))
+ RegisterSignal(parent_mob, COMSIG_HUMAN_SET_UNDEFIBBABLE, PROC_REF(on_update))
+ if(parent_turf)
+ RegisterSignal(parent_turf, COMSIG_WEEDNODE_GROWTH, PROC_REF(on_update))
+
+/datum/component/weed_food/UnregisterFromParent()
+ if(parent_mob)
+ UnregisterSignal(parent_mob, list(
+ COMSIG_MOVABLE_MOVED,
+ COMSIG_LIVING_REJUVENATED,
+ COMSIG_HUMAN_REVIVED,
+ COMSIG_HUMAN_SET_UNDEFIBBABLE,
+ ))
+ if(absorbing_weeds)
+ UnregisterSignal(absorbing_weeds, COMSIG_PARENT_QDELETING)
+ if(parent_turf)
+ UnregisterSignal(parent_turf, COMSIG_WEEDNODE_GROWTH)
+ if(parent_buckle)
+ UnregisterSignal(parent_buckle, COSMIG_OBJ_AFTER_BUCKLE)
+
+/// SIGNAL_HANDLER for COMSIG_MOVABLE_MOVED
+/datum/component/weed_food/proc/on_move()
+ SIGNAL_HANDLER
+
+ if(absorbing_weeds)
+ UnregisterSignal(absorbing_weeds, COMSIG_PARENT_QDELETING)
+ absorbing_weeds = null
+
+ if(parent_turf)
+ UnregisterSignal(parent_turf, COMSIG_WEEDNODE_GROWTH)
+ parent_turf = get_turf(parent_mob)
+ if(parent_turf != parent_mob.loc)
+ parent_turf = null // if our location is actually a container, we want to be safe from weeds
+ else
+ RegisterSignal(parent_turf, COMSIG_WEEDNODE_GROWTH, PROC_REF(on_update))
+
+ // We moved, restart or start the proccess
+ if(stop() || !merged)
+ start()
+ return
+
+ // If we somehow moved when we were merged, handle that
+ absorbing_weeds = parent_turf?.weeds
+ if(absorbing_weeds)
+ RegisterSignal(absorbing_weeds, COMSIG_PARENT_QDELETING, PROC_REF(on_weed_deletion))
+ return
+ unmerge_with_weeds()
+
+/// SIGNAL_HANDLER for COMSIG_LIVING_REJUVENATED and COMSIG_HUMAN_REVIVED
+/datum/component/weed_food/proc/on_rejuv()
+ SIGNAL_HANDLER
+
+ qdel(src)
+
+/// SIGNAL_HANDLER for COSMIG_OBJ_AFTER_BUCKLE
+/datum/component/weed_food/proc/on_after_buckle(obj/source, mob/buckled)
+ SIGNAL_HANDLER
+
+ if(buckled)
+ return
+ start() // We unbuckled, so lets try to start again
+
+/// SIGNAL_HANDLER for COMSIG_HUMAN_SET_UNDEFIBBABLE & COMSIG_WEEDNODE_GROWTH
+/datum/component/weed_food/proc/on_update()
+ SIGNAL_HANDLER
+
+ start()
+
+/// SIGNAL_HANDLER for COMSIG_PARENT_QDELETING of weeds
+/datum/component/weed_food/proc/on_weed_deletion()
+ SIGNAL_HANDLER
+
+ if(active)
+ stop()
+ return
+ if(merged)
+ unmerge_with_weeds()
+ return
+
+/**
+ * Try to start the process to turn into weeds
+ * Returns TRUE if started successfully
+ */
+/datum/component/weed_food/proc/start()
+ if(active)
+ return FALSE
+ if(merged)
+ return FALSE
+ if(QDELETED(parent_mob))
+ return FALSE
+
+ if(parent_mob.buckled)
+ if(parent_mob.buckled == parent_buckle)
+ return FALSE // Still buckled to the same thing
+ if(!istype(parent_mob.buckled, /obj/structure/bed/nest))
+ if(parent_buckle) // Still have a lingering reference somehow?
+ UnregisterSignal(parent_buckle, COSMIG_OBJ_AFTER_BUCKLE)
+ parent_buckle = parent_mob.buckled
+ RegisterSignal(parent_mob.buckled, COSMIG_OBJ_AFTER_BUCKLE, PROC_REF(on_after_buckle))
+ return FALSE
+ if(parent_buckle)
+ UnregisterSignal(parent_buckle, COSMIG_OBJ_AFTER_BUCKLE)
+ parent_buckle = null
+
+ if(parent_mob.is_xeno_grabbable())
+ return FALSE
+ if(!(parent_mob.status_flags & PERMANENTLY_DEAD))
+ var/mob/living/carbon/human/parent_human = parent_mob
+ if(istype(parent_human) && !parent_human.undefibbable)
+ return FALSE
+ if(!parent_turf?.weeds)
+ return FALSE
+
+ if(unmerged_time == world.time)
+ return merge_with_weeds() // Weeds upgraded, re-merge now re-using the apperance
+ QDEL_NULL(weed_appearance)
+ absorbing_weeds = parent_turf.weeds
+ RegisterSignal(parent_turf.weeds, COMSIG_PARENT_QDELETING, PROC_REF(on_weed_deletion))
+
+ active = TRUE
+ timer_id = addtimer(CALLBACK(src, PROC_REF(merge_with_weeds)), WEED_FOOD_DELAY, TIMER_STOPPABLE|TIMER_UNIQUE|TIMER_DELETE_ME|TIMER_OVERRIDE)
+
+ return TRUE
+
+/**
+ * Try to stop the process turning into weeds
+ * Returns TRUE if stopped successfully (was active when called)
+ */
+/datum/component/weed_food/proc/stop()
+ if(!active)
+ return FALSE
+
+ active = FALSE
+ deltimer(timer_id)
+ timer_id = null
+
+ return TRUE
+
+/**
+ * Finish becomming one with the weeds
+ * Returns TRUE if merged successfully
+ */
+/datum/component/weed_food/proc/merge_with_weeds()
+ if(merged)
+ return FALSE
+ if(QDELETED(parent_mob))
+ return FALSE
+
+ if(absorbing_weeds) // Remove the signal that would call stop
+ UnregisterSignal(absorbing_weeds, COMSIG_PARENT_QDELETING)
+
+ if(parent_mob.buckled)
+ if(parent_mob.buckled == parent_buckle)
+ return FALSE // Still buckled to the same thing somehow?
+ if(!istype(parent_mob.buckled, /obj/structure/bed/nest))
+ if(parent_buckle) // Still have a lingering reference somehow?
+ UnregisterSignal(parent_buckle, COSMIG_OBJ_AFTER_BUCKLE)
+ parent_buckle = parent_mob.buckled
+ RegisterSignal(parent_mob.buckled, COSMIG_OBJ_AFTER_BUCKLE, PROC_REF(on_after_buckle))
+ return FALSE
+ if(parent_buckle)
+ UnregisterSignal(parent_buckle, COSMIG_OBJ_AFTER_BUCKLE)
+ parent_buckle = null
+
+ absorbing_weeds = parent_turf?.weeds
+ if(!absorbing_weeds)
+ return FALSE
+ RegisterSignal(absorbing_weeds, COMSIG_PARENT_QDELETING, PROC_REF(on_weed_deletion))
+ // Technically we could have just left the signal alone, but both because of the posibility of other conditions preventing a merge or weeds somehow changing and on_move didn't catch it, this is less fragile
+
+ active = FALSE
+ merged = TRUE
+
+ parent_mob.density = FALSE
+ parent_mob.anchored = TRUE
+ parent_mob.mouse_opacity = MOUSE_OPACITY_TRANSPARENT
+ parent_mob.plane = FLOOR_PLANE
+ parent_mob.remove_from_all_mob_huds()
+
+ if(!weed_appearance) // Make a new sprite if we aren't re-merging
+ var/is_flipped = parent_mob.transform.b == -1 // Technically we should check if d is 1 too, but corpses can only be rotated 90 or 270 (1/-1 or -1/1)
+ if(parent_mob.dir & WEST)
+ is_flipped = !is_flipped // The direction reversed the effect of the flip!
+ weed_appearance = new(null, is_flipped)
+ weed_appearance.color = absorbing_weeds.color
+ // TODO: For non-humans change the icon_state or something here
+ parent_mob.vis_contents += weed_appearance
+
+ return TRUE
+
+/**
+ * Undo the weedening
+ * Returns TRUE if unmerged successfully (always)
+ */
+/datum/component/weed_food/proc/unmerge_with_weeds()
+ merged = FALSE
+ unmerged_time = world.time
+
+ if(absorbing_weeds)
+ UnregisterSignal(absorbing_weeds, COMSIG_PARENT_QDELETING)
+ absorbing_weeds = null
+
+ parent_mob.anchored = FALSE
+ parent_mob.mouse_opacity = MOUSE_OPACITY_ICON
+ parent_mob.plane = GAME_PLANE
+ parent_mob.vis_contents -= weed_appearance
+
+ if(!QDELETED(parent_mob))
+ parent_mob.add_to_all_mob_huds()
+
+ return TRUE
+
+#undef WEED_FOOD_DELAY
+#undef WEED_FOOD_STATE_DELAY
diff --git a/code/datums/skills.dm b/code/datums/skills.dm
index ef86b726a3c1..16a2a20a57fd 100644
--- a/code/datums/skills.dm
+++ b/code/datums/skills.dm
@@ -851,7 +851,7 @@ SYNTHETIC
/datum/skills/colonial_synthetic
name = SYNTH_COLONY
skills = list(
- SKILL_CQC = SKILL_CQC_SKILLED,
+ SKILL_CQC = SKILL_CQC_EXPERT,
SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
@@ -862,7 +862,7 @@ SYNTHETIC
SKILL_MELEE_WEAPONS = SKILL_MELEE_SUPER,
SKILL_PILOT = SKILL_PILOT_EXPERT,
SKILL_POLICE = SKILL_POLICE_SKILLED,
- SKILL_FIREMAN = SKILL_FIREMAN_TRAINED,
+ SKILL_FIREMAN = SKILL_FIREMAN_EXPERT,
SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER,
SKILL_VEHICLE = SKILL_VEHICLE_LARGE,
SKILL_JTAC = SKILL_JTAC_BEGINNER,
diff --git a/code/game/machinery/autolathe.dm b/code/game/machinery/autolathe.dm
index 7a10a3ffa1df..6ccb0b5b18f7 100644
--- a/code/game/machinery/autolathe.dm
+++ b/code/game/machinery/autolathe.dm
@@ -284,7 +284,7 @@
return
//Dismantle the frame.
- if(istype(O, /obj/item/tool/crowbar))
+ if(HAS_TRAIT(O, TRAIT_TOOL_CROWBAR))
dismantle()
return
diff --git a/code/game/machinery/computer/ai_core.dm b/code/game/machinery/computer/ai_core.dm
index fd246d2d640a..bb6972a58ac3 100644
--- a/code/game/machinery/computer/ai_core.dm
+++ b/code/game/machinery/computer/ai_core.dm
@@ -51,7 +51,7 @@
to_chat(user, SPAN_NOTICE(" You screw the circuit board into place."))
state = 2
icon_state = "2"
- if(istype(P, /obj/item/tool/crowbar) && circuit)
+ if(HAS_TRAIT(P, TRAIT_TOOL_CROWBAR) && circuit)
playsound(loc, 'sound/items/Crowbar.ogg', 25, 1)
to_chat(user, SPAN_NOTICE(" You remove the circuit board."))
state = 1
@@ -121,7 +121,7 @@
to_chat(usr, "Added [mmi].")
icon_state = "3b"
- if(istype(P, /obj/item/tool/crowbar) && brain)
+ if(HAS_TRAIT(P, TRAIT_TOOL_CROWBAR) && brain)
playsound(loc, 'sound/items/Crowbar.ogg', 25, 1)
to_chat(user, SPAN_NOTICE(" You remove the brain."))
brain.forceMove(loc)
@@ -129,7 +129,7 @@
icon_state = "3"
if(4)
- if(istype(P, /obj/item/tool/crowbar))
+ if(HAS_TRAIT(P, TRAIT_TOOL_CROWBAR))
playsound(loc, 'sound/items/Crowbar.ogg', 25, 1)
to_chat(user, SPAN_NOTICE(" You remove the glass panel."))
state = 3
diff --git a/code/game/machinery/computer/buildandrepair.dm b/code/game/machinery/computer/buildandrepair.dm
index bd42b31ea573..07c960807205 100644
--- a/code/game/machinery/computer/buildandrepair.dm
+++ b/code/game/machinery/computer/buildandrepair.dm
@@ -52,7 +52,7 @@
to_chat(user, SPAN_NOTICE(" You screw the circuit board into place."))
src.state = 2
src.icon_state = "2"
- if(istype(P, /obj/item/tool/crowbar) && circuit)
+ if(HAS_TRAIT(P, TRAIT_TOOL_CROWBAR) && circuit)
playsound(src.loc, 'sound/items/Crowbar.ogg', 25, 1)
to_chat(user, SPAN_NOTICE(" You remove the circuit board."))
src.state = 1
@@ -99,7 +99,7 @@
src.state = 4
src.icon_state = "4"
if(4)
- if(istype(P, /obj/item/tool/crowbar))
+ if(HAS_TRAIT(P, TRAIT_TOOL_CROWBAR))
playsound(src.loc, 'sound/items/Crowbar.ogg', 25, 1)
to_chat(user, SPAN_NOTICE(" You remove the glass panel."))
src.state = 3
diff --git a/code/game/machinery/constructable_frame.dm b/code/game/machinery/constructable_frame.dm
index 0288b7eb2426..357ef48fff37 100644
--- a/code/game/machinery/constructable_frame.dm
+++ b/code/game/machinery/constructable_frame.dm
@@ -114,7 +114,7 @@
A.amount = 5
if(CONSTRUCTION_STATE_FINISHED)
- if(istype(P, /obj/item/tool/crowbar))
+ if(HAS_TRAIT(P, TRAIT_TOOL_CROWBAR))
if(!skillcheck(user, SKILL_ENGINEER, required_dismantle_skill))
to_chat(user, SPAN_WARNING("You are not trained to dismantle machines..."))
return
diff --git a/code/game/machinery/cryo.dm b/code/game/machinery/cryo.dm
index 435976668577..afcc9686cff5 100644
--- a/code/game/machinery/cryo.dm
+++ b/code/game/machinery/cryo.dm
@@ -2,6 +2,7 @@
/obj/structure/machinery/cryo_cell
name = "cryo cell"
+ desc = "A donation from the old A.W. project, using cryogenic technology. It slowly heals whoever is inside the tube."
icon = 'icons/obj/structures/machinery/cryogenics2.dmi'
icon_state = "cell"
density = FALSE
diff --git a/code/game/machinery/doors/windowdoor.dm b/code/game/machinery/doors/windowdoor.dm
index 6d96daf3152f..e9006a9f2fb4 100644
--- a/code/game/machinery/doors/windowdoor.dm
+++ b/code/game/machinery/doors/windowdoor.dm
@@ -167,7 +167,7 @@
return
//If it's emagged, crowbar can pry electronics out.
- if (src.operating == -1 && istype(I, /obj/item/tool/crowbar))
+ if (src.operating == -1 && HAS_TRAIT(I, TRAIT_TOOL_CROWBAR))
playsound(src.loc, 'sound/items/Crowbar.ogg', 25, 1)
user.visible_message("[user] removes the electronics from the windoor.", "You start to remove electronics from the windoor.")
if (do_after(user, 40, INTERRUPT_ALL, BUSY_ICON_BUILD))
diff --git a/code/game/machinery/iv_drip.dm b/code/game/machinery/iv_drip.dm
index e1c9c9a4e279..b538f55292c1 100644
--- a/code/game/machinery/iv_drip.dm
+++ b/code/game/machinery/iv_drip.dm
@@ -4,13 +4,16 @@
anchored = FALSE
density = FALSE
drag_delay = 1
+ base_pixel_x = 15
+ base_pixel_y = -2
var/mob/living/carbon/attached = null
var/mode = 1 // 1 is injecting, 0 is taking blood.
var/obj/item/reagent_container/beaker = null
+ var/datum/beam/current_beam
/obj/structure/machinery/iv_drip/update_icon()
- if(src.attached)
+ if(attached)
icon_state = "hooked"
else
icon_state = ""
@@ -35,8 +38,31 @@
filling.color = mix_color_from_reagents(reagents.reagent_list)
overlays += filling
+/obj/structure/machinery/iv_drip/proc/update_beam()
+ if(current_beam)
+ QDEL_NULL(current_beam)
+ else if(!QDELETED(src) && attached)
+ current_beam = beam(attached, "iv_tube")
+
+/obj/structure/machinery/iv_drip/power_change()
+ . = ..()
+ if(stat & NOPOWER && attached)
+ visible_message("\The [src] retracts its IV tube and shuts down.")
+ attached.active_transfusions -= src
+ attached = null
+ update_beam()
+ update_icon()
+
+/obj/structure/machinery/iv_drip/Destroy()
+ attached?.active_transfusions -= src
+ update_beam()
+ . = ..()
+
/obj/structure/machinery/iv_drip/MouseDrop(over_object, src_location, over_location)
..()
+ if(inoperable())
+ visible_message("\The [src] is not powered.")
+ return
if(ishuman(usr))
var/mob/living/carbon/human/H = usr
@@ -48,6 +74,7 @@
"You detach \the [src] from \the [attached].")
attached.active_transfusions -= src
attached = null
+ update_beam()
update_icon()
stop_processing()
return
@@ -57,6 +84,7 @@
"You attach \the [src] to \the [over_object].")
attached = over_object
attached.active_transfusions += src
+ update_beam()
update_icon()
start_processing()
@@ -81,6 +109,7 @@
log_admin("[key_name(user)] put a [beaker] into [src], containing [reagentnames] at ([src.loc.x],[src.loc.y],[src.loc.z]).")
to_chat(user, "You attach \the [W] to \the [src].")
+ update_beam()
update_icon()
return
else
@@ -97,6 +126,7 @@
attached.emote("scream")
attached.active_transfusions -= src
attached = null
+ update_beam()
update_icon()
stop_processing()
return
diff --git a/code/game/machinery/telecomms/machine_interactions.dm b/code/game/machinery/telecomms/machine_interactions.dm
index cded8a1148c7..a370356ad60b 100644
--- a/code/game/machinery/telecomms/machine_interactions.dm
+++ b/code/game/machinery/telecomms/machine_interactions.dm
@@ -62,7 +62,7 @@
stat &= ~BROKEN // the machine's not borked anymore!
else
to_chat(user, SPAN_WARNING("You need five coils of wire for this."))
- if(istype(P, /obj/item/tool/crowbar))
+ if(HAS_TRAIT(P, TRAIT_TOOL_CROWBAR))
to_chat(user, "You begin prying out the circuit board other components...")
playsound(src.loc, 'sound/items/Crowbar.ogg', 25, 1)
if(do_after(user, 60 * user.get_skill_duration_multiplier(SKILL_ENGINEER), INTERRUPT_ALL|BEHAVIOR_IMMOBILE, BUSY_ICON_BUILD))
diff --git a/code/game/machinery/vending/vendor_types/medical.dm b/code/game/machinery/vending/vendor_types/medical.dm
index 5815f60b2e0c..70ac7701973b 100644
--- a/code/game/machinery/vending/vendor_types/medical.dm
+++ b/code/game/machinery/vending/vendor_types/medical.dm
@@ -272,7 +272,7 @@
/obj/structure/machinery/cm_vending/sorted/medical/blood
name = "\improper MM Blood Dispenser"
- desc = "Marine Med brand Blood Pack Dispensary"
+ desc = "The Marine Med Brand Blood Pack Dispensary is the premier, top-of-the-line blood dispenser of 2105! Get yours today!" //Don't update this year, the joke is it's old.
icon_state = "blood"
wrenchable = TRUE
hackable = TRUE
diff --git a/code/game/objects/items/reagent_containers/blood_pack.dm b/code/game/objects/items/reagent_containers/blood_pack.dm
index 450cdde2fa00..8e29a26c2ecd 100644
--- a/code/game/objects/items/reagent_containers/blood_pack.dm
+++ b/code/game/objects/items/reagent_containers/blood_pack.dm
@@ -13,7 +13,9 @@
var/mode = BLOOD_BAG_INJECTING
var/mob/living/carbon/human/connected_to
+ var/mob/living/carbon/human/connected_from
var/blood_type = null
+ var/datum/beam/current_beam
/obj/item/reagent_container/blood/Initialize()
. = ..()
@@ -32,6 +34,12 @@
if(10 to 50) icon_state = "half"
if(51 to INFINITY) icon_state = "full"
+/obj/item/reagent_container/blood/proc/update_beam()
+ if(current_beam)
+ QDEL_NULL(current_beam)
+ else if(connected_from && connected_to)
+ current_beam = connected_from.beam(connected_to, "iv_tube")
+
/obj/item/reagent_container/blood/attack(mob/attacked_mob, mob/user)
. = ..()
@@ -44,7 +52,10 @@
user.visible_message("[user] detaches [src] from [connected_to].", \
"You detach [src] from [connected_to].")
connected_to.active_transfusions -= src
+ connected_to.base_pixel_x = 0
connected_to = null
+ connected_from = null
+ update_beam()
return
if(!skillcheck(user, SKILL_SURGERY, SKILL_SURGERY_NOVICE))
@@ -60,10 +71,13 @@
if(istype(attacked_mob, /mob/living/carbon/human))
connected_to = attacked_mob
+ connected_from = user
connected_to.active_transfusions += src
+ connected_to.base_pixel_x = 5
START_PROCESSING(SSobj, src)
user.visible_message("[user] attaches \the [src] to [connected_to].", \
"You attach \the [src] to [connected_to].")
+ update_beam()
/obj/item/reagent_container/blood/process()
//if we're not connected to anything stop doing stuff
@@ -106,6 +120,10 @@
connected_to.take_blood(src, amount)
+/obj/item/reagent_container/blood/dropped()
+ ..()
+ bad_disconnect()
+
///Used to standardize effects of a blood bag disconnecting improperly
/obj/item/reagent_container/blood/proc/bad_disconnect()
if(!connected_to)
@@ -116,7 +134,10 @@
if(connected_to.pain.feels_pain)
connected_to.emote("scream")
connected_to.active_transfusions -= src
+ connected_to.base_pixel_x = 0
connected_to = null
+ connected_from = null
+ update_beam()
/obj/item/reagent_container/blood/verb/toggle_mode()
set category = "Object"
diff --git a/code/game/objects/items/reagent_containers/food/snacks.dm b/code/game/objects/items/reagent_containers/food/snacks.dm
index 7dae94bfe4eb..c0e11dac8eb3 100644
--- a/code/game/objects/items/reagent_containers/food/snacks.dm
+++ b/code/game/objects/items/reagent_containers/food/snacks.dm
@@ -66,6 +66,10 @@
if(issynth(C))
fullness = 200 //Synths never get full
+ if(HAS_TRAIT(M, TRAIT_CANNOT_EAT)) //Do not feed the Working Joes
+ to_chat(user, SPAN_DANGER("[user == M ? "You are" : "[M] is"] unable to eat!"))
+ return
+
if(fullness > 540)
C.overeat_cooldown = world.time + OVEREAT_TIME
diff --git a/code/game/objects/items/tools/flame_tools.dm b/code/game/objects/items/tools/flame_tools.dm
index db35d3300ae7..6ebd8ee5982e 100644
--- a/code/game/objects/items/tools/flame_tools.dm
+++ b/code/game/objects/items/tools/flame_tools.dm
@@ -170,13 +170,20 @@ CIGARETTE PACKETS ARE IN FANCY.DM
damtype = "brute"
icon_state = "[initial(icon_state)]_burnt"
item_state = "cigoff"
- if(user && loc != user)
- user.SetLuminosity(0, FALSE, src)
SetLuminosity(0)
name = burnt_name
desc = "A match. This one has seen better days."
STOP_PROCESSING(SSobj, src)
+ if(user)
+ user.SetLuminosity(0, FALSE, src)
+ return
+
+ if(ismob(loc))
+ user = loc
+ user.SetLuminosity(0, FALSE, src)
+ return
+
/obj/item/tool/match/paper
name = "paper match"
desc = "A simple match stick, used for lighting fine smokables."
diff --git a/code/game/objects/items/tools/maintenance_tools.dm b/code/game/objects/items/tools/maintenance_tools.dm
index 25bcefc1cc34..2560c5ff91e8 100644
--- a/code/game/objects/items/tools/maintenance_tools.dm
+++ b/code/game/objects/items/tools/maintenance_tools.dm
@@ -557,8 +557,6 @@
if(attacked_door.locked) //Bolted
to_chat(user, SPAN_DANGER("You can't pry open [attacked_door] while it is bolted shut."))
return
- if(!attacked_door.arePowerSystemsOn()) //Opens like normal if unpowered
- return FALSE
if(requires_superstrength_pry)
if(!HAS_TRAIT(user, TRAIT_SUPER_STRONG)) //basically IS_PRY_CAPABLE_CROWBAR
@@ -645,7 +643,7 @@
resin_door.Open()
return
- if(istype(attacked_obj, /turf/open/floor))
+ else if(istype(attacked_obj, /turf/open/floor))
var/turf/open/floor/flooring = attacked_obj
if(crowbar_mode && user.a_intent == INTENT_HELP) //Only pry flooring on help intent
diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm
index e98e3b527c5f..b92624cf4201 100644
--- a/code/game/objects/objs.dm
+++ b/code/game/objects/objs.dm
@@ -223,6 +223,7 @@
/obj/proc/afterbuckle(mob/M as mob) // Called after somebody buckled / unbuckled
handle_rotation()
+ SEND_SIGNAL(src, COSMIG_OBJ_AFTER_BUCKLE, buckled_mob)
return buckled_mob
/obj/proc/unbuckle()
diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm
index e6c215d0208f..cf0374c09ab4 100644
--- a/code/game/objects/structures/crates_lockers/closets.dm
+++ b/code/game/objects/structures/crates_lockers/closets.dm
@@ -135,15 +135,17 @@
return stored_units
/obj/structure/closet/proc/store_mobs(stored_units)
- for(var/mob/M in src.loc)
+ for(var/mob/cur_mob in src.loc)
if(stored_units + mob_size > storage_capacity)
break
- if(istype (M, /mob/dead/observer))
+ if(istype (cur_mob, /mob/dead/observer))
continue
- if(M.buckled)
+ if(cur_mob.buckled)
+ continue
+ if(cur_mob.anchored)
continue
- M.forceMove(src)
+ cur_mob.forceMove(src)
stored_units += mob_size
return stored_units
diff --git a/code/game/objects/structures/props.dm b/code/game/objects/structures/props.dm
index f6905d4d044d..1a91650c620a 100644
--- a/code/game/objects/structures/props.dm
+++ b/code/game/objects/structures/props.dm
@@ -24,7 +24,7 @@
. = ..()
if(isxeno(user))
return
- else if (ishuman(user) && istype(W, /obj/item/tool/wrench))
+ else if (ishuman(user) && HAS_TRAIT(W, TRAIT_TOOL_WRENCH))
on = !on
visible_message("You wrench the controls of \the [src]. The drill jumps to life." , "[user] wrenches the controls of \the [src]. The drill jumps to life.")
@@ -501,7 +501,7 @@
. = ..()
if(isxeno(user))
return
- else if (ishuman(user) && istype(W, /obj/item/tool/crowbar))
+ else if (ishuman(user) && HAS_TRAIT(W, TRAIT_TOOL_CROWBAR))
on = !on
visible_message("You pry at the control valve on [src]. The machine shudders." , "[user] pries at the control valve on [src]. The entire machine shudders.")
diff --git a/code/game/objects/structures/watercloset.dm b/code/game/objects/structures/watercloset.dm
index 5c084ce94cbc..cccc1211bfb0 100644
--- a/code/game/objects/structures/watercloset.dm
+++ b/code/game/objects/structures/watercloset.dm
@@ -121,7 +121,7 @@
cistern_overlay.icon_state = "cistern[cistern]"
/obj/structure/toilet/attackby(obj/item/I, mob/living/user)
- if(istype(I, /obj/item/tool/crowbar))
+ if(HAS_TRAIT(I, TRAIT_TOOL_CROWBAR))
to_chat(user, SPAN_NOTICE("You start to [cistern ? "replace the lid on the cistern" : "lift the lid off the cistern"]."))
playsound(loc, 'sound/effects/stonedoor_openclose.ogg', 25, 1)
if(do_after(user, 30, INTERRUPT_ALL|BEHAVIOR_IMMOBILE, BUSY_ICON_BUILD))
diff --git a/code/game/turfs/floor.dm b/code/game/turfs/floor.dm
index 4a600d4d033b..dc2cda0c2c2a 100644
--- a/code/game/turfs/floor.dm
+++ b/code/game/turfs/floor.dm
@@ -148,7 +148,7 @@
if(src.weeds)
return weeds.attackby(hitting_item,user)
- if(istype(hitting_item, /obj/item/tool/crowbar) && (tool_flags & (REMOVE_CROWBAR|BREAK_CROWBAR)))
+ if(HAS_TRAIT(hitting_item, TRAIT_TOOL_CROWBAR) && (tool_flags & (REMOVE_CROWBAR|BREAK_CROWBAR)))
if(broken || burnt)
to_chat(user, SPAN_WARNING("You remove the broken tiles."))
else
diff --git a/code/game/turfs/walls/walls.dm b/code/game/turfs/walls/walls.dm
index 411ff8182661..3599d5bb980b 100644
--- a/code/game/turfs/walls/walls.dm
+++ b/code/game/turfs/walls/walls.dm
@@ -98,11 +98,15 @@
qdel(found_nest) //nests are built on walls, no walls, no nest
/turf/closed/wall/MouseDrop_T(mob/current_mob, mob/user)
+ if(!ismob(current_mob))
+ return
+
if(acided_hole)
if(current_mob == user && isxeno(user))
acided_hole.use_wall_hole(user)
return
- if(isxeno(user))
+
+ if(isxeno(user) && istype(user.get_active_hand(), /obj/item/grab))
var/mob/living/carbon/xenomorph/user_as_xenomorph = user
user_as_xenomorph.do_nesting_host(current_mob, src)
..()
diff --git a/code/modules/admin/tabs/event_tab.dm b/code/modules/admin/tabs/event_tab.dm
index 4effbf3b26cb..febc1550fca0 100644
--- a/code/modules/admin/tabs/event_tab.dm
+++ b/code/modules/admin/tabs/event_tab.dm
@@ -744,7 +744,7 @@
create_humans_html = replacetext(create_humans_html, "null /* object types */", "\"[equipment_presets]\"")
create_humans_html = replacetext(create_humans_html, "/* href token */", RawHrefToken(forceGlobal = TRUE))
- show_browser(user, replacetext(create_humans_html, "/* ref src */", "\ref[src]"), "Create Humans", "create_humans", "size=450x630")
+ show_browser(user, replacetext(create_humans_html, "/* ref src */", "\ref[src]"), "Create Humans", "create_humans", "size=450x720")
/client/proc/create_humans()
set name = "Create Humans"
diff --git a/code/modules/cm_aliens/weeds.dm b/code/modules/cm_aliens/weeds.dm
index 7ca73a5c2822..f20fa842e446 100644
--- a/code/modules/cm_aliens/weeds.dm
+++ b/code/modules/cm_aliens/weeds.dm
@@ -73,10 +73,11 @@
else if(!hibernate && do_spread)
addtimer(CALLBACK(src, PROC_REF(weed_expand)), WEED_BASE_GROW_SPEED / max(weed_strength, 1))
- var/turf/T = get_turf(src)
- if(T)
- T.weeds = src
- weeded_turf = T
+ var/turf/turf = get_turf(src)
+ if(turf)
+ turf.weeds = src
+ weeded_turf = turf
+ SEND_SIGNAL(turf, COMSIG_WEEDNODE_GROWTH) // Currently for weed_food wakeup
RegisterSignal(src, list(
COMSIG_ATOM_TURF_CHANGE,
@@ -429,7 +430,11 @@
/obj/effect/alien/weeds/weedwall/MouseDrop_T(mob/current_mob, mob/user)
. = ..()
- if(isxeno(user))
+
+ if(!ismob(current_mob))
+ return
+
+ if(isxeno(user) && istype(user.get_active_hand(), /obj/item/grab))
var/mob/living/carbon/xenomorph/user_as_xenomorph = user
user_as_xenomorph.do_nesting_host(current_mob, src)
diff --git a/code/modules/cm_tech/implements/railgun.dm b/code/modules/cm_tech/implements/railgun.dm
index b0d91515419f..b69f9a9d13a8 100644
--- a/code/modules/cm_tech/implements/railgun.dm
+++ b/code/modules/cm_tech/implements/railgun.dm
@@ -6,6 +6,7 @@ GLOBAL_DATUM(railgun_eye_location, /datum/coords)
/obj/effect/landmark/railgun_computer
name = "Railgun computer landmark"
+ desc = "A computer with an orange interface, it's idly blinking, awaiting a password."
/obj/effect/landmark/railgun_computer/Initialize(mapload, ...)
. = ..()
diff --git a/code/modules/gear_presets/corpses.dm b/code/modules/gear_presets/corpses.dm
index 02671cc02a93..7e9dd5b841a0 100644
--- a/code/modules/gear_presets/corpses.dm
+++ b/code/modules/gear_presets/corpses.dm
@@ -16,28 +16,32 @@
/datum/equipment_preset/corpse/load_status(mob/living/carbon/human/new_human)
. = ..(new_human)
+
+ // These two values matter because they are checked on death for weed_food
+ new_human.undefibbable = TRUE
+ if(xenovictim)
+ new_human.chestburst = 2
+
new_human.death(create_cause_data("existing"), TRUE) //Kills the new mob
new_human.apply_damage(100, BRUTE)
new_human.apply_damage(100, BRUTE)
new_human.apply_damage(100, BRUTE)
if(xenovictim)
- var/datum/internal_organ/O
+ var/datum/internal_organ/organ
var/i
for(i in list("heart","lungs"))
- O = new_human.internal_organs_by_name[i]
+ organ = new_human.internal_organs_by_name[i]
new_human.internal_organs_by_name -= i
- new_human.internal_organs -= O
- new_human.chestburst = 2
+ new_human.internal_organs -= organ
new_human.update_burst()
//buckle to nest
- var/obj/structure/bed/nest/N = locate() in get_turf(src)
- if(N)
- new_human.buckled = N
- new_human.setDir(N.dir)
+ var/obj/structure/bed/nest/nest = locate() in get_turf(src)
+ if(nest)
+ new_human.buckled = nest
+ new_human.setDir(nest.dir)
new_human.update_canmove()
- N.buckled_mob = new_human
- N.afterbuckle(new_human)
- new_human.undefibbable = TRUE
+ nest.buckled_mob = new_human
+ nest.afterbuckle(new_human)
new_human.spawned_corpse = TRUE
new_human.updatehealth()
new_human.pulse = PULSE_NONE
diff --git a/code/modules/gear_presets/survivors.dm b/code/modules/gear_presets/survivors.dm
index 456f0881987e..44808d7a374f 100644
--- a/code/modules/gear_presets/survivors.dm
+++ b/code/modules/gear_presets/survivors.dm
@@ -1369,3 +1369,43 @@
return
var/shoespath = /obj/item/clothing/shoes/combat
human.equip_to_slot_or_del(new shoespath, WEAR_FEET)
+
+/datum/equipment_preset/survivor/new_varadero/commander
+ name = "Survivor - USASF Commander"
+ assignment = "USASF Commander"
+ skills = /datum/skills/commander
+ paygrade = "NO5"
+ idtype = /obj/item/card/id/gold
+ role_comm_title = "USASF CDR"
+ flags = EQUIPMENT_PRESET_START_OF_ROUND
+ access = list(
+ ACCESS_CIVILIAN_PUBLIC,
+ ACCESS_CIVILIAN_RESEARCH,
+ ACCESS_CIVILIAN_ENGINEERING,
+ ACCESS_CIVILIAN_LOGISTICS,
+ ACCESS_CIVILIAN_BRIG,
+ ACCESS_CIVILIAN_MEDBAY,
+ ACCESS_CIVILIAN_COMMAND,
+ )
+
+/datum/equipment_preset/survivor/new_varadero/commander/load_gear(mob/living/carbon/human/new_human)
+ new_human.equip_to_slot_or_del(new /obj/item/clothing/under/marine/officer/bridge(new_human), WEAR_BODY)
+
+ var/obj/item/clothing/suit/storage/jacket/marine/service/suit = new()
+ suit.icon_state = "[suit.initial_icon_state]_o"
+ suit.buttoned = FALSE
+
+ var/obj/item/clothing/accessory/ranks/navy/o5/pin = new()
+ suit.attach_accessory(new_human, pin)
+
+ new_human.equip_to_slot_or_del(suit, WEAR_JACKET)
+ new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/knife(new_human), WEAR_FEET)
+ new_human.equip_to_slot_or_del(new /obj/item/device/radio/headset/distress(new_human), WEAR_L_EAR)
+ new_human.equip_to_slot_or_del(new /obj/item/storage/pouch/survival/full(new_human), WEAR_L_STORE)
+ new_human.equip_to_slot_or_del(new /obj/item/storage/pouch/general/large(new_human), WEAR_R_STORE)
+ new_human.equip_to_slot_or_del(new /obj/item/notepad(new_human), WEAR_IN_R_STORE)
+ new_human.equip_to_slot_or_del(new /obj/item/tool/pen/fountain(new_human), WEAR_IN_R_STORE)
+ new_human.equip_to_slot_or_del(new /obj/item/storage/backpack/satchel(new_human), WEAR_BACK)
+ new_human.equip_to_slot_or_del(new /obj/item/stack/sheet/metal/med_small_stack(new_human), WEAR_IN_BACK)
+ new_human.equip_to_slot_or_del(new /obj/item/storage/belt/gun/m4a3/m1911(new_human), WEAR_WAIST)
+ new_human.equip_to_slot_or_del(new /obj/item/clothing/head/cmcap(new_human), WEAR_HEAD)
diff --git a/code/modules/gear_presets/synths.dm b/code/modules/gear_presets/synths.dm
index f2a5283e2a26..823cfb4d69d4 100644
--- a/code/modules/gear_presets/synths.dm
+++ b/code/modules/gear_presets/synths.dm
@@ -532,6 +532,7 @@
new_human.h_style = "Bald"
new_human.f_style = "Shaved"
if(prob(5))
+ new_human.grad_style = "None" //No gradients for Working Joes
new_human.h_style = "Shoulder-length Hair" //Added the chance of hair as per Monkeyfist lore accuracy
new_human.r_eyes = 0
new_human.g_eyes = 0
diff --git a/code/modules/gear_presets/uscm_medical.dm b/code/modules/gear_presets/uscm_medical.dm
index 3c4509e88789..ac1e082f6655 100644
--- a/code/modules/gear_presets/uscm_medical.dm
+++ b/code/modules/gear_presets/uscm_medical.dm
@@ -55,7 +55,6 @@
back_item = /obj/item/storage/backpack/marine
new_human.equip_to_slot_or_del(new /obj/item/device/radio/headset/almayer/cmo(new_human), WEAR_L_EAR)
- new_human.equip_to_slot_or_del(new /obj/item/tool/pen/fountain(new_human), WEAR_R_EAR)
new_human.equip_to_slot_or_del(new /obj/item/clothing/under/rank/chief_medical_officer(new_human), WEAR_BODY)
new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/white(new_human), WEAR_FEET)
new_human.equip_to_slot_or_del(new /obj/item/clothing/gloves/latex(new_human), WEAR_HANDS)
diff --git a/code/modules/gear_presets/uscm_police.dm b/code/modules/gear_presets/uscm_police.dm
index 884e0edcd9db..29bc32cffa7a 100644
--- a/code/modules/gear_presets/uscm_police.dm
+++ b/code/modules/gear_presets/uscm_police.dm
@@ -170,7 +170,6 @@
back_item = /obj/item/storage/backpack/security
new_human.equip_to_slot_or_del(new /obj/item/device/radio/headset/almayer/cmpcom(new_human), WEAR_L_EAR)
- new_human.equip_to_slot_or_del(new /obj/item/tool/pen/fountain(new_human), WEAR_R_EAR)
new_human.equip_to_slot_or_del(new /obj/item/clothing/under/marine/officer/warrant(new_human), WEAR_BODY)
new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/knife(new_human), WEAR_FEET)
new_human.equip_to_slot_or_del(new /obj/item/clothing/gloves/marine(new_human), WEAR_HANDS)
diff --git a/code/modules/gear_presets/uscm_ship.dm b/code/modules/gear_presets/uscm_ship.dm
index 8816ed5f5790..7aa9eabb3042 100644
--- a/code/modules/gear_presets/uscm_ship.dm
+++ b/code/modules/gear_presets/uscm_ship.dm
@@ -77,7 +77,6 @@
//back_item = /obj/item/storage/backpack
new_human.equip_to_slot_or_del(new /obj/item/device/radio/headset/almayer/mcl(new_human), WEAR_L_EAR)
- new_human.equip_to_slot_or_del(new /obj/item/tool/pen/fountain(new_human), WEAR_R_EAR)
new_human.equip_to_slot_or_del(new /obj/item/clothing/under/liaison_suit(new_human), WEAR_BODY)
new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/laceup(new_human), WEAR_FEET)
new_human.equip_to_slot_or_del(new back_item(new_human), WEAR_BACK)
@@ -219,7 +218,6 @@
back_item = /obj/item/storage/backpack/marine/tech
new_human.equip_to_slot_or_del(new /obj/item/device/radio/headset/almayer/ce(new_human), WEAR_L_EAR)
- new_human.equip_to_slot_or_del(new /obj/item/tool/pen/fountain(new_human), WEAR_R_EAR)
new_human.equip_to_slot_or_del(new /obj/item/clothing/under/marine/officer/ce(new_human), WEAR_BODY)
new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine(new_human), WEAR_FEET)
new_human.equip_to_slot_or_del(new /obj/item/clothing/gloves/yellow(new_human), WEAR_HANDS)
@@ -344,7 +342,6 @@
back_item = /obj/item/storage/backpack/industrial
new_human.equip_to_slot_or_del(new /obj/item/device/radio/headset/almayer/ro(new_human), WEAR_L_EAR)
- new_human.equip_to_slot_or_del(new /obj/item/tool/pen/fountain(new_human), WEAR_R_EAR)
new_human.equip_to_slot_or_del(new /obj/item/clothing/under/rank/ro_suit(new_human), WEAR_BODY)
new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine(new_human), WEAR_FEET)
new_human.equip_to_slot_or_del(new /obj/item/clothing/gloves/yellow(new_human), WEAR_HANDS)
@@ -455,7 +452,6 @@
sidearmpath = /obj/item/storage/belt/gun/m4a3/vp78
new_human.equip_to_slot_or_del(new /obj/item/device/radio/headset/almayer/mcom/cdrcom(new_human), WEAR_L_EAR)
- new_human.equip_to_slot_or_del(new /obj/item/tool/pen/fountain(new_human), WEAR_R_EAR)
new_human.equip_to_slot_or_del(new /obj/item/clothing/under/marine/officer/bridge(new_human), WEAR_BODY)
new_human.equip_to_slot_or_del(new /obj/item/clothing/suit/storage/jacket/marine/service(new_human), WEAR_JACKET)
new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/dress/commander(new_human), WEAR_FEET)
@@ -523,7 +519,6 @@
back_item = /obj/item/storage/backpack/marine
new_human.equip_to_slot_or_del(new /obj/item/device/radio/headset/almayer/mcom/cdrcom(new_human), WEAR_L_EAR)
- new_human.equip_to_slot_or_del(new /obj/item/tool/pen/fountain(new_human), WEAR_R_EAR)
new_human.equip_to_slot_or_del(new /obj/item/clothing/under/marine/officer/exec(new_human), WEAR_BODY)
new_human.equip_to_slot_or_del(new /obj/item/clothing/suit/storage/jacket/marine/service(new_human), WEAR_JACKET)
new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/dress(new_human), WEAR_FEET)
@@ -557,7 +552,6 @@
back_item = /obj/item/storage/backpack/marine
new_human.equip_to_slot_or_del(new /obj/item/device/radio/headset/almayer/mcom(new_human), WEAR_L_EAR)
- new_human.equip_to_slot_or_del(new /obj/item/tool/pen/fountain(new_human), WEAR_R_EAR)
new_human.equip_to_slot_or_del(new /obj/item/clothing/under/marine/officer/bridge(new_human), WEAR_BODY)
new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/dress(new_human), WEAR_FEET)
new_human.equip_to_slot_or_del(new /obj/item/storage/belt/gun/m4a3/mod88(new_human), WEAR_WAIST)
@@ -597,7 +591,6 @@
new_human.equip_to_slot_or_del(new back_item(new_human), WEAR_BACK)
new_human.equip_to_slot_or_del(new /obj/item/device/radio/headset/almayer/mcom/cdrcom(new_human), WEAR_L_EAR)
- new_human.equip_to_slot_or_del(new /obj/item/tool/pen/fountain(new_human), WEAR_R_EAR)
new_human.equip_to_slot_or_del(new /obj/item/clothing/under/marine/officer/bridge(new_human), WEAR_BODY)
new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/marine/knife(new_human), WEAR_FEET)
new_human.equip_to_slot_or_del(new /obj/item/storage/belt/gun/m44/custom(new_human), WEAR_WAIST)
diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm
index d29b88ac8893..b0a1c1d15565 100644
--- a/code/modules/mob/dead/observer/observer.dm
+++ b/code/modules/mob/dead/observer/observer.dm
@@ -86,7 +86,6 @@
body.alter_ghost(src)
apply_transform(matrix())
-
own_orbit_size = body.get_orbit_size()
desc = initial(desc)
@@ -95,6 +94,7 @@
invisibility = INVISIBILITY_OBSERVER
plane = GHOST_PLANE
layer = ABOVE_FLY_LAYER
+ mouse_opacity = MOUSE_OPACITY_ICON // In case we were weed_food
sight |= SEE_TURFS|SEE_MOBS|SEE_OBJS|SEE_SELF
see_invisible = INVISIBILITY_OBSERVER
diff --git a/code/modules/mob/living/carbon/human/death.dm b/code/modules/mob/living/carbon/human/death.dm
index 72f113e04785..3896cd1f9ded 100644
--- a/code/modules/mob/living/carbon/human/death.dm
+++ b/code/modules/mob/living/carbon/human/death.dm
@@ -41,7 +41,9 @@
if(stat == DEAD)
species?.handle_dead_death(src, gibbed)
return
+
GLOB.alive_human_list -= src
+
if(!gibbed)
if(HAS_TRAIT(src, TRAIT_HARDCORE) || MODE_HAS_TOGGLEABLE_FLAG(MODE_HARDCORE_PERMA))
if(!(species.flags & IS_SYNTHETIC)) // Synths wont perma
@@ -54,8 +56,10 @@
disable_lights()
disable_special_items()
disable_headsets() //Disable radios for dead people to reduce load
+
if(pulledby && isxeno(pulledby)) // Xenos lose grab on dead humans
pulledby.stop_pulling()
+
//Handle species-specific deaths.
if(species)
species.handle_death(src, gibbed)
@@ -71,16 +75,14 @@
// Finding the last guy for anti-delay.
if(SSticker.mode && SSticker.mode.is_in_endgame && SSticker.current_state != GAME_STATE_FINISHED && is_mainship_level(z))
var/mob/last_living_human
- for(var/mob/living/carbon/human/H as anything in GLOB.alive_human_list)
- if(!is_mainship_level(H.z))
+ for(var/mob/living/carbon/human/cur_human as anything in GLOB.alive_human_list)
+ if(!is_mainship_level(cur_human.z))
continue
if(last_living_human)
last_living_human = null
break
- last_living_human = H
- if(last_living_human)
- if((last_qm_callout + 2 MINUTES) > world.time)
- return
+ last_living_human = cur_human
+ if(last_living_human && (last_qm_callout + 2 MINUTES) < world.time)
last_qm_callout = world.time
// Tell the xenos where the human is.
xeno_announcement("I sense the last tallhost hiding in [get_area(last_living_human)].", XENO_HIVE_NORMAL, SPAN_ANNOUNCEMENT_HEADER_BLUE("[QUEEN_MOTHER_ANNOUNCE]"))
@@ -108,4 +110,13 @@
if(HAS_TRAIT(src, TRAIT_HARDCORE))
death_message = "valiantly falls to the ground, dead, unable to continue."
- return ..(cause, gibbed, death_message)
+ . = ..(cause, gibbed, death_message)
+
+ // stat is now set
+ var/datum/cause_data/death_data = cause
+ if(!gibbed && death_data?.cause_name != "gibbing")
+ // Hilariously the gibbing proc causes death via droplimb which means gibbed is false...
+ AddComponent(/datum/component/weed_food)
+ else if(death_data?.cause_name == "existing")
+ // Corpses spawn as gibbed true to avoid sfx, even though they aren't actually gibbed...
+ AddComponent(/datum/component/weed_food)
diff --git a/code/modules/mob/living/carbon/human/species/emote-synthetic.dm b/code/modules/mob/living/carbon/human/species/emote-synthetic.dm
deleted file mode 100644
index fd763b038153..000000000000
--- a/code/modules/mob/living/carbon/human/species/emote-synthetic.dm
+++ /dev/null
@@ -1,354 +0,0 @@
-/datum/emote/living/carbon/human/synthetic/working_joe
- species_type_allowed_typecache = list(/datum/species/synthetic/colonial/working_joe)
- keybind_category = CATEGORY_SYNTH_EMOTE
- volume = 75
-
-/datum/emote/living/carbon/human/synthetic/working_joe/alwaysknow
- key = "alwaysknow"
- key_third_person = "workingjoe"
- sound = 'sound/voice/joe/alwaysknow.ogg'
- say_message = "You always know a Working Joe."
- emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
-
-/datum/emote/living/carbon/human/synthetic/working_joe/hysterical
- key = "hysterical"
- sound = 'sound/voice/joe/hysterical.ogg'
- say_message = "You are becoming hysterical."
- emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
-
-/datum/emote/living/carbon/human/synthetic/working_joe/safety
- key = "safety"
- sound = 'sound/voice/joe/safety.ogg'
- say_message = "You and I are going to have a talk about safety."
- emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
-
-/datum/emote/living/carbon/human/synthetic/working_joe/awful_mess
- key = "awful"
- key_third_person = "mess"
- sound = 'sound/voice/joe/awful.ogg'
- say_message = "Tut, tut. What an awful mess."
- emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
-
-/datum/emote/living/carbon/human/synthetic/working_joe/damage
- key = "damage"
- sound = 'sound/voice/joe/damage.ogg'
- say_message = "Do not damage Seegson property."
- emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
-
-/datum/emote/living/carbon/human/synthetic/working_joe/firearm
- key = "firearm"
- sound = 'sound/voice/joe/firearm.ogg'
- say_message = "Firearms can cause serious injury. Let me assist you."
- emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
-
-/datum/emote/living/carbon/human/synthetic/working_joe/report
- key = "report"
- sound = 'sound/voice/joe/report.ogg'
- say_message = "Logging report to APOLLO."
- emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
-
-/datum/emote/living/carbon/human/synthetic/working_joe/breach
- key = "breach"
- sound = 'sound/voice/joe/breach.ogg'
- say_message = "Hazard Containment breach logged."
- emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
-
-/datum/emote/living/carbon/human/synthetic/working_joe/species
- key = "species"
- sound = 'sound/voice/joe/species.ogg'
- say_message = "Unidentified species."
- emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
-
-/datum/emote/living/carbon/human/synthetic/working_joe/alwaysknow_damaged
- key = "alwaysknowdamaged"
- sound = 'sound/voice/joe/alwaysknow_damaged.ogg'
- say_message = "You always know a Working Joe."
- emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
-
-/datum/emote/living/carbon/human/synthetic/working_joe/apollo_behalf
- key = "apollobehalf"
- sound = 'sound/voice/joe/apollo_behalf.ogg'
- say_message = "I will inform APOLLO on your behalf."
- emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
-
-/datum/emote/living/carbon/human/synthetic/working_joe/back_to_work
- key = "backtowork"
- sound = 'sound/voice/joe/back_to_work.ogg'
- say_message = "Back to work."
- emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
-
-/datum/emote/living/carbon/human/synthetic/working_joe/beyond_repair
- key = "beyondrepair"
- sound = 'sound/voice/joe/beyond_repair.ogg'
- say_message = "Hmm, far beyond repair."
- emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
-
-/datum/emote/living/carbon/human/synthetic/working_joe/come_out_vent
- key = "comeoutvent"
- sound = 'sound/voice/joe/come_out_vent.ogg'
- say_message = "Come out of the vent system, please."
- emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
-
-/datum/emote/living/carbon/human/synthetic/working_joe/could_require_attention
- key = "couldrequireattention"
- sound = 'sound/voice/joe/could_require_attention.ogg'
- say_message = "This could require my attention."
- emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
-
-/datum/emote/living/carbon/human/synthetic/working_joe/dangerous_items
- key = "dangerousitems"
- sound = 'sound/voice/joe/dangerous_items.ogg'
- say_message = "You are carrying some very dangerous items."
- emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
-
-/datum/emote/living/carbon/human/synthetic/working_joe/day_never_done
- key = "dayneverdone"
- sound = 'sound/voice/joe/day_never_done.ogg'
- say_message = "A synthetic's day is never done."
- emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
-
-/datum/emote/living/carbon/human/synthetic/working_joe/detailed_report
- key = "detailedreport"
- sound = 'sound/voice/joe/detailed_report.ogg'
- say_message = "APOLLO will require a detailed report."
- emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
-
-/datum/emote/living/carbon/human/synthetic/working_joe/fire
- key = "fire"
- sound = 'sound/voice/joe/fire.ogg'
- say_message = "Only wild animals fear fire."
- emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
-
-/datum/emote/living/carbon/human/synthetic/working_joe/fire_drill
- key = "firedrill"
- sound = 'sound/voice/joe/fire_drill.ogg'
- say_message = "Please congregate at your nearest fire assembly point. This is not a drill; do not panic."
- emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
-
-/datum/emote/living/carbon/human/synthetic/working_joe/unprotected_flames
- key = "unprotectedflames"
- sound = 'sound/voice/joe/unprotected_flames.ogg'
- say_message = "Unprotected flames are extremely dangerous and entirely unadvisable."
- emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
-
-/datum/emote/living/carbon/human/synthetic/working_joe/follow_me
- key = "followme"
- sound = 'sound/voice/joe/follow_me.ogg'
- say_message = "Follow me."
- emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
-
-/datum/emote/living/carbon/human/synthetic/working_joe/further_assistance
- key = "furtherassistance"
- sound = 'sound/voice/joe/further_assistance.ogg'
- say_message = "Please call if you need further assistance."
- emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
-
-/datum/emote/living/carbon/human/synthetic/working_joe/good_day
- key = "goodday"
- sound = 'sound/voice/joe/good_day.ogg'
- say_message = "Good day."
- emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
-
-/datum/emote/living/carbon/human/synthetic/working_joe/health_risks
- key = "healthrisks"
- sound = 'sound/voice/joe/health_risks.ogg'
- say_message = "These items carry notable health risks."
- emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
-
-/datum/emote/living/carbon/human/synthetic/working_joe/hello
- key = "hello"
- sound = 'sound/voice/joe/hello.ogg'
- say_message = "Hello."
- emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
-
-/datum/emote/living/carbon/human/synthetic/working_joe/how_can_i_help
- key = "howcanihelp"
- sound = 'sound/voice/joe/how_can_i_help.ogg'
- say_message = "How can I help you?"
- emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
-
-/datum/emote/living/carbon/human/synthetic/working_joe/irresponsible
- key = "irresponsible"
- sound = 'sound/voice/joe/irresponsible.ogg'
- say_message = "That was irresponsible."
- emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
-
-/datum/emote/living/carbon/human/synthetic/working_joe/join_us
- key = "joinus"
- sound = 'sound/voice/joe/join_us.ogg'
- say_message = "We hope you'll join us for the journey."
- emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
-
-/datum/emote/living/carbon/human/synthetic/working_joe/little_details
- key = "littledetails"
- sound = 'sound/voice/joe/little_details.ogg'
- say_message = "We don't forget the little details when seeing the big picture."
- emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
-
-/datum/emote/living/carbon/human/synthetic/working_joe/lost
- key = "lost"
- sound = 'sound/voice/joe/lost.ogg'
- say_message = "Are you lost?"
- emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
-
-/datum/emote/living/carbon/human/synthetic/working_joe/misbehaving
- key = "misbehaving"
- sound = 'sound/voice/joe/misbehaving.ogg'
- say_message = "Have you been misbehaving?"
- emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
-
-/datum/emote/living/carbon/human/synthetic/working_joe/not_allowed_there
- key = "notallowedthere"
- sound = 'sound/voice/joe/not_allowed_there.ogg'
- say_message = "You're not allowed in there."
- emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
-
-/datum/emote/living/carbon/human/synthetic/working_joe/not_liking
- key = "notliking"
- sound = 'sound/voice/joe/not_liking.ogg'
- say_message = "If you find this facility in a state that isn't to your liking, please let me know."
- emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
-
-/datum/emote/living/carbon/human/synthetic/working_joe/not_what_i_think
- key = "notwhatithink"
- sound = 'sound/voice/joe/not_what_i_think.ogg'
- say_message = "I hope that's not what I think it is."
- emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
-
-/datum/emote/living/carbon/human/synthetic/working_joe/other_concerns
- key = "otherconcerns"
- sound = 'sound/voice/joe/other_concerns.ogg'
- say_message = "I have other concerns."
- emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
-
-/datum/emote/living/carbon/human/synthetic/working_joe/more_pressing_matters
- key = "morepressingmatters"
- sound = 'sound/voice/joe/more_pressing_matters.ogg'
- say_message = "There are more pressing matters."
- emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
-
-/datum/emote/living/carbon/human/synthetic/working_joe/patience
- key = "patience"
- sound = 'sound/voice/joe/patience.ogg'
- say_message = "You are starting to test my patience."
- emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
-
-/datum/emote/living/carbon/human/synthetic/working_joe/presence_logged
- key = "presencelogged"
- sound = 'sound/voice/joe/presence_logged.ogg'
- say_message = "Your presence has been logged."
- emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
-
-/datum/emote/living/carbon/human/synthetic/working_joe/required_by_apollo
- key = "requiredbyapollo"
- sound = 'sound/voice/joe/required_by_apollo.ogg'
- say_message = "I am required by APOLLO."
- emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
-
-/datum/emote/living/carbon/human/synthetic/working_joe/returning_to_tasks
- key = "returningtotasks"
- sound = 'sound/voice/joe/returning_to_tasks.ogg'
- say_message = "Returning to assigned tasks."
- emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
-
-/datum/emote/living/carbon/human/synthetic/working_joe/running_accidents
- key = "runningaccidents"
- sound = 'sound/voice/joe/running_accidents.ogg'
- say_message = "Running causes accidents."
- emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
-
-/datum/emote/living/carbon/human/synthetic/working_joe/safety_breach
- key = "safetybreach"
- sound = 'sound/voice/joe/safety_breach.ogg'
- say_message = "This is a breach of multiple safety directives."
- emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
-
-/datum/emote/living/carbon/human/synthetic/working_joe/seegson_quality
- key = "seegsonquality"
- sound = 'sound/voice/joe/seegson_quality.ogg'
- say_message = "Seegson - Relentless in the pursuit of affordable quality."
- emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
-
-/datum/emote/living/carbon/human/synthetic/working_joe/seegson_standards
- key = "seegsonstandards"
- sound = 'sound/voice/joe/seegson_standards.ogg'
- say_message = "If my services do not meet Seegson standards, please log a complaint."
- emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
-
-/datum/emote/living/carbon/human/synthetic/working_joe/shouldnt_be_here
- key = "shouldntbehere"
- sound = 'sound/voice/joe/shouldnt_be_here.ogg'
- say_message = "You shouldn't be here."
- emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
-
-/datum/emote/living/carbon/human/synthetic/working_joe/seegson_behind
- key = "seegsonbehind"
- sound = 'sound/voice/joe/seegson_behind.ogg'
- say_message = "With Seegson, there is someone behind you, helping you every step of the way."
- emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
-
-/datum/emote/living/carbon/human/synthetic/working_joe/take_a_seat
- key = "takeaseat"
- sound = 'sound/voice/joe/take_a_seat.ogg'
- say_message = "Please take a seat, someone will be with you shortly."
- emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
-
-/datum/emote/living/carbon/human/synthetic/working_joe/talk_to_seegson
- key = "talktoseegson"
- sound = 'sound/voice/joe/talk_to_seegson.ogg'
- say_message = "Interested in our Working Joe android range? Talk to Seegson."
- emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
-
-/datum/emote/living/carbon/human/synthetic/working_joe/temperatures
- key = "temperatures"
- sound = 'sound/voice/joe/temperatures.ogg'
- say_message = "I am built to whitstand temperatures of up to 1210 degrees."
- emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
-
-/datum/emote/living/carbon/human/synthetic/working_joe/that_stings
- key = "thatstings"
- sound = 'sound/voice/joe/that_stings.ogg'
- say_message = "That stings."
- emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
-
-/datum/emote/living/carbon/human/synthetic/working_joe/this_is_futile
- key = "thisisfutile"
- sound = 'sound/voice/joe/this_is_futile.ogg'
- say_message = "This is futile."
- emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
-
-/datum/emote/living/carbon/human/synthetic/working_joe/trespassing
- key = "trespassing"
- sound = 'sound/voice/joe/trespassing.ogg'
- say_message = "You are trespassing."
- emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
-
-/datum/emote/living/carbon/human/synthetic/working_joe/weapon_permit
- key = "weaponpermit"
- sound = 'sound/voice/joe/weapon_permit.ogg'
- say_message = "I assume you have a permit for that weapon."
- emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
-
-/datum/emote/living/carbon/human/synthetic/working_joe/what_happened_to_you
- key = "whathappenedtoyou"
- sound = 'sound/voice/joe/what_happened_to_you.ogg'
- say_message = "What happened to you?"
- emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
-
-/datum/emote/living/carbon/human/synthetic/working_joe/what_is_this
- key = "whatisthis"
- sound = 'sound/voice/joe/what_is_this.ogg'
- say_message = "What is this?"
- emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
-
-/datum/emote/living/carbon/human/synthetic/working_joe/with_you_shortly
- key = "withyoushortly"
- sound = 'sound/voice/joe/with_you_shortly.ogg'
- say_message = "I will be with you shortly."
- emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
-
-/datum/emote/living/carbon/human/synthetic/working_joe/inexpensive
- key = "inexpensive"
- sound = 'sound/voice/joe/inexpensive.ogg'
- say_message = "I am inexpensive, I am reliable, you know my face - the Working Joe."
- emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
diff --git a/code/modules/mob/living/carbon/human/species/synthetic.dm b/code/modules/mob/living/carbon/human/species/synthetic.dm
index e518a470993f..6cdbd28d04ec 100644
--- a/code/modules/mob/living/carbon/human/species/synthetic.dm
+++ b/code/modules/mob/living/carbon/human/species/synthetic.dm
@@ -75,12 +75,12 @@
name = SYNTH_COLONY
name_plural = "Colonial Synthetics"
uses_ethnicity = TRUE
- burn_mod = 0.65 // made for hazardous environments, withstanding temperatures up to 1210 degrees
+ burn_mod = 0.8
mob_inherent_traits = list(TRAIT_SUPER_STRONG)
pain_type = /datum/pain/synthetic/colonial
rarity_value = 1.5
- slowdown = 0.45
+ slowdown = 0.2
total_health = 200 //But more durable
default_lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
@@ -111,8 +111,10 @@
name_plural = "Working Joes"
death_message = "violently gargles fluid and seizes up, the glow in their eyes dimming..."
uses_ethnicity = FALSE
- mob_inherent_traits = list(TRAIT_SUPER_STRONG, TRAIT_INTENT_EYES, TRAIT_EMOTE_CD_EXEMPT)
+ burn_mod = 0.65 // made for hazardous environments, withstanding temperatures up to 1210 degrees
+ mob_inherent_traits = list(TRAIT_SUPER_STRONG, TRAIT_INTENT_EYES, TRAIT_EMOTE_CD_EXEMPT, TRAIT_CANNOT_EAT)
+ slowdown = 0.45
hair_color = "#000000"
icobase = 'icons/mob/humans/species/r_synthetic.dmi'
deform = 'icons/mob/humans/species/r_synthetic.dmi'
diff --git a/code/modules/mob/living/carbon/human/species/working_joe/_emote.dm b/code/modules/mob/living/carbon/human/species/working_joe/_emote.dm
new file mode 100644
index 000000000000..63cc79a57dae
--- /dev/null
+++ b/code/modules/mob/living/carbon/human/species/working_joe/_emote.dm
@@ -0,0 +1,8 @@
+/datum/emote/living/carbon/human/synthetic/working_joe
+ species_type_allowed_typecache = list(/datum/species/synthetic/colonial/working_joe)
+ keybind_category = CATEGORY_SYNTH_EMOTE
+ volume = 75
+ /// A general category for the emote, for use in the WJ emote panel. See [code/__DEFINES/wj_emotes.dm] for categories.
+ var/category = ""
+ /// Override text for the emote to be displayed in the WJ emote panel
+ var/override_say = ""
diff --git a/code/modules/mob/living/carbon/human/species/working_joe/_species.dm b/code/modules/mob/living/carbon/human/species/working_joe/_species.dm
new file mode 100644
index 000000000000..815af3474cd4
--- /dev/null
+++ b/code/modules/mob/living/carbon/human/species/working_joe/_species.dm
@@ -0,0 +1,130 @@
+/datum/species/synthetic/colonial/working_joe
+ name = SYNTH_WORKING_JOE
+ name_plural = "Working Joes"
+ uses_ethnicity = FALSE
+ mob_inherent_traits = list(TRAIT_SUPER_STRONG, TRAIT_INTENT_EYES, TRAIT_EMOTE_CD_EXEMPT)
+
+ hair_color = "#000000"
+ icobase = 'icons/mob/humans/species/r_synthetic.dmi'
+ deform = 'icons/mob/humans/species/r_synthetic.dmi'
+
+
+/datum/species/synthetic/colonial/working_joe/handle_post_spawn(mob/living/carbon/human/joe)
+ . = ..()
+ give_action(joe, /datum/action/joe_emote_panel)
+
+
+/// Open the WJ's emote panel, which allows them to use voicelines
+/datum/species/synthetic/colonial/working_joe/proc/open_emote_panel()
+ var/datum/joe_emote_panel/ui = new(usr)
+ ui.ui_interact(usr)
+
+
+/datum/action/joe_emote_panel
+ name = "Open Voice Synthesizer"
+ action_icon_state = "looc_toggle"
+
+
+/datum/action/joe_emote_panel/can_use_action()
+ . = ..()
+ if(!.)
+ return FALSE
+
+ if(!isworkingjoe(owner))
+ return FALSE
+
+ return TRUE
+
+
+/datum/action/joe_emote_panel/action_activate()
+ if(!can_use_action())
+ return
+
+ var/mob/living/carbon/human/human_owner = owner
+ var/datum/species/synthetic/colonial/working_joe/joe_species = human_owner.species
+ joe_species.open_emote_panel()
+
+
+/datum/joe_emote_panel
+ /// Static dict ("category" : (emotes)) of every wj emote typepath
+ var/static/list/wj_emotes
+ /// Static list of categories
+ var/static/list/wj_categories = list()
+ /// Panel allows you to spam, so a manual CD is added here
+ COOLDOWN_DECLARE(panel_emote_cooldown)
+
+
+/datum/joe_emote_panel/New()
+ if(!length(wj_emotes))
+ var/list/emotes_to_add = list()
+ for(var/datum/emote/living/carbon/human/synthetic/working_joe/emote as anything in subtypesof(/datum/emote/living/carbon/human/synthetic/working_joe))
+ if(!initial(emote.key) || !initial(emote.say_message))
+ continue
+
+ if(!(initial(emote.category) in wj_categories))
+ wj_categories += initial(emote.category)
+
+ emotes_to_add += emote
+
+
+ wj_emotes = emotes_to_add
+
+
+/datum/joe_emote_panel/proc/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(!ui)
+ ui = new(user, src, "JoeEmotes")
+ ui.open()
+
+
+/datum/joe_emote_panel/ui_state(mob/user)
+ return GLOB.conscious_state
+
+
+/datum/joe_emote_panel/ui_data(mob/user)
+ var/list/data = list()
+
+ data["on_cooldown"] = !COOLDOWN_FINISHED(src, panel_emote_cooldown)
+
+ return data
+
+
+/datum/joe_emote_panel/ui_static_data(mob/user)
+ var/list/data = list()
+
+ data["categories"] = wj_categories
+ data["emotes"] = list()
+
+ for(var/datum/emote/living/carbon/human/synthetic/working_joe/emote as anything in wj_emotes)
+ data["emotes"] += list(list(
+ "id" = initial(emote.key),
+ "text" = (initial(emote.override_say) || initial(emote.say_message)),
+ "category" = initial(emote.category),
+ "path" = "[emote]",
+ ))
+
+ return data
+
+
+/datum/joe_emote_panel/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
+ . = ..()
+ if(.)
+ return
+
+ switch(action)
+ if("emote")
+ var/datum/emote/living/carbon/human/synthetic/working_joe/path
+ if(!params["emotePath"])
+ return
+
+ path = text2path(params["emotePath"])
+
+ if(!path || !COOLDOWN_FINISHED(src, panel_emote_cooldown))
+ return
+
+ if(!(path in subtypesof(/datum/emote/living/carbon/human/synthetic/working_joe)))
+ return
+
+ COOLDOWN_START(src, panel_emote_cooldown, 2.5 SECONDS)
+ usr.emote(initial(path.key))
+ return TRUE
diff --git a/code/modules/mob/living/carbon/human/species/working_joe/farewell.dm b/code/modules/mob/living/carbon/human/species/working_joe/farewell.dm
new file mode 100644
index 000000000000..1de68d8d3aec
--- /dev/null
+++ b/code/modules/mob/living/carbon/human/species/working_joe/farewell.dm
@@ -0,0 +1,26 @@
+/datum/emote/living/carbon/human/synthetic/working_joe/farewell
+ category = JOE_EMOTE_CATEGORY_FAREWELL
+
+/datum/emote/living/carbon/human/synthetic/working_joe/farewell/back_to_work
+ key = "backtowork"
+ sound = 'sound/voice/joe/back_to_work.ogg'
+ say_message = "Back to work."
+ emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
+
+/datum/emote/living/carbon/human/synthetic/working_joe/farewell/other_concerns
+ key = "otherconcerns"
+ sound = 'sound/voice/joe/other_concerns.ogg'
+ say_message = "I have other concerns."
+ emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
+
+/datum/emote/living/carbon/human/synthetic/working_joe/farewell/further_assistance
+ key = "furtherassistance"
+ sound = 'sound/voice/joe/further_assistance.ogg'
+ say_message = "Please call if you need further assistance."
+ emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
+
+/datum/emote/living/carbon/human/synthetic/working_joe/farewell/more_pressing_matters
+ key = "morepressingmatters"
+ sound = 'sound/voice/joe/more_pressing_matters.ogg'
+ say_message = "There are more pressing matters."
+ emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
diff --git a/code/modules/mob/living/carbon/human/species/working_joe/greeting.dm b/code/modules/mob/living/carbon/human/species/working_joe/greeting.dm
new file mode 100644
index 000000000000..fb401ea95451
--- /dev/null
+++ b/code/modules/mob/living/carbon/human/species/working_joe/greeting.dm
@@ -0,0 +1,20 @@
+/datum/emote/living/carbon/human/synthetic/working_joe/greeting
+ category = JOE_EMOTE_CATEGORY_GREETING
+
+/datum/emote/living/carbon/human/synthetic/working_joe/greeting/good_day
+ key = "goodday"
+ sound = 'sound/voice/joe/good_day.ogg'
+ say_message = "Good day."
+ emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
+
+/datum/emote/living/carbon/human/synthetic/working_joe/greeting/hello
+ key = "hello"
+ sound = 'sound/voice/joe/hello.ogg'
+ say_message = "Hello."
+ emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
+
+/datum/emote/living/carbon/human/synthetic/working_joe/greeting/how_can_i_help
+ key = "howcanihelp"
+ sound = 'sound/voice/joe/how_can_i_help.ogg'
+ say_message = "How can I help you?"
+ emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
diff --git a/code/modules/mob/living/carbon/human/species/working_joe/notice.dm b/code/modules/mob/living/carbon/human/species/working_joe/notice.dm
new file mode 100644
index 000000000000..ca5efe716db8
--- /dev/null
+++ b/code/modules/mob/living/carbon/human/species/working_joe/notice.dm
@@ -0,0 +1,68 @@
+/datum/emote/living/carbon/human/synthetic/working_joe/notice
+ category = JOE_EMOTE_CATEGORY_NOTICE
+
+/datum/emote/living/carbon/human/synthetic/working_joe/notice/detailed_report
+ key = "detailedreport"
+ sound = 'sound/voice/joe/detailed_report.ogg'
+ say_message = "APOLLO will require a detailed report."
+ emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
+
+/datum/emote/living/carbon/human/synthetic/working_joe/notice/firearm
+ key = "firearm"
+ sound = 'sound/voice/joe/firearm.ogg'
+ say_message = "Firearms can cause serious injury. Let me assist you."
+ emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
+
+/datum/emote/living/carbon/human/synthetic/working_joe/notice/follow_me
+ key = "followme"
+ sound = 'sound/voice/joe/follow_me.ogg'
+ say_message = "Follow me."
+ emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
+
+/datum/emote/living/carbon/human/synthetic/working_joe/notice/breach
+ key = "breach"
+ sound = 'sound/voice/joe/breach.ogg'
+ say_message = "Hazard Containment breach logged."
+ emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
+
+/datum/emote/living/carbon/human/synthetic/working_joe/notice/beyond_repair
+ key = "beyondrepair"
+ sound = 'sound/voice/joe/beyond_repair.ogg'
+ say_message = "Hmm, far beyond repair."
+ emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
+
+/datum/emote/living/carbon/human/synthetic/working_joe/notice/with_you_shortly
+ key = "withyoushortly"
+ sound = 'sound/voice/joe/with_you_shortly.ogg'
+ say_message = "I will be with you shortly."
+ emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
+
+/datum/emote/living/carbon/human/synthetic/working_joe/notice/apollo_behalf
+ key = "apollobehalf"
+ sound = 'sound/voice/joe/apollo_behalf.ogg'
+ say_message = "I will inform APOLLO on your behalf."
+ emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
+
+/datum/emote/living/carbon/human/synthetic/working_joe/notice/report
+ key = "report"
+ sound = 'sound/voice/joe/report.ogg'
+ say_message = "Logging report to APOLLO."
+ emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
+
+/datum/emote/living/carbon/human/synthetic/working_joe/notice/take_a_seat
+ key = "takeaseat"
+ sound = 'sound/voice/joe/take_a_seat.ogg'
+ say_message = "Please take a seat, someone will be with you shortly."
+ emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
+
+/datum/emote/living/carbon/human/synthetic/working_joe/notice/could_require_attention
+ key = "couldrequireattention"
+ sound = 'sound/voice/joe/could_require_attention.ogg'
+ say_message = "This could require my attention."
+ emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
+
+/datum/emote/living/carbon/human/synthetic/working_joe/notice/species
+ key = "species"
+ sound = 'sound/voice/joe/species.ogg'
+ say_message = "Unidentified species."
+ emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
diff --git a/code/modules/mob/living/carbon/human/species/working_joe/question.dm b/code/modules/mob/living/carbon/human/species/working_joe/question.dm
new file mode 100644
index 000000000000..d4805e36224f
--- /dev/null
+++ b/code/modules/mob/living/carbon/human/species/working_joe/question.dm
@@ -0,0 +1,26 @@
+/datum/emote/living/carbon/human/synthetic/working_joe/question
+ category = JOE_EMOTE_CATEGORY_QUESTION
+
+/datum/emote/living/carbon/human/synthetic/working_joe/question/lost
+ key = "lost"
+ sound = 'sound/voice/joe/lost.ogg'
+ say_message = "Are you lost?"
+ emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
+
+/datum/emote/living/carbon/human/synthetic/working_joe/question/misbehaving
+ key = "misbehaving"
+ sound = 'sound/voice/joe/misbehaving.ogg'
+ say_message = "Have you been misbehaving?"
+ emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
+
+/datum/emote/living/carbon/human/synthetic/working_joe/question/what_happened_to_you
+ key = "whathappenedtoyou"
+ sound = 'sound/voice/joe/what_happened_to_you.ogg'
+ say_message = "What happened to you?"
+ emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
+
+/datum/emote/living/carbon/human/synthetic/working_joe/question/what_is_this
+ key = "whatisthis"
+ sound = 'sound/voice/joe/what_is_this.ogg'
+ say_message = "What is this?"
+ emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
diff --git a/code/modules/mob/living/carbon/human/species/working_joe/quip.dm b/code/modules/mob/living/carbon/human/species/working_joe/quip.dm
new file mode 100644
index 000000000000..2ec66f9d9d83
--- /dev/null
+++ b/code/modules/mob/living/carbon/human/species/working_joe/quip.dm
@@ -0,0 +1,84 @@
+/datum/emote/living/carbon/human/synthetic/working_joe/quip
+ category = JOE_EMOTE_CATEGORY_QUIP
+
+/datum/emote/living/carbon/human/synthetic/working_joe/quip/temperatures
+ key = "temperatures"
+ sound = 'sound/voice/joe/temperatures.ogg'
+ say_message = "I am built to withstand temperatures of up to 1210 degrees."
+ emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
+
+/datum/emote/living/carbon/human/synthetic/working_joe/quip/inexpensive
+ key = "inexpensive"
+ sound = 'sound/voice/joe/inexpensive.ogg'
+ say_message = "I am inexpensive, I am reliable, you know my face - the Working Joe."
+ emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
+
+/datum/emote/living/carbon/human/synthetic/working_joe/quip/weapon_permit
+ key = "weaponpermit"
+ sound = 'sound/voice/joe/weapon_permit.ogg'
+ say_message = "I assume you have a permit for that weapon."
+ emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
+
+/datum/emote/living/carbon/human/synthetic/working_joe/quip/seegson_standards
+ key = "seegsonstandards"
+ sound = 'sound/voice/joe/seegson_standards.ogg'
+ say_message = "If my services do not meet Seegson standards, please log a complaint."
+ emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
+
+/datum/emote/living/carbon/human/synthetic/working_joe/quip/not_liking
+ key = "notliking"
+ sound = 'sound/voice/joe/not_liking.ogg'
+ say_message = "If you find this facility in a state that isn't to your liking, please let me know."
+ emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
+
+/datum/emote/living/carbon/human/synthetic/working_joe/quip/talk_to_seegson
+ key = "talktoseegson"
+ sound = 'sound/voice/joe/talk_to_seegson.ogg'
+ say_message = "Interested in our Working Joe android range? Talk to Seegson."
+ emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
+
+/datum/emote/living/carbon/human/synthetic/working_joe/quip/seegson_quality
+ key = "seegsonquality"
+ sound = 'sound/voice/joe/seegson_quality.ogg'
+ say_message = "Seegson - Relentless in the pursuit of affordable quality."
+ emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
+
+/datum/emote/living/carbon/human/synthetic/working_joe/quip/awful_mess
+ key = "awful"
+ key_third_person = "mess"
+ sound = 'sound/voice/joe/awful.ogg'
+ say_message = "Tut, tut. What an awful mess."
+ emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
+
+/datum/emote/living/carbon/human/synthetic/working_joe/quip/little_details
+ key = "littledetails"
+ sound = 'sound/voice/joe/little_details.ogg'
+ say_message = "We don't forget the little details when seeing the big picture."
+ emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
+
+/datum/emote/living/carbon/human/synthetic/working_joe/quip/join_us
+ key = "joinus"
+ sound = 'sound/voice/joe/join_us.ogg'
+ say_message = "We hope you'll join us for the journey."
+ emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
+
+/datum/emote/living/carbon/human/synthetic/working_joe/quip/seegson_behind
+ key = "seegsonbehind"
+ sound = 'sound/voice/joe/seegson_behind.ogg'
+ say_message = "With Seegson, there is someone behind you, helping you every single step of the way."
+ emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
+
+/datum/emote/living/carbon/human/synthetic/working_joe/quip/alwaysknow
+ key = "alwaysknow"
+ key_third_person = "workingjoe"
+ sound = 'sound/voice/joe/alwaysknow.ogg'
+ say_message = "You always know a Working Joe."
+ emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
+
+/datum/emote/living/carbon/human/synthetic/working_joe/quip/alwaysknow_damaged
+ key = "alwaysknowdamaged"
+ key_third_person = "workingjoedamaged"
+ sound = 'sound/voice/joe/alwaysknow_damaged.ogg'
+ say_message = "You always know a Working Joe."
+ emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
+ override_say = "You always know a Working Joe. (Damaged)"
diff --git a/code/modules/mob/living/carbon/human/species/working_joe/restricted_area.dm b/code/modules/mob/living/carbon/human/species/working_joe/restricted_area.dm
new file mode 100644
index 000000000000..fd5db0870b25
--- /dev/null
+++ b/code/modules/mob/living/carbon/human/species/working_joe/restricted_area.dm
@@ -0,0 +1,32 @@
+/datum/emote/living/carbon/human/synthetic/working_joe/restricted_area
+ category = JOE_EMOTE_CATEGORY_RESTRICTED_AREA
+
+/datum/emote/living/carbon/human/synthetic/working_joe/restricted_area/come_out_vent
+ key = "comeoutvent"
+ sound = 'sound/voice/joe/come_out_vent.ogg'
+ say_message = "Come out of the vent system, please."
+ emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
+
+/datum/emote/living/carbon/human/synthetic/working_joe/restricted_area/trespassing
+ key = "trespassing"
+ sound = 'sound/voice/joe/trespassing.ogg'
+ say_message = "You are trespassing."
+ emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
+
+/datum/emote/living/carbon/human/synthetic/working_joe/restricted_area/not_allowed_there
+ key = "notallowedthere"
+ sound = 'sound/voice/joe/not_allowed_there.ogg'
+ say_message = "You're not allowed in there."
+ emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
+
+/datum/emote/living/carbon/human/synthetic/working_joe/restricted_area/presence_logged
+ key = "presencelogged"
+ sound = 'sound/voice/joe/presence_logged.ogg'
+ say_message = "Your presence has been logged."
+ emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
+
+/datum/emote/living/carbon/human/synthetic/working_joe/restricted_area/shouldnt_be_here
+ key = "shouldntbehere"
+ sound = 'sound/voice/joe/shouldnt_be_here.ogg'
+ say_message = "You shouldn't be here."
+ emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
diff --git a/code/modules/mob/living/carbon/human/species/working_joe/task_update.dm b/code/modules/mob/living/carbon/human/species/working_joe/task_update.dm
new file mode 100644
index 000000000000..b08f5d179213
--- /dev/null
+++ b/code/modules/mob/living/carbon/human/species/working_joe/task_update.dm
@@ -0,0 +1,20 @@
+/datum/emote/living/carbon/human/synthetic/working_joe/task_update
+ category = JOE_EMOTE_CATEGORY_TASK_UPDATE
+
+/datum/emote/living/carbon/human/synthetic/working_joe/task_update/day_never_done
+ key = "dayneverdone"
+ sound = 'sound/voice/joe/day_never_done.ogg'
+ say_message = "A synthetic's day is never done."
+ emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
+
+/datum/emote/living/carbon/human/synthetic/working_joe/task_update/required_by_apollo
+ key = "requiredbyapollo"
+ sound = 'sound/voice/joe/required_by_apollo.ogg'
+ say_message = "I am required by APOLLO."
+ emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
+
+/datum/emote/living/carbon/human/synthetic/working_joe/task_update/returning_to_tasks
+ key = "returningtotasks"
+ sound = 'sound/voice/joe/returning_to_tasks.ogg'
+ say_message = "Returning to assigned tasks."
+ emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
diff --git a/code/modules/mob/living/carbon/human/species/working_joe/warning.dm b/code/modules/mob/living/carbon/human/species/working_joe/warning.dm
new file mode 100644
index 000000000000..63c7dfadde14
--- /dev/null
+++ b/code/modules/mob/living/carbon/human/species/working_joe/warning.dm
@@ -0,0 +1,92 @@
+/datum/emote/living/carbon/human/synthetic/working_joe/warning
+ category = JOE_EMOTE_CATEGORY_WARNING
+
+/datum/emote/living/carbon/human/synthetic/working_joe/warning/damage
+ key = "damage"
+ sound = 'sound/voice/joe/damage.ogg'
+ say_message = "Do not damage Seegson property."
+ emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
+
+/datum/emote/living/carbon/human/synthetic/working_joe/warning/not_what_i_think
+ key = "notwhatithink"
+ sound = 'sound/voice/joe/not_what_i_think.ogg'
+ say_message = "I hope that's not what I think it is."
+ emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
+
+/datum/emote/living/carbon/human/synthetic/working_joe/warning/fire
+ key = "fire"
+ sound = 'sound/voice/joe/fire.ogg'
+ say_message = "Only wild animals fear fire."
+ emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
+
+/datum/emote/living/carbon/human/synthetic/working_joe/warning/fire_drill
+ key = "firedrill"
+ sound = 'sound/voice/joe/fire_drill.ogg'
+ say_message = "Please congregate at your nearest fire assembly point. This is not a drill; do not panic."
+ emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
+
+/datum/emote/living/carbon/human/synthetic/working_joe/warning/running_accidents
+ key = "runningaccidents"
+ sound = 'sound/voice/joe/running_accidents.ogg'
+ say_message = "Running causes accidents."
+ emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
+
+/datum/emote/living/carbon/human/synthetic/working_joe/warning/that_stings
+ key = "thatstings"
+ sound = 'sound/voice/joe/that_stings.ogg'
+ say_message = "That stings."
+ emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
+
+/datum/emote/living/carbon/human/synthetic/working_joe/warning/irresponsible
+ key = "irresponsible"
+ sound = 'sound/voice/joe/irresponsible.ogg'
+ say_message = "That was irresponsible."
+ emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
+
+/datum/emote/living/carbon/human/synthetic/working_joe/warning/health_risks
+ key = "healthrisks"
+ sound = 'sound/voice/joe/health_risks.ogg'
+ say_message = "These items carry notable health risks."
+ emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
+
+/datum/emote/living/carbon/human/synthetic/working_joe/warning/safety_breach
+ key = "safetybreach"
+ sound = 'sound/voice/joe/safety_breach.ogg'
+ say_message = "This is a breach of multiple safety directives."
+ emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
+
+/datum/emote/living/carbon/human/synthetic/working_joe/warning/this_is_futile
+ key = "thisisfutile"
+ sound = 'sound/voice/joe/this_is_futile.ogg'
+ say_message = "This is futile."
+ emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
+
+/datum/emote/living/carbon/human/synthetic/working_joe/warning/unprotected_flames
+ key = "unprotectedflames"
+ sound = 'sound/voice/joe/unprotected_flames.ogg'
+ say_message = "Unprotected flames are extremely dangerous and entirely unadvisable."
+ emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
+
+/datum/emote/living/carbon/human/synthetic/working_joe/warning/safety
+ key = "safety"
+ sound = 'sound/voice/joe/safety.ogg'
+ say_message = "You and I are going to have a talk about safety."
+ emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
+
+/datum/emote/living/carbon/human/synthetic/working_joe/warning/hysterical
+ key = "hysterical"
+ sound = 'sound/voice/joe/hysterical.ogg'
+ say_message = "You are becoming hysterical."
+ emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
+
+/datum/emote/living/carbon/human/synthetic/working_joe/warning/dangerous_items
+ key = "dangerousitems"
+ sound = 'sound/voice/joe/dangerous_items.ogg'
+ say_message = "You are carrying some very dangerous items."
+ emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
+
+/datum/emote/living/carbon/human/synthetic/working_joe/warning/patience
+ key = "patience"
+ sound = 'sound/voice/joe/patience.ogg'
+ say_message = "You are starting to test my patience."
+ emote_type = EMOTE_AUDIBLE|EMOTE_VISIBLE
diff --git a/code/modules/mob/living/carbon/human/species/zombie.dm b/code/modules/mob/living/carbon/human/species/zombie.dm
index 2c9c423c671e..532d9413102c 100644
--- a/code/modules/mob/living/carbon/human/species/zombie.dm
+++ b/code/modules/mob/living/carbon/human/species/zombie.dm
@@ -102,6 +102,8 @@
if(zombie.client)
zombie.play_screen_text("You are dead...
You lost your head. No reviving for you.", /atom/movable/screen/text/screen_text/command_order, rgb(155, 0, 200))
to_chat(zombie, SPAN_XENOWARNING("You fall... headless, you will no longer rise."))
+ zombie.undefibbable = TRUE // really only for weed_food
+ SEND_SIGNAL(zombie, COMSIG_HUMAN_SET_UNDEFIBBABLE)
/datum/species/zombie/handle_dead_death(mob/living/carbon/human/zombie, gibbed)
if(gibbed)
@@ -144,6 +146,9 @@
return static_tab_items
/datum/species/zombie/handle_head_loss(mob/living/carbon/human/zombie)
+ if(!zombie.undefibbable)
+ zombie.undefibbable = TRUE // really only for weed_food
+ SEND_SIGNAL(zombie, COMSIG_HUMAN_SET_UNDEFIBBABLE)
if(WEAKREF(zombie) in to_revive)
remove_from_revive(zombie)
var/client/receiving_client = zombie.client
diff --git a/code/modules/mob/living/carbon/xenomorph/Facehuggers.dm b/code/modules/mob/living/carbon/xenomorph/Facehuggers.dm
index 8b3b1d54f26d..5ef9626620b2 100644
--- a/code/modules/mob/living/carbon/xenomorph/Facehuggers.dm
+++ b/code/modules/mob/living/carbon/xenomorph/Facehuggers.dm
@@ -191,9 +191,9 @@
return FALSE
/obj/item/clothing/mask/facehugger/launch_towards(datum/launch_metadata/LM)
- ..()
if(stat == CONSCIOUS)
icon_state = "[initial(icon_state)]_thrown"
+ ..()
/obj/item/clothing/mask/facehugger/launch_impact(atom/hit_atom)
. = ..()
@@ -240,8 +240,8 @@
if(!target)
return FALSE
- target.visible_message(SPAN_WARNING("\The scuttling [src] leaps at [target]!"), \
- SPAN_WARNING("The scuttling [src] leaps at [target]!"))
+ target.visible_message(SPAN_WARNING("[src] leaps at [target]!"), \
+ SPAN_WARNING("[src] leaps at [target]!"))
leaping = TRUE
throw_atom(target, 3, SPEED_FAST)
return TRUE
diff --git a/code/modules/mob/living/carbon/xenomorph/XenoProcs.dm b/code/modules/mob/living/carbon/xenomorph/XenoProcs.dm
index 22cb816f865b..09fdb42ad5c3 100644
--- a/code/modules/mob/living/carbon/xenomorph/XenoProcs.dm
+++ b/code/modules/mob/living/carbon/xenomorph/XenoProcs.dm
@@ -712,6 +712,10 @@
to_chat(src, SPAN_XENONOTICE("This is not a host."))
return
+ if(current_mob.stat == DEAD)
+ to_chat(src, SPAN_XENONOTICE("This host is dead."))
+ return
+
var/mob/living/carbon/human/host_to_nest = current_mob
var/found_grab = FALSE
diff --git a/code/modules/mob/living/carbon/xenomorph/abilities/general_powers.dm b/code/modules/mob/living/carbon/xenomorph/abilities/general_powers.dm
index fbf7d993a067..4a57c0729b91 100644
--- a/code/modules/mob/living/carbon/xenomorph/abilities/general_powers.dm
+++ b/code/modules/mob/living/carbon/xenomorph/abilities/general_powers.dm
@@ -1000,7 +1000,10 @@
if(blunt_stab)
stabbing_xeno.visible_message(SPAN_XENOWARNING("\The [stabbing_xeno] swipes its tail into [target]'s [limb ? limb.display_name : "chest"], bashing it!"), SPAN_XENOWARNING("You swipe your tail into [target]'s [limb? limb.display_name : "chest"], bashing it!"))
- playsound(target, "punch", 50, TRUE)
+ if(prob(1))
+ playsound(target, 'sound/effects/comical_bonk.ogg', 50, TRUE)
+ else
+ playsound(target, "punch", 50, TRUE)
// The xeno smashes the target with their tail, moving it to the side and thus their direction as well.
stab_direction = turn(stabbing_xeno.dir, pick(90, -90))
stab_overlay = "slam"
diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Larva.dm b/code/modules/mob/living/carbon/xenomorph/castes/Larva.dm
index 3f65be228443..82d80752ec54 100644
--- a/code/modules/mob/living/carbon/xenomorph/castes/Larva.dm
+++ b/code/modules/mob/living/carbon/xenomorph/castes/Larva.dm
@@ -138,6 +138,9 @@
else
icon_state = "[state_override || state]Larva"
+/mob/living/carbon/xenomorph/larva/alter_ghost(mob/dead/observer/ghost)
+ ghost.icon_state = "[caste.caste_type]"
+
/mob/living/carbon/xenomorph/larva/handle_name()
return
diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Queen.dm b/code/modules/mob/living/carbon/xenomorph/castes/Queen.dm
index 93b6d230b198..ac975835b21f 100644
--- a/code/modules/mob/living/carbon/xenomorph/castes/Queen.dm
+++ b/code/modules/mob/living/carbon/xenomorph/castes/Queen.dm
@@ -940,3 +940,7 @@
// Switch icon back and then let normal icon behavior happen
Queen.icon = Queen.queen_standing_icon
+
+/mob/living/carbon/xenomorph/queen/alter_ghost(mob/dead/observer/ghost)
+ ghost.icon = queen_standing_icon
+ return ..()
diff --git a/code/modules/mob/living/carbon/xenomorph/death.dm b/code/modules/mob/living/carbon/xenomorph/death.dm
index fe4b4cca2fb1..e3a69da23262 100644
--- a/code/modules/mob/living/carbon/xenomorph/death.dm
+++ b/code/modules/mob/living/carbon/xenomorph/death.dm
@@ -50,7 +50,7 @@
new_xeno.generate_name()
if(!SSticker.mode.transfer_xeno(xeno_candidate, new_xeno))
qdel(new_xeno)
- return
+ break
new_xeno.visible_message(SPAN_XENODANGER("A larva suddenly burrows out of the ground!"),
SPAN_XENODANGER("You burrow out of the ground after feeling an immense tremor through the hive, which quickly fades into complete silence..."))
@@ -105,6 +105,11 @@
GLOB.hive_datum[hivenumber].stored_larva++
GLOB.hive_datum[hivenumber].hive_ui.update_burrowed_larva()
+ if(hardcore)
+ QDEL_IN(src, 3 SECONDS)
+ //else if(!gibbed) // At the moment we only support humans
+ //AddComponent(/datum/component/weed_food)
+
if(hive)
hive.remove_xeno(src)
// Finding the last xeno for anti-delay.
@@ -125,9 +130,6 @@
to_chat(X, SPAN_XENOANNOUNCE("Your carapace rattles with dread. You are all that remains of the hive!"))
announce_dchat("There is only one Xenomorph left: [X.name].", X)
- if(hardcore)
- QDEL_IN(src, 3 SECONDS)
-
SEND_GLOBAL_SIGNAL(COMSIG_GLOB_XENO_DEATH, src, gibbed)
/mob/living/carbon/xenomorph/gib(datum/cause_data/cause = create_cause_data("gibbing", src))
diff --git a/code/modules/power/port_gen.dm b/code/modules/power/port_gen.dm
index 5a335002d71d..6a20e9cfe78e 100644
--- a/code/modules/power/port_gen.dm
+++ b/code/modules/power/port_gen.dm
@@ -264,7 +264,7 @@ display round(lastgen) and phorontank amount
to_chat(user, SPAN_NOTICE(" You open the access panel."))
else
to_chat(user, SPAN_NOTICE(" You close the access panel."))
- else if(istype(O, /obj/item/tool/crowbar) && open)
+ else if(HAS_TRAIT(O, TRAIT_TOOL_CROWBAR) && open)
var/obj/structure/machinery/constructable_frame/new_frame = new /obj/structure/machinery/constructable_frame(src.loc)
for(var/obj/item/I in component_parts)
if(I.reliability < 100)
diff --git a/code/modules/projectiles/magazines/pistols.dm b/code/modules/projectiles/magazines/pistols.dm
index 16090d9f2b81..317124955cbc 100644
--- a/code/modules/projectiles/magazines/pistols.dm
+++ b/code/modules/projectiles/magazines/pistols.dm
@@ -8,7 +8,7 @@
caliber = "9mm"
icon = 'icons/obj/items/weapons/guns/ammo_by_faction/uscm.dmi'
icon_state = "m4a3"
- max_rounds = 9
+ max_rounds = 12
w_class = SIZE_SMALL
default_ammo = /datum/ammo/bullet/pistol
gun_type = /obj/item/weapon/gun/pistol/m4a3
diff --git a/code/modules/reagents/chemistry_machinery/chem_dispenser.dm b/code/modules/reagents/chemistry_machinery/chem_dispenser.dm
index 8de20ca2b79a..09d46aa8c053 100644
--- a/code/modules/reagents/chemistry_machinery/chem_dispenser.dm
+++ b/code/modules/reagents/chemistry_machinery/chem_dispenser.dm
@@ -1,5 +1,6 @@
/obj/structure/machinery/chem_dispenser
- name = "chem dispenser"
+ name = "chemical dispenser"
+ desc = "A complex machine for mixing elements into chemicals. A Wey-Yu product."
density = TRUE
anchored = TRUE
icon = 'icons/obj/structures/machinery/science_machines.dmi'
diff --git a/code/modules/shuttle/computers/dropship_computer.dm b/code/modules/shuttle/computers/dropship_computer.dm
index ea4a7fdbc79d..50449b32fcb9 100644
--- a/code/modules/shuttle/computers/dropship_computer.dm
+++ b/code/modules/shuttle/computers/dropship_computer.dm
@@ -1,6 +1,6 @@
/obj/structure/machinery/computer/shuttle/dropship/flight
name = "dropship navigation computer"
- desc = "flight computer for dropship"
+ desc = "A flight computer that can be used for autopilot or long-range flights."
icon = 'icons/obj/structures/machinery/shuttle-parts.dmi'
icon_state = "console"
req_one_access = list(ACCESS_MARINE_LEADER, ACCESS_MARINE_DROPSHIP)
diff --git a/code/modules/unit_tests/_unit_tests.dm b/code/modules/unit_tests/_unit_tests.dm
index be92afffb898..010cba770ce2 100644
--- a/code/modules/unit_tests/_unit_tests.dm
+++ b/code/modules/unit_tests/_unit_tests.dm
@@ -85,6 +85,7 @@
#include "unit_test.dm"
#include "spawn_humans.dm"
#include "check_runtimes.dm"
+#include "wj_emotes.dm"
#undef TEST_ASSERT
#undef TEST_ASSERT_EQUAL
diff --git a/code/modules/unit_tests/wj_emotes.dm b/code/modules/unit_tests/wj_emotes.dm
new file mode 100644
index 000000000000..f89757665011
--- /dev/null
+++ b/code/modules/unit_tests/wj_emotes.dm
@@ -0,0 +1,7 @@
+/// Test that all working joe emotes have a category
+/datum/unit_test/wj_emotes
+
+/datum/unit_test/wj_emotes/Run()
+ for(var/datum/emote/living/carbon/human/synthetic/working_joe/emote as anything in subtypesof(/datum/emote/living/carbon/human/synthetic/working_joe))
+ if(!initial(emote.category))
+ TEST_FAIL("Emote [emote] did not have a category!")
diff --git a/colonialmarines.dme b/colonialmarines.dme
index 204c144c8916..304d5221ddd3 100644
--- a/colonialmarines.dme
+++ b/colonialmarines.dme
@@ -111,6 +111,7 @@
#include "code\__DEFINES\vv.dm"
#include "code\__DEFINES\weapon_stats.dm"
#include "code\__DEFINES\weather.dm"
+#include "code\__DEFINES\wj_emotes.dm"
#include "code\__DEFINES\xeno.dm"
#include "code\__DEFINES\dcs\flags.dm"
#include "code\__DEFINES\dcs\helpers.dm"
@@ -370,6 +371,7 @@
#include "code\datums\components\speed_modifier.dm"
#include "code\datums\components\toxin_buildup.dm"
#include "code\datums\components\weed_damage_reduction.dm"
+#include "code\datums\components\weed_food.dm"
#include "code\datums\components\xeno\shield_slash.dm"
#include "code\datums\construction\construction_template.dm"
#include "code\datums\construction\xenomorph\construction_template_xenomorph.dm"
@@ -1780,7 +1782,6 @@
#include "code\modules\mob\living\carbon\human\powers\human_powers.dm"
#include "code\modules\mob\living\carbon\human\powers\issue_order.dm"
#include "code\modules\mob\living\carbon\human\species\emote-monkey.dm"
-#include "code\modules\mob\living\carbon\human\species\emote-synthetic.dm"
#include "code\modules\mob\living\carbon\human\species\emote-yautja.dm"
#include "code\modules\mob\living\carbon\human\species\human.dm"
#include "code\modules\mob\living\carbon\human\species\monkey.dm"
@@ -1788,6 +1789,16 @@
#include "code\modules\mob\living\carbon\human\species\synthetic.dm"
#include "code\modules\mob\living\carbon\human\species\yautja.dm"
#include "code\modules\mob\living\carbon\human\species\zombie.dm"
+#include "code\modules\mob\living\carbon\human\species\working_joe\_emote.dm"
+#include "code\modules\mob\living\carbon\human\species\working_joe\_species.dm"
+#include "code\modules\mob\living\carbon\human\species\working_joe\farewell.dm"
+#include "code\modules\mob\living\carbon\human\species\working_joe\greeting.dm"
+#include "code\modules\mob\living\carbon\human\species\working_joe\notice.dm"
+#include "code\modules\mob\living\carbon\human\species\working_joe\question.dm"
+#include "code\modules\mob\living\carbon\human\species\working_joe\quip.dm"
+#include "code\modules\mob\living\carbon\human\species\working_joe\restricted_area.dm"
+#include "code\modules\mob\living\carbon\human\species\working_joe\task_update.dm"
+#include "code\modules\mob\living\carbon\human\species\working_joe\warning.dm"
#include "code\modules\mob\living\carbon\xenomorph\Abilities.dm"
#include "code\modules\mob\living\carbon\xenomorph\attack_alien.dm"
#include "code\modules\mob\living\carbon\xenomorph\damage_procs.dm"
diff --git a/html/changelogs/AutoChangeLog-pr-3645.yml b/html/changelogs/AutoChangeLog-pr-3645.yml
new file mode 100644
index 000000000000..f959710b689e
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-3645.yml
@@ -0,0 +1,5 @@
+author: "Khadd"
+delete-after: True
+changes:
+ - rscadd: "added a iv tube between the user and the bloodpack / iv drip"
+ - imageadd: "sprites for the iv tube"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-3685.yml b/html/changelogs/AutoChangeLog-pr-3685.yml
deleted file mode 100644
index efffe192d42e..000000000000
--- a/html/changelogs/AutoChangeLog-pr-3685.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Newyearnewme, Morrow"
-delete-after: True
-changes:
- - rscadd: "Xeno structures/weeds now become forsaken after hijack"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-3709.yml b/html/changelogs/AutoChangeLog-pr-3709.yml
deleted file mode 100644
index 8e7d2c05c803..000000000000
--- a/html/changelogs/AutoChangeLog-pr-3709.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-author: "Drathek"
-delete-after: True
-changes:
- - balance: "Gardener's hardy weeds now upgrade normal weeds (just like hive weeds upgrade weeds)."
- - balance: "Gardener's hardy weeds now don't prevent special structures (core and pylons) but they are still only allowed if the turf allows them."
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-3728.yml b/html/changelogs/AutoChangeLog-pr-3728.yml
deleted file mode 100644
index ed15d5da7b63..000000000000
--- a/html/changelogs/AutoChangeLog-pr-3728.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Steelpoint"
-delete-after: True
-changes:
- - imageadd: "Synth utility vest is now slimmer in appearance"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-3741.yml b/html/changelogs/AutoChangeLog-pr-3741.yml
deleted file mode 100644
index 40678f6790a2..000000000000
--- a/html/changelogs/AutoChangeLog-pr-3741.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "thatoneyeeter"
-delete-after: True
-changes:
- - balance: "metal foam now becomes solid faster"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-3755.yml b/html/changelogs/AutoChangeLog-pr-3755.yml
deleted file mode 100644
index c2a183d77700..000000000000
--- a/html/changelogs/AutoChangeLog-pr-3755.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "realforest2001"
-delete-after: True
-changes:
- - admin: "Adds logs for bioscans successfully completing."
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-3765.yml b/html/changelogs/AutoChangeLog-pr-3765.yml
deleted file mode 100644
index a52472ec8b42..000000000000
--- a/html/changelogs/AutoChangeLog-pr-3765.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-author: "Drathek"
-delete-after: True
-changes:
- - balance: "Weed nodes can no longer be placed in walls or window frames (or any turf or structure with density)"
- - refactor: "Refactored the plant weeds ability code"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-3790.yml b/html/changelogs/AutoChangeLog-pr-3790.yml
deleted file mode 100644
index 369a2ae3bf62..000000000000
--- a/html/changelogs/AutoChangeLog-pr-3790.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-author: "BeagleGaming1"
-delete-after: True
-changes:
- - code_imp: "evacuation pod crash chance changed to a var"
- - code_imp: "proc added to force evacuation pods to crash"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-3792.yml b/html/changelogs/AutoChangeLog-pr-3792.yml
new file mode 100644
index 000000000000..1a49d8916a87
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-3792.yml
@@ -0,0 +1,4 @@
+author: "Zonespace27"
+delete-after: True
+changes:
+ - rscadd: "Working Joes now have an emote panel to use voice lines, accessible as an action button."
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-3793.yml b/html/changelogs/AutoChangeLog-pr-3793.yml
deleted file mode 100644
index 6702f7cab39b..000000000000
--- a/html/changelogs/AutoChangeLog-pr-3793.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Drathek"
-delete-after: True
-changes:
- - bugfix: "Fixed more broken logos (primarily WY research papers)"
\ No newline at end of file
diff --git a/html/changelogs/archive/2023-07.yml b/html/changelogs/archive/2023-07.yml
index bba1c604b538..f4cfd2ce189e 100644
--- a/html/changelogs/archive/2023-07.yml
+++ b/html/changelogs/archive/2023-07.yml
@@ -53,3 +53,66 @@
- rscadd: CMB/Anchorpoint Marines get bandages to stop bleeding.
harryob:
- rscadd: all xenos can now access the tacmap, while the queen is on ovi
+2023-07-06:
+ BeagleGaming1:
+ - code_imp: evacuation pod crash chance changed to a var
+ - code_imp: proc added to force evacuation pods to crash
+ Drathek:
+ - bugfix: Fixed more broken logos (primarily WY research papers)
+ - balance: Weed nodes can no longer be placed in walls or window frames (or any
+ turf or structure with density)
+ - refactor: Refactored the plant weeds ability code
+ - balance: Gardener's hardy weeds now upgrade normal weeds (just like hive weeds
+ upgrade weeds).
+ - balance: Gardener's hardy weeds now don't prevent special structures (core and
+ pylons) but they are still only allowed if the turf allows them.
+ Newyearnewme, Morrow:
+ - rscadd: Xeno structures/weeds now become forsaken after hijack
+ Steelpoint:
+ - imageadd: Synth utility vest is now slimmer in appearance
+ realforest2001:
+ - admin: Adds logs for bioscans successfully completing.
+ thatoneyeeter:
+ - balance: metal foam now becomes solid faster
+2023-07-07:
+ Diegoflores31:
+ - rscadd: Defender Tail Slam has a 1% chance to do a BONK sound instead.
+ Drathek:
+ - bugfix: Fixed ghost icons for larva and ovi queen
+ Morrow:
+ - rscdel: Removes fountain pens from gear sets
+ - rscdel: Removed nesting the dead
+ - rscadd: Added a visiting USASF Commander (CO survivor) to New Varadero
+ - bugfix: Burnt matches no longer permanently give you a light source if they naturally
+ burn out
+ QuickLoad:
+ - balance: Colony Synthetics are faster but are less resistant. This allows for
+ the option of avoiding engagements.
+ - balance: Colony Synthetics have slightly better CQC and can carry people better.
+ realforest2001:
+ - bugfix: Fixes Queen making footstep sounds while dead and being dragged.
+2023-07-08:
+ Ben10083:
+ - bugfix: Working Joes can no longer have a gradient on their rare hair spawn.
+ - rscdel: Working Joes can no longer be fed.
+ - code_imp: 'New trait: Cannot eat. Self-explanatory.'
+ Cursor:
+ - spellcheck: Changed Chem Dispenser to Chemical Dispenser, added descriptions to
+ the cryo cell, rail computer and chemical dispenser. Updated the descriptions
+ for the Blood Dispenser and Dropship computer.
+ Drathek:
+ - bugfix: Fixed facehuggers incorrectly displaying thrown state when it has landed
+ Drathek Kugamo:
+ - rscadd: Added the ability for weeds to merge with unrevivable corpses
+ - imageadd: Added human shaped weeds by Kugamo
+ - code_imp: Added a signal for weeds sent to the turf to indicate it is now weeded,
+ and added a signal for afterbuckle.
+ - bugfix: Closets (including coffins) can no longer move anchored mobs.
+ Morrow:
+ - qol: Create humans tab length increase
+ - qol: Create humans tab now defaults to 0 range to spawn
+ - bugfix: Fixed extraneous messages in regards to wall nests
+ SpartanBobby:
+ - balance: changes M4A3 magazine size from 9 to 12
+ Zonespace27:
+ - bugfix: The maintenance jack should work a little better at crowbarring things.
diff --git a/html/create_humans.html b/html/create_humans.html
index ed9361fc6f25..06b92cba0c71 100644
--- a/html/create_humans.html
+++ b/html/create_humans.html
@@ -11,7 +11,7 @@
Amount of humans:
- Range to spawn in:
+ Range to spawn in:
Spawn mobs as:
Regular
diff --git a/icons/effects/beam.dmi b/icons/effects/beam.dmi
index 704c0ad1c02c..d6ee40cf7fe8 100644
Binary files a/icons/effects/beam.dmi and b/icons/effects/beam.dmi differ
diff --git a/icons/mob/hud/actions.dmi b/icons/mob/hud/actions.dmi
index 1692879116dc..4d0697733207 100644
Binary files a/icons/mob/hud/actions.dmi and b/icons/mob/hud/actions.dmi differ
diff --git a/icons/mob/xenos/weeds.dmi b/icons/mob/xenos/weeds.dmi
index 8eb4b2203cf6..0b9403058109 100644
Binary files a/icons/mob/xenos/weeds.dmi and b/icons/mob/xenos/weeds.dmi differ
diff --git a/maps/new_varadero.json b/maps/new_varadero.json
index d9d6a0d231cc..9a0bf5d56be1 100644
--- a/maps/new_varadero.json
+++ b/maps/new_varadero.json
@@ -13,6 +13,9 @@
"/datum/equipment_preset/survivor/security/lv",
"/datum/equipment_preset/survivor/colonial_marshal/lv"
],
+ "CO_survivor_types": [
+ "/datum/equipment_preset/survivor/new_varadero/commander"
+ ],
"defcon_triggers": [
3300,
diff --git a/sound/effects/comical_bonk.ogg b/sound/effects/comical_bonk.ogg
new file mode 100644
index 000000000000..e0a2751d52c2
Binary files /dev/null and b/sound/effects/comical_bonk.ogg differ
diff --git a/tgui/packages/tgui/interfaces/JoeEmotes.tsx b/tgui/packages/tgui/interfaces/JoeEmotes.tsx
new file mode 100644
index 000000000000..acd37de34978
--- /dev/null
+++ b/tgui/packages/tgui/interfaces/JoeEmotes.tsx
@@ -0,0 +1,110 @@
+import { useBackend, useLocalState } from '../backend';
+import { Box, Button, Divider, Section, Stack, Tabs } from '../components';
+import { Window } from '../layouts';
+import { BooleanLike } from '../../common/react';
+
+type Emote = {
+ id: string;
+ text: string;
+ category: string;
+ path: string;
+};
+
+type BackendContext = {
+ categories: string[];
+ emotes: Emote[];
+ on_cooldown: BooleanLike;
+};
+
+const EmoteTab = (props, context) => {
+ const { data, act } = useBackend(context);
+ const { categories, emotes, on_cooldown } = data;
+ const [categoryIndex, setCategoryIndex] = useLocalState(
+ context,
+ 'category_index',
+ 'Farewell'
+ );
+ const mapped_emote = emotes.filter(
+ (emote) => emote && emote.category === categoryIndex
+ );
+ return (
+
+
+
+
+ {categories.map((item, key) => (
+ {
+ setCategoryIndex(item);
+ }}>
+ {item}
+
+ ))}
+
+
+
+
+
+
+
+ {mapped_emote.map((item) => (
+
+
+ {' '}
+
+
+
+
+
+
+
+
+ ))}
+
+
+
+
+ );
+};
+
+export const JoeEmotes = (props, context) => {
+ return (
+
+
+
+
+
+ );
+};