diff --git a/artifacts/scripting/arrays.txt b/artifacts/scripting/arrays.txt index 482e27a6..71c60e97 100644 --- a/artifacts/scripting/arrays.txt +++ b/artifacts/scripting/arrays.txt @@ -169,6 +169,7 @@ Example: - if used on list, "key" must be numeric and within valid index range (0..size-1) - if used on map, key can be of any type - to "unset" a value from map, just set it to zero (0) +- NOTE: to add a value of 0 for the key, use the float value (0.0) - this works exactly like statement: arrayID[key] := value; diff --git a/artifacts/scripting/headers/sfall.h b/artifacts/scripting/headers/sfall.h index f1a8cb9c..851e1e80 100644 --- a/artifacts/scripting/headers/sfall.h +++ b/artifacts/scripting/headers/sfall.h @@ -114,14 +114,18 @@ #define array_exists(array) (len_array(array) != -1) // remove all elements from array #define clear_array(array) resize_array(array, 0) -// sort array in ascending order +// sort array or map by key in ascending order #define sort_array(array) resize_array(array, -2) -// sort array in descending order +// sort array or map by key in descending order #define sort_array_reverse(array) resize_array(array, -3) -// reverse elements in list +// reverse elements in list/map #define reverse_array(array) resize_array(array, -4) -// randomly shuffle elements in list +// randomly shuffle elements in list/map #define shuffle_array(array) resize_array(array, -5) +// sort map in ascending order by value +#define sort_map_value(array) resize_array(array, -6) +// sort map in descending order by value +#define sort_map_value_desc(array) resize_array(array, -7) // remove element from map or just replace value with 0 for list #define unset_array(array, item) set_array(array, item, 0) // same as "key_pressed" but checks VK codes instead of DX codes diff --git a/sfall/Arrays.cpp b/sfall/Arrays.cpp index a252051d..b79c29bd 100644 --- a/sfall/Arrays.cpp +++ b/sfall/Arrays.cpp @@ -498,6 +498,60 @@ int _stdcall LenArray(DWORD id) { else return arrays[id].size(); } +template +static void ListSort(std::vector &arr, int type) { + switch (type) { + case ARRAY_ACTION_SORT: // sort ascending + std::sort(arr.begin(), arr.end()); + break; + case ARRAY_ACTION_RSORT: // sort descending + std::sort(arr.rbegin(), arr.rend()); + break; + case ARRAY_ACTION_REVERSE: // reverse elements + std::reverse(arr.rbegin(), arr.rend()); + break; + case ARRAY_ACTION_SHUFFLE: // shuffle elements + std::random_shuffle(arr.rbegin(), arr.rend()); + break; + } +} + +static void MapSort(sArrayVar& arr, int type) { + std::vector> map; + bool sortByValue = false; + if (type < ARRAY_ACTION_SHUFFLE) { + type += 4; + sortByValue = true; + } + + sArrayElement key, val; + for (size_t i = 0; i < arr.val.size(); ++i) { + if (sortByValue) { + val = arr.val[i++]; // map key > value + key = arr.val[i]; // map value > key + } else { + key = arr.val[i]; // key + val = arr.val[++i]; // value + } + map.push_back(std::make_pair(key, val)); + } + ListSort(map, type); + + arr.val.clear(); + arr.keyHash.clear(); + for (size_t i = 0; i < map.size(); ++i) { + size_t el = arr.val.size(); + if (sortByValue) { + arr.val.push_back(map[i].second); // map value > key + arr.val.push_back(map[i].first); // map key > value + } else { + arr.val.push_back(map[i].first); + arr.val.push_back(map[i].second); + } + arr.keyHash[arr.val[el]] = el; + } +} + void _stdcall ResizeArray(DWORD id, int newlen) { if (newlen == -1 || arrays.find(id) == arrays.end() || arrays[id].size() == newlen) return; sArrayVar &arr = arrays[id]; @@ -514,7 +568,11 @@ void _stdcall ResizeArray(DWORD id, int newlen) { arr.clearRange(actualLen); arr.val.resize(actualLen); } else if (newlen < 0) { - DebugPrintf("\nOPCODE ERROR: resize_array() - array sorting error."); + if (newlen < (ARRAY_ACTION_SHUFFLE - 2)) { + DebugPrintf("\nOPCODE ERROR: resize_array() - array sorting error."); + return; + } + MapSort(arr, newlen); } return; } @@ -529,20 +587,7 @@ void _stdcall ResizeArray(DWORD id, int newlen) { DebugPrintf("\nOPCODE ERROR: resize_array() - array sorting error."); return; } - switch (newlen) { - case ARRAY_ACTION_SORT: // sort ascending - std::sort(arr.val.begin(), arr.val.end()); - break; - case ARRAY_ACTION_RSORT: // sort descending - std::sort(arr.val.rbegin(), arr.val.rend()); - break; - case ARRAY_ACTION_REVERSE: // reverse elements - std::reverse(arr.val.rbegin(), arr.val.rend()); - break; - case ARRAY_ACTION_SHUFFLE: // shuffle elements - std::random_shuffle(arr.val.rbegin(), arr.val.rend()); - break; - } + ListSort(arr.val, newlen); } }