mirror of
https://github.com/vgstation-coders/vgstation13.git
synced 2025-12-10 10:21:11 +00:00
353 lines
12 KiB
Plaintext
353 lines
12 KiB
Plaintext
/obj/structure/grille
|
|
name = "grille"
|
|
desc = "A matrix of metal rods, usually used as a support for window bays, with screws to secure it to the floor."
|
|
icon = 'icons/obj/structures.dmi'
|
|
icon_state = "grille0"
|
|
density = 1
|
|
anchored = 1
|
|
flags = FPRINT
|
|
siemens_coefficient = 1
|
|
pressure_resistance = 5*ONE_ATMOSPHERE
|
|
layer = BELOW_OBJ_LAYER
|
|
explosion_resistance = 5
|
|
pass_flags_self = PASSGRILLE
|
|
var/health = 20 //Relatively "strong" since it's hard to dismantle via brute force
|
|
var/broken = 0
|
|
var/grille_material = /obj/item/stack/rods
|
|
|
|
/obj/structure/grille/canSmoothWith()
|
|
var/static/list/smoothables = list(
|
|
/obj/structure/grille,
|
|
)
|
|
return smoothables
|
|
|
|
/obj/structure/grille/New(loc)
|
|
..(loc)
|
|
if(ticker && ticker.current_state >= GAME_STATE_PLAYING)
|
|
initialize()
|
|
|
|
/obj/structure/grille/initialize()
|
|
relativewall()
|
|
relativewall_neighbours()
|
|
|
|
/obj/structure/grille/relativewall()
|
|
if(broken)
|
|
return
|
|
var/junction = findSmoothingNeighbors()
|
|
icon_state = "grille[junction]"
|
|
|
|
/obj/structure/grille/isSmoothableNeighbor(atom/A)
|
|
if(istype(A,/obj/structure/grille))
|
|
var/obj/structure/grille/G = A
|
|
if(G.broken)
|
|
return 0
|
|
return ..()
|
|
|
|
/obj/structure/grille/examine(mob/user)
|
|
|
|
..()
|
|
if(!anchored)
|
|
to_chat(user, "Its screws are loose.")
|
|
if(broken) //We're not going to bother with the damage
|
|
to_chat(user, "It has been completely smashed apart! Only a few rods are still holding together.")
|
|
|
|
/obj/structure/grille/cultify()
|
|
new /obj/structure/grille/cult(get_turf(src))
|
|
qdel(src)
|
|
|
|
/obj/structure/grille/proc/healthcheck(var/hitsound = 0) //Note : Doubles as the destruction proc()
|
|
if(hitsound)
|
|
playsound(loc, 'sound/effects/grillehit.ogg', 80, 1)
|
|
if(health <= (0.25*initial(health)) && !broken) //Modular, 1/4th of original health. Do make sure the grille isn't broken !
|
|
broken = 1
|
|
icon_state = "[initial(icon_state)]-b"
|
|
setDensity(FALSE) //Not blocking anything anymore
|
|
new grille_material(get_turf(src)) //One rod set
|
|
relativewall_neighbours()
|
|
else if(health > (0.25*initial(health)) && broken) //Repair the damage to this bitch
|
|
broken = 0
|
|
icon_state = initial(icon_state)
|
|
setDensity(TRUE)
|
|
relativewall_neighbours()
|
|
if(health <= 0) //Dead
|
|
new grille_material(get_turf(src)) //Drop the second set of rods
|
|
qdel(src)
|
|
|
|
/obj/structure/grille/ex_act(severity)
|
|
switch(severity)
|
|
if(1)
|
|
health -= rand(30, 50)
|
|
if(2)
|
|
health -= rand(15, 30)
|
|
if(3)
|
|
health -= rand(5, 15)
|
|
healthcheck(hitsound = 1)
|
|
return
|
|
|
|
/obj/structure/grille/blob_act()
|
|
anim(target = loc, a_icon = 'icons/mob/blob/blob.dmi', flick_anim = "blob_act", sleeptime = 15, lay = 12)
|
|
health -= rand(initial(health)*0.8, initial(health)*3) //Grille will always be blasted, but chances of leaving things over
|
|
healthcheck(hitsound = 1)
|
|
|
|
/obj/structure/grille/Bumped(atom/user)
|
|
if(ismob(user))
|
|
shock(user, 60) //Give the user the benifit of the doubt
|
|
|
|
/obj/structure/grille/hitby(var/atom/movable/AM)
|
|
. = ..()
|
|
if(.)
|
|
return
|
|
if(ismob(AM))
|
|
var/mob/M = AM
|
|
health -= 10
|
|
healthcheck(TRUE)
|
|
if (AM.invisibility < 101)
|
|
visible_message("<span class='danger'>\The [M] slams into \the [src].</span>", \
|
|
"<span class='danger'>You slam into \the [src].</span>")
|
|
else if(isobj(AM))
|
|
var/obj/item/I = AM
|
|
health -= I.throwforce
|
|
healthcheck(TRUE)
|
|
if (AM.invisibility < 101)
|
|
visible_message("<span class='danger'>\The [I] slams into \the [src].</span>")
|
|
|
|
/obj/structure/grille/attack_paw(mob/user as mob)
|
|
attack_hand(user)
|
|
|
|
/obj/structure/grille/attack_hand(mob/user as mob)
|
|
user.do_attack_animation(src, user)
|
|
var/humanverb = pick(list("kick", "slam", "elbow")) //Only verbs with a third person "s", thank you
|
|
user.delayNextAttack(8)
|
|
user.visible_message("<span class='warning'>[user] [humanverb]s \the [src].</span>", \
|
|
"<span class='warning'>You [humanverb] \the [src].</span>", \
|
|
"<span class='warning'>You hear twisting metal.</span>")
|
|
if(M_HULK in user.mutations)
|
|
health -= 5 //Fair hit
|
|
else
|
|
health -= 3 //Do decent damage, still not as good as using a real tool
|
|
healthcheck(hitsound = 1)
|
|
shock(user, 100) //If there's power running in the grille, allow the attack but grill the user
|
|
|
|
/obj/structure/grille/attack_alien(mob/user as mob)
|
|
if(istype(user, /mob/living/carbon/alien/larva))
|
|
return
|
|
user.do_attack_animation(src, user)
|
|
var/alienverb = pick(list("slam", "rip", "claw")) //See above
|
|
user.delayNextAttack(8)
|
|
user.visible_message("<span class='warning'>[user] [alienverb]s \the [src].</span>", \
|
|
"<span class='warning'>You [alienverb] \the [src].</span>", \
|
|
"You hear twisting metal.")
|
|
health -= 5
|
|
healthcheck(hitsound = 1)
|
|
shock(user, 75) //Ditto above
|
|
|
|
/obj/structure/grille/attack_slime(mob/user as mob)
|
|
if(!istype(user, /mob/living/carbon/slime/adult))
|
|
return
|
|
user.do_attack_animation(src, user)
|
|
user.delayNextAttack(8)
|
|
user.visible_message("<span class='warning'>[user] smashes against \the [src].</span>", \
|
|
"<span class='warning'>You smash against \the [src].</span>", \
|
|
"You hear twisting metal.")
|
|
health -= 3
|
|
healthcheck(hitsound = 1)
|
|
shock(user, 100)
|
|
return
|
|
|
|
/obj/structure/grille/attack_animal(var/mob/living/simple_animal/M as mob)
|
|
M.delayNextAttack(8)
|
|
if(M.melee_damage_upper == 0)
|
|
return
|
|
M.do_attack_animation(src, M)
|
|
M.visible_message("<span class='warning'>[M] smashes against \the [src].</span>", \
|
|
"<span class='warning'>You smash against \the [src].</span>", \
|
|
"You hear twisting metal.")
|
|
health -= rand(M.melee_damage_lower, M.melee_damage_upper)
|
|
healthcheck(hitsound = 1)
|
|
shock(M, 100)
|
|
return
|
|
|
|
|
|
/obj/structure/grille/Cross(atom/movable/mover, turf/target, height = 1.5, air_group = 0)
|
|
if(air_group || (height == 0))
|
|
return 1
|
|
if(istype(mover) && mover.checkpass(pass_flags_self))
|
|
return 1
|
|
else
|
|
if(istype(mover, /obj/item/projectile))
|
|
var/obj/item/projectile/projectile = mover
|
|
return prob(projectile.grillepasschance) //Fairly hit chance
|
|
else
|
|
return !density
|
|
|
|
/obj/structure/grille/projectile_check() //handled by the projectile's grillepasschance in Cross()
|
|
return
|
|
|
|
/obj/structure/grille/bullet_act(var/obj/item/projectile/Proj)
|
|
if(!Proj)
|
|
return
|
|
health -= Proj.damage //Just use the projectile damage, it already has high odds of "missing"
|
|
healthcheck(hitsound = 1)
|
|
return ..()
|
|
|
|
/obj/structure/grille/attackby(obj/item/weapon/W as obj, mob/user as mob)
|
|
user.delayNextAttack(8)
|
|
if(isglasssheet(W))
|
|
if (get_dir(src, user) in cardinal)
|
|
var/obj/item/stack/sheet/glass/G = W
|
|
for(var/datum/stack_recipe/SR in G.recipes)
|
|
if(ispath(SR.result_type, /obj/structure/window))
|
|
var/obj/structure/window/S = SR.build(user,G,1,loc)
|
|
if(S)
|
|
S.forceMove(get_turf(src))
|
|
S.dir = get_dir(src, user)
|
|
return
|
|
else
|
|
to_chat(user, "<span class='warning'>You need to stand properly in front of the grille to place windows on it.</span>")
|
|
return
|
|
if(W.is_wirecutter(user))
|
|
if(!shock(user, 100, W.siemens_coefficient)) //Prevent user from doing it if he gets shocked
|
|
W.playtoolsound(loc, 100)
|
|
drop_stack(grille_material, get_turf(src), broken ? 1 : 2, user) //Drop the rods, taking account on whenever the grille is broken or not !
|
|
qdel(src)
|
|
return
|
|
return //Return in case the user starts cutting and gets shocked, so that it doesn't continue downwards !
|
|
else if((W.is_screwdriver(user)) && (istype(loc, /turf/simulated) || anchored))
|
|
if(!shock(user, 90, W.siemens_coefficient))
|
|
W.playtoolsound(loc, 100)
|
|
anchored = !anchored
|
|
user.visible_message("<span class='notice'>[user] [anchored ? "fastens" : "unfastens"] the grille [anchored ? "to" : "from"] the floor.</span>", \
|
|
"<span class='notice'>You [anchored ? "fasten" : "unfasten"] the grille [anchored ? "to" : "from"] the floor.</span>")
|
|
return
|
|
var/dam = 0
|
|
if(istype(W, /obj/item/weapon/fireaxe)) //Fireaxes instantly kill grilles
|
|
dam = health
|
|
else if(istype(W, /obj/item/weapon/shard))
|
|
dam = W.force * 0.1 //Turns the base shard into a .5 damage item. If you want to break an electrified grille with that, you're going to EARN IT, ROD. BY. ROD.
|
|
else
|
|
switch(W.damtype)
|
|
if("fire")
|
|
dam = W.force //Fire-based tools like welding tools are ideal to work through small metal rods !
|
|
if("brute")
|
|
dam = W.force * 0.5 //Rod matrices have an innate resistance to brute damage
|
|
|
|
if(!(W.sharpness_flags & INSULATED_EDGE))
|
|
shock(user, 100 * W.siemens_coefficient, W.siemens_coefficient) //Chance of getting shocked is proportional to conductivity
|
|
|
|
if(dam)
|
|
user.do_attack_animation(src, W)
|
|
visible_message("<span class='danger'>[user] hits [src] with [W].</span>")
|
|
health -= dam
|
|
healthcheck(hitsound = 1)
|
|
..()
|
|
//Shock user with probability prb (if all connections & power are working)
|
|
//Returns 1 if shocked, 0 otherwise
|
|
|
|
/obj/structure/grille/proc/shock(mob/user as mob, prb, siemens_coeff)
|
|
if(!anchored || broken) //De-anchored and destroyed grilles are never connected to the powernet !
|
|
return 0
|
|
if(!prob(prb)) //If the probability roll failed, don't go further
|
|
return 0
|
|
if(!Adjacent(user)) //To prevent TK and mech users from getting shocked
|
|
return 0
|
|
//Process the shocking via powernet, our job is done here
|
|
var/turf/T = get_turf(src)
|
|
var/obj/structure/cable/C = T.get_cable_node()
|
|
if(C)
|
|
if(electrocute_mob(user, C, src, siemens_coeff))
|
|
spark(src)
|
|
return 1
|
|
else
|
|
return 0
|
|
return 0
|
|
|
|
/obj/structure/grille/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume)
|
|
if(exposed_temperature > T0C + 1500)
|
|
health -= 1
|
|
healthcheck() //Note : This healthcheck is silent, and it's going to stay that way
|
|
..()
|
|
|
|
/obj/structure/grille/clockworkify()
|
|
var/our_glow = broken ? BROKEN_REPLICANT_GRILLE_GLOW : REPLICANT_GRILLE_GLOW
|
|
GENERIC_CLOCKWORK_CONVERSION(src, /obj/structure/grille/replicant, our_glow)
|
|
|
|
/obj/structure/grille/send_to_past(var/duration)
|
|
..()
|
|
var/static/list/resettable_vars = list(
|
|
"health",
|
|
"broken")
|
|
|
|
reset_vars_after_duration(resettable_vars, duration)
|
|
|
|
/obj/structure/grille/AltClick(var/mob/user)
|
|
var/turf/T = loc
|
|
if (istype(T))
|
|
if (user.listed_turf == T)
|
|
user.listed_turf = null
|
|
else
|
|
user.listed_turf = T
|
|
user.client.statpanel = T.name
|
|
|
|
//Mapping entities and alternatives !
|
|
|
|
/obj/structure/grille/broken //THIS IS ONLY TO BE USED FOR MAPPING, THANK YOU FOR YOUR UNDERSTANDING
|
|
|
|
//We need to set all variables for broken grilles manually, notably to have those show up nicely in mapmaker
|
|
icon_state = "grille0-b"
|
|
broken = 1
|
|
density = 0 //Not blocking anything anymore
|
|
|
|
/obj/structure/grille/broken/New()
|
|
..()
|
|
health -= rand(initial(health)*0.8, initial(health)*0.9) //Largely under broken threshold, this is used to adjust the health, NOT to break it
|
|
healthcheck() //Send this to healthcheck just in case we want to do something else with it
|
|
|
|
/obj/structure/grille/broken/healthcheck(var/hitsound = 0) //needed because initial icon_state for broken is grille-b for mapping
|
|
..()
|
|
if(broken)
|
|
icon_state = "grille-b"
|
|
else
|
|
icon_state = "grille"
|
|
|
|
/obj/structure/grille/cult //Used to get rid of those ugly fucking walls everywhere while still blocking air
|
|
|
|
name = "cult grille"
|
|
desc = "A matrix 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
|
|
|
|
/obj/structure/grille/cult/Cross(atom/movable/mover, turf/target, height = 1.5, air_group = 0)
|
|
if(air_group || !broken)
|
|
return 0 //Make sure air doesn't drain
|
|
return ..()
|
|
|
|
/obj/structure/grille/cult/relativewall()
|
|
return
|
|
|
|
/obj/structure/grille/invulnerable
|
|
desc = "A reinforced grille made with advanced alloys and techniques. It's impossible to break one without the use of heavy machinery."
|
|
|
|
/obj/structure/grille/invulnerable/healthcheck(hitsound)
|
|
return
|
|
|
|
/obj/structure/grille/invulnerable/ex_act()
|
|
return
|
|
|
|
/obj/structure/grille/invulnerable/attackby()
|
|
return
|
|
|
|
/obj/structure/grille/replicant
|
|
name = "replicant grille"
|
|
desc = "A strangely-shaped grille."
|
|
icon_state = "replicantgrille"
|
|
health = 30
|
|
grille_material = /obj/item/stack/sheet/ralloy
|
|
|
|
/obj/structure/grille/replicant/cultify()
|
|
return
|
|
|
|
/obj/structure/grille/replicant/clockworkify()
|
|
return
|
|
|
|
/obj/structure/grille/replicant/relativewall()
|
|
return |