Adds an universal object health system. (#21266)

https://www.youtube.com/watch?v=ZpUYjpKg9KY

As per title. The goal is to add health to most objects in the game and
thus allow them to be dynamically destructible, while also avoiding
shitcode like each structure having its own snowflake health update
proc.

---------

Signed-off-by: Matt Atlas <mattiathebest2000@hotmail.it>
Co-authored-by: Matt Atlas <liermattia@gmail.com>
Co-authored-by: SleepyGemmy <99297919+SleepyGemmy@users.noreply.github.com>
This commit is contained in:
Matt Atlas
2026-04-16 23:22:08 +00:00
committed by GitHub
co-authored by Matt Atlas SleepyGemmy
parent 1d2871729f
commit d5931c5ffe
213 changed files with 1448 additions and 1424 deletions
+7 -24
View File
@@ -6,7 +6,7 @@
anchored = TRUE
density = FALSE
mouse_opacity = MOUSE_OPACITY_ICON
var/health = 15
maxhealth = OBJECT_HEALTH_FRAGILE
//similar to weeds, but only barfed out by nurses manually
/obj/effect/spider/ex_act(severity)
@@ -34,27 +34,20 @@
user.do_attack_animation(src)
playsound(loc, attacking_item.hitsound, 50, 1, -1)
health -= damage
healthcheck()
add_damage(damage)
/obj/effect/spider/bullet_act(obj/projectile/hitting_projectile, def_zone, piercing_hit)
. = ..()
if(. != BULLET_ACT_HIT)
return .
health -= hitting_projectile.get_structure_damage()
healthcheck()
/obj/effect/spider/proc/healthcheck()
if(health <= 0)
qdel(src)
add_damage(hitting_projectile.get_structure_damage())
/obj/effect/spider/fire_act(exposed_temperature, exposed_volume)
. = ..()
if(exposed_temperature > 300 + T0C)
health -= 5
healthcheck()
add_damage(5)
/obj/effect/spider/stickyweb
icon_state = "stickyweb1"
@@ -89,7 +82,7 @@
name = "egg cluster"
desc = "They seem to pulse slightly with an inner life."
icon_state = "eggs"
health = 10
maxhealth = OBJECT_HEALTH_FRAGILE
var/amount_grown = 0
/obj/effect/spider/eggcluster/Initialize(var/mapload, var/atom/parent)
@@ -119,11 +112,6 @@
new /obj/effect/spider/spiderling(src.loc, src, 0.75)
qdel(src)
/obj/effect/spider/eggcluster/proc/take_damage(var/damage)
health -= damage
if(health <= 0)
qdel(src)
/obj/effect/spider/spiderling
name = "greimorian larva"
desc = "A small, agile alien creature. It oozes some disgusting slime."
@@ -133,7 +121,7 @@
icon_state = "spiderling"
anchored = FALSE
layer = OPEN_DOOR_LAYER // 2.7
health = 3
maxhealth = 3
var/last_itch = 0
/// % chance that the spiderling will eventually turn into a fully-grown greimorian.
var/can_mature_chance = 50
@@ -185,10 +173,6 @@
new /obj/effect/decal/cleanable/spiderling_remains(loc)
qdel(src)
/obj/effect/spider/spiderling/healthcheck()
if(health <= 0)
die()
/obj/effect/spider/spiderling/process()
if(travelling_in_vent)
if(istype(src.loc, /turf))
@@ -291,11 +275,10 @@
name = "cocoon"
desc = "Something wrapped in silky greimorian web"
icon_state = "cocoon1"
health = 60
maxhealth = OBJECT_HEALTH_VERY_LOW
/obj/effect/spider/cocoon/Initialize()
. = ..()
icon_state = pick("cocoon1","cocoon2","cocoon3")
/obj/effect/spider/cocoon/Destroy()
+3 -14
View File
@@ -4,6 +4,8 @@
w_class = WEIGHT_CLASS_NORMAL
light_system = MOVABLE_LIGHT
blocks_emissive = EMISSIVE_BLOCK_GENERIC
/// Generic hit sound
hitsound = SFX_SWING_HIT
/// This saves our blood splatter overlay, which will be processed not to go over the edges of the sprite
var/image/blood_overlay
@@ -11,13 +13,9 @@
var/randpixel = 6
var/abstract = 0
var/r_speed = 1.0
var/health
var/burn_point
var/burning
/// Generic hit sound
var/hitsound = SFX_SWING_HIT
var/storage_cost
var/storage_slot_sort_by_name = FALSE
@@ -151,10 +149,6 @@
/// Sound uses when dropping the item, or when its thrown.
var/drop_sound = SFX_DROP
var/list/armor
/// How fast armor will degrade, multiplier to blocked damage to get armor damage value.
var/armor_degradation_speed
//Item_state definition moved to /obj
//var/item_state = null // Used to specify the item state for the on-mob overlays.
@@ -245,11 +239,6 @@
/obj/item/Initialize(mapload, ...)
. = ..()
if(islist(armor))
for(var/type in armor)
if(armor[type])
AddComponent(/datum/component/armor, armor)
break
if(item_flags & ITEM_FLAG_HELD_MAP_TEXT)
set_initial_maptext()
check_maptext()
@@ -345,7 +334,7 @@
. = ..(user, distance, is_adjacent, "It is a [size] item.", get_extended = get_extended)
var/datum/component/armor/armor_component = GetComponent(/datum/component/armor)
if(armor_component)
if(armor_component && !armor_component.hidden)
. += FONT_SMALL(SPAN_NOTICE("\[?\] This item has armor values. <a href='byond://?src=[REF(src)];examine_armor=1'>\[Show Armor Values\]</a>"))
/obj/item/Topic(href, href_list)
@@ -29,6 +29,7 @@
icon_state = "box"
item_state = "box"
contained_sprite = TRUE
maxhealth = OBJECT_HEALTH_EXTREMELY_LOW
color = COLOR_CARDBOARD
var/label = "label"
var/illustration = "writing"
@@ -39,19 +40,17 @@
///Boolean, if set, can be crushed into a trash item when empty
var/trash = null
var/maxHealth = 20 //health is already defined
use_sound = 'sound/items/storage/box.ogg'
drop_sound = 'sound/items/drop/cardboardbox.ogg'
pickup_sound = 'sound/items/pickup/cardboardbox.ogg'
var/chewable = TRUE
/obj/item/storage/box/condition_hints(mob/user, distance, is_adjacent)
. += ..()
if (health < maxHealth)
if (health >= (maxHealth * 0.5))
. += SPAN_WARNING("It is slightly torn.")
/obj/item/storage/box/get_damage_condition_hints(mob/user, distance, is_adjacent)
if (health < maxhealth)
if (health >= (maxhealth * 0.5))
. = SPAN_WARNING("It is slightly torn.")
else
. += SPAN_DANGER("It is full of tears and holes.")
. = SPAN_DANGER("It is full of tears and holes.")
/obj/item/storage/box/mechanics_hints(mob/user, distance, is_adjacent)
. += ..()
@@ -74,7 +73,8 @@
/obj/item/storage/box/Initialize()
. = ..()
health = maxHealth
if(illustration)
AddOverlays(illustration)
update_icon()
/obj/item/storage/box/proc/damage(var/severity)
@@ -556,7 +556,6 @@
/obj/item/reagent_containers/food/snacks/truffle/random
)
starts_with = list(/obj/item/reagent_containers/food/snacks/truffle/random = 8)
maxHealth = 40
/obj/item/storage/box/fancy/chocolate_box/fill()
for(var/i=1; i <= storage_slots; i++)
+2 -1
View File
@@ -44,7 +44,8 @@
anchored = TRUE
mouse_opacity = MOUSE_OPACITY_ICON
var/health = 50
maxhealth = OBJECT_HEALTH_VERY_LOW
var/mob/living/affecting = null //Who it is currently affecting, if anyone.
/obj/effect/energy_net/Initialize()
+58 -22
View File
@@ -4,64 +4,76 @@
/// Used to store information about the contents of the object.
var/list/matter
/// Whether the object can be recycled (eaten) by something like the Autolathe
/// Whether the object can be recycled (eaten) by something like the Autolathe.
var/recyclable = FALSE
/// Size of the object.
var/w_class
/// Used by R&D to determine what research bonuses it grants.
var/list/origin_tech = null
/// Universal "unacidabliness" var, here so you can use it in any obj.
var/unacidable = FALSE
/// Universal "unacidabliness" var, here so you can use it in any obj. As xeno acid is gone, this is now only used for chemistry acid.
var/unacidable = 0
/// Special flags such as whether or not this object can be rotated.
var/obj_flags
/// Integer. Used for varied damage and item volume calculations.
var/throwforce = 1
/// Used in attackby() to say how something was attacked "[x] has been [z.attack_verb] by [y] with [z]"
/// Used in attackby() to say how something was attacked "[x] has been [z.attack_verb] by [y] with [z]".
var/list/attack_verb
/// Whether this object cuts.
var/sharp = FALSE
/// Whether this object is more likely to dismember its poor foes.
/// Whether this object creates CUT wounds.
var/sharp = 0
/// Whether this object is more likely to dismember.
var/edge = FALSE
/// If we have a user using us, this will be set on. We will check if the user has stopped using us, and thus stop updating and LAGGING EVERYTHING!
var/in_use = FALSE
/// Type of damage this object deals.
var/in_use = 0
/// The type of damage this object deals.
var/damtype = DAMAGE_BRUTE
/// The damage this object deals.
var/force = 0
/// The armour penetration this object has.
var/armor_penetration = 0
/// Makes an object not able to slice things.
/// To make it not able to slice things. Used for curtains, flaps, pumpkins... why aren't you just using edge?
var/noslice = FALSE
/// The armor of this object, turned into an armor component.
var/list/armor
/// Set to TRUE when shocked by the tesla ball, to not repeatedly shock the object.
var/being_shocked = FALSE
var/being_shocked = 0
/// If set, this holds the 3-letter shortname of a species, used for species-specific worn icons.
/// The slot the object will equip to.
var/equip_slot = 0
/// If set, this holds the 3-letter shortname of a species, used for species-specific worn icons
var/icon_species_tag = ""
/// If TRUE, this item will automatically change its species tag to match the wearer's species, given the wearer's species is listed in icon_supported_species_tags.
var/icon_auto_adapt = FALSE
/// If 1, this item will automatically change its species tag to match the wearer's species. Requires that the wearer's species is listed in icon_supported_species_tags.
var/icon_auto_adapt = 0
/**
* A list of strings used with icon_auto_adapt, a list of species which have differing appearances for this item,
* based on the specie short name
* based on the species short name
*/
var/list/icon_supported_species_tags
/// If `TRUE`, will use the `icon_species_tag` var for rendering this item in the left/right hand.
var/icon_species_in_hand = FALSE
var/equip_slot = 0
/// Played when the item is used, for example tools.
///Played when the item is used, for example tools
var/usesound
/// The speed of the tool. This is generally a divisor.
var/toolspeed = 1
/// The sound this tool makes in surgery.
var/surgerysound
/* START BUCKLING VARS */
/// A list of things that can buckle to this atom.
var/list/can_buckle
/// If the buckled atom can move, and thus face directions.
var/buckle_movable = 0
/// The direction forced on a buckled atom.
var/buckle_dir = 0
var/buckle_lying = -1 //bed-like behavior, forces mob.lying = buckle_lying if != -1
var/buckle_require_restraints = 0 //require people to be handcuffed before being able to buckle. eg: pipes
/// Causes bed-like behavior, forces mob.lying = buckle_lying if != -1.
var/buckle_lying = -1
/// Require people to be handcuffed before being able to buckle. eg: pipes.
var/buckle_require_restraints = 0
/// The atom buckled to us.
var/atom/movable/buckled = null
/**
* Stores the original layer of a buckled atom.
@@ -71,11 +83,14 @@
* Used in `/unbuckle()` to restore the original layer.
*/
var/buckled_original_layer = null
var/buckle_delay = 0 //How much extra time to buckle someone to this object.
/// How much extra time to buckle someone to this object.
var/buckle_delay = 0
/* END BUCKLING VARS */
/* START ACCESS VARS */
/// Required access.
var/list/req_access
/// Only require one of these accesses.
var/list/req_one_access
/* END ACCESS VARS */
@@ -93,6 +108,20 @@
var/persistant_objects_expiration_time_days = PERSISTENT_DEFAULT_EXPIRATION_DAYS
/* END PERSISTENCE VARS */
/obj/Initialize(mapload, ...)
. = ..()
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)
/obj/Destroy()
if(persistent_objects_track_active) // Prevent hard deletion of references in the persistence register by removing it preemptively
SSpersistence.objectsDeregisterTrack(src)
@@ -127,6 +156,8 @@
/mob/proc/CanUseObjTopic()
return 1
/obj/proc/CouldUseTopic(var/mob/user)
user.AddTopicPrint(src)
@@ -169,6 +200,11 @@
if(loc)
return loc.return_air()
/obj/condition_hints(mob/user, distance, is_adjacent)
. += ..()
if(health < maxhealth)
. += get_damage_condition_hints(user, distance, is_adjacent)
/obj/proc/updateUsrDialog()
if(in_use)
var/is_in_use = 0
+21 -16
View File
@@ -4,10 +4,10 @@
layer = STRUCTURE_LAYER
blocks_emissive = EMISSIVE_BLOCK_GENERIC
pass_flags_self = PASSSTRUCTURE
should_use_health = TRUE
var/material_alteration = MATERIAL_ALTERATION_ALL // Overrides for material shit. Set them manually if you don't want colors etc. See wood chairs/office chairs.
var/climbable
var/breakable
var/parts
var/list/climbers
var/list/footstep_sound //footstep sounds when stepped on
@@ -40,15 +40,23 @@
material = null
return ..()
/obj/structure/attackby(obj/item/attacking_item, mob/user, params)
. = ..()
if(user?.a_intent == I_HURT && maxhealth)
user.do_attack_animation(src)
user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
add_damage(attacking_item.force, attacking_item.damage_flags(), attacking_item.damtype, attacking_item.armor_penetration, attacking_item)
if(hitsound)
playsound(user, hitsound, attacking_item.get_clamped_volume())
/obj/structure/attack_hand(mob/living/user)
if(breakable)
if((user.mutations & HULK) && !(user.isSynthetic()) && !(isvaurca(user)))
user.say(pick(";RAAAAAAAARGH!", ";HNNNNNNNNNGGGGGGH!", ";GWAAAAAAAARRRHHH!", "NNNNNNNNGGGGGGGGHH!", ";AAAAAAARRRGH!" ))
attack_generic(user,1,"smashes")
else if(istype(user,/mob/living/carbon/human))
var/mob/living/carbon/human/H = user
if(H.species.can_shred(user))
attack_generic(user,1,"slices")
if((user.mutations & HULK) && !(user.isSynthetic()) && !(isvaurca(user)))
user.say(pick("RAAAAAAAARGH!!!", "HNNNNNNNNNGGGGGGH!!!", "GWAAAAAAAARRRHHH!!!", "NNNNNNNNGGGGGGGGHH!!!", "AAAAAAARRRGH!!!" ))
attack_generic(user, 25, "smashes")
else if(istype(user,/mob/living/carbon/human))
var/mob/living/carbon/human/H = user
if(H.species.can_shred(user))
attack_generic(user, 25, "slices")
if(LAZYLEN(climbers) && !(user in climbers))
user.visible_message(SPAN_WARNING("[user] shakes \the [src]."), \
@@ -75,6 +83,8 @@
dismantle_material = SSmaterials.get_material_by_name(DEFAULT_WALL_MATERIAL) //if there is no defined material, it will use steel
else
dismantle_material = get_material()
if(should_use_health && health <= 0)
build_amt /= rand(2, 4) //if the structure is destroyed by damage, it will yield less materials
for(var/i = 1 to build_amt)
dismantle_material.place_sheet(loc)
qdel(src)
@@ -227,13 +237,8 @@
return 0
return 1
/obj/structure/attack_generic(mob/user, damage, attack_message, environment_smash, armor_penetration, attack_flags, damage_type)
if(!breakable || !damage || !environment_smash)
return 0
visible_message(SPAN_DANGER("[user] [attack_verb] the [src] apart!"))
user.do_attack_animation(src)
qdel(src)
return 1
/obj/structure/on_death(damage, damage_flags, damage_type, armor_penetration, obj/weapon)
dismantle()
/obj/structure/get_material()
return material
@@ -4,20 +4,13 @@
anchored = TRUE
density = TRUE
atom_flags = ATOM_FLAG_CHECKS_BORDER
maxhealth = OBJECT_HEALTH_LOW
/// The type of stack the barricade dropped when disassembled if any.
var/stack_type
/// The amount of stack dropped when disassembled at full health
var/stack_amount = 5
/// to specify a non-zero amount of stack to drop when destroyed
var/destroyed_stack_amount
/// Pretty tough. Changes sprites at 300 and 150
var/health = 100
/// Basic code functions
var/maxhealth = 100
/// Used for calculating some stuff related to maxhealth as it constantly changes due to e.g. barbed wire. set to 100 to avoid possible divisions by zero
var/starting_maxhealth = 100
/// How much force an item needs to even damage it at all.
var/force_level_absorption = 5
var/barricade_hitsound
@@ -33,19 +26,17 @@
/obj/structure/barricade/Initialize(mapload, mob/user)
. = ..()
update_icon()
starting_maxhealth = maxhealth
/obj/structure/barricade/condition_hints(mob/user, distance, is_adjacent)
. += ..()
/obj/structure/barricade/get_damage_condition_hints(mob/user, distance, is_adjacent)
switch(damage_state)
if(BARRICADE_DMG_NONE)
. += SPAN_INFO("It appears to be in good shape.")
. = SPAN_INFO("It appears to be in good shape.")
if(BARRICADE_DMG_SLIGHT)
. += SPAN_WARNING("It's slightly damaged, but still very functional.")
. = SPAN_WARNING("It's slightly damaged, but still very functional.")
if(BARRICADE_DMG_MODERATE)
. += SPAN_WARNING("It's quite beat up, but it's holding together.")
. = SPAN_WARNING("It's quite beat up, but it's holding together.")
if(BARRICADE_DMG_HEAVY)
. += SPAN_WARNING("It's crumbling apart, just a few more blows will tear it apart!")
. = SPAN_WARNING("It's crumbling apart, just a few more blows will tear it apart!")
/obj/structure/barricade/mechanics_hints(mob/user, distance, is_adjacent)
. += ..()
@@ -164,7 +155,7 @@
visible_message(SPAN_DANGER("\The [src]'s barbed wire slices into [L]!"))
L.apply_damage((5), DAMAGE_BRUTE, pick(BP_R_HAND, BP_L_HAND), "barbed wire", DAMAGE_FLAG_SHARP|DAMAGE_FLAG_EDGE, 25)
L.do_attack_animation(src)
take_damage(damage)
add_damage(damage)
/obj/structure/barricade/attackby(obj/item/attacking_item, mob/user)
if(istype(attacking_item, /obj/item/stack/barbed_wire))
@@ -181,8 +172,8 @@
user.visible_message(SPAN_NOTICE("[user] sets up [attacking_item.name] on [src]."),
SPAN_NOTICE("You set up [attacking_item.name] on [src]."))
maxhealth += 50
update_health(-50)
set_maxhealth(maxhealth + 50)
add_health(50)
can_wire = FALSE
is_wired = TRUE
climbable = FALSE
@@ -196,12 +187,11 @@
if(do_after(user, 20, src, DO_REPAIR_CONSTRUCT))
if(!is_wired)
return
playsound(src.loc, 'sound/items/Wirecutter.ogg', 25, 1)
user.visible_message(SPAN_NOTICE("[user] removes the barbed wire on [src]."),
SPAN_NOTICE("You remove the barbed wire on [src]."))
maxhealth -= 50
update_health(50)
set_maxhealth(maxhealth - 50)
add_damage(50)
can_wire = TRUE
is_wired = FALSE
climbable = TRUE
@@ -222,7 +212,7 @@
bullet_ping(hitting_projectile)
var/damage_to_take = hitting_projectile.damage * hitting_projectile.anti_materiel_potential
take_damage(damage_to_take)
add_damage(damage_to_take, hitting_projectile.damage_flags(), hitting_projectile.damtype, hitting_projectile.armor_penetration, hitting_projectile)
/obj/structure/barricade/proc/barricade_deconstruct(deconstruct)
if(deconstruct && is_wired)
@@ -232,7 +222,7 @@
if(!deconstruct && destroyed_stack_amount)
stack_amt = destroyed_stack_amount
else
stack_amt = round(stack_amount * (health/starting_maxhealth)) //Get an amount of sheets back equivalent to remaining health. Obviously, fully destroyed means 0
stack_amt = round(stack_amount * (health/initial(maxhealth))) //Get an amount of sheets back equivalent to remaining health. Obviously, fully destroyed means 0
if(stack_amt)
new stack_type (loc, stack_amt)
@@ -242,7 +232,7 @@
for(var/obj/structure/barricade/B in get_step(src,dir)) //discourage double-stacking barricades by removing health from opposing barricade
if(B.dir == REVERSE_DIR(dir))
INVOKE_ASYNC(B, TYPE_PROC_REF(/atom, ex_act), severity, direction)
update_health(round(severity))
add_damage(round(severity))
// This proc is called whenever the cade is moved, so I thought it was appropriate,
// especially since the barricade's direction needs to be handled when moving
@@ -267,26 +257,20 @@
var/message = pick(I.attack_verb)
visible_message(SPAN_DANGER("[L] has [message] the [src]!"))
L.do_attack_animation(src)
take_damage(I.force)
add_damage(I.force, I.damage_flags(), I.damtype, I.armor_penetration, I)
/obj/structure/barricade/proc/take_damage(var/damage)
/obj/structure/barricade/add_damage(damage, damage_flags, damage_type, armor_penetration, obj/weapon)
for(var/obj/structure/barricade/B in get_step(src,dir)) //discourage double-stacking barricades by removing health from opposing barricade
if(B.dir == REVERSE_DIR(dir))
B.update_health(damage)
update_health(damage)
/obj/structure/barricade/proc/update_health(damage, nomessage)
health -= damage
health = clamp(health, 0, maxhealth)
B.add_damage(damage, damage_flags, damage_type, armor_penetration, weapon)
if(..())
update_damage_state()
update_icon()
/obj/structure/barricade/on_death(damage, damage_flags, damage_type, armor_penetration, obj/weapon)
if(!health)
if(!nomessage)
visible_message(SPAN_DANGER("[src] falls apart!"))
visible_message(SPAN_DANGER("[src] falls apart!"))
barricade_deconstruct()
return
update_damage_state()
update_icon()
/obj/structure/barricade/proc/update_damage_state()
var/health_percent = round(health/maxhealth * 100)
@@ -309,7 +293,7 @@
if(WT.use_tool(src, user, 7 SECONDS, volume = 40))
user.visible_message(SPAN_NOTICE("[user] repairs some damage on [src]."),
SPAN_NOTICE("You repair \the [src]."))
update_health(-200)
add_health(200)
return TRUE
@@ -120,7 +120,7 @@
health = BARRICADE_LIQUIDBAG_TRESHOLD_5
maxhealth = BARRICADE_LIQUIDBAG_TRESHOLD_5
maxhealth += 50
update_health(-50)
add_health(50)
stack_amount = 5
can_wire = FALSE
is_wired = TRUE
@@ -109,7 +109,7 @@
/obj/structure/barricade/metal/wired/Initialize(mapload, mob/user)
. = ..()
maxhealth += 50
update_health(-50)
add_health(50)
can_wire = FALSE
is_wired = TRUE
climbable = FALSE
@@ -29,7 +29,7 @@
visible_message(SPAN_NOTICE("[user] begins to repair [src]."))
if(do_after(user, 2 SECONDS, src, DO_REPAIR_CONSTRUCT) && (health < maxhealth))
if(D.use(1))
update_health(-0.5*maxhealth)
add_health(maxhealth*0.5)
update_damage_state()
visible_message(SPAN_NOTICE("[user] haphazardly repairs [src]."))
return
+1
View File
@@ -4,6 +4,7 @@
icon = 'icons/obj/coatrack.dmi'
icon_state = "coatrack"
layer = ABOVE_HUMAN_LAYER
maxhealth = OBJECT_HEALTH_VERY_LOW
var/obj/item/clothing/coat
var/obj/item/clothing/head/hat
/// Custom manual sprite override.
@@ -3,10 +3,13 @@
desc = "It's a basic storage unit."
icon = 'icons/obj/containers/closet.dmi'
icon_state = "generic"
hitsound = 'sound/effects/metalhit.ogg'
density = TRUE
build_amt = 2
slowdown = 2.5
pass_flags_self = PASSSTRUCTURE | LETPASSCLICKS | PASSTRACE
maxhealth = OBJECT_HEALTH_MEDIUM
armor = list(MELEE = ARMOR_MELEE_RESISTANT, BULLET = ARMOR_BALLISTIC_PISTOL, LASER = ARMOR_LASER_KEVLAR)
var/icon_door = null
/// Override to have open overlay use icon different to its base's
@@ -34,7 +37,6 @@
/// Never solid (You can always pass over it)
var/wall_mounted = FALSE
var/health = 100
/// If someone is currently breaking out. mutex
var/breakout = 0
@@ -157,6 +159,10 @@
. = ..()
/obj/structure/closet/on_death(damage, damage_flags, damage_type, armor_penetration, obj/weapon)
dump_contents()
. = ..()
/// Fill lockers with this.
/obj/structure/closet/proc/fill()
return
@@ -318,11 +324,11 @@
/obj/structure/closet/ex_act(severity)
switch(severity)
if(1)
health -= rand(120, 240)
add_damage(rand(120, 240))
if(2)
health -= rand(60, 120)
add_damage(rand(60, 120))
if(3)
health -= rand(30, 60)
add_damage(rand(30, 60))
if(health <= 0)
for (var/atom/movable/A as mob|obj in src)
@@ -525,9 +531,13 @@
playsound(loc, 'sound/weapons/blade.ogg', 50, 1)
else
attack_hand(user)
else
return ..()
else
attack_hand(user)
return
if(attacking_item.force < 10 && user.a_intent != I_HURT)
attack_hand(user)
else
return ..()
// helper procs for callbacks
/obj/structure/closet/proc/is_closed()
@@ -7,7 +7,13 @@
secure = TRUE
opened = FALSE
locked = TRUE
health = 200
health = OBJECT_HEALTH_VERY_HIGH
armor = list(
MELEE = ARMOR_MELEE_RESISTANT,
BULLET = ARMOR_BALLISTIC_MEDIUM,
LASER = ARMOR_LASER_MEDIUM,
ENERGY = ARMOR_ENERGY_RESISTANT,
)
/obj/structure/closet/emp_act(severity)
. = ..()
@@ -243,7 +243,13 @@
locked = TRUE
secure = TRUE
secure_lights = TRUE
health = 200
maxhealth = OBJECT_HEALTH_VERY_HIGH
armor = list(
MELEE = ARMOR_MELEE_RESISTANT,
BULLET = ARMOR_BALLISTIC_MEDIUM,
LASER = ARMOR_LASER_MEDIUM,
ENERGY = ARMOR_ENERGY_RESISTANT,
)
/obj/structure/closet/crate/plastic
name = "plastic crate"
+23 -35
View File
@@ -5,25 +5,25 @@
icon_state = "scattered"
anchored = TRUE
density = FALSE
maxhealth = OBJECT_HEALTH_HIGH
var/singleton/reagent/reagent_id
var/state = 0
var/health = 100
var/mine_rate = 1 // how fast you can mine it
var/obj/machinery/power/crystal_agitator/creator // used to re-add dense turfs to agitation list when destroyed
/obj/structure/reagent_crystal/condition_hints(mob/user, distance, is_adjacent)
. += ..()
var/current_damage = health / initial(health)
/obj/structure/reagent_crystal/get_damage_condition_hints(mob/user, distance, is_adjacent)
var/current_damage = health / maxhealth
switch(current_damage)
if(0 to 0.2)
. += SPAN_DANGER("The crystal is barely holding together!")
. = SPAN_DANGER("The crystal is barely holding together!")
if(0.2 to 0.4)
. += SPAN_WARNING("The crystal has various cracks visible!")
. = SPAN_WARNING("The crystal has various cracks visible!")
if(0.4 to 0.8)
. += SPAN_WARNING("The crystal has scratches and deeper grooves on its surface.")
. = SPAN_WARNING("The crystal has scratches and deeper grooves on its surface.")
if(0.8 to 1)
. += SPAN_NOTICE("The crystal looks structurally sound.")
. = SPAN_NOTICE("The crystal looks structurally sound.")
/obj/structure/reagent_crystal/Initialize(mapload, var/reagent_i = null, var/our_creator = null)
. = ..()
@@ -39,16 +39,15 @@
if(our_creator)
creator = our_creator
/obj/structure/reagent_crystal/proc/take_damage(var/damage)
health -= damage
if(health <= 0)
visible_message(SPAN_WARNING("\The [src] collapses into smaller crystals!"))
harvest()
/obj/structure/reagent_crystal/on_death(damage, damage_flags, damage_type, armor_penetration, obj/weapon)
visible_message(SPAN_WARNING("\The [src] collapses into smaller crystals!"))
new /obj/item/reagent_crystal(get_turf(src), reagent_id, 5)
qdel(src)
/obj/structure/reagent_crystal/attack_hand(mob/user)
if((user.mutations & HULK))
user.visible_message(SPAN_WARNING("\The [user] smashes \the [src] apart!"), SPAN_WARNING("You smash \the [src] apart!"))
harvest()
add_damage(health)
return
return ..()
@@ -75,7 +74,7 @@
user.do_attack_animation(src)
playsound(get_turf(src), 'sound/weapons/smash.ogg', 50)
visible_message(SPAN_WARNING("\The [user] smashes \the [attacking_item] into \the [src]."))
take_damage(attacking_item.force * 4)
add_damage(attacking_item.force * 4)
/obj/structure/reagent_crystal/proc/mine_crystal(var/mob/user, var/time_to_dig, var/use_sound)
if(!user)
@@ -86,46 +85,35 @@
if(do_after(user, time_to_dig * mine_rate, src))
if(!src)
return
harvest()
add_damage(health)
if(use_sound)
playsound(get_turf(src), use_sound, 30, TRUE)
/obj/structure/reagent_crystal/proc/harvest()
new /obj/item/reagent_crystal(get_turf(src), reagent_id, 5)
qdel(src)
/obj/structure/reagent_crystal/ex_act(severity)
switch(severity)
if(1.0)
qdel(src)
return
if(2.0)
if(prob(30))
harvest()
return
add_damage(health)
else
health -= rand(60,180)
add_damage(rand(60,180))
if(3.0)
if(prob(5))
harvest()
return
add_damage(health)
else
health -= rand(40,80)
if(health <= 0)
harvest()
return
add_damage(rand(40,80))
/obj/structure/reagent_crystal/attack_generic(mob/user, damage, attack_message, environment_smash, armor_penetration, attack_flags, damage_type)
if(!damage || !environment_smash)
return FALSE
user.do_attack_animation(src)
visible_message(SPAN_WARNING("\The [user] [attack_message] \the [src]!"))
harvest()
add_damage(health)
return TRUE
/obj/structure/reagent_crystal/proc/become_dense()
var/health_mod = health / initial(health)
var/health_mod = health / maxhealth
var/obj/structure/reagent_crystal/dense/P = new /obj/structure/reagent_crystal/dense(get_turf(src), reagent_id, creator)
P.health *= health_mod
if(creator)
@@ -136,10 +124,10 @@
name = "dense chemical crystal cluster"
desc = "A dense cluster of hardened chemical crystals."
icon_state = "dense"
health = 200
maxhealth = OBJECT_HEALTH_HIGH
mine_rate = 2
/obj/structure/reagent_crystal/dense/harvest()
/obj/structure/reagent_crystal/dense/on_death(damage, damage_flags, damage_type, armor_penetration, obj/weapon)
var/turf/our_turf = get_turf(src)
for(var/i = 0 to 2)
new /obj/item/reagent_crystal(our_turf, reagent_id, 5)
+1 -1
View File
@@ -7,7 +7,7 @@
anchored = TRUE
unacidable = TRUE
req_access = list(ACCESS_CAPTAIN)
var/health = 30
maxhealth = OBJECT_HEALTH_VERY_LOW
var/obj/held_obj
var/open = FALSE
var/destroyed = FALSE
@@ -3,6 +3,7 @@
desc = "A steel window frame."
icon = 'icons/obj/smooth/window/full_window_frame_color.dmi'
icon_state = "window_frame"
maxhealth = OBJECT_HEALTH_MEDIUM
color = COLOR_GRAY20
build_amt = 4
layer = WINDOW_FRAME_LAYER
@@ -10,7 +11,6 @@
density = TRUE
climbable = TRUE
smoothing_flags = SMOOTH_MORE
breakable = TRUE
can_be_unanchored = TRUE
canSmoothWith = list(
/turf/simulated/wall,
@@ -169,6 +169,7 @@
new_grille.shock(user, 70) // You haven't forgotten your precautions, have you?
has_grille_installed = TRUE
return
else return ..()
/obj/structure/window_frame/hitby(atom/movable/hitting_atom, skipcatch, hitpush, blocked, datum/thrownthing/throwingdatum)
. = ..()
@@ -177,6 +178,7 @@
W.hitby(arglist(args))
/obj/structure/window_frame/wood
maxhealth = OBJECT_HEALTH_LOW
color = "#8f5847"
/obj/structure/window_frame/unanchored // Used during in-game construction.
@@ -187,6 +189,7 @@
should_check_mapload = FALSE // No glass.
/obj/structure/window_frame/shuttle
maxhealth = OBJECT_HEALTH_HIGH
icon = 'icons/obj/smooth/window/full_window_frame_color.dmi'
color = null
smoothing_flags = SMOOTH_MORE
+19 -30
View File
@@ -7,8 +7,8 @@
w_class = WEIGHT_CLASS_HUGE
obj_flags = OBJ_FLAG_MOVES_UNSUPPORTED
pass_flags_self = PASSTABLE
maxhealth = OBJECT_HEALTH_HIGH
var/state = 0
var/health = 200
/// How much cover the girder provides against projectiles.
var/cover = 50
build_amt = 2
@@ -16,10 +16,9 @@
var/reinforcing = 0
var/plating = FALSE
/obj/structure/girder/condition_hints(mob/user, distance, is_adjacent)
. += ..()
/obj/structure/girder/get_damage_condition_hints(mob/user, distance, is_adjacent)
var/state
var/current_damage = health / initial(health)
var/current_damage = health / maxhealth
switch(current_damage)
if(0 to 0.2)
state = SPAN_DANGER("The support struts are collapsing!")
@@ -29,7 +28,7 @@
state = SPAN_NOTICE("The support struts are dented, but holding together.")
if(0.8 to 1)
state = SPAN_NOTICE("The support struts look completely intact.")
. += state
. = state
/obj/structure/girder/mechanics_hints(mob/user, distance, is_adjacent)
. += ..()
@@ -68,7 +67,7 @@
name = "displaced girder"
icon_state = "displaced"
anchored = 0
health = 50
maxhealth = OBJECT_HEALTH_VERY_LOW
cover = 25
/obj/structure/girder/bullet_act(obj/projectile/hitting_projectile, def_zone, piercing_hit)
@@ -83,20 +82,18 @@
if(!istype(hitting_projectile, /obj/projectile/beam))
damage *= 0.4 //non beams do reduced damage
take_damage(damage)
add_damage(damage)
return ..()
/obj/structure/girder/proc/take_damage(var/damage)
health -= damage
if(health <= 0)
visible_message(SPAN_WARNING("\The [src] falls apart!"))
dismantle()
/obj/structure/girder/on_death(damage, damage_flags, damage_type, armor_penetration, obj/weapon)
visible_message(SPAN_WARNING("\The [src] falls apart!"))
. = ..()
/obj/structure/girder/proc/reset_girder()
anchored = 1
anchored = TRUE
cover = initial(cover)
health = min(health,initial(health))
set_health(maxhealth)
state = 0
icon_state = initial(icon_state)
reinforcing = 0
@@ -200,7 +197,7 @@
to_chat(user, SPAN_NOTICE("You dislodged the girder!"))
icon_state = "displaced"
anchored = 0
health = 50
set_maxhealth(OBJECT_HEALTH_VERY_LOW, TRUE)
cover = 25
else if(istype(attacking_item, /obj/item/stack/material))
@@ -222,7 +219,7 @@
if(damage_to_deal > weaken && (damage_to_deal > MIN_DAMAGE_TO_HIT))
damage_to_deal -= weaken
visible_message(SPAN_WARNING("[user] strikes \the [src] with \the [attacking_item], [is_sharp(attacking_item) ? "slicing" : "denting"] a support rod!"))
take_damage(damage_to_deal)
add_damage(damage_to_deal)
else
visible_message(SPAN_WARNING("[user] strikes \the [src] with \the [attacking_item], but it bounces off!"))
user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
@@ -301,7 +298,7 @@
/obj/structure/girder/proc/reinforce_girder()
cover = reinf_material.hardness
health = 500
set_maxhealth(OBJECT_HEALTH_EXTREMELY_HIGH, TRUE)
state = 2
icon_state = "reinforced"
reinforcing = 0
@@ -316,26 +313,18 @@
/obj/structure/girder/ex_act(severity)
switch(severity)
if(1.0)
if(1)
qdel(src)
return
if(2.0)
if(2)
if (prob(30))
dismantle()
return
else
health -= rand(60,180)
if(3.0)
add_damage(rand(60,180))
if(3)
if (prob(5))
dismantle()
return
else
health -= rand(40,80)
if(health <= 0)
dismantle()
return
add_damage(rand(40,80))
/obj/structure/girder/attack_generic(mob/user, damage, attack_message, environment_smash, armor_penetration, attack_flags, damage_type)
if(!damage || !environment_smash)
+16 -27
View File
@@ -4,18 +4,13 @@
icon = 'icons/obj/gore_structures.dmi'
anchored = TRUE
density = FALSE
maxhealth = OBJECT_HEALTH_VERY_LOW
var/destroy_message = "THE STRUCTURE collapses in on itself!"
var/maxHealth = 50
var/health = 50
/obj/structure/gore/Initialize(mapload)
. = ..()
health = maxHealth
/obj/structure/gore/get_examine_text(mob/user, distance, is_adjacent, infix, suffix)
. = ..()
if(distance <= 2)
var/health_div = health / maxHealth
var/health_div = health / maxhealth
if(health_div >= 0.9)
. += SPAN_NOTICE("\The [src] appears completely intact.")
else if(health_div >= 0.7)
@@ -25,32 +20,29 @@
else
. += SPAN_WARNING("\The [src] is barely holding itself together!")
/obj/structure/gore/proc/healthcheck()
if(health <= 0)
var/final_message = replacetext(destroy_message, "THE STRUCTURE", "\The [src]")
visible_message(SPAN_WARNING(final_message))
qdel(src)
/obj/structure/gore/on_death(damage, damage_flags, damage_type, armor_penetration, obj/weapon)
var/final_message = replacetext(destroy_message, "THE STRUCTURE", "\The [src]")
visible_message(SPAN_WARNING(final_message))
qdel(src)
/obj/structure/gore/bullet_act(obj/projectile/hitting_projectile, def_zone, piercing_hit)
. = ..()
if(. != BULLET_ACT_HIT)
return .
health -= hitting_projectile.damage
healthcheck()
add_damage(hitting_projectile.damage)
/obj/structure/gore/ex_act(severity)
switch(severity)
if(1.0)
health -= 50
add_damage(50)
if(2.0)
health -= 50
add_damage(50)
if(3.0)
if(prob(50))
health -= 50
add_damage(50)
else
health -= 25
healthcheck()
add_damage(25)
/obj/structure/gore/hitby(atom/movable/hitting_atom, skipcatch, hitpush, blocked, datum/thrownthing/throwingdatum)
. = ..()
@@ -62,21 +54,18 @@
throw_force = O.throwforce
else if(ismob(hitting_atom))
throw_force = 10
health -= throw_force
healthcheck()
add_damage(throw_force)
/obj/structure/gore/attack_generic(mob/user, damage, attack_message, environment_smash, armor_penetration, attack_flags, damage_type)
attack_hand(usr)
/obj/structure/gore/attackby(obj/item/attacking_item, mob/user)
user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
user.do_attack_animation(src, attacking_item)
var/force_damage = attacking_item.force
var/damage = attacking_item.force
if(attacking_item.damtype == DAMAGE_BURN)
force_damage *= 1.25
health -= force_damage
damage *= 1.25
. = ..()
add_damage(damage)
playsound(loc, 'sound/effects/attackblob.ogg', 80, TRUE)
healthcheck()
/obj/structure/gore/CanPass(atom/movable/mover, turf/target, height=0, air_group=0)
if(air_group)
+10 -18
View File
@@ -5,18 +5,13 @@
desc = "It's a gruesome pile of thick, sticky flesh shaped like a nest."
icon = 'icons/obj/gore_structures.dmi'
icon_state = "nest"
maxhealth = OBJECT_HEALTH_LOW
var/destroy_message = "THE STRUCTURE collapses in on itself!"
var/maxHealth = 100
var/health = 100
/obj/structure/bed/nest/Initialize(mapload, new_material, new_padding_material)
. = ..()
health = maxHealth
/obj/structure/bed/nest/get_examine_text(mob/user, distance, is_adjacent, infix, suffix)
. = ..()
if(distance <= 2)
var/health_div = health / maxHealth
var/health_div = health / maxhealth
if(health_div >= 0.9)
. += SPAN_NOTICE("\The [src] appears completely intact.")
else if(health_div >= 0.7)
@@ -51,19 +46,16 @@
unbuckle()
/obj/structure/bed/nest/attackby(obj/item/attacking_item, mob/user)
user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
user.do_attack_animation(src, attacking_item)
var/force_damage = attacking_item.force
var/damage = attacking_item.force
if(attacking_item.damtype == DAMAGE_BURN)
force_damage *= 1.25
health -= force_damage
damage *= 1.25
. = ..()
add_damage(damage)
playsound(loc, 'sound/effects/attackblob.ogg', 80, TRUE)
healthcheck()
/obj/structure/bed/nest/proc/healthcheck()
if(health <= 0)
var/final_message = replacetext(destroy_message, "THE STRUCTURE", "\The [src]")
visible_message(SPAN_WARNING(final_message))
qdel(src)
/obj/structure/bed/nest/on_death(damage, damage_flags, damage_type, armor_penetration, obj/weapon)
var/final_message = replacetext(destroy_message, "THE STRUCTURE", "\The [src]")
visible_message(SPAN_WARNING(final_message))
qdel(src)
#undef NEST_RESIST_TIME
@@ -4,7 +4,7 @@
name = "bloody tendrils"
desc = "Bloody, pulsating tendrils."
icon_state = "tendril"
maxHealth = 40
maxhealth = OBJECT_HEALTH_VERY_LOW
pass_flags = PASSTABLE | PASSMOB | PASSTRACE | PASSRAILING
var/being_destroyed = FALSE
var/is_node = FALSE
@@ -18,7 +18,7 @@
desc = "Clumped up flesh, pulsating in rhythm with the tendrils that surround it."
icon_state = "tendril_node"
density = TRUE
maxHealth = 150
maxhealth = OBJECT_HEALTH_MEDIUM
light_range = NODERANGE
light_color = LIGHT_COLOR_EMERGENCY
is_node = TRUE
@@ -125,18 +125,16 @@
/obj/structure/gore/tendrils/ex_act(severity)
switch(severity)
if(1.0)
health = 0
add_damage(maxhealth)
if(2.0)
health -= maxHealth / 2
add_damage(maxhealth / 2)
if(3.0)
health -= maxHealth / 5
healthcheck()
add_damage(maxhealth / 5)
/obj/structure/gore/tendrils/fire_act(exposed_temperature, exposed_volume)
. = ..()
if(exposed_temperature > 300 + T0C)
health -= 5
healthcheck()
add_damage(5)
#undef NODERANGE
+5 -6
View File
@@ -2,21 +2,21 @@
name = "flesh floor"
desc = "Looks like the floor was covered by some fleshlike growth."
icon_state = "flesh_floor"
maxHealth = 100
maxhealth = OBJECT_HEALTH_LOW
/obj/structure/gore/wall
name = "flesh wall"
desc = "Chunks of flesh sculpted to form an impassable wall."
icon_state = "flesh_wall"
opacity = TRUE
maxHealth = 200
maxhealth = OBJECT_HEALTH_HIGH
/obj/structure/gore/wall/membrane
name = "flesh membrane"
desc = "Skin and muscle stretched just thin enough to let light pass through."
icon_state = "flesh_membrane"
opacity = FALSE
maxHealth = 120
maxhealth = 120
/obj/structure/gore/wall/Initialize()
. = ..()
@@ -33,8 +33,7 @@
user.do_attack_animation(src, FIST_ATTACK_ANIMATION)
if((user.mutations & HULK))
visible_message(SPAN_DANGER("\The [user] destroys \the [src]!"))
health = 0
add_damage(maxhealth)
else
visible_message(SPAN_DANGER("\The [user] claws at \the [src]!"))
health -= rand(5, 10)
healthcheck()
add_damage(rand(5, 10))
+22 -39
View File
@@ -9,11 +9,15 @@
obj_flags = OBJ_FLAG_CONDUCTABLE | OBJ_FLAG_MOVES_UNSUPPORTED
explosion_resistance = 1
layer = BELOW_WINDOW_LAYER
var/health = 10
maxhealth = OBJECT_HEALTH_FRAGILE
armor = list(
MELEE = ARMOR_MELEE_KNIVES,
LASER = ARMOR_LASER_SMALL,
ENERGY = ARMOR_ENERGY_SMALL
)
var/destroyed = 0
/obj/structure/grille/condition_hints(mob/user, distance, is_adjacent)
. += ..()
/obj/structure/grille/get_damage_condition_hints(mob/user, distance, is_adjacent)
if(health < initial(health))
var/state
var/current_damage = health / initial(health)
@@ -24,7 +28,7 @@
state = SPAN_ALERT("The grille has taken some serious damage.")
if(0.8 to 1)
state = SPAN_NOTICE("The grille is in less than perfect condition.")
. += state
. = state
/obj/structure/grille/mechanics_hints(mob/user, distance, is_adjacent)
. += ..()
@@ -179,8 +183,7 @@
. = BULLET_ACT_HIT
damage = between(0, (damage - hitting_projectile.damage)*(hitting_projectile.damage_type == DAMAGE_BRUTE? 0.4 : 1), 10) //if the bullet passes through then the grille avoids most of the damage
src.health -= damage*0.2
spawn(0) healthcheck() //spawn to make sure we return properly if the grille is deleted
add_damage(damage * 0.2)
/obj/structure/grille/attackby(obj/item/attacking_item, mob/user)
if(attacking_item.tool_behaviour == TOOL_WIRECUTTER)
@@ -262,30 +265,19 @@
user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
user.do_attack_animation(src)
playsound(loc, 'sound/effects/grillehit.ogg', 80, 1)
switch(attacking_item.damtype)
if("fire")
health -= attacking_item.force
if("brute")
health -= attacking_item.force * 0.1
healthcheck()
add_damage(attacking_item.force)
..()
return
/obj/structure/grille/on_death(damage, damage_flags, damage_type, armor_penetration, obj/weapon)
if(!destroyed)
density = FALSE
destroyed = TRUE
update_icon()
new /obj/item/stack/rods(get_turf(src))
/obj/structure/grille/proc/healthcheck()
if(health <= 0)
if(!destroyed)
density = 0
destroyed = 1
update_icon()
new /obj/item/stack/rods(get_turf(src))
else
if(health <= -6)
new /obj/item/stack/rods(get_turf(src))
qdel(src)
return
return
else
. = ..()
// shock user with probability prb (if all connections & power are working)
// returns 1 if shocked, 0 otherwise
@@ -314,17 +306,9 @@
/obj/structure/grille/fire_act(exposed_temperature, exposed_volume)
if(!destroyed)
if(exposed_temperature > T0C + 1500)
health -= 1
healthcheck()
add_damage(1)
..()
/obj/structure/grille/attack_generic(mob/user, damage, attack_message, environment_smash, armor_penetration, attack_flags, damage_type)
visible_message(SPAN_DANGER("[user] [attack_verb] the [src]!"))
user.do_attack_animation(src)
health -= damage
spawn(1) healthcheck()
return 1
// Used in mapping to avoid
/obj/structure/grille/broken
destroyed = 1
@@ -333,8 +317,7 @@
/obj/structure/grille/broken/New()
..()
health = rand(-5, -1) //In the destroyed but not utterly threshold.
healthcheck() //Send this to healthcheck just in case we want to do something else with it.
add_damage(rand(-5, -1)) //In the destroyed but not utterly threshold.
/obj/structure/grille/diagonal
icon_state = "grille_diagonal"
@@ -343,7 +326,7 @@
name = "cult grille"
desc = "A matrice built out of an unknown material, with some sort of force field blocking air around it"
icon_state = "grillecult"
health = 40 //Make it strong enough to avoid people breaking in too easily
maxhealth = OBJECT_HEALTH_VERY_LOW //Make it strong enough to avoid people breaking in too easily
appearance_flags = NO_CLIENT_COLOR
/obj/structure/grille/cult/CanPass(atom/movable/mover, turf/target, height = 1.5, air_group = 0)
+1 -1
View File
@@ -6,11 +6,11 @@
density = TRUE
anchored = TRUE
layer = ABOVE_HUMAN_LAYER
maxhealth = OBJECT_HEALTH_MEDIUM
var/toppled = FALSE
var/outside = FALSE
var/already_toppled = FALSE
var/toppling_sound = 'sound/effects/metalhit.ogg'
var/health = 100
/obj/structure/hadii_statue/stone
icon_state = "stone"
+1 -1
View File
@@ -3,8 +3,8 @@
desc = "The central core of the Hivebot Secondary Transmitter Drone - all that remains after the machine's destruction. Perhaps some data as to the threat can be gleaned from this?"
icon = 'icons/obj/structure/hivebot_head.dmi'
icon_state = "hivebot_head"
maxhealth = null
w_class = WEIGHT_CLASS_BULKY
breakable = FALSE
climbable = FALSE
density = FALSE
+3 -1
View File
@@ -47,10 +47,12 @@
anchored = TRUE
atmos_canpass = CANPASS_DENSITY
maxhealth = OBJECT_HEALTH_FRAGILE
var/deflating = FALSE
var/undeploy_path = null
var/torn_path = null
var/health = 15
/obj/structure/inflatable/mechanics_hints(mob/user, distance, is_adjacent)
. += ..()
+18 -21
View File
@@ -13,9 +13,10 @@
obj_flags = OBJ_FLAG_ROTATABLE|OBJ_FLAG_MOVES_UNSUPPORTED
build_amt = 2
maxhealth = OBJECT_HEALTH_EXTREMELY_LOW
var/broken = FALSE
var/health = 70
var/maxhealth = 70
var/neighbor_status = 0
/// If the object shouldn't inherit a material, set this to True.
@@ -25,16 +26,15 @@
can_astar_pass = CANASTARPASS_ALWAYS_PROC
/obj/structure/railing/condition_hints(mob/user, distance, is_adjacent)
. += ..()
/obj/structure/railing/get_damage_condition_hints(mob/user, distance, is_adjacent)
if (health < maxhealth)
switch(health / maxhealth)
if (0.0 to 0.5)
. += SPAN_WARNING("It looks severely damaged!")
. = SPAN_WARNING("It looks severely damaged!")
if (0.25 to 0.5)
. += SPAN_WARNING("It looks damaged!")
. = SPAN_WARNING("It looks damaged!")
if (0.5 to 1.0)
. += SPAN_NOTICE("It has a few scrapes and dents.")
. = SPAN_NOTICE("It has a few scrapes and dents.")
/obj/structure/railing/mechanics_hints(mob/user, distance, is_adjacent)
. += ..()
@@ -88,8 +88,8 @@
name = "[material.display_name] [initial(name)]"
desc = "A simple [material.display_name] railing designed to protect against careless trespass."
maxhealth = round(material.integrity / 5)
health = maxhealth
set_maxhealth(round(material.integrity / 5))
set_health(maxhealth)
color = material.icon_colour
if(material.products_need_process())
@@ -124,13 +124,11 @@
return !density
return TRUE
/obj/structure/railing/proc/take_damage(amount)
health -= amount
if(health <= 0)
visible_message(SPAN_WARNING("\The [src] [material.destruction_desc]!"))
playsound(get_turf(src), 'sound/effects/grillehit.ogg', 50, TRUE)
material.place_shard(get_turf(src))
qdel(src)
/obj/structure/railing/on_death(damage, damage_flags, damage_type, armor_penetration, obj/weapon)
visible_message(SPAN_WARNING("\The [src] [material.destruction_desc]!"))
playsound(get_turf(src), 'sound/effects/grillehit.ogg', 50, TRUE)
material.place_shard(get_turf(src))
qdel(src)
/obj/structure/railing/proc/NeighborsCheck(var/UpdateNeighbors = 1)
neighbor_status = 0
@@ -298,7 +296,7 @@
if(health >= maxhealth)
return
user.visible_message(SPAN_NOTICE("\The [user] repairs some damage to \the [src]."), SPAN_NOTICE("You repair some damage to \the [src]."))
health = min(health + (maxhealth / 5), maxhealth)
add_health(maxhealth * 0.5)
return
// Install
@@ -320,7 +318,7 @@
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]!"))
take_damage(attacking_item.force)
add_damage(attacking_item.force, attacking_item.damage_flags(), attacking_item.damtype, attacking_item.armor_penetration, attacking_item)
return
. = ..()
@@ -367,7 +365,7 @@
LAZYREMOVE(climbers, user)
if(!anchored || material.is_brittle())
take_damage(maxhealth) // Fatboy
add_damage(maxhealth) // Fatboy
/obj/structure/railing/proc/get_destination_turf(var/mob/user)
. = get_turf(src) // by default, we pop into the turf the railing's on
@@ -394,8 +392,7 @@
icon = 'icons/obj/doors/retractable_railing.dmi'
icon_state = "railing1"
anchored = TRUE
health = 150
maxhealth = 150
maxhealth = OBJECT_HEALTH_MEDIUM
non_material_object = TRUE
can_wrench = FALSE
can_screwdriver = FALSE
+5 -4
View File
@@ -2,18 +2,19 @@
name = "door"
density = 1
anchored = 1
maxhealth = OBJECT_HEALTH_VERY_LOW
icon = 'icons/obj/doors/material_doors.dmi'
icon_state = "metal"
build_amt = 10
var/state = 0 //closed, 1 == open
var/isSwitchingStates = 0
var/oreAmount = 7
var/datum/lock/lock
var/initial_lock_value //for mapping purposes. Basically if this value is set, it sets the lock to this value.
var/health = 100
var/maxhealth = 100
/obj/structure/simple_door/feedback_hints(mob/user, distance, is_adjacent)
. += ..()
@@ -41,8 +42,8 @@
name = "[material.display_name] door"
color = material.icon_colour
maxhealth = max(1,round(material.integrity))
health = maxhealth
set_health(material.integrity)
set_health(maxhealth)
if(initial_lock_value)
locked = initial_lock_value
@@ -252,12 +252,15 @@
update_icon()
/obj/structure/bed/dismantle(obj/item/W, mob/user)
user.visible_message("<b>[user]</b> begins dismantling \the [src].", SPAN_NOTICE("You begin dismantling \the [src]."))
if(W.use_tool(src, user, 20, volume = 50))
user.visible_message("\The [user] dismantles \the [src].", SPAN_NOTICE("You dismantle \the [src]."))
if(padding_material)
padding_material.place_sheet(get_turf(src))
..()
if(user)
user.visible_message("<b>[user]</b> begins dismantling \the [src].", SPAN_NOTICE("You begin dismantling \the [src]."))
if(W.use_tool(src, user, 20, volume = 50))
user.visible_message("\The [user] dismantles \the [src].", SPAN_NOTICE("You dismantle \the [src]."))
else
return FALSE
if(padding_material)
padding_material.place_sheet(get_turf(src))
..()
/obj/structure/bed/Move()
. = ..()
+2 -3
View File
@@ -744,7 +744,7 @@ ABSTRACT_TYPE(/obj/structure/stairs/urban/road_ramp)
icon = 'icons/obj/structure/urban/windows_tall.dmi'
icon_state = "wood"
basestate = "wood"
maxhealth = 60
maxhealth = OBJECT_HEALTH_VERY_LOW
alpha = 255
/obj/structure/window/urban/framed
@@ -791,8 +791,7 @@ ABSTRACT_TYPE(/obj/structure/stairs/urban/road_ramp)
icon = 'icons/obj/structure/urban/building_external.dmi'
icon_state = "wall_half"
//basestate = "wall_half"
health = 200
maxhealth = 200
maxhealth = OBJECT_HEALTH_HIGH
layer = ABOVE_HUMAN_LAYER
/obj/structure/blocker/exterior_wall/red
+37 -88
View File
@@ -17,11 +17,11 @@
anchored = TRUE
atom_flags = ATOM_FLAG_CHECKS_BORDER
obj_flags = OBJ_FLAG_ROTATABLE|OBJ_FLAG_MOVES_UNSUPPORTED
var/hitsound = 'sound/effects/glass_hit.ogg'
var/maxhealth = 14
maxhealth = OBJECT_HEALTH_FRAGILE
hitsound = 'sound/effects/glass_hit.ogg'
var/maximal_heat = T0C + 100 // Maximal heat before this window begins taking damage from fire
var/damage_per_fire_tick = 2 // Amount of damage per fire tick. Regular windows are not fireproof so they might as well break quickly.
var/health
var/ini_dir = null
var/state = 2
var/reinf = FALSE
@@ -34,27 +34,26 @@
atmos_canpass = CANPASS_PROC
/obj/structure/window/condition_hints(mob/user, distance, is_adjacent)
. += ..()
/obj/structure/window/get_damage_condition_hints(mob/user, distance, is_adjacent)
if(health == maxhealth)
. += SPAN_NOTICE("It looks fully intact.")
. = SPAN_NOTICE("It looks fully intact.")
else
var/perc = health / maxhealth
if(perc > 0.75)
. += SPAN_NOTICE("It has a few cracks.")
. = SPAN_NOTICE("It has a few cracks.")
else if(perc > 0.5)
. += SPAN_WARNING("It looks slightly damaged.")
. = SPAN_WARNING("It looks slightly damaged.")
else if(perc > 0.25)
. += SPAN_WARNING("It looks moderately damaged.")
. = SPAN_WARNING("It looks moderately damaged.")
else
. += SPAN_DANGER("It looks heavily damaged.")
. = SPAN_DANGER("It looks heavily damaged.")
if(silicate)
if (silicate < 30)
. += SPAN_NOTICE("It has a thin layer of silicate.")
. = SPAN_NOTICE("It has a thin layer of silicate.")
else if (silicate < 70)
. += SPAN_NOTICE("It is covered in silicate.")
. = SPAN_NOTICE("It is covered in silicate.")
else
. += SPAN_NOTICE("There is a thick layer of silicate covering it.")
. = SPAN_NOTICE("There is a thick layer of silicate covering it.")
/obj/structure/window/proc/update_nearby_icons()
QUEUE_SMOOTH_NEIGHBORS(src)
@@ -65,38 +64,14 @@
layer = ABOVE_HUMAN_LAYER
QUEUE_SMOOTH(src)
/obj/structure/window/proc/take_damage(var/damage = 0, var/sound_effect = 1, message = TRUE)
var/initialhealth = health
if(silicate)
damage = damage * (1 - silicate / 200)
health = max(0, health - damage)
if(health <= 0)
shatter(message)
else
if(sound_effect)
playsound(loc, 'sound/effects/glass_hit.ogg', 100, 1)
if(health < maxhealth / 4 && initialhealth >= maxhealth / 4)
if(message)
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)
if(message)
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)
if(message)
visible_message(SPAN_WARNING("Cracks begin to appear in [src]!"))
playsound(loc, SFX_GLASS_CRACK, 100, 1)
return
/obj/structure/window/on_death(damage, damage_flags, damage_type, armor_penetration, obj/weapon, message)
shatter(message)
/obj/structure/window/proc/apply_silicate(var/amount)
if(health < maxhealth) // Mend the damage.
health = min(health + amount * 3, maxhealth)
add_health(amount * 3)
if(health == maxhealth)
visible_message("[src] looks fully repaired." )
visible_message(SPAN_NOTICE("The silicate fully mends the damage on \the [src]."))
else // Reinforce.
silicate = min(silicate + amount, 100)
updateSilicate()
@@ -145,23 +120,19 @@
if(. != BULLET_ACT_HIT)
return .
take_damage(proj_damage)
return
add_damage(proj_damage)
/obj/structure/window/ex_act(severity)
switch(severity)
if(1)
qdel(src)
return
if(2)
shatter(0)
return
if(3)
if(prob(50))
shatter(0)
return
else
take_damage(rand(10,30), TRUE, FALSE)
add_damage(rand(10,30), TRUE, FALSE)
// This and relevant verbs/procs can probably be removed since full windows are a thing now. -Gem
/obj/structure/window/proc/is_full_window()
@@ -210,7 +181,7 @@
anchored = 0
update_nearby_icons()
step(src, get_dir(hitting_atom, src))
take_damage(tforce)
add_damage(tforce)
/obj/structure/window/attack_hand(var/mob/living/user)
user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
@@ -243,7 +214,7 @@
user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
if(damage >= 10)
visible_message(SPAN_DANGER("[user] smashes into [src]!"))
take_damage(damage)
add_damage(damage)
else
visible_message(SPAN_NOTICE("\The [user] bonks \the [src] harmlessly."))
playsound(src.loc, 'sound/effects/glass_hit.ogg', 10, 1, -2)
@@ -347,8 +318,7 @@
/obj/structure/window/proc/hit(var/damage, var/sound_effect = 1)
if(reinf)
damage *= 0.5
take_damage(damage)
return
add_damage(damage)
/obj/structure/window/proc/dismantle_window()
if(dir == SOUTHWEST)
@@ -369,8 +339,6 @@
if (start_dir)
set_dir(start_dir)
health = maxhealth
ini_dir = dir
update_nearby_tiles(need_rebuild=1)
@@ -429,7 +397,7 @@
glasstype = /obj/item/stack/material/glass
maximal_heat = T0C + 100
damage_per_fire_tick = 2
maxhealth = 12
maxhealth = OBJECT_HEALTH_FRAGILE
/obj/structure/window/basic/full
name = "glass"
@@ -441,7 +409,7 @@
desc = "It looks rather strong. Might take a few good hits to shatter it."
icon_state = "rwindow"
basestate = "rwindow"
maxhealth = 40
maxhealth = OBJECT_HEALTH_LOW
reinf = TRUE
maximal_heat = T0C + 750
damage_per_fire_tick = 2
@@ -462,7 +430,7 @@
/obj/structure/window/reinforced/tinted/frosted
name = "reinforced frosted glass pane"
desc = "It looks rather strong and frosted over. Looks like it might take a few less hits then a normal reinforced window."
maxhealth = 30
maxhealth = OBJECT_HEALTH_EXTREMELY_LOW
/obj/structure/window/reinforced/polarized
name = "reinforced electrochromic glass pane"
@@ -489,9 +457,6 @@
/obj/structure/window/reinforced/crescent/hitby(atom/movable/hitting_atom, skipcatch, hitpush, blocked, datum/thrownthing/throwingdatum)
return
/obj/structure/window/reinforced/crescent/take_damage()
return
/obj/structure/window/reinforced/crescent/shatter()
return
@@ -536,7 +501,7 @@
glasstype = /obj/item/stack/material/glass/phoronglass
maximal_heat = T0C + 2000
damage_per_fire_tick = 1 // This should last for 80 fire ticks if the window is not damaged at all. The idea is that borosilicate windows have something like ablative layer that protects them for a while.
maxhealth = 40
maxhealth = OBJECT_HEALTH_VERY_LOW
/// Phoron-infused silicate
rad_resistance_modifier = 4
@@ -547,13 +512,13 @@
glasstype = /obj/item/stack/material/glass/phoronrglass
reinf = TRUE
maximal_heat = T0C + 4000
maxhealth = 80
maxhealth = OBJECT_HEALTH_LOW
/obj/structure/window/borosilicate/reinforced/skrell
name = "advanced borosilicate alloy window"
desc = "A window made out of a higly advanced borosilicate alloy. It seems to be extremely strong."
color = GLASS_COLOR_PHORON
maxhealth = 250
maxhealth = OBJECT_HEALTH_HIGH
/********** Shuttle Windows **********/
/obj/structure/window/shuttle
@@ -564,7 +529,7 @@
basestate = "w"
atom_flags = 0
obj_flags = null
maxhealth = 40
maxhealth = OBJECT_HEALTH_VERY_LOW
reinf = TRUE
dir = 5
smoothing_flags = SMOOTH_TRUE
@@ -579,8 +544,7 @@
/obj/structure/window/shuttle/legion
name = "reinforced cockpit window"
icon = 'icons/obj/smooth/shuttle_window_legion.dmi'
health = 160
maxhealth = 160
maxhealth = OBJECT_HEALTH_HIGH
/obj/structure/window/shuttle/palepurple
icon = 'icons/obj/smooth/shuttle_window_palepurple.dmi'
@@ -589,8 +553,7 @@
name = "advanced borosilicate alloy window"
desc = "It looks extremely strong. Might take many good hits to crack it."
icon = 'icons/obj/smooth/skrell_window_purple.dmi'
health = 500
maxhealth = 500
maxhealth = OBJECT_HEALTH_VERY_HIGH
smoothing_flags = SMOOTH_MORE | SMOOTH_DIAGONAL
canSmoothWith = list(
/turf/simulated/wall/shuttle/skrell,
@@ -602,8 +565,7 @@
desc = "It looks extremely strong. Might take many good hits to crack it."
icon = 'icons/turf/smooth/scc_ship/scc_ship_windows.dmi'
icon_state = "map_window"
health = 500
maxhealth = 500
maxhealth = OBJECT_HEALTH_VERY_HIGH
alpha = 255
smoothing_flags = SMOOTH_MORE
canSmoothWith = list(
@@ -629,15 +591,11 @@
/obj/structure/window/shuttle/scc
icon = 'icons/obj/smooth/scc_shuttle_window.dmi'
health = 160
maxhealth = 160
maxhealth = OBJECT_HEALTH_HIGH
/obj/structure/window/shuttle/crescent
desc = "It looks rather strong."
/obj/structure/window/shuttle/crescent/take_damage()
return
//
// Full Windows
//
@@ -647,7 +605,7 @@
atom_flags = 0
obj_flags = null
dir = 5
maxhealth = 28 // Two glass panes worth of health, since that's the minimum you need to break through to get to the other side.
maxhealth = OBJECT_HEALTH_EXTREMELY_LOW
glasstype = /obj/item/stack/material/glass
shardtype = /obj/item/material/shard
full = TRUE
@@ -757,14 +715,12 @@
qdel(src)
return
/obj/structure/window/full/take_damage(var/damage = 0, var/sound_effect = 1)
/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)
health = max(0, health - damage)
if(health <= 0)
shatter()
else
@@ -779,7 +735,6 @@
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)
return
/obj/structure/window/full/dismantle_window()
var/obj/item/stack/material/mats = new glasstype(loc)
@@ -803,7 +758,7 @@
icon = 'icons/obj/smooth/window/full_window.dmi'
icon_state = "window_glass"
basestate = "window_glass"
maxhealth = 80 // Two reinforced panes worth of health, since that's the minimum you need to break through to get to the other side.
maxhealth = OBJECT_HEALTH_LOW
reinf = TRUE
maximal_heat = T0C + 750
glasstype = /obj/item/stack/material/glass/reinforced
@@ -834,9 +789,6 @@
/obj/structure/window/full/reinforced/indestructible/hitby(atom/movable/hitting_atom, skipcatch, hitpush, blocked, datum/thrownthing/throwingdatum)
return
/obj/structure/window/full/reinforced/indestructible/take_damage()
return
/obj/structure/window/full/reinforced/indestructible/shatter()
return
@@ -867,9 +819,6 @@
/obj/structure/window/full/reinforced/polarized/indestructible/hitby(atom/movable/hitting_atom, skipcatch, hitpush, blocked, datum/thrownthing/throwingdatum)
return
/obj/structure/window/full/reinforced/polarized/indestructible/take_damage()
return
/obj/structure/window/full/reinforced/polarized/indestructible/shatter()
return
@@ -898,7 +847,7 @@
basestate = "window_glass"
glasstype = /obj/item/stack/material/glass/phoronglass
shardtype = /obj/item/material/shard/phoron
maxhealth = 80 // Two borosilicate glass panes worth of health, since that's the minimum you need to break through to get to the other side.
maxhealth = OBJECT_HEALTH_LOW
maximal_heat = T0C + 2000
damage_per_fire_tick = 1
@@ -907,7 +856,7 @@
name = "reinforced borosilicate window"
desc = "A borosilicate alloy window, with rods supporting it. It seems to be very strong."
glasstype = /obj/item/stack/material/glass/phoronrglass
maxhealth = 160 // Two reinforced borosilicate glass panes worth of health, since that's the minimum you need to break through to get to the other side.
maxhealth = OBJECT_HEALTH_MEDIUM
reinf = TRUE
maximal_heat = T0C + 4000
rad_resistance_modifier = 4