home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2010 July / maximum-cd-2010-07.iso / DiscContents / wesnoth-1.8-win32.exe / data / core / macros / utils.cfg < prev   
Encoding:
Text File  |  2010-03-08  |  25.2 KB  |  854 lines

  1. #textdomain wesnoth
  2. # This file contains general utility macros for WML authors.
  3. #
  4. # Later macros in this file are built using earlier ones, which
  5. # is why they live here rather than being broken out into topic-specific files.
  6.  
  7. # ! in comments is used in generating HTML documentation, ignore it otherwise.
  8. #define QUANTITY NAME EASY_VALUE NORMAL_VALUE HARD_VALUE
  9.     # Macro to define a 'quantity' differently based on difficulty levels.
  10. #ifdef EASY
  11.     {NAME}={EASY_VALUE}
  12. #endif
  13. #ifdef NORMAL
  14.     {NAME}={NORMAL_VALUE}
  15. #endif
  16. #ifdef HARD
  17.     {NAME}={HARD_VALUE}
  18. #endif
  19. #enddef
  20.  
  21. #define TURNS EASY_AMOUNT NORMAL_AMOUNT HARD_AMOUNT
  22.     # Macro to define number of turns for different difficulty levels.
  23.     {QUANTITY turns {EASY_AMOUNT} {NORMAL_AMOUNT} {HARD_AMOUNT}}
  24. #enddef
  25.  
  26. #define GOLD EASY_AMOUNT NORMAL_AMOUNT HARD_AMOUNT
  27.     # Macro which will let you say {GOLD x y z} to set
  28.     # starting gold depending on easy/medium/hard - x/y/z
  29.     {QUANTITY gold {EASY_AMOUNT} {NORMAL_AMOUNT} {HARD_AMOUNT}}
  30. #enddef
  31.  
  32. #define INCOME EASY_AMOUNT NORMAL_AMOUNT HARD_AMOUNT
  33.     # Macro which will let you say {GOLD x y z} to set
  34.     # per-turn income depending on easy/medium/hard - x/y/z
  35.     {QUANTITY income {EASY_AMOUNT} {NORMAL_AMOUNT} {HARD_AMOUNT}}
  36. #enddef
  37.  
  38. #define NO_INCOME
  39.     # Used to specify when a side should not have any income
  40.     # every turn.
  41.     income=-2
  42. #enddef
  43.  
  44. #define ATTACK_DEPTH EASY_VALUE NORMAL_VALUE HARD_VALUE
  45.     # Macro to define AI attack depth for different difficulty levels
  46.     # (set it to 1-6)
  47.     {QUANTITY attack_depth {EASY_VALUE} {NORMAL_VALUE} {HARD_VALUE}}
  48. #enddef
  49.  
  50. #define NO_SCOUTS
  51.     # Macro to make an AI team not recruit scouts.
  52.     villages_per_scout=0
  53. #enddef
  54.  
  55. #define RANDOM THING_VALUE
  56.     # Macro to quickly pick a random value (in the $random variable, to avoid
  57.     # cluttering up savegames with such temporary variables).
  58.     [set_variable]
  59.         name=random
  60.         rand={THING_VALUE}
  61.     [/set_variable]
  62. #enddef
  63.  
  64. #define VARIABLE VAR VALUE
  65.     # Macro to initialize a variable.  Strictly a syntatic shortcut.
  66.     [set_variable]
  67.         name={VAR}
  68.         value={VALUE}
  69.     [/set_variable]
  70. #enddef
  71.  
  72. #define VARIABLE_OP VAR OP_NAME VALUE
  73.     # Macro to do mathematical operations on variables.
  74.     [set_variable]
  75.         name={VAR}
  76.         {OP_NAME}={VALUE}
  77.     [/set_variable]
  78. #enddef
  79.  
  80. #define CLEAR_VARIABLE VAR
  81.     # Macro to clear a variable previously set.
  82.     [clear_variable]
  83.         name={VAR}
  84.     [/clear_variable]
  85. #enddef
  86.  
  87. # wmlindent: start ignoring
  88. #define FOREACH ARRAY_VALUE VAR
  89. # Macro to begin a WML clause that iterates over an array.
  90. {VARIABLE {VAR} 0}
  91. [while]
  92.     [variable]
  93.     name={VAR}
  94.     less_than=${ARRAY_VALUE}.length
  95.     [/variable]
  96.     [do]
  97. #enddef
  98.  
  99. #define NEXT VAR
  100. # Macro to end a WML clause that iterates over an array.
  101.     [set_variable]
  102.     name={VAR}
  103.     add=1
  104.     [/set_variable]
  105.     [/do]
  106. [/while]
  107. {CLEAR_VARIABLE {VAR}}
  108. #enddef
  109. # wmlindent: stop ignoring
  110.  
  111. # wmlindent: opener "{FOREACH "
  112. # wmlindent: closer "{NEXT "
  113.  
  114. #define REPEAT NUMBER BODY_WML
  115.     # Macro to execute some WML a defined number of times.
  116.     #
  117.     # Example that causes screen to quake 5 times:
  118.     #! {REPEAT 5 (
  119.     #!     {QUAKE "rumble.ogg"}
  120.     #! )}
  121.     {VARIABLE REPEAT_i 0}
  122.  
  123.     [while]
  124.         [variable]
  125.             name=REPEAT_i
  126.             less_than={NUMBER}
  127.         [/variable]
  128.  
  129.         [do]
  130.             {BODY_WML}
  131.  
  132.             {VARIABLE_OP REPEAT_i add 1}
  133.         [/do]
  134.     [/while]
  135.  
  136.     {CLEAR_VARIABLE REPEAT_i}
  137. #enddef
  138.  
  139. #define LOOKUP_INDEX FROM_ARRAY_NAME WHERE_KEY_NAME WHERE_VALUE SAVE_AS_NAME
  140.     # Call this to lookup an array element that has a particular key-value pair
  141.     # then it saves the index of that element, or
  142.     # if the key-value pair is not found it saves the array's length
  143.     {VARIABLE {SAVE_AS_NAME} 0}
  144.     [while]
  145.         [variable]
  146.             name={SAVE_AS_NAME}
  147.             less_than=${FROM_ARRAY_NAME}.length
  148.         [/variable]
  149.         [variable]
  150.             name={FROM_ARRAY_NAME}[${SAVE_AS_NAME}].{WHERE_KEY_NAME}
  151.             not_equals={WHERE_VALUE}
  152.         [/variable]
  153.         [do]
  154.             {VARIABLE_OP {SAVE_AS_NAME} add 1}
  155.         [/do]
  156.     [/while]
  157. #enddef
  158.  
  159. #define LOOKUP_VALUE FROM_ARRAY_NAME WHERE_KEY_NAME WHERE_VALUE SAVE_KEY_NAME DEFAULT_VALUE SAVE_AS_NAME
  160.     # Call this to look up an array element that has a particular key-value pair
  161.     # then it saves another key from that same element.
  162.     {LOOKUP_INDEX {FROM_ARRAY_NAME} {WHERE_KEY_NAME} {WHERE_VALUE} {SAVE_AS_NAME}}
  163.     [if]
  164.         [variable]
  165.             name={SAVE_AS_NAME}
  166.             numerical_equals=${FROM_ARRAY_NAME}.length
  167.         [/variable]
  168.         [then]
  169.             {VARIABLE {SAVE_AS_NAME} {DEFAULT_VALUE}}
  170.         [/then]
  171.         [else]
  172.             {VARIABLE {SAVE_AS_NAME} ${FROM_ARRAY_NAME}[${SAVE_AS_NAME}].{SAVE_KEY_NAME}}
  173.         [/else]
  174.     [/if]
  175. #enddef
  176.  
  177. #define DEBUG_MSG MESSAGE_TEXT
  178.     # Emit a debug message.  Meant to be overridden with no-op definition
  179.     # of the same name for production use.
  180.     [message]
  181.         speaker=narrator
  182.         message={MESSAGE_TEXT}
  183.         image=wesnoth-icon.png
  184.     [/message]
  185. #enddef
  186.  
  187. #define MODIFY_UNIT FILTER VAR VALUE
  188.     # Alters a unit variable (such as unit.x, unit.type,
  189.     # unit.side), handling all the storing and unstoring.
  190.     #
  191.     # Example that flips all spearmen to side 2:
  192.     #! {MODIFY_UNIT type=Spearman side 2}
  193.     [store_unit]
  194.         [filter]
  195.             {FILTER}
  196.         [/filter]
  197.  
  198.         variable=MODIFY_UNIT_store
  199.         kill=yes
  200.     [/store_unit]
  201.  
  202.     {FOREACH MODIFY_UNIT_store MODIFY_UNIT_i}
  203.         [set_variable]
  204.             name=MODIFY_UNIT_store[$MODIFY_UNIT_i].{VAR}
  205.             value={VALUE}
  206.         [/set_variable]
  207.  
  208.         [unstore_unit]
  209.             variable=MODIFY_UNIT_store[$MODIFY_UNIT_i]
  210.             find_vacant=no
  211.         [/unstore_unit]
  212.     {NEXT MODIFY_UNIT_i}
  213.  
  214.     {CLEAR_VARIABLE MODIFY_UNIT_store}
  215. #enddef
  216.  
  217. #define MOVE_UNIT_BY FILTER OFFSET_X OFFSET_Y
  218.     #TODO COMMENT
  219.     [store_unit]
  220.         [filter]
  221.             {FILTER}
  222.         [/filter]
  223.  
  224.         variable=MOVE_UNIT_store
  225.         kill=yes
  226.     [/store_unit]
  227.  
  228.     {FOREACH MOVE_UNIT_store unit}
  229.         {VARIABLE_OP MOVE_UNIT_store[$unit].x add {OFFSET_X}}
  230.         {VARIABLE_OP MOVE_UNIT_store[$unit].y add {OFFSET_Y}}
  231.         [unstore_unit]
  232.             variable=MOVE_UNIT_store[$unit]
  233.             find_vacant=no
  234.         [/unstore_unit]
  235.     {NEXT unit}
  236.     {CLEAR_VARIABLE MOVE_UNIT_store}
  237. #enddef
  238.  
  239. #define MOVE_UNIT FILTER TO_X TO_Y
  240.     # Moves a unit from its current location to the given location along a
  241.     # relatively straight line displaying the movement just like
  242.     # [move_unit_fake] does.
  243.     #
  244.     # Note that setting the destination on an existing unit does not kill either
  245.     # one, but causes the unit to move to the nearest vacant hex instead.
  246.     [store_unit]
  247.         [filter]
  248.             {FILTER}
  249.         [/filter]
  250.  
  251.         variable=MOVE_UNIT_temp
  252.         kill=no
  253.     [/store_unit]
  254.  
  255.     [scroll_to]
  256.         x=$MOVE_UNIT_temp.x
  257.         y=$MOVE_UNIT_temp.y
  258.     [/scroll_to]
  259.  
  260.     {VARIABLE_OP MOVE_UNIT_path_coords_x format ("$MOVE_UNIT_temp.x|,{TO_X}")}
  261.     {VARIABLE_OP MOVE_UNIT_path_coords_y format ("$MOVE_UNIT_temp.y|,{TO_Y}")}
  262.  
  263.     [if]
  264.         [variable]
  265.             name=MOVE_UNIT_temp.x
  266.             less_than={TO_X}
  267.         [/variable]
  268.  
  269.         [then]
  270.             {VARIABLE MOVE_UNIT_temp.facing se}
  271.         [/then]
  272.  
  273.         [else]
  274.             [if]
  275.                 [variable]
  276.                     name=MOVE_UNIT_temp.x
  277.                     greater_than={TO_X}
  278.                 [/variable]
  279.  
  280.                 [then]
  281.                     {VARIABLE MOVE_UNIT_temp.facing sw}
  282.                 [/then]
  283.             [/if]
  284.         [/else]
  285.     [/if]
  286.  
  287.     {VARIABLE MOVE_UNIT_temp.x {TO_X}}
  288.     {VARIABLE MOVE_UNIT_temp.y {TO_Y}}
  289.  
  290.     [kill]
  291.         {FILTER}
  292.  
  293.         animate=no
  294.         fire_event=no
  295.     [/kill]
  296.  
  297.     [move_unit_fake]
  298.         type=$MOVE_UNIT_temp.type
  299.         gender=$MOVE_UNIT_temp.gender
  300.         variation=$MOVE_UNIT_temp.variation
  301.         side=$MOVE_UNIT_temp.side
  302.         x=$MOVE_UNIT_path_coords_x
  303.         y=$MOVE_UNIT_path_coords_y
  304.     [/move_unit_fake]
  305.  
  306.     [unstore_unit]
  307.         variable=MOVE_UNIT_temp
  308.         find_vacant=yes
  309.     [/unstore_unit]
  310.  
  311.     [redraw][/redraw]
  312.     {CLEAR_VARIABLE MOVE_UNIT_temp}
  313.     {CLEAR_VARIABLE MOVE_UNIT_path_coords_x}
  314.     {CLEAR_VARIABLE MOVE_UNIT_path_coords_y}
  315. #enddef
  316.  
  317. #define FULL_HEAL FILTER
  318.     # This heals the specified unit(s) to full health.
  319.     [store_unit]
  320.         [filter]
  321.             {FILTER}
  322.         [/filter]
  323.         variable=FULL_HEAL_temp
  324.     [/store_unit]
  325.  
  326.     {FOREACH FULL_HEAL_temp FULL_HEAL_i}
  327.         [set_variable]
  328.             name=FULL_HEAL_temp[$FULL_HEAL_i].hitpoints
  329.             value=$FULL_HEAL_temp[$FULL_HEAL_i].max_hitpoints
  330.         [/set_variable]
  331.         [unstore_unit]
  332.             find_vacant=no
  333.             variable=FULL_HEAL_temp[$FULL_HEAL_i]
  334.         [/unstore_unit]
  335.     {NEXT FULL_HEAL_i}
  336.  
  337.     {CLEAR_VARIABLE FULL_HEAL_temp}
  338. #enddef
  339.  
  340. #define PUT_TO_RECALL_LIST FILTER
  341.     # This places a given unit back to the recall list of the side it is on.
  342.     # Note however, that the unit is not healed to full health, so when
  343.     # recalled (even if not until the next scenario) the unit may have less
  344.     # than his maximum hp left.
  345.     #
  346.     # An example that returns all units stepping on (20,38) back to the recall
  347.     # list:
  348.     #
  349.     #! [event]
  350.     #!     name=moveto
  351.     #!
  352.     #!     [filter]
  353.     #!         x,y=20,38
  354.     #!     [/filter]
  355.     #!
  356.     #!     {PUT_TO_RECALL_LIST x,y=20,38}
  357.     #! [/event]
  358.     [store_unit]
  359.         [filter]
  360.             {FILTER}
  361.         [/filter]
  362.  
  363.         variable=PUT_TO_RECALL_LIST_temp
  364.         kill=yes
  365.     [/store_unit]
  366.  
  367.     {FOREACH PUT_TO_RECALL_LIST_temp i}
  368.         {VARIABLE PUT_TO_RECALL_LIST_temp[$i].x "recall"}
  369.         {VARIABLE PUT_TO_RECALL_LIST_temp[$i].y "recall"}
  370.  
  371.         [unstore_unit]
  372.             variable=PUT_TO_RECALL_LIST_temp[$i]
  373.             find_vacant=no
  374.         [/unstore_unit]
  375.     {NEXT i}
  376.  
  377.     {CLEAR_VARIABLE PUT_TO_RECALL_LIST_temp}
  378. #enddef
  379.  
  380. # FIXME: Documentation for these is needed.
  381.  
  382. #define MENU_IMG_TXT IMAGE TEXT
  383. "&"+{IMAGE}+"="+{TEXT}#enddef
  384.  
  385. #define MENU_IMG_TXT2 IMAGE FIRST_TEXT_VALUE SECOND_TEXT_VALUE
  386. "&"+{IMAGE}+"="+{FIRST_TEXT_VALUE}+"="+{SECOND_TEXT_VALUE}#enddef
  387.  
  388. #define TIME_ACTIONS CONTENT_WML
  389.     # Measure (in milliseconds) the time arbitrary event WML takes to
  390.     # execute.  Afterwards, the time the enclosed WML took to execute
  391.     # is found in the variable $timed_actions_ms.
  392.     #
  393.     # Example:
  394.     #! [event]
  395.     #!     name=start
  396.     #!
  397.     #!     {TIME_ACTIONS (
  398.     #!         {MODIFY_UNIT race=orc name ( _ "Azir")}
  399.     #!     )}
  400.     #!
  401.     #!     {DEBUG_MSG "Renaming all orcs to Azir took $timed_actions_ms|ms."}
  402.     #! [/event]
  403.     {VARIABLE_OP TIME_ACTIONS_time_begin time stamp}
  404.  
  405.     {CONTENT_WML}
  406.  
  407.     {VARIABLE_OP TIME_ACTIONS_time_end time stamp}
  408.  
  409.     {VARIABLE timed_actions_ms $TIME_ACTIONS_time_end}
  410.     {VARIABLE_OP timed_actions_ms add "-$TIME_ACTIONS_time_begin"}
  411.  
  412.     {CLEAR_VARIABLE TIME_ACTIONS_time_begin}
  413.     {CLEAR_VARIABLE TIME_ACTIONS_time_end}
  414. #enddef
  415.  
  416. #define RECRUIT_UNIT_VARIATIONS SIDE TYPE VARIATIONS_VALUE
  417.     # Allows a side to seemingly recruit variations of a given unit, such as the
  418.     # the Walking Corpse.
  419.     #
  420.     # An example which makes side 2 have a 50% chance of getting a normal WC
  421.     # and a 50% chance of getting either a drake or dwarf variation:
  422.     #! {RECRUIT_UNIT_VARIATIONS 2 "Walking Corpse" none,none,drake,dwarf}
  423.     [event]
  424.         name=prerecruit
  425.         first_time_only=no
  426.  
  427.         [filter]
  428.             side={SIDE}
  429.             type={TYPE}
  430.         [/filter]
  431.  
  432.         {VARIABLE_OP recruited_unit_random_variation rand {VARIATIONS_VALUE}}
  433.  
  434.         [if]
  435.             [variable]
  436.                 name=recruited_unit_random_variation
  437.                 not_equals=none
  438.             [/variable]
  439.  
  440.             [then]
  441.                 [object]
  442.                     duration=forever
  443.                     silent=yes
  444.  
  445.                     [filter]
  446.                         x,y=$x1,$y1
  447.                     [/filter]
  448.  
  449.                     [effect]
  450.                         apply_to=variation
  451.                         name=$recruited_unit_random_variation
  452.                     [/effect]
  453.                 [/object]
  454.             [/then]
  455.         [/if]
  456.     [/event]
  457. #enddef
  458.  
  459. #define NEUTRAL_SIDE SIDE
  460.     # Allows a side to appear as if allied with every other side.
  461.     #
  462.     # Limitations: if we have three sides A, B and C, and C is a neutral side, then
  463.     # sides B and C will appear as enemies during A's turn, and likewise A and C on
  464.     # B's turn.
  465.     #
  466.     # IMPORTANT NOTE: the scenario needs victory_when_enemies_defeated=no to be set.
  467.     # Also note that this can also be achieved by assigning a side to multiple
  468.     # teams using comma-seperated names in the side's team_name.
  469.     [event]
  470.         name=prestart
  471.  
  472.         {VARIABLE NEUTRAL_SIDE_i 1}
  473.  
  474.         [store_side]
  475.             side=$NEUTRAL_SIDE_i
  476.             variable=NEUTRAL_SIDE_side_store
  477.         [/store_side]
  478.  
  479.         [while]
  480.             [variable]
  481.                 name=NEUTRAL_SIDE_side_store.team_name
  482.                 not_equals=$empty
  483.             [/variable]
  484.  
  485.             [do]
  486.                 {VARIABLE side_$NEUTRAL_SIDE_i|_original_team_name $NEUTRAL_SIDE_side_store.team_name}
  487.                 {VARIABLE side_$NEUTRAL_SIDE_i|_original_user_team_name $NEUTRAL_SIDE_side_store.user_team_name}
  488.  
  489.                 {VARIABLE_OP NEUTRAL_SIDE_i add 1}
  490.  
  491.                 {CLEAR_VARIABLE NEUTRAL_SIDE_side_store}
  492.  
  493.                 [store_side]
  494.                     side=$NEUTRAL_SIDE_i
  495.                     variable=NEUTRAL_SIDE_side_store
  496.                 [/store_side]
  497.             [/do]
  498.         [/while]
  499.  
  500.         {CLEAR_VARIABLE NEUTRAL_SIDE_side_store}
  501.     [/event]
  502.  
  503.     [event]
  504.         name=side turn
  505.         first_time_only=no
  506.  
  507.         [if]
  508.             [variable]
  509.                 name=side_number
  510.                 not_equals={SIDE}
  511.             [/variable]
  512.  
  513.             [then]
  514.                 {VARIABLE NEUTRAL_SIDE_i 1}
  515.  
  516.                 [while]
  517.                     [variable]
  518.                         name=side_$NEUTRAL_SIDE_i|_original_team_name
  519.                         not_equals=$empty
  520.                     [/variable]
  521.  
  522.                     [do]
  523.                         [modify_side]
  524.                             side=$NEUTRAL_SIDE_i
  525.                             team_name=$side_$NEUTRAL_SIDE_i|_original_team_name
  526.                             user_team_name=$side_$NEUTRAL_SIDE_i|_original_user_team_name
  527.                         [/modify_side]
  528.  
  529.                         {VARIABLE_OP NEUTRAL_SIDE_i add 1}
  530.                     [/do]
  531.                 [/while]
  532.  
  533.                 [store_side]
  534.                     side=$side_number
  535.                     variable=NEUTRAL_SIDE_side_store
  536.                 [/store_side]
  537.  
  538.                 [modify_side]
  539.                     side={SIDE}
  540.                     team_name=$NEUTRAL_SIDE_side_store.team_name
  541.                     user_team_name=$side_{SIDE}_original_user_team_name
  542.                 [/modify_side]
  543.  
  544.                 {CLEAR_VARIABLE NEUTRAL_SIDE_side_store}
  545.             [/then]
  546.  
  547.             [else]
  548.                 {VARIABLE NEUTRAL_SIDE_i 1}
  549.  
  550.                 [while]
  551.                     [variable]
  552.                         name=side_$NEUTRAL_SIDE_i|_original_team_name
  553.                         not_equals=$empty
  554.                     [/variable]
  555.  
  556.                     [do]
  557.                         [modify_side]
  558.                             side=$NEUTRAL_SIDE_i
  559.                             team_name=friends_with_all
  560.                             user_team_name=$side_$NEUTRAL_SIDE_i|_original_user_team_name
  561.                         [/modify_side]
  562.  
  563.                         {VARIABLE_OP NEUTRAL_SIDE_i add 1}
  564.                     [/do]
  565.                 [/while]
  566.             [/else]
  567.         [/if]
  568.     [/event]
  569. #enddef 
  570. #define SCATTER_UNITS NUMBER TYPES PADDING_RADIUS FILTER UNIT_WML
  571.     # Scatters the given kind of units randomly on a given area on the map.
  572.     #
  573.     # An example which scatters some loyal elves on forest hexes in
  574.     # x,y=10-30,20-40, at a minimum of three hexes apart from each other and
  575.     # never on top of or adjacent to any already existing units:
  576.     #! {SCATTER_UNITS 20 "Elvish Fighter,Elvish Archer,Elvish Shaman" 3 (
  577.     #!     terrain=Gs^Fp
  578.     #!     x=10-30
  579.     #!     y=20-40
  580.     #!
  581.     #!     [not]
  582.     #!         [filter]
  583.     #!         [/filter]
  584.     #!     [/not]
  585.     #!
  586.     #!     [not]
  587.     #!         [filter_adjacent_location]
  588.     #!             [filter]
  589.     #!             [/filter]
  590.     #!         [/filter_adjacent_location]
  591.     #!     [/not]
  592.     #! ) (
  593.     #!     side=2
  594.     #!     generate_name=yes
  595.     #!     random_traits=yes
  596.     #!
  597.     #!     [modifications]
  598.     #!         {TRAIT_LOYAL}
  599.     #!     [/modifications]
  600.     #! )}
  601.  
  602.     [store_locations]
  603.         {FILTER}
  604.  
  605.         variable=possible_unit_locations
  606.     [/store_locations]
  607.  
  608.     [set_variables]
  609.         name=unit_type_table
  610.  
  611.         [split]
  612.             list={TYPES}
  613.             key=type
  614.             separator=,
  615.         [/split]
  616.     [/set_variables]
  617.  
  618.     {VARIABLE unit_type_table_i 0}
  619.     {VARIABLE units_to_place {NUMBER}}
  620.  
  621.     [while]
  622.         [variable]
  623.             name=units_to_place
  624.             greater_than=0
  625.         [/variable]
  626.  
  627.         [do]
  628.             [set_variable]
  629.                 name=random_subscript
  630.                 rand=1..$possible_unit_locations.length
  631.             [/set_variable]
  632.             {VARIABLE_OP random_subscript add -1}
  633.  
  634.             [unit]
  635.                 type=$unit_type_table[$unit_type_table_i].type
  636.                 x,y=$possible_unit_locations[$random_subscript].x,$possible_unit_locations[$random_subscript].y
  637.                 {UNIT_WML}
  638.             [/unit]
  639.  
  640.             [store_locations]
  641.                 find_in=possible_unit_locations
  642.                 [not]
  643.                     x,y=$possible_unit_locations[$random_subscript].x,$possible_unit_locations[$random_subscript].y
  644.                     radius={PADDING_RADIUS}
  645.                 [/not]
  646.                 variable=possible_unit_locations
  647.             [/store_locations]
  648.  
  649.             [if]
  650.                 [variable]
  651.                     name=possible_unit_locations.length
  652.                     less_than=1
  653.                 [/variable]
  654.  
  655.                 [then]
  656.                     {VARIABLE units_to_place 0}
  657.                 [/then]
  658.             [/if]
  659.  
  660.             {VARIABLE_OP unit_type_table_i add 1}
  661.  
  662.             [if]
  663.                 [variable]
  664.                     name=unit_type_table_i
  665.                     numerical_equals=$unit_type_table.length
  666.                 [/variable]
  667.  
  668.                 [then]
  669.                     {VARIABLE unit_type_table_i 0}
  670.                 [/then]
  671.             [/if]
  672.  
  673.             {VARIABLE_OP units_to_place add -1}
  674.         [/do]
  675.     [/while]
  676.  
  677.     {CLEAR_VARIABLE unit_type_table,unit_type_table_i,possible_unit_locations,random_subscript,units_to_place}
  678. #enddef
  679.  
  680. #define FORCE_CHANCE_TO_HIT FILTER SECOND_FILTER CTH_NUMBER EXTRA_CONDITIONS_WML
  681.     # Invisibly forces certain units to always have a specific chance to hit
  682.     # when fighting against certain other units.
  683.     #
  684.     # Note that the player still only sees the regular damage calculations, so
  685.     # this is useful if you need to give an invisible helping hand to the player
  686.     # or AI. For example, if the player is forced to attack with only a couple
  687.     # of units at the beginning of a scenario, you can use this to ensure that
  688.     # simply having bad luck cannot ruin their attempt so easily. Also you might
  689.     # have enemy leaders which the player is not supposed to fight or be able to
  690.     # defeat due to storyline reasons, but could theoretically still kill with
  691.     # some clever trick, AI mistake or sheer exceptional luck.
  692.     #
  693.     # An example which forces Konrad's attacks to always hit Li'sar, but only
  694.     # after turn 10:
  695.     #! {FORCE_CHANCE_TO_HIT id=Konrad id="Li'sar" 100 (
  696.     #!     [variable]
  697.     #!         name=turn_number
  698.     #!         greater_than=10
  699.     #!     [/variable]
  700.     #! )}
  701.     [event]
  702.         name=attack
  703.         first_time_only=no
  704.  
  705.         [filter]
  706.             {FILTER}
  707.         [/filter]
  708.  
  709.         [filter_second]
  710.             {SECOND_FILTER}
  711.         [/filter_second]
  712.  
  713.         [if]
  714.             [and]
  715.                 {EXTRA_CONDITIONS_WML}
  716.             [/and]
  717.  
  718.             [then]
  719.                 {FOREACH unit.attack i}
  720.                     [if]
  721.                         [variable]
  722.                             name=unit.attack[$i].specials.chance_to_hit.length
  723.                             greater_than=0
  724.                         [/variable]
  725.  
  726.                         [then]
  727.                             [set_variables]
  728.                                 name=unit.attack[$i].specials.original_chance_to_hit
  729.                                 to_variable=unit.attack[$i].specials.chance_to_hit
  730.                             [/set_variables]
  731.  
  732.                             {CLEAR_VARIABLE unit.attack[$i].specials.chance_to_hit}
  733.                         [/then]
  734.                     [/if]
  735.  
  736.                     [set_variables]
  737.                         name=unit.attack[$i].specials.chance_to_hit
  738.  
  739.                         [value]
  740.                             id=forced_cth
  741.                             value={CTH_NUMBER}
  742.                             cumulative=no
  743.                         [/value]
  744.                     [/set_variables]
  745.                 {NEXT i}
  746.  
  747.                 [unstore_unit]
  748.                     variable=unit
  749.                     find_vacant=no
  750.                 [/unstore_unit]
  751.  
  752.                 [event]
  753.                     name=attack end
  754.                     delayed_variable_substitution=yes
  755.  
  756.                     {FOREACH unit.attack i}
  757.                         {CLEAR_VARIABLE unit.attack[$i].specials.chance_to_hit}
  758.  
  759.                         [set_variables]
  760.                             name=unit.attack[$i].specials.chance_to_hit
  761.                             to_variable=unit.attack[$i].specials.original_chance_to_hit
  762.                         [/set_variables]
  763.  
  764.                         {CLEAR_VARIABLE unit.attack[$i].specials.original_chance_to_hit}
  765.                     {NEXT i}
  766.  
  767.                     [unstore_unit]
  768.                         variable=unit
  769.                         find_vacant=no
  770.                     [/unstore_unit]
  771.                 [/event]
  772.             [/then]
  773.         [/if]
  774.     [/event]
  775.  
  776.     # The following event is a simple duplicates of the above ones, with the
  777.     # primary and secondary units reversed so that the effect is applied also on
  778.     # defense.
  779.     [event]
  780.         name=attack
  781.         first_time_only=no
  782.  
  783.         [filter]
  784.             {SECOND_FILTER}
  785.         [/filter]
  786.  
  787.         [filter_second]
  788.             {FILTER}
  789.         [/filter_second]
  790.  
  791.         [if]
  792.             [and]
  793.                 {EXTRA_CONDITIONS_WML}
  794.             [/and]
  795.  
  796.             [then]
  797.                 {FOREACH second_unit.attack i}
  798.                     [if]
  799.                         [variable]
  800.                             name=second_unit.attack[$i].specials.chance_to_hit.length
  801.                             greater_than=0
  802.                         [/variable]
  803.  
  804.                         [then]
  805.                             [set_variables]
  806.                                 name=second_unit.attack[$i].specials.original_chance_to_hit
  807.                                 to_variable=second_unit.attack[$i].specials.chance_to_hit
  808.                             [/set_variables]
  809.  
  810.                             {CLEAR_VARIABLE second_unit.attack[$i].specials.chance_to_hit}
  811.                         [/then]
  812.                     [/if]
  813.  
  814.                     [set_variables]
  815.                         name=second_unit.attack[$i].specials.chance_to_hit
  816.  
  817.                         [value]
  818.                             id=forced_cth
  819.                             value={CTH_NUMBER}
  820.                             cumulative=no
  821.                         [/value]
  822.                     [/set_variables]
  823.                 {NEXT i}
  824.  
  825.                 [unstore_unit]
  826.                     variable=second_unit
  827.                     find_vacant=no
  828.                 [/unstore_unit]
  829.  
  830.                 [event]
  831.                     name=attack end
  832.                     delayed_variable_substitution=yes
  833.  
  834.                     {FOREACH second_unit.attack i}
  835.                         {CLEAR_VARIABLE second_unit.attack[$i].specials.chance_to_hit}
  836.  
  837.                         [set_variables]
  838.                             name=second_unit.attack[$i].specials.chance_to_hit
  839.                             to_variable=second_unit.attack[$i].specials.original_chance_to_hit
  840.                         [/set_variables]
  841.  
  842.                         {CLEAR_VARIABLE second_unit.attack[$i].specials.original_chance_to_hit}
  843.                     {NEXT i}
  844.  
  845.                     [unstore_unit]
  846.                         variable=second_unit
  847.                         find_vacant=no
  848.                     [/unstore_unit]
  849.                 [/event]
  850.             [/then]
  851.         [/if]
  852.     [/event]
  853. #enddef
  854.