diff --git a/code/_globalvars/lists/objects.dm b/code/_globalvars/lists/objects.dm index 906bacf0e54..e6f463d6f23 100644 --- a/code/_globalvars/lists/objects.dm +++ b/code/_globalvars/lists/objects.dm @@ -19,7 +19,6 @@ GLOBAL_LIST_INIT(navigation_computers, list()) GLOBAL_LIST_INIT(all_areas, list()) GLOBAL_LIST_INIT(machines, list()) -GLOBAL_LIST_INIT(processing_power_items, list()) //items that ask to be called every cycle GLOBAL_LIST_INIT(rcd_list, list()) //list of Rapid Construction Devices. GLOBAL_LIST_INIT(apcs, list()) diff --git a/code/_globalvars/misc.dm b/code/_globalvars/misc.dm index 0b8c8d58a95..77443fb4ab2 100644 --- a/code/_globalvars/misc.dm +++ b/code/_globalvars/misc.dm @@ -1,6 +1,9 @@ var/global/obj/effect/overlay/plmaster = null var/global/obj/effect/overlay/slmaster = null +GLOBAL_VAR_INIT(CELLRATE, 0.002) // conversion ratio between a watt-tick and kilojoule +GLOBAL_VAR_INIT(CHARGELEVEL, 0.001) // Cap for how fast cells charge, as a percentage-per-tick (.001 means cellcharge is capped to 1% per second) + // Announcer intercom, because too much stuff creates an intercom for one message then hard del()s it. var/global/obj/item/radio/intercom/global_announcer = create_global_announcer() var/global/obj/item/radio/intercom/command/command_announcer = create_command_announcer() diff --git a/code/_globalvars/station.dm b/code/_globalvars/station.dm index 2d635996b30..e997a672e1f 100644 --- a/code/_globalvars/station.dm +++ b/code/_globalvars/station.dm @@ -1,6 +1,3 @@ var/global/datum/datacore/data_core = null -var/CELLRATE = 0.002 // multiplier for watts per tick <> cell storage (eg: .002 means if there is a load of 1000 watts, 20 units will be taken from a cell per second) -var/CHARGELEVEL = 0.001 // Cap for how fast cells charge, as a percentage-per-tick (.001 means cellcharge is capped to 1% per second) - var/map_name = "Unknown" //The name of the map that is loaded. Assigned in world/New() \ No newline at end of file diff --git a/code/controllers/subsystem/machinery.dm b/code/controllers/subsystem/machinery.dm index 7038ad4db4f..9a73c1dbabb 100644 --- a/code/controllers/subsystem/machinery.dm +++ b/code/controllers/subsystem/machinery.dm @@ -64,23 +64,6 @@ SUBSYSTEM_DEF(machines) if(MC_TICK_CHECK) return -/datum/controller/subsystem/machines/proc/process_premachines(resumed = 0) - /* Literally exists as snowflake for fucking powersinks goddamnit */ - if(!resumed) - src.currentrun = GLOB.processing_power_items.Copy() - //cache for sanid speed (lists are references anyways) - var/list/currentrun = src.currentrun - while(currentrun.len) - var/obj/item/I = currentrun[currentrun.len] - currentrun.len-- - if(!QDELETED(I)) - if(!I.pwr_drain()) - GLOB.processing_power_items.Remove(I) - else - GLOB.processing_power_items.Remove(I) - if(MC_TICK_CHECK) - return - /datum/controller/subsystem/machines/proc/process_machines(resumed = 0) var/seconds = wait * 0.1 if(!resumed) @@ -113,13 +96,6 @@ SUBSYSTEM_DEF(machines) if(state != SS_RUNNING) return resumed = 0 - currentpart = SSMACHINES_PREMACHINERY - - if(currentpart == SSMACHINES_PREMACHINERY || !resumed) - process_premachines(resumed) - if(state != SS_RUNNING) - return - resumed = 0 currentpart = SSMACHINES_MACHINERY if(currentpart == SSMACHINES_MACHINERY || !resumed) diff --git a/code/game/machinery/computer/power.dm b/code/game/machinery/computer/power.dm index a5198da6e56..b39c005855c 100644 --- a/code/game/machinery/computer/power.dm +++ b/code/game/machinery/computer/power.dm @@ -38,7 +38,7 @@ if(isturf(T)) attached = locate() in T if(attached) - return attached.get_powernet() + return attached.powernet /obj/machinery/computer/monitor/attack_ai(mob/user) attack_hand(user) diff --git a/code/game/machinery/syndicatebeacon.dm b/code/game/machinery/syndicatebeacon.dm index 304dc7dc639..6422e94dc74 100644 --- a/code/game/machinery/syndicatebeacon.dm +++ b/code/game/machinery/syndicatebeacon.dm @@ -188,11 +188,11 @@ /obj/machinery/power/singularity_beacon/process() if(!active) return PROCESS_KILL + + if(surplus() >= 1500) + add_load(1500) else - if(surplus() > 1500) - draw_power(1500) - else - Deactivate() + Deactivate() /obj/machinery/power/singularity_beacon/syndicate icontype = "beaconsynd" diff --git a/code/game/objects/items/devices/powersink.dm b/code/game/objects/items/devices/powersink.dm index 463223f4268..562800c2ce0 100644 --- a/code/game/objects/items/devices/powersink.dm +++ b/code/game/objects/items/devices/powersink.dm @@ -1,3 +1,7 @@ +#define DISCONNECTED 0 +#define CLAMPED_OFF 1 +#define OPERATING 2 + // Powersink - used to drain station power /obj/item/powersink @@ -13,28 +17,55 @@ throw_range = 2 materials = list(MAT_METAL=750) origin_tech = "powerstorage=5;syndicate=5" - var/drain_rate = 1600000 // amount of power to drain per tick - var/apc_drain_rate = 50 // Max. amount drained from single APC. In Watts. - var/dissipation_rate = 20000 // Passive dissipation of drained power. In Watts. - var/power_drained = 0 // Amount of power drained. - var/max_power = 1e10 // Detonation point. - var/mode = 0 // 0 = off, 1=clamped (off), 2=operating - var/drained_this_tick = 0 // This is unfortunately necessary to ensure we process powersinks BEFORE other machinery such as APCs. - var/admins_warned = 0 // stop spam, only warn the admins once that we are about to go boom + var/drain_rate = 2000000 // amount of power to drain per tick + var/power_drained = 0 // has drained this much power + var/max_power = 6e8 // maximum power that can be drained before exploding + var/mode = 0 // 0 = off, 1=clamped (off), 2=operating + var/admins_warned = FALSE // stop spam, only warn the admins once that we are about to boom - var/datum/powernet/PN // Our powernet var/obj/structure/cable/attached // the attached cable /obj/item/powersink/Destroy() STOP_PROCESSING(SSobj, src) - GLOB.processing_power_items.Remove(src) - PN = null attached = null return ..() -/obj/item/powersink/attackby(var/obj/item/I, var/mob/user) - if(istype(I, /obj/item/screwdriver)) - if(mode == 0) +/obj/item/powersink/update_icon() + icon_state = "powersink[mode == OPERATING]" + +/obj/item/powersink/proc/set_mode(value) + if(value == mode) + return + switch(value) + if(DISCONNECTED) + attached = null + if(mode == OPERATING) + STOP_PROCESSING(SSobj, src) + anchored = FALSE + density = FALSE + + if(CLAMPED_OFF) + if(!attached) + return + if(mode == OPERATING) + STOP_PROCESSING(SSobj, src) + anchored = TRUE + density = TRUE + + if(OPERATING) + if(!attached) + return + START_PROCESSING(SSobj, src) + anchored = TRUE + density = TRUE + + mode = value + update_icon() + set_light(0) + +/obj/item/powersink/attackby(obj/item/I, mob/user) + if(isscrewdriver(I)) + if(mode == DISCONNECTED) var/turf/T = loc if(isturf(T) && !T.intact) attached = locate() in T @@ -42,98 +73,81 @@ to_chat(user, "No exposed cable here to attach to.") return else - anchored = 1 - mode = 1 - src.visible_message("[user] attaches [src] to the cable!") + set_mode(CLAMPED_OFF) + visible_message("[user] attaches [src] to the cable!") message_admins("Power sink activated by [key_name_admin(user)] at ([x],[y],[z] - JMP)") log_game("Power sink activated by [key_name(user)] at ([x],[y],[z])") - return else to_chat(user, "Device must be placed over an exposed cable to attach to it.") - return else - if(mode == 2) - STOP_PROCESSING(SSobj, src) // Now the power sink actually stops draining the station's power if you unhook it. --NeoFite - GLOB.processing_power_items.Remove(src) - anchored = 0 - mode = 0 + set_mode(DISCONNECTED) src.visible_message("[user] detaches [src] from the cable!") - set_light(0) - icon_state = "powersink0" - - return else - ..() + return ..() /obj/item/powersink/attack_ai() return /obj/item/powersink/attack_hand(var/mob/user) switch(mode) - if(0) + if(DISCONNECTED) ..() - if(1) - src.visible_message("[user] activates [src]!") - mode = 2 - icon_state = "powersink1" - START_PROCESSING(SSobj, src) - GLOB.processing_power_items.Add(src) - if(2) //This switch option wasn't originally included. It exists now. --NeoFite - src.visible_message("[user] deactivates [src]!") - mode = 1 - set_light(0) - icon_state = "powersink0" - STOP_PROCESSING(SSobj, src) - GLOB.processing_power_items.Remove(src) - -/obj/item/powersink/pwr_drain() - if(!attached) - return 0 - - if(drained_this_tick) - return 1 - drained_this_tick = 1 - - var/drained = 0 - - if(!PN) - return 1 - - set_light(12) - PN.trigger_warning() - // found a powernet, so drain up to max power from it - drained = PN.draw_power(drain_rate) - // if tried to drain more than available on powernet - // now look for APCs and drain their cells - if(drained < drain_rate) - for(var/obj/machinery/power/terminal/T in PN.nodes) - // Enough power drained this tick, no need to torture more APCs - if(drained >= drain_rate) - break - if(istype(T.master, /obj/machinery/power/apc)) - var/obj/machinery/power/apc/A = T.master - if(A.operating && A.cell) - A.cell.charge = max(0, A.cell.charge - apc_drain_rate) - drained += apc_drain_rate - if(A.charging == 2) // If the cell was full - A.charging = 1 // It's no longer full - power_drained += drained - return 1 + if(CLAMPED_OFF) + user.visible_message( \ + "[user] activates \the [src]!", \ + "You activate \the [src].", + "You hear a click.") + message_admins("Power sink activated by [ADMIN_LOOKUPFLW(user)] at [ADMIN_VERBOSEJMP(src)]") + log_game("Power sink activated by [key_name(user)] at [AREACOORD(src)]") + set_mode(OPERATING) + if(OPERATING) + user.visible_message( \ + "[user] deactivates \the [src]!", \ + "You deactivate \the [src].", + "You hear a click.") + set_mode(CLAMPED_OFF) /obj/item/powersink/process() - drained_this_tick = 0 - power_drained -= min(dissipation_rate, power_drained) + if(!attached) + set_mode(DISCONNECTED) + return + + var/datum/powernet/PN = attached.powernet + if(PN) + set_light(5) + + // found a powernet, so drain up to max power from it + + var/drained = min (drain_rate, attached.newavail()) + attached.add_delayedload(drained) + power_drained += drained + + // if tried to drain more than available on powernet + // now look for APCs and drain their cells + if(drained < drain_rate) + for(var/obj/machinery/power/terminal/T in PN.nodes) + if(istype(T.master, /obj/machinery/power/apc)) + var/obj/machinery/power/apc/A = T.master + if(A.operating && A.cell) + A.cell.charge = max(0, A.cell.charge - 50) + power_drained += 50 + if(A.charging == 2) // If the cell was full + A.charging = 1 // It's no longer full + if(drained >= drain_rate) + break + if(power_drained > max_power * 0.98) - if(!admins_warned) - admins_warned = 1 + if (!admins_warned) + admins_warned = TRUE message_admins("Power sink at ([x],[y],[z] - JMP) is 95% full. Explosion imminent.") playsound(src, 'sound/effects/screech.ogg', 100, 1, 1) + if(power_drained >= max_power) + STOP_PROCESSING(SSobj, src) explosion(src.loc, 4,8,16,32) qdel(src) - return - if(attached && attached.powernet) - PN = attached.powernet - else - PN = null + +#undef DISCONNECTED +#undef CLAMPED_OFF +#undef OPERATING \ No newline at end of file diff --git a/code/game/objects/structures/grille.dm b/code/game/objects/structures/grille.dm index 154d4438530..1e3cb331cd1 100644 --- a/code/game/objects/structures/grille.dm +++ b/code/game/objects/structures/grille.dm @@ -273,8 +273,8 @@ var/obj/structure/cable/C = T.get_cable_node() if(C) playsound(loc, 'sound/magic/lightningshock.ogg', 100, 1, extrarange = 5) - tesla_zap(src, 3, C.powernet.avail * 0.01) //Zap for 1/100 of the amount of power. At a million watts in the grid, it will be as powerful as a tesla revolver shot. - C.powernet.load += C.powernet.avail * 0.0375 // you can gain up to 3.5 via the 4x upgrades power is halved by the pole so thats 2x then 1X then .5X for 3.5x the 3 bounces shock. + tesla_zap(src, 3, C.newavail() * 0.01) //Zap for 1/100 of the amount of power. At a million watts in the grid, it will be as powerful as a tesla revolver shot. + C.add_delayedload(C.newavail() * 0.0375) // you can gain up to 3.5 via the 4x upgrades power is halved by the pole so thats 2x then 1X then .5X for 3.5x the 3 bounces shock. return ..() /obj/structure/grille/broken // Pre-broken grilles for map placement diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm index 9d5d09c0447..4fcf95dbfd2 100644 --- a/code/modules/admin/admin.dm +++ b/code/modules/admin/admin.dm @@ -950,9 +950,6 @@ var/gamma_ship_location = 1 // 0 = station , 1 = space for(var/obj/machinery/mech_bay_recharge_port/P in toArea) P.update_recharge_turf() - for(var/obj/machinery/power/apc/A in toArea) - A.init() - if(gamma_ship_location) gamma_ship_location = 0 else @@ -1096,7 +1093,7 @@ var/gamma_ship_location = 1 // 0 = station , 1 = space dat += "" + id + "" dat += "" + ckey + "" dat += "Unlink" - + dat += "" usr << browse(dat, "window=duplicates;size=500x480") \ No newline at end of file diff --git a/code/modules/modular_computers/computers/item/computer_power.dm b/code/modules/modular_computers/computers/item/computer_power.dm index d43a5f6d00c..0a7955cfe52 100644 --- a/code/modules/modular_computers/computers/item/computer_power.dm +++ b/code/modules/modular_computers/computers/item/computer_power.dm @@ -13,10 +13,10 @@ if(battery_module && battery_module.battery && battery_module.battery.charge) var/obj/item/stock_parts/cell/cell = battery_module.battery - if(cell.use(amount * CELLRATE)) + if(cell.use(amount * GLOB.CELLRATE)) return TRUE else // Discharge the cell anyway. - cell.use(min(amount*CELLRATE, cell.charge)) + cell.use(min(amount*GLOB.CELLRATE, cell.charge)) return FALSE return FALSE diff --git a/code/modules/modular_computers/file_system/programs/engineering/power_monitor.dm b/code/modules/modular_computers/file_system/programs/engineering/power_monitor.dm index 2efe872a7f5..783ae9fa947 100644 --- a/code/modules/modular_computers/file_system/programs/engineering/power_monitor.dm +++ b/code/modules/modular_computers/file_system/programs/engineering/power_monitor.dm @@ -39,7 +39,7 @@ data["powermonitor"] = attached ? TRUE : FALSE if(attached) - var/datum/powernet/powernet = attached.get_powernet() + var/datum/powernet/powernet = attached.powernet data["poweravail"] = powernet.avail data["powerload"] = powernet.viewload data["powerdemand"] = powernet.load diff --git a/code/modules/modular_computers/hardware/recharger.dm b/code/modules/modular_computers/hardware/recharger.dm index 688d689cf67..418a9736528 100644 --- a/code/modules/modular_computers/hardware/recharger.dm +++ b/code/modules/modular_computers/hardware/recharger.dm @@ -20,7 +20,7 @@ return if(use_power(charge_rate, charging=1)) - holder.give_power(charge_rate * CELLRATE) + holder.give_power(charge_rate * GLOB.CELLRATE) /obj/item/computer_hardware/recharger/APC diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm index c7adce7f533..a3186b115a4 100644 --- a/code/modules/power/apc.dm +++ b/code/modules/power/apc.dm @@ -46,7 +46,6 @@ name = "area power controller" desc = "A control terminal for the area electrical systems." icon_state = "apc0" - anchored = 1 use_power = NO_POWER_USE req_access = list(access_engine_equip) siemens_strength = 1 @@ -55,7 +54,7 @@ var/areastring = null var/obj/item/stock_parts/cell/cell var/start_charge = 90 // initial cell charge % - var/cell_type = 2500 + var/cell_type = 2500 //Base cell has 2500 capacity. Enter the path of a different cell you want to use. cell determines charge rates, max capacity, ect. These can also be changed with other APC vars, but isn't recommended to minimize the risk of accidental usage of dirty editted APCs var/opened = 0 //0=closed, 1=opened, 2=cover removed var/shorted = 0 var/lighting = 3 @@ -137,40 +136,35 @@ /obj/machinery/power/apc/connect_to_network() //Override because the APC does not directly connect to the network; it goes through a terminal. //The terminal is what the power computer looks for anyway. - if(!terminal) - make_terminal() if(terminal) terminal.connect_to_network() -/obj/machinery/power/apc/New(turf/loc, var/ndir, var/building=0) +/obj/machinery/power/apc/New(turf/loc, ndir, building = 0) if(!armor) armor = list(melee = 20, bullet = 20, laser = 10, energy = 100, bomb = 30, bio = 100, rad = 100) ..() GLOB.apcs += src GLOB.apcs = sortAtom(GLOB.apcs) - wires = new(src) + wires = new(src) // offset 24 pixels in direction of dir // this allows the APC to be embedded in a wall, yet still inside an area if(building) - dir = ndir - src.tdir = dir // to fix Vars bug - dir = SOUTH + setDir(ndir) + tdir = dir // to fix Vars bug + setDir(SOUTH) pixel_x = (src.tdir & 3)? 0 : (src.tdir == 4 ? 24 : -24) pixel_y = (src.tdir & 3)? (src.tdir ==1 ? 24 : -24) : 0 - if(building==0) - init() - else + if(building) area = get_area(src) area.apc |= src opened = 1 operating = 0 name = "[area.name] APC" stat |= MAINT - src.update_icon() - spawn(5) - src.update() + update_icon() + addtimer(CALLBACK(src, .proc/update), 5) /obj/machinery/power/apc/Destroy() GLOB.apcs -= src @@ -193,14 +187,17 @@ // create a terminal object at the same position as original turf loc // wires will attach to this terminal = new/obj/machinery/power/terminal(src.loc) - terminal.dir = tdir + terminal.setDir(tdir) terminal.master = src -/obj/machinery/power/apc/proc/init() +/obj/machinery/power/apc/Initialize(mapload) + . = ..() + if(!mapload) + return has_electronics = 2 //installed and secured // is starting with a power cell installed, create it and set its charge level if(cell_type) - src.cell = new/obj/item/stock_parts/cell(src) + cell = new/obj/item/stock_parts/cell(src) cell.maxcharge = cell_type // cell_type is maximum charge (old default was 1000 or 2500 (values one and two respectively) cell.charge = start_charge * cell.maxcharge / 100 // (convert percentage to actual value) @@ -219,12 +216,12 @@ area = get_area_name(areastring) name = "\improper [area.name] APC" area.apc |= src + update_icon() make_terminal() - spawn(5) - src.update() + addtimer(CALLBACK(src, .proc/update), 5) /obj/machinery/power/apc/examine(mob/user) if(..(user, 1)) @@ -1084,14 +1081,9 @@ else return 0 -//Returns 1 if the APC should attempt to charge -/obj/machinery/power/apc/proc/attempt_charging() - return (chargemode && charging == 1 && operating) - -/obj/machinery/power/apc/draw_power(var/amount) +/obj/machinery/power/apc/add_load(amount) if(terminal && terminal.powernet) - return terminal.powernet.draw_power(amount) - return 0 + terminal.add_load(amount) /obj/machinery/power/apc/avail() if(terminal) @@ -1100,7 +1092,6 @@ return 0 /obj/machinery/power/apc/process() - if(stat & (BROKEN|MAINT)) return if(!area.requires_power) @@ -1136,18 +1127,21 @@ if(cell && !shorted) // draw power from cell as before to power the area - var/cellused = min(cell.charge, CELLRATE * lastused_total) // clamp deduction to a max, amount left in cell + var/cellused = min(cell.charge, GLOB.CELLRATE * lastused_total) // clamp deduction to a max, amount left in cell cell.use(cellused) if(excess > lastused_total) // if power excess recharge the cell // by the same amount just used - var/draw = draw_power(cellused/CELLRATE) // draw the power needed to charge this cell - cell.give(draw * CELLRATE) + cell.give(cellused) + add_load(cellused/GLOB.CELLRATE) // add the load used to recharge the cell + + else // no excess, and not enough per-apc - if( (cell.charge/CELLRATE + excess) >= lastused_total) // can we draw enough from cell+grid to cover last usage? - var/draw = draw_power(excess) - cell.charge = min(cell.maxcharge, cell.charge + CELLRATE * draw) //recharge with what we can + if((cell.charge/GLOB.CELLRATE + excess) >= lastused_total) // can we draw enough from cell+grid to cover last usage? + cell.charge = min(cell.maxcharge, cell.charge + GLOB.CELLRATE * excess) //recharge with what we can + add_load(excess) // so draw what we can from the grid charging = 0 + else // not enough power available to run the last tick! charging = 0 chargecount = 0 @@ -1200,14 +1194,12 @@ autoflag = 0 // now trickle-charge the cell - - if(src.attempt_charging()) + if(chargemode && charging == 1 && operating) if(excess > 0) // check to make sure we have enough to charge // Max charge is capped to % per second constant - var/ch = min(excess*CELLRATE, cell.maxcharge*CHARGELEVEL) - - ch = draw_power(ch/CELLRATE) // Removes the power we're taking from the grid - cell.give(ch*CELLRATE) // actually recharge the cell + var/ch = min(excess*GLOB.CELLRATE, cell.maxcharge*GLOB.CHARGELEVEL) + add_load(ch/GLOB.CELLRATE) // Removes the power we're taking from the grid + cell.give(ch) // actually recharge the cell else charging = 0 // stop charging @@ -1220,12 +1212,12 @@ if(chargemode) if(!charging) - if(excess > cell.maxcharge*CHARGELEVEL) + if(excess > cell.maxcharge*GLOB.CHARGELEVEL) chargecount++ else chargecount = 0 - if(chargecount >= 10) + if(chargecount == 10) chargecount = 0 charging = 1 @@ -1292,9 +1284,13 @@ lighting = 0 equipment = 0 environ = 0 + update_icon() + update() spawn(600) equipment = 3 environ = 3 + update_icon() + update() ..() /obj/machinery/power/apc/ex_act(severity) diff --git a/code/modules/power/cable.dm b/code/modules/power/cable.dm index c71bc3e7c8c..5cf1d5efbe3 100644 --- a/code/modules/power/cable.dm +++ b/code/modules/power/cable.dm @@ -59,21 +59,18 @@ By design, d1 is the smallest direction and d2 is the highest /obj/structure/cable/white color = COLOR_WHITE -/obj/structure/cable/New() - ..() - +/obj/structure/cable/Initialize(mapload) + . = ..() // 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 )) - 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) + var/turf/T = get_turf(src) // hide if turf is not intact + if(level == 1) + hide(T.intact) LAZYADD(GLOB.cable_list, src) //add it to the global cable list @@ -83,14 +80,23 @@ By design, d1 is the smallest direction and d2 is the highest LAZYREMOVE(GLOB.cable_list, src) //remove it from global cable list return ..() // then go ahead and delete the cable + +/obj/structure/cable/deconstruct(disassembled = TRUE) + var/turf/T = get_turf(src) + if(d1) // 0-X cables are 1 unit, X-X cables are 2 units long + new/obj/item/stack/cable_coil(T, 2, paramcolor = color) + else + new/obj/item/stack/cable_coil(T, 1, paramcolor = color) + qdel(src) + /////////////////////////////////// // General procedures /////////////////////////////////// //If underfloor, hide the cable -/obj/structure/cable/hide(var/i) +/obj/structure/cable/hide(i) - if(level == 1 && istype(loc, /turf)) + if(level == 1 && isturf(loc)) invisibility = i ? 101 : 0 updateicon() @@ -101,9 +107,49 @@ By design, d1 is the smallest direction and d2 is the highest icon_state = "[d1]-[d2]" -// returns the powernet this cable belongs to -/obj/structure/cable/proc/get_powernet() //TODO: remove this as it is obsolete - return powernet +//////////////////////////////////////////// +// Power related +/////////////////////////////////////////// + +// All power generation handled in add_avail() +// Machines should use add_load(), surplus(), avail() +// Non-machines should use add_delayedload(), delayed_surplus(), newavail() + +/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 Clamp(powernet.avail-powernet.load, 0, powernet.avail) + else + return 0 + +/obj/structure/cable/proc/avail() + if(powernet) + return powernet.avail + else + return 0 + +/obj/structure/cable/proc/add_delayedload(amount) + if(powernet) + powernet.delayedload += amount + +/obj/structure/cable/proc/delayed_surplus() + if(powernet) + return Clamp(powernet.newavail - powernet.delayedload, 0, powernet.newavail) + else + return 0 + +/obj/structure/cable/proc/newavail() + if(powernet) + return powernet.newavail + else + return 0 //Telekinesis has no effect on a cable /obj/structure/cable/attack_tk(mob/user) @@ -120,47 +166,19 @@ By design, d1 is the smallest direction and d2 is the highest if(T.intact) return - if(istype(W, /obj/item/wirecutters)) -///// Z-Level Stuff - /* if(src.d1 == 12 || src.d2 == 12) - to_chat(user, "You must cut this cable from above.") - return */ -///// Z-Level Stuff - /* if(breaker_box) - to_chat(user, "This cable is connected to nearby breaker box. Use breaker box to interact with it.") - return */ - + if(iswirecutter(W)) if(shock(user, 50)) return - - if(src.d1) // 0-X cables are 1 unit, X-X cables are 2 units long - new/obj/item/stack/cable_coil(T, 2, paramcolor = color) - else - new/obj/item/stack/cable_coil(T, 1, paramcolor = color) - - for(var/mob/O in viewers(src, null)) - O.show_message("[user] cuts the cable.", 1) - -///// Z-Level Stuff - /*if(src.d1 == 11 || src.d2 == 11) - var/turf/controllerlocation = locate(1, 1, z) - for(var/obj/effect/landmark/zcontroller/controller in controllerlocation) - if(controller.down) - var/turf/below = locate(src.x, src.y, controller.down_target) - for(var/obj/structure/cable/c in below) - if(c.d1 == 12 || c.d2 == 12) - c.qdel()*/ -///// Z-Level Stuff + user.visible_message("[user] cuts the cable.", "You cut the cable.") investigate_log("was cut by [key_name(usr, 1)] in [get_area(user)]([T.x], [T.y], [T.z] - [ADMIN_JMP(T)])","wires") - - qdel(src) // qdel + deconstruct() return else if(istype(W, /obj/item/stack/cable_coil)) var/obj/item/stack/cable_coil/coil = W if(coil.get_amount() < 1) - to_chat(user, "Not enough cable") + to_chat(user, "Not enough cable!") return coil.cable_join(src, user) @@ -173,11 +191,9 @@ By design, d1 is the smallest direction and d2 is the highest else if(istype(W, /obj/item/multitool)) if(powernet && (powernet.avail > 0)) // is it powered? - to_chat(user, "[powernet.avail]W in power network.") - + to_chat(user, "Total power: [DisplayPower(powernet.avail)]\nLoad: [DisplayPower(powernet.load)]\nExcess power: [DisplayPower(surplus())]") else - to_chat(user, "The cable is not powered.") - + to_chat(user, "The cable is not powered.") shock(user, 5, 0.2) else if(istype(W, /obj/item/toy/crayon)) @@ -188,7 +204,7 @@ By design, d1 is the smallest direction and d2 is the highest if(W.flags & CONDUCT) shock(user, 50, 0.7) - src.add_fingerprint(user) + add_fingerprint(user) // shock the user with probability prb /obj/structure/cable/proc/shock(mob/user, prb, siemens_coeff = 1) @@ -200,21 +216,22 @@ By design, d1 is the smallest direction and d2 is the highest else return FALSE +/obj/structure/cable/singularity_pull(S, current_size) + ..() + if(current_size >= STAGE_FIVE) + deconstruct() + //explosion handling /obj/structure/cable/ex_act(severity) switch(severity) - if(1.0) + if(1) qdel(src) // qdel - if(2.0) + if(2) if(prob(50)) - new/obj/item/stack/cable_coil(get_turf(src), src.d1 ? 2 : 1, paramcolor = color) - qdel(src) // qdel - - if(3.0) + deconstruct() + if(3) if(prob(25)) - new/obj/item/stack/cable_coil(get_turf(src), src.d1 ? 2 : 1, paramcolor = color) - qdel(src) // qdel - return + deconstruct() obj/structure/cable/proc/cable_color(var/colorC) if(colorC) @@ -235,7 +252,7 @@ obj/structure/cable/proc/cable_color(var/colorC) //handles merging diagonally matching cables //for info : direction^3 is flipping horizontally, direction^12 is flipping vertically -/obj/structure/cable/proc/mergeDiagonalsNetworks(var/direction) +/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 @@ -279,7 +296,7 @@ obj/structure/cable/proc/cable_color(var/colorC) 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(var/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 @@ -317,25 +334,27 @@ obj/structure/cable/proc/cable_color(var/colorC) //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)) + 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 == 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)) + 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) + 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 + else if(istype(AM, /obj/machinery/power)) //other power machines var/obj/machinery/power/M = AM if(M.powernet == powernet) @@ -353,23 +372,10 @@ obj/structure/cable/proc/cable_color(var/colorC) ////////////////////////////////////////////// //if powernetless_only = 1, will only get connections without powernet -/obj/structure/cable/proc/get_connections(var/powernetless_only = 0) +/obj/structure/cable/proc/get_connections(powernetless_only = 0) . = list() // this will be a list of all connected power objects var/turf/T -///// Z-Level Stuff - /* if(d1 == 11 || d1 == 12) - var/turf/controllerlocation = locate(1, 1, z) - for(var/obj/effect/landmark/zcontroller/controller in controllerlocation) - if(controller.up && d1 == 12) - T = locate(src.x, src.y, controller.up_target) - if(T) - . += power_list(T, src, 11, 1) - if(controller.down && d1 == 11) - T = locate(src.x, src.y, controller.down_target) - if(T) - . += power_list(T, src, 12, 1) */ -///// Z-Level Stuff //get matching cables from the first direction if(d1) //if not a node cable T = get_step(src, d1) @@ -386,20 +392,6 @@ obj/structure/cable/proc/cable_color(var/colorC) . += power_list(loc, src, d1, powernetless_only) //get on turf matching cables -///// Z-Level Stuff - /*if(d2 == 11 || d2 == 12) - var/turf/controllerlocation = locate(1, 1, z) - for(var/obj/effect/landmark/zcontroller/controller in controllerlocation) - if(controller.up && d2 == 12) - T = locate(src.x, src.y, controller.up_target) - if(T) - . += power_list(T, src, 11, 1) - if(controller.down && d2 == 11) - T = locate(src.x, src.y, controller.down_target) - if(T) - . += power_list(T, src, 12, 1) -///// Z-Level Stuff - else */ //do the same on the second direction (which can't be 0) T = get_step(src, d2) if(T) @@ -420,7 +412,8 @@ obj/structure/cable/proc/cable_color(var/colorC) //needed as this can, unlike other placements, disconnect cables /obj/structure/cable/proc/denode() var/turf/T1 = loc - if(!T1) return + 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) @@ -428,13 +421,19 @@ obj/structure/cable/proc/cable_color(var/colorC) 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) // qdel + qdel(PN) + +/obj/structure/cable/proc/auto_propogate_cut_cable(obj/O) + 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 // cut the cable's powernet at this cable and updates the powergrid -/obj/structure/cable/proc/cut_cable_from_powernet() +/obj/structure/cable/proc/cut_cable_from_powernet(remove=TRUE) var/turf/T1 = loc var/list/P_list - if(!T1) return + 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... @@ -452,11 +451,13 @@ obj/structure/cable/proc/cable_color(var/colorC) 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 + if(remove) + loc = null powernet.remove_cable(src) //remove the cut cable from its powernet // queue it to rebuild SSmachines.deferred_powernet_rebuilds += O +// addtimer(CALLBACK(O, .proc/auto_propogate_cut_cable, O), 0) //so we don't rebuild the network X times when singulo/explosion destroys a line of X cables // Disconnect machines connected to nodes if(d1 == 0) // if we cut a node (O-X) cable @@ -464,6 +465,7 @@ obj/structure/cable/proc/cable_color(var/colorC) 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 /////////////////////////////////////////////// @@ -472,9 +474,7 @@ obj/structure/cable/proc/cable_color(var/colorC) // Definitions //////////////////////////////// -var/global/list/datum/stack_recipe/cable_coil_recipes = list( - new /datum/stack_recipe/cable_restraints("cable restraints", /obj/item/restraints/handcuffs/cable, 15), -) +GLOBAL_LIST_INIT(cable_coil_recipes, list (new/datum/stack_recipe("cable restraints", /obj/item/restraints/handcuffs/cable, 15))) /obj/item/stack/cable_coil name = "cable coil" @@ -514,7 +514,7 @@ var/global/list/datum/stack_recipe/cable_coil_recipes = list( pixel_x = rand(-2,2) pixel_y = rand(-2,2) update_icon() - recipes = cable_coil_recipes + recipes = GLOB.cable_coil_recipes update_wclass() /////////////////////////////////// @@ -657,7 +657,7 @@ var/global/list/datum/stack_recipe/cable_coil_recipes = list( to_chat(user, "You can't lay cable at a place that far away!") return - var/dirn = null + var/dirn if(!dirnew) //If we weren't given a direction, come up with one! (Called as null from catwalk.dm and floor.dm) if(user.loc == T) dirn = user.dir //If laying on the tile we're on, lay in the direction we're facing @@ -694,7 +694,7 @@ var/global/list/datum/stack_recipe/cable_coil_recipes = list( if(C.shock(user, 50)) if(prob(50)) //fail new /obj/item/stack/cable_coil(get_turf(C), 1, paramcolor = C.color) - qdel(C) // qdel + C.deconstruct() return C @@ -711,7 +711,7 @@ var/global/list/datum/stack_recipe/cable_coil_recipes = list( return if(get_dist(C, user) > 1) // make sure it's close enough - to_chat(user, "You can't lay cable at a place that far away.") + to_chat(user, "You can't lay cable at a place that far away!") return @@ -724,13 +724,41 @@ var/global/list/datum/stack_recipe/cable_coil_recipes = list( // one end of the clicked cable is pointing towards us if(C.d1 == dirn || C.d2 == dirn) if(U.intact) // can't place a cable if the floor is complete - to_chat(user, "You can't lay cable there unless the floor tiles are removed.") + to_chat(user, "You can't lay cable there unless the floor tiles are removed!") 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 - place_turf(U, user, turn(dirn, 180)) + 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) + to_chat(user, "There's already a cable at that position!") + return + + var/obj/structure/cable/NC = get_new_cable (U) + + NC.d1 = 0 + NC.d2 = fdirn + NC.add_fingerprint(user) + NC.update_icon() + + //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 @@ -749,7 +777,7 @@ var/global/list/datum/stack_recipe/cable_coil_recipes = list( 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 - to_chat(user, "There's already a cable at that position.") + to_chat(user, "There's already a cable at that position!") return @@ -776,8 +804,7 @@ var/global/list/datum/stack_recipe/cable_coil_recipes = list( if(C.shock(user, 50)) if(prob(50)) //fail - new/obj/item/stack/cable_coil(get_turf(C), 2, paramcolor = C.color) - qdel(C) // qdel + 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. @@ -790,8 +817,8 @@ var/global/list/datum/stack_recipe/cable_coil_recipes = list( /obj/item/stack/cable_coil/cut item_state = "coil2" -/obj/item/stack/cable_coil/cut/New(loc) - ..() +/obj/item/stack/cable_coil/cut/Initialize(mapload) + . = ..() src.amount = rand(1,2) pixel_x = rand(-2,2) pixel_y = rand(-2,2) diff --git a/code/modules/power/gravitygenerator.dm b/code/modules/power/gravitygenerator.dm index 3a453ffe10c..8b5f64e94fb 100644 --- a/code/modules/power/gravitygenerator.dm +++ b/code/modules/power/gravitygenerator.dm @@ -85,8 +85,8 @@ var/const/GRAV_NEEDS_WRENCH = 3 // Generator which spawns with the station. // -/obj/machinery/gravity_generator/main/station/Initialize() - ..() +/obj/machinery/gravity_generator/main/station/Initialize(mapload) + . = ..() setup_parts() middle.overlays += "activated" update_list() diff --git a/code/modules/power/power.dm b/code/modules/power/power.dm index 3e5d614896e..33741d1475b 100644 --- a/code/modules/power/power.dm +++ b/code/modules/power/power.dm @@ -9,7 +9,7 @@ /obj/machinery/power name = null icon = 'icons/obj/power.dmi' - anchored = 1.0 + anchored = TRUE on_blueprints = TRUE var/datum/powernet/powernet = null use_power = NO_POWER_USE @@ -25,18 +25,24 @@ ////////////////////////////// // common helper procs for all power machines -/obj/machinery/power/proc/add_avail(var/amount) +// All power generation handled in add_avail() +// Machines should use add_load(), surplus(), avail() +// Non-machines should use add_delayedload(), delayed_surplus(), newavail() + +/obj/machinery/power/proc/add_avail(amount) if(powernet) powernet.newavail += amount + return TRUE + else + return FALSE -/obj/machinery/power/proc/draw_power(var/amount) +/obj/machinery/power/proc/add_load(amount) if(powernet) - return powernet.draw_power(amount) - return 0 + powernet.load += amount /obj/machinery/power/proc/surplus() if(powernet) - return powernet.avail-powernet.load + return Clamp(powernet.avail-powernet.load, 0, powernet.avail) else return 0 @@ -46,9 +52,19 @@ else return 0 -/obj/machinery/power/proc/load() +/obj/machinery/power/proc/add_delayedload(amount) if(powernet) - return powernet.load + powernet.delayedload += amount + +/obj/machinery/power/proc/delayed_surplus() + if(powernet) + return Clamp(powernet.newavail - powernet.delayedload, 0, powernet.newavail) + else + return 0 + +/obj/machinery/power/proc/newavail() + if(powernet) + return powernet.newavail else return 0 @@ -58,21 +74,20 @@ // 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 + return FALSE if(!use_power) - return 1 + return TRUE var/area/A = get_area(src) // make sure it's in an area if(!A) - return 0 // if not, then not powered + return FALSE // if not, then not powered if(chan == -1) chan = power_channel return A.powered(chan) // return power status of the area // increment the power usage stats for an area -/obj/machinery/proc/use_power(var/amount, var/chan = -1) // defaults to power_channel +/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) return @@ -103,43 +118,36 @@ /obj/machinery/power/proc/connect_to_network() var/turf/T = src.loc if(!T || !istype(T)) - return 0 + return FALSE 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 + return FALSE C.powernet.add_machine(src) - return 1 + return TRUE // remove and disconnect the machine from its current powernet /obj/machinery/power/proc/disconnect_from_network() if(!powernet) - return 0 + return FALSE powernet.remove_machine(src) - return 1 + return TRUE // 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/W, mob/user) - - if(istype(W, /obj/item/stack/cable_coil)) - - var/obj/item/stack/cable_coil/coil = W - +/obj/machinery/power/attackby(obj/item/I, mob/user, params) + if(istype(I, /obj/item/stack/cable_coil)) + var/obj/item/stack/cable_coil/coil = I var/turf/T = user.loc - - if(T.intact || !istype(T, /turf/simulated/floor)) + if(T.intact || !isfloorturf(T)) return - if(get_dist(src, user) > 1) return - coil.place_turf(T, user) - return else - ..() - return + return ..() + /////////////////////////////////////////// // Powernet handling helpers @@ -159,7 +167,8 @@ cdir = get_dir(T,loc) for(var/obj/structure/cable/C in T) - if(C.powernet) continue + if(C.powernet) + continue if(C.d1 == cdir || C.d2 == cdir) . += C return . @@ -186,7 +195,8 @@ /obj/machinery/power/proc/get_indirect_connections() . = list() for(var/obj/structure/cable/C in loc) - if(C.powernet) continue + if(C.powernet) + continue if(C.d1 == 0) // the cable is a node cable . += C return . @@ -199,44 +209,32 @@ // 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(var/turf/T, var/source, var/d, var/unmarked=0, var/cable_only = 0) +/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) -///// Z-Level Stuff - var/Zdir - if(d==11) - Zdir = 11 - else if(d==12) - Zdir = 12 - else - Zdir = 999 -///// Z-Level Stuff - for(var/AM in T) - if(AM == source) continue //we don't want to return source - if(!cable_only && istype(AM,/obj/machinery/power)) + 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(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)) + else if(istype(AM, /obj/structure/cable)) var/obj/structure/cable/C = AM if(!unmarked || !C.powernet) -///// Z-Level Stuff - if(C.d1 == fdir || C.d2 == fdir || C.d1 == Zdir || C.d2 == Zdir) -///// Z-Level Stuff - . += C - else if(C.d1 == d || C.d2 == d) + 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(var/obj/O, var/datum/powernet/PN) - //log_world("propagating new network") +/proc/propagate_network(obj/O, datum/powernet/PN) var/list/worklist = list() var/list/found_machines = list() var/index = 1 @@ -248,13 +246,13 @@ P = worklist[index] //get the next power object found index++ - if( istype(P,/obj/structure/cable)) + 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)) + 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 @@ -268,7 +266,7 @@ //Merge two powernets, the bigger (in cable length term) absorbing the other -/proc/merge_powernets(var/datum/powernet/net1, var/datum/powernet/net2) +/proc/merge_powernets(datum/powernet/net1, datum/powernet/net2) if(!net1 || !net2) //if one of the powernet doesn't exist, return return @@ -285,8 +283,6 @@ for(var/obj/structure/cable/Cable in net2.cables) //merge cables net1.add_cable(Cable) - if(!net2) return net1 - 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 @@ -299,14 +295,12 @@ //source is an object caused electrocuting (airlock, grille, etc) //No animations will be performed by this proc. /proc/electrocute_mob(mob/living/M, power_source, obj/source, siemens_coeff = 1, dist_check = FALSE) - if(!istype(M)) - return FALSE - if(istype(M.loc,/obj/mecha)) + if(!M || ismecha(M.loc)) return FALSE //feckin mechs are dumb if(dist_check) if(!in_range(source, M)) return FALSE - if(istype(M,/mob/living/carbon/human)) + if(ishuman(M)) var/mob/living/carbon/human/H = M if(H.gloves) var/obj/item/clothing/gloves/G = H.gloves @@ -326,7 +320,7 @@ if(istype(power_source, /datum/powernet)) PN = power_source - else if(istype(power_source,/obj/item/stock_parts/cell)) + else if(istype(power_source, /obj/item/stock_parts/cell)) cell = power_source else if(istype(power_source, /obj/machinery/power/apc)) var/obj/machinery/power/apc/apc = power_source @@ -357,10 +351,30 @@ 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" - drained_power = PN.draw_power(drained_power) - else if(istype(power_source, /obj/item/stock_parts/cell)) + source_area.use_power(drained_energy/GLOB.CELLRATE) + else if(istype(power_source, /datum/powernet)) + var/drained_power = drained_energy/GLOB.CELLRATE //convert from "joules" to "watts" + PN.delayedload += (min(drained_power, max(PN.newavail - PN.delayedload, 0))) + else if (istype(power_source, /obj/item/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 GLOB.apcs) + if(APC.area == src) + return APC \ No newline at end of file diff --git a/code/modules/power/powernet.dm b/code/modules/power/powernet.dm index 228b4232968..b64481b1104 100644 --- a/code/modules/power/powernet.dm +++ b/code/modules/power/powernet.dm @@ -1,19 +1,19 @@ +//////////////////////////////////////////// +// 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/number = 0 // Unused //TODEL - - var/perapc = 0 // per-apc avilability - var/perapc_excess = 0 - var/netexcess = 0 // excess power on the powernet (typically avail-load) - - var/problem = 0 // If either of these is set to 1 there is some sort of issue at the powernet. - + var/netexcess = 0 // excess power on the powernet (typically avail-load)/////// + var/delayedload = 0 // load applied to powernet between power ticks. /datum/powernet/New() SSmachines.powernets += src @@ -31,31 +31,21 @@ SSmachines.powernets -= src return ..() -//Returns the amount of excess power (before refunding to SMESs) from last tick. -//This is for machines that might adjust their power consumption using this data. -/datum/powernet/proc/last_surplus() - return max(avail - load, 0) - -/datum/powernet/proc/draw_power(var/amount) - var/draw = between(0, amount, avail - load) - load += draw - return draw - /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(var/obj/structure/cable/C) +/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 - qdel + 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(var/obj/structure/cable/C) +/datum/powernet/proc/add_cable(obj/structure/cable/C) if(C.powernet)// if C already has a powernet... if(C.powernet == src) return @@ -67,16 +57,16 @@ //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(var/obj/machinery/power/M) +/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 - qdel + 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(var/obj/machinery/power/M) +/datum/powernet/proc/add_machine(obj/machinery/power/M) if(M.powernet)// if M already has a powernet... if(M.powernet == src) return @@ -85,45 +75,23 @@ M.powernet = src nodes[M] = M -// Triggers warning for certain amount of ticks -/datum/powernet/proc/trigger_warning(var/duration_ticks = 20) - problem = max(duration_ticks, problem) - //handles the power changes in the powernet //called every ticks by the powernet controller /datum/powernet/proc/reset() - var/numapc = 0 - - if(problem > 0) - problem = max(problem - 1, 0) - - if(nodes && nodes.len) // Added to fix a bad list bug -- TLE - for(var/obj/machinery/power/terminal/term in nodes) - if( istype( term.master, /obj/machinery/power/apc ) ) - numapc++ - + //see if there's a surplus of power remaining in the powernet and stores unused power in the SMES netexcess = avail - load - if(numapc) - //very simple load balancing. If there was a net excess this tick then it must have been that some APCs used less than perapc, since perapc*numapc = avail - //Therefore we can raise the amount of power rationed out to APCs on the assumption that those APCs that used less than perapc will continue to do so. - //If that assumption fails, then some APCs will miss out on power next tick, however it will be rebalanced for the tick after. - if(netexcess >= 0) - perapc_excess += min(netexcess/numapc, (avail - perapc) - perapc_excess) - else - perapc_excess = 0 - - perapc = avail/numapc + perapc_excess - 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 - //updates the viewed load (as seen on power computers) - viewload = round(load) + // update power consoles + viewavail = round(0.8 * viewavail + 0.2 * avail) + viewload = round(0.8 * viewload + 0.2 * load) - //reset the powernet - load = 0 + // reset the powernet + load = delayedload + delayedload = 0 avail = newavail newavail = 0 @@ -131,27 +99,4 @@ if(avail >= 1000) return Clamp(20 + round(avail / 25000), 20, 195) + rand(-5, 5) else - return 0 - -//////////////////////////////////////////////// -// 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(!istype(src, /turf/simulated/floor)) - return null - for(var/obj/structure/cable/C in src) - if(C.d1 == 0) - return C - return null - -/area/proc/get_apc() - // This was a simple locate() in src, but an unresolved BYOND bug causes trying to locate() in an - // area to take an inconceivably long time, especially for large areas. - // See: http://www.byond.com/forum/?post=1860571 - var/obj/machinery/power/apc/FINDME - for(FINDME in src) - return FINDME \ No newline at end of file + return 0 \ No newline at end of file diff --git a/code/modules/power/singularity/collector.dm b/code/modules/power/singularity/collector.dm index a85d9e880bd..3e910a613b0 100644 --- a/code/modules/power/singularity/collector.dm +++ b/code/modules/power/singularity/collector.dm @@ -15,8 +15,8 @@ var/global/list/rad_collectors = list() var/locked = 0 var/drainratio = 1 -/obj/machinery/power/rad_collector/New() - ..() +/obj/machinery/power/rad_collector/Initialize(mapload) + . = ..() rad_collectors += src /obj/machinery/power/rad_collector/Destroy() diff --git a/code/modules/power/singularity/emitter.dm b/code/modules/power/singularity/emitter.dm index 7e031755e22..9ba302ab19b 100644 --- a/code/modules/power/singularity/emitter.dm +++ b/code/modules/power/singularity/emitter.dm @@ -23,18 +23,25 @@ var/frequency = 0 var/id_tag = null + var/projectile_type = /obj/item/projectile/beam/emitter + var/projectile_sound = 'sound/weapons/emitter.ogg' var/datum/radio_frequency/radio_connection var/datum/effect_system/spark_spread/sparks -/obj/machinery/power/emitter/New() - ..() +/obj/machinery/power/emitter/Initialize(mapload) + . = ..() component_parts = list() component_parts += new /obj/item/circuitboard/emitter(null) component_parts += new /obj/item/stock_parts/micro_laser(null) component_parts += new /obj/item/stock_parts/manipulator(null) RefreshParts() + if(state == 2 && anchored) + connect_to_network() sparks = new + sparks.attach(src) sparks.set_up(5, 1, src) + if(frequency) + set_frequency(frequency) /obj/machinery/power/emitter/RefreshParts() var/max_firedelay = 120 @@ -79,13 +86,6 @@ return rotate() -/obj/machinery/power/emitter/Initialize() - ..() - if(state == 2 && anchored) - connect_to_network() - if(frequency) - set_frequency(frequency) - /obj/machinery/power/emitter/multitool_menu(var/mob/user,var/obj/item/multitool/P) return {"