initial commit - cross reference with 5th port - obviously has compile errors
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
/obj/item/weapon/am_containment
|
||||
name = "antimatter containment jar"
|
||||
desc = "Holds antimatter."
|
||||
icon = 'icons/obj/machines/antimatter.dmi'
|
||||
icon_state = "jar"
|
||||
density = 0
|
||||
anchored = 0
|
||||
force = 8
|
||||
throwforce = 10
|
||||
throw_speed = 1
|
||||
throw_range = 2
|
||||
|
||||
var/fuel = 10000
|
||||
var/fuel_max = 10000//Lets try this for now
|
||||
var/stability = 100//TODO: add all the stability things to this so its not very safe if you keep hitting in on things
|
||||
|
||||
|
||||
/obj/item/weapon/am_containment/ex_act(severity, target)
|
||||
switch(severity)
|
||||
if(1)
|
||||
explosion(get_turf(src), 1, 2, 3, 5)//Should likely be larger but this works fine for now I guess
|
||||
if(src)
|
||||
qdel(src)
|
||||
if(2)
|
||||
if(prob((fuel/10)-stability))
|
||||
explosion(get_turf(src), 1, 2, 3, 5)
|
||||
if(src)
|
||||
qdel(src)
|
||||
return
|
||||
stability -= 40
|
||||
if(3)
|
||||
stability -= 20
|
||||
//check_stability()
|
||||
return
|
||||
|
||||
/obj/item/weapon/am_containment/proc/usefuel(wanted)
|
||||
if(fuel < wanted)
|
||||
wanted = fuel
|
||||
fuel -= wanted
|
||||
return wanted
|
||||
@@ -0,0 +1,353 @@
|
||||
/obj/machinery/power/am_control_unit
|
||||
name = "antimatter control unit"
|
||||
desc = "This device injects antimatter into connected shielding units, the more antimatter injected the more power produced. Wrench the device to set it up."
|
||||
icon = 'icons/obj/machines/antimatter.dmi'
|
||||
icon_state = "control"
|
||||
anchored = 1
|
||||
density = 1
|
||||
use_power = 1
|
||||
idle_power_usage = 100
|
||||
active_power_usage = 1000
|
||||
|
||||
var/list/obj/machinery/am_shielding/linked_shielding
|
||||
var/list/obj/machinery/am_shielding/linked_cores
|
||||
var/obj/item/weapon/am_containment/fueljar
|
||||
var/update_shield_icons = 0
|
||||
var/stability = 100
|
||||
var/exploding = 0
|
||||
|
||||
var/active = 0//On or not
|
||||
var/fuel_injection = 2//How much fuel to inject
|
||||
var/shield_icon_delay = 0//delays resetting for a short time
|
||||
var/reported_core_efficiency = 0
|
||||
|
||||
var/power_cycle = 0
|
||||
var/power_cycle_delay = 4//How many ticks till produce_power is called
|
||||
var/stored_core_stability = 0
|
||||
var/stored_core_stability_delay = 0
|
||||
|
||||
var/stored_power = 0//Power to deploy per tick
|
||||
|
||||
|
||||
/obj/machinery/power/am_control_unit/New()
|
||||
..()
|
||||
linked_shielding = list()
|
||||
linked_cores = list()
|
||||
|
||||
|
||||
/obj/machinery/power/am_control_unit/Destroy()//Perhaps damage and run stability checks rather than just del on the others
|
||||
for(var/obj/machinery/am_shielding/AMS in linked_shielding)
|
||||
qdel(AMS)
|
||||
return ..()
|
||||
|
||||
|
||||
/obj/machinery/power/am_control_unit/process()
|
||||
if(exploding)
|
||||
explosion(get_turf(src),8,12,18,12)
|
||||
if(src)
|
||||
qdel(src)
|
||||
|
||||
if(update_shield_icons && !shield_icon_delay)
|
||||
check_shield_icons()
|
||||
update_shield_icons = 0
|
||||
|
||||
if(stat & (NOPOWER|BROKEN) || !active)//can update the icons even without power
|
||||
return
|
||||
|
||||
if(!fueljar)//No fuel but we are on, shutdown
|
||||
toggle_power()
|
||||
//Angry buzz or such here
|
||||
return
|
||||
|
||||
add_avail(stored_power)
|
||||
|
||||
power_cycle++
|
||||
if(power_cycle >= power_cycle_delay)
|
||||
produce_power()
|
||||
power_cycle = 0
|
||||
|
||||
return
|
||||
|
||||
|
||||
/obj/machinery/power/am_control_unit/proc/produce_power()
|
||||
playsound(src.loc, 'sound/effects/bang.ogg', 25, 1)
|
||||
var/core_power = reported_core_efficiency//Effectively how much fuel we can safely deal with
|
||||
if(core_power <= 0)
|
||||
return 0//Something is wrong
|
||||
var/core_damage = 0
|
||||
var/fuel = fueljar.usefuel(fuel_injection)
|
||||
|
||||
stored_power = (fuel/core_power)*fuel*200000
|
||||
//Now check if the cores could deal with it safely, this is done after so you can overload for more power if needed, still a bad idea
|
||||
if(fuel > (2*core_power))//More fuel has been put in than the current cores can deal with
|
||||
if(prob(50))
|
||||
core_damage = 1//Small chance of damage
|
||||
if((fuel-core_power) > 5)
|
||||
core_damage = 5//Now its really starting to overload the cores
|
||||
if((fuel-core_power) > 10)
|
||||
core_damage = 20//Welp now you did it, they wont stand much of this
|
||||
if(core_damage == 0)
|
||||
return
|
||||
for(var/obj/machinery/am_shielding/AMS in linked_cores)
|
||||
AMS.stability -= core_damage
|
||||
AMS.check_stability(1)
|
||||
playsound(src.loc, 'sound/effects/bang.ogg', 50, 1)
|
||||
return
|
||||
|
||||
|
||||
/obj/machinery/power/am_control_unit/emp_act(severity)
|
||||
switch(severity)
|
||||
if(1)
|
||||
if(active)
|
||||
toggle_power()
|
||||
stability -= rand(15,30)
|
||||
if(2)
|
||||
if(active)
|
||||
toggle_power()
|
||||
stability -= rand(10,20)
|
||||
..()
|
||||
return 0
|
||||
|
||||
|
||||
/obj/machinery/power/am_control_unit/blob_act()
|
||||
stability -= 20
|
||||
if(prob(100-stability))//Might infect the rest of the machine
|
||||
for(var/obj/machinery/am_shielding/AMS in linked_shielding)
|
||||
AMS.blob_act()
|
||||
qdel(src)
|
||||
return
|
||||
check_stability()
|
||||
return
|
||||
|
||||
|
||||
/obj/machinery/power/am_control_unit/ex_act(severity, target)
|
||||
stability -= (80 - (severity * 20))
|
||||
check_stability()
|
||||
return
|
||||
|
||||
|
||||
/obj/machinery/power/am_control_unit/bullet_act(obj/item/projectile/Proj)
|
||||
. = ..()
|
||||
if(Proj.flag != "bullet")
|
||||
stability -= Proj.force
|
||||
check_stability()
|
||||
|
||||
|
||||
/obj/machinery/power/am_control_unit/power_change()
|
||||
..()
|
||||
if(stat & NOPOWER && active)
|
||||
toggle_power()
|
||||
return
|
||||
|
||||
|
||||
/obj/machinery/power/am_control_unit/update_icon()
|
||||
if(active)
|
||||
icon_state = "control_on"
|
||||
else icon_state = "control"
|
||||
//No other icons for it atm
|
||||
|
||||
|
||||
/obj/machinery/power/am_control_unit/attackby(obj/item/W, mob/user, params)
|
||||
if(istype(W, /obj/item/weapon/wrench))
|
||||
if(!anchored)
|
||||
playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1)
|
||||
user.visible_message("[user.name] secures the [src.name] to the floor.", \
|
||||
"<span class='notice'>You secure the anchor bolts to the floor.</span>", \
|
||||
"<span class='italics'>You hear a ratchet.</span>")
|
||||
src.anchored = 1
|
||||
connect_to_network()
|
||||
else if(!linked_shielding.len > 0)
|
||||
playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1)
|
||||
user.visible_message("[user.name] unsecures the [src.name].", \
|
||||
"<span class='notice'>You remove the anchor bolts.</span>", \
|
||||
"<span class='italics'>You hear a ratchet.</span>")
|
||||
src.anchored = 0
|
||||
disconnect_from_network()
|
||||
else
|
||||
user << "<span class='warning'>Once bolted and linked to a shielding unit it the [src.name] is unable to be moved!</span>"
|
||||
|
||||
else if(istype(W, /obj/item/weapon/am_containment))
|
||||
if(fueljar)
|
||||
user << "<span class='warning'>There is already a [fueljar] inside!</span>"
|
||||
return
|
||||
fueljar = W
|
||||
W.loc = src
|
||||
if(user.client)
|
||||
user.client.screen -= W
|
||||
user.unEquip(W)
|
||||
user.update_icons()
|
||||
user.visible_message("[user.name] loads an [W.name] into the [src.name].", \
|
||||
"<span class='notice'>You load an [W.name].</span>", \
|
||||
"<span class='italics'>You hear a thunk.</span>")
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/machinery/power/am_control_unit/take_damage(damage, damage_type = BRUTE, sound_effect = 1)
|
||||
switch(damage_type)
|
||||
if(BRUTE)
|
||||
if(sound_effect)
|
||||
if(damage)
|
||||
playsound(loc, 'sound/weapons/smash.ogg', 50, 1)
|
||||
else
|
||||
playsound(loc, 'sound/weapons/tap.ogg', 50, 1)
|
||||
if(BURN)
|
||||
if(sound_effect)
|
||||
playsound(src.loc, 'sound/items/Welder.ogg', 100, 1)
|
||||
else
|
||||
return
|
||||
if(damage >= 20)
|
||||
stability -= damage/2
|
||||
check_stability()
|
||||
|
||||
/obj/machinery/power/am_control_unit/attack_hand(mob/user)
|
||||
if(anchored)
|
||||
interact(user)
|
||||
|
||||
/obj/machinery/power/am_control_unit/proc/add_shielding(obj/machinery/am_shielding/AMS, AMS_linking = 0)
|
||||
if(!istype(AMS))
|
||||
return 0
|
||||
if(!anchored)
|
||||
return 0
|
||||
if(!AMS_linking && !AMS.link_control(src))
|
||||
return 0
|
||||
linked_shielding.Add(AMS)
|
||||
update_shield_icons = 1
|
||||
return 1
|
||||
|
||||
|
||||
/obj/machinery/power/am_control_unit/proc/remove_shielding(obj/machinery/am_shielding/AMS)
|
||||
if(!istype(AMS))
|
||||
return 0
|
||||
linked_shielding.Remove(AMS)
|
||||
update_shield_icons = 2
|
||||
if(active)
|
||||
toggle_power()
|
||||
return 1
|
||||
|
||||
|
||||
/obj/machinery/power/am_control_unit/proc/check_stability()//TODO: make it break when low also might want to add a way to fix it like a part or such that can be replaced
|
||||
if(stability <= 0)
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
|
||||
/obj/machinery/power/am_control_unit/proc/toggle_power()
|
||||
active = !active
|
||||
if(active)
|
||||
use_power = 2
|
||||
visible_message("The [src.name] starts up.")
|
||||
else
|
||||
use_power = 1
|
||||
visible_message("The [src.name] shuts down.")
|
||||
update_icon()
|
||||
return
|
||||
|
||||
|
||||
/obj/machinery/power/am_control_unit/proc/check_shield_icons()//Forces icon_update for all shields
|
||||
if(shield_icon_delay)
|
||||
return
|
||||
shield_icon_delay = 1
|
||||
if(update_shield_icons == 2)//2 means to clear everything and rebuild
|
||||
for(var/obj/machinery/am_shielding/AMS in linked_shielding)
|
||||
if(AMS.processing)
|
||||
AMS.shutdown_core()
|
||||
AMS.control_unit = null
|
||||
spawn(10)
|
||||
AMS.controllerscan()
|
||||
linked_shielding = list()
|
||||
|
||||
else
|
||||
for(var/obj/machinery/am_shielding/AMS in linked_shielding)
|
||||
AMS.update_icon()
|
||||
spawn(20)
|
||||
shield_icon_delay = 0
|
||||
return
|
||||
|
||||
|
||||
/obj/machinery/power/am_control_unit/proc/check_core_stability()
|
||||
if(stored_core_stability_delay || linked_cores.len <= 0)
|
||||
return
|
||||
stored_core_stability_delay = 1
|
||||
stored_core_stability = 0
|
||||
for(var/obj/machinery/am_shielding/AMS in linked_cores)
|
||||
stored_core_stability += AMS.stability
|
||||
stored_core_stability/=linked_cores.len
|
||||
spawn(40)
|
||||
stored_core_stability_delay = 0
|
||||
return
|
||||
|
||||
|
||||
/obj/machinery/power/am_control_unit/interact(mob/user)
|
||||
if((get_dist(src, user) > 1) || (stat & (BROKEN|NOPOWER)))
|
||||
if(!istype(user, /mob/living/silicon/ai))
|
||||
user.unset_machine()
|
||||
user << browse(null, "window=AMcontrol")
|
||||
return
|
||||
user.set_machine(src)
|
||||
|
||||
var/dat = ""
|
||||
dat += "AntiMatter Control Panel<BR>"
|
||||
dat += "<A href='?src=\ref[src];close=1'>Close</A><BR>"
|
||||
dat += "<A href='?src=\ref[src];refresh=1'>Refresh</A><BR>"
|
||||
dat += "<A href='?src=\ref[src];refreshicons=1'>Force Shielding Update</A><BR><BR>"
|
||||
dat += "Status: [(active?"Injecting":"Standby")] <BR>"
|
||||
dat += "<A href='?src=\ref[src];togglestatus=1'>Toggle Status</A><BR>"
|
||||
|
||||
dat += "Stability: [stability]%<BR>"
|
||||
dat += "Reactor parts: [linked_shielding.len]<BR>"//TODO: perhaps add some sort of stability check
|
||||
dat += "Cores: [linked_cores.len]<BR><BR>"
|
||||
dat += "-Current Efficiency: [reported_core_efficiency]<BR>"
|
||||
dat += "-Average Stability: [stored_core_stability] <A href='?src=\ref[src];refreshstability=1'>(update)</A><BR>"
|
||||
dat += "Last Produced: [stored_power]<BR>"
|
||||
|
||||
dat += "Fuel: "
|
||||
if(!fueljar)
|
||||
dat += "<BR>No fuel receptacle detected."
|
||||
else
|
||||
dat += "<A href='?src=\ref[src];ejectjar=1'>Eject</A><BR>"
|
||||
dat += "- [fueljar.fuel]/[fueljar.fuel_max] Units<BR>"
|
||||
|
||||
dat += "- Injecting: [fuel_injection] units<BR>"
|
||||
dat += "- <A href='?src=\ref[src];strengthdown=1'>--</A>|<A href='?src=\ref[src];strengthup=1'>++</A><BR><BR>"
|
||||
|
||||
|
||||
user << browse(dat, "window=AMcontrol;size=420x500")
|
||||
onclose(user, "AMcontrol")
|
||||
return
|
||||
|
||||
|
||||
/obj/machinery/power/am_control_unit/Topic(href, href_list)
|
||||
if(..())
|
||||
return
|
||||
|
||||
if(href_list["close"])
|
||||
usr << browse(null, "window=AMcontrol")
|
||||
usr.unset_machine()
|
||||
return
|
||||
|
||||
if(href_list["togglestatus"])
|
||||
toggle_power()
|
||||
|
||||
if(href_list["refreshicons"])
|
||||
update_shield_icons = 1
|
||||
|
||||
if(href_list["ejectjar"])
|
||||
if(fueljar)
|
||||
fueljar.loc = src.loc
|
||||
fueljar = null
|
||||
//fueljar.control_unit = null currently it does not care where it is
|
||||
//update_icon() when we have the icon for it
|
||||
|
||||
if(href_list["strengthup"])
|
||||
fuel_injection++
|
||||
|
||||
if(href_list["strengthdown"])
|
||||
fuel_injection--
|
||||
if(fuel_injection < 0)
|
||||
fuel_injection = 0
|
||||
|
||||
if(href_list["refreshstability"])
|
||||
check_core_stability()
|
||||
|
||||
updateDialog()
|
||||
return
|
||||
@@ -0,0 +1,235 @@
|
||||
//like orange but only checks north/south/east/west for one step
|
||||
/proc/cardinalrange(var/center)
|
||||
var/list/things = list()
|
||||
for(var/direction in cardinal)
|
||||
var/turf/T = get_step(center, direction)
|
||||
if(!T) continue
|
||||
things += T.contents
|
||||
return things
|
||||
|
||||
/obj/machinery/am_shielding
|
||||
name = "antimatter reactor section"
|
||||
desc = "This device was built using a plasma life-form that seems to increase plasma's natural ability to react with neutrinos while reducing the combustibility."
|
||||
|
||||
icon = 'icons/obj/machines/antimatter.dmi'
|
||||
icon_state = "shield"
|
||||
anchored = 1
|
||||
density = 1
|
||||
dir = NORTH
|
||||
use_power = 0//Living things generally dont use power
|
||||
idle_power_usage = 0
|
||||
active_power_usage = 0
|
||||
|
||||
var/obj/machinery/power/am_control_unit/control_unit = null
|
||||
var/processing = 0//To track if we are in the update list or not, we need to be when we are damaged and if we ever
|
||||
var/stability = 100//If this gets low bad things tend to happen
|
||||
var/efficiency = 1//How many cores this core counts for when doing power processing, plasma in the air and stability could affect this
|
||||
|
||||
|
||||
/obj/machinery/am_shielding/New(loc)
|
||||
..(loc)
|
||||
spawn(10)
|
||||
controllerscan()
|
||||
return
|
||||
|
||||
|
||||
/obj/machinery/am_shielding/proc/controllerscan(priorscan = 0)
|
||||
//Make sure we are the only one here
|
||||
if(!istype(src.loc, /turf))
|
||||
qdel(src)
|
||||
return
|
||||
for(var/obj/machinery/am_shielding/AMS in loc.contents)
|
||||
if(AMS == src)
|
||||
continue
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
//Search for shielding first
|
||||
for(var/obj/machinery/am_shielding/AMS in cardinalrange(src))
|
||||
if(AMS && AMS.control_unit && link_control(AMS.control_unit))
|
||||
break
|
||||
|
||||
if(!control_unit)//No other guys nearby look for a control unit
|
||||
for(var/direction in cardinal)
|
||||
for(var/obj/machinery/power/am_control_unit/AMC in cardinalrange(src))
|
||||
if(AMC.add_shielding(src))
|
||||
break
|
||||
|
||||
if(!control_unit)
|
||||
if(!priorscan)
|
||||
spawn(20)
|
||||
controllerscan(1)//Last chance
|
||||
return
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
|
||||
/obj/machinery/am_shielding/Destroy()
|
||||
if(control_unit)
|
||||
control_unit.remove_shielding(src)
|
||||
if(processing)
|
||||
shutdown_core()
|
||||
visible_message("<span class='danger'>The [src.name] melts!</span>")
|
||||
//Might want to have it leave a mess on the floor but no sprites for now
|
||||
return ..()
|
||||
|
||||
|
||||
/obj/machinery/am_shielding/CanPass(atom/movable/mover, turf/target, height=0)
|
||||
if(height==0)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
||||
/obj/machinery/am_shielding/process()
|
||||
if(!processing)
|
||||
. = PROCESS_KILL
|
||||
//TODO: core functions and stability
|
||||
//TODO: think about checking the airmix for plasma and increasing power output
|
||||
return
|
||||
|
||||
|
||||
/obj/machinery/am_shielding/emp_act()//Immune due to not really much in the way of electronics.
|
||||
return 0
|
||||
|
||||
|
||||
/obj/machinery/am_shielding/blob_act()
|
||||
stability -= 20
|
||||
if(prob(100-stability))
|
||||
if(prob(10))//Might create a node
|
||||
new /obj/effect/blob/node(src.loc,150)
|
||||
else
|
||||
new /obj/effect/blob(src.loc,60)
|
||||
qdel(src)
|
||||
return
|
||||
check_stability()
|
||||
return
|
||||
|
||||
|
||||
/obj/machinery/am_shielding/ex_act(severity, target)
|
||||
stability -= (80 - (severity * 20))
|
||||
check_stability()
|
||||
return
|
||||
|
||||
|
||||
/obj/machinery/am_shielding/bullet_act(obj/item/projectile/Proj)
|
||||
. = ..()
|
||||
if(Proj.flag != "bullet")
|
||||
stability -= Proj.force/2
|
||||
check_stability()
|
||||
|
||||
|
||||
/obj/machinery/am_shielding/update_icon()
|
||||
cut_overlays()
|
||||
for(var/direction in alldirs)
|
||||
var/machine = locate(/obj/machinery, get_step(loc, direction))
|
||||
if((istype(machine, /obj/machinery/am_shielding) && machine:control_unit == control_unit)||(istype(machine, /obj/machinery/power/am_control_unit) && machine == control_unit))
|
||||
add_overlay("shield_[direction]")
|
||||
|
||||
if(core_check())
|
||||
add_overlay("core")
|
||||
if(!processing)
|
||||
setup_core()
|
||||
else if(processing)
|
||||
shutdown_core()
|
||||
|
||||
|
||||
/obj/machinery/am_shielding/take_damage(damage, damage_type = BRUTE, sound_effect = 1)
|
||||
switch(damage_type)
|
||||
if(BRUTE)
|
||||
if(sound_effect)
|
||||
if(damage)
|
||||
playsound(loc, 'sound/weapons/smash.ogg', 50, 1)
|
||||
else
|
||||
playsound(loc, 'sound/weapons/tap.ogg', 50, 1)
|
||||
if(BURN)
|
||||
if(sound_effect)
|
||||
playsound(src.loc, 'sound/items/Welder.ogg', 100, 1)
|
||||
else
|
||||
return
|
||||
if(damage >= 10)
|
||||
stability -= damage/2
|
||||
check_stability()
|
||||
|
||||
|
||||
//Call this to link a detected shilding unit to the controller
|
||||
/obj/machinery/am_shielding/proc/link_control(obj/machinery/power/am_control_unit/AMC)
|
||||
if(!istype(AMC))
|
||||
return 0
|
||||
if(control_unit && control_unit != AMC)
|
||||
return 0//Already have one
|
||||
control_unit = AMC
|
||||
control_unit.add_shielding(src,1)
|
||||
return 1
|
||||
|
||||
|
||||
//Scans cards for shields or the control unit and if all there it
|
||||
/obj/machinery/am_shielding/proc/core_check()
|
||||
for(var/direction in alldirs)
|
||||
var/machine = locate(/obj/machinery, get_step(loc, direction))
|
||||
if(!machine)
|
||||
return 0//Need all for a core
|
||||
if(!istype(machine, /obj/machinery/am_shielding) && !istype(machine, /obj/machinery/power/am_control_unit))
|
||||
return 0
|
||||
return 1
|
||||
|
||||
|
||||
/obj/machinery/am_shielding/proc/setup_core()
|
||||
processing = 1
|
||||
machines |= src
|
||||
START_PROCESSING(SSmachine, src)
|
||||
if(!control_unit)
|
||||
return
|
||||
control_unit.linked_cores.Add(src)
|
||||
control_unit.reported_core_efficiency += efficiency
|
||||
return
|
||||
|
||||
|
||||
/obj/machinery/am_shielding/proc/shutdown_core()
|
||||
processing = 0
|
||||
if(!control_unit)
|
||||
return
|
||||
control_unit.linked_cores.Remove(src)
|
||||
control_unit.reported_core_efficiency -= efficiency
|
||||
return
|
||||
|
||||
|
||||
/obj/machinery/am_shielding/proc/check_stability(injecting_fuel = 0)
|
||||
if(stability > 0)
|
||||
return
|
||||
if(injecting_fuel && control_unit)
|
||||
control_unit.exploding = 1
|
||||
if(src)
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
|
||||
/obj/machinery/am_shielding/proc/recalc_efficiency(new_efficiency)//tbh still not 100% sure how I want to deal with efficiency so this is likely temp
|
||||
if(!control_unit || !processing)
|
||||
return
|
||||
if(stability < 50)
|
||||
new_efficiency /= 2
|
||||
control_unit.reported_core_efficiency += (new_efficiency - efficiency)
|
||||
efficiency = new_efficiency
|
||||
return
|
||||
|
||||
|
||||
|
||||
/obj/item/device/am_shielding_container
|
||||
name = "packaged antimatter reactor section"
|
||||
desc = "A small storage unit containing an antimatter reactor section. To use place near an antimatter control unit or deployed antimatter reactor section and use a multitool to activate this package."
|
||||
icon = 'icons/obj/machines/antimatter.dmi'
|
||||
icon_state = "box"
|
||||
item_state = "electronic"
|
||||
w_class = 4
|
||||
flags = CONDUCT
|
||||
throwforce = 5
|
||||
throw_speed = 1
|
||||
throw_range = 2
|
||||
materials = list(MAT_METAL=100)
|
||||
|
||||
/obj/item/device/am_shielding_container/attackby(obj/item/I, mob/user, params)
|
||||
if(istype(I, /obj/item/device/multitool) && istype(src.loc,/turf))
|
||||
new/obj/machinery/am_shielding(src.loc)
|
||||
qdel(src)
|
||||
else
|
||||
return ..()
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,785 @@
|
||||
///////////////////////////////
|
||||
//CABLE STRUCTURE
|
||||
///////////////////////////////
|
||||
|
||||
|
||||
////////////////////////////////
|
||||
// Definitions
|
||||
////////////////////////////////
|
||||
|
||||
/* Cable directions (d1 and d2)
|
||||
|
||||
|
||||
9 1 5
|
||||
\ | /
|
||||
8 - 0 - 4
|
||||
/ | \
|
||||
10 2 6
|
||||
|
||||
If d1 = 0 and d2 = 0, there's no cable
|
||||
If d1 = 0 and d2 = dir, it's a O-X cable, getting from the center of the tile to dir (knot cable)
|
||||
If d1 = dir1 and d2 = dir2, it's a full X-X cable, getting from dir1 to dir2
|
||||
By design, d1 is the smallest direction and d2 is the highest
|
||||
*/
|
||||
|
||||
/obj/structure/cable
|
||||
level = 1 //is underfloor
|
||||
anchored =1
|
||||
on_blueprints = TRUE
|
||||
var/datum/powernet/powernet
|
||||
name = "power cable"
|
||||
desc = "A flexible, superconducting insulated cable for heavy-duty power transfer."
|
||||
icon = 'icons/obj/power_cond/power_cond_red.dmi'
|
||||
icon_state = "0-1"
|
||||
var/d1 = 0 // cable direction 1 (see above)
|
||||
var/d2 = 1 // cable direction 2 (see above)
|
||||
layer = WIRE_LAYER //Above pipes, which are at GAS_PIPE_LAYER
|
||||
var/cable_color = "red"
|
||||
var/obj/item/stack/cable_coil/stored
|
||||
|
||||
/obj/structure/cable/yellow
|
||||
cable_color = "yellow"
|
||||
icon = 'icons/obj/power_cond/power_cond_yellow.dmi'
|
||||
|
||||
/obj/structure/cable/green
|
||||
cable_color = "green"
|
||||
icon = 'icons/obj/power_cond/power_cond_green.dmi'
|
||||
|
||||
/obj/structure/cable/blue
|
||||
cable_color = "blue"
|
||||
icon = 'icons/obj/power_cond/power_cond_blue.dmi'
|
||||
|
||||
/obj/structure/cable/pink
|
||||
cable_color = "pink"
|
||||
icon = 'icons/obj/power_cond/power_cond_pink.dmi'
|
||||
|
||||
/obj/structure/cable/orange
|
||||
cable_color = "orange"
|
||||
icon = 'icons/obj/power_cond/power_cond_orange.dmi'
|
||||
|
||||
/obj/structure/cable/cyan
|
||||
cable_color = "cyan"
|
||||
icon = 'icons/obj/power_cond/power_cond_cyan.dmi'
|
||||
|
||||
/obj/structure/cable/white
|
||||
cable_color = "white"
|
||||
icon = 'icons/obj/power_cond/power_cond_white.dmi'
|
||||
|
||||
// the power cable object
|
||||
/obj/structure/cable/New()
|
||||
..()
|
||||
|
||||
|
||||
// ensure d1 & d2 reflect the icon_state for entering and exiting cable
|
||||
var/dash = findtext(icon_state, "-")
|
||||
|
||||
d1 = text2num( copytext( icon_state, 1, dash ) )
|
||||
|
||||
d2 = text2num( copytext( icon_state, dash+1 ) )
|
||||
|
||||
var/turf/T = src.loc // hide if turf is not intact
|
||||
|
||||
if(level==1) hide(T.intact)
|
||||
cable_list += src //add it to the global cable list
|
||||
|
||||
if(d1)
|
||||
stored = new/obj/item/stack/cable_coil(null,2,cable_color)
|
||||
else
|
||||
stored = new/obj/item/stack/cable_coil(null,1,cable_color)
|
||||
|
||||
/obj/structure/cable/Destroy() // called when a cable is deleted
|
||||
if(powernet)
|
||||
cut_cable_from_powernet() // update the powernets
|
||||
cable_list -= src //remove it from global cable list
|
||||
return ..() // then go ahead and delete the cable
|
||||
|
||||
/obj/structure/cable/Deconstruct()
|
||||
var/turf/T = loc
|
||||
stored.loc = T
|
||||
..()
|
||||
|
||||
///////////////////////////////////
|
||||
// General procedures
|
||||
///////////////////////////////////
|
||||
|
||||
//If underfloor, hide the cable
|
||||
/obj/structure/cable/hide(i)
|
||||
|
||||
if(level == 1 && istype(loc, /turf))
|
||||
invisibility = i ? INVISIBILITY_MAXIMUM : 0
|
||||
updateicon()
|
||||
|
||||
/obj/structure/cable/proc/updateicon()
|
||||
if(invisibility)
|
||||
icon_state = "[d1]-[d2]-f"
|
||||
else
|
||||
icon_state = "[d1]-[d2]"
|
||||
|
||||
//Telekinesis has no effect on a cable
|
||||
/obj/structure/cable/attack_tk(mob/user)
|
||||
return
|
||||
|
||||
// Items usable on a cable :
|
||||
// - Wirecutters : cut it duh !
|
||||
// - Cable coil : merge cables
|
||||
// - Multitool : get the power currently passing through the cable
|
||||
//
|
||||
/obj/structure/cable/attackby(obj/item/W, mob/user, params)
|
||||
var/turf/T = src.loc
|
||||
if(T.intact)
|
||||
return
|
||||
if(istype(W, /obj/item/weapon/wirecutters))
|
||||
if (shock(user, 50))
|
||||
return
|
||||
user.visible_message("[user] cuts the cable.", "<span class='notice'>You cut the cable.</span>")
|
||||
stored.add_fingerprint(user)
|
||||
investigate_log("was cut by [key_name(usr, usr.client)] in [user.loc.loc]","wires")
|
||||
Deconstruct()
|
||||
return
|
||||
|
||||
else if(istype(W, /obj/item/stack/cable_coil))
|
||||
var/obj/item/stack/cable_coil/coil = W
|
||||
if (coil.get_amount() < 1)
|
||||
user << "<span class='warning'>Not enough cable!</span>"
|
||||
return
|
||||
coil.cable_join(src, user)
|
||||
|
||||
else if(istype(W, /obj/item/device/multitool))
|
||||
if(powernet && (powernet.avail > 0)) // is it powered?
|
||||
user << "<span class='danger'>[powernet.avail]W in power network.</span>"
|
||||
else
|
||||
user << "<span class='danger'>The cable is not powered.</span>"
|
||||
shock(user, 5, 0.2)
|
||||
|
||||
src.add_fingerprint(user)
|
||||
|
||||
// shock the user with probability prb
|
||||
/obj/structure/cable/proc/shock(mob/user, prb, siemens_coeff = 1)
|
||||
if(!prob(prb))
|
||||
return 0
|
||||
if (electrocute_mob(user, powernet, src, siemens_coeff))
|
||||
var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
|
||||
s.set_up(5, 1, src)
|
||||
s.start()
|
||||
return 1
|
||||
else
|
||||
return 0
|
||||
|
||||
//explosion handling
|
||||
/obj/structure/cable/ex_act(severity, target)
|
||||
..()
|
||||
if(!qdeleted(src))
|
||||
switch(severity)
|
||||
if(2)
|
||||
if(prob(50))
|
||||
Deconstruct()
|
||||
if(3)
|
||||
if(prob(25))
|
||||
Deconstruct()
|
||||
|
||||
/obj/structure/cable/singularity_pull(S, current_size)
|
||||
if(current_size >= STAGE_FIVE)
|
||||
Deconstruct()
|
||||
|
||||
/obj/structure/cable/proc/cableColor(colorC = "red")
|
||||
cable_color = colorC
|
||||
switch(colorC)
|
||||
if("red")
|
||||
icon = 'icons/obj/power_cond/power_cond_red.dmi'
|
||||
if("yellow")
|
||||
icon = 'icons/obj/power_cond/power_cond_yellow.dmi'
|
||||
if("green")
|
||||
icon = 'icons/obj/power_cond/power_cond_green.dmi'
|
||||
if("blue")
|
||||
icon = 'icons/obj/power_cond/power_cond_blue.dmi'
|
||||
if("pink")
|
||||
icon = 'icons/obj/power_cond/power_cond_pink.dmi'
|
||||
if("orange")
|
||||
icon = 'icons/obj/power_cond/power_cond_orange.dmi'
|
||||
if("cyan")
|
||||
icon = 'icons/obj/power_cond/power_cond_cyan.dmi'
|
||||
if("white")
|
||||
icon = 'icons/obj/power_cond/power_cond_white.dmi'
|
||||
|
||||
/obj/structure/cable/proc/update_stored(var/length = 1, var/color = "red")
|
||||
stored.amount = length
|
||||
stored.item_color = color
|
||||
stored.update_icon()
|
||||
|
||||
////////////////////////////////////////////
|
||||
// Power related
|
||||
///////////////////////////////////////////
|
||||
|
||||
/obj/structure/cable/proc/add_avail(amount)
|
||||
if(powernet)
|
||||
powernet.newavail += amount
|
||||
|
||||
/obj/structure/cable/proc/add_load(amount)
|
||||
if(powernet)
|
||||
powernet.load += amount
|
||||
|
||||
/obj/structure/cable/proc/surplus()
|
||||
if(powernet)
|
||||
return powernet.avail-powernet.load
|
||||
else
|
||||
return 0
|
||||
|
||||
/obj/structure/cable/proc/avail()
|
||||
if(powernet)
|
||||
return powernet.avail
|
||||
else
|
||||
return 0
|
||||
|
||||
/////////////////////////////////////////////////
|
||||
// Cable laying helpers
|
||||
////////////////////////////////////////////////
|
||||
|
||||
//handles merging diagonally matching cables
|
||||
//for info : direction^3 is flipping horizontally, direction^12 is flipping vertically
|
||||
/obj/structure/cable/proc/mergeDiagonalsNetworks(direction)
|
||||
|
||||
//search for and merge diagonally matching cables from the first direction component (north/south)
|
||||
var/turf/T = get_step(src, direction&3)//go north/south
|
||||
|
||||
for(var/obj/structure/cable/C in T)
|
||||
|
||||
if(!C)
|
||||
continue
|
||||
|
||||
if(src == C)
|
||||
continue
|
||||
|
||||
if(C.d1 == (direction^3) || C.d2 == (direction^3)) //we've got a diagonally matching cable
|
||||
if(!C.powernet) //if the matching cable somehow got no powernet, make him one (should not happen for cables)
|
||||
var/datum/powernet/newPN = new()
|
||||
newPN.add_cable(C)
|
||||
|
||||
if(powernet) //if we already have a powernet, then merge the two powernets
|
||||
merge_powernets(powernet,C.powernet)
|
||||
else
|
||||
C.powernet.add_cable(src) //else, we simply connect to the matching cable powernet
|
||||
|
||||
//the same from the second direction component (east/west)
|
||||
T = get_step(src, direction&12)//go east/west
|
||||
|
||||
for(var/obj/structure/cable/C in T)
|
||||
|
||||
if(!C)
|
||||
continue
|
||||
|
||||
if(src == C)
|
||||
continue
|
||||
if(C.d1 == (direction^12) || C.d2 == (direction^12)) //we've got a diagonally matching cable
|
||||
if(!C.powernet) //if the matching cable somehow got no powernet, make him one (should not happen for cables)
|
||||
var/datum/powernet/newPN = new()
|
||||
newPN.add_cable(C)
|
||||
|
||||
if(powernet) //if we already have a powernet, then merge the two powernets
|
||||
merge_powernets(powernet,C.powernet)
|
||||
else
|
||||
C.powernet.add_cable(src) //else, we simply connect to the matching cable powernet
|
||||
|
||||
// merge with the powernets of power objects in the given direction
|
||||
/obj/structure/cable/proc/mergeConnectedNetworks(direction)
|
||||
|
||||
var/fdir = (!direction)? 0 : turn(direction, 180) //flip the direction, to match with the source position on its turf
|
||||
|
||||
if(!(d1 == direction || d2 == direction)) //if the cable is not pointed in this direction, do nothing
|
||||
return
|
||||
|
||||
var/turf/TB = get_step(src, direction)
|
||||
|
||||
for(var/obj/structure/cable/C in TB)
|
||||
|
||||
if(!C)
|
||||
continue
|
||||
|
||||
if(src == C)
|
||||
continue
|
||||
|
||||
if(C.d1 == fdir || C.d2 == fdir) //we've got a matching cable in the neighbor turf
|
||||
if(!C.powernet) //if the matching cable somehow got no powernet, make him one (should not happen for cables)
|
||||
var/datum/powernet/newPN = new()
|
||||
newPN.add_cable(C)
|
||||
|
||||
if(powernet) //if we already have a powernet, then merge the two powernets
|
||||
merge_powernets(powernet,C.powernet)
|
||||
else
|
||||
C.powernet.add_cable(src) //else, we simply connect to the matching cable powernet
|
||||
|
||||
// merge with the powernets of power objects in the source turf
|
||||
/obj/structure/cable/proc/mergeConnectedNetworksOnTurf()
|
||||
var/list/to_connect = list()
|
||||
|
||||
if(!powernet) //if we somehow have no powernet, make one (should not happen for cables)
|
||||
var/datum/powernet/newPN = new()
|
||||
newPN.add_cable(src)
|
||||
|
||||
//first let's add turf cables to our powernet
|
||||
//then we'll connect machines on turf with a node cable is present
|
||||
for(var/AM in loc)
|
||||
if(istype(AM,/obj/structure/cable))
|
||||
var/obj/structure/cable/C = AM
|
||||
if(C.d1 == d1 || C.d2 == d1 || C.d1 == d2 || C.d2 == d2) //only connected if they have a common direction
|
||||
if(C.powernet == powernet)
|
||||
continue
|
||||
if(C.powernet)
|
||||
merge_powernets(powernet, C.powernet)
|
||||
else
|
||||
powernet.add_cable(C) //the cable was powernetless, let's just add it to our powernet
|
||||
|
||||
else if(istype(AM,/obj/machinery/power/apc))
|
||||
var/obj/machinery/power/apc/N = AM
|
||||
if(!N.terminal)
|
||||
continue // APC are connected through their terminal
|
||||
|
||||
if(N.terminal.powernet == powernet)
|
||||
continue
|
||||
|
||||
to_connect += N.terminal //we'll connect the machines after all cables are merged
|
||||
|
||||
else if(istype(AM,/obj/machinery/power)) //other power machines
|
||||
var/obj/machinery/power/M = AM
|
||||
|
||||
if(M.powernet == powernet)
|
||||
continue
|
||||
|
||||
to_connect += M //we'll connect the machines after all cables are merged
|
||||
|
||||
//now that cables are done, let's connect found machines
|
||||
for(var/obj/machinery/power/PM in to_connect)
|
||||
if(!PM.connect_to_network())
|
||||
PM.disconnect_from_network() //if we somehow can't connect the machine to the new powernet, remove it from the old nonetheless
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// Powernets handling helpers
|
||||
//////////////////////////////////////////////
|
||||
|
||||
//if powernetless_only = 1, will only get connections without powernet
|
||||
/obj/structure/cable/proc/get_connections(powernetless_only = 0)
|
||||
. = list() // this will be a list of all connected power objects
|
||||
var/turf/T
|
||||
|
||||
//get matching cables from the first direction
|
||||
if(d1) //if not a node cable
|
||||
T = get_step(src, d1)
|
||||
if(T)
|
||||
. += power_list(T, src, turn(d1, 180), powernetless_only) //get adjacents matching cables
|
||||
|
||||
if(d1&(d1-1)) //diagonal direction, must check the 4 possibles adjacents tiles
|
||||
T = get_step(src,d1&3) // go north/south
|
||||
if(T)
|
||||
. += power_list(T, src, d1 ^ 3, powernetless_only) //get diagonally matching cables
|
||||
T = get_step(src,d1&12) // go east/west
|
||||
if(T)
|
||||
. += power_list(T, src, d1 ^ 12, powernetless_only) //get diagonally matching cables
|
||||
|
||||
. += power_list(loc, src, d1, powernetless_only) //get on turf matching cables
|
||||
|
||||
//do the same on the second direction (which can't be 0)
|
||||
T = get_step(src, d2)
|
||||
if(T)
|
||||
. += power_list(T, src, turn(d2, 180), powernetless_only) //get adjacents matching cables
|
||||
|
||||
if(d2&(d2-1)) //diagonal direction, must check the 4 possibles adjacents tiles
|
||||
T = get_step(src,d2&3) // go north/south
|
||||
if(T)
|
||||
. += power_list(T, src, d2 ^ 3, powernetless_only) //get diagonally matching cables
|
||||
T = get_step(src,d2&12) // go east/west
|
||||
if(T)
|
||||
. += power_list(T, src, d2 ^ 12, powernetless_only) //get diagonally matching cables
|
||||
. += power_list(loc, src, d2, powernetless_only) //get on turf matching cables
|
||||
|
||||
return .
|
||||
|
||||
//should be called after placing a cable which extends another cable, creating a "smooth" cable that no longer terminates in the centre of a turf.
|
||||
//needed as this can, unlike other placements, disconnect cables
|
||||
/obj/structure/cable/proc/denode()
|
||||
var/turf/T1 = loc
|
||||
if(!T1) return
|
||||
|
||||
var/list/powerlist = power_list(T1,src,0,0) //find the other cables that ended in the centre of the turf, with or without a powernet
|
||||
if(powerlist.len>0)
|
||||
var/datum/powernet/PN = new()
|
||||
propagate_network(powerlist[1],PN) //propagates the new powernet beginning at the source cable
|
||||
|
||||
if(PN.is_empty()) //can happen with machines made nodeless when smoothing cables
|
||||
qdel(PN)
|
||||
|
||||
// cut the cable's powernet at this cable and updates the powergrid
|
||||
/obj/structure/cable/proc/cut_cable_from_powernet()
|
||||
var/turf/T1 = loc
|
||||
var/list/P_list
|
||||
if(!T1)
|
||||
return
|
||||
if(d1)
|
||||
T1 = get_step(T1, d1)
|
||||
P_list = power_list(T1, src, turn(d1,180),0,cable_only = 1) // what adjacently joins on to cut cable...
|
||||
|
||||
P_list += power_list(loc, src, d1, 0, cable_only = 1)//... and on turf
|
||||
|
||||
|
||||
if(P_list.len == 0)//if nothing in both list, then the cable was a lone cable, just delete it and its powernet
|
||||
powernet.remove_cable(src)
|
||||
|
||||
for(var/obj/machinery/power/P in T1)//check if it was powering a machine
|
||||
if(!P.connect_to_network()) //can't find a node cable on a the turf to connect to
|
||||
P.disconnect_from_network() //remove from current network (and delete powernet)
|
||||
return
|
||||
|
||||
var/obj/O = P_list[1]
|
||||
// remove the cut cable from its turf and powernet, so that it doesn't get count in propagate_network worklist
|
||||
loc = null
|
||||
powernet.remove_cable(src) //remove the cut cable from its powernet
|
||||
|
||||
spawn(0) //so we don't rebuild the network X times when singulo/explosion destroys a line of X cables
|
||||
if(O && !qdeleted(O))
|
||||
var/datum/powernet/newPN = new()// creates a new powernet...
|
||||
propagate_network(O, newPN)//... and propagates it to the other side of the cable
|
||||
|
||||
// Disconnect machines connected to nodes
|
||||
if(d1 == 0) // if we cut a node (O-X) cable
|
||||
for(var/obj/machinery/power/P in T1)
|
||||
if(!P.connect_to_network()) //can't find a node cable on a the turf to connect to
|
||||
P.disconnect_from_network() //remove from current network
|
||||
|
||||
///////////////////////////////////////////////
|
||||
// The cable coil object, used for laying cable
|
||||
///////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////
|
||||
// Definitions
|
||||
////////////////////////////////
|
||||
|
||||
var/global/list/datum/stack_recipe/cable_coil_recipes = list ( \
|
||||
new/datum/stack_recipe("cable restraints", /obj/item/weapon/restraints/handcuffs/cable, 15), \
|
||||
)
|
||||
|
||||
/obj/item/stack/cable_coil
|
||||
name = "cable coil"
|
||||
gender = NEUTER //That's a cable coil sounds better than that's some cable coils
|
||||
icon = 'icons/obj/power.dmi'
|
||||
icon_state = "coil_red"
|
||||
item_state = "coil_red"
|
||||
max_amount = MAXCOIL
|
||||
amount = MAXCOIL
|
||||
merge_type = /obj/item/stack/cable_coil // This is here to let its children merge between themselves
|
||||
item_color = "red"
|
||||
desc = "A coil of insulated power cable."
|
||||
throwforce = 0
|
||||
w_class = 2
|
||||
throw_speed = 3
|
||||
throw_range = 5
|
||||
materials = list(MAT_METAL=10, MAT_GLASS=5)
|
||||
flags = CONDUCT
|
||||
slot_flags = SLOT_BELT
|
||||
attack_verb = list("whipped", "lashed", "disciplined", "flogged")
|
||||
singular_name = "cable piece"
|
||||
|
||||
/obj/item/stack/cable_coil/cyborg
|
||||
is_cyborg = 1
|
||||
materials = list()
|
||||
cost = 1
|
||||
|
||||
/obj/item/stack/cable_coil/cyborg/attack_self(mob/user)
|
||||
var/cable_color = input(user,"Pick a cable color.","Cable Color") in list("red","yellow","green","blue","pink","orange","cyan","white")
|
||||
item_color = cable_color
|
||||
update_icon()
|
||||
|
||||
/obj/item/stack/cable_coil/suicide_act(mob/user)
|
||||
if(locate(/obj/structure/chair/stool) in get_turf(user))
|
||||
user.visible_message("<span class='suicide'>[user] is making a noose with the [src.name]! It looks like \he's trying to commit suicide.</span>")
|
||||
else
|
||||
user.visible_message("<span class='suicide'>[user] is strangling \himself with the [src.name]! It looks like \he's trying to commit suicide.</span>")
|
||||
return(OXYLOSS)
|
||||
|
||||
/obj/item/stack/cable_coil/New(loc, amount = MAXCOIL, var/param_color = null)
|
||||
..()
|
||||
src.amount = amount
|
||||
if(param_color)
|
||||
item_color = param_color
|
||||
pixel_x = rand(-2,2)
|
||||
pixel_y = rand(-2,2)
|
||||
update_icon()
|
||||
recipes = cable_coil_recipes
|
||||
|
||||
///////////////////////////////////
|
||||
// General procedures
|
||||
///////////////////////////////////
|
||||
|
||||
//you can use wires to heal robotics
|
||||
/obj/item/stack/cable_coil/attack(mob/living/carbon/human/H, mob/user)
|
||||
if(!istype(H))
|
||||
return ..()
|
||||
|
||||
var/obj/item/bodypart/affecting = H.get_bodypart(check_zone(user.zone_selected))
|
||||
if(affecting && affecting.status == ORGAN_ROBOTIC)
|
||||
user.visible_message("<span class='notice'>[user] starts to fix some of the wires in [H]'s [affecting.name].</span>", "<span class='notice'>You start fixing some of the wires in [H]'s [affecting.name].</span>")
|
||||
if(!do_mob(user, H, 50))
|
||||
return
|
||||
if(item_heal_robotic(H, user, 0, 5))
|
||||
use(1)
|
||||
return
|
||||
else
|
||||
return ..()
|
||||
|
||||
|
||||
/obj/item/stack/cable_coil/update_icon()
|
||||
if(!item_color)
|
||||
item_color = pick("red", "yellow", "blue", "green")
|
||||
item_state = "coil_[item_color]"
|
||||
if(amount == 1)
|
||||
icon_state = "coil_[item_color]1"
|
||||
name = "cable piece"
|
||||
else if(amount == 2)
|
||||
icon_state = "coil_[item_color]2"
|
||||
name = "cable piece"
|
||||
else
|
||||
icon_state = "coil_[item_color]"
|
||||
name = "cable coil"
|
||||
|
||||
/obj/item/stack/cable_coil/attack_hand(mob/user)
|
||||
var/obj/item/stack/cable_coil/new_cable = ..()
|
||||
if(istype(new_cable))
|
||||
new_cable.item_color = item_color
|
||||
new_cable.update_icon()
|
||||
|
||||
//add cables to the stack
|
||||
/obj/item/stack/cable_coil/proc/give(extra)
|
||||
if(amount + extra > max_amount)
|
||||
amount = max_amount
|
||||
else
|
||||
amount += extra
|
||||
update_icon()
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////
|
||||
// Cable laying procedures
|
||||
//////////////////////////////////////////////
|
||||
|
||||
/obj/item/stack/cable_coil/proc/get_new_cable(location)
|
||||
var/path = "/obj/structure/cable" + (item_color == "red" ? "" : "/" + item_color)
|
||||
return new path (location)
|
||||
|
||||
// called when cable_coil is clicked on a turf
|
||||
/obj/item/stack/cable_coil/proc/place_turf(turf/T, mob/user)
|
||||
if(!isturf(user.loc))
|
||||
return
|
||||
|
||||
if(!T.can_have_cabling())
|
||||
user << "<span class='warning'>You can only lay cables on catwalks and plating!</span>"
|
||||
return
|
||||
|
||||
if(get_amount() < 1) // Out of cable
|
||||
user << "<span class='warning'>There is no cable left!</span>"
|
||||
return
|
||||
|
||||
if(get_dist(T,user) > 1) // Too far
|
||||
user << "<span class='warning'>You can't lay cable at a place that far away!</span>"
|
||||
return
|
||||
|
||||
else
|
||||
var/dirn
|
||||
|
||||
if(user.loc == T)
|
||||
dirn = user.dir // if laying on the tile we're on, lay in the direction we're facing
|
||||
else
|
||||
dirn = get_dir(T, user)
|
||||
|
||||
for(var/obj/structure/cable/LC in T)
|
||||
if(LC.d2 == dirn && LC.d1 == 0)
|
||||
user << "<span class='warning'>There's already a cable at that position!</span>"
|
||||
return
|
||||
|
||||
var/obj/structure/cable/C = get_new_cable(T)
|
||||
|
||||
//set up the new cable
|
||||
C.d1 = 0 //it's a O-X node cable
|
||||
C.d2 = dirn
|
||||
C.add_fingerprint(user)
|
||||
C.updateicon()
|
||||
|
||||
//create a new powernet with the cable, if needed it will be merged later
|
||||
var/datum/powernet/PN = new()
|
||||
PN.add_cable(C)
|
||||
|
||||
C.mergeConnectedNetworks(C.d2) //merge the powernet with adjacents powernets
|
||||
C.mergeConnectedNetworksOnTurf() //merge the powernet with on turf powernets
|
||||
|
||||
if(C.d2 & (C.d2 - 1))// if the cable is layed diagonally, check the others 2 possible directions
|
||||
C.mergeDiagonalsNetworks(C.d2)
|
||||
|
||||
|
||||
use(1)
|
||||
|
||||
if (C.shock(user, 50))
|
||||
if (prob(50)) //fail
|
||||
C.Deconstruct()
|
||||
|
||||
// called when cable_coil is click on an installed obj/cable
|
||||
// or click on a turf that already contains a "node" cable
|
||||
/obj/item/stack/cable_coil/proc/cable_join(obj/structure/cable/C, mob/user)
|
||||
var/turf/U = user.loc
|
||||
if(!isturf(U))
|
||||
return
|
||||
|
||||
var/turf/T = C.loc
|
||||
|
||||
if(!isturf(T) || T.intact) // sanity checks, also stop use interacting with T-scanner revealed cable
|
||||
return
|
||||
|
||||
if(get_dist(C, user) > 1) // make sure it's close enough
|
||||
user << "<span class='warning'>You can't lay cable at a place that far away!</span>"
|
||||
return
|
||||
|
||||
|
||||
if(U == T) //if clicked on the turf we're standing on, try to put a cable in the direction we're facing
|
||||
place_turf(T,user)
|
||||
return
|
||||
|
||||
var/dirn = get_dir(C, user)
|
||||
|
||||
// one end of the clicked cable is pointing towards us
|
||||
if(C.d1 == dirn || C.d2 == dirn)
|
||||
if(!U.can_have_cabling()) //checking if it's a plating or catwalk
|
||||
user << "<span class='warning'>You can only lay cables on catwalks and plating!</span>"
|
||||
return
|
||||
if(U.intact) //can't place a cable if it's a plating with a tile on it
|
||||
user << "<span class='warning'>You can't lay cable there unless the floor tiles are removed!</span>"
|
||||
return
|
||||
else
|
||||
// cable is pointing at us, we're standing on an open tile
|
||||
// so create a stub pointing at the clicked cable on our tile
|
||||
|
||||
var/fdirn = turn(dirn, 180) // the opposite direction
|
||||
|
||||
for(var/obj/structure/cable/LC in U) // check to make sure there's not a cable there already
|
||||
if(LC.d1 == fdirn || LC.d2 == fdirn)
|
||||
user << "<span class='warning'>There's already a cable at that position!</span>"
|
||||
return
|
||||
|
||||
var/obj/structure/cable/NC = get_new_cable (U)
|
||||
|
||||
NC.d1 = 0
|
||||
NC.d2 = fdirn
|
||||
NC.add_fingerprint()
|
||||
NC.updateicon()
|
||||
|
||||
//create a new powernet with the cable, if needed it will be merged later
|
||||
var/datum/powernet/newPN = new()
|
||||
newPN.add_cable(NC)
|
||||
|
||||
NC.mergeConnectedNetworks(NC.d2) //merge the powernet with adjacents powernets
|
||||
NC.mergeConnectedNetworksOnTurf() //merge the powernet with on turf powernets
|
||||
|
||||
if(NC.d2 & (NC.d2 - 1))// if the cable is layed diagonally, check the others 2 possible directions
|
||||
NC.mergeDiagonalsNetworks(NC.d2)
|
||||
|
||||
use(1)
|
||||
|
||||
if (NC.shock(user, 50))
|
||||
if (prob(50)) //fail
|
||||
NC.Deconstruct()
|
||||
|
||||
return
|
||||
|
||||
// exisiting cable doesn't point at our position, so see if it's a stub
|
||||
else if(C.d1 == 0)
|
||||
// if so, make it a full cable pointing from it's old direction to our dirn
|
||||
var/nd1 = C.d2 // these will be the new directions
|
||||
var/nd2 = dirn
|
||||
|
||||
|
||||
if(nd1 > nd2) // swap directions to match icons/states
|
||||
nd1 = dirn
|
||||
nd2 = C.d2
|
||||
|
||||
|
||||
for(var/obj/structure/cable/LC in T) // check to make sure there's no matching cable
|
||||
if(LC == C) // skip the cable we're interacting with
|
||||
continue
|
||||
if((LC.d1 == nd1 && LC.d2 == nd2) || (LC.d1 == nd2 && LC.d2 == nd1) ) // make sure no cable matches either direction
|
||||
user << "<span class='warning'>There's already a cable at that position!</span>"
|
||||
return
|
||||
|
||||
|
||||
C.cableColor(item_color)
|
||||
|
||||
C.d1 = nd1
|
||||
C.d2 = nd2
|
||||
|
||||
//updates the stored cable coil
|
||||
C.update_stored(2, item_color)
|
||||
|
||||
C.add_fingerprint()
|
||||
C.updateicon()
|
||||
|
||||
|
||||
C.mergeConnectedNetworks(C.d1) //merge the powernets...
|
||||
C.mergeConnectedNetworks(C.d2) //...in the two new cable directions
|
||||
C.mergeConnectedNetworksOnTurf()
|
||||
|
||||
if(C.d1 & (C.d1 - 1))// if the cable is layed diagonally, check the others 2 possible directions
|
||||
C.mergeDiagonalsNetworks(C.d1)
|
||||
|
||||
if(C.d2 & (C.d2 - 1))// if the cable is layed diagonally, check the others 2 possible directions
|
||||
C.mergeDiagonalsNetworks(C.d2)
|
||||
|
||||
use(1)
|
||||
|
||||
if (C.shock(user, 50))
|
||||
if (prob(50)) //fail
|
||||
C.Deconstruct()
|
||||
return
|
||||
|
||||
C.denode()// this call may have disconnected some cables that terminated on the centre of the turf, if so split the powernets.
|
||||
return
|
||||
|
||||
//////////////////////////////
|
||||
// Misc.
|
||||
/////////////////////////////
|
||||
|
||||
/obj/item/stack/cable_coil/cut
|
||||
item_state = "coil_red2"
|
||||
|
||||
/obj/item/stack/cable_coil/cut/New(loc)
|
||||
..()
|
||||
src.amount = rand(1,2)
|
||||
pixel_x = rand(-2,2)
|
||||
pixel_y = rand(-2,2)
|
||||
update_icon()
|
||||
|
||||
/obj/item/stack/cable_coil/yellow
|
||||
item_color = "yellow"
|
||||
icon_state = "coil_yellow"
|
||||
|
||||
/obj/item/stack/cable_coil/blue
|
||||
item_color = "blue"
|
||||
icon_state = "coil_blue"
|
||||
item_state = "coil_blue"
|
||||
|
||||
/obj/item/stack/cable_coil/green
|
||||
item_color = "green"
|
||||
icon_state = "coil_green"
|
||||
|
||||
/obj/item/stack/cable_coil/pink
|
||||
item_color = "pink"
|
||||
icon_state = "coil_pink"
|
||||
|
||||
/obj/item/stack/cable_coil/orange
|
||||
item_color = "orange"
|
||||
icon_state = "coil_orange"
|
||||
|
||||
/obj/item/stack/cable_coil/cyan
|
||||
item_color = "cyan"
|
||||
icon_state = "coil_cyan"
|
||||
|
||||
/obj/item/stack/cable_coil/white
|
||||
item_color = "white"
|
||||
icon_state = "coil_white"
|
||||
|
||||
/obj/item/stack/cable_coil/random/New()
|
||||
item_color = pick("red","orange","yellow","green","cyan","blue","pink","white")
|
||||
icon_state = "coil_[item_color]"
|
||||
..()
|
||||
@@ -0,0 +1,301 @@
|
||||
/obj/item/weapon/stock_parts/cell
|
||||
name = "power cell"
|
||||
desc = "A rechargable electrochemical power cell."
|
||||
var/ratingdesc
|
||||
icon = 'icons/obj/power.dmi'
|
||||
icon_state = "cell"
|
||||
item_state = "cell"
|
||||
origin_tech = "powerstorage=1"
|
||||
force = 5
|
||||
throwforce = 5
|
||||
throw_speed = 2
|
||||
throw_range = 5
|
||||
w_class = 2
|
||||
var/charge = 0 // note %age conveted to actual charge in New
|
||||
var/maxcharge = 1000
|
||||
materials = list(MAT_METAL=700, MAT_GLASS=50)
|
||||
var/rigged = 0 // true if rigged to explode
|
||||
var/chargerate = 100 //how much power is given every tick in a recharger
|
||||
var/self_recharge = 0 //does it self recharge, over time, or not?
|
||||
|
||||
/obj/item/weapon/stock_parts/cell/New()
|
||||
..()
|
||||
START_PROCESSING(SSobj, src)
|
||||
charge = maxcharge
|
||||
ratingdesc = " This one has a power rating of [maxcharge], and you should not swallow it."
|
||||
desc = desc + ratingdesc
|
||||
updateicon()
|
||||
|
||||
/obj/item/weapon/stock_parts/cell/Destroy()
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
return ..()
|
||||
|
||||
/obj/item/weapon/stock_parts/cell/on_varedit(modified_var)
|
||||
if(modified_var == "self_recharge")
|
||||
if(self_recharge)
|
||||
START_PROCESSING(SSobj, src)
|
||||
else
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
..()
|
||||
|
||||
/obj/item/weapon/stock_parts/cell/process()
|
||||
if(self_recharge)
|
||||
give(chargerate * 0.25)
|
||||
else
|
||||
return PROCESS_KILL
|
||||
|
||||
/obj/item/weapon/stock_parts/cell/proc/updateicon()
|
||||
cut_overlays()
|
||||
if(charge < 0.01)
|
||||
return
|
||||
else if(charge/maxcharge >=0.995)
|
||||
add_overlay(image('icons/obj/power.dmi', "cell-o2"))
|
||||
else
|
||||
add_overlay(image('icons/obj/power.dmi', "cell-o1"))
|
||||
|
||||
/obj/item/weapon/stock_parts/cell/proc/percent() // return % charge of cell
|
||||
return 100*charge/maxcharge
|
||||
|
||||
// use power from a cell
|
||||
/obj/item/weapon/stock_parts/cell/proc/use(amount)
|
||||
if(rigged && amount > 0)
|
||||
explode()
|
||||
return 0
|
||||
if(charge < amount)
|
||||
return 0
|
||||
charge = (charge - amount)
|
||||
if(!istype(loc, /obj/machinery/power/apc))
|
||||
feedback_add_details("cell_used","[src.type]")
|
||||
return 1
|
||||
|
||||
// recharge the cell
|
||||
/obj/item/weapon/stock_parts/cell/proc/give(amount)
|
||||
if(rigged && amount > 0)
|
||||
explode()
|
||||
return 0
|
||||
if(maxcharge < amount)
|
||||
amount = maxcharge
|
||||
var/power_used = min(maxcharge-charge,amount)
|
||||
charge += power_used
|
||||
return power_used
|
||||
|
||||
/obj/item/weapon/stock_parts/cell/examine(mob/user)
|
||||
..()
|
||||
if(rigged)
|
||||
user << "<span class='danger'>This power cell seems to be faulty!</span>"
|
||||
else
|
||||
user << "The charge meter reads [round(src.percent() )]%."
|
||||
|
||||
/obj/item/weapon/stock_parts/cell/suicide_act(mob/user)
|
||||
user.visible_message("<span class='suicide'>[user] is licking the electrodes of the [src.name]! It looks like \he's trying to commit suicide.</span>")
|
||||
return (FIRELOSS)
|
||||
|
||||
/obj/item/weapon/stock_parts/cell/attackby(obj/item/W, mob/user, params)
|
||||
..()
|
||||
if(istype(W, /obj/item/weapon/reagent_containers/syringe))
|
||||
var/obj/item/weapon/reagent_containers/syringe/S = W
|
||||
user << "<span class='notice'>You inject the solution into the power cell.</span>"
|
||||
if(S.reagents.has_reagent("plasma", 5))
|
||||
rigged = 1
|
||||
S.reagents.clear_reagents()
|
||||
|
||||
|
||||
/obj/item/weapon/stock_parts/cell/proc/explode()
|
||||
var/turf/T = get_turf(src.loc)
|
||||
/*
|
||||
* 1000-cell explosion(T, -1, 0, 1, 1)
|
||||
* 2500-cell explosion(T, -1, 0, 1, 1)
|
||||
* 10000-cell explosion(T, -1, 1, 3, 3)
|
||||
* 15000-cell explosion(T, -1, 2, 4, 4)
|
||||
* */
|
||||
if (charge==0)
|
||||
return
|
||||
var/devastation_range = -1 //round(charge/11000)
|
||||
var/heavy_impact_range = round(sqrt(charge)/60)
|
||||
var/light_impact_range = round(sqrt(charge)/30)
|
||||
var/flash_range = light_impact_range
|
||||
if (light_impact_range==0)
|
||||
rigged = 0
|
||||
corrupt()
|
||||
return
|
||||
//explosion(T, 0, 1, 2, 2)
|
||||
explosion(T, devastation_range, heavy_impact_range, light_impact_range, flash_range)
|
||||
qdel(src)
|
||||
|
||||
/obj/item/weapon/stock_parts/cell/proc/corrupt()
|
||||
charge /= 2
|
||||
maxcharge = max(maxcharge/2, chargerate)
|
||||
if (prob(10))
|
||||
rigged = 1 //broken batterys are dangerous
|
||||
|
||||
/obj/item/weapon/stock_parts/cell/emp_act(severity)
|
||||
charge -= 1000 / severity
|
||||
if (charge < 0)
|
||||
charge = 0
|
||||
..()
|
||||
|
||||
/obj/item/weapon/stock_parts/cell/ex_act(severity, target)
|
||||
..()
|
||||
if(!qdeleted(src))
|
||||
switch(severity)
|
||||
if(2)
|
||||
if(prob(50))
|
||||
corrupt()
|
||||
if(3)
|
||||
if(prob(25))
|
||||
corrupt()
|
||||
|
||||
|
||||
/obj/item/weapon/stock_parts/cell/blob_act(obj/effect/blob/B)
|
||||
ex_act(1)
|
||||
|
||||
/obj/item/weapon/stock_parts/cell/proc/get_electrocute_damage()
|
||||
if(charge >= 1000)
|
||||
return Clamp(round(charge/10000), 10, 90) + rand(-5,5)
|
||||
else
|
||||
return 0
|
||||
|
||||
/* Cell variants*/
|
||||
/obj/item/weapon/stock_parts/cell/crap
|
||||
name = "\improper Nanotrasen brand rechargable AA battery"
|
||||
desc = "You can't top the plasma top." //TOTALLY TRADEMARK INFRINGEMENT
|
||||
maxcharge = 500
|
||||
materials = list(MAT_GLASS=40)
|
||||
rating = 2
|
||||
|
||||
/obj/item/weapon/stock_parts/cell/crap/empty/New()
|
||||
..()
|
||||
charge = 0
|
||||
|
||||
/obj/item/weapon/stock_parts/cell/secborg
|
||||
name = "security borg rechargable D battery"
|
||||
origin_tech = null
|
||||
maxcharge = 600 //600 max charge / 100 charge per shot = six shots
|
||||
materials = list(MAT_GLASS=40)
|
||||
rating = 2.5
|
||||
|
||||
/obj/item/weapon/stock_parts/cell/secborg/empty/New()
|
||||
..()
|
||||
charge = 0
|
||||
|
||||
/obj/item/weapon/stock_parts/cell/pulse //200 pulse shots
|
||||
name = "pulse rifle power cell"
|
||||
maxcharge = 40000
|
||||
rating = 3
|
||||
chargerate = 1500
|
||||
|
||||
/obj/item/weapon/stock_parts/cell/pulse/carbine //25 pulse shots
|
||||
name = "pulse carbine power cell"
|
||||
maxcharge = 5000
|
||||
|
||||
/obj/item/weapon/stock_parts/cell/pulse/pistol //10 pulse shots
|
||||
name = "pulse pistol power cell"
|
||||
maxcharge = 2000
|
||||
|
||||
/obj/item/weapon/stock_parts/cell/high
|
||||
name = "high-capacity power cell"
|
||||
origin_tech = "powerstorage=2"
|
||||
icon_state = "hcell"
|
||||
maxcharge = 10000
|
||||
materials = list(MAT_GLASS=60)
|
||||
rating = 3
|
||||
chargerate = 1500
|
||||
|
||||
/obj/item/weapon/stock_parts/cell/high/plus
|
||||
name = "high-capacity power cell+"
|
||||
desc = "Where did these come from?"
|
||||
icon_state = "h+cell"
|
||||
maxcharge = 15000
|
||||
chargerate = 2250
|
||||
|
||||
/obj/item/weapon/stock_parts/cell/high/empty/New()
|
||||
..()
|
||||
charge = 0
|
||||
|
||||
/obj/item/weapon/stock_parts/cell/super
|
||||
name = "super-capacity power cell"
|
||||
origin_tech = "powerstorage=3;materials=3"
|
||||
icon_state = "scell"
|
||||
maxcharge = 20000
|
||||
materials = list(MAT_GLASS=300)
|
||||
rating = 4
|
||||
chargerate = 2000
|
||||
|
||||
/obj/item/weapon/stock_parts/cell/super/empty/New()
|
||||
..()
|
||||
charge = 0
|
||||
|
||||
/obj/item/weapon/stock_parts/cell/hyper
|
||||
name = "hyper-capacity power cell"
|
||||
origin_tech = "powerstorage=4;engineering=4;materials=4"
|
||||
icon_state = "hpcell"
|
||||
maxcharge = 30000
|
||||
materials = list(MAT_GLASS=400)
|
||||
rating = 5
|
||||
chargerate = 3000
|
||||
|
||||
/obj/item/weapon/stock_parts/cell/hyper/empty/New()
|
||||
..()
|
||||
charge = 0
|
||||
|
||||
/obj/item/weapon/stock_parts/cell/bluespace
|
||||
name = "bluespace power cell"
|
||||
desc = "A rechargable transdimensional power cell."
|
||||
origin_tech = "powerstorage=5;bluespace=4;materials=4;engineering=4"
|
||||
icon_state = "bscell"
|
||||
maxcharge = 40000
|
||||
materials = list(MAT_GLASS=600)
|
||||
rating = 6
|
||||
chargerate = 4000
|
||||
|
||||
/obj/item/weapon/stock_parts/cell/bluespace/empty/New()
|
||||
..()
|
||||
charge = 0
|
||||
|
||||
/obj/item/weapon/stock_parts/cell/infinite
|
||||
name = "infinite-capacity power cell!"
|
||||
icon_state = "icell"
|
||||
origin_tech = "powerstorage=7"
|
||||
maxcharge = 30000
|
||||
materials = list(MAT_GLASS=1000)
|
||||
rating = 6
|
||||
chargerate = 30000
|
||||
|
||||
/obj/item/weapon/stock_parts/cell/infinite/use()
|
||||
return 1
|
||||
|
||||
/obj/item/weapon/stock_parts/cell/potato
|
||||
name = "potato battery"
|
||||
desc = "A rechargable starch based power cell."
|
||||
icon = 'icons/obj/power.dmi' //'icons/obj/hydroponics/harvest.dmi'
|
||||
icon_state = "potato_cell" //"potato_battery"
|
||||
origin_tech = "powerstorage=1;biotech=1"
|
||||
charge = 100
|
||||
maxcharge = 300
|
||||
materials = list()
|
||||
rating = 1
|
||||
|
||||
/obj/item/weapon/stock_parts/cell/high/slime
|
||||
name = "charged slime core"
|
||||
desc = "A yellow slime core infused with plasma, it crackles with power."
|
||||
origin_tech = "powerstorage=5;biotech=4"
|
||||
icon = 'icons/mob/slimes.dmi'
|
||||
icon_state = "yellow slime extract"
|
||||
materials = list()
|
||||
self_recharge = 1 // Infused slime cores self-recharge, over time
|
||||
|
||||
/obj/item/weapon/stock_parts/cell/emproof
|
||||
name = "\improper EMP-proof cell"
|
||||
desc = "An EMP-proof cell."
|
||||
maxcharge = 500
|
||||
rating = 2
|
||||
|
||||
/obj/item/weapon/stock_parts/cell/emproof/empty/New()
|
||||
..()
|
||||
charge = 0
|
||||
|
||||
/obj/item/weapon/stock_parts/cell/emproof/emp_act(severity)
|
||||
return
|
||||
|
||||
/obj/item/weapon/stock_parts/cell/emproof/corrupt()
|
||||
return
|
||||
@@ -0,0 +1,16 @@
|
||||
/turf/open/floor/engine/attack_paw(mob/user)
|
||||
return src.attack_hand(user)
|
||||
|
||||
/turf/open/floor/engine/attack_hand(mob/user)
|
||||
user.Move_Pulled(src)
|
||||
|
||||
/turf/open/floor/engine/ex_act(severity, target)
|
||||
contents_explosion(severity, target)
|
||||
switch(severity)
|
||||
if(1)
|
||||
ChangeTurf(src.baseturf)
|
||||
if(2)
|
||||
if(prob(50))
|
||||
ChangeTurf(src.baseturf)
|
||||
else
|
||||
return
|
||||
@@ -0,0 +1,199 @@
|
||||
// dummy generator object for testing
|
||||
|
||||
/*/obj/machinery/power/generator/verb/set_amount(var/g as num)
|
||||
set src in view(1)
|
||||
|
||||
gen_amount = g
|
||||
|
||||
*/
|
||||
|
||||
/obj/machinery/power/generator
|
||||
name = "thermoelectric generator"
|
||||
desc = "It's a high efficiency thermoelectric generator."
|
||||
icon_state = "teg"
|
||||
anchored = 1
|
||||
density = 1
|
||||
use_power = 0
|
||||
|
||||
var/obj/machinery/atmospherics/components/binary/circulator/cold_circ
|
||||
var/obj/machinery/atmospherics/components/binary/circulator/hot_circ
|
||||
|
||||
//note: these currently only support EAST and WEST
|
||||
var/cold_dir = WEST
|
||||
var/hot_dir = EAST
|
||||
|
||||
var/lastgen = 0
|
||||
var/lastgenlev = -1
|
||||
var/lastcirc = "00"
|
||||
|
||||
|
||||
/obj/machinery/power/generator/initialize()
|
||||
var/obj/machinery/atmospherics/components/binary/circulator/circpath = /obj/machinery/atmospherics/components/binary/circulator
|
||||
cold_circ = locate(circpath) in get_step(src, cold_dir)
|
||||
hot_circ = locate(circpath) in get_step(src, hot_dir)
|
||||
connect_to_network()
|
||||
|
||||
if(cold_circ)
|
||||
switch(cold_dir)
|
||||
if(EAST)
|
||||
cold_circ.side = circpath.CIRC_RIGHT
|
||||
if(WEST)
|
||||
cold_circ.side = circpath.CIRC_LEFT
|
||||
cold_circ.update_icon()
|
||||
|
||||
if(hot_circ)
|
||||
switch(hot_dir)
|
||||
if(EAST)
|
||||
hot_circ.side = circpath.CIRC_RIGHT
|
||||
if(WEST)
|
||||
hot_circ.side = circpath.CIRC_LEFT
|
||||
hot_circ.update_icon()
|
||||
|
||||
if(!cold_circ || !hot_circ)
|
||||
stat |= BROKEN
|
||||
|
||||
update_icon()
|
||||
|
||||
|
||||
/obj/machinery/power/generator/update_icon()
|
||||
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
cut_overlays()
|
||||
else
|
||||
cut_overlays()
|
||||
|
||||
if(lastgenlev != 0)
|
||||
add_overlay(image('icons/obj/power.dmi', "teg-op[lastgenlev]"))
|
||||
|
||||
add_overlay(image('icons/obj/power.dmi', "teg-oc[lastcirc]"))
|
||||
|
||||
|
||||
#define GENRATE 800 // generator output coefficient from Q
|
||||
|
||||
/obj/machinery/power/generator/process()
|
||||
|
||||
if(!cold_circ || !hot_circ)
|
||||
return
|
||||
|
||||
lastgen = 0
|
||||
|
||||
if(powernet)
|
||||
//world << "cold_circ and hot_circ pass"
|
||||
|
||||
var/datum/gas_mixture/cold_air = cold_circ.return_transfer_air()
|
||||
var/datum/gas_mixture/hot_air = hot_circ.return_transfer_air()
|
||||
|
||||
//world << "hot_air = [hot_air]; cold_air = [cold_air];"
|
||||
|
||||
if(cold_air && hot_air)
|
||||
|
||||
//world << "hot_air = [hot_air] temperature = [hot_air.temperature]; cold_air = [cold_air] temperature = [hot_air.temperature];"
|
||||
|
||||
//world << "coldair and hotair pass"
|
||||
var/cold_air_heat_capacity = cold_air.heat_capacity()
|
||||
var/hot_air_heat_capacity = hot_air.heat_capacity()
|
||||
|
||||
var/delta_temperature = hot_air.temperature - cold_air.temperature
|
||||
|
||||
//world << "delta_temperature = [delta_temperature]; cold_air_heat_capacity = [cold_air_heat_capacity]; hot_air_heat_capacity = [hot_air_heat_capacity]"
|
||||
|
||||
if(delta_temperature > 0 && cold_air_heat_capacity > 0 && hot_air_heat_capacity > 0)
|
||||
var/efficiency = 0.65
|
||||
|
||||
var/energy_transfer = delta_temperature*hot_air_heat_capacity*cold_air_heat_capacity/(hot_air_heat_capacity+cold_air_heat_capacity)
|
||||
|
||||
var/heat = energy_transfer*(1-efficiency)
|
||||
lastgen = energy_transfer*efficiency
|
||||
|
||||
//world << "lastgen = [lastgen]; heat = [heat]; delta_temperature = [delta_temperature]; hot_air_heat_capacity = [hot_air_heat_capacity]; cold_air_heat_capacity = [cold_air_heat_capacity];"
|
||||
|
||||
hot_air.temperature = hot_air.temperature - energy_transfer/hot_air_heat_capacity
|
||||
cold_air.temperature = cold_air.temperature + heat/cold_air_heat_capacity
|
||||
|
||||
//world << "POWER: [lastgen] W generated at [efficiency*100]% efficiency and sinks sizes [cold_air_heat_capacity], [hot_air_heat_capacity]"
|
||||
|
||||
add_avail(lastgen)
|
||||
// update icon overlays only if displayed level has changed
|
||||
|
||||
if(hot_air)
|
||||
var/datum/gas_mixture/hot_circ_air1 = hot_circ.AIR1
|
||||
hot_circ_air1.merge(hot_air)
|
||||
|
||||
if(cold_air)
|
||||
var/datum/gas_mixture/cold_circ_air1 = cold_circ.AIR1
|
||||
cold_circ_air1.merge(cold_air)
|
||||
|
||||
var/genlev = max(0, min( round(11*lastgen / 100000), 11))
|
||||
var/circ = "[cold_circ && cold_circ.last_pressure_delta > 0 ? "1" : "0"][hot_circ && hot_circ.last_pressure_delta > 0 ? "1" : "0"]"
|
||||
if((genlev != lastgenlev) || (circ != lastcirc))
|
||||
lastgenlev = genlev
|
||||
lastcirc = circ
|
||||
update_icon()
|
||||
|
||||
src.updateDialog()
|
||||
|
||||
/obj/machinery/power/generator/attack_hand(mob/user)
|
||||
if(..())
|
||||
user << browse(null, "window=teg")
|
||||
return
|
||||
interact(user)
|
||||
|
||||
/obj/machinery/power/generator/proc/get_menu(include_link = 1)
|
||||
var/t = ""
|
||||
if(!powernet)
|
||||
t += "<span class='bad'>Unable to connect to the power network!</span>"
|
||||
else if(cold_circ && hot_circ)
|
||||
var/datum/gas_mixture/cold_circ_air1 = cold_circ.AIR1
|
||||
var/datum/gas_mixture/cold_circ_air2 = cold_circ.AIR2
|
||||
var/datum/gas_mixture/hot_circ_air1 = hot_circ.AIR1
|
||||
var/datum/gas_mixture/hot_circ_air2 = hot_circ.AIR2
|
||||
|
||||
t += "<div class='statusDisplay'>"
|
||||
|
||||
t += "Output: [round(lastgen)] W"
|
||||
|
||||
t += "<BR>"
|
||||
|
||||
t += "<B><font color='blue'>Cold loop</font></B><BR>"
|
||||
t += "Temperature Inlet: [round(cold_circ_air2.temperature, 0.1)] K / Outlet: [round(cold_circ_air1.temperature, 0.1)] K<BR>"
|
||||
t += "Pressure Inlet: [round(cold_circ_air2.return_pressure(), 0.1)] kPa / Outlet: [round(cold_circ_air1.return_pressure(), 0.1)] kPa<BR>"
|
||||
|
||||
t += "<B><font color='red'>Hot loop</font></B><BR>"
|
||||
t += "Temperature Inlet: [round(hot_circ_air2.temperature, 0.1)] K / Outlet: [round(hot_circ_air1.temperature, 0.1)] K<BR>"
|
||||
t += "Pressure Inlet: [round(hot_circ_air2.return_pressure(), 0.1)] kPa / Outlet: [round(hot_circ_air1.return_pressure(), 0.1)] kPa<BR>"
|
||||
|
||||
t += "</div>"
|
||||
else
|
||||
t += "<span class='bad'>Unable to locate all parts!</span>"
|
||||
if(include_link)
|
||||
t += "<BR><A href='?src=\ref[src];close=1'>Close</A>"
|
||||
|
||||
return t
|
||||
|
||||
/obj/machinery/power/generator/interact(mob/user)
|
||||
|
||||
user.set_machine(src)
|
||||
|
||||
//user << browse(t, "window=teg;size=460x300")
|
||||
//onclose(user, "teg")
|
||||
|
||||
var/datum/browser/popup = new(user, "teg", "Thermo-Electric Generator", 460, 300)
|
||||
popup.set_content(get_menu())
|
||||
popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state))
|
||||
popup.open()
|
||||
return 1
|
||||
|
||||
|
||||
/obj/machinery/power/generator/Topic(href, href_list)
|
||||
if(..())
|
||||
return
|
||||
if( href_list["close"] )
|
||||
usr << browse(null, "window=teg")
|
||||
usr.unset_machine()
|
||||
return 0
|
||||
return 1
|
||||
|
||||
|
||||
/obj/machinery/power/generator/power_change()
|
||||
..()
|
||||
update_icon()
|
||||
@@ -0,0 +1,409 @@
|
||||
|
||||
//
|
||||
// Gravity Generator
|
||||
//
|
||||
|
||||
var/list/gravity_generators = list() // We will keep track of this by adding new gravity generators to the list, and keying it with the z level.
|
||||
|
||||
var/const/POWER_IDLE = 0
|
||||
var/const/POWER_UP = 1
|
||||
var/const/POWER_DOWN = 2
|
||||
|
||||
var/const/GRAV_NEEDS_SCREWDRIVER = 0
|
||||
var/const/GRAV_NEEDS_WELDING = 1
|
||||
var/const/GRAV_NEEDS_PLASTEEL = 2
|
||||
var/const/GRAV_NEEDS_WRENCH = 3
|
||||
|
||||
//
|
||||
// Abstract Generator
|
||||
//
|
||||
|
||||
/obj/machinery/gravity_generator
|
||||
name = "gravitational generator"
|
||||
desc = "A device which produces a gravaton field when set up."
|
||||
icon = 'icons/obj/machines/gravity_generator.dmi'
|
||||
anchored = 1
|
||||
density = 1
|
||||
use_power = 0
|
||||
unacidable = 1
|
||||
var/sprite_number = 0
|
||||
|
||||
/obj/machinery/gravity_generator/ex_act(severity, target)
|
||||
if(severity == 1) // Very sturdy.
|
||||
set_broken()
|
||||
|
||||
/obj/machinery/gravity_generator/blob_act(obj/effect/blob/B)
|
||||
if(prob(20))
|
||||
set_broken()
|
||||
|
||||
/obj/machinery/gravity_generator/update_icon()
|
||||
..()
|
||||
icon_state = "[get_status()]_[sprite_number]"
|
||||
|
||||
//prevents shuttles attempting to rotate this since it messes up sprites
|
||||
/obj/machinery/gravity_generator/shuttleRotate()
|
||||
return
|
||||
|
||||
/obj/machinery/gravity_generator/proc/get_status()
|
||||
return "off"
|
||||
|
||||
// You aren't allowed to move.
|
||||
/obj/machinery/gravity_generator/Move()
|
||||
..()
|
||||
qdel(src)
|
||||
|
||||
/obj/machinery/gravity_generator/proc/set_broken()
|
||||
stat |= BROKEN
|
||||
|
||||
/obj/machinery/gravity_generator/proc/set_fix()
|
||||
stat &= ~BROKEN
|
||||
|
||||
/obj/machinery/gravity_generator/part/Destroy()
|
||||
set_broken()
|
||||
if(main_part)
|
||||
qdel(main_part)
|
||||
return ..()
|
||||
|
||||
//
|
||||
// Part generator which is mostly there for looks
|
||||
//
|
||||
|
||||
/obj/machinery/gravity_generator/part
|
||||
var/obj/machinery/gravity_generator/main/main_part = null
|
||||
|
||||
/obj/machinery/gravity_generator/part/attackby(obj/item/I, mob/user, params)
|
||||
return main_part.attackby(I, user)
|
||||
|
||||
/obj/machinery/gravity_generator/part/get_status()
|
||||
return main_part.get_status()
|
||||
|
||||
/obj/machinery/gravity_generator/part/attack_hand(mob/user)
|
||||
return main_part.attack_hand(user)
|
||||
|
||||
/obj/machinery/gravity_generator/part/set_broken()
|
||||
..()
|
||||
if(main_part && !(main_part.stat & BROKEN))
|
||||
main_part.set_broken()
|
||||
|
||||
//
|
||||
// Generator which spawns with the station.
|
||||
//
|
||||
|
||||
/obj/machinery/gravity_generator/main/station/initialize()
|
||||
setup_parts()
|
||||
middle.add_overlay("activated")
|
||||
update_list()
|
||||
|
||||
//
|
||||
// Generator an admin can spawn
|
||||
//
|
||||
/obj/machinery/gravity_generator/main/station/admin
|
||||
use_power = 0
|
||||
|
||||
/obj/machinery/gravity_generator/main/station/admin/New()
|
||||
..()
|
||||
initialize()
|
||||
|
||||
//
|
||||
// Main Generator with the main code
|
||||
//
|
||||
|
||||
/obj/machinery/gravity_generator/main
|
||||
icon_state = "on_8"
|
||||
idle_power_usage = 0
|
||||
active_power_usage = 3000
|
||||
power_channel = ENVIRON
|
||||
sprite_number = 8
|
||||
use_power = 1
|
||||
interact_offline = 1
|
||||
var/on = 1
|
||||
var/breaker = 1
|
||||
var/list/parts = list()
|
||||
var/obj/middle = null
|
||||
var/charging_state = POWER_IDLE
|
||||
var/charge_count = 100
|
||||
var/current_overlay = null
|
||||
var/broken_state = 0
|
||||
|
||||
/obj/machinery/gravity_generator/main/Destroy() // If we somehow get deleted, remove all of our other parts.
|
||||
investigate_log("was destroyed!", "gravity")
|
||||
on = 0
|
||||
update_list()
|
||||
for(var/obj/machinery/gravity_generator/part/O in parts)
|
||||
O.main_part = null
|
||||
qdel(O)
|
||||
return ..()
|
||||
|
||||
/obj/machinery/gravity_generator/main/proc/setup_parts()
|
||||
var/turf/our_turf = get_turf(src)
|
||||
// 9x9 block obtained from the bottom middle of the block
|
||||
var/list/spawn_turfs = block(locate(our_turf.x - 1, our_turf.y + 2, our_turf.z), locate(our_turf.x + 1, our_turf.y, our_turf.z))
|
||||
var/count = 10
|
||||
for(var/turf/T in spawn_turfs)
|
||||
count--
|
||||
if(T == our_turf) // Skip our turf.
|
||||
continue
|
||||
var/obj/machinery/gravity_generator/part/part = new(T)
|
||||
if(count == 5) // Middle
|
||||
middle = part
|
||||
if(count <= 3) // Their sprite is the top part of the generator
|
||||
part.density = 0
|
||||
part.layer = WALL_OBJ_LAYER
|
||||
part.sprite_number = count
|
||||
part.main_part = src
|
||||
parts += part
|
||||
part.update_icon()
|
||||
|
||||
/obj/machinery/gravity_generator/main/proc/connected_parts()
|
||||
return parts.len == 8
|
||||
|
||||
/obj/machinery/gravity_generator/main/set_broken()
|
||||
..()
|
||||
for(var/obj/machinery/gravity_generator/M in parts)
|
||||
if(!(M.stat & BROKEN))
|
||||
M.set_broken()
|
||||
middle.cut_overlays()
|
||||
charge_count = 0
|
||||
breaker = 0
|
||||
set_power()
|
||||
set_state(0)
|
||||
investigate_log("has broken down.", "gravity")
|
||||
|
||||
/obj/machinery/gravity_generator/main/set_fix()
|
||||
..()
|
||||
for(var/obj/machinery/gravity_generator/M in parts)
|
||||
if(M.stat & BROKEN)
|
||||
M.set_fix()
|
||||
broken_state = 0
|
||||
update_icon()
|
||||
set_power()
|
||||
|
||||
// Interaction
|
||||
|
||||
// Fixing the gravity generator.
|
||||
/obj/machinery/gravity_generator/main/attackby(obj/item/I, mob/user, params)
|
||||
switch(broken_state)
|
||||
if(GRAV_NEEDS_SCREWDRIVER)
|
||||
if(istype(I, /obj/item/weapon/screwdriver))
|
||||
user << "<span class='notice'>You secure the screws of the framework.</span>"
|
||||
playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1)
|
||||
broken_state++
|
||||
update_icon()
|
||||
return
|
||||
if(GRAV_NEEDS_WELDING)
|
||||
if(istype(I, /obj/item/weapon/weldingtool))
|
||||
var/obj/item/weapon/weldingtool/WT = I
|
||||
if(WT.remove_fuel(1, user))
|
||||
user << "<span class='notice'>You mend the damaged framework.</span>"
|
||||
playsound(src.loc, 'sound/items/Welder2.ogg', 50, 1)
|
||||
broken_state++
|
||||
update_icon()
|
||||
else if(WT.isOn())
|
||||
user << "<span class='warning'>You don't have enough fuel to mend the damaged framework!</span>"
|
||||
return
|
||||
if(GRAV_NEEDS_PLASTEEL)
|
||||
if(istype(I, /obj/item/stack/sheet/plasteel))
|
||||
var/obj/item/stack/sheet/plasteel/PS = I
|
||||
if(PS.amount >= 10)
|
||||
PS.use(10)
|
||||
user << "<span class='notice'>You add the plating to the framework.</span>"
|
||||
playsound(src.loc, 'sound/machines/click.ogg', 75, 1)
|
||||
broken_state++
|
||||
update_icon()
|
||||
else
|
||||
user << "<span class='warning'>You need 10 sheets of plasteel!</span>"
|
||||
return
|
||||
if(GRAV_NEEDS_WRENCH)
|
||||
if(istype(I, /obj/item/weapon/wrench))
|
||||
user << "<span class='notice'>You secure the plating to the framework.</span>"
|
||||
playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1)
|
||||
set_fix()
|
||||
return
|
||||
return ..()
|
||||
|
||||
|
||||
/obj/machinery/gravity_generator/main/attack_hand(mob/user)
|
||||
if(!..())
|
||||
return interact(user)
|
||||
|
||||
/obj/machinery/gravity_generator/main/interact(mob/user)
|
||||
if(stat & BROKEN)
|
||||
return
|
||||
var/dat = "Gravity Generator Breaker: "
|
||||
if(breaker)
|
||||
dat += "<span class='linkOn'>ON</span> <A href='?src=\ref[src];gentoggle=1'>OFF</A>"
|
||||
else
|
||||
dat += "<A href='?src=\ref[src];gentoggle=1'>ON</A> <span class='linkOn'>OFF</span> "
|
||||
|
||||
dat += "<br>Generator Status:<br><div class='statusDisplay'>"
|
||||
if(charging_state != POWER_IDLE)
|
||||
dat += "<font class='bad'>WARNING</font> Radiation Detected. <br>[charging_state == POWER_UP ? "Charging..." : "Discharging..."]"
|
||||
else if(on)
|
||||
dat += "Powered."
|
||||
else
|
||||
dat += "Unpowered."
|
||||
|
||||
dat += "<br>Gravity Charge: [charge_count]%</div>"
|
||||
|
||||
var/datum/browser/popup = new(user, "gravgen", name)
|
||||
popup.set_content(dat)
|
||||
popup.open()
|
||||
|
||||
|
||||
/obj/machinery/gravity_generator/main/Topic(href, href_list)
|
||||
|
||||
if(..())
|
||||
return
|
||||
|
||||
if(href_list["gentoggle"])
|
||||
breaker = !breaker
|
||||
investigate_log("was toggled [breaker ? "<font color='green'>ON</font>" : "<font color='red'>OFF</font>"] by [usr.key].", "gravity")
|
||||
set_power()
|
||||
src.updateUsrDialog()
|
||||
|
||||
// Power and Icon States
|
||||
|
||||
/obj/machinery/gravity_generator/main/power_change()
|
||||
..()
|
||||
investigate_log("has [stat & NOPOWER ? "lost" : "regained"] power.", "gravity")
|
||||
set_power()
|
||||
|
||||
/obj/machinery/gravity_generator/main/get_status()
|
||||
if(stat & BROKEN)
|
||||
return "fix[min(broken_state, 3)]"
|
||||
return on || charging_state != POWER_IDLE ? "on" : "off"
|
||||
|
||||
/obj/machinery/gravity_generator/main/update_icon()
|
||||
..()
|
||||
for(var/obj/O in parts)
|
||||
O.update_icon()
|
||||
|
||||
// Set the charging state based on power/breaker.
|
||||
/obj/machinery/gravity_generator/main/proc/set_power()
|
||||
var/new_state = 0
|
||||
if(stat & (NOPOWER|BROKEN) || !breaker)
|
||||
new_state = 0
|
||||
else if(breaker)
|
||||
new_state = 1
|
||||
|
||||
charging_state = new_state ? POWER_UP : POWER_DOWN // Startup sequence animation.
|
||||
investigate_log("is now [charging_state == POWER_UP ? "charging" : "discharging"].", "gravity")
|
||||
update_icon()
|
||||
|
||||
// Set the state of the gravity.
|
||||
/obj/machinery/gravity_generator/main/proc/set_state(new_state)
|
||||
charging_state = POWER_IDLE
|
||||
on = new_state
|
||||
use_power = on ? 2 : 1
|
||||
// Sound the alert if gravity was just enabled or disabled.
|
||||
var/alert = 0
|
||||
var/area/area = get_area(src)
|
||||
if(on && ticker && ticker.current_state == GAME_STATE_PLAYING) // If we turned on and the game is live.
|
||||
if(gravity_in_level() == 0)
|
||||
alert = 1
|
||||
investigate_log("was brought online and is now producing gravity for this level.", "gravity")
|
||||
message_admins("The gravity generator was brought online. (<A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[x];Y=[y];Z=[z]'>[area.name]</a>)")
|
||||
else
|
||||
if(gravity_in_level() == 1)
|
||||
alert = 1
|
||||
investigate_log("was brought offline and there is now no gravity for this level.", "gravity")
|
||||
message_admins("The gravity generator was brought offline with no backup generator. (<A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[x];Y=[y];Z=[z]'>[area.name]</a>)")
|
||||
|
||||
update_icon()
|
||||
update_list()
|
||||
src.updateUsrDialog()
|
||||
if(alert)
|
||||
shake_everyone()
|
||||
|
||||
// Charge/Discharge and turn on/off gravity when you reach 0/100 percent.
|
||||
// Also emit radiation and handle the overlays.
|
||||
/obj/machinery/gravity_generator/main/process()
|
||||
if(stat & BROKEN)
|
||||
return
|
||||
if(charging_state != POWER_IDLE)
|
||||
if(charging_state == POWER_UP && charge_count >= 100)
|
||||
set_state(1)
|
||||
else if(charging_state == POWER_DOWN && charge_count <= 0)
|
||||
set_state(0)
|
||||
else
|
||||
if(charging_state == POWER_UP)
|
||||
charge_count += 2
|
||||
else if(charging_state == POWER_DOWN)
|
||||
charge_count -= 2
|
||||
|
||||
if(charge_count % 4 == 0 && prob(75)) // Let them know it is charging/discharging.
|
||||
playsound(src.loc, 'sound/effects/EMPulse.ogg', 100, 1)
|
||||
|
||||
updateDialog()
|
||||
if(prob(25)) // To help stop "Your clothes feel warm." spam.
|
||||
pulse_radiation()
|
||||
|
||||
var/overlay_state = null
|
||||
switch(charge_count)
|
||||
if(0 to 20)
|
||||
overlay_state = null
|
||||
if(21 to 40)
|
||||
overlay_state = "startup"
|
||||
if(41 to 60)
|
||||
overlay_state = "idle"
|
||||
if(61 to 80)
|
||||
overlay_state = "activating"
|
||||
if(81 to 100)
|
||||
overlay_state = "activated"
|
||||
|
||||
if(overlay_state != current_overlay)
|
||||
if(middle)
|
||||
middle.cut_overlays()
|
||||
if(overlay_state)
|
||||
middle.add_overlay(overlay_state)
|
||||
current_overlay = overlay_state
|
||||
|
||||
|
||||
/obj/machinery/gravity_generator/main/proc/pulse_radiation()
|
||||
radiation_pulse(get_turf(src), 3, 7, 20)
|
||||
|
||||
// Shake everyone on the z level to let them know that gravity was enagaged/disenagaged.
|
||||
/obj/machinery/gravity_generator/main/proc/shake_everyone()
|
||||
var/turf/T = get_turf(src)
|
||||
for(var/mob/M in mob_list)
|
||||
if(M.z != z)
|
||||
continue
|
||||
M.update_gravity(M.mob_has_gravity())
|
||||
if(M.client)
|
||||
shake_camera(M, 15, 1)
|
||||
M.playsound_local(T, 'sound/effects/alert.ogg', 100, 1, 0.5)
|
||||
|
||||
/obj/machinery/gravity_generator/main/proc/gravity_in_level()
|
||||
var/turf/T = get_turf(src)
|
||||
if(!T)
|
||||
return 0
|
||||
if(gravity_generators["[T.z]"])
|
||||
return length(gravity_generators["[T.z]"])
|
||||
return 0
|
||||
|
||||
/obj/machinery/gravity_generator/main/proc/update_list()
|
||||
var/turf/T = get_turf(src.loc)
|
||||
if(T)
|
||||
if(!gravity_generators["[T.z]"])
|
||||
gravity_generators["[T.z]"] = list()
|
||||
if(on)
|
||||
gravity_generators["[T.z]"] |= src
|
||||
else
|
||||
gravity_generators["[T.z]"] -= src
|
||||
|
||||
// Misc
|
||||
|
||||
/obj/item/weapon/paper/gravity_gen
|
||||
name = "paper- 'Generate your own gravity!'"
|
||||
info = {"<h1>Gravity Generator Instructions For Dummies</h1>
|
||||
<p>Surprisingly, gravity isn't that hard to make! All you have to do is inject deadly radioactive minerals into a ball of
|
||||
energy and you have yourself gravity! You can turn the machine on or off when required but you must remember that the generator
|
||||
will EMIT RADIATION when charging or discharging, you can tell it is charging or discharging by the noise it makes, so please WEAR PROTECTIVE CLOTHING.</p>
|
||||
<br>
|
||||
<h3>It blew up!</h3>
|
||||
<p>Don't panic! The gravity generator was designed to be easily repaired. If, somehow, the sturdy framework did not survive then
|
||||
please proceed to panic; otherwise follow these steps.</p><ol>
|
||||
<li>Secure the screws of the framework with a screwdriver.</li>
|
||||
<li>Mend the damaged framework with a welding tool.</li>
|
||||
<li>Add additional plasteel plating.</li>
|
||||
<li>Secure the additional plating with a wrench.</li></ol>"}
|
||||
@@ -0,0 +1,638 @@
|
||||
// The lighting system
|
||||
//
|
||||
// consists of light fixtures (/obj/machinery/light) and light tube/bulb items (/obj/item/weapon/light)
|
||||
|
||||
|
||||
// status values shared between lighting fixtures and items
|
||||
#define LIGHT_OK 0
|
||||
#define LIGHT_EMPTY 1
|
||||
#define LIGHT_BROKEN 2
|
||||
#define LIGHT_BURNED 3
|
||||
|
||||
|
||||
|
||||
/obj/item/wallframe/light_fixture
|
||||
name = "light fixture frame"
|
||||
desc = "Used for building lights."
|
||||
icon = 'icons/obj/lighting.dmi'
|
||||
icon_state = "tube-construct-item"
|
||||
result_path = /obj/machinery/light_construct
|
||||
inverse = 1
|
||||
|
||||
/obj/item/wallframe/light_fixture/small
|
||||
name = "small light fixture frame"
|
||||
icon_state = "bulb-construct-item"
|
||||
result_path = /obj/machinery/light_construct/small
|
||||
materials = list(MAT_METAL=MINERAL_MATERIAL_AMOUNT)
|
||||
|
||||
|
||||
/obj/machinery/light_construct
|
||||
name = "light fixture frame"
|
||||
desc = "A light fixture under construction."
|
||||
icon = 'icons/obj/lighting.dmi'
|
||||
icon_state = "tube-construct-stage1"
|
||||
anchored = 1
|
||||
layer = WALL_OBJ_LAYER
|
||||
var/stage = 1
|
||||
var/fixture_type = "tube"
|
||||
var/sheets_refunded = 2
|
||||
var/obj/machinery/light/newlight = null
|
||||
|
||||
/obj/machinery/light_construct/New(loc, ndir, building)
|
||||
..()
|
||||
if(building)
|
||||
setDir(ndir)
|
||||
|
||||
/obj/machinery/light_construct/examine(mob/user)
|
||||
..()
|
||||
switch(src.stage)
|
||||
if(1)
|
||||
user << "It's an empty frame."
|
||||
if(2)
|
||||
user << "It's wired."
|
||||
if(3)
|
||||
user << "The casing is closed."
|
||||
|
||||
/obj/machinery/light_construct/attackby(obj/item/weapon/W, mob/user, params)
|
||||
add_fingerprint(user)
|
||||
switch(stage)
|
||||
if(1)
|
||||
if(istype(W, /obj/item/weapon/wrench))
|
||||
playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1)
|
||||
usr << "<span class='notice'>You begin deconstructing [src]...</span>"
|
||||
if (!do_after(usr, 30/W.toolspeed, target = src))
|
||||
return
|
||||
new /obj/item/stack/sheet/metal( get_turf(src.loc), sheets_refunded )
|
||||
user.visible_message("[user.name] deconstructs [src].", \
|
||||
"<span class='notice'>You deconstruct [src].</span>", "<span class='italics'>You hear a ratchet.</span>")
|
||||
playsound(src.loc, 'sound/items/Deconstruct.ogg', 75, 1)
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
if(istype(W, /obj/item/stack/cable_coil))
|
||||
var/obj/item/stack/cable_coil/coil = W
|
||||
if(coil.use(1))
|
||||
switch(fixture_type)
|
||||
if ("tube")
|
||||
icon_state = "tube-construct-stage2"
|
||||
if("bulb")
|
||||
icon_state = "bulb-construct-stage2"
|
||||
stage = 2
|
||||
user.visible_message("[user.name] adds wires to [src].", \
|
||||
"<span class='notice'>You add wires to [src].</span>")
|
||||
else
|
||||
user << "<span class='warning'>You need one length of cable to wire [src]!</span>"
|
||||
return
|
||||
if(2)
|
||||
if(istype(W, /obj/item/weapon/wrench))
|
||||
usr << "<span class='warning'>You have to remove the wires first!</span>"
|
||||
return
|
||||
|
||||
if(istype(W, /obj/item/weapon/wirecutters))
|
||||
stage = 1
|
||||
switch(fixture_type)
|
||||
if ("tube")
|
||||
icon_state = "tube-construct-stage1"
|
||||
if("bulb")
|
||||
icon_state = "bulb-construct-stage1"
|
||||
new /obj/item/stack/cable_coil(get_turf(loc), 1, "red")
|
||||
user.visible_message("[user.name] removes the wiring from [src].", \
|
||||
"<span class='notice'>You remove the wiring from [src].</span>", "<span class='italics'>You hear clicking.</span>")
|
||||
playsound(loc, 'sound/items/Wirecutter.ogg', 100, 1)
|
||||
return
|
||||
|
||||
if(istype(W, /obj/item/weapon/screwdriver))
|
||||
user.visible_message("[user.name] closes [src]'s casing.", \
|
||||
"<span class='notice'>You close [src]'s casing.</span>", "<span class='italics'>You hear screwing.</span>")
|
||||
playsound(loc, 'sound/items/Screwdriver.ogg', 75, 1)
|
||||
switch(fixture_type)
|
||||
if("tube")
|
||||
newlight = new /obj/machinery/light/built(loc)
|
||||
if ("bulb")
|
||||
newlight = new /obj/machinery/light/small/built(loc)
|
||||
newlight.setDir(dir)
|
||||
transfer_fingerprints_to(newlight)
|
||||
qdel(src)
|
||||
return
|
||||
return ..()
|
||||
|
||||
|
||||
/obj/machinery/light_construct/small
|
||||
name = "small light fixture frame"
|
||||
icon_state = "bulb-construct-stage1"
|
||||
fixture_type = "bulb"
|
||||
sheets_refunded = 1
|
||||
|
||||
// the standard tube light fixture
|
||||
/obj/machinery/light
|
||||
name = "light fixture"
|
||||
icon = 'icons/obj/lighting.dmi'
|
||||
var/base_state = "tube" // base description and icon_state
|
||||
icon_state = "tube1"
|
||||
desc = "A lighting fixture."
|
||||
anchored = 1
|
||||
layer = WALL_OBJ_LAYER
|
||||
use_power = 2
|
||||
idle_power_usage = 2
|
||||
active_power_usage = 20
|
||||
power_channel = LIGHT //Lights are calc'd via area so they dont need to be in the machine list
|
||||
var/on = 0 // 1 if on, 0 if off
|
||||
var/on_gs = 0
|
||||
var/static_power_used = 0
|
||||
var/brightness = 8 // luminosity when on, also used in power calculation
|
||||
var/status = LIGHT_OK // LIGHT_OK, _EMPTY, _BURNED or _BROKEN
|
||||
var/flickering = 0
|
||||
var/light_type = /obj/item/weapon/light/tube // the type of light item
|
||||
var/fitting = "tube"
|
||||
var/switchcount = 0 // count of number of times switched on/off
|
||||
// this is used to calc the probability the light burns out
|
||||
|
||||
var/rigged = 0 // true if rigged to explode
|
||||
var/health = 20
|
||||
|
||||
// the smaller bulb light fixture
|
||||
|
||||
/obj/machinery/light/small
|
||||
icon_state = "bulb1"
|
||||
base_state = "bulb"
|
||||
fitting = "bulb"
|
||||
brightness = 4
|
||||
desc = "A small lighting fixture."
|
||||
light_type = /obj/item/weapon/light/bulb
|
||||
health = 15
|
||||
|
||||
|
||||
/obj/machinery/light/Move()
|
||||
if(status != LIGHT_BROKEN)
|
||||
broken(1)
|
||||
return ..()
|
||||
|
||||
/obj/machinery/light/built/New()
|
||||
status = LIGHT_EMPTY
|
||||
update(0)
|
||||
..()
|
||||
|
||||
/obj/machinery/light/small/built/New()
|
||||
status = LIGHT_EMPTY
|
||||
update(0)
|
||||
..()
|
||||
|
||||
|
||||
// create a new lighting fixture
|
||||
/obj/machinery/light/New()
|
||||
..()
|
||||
spawn(2)
|
||||
switch(fitting)
|
||||
if("tube")
|
||||
brightness = 8
|
||||
if(prob(2))
|
||||
broken(1)
|
||||
if("bulb")
|
||||
brightness = 4
|
||||
if(prob(5))
|
||||
broken(1)
|
||||
spawn(1)
|
||||
update(0)
|
||||
|
||||
/obj/machinery/light/Destroy()
|
||||
var/area/A = get_area(src)
|
||||
if(A)
|
||||
on = 0
|
||||
// A.update_lights()
|
||||
return ..()
|
||||
|
||||
/obj/machinery/light/update_icon()
|
||||
|
||||
switch(status) // set icon_states
|
||||
if(LIGHT_OK)
|
||||
icon_state = "[base_state][on]"
|
||||
if(LIGHT_EMPTY)
|
||||
icon_state = "[base_state]-empty"
|
||||
on = 0
|
||||
if(LIGHT_BURNED)
|
||||
icon_state = "[base_state]-burned"
|
||||
on = 0
|
||||
if(LIGHT_BROKEN)
|
||||
icon_state = "[base_state]-broken"
|
||||
on = 0
|
||||
return
|
||||
|
||||
// update the icon_state and luminosity of the light depending on its state
|
||||
/obj/machinery/light/proc/update(trigger = 1)
|
||||
|
||||
update_icon()
|
||||
if(on)
|
||||
if(!light || light.luminosity != brightness)
|
||||
switchcount++
|
||||
if(rigged)
|
||||
if(status == LIGHT_OK && trigger)
|
||||
explode()
|
||||
else if( prob( min(60, switchcount*switchcount*0.01) ) )
|
||||
if(status == LIGHT_OK && trigger)
|
||||
status = LIGHT_BURNED
|
||||
icon_state = "[base_state]-burned"
|
||||
on = 0
|
||||
SetLuminosity(0)
|
||||
else
|
||||
use_power = 2
|
||||
SetLuminosity(brightness)
|
||||
else
|
||||
use_power = 1
|
||||
SetLuminosity(0)
|
||||
|
||||
active_power_usage = (brightness * 10)
|
||||
if(on != on_gs)
|
||||
on_gs = on
|
||||
if(on)
|
||||
static_power_used = brightness * 20 //20W per unit luminosity
|
||||
addStaticPower(static_power_used, STATIC_LIGHT)
|
||||
else
|
||||
removeStaticPower(static_power_used, STATIC_LIGHT)
|
||||
|
||||
|
||||
// attempt to set the light's on/off status
|
||||
// will not switch on if broken/burned/empty
|
||||
/obj/machinery/light/proc/seton(s)
|
||||
on = (s && status == LIGHT_OK)
|
||||
update()
|
||||
|
||||
// examine verb
|
||||
/obj/machinery/light/examine(mob/user)
|
||||
..()
|
||||
switch(status)
|
||||
if(LIGHT_OK)
|
||||
user << "It is turned [on? "on" : "off"]."
|
||||
if(LIGHT_EMPTY)
|
||||
user << "The [fitting] has been removed."
|
||||
if(LIGHT_BURNED)
|
||||
user << "The [fitting] is burnt out."
|
||||
if(LIGHT_BROKEN)
|
||||
user << "The [fitting] has been smashed."
|
||||
|
||||
|
||||
|
||||
// attack with item - insert light (if right type), otherwise try to break the light
|
||||
|
||||
/obj/machinery/light/attackby(obj/item/W, mob/living/user, params)
|
||||
|
||||
//Light replacer code
|
||||
if(istype(W, /obj/item/device/lightreplacer))
|
||||
var/obj/item/device/lightreplacer/LR = W
|
||||
LR.ReplaceLight(src, user)
|
||||
|
||||
// attempt to insert light
|
||||
else if(istype(W, /obj/item/weapon/light))
|
||||
if(status != LIGHT_EMPTY)
|
||||
user << "<span class='warning'>There is a [fitting] already inserted!</span>"
|
||||
else
|
||||
src.add_fingerprint(user)
|
||||
var/obj/item/weapon/light/L = W
|
||||
if(istype(L, light_type))
|
||||
if(!user.drop_item())
|
||||
return
|
||||
status = L.status
|
||||
user << "<span class='notice'>You insert the [L.name].</span>"
|
||||
switchcount = L.switchcount
|
||||
rigged = L.rigged
|
||||
brightness = L.brightness
|
||||
on = has_power()
|
||||
update()
|
||||
|
||||
qdel(L)
|
||||
|
||||
if(on && rigged)
|
||||
explode()
|
||||
else
|
||||
user << "<span class='warning'>This type of light requires a [fitting]!</span>"
|
||||
|
||||
// attempt to stick weapon into light socket
|
||||
else if(status == LIGHT_EMPTY)
|
||||
if(istype(W, /obj/item/weapon/screwdriver)) //If it's a screwdriver open it.
|
||||
playsound(src.loc, 'sound/items/Screwdriver.ogg', 75, 1)
|
||||
user.visible_message("[user.name] opens [src]'s casing.", \
|
||||
"<span class='notice'>You open [src]'s casing.</span>", "<span class='italics'>You hear a noise.</span>")
|
||||
var/obj/machinery/light_construct/newlight = null
|
||||
switch(fitting)
|
||||
if("tube")
|
||||
newlight = new /obj/machinery/light_construct(src.loc)
|
||||
newlight.icon_state = "tube-construct-stage2"
|
||||
|
||||
if("bulb")
|
||||
newlight = new /obj/machinery/light_construct/small(src.loc)
|
||||
newlight.icon_state = "bulb-construct-stage2"
|
||||
newlight.setDir(src.dir)
|
||||
newlight.stage = 2
|
||||
transfer_fingerprints_to(newlight)
|
||||
qdel(src)
|
||||
else
|
||||
user << "<span class='userdanger'>You stick \the [W] into the light socket!</span>"
|
||||
if(has_power() && (W.flags & CONDUCT))
|
||||
var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
|
||||
s.set_up(3, 1, src)
|
||||
s.start()
|
||||
if (prob(75))
|
||||
electrocute_mob(user, get_area(src), src, rand(0.7,1.0))
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/machinery/light/attacked_by(obj/item/I, mob/living/user)
|
||||
..()
|
||||
if(status == LIGHT_BROKEN || status == LIGHT_EMPTY)
|
||||
if(on && (I.flags & CONDUCT))
|
||||
if(prob(12))
|
||||
electrocute_mob(user, get_area(src), src, 0.3)
|
||||
|
||||
/obj/machinery/light/take_damage(damage, damage_type = BRUTE, sound_effect = 1)
|
||||
switch(damage_type)
|
||||
if(BRUTE)
|
||||
if(sound_effect)
|
||||
switch(status)
|
||||
if(LIGHT_EMPTY)
|
||||
playsound(loc, 'sound/weapons/smash.ogg', 50, 1)
|
||||
if(LIGHT_BROKEN)
|
||||
playsound(loc, 'sound/effects/hit_on_shattered_glass.ogg', 90, 1)
|
||||
else
|
||||
playsound(loc, 'sound/effects/Glasshit.ogg', 90, 1)
|
||||
if(BURN)
|
||||
if(sound_effect)
|
||||
playsound(src.loc, 'sound/items/Welder.ogg', 100, 1)
|
||||
else
|
||||
return
|
||||
health -= damage
|
||||
if(health <= 0)
|
||||
broken()
|
||||
|
||||
|
||||
// returns whether this light has power
|
||||
// true if area has power and lightswitch is on
|
||||
/obj/machinery/light/proc/has_power()
|
||||
var/area/A = src.loc.loc
|
||||
return A.master.lightswitch && A.master.power_light
|
||||
|
||||
/obj/machinery/light/proc/flicker(var/amount = rand(10, 20))
|
||||
set waitfor = 0
|
||||
if(flickering) return
|
||||
flickering = 1
|
||||
if(on && status == LIGHT_OK)
|
||||
for(var/i = 0; i < amount; i++)
|
||||
if(status != LIGHT_OK) break
|
||||
on = !on
|
||||
update(0)
|
||||
sleep(rand(5, 15))
|
||||
on = (status == LIGHT_OK)
|
||||
update(0)
|
||||
flickering = 0
|
||||
|
||||
// ai attack - make lights flicker, because why not
|
||||
|
||||
/obj/machinery/light/attack_ai(mob/user)
|
||||
src.flicker(1)
|
||||
return
|
||||
|
||||
/obj/machinery/light/bullet_act(obj/item/projectile/P)
|
||||
. = ..()
|
||||
take_damage(P.damage, P.damage_type, 0)
|
||||
|
||||
/obj/machinery/light/hitby(AM as mob|obj)
|
||||
..()
|
||||
var/tforce = 0
|
||||
if(ismob(AM))
|
||||
tforce = 40
|
||||
else if(isobj(AM))
|
||||
var/obj/item/I = AM
|
||||
tforce = I.throwforce
|
||||
take_damage(tforce)
|
||||
|
||||
// attack with hand - remove tube/bulb
|
||||
// if hands aren't protected and the light is on, burn the player
|
||||
|
||||
/obj/machinery/light/attack_hand(mob/living/carbon/human/user)
|
||||
user.changeNext_move(CLICK_CD_MELEE)
|
||||
add_fingerprint(user)
|
||||
|
||||
if(status == LIGHT_EMPTY)
|
||||
user << "There is no [fitting] in this light."
|
||||
return
|
||||
|
||||
// make it burn hands if not wearing fire-insulated gloves
|
||||
if(on)
|
||||
var/prot = 0
|
||||
var/mob/living/carbon/human/H = user
|
||||
|
||||
if(istype(H))
|
||||
|
||||
if(H.gloves)
|
||||
var/obj/item/clothing/gloves/G = H.gloves
|
||||
if(G.max_heat_protection_temperature)
|
||||
prot = (G.max_heat_protection_temperature > 360)
|
||||
else
|
||||
prot = 1
|
||||
|
||||
if(prot > 0)
|
||||
user << "<span class='notice'>You remove the light [fitting].</span>"
|
||||
else if(istype(user) && user.dna.check_mutation(TK))
|
||||
user << "<span class='notice'>You telekinetically remove the light [fitting].</span>"
|
||||
else
|
||||
user << "<span class='warning'>You try to remove the light [fitting], but you burn your hand on it!</span>"
|
||||
|
||||
var/obj/item/bodypart/affecting = H.get_bodypart("[user.hand ? "l" : "r" ]_arm")
|
||||
if(affecting && affecting.take_damage( 0, 5 )) // 5 burn damage
|
||||
H.update_damage_overlays(0)
|
||||
H.updatehealth()
|
||||
return // if burned, don't remove the light
|
||||
else
|
||||
user << "<span class='notice'>You remove the light [fitting].</span>"
|
||||
// create a light tube/bulb item and put it in the user's hand
|
||||
var/obj/item/weapon/light/L = new light_type()
|
||||
L.status = status
|
||||
L.rigged = rigged
|
||||
L.brightness = brightness
|
||||
|
||||
// light item inherits the switchcount, then zero it
|
||||
L.switchcount = switchcount
|
||||
switchcount = 0
|
||||
|
||||
L.update()
|
||||
L.add_fingerprint(user)
|
||||
L.loc = loc
|
||||
|
||||
user.put_in_active_hand(L) //puts it in our active hand
|
||||
|
||||
status = LIGHT_EMPTY
|
||||
update()
|
||||
|
||||
/obj/machinery/light/attack_tk(mob/user)
|
||||
if(status == LIGHT_EMPTY)
|
||||
user << "There is no [fitting] in this light."
|
||||
return
|
||||
|
||||
user << "<span class='notice'>You telekinetically remove the light [fitting].</span>"
|
||||
// create a light tube/bulb item and put it in the user's hand
|
||||
var/obj/item/weapon/light/L = new light_type()
|
||||
L.status = status
|
||||
L.rigged = rigged
|
||||
L.brightness = brightness
|
||||
|
||||
// light item inherits the switchcount, then zero it
|
||||
L.switchcount = switchcount
|
||||
switchcount = 0
|
||||
|
||||
L.update()
|
||||
L.add_fingerprint(user)
|
||||
L.loc = loc
|
||||
|
||||
status = LIGHT_EMPTY
|
||||
update()
|
||||
|
||||
// break the light and make sparks if was on
|
||||
|
||||
/obj/machinery/light/proc/broken(skip_sound_and_sparks = 0)
|
||||
if(status == LIGHT_EMPTY)
|
||||
return
|
||||
|
||||
if(!skip_sound_and_sparks)
|
||||
if(status == LIGHT_OK || status == LIGHT_BURNED)
|
||||
playsound(src.loc, 'sound/effects/Glasshit.ogg', 75, 1)
|
||||
if(on)
|
||||
var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
|
||||
s.set_up(3, 1, src)
|
||||
s.start()
|
||||
status = LIGHT_BROKEN
|
||||
update()
|
||||
|
||||
/obj/machinery/light/proc/fix()
|
||||
if(status == LIGHT_OK)
|
||||
return
|
||||
status = LIGHT_OK
|
||||
brightness = initial(brightness)
|
||||
on = 1
|
||||
update()
|
||||
|
||||
// explosion effect
|
||||
// destroy the whole light fixture or just shatter it
|
||||
|
||||
/obj/machinery/light/ex_act(severity, target)
|
||||
..()
|
||||
if(!qdeleted(src))
|
||||
switch(severity)
|
||||
if(2)
|
||||
if(prob(50))
|
||||
broken()
|
||||
if(3)
|
||||
if(prob(25))
|
||||
broken()
|
||||
|
||||
// called when area power state changes
|
||||
/obj/machinery/light/power_change()
|
||||
var/area/A = get_area(src)
|
||||
A = A.master
|
||||
seton(A.lightswitch && A.power_light)
|
||||
|
||||
// called when on fire
|
||||
|
||||
/obj/machinery/light/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume)
|
||||
if(prob(max(0, exposed_temperature - 673))) //0% at <400C, 100% at >500C
|
||||
broken()
|
||||
|
||||
// explode the light
|
||||
|
||||
/obj/machinery/light/proc/explode()
|
||||
set waitfor = 0
|
||||
var/turf/T = get_turf(src.loc)
|
||||
broken() // break it first to give a warning
|
||||
sleep(2)
|
||||
explosion(T, 0, 0, 2, 2)
|
||||
sleep(1)
|
||||
qdel(src)
|
||||
|
||||
// the light item
|
||||
// can be tube or bulb subtypes
|
||||
// will fit into empty /obj/machinery/light of the corresponding type
|
||||
|
||||
/obj/item/weapon/light
|
||||
icon = 'icons/obj/lighting.dmi'
|
||||
force = 2
|
||||
throwforce = 5
|
||||
w_class = 1
|
||||
var/status = 0 // LIGHT_OK, LIGHT_BURNED or LIGHT_BROKEN
|
||||
var/base_state
|
||||
var/switchcount = 0 // number of times switched
|
||||
materials = list(MAT_METAL=60)
|
||||
var/rigged = 0 // true if rigged to explode
|
||||
var/brightness = 2 //how much light it gives off
|
||||
|
||||
/obj/item/weapon/light/tube
|
||||
name = "light tube"
|
||||
desc = "A replacement light tube."
|
||||
icon_state = "ltube"
|
||||
base_state = "ltube"
|
||||
item_state = "c_tube"
|
||||
materials = list(MAT_GLASS=100)
|
||||
brightness = 8
|
||||
|
||||
/obj/item/weapon/light/bulb
|
||||
name = "light bulb"
|
||||
desc = "A replacement light bulb."
|
||||
icon_state = "lbulb"
|
||||
base_state = "lbulb"
|
||||
item_state = "contvapour"
|
||||
materials = list(MAT_GLASS=100)
|
||||
brightness = 4
|
||||
|
||||
/obj/item/weapon/light/throw_impact(atom/hit_atom)
|
||||
if(!..()) //not caught by a mob
|
||||
shatter()
|
||||
|
||||
// update the icon state and description of the light
|
||||
|
||||
/obj/item/weapon/light/proc/update()
|
||||
switch(status)
|
||||
if(LIGHT_OK)
|
||||
icon_state = base_state
|
||||
desc = "A replacement [name]."
|
||||
if(LIGHT_BURNED)
|
||||
icon_state = "[base_state]-burned"
|
||||
desc = "A burnt-out [name]."
|
||||
if(LIGHT_BROKEN)
|
||||
icon_state = "[base_state]-broken"
|
||||
desc = "A broken [name]."
|
||||
|
||||
|
||||
/obj/item/weapon/light/New()
|
||||
..()
|
||||
update()
|
||||
|
||||
|
||||
// attack bulb/tube with object
|
||||
// if a syringe, can inject plasma to make it explode
|
||||
/obj/item/weapon/light/attackby(obj/item/I, mob/user, params)
|
||||
..()
|
||||
if(istype(I, /obj/item/weapon/reagent_containers/syringe))
|
||||
var/obj/item/weapon/reagent_containers/syringe/S = I
|
||||
|
||||
user << "<span class='notice'>You inject the solution into \the [src].</span>"
|
||||
|
||||
if(S.reagents.has_reagent("plasma", 5))
|
||||
|
||||
rigged = 1
|
||||
|
||||
S.reagents.clear_reagents()
|
||||
else
|
||||
..()
|
||||
return
|
||||
|
||||
/obj/item/weapon/light/attack(mob/living/M, mob/living/user, def_zone)
|
||||
..()
|
||||
shatter()
|
||||
|
||||
/obj/item/weapon/light/attack_obj(obj/O, mob/living/user)
|
||||
..()
|
||||
shatter()
|
||||
|
||||
/obj/item/weapon/light/proc/shatter()
|
||||
if(status == LIGHT_OK || status == LIGHT_BURNED)
|
||||
src.visible_message("<span class='danger'>[name] shatters.</span>","<span class='italics'>You hear a small glass object shatter.</span>")
|
||||
status = LIGHT_BROKEN
|
||||
force = 5
|
||||
playsound(src.loc, 'sound/effects/Glasshit.ogg', 75, 1)
|
||||
update()
|
||||
@@ -0,0 +1,81 @@
|
||||
/obj/machinery/computer/monitor
|
||||
name = "power monitoring console"
|
||||
desc = "It monitors power levels across the station."
|
||||
icon_screen = "power"
|
||||
icon_keyboard = "power_key"
|
||||
use_power = 2
|
||||
idle_power_usage = 20
|
||||
active_power_usage = 100
|
||||
circuit = /obj/item/weapon/circuitboard/computer/powermonitor
|
||||
|
||||
var/obj/structure/cable/attached
|
||||
|
||||
var/list/history = list()
|
||||
var/record_size = 60
|
||||
var/record_interval = 50
|
||||
var/next_record = 0
|
||||
|
||||
/obj/machinery/computer/monitor/New()
|
||||
..()
|
||||
search()
|
||||
history["supply"] = list()
|
||||
history["demand"] = list()
|
||||
|
||||
/obj/machinery/computer/monitor/process()
|
||||
if(!attached)
|
||||
use_power = 1
|
||||
search()
|
||||
else
|
||||
use_power = 2
|
||||
record()
|
||||
|
||||
/obj/machinery/computer/monitor/proc/search()
|
||||
var/turf/T = get_turf(src)
|
||||
attached = locate() in T
|
||||
|
||||
/obj/machinery/computer/monitor/proc/record()
|
||||
if(world.time >= next_record)
|
||||
next_record = world.time + record_interval
|
||||
|
||||
var/list/supply = history["supply"]
|
||||
supply += attached.powernet.viewavail
|
||||
if(supply.len > record_size)
|
||||
supply.Cut(1, 2)
|
||||
|
||||
var/list/demand = history["demand"]
|
||||
demand += attached.powernet.viewload
|
||||
if(demand.len > record_size)
|
||||
demand.Cut(1, 2)
|
||||
|
||||
/obj/machinery/computer/monitor/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, \
|
||||
datum/tgui/master_ui = null, datum/ui_state/state = default_state)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "power_monitor", name, 1200, 1000, master_ui, state)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/computer/monitor/ui_data()
|
||||
var/list/data = list()
|
||||
data["stored"] = record_size
|
||||
data["interval"] = record_interval / 10
|
||||
data["attached"] = attached ? TRUE : FALSE
|
||||
if(attached)
|
||||
data["supply"] = attached.powernet.viewavail
|
||||
data["demand"] = attached.powernet.viewload
|
||||
data["history"] = history
|
||||
|
||||
data["areas"] = list()
|
||||
for(var/obj/machinery/power/terminal/term in attached.powernet.nodes)
|
||||
var/obj/machinery/power/apc/A = term.master
|
||||
if(istype(A))
|
||||
data["areas"] += list(list(
|
||||
"name" = A.area.name,
|
||||
"charge" = A.cell.percent(),
|
||||
"load" = A.lastused_total,
|
||||
"charging" = A.charging,
|
||||
"eqp" = A.equipment,
|
||||
"lgt" = A.lighting,
|
||||
"env" = A.environ
|
||||
))
|
||||
|
||||
return data
|
||||
@@ -0,0 +1,346 @@
|
||||
//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:33
|
||||
|
||||
/* new portable generator - work in progress
|
||||
|
||||
/obj/machinery/power/port_gen
|
||||
name = "portable generator"
|
||||
desc = "A portable generator used for emergency backup power."
|
||||
icon = 'generator.dmi'
|
||||
icon_state = "off"
|
||||
density = 1
|
||||
anchored = 0
|
||||
var/t_status = 0
|
||||
var/t_per = 5000
|
||||
var/filter = 1
|
||||
var/tank = null
|
||||
var/turf/inturf
|
||||
var/starter = 0
|
||||
var/rpm = 0
|
||||
var/rpmtarget = 0
|
||||
var/capacity = 1e6
|
||||
var/turf/outturf
|
||||
var/lastgen
|
||||
|
||||
|
||||
/obj/machinery/power/port_gen/process()
|
||||
ideally we're looking to generate 5000
|
||||
|
||||
/obj/machinery/power/port_gen/attackby(obj/item/weapon/W, mob/user)
|
||||
tank [un]loading stuff
|
||||
|
||||
/obj/machinery/power/port_gen/attack_hand(mob/user)
|
||||
turn on/off
|
||||
|
||||
/obj/machinery/power/port_gen/examine(mob/user)
|
||||
display round(lastgen) and plasmatank amount
|
||||
|
||||
*/
|
||||
|
||||
//Previous code been here forever, adding new framework for portable generators
|
||||
|
||||
|
||||
//Baseline portable generator. Has all the default handling. Not intended to be used on it's own (since it generates unlimited power).
|
||||
/obj/machinery/power/port_gen
|
||||
name = "portable generator"
|
||||
desc = "A portable generator for emergency backup power."
|
||||
icon = 'icons/obj/power.dmi'
|
||||
icon_state = "portgen0"
|
||||
density = 1
|
||||
anchored = 0
|
||||
use_power = 0
|
||||
|
||||
var/active = 0
|
||||
var/power_gen = 5000
|
||||
var/recent_fault = 0
|
||||
var/power_output = 1
|
||||
var/consumption = 0
|
||||
|
||||
/obj/machinery/power/port_gen/proc/HasFuel() //Placeholder for fuel check.
|
||||
return 1
|
||||
|
||||
/obj/machinery/power/port_gen/proc/UseFuel() //Placeholder for fuel use.
|
||||
return
|
||||
|
||||
/obj/machinery/power/port_gen/proc/DropFuel()
|
||||
return
|
||||
|
||||
/obj/machinery/power/port_gen/proc/handleInactive()
|
||||
return
|
||||
|
||||
/obj/machinery/power/port_gen/process()
|
||||
if(active && HasFuel() && !crit_fail && anchored && powernet)
|
||||
add_avail(power_gen * power_output)
|
||||
UseFuel()
|
||||
src.updateDialog()
|
||||
|
||||
else
|
||||
active = 0
|
||||
icon_state = initial(icon_state)
|
||||
handleInactive()
|
||||
|
||||
/obj/machinery/power/port_gen/attack_hand(mob/user)
|
||||
if(..())
|
||||
return
|
||||
if(!anchored)
|
||||
return
|
||||
|
||||
/obj/machinery/power/port_gen/examine(mob/user)
|
||||
..()
|
||||
user << "It is[!active?"n't":""] running."
|
||||
|
||||
/obj/machinery/power/port_gen/pacman
|
||||
name = "\improper P.A.C.M.A.N.-type portable generator"
|
||||
var/sheets = 0
|
||||
var/max_sheets = 100
|
||||
var/sheet_name = ""
|
||||
var/sheet_path = /obj/item/stack/sheet/mineral/plasma
|
||||
var/board_path = /obj/item/weapon/circuitboard/machine/pacman
|
||||
var/sheet_left = 0 // How much is left of the sheet
|
||||
var/time_per_sheet = 260
|
||||
var/current_heat = 0
|
||||
|
||||
/obj/machinery/power/port_gen/pacman/initialize()
|
||||
..()
|
||||
if(anchored)
|
||||
connect_to_network()
|
||||
|
||||
/obj/machinery/power/port_gen/pacman/New()
|
||||
..()
|
||||
var/obj/item/weapon/circuitboard/machine/B = new board_path(null)
|
||||
B.apply_default_parts(src)
|
||||
|
||||
var/obj/sheet = new sheet_path(null)
|
||||
sheet_name = sheet.name
|
||||
|
||||
/obj/item/weapon/circuitboard/machine/pacman
|
||||
name = "circuit board (PACMAN-type Generator)"
|
||||
build_path = /obj/machinery/power/port_gen/pacman
|
||||
origin_tech = "programming=2;powerstorage=3;plasmatech=3;engineering=3"
|
||||
req_components = list(
|
||||
/obj/item/weapon/stock_parts/matter_bin = 1,
|
||||
/obj/item/weapon/stock_parts/micro_laser = 1,
|
||||
/obj/item/stack/cable_coil = 2,
|
||||
/obj/item/weapon/stock_parts/capacitor = 1)
|
||||
|
||||
/obj/item/weapon/circuitboard/machine/pacman/super
|
||||
name = "circuit board (SUPERPACMAN-type Generator)"
|
||||
build_path = /obj/machinery/power/port_gen/pacman/super
|
||||
origin_tech = "programming=3;powerstorage=4;engineering=4"
|
||||
|
||||
/obj/item/weapon/circuitboard/machine/pacman/mrs
|
||||
name = "circuit board (MRSPACMAN-type Generator)"
|
||||
build_path = "/obj/machinery/power/port_gen/pacman/mrs"
|
||||
origin_tech = "programming=3;powerstorage=4;engineering=4;plasmatech=4"
|
||||
|
||||
/obj/machinery/power/port_gen/pacman/Destroy()
|
||||
DropFuel()
|
||||
return ..()
|
||||
|
||||
/obj/machinery/power/port_gen/pacman/RefreshParts()
|
||||
var/temp_rating = 0
|
||||
var/consumption_coeff = 0
|
||||
for(var/obj/item/weapon/stock_parts/SP in component_parts)
|
||||
if(istype(SP, /obj/item/weapon/stock_parts/matter_bin))
|
||||
max_sheets = SP.rating * SP.rating * 50
|
||||
else if(istype(SP, /obj/item/weapon/stock_parts/capacitor))
|
||||
temp_rating += SP.rating
|
||||
else
|
||||
consumption_coeff += SP.rating
|
||||
power_gen = round(initial(power_gen) * temp_rating * 2)
|
||||
consumption = consumption_coeff
|
||||
|
||||
/obj/machinery/power/port_gen/pacman/examine(mob/user)
|
||||
..()
|
||||
user << "<span class='notice'>The generator has [sheets] units of [sheet_name] fuel left, producing [power_gen] per cycle.</span>"
|
||||
if(crit_fail) user << "<span class='danger'>The generator seems to have broken down.</span>"
|
||||
|
||||
/obj/machinery/power/port_gen/pacman/HasFuel()
|
||||
if(sheets >= 1 / (time_per_sheet / power_output) - sheet_left)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/obj/machinery/power/port_gen/pacman/DropFuel()
|
||||
if(sheets)
|
||||
var/fail_safe = 0
|
||||
while(sheets > 0 && fail_safe < 100)
|
||||
fail_safe += 1
|
||||
var/obj/item/stack/sheet/S = new sheet_path(loc)
|
||||
var/amount = min(sheets, S.max_amount)
|
||||
S.amount = amount
|
||||
sheets -= amount
|
||||
|
||||
/obj/machinery/power/port_gen/pacman/UseFuel()
|
||||
var/needed_sheets = 1 / (time_per_sheet * consumption / power_output)
|
||||
var/temp = min(needed_sheets, sheet_left)
|
||||
needed_sheets -= temp
|
||||
sheet_left -= temp
|
||||
sheets -= round(needed_sheets)
|
||||
needed_sheets -= round(needed_sheets)
|
||||
if (sheet_left <= 0 && sheets > 0)
|
||||
sheet_left = 1 - needed_sheets
|
||||
sheets--
|
||||
|
||||
var/lower_limit = 56 + power_output * 10
|
||||
var/upper_limit = 76 + power_output * 10
|
||||
var/bias = 0
|
||||
if (power_output > 4)
|
||||
upper_limit = 400
|
||||
bias = power_output - consumption * (4 - consumption)
|
||||
if (current_heat < lower_limit)
|
||||
current_heat += 4 - consumption
|
||||
else
|
||||
current_heat += rand(-7 + bias, 7 + bias)
|
||||
if (current_heat < lower_limit)
|
||||
current_heat = lower_limit
|
||||
if (current_heat > upper_limit)
|
||||
current_heat = upper_limit
|
||||
|
||||
if (current_heat > 300)
|
||||
overheat()
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
/obj/machinery/power/port_gen/pacman/handleInactive()
|
||||
|
||||
if (current_heat > 0)
|
||||
current_heat = max(current_heat - 2, 0)
|
||||
src.updateDialog()
|
||||
|
||||
/obj/machinery/power/port_gen/pacman/proc/overheat()
|
||||
explosion(src.loc, 2, 5, 2, -1)
|
||||
|
||||
/obj/machinery/power/port_gen/pacman/attackby(obj/item/O, mob/user, params)
|
||||
if(istype(O, sheet_path))
|
||||
var/obj/item/stack/addstack = O
|
||||
var/amount = min((max_sheets - sheets), addstack.amount)
|
||||
if(amount < 1)
|
||||
user << "<span class='notice'>The [src.name] is full!</span>"
|
||||
return
|
||||
user << "<span class='notice'>You add [amount] sheets to the [src.name].</span>"
|
||||
sheets += amount
|
||||
addstack.use(amount)
|
||||
updateUsrDialog()
|
||||
return
|
||||
else if(!active)
|
||||
|
||||
if(exchange_parts(user, O))
|
||||
return
|
||||
|
||||
if(istype(O, /obj/item/weapon/wrench))
|
||||
|
||||
if(!anchored && !isinspace())
|
||||
connect_to_network()
|
||||
user << "<span class='notice'>You secure the generator to the floor.</span>"
|
||||
anchored = 1
|
||||
else if(anchored)
|
||||
disconnect_from_network()
|
||||
user << "<span class='notice'>You unsecure the generator from the floor.</span>"
|
||||
anchored = 0
|
||||
|
||||
playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1)
|
||||
return
|
||||
else if(istype(O, /obj/item/weapon/screwdriver))
|
||||
panel_open = !panel_open
|
||||
playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1)
|
||||
if(panel_open)
|
||||
user << "<span class='notice'>You open the access panel.</span>"
|
||||
else
|
||||
user << "<span class='notice'>You close the access panel.</span>"
|
||||
return
|
||||
else if(default_deconstruction_crowbar(O))
|
||||
return
|
||||
return ..()
|
||||
|
||||
/obj/machinery/power/port_gen/pacman/emag_act(mob/user)
|
||||
if(!emagged)
|
||||
emagged = 1
|
||||
emp_act(1)
|
||||
|
||||
/obj/machinery/power/port_gen/pacman/attack_hand(mob/user)
|
||||
..()
|
||||
if (!anchored)
|
||||
return
|
||||
|
||||
interact(user)
|
||||
|
||||
/obj/machinery/power/port_gen/pacman/attack_ai(mob/user)
|
||||
interact(user)
|
||||
|
||||
/obj/machinery/power/port_gen/pacman/attack_paw(mob/user)
|
||||
interact(user)
|
||||
|
||||
/obj/machinery/power/port_gen/pacman/interact(mob/user)
|
||||
if (get_dist(src, user) > 1 )
|
||||
if (!istype(user, /mob/living/silicon/ai))
|
||||
user.unset_machine()
|
||||
user << browse(null, "window=port_gen")
|
||||
return
|
||||
|
||||
user.set_machine(src)
|
||||
|
||||
var/dat = text("<b>[name]</b><br>")
|
||||
if (active)
|
||||
dat += text("Generator: <A href='?src=\ref[src];action=disable'>On</A><br>")
|
||||
else
|
||||
dat += text("Generator: <A href='?src=\ref[src];action=enable'>Off</A><br>")
|
||||
dat += text("[capitalize(sheet_name)]: [sheets] - <A href='?src=\ref[src];action=eject'>Eject</A><br>")
|
||||
var/stack_percent = round(sheet_left * 100, 1)
|
||||
dat += text("Current stack: [stack_percent]% <br>")
|
||||
dat += text("Power output: <A href='?src=\ref[src];action=lower_power'>-</A> [power_gen * power_output] <A href='?src=\ref[src];action=higher_power'>+</A><br>")
|
||||
dat += text("Power current: [(powernet == null ? "Unconnected" : "[avail()]")]<br>")
|
||||
dat += text("Heat: [current_heat]<br>")
|
||||
dat += "<br><A href='?src=\ref[src];action=close'>Close</A>"
|
||||
user << browse("[dat]", "window=port_gen")
|
||||
onclose(user, "port_gen")
|
||||
|
||||
/obj/machinery/power/port_gen/pacman/Topic(href, href_list)
|
||||
if(..())
|
||||
return
|
||||
|
||||
src.add_fingerprint(usr)
|
||||
if(href_list["action"])
|
||||
if(href_list["action"] == "enable")
|
||||
if(!active && HasFuel() && !crit_fail)
|
||||
active = 1
|
||||
icon_state = "portgen1"
|
||||
src.updateUsrDialog()
|
||||
if(href_list["action"] == "disable")
|
||||
if (active)
|
||||
active = 0
|
||||
icon_state = "portgen0"
|
||||
src.updateUsrDialog()
|
||||
if(href_list["action"] == "eject")
|
||||
if(!active)
|
||||
DropFuel()
|
||||
src.updateUsrDialog()
|
||||
if(href_list["action"] == "lower_power")
|
||||
if (power_output > 1)
|
||||
power_output--
|
||||
src.updateUsrDialog()
|
||||
if (href_list["action"] == "higher_power")
|
||||
if (power_output < 4 || emagged)
|
||||
power_output++
|
||||
src.updateUsrDialog()
|
||||
if (href_list["action"] == "close")
|
||||
usr << browse(null, "window=port_gen")
|
||||
usr.unset_machine()
|
||||
|
||||
/obj/machinery/power/port_gen/pacman/super
|
||||
name = "\improper S.U.P.E.R.P.A.C.M.A.N.-type portable generator"
|
||||
icon_state = "portgen1"
|
||||
sheet_path = /obj/item/stack/sheet/mineral/uranium
|
||||
power_gen = 15000
|
||||
time_per_sheet = 85
|
||||
board_path = /obj/item/weapon/circuitboard/machine/pacman/super
|
||||
overheat()
|
||||
explosion(src.loc, 3, 3, 3, -1)
|
||||
|
||||
/obj/machinery/power/port_gen/pacman/mrs
|
||||
name = "\improper M.R.S.P.A.C.M.A.N.-type portable generator"
|
||||
icon_state = "portgen2"
|
||||
sheet_path = /obj/item/stack/sheet/mineral/diamond
|
||||
power_gen = 40000
|
||||
time_per_sheet = 80
|
||||
board_path = /obj/item/weapon/circuitboard/machine/pacman/mrs
|
||||
overheat()
|
||||
explosion(src.loc, 4, 4, 4, -1)
|
||||
@@ -0,0 +1,361 @@
|
||||
//////////////////////////////
|
||||
// POWER MACHINERY BASE CLASS
|
||||
//////////////////////////////
|
||||
|
||||
/////////////////////////////
|
||||
// Definitions
|
||||
/////////////////////////////
|
||||
|
||||
/obj/machinery/power
|
||||
name = null
|
||||
icon = 'icons/obj/power.dmi'
|
||||
anchored = 1
|
||||
on_blueprints = TRUE
|
||||
var/datum/powernet/powernet = null
|
||||
use_power = 0
|
||||
idle_power_usage = 0
|
||||
active_power_usage = 0
|
||||
|
||||
/obj/machinery/power/Destroy()
|
||||
disconnect_from_network()
|
||||
return ..()
|
||||
|
||||
///////////////////////////////
|
||||
// General procedures
|
||||
//////////////////////////////
|
||||
|
||||
// common helper procs for all power machines
|
||||
/obj/machinery/power/proc/add_avail(amount)
|
||||
if(powernet)
|
||||
powernet.newavail += amount
|
||||
|
||||
/obj/machinery/power/proc/add_load(amount)
|
||||
if(powernet)
|
||||
powernet.load += amount
|
||||
|
||||
/obj/machinery/power/proc/surplus()
|
||||
if(powernet)
|
||||
return powernet.avail - powernet.load
|
||||
else
|
||||
return 0
|
||||
|
||||
/obj/machinery/power/proc/avail()
|
||||
if(powernet)
|
||||
return powernet.avail
|
||||
else
|
||||
return 0
|
||||
|
||||
/obj/machinery/power/proc/disconnect_terminal() // machines without a terminal will just return, no harm no fowl.
|
||||
return
|
||||
|
||||
// returns true if the area has power on given channel (or doesn't require power).
|
||||
// defaults to power_channel
|
||||
/obj/machinery/proc/powered(var/chan = -1) // defaults to power_channel
|
||||
if(!loc)
|
||||
return 0
|
||||
if(!use_power)
|
||||
return 1
|
||||
|
||||
var/area/A = src.loc.loc // make sure it's in an area
|
||||
if(!A || !isarea(A) || !A.master)
|
||||
return 0 // if not, then not powered
|
||||
if(chan == -1)
|
||||
chan = power_channel
|
||||
return A.master.powered(chan) // return power status of the area
|
||||
|
||||
// increment the power usage stats for an area
|
||||
/obj/machinery/proc/use_power(amount, chan = -1) // defaults to power_channel
|
||||
var/area/A = get_area(src) // make sure it's in an area
|
||||
if(!A || !isarea(A) || !A.master)
|
||||
return
|
||||
if(chan == -1)
|
||||
chan = power_channel
|
||||
A.master.use_power(amount, chan)
|
||||
|
||||
/obj/machinery/proc/addStaticPower(value, powerchannel)
|
||||
var/area/A = get_area(src)
|
||||
if(!A || !A.master)
|
||||
return
|
||||
A.master.addStaticPower(value, powerchannel)
|
||||
|
||||
/obj/machinery/proc/removeStaticPower(value, powerchannel)
|
||||
addStaticPower(-value, powerchannel)
|
||||
|
||||
/obj/machinery/proc/power_change() // called whenever the power settings of the containing area change
|
||||
// by default, check equipment channel & set flag
|
||||
// can override if needed
|
||||
if(powered(power_channel))
|
||||
stat &= ~NOPOWER
|
||||
else
|
||||
|
||||
stat |= NOPOWER
|
||||
return
|
||||
|
||||
// connect the machine to a powernet if a node cable is present on the turf
|
||||
/obj/machinery/power/proc/connect_to_network()
|
||||
var/turf/T = src.loc
|
||||
if(!T || !istype(T))
|
||||
return 0
|
||||
|
||||
var/obj/structure/cable/C = T.get_cable_node() //check if we have a node cable on the machine turf, the first found is picked
|
||||
if(!C || !C.powernet)
|
||||
return 0
|
||||
|
||||
C.powernet.add_machine(src)
|
||||
return 1
|
||||
|
||||
// remove and disconnect the machine from its current powernet
|
||||
/obj/machinery/power/proc/disconnect_from_network()
|
||||
if(!powernet)
|
||||
return 0
|
||||
powernet.remove_machine(src)
|
||||
return 1
|
||||
|
||||
// attach a wire to a power machine - leads from the turf you are standing on
|
||||
//almost never called, overwritten by all power machines but terminal and generator
|
||||
/obj/machinery/power/attackby(obj/item/weapon/W, mob/user, params)
|
||||
if(istype(W, /obj/item/stack/cable_coil))
|
||||
var/obj/item/stack/cable_coil/coil = W
|
||||
var/turf/T = user.loc
|
||||
if(T.intact || !istype(T, /turf/open/floor))
|
||||
return
|
||||
if(get_dist(src, user) > 1)
|
||||
return
|
||||
coil.place_turf(T, user)
|
||||
else
|
||||
return ..()
|
||||
|
||||
|
||||
///////////////////////////////////////////
|
||||
// Powernet handling helpers
|
||||
//////////////////////////////////////////
|
||||
|
||||
//returns all the cables WITHOUT a powernet in neighbors turfs,
|
||||
//pointing towards the turf the machine is located at
|
||||
/obj/machinery/power/proc/get_connections()
|
||||
|
||||
. = list()
|
||||
|
||||
var/cdir
|
||||
var/turf/T
|
||||
|
||||
for(var/card in cardinal)
|
||||
T = get_step(loc,card)
|
||||
cdir = get_dir(T,loc)
|
||||
|
||||
for(var/obj/structure/cable/C in T)
|
||||
if(C.powernet)
|
||||
continue
|
||||
if(C.d1 == cdir || C.d2 == cdir)
|
||||
. += C
|
||||
return .
|
||||
|
||||
//returns all the cables in neighbors turfs,
|
||||
//pointing towards the turf the machine is located at
|
||||
/obj/machinery/power/proc/get_marked_connections()
|
||||
|
||||
. = list()
|
||||
|
||||
var/cdir
|
||||
var/turf/T
|
||||
|
||||
for(var/card in cardinal)
|
||||
T = get_step(loc,card)
|
||||
cdir = get_dir(T,loc)
|
||||
|
||||
for(var/obj/structure/cable/C in T)
|
||||
if(C.d1 == cdir || C.d2 == cdir)
|
||||
. += C
|
||||
return .
|
||||
|
||||
//returns all the NODES (O-X) cables WITHOUT a powernet in the turf the machine is located at
|
||||
/obj/machinery/power/proc/get_indirect_connections()
|
||||
. = list()
|
||||
for(var/obj/structure/cable/C in loc)
|
||||
if(C.powernet)
|
||||
continue
|
||||
if(C.d1 == 0) // the cable is a node cable
|
||||
. += C
|
||||
return .
|
||||
|
||||
///////////////////////////////////////////
|
||||
// GLOBAL PROCS for powernets handling
|
||||
//////////////////////////////////////////
|
||||
|
||||
|
||||
// returns a list of all power-related objects (nodes, cable, junctions) in turf,
|
||||
// excluding source, that match the direction d
|
||||
// if unmarked==1, only return those with no powernet
|
||||
/proc/power_list(turf/T, source, d, unmarked=0, cable_only = 0)
|
||||
. = list()
|
||||
//var/fdir = (!d)? 0 : turn(d, 180) // the opposite direction to d (or 0 if d==0)
|
||||
|
||||
for(var/AM in T)
|
||||
if(AM == source)
|
||||
continue //we don't want to return source
|
||||
|
||||
if(!cable_only && istype(AM,/obj/machinery/power))
|
||||
var/obj/machinery/power/P = AM
|
||||
if(P.powernet == 0)
|
||||
continue // exclude APCs which have powernet=0
|
||||
|
||||
if(!unmarked || !P.powernet) //if unmarked=1 we only return things with no powernet
|
||||
if(d == 0)
|
||||
. += P
|
||||
|
||||
else if(istype(AM,/obj/structure/cable))
|
||||
var/obj/structure/cable/C = AM
|
||||
|
||||
if(!unmarked || !C.powernet)
|
||||
if(C.d1 == d || C.d2 == d)
|
||||
. += C
|
||||
return .
|
||||
|
||||
|
||||
|
||||
|
||||
//remove the old powernet and replace it with a new one throughout the network.
|
||||
/proc/propagate_network(obj/O, datum/powernet/PN)
|
||||
//world.log << "propagating new network"
|
||||
var/list/worklist = list()
|
||||
var/list/found_machines = list()
|
||||
var/index = 1
|
||||
var/obj/P = null
|
||||
|
||||
worklist+=O //start propagating from the passed object
|
||||
|
||||
while(index<=worklist.len) //until we've exhausted all power objects
|
||||
P = worklist[index] //get the next power object found
|
||||
index++
|
||||
|
||||
if( istype(P,/obj/structure/cable))
|
||||
var/obj/structure/cable/C = P
|
||||
if(C.powernet != PN) //add it to the powernet, if it isn't already there
|
||||
PN.add_cable(C)
|
||||
worklist |= C.get_connections() //get adjacents power objects, with or without a powernet
|
||||
|
||||
else if(P.anchored && istype(P,/obj/machinery/power))
|
||||
var/obj/machinery/power/M = P
|
||||
found_machines |= M //we wait until the powernet is fully propagates to connect the machines
|
||||
|
||||
else
|
||||
continue
|
||||
|
||||
//now that the powernet is set, connect found machines to it
|
||||
for(var/obj/machinery/power/PM in found_machines)
|
||||
if(!PM.connect_to_network()) //couldn't find a node on its turf...
|
||||
PM.disconnect_from_network() //... so disconnect if already on a powernet
|
||||
|
||||
|
||||
//Merge two powernets, the bigger (in cable length term) absorbing the other
|
||||
/proc/merge_powernets(datum/powernet/net1, datum/powernet/net2)
|
||||
if(!net1 || !net2) //if one of the powernet doesn't exist, return
|
||||
return
|
||||
|
||||
if(net1 == net2) //don't merge same powernets
|
||||
return
|
||||
|
||||
//We assume net1 is larger. If net2 is in fact larger we are just going to make them switch places to reduce on code.
|
||||
if(net1.cables.len < net2.cables.len) //net2 is larger than net1. Let's switch them around
|
||||
var/temp = net1
|
||||
net1 = net2
|
||||
net2 = temp
|
||||
|
||||
//merge net2 into net1
|
||||
for(var/obj/structure/cable/Cable in net2.cables) //merge cables
|
||||
net1.add_cable(Cable)
|
||||
|
||||
for(var/obj/machinery/power/Node in net2.nodes) //merge power machines
|
||||
if(!Node.connect_to_network())
|
||||
Node.disconnect_from_network() //if somehow we can't connect the machine to the new powernet, disconnect it from the old nonetheless
|
||||
|
||||
return net1
|
||||
|
||||
//Determines how strong could be shock, deals damage to mob, uses power.
|
||||
//M is a mob who touched wire/whatever
|
||||
//power_source is a source of electricity, can be powercell, area, apc, cable, powernet or null
|
||||
//source is an object caused electrocuting (airlock, grille, etc)
|
||||
//No animations will be performed by this proc.
|
||||
/proc/electrocute_mob(mob/living/carbon/M, power_source, obj/source, siemens_coeff = 1)
|
||||
if(istype(M.loc,/obj/mecha))
|
||||
return 0 //feckin mechs are dumb
|
||||
if(istype(M,/mob/living/carbon/human))
|
||||
var/mob/living/carbon/human/H = M
|
||||
if(H.gloves)
|
||||
var/obj/item/clothing/gloves/G = H.gloves
|
||||
if(G.siemens_coefficient == 0)
|
||||
return 0 //to avoid spamming with insulated glvoes on
|
||||
|
||||
var/area/source_area
|
||||
if(istype(power_source,/area))
|
||||
source_area = power_source
|
||||
power_source = source_area.get_apc()
|
||||
if(istype(power_source,/obj/structure/cable))
|
||||
var/obj/structure/cable/Cable = power_source
|
||||
power_source = Cable.powernet
|
||||
|
||||
var/datum/powernet/PN
|
||||
var/obj/item/weapon/stock_parts/cell/cell
|
||||
|
||||
if(istype(power_source,/datum/powernet))
|
||||
PN = power_source
|
||||
else if(istype(power_source,/obj/item/weapon/stock_parts/cell))
|
||||
cell = power_source
|
||||
else if(istype(power_source,/obj/machinery/power/apc))
|
||||
var/obj/machinery/power/apc/apc = power_source
|
||||
cell = apc.cell
|
||||
if (apc.terminal)
|
||||
PN = apc.terminal.powernet
|
||||
else if (!power_source)
|
||||
return 0
|
||||
else
|
||||
log_admin("ERROR: /proc/electrocute_mob([M], [power_source], [source]): wrong power_source")
|
||||
return 0
|
||||
if (!cell && !PN)
|
||||
return 0
|
||||
var/PN_damage = 0
|
||||
var/cell_damage = 0
|
||||
if (PN)
|
||||
PN_damage = PN.get_electrocute_damage()
|
||||
if (cell)
|
||||
cell_damage = cell.get_electrocute_damage()
|
||||
var/shock_damage = 0
|
||||
if (PN_damage>=cell_damage)
|
||||
power_source = PN
|
||||
shock_damage = PN_damage
|
||||
else
|
||||
power_source = cell
|
||||
shock_damage = cell_damage
|
||||
var/drained_hp = M.electrocute_act(shock_damage, source, siemens_coeff) //zzzzzzap!
|
||||
add_logs(source, M, "electrocuted")
|
||||
|
||||
var/drained_energy = drained_hp*20
|
||||
|
||||
if (source_area)
|
||||
source_area.use_power(drained_energy/CELLRATE)
|
||||
else if (istype(power_source,/datum/powernet))
|
||||
var/drained_power = drained_energy/CELLRATE //convert from "joules" to "watts"
|
||||
PN.load+=drained_power
|
||||
else if (istype(power_source, /obj/item/weapon/stock_parts/cell))
|
||||
cell.use(drained_energy)
|
||||
return drained_energy
|
||||
|
||||
////////////////////////////////////////////////
|
||||
// Misc.
|
||||
///////////////////////////////////////////////
|
||||
|
||||
|
||||
// return a knot cable (O-X) if one is present in the turf
|
||||
// null if there's none
|
||||
/turf/proc/get_cable_node()
|
||||
if(!can_have_cabling())
|
||||
return null
|
||||
for(var/obj/structure/cable/C in src)
|
||||
if(C.d1 == 0)
|
||||
return C
|
||||
return null
|
||||
|
||||
/area/proc/get_apc()
|
||||
for(var/obj/machinery/power/apc/APC in apcs_list)
|
||||
if(APC.area == src)
|
||||
return APC
|
||||
@@ -0,0 +1,99 @@
|
||||
////////////////////////////////////////////
|
||||
// POWERNET DATUM
|
||||
// each contiguous network of cables & nodes
|
||||
/////////////////////////////////////
|
||||
/datum/powernet
|
||||
var/number // unique id
|
||||
var/list/cables = list() // all cables & junctions
|
||||
var/list/nodes = list() // all connected machines
|
||||
|
||||
var/load = 0 // the current load on the powernet, increased by each machine at processing
|
||||
var/newavail = 0 // what available power was gathered last tick, then becomes...
|
||||
var/avail = 0 //...the current available power in the powernet
|
||||
var/viewavail = 0 // the available power as it appears on the power console (gradually updated)
|
||||
var/viewload = 0 // the load as it appears on the power console (gradually updated)
|
||||
var/netexcess = 0 // excess power on the powernet (typically avail-load)///////
|
||||
|
||||
/datum/powernet/New()
|
||||
SSmachine.powernets += src
|
||||
|
||||
/datum/powernet/Destroy()
|
||||
//Go away references, you suck!
|
||||
for(var/obj/structure/cable/C in cables)
|
||||
cables -= C
|
||||
C.powernet = null
|
||||
for(var/obj/machinery/power/M in nodes)
|
||||
nodes -= M
|
||||
M.powernet = null
|
||||
|
||||
SSmachine.powernets -= src
|
||||
return ..()
|
||||
|
||||
/datum/powernet/proc/is_empty()
|
||||
return !cables.len && !nodes.len
|
||||
|
||||
//remove a cable from the current powernet
|
||||
//if the powernet is then empty, delete it
|
||||
//Warning : this proc DON'T check if the cable exists
|
||||
/datum/powernet/proc/remove_cable(obj/structure/cable/C)
|
||||
cables -= C
|
||||
C.powernet = null
|
||||
if(is_empty())//the powernet is now empty...
|
||||
qdel(src)///... delete it
|
||||
|
||||
//add a cable to the current powernet
|
||||
//Warning : this proc DON'T check if the cable exists
|
||||
/datum/powernet/proc/add_cable(obj/structure/cable/C)
|
||||
if(C.powernet)// if C already has a powernet...
|
||||
if(C.powernet == src)
|
||||
return
|
||||
else
|
||||
C.powernet.remove_cable(C) //..remove it
|
||||
C.powernet = src
|
||||
cables +=C
|
||||
|
||||
//remove a power machine from the current powernet
|
||||
//if the powernet is then empty, delete it
|
||||
//Warning : this proc DON'T check if the machine exists
|
||||
/datum/powernet/proc/remove_machine(obj/machinery/power/M)
|
||||
nodes -=M
|
||||
M.powernet = null
|
||||
if(is_empty())//the powernet is now empty...
|
||||
qdel(src)///... delete it
|
||||
|
||||
|
||||
//add a power machine to the current powernet
|
||||
//Warning : this proc DON'T check if the machine exists
|
||||
/datum/powernet/proc/add_machine(obj/machinery/power/M)
|
||||
if(M.powernet)// if M already has a powernet...
|
||||
if(M.powernet == src)
|
||||
return
|
||||
else
|
||||
M.disconnect_from_network()//..remove it
|
||||
M.powernet = src
|
||||
nodes[M] = M
|
||||
|
||||
//handles the power changes in the powernet
|
||||
//called every ticks by the powernet controller
|
||||
/datum/powernet/proc/reset()
|
||||
//see if there's a surplus of power remaining in the powernet and stores unused power in the SMES
|
||||
netexcess = avail - load
|
||||
|
||||
if(netexcess > 100 && nodes && nodes.len) // if there was excess power last cycle
|
||||
for(var/obj/machinery/power/smes/S in nodes) // find the SMESes in the network
|
||||
S.restore() // and restore some of the power that was used
|
||||
|
||||
// update power consoles
|
||||
viewavail = round(0.8 * viewavail + 0.2 * avail)
|
||||
viewload = round(0.8 * viewload + 0.2 * load)
|
||||
|
||||
// reset the powernet
|
||||
load = 0
|
||||
avail = newavail
|
||||
newavail = 0
|
||||
|
||||
/datum/powernet/proc/get_electrocute_damage()
|
||||
if(avail >= 1000)
|
||||
return Clamp(round(avail/10000), 10, 90) + rand(-5,5)
|
||||
else
|
||||
return 0
|
||||
@@ -0,0 +1,158 @@
|
||||
//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:33
|
||||
var/global/list/rad_collectors = list()
|
||||
|
||||
/obj/machinery/power/rad_collector
|
||||
name = "Radiation Collector Array"
|
||||
desc = "A device which uses Hawking Radiation and plasma to produce power."
|
||||
icon = 'icons/obj/singularity.dmi'
|
||||
icon_state = "ca"
|
||||
anchored = 0
|
||||
density = 1
|
||||
req_access = list(access_engine_equip)
|
||||
// use_power = 0
|
||||
var/obj/item/weapon/tank/internals/plasma/loaded_tank = null
|
||||
var/last_power = 0
|
||||
var/active = 0
|
||||
var/locked = 0
|
||||
var/drainratio = 1
|
||||
|
||||
/obj/machinery/power/rad_collector/New()
|
||||
..()
|
||||
rad_collectors += src
|
||||
|
||||
/obj/machinery/power/rad_collector/Destroy()
|
||||
rad_collectors -= src
|
||||
return ..()
|
||||
|
||||
/obj/machinery/power/rad_collector/process()
|
||||
if(loaded_tank)
|
||||
if(!loaded_tank.air_contents.gases["plasma"])
|
||||
investigate_log("<font color='red'>out of fuel</font>.","singulo")
|
||||
eject()
|
||||
else
|
||||
loaded_tank.air_contents.gases["plasma"][MOLES] -= 0.001*drainratio
|
||||
loaded_tank.air_contents.garbage_collect()
|
||||
return
|
||||
|
||||
|
||||
/obj/machinery/power/rad_collector/attack_hand(mob/user)
|
||||
if(..())
|
||||
return
|
||||
if(anchored)
|
||||
if(!src.locked)
|
||||
toggle_power()
|
||||
user.visible_message("[user.name] turns the [src.name] [active? "on":"off"].", \
|
||||
"<span class='notice'>You turn the [src.name] [active? "on":"off"].</span>")
|
||||
investigate_log("turned [active?"<font color='green'>on</font>":"<font color='red'>off</font>"] by [user.key]. [loaded_tank?"Fuel: [round(loaded_tank.air_contents.gases["plasma"][MOLES]/0.29)]%":"<font color='red'>It is empty</font>"].","singulo")
|
||||
return
|
||||
else
|
||||
user << "<span class='warning'>The controls are locked!</span>"
|
||||
return
|
||||
..()
|
||||
|
||||
|
||||
/obj/machinery/power/rad_collector/attackby(obj/item/W, mob/user, params)
|
||||
if(istype(W, /obj/item/device/multitool))
|
||||
user << "<span class='notice'>The [W.name] detects that [last_power]W were recently produced.</span>"
|
||||
return 1
|
||||
else if(istype(W, /obj/item/device/analyzer) && loaded_tank)
|
||||
atmosanalyzer_scan(loaded_tank.air_contents, user)
|
||||
else if(istype(W, /obj/item/weapon/tank/internals/plasma))
|
||||
if(!anchored)
|
||||
user << "<span class='warning'>The [src] needs to be secured to the floor first!</span>"
|
||||
return 1
|
||||
if(loaded_tank)
|
||||
user << "<span class='warning'>There's already a plasma tank loaded!</span>"
|
||||
return 1
|
||||
if(!user.drop_item())
|
||||
return 1
|
||||
loaded_tank = W
|
||||
W.loc = src
|
||||
update_icons()
|
||||
else if(istype(W, /obj/item/weapon/crowbar))
|
||||
if(loaded_tank && !src.locked)
|
||||
eject()
|
||||
return 1
|
||||
else if(istype(W, /obj/item/weapon/wrench))
|
||||
if(loaded_tank)
|
||||
user << "<span class='warning'>Remove the plasma tank first!</span>"
|
||||
return 1
|
||||
if(!anchored && !isinspace())
|
||||
playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1)
|
||||
anchored = 1
|
||||
user.visible_message("[user.name] secures the [src.name].", \
|
||||
"<span class='notice'>You secure the external bolts.</span>", \
|
||||
"<span class='italics'>You hear a ratchet.</span>")
|
||||
connect_to_network()
|
||||
else if(anchored)
|
||||
playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1)
|
||||
anchored = 0
|
||||
user.visible_message("[user.name] unsecures the [src.name].", \
|
||||
"<span class='notice'>You unsecure the external bolts.</span>", \
|
||||
"<span class='italics'>You hear a ratchet.</span>")
|
||||
disconnect_from_network()
|
||||
else if(W.GetID())
|
||||
if(allowed(user))
|
||||
if(active)
|
||||
locked = !locked
|
||||
user << "<span class='notice'>You [locked ? "lock" : "unlock"] the controls.</span>"
|
||||
else
|
||||
user << "<span class='warning'>The controls can only be locked when \the [src] is active!</span>"
|
||||
else
|
||||
user << "<span class='danger'>Access denied.</span>"
|
||||
return 1
|
||||
else
|
||||
return ..()
|
||||
|
||||
|
||||
/obj/machinery/power/rad_collector/ex_act(severity, target)
|
||||
switch(severity)
|
||||
if(2, 3)
|
||||
eject()
|
||||
return ..()
|
||||
|
||||
|
||||
/obj/machinery/power/rad_collector/proc/eject()
|
||||
locked = 0
|
||||
var/obj/item/weapon/tank/internals/plasma/Z = src.loaded_tank
|
||||
if (!Z)
|
||||
return
|
||||
Z.loc = get_turf(src)
|
||||
Z.layer = initial(Z.layer)
|
||||
src.loaded_tank = null
|
||||
if(active)
|
||||
toggle_power()
|
||||
else
|
||||
update_icons()
|
||||
|
||||
/obj/machinery/power/rad_collector/proc/receive_pulse(pulse_strength)
|
||||
if(loaded_tank && active)
|
||||
var/power_produced = loaded_tank.air_contents.gases["plasma"] ? loaded_tank.air_contents.gases["plasma"][MOLES] : 0
|
||||
power_produced *= pulse_strength*20
|
||||
add_avail(power_produced)
|
||||
last_power = power_produced
|
||||
return
|
||||
return
|
||||
|
||||
|
||||
/obj/machinery/power/rad_collector/proc/update_icons()
|
||||
cut_overlays()
|
||||
if(loaded_tank)
|
||||
add_overlay(image('icons/obj/singularity.dmi', "ptank"))
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
return
|
||||
if(active)
|
||||
add_overlay(image('icons/obj/singularity.dmi', "on"))
|
||||
|
||||
|
||||
/obj/machinery/power/rad_collector/proc/toggle_power()
|
||||
active = !active
|
||||
if(active)
|
||||
icon_state = "ca_on"
|
||||
flick("ca_active", src)
|
||||
else
|
||||
icon_state = "ca"
|
||||
flick("ca_deactive", src)
|
||||
update_icons()
|
||||
return
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:33
|
||||
|
||||
/obj/machinery/field/containment
|
||||
name = "Containment Field"
|
||||
desc = "An energy field."
|
||||
icon = 'icons/obj/singularity.dmi'
|
||||
icon_state = "Contain_F"
|
||||
anchored = 1
|
||||
density = 0
|
||||
unacidable = 1
|
||||
use_power = 0
|
||||
luminosity = 4
|
||||
layer = ABOVE_OBJ_LAYER
|
||||
var/obj/machinery/field/generator/FG1 = null
|
||||
var/obj/machinery/field/generator/FG2 = null
|
||||
|
||||
/obj/machinery/field/containment/Destroy()
|
||||
FG1.fields -= src
|
||||
FG2.fields -= src
|
||||
return ..()
|
||||
|
||||
/obj/machinery/field/containment/attack_hand(mob/user)
|
||||
if(get_dist(src, user) > 1)
|
||||
return 0
|
||||
else
|
||||
shock(user)
|
||||
return 1
|
||||
|
||||
|
||||
/obj/machinery/field/containment/blob_act(obj/effect/blob/B)
|
||||
return 0
|
||||
|
||||
|
||||
/obj/machinery/field/containment/ex_act(severity, target)
|
||||
return 0
|
||||
|
||||
|
||||
/obj/machinery/field/containment/Crossed(mob/mover)
|
||||
if(isliving(mover))
|
||||
shock(mover)
|
||||
|
||||
/obj/machinery/field/containment/Crossed(obj/mover)
|
||||
if(istype(mover, /obj/machinery) || istype(mover, /obj/structure) || istype(mover, /obj/mecha))
|
||||
bump_field(mover)
|
||||
|
||||
/obj/machinery/field/containment/proc/set_master(master1,master2)
|
||||
if(!master1 || !master2)
|
||||
return 0
|
||||
FG1 = master1
|
||||
FG2 = master2
|
||||
return 1
|
||||
|
||||
/obj/machinery/field/containment/shock(mob/living/user)
|
||||
if(!FG1 || !FG2)
|
||||
qdel(src)
|
||||
return 0
|
||||
..()
|
||||
|
||||
/obj/machinery/field/containment/Move()
|
||||
qdel(src)
|
||||
|
||||
// Abstract Field Class
|
||||
// Used for overriding certain procs
|
||||
|
||||
/obj/machinery/field
|
||||
var/hasShocked = 0 //Used to add a delay between shocks. In some cases this used to crash servers by spawning hundreds of sparks every second.
|
||||
|
||||
/obj/machinery/field/CanPass(atom/movable/mover, turf/target, height=0)
|
||||
if(hasShocked)
|
||||
return 0
|
||||
if(isliving(mover)) // Don't let mobs through
|
||||
shock(mover)
|
||||
return 0
|
||||
if(istype(mover, /obj/machinery) || istype(mover, /obj/structure) || istype(mover, /obj/mecha))
|
||||
bump_field(mover)
|
||||
return 0
|
||||
return ..()
|
||||
|
||||
/obj/machinery/field/proc/shock(mob/living/user)
|
||||
if(isliving(user))
|
||||
var/shock_damage = min(rand(30,40),rand(30,40))
|
||||
|
||||
if(iscarbon(user))
|
||||
var/stun = min(shock_damage, 15)
|
||||
user.Stun(stun)
|
||||
user.Weaken(10)
|
||||
user.electrocute_act(shock_damage, src, 1)
|
||||
|
||||
else if(issilicon(user))
|
||||
if(prob(20))
|
||||
user.Stun(2)
|
||||
user.take_overall_damage(0, shock_damage)
|
||||
user.visible_message("<span class='danger'>[user.name] was shocked by the [src.name]!</span>", \
|
||||
"<span class='userdanger'>Energy pulse detected, system damaged!</span>", \
|
||||
"<span class='italics'>You hear an electrical crack.</span>")
|
||||
|
||||
user.updatehealth()
|
||||
bump_field(user)
|
||||
return
|
||||
|
||||
/obj/machinery/field/proc/clear_shock()
|
||||
hasShocked = 0
|
||||
|
||||
/obj/machinery/field/proc/bump_field(atom/movable/AM as mob|obj)
|
||||
if(hasShocked)
|
||||
return 0
|
||||
hasShocked = 1
|
||||
var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
|
||||
s.set_up(5, 1, AM.loc)
|
||||
s.start()
|
||||
var/atom/target = get_edge_target_turf(AM, get_dir(src, get_step_away(AM, src)))
|
||||
AM.throw_at(target, 200, 4)
|
||||
addtimer(src, "clear_shock", 5)
|
||||
@@ -0,0 +1,289 @@
|
||||
//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:33
|
||||
|
||||
/obj/machinery/power/emitter
|
||||
name = "Emitter"
|
||||
desc = "A heavy duty industrial laser.\n<span class='notice'>Alt-click to rotate it clockwise.</span>"
|
||||
icon = 'icons/obj/singularity.dmi'
|
||||
icon_state = "emitter"
|
||||
var/icon_state_on = "emitter_+a"
|
||||
anchored = 0
|
||||
density = 1
|
||||
req_access = list(access_engine_equip)
|
||||
|
||||
use_power = 0
|
||||
idle_power_usage = 10
|
||||
active_power_usage = 300
|
||||
|
||||
var/active = 0
|
||||
var/powered = 0
|
||||
var/fire_delay = 100
|
||||
var/maximum_fire_delay = 100
|
||||
var/minimum_fire_delay = 20
|
||||
var/last_shot = 0
|
||||
var/shot_number = 0
|
||||
var/state = 0
|
||||
var/locked = 0
|
||||
|
||||
var/projectile_type = /obj/item/projectile/beam/emitter
|
||||
|
||||
var/projectile_sound = 'sound/weapons/emitter.ogg'
|
||||
|
||||
/obj/machinery/power/emitter/New()
|
||||
..()
|
||||
var/obj/item/weapon/circuitboard/machine/B = new /obj/item/weapon/circuitboard/machine/emitter(null)
|
||||
B.apply_default_parts(src)
|
||||
RefreshParts()
|
||||
|
||||
/obj/item/weapon/circuitboard/machine/emitter
|
||||
name = "circuit board (Emitter)"
|
||||
build_path = /obj/machinery/power/emitter
|
||||
origin_tech = "programming=3;powerstorage=4;engineering=4"
|
||||
req_components = list(
|
||||
/obj/item/weapon/stock_parts/micro_laser = 1,
|
||||
/obj/item/weapon/stock_parts/manipulator = 1)
|
||||
|
||||
/obj/machinery/power/emitter/RefreshParts()
|
||||
var/max_firedelay = 120
|
||||
var/firedelay = 120
|
||||
var/min_firedelay = 24
|
||||
var/power_usage = 350
|
||||
for(var/obj/item/weapon/stock_parts/micro_laser/L in component_parts)
|
||||
max_firedelay -= 20 * L.rating
|
||||
min_firedelay -= 4 * L.rating
|
||||
firedelay -= 20 * L.rating
|
||||
maximum_fire_delay = max_firedelay
|
||||
minimum_fire_delay = min_firedelay
|
||||
fire_delay = firedelay
|
||||
for(var/obj/item/weapon/stock_parts/manipulator/M in component_parts)
|
||||
power_usage -= 50 * M.rating
|
||||
active_power_usage = power_usage
|
||||
|
||||
/obj/machinery/power/emitter/verb/rotate()
|
||||
set name = "Rotate"
|
||||
set category = "Object"
|
||||
set src in oview(1)
|
||||
|
||||
if(usr.stat || !usr.canmove || usr.restrained())
|
||||
return
|
||||
if (src.anchored)
|
||||
usr << "<span class='warning'>It is fastened to the floor!</span>"
|
||||
return 0
|
||||
src.setDir(turn(src.dir, 270))
|
||||
return 1
|
||||
|
||||
/obj/machinery/power/emitter/AltClick(mob/user)
|
||||
..()
|
||||
if(user.incapacitated())
|
||||
user << "<span class='warning'>You can't do that right now!</span>"
|
||||
return
|
||||
if(!in_range(src, user))
|
||||
return
|
||||
else
|
||||
rotate()
|
||||
|
||||
/obj/machinery/power/emitter/initialize()
|
||||
..()
|
||||
if(state == 2 && anchored)
|
||||
connect_to_network()
|
||||
|
||||
/obj/machinery/power/emitter/Destroy()
|
||||
if(ticker && ticker.current_state == GAME_STATE_PLAYING)
|
||||
message_admins("Emitter deleted at ([x],[y],[z] - <A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[x];Y=[y];Z=[z]'>JMP</a>)",0,1)
|
||||
log_game("Emitter deleted at ([x],[y],[z])")
|
||||
investigate_log("<font color='red'>deleted</font> at ([x],[y],[z])","singulo")
|
||||
return ..()
|
||||
|
||||
/obj/machinery/power/emitter/update_icon()
|
||||
if (active && powernet && avail(active_power_usage))
|
||||
icon_state = icon_state_on
|
||||
else
|
||||
icon_state = initial(icon_state)
|
||||
|
||||
|
||||
/obj/machinery/power/emitter/attack_hand(mob/user)
|
||||
src.add_fingerprint(user)
|
||||
if(state == 2)
|
||||
if(!powernet)
|
||||
user << "<span class='warning'>The emitter isn't connected to a wire!</span>"
|
||||
return 1
|
||||
if(!src.locked)
|
||||
if(src.active==1)
|
||||
src.active = 0
|
||||
user << "<span class='notice'>You turn off \the [src].</span>"
|
||||
message_admins("Emitter turned off by [key_name_admin(user)](<A HREF='?_src_=holder;adminmoreinfo=\ref[user]'>?</A>) (<A HREF='?_src_=holder;adminplayerobservefollow=\ref[user]'>FLW</A>) in ([x],[y],[z] - <A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[x];Y=[y];Z=[z]'>JMP</a>)",0,1)
|
||||
log_game("Emitter turned off by [key_name(user)] in ([x],[y],[z])")
|
||||
investigate_log("turned <font color='red'>off</font> by [key_name(user)]","singulo")
|
||||
else
|
||||
src.active = 1
|
||||
user << "<span class='notice'>You turn on \the [src].</span>"
|
||||
src.shot_number = 0
|
||||
src.fire_delay = maximum_fire_delay
|
||||
investigate_log("turned <font color='green'>on</font> by [key_name(user)]","singulo")
|
||||
update_icon()
|
||||
else
|
||||
user << "<span class='warning'>The controls are locked!</span>"
|
||||
else
|
||||
user << "<span class='warning'>The [src] needs to be firmly secured to the floor first!</span>"
|
||||
return 1
|
||||
|
||||
|
||||
/obj/machinery/power/emitter/emp_act(severity)//Emitters are hardened but still might have issues
|
||||
// add_load(1000)
|
||||
/* if((severity == 1)&&prob(1)&&prob(1))
|
||||
if(src.active)
|
||||
src.active = 0
|
||||
src.use_power = 1 */
|
||||
return 1
|
||||
|
||||
|
||||
/obj/machinery/power/emitter/process()
|
||||
if(stat & (BROKEN))
|
||||
return
|
||||
if(src.state != 2 || (!powernet && active_power_usage))
|
||||
src.active = 0
|
||||
update_icon()
|
||||
return
|
||||
if(((src.last_shot + src.fire_delay) <= world.time) && (src.active == 1))
|
||||
|
||||
if(!active_power_usage || avail(active_power_usage))
|
||||
add_load(active_power_usage)
|
||||
if(!powered)
|
||||
powered = 1
|
||||
update_icon()
|
||||
investigate_log("regained power and turned <font color='green'>on</font>","singulo")
|
||||
else
|
||||
if(powered)
|
||||
powered = 0
|
||||
update_icon()
|
||||
investigate_log("lost power and turned <font color='red'>off</font>","singulo")
|
||||
log_game("Emitter lost power in ([x],[y],[z])")
|
||||
message_admins("Emitter lost power in ([x],[y],[z] - <a href='?_src_=holder;adminplayerobservecoodjump=1;X=[x];Y=[y];Z=[z]'>JMP</a>)",0,1)
|
||||
return
|
||||
|
||||
src.last_shot = world.time
|
||||
if(src.shot_number < 3)
|
||||
src.fire_delay = 2
|
||||
src.shot_number ++
|
||||
else
|
||||
src.fire_delay = rand(minimum_fire_delay,maximum_fire_delay)
|
||||
src.shot_number = 0
|
||||
|
||||
var/obj/item/projectile/A = PoolOrNew(projectile_type,src.loc)
|
||||
|
||||
A.setDir(src.dir)
|
||||
playsound(src.loc, projectile_sound, 25, 1)
|
||||
|
||||
if(prob(35))
|
||||
var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
|
||||
s.set_up(5, 1, src)
|
||||
s.start()
|
||||
|
||||
switch(dir)
|
||||
if(NORTH)
|
||||
A.yo = 20
|
||||
A.xo = 0
|
||||
if(EAST)
|
||||
A.yo = 0
|
||||
A.xo = 20
|
||||
if(WEST)
|
||||
A.yo = 0
|
||||
A.xo = -20
|
||||
else // Any other
|
||||
A.yo = -20
|
||||
A.xo = 0
|
||||
A.starting = loc
|
||||
A.fire()
|
||||
|
||||
|
||||
/obj/machinery/power/emitter/attackby(obj/item/W, mob/user, params)
|
||||
|
||||
if(istype(W, /obj/item/weapon/wrench))
|
||||
if(active)
|
||||
user << "<span class='warning'>Turn off \the [src] first!</span>"
|
||||
return
|
||||
switch(state)
|
||||
if(0)
|
||||
if(isinspace()) return
|
||||
state = 1
|
||||
playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1)
|
||||
user.visible_message("[user.name] secures [src.name] to the floor.", \
|
||||
"<span class='notice'>You secure the external reinforcing bolts to the floor.</span>", \
|
||||
"<span class='italics'>You hear a ratchet</span>")
|
||||
src.anchored = 1
|
||||
if(1)
|
||||
state = 0
|
||||
playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1)
|
||||
user.visible_message("[user.name] unsecures [src.name] reinforcing bolts from the floor.", \
|
||||
"<span class='notice'>You undo the external reinforcing bolts.</span>", \
|
||||
"<span class='italics'>You hear a ratchet.</span>")
|
||||
src.anchored = 0
|
||||
if(2)
|
||||
user << "<span class='warning'>The [src.name] needs to be unwelded from the floor!</span>"
|
||||
return
|
||||
|
||||
if(istype(W, /obj/item/weapon/weldingtool))
|
||||
var/obj/item/weapon/weldingtool/WT = W
|
||||
if(active)
|
||||
user << "Turn off \the [src] first."
|
||||
return
|
||||
switch(state)
|
||||
if(0)
|
||||
user << "<span class='warning'>The [src.name] needs to be wrenched to the floor!</span>"
|
||||
if(1)
|
||||
if (WT.remove_fuel(0,user))
|
||||
playsound(src.loc, 'sound/items/Welder2.ogg', 50, 1)
|
||||
user.visible_message("[user.name] starts to weld the [src.name] to the floor.", \
|
||||
"<span class='notice'>You start to weld \the [src] to the floor...</span>", \
|
||||
"<span class='italics'>You hear welding.</span>")
|
||||
if (do_after(user,20/W.toolspeed, target = src))
|
||||
if(!src || !WT.isOn()) return
|
||||
state = 2
|
||||
user << "<span class='notice'>You weld \the [src] to the floor.</span>"
|
||||
connect_to_network()
|
||||
if(2)
|
||||
if (WT.remove_fuel(0,user))
|
||||
playsound(src.loc, 'sound/items/Welder2.ogg', 50, 1)
|
||||
user.visible_message("[user.name] starts to cut the [src.name] free from the floor.", \
|
||||
"<span class='notice'>You start to cut \the [src] free from the floor...</span>", \
|
||||
"<span class='italics'>You hear welding.</span>")
|
||||
if (do_after(user,20/W.toolspeed, target = src))
|
||||
if(!src || !WT.isOn()) return
|
||||
state = 1
|
||||
user << "<span class='notice'>You cut \the [src] free from the floor.</span>"
|
||||
disconnect_from_network()
|
||||
return
|
||||
|
||||
if(W.GetID())
|
||||
if(emagged)
|
||||
user << "<span class='warning'>The lock seems to be broken!</span>"
|
||||
return
|
||||
if(allowed(user))
|
||||
if(active)
|
||||
locked = !locked
|
||||
user << "<span class='notice'>You [src.locked ? "lock" : "unlock"] the controls.</span>"
|
||||
else
|
||||
user << "<span class='warning'>The controls can only be locked when \the [src] is online!</span>"
|
||||
else
|
||||
user << "<span class='danger'>Access denied.</span>"
|
||||
return
|
||||
|
||||
if(default_deconstruction_screwdriver(user, "emitter_open", "emitter", W))
|
||||
return
|
||||
|
||||
if(exchange_parts(user, W))
|
||||
return
|
||||
|
||||
if(default_pry_open(W))
|
||||
return
|
||||
|
||||
if(default_deconstruction_crowbar(W))
|
||||
return
|
||||
|
||||
return ..()
|
||||
|
||||
/obj/machinery/power/emitter/emag_act(mob/user)
|
||||
if(!emagged)
|
||||
locked = 0
|
||||
emagged = 1
|
||||
if(user)
|
||||
user.visible_message("[user.name] emags the [src.name].","<span class='notice'>You short out the lock.</span>")
|
||||
@@ -0,0 +1,338 @@
|
||||
//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:33
|
||||
|
||||
|
||||
/*
|
||||
field_generator power level display
|
||||
The icon used for the field_generator need to have 'num_power_levels' number of icon states
|
||||
named 'Field_Gen +p[num]' where 'num' ranges from 1 to 'num_power_levels'
|
||||
|
||||
The power level is displayed using overlays. The current displayed power level is stored in 'powerlevel'.
|
||||
The overlay in use and the powerlevel variable must be kept in sync. A powerlevel equal to 0 means that
|
||||
no power level overlay is currently in the overlays list.
|
||||
-Aygar
|
||||
*/
|
||||
|
||||
#define field_generator_max_power 250
|
||||
|
||||
#define FG_UNSECURED 0
|
||||
#define FG_SECURED 1
|
||||
#define FG_WELDED 2
|
||||
|
||||
#define FG_OFFLINE 0
|
||||
#define FG_CHARGING 1
|
||||
#define FG_ONLINE 2
|
||||
|
||||
/obj/machinery/field/generator
|
||||
name = "Field Generator"
|
||||
desc = "A large thermal battery that projects a high amount of energy when powered."
|
||||
icon = 'icons/obj/machines/field_generator.dmi'
|
||||
icon_state = "Field_Gen"
|
||||
anchored = 0
|
||||
density = 1
|
||||
use_power = 0
|
||||
var/const/num_power_levels = 6 // Total number of power level icon has
|
||||
var/power_level = 0
|
||||
var/active = FG_OFFLINE
|
||||
var/power = 20 // Current amount of power
|
||||
var/state = FG_UNSECURED
|
||||
var/warming_up = 0
|
||||
var/list/obj/machinery/field/containment/fields
|
||||
var/list/obj/machinery/field/generator/connected_gens
|
||||
var/clean_up = 0
|
||||
|
||||
/obj/machinery/field/generator/update_icon()
|
||||
cut_overlays()
|
||||
if(warming_up)
|
||||
add_overlay("+a[warming_up]")
|
||||
if(fields.len)
|
||||
add_overlay("+on")
|
||||
if(power_level)
|
||||
add_overlay("+p[power_level]")
|
||||
|
||||
|
||||
/obj/machinery/field/generator/New()
|
||||
..()
|
||||
fields = list()
|
||||
connected_gens = list()
|
||||
|
||||
|
||||
/obj/machinery/field/generator/process()
|
||||
if(active == FG_ONLINE)
|
||||
calc_power()
|
||||
|
||||
/obj/machinery/field/generator/attack_hand(mob/user)
|
||||
if(state == FG_WELDED)
|
||||
if(get_dist(src, user) <= 1)//Need to actually touch the thing to turn it on
|
||||
if(active >= FG_CHARGING)
|
||||
user << "<span class='warning'>You are unable to turn off the [name] once it is online!</span>"
|
||||
return 1
|
||||
else
|
||||
user.visible_message("[user.name] turns on the [name].", \
|
||||
"<span class='notice'>You turn on the [name].</span>", \
|
||||
"<span class='italics'>You hear heavy droning.</span>")
|
||||
turn_on()
|
||||
investigate_log("<font color='green'>activated</font> by [user.key].","singulo")
|
||||
|
||||
add_fingerprint(user)
|
||||
else
|
||||
user << "<span class='warning'>The [src] needs to be firmly secured to the floor first!</span>"
|
||||
|
||||
|
||||
/obj/machinery/field/generator/attackby(obj/item/W, mob/user, params)
|
||||
if(active)
|
||||
user << "<span class='warning'>The [src] needs to be off!</span>"
|
||||
return
|
||||
else if(istype(W, /obj/item/weapon/wrench))
|
||||
switch(state)
|
||||
if(FG_UNSECURED)
|
||||
if(isinspace()) return
|
||||
state = FG_SECURED
|
||||
playsound(loc, 'sound/items/Ratchet.ogg', 75, 1)
|
||||
user.visible_message("[user.name] secures [name] to the floor.", \
|
||||
"<span class='notice'>You secure the external reinforcing bolts to the floor.</span>", \
|
||||
"<span class='italics'>You hear ratchet.</span>")
|
||||
anchored = 1
|
||||
if(FG_SECURED)
|
||||
state = FG_UNSECURED
|
||||
playsound(loc, 'sound/items/Ratchet.ogg', 75, 1)
|
||||
user.visible_message("[user.name] unsecures [name] reinforcing bolts from the floor.", \
|
||||
"<span class='notice'>You undo the external reinforcing bolts.</span>", \
|
||||
"<span class='italics'>You hear ratchet.</span>")
|
||||
anchored = 0
|
||||
if(FG_WELDED)
|
||||
user << "<span class='warning'>The [name] needs to be unwelded from the floor!</span>"
|
||||
|
||||
else if(istype(W, /obj/item/weapon/weldingtool))
|
||||
var/obj/item/weapon/weldingtool/WT = W
|
||||
switch(state)
|
||||
if(FG_UNSECURED)
|
||||
user << "<span class='warning'>The [name] needs to be wrenched to the floor!</span>"
|
||||
|
||||
if(FG_SECURED)
|
||||
if (WT.remove_fuel(0,user))
|
||||
playsound(loc, 'sound/items/Welder2.ogg', 50, 1)
|
||||
user.visible_message("[user.name] starts to weld the [name] to the floor.", \
|
||||
"<span class='notice'>You start to weld \the [src] to the floor...</span>", \
|
||||
"<span class='italics'>You hear welding.</span>")
|
||||
if (do_after(user,20/W.toolspeed, target = src))
|
||||
if(!src || !WT.isOn()) return
|
||||
state = FG_WELDED
|
||||
user << "<span class='notice'>You weld the field generator to the floor.</span>"
|
||||
|
||||
if(FG_WELDED)
|
||||
if (WT.remove_fuel(0,user))
|
||||
playsound(loc, 'sound/items/Welder2.ogg', 50, 1)
|
||||
user.visible_message("[user.name] starts to cut the [name] free from the floor.", \
|
||||
"<span class='notice'>You start to cut \the [src] free from the floor...</span>", \
|
||||
"<span class='italics'>You hear welding.</span>")
|
||||
if (do_after(user,20/W.toolspeed, target = src))
|
||||
if(!src || !WT.isOn()) return
|
||||
state = FG_SECURED
|
||||
user << "<span class='notice'>You cut \the [src] free from the floor.</span>"
|
||||
|
||||
else
|
||||
return ..()
|
||||
|
||||
|
||||
/obj/machinery/field/generator/emp_act()
|
||||
return 0
|
||||
|
||||
|
||||
/obj/machinery/field/generator/blob_act(obj/effect/blob/B)
|
||||
if(active)
|
||||
return 0
|
||||
else
|
||||
..()
|
||||
|
||||
/obj/machinery/field/generator/bullet_act(obj/item/projectile/Proj)
|
||||
if(Proj.flag != "bullet")
|
||||
power = min(power + Proj.damage, field_generator_max_power)
|
||||
check_power_level()
|
||||
return 0
|
||||
|
||||
|
||||
/obj/machinery/field/generator/Destroy()
|
||||
cleanup()
|
||||
return ..()
|
||||
|
||||
|
||||
/obj/machinery/field/generator/proc/check_power_level()
|
||||
var/new_level = round(num_power_levels * power / field_generator_max_power)
|
||||
if(new_level != power_level)
|
||||
power_level = new_level
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/field/generator/proc/turn_off()
|
||||
active = FG_OFFLINE
|
||||
spawn(1)
|
||||
cleanup()
|
||||
while (warming_up>0 && !active)
|
||||
sleep(50)
|
||||
warming_up--
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/field/generator/proc/turn_on()
|
||||
active = FG_CHARGING
|
||||
spawn(1)
|
||||
while (warming_up<3 && active)
|
||||
sleep(50)
|
||||
warming_up++
|
||||
update_icon()
|
||||
if(warming_up >= 3)
|
||||
start_fields()
|
||||
|
||||
|
||||
/obj/machinery/field/generator/proc/calc_power()
|
||||
var/power_draw = 2 + fields.len
|
||||
|
||||
if(draw_power(round(power_draw/2,1)))
|
||||
check_power_level()
|
||||
return 1
|
||||
else
|
||||
visible_message("<span class='danger'>The [name] shuts down!</span>", "<span class='italics'>You hear something shutting down.</span>")
|
||||
turn_off()
|
||||
investigate_log("ran out of power and <font color='red'>deactivated</font>","singulo")
|
||||
power = 0
|
||||
check_power_level()
|
||||
return 0
|
||||
|
||||
//This could likely be better, it tends to start loopin if you have a complex generator loop setup. Still works well enough to run the engine fields will likely recode the field gens and fields sometime -Mport
|
||||
/obj/machinery/field/generator/proc/draw_power(draw = 0, failsafe = 0, obj/machinery/field/generator/G = null, obj/machinery/field/generator/last = null)
|
||||
if((G && (G == src)) || (failsafe >= 8))//Loopin, set fail
|
||||
return 0
|
||||
else
|
||||
failsafe++
|
||||
|
||||
if(power >= draw)//We have enough power
|
||||
power -= draw
|
||||
return 1
|
||||
|
||||
else//Need more power
|
||||
draw -= power
|
||||
power = 0
|
||||
for(var/CG in connected_gens)
|
||||
var/obj/machinery/field/generator/FG = CG
|
||||
if(FG == last)//We just asked you
|
||||
continue
|
||||
if(G)//Another gen is askin for power and we dont have it
|
||||
if(FG.draw_power(draw,failsafe,G,src))//Can you take the load
|
||||
return 1
|
||||
else
|
||||
return 0
|
||||
else//We are askin another for power
|
||||
if(FG.draw_power(draw,failsafe,src,src))
|
||||
return 1
|
||||
else
|
||||
return 0
|
||||
|
||||
|
||||
/obj/machinery/field/generator/proc/start_fields()
|
||||
if(state != FG_WELDED || !anchored)
|
||||
turn_off()
|
||||
return
|
||||
spawn(1)
|
||||
setup_field(1)
|
||||
spawn(2)
|
||||
setup_field(2)
|
||||
spawn(3)
|
||||
setup_field(4)
|
||||
spawn(4)
|
||||
setup_field(8)
|
||||
spawn(5)
|
||||
active = FG_ONLINE
|
||||
|
||||
|
||||
/obj/machinery/field/generator/proc/setup_field(NSEW)
|
||||
var/turf/T = loc
|
||||
if(!istype(T))
|
||||
return 0
|
||||
|
||||
var/obj/machinery/field/generator/G = null
|
||||
var/steps = 0
|
||||
if(!NSEW)//Make sure its ran right
|
||||
return 0
|
||||
for(var/dist in 0 to 7) // checks out to 8 tiles away for another generator
|
||||
T = get_step(T, NSEW)
|
||||
if(T.density)//We cant shoot a field though this
|
||||
return 0
|
||||
|
||||
G = locate(/obj/machinery/field/generator) in T
|
||||
if(G)
|
||||
steps -= 1
|
||||
if(!G.active)
|
||||
return 0
|
||||
break
|
||||
|
||||
for(var/TC in T.contents)
|
||||
var/atom/A = TC
|
||||
if(ismob(A))
|
||||
continue
|
||||
if(A.density)
|
||||
return 0
|
||||
|
||||
steps++
|
||||
|
||||
if(!G)
|
||||
return 0
|
||||
|
||||
T = loc
|
||||
for(var/dist in 0 to steps) // creates each field tile
|
||||
var/field_dir = get_dir(T,get_step(G.loc, NSEW))
|
||||
T = get_step(T, NSEW)
|
||||
if(!locate(/obj/machinery/field/containment) in T)
|
||||
var/obj/machinery/field/containment/CF = new/obj/machinery/field/containment()
|
||||
CF.set_master(src,G)
|
||||
CF.loc = T
|
||||
CF.setDir(field_dir)
|
||||
fields += CF
|
||||
G.fields += CF
|
||||
for(var/mob/living/L in T)
|
||||
CF.Crossed(L)
|
||||
|
||||
connected_gens |= G
|
||||
G.connected_gens |= src
|
||||
update_icon()
|
||||
|
||||
|
||||
/obj/machinery/field/generator/proc/cleanup()
|
||||
clean_up = 1
|
||||
for (var/F in fields)
|
||||
qdel(F)
|
||||
|
||||
for(var/CG in connected_gens)
|
||||
var/obj/machinery/field/generator/FG = CG
|
||||
FG.connected_gens -= src
|
||||
if(!FG.clean_up)//Makes the other gens clean up as well
|
||||
FG.cleanup()
|
||||
connected_gens -= FG
|
||||
clean_up = 0
|
||||
update_icon()
|
||||
|
||||
//This is here to help fight the "hurr durr, release singulo cos nobody will notice before the
|
||||
//singulo eats the evidence". It's not fool-proof but better than nothing.
|
||||
//I want to avoid using global variables.
|
||||
spawn(1)
|
||||
var/temp = 1 //stops spam
|
||||
for(var/obj/singularity/O in world)
|
||||
if(O.last_warning && temp)
|
||||
if((world.time - O.last_warning) > 50) //to stop message-spam
|
||||
temp = 0
|
||||
message_admins("A singulo exists and a containment field has failed.",1)
|
||||
investigate_log("has <font color='red'>failed</font> whilst a singulo exists.","singulo")
|
||||
O.last_warning = world.time
|
||||
|
||||
/obj/machinery/field/generator/shock(mob/living/user)
|
||||
if(fields.len)
|
||||
..()
|
||||
|
||||
/obj/machinery/field/generator/bump_field(atom/movable/AM as mob|obj)
|
||||
if(fields.len)
|
||||
..()
|
||||
|
||||
#undef FG_UNSECURED
|
||||
#undef FG_SECURED
|
||||
#undef FG_WELDED
|
||||
|
||||
#undef FG_OFFLINE
|
||||
#undef FG_CHARGING
|
||||
#undef FG_ONLINE
|
||||
@@ -0,0 +1,37 @@
|
||||
/////SINGULARITY SPAWNER
|
||||
/obj/machinery/the_singularitygen/
|
||||
name = "Gravitational Singularity Generator"
|
||||
desc = "An Odd Device which produces a Gravitational Singularity when set up."
|
||||
icon = 'icons/obj/singularity.dmi'
|
||||
icon_state = "TheSingGen"
|
||||
anchored = 0
|
||||
density = 1
|
||||
use_power = 0
|
||||
var/energy = 0
|
||||
var/creation_type = /obj/singularity
|
||||
|
||||
/obj/machinery/the_singularitygen/process()
|
||||
var/turf/T = get_turf(src)
|
||||
if(src.energy >= 200)
|
||||
feedback_add_details("engine_started","[src.type]")
|
||||
var/obj/singularity/S = new creation_type(T, 50)
|
||||
transfer_fingerprints_to(S)
|
||||
qdel(src)
|
||||
|
||||
/obj/machinery/the_singularitygen/attackby(obj/item/W, mob/user, params)
|
||||
if(istype(W, /obj/item/weapon/wrench))
|
||||
|
||||
if(!anchored && !isinspace())
|
||||
user.visible_message("[user.name] secures [src.name] to the floor.", \
|
||||
"<span class='notice'>You secure the [src.name] to the floor.</span>", \
|
||||
"<span class='italics'>You hear a ratchet.</span>")
|
||||
playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1)
|
||||
anchored = 1
|
||||
else if(anchored)
|
||||
user.visible_message("[user.name] unsecures [src.name] from the floor.", \
|
||||
"<span class='notice'>You unsecure the [src.name] from the floor.</span>", \
|
||||
"<span class='italics'>You hear a ratchet.</span>")
|
||||
playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1)
|
||||
anchored = 0
|
||||
else
|
||||
return ..()
|
||||
@@ -0,0 +1,4 @@
|
||||
/area/engine/engineering/poweralert(state, source)
|
||||
if (state != poweralm)
|
||||
investigate_log("has a power alarm!","singulo")
|
||||
..()
|
||||
@@ -0,0 +1,160 @@
|
||||
/obj/singularity/narsie //Moving narsie to a child object of the singularity so it can be made to function differently. --NEO
|
||||
name = "Nar-sie's Avatar"
|
||||
desc = "Your mind begins to bubble and ooze as it tries to comprehend what it sees."
|
||||
icon = 'icons/obj/magic_terror.dmi'
|
||||
pixel_x = -89
|
||||
pixel_y = -85
|
||||
density = 0
|
||||
current_size = 9 //It moves/eats like a max-size singulo, aside from range. --NEO
|
||||
contained = 0 //Are we going to move around?
|
||||
dissipate = 0 //Do we lose energy over time?
|
||||
move_self = 1 //Do we move on our own?
|
||||
grav_pull = 5 //How many tiles out do we pull?
|
||||
consume_range = 6 //How many tiles out do we eat
|
||||
var/clashing = FALSE //If Nar-Sie is fighting Ratvar
|
||||
|
||||
/obj/singularity/narsie/large
|
||||
name = "Nar-Sie"
|
||||
icon = 'icons/obj/narsie.dmi'
|
||||
// Pixel stuff centers Narsie.
|
||||
pixel_x = -236
|
||||
pixel_y = -256
|
||||
current_size = 12
|
||||
grav_pull = 10
|
||||
consume_range = 12 //How many tiles out do we eat
|
||||
|
||||
/obj/singularity/narsie/large/New()
|
||||
..()
|
||||
world << "<span class='narsie'>NAR-SIE HAS RISEN</span>"
|
||||
world << pick('sound/hallucinations/im_here1.ogg', 'sound/hallucinations/im_here2.ogg')
|
||||
|
||||
var/area/A = get_area(src)
|
||||
if(A)
|
||||
var/image/alert_overlay = image('icons/effects/effects.dmi', "ghostalertsie")
|
||||
notify_ghosts("Nar-Sie has risen in \the [A.name]. Reach out to the Geometer to be given a new shell for your soul.", source = src, alert_overlay = alert_overlay, action=NOTIFY_ATTACK)
|
||||
|
||||
narsie_spawn_animation()
|
||||
|
||||
sleep(70)
|
||||
SSshuttle.emergency.request(null, 0.3) // Cannot recall
|
||||
|
||||
|
||||
/obj/singularity/narsie/large/attack_ghost(mob/dead/observer/user as mob)
|
||||
makeNewConstruct(/mob/living/simple_animal/hostile/construct/harvester, user, null, 0, loc_override = src.loc)
|
||||
PoolOrNew(/obj/effect/particle_effect/smoke/sleeping, src.loc)
|
||||
|
||||
|
||||
/obj/singularity/narsie/process()
|
||||
if(clashing)
|
||||
return
|
||||
eat()
|
||||
if(!target || prob(5))
|
||||
pickcultist()
|
||||
if(istype(target, /obj/structure/clockwork/massive/ratvar))
|
||||
move(get_dir(src, target)) //Oh, it's you again.
|
||||
else
|
||||
move()
|
||||
if(prob(25))
|
||||
mezzer()
|
||||
|
||||
|
||||
/obj/singularity/narsie/Process_Spacemove()
|
||||
return clashing
|
||||
|
||||
|
||||
/obj/singularity/narsie/Bump(atom/A)
|
||||
forceMove(get_turf(A))
|
||||
A.narsie_act()
|
||||
|
||||
|
||||
/obj/singularity/narsie/mezzer()
|
||||
for(var/mob/living/carbon/M in viewers(consume_range, src))
|
||||
if(M.stat == CONSCIOUS)
|
||||
if(!iscultist(M))
|
||||
M << "<span class='cultsmall'>You feel conscious thought crumble away in an instant as you gaze upon [src.name]...</span>"
|
||||
M.apply_effect(3, STUN)
|
||||
|
||||
|
||||
/obj/singularity/narsie/consume(atom/A)
|
||||
A.narsie_act()
|
||||
|
||||
|
||||
/obj/singularity/narsie/ex_act() //No throwing bombs at her either.
|
||||
return
|
||||
|
||||
|
||||
/obj/singularity/narsie/proc/pickcultist() //Narsie rewards her cultists with being devoured first, then picks a ghost to follow.
|
||||
var/list/cultists = list()
|
||||
var/list/noncultists = list()
|
||||
for(var/obj/structure/clockwork/massive/ratvar/enemy in poi_list) //Prioritize killing Ratvar
|
||||
if(enemy.z != z)
|
||||
continue
|
||||
acquire(enemy)
|
||||
return
|
||||
|
||||
for(var/mob/living/carbon/food in living_mob_list) //we don't care about constructs or cult-Ians or whatever. cult-monkeys are fair game i guess
|
||||
var/turf/pos = get_turf(food)
|
||||
if(pos.z != src.z)
|
||||
continue
|
||||
|
||||
if(iscultist(food))
|
||||
cultists += food
|
||||
else
|
||||
noncultists += food
|
||||
|
||||
if(cultists.len) //cultists get higher priority
|
||||
acquire(pick(cultists))
|
||||
return
|
||||
|
||||
if(noncultists.len)
|
||||
acquire(pick(noncultists))
|
||||
return
|
||||
|
||||
//no living humans, follow a ghost instead.
|
||||
for(var/mob/dead/observer/ghost in player_list)
|
||||
if(!ghost.client)
|
||||
continue
|
||||
var/turf/pos = get_turf(ghost)
|
||||
if(pos.z != src.z)
|
||||
continue
|
||||
cultists += ghost
|
||||
if(cultists.len)
|
||||
acquire(pick(cultists))
|
||||
return
|
||||
|
||||
|
||||
/obj/singularity/narsie/proc/acquire(atom/food)
|
||||
if(food == target)
|
||||
return
|
||||
target << "<span class='cultsmall'>NAR-SIE HAS LOST INTEREST IN YOU.</span>"
|
||||
target = food
|
||||
if(isliving(target))
|
||||
target << "<span class ='cult'>NAR-SIE HUNGERS FOR YOUR SOUL.</span>"
|
||||
else
|
||||
target << "<span class ='cult'>NAR-SIE HAS CHOSEN YOU TO LEAD HER TO HER NEXT MEAL.</span>"
|
||||
|
||||
//Wizard narsie
|
||||
/obj/singularity/narsie/wizard
|
||||
grav_pull = 0
|
||||
|
||||
/obj/singularity/narsie/wizard/eat()
|
||||
set background = BACKGROUND_ENABLED
|
||||
// if(defer_powernet_rebuild != 2)
|
||||
// defer_powernet_rebuild = 1
|
||||
for(var/atom/X in urange(consume_range,src,1))
|
||||
if(isturf(X) || istype(X, /atom/movable))
|
||||
consume(X)
|
||||
// if(defer_powernet_rebuild != 2)
|
||||
// defer_powernet_rebuild = 0
|
||||
return
|
||||
|
||||
|
||||
/obj/singularity/narsie/proc/narsie_spawn_animation()
|
||||
icon = 'icons/obj/narsie_spawn_anim.dmi'
|
||||
setDir(SOUTH)
|
||||
move_self = 0
|
||||
flick("narsie_spawn_anim",src)
|
||||
sleep(11)
|
||||
move_self = 1
|
||||
icon = initial(icon)
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
/obj/effect/accelerated_particle
|
||||
name = "Accelerated Particles"
|
||||
desc = "Small things moving very fast."
|
||||
icon = 'icons/obj/machines/particle_accelerator.dmi'
|
||||
icon_state = "particle"
|
||||
anchored = 1
|
||||
density = 1
|
||||
var/movement_range = 10
|
||||
var/energy = 10
|
||||
|
||||
/obj/effect/accelerated_particle/weak
|
||||
movement_range = 8
|
||||
energy = 5
|
||||
|
||||
/obj/effect/accelerated_particle/strong
|
||||
movement_range = 15
|
||||
energy = 15
|
||||
|
||||
/obj/effect/accelerated_particle/powerful
|
||||
movement_range = 20
|
||||
energy = 50
|
||||
|
||||
|
||||
/obj/effect/accelerated_particle/New(loc, dir = 2)
|
||||
src.setDir(dir)
|
||||
|
||||
spawn(0)
|
||||
move(1)
|
||||
|
||||
|
||||
/obj/effect/accelerated_particle/Bump(atom/A)
|
||||
if (A)
|
||||
if(ismob(A))
|
||||
toxmob(A)
|
||||
if((istype(A,/obj/machinery/the_singularitygen))||(istype(A,/obj/singularity/)))
|
||||
A:energy += energy
|
||||
|
||||
|
||||
/obj/effect/accelerated_particle/Bumped(atom/A)
|
||||
if(ismob(A))
|
||||
Bump(A)
|
||||
|
||||
|
||||
/obj/effect/accelerated_particle/ex_act(severity, target)
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/accelerated_particle/proc/toxmob(mob/living/M)
|
||||
M.rad_act(energy*6)
|
||||
M.updatehealth()
|
||||
|
||||
|
||||
/obj/effect/accelerated_particle/proc/move(lag)
|
||||
if(!step(src,dir))
|
||||
loc = get_step(src,dir)
|
||||
movement_range--
|
||||
if(movement_range == 0)
|
||||
qdel(src)
|
||||
else
|
||||
sleep(lag)
|
||||
move(lag)
|
||||
@@ -0,0 +1,203 @@
|
||||
/*Composed of 7 parts :
|
||||
|
||||
3 Particle Emitters
|
||||
1 Power Box
|
||||
1 Fuel Chamber
|
||||
1 End Cap
|
||||
1 Control computer
|
||||
|
||||
Setup map
|
||||
|
||||
|EC|
|
||||
CC|FC|
|
||||
|PB|
|
||||
PE|PE|PE
|
||||
|
||||
*/
|
||||
#define PA_CONSTRUCTION_UNSECURED 0
|
||||
#define PA_CONSTRUCTION_UNWIRED 1
|
||||
#define PA_CONSTRUCTION_PANEL_OPEN 2
|
||||
#define PA_CONSTRUCTION_COMPLETE 3
|
||||
|
||||
/obj/structure/particle_accelerator
|
||||
name = "Particle Accelerator"
|
||||
desc = "Part of a Particle Accelerator."
|
||||
icon = 'icons/obj/machines/particle_accelerator.dmi'
|
||||
icon_state = "none"
|
||||
anchored = 0
|
||||
density = 1
|
||||
var/obj/machinery/particle_accelerator/control_box/master = null
|
||||
var/construction_state = PA_CONSTRUCTION_UNSECURED
|
||||
var/reference = null
|
||||
var/powered = 0
|
||||
var/strength = null
|
||||
|
||||
/obj/structure/particle_accelerator/examine(mob/user)
|
||||
..()
|
||||
|
||||
switch(construction_state)
|
||||
if(PA_CONSTRUCTION_UNSECURED)
|
||||
user << "Looks like it's not attached to the flooring"
|
||||
if(PA_CONSTRUCTION_UNWIRED)
|
||||
user << "It is missing some cables"
|
||||
if(PA_CONSTRUCTION_PANEL_OPEN)
|
||||
user << "The panel is open"
|
||||
|
||||
user << "<span class='notice'>Alt-click to rotate it clockwise.</span>"
|
||||
|
||||
/obj/structure/particle_accelerator/Destroy()
|
||||
construction_state = PA_CONSTRUCTION_UNSECURED
|
||||
if(master)
|
||||
master.connected_parts -= src
|
||||
master.assembled = 0
|
||||
master = null
|
||||
return ..()
|
||||
|
||||
/obj/structure/particle_accelerator/verb/rotate()
|
||||
set name = "Rotate Clockwise"
|
||||
set category = "Object"
|
||||
set src in oview(1)
|
||||
|
||||
if(usr.stat || !usr.canmove || usr.restrained())
|
||||
return
|
||||
if (anchored)
|
||||
usr << "It is fastened to the floor!"
|
||||
return 0
|
||||
setDir(turn(dir, -90))
|
||||
return 1
|
||||
|
||||
/obj/structure/particle_accelerator/AltClick(mob/user)
|
||||
..()
|
||||
if(user.incapacitated())
|
||||
user << "<span class='warning'>You can't do that right now!</span>"
|
||||
return
|
||||
if(!in_range(src, user))
|
||||
return
|
||||
else
|
||||
rotate()
|
||||
|
||||
/obj/structure/particle_accelerator/verb/rotateccw()
|
||||
set name = "Rotate Counter Clockwise"
|
||||
set category = "Object"
|
||||
set src in oview(1)
|
||||
|
||||
if(usr.stat || !usr.canmove || usr.restrained())
|
||||
return
|
||||
if (anchored)
|
||||
usr << "It is fastened to the floor!"
|
||||
return 0
|
||||
setDir(turn(dir, 90))
|
||||
return 1
|
||||
|
||||
/obj/structure/particle_accelerator/attackby(obj/item/W, mob/user, params)
|
||||
var/did_something = FALSE
|
||||
|
||||
switch(construction_state)
|
||||
if(PA_CONSTRUCTION_UNSECURED)
|
||||
if(istype(W, /obj/item/weapon/wrench) && !isinspace())
|
||||
playsound(loc, 'sound/items/Ratchet.ogg', 75, 1)
|
||||
anchored = 1
|
||||
user.visible_message("[user.name] secures the [name] to the floor.", \
|
||||
"You secure the external bolts.")
|
||||
construction_state = PA_CONSTRUCTION_UNWIRED
|
||||
did_something = TRUE
|
||||
if(PA_CONSTRUCTION_UNWIRED)
|
||||
if(istype(W, /obj/item/weapon/wrench))
|
||||
playsound(loc, 'sound/items/Ratchet.ogg', 75, 1)
|
||||
anchored = 0
|
||||
user.visible_message("[user.name] detaches the [name] from the floor.", \
|
||||
"You remove the external bolts.")
|
||||
construction_state = PA_CONSTRUCTION_UNSECURED
|
||||
did_something = TRUE
|
||||
else if(istype(W, /obj/item/stack/cable_coil))
|
||||
var/obj/item/stack/cable_coil/CC = W
|
||||
if(CC.use(1))
|
||||
user.visible_message("[user.name] adds wires to the [name].", \
|
||||
"You add some wires.")
|
||||
construction_state = PA_CONSTRUCTION_PANEL_OPEN
|
||||
did_something = TRUE
|
||||
if(PA_CONSTRUCTION_PANEL_OPEN)
|
||||
if(istype(W, /obj/item/weapon/wirecutters))//TODO:Shock user if its on?
|
||||
user.visible_message("[user.name] removes some wires from the [name].", \
|
||||
"You remove some wires.")
|
||||
construction_state = PA_CONSTRUCTION_UNWIRED
|
||||
did_something = TRUE
|
||||
else if(istype(W, /obj/item/weapon/screwdriver))
|
||||
user.visible_message("[user.name] closes the [name]'s access panel.", \
|
||||
"You close the access panel.")
|
||||
construction_state = PA_CONSTRUCTION_COMPLETE
|
||||
did_something = TRUE
|
||||
if(PA_CONSTRUCTION_COMPLETE)
|
||||
if(istype(W, /obj/item/weapon/screwdriver))
|
||||
user.visible_message("[user.name] opens the [name]'s access panel.", \
|
||||
"You open the access panel.")
|
||||
construction_state = PA_CONSTRUCTION_PANEL_OPEN
|
||||
did_something = TRUE
|
||||
|
||||
if(did_something)
|
||||
user.changeNext_move(CLICK_CD_MELEE)
|
||||
update_state()
|
||||
update_icon()
|
||||
return
|
||||
|
||||
return ..()
|
||||
|
||||
|
||||
/obj/structure/particle_accelerator/Move()
|
||||
..()
|
||||
if(master && master.active)
|
||||
master.toggle_power()
|
||||
investigate_log("was moved whilst active; it <font color='red'>powered down</font>.","singulo")
|
||||
|
||||
/obj/structure/particle_accelerator/blob_act(obj/effect/blob/B)
|
||||
if(prob(50))
|
||||
qdel(src)
|
||||
|
||||
|
||||
/obj/structure/particle_accelerator/update_icon()
|
||||
switch(construction_state)
|
||||
if(PA_CONSTRUCTION_UNSECURED,PA_CONSTRUCTION_UNWIRED)
|
||||
icon_state="[reference]"
|
||||
if(PA_CONSTRUCTION_PANEL_OPEN)
|
||||
icon_state="[reference]w"
|
||||
if(PA_CONSTRUCTION_COMPLETE)
|
||||
if(powered)
|
||||
icon_state="[reference]p[strength]"
|
||||
else
|
||||
icon_state="[reference]c"
|
||||
return
|
||||
|
||||
/obj/structure/particle_accelerator/proc/update_state()
|
||||
if(master)
|
||||
master.update_state()
|
||||
|
||||
/obj/structure/particle_accelerator/proc/connect_master(obj/O)
|
||||
if(O.dir == dir)
|
||||
master = O
|
||||
return 1
|
||||
return 0
|
||||
|
||||
///////////
|
||||
// PARTS //
|
||||
///////////
|
||||
|
||||
|
||||
/obj/structure/particle_accelerator/end_cap
|
||||
name = "Alpha Particle Generation Array"
|
||||
desc = "This is where Alpha particles are generated from \[REDACTED\]"
|
||||
icon_state = "end_cap"
|
||||
reference = "end_cap"
|
||||
|
||||
/obj/structure/particle_accelerator/power_box
|
||||
name = "Particle Focusing EM Lens"
|
||||
desc = "This uses electromagnetic waves to focus the Alpha-Particles."
|
||||
icon = 'icons/obj/machines/particle_accelerator.dmi'
|
||||
icon_state = "power_box"
|
||||
reference = "power_box"
|
||||
|
||||
/obj/structure/particle_accelerator/fuel_chamber
|
||||
name = "EM Acceleration Chamber"
|
||||
desc = "This is where the Alpha particles are accelerated to <b><i>radical speeds</i></b>."
|
||||
icon = 'icons/obj/machines/particle_accelerator.dmi'
|
||||
icon_state = "fuel_chamber"
|
||||
reference = "fuel_chamber"
|
||||
@@ -0,0 +1,330 @@
|
||||
|
||||
|
||||
/obj/machinery/particle_accelerator/control_box
|
||||
name = "Particle Accelerator Control Console"
|
||||
desc = "This controls the density of the particles."
|
||||
icon = 'icons/obj/machines/particle_accelerator.dmi'
|
||||
icon_state = "control_box"
|
||||
anchored = 0
|
||||
density = 1
|
||||
use_power = 0
|
||||
idle_power_usage = 500
|
||||
active_power_usage = 10000
|
||||
dir = NORTH
|
||||
var/strength_upper_limit = 2
|
||||
var/interface_control = 1
|
||||
var/list/obj/structure/particle_accelerator/connected_parts
|
||||
var/assembled = 0
|
||||
var/construction_state = PA_CONSTRUCTION_UNSECURED
|
||||
var/active = 0
|
||||
var/strength = 0
|
||||
var/powered = 0
|
||||
mouse_opacity = 2
|
||||
|
||||
/obj/machinery/particle_accelerator/control_box/New()
|
||||
wires = new /datum/wires/particle_accelerator/control_box(src)
|
||||
connected_parts = list()
|
||||
..()
|
||||
|
||||
/obj/machinery/particle_accelerator/control_box/Destroy()
|
||||
if(active)
|
||||
toggle_power()
|
||||
for(var/CP in connected_parts)
|
||||
var/obj/structure/particle_accelerator/part = CP
|
||||
part.master = null
|
||||
connected_parts.Cut()
|
||||
qdel(wires)
|
||||
wires = null
|
||||
return ..()
|
||||
|
||||
/obj/machinery/particle_accelerator/control_box/attack_hand(mob/user)
|
||||
if(construction_state == PA_CONSTRUCTION_COMPLETE)
|
||||
interact(user)
|
||||
else if(construction_state == PA_CONSTRUCTION_PANEL_OPEN)
|
||||
wires.interact(user)
|
||||
|
||||
/obj/machinery/particle_accelerator/control_box/proc/update_state()
|
||||
if(construction_state < PA_CONSTRUCTION_COMPLETE)
|
||||
use_power = 0
|
||||
assembled = 0
|
||||
active = 0
|
||||
for(var/CP in connected_parts)
|
||||
var/obj/structure/particle_accelerator/part = CP
|
||||
part.strength = null
|
||||
part.powered = 0
|
||||
part.update_icon()
|
||||
connected_parts.Cut()
|
||||
return
|
||||
if(!part_scan())
|
||||
use_power = 1
|
||||
active = 0
|
||||
connected_parts.Cut()
|
||||
|
||||
/obj/machinery/particle_accelerator/control_box/update_icon()
|
||||
if(active)
|
||||
icon_state = "control_boxp1"
|
||||
else
|
||||
if(use_power)
|
||||
if(assembled)
|
||||
icon_state = "control_boxp"
|
||||
else
|
||||
icon_state = "ucontrol_boxp"
|
||||
else
|
||||
switch(construction_state)
|
||||
if(PA_CONSTRUCTION_UNSECURED, PA_CONSTRUCTION_UNWIRED)
|
||||
icon_state = "control_box"
|
||||
if(PA_CONSTRUCTION_PANEL_OPEN)
|
||||
icon_state = "control_boxw"
|
||||
else
|
||||
icon_state = "control_boxc"
|
||||
|
||||
/obj/machinery/particle_accelerator/control_box/Topic(href, href_list)
|
||||
if(..())
|
||||
return
|
||||
|
||||
if(!interface_control)
|
||||
usr << "<span class='error'>ERROR: Request timed out. Check wire contacts.</span>"
|
||||
return
|
||||
|
||||
if(href_list["close"])
|
||||
usr << browse(null, "window=pacontrol")
|
||||
usr.unset_machine()
|
||||
return
|
||||
if(href_list["togglep"])
|
||||
if(!wires.is_cut(WIRE_POWER))
|
||||
toggle_power()
|
||||
|
||||
else if(href_list["scan"])
|
||||
part_scan()
|
||||
|
||||
else if(href_list["strengthup"])
|
||||
if(!wires.is_cut(WIRE_STRENGTH))
|
||||
add_strength()
|
||||
|
||||
else if(href_list["strengthdown"])
|
||||
if(!wires.is_cut(WIRE_STRENGTH))
|
||||
remove_strength()
|
||||
|
||||
updateDialog()
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/particle_accelerator/control_box/proc/strength_change()
|
||||
for(var/CP in connected_parts)
|
||||
var/obj/structure/particle_accelerator/part = CP
|
||||
part.strength = strength
|
||||
part.update_icon()
|
||||
|
||||
/obj/machinery/particle_accelerator/control_box/proc/add_strength(s)
|
||||
if(assembled && (strength < strength_upper_limit))
|
||||
strength++
|
||||
strength_change()
|
||||
|
||||
message_admins("PA Control Computer increased to [strength] by [key_name_admin(usr)](<A HREF='?_src_=holder;adminmoreinfo=\ref[usr]'>?</A>) (<A HREF='?_src_=holder;adminplayerobservefollow=\ref[usr]'>FLW</A>) in ([x],[y],[z] - <A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[x];Y=[y];Z=[z]'>JMP</a>)",0,1)
|
||||
log_game("PA Control Computer increased to [strength] by [key_name(usr)] in ([x],[y],[z])")
|
||||
investigate_log("increased to <font color='red'>[strength]</font> by [key_name(usr)]","singulo")
|
||||
|
||||
|
||||
/obj/machinery/particle_accelerator/control_box/proc/remove_strength(s)
|
||||
if(assembled && (strength > 0))
|
||||
strength--
|
||||
strength_change()
|
||||
|
||||
message_admins("PA Control Computer decreased to [strength] by [key_name_admin(usr)](<A HREF='?_src_=holder;adminmoreinfo=\ref[usr]'>?</A>) (<A HREF='?_src_=holder;adminplayerobservefollow=\ref[usr]'>FLW</A>) in ([x],[y],[z] - <A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[x];Y=[y];Z=[z]'>JMP</a>)",0,1)
|
||||
log_game("PA Control Computer decreased to [strength] by [key_name(usr)] in ([x],[y],[z])")
|
||||
investigate_log("decreased to <font color='green'>[strength]</font> by [key_name(usr)]","singulo")
|
||||
|
||||
|
||||
/obj/machinery/particle_accelerator/control_box/power_change()
|
||||
..()
|
||||
if(stat & NOPOWER)
|
||||
active = 0
|
||||
use_power = 0
|
||||
else if(!stat && construction_state == PA_CONSTRUCTION_COMPLETE)
|
||||
use_power = 1
|
||||
|
||||
/obj/machinery/particle_accelerator/control_box/process()
|
||||
if(active)
|
||||
//a part is missing!
|
||||
if(connected_parts.len < 6)
|
||||
investigate_log("lost a connected part; It <font color='red'>powered down</font>.","singulo")
|
||||
toggle_power()
|
||||
update_icon()
|
||||
return
|
||||
//emit some particles
|
||||
for(var/obj/structure/particle_accelerator/particle_emitter/PE in connected_parts)
|
||||
PE.emit_particle(strength)
|
||||
|
||||
/obj/machinery/particle_accelerator/control_box/proc/part_scan()
|
||||
var/ldir = turn(dir,-90)
|
||||
var/rdir = turn(dir,90)
|
||||
var/odir = turn(dir,180)
|
||||
var/turf/T = loc
|
||||
|
||||
assembled = 0
|
||||
|
||||
var/obj/structure/particle_accelerator/fuel_chamber/F = locate() in orange(1,src)
|
||||
if(!F)
|
||||
return 0
|
||||
|
||||
setDir(F.dir)
|
||||
connected_parts.Cut()
|
||||
|
||||
T = get_step(T,rdir)
|
||||
if(!check_part(T,/obj/structure/particle_accelerator/fuel_chamber))
|
||||
return 0
|
||||
T = get_step(T,odir)
|
||||
if(!check_part(T,/obj/structure/particle_accelerator/end_cap))
|
||||
return 0
|
||||
T = get_step(T,dir)
|
||||
T = get_step(T,dir)
|
||||
if(!check_part(T,/obj/structure/particle_accelerator/power_box))
|
||||
return 0
|
||||
T = get_step(T,dir)
|
||||
if(!check_part(T,/obj/structure/particle_accelerator/particle_emitter/center))
|
||||
return 0
|
||||
T = get_step(T,ldir)
|
||||
if(!check_part(T,/obj/structure/particle_accelerator/particle_emitter/left))
|
||||
return 0
|
||||
T = get_step(T,rdir)
|
||||
T = get_step(T,rdir)
|
||||
if(!check_part(T,/obj/structure/particle_accelerator/particle_emitter/right))
|
||||
return 0
|
||||
|
||||
assembled = 1
|
||||
return 1
|
||||
|
||||
/obj/machinery/particle_accelerator/control_box/proc/check_part(turf/T, type)
|
||||
var/obj/structure/particle_accelerator/PA = locate(/obj/structure/particle_accelerator) in T
|
||||
if(istype(PA, type) && (PA.construction_state == PA_CONSTRUCTION_COMPLETE))
|
||||
if(PA.connect_master(src))
|
||||
connected_parts.Add(PA)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
||||
/obj/machinery/particle_accelerator/control_box/proc/toggle_power()
|
||||
active = !active
|
||||
investigate_log("turned [active?"<font color='red'>ON</font>":"<font color='green'>OFF</font>"] by [usr ? key_name(usr) : "outside forces"]","singulo")
|
||||
message_admins("PA Control Computer turned [active ?"ON":"OFF"] by [usr ? key_name_admin(usr) : "outside forces"](<A HREF='?_src_=holder;adminmoreinfo=\ref[usr]'>?</A>) (<A HREF='?_src_=holder;adminplayerobservefollow=\ref[usr]'>FLW</A>) in ([x],[y],[z] - <A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[x];Y=[y];Z=[z]'>JMP</a>)",0,1)
|
||||
log_game("PA Control Computer turned [active ?"ON":"OFF"] by [usr ? "[key_name(usr)]" : "outside forces"] in ([x],[y],[z])")
|
||||
if(active)
|
||||
use_power = 2
|
||||
for(var/CP in connected_parts)
|
||||
var/obj/structure/particle_accelerator/part = CP
|
||||
part.strength = strength
|
||||
part.powered = 1
|
||||
part.update_icon()
|
||||
else
|
||||
use_power = 1
|
||||
for(var/CP in connected_parts)
|
||||
var/obj/structure/particle_accelerator/part = CP
|
||||
part.strength = null
|
||||
part.powered = 0
|
||||
part.update_icon()
|
||||
return 1
|
||||
|
||||
|
||||
/obj/machinery/particle_accelerator/control_box/interact(mob/user)
|
||||
if((get_dist(src, user) > 1) || (stat & (BROKEN|NOPOWER)))
|
||||
if(!istype(user, /mob/living/silicon))
|
||||
user.unset_machine()
|
||||
user << browse(null, "window=pacontrol")
|
||||
return
|
||||
user.set_machine(src)
|
||||
|
||||
var/dat = ""
|
||||
dat += "<A href='?src=\ref[src];close=1'>Close</A><BR><BR>"
|
||||
dat += "<h3>Status</h3>"
|
||||
if(!assembled)
|
||||
dat += "Unable to detect all parts!<BR>"
|
||||
dat += "<A href='?src=\ref[src];scan=1'>Run Scan</A><BR><BR>"
|
||||
else
|
||||
dat += "All parts in place.<BR><BR>"
|
||||
dat += "Power:"
|
||||
if(active)
|
||||
dat += "On<BR>"
|
||||
else
|
||||
dat += "Off <BR>"
|
||||
dat += "<A href='?src=\ref[src];togglep=1'>Toggle Power</A><BR><BR>"
|
||||
dat += "Particle Strength: [strength] "
|
||||
dat += "<A href='?src=\ref[src];strengthdown=1'>--</A>|<A href='?src=\ref[src];strengthup=1'>++</A><BR><BR>"
|
||||
|
||||
//user << browse(dat, "window=pacontrol;size=420x500")
|
||||
//onclose(user, "pacontrol")
|
||||
var/datum/browser/popup = new(user, "pacontrol", name, 420, 300)
|
||||
popup.set_content(dat)
|
||||
popup.set_title_image(user.browse_rsc_icon(icon, icon_state))
|
||||
popup.open()
|
||||
|
||||
/obj/machinery/particle_accelerator/control_box/examine(mob/user)
|
||||
..()
|
||||
switch(construction_state)
|
||||
if(PA_CONSTRUCTION_UNSECURED)
|
||||
user << "Looks like it's not attached to the flooring"
|
||||
if(PA_CONSTRUCTION_UNWIRED)
|
||||
user << "It is missing some cables"
|
||||
if(PA_CONSTRUCTION_PANEL_OPEN)
|
||||
user << "The panel is open"
|
||||
|
||||
|
||||
/obj/machinery/particle_accelerator/control_box/attackby(obj/item/W, mob/user, params)
|
||||
var/did_something = FALSE
|
||||
|
||||
switch(construction_state)
|
||||
if(PA_CONSTRUCTION_UNSECURED)
|
||||
if(istype(W, /obj/item/weapon/wrench) && !isinspace())
|
||||
playsound(loc, 'sound/items/Ratchet.ogg', 75, 1)
|
||||
anchored = 1
|
||||
user.visible_message("[user.name] secures the [name] to the floor.", \
|
||||
"You secure the external bolts.")
|
||||
construction_state = PA_CONSTRUCTION_UNWIRED
|
||||
did_something = TRUE
|
||||
if(PA_CONSTRUCTION_UNWIRED)
|
||||
if(istype(W, /obj/item/weapon/wrench))
|
||||
playsound(loc, 'sound/items/Ratchet.ogg', 75, 1)
|
||||
anchored = 0
|
||||
user.visible_message("[user.name] detaches the [name] from the floor.", \
|
||||
"You remove the external bolts.")
|
||||
construction_state = PA_CONSTRUCTION_UNSECURED
|
||||
did_something = TRUE
|
||||
else if(istype(W, /obj/item/stack/cable_coil))
|
||||
var/obj/item/stack/cable_coil/CC = W
|
||||
if(CC.use(1))
|
||||
user.visible_message("[user.name] adds wires to the [name].", \
|
||||
"You add some wires.")
|
||||
construction_state = PA_CONSTRUCTION_PANEL_OPEN
|
||||
did_something = TRUE
|
||||
if(PA_CONSTRUCTION_PANEL_OPEN)
|
||||
if(istype(W, /obj/item/weapon/wirecutters))//TODO:Shock user if its on?
|
||||
user.visible_message("[user.name] removes some wires from the [name].", \
|
||||
"You remove some wires.")
|
||||
construction_state = PA_CONSTRUCTION_UNWIRED
|
||||
did_something = TRUE
|
||||
else if(istype(W, /obj/item/weapon/screwdriver))
|
||||
user.visible_message("[user.name] closes the [name]'s access panel.", \
|
||||
"You close the access panel.")
|
||||
construction_state = PA_CONSTRUCTION_COMPLETE
|
||||
did_something = TRUE
|
||||
if(PA_CONSTRUCTION_COMPLETE)
|
||||
if(istype(W, /obj/item/weapon/screwdriver))
|
||||
user.visible_message("[user.name] opens the [name]'s access panel.", \
|
||||
"You open the access panel.")
|
||||
construction_state = PA_CONSTRUCTION_PANEL_OPEN
|
||||
did_something = TRUE
|
||||
|
||||
if(did_something)
|
||||
user.changeNext_move(CLICK_CD_MELEE)
|
||||
update_state()
|
||||
update_icon()
|
||||
return
|
||||
|
||||
..()
|
||||
|
||||
/obj/machinery/particle_accelerator/control_box/blob_act(obj/effect/blob/B)
|
||||
if(prob(50))
|
||||
qdel(src)
|
||||
|
||||
#undef PA_CONSTRUCTION_UNSECURED
|
||||
#undef PA_CONSTRUCTION_UNWIRED
|
||||
#undef PA_CONSTRUCTION_PANEL_OPEN
|
||||
#undef PA_CONSTRUCTION_COMPLETE
|
||||
@@ -0,0 +1,41 @@
|
||||
/obj/structure/particle_accelerator/particle_emitter
|
||||
name = "EM Containment Grid"
|
||||
desc = "This launchs the Alpha particles, might not want to stand near this end."
|
||||
icon = 'icons/obj/machines/particle_accelerator.dmi'
|
||||
icon_state = "none"
|
||||
var/fire_delay = 50
|
||||
var/last_shot = 0
|
||||
|
||||
/obj/structure/particle_accelerator/particle_emitter/center
|
||||
icon_state = "emitter_center"
|
||||
reference = "emitter_center"
|
||||
|
||||
/obj/structure/particle_accelerator/particle_emitter/left
|
||||
icon_state = "emitter_left"
|
||||
reference = "emitter_left"
|
||||
|
||||
/obj/structure/particle_accelerator/particle_emitter/right
|
||||
icon_state = "emitter_right"
|
||||
reference = "emitter_right"
|
||||
|
||||
/obj/structure/particle_accelerator/particle_emitter/proc/set_delay(delay)
|
||||
if(delay >= 0)
|
||||
fire_delay = delay
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/obj/structure/particle_accelerator/particle_emitter/proc/emit_particle(strength = 0)
|
||||
if((last_shot + fire_delay) <= world.time)
|
||||
last_shot = world.time
|
||||
var/turf/T = get_step(src,dir)
|
||||
switch(strength)
|
||||
if(0)
|
||||
new/obj/effect/accelerated_particle/weak(T, dir)
|
||||
if(1)
|
||||
new/obj/effect/accelerated_particle(T, dir)
|
||||
if(2)
|
||||
new/obj/effect/accelerated_particle/strong(T, dir)
|
||||
if(3)
|
||||
new/obj/effect/accelerated_particle/powerful(T, dir)
|
||||
return 1
|
||||
return 0
|
||||
@@ -0,0 +1,429 @@
|
||||
//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:33
|
||||
|
||||
/obj/singularity
|
||||
name = "gravitational singularity"
|
||||
desc = "A gravitational singularity."
|
||||
icon = 'icons/obj/singularity.dmi'
|
||||
icon_state = "singularity_s1"
|
||||
anchored = 1
|
||||
density = 1
|
||||
layer = MASSIVE_OBJ_LAYER
|
||||
luminosity = 6
|
||||
unacidable = 1 //Don't comment this out.
|
||||
var/current_size = 1
|
||||
var/allowed_size = 1
|
||||
var/contained = 1 //Are we going to move around?
|
||||
var/energy = 100 //How strong are we?
|
||||
var/dissipate = 1 //Do we lose energy over time?
|
||||
var/dissipate_delay = 10
|
||||
var/dissipate_track = 0
|
||||
var/dissipate_strength = 1 //How much energy do we lose?
|
||||
var/move_self = 1 //Do we move on our own?
|
||||
var/grav_pull = 4 //How many tiles out do we pull?
|
||||
var/consume_range = 0 //How many tiles out do we eat
|
||||
var/event_chance = 15 //Prob for event each tick
|
||||
var/target = null //its target. moves towards the target if it has one
|
||||
var/last_failed_movement = 0//Will not move in the same dir if it couldnt before, will help with the getting stuck on fields thing
|
||||
var/last_warning
|
||||
var/consumedSupermatter = 0 //If the singularity has eaten a supermatter shard and can go to stage six
|
||||
burn_state = LAVA_PROOF
|
||||
|
||||
/obj/singularity/New(loc, var/starting_energy = 50, var/temp = 0)
|
||||
//CARN: admin-alert for chuckle-fuckery.
|
||||
admin_investigate_setup()
|
||||
|
||||
src.energy = starting_energy
|
||||
..()
|
||||
START_PROCESSING(SSobj, src)
|
||||
poi_list |= src
|
||||
for(var/obj/machinery/power/singularity_beacon/singubeacon in machines)
|
||||
if(singubeacon.active)
|
||||
target = singubeacon
|
||||
break
|
||||
return
|
||||
|
||||
/obj/singularity/Destroy()
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
poi_list.Remove(src)
|
||||
return ..()
|
||||
|
||||
/obj/singularity/Move(atom/newloc, direct)
|
||||
if(current_size >= STAGE_FIVE || check_turfs_in(direct))
|
||||
last_failed_movement = 0//Reset this because we moved
|
||||
return ..()
|
||||
else
|
||||
last_failed_movement = direct
|
||||
return 0
|
||||
|
||||
|
||||
/obj/singularity/attack_hand(mob/user)
|
||||
consume(user)
|
||||
return 1
|
||||
|
||||
/obj/singularity/Process_Spacemove() //The singularity stops drifting for no man!
|
||||
return 0
|
||||
|
||||
/obj/singularity/blob_act(obj/effect/blob/B)
|
||||
return
|
||||
|
||||
/obj/singularity/ex_act(severity, target)
|
||||
switch(severity)
|
||||
if(1)
|
||||
if(current_size <= STAGE_TWO)
|
||||
investigate_log("has been destroyed by a heavy explosion.","singulo")
|
||||
qdel(src)
|
||||
return
|
||||
else
|
||||
energy -= round(((energy+1)/2),1)
|
||||
if(2)
|
||||
energy -= round(((energy+1)/3),1)
|
||||
if(3)
|
||||
energy -= round(((energy+1)/4),1)
|
||||
return
|
||||
|
||||
|
||||
/obj/singularity/bullet_act(obj/item/projectile/P)
|
||||
return 0 //Will there be an impact? Who knows. Will we see it? No.
|
||||
|
||||
|
||||
/obj/singularity/Bump(atom/A)
|
||||
consume(A)
|
||||
return
|
||||
|
||||
|
||||
/obj/singularity/Bumped(atom/A)
|
||||
consume(A)
|
||||
return
|
||||
|
||||
|
||||
/obj/singularity/process()
|
||||
if(current_size >= STAGE_TWO)
|
||||
move()
|
||||
pulse()
|
||||
if(prob(event_chance))//Chance for it to run a special event TODO:Come up with one or two more that fit
|
||||
event()
|
||||
eat()
|
||||
dissipate()
|
||||
check_energy()
|
||||
|
||||
return
|
||||
|
||||
|
||||
/obj/singularity/attack_ai() //to prevent ais from gibbing themselves when they click on one.
|
||||
return
|
||||
|
||||
|
||||
/obj/singularity/proc/admin_investigate_setup()
|
||||
last_warning = world.time
|
||||
var/count = locate(/obj/machinery/field/containment) in urange(30, src, 1)
|
||||
if(!count)
|
||||
message_admins("A singulo has been created without containment fields active ([x],[y],[z])",1)
|
||||
investigate_log("was created. [count?"":"<font color='red'>No containment fields were active</font>"]","singulo")
|
||||
|
||||
/obj/singularity/proc/dissipate()
|
||||
if(!dissipate)
|
||||
return
|
||||
if(dissipate_track >= dissipate_delay)
|
||||
src.energy -= dissipate_strength
|
||||
dissipate_track = 0
|
||||
else
|
||||
dissipate_track++
|
||||
|
||||
|
||||
/obj/singularity/proc/expand(force_size = 0)
|
||||
var/temp_allowed_size = src.allowed_size
|
||||
if(force_size)
|
||||
temp_allowed_size = force_size
|
||||
if(temp_allowed_size >= STAGE_SIX && !consumedSupermatter)
|
||||
temp_allowed_size = STAGE_FIVE
|
||||
switch(temp_allowed_size)
|
||||
if(STAGE_ONE)
|
||||
current_size = STAGE_ONE
|
||||
icon = 'icons/obj/singularity.dmi'
|
||||
icon_state = "singularity_s1"
|
||||
pixel_x = 0
|
||||
pixel_y = 0
|
||||
grav_pull = 4
|
||||
consume_range = 0
|
||||
dissipate_delay = 10
|
||||
dissipate_track = 0
|
||||
dissipate_strength = 1
|
||||
if(STAGE_TWO)
|
||||
if((check_turfs_in(1,1))&&(check_turfs_in(2,1))&&(check_turfs_in(4,1))&&(check_turfs_in(8,1)))
|
||||
current_size = STAGE_TWO
|
||||
icon = 'icons/effects/96x96.dmi'
|
||||
icon_state = "singularity_s3"
|
||||
pixel_x = -32
|
||||
pixel_y = -32
|
||||
grav_pull = 6
|
||||
consume_range = 1
|
||||
dissipate_delay = 5
|
||||
dissipate_track = 0
|
||||
dissipate_strength = 5
|
||||
if(STAGE_THREE)
|
||||
if((check_turfs_in(1,2))&&(check_turfs_in(2,2))&&(check_turfs_in(4,2))&&(check_turfs_in(8,2)))
|
||||
current_size = STAGE_THREE
|
||||
icon = 'icons/effects/160x160.dmi'
|
||||
icon_state = "singularity_s5"
|
||||
pixel_x = -64
|
||||
pixel_y = -64
|
||||
grav_pull = 8
|
||||
consume_range = 2
|
||||
dissipate_delay = 4
|
||||
dissipate_track = 0
|
||||
dissipate_strength = 20
|
||||
if(STAGE_FOUR)
|
||||
if((check_turfs_in(1,3))&&(check_turfs_in(2,3))&&(check_turfs_in(4,3))&&(check_turfs_in(8,3)))
|
||||
current_size = STAGE_FOUR
|
||||
icon = 'icons/effects/224x224.dmi'
|
||||
icon_state = "singularity_s7"
|
||||
pixel_x = -96
|
||||
pixel_y = -96
|
||||
grav_pull = 10
|
||||
consume_range = 3
|
||||
dissipate_delay = 10
|
||||
dissipate_track = 0
|
||||
dissipate_strength = 10
|
||||
if(STAGE_FIVE)//this one also lacks a check for gens because it eats everything
|
||||
current_size = STAGE_FIVE
|
||||
icon = 'icons/effects/288x288.dmi'
|
||||
icon_state = "singularity_s9"
|
||||
pixel_x = -128
|
||||
pixel_y = -128
|
||||
grav_pull = 10
|
||||
consume_range = 4
|
||||
dissipate = 0 //It cant go smaller due to e loss
|
||||
if(STAGE_SIX) //This only happens if a stage 5 singulo consumes a supermatter shard.
|
||||
current_size = STAGE_SIX
|
||||
icon = 'icons/effects/352x352.dmi'
|
||||
icon_state = "singularity_s11"
|
||||
pixel_x = -160
|
||||
pixel_y = -160
|
||||
grav_pull = 15
|
||||
consume_range = 5
|
||||
dissipate = 0
|
||||
if(current_size == allowed_size)
|
||||
investigate_log("<font color='red'>grew to size [current_size]</font>","singulo")
|
||||
return 1
|
||||
else if(current_size < (--temp_allowed_size))
|
||||
expand(temp_allowed_size)
|
||||
else
|
||||
return 0
|
||||
|
||||
|
||||
/obj/singularity/proc/check_energy()
|
||||
if(energy <= 0)
|
||||
investigate_log("collapsed.","singulo")
|
||||
qdel(src)
|
||||
return 0
|
||||
switch(energy)//Some of these numbers might need to be changed up later -Mport
|
||||
if(1 to 199)
|
||||
allowed_size = STAGE_ONE
|
||||
if(200 to 499)
|
||||
allowed_size = STAGE_TWO
|
||||
if(500 to 999)
|
||||
allowed_size = STAGE_THREE
|
||||
if(1000 to 1999)
|
||||
allowed_size = STAGE_FOUR
|
||||
if(2000 to INFINITY)
|
||||
if(energy >= 3000 && consumedSupermatter)
|
||||
allowed_size = STAGE_SIX
|
||||
else
|
||||
allowed_size = STAGE_FIVE
|
||||
if(current_size != allowed_size)
|
||||
expand()
|
||||
return 1
|
||||
|
||||
|
||||
/obj/singularity/proc/eat()
|
||||
set background = BACKGROUND_ENABLED
|
||||
for(var/tile in spiral_range_turfs(grav_pull, src, 1))
|
||||
var/turf/T = tile
|
||||
if(!T || !isturf(loc))
|
||||
continue
|
||||
if(get_dist(T, src) > consume_range)
|
||||
T.singularity_pull(src, current_size)
|
||||
else
|
||||
consume(T)
|
||||
for(var/thing in T)
|
||||
if(isturf(loc))
|
||||
var/atom/movable/X = thing
|
||||
if(get_dist(X, src) > consume_range)
|
||||
X.singularity_pull(src, current_size)
|
||||
else
|
||||
consume(X)
|
||||
CHECK_TICK
|
||||
return
|
||||
|
||||
|
||||
/obj/singularity/proc/consume(atom/A)
|
||||
var/gain = A.singularity_act(current_size, src)
|
||||
src.energy += gain
|
||||
if(istype(A, /obj/machinery/power/supermatter_shard) && !consumedSupermatter)
|
||||
desc = "[initial(desc)] It glows fiercely with inner fire."
|
||||
name = "supermatter-charged [initial(name)]"
|
||||
consumedSupermatter = 1
|
||||
luminosity = 10
|
||||
return
|
||||
|
||||
|
||||
/obj/singularity/proc/move(force_move = 0)
|
||||
if(!move_self)
|
||||
return 0
|
||||
|
||||
var/movement_dir = pick(alldirs - last_failed_movement)
|
||||
|
||||
if(force_move)
|
||||
movement_dir = force_move
|
||||
|
||||
if(target && prob(60))
|
||||
movement_dir = get_dir(src,target) //moves to a singulo beacon, if there is one
|
||||
|
||||
step(src, movement_dir)
|
||||
|
||||
|
||||
/obj/singularity/proc/check_turfs_in(direction = 0, step = 0)
|
||||
if(!direction)
|
||||
return 0
|
||||
var/steps = 0
|
||||
if(!step)
|
||||
switch(current_size)
|
||||
if(STAGE_ONE)
|
||||
steps = 1
|
||||
if(STAGE_TWO)
|
||||
steps = 3//Yes this is right
|
||||
if(STAGE_THREE)
|
||||
steps = 3
|
||||
if(STAGE_FOUR)
|
||||
steps = 4
|
||||
if(STAGE_FIVE)
|
||||
steps = 5
|
||||
else
|
||||
steps = step
|
||||
var/list/turfs = list()
|
||||
var/turf/T = src.loc
|
||||
for(var/i = 1 to steps)
|
||||
T = get_step(T,direction)
|
||||
if(!isturf(T))
|
||||
return 0
|
||||
turfs.Add(T)
|
||||
var/dir2 = 0
|
||||
var/dir3 = 0
|
||||
switch(direction)
|
||||
if(NORTH||SOUTH)
|
||||
dir2 = 4
|
||||
dir3 = 8
|
||||
if(EAST||WEST)
|
||||
dir2 = 1
|
||||
dir3 = 2
|
||||
var/turf/T2 = T
|
||||
for(var/j = 1 to steps-1)
|
||||
T2 = get_step(T2,dir2)
|
||||
if(!isturf(T2))
|
||||
return 0
|
||||
turfs.Add(T2)
|
||||
for(var/k = 1 to steps-1)
|
||||
T = get_step(T,dir3)
|
||||
if(!isturf(T))
|
||||
return 0
|
||||
turfs.Add(T)
|
||||
for(var/turf/T3 in turfs)
|
||||
if(isnull(T3))
|
||||
continue
|
||||
if(!can_move(T3))
|
||||
return 0
|
||||
return 1
|
||||
|
||||
|
||||
/obj/singularity/proc/can_move(turf/T)
|
||||
if(!T)
|
||||
return 0
|
||||
if((locate(/obj/machinery/field/containment) in T)||(locate(/obj/machinery/shieldwall) in T))
|
||||
return 0
|
||||
else if(locate(/obj/machinery/field/generator) in T)
|
||||
var/obj/machinery/field/generator/G = locate(/obj/machinery/field/generator) in T
|
||||
if(G && G.active)
|
||||
return 0
|
||||
else if(locate(/obj/machinery/shieldwallgen) in T)
|
||||
var/obj/machinery/shieldwallgen/S = locate(/obj/machinery/shieldwallgen) in T
|
||||
if(S && S.active)
|
||||
return 0
|
||||
return 1
|
||||
|
||||
|
||||
/obj/singularity/proc/event()
|
||||
var/numb = pick(1,2,3,4,5,6)
|
||||
switch(numb)
|
||||
if(1)//EMP
|
||||
emp_area()
|
||||
if(2,3)//tox damage all carbon mobs in area
|
||||
toxmob()
|
||||
if(4)//Stun mobs who lack optic scanners
|
||||
mezzer()
|
||||
if(5,6) //Sets all nearby mobs on fire
|
||||
if(current_size < STAGE_SIX)
|
||||
return 0
|
||||
combust_mobs()
|
||||
else
|
||||
return 0
|
||||
return 1
|
||||
|
||||
|
||||
/obj/singularity/proc/toxmob()
|
||||
var/toxrange = 10
|
||||
var/radiation = 15
|
||||
var/radiationmin = 3
|
||||
if (energy>200)
|
||||
radiation += round((energy-150)/10,1)
|
||||
radiationmin = round((radiation/5),1)
|
||||
for(var/mob/living/M in view(toxrange, src.loc))
|
||||
M.rad_act(rand(radiationmin,radiation))
|
||||
|
||||
|
||||
/obj/singularity/proc/combust_mobs()
|
||||
for(var/mob/living/carbon/C in urange(20, src, 1))
|
||||
C.visible_message("<span class='warning'>[C]'s skin bursts into flame!</span>", \
|
||||
"<span class='userdanger'>You feel an inner fire as your skin bursts into flames!</span>")
|
||||
C.adjust_fire_stacks(5)
|
||||
C.IgniteMob()
|
||||
return
|
||||
|
||||
|
||||
/obj/singularity/proc/mezzer()
|
||||
for(var/mob/living/carbon/M in oviewers(8, src))
|
||||
if(istype(M, /mob/living/carbon/brain)) //Ignore brains
|
||||
continue
|
||||
|
||||
if(M.stat == CONSCIOUS)
|
||||
if (istype(M,/mob/living/carbon/human))
|
||||
var/mob/living/carbon/human/H = M
|
||||
if(istype(H.glasses, /obj/item/clothing/glasses/meson))
|
||||
var/obj/item/clothing/glasses/meson/MS = H.glasses
|
||||
if(MS.vision_flags == SEE_TURFS)
|
||||
H << "<span class='notice'>You look directly into the [src.name], good thing you had your protective eyewear on!</span>"
|
||||
return
|
||||
|
||||
M.apply_effect(3, STUN)
|
||||
M.visible_message("<span class='danger'>[M] stares blankly at the [src.name]!</span>", \
|
||||
"<span class='userdanger'>You look directly into the [src.name] and feel weak.</span>")
|
||||
return
|
||||
|
||||
|
||||
/obj/singularity/proc/emp_area()
|
||||
empulse(src, 8, 10)
|
||||
return
|
||||
|
||||
|
||||
/obj/singularity/proc/pulse()
|
||||
|
||||
for(var/obj/machinery/power/rad_collector/R in rad_collectors)
|
||||
if(get_dist(R, src) <= 15) // Better than using orange() every process
|
||||
R.receive_pulse(energy)
|
||||
return
|
||||
|
||||
/obj/singularity/singularity_act()
|
||||
var/gain = (energy/2)
|
||||
var/dist = max((current_size - 2),1)
|
||||
explosion(src.loc,(dist),(dist*2),(dist*4))
|
||||
qdel(src)
|
||||
return(gain)
|
||||
@@ -0,0 +1,466 @@
|
||||
// the SMES
|
||||
// stores power
|
||||
|
||||
#define SMESRATE 0.05 // rate of internal charge to external power
|
||||
|
||||
//Cache defines
|
||||
#define SMES_CLEVEL_1 1
|
||||
#define SMES_CLEVEL_2 2
|
||||
#define SMES_CLEVEL_3 3
|
||||
#define SMES_CLEVEL_4 4
|
||||
#define SMES_CLEVEL_5 5
|
||||
#define SMES_OUTPUTTING 6
|
||||
#define SMES_NOT_OUTPUTTING 7
|
||||
#define SMES_INPUTTING 8
|
||||
#define SMES_INPUT_ATTEMPT 9
|
||||
|
||||
/obj/machinery/power/smes
|
||||
name = "power storage unit"
|
||||
desc = "A high-capacity superconducting magnetic energy storage (SMES) unit."
|
||||
icon_state = "smes"
|
||||
density = 1
|
||||
anchored = 1
|
||||
use_power = 0
|
||||
var/capacity = 5e6 // maximum charge
|
||||
var/charge = 0 // actual charge
|
||||
|
||||
var/input_attempt = 1 // 1 = attempting to charge, 0 = not attempting to charge
|
||||
var/inputting = 1 // 1 = actually inputting, 0 = not inputting
|
||||
var/input_level = 50000 // amount of power the SMES attempts to charge by
|
||||
var/input_level_max = 200000 // cap on input_level
|
||||
var/input_available = 0 // amount of charge available from input last tick
|
||||
|
||||
var/output_attempt = 1 // 1 = attempting to output, 0 = not attempting to output
|
||||
var/outputting = 1 // 1 = actually outputting, 0 = not outputting
|
||||
var/output_level = 50000 // amount of power the SMES attempts to output
|
||||
var/output_level_max = 200000 // cap on output_level
|
||||
var/output_used = 0 // amount of power actually outputted. may be less than output_level if the powernet returns excess power
|
||||
|
||||
var/obj/machinery/power/terminal/terminal = null
|
||||
|
||||
var/static/list/smesImageCache
|
||||
|
||||
|
||||
/obj/machinery/power/smes/New()
|
||||
..()
|
||||
var/obj/item/weapon/circuitboard/machine/B = new /obj/item/weapon/circuitboard/machine/smes(null)
|
||||
B.apply_default_parts(src)
|
||||
|
||||
spawn(5)
|
||||
dir_loop:
|
||||
for(var/d in cardinal)
|
||||
var/turf/T = get_step(src, d)
|
||||
for(var/obj/machinery/power/terminal/term in T)
|
||||
if(term && term.dir == turn(d, 180))
|
||||
terminal = term
|
||||
break dir_loop
|
||||
|
||||
if(!terminal)
|
||||
stat |= BROKEN
|
||||
return
|
||||
terminal.master = src
|
||||
update_icon()
|
||||
return
|
||||
|
||||
/obj/item/weapon/circuitboard/machine/smes
|
||||
name = "circuit board (SMES)"
|
||||
build_path = /obj/machinery/power/smes
|
||||
origin_tech = "programming=3;powerstorage=3;engineering=3"
|
||||
req_components = list(
|
||||
/obj/item/stack/cable_coil = 5,
|
||||
/obj/item/weapon/stock_parts/cell = 5,
|
||||
/obj/item/weapon/stock_parts/capacitor = 1)
|
||||
def_components = list(/obj/item/weapon/stock_parts/cell = /obj/item/weapon/stock_parts/cell/high/empty)
|
||||
|
||||
/obj/machinery/power/smes/RefreshParts()
|
||||
var/IO = 0
|
||||
var/MC = 0
|
||||
var/C
|
||||
for(var/obj/item/weapon/stock_parts/capacitor/CP in component_parts)
|
||||
IO += CP.rating
|
||||
input_level_max = initial(input_level_max) * IO
|
||||
output_level_max = initial(output_level_max) * IO
|
||||
for(var/obj/item/weapon/stock_parts/cell/PC in component_parts)
|
||||
MC += PC.maxcharge
|
||||
C += PC.charge
|
||||
capacity = MC / (15000) * 1e6
|
||||
if(!initial(charge) && !charge)
|
||||
charge = C / 15000 * 1e6
|
||||
|
||||
/obj/machinery/power/smes/attackby(obj/item/I, mob/user, params)
|
||||
//opening using screwdriver
|
||||
if(default_deconstruction_screwdriver(user, "[initial(icon_state)]-o", initial(icon_state), I))
|
||||
update_icon()
|
||||
return
|
||||
|
||||
//changing direction using wrench
|
||||
if(default_change_direction_wrench(user, I))
|
||||
terminal = null
|
||||
var/turf/T = get_step(src, dir)
|
||||
for(var/obj/machinery/power/terminal/term in T)
|
||||
if(term && term.dir == turn(dir, 180))
|
||||
terminal = term
|
||||
terminal.master = src
|
||||
user << "<span class='notice'>Terminal found.</span>"
|
||||
break
|
||||
if(!terminal)
|
||||
user << "<span class='alert'>No power source found.</span>"
|
||||
return
|
||||
stat &= ~BROKEN
|
||||
update_icon()
|
||||
return
|
||||
|
||||
//exchanging parts using the RPE
|
||||
if(exchange_parts(user, I))
|
||||
return
|
||||
|
||||
//building and linking a terminal
|
||||
if(istype(I, /obj/item/stack/cable_coil))
|
||||
var/dir = get_dir(user,src)
|
||||
if(dir & (dir-1))//we don't want diagonal click
|
||||
return
|
||||
|
||||
if(terminal) //is there already a terminal ?
|
||||
user << "<span class='warning'>This SMES already has a power terminal!</span>"
|
||||
return
|
||||
|
||||
if(!panel_open) //is the panel open ?
|
||||
user << "<span class='warning'>You must open the maintenance panel first!</span>"
|
||||
return
|
||||
|
||||
var/turf/T = get_turf(user)
|
||||
if (T.intact) //is the floor plating removed ?
|
||||
user << "<span class='warning'>You must first remove the floor plating!</span>"
|
||||
return
|
||||
|
||||
|
||||
var/obj/item/stack/cable_coil/C = I
|
||||
if(C.amount < 10)
|
||||
user << "<span class='warning'>You need more wires!</span>"
|
||||
return
|
||||
|
||||
user << "<span class='notice'>You start building the power terminal...</span>"
|
||||
playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1)
|
||||
|
||||
if(do_after(user, 20, target = src) && C.amount >= 10)
|
||||
var/obj/structure/cable/N = T.get_cable_node() //get the connecting node cable, if there's one
|
||||
if (prob(50) && electrocute_mob(usr, N, N)) //animate the electrocution if uncautious and unlucky
|
||||
var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
|
||||
s.set_up(5, 1, src)
|
||||
s.start()
|
||||
return
|
||||
|
||||
C.use(10)
|
||||
user.visible_message(\
|
||||
"[user.name] has built a power terminal.",\
|
||||
"<span class='notice'>You build the power terminal.</span>")
|
||||
|
||||
//build the terminal and link it to the network
|
||||
make_terminal(T)
|
||||
terminal.connect_to_network()
|
||||
return
|
||||
|
||||
//disassembling the terminal
|
||||
if(istype(I, /obj/item/weapon/wirecutters) && terminal && panel_open)
|
||||
terminal.dismantle(user)
|
||||
return
|
||||
|
||||
//crowbarring it !
|
||||
var/turf/T = get_turf(src)
|
||||
if(default_deconstruction_crowbar(I))
|
||||
message_admins("[src] has been deconstructed by [key_name_admin(user)](<A HREF='?_src_=holder;adminmoreinfo=\ref[user]'>?</A>) (<A HREF='?_src_=holder;adminplayerobservefollow=\ref[user]'>FLW</A>) in ([T.x],[T.y],[T.z] - <A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[T.x];Y=[T.y];Z=[T.z]'>JMP</a>)",0,1)
|
||||
log_game("[src] has been deconstructed by [key_name(user)]")
|
||||
investigate_log("SMES deconstructed by [key_name(user)]","singulo")
|
||||
return
|
||||
|
||||
return ..()
|
||||
|
||||
/obj/machinery/power/smes/deconstruction()
|
||||
for(var/obj/item/weapon/stock_parts/cell/cell in component_parts)
|
||||
cell.charge = (charge / capacity) * cell.maxcharge
|
||||
|
||||
/obj/machinery/power/smes/Destroy()
|
||||
if(ticker && ticker.current_state == GAME_STATE_PLAYING)
|
||||
var/area/area = get_area(src)
|
||||
message_admins("SMES deleted at (<A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[x];Y=[y];Z=[z]'>[area.name]</a>)")
|
||||
log_game("SMES deleted at ([area.name])")
|
||||
investigate_log("<font color='red'>deleted</font> at ([area.name])","singulo")
|
||||
if(terminal)
|
||||
disconnect_terminal()
|
||||
return ..()
|
||||
|
||||
// create a terminal object pointing towards the SMES
|
||||
// wires will attach to this
|
||||
/obj/machinery/power/smes/proc/make_terminal(turf/T)
|
||||
terminal = new/obj/machinery/power/terminal(T)
|
||||
terminal.setDir(get_dir(T,src))
|
||||
terminal.master = src
|
||||
|
||||
/obj/machinery/power/smes/disconnect_terminal()
|
||||
if(terminal)
|
||||
terminal.master = null
|
||||
terminal = null
|
||||
|
||||
|
||||
/obj/machinery/power/smes/update_icon()
|
||||
cut_overlays()
|
||||
if(stat & BROKEN)
|
||||
return
|
||||
|
||||
if(panel_open)
|
||||
return
|
||||
|
||||
if(!smesImageCache || !smesImageCache.len)
|
||||
smesImageCache = list()
|
||||
smesImageCache.len = 9
|
||||
|
||||
smesImageCache[SMES_CLEVEL_1] = image('icons/obj/power.dmi',"smes-og1")
|
||||
smesImageCache[SMES_CLEVEL_2] = image('icons/obj/power.dmi',"smes-og2")
|
||||
smesImageCache[SMES_CLEVEL_3] = image('icons/obj/power.dmi',"smes-og3")
|
||||
smesImageCache[SMES_CLEVEL_4] = image('icons/obj/power.dmi',"smes-og4")
|
||||
smesImageCache[SMES_CLEVEL_5] = image('icons/obj/power.dmi',"smes-og5")
|
||||
|
||||
smesImageCache[SMES_OUTPUTTING] = image('icons/obj/power.dmi', "smes-op1")
|
||||
smesImageCache[SMES_NOT_OUTPUTTING] = image('icons/obj/power.dmi',"smes-op0")
|
||||
smesImageCache[SMES_INPUTTING] = image('icons/obj/power.dmi', "smes-oc1")
|
||||
smesImageCache[SMES_INPUT_ATTEMPT] = image('icons/obj/power.dmi', "smes-oc0")
|
||||
|
||||
if(outputting)
|
||||
add_overlay(smesImageCache[SMES_OUTPUTTING])
|
||||
else
|
||||
add_overlay(smesImageCache[SMES_NOT_OUTPUTTING])
|
||||
|
||||
if(inputting)
|
||||
add_overlay(smesImageCache[SMES_INPUTTING])
|
||||
else
|
||||
if(input_attempt)
|
||||
add_overlay(smesImageCache[SMES_INPUT_ATTEMPT])
|
||||
|
||||
var/clevel = chargedisplay()
|
||||
if(clevel>0)
|
||||
add_overlay(smesImageCache[clevel])
|
||||
return
|
||||
|
||||
|
||||
/obj/machinery/power/smes/proc/chargedisplay()
|
||||
return round(5.5*charge/capacity)
|
||||
|
||||
/obj/machinery/power/smes/process()
|
||||
|
||||
if(stat & BROKEN)
|
||||
return
|
||||
|
||||
//store machine state to see if we need to update the icon overlays
|
||||
var/last_disp = chargedisplay()
|
||||
var/last_chrg = inputting
|
||||
var/last_onln = outputting
|
||||
|
||||
//inputting
|
||||
if(terminal && input_attempt)
|
||||
input_available = terminal.surplus()
|
||||
|
||||
if(inputting)
|
||||
if(input_available > 0 && input_available >= input_level) // if there's power available, try to charge
|
||||
|
||||
var/load = min((capacity-charge)/SMESRATE, input_level) // charge at set rate, limited to spare capacity
|
||||
|
||||
charge += load * SMESRATE // increase the charge
|
||||
|
||||
add_load(load) // add the load to the terminal side network
|
||||
|
||||
else // if not enough capcity
|
||||
inputting = 0 // stop inputting
|
||||
|
||||
else
|
||||
if(input_attempt && input_available > 0 && input_available >= input_level)
|
||||
inputting = 1
|
||||
else
|
||||
inputting = 0
|
||||
|
||||
//outputting
|
||||
if(output_attempt)
|
||||
if(outputting)
|
||||
output_used = min( charge/SMESRATE, output_level) //limit output to that stored
|
||||
|
||||
charge -= output_used*SMESRATE // reduce the storage (may be recovered in /restore() if excessive)
|
||||
|
||||
add_avail(output_used) // add output to powernet (smes side)
|
||||
|
||||
if(output_used < 0.0001) // either from no charge or set to 0
|
||||
outputting = 0
|
||||
investigate_log("lost power and turned <font color='red'>off</font>","singulo")
|
||||
else if(output_attempt && charge > output_level && output_level > 0)
|
||||
outputting = 1
|
||||
else
|
||||
output_used = 0
|
||||
else
|
||||
outputting = 0
|
||||
|
||||
// only update icon if state changed
|
||||
if(last_disp != chargedisplay() || last_chrg != inputting || last_onln != outputting)
|
||||
update_icon()
|
||||
|
||||
|
||||
|
||||
// called after all power processes are finished
|
||||
// restores charge level to smes if there was excess this ptick
|
||||
/obj/machinery/power/smes/proc/restore()
|
||||
if(stat & BROKEN)
|
||||
return
|
||||
|
||||
if(!outputting)
|
||||
output_used = 0
|
||||
return
|
||||
|
||||
var/excess = powernet.netexcess // this was how much wasn't used on the network last ptick, minus any removed by other SMESes
|
||||
|
||||
excess = min(output_used, excess) // clamp it to how much was actually output by this SMES last ptick
|
||||
|
||||
excess = min((capacity-charge)/SMESRATE, excess) // for safety, also limit recharge by space capacity of SMES (shouldn't happen)
|
||||
|
||||
// now recharge this amount
|
||||
|
||||
var/clev = chargedisplay()
|
||||
|
||||
charge += excess * SMESRATE // restore unused power
|
||||
powernet.netexcess -= excess // remove the excess from the powernet, so later SMESes don't try to use it
|
||||
|
||||
output_used -= excess
|
||||
|
||||
if(clev != chargedisplay() ) //if needed updates the icons overlay
|
||||
update_icon()
|
||||
return
|
||||
|
||||
|
||||
/obj/machinery/power/smes/add_load(amount)
|
||||
if(terminal && terminal.powernet)
|
||||
terminal.powernet.load += amount
|
||||
|
||||
/obj/machinery/power/smes/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, \
|
||||
datum/tgui/master_ui = null, datum/ui_state/state = default_state)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "smes", name, 340, 440, master_ui, state)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/power/smes/ui_data()
|
||||
var/list/data = list(
|
||||
"capacityPercent" = round(100*charge/capacity, 0.1),
|
||||
"capacity" = capacity,
|
||||
"charge" = charge,
|
||||
|
||||
"inputAttempt" = input_attempt,
|
||||
"inputting" = inputting,
|
||||
"inputLevel" = input_level,
|
||||
"inputLevelMax" = input_level_max,
|
||||
"inputAvailable" = input_available,
|
||||
|
||||
"outputAttempt" = output_attempt,
|
||||
"outputting" = outputting,
|
||||
"outputLevel" = output_level,
|
||||
"outputLevelMax" = output_level_max,
|
||||
"outputUsed" = output_used
|
||||
)
|
||||
return data
|
||||
|
||||
/obj/machinery/power/smes/ui_act(action, params)
|
||||
if(..())
|
||||
return
|
||||
switch(action)
|
||||
if("tryinput")
|
||||
input_attempt = !input_attempt
|
||||
log_smes(usr.ckey)
|
||||
update_icon()
|
||||
. = TRUE
|
||||
if("tryoutput")
|
||||
output_attempt = !output_attempt
|
||||
log_smes(usr.ckey)
|
||||
update_icon()
|
||||
. = TRUE
|
||||
if("input")
|
||||
var/target = params["target"]
|
||||
var/adjust = text2num(params["adjust"])
|
||||
if(target == "input")
|
||||
target = input("New input target (0-[input_level_max]):", name, input_level) as num|null
|
||||
if(!isnull(target) && !..())
|
||||
. = TRUE
|
||||
else if(target == "min")
|
||||
target = 0
|
||||
. = TRUE
|
||||
else if(target == "max")
|
||||
target = input_level_max
|
||||
. = TRUE
|
||||
else if(adjust)
|
||||
target = input_level + adjust
|
||||
. = TRUE
|
||||
else if(text2num(target) != null)
|
||||
target = text2num(target)
|
||||
. = TRUE
|
||||
if(.)
|
||||
input_level = Clamp(target, 0, input_level_max)
|
||||
log_smes(usr.ckey)
|
||||
if("output")
|
||||
var/target = params["target"]
|
||||
var/adjust = text2num(params["adjust"])
|
||||
if(target == "input")
|
||||
target = input("New output target (0-[output_level_max]):", name, output_level) as num|null
|
||||
if(!isnull(target) && !..())
|
||||
. = TRUE
|
||||
else if(target == "min")
|
||||
target = 0
|
||||
. = TRUE
|
||||
else if(target == "max")
|
||||
target = output_level_max
|
||||
. = TRUE
|
||||
else if(adjust)
|
||||
target = output_level + adjust
|
||||
. = TRUE
|
||||
else if(text2num(target) != null)
|
||||
target = text2num(target)
|
||||
. = TRUE
|
||||
if(.)
|
||||
output_level = Clamp(target, 0, output_level_max)
|
||||
log_smes(usr.ckey)
|
||||
|
||||
/obj/machinery/power/smes/proc/log_smes(user = "")
|
||||
investigate_log("input/output; [input_level>output_level?"<font color='green'>":"<font color='red'>"][input_level]/[output_level]</font> | Charge: [charge] | Output-mode: [output_attempt?"<font color='green'>on</font>":"<font color='red'>off</font>"] | Input-mode: [input_attempt?"<font color='green'>auto</font>":"<font color='red'>off</font>"] by [user]", "singulo")
|
||||
|
||||
|
||||
/obj/machinery/power/smes/emp_act(severity)
|
||||
input_attempt = rand(0,1)
|
||||
inputting = input_attempt
|
||||
output_attempt = rand(0,1)
|
||||
outputting = output_attempt
|
||||
output_level = rand(0, output_level_max)
|
||||
input_level = rand(0, input_level_max)
|
||||
charge -= 1e6/severity
|
||||
if (charge < 0)
|
||||
charge = 0
|
||||
update_icon()
|
||||
log_smes("an emp")
|
||||
..()
|
||||
|
||||
/obj/machinery/power/smes/engineering
|
||||
charge = 1.5e6 // Engineering starts with some charge for singulo
|
||||
|
||||
/obj/machinery/power/smes/magical
|
||||
name = "magical power storage unit"
|
||||
desc = "A high-capacity superconducting magnetic energy storage (SMES) unit. Magically produces power."
|
||||
|
||||
/obj/machinery/power/smes/magical/process()
|
||||
capacity = INFINITY
|
||||
charge = INFINITY
|
||||
..()
|
||||
|
||||
|
||||
#undef SMESRATE
|
||||
|
||||
#undef SMES_CLEVEL_1
|
||||
#undef SMES_CLEVEL_2
|
||||
#undef SMES_CLEVEL_3
|
||||
#undef SMES_CLEVEL_4
|
||||
#undef SMES_CLEVEL_5
|
||||
#undef SMES_OUTPUTTING
|
||||
#undef SMES_NOT_OUTPUTTING
|
||||
#undef SMES_INPUTTING
|
||||
#undef SMES_INPUT_ATTEMPT
|
||||
@@ -0,0 +1,552 @@
|
||||
#define SOLAR_MAX_DIST 40
|
||||
#define SOLARGENRATE 1500
|
||||
|
||||
/obj/machinery/power/solar
|
||||
name = "solar panel"
|
||||
desc = "A solar panel. Generates electricity when in contact with sunlight."
|
||||
icon = 'icons/obj/power.dmi'
|
||||
icon_state = "sp_base"
|
||||
anchored = 1
|
||||
density = 1
|
||||
use_power = 0
|
||||
idle_power_usage = 0
|
||||
active_power_usage = 0
|
||||
var/id = 0
|
||||
var/health = 20
|
||||
var/obscured = 0
|
||||
var/sunfrac = 0
|
||||
var/adir = SOUTH // actual dir
|
||||
var/ndir = SOUTH // target dir
|
||||
var/turn_angle = 0
|
||||
var/obj/machinery/power/solar_control/control = null
|
||||
|
||||
/obj/machinery/power/solar/New(var/turf/loc, var/obj/item/solar_assembly/S)
|
||||
..(loc)
|
||||
Make(S)
|
||||
connect_to_network()
|
||||
|
||||
/obj/machinery/power/solar/Destroy()
|
||||
unset_control() //remove from control computer
|
||||
return ..()
|
||||
|
||||
//set the control of the panel to a given computer if closer than SOLAR_MAX_DIST
|
||||
/obj/machinery/power/solar/proc/set_control(obj/machinery/power/solar_control/SC)
|
||||
if(!SC || (get_dist(src, SC) > SOLAR_MAX_DIST))
|
||||
return 0
|
||||
control = SC
|
||||
SC.connected_panels |= src
|
||||
return 1
|
||||
|
||||
//set the control of the panel to null and removes it from the control list of the previous control computer if needed
|
||||
/obj/machinery/power/solar/proc/unset_control()
|
||||
if(control)
|
||||
control.connected_panels.Remove(src)
|
||||
control = null
|
||||
|
||||
/obj/machinery/power/solar/proc/Make(obj/item/solar_assembly/S)
|
||||
if(!S)
|
||||
S = new /obj/item/solar_assembly(src)
|
||||
S.glass_type = /obj/item/stack/sheet/glass
|
||||
S.anchored = 1
|
||||
S.loc = src
|
||||
if(S.glass_type == /obj/item/stack/sheet/rglass) //if the panel is in reinforced glass
|
||||
health *= 2 //this need to be placed here, because panels already on the map don't have an assembly linked to
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/power/solar/attackby(obj/item/weapon/W, mob/user, params)
|
||||
if(istype(W, /obj/item/weapon/crowbar))
|
||||
playsound(src.loc, 'sound/machines/click.ogg', 50, 1)
|
||||
user.visible_message("[user] begins to take the glass off the solar panel.", "<span class='notice'>You begin to take the glass off the solar panel...</span>")
|
||||
if(do_after(user, 50/W.toolspeed, target = src))
|
||||
var/obj/item/solar_assembly/S = locate() in src
|
||||
if(S)
|
||||
S.loc = src.loc
|
||||
S.give_glass(stat & BROKEN)
|
||||
|
||||
playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1)
|
||||
user.visible_message("[user] takes the glass off the solar panel.", "<span class='notice'>You take the glass off the solar panel.</span>")
|
||||
qdel(src)
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/machinery/power/solar/bullet_act(obj/item/projectile/P)
|
||||
. = ..()
|
||||
take_damage(P.damage, P.damage_type)
|
||||
|
||||
/obj/machinery/power/solar/hitby(AM as mob|obj)
|
||||
..()
|
||||
var/tforce = 0
|
||||
if(ismob(AM))
|
||||
tforce = 20
|
||||
else if(isobj(AM))
|
||||
var/obj/item/I = AM
|
||||
tforce = I.throwforce
|
||||
take_damage(tforce)
|
||||
|
||||
/obj/machinery/power/solar/take_damage(damage, damage_type = BRUTE, sound_effect = 1)
|
||||
switch(damage_type)
|
||||
if(BRUTE)
|
||||
if(sound_effect)
|
||||
if(stat & BROKEN)
|
||||
playsound(loc, 'sound/effects/hit_on_shattered_glass.ogg', 60, 1)
|
||||
else
|
||||
playsound(loc, 'sound/effects/Glasshit.ogg', 90, 1)
|
||||
if(BURN)
|
||||
if(sound_effect)
|
||||
playsound(loc, 'sound/items/Welder.ogg', 100, 1)
|
||||
else
|
||||
return
|
||||
health -= damage
|
||||
if(health <= 0)
|
||||
playsound(src, "shatter", 70, 1)
|
||||
new /obj/item/weapon/shard(src.loc)
|
||||
new /obj/item/weapon/shard(src.loc)
|
||||
qdel(src)
|
||||
else if(health <= 10)
|
||||
if(!(stat & BROKEN))
|
||||
playsound(loc, 'sound/effects/Glassbr3.ogg', 100, 1)
|
||||
set_broken()
|
||||
|
||||
/obj/machinery/power/solar/update_icon()
|
||||
..()
|
||||
cut_overlays()
|
||||
if(stat & BROKEN)
|
||||
add_overlay(image('icons/obj/power.dmi', icon_state = "solar_panel-b", layer = FLY_LAYER))
|
||||
else
|
||||
add_overlay(image('icons/obj/power.dmi', icon_state = "solar_panel", layer = FLY_LAYER))
|
||||
src.setDir(angle2dir(adir))
|
||||
return
|
||||
|
||||
//calculates the fraction of the sunlight that the panel recieves
|
||||
/obj/machinery/power/solar/proc/update_solar_exposure()
|
||||
if(obscured)
|
||||
sunfrac = 0
|
||||
return
|
||||
|
||||
//find the smaller angle between the direction the panel is facing and the direction of the sun (the sign is not important here)
|
||||
var/p_angle = min(abs(adir - SSsun.angle), 360 - abs(adir - SSsun.angle))
|
||||
|
||||
if(p_angle > 90) // if facing more than 90deg from sun, zero output
|
||||
sunfrac = 0
|
||||
return
|
||||
|
||||
sunfrac = cos(p_angle) ** 2
|
||||
//isn't the power recieved from the incoming light proportionnal to cos(p_angle) (Lambert's cosine law) rather than cos(p_angle)^2 ?
|
||||
|
||||
/obj/machinery/power/solar/process()//TODO: remove/add this from machines to save on processing as needed ~Carn PRIORITY
|
||||
if(stat & BROKEN)
|
||||
return
|
||||
if(!control) //if there's no sun or the panel is not linked to a solar control computer, no need to proceed
|
||||
return
|
||||
|
||||
if(powernet)
|
||||
if(powernet == control.powernet)//check if the panel is still connected to the computer
|
||||
if(obscured) //get no light from the sun, so don't generate power
|
||||
return
|
||||
var/sgen = SOLARGENRATE * sunfrac
|
||||
add_avail(sgen)
|
||||
control.gen += sgen
|
||||
else //if we're no longer on the same powernet, remove from control computer
|
||||
unset_control()
|
||||
|
||||
/obj/machinery/power/solar/proc/set_broken()
|
||||
. = (!(stat & BROKEN))
|
||||
stat |= BROKEN
|
||||
unset_control()
|
||||
update_icon()
|
||||
|
||||
|
||||
/obj/machinery/power/solar/ex_act(severity, target)
|
||||
..()
|
||||
if(!qdeleted(src))
|
||||
switch(severity)
|
||||
if(2)
|
||||
take_damage(rand(10,20), BRUTE, 0)
|
||||
if(3)
|
||||
take_damage(rand(5,15), BRUTE, 0)
|
||||
|
||||
/obj/machinery/power/solar/fake/New(var/turf/loc, var/obj/item/solar_assembly/S)
|
||||
..(loc, S, 0)
|
||||
|
||||
/obj/machinery/power/solar/fake/process()
|
||||
. = PROCESS_KILL
|
||||
return
|
||||
|
||||
//trace towards sun to see if we're in shadow
|
||||
/obj/machinery/power/solar/proc/occlusion()
|
||||
|
||||
var/ax = x // start at the solar panel
|
||||
var/ay = y
|
||||
var/turf/T = null
|
||||
var/dx = SSsun.dx
|
||||
var/dy = SSsun.dy
|
||||
|
||||
for(var/i = 1 to 20) // 20 steps is enough
|
||||
ax += dx // do step
|
||||
ay += dy
|
||||
|
||||
T = locate( round(ax,0.5),round(ay,0.5),z)
|
||||
|
||||
if(T.x == 1 || T.x==world.maxx || T.y==1 || T.y==world.maxy) // not obscured if we reach the edge
|
||||
break
|
||||
|
||||
if(T.density) // if we hit a solid turf, panel is obscured
|
||||
obscured = 1
|
||||
return
|
||||
|
||||
obscured = 0 // if hit the edge or stepped 20 times, not obscured
|
||||
update_solar_exposure()
|
||||
|
||||
|
||||
//
|
||||
// Solar Assembly - For construction of solar arrays.
|
||||
//
|
||||
|
||||
/obj/item/solar_assembly
|
||||
name = "solar panel assembly"
|
||||
desc = "A solar panel assembly kit, allows constructions of a solar panel, or with a tracking circuit board, a solar tracker."
|
||||
icon = 'icons/obj/power.dmi'
|
||||
icon_state = "sp_base"
|
||||
item_state = "electropack"
|
||||
w_class = 4 // Pretty big!
|
||||
anchored = 0
|
||||
var/tracker = 0
|
||||
var/glass_type = null
|
||||
|
||||
/obj/item/solar_assembly/attack_hand(mob/user)
|
||||
if(!anchored && isturf(loc)) // You can't pick it up
|
||||
..()
|
||||
|
||||
// Give back the glass type we were supplied with
|
||||
/obj/item/solar_assembly/proc/give_glass(device_broken)
|
||||
if(device_broken)
|
||||
new /obj/item/weapon/shard(loc)
|
||||
new /obj/item/weapon/shard(loc)
|
||||
else if(glass_type)
|
||||
var/obj/item/stack/sheet/S = new glass_type(loc)
|
||||
S.amount = 2
|
||||
glass_type = null
|
||||
|
||||
|
||||
/obj/item/solar_assembly/attackby(obj/item/weapon/W, mob/user, params)
|
||||
if(istype(W, /obj/item/weapon/wrench) && isturf(loc))
|
||||
if(isinspace())
|
||||
user << "<span class='warning'>You can't secure [src] here.</span>"
|
||||
return
|
||||
anchored = !anchored
|
||||
if(anchored)
|
||||
user.visible_message("[user] wrenches the solar assembly into place.", "<span class='notice'>You wrench the solar assembly into place.</span>")
|
||||
playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1)
|
||||
else
|
||||
user.visible_message("[user] unwrenches the solar assembly from its place.", "<span class='notice'>You unwrench the solar assembly from its place.</span>")
|
||||
playsound(src.loc, 'sound/items/Ratchet.ogg', 75, 1)
|
||||
return 1
|
||||
|
||||
if(istype(W, /obj/item/stack/sheet/glass) || istype(W, /obj/item/stack/sheet/rglass))
|
||||
if(!anchored)
|
||||
user << "<span class='warning'>You need to secure the assembly before you can add glass.</span>"
|
||||
return
|
||||
var/obj/item/stack/sheet/S = W
|
||||
if(S.use(2))
|
||||
glass_type = W.type
|
||||
playsound(src.loc, 'sound/machines/click.ogg', 50, 1)
|
||||
user.visible_message("[user] places the glass on the solar assembly.", "<span class='notice'>You place the glass on the solar assembly.</span>")
|
||||
if(tracker)
|
||||
new /obj/machinery/power/tracker(get_turf(src), src)
|
||||
else
|
||||
new /obj/machinery/power/solar(get_turf(src), src)
|
||||
else
|
||||
user << "<span class='warning'>You need two sheets of glass to put them into a solar panel!</span>"
|
||||
return
|
||||
return 1
|
||||
|
||||
if(!tracker)
|
||||
if(istype(W, /obj/item/weapon/electronics/tracker))
|
||||
if(!user.drop_item())
|
||||
return
|
||||
tracker = 1
|
||||
qdel(W)
|
||||
user.visible_message("[user] inserts the electronics into the solar assembly.", "<span class='notice'>You insert the electronics into the solar assembly.</span>")
|
||||
return 1
|
||||
else
|
||||
if(istype(W, /obj/item/weapon/crowbar))
|
||||
new /obj/item/weapon/electronics/tracker(src.loc)
|
||||
tracker = 0
|
||||
user.visible_message("[user] takes out the electronics from the solar assembly.", "<span class='notice'>You take out the electronics from the solar assembly.</span>")
|
||||
return 1
|
||||
return ..()
|
||||
|
||||
//
|
||||
// Solar Control Computer
|
||||
//
|
||||
|
||||
/obj/machinery/power/solar_control
|
||||
name = "solar panel control"
|
||||
desc = "A controller for solar panel arrays."
|
||||
icon = 'icons/obj/computer.dmi'
|
||||
icon_state = "computer"
|
||||
anchored = 1
|
||||
density = 1
|
||||
use_power = 1
|
||||
idle_power_usage = 250
|
||||
var/health = 25
|
||||
var/icon_screen = "solar"
|
||||
var/icon_keyboard = "power_key"
|
||||
var/id = 0
|
||||
var/currentdir = 0
|
||||
var/targetdir = 0 // target angle in manual tracking (since it updates every game minute)
|
||||
var/gen = 0
|
||||
var/lastgen = 0
|
||||
var/track = 0 // 0= off 1=timed 2=auto (tracker)
|
||||
var/trackrate = 600 // 300-900 seconds
|
||||
var/nexttime = 0 // time for a panel to rotate of 1° in manual tracking
|
||||
var/obj/machinery/power/tracker/connected_tracker = null
|
||||
var/list/connected_panels = list()
|
||||
|
||||
|
||||
/obj/machinery/power/solar_control/New()
|
||||
..()
|
||||
if(ticker)
|
||||
initialize()
|
||||
connect_to_network()
|
||||
|
||||
/obj/machinery/power/solar_control/Destroy()
|
||||
for(var/obj/machinery/power/solar/M in connected_panels)
|
||||
M.unset_control()
|
||||
if(connected_tracker)
|
||||
connected_tracker.unset_control()
|
||||
return ..()
|
||||
|
||||
/obj/machinery/power/solar_control/disconnect_from_network()
|
||||
..()
|
||||
SSsun.solars.Remove(src)
|
||||
|
||||
/obj/machinery/power/solar_control/connect_to_network()
|
||||
var/to_return = ..()
|
||||
if(powernet) //if connected and not already in solar_list...
|
||||
SSsun.solars |= src //... add it
|
||||
return to_return
|
||||
|
||||
//search for unconnected panels and trackers in the computer powernet and connect them
|
||||
/obj/machinery/power/solar_control/proc/search_for_connected()
|
||||
if(powernet)
|
||||
for(var/obj/machinery/power/M in powernet.nodes)
|
||||
if(istype(M, /obj/machinery/power/solar))
|
||||
var/obj/machinery/power/solar/S = M
|
||||
if(!S.control) //i.e unconnected
|
||||
S.set_control(src)
|
||||
else if(istype(M, /obj/machinery/power/tracker))
|
||||
if(!connected_tracker) //if there's already a tracker connected to the computer don't add another
|
||||
var/obj/machinery/power/tracker/T = M
|
||||
if(!T.control) //i.e unconnected
|
||||
T.set_control(src)
|
||||
|
||||
//called by the sun controller, update the facing angle (either manually or via tracking) and rotates the panels accordingly
|
||||
/obj/machinery/power/solar_control/proc/update()
|
||||
if(stat & (NOPOWER | BROKEN))
|
||||
return
|
||||
|
||||
switch(track)
|
||||
if(1)
|
||||
if(trackrate) //we're manual tracking. If we set a rotation speed...
|
||||
currentdir = targetdir //...the current direction is the targetted one (and rotates panels to it)
|
||||
if(2) // auto-tracking
|
||||
if(connected_tracker)
|
||||
connected_tracker.set_angle(SSsun.angle)
|
||||
|
||||
set_panels(currentdir)
|
||||
updateDialog()
|
||||
|
||||
|
||||
/obj/machinery/power/solar_control/initialize()
|
||||
..()
|
||||
if(!powernet) return
|
||||
set_panels(currentdir)
|
||||
|
||||
/obj/machinery/power/solar_control/update_icon()
|
||||
cut_overlays()
|
||||
if(stat & NOPOWER)
|
||||
add_overlay("[icon_keyboard]_off")
|
||||
return
|
||||
add_overlay(icon_keyboard)
|
||||
if(stat & BROKEN)
|
||||
add_overlay("[icon_state]_broken")
|
||||
else
|
||||
add_overlay(icon_screen)
|
||||
if(currentdir > -1)
|
||||
add_overlay(image('icons/obj/computer.dmi', "solcon-o", FLY_LAYER, angle2dir(currentdir)))
|
||||
|
||||
/obj/machinery/power/solar_control/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, \
|
||||
datum/tgui/master_ui = null, datum/ui_state/state = default_state)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "solar_control", name, 500, 400, master_ui, state)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/power/solar_control/ui_data()
|
||||
var/data = list()
|
||||
|
||||
data["generated"] = round(lastgen)
|
||||
data["angle"] = currentdir
|
||||
data["direction"] = angle2text(currentdir)
|
||||
|
||||
data["tracking_state"] = track
|
||||
data["tracking_rate"] = trackrate
|
||||
data["rotating_way"] = (trackrate<0 ? "CCW" : "CW")
|
||||
|
||||
data["connected_panels"] = connected_panels.len
|
||||
data["connected_tracker"] = (connected_tracker ? 1 : 0)
|
||||
return data
|
||||
|
||||
/obj/machinery/power/solar_control/ui_act(action, params)
|
||||
if(..())
|
||||
return
|
||||
switch(action)
|
||||
if("direction")
|
||||
var/adjust = text2num(params["adjust"])
|
||||
if(adjust)
|
||||
currentdir = Clamp((360 + adjust + currentdir) % 360, 0, 359)
|
||||
targetdir = currentdir
|
||||
set_panels(currentdir)
|
||||
. = TRUE
|
||||
if("rate")
|
||||
var/adjust = text2num(params["adjust"])
|
||||
if(adjust)
|
||||
trackrate = Clamp(trackrate + adjust, -7200, 7200)
|
||||
if(trackrate)
|
||||
nexttime = world.time + 36000 / abs(trackrate)
|
||||
. = TRUE
|
||||
if("tracking")
|
||||
var/mode = text2num(params["mode"])
|
||||
if(mode)
|
||||
track = mode
|
||||
. = TRUE
|
||||
if(mode == 2 && connected_tracker)
|
||||
connected_tracker.set_angle(SSsun.angle)
|
||||
set_panels(currentdir)
|
||||
else if(mode == 1)
|
||||
targetdir = currentdir
|
||||
if(trackrate)
|
||||
nexttime = world.time + 36000 / abs(trackrate)
|
||||
set_panels(targetdir)
|
||||
if("refresh")
|
||||
search_for_connected()
|
||||
if(connected_tracker && track == 2)
|
||||
connected_tracker.set_angle(SSsun.angle)
|
||||
set_panels(currentdir)
|
||||
. = TRUE
|
||||
|
||||
/obj/machinery/power/solar_control/attackby(obj/item/I, mob/user, params)
|
||||
if(istype(I, /obj/item/weapon/screwdriver))
|
||||
playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1)
|
||||
if(do_after(user, 20/I.toolspeed, target = src))
|
||||
if (src.stat & BROKEN)
|
||||
user << "<span class='notice'>The broken glass falls out.</span>"
|
||||
var/obj/structure/frame/computer/A = new /obj/structure/frame/computer( src.loc )
|
||||
new /obj/item/weapon/shard( src.loc )
|
||||
var/obj/item/weapon/circuitboard/computer/solar_control/M = new /obj/item/weapon/circuitboard/computer/solar_control( A )
|
||||
for (var/obj/C in src)
|
||||
C.loc = src.loc
|
||||
A.circuit = M
|
||||
A.state = 3
|
||||
A.icon_state = "3"
|
||||
A.anchored = 1
|
||||
qdel(src)
|
||||
else
|
||||
user << "<span class='notice'>You disconnect the monitor.</span>"
|
||||
var/obj/structure/frame/computer/A = new /obj/structure/frame/computer( src.loc )
|
||||
var/obj/item/weapon/circuitboard/computer/solar_control/M = new /obj/item/weapon/circuitboard/computer/solar_control( A )
|
||||
for (var/obj/C in src)
|
||||
C.loc = src.loc
|
||||
A.circuit = M
|
||||
A.state = 4
|
||||
A.icon_state = "4"
|
||||
A.anchored = 1
|
||||
qdel(src)
|
||||
else if(user.a_intent != "harm" && !(I.flags & NOBLUDGEON))
|
||||
src.attack_hand(user)
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/machinery/power/solar_control/bullet_act(obj/item/projectile/P)
|
||||
. = ..()
|
||||
take_damage(P.damage, P.damage_type)
|
||||
|
||||
/obj/machinery/power/solar_control/take_damage(damage, damage_type = BRUTE, sound_effect = 1)
|
||||
switch(damage_type)
|
||||
if(BRUTE)
|
||||
if(sound_effect)
|
||||
if(stat & BROKEN)
|
||||
playsound(src.loc, 'sound/effects/hit_on_shattered_glass.ogg', 70, 1)
|
||||
else
|
||||
playsound(src.loc, 'sound/effects/Glasshit.ogg', 75, 1)
|
||||
if(BURN)
|
||||
if(sound_effect)
|
||||
playsound(src.loc, 'sound/items/Welder.ogg', 100, 1)
|
||||
else
|
||||
return
|
||||
health -= damage
|
||||
if(health <= 0 && !(stat & BROKEN))
|
||||
playsound(loc, 'sound/effects/Glassbr3.ogg', 100, 1)
|
||||
stat |= BROKEN
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/power/solar_control/process()
|
||||
lastgen = gen
|
||||
gen = 0
|
||||
|
||||
if(stat & (NOPOWER | BROKEN))
|
||||
return
|
||||
|
||||
if(connected_tracker) //NOTE : handled here so that we don't add trackers to the processing list
|
||||
if(connected_tracker.powernet != powernet)
|
||||
connected_tracker.unset_control()
|
||||
|
||||
if(track==1 && trackrate) //manual tracking and set a rotation speed
|
||||
if(nexttime <= world.time) //every time we need to increase/decrease the angle by 1°...
|
||||
targetdir = (targetdir + trackrate/abs(trackrate) + 360) % 360 //... do it
|
||||
nexttime += 36000/abs(trackrate) //reset the counter for the next 1°
|
||||
|
||||
//rotates the panel to the passed angle
|
||||
/obj/machinery/power/solar_control/proc/set_panels(currentdir)
|
||||
|
||||
for(var/obj/machinery/power/solar/S in connected_panels)
|
||||
S.adir = currentdir //instantly rotates the panel
|
||||
S.occlusion()//and
|
||||
S.update_icon() //update it
|
||||
|
||||
update_icon()
|
||||
|
||||
|
||||
/obj/machinery/power/solar_control/power_change()
|
||||
..()
|
||||
update_icon()
|
||||
|
||||
|
||||
/obj/machinery/power/solar_control/proc/set_broken()
|
||||
stat |= BROKEN
|
||||
update_icon()
|
||||
|
||||
|
||||
/obj/machinery/power/solar_control/ex_act(severity, target)
|
||||
..()
|
||||
if(!qdeleted(src))
|
||||
switch(severity)
|
||||
if(2)
|
||||
take_damage(rand(20,30), BRUTE, 0)
|
||||
if(3)
|
||||
take_damage(rand(10,20), BRUTE, 0)
|
||||
|
||||
/obj/machinery/power/solar_control/blob_act(obj/effect/blob/B)
|
||||
if (prob(75))
|
||||
set_broken()
|
||||
src.density = 0
|
||||
|
||||
|
||||
//
|
||||
// MISC
|
||||
//
|
||||
|
||||
/obj/item/weapon/paper/solar
|
||||
name = "paper- 'Going green! Setup your own solar array instructions.'"
|
||||
info = "<h1>Welcome</h1><p>At greencorps we love the environment, and space. With this package you are able to help mother nature and produce energy without any usage of fossil fuel or plasma! Singularity energy is dangerous while solar energy is safe, which is why it's better. Now here is how you setup your own solar array.</p><p>You can make a solar panel by wrenching the solar assembly onto a cable node. Adding a glass panel, reinforced or regular glass will do, will finish the construction of your solar panel. It is that easy!</p><p>Now after setting up 19 more of these solar panels you will want to create a solar tracker to keep track of our mother nature's gift, the sun. These are the same steps as before except you insert the tracker equipment circuit into the assembly before performing the final step of adding the glass. You now have a tracker! Now the last step is to add a computer to calculate the sun's movements and to send commands to the solar panels to change direction with the sun. Setting up the solar computer is the same as setting up any computer, so you should have no trouble in doing that. You do need to put a wire node under the computer, and the wire needs to be connected to the tracker.</p><p>Congratulations, you should have a working solar array. If you are having trouble, here are some tips. Make sure all solar equipment are on a cable node, even the computer. You can always deconstruct your creations if you make a mistake.</p><p>That's all to it, be safe, be green!</p>"
|
||||
@@ -0,0 +1,341 @@
|
||||
//Ported from /vg/station13, which was in turn forked from baystation12;
|
||||
//Please do not bother them with bugs from this port, however, as it has been modified quite a bit.
|
||||
//Modifications include removing the world-ending full supermatter variation, and leaving only the shard.
|
||||
|
||||
#define NITROGEN_RETARDATION_FACTOR 2 //Higher == N2 slows reaction more
|
||||
#define THERMAL_RELEASE_MODIFIER 5 //Higher == less heat released during reaction
|
||||
#define PLASMA_RELEASE_MODIFIER 750 //Higher == less plasma released by reaction
|
||||
#define OXYGEN_RELEASE_MODIFIER 325 //Higher == less oxygen released at high temperature/power
|
||||
#define REACTION_POWER_MODIFIER 0.55 //Higher == more overall power
|
||||
|
||||
|
||||
//These would be what you would get at point blank, decreases with distance
|
||||
#define DETONATION_RADS 200
|
||||
#define DETONATION_HALLUCINATION 600
|
||||
|
||||
|
||||
#define WARNING_DELAY 30 //seconds between warnings.
|
||||
|
||||
/obj/machinery/power/supermatter_shard
|
||||
name = "supermatter shard"
|
||||
desc = "A strangely translucent and iridescent crystal that looks like it used to be part of a larger structure. <span class='danger'>You get headaches just from looking at it.</span>"
|
||||
icon = 'icons/obj/supermatter.dmi'
|
||||
icon_state = "darkmatter_shard"
|
||||
density = 1
|
||||
anchored = 0
|
||||
luminosity = 4
|
||||
|
||||
|
||||
var/gasefficency = 0.125
|
||||
|
||||
var/base_icon_state = "darkmatter_shard"
|
||||
|
||||
var/damage = 0
|
||||
var/damage_archived = 0
|
||||
var/safe_alert = "Crystalline hyperstructure returning to safe operating levels."
|
||||
var/warning_point = 50
|
||||
var/warning_alert = "Danger! Crystal hyperstructure instability!"
|
||||
var/emergency_point = 500
|
||||
var/emergency_alert = "CRYSTAL DELAMINATION IMMINENT."
|
||||
var/explosion_point = 900
|
||||
|
||||
var/emergency_issued = 0
|
||||
|
||||
var/explosion_power = 8
|
||||
|
||||
var/lastwarning = 0 // Time in 1/10th of seconds since the last sent warning
|
||||
var/power = 0
|
||||
|
||||
var/oxygen = 0 // Moving this up here for easier debugging.
|
||||
|
||||
//Temporary values so that we can optimize this
|
||||
//How much the bullets damage should be multiplied by when it is added to the internal variables
|
||||
var/config_bullet_energy = 2
|
||||
//How much of the power is left after processing is finished?
|
||||
// var/config_power_reduction_per_tick = 0.5
|
||||
//How much hallucination should it produce per unit of power?
|
||||
var/config_hallucination_power = 0.1
|
||||
|
||||
var/obj/item/device/radio/radio
|
||||
|
||||
//for logging
|
||||
var/has_been_powered = 0
|
||||
var/has_reached_emergency = 0
|
||||
|
||||
// For making hugbox supermatter
|
||||
var/takes_damage = 1
|
||||
var/produces_gas = 1
|
||||
|
||||
/obj/machinery/power/supermatter_shard/New()
|
||||
. = ..()
|
||||
poi_list |= src
|
||||
radio = new(src)
|
||||
radio.listening = 0
|
||||
investigate_log("has been created.", "supermatter")
|
||||
|
||||
|
||||
/obj/machinery/power/supermatter_shard/Destroy()
|
||||
investigate_log("has been destroyed.", "supermatter")
|
||||
qdel(radio)
|
||||
poi_list -= src
|
||||
. = ..()
|
||||
|
||||
/obj/machinery/power/supermatter_shard/proc/explode()
|
||||
investigate_log("has exploded.", "supermatter")
|
||||
explosion(get_turf(src), explosion_power, explosion_power * 2, explosion_power * 3, explosion_power * 4, 1, 1)
|
||||
qdel(src)
|
||||
|
||||
/obj/machinery/power/supermatter_shard/process()
|
||||
var/turf/L = loc
|
||||
|
||||
if(isnull(L)) // We have a null turf...something is wrong, stop processing this entity.
|
||||
return PROCESS_KILL
|
||||
|
||||
if(!istype(L)) //We are in a crate or somewhere that isn't turf, if we return to turf resume processing but for now.
|
||||
return //Yeah just stop.
|
||||
|
||||
if(istype(L, /turf/open/space)) // Stop processing this stuff if we've been ejected.
|
||||
return
|
||||
|
||||
if(damage > warning_point) // while the core is still damaged and it's still worth noting its status
|
||||
if((world.timeofday - lastwarning) / 10 >= WARNING_DELAY)
|
||||
var/stability = num2text(round((damage / explosion_point) * 100))
|
||||
|
||||
if(damage > emergency_point)
|
||||
radio.talk_into(src, "[emergency_alert] Instability: [stability]%")
|
||||
lastwarning = world.timeofday
|
||||
if(!has_reached_emergency)
|
||||
investigate_log("has reached the emergency point for the first time.", "supermatter")
|
||||
message_admins("[src] has reached the emergency point <A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[x];Y=[y];Z=[z]'>(JMP)</a>.")
|
||||
has_reached_emergency = 1
|
||||
|
||||
else if(damage >= damage_archived) // The damage is still going up
|
||||
radio.talk_into(src, "[warning_alert] Instability: [stability]%")
|
||||
lastwarning = world.timeofday - 150
|
||||
|
||||
else // Phew, we're safe
|
||||
radio.talk_into(src, "[safe_alert]")
|
||||
lastwarning = world.timeofday
|
||||
|
||||
if(damage > explosion_point)
|
||||
for(var/mob/living/mob in living_mob_list)
|
||||
if(istype(mob, /mob/living/carbon/human))
|
||||
//Hilariously enough, running into a closet should make you get hit the hardest.
|
||||
var/mob/living/carbon/human/H = mob
|
||||
H.hallucination += max(50, min(300, DETONATION_HALLUCINATION * sqrt(1 / (get_dist(mob, src) + 1)) ) )
|
||||
var/rads = DETONATION_RADS * sqrt( 1 / (get_dist(mob, src) + 1) )
|
||||
mob.rad_act(rads)
|
||||
|
||||
explode()
|
||||
|
||||
//Ok, get the air from the turf
|
||||
var/datum/gas_mixture/env = L.return_air()
|
||||
|
||||
var/datum/gas_mixture/removed
|
||||
|
||||
if(produces_gas)
|
||||
//Remove gas from surrounding area
|
||||
removed = env.remove(gasefficency * env.total_moles())
|
||||
else
|
||||
// Pass all the gas related code an empty gas container
|
||||
removed = new()
|
||||
|
||||
if(!removed || !removed.total_moles())
|
||||
if(takes_damage)
|
||||
damage += max((power-1600)/10, 0)
|
||||
power = min(power, 1600)
|
||||
return 1
|
||||
|
||||
damage_archived = damage
|
||||
if(takes_damage)
|
||||
damage = max( damage + ( (removed.temperature - 800) / 150 ) , 0 )
|
||||
//Ok, 100% oxygen atmosphere = best reaction
|
||||
//Maxes out at 100% oxygen pressure
|
||||
var/removed_nitrogen = 0
|
||||
if(removed.gases["n2"])
|
||||
removed_nitrogen = (removed.gases["n2"][MOLES] * NITROGEN_RETARDATION_FACTOR)
|
||||
|
||||
removed.assert_gases("o2", "plasma")
|
||||
|
||||
oxygen = max(min((removed.gases["o2"][MOLES] - removed_nitrogen) / MOLES_CELLSTANDARD, 1), 0)
|
||||
|
||||
var/temp_factor = 50
|
||||
|
||||
if(oxygen > 0.8)
|
||||
// with a perfect gas mix, make the power less based on heat
|
||||
icon_state = "[base_icon_state]_glow"
|
||||
else
|
||||
// in normal mode, base the produced energy around the heat
|
||||
temp_factor = 30
|
||||
icon_state = base_icon_state
|
||||
|
||||
power = max( (removed.temperature * temp_factor / T0C) * oxygen + power, 0) //Total laser power plus an overload
|
||||
|
||||
//We've generated power, now let's transfer it to the collectors for storing/usage
|
||||
transfer_energy()
|
||||
|
||||
var/device_energy = power * REACTION_POWER_MODIFIER
|
||||
|
||||
//To figure out how much temperature to add each tick, consider that at one atmosphere's worth
|
||||
//of pure oxygen, with all four lasers firing at standard energy and no N2 present, at room temperature
|
||||
//that the device energy is around 2140. At that stage, we don't want too much heat to be put out
|
||||
//Since the core is effectively "cold"
|
||||
|
||||
//Also keep in mind we are only adding this temperature to (efficiency)% of the one tile the rock
|
||||
//is on. An increase of 4*C @ 25% efficiency here results in an increase of 1*C / (#tilesincore) overall.
|
||||
removed.temperature += (device_energy / THERMAL_RELEASE_MODIFIER)
|
||||
|
||||
removed.temperature = max(0, min(removed.temperature, 2500))
|
||||
|
||||
//Calculate how much gas to release
|
||||
removed.gases["plasma"][MOLES] += max(device_energy / PLASMA_RELEASE_MODIFIER, 0)
|
||||
|
||||
removed.gases["o2"][MOLES] += max((device_energy + removed.temperature - T0C) / OXYGEN_RELEASE_MODIFIER, 0)
|
||||
|
||||
if(produces_gas)
|
||||
env.merge(removed)
|
||||
|
||||
for(var/mob/living/carbon/human/l in view(src, min(7, round(power ** 0.25)))) // If they can see it without mesons on. Bad on them.
|
||||
if(!istype(l.glasses, /obj/item/clothing/glasses/meson))
|
||||
var/D = sqrt(1 / max(1, get_dist(l, src)))
|
||||
l.hallucination += power * config_hallucination_power * D
|
||||
l.hallucination = Clamp(0, 200, l.hallucination)
|
||||
|
||||
for(var/mob/living/l in range(src, round((power / 100) ** 0.25)))
|
||||
var/rads = (power / 10) * sqrt( 1 / max(get_dist(l, src),1) )
|
||||
l.rad_act(rads)
|
||||
|
||||
power -= (power/500)**3
|
||||
|
||||
return 1
|
||||
|
||||
/obj/machinery/power/supermatter_shard
|
||||
|
||||
/obj/machinery/power/supermatter_shard/bullet_act(obj/item/projectile/Proj)
|
||||
var/turf/L = loc
|
||||
if(!istype(L)) // We don't run process() when we are in space
|
||||
return 0 // This stops people from being able to really power up the supermatter
|
||||
// Then bring it inside to explode instantly upon landing on a valid turf.
|
||||
|
||||
|
||||
if(Proj.flag != "bullet")
|
||||
power += Proj.damage * config_bullet_energy
|
||||
if(!has_been_powered)
|
||||
investigate_log("has been powered for the first time.", "supermatter")
|
||||
message_admins("[src] has been powered for the first time <A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[x];Y=[y];Z=[z]'>(JMP)</a>.")
|
||||
has_been_powered = 1
|
||||
else if(takes_damage)
|
||||
damage += Proj.damage * config_bullet_energy
|
||||
return 0
|
||||
|
||||
/obj/machinery/power/supermatter_shard/singularity_act()
|
||||
var/gain = 100
|
||||
investigate_log("Supermatter shard consumed by singularity.","singulo")
|
||||
message_admins("Singularity has consumed a supermatter shard and can now become stage six.")
|
||||
visible_message("<span class='userdanger'>[src] is consumed by the singularity!</span>")
|
||||
for(var/mob/M in mob_list)
|
||||
M << 'sound/effects/supermatter.ogg' //everyone goan know bout this
|
||||
M << "<span class='boldannounce'>A horrible screeching fills your ears, and a wave of dread washes over you...</span>"
|
||||
qdel(src)
|
||||
return(gain)
|
||||
|
||||
/obj/machinery/power/supermatter_shard/blob_act(obj/effect/blob/B)
|
||||
if(B && !istype(loc, /turf/open/space)) //does nothing in space
|
||||
playsound(get_turf(src), 'sound/effects/supermatter.ogg', 50, 1)
|
||||
damage += B.health * 0.5 //take damage equal to 50% of remaining blob health before it tried to eat us
|
||||
if(B.health > 100)
|
||||
B.visible_message("<span class='danger'>\The [B] strikes at \the [src] and flinches away!</span>",\
|
||||
"<span class='italics'>You hear a loud crack as you are washed with a wave of heat.</span>")
|
||||
B.take_damage(100, BURN, src)
|
||||
else
|
||||
B.visible_message("<span class='danger'>\The [B] strikes at \the [src] and rapidly flashes to ash.</span>",\
|
||||
"<span class='italics'>You hear a loud crack as you are washed with a wave of heat.</span>")
|
||||
Consume(B)
|
||||
|
||||
/obj/machinery/power/supermatter_shard/attack_paw(mob/user)
|
||||
return attack_hand(user)
|
||||
|
||||
|
||||
/obj/machinery/power/supermatter_shard/attack_robot(mob/user)
|
||||
if(Adjacent(user))
|
||||
return attack_hand(user)
|
||||
else
|
||||
user << "<span class='warning'>You attempt to interface with the control circuits but find they are not connected to your network. Maybe in a future firmware update.</span>"
|
||||
|
||||
/obj/machinery/power/supermatter_shard/attack_ai(mob/user)
|
||||
user << "<span class='warning'>You attempt to interface with the control circuits but find they are not connected to your network. Maybe in a future firmware update.</span>"
|
||||
|
||||
/obj/machinery/power/supermatter_shard/attack_hand(mob/living/user)
|
||||
if(!istype(user))
|
||||
return
|
||||
user.visible_message("<span class='danger'>\The [user] reaches out and touches \the [src], inducing a resonance... \his body starts to glow and bursts into flames before flashing into ash.</span>",\
|
||||
"<span class='userdanger'>You reach out and touch \the [src]. Everything starts burning and all you can hear is ringing. Your last thought is \"That was not a wise decision.\"</span>",\
|
||||
"<span class='italics'>You hear an unearthly noise as a wave of heat washes over you.</span>")
|
||||
|
||||
playsound(get_turf(src), 'sound/effects/supermatter.ogg', 50, 1)
|
||||
|
||||
Consume(user)
|
||||
|
||||
/obj/machinery/power/supermatter_shard/proc/transfer_energy()
|
||||
for(var/obj/machinery/power/rad_collector/R in rad_collectors)
|
||||
if(get_dist(R, src) <= 15) // Better than using orange() every process
|
||||
R.receive_pulse(power/10)
|
||||
|
||||
/obj/machinery/power/supermatter_shard/attackby(obj/item/W, mob/living/user, params)
|
||||
if(!istype(W) || (W.flags & ABSTRACT) || !istype(user))
|
||||
return
|
||||
if(user.drop_item(W))
|
||||
Consume(W)
|
||||
user.visible_message("<span class='danger'>As [user] touches \the [src] with \a [W], silence fills the room...</span>",\
|
||||
"<span class='userdanger'>You touch \the [src] with \the [W], and everything suddenly goes silent.</span>\n<span class='notice'>\The [W] flashes into dust as you flinch away from \the [src].</span>",\
|
||||
"<span class='italics'>Everything suddenly goes silent.</span>")
|
||||
|
||||
playsound(get_turf(src), 'sound/effects/supermatter.ogg', 50, 1)
|
||||
|
||||
radiation_pulse(get_turf(src), 1, 1, 150, 1)
|
||||
|
||||
|
||||
/obj/machinery/power/supermatter_shard/Bumped(atom/AM as mob|obj)
|
||||
if(istype(AM, /mob/living))
|
||||
AM.visible_message("<span class='danger'>\The [AM] slams into \the [src] inducing a resonance... \his body starts to glow and catch flame before flashing into ash.</span>",\
|
||||
"<span class='userdanger'>You slam into \the [src] as your ears are filled with unearthly ringing. Your last thought is \"Oh, fuck.\"</span>",\
|
||||
"<span class='italics'>You hear an unearthly noise as a wave of heat washes over you.</span>")
|
||||
else if(isobj(AM) && !istype(AM, /obj/effect))
|
||||
AM.visible_message("<span class='danger'>\The [AM] smacks into \the [src] and rapidly flashes to ash.</span>",\
|
||||
"<span class='italics'>You hear a loud crack as you are washed with a wave of heat.</span>")
|
||||
else
|
||||
return
|
||||
|
||||
playsound(get_turf(src), 'sound/effects/supermatter.ogg', 50, 1)
|
||||
|
||||
Consume(AM)
|
||||
|
||||
|
||||
/obj/machinery/power/supermatter_shard/proc/Consume(atom/movable/AM)
|
||||
if(istype(AM, /mob/living))
|
||||
var/mob/living/user = AM
|
||||
message_admins("[src] has consumed [key_name_admin(user)]<A HREF='?_src_=holder;adminmoreinfo=\ref[user]'>?</A> (<A HREF='?_src_=holder;adminplayerobservefollow=\ref[user]'>FLW</A>) <A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[x];Y=[y];Z=[z]'>(JMP)</a>.")
|
||||
investigate_log("has consumed [key_name(user)].", "supermatter")
|
||||
user.dust()
|
||||
power += 200
|
||||
else if(isobj(AM) && (!istype(AM, /obj/effect) || istype(AM, /obj/effect/blob)))
|
||||
investigate_log("has consumed [AM].", "supermatter")
|
||||
qdel(AM)
|
||||
|
||||
power += 200
|
||||
|
||||
//Some poor sod got eaten, go ahead and irradiate people nearby.
|
||||
radiation_pulse(get_turf(src), 4, 10, 500, 1)
|
||||
for(var/mob/living/L in range(10))
|
||||
investigate_log("has irradiated [L] after consuming [AM].", "supermatter")
|
||||
if(L in view())
|
||||
L.show_message("<span class='danger'>As \the [src] slowly stops resonating, you find your skin covered in new radiation burns.</span>", 1,\
|
||||
"<span class='danger'>The unearthly ringing subsides and you notice you have new radiation burns.</span>", 2)
|
||||
else
|
||||
L.show_message("<span class='italics'>You hear an uneartly ringing and notice your skin is covered in fresh radiation burns.</span>", 2)
|
||||
|
||||
// When you wanna make a supermatter shard for the dramatic effect, but
|
||||
// don't want it exploding suddenly
|
||||
/obj/machinery/power/supermatter_shard/hugbox
|
||||
takes_damage = 0
|
||||
produces_gas = 0
|
||||
@@ -0,0 +1,84 @@
|
||||
//This is a power switch. When turned on it looks at the cables around the tile that it's on and notes which cables are trying to connect to it.
|
||||
//After it knows this it creates the number of cables from the center to each of the cables attempting to conenct. These cables cannot be removed
|
||||
//with wirecutters. When the switch is turned off it removes all the cables on the tile it's on.
|
||||
//The switch uses a 5s delay to prevent powernet change spamming.
|
||||
/*
|
||||
/obj/structure/powerswitch
|
||||
name = "power switch"
|
||||
desc = "A switch that controls power."
|
||||
icon = 'icons/obj/power.dmi'
|
||||
icon_state = "switch-dbl-up"
|
||||
var/icon_state_on = "switch-dbl-down"
|
||||
var/icon_state_off = "switch-dbl-up"
|
||||
density = 0
|
||||
anchored = 1
|
||||
var/on = 0 //up is off, down is on
|
||||
var/busy = 0 //set to 1 when you start pulling
|
||||
|
||||
/obj/structure/powerswitch/simple
|
||||
icon_state = "switch-up"
|
||||
icon_state_on = "switch-down"
|
||||
icon_state_off = "switch-up"
|
||||
|
||||
|
||||
/obj/structure/powerswitch/examine(mob/user)
|
||||
..()
|
||||
if(on)
|
||||
user << "The switch is in the on position"
|
||||
else
|
||||
user << "The switch is in the off position"
|
||||
|
||||
/obj/structure/powerswitch/attack_ai(mob/user)
|
||||
user << "\red You're an AI. This is a manual switch. It's not going to work."
|
||||
return
|
||||
|
||||
/obj/structure/powerswitch/attack_hand(mob/user)
|
||||
|
||||
if(busy)
|
||||
user << "\red This switch is already being toggled."
|
||||
return
|
||||
|
||||
..()
|
||||
|
||||
busy = 1
|
||||
for(var/mob/O in viewers(user))
|
||||
O.show_message(text("\red [user] started pulling the [src]."), 1)
|
||||
|
||||
if(do_after(user, 50))
|
||||
set_state(!on)
|
||||
for(var/mob/O in viewers(user))
|
||||
O.show_message(text("\red [user] flipped the [src] into the [on ? "on": "off"] position."), 1)
|
||||
busy = 0
|
||||
|
||||
/obj/structure/powerswitch/proc/set_state(var/state)
|
||||
on = state
|
||||
if(on)
|
||||
icon_state = icon_state_on
|
||||
var/list/connection_dirs = list()
|
||||
for(var/direction in list(1,2,4,8,5,6,9,10))
|
||||
for(var/obj/structure/cable/C in get_step(src,direction))
|
||||
if(C.d1 == turn(direction, 180) || C.d2 == turn(direction, 180))
|
||||
connection_dirs += direction
|
||||
break
|
||||
|
||||
for(var/direction in connection_dirs)
|
||||
var/obj/structure/cable/C = new/obj/structure/cable(src.loc)
|
||||
C.d1 = 0
|
||||
C.d2 = direction
|
||||
C.icon_state = "[C.d1]-[C.d2]"
|
||||
C.power_switch = src
|
||||
|
||||
var/datum/powernet/PN = new()
|
||||
PN.number = powernets.len + 1
|
||||
powernets += PN
|
||||
C.netnum = PN.number
|
||||
PN.cables += C
|
||||
|
||||
C.mergeConnectedNetworks(C.d2)
|
||||
C.mergeConnectedNetworksOnTurf()
|
||||
|
||||
else
|
||||
icon_state = icon_state_off
|
||||
for(var/obj/structure/cable/C in src.loc)
|
||||
qdel(C)
|
||||
*/
|
||||
@@ -0,0 +1,78 @@
|
||||
// the underfloor wiring terminal for the APC
|
||||
// autogenerated when an APC is placed
|
||||
// all conduit connects go to this object instead of the APC
|
||||
// using this solves the problem of having the APC in a wall yet also inside an area
|
||||
|
||||
/obj/machinery/power/terminal
|
||||
name = "terminal"
|
||||
icon_state = "term"
|
||||
desc = "It's an underfloor wiring terminal for power equipment."
|
||||
level = 1
|
||||
var/obj/machinery/power/master = null
|
||||
anchored = 1
|
||||
layer = WIRE_TERMINAL_LAYER //a bit above wires
|
||||
|
||||
|
||||
/obj/machinery/power/terminal/New()
|
||||
..()
|
||||
var/turf/T = src.loc
|
||||
if(level==1) hide(T.intact)
|
||||
return
|
||||
|
||||
/obj/machinery/power/terminal/Destroy()
|
||||
if(master)
|
||||
master.disconnect_terminal()
|
||||
return ..()
|
||||
|
||||
/obj/machinery/power/terminal/hide(i)
|
||||
if(i)
|
||||
invisibility = INVISIBILITY_MAXIMUM
|
||||
icon_state = "term-f"
|
||||
else
|
||||
invisibility = 0
|
||||
icon_state = "term"
|
||||
|
||||
|
||||
/obj/machinery/power/proc/can_terminal_dismantle()
|
||||
. = 0
|
||||
|
||||
/obj/machinery/power/apc/can_terminal_dismantle()
|
||||
. = 0
|
||||
if(opened && has_electronics != 2)
|
||||
. = 1
|
||||
|
||||
/obj/machinery/power/smes/can_terminal_dismantle()
|
||||
. = 0
|
||||
if(panel_open)
|
||||
. = 1
|
||||
|
||||
|
||||
/obj/machinery/power/terminal/proc/dismantle(mob/living/user)
|
||||
if(istype(loc, /turf))
|
||||
var/turf/T = loc
|
||||
if(T.intact)
|
||||
user << "<span class='warning'>You must first expose the power terminal!</span>"
|
||||
return
|
||||
|
||||
if(master && master.can_terminal_dismantle())
|
||||
user.visible_message("[user.name] dismantles the power terminal from [master].", \
|
||||
"<span class='notice'>You begin to cut the cables...</span>")
|
||||
|
||||
playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1)
|
||||
if(do_after(user, 50, target = src))
|
||||
if(master && master.can_terminal_dismantle())
|
||||
if(prob(50) && electrocute_mob(user, powernet, src))
|
||||
var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
|
||||
s.set_up(5, 1, master)
|
||||
s.start()
|
||||
return
|
||||
new /obj/item/stack/cable_coil(loc, 10)
|
||||
user << "<span class='notice'>You cut the cables and dismantle the power terminal.</span>"
|
||||
qdel(src)
|
||||
|
||||
|
||||
/obj/machinery/power/terminal/attackby(obj/item/W, mob/living/user, params)
|
||||
if(istype(W, /obj/item/weapon/wirecutters))
|
||||
dismantle(user)
|
||||
else
|
||||
return ..()
|
||||
@@ -0,0 +1,97 @@
|
||||
/obj/machinery/power/tesla_coil
|
||||
name = "tesla coil"
|
||||
desc = "For the union!"
|
||||
icon = 'icons/obj/tesla_engine/tesla_coil.dmi'
|
||||
icon_state = "coil"
|
||||
anchored = 0
|
||||
density = 1
|
||||
var/power_loss = 2
|
||||
var/input_power_multiplier = 1
|
||||
|
||||
/obj/machinery/power/tesla_coil/New()
|
||||
..()
|
||||
var/obj/item/weapon/circuitboard/machine/B = new /obj/item/weapon/circuitboard/machine/tesla_coil(null)
|
||||
B.apply_default_parts(src)
|
||||
|
||||
/obj/item/weapon/circuitboard/machine/tesla_coil
|
||||
name = "circuit board (Tesla Coil)"
|
||||
build_path = /obj/machinery/power/tesla_coil
|
||||
origin_tech = "programming=3;magnets=3;powerstorage=3"
|
||||
req_components = list(/obj/item/weapon/stock_parts/capacitor = 1)
|
||||
|
||||
/obj/machinery/power/tesla_coil/RefreshParts()
|
||||
var/power_multiplier = 0
|
||||
for(var/obj/item/weapon/stock_parts/capacitor/C in component_parts)
|
||||
power_multiplier += C.rating
|
||||
input_power_multiplier = power_multiplier
|
||||
|
||||
/obj/machinery/power/tesla_coil/attackby(obj/item/W, mob/user, params)
|
||||
if(default_deconstruction_screwdriver(user, "coil", "coil", W))
|
||||
return
|
||||
|
||||
if(exchange_parts(user, W))
|
||||
return
|
||||
|
||||
if(default_pry_open(W))
|
||||
return
|
||||
|
||||
if(default_unfasten_wrench(user, W))
|
||||
if(!anchored)
|
||||
disconnect_from_network()
|
||||
else
|
||||
connect_to_network()
|
||||
return
|
||||
|
||||
if(default_deconstruction_crowbar(W))
|
||||
return
|
||||
|
||||
return ..()
|
||||
|
||||
/obj/machinery/power/tesla_coil/tesla_act(var/power)
|
||||
being_shocked = 1
|
||||
var/power_produced = power / power_loss
|
||||
add_avail(power_produced*input_power_multiplier)
|
||||
flick("coilhit", src)
|
||||
playsound(src.loc, 'sound/magic/LightningShock.ogg', 100, 1, extrarange = 5)
|
||||
tesla_zap(src, 5, power_produced)
|
||||
addtimer(src, "reset_shocked", 10)
|
||||
|
||||
/obj/machinery/power/grounding_rod
|
||||
name = "Grounding Rod"
|
||||
desc = "Keep an area from being fried from Edison's Bane."
|
||||
icon = 'icons/obj/tesla_engine/tesla_coil.dmi'
|
||||
icon_state = "grounding_rod"
|
||||
anchored = 0
|
||||
density = 1
|
||||
|
||||
/obj/machinery/power/grounding_rod/New()
|
||||
..()
|
||||
var/obj/item/weapon/circuitboard/machine/B = new /obj/item/weapon/circuitboard/machine/grounding_rod(null)
|
||||
B.apply_default_parts(src)
|
||||
|
||||
/obj/item/weapon/circuitboard/machine/grounding_rod
|
||||
name = "circuit board (Grounding Rod)"
|
||||
build_path = /obj/machinery/power/grounding_rod
|
||||
origin_tech = "programming=3;powerstorage=3;magnets=3;plasmatech=2"
|
||||
req_components = list(/obj/item/weapon/stock_parts/capacitor = 1)
|
||||
|
||||
/obj/machinery/power/grounding_rod/attackby(obj/item/W, mob/user, params)
|
||||
if(default_deconstruction_screwdriver(user, "grounding_rod", "grounding_rod", W))
|
||||
return
|
||||
|
||||
if(exchange_parts(user, W))
|
||||
return
|
||||
|
||||
if(default_pry_open(W))
|
||||
return
|
||||
|
||||
if(default_unfasten_wrench(user, W))
|
||||
return
|
||||
|
||||
if(default_deconstruction_crowbar(W))
|
||||
return
|
||||
|
||||
return ..()
|
||||
|
||||
/obj/machinery/power/grounding_rod/tesla_act(var/power)
|
||||
flick("coil_shock_1", src)
|
||||
@@ -0,0 +1,266 @@
|
||||
#define TESLA_DEFAULT_POWER 1738260
|
||||
#define TESLA_MINI_POWER 869130
|
||||
|
||||
var/list/blacklisted_tesla_types = typecacheof(list(/obj/machinery/atmospherics,
|
||||
/obj/machinery/power/emitter,
|
||||
/obj/machinery/field/generator,
|
||||
/mob/living/simple_animal,
|
||||
/obj/machinery/particle_accelerator/control_box,
|
||||
/obj/structure/particle_accelerator/fuel_chamber,
|
||||
/obj/structure/particle_accelerator/particle_emitter/center,
|
||||
/obj/structure/particle_accelerator/particle_emitter/left,
|
||||
/obj/structure/particle_accelerator/particle_emitter/right,
|
||||
/obj/structure/particle_accelerator/power_box,
|
||||
/obj/structure/particle_accelerator/end_cap,
|
||||
/obj/machinery/field/containment,
|
||||
/obj/structure/disposalpipe,
|
||||
/obj/structure/sign,
|
||||
/obj/machinery/gateway))
|
||||
|
||||
/obj/singularity/energy_ball
|
||||
name = "energy ball"
|
||||
desc = "An energy ball."
|
||||
icon = 'icons/obj/tesla_engine/energy_ball.dmi'
|
||||
icon_state = "energy_ball"
|
||||
pixel_x = -32
|
||||
pixel_y = -32
|
||||
current_size = STAGE_TWO
|
||||
move_self = 1
|
||||
grav_pull = 0
|
||||
contained = 0
|
||||
density = 1
|
||||
energy = 0
|
||||
dissipate = 1
|
||||
dissipate_delay = 5
|
||||
dissipate_strength = 1
|
||||
var/list/orbiting_balls = list()
|
||||
var/produced_power
|
||||
var/energy_to_raise = 32
|
||||
var/energy_to_lower = -20
|
||||
|
||||
/obj/singularity/energy_ball/Destroy()
|
||||
if(orbiting && istype(orbiting, /obj/singularity/energy_ball))
|
||||
var/obj/singularity/energy_ball/EB = orbiting
|
||||
EB.orbiting_balls -= src
|
||||
orbiting = null
|
||||
|
||||
for(var/ball in orbiting_balls)
|
||||
var/obj/singularity/energy_ball/EB = ball
|
||||
qdel(EB)
|
||||
|
||||
return ..()
|
||||
|
||||
/obj/singularity/energy_ball/process()
|
||||
if(!orbiting)
|
||||
handle_energy()
|
||||
|
||||
move_the_basket_ball(4 + orbiting_balls.len * 1.5)
|
||||
|
||||
playsound(src.loc, 'sound/magic/lightningbolt.ogg', 100, 1, extrarange = 30)
|
||||
|
||||
pixel_x = 0
|
||||
pixel_y = 0
|
||||
|
||||
setDir(tesla_zap(src, 7, TESLA_DEFAULT_POWER))
|
||||
|
||||
pixel_x = -32
|
||||
pixel_y = -32
|
||||
for (var/ball in orbiting_balls)
|
||||
var/range = rand(1, Clamp(orbiting_balls.len, 3, 7))
|
||||
tesla_zap(ball, range, TESLA_MINI_POWER/7*range)
|
||||
else
|
||||
energy = 0 // ensure we dont have miniballs of miniballs
|
||||
|
||||
return
|
||||
|
||||
/obj/singularity/energy_ball/examine(mob/user)
|
||||
..()
|
||||
if(orbiting_balls.len)
|
||||
user << "The amount of orbiting mini-balls is [orbiting_balls.len]."
|
||||
|
||||
|
||||
/obj/singularity/energy_ball/proc/move_the_basket_ball(var/move_amount)
|
||||
//we face the last thing we zapped, so this lets us favor that direction a bit
|
||||
var/first_move = dir
|
||||
for(var/i in 0 to move_amount)
|
||||
var/move_dir = pick(alldirs + first_move) //give the first move direction a bit of favoring.
|
||||
if(target && prob(60))
|
||||
move_dir = get_dir(src,target)
|
||||
var/turf/T = get_step(src, move_dir)
|
||||
if(can_move(T))
|
||||
loc = T
|
||||
|
||||
|
||||
/obj/singularity/energy_ball/proc/handle_energy()
|
||||
|
||||
if(energy >= energy_to_raise)
|
||||
energy_to_lower = energy_to_raise - 20
|
||||
energy_to_raise = energy_to_raise * 1.25
|
||||
|
||||
playsound(src.loc, 'sound/magic/lightning_chargeup.ogg', 100, 1, extrarange = 30)
|
||||
spawn(100)
|
||||
if (!loc)
|
||||
return
|
||||
var/obj/singularity/energy_ball/EB = new(loc)
|
||||
|
||||
EB.transform *= pick(0.3, 0.4, 0.5, 0.6, 0.7)
|
||||
var/icon/I = icon(icon,icon_state,dir)
|
||||
|
||||
var/orbitsize = (I.Width() + I.Height()) * pick(0.4, 0.5, 0.6, 0.7, 0.8)
|
||||
orbitsize -= (orbitsize / world.icon_size) * (world.icon_size * 0.25)
|
||||
|
||||
EB.orbit(src, orbitsize, pick(FALSE, TRUE), rand(10, 25), pick(3, 4, 5, 6, 36))
|
||||
|
||||
|
||||
else if(energy < energy_to_lower && orbiting_balls.len)
|
||||
energy_to_raise = energy_to_raise / 1.25
|
||||
energy_to_lower = (energy_to_raise / 1.25) - 20
|
||||
|
||||
var/Orchiectomy_target = pick(orbiting_balls)
|
||||
qdel(Orchiectomy_target)
|
||||
|
||||
else if(orbiting_balls.len)
|
||||
dissipate() //sing code has a much better system.
|
||||
|
||||
/obj/singularity/energy_ball/Bump(atom/A)
|
||||
dust_mobs(A)
|
||||
|
||||
/obj/singularity/energy_ball/Bumped(atom/A)
|
||||
dust_mobs(A)
|
||||
|
||||
/obj/singularity/energy_ball/orbit(obj/singularity/energy_ball/target)
|
||||
if (istype(target))
|
||||
target.orbiting_balls += src
|
||||
poi_list -= src
|
||||
target.dissipate_strength = target.orbiting_balls.len
|
||||
|
||||
. = ..()
|
||||
|
||||
if (istype(target))
|
||||
target.orbiting_balls -= src
|
||||
target.dissipate_strength = target.orbiting_balls.len
|
||||
if (!loc)
|
||||
qdel(src)
|
||||
|
||||
/obj/singularity/energy_ball/proc/dust_mobs(atom/A)
|
||||
if(istype(A, /mob/living/carbon))
|
||||
var/mob/living/carbon/C = A
|
||||
C.dust()
|
||||
return
|
||||
|
||||
/proc/tesla_zap(var/atom/source, zap_range = 3, power)
|
||||
. = source.dir
|
||||
if(power < 1000)
|
||||
return
|
||||
|
||||
var/closest_dist = 0
|
||||
var/closest_atom
|
||||
var/obj/machinery/power/tesla_coil/closest_tesla_coil
|
||||
var/obj/machinery/power/grounding_rod/closest_grounding_rod
|
||||
var/mob/living/closest_mob
|
||||
var/obj/machinery/closest_machine
|
||||
var/obj/structure/closest_structure
|
||||
var/obj/effect/blob/closest_blob
|
||||
|
||||
for(var/A in oview(source, zap_range+2))
|
||||
if(istype(A, /obj/machinery/power/tesla_coil))
|
||||
var/dist = get_dist(source, A)
|
||||
var/obj/machinery/power/tesla_coil/C = A
|
||||
if(dist <= zap_range && (dist < closest_dist || !closest_tesla_coil) && !C.being_shocked)
|
||||
closest_dist = dist
|
||||
|
||||
//we use both of these to save on istype and typecasting overhead later on
|
||||
//while still allowing common code to run before hand
|
||||
closest_tesla_coil = C
|
||||
closest_atom = C
|
||||
|
||||
|
||||
else if(closest_tesla_coil)
|
||||
continue //no need checking these other things
|
||||
|
||||
else if(istype(A, /obj/machinery/power/grounding_rod))
|
||||
var/dist = get_dist(source, A)-2
|
||||
if(dist <= zap_range && (dist < closest_dist || !closest_grounding_rod))
|
||||
closest_grounding_rod = A
|
||||
closest_atom = A
|
||||
closest_dist = dist
|
||||
|
||||
else if(closest_grounding_rod || is_type_in_typecache(A, blacklisted_tesla_types))
|
||||
continue
|
||||
|
||||
else if(istype(A, /mob/living))
|
||||
var/dist = get_dist(source, A)
|
||||
var/mob/living/L = A
|
||||
if(dist <= zap_range && (dist < closest_dist || !closest_mob) && L.stat != DEAD)
|
||||
closest_mob = L
|
||||
closest_atom = A
|
||||
closest_dist = dist
|
||||
|
||||
else if(closest_mob)
|
||||
continue
|
||||
|
||||
else if(istype(A, /obj/machinery))
|
||||
var/obj/machinery/M = A
|
||||
var/dist = get_dist(source, A)
|
||||
if(dist <= zap_range && (dist < closest_dist || !closest_machine) && !M.being_shocked)
|
||||
closest_machine = M
|
||||
closest_atom = A
|
||||
closest_dist = dist
|
||||
|
||||
else if(closest_mob)
|
||||
continue
|
||||
|
||||
else if(istype(A, /obj/effect/blob))
|
||||
var/obj/effect/blob/B = A
|
||||
var/dist = get_dist(source, A)
|
||||
if(dist <= zap_range && (dist < closest_dist || !closest_tesla_coil) && !B.being_shocked)
|
||||
closest_blob = B
|
||||
closest_atom = A
|
||||
closest_dist = dist
|
||||
|
||||
else if(closest_blob)
|
||||
continue
|
||||
|
||||
else if(istype(A, /obj/structure))
|
||||
var/obj/structure/S = A
|
||||
var/dist = get_dist(source, A)
|
||||
if(dist <= zap_range && (dist < closest_dist || !closest_tesla_coil) && !S.being_shocked)
|
||||
closest_structure = S
|
||||
closest_atom = A
|
||||
closest_dist = dist
|
||||
|
||||
//Alright, we've done our loop, now lets see if was anything interesting in range
|
||||
if(closest_atom)
|
||||
//common stuff
|
||||
source.Beam(closest_atom, icon_state="lightning[rand(1,12)]", icon='icons/effects/effects.dmi', time=5)
|
||||
var/zapdir = get_dir(source, closest_atom)
|
||||
if(zapdir)
|
||||
. = zapdir
|
||||
|
||||
//per type stuff:
|
||||
if(closest_tesla_coil)
|
||||
closest_tesla_coil.tesla_act(power)
|
||||
|
||||
else if(closest_grounding_rod)
|
||||
closest_grounding_rod.tesla_act(power)
|
||||
|
||||
else if(closest_mob)
|
||||
var/shock_damage = Clamp(round(power/400), 10, 90) + rand(-5, 5)
|
||||
closest_mob.electrocute_act(shock_damage, source, 1, tesla_shock = 1)
|
||||
if(istype(closest_mob, /mob/living/silicon))
|
||||
var/mob/living/silicon/S = closest_mob
|
||||
S.emp_act(2)
|
||||
tesla_zap(S, 7, power / 1.5) // metallic folks bounce it further
|
||||
else
|
||||
tesla_zap(closest_mob, 5, power / 1.5)
|
||||
|
||||
else if(closest_machine)
|
||||
closest_machine.tesla_act(power)
|
||||
|
||||
else if(closest_blob)
|
||||
closest_blob.tesla_act(power)
|
||||
|
||||
else if(closest_structure)
|
||||
closest_structure.tesla_act(power)
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
/obj/machinery/the_singularitygen/tesla
|
||||
name = "energy ball generator"
|
||||
desc = "Makes the wardenclyffe look like a child's plaything when shot with a particle accelerator."
|
||||
icon = 'icons/obj/tesla_engine/tesla_generator.dmi'
|
||||
icon_state = "TheSingGen"
|
||||
creation_type = /obj/singularity/energy_ball
|
||||
@@ -0,0 +1,80 @@
|
||||
//Solar tracker
|
||||
|
||||
//Machine that tracks the sun and reports it's direction to the solar controllers
|
||||
//As long as this is working, solar panels on same powernet will track automatically
|
||||
|
||||
/obj/machinery/power/tracker
|
||||
name = "solar tracker"
|
||||
desc = "A solar directional tracker."
|
||||
icon = 'icons/obj/power.dmi'
|
||||
icon_state = "tracker"
|
||||
anchored = 1
|
||||
density = 1
|
||||
use_power = 0
|
||||
|
||||
var/id = 0
|
||||
var/sun_angle = 0 // sun angle as set by sun datum
|
||||
var/obj/machinery/power/solar_control/control = null
|
||||
|
||||
/obj/machinery/power/tracker/New(var/turf/loc, var/obj/item/solar_assembly/S)
|
||||
..(loc)
|
||||
Make(S)
|
||||
connect_to_network()
|
||||
|
||||
/obj/machinery/power/tracker/Destroy()
|
||||
unset_control() //remove from control computer
|
||||
return ..()
|
||||
|
||||
//set the control of the tracker to a given computer if closer than SOLAR_MAX_DIST
|
||||
/obj/machinery/power/tracker/proc/set_control(obj/machinery/power/solar_control/SC)
|
||||
if(!SC || (get_dist(src, SC) > SOLAR_MAX_DIST))
|
||||
return 0
|
||||
control = SC
|
||||
SC.connected_tracker = src
|
||||
return 1
|
||||
|
||||
//set the control of the tracker to null and removes it from the previous control computer if needed
|
||||
/obj/machinery/power/tracker/proc/unset_control()
|
||||
if(control)
|
||||
control.connected_tracker = null
|
||||
control = null
|
||||
|
||||
/obj/machinery/power/tracker/proc/Make(obj/item/solar_assembly/S)
|
||||
if(!S)
|
||||
S = new /obj/item/solar_assembly(src)
|
||||
S.glass_type = /obj/item/stack/sheet/glass
|
||||
S.tracker = 1
|
||||
S.anchored = 1
|
||||
S.loc = src
|
||||
update_icon()
|
||||
|
||||
//updates the tracker icon and the facing angle for the control computer
|
||||
/obj/machinery/power/tracker/proc/set_angle(angle)
|
||||
sun_angle = angle
|
||||
|
||||
//set icon dir to show sun illumination
|
||||
setDir(turn(NORTH, -angle - 22.5) )// 22.5 deg bias ensures, e.g. 67.5-112.5 is EAST
|
||||
|
||||
if(powernet && (powernet == control.powernet)) //update if we're still in the same powernet
|
||||
control.currentdir = angle
|
||||
|
||||
/obj/machinery/power/tracker/attackby(obj/item/weapon/W, mob/user, params)
|
||||
|
||||
if(istype(W, /obj/item/weapon/crowbar))
|
||||
playsound(src.loc, 'sound/machines/click.ogg', 50, 1)
|
||||
user.visible_message("[user] begins to take the glass off the solar tracker.", "<span class='notice'>You begin to take the glass off the solar tracker...</span>")
|
||||
if(do_after(user, 50/W.toolspeed, target = src))
|
||||
var/obj/item/solar_assembly/S = locate() in src
|
||||
if(S)
|
||||
S.loc = src.loc
|
||||
S.give_glass(stat & BROKEN)
|
||||
playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1)
|
||||
user.visible_message("[user] takes the glass off the tracker.", "<span class='notice'>You take the glass off the tracker.</span>")
|
||||
qdel(src)
|
||||
else
|
||||
return ..()
|
||||
|
||||
// Tracker Electronic
|
||||
|
||||
/obj/item/weapon/electronics/tracker
|
||||
name = "tracker electronics"
|
||||
@@ -0,0 +1,401 @@
|
||||
// TURBINE v2 AKA rev4407 Engine reborn!
|
||||
|
||||
// How to use it? - Mappers
|
||||
//
|
||||
// This is a very good power generating mechanism. All you need is a blast furnace with soaring flames and output.
|
||||
// Not everything is included yet so the turbine can run out of fuel quiet quickly. The best thing about the turbine is that even
|
||||
// though something is on fire that passes through it, it won't be on fire as it passes out of it. So the exhaust fumes can still
|
||||
// containt unreacted fuel - plasma and oxygen that needs to be filtered out and re-routed back. This of course requires smart piping
|
||||
// For a computer to work with the turbine the compressor requires a comp_id matching with the turbine computer's id. This will be
|
||||
// subjected to a change in the near future mind you. Right now this method of generating power is a good backup but don't expect it
|
||||
// become a main power source unless some work is done. Have fun. At 50k RPM it generates 60k power. So more than one turbine is needed!
|
||||
//
|
||||
// - Numbers
|
||||
//
|
||||
// Example setup S - sparker
|
||||
// B - Blast doors into space for venting
|
||||
// *BBB****BBB* C - Compressor
|
||||
// S CT * T - Turbine
|
||||
// * ^ * * V * D - Doors with firedoor
|
||||
// **|***D**|** ^ - Fuel feed (Not vent, but a gas outlet)
|
||||
// | | V - Suction vent (Like the ones in atmos
|
||||
//
|
||||
|
||||
|
||||
/obj/machinery/power/compressor
|
||||
name = "compressor"
|
||||
desc = "The compressor stage of a gas turbine generator."
|
||||
icon = 'icons/obj/atmospherics/pipes/simple.dmi'
|
||||
icon_state = "compressor"
|
||||
anchored = 1
|
||||
density = 1
|
||||
var/obj/machinery/power/turbine/turbine
|
||||
var/datum/gas_mixture/gas_contained
|
||||
var/turf/inturf
|
||||
var/starter = 0
|
||||
var/rpm = 0
|
||||
var/rpmtarget = 0
|
||||
var/capacity = 1e6
|
||||
var/comp_id = 0
|
||||
var/efficiency
|
||||
|
||||
|
||||
/obj/machinery/power/turbine
|
||||
name = "gas turbine generator"
|
||||
desc = "A gas turbine used for backup power generation."
|
||||
icon = 'icons/obj/atmospherics/pipes/simple.dmi'
|
||||
icon_state = "turbine"
|
||||
anchored = 1
|
||||
density = 1
|
||||
var/opened = 0
|
||||
var/obj/machinery/power/compressor/compressor
|
||||
var/turf/outturf
|
||||
var/lastgen
|
||||
var/productivity = 1
|
||||
|
||||
/obj/machinery/computer/turbine_computer
|
||||
name = "gas turbine control computer"
|
||||
desc = "A computer to remotely control a gas turbine."
|
||||
icon_screen = "turbinecomp"
|
||||
icon_keyboard = "tech_key"
|
||||
circuit = /obj/item/weapon/circuitboard/computer/turbine_computer
|
||||
var/obj/machinery/power/compressor/compressor
|
||||
var/id = 0
|
||||
|
||||
// the inlet stage of the gas turbine electricity generator
|
||||
|
||||
/obj/machinery/power/compressor/New()
|
||||
..()
|
||||
var/obj/item/weapon/circuitboard/machine/B = new /obj/item/weapon/circuitboard/machine/power_compressor(null)
|
||||
B.apply_default_parts(src)
|
||||
// The inlet of the compressor is the direction it faces
|
||||
|
||||
gas_contained = new
|
||||
inturf = get_step(src, dir)
|
||||
|
||||
/obj/item/weapon/circuitboard/machine/power_compressor
|
||||
name = "circuit board (Power Compressor)"
|
||||
build_path = /obj/machinery/power/compressor
|
||||
origin_tech = "programming=4;powerstorage=4;engineering=4"
|
||||
req_components = list(
|
||||
/obj/item/stack/cable_coil = 5,
|
||||
/obj/item/weapon/stock_parts/manipulator = 6)
|
||||
|
||||
/obj/machinery/power/compressor/initialize()
|
||||
..()
|
||||
locate_machinery()
|
||||
if(!turbine)
|
||||
stat |= BROKEN
|
||||
|
||||
|
||||
#define COMPFRICTION 5e5
|
||||
#define COMPSTARTERLOAD 2800
|
||||
|
||||
|
||||
// Crucial to make things work!!!!
|
||||
// OLD FIX - explanation given down below.
|
||||
// /obj/machinery/power/compressor/CanPass(atom/movable/mover, turf/target, height=0)
|
||||
// return !density
|
||||
|
||||
/obj/machinery/power/compressor/locate_machinery()
|
||||
if(turbine)
|
||||
return
|
||||
turbine = locate() in get_step(src, get_dir(inturf, src))
|
||||
if(turbine)
|
||||
turbine.locate_machinery()
|
||||
|
||||
/obj/machinery/power/compressor/RefreshParts()
|
||||
var/E = 0
|
||||
for(var/obj/item/weapon/stock_parts/manipulator/M in component_parts)
|
||||
E += M.rating
|
||||
efficiency = E / 6
|
||||
|
||||
/obj/machinery/power/compressor/attackby(obj/item/I, mob/user, params)
|
||||
if(default_deconstruction_screwdriver(user, initial(icon_state), initial(icon_state), I))
|
||||
return
|
||||
|
||||
if(default_change_direction_wrench(user, I))
|
||||
turbine = null
|
||||
inturf = get_step(src, dir)
|
||||
locate_machinery()
|
||||
if(turbine)
|
||||
user << "<span class='notice'>Turbine connected.</span>"
|
||||
stat &= ~BROKEN
|
||||
else
|
||||
user << "<span class='alert'>Turbine not connected.</span>"
|
||||
stat |= BROKEN
|
||||
return
|
||||
|
||||
if(exchange_parts(user, I))
|
||||
return
|
||||
|
||||
default_deconstruction_crowbar(I)
|
||||
|
||||
/obj/machinery/power/compressor/CanAtmosPass(turf/T)
|
||||
return !density
|
||||
|
||||
/obj/machinery/power/compressor/process()
|
||||
if(!turbine)
|
||||
stat = BROKEN
|
||||
if(stat & BROKEN || panel_open)
|
||||
return
|
||||
if(!starter)
|
||||
return
|
||||
cut_overlays()
|
||||
|
||||
rpm = 0.9* rpm + 0.1 * rpmtarget
|
||||
var/datum/gas_mixture/environment = inturf.return_air()
|
||||
|
||||
// It's a simplified version taking only 1/10 of the moles from the turf nearby. It should be later changed into a better version
|
||||
|
||||
var/transfer_moles = environment.total_moles()/10
|
||||
//var/transfer_moles = rpm/10000*capacity
|
||||
var/datum/gas_mixture/removed = inturf.remove_air(transfer_moles)
|
||||
gas_contained.merge(removed)
|
||||
|
||||
// RPM function to include compression friction - be advised that too low/high of a compfriction value can make things screwy
|
||||
|
||||
rpm = max(0, rpm - (rpm*rpm)/(COMPFRICTION/efficiency))
|
||||
|
||||
|
||||
if(starter && !(stat & NOPOWER))
|
||||
use_power(2800)
|
||||
if(rpm<1000)
|
||||
rpmtarget = 1000
|
||||
else
|
||||
if(rpm<1000)
|
||||
rpmtarget = 0
|
||||
|
||||
|
||||
|
||||
if(rpm>50000)
|
||||
add_overlay(image('icons/obj/atmospherics/pipes/simple.dmi', "comp-o4", FLY_LAYER))
|
||||
else if(rpm>10000)
|
||||
add_overlay(image('icons/obj/atmospherics/pipes/simple.dmi', "comp-o3", FLY_LAYER))
|
||||
else if(rpm>2000)
|
||||
add_overlay(image('icons/obj/atmospherics/pipes/simple.dmi', "comp-o2", FLY_LAYER))
|
||||
else if(rpm>500)
|
||||
add_overlay(image('icons/obj/atmospherics/pipes/simple.dmi', "comp-o1", FLY_LAYER))
|
||||
//TODO: DEFERRED
|
||||
|
||||
// These are crucial to working of a turbine - the stats modify the power output. TurbGenQ modifies how much raw energy can you get from
|
||||
// rpms, TurbGenG modifies the shape of the curve - the lower the value the less straight the curve is.
|
||||
|
||||
#define TURBPRES 9000000
|
||||
#define TURBGENQ 100000
|
||||
#define TURBGENG 0.5
|
||||
|
||||
/obj/machinery/power/turbine/New()
|
||||
..()
|
||||
var/obj/item/weapon/circuitboard/machine/B = new /obj/item/weapon/circuitboard/machine/power_turbine(null)
|
||||
B.apply_default_parts(src)
|
||||
// The outlet is pointed at the direction of the turbine component
|
||||
outturf = get_step(src, dir)
|
||||
|
||||
/obj/item/weapon/circuitboard/machine/power_turbine
|
||||
name = "circuit board (Power Turbine)"
|
||||
build_path = /obj/machinery/power/turbine
|
||||
origin_tech = "programming=4;powerstorage=4;engineering=4"
|
||||
req_components = list(
|
||||
/obj/item/stack/cable_coil = 5,
|
||||
/obj/item/weapon/stock_parts/capacitor = 6)
|
||||
|
||||
/obj/machinery/power/turbine/initialize()
|
||||
..()
|
||||
locate_machinery()
|
||||
if(!compressor)
|
||||
stat |= BROKEN
|
||||
|
||||
/obj/machinery/power/turbine/RefreshParts()
|
||||
var/P = 0
|
||||
for(var/obj/item/weapon/stock_parts/capacitor/C in component_parts)
|
||||
P += C.rating
|
||||
productivity = P / 6
|
||||
|
||||
/obj/machinery/power/turbine/locate_machinery()
|
||||
if(compressor)
|
||||
return
|
||||
compressor = locate() in get_step(src, get_dir(outturf, src))
|
||||
if(compressor)
|
||||
compressor.locate_machinery()
|
||||
|
||||
/obj/machinery/power/turbine/CanAtmosPass(turf/T)
|
||||
return !density
|
||||
|
||||
/obj/machinery/power/turbine/process()
|
||||
|
||||
if(!compressor)
|
||||
stat = BROKEN
|
||||
|
||||
if((stat & BROKEN) || panel_open)
|
||||
return
|
||||
if(!compressor.starter)
|
||||
return
|
||||
cut_overlays()
|
||||
|
||||
// This is the power generation function. If anything is needed it's good to plot it in EXCEL before modifying
|
||||
// the TURBGENQ and TURBGENG values
|
||||
|
||||
lastgen = ((compressor.rpm / TURBGENQ)**TURBGENG) * TURBGENQ * productivity
|
||||
|
||||
add_avail(lastgen)
|
||||
|
||||
// Weird function but it works. Should be something else...
|
||||
|
||||
var/newrpm = ((compressor.gas_contained.temperature) * compressor.gas_contained.total_moles())/4
|
||||
|
||||
newrpm = max(0, newrpm)
|
||||
|
||||
if(!compressor.starter || newrpm > 1000)
|
||||
compressor.rpmtarget = newrpm
|
||||
|
||||
if(compressor.gas_contained.total_moles()>0)
|
||||
var/oamount = min(compressor.gas_contained.total_moles(), (compressor.rpm+100)/35000*compressor.capacity)
|
||||
var/datum/gas_mixture/removed = compressor.gas_contained.remove(oamount)
|
||||
outturf.assume_air(removed)
|
||||
|
||||
// If it works, put an overlay that it works!
|
||||
|
||||
if(lastgen > 100)
|
||||
add_overlay(image('icons/obj/atmospherics/pipes/simple.dmi', "turb-o", FLY_LAYER))
|
||||
|
||||
updateDialog()
|
||||
|
||||
/obj/machinery/power/turbine/attack_hand(mob/user)
|
||||
|
||||
if(..())
|
||||
return
|
||||
|
||||
interact(user)
|
||||
|
||||
/obj/machinery/power/turbine/attackby(obj/item/I, mob/user, params)
|
||||
if(default_deconstruction_screwdriver(user, initial(icon_state), initial(icon_state), I))
|
||||
return
|
||||
|
||||
if(default_change_direction_wrench(user, I))
|
||||
compressor = null
|
||||
outturf = get_step(src, dir)
|
||||
locate_machinery()
|
||||
if(compressor)
|
||||
user << "<span class='notice'>Compressor connected.</span>"
|
||||
stat &= ~BROKEN
|
||||
else
|
||||
user << "<span class='alert'>Compressor not connected.</span>"
|
||||
stat |= BROKEN
|
||||
return
|
||||
|
||||
if(exchange_parts(user, I))
|
||||
return
|
||||
|
||||
default_deconstruction_crowbar(I)
|
||||
|
||||
/obj/machinery/power/turbine/interact(mob/user)
|
||||
|
||||
if ( !Adjacent(user) || (stat & (NOPOWER|BROKEN)) && (!istype(user, /mob/living/silicon)) )
|
||||
user.unset_machine(src)
|
||||
user << browse(null, "window=turbine")
|
||||
return
|
||||
|
||||
var/t = "<TT><B>Gas Turbine Generator</B><HR><PRE>"
|
||||
|
||||
t += "Generated power : [round(lastgen)] W<BR><BR>"
|
||||
|
||||
t += "Turbine: [round(compressor.rpm)] RPM<BR>"
|
||||
|
||||
t += "Starter: [ compressor.starter ? "<A href='?src=\ref[src];str=1'>Off</A> <B>On</B>" : "<B>Off</B> <A href='?src=\ref[src];str=1'>On</A>"]"
|
||||
|
||||
t += "</PRE><HR><A href='?src=\ref[src];close=1'>Close</A>"
|
||||
|
||||
t += "</TT>"
|
||||
var/datum/browser/popup = new(user, "turbine", name)
|
||||
popup.set_content(t)
|
||||
popup.open()
|
||||
|
||||
return
|
||||
|
||||
/obj/machinery/power/turbine/Topic(href, href_list)
|
||||
if(..())
|
||||
return
|
||||
|
||||
if( href_list["close"] )
|
||||
usr << browse(null, "window=turbine")
|
||||
usr.unset_machine(src)
|
||||
return
|
||||
|
||||
else if( href_list["str"] )
|
||||
if(compressor)
|
||||
compressor.starter = !compressor.starter
|
||||
|
||||
updateDialog()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// COMPUTER NEEDS A SERIOUS REWRITE.
|
||||
|
||||
|
||||
|
||||
/obj/machinery/computer/turbine_computer/initialize()
|
||||
..()
|
||||
spawn(10)
|
||||
locate_machinery()
|
||||
|
||||
/obj/machinery/computer/turbine_computer/locate_machinery()
|
||||
compressor = locate(/obj/machinery/power/compressor) in range(5, src)
|
||||
|
||||
/obj/machinery/computer/turbine_computer/attack_hand(var/mob/user as mob)
|
||||
if(..())
|
||||
return
|
||||
|
||||
interact(user)
|
||||
|
||||
/obj/machinery/computer/turbine_computer/interact(mob/user)
|
||||
|
||||
var/dat
|
||||
if(compressor && compressor.turbine)
|
||||
dat += "<BR><B>Gas turbine remote control system</B><HR>"
|
||||
if(compressor.stat || compressor.turbine.stat)
|
||||
dat += "[compressor.stat ? "<B>Compressor is inoperable</B><BR>" : "<B>Turbine is inoperable</B>"]"
|
||||
else
|
||||
dat += {"Turbine status: [ src.compressor.starter ? "<A href='?src=\ref[src];str=1'>Off</A> <B>On</B>" : "<B>Off</B> <A href='?src=\ref[src];str=1'>On</A>"]
|
||||
\n<BR>
|
||||
\nTurbine speed: [src.compressor.rpm]rpm<BR>
|
||||
\nPower currently being generated: [src.compressor.turbine.lastgen]W<BR>
|
||||
\nInternal gas temperature: [src.compressor.gas_contained.temperature]K<BR>
|
||||
\n</PRE><HR><A href='?src=\ref[src];close=1'>Close</A>
|
||||
\n<BR>
|
||||
\n"}
|
||||
else
|
||||
dat += "<B>There is [!compressor ? "no compressor" : " compressor[!compressor.turbine ? " but no turbine" : ""]"].</B><BR>"
|
||||
if(!compressor)
|
||||
dat += "<A href='?src=\ref[src];search=1'>Search for compressor</A>"
|
||||
|
||||
var/datum/browser/popup = new(user, "turbinecomputer", name)
|
||||
popup.set_content(dat)
|
||||
popup.open()
|
||||
return
|
||||
|
||||
/obj/machinery/computer/turbine_computer/Topic(href, href_list)
|
||||
if(..())
|
||||
return
|
||||
|
||||
else if( href_list["str"] )
|
||||
if(compressor && compressor.turbine)
|
||||
compressor.starter = !compressor.starter
|
||||
else if( href_list["close"] )
|
||||
usr << browse(null, "window=turbinecomputer")
|
||||
usr.unset_machine(src)
|
||||
return
|
||||
else if(href_list["search"])
|
||||
locate_machinery()
|
||||
|
||||
src.updateUsrDialog()
|
||||
return
|
||||
|
||||
/obj/machinery/computer/turbine_computer/process()
|
||||
src.updateDialog()
|
||||
return
|
||||
Reference in New Issue
Block a user