Files
FenodyreeAv cf585ef505 Ship combat rework (#22566)
Makes ship combat significantly more destructive (and a bit deadlier),
especially with non-explosive projectiles.

**Additions:**
- A shell that penetrates a solid (dense) structure will cause spalling.
This spall does 2-30 damage, depending on range and has a high embed
chance. These embedded chunks are large enough to be ripped out by hand.
(But you probably shouldn't). The pilot's suit has 30 ballistic armor,
so a prepared bridge crew can survive a lot of spall.
- Adds a gun that shoots any ship weapon that admins can spawn. Useful
for testing, or for adminbus where they don't want to have to spawn a
whole overmap ship.
- Made several structures destructible, vending machines, computer
frames, grilles (these were just bugged) and watertanks (and their
children). These structures could just block infinite shots and were
common enough to serve as effective armor for the horizon. These now
spawn shrapnel (of their material if it's set), in addition to sheets of
steel when destroyed.
- Added support for negative maim chance. This allows chosen projectiles
to be prevented from decapitating. No more accidentally gibbing the
bridge crew's heads. (Unless they get hit with something really really
big).

**Balance:**
- All non-explosive anti ship rounds got significant buffs. Typically
2-3x Anti-Material numbers.
- Armour piercing anti-ship rounds got massively increased penetration
stats. Typically 4-8 from 1-2.
- Doors now get destroyed in less hits, if they are hit by anti-material
projectiles. Hits to destroy -= Antimaterial / 2
- Francisca frag shells now shoot less fragments but deal more damage.
394 projectiles for every shot was a bit laggy, now it's only 280.

**Shields:**
Shields now take more power. 13-14 megawatts for a 10 strength shield.
Just inside the ship's generation capacity with both the INDRA and
Supermatter running.

Instead of deleting any projectile they are hit by, shields now have
different failure modes.
- Firstly, a piercing projectile has it's penetration reduced by the
shield strength. Eg A shot that would go through 10 walls, only
penetrates 4 after going through a 6 strength shield.
- Secondly, a projectile has it's damage multiplied by 1 - shield
strength / 10, then has shield strength subtracted from it's damage. Eg.
A damage 100 projectile, hitting a 5 strength shield, has it's damaged
reduced to 50, (100 * 0.5), then to 45. (50-5)
- Thirdly, an explosive projectile (that does not penetrate per the
first step) does not explode, but instead deals it's full damage to the
shield.

Hits to the shield now also damage the field itself, not just the shield
tile. As such, a very big hit on the shield can bring the whole thing
down, requiring an engineer to reset it.

Shields can now be upgraded with research components. Additionally,
shield generators can now support more than one capacitor. The
roundstart capacitor on the Horizon is only good enough to support a 6
strength shield.
The upgrades increase efficiency, strength loss over time and charge
speed.

**Overmap Targetting**
Previously, shells would spawn within 20 tiles of their target and aim
directly forwards. This was bugged for shots with burst, which would
instead all aim inwards and mostly miss. This is the reason the Grauwolf
(in addition to the explosion bug below) and Fransisca felt so useless,
only one of every shell in a burst would hit.

Shots now spawn at the map edge, based on the orientation of the
projectile and ship. Diagonals are now accounted for.
Shots are then aimed directly at the target selected on the console,
with 3 degrees of dispersion.

**Bugfixes:**
- Fixes lots of explosions that didn't pass a turf to the explosions
subsystem. This caused the explosion not to happen if the thing hit got
qdeled before the subsystem could get the turf to spawn the explosion
on.
- Embedded shrapnel no longer gets the initial projectile name, this
prevents it getting named shrapnelshrapnel.
- Fixes a bunch of projectile piercing bugs, mostly with grilles and
windows. Shots now go past window frames without hitting them.
- Fixes shields not having a click delay when attacked.

---------

Signed-off-by: FenodyreeAv <fenodyree.av@gmail.com>
Co-authored-by: Matt Atlas <mattiathebest2000@hotmail.it>
2026-06-03 16:52:13 +00:00

815 lines
25 KiB
Plaintext

/obj/structure/window
name = "glass pane"
desc = "A glass pane."
icon = 'icons/obj/structure/window/window_panes.dmi'
icon_state = "window"
alpha = 196
density = TRUE
pass_flags_self = PASSWINDOW
w_class = WEIGHT_CLASS_NORMAL
layer = OBJ_LAYER
anchored = TRUE
atom_flags = ATOM_FLAG_CHECKS_BORDER
obj_flags = OBJ_FLAG_ROTATABLE|OBJ_FLAG_MOVES_UNSUPPORTED
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/ini_dir = null
var/state = 2
var/reinf = FALSE
var/basestate
var/shardtype = /obj/item/material/shard
var/glasstype = null // Set this in subtypes. Null is assumed strange or otherwise impossible to dismantle, such as for shuttle glass.
var/silicate = 0 // number of units of silicate
var/base_frame = null
var/full = FALSE
atmos_canpass = CANPASS_PROC
/obj/structure/window/get_damage_condition_hints(mob/user, distance, is_adjacent)
if(health == maxhealth)
. = SPAN_NOTICE("It looks fully intact.")
else
var/perc = health / maxhealth
if(perc > 0.75)
. = SPAN_NOTICE("It has a few cracks.")
else if(perc > 0.5)
. = SPAN_WARNING("It looks slightly damaged.")
else if(perc > 0.25)
. = SPAN_WARNING("It looks moderately damaged.")
else
. = SPAN_DANGER("It looks heavily damaged.")
if(silicate)
if (silicate < 30)
. = SPAN_NOTICE("It has a thin layer of silicate.")
else if (silicate < 70)
. = SPAN_NOTICE("It is covered in silicate.")
else
. = SPAN_NOTICE("There is a thick layer of silicate covering it.")
/obj/structure/window/proc/update_nearby_icons()
QUEUE_SMOOTH_NEIGHBORS(src)
/obj/structure/window/update_icon()
if(!full)
if(dir == SOUTH)
layer = ABOVE_HUMAN_LAYER
QUEUE_SMOOTH(src)
/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.
add_health(amount * 3)
if(health == maxhealth)
visible_message(SPAN_NOTICE("The silicate fully mends the damage on \the [src]."))
else // Reinforce.
silicate = min(silicate + amount, 100)
updateSilicate()
/obj/structure/window/proc/updateSilicate()
ClearOverlays()
var/image/img = image(icon, icon_state)
img.color = "#ffffff"
img.alpha = silicate * 255 / 100
AddOverlays(img)
/obj/structure/window/proc/shatter(var/display_message = 1)
playsound(src, SFX_BREAK_GLASS, 70, 1)
if(display_message)
visible_message(SPAN_WARNING("\The [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)
if(base_frame)
if(prob(50))
var/obj/F = new base_frame(loc)
F.anchored = anchored
else
new /obj/item/material/shard/shrapnel(loc)
qdel(src)
return
/obj/structure/window/bullet_act(obj/projectile/hitting_projectile, def_zone, piercing_hit)
var/proj_damage = hitting_projectile.get_structure_damage()
if(!proj_damage)
return BULLET_ACT_BLOCK
. = ..()
if(. != BULLET_ACT_HIT)
return .
add_damage(proj_damage, hitting_projectile.damage_flags(), hitting_projectile.damage_type, hitting_projectile.armor_penetration, hitting_projectile)
/obj/structure/window/ex_act(severity)
switch(severity)
if(1)
qdel(src)
if(2)
shatter(0)
if(3)
if(prob(50))
shatter(0)
else
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()
return (dir == SOUTHWEST || dir == SOUTHEAST || dir == NORTHWEST || dir == NORTHEAST)
/obj/structure/window/CanPass(atom/movable/mover, turf/target, height=0, air_group=0)
if(mover?.movement_type & PHASING)
return TRUE
if(istype(mover) && mover.pass_flags & PASSGLASS)
return TRUE
if(is_full_window())
return !density //full tile window, you can't move into it if it's solid!
var/movingdir = get_dir(loc,target)
if(movingdir == 0)
movingdir = get_dir(loc,mover)
if(movingdir & dir)
return !density
else
return TRUE
/obj/structure/window/CheckExit(atom/movable/O, turf/target)
if(istype(O) && O.pass_flags & PASSGLASS)
return 1
if(get_dir(O.loc, target) == dir)
return 0
return 1
/obj/structure/window/hitby(atom/movable/hitting_atom, skipcatch, hitpush, blocked, datum/thrownthing/throwingdatum)
..()
var/tforce = 0
if(ismob(hitting_atom))
if(isliving(hitting_atom))
var/mob/living/M = hitting_atom
M.turf_collision(src, throwingdatum.speed, SFX_GLASS_CRACK)
return
else
visible_message(SPAN_DANGER("\The [src] was hit by \the [hitting_atom]."))
tforce = 40
else if(isobj(hitting_atom))
visible_message(SPAN_DANGER("\The [src] was hit by \the [hitting_atom]."))
var/obj/item/I = hitting_atom
tforce = I.throwforce
if(reinf)
tforce *= 0.25
add_damage(tforce)
/obj/structure/window/attack_hand(var/mob/living/user)
user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
if((user.mutations & HULK) && !(user.isSynthetic()) && !(isvaurca(user)))
user.say(pick(";RAAAAAAAARGH!", ";HNNNNNNNNNGGGGGGH!", ";GWAAAAAAAARRRHHH!", "NNNNNNNNGGGGGGGGHH!", ";AAAAAAARRRGH!"))
user.visible_message(SPAN_DANGER("[user] smashes through [src]!"))
user.do_attack_animation(src)
shatter()
else if (user.a_intent == I_HURT)
if(ishuman(user))
var/mob/living/carbon/human/H = user
if(H.species.can_shred(H) || (H.is_berserk()))
attack_generic(H,25)
return
playsound(src.loc, 'sound/effects/glass_knock.ogg', 90, 1)
user.do_attack_animation(src)
user.visible_message(SPAN_DANGER("\The [user] bangs against \the [src]!"),
SPAN_DANGER("You bang against \the [src]!"),
"You hear a banging sound.")
else
playsound(src.loc, 'sound/effects/glass_knock.ogg', 60, 1)
user.visible_message("<b>[user]</b> knocks on \the [src.name].",
"You knock on \the [src.name].",
"You hear a knocking sound.")
return
/obj/structure/window/attack_generic(mob/user, damage, attack_message, environment_smash, armor_penetration, attack_flags, damage_type)
user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
if(damage >= 10)
visible_message(SPAN_DANGER("[user] smashes into [src]!"))
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)
user.do_attack_animation(src)
return 1
/obj/structure/window/do_simple_ranged_interaction(var/mob/user)
visible_message(SPAN_NOTICE("Something knocks on \the [src]."))
playsound(loc, 'sound/effects/glass_hit.ogg', 50, 1)
return TRUE
/obj/structure/window/attackby(obj/item/attacking_item, mob/user)
if(!istype(attacking_item) || istype(attacking_item, /obj/item/flag))
return
// Slamming someone against the window interaction
if(istype(attacking_item, /obj/item/grab) && get_dist(src,user)<2)
var/obj/item/grab/G = attacking_item
if(istype(G.affecting, /mob/living))
grab_smash_attack(G, DAMAGE_BRUTE)
return
if(attacking_item.item_flags & ITEM_FLAG_NO_BLUDGEON)
return
if(handle_construction(attacking_item, user))
return
. = ..()
/obj/structure/window/proc/handle_construction(obj/item/attacking_item, mob/user)
// Screwdriver
if(attacking_item.tool_behaviour == TOOL_SCREWDRIVER && user.a_intent != I_HURT)
if(reinf && state >= 1)
state = 3 - state
update_nearby_icons()
attacking_item.play_tool_sound(get_turf(src), 75)
to_chat(user, (state == 1 ? SPAN_NOTICE("You have unfastened the window from the frame.") : SPAN_NOTICE("You have fastened the window to the frame.")))
else if(reinf && state == 0)
anchored = !anchored
update_icon()
update_nearby_icons()
attacking_item.play_tool_sound(get_turf(src), 75)
to_chat(user, (anchored ? SPAN_NOTICE("You have fastened the frame to the floor.") : SPAN_NOTICE("You have unfastened the frame from the floor.")))
else
anchored = !anchored
update_nearby_icons()
attacking_item.play_tool_sound(get_turf(src), 75)
to_chat(user, (anchored ? SPAN_NOTICE("You have fastened the window to the floor.") : SPAN_NOTICE("You have unfastened the window.")))
update_icon()
update_nearby_icons()
return TRUE
// Crowbar
else if(attacking_item.tool_behaviour == TOOL_CROWBAR && reinf && state <= 1 && user.a_intent != I_HURT)
state = 1 - state
attacking_item.play_tool_sound(get_turf(src), 75)
to_chat(user, (state ? SPAN_NOTICE("You have pried the window into the frame.") : SPAN_NOTICE("You have pried the window out of the frame.")))
return TRUE
// Wrench
else if(attacking_item.tool_behaviour == TOOL_WRENCH && !anchored && (!state || !reinf) && user.a_intent != I_HURT)
if(!glasstype)
to_chat(user, SPAN_NOTICE("You're not sure how to dismantle \the [src] properly."))
else
visible_message(SPAN_NOTICE("[user] dismantles \the [src]."))
dismantle_window()
return TRUE
return FALSE
/obj/structure/window/proc/grab_smash_attack(obj/item/grab/G, var/damtype = DAMAGE_BRUTE)
var/mob/living/M = G.affecting
var/mob/living/user = G.assailant
var/state = G.state
qdel(G) //gotta delete it here because if window breaks, it won't get deleted
var/def_zone = ran_zone(BP_HEAD, 20)
switch (state)
if(1)
M.visible_message(SPAN_WARNING("[user] slams [M] against \the [src]!"))
M.apply_damage(7, damtype, def_zone, used_weapon = src)
hit(10)
if(2)
M.visible_message(SPAN_DANGER("[user] bashes [M] against \the [src]!"))
if (prob(50))
M.Weaken(1)
M.apply_damage(10, damtype, def_zone, used_weapon = src)
hit(25)
if(3)
M.visible_message(SPAN_DANGER("<big>[user] crushes [M] against \the [src]!</big>"))
M.Weaken(5)
M.apply_damage(20, damtype, def_zone, used_weapon = src)
hit(50)
/obj/structure/window/proc/hit(var/damage, var/sound_effect = 1)
if(reinf)
damage *= 0.5
add_damage(damage)
/obj/structure/window/proc/dismantle_window()
if(dir == SOUTHWEST)
var/obj/item/stack/material/mats = new glasstype(loc)
mats.amount = is_fulltile() ? 4 : 2
else
new glasstype(loc)
qdel(src)
/obj/structure/window/Initialize(mapload, start_dir = null, constructed = 0)
. = ..()
if(!full && constructed)
anchored = FALSE
if (!mapload && constructed)
state = 0
if (start_dir)
set_dir(start_dir)
ini_dir = dir
update_nearby_tiles(need_rebuild=1)
update_nearby_icons()
update_icon()
/obj/structure/window/Destroy()
density = 0
update_nearby_tiles()
var/turf/location = loc
loc = null
for(var/obj/structure/window/W in orange(location, 1))
W.update_icon()
for(var/obj/structure/table/T in view(location, 1))
T.update_connections()
T.update_icon()
loc = location
return ..()
/obj/structure/window/Move()
var/ini_dir = dir
var/oldloc = loc
update_nearby_tiles(need_rebuild=1)
. = ..()
set_dir(ini_dir)
update_nearby_tiles(need_rebuild=1)
if(loc != oldloc)
for(var/obj/structure/table/T in view(oldloc, 1) | view(loc, 1))
T.update_connections()
T.update_icon()
/obj/structure/window/proc/is_fulltile() // Checks if this window is a full-tile one.
if(dir & (dir - 1))
return 1
return 0
/obj/structure/window/fire_act(exposed_temperature, exposed_volume)
if(exposed_temperature > maximal_heat)
hit(damage_per_fire_tick, 0)
..()
/********** Glass and Glass Panes **********/
/obj/structure/window/basic
name = "glass pane"
desc = "It looks thin and flimsy. A few hits with anything will shatter it."
icon_state = "window"
basestate = "window"
glasstype = /obj/item/stack/material/glass
maximal_heat = T0C + 100
damage_per_fire_tick = 2
maxhealth = OBJECT_HEALTH_FRAGILE
/obj/structure/window/basic/full
name = "glass"
icon_state = "window"
dir = 5
/obj/structure/window/reinforced
name = "reinforced glass pane"
desc = "It looks rather strong. Might take a few good hits to shatter it."
icon_state = "rwindow"
basestate = "rwindow"
maxhealth = OBJECT_HEALTH_LOW
reinf = TRUE
maximal_heat = T0C + 750
damage_per_fire_tick = 2
glasstype = /obj/item/stack/material/glass/reinforced
/obj/structure/window/reinforced/full
name = "reinforced glass"
icon_state = "rwindow"
dir = 5
/obj/structure/window/reinforced/tinted
name = "reinforced tinted glass pane"
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 = "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 = OBJECT_HEALTH_EXTREMELY_LOW
/obj/structure/window/reinforced/polarized
name = "reinforced electrochromic glass pane"
desc = "Adjusts its tint with voltage. Might take a few good hits to shatter it."
var/id
/obj/structure/window/reinforced/polarized/proc/toggle()
if(opacity)
animate(src, color="#FFFFFF", time=5)
set_opacity(0)
else
animate(src, color="#222222", time=5)
set_opacity(1)
/obj/structure/window/reinforced/crescent/attack_hand()
return
/obj/structure/window/reinforced/crescent/attackby()
return
/obj/structure/window/reinforced/crescent/ex_act(var/severity = 2)
return
/obj/structure/window/reinforced/crescent/hitby(atom/movable/hitting_atom, skipcatch, hitpush, blocked, datum/thrownthing/throwingdatum)
return
/obj/structure/window/reinforced/crescent/shatter()
return
/obj/structure/machinery/button/switch/windowtint
name = "window tint control"
desc = "A remote control switch for polarized windows."
var/range = 16
/obj/structure/machinery/button/switch/windowtint/update_icon()
icon_state = "light[active]"
/obj/structure/machinery/button/switch/windowtint/attack_hand(mob/user as mob)
if(..())
return TRUE
toggle_tint()
/obj/structure/machinery/button/switch/windowtint/proc/toggle_tint()
use_power_oneoff(5)
active = !active
update_icon()
for(var/obj/structure/window/reinforced/polarized/W in range(src, range))
if(W.id == src.id || !W.id)
W.toggle()
for(var/obj/structure/window/full/reinforced/polarized/W in range(src, range))
if(W.id == src.id || !W.id)
W.toggle()
/obj/structure/machinery/button/switch/windowtint/power_change()
..()
if(active && !powered(power_channel))
toggle_tint()
/obj/structure/window/borosilicate
name = "borosilicate glass pane"
desc = "A borosilicate alloy window. It seems to be quite strong."
color = GLASS_COLOR_PHORON
shardtype = /obj/item/material/shard/phoron
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 = OBJECT_HEALTH_VERY_LOW
/// Phoron-infused silicate
rad_resistance_modifier = 4
/obj/structure/window/borosilicate/reinforced
name = "reinforced borosilicate glass pane"
desc = "A borosilicate alloy window, with rods supporting it. It seems to be very strong."
color = GLASS_COLOR_PHORON_R
glasstype = /obj/item/stack/material/glass/phoronrglass
reinf = TRUE
maximal_heat = T0C + 4000
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 = OBJECT_HEALTH_HIGH
/********** Shuttle Windows **********/
/obj/structure/window/shuttle
name = "reinforced shuttle window"
desc = "It looks rather strong. Might take a few good hits to shatter it."
icon = 'icons/obj/smooth/shuttle_window.dmi'
icon_state = "shuttle_window"
basestate = "w"
atom_flags = 0
obj_flags = null
maxhealth = OBJECT_HEALTH_VERY_LOW
reinf = TRUE
dir = 5
smoothing_flags = SMOOTH_TRUE
can_be_unanchored = TRUE
layer = FULL_WINDOW_LAYER
rad_resistance_modifier = 4
/obj/structure/window/shuttle/mouse_drop_receive(atom/dropping, mob/user, params)
//Adds the component only once. We do it here & not in Initialize() because there are tons of walls & we don't want to add to their init times
LoadComponent(/datum/component/leanable, dropping)
/obj/structure/window/shuttle/legion
name = "reinforced cockpit window"
icon = 'icons/obj/smooth/shuttle_window_legion.dmi'
maxhealth = OBJECT_HEALTH_HIGH
/obj/structure/window/shuttle/palepurple
icon = 'icons/obj/smooth/shuttle_window_palepurple.dmi'
/obj/structure/window/shuttle/skrell
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'
maxhealth = OBJECT_HEALTH_VERY_HIGH
smoothing_flags = SMOOTH_MORE | SMOOTH_DIAGONAL
canSmoothWith = list(
/turf/simulated/wall/shuttle/skrell,
/obj/structure/window/shuttle/skrell
)
/obj/structure/window/shuttle/scc_space_ship
name = "advanced borosilicate alloy window"
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"
maxhealth = OBJECT_HEALTH_VERY_HIGH
alpha = 255
smoothing_flags = SMOOTH_MORE
canSmoothWith = list(
/obj/structure/window/shuttle/scc_space_ship,
/turf/simulated/wall/shuttle/scc_space_ship,
/turf/unsimulated/wall/shuttle/scc_space_ship
)
blend_overlay = "-wall"
attach_overlay = "attach"
can_blend_with = list(
/turf/simulated/wall/shuttle/scc_space_ship,
/turf/unsimulated/wall/shuttle/scc_space_ship,
/obj/structure/window/shuttle/scc_space_ship
)
/obj/structure/window/shuttle/scc_space_ship/cardinal
smoothing_flags = SMOOTH_MORE
/obj/structure/window/shuttle/scc_space_ship/cardinal_smooth(adjacencies, var/list/dir_mods)
dir_mods = handle_blending(adjacencies, dir_mods)
return ..(adjacencies, dir_mods)
/obj/structure/window/shuttle/scc
icon = 'icons/obj/smooth/scc_shuttle_window.dmi'
maxhealth = OBJECT_HEALTH_HIGH
/obj/structure/window/shuttle/crescent
desc = "It looks rather strong."
//
// Full Windows
//
/obj/structure/window/full
name = "window"
desc = "You aren't supposed to see this."
atom_flags = 0
obj_flags = null
dir = 5
maxhealth = OBJECT_HEALTH_EXTREMELY_LOW
glasstype = /obj/item/stack/material/glass
shardtype = /obj/item/material/shard
full = TRUE
layer = FULL_WINDOW_LAYER
base_frame = /obj/structure/window_frame
smoothing_flags = SMOOTH_MORE
canSmoothWith = list(
/turf/simulated/wall,
/turf/simulated/wall/r_wall,
/turf/unsimulated/wall/steel,
/turf/unsimulated/wall/darkshuttlewall,
/turf/unsimulated/wall/riveted,
/turf/unsimulated/wall/fakepdoor,
/obj/structure/window_frame,
/obj/structure/window_frame/unanchored,
/obj/structure/window_frame/empty,
/obj/structure/window/full/reinforced,
/obj/structure/window/full/reinforced/indestructible,
/obj/structure/window/full/reinforced/polarized,
/obj/structure/window/full/reinforced/polarized/indestructible,
/obj/structure/window/full/phoron/reinforced,
/obj/structure/window/shuttle/scc_space_ship,
/turf/simulated/wall/shuttle/scc_space_ship,
/obj/structure/machinery/door
)
blend_overlay = "wall"
attach_overlay = "attach"
can_blend_with = list(
/turf/simulated/wall,
/obj/structure/machinery/door,
/obj/structure/window_frame
)
/obj/structure/window/full/Destroy()
var/obj/structure/window_frame/WF = locate(/obj/structure/window_frame) in get_turf(src)
if(WF)
WF.has_glass_installed = FALSE
return ..()
/obj/structure/window/full/handle_construction(obj/item/attacking_item, mob/user)
if(attacking_item.tool_behaviour == TOOL_SCREWDRIVER && user.a_intent != I_HURT)
if(state == 2)
if(attacking_item.use_tool(src, user, 2 SECONDS, volume = 50))
to_chat(user, SPAN_NOTICE("You have unfastened the glass from the window frame."))
state--
update_nearby_icons()
return TRUE
else if(state == 1)
if(attacking_item.use_tool(src, user, 2 SECONDS, volume = 50))
to_chat(user, SPAN_NOTICE("You have fastened the glass to the window frame."))
state++
update_nearby_icons()
return TRUE
else if(attacking_item.tool_behaviour == TOOL_CROWBAR && user.a_intent != I_HURT)
if(state == 1)
if(attacking_item.use_tool(src, user, 2 SECONDS, volume = 50))
to_chat(user, SPAN_NOTICE("You pry the glass out of the window frame."))
state--
update_nearby_icons()
return TRUE
else if(state == 0)
if(attacking_item.use_tool(src, user, 2 SECONDS, volume = 50))
to_chat(user, SPAN_NOTICE("You pry the glass into the window frame."))
state++
update_nearby_icons()
return TRUE
else if(attacking_item.tool_behaviour == TOOL_WRENCH && user.a_intent != I_HURT)
if(state == 0)
user.visible_message(SPAN_DANGER("\The [user] is dismantling \the [src]!"))
if(attacking_item.use_tool(src, user, 2 SECONDS, volume = 50))
to_chat(user, SPAN_NOTICE("You undo the safety bolts and remove the glass from \the [src]."))
dismantle_window()
return TRUE
return FALSE
/obj/structure/window/full/shatter(var/display_message = 1)
playsound(src, SFX_BREAK_GLASS, 70, 1)
if(display_message)
visible_message(SPAN_WARNING("\The [src] shatters!"))
if(reinf)
new /obj/item/stack/rods(loc, 4)
for(var/i = 1 to 4)
new shardtype(loc)
qdel(src)
return
/obj/structure/window/full/dismantle_window()
var/obj/item/stack/material/mats = new glasstype(loc)
mats.amount = 4
var/obj/structure/window_frame/WF = locate(/obj/structure/window_frame) in get_turf(src)
if(istype(WF))
WF.has_glass_installed = FALSE
WF.desc = "An empty steel window frame."
qdel(src)
update_nearby_icons()
/obj/structure/window/full/mouse_drop_receive(atom/dropping, mob/user, params)
//Adds the component only once. We do it here & not in Initialize() because there are tons of walls & we don't want to add to their init times
LoadComponent(/datum/component/leanable, dropping)
/********** Full Windows **********/
// Reinforced Window
/obj/structure/window/full/reinforced
name = "reinforced window"
desc = "It looks rather strong. Might take a few good hits to shatter it."
icon = 'icons/obj/smooth/window/full_window.dmi'
icon_state = "window_glass"
basestate = "window_glass"
maxhealth = OBJECT_HEALTH_LOW
reinf = TRUE
maximal_heat = T0C + 750
glasstype = /obj/item/stack/material/glass/reinforced
layer = FULL_WINDOW_LAYER
base_frame = /obj/structure/window_frame
smoothing_flags = SMOOTH_MORE
/obj/structure/window/full/cardinal_smooth(adjacencies, var/list/dir_mods)
dir_mods = handle_blending(adjacencies, dir_mods)
return ..(adjacencies, dir_mods)
/obj/structure/window_frame/proc/update_nearby_icons()
QUEUE_SMOOTH_NEIGHBORS(src)
/obj/structure/window_frame/update_icon()
QUEUE_SMOOTH(src)
// Indestructible Reinforced Window
/obj/structure/window/full/reinforced/indestructible/attack_hand()
return
/obj/structure/window/full/reinforced/indestructible/attackby()
return
/obj/structure/window/full/reinforced/indestructible/ex_act(var/severity = 2)
return
/obj/structure/window/full/reinforced/indestructible/hitby(atom/movable/hitting_atom, skipcatch, hitpush, blocked, datum/thrownthing/throwingdatum)
return
/obj/structure/window/full/reinforced/indestructible/shatter()
return
// Reinforced Polarized Window
/obj/structure/window/full/reinforced/polarized
name = "reinforced electrochromic window"
desc = "Adjusts its tint with voltage. Might take a few good hits to shatter it."
var/id
/obj/structure/window/full/reinforced/polarized/proc/toggle()
if(opacity)
animate(src, color="#FFFFFF", time = 1 SECOND)
set_opacity(FALSE)
else
animate(src, color="#606060", time = 1 SECOND)
set_opacity(TRUE)
// Indestructible Reinforced Polarized Window
/obj/structure/window/full/reinforced/polarized/indestructible/attack_hand()
return
/obj/structure/window/full/reinforced/polarized/indestructible/attackby()
return
/obj/structure/window/full/reinforced/polarized/indestructible/ex_act(var/severity = 2)
return
/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/shatter()
return
//Shuttle exterior window
/obj/structure/window/full/reinforced/shuttle
icon = 'icons/obj/smooth/window/shuttle_window_dark.dmi'
color = "#006eff"
icon_state = "window_glass"
basestate = "window_glass"
/obj/structure/window/full/reinforced/shuttle/red
color = "#ff0000"
/obj/structure/window/full/reinforced/shuttle/green
color = "#00ff40"
/obj/structure/window/full/reinforced/shuttle/black
color = "#150b41"
// Borosilicate Window (I.e. Phoron Window)
/obj/structure/window/full/phoron
name = "borosilicate window"
desc = "You aren't supposed to see this."
icon = 'icons/obj/smooth/window/full_window_phoron.dmi'
icon_state = "window_glass"
basestate = "window_glass"
glasstype = /obj/item/stack/material/glass/phoronglass
shardtype = /obj/item/material/shard/phoron
maxhealth = OBJECT_HEALTH_LOW
maximal_heat = T0C + 2000
damage_per_fire_tick = 1
// Reinforced Borosilicate Window (I.e. Reinforced Phoron Window)
/obj/structure/window/full/phoron/reinforced
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 = OBJECT_HEALTH_MEDIUM
reinf = TRUE
maximal_heat = T0C + 4000
rad_resistance_modifier = 4