diff --git a/code/__DEFINES/tools.dm b/code/__DEFINES/tools.dm index a1504265fa5..76031d5a383 100644 --- a/code/__DEFINES/tools.dm +++ b/code/__DEFINES/tools.dm @@ -18,6 +18,8 @@ #define TOOL_KNIFE "knife" #define TOOL_BLOODFILTER "bloodfilter" #define TOOL_ROLLINGPIN "rollingpin" +/// Can be used to scrape rust off an any atom; which will result in the Rust Component being qdel'd +#define TOOL_RUSTSCRAPER "rustscraper" // If delay between the start and the end of tool operation is less than MIN_TOOL_SOUND_DELAY, // tool sound is only played when op is started. If not, it's played twice. diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm index ecdf85a398e..8971cfc322f 100644 --- a/code/__DEFINES/traits.dm +++ b/code/__DEFINES/traits.dm @@ -566,6 +566,8 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define HIGHLANDER_TRAIT "highlander" ///generic atom traits +/// Trait from [/datum/component/rust]. Its rusty and should be applying a special overlay to denote this. +#define TRAIT_RUSTY "rust_trait" #define DO_NOT_SPLASH "do_not_splash" // unique trait sources, still defines diff --git a/code/datums/components/rust.dm b/code/datums/components/rust.dm new file mode 100644 index 00000000000..92833de3d80 --- /dev/null +++ b/code/datums/components/rust.dm @@ -0,0 +1,85 @@ +/** + * Adding this component to an Atom will have it automatically render an overlay. + * The overlay can be specified in new as the first and only parameter; it defaults to "rust" if not included. + */ +/datum/component/rust + dupe_mode = COMPONENT_DUPE_UNIQUE + /// Internal variable to store the rust overlay we are using to avoid regenerating it every overlay update call + var/mutable_appearance/rust_overlay + +/turf/closed/wall/rust/New() + var/atom/wall_new = new /turf/closed/wall(src) + wall_new.AddComponent(/datum/component/rust) + +/turf/closed/wall/r_wall/rust/New() + var/atom/wall_new = new /turf/closed/wall/r_wall(src) + wall_new.AddComponent(/datum/component/rust) + +/turf/open/floor/plating/rust/New() + var/atom/wall_new = new /turf/open/floor/plating(src) + wall_new.AddComponent(/datum/component/rust) + +/datum/component/rust/Initialize(rust_iconstate = "rust") + . = ..() + if(!isatom(parent)) + return COMPONENT_INCOMPATIBLE + var/atom/parent_atom = parent + if(!(rust_iconstate in icon_states(parent_atom.icon))) + return COMPONENT_INCOMPATIBLE + + rust_overlay = mutable_appearance(parent_atom.icon, rust_iconstate) + +/datum/component/rust/RegisterWithParent() + RegisterSignal(parent, COMSIG_ATOM_UPDATE_OVERLAYS, .proc/apply_rust_overlay) + RegisterSignal(parent, list(COMSIG_ATOM_SECONDARY_TOOL_ACT(TOOL_WELDER), COMSIG_ATOM_SECONDARY_TOOL_ACT(TOOL_RUSTSCRAPER)), .proc/secondary_tool_act) + RegisterSignal(parent, COMSIG_PARENT_PREQDELETED, .proc/parent_del) + RegisterSignal(parent, COMSIG_PARENT_EXAMINE, .proc/handle_examine) + ADD_TRAIT(parent, TRAIT_RUSTY, src) + +/datum/component/rust/UnregisterFromParent() + UnregisterSignal(parent,\ + list(COMSIG_ATOM_UPDATE_OVERLAYS, COMSIG_ATOM_SECONDARY_TOOL_ACT(TOOL_WELDER), COMSIG_ATOM_SECONDARY_TOOL_ACT(TOOL_RUSTSCRAPER)), COMSIG_PARENT_PREQDELETED) + REMOVE_TRAIT(parent, TRAIT_RUSTY, src) + var/atom/parent_atom = parent + parent_atom.update_icon(UPDATE_OVERLAYS) + +/datum/component/rust/proc/handle_examine(datum/source, mob/user, list/examine_text) + SIGNAL_HANDLER + examine_text += span_notice("[source] is very rusty, you could probably burn or scrape it off.") + +/datum/component/rust/proc/apply_rust_overlay(atom/parent_atom, list/overlays) + SIGNAL_HANDLER + overlays |= rust_overlay + +/datum/component/rust/proc/parent_del() + SIGNAL_HANDLER + qdel(src) + +/datum/component/rust/Destroy() + rust_overlay = null + return ..() + +/// We call this from secondary_tool_act because we sleep with do_after +/datum/component/rust/proc/handle_tool_use(atom/source, mob/user, obj/item/item) + switch(item.tool_behaviour) + if(TOOL_WELDER) + if(item.use(5)) + user.balloon_alert(user, "burning off rust...") + if(!do_after(user, 5 SECONDS * item.toolspeed, parent)) + return + user.balloon_alert(user, "burned off rust") + qdel(src) + return + if(TOOL_RUSTSCRAPER) + user.balloon_alert(user, "scraping off rust...") + if(!do_after(user, 2 SECONDS * item.toolspeed, parent)) + return + user.balloon_alert(user, "scraped off rust") + qdel(src) + return + +/// Because do_after sleeps we register the signal here and defer via an async call +/datum/component/rust/proc/secondary_tool_act(atom/source, mob/user, obj/item/item) + SIGNAL_HANDLER + INVOKE_ASYNC(src, .proc/handle_tool_use, source, user, item) + return COMPONENT_BLOCK_TOOL_ATTACK diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 5f4662cbfcb..ff042c73c5a 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -1936,7 +1936,7 @@ * Override this if you want custom behaviour in whatever gets hit by the rust */ /atom/proc/rust_heretic_act() - return + AddComponent(/datum/component/rust) /** * Used to set something as 'open' if it's being used as a supplypod diff --git a/code/game/objects/items/debug_items.dm b/code/game/objects/items/debug_items.dm index 61913d89d50..86cbfb48700 100644 --- a/code/game/objects/items/debug_items.dm +++ b/code/game/objects/items/debug_items.dm @@ -66,7 +66,8 @@ "Bonesetter" = image(icon = 'icons/obj/surgery.dmi', icon_state = "bone setter"), "Knife" = image(icon = 'icons/obj/kitchen.dmi', icon_state = "knife"), "Blood Filter" = image(icon = 'icons/obj/surgery.dmi', icon_state = "bloodfilter"), - "Rolling Pin" = image(icon = 'icons/obj/kitchen.dmi', icon_state = "rolling_pin") + "Rolling Pin" = image(icon = 'icons/obj/kitchen.dmi', icon_state = "rolling_pin"), + "Wire Brush" = image(icon = 'icons/obj/tools.dmi', icon_state = "wirebrush"), ) var/tool_result = show_radial_menu(user, src, tool_list, custom_check = CALLBACK(src, .proc/check_menu, user), require_near = TRUE, tooltips = TRUE) if(!check_menu(user)) @@ -110,3 +111,5 @@ tool_behaviour = TOOL_BLOODFILTER if("Rolling Pin") tool_behaviour = TOOL_ROLLINGPIN + if("Wire Brush") + tool_behaviour = TOOL_RUSTSCRAPER diff --git a/code/game/objects/items/tools/wirebrush.dm b/code/game/objects/items/tools/wirebrush.dm new file mode 100644 index 00000000000..cd193cf74a6 --- /dev/null +++ b/code/game/objects/items/tools/wirebrush.dm @@ -0,0 +1,63 @@ +/** + * The wirebrush is a tool whose sole purpose is to remove rust from anything that is rusty. + * Because of the inherent nature of hard countering rust heretics it does it very slowly. + */ +/obj/item/wirebrush + name = "wirebrush" + desc = "A tool that is used to scrub the rust thoroughly off walls. Not for hair!" + icon = 'icons/obj/tools.dmi' + icon_state = "wirebrush" + tool_behaviour = TOOL_RUSTSCRAPER + toolspeed = 1 + +/** + * An advanced form of the wirebrush that trades the safety of the user for instant rust removal. + * If the person using this is unlucky they are going to die painfully. + */ +/obj/item/wirebrush/advanced + name = "advanced wirebrush" + desc = "An advanced wirebrush; uses radiation to almost instantly liquify rust." + icon_state = "wirebrush_adv" + toolspeed = 0.1 + + /// The amount of radiation to give to the user of this tool; regardless of what they did with it. + var/radiation_on_use = 20 + + /// How likely is a critical fail? + var/crit_fail_prob = 1 + + /// The amount of radiation to give to the user if they roll the worst effects. Negative numbers will heal radiation instead! + var/crit_fail_rads = 50 + + /// The amount of damage to take in BOTH Tox and Oxy on critical fail + var/crit_fail_damage = 15 + + /// We only apply damage and force vomit if the user has OVER this many rads + var/crit_fail_rads_threshold = 300 + +/obj/item/wirebrush/advanced/examine(mob/user) + . = ..() + . += span_danger("There is a warning label that indicates extended use of [src] may result in loss of hair, yellowing skin, and death.") + +/obj/item/wirebrush/advanced/pre_attack(atom/A, mob/living/user) + . = ..() + + if(!istype(user)) + return + + if(prob(crit_fail_prob)) + to_chat(user, span_danger("You feel a sharp pain as your entire body grows oddly warm.")) + user.radiation += crit_fail_rads + if(user.radiation > crit_fail_rads_threshold) // If you ignore the warning signs you get punished + user.emote("vomit") + user.adjustToxLoss(crit_fail_damage, forced=TRUE) + user.adjustOxyLoss(crit_fail_damage, forced=TRUE) + return + + user.radiation += radiation_on_use + + if(prob(25)) + user.emote("cough") + +/obj/item/wirebrush/advanced/pre_attack_secondary() + return SECONDARY_ATTACK_CALL_NORMAL diff --git a/code/game/objects/structures/statues.dm b/code/game/objects/structures/statues.dm index e7323cf55a0..8eeb5b920a4 100644 --- a/code/game/objects/structures/statues.dm +++ b/code/game/objects/structures/statues.dm @@ -313,6 +313,8 @@ drop_sound = 'sound/items/handling/screwdriver_drop.ogg' pickup_sound = 'sound/items/handling/screwdriver_pickup.ogg' sharpness = SHARP_POINTY + tool_behaviour = TOOL_RUSTSCRAPER + toolspeed = 3 // You're gonna have a bad time /// Block we're currently carving in var/obj/structure/carving_block/prepared_block diff --git a/code/game/turfs/closed/wall/misc_walls.dm b/code/game/turfs/closed/wall/misc_walls.dm index af5b80b0649..f9b262d474c 100644 --- a/code/game/turfs/closed/wall/misc_walls.dm +++ b/code/game/turfs/closed/wall/misc_walls.dm @@ -83,9 +83,6 @@ smoothing_flags = SMOOTH_BITMASK hardness = 45 -/turf/closed/wall/rust/rust_heretic_act() - ScrapeAway() - /turf/closed/wall/r_wall/rust name = "rusted reinforced wall" desc = "A huge chunk of rusted reinforced metal." @@ -95,11 +92,6 @@ smoothing_flags = SMOOTH_BITMASK hardness = 15 -/turf/closed/wall/r_wall/rust/rust_heretic_act() - if(prob(50)) - return - ScrapeAway() - /turf/closed/wall/mineral/bronze name = "clockwork wall" desc = "A huge chunk of bronze, decorated like gears and cogs." diff --git a/code/game/turfs/closed/wall/reinf_walls.dm b/code/game/turfs/closed/wall/reinf_walls.dm index fbcff87ac79..a323ddf34e3 100644 --- a/code/game/turfs/closed/wall/reinf_walls.dm +++ b/code/game/turfs/closed/wall/reinf_walls.dm @@ -230,9 +230,10 @@ /turf/closed/wall/r_wall/rust_heretic_act() if(prob(50)) return - if(prob(70)) - new /obj/effect/temp_visual/glowing_rune(src) - ChangeTurf(/turf/closed/wall/r_wall/rust) + if(HAS_TRAIT(src, TRAIT_RUSTY)) + ScrapeAway() + return + return ..() /turf/closed/wall/r_wall/syndicate name = "hull" diff --git a/code/game/turfs/closed/walls.dm b/code/game/turfs/closed/walls.dm index 282caf3ae6e..e6fb3889adf 100644 --- a/code/game/turfs/closed/walls.dm +++ b/code/game/turfs/closed/walls.dm @@ -309,8 +309,11 @@ add_overlay(dent_decals) /turf/closed/wall/rust_heretic_act() + if(HAS_TRAIT(src, TRAIT_RUSTY)) + ScrapeAway() + return if(prob(70)) new /obj/effect/temp_visual/glowing_rune(src) - ChangeTurf(/turf/closed/wall/rust) + return ..() #undef MAX_DENT_DECALS diff --git a/code/game/turfs/open/floor/iron_floor.dm b/code/game/turfs/open/floor/iron_floor.dm index 5ae6755cc1a..2d208217ec2 100644 --- a/code/game/turfs/open/floor/iron_floor.dm +++ b/code/game/turfs/open/floor/iron_floor.dm @@ -17,7 +17,8 @@ /turf/open/floor/iron/rust_heretic_act() if(prob(70)) new /obj/effect/temp_visual/glowing_rune(src) - ChangeTurf(/turf/open/floor/plating/rust) + ChangeTurf(/turf/open/floor/plating) + return ..() /turf/open/floor/iron/update_icon_state() diff --git a/code/game/turfs/open/floor/misc_floor.dm b/code/game/turfs/open/floor/misc_floor.dm index 31c85564516..692550c8590 100644 --- a/code/game/turfs/open/floor/misc_floor.dm +++ b/code/game/turfs/open/floor/misc_floor.dm @@ -207,9 +207,6 @@ /turf/open/floor/plating/rust/plasma initial_gas_mix = "plasma=104;TEMP=293.15" -/turf/open/floor/plating/rust/rust_heretic_act() - return - /turf/open/floor/stone name = "stone brick floor" desc = "Odd, really, how it looks exactly like the iron walls yet is stone instead of iron. Now, if that's really more of a complaint about\ diff --git a/code/game/turfs/open/floor/plating.dm b/code/game/turfs/open/floor/plating.dm index 687386bc49d..99f4b875ef2 100644 --- a/code/game/turfs/open/floor/plating.dm +++ b/code/game/turfs/open/floor/plating.dm @@ -95,7 +95,7 @@ /turf/open/floor/plating/rust_heretic_act() if(prob(70)) new /obj/effect/temp_visual/glowing_rune(src) - ChangeTurf(/turf/open/floor/plating/rust) + return ..() /turf/open/floor/plating/make_plating(force = FALSE) return diff --git a/code/modules/antagonists/eldritch_cult/knowledge/rust_lore.dm b/code/modules/antagonists/eldritch_cult/knowledge/rust_lore.dm index d82cf4948ae..63ef9d195fb 100644 --- a/code/modules/antagonists/eldritch_cult/knowledge/rust_lore.dm +++ b/code/modules/antagonists/eldritch_cult/knowledge/rust_lore.dm @@ -262,8 +262,8 @@ edge_turfs = list() var/list/removal_list = list() var/max_dist = 1 - for(var/turfie in turfs) - if(!istype(turfie,/turf/closed/wall/rust) && !istype(turfie,/turf/closed/wall/r_wall/rust) && !istype(turfie,/turf/open/floor/plating/rust)) + for(var/atom/turfie as anything in turfs) + if(!HAS_TRAIT(turfie, TRAIT_RUSTY)) removal_list += turfie max_dist = max(max_dist, get_dist(turfie,centre) +1) turfs -= removal_list diff --git a/code/modules/research/designs/tool_designs.dm b/code/modules/research/designs/tool_designs.dm index ba5d12486ed..f2cbac71291 100644 --- a/code/modules/research/designs/tool_designs.dm +++ b/code/modules/research/designs/tool_designs.dm @@ -268,3 +268,24 @@ materials = list(/datum/material/iron = 2000, /datum/material/silver = 1500, /datum/material/plasma = 500, /datum/material/titanium = 1500) category = list("Tool Designs") departmental_flags = DEPARTMENTAL_FLAG_MEDICAL + +/datum/design/wirebrush + name = "Wirebrush" + desc = "A tool to remove rust from walls." + id = "wirebrush" + build_type = AUTOLATHE | PROTOLATHE | AWAY_LATHE + category = list("initial", "Tools") + materials = list(/datum/material/iron = 200, /datum/material/glass = 200) + build_path = /obj/item/wirebrush + category = list("Equipment") + departmental_flags = DEPARTMENTAL_FLAG_SERVICE + +/datum/design/wirebrush_adv + name = "Advanced Wirebrush" + desc = "An advanced wirebrush." + id = "wirebrush_adv" + build_type = PROTOLATHE | AWAY_LATHE + materials = list(/datum/material/iron = 200, /datum/material/glass = 200, /datum/material/uranium = 200, /datum/material/plasma = 200) + build_path = /obj/item/wirebrush/advanced + category = list("Equipment") + departmental_flags = DEPARTMENTAL_FLAG_SERVICE diff --git a/code/modules/research/techweb/all_nodes.dm b/code/modules/research/techweb/all_nodes.dm index 4f84f54036e..0e8f23e5baa 100644 --- a/code/modules/research/techweb/all_nodes.dm +++ b/code/modules/research/techweb/all_nodes.dm @@ -151,6 +151,7 @@ "tscanner", "welding_helmet", "welding_tool", + "wirebrush", "wirecutters", "wrench", ) @@ -1213,6 +1214,7 @@ "laserscalpel", "mechanicalpinches", "searingtool", + "wirebrush_adv", ) research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 7500) discount_experiments = list(/datum/experiment/scanning/random/material/hard/one = 5000) diff --git a/icons/obj/tools.dmi b/icons/obj/tools.dmi index 5cc32e7af07..ebc2ec637a5 100644 Binary files a/icons/obj/tools.dmi and b/icons/obj/tools.dmi differ diff --git a/icons/turf/walls/reinforced_wall.dmi b/icons/turf/walls/reinforced_wall.dmi index c7b05315d50..35d64734e14 100644 Binary files a/icons/turf/walls/reinforced_wall.dmi and b/icons/turf/walls/reinforced_wall.dmi differ diff --git a/icons/turf/walls/wall.dmi b/icons/turf/walls/wall.dmi index 651227fe8de..4e7efd1e23e 100644 Binary files a/icons/turf/walls/wall.dmi and b/icons/turf/walls/wall.dmi differ diff --git a/tgstation.dme b/tgstation.dme index 9df91f0c29b..272ffd2578c 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -552,6 +552,7 @@ #include "code\datums\components\rename.dm" #include "code\datums\components\rot.dm" #include "code\datums\components\rotation.dm" +#include "code\datums\components\rust.dm" #include "code\datums\components\shell.dm" #include "code\datums\components\shielded.dm" #include "code\datums\components\shrink.dm" @@ -1371,6 +1372,7 @@ #include "code\game\objects\items\tools\crowbar.dm" #include "code\game\objects\items\tools\screwdriver.dm" #include "code\game\objects\items\tools\weldingtool.dm" +#include "code\game\objects\items\tools\wirebrush.dm" #include "code\game\objects\items\tools\wirecutters.dm" #include "code\game\objects\items\tools\wrench.dm" #include "code\game\objects\structures\ai_core.dm"