diff --git a/aurorastation.dme b/aurorastation.dme index 212639656ab..17a4a2a0c98 100644 --- a/aurorastation.dme +++ b/aurorastation.dme @@ -259,9 +259,9 @@ #include "code\__HELPERS\paths\jps.dm" #include "code\__HELPERS\paths\path.dm" #include "code\__HELPERS\paths\sssp.dm" -#include "code\__HELPERS\sorting\__main.dm" -#include "code\__HELPERS\sorting\cmp.dm" -#include "code\__HELPERS\sorting\TimSort.dm" +#include "code\__HELPERS\sorts\cmp.dm" +#include "code\__HELPERS\sorts\helpers.dm" +#include "code\__HELPERS\sorts\sort_instance.dm" #include "code\_globalvars\configuration.dm" #include "code\_globalvars\edible.dm" #include "code\_globalvars\logging.dm" diff --git a/code/__HELPERS/_lists.dm b/code/__HELPERS/_lists.dm index 166460940b0..1a33d1e43b0 100644 --- a/code/__HELPERS/_lists.dm +++ b/code/__HELPERS/_lists.dm @@ -258,6 +258,74 @@ return null +/** + * Move a single element from position from_index within a list, to position to_index + * All elements in the range [1,to_index) before the move will be before the pivot afterwards + * All elements in the range [to_index, L.len+1) before the move will be after the pivot afterwards + * In other words, it's as if the range [from_index,to_index) have been rotated using a <<< operation common to other languages. + * from_index and to_index must be in the range [1,L.len+1] + * This will preserve associations ~Carnie +**/ +/proc/move_element(list/inserted_list, from_index, to_index) + if(from_index == to_index || from_index + 1 == to_index) //no need to move + return + if(from_index > to_index) + ++from_index //since a null will be inserted before from_index, the index needs to be nudged right by one + + inserted_list.Insert(to_index, null) + inserted_list.Swap(from_index, to_index) + inserted_list.Cut(from_index, from_index + 1) + + +/** + * Move elements [from_index,from_index+len) to [to_index-len, to_index) + * Same as moveElement but for ranges of elements + * This will preserve associations ~Carnie +**/ +/proc/move_range(list/inserted_list, from_index, to_index, len = 1) + var/distance = abs(to_index - from_index) + 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(from_index <= to_index) + return //no need to move + from_index += len //we want to shift left instead of right + + for(var/i in 1 to distance) + inserted_list.Insert(from_index, null) + inserted_list.Swap(from_index, to_index) + inserted_list.Cut(to_index, to_index + 1) + else + if(from_index > to_index) + from_index += len + + for(var/i in 1 to len) + inserted_list.Insert(to_index, null) + inserted_list.Swap(from_index, to_index) + inserted_list.Cut(from_index, from_index + 1) + +///Move elements from [from_index, from_index+len) to [to_index, to_index+len) +///Move any elements being overwritten by the move to the now-empty elements, preserving order +///Note: if the two ranges overlap, only the destination order will be preserved fully, since some elements will be within both ranges ~Carnie +/proc/swap_range(list/inserted_list, from_index, to_index, len=1) + var/distance = abs(to_index - from_index) + if(len > distance) //there is an overlap, therefore swapping each element will require more swaps than inserting new elements + if(from_index < to_index) + to_index += len + else + from_index += len + + for(var/i in 1 to distance) + inserted_list.Insert(from_index, null) + inserted_list.Swap(from_index, to_index) + inserted_list.Cut(to_index, to_index + 1) + else + if(to_index > from_index) + var/temp = to_index + to_index = from_index + from_index = temp + + for(var/i in 1 to len) + inserted_list.Swap(from_index++, to_index++) + ///replaces reverseList ~Carnie /proc/reverse_range(list/inserted_list, start = 1, end = 0) if(inserted_list.len) diff --git a/code/__HELPERS/areas.dm b/code/__HELPERS/areas.dm index e3c4ea38fcc..162abd045f3 100644 --- a/code/__HELPERS/areas.dm +++ b/code/__HELPERS/areas.dm @@ -105,3 +105,15 @@ /proc/is_not_maint_area(var/area/A) . = !is_maint_area(A) + +/* + Area Sorting +*/ +/proc/require_area_resort() + GLOB.sortedAreas = null + +/// Returns a sorted version of GLOB.areas, by name +/proc/get_sorted_areas() + if(!GLOB.sortedAreas) + GLOB.sortedAreas = sortTim(GLOB.areas.Copy(), /proc/cmp_name_asc) + return GLOB.sortedAreas diff --git a/code/__HELPERS/game.dm b/code/__HELPERS/game.dm index 8a01da3a0ed..890ea77bb5c 100644 --- a/code/__HELPERS/game.dm +++ b/code/__HELPERS/game.dm @@ -11,7 +11,7 @@ return max_z /proc/get_area_name(N) //get area by its name - for(var/area/A in GLOB.all_areas) + for(var/area/A in get_sorted_areas()) if(A.name == N) return A return 0 diff --git a/code/__HELPERS/global_lists.dm b/code/__HELPERS/global_lists.dm index 0d3dceb1900..7cd6f3443cf 100644 --- a/code/__HELPERS/global_lists.dm +++ b/code/__HELPERS/global_lists.dm @@ -48,10 +48,8 @@ GLOBAL_LIST_EMPTY(implants) /// Turf is added to this list if is_station_level() passes when it's initialized. GLOBAL_LIST_EMPTY(station_turfs) -/// List of all instanced areas by type. +/// List of all instanced areas by type. THIS IS DIFFERENT FROM TG AS IT DOES NOT ONLY CONTAIN UNIQUE AREAS. GLOBAL_LIST_EMPTY(areas_by_type) -/// List of all instanced areas. -GLOBAL_LIST_EMPTY(all_areas) /// Languages/species/whitelist. GLOBAL_LIST_EMPTY_TYPED(all_species, /datum/species) diff --git a/code/__HELPERS/sorting/TimSort.dm b/code/__HELPERS/sorting/TimSort.dm deleted file mode 100644 index db16460da4a..00000000000 --- a/code/__HELPERS/sorting/TimSort.dm +++ /dev/null @@ -1,17 +0,0 @@ -//TimSort interface -/proc/sortTim(list/L, cmp=GLOBAL_PROC_REF(cmp_numeric_asc), associative, fromIndex=1, toIndex=0) - if(L && L.len >= 2) - fromIndex = fromIndex % L.len - toIndex = toIndex % (L.len+1) - if(fromIndex <= 0) - fromIndex += L.len - if(toIndex <= 0) - toIndex += L.len + 1 - - sortInstance.L = L - sortInstance.cmp = cmp - sortInstance.associative = associative - - sortInstance.timSort(fromIndex, toIndex) - - return L diff --git a/code/__HELPERS/sorting/cmp.dm b/code/__HELPERS/sorts/cmp.dm similarity index 100% rename from code/__HELPERS/sorting/cmp.dm rename to code/__HELPERS/sorts/cmp.dm diff --git a/code/__HELPERS/sorts/helpers.dm b/code/__HELPERS/sorts/helpers.dm new file mode 100644 index 00000000000..e8abd2e8f38 --- /dev/null +++ b/code/__HELPERS/sorts/helpers.dm @@ -0,0 +1,49 @@ +/// Helper for the sorting procs. Prevents some code duplication. Creates /datum/sort_instance/sorter +#define CREATE_SORT_INSTANCE(to_sort, cmp, associative, fromIndex, toIndex) \ + if(length(to_sort) < 2) { \ + return to_sort; \ + } \ + fromIndex = fromIndex % length(to_sort); \ + toIndex = toIndex % (length(to_sort) + 1); \ + if (fromIndex <= 0) { \ + fromIndex += length(to_sort); \ + } \ + if (toIndex <= 0) { \ + toIndex += length(to_sort) + 1; \ + } \ + var/datum/sort_instance/sorter = GLOB.sortInstance; \ + if (isnull(sorter)) { \ + sorter = new; \ + } \ + sorter.L = to_sort; \ + sorter.cmp = cmp; \ + sorter.associative = associative; + +/** + * ## Tim Sort + * Hybrid sorting algorithm derived from merge sort and insertion sort. + * + * **Sorts in place**. + * You might not need to get the return value. + * + * @see + * https://en.wikipedia.org/wiki/Timsort + * + * @param {list} to_sort - The list to sort. + * + * @param {proc} cmp - The comparison proc to use. Default: Numeric ascending. + * + * @param {boolean} associative - Whether the list is associative. Default: FALSE. + * + * @param {int} fromIndex - The index to start sorting from. Default: 1. + * + * @param {int} toIndex - The index to stop sorting at. Default: 0. + */ +/proc/sortTim(list/to_sort, cmp = GLOBAL_PROC_REF(cmp_numeric_asc), associative = FALSE, fromIndex = 1, toIndex = 0) as /list + CREATE_SORT_INSTANCE(to_sort, cmp, associative, fromIndex, toIndex) + + sorter.timSort(fromIndex, toIndex) + + return to_sort + +#undef CREATE_SORT_INSTANCE diff --git a/code/__HELPERS/sorting/__main.dm b/code/__HELPERS/sorts/sort_instance.dm similarity index 64% rename from code/__HELPERS/sorting/__main.dm rename to code/__HELPERS/sorts/sort_instance.dm index 97e0508a1d2..eaae55c18d3 100644 --- a/code/__HELPERS/sorting/__main.dm +++ b/code/__HELPERS/sorts/sort_instance.dm @@ -8,9 +8,9 @@ //When we get into galloping mode, we stay there until both runs win less often than MIN_GALLOP consecutive times. #define MIN_GALLOP 7 - //This is a global instance to allow much of this code to be reused. The interfaces are kept seperately -var/datum/sortInstance/sortInstance = new() -/datum/sortInstance +//This is a global instance to allow much of this code to be reused. The interfaces are kept separately +GLOBAL_DATUM_INIT(sortInstance, /datum/sort_instance, new()) +/datum/sort_instance //The array being sorted. var/list/L @@ -20,19 +20,18 @@ var/datum/sortInstance/sortInstance = new() //whether we are sorting list keys (0: L[i]) or associated values (1: L[L[i]]) var/associative = 0 - //This controls when we get *into* galloping mode. It is initialized to MIN_GALLOP. + //This controls when we get *into* galloping mode. It is initialized to MIN_GALLOP. //The mergeLo and mergeHi methods nudge it higher for random data, and lower for highly structured data. var/minGallop = MIN_GALLOP //Stores information regarding runs yet to be merged. //Run i starts at runBase[i] and extends for runLen[i] elements. //runBase[i] + runLen[i] == runBase[i+1] - //var/stackSize var/list/runBases = list() var/list/runLens = list() -/datum/sortInstance/proc/timSort(start, end) +/datum/sort_instance/proc/timSort(start, end) runBases.Cut() runLens.Cut() @@ -83,26 +82,27 @@ var/datum/sortInstance/sortInstance = new() return L -/** - * Sorts the specified portion of the specified array using a binary - * insertion sort. This is the best method for sorting small numbers - * of elements. It requires O(n log n) compares, but O(n^2) data - * movement (worst case). - * - * If the initial part of the specified range is already sorted, - * this method can take advantage of it: the method assumes that the - * elements in range [lo,start) are already sorted - * - * lo the index of the first element in the range to be sorted - * hi the index after the last element in the range to be sorted - * start the index of the first element in the range that is not already known to be sorted - */ -/datum/sortInstance/proc/binarySort(lo, hi, start) + /* + Sorts the specified portion of the specified array using a binary + insertion sort. This is the best method for sorting small numbers + of elements. It requires O(n log n) compares, but O(n^2) data + movement (worst case). + + If the initial part of the specified range is already sorted, + this method can take advantage of it: the method assumes that the + elements in range [lo,start) are already sorted + + lo the index of the first element in the range to be sorted + hi the index after the last element in the range to be sorted + start the index of the first element in the range that is not already known to be sorted + */ +/datum/sort_instance/proc/binarySort(lo, hi, start) //ASSERT(lo <= start && start <= hi) if(start <= lo) start = lo + 1 - for(,start < hi, ++start) + var/list/L = src.L + for(start in start to hi - 1) var/pivot = fetchElement(L,start) //set left and right to the index where pivot belongs @@ -113,34 +113,35 @@ var/datum/sortInstance/sortInstance = new() //[lo, left) elements <= pivot < [right, start) elements //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) + var/mid = (left + right) >> 1 //round((left+right)/2) if(call(cmp)(fetchElement(L,mid), pivot) > 0) right = mid else left = mid+1 //ASSERT(left == right) - moveElement(L, start, left) //move pivot element to correct location in the sorted range - -/** - * Returns the length of the run beginning at the specified position and reverses the run if it is back-to-front - * - * A run is the longest ascending sequence with: - * a[lo] <= a[lo + 1] <= a[lo + 2] <= ... - * or the longest descending sequence with: - * a[lo] > a[lo + 1] > a[lo + 2] > ... - * - * For its intended use in a stable mergesort, the strictness of the - * definition of "descending" is needed so that the call can safely - * reverse a descending sequence without violating stability. - */ -/datum/sortInstance/proc/countRunAndMakeAscending(lo, hi) + move_element(L, start, left) //move pivot element to correct location in the sorted range + + /* + Returns the length of the run beginning at the specified position and reverses the run if it is back-to-front + + A run is the longest ascending sequence with: + a[lo] <= a[lo + 1] <= a[lo + 2] <= ... + or the longest descending sequence with: + a[lo] > a[lo + 1] > a[lo + 2] > ... + + For its intended use in a stable mergesort, the strictness of the + definition of "descending" is needed so that the call can safely + reverse a descending sequence without violating stability. + */ +/datum/sort_instance/proc/countRunAndMakeAscending(lo, hi) //ASSERT(lo < hi) var/runHi = lo + 1 if(runHi >= hi) return 1 + var/list/L = src.L var/last = fetchElement(L,lo) var/current = fetchElement(L,runHi++) @@ -151,7 +152,7 @@ var/datum/sortInstance/sortInstance = new() if(call(cmp)(current, last) >= 0) break ++runHi - reverseRange(L, lo, runHi) + reverse_range(L, lo, runHi) else while(runHi < hi) last = current @@ -162,26 +163,22 @@ var/datum/sortInstance/sortInstance = new() return runHi - lo -/** - * Returns the minimum acceptable run length for an array of the specified length. - * Natural runs shorter than this will be extended with binarySort - */ -/datum/sortInstance/proc/minRunLength(n) + //Returns the minimum acceptable run length for an array of the specified length. + //Natural runs shorter than this will be extended with binarySort +/datum/sort_instance/proc/minRunLength(n) //ASSERT(n >= 0) - var/r = 0 //becomes 1 if any bits are shifted off + var/r = 0 //becomes 1 if any bits are shifted off while(n >= MIN_MERGE) r |= (n & 1) n >>= 1 return n + r -/** - * Examines the stack of runs waiting to be merged and merges adjacent runs until the stack invariants are reestablished: - * runLen[i-3] > runLen[i-2] + runLen[i-1] - * runLen[i-2] > runLen[i-1] - * This method is called each time a new run is pushed onto the stack. - * So the invariants are guaranteed to hold for i runLen[i-2] + runLen[i-1] + // runLen[i-2] > runLen[i-1] + //This method is called each time a new run is pushed onto the stack. + //So the invariants are guaranteed to hold for i= 2) var/n = runBases.len - 1 if(n > 1 && runLens[n-1] <= runLens[n] + runLens[n+1]) @@ -191,25 +188,23 @@ var/datum/sortInstance/sortInstance = new() else if(runLens[n] <= runLens[n+1]) mergeAt(n) else - break //Invariant is established + break //Invariant is established + -/** - * Merges all runs on the stack until only one remains. - * Called only once, to finalise the sort - */ -/datum/sortInstance/proc/mergeForceCollapse() + //Merges all runs on the stack until only one remains. + //Called only once, to finalise the sort +/datum/sort_instance/proc/mergeForceCollapse() while(runBases.len >= 2) var/n = runBases.len - 1 if(n > 1 && runLens[n-1] < runLens[n+1]) --n mergeAt(n) -/** - * Merges the two consecutive runs at stack indices i and i+1 - * Run i must be the penultimate or antepenultimate run on the stack - * In other words, i must be equal to stackSize-2 or stackSize-3 - */ -/datum/sortInstance/proc/mergeAt(i) + + //Merges the two consecutive runs at stack indices i and i+1 + //Run i must be the penultimate or antepenultimate run on the stack + //In other words, i must be equal to stackSize-2 or stackSize-3 +/datum/sort_instance/proc/mergeAt(i) //ASSERT(runBases.len >= 2) //ASSERT(i >= 1) //ASSERT(i == runBases.len - 1 || i == runBases.len - 2) @@ -228,7 +223,6 @@ var/datum/sortInstance/sortInstance = new() runLens.Cut(i+1, i+2) runBases.Cut(i+1, i+2) - //Find where the first element of run2 goes in run1. //Prior elements in run1 can be ignored (because they're already in place) var/k = gallopRight(fetchElement(L,base2), base1, len1, 0) @@ -252,20 +246,21 @@ var/datum/sortInstance/sortInstance = new() mergeHi(base1, len1, base2, len2) -/** - * Locates the position to insert key within the specified sorted range - * If the range contains elements equal to key, this will return the index of the LEFTMOST of those elements - * - * key the element to be inserted into the sorted range - * base the index of the first element of the sorted range - * len the length of the sorted range, must be greater than 0 - * hint the offset from base at which to begin the search, such that 0 <= hint < len; i.e. base <= hint < base+hint - * - * Returns the index at which to insert element 'key' -*/ -/datum/sortInstance/proc/gallopLeft(key, base, len, hint) + /* + Locates the position to insert key within the specified sorted range + If the range contains elements equal to key, this will return the index of the LEFTMOST of those elements + + key the element to be inserted into the sorted range + base the index of the first element of the sorted range + len the length of the sorted range, must be greater than 0 + hint the offset from base at which to begin the search, such that 0 <= hint < len; i.e. base <= hint < base+hint + + Returns the index at which to insert element 'key' + */ +/datum/sort_instance/proc/gallopLeft(key, base, len, hint) //ASSERT(len > 0 && hint >= 0 && hint < len) + var/list/L = src.L var/lastOffset = 0 var/offset = 1 if(call(cmp)(key, fetchElement(L,base+hint)) > 0) @@ -309,31 +304,30 @@ var/datum/sortInstance/sortInstance = new() //ASSERT(lastOffset == offset) return offset -/** - * Like gallopLeft, except that if the range contains an element equal to - * key, gallopRight returns the index after the rightmost equal element. - * - * @param key the key whose insertion point to search for - * @param a the array in which to search - * @param base the index of the first element in the range - * @param len the length of the range; must be > 0 - * @param hint the index at which to begin the search, 0 <= hint < n. - * The closer hint is to the result, the faster this method will run. - * @param c the comparator used to order the range, and to search - * @return the int k, 0 <= k <= n such that a[b + k - 1] <= key < a[b + k] - */ -/datum/sortInstance/proc/gallopRight(key, base, len, hint) + /** + * Like gallopLeft, except that if the range contains an element equal to + * key, gallopRight returns the index after the rightmost equal element. + * + * @param key the key whose insertion point to search for + * @param a the array in which to search + * @param base the index of the first element in the range + * @param len the length of the range; must be > 0 + * @param hint the index at which to begin the search, 0 <= hint < n. + * The closer hint is to the result, the faster this method will run. + * @param c the comparator used to order the range, and to search + * @return the int k, 0 <= k <= n such that `a[b + k - 1] <= key < a[b + k]` + */ +/datum/sort_instance/proc/gallopRight(key, base, len, hint) //ASSERT(len > 0 && hint >= 0 && hint < len) + var/list/L = src.L var/offset = 1 var/lastOffset = 0 - if(call(cmp)(key, fetchElement(L,base+hint)) < 0) //key <= L[base+hint] - var/maxOffset = hint + 1 //therefore we want to insert somewhere in the range [base,base+hint] = [base+,base+(hint+1)) - while(offset < maxOffset && call(cmp)(key, fetchElement(L,base+hint-offset)) < 0) //we are iterating backwards + if(call(cmp)(key, fetchElement(L,base+hint)) < 0) //key <= L[base+hint] + var/maxOffset = hint + 1 //therefore we want to insert somewhere in the range [base,base+hint] = [base+,base+(hint+1)) + while(offset < maxOffset && call(cmp)(key, fetchElement(L,base+hint-offset)) < 0) //we are iterating backwards lastOffset = offset - offset = (offset << 1) + 1 //1 3 7 15 - //if(offset <= 0) //int overflow, not an issue here since we are using floats - // offset = maxOffset + offset = (offset << 1) + 1 //1 3 7 15 if(offset > maxOffset) offset = maxOffset @@ -342,13 +336,11 @@ var/datum/sortInstance/sortInstance = new() lastOffset = hint - offset offset = hint - temp - else //key > L[base+hint] - var/maxOffset = len - hint //therefore we want to insert somewhere in the range (base+hint,base+len) = [base+hint+1, base+hint+(len-hint)) + else //key > L[base+hint] + var/maxOffset = len - hint //therefore we want to insert somewhere in the range (base+hint,base+len) = [base+hint+1, base+hint+(len-hint)) while(offset < maxOffset && call(cmp)(key, fetchElement(L,base+hint+offset)) >= 0) lastOffset = offset offset = (offset << 1) + 1 - //if(offset <= 0) //int overflow, not an issue here since we are using floats - // offset = maxOffset if(offset > maxOffset) offset = maxOffset @@ -362,50 +354,50 @@ var/datum/sortInstance/sortInstance = new() while(lastOffset < offset) var/m = lastOffset + ((offset - lastOffset) >> 1) - if(call(cmp)(key, fetchElement(L,base+m)) < 0) //key <= L[base+m] + if(call(cmp)(key, fetchElement(L,base+m)) < 0) //key <= L[base+m] offset = m - else //key > L[base+m] + else //key > L[base+m] lastOffset = m + 1 //ASSERT(lastOffset == offset) return offset -/** - * Merges two adjacent runs in-place in a stable fashion. - * For performance this method should only be called when len1 <= len2! - */ -/datum/sortInstance/proc/mergeLo(base1, len1, base2, len2) + + //Merges two adjacent runs in-place in a stable fashion. + //For performance this method should only be called when len1 <= len2! +/datum/sort_instance/proc/mergeLo(base1, len1, base2, len2) //ASSERT(len1 > 0 && len2 > 0 && base1 + len1 == base2) + var/list/L = src.L var/cursor1 = base1 var/cursor2 = base2 //degenerate cases if(len2 == 1) - moveElement(L, cursor2, cursor1) + move_element(L, cursor2, cursor1) return if(len1 == 1) - moveElement(L, cursor1, cursor2+len2) + move_element(L, cursor1, cursor2+len2) return //Move first element of second run - moveElement(L, cursor2++, cursor1++) + move_element(L, cursor2++, cursor1++) --len2 outer: while(1) - var/count1 = 0 //# of times in a row that first run won - var/count2 = 0 // " " " " " " second run won + var/count1 = 0 //# of times in a row that first run won + var/count2 = 0 // " " " " " " second run won - //do the straightfoward thin until one run starts winning consistently + //do the straightforward thin until one run starts winning consistently do //ASSERT(len1 > 1 && len2 > 0) if(call(cmp)(fetchElement(L,cursor2), fetchElement(L,cursor1)) < 0) - moveElement(L, cursor2++, cursor1++) + move_element(L, cursor2++, cursor1++) --len2 ++count2 @@ -425,7 +417,7 @@ var/datum/sortInstance/sortInstance = new() while((count1 | count2) < minGallop) - //one run is winning consistently so galloping may provide huge benifits + //one run is winning consistently so galloping may provide huge benefits //so try galloping, until such time as the run is no longer consistently winning do //ASSERT(len1 > 1 && len2 > 0) @@ -438,7 +430,7 @@ var/datum/sortInstance/sortInstance = new() if(len1 <= 1) break outer - moveElement(L, cursor2, cursor1) + move_element(L, cursor2, cursor1) ++cursor2 ++cursor1 if(--len2 == 0) @@ -446,7 +438,7 @@ var/datum/sortInstance/sortInstance = new() count2 = gallopLeft(fetchElement(L,cursor1), cursor2, len2, 0) if(count2) - moveRange(L, cursor2, cursor1, count2) + move_range(L, cursor2, cursor1, count2) cursor2 += count2 cursor1 += count2 @@ -470,41 +462,42 @@ var/datum/sortInstance/sortInstance = new() if(len1 == 1) //ASSERT(len2 > 0) - moveElement(L, cursor1, cursor2+len2) + move_element(L, cursor1, cursor2+len2) //else //ASSERT(len2 == 0) //ASSERT(len1 > 1) -/datum/sortInstance/proc/mergeHi(base1, len1, base2, len2) +/datum/sort_instance/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/list/L = src.L + var/cursor1 = base1 + len1 - 1 //start at end of sublists var/cursor2 = base2 + len2 - 1 //degenerate cases if(len2 == 1) - moveElement(L, base2, base1) + move_element(L, base2, base1) return if(len1 == 1) - moveElement(L, base1, cursor2+1) + move_element(L, base1, cursor2+1) return - moveElement(L, cursor1--, cursor2-- + 1) + move_element(L, cursor1--, cursor2-- + 1) --len1 outer: while(1) - var/count1 = 0 //# of times in a row that first run won - var/count2 = 0 // " " " " " " second run won + var/count1 = 0 //# of times in a row that first run won + var/count2 = 0 // " " " " " " second run won - //do the straightfoward thing until one run starts winning consistently + //do the straightforward thing until one run starts winning consistently do //ASSERT(len1 > 0 && len2 > 1) if(call(cmp)(fetchElement(L,cursor2), fetchElement(L,cursor1)) < 0) - moveElement(L, cursor1--, cursor2-- + 1) + move_element(L, cursor1--, cursor2-- + 1) --len1 ++count1 @@ -523,16 +516,16 @@ var/datum/sortInstance/sortInstance = new() break outer while((count1 | count2) < minGallop) - //one run is winning consistently so galloping may provide huge benifits + //one run is winning consistently so galloping may provide huge benefits //so try galloping, until such time as the run is no longer consistently winning do //ASSERT(len1 > 0 && len2 > 1) - 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) cursor1 -= count1 - moveRange(L, cursor1+1, cursor2+1, count1) //cursor1+1 == cursor2 by definition + move_range(L, cursor1+1, cursor2+1, count1) //cursor1+1 == cursor2 by definition cursor2 -= count1 len1 -= count1 @@ -553,7 +546,7 @@ var/datum/sortInstance/sortInstance = new() if(len2 <= 1) break outer - moveElement(L, cursor1--, cursor2-- + 1) + move_element(L, cursor1--, cursor2-- + 1) --len1 if(len1 == 0) @@ -564,26 +557,25 @@ var/datum/sortInstance/sortInstance = new() if(minGallop < 0) minGallop = 0 - minGallop += 2 // Penalize for leaving gallop mode + minGallop += 2 // Penalize for leaving gallop mode if(len2 == 1) //ASSERT(len1 > 0) cursor1 -= len1 - moveRange(L, cursor1+1, cursor2+1, len1) + move_range(L, cursor1+1, cursor2+1, len1) //else //ASSERT(len1 == 0) //ASSERT(len2 > 0) -/datum/sortInstance/proc/mergeSort(start, end) +/datum/sort_instance/proc/mergeSort(start, end) var/remaining = end - start //If array is small, do an insertion sort if(remaining < MIN_MERGE) - //var/initRunLen = countRunAndMakeAscending(start, end) - binarySort(start, end, start)/*+initRunLen*/ + binarySort(start, end, start/*+initRunLen*/) return var/minRun = minRunLength(remaining) @@ -612,7 +604,7 @@ var/datum/sortInstance/sortInstance = new() else if(runLens[n] <= runLens[n+1]) mergeAt2(n) else - break //Invariant is established + break //Invariant is established while(runBases.len >= 2) var/n = runBases.len - 1 @@ -622,7 +614,8 @@ var/datum/sortInstance/sortInstance = new() return L -/datum/sortInstance/proc/mergeAt2(i) +/datum/sort_instance/proc/mergeAt2(i) + var/list/L = src.L var/cursor1 = runBases[i] var/cursor2 = runBases[i+1] @@ -638,14 +631,12 @@ var/datum/sortInstance/sortInstance = new() break val1 = fetchElement(L,cursor1) else - moveElement(L,cursor2,cursor1) + move_element(L,cursor2,cursor1) if(++cursor2 >= end2) break ++end1 ++cursor1 - //if(++cursor1 >= end1) - // break val2 = fetchElement(L,cursor2) diff --git a/code/_globalvars/lists/mapping.dm b/code/_globalvars/lists/mapping.dm index 9e123e63d9e..7a406477291 100644 --- a/code/_globalvars/lists/mapping.dm +++ b/code/_globalvars/lists/mapping.dm @@ -92,3 +92,10 @@ GLOBAL_LIST_INIT(alldirs, list( SOUTHEAST, SOUTHWEST, )) + +/// Just a list of all the area objects in the game +/// Note, areas can have duplicate types +GLOBAL_LIST_EMPTY(areas) +/// Used by jump-to-area etc. Updated by area/updateName() +/// If this is null, it needs to be recalculated. Use get_sorted_areas() as a getter please +GLOBAL_LIST_EMPTY(sortedAreas) diff --git a/code/controllers/subsystems/evacuation/evacuation.dm b/code/controllers/subsystems/evacuation/evacuation.dm index fad58dc830d..20f930df1d4 100644 --- a/code/controllers/subsystems/evacuation/evacuation.dm +++ b/code/controllers/subsystems/evacuation/evacuation.dm @@ -81,7 +81,7 @@ var/datum/evacuation_controller/evacuation_controller state = EVAC_PREPPING switch(evacuation_type) if(TRANSFER_EMERGENCY) - for(var/area/A in GLOB.all_areas) + for(var/area/A in get_sorted_areas()) if(istype(A, /area/hallway)) A.readyalert() if(!skip_announce) @@ -111,7 +111,7 @@ var/datum/evacuation_controller/evacuation_controller switch(evacuation_type) if(TRANSFER_EMERGENCY) evac_recalled.Announce(SSatlas.current_map.emergency_shuttle_recall_message, new_sound = 'sound/AI/emergency_shuttle_recall_message.ogg') - for(var/area/A in GLOB.all_areas) + for(var/area/A in get_sorted_areas()) if(istype(A, /area/hallway)) A.readyreset() if(TRANSFER_JUMP) diff --git a/code/controllers/subsystems/initialization/map_finalization.dm b/code/controllers/subsystems/initialization/map_finalization.dm index 4f0e2035e74..0d926e09797 100644 --- a/code/controllers/subsystems/initialization/map_finalization.dm +++ b/code/controllers/subsystems/initialization/map_finalization.dm @@ -24,7 +24,7 @@ SUBSYSTEM_DEF(finalize) log_subsystem_mapfinalization("Generated asteroid in [(world.time - time)/10] seconds.") // Generate the area list. - resort_all_areas() + require_area_resort() // This is dependant on markers. populate_antag_spawns() @@ -34,13 +34,6 @@ SUBSYSTEM_DEF(finalize) return SS_INIT_SUCCESS -/proc/resort_all_areas() - GLOB.all_areas = list() - for (var/area/A in world) - GLOB.all_areas += A - - sortTim(GLOB.all_areas, GLOBAL_PROC_REF(cmp_name_asc)) - /datum/controller/subsystem/finalize/proc/load_space_ruin() maploader = new diff --git a/code/controllers/subsystems/initialization/misc_late.dm b/code/controllers/subsystems/initialization/misc_late.dm index 5e4fb2e3326..d46834c6728 100644 --- a/code/controllers/subsystems/initialization/misc_late.dm +++ b/code/controllers/subsystems/initialization/misc_late.dm @@ -43,8 +43,3 @@ SUBSYSTEM_DEF(misc_late) GLOB.outfit_cache[new_outfit.name] = new_outfit return SS_INIT_SUCCESS - -/proc/sorted_add_area(area/A) - GLOB.all_areas += A - - sortTim(GLOB.all_areas, GLOBAL_PROC_REF(cmp_name_asc)) diff --git a/code/controllers/subsystems/night_lighting.dm b/code/controllers/subsystems/night_lighting.dm index 423e0dcad80..6412dc52c3a 100644 --- a/code/controllers/subsystems/night_lighting.dm +++ b/code/controllers/subsystems/night_lighting.dm @@ -50,7 +50,7 @@ SUBSYSTEM_DEF(nightlight) /datum/controller/subsystem/nightlight/proc/get_apc_list(var/whitelisted_only = 1) var/list/obj/machinery/power/apc/lighting_apcs = list() - for (var/A in GLOB.all_areas) + for (var/A in get_sorted_areas()) var/area/B = A if (B.no_light_control || (!(B.allow_nightmode) && whitelisted_only)) continue diff --git a/code/game/area/ai_monitored.dm b/code/game/area/ai_monitored.dm index 84ed4a50e4f..deceba9104d 100644 --- a/code/game/area/ai_monitored.dm +++ b/code/game/area/ai_monitored.dm @@ -1,7 +1,7 @@ /area/ai_monitored name = "AI Monitored Area" var/obj/machinery/camera/motioncamera = null - station_area = 1 + station_area = TRUE /area/ai_monitored/LateInitialize() // locate and store the motioncamera diff --git a/code/game/area/areas.dm b/code/game/area/areas.dm index 8f78a7b3a5f..caeb16ddd2b 100644 --- a/code/game/area/areas.dm +++ b/code/game/area/areas.dm @@ -71,7 +71,13 @@ var/global/list/area_blurb_stated_to = list() var/allow_nightmode = FALSE // If TRUE, lights in area will be darkened by the night mode controller. var/emergency_lights = FALSE + /** + * Boolean, if the area is part of the station (aka main map) + * + * This includes any non-space area, including maintenance; it doesn't include space or shuttles (as they could be outside the station) + */ var/station_area = FALSE + var/centcomm_area = FALSE /// A text-based description of the area, can be used for sounds, notable things in the room, etc. @@ -86,6 +92,7 @@ var/global/list/area_blurb_stated_to = list() // DMMS hook - Required for areas to work properly. if (!GLOB.areas_by_type[type]) GLOB.areas_by_type[type] = src + GLOB.areas += src // Atmos code needs this, so we need to make sure this is done by the time they initialize. uid = ++global_uid if(isnull(area_blurb_category)) @@ -131,6 +138,22 @@ var/global/list/area_blurb_stated_to = list() for(var/turf/T in src) turf_initializer.initialize(T) +/area/Destroy() + if(GLOB.areas_by_type[type] == src) + GLOB.areas_by_type[type] = null + //this is not initialized until get_sorted_areas() is called so we have to do a null check + if(!isnull(GLOB.sortedAreas)) + GLOB.sortedAreas -= src + //just for sanity sake cause why not + if(!isnull(GLOB.areas)) + GLOB.areas -= src + + GLOB.centcom_areas -= src + GLOB.the_station_areas -= src + + //parent cleanup + return ..() + /area/proc/is_prison() return area_flags & AREA_FLAG_PRISON diff --git a/code/game/gamemodes/cult/hell_universe.dm b/code/game/gamemodes/cult/hell_universe.dm index 1e91fd52181..6dab6cf64dd 100644 --- a/code/game/gamemodes/cult/hell_universe.dm +++ b/code/game/gamemodes/cult/hell_universe.dm @@ -51,7 +51,7 @@ In short: SScult.rune_boost += 9001 //basically removing the rune cap /datum/universal_state/hell/proc/AreaSet() - for(var/area/A in GLOB.all_areas) + for(var/area/A in get_sorted_areas()) if(!istype(A,/area) || istype(A, /area/space)) continue diff --git a/code/game/gamemodes/endgame/supermatter_cascade/universe.dm b/code/game/gamemodes/endgame/supermatter_cascade/universe.dm index e7e3d0a2bcc..a3d812aaab4 100644 --- a/code/game/gamemodes/endgame/supermatter_cascade/universe.dm +++ b/code/game/gamemodes/endgame/supermatter_cascade/universe.dm @@ -90,7 +90,7 @@ The access requirements on the Asteroid Shuttles' consoles have now been revoked universe_has_ended = 1 /datum/universal_state/supermatter_cascade/proc/AreaSet() - for(var/area/A in GLOB.all_areas) + for(var/area/A in get_sorted_areas()) if(!istype(A,/area) || istype(A, /area/space)) continue diff --git a/code/game/machinery/turret_control.dm b/code/game/machinery/turret_control.dm index a89f486fe91..ad51378af4a 100644 --- a/code/game/machinery/turret_control.dm +++ b/code/game/machinery/turret_control.dm @@ -53,7 +53,7 @@ if(!control_area) control_area = get_area(src) else if(istext(control_area)) - for(var/area/A in GLOB.all_areas) + for(var/area/A in get_sorted_areas()) if(A.name && A.name==control_area) control_area = A break diff --git a/code/game/supplyshuttle.dm b/code/game/supplyshuttle.dm index c1f550771b9..e7bbc93c6ec 100644 --- a/code/game/supplyshuttle.dm +++ b/code/game/supplyshuttle.dm @@ -10,7 +10,7 @@ name = "Supply Shuttle" icon_state = "shuttle3" requires_power = 0 - station_area = 1 + station_area = TRUE area_flags = AREA_FLAG_SPAWN_ROOF | AREA_FLAG_HIDE_FROM_HOLOMAP /area/supply/dock diff --git a/code/modules/admin/secrets/fun_secrets/light_switches.dm b/code/modules/admin/secrets/fun_secrets/light_switches.dm index 40b8fe0013c..76d4270a4df 100644 --- a/code/modules/admin/secrets/fun_secrets/light_switches.dm +++ b/code/modules/admin/secrets/fun_secrets/light_switches.dm @@ -25,6 +25,6 @@ set_switches(null) /datum/admin_secret_item/fun_secret/light_switches/proc/set_switches(var/new_state) - for(var/area/A in GLOB.all_areas) + for(var/area/A in get_sorted_areas()) if(A.lightswitch != new_state) A.set_lightswitch(new_state) diff --git a/code/modules/admin/verbs/adminjump.dm b/code/modules/admin/verbs/adminjump.dm index 74bd12da18e..153d526f82b 100644 --- a/code/modules/admin/verbs/adminjump.dm +++ b/code/modules/admin/verbs/adminjump.dm @@ -4,7 +4,7 @@ /mob/abstract/ghost/on_mob_jump() QDEL_NULL(orbiting) -/client/proc/Jump(var/area/A in GLOB.all_areas) +/client/proc/Jump(var/area/A in get_sorted_areas()) set name = "Jump to Area" set desc = "Area to jump to" set category = "Admin" @@ -263,7 +263,7 @@ set name = "Send Mob" if(!check_rights(R_ADMIN|R_MOD|R_DEBUG)) return - var/area/A = input(usr, "Pick an area.", "Pick an area") in GLOB.all_areas + var/area/A = input(usr, "Pick an area.", "Pick an area") in get_sorted_areas() if(A) if(GLOB.config.allow_admin_jump) M.on_mob_jump() diff --git a/code/modules/awaymissions/bluespaceartillery.dm b/code/modules/awaymissions/bluespaceartillery.dm index e4824441da6..a1bf5c86609 100644 --- a/code/modules/awaymissions/bluespaceartillery.dm +++ b/code/modules/awaymissions/bluespaceartillery.dm @@ -28,7 +28,7 @@ return 1 if(href_list["fireArea"]) - var/area/A = input("Area to jump bombard", "Open Fire") in GLOB.all_areas + var/area/A = input("Area to jump bombard", "Open Fire") in get_sorted_areas() var/turf/loc = pick(get_area_turfs(A)) announce_and_fire(loc, usr) else if(href_list["fireCords"]) diff --git a/code/modules/events/radiation_storm.dm b/code/modules/events/radiation_storm.dm index a57a7d5b4e1..d089b029de0 100644 --- a/code/modules/events/radiation_storm.dm +++ b/code/modules/events/radiation_storm.dm @@ -57,7 +57,7 @@ return /datum/event/radiation_storm/proc/lights(var/turnOn = FALSE) - for(var/area/A in GLOB.all_areas) + for(var/area/A in get_sorted_areas()) if(A.area_flags & AREA_FLAG_RAD_SHIELDED) continue if(turnOn) diff --git a/code/modules/mapping/map_template.dm b/code/modules/mapping/map_template.dm index 173f06323dc..bbcb108740a 100644 --- a/code/modules/mapping/map_template.dm +++ b/code/modules/mapping/map_template.dm @@ -89,7 +89,7 @@ GLOB.map_templates["[z_index]"] = src smooth_zlevel(world.maxz) - resort_all_areas() + require_area_resort() post_exoplanet_generation(bounds) diff --git a/code/modules/mob/living/silicon/robot/drone/drone_console.dm b/code/modules/mob/living/silicon/robot/drone/drone_console.dm index 4792e2a7096..4c0ee681dc7 100644 --- a/code/modules/mob/living/silicon/robot/drone/drone_console.dm +++ b/code/modules/mob/living/silicon/robot/drone/drone_console.dm @@ -63,7 +63,7 @@ if(href_list["setarea"]) if(!call_area_names) call_area_names = list() - for(var/area/A as anything in GLOB.all_areas) + for(var/area/A as anything in get_sorted_areas()) if(A.station_area) call_area_names += A.name //Probably should consider using another list, but this one will do. diff --git a/code/modules/power/gravitygenerator.dm b/code/modules/power/gravitygenerator.dm index d298f6852e0..6452156f549 100644 --- a/code/modules/power/gravitygenerator.dm +++ b/code/modules/power/gravitygenerator.dm @@ -462,7 +462,7 @@ linked.gravity_generator = src /obj/machinery/gravity_generator/main/proc/updateareas() - for(var/area/A in GLOB.all_areas) + for(var/area/A in get_sorted_areas()) if(!(get_area_type(A) == AREA_STATION)) continue localareas += A diff --git a/code/modules/turbolift/turbolift.dm b/code/modules/turbolift/turbolift.dm index f891d0e2721..a54c3dc30fd 100644 --- a/code/modules/turbolift/turbolift.dm +++ b/code/modules/turbolift/turbolift.dm @@ -66,7 +66,7 @@ doors_closing = 0 // The doors weren't open, so they are done closing - var/area/turbolift/origin = locate(current_floor.area_ref) in GLOB.all_areas + var/area/turbolift/origin = locate(current_floor.area_ref) in get_sorted_areas() if(target_floor == current_floor) playsound(control_panel_interior.loc, origin.arrival_sound, 50, 1) @@ -86,7 +86,7 @@ else next_floor = floors[current_floor_index - 1] - var/area/turbolift/destination = locate(next_floor.area_ref) in GLOB.all_areas + var/area/turbolift/destination = locate(next_floor.area_ref) in get_sorted_areas() if(!istype(origin) || !istype(destination) || (origin == destination)) return 0 diff --git a/code/modules/turbolift/turbolift_areas.dm b/code/modules/turbolift/turbolift_areas.dm index 87ad28e0c85..b5d62178ef3 100644 --- a/code/modules/turbolift/turbolift_areas.dm +++ b/code/modules/turbolift/turbolift_areas.dm @@ -3,7 +3,7 @@ name = "Turbolift" base_turf = /turf/simulated/open requires_power = 0 - station_area = 1 + station_area = TRUE sound_environment = SOUND_AREA_SMALL_ENCLOSED ambience = AMBIENCE_ELEVATOR diff --git a/code/unit_tests/area_configuration_tests.dm b/code/unit_tests/area_configuration_tests.dm index 9a03b2ce33c..c59ae9df9fe 100644 --- a/code/unit_tests/area_configuration_tests.dm +++ b/code/unit_tests/area_configuration_tests.dm @@ -29,3 +29,27 @@ ABSTRACT_TYPE(/datum/unit_test/area_configuration) TEST_PASS("All exoplanet areas have an exoplanet base turf.") return test_status + +/datum/unit_test/area_configuration/shuttles_area_not_station_area + name = "AREA CONFIG: Shuttle areas must not be station areas" + +/datum/unit_test/area_configuration/shuttles_area_not_station_area/start_test() + var/test_status = UNIT_TEST_PASSED + + for(var/area/shuttle/shuttle_area_typepath in subtypesof(/area/shuttle)) + //No need for abstract areas to respect this really + if(is_abstract(shuttle_area_typepath)) + TEST_DEBUG("Skipping abstract shuttle area [shuttle_area_typepath]") + continue + + TEST_DEBUG("Now testing shuttle area [shuttle_area_typepath]") + if(shuttle_area_typepath::station_area) + test_status = TEST_FAIL("The shuttle area [shuttle_area_typepath] is a station area!") + else + TEST_NOTICE("The shuttle area [shuttle_area_typepath] is not a station area.") + TEST_DEBUG("The shuttle area [shuttle_area_typepath] is not a station area.") + + if(test_status == UNIT_TEST_PASSED) + TEST_PASS("All shuttle areas are not station areas.") + + return test_status diff --git a/code/unit_tests/map_tests.dm b/code/unit_tests/map_tests.dm index 7cc764203ae..fbe59fdb2e5 100644 --- a/code/unit_tests/map_tests.dm +++ b/code/unit_tests/map_tests.dm @@ -35,7 +35,7 @@ var/list/exempt_from_apc = typecacheof(SSatlas.current_map.ut_apc_exempt_areas) var/list/exempt_from_fire = typecacheof(SSatlas.current_map.ut_fire_exempt_areas) - for(var/area/A in typecache_filter_list_reverse(GLOB.all_areas, exempt_areas)) + for(var/area/A in typecache_filter_list_reverse(get_sorted_areas(), exempt_areas)) if(is_station_level(A.z)) area_test_count++ var/bad_msg = "[ascii_red]--------------- [A.name] ([A.type])" @@ -366,5 +366,54 @@ return test_status +/datum/unit_test/map_test/areas_in_station_zlevels_must_be_marked_as_station_areas + name = "MAP: Areas in station z-levels must be marked as station areas" + + /** + * A list of types of areas that we do not want to check + */ + var/list/do_not_check_areas_types = list( + /area/space, + /area/shuttle, + /area/template_noop, + ) + +/datum/unit_test/map_test/areas_in_station_zlevels_must_be_marked_as_station_areas/start_test() + var/test_status = UNIT_TEST_PASSED + + for(var/area/possible_station_area in GLOB.areas) + + if(is_type_in_list(possible_station_area, do_not_check_areas_types)) + TEST_DEBUG("Skipping area [possible_station_area] ([possible_station_area.type]) as it is in the do not check list.") + continue + + //We get a turf from the area, to see if we are in the "station" + var/list/turf/area_turfs = get_area_turfs(possible_station_area) + if(!length(area_turfs)) + TEST_NOTICE("Skipping area [possible_station_area] ([possible_station_area.type]) as it has no turfs.") + continue + + var/turf/turf_to_get_z = pick(area_turfs) + + //See if the turf is in a station z-level, if not abort + if(!is_station_turf(turf_to_get_z)) + TEST_DEBUG("Skipping area [possible_station_area] ([possible_station_area.type]) as it is not in a station z-level (picked check turf: [turf_to_get_z] on Z [turf_to_get_z.z]).") + continue + + /* At this point, we know the area must be checked and is present in the station z-level */ + + if(!possible_station_area.station_area) + test_status = TEST_FAIL("Area [possible_station_area] ([possible_station_area.type]) is not marked as a station area, despite being in a station z-level.") + else + TEST_DEBUG("Area [possible_station_area] ([possible_station_area.type]) is marked as a station area.") + + + if(test_status == UNIT_TEST_PASSED) + TEST_PASS("All areas in station z-levels are marked as station areas.") + else + TEST_FAIL("Some areas in station z-levels are not marked as station areas.") + + return test_status + #undef SUCCESS #undef FAILURE diff --git a/html/changelogs/fluffyghost-stationareaandareaimprovements.yml b/html/changelogs/fluffyghost-stationareaandareaimprovements.yml new file mode 100644 index 00000000000..db51717d1c3 --- /dev/null +++ b/html/changelogs/fluffyghost-stationareaandareaimprovements.yml @@ -0,0 +1,62 @@ +################################ +# Example Changelog File +# +# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb. +# +# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.) +# When it is, any changes listed below will disappear. +# +# Valid Prefixes: +# bugfix +# - (fixes bugs) +# wip +# - (work in progress) +# qol +# - (quality of life) +# soundadd +# - (adds a sound) +# sounddel +# - (removes a sound) +# rscadd +# - (adds a feature) +# rscdel +# - (removes a feature) +# imageadd +# - (adds an image or sprite) +# imagedel +# - (removes an image or sprite) +# spellcheck +# - (fixes spelling or grammar) +# experiment +# - (experimental change) +# balance +# - (balance changes) +# code_imp +# - (misc internal code change) +# refactor +# - (refactors code) +# config +# - (makes a change to the config files) +# admin +# - (makes changes to administrator tools) +# server +# - (miscellaneous changes to server) +################################# + +# Your name. +author: FluffyGhost + +# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again. +delete-after: True + +# Any changes you've made. See valid prefix list above. +# INDENT WITH TWO SPACES. NOT TABS. SPACES. +# SCREW THIS UP AND IT WON'T WORK. +# Also, this gets changed to [] after reading. Just remove the brackets when you add new shit. +# Please surround your changes in double quotes ("). It works without them, but if you use certain characters it screws up compiling. The quotes will not show up in the changelog. +changes: + - refactor: "Refactored sorting." + - server: "Added test to verify all horizon areas (outside exceptions) are marked as station areas." + - server: "Added test to verify shuttle areas are not marked as station areas." + - refactor: "Refactored how the area sorting var is made and used." + - refactor: "Added a global list of all areas." diff --git a/maps/_common/areas/ai.dm b/maps/_common/areas/ai.dm index d873d10ec43..1c929210f8c 100644 --- a/maps/_common/areas/ai.dm +++ b/maps/_common/areas/ai.dm @@ -14,7 +14,7 @@ icon_state = "storage" /area/turret_protected - station_area = 1 + station_area = TRUE area_flags = AREA_FLAG_HIDE_FROM_HOLOMAP /area/turret_protected/ai_upload diff --git a/maps/_common/areas/asteroid_areas.dm b/maps/_common/areas/asteroid_areas.dm index 2651e951fb4..fd80034d3aa 100644 --- a/maps/_common/areas/asteroid_areas.dm +++ b/maps/_common/areas/asteroid_areas.dm @@ -34,7 +34,7 @@ // Main mining /area/outpost/mining_main icon_state = "outpost_mine_main" - station_area = 1 + station_area = TRUE holomap_color = HOLOMAP_AREACOLOR_OPERATIONS /area/outpost/mining_main/dorms @@ -61,7 +61,7 @@ // Engineering /area/outpost/engineering icon_state = "outpost_engine" - station_area = 1 + station_area = TRUE holomap_color = HOLOMAP_AREACOLOR_ENGINEERING /area/outpost/engineering/hallway @@ -85,7 +85,7 @@ // Research /area/outpost/research icon_state = "outpost_research" - station_area = 1 + station_area = TRUE holomap_color = HOLOMAP_AREACOLOR_SCIENCE /area/outpost/research/hallway diff --git a/maps/_common/areas/derelict.dm b/maps/_common/areas/derelict.dm index aebad2da6e3..1ef5c8bcb23 100644 --- a/maps/_common/areas/derelict.dm +++ b/maps/_common/areas/derelict.dm @@ -165,7 +165,7 @@ icon_state = "yellow" no_light_control = 1 base_turf = /turf/space - station_area = 1 + station_area = TRUE /area/construction/supplyshuttle name = "Supply Shuttle" diff --git a/maps/_common/areas/station/civilian.dm b/maps/_common/areas/station/civilian.dm index 5696a605c98..f3fb6c29c30 100644 --- a/maps/_common/areas/station/civilian.dm +++ b/maps/_common/areas/station/civilian.dm @@ -3,13 +3,13 @@ name = "Dormitories" icon_state = "Sleep" area_flags = AREA_FLAG_RAD_SHIELDED - station_area = 1 + station_area = TRUE holomap_color = HOLOMAP_AREACOLOR_CIVILIAN /area/sconference_room name = "Surface - Conference Room" icon_state = "Sleep" - station_area = 1 + station_area = TRUE /area/crew_quarters/toilet name = "Surface - Washroom" @@ -115,10 +115,10 @@ name = "Library" icon_state = "library" sound_environment = SOUND_AREA_LARGE_SOFTFLOOR - station_area = 1 + station_area = TRUE /area/chapel - station_area = 1 + station_area = TRUE holomap_color = HOLOMAP_AREACOLOR_CIVILIAN /area/chapel/main @@ -161,7 +161,7 @@ /area/quartermaster name = "Operations Manager" icon_state = "quart" - station_area = 1 + station_area = TRUE holomap_color = HOLOMAP_AREACOLOR_OPERATIONS /area/quartermaster/office @@ -202,7 +202,7 @@ /area/janitor name = "Custodial Closet" icon_state = "janitor" - station_area = 1 + station_area = TRUE ambience = AMBIENCE_MAINTENANCE /area/janitor/stairs @@ -212,7 +212,7 @@ name = "Hydroponics" icon_state = "hydro" no_light_control = TRUE - station_area = 1 + station_area = TRUE /area/hydroponics/garden name = "Garden" @@ -221,9 +221,9 @@ /area/store name = "Surface - Commissary" icon_state = "quartstorage" - station_area = 1 + station_area = TRUE /area/journalistoffice name = "Journalist's Office" - station_area = 1 + station_area = TRUE sound_environment = SOUND_AREA_SMALL_SOFTFLOOR diff --git a/maps/_common/areas/station/command.dm b/maps/_common/areas/station/command.dm index 465baa44401..8c5e821e8d8 100644 --- a/maps/_common/areas/station/command.dm +++ b/maps/_common/areas/station/command.dm @@ -4,7 +4,7 @@ name = "Bridge" icon_state = "bridge" no_light_control = 1 - station_area = 1 + station_area = TRUE holomap_color = HOLOMAP_AREACOLOR_COMMAND area_blurb = "The sound here seems to carry more than others, every click of a shoe or clearing of a throat amplified. The smell of ink, written and printed, wafts notably through the air." area_blurb_category = "command" @@ -115,12 +115,12 @@ name = "Communications Relay" icon_state = "tcomsatcham" no_light_control = 1 - station_area = 1 + station_area = TRUE /area/server name = "Research Server Room" icon_state = "server" - station_area = 1 + station_area = TRUE holomap_color = HOLOMAP_AREACOLOR_SCIENCE @@ -128,4 +128,4 @@ /area/teleporter name = "Command - Teleporter" icon_state = "teleporter" - station_area = 1 + station_area = TRUE diff --git a/maps/_common/areas/station/engineering.dm b/maps/_common/areas/station/engineering.dm index b829455f667..3c771975868 100644 --- a/maps/_common/areas/station/engineering.dm +++ b/maps/_common/areas/station/engineering.dm @@ -5,7 +5,7 @@ name = "Engineering" icon_state = "engineering" ambience = AMBIENCE_ENGINEERING - station_area = 1 + station_area = TRUE holomap_color = HOLOMAP_AREACOLOR_ENGINEERING /area/engineering/atmos diff --git a/maps/_common/areas/station/maintenance.dm b/maps/_common/areas/station/maintenance.dm index 03869815d70..8317d3096b7 100644 --- a/maps/_common/areas/station/maintenance.dm +++ b/maps/_common/areas/station/maintenance.dm @@ -5,7 +5,7 @@ sound_environment = SOUND_AREA_TUNNEL_ENCLOSED turf_initializer = new /datum/turf_initializer/maintenance() ambience = AMBIENCE_MAINTENANCE - station_area = 1 + station_area = TRUE area_blurb = "Scarcely lit, cramped, and filled with stale, dusty air. Around you hisses compressed air through the pipes, a buzz of electrical charge through the wires, and muffled rumbles of the hull settling. This place may feel alien compared to the interior of the ship and is a place where one could get lost or badly hurt, but some may find the isolation comforting." area_blurb_category = "maint" @@ -304,7 +304,7 @@ always_unpowered = 1 ambience = AMBIENCE_SPACE base_turf = /turf/space - station_area = 1 + station_area = TRUE /area/solar/auxport name = "Roof Solar Array" diff --git a/maps/_common/areas/station/medical.dm b/maps/_common/areas/station/medical.dm index 8b850f7d6d7..48041c54f5b 100644 --- a/maps/_common/areas/station/medical.dm +++ b/maps/_common/areas/station/medical.dm @@ -2,7 +2,7 @@ //MedBay /area/medical - station_area = 1 + station_area = TRUE holomap_color = HOLOMAP_AREACOLOR_MEDICAL area_blurb = "Various smells waft through the air: disinfectants, various medicines, sterile gloves, and gauze. It's not a pleasant smell, but one you could grow to ignore." area_blurb_category = "mecical" diff --git a/maps/_common/areas/station/research.dm b/maps/_common/areas/station/research.dm index 3a2bad87c01..d38d5298f80 100644 --- a/maps/_common/areas/station/research.dm +++ b/maps/_common/areas/station/research.dm @@ -1,5 +1,5 @@ /area/assembly - station_area = 1 + station_area = TRUE /area/assembly/chargebay name = "Mech Bay" @@ -27,7 +27,7 @@ //rnd (Research and Development /area/rnd - station_area = 1 + station_area = TRUE holomap_color = HOLOMAP_AREACOLOR_SCIENCE /area/rnd/hallway @@ -197,9 +197,9 @@ area_flags = AREA_FLAG_FIRING_RANGE /area/toxins - station_area = 1 + station_area = TRUE /area/toxins/server name = "Research - Server Room" icon_state = "server" - station_area = 1 + station_area = TRUE diff --git a/maps/_common/areas/station/security.dm b/maps/_common/areas/station/security.dm index d817793ef46..abbf36d206f 100644 --- a/maps/_common/areas/station/security.dm +++ b/maps/_common/areas/station/security.dm @@ -3,7 +3,7 @@ /area/security no_light_control = 1 - station_area = 1 + station_area = TRUE holomap_color = HOLOMAP_AREACOLOR_SECURITY /area/security/main diff --git a/maps/_common/areas/station/storage.dm b/maps/_common/areas/station/storage.dm index 11014610bbe..6c03d8ca67d 100644 --- a/maps/_common/areas/station/storage.dm +++ b/maps/_common/areas/station/storage.dm @@ -1,7 +1,7 @@ //Storage /area/storage - station_area = 1 + station_area = TRUE /area/storage/tools name = "Auxiliary Tool Storage" diff --git a/maps/_common/areas/telecomms.dm b/maps/_common/areas/telecomms.dm index b2cb5c1a8ed..cf0e1dc894c 100644 --- a/maps/_common/areas/telecomms.dm +++ b/maps/_common/areas/telecomms.dm @@ -4,7 +4,7 @@ /area/tcommsat ambience = AMBIENCE_ENGINEERING no_light_control = 1 - station_area = 1 + station_area = TRUE holomap_color = HOLOMAP_AREACOLOR_ENGINEERING /area/tcommsat/entrance