Fixes some atom health bugs (#22312)

## About PR
- Fixes #22260
- Fixes #22304
- Fixes #22234

Additionally changes some health values for:

- Canisters, `50` -> `100`. Takes 5 crowbar hits to break instead of 3,
these shouldn't break so easily
- Railings, `30` -> `75`. 3 crowbars instead of 1
- Reinforced girders, `600` -> `300`. Still takes a lot of crowbars
before breaking, barebone girders shouldn't compete reinforced walls
This commit is contained in:
Kano
2026-04-23 00:34:59 +00:00
committed by GitHub
parent 44bb1d5c82
commit 3d5f69f548
11 changed files with 120 additions and 169 deletions
+8 -18
View File
@@ -6,7 +6,12 @@
anchored = TRUE
density = FALSE
mouse_opacity = MOUSE_OPACITY_ICON
maxhealth = OBJECT_HEALTH_FRAGILE
should_use_health = TRUE
maxhealth = OBJECT_HEALTH_VERY_LOW
armor = list(
MELEE = ARMOR_MELEE_MINOR,
BULLET = ARMOR_BALLISTIC_MINOR
)
//similar to weeds, but only barfed out by nurses manually
/obj/effect/spider/ex_act(severity)
@@ -21,21 +26,6 @@
qdel(src)
return
/obj/effect/spider/attackby(obj/item/attacking_item, mob/user)
visible_message(SPAN_WARNING("\The [src] has been [LAZYPICK(attacking_item.attack_verb, "attacked")] with [attacking_item][(user ? " by [user]." : ".")]"))
var/damage = attacking_item.force / 4.0
if(attacking_item.tool_behaviour == TOOL_WELDER)
var/obj/item/weldingtool/WT = attacking_item
if(WT.use(0, user))
damage = 15
playsound(loc, 'sound/items/Welder.ogg', 100, 1)
return TRUE
else
user.do_attack_animation(src)
playsound(loc, attacking_item.hitsound, 50, 1, -1)
add_damage(damage)
/obj/effect/spider/bullet_act(obj/projectile/hitting_projectile, def_zone, piercing_hit)
. = ..()
if(. != BULLET_ACT_HIT)
@@ -258,13 +248,14 @@
die()
/obj/effect/spider/spiderling/attackby(obj/item/attacking_item, mob/user)
. = ..()
if(istype(attacking_item, /obj/item/newspaper))
var/obj/item/newspaper/N = attacking_item
if(N.rolled)
die()
return TRUE
. = ..()
/obj/effect/decal/cleanable/spiderling_remains
name = "greimorian larva remains"
desc = "Green squishy mess."
@@ -275,7 +266,6 @@
name = "cocoon"
desc = "Something wrapped in silky greimorian web"
icon_state = "cocoon1"
maxhealth = OBJECT_HEALTH_VERY_LOW
/obj/effect/spider/cocoon/Initialize()
. = ..()
+25 -26
View File
@@ -11,6 +11,8 @@
var/obj/held_obj
var/open = FALSE
var/destroyed = FALSE
hitsound = 'sound/effects/glass_hit.ogg'
destroy_sound = SFX_BREAK_GLASS
var/spawn_contained_type
/obj/structure/displaycase/Initialize(mapload)
@@ -23,15 +25,14 @@
/obj/structure/displaycase/ex_act(severity)
switch(severity)
if (1)
do_destroy()
on_death()
if (2)
if(prob(50))
health -= 15
health_check()
on_death()
else
add_damage(rand(20, 50))
if (3)
if(prob(50))
health -= 5
health_check()
add_damage(rand(10, 40))
/obj/structure/displaycase/bullet_act(obj/projectile/hitting_projectile, def_zone, piercing_hit)
@@ -39,21 +40,15 @@
if(. != BULLET_ACT_HIT)
return .
health -= hitting_projectile.get_structure_damage()
health_check()
var/damage = hitting_projectile.damage
if(damage)
add_damage(damage)
/obj/structure/displaycase/proc/health_check()
if(health <= 0)
do_destroy()
else
playsound(loc, 'sound/effects/glass_hit.ogg', 75, 1)
/obj/structure/displaycase/proc/do_destroy()
/obj/structure/displaycase/on_death()
if(!destroyed)
density = FALSE
destroyed = TRUE
new /obj/item/material/shard(loc)
playsound(src, SFX_BREAK_GLASS, 70, 1)
update_icon()
/obj/structure/displaycase/update_icon()
@@ -69,30 +64,33 @@
underlays += I
/obj/structure/displaycase/attackby(obj/item/attacking_item, mob/user)
user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
if(istype(attacking_item, /obj/item/card/id))
if(destroyed)
to_chat(user, SPAN_WARNING("\The [src] has been destroyed and cannot be unlocked."))
return
var/obj/item/card/id/ID = attacking_item
if(check_access(ID))
user.visible_message("<b>[user]</b> presses their ID against \the [src], [open ? "closing" : "opening"] it.", SPAN_NOTICE("You press your ID against \the [src], [open ? "closing" : "opening"] it."))
open = !open
update_icon()
else
to_chat(user, SPAN_WARNING("Access denied."))
return
else if(!held_obj && (destroyed || open))
to_chat(user, SPAN_NOTICE("You set \the [attacking_item] down on \the [src]."))
user.drop_from_inventory(attacking_item, src)
held_obj = attacking_item
update_icon()
else
if(destroyed)
to_chat(user, SPAN_WARNING("\The [src] has already been destroyed."))
return
health -= attacking_item.force
health_check()
return ..()
if(destroyed)
to_chat(user, SPAN_WARNING("\The [src] has already been destroyed."))
return
. = ..()
/obj/structure/displaycase/attack_hand(mob/user)
user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
@@ -112,8 +110,9 @@
to_chat(user, SPAN_NOTICE("You peer inside \the [src], noticing it has nothing inside."))
else
user.visible_message("<b>[user]</b> kicks \the [src].", SPAN_WARNING("You kick \the [src]."))
health -= 2
health_check()
user.do_attack_animation(src)
playsound(src, 'sound/effects/glass_hit.ogg', 50, 1)
add_damage(3)
/obj/structure/displaycase/captain_laser
spawn_contained_type = /obj/item/gun/energy/captain
+1 -1
View File
@@ -298,7 +298,7 @@
/obj/structure/girder/proc/reinforce_girder()
cover = reinf_material.hardness
set_maxhealth(OBJECT_HEALTH_EXTREMELY_HIGH, TRUE)
set_maxhealth(OBJECT_HEALTH_VERY_HIGH, TRUE)
state = 2
icon_state = "reinforced"
reinforcing = 0
@@ -59,6 +59,9 @@
. += "To deflate it safely, use the 'deflate' verb or ctrl-click on it."
. += "Hitting these with any objects will probably puncture and break it forever."
/obj/structure/inflatable/on_death()
deflate(TRUE)
/obj/structure/inflatable/wall
name = "inflatable wall"
undeploy_path = /obj/item/inflatable/wall
+2 -8
View File
@@ -8,14 +8,13 @@
layer = OBJ_LAYER
anchored = FALSE
pass_flags_self = LETPASSTHROW|PASSSTRUCTURE|PASSRAILING
hitsound = 'sound/effects/metalhit.ogg'
atom_flags = ATOM_FLAG_CHECKS_BORDER
obj_flags = OBJ_FLAG_ROTATABLE|OBJ_FLAG_MOVES_UNSUPPORTED
build_amt = 2
maxhealth = OBJECT_HEALTH_EXTREMELY_LOW
var/broken = FALSE
var/neighbor_status = 0
@@ -88,7 +87,7 @@
name = "[material.display_name] [initial(name)]"
desc = "A simple [material.display_name] railing designed to protect against careless trespass."
set_maxhealth(round(material.integrity / 5))
set_maxhealth(round(material.integrity / 2), TRUE)
set_health(maxhealth)
color = material.icon_colour
@@ -315,11 +314,6 @@
update_icon()
return
if(attacking_item.force && (attacking_item.damtype == DAMAGE_BURN || attacking_item.damtype == DAMAGE_BRUTE))
user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
visible_message(SPAN_WARNING("\The [src] has been [LAZYLEN(attacking_item.attack_verb) ? pick(attacking_item.attack_verb) : "attacked"] with \the [attacking_item] by \the [user]!"))
add_damage(attacking_item.force, attacking_item.damage_flags(), attacking_item.damtype, attacking_item.armor_penetration, attacking_item)
return
. = ..()
/obj/structure/railing/ex_act(severity)
+36 -88
View File
@@ -1,9 +1,3 @@
//
// Glass
//
#define FULL_REINFORCED_WINDOW_DAMAGE_FORCE 8
#define REINFORCED_WINDOW_DAMAGE_FORCE 8
/obj/structure/window
name = "glass pane"
desc = "A glass pane."
@@ -177,10 +171,6 @@
tforce = I.throwforce
if(reinf)
tforce *= 0.25
if(health - tforce <= 7 && !reinf)
anchored = 0
update_nearby_icons()
step(src, get_dir(hitting_atom, src))
add_damage(tforce)
/obj/structure/window/attack_hand(var/mob/living/user)
@@ -229,66 +219,66 @@
/obj/structure/window/attackby(obj/item/attacking_item, mob/user)
if(!istype(attacking_item) || istype(attacking_item, /obj/item/flag))
return
// Slamming someone against the window interaction
if(istype(attacking_item, /obj/item/grab) && get_dist(src,user)<2)
var/obj/item/grab/G = attacking_item
if(istype(G.affecting,/mob/living))
if(istype(G.affecting, /mob/living))
grab_smash_attack(G, DAMAGE_BRUTE)
return
if(attacking_item.item_flags & ITEM_FLAG_NO_BLUDGEON)
return
if(handle_construction(attacking_item, user))
return
. = ..()
/obj/structure/window/proc/handle_construction(obj/item/attacking_item, mob/user)
// Screwdriver
if(attacking_item.tool_behaviour == TOOL_SCREWDRIVER && user.a_intent != I_HURT)
if(reinf && state >= 1)
state = 3 - state
update_nearby_icons()
attacking_item.play_tool_sound(get_turf(src), 75)
to_chat(user, (state == 1 ? SPAN_NOTICE("You have unfastened the window from the frame.") : SPAN_NOTICE("You have fastened the window to the frame.")))
else if(reinf && state == 0)
anchored = !anchored
update_icon()
update_nearby_icons()
attacking_item.play_tool_sound(get_turf(src), 75)
to_chat(user, (anchored ? SPAN_NOTICE("You have fastened the frame to the floor.") : SPAN_NOTICE("You have unfastened the frame from the floor.")))
else if(!reinf)
else
anchored = !anchored
update_nearby_icons()
attacking_item.play_tool_sound(get_turf(src), 75)
to_chat(user, (anchored ? SPAN_NOTICE("You have fastened the window to the floor.") : SPAN_NOTICE("You have unfastened the window.")))
update_icon()
update_nearby_icons()
return TRUE
// Crowbar
else if(attacking_item.tool_behaviour == TOOL_CROWBAR && reinf && state <= 1 && user.a_intent != I_HURT)
state = 1 - state
attacking_item.play_tool_sound(get_turf(src), 75)
to_chat(user, (state ? SPAN_NOTICE("You have pried the window into the frame.") : SPAN_NOTICE("You have pried the window out of the frame.")))
return TRUE
// Wrench
else if(attacking_item.tool_behaviour == TOOL_WRENCH && !anchored && (!state || !reinf) && user.a_intent != I_HURT)
if(!glasstype)
to_chat(user, SPAN_NOTICE("You're not sure how to dismantle \the [src] properly."))
else
visible_message(SPAN_NOTICE("[user] dismantles \the [src]."))
dismantle_window()
else
user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
if(attacking_item.damtype == DAMAGE_BRUTE || attacking_item.damtype == DAMAGE_BURN)
if(reinf)
user.do_attack_animation(src)
if(attacking_item.force >= REINFORCED_WINDOW_DAMAGE_FORCE)
user.visible_message(SPAN_DANGER("\The [user] forcefully strikes \the [src] with \the [attacking_item]!"))
playsound(src, hitsound, attacking_item.get_clamped_volume(), 1)
hit(attacking_item.force)
else
user.visible_message(SPAN_WARNING("[user] hits \the [src] with \the [attacking_item], but it glances off, doing no damage."))
playsound(src, hitsound, attacking_item.get_clamped_volume(), 1)
else
user.do_attack_animation(src)
hit(attacking_item.force)
if(health <= 7)
anchored = 0
update_nearby_icons()
step(src, get_dir(user, src))
else
playsound(src, hitsound, 10, 1)
return
return TRUE
return FALSE
/obj/structure/window/proc/grab_smash_attack(obj/item/grab/G, var/damtype = DAMAGE_BRUTE)
var/mob/living/M = G.affecting
@@ -645,64 +635,46 @@
WF.has_glass_installed = FALSE
return ..()
/obj/structure/window/full/attackby(obj/item/attacking_item, mob/user)
if(!istype(attacking_item) || istype(attacking_item, /obj/item/flag))
return
if(istype(attacking_item, /obj/item/grab) && get_dist(src,user)<2)
var/obj/item/grab/G = attacking_item
if(istype(G.affecting,/mob/living))
grab_smash_attack(G, DAMAGE_BRUTE)
return
if(attacking_item.item_flags & ITEM_FLAG_NO_BLUDGEON)
return
/obj/structure/window/full/handle_construction(obj/item/attacking_item, mob/user)
if(attacking_item.tool_behaviour == TOOL_SCREWDRIVER && user.a_intent != I_HURT)
if(state == 2)
if(attacking_item.use_tool(src, user, 2 SECONDS, volume = 50))
to_chat(user, SPAN_NOTICE("You have unfastened the glass from the window frame."))
state--
update_nearby_icons()
return TRUE
else if(state == 1)
if(attacking_item.use_tool(src, user, 2 SECONDS, volume = 50))
to_chat(user, SPAN_NOTICE("You have fastened the glass to the window frame."))
state++
update_nearby_icons()
return TRUE
else if(attacking_item.tool_behaviour == TOOL_CROWBAR && user.a_intent != I_HURT)
if(state == 1)
if(attacking_item.use_tool(src, user, 2 SECONDS, volume = 50))
to_chat(user, SPAN_NOTICE("You pry the glass out of the window frame."))
state--
update_nearby_icons()
return TRUE
else if(state == 0)
if(attacking_item.use_tool(src, user, 2 SECONDS, volume = 50))
to_chat(user, SPAN_NOTICE("You pry the glass into the window frame."))
state++
update_nearby_icons()
return TRUE
else if(attacking_item.tool_behaviour == TOOL_WRENCH && user.a_intent != I_HURT)
if(state == 0)
user.visible_message(SPAN_DANGER("\The [user] is dismantling \the [src]!"))
if(attacking_item.use_tool(src, user, 2 SECONDS, volume = 50))
to_chat(user, SPAN_NOTICE("You undo the safety bolts and remove the glass from \the [src]."))
dismantle_window()
else
user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
if(attacking_item.damtype == DAMAGE_BRUTE || attacking_item.damtype == DAMAGE_BURN)
if(reinf)
user.do_attack_animation(src)
if(attacking_item.force >= FULL_REINFORCED_WINDOW_DAMAGE_FORCE)
user.visible_message(SPAN_DANGER("\The [user] forcefully strikes \the [src] with \the [attacking_item]!"))
playsound(src, hitsound, attacking_item.get_clamped_volume(), 1)
hit(attacking_item.force)
else
user.visible_message(SPAN_WARNING("[user] hits \the [src] with \the [attacking_item], but it glances off, doing no damage."))
playsound(src, hitsound, attacking_item.get_clamped_volume(), 1)
else
user.do_attack_animation(src)
hit(attacking_item.force)
else
playsound(src, hitsound, 10, 1)
return
return TRUE
return FALSE
/obj/structure/window/full/shatter(var/display_message = 1)
playsound(src, SFX_BREAK_GLASS, 70, 1)
@@ -716,27 +688,6 @@
qdel(src)
return
/obj/structure/window/full/add_damage(damage, damage_flags, damage_type, armor_penetration, obj/weapon, sound_effect = TRUE)
var/initialhealth = health
if(silicate)
damage = damage * (1 - silicate / 200)
if(health <= 0)
shatter()
else
if(sound_effect)
playsound(loc, 'sound/effects/glass_hit.ogg', 100, 1)
if(health < maxhealth / 4 && initialhealth >= maxhealth / 4)
visible_message(SPAN_DANGER("[src] looks like it's about to shatter!"))
playsound(loc, SFX_GLASS_CRACK, 100, 1)
else if(health < maxhealth / 2 && initialhealth >= maxhealth / 2)
visible_message(SPAN_WARNING("[src] looks seriously damaged!"))
playsound(loc, SFX_GLASS_CRACK, 100, 1)
else if(health < maxhealth * 3/4 && initialhealth >= maxhealth * 3/4)
visible_message(SPAN_WARNING("Cracks begin to appear in [src]!"))
playsound(loc, SFX_GLASS_CRACK, 100, 1)
/obj/structure/window/full/dismantle_window()
var/obj/item/stack/material/mats = new glasstype(loc)
mats.amount = 4
@@ -861,6 +812,3 @@
reinf = TRUE
maximal_heat = T0C + 4000
rad_resistance_modifier = 4
#undef FULL_REINFORCED_WINDOW_DAMAGE_FORCE
#undef REINFORCED_WINDOW_DAMAGE_FORCE