From e3746f7547940f1818c8cf9ab9a8bcc2c415ccb2 Mon Sep 17 00:00:00 2001 From: D3athrow Date: Thu, 5 Feb 2015 17:44:48 -0600 Subject: [PATCH] Up to date timesort to resolve list issues. --- code/__HELPERS/lists.dm | 216 +++++++------------ code/__HELPERS/sorts/_Main.dm | 56 ++--- code/__HELPERS/type2type.dm | 2 +- code/__HELPERS/unsorted.dm | 25 ++- code/defines/obj.dm | 2 +- code/game/area/Space Station 13 areas.dm | 57 +---- code/game/machinery/computer/crew.dm | 2 +- code/game/machinery/kitchen/smartfridge.dm | 2 +- code/game/objects/items/blueprints.dm | 1 + code/game/objects/items/devices/handtv.dm | 2 +- code/global.dm | 5 +- code/modules/admin/admin_verbs.dm | 1 + code/modules/admin/verbs/adminjump.dm | 21 +- code/modules/admin/verbs/debug.dm | 17 ++ code/modules/reagents/Chemistry-Machinery.dm | 1 + code/world.dm | 5 +- 16 files changed, 169 insertions(+), 246 deletions(-) diff --git a/code/__HELPERS/lists.dm b/code/__HELPERS/lists.dm index 2c0e852d5ba..84f702306fa 100644 --- a/code/__HELPERS/lists.dm +++ b/code/__HELPERS/lists.dm @@ -31,29 +31,28 @@ return "[output][and_text][input[index]]" //Returns list element or null. Should prevent "index out of bounds" error. -proc/listgetindex(var/list/list,index) - if(istype(list) && list.len) +/proc/listgetindex(list/L, index) + if(istype(L)) if(isnum(index)) - if(IsInRange(index,1,list.len)) - return list[index] - else if(index in list) - return list[index] + if(IsInRange(index,1,L.len)) + return L[index] + else if(index in L) + return L[index] return -proc/islist(list/list) - if(istype(list)) +/proc/islist(list/L) + if(istype(L)) return 1 return 0 //Return either pick(list) or null if list is not of type /list or is empty -proc/safepick(list/list) - if(!islist(list) || !list.len) - return - return pick(list) +/proc/safepick(list/L) + if(istype(L) && L.len) + return pick(L) //Checks if the list is empty -proc/isemptylist(list/list) - if(!list.len) +/proc/isemptylist(list/L) + if(!L.len) return 1 return 0 @@ -65,17 +64,20 @@ proc/isemptylist(list/list) return 0 //Empties the list by setting the length to 0. Hopefully the elements get garbage collected -proc/clearlist(list/list) +/proc/clearlist(list/list) if(istype(list)) list.len = 0 return //Removes any null entries from the list -proc/listclearnulls(list/list) - if(istype(list)) - while(null in list) - list -= null - return +/proc/listclearnulls(list/L) + if(istype(L)) + var/i=1 + for(var/thing in L) + if(thing != null) + ++i + continue + L.Cut(i,i+1) /* * Returns list containing all the entries from first list that are not present in second. @@ -127,21 +129,43 @@ proc/listclearnulls(list/list) return null //Pick a random element from the list and remove it from the list. -/proc/pick_n_take(list/listfrom) - if (listfrom.len > 0) - var/picked = pick(listfrom) - listfrom -= picked - return picked - return null +/proc/pick_n_take(list/L) + if(L.len) + var/picked = rand(1,L.len) + . = L[picked] + L.Cut(picked,picked+1) //Cut is far more efficient that Remove() //Returns the top(last) element from the list and removes it from the list (typical stack function) -/proc/pop(list/listfrom) - if (listfrom.len > 0) - var/picked = listfrom[listfrom.len] - listfrom.len-- - return picked - return null +/proc/pop(list/L) + if(L.len) + . = L[L.len] + L.len-- +/proc/sorted_insert(list/L, thing, comparator) + var/pos = L.len + while(pos > 0 && call(comparator)(thing, L[pos]) > 0) + pos-- + L.Insert(pos+1, thing) + +// Returns the next item in a list +/proc/next_list_item(var/item, var/list/L) + var/i + i = L.Find(item) + if(i == L.len) + i = 1 + else + i++ + return L[i] + +// Returns the previous item in a list +/proc/previous_list_item(var/item, var/list/L) + var/i + i = L.Find(item) + if(i == 1) + i = L.len + else + i-- + return L[i] /* * Sorting @@ -165,6 +189,7 @@ proc/listclearnulls(list/list) L.Swap(i,rand(1,L.len)) return L + //Return a list with no duplicate entries /proc/uniquelist(var/list/L) var/list/K = list() @@ -184,39 +209,12 @@ proc/listclearnulls(list/list) //any value in a list /proc/sortList(var/list/L, cmp=/proc/cmp_text_asc) - if(!istype(L)) - return return sortTim(L.Copy(), cmp) //uses sortList() but uses the var's name specifically. This should probably be using mergeAtom() instead /proc/sortNames(var/list/L, order=1) return sortTim(L, order >= 0 ? /proc/cmp_name_asc : /proc/cmp_name_dsc) -//Mergesort: divides up the list into halves to begin the sort -/proc/sortAtom(var/list/atom/L, var/order = 1) - if(isnull(L) || L.len < 2) - return L - var/middle = L.len / 2 + 1 - return mergeAtoms(sortAtom(L.Copy(0,middle)), sortAtom(L.Copy(middle)), order) - -//Mergsort: does the actual sorting and returns the results back to sortAtom -/proc/mergeAtoms(var/list/atom/L, var/list/atom/R, var/order = 1) - var/Li=1 - var/Ri=1 - ASSERT(L) - ASSERT(R) - var/list/result = new() - while(Li <= L.len && Ri <= R.len) - var/atom/rL = L[Li] - var/atom/rR = R[Ri] - if(sorttext(rL.name, rR.name) == order) - result += L[Li++] - else - result += R[Ri++] - - if(Li <= L.len) - return (result + L.Copy(Li, 0)) - return (result + R.Copy(Ri, 0)) //Converts a bitfield to a list of numbers (or words if a wordlist is provided) /proc/bitfield2list(bitfield = 0, list/wordlist) @@ -251,104 +249,38 @@ proc/listclearnulls(list/list) i++ return i -//Don't use this on lists larger than half a dozen or so -/proc/insertion_sort_numeric_list_ascending(var/list/L) - //world.log << "ascending len input: [L.len]" - var/list/out = list(pop(L)) - for(var/entry in L) - if(isnum(entry)) - var/success = 0 - for(var/i=1, i<=out.len, i++) - if(entry <= out[i]) - success = 1 - out.Insert(i, entry) - break - if(!success) - out.Add(entry) - - //world.log << " output: [out.len]" - return out - -/proc/insertion_sort_numeric_list_descending(var/list/L) - //world.log << "descending len input: [L.len]" - var/list/out = insertion_sort_numeric_list_ascending(L) - //world.log << " output: [out.len]" - return reverseRange(out) - -// List of lists, sorts by element[key] - for things like crew monitoring computer sorting records by name. -/proc/sortByKey(var/list/L, var/key) - if(L.len < 2) - return L - var/middle = L.len / 2 + 1 - return mergeKeyedLists(sortByKey(L.Copy(0, middle), key), sortByKey(L.Copy(middle), key), key) - -/proc/mergeKeyedLists(var/list/L, var/list/R, var/key) - var/Li=1 - var/Ri=1 - var/list/result = new() - while(Li <= L.len && Ri <= R.len) - if(sorttext(L[Li][key], R[Ri][key]) < 1) - // Works around list += list2 merging lists; it's not pretty but it works - result += "temp item" - result[result.len] = R[Ri++] - else - result += "temp item" - result[result.len] = L[Li++] - - if(Li <= L.len) - return (result + L.Copy(Li, 0)) - return (result + R.Copy(Ri, 0)) - - -//Mergesort: any value in a list, preserves key=value structure -/proc/sortAssoc(var/list/L) - if(L.len < 2) - return L - var/middle = L.len / 2 + 1 // Copy is first,second-1 - return mergeAssoc(sortAssoc(L.Copy(0,middle)), sortAssoc(L.Copy(middle))) //second parameter null = to end of list - -/proc/mergeAssoc(var/list/L, var/list/R) - var/Li=1 - var/Ri=1 - var/list/result = new() - while(Li <= L.len && Ri <= R.len) - if(sorttext(L[Li], R[Ri]) < 1) - result += R&R[Ri++] - else - result += L&L[Li++] - - if(Li <= L.len) - return (result + L.Copy(Li, 0)) - return (result + R.Copy(Ri, 0)) - /proc/find_record(field, value, list/L) for(var/datum/data/record/R in L) if(R.fields[field] == value) return R + //Move a single element from position fromIndex within a list, to position toIndex +//All elements in the range [1,toIndex) before the move will be before the pivot afterwards +//All elements in the range [toIndex, L.len+1) before the move will be after the pivot afterwards +//In other words, it's as if the range [fromIndex,toIndex) have been rotated using a <<< operation common to other languages. +//fromIndex and toIndex must be in the range [1,L.len+1] //This will preserve associations ~Carnie /proc/moveElement(list/L, fromIndex, toIndex) + if(fromIndex == toIndex || fromIndex+1 == toIndex) //no need to move + return if(fromIndex > toIndex) - ++fromIndex - else - ++toIndex + ++fromIndex //since a null will be inserted before fromIndex, the index needs to be nudged right by one L.Insert(toIndex, null) L.Swap(fromIndex, toIndex) L.Cut(fromIndex, fromIndex+1) -//Move elements [fromIndex,fromIndex+len) to [toIndex,toIndex+len) -//This will preserve associations and is much faster than copying to a new list -//or checking for associative lists and manually copying elements ~Carnie +//Move elements [fromIndex,fromIndex+len) to [toIndex-len, toIndex) +//Same as moveElement but for ranges of elements +//This will preserve associations ~Carnie /proc/moveRange(list/L, fromIndex, toIndex, len=1) var/distance = abs(toIndex - fromIndex) - if(len > distance) //there are more elements to be moved than the distance to be moved. Therefore the same result can be achieved (with fewer operations) by moving elements between where we are and where we are going - if(fromIndex < toIndex) - toIndex += len - else - fromIndex += len + if(len >= distance) //there are more elements to be moved than the distance to be moved. Therefore the same result can be achieved (with fewer operations) by moving elements between where we are and where we are going. The result being, our range we are moving is shifted left or right by dist elements + if(fromIndex <= toIndex) + return //no need to move + fromIndex += len //we want to shift left instead of right for(var/i=0, i toIndex) fromIndex += len - else - toIndex += len //? for(var/i=0, i (toIndex)){L.Insert((toIndex), null);L.Swap((fromIndex)+1, (toIndex));L.Cut((fromIndex)+1, (fromIndex)+2);}else{L.Insert((toIndex)+1, null);L.Swap((fromIndex), (toIndex)+1);L.Cut((fromIndex), (fromIndex)+1);} #define fetchElement(L, i) (associative) ? L[L[i]] : L[i] //Minimum sized sequence that will be merged. Anything smaller than this will use binary-insertion sort. @@ -34,8 +33,8 @@ var/datum/sortInstance/sortInstance = new() proc/timSort(start, end) - runBases.len = 0 - runLens.len = 0 + runBases.Cut() + runLens.Cut() var/remaining = end - start @@ -115,7 +114,7 @@ var/datum/sortInstance/sortInstance = new() //in other words, find where the pivot element should go using bisection search while(left < right) var/mid = (left + right) >> 1 //round((left+right)/2) - if(call(cmp)(pivot, fetchElement(L,mid)) < 0) + if(call(cmp)(fetchElement(L,mid), pivot) > 0) right = mid else left = mid+1 @@ -372,23 +371,23 @@ var/datum/sortInstance/sortInstance = new() proc/mergeLo(base1, len1, base2, len2) //ASSERT(len1 > 0 && len2 > 0 && base1 + len1 == base2) + var/cursor1 = base1 + var/cursor2 = base2 + //degenerate cases if(len2 == 1) - moveElement(L, base2, base1) + moveElement(L, cursor2, cursor1) return if(len1 == 1) - moveElement(L, base1, base2+len2-1) + moveElement(L, cursor1, cursor2+len2) return //Move first element of second run - moveElement(L, base2, base1) //L[dest++] = L[cursor2++] + moveElement(L, cursor2++, cursor1++) --len2 - var/cursor1 = base1+1 - var/cursor2 = base2+1 - outer: while(1) var/count1 = 0 //# of times in a row that first run won @@ -399,9 +398,7 @@ var/datum/sortInstance/sortInstance = new() do //ASSERT(len1 > 1 && len2 > 0) if(call(cmp)(fetchElement(L,cursor2), fetchElement(L,cursor1)) < 0) - moveElement(L, cursor2, cursor1) - ++cursor2 - ++cursor1 + moveElement(L, cursor2++, cursor1++) --len2 ++count2 @@ -466,8 +463,7 @@ var/datum/sortInstance/sortInstance = new() if(len1 == 1) //ASSERT(len2 > 0) - - moveRange(L, cursor2, cursor1, len2) + moveElement(L, cursor1, cursor2+len2) //else //ASSERT(len2 == 0) @@ -477,22 +473,20 @@ var/datum/sortInstance/sortInstance = new() proc/mergeHi(base1, len1, base2, len2) //ASSERT(len1 > 0 && len2 > 0 && base1 + len1 == base2) + var/cursor1 = base1 + len1 - 1 //start at end of sublists + var/cursor2 = base2 + len2 - 1 + //degenerate cases if(len2 == 1) moveElement(L, base2, base1) return if(len1 == 1) - moveElement(L, base1, base2+len2-1) + moveElement(L, base1, cursor2+1) return - var/cursor1 = base1 + len1 - 1 - var/cursor2 = base2 + len2 - 1 - - moveElement(L, cursor1, cursor2) + moveElement(L, cursor1--, cursor2-- + 1) --len1 - --cursor1 - --cursor2 outer: while(1) @@ -503,10 +497,7 @@ var/datum/sortInstance/sortInstance = new() do //ASSERT(len1 > 0 && len2 > 1) if(call(cmp)(fetchElement(L,cursor2), fetchElement(L,cursor1)) < 0) - moveElement(L, cursor1, cursor2) - - --cursor1 - --cursor2 + moveElement(L, cursor1--, cursor2-- + 1) --len1 ++count1 @@ -533,11 +524,12 @@ var/datum/sortInstance/sortInstance = new() count1 = len1 - gallopRight(fetchElement(L,cursor2), base1, len1, len1-1) //should cursor1 be base1? if(count1) cursor1 -= count1 + + moveRange(L, cursor1+1, cursor2+1, count1) //cursor1+1 == cursor2 by definition + cursor2 -= count1 len1 -= count1 - moveRange(L, cursor1+1, cursor2+1, count1) - if(len1 == 0) break outer @@ -546,7 +538,7 @@ var/datum/sortInstance/sortInstance = new() if(--len2 == 1) break outer - count2 = len2 - gallopLeft(fetchElement(L,cursor1), base1+len1, len2, len2-1) + count2 = len2 - gallopLeft(fetchElement(L,cursor1), cursor1+1, len2, len2-1) if(count2) cursor2 -= count2 len2 -= count2 @@ -554,9 +546,7 @@ var/datum/sortInstance/sortInstance = new() if(len2 <= 1) break outer - moveElement(L, cursor1, cursor2) - --cursor1 - --cursor2 + moveElement(L, cursor1--, cursor2-- + 1) --len1 if(len1 == 0) @@ -573,7 +563,6 @@ var/datum/sortInstance/sortInstance = new() //ASSERT(len1 > 0) cursor1 -= len1 - cursor2 -= len1 moveRange(L, cursor1+1, cursor2+1, len1) //else @@ -664,5 +653,4 @@ var/datum/sortInstance/sortInstance = new() #undef MIN_GALLOP #undef MIN_MERGE -#undef moveElement #undef fetchElement \ No newline at end of file diff --git a/code/__HELPERS/type2type.dm b/code/__HELPERS/type2type.dm index eb2cb001165..c4287b51fb2 100644 --- a/code/__HELPERS/type2type.dm +++ b/code/__HELPERS/type2type.dm @@ -69,7 +69,7 @@ . = "[ls[++i]]" // Make sure the initial element is converted to text. if(l-1 & 0x01) // 'i' will always be 1 here. - . += S1 // Append 1 element if the remaining elements are not a multiple of 2. + . += "[S1]" // Append 1 element if the remaining elements are not a multiple of 2. if(l-i & 0x02) . = text("[][][]", ., S1, S1) // Append 2 elements if the remaining elements are not a multiple of 4. if(l-i & 0x04) diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm index 08e9d576e37..38eebce1a02 100644 --- a/code/__HELPERS/unsorted.dm +++ b/code/__HELPERS/unsorted.dm @@ -424,7 +424,7 @@ Turf and target are seperate in case you want to teleport some distance from a t //Orders mobs by type then by name /proc/sortmobs() var/list/moblist = list() - var/list/sortmob = sortAtom(mob_list) + var/list/sortmob = sortNames(mob_list) for(var/mob/living/silicon/ai/M in sortmob) moblist.Add(M) for(var/mob/camera/M in sortmob) @@ -767,16 +767,21 @@ proc/anim(turf/location as turf,target as mob|obj,a_icon,a_icon_state as text,fl if(A.vars.Find(lowertext(varname))) return 1 else return 0 -//Returns: all the areas in the world -/proc/return_areas() - var/list/area/areas = list() +//Returns sortedAreas list if populated +//else populates the list first before returning it +/proc/SortAreas() for(var/area/A in world) - areas += A - return areas + if(A.lighting_subarea) + continue + sortedAreas.Add(A) -//Returns: all the areas in the world, sorted. -/proc/return_sorted_areas() - return sortNames(return_areas()) + sortTim(sortedAreas, /proc/cmp_name_asc) + + + +/area/proc/addSorted() + sortedAreas.Add(src) + sortTim(sortedAreas, /proc/cmp_name_asc) //Takes: Area type as text string or as typepath OR an instance of the area. //Returns: A list of all areas of that type in the world. @@ -1456,4 +1461,4 @@ proc/rotate_icon(file, state, step = 1, aa = FALSE) /proc/has_edge(obj/O as obj) if (!O) return 0 if(O.edge) return 1 - return 0 \ No newline at end of file + return 0 diff --git a/code/defines/obj.dm b/code/defines/obj.dm index 29724b9c183..b564a10d051 100644 --- a/code/defines/obj.dm +++ b/code/defines/obj.dm @@ -72,7 +72,7 @@ "} var/even = 0 // sort mobs - for(var/datum/data/record/t in data_core.general) + for(var/datum/data/record/t in sortRecord(data_core.general)) var/name = t.fields["name"] var/rank = t.fields["rank"] var/real_rank = t.fields["real_rank"] diff --git a/code/game/area/Space Station 13 areas.dm b/code/game/area/Space Station 13 areas.dm index 59e0d77431e..2fa25240236 100755 --- a/code/game/area/Space Station 13 areas.dm +++ b/code/game/area/Space Station 13 areas.dm @@ -79,26 +79,12 @@ proc/process_teleport_locs() for(var/area/AR in world) if(istype(AR, /area/shuttle) || istype(AR, /area/syndicate_station) || istype(AR, /area/wizard_station)) continue if(teleportlocs.Find(AR.name)) continue - var/list/turfss = get_area_turfs(AR.type) - if(!istype(turfss) || !turfss.len) - //warning("Area [AR] had no turfs!") - continue - //testing("Picking a turf from [AR]/([AR.type]) turfs length [turfss.len]") - var/turf/picked = pick(get_area_turfs(AR.type)) - if (picked.z == 1) + var/turf/picked = safepick(get_area_turfs(AR.type)) + if (picked && picked.z == 1) teleportlocs += AR.name teleportlocs[AR.name] = AR - var/not_in_order = 0 - do - not_in_order = 0 - if(teleportlocs.len <= 1) - break - for(var/i = 1, i <= (teleportlocs.len - 1), i++) - if(sorttext(teleportlocs[i], teleportlocs[i+1]) == -1) - teleportlocs.Swap(i, i+1) - not_in_order = 1 - while(not_in_order) + sortTim(teleportlocs, /proc/cmp_text_dsc) var/list/ghostteleportlocs = list() @@ -108,45 +94,24 @@ proc/process_ghost_teleport_locs() if(istype(AR, /area/turret_protected/aisat) || istype(AR, /area/derelict) || istype(AR, /area/tdome)) ghostteleportlocs += AR.name ghostteleportlocs[AR.name] = AR - var/list/turfss = get_area_turfs(AR.type) - if(!istype(turfss) || !turfss.len) - //warning("Area [AR] had no turfs!") - continue - //testing("Picking a turf from [AR]/([AR.type]) turfs length [turfss.len]") - var/turf/picked = pick(get_area_turfs(AR.type)) - if (picked.z == 1 || picked.z == 5 || picked.z == 3) + var/turf/picked = safepick(get_area_turfs(AR.type)) + if (picked && (picked.z == 1 || picked.z == 5 || picked.z == 3)) ghostteleportlocs += AR.name ghostteleportlocs[AR.name] = AR - var/not_in_order = 0 - do - not_in_order = 0 - if(ghostteleportlocs.len <= 1) - break - for(var/i = 1, i <= (ghostteleportlocs.len - 1), i++) - if(sorttext(ghostteleportlocs[i], ghostteleportlocs[i+1]) == -1) - ghostteleportlocs.Swap(i, i+1) - not_in_order = 1 - while(not_in_order) + sortTim(ghostteleportlocs, /proc/cmp_text_dsc) var/global/list/adminbusteleportlocs = list() proc/process_adminbus_teleport_locs() for(var/area/AR in world) if(adminbusteleportlocs.Find(AR.name)) continue - adminbusteleportlocs += AR.name - adminbusteleportlocs[AR.name] = AR + var/turf/picked = safepick(get_area_turfs(AR.type)) + if (picked) + adminbusteleportlocs += AR.name + adminbusteleportlocs[AR.name] = AR - var/not_in_order = 0 - do - not_in_order = 0 - if(adminbusteleportlocs.len <= 1) - break - for(var/i = 1, i <= (adminbusteleportlocs.len - 1), i++) - if(sorttext(adminbusteleportlocs[i], adminbusteleportlocs[i+1]) == -1) - adminbusteleportlocs.Swap(i, i+1) - not_in_order = 1 - while(not_in_order) + sortTim(adminbusteleportlocs, /proc/cmp_text_dsc) /*-----------------------------------------------------------------------------*/ diff --git a/code/game/machinery/computer/crew.dm b/code/game/machinery/computer/crew.dm index 3ac8dd96d2c..9a27690db6c 100644 --- a/code/game/machinery/computer/crew.dm +++ b/code/game/machinery/computer/crew.dm @@ -117,7 +117,7 @@ //crewmembers += "temporary item" //crewmembers[crewmembers.len] = crewmemberData - crewmembers = sortByKey(crewmembers, "name") + crewmembers = sortList(crewmembers) data["crewmembers"] = crewmembers diff --git a/code/game/machinery/kitchen/smartfridge.dm b/code/game/machinery/kitchen/smartfridge.dm index edc3c44bdb5..a1ec4a15f6e 100644 --- a/code/game/machinery/kitchen/smartfridge.dm +++ b/code/game/machinery/kitchen/smartfridge.dm @@ -265,7 +265,7 @@ else user << "\The [src] smartly refuses [O]." return 1 - + sortList(item_quants) updateUsrDialog() /obj/machinery/smartfridge/attack_paw(mob/user as mob) diff --git a/code/game/objects/items/blueprints.dm b/code/game/objects/items/blueprints.dm index 522affb3ad4..95df4698521 100644 --- a/code/game/objects/items/blueprints.dm +++ b/code/game/objects/items/blueprints.dm @@ -132,6 +132,7 @@ move an amendment to the drawing.

A.power_environ = 0 A.always_unpowered = 0 A.SetDynamicLighting() + A.addSorted() spawn() move_turfs_to_area(turfs, A) A.always_unpowered = 0 diff --git a/code/game/objects/items/devices/handtv.dm b/code/game/objects/items/devices/handtv.dm index eb0a79593a2..b11091bb7b6 100644 --- a/code/game/objects/items/devices/handtv.dm +++ b/code/game/objects/items/devices/handtv.dm @@ -21,7 +21,7 @@ var/global/list/camera_bugs = list() for (var/obj/item/device/camera_bug/C in cameras) friendly_cameras.Add(C.c_tag) - var/target = input("Select the camera to observe", null) as null|anything in friendly_cameras + var/target = input("Select the camera to observe", null) as null|anything in sortList(friendly_cameras) if (!target) user.unset_machine() user.reset_view(user) diff --git a/code/global.dm b/code/global.dm index 2aa167806b3..11620b4da17 100644 --- a/code/global.dm +++ b/code/global.dm @@ -367,4 +367,7 @@ var/global/list/plugins = list() var/global/datum/gas_mixture/space_gas = new //Announcement intercom -var/obj/item/device/radio/intercom/announcement_intercom = new(null) \ No newline at end of file +var/obj/item/device/radio/intercom/announcement_intercom = new(null) + +//used by jump-to-area etc. Updated by area/updateName() +var/list/sortedAreas = list() \ No newline at end of file diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index 1d3fb2d4b9d..2457ade9e22 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -247,6 +247,7 @@ var/list/admin_verbs_hideable = list( /client/proc/cmd_debug_tog_aliens, /client/proc/air_report, /client/proc/enable_debug_verbs, + /client/proc/mob_list() /proc/possess, /proc/release ) diff --git a/code/modules/admin/verbs/adminjump.dm b/code/modules/admin/verbs/adminjump.dm index 0a28ebc25a6..e7ee90d5da4 100644 --- a/code/modules/admin/verbs/adminjump.dm +++ b/code/modules/admin/verbs/adminjump.dm @@ -1,4 +1,4 @@ -/client/proc/Jump(var/area/A in return_sorted_areas()) +/client/proc/Jump(var/area/A in sortedAreas) set name = "Jump to Area" set desc = "Area to jump to" set category = "Admin" @@ -7,10 +7,21 @@ return if(config.allow_admin_jump) - var/list/L = get_area_turfs(A) - if(!L || !L.len) + if(!A) return - usr.loc = pick(get_area_turfs(A)) + + var/list/turfs = list() + for(var/area/Ar in A.related) + for(var/turf/T in Ar) + if(T.density) + continue + turfs.Add(T) + + var/turf/T = pick_n_take(turfs) + if(!T) + src << "Nowhere to jump to!" + return + usr.loc = T log_admin("[key_name(usr)] jumped to [A]") message_admins("[key_name_admin(usr)] jumped to [A]", 1) @@ -148,7 +159,7 @@ if(!src.holder) src << "Only administrators may use this command." return - var/area/A = input(usr, "Pick an area.", "Pick an area") in return_sorted_areas() + var/area/A = input(usr, "Pick an area.", "Pick an area") in sortedAreas if(A) if(config.allow_admin_jump) M.loc = pick(get_area_turfs(A)) diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm index 5503d39c219..eae7484c0dc 100644 --- a/code/modules/admin/verbs/debug.dm +++ b/code/modules/admin/verbs/debug.dm @@ -1258,3 +1258,20 @@ client/proc/delete_all_adminbus() for(var/obj/structure/stool/bed/chair/vehicle/adminbus/AB in world) AB.Adminbus_Deletion() + +client/proc/mob_list() + set name = "show mob list" + set category = "Debug" + if(!holder) return + usr << "mob list length is [mob_list.len]" + var/foundnull = 0 + for(var/mob/V in mob_list) + var/msg = "mob ([V]) is in slot [mob_list.Find(V)]" + if(!ismob(V)) + if(isnull(V)) + foundnull++ + msg = "Non mob found in mob list [isnull(V) ? "null entry found at mob_list.Find(V)" : "[V]'s type is [V.type]"]" + usr << msg + if(foundnull) + usr << "Found [foundnull] null entries in the mob list, running null clearer." + listclearnulls(mob_list) \ No newline at end of file diff --git a/code/modules/reagents/Chemistry-Machinery.dm b/code/modules/reagents/Chemistry-Machinery.dm index f7b904f3b93..c9209503a40 100644 --- a/code/modules/reagents/Chemistry-Machinery.dm +++ b/code/modules/reagents/Chemistry-Machinery.dm @@ -51,6 +51,7 @@ USE THIS CHEMISTRY DISPENSER FOR MAPS SO THEY START AT 100 ENERGY ) RefreshParts() + dispensable_reagents = sortList(dispensable_reagents) /obj/machinery/chem_dispenser/RefreshParts() var/T = 0 diff --git a/code/world.dm b/code/world.dm index d16d950d7e0..736512d06d5 100644 --- a/code/world.dm +++ b/code/world.dm @@ -128,9 +128,10 @@ plugins[P.name] = P P.on_world_loaded() - process_teleport_locs() //Sets up the wizard teleport locations - process_ghost_teleport_locs() //Sets up ghost teleport locations. + process_teleport_locs() //Sets up the wizard teleport locations + process_ghost_teleport_locs() //Sets up ghost teleport locations. process_adminbus_teleport_locs() //Sets up adminbus teleport locations. + SortAreas() //Build the list of all existing areas and sort it alphabetically spawn(3000) //so we aren't adding to the round-start lag if(config.ToRban)