mirror of
https://github.com/CHOMPStation2/CHOMPStation2.git
synced 2025-12-31 12:33:37 +00:00
Windows and doors will display messages indicating extant of damage as they are damaged (e.g. "Cracks begin to appear in [src]!") Metal rods can substitute for crowbars to force unpowered and broken doors, as well as firelocks. Window damage code cleaned up and centralized.
436 lines
13 KiB
Plaintext
436 lines
13 KiB
Plaintext
/obj/structure/window
|
|
name = "window"
|
|
desc = "A window."
|
|
icon = 'icons/obj/structures.dmi'
|
|
density = 1
|
|
layer = 3.2//Just above doors
|
|
pressure_resistance = 4*ONE_ATMOSPHERE
|
|
anchored = 1.0
|
|
flags = ON_BORDER
|
|
var/maxhealth = 14.0
|
|
var/health
|
|
var/ini_dir = null
|
|
var/state = 2
|
|
var/reinf = 0
|
|
var/basestate
|
|
var/shardtype = /obj/item/weapon/shard
|
|
// var/silicate = 0 // number of units of silicate
|
|
// var/icon/silicateIcon = null // the silicated icon
|
|
|
|
|
|
/obj/structure/window/proc/take_damage(var/damage = 0, var/sound_effect = 1)
|
|
var/initialhealth = src.health
|
|
src.health = max(0, src.health - damage)
|
|
if(src.health <= 0)
|
|
src.shatter()
|
|
else
|
|
if(sound_effect)
|
|
playsound(loc, 'sound/effects/Glasshit.ogg', 100, 1)
|
|
if(src.health < src.maxhealth / 4 && initialhealth >= src.maxhealth / 4)
|
|
visible_message("[src] looks like it's about to shatter!" )
|
|
else if(src.health < src.maxhealth / 2 && initialhealth >= src.maxhealth / 2)
|
|
visible_message("[src] looks seriously damaged!" )
|
|
else if(src.health < src.maxhealth * 3/4 && initialhealth >= src.maxhealth * 3/4)
|
|
visible_message("Cracks begin to appear in [src]!" )
|
|
return
|
|
|
|
/obj/structure/window/proc/shatter(var/display_message = 1)
|
|
playsound(src, "shatter", 70, 1)
|
|
if(display_message)
|
|
visible_message("[src] shatters!")
|
|
if(dir == SOUTHWEST)
|
|
var/index = null
|
|
index = 0
|
|
while(index < 2)
|
|
new shardtype(loc)
|
|
if(reinf) new /obj/item/stack/rods(loc)
|
|
index++
|
|
else
|
|
new shardtype(loc)
|
|
if(reinf) new /obj/item/stack/rods(loc)
|
|
del(src)
|
|
return
|
|
|
|
|
|
/obj/structure/window/bullet_act(var/obj/item/projectile/Proj)
|
|
|
|
//Tasers and the like should not damage windows.
|
|
if(Proj.damage_type == HALLOSS)
|
|
return
|
|
|
|
..()
|
|
take_damage(Proj.damage * 4)
|
|
return
|
|
|
|
|
|
/obj/structure/window/ex_act(severity)
|
|
switch(severity)
|
|
if(1.0)
|
|
del(src)
|
|
return
|
|
if(2.0)
|
|
shatter(0)
|
|
return
|
|
if(3.0)
|
|
if(prob(50))
|
|
shatter(0)
|
|
return
|
|
|
|
|
|
/obj/structure/window/blob_act()
|
|
shatter()
|
|
|
|
|
|
/obj/structure/window/meteorhit()
|
|
shatter()
|
|
|
|
|
|
/obj/structure/window/CanPass(atom/movable/mover, turf/target, height=0, air_group=0)
|
|
if(istype(mover) && mover.checkpass(PASSGLASS))
|
|
return 1
|
|
if(dir == SOUTHWEST || dir == SOUTHEAST || dir == NORTHWEST || dir == NORTHEAST)
|
|
return 0 //full tile window, you can't move into it!
|
|
if(get_dir(loc, target) == dir)
|
|
return !density
|
|
else
|
|
return 1
|
|
|
|
|
|
/obj/structure/window/CheckExit(atom/movable/O as mob|obj, target as turf)
|
|
if(istype(O) && O.checkpass(PASSGLASS))
|
|
return 1
|
|
if(get_dir(O.loc, target) == dir)
|
|
return 0
|
|
return 1
|
|
|
|
|
|
/obj/structure/window/hitby(AM as mob|obj)
|
|
..()
|
|
visible_message("<span class='danger'>[src] was hit by [AM].</span>")
|
|
var/tforce = 0
|
|
if(ismob(AM))
|
|
tforce = 40
|
|
else if(isobj(AM))
|
|
var/obj/item/I = AM
|
|
tforce = I.throwforce
|
|
if(reinf) tforce *= 0.25
|
|
if(health - tforce <= 7 && !reinf)
|
|
anchored = 0
|
|
update_nearby_icons()
|
|
step(src, get_dir(AM, src))
|
|
take_damage(tforce)
|
|
|
|
/obj/structure/window/attack_tk(mob/user as mob)
|
|
user.visible_message("<span class='notice'>Something knocks on [src].</span>")
|
|
playsound(loc, 'sound/effects/Glasshit.ogg', 50, 1)
|
|
|
|
/obj/structure/window/attack_hand(mob/user as mob)
|
|
if(HULK in user.mutations)
|
|
user.say(pick(";RAAAAAAAARGH!", ";HNNNNNNNNNGGGGGGH!", ";GWAAAAAAAARRRHHH!", "NNNNNNNNGGGGGGGGHH!", ";AAAAAAARRRGH!"))
|
|
user.visible_message("<span class='danger'>[user] smashes through [src]!</span>")
|
|
shatter()
|
|
|
|
else if (usr.a_intent == "hurt")
|
|
|
|
if (istype(usr,/mob/living/carbon/human))
|
|
var/mob/living/carbon/human/H = usr
|
|
if(H.species.can_shred(H))
|
|
attack_generic(H,25)
|
|
return
|
|
|
|
playsound(src.loc, 'sound/effects/glassknock.ogg', 80, 1)
|
|
usr.visible_message("\red [usr.name] bangs against the [src.name]!", \
|
|
"\red You bang against the [src.name]!", \
|
|
"You hear a banging sound.")
|
|
else
|
|
playsound(src.loc, 'sound/effects/glassknock.ogg', 80, 1)
|
|
usr.visible_message("[usr.name] knocks on the [src.name].", \
|
|
"You knock on the [src.name].", \
|
|
"You hear a knocking sound.")
|
|
return
|
|
|
|
|
|
/obj/structure/window/attack_paw(mob/user as mob)
|
|
return attack_hand(user)
|
|
|
|
|
|
/obj/structure/window/proc/attack_generic(mob/user as mob, damage = 0) //used by attack_animal and attack_slime
|
|
user.visible_message("<span class='danger'>[user] smashes into [src]!</span>")
|
|
take_damage(damage)
|
|
|
|
/obj/structure/window/attack_animal(mob/user as mob)
|
|
if(!isanimal(user)) return
|
|
var/mob/living/simple_animal/M = user
|
|
if(M.melee_damage_upper <= 0) return
|
|
attack_generic(M, M.melee_damage_upper)
|
|
|
|
|
|
/obj/structure/window/attack_slime(mob/user as mob)
|
|
var/mob/living/carbon/slime/S = user
|
|
if (!S.is_adult)
|
|
return
|
|
attack_generic(user, rand(10, 15))
|
|
|
|
|
|
/obj/structure/window/attackby(obj/item/W as obj, mob/user as mob)
|
|
if(!istype(W)) return//I really wish I did not need this
|
|
if(W.flags & NOBLUDGEON) return
|
|
|
|
if (istype(W, /obj/item/weapon/grab) && get_dist(src,user)<2)
|
|
var/obj/item/weapon/grab/G = W
|
|
if (istype(G.affecting, /mob/living))
|
|
var/mob/living/M = G.affecting
|
|
var/state = G.state
|
|
del(W) //gotta delete it here because if window breaks, it won't get deleted
|
|
switch (state)
|
|
if(1)
|
|
M.apply_damage(7)
|
|
hit(10)
|
|
visible_message("\red [user] slams [M] against \the [src]!")
|
|
if(2)
|
|
if (prob(50))
|
|
M.Weaken(1)
|
|
M.apply_damage(10)
|
|
hit(25)
|
|
visible_message("\red <b>[user] bashes [M] against \the [src]!</b>")
|
|
if(3)
|
|
M.Weaken(5)
|
|
M.apply_damage(20)
|
|
hit(50)
|
|
visible_message("\red <big><b>[user] crushes [M] against \the [src]!</b></big>")
|
|
return
|
|
if(istype(W, /obj/item/weapon/screwdriver))
|
|
if(reinf && state >= 1)
|
|
state = 3 - state
|
|
playsound(loc, 'sound/items/Screwdriver.ogg', 75, 1)
|
|
user << (state == 1 ? "<span class='notice'>You have unfastened the window from the frame.</span>" : "<span class='notice'>You have fastened the window to the frame.</span>")
|
|
else if(reinf && state == 0)
|
|
anchored = !anchored
|
|
update_nearby_icons()
|
|
playsound(loc, 'sound/items/Screwdriver.ogg', 75, 1)
|
|
user << (anchored ? "<span class='notice'>You have fastened the frame to the floor.</span>" : "<span class='notice'>You have unfastened the frame from the floor.</span>")
|
|
else if(!reinf)
|
|
anchored = !anchored
|
|
update_nearby_icons()
|
|
playsound(loc, 'sound/items/Screwdriver.ogg', 75, 1)
|
|
user << (anchored ? "<span class='notice'>You have fastened the window to the floor.</span>" : "<span class='notice'>You have unfastened the window.</span>")
|
|
else if(istype(W, /obj/item/weapon/crowbar) && reinf && state <= 1)
|
|
state = 1 - state
|
|
playsound(loc, 'sound/items/Crowbar.ogg', 75, 1)
|
|
user << (state ? "<span class='notice'>You have pried the window into the frame.</span>" : "<span class='notice'>You have pried the window out of the frame.</span>")
|
|
else
|
|
if(W.damtype == BRUTE || W.damtype == BURN)
|
|
hit(W.force)
|
|
if(health <= 7)
|
|
anchored = 0
|
|
update_nearby_icons()
|
|
step(src, get_dir(user, src))
|
|
else
|
|
playsound(loc, 'sound/effects/Glasshit.ogg', 75, 1)
|
|
..()
|
|
return
|
|
|
|
/obj/structure/window/proc/hit(var/damage, var/sound_effect = 1)
|
|
if(reinf) damage *= 0.5
|
|
take_damage(damage)
|
|
return
|
|
|
|
|
|
/obj/structure/window/verb/rotate()
|
|
set name = "Rotate Window Counter-Clockwise"
|
|
set category = "Object"
|
|
set src in oview(1)
|
|
|
|
if(anchored)
|
|
usr << "It is fastened to the floor therefore you can't rotate it!"
|
|
return 0
|
|
|
|
update_nearby_tiles(need_rebuild=1) //Compel updates before
|
|
dir = turn(dir, 90)
|
|
// updateSilicate()
|
|
update_nearby_tiles(need_rebuild=1)
|
|
ini_dir = dir
|
|
return
|
|
|
|
|
|
/obj/structure/window/verb/revrotate()
|
|
set name = "Rotate Window Clockwise"
|
|
set category = "Object"
|
|
set src in oview(1)
|
|
|
|
if(anchored)
|
|
usr << "It is fastened to the floor therefore you can't rotate it!"
|
|
return 0
|
|
|
|
update_nearby_tiles(need_rebuild=1) //Compel updates before
|
|
dir = turn(dir, 270)
|
|
// updateSilicate()
|
|
update_nearby_tiles(need_rebuild=1)
|
|
ini_dir = dir
|
|
return
|
|
|
|
|
|
/*
|
|
/obj/structure/window/proc/updateSilicate()
|
|
if(silicateIcon && silicate)
|
|
icon = initial(icon)
|
|
|
|
var/icon/I = icon(icon,icon_state,dir)
|
|
|
|
var/r = (silicate / 100) + 1
|
|
var/g = (silicate / 70) + 1
|
|
var/b = (silicate / 50) + 1
|
|
I.SetIntensity(r,g,b)
|
|
icon = I
|
|
silicateIcon = I
|
|
*/
|
|
|
|
|
|
/obj/structure/window/New(Loc,re=0)
|
|
..()
|
|
|
|
// if(re) reinf = re
|
|
|
|
health = maxhealth
|
|
|
|
ini_dir = dir
|
|
|
|
update_nearby_tiles(need_rebuild=1)
|
|
update_nearby_icons()
|
|
|
|
return
|
|
|
|
|
|
/obj/structure/window/Del()
|
|
density = 0
|
|
update_nearby_tiles()
|
|
update_nearby_icons()
|
|
..()
|
|
|
|
|
|
/obj/structure/window/Move()
|
|
update_nearby_tiles(need_rebuild=1)
|
|
..()
|
|
dir = ini_dir
|
|
update_nearby_tiles(need_rebuild=1)
|
|
|
|
|
|
//This proc has to do with airgroups and atmos, it has nothing to do with smoothwindows, that's update_nearby_tiles().
|
|
/obj/structure/window/proc/update_nearby_tiles(need_rebuild)
|
|
if(!air_master)
|
|
return 0
|
|
air_master.mark_for_update(get_turf(src))
|
|
|
|
return 1
|
|
|
|
//checks if this window is full-tile one
|
|
/obj/structure/window/proc/is_fulltile()
|
|
if(dir & (dir - 1))
|
|
return 1
|
|
return 0
|
|
|
|
//This proc is used to update the icons of nearby windows. It should not be confused with update_nearby_tiles(), which is an atmos proc!
|
|
/obj/structure/window/proc/update_nearby_icons()
|
|
update_icon()
|
|
for(var/direction in cardinal)
|
|
for(var/obj/structure/window/W in get_step(src,direction) )
|
|
W.update_icon()
|
|
|
|
//merges adjacent full-tile windows into one (blatant ripoff from game/smoothwall.dm)
|
|
/obj/structure/window/update_icon()
|
|
//A little cludge here, since I don't know how it will work with slim windows. Most likely VERY wrong.
|
|
//this way it will only update full-tile ones
|
|
//This spawn is here so windows get properly updated when one gets deleted.
|
|
spawn(2)
|
|
if(!src) return
|
|
if(!is_fulltile())
|
|
icon_state = "[basestate]"
|
|
return
|
|
var/junction = 0 //will be used to determine from which side the window is connected to other windows
|
|
if(anchored)
|
|
for(var/obj/structure/window/W in orange(src,1))
|
|
if(W.anchored && W.density && W.is_fulltile()) //Only counts anchored, not-destroyed fill-tile windows.
|
|
if(abs(x-W.x)-abs(y-W.y) ) //doesn't count windows, placed diagonally to src
|
|
junction |= get_dir(src,W)
|
|
if(opacity)
|
|
icon_state = "[basestate][junction]"
|
|
else
|
|
if(reinf)
|
|
icon_state = "[basestate][junction]"
|
|
else
|
|
icon_state = "[basestate][junction]"
|
|
|
|
return
|
|
|
|
/obj/structure/window/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume)
|
|
if(exposed_temperature > T0C + 800)
|
|
hit(round(exposed_volume / 100), 0)
|
|
..()
|
|
|
|
|
|
|
|
/obj/structure/window/basic
|
|
desc = "It looks thin and flimsy. A few knocks with... anything, really should shatter it."
|
|
icon_state = "window"
|
|
basestate = "window"
|
|
|
|
/obj/structure/window/phoronbasic
|
|
name = "phoron window"
|
|
desc = "A phoron-glass alloy window. It looks insanely tough to break. It appears it's also insanely tough to burn through."
|
|
basestate = "phoronwindow"
|
|
icon_state = "phoronwindow"
|
|
shardtype = /obj/item/weapon/shard/phoron
|
|
maxhealth = 120
|
|
|
|
/obj/structure/window/phoronbasic/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume)
|
|
if(exposed_temperature > T0C + 32000)
|
|
hit(round(exposed_volume / 1000), 0)
|
|
..()
|
|
|
|
/obj/structure/window/phoronreinforced
|
|
name = "reinforced phoron window"
|
|
desc = "A phoron-glass alloy window, with rods supporting it. It looks hopelessly tough to break. It also looks completely fireproof, considering how basic phoron windows are insanely fireproof."
|
|
basestate = "phoronrwindow"
|
|
icon_state = "phoronrwindow"
|
|
shardtype = /obj/item/weapon/shard/phoron
|
|
reinf = 1
|
|
maxhealth = 160
|
|
|
|
/obj/structure/window/phoronreinforced/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume)
|
|
return
|
|
|
|
/obj/structure/window/reinforced
|
|
name = "reinforced window"
|
|
desc = "It looks rather strong. Might take a few good hits to shatter it."
|
|
icon_state = "rwindow"
|
|
basestate = "rwindow"
|
|
maxhealth = 40
|
|
reinf = 1
|
|
|
|
/obj/structure/window/reinforced/tinted
|
|
name = "tinted window"
|
|
desc = "It looks rather strong and opaque. Might take a few good hits to shatter it."
|
|
icon_state = "twindow"
|
|
basestate = "twindow"
|
|
opacity = 1
|
|
|
|
/obj/structure/window/reinforced/tinted/frosted
|
|
name = "frosted window"
|
|
desc = "It looks rather strong and frosted over. Looks like it might take a few less hits then a normal reinforced window."
|
|
icon_state = "fwindow"
|
|
basestate = "fwindow"
|
|
maxhealth = 30
|
|
|
|
/obj/structure/window/shuttle
|
|
name = "shuttle window"
|
|
desc = "It looks rather strong. Might take a few good hits to shatter it."
|
|
icon = 'icons/obj/podwindows.dmi'
|
|
icon_state = "window"
|
|
basestate = "window"
|
|
maxhealth = 40
|
|
reinf = 1
|
|
dir = 5
|
|
|
|
update_icon() //icon_state has to be set manually
|
|
return
|