Changes Shields

See PR for details
This commit is contained in:
Neerti
2017-04-13 00:36:13 -04:00
parent bff7d59312
commit c84ab67fd3
14 changed files with 444 additions and 137 deletions

View File

@@ -3,6 +3,10 @@ var/global/defer_powernet_rebuild = 0 // True if net rebuild will be called
#define CELLRATE 0.002 // Multiplier for watts per tick <> cell storage (e.g., 0.02 means if there is a load of 1000 watts, 20 units will be taken from a cell per second) #define CELLRATE 0.002 // Multiplier for watts per tick <> cell storage (e.g., 0.02 means if there is a load of 1000 watts, 20 units will be taken from a cell per second)
// It's a conversion constant. power_used*CELLRATE = charge_provided, or charge_used/CELLRATE = power_provided // It's a conversion constant. power_used*CELLRATE = charge_provided, or charge_used/CELLRATE = power_provided
#define KILOWATTS *1000
#define MEGAWATTS *1000000
#define GIGAWATTS *1000000000
// Doors! // Doors!
#define DOOR_CRUSH_DAMAGE 20 #define DOOR_CRUSH_DAMAGE 20
#define ALIEN_SELECT_AFK_BUFFER 1 // How many minutes that a person can be AFK before not being allowed to be an alien. #define ALIEN_SELECT_AFK_BUFFER 1 // How many minutes that a person can be AFK before not being allowed to be an alien.

View File

@@ -1299,3 +1299,16 @@ var/mob/dview/dview_mob = new
tY = max(1, min(world.maxy, origin.y + (text2num(tY) - (world.view + 1)))) tY = max(1, min(world.maxy, origin.y + (text2num(tY) - (world.view + 1))))
return locate(tX, tY, tZ) return locate(tX, tY, tZ)
// Displays something as commonly used (non-submultiples) SI units.
/proc/format_SI(var/number, var/symbol)
switch(round(abs(number)))
if(0 to 1000-1)
return "[number] [symbol]"
if(1e3 to 1e6-1)
return "[round(number / 1000, 0.1)] k[symbol]" // kilo
if(1e6 to 1e9-1)
return "[round(number / 1e6, 0.1)] m[symbol]" // mega
if(1e9 to 1e12-1) // Probably not needed but why not be complete?
return "[round(number / 1e9, 0.1)] g[symbol]" // giga
if(1e12 to 1e15-1)
return "[round(number / 1e12, 0.1)] t[symbol]" // tera

View File

@@ -80,6 +80,10 @@
var/turf/T = locate(endx, endy, Z) var/turf/T = locate(endx, endy, Z)
return T return T
// Override for special behavior when getting hit by meteors, and only meteors. Return one if the meteor hasn't been 'stopped'.
/atom/proc/handle_meteor_impact(var/obj/effect/meteor/meteor)
return TRUE
/////////////////////// ///////////////////////
//The meteor effect //The meteor effect
////////////////////// //////////////////////
@@ -101,6 +105,11 @@
var/meteordrop = /obj/item/weapon/ore/iron var/meteordrop = /obj/item/weapon/ore/iron
var/dropamt = 2 var/dropamt = 2
// How much damage it does to walls, using take_damage().
// Normal walls will die to 150 or more, where as reinforced walls need 800 to penetrate. Durasteel walls need 1200 damage to go through.
// Multiply this and the hits var to get a rough idea of how penetrating a meteor is.
var/wall_power = 100
/obj/effect/meteor/New() /obj/effect/meteor/New()
..() ..()
z_original = z z_original = z
@@ -132,8 +141,11 @@
/obj/effect/meteor/Bump(atom/A) /obj/effect/meteor/Bump(atom/A)
if(A) if(A)
if(A.handle_meteor_impact(src)) // Used for special behaviour when getting hit specifically by a meteor, like a shield.
ram_turf(get_turf(A)) ram_turf(get_turf(A))
get_hit() get_hit()
else
die(0)
/obj/effect/meteor/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) /obj/effect/meteor/CanPass(atom/movable/mover, turf/target, height=0, air_group=0)
return istype(mover, /obj/effect/meteor) ? 1 : ..() return istype(mover, /obj/effect/meteor) ? 1 : ..()
@@ -146,7 +158,11 @@
//then, ram the turf if it still exists //then, ram the turf if it still exists
if(T) if(T)
T.ex_act(hitpwr) if(istype(T, /turf/simulated/wall))
var/turf/simulated/wall/W = T
W.take_damage(wall_power) // Stronger walls can halt asteroids.
else
T.ex_act(hitpwr) // Floors and other things lack fancy health.
//process getting 'hit' by colliding with a dense object //process getting 'hit' by colliding with a dense object
@@ -154,8 +170,11 @@
/obj/effect/meteor/proc/get_hit() /obj/effect/meteor/proc/get_hit()
hits-- hits--
if(hits <= 0) if(hits <= 0)
die(1)
/obj/effect/meteor/proc/die(var/explode = 1)
make_debris() make_debris()
meteor_effect() meteor_effect(explode)
qdel(src) qdel(src)
/obj/effect/meteor/ex_act() /obj/effect/meteor/ex_act()
@@ -172,8 +191,7 @@
var/obj/item/O = new meteordrop(get_turf(src)) var/obj/item/O = new meteordrop(get_turf(src))
O.throw_at(dest, 5, 10) O.throw_at(dest, 5, 10)
/obj/effect/meteor/proc/meteor_effect() /obj/effect/meteor/proc/shake_players()
if(heavy)
for(var/mob/M in player_list) for(var/mob/M in player_list)
var/turf/T = get_turf(M) var/turf/T = get_turf(M)
if(!T || T.z != src.z) if(!T || T.z != src.z)
@@ -181,12 +199,16 @@
var/dist = get_dist(M.loc, src.loc) var/dist = get_dist(M.loc, src.loc)
shake_camera(M, dist > 20 ? 3 : 5, dist > 20 ? 1 : 3) shake_camera(M, dist > 20 ? 3 : 5, dist > 20 ? 1 : 3)
/obj/effect/meteor/proc/meteor_effect(var/explode)
if(heavy)
shake_players()
/////////////////////// ///////////////////////
//Meteor types //Meteor types
/////////////////////// ///////////////////////
//Dust // Dust breaks windows and hurts normal walls, generally more of an annoyance than a danger unless two happen to hit the same spot.
/obj/effect/meteor/dust /obj/effect/meteor/dust
name = "space dust" name = "space dust"
icon_state = "dust" icon_state = "dust"
@@ -194,63 +216,74 @@
hits = 1 hits = 1
hitpwr = 3 hitpwr = 3
meteordrop = /obj/item/weapon/ore/glass meteordrop = /obj/item/weapon/ore/glass
wall_power = 50
//Medium-sized // Medium-sized meteors aren't very special and can be stopped easily by r-walls.
/obj/effect/meteor/medium /obj/effect/meteor/medium
name = "meteor" name = "meteor"
dropamt = 3 dropamt = 3
wall_power = 200
/obj/effect/meteor/medium/meteor_effect() /obj/effect/meteor/medium/meteor_effect(var/explode)
..() ..()
if(explode)
explosion(src.loc, 0, 1, 2, 3, 0) explosion(src.loc, 0, 1, 2, 3, 0)
//Large-sized // Large-sized meteors generally pack the most punch, but are more concentrated towards the epicenter.
/obj/effect/meteor/big /obj/effect/meteor/big
name = "large meteor" name = "large meteor"
icon_state = "large" icon_state = "large"
hits = 6 hits = 8
heavy = 1 heavy = 1
dropamt = 4 dropamt = 4
wall_power = 400
/obj/effect/meteor/big/meteor_effect() /obj/effect/meteor/big/meteor_effect(var/explode)
..() ..()
explosion(src.loc, 1, 2, 3, 4, 0) if(explode)
explosion(src.loc, devastation_range = 2, heavy_impact_range = 4, light_impact_range = 6, flash_range = 12, adminlog = 0)
//Flaming meteor // 'Flaming' meteors do less overall damage but are spread out more due to a larger but weaker explosion at the end.
/obj/effect/meteor/flaming /obj/effect/meteor/flaming
name = "flaming meteor" name = "flaming meteor"
icon_state = "flaming" icon_state = "flaming"
hits = 5 hits = 5
heavy = 1 heavy = 1
meteordrop = /obj/item/weapon/ore/phoron meteordrop = /obj/item/weapon/ore/phoron
wall_power = 100
/obj/effect/meteor/flaming/meteor_effect() /obj/effect/meteor/flaming/meteor_effect(var/explode)
..() ..()
explosion(src.loc, 1, 2, 3, 4, 0, 0, 5) if(explode)
explosion(src.loc, devastation_range = 1, heavy_impact_range = 2, light_impact_range = 8, flash_range = 16, adminlog = 0)
//Radiation meteor // Irradiated meteors do less physical damage but project a ten-tile ranged pulse of radiation upon exploding.
/obj/effect/meteor/irradiated /obj/effect/meteor/irradiated
name = "glowing meteor" name = "glowing meteor"
icon_state = "glowing" icon_state = "glowing"
heavy = 1 heavy = 1
meteordrop = /obj/item/weapon/ore/uranium meteordrop = /obj/item/weapon/ore/uranium
wall_power = 75
/obj/effect/meteor/irradiated/meteor_effect() /obj/effect/meteor/irradiated/meteor_effect(var/explode)
..() ..()
explosion(src.loc, 0, 0, 4, 3, 0) if(explode)
explosion(src.loc, devastation_range = 0, heavy_impact_range = 0, light_impact_range = 4, flash_range = 6, adminlog = 0)
new /obj/effect/decal/cleanable/greenglow(get_turf(src)) new /obj/effect/decal/cleanable/greenglow(get_turf(src))
for(var/mob/living/L in view(5, src)) for(var/mob/living/L in view(10, src))
L.apply_effect(40, IRRADIATE) L.apply_effect(40, IRRADIATE)
// This meteor fries toasters.
/obj/effect/meteor/emp /obj/effect/meteor/emp
name = "conducting meteor" name = "conducting meteor"
icon_state = "glowing_blue" icon_state = "glowing_blue"
desc = "Hide your floppies!" desc = "Hide your floppies!"
meteordrop = /obj/item/weapon/ore/osmium meteordrop = /obj/item/weapon/ore/osmium
dropamt = 3 dropamt = 3
wall_power = 80
/obj/effect/meteor/emp/meteor_effect() /obj/effect/meteor/emp/meteor_effect(var/explode)
..() ..()
// Best case scenario: Comparable to a low-yield EMP grenade. // Best case scenario: Comparable to a low-yield EMP grenade.
// Worst case scenario: Comparable to a standard yield EMP grenade. // Worst case scenario: Comparable to a standard yield EMP grenade.
@@ -265,9 +298,11 @@
hitpwr = 1 hitpwr = 1
heavy = 1 heavy = 1
meteordrop = /obj/item/weapon/ore/phoron meteordrop = /obj/item/weapon/ore/phoron
wall_power = 150
/obj/effect/meteor/tunguska/meteor_effect() /obj/effect/meteor/tunguska/meteor_effect(var/explode)
..() ..()
if(explode)
explosion(src.loc, 5, 10, 15, 20, 0) explosion(src.loc, 5, 10, 15, 20, 0)
/obj/effect/meteor/tunguska/Bump() /obj/effect/meteor/tunguska/Bump()

View File

@@ -944,7 +944,7 @@ About the new airlock wires panel:
healthcheck() healthcheck()
/obj/effect/energy_field/airlock_crush(var/crush_damage) /obj/effect/energy_field/airlock_crush(var/crush_damage)
Stress(crush_damage) adjust_strength(crush_damage)
/obj/structure/closet/airlock_crush(var/crush_damage) /obj/structure/closet/airlock_crush(var/crush_damage)
..() ..()

View File

@@ -1,61 +1,100 @@
//---------- actual energy field //---------- actual energy field
// Each field object has a strength var (mensured in "Renwicks").
// Melee weapons do 5% of their normal (force var) damage, so a harmbaton would do 0.75 Renwick.
// Projectiles do 5% of their structural damage, so a normal laser would do 2 Renwick damage.
// For meteors, one Renwick is about equal to one layer of r-wall.
// Meteors will be completely halted by the shield if the shield survives the impact.
// Explosions do 4 Renwick of damage per severity, at a max of 12.
/obj/effect/energy_field /obj/effect/energy_field
name = "energy field" name = "energy shield field"
desc = "Impenetrable field of energy, capable of blocking anything as long as it's active." desc = "Impenetrable field of energy, capable of blocking anything as long as it's active."
icon = 'icons/obj/machines/shielding.dmi' icon = 'icons/obj/machines/shielding.dmi'
icon_state = "shieldsparkles" icon_state = "shield"
alpha = 100
anchored = 1 anchored = 1
layer = 4.1 //just above mobs layer = 4.1 //just above mobs
density = 0 density = 0
invisibility = 101 var/obj/machinery/shield_gen/my_gen = null
var/strength = 0 var/strength = 0 // in Renwicks
var/ticks_recovering = 10 var/ticks_recovering = 10
var/max_strength = 10
/obj/effect/energy_field/New() /obj/effect/energy_field/New(var/newloc, var/new_gen)
..() ..(newloc)
my_gen = new_gen
update_nearby_tiles() update_nearby_tiles()
/obj/effect/energy_field/Destroy() /obj/effect/energy_field/Destroy()
update_nearby_tiles() update_nearby_tiles()
my_gen.field.Remove(src)
my_gen = null
var/turf/current_loc = get_turf(src)
spawn(1) // Updates neightbors after we're gone.
for(var/direction in cardinal)
var/turf/T = get_step(current_loc, direction)
if(T)
for(var/obj/effect/energy_field/F in T)
F.update_icon()
..() ..()
/obj/effect/energy_field/ex_act(var/severity) /obj/effect/energy_field/ex_act(var/severity)
Stress(0.5 + severity) adjust_strength(-(4 - severity) * 4)
/obj/effect/energy_field/bullet_act(var/obj/item/projectile/Proj) /obj/effect/energy_field/bullet_act(var/obj/item/projectile/Proj)
Stress(Proj.get_structure_damage() / 10) adjust_strength(-Proj.get_structure_damage() / 10)
/obj/effect/energy_field/proc/Stress(var/severity) /obj/effect/energy_field/attackby(obj/item/W, mob/user)
strength -= severity if(W.force)
adjust_strength(-W.force / 20)
user.do_attack_animation(src)
user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
..()
/obj/effect/energy_field/attack_hand(var/mob/living/user)
impact_effect(3) // Harmless, but still produces the 'impact' effect.
..()
/obj/effect/energy_field/Bumped(atom/A)
..(A)
impact_effect(2)
/obj/effect/energy_field/handle_meteor_impact(var/obj/effect/meteor/meteor)
var/penetrated = TRUE
adjust_strength(-max((meteor.wall_power * meteor.hits) / 800, 0)) // One renwick (strength var) equals one r-wall for the purposes of meteor-stopping.
sleep(1)
if(density) // Check if we're still up.
penetrated = FALSE
explosion(meteor.loc, 0, 0, 0, 0, 0, 0, 0) // For the sound effect.
// Returning FALSE will kill the meteor.
return penetrated // If the shield's still around, the meteor was successfully stopped, otherwise keep going and plow into the station.
/obj/effect/energy_field/proc/adjust_strength(amount, impact = 1)
var/old_density = density
strength = between(0, strength + amount, max_strength)
//maptext = "[round(strength, 0.1)]/[max_strength]"
//if we take too much damage, drop out - the generator will bring us back up if we have enough power //if we take too much damage, drop out - the generator will bring us back up if we have enough power
if(amount < 0) // Taking damage.
if(impact)
impact_effect(round(abs(amount * 2)))
ticks_recovering = min(ticks_recovering + 2, 10) ticks_recovering = min(ticks_recovering + 2, 10)
if(strength < 1) if(strength < 1) // We broke
invisibility = 101
density = 0 density = 0
ticks_recovering = 10 ticks_recovering = 10
strength = 0 strength = 0
else if(strength >= 1)
invisibility = 0
density = 1
/obj/effect/energy_field/proc/Strengthen(var/severity) else if(amount > 0) // Healing damage.
strength += severity
if (strength < 0)
strength = 0
//if we take too much damage, drop out - the generator will bring us back up if we have enough power
var/old_density = density
if(strength >= 1) if(strength >= 1)
invisibility = 0
density = 1 density = 1
else if(strength < 1)
invisibility = 101
density = 0
if(density != old_density) if(density != old_density)
update_icon()
update_nearby_tiles() update_nearby_tiles()
/obj/effect/energy_field/CanPass(atom/movable/mover, turf/target, height=1.5, air_group = 0) /obj/effect/energy_field/CanPass(atom/movable/mover, turf/target, height=1.5, air_group = 0)
@@ -66,3 +105,44 @@
//return (!density || !height || air_group) //return (!density || !height || air_group)
return !density return !density
/obj/effect/energy_field/update_icon(var/update_neightbors = 0)
overlays.Cut()
var/list/adjacent_shields_dir = list()
for(var/direction in cardinal)
var/turf/T = get_step(src, direction)
if(T) // Incase we somehow stepped off the map.
for(var/obj/effect/energy_field/F in T)
if(update_neightbors)
F.update_icon(0)
adjacent_shields_dir |= direction
break
// Icon_state and Glow
if(density)
icon_state = "shield"
set_light(3, 3, "#66FFFF")
else
icon_state = "shield_broken"
set_light(3, 5, "#FF9900")
// Edge overlays
for(var/found_dir in adjacent_shields_dir)
overlays += image(src.icon, src, icon_state = "shield_edge", dir = found_dir)
// Small visual effect, makes the shield tiles brighten up by becoming more opaque for a moment, and spreads to nearby shields.
/obj/effect/energy_field/proc/impact_effect(var/i, var/list/affected_shields = list())
i = between(1, i, 10)
alpha = 200
animate(src, alpha = initial(alpha), time = 1 SECOND)
affected_shields |= src
i--
if(i)
spawn(2)
for(var/direction in cardinal)
var/turf/T = get_step(src, direction)
if(T) // Incase we somehow stepped off the map.
for(var/obj/effect/energy_field/F in T)
if(!(F in affected_shields))
F.impact_effect(i, affected_shields) // Spread the effect to them.

View File

@@ -0,0 +1,49 @@
/obj/item/weapon/shield_diffuser
name = "portable shield diffuser"
desc = "A small handheld device designed to disrupt energy barriers"
description_info = "This device disrupts shields on directly adjacent tiles (in a + shaped pattern), in a similar way the floor mounted variant does. It is, however, portable and run by an internal battery. Can be recharged with a regular recharger."
icon = 'icons/obj/machines/shielding.dmi'
icon_state = "hdiffuser_off"
var/obj/item/weapon/cell/device/cell
var/enabled = 0
/obj/item/weapon/shield_diffuser/update_icon()
if(enabled)
icon_state = "hdiffuser_on"
else
icon_state = "hdiffuser_off"
/obj/item/weapon/shield_diffuser/New()
cell = new(src)
..()
/obj/item/weapon/shield_diffuser/Destroy()
qdel(cell)
cell = null
if(enabled)
processing_objects.Remove(src)
. = ..()
/obj/item/weapon/shield_diffuser/process()
if(!enabled)
return
for(var/direction in cardinal)
var/turf/simulated/shielded_tile = get_step(get_turf(src), direction)
for(var/obj/effect/energy_field/S in shielded_tile)
if(istype(S) && cell.checked_use(10 KILOWATTS * CELLRATE))
qdel(S)
/obj/item/weapon/shield_diffuser/attack_self()
enabled = !enabled
update_icon()
if(enabled)
processing_objects.Add(src)
else
processing_objects.Remove(src)
to_chat(usr, "You turn \the [src] [enabled ? "on" : "off"].")
/obj/item/weapon/shield_diffuser/examine()
. = ..()
to_chat(usr, "The charge meter reads [cell ? cell.percent() : 0]%")
to_chat(usr, "It is [enabled ? "enabled" : "disabled"].")

View File

@@ -19,14 +19,6 @@
var/charge_rate = 100000 //100 kW var/charge_rate = 100000 //100 kW
var/obj/machinery/shield_gen/owned_gen var/obj/machinery/shield_gen/owned_gen
/obj/machinery/shield_capacitor/New()
spawn(10)
for(var/obj/machinery/shield_gen/possible_gen in range(1, src))
if(get_dir(src, possible_gen) == src.dir)
possible_gen.owned_capacitor = src
break
..()
/obj/machinery/shield_capacitor/emag_act(var/remaining_charges, var/mob/user) /obj/machinery/shield_capacitor/emag_act(var/remaining_charges, var/mob/user)
if(prob(75)) if(prob(75))
src.locked = !src.locked src.locked = !src.locked
@@ -54,13 +46,13 @@
if(anchored) if(anchored)
spawn(0) spawn(0)
for(var/obj/machinery/shield_gen/gen in range(1, src)) for(var/obj/machinery/shield_gen/gen in range(1, src))
if(get_dir(src, gen) == src.dir && !gen.owned_capacitor) if(get_dir(src, gen) == src.dir)
owned_gen = gen owned_gen = gen
owned_gen.owned_capacitor = src owned_gen.capacitors |= src
owned_gen.updateDialog() owned_gen.updateDialog()
else else
if(owned_gen && owned_gen.owned_capacitor == src) if(owned_gen && src in owned_gen.capacitors)
owned_gen.owned_capacitor = null owned_gen.capacitors -= src
owned_gen = null owned_gen = null
else else
..() ..()
@@ -82,16 +74,16 @@
else else
t += "This capacitor is: [active ? "<font color=green>Online</font>" : "<font color=red>Offline</font>" ] <a href='?src=\ref[src];toggle=1'>[active ? "\[Deactivate\]" : "\[Activate\]"]</a><br>" t += "This capacitor is: [active ? "<font color=green>Online</font>" : "<font color=red>Offline</font>" ] <a href='?src=\ref[src];toggle=1'>[active ? "\[Deactivate\]" : "\[Activate\]"]</a><br>"
t += "Capacitor Status: [time_since_fail > 2 ? "<font color=green>OK.</font>" : "<font color=red>Discharging!</font>"]<br>" t += "Capacitor Status: [time_since_fail > 2 ? "<font color=green>OK.</font>" : "<font color=red>Discharging!</font>"]<br>"
t += "Stored Energy: [round(stored_charge/1000, 0.1)] kJ ([100 * round(stored_charge/max_charge, 0.1)]%)<br>" t += "Stored Energy: [format_SI(stored_charge, "J")] ([100 * round(stored_charge/max_charge, 0.01)]%)<br>"
t += "Charge Rate: \ t += "Charge Rate: \
<a href='?src=\ref[src];charge_rate=-100000'>\[----\]</a> \ <a href='?src=\ref[src];charge_rate=-100000'>\[----\]</a> \
<a href='?src=\ref[src];charge_rate=-10000'>\[---\]</a> \ <a href='?src=\ref[src];charge_rate=-10000'>\[---\]</a> \
<a href='?src=\ref[src];charge_rate=-1000'>\[--\]</a> \ <a href='?src=\ref[src];charge_rate=-1000'>\[--\]</a> \
<a href='?src=\ref[src];charge_rate=-100'>\[-\]</a>[charge_rate] W \ <a href='?src=\ref[src];charge_rate=-100'>\[-\]</a>[format_SI(charge_rate, "W")]\
<a href='?src=\ref[src];charge_rate=100'>\[+\]</a> \ <a href='?src=\ref[src];charge_rate=100'>\[+\]</a> \
<a href='?src=\ref[src];charge_rate=1000'>\[++\]</a> \ <a href='?src=\ref[src];charge_rate=1000'>\[++\]</a> \
<a href='?src=\ref[src];charge_rate=10000'>\[+++\]</a> \ <a href='?src=\ref[src];charge_rate=10000'>\[+++\]</a> \
<a href='?src=\ref[src];charge_rate=100000'>\[+++\]</a><br>" <a href='?src=\ref[src];charge_rate=100000'>\[++++\]</a><br>"
t += "<hr>" t += "<hr>"
t += "<A href='?src=\ref[src]'>Refresh</A> " t += "<A href='?src=\ref[src]'>Refresh</A> "
t += "<A href='?src=\ref[src];close=1'>Close</A><BR>" t += "<A href='?src=\ref[src];close=1'>Close</A><BR>"

View File

@@ -0,0 +1,74 @@
/obj/machinery/shield_diffuser
name = "shield diffuser"
desc = "A small underfloor device specifically designed to disrupt energy barriers."
description_info = "This device disrupts shields on directly adjacent tiles (in a + shaped pattern). They are commonly installed around exterior airlocks to prevent shields from blocking EVA access."
icon = 'icons/obj/machines/shielding.dmi'
icon_state = "fdiffuser_on"
use_power = 2
idle_power_usage = 100
active_power_usage = 2000
anchored = 1
density = 0
level = 1
var/alarm = 0
var/enabled = 1
/obj/machinery/shield_diffuser/New()
..()
var/turf/T = get_turf(src)
hide(!T.is_plating())
//If underfloor, hide the cable
/obj/machinery/shield_diffuser/hide(var/i)
if(istype(loc, /turf))
invisibility = i ? 101 : 0
update_icon()
/obj/machinery/shield_diffuser/hides_under_flooring()
return 1
/obj/machinery/shield_diffuser/process()
if(alarm)
alarm--
if(!alarm)
update_icon()
return
if(!enabled)
return
for(var/direction in cardinal)
var/turf/simulated/shielded_tile = get_step(get_turf(src), direction)
for(var/obj/effect/energy_field/S in shielded_tile)
qdel(S)
/obj/machinery/shield_diffuser/update_icon()
if(alarm)
icon_state = "fdiffuser_emergency"
return
if((stat & (NOPOWER | BROKEN)) || !enabled)
icon_state = "fdiffuser_off"
else
icon_state = "fdiffuser_on"
/obj/machinery/shield_diffuser/attack_hand()
if(alarm)
to_chat(usr, "You press an override button on \the [src], re-enabling it.")
alarm = 0
update_icon()
return
enabled = !enabled
use_power = enabled + 1
update_icon()
to_chat(usr, "You turn \the [src] [enabled ? "on" : "off"].")
/obj/machinery/shield_diffuser/proc/meteor_alarm(var/duration)
if(!duration)
return
alarm = round(max(alarm, duration))
update_icon()
/obj/machinery/shield_diffuser/examine(var/mob/user)
. = ..()
to_chat(user, "It is [enabled ? "enabled" : "disabled"].")
if(alarm)
to_chat(user, "A red LED labeled \"Proximity Alarm\" is blinking on the control panel.")

View File

@@ -1,10 +1,3 @@
//renwicks: fictional unit to describe shield strength
//a small meteor hit will deduct 1 renwick of strength from that shield tile
//light explosion range will do 1 renwick's damage
//medium explosion range will do 2 renwick's damage
//heavy explosion range will do 3 renwick's damage
//explosion damage is cumulative. if a tile is in range of light, medium and heavy damage, it will take a hit from all three
/obj/machinery/shield_gen /obj/machinery/shield_gen
name = "bubble shield generator" name = "bubble shield generator"
desc = "Machine that generates an impenetrable field of energy when activated." desc = "Machine that generates an impenetrable field of energy when activated."
@@ -13,7 +6,7 @@
var/active = 0 var/active = 0
var/field_radius = 3 var/field_radius = 3
var/max_field_radius = 100 var/max_field_radius = 100
var/list/field var/list/field = list()
density = 1 density = 1
var/locked = 0 var/locked = 0
var/average_field_strength = 0 var/average_field_strength = 0
@@ -23,20 +16,25 @@
var/min_dissipation = 0.01 //will dissipate by at least this rate in renwicks per field tile (otherwise field would never dissipate completely as dissipation is a percentage) var/min_dissipation = 0.01 //will dissipate by at least this rate in renwicks per field tile (otherwise field would never dissipate completely as dissipation is a percentage)
var/powered = 0 var/powered = 0
var/check_powered = 1 var/check_powered = 1
var/obj/machinery/shield_capacitor/owned_capacitor var/list/capacitors = list()
var/target_field_strength = 10 var/target_field_strength = 10
var/max_field_strength = 10 var/max_field_strength = 10
var/time_since_fail = 100 var/time_since_fail = 100
var/energy_conversion_rate = 0.0002 //how many renwicks per watt? var/energy_conversion_rate = 0.0002 //how many renwicks per watt?
var/z_range = 0 // How far 'up and or down' to extend the shield to, in z-levels. Only works on MultiZ supported z-levels.
use_power = 0 //doesn't use APC power use_power = 0 //doesn't use APC power
/obj/machinery/shield_gen/New() /obj/machinery/shield_gen/New()
spawn(10) spawn(1 SECOND)
for(var/obj/machinery/shield_capacitor/possible_cap in range(1, src)) if(anchored)
if(get_dir(possible_cap, src) == possible_cap.dir) for(var/obj/machinery/shield_capacitor/cap in range(1, src))
owned_capacitor = possible_cap if(!cap.anchored)
break continue
field = new/list() if(cap.owned_gen)
continue
if(get_dir(cap, src) == cap.dir)
capacitors |= cap
cap.owned_gen = src
..() ..()
/obj/machinery/shield_gen/Destroy() /obj/machinery/shield_gen/Destroy()
@@ -76,14 +74,14 @@
if(cap.owned_gen) if(cap.owned_gen)
continue continue
if(get_dir(cap, src) == cap.dir && src.anchored) if(get_dir(cap, src) == cap.dir && src.anchored)
owned_capacitor = cap // owned_capacitor = cap
owned_capacitor.owned_gen = src capacitors |= cap
cap.owned_gen = src
updateDialog() updateDialog()
break // break
else else
if(owned_capacitor && owned_capacitor.owned_gen == src) for(var/obj/machinery/shield_capacitor/capacitor in capacitors)
owned_capacitor.owned_gen = null capacitor.owned_gen = null
owned_capacitor = null
else else
..() ..()
@@ -105,7 +103,13 @@
if(locked) if(locked)
t += "<i>Swipe your ID card to begin.</i>" t += "<i>Swipe your ID card to begin.</i>"
else else
t += "[owned_capacitor ? "<font color=green>Charge capacitor connected.</font>" : "<font color=red>Unable to locate charge capacitor!</font>"]<br>" t += "[capacitors.len ? "<font color=green>Charge capacitor(s) connected.</font>" : "<font color=red>Unable to locate charge capacitor!</font>"]<br>"
var/i = 0
for(var/obj/machinery/shield_capacitor/capacitor in capacitors)
i++
t += "Capacitor #[i]: [capacitor.active ? "<font color=green>Online.</font>" : "<font color=red>Offline.</font>"] \
Charge: [round(capacitor.stored_charge/1000, 0.1)] kJ ([100 * round(capacitor.stored_charge/capacitor.max_charge, 0.01)]%) \
Status: [capacitor.time_since_fail > 2 ? "<font color=green>OK.</font>" : "<font color=red>Discharging!</font>"]<br>"
t += "This generator is: [active ? "<font color=green>Online</font>" : "<font color=red>Offline</font>" ] <a href='?src=\ref[src];toggle=1'>[active ? "\[Deactivate\]" : "\[Activate\]"]</a><br>" t += "This generator is: [active ? "<font color=green>Online</font>" : "<font color=red>Offline</font>" ] <a href='?src=\ref[src];toggle=1'>[active ? "\[Deactivate\]" : "\[Activate\]"]</a><br>"
t += "Field Status: [time_since_fail > 2 ? "<font color=green>Stable</font>" : "<font color=red>Unstable</font>"]<br>" t += "Field Status: [time_since_fail > 2 ? "<font color=green>Stable</font>" : "<font color=red>Unstable</font>"]<br>"
t += "Coverage Radius (restart required): \ t += "Coverage Radius (restart required): \
@@ -116,12 +120,17 @@
<a href='?src=\ref[src];change_radius=1'>+</a> \ <a href='?src=\ref[src];change_radius=1'>+</a> \
<a href='?src=\ref[src];change_radius=5'>++</a> \ <a href='?src=\ref[src];change_radius=5'>++</a> \
<a href='?src=\ref[src];change_radius=50'>+++</a><br>" <a href='?src=\ref[src];change_radius=50'>+++</a><br>"
if(HasAbove(src.z) || HasBelow(src.z)) // Won't show up on maps lacking MultiZ support.
t += "Vertical Shielding (restart required): \
<a href='?src=\ref[src];z_range=-1'>-</a> \
[z_range] Vertical Range \
<a href='?src=\ref[src];z_range=1'>+</a><br>"
t += "Overall Field Strength: [round(average_field_strength, 0.01)] Renwick ([target_field_strength ? round(100 * average_field_strength / target_field_strength, 0.1) : "NA"]%)<br>" t += "Overall Field Strength: [round(average_field_strength, 0.01)] Renwick ([target_field_strength ? round(100 * average_field_strength / target_field_strength, 0.1) : "NA"]%)<br>"
t += "Upkeep Power: [round(field.len * max(average_field_strength * dissipation_rate, min_dissipation) / energy_conversion_rate)] W<br>" t += "Upkeep Power: [format_SI(round(field.len * max(average_field_strength * dissipation_rate, min_dissipation) / energy_conversion_rate), "W")]<br>"
t += "Charge Rate: <a href='?src=\ref[src];strengthen_rate=-0.1'>--</a> \ t += "Charge Rate: <a href='?src=\ref[src];strengthen_rate=-0.1'>--</a> \
[strengthen_rate] Renwick/s \ [strengthen_rate] Renwick/s \
<a href='?src=\ref[src];strengthen_rate=0.1'>++</a><br>" <a href='?src=\ref[src];strengthen_rate=0.1'>++</a><br>"
t += "Shield Generation Power: [round(field.len * min(strengthen_rate, target_field_strength - average_field_strength) / energy_conversion_rate)] W<br>" t += "Shield Generation Power: [format_SI(round(field.len * min(strengthen_rate, target_field_strength - average_field_strength) / energy_conversion_rate), "W")]<br>"
t += "Maximum Field Strength: \ t += "Maximum Field Strength: \
<a href='?src=\ref[src];target_field_strength=-10'>\[min\]</a> \ <a href='?src=\ref[src];target_field_strength=-10'>\[min\]</a> \
<a href='?src=\ref[src];target_field_strength=-5'>--</a> \ <a href='?src=\ref[src];target_field_strength=-5'>--</a> \
@@ -148,13 +157,28 @@
var/renwick_upkeep_per_field = max(average_field_strength * dissipation_rate, min_dissipation) var/renwick_upkeep_per_field = max(average_field_strength * dissipation_rate, min_dissipation)
//figure out how much energy we need to draw from the capacitor //figure out how much energy we need to draw from the capacitor
if(active && owned_capacitor && owned_capacitor.active) if(active && capacitors.len)
// Get a list of active capacitors to drain from.
var/list/active_capacitors = list()
for(var/obj/machinery/shield_capacitor/capacitor in capacitors) // Some capacitors might be off. Exclude them.
if(capacitor.active && capacitor.stored_charge > 0)
active_capacitors |= capacitor
var/target_renwick_increase = min(target_field_strength - average_field_strength, strengthen_rate) + renwick_upkeep_per_field //per field tile var/target_renwick_increase = min(target_field_strength - average_field_strength, strengthen_rate) + renwick_upkeep_per_field //per field tile
var/required_energy = field.len * target_renwick_increase / energy_conversion_rate var/required_energy = field.len * target_renwick_increase / energy_conversion_rate
var/assumed_charge = min(owned_capacitor.stored_charge, required_energy)
// Gets the charge for all capacitors
var/sum_charge = 0
for(var/obj/machinery/shield_capacitor/capacitor in active_capacitors)
sum_charge += capacitor.stored_charge
var/assumed_charge = min(sum_charge, required_energy)
total_renwick_increase = assumed_charge * energy_conversion_rate total_renwick_increase = assumed_charge * energy_conversion_rate
owned_capacitor.stored_charge -= assumed_charge
for(var/obj/machinery/shield_capacitor/capacitor in active_capacitors)
capacitor.stored_charge -= max(assumed_charge / active_capacitors.len, 0) // Drain from all active capacitors evenly.
else else
renwick_upkeep_per_field = max(renwick_upkeep_per_field, 0.5) renwick_upkeep_per_field = max(renwick_upkeep_per_field, 0.5)
@@ -162,12 +186,13 @@
average_field_strength = 0 //recalculate the average field strength average_field_strength = 0 //recalculate the average field strength
for(var/obj/effect/energy_field/E in field) for(var/obj/effect/energy_field/E in field)
E.max_strength = target_field_strength
var/amount_to_strengthen = renwick_increase_per_field - renwick_upkeep_per_field var/amount_to_strengthen = renwick_increase_per_field - renwick_upkeep_per_field
if(E.ticks_recovering > 0 && amount_to_strengthen > 0) if(E.ticks_recovering > 0 && amount_to_strengthen > 0)
E.Strengthen( min(amount_to_strengthen / 10, 0.1) ) E.adjust_strength( min(amount_to_strengthen / 10, 0.1), 0 )
E.ticks_recovering -= 1 E.ticks_recovering -= 1
else else
E.Strengthen(amount_to_strengthen) E.adjust_strength(amount_to_strengthen, 0)
average_field_strength += E.strength average_field_strength += E.strength
@@ -194,6 +219,8 @@
strengthen_rate = between(0, strengthen_rate + text2num(href_list["strengthen_rate"]), max_strengthen_rate) strengthen_rate = between(0, strengthen_rate + text2num(href_list["strengthen_rate"]), max_strengthen_rate)
else if( href_list["target_field_strength"] ) else if( href_list["target_field_strength"] )
target_field_strength = between(1, target_field_strength + text2num(href_list["target_field_strength"]), max_field_strength) target_field_strength = between(1, target_field_strength + text2num(href_list["target_field_strength"]), max_field_strength)
else if( href_list["z_range"] )
z_range = between(0, z_range + text2num(href_list["z_range"]), 10) // Max is extending ten z-levels up and down. Probably too big of a number but it shouldn't matter.
updateDialog() updateDialog()
@@ -213,16 +240,19 @@
if(T in covered_turfs) if(T in covered_turfs)
covered_turfs.Remove(T) covered_turfs.Remove(T)
for(var/turf/O in covered_turfs) for(var/turf/O in covered_turfs)
var/obj/effect/energy_field/E = new(O) var/obj/effect/energy_field/E = new(O, src)
field.Add(E) field.Add(E)
covered_turfs = null covered_turfs = null
for(var/mob/M in view(5,src)) for(var/mob/M in view(5,src))
M << "\icon[src] You hear heavy droning start up." M << "\icon[src] You hear heavy droning start up."
for(var/obj/effect/energy_field/E in field) // Update the icons here to ensure all the shields have been made already.
E.update_icon()
else else
for(var/obj/effect/energy_field/D in field) for(var/obj/effect/energy_field/D in field)
field.Remove(D) field.Remove(D)
D.loc = null //D.loc = null
qdel(D)
for(var/mob/M in view(5,src)) for(var/mob/M in view(5,src))
M << "\icon[src] You hear heavy droning fade out." M << "\icon[src] You hear heavy droning fade out."
@@ -236,12 +266,38 @@
else else
icon_state = "generator0" icon_state = "generator0"
//TODO MAKE THIS MULTIZ COMPATIBLE
//grab the border tiles in a circle around this machine //grab the border tiles in a circle around this machine
/obj/machinery/shield_gen/proc/get_shielded_turfs() /obj/machinery/shield_gen/proc/get_shielded_turfs()
var/list/out = list() var/list/out = list()
var/turf/gen_turf = get_turf(src) var/turf/T = get_turf(src)
if (!T)
return
out += get_shielded_turfs_on_z_level(T)
if(z_range)
var/i = z_range
while(HasAbove(T.z) && i)
T = GetAbove(T)
i--
if(istype(T))
out += get_shielded_turfs_on_z_level(T)
T = get_turf(src)
i = z_range
while(HasBelow(T.z) && i)
T = GetBelow(T)
i--
if(istype(T))
out += get_shielded_turfs_on_z_level(T)
return out
/obj/machinery/shield_gen/proc/get_shielded_turfs_on_z_level(var/turf/gen_turf)
var/list/out = list()
if (!gen_turf) if (!gen_turf)
return return

View File

@@ -7,12 +7,10 @@
/obj/machinery/shield_gen/external/New() /obj/machinery/shield_gen/external/New()
..() ..()
//NOT MULTIZ COMPATIBLE
//Search for space turfs within range that are adjacent to a simulated turf. //Search for space turfs within range that are adjacent to a simulated turf.
/obj/machinery/shield_gen/external/get_shielded_turfs() /obj/machinery/shield_gen/external/get_shielded_turfs_on_z_level(var/turf/gen_turf)
var/list/out = list() var/list/out = list()
var/turf/gen_turf = get_turf(src)
if (!gen_turf) if (!gen_turf)
return return

View File

@@ -30,9 +30,9 @@
..() ..()
for(var/obj/effect/energy_field/E in created_field) for(var/obj/effect/energy_field/E in created_field)
if(E.strength < 1) if(E.strength < 1)
E.Strengthen(0.15) E.adjust_strength(0.15, 0)
else if(E.strength < 5) else if(E.strength < 5)
E.Strengthen(0.25) E.adjust_strength(0.25, 0)
/datum/artifact_effect/forcefield/UpdateMove() /datum/artifact_effect/forcefield/UpdateMove()
if(created_field.len && holder) if(created_field.len && holder)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

View File

@@ -31,12 +31,16 @@
"E" = (/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/effect/floor_decal/corner/white/diagonal,/turf/simulated/floor/tiled/dark,/area/aisat) "E" = (/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/effect/floor_decal/corner/white/diagonal,/turf/simulated/floor/tiled/dark,/area/aisat)
"F" = (/obj/effect/landmark{name = "JoinLate"},/obj/effect/floor_decal/corner/white/diagonal,/turf/simulated/floor/tiled/dark,/area/aisat) "F" = (/obj/effect/landmark{name = "JoinLate"},/obj/effect/floor_decal/corner/white/diagonal,/turf/simulated/floor/tiled/dark,/area/aisat)
"G" = (/obj/effect/landmark/start,/turf/simulated/floor/tiled/dark,/area/aisat) "G" = (/obj/effect/landmark/start,/turf/simulated/floor/tiled/dark,/area/aisat)
"H" = (/obj/structure/stairs/south,/turf/simulated/floor/tiled/dark,/area/aisat) "H" = (/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/effect/floor_decal/corner/white/diagonal,/obj/machinery/shield_gen,/turf/simulated/floor/tiled/dark,/area/aisat)
"I" = (/obj/effect/floor_decal/sign/a,/turf/simulated/floor/tiled/dark,/area/aisat) "I" = (/obj/structure/stairs/south,/turf/simulated/floor/tiled/dark,/area/aisat)
"J" = (/obj/machinery/light,/obj/effect/floor_decal/corner/white/diagonal,/turf/simulated/floor/tiled/dark,/area/aisat) "J" = (/obj/effect/floor_decal/sign/a,/turf/simulated/floor/tiled/dark,/area/aisat)
"K" = (/obj/structure/cable/yellow,/obj/structure/cable/yellow{d1 = 16; d2 = 0; icon_state = "16-0"},/turf/simulated/floor/plating,/area/aisat) "K" = (/obj/machinery/light,/obj/effect/floor_decal/corner/white/diagonal,/turf/simulated/floor/tiled/dark,/area/aisat)
"L" = (/turf/simulated/floor/tiled/red,/area/aisat) "L" = (/obj/machinery/light,/obj/machinery/shield_capacitor{anchored = 1; dir = 4; icon_state = "capacitor"; tag = "icon-capacitor (EAST)"},/obj/structure/cable/yellow{d2 = 4; icon_state = "0-4"},/turf/simulated/floor/plating,/area/aisat)
"M" = (/obj/turbolift_map_holder/example{dir = 1; icon = 'icons/obj/turbolift_preview_5x5.dmi'},/turf/simulated/floor/tiled/red,/area/aisat) "M" = (/obj/machinery/shield_gen/external{anchored = 1},/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/plating,/area/aisat)
"N" = (/obj/machinery/shield_capacitor{anchored = 1; dir = 8; icon_state = "capacitor"; tag = "icon-capacitor (WEST)"},/obj/structure/cable/yellow{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/structure/cable/yellow{d2 = 8; icon_state = "0-8"},/turf/simulated/floor/plating,/area/aisat)
"O" = (/obj/structure/cable/yellow,/obj/structure/cable/yellow{d1 = 16; d2 = 0; icon_state = "16-0"},/obj/structure/cable/yellow{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/plating,/area/aisat)
"P" = (/turf/simulated/floor/tiled/red,/area/aisat)
"Q" = (/obj/turbolift_map_holder/example{dir = 1; icon = 'icons/obj/turbolift_preview_5x5.dmi'},/turf/simulated/floor/tiled/red,/area/aisat)
(1,1,1) = {" (1,1,1) = {"
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
@@ -58,16 +62,16 @@ aaaaaaaabuhhhhhvhhhhhhbaaaaaaaaa
aaaaaaaabwnnnnxyznnnnAbaaaaaaaaa aaaaaaaabwnnnnxyznnnnAbaaaaaaaaa
aaaaaaaabhhhhhBCDhhhhEbaaaaaaaaa aaaaaaaabhhhhhBCDhhhhEbaaaaaaaaa
aaaaaaaabhhFFFhnhhhhhEbaaaaaaaaa aaaaaaaabhhFFFhnhhhhhEbaaaaaaaaa
aaaaaaaabhhFFFhGhhhhhEbaaaaaaaaa aaaaaaaabhhFFFhGhhhhhHbaaaaaaaaa
aaaaaaaabnbFFFhnhhhhhEbaaaaaaaaa aaaaaaaabnbFFFhnhhhhhEbaaaaaaaaa
aaaaaaaabHbhhhhIhhhhhEbaaaaaaaaa aaaaaaaabIbhhhhJhhhhhEbaaaaaaaaa
aaaaaaaabbbhJhhnhhJhhKbaaaaaaaaa aaaaaaaabbbhKhhnhhLMNObaaaaaaaaa
aaaaaaaabbbbbbnnnbbbbbbaaaaaaaaa aaaaaaaabbbbbbnnnbbbbbbaaaaaaaaa
aaaaaaaaaaaabLLLLLbaaaaaaaaaaaaa aaaaaaaaaaaabPPPPPbaaaaaaaaaaaaa
aaaaaaaaaaaabLLLLLbaaaaaaaaaaaaa aaaaaaaaaaaabPPPPPbaaaaaaaaaaaaa
aaaaaaaaaaaabLLLLLbaaaaaaaaaaaaa aaaaaaaaaaaabPPPPPbaaaaaaaaaaaaa
aaaaaaaaaaaabLLLLLbaaaaaaaaaaaaa aaaaaaaaaaaabPPPPPbaaaaaaaaaaaaa
aaaaaaaaaaaabMLLLLbaaaaaaaaaaaaa aaaaaaaaaaaabQPPPPbaaaaaaaaaaaaa
aaaaaaaaaaaabbbbbbbaaaaaaaaaaaaa aaaaaaaaaaaabbbbbbbaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

View File

@@ -2008,8 +2008,10 @@
#include "code\modules\security levels\security levels.dm" #include "code\modules\security levels\security levels.dm"
#include "code\modules\shieldgen\emergency_shield.dm" #include "code\modules\shieldgen\emergency_shield.dm"
#include "code\modules\shieldgen\energy_field.dm" #include "code\modules\shieldgen\energy_field.dm"
#include "code\modules\shieldgen\handheld_defuser.dm"
#include "code\modules\shieldgen\sheldwallgen.dm" #include "code\modules\shieldgen\sheldwallgen.dm"
#include "code\modules\shieldgen\shield_capacitor.dm" #include "code\modules\shieldgen\shield_capacitor.dm"
#include "code\modules\shieldgen\shield_diffuser.dm"
#include "code\modules\shieldgen\shield_gen.dm" #include "code\modules\shieldgen\shield_gen.dm"
#include "code\modules\shieldgen\shield_gen_external.dm" #include "code\modules\shieldgen\shield_gen_external.dm"
#include "code\modules\shuttles\antagonist.dm" #include "code\modules\shuttles\antagonist.dm"