diff --git a/code/__defines/is_helpers.dm b/code/__defines/is_helpers.dm index 47226383ea8..e121f552168 100644 --- a/code/__defines/is_helpers.dm +++ b/code/__defines/is_helpers.dm @@ -52,3 +52,4 @@ //--------------- //#define isturf(D) istype(D, /turf) //Built in #define isopenspace(A) istype(A, /turf/simulated/open) +#define isspace(A) istype(A, /turf/space) diff --git a/code/modules/shieldgen/energy_shield.dm b/code/modules/shieldgen/energy_shield.dm index 2efb5a7d8f6..978fd380c53 100644 --- a/code/modules/shieldgen/energy_shield.dm +++ b/code/modules/shieldgen/energy_shield.dm @@ -15,23 +15,45 @@ var/disabled_for = 0 var/diffused_for = 0 can_atmos_pass = ATMOS_PASS_YES + var/enabled_icon_state -/obj/effect/shield/update_icon() - if(gen && gen.check_flag(MODEFLAG_PHOTONIC) && !disabled_for && !diffused_for) - set_opacity(1) +/obj/effect/shield/proc/update_visuals() + update_iconstate() + update_color() + update_glow() + update_opacity() + +/obj/effect/shield/proc/update_iconstate() + if(!enabled_icon_state) + enabled_icon_state = icon_state + + if(disabled_for || diffused_for) + icon_state = "shield_broken" + overlays.Cut() //NOT ssoverlays else - set_opacity(0) + icon_state = enabled_icon_state + flags |= OVERLAY_QUEUED //Trick SSoverlays + SSoverlays.queue += src - if(gen && gen.check_flag(MODEFLAG_OVERCHARGE)) - icon_state = "shield_overcharged" +/obj/effect/shield/proc/update_color() + if(disabled_for || diffused_for) + color = "#FFA500" + else if(gen?.check_flag(MODEFLAG_OVERCHARGE)) + color = "#FE6666" else - icon_state = "shield_normal" + color = "#00AAFF" +/obj/effect/shield/proc/update_glow() if(density) set_light(3, 3, "#66FFFF") else set_light(0) +/obj/effect/shield/proc/update_opacity() + if(gen?.check_flag(MODEFLAG_PHOTONIC) && !disabled_for && !diffused_for) + set_opacity(1) + else + set_opacity(0) // Prevents singularities and pretty much everything else from moving the field segments away. // The only thing that is allowed to move us is the Destroy() proc. @@ -42,7 +64,7 @@ /obj/effect/shield/Destroy() if(can_atmos_pass != ATMOS_PASS_YES) - update_nearby_tiles() + update_nearby_tiles() //Force ZAS update . = ..() if(gen) if(src in gen.field_segments) @@ -59,12 +81,11 @@ if(gen) gen.damaged_segments |= src disabled_for += duration - set_density(0) - set_invisibility(INVISIBILITY_MAXIMUM) - update_nearby_tiles() - update_icon() - update_explosion_resistance() + set_density(0) + update_visuals() + update_nearby_tiles() //Force ZAS update + update_explosion_resistance() // Regenerates this shield segment. /obj/effect/shield/proc/regenerate() @@ -76,25 +97,23 @@ if(!disabled_for && !diffused_for) set_density(1) - set_invisibility(0) - update_nearby_tiles() - update_icon() + update_visuals() + update_nearby_tiles() //Force ZAS update update_explosion_resistance() gen.damaged_segments -= src - /obj/effect/shield/proc/diffuse(var/duration) // The shield is trying to counter diffusers. Cause lasting stress on the shield. - if(gen.check_flag(MODEFLAG_BYPASS) && !disabled_for) + if(gen?.check_flag(MODEFLAG_BYPASS) && !disabled_for) take_damage(duration * rand(8, 12), SHIELD_DAMTYPE_EM) return diffused_for = max(duration, 0) - gen.damaged_segments |= src + gen?.damaged_segments |= src + set_density(0) - set_invisibility(INVISIBILITY_MAXIMUM) - update_nearby_tiles() - update_icon() + update_visuals() + update_nearby_tiles() //Force ZAS update update_explosion_resistance() /obj/effect/shield/attack_generic(var/source, var/damage, var/emote) @@ -191,7 +210,7 @@ if(new_value == can_atmos_pass) return can_atmos_pass = new_value - update_nearby_tiles() + update_nearby_tiles() //Force ZAS update // EMP. It may seem weak but keep in mind that multiple shield segments are likely to be affected. @@ -218,7 +237,7 @@ take_damage(proj.get_structure_damage(), SHIELD_DAMTYPE_HEAT) else if (proj.damage_type == BRUTE) take_damage(proj.get_structure_damage(), SHIELD_DAMTYPE_PHYSICAL) - else + else //TODO - This will never happen because of get_structure_damage() only returning values for BRUTE and BURN damage types take_damage(proj.get_structure_damage(), SHIELD_DAMTYPE_EM) diff --git a/code/modules/shieldgen/shield_generator.dm b/code/modules/shieldgen/shield_generator.dm index 7e00c845b7c..846a2ba8a8c 100644 --- a/code/modules/shieldgen/shield_generator.dm +++ b/code/modules/shieldgen/shield_generator.dm @@ -104,14 +104,8 @@ // Generates the field objects. Deletes existing field, if applicable. /obj/machinery/power/shield_generator/proc/regenerate_field() - if(field_segments.len) - for(var/obj/effect/shield/S in field_segments) - qdel(S) - - // The generator is not turned on, so don't generate any new tiles. - if(!running) - return - + for(var/obj/effect/shield/S in field_segments) + qdel(S) var/list/shielded_turfs if(check_flag(MODEFLAG_HULL)) @@ -124,8 +118,145 @@ S.gen = src S.flags_updated() field_segments |= S + + //Hull shield chaos icon generation + if(check_flag(MODEFLAG_HULL)) + var/list/midsections = list() + var/list/startends = list() + var/list/corners = list() + var/list/horror = list() + + for(var/obj/effect/shield/SE in field_segments) + var/adjacent_fields = 0 + for(var/direction in cardinal) + var/turf/T = get_step(SE, direction) + var/obj/effect/shield/S = locate() in T + if(S) + adjacent_fields |= direction + + //What? + if(!adjacent_fields) + horror += SE + testing("Solo shield turf at [SE.x], [SE.y], [SE.z]") + continue + + //Middle section or corner (multiple bits set) + if((adjacent_fields & (adjacent_fields - 1)) != 0) + //'Impossible' directions + if(adjacent_fields == (NORTH|SOUTH) || adjacent_fields == (EAST|WEST)) + midsections[SE] = adjacent_fields + //It's a simple corner + else //if (adjacent_fields in cornerdirs) + corners[SE] = adjacent_fields + + //Not 0, not multiple bits, it's a start or an end + else + startends[SE] = adjacent_fields + + //Midsections go first + for(var/obj/effect/shield/SE in midsections) + var/adjacent = midsections[SE] + var/turf/L = get_step(SE, ~adjacent & (SOUTH|WEST)) + var/turf/R = get_step(SE, ~adjacent & (NORTH|EAST)) + if(!isspace(L) && !isspace(R)) // Squished in a single tile gap of space! + switch(adjacent) + if(NORTH|SOUTH) //Middle vertical section + if(SE.x < src.x) //Left of generator goes north + SE.set_dir(NORTH) + else + SE.set_dir(SOUTH) + if(EAST|WEST) //Middle horizontal section + if(SE.y < src.y) //South of generator goes left + SE.set_dir(WEST) + else + SE.set_dir(EAST) + else if(isspace(L)) + SE.set_dir(turn(~adjacent & (SOUTH|WEST), -90)) + else + SE.set_dir(turn(~adjacent & (NORTH|EAST), -90)) + + midsections -= SE + + //Corners + for(var/obj/effect/shield/S in corners) + var/adjacent = corners[S] + if(adjacent in cornerdirs) + do_corner_shield(S, adjacent) //Dir is adjacent fields direction + else + // Okay first a quick hack. If only one nonshield... + var/nonshield = adjacent ^ (NORTH|SOUTH|EAST|WEST) + if((nonshield & (nonshield - 1)) == 0) + if(!isspace(get_step(S, nonshield))) + S.set_dir(turn(nonshield, 90)) // We're basically a normal midsection just with another touching. Ignore it. + //What's this mysterious 3rd shield touching us? + var/dir_to_them = turn(nonshield, 180) + var/turf/T = get_step(S, dir_to_them) + var/obj/effect/shield/SO = locate() in T + //They are a corner + if((SO.dir & (SO.dir - 1)) != 0) + continue + else if(dir_to_them & SO.dir) //They're facing away from us, so we're their start + add_overlay(image(icon, icon_state = "shield_start" , dir = SO.dir)) + else if(SO.dir & nonshield) //They're facing us (and the wall) + add_overlay(image(icon, icon_state = "shield_end" , dir = SO.dir)) + + else + var/list/touchnonshield = list() + for(var/direction in cornerdirs) + var/turf/T = get_step(S, direction) + if(!isspace(T)) + touchnonshield += T + if(touchnonshield.len == 1) + do_corner_shield(S, get_dir(S, touchnonshield[1])) + else + S.icon_state = "capacitor" + else + // Not actually a corner... It has MULTIPLE! + S.icon_state = "arrow" //Error state/unhandled + + for(var/obj/effect/shield/SE in midsections) + SE.icon_state = "arrow" //Error state/unhandled + + for(var/obj/effect/shield/SE in field_segments) + SE.update_visuals() + + //Phew, update our own icon update_icon() +/obj/machinery/power/shield_generator/proc/do_corner_shield(var/obj/effect/shield/S, var/new_dir) + S.icon_state = "blank" + S.set_dir(new_dir) + var/inside = isspace(get_step(S, new_dir)) + // TODO - Obviously this can be more elegant + if(inside) + switch(new_dir) + if(NORTHEAST) + S.add_overlay(image(S.icon, icon_state = "shield_end", dir = SOUTH)) + S.add_overlay(image(S.icon, icon_state = "shield_start", dir = EAST)) + if(NORTHWEST) + S.add_overlay(image(S.icon, icon_state = "shield_end", dir = EAST)) + S.add_overlay(image(S.icon, icon_state = "shield_start", dir = NORTH)) + if(SOUTHEAST) + S.add_overlay(image(S.icon, icon_state = "shield_end", dir = WEST)) + S.add_overlay(image(S.icon, icon_state = "shield_start", dir = SOUTH)) + if(SOUTHWEST) + S.add_overlay(image(S.icon, icon_state = "shield_end", dir = NORTH)) + S.add_overlay(image(S.icon, icon_state = "shield_start", dir = WEST)) + else + switch(new_dir) + if(NORTHEAST) + S.add_overlay(image(S.icon, icon_state = "shield_end", dir = WEST)) + S.add_overlay(image(S.icon, icon_state = "shield_start", dir = NORTH)) + if(NORTHWEST) + S.add_overlay(image(S.icon, icon_state = "shield_end", dir = SOUTH)) + S.add_overlay(image(S.icon, icon_state = "shield_start", dir = WEST)) + if(SOUTHEAST) + S.add_overlay(image(S.icon, icon_state = "shield_end", dir = NORTH)) + S.add_overlay(image(S.icon, icon_state = "shield_start", dir = EAST)) + if(SOUTHWEST) + S.add_overlay(image(S.icon, icon_state = "shield_end", dir = EAST)) + S.add_overlay(image(S.icon, icon_state = "shield_start", dir = SOUTH)) + // Recalculates and updates the upkeep multiplier /obj/machinery/power/shield_generator/proc/update_upkeep_multiplier() diff --git a/icons/obj/machines/shielding.dmi b/icons/obj/machines/shielding.dmi index daf8906f1f3..195192b1c87 100644 Binary files a/icons/obj/machines/shielding.dmi and b/icons/obj/machines/shielding.dmi differ