diff --git a/code/WorkInProgress/Cael_Aislinn/energy_field.dm b/code/WorkInProgress/Cael_Aislinn/energy_field.dm new file mode 100644 index 00000000000..363b1ada26b --- /dev/null +++ b/code/WorkInProgress/Cael_Aislinn/energy_field.dm @@ -0,0 +1,41 @@ + +//---------- actual energy field + +/obj/effect/energy_field + name = "energy field" + desc = "Impenetrable field of energy, capable of blocking anything as long as it's active." + icon = 'shielding.dmi' + icon_state = "shieldsparkles" + anchored = 1 + layer = 2.1 + density = 0 + invisibility = 2 + var/strength = 0 + var/obj/machinery/shield_gen/parent + var/stress = 0 + +/obj/effect/energy_field/ex_act(var/severity) + Stress(2) + //nothing + +/obj/effect/energy_field/meteorhit(obj/effect/meteor/M as obj) + if(M) + walk(M,0) + +/obj/effect/energy_field/proc/Stress(var/severity) + strength -= severity + stress += severity + + //if we take too much damage, drop out - the generator will bring us back up if we have enough power + if(strength < 1) + invisibility = 2 + density = 0 + +/obj/effect/energy_field/CanPass(atom/movable/mover, turf/target, height=1.5, air_group = 0) + //Purpose: Determines if the object (or airflow) can pass this atom. + //Called by: Movement, airflow. + //Inputs: The moving atom (optional), target turf, "height" and air group + //Outputs: Boolean if can pass. + + //return (!density || !height || air_group) + return 0 diff --git a/code/WorkInProgress/Cael_Aislinn/external_shield_gen.dm b/code/WorkInProgress/Cael_Aislinn/external_shield_gen.dm new file mode 100644 index 00000000000..c4524ad94e0 --- /dev/null +++ b/code/WorkInProgress/Cael_Aislinn/external_shield_gen.dm @@ -0,0 +1,64 @@ + +//---------- external shield generator +//generates an energy field that loops around any built up area in space (is useless inside) halts movement and airflow, is blocked by walls, windows, airlocks etc + +/obj/machinery/shield_gen/external/New() + ..() + +/obj/machinery/shield_gen/external/get_shielded_turfs() + var + list + open = list(get_turf(src)) + closed = list() + + while(open.len) + for(var/turf/T in open) + for(var/turf/O in orange(1, T)) + if(get_dist(O,src) > field_radius) + continue + var/add_this_turf = 0 + if(istype(O,/turf/space)) + for(var/turf/simulated/G in orange(1, O)) + add_this_turf = 1 + break + for(var/obj/structure/S in orange(1, O)) + add_this_turf = 1 + break + for(var/obj/structure/S in O) + add_this_turf = 0 + break + + if(add_this_turf && !(O in open) && !(O in closed)) + open += O + open -= T + closed += T + + return closed + +/obj/machinery/shield_gen/external/process() + /*if(stat & (NOPOWER|BROKEN)) + return*/ + if(!active) + return + /*spawn(100) + power()*/ + /*if(src.active >= 1) + if(src.power == 0) + src.visible_message("\red The [src.name] shuts down due to lack of power!", \ + "You hear heavy droning fade out") + icon_state = "generator0" + src.active = 0*/ + ..() + +/obj/item/weapon/circuitboard/shield_gen/external + name = "Circuit Board (External Shield Generator)" + build_path = "/obj/machinery/shield_gen/external" + board_type = "machine" + origin_tech = "electromagnetic=3;engineering=2;power=1" + frame_desc = "Requires, 2 Cable Coil, 2 Nano Manipulator, 1 Advanced Matter Bin, 1 Console Screen and 1 High-Power Micro-Laser. " + req_components = list( + "/obj/item/weapon/cable_coil" = 2, + "/obj/item/weapon/stock_parts/manipulator/nano" = 2, + "/obj/item/weapon/stock_parts/matter_bin/adv" = 1, + "/obj/item/weapon/stock_parts/console_screen" = 1, + "/obj/item/weapon/stock_parts/micro_laser/high" = 1) diff --git a/code/WorkInProgress/Cael_Aislinn/shield_capacitor.dm b/code/WorkInProgress/Cael_Aislinn/shield_capacitor.dm new file mode 100644 index 00000000000..50896434d7f --- /dev/null +++ b/code/WorkInProgress/Cael_Aislinn/shield_capacitor.dm @@ -0,0 +1,156 @@ + +//---------- shield capacitor +//pulls energy out of a power net and charges an adjacent generator + +/obj/machinery/shield_capacitor + name = "shield capacitor" + desc = "Machine that charges a shield generator." + icon = 'shielding.dmi' + icon_state = "capacitor" + var/active = 1 + density = 1 + anchored = 1 + var/obj/machinery/shield_gen/target_generator + var/stored_charge = 0 + var/time_since_fail = 100 + var/max_charge = 1000000 + var/max_charge_rate = 100000 + var/min_charge_rate = 0 + var/locked = 0 + // + use_power = 1 //0 use nothing + //1 use idle power + //2 use active power + idle_power_usage = 10 + active_power_usage = 100 + var/charge_rate = 100 + +/obj/machinery/shield_capacitor/New() + ..() + target_generator = locate() in get_step(src,dir) + if(target_generator && !target_generator.owned_capacitor) + target_generator.owned_capacitor = src + /*spawn(10) + check_powered()*/ + +/obj/machinery/shield_capacitor/power_change() + if(stat & BROKEN) + icon_state = "broke" + else + if( powered() ) + if (src.active) + icon_state = "capacitor" + else + icon_state = "capacitor" + stat &= ~NOPOWER + else + spawn(rand(0, 15)) + src.icon_state = "capacitor" + stat |= NOPOWER + +/obj/machinery/shield_capacitor/process() + // + if(active) + use_power = 2 + if(stored_charge + charge_rate > max_charge) + active_power_usage = max_charge - stored_charge + else + active_power_usage = charge_rate + stored_charge += active_power_usage + else + use_power = 1 + + time_since_fail++ + if(stored_charge < active_power_usage * 1.5) + time_since_fail = 0 + // + updateDialog() + +/obj/machinery/shield_capacitor/attackby(obj/item/W, mob/user) + /*if(istype(W, /obj/item/weapon/wrench)) + if(active) + user << "Turn off the field generator first." + return + + else if(state == 0) + state = 1 + playsound(src.loc, 'Ratchet.ogg', 75, 1) + user << "You secure the external reinforcing bolts to the floor." + src.anchored = 1 + return + + else if(state == 1) + state = 0 + playsound(src.loc, 'Ratchet.ogg', 75, 1) + user << "You undo the external reinforcing bolts." + src.anchored = 0 + return*/ + + if(istype(W, /obj/item/weapon/card/id)||istype(W, /obj/item/device/pda)) + if (src.allowed(user)) + src.locked = !src.locked + user << "Controls are now [src.locked ? "locked." : "unlocked."]" + else + user << "\red Access denied." + + else + src.add_fingerprint(user) + user << "\red You hit the [src.name] with your [W.name]!" + for(var/mob/M in viewers(src)) + if(M == user) continue + M.show_message("\red The [src.name] has been hit with the [W.name] by [user.name]!") + +/obj/machinery/shield_capacitor/attack_hand(mob/user as mob) + interact(user) + src.add_fingerprint(user) + +/obj/machinery/shield_capacitor/Topic(href, href_list[]) + ..() + if( href_list["close"] ) + usr << browse(null, "window=shield_capacitor") + usr.machine = null + return + if( href_list["toggle"] ) + active = !active + if(active) + use_power = 2 + else + use_power = 1 + if( href_list["charge_rate"] ) + charge_rate += text2num(href_list["charge_rate"]) + if(charge_rate > max_charge_rate) + charge_rate = max_charge_rate + else if(charge_rate < min_charge_rate) + charge_rate = min_charge_rate + // + updateDialog() + +/obj/machinery/shield_capacitor/proc/interact(mob/user) + if ( (get_dist(src, user) > 1 ) || (stat & (BROKEN|NOPOWER)) ) + if (!istype(user, /mob/living/silicon)) + user.machine = null + user << browse(null, "window=shield_capacitor") + return + var/t = "Shield Capacitor Control Console
" + t += "[target_generator ? "Shield generator connected." : "Unable to locate shield generator!"]
" + t += "This capacitor is: [active ? "Online" : "Offline" ] [active ? "\[Deactivate\]" : "\[Activate\]"]
" + t += "[time_since_fail > 2 ? "Charging stable." : "Warning, low charge!"]
" + t += "Capacitor charge: [stored_charge] Watts ([100 * stored_charge/max_charge]%)
" + t += "Capacitor charge rate (approx): \[min\] \[--\] \[-\][charge_rate] Watts/sec \[+\] \[++\] \[max\]
" + t += "
" + t += "Close
" + user << browse(t, "window=shield_capacitor;size=500x800") + user.machine = src + +/obj/item/weapon/circuitboard/shield_capacitor + name = "Circuit Board (Shield Capacitor)" + build_path = "/obj/machinery/shield_capacitor" + board_type = "machine" + origin_tech = "electromagnetic=3;engineering=2;power=1" + frame_desc = "Requires, 2 Cable Coil, 2 Nano Manipulator, 1 Advanced Matter Bin, 1 Console Screen and 1 High-Power Micro-Laser. " + req_components = list( + "/obj/item/weapon/cable_coil" = 2, + "/obj/item/weapon/stock_parts/manipulator/nano" = 2, + "/obj/item/weapon/stock_parts/matter_bin/adv" = 1, + "/obj/item/weapon/stock_parts/console_screen" = 1, + "/obj/item/weapon/stock_parts/micro_laser/high" = 1) diff --git a/code/WorkInProgress/Cael_Aislinn/shield_gen.dm b/code/WorkInProgress/Cael_Aislinn/shield_gen.dm new file mode 100644 index 00000000000..46f1f4c6abb --- /dev/null +++ b/code/WorkInProgress/Cael_Aislinn/shield_gen.dm @@ -0,0 +1,280 @@ +//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 = "shield generator" + desc = "Machine that generates an impenetrable field of energy when activated." + icon = 'shielding.dmi' + icon_state = "generator0" + var/active = 0 + var/field_radius = 3 + var/list/field + density = 1 + anchored = 1 + var/locked = 0 + var/average_field_strength = 0 + var/strengthen_rate = 0.2 + var/max_strengthen_rate = 0.2 + var/powered = 0 + var/check_powered = 1 + var/obj/machinery/shield_capacitor/owned_capacitor + var/max_field_strength = 10 + var/time_since_fail = 100 + var/energy_conversion_rate = 0.01 //how many renwicks per watt? + var/flicker_shield_glitch = 1 //shield is slightly faulty, and flickers + // + use_power = 1 //0 use nothing + //1 use idle power + //2 use active power + idle_power_usage = 20 + active_power_usage = 100 + +/obj/machinery/shield_gen/New() + ..() + field = new/list() + for(var/obj/machinery/shield_capacitor/possible_cap in range(1)) + if(get_dir(possible_cap, src) == possible_cap.dir) + owned_capacitor = possible_cap + break + /*spawn(10) + check_powered()*/ + +//copied from a copypaste. DRY, right? +/obj/machinery/shield_gen/proc/check_powered() + /* + check_powered = 1 + if(!anchored) + powered = 0 + return 0 + var/turf/T = src.loc + var/obj/structure/cable/C = T.get_cable_node() + var/net + if (C) + net = C.netnum // find the powernet of the connected cable + + if(!net) + powered = 0 + return 0 + var/datum/powernet/PN = powernets[net] // find the powernet. Magic code, voodoo code. + + if(!PN) + powered = 0 + return 0 + var/surplus = max(PN.avail-PN.load, 0) + var/shieldload = min(rand(50,200), surplus) + if(shieldload==0 && !storedpower) // no cable or no power, and no power stored + powered = 0 + return 0 + else + powered = 1 + if(PN) + storedpower += shieldload + PN.newload += shieldload //uses powernet power. + */ + +/obj/machinery/shield_gen/process() + + if(!owned_capacitor) + for(var/obj/machinery/shield_capacitor/possible_cap in range(1)) + if(get_dir(possible_cap, src) == possible_cap.dir) + owned_capacitor = possible_cap + break + + if(active && field.len) + var/stored_renwicks = 0 + var/target_field_strength = min(average_field_strength + strengthen_rate, max_field_strength) + if(owned_capacitor) + var/assumed_charge = min(owned_capacitor.stored_charge, (target_field_strength / energy_conversion_rate) * field.len) + stored_renwicks = assumed_charge * energy_conversion_rate + owned_capacitor.stored_charge -= assumed_charge + + time_since_fail++ + + average_field_strength = 0 + target_field_strength = stored_renwicks / field.len + + if(!flicker_shield_glitch) + for(var/obj/effect/energy_field/E in field) + //check to see if the shield is strengthening or failing + if(E.strength > target_field_strength) + E.strength = target_field_strength + else if(E.strength + strengthen_rate > target_field_strength) + E.strength = target_field_strength + else + E.strength += strengthen_rate + + if(stored_renwicks - E.strength < 0) + E.strength = stored_renwicks + stored_renwicks -= E.strength + + average_field_strength += E.strength + //check if the current shield tile has enough energy to maintain itself + if(E.strength >= 1) + E.density = 1 + E.invisibility = 0 + else + E.density = 0 + E.invisibility = 2 + else + //the flicker shield glitch is an intersting quirk in 'older' and/or faulty shielding models + //basically, it strengthens the shields continuously until it can no longer sustain them... then it drops out for a few seconds and starts again + //this makes the shield 'flicker' every now and then until it stabilises + //when this glitch is fixed, shields will only be charged as much as is sustainable + for(var/obj/effect/energy_field/E in field) + //check to see if the shield is strengthening or failing + if(E.strength < target_field_strength) + E.strength += strengthen_rate + + retry: + if(stored_renwicks - E.strength < 0) + if(owned_capacitor.stored_charge > 0) + var/emergency_renwicks = min(E.strength, owned_capacitor.stored_charge * energy_conversion_rate) + owned_capacitor.stored_charge -= emergency_renwicks / energy_conversion_rate + stored_renwicks += emergency_renwicks + goto retry + else + E.strength = stored_renwicks + stored_renwicks -= E.strength + + average_field_strength += E.strength + //check if the current shield tile has enough energy to maintain itself + if(E.strength >= 1) + E.density = 1 + E.invisibility = 0 + else + E.density = 0 + E.invisibility = 2 + + //add any leftover charge back to the capacitor + if(owned_capacitor && stored_renwicks >= 0) + owned_capacitor.stored_charge += stored_renwicks / energy_conversion_rate + + average_field_strength /= field.len + if(average_field_strength < 0) + time_since_fail = 0 + else + average_field_strength = 0 + // + updateDialog() + +/obj/machinery/shield_gen/attack_hand(mob/user as mob) + + interact(user) + src.add_fingerprint(user) + +/obj/machinery/shield_gen/attackby(obj/item/W, mob/user) + + if(istype(W, /obj/item/weapon/card/id)||istype(W, /obj/item/device/pda)) + if (src.allowed(user)) + src.locked = !src.locked + user << "Controls are now [src.locked ? "locked." : "unlocked."]" + else + user << "\red Access denied." + + else + src.add_fingerprint(user) + user << "\red You hit the [src.name] with your [W.name]!" + for(var/mob/M in viewers(src)) + if(M == user) continue + M.show_message("\red The [src.name] has been hit with the [W.name] by [user.name]!") + +/obj/machinery/shield_gen/power_change() + if(stat & BROKEN) + icon_state = "broke" + else + if( powered() ) + if (src.active) + icon_state = "generator1" + else + icon_state = "generator0" + stat &= ~NOPOWER + else + spawn(rand(0, 15)) + src.icon_state = "generator0" + stat |= NOPOWER + if (src.active) + toggle() + +/obj/machinery/shield_gen/proc/toggle() + active = !active + power_change() + if(active) + var/list/covered_turfs = get_shielded_turfs() + if(get_turf(src) in covered_turfs) + covered_turfs.Remove(get_turf(src)) + for(var/turf/O in covered_turfs) + var/obj/effect/energy_field/E = new(O) + field.Add(E) + del covered_turfs + + for(var/mob/M in view(5,src)) + M << "\icon[src] You hear heavy droning start up." + else + for(var/obj/effect/energy_field/D in field) + field.Remove(D) + del D + + for(var/mob/M in view(5,src)) + M << "\icon[src] You hear heavy droning fade out." + +/obj/machinery/shield_gen/Topic(href, href_list[]) + ..() + if( href_list["close"] ) + usr << browse(null, "window=shield_generator") + usr.machine = null + return + else if( href_list["toggle"] ) + toggle() + else if( href_list["change_radius"] ) + field_radius += text2num(href_list["change_radius"]) + if(field_radius > 200) + field_radius = 200 + else if(field_radius < 0) + field_radius = 0 + else if( href_list["strengthen_rate"] ) + strengthen_rate += text2num(href_list["strengthen_rate"]) + if(strengthen_rate > 0.2) + strengthen_rate = 0.2 + else if(strengthen_rate < 0) + strengthen_rate = 0 + else if( href_list["max_field_strength"] ) + max_field_strength += text2num(href_list["max_field_strength"]) + if(max_field_strength > 1000) + max_field_strength = 1000 + else if(max_field_strength < 0) + max_field_strength = 0 + // + updateDialog() + +/obj/machinery/shield_gen/proc/interact(mob/user) + if ( (get_dist(src, user) > 1 ) || (stat & (BROKEN|NOPOWER)) ) + if (!istype(user, /mob/living/silicon)) + user.machine = null + user << browse(null, "window=shield_generator") + return + var/t = "Shield Generator Control Console
" + t += "[owned_capacitor ? "Charge capacitor connected." : "Unable to locate charge capacitor!"]
" + t += "This generator is: [active ? "Online" : "Offline" ] [active ? "\[Deactivate\]" : "\[Activate\]"]
" + t += "[time_since_fail > 2 ? "Field is stable." : "Warning, field is unstable!"]
" + t += "Coverage radius (generator will need a restart to take effect): -- - [field_radius * 2]m + ++
" + t += "Overall field strength: [average_field_strength] Renwicks ([100 * average_field_strength / max_field_strength]%)
" + t += "Charge consumption: [( (min(average_field_strength + strengthen_rate, max_field_strength)) / energy_conversion_rate) * field.len] Watts/sec
" + t += "Field charge rate (approx): -- -[strengthen_rate] Renwicks/sec + ++
" + t += "Maximum field strength (avg across field): \[min\] -- -[max_field_strength] Renwicks + ++ \[max\]
" + t += "
" + t += "Close
" + user << browse(t, "window=shield_generator;size=500x800") + user.machine = src + +/obj/machinery/shield_gen/proc/get_shielded_turfs() + return list() + +/obj/machinery/shield_gen/ex_act(var/severity) + + if(active) + toggle() + return ..() diff --git a/code/game/objects/explosion.dm b/code/game/objects/explosion.dm index f701024bd6a..658d1a26c4c 100644 --- a/code/game/objects/explosion.dm +++ b/code/game/objects/explosion.dm @@ -36,7 +36,8 @@ proc/explosion(turf/epicenter, devastation_range, heavy_impact_range, light_impa var/list/fTurfs = list() //Holds turfs to loop through for mobs to flash. (Hehehe, dirty) //cael - replaced range() and circlerange() with FloodFill() to prevent explosions getting through shielding (ultrarealism mode) - //if testing indicates this is adding too much lag, roll back all shield handling + //also lag is pre'y bad + /* if(roundExplosions) if(/obj/effect/energy_field in range(src, max(devastation_range, heavy_impact_range, light_impact_range))) fTurfs = ExplosionCircleFloodFill(epicenter,max(devastation_range, heavy_impact_range, light_impact_range, flash_range)) @@ -68,6 +69,45 @@ proc/explosion(turf/epicenter, devastation_range, heavy_impact_range, light_impa hTurfs = range(epicenter,heavy_impact_range) - dTurfs lTurfs = range(epicenter,light_impact_range) - dTurfs - hTurfs + //add some stress to nearby shields + for(var/obj/effect/energy_field/E in range(epicenter, devastation_range)) + E.Stress(3) + for(var/obj/effect/energy_field/E in range(epicenter, heavy_impact_range)) + E.Stress(2) + for(var/obj/effect/energy_field/E in range(epicenter, light_impact_range)) + E.Stress(1)*/ + + if(roundExplosions) + if(/obj/effect/energy_field in range(src, max(devastation_range, heavy_impact_range, light_impact_range))) + fTurfs = circlerange(epicenter,max(devastation_range, heavy_impact_range, light_impact_range, flash_range)) + dTurfs = circlerange(epicenter,devastation_range) + hTurfs = circlerange(epicenter,heavy_impact_range) - dTurfs + lTurfs = circlerange(epicenter,light_impact_range) - dTurfs - hTurfs + else + fTurfs = circlerange(epicenter,max(devastation_range, heavy_impact_range, light_impact_range, flash_range)) + dTurfs = circlerange(epicenter,devastation_range) + hTurfs = circlerange(epicenter,heavy_impact_range) - dTurfs + lTurfs = circlerange(epicenter,light_impact_range) - dTurfs - hTurfs + + //add some stress to nearby shields + for(var/obj/effect/energy_field/E in circlerange(epicenter, devastation_range)) + E.Stress(3) + for(var/obj/effect/energy_field/E in circlerange(epicenter, heavy_impact_range)) + E.Stress(2) + for(var/obj/effect/energy_field/E in circlerange(epicenter, light_impact_range)) + E.Stress(1) + else + if(/obj/effect/energy_field in range(src, max(devastation_range, heavy_impact_range, light_impact_range))) + fTurfs = range(epicenter,max(devastation_range, heavy_impact_range, light_impact_range, flash_range)) + dTurfs = range(epicenter,devastation_range) + hTurfs = range(epicenter,heavy_impact_range) - dTurfs + lTurfs = range(epicenter,light_impact_range) - dTurfs - hTurfs + else + fTurfs = range(epicenter,max(devastation_range, heavy_impact_range, light_impact_range, flash_range)) + dTurfs = range(epicenter,devastation_range) + hTurfs = range(epicenter,heavy_impact_range) - dTurfs + lTurfs = range(epicenter,light_impact_range) - dTurfs - hTurfs + //add some stress to nearby shields for(var/obj/effect/energy_field/E in range(epicenter, devastation_range)) E.Stress(3)