/* * Holds procs to help with list operations * Contains groups: * Misc * Sorting */ /* * Misc */ //Returns a list in plain english as a string /proc/english_list(var/list/input, nothing_text = "nothing", and_text = " and ", comma_text = ", ", final_comma_text = "" ) var/total = input.len if (!total) return "[nothing_text]" else if (total == 1) return "[input[1]]" else if (total == 2) return "[input[1]][and_text][input[2]]" else var/output = "" var/index = 1 while (index < total) if (index == total - 1) comma_text = final_comma_text output += "[input[index]][comma_text]" index++ return "[output][and_text][input[index]]" /proc/ConvertReqString2List(var/list/source_list) var/list/temp_list = params2list(source_list) for(var/O in temp_list) temp_list[O] = text2num(temp_list[O]) return temp_list //Returns list element or null. Should prevent "index out of bounds" error. proc/listgetindex(var/list/list,index) if(istype(list) && list.len) if(isnum(index)) if(InRange(index,1,list.len)) return list[index] else if(index in list) return list[index] return proc/islist(list/list) if(istype(list)) return 1 return 0 //Return either pick(list) or null if list is not of type /list or is empty proc/safepick(list/list) if(!islist(list) || !list.len) return return pick(list) //Checks if the list is empty proc/isemptylist(list/list) if(!list.len) return 1 return 0 //Checks for specific types in a list /proc/is_type_in_list(var/atom/A, var/list/L) for(var/type in L) if(istype(A, type)) return 1 return 0 //Empties the list by setting the length to 0. Hopefully the elements get garbage collected proc/clearlist(list/list) if(istype(list)) list.len = 0 return //Removes any null entries from the list proc/listclearnulls(list/list) if(istype(list)) while(null in list) list -= null return /* * Returns list containing all the entries from first list that are not present in second. * If skiprep = 1, repeated elements are treated as one. * If either of arguments is not a list, returns null */ /proc/difflist(var/list/first, var/list/second, var/skiprep=0) if(!islist(first) || !islist(second)) return var/list/result = new if(skiprep) for(var/e in first) if(!(e in result) && !(e in second)) result += e else result = first - second return result /* * Returns list containing entries that are in either list but not both. * If skipref = 1, repeated elements are treated as one. * If either of arguments is not a list, returns null */ /proc/uniquemergelist(var/list/first, var/list/second, var/skiprep=0) if(!islist(first) || !islist(second)) return var/list/result = new if(skiprep) result = difflist(first, second, skiprep)+difflist(second, first, skiprep) else result = first ^ second return result //Pretends to pick an element based on its weight but really just seems to pick a random element. /proc/pickweight(list/L) var/total = 0 var/item for (item in L) if (!L[item]) L[item] = 1 total += L[item] total = rand(1, total) for (item in L) total -=L [item] if (total <= 0) return item return null //Pick a random element from the list and remove it from the list. /proc/pick_n_take(list/listfrom) if (listfrom.len > 0) var/picked = pick(listfrom) listfrom -= picked return picked return null //Returns the top(last) element from the list and removes it from the list (typical stack function) /proc/pop(list/listfrom) if (listfrom.len > 0) var/picked = listfrom[listfrom.len] listfrom.len-- return picked return null //Returns the next element in parameter list after first appearance of parameter element. If it is the last element of the list or not present in list, returns first element. /proc/next_in_list(element, list/L) for(var/i=1, i= 1; i--) output += L[i] return output //Randomize: Return the list in a random order /proc/shuffle(var/list/L) if(!L) return L = L.Copy() for(var/i=1; i current_index) current_index++ current_item = sorted_list[current_index] current_item_value = current_item:dd_SortValue() current_sort_object_value = current_sort_object:dd_SortValue() if (current_sort_object_value < current_item_value) high_index = current_index - 1 else if (current_sort_object_value > current_item_value) low_index = current_index + 1 else // current_sort_object == current_item low_index = current_index break // Insert before low_index. insert_index = low_index // Special case adding to end of list. if (insert_index > sorted_list.len) sorted_list += current_sort_object continue // Because BYOND lists don't support insert, have to do it by: // 1) taking out bottom of list, 2) adding item, 3) putting back bottom of list. list_bottom = sorted_list.Copy(insert_index) sorted_list.Cut(insert_index) sorted_list += current_sort_object sorted_list += list_bottom return sorted_list */ proc/dd_sortedtextlist(list/incoming, case_sensitive = 0) // Returns a new list with the text values sorted. // Use binary search to order by sortValue. // This works by going to the half-point of the list, seeing if the node in question is higher or lower cost, // then going halfway up or down the list and checking again. // This is a very fast way to sort an item into a list. var/list/sorted_text = new() var/low_index var/high_index var/insert_index var/midway_calc var/current_index var/current_item var/list/list_bottom var/sort_result var/current_sort_text for (current_sort_text in incoming) low_index = 1 high_index = sorted_text.len while (low_index <= high_index) // Figure out the midpoint, rounding up for fractions. (BYOND rounds down, so add 1 if necessary.) midway_calc = (low_index + high_index) / 2 current_index = round(midway_calc) if (midway_calc > current_index) current_index++ current_item = sorted_text[current_index] if (case_sensitive) sort_result = sorttextEx(current_sort_text, current_item) else sort_result = sorttext(current_sort_text, current_item) switch(sort_result) if (1) high_index = current_index - 1 // current_sort_text < current_item if (-1) low_index = current_index + 1 // current_sort_text > current_item if (0) low_index = current_index // current_sort_text == current_item break // Insert before low_index. insert_index = low_index // Special case adding to end of list. if (insert_index > sorted_text.len) sorted_text += current_sort_text continue // Because BYOND lists don't support insert, have to do it by: // 1) taking out bottom of list, 2) adding item, 3) putting back bottom of list. list_bottom = sorted_text.Copy(insert_index) sorted_text.Cut(insert_index) sorted_text += current_sort_text sorted_text += list_bottom return sorted_text proc/dd_sortedTextList(list/incoming) var/case_sensitive = 1 return dd_sortedtextlist(incoming, case_sensitive) datum/proc/dd_SortValue() return "[src]" /obj/machinery/dd_SortValue() return "[sanitize_old(name)]" /obj/machinery/camera/dd_SortValue() return "[c_tag]" /datum/alarm/dd_SortValue() return "[sanitize_old(last_name)]" //creates every subtype of prototype (excluding prototype) and adds it to list L. //if no list/L is provided, one is created. /proc/init_subtypes(prototype, list/L) if(!istype(L)) L = list() for(var/path in (typesof(prototype) - prototype)) L += new path() return L