NOTE: the following scripts have NOT been tested on singleplayer world map (they should be used inside missions only).
1. List system
Based on Lumos version (clicky) of list system, I've made a more general list system (which can use more than one list).
How to install:
1. Copy all scripts (from the spoiler below) inside module_scripts, before the last ']'
2. Done!
Creating a list: each list is represented by a troop entry inside module troops. To create one new list you need to make a new troop inside module_troops, preferably starting with 'list_' and being somewhere at the bottom of the troops list (so you don't mess any loop or script that loops over troops).
Clearing a list: is done by calling script 'list_clear' with the desired list to be cleared.
Adding elements/values to a list: it can be done in two ways:
1. Appending an element (or adding it to the end of the list) - is done by calling script "list_add" with the list and the desired value.
2. Adding an element on a specified index - is done by calling "list_add_at" with the list, value and index. If the index is greater than the last valid list index, the value will be appended to the end of the list. It does not handle negative indexes!(Error will pop) Note: it does not replace a value, it will insert it there
Modifying a value: it is done by calling script "list_set" with list, value and index. If the index is invalid, it will do nothing.
Getting a value: is done by calling script "list_at" with list and index. The returned value is stored in reg1. If the index is invalid, it returns 0.
Removing a value: can be done in 3 ways:
1. Removing the last element from the list - by calling script "list_remove" with list id.
2. Removing by index - by calling 'list_remove_at' with list id and index.
3. Removing by value - by calling 'list_remove_val' with list id and value.
Getting number of elements : is done by calling 'list_count' with list id. Th returned value is stored in reg1.
Getting the last element : is done by calling 'list_last' with list id. The returned value is stored in reg1.
Getting index of a value : is done by calling 'list_index_of' with list id and value. The returned value is stored in reg1. If the value is not found, -1 is returned.
Getting random element : is done by calling 'list_random' with list id. reg1 will contain the value of the random element and reg2 wil contain the index of the element.
Notes:
1. if you are modifying a list inside a mission (like adding agents ids or player ids), then you need to clear it at the beginning of the mission (because if you change the mission, the list will not be reset by the game, leaving the old list's values unchanged).
2. the indexes are 1 based. index 0 is invalid.
2. Timed callbacks system
The timed callbacks system allows you to call a script with a delay. Normally, if you would want something to be called after a period of time, you would need to set up triggers that would check when that thing should be called. With this system you can do that in just one line of code.
Very important note - these scripts requires list system AND dynamic memory to be installed!!!!!!!!!!!
How to install:
1. Copy the scripts (from the 'scripts' spoiler below) inside module_scripts, before the last ']'
2. Add '(call_script, "script_init_callbacks"),' in trigger 'ti_before_mission_start' (in each mission template which will use the timed callbacks system)
3. Add the trigger (from the 'trigger' spoiler below) in each mission template which will use the timed callbacks system
Notes:
1. there is a maximum of 10 parameters that you can pass to a script
2. due to technical reasons, it can't call the script after exactly the amount of time specified. The minimum delay is based on the server fps.
3. the max amount of concurrent registered scripts is not something to worry about because it is somewhere around 1048576 (that is the max slot that can be used for a troop).
3. Dynamic memory
This system allows you to make memory allocations. Because I don't know how to explain it better, I will give some examples.
There are 2 main functions: 'alloc' and 'free'.
'alloc' takes 1 parameter which specifies the amount of elements to allocate. The returned value (is stored in reg0) is a pointer that points to the first element in the allocated memory block.
'free' takes 1 parameter which is a pointer to a block of memory that we want to free.
To read values, we have 2 scripts:
1. 'get' - takes one parameter (a pointer) and returns (in reg0) the value that is being pointed to by the pointer
2. 'v_get' - takes 2 parameters, a pointer and an index. It returns (in reg0) the value that is at the specified index within the vector that is being pointed to by the pointer
To write values, there are another 2 scripts:
1. 'set' - takes two parameters, a pointer and a value. It sets the value that the pointer is pointing to
2. 'v_set' - takes 3 parameters, a pointer, an index and a value. It sets the value that is at the specified index within the vector that the pointer is pointing to
Very important note: this system uses the list system!!! you need to have list system install for it to work!!!!
How to install:
1. Copy the scripts (from the 'scripts' spoiler below) inside module_scripts
2. Add '(call_script, "script_init_memory_management"),' in trigger 'ti_before_mission_start' (in each mission template which will use the dynamic memory system)
3. Copy the troops (from the 'troops' spoiler below) inside module_troops, somewhere at the bottom of the troop list
Notes:
1. The max amount of total allocated elements is limited to 1048576 (or around that number).
2. After you free the memory, you can still use it, but in future it can cause trouble because of a reuse of that memory block (two things using the same memory)
3. There are no index validation. You can edit by mistake other blocks of memory due to a bad index
1. List system
Based on Lumos version (clicky) of list system, I've made a more general list system (which can use more than one list).
How to install:
1. Copy all scripts (from the spoiler below) inside module_scripts, before the last ']'
2. Done!
#-## List management (no dependency)
("list_clear", [
## The list's zero slot holds the number of current items in it
# script_list_clear
# Clears all items from the list
# INPUT: arg1 - list no
# OUTPUT: none
(store_script_param, ":list_no", 1),
(troop_get_slot, ":num_elements", ":list_no", 0),
(val_add, ":num_elements", 1),
(try_for_range, ":slot", 1, ":num_elements"),
(troop_set_slot, ":list_no", ":slot", 0),
(try_end),
(troop_set_slot, ":list_no", 0, 0), # Reset number of elements
]),
("list_at",[
# Returns the value at the specified index, 0 if index is invalid
# INPUT: arg1 - list no; arg2 - index
# OUTPUT: arg1 - value
(store_script_param, ":list_no", 1),
(store_script_param, ":index", 2),
(troop_get_slot, ":num_elements", ":list_no", 0),
(assign, reg1, 0),
(try_begin),
(ge, ":index", 1),
(le, ":index", ":num_elements"),
(troop_get_slot, reg1, ":list_no", ":index"),
(try_end),
]),
("list_at_nc",[
# Returns the value at the specified index; IT DOES NOT CHECK FOR INDEX VALIDITY
# INPUT: arg1 - list no; arg2 - index
# OUTPUT: arg1 - value
(store_script_param, ":list_no", 1),
(store_script_param, ":index", 2),
(troop_get_slot, reg1, ":list_no", ":index"),
]),
("list_set", [
# script_list_set
# Sets an item's, at the specified index
# INPUT: arg1 - list no; arg2 - the value which we will set, arg3 - where we want it (ONE-BASED!)
# OUTPUT: none
(store_script_param, ":list_no", 1),
(store_script_param, ":value", 2),
(store_script_param, ":index", 3),
(troop_get_slot, ":num_elements", ":list_no", 0),
(try_begin),
(ge, ":index", 1),
(le, ":index", ":num_elements"),
(troop_set_slot, ":list_no", ":index", ":value"),
(try_end),
]),
("list_add", [
# script_list_add
# Appends an item to the list
# INPUT: arg1 - list no; arg2 - the value which we will add to the list
# OUTPUT: none
(store_script_param, ":list_no", 1),
(store_script_param, ":value", 2),
(troop_get_slot, ":num_elements", ":list_no", 0),
(val_add, ":num_elements", 1),
(troop_set_slot, ":list_no", ":num_elements", ":value"),
(troop_set_slot, ":list_no", 0, ":num_elements"),
]),
("list_add_at", [
# script_list_add_at
# Appends an item to the list, at the specified index
# INPUT: arg1 - list no; arg2 - the value which we will add to the list, arg3 - where we want it (ONE-BASED!)
# OUTPUT: none
(store_script_param, ":list_no", 1),
(store_script_param, ":value", 2),
(store_script_param, ":index", 3),
(troop_get_slot, ":num_elements", ":list_no", 0),
(val_add, ":num_elements", 1),
(try_begin),
(gt, ":index", ":num_elements"),
(assign, ":index", ":num_elements"),
(try_end),
(try_for_range_backwards, ":slot", ":index", ":num_elements"),
(store_add, ":target", ":slot", 1),
(troop_get_slot, ":val", ":list_no", ":slot"),
(troop_set_slot, ":list_no", ":target", ":val"),
(try_end),
(troop_set_slot, ":list_no", ":index", ":value"),
(troop_set_slot, ":list_no", 0, ":num_elements"),
]),
("list_remove", [
# script_list_remove
# Removes the last item from the list
# INPUT: arg1 - list no
# OUTPUT: none
(store_script_param, ":list_no", 1),
(troop_get_slot, ":num_elements", ":list_no", 0),
(troop_set_slot, ":list_no", ":num_elements", 0),
(val_sub, ":num_elements", 1),
(troop_set_slot, ":list_no", 0, ":num_elements"),
]),
("list_remove_at", [
# script_list_remove_at
# Removes an item from the list, at the specified index
# INPUT: arg1 - list no; arg2 - the index we'll remove from (ONE-BASED!)
# OUTPUT: none
(store_script_param, ":list_no", 1),
(store_script_param, ":index", 2),
(troop_get_slot, ":num_elements", ":list_no", 0),
(try_begin),
(gt, ":index", ":num_elements"),
(assign, ":index", ":num_elements"),
(try_end),
(store_add, ":end", ":num_elements", 1),
(val_sub, ":num_elements", 1),
(store_add, ":start", ":index", 1),
(try_for_range, ":slot", ":start", ":end"),
(troop_get_slot, ":val", ":list_no", ":slot"),
(troop_set_slot, ":list_no", ":index", ":val"),
(val_add, ":index", 1),
(try_end),
(troop_set_slot, ":list_no", 0, ":num_elements"),
]),
("list_remove_val", [
# script_list_remove_val
# Removes a value from the list
# INPUT: arg1 - list no; arg2 - the value we'll remove
# OUTPUT: none
(store_script_param, ":list_no", 1),
(store_script_param, ":value", 2),
(call_script, "script_list_index_of", ":list_no", ":value"),
(try_begin),
(neq, reg1, -1),
(assign, ":index", reg1),
(troop_get_slot, ":num_elements", ":list_no", 0),
(try_begin),
(gt, ":index", ":num_elements"),
(assign, ":index", ":num_elements"),
(try_end),
(store_add, ":end", ":num_elements", 1),
(val_sub, ":num_elements", 1),
(store_add, ":start", ":index", 1),
(try_for_range, ":slot", ":start", ":end"),
(troop_get_slot, ":val", ":list_no", ":slot"),
(troop_set_slot, ":list_no", ":index", ":val"),
(val_add, ":index", 1),
(try_end),
(troop_set_slot, ":list_no", 0, ":num_elements"),
(try_end),
]),
("list_index_of", [
# script_list_index_of
# Returns the index of something from the list
# INPUT: arg1 - list no; arg2 - the value we're looking for
# OUTPUT: reg1 - the index (-1 if not found)
(store_script_param, ":list_no", 1),
(store_script_param, ":val", 2),
(assign, ":index", -1),
(troop_get_slot, ":num_elements", ":list_no", 0),
(val_add, ":num_elements", 1),
(try_for_range, ":slot", 1, ":num_elements"),
(troop_slot_eq, ":list_no", ":slot", ":val"),
(assign, ":index", ":slot"),
(assign, ":num_elements", 0),
(try_end),
(assign, reg1, ":index"),
]),
("list_count", [
# script_list_count
# Returns how many items there are in the list
# INPUT: arg1 - list no
# OUTPUT: reg1 - the list's length
(store_script_param, ":list_no", 1),
(troop_get_slot, reg1, ":list_no", 0),
]),
("list_last", [
# script_list_last
# Returns the last element of the list
# INPUT: arg1 - list no
# OUTPUT: reg1 - last value
(store_script_param, ":list_no", 1),
(troop_get_slot, ":num_elements", ":list_no", 0),
(troop_get_slot, reg1, ":list_no", ":num_elements"),
]),
("list_random", [
# script_list_random
# Returns a random element from the list, along with its index
# INPUT: arg1 - list no
# OUTPUT: reg1 - the value of the item, reg2 - its index
(store_script_param, ":list_no", 1),
(troop_get_slot, ":num_elements", ":list_no", 0),
(val_add, ":num_elements", 1),
(store_random_in_range, reg2, 1, ":num_elements"),
(troop_get_slot, reg1, ":list_no", reg2),
]),
#-## List management end
("list_clear", [
## The list's zero slot holds the number of current items in it
# script_list_clear
# Clears all items from the list
# INPUT: arg1 - list no
# OUTPUT: none
(store_script_param, ":list_no", 1),
(troop_get_slot, ":num_elements", ":list_no", 0),
(val_add, ":num_elements", 1),
(try_for_range, ":slot", 1, ":num_elements"),
(troop_set_slot, ":list_no", ":slot", 0),
(try_end),
(troop_set_slot, ":list_no", 0, 0), # Reset number of elements
]),
("list_at",[
# Returns the value at the specified index, 0 if index is invalid
# INPUT: arg1 - list no; arg2 - index
# OUTPUT: arg1 - value
(store_script_param, ":list_no", 1),
(store_script_param, ":index", 2),
(troop_get_slot, ":num_elements", ":list_no", 0),
(assign, reg1, 0),
(try_begin),
(ge, ":index", 1),
(le, ":index", ":num_elements"),
(troop_get_slot, reg1, ":list_no", ":index"),
(try_end),
]),
("list_at_nc",[
# Returns the value at the specified index; IT DOES NOT CHECK FOR INDEX VALIDITY
# INPUT: arg1 - list no; arg2 - index
# OUTPUT: arg1 - value
(store_script_param, ":list_no", 1),
(store_script_param, ":index", 2),
(troop_get_slot, reg1, ":list_no", ":index"),
]),
("list_set", [
# script_list_set
# Sets an item's, at the specified index
# INPUT: arg1 - list no; arg2 - the value which we will set, arg3 - where we want it (ONE-BASED!)
# OUTPUT: none
(store_script_param, ":list_no", 1),
(store_script_param, ":value", 2),
(store_script_param, ":index", 3),
(troop_get_slot, ":num_elements", ":list_no", 0),
(try_begin),
(ge, ":index", 1),
(le, ":index", ":num_elements"),
(troop_set_slot, ":list_no", ":index", ":value"),
(try_end),
]),
("list_add", [
# script_list_add
# Appends an item to the list
# INPUT: arg1 - list no; arg2 - the value which we will add to the list
# OUTPUT: none
(store_script_param, ":list_no", 1),
(store_script_param, ":value", 2),
(troop_get_slot, ":num_elements", ":list_no", 0),
(val_add, ":num_elements", 1),
(troop_set_slot, ":list_no", ":num_elements", ":value"),
(troop_set_slot, ":list_no", 0, ":num_elements"),
]),
("list_add_at", [
# script_list_add_at
# Appends an item to the list, at the specified index
# INPUT: arg1 - list no; arg2 - the value which we will add to the list, arg3 - where we want it (ONE-BASED!)
# OUTPUT: none
(store_script_param, ":list_no", 1),
(store_script_param, ":value", 2),
(store_script_param, ":index", 3),
(troop_get_slot, ":num_elements", ":list_no", 0),
(val_add, ":num_elements", 1),
(try_begin),
(gt, ":index", ":num_elements"),
(assign, ":index", ":num_elements"),
(try_end),
(try_for_range_backwards, ":slot", ":index", ":num_elements"),
(store_add, ":target", ":slot", 1),
(troop_get_slot, ":val", ":list_no", ":slot"),
(troop_set_slot, ":list_no", ":target", ":val"),
(try_end),
(troop_set_slot, ":list_no", ":index", ":value"),
(troop_set_slot, ":list_no", 0, ":num_elements"),
]),
("list_remove", [
# script_list_remove
# Removes the last item from the list
# INPUT: arg1 - list no
# OUTPUT: none
(store_script_param, ":list_no", 1),
(troop_get_slot, ":num_elements", ":list_no", 0),
(troop_set_slot, ":list_no", ":num_elements", 0),
(val_sub, ":num_elements", 1),
(troop_set_slot, ":list_no", 0, ":num_elements"),
]),
("list_remove_at", [
# script_list_remove_at
# Removes an item from the list, at the specified index
# INPUT: arg1 - list no; arg2 - the index we'll remove from (ONE-BASED!)
# OUTPUT: none
(store_script_param, ":list_no", 1),
(store_script_param, ":index", 2),
(troop_get_slot, ":num_elements", ":list_no", 0),
(try_begin),
(gt, ":index", ":num_elements"),
(assign, ":index", ":num_elements"),
(try_end),
(store_add, ":end", ":num_elements", 1),
(val_sub, ":num_elements", 1),
(store_add, ":start", ":index", 1),
(try_for_range, ":slot", ":start", ":end"),
(troop_get_slot, ":val", ":list_no", ":slot"),
(troop_set_slot, ":list_no", ":index", ":val"),
(val_add, ":index", 1),
(try_end),
(troop_set_slot, ":list_no", 0, ":num_elements"),
]),
("list_remove_val", [
# script_list_remove_val
# Removes a value from the list
# INPUT: arg1 - list no; arg2 - the value we'll remove
# OUTPUT: none
(store_script_param, ":list_no", 1),
(store_script_param, ":value", 2),
(call_script, "script_list_index_of", ":list_no", ":value"),
(try_begin),
(neq, reg1, -1),
(assign, ":index", reg1),
(troop_get_slot, ":num_elements", ":list_no", 0),
(try_begin),
(gt, ":index", ":num_elements"),
(assign, ":index", ":num_elements"),
(try_end),
(store_add, ":end", ":num_elements", 1),
(val_sub, ":num_elements", 1),
(store_add, ":start", ":index", 1),
(try_for_range, ":slot", ":start", ":end"),
(troop_get_slot, ":val", ":list_no", ":slot"),
(troop_set_slot, ":list_no", ":index", ":val"),
(val_add, ":index", 1),
(try_end),
(troop_set_slot, ":list_no", 0, ":num_elements"),
(try_end),
]),
("list_index_of", [
# script_list_index_of
# Returns the index of something from the list
# INPUT: arg1 - list no; arg2 - the value we're looking for
# OUTPUT: reg1 - the index (-1 if not found)
(store_script_param, ":list_no", 1),
(store_script_param, ":val", 2),
(assign, ":index", -1),
(troop_get_slot, ":num_elements", ":list_no", 0),
(val_add, ":num_elements", 1),
(try_for_range, ":slot", 1, ":num_elements"),
(troop_slot_eq, ":list_no", ":slot", ":val"),
(assign, ":index", ":slot"),
(assign, ":num_elements", 0),
(try_end),
(assign, reg1, ":index"),
]),
("list_count", [
# script_list_count
# Returns how many items there are in the list
# INPUT: arg1 - list no
# OUTPUT: reg1 - the list's length
(store_script_param, ":list_no", 1),
(troop_get_slot, reg1, ":list_no", 0),
]),
("list_last", [
# script_list_last
# Returns the last element of the list
# INPUT: arg1 - list no
# OUTPUT: reg1 - last value
(store_script_param, ":list_no", 1),
(troop_get_slot, ":num_elements", ":list_no", 0),
(troop_get_slot, reg1, ":list_no", ":num_elements"),
]),
("list_random", [
# script_list_random
# Returns a random element from the list, along with its index
# INPUT: arg1 - list no
# OUTPUT: reg1 - the value of the item, reg2 - its index
(store_script_param, ":list_no", 1),
(troop_get_slot, ":num_elements", ":list_no", 0),
(val_add, ":num_elements", 1),
(store_random_in_range, reg2, 1, ":num_elements"),
(troop_get_slot, reg1, ":list_no", reg2),
]),
#-## List management end
Creating a list: each list is represented by a troop entry inside module troops. To create one new list you need to make a new troop inside module_troops, preferably starting with 'list_' and being somewhere at the bottom of the troops list (so you don't mess any loop or script that loops over troops).
["list_example","-","-",tf_hero, 0,0, fac_commoners,[],def_attrib|level(2),wp(20),knows_inventory_management_10,0],
Clearing a list: is done by calling script 'list_clear' with the desired list to be cleared.
(call_script, "script_list_clear", "trp_list_example"),
Adding elements/values to a list: it can be done in two ways:
1. Appending an element (or adding it to the end of the list) - is done by calling script "list_add" with the list and the desired value.
(call_script, "script_list_add", "trp_list_example", 123),
(call_script, "script_list_add", "trp_list_example", 234),
# the list will contain two elements, 1 - > '123'; 2 -> '234'
(call_script, "script_list_add", "trp_list_example", 234),
# the list will contain two elements, 1 - > '123'; 2 -> '234'
(call_script, "script_list_add_at", "trp_list_example", 456, 1),
# the list will contain three values, '456', '123' and '234' (in this order)
# the list will contain three values, '456', '123' and '234' (in this order)
Modifying a value: it is done by calling script "list_set" with list, value and index. If the index is invalid, it will do nothing.
(call_script, "script_list_set", "trp_list_example", 100, 2),
# the list will contain three values, '456', '100' and '234'
# the list will contain three values, '456', '100' and '234'
Getting a value: is done by calling script "list_at" with list and index. The returned value is stored in reg1. If the index is invalid, it returns 0.
(call_script, "script_list_at", "trp_list_example", 1),
# reg1 will be equal to 456
# reg1 will be equal to 456
Removing a value: can be done in 3 ways:
1. Removing the last element from the list - by calling script "list_remove" with list id.
(call_script, "script_list_remove", "trp_list_example"),
# the list will contain '456' and '100'
# the list will contain '456' and '100'
(call_script, "script_list_remove_at", "trp_list_example" , 1),
# the list will contain one element, 1 -> '100'
# the list will contain one element, 1 -> '100'
(call_script, "script_list_remove_val", "trp_list_example" , 100),
# the list will be empty
# the list will be empty
Getting number of elements : is done by calling 'list_count' with list id. Th returned value is stored in reg1.
(call_script, "scrip_list_count", "trp_list_example"),
# reg1 will be equal to 0, because the list is empty
# reg1 will be equal to 0, because the list is empty
Getting the last element : is done by calling 'list_last' with list id. The returned value is stored in reg1.
Getting index of a value : is done by calling 'list_index_of' with list id and value. The returned value is stored in reg1. If the value is not found, -1 is returned.
Getting random element : is done by calling 'list_random' with list id. reg1 will contain the value of the random element and reg2 wil contain the index of the element.
Notes:
1. if you are modifying a list inside a mission (like adding agents ids or player ids), then you need to clear it at the beginning of the mission (because if you change the mission, the list will not be reset by the game, leaving the old list's values unchanged).
2. the indexes are 1 based. index 0 is invalid.
2. Timed callbacks system
The timed callbacks system allows you to call a script with a delay. Normally, if you would want something to be called after a period of time, you would need to set up triggers that would check when that thing should be called. With this system you can do that in just one line of code.
Very important note - these scripts requires list system AND dynamic memory to be installed!!!!!!!!!!!
(call_script, "script_register_cb", 1000, "script_display_message_after_1_second", 0),
# the first value, '1000', tells how many miliseconds needs to pass until the script is called
# the second value, "script_display_message_after_1_second", specifies the script that will be called after 1000 miliseconds
# the third value, '0', specifies the number of parameters that the specified script will be called with. In our case, no parameters
("display_message_after_1_second", [
(display_message, "@Just a test message that willbe displayed after 1 second from registration!"),
]),
# the first value, '1000', tells how many miliseconds needs to pass until the script is called
# the second value, "script_display_message_after_1_second", specifies the script that will be called after 1000 miliseconds
# the third value, '0', specifies the number of parameters that the specified script will be called with. In our case, no parameters
("display_message_after_1_second", [
(display_message, "@Just a test message that willbe displayed after 1 second from registration!"),
]),
(call_script, "script_register_cb", 2500, "script_display_value", 1, 100),
(call_script, "script_register_cb", 5000, "script_display_value", 1, 50),
(call_script, "script_register_cb", 6000, "script_display_value", 1, 12),
("display_value",[
(store_script_param_1, reg1),
(display_message, "@Value is {reg1}!"),
]),
# after 2.5 seconds from the registration call, value 100 will be shown. After another 2.5 seconds, value 50 will be displayed. After another second, value 12 will be displayed
(call_script, "script_register_cb", 5000, "script_display_value", 1, 50),
(call_script, "script_register_cb", 6000, "script_display_value", 1, 12),
("display_value",[
(store_script_param_1, reg1),
(display_message, "@Value is {reg1}!"),
]),
# after 2.5 seconds from the registration call, value 100 will be shown. After another 2.5 seconds, value 50 will be displayed. After another second, value 12 will be displayed
How to install:
1. Copy the scripts (from the 'scripts' spoiler below) inside module_scripts, before the last ']'
2. Add '(call_script, "script_init_callbacks"),' in trigger 'ti_before_mission_start' (in each mission template which will use the timed callbacks system)
3. Add the trigger (from the 'trigger' spoiler below) in each mission template which will use the timed callbacks system
#-## Timed callbacks (no dependency)
("init_callbacks",[
(assign, "$callbacks_root_p", 0),
]),
("register_cb",[
(store_script_param_1, ":miliseconds"),
(store_script_param_2, ":script_no"),
(store_script_param, ":num_params", 3),
(store_mission_timer_c_msec, ":c_milis"),
(store_add, ":cb_time", ":c_milis", ":miliseconds"),
(call_script, "script_alloc", 14), ## 2 pointers + time + script + 10 params = 14 vars
(assign, ":new_node", reg0),
(call_script, "script_v_set", ":new_node", 0, 0),# prev p
(call_script, "script_v_set", ":new_node", 1, 0),# next p
(call_script, "script_v_set", ":new_node", 2, ":cb_time"), # time
(call_script, "script_v_set", ":new_node", 3, ":script_no"), # script no
(val_clamp, ":num_params", 0, 11),
(assign, ":c_script_param", 4),
(store_add, ":end_cond", ":num_params", 4),
(assign, ":c_i", 4),
(try_for_range, ":c_script_param", 4, ":end_cond"),
(store_script_param, ":param_value", ":c_script_param"),
(call_script, "script_v_set", ":new_node", ":c_i", ":param_value"), # params
(val_add, ":c_i", 1),
(try_end),
(try_for_range, ":i", ":c_i", 11),
(call_script, "script_v_set", ":new_node", ":i", 0), # params
(try_end),
### node is constructed
(assign, reg10, ":miliseconds"),
(try_begin),
(eq, "$callbacks_root_p", 0),
(assign, "$callbacks_root_p", ":new_node"),
(display_message, "@{reg10} - 1"),
(else_try),
(assign, ":end_cond", 9999),
(assign, ":c_node", "$callbacks_root_p"),
(try_for_range, ":unused", 0, ":end_cond"),
(call_script, "script_v_get", ":c_node", 1),
(assign, ":next_p", reg0),
(call_script, "script_v_get", ":c_node", 2),
(try_begin),
(ge, reg0, ":cb_time"),
(display_message, "@{reg10} - 2"),
(try_begin),
(call_script, "script_v_get", ":c_node", 0), # get the prev p
(try_begin),
(neq, reg0, 0),
(display_message, "@{reg10} - 3"),
(call_script, "script_v_set", reg0, 1, ":new_node"), # set prev p next's p to the new node
(call_script, "script_v_set", ":new_node", 0, reg0),
(else_try),
(assign, "$callbacks_root_p", ":new_node"),
(display_message, "@{reg10} - 4"),
(try_end),
(call_script, "script_v_set", ":c_node", 0, ":new_node"), # set next p prev's p to new node
(call_script, "script_v_set", ":new_node", 1, ":c_node"),
(try_end),
(assign, ":end_cond", 0),
(else_try),
(eq, ":next_p", 0),
(display_message, "@{reg10} - 6"),
(call_script, "script_v_set", ":c_node", 1, ":new_node"),
(call_script, "script_v_set", ":new_node", 0, ":c_node"),
(assign, ":end_cond", 0),
(try_end),
(display_message, "@{reg10} - 7"),
(assign, ":c_node", ":next_p"),
(try_end),
(try_end),
]),
("process_callbacks",[
(try_begin),
(neq, "$callbacks_root_p", 0),
(store_mission_timer_c_msec, ":c_milis"),
(assign, ":c_node", "$callbacks_root_p"),
(assign, ":end_cond", 9999),
(try_for_range, ":unused", 0, ":end_cond"),
(call_script, "script_v_get", ":c_node", 2),
(try_begin),
(ge, ":c_milis", reg0),
## execute script
(call_script, "script_v_get", ":c_node", 3),
(assign, ":script_no", reg0),
(call_script, "script_v_get", ":c_node", 4),
(assign, ":param_1", reg0),
(call_script, "script_v_get", ":c_node", 5),
(assign, ":param_2", reg0),
(call_script, "script_v_get", ":c_node", 6),
(assign, ":param_3", reg0),
(call_script, "script_v_get", ":c_node", 7),
(assign, ":param_4", reg0),
(call_script, "script_v_get", ":c_node", ,
(assign, ":param_5", reg0),
(call_script, "script_v_get", ":c_node", 9),
(assign, ":param_6", reg0),
(call_script, "script_v_get", ":c_node", 10),
(assign, ":param_7", reg0),
(call_script, "script_v_get", ":c_node", 11),
(assign, ":param_8", reg0),
(call_script, "script_v_get", ":c_node", 12),
(assign, ":param_9", reg0),
(call_script, "script_v_get", ":c_node", 13),
(assign, ":param_10", reg0),
(call_script, "script_v_get", ":c_node", 1), # get next p
(assign, ":next_p", reg0),
(try_begin),
(neq, ":next_p", 0),
(call_script, "script_v_set", ":next_p", 0, 0), # set next node's prev pointer to null
(assign, "$callbacks_root_p", ":next_p"),
(else_try),
(assign, "$callbacks_root_p", 0),
(assign, ":end_cond", 0),
(try_end),
(call_script, "script_free", ":c_node"),
(assign, ":c_node", ":next_p"),
(call_script, ":script_no", ":param_1", ":param_2", ":param_3", ":param_4", ":param_5", ":param_6", ":param_7", ":param_8", ":param_9", ":param_10"),
(else_try),
(assign, ":end_cond", 0),
(try_end),
(try_end),
(try_end),
]),
#-## Timed callbacks end
("init_callbacks",[
(assign, "$callbacks_root_p", 0),
]),
("register_cb",[
(store_script_param_1, ":miliseconds"),
(store_script_param_2, ":script_no"),
(store_script_param, ":num_params", 3),
(store_mission_timer_c_msec, ":c_milis"),
(store_add, ":cb_time", ":c_milis", ":miliseconds"),
(call_script, "script_alloc", 14), ## 2 pointers + time + script + 10 params = 14 vars
(assign, ":new_node", reg0),
(call_script, "script_v_set", ":new_node", 0, 0),# prev p
(call_script, "script_v_set", ":new_node", 1, 0),# next p
(call_script, "script_v_set", ":new_node", 2, ":cb_time"), # time
(call_script, "script_v_set", ":new_node", 3, ":script_no"), # script no
(val_clamp, ":num_params", 0, 11),
(assign, ":c_script_param", 4),
(store_add, ":end_cond", ":num_params", 4),
(assign, ":c_i", 4),
(try_for_range, ":c_script_param", 4, ":end_cond"),
(store_script_param, ":param_value", ":c_script_param"),
(call_script, "script_v_set", ":new_node", ":c_i", ":param_value"), # params
(val_add, ":c_i", 1),
(try_end),
(try_for_range, ":i", ":c_i", 11),
(call_script, "script_v_set", ":new_node", ":i", 0), # params
(try_end),
### node is constructed
(assign, reg10, ":miliseconds"),
(try_begin),
(eq, "$callbacks_root_p", 0),
(assign, "$callbacks_root_p", ":new_node"),
(display_message, "@{reg10} - 1"),
(else_try),
(assign, ":end_cond", 9999),
(assign, ":c_node", "$callbacks_root_p"),
(try_for_range, ":unused", 0, ":end_cond"),
(call_script, "script_v_get", ":c_node", 1),
(assign, ":next_p", reg0),
(call_script, "script_v_get", ":c_node", 2),
(try_begin),
(ge, reg0, ":cb_time"),
(display_message, "@{reg10} - 2"),
(try_begin),
(call_script, "script_v_get", ":c_node", 0), # get the prev p
(try_begin),
(neq, reg0, 0),
(display_message, "@{reg10} - 3"),
(call_script, "script_v_set", reg0, 1, ":new_node"), # set prev p next's p to the new node
(call_script, "script_v_set", ":new_node", 0, reg0),
(else_try),
(assign, "$callbacks_root_p", ":new_node"),
(display_message, "@{reg10} - 4"),
(try_end),
(call_script, "script_v_set", ":c_node", 0, ":new_node"), # set next p prev's p to new node
(call_script, "script_v_set", ":new_node", 1, ":c_node"),
(try_end),
(assign, ":end_cond", 0),
(else_try),
(eq, ":next_p", 0),
(display_message, "@{reg10} - 6"),
(call_script, "script_v_set", ":c_node", 1, ":new_node"),
(call_script, "script_v_set", ":new_node", 0, ":c_node"),
(assign, ":end_cond", 0),
(try_end),
(display_message, "@{reg10} - 7"),
(assign, ":c_node", ":next_p"),
(try_end),
(try_end),
]),
("process_callbacks",[
(try_begin),
(neq, "$callbacks_root_p", 0),
(store_mission_timer_c_msec, ":c_milis"),
(assign, ":c_node", "$callbacks_root_p"),
(assign, ":end_cond", 9999),
(try_for_range, ":unused", 0, ":end_cond"),
(call_script, "script_v_get", ":c_node", 2),
(try_begin),
(ge, ":c_milis", reg0),
## execute script
(call_script, "script_v_get", ":c_node", 3),
(assign, ":script_no", reg0),
(call_script, "script_v_get", ":c_node", 4),
(assign, ":param_1", reg0),
(call_script, "script_v_get", ":c_node", 5),
(assign, ":param_2", reg0),
(call_script, "script_v_get", ":c_node", 6),
(assign, ":param_3", reg0),
(call_script, "script_v_get", ":c_node", 7),
(assign, ":param_4", reg0),
(call_script, "script_v_get", ":c_node", ,
(assign, ":param_5", reg0),
(call_script, "script_v_get", ":c_node", 9),
(assign, ":param_6", reg0),
(call_script, "script_v_get", ":c_node", 10),
(assign, ":param_7", reg0),
(call_script, "script_v_get", ":c_node", 11),
(assign, ":param_8", reg0),
(call_script, "script_v_get", ":c_node", 12),
(assign, ":param_9", reg0),
(call_script, "script_v_get", ":c_node", 13),
(assign, ":param_10", reg0),
(call_script, "script_v_get", ":c_node", 1), # get next p
(assign, ":next_p", reg0),
(try_begin),
(neq, ":next_p", 0),
(call_script, "script_v_set", ":next_p", 0, 0), # set next node's prev pointer to null
(assign, "$callbacks_root_p", ":next_p"),
(else_try),
(assign, "$callbacks_root_p", 0),
(assign, ":end_cond", 0),
(try_end),
(call_script, "script_free", ":c_node"),
(assign, ":c_node", ":next_p"),
(call_script, ":script_no", ":param_1", ":param_2", ":param_3", ":param_4", ":param_5", ":param_6", ":param_7", ":param_8", ":param_9", ":param_10"),
(else_try),
(assign, ":end_cond", 0),
(try_end),
(try_end),
(try_end),
]),
#-## Timed callbacks end
(0, 0, 0, [], [(call_script, "script_process_callbacks")]),
Notes:
1. there is a maximum of 10 parameters that you can pass to a script
2. due to technical reasons, it can't call the script after exactly the amount of time specified. The minimum delay is based on the server fps.
3. the max amount of concurrent registered scripts is not something to worry about because it is somewhere around 1048576 (that is the max slot that can be used for a troop).
3. Dynamic memory
This system allows you to make memory allocations. Because I don't know how to explain it better, I will give some examples.
There are 2 main functions: 'alloc' and 'free'.
'alloc' takes 1 parameter which specifies the amount of elements to allocate. The returned value (is stored in reg0) is a pointer that points to the first element in the allocated memory block.
'free' takes 1 parameter which is a pointer to a block of memory that we want to free.
To read values, we have 2 scripts:
1. 'get' - takes one parameter (a pointer) and returns (in reg0) the value that is being pointed to by the pointer
2. 'v_get' - takes 2 parameters, a pointer and an index. It returns (in reg0) the value that is at the specified index within the vector that is being pointed to by the pointer
To write values, there are another 2 scripts:
1. 'set' - takes two parameters, a pointer and a value. It sets the value that the pointer is pointing to
2. 'v_set' - takes 3 parameters, a pointer, an index and a value. It sets the value that is at the specified index within the vector that the pointer is pointing to
(call_script, "script_alloc", 20), # allocates a vector of 20 elements
(assign, ":p_1", reg0), # reg0 contains the address of the first element
(call_script, "script_v_set", ":p_1", 0, 10), # set the first element to 10
(call_script, "script_v_set", ":p_1", 5, 23), # set the sixth element to 23
(call_script, "script_v_get", ":p_1", 5), # returns 23 (in reg0)
(display_message, "@The sixth's element value = {reg0}!"),
(call_script, "script_free", ":p_1"), # frees the memory so it can be reused
(call_script, "script_alloc", 1), # allocates one element
(assign, ":p_2", reg0), # reg0 contains the address of the element
(call_script, "script_set", ":p_2", 1234),
(call_script, "script_get", ":p_2"),
(display_message, "@Value = {reg0}!"),
(call_script, "script_free", ":p_2"),
(assign, ":p_1", reg0), # reg0 contains the address of the first element
(call_script, "script_v_set", ":p_1", 0, 10), # set the first element to 10
(call_script, "script_v_set", ":p_1", 5, 23), # set the sixth element to 23
(call_script, "script_v_get", ":p_1", 5), # returns 23 (in reg0)
(display_message, "@The sixth's element value = {reg0}!"),
(call_script, "script_free", ":p_1"), # frees the memory so it can be reused
(call_script, "script_alloc", 1), # allocates one element
(assign, ":p_2", reg0), # reg0 contains the address of the element
(call_script, "script_set", ":p_2", 1234),
(call_script, "script_get", ":p_2"),
(display_message, "@Value = {reg0}!"),
(call_script, "script_free", ":p_2"),
Very important note: this system uses the list system!!! you need to have list system install for it to work!!!!
How to install:
1. Copy the scripts (from the 'scripts' spoiler below) inside module_scripts
2. Add '(call_script, "script_init_memory_management"),' in trigger 'ti_before_mission_start' (in each mission template which will use the dynamic memory system)
3. Copy the troops (from the 'troops' spoiler below) inside module_troops, somewhere at the bottom of the troop list
#-## dynamic memory (list system dependent!!!)
("init_memory_management", [
(troop_set_slot, "trp_dynamic_memory", 0, 0),
(call_script, "script_list_clear", "trp_list_free_dynamic_memory_pointers_indexes"),
(call_script, "script_list_clear", "trp_list_free_dynamic_memory_pointers_sizes"),
(call_script, "script_list_clear", "trp_list_allocated_dynamic_memory_pointers_indexes"),
(call_script, "script_list_clear", "trp_list_allocated_dynamic_memory_pointers_sizes"),
]),
("alloc", [
## This script allocates the specified ammount of variables
# script_alloc
# Allocates memory
# INPUT: arg1 - num variables to allocate
# OUTPUT: reg0 - pointer to the firs variable
(store_script_param_1, ":block_size"),
(troop_get_slot, ":num_free_pointers", "trp_list_free_dynamic_memory_pointers_sizes", 0),
(assign, ":found", 0),
(try_begin),
(neq, ":num_free_pointers", 0),
(val_add, ":num_free_pointers", 1),
(try_for_range, ":i_pointer_index", 1, ":num_free_pointers"),
(troop_slot_ge, "trp_list_free_dynamic_memory_pointers_sizes", ":i_pointer_index", ":block_size"),
# we've found our pointer; remove it from the list and return it
(assign, ":found", 1),
(assign, ":num_free_pointers", 0),
(call_script, "script_list_at_nc", "trp_list_free_dynamic_memory_pointers_sizes", ":i_pointer_index"),
(call_script, "script_list_add", "trp_list_allocated_dynamic_memory_pointers_sizes", reg1),
(call_script, "script_list_at_nc", "trp_list_free_dynamic_memory_pointers_indexes", ":i_pointer_index"),
(assign, reg0, reg1),
(call_script, "script_list_add", "trp_list_allocated_dynamic_memory_pointers_indexes", reg1),
(call_script, "script_list_remove_at", "trp_list_free_dynamic_memory_pointers_indexes", ":i_pointer_index"),
(call_script, "script_list_remove_at", "trp_list_free_dynamic_memory_pointers_sizes", ":i_pointer_index"),
(try_end),
(try_end),
(try_begin),
(eq, ":found", 0),
(troop_get_slot, ":pointer_to_end", "trp_dynamic_memory", 0),
(store_add, reg0, ":pointer_to_end", 1),
(call_script, "script_list_add", "trp_list_allocated_dynamic_memory_pointers_indexes", reg0),
(call_script, "script_list_add", "trp_list_allocated_dynamic_memory_pointers_sizes", ":block_size"),
(val_add, ":pointer_to_end", ":block_size"),
(troop_set_slot, "trp_dynamic_memory", 0, ":pointer_to_end"),
(try_end),
]),
("free", [
## This script frees allocated memory block
# script_free
# Frees memory
# INPUT: arg1 - pointer to block of variables that needs to be freed
# OUTPUT: none
(store_script_param_1, ":block_pointer"),
(call_script, "script_list_index_of", "trp_list_allocated_dynamic_memory_pointers_indexes", ":block_pointer"),
(assign, ":p_index", reg1),
(try_begin),
(eq, ":p_index", -1),
### ERROR! invalid pointer
(else_try),
(call_script, "script_list_add", "trp_list_free_dynamic_memory_pointers_indexes", ":block_pointer"),
(call_script, "script_list_at_nc", "trp_list_allocated_dynamic_memory_pointers_sizes", ":p_index"),
(call_script, "script_list_add", "trp_list_free_dynamic_memory_pointers_sizes", reg1),
(call_script, "script_list_remove_at", "trp_list_allocated_dynamic_memory_pointers_indexes", ":p_index"),
(call_script, "script_list_remove_at", "trp_list_allocated_dynamic_memory_pointers_sizes", ":p_index"),
(try_end),
]),
("get",[
## This script returns the value pointed to by the pointer
# script_get
# Return value being pointed at
# INPUT: arg1 - pointer
# OUTPUT: reg0 - value pointed by the pointer
(store_script_param_1, ":pointer"),
(troop_get_slot, reg0, "trp_dynamic_memory", ":pointer"),
]),
("set",[
## This script sets the value of the pointed object
# script_set
# Sets value
# INPUT: arg1 - pointer; arg2 - value to set
# OUTPUT: none
(store_script_param_1, ":pointer"),
(store_script_param_2, ":value"),
(try_begin),
(neq, ":pointer", 0),
(troop_set_slot, "trp_dynamic_memory", ":pointer", ":value"),
(try_end),
]),
("v_get",[
## This script returns the value pointed to by the pointer, at a specific index
# script_v_get
# Return value being pointed at
# INPUT: arg1 - pointer; arg2 - index
# OUTPUT: reg0 - value pointed by the pointer
(store_script_param_1, ":pointer"),
(store_script_param_2, ":index"),
(val_add, ":pointer", ":index"),
(troop_get_slot, reg0, "trp_dynamic_memory", ":pointer"),
]),
("v_set",[
## This script sets the value of the pointed object, at a specific index
# script_v_set
# Sets value
# INPUT: arg1 - pointer; arg2 - index; arg3 - value to set
# OUTPUT: none
(store_script_param_1, ":pointer"),
(store_script_param_2, ":index"),
(store_script_param, ":value", 3),
(val_add, ":pointer", ":index"),
(try_begin),
(neq, ":pointer", 0),
(troop_set_slot, "trp_dynamic_memory", ":pointer", ":value"),
(try_end),
]),
#-## dynamic memory end
("init_memory_management", [
(troop_set_slot, "trp_dynamic_memory", 0, 0),
(call_script, "script_list_clear", "trp_list_free_dynamic_memory_pointers_indexes"),
(call_script, "script_list_clear", "trp_list_free_dynamic_memory_pointers_sizes"),
(call_script, "script_list_clear", "trp_list_allocated_dynamic_memory_pointers_indexes"),
(call_script, "script_list_clear", "trp_list_allocated_dynamic_memory_pointers_sizes"),
]),
("alloc", [
## This script allocates the specified ammount of variables
# script_alloc
# Allocates memory
# INPUT: arg1 - num variables to allocate
# OUTPUT: reg0 - pointer to the firs variable
(store_script_param_1, ":block_size"),
(troop_get_slot, ":num_free_pointers", "trp_list_free_dynamic_memory_pointers_sizes", 0),
(assign, ":found", 0),
(try_begin),
(neq, ":num_free_pointers", 0),
(val_add, ":num_free_pointers", 1),
(try_for_range, ":i_pointer_index", 1, ":num_free_pointers"),
(troop_slot_ge, "trp_list_free_dynamic_memory_pointers_sizes", ":i_pointer_index", ":block_size"),
# we've found our pointer; remove it from the list and return it
(assign, ":found", 1),
(assign, ":num_free_pointers", 0),
(call_script, "script_list_at_nc", "trp_list_free_dynamic_memory_pointers_sizes", ":i_pointer_index"),
(call_script, "script_list_add", "trp_list_allocated_dynamic_memory_pointers_sizes", reg1),
(call_script, "script_list_at_nc", "trp_list_free_dynamic_memory_pointers_indexes", ":i_pointer_index"),
(assign, reg0, reg1),
(call_script, "script_list_add", "trp_list_allocated_dynamic_memory_pointers_indexes", reg1),
(call_script, "script_list_remove_at", "trp_list_free_dynamic_memory_pointers_indexes", ":i_pointer_index"),
(call_script, "script_list_remove_at", "trp_list_free_dynamic_memory_pointers_sizes", ":i_pointer_index"),
(try_end),
(try_end),
(try_begin),
(eq, ":found", 0),
(troop_get_slot, ":pointer_to_end", "trp_dynamic_memory", 0),
(store_add, reg0, ":pointer_to_end", 1),
(call_script, "script_list_add", "trp_list_allocated_dynamic_memory_pointers_indexes", reg0),
(call_script, "script_list_add", "trp_list_allocated_dynamic_memory_pointers_sizes", ":block_size"),
(val_add, ":pointer_to_end", ":block_size"),
(troop_set_slot, "trp_dynamic_memory", 0, ":pointer_to_end"),
(try_end),
]),
("free", [
## This script frees allocated memory block
# script_free
# Frees memory
# INPUT: arg1 - pointer to block of variables that needs to be freed
# OUTPUT: none
(store_script_param_1, ":block_pointer"),
(call_script, "script_list_index_of", "trp_list_allocated_dynamic_memory_pointers_indexes", ":block_pointer"),
(assign, ":p_index", reg1),
(try_begin),
(eq, ":p_index", -1),
### ERROR! invalid pointer
(else_try),
(call_script, "script_list_add", "trp_list_free_dynamic_memory_pointers_indexes", ":block_pointer"),
(call_script, "script_list_at_nc", "trp_list_allocated_dynamic_memory_pointers_sizes", ":p_index"),
(call_script, "script_list_add", "trp_list_free_dynamic_memory_pointers_sizes", reg1),
(call_script, "script_list_remove_at", "trp_list_allocated_dynamic_memory_pointers_indexes", ":p_index"),
(call_script, "script_list_remove_at", "trp_list_allocated_dynamic_memory_pointers_sizes", ":p_index"),
(try_end),
]),
("get",[
## This script returns the value pointed to by the pointer
# script_get
# Return value being pointed at
# INPUT: arg1 - pointer
# OUTPUT: reg0 - value pointed by the pointer
(store_script_param_1, ":pointer"),
(troop_get_slot, reg0, "trp_dynamic_memory", ":pointer"),
]),
("set",[
## This script sets the value of the pointed object
# script_set
# Sets value
# INPUT: arg1 - pointer; arg2 - value to set
# OUTPUT: none
(store_script_param_1, ":pointer"),
(store_script_param_2, ":value"),
(try_begin),
(neq, ":pointer", 0),
(troop_set_slot, "trp_dynamic_memory", ":pointer", ":value"),
(try_end),
]),
("v_get",[
## This script returns the value pointed to by the pointer, at a specific index
# script_v_get
# Return value being pointed at
# INPUT: arg1 - pointer; arg2 - index
# OUTPUT: reg0 - value pointed by the pointer
(store_script_param_1, ":pointer"),
(store_script_param_2, ":index"),
(val_add, ":pointer", ":index"),
(troop_get_slot, reg0, "trp_dynamic_memory", ":pointer"),
]),
("v_set",[
## This script sets the value of the pointed object, at a specific index
# script_v_set
# Sets value
# INPUT: arg1 - pointer; arg2 - index; arg3 - value to set
# OUTPUT: none
(store_script_param_1, ":pointer"),
(store_script_param_2, ":index"),
(store_script_param, ":value", 3),
(val_add, ":pointer", ":index"),
(try_begin),
(neq, ":pointer", 0),
(troop_set_slot, "trp_dynamic_memory", ":pointer", ":value"),
(try_end),
]),
#-## dynamic memory end
["dynamic_memory","-","-",tf_hero, 0,0, fac_commoners,[],def_attrib|level(2),wp(20),knows_inventory_management_10,0],
["list_free_dynamic_memory_pointers_indexes","-","-",tf_hero, 0,0, fac_commoners,[],def_attrib|level(2),wp(20),knows_inventory_management_10,0],
["list_free_dynamic_memory_pointers_sizes","-","-",tf_hero, 0,0, fac_commoners,[],def_attrib|level(2),wp(20),knows_inventory_management_10,0],
["list_allocated_dynamic_memory_pointers_indexes","-","-",tf_hero, 0,0, fac_commoners,[],def_attrib|level(2),wp(20),knows_inventory_management_10,0],
["list_allocated_dynamic_memory_pointers_sizes","-","-",tf_hero, 0,0, fac_commoners,[],def_attrib|level(2),wp(20),knows_inventory_management_10,0],
["list_free_dynamic_memory_pointers_indexes","-","-",tf_hero, 0,0, fac_commoners,[],def_attrib|level(2),wp(20),knows_inventory_management_10,0],
["list_free_dynamic_memory_pointers_sizes","-","-",tf_hero, 0,0, fac_commoners,[],def_attrib|level(2),wp(20),knows_inventory_management_10,0],
["list_allocated_dynamic_memory_pointers_indexes","-","-",tf_hero, 0,0, fac_commoners,[],def_attrib|level(2),wp(20),knows_inventory_management_10,0],
["list_allocated_dynamic_memory_pointers_sizes","-","-",tf_hero, 0,0, fac_commoners,[],def_attrib|level(2),wp(20),knows_inventory_management_10,0],
Notes:
1. The max amount of total allocated elements is limited to 1048576 (or around that number).
2. After you free the memory, you can still use it, but in future it can cause trouble because of a reuse of that memory block (two things using the same memory)
3. There are no index validation. You can edit by mistake other blocks of memory due to a bad index