diff --git a/code/datums/ductnet.dm b/code/datums/ductnet.dm index 37b07161df7..744d9a919b0 100644 --- a/code/datums/ductnet.dm +++ b/code/datums/ductnet.dm @@ -14,19 +14,20 @@ ///Remove a duct from our network and commit suicide, because this is probably easier than to check who that duct was connected to and what part of us was lost /datum/ductnet/proc/remove_duct(obj/machinery/duct/ducting) destroy_network(FALSE) - for(var/A in ducting.neighbours) - var/obj/machinery/duct/D = A - D.attempt_connect() //we destroyed the network, so now we tell the disconnected ducts neighbours they can start making a new ductnet + for(var/obj/machinery/duct/D in ducting.neighbours) + addtimer(CALLBACK(D, /obj/machinery/duct/proc/reconnect), 0) //all needs to happen after the original duct that was destroyed finishes destroying itself + addtimer(CALLBACK(D, /obj/machinery/duct/proc/generate_connects), 0) qdel(src) ///add a plumbing object to either demanders or suppliers /datum/ductnet/proc/add_plumber(datum/component/plumbing/P, dir) if(!P.can_add(src, dir)) - return + return FALSE P.ducts[num2text(dir)] = src if(dir & P.supply_connects) suppliers += P else if(dir & P.demand_connects) demanders += P + return TRUE ///remove a plumber. we dont delete ourselves because ductnets dont persist through plumbing objects /datum/ductnet/proc/remove_plumber(datum/component/plumbing/P) suppliers.Remove(P) //we're probably only in one of these, but Remove() is inherently sane so this is fine diff --git a/code/modules/plumbing/ducts.dm b/code/modules/plumbing/ducts.dm index af2f81db07d..5d27d1c6f2c 100644 --- a/code/modules/plumbing/ducts.dm +++ b/code/modules/plumbing/ducts.dm @@ -10,7 +10,7 @@ All the important duct code: level = 1 ///bitfield with the directions we're connected in var/connects - ///set to TRUE to disable smart cable behaviour + ///set to TRUE to disable smart duct behaviour var/dumb = FALSE ///wheter we allow our connects to be changed after initialization or not var/lock_connects = FALSE @@ -93,11 +93,11 @@ All the important duct code: if(!dumb && D.dumb && !(opposite_dir & D.connects)) return - if(dumb && D.dumb && !(connects & D.connects)) //we eliminated a few more scenario in attempt connect + if(dumb && D.dumb && !(connects & D.connects)) //we eliminated a few more scenarios in attempt connect return if((duct == D.duct) && duct)//check if we're not just comparing two null values - add_neighbour(D) + add_neighbour(D, direction) D.add_connects(opposite_dir) D.update_icon() @@ -119,8 +119,10 @@ All the important duct code: else create_duct() duct.add_duct(D) - add_neighbour(D) - D.attempt_connect()//tell our buddy its time to pass on the torch of connecting to pipes. This shouldn't ever infinitely loop since it only works on pipes that havent been inductrinated + add_neighbour(D, direction) + //tell our buddy its time to pass on the torch of connecting to pipes. This shouldn't ever infinitely loop since it only works on pipes that havent been inductrinated + D.attempt_connect() + return TRUE ///connect to a plumbing object /obj/machinery/duct/proc/connect_plumber(datum/component/plumbing/P, direction) @@ -135,8 +137,9 @@ All the important duct code: if(opposite_dir & comp_directions) if(!duct) create_duct() - duct.add_plumber(P, opposite_dir) - return TRUE + if(duct.add_plumber(P, opposite_dir)) + neighbours[P.parent] = direction + return TRUE ///we disconnect ourself from our neighbours. we also destroy our ductnet and tell our neighbours to make a new one /obj/machinery/duct/proc/disconnect_duct() anchored = FALSE @@ -150,20 +153,52 @@ All the important duct code: new drop_on_wrench(drop_location()) qdel(src) +///''''''''''''''''optimized''''''''''''''''' proc for quickly reconnecting after a duct net was destroyed +/obj/machinery/duct/proc/reconnect() + if(neighbours.len && !duct) + create_duct() + for(var/atom/movable/AM in neighbours) + if(istype(AM, /obj/machinery/duct)) + var/obj/machinery/duct/D = AM + if(D.duct) + if(D.duct == duct) //we're already connected + continue + else + duct.assimilate(D.duct) + continue + else + duct.add_duct(D) + D.reconnect() + else + var/datum/component/plumbing/P = AM.GetComponent(/datum/component/plumbing) + if(AM in get_step(src, neighbours[AM])) //did we move? + if(P) + connect_plumber(P, neighbours[AM]) + else + neighbours -= AM //we moved + +///Special proc to draw a new connect frame based on neighbours. not the norm so we can support multiple duct kinds +/obj/machinery/duct/proc/generate_connects() + if(lock_connects) + return + connects = 0 + for(var/A in neighbours) + connects |= neighbours[A] + update_icon() + ///create a new duct datum /obj/machinery/duct/proc/create_duct() duct = new() duct.add_duct(src) ///add a duct as neighbour. this means we're connected and will connect again if we ever regenerate -/obj/machinery/duct/proc/add_neighbour(obj/machinery/duct/D) +/obj/machinery/duct/proc/add_neighbour(obj/machinery/duct/D, direction) if(!(D in neighbours)) - neighbours += D + neighbours[D] = direction if(!(src in D.neighbours)) - D.neighbours += src + D.neighbours[src] = turn(direction, 180) ///remove all our neighbours, and remove us from our neighbours aswell /obj/machinery/duct/proc/lose_neighbours() - for(var/A in neighbours) - var/obj/machinery/duct/D = A + for(var/obj/machinery/duct/D in neighbours) D.neighbours.Remove(src) neighbours = list() ///add a connect direction @@ -272,7 +307,7 @@ All the important duct code: return add_connects(direction) //the connect of the other duct is handled in connect_network, but do this here for the parent duct because it's not necessary in normal cases - add_neighbour(D) + add_neighbour(D, direction) connect_network(D, direction, TRUE) update_icon() ///has a total of 5 layers and doesnt give a shit about color. its also dumb so doesnt autoconnect.