From 8e602afb32e13046ec594cd965f3b6b854100eb9 Mon Sep 17 00:00:00 2001 From: Batrachophreno Date: Thu, 26 Feb 2026 20:12:05 -0500 Subject: [PATCH] Paint gun consolidation and crate/locker painting (#21902) We don't need a million paint guns. Makes it so a single paint gun can paint whatever you want. Which now also includes crates and lockers. changes: - rscadd: "Paint sprayers can now be used on unpainted crates and lockers to give them a custom appearance." - rscadd: "Adds paint sprayers to Hangar Tech lockers." - qol: "Moves pipe painter functionality to paint sprayers; pipe painters now just flavor objects on some offsites." - qol: "Adds paint sprayers to allowed items list for utility toolbelts." - imageadd: "Codersprites pipe painter with recolorable paint storage component indicating current color (used by paint sprayer)." - imagedel: "Removes old paint sprayer sprite." - bugfix: "Removes old runtime caused by targeting turfs w/ paint sprayers that don't have flooring singletons assigned." Screenshot 2026-02-20 142403 Screenshot 2026-02-20 142424 image --- aurorastation.dme | 1 - code/datums/trading/goods.dm | 1 - .../objects/items/devices/paint_sprayer.dm | 141 +++++++++++++++++- .../objects/items/devices/pipe_painter.dm | 35 ----- .../objects/items/weapons/storage/belt.dm | 3 +- .../structures/crates_lockers/closets.dm | 26 +++- .../closets/secure/engineering.dm | 2 - .../closets/secure/operations.dm | 1 + code/modules/atmospherics/atmospherics.dm | 2 +- code/modules/atmospherics/pipes.dm | 4 +- code/modules/cargo/items/atmos.dm | 6 +- code/modules/clothing/suits/hazardvests.dm | 2 +- .../mob/living/silicon/robot/robot_modules.dm | 3 - html/changelogs/Bat-PaintGun.yml | 64 ++++++++ icons/obj/item/paint_sprayer.dmi | Bin 935 -> 804 bytes icons/obj/item/pipe_painter.dmi | Bin 745 -> 0 bytes 16 files changed, 235 insertions(+), 56 deletions(-) delete mode 100644 code/game/objects/items/devices/pipe_painter.dm create mode 100644 html/changelogs/Bat-PaintGun.yml delete mode 100644 icons/obj/item/pipe_painter.dmi diff --git a/aurorastation.dme b/aurorastation.dme index f726fa459c5..18f07b737fb 100644 --- a/aurorastation.dme +++ b/aurorastation.dme @@ -1231,7 +1231,6 @@ #include "code\game\objects\items\devices\paint_sprayer.dm" #include "code\game\objects\items\devices\personal_shield.dm" #include "code\game\objects\items\devices\pin_extractor.dm" -#include "code\game\objects\items\devices\pipe_painter.dm" #include "code\game\objects\items\devices\powersink.dm" #include "code\game\objects\items\devices\radio_jammer.dm" #include "code\game\objects\items\devices\scanners.dm" diff --git a/code/datums/trading/goods.dm b/code/datums/trading/goods.dm index d7951bda7d2..cbbfa277bb9 100644 --- a/code/datums/trading/goods.dm +++ b/code/datums/trading/goods.dm @@ -223,7 +223,6 @@ Sells devices, odds and ends, and medical stuff /obj/item/lightreplacer = TRADER_THIS_TYPE, /obj/item/megaphone = TRADER_THIS_TYPE, /obj/item/paicard = TRADER_THIS_TYPE, - /obj/item/pipe_painter = TRADER_THIS_TYPE, /obj/item/healthanalyzer = TRADER_THIS_TYPE, /obj/item/breath_analyzer = TRADER_THIS_TYPE, /obj/item/analyzer = TRADER_ALL, diff --git a/code/game/objects/items/devices/paint_sprayer.dm b/code/game/objects/items/devices/paint_sprayer.dm index 72d4cb62b62..8311a894068 100644 --- a/code/game/objects/items/devices/paint_sprayer.dm +++ b/code/game/objects/items/devices/paint_sprayer.dm @@ -8,7 +8,8 @@ desc = "A Hephaestus-made paint gun that uses microbes to replenish its paint storage. Very high-tech and fancy too!" icon = 'icons/obj/item/paint_sprayer.dmi' icon_state = "paint_sprayer" - item_state = "mister" + item_state = "paint_sprayer" + contained_sprite = TRUE var/decal = "remove all decals" var/paint_dir = "precise" var/paint_colour = COLOR_WHITE @@ -79,9 +80,58 @@ "bulkhead black" = COLOR_WALL_GUNMETAL ) + var/list/locker_paint_schemes = list( + "Fire Control" = "fire", + "Emergency O2" = "emergency", + "Medical" = "med", + "Ops (Mining)" = "miner", + "Ops (Hangar Tech)" = "hangar_tech", + "Ops (Machinist)" = "machinist", + "Hazmat" = "hazmat", + "Hazmat (Custodial)" = "hazmat_custodial", + "Engi (Tool)" = "eng_tool", + "Engi (Rad)" = "eng_rad", + "Engi (Elec)" = "eng_elec", + "Engi (Weld)" = "eng_weld", + "Engi (L2)" = "eng_l2", + "Atmos" = "atmos", + "Security" = "sec", + "Hydroponics" = "hydro" + ) + + var/list/crate_paint_schemes = list( + "Fire Control" = "fire", + "Emergency O2" = "o2_crate", + "Medical" = "medical_crate", + "Science" = "science_crate", + "Engi (Tool)" = "eng_tool", + "Engi (Rad)" = "eng_rad", + "Engi (Elec)" = "eng_elec", + "Engi (Weld)" = "eng_weld", + "Engi (L2)" = "eng_l2", + "Security" = "security_crate", + "Contraband Stripes" = "secgear_crate", + "Hydroponics" = "hydro_crate" + ) + + /// Pipe painting modes + var/list/modes + var/mode + + +/// Initialize available pipe color modes. +/obj/item/paint_sprayer/New() + ..() + modes = new() + for(var/C in GLOB.pipe_colors) + modes += "[C]" + mode = pick(modes) + /obj/item/paint_sprayer/mechanics_hints(mob/user, distance, is_adjacent) . += ..() - . += "CTRL-click a turf with the paint sprayer to copy the color(s) used on it." + . += "Use a paint sprayer on yourself to configure it." + . += "Paint sprayers can be used on the following targets: floors, airlocks, exosuit frames and components, beds, atmos pipes, and (plain grey) lockers/crates." + . += "CTRL-click a turf or airlock with the paint sprayer to copy the color(s) used on it." . += "SHIFT-click a turf with the paint sprayer to clear all decals from it." /obj/item/paint_sprayer/feedback_hints(mob/user, distance, is_adjacent) @@ -126,8 +176,24 @@ else if (istype(A, /turf/simulated/floor)) return paint_floor(A, user, params) + else if (istype(A, /obj/structure/closet/crate)) + return paint_crate(A, user, params) + + else if (istype(A, /obj/structure/closet)) + return paint_locker(A, user, params) + + else if(istype(A,/obj/machinery/atmospherics/pipe)) + var/obj/machinery/atmospherics/pipe/P = A + P.change_color(GLOB.pipe_colors[mode]) + playsound(get_turf(src), 'sound/effects/spray3.ogg', 30, 1, -6) + + else if(istype(A, /obj/item/pipe) && pipe_color_check(GLOB.pipe_colors[mode])) + var/obj/item/pipe/P = A + P.color = GLOB.pipe_colors[mode] + playsound(get_turf(src), 'sound/effects/spray3.ogg', 30, 1, -6) + /obj/item/paint_sprayer/proc/paint_floor(turf/simulated/floor/F, mob/user, params) - if(!F.flooring.can_paint) + if(!F.flooring?.can_paint) to_chat(user, SPAN_WARNING("\The [src] cannot paint this type of flooring.")) return @@ -185,20 +251,22 @@ new painting_decal(F, painting_dir, painting_colour) /obj/item/paint_sprayer/attack_self(var/mob/user) - var/choice = tgui_alert(user, "Do you wish to change the decal type, paint direction, or paint colour?", "Paint Sprayer", list("Decal","Direction", "Colour")) + var/choice = tgui_input_list(user, "Do you wish to change: decal type, paint direction, paint colour (for turfs), or pipe colour mode?", "Paint Sprayer", list("Decal","Direction","Colour","Pipe Colour"), 30 SECONDS) if(choice == "Decal") choose_decal() else if(choice == "Direction") choose_direction() else if(choice == "Colour") choose_colour() + else if(choice == "Pipe Colour") + choose_pipe_colour() /obj/item/paint_sprayer/proc/change_colour(new_colour, mob/user) if (new_colour) paint_colour = new_colour if (user) add_fingerprint(user) - to_chat(user, SPAN_NOTICE("You set \the [src] to paint with a new color.")) + to_chat(user, SPAN_NOTICE("You set \the [src] to paint with a new colour.")) update_icon() playsound(src, 'sound/weapons/blade_open.ogg', 30, 1) return TRUE @@ -365,5 +433,68 @@ paint_dir = new_dir to_chat(usr, SPAN_NOTICE("You set \the [src] direction to '[paint_dir]'.")) +/obj/item/paint_sprayer/verb/choose_pipe_colour(var/mob/user) + mode = tgui_input_list(user, "Choose a colour.", "Pipe Painter", modes, mode) + +/obj/item/paint_sprayer/proc/paint_locker(obj/structure/closet/target_closet, mob/user, input_text) + if(!target_closet.can_label) + to_chat(user, SPAN_NOTICE("This container has already been painted.")) + return FALSE + var/paint_job = tgui_input_list(usr, "Choose locker paint scheme.", "Paint Sprayer", locker_paint_schemes) + if(paint_job) + var/new_icon_state = locker_paint_schemes[paint_job] + target_closet.paint_container(new_icon_state) + playsound(get_turf(src), 'sound/effects/spray3.ogg', 30, 1, -6) + return TRUE + +/obj/item/paint_sprayer/proc/paint_crate(obj/structure/closet/crate/target_crate, mob/user, input_text) + if(!target_crate.can_label) + to_chat(user, SPAN_NOTICE("This container has already been painted.")) + return FALSE + var/paint_job = tgui_input_list(usr, "Choose crate paint scheme.", "Paint Sprayer", crate_paint_schemes) + if(paint_job) + var/new_icon_state = crate_paint_schemes[paint_job] + target_crate.paint_container(new_icon_state) + playsound(get_turf(src), 'sound/effects/spray3.ogg', 30, 1, -6) + . = TRUE + #undef AIRLOCK_REGION_PAINT #undef AIRLOCK_REGION_STRIPE + + +// Pipe painter still exists but only as offsite flavor. +/obj/item/pipe_painter + name = "pipe painter" + icon = 'icons/obj/item/paint_sprayer.dmi' + icon_state = "pipe_painter" + item_state = "pipe_painter" + var/list/modes + var/mode + +/obj/item/pipe_painter/feedback_hints(mob/user, distance, is_adjacent) + . += ..() + . += "It is in [mode] mode." + +/obj/item/pipe_painter/New() + ..() + modes = new() + for(var/C in GLOB.pipe_colors) + modes += "[C]" + mode = pick(modes) + +/obj/item/pipe_painter/afterattack(var/atom/A, var/mob/user, proximity) + if(!proximity) + return + if(!in_range(user, A)) + return + else if(is_type_in_list(A, list(/obj/machinery/atmospherics/pipe/tank, /obj/machinery/atmospherics/pipe/simple/heat_exchanging))) + return + else if(istype(A,/obj/machinery/atmospherics/pipe)) + var/obj/machinery/atmospherics/pipe/P = A + P.change_color(GLOB.pipe_colors[mode]) + else if(istype(A, /obj/item/pipe) && pipe_color_check(GLOB.pipe_colors[mode])) + var/obj/item/pipe/P = A + P.color = GLOB.pipe_colors[mode] + +/obj/item/pipe_painter/attack_self(var/mob/user) + mode = tgui_input_list(user, "Which colour do you want to use?", "Pipe Painter", modes, mode) diff --git a/code/game/objects/items/devices/pipe_painter.dm b/code/game/objects/items/devices/pipe_painter.dm deleted file mode 100644 index b398ab9436a..00000000000 --- a/code/game/objects/items/devices/pipe_painter.dm +++ /dev/null @@ -1,35 +0,0 @@ -/obj/item/pipe_painter - name = "pipe painter" - icon = 'icons/obj/item/pipe_painter.dmi' - icon_state = "pipe_painter" - item_state = "pipe_painter" - var/list/modes - var/mode - -/obj/item/pipe_painter/feedback_hints(mob/user, distance, is_adjacent) - . += ..() - . += "It is in [mode] mode." - -/obj/item/pipe_painter/New() - ..() - modes = new() - for(var/C in GLOB.pipe_colors) - modes += "[C]" - mode = pick(modes) - -/obj/item/pipe_painter/afterattack(var/atom/A, var/mob/user, proximity) - if(!proximity) - return - if(!in_range(user, A)) - return - else if(is_type_in_list(A, list(/obj/machinery/atmospherics/pipe/tank, /obj/machinery/atmospherics/pipe/simple/heat_exchanging))) - return - else if(istype(A,/obj/machinery/atmospherics/pipe)) - var/obj/machinery/atmospherics/pipe/P = A - P.change_color(GLOB.pipe_colors[mode]) - else if(istype(A, /obj/item/pipe) && pipe_color_check(GLOB.pipe_colors[mode])) - var/obj/item/pipe/P = A - P.color = GLOB.pipe_colors[mode] - -/obj/item/pipe_painter/attack_self(var/mob/user) - mode = tgui_input_list(user, "Which colour do you want to use?", "Pipe Painter", modes, mode) diff --git a/code/game/objects/items/weapons/storage/belt.dm b/code/game/objects/items/weapons/storage/belt.dm index cf9c825e7d6..158b20de654 100644 --- a/code/game/objects/items/weapons/storage/belt.dm +++ b/code/game/objects/items/weapons/storage/belt.dm @@ -122,7 +122,8 @@ /obj/item/price_scanner, /obj/item/cratescanner, /obj/item/destTagger, - /obj/item/quikpay + /obj/item/quikpay, + /obj/item/paint_sprayer ) content_overlays = TRUE diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm index a3284de8a89..c143390f5ea 100644 --- a/code/game/objects/structures/crates_lockers/closets.dm +++ b/code/game/objects/structures/crates_lockers/closets.dm @@ -79,6 +79,9 @@ /// Used by body bags and air bubbles. var/contains_body = FALSE + /// If its a plain grey closet or crate, you can use the paint sprayer on it ONCE to change its appearance. + var/can_label = FALSE + /obj/structure/closet/mechanics_hints(mob/user, distance, is_adjacent) . += ..() . += "When closed, a welder could be used to weld the closet shut." @@ -124,6 +127,10 @@ fill() if(secure) verbs += /obj/structure/closet/proc/verb_togglelock + + // Only plain grey crates and closets can be repainted. Handle label-ability here so we don't have to deal with a ton of bespoke definition adjustments. + if(icon_state == "crate" || icon_state == "generic") + can_label = TRUE return mapload ? INITIALIZE_HINT_LATELOAD : INITIALIZE_HINT_NORMAL /obj/structure/closet/LateInitialize() @@ -492,8 +499,10 @@ attack_hand(user) else if(istype(attacking_item,/obj/item/card/id) && secure) togglelock(user) + else if(istype(attacking_item, /obj/item/paint_sprayer)) + return -// Secure locker cutting open stuff. + // Secure locker cutting open stuff. else if(!opened && secure) if(!broken && istype(attacking_item,/obj/item/material/twohanded/chainsaw)) var/obj/item/material/twohanded/chainsaw/ChainSawVar = attacking_item @@ -834,6 +843,21 @@ new /obj/item/stack/material/steel(get_turf(src)) qdel(src) +/obj/structure/closet/proc/paint_container(paint_color) + // Fucking engineering container sprites. Closets and crates handle their main sprite/door naming differently. + var/eng_prefix = findtext(paint_color,"eng_") + if(eng_prefix) + if(istype(src,/obj/structure/closet/crate)) + icon_state = paint_color + icon_door = "eng" + else + icon_state = "eng" + icon_door = paint_color + // And back to sanity. + else + icon_state = paint_color + can_label = FALSE + update_icon() /* ========================== Contents Scanner diff --git a/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm b/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm index 995b15c24ce..1b9a6946380 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm @@ -86,7 +86,6 @@ // Painters new /obj/item/paint_sprayer(src) - new /obj/item/pipe_painter(src) // Atmospherics Technician /obj/structure/closet/secure_closet/atmos_personal @@ -120,7 +119,6 @@ // Painters new /obj/item/paint_sprayer(src) - new /obj/item/pipe_painter(src) // Electrical Supplies /obj/structure/closet/secure_closet/engineering_electrical diff --git a/code/game/objects/structures/crates_lockers/closets/secure/operations.dm b/code/game/objects/structures/crates_lockers/closets/secure/operations.dm index eb2a4dd1edc..5b4a2b7274e 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/operations.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/operations.dm @@ -53,6 +53,7 @@ new /obj/item/storage/belt/utility(src) new /obj/item/flashlight/marshallingwand(src) new /obj/item/flashlight/marshallingwand(src) + new /obj/item/paint_sprayer(src) // Machinist /obj/structure/closet/secure_closet/machinist diff --git a/code/modules/atmospherics/atmospherics.dm b/code/modules/atmospherics/atmospherics.dm index a03ee65aec7..ba316f2a229 100644 --- a/code/modules/atmospherics/atmospherics.dm +++ b/code/modules/atmospherics/atmospherics.dm @@ -56,7 +56,7 @@ Pipelines + Other Objects -> Pipe network atmos_init() /obj/machinery/atmospherics/attackby(obj/item/attacking_item, mob/user) - if(istype(attacking_item, /obj/item/pipe_painter)) + if(istype(attacking_item, /obj/item/paint_sprayer)) return FALSE ..() diff --git a/code/modules/atmospherics/pipes.dm b/code/modules/atmospherics/pipes.dm index cb13eb4e4db..574b4938f1e 100644 --- a/code/modules/atmospherics/pipes.dm +++ b/code/modules/atmospherics/pipes.dm @@ -95,7 +95,7 @@ if (istype(src, /obj/machinery/atmospherics/pipe/tank)) return ..() - if(istype(attacking_item,/obj/item/pipe_painter)) + if(istype(attacking_item,/obj/item/paint_sprayer)) return FALSE if(istype(attacking_item, /obj/item/analyzer) && Adjacent(user)) @@ -1303,7 +1303,7 @@ return null /obj/machinery/atmospherics/pipe/tank/attackby(obj/item/attacking_item, mob/user) - if(istype(attacking_item, /obj/item/pipe_painter)) + if(istype(attacking_item, /obj/item/paint_sprayer)) return FALSE if(istype(attacking_item, /obj/item/analyzer) && in_range(user, src)) diff --git a/code/modules/cargo/items/atmos.dm b/code/modules/cargo/items/atmos.dm index 4598d62480c..0e26be3bc2f 100644 --- a/code/modules/cargo/items/atmos.dm +++ b/code/modules/cargo/items/atmos.dm @@ -208,14 +208,14 @@ groupable = FALSE spawn_amount = 1 -/singleton/cargo_item/pipepainter +/singleton/cargo_item/paint_sprayer category = "atmos" - name = "pipe painter" + name = "paint sprayer" supplier = "hephaestus" description = "Its said that green pipes are safe to travel through." price = 25 items = list( - /obj/item/pipe_painter + /obj/item/paint_sprayer ) access = ACCESS_ENGINE container_type = "crate" diff --git a/code/modules/clothing/suits/hazardvests.dm b/code/modules/clothing/suits/hazardvests.dm index 8e6d31aa9b4..e3bb76fdb62 100644 --- a/code/modules/clothing/suits/hazardvests.dm +++ b/code/modules/clothing/suits/hazardvests.dm @@ -6,7 +6,7 @@ item_state = "hazard" contained_sprite = TRUE blood_overlay_type = "armor" - allowed = list (/obj/item/analyzer, /obj/item/flashlight, /obj/item/multitool, /obj/item/pipe_painter, /obj/item/radio, /obj/item/t_scanner, \ + allowed = list (/obj/item/analyzer, /obj/item/flashlight, /obj/item/multitool, /obj/item/paint_sprayer, /obj/item/radio, /obj/item/t_scanner, \ /obj/item/crowbar, /obj/item/screwdriver, /obj/item/weldingtool, /obj/item/wirecutters, /obj/item/wrench, /obj/item/tank/emergency_oxygen, \ /obj/item/clothing/mask/gas, /obj/item/taperoll/engineering, /obj/item/storage/bag/inflatable) body_parts_covered = UPPER_TORSO diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm index 74fb65fca4e..7f3b4da951d 100644 --- a/code/modules/mob/living/silicon/robot/robot_modules.dm +++ b/code/modules/mob/living/silicon/robot/robot_modules.dm @@ -372,7 +372,6 @@ GLOBAL_LIST_INIT(robot_modules, list( modules += new /obj/item/screwdriver/robotic(src) modules += new /obj/item/wrench/robotic(src) modules += new /obj/item/weldingtool/experimental(src) - modules += new /obj/item/pipe_painter(src) modules += new /obj/item/gripper/no_use/loader(src) modules += new /obj/item/gripper(src) modules += new /obj/item/t_scanner(src) // to check underfloor wiring @@ -443,7 +442,6 @@ GLOBAL_LIST_INIT(robot_modules, list( modules += new /obj/item/gripper(src) modules += new /obj/item/gripper/no_use/loader(src) modules += new /obj/item/lightreplacer(src) - modules += new /obj/item/pipe_painter(src) modules += new /obj/item/paint_sprayer(src) modules += new /obj/item/taperoll/engineering(src) // To enable 'borgs to telegraph danger visually. modules += new /obj/item/inflatable_dispenser(src) // To enable 'borgs to protect Crew from danger in direct hazards. @@ -984,7 +982,6 @@ GLOBAL_LIST_INIT(robot_modules, list( modules += new /obj/item/lightreplacer(src) modules += new /obj/item/soap/drone(src) modules += new /obj/item/extinguisher(src) - modules += new /obj/item/pipe_painter(src) modules += new /obj/item/paint_sprayer(src) modules += new /obj/item/t_scanner(src) modules += new /obj/item/gripper/multi_purpose(src) diff --git a/html/changelogs/Bat-PaintGun.yml b/html/changelogs/Bat-PaintGun.yml new file mode 100644 index 00000000000..882b49b07ea --- /dev/null +++ b/html/changelogs/Bat-PaintGun.yml @@ -0,0 +1,64 @@ +################################ +# Example Changelog File +# +# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb. +# +# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.) +# When it is, any changes listed below will disappear. +# +# Valid Prefixes: +# bugfix +# - (fixes bugs) +# wip +# - (work in progress) +# qol +# - (quality of life) +# soundadd +# - (adds a sound) +# sounddel +# - (removes a sound) +# rscadd +# - (adds a feature) +# rscdel +# - (removes a feature) +# imageadd +# - (adds an image or sprite) +# imagedel +# - (removes an image or sprite) +# spellcheck +# - (fixes spelling or grammar) +# experiment +# - (experimental change) +# balance +# - (balance changes) +# code_imp +# - (misc internal code change) +# refactor +# - (refactors code) +# config +# - (makes a change to the config files) +# admin +# - (makes changes to administrator tools) +# server +# - (miscellaneous changes to server) +################################# + +# Your name. +author: Batrachophrenoboocosmomachia + +# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again. +delete-after: True + +# Any changes you've made. See valid prefix list above. +# INDENT WITH TWO SPACES. NOT TABS. SPACES. +# SCREW THIS UP AND IT WON'T WORK. +# Also, this gets changed to [] after reading. Just remove the brackets when you add new shit. +# Please surround your changes in double quotes ("). It works without them, but if you use certain characters it screws up compiling. The quotes will not show up in the changelog. +changes: + - rscadd: "Paint sprayers can now be used on unpainted crates and lockers to give them a custom appearance." + - rscadd: "Adds paint sprayers to Hangar Tech lockers." + - qol: "Moves pipe painter functionality to paint sprayers; pipe painters now just flavor objects on some offsites." + - qol: "Adds paint sprayers to allowed items list for utility toolbelts." + - imageadd: "Codersprites pipe painter with recolorable paint storage component indicating current color (used by paint sprayer)." + - imagedel: "Removes old paint sprayer sprite." + - bugfix: "Removes old runtime caused by targeting turfs w/ paint sprayers that don't have flooring singletons assigned." diff --git a/icons/obj/item/paint_sprayer.dmi b/icons/obj/item/paint_sprayer.dmi index 324d59e01b51fb9a0ca7bf570a69409dcb6f20b9..eb34246db2201644c9c54a4dd16a30f76e0cdc63 100644 GIT binary patch delta 685 zcmV;e0#f~_2c!m&B!5>>OjJd{z`!0J9xW{`0K)tLKTu3eOp!VOH6H*yJw5+w02UJu zEhZjJKr?GvM*si-3JMAt85uY@I6XvJD=RBSOkq=7c4lmVnw+-K(&;HMMF1Z?06~Ai zz`(nf{mB3T00DGTPE!Ct=GbNc004!0R9JLGWpiV4X>fFDZ;_^Af2y9M41@*~Vl?F7 z)S#^3>gNLXGytirOxY`KHsAmN0qRLaK~!jg?V5{ngCGz^1(hIe#XR~*^8f!?z@VUl zE^V>X?wL%+8QI;N&6<%LivmHA-v}}6S(+C5wMXr;DyzEQr336h>bm9zeN<-_z?uW$ z7ITzc03kvMN;#)=e}}JtHANwwo?nD1-O@Jm5bFB9fL0yI{2dq?P$&UX%I+w0mUjgx z1t-~^kC*V`lYX0=XV8Moi*V}e0+-jf_n3hBd2szn%v`|7iU9vSbYR#trk_C}#sZ)Y zkP`NzVLm(IVkJ0IjAiu(Wyz0apRxe|`P!gYZzmLoH|(kots@ zTXzEqQ0rBcr@)oaK&DzZpu3;%kQk=ccU}wBg*ixQVD-&B>kdHB>vfzvJ6eK)0k3L5 z%~#@BPf|7nK@bE%5Cr)%#BPdV_sjm`tvB1#eS0_~OhGK~G$ypyhk5|+`u=!b!F=ED zK2jm|t?Asp# zfF_KS2j(9v?c1#f0Ab9N;2$jQ_ftFo8E5Sad{Xb7OL8aFL*8e^^g$W^oBnaZv_B zr3qe@IXG1+E4cc(fV~L-An`{3Z^lFI0007HNklW)_enGMGx9b{>2GI9?-TH^av8IClcsw3@QCC2J8bEx?5HwGW6_WS0Lr6lyW*I$E@es zEr$^EdgLF+g@%DK{q-hD)=#|& z%JzUTO6BW!e}7YNqS$P16Go|pw19=+eCZ}g-8}zMHUZ^vjYgx%o}d#FZi~fS*}V!HHfUX#xBkjtNe5f9^;NV3h?Coao$<7QiYC+CPX1 zK!gV&=-|j26m+uB$hW-&l8ah-v-(63NG@vSpR3PCqtR$IxOlBt`wfno_22zbkvD%- zK10he=BVhZVB?F5`K!L|2ASqz+2ng_a1O#|I0s=f90Ryhf67SM*00001bW%=J06^y0W&i*HetJ|`bVOxyV{&P5bZKvH z004NLQ&wh@cAT_=qF*C0uwMdDJGbOXA7$|JW#hF%=n41b=V^thqlz~uhLWKGpoa&Vo zT>V_Yt_J`}hdQ|fG(}_p00G5GL_t(&f$f>yl7k=&g#neKyDM$2-S>af1+2iXoM7{y9aDNJS?_5=Dk~3IH z4Qg?~K-6&wGw~X5HRwHHmCze}eJ;2jHOj!mo29`zjoHbA)|W@!}gQr$%#X11VIo4K@b6@rUKV*z`=1}zny_| zNcwsY?2G`#r+vK_kDL)e9iXpYB0tdsWj>-}K#vpPUuKkIXxK}HAa>pup_Au6K- z_x1CPfC1K7<#wIh;^