Expanded create/temp_array functions to allow creating a new "lookup" type of associative array (from Mr.Stalin)

This commit is contained in:
NovaRain
2019-01-08 06:52:00 +08:00
parent 4f48926105
commit e320acce0b
7 changed files with 81 additions and 52 deletions
+1 -1
View File
@@ -1,5 +1,5 @@
;Controls the elevators ;Controls the elevators
;Image must match up with the image of an existing elevator (can be overrided in sfall 3.8.14 or newer) ;Image must match up with the image of an existing elevator (can be overrided in sfall 4.1.4/3.8.14 or newer)
;Make sure you specify the correct number of exit targets ;Make sure you specify the correct number of exit targets
;The maximum number of elevators is currently capped at 50 ;The maximum number of elevators is currently capped at 50
;Use the line number (0-indexed) of the corresponding FRM in intrface.lst to set the appearance of the elevator ;Use the line number (0-indexed) of the corresponding FRM in intrface.lst to set the appearance of the elevator
+29 -27
View File
@@ -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) key value
- 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,7 +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 (0.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;
@@ -183,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
+11
View File
@@ -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
*/ */
+4
View File
@@ -102,6 +102,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
+2 -2
View File
@@ -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)
+31 -20
View File
@@ -312,7 +312,6 @@ 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
@@ -359,10 +358,14 @@ DWORD _stdcall getScriptTypeBySfallType(DWORD dataType) {
} }
} }
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);
} }
@@ -377,8 +380,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;
} }
@@ -421,7 +424,7 @@ DWORD _stdcall GetArrayKey(DWORD id, int index, DWORD* resultType) {
DWORD _stdcall GetArray(DWORD id, DWORD key, DWORD keyType, DWORD* resultType) { DWORD _stdcall GetArray(DWORD id, DWORD key, DWORD keyType, DWORD* resultType) {
*resultType = VAR_TYPE_INT; *resultType = VAR_TYPE_INT;
if(arrays.find(id)==arrays.end()) return 0; if (arrays.find(id) == arrays.end()) return 0;
int el; int el;
sArrayVar &arr = arrays[id]; sArrayVar &arr = arrays[id];
if (arr.isAssoc()) { if (arr.isAssoc()) {
@@ -448,17 +451,24 @@ DWORD _stdcall GetArray(DWORD id, DWORD key, DWORD keyType, DWORD* resultType) {
} }
return 0; return 0;
} }
void _stdcall SetArray(DWORD id, DWORD key, DWORD keyType, DWORD val, DWORD valType, DWORD allowUnset) { void _stdcall SetArray(DWORD id, DWORD key, DWORD keyType, DWORD val, DWORD valType, DWORD allowUnset) {
keyType = getSfallTypeByScriptType(keyType); keyType = getSfallTypeByScriptType(keyType);
valType = getSfallTypeByScriptType(valType); valType = getSfallTypeByScriptType(valType);
if(arrays.find(id)==arrays.end()) return; if (arrays.find(id) == arrays.end()) return;
int el; int el;
sArrayVar &arr = arrays[id]; sArrayVar &arr = arrays[id];
if (arrays[id].isAssoc()) { if (arrays[id].isAssoc()) {
sArrayElement sEl(key, keyType); sArrayElement sEl(key, keyType);
ArrayKeysMap::iterator elIter = arr.keyHash.find(sEl); ArrayKeysMap::iterator elIter = arr.keyHash.find(sEl);
el = (elIter != arr.keyHash.end()) ? elIter->second : -1; el = (elIter != arr.keyHash.end())
if (valType == DATATYPE_INT && val == 0 && allowUnset) { ? elIter->second
: -1;
bool lookupMap = (arr.flags & ARRAYFLAG_CONSTVAL) != 0;
if (lookupMap && el != -1) return; // don't update value of key
if (allowUnset && !lookupMap && (valType == DATATYPE_INT && val == 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
@@ -603,15 +613,15 @@ int _stdcall ScanArray(DWORD id, DWORD val, DWORD datatype, DWORD* resultType) {
for (DWORD i = 0; i < arrays[id].val.size(); i += step) { for (DWORD 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 == datatype) { if (el.type == datatype) {
if ((datatype != DATATYPE_STR && *(DWORD*)&(el.intVal) == val) || if ((datatype != DATATYPE_STR && *(DWORD*)&(el.intVal) == val) ||
(datatype == DATATYPE_STR && strcmp(el.strVal, (char*)val) == 0)) { (datatype == DATATYPE_STR && strcmp(el.strVal, (char*)val) == 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
*resultType = getScriptTypeBySfallType(arrays[id].val[i].type); *resultType = getScriptTypeBySfallType(arrays[id].val[i].type);
return *(DWORD *)&arrays[id].val[i].intVal; return *(DWORD *)&arrays[id].val[i].intVal;
} else { } else {
return i; return i;
} }
} }
} }
} }
return -1; return -1;
@@ -635,8 +645,9 @@ DWORD _stdcall LoadArray(DWORD key, DWORD keyType) {
} }
} else { } else {
ArrayKeysMap::iterator it = savedArrays.find(keyEl); ArrayKeysMap::iterator it = savedArrays.find(keyEl);
if (it != savedArrays.end()) if (it != savedArrays.end()) {
return it->second; return it->second;
}
} }
} }
return 0; // not found return 0; // not found
+3 -2
View File
@@ -74,6 +74,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::tr1::unordered_map<sArrayElement, DWORD, sArrayElement_HashFunc, sArrayElement_EqualFunc> ArrayKeysMap; typedef std::tr1::unordered_map<sArrayElement, DWORD, sArrayElement_HashFunc, sArrayElement_EqualFunc> ArrayKeysMap;
@@ -148,9 +149,9 @@ const char* _stdcall GetSfallTypeName(DWORD dataType);
DWORD _stdcall getSfallTypeByScriptType(DWORD varType); DWORD _stdcall getSfallTypeByScriptType(DWORD varType);
DWORD _stdcall getScriptTypeBySfallType(DWORD dataType); DWORD _stdcall getScriptTypeBySfallType(DWORD dataType);
// 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);
/* /*