diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm index a0ea6b60777..35f837e97fd 100644 --- a/code/__DEFINES/subsystems.dm +++ b/code/__DEFINES/subsystems.dm @@ -1,23 +1,18 @@ -//Update this whenever the db schema changes -//make sure you add an update to the schema_version stable in the db changelog -#define DB_MAJOR_VERSION 4 -#define DB_MINOR_VERSION 1 - //Timing subsystem //Don't run if there is an identical unique timer active //if the arguments to addtimer are the same as an existing timer, it doesn't create a new timer, and returns the id of the existing timer -#define TIMER_UNIQUE 0x1 +#define TIMER_UNIQUE 1 //For unique timers: Replace the old timer rather then not start this one -#define TIMER_OVERRIDE 0x2 +#define TIMER_OVERRIDE 2 //Timing should be based on how timing progresses on clients, not the sever. // tracking this is more expensive, // should only be used in conjuction with things that have to progress client side, such as animate() or sound() -#define TIMER_CLIENT_TIME 0x4 +#define TIMER_CLIENT_TIME 4 //Timer can be stopped using deltimer() -#define TIMER_STOPPABLE 0x8 +#define TIMER_STOPPABLE 8 //To be used with TIMER_UNIQUE //prevents distinguishing identical timers with the wait variable -#define TIMER_NO_HASH_WAIT 0x10 +#define TIMER_NO_HASH_WAIT 16 #define TIMER_NO_INVOKE_WARNING 600 //number of byond ticks that are allowed to pass before the timer subsystem thinks it hung on something diff --git a/code/__HELPERS/lists.dm b/code/__HELPERS/lists.dm index 5627a355557..799f94feebb 100644 --- a/code/__HELPERS/lists.dm +++ b/code/__HELPERS/lists.dm @@ -687,43 +687,43 @@ proc/dd_sortedObjectList(list/incoming) //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 + if(fromIndex == toIndex || fromIndex + 1 == toIndex) //no need to move return if(fromIndex > 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) + L.Cut(fromIndex, fromIndex + 1) //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) +/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. 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 - for(var/i=0, i distance) //there is an overlap, therefore swapping each element will require more swaps than inserting new elements if(fromIndex < toIndex) @@ -731,24 +731,24 @@ proc/dd_sortedObjectList(list/incoming) else fromIndex += len - for(var/i=0, i fromIndex) var/a = toIndex toIndex = fromIndex fromIndex = a - for(var/i=0, i= 2) fromIndex = fromIndex % L.len - toIndex = toIndex % (L.len+1) + toIndex = toIndex % (L.len + 1) if(fromIndex <= 0) fromIndex += L.len if(toIndex <= 0) diff --git a/code/__HELPERS/sorts/MergeSort.dm b/code/__HELPERS/sorts/MergeSort.dm index 39d37997255..d8c3d1477d0 100644 --- a/code/__HELPERS/sorts/MergeSort.dm +++ b/code/__HELPERS/sorts/MergeSort.dm @@ -1,8 +1,8 @@ //merge-sort - gernerally faster than insert sort, for runs of 7 or larger -/proc/sortMerge(list/L, cmp=/proc/cmp_numeric_asc, associative, fromIndex=1, toIndex) +/proc/sortMerge(list/L, cmp = /proc/cmp_numeric_asc, associative, fromIndex = 1, toIndex) if(L && L.len >= 2) fromIndex = fromIndex % L.len - toIndex = toIndex % (L.len+1) + toIndex = toIndex % (L.len + 1) if(fromIndex <= 0) fromIndex += L.len if(toIndex <= 0) diff --git a/code/__HELPERS/sorts/TimSort.dm b/code/__HELPERS/sorts/TimSort.dm index d709044dc05..b3aca97ea99 100644 --- a/code/__HELPERS/sorts/TimSort.dm +++ b/code/__HELPERS/sorts/TimSort.dm @@ -1,8 +1,8 @@ //TimSort interface -/proc/sortTim(list/L, cmp=/proc/cmp_numeric_asc, associative, fromIndex=1, toIndex=0) +/proc/sortTim(list/L, cmp = /proc/cmp_numeric_asc, associative, fromIndex = 1, toIndex = 0) if(L && L.len >= 2) fromIndex = fromIndex % L.len - toIndex = toIndex % (L.len+1) + toIndex = toIndex % (L.len + 1) if(fromIndex <= 0) fromIndex += L.len if(toIndex <= 0) diff --git a/code/__HELPERS/sorts/__main.dm b/code/__HELPERS/sorts/__main.dm index 768622818ff..b5368330d59 100644 --- a/code/__HELPERS/sorts/__main.dm +++ b/code/__HELPERS/sorts/__main.dm @@ -8,7 +8,7 @@ //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 separately +//This is a global instance to allow much of this code to be reused. The interfaces are kept separately GLOBAL_DATUM_INIT(sortInstance, /datum/sortInstance, new()) /datum/sortInstance //The array being sorted. @@ -31,615 +31,615 @@ GLOBAL_DATUM_INIT(sortInstance, /datum/sortInstance, new()) var/list/runLens = list() - proc/timSort(start, end) - runBases.Cut() - runLens.Cut() +/datum/sortInstance/proc/timSort(start, end) + runBases.Cut() + runLens.Cut() - var/remaining = end - start + var/remaining = end - start - //If array is small, do a 'mini-TimSort' with no merges - if(remaining < MIN_MERGE) - var/initRunLen = countRunAndMakeAscending(start, end) - binarySort(start, end, start+initRunLen) - return + //If array is small, do a 'mini-TimSort' with no merges + if(remaining < MIN_MERGE) + var/initRunLen = countRunAndMakeAscending(start, end) + binarySort(start, end, start + initRunLen) + return - //March over the array finding natural runs - //Extend any short natural runs to runs of length minRun - var/minRun = minRunLength(remaining) + //March over the array finding natural runs + //Extend any short natural runs to runs of length minRun + var/minRun = minRunLength(remaining) - do - //identify next run - var/runLen = countRunAndMakeAscending(start, end) + do + //identify next run + var/runLen = countRunAndMakeAscending(start, end) - //if run is short, extend to min(minRun, remaining) - if(runLen < minRun) - var/force = (remaining <= minRun) ? remaining : minRun + //if run is short, extend to min(minRun, remaining) + if(runLen < minRun) + var/force = (remaining <= minRun) ? remaining : minRun - binarySort(start, start+force, start+runLen) - runLen = force + binarySort(start, start + force, start+runLen) + runLen = force - //add data about run to queue - runBases.Add(start) - runLens.Add(runLen) + //add data about run to queue + runBases.Add(start) + runLens.Add(runLen) - //maybe merge - mergeCollapse() + //maybe merge + mergeCollapse() - //Advance to find next run - start += runLen - remaining -= runLen + //Advance to find next run + start += runLen + remaining -= runLen - while(remaining > 0) + while(remaining > 0) - //Merge all remaining runs to complete sort - //ASSERT(start == end) - mergeForceCollapse(); - //ASSERT(runBases.len == 1) + //Merge all remaining runs to complete sort + //ASSERT(start == end) + mergeForceCollapse(); + //ASSERT(runBases.len == 1) - //reset minGallop, for successive calls - minGallop = MIN_GALLOP + //reset minGallop, for successive calls + minGallop = MIN_GALLOP - return L + 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). +/* +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 +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 - */ - proc/binarySort(lo, hi, start) - //ASSERT(lo <= start && start <= hi) - if(start <= lo) - start = lo + 1 +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) + //ASSERT(lo <= start && start <= hi) + if(start <= lo) + start = lo + 1 - for(,start < hi, ++start) - var/pivot = fetchElement(L,start) + for(,start < hi, ++start) + var/pivot = fetchElement(L,start) - //set left and right to the index where pivot belongs - var/left = lo - var/right = start - //ASSERT(left <= right) + //set left and right to the index where pivot belongs + var/left = lo + var/right = start + //ASSERT(left <= right) - //[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) - 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. - */ - proc/countRunAndMakeAscending(lo, hi) - //ASSERT(lo < hi) - - var/runHi = lo + 1 - if(runHi >= hi) - return 1 - - var/last = fetchElement(L,lo) - var/current = fetchElement(L,runHi++) - - if(call(cmp)(current, last) < 0) - while(runHi < hi) - last = current - current = fetchElement(L,runHi) - if(call(cmp)(current, last) >= 0) - break - ++runHi - reverseRange(L, lo, runHi) - else - while(runHi < hi) - last = current - current = fetchElement(L,runHi) - if(call(cmp)(current, last) < 0) - break - ++runHi - - 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 - proc/minRunLength(n) - //ASSERT(n >= 0) - 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= 2) - var/n = runBases.len - 1 - if(n > 1 && runLens[n-1] <= runLens[n] + runLens[n+1]) - if(runLens[n-1] < runLens[n+1]) - --n - mergeAt(n) - else if(runLens[n] <= runLens[n+1]) - mergeAt(n) + //[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) + if(call(cmp)(fetchElement(L, mid), pivot) > 0) + right = mid else - break //Invariant is established + left = mid + 1 + //ASSERT(left == right) + moveElement(L, start, left) //move pivot element to correct location in the sorted range - //Merges all runs on the stack until only one remains. - //Called only once, to finalise the sort - proc/mergeForceCollapse() - while(runBases.len >= 2) - var/n = runBases.len - 1 - if(n > 1 && runLens[n-1] < runLens[n+1]) +/* +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) + //ASSERT(lo < hi) + + var/runHi = lo + 1 + if(runHi >= hi) + return 1 + + var/last = fetchElement(L, lo) + var/current = fetchElement(L, runHi++) + + if(call(cmp)(current, last) < 0) + while(runHi < hi) + last = current + current = fetchElement(L,runHi) + if(call(cmp)(current, last) >= 0) + break + ++runHi + reverseRange(L, lo, runHi) + else + while(runHi < hi) + last = current + current = fetchElement(L,runHi) + if(call(cmp)(current, last) < 0) + break + ++runHi + + 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) + //ASSERT(n >= 0) + 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= 2) + var/n = runBases.len - 1 + if(n > 1 && runLens[n - 1] <= runLens[n] + runLens[n + 1]) + if(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 - proc/mergeAt(i) - //ASSERT(runBases.len >= 2) - //ASSERT(i >= 1) - //ASSERT(i == runBases.len - 1 || i == runBases.len - 2) - - var/base1 = runBases[i] - var/base2 = runBases[i+1] - var/len1 = runLens[i] - var/len2 = runLens[i+1] - - //ASSERT(len1 > 0 && len2 > 0) - //ASSERT(base1 + len1 == base2) - - //Record the legth of the combined runs. If i is the 3rd last run now, also slide over the last run - //(which isn't involved in this merge). The current run (i+1) goes away in any case. - runLens[i] += runLens[i+1] - 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) - //ASSERT(k >= 0) - base1 += k - len1 -= k - if(len1 == 0) - return - - //Find where the last element of run1 goes in run2. - //Subsequent elements in run2 can be ignored (because they're already in place) - len2 = gallopLeft(fetchElement(L,base1 + len1 - 1), base2, len2, len2-1) - //ASSERT(len2 >= 0) - if(len2 == 0) - return - - //Merge remaining runs, using tmp array with min(len1, len2) elements - if(len1 <= len2) - mergeLo(base1, len1, base2, len2) + else if(runLens[n] <= runLens[n + 1]) + mergeAt(n) else - mergeHi(base1, len1, base2, len2) + break //Invariant is established - /* - 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 +//Merges all runs on the stack until only one remains. +//Called only once, to finalise the sort +/datum/sortInstance/proc/mergeForceCollapse() + while(runBases.len >= 2) + var/n = runBases.len - 1 + if(n > 1 && runLens[n - 1] < runLens[n + 1]) + --n + mergeAt(n) - 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' - */ - proc/gallopLeft(key, base, len, hint) - //ASSERT(len > 0 && hint >= 0 && hint < len) +//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) + //ASSERT(runBases.len >= 2) + //ASSERT(i >= 1) + //ASSERT(i == runBases.len - 1 || i == runBases.len - 2) - var/lastOffset = 0 - var/offset = 1 - if(call(cmp)(key, fetchElement(L,base+hint)) > 0) - var/maxOffset = len - hint - while(offset < maxOffset && call(cmp)(key, fetchElement(L,base+hint+offset)) > 0) - lastOffset = offset - offset = (offset << 1) + 1 + var/base1 = runBases[i] + var/base2 = runBases[i + 1] + var/len1 = runLens[i] + var/len2 = runLens[i + 1] - if(offset > maxOffset) - offset = maxOffset + //ASSERT(len1 > 0 && len2 > 0) + //ASSERT(base1 + len1 == base2) - lastOffset += hint - offset += hint + //Record the legth of the combined runs. If i is the 3rd last run now, also slide over the last run + //(which isn't involved in this merge). The current run (i+1) goes away in any case. + runLens[i] += runLens[i + 1] + runLens.Cut(i + 1, i + 2) + runBases.Cut(i + 1, i + 2) - else - var/maxOffset = hint + 1 - while(offset < maxOffset && call(cmp)(key, fetchElement(L,base+hint-offset)) <= 0) - lastOffset = offset - offset = (offset << 1) + 1 - if(offset > maxOffset) - offset = maxOffset + //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) + //ASSERT(k >= 0) + base1 += k + len1 -= k + if(len1 == 0) + return - var/temp = lastOffset - lastOffset = hint - offset - offset = hint - temp + //Find where the last element of run1 goes in run2. + //Subsequent elements in run2 can be ignored (because they're already in place) + len2 = gallopLeft(fetchElement(L, base1 + len1 - 1), base2, len2, len2 - 1) + //ASSERT(len2 >= 0) + if(len2 == 0) + return - //ASSERT(-1 <= lastOffset && lastOffset < offset && offset <= len) + //Merge remaining runs, using tmp array with min(len1, len2) elements + if(len1 <= len2) + mergeLo(base1, len1, base2, len2) + else + mergeHi(base1, len1, base2, len2) - //Now L[base+lastOffset] < key <= L[base+offset], so key belongs somewhere to the right of lastOffset but no farther than - //offset. Do a binary search with invariant L[base+lastOffset-1] < key <= L[base+offset] - ++lastOffset - while(lastOffset < offset) - var/m = lastOffset + ((offset - lastOffset) >> 1) - if(call(cmp)(key, fetchElement(L,base+m)) > 0) - lastOffset = m + 1 - else - offset = m +/* + 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 - //ASSERT(lastOffset == offset) - return offset + 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 - /** - * 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] - */ - proc/gallopRight(key, base, len, hint) - //ASSERT(len > 0 && hint >= 0 && hint < len) + Returns the index at which to insert element 'key' +*/ +/datum/sortInstance/proc/gallopLeft(key, base, len, hint) + //ASSERT(len > 0 && hint >= 0 && hint < len) - 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 - lastOffset = offset - offset = (offset << 1) + 1 //1 3 7 15 + var/lastOffset = 0 + var/offset = 1 + if(call(cmp)(key, fetchElement(L,base + hint)) > 0) + var/maxOffset = len - hint + while(offset < maxOffset && call(cmp)(key, fetchElement(L, base + hint + offset)) > 0) + lastOffset = offset + offset = (offset << 1) + 1 - if(offset > maxOffset) - offset = maxOffset + if(offset > maxOffset) + offset = maxOffset - var/temp = lastOffset - lastOffset = hint - offset - offset = hint - temp + lastOffset += hint + offset += 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 + else + var/maxOffset = hint + 1 + while(offset < maxOffset && call(cmp)(key, fetchElement(L, base + hint - offset)) <= 0) + lastOffset = offset + offset = (offset << 1) + 1 - if(offset > maxOffset) - offset = maxOffset + if(offset > maxOffset) + offset = maxOffset - lastOffset += hint - offset += hint + var/temp = lastOffset + lastOffset = hint - offset + offset = hint - temp //ASSERT(-1 <= lastOffset && lastOffset < offset && offset <= len) - ++lastOffset - while(lastOffset < offset) - var/m = lastOffset + ((offset - lastOffset) >> 1) + //Now L[base+lastOffset] < key <= L[base+offset], so key belongs somewhere to the right of lastOffset but no farther than + //offset. Do a binary search with invariant L[base+lastOffset-1] < key <= L[base+offset] + ++lastOffset + while(lastOffset < offset) + var/m = lastOffset + ((offset - lastOffset) >> 1) - if(call(cmp)(key, fetchElement(L,base+m)) < 0) //key <= L[base+m] - offset = m - else //key > L[base+m] - lastOffset = m + 1 + if(call(cmp)(key, fetchElement(L,base + m)) > 0) + lastOffset = m + 1 + else + offset = m - //ASSERT(lastOffset == offset) + //ASSERT(lastOffset == offset) + return 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) + //ASSERT(len > 0 && hint >= 0 && hint < len) + + 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 + lastOffset = offset + offset = (offset << 1) + 1 //1 3 7 15 + + if(offset > maxOffset) + offset = maxOffset + + var/temp = lastOffset + 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)) + while(offset < maxOffset && call(cmp)(key, fetchElement(L, base + hint + offset)) >= 0) + lastOffset = offset + offset = (offset << 1) + 1 + + if(offset > maxOffset) + offset = maxOffset + + lastOffset += hint + offset += hint + + //ASSERT(-1 <= lastOffset && lastOffset < offset && offset <= len) + + ++lastOffset + while(lastOffset < offset) + var/m = lastOffset + ((offset - lastOffset) >> 1) + + if(call(cmp)(key, fetchElement(L, base + m)) < 0) //key <= L[base+m] + offset = 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! - proc/mergeLo(base1, len1, base2, len2) - //ASSERT(len1 > 0 && len2 > 0 && base1 + len1 == base2) +//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) + //ASSERT(len1 > 0 && len2 > 0 && base1 + len1 == base2) - var/cursor1 = base1 - var/cursor2 = base2 + var/cursor1 = base1 + var/cursor2 = base2 - //degenerate cases - if(len2 == 1) - moveElement(L, cursor2, cursor1) - return + //degenerate cases + if(len2 == 1) + moveElement(L, cursor2, cursor1) + return - if(len1 == 1) - moveElement(L, cursor1, cursor2+len2) - return + if(len1 == 1) + moveElement(L, cursor1, cursor2 + len2) + return - //Move first element of second run - moveElement(L, cursor2++, cursor1++) - --len2 + //Move first element of second run + moveElement(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 + outer: + while(1) + 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 straightfoward 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++) - --len2 + do + //ASSERT(len1 > 1 && len2 > 0) + if(call(cmp)(fetchElement(L, cursor2), fetchElement(L, cursor1)) < 0) + moveElement(L, cursor2++, cursor1++) + --len2 - ++count2 - count1 = 0 + ++count2 + count1 = 0 - if(len2 == 0) - break outer - else - ++cursor1 - - ++count1 - count2 = 0 - - if(--len1 == 1) - break outer - - while((count1 | count2) < minGallop) - - - //one run is winning consistently so galloping may provide huge benifits - //so try galloping, until such time as the run is no longer consistently winning - do - //ASSERT(len1 > 1 && len2 > 0) - - count1 = gallopRight(fetchElement(L,cursor2), cursor1, len1, 0) - if(count1) - cursor1 += count1 - len1 -= count1 - - if(len1 <= 1) - break outer - - moveElement(L, cursor2, cursor1) - ++cursor2 - ++cursor1 - if(--len2 == 0) + if(len2 == 0) break outer - - count2 = gallopLeft(fetchElement(L,cursor1), cursor2, len2, 0) - if(count2) - moveRange(L, cursor2, cursor1, count2) - - cursor2 += count2 - cursor1 += count2 - len2 -= count2 - - if(len2 == 0) - break outer - + else ++cursor1 + + ++count1 + count2 = 0 + if(--len1 == 1) break outer - --minGallop - - while((count1|count2) > MIN_GALLOP) - - if(minGallop < 0) - minGallop = 0 - minGallop += 2; // Penalize for leaving gallop mode + while((count1 | count2) < minGallop) - if(len1 == 1) - //ASSERT(len2 > 0) - moveElement(L, cursor1, cursor2+len2) + //one run is winning consistently so galloping may provide huge benifits + //so try galloping, until such time as the run is no longer consistently winning + do + //ASSERT(len1 > 1 && len2 > 0) - //else - //ASSERT(len2 == 0) - //ASSERT(len1 > 1) + count1 = gallopRight(fetchElement(L, cursor2), cursor1, len1, 0) + if(count1) + cursor1 += count1 + len1 -= count1 - - 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, cursor2+1) - return - - moveElement(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 - - //do the straightfoward 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) - --len1 - - ++count1 - count2 = 0 - - if(len1 == 0) - break outer - else - --cursor2 - --len2 - - ++count2 - count1 = 0 - - if(len2 == 1) - break outer - while((count1 | count2) < minGallop) - - //one run is winning consistently so galloping may provide huge benifits - //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? - if(count1) - cursor1 -= count1 - - moveRange(L, cursor1+1, cursor2+1, count1) //cursor1+1 == cursor2 by definition - - cursor2 -= count1 - len1 -= count1 - - if(len1 == 0) - break outer - - --cursor2 - - if(--len2 == 1) + if(len1 <= 1) break outer - count2 = len2 - gallopLeft(fetchElement(L,cursor1), cursor1+1, len2, len2-1) - if(count2) - cursor2 -= count2 - len2 -= count2 + moveElement(L, cursor2, cursor1) + ++cursor2 + ++cursor1 + if(--len2 == 0) + break outer - if(len2 <= 1) - break outer + count2 = gallopLeft(fetchElement(L, cursor1), cursor2, len2, 0) + if(count2) + moveRange(L, cursor2, cursor1, count2) + cursor2 += count2 + cursor1 += count2 + len2 -= count2 + + if(len2 == 0) + break outer + + ++cursor1 + if(--len1 == 1) + break outer + + --minGallop + + while((count1|count2) > MIN_GALLOP) + + if(minGallop < 0) + minGallop = 0 + minGallop += 2; // Penalize for leaving gallop mode + + + if(len1 == 1) + //ASSERT(len2 > 0) + moveElement(L, cursor1, cursor2 + len2) + + //else + //ASSERT(len2 == 0) + //ASSERT(len1 > 1) + + +/datum/sortInstance/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, cursor2 + 1) + return + + moveElement(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 + + //do the straightfoward 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) --len1 + ++count1 + count2 = 0 + + if(len1 == 0) + break outer + else + --cursor2 + --len2 + + ++count2 + count1 = 0 + + if(len2 == 1) + break outer + while((count1 | count2) < minGallop) + + //one run is winning consistently so galloping may provide huge benifits + //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? + if(count1) + cursor1 -= count1 + + moveRange(L, cursor1 + 1, cursor2 + 1, count1) //cursor1+1 == cursor2 by definition + + cursor2 -= count1 + len1 -= count1 + if(len1 == 0) break outer - --minGallop - while((count1|count2) > MIN_GALLOP) + --cursor2 - if(minGallop < 0) - minGallop = 0 - minGallop += 2 // Penalize for leaving gallop mode + if(--len2 == 1) + break outer - if(len2 == 1) - //ASSERT(len1 > 0) + count2 = len2 - gallopLeft(fetchElement(L, cursor1), cursor1 + 1, len2, len2 - 1) + if(count2) + cursor2 -= count2 + len2 -= count2 - cursor1 -= len1 - moveRange(L, cursor1+1, cursor2+1, len1) + if(len2 <= 1) + break outer - //else - //ASSERT(len1 == 0) - //ASSERT(len2 > 0) + moveElement(L, cursor1--, cursor2-- + 1) + --len1 + + if(len1 == 0) + break outer + + --minGallop + while((count1|count2) > MIN_GALLOP) + + if(minGallop < 0) + minGallop = 0 + minGallop += 2 // Penalize for leaving gallop mode + + if(len2 == 1) + //ASSERT(len1 > 0) + + cursor1 -= len1 + moveRange(L, cursor1 + 1, cursor2 + 1, len1) + + //else + //ASSERT(len1 == 0) + //ASSERT(len2 > 0) - proc/mergeSort(start, end) - var/remaining = end - start +/datum/sortInstance/proc/mergeSort(start, end) + var/remaining = end - start - //If array is small, do an insertion sort - if(remaining < MIN_MERGE) - binarySort(start, end, start/*+initRunLen*/) - return + //If array is small, do an insertion sort + if(remaining < MIN_MERGE) + binarySort(start, end, start/*+initRunLen*/) + return - var/minRun = minRunLength(remaining) + var/minRun = minRunLength(remaining) - do - var/runLen = (remaining <= minRun) ? remaining : minRun + do + var/runLen = (remaining <= minRun) ? remaining : minRun - binarySort(start, start+runLen, start) + binarySort(start, start + runLen, start) - //add data about run to queue - runBases.Add(start) - runLens.Add(runLen) + //add data about run to queue + runBases.Add(start) + runLens.Add(runLen) - //Advance to find next run - start += runLen - remaining -= runLen + //Advance to find next run + start += runLen + remaining -= runLen - while(remaining > 0) + while(remaining > 0) - while(runBases.len >= 2) - var/n = runBases.len - 1 - if(n > 1 && runLens[n-1] <= runLens[n] + runLens[n+1]) - if(runLens[n-1] < runLens[n+1]) - --n - mergeAt2(n) - else if(runLens[n] <= runLens[n+1]) - mergeAt2(n) - else - break //Invariant is established - - while(runBases.len >= 2) - var/n = runBases.len - 1 - if(n > 1 && runLens[n-1] < runLens[n+1]) + while(runBases.len >= 2) + var/n = runBases.len - 1 + if(n > 1 && runLens[n - 1] <= runLens[n] + runLens[n + 1]) + if(runLens[n - 1] < runLens[n + 1]) --n mergeAt2(n) + else if(runLens[n] <= runLens[n + 1]) + mergeAt2(n) + else + break //Invariant is established - return L + while(runBases.len >= 2) + var/n = runBases.len - 1 + if(n > 1 && runLens[n - 1] < runLens[n + 1]) + --n + mergeAt2(n) - proc/mergeAt2(i) - var/cursor1 = runBases[i] - var/cursor2 = runBases[i+1] + return L - var/end1 = cursor1+runLens[i] - var/end2 = cursor2+runLens[i+1] +/datum/sortInstance/proc/mergeAt2(i) + var/cursor1 = runBases[i] + var/cursor2 = runBases[i + 1] - var/val1 = fetchElement(L,cursor1) - var/val2 = fetchElement(L,cursor2) + var/end1 = cursor1+runLens[i] + var/end2 = cursor2+runLens[i + 1] - while(1) - if(call(cmp)(val1,val2) <= 0) - if(++cursor1 >= end1) - break - val1 = fetchElement(L,cursor1) - else - moveElement(L,cursor2,cursor1) + var/val1 = fetchElement(L, cursor1) + var/val2 = fetchElement(L, cursor2) - if(++cursor2 >= end2) - break - ++end1 - ++cursor1 + while(1) + if(call(cmp)(val1, val2) <= 0) + if(++cursor1 >= end1) + break + val1 = fetchElement(L, cursor1) + else + moveElement(L, cursor2, cursor1) - val2 = fetchElement(L,cursor2) + if(++cursor2 >= end2) + break + ++end1 + ++cursor1 + + val2 = fetchElement(L, cursor2) - //Record the legth of the combined runs. If i is the 3rd last run now, also slide over the last run - //(which isn't involved in this merge). The current run (i+1) goes away in any case. - runLens[i] += runLens[i+1] - runLens.Cut(i+1, i+2) - runBases.Cut(i+1, i+2) + //Record the legth of the combined runs. If i is the 3rd last run now, also slide over the last run + //(which isn't involved in this merge). The current run (i+1) goes away in any case. + runLens[i] += runLens[i + 1] + runLens.Cut(i + 1, i + 2) + runBases.Cut(i + 1, i + 2) #undef MIN_GALLOP #undef MIN_MERGE diff --git a/code/__HELPERS/time.dm b/code/__HELPERS/time.dm index 0fceedac3b0..6d28c2c0cd4 100644 --- a/code/__HELPERS/time.dm +++ b/code/__HELPERS/time.dm @@ -170,6 +170,6 @@ proc/isDay(var/month, var/day) GLOBAL_VAR_INIT(midnight_rollovers, 0) GLOBAL_VAR_INIT(rollovercheck_last_timeofday, 0) /proc/update_midnight_rollover() - if (world.timeofday < GLOB.rollovercheck_last_timeofday) //TIME IS GOING BACKWARDS! + if(world.timeofday < GLOB.rollovercheck_last_timeofday) //TIME IS GOING BACKWARDS! return GLOB.midnight_rollovers++ return GLOB.midnight_rollovers \ No newline at end of file diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm index c76e04fc9d8..88fdb83da10 100644 --- a/code/controllers/configuration.dm +++ b/code/controllers/configuration.dm @@ -197,7 +197,7 @@ var/high_pop_mc_tick_rate = 1.1 var/high_pop_mc_mode_amount = 65 - var/disable_high_pop_mc_mode_amount = 60 + var/disable_high_pop_mc_mode_amount = 60 /datum/configuration/New() var/list/L = subtypesof(/datum/game_mode) diff --git a/code/controllers/subsystem/air.dm b/code/controllers/subsystem/air.dm index 7ff5743294f..4434053e4ec 100644 --- a/code/controllers/subsystem/air.dm +++ b/code/controllers/subsystem/air.dm @@ -144,7 +144,7 @@ SUBSYSTEM_DEF(air) currentpart = SSAIR_PIPENETS /datum/controller/subsystem/air/proc/process_deferred_pipenets(resumed = 0) - if (!resumed) + if(!resumed) src.currentrun = deferred_pipenet_rebuilds.Copy() //cache for sanic speed (lists are references anyways) var/list/currentrun = src.currentrun @@ -159,7 +159,7 @@ SUBSYSTEM_DEF(air) return /datum/controller/subsystem/air/proc/process_pipenets(resumed = 0) - if (!resumed) + if(!resumed) src.currentrun = networks.Copy() //cache for sanic speed (lists are references anyways) var/list/currentrun = src.currentrun @@ -175,7 +175,7 @@ SUBSYSTEM_DEF(air) /datum/controller/subsystem/air/proc/process_atmos_machinery(resumed = 0) var/seconds = wait * 0.1 - if (!resumed) + if(!resumed) src.currentrun = atmos_machinery.Copy() //cache for sanic speed (lists are references anyways) var/list/currentrun = src.currentrun @@ -188,7 +188,7 @@ SUBSYSTEM_DEF(air) return /datum/controller/subsystem/air/proc/process_super_conductivity(resumed = 0) - if (!resumed) + if(!resumed) src.currentrun = active_super_conductivity.Copy() //cache for sanic speed (lists are references anyways) var/list/currentrun = src.currentrun @@ -200,14 +200,14 @@ SUBSYSTEM_DEF(air) return /datum/controller/subsystem/air/proc/process_hotspots(resumed = 0) - if (!resumed) + if(!resumed) src.currentrun = hotspots.Copy() //cache for sanic speed (lists are references anyways) var/list/currentrun = src.currentrun while(currentrun.len) var/obj/effect/hotspot/H = currentrun[currentrun.len] currentrun.len-- - if (H) + if(H) H.process() else hotspots -= H @@ -215,7 +215,7 @@ SUBSYSTEM_DEF(air) return /datum/controller/subsystem/air/proc/process_high_pressure_delta(resumed = 0) - while (high_pressure_delta.len) + while(high_pressure_delta.len) var/turf/simulated/T = high_pressure_delta[high_pressure_delta.len] high_pressure_delta.len-- T.high_pressure_movements() @@ -226,20 +226,20 @@ SUBSYSTEM_DEF(air) /datum/controller/subsystem/air/proc/process_active_turfs(resumed = 0) //cache for sanic speed var/fire_count = times_fired - if (!resumed) + if(!resumed) src.currentrun = active_turfs.Copy() //cache for sanic speed (lists are references anyways) var/list/currentrun = src.currentrun while(currentrun.len) var/turf/simulated/T = currentrun[currentrun.len] currentrun.len-- - if (T) + if(T) T.process_cell(fire_count) - if (MC_TICK_CHECK) + if(MC_TICK_CHECK) return /datum/controller/subsystem/air/proc/process_excited_groups(resumed = 0) - if (!resumed) + if(!resumed) src.currentrun = excited_groups.Copy() //cache for sanic speed (lists are references anyways) var/list/currentrun = src.currentrun @@ -251,7 +251,7 @@ SUBSYSTEM_DEF(air) EG.self_breakdown() else if(EG.breakdown_cooldown >= 20) EG.dismantle() - if (MC_TICK_CHECK) + if(MC_TICK_CHECK) return /datum/controller/subsystem/air/proc/remove_from_active(turf/simulated/T) @@ -294,24 +294,24 @@ SUBSYSTEM_DEF(air) /turf/simulated/proc/resolve_active_graph() . = list() var/datum/excited_group/EG = excited_group - if (blocks_air || !air) + if(blocks_air || !air) return - if (!EG) + if(!EG) EG = new EG.add_turf(src) - for (var/turf/simulated/ET in atmos_adjacent_turfs) - if ( ET.blocks_air || !ET.air) + for(var/turf/simulated/ET in atmos_adjacent_turfs) + if(ET.blocks_air || !ET.air) continue var/ET_EG = ET.excited_group - if (ET_EG) - if (ET_EG != EG) + if(ET_EG) + if(ET_EG != EG) EG.merge_groups(ET_EG) EG = excited_group //merge_groups() may decide to replace our current EG else EG.add_turf(ET) - if (!ET.excited) + if(!ET.excited) ET.excited = 1 . += ET @@ -358,7 +358,7 @@ SUBSYSTEM_DEF(air) icemaster = new /obj/effect/overlay() icemaster.icon = 'icons/turf/overlays.dmi' icemaster.icon_state = "snowfloor" - icemaster.layer = TURF_LAYER+0.1 + icemaster.layer = TURF_LAYER + 0.1 icemaster.mouse_opacity = 0 #undef SSAIR_PIPENETS diff --git a/code/controllers/subsystem/spacedrift.dm b/code/controllers/subsystem/spacedrift.dm index c251492227a..fcc62a2fa50 100644 --- a/code/controllers/subsystem/spacedrift.dm +++ b/code/controllers/subsystem/spacedrift.dm @@ -13,30 +13,30 @@ SUBSYSTEM_DEF(spacedrift) /datum/controller/subsystem/spacedrift/fire(resumed = 0) - if (!resumed) + if(!resumed) src.currentrun = processing.Copy() //cache for sanic speed (lists are references anyways) var/list/currentrun = src.currentrun - while (currentrun.len) + while(currentrun.len) var/atom/movable/AM = currentrun[currentrun.len] currentrun.len-- - if (!AM) + if(!AM) processing -= AM if (MC_TICK_CHECK) return continue - if (AM.inertia_next_move > world.time) + if(AM.inertia_next_move > world.time) if (MC_TICK_CHECK) return continue - if (!AM.loc || AM.loc != AM.inertia_last_loc || AM.Process_Spacemove(0)) + if(!AM.loc || AM.loc != AM.inertia_last_loc || AM.Process_Spacemove(0)) AM.inertia_dir = 0 - if (!AM.inertia_dir) + if(!AM.inertia_dir) AM.inertia_last_loc = null processing -= AM if (MC_TICK_CHECK) @@ -49,11 +49,11 @@ SUBSYSTEM_DEF(spacedrift) step(AM, AM.inertia_dir) AM.inertia_moving = FALSE AM.inertia_next_move = world.time + AM.inertia_move_delay - if (AM.loc == old_loc) + if(AM.loc == old_loc) AM.inertia_dir = 0 AM.setDir(old_dir) AM.inertia_last_loc = AM.loc - if (MC_TICK_CHECK) + if(MC_TICK_CHECK) return diff --git a/code/controllers/subsystem/throwing.dm b/code/controllers/subsystem/throwing.dm index c32b5a707ae..b74e3a1a6c9 100644 --- a/code/controllers/subsystem/throwing.dm +++ b/code/controllers/subsystem/throwing.dm @@ -14,9 +14,8 @@ SUBSYSTEM_DEF(throwing) /datum/controller/subsystem/throwing/stat_entry() ..("P:[processing.len]") - /datum/controller/subsystem/throwing/fire(resumed = 0) - if (!resumed) + if(!resumed) src.currentrun = processing.Copy() //cache for sanic speed (lists are references anyways) @@ -26,15 +25,15 @@ SUBSYSTEM_DEF(throwing) var/atom/movable/AM = currentrun[currentrun.len] var/datum/thrownthing/TT = currentrun[AM] currentrun.len-- - if (!AM || !TT) + if(!AM || !TT) processing -= AM - if (MC_TICK_CHECK) + if(MC_TICK_CHECK) return continue TT.tick() - if (MC_TICK_CHECK) + if(MC_TICK_CHECK) return currentrun = null @@ -63,7 +62,7 @@ SUBSYSTEM_DEF(throwing) /datum/thrownthing/proc/tick() var/atom/movable/AM = thrownthing - if (!isturf(AM.loc) || !AM.throwing) + if(!isturf(AM.loc) || !AM.throwing) finalize() return @@ -71,7 +70,7 @@ SUBSYSTEM_DEF(throwing) delayed_time += world.time - last_move return - if (dist_travelled && hitcheck()) //to catch sneaky things moving on our tile while we slept + if(dist_travelled && hitcheck()) //to catch sneaky things moving on our tile while we slept finalize() return @@ -80,51 +79,51 @@ SUBSYSTEM_DEF(throwing) last_move = world.time //calculate how many tiles to move, making up for any missed ticks. - var/tilestomove = CEILING(min(((((world.time+world.tick_lag) - start_time + delayed_time) * speed) - (dist_travelled ? dist_travelled : -1)), speed*MAX_TICKS_TO_MAKE_UP) * (world.tick_lag * SSthrowing.wait), 1) - while (tilestomove-- > 0) - if ((dist_travelled >= maxrange || AM.loc == target_turf) && has_gravity(AM, AM.loc)) + var/tilestomove = CEILING(min(((((world.time + world.tick_lag) - start_time + delayed_time) * speed) - (dist_travelled ? dist_travelled : -1)), speed * MAX_TICKS_TO_MAKE_UP) * (world.tick_lag * SSthrowing.wait), 1) + while(tilestomove-- > 0) + if((dist_travelled >= maxrange || AM.loc == target_turf) && has_gravity(AM, AM.loc)) finalize() return - if (dist_travelled <= max(dist_x, dist_y)) //if we haven't reached the target yet we home in on it, otherwise we use the initial direction + if(dist_travelled <= max(dist_x, dist_y)) //if we haven't reached the target yet we home in on it, otherwise we use the initial direction step = get_step(AM, get_dir(AM, target_turf)) else step = get_step(AM, init_dir) - if (!pure_diagonal && !diagonals_first) // not a purely diagonal trajectory and we don't want all diagonal moves to be done first - if (diagonal_error >= 0 && max(dist_x,dist_y) - dist_travelled != 1) //we do a step forward unless we're right before the target + if(!pure_diagonal && !diagonals_first) // not a purely diagonal trajectory and we don't want all diagonal moves to be done first + if (diagonal_error >= 0 && max(dist_x, dist_y) - dist_travelled != 1) //we do a step forward unless we're right before the target step = get_step(AM, dx) - diagonal_error += (diagonal_error < 0) ? dist_x/2 : -dist_y + diagonal_error += (diagonal_error < 0) ? dist_x / 2 : -dist_y - if (!step) // going off the edge of the map makes get_step return null, don't let things go off the edge + if(!step) // going off the edge of the map makes get_step return null, don't let things go off the edge finalize() return AM.Move(step, get_dir(AM, step)) - if (!AM.throwing) // we hit something during our move + if(!AM.throwing) // we hit something during our move finalize(hit = TRUE) return dist_travelled++ - if (dist_travelled > MAX_THROWING_DIST) + if(dist_travelled > MAX_THROWING_DIST) finalize() return -/datum/thrownthing/proc/finalize(hit = FALSE, target=null) +/datum/thrownthing/proc/finalize(hit = FALSE, target = null) set waitfor = 0 SSthrowing.processing -= thrownthing //done throwing, either because it hit something or it finished moving thrownthing.throwing = null - if (!hit) - for (var/thing in get_turf(thrownthing)) //looking for our target on the turf we land on. + if(!hit) + for(var/thing in get_turf(thrownthing)) //looking for our target on the turf we land on. var/atom/A = thing - if (A == target) + if(A == target) hit = 1 thrownthing.throw_impact(A, src) break - if (!hit) + if(!hit) thrownthing.throw_impact(get_turf(thrownthing), src) // we haven't hit something yet and we still must, let's hit the ground. thrownthing.newtonian_move(init_dir) else @@ -133,17 +132,17 @@ SUBSYSTEM_DEF(throwing) if(target) thrownthing.throw_impact(target, src) - if (callback) + if(callback) callback.Invoke() /datum/thrownthing/proc/hit_atom(atom/A) - finalize(hit=TRUE, target=A) + finalize(hit = TRUE, target = A) /datum/thrownthing/proc/hitcheck() - for (var/thing in get_turf(thrownthing)) + for(var/thing in get_turf(thrownthing)) var/atom/movable/AM = thing - if (AM == thrownthing) + if(AM == thrownthing) continue if(AM.density && !(AM.pass_flags & LETPASSTHROW) && !(AM.flags & ON_BORDER)) - finalize(hit=TRUE, target=AM) + finalize(hit = TRUE, target = AM) return TRUE