mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2025-12-31 03:52:31 +00:00
About The Pull Request
full tile Reinforced windows now require a melee item over 11 damage to damage, have 150 health, and 90 melee armor. This is approximately 2 minutes of sustained beating with a toolbox.
full tile reinforced Plasmaglass windows now require a melee item over 21 damage to damage, have 200 health, and 95 melee resistance. This is approximately 3 minutes of sustained beating with a toolbox.
dir windows have been given the appropriate halved health values.
Current deconstruction steps:
heat one way screws (welder, 18 seconds, harm intent required)
unscrew one way screws (screwdriver, 8 seconds)
pop out panel (crowbar, 5 seconds)
cut connecting bars (wirecutter, 3 seconds)
unbolt frame (wrench, 5 seconds)
theoretical fastest time: 39 seconds
more practical time: 45 seconds
if the bolts are heated and then not unscrewed within 30 seconds they cool off again, and must be heated again
Construction is the same as before except the crowbar levering step takes 10 seconds instead of 3.
Why It's Good For The Game
Getting into places you shouldn't be is currently way too easy.
This change forces you to hack in, disassemble the window, or target a weak point like a windoor.
At the moment, it is possible to smash down what is intended to be a secure window with an item you get in your bag at roundstart for free. This is stupid. It should require some planning or at least thinking to be able to make your way in places you should not be.
Oranges has talked in the past about departments being designed like impenetrable fortresses with shutters everywhere, and this happens because reinforced windows are far too weak and unreliable to be able to have as effective defense of any department against even underequipped and underprepared people. This leads to the introduction of shutters which are too strong and difficult to deal with in most cases.
This is part of some plans to make departments more secure overall while still providing ample avenues for determined or properly prepared individuals able to get in if they want to. Despite having more plans along with this, this is a standalone change as is. This is not a "this will only work with later changes I'm totally going to do" situation
Changelog
cl
balance: Reinforced windows now require a melee item over 11 damage to damage, have 150 health, and 90 melee armor. This is approximately 2 minutes of sustained beating with a toolbox.
balance: Plasmaglass windows now require a melee item over 21 damage to damage, have 200 health, and 90 melee resistance. This is approximately 3 minutes of sustained beating with a toolbox.
/cl
292 lines
11 KiB
Plaintext
292 lines
11 KiB
Plaintext
|
|
///the essential proc to call when an obj must receive damage of any kind.
|
|
/obj/proc/take_damage(damage_amount, damage_type = BRUTE, damage_flag = "", sound_effect = TRUE, attack_dir, armour_penetration = 0)
|
|
if(QDELETED(src))
|
|
stack_trace("[src] taking damage after deletion")
|
|
return
|
|
if(sound_effect)
|
|
play_attack_sound(damage_amount, damage_type, damage_flag)
|
|
if((resistance_flags & INDESTRUCTIBLE) || obj_integrity <= 0)
|
|
return
|
|
damage_amount = run_obj_armor(damage_amount, damage_type, damage_flag, attack_dir, armour_penetration)
|
|
if(damage_amount < DAMAGE_PRECISION)
|
|
return
|
|
. = damage_amount
|
|
obj_integrity = max(obj_integrity - damage_amount, 0)
|
|
//BREAKING FIRST
|
|
if(integrity_failure && obj_integrity <= integrity_failure)
|
|
obj_break(damage_flag)
|
|
//DESTROYING SECOND
|
|
if(obj_integrity <= 0)
|
|
obj_destruction(damage_flag)
|
|
|
|
///returns the damage value of the attack after processing the obj's various armor protections
|
|
/obj/proc/run_obj_armor(damage_amount, damage_type, damage_flag = 0, attack_dir, armour_penetration = 0)
|
|
if(damage_flag == "melee" && damage_amount < damage_deflection)
|
|
return 0
|
|
switch(damage_type)
|
|
if(BRUTE)
|
|
if(BURN)
|
|
else
|
|
return 0
|
|
var/armor_protection = 0
|
|
if(damage_flag)
|
|
armor_protection = armor.getRating(damage_flag)
|
|
if(armor_protection) //Only apply weak-against-armor/hollowpoint effects if there actually IS armor.
|
|
armor_protection = CLAMP(armor_protection - armour_penetration, min(armor_protection, 0), 100)
|
|
return round(damage_amount * (100 - armor_protection)*0.01, DAMAGE_PRECISION)
|
|
|
|
///the sound played when the obj is damaged.
|
|
/obj/proc/play_attack_sound(damage_amount, damage_type = BRUTE, damage_flag = 0)
|
|
switch(damage_type)
|
|
if(BRUTE)
|
|
if(damage_amount)
|
|
playsound(src, 'sound/weapons/smash.ogg', 50, 1)
|
|
else
|
|
playsound(src, 'sound/weapons/tap.ogg', 50, 1)
|
|
if(BURN)
|
|
playsound(src.loc, 'sound/items/welder.ogg', 100, 1)
|
|
|
|
/obj/hitby(atom/movable/AM, skipcatch, hitpush, blocked, datum/thrownthing/throwingdatum)
|
|
..()
|
|
take_damage(AM.throwforce, BRUTE, "melee", 1, get_dir(src, AM))
|
|
|
|
/obj/ex_act(severity, target)
|
|
if(resistance_flags & INDESTRUCTIBLE)
|
|
return
|
|
..() //contents explosion
|
|
if(target == src)
|
|
take_damage(INFINITY, BRUTE, "bomb", 0)
|
|
return
|
|
switch(severity)
|
|
if(1)
|
|
take_damage(INFINITY, BRUTE, "bomb", 0)
|
|
if(2)
|
|
take_damage(rand(100, 250), BRUTE, "bomb", 0)
|
|
if(3)
|
|
take_damage(rand(10, 90), BRUTE, "bomb", 0)
|
|
|
|
/obj/bullet_act(obj/item/projectile/P)
|
|
. = ..()
|
|
playsound(src, P.hitsound, 50, 1)
|
|
visible_message("<span class='danger'>[src] is hit by \a [P]!</span>", null, null, COMBAT_MESSAGE_RANGE)
|
|
if(!QDELETED(src)) //Bullet on_hit effect might have already destroyed this object
|
|
take_damage(P.damage, P.damage_type, P.flag, 0, turn(P.dir, 180), P.armour_penetration)
|
|
|
|
///Called to get the damage that hulks will deal to the obj.
|
|
/obj/proc/hulk_damage()
|
|
return 150 //the damage hulks do on punches to this object, is affected by melee armor
|
|
|
|
/obj/attack_hulk(mob/living/carbon/human/user, does_attack_animation = 0)
|
|
if(user.a_intent == INTENT_HARM)
|
|
..(user, 1)
|
|
user.visible_message("<span class='danger'>[user] smashes [src]!</span>", "<span class='danger'>You smash [src]!</span>", null, COMBAT_MESSAGE_RANGE)
|
|
if(density)
|
|
playsound(src, 'sound/effects/meteorimpact.ogg', 100, 1)
|
|
user.say(pick(";RAAAAAAAARGH!", ";HNNNNNNNNNGGGGGGH!", ";GWAAAAAAAARRRHHH!", "NNNNNNNNGGGGGGGGHH!", ";AAAAAAARRRGH!" ), forced="hulk")
|
|
else
|
|
playsound(src, 'sound/effects/bang.ogg', 50, 1)
|
|
take_damage(hulk_damage(), BRUTE, "melee", 0, get_dir(src, user))
|
|
return 1
|
|
return 0
|
|
|
|
/obj/blob_act(obj/structure/blob/B)
|
|
if(isturf(loc))
|
|
var/turf/T = loc
|
|
if(T.intact && level == 1) //the blob doesn't destroy thing below the floor
|
|
return
|
|
take_damage(400, BRUTE, "melee", 0, get_dir(src, B))
|
|
|
|
/obj/proc/attack_generic(mob/user, damage_amount = 0, damage_type = BRUTE, damage_flag = 0, sound_effect = 1, armor_penetration = 0) //used by attack_alien, attack_animal, and attack_slime
|
|
user.do_attack_animation(src)
|
|
user.changeNext_move(CLICK_CD_MELEE)
|
|
return take_damage(damage_amount, damage_type, damage_flag, sound_effect, get_dir(src, user), armor_penetration)
|
|
|
|
/obj/attack_alien(mob/living/carbon/alien/humanoid/user)
|
|
if(attack_generic(user, 60, BRUTE, "melee", 0))
|
|
playsound(src.loc, 'sound/weapons/slash.ogg', 100, 1)
|
|
|
|
/obj/attack_animal(mob/living/simple_animal/M)
|
|
if(!M.melee_damage_upper && !M.obj_damage)
|
|
M.emote("custom", message = "[M.friendly] [src].")
|
|
return 0
|
|
else
|
|
var/play_soundeffect = 1
|
|
if(M.environment_smash)
|
|
play_soundeffect = 0
|
|
if(M.obj_damage)
|
|
. = attack_generic(M, M.obj_damage, M.melee_damage_type, "melee", play_soundeffect, M.armour_penetration)
|
|
else
|
|
. = attack_generic(M, rand(M.melee_damage_lower,M.melee_damage_upper), M.melee_damage_type, "melee", play_soundeffect, M.armour_penetration)
|
|
if(. && !play_soundeffect)
|
|
playsound(src, 'sound/effects/meteorimpact.ogg', 100, 1)
|
|
|
|
/obj/force_pushed(atom/movable/pusher, force = MOVE_FORCE_DEFAULT, direction)
|
|
return TRUE
|
|
|
|
/obj/move_crushed(atom/movable/pusher, force = MOVE_FORCE_DEFAULT, direction)
|
|
collision_damage(pusher, force, direction)
|
|
return TRUE
|
|
|
|
/obj/proc/collision_damage(atom/movable/pusher, force = MOVE_FORCE_DEFAULT, direction)
|
|
var/amt = max(0, ((force - (move_resist * MOVE_FORCE_CRUSH_RATIO)) / (move_resist * MOVE_FORCE_CRUSH_RATIO)) * 10)
|
|
take_damage(amt, BRUTE)
|
|
|
|
/obj/attack_slime(mob/living/simple_animal/slime/user)
|
|
if(!user.is_adult)
|
|
return
|
|
attack_generic(user, rand(10, 15), "melee", 1)
|
|
|
|
/obj/mech_melee_attack(obj/mecha/M)
|
|
M.do_attack_animation(src)
|
|
var/play_soundeffect = 0
|
|
var/mech_damtype = M.damtype
|
|
if(M.selected)
|
|
mech_damtype = M.selected.damtype
|
|
play_soundeffect = 1
|
|
else
|
|
switch(M.damtype)
|
|
if(BRUTE)
|
|
playsound(src, 'sound/weapons/punch4.ogg', 50, 1)
|
|
if(BURN)
|
|
playsound(src, 'sound/items/welder.ogg', 50, 1)
|
|
if(TOX)
|
|
playsound(src, 'sound/effects/spray2.ogg', 50, 1)
|
|
return 0
|
|
else
|
|
return 0
|
|
M.visible_message("<span class='danger'>[M.name] hits [src]!</span>", "<span class='danger'>You hit [src]!</span>", null, COMBAT_MESSAGE_RANGE)
|
|
return take_damage(M.force*3, mech_damtype, "melee", play_soundeffect, get_dir(src, M)) // multiplied by 3 so we can hit objs hard but not be overpowered against mobs.
|
|
|
|
/obj/singularity_act()
|
|
ex_act(EXPLODE_DEVASTATE)
|
|
if(src && !QDELETED(src))
|
|
qdel(src)
|
|
return 2
|
|
|
|
|
|
///// ACID
|
|
|
|
GLOBAL_DATUM_INIT(acid_overlay, /mutable_appearance, mutable_appearance('icons/effects/effects.dmi', "acid"))
|
|
|
|
///the obj's reaction when touched by acid
|
|
/obj/acid_act(acidpwr, acid_volume)
|
|
if(!(resistance_flags & UNACIDABLE) && acid_volume)
|
|
|
|
if(!acid_level)
|
|
SSacid.processing[src] = src
|
|
add_overlay(GLOB.acid_overlay, TRUE)
|
|
var/acid_cap = acidpwr * 300 //so we cannot use huge amounts of weak acids to do as well as strong acids.
|
|
if(acid_level < acid_cap)
|
|
acid_level = min(acid_level + acidpwr * acid_volume, acid_cap)
|
|
return 1
|
|
|
|
///the proc called by the acid subsystem to process the acid that's on the obj
|
|
/obj/proc/acid_processing()
|
|
. = 1
|
|
if(!(resistance_flags & ACID_PROOF))
|
|
for(var/armour_value in armor)
|
|
if(armour_value != "acid" && armour_value != "fire")
|
|
armor = armor.modifyAllRatings(0 - round(sqrt(acid_level)*0.1))
|
|
if(prob(33))
|
|
playsound(loc, 'sound/items/welder.ogg', 150, 1)
|
|
take_damage(min(1 + round(sqrt(acid_level)*0.3), 300), BURN, "acid", 0)
|
|
|
|
acid_level = max(acid_level - (5 + 3*round(sqrt(acid_level))), 0)
|
|
if(!acid_level)
|
|
return 0
|
|
|
|
///called when the obj is destroyed by acid.
|
|
/obj/proc/acid_melt()
|
|
SSacid.processing -= src
|
|
deconstruct(FALSE)
|
|
|
|
//// FIRE
|
|
|
|
///Called when the obj is exposed to fire.
|
|
/obj/fire_act(exposed_temperature, exposed_volume)
|
|
if(isturf(loc))
|
|
var/turf/T = loc
|
|
if(T.intact && level == 1) //fire can't damage things hidden below the floor.
|
|
return
|
|
if(exposed_temperature && !(resistance_flags & FIRE_PROOF))
|
|
take_damage(CLAMP(0.02 * exposed_temperature, 0, 20), BURN, "fire", 0)
|
|
if(!(resistance_flags & ON_FIRE) && (resistance_flags & FLAMMABLE) && !(resistance_flags & FIRE_PROOF))
|
|
resistance_flags |= ON_FIRE
|
|
SSfire_burning.processing[src] = src
|
|
add_overlay(GLOB.fire_overlay, TRUE)
|
|
return 1
|
|
|
|
///called when the obj is destroyed by fire
|
|
/obj/proc/burn()
|
|
if(resistance_flags & ON_FIRE)
|
|
SSfire_burning.processing -= src
|
|
deconstruct(FALSE)
|
|
|
|
///Called when the obj is no longer on fire.
|
|
/obj/proc/extinguish()
|
|
if(resistance_flags & ON_FIRE)
|
|
resistance_flags &= ~ON_FIRE
|
|
cut_overlay(GLOB.fire_overlay, TRUE)
|
|
SSfire_burning.processing -= src
|
|
|
|
///Called when the obj is hit by a tesla bolt.
|
|
/obj/proc/tesla_act(power, tesla_flags, shocked_targets)
|
|
obj_flags |= BEING_SHOCKED
|
|
var/power_bounced = power / 2
|
|
tesla_zap(src, 3, power_bounced, tesla_flags, shocked_targets)
|
|
addtimer(CALLBACK(src, .proc/reset_shocked), 10)
|
|
|
|
//The surgeon general warns that being buckled to certain objects receiving powerful shocks is greatly hazardous to your health
|
|
///Only tesla coils and grounding rods currently call this because mobs are already targeted over all other objects, but this might be useful for more things later.
|
|
/obj/proc/tesla_buckle_check(var/strength)
|
|
if(has_buckled_mobs())
|
|
for(var/m in buckled_mobs)
|
|
var/mob/living/buckled_mob = m
|
|
buckled_mob.electrocute_act((CLAMP(round(strength/400), 10, 90) + rand(-5, 5)), src, tesla_shock = 1)
|
|
|
|
/obj/proc/reset_shocked()
|
|
obj_flags &= ~BEING_SHOCKED
|
|
|
|
///the obj is deconstructed into pieces, whether through careful disassembly or when destroyed.
|
|
/obj/proc/deconstruct(disassembled = TRUE)
|
|
SEND_SIGNAL(src, COMSIG_OBJ_DECONSTRUCT, disassembled)
|
|
qdel(src)
|
|
|
|
///called after the obj takes damage and integrity is below integrity_failure level
|
|
/obj/proc/obj_break(damage_flag)
|
|
return
|
|
|
|
///what happens when the obj's integrity reaches zero.
|
|
/obj/proc/obj_destruction(damage_flag)
|
|
if(damage_flag == "acid")
|
|
acid_melt()
|
|
else if(damage_flag == "fire")
|
|
burn()
|
|
else
|
|
deconstruct(FALSE)
|
|
|
|
///changes max_integrity while retaining current health percentage, returns TRUE if the obj got broken.
|
|
/obj/proc/modify_max_integrity(new_max, can_break = TRUE, damage_type = BRUTE, new_failure_integrity = null)
|
|
var/current_integrity = obj_integrity
|
|
var/current_max = max_integrity
|
|
|
|
if(current_integrity != 0 && current_max != 0)
|
|
var/percentage = current_integrity / current_max
|
|
current_integrity = max(1, round(percentage * new_max)) //don't destroy it as a result
|
|
obj_integrity = current_integrity
|
|
|
|
max_integrity = new_max
|
|
|
|
if(new_failure_integrity != null)
|
|
integrity_failure = new_failure_integrity
|
|
|
|
if(can_break && integrity_failure && current_integrity <= integrity_failure)
|
|
obj_break(damage_type)
|
|
return TRUE
|
|
return FALSE
|
|
|
|
///returns how much the object blocks an explosion. Used by subtypes.
|
|
/obj/proc/GetExplosionBlock()
|
|
CRASH("Unimplemented GetExplosionBlock()")
|