mirror of
https://github.com/CHOMPStation2/CHOMPStation2.git
synced 2025-12-11 10:43:20 +00:00
@@ -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)
|
||||
// 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!
|
||||
#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.
|
||||
|
||||
@@ -1299,3 +1299,16 @@ var/mob/dview/dview_mob = new
|
||||
tY = max(1, min(world.maxy, origin.y + (text2num(tY) - (world.view + 1))))
|
||||
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
|
||||
|
||||
@@ -80,6 +80,10 @@
|
||||
var/turf/T = locate(endx, endy, Z)
|
||||
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
|
||||
//////////////////////
|
||||
@@ -101,6 +105,11 @@
|
||||
var/meteordrop = /obj/item/weapon/ore/iron
|
||||
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()
|
||||
..()
|
||||
z_original = z
|
||||
@@ -132,8 +141,11 @@
|
||||
|
||||
/obj/effect/meteor/Bump(atom/A)
|
||||
if(A)
|
||||
ram_turf(get_turf(A))
|
||||
get_hit()
|
||||
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))
|
||||
get_hit()
|
||||
else
|
||||
die(0)
|
||||
|
||||
/obj/effect/meteor/CanPass(atom/movable/mover, turf/target, height=0, air_group=0)
|
||||
return istype(mover, /obj/effect/meteor) ? 1 : ..()
|
||||
@@ -146,7 +158,11 @@
|
||||
|
||||
//then, ram the turf if it still exists
|
||||
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
|
||||
@@ -154,9 +170,12 @@
|
||||
/obj/effect/meteor/proc/get_hit()
|
||||
hits--
|
||||
if(hits <= 0)
|
||||
make_debris()
|
||||
meteor_effect()
|
||||
qdel(src)
|
||||
die(1)
|
||||
|
||||
/obj/effect/meteor/proc/die(var/explode = 1)
|
||||
make_debris()
|
||||
meteor_effect(explode)
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/meteor/ex_act()
|
||||
return
|
||||
@@ -172,21 +191,24 @@
|
||||
var/obj/item/O = new meteordrop(get_turf(src))
|
||||
O.throw_at(dest, 5, 10)
|
||||
|
||||
/obj/effect/meteor/proc/meteor_effect()
|
||||
/obj/effect/meteor/proc/shake_players()
|
||||
for(var/mob/M in player_list)
|
||||
var/turf/T = get_turf(M)
|
||||
if(!T || T.z != src.z)
|
||||
continue
|
||||
var/dist = get_dist(M.loc, src.loc)
|
||||
shake_camera(M, dist > 20 ? 3 : 5, dist > 20 ? 1 : 3)
|
||||
|
||||
/obj/effect/meteor/proc/meteor_effect(var/explode)
|
||||
if(heavy)
|
||||
for(var/mob/M in player_list)
|
||||
var/turf/T = get_turf(M)
|
||||
if(!T || T.z != src.z)
|
||||
continue
|
||||
var/dist = get_dist(M.loc, src.loc)
|
||||
shake_camera(M, dist > 20 ? 3 : 5, dist > 20 ? 1 : 3)
|
||||
shake_players()
|
||||
|
||||
|
||||
///////////////////////
|
||||
//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
|
||||
name = "space dust"
|
||||
icon_state = "dust"
|
||||
@@ -194,63 +216,74 @@
|
||||
hits = 1
|
||||
hitpwr = 3
|
||||
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
|
||||
name = "meteor"
|
||||
dropamt = 3
|
||||
wall_power = 200
|
||||
|
||||
/obj/effect/meteor/medium/meteor_effect()
|
||||
/obj/effect/meteor/medium/meteor_effect(var/explode)
|
||||
..()
|
||||
explosion(src.loc, 0, 1, 2, 3, 0)
|
||||
if(explode)
|
||||
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
|
||||
name = "large meteor"
|
||||
icon_state = "large"
|
||||
hits = 6
|
||||
hits = 8
|
||||
heavy = 1
|
||||
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
|
||||
name = "flaming meteor"
|
||||
icon_state = "flaming"
|
||||
hits = 5
|
||||
heavy = 1
|
||||
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
|
||||
name = "glowing meteor"
|
||||
icon_state = "glowing"
|
||||
heavy = 1
|
||||
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))
|
||||
for(var/mob/living/L in view(5, src))
|
||||
for(var/mob/living/L in view(10, src))
|
||||
L.apply_effect(40, IRRADIATE)
|
||||
|
||||
// This meteor fries toasters.
|
||||
/obj/effect/meteor/emp
|
||||
name = "conducting meteor"
|
||||
icon_state = "glowing_blue"
|
||||
desc = "Hide your floppies!"
|
||||
meteordrop = /obj/item/weapon/ore/osmium
|
||||
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.
|
||||
// Worst case scenario: Comparable to a standard yield EMP grenade.
|
||||
@@ -265,10 +298,12 @@
|
||||
hitpwr = 1
|
||||
heavy = 1
|
||||
meteordrop = /obj/item/weapon/ore/phoron
|
||||
wall_power = 150
|
||||
|
||||
/obj/effect/meteor/tunguska/meteor_effect()
|
||||
/obj/effect/meteor/tunguska/meteor_effect(var/explode)
|
||||
..()
|
||||
explosion(src.loc, 5, 10, 15, 20, 0)
|
||||
if(explode)
|
||||
explosion(src.loc, 5, 10, 15, 20, 0)
|
||||
|
||||
/obj/effect/meteor/tunguska/Bump()
|
||||
..()
|
||||
|
||||
@@ -944,7 +944,7 @@ About the new airlock wires panel:
|
||||
healthcheck()
|
||||
|
||||
/obj/effect/energy_field/airlock_crush(var/crush_damage)
|
||||
Stress(crush_damage)
|
||||
adjust_strength(crush_damage)
|
||||
|
||||
/obj/structure/closet/airlock_crush(var/crush_damage)
|
||||
..()
|
||||
|
||||
@@ -1,61 +1,100 @@
|
||||
|
||||
//---------- 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
|
||||
name = "energy field"
|
||||
name = "energy shield field"
|
||||
desc = "Impenetrable field of energy, capable of blocking anything as long as it's active."
|
||||
icon = 'icons/obj/machines/shielding.dmi'
|
||||
icon_state = "shieldsparkles"
|
||||
icon_state = "shield"
|
||||
alpha = 100
|
||||
anchored = 1
|
||||
layer = 4.1 //just above mobs
|
||||
density = 0
|
||||
invisibility = 101
|
||||
var/strength = 0
|
||||
var/obj/machinery/shield_gen/my_gen = null
|
||||
var/strength = 0 // in Renwicks
|
||||
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()
|
||||
|
||||
/obj/effect/energy_field/Destroy()
|
||||
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)
|
||||
Stress(0.5 + severity)
|
||||
adjust_strength(-(4 - severity) * 4)
|
||||
|
||||
/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)
|
||||
strength -= severity
|
||||
/obj/effect/energy_field/attackby(obj/item/W, mob/user)
|
||||
if(W.force)
|
||||
adjust_strength(-W.force / 20)
|
||||
user.do_attack_animation(src)
|
||||
user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
|
||||
..()
|
||||
|
||||
//if we take too much damage, drop out - the generator will bring us back up if we have enough power
|
||||
ticks_recovering = min(ticks_recovering + 2, 10)
|
||||
if(strength < 1)
|
||||
invisibility = 101
|
||||
density = 0
|
||||
ticks_recovering = 10
|
||||
strength = 0
|
||||
else if(strength >= 1)
|
||||
invisibility = 0
|
||||
density = 1
|
||||
/obj/effect/energy_field/attack_hand(var/mob/living/user)
|
||||
impact_effect(3) // Harmless, but still produces the 'impact' effect.
|
||||
..()
|
||||
|
||||
/obj/effect/energy_field/proc/Strengthen(var/severity)
|
||||
strength += severity
|
||||
if (strength < 0)
|
||||
strength = 0
|
||||
/obj/effect/energy_field/Bumped(atom/A)
|
||||
..(A)
|
||||
impact_effect(2)
|
||||
|
||||
//if we take too much damage, drop out - the generator will bring us back up if we have enough power
|
||||
/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
|
||||
if(strength >= 1)
|
||||
invisibility = 0
|
||||
density = 1
|
||||
else if(strength < 1)
|
||||
invisibility = 101
|
||||
density = 0
|
||||
|
||||
if (density != old_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(amount < 0) // Taking damage.
|
||||
if(impact)
|
||||
impact_effect(round(abs(amount * 2)))
|
||||
|
||||
ticks_recovering = min(ticks_recovering + 2, 10)
|
||||
if(strength < 1) // We broke
|
||||
density = 0
|
||||
ticks_recovering = 10
|
||||
strength = 0
|
||||
|
||||
else if(amount > 0) // Healing damage.
|
||||
if(strength >= 1)
|
||||
density = 1
|
||||
|
||||
if(density != old_density)
|
||||
update_icon()
|
||||
update_nearby_tiles()
|
||||
|
||||
/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
|
||||
|
||||
/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.
|
||||
|
||||
|
||||
49
code/modules/shieldgen/handheld_defuser.dm
Normal file
49
code/modules/shieldgen/handheld_defuser.dm
Normal 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"].")
|
||||
@@ -19,14 +19,6 @@
|
||||
var/charge_rate = 100000 //100 kW
|
||||
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)
|
||||
if(prob(75))
|
||||
src.locked = !src.locked
|
||||
@@ -54,13 +46,13 @@
|
||||
if(anchored)
|
||||
spawn(0)
|
||||
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.owned_capacitor = src
|
||||
owned_gen.capacitors |= src
|
||||
owned_gen.updateDialog()
|
||||
else
|
||||
if(owned_gen && owned_gen.owned_capacitor == src)
|
||||
owned_gen.owned_capacitor = null
|
||||
if(owned_gen && src in owned_gen.capacitors)
|
||||
owned_gen.capacitors -= src
|
||||
owned_gen = null
|
||||
else
|
||||
..()
|
||||
@@ -82,16 +74,16 @@
|
||||
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 += "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: \
|
||||
<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=-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=1000'>\[++\]</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 += "<A href='?src=\ref[src]'>Refresh</A> "
|
||||
t += "<A href='?src=\ref[src];close=1'>Close</A><BR>"
|
||||
|
||||
74
code/modules/shieldgen/shield_diffuser.dm
Normal file
74
code/modules/shieldgen/shield_diffuser.dm
Normal 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.")
|
||||
@@ -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
|
||||
name = "bubble shield generator"
|
||||
desc = "Machine that generates an impenetrable field of energy when activated."
|
||||
@@ -13,7 +6,7 @@
|
||||
var/active = 0
|
||||
var/field_radius = 3
|
||||
var/max_field_radius = 100
|
||||
var/list/field
|
||||
var/list/field = list()
|
||||
density = 1
|
||||
var/locked = 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/powered = 0
|
||||
var/check_powered = 1
|
||||
var/obj/machinery/shield_capacitor/owned_capacitor
|
||||
var/list/capacitors = list()
|
||||
var/target_field_strength = 10
|
||||
var/max_field_strength = 10
|
||||
var/time_since_fail = 100
|
||||
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
|
||||
|
||||
/obj/machinery/shield_gen/New()
|
||||
spawn(10)
|
||||
for(var/obj/machinery/shield_capacitor/possible_cap in range(1, src))
|
||||
if(get_dir(possible_cap, src) == possible_cap.dir)
|
||||
owned_capacitor = possible_cap
|
||||
break
|
||||
field = new/list()
|
||||
spawn(1 SECOND)
|
||||
if(anchored)
|
||||
for(var/obj/machinery/shield_capacitor/cap in range(1, src))
|
||||
if(!cap.anchored)
|
||||
continue
|
||||
if(cap.owned_gen)
|
||||
continue
|
||||
if(get_dir(cap, src) == cap.dir)
|
||||
capacitors |= cap
|
||||
cap.owned_gen = src
|
||||
..()
|
||||
|
||||
/obj/machinery/shield_gen/Destroy()
|
||||
@@ -44,7 +42,7 @@
|
||||
field.Remove(D)
|
||||
D.loc = null
|
||||
..()
|
||||
|
||||
|
||||
/obj/machinery/shield_gen/emag_act(var/remaining_charges, var/mob/user)
|
||||
if(prob(75))
|
||||
src.locked = !src.locked
|
||||
@@ -76,14 +74,14 @@
|
||||
if(cap.owned_gen)
|
||||
continue
|
||||
if(get_dir(cap, src) == cap.dir && src.anchored)
|
||||
owned_capacitor = cap
|
||||
owned_capacitor.owned_gen = src
|
||||
// owned_capacitor = cap
|
||||
capacitors |= cap
|
||||
cap.owned_gen = src
|
||||
updateDialog()
|
||||
break
|
||||
// break
|
||||
else
|
||||
if(owned_capacitor && owned_capacitor.owned_gen == src)
|
||||
owned_capacitor.owned_gen = null
|
||||
owned_capacitor = null
|
||||
for(var/obj/machinery/shield_capacitor/capacitor in capacitors)
|
||||
capacitor.owned_gen = null
|
||||
else
|
||||
..()
|
||||
|
||||
@@ -105,7 +103,13 @@
|
||||
if(locked)
|
||||
t += "<i>Swipe your ID card to begin.</i>"
|
||||
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 += "Field Status: [time_since_fail > 2 ? "<font color=green>Stable</font>" : "<font color=red>Unstable</font>"]<br>"
|
||||
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=5'>++</a> \
|
||||
<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 += "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> \
|
||||
[strengthen_rate] Renwick/s \
|
||||
<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: \
|
||||
<a href='?src=\ref[src];target_field_strength=-10'>\[min\]</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)
|
||||
|
||||
//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/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
|
||||
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
|
||||
renwick_upkeep_per_field = max(renwick_upkeep_per_field, 0.5)
|
||||
|
||||
@@ -162,12 +186,13 @@
|
||||
|
||||
average_field_strength = 0 //recalculate the average field strength
|
||||
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
|
||||
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
|
||||
else
|
||||
E.Strengthen(amount_to_strengthen)
|
||||
E.adjust_strength(amount_to_strengthen, 0)
|
||||
|
||||
average_field_strength += E.strength
|
||||
|
||||
@@ -194,6 +219,8 @@
|
||||
strengthen_rate = between(0, strengthen_rate + text2num(href_list["strengthen_rate"]), max_strengthen_rate)
|
||||
else if( href_list["target_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()
|
||||
|
||||
@@ -213,16 +240,19 @@
|
||||
if(T in covered_turfs)
|
||||
covered_turfs.Remove(T)
|
||||
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)
|
||||
covered_turfs = null
|
||||
|
||||
for(var/mob/M in view(5,src))
|
||||
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
|
||||
for(var/obj/effect/energy_field/D in field)
|
||||
field.Remove(D)
|
||||
D.loc = null
|
||||
//D.loc = null
|
||||
qdel(D)
|
||||
|
||||
for(var/mob/M in view(5,src))
|
||||
M << "\icon[src] You hear heavy droning fade out."
|
||||
@@ -236,12 +266,38 @@
|
||||
else
|
||||
icon_state = "generator0"
|
||||
|
||||
//TODO MAKE THIS MULTIZ COMPATIBLE
|
||||
//grab the border tiles in a circle around this machine
|
||||
/obj/machinery/shield_gen/proc/get_shielded_turfs()
|
||||
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)
|
||||
return
|
||||
|
||||
@@ -260,4 +316,4 @@
|
||||
T = locate(gen_turf.x + field_radius, gen_turf.y + y_offset, gen_turf.z)
|
||||
if (T) out += T
|
||||
|
||||
return out
|
||||
return out
|
||||
@@ -7,15 +7,13 @@
|
||||
/obj/machinery/shield_gen/external/New()
|
||||
..()
|
||||
|
||||
//NOT MULTIZ COMPATIBLE
|
||||
//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/turf/gen_turf = get_turf(src)
|
||||
|
||||
if (!gen_turf)
|
||||
return
|
||||
|
||||
|
||||
var/turf/T
|
||||
for (var/x_offset = -field_radius; x_offset <= field_radius; x_offset++)
|
||||
for (var/y_offset = -field_radius; y_offset <= field_radius; y_offset++)
|
||||
@@ -24,4 +22,4 @@
|
||||
//check neighbors of T
|
||||
if (locate(/turf/simulated/) in orange(1, T))
|
||||
out += T
|
||||
return out
|
||||
return out
|
||||
@@ -30,9 +30,9 @@
|
||||
..()
|
||||
for(var/obj/effect/energy_field/E in created_field)
|
||||
if(E.strength < 1)
|
||||
E.Strengthen(0.15)
|
||||
E.adjust_strength(0.15, 0)
|
||||
else if(E.strength < 5)
|
||||
E.Strengthen(0.25)
|
||||
E.adjust_strength(0.25, 0)
|
||||
|
||||
/datum/artifact_effect/forcefield/UpdateMove()
|
||||
if(created_field.len && holder)
|
||||
|
||||
Reference in New Issue
Block a user