diff --git a/code/controllers/garbage.dm b/code/controllers/garbage.dm index 6ef53e355eb..1a16906a212 100644 --- a/code/controllers/garbage.dm +++ b/code/controllers/garbage.dm @@ -66,5 +66,14 @@ var/global/list/uncollectable_vars=list( Pop() waiting-- -/proc/qdel(var/atom/A) +/** +* NEVER USE THIS FOR ANYTHING OTHER THAN /atom/movable +* OTHER TYPES CANNOT BE QDEL'D BECAUSE THEIR LOC IS LOCKED OR THEY DON'T HAVE ONE. +*/ +/proc/qdel(var/atom/movable/A) + if(!A) return + if(!istype(A)) + warning("qdel passed a [A.type]. qdel() can only handle /atom/movable types.") + del(A) + return garbage.AddTrash(A) \ No newline at end of file diff --git a/code/defines/procs/AStar.dm b/code/defines/procs/AStar.dm index e28a159c6ad..0af47ba12c6 100644 --- a/code/defines/procs/AStar.dm +++ b/code/defines/procs/AStar.dm @@ -38,126 +38,148 @@ length to avoid portals or something i guess?? Not that they're counted right no PriorityQueue - var/list/queue - var/proc/comparison_function - + var/L[] + var/cmp New(compare) - queue = list() - comparison_function = compare + L = new() + cmp = compare + proc + IsEmpty() + return !L.len + Enqueue(d) + var/i + var/j + L.Add(d) + i = L.len + j = i>>1 + while(i > 1 && call(cmp)(L[j],L[i]) > 0) + L.Swap(i,j) + i = j + j >>= 1 - proc/IsEmpty() - return !queue.len - - proc/Enqueue(var/data) - queue.Add(data) - var/index = queue.len - - //From what I can tell, this automagically sorts the added data into the correct location. - while(index > 2 && call(comparison_function)(queue[index / 2], queue[index]) > 0) - queue.Swap(index, index / 2) - index /= 2 - - proc/Dequeue() - if(!queue.len) - return - return Remove(1) - - proc/Remove(index) - if(index > queue.len) - return - - var/thing = queue[index] - queue.Cut(index, index + 1) - return thing - - proc/List() - return queue.Copy() - - proc/Length() - return queue.len - - proc/RemoveItem(data) - var/index = queue.Find(data) - if(index) - return Remove(index) + Dequeue() + if(!L.len) return 0 + . = L[1] + Remove(1) + Remove(i) + if(i > L.len) return 0 + L.Swap(i,L.len) + L.Cut(L.len) + if(i < L.len) + _Fix(i) + _Fix(i) + var/child = i + i + var/item = L[i] + while(child <= L.len) + if(child + 1 <= L.len && call(cmp)(L[child],L[child + 1]) > 0) + child++ + if(call(cmp)(item,L[child]) > 0) + L[i] = L[child] + i = child + else + break + child = i + i + L[i] = item + List() + var/ret[] = new() + var/copy = L.Copy() + while(!IsEmpty()) + ret.Add(Dequeue()) + L = copy + return ret + RemoveItem(i) + var/ind = L.Find(i) + if(ind) + Remove(ind) PathNode - var/datum/position - var/PathNode/previous_node + var/datum/source + var/PathNode/prevNode + var/f + var/g + var/h + var/nt // Nodes traversed + New(s,p,pg,ph,pnt) + source = s + prevNode = p + g = pg + h = ph + f = g + h + source.bestF = f + nt = pnt - var/best_estimated_cost - var/estimated_cost - var/known_cost - var/cost - var/nodes_traversed +datum + var/bestF +proc + PathWeightCompare(PathNode/a, PathNode/b) + return a.f - b.f - New(_position, _previous_node, _known_cost, _cost, _nodes_traversed) - position = _position - previous_node = _previous_node + AStar(start,end,adjacent,dist,maxnodes,maxnodedepth = 30,mintargetdist,minnodedist,id=null, var/turf/exclude=null) - known_cost = _known_cost - cost = _cost - estimated_cost = cost + known_cost +// world << "A*: [start] [end] [adjacent] [dist] [maxnodes] [maxnodedepth] [mintargetdist], [minnodedist] [id]" + var/PriorityQueue/open = new /PriorityQueue(/proc/PathWeightCompare) + var/closed[] = new() + var/path[] + start = get_turf(start) + if(!start) return 0 - best_estimated_cost = estimated_cost - nodes_traversed = _nodes_traversed + open.Enqueue(new /PathNode(start,null,0,call(start,dist)(end))) -proc/PathWeightCompare(PathNode/a, PathNode/b) - return a.estimated_cost - b.estimated_cost + while(!open.IsEmpty() && !path) + { + var/PathNode/cur = open.Dequeue() + closed.Add(cur.source) -proc/AStar(var/start, var/end, var/proc/adjacent, var/proc/dist, var/max_nodes, var/max_node_depth = 30, var/min_target_dist = 0, var/min_node_dist, var/id, var/datum/exclude) - var/PriorityQueue/open = new /PriorityQueue(/proc/PathWeightCompare) - var/list/closed = list() - var/list/path - var/list/path_node_by_position = list() - start = get_turf(start) - if(!start) - return 0 + var/closeenough + if(mintargetdist) + closeenough = call(cur.source,dist)(end) <= mintargetdist - open.Enqueue(new /PathNode(start, null, 0, call(start, dist)(end), 0)) + if(cur.source == end || closeenough) + path = new() + path.Add(cur.source) + while(cur.prevNode) + cur = cur.prevNode + path.Add(cur.source) + break - while(!open.IsEmpty() && !path) - var/PathNode/current = open.Dequeue() - closed.Add(current.position) + var/L[] = call(cur.source,adjacent)(id) + if(minnodedist && maxnodedepth) + if(call(cur.source,minnodedist)(end) + cur.nt >= maxnodedepth) + continue + else if(maxnodedepth) + if(cur.nt >= maxnodedepth) + continue - if(current.position == end || call(current.position, dist)(end) <= min_target_dist) - path = new /list(current.nodes_traversed + 1) - path[path.len] = current.position - var/index = path.len - 1 - - while(current.previous_node) - current = current.previous_node - path[index--] = current.position - break - - if(min_node_dist && max_node_depth) - if(call(current.position, min_node_dist)(end) + current.nodes_traversed >= max_node_depth) - continue - - if(max_node_depth) - if(current.nodes_traversed >= max_node_depth) - continue - - for(var/datum/datum in call(current.position, adjacent)(id)) - if(datum == exclude) - continue - - var/best_estimated_cost = current.estimated_cost + call(current.position, dist)(datum) - - //handle removal of sub-par positions - if(datum in path_node_by_position) - var/PathNode/target = path_node_by_position[datum] - if(target.best_estimated_cost) - if(best_estimated_cost + call(datum, dist)(end) < target.best_estimated_cost) - open.RemoveItem(target) + for(var/datum/d in L) + if(d == exclude) + continue + var/ng = cur.g + call(cur.source,dist)(d) + if(d.bestF) + if(ng + call(d,dist)(end) < d.bestF) + for(var/i = 1; i <= open.L.len; i++) + var/PathNode/n = open.L[i] + if(n.source == d) + open.Remove(i) + break else continue - var/PathNode/next_node = new (datum, current, best_estimated_cost, call(datum, dist)(end), current.nodes_traversed + 1) - path_node_by_position[datum] = next_node - open.Enqueue(next_node) + open.Enqueue(new /PathNode(d,cur,ng,call(d,dist)(end),cur.nt+1)) + if(maxnodes && open.L.len > maxnodes) + open.L.Cut(open.L.len) + } - if(max_nodes && open.Length() > max_nodes) - open.Remove(open.Length()) + var/PathNode/temp + while(!open.IsEmpty()) + temp = open.Dequeue() + temp.source.bestF = 0 + while(closed.len) + temp = closed[closed.len] + temp.bestF = 0 + closed.Cut(closed.len) - return path + if(path) + for(var/i = 1; i <= path.len/2; i++) + path.Swap(i,path.len-i+1) + + return path diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index 65c14ffd4fa..72b6e54bf62 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -183,4 +183,11 @@ /atom/movable/overlay/attack_hand(a, b, c) if (src.master) return src.master.attack_hand(a, b, c) - return \ No newline at end of file + return + +///////////////////////////// +// SINGULOTH PULL REFACTOR +///////////////////////////// +/atom/movable/proc/canSingulothPull(var/obj/machinery/singularity/singulo) + return 1 + diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 00b1a4c3955..736770a9788 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -1458,3 +1458,14 @@ mob/living/carbon/human/yank_out_object() drop_from_inventory(head) update_hair() update_body() + +/mob/living/carbon/human/canSingulothPull(var/obj/machinery/singularity/singulo) + if(!..()) + return 0 + + if(istype(shoes,/obj/item/clothing/shoes/magboots)) + var/obj/item/clothing/shoes/magboots/M = shoes + if(M.magpulse) + return 0 + return 1 + diff --git a/code/modules/power/singularity/singularity.dm b/code/modules/power/singularity/singularity.dm index 181cc509cb5..e94f4939f2a 100644 --- a/code/modules/power/singularity/singularity.dm +++ b/code/modules/power/singularity/singularity.dm @@ -214,7 +214,10 @@ var/global/list/uneatable = list( // Movable atoms only if(dist > consume_range && istype(X, /atom/movable)) if(is_type_in_list(X, uneatable)) continue - if(((X) &&(!X:anchored) && (!istype(X,/mob/living/carbon/human)))|| (src.current_size >= 9)) + if(canPull(X)) + step_towards(X,src) + /* + if((X &&!X:anchored && !istype(X,/mob/living/carbon/human))|| (src.current_size >= 9)) step_towards(X,src) else if(istype(X,/mob/living/carbon/human)) var/mob/living/carbon/human/H = X @@ -223,6 +226,7 @@ var/global/list/uneatable = list( if(M.magpulse) continue step_towards(H,src) + */ // Turf and movable atoms else if(dist <= consume_range && (isturf(X) || istype(X, /atom/movable))) consume(X) @@ -231,6 +235,18 @@ var/global/list/uneatable = list( defer_powernet_rebuild = 0 return +// Singulo optimization: +// Jump out whenever we've made a decision. +/obj/machinery/singularity/proc/canPull(var/atom/movable/A) + // If we're big enough, stop checking for this and that and JUST EAT. + if(current_size >= 9) + return 1 + else + if(A && !A:anchored) + if(A.canSingulothPull(src)) + return 1 + return 0 + /obj/machinery/singularity/proc/consume(var/atom/A) var/gain = 0 @@ -241,15 +257,14 @@ var/global/list/uneatable = list( if(istype(A,/mob/living/carbon/human)) var/mob/living/carbon/human/H = A if(H.mind) - - if((H.mind.assigned_role == "Station Engineer") || (H.mind.assigned_role == "Chief Engineer") ) - gain = 100 - - if(H.mind.assigned_role == "Clown") - gain = rand(-300, 300) // HONK - + switch(H.mind.assigned_role) + if("Station Engineer","Chief Engineer") + gain = 100 + if("Clown") + gain = rand(-300, 300) // HONK spawn() A:gib() + // Why sleep(1) else if(istype(A,/obj/)) @@ -257,7 +272,6 @@ var/global/list/uneatable = list( var/dist = max((current_size - 2),1) explosion(src.loc,(dist),(dist*2),(dist*4)) return - if(istype(A, /obj/machinery/singularity))//Welp now you did it var/obj/machinery/singularity/S = A src.energy += (S.energy/2)//Absorb most of it @@ -267,13 +281,11 @@ var/global/list/uneatable = list( return//Quits here, the obj should be gone, hell we might be if((teleport_del) && (!istype(A, /obj/machinery)))//Going to see if it does not lag less to tele items over to Z 2 - var/obj/O = A - O.x = 2 - O.y = 2 - O.z = 2 + qdel(A) else A.ex_act(1.0) - if(A) del(A) + if(A) + qdel(A) gain = 2 else if(isturf(A)) var/turf/T = A @@ -492,7 +504,7 @@ var/global/list/uneatable = list( A:gib() else if(istype(A,/obj/)) A:ex_act(1.0) - if(A) del(A) + if(A) qdel(A) else if(isturf(A)) var/turf/T = A if(T.intact)