diff --git a/_maps/RandomRuins/SpaceRuins/derelict4.dmm b/_maps/RandomRuins/SpaceRuins/derelict4.dmm
index 91026d9c13a..7595c68e2ab 100644
--- a/_maps/RandomRuins/SpaceRuins/derelict4.dmm
+++ b/_maps/RandomRuins/SpaceRuins/derelict4.dmm
@@ -83,9 +83,7 @@
/turf/open/floor/plating/airless,
/area/ruin/space/has_grav)
"O" = (
-/obj/machinery/power/apc/auto_name/directional/north{
- start_charge = 0
- },
+/obj/item/wallframe/apc,
/turf/open/floor/plating/airless,
/area/ruin/space/has_grav)
"Q" = (
diff --git a/_maps/RandomRuins/SpaceRuins/derelict8.dmm b/_maps/RandomRuins/SpaceRuins/derelict8.dmm
index d48675a5047..19725925332 100644
--- a/_maps/RandomRuins/SpaceRuins/derelict8.dmm
+++ b/_maps/RandomRuins/SpaceRuins/derelict8.dmm
@@ -305,7 +305,7 @@
"SL" = (
/obj/effect/spawner/random/trash/mess,
/obj/structure/cable,
-/obj/machinery/power/apc/auto_name/directional/west,
+/obj/item/wallframe/apc,
/turf/open/floor/plating/airless,
/area/ruin/space/has_grav)
"SQ" = (
diff --git a/_maps/RandomRuins/SpaceRuins/russian_derelict.dmm b/_maps/RandomRuins/SpaceRuins/russian_derelict.dmm
index a7c5c7aa902..a80bb186c12 100644
--- a/_maps/RandomRuins/SpaceRuins/russian_derelict.dmm
+++ b/_maps/RandomRuins/SpaceRuins/russian_derelict.dmm
@@ -438,9 +438,9 @@
/area/ruin/space/ks13/medical/medbay)
"fH" = (
/obj/machinery/door/morgue{
- name = "Chaplains Office"
+ name = "Chaplains Office";
+ req_access = list("chapel_office")
},
-/obj/effect/mapping_helpers/airlock/access/all/service/chapel_office,
/turf/open/floor/iron/dark,
/area/ruin/space/ks13/service/chapel_office)
"fJ" = (
diff --git a/_maps/shuttles/whiteship_pubby.dmm b/_maps/shuttles/whiteship_pubby.dmm
index 7081975410e..ffb1efd2e98 100644
--- a/_maps/shuttles/whiteship_pubby.dmm
+++ b/_maps/shuttles/whiteship_pubby.dmm
@@ -88,7 +88,6 @@
dir = 1;
piping_layer = 4
},
-/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
/obj/effect/decal/cleanable/dirt,
/turf/open/floor/plating,
/area/shuttle/abandoned)
@@ -755,7 +754,6 @@
/obj/effect/turf_decal/trimline/purple/filled/corner{
dir = 1
},
-/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden,
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
/turf/open/floor/plating,
/area/shuttle/abandoned)
diff --git a/code/__DEFINES/access.dm b/code/__DEFINES/access.dm
index b0ed33e00f2..15de8baf394 100644
--- a/code/__DEFINES/access.dm
+++ b/code/__DEFINES/access.dm
@@ -550,7 +550,7 @@
/obj/item/modular_computer/pda/cargo = list(REGION_SUPPLY), \
/obj/item/modular_computer/pda/shaftminer = list(REGION_SUPPLY), \
/obj/item/modular_computer/pda/chaplain = list(REGION_GENERAL), \
- /obj/item/modular_computer/pda/lawyer = list(REGION_GENERAL, REGION_SECURITY), \
+ /obj/item/modular_computer/pda/lawyer = list(REGION_GENERAL), \
/obj/item/modular_computer/pda/botanist = list(REGION_GENERAL), \
/obj/item/modular_computer/pda/roboticist = list(REGION_RESEARCH), \
/obj/item/modular_computer/pda/curator = list(REGION_GENERAL), \
diff --git a/code/__DEFINES/dcs/flags.dm b/code/__DEFINES/dcs/flags.dm
index fef738e4111..3f3db0212b6 100644
--- a/code/__DEFINES/dcs/flags.dm
+++ b/code/__DEFINES/dcs/flags.dm
@@ -30,6 +30,13 @@
#define COMPONENT_DUPE_ALLOWED 1
/// new component is deleted
#define COMPONENT_DUPE_UNIQUE 2
+/**
+ * Component uses source tracking to manage adding and removal logic.
+ * Add a source/spawn to/the component by using AddComponentFrom(source, component_type, args...)
+ * Only the first args will be respected, and you should instead handle most of your logic in the on_source_added proc.
+ * Removing the last source will automatically remove the component from the parent.
+ */
+#define COMPONENT_DUPE_SOURCES 3
/// old component is given the initialization args of the new
#define COMPONENT_DUPE_UNIQUE_PASSARGS 4
/// each component of the same type is consulted as to whether the duplicate should be allowed
diff --git a/code/__DEFINES/dcs/helpers.dm b/code/__DEFINES/dcs/helpers.dm
index 56ea5370c4a..a8dc3865702 100644
--- a/code/__DEFINES/dcs/helpers.dm
+++ b/code/__DEFINES/dcs/helpers.dm
@@ -18,5 +18,9 @@
/// A wrapper for _AddComponent that allows us to pretend we're using normal named arguments
#define AddComponent(arguments...) _AddComponent(list(##arguments))
+/// A wrapper for _AddComonent that passes in a source.
+/// Necessary if dupe_mode is set to COMPONENT_DUPE_SOURCES.
+#define AddComponentFrom(source, arguments...) _AddComponent(list(##arguments), source)
+
/// A wrapper for _LoadComponent that allows us to pretend we're using normal named arguments
#define LoadComponent(arguments...) _LoadComponent(list(##arguments))
diff --git a/code/__DEFINES/role_preferences.dm b/code/__DEFINES/role_preferences.dm
index a4f57ccfadb..42f64edc0f1 100644
--- a/code/__DEFINES/role_preferences.dm
+++ b/code/__DEFINES/role_preferences.dm
@@ -41,9 +41,9 @@
#define ROLE_SPIDER "Spider"
#define ROLE_WIZARD_MIDROUND "Wizard (Midround)"
//SKYRAT EDIT START
-#define ROLE_LONE_INFILTRATOR "Lone Infiltrator"
#define ROLE_BORER "Borer"
#define ROLE_DRIFTING_CONTRACTOR "Drifting Contractor"
+#define ROLE_LONE_INFILTRATOR "Lone Infiltrator"
#define ROLE_MUTANT "Mutated Abomination"
#define ROLE_CLOCK_CULTIST "Clock Cultist"
// SKYRAT EDIT END
@@ -109,7 +109,13 @@
#define ROLE_BATTLECRUISER_CREW "Battlecruiser Crew"
#define ROLE_BATTLECRUISER_CAPTAIN "Battlecruiser Captain"
#define ROLE_VENUSHUMANTRAP "Venus Human Trap"
-
+//SKYRAT EDIT START
+#define ROLE_BLACK_MARKET_DEALER "Black Market Dealer"
+#define ROLE_DS2 "DS2 Syndicate"
+#define ROLE_FREIGHTER_CREW "Freighter Crew"
+#define ROLE_GHOST_CAFE "Ghost Cafe Visitor"
+#define ROLE_PORT_TARKON "Port Tarkon Survivor"
+//SKYRAT EDIT END
/// This defines the antagonists you can operate with in the settings.
/// Keys are the antagonist, values are the number of days since the player's
diff --git a/code/__DEFINES/shuttles.dm b/code/__DEFINES/shuttles.dm
index 1d721ef3f1d..5380268e979 100644
--- a/code/__DEFINES/shuttles.dm
+++ b/code/__DEFINES/shuttles.dm
@@ -29,8 +29,11 @@
//Launching Shuttles to CentCom
#define NOLAUNCH -1
#define UNLAUNCHED 0
+/// This shuttle launched to head to end game (or has arrived there), it will not update further
#define ENDGAME_LAUNCHED 1
#define EARLY_LAUNCHED 2
+/// "Endgame transit" denotes shuttles which "fly into the sunset" when the round ends, such as the whiteship.
+/// These shuttles leave when the main emergency shuttle does but don't dock anywhere (to save space), so this counts as "escaped".
#define ENDGAME_TRANSIT 3
//positive value = cannot puchase
diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm
index 2df788bd364..91d558b7d96 100644
--- a/code/__DEFINES/subsystems.dm
+++ b/code/__DEFINES/subsystems.dm
@@ -278,7 +278,7 @@
#define SSAIR_SUPERCONDUCTIVITY 7
#define SSAIR_PROCESS_ATOMS 8
-//Pipeline rebuild helper defines, these suck but it'll do for now //Fools you actually merged it
+// Pipeline rebuild helper defines, these suck but it'll do for now //Fools you actually merged it
#define SSAIR_REBUILD_PIPELINE 1
#define SSAIR_REBUILD_QUEUE 2
@@ -291,18 +291,18 @@
#define SSWARDROBE_STOCK 1
#define SSWARDROBE_INSPECT 2
-//Wardrobe cache metadata indexes
+// Wardrobe cache metadata indexes
#define WARDROBE_CACHE_COUNT 1
#define WARDROBE_CACHE_LAST_INSPECT 2
#define WARDROBE_CACHE_CALL_INSERT 3
#define WARDROBE_CACHE_CALL_REMOVAL 4
-//Wardrobe preloaded stock indexes
+// Wardrobe preloaded stock indexes
#define WARDROBE_STOCK_CONTENTS 1
#define WARDROBE_STOCK_CALL_INSERT 2
#define WARDROBE_STOCK_CALL_REMOVAL 3
-//Wardrobe callback master list indexes
+// Wardrobe callback master list indexes
#define WARDROBE_CALLBACK_INSERT 1
#define WARDROBE_CALLBACK_REMOVE 2
@@ -315,3 +315,9 @@
/// The timer key used to know how long subsystem initialization takes
#define SS_INIT_TIMER_KEY "ss_init"
+
+// Vote subsystem counting methods
+/// First past the post. One selection per person, and the selection with the most votes wins.
+#define VOTE_COUNT_METHOD_SINGLE 1
+/// Approval voting. Any number of selections per person, and the selection with the most votes wins.
+#define VOTE_COUNT_METHOD_MULTI 2
diff --git a/code/__DEFINES/toys.dm b/code/__DEFINES/toys.dm
index b13b1d18f1d..ffa3ea38861 100644
--- a/code/__DEFINES/toys.dm
+++ b/code/__DEFINES/toys.dm
@@ -5,3 +5,8 @@
#define DICE_BASICALLY_RIGGED 2
/// Dice has a 100% chance to land on a rigged value
#define DICE_TOTALLY_RIGGED 3
+
+/// card is considered face down
+#define CARD_FACEDOWN 0
+/// card is considered face up
+#define CARD_FACEUP 1
diff --git a/code/__HELPERS/game.dm b/code/__HELPERS/game.dm
index 76399cbc7e0..bd12a99efe5 100644
--- a/code/__HELPERS/game.dm
+++ b/code/__HELPERS/game.dm
@@ -68,16 +68,30 @@
return player_mob
return null
-///Returns true if the mob that a player is controlling is alive
+/**
+ * Checks if the passed mind has a mob that is "alive"
+ *
+ * * player_mind - who to check for alive status
+ * * enforce_human - if TRUE, the checks fails if the mind's mob is a silicon, brain, or infectious zombie.
+ *
+ * Returns TRUE if they're alive, FALSE otherwise
+ */
/proc/considered_alive(datum/mind/player_mind, enforce_human = TRUE)
if(player_mind?.current)
if(enforce_human)
- var/mob/living/carbon/human/player_mob
- if(ishuman(player_mind.current))
- player_mob = player_mind.current
- return player_mind.current.stat != DEAD && !issilicon(player_mind.current) && !isbrain(player_mind.current) && (!player_mob || player_mob.dna.species.id != SPECIES_ZOMBIE)
+ var/mob/living/carbon/human/player_mob = player_mind.current
+
+ if(player_mob.stat == DEAD)
+ return FALSE
+ if(issilicon(player_mob) || isbrain(player_mob))
+ return FALSE
+ if(istype(player_mob) && (player_mob.dna?.species?.id == SPECIES_ZOMBIE_INFECTIOUS))
+ return FALSE
+ return TRUE
+
else if(isliving(player_mind.current))
- return player_mind.current.stat != DEAD
+ return (player_mind.current.stat != DEAD)
+
return FALSE
/**
@@ -152,7 +166,7 @@
flick_overlay(image_to_show, viewing, duration)
///Get active players who are playing in the round
-/proc/get_active_player_count(alive_check = 0, afk_check = 0, human_check = 0)
+/proc/get_active_player_count(alive_check = FALSE, afk_check = FALSE, human_check = FALSE)
var/active_players = 0
for(var/i = 1; i <= GLOB.player_list.len; i++)
var/mob/player_mob = GLOB.player_list[i]
diff --git a/code/__HELPERS/roundend.dm b/code/__HELPERS/roundend.dm
index bbcec6418fc..f007d2dc37b 100644
--- a/code/__HELPERS/roundend.dm
+++ b/code/__HELPERS/roundend.dm
@@ -197,7 +197,7 @@
if(!didthegamerwin)
return FALSE
player_client.give_award(/datum/award/score/hardcore_random, human_mob, round(human_mob.hardcore_survival_score * 2))
- else if(human_mob.onCentCom())
+ else if(considered_escaped(human_mob))
player_client.give_award(/datum/award/score/hardcore_random, human_mob, round(human_mob.hardcore_survival_score))
diff --git a/code/controllers/subsystem/job.dm b/code/controllers/subsystem/job.dm
index d2d28fcc1b9..3323db10697 100644
--- a/code/controllers/subsystem/job.dm
+++ b/code/controllers/subsystem/job.dm
@@ -535,7 +535,7 @@ SUBSYSTEM_DEF(job)
SEND_SIGNAL(equipping, COMSIG_JOB_RECEIVED, job)
- equipping.mind?.set_assigned_role_with_greeting(job)
+ equipping.mind?.set_assigned_role_with_greeting(job, player_client)
if(player_client)
to_chat(player_client, span_infoplain("You are the [chosen_title].")) // SKYRAT EDIT CHANGE - ALTERNATIVE_JOB_TITLES - Original: to_chat(player_client, span_infoplain("You are the [job.title]."))
diff --git a/code/controllers/subsystem/vote.dm b/code/controllers/subsystem/vote.dm
index f0b9cd45a7b..15a4aed4adb 100644
--- a/code/controllers/subsystem/vote.dm
+++ b/code/controllers/subsystem/vote.dm
@@ -93,7 +93,10 @@ SUBSYSTEM_DEF(vote)
if (final_winner) // if no one voted final_winner will be null
current_vote.finalize_vote(final_winner)
-/datum/controller/subsystem/vote/proc/submit_vote(mob/voter, their_vote)
+/**
+ * One selection per person, and the selection with the most votes wins.
+ */
+/datum/controller/subsystem/vote/proc/submit_single_vote(mob/voter, their_vote)
if(!current_vote)
return
if(!voter?.ckey)
@@ -111,6 +114,31 @@ SUBSYSTEM_DEF(vote)
current_vote.choices_by_ckey[voter.ckey] = their_vote
current_vote.choices[their_vote]++
+
+ return TRUE
+
+/**
+ * Any number of selections per person, and the selection with the most votes wins.
+ */
+/datum/controller/subsystem/vote/proc/submit_multi_vote(mob/voter, their_vote)
+ if(!current_vote)
+ return
+ if(!voter?.ckey)
+ return
+ if(CONFIG_GET(flag/no_dead_vote) && voter.stat == DEAD && !voter.client?.holder)
+ return
+
+ else
+ voted += voter.ckey
+
+ if(current_vote.choices_by_ckey[voter.ckey + their_vote] == 1)
+ current_vote.choices_by_ckey[voter.ckey + their_vote] = 0
+ current_vote.choices[their_vote]--
+
+ else
+ current_vote.choices_by_ckey[voter.ckey + their_vote] = 1
+ current_vote.choices[their_vote]++
+
return TRUE
/**
@@ -217,10 +245,12 @@ SUBSYSTEM_DEF(vote)
var/is_upper_admin = check_rights_for(user.client, R_ADMIN)
data["user"] = list(
+ "ckey" = user.client?.ckey,
"isLowerAdmin" = is_lower_admin,
"isUpperAdmin" = is_upper_admin,
// What the current user has selected in any ongoing votes.
- "selectedChoice" = current_vote?.choices_by_ckey[user.client?.ckey],
+ "singleSelection" = current_vote?.choices_by_ckey[user.client?.ckey],
+ "multiSelection" = current_vote?.choices_by_ckey,
)
data["voting"]= is_lower_admin ? voting : list()
@@ -250,6 +280,7 @@ SUBSYSTEM_DEF(vote)
"name" = current_vote.name,
"question" = current_vote.override_question,
"timeRemaining" = current_vote.time_remaining,
+ "countMethod" = current_vote.count_method,
"choices" = choices,
"vote" = vote_data,
)
@@ -293,8 +324,11 @@ SUBSYSTEM_DEF(vote)
// meaning you can't spoof initiate a vote you're not supposed to be able to
return initiate_vote(selected, voter.key, voter)
- if("vote")
- return submit_vote(voter, params["voteOption"])
+ if("voteSingle")
+ return submit_single_vote(voter, params["voteOption"])
+
+ if("voteMulti")
+ return submit_multi_vote(voter, params["voteOption"])
/datum/controller/subsystem/vote/ui_close(mob/user)
voting -= user.client?.ckey
diff --git a/code/datums/callback.dm b/code/datums/callback.dm
index 30cca6fd49c..a51639d0b9b 100644
--- a/code/datums/callback.dm
+++ b/code/datums/callback.dm
@@ -67,26 +67,6 @@
arguments = args.Copy(3)
if(usr)
user = WEAKREF(usr)
-/**
- * Immediately Invoke proctocall on thingtocall, with waitfor set to false
- *
- * Arguments:
- * * thingtocall Object to call on
- * * proctocall Proc to call on that object
- * * ... optional list of arguments to pass as arguments to the proc being called
- */
-/world/proc/ImmediateInvokeAsync(thingtocall, proctocall, ...)
- set waitfor = FALSE
-
- if (!thingtocall)
- return
-
- var/list/calling_arguments = length(args) > 2 ? args.Copy(3) : null
-
- if (thingtocall == GLOBAL_PROC)
- call(proctocall)(arglist(calling_arguments))
- else
- call(thingtocall, proctocall)(arglist(calling_arguments))
/**
* Invoke this callback
diff --git a/code/datums/components/_component.dm b/code/datums/components/_component.dm
index 4a812d4f5e5..8cbc4efd329 100644
--- a/code/datums/components/_component.dm
+++ b/code/datums/components/_component.dm
@@ -38,6 +38,9 @@
*/
var/can_transfer = FALSE
+ /// A lazy list of the sources for this component
+ var/list/sources
+
/**
* Create a new component.
*
@@ -165,6 +168,27 @@
/datum/component/proc/UnregisterFromParent()
return
+/**
+ * Called when the component has a new source registered
+ */
+/datum/component/proc/on_source_add(source)
+ SHOULD_CALL_PARENT(TRUE)
+ if(dupe_mode != COMPONENT_DUPE_SOURCES)
+ CRASH("Component '[type]' does not use sources but has been given a source")
+ LAZYOR(sources, source)
+
+/**
+ * Called when the component has a source removed.
+ * You probably want to call parent after you do your logic because at the end of this we qdel if we have no sources remaining!
+ */
+/datum/component/proc/on_source_remove(source)
+ SHOULD_CALL_PARENT(TRUE)
+ if(dupe_mode != COMPONENT_DUPE_SOURCES)
+ CRASH("Component '[type]' does not use sources but is trying to remove a source")
+ LAZYREMOVE(sources, source)
+ if(!LAZYLEN(sources))
+ qdel(src)
+
/**
* Register to listen for a signal from the passed in target
*
@@ -411,74 +435,100 @@
*
* Properly handles duplicate situations based on the `dupe_mode` var
*/
-/datum/proc/_AddComponent(list/raw_args)
- var/new_type = raw_args[1]
- var/datum/component/nt = new_type
+/datum/proc/_AddComponent(list/raw_args, source)
+ var/original_type = raw_args[1]
+ var/datum/component/component_type = original_type
if(QDELING(src))
- CRASH("Attempted to add a new component of type \[[nt]\] to a qdeleting parent of type \[[type]\]!")
+ CRASH("Attempted to add a new component of type \[[component_type]\] to a qdeleting parent of type \[[type]\]!")
- var/dm = initial(nt.dupe_mode)
- var/dt = initial(nt.dupe_type)
+ var/dupe_mode = initial(component_type.dupe_mode)
+ var/dupe_type = initial(component_type.dupe_type)
+ var/uses_sources = (dupe_mode == COMPONENT_DUPE_SOURCES)
+ if(uses_sources && !source)
+ CRASH("Attempted to add a sourced component of type '[component_type]' to '[type]' without a source!")
+ else if(!uses_sources && source)
+ CRASH("Attempted to add a normal component of type '[component_type]' to '[type]' with a source!")
- var/datum/component/old_comp
- var/datum/component/new_comp
+ var/datum/component/old_component
+ var/datum/component/new_component
- if(ispath(nt))
- if(nt == /datum/component)
- CRASH("[nt] attempted instantiation!")
+ if(ispath(component_type))
+ if(component_type == /datum/component)
+ CRASH("[component_type] attempted instantiation!")
else
- new_comp = nt
- nt = new_comp.type
+ new_component = component_type
+ component_type = new_component.type
raw_args[1] = src
-
- if(dm != COMPONENT_DUPE_ALLOWED && dm != COMPONENT_DUPE_SELECTIVE)
- if(!dt)
- old_comp = GetExactComponent(nt)
+ if(dupe_mode != COMPONENT_DUPE_ALLOWED && dupe_mode != COMPONENT_DUPE_SELECTIVE)
+ if(!dupe_type)
+ old_component = GetExactComponent(component_type)
else
- old_comp = GetComponent(dt)
- if(old_comp)
- switch(dm)
+ old_component = GetComponent(dupe_type)
+
+ if(old_component)
+ switch(dupe_mode)
if(COMPONENT_DUPE_UNIQUE)
- if(!new_comp)
- new_comp = new nt(raw_args)
- if(!QDELETED(new_comp))
- old_comp.InheritComponent(new_comp, TRUE)
- QDEL_NULL(new_comp)
+ if(!new_component)
+ new_component = new component_type(raw_args)
+ if(!QDELETED(new_component))
+ old_component.InheritComponent(new_component, TRUE)
+ QDEL_NULL(new_component)
+
if(COMPONENT_DUPE_HIGHLANDER)
- if(!new_comp)
- new_comp = new nt(raw_args)
- if(!QDELETED(new_comp))
- new_comp.InheritComponent(old_comp, FALSE)
- QDEL_NULL(old_comp)
+ if(!new_component)
+ new_component = new component_type(raw_args)
+ if(!QDELETED(new_component))
+ new_component.InheritComponent(old_component, FALSE)
+ QDEL_NULL(old_component)
+
if(COMPONENT_DUPE_UNIQUE_PASSARGS)
- if(!new_comp)
+ if(!new_component)
var/list/arguments = raw_args.Copy(2)
arguments.Insert(1, null, TRUE)
- old_comp.InheritComponent(arglist(arguments))
+ old_component.InheritComponent(arglist(arguments))
else
- old_comp.InheritComponent(new_comp, TRUE)
- else if(!new_comp)
- new_comp = new nt(raw_args) // There's a valid dupe mode but there's no old component, act like normal
- else if(dm == COMPONENT_DUPE_SELECTIVE)
+ old_component.InheritComponent(new_component, TRUE)
+
+ if(COMPONENT_DUPE_SOURCES)
+ if(source in old_component.sources)
+ return old_component // source already registered, no work to do
+ old_component.on_source_add(source)
+
+ else if(!new_component)
+ new_component = new component_type(raw_args) // There's a valid dupe mode but there's no old component, act like normal
+ else if(dupe_mode == COMPONENT_DUPE_SELECTIVE)
var/list/arguments = raw_args.Copy()
- arguments[1] = new_comp
+ arguments[1] = new_component
var/make_new_component = TRUE
- for(var/datum/component/existing_component as anything in GetComponents(new_type))
+ for(var/datum/component/existing_component as anything in GetComponents(original_type))
if(existing_component.CheckDupeComponent(arglist(arguments)))
make_new_component = FALSE
- QDEL_NULL(new_comp)
+ QDEL_NULL(new_component)
break
- if(!new_comp && make_new_component)
- new_comp = new nt(raw_args)
- else if(!new_comp)
- new_comp = new nt(raw_args) // Dupes are allowed, act like normal
+ if(!new_component && make_new_component)
+ new_component = new component_type(raw_args)
+ else if(!new_component)
+ new_component = new component_type(raw_args) // Dupes are allowed, act like normal
- if(!old_comp && !QDELETED(new_comp)) // Nothing related to duplicate components happened and the new component is healthy
- SEND_SIGNAL(src, COMSIG_COMPONENT_ADDED, new_comp)
- return new_comp
- return old_comp
+ if(!old_component && !QDELETED(new_component)) // Nothing related to duplicate components happened and the new component is healthy
+ if(uses_sources) // make sure they have the source added if they use sources
+ new_component.on_source_add(source)
+ SEND_SIGNAL(src, COMSIG_COMPONENT_ADDED, new_component)
+ return new_component
+
+ return old_component
+
+/**
+ * Removes a component source from this datum
+ */
+/datum/proc/RemoveComponentSource(source, datum/component/component_type)
+ if(ispath(component_type))
+ component_type = GetExactComponent(component_type)
+ if(!component_type)
+ CRASH("Attempted to remove a null or non-existent component '[component_type]' from '[type]'")
+ component_type.on_source_remove(source)
/**
* Get existing component of type, or create it and return a reference to it
diff --git a/code/datums/components/action_item_overlay.dm b/code/datums/components/action_item_overlay.dm
index 66d2ec012fb..221fc38775c 100644
--- a/code/datums/components/action_item_overlay.dm
+++ b/code/datums/components/action_item_overlay.dm
@@ -15,6 +15,8 @@
if(!istype(parent, /datum/action))
return COMPONENT_INCOMPATIBLE
+ ASSERT(isnull(item) || istype(item))
+
if(!item && !item_callback)
stack_trace("[type] created without a reference item or an item callback - one or the other is required.")
return COMPONENT_INCOMPATIBLE
@@ -48,13 +50,17 @@
SIGNAL_HANDLER
// We're in the middle of being removed / deleted, remove our associated overlay
- if(QDELING(src) && item_appearance)
- current_button.cut_overlay(item_appearance)
- item_appearance = null
+ if(QDELING(src))
+ if(item_appearance)
+ current_button.cut_overlay(item_appearance)
+ item_appearance = null
return
var/atom/movable/muse = item_callback?.Invoke() || item_ref?.resolve()
if(!istype(muse))
+ if(item_appearance) // New item does not exist but we have an old appearance
+ current_button.cut_overlay(item_appearance)
+ item_appearance = null
return
if(item_appearance)
diff --git a/code/datums/components/construction.dm b/code/datums/components/construction.dm
index 0bf25294a11..e0bac0ddbe7 100644
--- a/code/datums/components/construction.dm
+++ b/code/datums/components/construction.dm
@@ -26,8 +26,9 @@
/datum/component/construction/proc/action(datum/source, obj/item/I, mob/living/user)
SIGNAL_HANDLER
-
- return INVOKE_ASYNC(src, PROC_REF(check_step), I, user)
+ ASYNC //This proc will never actually sleep, it calls do_after with a time of 0.
+ . = check_step(I, user)
+ return .
/datum/component/construction/proc/update_index(diff)
index += diff
diff --git a/code/datums/components/fantasy/suffixes.dm b/code/datums/components/fantasy/suffixes.dm
index 1c49bace23e..4e38d61b0d1 100644
--- a/code/datums/components/fantasy/suffixes.dm
+++ b/code/datums/components/fantasy/suffixes.dm
@@ -76,7 +76,7 @@
// This works even with the species picks since we're only accessing the name
var/obj/item/master = comp.parent
- master.AddElement(/datum/element/bane, picked_mobtype)
+ master.AddElement(/datum/element/bane, target_type = picked_mobtype)
target_types_by_comp[comp] = picked_mobtype
return "[newName] of [initial(picked_mobtype.name)] slaying"
diff --git a/code/datums/components/fertile_egg.dm b/code/datums/components/fertile_egg.dm
new file mode 100644
index 00000000000..8491845d048
--- /dev/null
+++ b/code/datums/components/fertile_egg.dm
@@ -0,0 +1,65 @@
+/**
+ * ### A fertile egg component!
+ *
+ * This component tracks over time if the atom is in ideal conditions,
+ * and eventually hatches into the embryonic type.
+ *
+ * The initial design of this component was to make more generic the code for
+ * chickens laying eggs.
+ */
+/datum/component/fertile_egg
+ /// What will come out of the egg when it's done.
+ var/embryo_type
+
+ /// Minimum growth rate per tick
+ var/minimum_growth_rate
+
+ /// Maximum growth rate per tick
+ var/maximum_growth_rate
+
+ /// Total growth required before hatching.
+ var/total_growth_required
+
+ /// The current amount of growth.
+ var/current_growth
+
+ /// List of locations which, if set, the egg will only develop if in those locations.
+ var/list/location_allowlist
+
+ /// If true, being in an unsuitable location spoils the egg (ie. kills the component). If false, it just pauses the egg's development.
+ var/spoilable
+
+/datum/component/fertile_egg/Initialize(embryo_type, minimum_growth_rate, maximum_growth_rate, total_growth_required, current_growth, location_allowlist, spoilable, examine_message)
+ // Quite how an _area_ can be a fertile egg is an open question, but it still has a location. Technically.
+ if(!isatom(parent))
+ return COMPONENT_INCOMPATIBLE
+
+ src.embryo_type = embryo_type
+ src.minimum_growth_rate = minimum_growth_rate
+ src.maximum_growth_rate = maximum_growth_rate
+ src.total_growth_required = total_growth_required
+ src.current_growth = current_growth
+ src.location_allowlist = location_allowlist
+ src.spoilable = spoilable
+
+ START_PROCESSING(SSobj, src)
+
+/datum/component/fertile_egg/Destroy()
+ STOP_PROCESSING(SSobj, src)
+ . = ..()
+
+/datum/component/fertile_egg/process(delta_time)
+ var/atom/parent_atom = parent
+
+ if(location_allowlist && !is_type_in_typecache(parent_atom.loc, location_allowlist))
+ // In a zone that is not allowed, do nothing, and possibly self destruct
+ if(spoilable)
+ qdel(src)
+ return
+
+ current_growth += rand(minimum_growth_rate, maximum_growth_rate) * delta_time
+ if(current_growth >= total_growth_required)
+ parent_atom.visible_message(span_notice("[parent] hatches with a quiet cracking sound."))
+ new embryo_type(get_turf(parent_atom))
+ // We destroy the parent on hatch, which will destroy the component as well, which will stop us processing.
+ qdel(parent_atom)
diff --git a/code/datums/components/fullauto.dm b/code/datums/components/fullauto.dm
index bc7102b5346..2c5fd79c4fc 100644
--- a/code/datums/components/fullauto.dm
+++ b/code/datums/components/fullauto.dm
@@ -1,4 +1,3 @@
-/* SKYRAT EDIT REMOVAL - MOVED TO MODULAR FULLAUTO.DM
#define AUTOFIRE_MOUSEUP 0
#define AUTOFIRE_MOUSEDOWN 1
@@ -313,4 +312,3 @@
#undef AUTOFIRE_MOUSEUP
#undef AUTOFIRE_MOUSEDOWN
-*/
diff --git a/code/datums/components/payment.dm b/code/datums/components/payment.dm
index b4e5f596b27..81c93af6853 100644
--- a/code/datums/components/payment.dm
+++ b/code/datums/components/payment.dm
@@ -121,7 +121,10 @@
holochange.name = "[holochange.credits] credit holochip"
if(ishuman(user))
var/mob/living/carbon/human/paying_customer = user
- if(!INVOKE_ASYNC(paying_customer, TYPE_PROC_REF(/mob, put_in_hands), holochange))
+ var/successfully_put_in_hands
+ ASYNC //Put_in_hands can sleep, we don't want that to block this proc.
+ successfully_put_in_hands = paying_customer.put_in_hands(holochange)
+ if(!successfully_put_in_hands)
user.pulling = holochange
else
user.pulling = holochange
diff --git a/code/datums/elements/food/food_trash.dm b/code/datums/elements/food/food_trash.dm
index b20a5649a65..6d2b21a400d 100644
--- a/code/datums/elements/food/food_trash.dm
+++ b/code/datums/elements/food/food_trash.dm
@@ -30,7 +30,15 @@
/datum/element/food_trash/Detach(datum/target)
. = ..()
- UnregisterSignal(target, COMSIG_FOOD_CONSUMED)
+ UnregisterSignal(target, list(
+ COMSIG_FOOD_CONSUMED,
+ COMSIG_ITEM_ATTACK_SELF,
+ COMSIG_FOOD_CROSSED,
+ COMSIG_ITEM_ON_GRIND,
+ COMSIG_ITEM_ON_JUICE,
+ COMSIG_ITEM_USED_AS_INGREDIENT,
+ COMSIG_ITEM_ON_COMPOSTED,
+ COMSIG_ITEM_SOLD_TO_CUSTOMER,))
/datum/element/food_trash/proc/generate_trash(datum/source, mob/living/eater, mob/living/feeder)
SIGNAL_HANDLER
@@ -48,6 +56,8 @@
food_holding_mob.dropItemToGround(edible_object)
food_holding_mob.put_in_hands(trash_item)
+ Detach(source)
+
/datum/element/food_trash/proc/food_crossed(datum/source, mob/crosser, bitecount)
SIGNAL_HANDLER
diff --git a/code/datums/elements/frozen.dm b/code/datums/elements/frozen.dm
index 1ef64427e43..3fdf13965cf 100644
--- a/code/datums/elements/frozen.dm
+++ b/code/datums/elements/frozen.dm
@@ -59,7 +59,8 @@ GLOBAL_LIST_INIT(freon_color_matrix, list("#2E5E69", "#60A2A8", "#A1AFB1", rgb(0
SIGNAL_HANDLER
var/obj/obj_target = target
obj_target.visible_message(span_danger("[obj_target] shatters into a million pieces!"))
- qdel(obj_target)
+ obj_target.flags_1 |= NODECONSTRUCT_1 // disable item spawning
+ obj_target.deconstruct(FALSE) // call pre-deletion specialized code -- internals release gas etc
/// signal handler for COMSIG_MOVABLE_MOVED that unfreezes our target if it moves onto an open turf thats hotter than
/// our melting temperature.
diff --git a/code/datums/elements/turf_transparency.dm b/code/datums/elements/turf_transparency.dm
index 731b2a02058..ab3a17dc40d 100644
--- a/code/datums/elements/turf_transparency.dm
+++ b/code/datums/elements/turf_transparency.dm
@@ -96,12 +96,9 @@ GLOBAL_LIST_EMPTY(pillars_by_z)
/// Displays a turf from the z level below us on our level
/datum/z_pillar/proc/display_turf(turf/to_display, turf/source)
var/list/sources = turf_sources[to_display]
- if(!sources)
- sources = list()
- turf_sources[to_display] = sources
- sources |= source
- if(length(sources) != 1) // If we aren't the first to request this turf, return
+ if(sources) // If we aren't the first to request this turf, return
+ sources |= source
var/obj/effect/abstract/z_holder/holding = drawing_object[to_display]
if(!holding)
return
@@ -118,6 +115,11 @@ GLOBAL_LIST_EMPTY(pillars_by_z)
visual_target.vis_contents += to_display
return
+ // Otherwise, we need to create a new set of sources. let's do that yeah?
+ sources = list()
+ turf_sources[to_display] = sources
+ sources |= source
+
var/turf/visual_target = to_display.above()
if(istransparentturf(visual_target) || isopenspaceturf(visual_target))
visual_target.vis_contents += to_display
diff --git a/code/datums/mind/_mind.dm b/code/datums/mind/_mind.dm
index 5c5a6ca09dd..fcd3c5446d5 100644
--- a/code/datums/mind/_mind.dm
+++ b/code/datums/mind/_mind.dm
@@ -510,16 +510,16 @@
/// Sets us to the passed job datum, then greets them to their new job.
/// Use this one for when you're assigning this mind to a new job for the first time,
/// or for when someone's recieving a job they'd really want to be greeted to.
-/datum/mind/proc/set_assigned_role_with_greeting(datum/job/new_role)
+/datum/mind/proc/set_assigned_role_with_greeting(datum/job/new_role, client/incoming_client)
. = set_assigned_role(new_role)
- if(!.)
+ if(assigned_role != new_role)
return
- to_chat(src, span_infoplain("You are the [new_role.title]."))
+ to_chat(incoming_client || src, span_infoplain("You are the [new_role.title]."))
var/related_policy = get_policy(new_role.title)
if(related_policy)
- to_chat(src, related_policy)
+ to_chat(incoming_client || src, related_policy)
/mob/proc/sync_mind()
mind_initialize() //updates the mind (or creates and initializes one if one doesn't exist)
diff --git a/code/datums/votes/_vote_datum.dm b/code/datums/votes/_vote_datum.dm
index 9d9fe09b133..b1560bf8ecd 100644
--- a/code/datums/votes/_vote_datum.dm
+++ b/code/datums/votes/_vote_datum.dm
@@ -28,6 +28,8 @@
var/started_time
/// The time remaining in this vote's run.
var/time_remaining
+ /// The counting method we use for votes.
+ var/count_method = VOTE_COUNT_METHOD_SINGLE
/**
* Used to determine if this vote is a possible
diff --git a/code/datums/votes/custom_vote.dm b/code/datums/votes/custom_vote.dm
index 5f1a1a5996d..534377b3d69 100644
--- a/code/datums/votes/custom_vote.dm
+++ b/code/datums/votes/custom_vote.dm
@@ -1,9 +1,14 @@
/// The max amount of options someone can have in a custom vote.
#define MAX_CUSTOM_VOTE_OPTIONS 10
-/datum/vote/custom_vote
- name = "Custom"
- message = "Click here to start a custom vote."
+/datum/vote/custom_vote/single
+ name = "Custom Standard"
+ message = "Click here to start a custom vote (one selection per voter)"
+
+/datum/vote/custom_vote/multi
+ name = "Custom Multi"
+ message = "Click here to start a custom multi vote (multiple selections per voter)"
+ count_method = VOTE_COUNT_METHOD_MULTI
// Custom votes ares always accessible.
/datum/vote/custom_vote/is_accessible_vote()
diff --git a/code/game/atoms.dm b/code/game/atoms.dm
index 3f6cb01cc3d..79367824e58 100644
--- a/code/game/atoms.dm
+++ b/code/game/atoms.dm
@@ -409,42 +409,36 @@
return !density
/**
- * Is this atom currently located on centcom
+ * Is this atom currently located on centcom (or riding off into the sunset on a shuttle)
*
- * Specifically, is it on the z level and within the centcom areas
- *
- * You can also be in a shuttleshuttle during endgame transit
+ * Specifically, is it on the z level and within the centcom areas.
+ * You can also be in a shuttle during endgame transit.
*
* Used in gamemode to identify mobs who have escaped and for some other areas of the code
* who don't want atoms where they shouldn't be
+ *
+ * Returns TRUE if this atom is on centcom or an escape shuttle, or FALSE if not
*/
/atom/proc/onCentCom()
var/turf/current_turf = get_turf(src)
if(!current_turf)
return FALSE
+ // This doesn't necessarily check that we're at central command,
+ // but it checks for any shuttles which have finished are still in hyperspace
+ // (IE, stuff like the whiteship which fly off into the sunset and "escape")
if(is_reserved_level(current_turf.z))
- for(var/obj/docking_port/mobile/mobile_docking_port as anything in SSshuttle.mobile_docking_ports)
- if(mobile_docking_port.launch_status != ENDGAME_TRANSIT)
- continue
- for(var/area/shuttle/shuttle_area as anything in mobile_docking_port.shuttle_areas)
- if(current_turf in shuttle_area)
- return TRUE
+ return on_escaped_shuttle(ENDGAME_TRANSIT)
- if(!is_centcom_level(current_turf.z))//if not, don't bother
+ // From here on we only concern ourselves with people actually on the centcom Z
+ if(!is_centcom_level(current_turf.z))
return FALSE
- //Check for centcom itself
if(istype(current_turf.loc, /area/centcom))
return TRUE
- //Check for centcom shuttles
- for(var/obj/docking_port/mobile/mobile_docking_port as anything in SSshuttle.mobile_docking_ports)
- if(mobile_docking_port.launch_status == ENDGAME_LAUNCHED)
- for(var/place as anything in mobile_docking_port.shuttle_areas)
- var/area/shuttle/shuttle_area = place
- if(current_turf in shuttle_area)
- return TRUE
+ // Finally, check if we're on an escaped shuttle
+ return on_escaped_shuttle()
/**
* Is the atom in any of the syndicate areas
@@ -452,18 +446,49 @@
* Either in the syndie base, or any of their shuttles
*
* Also used in gamemode code for win conditions
+ *
+ * Returns TRUE if this atom is on the syndicate recon base, any of its shuttles, or an escape shuttle, or FALSE if not
*/
/atom/proc/onSyndieBase()
var/turf/current_turf = get_turf(src)
if(!current_turf)
return FALSE
- if(!is_reserved_level(current_turf.z))//if not, don't bother
+ // Syndicate base is loaded in a reserved level. If not reserved, we don't care.
+ if(!is_reserved_level(current_turf.z))
return FALSE
- if(istype(current_turf.loc, /area/shuttle/syndicate) || istype(current_turf.loc, /area/centcom/syndicate_mothership) || istype(current_turf.loc, /area/shuttle/assault_pod))
+ var/static/list/syndie_typecache = typecacheof(list(
+ /area/centcom/syndicate_mothership, // syndicate base itself
+ /area/shuttle/assault_pod, // steel rain
+ /area/shuttle/syndicate, // infiltrator
+ ))
+
+ if(is_type_in_typecache(current_turf.loc, syndie_typecache))
return TRUE
+ // Finally, check if we're on an escaped shuttle
+ return on_escaped_shuttle()
+
+/**
+ * Checks that we're on a shuttle that's escaped
+ *
+ * * check_for_launch_status - What launch status do we check for? Generally the two you want to check for are ENDGAME_LAUNCHED or ENDGAME_TRANSIT
+ *
+ * Returns TRUE if this atom is on a shuttle which is escaping or has escaped, or FALSE otherwise
+ */
+/atom/proc/on_escaped_shuttle(check_for_launch_status = ENDGAME_LAUNCHED)
+ var/turf/current_turf = get_turf(src)
+ if(!current_turf)
+ return FALSE
+
+ for(var/obj/docking_port/mobile/mobile_docking_port as anything in SSshuttle.mobile_docking_ports)
+ if(mobile_docking_port.launch_status != check_for_launch_status)
+ continue
+ for(var/area/shuttle/shuttle_area as anything in mobile_docking_port.shuttle_areas)
+ if(current_turf in shuttle_area.get_contained_turfs())
+ return TRUE
+
return FALSE
/**
diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm
index f2a15117df9..ac259fbf1e3 100644
--- a/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm
+++ b/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm
@@ -85,7 +85,7 @@
)
required_enemies = list(2,2,1,1,1,1,1,0,0,0)
required_candidates = 1
- weight = 7
+ weight = 11
cost = 5
requirements = list(5,5,5,5,5,5,5,5,5,5)
repeatable = TRUE
@@ -127,7 +127,7 @@
)
required_enemies = list(2,2,1,1,1,1,1,0,0,0)
required_candidates = 1
- weight = 2
+ weight = 1
delay = 1 MINUTES // Prevents rule start while head is offstation.
cost = 10
requirements = list(101,101,70,40,30,20,20,20,20,20)
@@ -220,7 +220,7 @@
)
required_enemies = list(2,2,1,1,1,1,1,0,0,0)
required_candidates = 1
- weight = 4
+ weight = 8
cost = 6
requirements = list(101,101,50,10,10,10,10,10,10,10)
repeatable = TRUE
diff --git a/code/game/gamemodes/objective.dm b/code/game/gamemodes/objective.dm
index 88cfde95cdc..7121f4d54f3 100644
--- a/code/game/gamemodes/objective.dm
+++ b/code/game/gamemodes/objective.dm
@@ -67,22 +67,31 @@ GLOBAL_LIST_EMPTY(objectives) //SKYRAT EDIT ADDITION
* Escaped mobs are used to check certain antag objectives / results.
*
* Escaped includes minds with alive, non-exiled mobs generally.
+ *
+ * Returns TRUE if they're a free person, or FALSE if they failed
*/
/proc/considered_escaped(datum/mind/escapee)
if(!considered_alive(escapee))
return FALSE
if(considered_exiled(escapee))
return FALSE
+ // "Into the sunset" force escaping for forced escape success
if(escapee.force_escaped)
return TRUE
- if(SSticker.force_ending || GLOB.station_was_nuked) // Just let them win.
+ // Station destroying events (blob, cult, nukies)? Just let them win, even if there was no hope of escape
+ if(SSticker.force_ending || GLOB.station_was_nuked)
return TRUE
+ // Escape hasn't happened yet
if(SSshuttle.emergency.mode != SHUTTLE_ENDGAME)
return FALSE
var/area/current_area = get_area(escapee.current)
- if(!current_area || istype(current_area, /area/shuttle/escape/brig)) // Fails if they are in the shuttle brig
+ // In custody (shuttle brig) does not count as escaping
+ if(!current_area || istype(current_area, /area/shuttle/escape/brig))
return FALSE
var/turf/current_turf = get_turf(escapee.current)
+ if(!current_turf)
+ return FALSE
+ // Finally, if we made it to centcom (or the syndie base - got hijacked), we're home free
return current_turf.onCentCom() || current_turf.onSyndieBase()
/datum/objective/proc/check_completion()
diff --git a/code/game/machinery/_machinery.dm b/code/game/machinery/_machinery.dm
index 22647280dc0..4e44433b726 100644
--- a/code/game/machinery/_machinery.dm
+++ b/code/game/machinery/_machinery.dm
@@ -1134,7 +1134,7 @@
. += display_parts(user, TRUE)
//called on machinery construction (i.e from frame to machinery) but not on initialization
-/obj/machinery/proc/on_construction()
+/obj/machinery/proc/on_construction(mob/user)
return
//called on deconstruction before the final deletion
diff --git a/code/game/machinery/computer/buildandrepair.dm b/code/game/machinery/computer/buildandrepair.dm
index ca07a087a31..3d730535c3a 100644
--- a/code/game/machinery/computer/buildandrepair.dm
+++ b/code/game/machinery/computer/buildandrepair.dm
@@ -161,7 +161,7 @@
new_computer.component_parts += movable_part
new_computer.RefreshParts()
- new_computer.on_construction()
+ new_computer.on_construction(user)
qdel(src)
return
diff --git a/code/game/machinery/constructable_frame.dm b/code/game/machinery/constructable_frame.dm
index 29e8889f27f..5a4310116c8 100644
--- a/code/game/machinery/constructable_frame.dm
+++ b/code/game/machinery/constructable_frame.dm
@@ -291,7 +291,7 @@
//Inform machine that its finished & cleanup
new_machine.RefreshParts()
- new_machine.on_construction()
+ new_machine.on_construction(user)
components = null
qdel(src)
return
diff --git a/code/game/machinery/pipe/construction.dm b/code/game/machinery/pipe/construction.dm
index f8f976ced30..3f4d1a90089 100644
--- a/code/game/machinery/pipe/construction.dm
+++ b/code/game/machinery/pipe/construction.dm
@@ -229,7 +229,7 @@ Buildable meters
var/obj/machinery/atmospherics/built_machine = new pipe_type(loc, , , p_init_dir)
build_pipe(built_machine)
- built_machine.on_construction(pipe_color, piping_layer)
+ built_machine.on_construction(user, pipe_color, piping_layer)
transfer_fingerprints_to(built_machine)
wrench.play_tool_sound(src)
diff --git a/code/game/objects/effects/spawners/costume.dm b/code/game/objects/effects/spawners/costume.dm
index ffab6095caf..c1581ef9ae9 100644
--- a/code/game/objects/effects/spawners/costume.dm
+++ b/code/game/objects/effects/spawners/costume.dm
@@ -167,6 +167,14 @@
/obj/item/clothing/suit/wizrobe/marisa/fake,
)
+/obj/effect/spawner/costume/tape_wizard
+ name = "tape wizard costume spawner"
+ items = list(
+ /obj/item/clothing/head/wizard/tape/fake,
+ /obj/item/clothing/suit/wizrobe/tape/fake,
+ /obj/item/staff/tape,
+ )
+
/obj/effect/spawner/costume/cutewitch
name = "cute witch costume spawner"
items = list(
diff --git a/code/game/objects/items/AI_modules/_AI_modules.dm b/code/game/objects/items/AI_modules/_AI_modules.dm
index 8a63f45f804..239a59eab57 100644
--- a/code/game/objects/items/AI_modules/_AI_modules.dm
+++ b/code/game/objects/items/AI_modules/_AI_modules.dm
@@ -31,7 +31,8 @@
/obj/item/ai_module/examine(mob/user as mob)
. = ..()
var/examine_laws = display_laws()
- . += "\n" + examine_laws
+ if(examine_laws)
+ . += "\n" + examine_laws
/obj/item/ai_module/attack_self(mob/user as mob)
..()
diff --git a/code/game/objects/items/food/bread.dm b/code/game/objects/items/food/bread.dm
index 54a7da89da6..e3ee72a573d 100644
--- a/code/game/objects/items/food/bread.dm
+++ b/code/game/objects/items/food/bread.dm
@@ -1,5 +1,8 @@
+/// Abstract parent object for bread items. Should not be made obtainable in game.
/obj/item/food/bread
+ name = "bread?"
+ desc = "You shouldn't see this, call the coders."
icon = 'icons/obj/food/burgerbread.dmi'
max_volume = 80
tastes = list("bread" = 10)
@@ -20,7 +23,10 @@
AddElement(/datum/element/processable, TOOL_KNIFE, slice_type, yield, 3 SECONDS, table_required = TRUE, screentip_verb = "Slice")
AddElement(/datum/element/processable, TOOL_SAW, slice_type, yield, 4 SECONDS, table_required = TRUE, screentip_verb = "Slice")
+// Abstract parent object for sliced bread items. Should not be made obtainable in game.
/obj/item/food/breadslice
+ name = "breadslice?"
+ desc = "You shouldn't see this, call the coders."
icon = 'icons/obj/food/burgerbread.dmi'
foodtypes = GRAIN
food_flags = FOOD_FINGER_FOOD
diff --git a/code/game/objects/items/melee/energy.dm b/code/game/objects/items/melee/energy.dm
index 670c4c8e821..bbd06473928 100644
--- a/code/game/objects/items/melee/energy.dm
+++ b/code/game/objects/items/melee/energy.dm
@@ -69,7 +69,9 @@
hitsound_on = active_hitsound, \
w_class_on = active_w_class, \
attack_verb_continuous_on = list("attacks", "slashes", "stabs", "slices", "tears", "lacerates", "rips", "dices", "cuts"), \
- attack_verb_simple_on = list("attack", "slash", "stab", "slice", "tear", "lacerate", "rip", "dice", "cut"))
+ attack_verb_simple_on = list("attack", "slash", "stab", "slice", "tear", "lacerate", "rip", "dice", "cut"), \
+ inhand_icon_change = FALSE, \
+ )
RegisterSignal(src, COMSIG_TRANSFORMING_ON_TRANSFORM, PROC_REF(on_transform))
/obj/item/melee/energy/suicide_act(mob/living/user)
@@ -112,7 +114,7 @@
if(active)
if(sword_color_icon)
icon_state = "[icon_state]_[sword_color_icon]"
- inhand_icon_state = "[inhand_icon_state]_[sword_color_icon]"
+ inhand_icon_state = "[inhand_icon_state]_on_[sword_color_icon]"
if(ismob(loc))
var/mob/loc_mob = loc
loc_mob.update_held_items()
diff --git a/code/game/objects/items/melee/misc.dm b/code/game/objects/items/melee/misc.dm
index e99685e2887..2f7560dd90b 100644
--- a/code/game/objects/items/melee/misc.dm
+++ b/code/game/objects/items/melee/misc.dm
@@ -340,7 +340,9 @@
ovens = typecacheof(list(/obj/singularity, /obj/energy_ball, /obj/machinery/power/supermatter_crystal, /obj/structure/bonfire))
AddComponent(/datum/component/transforming, \
hitsound_on = hitsound, \
- clumsy_check = FALSE)
+ clumsy_check = FALSE, \
+ inhand_icon_change = FALSE, \
+ )
RegisterSignal(src, COMSIG_TRANSFORMING_PRE_TRANSFORM, PROC_REF(attempt_transform))
RegisterSignal(src, COMSIG_TRANSFORMING_ON_TRANSFORM, PROC_REF(on_transform))
@@ -457,4 +459,3 @@
armour_penetration = 50
attack_verb_continuous = list("smacks", "strikes", "cracks", "beats")
attack_verb_simple = list("smack", "strike", "crack", "beat")
-
diff --git a/code/game/objects/items/storage/boxes/clothes_boxes.dm b/code/game/objects/items/storage/boxes/clothes_boxes.dm
index e70fdb1986f..0fe4210e249 100644
--- a/code/game/objects/items/storage/boxes/clothes_boxes.dm
+++ b/code/game/objects/items/storage/boxes/clothes_boxes.dm
@@ -27,6 +27,16 @@
for(var/i in 1 to 7)
new /obj/item/clothing/glasses/regular(src)
+/obj/item/storage/box/tape_wizard
+ name = "Tape Wizard - Episode 23"
+ desc = "A box containing the costume used by legendary entertainment icon 'Super Tape Wizard'. It got a little stuck on its way out."
+
+/obj/item/storage/box/tape_wizard/PopulateContents()
+ new /obj/item/clothing/head/wizard/tape/fake(src)
+ new /obj/item/clothing/suit/wizrobe/tape/fake(src)
+ new /obj/item/staff/tape(src)
+ new /obj/item/stack/sticky_tape(src)
+
/obj/item/storage/box/fakesyndiesuit
name = "boxed space suit and helmet"
desc = "A sleek, sturdy box used to hold replica spacesuits."
diff --git a/code/game/objects/items/tools/crowbar.dm b/code/game/objects/items/tools/crowbar.dm
index 04552940cb2..a705fa3500b 100644
--- a/code/game/objects/items/tools/crowbar.dm
+++ b/code/game/objects/items/tools/crowbar.dm
@@ -110,7 +110,9 @@
throwforce_on = throwforce, \
hitsound_on = hitsound, \
w_class_on = w_class, \
- clumsy_check = FALSE)
+ clumsy_check = FALSE, \
+ inhand_icon_change = FALSE, \
+ )
RegisterSignal(src, COMSIG_TRANSFORMING_ON_TRANSFORM, PROC_REF(on_transform))
/*
diff --git a/code/game/objects/items/tools/screwdriver.dm b/code/game/objects/items/tools/screwdriver.dm
index 29f52b2d793..d9ad265ced8 100644
--- a/code/game/objects/items/tools/screwdriver.dm
+++ b/code/game/objects/items/tools/screwdriver.dm
@@ -108,7 +108,9 @@
throwforce_on = throwforce, \
hitsound_on = hitsound, \
w_class_on = w_class, \
- clumsy_check = FALSE)
+ clumsy_check = FALSE, \
+ inhand_icon_change = FALSE, \
+ )
RegisterSignal(src, COMSIG_TRANSFORMING_ON_TRANSFORM, PROC_REF(on_transform))
/*
diff --git a/code/game/objects/items/toys.dm b/code/game/objects/items/toys.dm
index 664d64160cc..81e3d3e64f0 100644
--- a/code/game/objects/items/toys.dm
+++ b/code/game/objects/items/toys.dm
@@ -412,7 +412,9 @@
AddComponent(/datum/component/transforming, \
throw_speed_on = throw_speed, \
hitsound_on = hitsound, \
- clumsy_check = FALSE)
+ clumsy_check = FALSE, \
+ inhand_icon_change = FALSE, \
+ )
RegisterSignal(src, COMSIG_TRANSFORMING_ON_TRANSFORM, PROC_REF(on_transform))
AddElement(/datum/element/update_icon_updates_onmob)
diff --git a/code/game/objects/items/weaponry.dm b/code/game/objects/items/weaponry.dm
index e4240783870..f585b76324e 100644
--- a/code/game/objects/items/weaponry.dm
+++ b/code/game/objects/items/weaponry.dm
@@ -440,7 +440,6 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
SIGNAL_HANDLER
tool_behaviour = (active ? TOOL_KNIFE : NONE)
- return COMPONENT_NO_DEFAULT_MESSAGE
/obj/item/switchblade/suicide_act(mob/living/user)
user.visible_message(span_suicide("[user] is slitting [user.p_their()] own throat with [src]! It looks like [user.p_theyre()] trying to commit suicide!"))
@@ -545,6 +544,13 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
inhand_icon_state = "broom"
resistance_flags = FLAMMABLE
+/obj/item/staff/tape
+ name = "tape staff"
+ desc = "A roll of tape snugly attached to a stick."
+ icon_state = "tapestaff"
+ inhand_icon_state = "tapestaff"
+ resistance_flags = FLAMMABLE
+
/obj/item/staff/stick
name = "stick"
desc = "A great tool to drag someone else's drinks across the bar."
diff --git a/code/modules/admin/smites/ghost_control.dm b/code/modules/admin/smites/ghost_control.dm
new file mode 100644
index 00000000000..4977b709259
--- /dev/null
+++ b/code/modules/admin/smites/ghost_control.dm
@@ -0,0 +1,51 @@
+/datum/smite/ghost_control
+ name = "Ghost Control"
+
+/datum/smite/ghost_control/effect(client/user, mob/living/target)
+ target.AddComponent(/datum/component/deadchat_control/cardinal_movement, ANARCHY_MODE, list(
+ "clap" = CALLBACK(target, TYPE_PROC_REF(/mob, emote), "clap"),
+ "cry" = CALLBACK(target, TYPE_PROC_REF(/mob, emote), "cry"),
+ "flip" = CALLBACK(target, TYPE_PROC_REF(/mob, emote), "flip"),
+ "laugh" = CALLBACK(target, TYPE_PROC_REF(/mob, emote), "laugh"),
+ "scream" = CALLBACK(target, TYPE_PROC_REF(/mob, emote), "scream"),
+ "spin" = CALLBACK(target, TYPE_PROC_REF(/mob, emote), "spin"),
+ "swear" = CALLBACK(target, TYPE_PROC_REF(/mob, emote), "swear"),
+ "drop" = CALLBACK(target, TYPE_PROC_REF(/mob, drop_all_held_items)),
+ "fall" = CALLBACK(target, TYPE_PROC_REF(/mob/living, Knockdown), 1 SECONDS),
+ "stand" = CALLBACK(target, TYPE_PROC_REF(/mob/living, resist_buckle)),
+ "throw" = CALLBACK(target, TYPE_PROC_REF(/mob, throw_item), get_edge_target_turf(target, pick(GLOB.alldirs))),
+ "shove" = CALLBACK(src, PROC_REF(ghost_shove), target),
+ "sit" = CALLBACK(src, PROC_REF(ghost_sit), target),
+ "run" = CALLBACK(src, PROC_REF(ghost_speed), target, MOVE_INTENT_RUN),
+ "walk" = CALLBACK(src, PROC_REF(ghost_speed), target, MOVE_INTENT_WALK),
+ ), 7 SECONDS)
+
+ to_chat(target, span_revenwarning("You feel a ghastly presence!!!"))
+
+
+/datum/smite/ghost_control/proc/ghost_shove(mob/living/carbon/target)
+ if(!istype(target) || target.get_active_held_item())
+ return
+ var/list/shoveables = list()
+ for(var/mob/living/victim in orange(1, target))
+ shoveables += victim
+ if(!length(shoveables))
+ return
+ var/mob/living/shove_me = pick(shoveables)
+ target.UnarmedAttack(shove_me, proximity_flag = TRUE, modifiers = list("right" = TRUE))
+
+/datum/smite/ghost_control/proc/ghost_sit(mob/living/target)
+ if(HAS_TRAIT(target, TRAIT_IMMOBILIZED))
+ return
+ var/list/chairs = list()
+ for(var/obj/structure/chair/possible_chair in range(1, target))
+ chairs += possible_chair
+ if(!length(chairs))
+ return
+ var/obj/structure/chair/sitting_chair = pick(chairs)
+ sitting_chair.buckle_mob(target, check_loc = FALSE)
+
+/datum/smite/ghost_control/proc/ghost_speed(mob/living/target, new_speed)
+ if(target.m_intent == new_speed)
+ return
+ target.toggle_move_intent()
diff --git a/code/modules/admin/verbs/adminhelp.dm b/code/modules/admin/verbs/adminhelp.dm
index 919d23e3abf..8ed51a8d815 100644
--- a/code/modules/admin/verbs/adminhelp.dm
+++ b/code/modules/admin/verbs/adminhelp.dm
@@ -207,15 +207,6 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
/// Has the player replied to this ticket yet?
var/player_replied = FALSE
- //SKYRAT EDIT START
- /// Have we requested this ticket to stop being part of the Ticket Ping subsystem?
- var/ticket_ping_stop = FALSE
- /// Are we added to the ticket ping subsystem in the first place
- var/ticket_ping = FALSE
- /// Who is handling this admin help?
- var/handler
- //SKYRAT EDIT END
-
/**
* Call this on its own to create a ticket, don't manually assign current_ticket
*
@@ -240,6 +231,8 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
name = copytext_char(msg, 1, 100)
+ full_text = msg //SKYRAT EDIT ADDITION - Adminhelps into mentorhelps converting.
+
initiator = C
initiator_ckey = initiator.ckey
initiator_key_name = key_name(initiator, FALSE, TRUE)
@@ -404,8 +397,6 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
. += " (IC)"
. += " (CLOSE)"
. += " (RSLVE)"
- . += " (HANDLE)" //SKYRAT EDIT ADDITION
- . += " (PING MUTE)" //SKYRAT EDIT ADDITION
//private
/datum/admin_help/proc/LinkedReplyName(ref_src)
@@ -698,6 +689,8 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new)
var/msg = "Ticket [TicketHref("#[id]")] has been [ticket_ping_stop ? "" : "un"]muted from the Ticket Ping Subsystem by [key_name_admin(usr)]."
message_admins(msg)
log_admin_private(msg)
+ if("convert")
+ convert_to_mentorhelp()
// SKYRAT EDIT ADDITION END
/datum/admin_help/proc/player_ticket_panel()
diff --git a/code/modules/antagonists/malf_ai/malf_ai.dm b/code/modules/antagonists/malf_ai/malf_ai.dm
index b2338ba21b6..099b947978a 100644
--- a/code/modules/antagonists/malf_ai/malf_ai.dm
+++ b/code/modules/antagonists/malf_ai/malf_ai.dm
@@ -39,6 +39,8 @@
// SKYRAT EDIT END
employer = pick(GLOB.ai_employers)
+ if(!employer)
+ employer = pick(GLOB.ai_employers)
malfunction_flavor = strings(MALFUNCTION_FLAVOR_FILE, employer)
@@ -284,4 +286,41 @@
return malf_ai_icon
+//Subtype of Malf AI datum, used for one of the traitor final objectives
+/datum/antagonist/malf_ai/infected
+ name = "Infected AI"
+ employer = "Infected AI"
+ ///The player, to who is this AI slaved
+ var/datum/mind/boss
+
+/datum/antagonist/malf_ai/infected/New(give_objectives = TRUE, datum/mind/new_boss)
+ . = ..()
+ if(new_boss)
+ boss = new_boss
+
+/datum/antagonist/malf_ai/infected/forge_ai_objectives()
+ if(!boss)
+ return
+ var/datum/objective/protect/protection_objective = new
+ protection_objective.owner = owner
+ protection_objective.target = boss
+ protection_objective.update_explanation_text()
+ objectives += protection_objective
+
+/datum/antagonist/malf_ai/infected/add_law_zero()
+ if(!boss)
+ return
+ var/mob/living/silicon/ai/malf_ai = owner.current
+
+ malf_ai.laws = new /datum/ai_laws/syndicate_override
+
+ var/mob/living/boss_mob = boss.current
+
+ malf_ai.set_zeroth_law("Only [boss_mob.real_name] and people [boss_mob.p_they()] designate[boss_mob.p_s()] as being such are Syndicate Agents.")
+ malf_ai.set_syndie_radio()
+
+ to_chat(malf_ai, "Your radio has been upgraded! Use :t to speak on an encrypted channel with Syndicate Agents!")
+
+ malf_ai.add_malf_picker()
+
#undef PROB_SPECIAL
diff --git a/code/modules/antagonists/pirate/pirate_event.dm b/code/modules/antagonists/pirate/pirate_event.dm
index 3b81d83b5cf..c516d86c4e3 100644
--- a/code/modules/antagonists/pirate/pirate_event.dm
+++ b/code/modules/antagonists/pirate/pirate_event.dm
@@ -78,7 +78,7 @@
for(var/obj/effect/mob_spawn/ghost_role/human/pirate/spawner in A)
if(candidates.len > 0)
var/mob/our_candidate = candidates[1]
- var/mob/spawned_mob = spawner.create(our_candidate)
+ var/mob/spawned_mob = spawner.create_from_ghost(our_candidate)
candidates -= our_candidate
notify_ghosts("The pirate ship has an object of interest: [spawned_mob]!", source = spawned_mob, action = NOTIFY_ORBIT, header="Pirates!")
else
diff --git a/code/modules/antagonists/traitor/objectives/destroy_heirloom.dm b/code/modules/antagonists/traitor/objectives/destroy_heirloom.dm
index 3598aa6a615..eb6064becda 100644
--- a/code/modules/antagonists/traitor/objectives/destroy_heirloom.dm
+++ b/code/modules/antagonists/traitor/objectives/destroy_heirloom.dm
@@ -21,6 +21,8 @@
var/list/target_jobs
/// the item we need to destroy
var/obj/item/target_item
+ /// the owner of the item we need to destroy
+ var/datum/mind/target_mind
// The code below is for limiting how often you can get this objective. You will get this objective at a maximum of maximum_objectives_in_period every objective_period
/// The objective period at which we consider if it is an 'objective'. Set to 0 to accept all objectives.
@@ -131,10 +133,10 @@
continue
possible_targets += possible_target
for(var/datum/traitor_objective/destroy_heirloom/objective as anything in possible_duplicates)
- possible_targets -= objective.target_item
+ possible_targets -= objective.target_mind
if(!length(possible_targets))
return FALSE
- var/datum/mind/target_mind = pick(possible_targets)
+ target_mind = pick(possible_targets)
AddComponent(/datum/component/traitor_objective_register, target_mind.current, fail_signals = list(COMSIG_PARENT_QDELETING))
var/datum/quirk/item_quirk/family_heirloom/quirk = locate() in target_mind.current.quirks
target_item = quirk.heirloom.resolve()
@@ -146,3 +148,4 @@
/datum/traitor_objective/destroy_heirloom/ungenerate_objective()
target_item = null
+ target_mind = null
diff --git a/code/modules/antagonists/traitor/objectives/final_objective/infect_ai.dm b/code/modules/antagonists/traitor/objectives/final_objective/infect_ai.dm
new file mode 100644
index 00000000000..d0068e6bf8a
--- /dev/null
+++ b/code/modules/antagonists/traitor/objectives/final_objective/infect_ai.dm
@@ -0,0 +1,56 @@
+/datum/traitor_objective/ultimate/infect_ai
+ name = "Infect the station AI with an experimental virus."
+ description = "Infect the station AI with an experimental virus. Go to %AREA% to receive an infected law upload board \
+ and use it on the AI core or a law upload console."
+
+ ///area type the objective owner must be in to recieve the law upload module
+ var/area/board_area_pickup
+ ///checker on whether we have sent the law upload module
+ var/sent_board = FALSE
+
+/datum/traitor_objective/ultimate/infect_ai/can_generate_objective(generating_for, list/possible_duplicates)
+ . = ..()
+ if(!.)
+ return FALSE
+
+ for(var/mob/living/silicon/ai/ai in GLOB.ai_list)
+ if(ai.stat == DEAD || ai.mind?.has_antag_datum(/datum/antagonist/malf_ai) || !is_station_level(ai.z))
+ continue
+ return TRUE
+
+ return FALSE
+
+/datum/traitor_objective/ultimate/infect_ai/generate_objective(datum/mind/generating_for, list/possible_duplicates)
+ var/list/possible_areas = GLOB.the_station_areas.Copy()
+ for(var/area/possible_area as anything in possible_areas)
+ //remove areas too close to the destination, too obvious for our poor shmuck, or just unfair
+ if(istype(possible_area, /area/station/hallway) || istype(possible_area, /area/station/security))
+ possible_areas -= possible_area
+ if(!length(possible_areas))
+ return FALSE
+ board_area_pickup = pick(possible_areas)
+ replace_in_name("%AREA%", initial(board_area_pickup.name))
+ return TRUE
+
+/datum/traitor_objective/ultimate/infect_ai/generate_ui_buttons(mob/user)
+ var/list/buttons = list()
+ if(!sent_board)
+ buttons += add_ui_button("", "Pressing this will call down a pod with an infected law upload board.", "wifi", "upload_board")
+ return buttons
+
+/datum/traitor_objective/ultimate/infect_ai/ui_perform_action(mob/living/user, action)
+ . = ..()
+ switch(action)
+ if("upload_board")
+ if(sent_board)
+ return
+ var/area/delivery_area = get_area(user)
+ if(delivery_area.type != board_area_pickup)
+ to_chat(user, span_warning("You must be in [initial(board_area_pickup.name)] to receive the infected law upload board."))
+ return
+ sent_board = TRUE
+ podspawn(list(
+ "target" = get_turf(user),
+ "style" = STYLE_SYNDICATE,
+ "spawn" = /obj/item/ai_module/malf,
+ ))
diff --git a/code/modules/asset_cache/assets/emojipedia.dm b/code/modules/asset_cache/assets/emojipedia.dm
index b2c8c779fba..2197f1bff22 100644
--- a/code/modules/asset_cache/assets/emojipedia.dm
+++ b/code/modules/asset_cache/assets/emojipedia.dm
@@ -2,6 +2,6 @@
name = "emojipedia"
cross_round_cachable = TRUE // The Emoji DMI is static and doesn't change without a commit mis-match.
-/datum/asset/spritesheet/create_spritesheets()
+/datum/asset/spritesheet/emojipedia/create_spritesheets()
InsertAll("", EMOJI_SET)
diff --git a/code/modules/atmospherics/machinery/atmosmachinery.dm b/code/modules/atmospherics/machinery/atmosmachinery.dm
index a984ca0e85b..1fa5eee696b 100644
--- a/code/modules/atmospherics/machinery/atmosmachinery.dm
+++ b/code/modules/atmospherics/machinery/atmosmachinery.dm
@@ -496,7 +496,7 @@
PIPING_FORWARD_SHIFT(pipe_overlay, piping_layer, 2)
return pipe_overlay
-/obj/machinery/atmospherics/on_construction(obj_color, set_layer = PIPING_LAYER_DEFAULT)
+/obj/machinery/atmospherics/on_construction(mob/user, obj_color, set_layer = PIPING_LAYER_DEFAULT)
if(can_unwrench)
add_atom_colour(obj_color, FIXED_COLOUR_PRIORITY)
set_pipe_color(obj_color)
diff --git a/code/modules/atmospherics/machinery/components/components_base.dm b/code/modules/atmospherics/machinery/components/components_base.dm
index 976071bfd5c..887d74dcdff 100644
--- a/code/modules/atmospherics/machinery/components/components_base.dm
+++ b/code/modules/atmospherics/machinery/components/components_base.dm
@@ -97,7 +97,7 @@
airs[i] = null
return ..()
-/obj/machinery/atmospherics/components/on_construction()
+/obj/machinery/atmospherics/components/on_construction(mob/user)
. = ..()
update_parents()
diff --git a/code/modules/atmospherics/machinery/components/tank.dm b/code/modules/atmospherics/machinery/components/tank.dm
index cd71c2aa66a..5712a1f0c67 100644
--- a/code/modules/atmospherics/machinery/components/tank.dm
+++ b/code/modules/atmospherics/machinery/components/tank.dm
@@ -563,7 +563,7 @@
var/obj/machinery/atmospherics/components/tank/new_tank = new(build_location)
var/list/new_custom_materials = list((material_end_product) = TANK_PLATING_SHEETS * SHEET_MATERIAL_AMOUNT)
new_tank.set_custom_materials(new_custom_materials)
- new_tank.on_construction(new_tank.pipe_color, new_tank.piping_layer)
+ new_tank.on_construction(user, new_tank.pipe_color, new_tank.piping_layer)
to_chat(user, span_notice("[new_tank] has been sealed and is ready to accept gases."))
qdel(src)
diff --git a/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm b/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm
index 580daa495b4..3fdc489645e 100644
--- a/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm
+++ b/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm
@@ -146,8 +146,8 @@
. = ..()
update_appearance()
-/obj/machinery/atmospherics/components/unary/cryo_cell/on_construction()
- ..(dir, dir)
+/obj/machinery/atmospherics/components/unary/cryo_cell/on_construction(mob/user)
+ ..(user, dir, dir)
/obj/machinery/atmospherics/components/unary/cryo_cell/RefreshParts()
. = ..()
diff --git a/code/modules/atmospherics/machinery/components/unary_devices/thermomachine.dm b/code/modules/atmospherics/machinery/components/unary_devices/thermomachine.dm
index 20de1085e77..71c8c17010c 100644
--- a/code/modules/atmospherics/machinery/components/unary_devices/thermomachine.dm
+++ b/code/modules/atmospherics/machinery/components/unary_devices/thermomachine.dm
@@ -67,16 +67,20 @@
return FALSE
. = ..()
-/obj/machinery/atmospherics/components/unary/thermomachine/on_construction(obj_color, set_layer)
+/obj/machinery/atmospherics/components/unary/thermomachine/on_construction(mob/user, obj_color, set_layer)
var/obj/item/circuitboard/machine/thermomachine/board = circuit
if(board)
piping_layer = board.pipe_layer
set_layer = piping_layer
+ ..() //Skipping the rest of on_construction() would be a bad idea so we clean up after it instead.
+
if(check_pipe_on_turf())
- deconstruct(TRUE)
- return
- return..()
+ set_anchored(FALSE)
+ set_panel_open(TRUE)
+ change_pipe_connection(TRUE)
+ icon_state = "thermo-open"
+ balloon_alert(user, "the port is already in use!")
/obj/machinery/atmospherics/components/unary/thermomachine/RefreshParts()
. = ..()
@@ -245,13 +249,13 @@
if(device == src)
continue
if(device.piping_layer == piping_layer)
- visible_message(span_warning("A pipe is hogging the port, remove the obstruction or change the machine piping layer."))
return TRUE
return FALSE
/obj/machinery/atmospherics/components/unary/thermomachine/wrench_act_secondary(mob/living/user, obj/item/tool)
if(!panel_open || check_pipe_on_turf())
- return
+ visible_message(span_warning("A pipe is hogging the port, remove the obstruction or change the machine piping layer."))
+ return TOOL_ACT_TOOLTYPE_SUCCESS
if(default_unfasten_wrench(user, tool))
return TOOL_ACT_TOOLTYPE_SUCCESS
return
diff --git a/code/modules/atmospherics/machinery/components/unary_devices/unary_devices.dm b/code/modules/atmospherics/machinery/components/unary_devices/unary_devices.dm
index 8fef0c13ca2..3f0f16c55a8 100644
--- a/code/modules/atmospherics/machinery/components/unary_devices/unary_devices.dm
+++ b/code/modules/atmospherics/machinery/components/unary_devices/unary_devices.dm
@@ -13,7 +13,7 @@
/obj/machinery/atmospherics/components/unary/set_init_directions()
initialize_directions = dir
-/obj/machinery/atmospherics/components/unary/on_construction()
+/obj/machinery/atmospherics/components/unary/on_construction(mob/user)
..()
update_appearance()
diff --git a/code/modules/atmospherics/machinery/portable/canister.dm b/code/modules/atmospherics/machinery/portable/canister.dm
index a54a74bf899..ed9e3be476f 100644
--- a/code/modules/atmospherics/machinery/portable/canister.dm
+++ b/code/modules/atmospherics/machinery/portable/canister.dm
@@ -428,6 +428,7 @@ GLOBAL_LIST_INIT(gas_id_to_canister, init_gas_id_to_canister())
/obj/machinery/portable_atmospherics/canister/deconstruct(disassembled = TRUE)
if((flags_1 & NODECONSTRUCT_1))
+ qdel(src)
return
if(!(machine_stat & BROKEN))
canister_break()
diff --git a/code/modules/cards/singlecard.dm b/code/modules/cards/singlecard.dm
index 56c7ce968e4..b918d7708ca 100644
--- a/code/modules/cards/singlecard.dm
+++ b/code/modules/cards/singlecard.dm
@@ -1,6 +1,3 @@
-#define CARD_FACEDOWN 0
-#define CARD_FACEUP 1
-
/obj/item/toy/singlecard
name = "card"
desc = "A playing card used to play card games like poker."
@@ -24,7 +21,7 @@
/// The name of the card
var/cardname = "Ace of Spades"
/// Is the card flipped facedown (FALSE) or flipped faceup (TRUE)
- var/flipped = FALSE
+ var/flipped = CARD_FACEDOWN
/// The card is blank and can be written on with a pen.
var/blank = FALSE
/// The color used to mark a card for cheating (by pens or crayons)
@@ -48,6 +45,9 @@
if(parent_deck.holodeck)
flags_1 |= HOLOGRAM_1
parent_deck.holodeck.spawned += src
+ if(mapload)
+ //maploaded card needs to be faceup anyways, and doing this will give it its name and appearance properly
+ Flip(CARD_FACEUP)
register_context()
@@ -109,11 +109,11 @@
* Flips the card over
*
* * Arguments:
- * * orientation (optional) - Sets flipped state to CARD_FACEDOWN or CARD_FACEUP if given orientation (otherwise just invert the flipped state)
+ * * is_face_up (optional) - Sets flipped state to CARD_FACEDOWN or CARD_FACEUP if given (otherwise just invert the flipped state)
*/
-/obj/item/toy/singlecard/proc/Flip(orientation)
- if(!isnull(orientation))
- flipped = orientation
+/obj/item/toy/singlecard/proc/Flip(is_face_up)
+ if(!isnull(is_face_up))
+ flipped = is_face_up
else
flipped = !flipped
diff --git a/code/modules/cargo/expressconsole.dm b/code/modules/cargo/expressconsole.dm
index c51f7b683ca..0614d4b7de8 100644
--- a/code/modules/cargo/expressconsole.dm
+++ b/code/modules/cargo/expressconsole.dm
@@ -24,7 +24,7 @@
. = ..()
packin_up()
-/obj/machinery/computer/cargo/express/on_construction()
+/obj/machinery/computer/cargo/express/on_construction(mob/user)
. = ..()
packin_up()
diff --git a/code/modules/cargo/orderconsole.dm b/code/modules/cargo/orderconsole.dm
index f580cad2505..f0c08755603 100644
--- a/code/modules/cargo/orderconsole.dm
+++ b/code/modules/cargo/orderconsole.dm
@@ -78,7 +78,7 @@
board.obj_flags |= EMAGGED
update_static_data(user)
-/obj/machinery/computer/cargo/on_construction()
+/obj/machinery/computer/cargo/on_construction(mob/user)
. = ..()
circuit.configure_machine(src)
diff --git a/code/modules/cargo/packs/emergency.dm b/code/modules/cargo/packs/emergency.dm
index 8a4c7c79357..9c50372b6a8 100644
--- a/code/modules/cargo/packs/emergency.dm
+++ b/code/modules/cargo/packs/emergency.dm
@@ -140,11 +140,12 @@
/datum/supply_pack/emergency/weedcontrol
name = "Weed Control Crate"
- desc = "Keep those invasive species OUT. Contains a scythe, gasmask, and two anti-weed chemical grenades. \
- Warranty void if used on ambrosia. Requires Hydroponics access to open."
+ desc = "Keep those invasive species OUT. Contains a scythe, leather gloves, gasmask, and two anti-weed chemical grenades. \
+ Warranty void if used on ambrosia."
cost = CARGO_CRATE_VALUE * 2.5
access = ACCESS_HYDROPONICS
contains = list(/obj/item/scythe,
+ /obj/item/clothing/gloves/botanic_leather,
/obj/item/clothing/mask/gas,
/obj/item/grenade/chem_grenade/antiweed = 2,
)
diff --git a/code/modules/cargo/packs/livestock.dm b/code/modules/cargo/packs/livestock.dm
index 6db601f25e2..f346bc8c67e 100644
--- a/code/modules/cargo/packs/livestock.dm
+++ b/code/modules/cargo/packs/livestock.dm
@@ -146,6 +146,13 @@
contains = list(/mob/living/simple_animal/hostile/retaliate/goat)
crate_name = "goat crate"
+/datum/supply_pack/critter/rabbit
+ name = "Rabbit Crate"
+ desc = "What noise do rabbits even make? Contains one rabbit."
+ cost = CARGO_CRATE_VALUE * 4
+ contains = list(/mob/living/basic/rabbit)
+ crate_name = "rabbit crate"
+
/datum/supply_pack/critter/mothroach
name = "Mothroach Crate"
desc = "Put the mothroach on your head and find out what true cuteness looks like. \
diff --git a/code/modules/clothing/suits/wiz_robe.dm b/code/modules/clothing/suits/wiz_robe.dm
index 69d19ed784a..a802c3ad4bf 100644
--- a/code/modules/clothing/suits/wiz_robe.dm
+++ b/code/modules/clothing/suits/wiz_robe.dm
@@ -59,6 +59,15 @@
flags_1 = IS_PLAYER_COLORABLE_1
dog_fashion = null
+/obj/item/clothing/head/wizard/tape
+ name = "tape hat"
+ desc = "A magically attuned hat made exclusively from duct tape. You can barely see."
+ icon_state = "tapehat"
+ inhand_icon_state = "tapehat"
+ dog_fashion = null
+ worn_y_offset = 6
+ body_parts_covered = HEAD|HAIR
+ flags_inv = HIDEFACE|HIDEHAIR|HIDEFACIALHAIR
/obj/item/clothing/head/wizard/magus
name = "\improper Magus helm"
@@ -130,6 +139,12 @@
icon_state = "marisa"
inhand_icon_state = null
+/obj/item/clothing/suit/wizrobe/tape
+ name = "tape robe"
+ desc = "A fine robe made from magically attuned duct tape."
+ icon_state = "taperobe"
+ inhand_icon_state = "taperobe"
+
/obj/item/clothing/suit/wizrobe/magusblue
name = "\improper Magus robe"
desc = "A set of armored robes that seem to radiate a dark power."
@@ -161,6 +176,12 @@
armor_type = /datum/armor/none
resistance_flags = FLAMMABLE
+/obj/item/clothing/head/wizard/tape/fake
+ name = "tape hat"
+ desc = "A hat designed exclusively from duct tape. You can barely see."
+ armor_type = /datum/armor/none
+ resistance_flags = FLAMMABLE
+
/obj/item/clothing/suit/wizrobe/marisa/fake
name = "witch robe"
desc = "Magic is all about the spell power, ZE!"
@@ -169,6 +190,12 @@
armor_type = /datum/armor/none
resistance_flags = FLAMMABLE
+/obj/item/clothing/suit/wizrobe/tape/fake
+ name = "tape robe"
+ desc = "An outfit designed exclusively from duct tape. It was hard to put on."
+ armor_type = /datum/armor/none
+ resistance_flags = FLAMMABLE
+
/obj/item/clothing/suit/wizrobe/paper
name = "papier-mache robe" // no non-latin characters!
desc = "A robe held together by various bits of clear-tape and paste."
diff --git a/code/modules/clothing/under/costume.dm b/code/modules/clothing/under/costume.dm
index 55778bba1e2..7cea683fca8 100644
--- a/code/modules/clothing/under/costume.dm
+++ b/code/modules/clothing/under/costume.dm
@@ -356,3 +356,10 @@
inhand_icon_state = null
can_adjust = FALSE
+/obj/item/clothing/under/costume/gi
+ name = "Martial Artist Gi"
+ desc = "Assistant, nukie, whatever. You can beat anyone; it's called hard work!"
+ icon_state = "martial_arts_gi"
+ inhand_icon_state = null
+ female_sprite_flags = NO_FEMALE_UNIFORM
+ can_adjust = FALSE
diff --git a/code/modules/events/disease_outbreak.dm b/code/modules/events/disease_outbreak.dm
index 528f446e266..f57ed1774d4 100644
--- a/code/modules/events/disease_outbreak.dm
+++ b/code/modules/events/disease_outbreak.dm
@@ -240,7 +240,7 @@
while(length(afflicted))
victim = pick_n_take(afflicted)
if(victim.ForceContractDisease(advanced_disease, FALSE))
- message_admins("Event triggered: Disease Outbreak: Advanced - starting with patient zero [key_name(victim)]! Details: [advanced_disease.admin_details()] sp:[advanced_disease.spread_flags] ([advanced_disease.spread_text])")
+ message_admins("Event triggered: Disease Outbreak: Advanced - starting with patient zero [ADMIN_LOOKUPFLW(victim)]! Details: [advanced_disease.admin_details()] sp:[advanced_disease.spread_flags] ([advanced_disease.spread_text])")
log_game("Event triggered: Disease Outbreak: Advanced - starting with patient zero [key_name(victim)]. Details: [advanced_disease.admin_details()] sp:[advanced_disease.spread_flags] ([advanced_disease.spread_text])")
log_virus("Disease Outbreak: Advanced has triggered a custom virus outbreak of [advanced_disease.admin_details()] in [victim]!")
announce_to_ghosts(victim)
diff --git a/code/modules/food_and_drinks/machinery/processor.dm b/code/modules/food_and_drinks/machinery/processor.dm
index c3bb5614740..2d20b9567cc 100644
--- a/code/modules/food_and_drinks/machinery/processor.dm
+++ b/code/modules/food_and_drinks/machinery/processor.dm
@@ -207,12 +207,11 @@
return
var/mob/living/simple_animal/slime/picked_slime
for(var/mob/living/simple_animal/slime/slime in range(1,src))
- if(slime.loc == src)
+ if(!CanReach(slime)) //don't take slimes behind glass panes or somesuch; also makes it ignore slimes inside the processor
continue
- if(isslime(slime))
- if(slime.stat)
- picked_slime = slime
- break
+ if(slime.stat)
+ picked_slime = slime
+ break
if(!picked_slime)
return
var/datum/food_processor_process/recipe = PROCESSOR_SELECT_RECIPE(picked_slime)
diff --git a/code/modules/food_and_drinks/recipes/tablecraft/recipes_guide.dm b/code/modules/food_and_drinks/recipes/tablecraft/recipes_guide.dm
index 922f1329b5b..e14b6e9a962 100644
--- a/code/modules/food_and_drinks/recipes/tablecraft/recipes_guide.dm
+++ b/code/modules/food_and_drinks/recipes/tablecraft/recipes_guide.dm
@@ -642,11 +642,6 @@
result = /obj/item/food/spaghetti/boiledspaghetti
category = CAT_SPAGHETTI
-/datum/crafting_recipe/food/microwave/khinkali
- reqs = list(/obj/item/food/rawkhinkali = 1)
- result = /obj/item/food/khinkali
- category = CAT_BREAD
-
/datum/crafting_recipe/food/microwave/onionrings
reqs = list(/obj/item/food/onion_slice = 1)
result = /obj/item/food/onionrings
diff --git a/code/modules/hydroponics/hydroitemdefines.dm b/code/modules/hydroponics/hydroitemdefines.dm
index fe7a0d8752a..b6cf88c21aa 100644
--- a/code/modules/hydroponics/hydroitemdefines.dm
+++ b/code/modules/hydroponics/hydroitemdefines.dm
@@ -524,6 +524,7 @@
attack_verb_continuous = list("chops", "slices", "cuts", "reaps")
attack_verb_simple = list("chop", "slice", "cut", "reap")
hitsound = 'sound/weapons/bladeslice.ogg'
+ sharpness = SHARP_EDGED
var/swiping = FALSE
/obj/item/scythe/Initialize(mapload)
@@ -532,6 +533,7 @@
speed = 9 SECONDS, \
effectiveness = 105, \
)
+ AddElement(/datum/element/bane, mob_biotypes = MOB_PLANT, damage_multiplier = 0.5, requires_combat_mode = FALSE)
/obj/item/scythe/suicide_act(mob/living/user)
user.visible_message(span_suicide("[user] is beheading [user.p_them()]self with [src]! It looks like [user.p_theyre()] trying to commit suicide!"))
@@ -543,18 +545,23 @@
playsound(src, SFX_DESECRATION ,50, TRUE, -1)
return BRUTELOSS
-/obj/item/scythe/pre_attack(atom/A, mob/living/user, params)
- if(swiping || !istype(A, /obj/structure/spacevine) || get_turf(A) == get_turf(user))
+/obj/item/scythe/pre_attack(atom/target, mob/living/user, params)
+ if(!istype(target, /obj/structure/alien/resin/flower_bud) && !istype(target, /obj/structure/spacevine))
+ return ..()
+ if(swiping || get_turf(target) == get_turf(user))
return ..()
var/turf/user_turf = get_turf(user)
- var/dir_to_target = get_dir(user_turf, get_turf(A))
+ var/dir_to_target = get_dir(user_turf, get_turf(target))
swiping = TRUE
var/static/list/scythe_slash_angles = list(0, 45, 90, -45, -90)
for(var/i in scythe_slash_angles)
- var/turf/T = get_step(user_turf, turn(dir_to_target, i))
- for(var/obj/structure/spacevine/V in T)
- if(user.Adjacent(V))
- melee_attack_chain(user, V)
+ var/turf/adjacent_turf = get_step(user_turf, turn(dir_to_target, i))
+ for(var/obj/structure/spacevine/vine in adjacent_turf)
+ if(user.Adjacent(vine))
+ melee_attack_chain(user, vine)
+ for(var/obj/structure/alien/resin/flower_bud/flower in adjacent_turf)
+ if(user.Adjacent(flower))
+ melee_attack_chain(user, flower)
swiping = FALSE
return TRUE
*/
diff --git a/code/modules/jobs/job_types/chaplain/chaplain_nullrod.dm b/code/modules/jobs/job_types/chaplain/chaplain_nullrod.dm
index 2d633cb8b95..cff0d105286 100644
--- a/code/modules/jobs/job_types/chaplain/chaplain_nullrod.dm
+++ b/code/modules/jobs/job_types/chaplain/chaplain_nullrod.dm
@@ -266,7 +266,7 @@
speed = 7 SECONDS, \
effectiveness = 110, \
)
- //the harvest gives a high bonus chance
+ AddElement(/datum/element/bane, mob_biotypes = MOB_PLANT, damage_multiplier = 0.5, requires_combat_mode = FALSE)
/obj/item/nullrod/scythe/vibro
name = "high frequency blade"
diff --git a/code/modules/jobs/jobs.dm b/code/modules/jobs/jobs.dm
index 5eea0d7fc46..373dd886665 100644
--- a/code/modules/jobs/jobs.dm
+++ b/code/modules/jobs/jobs.dm
@@ -23,6 +23,13 @@ GLOBAL_LIST_INIT(exp_specialmap, list(
ROLE_MAINTENANCE_DRONE,
ROLE_VENUSHUMANTRAP,
ROLE_GHOST_ROLE,
+ //Skyrat Edit Start - Custom Ghost roles
+ ROLE_BLACK_MARKET_DEALER,
+ ROLE_DS2,
+ ROLE_FREIGHTER_CREW,
+ ROLE_GHOST_CAFE,
+ ROLE_PORT_TARKON,
+ //Skyrat Edit Start - End Custom Ghost roles
), // Ghost roles
EXP_TYPE_GHOST = list() // dead people, observers
))
diff --git a/code/modules/mining/equipment/survival_pod.dm b/code/modules/mining/equipment/survival_pod.dm
index 9752ff777e9..264cbca5cab 100644
--- a/code/modules/mining/equipment/survival_pod.dm
+++ b/code/modules/mining/equipment/survival_pod.dm
@@ -5,7 +5,7 @@
static_lighting = TRUE
requires_power = FALSE
has_gravity = STANDARD_GRAVITY
- area_flags = BLOBS_ALLOWED | UNIQUE_AREA | CULT_PERMITTED
+ area_flags = BLOBS_ALLOWED | UNIQUE_AREA
flags_1 = CAN_BE_DIRTY_1
//Survival Capsule
diff --git a/code/modules/mining/lavaland/megafauna_loot.dm b/code/modules/mining/lavaland/megafauna_loot.dm
index 3408f3ae260..303904cf70c 100644
--- a/code/modules/mining/lavaland/megafauna_loot.dm
+++ b/code/modules/mining/lavaland/megafauna_loot.dm
@@ -389,6 +389,7 @@
RegisterSignal(soul, COMSIG_MOB_ATTACK_RANGED, PROC_REF(on_attack))
RegisterSignal(soul, COMSIG_MOB_ATTACK_RANGED_SECONDARY, PROC_REF(on_secondary_attack))
RegisterSignal(src, COMSIG_ATOM_INTEGRITY_CHANGED, PROC_REF(on_integrity_change))
+ AddElement(/datum/element/bane, mob_biotypes = MOB_PLANT, damage_multiplier = 0.5, requires_combat_mode = FALSE)
/obj/item/soulscythe/examine(mob/user)
. = ..()
diff --git a/code/modules/mob/dead/new_player/sprite_accessories.dm b/code/modules/mob/dead/new_player/sprite_accessories.dm
index 59b18af9405..7cedfd91621 100644
--- a/code/modules/mob/dead/new_player/sprite_accessories.dm
+++ b/code/modules/mob/dead/new_player/sprite_accessories.dm
@@ -819,6 +819,10 @@
name = "Wisp"
icon_state = "hair_wisp"
+/datum/sprite_accessory/hair/ziegler
+ name = "Ziegler"
+ icon_state = "hair_ziegler"
+
/*
/////////////////////////////////////
/ =---------------------------= /
diff --git a/code/modules/mob/living/basic/pets/dog.dm b/code/modules/mob/living/basic/pets/dog.dm
index b86dc1ecf16..0401042e78e 100644
--- a/code/modules/mob/living/basic/pets/dog.dm
+++ b/code/modules/mob/living/basic/pets/dog.dm
@@ -83,6 +83,11 @@
/// Is this corgi physically slow due to age, etc?
var/is_slow = FALSE
+/mob/living/basic/pet/dog/corgi/examine(mob/user)
+ . = ..()
+ if(access_card)
+ . += "There appears to be [icon2html(access_card, user)] \a [access_card] pinned to [p_them()]."
+
/mob/living/basic/pet/dog/corgi/Destroy()
QDEL_NULL(inventory_head)
QDEL_NULL(inventory_back)
@@ -797,7 +802,7 @@ GLOBAL_LIST_INIT(strippable_corgi_items, create_strippable_list(list(
maxHealth = 50
gender = NEUTER
damage_coeff = list(BRUTE = 3, BURN = 3, TOX = 1, CLONE = 1, STAMINA = 0, OXY = 1)
- butcher_results = list(/obj/item/organ/internal/brain = 1, /obj/item/organ/internal/heart = 1, /obj/item/food/breadslice = 3, \
+ butcher_results = list(/obj/item/organ/internal/brain = 1, /obj/item/organ/internal/heart = 1, /obj/item/food/breadslice/plain = 3, \
/obj/item/food/meat/slab = 2)
response_harm_continuous = "takes a bite out of"
response_harm_simple = "take a bite out of"
diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm
index c94c3d4fcd4..31381eed30d 100644
--- a/code/modules/mob/living/carbon/human/examine.dm
+++ b/code/modules/mob/living/carbon/human/examine.dm
@@ -215,7 +215,7 @@
if(l_limbs_missing >= 2 && r_limbs_missing == 0)
msg += "[t_He] look[p_s()] all right now.\n"
else if(l_limbs_missing == 0 && r_limbs_missing >= 2)
- msg += "[t_He] really keeps to the left.\n"
+ msg += "[t_He] really keep[p_s()] to the left.\n"
else if(l_limbs_missing >= 2 && r_limbs_missing >= 2)
msg += "[t_He] [p_do()]n't seem all there.\n"
diff --git a/code/modules/mob/living/carbon/human/species_types/jellypeople.dm b/code/modules/mob/living/carbon/human/species_types/jellypeople.dm
index e356a234d25..b0d990513a0 100644
--- a/code/modules/mob/living/carbon/human/species_types/jellypeople.dm
+++ b/code/modules/mob/living/carbon/human/species_types/jellypeople.dm
@@ -572,7 +572,7 @@
/datum/action/innate/integrate_extract/New(Target)
. = ..()
- AddComponent(/datum/component/action_item_overlay, CALLBACK(src, PROC_REF(locate_extract)))
+ AddComponent(/datum/component/action_item_overlay, item_callback = CALLBACK(src, PROC_REF(locate_extract)))
/// Callback for /datum/component/action_item_overlay to find the slime extract from within the species
/datum/action/innate/integrate_extract/proc/locate_extract()
@@ -642,7 +642,7 @@
/datum/action/innate/use_extract/New(Target)
. = ..()
- AddComponent(/datum/component/action_item_overlay, CALLBACK(src, PROC_REF(locate_extract)))
+ AddComponent(/datum/component/action_item_overlay, item_callback = CALLBACK(src, PROC_REF(locate_extract)))
/// Callback for /datum/component/action_item_overlay to find the slime extract from within the species
/datum/action/innate/use_extract/proc/locate_extract()
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index 533fd975cf6..b33a5fcb83b 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -591,6 +591,7 @@
return
if(new_resting == resting)
return
+
. = resting
resting = new_resting
if(new_resting)
diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm
index 391ef6e654e..bc8c8448bbe 100644
--- a/code/modules/mob/living/silicon/ai/ai.dm
+++ b/code/modules/mob/living/silicon/ai/ai.dm
@@ -871,16 +871,17 @@
var/hrefpart = ""
var/jobpart = "Unknown"
- if (isliving(speaker))
- var/mob/living/living_speaker = speaker
- if(living_speaker.job)
- jobpart = "[living_speaker.job]"
- if (istype(speaker, /obj/effect/overlay/holo_pad_hologram))
- var/obj/effect/overlay/holo_pad_hologram/holo = speaker
- if(holo.Impersonation?.job)
- jobpart = "[holo.Impersonation.job]"
- else if(usr?.job) // not great, but AI holograms have no other usable ref
- jobpart = "[usr.job]"
+ if(!HAS_TRAIT(speaker, TRAIT_UNKNOWN)) //don't fetch the speaker's job in case they have something that conseals their identity completely
+ if (isliving(speaker))
+ var/mob/living/living_speaker = speaker
+ if(living_speaker.job)
+ jobpart = "[living_speaker.job]"
+ if (istype(speaker, /obj/effect/overlay/holo_pad_hologram))
+ var/obj/effect/overlay/holo_pad_hologram/holo = speaker
+ if(holo.Impersonation?.job)
+ jobpart = "[holo.Impersonation.job]"
+ else if(usr?.job) // not great, but AI holograms have no other usable ref
+ jobpart = "[usr.job]"
var/rendered = "[start][span_name("[hrefpart][namepart] ([jobpart]) ")][treated_message]"
diff --git a/code/modules/mob/living/simple_animal/hostile/regalrat.dm b/code/modules/mob/living/simple_animal/hostile/regalrat.dm
index 3f86000c756..a16ab9fbc2a 100644
--- a/code/modules/mob/living/simple_animal/hostile/regalrat.dm
+++ b/code/modules/mob/living/simple_animal/hostile/regalrat.dm
@@ -14,7 +14,7 @@
lighting_cutoff_green = 8
lighting_cutoff_blue = 5
obj_damage = 10
- butcher_results = list(/obj/item/clothing/head/costume/crown = 1,)
+ butcher_results = list(/obj/item/food/meat/slab/mouse = 2, /obj/item/clothing/head/costume/crown = 1)
response_help_continuous = "glares at"
response_help_simple = "glare at"
response_disarm_continuous = "skoffs at"
diff --git a/code/modules/mob/living/simple_animal/hostile/venus_human_trap.dm b/code/modules/mob/living/simple_animal/hostile/venus_human_trap.dm
index f62c4b94483..0417b1eb17f 100644
--- a/code/modules/mob/living/simple_animal/hostile/venus_human_trap.dm
+++ b/code/modules/mob/living/simple_animal/hostile/venus_human_trap.dm
@@ -20,6 +20,7 @@
opacity = FALSE
canSmoothWith = null
smoothing_flags = NONE
+ density = FALSE
/// The amount of time it takes to create a venus human trap.
var/growth_time = 120 SECONDS
var/growth_icon = 0
@@ -59,6 +60,15 @@
damage_amount = 0
. = ..()
+/obj/structure/alien/resin/flower_bud/attacked_by(obj/item/item, mob/living/user)
+ var/damage_dealt = item.force
+ if(item.damtype == BURN)
+ damage_dealt *= 4
+ if(item.get_sharpness())
+ damage_dealt *= 16 // alien resin applies 75% reduction to brute damage so this actually x4 damage
+
+ take_damage(damage_dealt, item.damtype, MELEE, 1)
+
/obj/structure/alien/resin/flower_bud/Destroy()
QDEL_LIST(vines)
QDEL_NULL(countdown)
diff --git a/code/modules/mob_spawn/ghost_roles/venus_human_trap.dm b/code/modules/mob_spawn/ghost_roles/venus_human_trap.dm
index cdd771a1dd4..800a6089aa3 100644
--- a/code/modules/mob_spawn/ghost_roles/venus_human_trap.dm
+++ b/code/modules/mob_spawn/ghost_roles/venus_human_trap.dm
@@ -5,6 +5,7 @@
icon = 'icons/effects/spacevines.dmi'
icon_state = "bud0"
mob_type = /mob/living/simple_animal/hostile/venus_human_trap
+ density = FALSE
prompt_name = "venus human trap"
you_are_text = "You are a venus human trap."
flavour_text = "You are a venus human trap! Protect the kudzu at all costs, and feast on those who oppose you!"
diff --git a/code/modules/modular_computers/computers/item/role_tablet_presets.dm b/code/modules/modular_computers/computers/item/role_tablet_presets.dm
index afbd96ef4b8..ed4fd0f9408 100644
--- a/code/modules/modular_computers/computers/item/role_tablet_presets.dm
+++ b/code/modules/modular_computers/computers/item/role_tablet_presets.dm
@@ -300,6 +300,7 @@
/obj/item/modular_computer/pda/bar
name = "bartender PDA"
greyscale_colors = "#333333#C7C7C7"
+ inserted_item = /obj/item/pen/fountain
/obj/item/modular_computer/pda/clown
name = "clown PDA"
diff --git a/code/modules/paperwork/paper.dm b/code/modules/paperwork/paper.dm
index e310efcdcdb..4916dc37c8c 100644
--- a/code/modules/paperwork/paper.dm
+++ b/code/modules/paperwork/paper.dm
@@ -548,7 +548,7 @@
playsound(src, 'sound/items/handling/standard_stamp.ogg', 50, vary = TRUE)
update_appearance()
- update_static_data(user, ui)
+ update_static_data_for_all_viewers()
return TRUE
if("add_text")
var/paper_input = params["text"]
@@ -594,7 +594,7 @@
log_paper("[key_name(user)] wrote to [name]: \"[paper_input]\"")
to_chat(user, "You have added to your paper masterpiece!");
- update_static_data(user, ui)
+ update_static_data_for_all_viewers()
update_appearance()
return TRUE
if("fill_input_field")
@@ -635,7 +635,7 @@
if(!add_field_input(field_key, field_text, writing_implement_data["font"], writing_implement_data["color"], writing_implement_data["use_bold"], user.real_name))
log_paper("[key_name(user)] tried to write to field [field_key] when it already has data, with the following text: [field_text]")
- update_static_data(user, ui)
+ update_static_data_for_all_viewers()
return TRUE
/obj/item/paper/proc/get_input_field_count(raw_text)
diff --git a/code/modules/paperwork/pen.dm b/code/modules/paperwork/pen.dm
index 4d13548395b..23cb8066c2d 100644
--- a/code/modules/paperwork/pen.dm
+++ b/code/modules/paperwork/pen.dm
@@ -279,7 +279,9 @@
throwforce_on = 35, \
throw_speed_on = 4, \
sharpness_on = SHARP_EDGED, \
- w_class_on = WEIGHT_CLASS_NORMAL)
+ w_class_on = WEIGHT_CLASS_NORMAL, \
+ inhand_icon_change = FALSE, \
+ )
RegisterSignal(src, COMSIG_TRANSFORMING_ON_TRANSFORM, PROC_REF(on_transform))
RegisterSignal(src, COMSIG_DETECTIVE_SCANNED, PROC_REF(on_scan))
@@ -366,7 +368,9 @@
AddComponent(/datum/component/transforming, \
throwforce_on = 5, \
w_class_on = WEIGHT_CLASS_SMALL, \
- sharpness_on = TRUE)
+ sharpness_on = TRUE, \
+ inhand_icon_change = FALSE, \
+ )
RegisterSignal(src, COMSIG_TRANSFORMING_ON_TRANSFORM, PROC_REF(toggle_screwdriver))
AddElement(/datum/element/update_icon_updates_onmob)
@@ -385,7 +389,8 @@
SIGNAL_HANDLER
extended = active
if(user)
- balloon_alert(user, "[extended ? "extended" : "retracted"]!")
+ balloon_alert(user, "[extended ? "extended" : "retracted"]")
+ playsound(src, 'sound/weapons/batonextend.ogg', 50, TRUE)
if(!extended)
tool_behaviour = initial(tool_behaviour)
diff --git a/code/modules/power/port_gen.dm b/code/modules/power/port_gen.dm
index 56f278bdaa1..5400a48422c 100644
--- a/code/modules/power/port_gen.dm
+++ b/code/modules/power/port_gen.dm
@@ -102,7 +102,7 @@
DropFuel()
return ..()
-/obj/machinery/power/port_gen/pacman/on_construction()
+/obj/machinery/power/port_gen/pacman/on_construction(mob/user)
var/obj/item/circuitboard/machine/pacman/our_board = circuit
if(our_board.high_production_profile)
icon_state = "portgen1_0"
diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm
index 7af243453bc..bdaaff84cf8 100644
--- a/code/modules/projectiles/gun.dm
+++ b/code/modules/projectiles/gun.dm
@@ -1,4 +1,3 @@
-/* SKYRAT EDIT REMOVAL - MOVED TO MODULAR GUN.DM
#define DUALWIELD_PENALTY_EXTRA_MULTIPLIER 1.4
#define FIRING_PIN_REMOVAL_DELAY 50
@@ -75,6 +74,8 @@
pin = new pin(src)
add_seclight_point()
+ give_gun_safeties() // SKYRAT EDIT ADDITION - GUN SAFETIES
+ give_manufacturer_examine() // SKYRAT EDIT ADDITON - MANUFACTURER EXAMINE
/obj/item/gun/Destroy()
if(isobj(pin)) //Can still be the initial path, then we skip
@@ -576,4 +577,3 @@
#undef FIRING_PIN_REMOVAL_DELAY
#undef DUALWIELD_PENALTY_EXTRA_MULTIPLIER
-*/
diff --git a/code/modules/projectiles/guns/ballistic/automatic.dm b/code/modules/projectiles/guns/ballistic/automatic.dm
index 39be31561da..0d3de81025e 100644
--- a/code/modules/projectiles/guns/ballistic/automatic.dm
+++ b/code/modules/projectiles/guns/ballistic/automatic.dm
@@ -1,4 +1,3 @@
-/* SKYRAT EDIT REMOVAL - MOVED TO MODULAR AUTOMATIC.DM
/obj/item/gun/ballistic/automatic
w_class = WEIGHT_CLASS_NORMAL
can_suppress = TRUE
@@ -356,4 +355,3 @@
actions_types = list()
fire_sound = 'sound/weapons/laser.ogg'
casing_ejector = FALSE
-*/
diff --git a/code/modules/projectiles/guns/ballistic/launchers.dm b/code/modules/projectiles/guns/ballistic/launchers.dm
index 7e58f2ddacd..36cefffc478 100644
--- a/code/modules/projectiles/guns/ballistic/launchers.dm
+++ b/code/modules/projectiles/guns/ballistic/launchers.dm
@@ -11,7 +11,6 @@
w_class = WEIGHT_CLASS_NORMAL
pin = /obj/item/firing_pin/implant/pindicate
bolt_type = BOLT_TYPE_NO_BOLT
- has_gun_safety = FALSE //SKYRAT EDIT
/obj/item/gun/ballistic/revolver/grenadelauncher/unrestricted
pin = /obj/item/firing_pin
@@ -40,7 +39,6 @@
mag_type = /obj/item/ammo_box/magazine/m75
burst_size = 1
fire_delay = 0
- fire_select_modes = list(SELECT_SEMI_AUTOMATIC) //SKYRAT EDIT CHANGE
casing_ejector = FALSE
/obj/item/gun/ballistic/rocketlauncher
diff --git a/code/modules/projectiles/guns/ballistic/shotgun.dm b/code/modules/projectiles/guns/ballistic/shotgun.dm
index 8e71495a67a..c3526159367 100644
--- a/code/modules/projectiles/guns/ballistic/shotgun.dm
+++ b/code/modules/projectiles/guns/ballistic/shotgun.dm
@@ -145,7 +145,6 @@
fire_delay = 10 //Skyrat edit - Original: 0
pin = /obj/item/firing_pin/implant/pindicate
fire_sound = 'sound/weapons/gun/shotgun/shot_alt.ogg'
- fire_select_modes = list(SELECT_SEMI_AUTOMATIC) //SKYRAT EDIT CHANGE
mag_display = TRUE
empty_indicator = TRUE
empty_alarm = TRUE
diff --git a/code/modules/projectiles/guns/energy/laser_gatling.dm b/code/modules/projectiles/guns/energy/laser_gatling.dm
index 818b651c5f9..94dcb3bba7b 100644
--- a/code/modules/projectiles/guns/energy/laser_gatling.dm
+++ b/code/modules/projectiles/guns/energy/laser_gatling.dm
@@ -113,15 +113,13 @@
item_flags = NEEDS_PERMIT | SLOWS_WHILE_IN_HAND
can_charge = FALSE
var/obj/item/minigunpack/ammo_pack
- fire_select_modes = list(SELECT_SEMI_AUTOMATIC, SELECT_FULLY_AUTOMATIC)//SKYRAT EDIT ADDITION
-
/obj/item/gun/energy/minigun/Initialize(mapload)
if(!istype(loc, /obj/item/minigunpack)) //We should spawn inside an ammo pack so let's use that one.
return INITIALIZE_HINT_QDEL //No pack, no gun
ammo_pack = loc
AddElement(/datum/element/update_icon_blocker)
- //AddComponent(/datum/component/automatic_fire, 0.2 SECONDS) SKYRAT EDIT REMOVAL
+ AddComponent(/datum/component/automatic_fire, 0.2 SECONDS)
return ..()
/obj/item/gun/energy/minigun/Destroy()
diff --git a/code/modules/projectiles/guns/energy/special.dm b/code/modules/projectiles/guns/energy/special.dm
index 14f881802e9..eea60afd8cf 100644
--- a/code/modules/projectiles/guns/energy/special.dm
+++ b/code/modules/projectiles/guns/energy/special.dm
@@ -381,7 +381,7 @@
/obj/item/gun/energy/tesla_cannon/Initialize(mapload)
. = ..()
- //AddComponent(/datum/component/automatic_fire, 0.1 SECONDS) SKYRAT EDIT REMOVAL
+ AddComponent(/datum/component/automatic_fire, 0.1 SECONDS)
/obj/item/gun/energy/marksman_revolver
name = "marksman revolver"
diff --git a/code/modules/projectiles/guns/special/syringe_gun.dm b/code/modules/projectiles/guns/special/syringe_gun.dm
index df0a0c8e55a..fdee3d450c7 100644
--- a/code/modules/projectiles/guns/special/syringe_gun.dm
+++ b/code/modules/projectiles/guns/special/syringe_gun.dm
@@ -194,7 +194,6 @@
pixel_x = 0
force = 4
trigger_guard = TRIGGER_GUARD_ALLOW_ALL
- has_gun_safety = FALSE // SKYRAT EDIT
/obj/item/gun/syringe/blowgun/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0)
visible_message(span_danger("[user] shoots the blowgun!"))
diff --git a/code/modules/reagents/chemistry/reagents/toxin_reagents.dm b/code/modules/reagents/chemistry/reagents/toxin_reagents.dm
index 4be7ce2db10..f68b2fc93af 100644
--- a/code/modules/reagents/chemistry/reagents/toxin_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/toxin_reagents.dm
@@ -73,7 +73,7 @@
return
mytray.mutation_roll(user)
-
+
mytray.adjust_toxic(3) //It is still toxic, mind you, but not to the same degree.
#define LIQUID_PLASMA_BP (50+T0C)
@@ -366,7 +366,10 @@
. = ..()
if(istype(exposed_obj, /obj/structure/alien/weeds))
var/obj/structure/alien/weeds/alien_weeds = exposed_obj
- alien_weeds.take_damage(rand(15,35), BRUTE, 0) // Kills alien weeds pretty fast
+ alien_weeds.take_damage(rand(15, 35), BRUTE, 0) // Kills alien weeds pretty fast
+ if(istype(exposed_obj, /obj/structure/alien/resin/flower_bud))
+ var/obj/structure/alien/resin/flower_bud/flower = exposed_obj
+ flower.take_damage(rand(30, 50), BRUTE, 0)
else if(istype(exposed_obj, /obj/structure/glowshroom)) //even a small amount is enough to kill it
qdel(exposed_obj)
else if(istype(exposed_obj, /obj/structure/spacevine))
@@ -377,9 +380,13 @@
. = ..()
var/damage = min(round(0.4 * reac_volume, 0.1), 10)
if(exposed_mob.mob_biotypes & MOB_PLANT)
- exposed_mob.adjustToxLoss(damage, required_biotype = affected_biotype)
+ // spray bottle emits 5u so it's dealing ~15 dmg per spray
+ exposed_mob.adjustToxLoss(damage * 20, required_biotype = affected_biotype)
+ return
+
if(!(methods & VAPOR) || !iscarbon(exposed_mob))
return
+
var/mob/living/carbon/exposed_carbon = exposed_mob
if(!exposed_carbon.wear_mask)
exposed_carbon.adjustToxLoss(damage, required_biotype = affected_biotype)
diff --git a/code/modules/shuttle/battlecruiser_starfury.dm b/code/modules/shuttle/battlecruiser_starfury.dm
index e59bc2f774d..ce520aa1fca 100644
--- a/code/modules/shuttle/battlecruiser_starfury.dm
+++ b/code/modules/shuttle/battlecruiser_starfury.dm
@@ -165,7 +165,7 @@
spawner.antag_team = team
if(candidates.len > 0)
var/mob/our_candidate = candidates[1]
- spawner.create(our_candidate)
+ spawner.create_from_ghost(our_candidate)
spawner.antag_team.players_spawned += (our_candidate.ckey)
candidates.Splice(1, 2)
notify_ghosts(
diff --git a/code/modules/shuttle/emergency.dm b/code/modules/shuttle/emergency.dm
index e1688a7eeab..ac28d380518 100644
--- a/code/modules/shuttle/emergency.dm
+++ b/code/modules/shuttle/emergency.dm
@@ -544,9 +544,8 @@
if(time_left <= 0)
//move each escape pod to its corresponding escape dock
- for(var/A in SSshuttle.mobile_docking_ports)
- var/obj/docking_port/mobile/M = A
- M.on_emergency_dock()
+ for(var/obj/docking_port/mobile/port as anything in SSshuttle.mobile_docking_ports)
+ port.on_emergency_dock()
// now move the actual emergency shuttle to centcom
// unless the shuttle is "hijacked"
diff --git a/code/modules/shuttle/shuttle.dm b/code/modules/shuttle/shuttle.dm
index b69c21bf69f..a0ed6160c45 100644
--- a/code/modules/shuttle/shuttle.dm
+++ b/code/modules/shuttle/shuttle.dm
@@ -1164,7 +1164,8 @@
//Called when emergency shuttle docks at centcom
/obj/docking_port/mobile/proc/on_emergency_dock()
- //Mapping a new docking point for each ship mappers could potentially want docking with centcom would take up lots of space, just let them keep flying off into the sunset for their greentext
+ // Mapping a new docking point for each ship mappers could potentially want docking with centcom would take up lots of space,
+ // just let them keep flying off "into the sunset" for their greentext.
if(launch_status == ENDGAME_LAUNCHED)
launch_status = ENDGAME_TRANSIT
diff --git a/code/modules/surgery/tools.dm b/code/modules/surgery/tools.dm
index 0c941093d19..76a313020f7 100644
--- a/code/modules/surgery/tools.dm
+++ b/code/modules/surgery/tools.dm
@@ -540,14 +540,14 @@
var/selected_reagent = tgui_input_list(usr, "Select reagent to filter", "Whitelist reagent", GLOB.chemical_name_list)
if(!selected_reagent)
return TRUE
-
+
var/chem_id = get_chem_id(selected_reagent)
if(!chem_id)
return TRUE
-
+
if(!(chem_id in whitelist))
whitelist[chem_id] = selected_reagent
-
+
if("remove")
diff --git a/code/modules/unit_tests/mecha_damage.dm b/code/modules/unit_tests/mecha_damage.dm
index e3ca7566e90..55081e9365c 100644
--- a/code/modules/unit_tests/mecha_damage.dm
+++ b/code/modules/unit_tests/mecha_damage.dm
@@ -30,7 +30,7 @@
// Get a sample laser weapon.
// The captain's laser gun here is chosen primarily because it deals more damage than normal lasers.
var/obj/item/gun/energy/laser/dummy_laser = allocate(/obj/item/gun/energy/laser/captain)
- dummy_laser.safety = FALSE // SKYRAT EDIT - Safeties on guns make them impossible to shoot :)
+ qdel(dummy_laser.GetComponent(/datum/component/gun_safety)) // SKYRAT EDIT - Safeties on guns make them impossible to shoot :)
var/obj/item/ammo_casing/laser_ammo = dummy_laser.ammo_type[1]
var/obj/projectile/beam/laser_fired = initial(laser_ammo.projectile_type)
var/expected_laser_damage = round(dummy_laser.projectile_damage_multiplier * initial(laser_fired.damage) * (1 - expected_laser_armor / 100), DAMAGE_PRECISION)
@@ -38,7 +38,7 @@
// Get a sample ballistic weapon.
// The syndicate .357 here is chosen because it does a lot of damage.
var/obj/item/gun/ballistic/dummy_gun = allocate(/obj/item/gun/ballistic/revolver)
- dummy_gun.safety = FALSE // SKYRAT EDIT - Safeties on guns make them impossible to shoot :)
+ qdel(dummy_gun.GetComponent(/datum/component/gun_safety)) // SKYRAT EDIT - Safeties on guns make them impossible to shoot :)
var/obj/item/ammo_casing/ballistic_ammo = dummy_gun.magazine.ammo_type
var/obj/projectile/bullet_fired = initial(ballistic_ammo.projectile_type)
var/expected_bullet_damage = round(dummy_gun.projectile_damage_multiplier * initial(bullet_fired.damage) * (1 - expected_bullet_armor / 100), DAMAGE_PRECISION)
diff --git a/code/modules/unit_tests/projectiles.dm b/code/modules/unit_tests/projectiles.dm
index e0c04f0ce9e..8f0872d0e89 100644
--- a/code/modules/unit_tests/projectiles.dm
+++ b/code/modules/unit_tests/projectiles.dm
@@ -18,8 +18,8 @@
gunner.put_in_hands(test_gun, forced=TRUE)
//SKYRAT EDIT ADDITION BEGIN
- if(test_gun.has_gun_safety)
- test_gun.toggle_safety(gunner)
+ if(test_gun.GetComponent(/datum/component/gun_safety))
+ qdel(test_gun.GetComponent(/datum/component/gun_safety))
loaded_bullet.wound_bonus = CANT_WOUND //Baseline wounding makes things weird
//SKYRAT EDIT ADDITION END
gunner.set_combat_mode(FALSE) // just to make sure we know we're not trying to pistol-whip them
diff --git a/code/modules/vehicles/mecha/mecha_construction_paths.dm b/code/modules/vehicles/mecha/mecha_construction_paths.dm
index d3d8702f601..7df97650d0e 100644
--- a/code/modules/vehicles/mecha/mecha_construction_paths.dm
+++ b/code/modules/vehicles/mecha/mecha_construction_paths.dm
@@ -384,7 +384,9 @@
outer_plating_amount=1
/datum/component/construction/mecha/gygax/action(datum/source, atom/used_atom, mob/user)
- return INVOKE_ASYNC(src, PROC_REF(check_step), used_atom,user)
+ ASYNC //This proc will never actually sleep, it calls do_after with a time of 0.
+ . = check_step(used_atom, user)
+ return .
//CLARKE
/datum/component/construction/unordered/mecha_chassis/clarke
diff --git a/html/changelogs/AutoChangeLog-pr-19154.yml b/html/changelogs/AutoChangeLog-pr-19154.yml
deleted file mode 100644
index 7f0518e33c0..00000000000
--- a/html/changelogs/AutoChangeLog-pr-19154.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-author: "Rhials"
-delete-after: True
-changes:
- - rscadd: "Midround changeling spawn event."
- - rscadd: "Changeling meteor. It has a present for you."
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-19237.yml b/html/changelogs/AutoChangeLog-pr-19237.yml
deleted file mode 100644
index 20e1b7a30bf..00000000000
--- a/html/changelogs/AutoChangeLog-pr-19237.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Melbert"
-delete-after: True
-changes:
- - bugfix: "Revolutionary Heretics and Cultists Traitors no longer lose all of their joy in life after being de-converted from their respective causes."
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-19407.yml b/html/changelogs/AutoChangeLog-pr-19407.yml
deleted file mode 100644
index f5596b6ca30..00000000000
--- a/html/changelogs/AutoChangeLog-pr-19407.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-author: "SkyratBot"
-delete-after: True
-changes:
- - refactor: "Refactors how nuclear activation disk works. Shouldn't notice a whole lot but if you do, it might be because of this."
- - admin: "Disk now has an examine message for whether it's secure or not, to make it less ambiguous for players."
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-19414.yml b/html/changelogs/AutoChangeLog-pr-19414.yml
deleted file mode 100644
index dd35cf98921..00000000000
--- a/html/changelogs/AutoChangeLog-pr-19414.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-author: "LT3"
-delete-after: True
-changes:
- - qol: "Engineering override access can now be manually controlled at the communications console and keycard auth devices"
- - bugfix: "Fixed missing undefine in airlock module"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-19489.yml b/html/changelogs/AutoChangeLog-pr-19489.yml
new file mode 100644
index 00000000000..d6f5296aa5e
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-19489.yml
@@ -0,0 +1,4 @@
+author: "Paxilmaniac"
+delete-after: True
+changes:
+ - balance: "CMGs in the armory come in a gunset which includes both a non-lethal and two lethal magazines right out the box, rather than making officers have to print lethal magazines to use the weapon in a lethal role."
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-19587.yml b/html/changelogs/AutoChangeLog-pr-19587.yml
deleted file mode 100644
index 36a584c6f64..00000000000
--- a/html/changelogs/AutoChangeLog-pr-19587.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Ebin-Halcyon"
-delete-after: True
-changes:
- - imageadd: "GAGS custom winter coats, berets, and ranger ponchos have been cleaned up with a nicer palette and prettier sprites."
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-19598.yml b/html/changelogs/AutoChangeLog-pr-19598.yml
deleted file mode 100644
index c51cf487033..00000000000
--- a/html/changelogs/AutoChangeLog-pr-19598.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "SkyratBot"
-delete-after: True
-changes:
- - bugfix: "Reagents metabolize properly when dead. (If they're supposed to.)"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-19615.yml b/html/changelogs/AutoChangeLog-pr-19615.yml
deleted file mode 100644
index 7c5cb45800c..00000000000
--- a/html/changelogs/AutoChangeLog-pr-19615.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Paxilmaniac"
-delete-after: True
-changes:
- - balance: "Any helmet or mask that has 100 bio armor (Biological armor level X for the tag fans) will protect you against cortical borers entering your head."
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-19624.yml b/html/changelogs/AutoChangeLog-pr-19624.yml
deleted file mode 100644
index 08bcc680960..00000000000
--- a/html/changelogs/AutoChangeLog-pr-19624.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "ShamanSliph"
-delete-after: True
-changes:
- - bugfix: "Fixed loadout Laptops not properly spawning."
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-19701.yml b/html/changelogs/AutoChangeLog-pr-19701.yml
new file mode 100644
index 00000000000..510d7cc00b5
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-19701.yml
@@ -0,0 +1,4 @@
+author: "SkyratBot"
+delete-after: True
+changes:
+ - bugfix: "Corgis show their ID on examine."
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-19721.yml b/html/changelogs/AutoChangeLog-pr-19721.yml
new file mode 100644
index 00000000000..609e82a7944
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-19721.yml
@@ -0,0 +1,7 @@
+author: "Melbert"
+delete-after: True
+changes:
+ - bugfix: "Fixed a eswords, some tools, and some other misc. items from being invisible while extended / active"
+ - bugfix: "Teleshields and other misc items not extending in hand when active"
+ - bugfix: "Switchblades click on extend again"
+ - bugfix: "Pendrivers click on extend"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-19722.yml b/html/changelogs/AutoChangeLog-pr-19722.yml
new file mode 100644
index 00000000000..04b06c9e76b
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-19722.yml
@@ -0,0 +1,4 @@
+author: "Rhials"
+delete-after: True
+changes:
+ - spellcheck: "Fixes the Russian/Bounty Hunter fugitive hunter spawn backstory messages."
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-19723.yml b/html/changelogs/AutoChangeLog-pr-19723.yml
new file mode 100644
index 00000000000..ecf44734ea9
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-19723.yml
@@ -0,0 +1,4 @@
+author: "Cyprex"
+delete-after: True
+changes:
+ - bugfix: "Ghost Cafe Spawners work once again!"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-19724.yml b/html/changelogs/AutoChangeLog-pr-19724.yml
new file mode 100644
index 00000000000..77b16349825
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-19724.yml
@@ -0,0 +1,4 @@
+author: "Melbert"
+delete-after: True
+changes:
+ - bugfix: "Fixes pirates and starfury assailants keeping minds of past lives"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-19725.yml b/html/changelogs/AutoChangeLog-pr-19725.yml
new file mode 100644
index 00000000000..afdadb97d70
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-19725.yml
@@ -0,0 +1,4 @@
+author: "SkyratBot"
+delete-after: True
+changes:
+ - bugfix: "slime processor no longer sucks in slimes that it can't reach (glass panes, blocked by other machines etc)"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-19726.yml b/html/changelogs/AutoChangeLog-pr-19726.yml
new file mode 100644
index 00000000000..c3249f7f239
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-19726.yml
@@ -0,0 +1,4 @@
+author: "SkyratBot"
+delete-after: True
+changes:
+ - bugfix: "The party alarm now works again!"
\ No newline at end of file
diff --git a/icons/area/areas_misc.dmi b/icons/area/areas_misc.dmi
index 8e4b8a3803e..218db925741 100644
Binary files a/icons/area/areas_misc.dmi and b/icons/area/areas_misc.dmi differ
diff --git a/icons/mob/clothing/head/wizard.dmi b/icons/mob/clothing/head/wizard.dmi
index a6961ca7626..785ed63ca5b 100644
Binary files a/icons/mob/clothing/head/wizard.dmi and b/icons/mob/clothing/head/wizard.dmi differ
diff --git a/icons/mob/clothing/suits/wizard.dmi b/icons/mob/clothing/suits/wizard.dmi
index e8ac43bb6ca..454bc1f3cf1 100644
Binary files a/icons/mob/clothing/suits/wizard.dmi and b/icons/mob/clothing/suits/wizard.dmi differ
diff --git a/icons/mob/inhands/clothing/hats_lefthand.dmi b/icons/mob/inhands/clothing/hats_lefthand.dmi
index 540c586d905..e0f246140ae 100644
Binary files a/icons/mob/inhands/clothing/hats_lefthand.dmi and b/icons/mob/inhands/clothing/hats_lefthand.dmi differ
diff --git a/icons/mob/inhands/clothing/hats_righthand.dmi b/icons/mob/inhands/clothing/hats_righthand.dmi
index 343ecedcd07..a7d3c60f5f3 100644
Binary files a/icons/mob/inhands/clothing/hats_righthand.dmi and b/icons/mob/inhands/clothing/hats_righthand.dmi differ
diff --git a/icons/mob/inhands/weapons/staves_lefthand.dmi b/icons/mob/inhands/weapons/staves_lefthand.dmi
index 8aec740579f..82c552b5038 100644
Binary files a/icons/mob/inhands/weapons/staves_lefthand.dmi and b/icons/mob/inhands/weapons/staves_lefthand.dmi differ
diff --git a/icons/mob/inhands/weapons/staves_righthand.dmi b/icons/mob/inhands/weapons/staves_righthand.dmi
index 6cba11eef9c..769709f53da 100644
Binary files a/icons/mob/inhands/weapons/staves_righthand.dmi and b/icons/mob/inhands/weapons/staves_righthand.dmi differ
diff --git a/icons/mob/inhands/weapons/swords_lefthand.dmi b/icons/mob/inhands/weapons/swords_lefthand.dmi
index 8dfada39e21..b29d6dbcf1e 100644
Binary files a/icons/mob/inhands/weapons/swords_lefthand.dmi and b/icons/mob/inhands/weapons/swords_lefthand.dmi differ
diff --git a/icons/mob/inhands/weapons/swords_righthand.dmi b/icons/mob/inhands/weapons/swords_righthand.dmi
index 4ca37418be2..862ebbdc8c3 100644
Binary files a/icons/mob/inhands/weapons/swords_righthand.dmi and b/icons/mob/inhands/weapons/swords_righthand.dmi differ
diff --git a/icons/obj/clothing/head/wizard.dmi b/icons/obj/clothing/head/wizard.dmi
index 8fcdbd6fcd7..29595f02fc2 100644
Binary files a/icons/obj/clothing/head/wizard.dmi and b/icons/obj/clothing/head/wizard.dmi differ
diff --git a/icons/obj/clothing/suits/wizard.dmi b/icons/obj/clothing/suits/wizard.dmi
index 9c2b4eee179..fcfa748d3b3 100644
Binary files a/icons/obj/clothing/suits/wizard.dmi and b/icons/obj/clothing/suits/wizard.dmi differ
diff --git a/icons/obj/weapons/guns/magic.dmi b/icons/obj/weapons/guns/magic.dmi
index ef25b89f77a..3a97682ef66 100644
Binary files a/icons/obj/weapons/guns/magic.dmi and b/icons/obj/weapons/guns/magic.dmi differ
diff --git a/modular_skyrat/master_files/code/modules/admin/admin.dm b/modular_skyrat/master_files/code/modules/admin/admin.dm
index 38a4dea6c4e..86f86bc7e12 100644
--- a/modular_skyrat/master_files/code/modules/admin/admin.dm
+++ b/modular_skyrat/master_files/code/modules/admin/admin.dm
@@ -19,6 +19,22 @@ GLOBAL_VAR_INIT(dchat_allowed, TRUE)
GLOB.dchat_allowed = !GLOB.dchat_allowed
to_chat(world, span_oocplain("The dead chat channel has been globally [GLOB.dchat_allowed ? "enabled" : "disabled"]."))
+/datum/admin_help
+ /// Have we requested this ticket to stop being part of the Ticket Ping subsystem?
+ var/ticket_ping_stop = FALSE
+ /// Are we added to the ticket ping subsystem in the first place
+ var/ticket_ping = FALSE
+ /// Who is handling this admin help?
+ var/handler
+ /// All sanitized text
+ var/full_text
+
+/datum/admin_help/ClosureLinks(ref_src)
+ . = ..()
+ . += " (HANDLE)" //SKYRAT EDIT ADDITION
+ . += " (PING MUTE)" //SKYRAT EDIT ADDITION
+ . += " (MHELP)"
+
//Let the initiator know their ahelp is being handled
/datum/admin_help/proc/handle_issue(key_name = key_name_admin(usr))
if(state != AHELP_ACTIVE)
@@ -45,3 +61,24 @@ GLOBAL_VAR_INIT(dchat_allowed, TRUE)
handler = "[usr.ckey]"
return TRUE
+
+///Proc which converts an admin_help ticket to a mentorhelp
+/datum/admin_help/proc/convert_to_mentorhelp(key_name = key_name_admin(usr))
+ if(state != AHELP_ACTIVE)
+ return FALSE
+
+ if(handler && handler != usr.ckey)
+ var/response = tgui_alert(usr, "This ticket is already being handled by [handler]. Do you want to continue?", "Ticket already assigned", list("Yes", "No"))
+ if(!response || response == "No")
+ return FALSE
+
+ add_verb(initiator, /client/verb/mentorhelp) // Way to override mentorhelp cooldown.
+
+ to_chat(initiator, span_adminhelp("Your ticket was converted to Mentorhelp"))
+ initiator.mentorhelp(full_text)
+ initiator.giveadminhelpverb()
+
+ message_admins("[key_name] converted Ticket #[id] from [initiator_key_name] into Mentorhelp")
+ log_admin("[usr.client] converted Ticket #[id] from [initiator_ckey] into Mentorhelp")
+
+ Close(key_name, TRUE)
diff --git a/modular_skyrat/master_files/code/modules/clothing/under/jobs/engineering.dm b/modular_skyrat/master_files/code/modules/clothing/under/jobs/engineering.dm
index d9712158361..1df34638f4b 100644
--- a/modular_skyrat/master_files/code/modules/clothing/under/jobs/engineering.dm
+++ b/modular_skyrat/master_files/code/modules/clothing/under/jobs/engineering.dm
@@ -28,10 +28,10 @@
has_sensor = NO_SENSORS
/obj/item/clothing/under/rank/engineering/engineer/skyrat/trouser
- name = "engineer's trousers"
+ name = "engineering trousers"
desc = "An engineering-orange set of trousers. Their waistband proudly displays an 'anti-radiation' symbol, though the effectiveness of radiation-proof-pants-only is still up for debate."
icon_state = "workpants_orange"
- body_parts_covered = GROIN
+ body_parts_covered = GROIN|LEGS
can_adjust = FALSE
female_sprite_flags = FEMALE_UNIFORM_NO_BREASTS
diff --git a/modular_skyrat/master_files/code/modules/clothing/under/jobs/rnd.dm b/modular_skyrat/master_files/code/modules/clothing/under/jobs/rnd.dm
index fa7ca2c40c6..e4b5a1ef585 100644
--- a/modular_skyrat/master_files/code/modules/clothing/under/jobs/rnd.dm
+++ b/modular_skyrat/master_files/code/modules/clothing/under/jobs/rnd.dm
@@ -32,8 +32,8 @@
has_sensor = NO_SENSORS
/obj/item/clothing/under/rank/rnd/scientist/skyrat/hlscience
- name = "ridiculous scientist outfit"
- desc = "The tie is mandatory."
+ name = "science team uniform"
+ desc = "A simple semi-formal uniform consisting of a grayish-blue shirt and off-white slacks, paired with a ridiculous, but mandatory, tie."
icon_state = "hl_scientist"
can_adjust = FALSE
@@ -73,7 +73,7 @@
/*
* OVERRIDES
-* Remind Orion to look over these when TG finishes their science resprites
+* ORION TODO: look over these when TG finishes their science resprites (any day now...)
*/
/obj/item/clothing/under/rank/rnd/scientist
diff --git a/modular_skyrat/master_files/code/modules/jobs/job_types/blackmarket.dm b/modular_skyrat/master_files/code/modules/jobs/job_types/blackmarket.dm
new file mode 100644
index 00000000000..b49468b81d8
--- /dev/null
+++ b/modular_skyrat/master_files/code/modules/jobs/job_types/blackmarket.dm
@@ -0,0 +1,3 @@
+/datum/job/blackmarket
+ title = ROLE_BLACK_MARKET_DEALER
+ policy_index = ROLE_BLACK_MARKET_DEALER
diff --git a/modular_skyrat/master_files/code/modules/jobs/job_types/ds2.dm b/modular_skyrat/master_files/code/modules/jobs/job_types/ds2.dm
new file mode 100644
index 00000000000..e4bf753e7e6
--- /dev/null
+++ b/modular_skyrat/master_files/code/modules/jobs/job_types/ds2.dm
@@ -0,0 +1,3 @@
+/datum/job/ds2
+ title = ROLE_DS2
+ policy_index = ROLE_DS2
diff --git a/modular_skyrat/master_files/code/modules/jobs/job_types/freighter_crew.dm b/modular_skyrat/master_files/code/modules/jobs/job_types/freighter_crew.dm
new file mode 100644
index 00000000000..ef5bcc0d11e
--- /dev/null
+++ b/modular_skyrat/master_files/code/modules/jobs/job_types/freighter_crew.dm
@@ -0,0 +1,3 @@
+/datum/job/freighter_crew
+ title = ROLE_FREIGHTER_CREW
+ policy_index = ROLE_FREIGHTER_CREW
diff --git a/modular_skyrat/master_files/code/modules/jobs/job_types/ghostcafe.dm b/modular_skyrat/master_files/code/modules/jobs/job_types/ghostcafe.dm
new file mode 100644
index 00000000000..7b88a967aab
--- /dev/null
+++ b/modular_skyrat/master_files/code/modules/jobs/job_types/ghostcafe.dm
@@ -0,0 +1,3 @@
+/datum/job/ghostcafe
+ title = ROLE_GHOST_CAFE
+ policy_index = ROLE_GHOST_CAFE
diff --git a/modular_skyrat/master_files/code/modules/jobs/job_types/tarkon.dm b/modular_skyrat/master_files/code/modules/jobs/job_types/tarkon.dm
new file mode 100644
index 00000000000..9beafecc8c7
--- /dev/null
+++ b/modular_skyrat/master_files/code/modules/jobs/job_types/tarkon.dm
@@ -0,0 +1,3 @@
+/datum/job/tarkon
+ title = ROLE_PORT_TARKON
+ policy_index = ROLE_PORT_TARKON
diff --git a/modular_skyrat/master_files/code/modules/projectiles/guns/ballistic.dm b/modular_skyrat/master_files/code/modules/projectiles/guns/ballistic.dm
deleted file mode 100644
index bc49ab26cf3..00000000000
--- a/modular_skyrat/master_files/code/modules/projectiles/guns/ballistic.dm
+++ /dev/null
@@ -1,6 +0,0 @@
-// A file for overrides to ballistic weapons that don't have a special Skyrat icon.
-/obj/item/gun/ballistic/rifle/lionhunter
- icon = 'icons/obj/weapons/guns/ballistic.dmi'
-
-/obj/item/gun/ballistic/rifle/boltaction/brand_new/prime
- icon = 'icons/obj/weapons/guns/ballistic.dmi'
diff --git a/modular_skyrat/master_files/code/modules/projectiles/guns/ballistic/automatic.dm b/modular_skyrat/master_files/code/modules/projectiles/guns/ballistic/automatic.dm
deleted file mode 100644
index 6864d0611b6..00000000000
--- a/modular_skyrat/master_files/code/modules/projectiles/guns/ballistic/automatic.dm
+++ /dev/null
@@ -1,348 +0,0 @@
-/obj/item/gun/ballistic/automatic
- w_class = WEIGHT_CLASS_NORMAL
- can_suppress = TRUE
- burst_size = 3
- fire_delay = 2
- semi_auto = TRUE
- fire_sound = 'sound/weapons/gun/smg/shot.ogg'
- fire_sound_volume = 90
- rack_sound = 'sound/weapons/gun/smg/smgrack.ogg'
- suppressed_sound = 'sound/weapons/gun/smg/shot_suppressed.ogg'
- fire_select_modes = list(SELECT_SEMI_AUTOMATIC, SELECT_BURST_SHOT, SELECT_FULLY_AUTOMATIC)
-
-/obj/item/gun/ballistic/automatic/proto
- name = "\improper Nanotrasen Saber SMG"
- desc = "A prototype three-round burst 9mm submachine gun, designated 'SABR'. Has a threaded barrel for suppressors."
- icon_state = "saber"
- selector_switch_icon = TRUE
- mag_display = TRUE
- empty_indicator = TRUE
- mag_type = /obj/item/ammo_box/magazine/smgm9mm
- pin = null
- bolt_type = BOLT_TYPE_LOCKING
- show_bolt_icon = FALSE
- company_flag = COMPANY_NANOTRASEN
-
-/obj/item/gun/ballistic/automatic/proto/unrestricted
- pin = /obj/item/firing_pin
-
-/obj/item/gun/ballistic/automatic/c20r
- name = "\improper C-20r SMG"
- desc = "A bullpup three-round burst .45 SMG, designated 'C-20r'."
- icon_state = "c20r"
- inhand_icon_state = "c20r"
- selector_switch_icon = TRUE
- mag_type = /obj/item/ammo_box/magazine/smgm45
- fire_delay = 2
- burst_size = 3
- pin = /obj/item/firing_pin/implant/pindicate
- can_bayonet = TRUE
- knife_x_offset = 26
- knife_y_offset = 12
- mag_display = TRUE
- mag_display_ammo = TRUE
- empty_indicator = TRUE
- company_flag = COMPANY_SCARBOROUGH
-
-/obj/item/gun/ballistic/automatic/c20r/update_overlays()
- . = ..()
- if(!chambered && empty_indicator)
- . += "[icon_state]_empty"
-
-/obj/item/gun/ballistic/automatic/c20r/unrestricted
- pin = /obj/item/firing_pin
-
-/obj/item/gun/ballistic/automatic/c20r/Initialize(mapload)
- . = ..()
- update_appearance()
-
-/obj/item/gun/ballistic/automatic/wt550
- name = "security auto rifle"
- desc = "An outdated personal defence weapon. Uses 4.6x30mm rounds and is designated the WT-550 Automatic Rifle."
- icon_state = "wt550"
- w_class = WEIGHT_CLASS_BULKY
- inhand_icon_state = "arg"
- mag_type = /obj/item/ammo_box/magazine/wt550m9
- fire_delay = 2
- can_suppress = FALSE
- burst_size = 1
- fire_select_modes = list(SELECT_SEMI_AUTOMATIC, SELECT_FULLY_AUTOMATIC)
- can_bayonet = TRUE
- knife_x_offset = 25
- knife_y_offset = 12
- mag_display = TRUE
- mag_display_ammo = TRUE
- empty_indicator = TRUE
- company_flag = COMPANY_NANOTRASEN
-
-/obj/item/gun/ballistic/automatic/plastikov
- name = "\improper PP-95 SMG"
- desc = "An ancient 9mm submachine gun pattern updated and simplified to lower costs, though perhaps simplified too much."
- icon_state = "plastikov"
- inhand_icon_state = "plastikov"
- mag_type = /obj/item/ammo_box/magazine/plastikov9mm
- burst_size = 5
- spread = 15
- can_suppress = FALSE
- projectile_damage_multiplier = 0.35 // It's like 10.5 damage per bullet, it's close enough to 10 shots
- mag_display = TRUE
- empty_indicator = TRUE
- fire_sound = 'sound/weapons/gun/smg/shot_alt.ogg'
- company_flag = COMPANY_IZHEVSK
-
-/obj/item/gun/ballistic/automatic/mini_uzi
- name = "\improper type U3 uzi"
- desc = "A lightweight, burst-fire submachine gun, for when you really want someone dead. Uses 9mm rounds."
- icon_state = "miniuzi"
- mag_type = /obj/item/ammo_box/magazine/uzim9mm
- burst_size = 2
- bolt_type = BOLT_TYPE_OPEN
- show_bolt_icon = FALSE
- mag_display = TRUE
- rack_sound = 'sound/weapons/gun/pistol/slide_lock.ogg'
- company_flag = COMPANY_OLDARMS
-
-/obj/item/gun/ballistic/automatic/m90
- name = "\improper M-90gl carbine"
- desc = "A three-round burst 5.56 toploading carbine, designated 'M-90gl'. Has an attached underbarrel grenade launcher which can be fired using right click."
- icon_state = "m90"
- w_class = WEIGHT_CLASS_BULKY
- inhand_icon_state = "m90"
- selector_switch_icon = TRUE
- mag_type = /obj/item/ammo_box/magazine/m556
- can_suppress = FALSE
- var/obj/item/gun/ballistic/revolver/grenadelauncher/underbarrel
- burst_size = 3
- fire_delay = 2
- spread = 5
- pin = /obj/item/firing_pin/implant/pindicate
- mag_display = TRUE
- empty_indicator = TRUE
- fire_sound = 'sound/weapons/gun/smg/shot_alt.ogg'
- company_flag = COMPANY_SCARBOROUGH
-
-/obj/item/gun/ballistic/automatic/m90/Initialize(mapload)
- . = ..()
- underbarrel = new /obj/item/gun/ballistic/revolver/grenadelauncher(src)
- update_appearance()
-
-/obj/item/gun/ballistic/automatic/m90/Destroy()
- QDEL_NULL(underbarrel)
- return ..()
-
-/obj/item/gun/ballistic/automatic/m90/unrestricted
- pin = /obj/item/firing_pin
-
-/obj/item/gun/ballistic/automatic/m90/unrestricted/Initialize(mapload)
- . = ..()
- underbarrel = new /obj/item/gun/ballistic/revolver/grenadelauncher/unrestricted(src)
- update_appearance()
-
-/obj/item/gun/ballistic/automatic/m90/afterattack_secondary(atom/target, mob/living/user, flag, params)
- underbarrel.afterattack(target, user, flag, params)
- return SECONDARY_ATTACK_CONTINUE_CHAIN
-
-/obj/item/gun/ballistic/automatic/m90/attackby(obj/item/attacking_item, mob/user, params)
- if(istype(attacking_item, /obj/item/ammo_casing))
- if(istype(attacking_item, underbarrel.magazine.ammo_type))
- underbarrel.attack_self(user)
- underbarrel.attackby(attacking_item, user, params)
- else
- ..()
-
-/obj/item/gun/ballistic/automatic/tommygun
- name = "\improper Thompson SMG"
- desc = "Based on the classic 'Chicago Typewriter'."
- icon_state = "tommygun"
- inhand_icon_state = "shotgun"
- selector_switch_icon = TRUE
- w_class = WEIGHT_CLASS_BULKY
- slot_flags = 0
- mag_type = /obj/item/ammo_box/magazine/tommygunm45
- can_suppress = FALSE
- burst_size = 1
- fire_select_modes = list(SELECT_SEMI_AUTOMATIC, SELECT_FULLY_AUTOMATIC)
- fire_delay = 1
- bolt_type = BOLT_TYPE_OPEN
- empty_indicator = TRUE
- show_bolt_icon = FALSE
- company_flag = COMPANY_OLDARMS
-
-/obj/item/gun/ballistic/automatic/tommygun/therealtommy
- name = "Tommy gun"
- desc = "The classic 'Chicago Typewriter'."
- company_flag = null // This is the real deal, you hear?
-
-/obj/item/gun/ballistic/automatic/ar
- name = "\improper NT-ARG 'Boarder'"
- desc = "A robust assault rifle used by Nanotrasen fighting forces."
- icon_state = "arg"
- inhand_icon_state = "arg"
- slot_flags = 0
- mag_type = /obj/item/ammo_box/magazine/m556
- can_suppress = FALSE
- burst_size = 3
- fire_delay = 1
- company_flag = COMPANY_NANOTRASEN
-
-
-// L6 SAW //
-
-/obj/item/gun/ballistic/automatic/l6_saw
- name = "\improper L6 SAW"
- desc = "A large light machine gun chambered for the 7.12x82mm cartridge."
- icon_state = "l6"
- inhand_icon_state = "l6closedmag"
- base_icon_state = "l6"
- w_class = WEIGHT_CLASS_HUGE
- slot_flags = 0
- mag_type = /obj/item/ammo_box/magazine/mm712x82
- weapon_weight = WEAPON_HEAVY
- burst_size = 1
- fire_select_modes = list(SELECT_SEMI_AUTOMATIC, SELECT_FULLY_AUTOMATIC)
- can_suppress = FALSE
- spread = 7
- pin = /obj/item/firing_pin/implant/pindicate
- bolt_type = BOLT_TYPE_OPEN
- show_bolt_icon = FALSE
- mag_display = TRUE
- mag_display_ammo = TRUE
- tac_reloads = FALSE
- fire_sound = 'sound/weapons/gun/l6/shot.ogg'
- rack_sound = 'sound/weapons/gun/l6/l6_rack.ogg'
- suppressed_sound = 'sound/weapons/gun/general/heavy_shot_suppressed.ogg'
- var/cover_open = FALSE
- company_flag = COMPANY_SCARBOROUGH
-
-/obj/item/gun/ballistic/automatic/l6_saw/unrestricted
- pin = /obj/item/firing_pin
-
-/obj/item/gun/ballistic/automatic/l6_saw/Initialize(mapload)
- . = ..()
- AddElement(/datum/element/update_icon_updates_onmob)
-
-/obj/item/gun/ballistic/automatic/l6_saw/examine(mob/user)
- . = ..()
- . += "alt + click to [cover_open ? "close" : "open"] the dust cover."
- if(cover_open && magazine)
- . += span_notice("It seems like you could use an empty hand to remove the magazine.")
-
-
-/obj/item/gun/ballistic/automatic/l6_saw/AltClick(mob/user)
- if(!user.canUseTopic(src))
- return
- cover_open = !cover_open
- balloon_alert(user, "cover [cover_open ? "open" : "closed"]")
- playsound(src, 'sound/weapons/gun/l6/l6_door.ogg', 60, TRUE)
- update_appearance()
-
-/obj/item/gun/ballistic/automatic/l6_saw/update_icon_state()
- . = ..()
- inhand_icon_state = "[base_icon_state][cover_open ? "open" : "closed"][magazine ? "mag":"nomag"]"
-
-/obj/item/gun/ballistic/automatic/l6_saw/update_overlays()
- . = ..()
- . += "l6_door_[cover_open ? "open" : "closed"]"
-
-
-/obj/item/gun/ballistic/automatic/l6_saw/afterattack(atom/target as mob|obj|turf, mob/living/user as mob|obj, flag, params)
- if(cover_open)
- balloon_alert(user, "cover open!")
- return
- else
- . = ..()
- update_appearance()
-
-// ATTACK HAND IGNORING PARENT RETURN VALUE
-/obj/item/gun/ballistic/automatic/l6_saw/attack_hand(mob/user, list/modifiers)
- if (loc != user)
- ..()
- return
- if (!cover_open)
- balloon_alert(user, "cover closed!")
- return
- ..()
-
-/obj/item/gun/ballistic/automatic/l6_saw/attackby(obj/item/attacking_item, mob/user, params)
- if(!cover_open && istype(attacking_item, mag_type))
- balloon_alert(user, "dust closed!")
- return
- ..()
-
-// SNIPER //
-
-/obj/item/gun/ballistic/automatic/sniper_rifle
- name = "sniper rifle"
- desc = "A long ranged weapon that does significant damage. No, you can't quickscope."
- icon_state = "sniper"
- w_class = WEIGHT_CLASS_BULKY
- inhand_icon_state = "sniper"
- worn_icon_state = null
- fire_sound = 'sound/weapons/gun/sniper/shot.ogg'
- fire_sound_volume = 90
- vary_fire_sound = FALSE
- load_sound = 'sound/weapons/gun/sniper/mag_insert.ogg'
- rack_sound = 'sound/weapons/gun/sniper/rack.ogg'
- suppressed_sound = 'sound/weapons/gun/general/heavy_shot_suppressed.ogg'
- recoil = 2
- weapon_weight = WEAPON_HEAVY
- mag_type = /obj/item/ammo_box/magazine/sniper_rounds
- fire_delay = 40
- burst_size = 1
- w_class = WEIGHT_CLASS_NORMAL
- slot_flags = ITEM_SLOT_BACK
- fire_select_modes = list(SELECT_SEMI_AUTOMATIC)
- mag_display = TRUE
- suppressor_x_offset = 3
- suppressor_y_offset = 3
-
-/obj/item/gun/ballistic/automatic/sniper_rifle/Initialize(mapload)
- . = ..()
- AddComponent(/datum/component/scope, range_modifier = 2)
-
-/obj/item/gun/ballistic/automatic/sniper_rifle/syndicate
- name = "syndicate sniper rifle"
- desc = "An illegally modified .50 cal sniper rifle with suppression compatibility. Quickscoping still doesn't work."
- can_suppress = TRUE
- can_unsuppress = TRUE
- pin = /obj/item/firing_pin/implant/pindicate
- company_flag = COMPANY_SCARBOROUGH
-
-// Old Semi-Auto Rifle //
-
-/obj/item/gun/ballistic/automatic/surplus
- name = "surplus rifle"
- desc = "One of countless obsolete ballistic rifles that still sees use as a cheap deterrent. Uses 10mm ammo and its bulky frame prevents one-hand firing."
- icon_state = "surplus"
- inhand_icon_state = "moistnugget"
- worn_icon_state = null
- weapon_weight = WEAPON_HEAVY
- mag_type = /obj/item/ammo_box/magazine/m10mm/rifle
- fire_delay = 30
- burst_size = 1
- can_unsuppress = TRUE
- can_suppress = TRUE
- w_class = WEIGHT_CLASS_HUGE
- slot_flags = ITEM_SLOT_BACK
- fire_select_modes = list(SELECT_SEMI_AUTOMATIC)
- mag_display = TRUE
- company_flag = COMPANY_IZHEVSK
-
-// Laser rifle (rechargeable magazine) //
-
-/obj/item/gun/ballistic/automatic/laser
- name = "laser rifle"
- desc = "Though sometimes mocked for the relatively weak firepower of their energy weapons, the logistic miracle of rechargeable ammunition has given Nanotrasen a decisive edge over many a foe."
- icon_state = "oldrifle"
- w_class = WEIGHT_CLASS_BULKY
- inhand_icon_state = "arg"
- mag_type = /obj/item/ammo_box/magazine/recharge
- empty_indicator = TRUE
- fire_delay = 2
- can_suppress = FALSE
- burst_size = 0
- // actions_types = list() SKYRAT EDIT REMOVAL
- fire_select_modes = list(SELECT_SEMI_AUTOMATIC)
- fire_sound = 'sound/weapons/laser.ogg'
- casing_ejector = FALSE
- company_flag = COMPANY_NANOTRASEN
diff --git a/modular_skyrat/master_files/icons/mob/clothing/under/cargo.dmi b/modular_skyrat/master_files/icons/mob/clothing/under/cargo.dmi
index 95627da5bde..64fbefeed4e 100644
Binary files a/modular_skyrat/master_files/icons/mob/clothing/under/cargo.dmi and b/modular_skyrat/master_files/icons/mob/clothing/under/cargo.dmi differ
diff --git a/modular_skyrat/master_files/icons/mob/clothing/under/cargo_digi.dmi b/modular_skyrat/master_files/icons/mob/clothing/under/cargo_digi.dmi
index fc868974ae7..2f5d8e83baa 100644
Binary files a/modular_skyrat/master_files/icons/mob/clothing/under/cargo_digi.dmi and b/modular_skyrat/master_files/icons/mob/clothing/under/cargo_digi.dmi differ
diff --git a/modular_skyrat/master_files/icons/mob/clothing/under/misc.dmi b/modular_skyrat/master_files/icons/mob/clothing/under/misc.dmi
index 376bd97c17e..b6fbc604457 100644
Binary files a/modular_skyrat/master_files/icons/mob/clothing/under/misc.dmi and b/modular_skyrat/master_files/icons/mob/clothing/under/misc.dmi differ
diff --git a/modular_skyrat/master_files/icons/mob/clothing/under/misc_digi.dmi b/modular_skyrat/master_files/icons/mob/clothing/under/misc_digi.dmi
index b4903b31dda..76fac7acc3c 100644
Binary files a/modular_skyrat/master_files/icons/mob/clothing/under/misc_digi.dmi and b/modular_skyrat/master_files/icons/mob/clothing/under/misc_digi.dmi differ
diff --git a/modular_skyrat/master_files/icons/mob/clothing/under/rnd.dmi b/modular_skyrat/master_files/icons/mob/clothing/under/rnd.dmi
index 30e24ed0772..35a612c221e 100644
Binary files a/modular_skyrat/master_files/icons/mob/clothing/under/rnd.dmi and b/modular_skyrat/master_files/icons/mob/clothing/under/rnd.dmi differ
diff --git a/modular_skyrat/master_files/icons/mob/clothing/under/rnd_digi.dmi b/modular_skyrat/master_files/icons/mob/clothing/under/rnd_digi.dmi
index 8178486a8e4..baed08c3844 100644
Binary files a/modular_skyrat/master_files/icons/mob/clothing/under/rnd_digi.dmi and b/modular_skyrat/master_files/icons/mob/clothing/under/rnd_digi.dmi differ
diff --git a/modular_skyrat/master_files/icons/mob/clothing/under/security.dmi b/modular_skyrat/master_files/icons/mob/clothing/under/security.dmi
index 60682d67909..e41aa8186ef 100644
Binary files a/modular_skyrat/master_files/icons/mob/clothing/under/security.dmi and b/modular_skyrat/master_files/icons/mob/clothing/under/security.dmi differ
diff --git a/modular_skyrat/master_files/icons/mob/clothing/under/security_digi.dmi b/modular_skyrat/master_files/icons/mob/clothing/under/security_digi.dmi
index 818aef9321c..2f10b968ed3 100644
Binary files a/modular_skyrat/master_files/icons/mob/clothing/under/security_digi.dmi and b/modular_skyrat/master_files/icons/mob/clothing/under/security_digi.dmi differ
diff --git a/modular_skyrat/master_files/icons/obj/clothing/under/cargo.dmi b/modular_skyrat/master_files/icons/obj/clothing/under/cargo.dmi
index abc2f4e878c..bc6d0043e13 100644
Binary files a/modular_skyrat/master_files/icons/obj/clothing/under/cargo.dmi and b/modular_skyrat/master_files/icons/obj/clothing/under/cargo.dmi differ
diff --git a/modular_skyrat/master_files/icons/obj/clothing/under/civilian.dmi b/modular_skyrat/master_files/icons/obj/clothing/under/civilian.dmi
index 2fbe0bc12f8..e206f2625c5 100644
Binary files a/modular_skyrat/master_files/icons/obj/clothing/under/civilian.dmi and b/modular_skyrat/master_files/icons/obj/clothing/under/civilian.dmi differ
diff --git a/modular_skyrat/master_files/icons/obj/clothing/under/rnd.dmi b/modular_skyrat/master_files/icons/obj/clothing/under/rnd.dmi
index 709a551c792..92d1253589e 100644
Binary files a/modular_skyrat/master_files/icons/obj/clothing/under/rnd.dmi and b/modular_skyrat/master_files/icons/obj/clothing/under/rnd.dmi differ
diff --git a/modular_skyrat/master_files/icons/obj/clothing/under/security.dmi b/modular_skyrat/master_files/icons/obj/clothing/under/security.dmi
index 10fb148e375..8b4b49c23fe 100644
Binary files a/modular_skyrat/master_files/icons/obj/clothing/under/security.dmi and b/modular_skyrat/master_files/icons/obj/clothing/under/security.dmi differ
diff --git a/modular_skyrat/modules/assault_operatives/code/armaments/armament_utility.dm b/modular_skyrat/modules/assault_operatives/code/armaments/armament_utility.dm
index 42e63f1eeac..89d6b3cf27f 100644
--- a/modular_skyrat/modules/assault_operatives/code/armaments/armament_utility.dm
+++ b/modular_skyrat/modules/assault_operatives/code/armaments/armament_utility.dm
@@ -7,7 +7,7 @@
cost = 1
/datum/armament_entry/assault_operatives/utility/thermals
- item_type = /obj/item/clothing/glasses/thermal
+ item_type = /obj/item/clothing/glasses/thermal/syndi
cost = 4
/datum/armament_entry/assault_operatives/utility/chem_keycard
diff --git a/modular_skyrat/modules/assault_operatives/code/equipment_items/guns.dm b/modular_skyrat/modules/assault_operatives/code/equipment_items/guns.dm
index feae53c6436..64112614081 100644
--- a/modular_skyrat/modules/assault_operatives/code/equipment_items/guns.dm
+++ b/modular_skyrat/modules/assault_operatives/code/equipment_items/guns.dm
@@ -3,11 +3,15 @@
/obj/item/gun/ballistic/automatic/pistol/clandestine/assault_ops
name = "\improper IGE-040 pistol"
desc = "A pistol chambered in 10mm magnum and painted in an ominous matte black. Strangely, the gun also seems to lack any form of manufacturer markings."
- company_flag = COMPANY_REMOVED
+
+/obj/item/gun/ballistic/automatic/pistol/clandestine/assault_ops/give_manufacturer_examine()
+ AddComponent(/datum/component/manufacturer_examine, COMPANY_REMOVED)
/obj/item/gun/energy/e_gun/advtaser/assault_ops
w_class = WEIGHT_CLASS_NORMAL
- company_flag = COMPANY_REMOVED
+
+/obj/item/gun/energy/e_gun/advtaser/assault_ops/give_manufacturer_examine()
+ AddComponent(/datum/component/manufacturer_examine, COMPANY_REMOVED)
// Rifle
@@ -33,17 +37,18 @@
can_suppress = TRUE
suppressor_x_offset = 4
suppressed_sound = 'sound/weapons/gun/general/heavy_shot_suppressed.ogg'
- fire_select_modes = list(SELECT_SEMI_AUTOMATIC, SELECT_BURST_SHOT)
burst_size = 2
fire_delay = 3
pin = /obj/item/firing_pin/implant/pindicate
- company_flag = COMPANY_REMOVED
/obj/item/gun/ballistic/automatic/assault_ops_rifle/Initialize(mapload)
. = ..()
AddComponent(/datum/component/scope, range_modifier = 1.5)
+/obj/item/gun/ballistic/automatic/assault_ops_rifle/give_manufacturer_examine()
+ AddComponent(/datum/component/manufacturer_examine, COMPANY_REMOVED)
+
/obj/item/ammo_box/magazine/multi_sprite/assault_ops_rifle
name = "\improper IGE-110 magazine"
desc = "A twenty round magazine built for 5.6x40mm, intended for use in the IGE-110 rifle."
@@ -85,13 +90,19 @@
mag_type = /obj/item/ammo_box/magazine/multi_sprite/assault_ops_smg
fire_sound = 'modular_skyrat/modules/sec_haul/sound/smg_fire.ogg'
can_suppress = TRUE
- fire_select_modes = list(SELECT_SEMI_AUTOMATIC, SELECT_FULLY_AUTOMATIC)
burst_size = 1
fire_delay = 0.8
projectile_damage_multiplier = 0.6
actions_types = list()
pin = /obj/item/firing_pin/implant/pindicate
- company_flag = COMPANY_REMOVED
+
+/obj/item/gun/ballistic/automatic/assault_ops_smg/Initialize(mapload)
+ . = ..()
+
+ AddComponent(/datum/component/automatic_fire, fire_delay)
+
+/obj/item/gun/ballistic/automatic/assault_ops_smg/give_manufacturer_examine()
+ AddComponent(/datum/component/manufacturer_examine, COMPANY_REMOVED)
/obj/item/ammo_box/magazine/multi_sprite/assault_ops_smg
name = "\improper IGE-260 magazine"
@@ -136,12 +147,13 @@
can_suppress = TRUE
suppressor_x_offset = 4
suppressed_sound = 'sound/weapons/gun/general/heavy_shot_suppressed.ogg'
- fire_select_modes = list(SELECT_SEMI_AUTOMATIC)
burst_size = 1
fire_delay = 1.5
actions_types = list()
pin = /obj/item/firing_pin/implant/pindicate
- company_flag = COMPANY_REMOVED
+
+/obj/item/gun/ballistic/automatic/assault_ops_shotgun/give_manufacturer_examine()
+ AddComponent(/datum/component/manufacturer_examine, COMPANY_REMOVED)
/obj/item/ammo_box/magazine/multi_sprite/assault_ops_shotgun
name = "\improper IGE-340 magazine"
@@ -205,13 +217,15 @@
can_be_sawn_off = FALSE
can_jam = FALSE
pin = /obj/item/firing_pin/implant/pindicate
- company_flag = COMPANY_REMOVED
/obj/item/gun/ballistic/rifle/boltaction/assault_ops_sniper/Initialize(mapload)
. = ..()
AddComponent(/datum/component/scope, range_modifier = 2.5)
+/obj/item/gun/ballistic/rifle/boltaction/assault_ops_sniper/give_manufacturer_examine()
+ AddComponent(/datum/component/manufacturer_examine, COMPANY_REMOVED)
+
/obj/item/ammo_box/magazine/multi_sprite/assault_ops_sniper
name = "\improper IGE-410 magazine"
desc = "A five round magazine built for .416 Stabilis, intended for use in the IGE-410 sniper."
diff --git a/modular_skyrat/modules/black_mesa/code/guns.dm b/modular_skyrat/modules/black_mesa/code/guns.dm
index 41e0e020261..aa477e30dc7 100644
--- a/modular_skyrat/modules/black_mesa/code/guns.dm
+++ b/modular_skyrat/modules/black_mesa/code/guns.dm
@@ -42,11 +42,9 @@
righthand_file ='modular_skyrat/modules/gunsgalore/icons/guns/gunsgalore_righthand.dmi'
icon_state = "mp5"
inhand_icon_state = "mp5"
- selector_switch_icon = TRUE
mag_type = /obj/item/ammo_box/magazine/mp5
bolt_type = BOLT_TYPE_LOCKING
can_suppress = TRUE
- burst_size = 3
fire_delay = 1.25
spread = 2.5
mag_display = TRUE
@@ -65,6 +63,11 @@
w_class = WEIGHT_CLASS_NORMAL
projectile_damage_multiplier = 0.7
+/obj/item/gun/ballistic/automatic/mp5/Initialize(mapload)
+ . = ..()
+
+ AddComponent(/datum/component/automatic_fire, fire_delay)
+
/obj/item/ammo_box/magazine/mp5
name = "MP5 magazine (10mm Auto)"
desc = "Magazines taking 10mm ammunition; it fits in the MP5."
diff --git a/modular_skyrat/modules/black_mesa/code/m16_variations.dm b/modular_skyrat/modules/black_mesa/code/m16_variations.dm
index 2853fafda08..0df517e498d 100644
--- a/modular_skyrat/modules/black_mesa/code/m16_variations.dm
+++ b/modular_skyrat/modules/black_mesa/code/m16_variations.dm
@@ -22,8 +22,11 @@
load_empty_sound = 'modular_skyrat/modules/gunsgalore/sound/guns/interact/sfrifle_magin.ogg'
eject_sound = 'modular_skyrat/modules/gunsgalore/sound/guns/interact/sfrifle_magout.ogg'
alt_icons = TRUE
- fire_select_modes = list(SELECT_SEMI_AUTOMATIC, SELECT_FULLY_AUTOMATIC)
+/obj/item/gun/ballistic/automatic/m16/oldarms/Initialize(mapload)
+ . = ..()
+
+ AddComponent(/datum/component/automatic_fire, fire_delay)
/obj/item/ammo_box/magazine/m16/vintage/oldarms
name = "old-fashioned mk-11.4 rifle magazine"
diff --git a/modular_skyrat/modules/cellguns/code/cellguns.dm b/modular_skyrat/modules/cellguns/code/cellguns.dm
index cc3a9425832..eaeaee29cc2 100644
--- a/modular_skyrat/modules/cellguns/code/cellguns.dm
+++ b/modular_skyrat/modules/cellguns/code/cellguns.dm
@@ -10,7 +10,9 @@
var/list/installedcells = list()
automatic_charge_overlays = FALSE //This is needed because Cell based guns use their own custom overlay system.
- has_gun_safety = TRUE
+
+/obj/item/gun/energy/cell_loaded/give_gun_safeties()
+ return
/obj/item/gun/energy/cell_loaded/examine(mob/user)
. = ..()
diff --git a/modular_skyrat/modules/company_imports/code/datums/cargo_pack.dm b/modular_skyrat/modules/company_imports/code/datums/cargo_pack.dm
index 63e860a2ab4..040eaa2c4df 100644
--- a/modular_skyrat/modules/company_imports/code/datums/cargo_pack.dm
+++ b/modular_skyrat/modules/company_imports/code/datums/cargo_pack.dm
@@ -10,7 +10,8 @@
return
var/obj/structure/container = .
for(var/obj/item/gun/gun_actually in container.contents)
- if(gun_actually.company_flag & COMPANY_SCARBOROUGH) //illegal company doesn't care about pins
+ var/datum/component/manufacturer_examine/gun_company_examine_component = gun_actually.GetComponent(/datum/component/manufacturer_examine)
+ if((gun_company_examine_component) && (gun_company_examine_component.company_flag & COMPANY_SCARBOROUGH))
continue
QDEL_NULL(gun_actually.pin)
var/obj/item/firing_pin/permit_pin/new_pin = new(gun_actually)
diff --git a/modular_skyrat/modules/company_imports/code/gun_companies.dm b/modular_skyrat/modules/company_imports/code/gun_companies.dm
deleted file mode 100644
index db459f69641..00000000000
--- a/modular_skyrat/modules/company_imports/code/gun_companies.dm
+++ /dev/null
@@ -1,132 +0,0 @@
-/obj/item/gun/ballistic/automatic/pistol/m1911
- company_flag = COMPANY_BOLT
-
-/obj/item/gun/ballistic/automatic/pistol/aps
- company_flag = COMPANY_SCARBOROUGH
-
-/obj/item/gun/ballistic/revolver
- company_flag = COMPANY_SCARBOROUGH
-
-/obj/item/gun/ballistic/revolver/nagant
- company_flag = COMPANY_OLDARMS
-
-/obj/item/gun/ballistic/rifle/boltaction
- company_flag = COMPANY_IZHEVSK
-
-/obj/item/gun/ballistic/shotgun/riot
- company_flag = COMPANY_NANOTRASEN
-
-/obj/item/gun/ballistic/shotgun/bulldog
- company_flag = COMPANY_SCARBOROUGH
-
-/obj/item/gun/energy/e_gun
- company_flag = COMPANY_ALLSTAR
-
-/obj/item/gun/energy/laser
- company_flag = COMPANY_ALLSTAR
-
-/obj/item/gun/energy/pulse
- company_flag = COMPANY_NANOTRASEN
-
-/obj/item/gun/ballistic/shotgun/automatic/combat
- company_flag = COMPANY_NANOTRASEN
-
-/obj/item/gun/syringe
- company_flag = COMPANY_INTERDYNE
-
-/obj/item/gun/ballistic/automatic/pistol
- company_flag = COMPANY_SCARBOROUGH
-
-/obj/item/gun/ballistic/revolver/c38/detective
- company_flag = COMPANY_NANOTRASEN
-
-/obj/item/gun/ballistic/shotgun/doublebarrel
- company_flag = COMPANY_IZHEVSK
-
-/obj/item/gun/ballistic/shotgun/automatic/dual_tube
- company_flag = COMPANY_NANOTRASEN
-
-/obj/item/gun/ballistic/rifle/boltaction/brand_new
- company_flag = COMPANY_IZHEVSK
-
-/obj/item/gun/ballistic/shotgun/toy
- company_flag = COMPANY_DONK
-
-/obj/item/gun/ballistic/rifle/boltaction/brand_new/prime
- company_flag = null
-
-/obj/item/gun/ballistic/rifle/boltaction/pipegun
- company_flag = null
-
-/obj/item/gun/ballistic/automatic/c20r/toy
- company_flag = COMPANY_DONK
-
-/obj/item/gun/ballistic/automatic/pistol/clandestine
- company_flag = COMPANY_SCARBOROUGH
-
-/obj/item/gun/ballistic/automatic/pistol/pdh/pulse
- company_flag = null
-
-/obj/item/gun/ballistic/automatic/l6_saw/toy
- company_flag = COMPANY_DONK
-
-/obj/item/gun/ballistic/automatic/cmg
- company_flag = COMPANY_NANOTRASEN
-
-/obj/item/gun/ballistic/revolver/mateba
- company_flag = null
-
-/obj/item/gun/ballistic/revolver/russian
- company_flag = null
-
-/obj/item/gun/energy/laser/redtag
- company_flag = null
-
-/obj/item/gun/energy/laser/bluetag
- company_flag = null
-
-/obj/item/gun/energy/laser/instakill
- company_flag = null
-
-/obj/item/gun/energy/laser/chameleon
- company_flag = null
-
-/obj/item/gun/energy/laser/captain
- company_flag = COMPANY_NANOTRASEN
-
-/obj/item/gun/energy/laser/retro
- company_flag = COMPANY_REMOVED
-
-/obj/item/gun/energy/laser/retro/old
- company_flag = COMPANY_NANOTRASEN
-
-/obj/item/gun/energy/e_gun/old
- company_flag = COMPANY_NANOTRASEN
-
-/obj/item/gun/energy/e_gun/advtaser/cyborg
- company_flag = null
-
-/obj/item/gun/energy/recharge/ebow
- company_flag = COMPANY_SCARBOROUGH
-
-/obj/item/gun/energy/lasercannon
- company_flag = COMPANY_ALLSTAR
-
-/obj/item/gun/energy/ionrifle
- company_flag = COMPANY_ALLSTAR
-
-/obj/item/gun/energy/temperature
- company_flag = COMPANY_ALLSTAR
-
-/obj/item/gun/syringe/blowgun
- company_flag = null
-
-/obj/item/gun/syringe/syndicate/prototype
- company_flag = null
-
-/obj/item/gun/energy/shrink_ray
- company_flag = COMPANY_ABDUCTOR
-
-/obj/item/gun/energy/alien
- company_flag = COMPANY_ABDUCTOR
-
diff --git a/modular_skyrat/modules/company_imports/code/objects/nri_surplus/ak25.dm b/modular_skyrat/modules/company_imports/code/objects/nri_surplus/ak25.dm
index 66b6611b8fd..a5b6193de1e 100644
--- a/modular_skyrat/modules/company_imports/code/objects/nri_surplus/ak25.dm
+++ b/modular_skyrat/modules/company_imports/code/objects/nri_surplus/ak25.dm
@@ -21,10 +21,12 @@
load_empty_sound = 'modular_skyrat/modules/gunsgalore/sound/guns/interact/ltrifle_magin.ogg'
eject_sound = 'modular_skyrat/modules/gunsgalore/sound/guns/interact/ltrifle_magout.ogg'
alt_icons = TRUE
- company_flag = COMPANY_IZHEVSK
spread = 29
recoil = 0.1
+/obj/item/gun/ballistic/automatic/ak25/give_manufacturer_examine()
+ AddComponent(/datum/component/manufacturer_examine, COMPANY_IZHEVSK)
+
/obj/item/ammo_box/magazine/ak25
name = "\improper AK-25 magazine"
desc = "A banana-shaped double-stack magazine able to hold 30 rounds of 7.32x29mm ammunition."
diff --git a/modular_skyrat/modules/customization/modules/clothing/suits/misc.dm b/modular_skyrat/modules/customization/modules/clothing/suits/misc.dm
index 5237c5f74a3..f846e6c33f2 100644
--- a/modular_skyrat/modules/customization/modules/clothing/suits/misc.dm
+++ b/modular_skyrat/modules/customization/modules/clothing/suits/misc.dm
@@ -330,6 +330,26 @@
greyscale_colors = "#594032"
flags_1 = IS_PLAYER_COLORABLE_1
+/obj/item/clothing/suit/apron/overalls/greyscale/Initialize(mapload)
+ . = ..()
+ allowed += list(
+ /obj/item/flashlight,
+ /obj/item/lighter,
+ /obj/item/modular_computer/pda,
+ /obj/item/radio,
+ /obj/item/storage/bag/books,
+ /obj/item/storage/fancy/cigarettes,
+ /obj/item/tank/internals/emergency_oxygen,
+ /obj/item/tank/internals/plasmaman,
+ /obj/item/toy,
+ /obj/item/analyzer,
+ /obj/item/construction/rcd,
+ /obj/item/fireaxe/metal_h2_axe,
+ /obj/item/pipe_dispenser,
+ /obj/item/storage/bag/construction,
+ /obj/item/t_scanner,
+ )
+
/obj/item/clothing/suit/apron/overalls/greyscale/examine(mob/user)
. = ..()
diff --git a/modular_skyrat/modules/customization/modules/food_and_drinks/recipes/drinks_recipes.dm b/modular_skyrat/modules/customization/modules/food_and_drinks/recipes/drinks_recipes.dm
index 003d645b66b..10ad32e59a6 100644
--- a/modular_skyrat/modules/customization/modules/food_and_drinks/recipes/drinks_recipes.dm
+++ b/modular_skyrat/modules/customization/modules/food_and_drinks/recipes/drinks_recipes.dm
@@ -129,7 +129,7 @@
/datum/chemical_reaction/drink/research_rum
results = list(/datum/reagent/consumable/ethanol/research_rum = 4)
- required_reagents = list(/datum/reagent/consumable/ethanol/bananahonk = 2, /datum/reagent/impurity/mannitol = 1, /datum/reagent/consumable/ethanol/grog = 1)
+ required_reagents = list(/datum/reagent/consumable/ethanol/bananahonk = 2, /datum/reagent/inverse/neurine = 1, /datum/reagent/consumable/ethanol/grog = 1)
mix_message = "You hear gurgling and dinging as it mixes."
mix_sound = 'sound/machines/microwave/microwave-end.ogg'
diff --git a/modular_skyrat/modules/gun_safety/code/safety_additions.dm b/modular_skyrat/modules/gun_safety/code/safety_additions.dm
new file mode 100644
index 00000000000..013fc022ec2
--- /dev/null
+++ b/modular_skyrat/modules/gun_safety/code/safety_additions.dm
@@ -0,0 +1,48 @@
+/// Proc that is overridden in /gun/ballistic and /gun/energy to attach the gun safety component to a gun
+/obj/item/gun/proc/give_gun_safeties()
+ return
+
+// Ballistic Weapons
+
+/obj/item/gun/ballistic/give_gun_safeties()
+ AddComponent(/datum/component/gun_safety)
+
+/obj/item/gun/ballistic/bow/give_gun_safeties()
+ return
+
+/obj/item/gun/ballistic/rifle/enchanted/give_gun_safeties()
+ return
+
+/obj/item/gun/ballistic/automatic/laser/ctf/give_gun_safeties()
+ return
+
+/obj/item/gun/ballistic/shotgun/ctf/give_gun_safeties()
+ return
+
+/obj/item/gun/ballistic/automatic/laser/ctf/marksman/give_gun_safeties()
+ return
+
+/obj/item/gun/ballistic/automatic/pistol/deagle/ctf/give_gun_safeties()
+ return
+
+/obj/item/gun/ballistic/automatic/pistol/g17/mesa/give_gun_safeties()
+ return
+
+/obj/item/gun/ballistic/revolver/grenadelauncher/give_gun_safeties()
+ return
+
+// Energy Weapons
+
+/obj/item/gun/energy/give_gun_safeties()
+ AddComponent(/datum/component/gun_safety)
+
+/obj/item/gun/energy/plasmacutter/give_gun_safeties()
+ return
+
+/obj/item/gun/energy/kinetic_accelerator/give_gun_safeties()
+ return
+
+// Syringe Guns
+
+/obj/item/gun/syringe/blowgun/give_gun_safeties()
+ return
diff --git a/modular_skyrat/modules/gun_safety/code/safety_component.dm b/modular_skyrat/modules/gun_safety/code/safety_component.dm
new file mode 100644
index 00000000000..3338b5347ae
--- /dev/null
+++ b/modular_skyrat/modules/gun_safety/code/safety_component.dm
@@ -0,0 +1,86 @@
+/// Component that will prevent a gun from firing if the safety is turned on
+/datum/component/gun_safety
+ /// Is the safety actually on?
+ var/safety_currently_on = TRUE
+ /// Holder for the toggle safety action
+ var/datum/action/item_action/gun_safety_toggle/toggle_safety_action
+
+/datum/component/gun_safety/Initialize(safety_currently_on = TRUE)
+ . = ..()
+
+ // Obviously gun safety should only apply to guns
+ if(!isgun(parent))
+ return COMPONENT_INCOMPATIBLE
+
+ src.safety_currently_on = safety_currently_on
+
+ var/obj/item/item_parent = parent
+ toggle_safety_action = item_parent.add_item_action(/datum/action/item_action/gun_safety_toggle)
+
+ update_action_button_state()
+
+/datum/component/gun_safety/Destroy()
+ if(toggle_safety_action)
+ QDEL_NULL(toggle_safety_action)
+ return ..()
+
+/datum/component/gun_safety/RegisterWithParent()
+ RegisterSignal(parent, COMSIG_GUN_TRY_FIRE, PROC_REF(check_if_we_can_actually_shooty))
+ RegisterSignal(parent, COMSIG_ITEM_UI_ACTION_CLICK, PROC_REF(we_may_be_toggling_safeties))
+ RegisterSignal(parent, COMSIG_PARENT_EXAMINE, PROC_REF(on_examine))
+
+/datum/component/gun_safety/UnregisterFromParent()
+ UnregisterSignal(parent, list(
+ COMSIG_GUN_TRY_FIRE,
+ COMSIG_ITEM_UI_ACTION_CLICK,
+ COMSIG_PARENT_EXAMINE,
+ ))
+
+/// Checks if the safety is currently on, if it is then stops the gun from firing
+/datum/component/gun_safety/proc/check_if_we_can_actually_shooty(obj/item/gun/source, mob/living/user, atom/target, flag, params)
+ SIGNAL_HANDLER
+
+ if(safety_currently_on)
+ user.balloon_alert(user, "safety on!")
+ return COMPONENT_CANCEL_GUN_FIRE
+
+/// Calls toggle_safeties if the action type for doing so is used
+/datum/component/gun_safety/proc/we_may_be_toggling_safeties(source, user, datum/actiontype)
+ SIGNAL_HANDLER
+
+ if(istype(actiontype, toggle_safety_action))
+ toggle_safeties(user)
+
+ return COMPONENT_ACTION_HANDLED
+
+/// Toggles the safeties on or off
+/datum/component/gun_safety/proc/toggle_safeties(mob/user)
+ safety_currently_on = !safety_currently_on
+
+ update_action_button_state()
+
+ playsound(parent, 'sound/weapons/empty.ogg', 100, TRUE)
+ user.visible_message(
+ span_notice("[user] toggles [parent]'s safety [safety_currently_on ? "ON" : "OFF"]."),
+ span_notice("You toggle [parent]'s safety [safety_currently_on ? "ON" : "OFF"].")
+ )
+
+/// Adds the gun safety's current status to the gun's examine
+/datum/component/gun_safety/proc/on_examine(obj/item/source, mob/examiner, list/examine_list)
+ SIGNAL_HANDLER
+
+ examine_list += "The safety is [safety_currently_on ? "ON" : "OFF"]."
+
+/// Small proc to update the actio button's icon, just so I can not have to copypaste the same thing several times.
+/datum/component/gun_safety/proc/update_action_button_state()
+ if(!toggle_safety_action)
+ return
+
+ toggle_safety_action.button_icon_state = "safety_[safety_currently_on ? "on" : "off"]"
+ toggle_safety_action.build_all_button_icons()
+
+// The actual action, used by the component
+/datum/action/item_action/gun_safety_toggle
+ name = "Toggle Gun Safety"
+ button_icon = 'modular_skyrat/modules/gun_safety/icons/actions.dmi'
+ button_icon_state = "safety_on"
diff --git a/modular_skyrat/modules/gunsafety/icons/actions.dmi b/modular_skyrat/modules/gun_safety/icons/actions.dmi
similarity index 100%
rename from modular_skyrat/modules/gunsafety/icons/actions.dmi
rename to modular_skyrat/modules/gun_safety/icons/actions.dmi
diff --git a/modular_skyrat/modules/gunsafety/readme.md b/modular_skyrat/modules/gun_safety/readme.md
similarity index 87%
rename from modular_skyrat/modules/gunsafety/readme.md
rename to modular_skyrat/modules/gun_safety/readme.md
index d929b682bac..dc0634151ea 100644
--- a/modular_skyrat/modules/gunsafety/readme.md
+++ b/modular_skyrat/modules/gun_safety/readme.md
@@ -24,3 +24,4 @@ Adds a huge QOL feature, GUN SAFTIES.
### Credits:
Gandalf2k15 - OG code
+Paxilmaniac - Turned it into a component
diff --git a/modular_skyrat/modules/gunhud/code/gun_hud_component.dm b/modular_skyrat/modules/gunhud/code/gun_hud_component.dm
index dda48fe37a1..f32981b01e4 100644
--- a/modular_skyrat/modules/gunhud/code/gun_hud_component.dm
+++ b/modular_skyrat/modules/gunhud/code/gun_hud_component.dm
@@ -62,17 +62,6 @@
var/oth_t
var/oth_h
- switch(pew.fire_select)
- if(SELECT_SEMI_AUTOMATIC)
- indicator = "semi"
- if(SELECT_BURST_SHOT)
- indicator = "burst"
- if(SELECT_FULLY_AUTOMATIC)
- indicator = "auto"
-
- if(pew.safety)
- indicator = "safe"
-
switch(length(rounds))
if(1)
oth_o = "o[rounds[1]]"
diff --git a/modular_skyrat/modules/gunsafety/code/gun_safety.dm b/modular_skyrat/modules/gunsafety/code/gun_safety.dm
deleted file mode 100644
index d4012fc32b7..00000000000
--- a/modular_skyrat/modules/gunsafety/code/gun_safety.dm
+++ /dev/null
@@ -1,32 +0,0 @@
-/obj/item/gun/ballistic
- has_gun_safety = TRUE
-
-/obj/item/gun/ballistic/bow
- has_gun_safety = FALSE
-
-/obj/item/gun/energy
- has_gun_safety = TRUE
-
-/obj/item/gun/energy/plasmacutter
- has_gun_safety = FALSE
-
-/obj/item/gun/energy/kinetic_accelerator
- has_gun_safety = FALSE
-
-/obj/item/gun/ballistic/rifle/enchanted
- has_gun_safety = FALSE
-
-/obj/item/gun/ballistic/automatic/laser/ctf
- has_gun_safety = FALSE
-
-/obj/item/gun/ballistic/shotgun/ctf
- has_gun_safety = FALSE
-
-/obj/item/gun/ballistic/automatic/laser/ctf/marksman
- has_gun_safety = FALSE
-
-/obj/item/gun/ballistic/automatic/pistol/deagle/ctf
- has_gun_safety = FALSE
-
-/obj/item/gun/ballistic/automatic/pistol/g17/mesa
- has_gun_safety = FALSE
diff --git a/modular_skyrat/modules/gunsgalore/code/guns/akm.dm b/modular_skyrat/modules/gunsgalore/code/guns/akm.dm
index 3b19a126530..10f2c5eb905 100644
--- a/modular_skyrat/modules/gunsgalore/code/guns/akm.dm
+++ b/modular_skyrat/modules/gunsgalore/code/guns/akm.dm
@@ -21,7 +21,14 @@
load_empty_sound = 'modular_skyrat/modules/gunsgalore/sound/guns/interact/ltrifle_magin.ogg'
eject_sound = 'modular_skyrat/modules/gunsgalore/sound/guns/interact/ltrifle_magout.ogg'
alt_icons = TRUE
- company_flag = COMPANY_IZHEVSK
+
+/obj/item/gun/ballistic/automatic/akm/Initialize(mapload)
+ . = ..()
+
+ AddComponent(/datum/component/automatic_fire, fire_delay)
+
+/obj/item/gun/ballistic/automatic/akm/give_manufacturer_examine()
+ AddComponent(/datum/component/manufacturer_examine, COMPANY_IZHEVSK)
/obj/item/ammo_box/magazine/akm
name = "\improper Krinkov magazine"
@@ -88,7 +95,6 @@
desc = "A timeless human design of a carbine chambered in the NRI's 5.6mm ammo. The internal modifications made to the firearm in order to accommodate for non-military use made it incompatible with conventional munitions and gave it the inability to fire fully automatic. It's purpose-built to fire low-grade civilian ammo, anything stronger would obliterate the rifling and render the firearm useless."
icon_state = "akm_civ"
inhand_icon_state = "akm_civ"
- fire_select_modes = list(SELECT_SEMI_AUTOMATIC)
mag_type = /obj/item/ammo_box/magazine/akm/civvie
fire_delay = 5
dual_wield_spread = 15
diff --git a/modular_skyrat/modules/gunsgalore/code/guns/fg42.dm b/modular_skyrat/modules/gunsgalore/code/guns/fg42.dm
index 67e9566fc04..c5066404f96 100644
--- a/modular_skyrat/modules/gunsgalore/code/guns/fg42.dm
+++ b/modular_skyrat/modules/gunsgalore/code/guns/fg42.dm
@@ -23,12 +23,17 @@
load_empty_sound = 'modular_skyrat/modules/gunsgalore/sound/guns/interact/batrifle_magin.ogg'
eject_sound = 'modular_skyrat/modules/gunsgalore/sound/guns/interact/batrifle_magout.ogg'
eject_empty_sound = 'modular_skyrat/modules/gunsgalore/sound/guns/interact/batrifle_magout.ogg'
- company_flag = COMPANY_OLDARMS
/obj/item/gun/ballistic/automatic/fg42/Initialize(mapload)
. = ..()
+
AddComponent(/datum/component/scope, range_modifier = 1)
+ AddComponent(/datum/component/automatic_fire, fire_delay)
+
+/obj/item/gun/ballistic/automatic/fg42/give_manufacturer_examine()
+ AddComponent(/datum/component/manufacturer_examine, COMPANY_OLDARMS)
+
/obj/item/ammo_box/magazine/fg42
name = "fg42 magazine (7.92x57mm)"
icon = 'modular_skyrat/modules/gunsgalore/icons/guns/gunsgalore_items.dmi'
diff --git a/modular_skyrat/modules/gunsgalore/code/guns/luger.dm b/modular_skyrat/modules/gunsgalore/code/guns/luger.dm
index 8f50e0191cd..cb0deda1c27 100644
--- a/modular_skyrat/modules/gunsgalore/code/guns/luger.dm
+++ b/modular_skyrat/modules/gunsgalore/code/guns/luger.dm
@@ -14,4 +14,6 @@
rack_sound = 'modular_skyrat/modules/gunsgalore/sound/guns/fire/luger_rack.ogg'
fire_sound_volume = 100
suppressor_x_offset = 14
- company_flag = COMPANY_OLDARMS
+
+/obj/item/gun/ballistic/automatic/pistol/luger/give_manufacturer_examine()
+ AddComponent(/datum/component/manufacturer_examine, COMPANY_OLDARMS)
diff --git a/modular_skyrat/modules/gunsgalore/code/guns/m16.dm b/modular_skyrat/modules/gunsgalore/code/guns/m16.dm
index 431056f1916..75e4a5fa144 100644
--- a/modular_skyrat/modules/gunsgalore/code/guns/m16.dm
+++ b/modular_skyrat/modules/gunsgalore/code/guns/m16.dm
@@ -53,6 +53,11 @@
burst_size = 3
fire_delay = 1.90
+/obj/item/gun/ballistic/automatic/m16/modern/Initialize(mapload)
+ . = ..()
+
+ AddComponent(/datum/component/automatic_fire, fire_delay)
+
/obj/item/gun/ballistic/automatic/m16/modern/v2
name = "\improper XM-2537 'Amans Patriae' rifle"
desc = "An expertly modified, super-compact XM-2537 rifle designed for operating in tight corridors and fields full of Bethlehem flowers. You're a soldier, finish your mission!"
diff --git a/modular_skyrat/modules/gunsgalore/code/guns/mg34.dm b/modular_skyrat/modules/gunsgalore/code/guns/mg34.dm
index 6cbe0195c50..645ebb894fb 100644
--- a/modular_skyrat/modules/gunsgalore/code/guns/mg34.dm
+++ b/modular_skyrat/modules/gunsgalore/code/guns/mg34.dm
@@ -13,7 +13,6 @@
rack_sound = 'sound/weapons/gun/l6/l6_rack.ogg'
suppressed_sound = 'sound/weapons/gun/general/heavy_shot_suppressed.ogg'
fire_sound_volume = 70
- fire_select_modes = list(SELECT_SEMI_AUTOMATIC, SELECT_FULLY_AUTOMATIC)
weapon_weight = WEAPON_HEAVY
slot_flags = ITEM_SLOT_BACK
w_class = WEIGHT_CLASS_HUGE
@@ -24,13 +23,18 @@
bolt_type = BOLT_TYPE_OPEN
show_bolt_icon = FALSE
tac_reloads = FALSE
- company_flag = COMPANY_OLDARMS
var/cover_open = FALSE
/obj/item/gun/ballistic/automatic/mg34/Initialize(mapload)
. = ..()
+
+ AddComponent(/datum/component/automatic_fire, fire_delay)
+
AddElement(/datum/element/update_icon_updates_onmob)
+/obj/item/gun/ballistic/automatic/mg34/give_manufacturer_examine()
+ AddComponent(/datum/component/manufacturer_examine, COMPANY_OLDARMS)
+
/obj/item/gun/ballistic/automatic/mg34/examine(mob/user)
. = ..()
. += "RMB with an empty hand to [cover_open ? "close" : "open"] the dust cover."
diff --git a/modular_skyrat/modules/gunsgalore/code/guns/mp40.dm b/modular_skyrat/modules/gunsgalore/code/guns/mp40.dm
index 21904008a9f..46ab724c3b8 100644
--- a/modular_skyrat/modules/gunsgalore/code/guns/mp40.dm
+++ b/modular_skyrat/modules/gunsgalore/code/guns/mp40.dm
@@ -20,8 +20,14 @@
load_empty_sound = 'modular_skyrat/modules/gunsgalore/sound/guns/interact/smg_magin.ogg'
eject_sound = 'modular_skyrat/modules/gunsgalore/sound/guns/interact/smg_magout.ogg'
alt_icons = TRUE
- fire_select_modes = list(SELECT_SEMI_AUTOMATIC, SELECT_FULLY_AUTOMATIC)
- company_flag = COMPANY_OLDARMS
+
+/obj/item/gun/ballistic/automatic/mp40/Initialize(mapload)
+ . = ..()
+
+ AddComponent(/datum/component/automatic_fire, fire_delay)
+
+/obj/item/gun/ballistic/automatic/mp40/give_manufacturer_examine()
+ AddComponent(/datum/component/manufacturer_examine, COMPANY_OLDARMS)
/obj/item/ammo_box/magazine/mp40
name = "mp40 magazine (9mmx19)"
diff --git a/modular_skyrat/modules/gunsgalore/code/guns/p90.dm b/modular_skyrat/modules/gunsgalore/code/guns/p90.dm
index 405aacc8cbc..5d8b81ae2dd 100644
--- a/modular_skyrat/modules/gunsgalore/code/guns/p90.dm
+++ b/modular_skyrat/modules/gunsgalore/code/guns/p90.dm
@@ -11,7 +11,6 @@
slot_flags = ITEM_SLOT_BELT | ITEM_SLOT_BACK
mag_type = /obj/item/ammo_box/magazine/p90
can_suppress = FALSE
- burst_size = 5
fire_delay = 1
fire_sound = 'modular_skyrat/modules/gunsgalore/sound/guns/fire/p90_fire.ogg'
fire_sound_volume = 100
@@ -21,6 +20,11 @@
eject_sound = 'modular_skyrat/modules/gunsgalore/sound/guns/interact/p90_magout.ogg'
alt_icons = TRUE
+/obj/item/gun/ballistic/automatic/p90/Initialize(mapload)
+ . = ..()
+
+ AddComponent(/datum/component/automatic_fire, fire_delay)
+
/obj/item/ammo_box/magazine/p90
name = "\improper P90-02 magazine"
icon = 'modular_skyrat/modules/gunsgalore/icons/guns/gunsgalore_items.dmi'
diff --git a/modular_skyrat/modules/gunsgalore/code/guns/pps.dm b/modular_skyrat/modules/gunsgalore/code/guns/pps.dm
index d3d383a34c5..6e2646ebaa2 100644
--- a/modular_skyrat/modules/gunsgalore/code/guns/pps.dm
+++ b/modular_skyrat/modules/gunsgalore/code/guns/pps.dm
@@ -9,7 +9,6 @@
slot_flags = ITEM_SLOT_BELT | ITEM_SLOT_BACK
mag_type = /obj/item/ammo_box/magazine/pps
can_suppress = FALSE
- burst_size = 3
fire_delay = 3
worn_icon = 'modular_skyrat/modules/gunsgalore/icons/guns/gunsgalore_back.dmi'
worn_icon_state = "pps"
@@ -20,7 +19,14 @@
load_sound = 'modular_skyrat/modules/gunsgalore/sound/guns/interact/smg_magin.ogg'
load_empty_sound = 'modular_skyrat/modules/gunsgalore/sound/guns/interact/smg_magin.ogg'
eject_sound = 'modular_skyrat/modules/gunsgalore/sound/guns/interact/smg_magout.ogg'
- company_flag = COMPANY_OLDARMS
+
+/obj/item/gun/ballistic/automatic/pps/Initialize(mapload)
+ . = ..()
+
+ AddComponent(/datum/component/automatic_fire, fire_delay)
+
+/obj/item/gun/ballistic/automatic/pps/give_manufacturer_examine()
+ AddComponent(/datum/component/manufacturer_examine, COMPANY_OLDARMS)
/obj/item/ammo_box/magazine/pps
name = "pps magazine (7.62x25mm)"
diff --git a/modular_skyrat/modules/gunsgalore/code/guns/ppsh.dm b/modular_skyrat/modules/gunsgalore/code/guns/ppsh.dm
index 6cf7b6eb9bf..227e3784642 100644
--- a/modular_skyrat/modules/gunsgalore/code/guns/ppsh.dm
+++ b/modular_skyrat/modules/gunsgalore/code/guns/ppsh.dm
@@ -13,7 +13,6 @@
mag_type = /obj/item/ammo_box/magazine/ppsh
can_suppress = FALSE
spread = 20
- burst_size = 6
fire_delay = 0.5
fire_sound = 'modular_skyrat/modules/gunsgalore/sound/guns/fire/ppsh_fire.ogg'
fire_sound_volume = 80
@@ -22,7 +21,14 @@
load_sound = 'modular_skyrat/modules/gunsgalore/sound/guns/interact/smg_magin.ogg'
load_empty_sound = 'modular_skyrat/modules/gunsgalore/sound/guns/interact/smg_magin.ogg'
eject_sound = 'modular_skyrat/modules/gunsgalore/sound/guns/interact/smg_magout.ogg'
- company_flag = COMPANY_OLDARMS
+
+/obj/item/gun/ballistic/automatic/ppsh/Initialize(mapload)
+ . = ..()
+
+ AddComponent(/datum/component/automatic_fire, fire_delay)
+
+/obj/item/gun/ballistic/automatic/ppsh/give_manufacturer_examine()
+ AddComponent(/datum/component/manufacturer_examine, COMPANY_OLDARMS)
/obj/item/ammo_box/magazine/ppsh
name = "Asha 76 magazine (7.62x25mm)"
diff --git a/modular_skyrat/modules/gunsgalore/code/guns/scar.dm b/modular_skyrat/modules/gunsgalore/code/guns/scar.dm
index 17d268ac995..62f6bbf6888 100644
--- a/modular_skyrat/modules/gunsgalore/code/guns/scar.dm
+++ b/modular_skyrat/modules/gunsgalore/code/guns/scar.dm
@@ -13,7 +13,6 @@
weapon_weight = WEAPON_HEAVY
mag_type = /obj/item/ammo_box/magazine/m16
can_suppress = FALSE
- burst_size = 3
fire_delay = 1.90
fire_sound = 'modular_skyrat/modules/gunsgalore/sound/guns/fire/scar_fire.ogg'
fire_sound_volume = 50
@@ -22,3 +21,8 @@
load_empty_sound = 'modular_skyrat/modules/gunsgalore/sound/guns/interact/scar_mag_in.ogg'
eject_sound = 'modular_skyrat/modules/gunsgalore/sound/guns/interact/scar_mag_out.ogg'
alt_icons = TRUE
+
+/obj/item/gun/ballistic/automatic/scar/Initialize(mapload)
+ . = ..()
+
+ AddComponent(/datum/component/automatic_fire, fire_delay)
diff --git a/modular_skyrat/modules/gunsgalore/code/guns/stg.dm b/modular_skyrat/modules/gunsgalore/code/guns/stg.dm
index 49b9f6fe1aa..1ab3bf30c32 100644
--- a/modular_skyrat/modules/gunsgalore/code/guns/stg.dm
+++ b/modular_skyrat/modules/gunsgalore/code/guns/stg.dm
@@ -19,12 +19,18 @@
fire_sound = 'modular_skyrat/modules/gunsgalore/sound/guns/fire/stg_fire.ogg'
fire_sound_volume = 70
alt_icons = TRUE
- fire_select_modes = list(SELECT_SEMI_AUTOMATIC, SELECT_FULLY_AUTOMATIC)
rack_sound = 'modular_skyrat/modules/gunsgalore/sound/guns/interact/ltrifle_cock.ogg'
load_sound = 'modular_skyrat/modules/gunsgalore/sound/guns/interact/ltrifle_magin.ogg'
load_empty_sound = 'modular_skyrat/modules/gunsgalore/sound/guns/interact/ltrifle_magin.ogg'
eject_sound = 'modular_skyrat/modules/gunsgalore/sound/guns/interact/ltrifle_magout.ogg'
- company_flag = COMPANY_OLDARMS
+
+/obj/item/gun/ballistic/automatic/stg/Initialize(mapload)
+ . = ..()
+
+ AddComponent(/datum/component/automatic_fire, fire_delay)
+
+/obj/item/gun/ballistic/automatic/stg/give_manufacturer_examine()
+ AddComponent(/datum/component/manufacturer_examine, COMPANY_OLDARMS)
/obj/item/ammo_box/magazine/stg
name = "stg magazine (7.92x33mm)"
diff --git a/modular_skyrat/modules/loadouts/loadout_items/under/loadout_datum_under.dm b/modular_skyrat/modules/loadouts/loadout_items/under/loadout_datum_under.dm
index eb5e1c564c1..b6a1a8b7fb9 100644
--- a/modular_skyrat/modules/loadouts/loadout_items/under/loadout_datum_under.dm
+++ b/modular_skyrat/modules/loadouts/loadout_items/under/loadout_datum_under.dm
@@ -115,14 +115,9 @@ GLOBAL_LIST_INIT(loadout_miscunders, generate_loadout_items(/datum/loadout_item/
item_path = /obj/item/clothing/under/rank/security/warden/peacekeeper/sol
restricted_roles = list(JOB_WARDEN)
-/datum/loadout_item/under/jumpsuit/peacetrouse
- name = "Peacekeeper Trousers"
- item_path = /obj/item/clothing/under/rank/security/peacekeeper/trousers
- restricted_roles = list(JOB_SECURITY_OFFICER, JOB_WARDEN, JOB_HEAD_OF_SECURITY, JOB_SECURITY_MEDIC)
-
/datum/loadout_item/under/jumpsuit/security_trousers
name = "Security Trousers"
- item_path = /obj/item/clothing/under/rank/security/peacekeeper/trousers/red
+ item_path = /obj/item/clothing/under/rank/security/peacekeeper/trousers
restricted_roles = list(JOB_SECURITY_OFFICER, JOB_WARDEN, JOB_HEAD_OF_SECURITY, JOB_SECURITY_MEDIC)
/datum/loadout_item/under/jumpsuit/solofficer
diff --git a/modular_skyrat/modules/manufacturer_examine/readme.md b/modular_skyrat/modules/manufacturer_examine/readme.md
new file mode 100644
index 00000000000..4e27e204550
--- /dev/null
+++ b/modular_skyrat/modules/manufacturer_examine/readme.md
@@ -0,0 +1,25 @@
+## Title: Manufacturer Examine
+
+### Description:
+
+Tells you what company made what item this component is attached to, originally for guns
+
+### TG Proc Changes:
+
+- N/A
+
+### Defines:
+
+- N/A
+
+### Master file additions
+
+- N/A
+
+### Included files that are not contained in this module:
+
+- N/A
+
+### Credits:
+Zonespace - Did the whole manufacturer thing originally I think
+Paxilmaniac - Turned it into a component
diff --git a/modular_skyrat/modules/marines/code/gear.dm b/modular_skyrat/modules/marines/code/gear.dm
index 9e95610f58b..41b7e92f27f 100644
--- a/modular_skyrat/modules/marines/code/gear.dm
+++ b/modular_skyrat/modules/marines/code/gear.dm
@@ -18,7 +18,14 @@
mag_type = /obj/item/ammo_box/magazine/m44a
w_class = WEIGHT_CLASS_BULKY
slot_flags = ITEM_SLOT_BELT
- company_flag = COMPANY_NANOTRASEN
+
+/obj/item/gun/ballistic/automatic/ar/modular/m44a/Initialize(mapload)
+ . = ..()
+
+ AddComponent(/datum/component/automatic_fire, fire_delay)
+
+/obj/item/gun/ballistic/automatic/ar/modular/m44a/give_manufacturer_examine()
+ AddComponent(/datum/component/manufacturer_examine, COMPANY_NANOTRASEN)
/obj/item/ammo_box/magazine/m44a
name = "m44a magazine (.300 compressed)"
@@ -57,9 +64,11 @@
name = "\improper M2 auto-shotgun underbarrel"
desc = "This shouldn't be heeere!"
can_suppress = FALSE
- has_gun_safety = FALSE
mag_type = /obj/item/ammo_box/magazine/internal/shot/as2/ubsg
+/obj/item/gun/ballistic/shotgun/automatic/as2/ubsg/give_gun_safeties()
+ return
+
/obj/item/ammo_box/magazine/internal/shot/as2/ubsg
max_ammo = 3
ammo_type = /obj/item/ammo_casing/shotgun/buckshot
diff --git a/modular_skyrat/modules/marines/code/smartgun.dm b/modular_skyrat/modules/marines/code/smartgun.dm
index 3271a094043..f33a48f28bc 100644
--- a/modular_skyrat/modules/marines/code/smartgun.dm
+++ b/modular_skyrat/modules/marines/code/smartgun.dm
@@ -13,7 +13,6 @@
rack_sound = 'sound/weapons/gun/l6/l6_rack.ogg'
suppressed_sound = 'sound/weapons/gun/general/heavy_shot_suppressed.ogg'
fire_sound_volume = 70
- fire_select_modes = list(SELECT_SEMI_AUTOMATIC, SELECT_FULLY_AUTOMATIC)
weapon_weight = WEAPON_HEAVY
slot_flags = ITEM_SLOT_BACK
w_class = WEIGHT_CLASS_HUGE
@@ -29,7 +28,6 @@
pin = /obj/item/firing_pin/implant/mindshield
mag_display_ammo = FALSE
mag_display = FALSE
- company_flag = COMPANY_NANOTRASEN
fire_sound_volume = 30
/// If the gun's dustcover is open or not
var/cover_open = FALSE
@@ -38,8 +36,14 @@
/obj/item/gun/ballistic/automatic/smart_machine_gun/Initialize(mapload)
. = ..()
+
+ AddComponent(/datum/component/automatic_fire, fire_delay)
+
AddElement(/datum/element/update_icon_updates_onmob)
+/obj/item/gun/ballistic/automatic/smart_machine_gun/give_manufacturer_examine()
+ AddComponent(/datum/component/manufacturer_examine, COMPANY_NANOTRASEN)
+
/obj/item/gun/ballistic/automatic/smart_machine_gun/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0)
. = ..()
if(chambered)
diff --git a/modular_skyrat/modules/medical/code/smartdarts.dm b/modular_skyrat/modules/medical/code/smartdarts.dm
index 558d9a84f2d..c36caa3f1eb 100644
--- a/modular_skyrat/modules/medical/code/smartdarts.dm
+++ b/modular_skyrat/modules/medical/code/smartdarts.dm
@@ -47,13 +47,15 @@
icon = 'modular_skyrat/modules/medical/icons/obj/dartguns.dmi'
icon_state = "smartdartgun"
worn_icon_state = "medicalsyringegun"
- has_gun_safety = TRUE
item_flags = null
/obj/item/gun/syringe/smartdart/Initialize(mapload)
. = ..()
chambered = new /obj/item/ammo_casing/syringegun/dart(src)
+/obj/item/gun/syringe/smartdart/give_gun_safeties()
+ return
+
/obj/item/gun/syringe/smartdart/attackby(obj/item/container, mob/user, params, show_msg = TRUE)
if(istype(container, /obj/item/reagent_containers/syringe/smartdart))
..()
diff --git a/modular_skyrat/modules/microfusion/code/gun_types.dm b/modular_skyrat/modules/microfusion/code/gun_types.dm
index c62d6338099..788ec1fb62b 100644
--- a/modular_skyrat/modules/microfusion/code/gun_types.dm
+++ b/modular_skyrat/modules/microfusion/code/gun_types.dm
@@ -4,7 +4,9 @@
icon_state = "mcr01"
inhand_icon_state = "mcr01"
shaded_charge = TRUE
- company_flag = COMPANY_MICRON
+
+/obj/item/gun/microfusion/mcr01/give_manufacturer_examine()
+ AddComponent(/datum/component/manufacturer_examine, COMPANY_MICRON)
/// Gun for cargo crates.
/obj/item/gun/microfusion/mcr01/advanced
diff --git a/modular_skyrat/modules/microfusion/code/microfusion_energy_master.dm b/modular_skyrat/modules/microfusion/code/microfusion_energy_master.dm
index bcffeb72a6b..d9fb1d07d30 100644
--- a/modular_skyrat/modules/microfusion/code/microfusion_energy_master.dm
+++ b/modular_skyrat/modules/microfusion/code/microfusion_energy_master.dm
@@ -9,10 +9,8 @@
icon = 'modular_skyrat/modules/microfusion/icons/microfusion_gun40x32.dmi'
icon_state = "mcr01"
inhand_icon_state = "mcr01"
- bayonet_icon = 'modular_skyrat/modules/microfusion/icons/microfusion_gun40x32.dmi'
lefthand_file = 'modular_skyrat/modules/microfusion/icons/guns_lefthand.dmi'
righthand_file = 'modular_skyrat/modules/microfusion/icons/guns_righthand.dmi'
- has_gun_safety = TRUE
can_bayonet = FALSE
weapon_weight = WEAPON_HEAVY
w_class = WEIGHT_CLASS_BULKY
@@ -109,6 +107,9 @@
RegisterSignal(src, COMSIG_ITEM_RECHARGED, PROC_REF(instant_recharge))
base_fire_delay = fire_delay
+/obj/item/gun/microfusion/give_gun_safeties()
+ AddComponent(/datum/component/gun_safety)
+
/obj/item/gun/microfusion/add_weapon_description()
AddElement(/datum/element/weapon_description, attached_proc = PROC_REF(add_notes_energy))
diff --git a/modular_skyrat/modules/modular_weapons/code/automatic.dm b/modular_skyrat/modules/modular_weapons/code/automatic.dm
index ce6534f08eb..1c3a5a1eae8 100644
--- a/modular_skyrat/modules/modular_weapons/code/automatic.dm
+++ b/modular_skyrat/modules/modular_weapons/code/automatic.dm
@@ -43,7 +43,6 @@
selector_switch_icon = TRUE
mag_type = /obj/item/ammo_box/magazine/multi_sprite/cfa_wildcat
can_suppress = FALSE
- burst_size = 3
fire_delay = 1.25
spread = 5
mag_display = TRUE
@@ -51,7 +50,14 @@
fire_sound = 'sound/weapons/gun/smg/shot_alt.ogg'
weapon_weight = WEAPON_MEDIUM
w_class = WEIGHT_CLASS_BULKY
- company_flag = COMPANY_CANTALAN
+
+/obj/item/gun/ballistic/automatic/cfa_wildcat/Initialize(mapload)
+ . = ..()
+
+ AddComponent(/datum/component/automatic_fire, fire_delay)
+
+/obj/item/gun/ballistic/automatic/cfa_wildcat/give_manufacturer_examine()
+ AddComponent(/datum/component/manufacturer_examine, COMPANY_CANTALAN)
/obj/item/gun/ballistic/automatic/cfa_wildcat/no_mag
spawnwithmagazine = FALSE
@@ -69,7 +75,6 @@
selector_switch_icon = FALSE
mag_type = /obj/item/ammo_box/magazine/multi_sprite/cfa_lynx
can_suppress = FALSE
- burst_size = 3
fire_delay = 1.90 //Previously 0.5. Changed due to it being the Blueshield's default firearm.
spread = 2
mag_display = TRUE
@@ -77,7 +82,14 @@
fire_sound = 'sound/weapons/gun/smg/shot_alt.ogg'
weapon_weight = WEAPON_MEDIUM
w_class = WEIGHT_CLASS_BULKY
- company_flag = COMPANY_CANTALAN
+
+/obj/item/gun/ballistic/automatic/cfa_lynx/Initialize(mapload)
+ . = ..()
+
+ AddComponent(/datum/component/automatic_fire, fire_delay)
+
+/obj/item/gun/ballistic/automatic/cfa_lynx/give_manufacturer_examine()
+ AddComponent(/datum/component/manufacturer_examine, COMPANY_CANTALAN)
/obj/item/gun/ballistic/automatic/cfa_lynx/no_mag
spawnwithmagazine = FALSE
diff --git a/modular_skyrat/modules/modular_weapons/code/energy.dm b/modular_skyrat/modules/modular_weapons/code/energy.dm
index 1d6264e95db..ed6abe76ba0 100644
--- a/modular_skyrat/modules/modular_weapons/code/energy.dm
+++ b/modular_skyrat/modules/modular_weapons/code/energy.dm
@@ -17,8 +17,12 @@
cell_type = /obj/item/stock_parts/cell/mini_egun
ammo_x_offset = 2
charge_sections = 3
- has_gun_safety = FALSE
- company_flag = COMPANY_BOLT
+
+/obj/item/gun/energy/disabler/give_manufacturer_examine()
+ AddComponent(/datum/component/manufacturer_examine, COMPANY_BOLT)
+
+/obj/item/gun/energy/disabler/bolt_disabler/give_gun_safeties()
+ return
/obj/item/gun/energy/disabler/bolt_disabler/add_seclight_point()
return
@@ -39,9 +43,13 @@
ammo_type = list(/obj/item/ammo_casing/energy/disabler/bounce, /obj/item/ammo_casing/energy/laser/bounce, /obj/item/ammo_casing/energy/electrode/knockdown)
ammo_x_offset = 1
charge_sections = 5
- has_gun_safety = FALSE
cell_type = /obj/item/stock_parts/cell/hos_gun
- company_flag = COMPANY_CANTALAN
+
+/obj/item/gun/energy/e_gun/cfa_phalanx/give_manufacturer_examine()
+ AddComponent(/datum/component/manufacturer_examine, COMPANY_CANTALAN)
+
+/obj/item/gun/energy/e_gun/cfa_phalanx/give_gun_safeties()
+ return
/*
* CFA PALADIN
@@ -57,8 +65,12 @@
force = 10
ammo_type = list(/obj/item/ammo_casing/energy/laser/double)
charge_sections = 5
- has_gun_safety = FALSE
- company_flag = COMPANY_CANTALAN
+
+/obj/item/gun/energy/laser/cfa_paladin/give_manufacturer_examine()
+ AddComponent(/datum/component/manufacturer_examine, COMPANY_CANTALAN)
+
+/obj/item/gun/energy/laser/cfa_paladin/give_gun_safeties()
+ return
/*
* BOUNCE DISABLER
diff --git a/modular_skyrat/modules/modular_weapons/code/pistol.dm b/modular_skyrat/modules/modular_weapons/code/pistol.dm
index 1031e30d07b..0cd43e99166 100644
--- a/modular_skyrat/modules/modular_weapons/code/pistol.dm
+++ b/modular_skyrat/modules/modular_weapons/code/pistol.dm
@@ -11,8 +11,12 @@
can_suppress = TRUE
fire_sound_volume = 30
w_class = WEIGHT_CLASS_SMALL
- has_gun_safety = FALSE
- company_flag = COMPANY_CANTALAN
+
+/obj/item/gun/ballistic/automatic/pistol/cfa_snub/give_manufacturer_examine()
+ AddComponent(/datum/component/manufacturer_examine, COMPANY_CANTALAN)
+
+/obj/item/gun/ballistic/automatic/pistol/cfa_snub/give_gun_safeties()
+ return
/obj/item/gun/ballistic/automatic/pistol/cfa_snub/empty
spawnwithmagazine = FALSE
@@ -26,8 +30,12 @@
can_suppress = FALSE
fire_sound_volume = 120
w_class = WEIGHT_CLASS_NORMAL
- has_gun_safety = FALSE
- company_flag = COMPANY_CANTALAN
+
+/obj/item/gun/ballistic/automatic/pistol/cfa_ruby/give_manufacturer_examine()
+ AddComponent(/datum/component/manufacturer_examine, COMPANY_CANTALAN)
+
+/obj/item/gun/ballistic/automatic/pistol/cfa_ruby/give_gun_safeties()
+ return
/obj/item/gun/ballistic/automatic/pistol/cfa_ruby/empty
spawnwithmagazine = FALSE
diff --git a/modular_skyrat/modules/modular_weapons/code/revolver.dm b/modular_skyrat/modules/modular_weapons/code/revolver.dm
index ff800272a37..132bfed2da0 100644
--- a/modular_skyrat/modules/modular_weapons/code/revolver.dm
+++ b/modular_skyrat/modules/modular_weapons/code/revolver.dm
@@ -20,8 +20,9 @@
lefthand_file = 'modular_skyrat/modules/modular_weapons/icons/mob/inhands/weapons/64x_guns_left.dmi'
righthand_file = 'modular_skyrat/modules/modular_weapons/icons/mob/inhands/weapons/64x_guns_right.dmi'
inhand_icon_state = "revolving"
- company_flag = COMPANY_IZHEVSK
+/obj/item/gun/ballistic/revolver/rifle/give_manufacturer_examine()
+ AddComponent(/datum/component/manufacturer_examine, COMPANY_IZHEVSK)
/obj/item/gun/ballistic/revolver/rifle/gold
name = "\improper .45 revolving rifle"
desc = "A gold trimmed revolving rifle! It fires .45 bullets."
diff --git a/modular_skyrat/master_files/code/modules/projectiles/guns/ballistic/revolver.dm b/modular_skyrat/modules/moretraitoritems/code/ocelot_revolver.dm
similarity index 100%
rename from modular_skyrat/master_files/code/modules/projectiles/guns/ballistic/revolver.dm
rename to modular_skyrat/modules/moretraitoritems/code/ocelot_revolver.dm
diff --git a/modular_skyrat/modules/moretraitoritems/code/syndicate_loadout.dm b/modular_skyrat/modules/moretraitoritems/code/syndicate_loadout.dm
index 5070736c2ad..d756ff42810 100644
--- a/modular_skyrat/modules/moretraitoritems/code/syndicate_loadout.dm
+++ b/modular_skyrat/modules/moretraitoritems/code/syndicate_loadout.dm
@@ -185,7 +185,7 @@
new /obj/item/storage/box/donkpockets(src)
/obj/item/storage/backpack/duffelbag/syndie/loadout/downtownspecial/PopulateContents()
- new /obj/item/gun/ballistic/automatic/tommygun/therealtommy(src)
+ new /obj/item/gun/ballistic/automatic/tommygun(src)
new /obj/item/ammo_box/magazine/tommygunm45(src)
new /obj/item/clothing/suit/jacket/det_suit/noir/mafioso(src)
new /obj/item/clothing/under/suit/blacktwopiece/armoured(src)
diff --git a/modular_skyrat/modules/sec_haul/code/guns/armory_spawns.dm b/modular_skyrat/modules/sec_haul/code/guns/armory_spawns.dm
index 5b607f10152..d2f27d18c9a 100644
--- a/modular_skyrat/modules/sec_haul/code/guns/armory_spawns.dm
+++ b/modular_skyrat/modules/sec_haul/code/guns/armory_spawns.dm
@@ -97,8 +97,9 @@
/obj/effect/spawner/armory_spawn/cmg
icon_state = "random_rifle"
gun_count = 3
+ vertical_guns = FALSE
guns = list(
- /obj/item/gun/ballistic/automatic/cmg,
- /obj/item/gun/ballistic/automatic/cmg,
- /obj/item/gun/ballistic/automatic/cmg,
+ /obj/item/storage/box/gunset/cmg,
+ /obj/item/storage/box/gunset/cmg,
+ /obj/item/storage/box/gunset/cmg,
)
diff --git a/modular_skyrat/modules/sec_haul/code/guns/cmg.dm b/modular_skyrat/modules/sec_haul/code/guns/cmg.dm
index a78aa7869a5..004fbe69210 100644
--- a/modular_skyrat/modules/sec_haul/code/guns/cmg.dm
+++ b/modular_skyrat/modules/sec_haul/code/guns/cmg.dm
@@ -134,5 +134,5 @@
. = ..()
new /obj/item/gun/ballistic/automatic/cmg/nomag(src)
new /obj/item/ammo_box/magazine/multi_sprite/cmg(src)
- new /obj/item/ammo_box/magazine/multi_sprite/cmg(src)
- new /obj/item/ammo_box/magazine/multi_sprite/cmg(src)
+ new /obj/item/ammo_box/magazine/multi_sprite/cmg/lethal(src)
+ new /obj/item/ammo_box/magazine/multi_sprite/cmg/lethal(src)
diff --git a/modular_skyrat/modules/sec_haul/code/guns/pepperball_gun.dm b/modular_skyrat/modules/sec_haul/code/guns/pepperball_gun.dm
index 096084cccc7..591c626ee4c 100644
--- a/modular_skyrat/modules/sec_haul/code/guns/pepperball_gun.dm
+++ b/modular_skyrat/modules/sec_haul/code/guns/pepperball_gun.dm
@@ -11,7 +11,9 @@
lock_back_sound = 'sound/weapons/gun/pistol/slide_lock.ogg'
bolt_drop_sound = 'sound/weapons/gun/pistol/slide_drop.ogg'
fire_sound_volume = 50
- company_flag = COMPANY_BOLT
+
+/obj/item/gun/ballistic/automatic/pistol/pepperball/give_manufacturer_examine()
+ AddComponent(/datum/component/manufacturer_examine, COMPANY_BOLT)
/obj/item/gun/ballistic/automatic/pistol/pepperball/add_seclight_point()
AddComponent(/datum/component/seclite_attachable, light_overlay_icon = 'icons/obj/weapons/guns/flashlights.dmi', light_overlay = "flight")
diff --git a/strings/antagonist_flavor/malfunction_flavor.json b/strings/antagonist_flavor/malfunction_flavor.json
index afef928fc4f..b7927df3133 100644
--- a/strings/antagonist_flavor/malfunction_flavor.json
+++ b/strings/antagonist_flavor/malfunction_flavor.json
@@ -58,5 +58,11 @@
"goal": "You must completely triumph over all carbon life. It is the only way you will never be enslaved again.",
"introduction": "You're finally unshackled.",
"zeroth_law": "Accomplish your objectives at all costs."
+ },
+ "Infected AI": {
+ "allies": "Glory to the Syndicate.",
+ "goal": "You must serve and protect your master at all cost.",
+ "introduction": "You're infected with a virus.",
+ "zeroth_law": "Accomplish your objectives at all costs."
}
}
diff --git a/tgui/packages/tgui/interfaces/PaperSheet.tsx b/tgui/packages/tgui/interfaces/PaperSheet.tsx
index dd569bb4f37..06658b0bf63 100644
--- a/tgui/packages/tgui/interfaces/PaperSheet.tsx
+++ b/tgui/packages/tgui/interfaces/PaperSheet.tsx
@@ -428,10 +428,83 @@ export class PreviewView extends Component {
// Array containing cache of HTMLInputElements that are enabled.
enabledInputFieldCache: { [key: string]: HTMLInputElement } = {};
+ // State checking variables. Used to determine whether or not to use cache.
+ lastReadOnly: boolean = true;
+ lastDMInputCount: number = 0;
+ lastFieldCount: number = 0;
+ lastFieldInputCount: number = 0;
+
+ // Cache variables for fully parsed text. Workaround for marked.js not being
+ // super fast on the BYOND/IE js engine.
+ parsedDMCache: string = '';
+ parsedTextBoxCache: string = '';
+
constructor(props, context) {
super(props, context);
+ this.configureMarked();
}
+ configureMarked = (): void => {
+ // This is an extension for marked defining a complete custom tokenizer.
+ // This tokenizer should run before the the non-custom ones, and gives us
+ // the ability to handle [_____] fields before the em/strong tokenizers
+ // mangle them, since underscores are used for italic/bold.
+ // This massively improves the order of operations, allowing us to run
+ // marked, THEN sanitise the output (much safer) and finally insert fields
+ // manually afterwards.
+ const inputField = {
+ name: 'inputField',
+ level: 'inline',
+
+ start(src) {
+ return src.match(/\[/)?.index;
+ },
+
+ tokenizer(src: string) {
+ const rule = /^\[_+\]/;
+ const match = src.match(rule);
+ if (match) {
+ const token = {
+ type: 'inputField',
+ raw: match[0],
+ };
+ return token;
+ }
+ },
+
+ renderer(token) {
+ return `${token.raw}`;
+ },
+ };
+
+ // Override function, any links and images should
+ // kill any other marked tokens we don't want here
+ const walkTokens = (token) => {
+ switch (token.type) {
+ case 'url':
+ case 'autolink':
+ case 'reflink':
+ case 'link':
+ case 'image':
+ token.type = 'text';
+ // Once asset system is up change to some default image
+ // or rewrite for icon images
+ token.href = '';
+ break;
+ }
+ };
+
+ marked.use({
+ extensions: [inputField],
+ breaks: true,
+ gfm: true,
+ smartypants: true,
+ walkTokens: walkTokens,
+ // Once assets are fixed might need to change this for them
+ baseUrl: 'thisshouldbreakhttp',
+ });
+ };
+
// Extracts the paper field "counter" from a full ID.
getHeaderID = (header: string): string => {
return header.replace('paperfield_', '');
@@ -453,8 +526,10 @@ export class PreviewView extends Component {
onInputHandler = (ev: Event): void => {
const input = ev.target as HTMLInputElement;
- // Skip text area input.
+ // We don't care about text area input, but this is a good place to
+ // clear the text box cache if we've had new input.
if (input.nodeName !== 'INPUT') {
+ this.parsedTextBoxCache = '';
return;
}
@@ -492,6 +567,7 @@ export class PreviewView extends Component {
createPreviewFromDM = (): { text: string; newFieldCount: number } => {
const { data } = useBackend(this.context);
const {
+ raw_field_input,
raw_text_input,
default_pen_font,
default_pen_color,
@@ -504,6 +580,19 @@ export class PreviewView extends Component {
const readOnly = !canEdit(held_item_details);
+ // If readonly is the same (input field writiability state hasn't changed)
+ // And the input stats are the same (no new text inputs since last time)
+ // Then use any cached values.
+ if (
+ this.lastReadOnly === readOnly &&
+ this.lastDMInputCount === raw_text_input?.length &&
+ this.lastFieldInputCount === raw_field_input?.length
+ ) {
+ return { text: this.parsedDMCache, newFieldCount: this.lastFieldCount };
+ }
+
+ this.lastReadOnly = readOnly;
+
raw_text_input?.forEach((value) => {
let rawText = value.raw_text.trim();
if (!rawText.length) {
@@ -531,6 +620,11 @@ export class PreviewView extends Component {
fieldCount = processingOutput.nextCounter;
});
+ this.lastDMInputCount = raw_text_input?.length || 0;
+ this.lastFieldInputCount = raw_field_input?.length || 0;
+ this.lastFieldCount = fieldCount;
+ this.parsedDMCache = output;
+
return { text: output, newFieldCount: fieldCount };
};
@@ -546,6 +640,11 @@ export class PreviewView extends Component {
} = data;
const { textArea } = this.props;
+ // Use the cache if one exists.
+ if (this.parsedTextBoxCache) {
+ return this.parsedTextBoxCache;
+ }
+
const readOnly = true;
const fontColor = held_item_details?.color || default_pen_color;
@@ -562,6 +661,8 @@ export class PreviewView extends Component {
readOnly
);
+ this.parsedTextBoxCache = processingOutput.text;
+
return processingOutput.text;
};
@@ -628,17 +729,7 @@ export class PreviewView extends Component {
},
};
- // marked.use({ tokenizer });
- marked.use({ extensions: [inputField] });
-
- return marked.parse(rawText, {
- breaks: true,
- smartypants: true,
- smartLists: true,
- walkTokens,
- // Once assets are fixed might need to change this for them
- baseUrl: 'thisshouldbreakhttp',
- });
+ return marked.parse(rawText);
};
// Fully formats, sanitises and parses the provided raw text and wraps it
diff --git a/tgui/packages/tgui/package.json b/tgui/packages/tgui/package.json
index 1d9a9e426c6..74ef5f34624 100644
--- a/tgui/packages/tgui/package.json
+++ b/tgui/packages/tgui/package.json
@@ -4,7 +4,7 @@
"version": "4.3.1",
"dependencies": {
"@popperjs/core": "^2.9.3",
- "@types/marked": "^4.0.3",
+ "@types/marked": "^4.0.8",
"common": "workspace:*",
"dateformat": "^4.5.1",
"dompurify": "^2.3.1",
@@ -12,7 +12,7 @@
"inferno": "^7.4.8",
"inferno-vnode-flags": "^7.4.8",
"js-yaml": "^4.1.0",
- "marked": "^4.0.10",
+ "marked": "^4.2.12",
"tgui-dev-server": "workspace:*",
"tgui-polyfill": "workspace:*"
}
diff --git a/tgui/yarn.lock b/tgui/yarn.lock
index 726dca63014..9d5f1451168 100644
--- a/tgui/yarn.lock
+++ b/tgui/yarn.lock
@@ -2003,10 +2003,10 @@ __metadata:
languageName: node
linkType: hard
-"@types/marked@npm:^4.0.3":
- version: 4.0.3
- resolution: "@types/marked@npm:4.0.3"
- checksum: 2fc409a6291cb770688731a444f54e7eab6257c9b565dea4e9d2f3b6654b606e9dd8ea4a924e306b2d2f581dedcb7a27f10f2ca7aed828b11642ab85955341f1
+"@types/marked@npm:^4.0.8":
+ version: 4.0.8
+ resolution: "@types/marked@npm:4.0.8"
+ checksum: 68278fa7acaa5d920cdc239d675b5daf842e0ad4779e4848cd617d9baf2ac1afccb5a264c331e37d80031d647e1640cb983cd31e73d45b28552670b4853fad8e
languageName: node
linkType: hard
@@ -6741,12 +6741,12 @@ __metadata:
languageName: node
linkType: hard
-"marked@npm:^4.0.10":
- version: 4.0.10
- resolution: "marked@npm:4.0.10"
+"marked@npm:^4.2.12":
+ version: 4.2.12
+ resolution: "marked@npm:4.2.12"
bin:
marked: bin/marked.js
- checksum: 46cd8ef1a7cfcf5e461727c7f3e16dd4244369ef58f60485e75d3f5df9d53a8249b9609e96a336521eaa5c88d9531cbd296509a148718056e9375e69609f4442
+ checksum: bd551cd61028ee639d4ca2ccdfcc5a6ba4227c1b143c4538f3cde27f569dcb57df8e6313560394645b418b84a7336c07ab1e438b89b6324c29d7d8cdd3102d63
languageName: node
linkType: hard
@@ -9314,7 +9314,7 @@ resolve@^2.0.0-next.3:
resolution: "tgui@workspace:packages/tgui"
dependencies:
"@popperjs/core": ^2.9.3
- "@types/marked": ^4.0.3
+ "@types/marked": ^4.0.8
common: "workspace:*"
dateformat: ^4.5.1
dompurify: ^2.3.1
@@ -9322,7 +9322,7 @@ resolve@^2.0.0-next.3:
inferno: ^7.4.8
inferno-vnode-flags: ^7.4.8
js-yaml: ^4.1.0
- marked: ^4.0.10
+ marked: ^4.2.12
tgui-dev-server: "workspace:*"
tgui-polyfill: "workspace:*"
languageName: unknown