initial commit - cross reference with 5th port - obviously has compile errors

This commit is contained in:
LetterJay
2016-07-03 02:17:19 -05:00
commit 35a1723e98
4355 changed files with 2221257 additions and 0 deletions
@@ -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
+353
View File
@@ -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
+235
View File
@@ -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
+785
View File
@@ -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]"
..()
+301
View File
@@ -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
+16
View File
@@ -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
+199
View File
@@ -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()
+409
View File
@@ -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>"}
+638
View File
@@ -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()
+81
View File
@@ -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
+346
View File
@@ -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)
+361
View File
@@ -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
+99
View File
@@ -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
+158
View File
@@ -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)
+289
View File
@@ -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")
..()
+160
View File
@@ -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)
+466
View File
@@ -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
+552
View File
@@ -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
+84
View File
@@ -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)
*/
+78
View File
@@ -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 ..()
+97
View File
@@ -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)
+266
View File
@@ -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)
+6
View File
@@ -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
+80
View File
@@ -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"
+401
View File
@@ -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