Warning: Physical trauma[LAZYLEN(wounded_part.wounds) > 1? "s" : ""] detected in [wounded_part.name]"
for(var/limb_wound in wounded_part.wounds)
var/datum/wound/current_wound = limb_wound
- render_list += "[simple_scan ? current_wound.get_simple_scanner_description() : current_wound.get_scanner_description()]
\n"
+ render_list += "[simple_scan ? current_wound.get_simple_scanner_description() : current_wound.get_scanner_description()]
"
if (scanner.give_wound_treatment_bonus)
ADD_TRAIT(current_wound, TRAIT_WOUND_SCANNED, ANALYZER_TRAIT)
if(!advised)
@@ -670,8 +704,8 @@
var/list/render = list()
for(var/datum/disease/disease as anything in patient.diseases)
if(!(disease.visibility_flags & HIDDEN_SCANNER))
- render += "Warning: [disease.form] detected\n\
- Name: [disease.name].\nType: [disease.spread_text].\nStage: [disease.stage]/[disease.max_stages].\nPossible Cure: [disease.cure_text]
\
+ render += "Warning: [disease.form] detected
\
+ Name: [disease.name].
Type: [disease.spread_text].
Stage: [disease.stage]/[disease.max_stages].
Possible Cure: [disease.cure_text]
\
"
if(!length(render))
diff --git a/code/game/objects/items/devices/taperecorder.dm b/code/game/objects/items/devices/taperecorder.dm
index b86489fae9ea7..9b6328fe682fa 100644
--- a/code/game/objects/items/devices/taperecorder.dm
+++ b/code/game/objects/items/devices/taperecorder.dm
@@ -162,7 +162,7 @@
if(mytape && recording)
mytape.timestamp += mytape.used_capacity
- mytape.storedinfo += "\[[time2text(mytape.used_capacity,"mm:ss")]\] [raw_message]"
+ mytape.storedinfo += "\[[time2text(mytape.used_capacity,"mm:ss")]\] [speaker.GetVoice()]: [raw_message]"
/obj/item/taperecorder/verb/record()
diff --git a/code/game/objects/items/devices/traitordevices.dm b/code/game/objects/items/devices/traitordevices.dm
index 8327e185ea612..ee4a61b935157 100644
--- a/code/game/objects/items/devices/traitordevices.dm
+++ b/code/game/objects/items/devices/traitordevices.dm
@@ -361,15 +361,6 @@ effective or pretty fucking useless.
new /obj/item/analyzer(src)
new /obj/item/wirecutters(src)
-/obj/item/storage/toolbox/emergency/turret/storage_insert_on_interacted_with(datum/storage, obj/item/inserted, mob/living/user)
- if(!istype(inserted, /obj/item/wrench/combat))
- return TRUE
- if(!user.combat_mode)
- return TRUE
- if(!inserted.toolspeed)
- return TRUE
- return FALSE
-
/obj/item/storage/toolbox/emergency/turret/item_interaction(mob/living/user, obj/item/tool, list/modifiers)
if(!istype(tool, /obj/item/wrench/combat))
return NONE
diff --git a/code/game/objects/items/devices/transfer_valve.dm b/code/game/objects/items/devices/transfer_valve.dm
index d17530c801085..4f0c0a84aa317 100644
--- a/code/game/objects/items/devices/transfer_valve.dm
+++ b/code/game/objects/items/devices/transfer_valve.dm
@@ -25,11 +25,36 @@
/obj/item/transfer_valve/Initialize(mapload)
. = ..()
RegisterSignal(src, COMSIG_ITEM_FRIED, PROC_REF(on_fried))
+ register_context()
/obj/item/transfer_valve/Destroy()
attached_device = null
return ..()
+/obj/item/transfer_valve/add_context(atom/source, list/context, obj/item/held_item, mob/user)
+ . = ..()
+
+ if(tank_one || tank_two)
+ context[SCREENTIP_CONTEXT_ALT_LMB] = "Remove [tank_one || tank_two]"
+ . = CONTEXTUAL_SCREENTIP_SET
+ if(istype(held_item) && is_type_in_list(held_item, list(/obj/item/tank, /obj/item/assembly)))
+ context[SCREENTIP_CONTEXT_LMB] = "Attach [held_item]"
+ . = CONTEXTUAL_SCREENTIP_SET
+
+ return . || NONE
+
+/obj/item/transfer_valve/click_alt(mob/user)
+ if(tank_one)
+ split_gases()
+ valve_open = FALSE
+ tank_one.forceMove(drop_location())
+ else if(tank_two)
+ split_gases()
+ valve_open = FALSE
+ tank_two.forceMove(drop_location())
+
+ return CLICK_ACTION_SUCCESS
+
/obj/item/transfer_valve/IsAssemblyHolder()
return TRUE
diff --git a/code/game/objects/items/eightball.dm b/code/game/objects/items/eightball.dm
index 4445cdd1b7277..40f08e78ffc77 100644
--- a/code/game/objects/items/eightball.dm
+++ b/code/game/objects/items/eightball.dm
@@ -153,7 +153,7 @@
/obj/item/toy/eightball/haunted/start_shaking(mob/user)
// notify ghosts that someone's shaking a haunted eightball
// and inform them of the message, (hopefully a yes/no question)
- selected_message = tgui_input_text(user, "What is your question?", "Eightball") || initial(selected_message)
+ selected_message = tgui_input_text(user, "What is your question?", "Eightball", max_length = MAX_MESSAGE_LEN) || initial(selected_message)
if (!(src in user.held_items))
return FALSE
notify_ghosts(
diff --git a/code/game/objects/items/emags.dm b/code/game/objects/items/emags.dm
index ccb52b71bc3bc..f854ba1b90a0c 100644
--- a/code/game/objects/items/emags.dm
+++ b/code/game/objects/items/emags.dm
@@ -137,16 +137,16 @@
. = ..()
type_blacklist = list(typesof(/obj/machinery/door/airlock) + typesof(/obj/machinery/door/window/) + typesof(/obj/machinery/door/firedoor) - typesof(/obj/machinery/door/airlock/tram)) //list of all typepaths that require a specialized emag to hack.
-/obj/item/card/emag/storage_insert_on_interaction(datum/storage, atom/storage_holder, mob/living/user)
- return !user.combat_mode
-
/obj/item/card/emag/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
+ if(SHOULD_SKIP_INTERACTION(interacting_with, src, user))
+ return NONE // lets us put things in bags without trying to emag them
if(!can_emag(interacting_with, user))
return ITEM_INTERACT_BLOCKING
log_combat(user, interacting_with, "attempted to emag")
if(interacting_with.emag_act(user, src))
SSblackbox.record_feedback("tally", "atom_emagged", 1, interacting_with.type)
- return ITEM_INTERACT_SUCCESS
+ return ITEM_INTERACT_SUCCESS
+ return NONE // In a perfect world this would be blocking, but this is not a perfect world
/obj/item/card/emag/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
return prox_check ? NONE : interact_with_atom(interacting_with, user)
diff --git a/code/game/objects/items/etherealdiscoball.dm b/code/game/objects/items/etherealdiscoball.dm
index fe066bd1bf572..4eca1dc2fc0a7 100644
--- a/code/game/objects/items/etherealdiscoball.dm
+++ b/code/game/objects/items/etherealdiscoball.dm
@@ -1,5 +1,5 @@
/obj/item/etherealballdeployer
- name = "Portable Ethereal Disco Ball"
+ name = "portable ethereal disco ball"
desc = "Press the button for a deployment of slightly-unethical PARTY!"
icon = 'icons/obj/devices/remote.dmi'
icon_state = "ethdisco"
@@ -11,7 +11,7 @@
qdel(src)
/obj/structure/etherealball
- name = "Ethereal Disco Ball"
+ name = "ethereal disco ball"
desc = "The ethics of this discoball are questionable."
icon = 'icons/obj/machines/floor.dmi'
icon_state = "ethdisco_head_0"
diff --git a/code/game/objects/items/extinguisher.dm b/code/game/objects/items/extinguisher.dm
index 764e2fc6173bf..c542048b49d98 100644
--- a/code/game/objects/items/extinguisher.dm
+++ b/code/game/objects/items/extinguisher.dm
@@ -207,13 +207,15 @@
else
return FALSE
-/obj/item/extinguisher/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
- return interact_with_atom(interacting_with, user, modifiers)
-
/obj/item/extinguisher/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
- if (interacting_with.loc == user)
+ if(interacting_with.loc == user)
return NONE
+ // Always skip interaction if it's a bag or table (that's not on fire)
+ if(!(interacting_with.resistance_flags & ON_FIRE) && HAS_TRAIT(interacting_with, TRAIT_COMBAT_MODE_SKIP_INTERACTION))
+ return NONE
+ return ranged_interact_with_atom(interacting_with, user, modifiers)
+/obj/item/extinguisher/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(refilling)
refilling = FALSE
return NONE
diff --git a/code/game/objects/items/food/bait.dm b/code/game/objects/items/food/bait.dm
index f31eb44f308eb..711c6cb1e68ff 100644
--- a/code/game/objects/items/food/bait.dm
+++ b/code/game/objects/items/food/bait.dm
@@ -6,6 +6,8 @@
var/bait_quality = TRAIT_BASIC_QUALITY_BAIT
/// Icon state added to main fishing rod icon when this bait is equipped
var/rod_overlay_icon_state
+ /// Is this included in the autowiki?
+ var/show_on_wiki = TRUE
/obj/item/food/bait/Initialize(mapload)
. = ..()
@@ -36,9 +38,14 @@
lefthand_file = 'icons/mob/inhands/items_lefthand.dmi'
righthand_file = 'icons/mob/inhands/items_righthand.dmi'
inhand_icon_state = "pen"
+ bait_quality = TRAIT_GREAT_QUALITY_BAIT //this is only here for autowiki purposes, it's removed on init.
food_reagents = list(/datum/reagent/drug/kronkaine = 2) //The kronkaine is the thing that makes this a great bait.
tastes = list("hypocrisy" = 1)
+/obj/item/food/bait/natural/Initialize(mapload)
+ . = ..()
+ REMOVE_TRAIT(src, bait_quality, INNATE_TRAIT)
+
/obj/item/food/bait/doughball
name = "doughball"
desc = "Small piece of dough. Simple but effective fishing bait."
@@ -51,17 +58,12 @@
bait_quality = TRAIT_BASIC_QUALITY_BAIT
rod_overlay_icon_state = "dough_overlay"
-/**
- * Bound to the tech fishing rod, from which cannot be removed,
- * Bait-related preferences and traits, both negative and positive,
- * should be ignored by this bait.
- * Otherwise it'd be hard/impossible to cath some fish with it,
- * making that rod a shoddy choice in the long run.
- */
+///The abstract synthetic doughball type.
/obj/item/food/bait/doughball/synthetic
name = "synthetic doughball"
icon_state = "doughball_blue"
preserved_food = TRUE
+ show_on_wiki = FALSE //It's an abstract item.
/obj/item/food/bait/doughball/synthetic/Initialize(mapload)
. = ..()
@@ -70,10 +72,17 @@
///Found in the can of omni-baits, only available from the super fishing toolbox, from the fishing mystery box.
/obj/item/food/bait/doughball/synthetic/super
name = "super-doughball"
- desc = "No fish will be able to resist this."
+ desc = "Be they herbivore or carnivores, no fish will be able to resist this."
bait_quality = TRAIT_GREAT_QUALITY_BAIT
+ show_on_wiki = TRUE
-///Used by the advanced fishing rod
+/**
+ * Bound to the tech fishing rod, from which cannot be removed,
+ * Bait-related preferences and traits, both negative and positive,
+ * should be ignored by this bait.
+ * Otherwise it'd be hard/impossible to cath some fish with it,
+ * making that rod a shoddy choice in the long run.
+ */
/obj/item/food/bait/doughball/syntethic/unconsumable
/obj/item/food/bait/doughball/synthetic/unconsumable/Initialize(mapload)
diff --git a/code/game/objects/items/food/donuts.dm b/code/game/objects/items/food/donuts.dm
index 0d2e2f91d3008..922ed2eaa6674 100644
--- a/code/game/objects/items/food/donuts.dm
+++ b/code/game/objects/items/food/donuts.dm
@@ -79,7 +79,7 @@
reagents.add_reagent(extra_reagent, 3)
/obj/item/food/donut/meat
- name = "Meat Donut"
+ name = "meat donut"
desc = "Tastes as gross as it looks."
icon_state = "donut_meat"
food_reagents = list(
diff --git a/code/game/objects/items/food/meatdish.dm b/code/game/objects/items/food/meatdish.dm
index 5ad5cea20fae8..a619be72062af 100644
--- a/code/game/objects/items/food/meatdish.dm
+++ b/code/game/objects/items/food/meatdish.dm
@@ -57,7 +57,7 @@
food_reagents = list(
/datum/reagent/consumable/nutriment/protein = 4,
/datum/reagent/consumable/nutriment/vitamin = 3,
- /datum/reagent/consumable/nutriment/fat/oil = 2,
+ /datum/reagent/consumable/nutriment/fat = 2,
)
bite_consumption = 4.5
crafting_complexity = FOOD_COMPLEXITY_1
@@ -99,14 +99,20 @@
/obj/item/food/fishmeat/gunner_jellyfish
name = "filleted gunner jellyfish"
- desc = "A gunner jellyfish with the stingers removed. Mildly hallucinogenic."
+ desc = "A gunner jellyfish with the stingers removed. Mildly hallucinogenic when raw."
icon = 'icons/obj/food/lizard.dmi'
icon_state = "jellyfish_fillet"
food_reagents = list(
- /datum/reagent/consumable/nutriment/protein = 4,
- /datum/reagent/toxin/mindbreaker = 2,
+ /datum/reagent/consumable/nutriment/protein = 4, //The halluginogen comes from the fish trait.
)
+///Premade gunner jellyfish fillets from supply orders. Contains the halluginogen that'd be normally from the fish trait.
+/obj/item/food/fishmeat/gunner_jellyfish/supply
+
+/obj/item/food/fishmeat/gunner_jellyfish/supply/Initialize(mapload)
+ food_reagents[/datum/reagent/toxin/mindbreaker/fish] = 2
+ return ..()
+
/obj/item/food/fishmeat/armorfish
name = "cleaned armorfish"
desc = "An armorfish with its guts and shell removed, ready for use in cooking."
diff --git a/code/game/objects/items/food/misc.dm b/code/game/objects/items/food/misc.dm
index b2cf4d132c5fb..54ec5ce019012 100644
--- a/code/game/objects/items/food/misc.dm
+++ b/code/game/objects/items/food/misc.dm
@@ -339,7 +339,7 @@
crafting_complexity = FOOD_COMPLEXITY_5
/obj/item/food/branrequests
- name = "Bran Requests Cereal"
+ name = "bran requests cereal"
desc = "A dry cereal that satiates your requests for bran. Tastes uniquely like raisins and salt."
icon_state = "bran_requests"
food_reagents = list(
@@ -422,7 +422,7 @@
w_class = WEIGHT_CLASS_TINY
/obj/item/food/crab_rangoon
- name = "Crab Rangoon"
+ name = "crab rangoon"
desc = "Has many names, like crab puffs, cheese won'tons, crab dumplings? Whatever you call them, they're a fabulous blast of cream cheesy crab."
icon = 'icons/obj/food/meat.dmi'
icon_state = "crabrangoon"
diff --git a/code/game/objects/items/grenades/_grenade.dm b/code/game/objects/items/grenades/_grenade.dm
index ca7da893bb4b4..cbf604db63d0d 100644
--- a/code/game/objects/items/grenades/_grenade.dm
+++ b/code/game/objects/items/grenades/_grenade.dm
@@ -51,6 +51,8 @@
var/shrapnel_radius
///Did we add the component responsible for spawning shrapnel to this?
var/shrapnel_initialized
+ ///Possible timers that can be assigned for detonation. Values are strings in SECONDS
+ var/list/possible_fuse_time = list("Instant", "3", "4", "5")
/obj/item/grenade/Initialize(mapload)
. = ..()
@@ -210,7 +212,10 @@
return FALSE
if(change_det_time())
tool.play_tool_sound(src)
- to_chat(user, span_notice("You modify the time delay. It's set for [DisplayTimeText(det_time)]."))
+ if(det_time == 0)
+ to_chat(user, span_notice("You modify the time delay. It's set to be instantaneous."))
+ else
+ to_chat(user, span_notice("You modify the time delay. It's set for [DisplayTimeText(det_time)]."))
return TRUE
/obj/item/grenade/multitool_act(mob/living/user, obj/item/tool)
@@ -220,7 +225,7 @@
. = TRUE
- var/newtime = tgui_input_list(user, "Please enter a new detonation time", "Detonation Timer", list("Instant", 3, 4, 5))
+ var/newtime = tgui_input_list(user, "Please enter a new detonation time", "Detonation Timer", possible_fuse_time)
if (isnull(newtime))
return
if(!user.can_perform_action(src))
@@ -228,25 +233,40 @@
if(newtime == "Instant" && change_det_time(0))
to_chat(user, span_notice("You modify the time delay. It's set to be instantaneous."))
return
- newtime = round(newtime)
+ newtime = round(text2num(newtime))
if(change_det_time(newtime))
to_chat(user, span_notice("You modify the time delay. It's set for [DisplayTimeText(det_time)]."))
-/obj/item/grenade/proc/change_det_time(time) //Time uses real time.
+/**
+ * Sets det_time to a number in SECONDS
+ *
+ * if time is passed as an argument, `det_time` will be `time SECONDS`
+ *
+ * Cycles the duration of the fuse of the grenade `det_time` based on the options provided in list/possible_fuse_time
+*/
+/obj/item/grenade/proc/change_det_time(time)
. = TRUE
+ //Multitool
if(!isnull(time))
- det_time = round(clamp(time * 10, 0, 5 SECONDS))
+ det_time = round(clamp(time SECONDS, 0, 5 SECONDS)) //This is fine for now but consider making this a variable if you want >5s fuse
+ return
+
+ //Screwdriver
+ if(det_time == 0)
+ det_time = "Instant"
+ else
+ det_time = num2text(det_time * 0.1)
+
+ var/old_selection = possible_fuse_time.Find(det_time) //Position of det_time in the list
+ if(old_selection >= possible_fuse_time.len)
+ det_time = possible_fuse_time[1]
else
- var/previous_time = det_time
- switch(det_time)
- if (0)
- det_time = 3 SECONDS
- if (3 SECONDS)
- det_time = 5 SECONDS
- if (5 SECONDS)
- det_time = 0
- if(det_time == previous_time)
- det_time = 5 SECONDS
+ det_time = possible_fuse_time[old_selection+1]
+
+ if(det_time == "Instant")
+ det_time = 0 //String to num conversion because I hate coders
+ return
+ det_time = text2num(det_time) SECONDS
/obj/item/grenade/attack_paw(mob/user, list/modifiers)
return attack_hand(user, modifiers)
diff --git a/code/game/objects/items/grenades/flashbang.dm b/code/game/objects/items/grenades/flashbang.dm
index 98e7a4bab796e..6817610bf76e7 100644
--- a/code/game/objects/items/grenades/flashbang.dm
+++ b/code/game/objects/items/grenades/flashbang.dm
@@ -4,6 +4,7 @@
inhand_icon_state = "flashbang"
lefthand_file = 'icons/mob/inhands/equipment/security_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/security_righthand.dmi'
+ possible_fuse_time = list("3", "4", "5")
var/flashbang_range = 7 //how many tiles away the mob will be stunned.
/obj/item/grenade/flashbang/apply_grenade_fantasy_bonuses(quality)
diff --git a/code/game/objects/items/implants/security/implant_noteleport.dm b/code/game/objects/items/implants/security/implant_noteleport.dm
index b4795a7f797b7..a757e2cc0cd0f 100644
--- a/code/game/objects/items/implants/security/implant_noteleport.dm
+++ b/code/game/objects/items/implants/security/implant_noteleport.dm
@@ -17,6 +17,7 @@
if(!. || !isliving(target))
return FALSE
RegisterSignal(target, COMSIG_MOVABLE_TELEPORTING, PROC_REF(on_teleport))
+ RegisterSignal(target, COMSIG_MOB_PRE_JAUNT, PROC_REF(on_jaunt))
return TRUE
/obj/item/implant/teleport_blocker/removed(mob/target, silent = FALSE, special = FALSE)
@@ -24,6 +25,7 @@
if(!. || !isliving(target))
return FALSE
UnregisterSignal(target, COMSIG_MOVABLE_TELEPORTING)
+ UnregisterSignal(target, COMSIG_MOB_PRE_JAUNT)
return TRUE
/// Signal for COMSIG_MOVABLE_TELEPORTED that blocks teleports and stuns the would-be-teleportee.
@@ -38,6 +40,18 @@
spark_system.start()
return COMPONENT_BLOCK_TELEPORT
+/// Signal for COMSIG_MOB_PRE_JAUNT that prevents a user from entering a jaunt.
+/obj/item/implant/teleport_blocker/proc/on_jaunt(mob/living/jaunter)
+ SIGNAL_HANDLER
+
+ to_chat(jaunter, span_holoparasite("As you attempt to jaunt, you slam directly into the barrier between realities and are sent crashing back into corporeality!"))
+
+ jaunter.apply_status_effect(/datum/status_effect/incapacitating/paralyzed, 5 SECONDS)
+ var/datum/effect_system/spark_spread/quantum/spark_system = new()
+ spark_system.set_up(5, TRUE, jaunter)
+ spark_system.start()
+ return COMPONENT_BLOCK_JAUNT
+
/obj/item/implantcase/teleport_blocker
name = "implant case - 'Bluespace Grounding'"
desc = "A glass case containing a bluespace grounding implant."
diff --git a/code/game/objects/items/implants/security/implant_track.dm b/code/game/objects/items/implants/security/implant_track.dm
index b95c0afa7d857..9b8050d7dade2 100644
--- a/code/game/objects/items/implants/security/implant_track.dm
+++ b/code/game/objects/items/implants/security/implant_track.dm
@@ -48,7 +48,7 @@
return
if(params["implant_action"] == "warn")
- var/warning = tgui_input_text(user, "What warning do you want to send to [imp_in.name]?", "Messaging")
+ var/warning = tgui_input_text(user, "What warning do you want to send to [imp_in.name]?", "Messaging", max_length = MAX_MESSAGE_LEN)
if(!warning || QDELETED(src) || QDELETED(user) || QDELETED(console) || isnull(imp_in))
return TRUE
if(!console.is_operational || !user.can_perform_action(console, NEED_DEXTERITY|ALLOW_SILICON_REACH))
diff --git a/code/game/objects/items/lighter.dm b/code/game/objects/items/lighter.dm
new file mode 100644
index 0000000000000..a0613450b28d6
--- /dev/null
+++ b/code/game/objects/items/lighter.dm
@@ -0,0 +1,362 @@
+/obj/item/lighter
+ name = "\improper Zippo lighter"
+ desc = "The zippo."
+ icon = 'icons/obj/cigarettes.dmi'
+ icon_state = "zippo"
+ inhand_icon_state = "zippo"
+ worn_icon_state = "lighter"
+ w_class = WEIGHT_CLASS_TINY
+ obj_flags = CONDUCTS_ELECTRICITY
+ slot_flags = ITEM_SLOT_BELT
+ resistance_flags = FIRE_PROOF
+ grind_results = list(/datum/reagent/iron = 1, /datum/reagent/fuel = 5, /datum/reagent/fuel/oil = 5)
+ custom_price = PAYCHECK_CREW * 1.1
+ light_system = OVERLAY_LIGHT
+ light_range = 2
+ light_power = 1.3
+ light_color = LIGHT_COLOR_FIRE
+ light_on = FALSE
+ toolspeed = 1.5
+ tool_behaviour = TOOL_WELDER
+ ///The amount of heat a lighter has while it's on. We're using the define to ensure lighters can't do things we don't want them to.
+ var/heat_while_on = HIGH_TEMPERATURE_REQUIRED - 100
+ ///The amount of time the lighter has been on for, for fuel consumption.
+ var/burned_fuel_for = 0
+ ///The max amount of fuel the lighter can hold.
+ var/maximum_fuel = 6
+ /// Whether the lighter is lit.
+ var/lit = FALSE
+ /// Whether the lighter is fancy. Fancy lighters have fancier flavortext and won't burn thumbs.
+ var/fancy = TRUE
+ /// The engraving overlay used by this lighter.
+ var/overlay_state
+ /// A list of possible engraving overlays.
+ var/list/overlay_list = list(
+ "plain",
+ "dame",
+ "thirteen",
+ "snake",
+ )
+
+/obj/item/lighter/Initialize(mapload)
+ . = ..()
+ create_reagents(maximum_fuel, REFILLABLE | DRAINABLE)
+ reagents.add_reagent(/datum/reagent/fuel, maximum_fuel)
+ if(!overlay_state)
+ overlay_state = pick(overlay_list)
+ AddComponent(\
+ /datum/component/bullet_intercepting,\
+ block_chance = 0.5,\
+ active_slots = ITEM_SLOT_SUITSTORE,\
+ on_intercepted = CALLBACK(src, PROC_REF(on_intercepted_bullet)),\
+ )
+ update_appearance()
+
+/// Destroy the lighter when it's shot by a bullet
+/obj/item/lighter/proc/on_intercepted_bullet(mob/living/victim, obj/projectile/bullet)
+ victim.visible_message(span_warning("\The [bullet] shatters on [victim]'s lighter!"))
+ playsound(victim, SFX_RICOCHET, 100, TRUE)
+ new /obj/effect/decal/cleanable/oil(get_turf(src))
+ do_sparks(1, TRUE, src)
+ victim.dropItemToGround(src, force = TRUE, silent = TRUE)
+ qdel(src)
+
+/obj/item/lighter/cyborg_unequip(mob/user)
+ if(!lit)
+ return
+ set_lit(FALSE)
+
+/obj/item/lighter/suicide_act(mob/living/carbon/user)
+ if (lit)
+ user.visible_message(span_suicide("[user] begins holding \the [src]'s flame up to [user.p_their()] face! It looks like [user.p_theyre()] trying to commit suicide!"))
+ playsound(src, 'sound/items/welder.ogg', 50, TRUE)
+ return FIRELOSS
+ else
+ user.visible_message(span_suicide("[user] begins whacking [user.p_them()]self with \the [src]! It looks like [user.p_theyre()] trying to commit suicide!"))
+ return BRUTELOSS
+
+/obj/item/lighter/update_icon_state()
+ icon_state = "[initial(icon_state)][lit ? "-on" : ""]"
+ return ..()
+
+/obj/item/lighter/update_overlays()
+ . = ..()
+ . += create_lighter_overlay()
+
+/// Generates an overlay used by this lighter.
+/obj/item/lighter/proc/create_lighter_overlay()
+ return mutable_appearance(icon, "lighter_overlay_[overlay_state][lit ? "-on" : ""]")
+
+/obj/item/lighter/ignition_effect(atom/A, mob/user)
+ if(get_temperature())
+ . = span_infoplain(span_rose("With a single flick of [user.p_their()] wrist, [user] smoothly lights [A] with [src]. Damn [user.p_theyre()] cool."))
+
+/obj/item/lighter/proc/set_lit(new_lit)
+ if(lit == new_lit)
+ return
+
+ lit = new_lit
+ if(lit)
+ force = 5
+ damtype = BURN
+ hitsound = 'sound/items/welder.ogg'
+ attack_verb_continuous = string_list(list("burns", "singes"))
+ attack_verb_simple = string_list(list("burn", "singe"))
+ heat = heat_while_on
+ START_PROCESSING(SSobj, src)
+ if(fancy)
+ playsound(src.loc , 'sound/items/zippo_on.ogg', 100, 1)
+ else
+ playsound(src.loc, 'sound/items/lighter_on.ogg', 100, 1)
+ if(isliving(loc))
+ var/mob/living/male_model = loc
+ if(male_model.fire_stacks && !(male_model.on_fire))
+ male_model.ignite_mob()
+ else
+ hitsound = SFX_SWING_HIT
+ force = 0
+ heat = 0
+ attack_verb_continuous = null //human_defense.dm takes care of it
+ attack_verb_simple = null
+ STOP_PROCESSING(SSobj, src)
+ if(fancy)
+ playsound(src.loc , 'sound/items/zippo_off.ogg', 100, 1)
+ else
+ playsound(src.loc , 'sound/items/lighter_off.ogg', 100, 1)
+ set_light_on(lit)
+ update_appearance()
+
+/obj/item/lighter/extinguish()
+ . = ..()
+ set_lit(FALSE)
+
+/obj/item/lighter/attack_self(mob/living/user)
+ if(!user.is_holding(src))
+ return ..()
+ if(lit)
+ set_lit(FALSE)
+ if(fancy)
+ user.visible_message(
+ span_notice("You hear a quiet click, as [user] shuts off [src] without even looking at what [user.p_theyre()] doing. Wow."),
+ span_notice("You quietly shut off [src] without even looking at what you're doing. Wow.")
+ )
+ else
+ user.visible_message(
+ span_notice("[user] quietly shuts off [src]."),
+ span_notice("You quietly shut off [src].")
+ )
+ return
+
+ if(get_fuel() <= 0)
+ return
+
+ set_lit(TRUE)
+
+ if(fancy)
+ user.visible_message(
+ span_notice("Without even breaking stride, [user] flips open and lights [src] in one smooth movement."),
+ span_notice("Without even breaking stride, you flip open and light [src] in one smooth movement.")
+ )
+ return
+
+ var/hand_protected = FALSE
+ var/mob/living/carbon/human/human_user = user
+ if(!istype(human_user) || HAS_TRAIT(human_user, TRAIT_RESISTHEAT) || HAS_TRAIT(human_user, TRAIT_RESISTHEATHANDS))
+ hand_protected = TRUE
+ else if(!istype(human_user.gloves, /obj/item/clothing/gloves))
+ hand_protected = FALSE
+ else
+ var/obj/item/clothing/gloves/gloves = human_user.gloves
+ if(gloves.max_heat_protection_temperature)
+ hand_protected = (gloves.max_heat_protection_temperature > 360)
+
+ if(hand_protected || prob(75))
+ user.visible_message(
+ span_notice("After a few attempts, [user] manages to light [src]."),
+ span_notice("After a few attempts, you manage to light [src].")
+ )
+ return
+
+ var/hitzone = user.held_index_to_dir(user.active_hand_index) == "r" ? BODY_ZONE_PRECISE_R_HAND : BODY_ZONE_PRECISE_L_HAND
+ user.apply_damage(5, BURN, hitzone)
+ user.visible_message(
+ span_warning("After a few attempts, [user] manages to light [src] - however, [user.p_they()] burn[user.p_s()] [user.p_their()] finger in the process."),
+ span_warning("You burn yourself while lighting the lighter!")
+ )
+ user.add_mood_event("burnt_thumb", /datum/mood_event/burnt_thumb)
+
+/obj/item/lighter/attack(mob/living/target_mob, mob/living/user, params)
+ if(lit)
+ use(0.5)
+ if(target_mob.ignite_mob())
+ message_admins("[ADMIN_LOOKUPFLW(user)] set [key_name_admin(target_mob)] on fire with [src] at [AREACOORD(user)]")
+ log_game("[key_name(user)] set [key_name(target_mob)] on fire with [src] at [AREACOORD(user)]")
+ var/obj/item/cigarette/cig = help_light_cig(target_mob)
+ if(!lit || !cig || user.combat_mode)
+ return ..()
+
+ if(cig.lit)
+ to_chat(user, span_warning("The [cig.name] is already lit!"))
+ if(target_mob == user)
+ cig.attackby(src, user)
+ return
+
+ if(fancy)
+ cig.light(span_rose("[user] whips the [name] out and holds it for [target_mob]. [user.p_Their()] arm is as steady as the unflickering flame [user.p_they()] light[user.p_s()] \the [cig] with."))
+ else
+ cig.light(span_notice("[user] holds the [name] out for [target_mob], and lights [target_mob.p_their()] [cig.name]."))
+
+///Checks if the lighter is able to perform a welding task.
+/obj/item/lighter/tool_use_check(mob/living/user, amount, heat_required)
+ if(!lit)
+ to_chat(user, span_warning("[src] has to be on to complete this task!"))
+ return FALSE
+ if(get_fuel() < amount)
+ to_chat(user, span_warning("You need more welding fuel to complete this task!"))
+ return FALSE
+ if(heat < heat_required)
+ return FALSE
+ return TRUE
+
+/obj/item/lighter/process(seconds_per_tick)
+ if(lit)
+ burned_fuel_for += seconds_per_tick
+ if(burned_fuel_for >= TOOL_FUEL_BURN_INTERVAL)
+ use(used = 0.25)
+
+ open_flame(heat)
+
+/obj/item/lighter/get_temperature()
+ return lit * heat
+
+/// Uses fuel from the lighter.
+/obj/item/lighter/use(used = 0)
+ if(!lit)
+ return FALSE
+
+ if(used > 0)
+ burned_fuel_for = 0
+
+ if(get_fuel() >= used)
+ reagents.remove_reagent(/datum/reagent/fuel, used)
+ if(get_fuel() <= 0)
+ set_lit(FALSE)
+ return TRUE
+ return FALSE
+
+///Returns the amount of fuel
+/obj/item/lighter/proc/get_fuel()
+ return reagents.get_reagent_amount(/datum/reagent/fuel)
+
+/obj/item/lighter/greyscale
+ name = "cheap lighter"
+ desc = "A cheap lighter."
+ icon_state = "lighter"
+ maximum_fuel = 3
+ fancy = FALSE
+ overlay_list = list(
+ "transp",
+ "tall",
+ "matte",
+ "zoppo", //u cant stoppo th zoppo
+ )
+
+ /// The color of the lighter.
+ var/lighter_color
+ /// The set of colors this lighter can be autoset as on init.
+ var/static/list/color_list = list( //Same 16 color selection as electronic assemblies
+ COLOR_ASSEMBLY_BLACK,
+ COLOR_FLOORTILE_GRAY,
+ COLOR_ASSEMBLY_BGRAY,
+ COLOR_ASSEMBLY_WHITE,
+ COLOR_ASSEMBLY_RED,
+ COLOR_ASSEMBLY_ORANGE,
+ COLOR_ASSEMBLY_BEIGE,
+ COLOR_ASSEMBLY_BROWN,
+ COLOR_ASSEMBLY_GOLD,
+ COLOR_ASSEMBLY_YELLOW,
+ COLOR_ASSEMBLY_GURKHA,
+ COLOR_ASSEMBLY_LGREEN,
+ COLOR_ASSEMBLY_GREEN,
+ COLOR_ASSEMBLY_LBLUE,
+ COLOR_ASSEMBLY_BLUE,
+ COLOR_ASSEMBLY_PURPLE
+ )
+
+/obj/item/lighter/greyscale/Initialize(mapload)
+ . = ..()
+ if(!lighter_color)
+ lighter_color = pick(color_list)
+ update_appearance()
+
+/obj/item/lighter/greyscale/create_lighter_overlay()
+ var/mutable_appearance/lighter_overlay = ..()
+ lighter_overlay.color = lighter_color
+ return lighter_overlay
+
+/obj/item/lighter/greyscale/ignition_effect(atom/A, mob/user)
+ if(get_temperature())
+ . = span_notice("After some fiddling, [user] manages to light [A] with [src].")
+
+
+/obj/item/lighter/slime
+ name = "slime zippo"
+ desc = "A specialty zippo made from slimes and industry. Has a much hotter flame than normal."
+ icon_state = "slighter"
+ heat_while_on = parent_type::heat_while_on + 1000 //Blue flame is hotter, this means this does act as a welding tool.
+ light_color = LIGHT_COLOR_CYAN
+ overlay_state = "slime"
+ grind_results = list(/datum/reagent/iron = 1, /datum/reagent/fuel = 5, /datum/reagent/medicine/pyroxadone = 5)
+
+/obj/item/lighter/skull
+ name = "badass zippo"
+ desc = "An absolutely badass zippo lighter. Just look at that skull!"
+ overlay_state = "skull"
+
+/obj/item/lighter/mime
+ name = "pale zippo"
+ desc = "In lieu of fuel, performative spirit can be used to light cigarettes."
+ icon_state = "mlighter" //These ones don't show a flame.
+ light_color = LIGHT_COLOR_HALOGEN
+ heat_while_on = 0 //I swear it's a real lighter dude you just can't see the flame dude I promise
+ overlay_state = "mime"
+ grind_results = list(/datum/reagent/iron = 1, /datum/reagent/toxin/mutetoxin = 5, /datum/reagent/consumable/nothing = 10)
+ light_range = 0
+ light_power = 0
+ fancy = FALSE
+
+/obj/item/lighter/mime/ignition_effect(atom/A, mob/user)
+ . = span_infoplain("[user] lifts the [name] to the [A], which miraculously lights!")
+
+/obj/item/lighter/bright
+ name = "illuminative zippo"
+ desc = "Sustains an incredibly bright chemical reaction when you spark it. Avoid looking directly at the igniter when lit."
+ icon_state = "slighter"
+ light_color = LIGHT_COLOR_ELECTRIC_CYAN
+ overlay_state = "bright"
+ grind_results = list(/datum/reagent/iron = 1, /datum/reagent/flash_powder = 10)
+ light_range = 8
+ light_power = 3 //Irritatingly bright and large enough to cover a small room.
+ fancy = FALSE
+
+/obj/item/lighter/bright/examine(mob/user)
+ . = ..()
+
+ if(lit && isliving(user))
+ var/mob/living/current_viewer = user
+ current_viewer.flash_act(4)
+
+/obj/item/lighter/bright/ignition_effect(atom/A, mob/user)
+ if(get_temperature())
+ . = span_infoplain(span_rose("[user] lifts the [src] to the [A], igniting it with a brilliant flash of light!"))
+ var/mob/living/current_viewer = user
+ current_viewer.flash_act(4)
+
+/obj/effect/spawner/random/special_lighter
+ name = "special lighter spawner"
+ icon_state = "lighter"
+ loot = list(
+ /obj/item/lighter/skull,
+ /obj/item/lighter/mime,
+ /obj/item/lighter/bright,
+ )
diff --git a/code/game/objects/items/machine_wand.dm b/code/game/objects/items/machine_wand.dm
index 75c765730f78b..7d8b4a0697d67 100644
--- a/code/game/objects/items/machine_wand.dm
+++ b/code/game/objects/items/machine_wand.dm
@@ -85,10 +85,12 @@
remove_old_machine()
return CLICK_ACTION_SUCCESS
-/obj/item/machine_remote/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
- return interact_with_atom(interacting_with, user, modifiers)
-
/obj/item/machine_remote/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
+ if(HAS_TRAIT(interacting_with, TRAIT_COMBAT_MODE_SKIP_INTERACTION) || (!ismachinery(interacting_with) && !isbot(interacting_with)))
+ return NONE
+ return ranged_interact_with_atom(interacting_with, user, modifiers)
+
+/obj/item/machine_remote/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(!COOLDOWN_FINISHED(src, timeout_time))
playsound(src, 'sound/machines/synth_no.ogg', 30 , TRUE)
say("Remote control disabled temporarily. Please try again soon.")
diff --git a/code/game/objects/items/mail.dm b/code/game/objects/items/mail.dm
index 2aec478162445..26cefd6eeedbd 100644
--- a/code/game/objects/items/mail.dm
+++ b/code/game/objects/items/mail.dm
@@ -548,10 +548,10 @@
shady_mail.made_by_cached_name = user.mind.name
if(index == 1)
- var/mail_name = tgui_input_text(user, "Enter mail title, or leave it blank", "Mail Counterfeiting")
+ var/mail_name = tgui_input_text(user, "Enter mail title, or leave it blank", "Mail Counterfeiting", max_length = MAX_LABEL_LEN)
if(!(src in user.contents))
return FALSE
- if(reject_bad_text(mail_name, ascii_only = FALSE))
+ if(reject_bad_text(mail_name, max_length = MAX_LABEL_LEN, ascii_only = FALSE))
shady_mail.name = mail_name
else
shady_mail.name = mail_type
diff --git a/code/game/objects/items/melee/baton.dm b/code/game/objects/items/melee/baton.dm
index 8c1ae33c4c70e..0fd63321519c0 100644
--- a/code/game/objects/items/melee/baton.dm
+++ b/code/game/objects/items/melee/baton.dm
@@ -479,7 +479,6 @@
else
cell = new preload_cell_type(src)
RegisterSignal(src, COMSIG_ATOM_ATTACKBY, PROC_REF(convert))
- RegisterSignal(src, COMSIG_HIT_BY_SABOTEUR, PROC_REF(on_saboteur))
update_appearance()
/obj/item/melee/baton/security/get_cell()
@@ -514,13 +513,14 @@
qdel(item)
qdel(src)
-/obj/item/melee/baton/security/proc/on_saboteur(datum/source, disrupt_duration)
- SIGNAL_HANDLER
+/obj/item/melee/baton/security/on_saboteur(datum/source, disrupt_duration)
+ . = ..()
if(!active)
return
turn_off()
update_appearance()
- return COMSIG_SABOTEUR_SUCCESS
+ return TRUE
+
/obj/item/melee/baton/security/Exited(atom/movable/mov_content)
. = ..()
if(mov_content == cell)
diff --git a/code/game/objects/items/rcd/RCD.dm b/code/game/objects/items/rcd/RCD.dm
index 5bd0b4c9d39b8..279bc91d622c5 100644
--- a/code/game/objects/items/rcd/RCD.dm
+++ b/code/game/objects/items/rcd/RCD.dm
@@ -126,7 +126,7 @@
var/atom/movable/rcd_structure = rcd_results["[RCD_DESIGN_PATH]"]
/**
*For anything that does not go an a wall we have to make sure that turf is clear for us to put the structure on it
- *If we are just trying to destory something then this check is not nessassary
+ *If we are just trying to destroy something then this check is not necessary
*RCD_WALLFRAME is also returned as the rcd_mode when upgrading apc, airalarm, firealarm using simple circuits upgrade
*/
if(rcd_mode != RCD_WALLFRAME && rcd_mode != RCD_DECONSTRUCT)
@@ -142,7 +142,7 @@
structures_to_ignore = list(/obj/structure/grille)
else //when building directional windows we ignore the grill and other directional windows
structures_to_ignore = list(/obj/structure/grille, /obj/structure/window)
- else //for directional windows we ignore other directional windows as they can be in diffrent directions on the turf.
+ else //for directional windows we ignore other directional windows as they can be in different directions on the turf.
structures_to_ignore = list(/obj/structure/window)
//check if we can build our window on the grill
@@ -152,7 +152,7 @@
return FALSE
/**
- * if we are trying to create plating on turf which is not a proper floor then dont check for objects on top of the turf just allow that turf to be converted into plating. e.g. create plating beneath a player or underneath a machine frame/any dense object
+ * if we are trying to create plating on turf which is not a proper floor then don't check for objects on top of the turf just allow that turf to be converted into plating. e.g. create plating beneath a player or underneath a machine frame/any dense object
* if we are trying to finish a wall girder then let it finish then make sure no one/nothing is stuck in the girder
*/
else if(rcd_mode == RCD_TURF && rcd_structure == /turf/open/floor/plating/rcd && (!istype(target_turf, /turf/open/floor) || istype(target, /obj/structure/girder)))
@@ -184,10 +184,10 @@
ignored_types = list(/obj/structure/window)
//if we are trying to create grills/windoors we can go ahead and further ignore other windoors on the turf
if(rcd_mode == RCD_WINDOWGRILLE || (rcd_mode == RCD_AIRLOCK && ispath(rcd_structure, /obj/machinery/door/window)))
- //only ignore mobs if we are trying to create windoors and not grills. We dont want to drop a grill on top of somebody
+ //only ignore mobs if we are trying to create windoors and not grills. We don't want to drop a grill on top of somebody
ignore_mobs = rcd_mode == RCD_AIRLOCK
ignored_types += /obj/machinery/door/window
- //if we are trying to create full airlock doors then we do the regular checks and make sure we have the full space for them. i.e. dont ignore anything dense on the turf
+ //if we are trying to create full airlock doors then we do the regular checks and make sure we have the full space for them. i.e. don't ignore anything dense on the turf
else if(rcd_mode == RCD_AIRLOCK)
ignored_types = list()
@@ -207,15 +207,15 @@
* * [mob][user]- the user building this structure
*/
/obj/item/construction/rcd/proc/rcd_create(atom/target, mob/user)
- //straight up cant touch this
+ var/list/rcd_results = target.rcd_vals(user, src) // does this atom allow for rcd actions?
+ if(!rcd_results) // nope
+ return NONE
+
+ //straight up can't touch this
if(mode == RCD_DECONSTRUCT && (target.resistance_flags & INDESTRUCTIBLE))
balloon_alert(user, "too durable!")
- return
+ return ITEM_INTERACT_BLOCKING
- //does this atom allow for rcd actions?
- var/list/rcd_results = target.rcd_vals(user, src)
- if(!rcd_results)
- return FALSE
rcd_results["[RCD_DESIGN_MODE]"] = mode
rcd_results["[RCD_DESIGN_PATH]"] = rcd_design_path
@@ -237,6 +237,7 @@
log_tool("[key_name(user)] used [src] to [rcd_results["[RCD_DESIGN_MODE]"] != RCD_DECONSTRUCT ? "construct [initial(design_path.name)]([design_path])" : "deconstruct [target_name]([target_path])"] at [location]")
current_active_effects -= 1
+ return ITEM_INTERACT_SUCCESS
/**
* Internal proc which creates the rcd effects & creates the structure
@@ -368,10 +369,10 @@
* The advantage of organizing designs into categories is that
* You can ignore an complete category if the design disk upgrade for that category isn't installed.
*/
- //You can't select designs from the Machines category if you dont have the frames upgrade installed.
+ //You can't select designs from the Machines category if you don't have the frames upgrade installed.
if(category == "Machines" && !(upgrade & RCD_UPGRADE_FRAMES))
return TRUE
- //You can't select designs from the Furniture category if you dont have the furnishing upgrade installed.
+ //You can't select designs from the Furniture category if you don't have the furnishing upgrade installed.
if(category == "Furniture" && !(upgrade & RCD_UPGRADE_FURNISHING))
return TRUE
@@ -401,29 +402,25 @@
return .
mode = construction_mode
- rcd_create(interacting_with, user)
- return ITEM_INTERACT_SUCCESS
+ return rcd_create(interacting_with, user)
/obj/item/construction/rcd/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(!ranged || !range_check(interacting_with, user))
return ITEM_INTERACT_BLOCKING
mode = construction_mode
- rcd_create(interacting_with, user)
- return ITEM_INTERACT_SUCCESS
+ return rcd_create(interacting_with, user)
/obj/item/construction/rcd/interact_with_atom_secondary(atom/interacting_with, mob/living/user, list/modifiers)
mode = RCD_DECONSTRUCT
- rcd_create(interacting_with, user)
- return ITEM_INTERACT_SUCCESS
+ return rcd_create(interacting_with, user)
/obj/item/construction/rcd/ranged_interact_with_atom_secondary(atom/interacting_with, mob/living/user, list/modifiers)
if(!ranged || !range_check(interacting_with, user))
return ITEM_INTERACT_BLOCKING
mode = RCD_DECONSTRUCT
- rcd_create(interacting_with, user)
- return ITEM_INTERACT_SUCCESS
+ return rcd_create(interacting_with, user)
/obj/item/construction/rcd/handle_openspace_click(turf/target, mob/user, list/modifiers)
interact_with_atom(target, user, modifiers)
diff --git a/code/game/objects/items/rcd/RHD.dm b/code/game/objects/items/rcd/RHD.dm
index a212274ce46be..8007fac4dd4c7 100644
--- a/code/game/objects/items/rcd/RHD.dm
+++ b/code/game/objects/items/rcd/RHD.dm
@@ -71,7 +71,7 @@
return silo_mats.mat_container.get_material_amount(/datum/material/iron) / SILO_USE_AMOUNT
return 0
-///returns local matter units available. overriden by rcd borg to return power units available
+///returns local matter units available. overridden by rcd borg to return power units available
/obj/item/construction/proc/get_matter(mob/user)
return matter
diff --git a/code/game/objects/items/religion.dm b/code/game/objects/items/religion.dm
index 232de4c461930..77b087b8ac53d 100644
--- a/code/game/objects/items/religion.dm
+++ b/code/game/objects/items/religion.dm
@@ -343,10 +343,12 @@
var/staffcooldown = 0
var/staffwait = 30
-/obj/item/godstaff/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
- return interact_with_atom(interacting_with, user, modifiers)
-
/obj/item/godstaff/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
+ if(SHOULD_SKIP_INTERACTION(interacting_with, src, user))
+ return NONE
+ return ranged_interact_with_atom(interacting_with, user, modifiers)
+
+/obj/item/godstaff/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(staffcooldown + staffwait > world.time)
return ITEM_INTERACT_BLOCKING
diff --git a/code/game/objects/items/robot/ai_upgrades.dm b/code/game/objects/items/robot/ai_upgrades.dm
index f6357b229efb9..b630a3b8a4231 100644
--- a/code/game/objects/items/robot/ai_upgrades.dm
+++ b/code/game/objects/items/robot/ai_upgrades.dm
@@ -1,4 +1,45 @@
///AI Upgrades
+/obj/item/aiupgrade
+ name = "ai upgrade disk"
+ desc = "You really shouldn't be seeing this"
+ icon = 'icons/obj/devices/circuitry_n_data.dmi'
+ icon_state = "datadisk3"
+ ///The upgrade that will be applied to the AI when installed
+ var/datum/ai_module/to_gift = /datum/ai_module
+
+/obj/item/aiupgrade/pre_attack(atom/target, mob/living/user, proximity)
+ if(!proximity)
+ return ..()
+ if(!isAI(target))
+ return ..()
+ var/mob/living/silicon/ai/AI = target
+ var/datum/action/innate/ai/action = locate(to_gift.power_type) in AI.actions
+ var/datum/ai_module/gifted_ability = new to_gift
+ if(!to_gift.upgrade)
+ if(!action)
+ var/ability = to_gift.power_type
+ var/datum/action/gifted_action = new ability
+ gifted_action.Grant(AI)
+ else if(gifted_ability.one_purchase)
+ to_chat(user, "[AI] already has an [src] installed!")
+ return
+ else
+ action.uses += initial(action.uses)
+ action.desc = "[initial(action.desc)] It has [action.uses] use\s remaining."
+ action.build_all_button_icons()
+ else
+ if(!action)
+ gifted_ability.upgrade(AI)
+ if(gifted_ability.unlock_text)
+ to_chat(AI, gifted_ability.unlock_text)
+ if(gifted_ability.unlock_sound)
+ AI.playsound_local(AI, gifted_ability.unlock_sound, 50, 0)
+ update_static_data(AI)
+ to_chat(user, span_notice("You install [src], upgrading [AI]."))
+ to_chat(AI, span_userdanger("[user] has upgraded you with [src]!"))
+ user.log_message("has upgraded [key_name(AI)] with a [src].", LOG_GAME)
+ qdel(src)
+ return TRUE
//Malf Picker
@@ -34,28 +75,21 @@
//Lipreading
-/obj/item/surveillance_upgrade
+/obj/item/aiupgrade/surveillance_upgrade
name = "surveillance software upgrade"
desc = "An illegal software package that will allow an artificial intelligence to 'hear' from its cameras via lip reading and hidden microphones."
- icon = 'icons/obj/devices/circuitry_n_data.dmi'
- icon_state = "datadisk3"
+ to_gift = /datum/ai_module/malf/upgrade/eavesdrop
-/obj/item/surveillance_upgrade/Initialize(mapload)
+/obj/item/aiupgrade/surveillance_upgrade/Initialize(mapload)
. = ..()
ADD_TRAIT(src, TRAIT_CONTRABAND, INNATE_TRAIT)
-/obj/item/surveillance_upgrade/pre_attack(atom/A, mob/living/user, proximity)
- if(!proximity)
- return ..()
- if(!isAI(A))
- return ..()
- var/mob/living/silicon/ai/AI = A
- if(AI.eyeobj)
- AI.eyeobj.relay_speech = TRUE
- to_chat(AI, span_userdanger("[user] has upgraded you with surveillance software!"))
- to_chat(AI, "Via a combination of hidden microphones and lip reading software, you are able to use your cameras to listen in on conversations.")
- to_chat(user, span_notice("You upgrade [AI]. [src] is consumed in the process."))
- user.log_message("has upgraded [key_name(AI)] with a [src].", LOG_GAME)
- message_admins("[ADMIN_LOOKUPFLW(user)] has upgraded [ADMIN_LOOKUPFLW(AI)] with a [src].")
- qdel(src)
- return TRUE
+
+/obj/item/aiupgrade/power_transfer
+ name = "power transfer upgrade"
+ desc = "A legal upgrade that allows an artificial intelligence to directly provide power to APCs from a distance"
+ to_gift = /datum/ai_module/power_apc
+
+
+
+
diff --git a/code/game/objects/items/spear.dm b/code/game/objects/items/spear.dm
index 53e307e31d6e0..f0548fa66f404 100644
--- a/code/game/objects/items/spear.dm
+++ b/code/game/objects/items/spear.dm
@@ -177,10 +177,8 @@
return
if(target.resistance_flags & INDESTRUCTIBLE) //due to the lich incident of 2021, embedding grenades inside of indestructible structures is forbidden
return
- if(ismob(target))
- var/mob/mob_target = target
- if(mob_target.status_flags & GODMODE) //no embedding grenade phylacteries inside of ghost poly either
- return
+ if(HAS_TRAIT(target, TRAIT_GODMODE))
+ return
if(iseffect(target)) //and no accidentally wasting your moment of glory on graffiti
return
user.say("[war_cry]", forced="spear warcry")
diff --git a/code/game/objects/items/stacks/sheets/sheets.dm b/code/game/objects/items/stacks/sheets/sheets.dm
index 568fd2f49aa29..110713d343612 100644
--- a/code/game/objects/items/stacks/sheets/sheets.dm
+++ b/code/game/objects/items/stacks/sheets/sheets.dm
@@ -63,7 +63,7 @@
* Facilitates sheets being smacked on the floor
*
* This is used for crafting by hitting the floor with items.
- * The inital use case is glass sheets breaking in to shards when the floor is hit.
+ * The initial use case is glass sheets breaking in to shards when the floor is hit.
* Args:
* * user: The user that did the action
* * params: paramas passed in from attackby
diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm
index 5eb651b2905d4..e2a8e10c4df49 100644
--- a/code/game/objects/items/stacks/stack.dm
+++ b/code/game/objects/items/stacks/stack.dm
@@ -177,7 +177,7 @@
/**
* use available_amount of sheets/pieces, return TRUE only if all sheets/pieces of this stack were used
* we don't delete this stack when it reaches 0 because we expect the all in one grinder, etc to delete
- * this stack if grinding was successfull
+ * this stack if grinding was successful
*/
use(available_amount, check = FALSE)
return available_amount == current_amount
@@ -546,7 +546,7 @@
update_weight()
return TRUE
-/obj/item/stack/tool_use_check(mob/living/user, amount)
+/obj/item/stack/tool_use_check(mob/living/user, amount, heat_required)
if(get_amount() < amount)
// general balloon alert that says they don't have enough
user.balloon_alert(user, "not enough material!")
diff --git a/code/game/objects/items/stacks/tiles/tile_types.dm b/code/game/objects/items/stacks/tiles/tile_types.dm
index 4b89719998c8f..b4855c52fae35 100644
--- a/code/game/objects/items/stacks/tiles/tile_types.dm
+++ b/code/game/objects/items/stacks/tiles/tile_types.dm
@@ -68,7 +68,7 @@
* Place our tile on a plating, or replace it.
*
* Arguments:
- * * target_plating - Instance of the plating we want to place on. Replaced during sucessful executions.
+ * * target_plating - Instance of the plating we want to place on. Replaced during successful executions.
* * user - The mob doing the placing.
*/
/obj/item/stack/tile/proc/place_tile(turf/open/floor/plating/target_plating, mob/user)
@@ -1259,7 +1259,7 @@
inhand_icon_state = "tile-catwalk"
mats_per_unit = list(/datum/material/iron=SMALL_MATERIAL_AMOUNT)
turf_type = /turf/open/floor/catwalk_floor
- merge_type = /obj/item/stack/tile/catwalk_tile //Just to be cleaner, these all stack with eachother
+ merge_type = /obj/item/stack/tile/catwalk_tile //Just to be cleaner, these all stack with each other
tile_reskin_types = list(
/obj/item/stack/tile/catwalk_tile,
/obj/item/stack/tile/catwalk_tile/iron,
diff --git a/code/game/objects/items/stacks/wrap.dm b/code/game/objects/items/stacks/wrap.dm
index d7fcd17f2950d..d1cbb7f1ce8a3 100644
--- a/code/game/objects/items/stacks/wrap.dm
+++ b/code/game/objects/items/stacks/wrap.dm
@@ -102,13 +102,6 @@
/obj/item/delivery/can_be_package_wrapped()
return FALSE
-/obj/item/stack/package_wrap/storage_insert_on_interaction(datum/storage, atom/storage_holder, mob/user)
- if(isitem(storage_holder))
- // Don't insert if the target can be wrapped
- var/obj/item/item = storage_holder
- return !item.can_be_package_wrapped()
- return TRUE
-
/obj/item/stack/package_wrap/interact_with_atom(obj/interacting_with, mob/living/user, list/modifiers)
if(!isobj(interacting_with))
return NONE
@@ -118,6 +111,8 @@
if(isitem(interacting_with))
var/obj/item/item = interacting_with
if(!item.can_be_package_wrapped())
+ if(SHOULD_SKIP_INTERACTION(interacting_with, src, user))
+ return NONE // put it in the bag instead of yelling
balloon_alert(user, "can't be wrapped!")
return ITEM_INTERACT_BLOCKING
if(user.is_holding(item))
diff --git a/code/game/objects/items/stickers.dm b/code/game/objects/items/stickers.dm
index 447e202247367..9924749379573 100644
--- a/code/game/objects/items/stickers.dm
+++ b/code/game/objects/items/stickers.dm
@@ -25,7 +25,7 @@
throw_range = 3
pressure_resistance = 0
- item_flags = NOBLUDGEON | XENOMORPH_HOLDABLE //funny ~Jimmyl
+ item_flags = NOBLUDGEON
w_class = WEIGHT_CLASS_TINY
/// `list` or `null`, contains possible alternate `icon_states`.
diff --git a/code/game/objects/items/storage/bags.dm b/code/game/objects/items/storage/bags.dm
index 269a6699d3e1c..095250fdcca52 100644
--- a/code/game/objects/items/storage/bags.dm
+++ b/code/game/objects/items/storage/bags.dm
@@ -155,13 +155,13 @@
UnregisterSignal(listeningTo, COMSIG_MOVABLE_MOVED)
listeningTo = null
-/obj/item/storage/bag/ore/storage_insert_on_interacted_with(datum/storage, obj/item/inserted, mob/living/user)
- if(istype(inserted, /obj/item/boulder))
- to_chat(user, span_warning("You can't fit [inserted] into [src]. \
+/obj/item/storage/bag/ore/item_interaction(mob/living/user, obj/item/tool, list/modifiers)
+ if(istype(tool, /obj/item/boulder))
+ to_chat(user, span_warning("You can't fit [tool] into [src]. \
Perhaps you should break it down first, or find an ore box."))
- return FALSE
+ return ITEM_INTERACT_BLOCKING
- return TRUE
+ return NONE
/obj/item/storage/bag/ore/proc/pickup_ores(mob/living/user)
SIGNAL_HANDLER
@@ -274,8 +274,6 @@
. += span_notice("Ctrl-click to activate seed extraction.")
/obj/item/storage/bag/plants/portaseeder/item_ctrl_click(mob/user)
- if(user.incapacitated)
- return
for(var/obj/item/plant in contents)
seedify(plant, 1)
return CLICK_ACTION_SUCCESS
@@ -577,7 +575,7 @@
new /obj/item/ammo_casing/harpoon(src)
/obj/item/storage/bag/rebar_quiver
- name = "Rebar Storage Quiver"
+ name = "rebar quiver"
icon = 'icons/obj/weapons/bows/quivers.dmi'
icon_state = "rebar_quiver"
worn_icon_state = "rebar_quiver"
@@ -607,7 +605,7 @@
desc = "A specialized quiver meant to hold any kind of bolts intended for use with the rebar crossbow. \
Clearly a better design than a cut up oxygen tank..."
slot_flags = ITEM_SLOT_NECK
- w_class = WEIGHT_CLASS_SMALL
+ w_class = WEIGHT_CLASS_NORMAL
resistance_flags = LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
actions_types = list(/datum/action/item_action/reload_rebar)
@@ -649,7 +647,7 @@
if(held_crossbow.magazine.contents.len >= held_crossbow.magazine.max_ammo)
user.balloon_alert(user, "no more room!")
return
- if(!do_after(user, 0.8 SECONDS, user, IGNORE_USER_LOC_CHANGE))
+ if(!do_after(user, 1.2 SECONDS, user))
return
var/obj/item/ammo_casing/rebar/ammo_to_load = contents[1]
diff --git a/code/game/objects/items/storage/belt.dm b/code/game/objects/items/storage/belt.dm
index 5386718d94718..40d35a334d08f 100644
--- a/code/game/objects/items/storage/belt.dm
+++ b/code/game/objects/items/storage/belt.dm
@@ -515,6 +515,7 @@
. = ..()
atom_storage.max_slots = 1
atom_storage.set_holdable(/obj/item/clothing/mask/luchador)
+ AddComponent(/datum/component/adjust_fishing_difficulty, -2)
/obj/item/storage/belt/military
name = "chest rig"
diff --git a/code/game/objects/items/storage/boxes/food_boxes.dm b/code/game/objects/items/storage/boxes/food_boxes.dm
index 86d59123c72aa..bac558ce3be78 100644
--- a/code/game/objects/items/storage/boxes/food_boxes.dm
+++ b/code/game/objects/items/storage/boxes/food_boxes.dm
@@ -301,7 +301,7 @@
new /obj/item/food/fishmeat/armorfish(src)
new /obj/item/food/fishmeat/carp(src)
new /obj/item/food/fishmeat/moonfish(src)
- new /obj/item/food/fishmeat/gunner_jellyfish(src)
+ new /obj/item/food/fishmeat/gunner_jellyfish/supply(src)
/obj/item/storage/box/ingredients/salads
theme_name = "salads"
diff --git a/code/game/objects/items/storage/medkit.dm b/code/game/objects/items/storage/medkit.dm
index 368ef9c0b406a..e5db3d75855ea 100644
--- a/code/game/objects/items/storage/medkit.dm
+++ b/code/game/objects/items/storage/medkit.dm
@@ -818,3 +818,8 @@
/obj/item/storage/test_tube_rack/update_icon_state()
icon_state = "[base_icon_state][contents.len > 0 ? contents.len : null]"
return ..()
+
+/obj/item/storage/test_tube_rack/full/PopulateContents()
+ for(var/i in 1 to atom_storage.max_slots)
+ new /obj/item/reagent_containers/cup/tube(src)
+
diff --git a/code/game/objects/items/storage/toolbox.dm b/code/game/objects/items/storage/toolbox.dm
index d2bb90e69e445..873b45210cdec 100644
--- a/code/game/objects/items/storage/toolbox.dm
+++ b/code/game/objects/items/storage/toolbox.dm
@@ -410,6 +410,7 @@
desc = "A bandana. It seems to have a little carp embroidered on the inside, as well as the kanji '魚'."
icon_state = "snake_eater"
inhand_icon_state = null
+ clothing_traits = list(TRAIT_FISH_EATER)
/obj/item/clothing/head/costume/knight
name = "fake medieval helmet"
diff --git a/code/game/objects/items/taster.dm b/code/game/objects/items/taster.dm
index 599b78971db11..cdd67ceae5654 100644
--- a/code/game/objects/items/taster.dm
+++ b/code/game/objects/items/taster.dm
@@ -16,4 +16,4 @@
else
var/message = interacting_with.reagents.generate_taste_message(user, taste_sensitivity)
to_chat(user, span_notice("[src] tastes [message] in [interacting_with]."))
- return ITEM_INTERACT_SUCCESS
+ return user.combat_mode ? NONE : ITEM_INTERACT_SUCCESS
diff --git a/code/game/objects/items/tcg/tcg.dm b/code/game/objects/items/tcg/tcg.dm
index 23204b4809ff8..30650fcd69f7e 100644
--- a/code/game/objects/items/tcg/tcg.dm
+++ b/code/game/objects/items/tcg/tcg.dm
@@ -3,7 +3,7 @@
/obj/item/tcgcard
name = "Coder"
- desc = "Wow, a mint condition coder card! Better tell the Github all about this!"
+ desc = "Wow, a mint condition coder card! Better tell the GitHub all about this!"
icon = DEFAULT_TCG_DMI_ICON
icon_state = "runtime"
w_class = WEIGHT_CLASS_TINY
@@ -332,11 +332,11 @@ GLOBAL_LIST_EMPTY(tcgcard_radial_choices)
/obj/item/cardpack
name = "Trading Card Pack: Coder"
- desc = "Contains six complete fuckups by the coders. Report this on github please!"
+ desc = "Contains six complete fuckups by the coders. Report this on GitHub please!"
icon = 'icons/obj/toys/tcgmisc.dmi'
icon_state = "error"
w_class = WEIGHT_CLASS_TINY
- custom_price = PAYCHECK_CREW * 0.75 //Price reduced from * 2 to * 0.75, this is planned as a temporary measure until card persistance is added.
+ custom_price = PAYCHECK_CREW * 0.75 //Price reduced from * 2 to * 0.75, this is planned as a temporary measure until card persistence is added.
///The card series to look in
var/series = "MEME"
///Chance of the pack having a coin in it out of 10
@@ -351,7 +351,7 @@ GLOBAL_LIST_EMPTY(tcgcard_radial_choices)
"epic" = 30,
"legendary" = 5,
"misprint" = 1)
- ///The amount of cards to draw from the guarenteed rarity table
+ ///The amount of cards to draw from the guaranteed rarity table
var/guaranteed_count = 1
///The guaranteed rarity table, acts about the same as the rarity table. it can have as many or as few raritys as you'd like
var/list/guar_rarity = list(
@@ -434,7 +434,7 @@ GLOBAL_LIST_EMPTY(tcgcard_radial_choices)
atom_storage.max_total_storage = 120
atom_storage.max_slots = 60
-///Returns a list of cards ids of card_cnt weighted by rarity from the pack's tables that have matching series, with gnt_cnt of the guarenteed table.
+///Returns a list of cards ids of card_cnt weighted by rarity from the pack's tables that have matching series, with gnt_cnt of the guaranteed table.
/obj/item/cardpack/proc/buildCardListWithRarity(card_cnt, rarity_cnt)
var/list/toReturn = list()
//You can always get at least one of some rarity
@@ -453,7 +453,7 @@ GLOBAL_LIST_EMPTY(tcgcard_radial_choices)
weight += rarity_table[chance]
var/random = rand(weight)
for(var/bracket in rarity_table)
- //Steals blatently from pick_weight(), sorry buddy I need the index
+ //Steals blatantly from pick_weight(), sorry buddy I need the index
random -= rarity_table[bracket]
if(random <= 0)
rarity = bracket
@@ -469,12 +469,12 @@ GLOBAL_LIST_EMPTY(tcgcard_radial_choices)
log_runtime("The index [rarity] of rarity_table does not exist in the global cache")
return toReturn
-//All of these values should be overriden by either a template or a card itself
+//All of these values should be overridden by either a template or a card itself
/datum/card
///Unique ID, for use in lookups and (eventually) for persistence. MAKE SURE THIS IS UNIQUE FOR EACH CARD IN AS SERIES, OR THE ENTIRE SYSTEM WILL BREAK, AND I WILL BE VERY DISAPPOINTED.
var/id = "coder"
var/name = "Coder"
- var/desc = "Wow, a mint condition coder card! Better tell the Github all about this!"
+ var/desc = "Wow, a mint condition coder card! Better tell the GitHub all about this!"
///This handles any extra rules for the card, i.e. extra attributes, special effects, etc. If you've played any other card game, you know how this works.
var/rules = "There are no rules here. There is no escape. No Recall or Intervention can work in this place."
var/icon = DEFAULT_TCG_DMI
diff --git a/code/game/objects/items/tcg/tcg_machines.dm b/code/game/objects/items/tcg/tcg_machines.dm
index 77b6891e4c17a..7a55e2e9554f7 100644
--- a/code/game/objects/items/tcg/tcg_machines.dm
+++ b/code/game/objects/items/tcg/tcg_machines.dm
@@ -90,7 +90,7 @@ GLOBAL_LIST_EMPTY(tcgcard_machine_radial_choices)
/obj/machinery/trading_card_holder/attack_hand_secondary(mob/user)
if(isnull(current_summon))
- var/card_name = tgui_input_text(user, "Insert card name", "Blank Card Naming", "blank card", MAX_NAME_LEN)
+ var/card_name = tgui_input_text(user, "Insert card name", "Blank Card Naming", "blank card", max_length = MAX_NAME_LEN)
if(isnull(card_name) || !user.can_perform_action(src))
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
current_summon = new /obj/structure/trading_card_summon/blank(locate(x + summon_offset_x, y + summon_offset_y, z))
diff --git a/code/game/objects/items/theft_tools.dm b/code/game/objects/items/theft_tools.dm
index e13251fe8e5ea..d51130a4d21d2 100644
--- a/code/game/objects/items/theft_tools.dm
+++ b/code/game/objects/items/theft_tools.dm
@@ -187,7 +187,7 @@
if(!isliving(hit_atom))
return ..()
var/mob/living/victim = hit_atom
- if(victim.incorporeal_move || victim.status_flags & GODMODE) //try to keep this in sync with supermatter's consume fail conditions
+ if(victim.incorporeal_move || HAS_TRAIT(victim, TRAIT_GODMODE)) //try to keep this in sync with supermatter's consume fail conditions
return ..()
var/mob/thrower = throwingdatum?.get_thrower()
if(thrower)
@@ -208,7 +208,7 @@
/obj/item/nuke_core/supermatter_sliver/pickup(mob/living/user)
..()
- if(!isliving(user) || user.status_flags & GODMODE) //try to keep this in sync with supermatter's consume fail conditions
+ if(!isliving(user) || HAS_TRAIT(user, TRAIT_GODMODE)) //try to keep this in sync with supermatter's consume fail conditions
return FALSE
user.visible_message(span_danger("[user] reaches out and tries to pick up [src]. [user.p_their()] body starts to glow and bursts into flames before flashing into dust!"),\
span_userdanger("You reach for [src] with your hands. That was dumb."),\
@@ -311,7 +311,7 @@
if(!isliving(AM))
return
var/mob/living/victim = AM
- if(victim.incorporeal_move || victim.status_flags & GODMODE) //try to keep this in sync with supermatter's consume fail conditions
+ if(victim.incorporeal_move || HAS_TRAIT(victim, TRAIT_GODMODE)) //try to keep this in sync with supermatter's consume fail conditions
return
victim.investigate_log("has been dusted by [src].", INVESTIGATE_DEATHS)
victim.dust()
diff --git a/code/game/objects/items/tools/weldingtool.dm b/code/game/objects/items/tools/weldingtool.dm
index 143b8eab174e6..dfc406437201b 100644
--- a/code/game/objects/items/tools/weldingtool.dm
+++ b/code/game/objects/items/tools/weldingtool.dm
@@ -1,5 +1,3 @@
-/// How many seconds between each fuel depletion tick ("use" proc)
-#define WELDER_FUEL_BURN_INTERVAL 5
/obj/item/weldingtool
name = "welding tool"
desc = "A standard edition welder provided by Nanotrasen."
@@ -89,7 +87,7 @@
force = 15
damtype = BURN
burned_fuel_for += seconds_per_tick
- if(burned_fuel_for >= WELDER_FUEL_BURN_INTERVAL)
+ if(burned_fuel_for >= TOOL_FUEL_BURN_INTERVAL)
use(TRUE)
update_appearance()
@@ -276,16 +274,17 @@
return welding
/// If welding tool ran out of fuel during a construction task, construction fails.
-/obj/item/weldingtool/tool_use_check(mob/living/user, amount)
+/obj/item/weldingtool/tool_use_check(mob/living/user, amount, heat_required)
if(!isOn() || !check_fuel())
to_chat(user, span_warning("[src] has to be on to complete this task!"))
return FALSE
-
- if(get_fuel() >= amount)
- return TRUE
- else
+ if(get_fuel() < amount)
to_chat(user, span_warning("You need more welding fuel to complete this task!"))
return FALSE
+ if(heat < heat_required)
+ to_chat(user, span_warning("[src] is not hot enough to complete this task!"))
+ return FALSE
+ return TRUE
/// Ran when the welder is attacked by a screwdriver.
/obj/item/weldingtool/proc/flamethrower_screwdriver(obj/item/tool, mob/user)
@@ -410,5 +409,3 @@
if(get_fuel() < max_fuel && nextrefueltick < world.time)
nextrefueltick = world.time + 10
reagents.add_reagent(/datum/reagent/fuel, 1)
-
-#undef WELDER_FUEL_BURN_INTERVAL
diff --git a/code/game/objects/items/toys.dm b/code/game/objects/items/toys.dm
index 1c82bffbf7c7e..139a3fcb216f2 100644
--- a/code/game/objects/items/toys.dm
+++ b/code/game/objects/items/toys.dm
@@ -1134,7 +1134,6 @@
name = "xenomorph action figure"
desc = "MEGA presents the new Xenos Isolated action figure! Comes complete with realistic sounds! Pull back string to use."
w_class = WEIGHT_CLASS_SMALL
- item_flags = XENOMORPH_HOLDABLE
var/cooldown = 0
/obj/item/toy/toy_xeno/attack_self(mob/user)
@@ -1405,7 +1404,7 @@
//Add changing looks when i feel suicidal about making 20 inhands for these.
/obj/item/toy/dummy/attack_self(mob/user)
- var/new_name = tgui_input_text(usr, "What would you like to name the dummy?", "Doll Name", doll_name, MAX_NAME_LEN)
+ var/new_name = tgui_input_text(usr, "What would you like to name the dummy?", "Doll Name", doll_name, max_length = MAX_NAME_LEN)
if(!new_name || !user.is_holding(src))
return
doll_name = new_name
diff --git a/code/game/objects/items/wall_mounted.dm b/code/game/objects/items/wall_mounted.dm
index ef19205cf8063..2db970b556ae1 100644
--- a/code/game/objects/items/wall_mounted.dm
+++ b/code/game/objects/items/wall_mounted.dm
@@ -61,9 +61,9 @@
/obj/item/wallframe/screwdriver_act(mob/living/user, obj/item/tool)
// For camera-building borgs
- var/turf/T = get_step(get_turf(user), user.dir)
- if(iswallturf(T))
- T.attackby(src, user)
+ var/turf/wall_turf = get_step(get_turf(user), user.dir)
+ if(iswallturf(wall_turf))
+ wall_turf.item_interaction(user, src)
return ITEM_INTERACT_SUCCESS
/obj/item/wallframe/wrench_act(mob/living/user, obj/item/tool)
diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm
index ef436e24e8c1a..0a88aade6978f 100644
--- a/code/game/objects/objs.dm
+++ b/code/game/objects/objs.dm
@@ -187,8 +187,11 @@ GLOBAL_LIST_EMPTY(objects_by_id_tag)
. = ..()
if(desc_controls)
. += span_notice(desc_controls)
+
+/obj/examine_tags(mob/user)
+ . = ..()
if(obj_flags & UNIQUE_RENAME)
- . += span_notice("Use a pen on it to rename it or change its description.")
+ .["renameable"] = "Use a pen on it to rename it or change its description."
/obj/analyzer_act(mob/living/user, obj/item/analyzer/tool)
if(atmos_scan(user=user, target=src, silent=FALSE))
diff --git a/code/game/objects/structures.dm b/code/game/objects/structures.dm
index 701c13bfcf755..e6c9579d67936 100644
--- a/code/game/objects/structures.dm
+++ b/code/game/objects/structures.dm
@@ -58,6 +58,9 @@
if(!broken)
return span_warning("It's falling apart!")
+/obj/structure/examine_descriptor(mob/user)
+ return "structure"
+
/obj/structure/rust_heretic_act()
take_damage(500, BRUTE, "melee", 1)
diff --git a/code/game/objects/structures/beds_chairs/bed.dm b/code/game/objects/structures/beds_chairs/bed.dm
index 4ade32bdd0e0a..9131a28e6eb06 100644
--- a/code/game/objects/structures/beds_chairs/bed.dm
+++ b/code/game/objects/structures/beds_chairs/bed.dm
@@ -27,6 +27,8 @@
var/elevation = 8
/// If this bed can be deconstructed using a wrench
var/can_deconstruct = TRUE
+ /// Directions in which the bed has its headrest on the left side.
+ var/left_headrest_dirs = NORTHEAST
/obj/structure/bed/Initialize(mapload)
. = ..()
@@ -58,7 +60,7 @@
update_buckle_vars(newdir)
/obj/structure/bed/proc/update_buckle_vars(newdir)
- buckle_lying = newdir & NORTHEAST ? 270 : 90
+ buckle_lying = newdir & left_headrest_dirs ? 270 : 90
/obj/structure/bed/atom_deconstruct(disassembled = TRUE)
if(build_stack_type)
@@ -83,6 +85,8 @@
icon_state = "med_down"
base_icon_state = "med"
anchored = FALSE
+ left_headrest_dirs = SOUTHWEST
+ buckle_lying = 270
resistance_flags = NONE
build_stack_type = /obj/item/stack/sheet/mineral/titanium
build_stack_amount = 1
diff --git a/code/game/objects/structures/beds_chairs/chair.dm b/code/game/objects/structures/beds_chairs/chair.dm
index e1581422d0570..73020ba93bbb7 100644
--- a/code/game/objects/structures/beds_chairs/chair.dm
+++ b/code/game/objects/structures/beds_chairs/chair.dm
@@ -16,7 +16,17 @@
var/buildstacktype = /obj/item/stack/sheet/iron
var/buildstackamount = 1
var/item_chair = /obj/item/chair // if null it can't be picked up
+ ///How much sitting on this chair influences fishing difficulty
+ var/fishing_modifier = -3
+/obj/structure/chair/Initialize(mapload)
+ . = ..()
+ if(prob(0.2))
+ name = "tactical [name]"
+ fishing_modifier -= 4
+ MakeRotate()
+ if(can_buckle && fishing_modifier)
+ AddComponent(/datum/component/adjust_fishing_difficulty, fishing_modifier)
/obj/structure/chair/examine(mob/user)
. = ..()
@@ -24,12 +34,6 @@
if(!has_buckled_mobs() && can_buckle)
. += span_notice("While standing on [src], drag and drop your sprite onto [src] to buckle to it.")
-/obj/structure/chair/Initialize(mapload)
- . = ..()
- if(prob(0.2))
- name = "tactical [name]"
- MakeRotate()
-
///This proc adds the rotate component, overwrite this if you for some reason want to change some specific args.
/obj/structure/chair/proc/MakeRotate()
AddComponent(/datum/component/simple_rotation, ROTATION_IGNORE_ANCHORED|ROTATION_GHOSTS_ALLOWED)
@@ -134,6 +138,7 @@
buildstacktype = /obj/item/stack/sheet/mineral/wood
buildstackamount = 3
item_chair = /obj/item/chair/wood
+ fishing_modifier = -4
/obj/structure/chair/wood/narsie_act()
return
@@ -151,6 +156,7 @@
max_integrity = 70
buildstackamount = 2
item_chair = null
+ fishing_modifier = -5
// The mutable appearance used for the overlay over buckled mobs.
var/mutable_appearance/armrest
@@ -226,11 +232,13 @@
desc = "A luxurious chair, the many purple scales reflect the light in a most pleasing manner."
icon_state = "carp_chair"
buildstacktype = /obj/item/stack/sheet/animalhide/carp
+ fishing_modifier = -10
/obj/structure/chair/office
anchored = FALSE
buildstackamount = 5
item_chair = null
+ fishing_modifier = -4
icon_state = "officechair_dark"
/obj/structure/chair/office/Initialize(mapload)
@@ -245,6 +253,10 @@
/obj/structure/chair/office/tactical
name = "tactical swivel chair"
+/obj/structure/chair/office/tactical/Initialize(mapload)
+ . = ..()
+ AddComponent(/datum/component/adjust_fishing_difficulty, -10)
+
/obj/structure/chair/office/light
icon_state = "officechair_white"
@@ -436,6 +448,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/chair/stool/bar, 0)
desc = "You sit in this. Either by will or force. Looks REALLY uncomfortable."
icon_state = "chairold"
item_chair = null
+ fishing_modifier = 4
/obj/structure/chair/bronze
name = "brass chair"
@@ -445,6 +458,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/chair/stool/bar, 0)
buildstacktype = /obj/item/stack/sheet/bronze
buildstackamount = 1
item_chair = null
+ fishing_modifier = -12 //the pinnacle of Ratvarian technology.
/// Total rotations made
var/turns = 0
@@ -484,6 +498,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/chair/stool/bar, 0)
item_chair = null
obj_flags = parent_type::obj_flags | NO_DEBRIS_AFTER_DECONSTRUCTION
alpha = 0
+ fishing_modifier = -20 //it only lives for 25 seconds, so we make them worth it.
/obj/structure/chair/mime/wrench_act_secondary(mob/living/user, obj/item/weapon)
return NONE
@@ -505,6 +520,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/chair/stool/bar, 0)
buildstacktype = /obj/item/stack/sheet/plastic
buildstackamount = 2
item_chair = /obj/item/chair/plastic
+ fishing_modifier = -8
/obj/structure/chair/plastic/post_buckle_mob(mob/living/Mob)
Mob.pixel_y += 2
diff --git a/code/game/objects/structures/beds_chairs/sofa.dm b/code/game/objects/structures/beds_chairs/sofa.dm
index bf9a221929b67..04bb0b1e25e3f 100644
--- a/code/game/objects/structures/beds_chairs/sofa.dm
+++ b/code/game/objects/structures/beds_chairs/sofa.dm
@@ -19,6 +19,7 @@ path/corner/color_name {\
icon = 'icons/obj/chairs_wide.dmi'
buildstackamount = 1
item_chair = null
+ fishing_modifier = -4
var/mutable_appearance/armrest
/obj/structure/chair/sofa/Initialize(mapload)
diff --git a/code/game/objects/structures/cannons/cannon_instructions.dm b/code/game/objects/structures/cannons/cannon_instructions.dm
index c259ea0e76f17..34cdcdf1ced68 100644
--- a/code/game/objects/structures/cannons/cannon_instructions.dm
+++ b/code/game/objects/structures/cannons/cannon_instructions.dm
@@ -17,4 +17,10 @@ REGULAR CANNONBALL: A fine choice for killing landlubbers! Will take off any lim
EXPLOSIVE SHELLBALL: The most elegant in breaching (er killin', if you're good at aimin') tools, ye be packing this shell with many scuppering chemicals! Just make sure to not fire it when ye be close to target!
MALFUNCTION SHOT: A very gentle "cannonball" dart at first glance, but make no mistake: This is their worst nightmare! Enjoy an easy boarding process while all their machines are broken and all their weapons unloaded from an EMP!
THE BIGGEST ONE: A shellball, but much bigger. Ye won't be seein' much of these as they were discontinued for sinkin' the firer's ship as often as it sunk the scallywag's ship. Very big boom! If ye have one, ye have been warned!
+
+
FIRING THAR CANISTER GATLING
+
+THE CANISTER GATLING AIN'T LIKE OTHER CANNONS, AND DOESN'T REQUIRE GUNPOWDER, INSTEAD RELYING ON SPECIAL CANISTER SHOT SHELLS.
+ALL YOU HAVE TO DO IS CRAM A SHELL IN THE BREACH, LIGHT HER UP AND YOU'LL BE BLOWING THOSE CORPORATE SODS TO KINGDOM COME!
+SHE LACKS THE SHEER WALL-BREAKING PUNCH OF THE HOLEMAKERS, BUT CHEWS THROUGH SOFT TARGETS LIKE A SHARK THROUGH A GROUP OF BEACH THROUGH A GROUP OF BEACHGOERS, YAHAR.
"}
diff --git a/code/game/objects/structures/cannons/mounted_guns/mounted_gun.dm b/code/game/objects/structures/cannons/mounted_guns/mounted_gun.dm
new file mode 100644
index 0000000000000..da27cdbdaf9df
--- /dev/null
+++ b/code/game/objects/structures/cannons/mounted_guns/mounted_gun.dm
@@ -0,0 +1,187 @@
+//Mounted guns are basically a smaller equivalent to cannons, designed to use pre-existing ammo rather than cannonballs.
+//Due to using pre-existing ammo, they dont require to be loaded with gunpowder or an equivalent.
+
+/obj/structure/mounted_gun
+ name = "Mounted Gun"
+ desc = "Default mounted gun for inheritance purposes."
+ density = TRUE
+ anchored = FALSE
+ icon = 'icons/obj/weapons/cannons.dmi'
+ icon_state = "falconet_patina"
+ var/icon_state_base = "falconet_patina"
+ var/icon_state_fire = "falconet_patina_fire"
+ max_integrity = 300
+ ///whether the cannon can be unwrenched from the ground. Anchorable_cannon equivalent.
+ var/anchorable_gun = TRUE
+ ///Max shots per firing of the gun.
+ var/max_shots_per_fire = 1
+ ///Shots currently loaded. Should never be more than max_shots_per_fire.
+ var/shots_in_gun = 1
+ ///shots added to gun, per piece of ammo loaded.
+ var/shots_per_load = 1
+ ///Accepted "ammo" type
+ var/obj/item/ammo_type = /obj/item/ammo_casing/strilka310
+ ///Projectile from said gun. Doesnt automatically inherit said ammo's projectile in case you wanted to make a gun that shoots floor tiles or something.
+ var/obj/item/projectile_type = /obj/projectile/bullet/strilka310
+ ///If the gun has anything in it.
+ var/loaded_gun = TRUE
+ ///If the gun is currently loaded with its maximum capacity.
+ var/fully_loaded_gun = TRUE
+ ///delay in firing the gun after lighting
+ var/fire_delay = 5
+ ///Delay between shots
+ var/shot_delay = 3
+ ///If the gun shakes the camera when firing
+ var/firing_shakes_camera = TRUE
+ ///sound of firing for all but last shot
+ var/fire_sound = 'sound/weapons/gun/general/mountedgun.ogg'
+ ///sound of firing for last shot
+ var/last_fire_sound = 'sound/weapons/gun/general/mountedgunend.ogg'
+
+/obj/structure/mounted_gun/wrench_act(mob/living/user, obj/item/tool)
+ . = ..()
+ if(!anchorable_gun) /// Can't anchor an unanchorable gun.
+ return FALSE
+ default_unfasten_wrench(user, tool)
+ return ITEM_INTERACT_SUCCESS
+
+///Covers Reloading and lighting of the gun
+/obj/structure/mounted_gun/attackby(obj/item/ammo_casing/used_item, mob/user, params)
+ var/ignition_message = used_item.ignition_effect(src, user) // Checks if item used can ignite stuff.
+ if(istype(used_item, ammo_type))
+ if(fully_loaded_gun)
+ balloon_alert(user, "already fully loaded!")
+ return
+ else
+ shots_in_gun = shots_in_gun + shots_per_load //Add one to the shots in the gun
+
+ loaded_gun = TRUE // Make sure it registers theres ammo in there, so it can fire.
+ QDEL_NULL(used_item)
+ if(shots_in_gun >= max_shots_per_fire)
+ shots_in_gun = max_shots_per_fire // in case of somehow firing only some of a guns shots, and reloading, you still cant get above the maximum ammo size.
+ fully_loaded_gun = TRUE //So you cant load extra.
+ return
+
+ else if(ignition_message) // if item the player used ignites, light the gun!
+ visible_message(ignition_message)
+ user.log_message("fired a cannon", LOG_ATTACK)
+ log_game("[key_name(user)] fired a cannon in [AREACOORD(src)]")
+ addtimer(CALLBACK(src, PROC_REF(fire)), fire_delay) //uses fire proc as shown below to shoot the gun
+ return
+ ..()
+
+/obj/structure/mounted_gun/proc/fire()
+ if (!loaded_gun)
+ balloon_alert_to_viewers("gun is not loaded!","",2)
+ return
+ for(var/times_fired = 1, times_fired <= shots_in_gun, times_fired++) //The normal DM for loop structure since the times it has fired is changing in the loop itself.
+ for(var/mob/shaken_mob in urange(10, src))
+ if(shaken_mob.stat == CONSCIOUS && firing_shakes_camera == TRUE)
+ shake_camera(shaken_mob, 3, 1)
+ icon_state = icon_state_fire
+ if(loaded_gun)
+
+ if (times_fired < shots_in_gun)
+ playsound(src, fire_sound, 50, FALSE, 5)
+ else
+ playsound(src, last_fire_sound, 50, TRUE, 5)
+ var/obj/projectile/fired_projectile = new projectile_type(get_turf(src))
+ fired_projectile.firer = src
+ fired_projectile.fired_from = src
+ fired_projectile.fire(dir2angle(dir))
+ sleep(shot_delay)
+ loaded_gun = FALSE
+ shots_in_gun = 0
+ fully_loaded_gun = FALSE
+ icon_state = icon_state_base
+
+/obj/structure/mounted_gun/pipe
+
+ name = "Pipe Organ Gun"
+ desc = "To become master over one who has killed, one must become a better killer. This engine of destruction is one of many things made to that end."
+ icon_state = "pipeorgangun"
+ icon_state_base = "pipeorgangun"
+ icon_state_fire = "pipeorgangun_fire"
+ anchored = FALSE
+ anchorable_gun = TRUE
+ max_shots_per_fire = 8
+ shots_in_gun = 8
+ shots_per_load = 2
+ ammo_type = /obj/item/ammo_casing/junk
+ projectile_type = /obj/projectile/bullet/junk
+ loaded_gun = TRUE
+ fully_loaded_gun = TRUE
+ fire_delay = 3
+ shot_delay = 2
+ firing_shakes_camera = FALSE
+
+/obj/structure/mounted_gun/pipe/examine_more(mob/user)
+ . = ..()
+ . += span_notice("Looking down at the [name], you recall a tale told to you in some distant memory...")
+
+ . += span_info("To commit an act of vengeance is not unlike to enter a blood pact with a devil, ending the life of another, at the cost of your own.")
+ . += span_info("When humanity first spilled the blood of its own kind, with likely nothing more than a rock, the seal was broken. Vengeance was borne unto the world.")
+ . += span_info("However, vengeance alone is not enough to carry through the grim deed of murder. One must an gain advantage over their adversary.")
+ . += span_info("As such, the man who ended another's life with a stone, was in turn smote himself by another wielding a spear. After spears, bows. Swords. Guns. Tanks. Missiles. And on and on Vengeance fed. Growing stronger. Growing Worse.")
+ . += span_info("Vengeance persists to this day. It sometimes may slumber, seemingly content with having gorged itself, but in the end, its ceaseless hunger can be neither numbed nor sated.")
+
+/obj/structure/mounted_gun/pipe/fire()
+ if (!loaded_gun)
+ balloon_alert_to_viewers("Gun is not loaded!","",2)
+ return
+ for(var/times_fired = 1, times_fired <= shots_in_gun, times_fired++) //The normal DM for loop structure since the times it has fired is changing in the loop itself.
+ for(var/mob/shaken_mob in urange(10, src))
+ if((shaken_mob.stat == CONSCIOUS)&&(firing_shakes_camera == TRUE))
+ shake_camera(shaken_mob, 3, 1)
+ icon_state = icon_state_fire
+ if(loaded_gun)
+ playsound(src, fire_sound, 50, TRUE, 5)
+
+ var/list_of_projectiles = list(
+ /obj/projectile/bullet/junk = 40,
+ /obj/projectile/bullet/incendiary/fire/junk = 25,
+ /obj/projectile/bullet/junk/shock = 25,
+ /obj/projectile/bullet/junk/hunter = 20,
+ /obj/projectile/bullet/junk/phasic = 8,
+ /obj/projectile/bullet/junk/ripper = 8,
+ /obj/projectile/bullet/junk/reaper = 3,
+ )
+ projectile_type = pick_weight(list_of_projectiles)
+
+ var/obj/projectile/fired_projectile = new projectile_type(get_turf(src))
+ fired_projectile.firer = src
+ fired_projectile.fired_from = src
+ fired_projectile.fire(dir2angle(dir))
+ sleep(shot_delay)
+ loaded_gun = FALSE
+ shots_in_gun = 0
+ fully_loaded_gun = FALSE
+ icon_state = icon_state_base
+
+/obj/structure/mounted_gun/canister_gatling //for the funny skeleton pirates!
+
+ name = "Canister Gatling Gun"
+ desc = "''Quantity has a quality of its own.''"
+ icon_state = "canister_gatling"
+ icon_state_base = "canister_gatling"
+ icon_state_fire = "canister_gatling_fire"
+ anchored = FALSE
+ anchorable_gun = TRUE
+ max_shots_per_fire = 50
+ shots_per_load = 50
+ shots_in_gun = 50
+ ammo_type = /obj/item/ammo_casing/canister_shot
+ projectile_type = /obj/projectile/bullet/shrapnel
+ loaded_gun = TRUE
+ fully_loaded_gun = TRUE
+ fire_delay = 3
+ shot_delay = 1
+ firing_shakes_camera = FALSE
+
+/obj/item/ammo_casing/canister_shot
+ name = "Canister Shot"
+ desc = "A gigantic... well, canister of canister shot. Used for reloading the Canister Gatling Gun."
+ icon_state = "canister_shot"
+ obj_flags = CONDUCTS_ELECTRICITY
+ throwforce = 0
+ w_class = WEIGHT_CLASS_BULKY
diff --git a/code/game/objects/structures/construction_console/construction_actions.dm b/code/game/objects/structures/construction_console/construction_actions.dm
index fc014d14318bd..b9abfe70c3f71 100644
--- a/code/game/objects/structures/construction_console/construction_actions.dm
+++ b/code/game/objects/structures/construction_console/construction_actions.dm
@@ -91,7 +91,7 @@
if(place_turf.density)
to_chat(owner, span_warning("[structure_name] may only be placed on a floor."))
return
- //Can't place two dense objects inside eachother
+ //Can't place two dense objects inside each other
if(initial(structure_path.density) && place_turf.is_blocked_turf())
to_chat(owner, span_warning("Location is obstructed by something. Please clear the location and try again."))
return
diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm
index f407dcd82c04f..c4740398d82d2 100644
--- a/code/game/objects/structures/crates_lockers/closets.dm
+++ b/code/game/objects/structures/crates_lockers/closets.dm
@@ -157,8 +157,8 @@ GLOBAL_LIST_EMPTY(roundstart_station_closets)
register_context()
if(opened)
- opened = FALSE //nessassary because open() proc will early return if its true
- if(open(special_effects = FALSE)) //closets which are meant to be open by default dont need to be animated open
+ opened = FALSE //necessary because open() proc will early return if its true
+ if(open(special_effects = FALSE)) //closets which are meant to be open by default don't need to be animated open
return
update_appearance()
@@ -823,21 +823,24 @@ GLOBAL_LIST_EMPTY(roundstart_station_closets)
balloon_alert(user, "unlock first!")
return
- if(isnull(id_card))
+ if(isnull(id_card) && secure)
balloon_alert(user, "not yours to rename!")
return
var/name_set = FALSE
var/desc_set = FALSE
- var/str = tgui_input_text(user, "Personal Locker Name", "Locker Name")
- if(!isnull(str))
- name = str
+
+ var/input_name = tgui_input_text(user, "Locker Name", "Locker Name", max_length = MAX_NAME_LEN)
+
+ if(!isnull(input_name))
+ name = input_name
name_set = TRUE
- str = tgui_input_text(user, "Personal Locker Description", "Locker Description")
- if(!isnull(str))
- desc = str
+ var/input_desc = tgui_input_text(user, "Locker Description", "Locker Description", max_length = MAX_DESC_LEN)
+
+ if(!isnull(input_desc))
+ desc = input_desc
desc_set = TRUE
var/bit_flag = NONE
@@ -888,7 +891,7 @@ GLOBAL_LIST_EMPTY(roundstart_station_closets)
user.log_message("[welded ? "welded":"unwelded"] closet [src] with [weapon]", LOG_GAME)
update_appearance()
- else if(!user.combat_mode)
+ else if(!user.combat_mode || (weapon.item_flags & NOBLUDGEON))
var/item_is_id = weapon.GetID()
if(!item_is_id)
return FALSE
@@ -915,8 +918,6 @@ GLOBAL_LIST_EMPTY(roundstart_station_closets)
/obj/structure/closet/mouse_drop_receive(atom/movable/O, mob/living/user, params)
if(!istype(O) || O.anchored || istype(O, /atom/movable/screen))
return
- if(!istype(user) || user.incapacitated || user.body_position == LYING_DOWN)
- return
if(user == O) //try to climb onto it
return ..()
if(!opened)
@@ -1068,7 +1069,7 @@ GLOBAL_LIST_EMPTY(roundstart_station_closets)
addtimer(CALLBACK(src, PROC_REF(check_if_shake)), next_check_time)
return TRUE
- // If we reach here, nobody is resisting, so dont shake
+ // If we reach here, nobody is resisting, so don't shake
return FALSE
/obj/structure/closet/proc/bust_open()
@@ -1191,15 +1192,13 @@ GLOBAL_LIST_EMPTY(roundstart_station_closets)
return
if(!opened && ((shove_flags & SHOVE_KNOCKDOWN_BLOCKED) || !(shove_flags & SHOVE_BLOCKED)))
return
- var/was_opened = opened
- if(!toggle())
- return
- if(was_opened)
- if (!target.Move(get_turf(src), get_dir(target, src)))
+ if(opened)
+ if (target.loc != loc)
return
target.forceMove(src)
else
target.Knockdown(SHOVE_KNOCKDOWN_SOLID)
+ toggle()
update_icon()
target.visible_message(span_danger("[shover.name] shoves [target.name] into [src]!"),
span_userdanger("You're shoved into [src] by [shover.name]!"),
diff --git a/code/game/objects/structures/crates_lockers/closets/bodybag.dm b/code/game/objects/structures/crates_lockers/closets/bodybag.dm
index ac8b444e47dc7..66950b0845f1d 100644
--- a/code/game/objects/structures/crates_lockers/closets/bodybag.dm
+++ b/code/game/objects/structures/crates_lockers/closets/bodybag.dm
@@ -116,8 +116,22 @@
*/
/obj/structure/closet/body_bag/proc/perform_fold(mob/living/carbon/human/the_folder)
visible_message(span_notice("[the_folder] folds up [src]."))
- var/obj/item/bodybag/folding_bodybag = foldedbag_instance || new foldedbag_path
- the_folder.put_in_hands(folding_bodybag)
+ the_folder.put_in_hands(undeploy_bodybag(the_folder.loc))
+
+/// Makes the bag into an item, returns that item
+/obj/structure/closet/body_bag/proc/undeploy_bodybag(atom/fold_loc)
+ var/obj/item/bodybag/folding_bodybag = foldedbag_instance || new foldedbag_path()
+ if(fold_loc)
+ folding_bodybag.forceMove(fold_loc)
+ return folding_bodybag
+
+/obj/structure/closet/body_bag/container_resist_act(mob/living/user, loc_required = TRUE)
+ // ideally we support this natively but i guess that's for a later time
+ if(!istype(loc, /obj/machinery/disposal))
+ return ..()
+ for(var/atom/movable/thing as anything in src)
+ thing.forceMove(loc)
+ undeploy_bodybag(loc)
/obj/structure/closet/body_bag/bluespace
name = "bluespace body bag"
@@ -152,7 +166,7 @@
/obj/structure/closet/body_bag/bluespace/perform_fold(mob/living/carbon/human/the_folder)
visible_message(span_notice("[the_folder] folds up [src]."))
- var/obj/item/bodybag/folding_bodybag = foldedbag_instance || new foldedbag_path
+ var/obj/item/bodybag/folding_bodybag = undeploy_bodybag(the_folder.loc)
var/max_weight_of_contents = initial(folding_bodybag.w_class)
for(var/am in contents)
var/atom/movable/content = am
@@ -186,7 +200,7 @@
contents_thermal_insulation = 0.5
foldedbag_path = /obj/item/bodybag/environmental
/// The list of weathers we protect from.
- var/list/weather_protection = list(TRAIT_ASHSTORM_IMMUNE, TRAIT_RADSTORM_IMMUNE, TRAIT_SNOWSTORM_IMMUNE, TRAIT_VOIDSTORM_IMMUNE) // Does not protect against lava or the The Floor Is Lava spell.
+ var/list/weather_protection = list(TRAIT_ASHSTORM_IMMUNE, TRAIT_RADSTORM_IMMUNE, TRAIT_SNOWSTORM_IMMUNE) // Does not protect against lava or the The Floor Is Lava spell.
/// The contents of the gas to be distributed to an occupant. Set in Initialize()
var/datum/gas_mixture/air_contents = null
@@ -277,18 +291,9 @@
icon_state = initial(icon_state)
/obj/structure/closet/body_bag/environmental/prisoner/container_resist_act(mob/living/user, loc_required = TRUE)
- /// copy-pasted with changes because flavor text as well as some other misc stuff
- if(opened)
- return
- if(ismovable(loc))
- user.changeNext_move(CLICK_CD_BREAKOUT)
- user.last_special = world.time + CLICK_CD_BREAKOUT
- var/atom/movable/location = loc
- location.relay_container_resist_act(user, src)
- return
- if(!sinched)
- open(user)
- return
+ // copy-pasted with changes because flavor text as well as some other misc stuff
+ if(opened || ismovable(loc) || !sinched)
+ return ..()
user.changeNext_move(CLICK_CD_BREAKOUT)
user.last_special = world.time + CLICK_CD_BREAKOUT
@@ -301,6 +306,8 @@
//we check after a while whether there is a point of resisting anymore and whether the user is capable of resisting
user.visible_message(span_danger("[user] successfully broke out of [src]!"),
span_notice("You successfully break out of [src]!"))
+ if(istype(loc, /obj/machinery/disposal))
+ return ..()
bust_open()
else
if(user.loc == src) //so we don't get the message if we resisted multiple times and succeeded.
@@ -369,7 +376,7 @@
icon_state = "holobag_med"
resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF
foldedbag_path = null
- weather_protection = list(TRAIT_VOIDSTORM_IMMUNE, TRAIT_SNOWSTORM_IMMUNE)
+ weather_protection = list(TRAIT_SNOWSTORM_IMMUNE)
/obj/structure/closet/body_bag/environmental/hardlight/play_attack_sound(damage_amount, damage_type = BRUTE, damage_flag = 0)
if(damage_type in list(BRUTE, BURN))
@@ -381,7 +388,7 @@
icon_state = "holobag_sec"
resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF
foldedbag_path = null
- weather_protection = list(TRAIT_VOIDSTORM_IMMUNE, TRAIT_SNOWSTORM_IMMUNE)
+ weather_protection = list(TRAIT_SNOWSTORM_IMMUNE)
/obj/structure/closet/body_bag/environmental/prisoner/hardlight/play_attack_sound(damage_amount, damage_type = BRUTE, damage_flag = 0)
if(damage_type in list(BRUTE, BURN))
diff --git a/code/game/objects/structures/crates_lockers/crates.dm b/code/game/objects/structures/crates_lockers/crates.dm
index cac9fbaf890bb..2fed72c5bab3b 100644
--- a/code/game/objects/structures/crates_lockers/crates.dm
+++ b/code/game/objects/structures/crates_lockers/crates.dm
@@ -5,7 +5,6 @@
icon_state = "crate"
base_icon_state = "crate"
req_access = null
- can_weld_shut = FALSE
horizontal = TRUE
allow_objects = TRUE
allow_dense = TRUE
@@ -95,6 +94,9 @@
else if(secure)
. += "securecrateg"
+ if(welded)
+ . += icon_welded
+
if(opened && lid_icon_state)
var/mutable_appearance/lid = mutable_appearance(icon = lid_icon, icon_state = lid_icon_state)
lid.pixel_x = lid_x
@@ -174,6 +176,7 @@
can_install_electronics = FALSE
paint_jobs = null
elevation_open = 0
+ can_weld_shut = FALSE
/obj/structure/closet/crate/trashcart //please make this a generic cart path later after things calm down a little
desc = "A heavy, metal trashcart with wheels."
@@ -190,6 +193,7 @@
base_icon_state = "laundry"
elevation = 14
elevation_open = 14
+ can_weld_shut = FALSE
/obj/structure/closet/crate/trashcart/Initialize(mapload)
. = ..()
@@ -224,7 +228,7 @@
/obj/structure/closet/crate/deforest
name = "deforest medical crate"
- desc = "A DeFortest brand crate of medical supplies."
+ desc = "A DeForest brand crate of medical supplies."
icon_state = "deforest"
base_icon_state = "deforest"
diff --git a/code/game/objects/structures/crates_lockers/crates/bins.dm b/code/game/objects/structures/crates_lockers/crates/bins.dm
index a686d53f392c6..8ff1e1aa21da8 100644
--- a/code/game/objects/structures/crates_lockers/crates/bins.dm
+++ b/code/game/objects/structures/crates_lockers/crates/bins.dm
@@ -12,6 +12,7 @@
paint_jobs = null
elevation = 17
elevation_open = 17
+ can_weld_shut = FALSE
/obj/structure/closet/crate/bin/LateInitialize()
. = ..()
diff --git a/code/game/objects/structures/crates_lockers/crates/cardboard.dm b/code/game/objects/structures/crates_lockers/crates/cardboard.dm
index 7b1e7dc725779..12008cc4022bf 100644
--- a/code/game/objects/structures/crates_lockers/crates/cardboard.dm
+++ b/code/game/objects/structures/crates_lockers/crates/cardboard.dm
@@ -12,6 +12,7 @@
close_sound_volume = 25
paint_jobs = null
cutting_tool = /obj/item/wirecutters
+ can_weld_shut = FALSE
/obj/structure/closet/crate/cardboard/mothic
name = "\improper Mothic Fleet box"
diff --git a/code/game/objects/structures/crates_lockers/crates/critter.dm b/code/game/objects/structures/crates_lockers/crates/critter.dm
index 5e1873d166ab6..d116a33d8ff75 100644
--- a/code/game/objects/structures/crates_lockers/crates/critter.dm
+++ b/code/game/objects/structures/crates_lockers/crates/critter.dm
@@ -17,6 +17,7 @@
can_install_electronics = FALSE
elevation = 21
elevation_open = 0
+ can_weld_shut = FALSE
var/obj/item/tank/internals/emergency_oxygen/tank
diff --git a/code/game/objects/structures/crates_lockers/crates/large.dm b/code/game/objects/structures/crates_lockers/crates/large.dm
index 0a08d9c7949a1..667dd9b2ebb8b 100644
--- a/code/game/objects/structures/crates_lockers/crates/large.dm
+++ b/code/game/objects/structures/crates_lockers/crates/large.dm
@@ -15,6 +15,7 @@
close_sound_volume = 50
can_install_electronics = FALSE
elevation = 22
+ can_weld_shut = FALSE
// Stops people from "diving into" a crate you can't open normally
divable = FALSE
diff --git a/code/game/objects/structures/deployable_turret.dm b/code/game/objects/structures/deployable_turret.dm
index 908d2348db4b3..6abb14294de5b 100644
--- a/code/game/objects/structures/deployable_turret.dm
+++ b/code/game/objects/structures/deployable_turret.dm
@@ -259,11 +259,11 @@
M.attacked_by(src, user)
add_fingerprint(user)
-/obj/item/gun_control/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
+/obj/item/gun_control/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
var/obj/machinery/deployable_turret/E = user.buckled
E.calculated_projectile_vars = calculate_projectile_angle_and_pixel_offsets(user, interacting_with, modifiers)
E.direction_track(user, interacting_with)
E.checkfire(interacting_with, user)
-/obj/item/gun_control/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
- return interact_with_atom(interacting_with, user, modifiers)
+/obj/item/gun_control/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
+ return ranged_interact_with_atom(interacting_with, user, modifiers)
diff --git a/code/game/objects/structures/detectiveboard.dm b/code/game/objects/structures/detectiveboard.dm
index f9d0560dfdee4..27c11cda5a018 100644
--- a/code/game/objects/structures/detectiveboard.dm
+++ b/code/game/objects/structures/detectiveboard.dm
@@ -50,11 +50,11 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/detectiveboard, 32)
to_chat(user, "You already attaching evidence!")
return
attaching_evidence = TRUE
- var/name = tgui_input_text(user, "Please enter the evidence name", "Detective's Board")
+ var/name = tgui_input_text(user, "Please enter the evidence name", "Detective's Board", max_length = MAX_NAME_LEN)
if(!name)
attaching_evidence = FALSE
return
- var/desc = tgui_input_text(user, "Please enter the evidence description", "Detective's Board")
+ var/desc = tgui_input_text(user, "Please enter the evidence description", "Detective's Board", max_length = MAX_DESC_LEN)
if(!desc)
attaching_evidence = FALSE
return
@@ -146,7 +146,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/detectiveboard, 32)
if("add_case")
if(cases.len == MAX_CASES)
return FALSE
- var/new_case = tgui_input_text(user, "Please enter the case name", "Detective's Board")
+ var/new_case = tgui_input_text(user, "Please enter the case name", "Detective's Board", max_length = MAX_NAME_LEN)
if(!new_case)
return FALSE
var/case_color = tgui_input_list(user, "Please choose case color", "Detective's Board", case_colors)
@@ -173,7 +173,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/detectiveboard, 32)
update_appearance(UPDATE_ICON)
return TRUE
if("rename_case")
- var/new_name = tgui_input_text(user, "Please ender the case new name", "Detective's Board")
+ var/new_name = tgui_input_text(user, "Please enter the new name for the case", "Detective's Board", max_length = MAX_NAME_LEN)
if(new_name)
var/datum/case/case = locate(params["case_ref"]) in cases
case.name = new_name
diff --git a/code/game/objects/structures/displaycase.dm b/code/game/objects/structures/displaycase.dm
index b582d86efde0e..03957e2708bf0 100644
--- a/code/game/objects/structures/displaycase.dm
+++ b/code/game/objects/structures/displaycase.dm
@@ -159,7 +159,7 @@
toggle_lock(user)
else if(open && !showpiece)
insert_showpiece(attacking_item, user)
- return TRUE //cancel the attack chain, wether we successfully placed an item or not
+ return TRUE //cancel the attack chain, whether we successfully placed an item or not
else if(glass_fix && broken && istype(attacking_item, /obj/item/stack/sheet/glass))
var/obj/item/stack/sheet/glass/glass_sheet = attacking_item
if(glass_sheet.get_amount() < 2)
@@ -426,7 +426,7 @@
return
if("change_message")
if(showpiece && !holographic_showpiece)
- var/new_trophy_message = tgui_input_text(usr, "Let's make history!", "Trophy Message", trophy_message, MAX_PLAQUE_LEN)
+ var/new_trophy_message = tgui_input_text(usr, "Let's make history!", "Trophy Message", trophy_message, max_length = MAX_PLAQUE_LEN)
if(!new_trophy_message)
return
trophy_message = new_trophy_message
diff --git a/code/game/objects/structures/door_assembly.dm b/code/game/objects/structures/door_assembly.dm
index 9493a7c941407..c2d67e6290145 100644
--- a/code/game/objects/structures/door_assembly.dm
+++ b/code/game/objects/structures/door_assembly.dm
@@ -83,7 +83,7 @@
/obj/structure/door_assembly/attackby(obj/item/W, mob/living/user, params)
if(IS_WRITING_UTENSIL(W) && !user.combat_mode)
- var/t = tgui_input_text(user, "Enter the name for the door", "Airlock Renaming", created_name, MAX_NAME_LEN)
+ var/t = tgui_input_text(user, "Enter the name for the door", "Airlock Renaming", created_name, max_length = MAX_NAME_LEN)
if(!t)
return
if(!in_range(src, usr) && loc != usr)
diff --git a/code/game/objects/structures/girders.dm b/code/game/objects/structures/girders.dm
index 0f20f87e0b547..389e8dcbd743d 100644
--- a/code/game/objects/structures/girders.dm
+++ b/code/game/objects/structures/girders.dm
@@ -500,7 +500,7 @@
/obj/structure/girder/bronze/attackby(obj/item/W, mob/living/user, params)
add_fingerprint(user)
if(W.tool_behaviour == TOOL_WELDER)
- if(!W.tool_start_check(user, amount = 0))
+ if(!W.tool_start_check(user, amount = 0, heat_required = HIGH_TEMPERATURE_REQUIRED))
return
balloon_alert(user, "slicing apart...")
if(W.use_tool(src, user, 40, volume=50))
diff --git a/code/game/objects/structures/kitchen_spike.dm b/code/game/objects/structures/kitchen_spike.dm
index 0cc73b9adef9c..57e30d58ef2bd 100644
--- a/code/game/objects/structures/kitchen_spike.dm
+++ b/code/game/objects/structures/kitchen_spike.dm
@@ -34,7 +34,7 @@
return CONTEXTUAL_SCREENTIP_SET
/obj/structure/kitchenspike_frame/welder_act(mob/living/user, obj/item/tool)
- if(!tool.tool_start_check(user, amount = 0))
+ if(!tool.tool_start_check(user, amount = 0, heat_required = HIGH_TEMPERATURE_REQUIRED))
return FALSE
to_chat(user, span_notice("You begin cutting \the [src] apart..."))
if(!tool.use_tool(src, user, 5 SECONDS, volume = 50))
diff --git a/code/game/objects/structures/lavaland/ore_vent.dm b/code/game/objects/structures/lavaland/ore_vent.dm
index f9214b989b95c..1de24f030bf5e 100644
--- a/code/game/objects/structures/lavaland/ore_vent.dm
+++ b/code/game/objects/structures/lavaland/ore_vent.dm
@@ -426,7 +426,7 @@
/**
* When the ore vent cannot spawn a mob due to being blocked from all sides, we cause some MILD, MILD explosions.
- * Explosion matches a gibtonite light explosion, as a way to clear neartby solid structures, with a high likelyhood of breaking the NODE drone.
+ * Explosion matches a gibtonite light explosion, as a way to clear nearby solid structures, with a high likelihood of breaking the NODE drone.
*/
/obj/structure/ore_vent/proc/anti_cheese()
explosion(src, heavy_impact_range = 1, light_impact_range = 3, flame_range = 0, flash_range = 0, adminlog = FALSE)
diff --git a/code/game/objects/structures/maintenance.dm b/code/game/objects/structures/maintenance.dm
index 9f88246966f94..a8de16271f36d 100644
--- a/code/game/objects/structures/maintenance.dm
+++ b/code/game/objects/structures/maintenance.dm
@@ -1,9 +1,9 @@
/** This structure acts as a source of moisture loving cell lines,
-as well as a location where a hidden item can somtimes be retrieved
+as well as a location where a hidden item can sometimes be retrieved
at the cost of risking a vicious bite.**/
/obj/structure/moisture_trap
name = "moisture trap"
- desc = "A device installed in order to control moisture in poorly ventilated areas.\nThe stagnant water inside basin seems to produce serious biofouling issues when improperly maintained.\nThis unit in particular seems to be teeming with life!\nWho thought mother Gaia could assert herself so vigoriously in this sterile and desolate place?"
+ desc = "A device installed in order to control moisture in poorly ventilated areas.\nThe stagnant water inside basin seems to produce serious biofouling issues when improperly maintained.\nThis unit in particular seems to be teeming with life!\nWho thought mother Gaia could assert herself so vigorously in this sterile and desolate place?"
icon_state = "moisture_trap"
anchored = TRUE
density = FALSE
@@ -58,7 +58,7 @@ at the cost of risking a vicious bite.**/
if(!isliving(user))
return FALSE
var/mob/living/living_user = user
- if(living_user.body_position == STANDING_UP && ishuman(living_user)) //I dont think monkeys can crawl on command.
+ if(living_user.body_position == STANDING_UP && ishuman(living_user)) //I don't think monkeys can crawl on command.
return FALSE
return TRUE
diff --git a/code/game/objects/structures/mystery_box.dm b/code/game/objects/structures/mystery_box.dm
index 9bb51ba09cbef..cb56cfe8ef120 100644
--- a/code/game/objects/structures/mystery_box.dm
+++ b/code/game/objects/structures/mystery_box.dm
@@ -142,7 +142,7 @@ GLOBAL_LIST_INIT(mystery_fishing, list(
/// Stores the current sound channel we're using so we can cut off our own sounds as needed. Randomized after each roll
var/current_sound_channel
/// How many time can it still be used?
- var/uses_left
+ var/uses_left = INFINITY
/// A list of weakrefs to mind datums of people that opened it and how many times.
var/list/datum/weakref/minds_that_opened_us
@@ -281,6 +281,7 @@ GLOBAL_LIST_INIT(mystery_fishing, list(
max_integrity = 100
damage_deflection = 30
grant_extra_mag = FALSE
+ anchored = FALSE
/obj/structure/mystery_box/handle_deconstruct(disassembled)
new /obj/item/stack/sheet/mineral/wood(drop_location(), 2)
diff --git a/code/game/objects/structures/petrified_statue.dm b/code/game/objects/structures/petrified_statue.dm
index 5383436d4dbff..d27a2e8e1cd8d 100644
--- a/code/game/objects/structures/petrified_statue.dm
+++ b/code/game/objects/structures/petrified_statue.dm
@@ -13,24 +13,24 @@
/obj/structure/statue/petrified/relaymove()
return
-/obj/structure/statue/petrified/Initialize(mapload, mob/living/L, statue_timer, save_brain)
+/obj/structure/statue/petrified/Initialize(mapload, mob/living/living, statue_timer, save_brain)
. = ..()
if(statue_timer)
timer = statue_timer
if(save_brain)
brain = save_brain
- if(L)
- petrified_mob = L
- if(L.buckled)
- L.buckled.unbuckle_mob(L,force=1)
- L.visible_message(span_warning("[L]'s skin rapidly turns to marble!"), span_userdanger("Your body freezes up! Can't... move... can't... think..."))
- L.forceMove(src)
- ADD_TRAIT(L, TRAIT_MUTE, STATUE_MUTE)
- L.faction |= FACTION_MIMIC //Stops mimics from instaqdeling people in statues
- L.status_flags |= GODMODE
- atom_integrity = L.health + 100 //stoning damaged mobs will result in easier to shatter statues
- max_integrity = atom_integrity
- START_PROCESSING(SSobj, src)
+ if(!living)
+ return
+ petrified_mob = living
+ if(living.buckled)
+ living.buckled.unbuckle_mob(living, force = TRUE)
+ living.visible_message(span_warning("[living]'s skin rapidly turns to marble!"), span_userdanger("Your body freezes up! Can't... move... can't... think..."))
+ living.forceMove(src)
+ living.add_traits(list(TRAIT_GODMODE, TRAIT_MUTE, TRAIT_NOBLOOD), STATUE_MUTE)
+ living.faction |= FACTION_MIMIC //Stops mimics from instaqdeling people in statues
+ atom_integrity = living.health + 100 //stoning damaged mobs will result in easier to shatter statues
+ max_integrity = atom_integrity
+ START_PROCESSING(SSobj, src)
/obj/structure/statue/petrified/process(seconds_per_tick)
if(!petrified_mob)
@@ -47,6 +47,9 @@
/obj/structure/statue/petrified/Exited(atom/movable/gone, direction)
. = ..()
if(gone == petrified_mob)
+ petrified_mob.remove_traits(list(TRAIT_GODMODE, TRAIT_MUTE, TRAIT_NOBLOOD), STATUE_MUTE)
+ petrified_mob.take_overall_damage((petrified_mob.health - atom_integrity + 100)) //any new damage the statue incurred is transferred to the mob
+ petrified_mob.faction -= FACTION_MIMIC
petrified_mob = null
/obj/structure/statue/petrified/Destroy()
@@ -64,13 +67,7 @@
for(var/obj/O in src)
O.forceMove(loc)
- if(petrified_mob)
- petrified_mob.status_flags &= ~GODMODE
- REMOVE_TRAIT(petrified_mob, TRAIT_MUTE, STATUE_MUTE)
- REMOVE_TRAIT(petrified_mob, TRAIT_NOBLOOD, MAGIC_TRAIT)
- petrified_mob.take_overall_damage((petrified_mob.health - atom_integrity + 100)) //any new damage the statue incurred is transferred to the mob
- petrified_mob.faction -= FACTION_MIMIC
- petrified_mob.forceMove(loc)
+ petrified_mob?.forceMove(loc)
return ..()
/obj/structure/statue/petrified/atom_deconstruct(disassembled = TRUE)
@@ -114,7 +111,6 @@
return FALSE
var/obj/structure/statue/petrified/S = new(loc, src, statue_timer, save_brain)
S.name = "statue of [name]"
- ADD_TRAIT(src, TRAIT_NOBLOOD, MAGIC_TRAIT)
S.copy_overlays(src)
var/newcolor = list(rgb(77,77,77), rgb(150,150,150), rgb(28,28,28), rgb(0,0,0))
if(colorlist)
diff --git a/code/game/objects/structures/pinatas.dm b/code/game/objects/structures/pinatas.dm
index 6483d39b1a26c..44d7a8b021594 100644
--- a/code/game/objects/structures/pinatas.dm
+++ b/code/game/objects/structures/pinatas.dm
@@ -28,7 +28,7 @@
. = ..()
if(get_integrity() < (max_integrity/2))
icon_state = "[base_icon_state]_damaged"
- if(damage_amount >= 10) // Swing means minimum damage threshhold for dropping candy is met.
+ if(damage_amount >= 10) // Swing means minimum damage threshold for dropping candy is met.
flick("[icon_state]_swing", src)
/obj/structure/pinata/play_attack_sound(damage_amount, damage_type, damage_flag)
diff --git a/code/game/objects/structures/plaques/_plaques.dm b/code/game/objects/structures/plaques/_plaques.dm
index 1277869dbf67f..951a538e7241a 100644
--- a/code/game/objects/structures/plaques/_plaques.dm
+++ b/code/game/objects/structures/plaques/_plaques.dm
@@ -88,7 +88,7 @@
var/namechoice = tgui_input_text(user, "Title this plaque. (e.g. 'Best HoP Award', 'Great Ashwalker War Memorial')", "Plaque Customization", max_length = MAX_NAME_LEN)
if(!namechoice)
return
- var/descriptionchoice = tgui_input_text(user, "Engrave this plaque's text", "Plaque Customization")
+ var/descriptionchoice = tgui_input_text(user, "Engrave this plaque's text", "Plaque Customization", max_length = MAX_PLAQUE_LEN)
if(!descriptionchoice)
return
if(!Adjacent(user)) //Make sure user is adjacent still
@@ -161,7 +161,7 @@
var/namechoice = tgui_input_text(user, "Title this plaque. (e.g. 'Best HoP Award', 'Great Ashwalker War Memorial')", "Plaque Customization", max_length = MAX_NAME_LEN)
if(!namechoice)
return
- var/descriptionchoice = tgui_input_text(user, "Engrave this plaque's text", "Plaque Customization")
+ var/descriptionchoice = tgui_input_text(user, "Engrave this plaque's text", "Plaque Customization", max_length = MAX_PLAQUE_LEN)
if(!descriptionchoice)
return
if(!Adjacent(user)) //Make sure user is adjacent still
diff --git a/code/game/objects/structures/railings.dm b/code/game/objects/structures/railings.dm
index 06a099ad4f906..fe2e4b06b4f10 100644
--- a/code/game/objects/structures/railings.dm
+++ b/code/game/objects/structures/railings.dm
@@ -4,7 +4,7 @@
icon = 'icons/obj/railings.dmi'
icon_state = "railing"
flags_1 = ON_BORDER_1
- obj_flags = CAN_BE_HIT | BLOCKS_CONSTRUCTION_DIR
+ obj_flags = CAN_BE_HIT | BLOCKS_CONSTRUCTION_DIR | IGNORE_DENSITY
density = TRUE
anchored = TRUE
pass_flags_self = LETPASSTHROW|PASSSTRUCTURE
diff --git a/code/game/objects/structures/signs/_signs.dm b/code/game/objects/structures/signs/_signs.dm
index 9268cb9c059ce..d3713ca1b2f68 100644
--- a/code/game/objects/structures/signs/_signs.dm
+++ b/code/game/objects/structures/signs/_signs.dm
@@ -12,7 +12,7 @@
var/buildable_sign = TRUE
///This determines if you can select this sign type when using a pen on a sign backing. False by default, set to true per sign type to override.
var/is_editable = FALSE
- ///sign_change_name is used to make nice looking, alphebetized and categorized names when you use a pen on any sign item or structure which is_editable.
+ ///sign_change_name is used to make nice looking, alphabetized and categorized names when you use a pen on any sign item or structure which is_editable.
var/sign_change_name
///Callback to the knock down proc for wallmounting behavior.
var/knock_down_callback
@@ -135,7 +135,7 @@
unwrenched_sign.setDir(dir)
qdel(src) //The sign structure on the wall goes poof and only the sign item from unwrenching remains.
-/obj/structure/sign/blank //This subtype is necessary for now because some other things (posters, picture frames, paintings) inheret from the parent type.
+/obj/structure/sign/blank //This subtype is necessary for now because some other things (posters, picture frames, paintings) inherit from the parent type.
icon_state = "backing"
name = "sign backing"
desc = "A plastic sign backing, use a pen to change the decal. It can be detached from the wall with a wrench."
diff --git a/code/game/objects/structures/tables_racks.dm b/code/game/objects/structures/tables_racks.dm
index 8dc8d82ff5f7d..32e76bb2c83ee 100644
--- a/code/game/objects/structures/tables_racks.dm
+++ b/code/game/objects/structures/tables_racks.dm
@@ -55,6 +55,8 @@
AddElement(/datum/element/give_turf_traits, give_turf_traits)
register_context()
+ ADD_TRAIT(src, TRAIT_COMBAT_MODE_SKIP_INTERACTION, INNATE_TRAIT)
+
///Adds the element used to make the object climbable, and also the one that shift the mob buckled to it up.
/obj/structure/table/proc/make_climbable()
AddElement(/datum/element/climbable)
@@ -224,36 +226,24 @@
deconstruct(TRUE)
return ITEM_INTERACT_SUCCESS
-/obj/structure/table/item_interaction_secondary(mob/living/user, obj/item/tool, list/modifiers)
- if(istype(tool, /obj/item/construction/rcd))
- return NONE
+// This extends base item interaction because tables default to blocking 99% of interactions
+/obj/structure/table/base_item_interaction(mob/living/user, obj/item/tool, list/modifiers)
+ . = ..()
+ if(.)
+ return .
- var/deck_act_value = NONE
if(istype(tool, /obj/item/toy/cards/deck))
- deck_act_value = deck_act(user, tool, modifiers, TRUE)
- // Continue to placing if we don't do anything else
- if(deck_act_value != NONE)
- return deck_act_value
-
- if(!user.combat_mode)
- return table_place_act(user, tool, modifiers)
-
- return NONE
-
-/obj/structure/table/item_interaction(mob/living/user, obj/item/tool, list/modifiers)
- . = NONE
+ . = deck_act(user, tool, modifiers, !!LAZYACCESS(modifiers, RIGHT_CLICK))
if(istype(tool, /obj/item/storage/bag/tray))
. = tray_act(user, tool)
- else if(istype(tool, /obj/item/toy/cards/deck))
- . = deck_act(user, tool, modifiers, FALSE)
else if(istype(tool, /obj/item/riding_offhand))
. = riding_offhand_act(user, tool)
// Continue to placing if we don't do anything else
- if(. != NONE)
+ if(.)
return .
- if(!user.combat_mode)
+ if(!user.combat_mode || (tool.item_flags & NOBLUDGEON))
return table_place_act(user, tool, modifiers)
return NONE
@@ -865,6 +855,7 @@
AddElement(/datum/element/climbable)
AddElement(/datum/element/elevation, pixel_shift = 12)
register_context()
+ ADD_TRAIT(src, TRAIT_COMBAT_MODE_SKIP_INTERACTION, INNATE_TRAIT)
/obj/structure/rack/add_context(atom/source, list/context, obj/item/held_item, mob/living/user)
if(isnull(held_item))
@@ -892,8 +883,11 @@
deconstruct(TRUE)
return ITEM_INTERACT_SUCCESS
-/obj/structure/rack/item_interaction(mob/living/user, obj/item/tool, list/modifiers)
- if((tool.item_flags & ABSTRACT) || user.combat_mode)
+/obj/structure/rack/base_item_interaction(mob/living/user, obj/item/tool, list/modifiers)
+ . = ..()
+ if(.)
+ return .
+ if((tool.item_flags & ABSTRACT) || (user.combat_mode && !(tool.item_flags & NOBLUDGEON)))
return NONE
if(user.transferItemToLoc(tool, drop_location(), silent = FALSE))
return ITEM_INTERACT_SUCCESS
diff --git a/code/game/objects/structures/tank_dispenser.dm b/code/game/objects/structures/tank_dispenser.dm
index 2d16ea30a69e4..46c18d85b407f 100644
--- a/code/game/objects/structures/tank_dispenser.dm
+++ b/code/game/objects/structures/tank_dispenser.dm
@@ -71,7 +71,7 @@
oxygentanks++
else
full = TRUE
- else if(!user.combat_mode)
+ else if(!user.combat_mode || (I.item_flags & NOBLUDGEON))
balloon_alert(user, "can't insert!")
return
else
diff --git a/code/game/objects/structures/votingbox.dm b/code/game/objects/structures/votingbox.dm
index 42ccd62509304..55909978fe2f7 100644
--- a/code/game/objects/structures/votingbox.dm
+++ b/code/game/objects/structures/votingbox.dm
@@ -94,7 +94,7 @@
ui_interact(user)
/obj/structure/votebox/proc/set_description(mob/user)
- var/new_description = tgui_input_text(user, "Enter a new description", "Vote Description", vote_description, multiline = TRUE)
+ var/new_description = tgui_input_text(user, "Enter a new description", "Vote Description", vote_description, multiline = TRUE, max_length = MAX_DESC_LEN)
if(new_description)
vote_description = new_description
diff --git a/code/game/objects/structures/water_structures/sink.dm b/code/game/objects/structures/water_structures/sink.dm
index 878dab578a52e..1cd3f7d7aaa53 100644
--- a/code/game/objects/structures/water_structures/sink.dm
+++ b/code/game/objects/structures/water_structures/sink.dm
@@ -204,7 +204,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/sink, (-14))
if(O.item_flags & ABSTRACT) //Abstract items like grabs won't wash. No-drop items will though because it's still technically an item in your hand.
return
- if(!user.combat_mode)
+ if(!user.combat_mode || (O.item_flags & NOBLUDGEON))
to_chat(user, span_notice("You start washing [O]..."))
busy = TRUE
if(!do_after(user, 4 SECONDS, target = src))
diff --git a/code/game/objects/structures/water_structures/water_source.dm b/code/game/objects/structures/water_structures/water_source.dm
index 9420156d91805..a59051f92dd50 100644
--- a/code/game/objects/structures/water_structures/water_source.dm
+++ b/code/game/objects/structures/water_structures/water_source.dm
@@ -114,7 +114,7 @@
attacking_item.use(1)
return
- if(!user.combat_mode)
+ if(!user.combat_mode || (attacking_item.item_flags & NOBLUDGEON))
to_chat(user, span_notice("You start washing [attacking_item]..."))
busy = TRUE
if(!do_after(user, 4 SECONDS, target = src))
diff --git a/code/game/objects/structures/windoor_assembly.dm b/code/game/objects/structures/windoor_assembly.dm
index 4c22cbf01b29d..4ff29eb606e8f 100644
--- a/code/game/objects/structures/windoor_assembly.dm
+++ b/code/game/objects/structures/windoor_assembly.dm
@@ -252,7 +252,7 @@
ae.forceMove(drop_location())
else if(IS_WRITING_UTENSIL(W))
- var/t = tgui_input_text(user, "Enter the name for the door", "Windoor Renaming", created_name, MAX_NAME_LEN)
+ var/t = tgui_input_text(user, "Enter the name for the door", "Windoor Renaming", created_name, max_length = MAX_NAME_LEN)
if(!t)
return
if(!in_range(src, usr) && loc != usr)
diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm
index f2a90d98dc52d..fdb5193035c84 100644
--- a/code/game/objects/structures/window.dm
+++ b/code/game/objects/structures/window.dm
@@ -505,7 +505,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/window/unanchored/spawner, 0)
switch(state)
if(RWINDOW_SECURE)
if(tool.tool_behaviour == TOOL_WELDER)
- if(tool.tool_start_check(user))
+ if(tool.tool_start_check(user, heat_required = HIGH_TEMPERATURE_REQUIRED))
user.visible_message(span_notice("[user] holds \the [tool] to the security screws on \the [src]..."),
span_notice("You begin heating the security screws on \the [src]..."))
if(tool.use_tool(src, user, 15 SECONDS, volume = 100))
diff --git a/code/game/shuttle_engines.dm b/code/game/shuttle_engines.dm
index 8ddae94231d31..52372448616c7 100644
--- a/code/game/shuttle_engines.dm
+++ b/code/game/shuttle_engines.dm
@@ -113,7 +113,7 @@
if(ENGINE_UNWRENCHED)
to_chat(user, span_warning("The [src.name] needs to be wrenched to the floor!"))
if(ENGINE_WRENCHED)
- if(!tool.tool_start_check(user, amount=round(ENGINE_WELDTIME / 5)))
+ if(!tool.tool_start_check(user, amount=round(ENGINE_WELDTIME / 5), heat_required = HIGH_TEMPERATURE_REQUIRED))
return TRUE
user.visible_message(span_notice("[user.name] starts to weld the [name] to the floor."), \
@@ -126,7 +126,7 @@
alter_engine_power(engine_power)
if(ENGINE_WELDED)
- if(!tool.tool_start_check(user, amount=round(ENGINE_WELDTIME / 5)))
+ if(!tool.tool_start_check(user, amount=round(ENGINE_WELDTIME / 5), heat_required = HIGH_TEMPERATURE_REQUIRED))
return TRUE
user.visible_message(span_notice("[user.name] starts to cut the [name] free from the floor."), \
diff --git a/code/game/turfs/closed/_closed.dm b/code/game/turfs/closed/_closed.dm
index 8ccaabc46c0af..cf287a6eb6d88 100644
--- a/code/game/turfs/closed/_closed.dm
+++ b/code/game/turfs/closed/_closed.dm
@@ -15,3 +15,6 @@
/turf/closed/get_smooth_underlay_icon(mutable_appearance/underlay_appearance, turf/asking_turf, adjacency_dir)
return FALSE
+
+/turf/closed/examine_descriptor(mob/user)
+ return "wall"
diff --git a/code/game/turfs/closed/wall/reinf_walls.dm b/code/game/turfs/closed/wall/reinf_walls.dm
index e94a31eeafef4..739ee5aeae0f4 100644
--- a/code/game/turfs/closed/wall/reinf_walls.dm
+++ b/code/game/turfs/closed/wall/reinf_walls.dm
@@ -76,7 +76,7 @@
if(COVER)
if(W.tool_behaviour == TOOL_WELDER)
- if(!W.tool_start_check(user, amount=2))
+ if(!W.tool_start_check(user, amount=2, heat_required = HIGH_TEMPERATURE_REQUIRED))
return
to_chat(user, span_notice("You begin slicing through the metal cover..."))
if(W.use_tool(src, user, 60, volume=100))
@@ -109,7 +109,7 @@
return TRUE
if(W.tool_behaviour == TOOL_WELDER)
- if(!W.tool_start_check(user, amount=2))
+ if(!W.tool_start_check(user, amount=2, heat_required = HIGH_TEMPERATURE_REQUIRED))
return
to_chat(user, span_notice("You begin welding the metal cover back to the frame..."))
if(W.use_tool(src, user, 60, volume=100))
@@ -143,7 +143,7 @@
if(SUPPORT_RODS)
if(W.tool_behaviour == TOOL_WELDER)
- if(!W.tool_start_check(user, amount=2))
+ if(!W.tool_start_check(user, amount=2, heat_required = HIGH_TEMPERATURE_REQUIRED))
return
to_chat(user, span_notice("You begin slicing through the support rods..."))
if(W.use_tool(src, user, 100, volume=100))
@@ -176,7 +176,7 @@
return TRUE
if(W.tool_behaviour == TOOL_WELDER)
- if(!W.tool_start_check(user, amount=0))
+ if(!W.tool_start_check(user, amount=0, heat_required = HIGH_TEMPERATURE_REQUIRED))
return
to_chat(user, span_notice("You begin welding the support rods back together..."))
if(W.use_tool(src, user, 100, volume=100))
diff --git a/code/game/turfs/closed/walls.dm b/code/game/turfs/closed/walls.dm
index a78579d713e9a..0fbe774a7c5ae 100644
--- a/code/game/turfs/closed/walls.dm
+++ b/code/game/turfs/closed/walls.dm
@@ -117,7 +117,6 @@
GLOB.station_turfs -= src
return ..()
-
/turf/closed/wall/examine(mob/user)
. += ..()
. += deconstruction_hints(user)
@@ -238,23 +237,18 @@
playsound(src, 'sound/weapons/genhit.ogg', 25, TRUE)
add_fingerprint(user)
-/turf/closed/wall/attackby(obj/item/W, mob/user, params)
- user.changeNext_move(CLICK_CD_MELEE)
+/turf/closed/wall/item_interaction(mob/living/user, obj/item/tool, list/modifiers)
if (!ISADVANCEDTOOLUSER(user))
to_chat(user, span_warning("You don't have the dexterity to do this!"))
- return
-
- //get the user's location
- if(!isturf(user.loc))
- return //can't do this stuff whilst inside objects and such
+ return ITEM_INTERACT_BLOCKING
add_fingerprint(user)
//the istype cascade has been spread among various procs for easy overriding
- if(try_clean(W, user) || try_wallmount(W, user) || try_decon(W, user))
- return
+ if(try_clean(tool, user) || try_wallmount(tool, user) || try_decon(tool, user))
+ return ITEM_INTERACT_SUCCESS
- return ..()
+ return NONE
/turf/closed/wall/proc/try_clean(obj/item/W, mob/living/user)
if((user.combat_mode) || !LAZYLEN(dent_decals))
@@ -290,7 +284,7 @@
/turf/closed/wall/proc/try_decon(obj/item/I, mob/user)
if(I.tool_behaviour == TOOL_WELDER)
- if(!I.tool_start_check(user, amount=round(slicing_duration / 50)))
+ if(!I.tool_start_check(user, amount=round(slicing_duration / 50), heat_required = HIGH_TEMPERATURE_REQUIRED))
return FALSE
to_chat(user, span_notice("You begin slicing through the outer plating..."))
diff --git a/code/game/turfs/open/_open.dm b/code/game/turfs/open/_open.dm
index f9b374c88cb88..01478f4d9f02b 100644
--- a/code/game/turfs/open/_open.dm
+++ b/code/game/turfs/open/_open.dm
@@ -74,6 +74,9 @@
. += burnt_appearance
+/turf/open/examine_descriptor(mob/user)
+ return "floor"
+
//direction is direction of travel of A
/turf/open/zPassIn(direction)
if(direction != DOWN)
diff --git a/code/game/turfs/open/floor.dm b/code/game/turfs/open/floor.dm
index 84b9ac26e9b8d..dad46fd8de6b6 100644
--- a/code/game/turfs/open/floor.dm
+++ b/code/game/turfs/open/floor.dm
@@ -14,8 +14,8 @@
smoothing_groups = SMOOTH_GROUP_TURF_OPEN + SMOOTH_GROUP_OPEN_FLOOR
canSmoothWith = SMOOTH_GROUP_TURF_OPEN + SMOOTH_GROUP_OPEN_FLOOR
- thermal_conductivity = 0.04
- heat_capacity = 10000
+ thermal_conductivity = 0.02
+ heat_capacity = 20000
tiled_dirt = TRUE
diff --git a/code/game/turfs/open/floor/reinforced_floor.dm b/code/game/turfs/open/floor/reinforced_floor.dm
index 0a44c78ceca5e..dcba9ed36673a 100644
--- a/code/game/turfs/open/floor/reinforced_floor.dm
+++ b/code/game/turfs/open/floor/reinforced_floor.dm
@@ -4,7 +4,7 @@
desc = "Extremely sturdy."
icon_state = "engine"
holodeck_compatible = TRUE
- thermal_conductivity = 0.025
+ thermal_conductivity = 0.01
heat_capacity = INFINITY
floor_tile = /obj/item/stack/rods
footstep = FOOTSTEP_PLATING
diff --git a/code/game/turfs/open/ice.dm b/code/game/turfs/open/ice.dm
index dbfff2efc8f91..f28bc8dd4b052 100644
--- a/code/game/turfs/open/ice.dm
+++ b/code/game/turfs/open/ice.dm
@@ -53,6 +53,7 @@
return NONE
balloon_alert(user, "dug hole")
AddComponent(/datum/component/fishing_spot, GLOB.preset_fish_sources[/datum/fish_source/ice_fishing])
+ ADD_TRAIT(src, TRAIT_CATCH_AND_RELEASE, INNATE_TRAIT)
add_overlay(mutable_appearance('icons/turf/overlays.dmi', "ice_hole"))
can_make_hole = FALSE
RemoveElement(/datum/element/contextual_screentip_tools, tool_screentips)
diff --git a/code/game/turfs/open/lava.dm b/code/game/turfs/open/lava.dm
index 23e2b6b38db84..c080e228438a5 100644
--- a/code/game/turfs/open/lava.dm
+++ b/code/game/turfs/open/lava.dm
@@ -48,6 +48,8 @@
. = ..()
if(fish_source_type)
AddElement(/datum/element/lazy_fishing_spot, fish_source_type)
+ // You can release chrabs and lavaloops and likes in lava, or be an absolute scumbag and drop other fish there too.
+ ADD_TRAIT(src, TRAIT_CATCH_AND_RELEASE, INNATE_TRAIT)
refresh_light()
if(!smoothing_flags)
update_appearance()
diff --git a/code/game/turfs/open/misc.dm b/code/game/turfs/open/misc.dm
index 5c5987f656e23..f00e6ed6ded6e 100644
--- a/code/game/turfs/open/misc.dm
+++ b/code/game/turfs/open/misc.dm
@@ -17,8 +17,8 @@
smoothing_groups = SMOOTH_GROUP_TURF_OPEN
canSmoothWith = SMOOTH_GROUP_TURF_OPEN + SMOOTH_GROUP_OPEN_FLOOR
- thermal_conductivity = 0.04
- heat_capacity = 10000
+ thermal_conductivity = 0.02
+ heat_capacity = 20000
tiled_dirt = TRUE
/turf/open/misc/attackby(obj/item/W, mob/user, params)
diff --git a/code/game/turfs/open/water.dm b/code/game/turfs/open/water.dm
index de895754d03ae..835d29089181b 100644
--- a/code/game/turfs/open/water.dm
+++ b/code/game/turfs/open/water.dm
@@ -1,4 +1,5 @@
/turf/open/water
+ name = "water"
gender = PLURAL
desc = "Shallow water."
icon = 'icons/turf/floors.dmi'
@@ -29,6 +30,7 @@
AddElement(/datum/element/watery_tile)
if(!isnull(fishing_datum))
AddElement(/datum/element/lazy_fishing_spot, fishing_datum)
+ ADD_TRAIT(src, TRAIT_CATCH_AND_RELEASE, INNATE_TRAIT)
/turf/open/water/jungle
diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm
index b0493ce0a8ad4..19356c2e32309 100644
--- a/code/game/turfs/turf.dm
+++ b/code/game/turfs/turf.dm
@@ -32,7 +32,7 @@ GLOBAL_LIST_EMPTY(station_turfs)
var/temperature = T20C
///Used for fire, if a melting temperature was reached, it will be destroyed
var/to_be_destroyed = 0
- ///The max temperature of the fire which it was subjected to
+ ///The max temperature of the fire which it was subjected to, determines the melting point of turf
var/max_fire_temperature_sustained = 0
var/blocks_air = FALSE
@@ -231,7 +231,7 @@ GLOBAL_LIST_EMPTY(station_turfs)
/// Call to move a turf from its current area to a new one
/turf/proc/change_area(area/old_area, area/new_area)
- //dont waste our time
+ //don't waste our time
if(old_area == new_area)
return
@@ -277,7 +277,7 @@ GLOBAL_LIST_EMPTY(station_turfs)
// We don't want to block ourselves
if((movable_content == source_atom))
continue
- // dont consider ignored atoms or their types
+ // don't consider ignored atoms or their types
if(length(ignore_atoms))
if(!type_list && (movable_content in ignore_atoms))
continue
@@ -306,7 +306,7 @@ GLOBAL_LIST_EMPTY(station_turfs)
return TRUE
return FALSE
-//The zpass procs exist to be overriden, not directly called
+//The zpass procs exist to be overridden, not directly called
//use can_z_pass for that
///If we'd allow anything to travel into us
/turf/proc/zPassIn(direction)
@@ -426,7 +426,7 @@ GLOBAL_LIST_EMPTY(station_turfs)
if(thing == mover || thing == mover_loc) // Multi tile objects and moving out of other objects
continue
if(!thing.Cross(mover))
- if(QDELETED(mover)) //deleted from Cross() (CanPass is pure so it cant delete, Cross shouldnt be doing this either though, but it can happen)
+ if(QDELETED(mover)) //deleted from Cross() (CanPass is pure so it can't delete, Cross shouldn't be doing this either though, but it can happen)
return FALSE
if(mover_is_phasing)
mover.Bump(thing)
diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm
index 68096367ef80b..1510783fc7cb8 100644
--- a/code/modules/admin/admin_verbs.dm
+++ b/code/modules/admin/admin_verbs.dm
@@ -320,7 +320,7 @@ ADMIN_VERB(give_mob_action, R_FUN, "Give Mob Action", ADMIN_VERB_NO_DESCRIPTION,
if(isnull(ability_melee_cooldown) || ability_melee_cooldown < 0)
ability_melee_cooldown = 2
add_ability.melee_cooldown_time = ability_melee_cooldown * 1 SECONDS
- add_ability.name = tgui_input_text(user, "Choose ability name", "Ability name", "Generic Ability")
+ add_ability.name = tgui_input_text(user, "Choose ability name", "Ability name", "Generic Ability", max_length = MAX_NAME_LEN)
add_ability.create_sequence_actions()
else
add_ability = new ability_type(ability_recipient)
@@ -523,7 +523,7 @@ ADMIN_VERB(spawn_debug_full_crew, R_DEBUG, "Spawn Debug Full Crew", "Creates a f
// Then, spawn a human and slap a person into it.
var/number_made = 0
for(var/rank in SSjob.name_occupations)
- var/datum/job/job = SSjob.GetJob(rank)
+ var/datum/job/job = SSjob.get_job(rank)
// JOB_CREW_MEMBER is all jobs that pretty much aren't silicon
if(!(job.job_flags & JOB_CREW_MEMBER))
@@ -535,7 +535,7 @@ ADMIN_VERB(spawn_debug_full_crew, R_DEBUG, "Spawn Debug Full Crew", "Creates a f
new_guy.mind.name = "[rank] Dummy"
// Assign the rank to the new player dummy.
- if(!SSjob.AssignRole(new_guy, job, do_eligibility_checks = FALSE))
+ if(!SSjob.assign_role(new_guy, job, do_eligibility_checks = FALSE))
qdel(new_guy)
to_chat(user, "[rank] wasn't able to be spawned.")
continue
@@ -547,7 +547,7 @@ ADMIN_VERB(spawn_debug_full_crew, R_DEBUG, "Spawn Debug Full Crew", "Creates a f
qdel(new_guy)
// Then equip up the human with job gear.
- SSjob.EquipRank(character, job)
+ SSjob.equip_rank(character, job)
job.after_latejoin_spawn(character)
// Finally, ensure the minds are tracked and in the manifest.
diff --git a/code/modules/admin/outfit_editor.dm b/code/modules/admin/outfit_editor.dm
index 67196c54bd434..a3bd433f52e40 100644
--- a/code/modules/admin/outfit_editor.dm
+++ b/code/modules/admin/outfit_editor.dm
@@ -100,7 +100,7 @@
drip.vars[slot] = null
if("rename")
- var/newname = tgui_input_text(owner, "What do you want to name this outfit?", OUTFIT_EDITOR_NAME)
+ var/newname = tgui_input_text(owner, "What do you want to name this outfit?", OUTFIT_EDITOR_NAME, max_length = MAX_NAME_LEN)
if(newname)
drip.name = newname
if("save")
diff --git a/code/modules/admin/painting_manager.dm b/code/modules/admin/painting_manager.dm
index 7a8bd7127a4d3..5ebcdef005904 100644
--- a/code/modules/admin/painting_manager.dm
+++ b/code/modules/admin/painting_manager.dm
@@ -55,7 +55,7 @@ ADMIN_VERB(painting_manager, R_ADMIN, "Paintings Manager", "View and redact pain
if("rename")
//Modify the metadata
var/old_title = chosen_painting.title
- var/new_title = tgui_input_text(user, "New painting title?", "Painting Rename", chosen_painting.title)
+ var/new_title = tgui_input_text(user, "New painting title?", "Painting Rename", chosen_painting.title, max_length = MAX_NAME_LEN)
if(!new_title)
return
chosen_painting.title = new_title
@@ -63,7 +63,7 @@ ADMIN_VERB(painting_manager, R_ADMIN, "Paintings Manager", "View and redact pain
return TRUE
if("rename_author")
var/old_name = chosen_painting.creator_name
- var/new_name = tgui_input_text(user, "New painting author name?", "Painting Rename", chosen_painting.creator_name)
+ var/new_name = tgui_input_text(user, "New painting author name?", "Painting Rename", chosen_painting.creator_name, max_length = MAX_NAME_LEN)
if(!new_name)
return
chosen_painting.creator_name = new_name
@@ -83,7 +83,7 @@ ADMIN_VERB(painting_manager, R_ADMIN, "Paintings Manager", "View and redact pain
log_admin("[key_name(user)] has removed tag [params["tag"]] from persistent painting made by [chosen_painting.creator_ckey] with id [chosen_painting.md5].")
return TRUE
if("add_tag")
- var/tag_name = tgui_input_text(user, "New tag name?", "Add Tag")
+ var/tag_name = tgui_input_text(user, "New tag name?", "Add Tag", max_length = MAX_NAME_LEN)
if(!tag_name)
return
if(!chosen_painting.tags)
diff --git a/code/modules/admin/sound_emitter.dm b/code/modules/admin/sound_emitter.dm
index d697537c6df5f..c68baa32e4ea1 100644
--- a/code/modules/admin/sound_emitter.dm
+++ b/code/modules/admin/sound_emitter.dm
@@ -81,7 +81,7 @@
return
var/mob/user = usr
if(href_list["edit_label"])
- var/new_label = tgui_input_text(user, "Choose a new label", "Sound Emitter")
+ var/new_label = tgui_input_text(user, "Choose a new label", "Sound Emitter", max_length = MAX_NAME_LEN)
if(!new_label)
return
maptext = MAPTEXT(new_label)
diff --git a/code/modules/admin/verbs/admin.dm b/code/modules/admin/verbs/admin.dm
index 37c50f53225ce..a0d772f665fe1 100644
--- a/code/modules/admin/verbs/admin.dm
+++ b/code/modules/admin/verbs/admin.dm
@@ -32,7 +32,7 @@ ADMIN_VERB(unprison, R_ADMIN, "UnPrison", ADMIN_VERB_NO_DESCRIPTION, ADMIN_CATEG
tgui_alert(user, "[prisoner.name] is not prisoned.")
return
- SSjob.SendToLateJoin(prisoner)
+ SSjob.send_to_late_join(prisoner)
message_admins("[key_name_admin(user)] has unprisoned [key_name_admin(prisoner)]")
log_admin("[key_name(user)] has unprisoned [key_name(prisoner)]")
BLACKBOX_LOG_ADMIN_VERB("Unprison")
diff --git a/code/modules/admin/verbs/admin_newscaster.dm b/code/modules/admin/verbs/admin_newscaster.dm
index 4cb7b5c3344e2..b1be5560d69d9 100644
--- a/code/modules/admin/verbs/admin_newscaster.dm
+++ b/code/modules/admin/verbs/admin_newscaster.dm
@@ -234,14 +234,14 @@ ADMIN_VERB(access_news_network, R_ADMIN, "Access Newscaster Network", "Allows yo
return TRUE
if("setCriminalName")
- var/temp_name = tgui_input_text(usr, "Write the Criminal's Name", "Warrent Alert Handler", "John Doe", MAX_NAME_LEN, multiline = FALSE)
+ var/temp_name = tgui_input_text(usr, "Write the Criminal's Name", "Warrent Alert Handler", "John Doe", max_length = MAX_NAME_LEN, multiline = FALSE)
if(!temp_name)
return TRUE
criminal_name = temp_name
return TRUE
if("setCrimeData")
- var/temp_desc = tgui_input_text(usr, "Write the Criminal's Crimes", "Warrent Alert Handler", "Unknown", MAX_BROADCAST_LEN, multiline = TRUE)
+ var/temp_desc = tgui_input_text(usr, "Write the Criminal's Crimes", "Warrent Alert Handler", "Unknown", max_length = MAX_BROADCAST_LEN, multiline = TRUE)
if(!temp_desc)
return TRUE
crime_description = temp_desc
@@ -339,7 +339,7 @@ ADMIN_VERB(access_news_network, R_ADMIN, "Access Newscaster Network", "Allows yo
if(channel_name == potential_channel.channel_ID)
current_channel = potential_channel
break
- var/temp_message = tgui_input_text(usr, "Write your Feed story", "Network Channel Handler", feed_channel_message, multiline = TRUE)
+ var/temp_message = tgui_input_text(usr, "Write your Feed story", "Network Channel Handler", feed_channel_message, max_length = MAX_BROADCAST_LEN, multiline = TRUE)
if(length(temp_message) <= 1)
return TRUE
if(temp_message)
diff --git a/code/modules/admin/verbs/adminevents.dm b/code/modules/admin/verbs/adminevents.dm
index 214cf653d4e1f..d2eeba90262cf 100644
--- a/code/modules/admin/verbs/adminevents.dm
+++ b/code/modules/admin/verbs/adminevents.dm
@@ -269,13 +269,21 @@ ADMIN_VERB(command_report_footnote, R_ADMIN, "Command Report Footnote", "Adds a
var/datum/command_footnote/command_report_footnote = new /datum/command_footnote()
GLOB.communications_controller.block_command_report += 1 //Add a blocking condition to the counter until the inputs are done.
- command_report_footnote.message = tgui_input_text(user, "This message will be attached to the bottom of the roundstart threat report. Be sure to delay the roundstart report if you need extra time.", "P.S.")
+ command_report_footnote.message = tgui_input_text(
+ user,
+ "This message will be attached to the bottom of the roundstart threat report. Be sure to delay the roundstart report if you need extra time.",
+ "P.S.",
+ )
if(!command_report_footnote.message)
GLOB.communications_controller.block_command_report -= 1
qdel(command_report_footnote)
return
- command_report_footnote.signature = tgui_input_text(user, "Whose signature will appear on this footnote?", "Also sign here, here, aaand here.")
+ command_report_footnote.signature = tgui_input_text(
+ user,
+ "Whose signature will appear on this footnote?",
+ "Also sign here, here, aaand here.",
+ )
if(!command_report_footnote.signature)
command_report_footnote.signature = "Classified"
diff --git a/code/modules/admin/verbs/admingame.dm b/code/modules/admin/verbs/admingame.dm
index 5982f62e5a904..488c670a19d4b 100644
--- a/code/modules/admin/verbs/admingame.dm
+++ b/code/modules/admin/verbs/admingame.dm
@@ -153,20 +153,24 @@ ADMIN_VERB_ONLY_CONTEXT_MENU(show_player_panel, R_ADMIN, "Show Player Panel", mo
user << browse(body, "window=adminplayeropts-[REF(player)];size=550x515")
BLACKBOX_LOG_ADMIN_VERB("Player Panel")
-/client/proc/cmd_admin_godmode(mob/M in GLOB.mob_list)
+/client/proc/cmd_admin_godmode(mob/mob in GLOB.mob_list)
set category = "Admin.Game"
set name = "Godmode"
if(!check_rights(R_ADMIN))
return
- M.status_flags ^= GODMODE
- to_chat(usr, span_adminnotice("Toggled [(M.status_flags & GODMODE) ? "ON" : "OFF"]"), confidential = TRUE)
+ var/had_trait = HAS_TRAIT_FROM(mob, TRAIT_GODMODE, ADMIN_TRAIT)
+ if(had_trait)
+ REMOVE_TRAIT(mob, TRAIT_GODMODE, ADMIN_TRAIT)
+ else
+ ADD_TRAIT(mob, TRAIT_GODMODE, ADMIN_TRAIT)
+ to_chat(usr, span_adminnotice("Toggled [had_trait ? "OFF" : "ON"]"), confidential = TRUE)
- log_admin("[key_name(usr)] has toggled [key_name(M)]'s nodamage to [(M.status_flags & GODMODE) ? "On" : "Off"]")
- var/msg = "[key_name_admin(usr)] has toggled [ADMIN_LOOKUPFLW(M)]'s nodamage to [(M.status_flags & GODMODE) ? "On" : "Off"]"
+ log_admin("[key_name(usr)] has toggled [key_name(mob)]'s nodamage to [had_trait ? "Off" : "On"]")
+ var/msg = "[key_name_admin(usr)] has toggled [ADMIN_LOOKUPFLW(mob)]'s nodamage to [had_trait ? "Off" : "On"]"
message_admins(msg)
- admin_ticket_log(M, msg)
- SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Godmode", "[M.status_flags & GODMODE ? "Enabled" : "Disabled"]")) // If you are copy-pasting this, ensure the 4th parameter is unique to the new proc!
+ admin_ticket_log(mob, msg)
+ SSblackbox.record_feedback("nested tally", "admin_toggle", 1, list("Godmode", "[had_trait ? "Disabled" : "Enabled"]")) // If you are copy-pasting this, ensure the 4th parameter is unique to the new proc!
/*
If a guy was gibbed and you want to revive him, this is a good way to do so.
@@ -193,7 +197,7 @@ ADMIN_VERB(respawn_character, R_ADMIN, "Respawn Character", "Respawn a player th
if(findtext(G_found.real_name,"monkey"))
if(tgui_alert(user,"This character appears to have been a monkey. Would you like to respawn them as such?",,list("Yes","No")) == "Yes")
var/mob/living/carbon/human/species/monkey/new_monkey = new
- SSjob.SendToLateJoin(new_monkey)
+ SSjob.send_to_late_join(new_monkey)
G_found.mind.transfer_to(new_monkey) //be careful when doing stuff like this! I've already checked the mind isn't in use
new_monkey.key = G_found.key
to_chat(new_monkey, "You have been fully respawned. Enjoy the game.", confidential = TRUE)
@@ -205,7 +209,7 @@ ADMIN_VERB(respawn_character, R_ADMIN, "Respawn Character", "Respawn a player th
//Ok, it's not a monkey. So, spawn a human.
var/mob/living/carbon/human/new_character = new//The mob being spawned.
- SSjob.SendToLateJoin(new_character)
+ SSjob.send_to_late_join(new_character)
var/datum/record/locked/record_found //Referenced to later to either randomize or not randomize the character.
if(G_found.mind && !G_found.mind.active) //mind isn't currently in use by someone/something
@@ -228,7 +232,7 @@ ADMIN_VERB(respawn_character, R_ADMIN, "Respawn Character", "Respawn a player th
else
new_character.mind_initialize()
if(is_unassigned_job(new_character.mind.assigned_role))
- new_character.mind.set_assigned_role(SSjob.GetJobType(SSjob.overflow_role))
+ new_character.mind.set_assigned_role(SSjob.get_job_type(SSjob.overflow_role))
new_character.key = G_found.key
@@ -245,7 +249,7 @@ ADMIN_VERB(respawn_character, R_ADMIN, "Respawn Character", "Respawn a player th
//Now for special roles and equipment.
var/datum/antagonist/traitor/traitordatum = new_character.mind.has_antag_datum(/datum/antagonist/traitor)
if(traitordatum)
- SSjob.EquipRank(new_character, new_character.mind.assigned_role, new_character.client)
+ SSjob.equip_rank(new_character, new_character.mind.assigned_role, new_character.client)
new_character.mind.give_uplink(silent = TRUE, antag_datum = traitordatum)
switch(new_character.mind.special_role)
@@ -274,7 +278,7 @@ ADMIN_VERB(respawn_character, R_ADMIN, "Respawn Character", "Respawn a player th
new_character = new_character.AIize()
else
if(!traitordatum) // Already equipped there.
- SSjob.EquipRank(new_character, new_character.mind.assigned_role, new_character.client)//Or we simply equip them.
+ SSjob.equip_rank(new_character, new_character.mind.assigned_role, new_character.client)//Or we simply equip them.
//Announces the character on all the systems, based on the record.
if(!record_found && (new_character.mind.assigned_role.job_flags & JOB_CREW_MEMBER))
diff --git a/code/modules/admin/verbs/ai_triumvirate.dm b/code/modules/admin/verbs/ai_triumvirate.dm
index d63994a25c319..38c2eba712c60 100644
--- a/code/modules/admin/verbs/ai_triumvirate.dm
+++ b/code/modules/admin/verbs/ai_triumvirate.dm
@@ -36,7 +36,7 @@ GLOBAL_DATUM(triple_ai_controller, /datum/triple_ai_controller)
to_chat(usr, "This option is currently only usable during pregame. This may change at a later date.", confidential = TRUE)
return
- var/datum/job/job = SSjob.GetJobType(/datum/job/ai)
+ var/datum/job/job = SSjob.get_job_type(/datum/job/ai)
if(!job)
to_chat(usr, "Unable to locate the AI job", confidential = TRUE)
CRASH("triple_ai() called, no /datum/job/ai to be found.")
diff --git a/code/modules/admin/verbs/ert.dm b/code/modules/admin/verbs/ert.dm
index 441a5d0dd56fe..23f1627503e06 100644
--- a/code/modules/admin/verbs/ert.dm
+++ b/code/modules/admin/verbs/ert.dm
@@ -248,7 +248,7 @@
ert_antag.random_names = ertemplate.random_names
ert_operative.mind.add_antag_datum(ert_antag,ert_team)
- ert_operative.mind.set_assigned_role(SSjob.GetJobType(ert_antag.ert_job_path))
+ ert_operative.mind.set_assigned_role(SSjob.get_job_type(ert_antag.ert_job_path))
//Logging and cleanup
ert_operative.log_message("has been selected as \a [ert_antag.name].", LOG_GAME)
diff --git a/code/modules/admin/verbs/lawpanel.dm b/code/modules/admin/verbs/lawpanel.dm
index f1daaf175761f..6de3ff70182b8 100644
--- a/code/modules/admin/verbs/lawpanel.dm
+++ b/code/modules/admin/verbs/lawpanel.dm
@@ -24,7 +24,7 @@ ADMIN_VERB(law_panel, R_ADMIN, "Law Panel", "View the AI laws.", ADMIN_CATEGORY_
var/lawtype = tgui_input_list(user, "Select law type", "Law type", lawtypes)
if(isnull(lawtype))
return FALSE
- var/lawtext = tgui_input_text(user, "Input law text", "Law text")
+ var/lawtext = tgui_input_text(user, "Input law text", "Law text") // admin verb so no max length and also any user-level input is config based already so ehhhh
if(!lawtext)
return FALSE
if(QDELETED(src) || QDELETED(borgo))
diff --git a/code/modules/admin/verbs/secrets.dm b/code/modules/admin/verbs/secrets.dm
index bcb89379ef40a..9012a8652bbff 100644
--- a/code/modules/admin/verbs/secrets.dm
+++ b/code/modules/admin/verbs/secrets.dm
@@ -84,7 +84,7 @@ ADMIN_VERB(secrets, R_NONE, "Secrets", "Abuse harder than you ever have before w
if("infinite_sec")
if(!is_debugger)
return
- var/datum/job/sec_job = SSjob.GetJobType(/datum/job/security_officer)
+ var/datum/job/sec_job = SSjob.get_job_type(/datum/job/security_officer)
sec_job.total_positions = -1
sec_job.spawn_positions = -1
message_admins("[key_name_admin(holder)] has removed the cap on security officers.")
diff --git a/code/modules/admin/view_variables/debug_variable_appearance.dm b/code/modules/admin/view_variables/debug_variable_appearance.dm
index 6d87f6cc85d86..c5a367e83a064 100644
--- a/code/modules/admin/view_variables/debug_variable_appearance.dm
+++ b/code/modules/admin/view_variables/debug_variable_appearance.dm
@@ -38,6 +38,9 @@
// can't use the name either for byond reasons
var/_vis_flags
+#if (MIN_COMPILER_VERSION > 515 || MIN_COMPILER_BUILD > 1643)
+#warn vis_flags should now be supported by mutable appearances so we can safely remove the weird copying in this code
+#endif
// all alone at the end of the universe
GLOBAL_DATUM_INIT(pluto, /atom/movable, new /atom/movable(null))
@@ -63,6 +66,28 @@ GLOBAL_DATUM_INIT(pluto, /atom/movable, new /atom/movable(null))
return FALSE
if(var_name == NAMEOF(src, realized_underlays))
return FALSE
+
+#if (MIN_COMPILER_VERSION >= 515 && MIN_COMPILER_BUILD >= 1643)
+#warn X/Y/Z and contents are now fully unviewable on our supported versions, remove the below check
+#endif
+
+// lummy removed these from the the MA/image type
+#if (DM_VERSION <= 515 && DM_BUILD < 1643)
+ // Filtering out the stuff I know we don't care about
+ if(var_name == NAMEOF(src, x))
+ return FALSE
+ if(var_name == NAMEOF(src, y))
+ return FALSE
+ if(var_name == NAMEOF(src, z))
+ return FALSE
+ #ifndef SPACEMAN_DMM // Spaceman doesn't believe in contents on appearances, sorry lads
+ if(var_name == NAMEOF(src, contents))
+ return FALSE
+ #endif
+ if(var_name == NAMEOF(src, loc))
+ return FALSE
+#endif
+ // Could make an argument for this but I think they will just confuse people, so yeeet
if(var_name == NAMEOF(src, vis_contents))
return FALSE
return ..()
diff --git a/code/modules/admin/view_variables/view_variables.dm b/code/modules/admin/view_variables/view_variables.dm
index 37bf0911c608f..66ac70f3f62f7 100644
--- a/code/modules/admin/view_variables/view_variables.dm
+++ b/code/modules/admin/view_variables/view_variables.dm
@@ -3,7 +3,7 @@
ADMIN_VERB_AND_CONTEXT_MENU(debug_variables, R_NONE, "View Variables", "View the variables of a datum.", ADMIN_CATEGORY_DEBUG, datum/thing in world)
user.debug_variables(thing)
-// This is kept as a seperate proc because admins are able to show VV to non-admins
+// This is kept as a separate proc because admins are able to show VV to non-admins
/client/proc/debug_variables(datum/thing in world)
set category = "Debug"
@@ -23,7 +23,7 @@ ADMIN_VERB_AND_CONTEXT_MENU(debug_variables, R_NONE, "View Variables", "View the
if(isappearance(thing))
thing = get_vv_appearance(thing) // this is /mutable_appearance/our_bs_subtype
- var/islist = islist(thing) || (!isdatum(thing) && hascall(thing, "Cut")) // Some special lists dont count as lists, but can be detected by if they have list procs
+ var/islist = islist(thing) || (!isdatum(thing) && hascall(thing, "Cut")) // Some special lists don't count as lists, but can be detected by if they have list procs
if(!islist && !isdatum(thing))
return
diff --git a/code/modules/antagonists/_common/antag_spawner.dm b/code/modules/antagonists/_common/antag_spawner.dm
index 5f7a7e579d3ee..da7c7e9e39cac 100644
--- a/code/modules/antagonists/_common/antag_spawner.dm
+++ b/code/modules/antagonists/_common/antag_spawner.dm
@@ -83,7 +83,7 @@
app.wiz_team = master_wizard.wiz_team
master_wizard.wiz_team.add_member(app_mind)
app_mind.add_antag_datum(app)
- app_mind.set_assigned_role(SSjob.GetJobType(/datum/job/wizard_apprentice))
+ app_mind.set_assigned_role(SSjob.get_job_type(/datum/job/wizard_apprentice))
app_mind.special_role = ROLE_WIZARD_APPRENTICE
SEND_SOUND(M, sound('sound/effects/magic.ogg'))
@@ -424,15 +424,7 @@
monkey_man.fully_replace_character_name(monkey_man.real_name, pick(GLOB.syndicate_monkey_names))
- monkey_man.dna.add_mutation(/datum/mutation/human/clever)
- // Can't make them human or nonclever. At least not with the easy and boring way out.
- for(var/datum/mutation/human/mutation as anything in monkey_man.dna.mutations)
- mutation.mutadone_proof = TRUE
- mutation.instability = 0
-
- // Extra backup!
- ADD_TRAIT(monkey_man, TRAIT_NO_DNA_SCRAMBLE, SPECIES_TRAIT)
- // Anything else requires enough effort that they deserve it.
+ monkey_man.make_clever_and_no_dna_scramble()
monkey_man.mind.enslave_mind_to_creator(user)
diff --git a/code/modules/antagonists/abductor/abductor.dm b/code/modules/antagonists/abductor/abductor.dm
index 7fc0c565ab1df..cd56fcdaa5cdc 100644
--- a/code/modules/antagonists/abductor/abductor.dm
+++ b/code/modules/antagonists/abductor/abductor.dm
@@ -70,7 +70,7 @@
return team
/datum/antagonist/abductor/on_gain()
- owner.set_assigned_role(SSjob.GetJobType(role_job))
+ owner.set_assigned_role(SSjob.get_job_type(role_job))
owner.special_role = ROLE_ABDUCTOR
objectives += team.objectives
finalize_abductor()
diff --git a/code/modules/antagonists/abductor/equipment/gear/abductor_items.dm b/code/modules/antagonists/abductor/equipment/gear/abductor_items.dm
index 25bbea665777c..ab1636b4dedfd 100644
--- a/code/modules/antagonists/abductor/equipment/gear/abductor_items.dm
+++ b/code/modules/antagonists/abductor/equipment/gear/abductor_items.dm
@@ -48,7 +48,7 @@
icon_state = "gizmo_scan"
to_chat(user, span_notice("You switch the device to [mode == GIZMO_SCAN? "SCAN": "MARK"] MODE"))
-/obj/item/abductor/gizmo/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
+/obj/item/abductor/gizmo/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(!ScientistCheck(user))
return ITEM_INTERACT_SKIP_TO_ATTACK // So you slap them with it
if(!console)
@@ -63,8 +63,10 @@
return ITEM_INTERACT_SUCCESS
-/obj/item/abductor/gizmo/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
- return interact_with_atom(interacting_with, user, modifiers)
+/obj/item/abductor/gizmo/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
+ if(!ismob(interacting_with))
+ return NONE
+ return ranged_interact_with_atom(interacting_with, user, modifiers)
/obj/item/abductor/gizmo/proc/scan(atom/target, mob/living/user)
if(ishuman(target))
@@ -104,15 +106,17 @@
icon_state = "silencer"
inhand_icon_state = "gizmo"
-/obj/item/abductor/silencer/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
+/obj/item/abductor/silencer/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(!AbductorCheck(user))
return ITEM_INTERACT_SKIP_TO_ATTACK // So you slap them with it
radio_off(interacting_with, user)
return ITEM_INTERACT_SUCCESS
-/obj/item/abductor/silencer/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
- return interact_with_atom(interacting_with, user, modifiers)
+/obj/item/abductor/silencer/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
+ if(!ismob(interacting_with))
+ return NONE
+ return ranged_interact_with_atom(interacting_with, user, modifiers)
/obj/item/abductor/silencer/proc/radio_off(atom/target, mob/living/user)
if( !(user in (viewers(7,target))) )
@@ -155,10 +159,12 @@
icon_state = "mind_device_message"
to_chat(user, span_notice("You switch the device to [mode == MIND_DEVICE_MESSAGE? "TRANSMISSION": "COMMAND"] MODE"))
-/obj/item/abductor/mind_device/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
- return interact_with_atom(interacting_with, user, modifiers)
-
/obj/item/abductor/mind_device/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
+ if(!ismob(interacting_with))
+ return NONE
+ return ranged_interact_with_atom(interacting_with, user, modifiers)
+
+/obj/item/abductor/mind_device/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(!ScientistCheck(user))
return ITEM_INTERACT_BLOCKING
@@ -183,8 +189,12 @@
to_chat(user, span_warning("Your target is already under a mind-controlling influence!"))
return
- var/command = tgui_input_text(user, "Enter the command for your target to follow.\
- Uses Left: [target_gland.mind_control_uses], Duration: [DisplayTimeText(target_gland.mind_control_duration)]", "Enter command")
+ var/command = tgui_input_text(
+ user,
+ "Enter the command for your target to follow. Uses Left: [target_gland.mind_control_uses], Duration: [DisplayTimeText(target_gland.mind_control_duration)]",
+ "Enter command",
+ max_length = MAX_MESSAGE_LEN,
+ )
if(!command)
return
@@ -209,7 +219,7 @@
if(living_target.stat == DEAD)
to_chat(user, span_warning("Your target is dead!"))
return
- var/message = tgui_input_text(user, "Message to send to your target's brain", "Enter message")
+ var/message = tgui_input_text(user, "Message to send to your target's brain", "Enter message", max_length = MAX_MESSAGE_LEN)
if(!message)
return
if(QDELETED(living_target) || living_target.stat == DEAD)
diff --git a/code/modules/antagonists/abductor/machinery/experiment.dm b/code/modules/antagonists/abductor/machinery/experiment.dm
index 09790f4ba897e..27093778c3116 100644
--- a/code/modules/antagonists/abductor/machinery/experiment.dm
+++ b/code/modules/antagonists/abductor/machinery/experiment.dm
@@ -190,7 +190,7 @@
H.forceMove(console.pad.teleport_target)
return
//Area not chosen / It's not safe area - teleport to arrivals
- SSjob.SendToLateJoin(H, FALSE)
+ SSjob.send_to_late_join(H, FALSE)
return
/obj/machinery/abductor/experiment/update_icon_state()
diff --git a/code/modules/antagonists/blob/blobstrains/_reagent.dm b/code/modules/antagonists/blob/blobstrains/_reagent.dm
index 2d7f4c5d34eb8..65a50621b1717 100644
--- a/code/modules/antagonists/blob/blobstrains/_reagent.dm
+++ b/code/modules/antagonists/blob/blobstrains/_reagent.dm
@@ -26,12 +26,21 @@
// These can only be applied by blobs. They are what (reagent) blobs are made out of.
/datum/reagent/blob
name = "Unknown"
- description = "shouldn't exist and you should adminhelp immediately."
+ description = ""
color = COLOR_WHITE
taste_description = "bad code and slime"
chemical_flags = NONE
penetrates_skin = NONE
+
+/datum/reagent/blob/New()
+ ..()
+
+ if(name == "Unknown")
+ description = "shouldn't exist and you should adminhelp immediately."
+ else if(description == "")
+ description = "[name] is the reagent created by that type of blob."
+
/// Used by blob reagents to calculate the reaction volume they should use when exposing mobs.
/datum/reagent/blob/proc/return_mob_expose_reac_volume(mob/living/exposed_mob, methods=TOUCH, reac_volume, show_message, touch_protection, mob/camera/blob/overmind)
if(exposed_mob.stat == DEAD || HAS_TRAIT(exposed_mob, TRAIT_BLOB_ALLY))
diff --git a/code/modules/antagonists/blob/blobstrains/cryogenic_poison.dm b/code/modules/antagonists/blob/blobstrains/cryogenic_poison.dm
index a18d802ff7dd4..acb4d96c23ad8 100644
--- a/code/modules/antagonists/blob/blobstrains/cryogenic_poison.dm
+++ b/code/modules/antagonists/blob/blobstrains/cryogenic_poison.dm
@@ -12,7 +12,7 @@
/datum/reagent/blob/cryogenic_poison
name = "Cryogenic Poison"
- description = "will inject targets with a freezing poison that does high damage over time."
+ description = "A freezing poison that does high damage over time. Cryogenic poison blobs inject this into their victims."
color = "#8BA6E9"
taste_description = "brain freeze"
diff --git a/code/modules/antagonists/blob/blobstrains/regenerative_materia.dm b/code/modules/antagonists/blob/blobstrains/regenerative_materia.dm
index a62895ae6c4b7..d9010a965376e 100644
--- a/code/modules/antagonists/blob/blobstrains/regenerative_materia.dm
+++ b/code/modules/antagonists/blob/blobstrains/regenerative_materia.dm
@@ -12,6 +12,7 @@
/datum/reagent/blob/regenerative_materia
name = "Regenerative Materia"
+ description = "Chemical that inflicts toxin damage and makes the target believe they are fully healed. Regenerative materia blobs inject this into their victims."
taste_description = "heaven"
color = "#A88FB7"
diff --git a/code/modules/antagonists/blob/structures/_blob.dm b/code/modules/antagonists/blob/structures/_blob.dm
index 324c91ea3a529..c7a2fc3a1107f 100644
--- a/code/modules/antagonists/blob/structures/_blob.dm
+++ b/code/modules/antagonists/blob/structures/_blob.dm
@@ -175,6 +175,7 @@
if(isspaceturf(T) && !(locate(/obj/structure/lattice) in T) && prob(80))
make_blob = FALSE
playsound(src.loc, 'sound/effects/splat.ogg', 50, TRUE) //Let's give some feedback that we DID try to spawn in space, since players are used to it
+ balloon_alert(controller, "failed to expand!")
ConsumeTile() //hit the tile we're in, making sure there are no border objects blocking us
if(!T.CanPass(src, get_dir(T, src))) //is the target turf impassable
diff --git a/code/modules/antagonists/blob/structures/core.dm b/code/modules/antagonists/blob/structures/core.dm
index 6eeccc8c361dd..f995dc0b81b03 100644
--- a/code/modules/antagonists/blob/structures/core.dm
+++ b/code/modules/antagonists/blob/structures/core.dm
@@ -24,7 +24,7 @@
GLOB.blob_cores += src
START_PROCESSING(SSobj, src)
SSpoints_of_interest.make_point_of_interest(src)
- update_appearance() //so it atleast appears
+ update_appearance() //so it at least appears
if(!placed && !overmind)
return INITIALIZE_HINT_QDEL
if(overmind)
diff --git a/code/modules/antagonists/brainwashing/brainwashing.dm b/code/modules/antagonists/brainwashing/brainwashing.dm
index 57707688f4daf..5d5cca3cb6de1 100644
--- a/code/modules/antagonists/brainwashing/brainwashing.dm
+++ b/code/modules/antagonists/brainwashing/brainwashing.dm
@@ -61,7 +61,7 @@
return
var/list/objectives = list()
do
- var/objective = tgui_input_text(admin, "Add an objective", "Brainwashing")
+ var/objective = tgui_input_text(admin, "Add an objective", "Brainwashing", max_length = MAX_MESSAGE_LEN)
if(objective)
objectives += objective
while(tgui_alert(admin, "Add another objective?", "More Brainwashing", list("Yes","No")) == "Yes")
diff --git a/code/modules/antagonists/changeling/powers/absorb.dm b/code/modules/antagonists/changeling/powers/absorb.dm
index 7e13612153b49..d5ee0c2fc873a 100644
--- a/code/modules/antagonists/changeling/powers/absorb.dm
+++ b/code/modules/antagonists/changeling/powers/absorb.dm
@@ -41,9 +41,14 @@
owner.visible_message(span_danger("[owner] sucks the fluids from [target]!"), span_notice("We have absorbed [target]."))
to_chat(target, span_userdanger("You are absorbed by the changeling!"))
+ var/true_absorbtion = (!isnull(target.client) || !isnull(target.mind) || !isnull(target.last_mind))
+ if (!true_absorbtion)
+ to_chat(owner, span_changeling(span_bold("You absorb [target], but their weak DNA is not enough to satisfy your hunger.")))
+
if(!changeling.has_profile_with_dna(target.dna))
changeling.add_new_profile(target)
- changeling.true_absorbs++
+ if (true_absorbtion)
+ changeling.true_absorbs++
if(owner.nutrition < NUTRITION_LEVEL_WELL_FED)
owner.set_nutrition(min((owner.nutrition + target.nutrition), NUTRITION_LEVEL_WELL_FED))
@@ -57,7 +62,8 @@
is_absorbing = FALSE
changeling.adjust_chemicals(10)
- changeling.can_respec = TRUE
+ if (true_absorbtion)
+ changeling.can_respec = TRUE
if(target.stat != DEAD)
target.investigate_log("has died from being changeling absorbed.", INVESTIGATE_DEATHS)
diff --git a/code/modules/antagonists/clown_ops/clownop.dm b/code/modules/antagonists/clown_ops/clownop.dm
index 07c1cc84ad756..9866ee30ccf13 100644
--- a/code/modules/antagonists/clown_ops/clownop.dm
+++ b/code/modules/antagonists/clown_ops/clownop.dm
@@ -11,7 +11,7 @@
nuke_icon_state = "bananiumbomb_base"
/datum/antagonist/nukeop/clownop/admin_add(datum/mind/new_owner,mob/admin)
- new_owner.set_assigned_role(SSjob.GetJobType(/datum/job/clown_operative))
+ new_owner.set_assigned_role(SSjob.get_job_type(/datum/job/clown_operative))
new_owner.add_antag_datum(src)
message_admins("[key_name_admin(admin)] has clown op'ed [key_name_admin(new_owner)].")
log_admin("[key_name(admin)] has clown op'ed [key_name(new_owner)].")
diff --git a/code/modules/antagonists/cult/cult_comms.dm b/code/modules/antagonists/cult/cult_comms.dm
index 3d5677996502a..45c3aee695574 100644
--- a/code/modules/antagonists/cult/cult_comms.dm
+++ b/code/modules/antagonists/cult/cult_comms.dm
@@ -27,7 +27,7 @@
return ..()
/datum/action/innate/cult/comm/Activate()
- var/input = tgui_input_text(usr, "Message to tell to the other acolytes", "Voice of Blood")
+ var/input = tgui_input_text(usr, "Message to tell to the other acolytes", "Voice of Blood", max_length = MAX_MESSAGE_LEN)
if(!input || !IsAvailable(feedback = TRUE))
return
diff --git a/code/modules/antagonists/cult/cult_objectives.dm b/code/modules/antagonists/cult/cult_objectives.dm
index d290b212ab22f..60542f259bf2a 100644
--- a/code/modules/antagonists/cult/cult_objectives.dm
+++ b/code/modules/antagonists/cult/cult_objectives.dm
@@ -63,7 +63,7 @@
/datum/objective/sacrifice/proc/on_possible_mindswap(mob/source)
SIGNAL_HANDLER
UnregisterSignal(target.current, list(COMSIG_QDELETING, COMSIG_MOB_MIND_TRANSFERRED_INTO))
- //we check if the mind is bodyless only after mindswap shenanigeans to avoid issues.
+ //we check if the mind is bodyless only after mindswap shenanigans to avoid issues.
addtimer(CALLBACK(src, PROC_REF(do_we_have_a_body)), 0 SECONDS)
/datum/objective/sacrifice/proc/do_we_have_a_body()
diff --git a/code/modules/antagonists/cult/cult_structures.dm b/code/modules/antagonists/cult/cult_structures.dm
index 773f890d25dbb..511988fb5bcbb 100644
--- a/code/modules/antagonists/cult/cult_structures.dm
+++ b/code/modules/antagonists/cult/cult_structures.dm
@@ -137,7 +137,7 @@
/*
* Set up and populate our list of options.
- * Overriden by subtypes.
+ * Overridden by subtypes.
*
* The list of options is a associated list of format:
* item_name = list(
diff --git a/code/modules/antagonists/ert/ert.dm b/code/modules/antagonists/ert/ert.dm
index 4b94666abc367..29515e45bb124 100644
--- a/code/modules/antagonists/ert/ert.dm
+++ b/code/modules/antagonists/ert/ert.dm
@@ -233,9 +233,11 @@
var/mob/living/carbon/human/H = owner.current
if(!istype(H))
return
+
if(isplasmaman(H))
- H.equipOutfit(plasmaman_outfit)
- H.open_internals(H.get_item_for_held_index(2))
+ H.dna.species.outfit_important_for_life = plasmaman_outfit
+
+ H.dna.species.give_important_for_life(H)
H.equipOutfit(outfit)
if(isplasmaman(H))
diff --git a/code/modules/antagonists/heretic/influences.dm b/code/modules/antagonists/heretic/influences.dm
index abba2c3f1007e..7b316d6cdb984 100644
--- a/code/modules/antagonists/heretic/influences.dm
+++ b/code/modules/antagonists/heretic/influences.dm
@@ -43,7 +43,7 @@
while((length(smashes) + num_drained) < how_many_can_we_make && location_sanity < 100)
var/turf/chosen_location = get_safe_random_station_turf()
- // We don't want them close to each other - at least 1 tile of seperation
+ // We don't want them close to each other - at least 1 tile of separation
var/list/nearby_things = range(1, chosen_location)
var/obj/effect/heretic_influence/what_if_i_have_one = locate() in nearby_things
var/obj/effect/visible_heretic_influence/what_if_i_had_one_but_its_used = locate() in nearby_things
diff --git a/code/modules/antagonists/heretic/items/heretic_armor.dm b/code/modules/antagonists/heretic/items/heretic_armor.dm
index 0c64e4a227eaf..8375c3ae44334 100644
--- a/code/modules/antagonists/heretic/items/heretic_armor.dm
+++ b/code/modules/antagonists/heretic/items/heretic_armor.dm
@@ -153,6 +153,7 @@
RemoveElement(/datum/element/heretic_focus)
if(isliving(loc))
+ REMOVE_TRAIT(loc, TRAIT_RESISTLOWPRESSURE, REF(src))
loc.balloon_alert(loc, "cloak hidden")
loc.visible_message(span_notice("Light shifts around [loc], making the cloak around them invisible!"))
@@ -163,5 +164,6 @@
AddElement(/datum/element/heretic_focus)
if(isliving(loc))
+ ADD_TRAIT(loc, TRAIT_RESISTLOWPRESSURE, REF(src))
loc.balloon_alert(loc, "cloak revealed")
loc.visible_message(span_notice("A kaleidoscope of colours collapses around [loc], a cloak appearing suddenly around their person!"))
diff --git a/code/modules/antagonists/heretic/items/heretic_necks.dm b/code/modules/antagonists/heretic/items/heretic_necks.dm
index 5c73c22a4e793..a738b4aae47ea 100644
--- a/code/modules/antagonists/heretic/items/heretic_necks.dm
+++ b/code/modules/antagonists/heretic/items/heretic_necks.dm
@@ -1,5 +1,5 @@
/obj/item/clothing/neck/heretic_focus
- name = "Amber Focus"
+ name = "amber focus"
desc = "An amber focusing glass that provides a link to the world beyond. The necklace seems to twitch, but only when you look at it from the corner of your eye."
icon_state = "eldritch_necklace"
w_class = WEIGHT_CLASS_SMALL
@@ -10,7 +10,7 @@
AddElement(/datum/element/heretic_focus)
/obj/item/clothing/neck/heretic_focus/crimson_medallion
- name = "Crimson Medallion"
+ name = "crimson medallion"
desc = "A blood-red focusing glass that provides a link to the world beyond, and worse. Its eye is constantly twitching and gazing in all directions. It almost seems to be silently screaming..."
icon_state = "crimson_medallion"
/// The aura healing component. Used to delete it when taken off.
@@ -105,7 +105,7 @@
. += span_red("You can also squeeze it to recover a large amount of health quickly, at a cost...")
/obj/item/clothing/neck/eldritch_amulet
- name = "Warm Eldritch Medallion"
+ name = "warm eldritch medallion"
desc = "A strange medallion. Peering through the crystalline surface, the world around you melts away. You see your own beating heart, and the pulsing of a thousand others."
icon = 'icons/obj/antags/eldritch.dmi'
icon_state = "eye_medalion"
@@ -134,7 +134,7 @@
user.update_sight()
/obj/item/clothing/neck/eldritch_amulet/piercing
- name = "Piercing Eldritch Medallion"
+ name = "piercing eldritch medallion"
desc = "A strange medallion. Peering through the crystalline surface, the light refracts into new and terrifying spectrums of color. You see yourself, reflected off cascading mirrors, warped into impossible shapes."
heretic_only_trait = TRAIT_XRAY_VISION
@@ -149,7 +149,7 @@
// The amulet conversion tool used by moon heretics
/obj/item/clothing/neck/heretic_focus/moon_amulet
- name = "Moonlight Amulet"
+ name = "moonlight amulet"
desc = "A piece of the mind, the soul and the moon. Gazing into it makes your head spin and hear whispers of laughter and joy."
icon = 'icons/obj/antags/eldritch.dmi'
icon_state = "moon_amulette"
diff --git a/code/modules/antagonists/heretic/items/labyrinth_handbook.dm b/code/modules/antagonists/heretic/items/labyrinth_handbook.dm
index 8555b60f0c393..e4f333260a88f 100644
--- a/code/modules/antagonists/heretic/items/labyrinth_handbook.dm
+++ b/code/modules/antagonists/heretic/items/labyrinth_handbook.dm
@@ -41,10 +41,12 @@
. += span_hypnophrase("Materializes a barrier upon any tile in sight, which only you can pass through. Lasts 8 seconds.")
. += span_hypnophrase("It has [uses] uses left.")
-/obj/item/heretic_labyrinth_handbook/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
- return interact_with_atom(interacting_with, user, modifiers)
-
/obj/item/heretic_labyrinth_handbook/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
+ if(HAS_TRAIT(interacting_with, TRAIT_COMBAT_MODE_SKIP_INTERACTION))
+ return NONE
+ return ranged_interact_with_atom(interacting_with, user, modifiers)
+
+/obj/item/heretic_labyrinth_handbook/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(!IS_HERETIC(user))
if(ishuman(user))
var/mob/living/carbon/human/human_user = user
diff --git a/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_knowledge.dm b/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_knowledge.dm
index 4b3525c93b044..5919f9a40d12a 100644
--- a/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_knowledge.dm
+++ b/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_knowledge.dm
@@ -501,6 +501,7 @@
sac_target.remove_status_effect(/datum/status_effect/necropolis_curse)
sac_target.remove_status_effect(/datum/status_effect/unholy_determination)
sac_target.reagents?.del_reagent(/datum/reagent/inverse/helgrasp/heretic)
+ sac_target.uncuff()
sac_target.clear_mood_event("shadow_realm")
if(IS_HERETIC(sac_target))
var/datum/antagonist/heretic/victim_heretic = sac_target.mind?.has_antag_datum(/datum/antagonist/heretic)
diff --git a/code/modules/antagonists/heretic/knowledge/side_blade_rust.dm b/code/modules/antagonists/heretic/knowledge/side_blade_rust.dm
index 3a0f17ed48391..2bae6ed540296 100644
--- a/code/modules/antagonists/heretic/knowledge/side_blade_rust.dm
+++ b/code/modules/antagonists/heretic/knowledge/side_blade_rust.dm
@@ -47,7 +47,7 @@
desc = "Allows you to transmute any ballistic weapon, such as a pipegun, with hide \
from any animal, a plank of wood, and a camera to create the Lionhunter's rifle. \
The Lionhunter's Rifle is a long ranged ballistic weapon with three shots. \
- These shots function as normal, albeit weak high caliber mutitions when fired from \
+ These shots function as normal, albeit weak high-caliber munitions when fired from \
close range or at inanimate objects. You can aim the rifle at distant foes, \
causing the shot to deal massively increased damage and hone in on them."
gain_text = "I met an old man in an antique shop who wielded a very unusual weapon. \
diff --git a/code/modules/antagonists/heretic/knowledge/side_flesh_void.dm b/code/modules/antagonists/heretic/knowledge/side_flesh_void.dm
index a958ab3f272bb..d54646fe103b2 100644
--- a/code/modules/antagonists/heretic/knowledge/side_flesh_void.dm
+++ b/code/modules/antagonists/heretic/knowledge/side_flesh_void.dm
@@ -37,6 +37,23 @@
route = PATH_SIDE
depth = 8
+/datum/heretic_knowledge/spell/void_prison
+ name = "Void Prison"
+ desc = "Grants you Void Prison, a spell that places your victim into ball, making them unable to do anything or speak. \
+ Applies void chill afterwards."
+ gain_text = "At first, I see myself, waltzing along a snow-laden street. \
+ I try to yell, grab hold of this fool and tell them to run. \
+ But the only welts made are on my own beating fist. \
+ My smiling face turns to regard me, reflecting back in glassy eyes the empty path I have been lead down."
+ next_knowledge = list(
+ /datum/heretic_knowledge/spell/void_phase,
+ /datum/heretic_knowledge/summon/raw_prophet,
+ )
+ spell_to_add = /datum/action/cooldown/spell/pointed/void_prison
+ cost = 1
+ route = PATH_SIDE
+ depth = 8
+
/datum/heretic_knowledge/spell/cleave
name = "Blood Cleave"
desc = "Grants you Cleave, an area-of-effect targeted spell \
diff --git a/code/modules/antagonists/heretic/knowledge/void_lore.dm b/code/modules/antagonists/heretic/knowledge/void_lore.dm
index 11031a51aca96..d2fd0efe8b570 100644
--- a/code/modules/antagonists/heretic/knowledge/void_lore.dm
+++ b/code/modules/antagonists/heretic/knowledge/void_lore.dm
@@ -12,9 +12,10 @@
*
* Mark of Void
* Ritual of Knowledge
- * Cone of Cold
+ * Void Conduit
* Void Phase
* > Sidepaths:
+ * Void Stasis
* Carving Knife
* Blood Siphon
*
@@ -78,7 +79,7 @@
var/mob/living/carbon/carbon_target = target
carbon_target.adjust_silence(10 SECONDS)
- carbon_target.apply_status_effect(/datum/status_effect/void_chill)
+ carbon_target.apply_status_effect(/datum/status_effect/void_chill, 2)
/datum/heretic_knowledge/cold_snap
name = "Aristocrat's Way"
@@ -96,12 +97,29 @@
research_tree_icon_path = 'icons/effects/effects.dmi'
research_tree_icon_state = "the_freezer"
depth = 4
+ /// Traits we apply to become immune to the environment
+ var/static/list/gain_traits = list(TRAIT_NO_SLIP_ICE, TRAIT_NO_SLIP_SLIDE)
/datum/heretic_knowledge/cold_snap/on_gain(mob/user, datum/antagonist/heretic/our_heretic)
user.add_traits(list(TRAIT_NOBREATH, TRAIT_RESISTCOLD), type)
+ RegisterSignal(user, COMSIG_LIVING_LIFE, PROC_REF(check_environment))
/datum/heretic_knowledge/cold_snap/on_lose(mob/user, datum/antagonist/heretic/our_heretic)
user.remove_traits(list(TRAIT_RESISTCOLD, TRAIT_NOBREATH), type)
+ UnregisterSignal(user, COMSIG_LIVING_LIFE)
+
+///Checks if our traits should be active
+/datum/heretic_knowledge/cold_snap/proc/check_environment(mob/living/user)
+ SIGNAL_HANDLER
+
+ var/datum/gas_mixture/environment = user.loc?.return_air()
+ if(!isnull(environment))
+ var/affected_temperature = environment.return_temperature()
+ var/affected_pressure = environment.return_pressure()
+ if(affected_temperature <= T0C || affected_pressure < ONE_ATMOSPHERE)
+ user.add_traits(gain_traits, type)
+ else
+ user.remove_traits(gain_traits, type)
/datum/heretic_knowledge/mark/void_mark
name = "Mark of Void"
@@ -114,17 +132,17 @@
mark_type = /datum/status_effect/eldritch/void
/datum/heretic_knowledge/knowledge_ritual/void
- next_knowledge = list(/datum/heretic_knowledge/spell/void_cone)
+ next_knowledge = list(/datum/heretic_knowledge/spell/void_conduit)
route = PATH_VOID
-/datum/heretic_knowledge/spell/void_cone
- name = "Void Blast"
- desc = "Grants you Void Blast, a spell that shoots out a freezing blast in a cone in front of you, \
- freezing the ground and any victims within."
- gain_text = "Every door I open racks my body. I am afraid of what is behind them. Someone is expecting me, \
- and my legs start to drag. Is that... snow?"
+/datum/heretic_knowledge/spell/void_conduit
+ name = "Void Conduit"
+ desc = "Grants you Void Conduit, a spell which summons a pulsing gate to the Void itself. Every pulse breaks windows and airlocks, while afflicting Heathens with an eldritch chill and shielding Heretics against low pressure."
+ gain_text = "The hum in the still, cold air turns to a cacophonous rattle. \
+ Over the noise, there is no distinction to the clattering of window panes and the yawning knowledge that ricochets through my skull. \
+ The doors won't close. I can't keep the cold out now."
next_knowledge = list(/datum/heretic_knowledge/spell/void_phase)
- spell_to_add = /datum/action/cooldown/spell/cone/staggered/cone_of_cold/void
+ spell_to_add = /datum/action/cooldown/spell/conjure/void_conduit
cost = 1
route = PATH_VOID
depth = 7
@@ -139,6 +157,7 @@
/datum/heretic_knowledge/blade_upgrade/void,
/datum/heretic_knowledge/reroll_targets,
/datum/heretic_knowledge/spell/blood_siphon,
+ /datum/heretic_knowledge/spell/void_prison,
/datum/heretic_knowledge/rune_carver,
)
spell_to_add = /datum/action/cooldown/spell/pointed/void_phase
@@ -149,13 +168,19 @@
/datum/heretic_knowledge/blade_upgrade/void
name = "Seeking Blade"
- desc = "You can now attack distant marked targets with your Void Blade, teleporting directly next to them."
+ desc = "Your blade now freezes enemies. Additionally, you can now attack distant marked targets with your Void Blade, teleporting directly next to them."
gain_text = "Fleeting memories, fleeting feet. I mark my way with frozen blood upon the snow. Covered and forgotten."
next_knowledge = list(/datum/heretic_knowledge/spell/void_pull)
route = PATH_VOID
research_tree_icon_path = 'icons/ui_icons/antags/heretic/knowledge.dmi'
research_tree_icon_state = "blade_upgrade_void"
+/datum/heretic_knowledge/blade_upgrade/void/do_melee_effects(mob/living/source, mob/living/target, obj/item/melee/sickly_blade/blade)
+ if(source == target)
+ return
+
+ target.apply_status_effect(/datum/status_effect/void_chill, 2)
+
/datum/heretic_knowledge/blade_upgrade/void/do_ranged_effects(mob/living/user, mob/living/target, obj/item/melee/sickly_blade/blade)
if(!target.has_status_effect(/datum/status_effect/eldritch))
return
@@ -200,6 +225,8 @@
var/datum/looping_sound/void_loop/sound_loop
///Reference to the ongoing voidstrom that surrounds the heretic
var/datum/weather/void_storm/storm
+ ///The storm where there are actual effects
+ var/datum/proximity_monitor/advanced/void_storm/heavy_storm
/datum/heretic_knowledge/ultimate/void_final/recipe_snowflake_check(mob/living/user, list/atoms, list/selected_atoms, turf/loc)
if(!isopenturf(loc))
@@ -221,16 +248,22 @@
sound = 'sound/ambience/antag/heretic/ascend_void.ogg',
color_override = "pink",
)
- ADD_TRAIT(user, TRAIT_RESISTLOWPRESSURE, MAGIC_TRAIT)
+ user.add_traits(list(TRAIT_RESISTLOWPRESSURE, TRAIT_NEGATES_GRAVITY, TRAIT_MOVE_FLYING, TRAIT_FREE_HYPERSPACE_MOVEMENT), MAGIC_TRAIT)
// Let's get this show on the road!
sound_loop = new(user, TRUE, TRUE)
RegisterSignal(user, COMSIG_LIVING_LIFE, PROC_REF(on_life))
- RegisterSignal(user, COMSIG_LIVING_DEATH, PROC_REF(on_death))
+ RegisterSignal(user, COMSIG_ATOM_PRE_BULLET_ACT, PROC_REF(hit_by_projectile))
+ RegisterSignals(user, list(COMSIG_LIVING_DEATH, COMSIG_QDELETING), PROC_REF(on_death))
+ heavy_storm = new(user, 10)
+ if(ishuman(user))
+ var/mob/living/carbon/human/ascended_human = user
+ var/obj/item/organ/internal/eyes/heretic_eyes = ascended_human.get_organ_slot(ORGAN_SLOT_EYES)
+ heretic_eyes?.color_cutoffs = list(30, 30, 30)
+ ascended_human.update_sight()
/datum/heretic_knowledge/ultimate/void_final/on_lose(mob/user, datum/antagonist/heretic/our_heretic)
on_death() // Losing is pretty much dying. I think
- RegisterSignals(user, list(COMSIG_LIVING_LIFE, COMSIG_LIVING_DEATH))
/**
* Signal proc for [COMSIG_LIVING_LIFE].
@@ -243,10 +276,29 @@
/datum/heretic_knowledge/ultimate/void_final/proc/on_life(mob/living/source, seconds_per_tick, times_fired)
SIGNAL_HANDLER
- for(var/mob/living/carbon/close_carbon in view(5, source))
- if(IS_HERETIC_OR_MONSTER(close_carbon))
- continue
- close_carbon.adjust_silence_up_to(2 SECONDS, 20 SECONDS)
+ for(var/atom/thing_in_range as anything in range(10, source))
+ if(iscarbon(thing_in_range))
+ var/mob/living/carbon/close_carbon = thing_in_range
+ if(IS_HERETIC_OR_MONSTER(close_carbon))
+ close_carbon.apply_status_effect(/datum/status_effect/void_conduit)
+ continue
+ close_carbon.adjust_silence_up_to(2 SECONDS, 20 SECONDS)
+ close_carbon.apply_status_effect(/datum/status_effect/void_chill, 1)
+ close_carbon.adjust_eye_blur(rand(0 SECONDS, 2 SECONDS))
+ close_carbon.adjust_bodytemperature(-30 * TEMPERATURE_DAMAGE_COEFFICIENT)
+
+ if(istype(thing_in_range, /obj/machinery/door) || istype(thing_in_range, /obj/structure/door_assembly))
+ var/obj/affected_door = thing_in_range
+ affected_door.take_damage(rand(60, 80))
+
+ if(istype(thing_in_range, /obj/structure/window) || istype(thing_in_range, /obj/structure/grille))
+ var/obj/structure/affected_structure = thing_in_range
+ affected_structure.take_damage(rand(20, 40))
+
+ if(isturf(thing_in_range))
+ var/turf/affected_turf = thing_in_range
+ var/datum/gas_mixture/environment = affected_turf.return_air()
+ environment.temperature *= 0.9
// Telegraph the storm in every area on the station.
var/list/station_levels = SSmapping.levels_by_trait(ZTRAIT_STATION)
@@ -254,14 +306,6 @@
storm = new /datum/weather/void_storm(station_levels)
storm.telegraph()
- // When the heretic enters a new area, intensify the storm in the new area,
- // and lessen the intensity in the former area.
- var/area/source_area = get_area(source)
- if(!storm.impacted_areas[source_area])
- storm.former_impacted_areas |= storm.impacted_areas
- storm.impacted_areas = list(source_area)
- storm.update_areas()
-
/**
* Signal proc for [COMSIG_LIVING_DEATH].
*
@@ -275,3 +319,32 @@
if(storm)
storm.end()
QDEL_NULL(storm)
+ if(heavy_storm)
+ QDEL_NULL(heavy_storm)
+ UnregisterSignal(source, list(COMSIG_LIVING_LIFE, COMSIG_ATOM_PRE_BULLET_ACT, COMSIG_LIVING_DEATH, COMSIG_QDELETING))
+
+///Few checks to determine if we can deflect bullets
+/datum/heretic_knowledge/ultimate/void_final/proc/can_deflect(mob/living/ascended_heretic)
+ if(!(ascended_heretic.mobility_flags & MOBILITY_USE))
+ return FALSE
+ if(!isturf(ascended_heretic.loc))
+ return FALSE
+ return TRUE
+
+/datum/heretic_knowledge/ultimate/void_final/proc/hit_by_projectile(mob/living/ascended_heretic, obj/projectile/hitting_projectile, def_zone)
+ SIGNAL_HANDLER
+
+ if(!can_deflect(ascended_heretic))
+ return NONE
+
+ ascended_heretic.visible_message(
+ span_danger("The void storm surrounding [ascended_heretic] deflects [hitting_projectile]!"),
+ span_userdanger("The void storm protects you from [hitting_projectile]!"),
+ )
+ playsound(ascended_heretic, pick('sound/magic/VoidDeflect01.ogg', 'sound/magic/VoidDeflect02.ogg', 'sound/magic/VoidDeflect03.ogg'), 75, TRUE)
+ hitting_projectile.firer = ascended_heretic
+ if(prob(75))
+ hitting_projectile.set_angle(get_angle(hitting_projectile.firer, hitting_projectile.fired_from))
+ else
+ hitting_projectile.set_angle(rand(0, 360))//SHING
+ return COMPONENT_BULLET_PIERCED
diff --git a/code/modules/antagonists/heretic/magic/void_conduit.dm b/code/modules/antagonists/heretic/magic/void_conduit.dm
new file mode 100644
index 0000000000000..07ca0cbe2ab0f
--- /dev/null
+++ b/code/modules/antagonists/heretic/magic/void_conduit.dm
@@ -0,0 +1,122 @@
+/datum/action/cooldown/spell/conjure/void_conduit
+ name = "Void Conduit"
+ desc = "Opens a gate to the Void; it releases an intermittent pulse that damages windows and airlocks, \
+ while afflicting Heathens with void chill. \
+ Affected Heretics instead receive low pressure resistance."
+ background_icon_state = "bg_heretic"
+ overlay_icon_state = "bg_heretic_border"
+ button_icon = 'icons/mob/actions/actions_ecult.dmi'
+ button_icon_state = "void_rift"
+
+ cooldown_time = 1 MINUTES
+
+ sound = null
+ school = SCHOOL_FORBIDDEN
+ invocation = "MBR'C' TH' V''D!"
+ invocation_type = INVOCATION_SHOUT
+ spell_requirements = NONE
+
+ summon_radius = 0
+ summon_type = list(/obj/structure/void_conduit)
+ summon_respects_density = TRUE
+ summon_respects_prev_spawn_points = TRUE
+
+/obj/structure/void_conduit
+ name = "Void Conduit"
+ desc = "An open gate which leads to nothingness. Releases pulses which you do not want to get hit by."
+ icon = 'icons/effects/effects.dmi'
+ icon_state = "void_conduit"
+ anchored = TRUE
+ density = TRUE
+ ///Overlay to apply to the tiles in range of the conduit
+ var/static/image/void_overlay = image(icon = 'icons/turf/overlays.dmi', icon_state = "voidtile")
+ ///List of tiles that we added an overlay to, so we can clear them when the conduit is deleted
+ var/list/overlayed_turfs = list()
+ ///How many tiles far our effect is
+ var/effect_range = 12
+ ///id of the deletion timer
+ var/timerid
+ ///Audio loop for the rift being alive
+ var/datum/looping_sound/void_conduit/soundloop
+
+/obj/structure/void_conduit/Initialize(mapload)
+ . = ..()
+ soundloop = new(src, start_immediately = TRUE)
+ timerid = QDEL_IN_STOPPABLE(src, 1 MINUTES)
+ START_PROCESSING(SSobj, src)
+ for(var/turf/affected_turf as anything in RANGE_TURFS(effect_range, src))
+ if(!isopenturf(affected_turf))
+ continue
+ affected_turf.add_overlay(void_overlay)
+ overlayed_turfs += affected_turf
+ void_overlay.mouse_opacity = MOUSE_OPACITY_TRANSPARENT
+ void_overlay.alpha = 180
+
+/obj/structure/void_conduit/Destroy(force)
+ QDEL_NULL(soundloop)
+ deltimer(timerid)
+ STOP_PROCESSING(SSobj, src)
+ for(var/turf/affected_turf as anything in overlayed_turfs) //If the portal is moved, the overlays don't stick around
+ affected_turf.cut_overlay(void_overlay)
+ return ..()
+
+/obj/structure/void_conduit/process(seconds_per_tick)
+ do_conduit_pulse()
+
+///Sends out a pulse
+/obj/structure/void_conduit/proc/do_conduit_pulse()
+ var/list/turfs_to_affect = list()
+ for(var/turf/affected_turf as anything in RANGE_TURFS(effect_range, loc))
+ var/distance = get_dist(loc, affected_turf)
+ if(!turfs_to_affect["[distance]"])
+ turfs_to_affect["[distance]"] = list()
+ turfs_to_affect["[distance]"] += affected_turf
+
+ for(var/distance in 0 to effect_range)
+ if(!turfs_to_affect["[distance]"])
+ continue
+ addtimer(CALLBACK(src, PROC_REF(handle_effects), turfs_to_affect["[distance]"]), (1 SECONDS) * distance)
+
+ new /obj/effect/temp_visual/circle_wave/void_conduit(get_turf(src))
+
+///Applies the effects of the pulse "hitting" something. Freezes non-heretic, destroys airlocks/windows
+/obj/structure/void_conduit/proc/handle_effects(list/turfs)
+ for(var/turf/affected_turf as anything in turfs)
+ for(var/atom/thing_to_affect as anything in affected_turf.contents)
+
+ if(isliving(thing_to_affect))
+ var/mob/living/affected_mob = thing_to_affect
+ if(affected_mob.can_block_magic(MAGIC_RESISTANCE))
+ continue
+ if(IS_HERETIC(affected_mob))
+ affected_mob.apply_status_effect(/datum/status_effect/void_conduit)
+ else
+ affected_mob.apply_status_effect(/datum/status_effect/void_chill, 1)
+
+ if(istype(thing_to_affect, /obj/machinery/door) || istype(thing_to_affect, /obj/structure/door_assembly))
+ var/obj/affected_door = thing_to_affect
+ affected_door.take_damage(rand(15, 30))
+
+ if(istype(thing_to_affect, /obj/structure/window) || istype(thing_to_affect, /obj/structure/grille))
+ var/obj/structure/affected_structure = thing_to_affect
+ affected_structure.take_damage(rand(10, 20))
+
+/datum/looping_sound/void_conduit
+ mid_sounds = 'sound/ambience/ambiatm1.ogg'
+ mid_length = 1 SECONDS
+ extra_range = 10
+ volume = 40
+ falloff_distance = 5
+ falloff_exponent = 20
+
+/datum/status_effect/void_conduit
+ duration = 15 SECONDS
+ status_type = STATUS_EFFECT_REPLACE
+ alert_type = null
+
+/datum/status_effect/void_conduit/on_apply()
+ ADD_TRAIT(owner, TRAIT_RESISTLOWPRESSURE, "void_conduit")
+ return TRUE
+
+/datum/status_effect/void_conduit/on_remove()
+ REMOVE_TRAIT(owner, TRAIT_RESISTLOWPRESSURE, "void_conduit")
diff --git a/code/modules/antagonists/heretic/magic/void_phase.dm b/code/modules/antagonists/heretic/magic/void_phase.dm
index 350ca0f29c100..c6e367e87608c 100644
--- a/code/modules/antagonists/heretic/magic/void_phase.dm
+++ b/code/modules/antagonists/heretic/magic/void_phase.dm
@@ -10,7 +10,7 @@
ranged_mousepointer = 'icons/effects/mouse_pointers/throw_target.dmi'
school = SCHOOL_FORBIDDEN
- cooldown_time = 30 SECONDS
+ cooldown_time = 25 SECONDS
invocation = "RE'L'TY PH'S'E."
invocation_type = INVOCATION_WHISPER
@@ -57,6 +57,7 @@
if(living_mob.can_block_magic(antimagic_flags))
continue
living_mob.apply_damage(40, BRUTE, wound_bonus = CANT_WOUND)
+ living_mob.apply_status_effect(/datum/status_effect/void_chill, 1)
/obj/effect/temp_visual/voidin
icon = 'icons/effects/96x96.dmi'
diff --git a/code/modules/antagonists/heretic/magic/void_prison.dm b/code/modules/antagonists/heretic/magic/void_prison.dm
new file mode 100644
index 0000000000000..211a747c8008e
--- /dev/null
+++ b/code/modules/antagonists/heretic/magic/void_prison.dm
@@ -0,0 +1,101 @@
+/datum/action/cooldown/spell/pointed/void_prison
+ name = "Void Prison"
+ desc = "Sends a heathen into the void for 10 seconds. \
+ They will be unable to perform any actions for the duration. \
+ Afterwards, they will be chilled and returned to the mortal plane."
+ background_icon_state = "bg_heretic"
+ overlay_icon_state = "bg_heretic_border"
+ button_icon = 'icons/mob/actions/actions_ecult.dmi'
+ button_icon_state = "voidball"
+ ranged_mousepointer = 'icons/effects/mouse_pointers/throw_target.dmi'
+ sound = 'sound/magic/voidblink.ogg'
+
+ cooldown_time = 1 MINUTES
+ cast_range = 3
+
+ sound = null
+ school = SCHOOL_FORBIDDEN
+ invocation = "V''D PR'S'N!"
+ invocation_type = INVOCATION_SHOUT
+ spell_requirements = NONE
+
+/datum/action/cooldown/spell/pointed/void_prison/before_cast(atom/cast_on)
+ . = ..()
+ if(. & SPELL_CANCEL_CAST)
+ return
+ if(!ismob(cast_on))
+ return SPELL_CANCEL_CAST
+
+/datum/action/cooldown/spell/pointed/void_prison/cast(mob/living/carbon/human/cast_on)
+ . = ..()
+ if(cast_on.can_block_magic(antimagic_flags))
+ cast_on.visible_message(
+ span_danger("A swirling, cold void wraps around [cast_on], but they burst free in a wave of heat!"),
+ span_danger("A yawning void begins to open before you, but a great wave of heat bursts it apart! You are protected!!")
+ )
+ return
+ cast_on.apply_status_effect(/datum/status_effect/void_prison, "void_stasis")
+
+/datum/status_effect/void_prison
+ id = "void_prison"
+ duration = 10 SECONDS
+ alert_type = /atom/movable/screen/alert/status_effect/void_prison
+ ///The overlay that gets applied to whoever has this status active
+ var/obj/effect/abstract/voidball/stasis_overlay
+
+/datum/status_effect/void_prison/on_creation(mob/living/new_owner, set_duration)
+ . = ..()
+ stasis_overlay = new /obj/effect/abstract/voidball(new_owner)
+ RegisterSignal(stasis_overlay, COMSIG_QDELETING, PROC_REF(clear_overlay))
+ new_owner.vis_contents += stasis_overlay
+ stasis_overlay.animate_opening()
+ addtimer(CALLBACK(src, PROC_REF(enter_prison), new_owner), 1 SECONDS)
+
+/datum/status_effect/void_prison/on_remove()
+ if(!IS_HERETIC(owner))
+ owner.apply_status_effect(/datum/status_effect/void_chill, 3)
+ if(stasis_overlay)
+ //Free our prisoner
+ owner.remove_traits(list(TRAIT_GODMODE, TRAIT_NO_TRANSFORM, TRAIT_SOFTSPOKEN), REF(src))
+ owner.forceMove(get_turf(stasis_overlay))
+ stasis_overlay.forceMove(owner)
+ owner.vis_contents += stasis_overlay
+ //Animate closing the ball
+ stasis_overlay.animate_closing()
+ stasis_overlay.icon_state = "voidball_closed"
+ QDEL_IN(stasis_overlay, 1.1 SECONDS)
+ stasis_overlay = null
+ return ..()
+
+///Freezes our prisoner in place
+/datum/status_effect/void_prison/proc/enter_prison(mob/living/prisoner)
+ stasis_overlay.forceMove(prisoner.loc)
+ prisoner.forceMove(stasis_overlay)
+ prisoner.add_traits(list(TRAIT_GODMODE, TRAIT_NO_TRANSFORM, TRAIT_SOFTSPOKEN), REF(src))
+
+///Makes sure to clear the ref in case the voidball ever suddenly disappears
+/datum/status_effect/void_prison/proc/clear_overlay()
+ SIGNAL_HANDLER
+ stasis_overlay = null
+
+//----Voidball effect
+/obj/effect/abstract/voidball
+ icon = 'icons/mob/actions/actions_ecult.dmi'
+ icon_state = "voidball_effect"
+ layer = ABOVE_ALL_MOB_LAYER
+ vis_flags = VIS_INHERIT_ID
+
+///Plays a opening animation
+/obj/effect/abstract/voidball/proc/animate_opening()
+ flick("voidball_opening", src)
+
+///Plays a closing animation
+/obj/effect/abstract/voidball/proc/animate_closing()
+ flick("voidball_closing", src)
+
+//---- Screen alert
+/atom/movable/screen/alert/status_effect/void_prison
+ name = "Void Prison"
+ desc = "A Yawning void encases your mortal coil." //Go straight to jail, do not pass GO, do not collect 200$
+ icon = 'icons/mob/actions/actions_ecult.dmi'
+ icon_state = "voidball_effect"
diff --git a/code/modules/antagonists/heretic/magic/void_pull.dm b/code/modules/antagonists/heretic/magic/void_pull.dm
index 2021bf8a04e4f..1db1c6601718e 100644
--- a/code/modules/antagonists/heretic/magic/void_pull.dm
+++ b/code/modules/antagonists/heretic/magic/void_pull.dm
@@ -9,7 +9,7 @@
sound = 'sound/magic/voidblink.ogg'
school = SCHOOL_FORBIDDEN
- cooldown_time = 40 SECONDS
+ cooldown_time = 30 SECONDS
invocation = "BR'NG F'RTH TH'M T' M'."
invocation_type = INVOCATION_WHISPER
@@ -32,6 +32,7 @@
// Before we cast the actual effects, deal AOE damage to anyone adjacent to us
for(var/mob/living/nearby_living as anything in get_things_to_cast_on(cast_on, damage_radius))
nearby_living.apply_damage(30, BRUTE, wound_bonus = CANT_WOUND)
+ nearby_living.apply_status_effect(/datum/status_effect/void_chill, 1)
/datum/action/cooldown/spell/aoe/void_pull/get_things_to_cast_on(atom/center, radius_override = 1)
var/list/things = list()
diff --git a/code/modules/antagonists/heretic/status_effects/buffs.dm b/code/modules/antagonists/heretic/status_effects/buffs.dm
index 1668ea5a11ef7..e4f5990040be4 100644
--- a/code/modules/antagonists/heretic/status_effects/buffs.dm
+++ b/code/modules/antagonists/heretic/status_effects/buffs.dm
@@ -251,11 +251,10 @@
status_type = STATUS_EFFECT_REFRESH
duration = -1
alert_type = null
- var/static/list/caretaking_traits = list(TRAIT_HANDS_BLOCKED, TRAIT_IGNORESLOWDOWN, TRAIT_SECLUDED_LOCATION)
+ var/static/list/caretaking_traits = list(TRAIT_GODMODE, TRAIT_HANDS_BLOCKED, TRAIT_IGNORESLOWDOWN, TRAIT_SECLUDED_LOCATION)
/datum/status_effect/caretaker_refuge/on_apply()
owner.add_traits(caretaking_traits, TRAIT_STATUS_EFFECT(id))
- owner.status_flags |= GODMODE
animate(owner, alpha = 45,time = 0.5 SECONDS)
owner.density = FALSE
RegisterSignal(owner, SIGNAL_REMOVETRAIT(TRAIT_ALLOW_HERETIC_CASTING), PROC_REF(on_focus_lost))
@@ -266,7 +265,6 @@
/datum/status_effect/caretaker_refuge/on_remove()
owner.remove_traits(caretaking_traits, TRAIT_STATUS_EFFECT(id))
- owner.status_flags &= ~GODMODE
owner.alpha = initial(owner.alpha)
owner.density = initial(owner.density)
UnregisterSignal(owner, SIGNAL_REMOVETRAIT(TRAIT_ALLOW_HERETIC_CASTING))
diff --git a/code/modules/antagonists/heretic/status_effects/debuffs.dm b/code/modules/antagonists/heretic/status_effects/debuffs.dm
index 7037d1cc3778b..8b1751bccde69 100644
--- a/code/modules/antagonists/heretic/status_effects/debuffs.dm
+++ b/code/modules/antagonists/heretic/status_effects/debuffs.dm
@@ -1,41 +1,3 @@
-// VOID CHILL
-/datum/status_effect/void_chill
- id = "void_chill"
- alert_type = /atom/movable/screen/alert/status_effect/void_chill
- duration = 8 SECONDS
- status_type = STATUS_EFFECT_REPLACE
- tick_interval = 0.5 SECONDS
- /// The amount the victim's body temperature changes each tick() in kelvin. Multiplied by TEMPERATURE_DAMAGE_COEFFICIENT.
- var/cooling_per_tick = -14
-
-/atom/movable/screen/alert/status_effect/void_chill
- name = "Void Chill"
- desc = "There's something freezing you from within and without. You've never felt cold this oppressive before..."
- icon_state = "void_chill"
-
-/datum/status_effect/void_chill/on_apply()
- owner.add_atom_colour(COLOR_BLUE_LIGHT, TEMPORARY_COLOUR_PRIORITY)
- owner.add_movespeed_modifier(/datum/movespeed_modifier/void_chill, update = TRUE)
- return TRUE
-
-/datum/status_effect/void_chill/on_remove()
- owner.remove_atom_colour(TEMPORARY_COLOUR_PRIORITY, COLOR_BLUE_LIGHT)
- owner.remove_movespeed_modifier(/datum/movespeed_modifier/void_chill, update = TRUE)
-
-/datum/status_effect/void_chill/tick(seconds_between_ticks)
- owner.adjust_bodytemperature(cooling_per_tick * TEMPERATURE_DAMAGE_COEFFICIENT)
-
-/datum/status_effect/void_chill/major
- duration = 10 SECONDS
- cooling_per_tick = -20
-
-/datum/status_effect/void_chill/lasting
- id = "lasting_void_chill"
- duration = -1
-
-/datum/movespeed_modifier/void_chill
- multiplicative_slowdown = 0.3
-
// AMOK
/datum/status_effect/amok
id = "amok"
diff --git a/code/modules/antagonists/heretic/status_effects/mark_effects.dm b/code/modules/antagonists/heretic/status_effects/mark_effects.dm
index b647ba6ca8077..4cbdbdf8c1ce1 100644
--- a/code/modules/antagonists/heretic/status_effects/mark_effects.dm
+++ b/code/modules/antagonists/heretic/status_effects/mark_effects.dm
@@ -105,7 +105,7 @@
effect_icon_state = "emark4"
/datum/status_effect/eldritch/void/on_effect()
- owner.apply_status_effect(/datum/status_effect/void_chill/major)
+ owner.apply_status_effect(/datum/status_effect/void_chill, 3)
owner.adjust_silence(10 SECONDS)
return ..()
diff --git a/code/modules/antagonists/heretic/status_effects/void_chill.dm b/code/modules/antagonists/heretic/status_effects/void_chill.dm
new file mode 100644
index 0000000000000..ed4bf1f3cb521
--- /dev/null
+++ b/code/modules/antagonists/heretic/status_effects/void_chill.dm
@@ -0,0 +1,113 @@
+/*!
+ * Contains the "Void Chill" status effect. Harmful debuff which freezes and slows down non-heretics
+ * Cannot affect silicons (How are you gonna freeze a robot?)
+ */
+/datum/status_effect/void_chill
+ id = "void_chill"
+ duration = 30 SECONDS
+ alert_type = /atom/movable/screen/alert/status_effect/void_chill
+ status_type = STATUS_EFFECT_REFRESH //Custom code
+ on_remove_on_mob_delete = TRUE
+ remove_on_fullheal = TRUE
+ ///Current amount of stacks we have
+ var/stacks
+ ///Maximum of stacks that we could possibly get
+ var/stack_limit = 5
+ ///icon for the overlay
+ var/image/stacks_overlay
+
+/datum/status_effect/void_chill/on_creation(mob/living/new_owner, new_stacks, ...)
+ . = ..()
+ RegisterSignal(owner, COMSIG_ATOM_UPDATE_OVERLAYS, PROC_REF(update_stacks_overlay))
+ set_stacks(new_stacks)
+ owner.add_atom_colour(COLOR_BLUE_LIGHT, TEMPORARY_COLOUR_PRIORITY)
+ owner.update_icon(UPDATE_OVERLAYS)
+
+/datum/status_effect/void_chill/on_apply()
+ if(issilicon(owner))
+ return FALSE
+ return TRUE
+
+/datum/status_effect/void_chill/on_remove()
+ owner.update_icon(UPDATE_OVERLAYS)
+ owner.remove_atom_colour(TEMPORARY_COLOUR_PRIORITY, COLOR_BLUE_LIGHT)
+ owner.remove_movespeed_modifier(/datum/movespeed_modifier/void_chill)
+ owner.remove_alt_appearance("heretic_status")
+ REMOVE_TRAIT(owner, TRAIT_HYPOTHERMIC, REF(src))
+ UnregisterSignal(owner, COMSIG_ATOM_UPDATE_OVERLAYS)
+
+/datum/status_effect/void_chill/tick(seconds_between_ticks)
+ owner.adjust_bodytemperature(-12 * stacks * seconds_between_ticks)
+
+/datum/status_effect/void_chill/refresh(mob/living/new_owner, new_stacks, forced = FALSE)
+ . = ..()
+ if(forced)
+ set_stacks(new_stacks)
+ else
+ adjust_stacks(new_stacks)
+ owner.update_icon(UPDATE_OVERLAYS)
+
+///Updates the overlay that gets applied on our victim
+/datum/status_effect/void_chill/proc/update_stacks_overlay(atom/parent_atom, list/overlays)
+ SIGNAL_HANDLER
+
+ linked_alert?.update_appearance(UPDATE_ICON_STATE|UPDATE_DESC)
+ owner.remove_alt_appearance("heretic_status")
+ stacks_overlay = image('icons/effects/effects.dmi', owner, "void_chill_partial")
+ if(stacks >= 5)
+ stacks_overlay = image('icons/effects/effects.dmi', owner, "void_chill_oh_fuck")
+ owner.add_alt_appearance(/datum/atom_hud/alternate_appearance/basic/heretic, "heretic_status", stacks_overlay, NONE)
+
+/**
+ * Setter and adjuster procs for stacks
+ *
+ * Arguments:
+ * - new_stacks
+ *
+ */
+
+/datum/status_effect/void_chill/proc/set_stacks(new_stacks)
+ stacks = max(0, min(stack_limit, new_stacks))
+ update_movespeed(stacks)
+
+/datum/status_effect/void_chill/proc/adjust_stacks(new_stacks)
+ stacks = max(0, min(stack_limit, stacks + new_stacks))
+ update_movespeed(stacks)
+ if(stacks >= 5)
+ ADD_TRAIT(owner, TRAIT_HYPOTHERMIC, REF(src))
+
+///Updates the movespeed of owner based on the amount of stacks of the debuff
+/datum/status_effect/void_chill/proc/update_movespeed(stacks)
+ owner.add_movespeed_modifier(/datum/movespeed_modifier/void_chill, update = TRUE)
+ owner.add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/void_chill, update = TRUE, multiplicative_slowdown = (0.5 * stacks))
+ linked_alert.maptext = MAPTEXT_TINY_UNICODE("[stacks]")
+
+/datum/status_effect/void_chill/lasting
+ id = "lasting_void_chill"
+ duration = -1
+
+/datum/movespeed_modifier/void_chill
+ variable = TRUE
+ multiplicative_slowdown = 0.1
+
+//---- Screen alert
+/atom/movable/screen/alert/status_effect/void_chill
+ name = "Void Chill"
+ desc = "There's something freezing you from within and without. You've never felt cold this oppressive before..."
+ icon_state = "void_chill_minor"
+
+/atom/movable/screen/alert/status_effect/void_chill/update_icon_state()
+ . = ..()
+ if(!istype(attached_effect, /datum/status_effect/void_chill))
+ return
+ var/datum/status_effect/void_chill/chill_effect = attached_effect
+ if(chill_effect.stacks >= 5)
+ icon_state = "void_chill_oh_fuck"
+
+/atom/movable/screen/alert/status_effect/void_chill/update_desc(updates)
+ . = ..()
+ if(!istype(attached_effect, /datum/status_effect/void_chill))
+ return
+ var/datum/status_effect/void_chill/chill_effect = attached_effect
+ if(chill_effect.stacks >= 5)
+ desc = "You had your chance to run, now it's too late. You may never feel warmth again..."
diff --git a/code/modules/antagonists/malf_ai/malf_ai.dm b/code/modules/antagonists/malf_ai/malf_ai.dm
index 4dc2568fe0e89..dc92289f66bef 100644
--- a/code/modules/antagonists/malf_ai/malf_ai.dm
+++ b/code/modules/antagonists/malf_ai/malf_ai.dm
@@ -41,6 +41,7 @@
malfunction_flavor = strings(MALFUNCTION_FLAVOR_FILE, employer)
add_law_zero()
+ RegisterSignal(owner.current, COMSIG_SILICON_AI_CORE_STATUS, PROC_REF(core_status))
if(malf_sound)
owner.current.playsound_local(get_turf(owner.current), malf_sound, 100, FALSE, pressure_affected = FALSE, use_reverb = FALSE)
owner.current.grant_language(/datum/language/codespeak, source = LANGUAGE_MALF)
@@ -58,7 +59,7 @@
QDEL_NULL(malf_ai.malf_picker)
owner.special_role = null
-
+ UnregisterSignal(owner, COMSIG_SILICON_AI_CORE_STATUS)
return ..()
/// Generates a complete set of malf AI objectives up to the traitor objective limit.
@@ -197,7 +198,7 @@
"name" = category,
"items" = (category == malf_ai.malf_picker.selected_cat ? list() : null))
for(var/module in malf_ai.malf_picker.possible_modules[category])
- var/datum/ai_module/mod = malf_ai.malf_picker.possible_modules[category][module]
+ var/datum/ai_module/malf/mod = malf_ai.malf_picker.possible_modules[category][module]
cat["items"] += list(list(
"name" = mod.name,
"cost" = mod.cost,
@@ -222,7 +223,7 @@
for(var/category in malf_ai.malf_picker.possible_modules)
buyable_items += malf_ai.malf_picker.possible_modules[category]
for(var/key in buyable_items)
- var/datum/ai_module/valid_mod = buyable_items[key]
+ var/datum/ai_module/malf/valid_mod = buyable_items[key]
if(valid_mod.name == item_name)
malf_ai.malf_picker.purchase_module(malf_ai, valid_mod)
return TRUE
@@ -271,6 +272,14 @@
return malf_ai_icon
+/datum/antagonist/malf_ai/proc/core_status(datum/source)
+ SIGNAL_HANDLER
+
+ var/mob/living/silicon/ai/malf_owner = owner.current
+ if(malf_owner.linked_core)
+ return COMPONENT_CORE_ALL_GOOD
+ return COMPONENT_CORE_DISCONNECTED
+
//Subtype of Malf AI datum, used for one of the traitor final objectives
/datum/antagonist/malf_ai/infected
name = "Infected AI"
diff --git a/code/modules/antagonists/malf_ai/malf_ai_modules.dm b/code/modules/antagonists/malf_ai/malf_ai_modules.dm
index 90f3b76649230..a9f84c51dad1a 100644
--- a/code/modules/antagonists/malf_ai/malf_ai_modules.dm
+++ b/code/modules/antagonists/malf_ai/malf_ai_modules.dm
@@ -52,7 +52,7 @@ GLOBAL_LIST_INIT(blacklisted_malf_machines, typecacheof(list(
/obj/machinery/computer/gateway_control,
)))
-GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module))
+GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module/malf))
/// The malf AI action subtype. All malf actions are subtypes of this.
/datum/action/innate/ai
@@ -137,19 +137,19 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module))
return
/// Modules causing destruction
-/datum/ai_module/destructive
+/datum/ai_module/malf/destructive
category = "Destructive Modules"
/// Modules with stealthy and utility uses
-/datum/ai_module/utility
+/datum/ai_module/malf/utility
category = "Utility Modules"
/// Modules that are improving AI abilities and assets
-/datum/ai_module/upgrade
+/datum/ai_module/malf/upgrade
category = "Upgrade Modules"
/// Doomsday Device: Starts the self-destruct timer. It can only be stopped by killing the AI completely.
-/datum/ai_module/destructive/nuke_station
+/datum/ai_module/malf/destructive/nuke_station
name = "Doomsday Device"
description = "Activate a weapon that will disintegrate all organic life on the station after a 450 second delay. \
Can only be used while on the station, will fail if your core is moved off station or destroyed. \
@@ -372,7 +372,7 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module))
return TRUE
/// Hostile Station Lockdown: Locks, bolts, and electrifies every airlock on the station. After 90 seconds, the doors reset.
-/datum/ai_module/destructive/lockdown
+/datum/ai_module/malf/destructive/lockdown
name = "Hostile Station Lockdown"
description = "Overload the airlock, blast door and fire control networks, locking them down. \
Caution! This command also electrifies all airlocks. The networks will automatically reset after 90 seconds, briefly \
@@ -424,7 +424,7 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module))
CHECK_TICK
/// Override Machine: Allows the AI to override a machine, animating it into an angry, living version of itself.
-/datum/ai_module/destructive/override_machine
+/datum/ai_module/malf/destructive/override_machine
name = "Machine Override"
description = "Overrides a machine's programming, causing it to rise up and attack everyone except other machines. Four uses per purchase."
cost = 30
@@ -481,7 +481,7 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module))
new /mob/living/simple_animal/hostile/mimic/copy/machine(get_turf(to_animate), to_animate, caller, TRUE)
/// Destroy RCDs: Detonates all non-cyborg RCDs on the station.
-/datum/ai_module/destructive/destroy_rcd
+/datum/ai_module/malf/destructive/destroy_rcd
name = "Destroy RCDs"
description = "Send a specialised pulse to detonate all hand-held and exosuit Rapid Construction Devices on the station."
cost = 25
@@ -506,7 +506,7 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module))
owner.playsound_local(owner, 'sound/machines/twobeep.ogg', 50, 0)
/// Overload Machine: Allows the AI to overload a machine, detonating it after a delay. Two uses per purchase.
-/datum/ai_module/destructive/overload_machine
+/datum/ai_module/malf/destructive/overload_machine
name = "Machine Overload"
description = "Overheats an electrical machine, causing a small explosion and destroying it. Two uses per purchase."
cost = 20
@@ -567,7 +567,7 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module))
return TRUE
/// Blackout: Overloads a random number of lights across the station. Three uses.
-/datum/ai_module/destructive/blackout
+/datum/ai_module/malf/destructive/blackout
name = "Blackout"
description = "Attempts to overload the lighting circuits on the station, destroying some bulbs. Three uses per purchase."
cost = 15
@@ -601,7 +601,7 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module))
build_all_button_icons()
/// HIGH IMPACT HONKING
-/datum/ai_module/destructive/megahonk
+/datum/ai_module/malf/destructive/megahonk
name = "Percussive Intercomm Interference"
description = "Emit a debilitatingly percussive auditory blast through the station intercoms. Does not overpower hearing protection. Two uses per purchase."
cost = 20
@@ -632,7 +632,7 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module))
to_chat(honk_victim, span_clown("HOOOOONK!"))
/// Robotic Factory: Places a large machine that converts humans that go through it into cyborgs. Unlocking this ability removes shunting.
-/datum/ai_module/utility/place_cyborg_transformer
+/datum/ai_module/malf/utility/place_cyborg_transformer
name = "Robotic Factory (Removes Shunting)"
description = "Build a machine anywhere, using expensive nanomachines, that can convert a living human into a loyal cyborg slave when placed inside."
cost = 100
@@ -707,7 +707,7 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module))
return success
/// Air Alarm Safety Override: Unlocks the ability to enable dangerous modes on all air alarms.
-/datum/ai_module/utility/break_air_alarms
+/datum/ai_module/malf/utility/break_air_alarms
name = "Air Alarm Safety Override"
description = "Gives you the ability to disable safeties on all air alarms. This will allow you to use extremely dangerous environmental modes. \
Anyone can check the air alarm's interface and may be tipped off by their nonfunctionality."
@@ -733,7 +733,7 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module))
owner.playsound_local(owner, 'sound/machines/terminal_off.ogg', 50, 0)
/// Thermal Sensor Override: Unlocks the ability to disable all fire alarms from doing their job.
-/datum/ai_module/utility/break_fire_alarms
+/datum/ai_module/malf/utility/break_fire_alarms
name = "Thermal Sensor Override"
description = "Gives you the ability to override the thermal sensors on all fire alarms. \
This will remove their ability to scan for fire and thus their ability to alert."
@@ -764,7 +764,7 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module))
owner.playsound_local(owner, 'sound/machines/terminal_off.ogg', 50, 0)
/// Disable Emergency Lights
-/datum/ai_module/utility/emergency_lights
+/datum/ai_module/malf/utility/emergency_lights
name = "Disable Emergency Lights"
description = "Cuts emergency lights across the entire station. If power is lost to light fixtures, \
they will not attempt to fall back on emergency power reserves."
@@ -791,7 +791,7 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module))
owner.playsound_local(owner, 'sound/effects/light_flicker.ogg', 50, FALSE)
/// Reactivate Camera Network: Reactivates up to 30 cameras across the station.
-/datum/ai_module/utility/reactivate_cameras
+/datum/ai_module/malf/utility/reactivate_cameras
name = "Reactivate Camera Network"
description = "Runs a network-wide diagnostic on the camera network, resetting focus and re-routing power to failed cameras. \
Can be used to repair up to 30 cameras."
@@ -832,7 +832,7 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module))
build_all_button_icons()
/// Upgrade Camera Network: EMP-proofs all cameras, in addition to giving them X-ray vision.
-/datum/ai_module/upgrade/upgrade_cameras
+/datum/ai_module/malf/upgrade/upgrade_cameras
name = "Upgrade Camera Network"
description = "Install broad-spectrum scanning and electrical redundancy firmware to the camera network, enabling EMP-proofing and light-amplified X-ray vision. Upgrade is done immediately upon purchase." //I <3 pointless technobabble
//This used to have motion sensing as well, but testing quickly revealed that giving it to the whole cameranet is PURE HORROR.
@@ -841,7 +841,7 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module))
unlock_text = span_notice("OTA firmware distribution complete! Cameras upgraded: CAMSUPGRADED. Light amplification system online.")
unlock_sound = 'sound/items/rped.ogg'
-/datum/ai_module/upgrade/upgrade_cameras/upgrade(mob/living/silicon/ai/AI)
+/datum/ai_module/malf/upgrade/upgrade_cameras/upgrade(mob/living/silicon/ai/AI)
// Sets up nightvision
RegisterSignal(AI, COMSIG_MOB_UPDATE_SIGHT, PROC_REF(on_update_sight))
AI.update_sight()
@@ -864,13 +864,13 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module))
upgraded_cameras++
unlock_text = replacetext(unlock_text, "CAMSUPGRADED", "[upgraded_cameras]") //This works, since unlock text is called after upgrade()
-/datum/ai_module/upgrade/upgrade_cameras/proc/on_update_sight(mob/source)
+/datum/ai_module/malf/upgrade/upgrade_cameras/proc/on_update_sight(mob/source)
SIGNAL_HANDLER
// Dim blue, pretty
source.lighting_color_cutoffs = blend_cutoff_colors(source.lighting_color_cutoffs, list(5, 25, 35))
/// AI Turret Upgrade: Increases the health and damage of all turrets.
-/datum/ai_module/upgrade/upgrade_turrets
+/datum/ai_module/malf/upgrade/upgrade_turrets
name = "AI Turret Upgrade"
description = "Improves the power and health of all AI turrets. This effect is permanent. Upgrade is done immediately upon purchase."
cost = 30
@@ -878,7 +878,7 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module))
unlock_text = span_notice("You establish a power diversion to your turrets, upgrading their health and damage.")
unlock_sound = 'sound/items/rped.ogg'
-/datum/ai_module/upgrade/upgrade_turrets/upgrade(mob/living/silicon/ai/AI)
+/datum/ai_module/malf/upgrade/upgrade_turrets/upgrade(mob/living/silicon/ai/AI)
for(var/obj/machinery/porta_turret/ai/turret as anything in SSmachines.get_machines_by_type_and_subtypes(/obj/machinery/porta_turret/ai))
turret.AddElement(/datum/element/empprotection, EMP_PROTECT_ALL)
turret.max_integrity = 200
@@ -887,7 +887,7 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module))
turret.lethal_projectile_sound = 'sound/weapons/lasercannonfire.ogg'
/// Enhanced Surveillance: Enables AI to hear conversations going on near its active vision.
-/datum/ai_module/upgrade/eavesdrop
+/datum/ai_module/malf/upgrade/eavesdrop
name = "Enhanced Surveillance"
description = "Via a combination of hidden microphones and lip reading software, \
you are able to use your cameras to listen in on conversations. Upgrade is done immediately upon purchase."
@@ -896,12 +896,12 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module))
unlock_text = span_notice("OTA firmware distribution complete! Cameras upgraded: Enhanced surveillance package online.")
unlock_sound = 'sound/items/rped.ogg'
-/datum/ai_module/upgrade/eavesdrop/upgrade(mob/living/silicon/ai/AI)
+/datum/ai_module/malf/upgrade/eavesdrop/upgrade(mob/living/silicon/ai/AI)
if(AI.eyeobj)
AI.eyeobj.relay_speech = TRUE
/// Unlock Mech Domination: Unlocks the ability to dominate mechs. Big shocker, right?
-/datum/ai_module/upgrade/mecha_domination
+/datum/ai_module/malf/upgrade/mecha_domination
name = "Unlock Mech Domination"
description = "Allows you to hack into a mech's onboard computer, shunting all processes into it and ejecting any occupants. \
Do not allow the mech to leave the station's vicinity or allow it to be destroyed. \
@@ -912,10 +912,10 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module))
Loss of signal will result in total system lockout.