OSP Code QoL [WB] Dynamic Villages and Scene Props Iterator

Users who are viewing this thread

Okay, the final variant is hereby presented for the community to use.

Insert this anywhere:
Code:
situational_scene_var_id = 127 ## When a scene prop has this number as first variation ID, it is subject to situational removal, all other scene props are ignored

Insert this into any mission template where you want conditional object removal (assuming you need mission-based control over objects, otherwise just don't use these lines and remove corresponding check in module_scene_props.py):
Code:
      (ti_before_mission_start, 0, 0, [], [(assign, "$g_scene_requires_objects_removal", 1)]),
      (ti_after_mission_start, 0, 0, [], [(assign, "$g_scene_requires_objects_removal", 0)]),

Insert this anywhere, preferably at the end of the file:
Code:
  # script_scene_prop_needs_removal
  # Input: scene_prop_id, variation_id
  # Output: reg0 should contain 1 or 0 (needs removal or not)
  # This is a dummy script which always tells to never remove anything.
  # Replace this with actual code according to your needs.
  ("scene_prop_needs_removal",
    [
      #(store_script_param_1, ":scene_prop_instance_id"),
      #(prop_instance_get_scene_prop_kind, ":scene_prop_id", ":scene_prop_instance_id"), ## For checks on scene_prop type etc
      (assign, reg0, 0),
    ]
  ),

Insert this at the very end of the file:
Code:
from ID_scripts import *
append_to_props_list = (ti_on_scene_prop_init,
    [
      (try_begin),
        (eq, "$g_scene_requires_objects_removal", 1), # If scene doesn't want situational control over scene props, we exit immediately
        (store_trigger_param_1, ":scene_prop_instance_id"),
        (prop_instance_get_variation_id, ":var_id", ":scene_prop_instance_id"),
        (eq, ":var_id", situational_scene_var_id), ## We check that first variation ID matches the one defined in constants as situational flag
        (call_script, "script_scene_prop_needs_removal", ":scene_prop_instance_id"),
        (eq, reg0, 1),
        (prop_instance_get_position, pos1, ":scene_prop_instance_id"),
        (position_set_z, pos1, -1000),
        (prop_instance_set_position, ":scene_prop_instance_id", pos1),
      (try_end),
    ]
  )

for key in range(len(scene_props)):
  scene_props[key][4].append(append_to_props_list)

Quick guide for scene editors.

1. Put 127 as the variation ID #1 to make the prop subject to situational removal.

2. Put conditional code (supplied by module scripters) as the variation ID #2.

3. Voila, when the condition defined by the conditional code is met, the prop will not appear on the scene.

4. All you need is the list of conditional codes, which will look like follows:

Code:
{1} Village has blacksmith
{2} Village does not have blacksmith
{3} Village has mill
{4} Village does not have mill
(etc)
 
For what it is worth, I would do some of the things differently: rather than "scene_prop_needs_removal" with reg0 as the result, change to "cf_scene_prop_needs_removal" and check the condition as the last line of that script (outside any try_begin try_end blocks) so the (call_script, "cf_scene_prop_needs_removal", ... line can be used just like other operations that can fail. I would also call the check script if the var1 was greater than some number like 100, so the people using it could have code like:
Code:
("cf_scene_prop_needs_removal",
 [(store_script_param, ":instance_id", 1),
  (store_script_param, ":variation_id", 2),

  (assign, ":remove", 0),
  (try_begin),
    (eq, ":variation_id", 127),
    (village_has_mill),
  (else_try),
    (eq, ":variation_id", 126),
    (village_has_blacksmith),
  (else_try),
    ...
  (else_try),
    (assign, ":remove", 1),
  (try_end),
  (eq, ":remove", 1),
  ]),
This way the scene makers can use whatever scene props needed to make up the different buildings, marking which enhancement they are part of by the var1 number. You also needed to use "spr_empty" rather than spr_empty in the first version of your code.

Another way of looping over all scene prop instances in a scene that might be fast enough is (requires warband 1.134 at least):
Code:
(try_for_range, ":instance_id", 0, 10000),
  (prop_instance_is_valid, ":instance_id"),
  ...
(try_end),
Or even something like this, presuming that the game assigns instance ids in some way that doesn't leave huge gaps (might be risky, if someone deleted a large amount of props at once):
Code:
(assign, ":loop_end", 1000000),
(assign, ":consectutive_invalid", 0),
(try_for_range, ":instance_id", 0, ":loop_end"),
  (try_begin),
    (prop_instance_is_valid, ":instance_id"),
    (assign, ":consectutive_invalid", 0),
    (try_begin),
      ...
    (try_end),
  (else_try),
    (val_add, ":consectutive_invalid", 1),
    (gt, ":consectutive_invalid", 100),
    (assign, ":loop_end", -1),
  (try_end),
(try_end),
 
Thanks for your comments, that's a perfectly valid method. I knew about cf_ scripts, but didn't have enough hands-on experience with them to experiment.

Your first version of fast iteration would probably work as well.

Anyway, since yesterday I also wrote this piece of experimental and TOTALLY UNTESTED code.

It creates the list of all scene_props on the scene and allows user to iterate through them at will.

Code:
########################################################################################################################
# Scene props iterator code starts here
# These lines should better be placed last in the file, but BEFORE the closing bracket.
########################################################################################################################
  ["scene_props_list","scene_props_list","scene_props_list", tf_hero, 0, 0, fac_commoners, [], def_attrib|level(1), wp(20), knows_common, 0],
########################################################################################################################
# Scene props iterator code ends here
########################################################################################################################

Code:
########################################################################################################################
# Scene props iterator code starts here
# These lines should be placed LAST in the file, AFTER the closing bracket!!!
########################################################################################################################
from ID_scripts import *
append_to_props_list = (ti_on_scene_prop_init,
    [
      (store_trigger_param_1, ":scene_prop_instance_id"),
      (call_script, "script_scene_props_iterator_append", ":scene_prop_instance_id"),
    ]
  )

for key in range(len(scene_props)):
  scene_props[key][4].append(append_to_props_list)
########################################################################################################################
# Scene props iterator code ends here
########################################################################################################################

Code:
########################################################################################################################
# Scene props iterator code starts here
# These triggers should be added to all mission templates where you want to use scene prop iterator
########################################################################################################################
  (ti_before_mission_start, 0, 0, [], [(call_script, "script_scene_props_iterator_init")]),
  (ti_after_mission_start,  0, 0, [], [(call_script, "script_scene_props_iterator_finalize")]),
  # ALTERNATIVELY you could use the following
  # (ti_before_mission_start, 0, 0, [], [(call_script, "script_scene_props_iterator_init")]),
  # (ti_after_mission_start,  0, 0, [], [(call_script, "script_scene_props_iterator", "script_my_callback_script")]),
########################################################################################################################
# Scene props iterator code ends here
########################################################################################################################

Code:
########################################################################################################################
# Scene props iterator code starts here
########################################################################################################################

  # script_scene_props_iterator_init
  # Input: none
  # Output: none
  ("scene_props_iterator_init",
    [
      (assign, "$g_sp_iterator_count", 0),
      (assign, "$g_sp_iterator_collecting", 1),
    ]
  ),

  # script_scene_props_iterator_finalize
  # Input: none
  # Output: none
  ("scene_props_iterator_finalize",
    [
      (assign, "$g_sp_iterator_collecting", 0),
    ]
  ),

  # script_scene_props_iterator_append
  # Input: scene_prop_instance_id
  # Output: none
  ("scene_props_iterator_append",
    [
      (try_begin),
        (eq, "$g_sp_iterator_collecting", 1),
        (store_script_param_1, ":scene_prop_instance_id"),
        # reg0 version:
        #(call_script, "script_scene_props_iterator_filter", ":scene_prop_instance_id"),
        #(eq, reg0, 1),
        # cf version:
        (call_script, "script_cf_scene_props_iterator_filter", ":scene_prop_instance_id"),
        (troop_set_slot, "trp_scene_props_list", "$g_sp_iterator_count", ":scene_prop_instance_id"),
        (val_add, "$g_sp_iterator_count", 1),
      (try_end),
    ]
  ),

  # script_scene_props_iterator_filter
  # Input: scene_prop_instance_id
  # Output: reg0
  # Note: assign reg0 to zero to prevent scene prop from being appended to iterator list
  ("scene_props_iterator_filter",
    [
      #(store_script_param_1, ":scene_prop_instance_id"),
      (assign, reg0, 1),
    ]
  ),

  # script_cf_scene_props_iterator_filter
  # Input: scene_prop_instance_id
  # Output: none
  # Note: return fail to prevent scene prop from being appended to iterator list
  ("cf_scene_props_iterator_filter",
    [
      #(store_script_param_1, ":scene_prop_instance_id"),
    ]
  ),

  # script_scene_props_iterator
  # Input: callback script (should accept scene_prop_instance_id as parameter)
  # Output: none
  ("scene_props_iterator",
    [
      (call_script, "script_scene_props_iterator_finalize"),
      (store_script_param_1, ":callback_script"),
      (try_begin),
        (gt, ":callback_script", 0),
        (try_for_range_backwards, ":iterator", 0, "$g_sp_iterator_count"),
          (troop_get_slot, ":scene_prop_instance_id", "trp_scene_props_list", ":iterator"),
          (call_script, ":callback_script", ":scene_prop_instance_id"),
        (try_end),
      (try_end),
    ]
  ),

  # script_delete_scene_prop_instance
  # Input: scene_prop_instance_id
  # Output: none
  # Note: This will hide the prop and remove it from iterator list.
  #       Use this to prevent "deleted" props from being processed again and again.
  # Performance note: THIS IS NOT OPTIMIZED TO BE USED FROM WITHIN ITERATOR!
  ("delete_scene_prop_instance",
    [
      (store_script_param_1, ":instance_to_delete"),
      (assign, ":index", -1),
      (try_for_range, ":iterator", 0, "$g_sp_iterator_count"),
        (troop_get_slot, ":found_value", "trp_scene_props_list", ":iterator"),
        (eq, ":instance_to_delete", ":found_value"),
        (assign, ":index", ":iterator"),
      (try_end),
      (try_begin),
        # Have we found the requested scene prop instance?
        (ge, ":index", 0),
        # First we hide it from user's view
        (prop_instance_get_position, pos1, ":instance_to_delete"),
        (position_set_z, pos1, -1000),
        (prop_instance_set_position, ":instance_to_delete", pos1),
        # Now we remove it from the iterator list
        (try_for_range, ":iterator", ":index", "$g_sp_iterator_count"),
          (store_add, ":take_from", ":iterator", 1),
          (troop_get_slot, ":value", "trp_scene_props_list", ":take_from"),
          (troop_set_slot, "trp_scene_props_list", ":iterator", ":value"),
        (try_end),
        # And reduce iterator list size by 1
        (val_sub, "$g_sp_iterator_count", 1),
      (try_end),
    ]
  ),

########################################################################################################################
# Scene props iterator code ends here
########################################################################################################################

This code is even more generic (it doesn't even check for variation ID numbers, leaving it to the author of iterator_filter and callback scripts to decide how to use them or whether to use them at all), equally fast and can easily replicate the effects of "dynamic villages" code.

And it even uses cf_ code according to Vornne's suggestion! :smile:
 
You shouldn't. :smile:

And if seriously, it's a tool to separate the jobs of programmer and scene designer.

Hmm, how about this example. Suppose there are enemy banners above the castle towers when you are doing the siege. When the siege is over, you want those banners to go down. Not a big problem, you know their codes and you program accordingly. But suppose you want the banner above the citadel NOT to go down if there are still defenders in the citadel? Or there's a 3rd party graphics developer who made his own banners and wants to put them on the scene so they would go down as well?

Both these tasks will require additional coding on your side.

With this script, however, the situation is absolutely transparent. Instead of writing a script which moves down all banners of type "prop_tower_banner_a", "prop_tower_banner_b" et cetera, you write a script which moves down all props with 1st var-id equal to 101, and also all props with 1st var-id equal to 102 when there are no defenders left. Additionally, your script will use 2nd variation-id number to determine speed with which those banners go down. Then you just tell scene designers (and put to documentation): "for castle siege missions, all objects with var-id = 101 will be moving down after victory, and all objects with var-id = 102 will also be moving down if there are no defenders left. For both, second var-id determines movement speed, default being 10".

And now a complete stranger can edit your module scenes and add his own objects - he just needs to put correct variation id numbers to the scene props, and they will behave in exactly the same manner in the same situations. He doesn't need to code, or in fact to know anything about how your scripts work, he just needs to know the proper codes.

Or consider a town scene, where you can see your own enterprise. When you are building it, there's a construction area on the town scene. When you built it, there's a house and all related paraphernalia. And as your enterprise develops, so does it's representation on the town scene.

Extra objects on the streets for N hrs after last siege, where N is defined separately for each scene prop? Easily. So within first few hours you will see dead bodies and rubble everywhere, then bodies will be removed but rubble remains, and then even rubble will be cleaned and everything will be fine. And again, you do not have to know or care what scene designers will put on the streets. You just determine what codes mean what and write the filter and callback scripts accordingly, and the rest is the job of scene designers.
 
An example of generic filter and callback scripts.

Operation codes for various situations (scene prop appearance conditions):
Code:
spac_improvement_not_exists      = 60
spac_improvement_is_building     = 61
spac_improvement_exists          = 62
spac_enterprise_not_exists       = 63
spac_enterprise_is_building      = 64
spac_enterprise_exists           = 65
spac_has_5_production_buildings  = 66
spac_has_10_production_buildings = 66
spac_prosperity_ge               = 70
spac_prosperity_lt               = 71
spac_belongs_to_faction          = 72
spac_has_tournament              = 73
spac_specific_day_time           = 74
spac_siege_mission               = 80
spac_siege_and_after_for_hours   = 81
spac_after_siege_for_hours       = 82

Filter and callback scripts:
Code:
  # script_cf_scene_props_iterator_filter
  # Input: scene_prop_instance_id
  # Output: none
  # Note: will filter away all scene props with undefined var-id #1.
  ("cf_scene_props_iterator_filter",
    [
      (store_script_param_1, ":scene_prop_instance_id"),
      (prop_instance_get_variation_id, ":var_id", ":scene_prop_instance_id"),
      (gt, ":var_id", 0),
    ]
  ),

  # script_scene_props_iterator_filter
  # Input: scene_prop_instance_id
  # Output: reg0
  # Note: will filter away all scene props with undefined var-id #1.
  ("scene_props_iterator_filter",
    [
      (assign, reg0, 0),
      (store_script_param_1, ":scene_prop_instance_id"),
      (prop_instance_get_variation_id, ":var_id", ":scene_prop_instance_id"),
      (try_begin),
        (gt, ":var_id", 0),
        (assign, reg0, 1),
      (try_end),
    ]
  ),

  # script_scene_props_iterator_callback
  # Input: scene_prop_instance_id
  # Output: none
  # Opcodes documentation:
  #   ID1 means prop's variation id #1. It determines scene prop's assigned behavior.
  #   ID2 means prop's variation id #2. It determines some aspects of assigned behavior.
  #
  # ID1 60. APPEARS WHEN CENTER IMPROVEMENT DOES NOT EXIST. ID2 determines what improvement to check (1 maps to village_improvements_begin).
  #         Usage tips: to fill the empty space with something.
  # ID1 61. APPEARS WHEN CENTER IMPROVEMENT IS UNDER CONSTRUCTION. ID2 determines what improvement to check (1 maps to village_improvements_begin, or 0 for any village improvement).
  #         Usage tips: entire construction site can be designed if necessary.
  # ID1 62. APPEARS WHEN CENTER IMPROVEMENT IS PRESENT. ID2 determines what improvement to check (1 maps to village_improvements_begin).
  #         Usage tips: self-explanatory.
  # ID1 63. APPEARS WHEN ENTERPRISE DOES NOT EXIST. ID2 determines what enterprise to check (1 maps to trade_goods_begin).
  #         Usage tips: to fill the empty space and to cover the passage into your enterprise.
  # ID1 64. APPEARS WHEN ENTERPRISE IS UNDER CONSTRUCTION. ID2 determines what enterprise to check (1 maps to trade_goods_begin, or 0 for any enterprise).
  #         Usage tipc: to show the construction site and to cover the passage into your enterprise.
  # ID1 65. APPEARS WHEN ENTERPRISE IS PRESENT. ID2 determines what enterprise to check (1 maps to trade_goods_begin, or 0 for any enterprise).
  #         Usage tips: self-explanatory.
  # ID1 66. APPEARS WHEN CENTER HAS AT LEAST 5 PRODUCTION BUILDINGS. ID2 determines production type to check (0 maps to slot_village_number_of_cattle).
  #         Usage tips: center has medium specialty in particular trade, might wish to reflect this on the scene
  # ID1 67. APPEARS WHEN CENTER HAS AT LEAST 10 PRODUCTION BUILDINGS. ID2 determines production type to check (0 maps to slot_village_number_of_cattle).
  #         Usage tips: center has high specialty in particular trade, might wish to reflect this on the scene
  # ID1 70. APPEARS WHEN CENTER PROSPERITY IS ABOVE CERTAIN THRESHOLD (>= check). ID2 is the threshold.
  #         Usage tips: if your town is prosperous, make it look wealthier.
  # ID1 71. APPEARS WHEN CENTER PROSPERITY IS BELOW CERTAIN THRESHOLD (< check). ID2 is the threshold.
  #         Usage tips: signs of desolation and poor lifestyle everywhere.
  # ID1 72. APPEARS WHEN CENTER BELONGS TO CERTAIN FACTION. ID2 is the faction id (direct match).
  #         Usage tips: faction-specific banners on the walls and towers.
  # ID1 73. APPEARS WHEN CENTER HAS TOURNAMENT.
  #         Usage tips: it's celebration time, why not reflect it on town's looks?
  # ID1 74. APPEARS DURING CERTAIN TIME OF DAY ONLY. ID2 is a bitmask determining period (1=night, 2=morning, 4=day, 8=evening).
  #         Usage tips: trade stands which are removed for the night, barriers which are set for the dark time of day...
  # ID1 80. APPEARS DURING SIEGE MISSIONS ONLY.
  #         Usage tips: replicates "script_remove_siege_objects" functionality, but much more versatile.
  # ID1 81. APPEARS DURING SIEGE MISSIONS AND X HOURS AFTER THAT. ID2 is the number of hours. Require additional coding to store the time of last siege.
  #         Usage tips: make damaged walls persist for some time after the siege.
  # ID1 82. APPEARS AFTER SIEGE FOR X HOURS. ID2 is the number of hours. Require additional coding to store the time of last siege.
  #         Usage tips: dead bodies and rubble everywhere.
  #

  ("scene_props_iterator_callback",
    [
      (store_script_param_1, ":scene_prop_instance_id"),
      (try_begin),
        (prop_instance_is_valid, ":scene_prop_instance_id"),
        (prop_instance_get_variation_id, ":operation_code", ":scene_prop_instance_id"),
        (prop_instance_get_variation_id_2, ":op_param", ":scene_prop_instance_id"),
        (assign, ":prop_needs_removal", 0),

        (try_begin),
          (eq, ":operation_code", spac_improvement_not_exists),
          (store_add, ":improvement_slot", village_improvements_begin, ":op_param"),
          (val_sub, ":improvement_slot", 1),
          (try_begin),
            (party_slot_eq, "$g_encountered_party", ":improvement_slot", 1),
            (assign, ":prop_needs_removal", 1),
          (try_end),

        (else_try),
          (eq, ":operation_code", spac_improvement_is_building),
          (store_add, ":improvement_slot", village_improvements_begin, ":op_param"),
          (val_sub, ":improvement_slot", 1),
          (assign, ":prop_needs_removal", 1),
          (try_begin), ## We request perfect match and there's a match
            (neg|eq, ":op_param", 0),
            (party_slot_eq, "$g_encountered_party", slot_center_current_improvement, ":improvement_slot"),
            (assign, ":prop_needs_removal", 0),
          (try_end),
          (try_begin), ## We request any building improvement and there's one building
            (eq, ":op_param", 0),
            (neg|party_slot_eq, "$g_encountered_party", slot_center_current_improvement, 0),
            (assign, ":prop_needs_removal", 0),
          (try_end),

        (else_try),
          (eq, ":operation_code", spac_improvement_exists),
          (store_add, ":improvement_slot", village_improvements_begin, ":op_param"),
          (val_sub, ":improvement_slot", 1),
          (try_begin),
            (party_slot_eq, "$g_encountered_party", ":improvement_slot", 0),
            (assign, ":prop_needs_removal", 1),
          (try_end),

        (else_try),
          (eq, ":operation_code", spac_enterprise_not_exists),
          (store_add, ":enterprise_type", trade_goods_begin, ":op_param"),
          (val_sub, ":enterprise_type", 1),
          (try_begin),
            (party_slot_eq, "$g_encountered_party", slot_center_player_enterprise, ":enterprise_type"),
            (neg|party_slot_ge, "$g_encountered_party", slot_center_player_enterprise_days_until_complete, 1),
            (assign, ":prop_needs_removal", 1),
          (try_end),

        (else_try),
          (eq, ":operation_code", spac_enterprise_is_building),
          (assign, ":prop_needs_removal", 1),
          (party_slot_ge, "$g_encountered_party", slot_center_player_enterprise_days_until_complete, 1),
          (store_add, ":enterprise_type", trade_goods_begin, ":op_param"),
          (val_sub, ":enterprise_type", 1),
          (try_begin), ## We request perfect match and there's a match
            (neg|eq, ":op_param", 0),
            (party_slot_eq, "$g_encountered_party", slot_center_player_enterprise, ":enterprise_type"),
            (assign, ":prop_needs_removal", 0),
          (try_end),
          (try_begin), ## We request any building improvement and there's one building
            (eq, ":op_param", 0),
            (neg|party_slot_eq, "$g_encountered_party", slot_center_player_enterprise, 0),
            (assign, ":prop_needs_removal", 0),
          (try_end),

        (else_try),
          (eq, ":operation_code", spac_enterprise_exists),
          (store_add, ":enterprise_type", trade_goods_begin, ":op_param"),
          (val_sub, ":enterprise_type", 1),
          (try_begin),
            (neg|eq, ":op_param", 0),
            (neg|party_slot_eq, "$g_encountered_party", slot_center_player_enterprise, ":enterprise_type"),
            (assign, ":prop_needs_removal", 1),
          (try_end),
          (try_begin),
            (eq, ":op_param", 0),
            (party_slot_eq, "$g_encountered_party", slot_center_player_enterprise, 0),
            (assign, ":prop_needs_removal", 1),
          (try_end),

        (else_try),
          (eq, ":operation_code", spac_has_5_production_buildings),
          (eq, ":operation_code", spac_improvement_exists),
          (store_add, ":production_slot", slot_village_number_of_cattle, ":op_param"),
          (try_begin),
            (neg|party_slot_ge, "$g_encountered_party", ":production_slot", 5),
            (assign, ":prop_needs_removal", 1),
          (try_end),

        (else_try),
          (eq, ":operation_code", spac_has_10_production_buildings),
          (eq, ":operation_code", spac_improvement_exists),
          (store_add, ":production_slot", slot_village_number_of_cattle, ":op_param"),
          (try_begin),
            (neg|party_slot_ge, "$g_encountered_party", ":production_slot", 10),
            (assign, ":prop_needs_removal", 1),
          (try_end),

        (else_try),
          (eq, ":operation_code", spac_prosperity_ge),
          (neg|party_slot_ge, "$g_encountered_party", slot_town_prosperity, ":op_param"),
          (assign, ":prop_needs_removal", 1),

        (else_try),
          (eq, ":operation_code", spac_prosperity_lt),
          (try_begin),
            (party_slot_ge, "$g_encountered_party", slot_town_prosperity, ":op_param"),
            (assign, ":prop_needs_removal", 1),
          (try_end),

        (else_try),
          (eq, ":operation_code", spac_belongs_to_faction),
          (try_begin),
            (neg|eq, "$g_encountered_party_faction", ":op_param"),
            (assign, ":prop_needs_removal", 1),
          (try_end),

        (else_try),
          (eq, ":operation_code", spac_has_tournament),
          (try_begin),
            (neg|party_slot_ge, "$g_encountered_party", slot_town_has_tournament, 1),
            (assign, ":prop_needs_removal", 1),
          (try_end),

        (else_try),
          (eq, ":operation_code", spac_specific_day_time),
          # TO BE IMPLEMENTED

        (else_try),
          (eq, ":operation_code", spac_siege_mission),
          # TO BE IMPLEMENTED

        (else_try),
          (eq, ":operation_code", spac_siege_and_after_for_hours),
          # TO BE IMPLEMENTED

        (else_try),
          (eq, ":operation_code", spac_after_siege_for_hours),
          # TO BE IMPLEMENTED

        (try_end),

        (try_begin),
          (eq, ":prop_needs_removal", 1),
          (prop_instance_get_position, pos1, ":scene_prop_instance_id"),
          (position_set_z, pos1, -1000),
          (prop_instance_set_position, ":scene_prop_instance_id", pos1),
        (try_end),

      (try_end),
    ]
  ),

And these lines are to be inserted into all mission templates affected by above behaviors:
Code:
  (ti_before_mission_start, 0, 0, [], [(call_script, "script_scene_props_iterator_init")]),
  (ti_after_mission_start,  0, 0, [], [(call_script, "script_scene_props_iterator", "script_scene_props_iterator_callback")]),
 
Great script!  Question - I'm able to remove scene props (portcullis, walls, rock piles, etc.) with this code, but NOT items (ie. items that are placed with edit mode, such as the weapons & shields on the blacksmith's table in town, horses placed in town).  Is there another operation (like prop_instance) that needs to be used with items?  Everything in the edit mode add-item dropdown under "scene props" is retrievable, but it seems that nothing under "item kinds" is.

Any ideas on what I'm doing wrong?  Thanks,
 
There are operations scene_item_get_num_instances and scene_item_get_instance which supposedly have similar effects. However there are also scene_spawned_item_get_num_instances/scene_spawned_item_get_instance operations, as well as ti_on_item_picked_up and ti_on_item_dropped triggers which are used for picked-up/dropped items. Finally, arrows and bolts can stuck in scenery, and I'm not sure how they are handled by the code.

In short, items seem to be somewhat more complex than normal scene props (no big surprise here) so you will probably need some extra research depending on what goals you want to achieve.
 
Back
Top Bottom