diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm
index 987818924f..4c0eeccf1d 100644
--- a/code/_onclick/item_attack.dm
+++ b/code/_onclick/item_attack.dm
@@ -20,7 +20,7 @@
return SendSignal(COMSIG_PARENT_ATTACKBY, W, user, params)
/obj/attackby(obj/item/I, mob/living/user, params)
- return ..() || I.attack_obj(src, user)
+ return ..() || (can_be_hit && I.attack_obj(src, user))
/mob/living/attackby(obj/item/I, mob/living/user, params)
user.changeNext_move(CLICK_CD_MELEE)
diff --git a/code/datums/components/paintable.dm b/code/datums/components/paintable.dm
new file mode 100644
index 0000000000..2ea94334d0
--- /dev/null
+++ b/code/datums/components/paintable.dm
@@ -0,0 +1,29 @@
+/datum/component/spraycan_paintable
+ var/current_paint
+
+/datum/component/spraycan_paintable/Initialize()
+ RegisterSignal(COMSIG_PARENT_ATTACKBY, .proc/Repaint)
+
+/datum/component/spraycan_paintable/Destroy()
+ RemoveCurrentCoat()
+ return ..()
+
+/datum/component/spraycan_paintable/proc/RemoveCurrentCoat()
+ var/atom/A = parent
+ A.remove_atom_colour(FIXED_COLOUR_PRIORITY, current_paint)
+
+/datum/component/spraycan_paintable/proc/Repaint(obj/item/toy/crayon/spraycan/spraycan, mob/living/user)
+ if(!istype(spraycan) || user.a_intent == INTENT_HARM)
+ return FALSE
+ . = TRUE
+ if(spraycan.is_capped)
+ to_chat(user, "Take the cap off first!")
+ return
+ RemoveCurrentCoat()
+ if(spraycan.use_charges(user, 2))
+ var/colour = spraycan.paint_color
+ current_paint = colour
+ var/atom/A = parent
+ A.add_atom_colour(colour, FIXED_COLOUR_PRIORITY)
+ playsound(spraycan, 'sound/effects/spray.ogg', 5, 1, 5)
+ to_chat(user, "You spray [spraycan] on [A], painting it.")
diff --git a/code/game/objects/effects/effects.dm b/code/game/objects/effects/effects.dm
index 4406c32fbd..d5f8e28d2a 100644
--- a/code/game/objects/effects/effects.dm
+++ b/code/game/objects/effects/effects.dm
@@ -4,9 +4,7 @@
/obj/effect
icon = 'icons/effects/effects.dmi'
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF | FREEZE_PROOF
-
-/obj/effect/attackby(obj/item/I, mob/living/user, params)
- return
+ can_be_hit = FALSE
/obj/effect/take_damage(damage_amount, damage_type = BRUTE, damage_flag = 0, sound_effect = 1, attack_dir)
return
@@ -57,4 +55,4 @@
return
/obj/effect/abstract/singularity_act()
- return
\ No newline at end of file
+ return
diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index 072896ac01..362148c801 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -26,6 +26,8 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
max_integrity = 200
+ can_be_hit = FALSE
+
var/hitsound = null
var/usesound = null
var/throwhitsound = null
@@ -322,6 +324,7 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
// Due to storage type consolidation this should get used more now.
// I have cleaned it up a little, but it could probably use more. -Sayu
// The lack of ..() is intentional, do not add one
+// added one, fuck the police
/obj/item/attackby(obj/item/W, mob/user, params)
if(istype(W, /obj/item/storage))
var/obj/item/storage/S = W
@@ -346,9 +349,12 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
qdel(progress)
to_chat(user, "You put everything you could [S.preposition] [S].")
+ return
else if(S.can_be_inserted(src))
S.handle_item_insertion(src)
+ return
+ return ..()
/obj/item/proc/handle_mass_pickup(obj/item/storage/S, list/things, atom/thing_loc, list/rejections, datum/progressbar/progress)
for(var/obj/item/I in things)
diff --git a/code/game/objects/items/crayons.dm b/code/game/objects/items/crayons.dm
index 23905200e9..882335d5e7 100644
--- a/code/game/objects/items/crayons.dm
+++ b/code/game/objects/items/crayons.dm
@@ -107,20 +107,19 @@
var/amount = weight * units_per_weight
reagents.add_reagent(reagent, amount)
-/obj/item/toy/crayon/proc/use_charges(amount)
+/obj/item/toy/crayon/proc/use_charges(mob/user, amount = 1, requires_full = TRUE)
// Returns number of charges actually used
- switch(paint_mode)
- if(PAINT_LARGE_HORIZONTAL)
- amount *= 3
-
if(charges == -1)
. = amount
refill()
else
- . = min(charges_left, amount)
- charges_left -= .
+ if(check_empty(user, amount, requires_full))
+ return 0
+ else
+ . = min(charges_left, amount)
+ charges_left -= .
-/obj/item/toy/crayon/proc/check_empty(mob/user)
+/obj/item/toy/crayon/proc/check_empty(mob/user, amount = 1, requires_full = TRUE)
// When eating a crayon, check_empty() can be called twice producing
// two messages unless we check for being deleted first
if(QDELETED(src))
@@ -131,10 +130,13 @@
if(charges == -1)
. = FALSE
else if(!charges_left)
- to_chat(user, "There is no more of \the [src.name] left!")
+ to_chat(user, "There is no more of [src] left!")
if(self_contained)
qdel(src)
. = TRUE
+ else if(charges_left < amount && requires_full)
+ to_chat(user, "There is not enough of [src] left!")
+ . = TRUE
/obj/item/toy/crayon/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.hands_state)
// tgui is a plague upon this codebase
@@ -298,7 +300,7 @@
var/takes_time = !instant
var/wait_time = 50
- if(PAINT_LARGE_HORIZONTAL)
+ if(paint_mode == PAINT_LARGE_HORIZONTAL)
wait_time *= 3
if(takes_time)
@@ -343,7 +345,7 @@
var/cost = 1
if(paint_mode == PAINT_LARGE_HORIZONTAL)
cost = 5
- . = use_charges(cost)
+ . = use_charges(user, cost)
var/fraction = min(1, . / reagents.maximum_volume)
if(affected_turfs.len)
fraction /= affected_turfs.len
@@ -355,7 +357,7 @@
/obj/item/toy/crayon/attack(mob/M, mob/user)
if(edible && (M == user))
to_chat(user, "You take a bite of the [src.name]. Delicious!")
- var/eaten = use_charges(5)
+ var/eaten = use_charges(user, 5, FALSE)
if(check_empty(user)) //Prevents divsion by zero
return
var/fraction = min(eaten / reagents.total_volume, 1)
@@ -527,7 +529,7 @@
H.lip_style = "spray_face"
H.lip_color = paint_color
H.update_body()
- var/used = use_charges(10)
+ var/used = use_charges(user, 10, FALSE)
var/fraction = min(1, used / reagents.maximum_volume)
reagents.reaction(user, VAPOR, fraction * volume_multiplier)
reagents.trans_to(user, used, volume_multiplier)
@@ -583,7 +585,7 @@
H.update_body()
// Caution, spray cans contain inflammable substances
- . = use_charges(10)
+ . = use_charges(user, 10, FALSE)
var/fraction = min(1, . / reagents.maximum_volume)
reagents.reaction(C, VAPOR, fraction * volume_multiplier)
@@ -596,7 +598,7 @@
target.set_opacity(255)
else
target.set_opacity(initial(target.opacity))
- . = use_charges(2)
+ . = use_charges(user, 2)
var/fraction = min(1, . / reagents.maximum_volume)
reagents.reaction(target, TOUCH, fraction * volume_multiplier)
reagents.trans_to(target, ., volume_multiplier)
diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm
index f2537945db..fb5a4344f0 100644
--- a/code/game/objects/objs.dm
+++ b/code/game/objects/objs.dm
@@ -13,6 +13,7 @@
var/integrity_failure = 0 //0 if we have no special broken behavior
var/resistance_flags = 0 // INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ON_FIRE | UNACIDABLE | ACID_PROOF
+ var/can_be_hit = TRUE //can this be bludgeoned by items?
var/acid_level = 0 //how much acid is on that obj
diff --git a/code/modules/clothing/head/helmet.dm b/code/modules/clothing/head/helmet.dm
index d89671d06d..da4fe1cf5c 100644
--- a/code/modules/clothing/head/helmet.dm
+++ b/code/modules/clothing/head/helmet.dm
@@ -17,13 +17,25 @@
dog_fashion = /datum/dog_fashion/head/helmet
-
-/obj/item/clothing/head/helmet/Initialize()
- . = ..()
-
/obj/item/clothing/head/helmet/sec
can_flashlight = 1
+/obj/item/clothing/head/helmet/sec/attackby(obj/item/I, mob/user, params)
+ if(issignaler(I))
+ var/obj/item/device/assembly/signaler/S = I
+ if(F) //Has a flashlight. Player must remove it, else it will be lost forever.
+ to_chat(user, "The mounted flashlight is in the way, remove it first!")
+ return
+
+ if(S.secured)
+ qdel(S)
+ var/obj/item/secbot_assembly/A = new /obj/item/secbot_assembly
+ user.put_in_hands(A)
+ to_chat(user, "You add the signaler to the helmet.")
+ qdel(src)
+ return
+ return ..()
+
/obj/item/clothing/head/helmet/alt
name = "bulletproof helmet"
desc = "A bulletproof combat helmet that excels in protecting the wearer against traditional projectile weaponry and explosives to a minor extent."
@@ -281,7 +293,7 @@
qdel(THL)
return
- ..()
+ return ..()
/obj/item/clothing/head/helmet/proc/toggle_helmlight()
set name = "Toggle Helmetlight"
diff --git a/code/modules/mining/equipment/explorer_gear.dm b/code/modules/mining/equipment/explorer_gear.dm
index 1b21b88447..f2cdefa9a4 100644
--- a/code/modules/mining/equipment/explorer_gear.dm
+++ b/code/modules/mining/equipment/explorer_gear.dm
@@ -46,3 +46,64 @@
/obj/item/clothing/mask/gas/explorer/folded/New()
..()
adjustmask()
+
+/obj/item/clothing/suit/space/hostile_environment
+ name = "H.E.C.K. suit"
+ desc = "Hostile Environiment Cross-Kinetic Suit: A suit designed to withstand the wide variety of hazards from Lavaland. It wasn't enough for its last owner."
+ icon_state = "hostile_env"
+ item_state = "hostile_env"
+ flags_1 = THICKMATERIAL_1 //not spaceproof
+ max_heat_protection_temperature = FIRE_IMMUNITY_SUIT_MAX_TEMP_PROTECT
+ resistance_flags = FIRE_PROOF | LAVA_PROOF
+ slowdown = 0
+ armor = list("melee" = 70, "bullet" = 40, "laser" = 10, "energy" = 10, "bomb" = 50, "bio" = 100, "rad" = 100, "fire" = 100, "acid" = 100)
+ allowed = list(/obj/item/device/flashlight, /obj/item/tank/internals, /obj/item/resonator, /obj/item/device/mining_scanner, /obj/item/device/t_scanner/adv_mining_scanner, /obj/item/gun/energy/kinetic_accelerator, /obj/item/pickaxe)
+
+/obj/item/clothing/suit/space/hostile_environment/Initialize()
+ . = ..()
+ AddComponent(/datum/component/spraycan_paintable)
+ START_PROCESSING(SSobj, src)
+
+/obj/item/clothing/suit/space/hostile_environment/Destroy()
+ STOP_PROCESSING(SSobj, src)
+ return ..()
+
+/obj/item/clothing/suit/space/hostile_environment/process()
+ var/mob/living/carbon/C = loc
+ if(istype(C) && prob(2)) //cursed by bubblegum
+ if(prob(15))
+ new /datum/hallucination/oh_yeah(C)
+ to_chat(C, "[pick("I AM IMMORTAL.","I SHALL TAKE BACK WHAT'S MINE.","I SEE YOU.","YOU CANNOT ESCAPE ME FOREVER.","DEATH CANNOT HOLD ME.")]")
+ else
+ to_chat(C, "[pick("You hear faint whispers.","You smell ash.","You feel hot.","You hear a roar in the distance.")]")
+
+/obj/item/clothing/head/helmet/space/hostile_environment
+ name = "H.E.C.K. helmet"
+ desc = "Hostile Environiment Cross-Kinetic Helmet: A helmet designed to withstand the wide variety of hazards from Lavaland. It wasn't enough for its last owner."
+ icon_state = "hostile_env"
+ item_state = "hostile_env"
+ w_class = WEIGHT_CLASS_NORMAL
+ max_heat_protection_temperature = FIRE_IMMUNITY_HELM_MAX_TEMP_PROTECT
+ flags_1 = THICKMATERIAL_1 // no space protection
+ armor = list("melee" = 70, "bullet" = 40, "laser" = 10, "energy" = 10, "bomb" = 50, "bio" = 100, "rad" = 100, "fire" = 100, "acid" = 100)
+ resistance_flags = FIRE_PROOF | LAVA_PROOF
+
+/obj/item/clothing/head/helmet/space/hostile_environment/Initialize()
+ . = ..()
+ AddComponent(/datum/component/spraycan_paintable)
+ update_icon()
+
+/obj/item/clothing/head/helmet/space/hostile_environment/update_icon()
+ ..()
+ cut_overlays()
+ var/mutable_appearance/glass_overlay = mutable_appearance(icon, "hostile_env_glass")
+ glass_overlay.appearance_flags = RESET_COLOR
+ add_overlay(glass_overlay)
+
+/obj/item/clothing/head/helmet/space/hostile_environment/worn_overlays(isinhands)
+ . = ..()
+ if(!isinhands)
+ var/mutable_appearance/M = mutable_appearance('icons/mob/head.dmi', "hostile_env_glass")
+ M.appearance_flags = RESET_COLOR
+ . += M
+
diff --git a/code/modules/mining/lavaland/necropolis_chests.dm b/code/modules/mining/lavaland/necropolis_chests.dm
index e16077fec1..95c4898605 100644
--- a/code/modules/mining/lavaland/necropolis_chests.dm
+++ b/code/modules/mining/lavaland/necropolis_chests.dm
@@ -932,6 +932,8 @@
name = "bubblegum chest"
/obj/structure/closet/crate/necropolis/bubblegum/PopulateContents()
+ new /obj/item/clothing/suit/space/hostile_environment(src)
+ new /obj/item/clothing/head/helmet/space/hostile_environment(src)
var/loot = rand(1,3)
switch(loot)
if(1)
diff --git a/code/modules/mob/living/simple_animal/bot/construction.dm b/code/modules/mob/living/simple_animal/bot/construction.dm
index 0d1f346dcf..c53925e076 100644
--- a/code/modules/mob/living/simple_animal/bot/construction.dm
+++ b/code/modules/mob/living/simple_animal/bot/construction.dm
@@ -357,28 +357,6 @@
var/build_step = 0
var/created_name = "Securitron" //To preserve the name if it's a unique securitron I guess
-/obj/item/clothing/head/helmet/attackby(obj/item/device/assembly/signaler/S, mob/user, params)
- ..()
- if(!issignaler(S))
- ..()
- return
-
- if(type != /obj/item/clothing/head/helmet/sec) //Eh, but we don't want people making secbots out of space helmets.
- return
-
- if(F) //Has a flashlight. Player must remove it, else it will be lost forever.
- to_chat(user, "The mounted flashlight is in the way, remove it first!")
- return
-
- if(S.secured)
- qdel(S)
- var/obj/item/secbot_assembly/A = new /obj/item/secbot_assembly
- user.put_in_hands(A)
- to_chat(user, "You add the signaler to the helmet.")
- qdel(src)
- else
- return
-
/obj/item/secbot_assembly/attackby(obj/item/I, mob/user, params)
..()
if(istype(I, /obj/item/weldingtool))
diff --git a/tgstation.dme b/tgstation.dme
index 8b927cf2bb..b996531842 100755
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -294,6 +294,7 @@
#include "code\datums\components\_component.dm"
#include "code\datums\components\archaeology.dm"
#include "code\datums\components\material_container.dm"
+#include "code\datums\components\paintable.dm"
#include "code\datums\components\slippery.dm"
#include "code\datums\components\squeek.dm"
#include "code\datums\diseases\_disease.dm"