Up to date timesort to resolve list issues.

This commit is contained in:
D3athrow
2015-02-05 17:44:48 -06:00
parent fe3866f28c
commit e3746f7547
16 changed files with 169 additions and 246 deletions

View File

@@ -31,29 +31,28 @@
return "[output][and_text][input[index]]" return "[output][and_text][input[index]]"
//Returns list element or null. Should prevent "index out of bounds" error. //Returns list element or null. Should prevent "index out of bounds" error.
proc/listgetindex(var/list/list,index) /proc/listgetindex(list/L, index)
if(istype(list) && list.len) if(istype(L))
if(isnum(index)) if(isnum(index))
if(IsInRange(index,1,list.len)) if(IsInRange(index,1,L.len))
return list[index] return L[index]
else if(index in list) else if(index in L)
return list[index] return L[index]
return return
proc/islist(list/list) /proc/islist(list/L)
if(istype(list)) if(istype(L))
return 1 return 1
return 0 return 0
//Return either pick(list) or null if list is not of type /list or is empty //Return either pick(list) or null if list is not of type /list or is empty
proc/safepick(list/list) /proc/safepick(list/L)
if(!islist(list) || !list.len) if(istype(L) && L.len)
return return pick(L)
return pick(list)
//Checks if the list is empty //Checks if the list is empty
proc/isemptylist(list/list) /proc/isemptylist(list/L)
if(!list.len) if(!L.len)
return 1 return 1
return 0 return 0
@@ -65,17 +64,20 @@ proc/isemptylist(list/list)
return 0 return 0
//Empties the list by setting the length to 0. Hopefully the elements get garbage collected //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)) if(istype(list))
list.len = 0 list.len = 0
return return
//Removes any null entries from the list //Removes any null entries from the list
proc/listclearnulls(list/list) /proc/listclearnulls(list/L)
if(istype(list)) if(istype(L))
while(null in list) var/i=1
list -= null for(var/thing in L)
return 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. * 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 return null
//Pick a random element from the list and remove it from the list. //Pick a random element from the list and remove it from the list.
/proc/pick_n_take(list/listfrom) /proc/pick_n_take(list/L)
if (listfrom.len > 0) if(L.len)
var/picked = pick(listfrom) var/picked = rand(1,L.len)
listfrom -= picked . = L[picked]
return picked L.Cut(picked,picked+1) //Cut is far more efficient that Remove()
return null
//Returns the top(last) element from the list and removes it from the list (typical stack function) //Returns the top(last) element from the list and removes it from the list (typical stack function)
/proc/pop(list/listfrom) /proc/pop(list/L)
if (listfrom.len > 0) if(L.len)
var/picked = listfrom[listfrom.len] . = L[L.len]
listfrom.len-- L.len--
return picked
return null
/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 * Sorting
@@ -165,6 +189,7 @@ proc/listclearnulls(list/list)
L.Swap(i,rand(1,L.len)) L.Swap(i,rand(1,L.len))
return L return L
//Return a list with no duplicate entries //Return a list with no duplicate entries
/proc/uniquelist(var/list/L) /proc/uniquelist(var/list/L)
var/list/K = list() var/list/K = list()
@@ -184,39 +209,12 @@ proc/listclearnulls(list/list)
//any value in a list //any value in a list
/proc/sortList(var/list/L, cmp=/proc/cmp_text_asc) /proc/sortList(var/list/L, cmp=/proc/cmp_text_asc)
if(!istype(L))
return
return sortTim(L.Copy(), cmp) return sortTim(L.Copy(), cmp)
//uses sortList() but uses the var's name specifically. This should probably be using mergeAtom() instead //uses sortList() but uses the var's name specifically. This should probably be using mergeAtom() instead
/proc/sortNames(var/list/L, order=1) /proc/sortNames(var/list/L, order=1)
return sortTim(L, order >= 0 ? /proc/cmp_name_asc : /proc/cmp_name_dsc) 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) //Converts a bitfield to a list of numbers (or words if a wordlist is provided)
/proc/bitfield2list(bitfield = 0, list/wordlist) /proc/bitfield2list(bitfield = 0, list/wordlist)
@@ -251,104 +249,38 @@ proc/listclearnulls(list/list)
i++ i++
return 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) /proc/find_record(field, value, list/L)
for(var/datum/data/record/R in L) for(var/datum/data/record/R in L)
if(R.fields[field] == value) if(R.fields[field] == value)
return R return R
//Move a single element from position fromIndex within a list, to position toIndex //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 //This will preserve associations ~Carnie
/proc/moveElement(list/L, fromIndex, toIndex) /proc/moveElement(list/L, fromIndex, toIndex)
if(fromIndex == toIndex || fromIndex+1 == toIndex) //no need to move
return
if(fromIndex > toIndex) if(fromIndex > toIndex)
++fromIndex ++fromIndex //since a null will be inserted before fromIndex, the index needs to be nudged right by one
else
++toIndex
L.Insert(toIndex, null) L.Insert(toIndex, null)
L.Swap(fromIndex, toIndex) L.Swap(fromIndex, toIndex)
L.Cut(fromIndex, fromIndex+1) L.Cut(fromIndex, fromIndex+1)
//Move elements [fromIndex,fromIndex+len) to [toIndex,toIndex+len) //Move elements [fromIndex,fromIndex+len) to [toIndex-len, toIndex)
//This will preserve associations and is much faster than copying to a new list //Same as moveElement but for ranges of elements
//or checking for associative lists and manually copying elements ~Carnie //This will preserve associations ~Carnie
/proc/moveRange(list/L, fromIndex, toIndex, len=1) /proc/moveRange(list/L, fromIndex, toIndex, len=1)
var/distance = abs(toIndex - fromIndex) 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(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) if(fromIndex <= toIndex)
toIndex += len return //no need to move
else fromIndex += len //we want to shift left instead of right
fromIndex += len
for(var/i=0, i<distance, ++i) for(var/i=0, i<distance, ++i)
L.Insert(fromIndex, null) L.Insert(fromIndex, null)
@@ -357,8 +289,6 @@ proc/listclearnulls(list/list)
else else
if(fromIndex > toIndex) if(fromIndex > toIndex)
fromIndex += len fromIndex += len
else
toIndex += len //?
for(var/i=0, i<len, ++i) for(var/i=0, i<len, ++i)
L.Insert(toIndex, null) L.Insert(toIndex, null)

View File

@@ -1,5 +1,4 @@
//These are macros used to reduce on proc calls //These are macros used to reduce on proc calls
#define moveElement(L, fromIndex, toIndex) if((fromIndex) > (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] #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. //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) proc/timSort(start, end)
runBases.len = 0 runBases.Cut()
runLens.len = 0 runLens.Cut()
var/remaining = end - start 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 //in other words, find where the pivot element should go using bisection search
while(left < right) while(left < right)
var/mid = (left + right) >> 1 //round((left+right)/2) 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 right = mid
else else
left = mid+1 left = mid+1
@@ -372,23 +371,23 @@ var/datum/sortInstance/sortInstance = new()
proc/mergeLo(base1, len1, base2, len2) proc/mergeLo(base1, len1, base2, len2)
//ASSERT(len1 > 0 && len2 > 0 && base1 + len1 == base2) //ASSERT(len1 > 0 && len2 > 0 && base1 + len1 == base2)
var/cursor1 = base1
var/cursor2 = base2
//degenerate cases //degenerate cases
if(len2 == 1) if(len2 == 1)
moveElement(L, base2, base1) moveElement(L, cursor2, cursor1)
return return
if(len1 == 1) if(len1 == 1)
moveElement(L, base1, base2+len2-1) moveElement(L, cursor1, cursor2+len2)
return return
//Move first element of second run //Move first element of second run
moveElement(L, base2, base1) //L[dest++] = L[cursor2++] moveElement(L, cursor2++, cursor1++)
--len2 --len2
var/cursor1 = base1+1
var/cursor2 = base2+1
outer: outer:
while(1) while(1)
var/count1 = 0 //# of times in a row that first run won var/count1 = 0 //# of times in a row that first run won
@@ -399,9 +398,7 @@ var/datum/sortInstance/sortInstance = new()
do do
//ASSERT(len1 > 1 && len2 > 0) //ASSERT(len1 > 1 && len2 > 0)
if(call(cmp)(fetchElement(L,cursor2), fetchElement(L,cursor1)) < 0) if(call(cmp)(fetchElement(L,cursor2), fetchElement(L,cursor1)) < 0)
moveElement(L, cursor2, cursor1) moveElement(L, cursor2++, cursor1++)
++cursor2
++cursor1
--len2 --len2
++count2 ++count2
@@ -466,8 +463,7 @@ var/datum/sortInstance/sortInstance = new()
if(len1 == 1) if(len1 == 1)
//ASSERT(len2 > 0) //ASSERT(len2 > 0)
moveElement(L, cursor1, cursor2+len2)
moveRange(L, cursor2, cursor1, len2)
//else //else
//ASSERT(len2 == 0) //ASSERT(len2 == 0)
@@ -477,22 +473,20 @@ var/datum/sortInstance/sortInstance = new()
proc/mergeHi(base1, len1, base2, len2) proc/mergeHi(base1, len1, base2, len2)
//ASSERT(len1 > 0 && len2 > 0 && base1 + len1 == base2) //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 //degenerate cases
if(len2 == 1) if(len2 == 1)
moveElement(L, base2, base1) moveElement(L, base2, base1)
return return
if(len1 == 1) if(len1 == 1)
moveElement(L, base1, base2+len2-1) moveElement(L, base1, cursor2+1)
return return
var/cursor1 = base1 + len1 - 1 moveElement(L, cursor1--, cursor2-- + 1)
var/cursor2 = base2 + len2 - 1
moveElement(L, cursor1, cursor2)
--len1 --len1
--cursor1
--cursor2
outer: outer:
while(1) while(1)
@@ -503,10 +497,7 @@ var/datum/sortInstance/sortInstance = new()
do do
//ASSERT(len1 > 0 && len2 > 1) //ASSERT(len1 > 0 && len2 > 1)
if(call(cmp)(fetchElement(L,cursor2), fetchElement(L,cursor1)) < 0) if(call(cmp)(fetchElement(L,cursor2), fetchElement(L,cursor1)) < 0)
moveElement(L, cursor1, cursor2) moveElement(L, cursor1--, cursor2-- + 1)
--cursor1
--cursor2
--len1 --len1
++count1 ++count1
@@ -533,11 +524,12 @@ var/datum/sortInstance/sortInstance = new()
count1 = len1 - gallopRight(fetchElement(L,cursor2), base1, len1, len1-1) //should cursor1 be base1? count1 = len1 - gallopRight(fetchElement(L,cursor2), base1, len1, len1-1) //should cursor1 be base1?
if(count1) if(count1)
cursor1 -= count1 cursor1 -= count1
moveRange(L, cursor1+1, cursor2+1, count1) //cursor1+1 == cursor2 by definition
cursor2 -= count1 cursor2 -= count1
len1 -= count1 len1 -= count1
moveRange(L, cursor1+1, cursor2+1, count1)
if(len1 == 0) if(len1 == 0)
break outer break outer
@@ -546,7 +538,7 @@ var/datum/sortInstance/sortInstance = new()
if(--len2 == 1) if(--len2 == 1)
break outer 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) if(count2)
cursor2 -= count2 cursor2 -= count2
len2 -= count2 len2 -= count2
@@ -554,9 +546,7 @@ var/datum/sortInstance/sortInstance = new()
if(len2 <= 1) if(len2 <= 1)
break outer break outer
moveElement(L, cursor1, cursor2) moveElement(L, cursor1--, cursor2-- + 1)
--cursor1
--cursor2
--len1 --len1
if(len1 == 0) if(len1 == 0)
@@ -573,7 +563,6 @@ var/datum/sortInstance/sortInstance = new()
//ASSERT(len1 > 0) //ASSERT(len1 > 0)
cursor1 -= len1 cursor1 -= len1
cursor2 -= len1
moveRange(L, cursor1+1, cursor2+1, len1) moveRange(L, cursor1+1, cursor2+1, len1)
//else //else
@@ -664,5 +653,4 @@ var/datum/sortInstance/sortInstance = new()
#undef MIN_GALLOP #undef MIN_GALLOP
#undef MIN_MERGE #undef MIN_MERGE
#undef moveElement
#undef fetchElement #undef fetchElement

View File

@@ -69,7 +69,7 @@
. = "[ls[++i]]" // Make sure the initial element is converted to text. . = "[ls[++i]]" // Make sure the initial element is converted to text.
if(l-1 & 0x01) // 'i' will always be 1 here. 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) if(l-i & 0x02)
. = text("[][][]", ., S1, S1) // Append 2 elements if the remaining elements are not a multiple of 4. . = text("[][][]", ., S1, S1) // Append 2 elements if the remaining elements are not a multiple of 4.
if(l-i & 0x04) if(l-i & 0x04)

View File

@@ -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 //Orders mobs by type then by name
/proc/sortmobs() /proc/sortmobs()
var/list/moblist = list() 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) for(var/mob/living/silicon/ai/M in sortmob)
moblist.Add(M) moblist.Add(M)
for(var/mob/camera/M in sortmob) 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 if(A.vars.Find(lowertext(varname))) return 1
else return 0 else return 0
//Returns: all the areas in the world //Returns sortedAreas list if populated
/proc/return_areas() //else populates the list first before returning it
var/list/area/areas = list() /proc/SortAreas()
for(var/area/A in world) for(var/area/A in world)
areas += A if(A.lighting_subarea)
return areas continue
sortedAreas.Add(A)
//Returns: all the areas in the world, sorted. sortTim(sortedAreas, /proc/cmp_name_asc)
/proc/return_sorted_areas()
return sortNames(return_areas())
/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. //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. //Returns: A list of all areas of that type in the world.

View File

@@ -72,7 +72,7 @@
"} "}
var/even = 0 var/even = 0
// sort mobs // 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/name = t.fields["name"]
var/rank = t.fields["rank"] var/rank = t.fields["rank"]
var/real_rank = t.fields["real_rank"] var/real_rank = t.fields["real_rank"]

View File

@@ -79,26 +79,12 @@ proc/process_teleport_locs()
for(var/area/AR in world) for(var/area/AR in world)
if(istype(AR, /area/shuttle) || istype(AR, /area/syndicate_station) || istype(AR, /area/wizard_station)) continue if(istype(AR, /area/shuttle) || istype(AR, /area/syndicate_station) || istype(AR, /area/wizard_station)) continue
if(teleportlocs.Find(AR.name)) continue if(teleportlocs.Find(AR.name)) continue
var/list/turfss = get_area_turfs(AR.type) var/turf/picked = safepick(get_area_turfs(AR.type))
if(!istype(turfss) || !turfss.len) if (picked && picked.z == 1)
//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)
teleportlocs += AR.name teleportlocs += AR.name
teleportlocs[AR.name] = AR teleportlocs[AR.name] = AR
var/not_in_order = 0 sortTim(teleportlocs, /proc/cmp_text_dsc)
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)
var/list/ghostteleportlocs = list() 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)) if(istype(AR, /area/turret_protected/aisat) || istype(AR, /area/derelict) || istype(AR, /area/tdome))
ghostteleportlocs += AR.name ghostteleportlocs += AR.name
ghostteleportlocs[AR.name] = AR ghostteleportlocs[AR.name] = AR
var/list/turfss = get_area_turfs(AR.type) var/turf/picked = safepick(get_area_turfs(AR.type))
if(!istype(turfss) || !turfss.len) if (picked && (picked.z == 1 || picked.z == 5 || picked.z == 3))
//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)
ghostteleportlocs += AR.name ghostteleportlocs += AR.name
ghostteleportlocs[AR.name] = AR ghostteleportlocs[AR.name] = AR
var/not_in_order = 0 sortTim(ghostteleportlocs, /proc/cmp_text_dsc)
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)
var/global/list/adminbusteleportlocs = list() var/global/list/adminbusteleportlocs = list()
proc/process_adminbus_teleport_locs() proc/process_adminbus_teleport_locs()
for(var/area/AR in world) for(var/area/AR in world)
if(adminbusteleportlocs.Find(AR.name)) continue if(adminbusteleportlocs.Find(AR.name)) continue
var/turf/picked = safepick(get_area_turfs(AR.type))
if (picked)
adminbusteleportlocs += AR.name adminbusteleportlocs += AR.name
adminbusteleportlocs[AR.name] = AR adminbusteleportlocs[AR.name] = AR
var/not_in_order = 0 sortTim(adminbusteleportlocs, /proc/cmp_text_dsc)
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)
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/

View File

@@ -117,7 +117,7 @@
//crewmembers += "temporary item" //crewmembers += "temporary item"
//crewmembers[crewmembers.len] = crewmemberData //crewmembers[crewmembers.len] = crewmemberData
crewmembers = sortByKey(crewmembers, "name") crewmembers = sortList(crewmembers)
data["crewmembers"] = crewmembers data["crewmembers"] = crewmembers

View File

@@ -265,7 +265,7 @@
else else
user << "<span class='notice'>\The [src] smartly refuses [O].</span>" user << "<span class='notice'>\The [src] smartly refuses [O].</span>"
return 1 return 1
sortList(item_quants)
updateUsrDialog() updateUsrDialog()
/obj/machinery/smartfridge/attack_paw(mob/user as mob) /obj/machinery/smartfridge/attack_paw(mob/user as mob)

View File

@@ -132,6 +132,7 @@ move an amendment</a> to the drawing.</p>
A.power_environ = 0 A.power_environ = 0
A.always_unpowered = 0 A.always_unpowered = 0
A.SetDynamicLighting() A.SetDynamicLighting()
A.addSorted()
spawn() move_turfs_to_area(turfs, A) spawn() move_turfs_to_area(turfs, A)
A.always_unpowered = 0 A.always_unpowered = 0

View File

@@ -21,7 +21,7 @@ var/global/list/camera_bugs = list()
for (var/obj/item/device/camera_bug/C in cameras) for (var/obj/item/device/camera_bug/C in cameras)
friendly_cameras.Add(C.c_tag) 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) if (!target)
user.unset_machine() user.unset_machine()
user.reset_view(user) user.reset_view(user)

View File

@@ -368,3 +368,6 @@ var/global/datum/gas_mixture/space_gas = new
//Announcement intercom //Announcement intercom
var/obj/item/device/radio/intercom/announcement_intercom = new(null) var/obj/item/device/radio/intercom/announcement_intercom = new(null)
//used by jump-to-area etc. Updated by area/updateName()
var/list/sortedAreas = list()

View File

@@ -247,6 +247,7 @@ var/list/admin_verbs_hideable = list(
/client/proc/cmd_debug_tog_aliens, /client/proc/cmd_debug_tog_aliens,
/client/proc/air_report, /client/proc/air_report,
/client/proc/enable_debug_verbs, /client/proc/enable_debug_verbs,
/client/proc/mob_list()
/proc/possess, /proc/possess,
/proc/release /proc/release
) )

View File

@@ -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 name = "Jump to Area"
set desc = "Area to jump to" set desc = "Area to jump to"
set category = "Admin" set category = "Admin"
@@ -7,10 +7,21 @@
return return
if(config.allow_admin_jump) if(config.allow_admin_jump)
var/list/L = get_area_turfs(A) if(!A)
if(!L || !L.len)
return 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]") log_admin("[key_name(usr)] jumped to [A]")
message_admins("[key_name_admin(usr)] jumped to [A]", 1) message_admins("[key_name_admin(usr)] jumped to [A]", 1)
@@ -148,7 +159,7 @@
if(!src.holder) if(!src.holder)
src << "Only administrators may use this command." src << "Only administrators may use this command."
return 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(A)
if(config.allow_admin_jump) if(config.allow_admin_jump)
M.loc = pick(get_area_turfs(A)) M.loc = pick(get_area_turfs(A))

View File

@@ -1258,3 +1258,20 @@ client/proc/delete_all_adminbus()
for(var/obj/structure/stool/bed/chair/vehicle/adminbus/AB in world) for(var/obj/structure/stool/bed/chair/vehicle/adminbus/AB in world)
AB.Adminbus_Deletion() 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)

View File

@@ -51,6 +51,7 @@ USE THIS CHEMISTRY DISPENSER FOR MAPS SO THEY START AT 100 ENERGY
) )
RefreshParts() RefreshParts()
dispensable_reagents = sortList(dispensable_reagents)
/obj/machinery/chem_dispenser/RefreshParts() /obj/machinery/chem_dispenser/RefreshParts()
var/T = 0 var/T = 0

View File

@@ -131,6 +131,7 @@
process_teleport_locs() //Sets up the wizard teleport locations process_teleport_locs() //Sets up the wizard teleport locations
process_ghost_teleport_locs() //Sets up ghost teleport locations. process_ghost_teleport_locs() //Sets up ghost teleport locations.
process_adminbus_teleport_locs() //Sets up adminbus 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 spawn(3000) //so we aren't adding to the round-start lag
if(config.ToRban) if(config.ToRban)