mirror of
https://github.com/sfall-team/sfall.git
synced 2026-07-27 16:52:34 -07:00
Expanded create/temp_array functions to allow creating a new "lookup" type of associative array (from Mr.Stalin)
This commit is contained in:
@@ -9,21 +9,21 @@ Array elements are accessed by index or key. For example:
|
|||||||
|
|
||||||
// this code puts some string in array "list" at index 5:
|
// this code puts some string in array "list" at index 5:
|
||||||
list[5] := "Value";
|
list[5] := "Value";
|
||||||
|
|
||||||
|
|
||||||
There are 2 different types of arrays currently available:
|
There are 2 different types of arrays currently available:
|
||||||
1) Lists - a set of values with specific size (number of elements), where all elements have numeric indexes starting from zero (0) up to array length minus one.
|
1) Lists - a set of values with specific size (number of elements), where all elements have numeric indexes starting from zero (0) up to array length minus one.
|
||||||
For example:
|
For example:
|
||||||
|
|
||||||
// this creates list with 3 elements. Element "A" has index 0, element "B" has index 1, element "C" - 2
|
// this creates list with 3 elements. Element "A" has index 0, element "B" has index 1, element "C" - 2
|
||||||
list := ["A", "B", "C"];
|
list := ["A", "B", "C"];
|
||||||
|
|
||||||
Limitations:
|
Limitations:
|
||||||
- all indexes are numeric, starting from 0;
|
- all indexes are numeric, starting from 0;
|
||||||
- to assign value to a specific index, you must first resize array to contain this index
|
- to assign value to a specific index, you must first resize array to contain this index
|
||||||
(for example, if list is of size 3 (indexes from 0 to 2), you can't assign value to index 4 unless you change list size to 5 first).
|
(for example, if list is of size 3 (indexes from 0 to 2), you can't assign value to index 4 unless you change list size to 5 first).
|
||||||
|
|
||||||
|
|
||||||
2) Maps (or associative arrays) - a set of key=>value pairs, where all elements (values) are accessed by corresponding keys.
|
2) Maps (or associative arrays) - a set of key=>value pairs, where all elements (values) are accessed by corresponding keys.
|
||||||
Differences from list:
|
Differences from list:
|
||||||
- maps don't have specific size (to assign values, you don't need to resize array first);
|
- maps don't have specific size (to assign values, you don't need to resize array first);
|
||||||
@@ -37,24 +37,24 @@ Both array types have their pros and cons and are suited for different tasks.
|
|||||||
Basically arrays are implemented using number of new operators (scripting functions). But for ease of use, there are some new syntax elements:
|
Basically arrays are implemented using number of new operators (scripting functions). But for ease of use, there are some new syntax elements:
|
||||||
|
|
||||||
1) Accessing elements. Use square brackets:
|
1) Accessing elements. Use square brackets:
|
||||||
|
|
||||||
display_msg(arr[5]);
|
display_msg(arr[5]);
|
||||||
mymap["price"] := 515.23;
|
mymap["price"] := 515.23;
|
||||||
|
|
||||||
2) Alternative accessing for maps. Use dot:
|
2) Alternative accessing for maps. Use dot:
|
||||||
|
|
||||||
display_msg(mymap.name);
|
display_msg(mymap.name);
|
||||||
mymap.price := 232.23;
|
mymap.price := 232.23;
|
||||||
|
|
||||||
3) Array expressions. Create and fill arrays with just one expression:
|
3) Array expressions. Create and fill arrays with just one expression:
|
||||||
|
|
||||||
// create list with 5 values
|
// create list with 5 values
|
||||||
[5, 777, 0, 3.14, "Cool Value"]
|
[5, 777, 0, 3.14, "Cool Value"]
|
||||||
|
|
||||||
// create map:
|
// create map:
|
||||||
{5: "Five", "health": 50, "speed": 0.252}
|
{5: "Five", "health": 50, "speed": 0.252}
|
||||||
|
|
||||||
NOTES:
|
NOTES:
|
||||||
- make sure to call "fix_array" if you want new array to be available in the next frame or "save_array" if you want to use it for a longer period
|
- make sure to call "fix_array" if you want new array to be available in the next frame or "save_array" if you want to use it for a longer period
|
||||||
(see next section for details)
|
(see next section for details)
|
||||||
|
|
||||||
@@ -64,16 +64,16 @@ NOTES:
|
|||||||
foreach (item in myarray) begin
|
foreach (item in myarray) begin
|
||||||
// this block is executed for each array element, where "item" contains current value on each step
|
// this block is executed for each array element, where "item" contains current value on each step
|
||||||
end
|
end
|
||||||
|
|
||||||
// alternative syntax:
|
// alternative syntax:
|
||||||
foreach (key: item in myarray) begin
|
foreach (key: item in myarray) begin
|
||||||
// "key" will contain current key (or numeric index, for lists)
|
// "key" will contain current key (or numeric index, for lists)
|
||||||
end
|
end
|
||||||
|
|
||||||
See "Script editor\docs\sslc readme.txt" file for full information on new SSL syntax features.
|
See "Script editor\docs\sslc readme.txt" file for full information on new SSL syntax features.
|
||||||
|
|
||||||
>>> STORING ARRAYS <<<
|
>>> STORING ARRAYS <<<
|
||||||
|
|
||||||
Apart from lists/maps arrays are divided by how they are stored.
|
Apart from lists/maps arrays are divided by how they are stored.
|
||||||
There a 3 types of arrays:
|
There a 3 types of arrays:
|
||||||
|
|
||||||
@@ -85,21 +85,21 @@ where you create temp_array, it will not be available next time your global scri
|
|||||||
This type of arrays are always available (by their ID) until you start a new game or load a saved game (at which point they are deleted).
|
This type of arrays are always available (by their ID) until you start a new game or load a saved game (at which point they are deleted).
|
||||||
|
|
||||||
3) Saved. If you want your array to really stay for a while, use function "save_array" to make any array "saved". However, they are, like permanent arrays,
|
3) Saved. If you want your array to really stay for a while, use function "save_array" to make any array "saved". However, they are, like permanent arrays,
|
||||||
"deleted" from memory when loading game. In order to use them properly, you must load them from the savegame using "load_array" whenever you want to use them.
|
"deleted" from memory when loading game. In order to use them properly, you must load them from the savegame using "load_array" whenever you want to use them.
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
variable savedArray;
|
variable savedArray;
|
||||||
procedure start begin
|
procedure start begin
|
||||||
if game_loaded then begin
|
if game_loaded then begin
|
||||||
savedArray := load_array("traps");
|
savedArray := load_array("traps");
|
||||||
end else begin
|
end else begin
|
||||||
foreach trap in traps begin
|
foreach trap in traps begin
|
||||||
....
|
....
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
>>> PRACTICAL EXAMPLES <<<
|
>>> PRACTICAL EXAMPLES <<<
|
||||||
|
|
||||||
@@ -114,8 +114,8 @@ Example:
|
|||||||
|
|
||||||
// call it:
|
// call it:
|
||||||
call give_item(dude_obj, {PID_SHOTGUN: 1, PID_SHOTGUN_SHELLS: 4, PID_STIMPAK: 3});
|
call give_item(dude_obj, {PID_SHOTGUN: 1, PID_SHOTGUN_SHELLS: 4, PID_STIMPAK: 3});
|
||||||
|
|
||||||
|
|
||||||
> Create arrays of objects (maps) for advanced scripting:
|
> Create arrays of objects (maps) for advanced scripting:
|
||||||
|
|
||||||
variable traps;
|
variable traps;
|
||||||
@@ -130,14 +130,14 @@ Example:
|
|||||||
traps[k] := load_array("trap_"+k); // each object is stored separately
|
traps[k] := load_array("trap_"+k); // each object is stored separately
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
procedure add_trap(variable trapArray) begin
|
procedure add_trap(variable trapArray) begin
|
||||||
variable index;
|
variable index;
|
||||||
index := len_array(traps);
|
index := len_array(traps);
|
||||||
save_array("trap_"+k, trapArray);
|
save_array("trap_"+k, trapArray);
|
||||||
array_push(traps, trapArray);
|
array_push(traps, trapArray);
|
||||||
end
|
end
|
||||||
|
|
||||||
// use them:
|
// use them:
|
||||||
foreach trap in traps begin
|
foreach trap in traps begin
|
||||||
if (self_elevation == trap["elev"] and tile_distance(self_tile, trap["tile"]) < trap["radius"]) then
|
if (self_elevation == trap["elev"] and tile_distance(self_tile, trap["tile"]) < trap["radius"]) then
|
||||||
@@ -151,14 +151,16 @@ Example:
|
|||||||
|
|
||||||
*mixed means any type
|
*mixed means any type
|
||||||
|
|
||||||
> int create_array(int size, int nothing):
|
> int create_array(int size, int flags):
|
||||||
- creates permanent array (but not "saved")
|
- creates permanent array (but not "saved")
|
||||||
- if size is >= 0, creates list with given size
|
- if size is >= 0, creates list with given size
|
||||||
- if size == -1, creates map (associative array)
|
- if size == -1, creates map (associative array)
|
||||||
- second argument is not used yet, just use 0
|
- if size == -1 and flags == 2, creates a "lookup" map in which the values of existing keys are read-only and can't be updated.
|
||||||
|
This type of array allows you to store a zero (0) value for a key
|
||||||
|
- NOTE: in earlier versions (up to 4.1.3/3.8.13) the second argument is not used, just use 0
|
||||||
- returns arrayID (valid until array is deleted)
|
- returns arrayID (valid until array is deleted)
|
||||||
|
|
||||||
> int temp_array(int size, int nothing):
|
> int temp_array(int size, int flags):
|
||||||
- works exactly like "create_array", only created array becomes "temporary"
|
- works exactly like "create_array", only created array becomes "temporary"
|
||||||
|
|
||||||
> void fix_array(int arrayID):
|
> void fix_array(int arrayID):
|
||||||
@@ -169,6 +171,7 @@ Example:
|
|||||||
- if used on list, "key" must be numeric and within valid index range (0..size-1)
|
- 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
|
- if used on map, key can be of any type
|
||||||
- to "unset" a value from map, just set it to zero (0)
|
- 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 of 0.0
|
||||||
- this works exactly like statement:
|
- this works exactly like statement:
|
||||||
arrayID[key] := value;
|
arrayID[key] := value;
|
||||||
|
|
||||||
@@ -182,7 +185,7 @@ Example:
|
|||||||
- changes array size
|
- changes array size
|
||||||
- applicable to maps too, but only to reduce elements
|
- applicable to maps too, but only to reduce elements
|
||||||
- there are number of special negative values of "size" which perform various operations on the array,
|
- there are number of special negative values of "size" which perform various operations on the array,
|
||||||
use macros sort_array, sort_array_reverse, reverse_array, shuffle_array from sfall.h header
|
use macros sort_array, sort_array_reverse, reverse_array, shuffle_array from sfall.h header
|
||||||
|
|
||||||
> void free_array(int arrayID):
|
> void free_array(int arrayID):
|
||||||
- deletes any array
|
- deletes any array
|
||||||
|
|||||||
@@ -20,6 +20,9 @@
|
|||||||
/*
|
/*
|
||||||
Generic array functions
|
Generic array functions
|
||||||
*/
|
*/
|
||||||
|
// returns True if the specified key exists in the associative array
|
||||||
|
procedure map_contains_key(variable arrayMap, variable key);
|
||||||
|
|
||||||
// push new item at the end of array, returns array
|
// push new item at the end of array, returns array
|
||||||
procedure array_push(variable array, variable item);
|
procedure array_push(variable array, variable item);
|
||||||
|
|
||||||
@@ -151,6 +154,14 @@ procedure load_collection(variable name);
|
|||||||
|
|
||||||
#define ARRAY_SET_BLOCK_SIZE (10)
|
#define ARRAY_SET_BLOCK_SIZE (10)
|
||||||
|
|
||||||
|
procedure map_contains_key(variable arrayMap, variable key) begin
|
||||||
|
variable i;
|
||||||
|
for (i := 0; i < len_array(arrayMap); i++) begin
|
||||||
|
if (array_key(arrayMap, i) == key) then return true;
|
||||||
|
end
|
||||||
|
return false;
|
||||||
|
end
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns first index of zero value
|
* Returns first index of zero value
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -117,6 +117,10 @@
|
|||||||
#define create_array_map (create_array(-1, 0))
|
#define create_array_map (create_array(-1, 0))
|
||||||
// create temporary map
|
// create temporary map
|
||||||
#define temp_array_map (temp_array(-1, 0))
|
#define temp_array_map (temp_array(-1, 0))
|
||||||
|
// create persistent lookup map (see arrays.txt for details)
|
||||||
|
#define create_lookup_map (create_array(-1, 2))
|
||||||
|
// create temporary lookup map
|
||||||
|
#define temp_lookup_map (temp_array(-1, 2))
|
||||||
// true if array is map, false otherwise
|
// true if array is map, false otherwise
|
||||||
#define array_is_map(x) (array_key(x, -1) == 1)
|
#define array_is_map(x) (array_key(x, -1) == 1)
|
||||||
// returns temp list with names of all arrays saved with save_array() in alphabetical order
|
// returns temp list with names of all arrays saved with save_array() in alphabetical order
|
||||||
|
|||||||
@@ -132,13 +132,13 @@
|
|||||||
0x819d - void set_sfall_global(string/int varname, int/float value)
|
0x819d - void set_sfall_global(string/int varname, int/float value)
|
||||||
0x819e - int get_sfall_global_int(string/int varname)
|
0x819e - int get_sfall_global_int(string/int varname)
|
||||||
0x819f - float get_sfall_global_float(string/int varname)
|
0x819f - float get_sfall_global_float(string/int varname)
|
||||||
0x822d - int create_array(int elementcount, int elementsize)
|
0x822d - int create_array(int elementcount, int flags)
|
||||||
0x822e - void set_array(int array, any element, any value)
|
0x822e - void set_array(int array, any element, any value)
|
||||||
0x822f - any get_array(int array, any element)
|
0x822f - any get_array(int array, any element)
|
||||||
0x8230 - void free_array(int array)
|
0x8230 - void free_array(int array)
|
||||||
0x8231 - int len_array(int array)
|
0x8231 - int len_array(int array)
|
||||||
0x8232 - void resize_array(int array, int newelementcount)
|
0x8232 - void resize_array(int array, int newelementcount)
|
||||||
0x8233 - int temp_array(int elementcount, int elementsize)
|
0x8233 - int temp_array(int elementcount, int flags)
|
||||||
0x8234 - void fix_array(int array)
|
0x8234 - void fix_array(int array)
|
||||||
0x8239 - int scan_array(int array, int/float var)
|
0x8239 - int scan_array(int array, int/float var)
|
||||||
0x8256 - int array_key(int array, int index)
|
0x8256 - int array_key(int array, int index)
|
||||||
|
|||||||
@@ -319,16 +319,19 @@ void DESetArray(int id, const DWORD* types, const void* data) {
|
|||||||
//memcpy(arrays[id].data, data, arrays[id].len*arrays[id].datalen);
|
//memcpy(arrays[id].data, data, arrays[id].len*arrays[id].datalen);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Array manipulation functions for script operators
|
Array manipulation functions for script operators
|
||||||
TODO: move somewhere else
|
TODO: move somewhere else
|
||||||
*/
|
*/
|
||||||
|
|
||||||
DWORD _stdcall CreateArray(int len, DWORD nothing) {
|
DWORD _stdcall CreateArray(int len, DWORD flags) {
|
||||||
sArrayVar var;
|
sArrayVar var;
|
||||||
if (len < 0) var.flags |= ARRAYFLAG_ASSOC;
|
var.flags = (flags & 0xFFFFFFFE); // reset 1 bit
|
||||||
else if (len > ARRAY_MAX_SIZE) len = ARRAY_MAX_SIZE; // safecheck
|
if (len < 0) {
|
||||||
|
var.flags |= ARRAYFLAG_ASSOC;
|
||||||
|
} else if (len > ARRAY_MAX_SIZE) {
|
||||||
|
len = ARRAY_MAX_SIZE; // safecheck
|
||||||
|
}
|
||||||
if (!var.isAssoc()) {
|
if (!var.isAssoc()) {
|
||||||
var.val.resize(len);
|
var.val.resize(len);
|
||||||
}
|
}
|
||||||
@@ -343,8 +346,8 @@ DWORD _stdcall CreateArray(int len, DWORD nothing) {
|
|||||||
return nextarrayid++;
|
return nextarrayid++;
|
||||||
}
|
}
|
||||||
|
|
||||||
DWORD _stdcall TempArray(DWORD len, DWORD nothing) {
|
DWORD _stdcall TempArray(DWORD len, DWORD flags) {
|
||||||
DWORD id = CreateArray(len, nothing);
|
DWORD id = CreateArray(len, flags);
|
||||||
tempArrays.insert(id);
|
tempArrays.insert(id);
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
@@ -428,7 +431,11 @@ void _stdcall SetArray(DWORD id, const ScriptValue& key, const ScriptValue& val,
|
|||||||
el = (elIter != arr.keyHash.end())
|
el = (elIter != arr.keyHash.end())
|
||||||
? elIter->second
|
? elIter->second
|
||||||
: -1;
|
: -1;
|
||||||
if (val.isInt() && val.asInt() == 0 && allowUnset) {
|
|
||||||
|
bool lookupMap = (arr.flags & ARRAYFLAG_CONSTVAL) != 0;
|
||||||
|
if (lookupMap && el != -1) return; // don't update value of key
|
||||||
|
|
||||||
|
if (allowUnset && !lookupMap && (val.isInt() && val.rawValue() == 0)) {
|
||||||
// after assigning zero to a key, no need to store it, because "get_array" returns 0 for non-existent keys: try unset
|
// after assigning zero to a key, no need to store it, because "get_array" returns 0 for non-existent keys: try unset
|
||||||
if (el >= 0) {
|
if (el >= 0) {
|
||||||
// remove from hashtable
|
// remove from hashtable
|
||||||
@@ -464,12 +471,12 @@ void _stdcall SetArray(DWORD id, const ScriptValue& key, const ScriptValue& val,
|
|||||||
}
|
}
|
||||||
|
|
||||||
int _stdcall LenArray(DWORD id) {
|
int _stdcall LenArray(DWORD id) {
|
||||||
if (arrays.find(id)==arrays.end()) return -1;
|
if (arrays.find(id) == arrays.end()) return -1;
|
||||||
else return arrays[id].size();
|
else return arrays[id].size();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
void ListSort(std::vector<T> &arr, int type) {
|
static void ListSort(std::vector<T> &arr, int type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case ARRAY_ACTION_SORT: // sort ascending
|
case ARRAY_ACTION_SORT: // sort ascending
|
||||||
std::sort(arr.begin(), arr.end());
|
std::sort(arr.begin(), arr.end());
|
||||||
@@ -486,7 +493,7 @@ void ListSort(std::vector<T> &arr, int type) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MapSort(sArrayVar& arr, int type) {
|
static void MapSort(sArrayVar& arr, int type) {
|
||||||
std::vector<std::pair<sArrayElement, sArrayElement>> map;
|
std::vector<std::pair<sArrayElement, sArrayElement>> map;
|
||||||
bool sortByValue = false;
|
bool sortByValue = false;
|
||||||
if (type < ARRAY_ACTION_SHUFFLE) {
|
if (type < ARRAY_ACTION_SHUFFLE) {
|
||||||
@@ -568,17 +575,17 @@ ScriptValue _stdcall ScanArray(DWORD id, const ScriptValue& val) {
|
|||||||
for (size_t i = 0; i < arrays[id].val.size(); i += step) {
|
for (size_t i = 0; i < arrays[id].val.size(); i += step) {
|
||||||
sArrayElement &el = arrays[id].val[i + step - 1];
|
sArrayElement &el = arrays[id].val[i + step - 1];
|
||||||
if (el.type == val.type()) {
|
if (el.type == val.type()) {
|
||||||
if ((!val.isString() && static_cast<DWORD>(el.intVal) == val.rawValue()) ||
|
if ((!val.isString() && static_cast<DWORD>(el.intVal) == val.rawValue()) ||
|
||||||
(val.isString() && strcmp(el.strVal, val.asString()) == 0)) {
|
(val.isString() && strcmp(el.strVal, val.asString()) == 0)) {
|
||||||
if (arrays[id].isAssoc()) { // return key instead of index for associative arrays
|
if (arrays[id].isAssoc()) { // return key instead of index for associative arrays
|
||||||
return ScriptValue(
|
return ScriptValue(
|
||||||
static_cast<DataType>(arrays[id].val[i].type),
|
static_cast<DataType>(arrays[id].val[i].type),
|
||||||
static_cast<DWORD>(arrays[id].val[i].intVal)
|
static_cast<DWORD>(arrays[id].val[i].intVal)
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return ScriptValue(static_cast<int>(i));
|
return ScriptValue(static_cast<int>(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ScriptValue(-1);
|
return ScriptValue(-1);
|
||||||
|
|||||||
@@ -82,6 +82,7 @@ struct sArrayVarOld
|
|||||||
};
|
};
|
||||||
|
|
||||||
#define ARRAYFLAG_ASSOC (1) // is map
|
#define ARRAYFLAG_ASSOC (1) // is map
|
||||||
|
#define ARRAYFLAG_CONSTVAL (2) // don't update value of key if the key exists in map
|
||||||
|
|
||||||
typedef std::unordered_map<sArrayElement, DWORD, sArrayElement_HashFunc, sArrayElement_EqualFunc> ArrayKeysMap;
|
typedef std::unordered_map<sArrayElement, DWORD, sArrayElement_HashFunc, sArrayElement_EqualFunc> ArrayKeysMap;
|
||||||
|
|
||||||
@@ -154,9 +155,9 @@ void DEGetArray(int id, DWORD* types, void* data);
|
|||||||
void DESetArray(int id, const DWORD* types, const void* data);
|
void DESetArray(int id, const DWORD* types, const void* data);
|
||||||
|
|
||||||
// creates new normal (persistent) array. len == -1 specifies associative array (map)
|
// creates new normal (persistent) array. len == -1 specifies associative array (map)
|
||||||
DWORD _stdcall CreateArray(int len, DWORD nothing);
|
DWORD _stdcall CreateArray(int len, DWORD flags);
|
||||||
// same as CreateArray, but creates temporary array instead (will die at the end of the frame)
|
// same as CreateArray, but creates temporary array instead (will die at the end of the frame)
|
||||||
DWORD _stdcall TempArray(DWORD len, DWORD nothing);
|
DWORD _stdcall TempArray(DWORD len, DWORD flags);
|
||||||
// destroys array
|
// destroys array
|
||||||
void _stdcall FreeArray(DWORD id);
|
void _stdcall FreeArray(DWORD id);
|
||||||
/*
|
/*
|
||||||
|
|||||||
Reference in New Issue
Block a user