OSP Code Optimisation List system, timed callbacks and dynamic memory

Users who are viewing this thread

  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!

#-## 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

  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'
    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
(call_script, "script_list_add_at", "trp_list_example", 456, 1),
# 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'

    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

    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'
    2. Removing by index - by calling 'list_remove_at' with list id and index.
(call_script, "script_list_remove_at", "trp_list_example" , 1),
# the list will contain one element, 1 -> '100'
    3. Removing by value  - by calling 'list_remove_val' with list id and value.
(call_script, "script_list_remove_val", "trp_list_example" , 100),
# 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

    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!"),
]),
(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

  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", :cool:,
        (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"),

  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

  ["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], 
 

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
 
I really need serious explanations how the lists are more useful and practical compared, because I don't get a thing out of that ever since. Perhaps, why I am not a coder in RL. Care to explain a little more user-friendly, mate? :razz:
 
An example of how I used lists in assassin hunt native server side mod.
I needed the player to have random armor each time it spawns, so I made 3 lists: one for head armor, one for body armor and one for foot armor.
At the beginning of the mission, I initialize the list (manually, by calling 'list_add' followed by the armor item id that I wanted).
When I want to spawn the player, I simply make 3 calls to 'list_random' script and then I set the player to spawn with those 3 items.

This could be done with slots directly too, but you would need to keep track of the slot number + the number of items in each slot container, to make the random choosing.

Another thing that I did using lists was reusing a type of scene prop that was needed now and then. I spawn a prop, the player uses it. When it doesn't need it anymore, instead of deleting it (if there would be a clean way of doing it...) I put the instance id in a list and use it later, when another player needs it.

+ the two other systems (timed callbacks and dynamic memory)
 
Hm, I see. Alright, thanks for the codes. I will try them when I can, thankie.
 
I haven't test for performance issues, but the list that contains the time when the script should execute is ordered ascending, so that each frame only 1 check is made (if the first script in the list needs to be called). If that check is passed, the first script is called, then the second one is checked. And so on. If the check is not meet, the trigger exits.
Lots of stuff happens when a script gets executed. That is a part that needs optimizing.

EDIT: Done! I've changed the system from using vector lists to using two way linked list (using dynamic memory). Now it is much much more efficient.
 
I like it--particularly the extension to timers (though admittedly I'm trying to come up with a good application of that where a trigger would be sub-optimal). Something to consider would be doing something closer to what sphere did with dynamic arrays (here), by using parties (one could also use agents for in-mission-only lists) to allow for the creation and deletion of the lists in real time rather than creating a new troop template for each while coding. (It looks like that is what this 'warp' project does, too.)
 
Back
Top Bottom