diff --git a/code/game/atom_health.dm b/code/game/atom_health.dm index 59c757e846f..82bef4e0751 100644 --- a/code/game/atom_health.dm +++ b/code/game/atom_health.dm @@ -70,16 +70,18 @@ return TRUE /** - * Use this proc to update an atom's maxhealth. Set update_current_health to TRUE if you want to change the current health proportionally to the new maxhealth, or FALSE if you want to keep the current health the same. + * Use this proc to update an atom's maxhealth. + * Set update_current_health to TRUE if you want to change the current health proportionally to the new maxhealth, or FALSE if you want to keep the current health the same. */ /atom/proc/set_maxhealth(new_maxhealth, update_current_health = FALSE) - if(!maxhealth || !should_use_health) + if(!should_use_health) return FALSE var/old_maxhealth = maxhealth maxhealth = new_maxhealth if(update_current_health || health > maxhealth) - health *= maxhealth / old_maxhealth + // Incase this proc is used to determine initial maxhealth value, we make sure to assign the health value instead of multiplying the null by the value. + health = health ? health * (maxhealth / old_maxhealth) : maxhealth return TRUE /** diff --git a/code/game/machinery/atmoalter/canister.dm b/code/game/machinery/atmoalter/canister.dm index a3942568c79..1a704f7c3bb 100644 --- a/code/game/machinery/atmoalter/canister.dm +++ b/code/game/machinery/atmoalter/canister.dm @@ -5,7 +5,7 @@ icon_state = "yellow" density = TRUE light_system = MOVABLE_LIGHT - maxhealth = OBJECT_HEALTH_VERY_LOW + maxhealth = OBJECT_HEALTH_LOW obj_flags = OBJ_FLAG_SIGNALER | OBJ_FLAG_CONDUCTABLE w_class = WEIGHT_CLASS_HUGE diff --git a/code/game/objects/effects/spiders.dm b/code/game/objects/effects/spiders.dm index e02e26cc56c..69791296697 100644 --- a/code/game/objects/effects/spiders.dm +++ b/code/game/objects/effects/spiders.dm @@ -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() . = ..() diff --git a/code/game/objects/structures/displaycase.dm b/code/game/objects/structures/displaycase.dm index 4196991a951..99d0e7e286a 100644 --- a/code/game/objects/structures/displaycase.dm +++ b/code/game/objects/structures/displaycase.dm @@ -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("[user] 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("[user] 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 diff --git a/code/game/objects/structures/girders.dm b/code/game/objects/structures/girders.dm index 68b9e1f3ef0..0962e89ba82 100644 --- a/code/game/objects/structures/girders.dm +++ b/code/game/objects/structures/girders.dm @@ -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 diff --git a/code/game/objects/structures/inflatable.dm b/code/game/objects/structures/inflatable.dm index d71f4c60601..d3d2477ca84 100644 --- a/code/game/objects/structures/inflatable.dm +++ b/code/game/objects/structures/inflatable.dm @@ -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 diff --git a/code/game/objects/structures/railing.dm b/code/game/objects/structures/railing.dm index cd2c12dd1c7..5350db06dcd 100644 --- a/code/game/objects/structures/railing.dm +++ b/code/game/objects/structures/railing.dm @@ -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) diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm index 0a29e00440c..026b09f98fc 100644 --- a/code/game/objects/structures/window.dm +++ b/code/game/objects/structures/window.dm @@ -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 diff --git a/code/game/turfs/simulated.dm b/code/game/turfs/simulated.dm index 1eecde825f3..d5323e35c7c 100644 --- a/code/game/turfs/simulated.dm +++ b/code/game/turfs/simulated.dm @@ -3,6 +3,8 @@ var/wet_type = 0 var/wet_amount = 0 var/image/wet_overlay = null + /// The armor of this object, turned into an armor component. + var/list/armor var/thermite = 0 initial_gas = list("oxygen" = MOLES_O2STANDARD, "nitrogen" = MOLES_N2STANDARD) @@ -24,6 +26,23 @@ if (!mapload) updateVisibility(src) + if(maxhealth) + if(!health) + // Allows you to set dynamic health states on initialize. + health = maxhealth + if(islist(armor)) + for(var/type in armor) + if(armor[type]) + AddComponent(/datum/component/armor, armor) + break + else if(should_use_health) + AddComponent(/datum/component/armor, GLOB.default_object_armor, TRUE) + +/turf/simulated/condition_hints(mob/user, distance, is_adjacent) + . += ..() + if(health < maxhealth) + . += get_damage_condition_hints(user, distance, is_adjacent) + /turf/simulated/proc/update_dirt() dirt = min(dirt+1, 101) var/obj/effect/decal/cleanable/dirt/dirtoverlay = locate(/obj/effect/decal/cleanable/dirt, src) diff --git a/code/game/turfs/simulated/walls.dm b/code/game/turfs/simulated/walls.dm index 7b9702bb2a8..a9f3c3847b4 100644 --- a/code/game/turfs/simulated/walls.dm +++ b/code/game/turfs/simulated/walls.dm @@ -48,29 +48,19 @@ pathing_pass_method = TURF_PATHING_PASS_NO //Literally a wall, until we implement bots that can wallwarp, we might aswell save the processing - -/turf/simulated/wall/condition_hints(mob/user, distance, is_adjacent) - . += ..() - if(health >= maxhealth) - . += SPAN_NOTICE("It looks fully intact.") - else - // Total damage is based of base material integrity and optionally, if reinforced, reinforcement material integrity on top - var/integrity = material.integrity - if(reinf_material) - integrity += reinf_material.integrity - - var/relative_damage = health / maxhealth - - if(relative_damage <= 0.25) - . += SPAN_NOTICE("It looks slightly damaged.") - else if(relative_damage <= 0.5) - . += SPAN_WARNING("It looks damaged.") - else if(relative_damage <= 0.75) - . += SPAN_WARNING("It looks moderately damaged.") - else if(relative_damage <= 0.9) - . += SPAN_DANGER("It looks heavily damaged.") - else - . += SPAN_DANGER("It looks critically damaged and on the verge of structural collapse.") +/turf/simulated/wall/get_damage_condition_hints(mob/user, distance, is_adjacent) + var/state + var/current_damage = health / maxhealth + switch(current_damage) + if(0 to 0.2) + state = SPAN_DANGER("\The [src] is about to collapse into shattered debris!") + if(0.2 to 0.4) + state = SPAN_WARNING("\The [src] shows massive cracks across its surface and is in dire need of repairs!") + if(0.4 to 0.8) + state = SPAN_NOTICE("\The [src] is dented, but still sturdy.") + if(0.8 to 1) + state = SPAN_NOTICE("\The [src] seems completely intact.") + . = state /turf/simulated/wall/mechanics_hints(mob/user, distance, is_adjacent) . += ..() @@ -113,7 +103,7 @@ reinf_material = SSmaterials.get_material_by_name(rmaterialtype) update_material() hitsound = material.hitsound - set_maxhealth(material.integrity + (reinf_material ? reinf_material.integrity : 0)) + set_maxhealth(material.integrity + (reinf_material ? reinf_material.integrity : 0), TRUE) if (material.radioactivity || (reinf_material && reinf_material.radioactivity)) START_PROCESSING(SSprocessing, src) diff --git a/html/changelogs/kano-dot-healthy-atoms.yml b/html/changelogs/kano-dot-healthy-atoms.yml new file mode 100644 index 00000000000..9747681b5c5 --- /dev/null +++ b/html/changelogs/kano-dot-healthy-atoms.yml @@ -0,0 +1,6 @@ +author: Kano + +delete-after: True + +changes: + - bugfix: "Fixed some atom health bugs and slightly refactored the code."