#textdomain wesnoth # This file contains general utility macros for WML authors. # # Later macros in this file are built using earlier ones, which # is why they live here rather than being broken out into topic-specific files. # ! in comments is used in generating HTML documentation, ignore it otherwise. #define QUANTITY NAME EASY_VALUE NORMAL_VALUE HARD_VALUE # Macro to define a 'quantity' differently based on difficulty levels. #ifdef EASY {NAME}={EASY_VALUE} #endif #ifdef NORMAL {NAME}={NORMAL_VALUE} #endif #ifdef HARD {NAME}={HARD_VALUE} #endif #enddef #define QUANTITY4 NAME EASY_VALUE NORMAL_VALUE HARD_VALUE NIGHTMARE_VALUE # Four-difficulty version of QUANTITY #ifdef EASY {NAME}={EASY_VALUE} #endif #ifdef NORMAL {NAME}={NORMAL_VALUE} #endif #ifdef HARD {NAME}={HARD_VALUE} #endif #ifdef NIGHTMARE {NAME}={NIGHTMARE_VALUE} #endif #enddef # No tab or space-based indentation for these macros to avoid trouble when these macros are used # in the middle of a quoted string literal # # wmlindent: start ignoring # wmlscope: start conditionals #ifdef EASY #define ON_DIFFICULTY EASY_VALUE NORMAL_VALUE HARD_VALUE {EASY_VALUE}#enddef #endif #ifdef NORMAL #define ON_DIFFICULTY EASY_VALUE NORMAL_VALUE HARD_VALUE {NORMAL_VALUE}#enddef #endif #ifdef HARD #define ON_DIFFICULTY EASY_VALUE NORMAL_VALUE HARD_VALUE {HARD_VALUE}#enddef #endif # wmlscope: stop conditionals # wmlindent: stop ignoring # wmlscope: prune ON_DIFFICULTY # No tab or space-based indentation for these macros to avoid trouble when these macros are used # in the middle of a quoted string literal # # wmlindent: start ignoring # wmlscope: start conditionals #ifdef EASY #define ON_DIFFICULTY4 EASY_VALUE NORMAL_VALUE HARD_VALUE NIGHTMARE_VALUE {EASY_VALUE}#enddef #endif #ifdef NORMAL #define ON_DIFFICULTY4 EASY_VALUE NORMAL_VALUE HARD_VALUE NIGHTMARE_VALUE {NORMAL_VALUE}#enddef #endif #ifdef HARD #define ON_DIFFICULTY4 EASY_VALUE NORMAL_VALUE HARD_VALUE NIGHTMARE_VALUE {HARD_VALUE}#enddef #endif #ifdef NIGHTMARE #define ON_DIFFICULTY4 EASY_VALUE NORMAL_VALUE HARD_VALUE NIGHTMARE_VALUE {NIGHTMARE_VALUE}#enddef #endif # wmlscope: stop conditionals # wmlindent: stop ignoring # wmlscope: prune ON_DIFFICULTY4 #define TURNS EASY_AMOUNT NORMAL_AMOUNT HARD_AMOUNT # Macro to define number of turns for different difficulty levels. {QUANTITY turns {EASY_AMOUNT} {NORMAL_AMOUNT} {HARD_AMOUNT}} #enddef #define TURNS4 EASY_AMOUNT NORMAL_AMOUNT HARD_AMOUNT NIGHTMARE_AMOUNT # Four-difficulty version of TURNS {QUANTITY4 turns {EASY_AMOUNT} {NORMAL_AMOUNT} {HARD_AMOUNT} {NIGHTMARE_AMOUNT}} #enddef #define GOLD EASY_AMOUNT NORMAL_AMOUNT HARD_AMOUNT # Macro which will let you say {GOLD x y z} to set # starting gold depending on easy/medium/hard - x/y/z {QUANTITY gold {EASY_AMOUNT} {NORMAL_AMOUNT} {HARD_AMOUNT}} #enddef #define GOLD4 EASY_AMOUNT NORMAL_AMOUNT HARD_AMOUNT NIGHTMARE_AMOUNT # Four-difficulty version of GOLD {QUANTITY4 gold {EASY_AMOUNT} {NORMAL_AMOUNT} {HARD_AMOUNT} {NIGHTMARE_AMOUNT}} #enddef #define INCOME EASY_AMOUNT NORMAL_AMOUNT HARD_AMOUNT # Macro which will let you say {INCOME x y z} to set # per-turn income depending on easy/medium/hard - x/y/z {QUANTITY income {EASY_AMOUNT} {NORMAL_AMOUNT} {HARD_AMOUNT}} #enddef #define INCOME4 EASY_AMOUNT NORMAL_AMOUNT HARD_AMOUNT NIGHTMARE_AMOUNT # Four-difficulty version of INCOME {QUANTITY4 income {EASY_AMOUNT} {NORMAL_AMOUNT} {HARD_AMOUNT} {NIGHTMARE_AMOUNT}} #enddef #define NO_INCOME # Used to specify when a side should not have any income # every turn. income=-2 #enddef #define ATTACK_DEPTH EASY_VALUE NORMAL_VALUE HARD_VALUE #deprecated 3 1.17 The attack_depth aspect has no effect on the AI any more. #enddef #define ATTACK_DEPTH4 EASY_VALUE NORMAL_VALUE HARD_VALUE NIGHTMARE_VALUE #deprecated 3 1.17 The attack_depth aspect has no effect on the AI any more. #enddef #define NO_SCOUTS # Macro to make an AI team not recruit scouts. villages_per_scout=0 #enddef #define RANDOM THING_VALUE # Macro to quickly pick a random value (in the $random variable, to avoid # cluttering up savegames with such temporary variables). [set_variable] name=random rand={THING_VALUE} [/set_variable] #enddef #define VARIABLE VAR VALUE # Macro to initialize a variable. Strictly a syntatic shortcut. [set_variable] name={VAR} value={VALUE} [/set_variable] #enddef #define GLOBAL_VARIABLE NAMESPACE LOCAL_VAR_NAME GLOBAL_VAR_NAME SIDE #Assigns a persistent variable with the contents of a standard variable. [set_global_variable] namespace={NAMESPACE} from_local={LOCAL_VAR_NAME} to_global={GLOBAL_VAR_NAME} side={SIDE} [/set_global_variable] #enddef #define VARIABLE_FROM_GLOBAL NAMESPACE GLOBAL_VAR_NAME LOCAL_VAR_NAME SIDE #Retrieves the contents of a persistent variable and stores them in a standard variable. [get_global_variable] namespace={NAMESPACE} from_global={GLOBAL_VAR_NAME} to_local={LOCAL_VAR_NAME} side={SIDE} #immediate=no [/get_global_variable] #enddef #define VARIABLE_OP VAR OP_NAME VALUE # Macro to do mathematical operations on variables. [set_variable] name={VAR} {OP_NAME}={VALUE} [/set_variable] #enddef #define VARIABLE_CONDITIONAL VAR OP_NAME VALUE # Macro to do conditional operations on variables. [variable] name={VAR} {OP_NAME}={VALUE} [/variable] #enddef #define CLEAR_VARIABLE VAR_NAME # Macro to clear a variable previously set. [clear_variable] name={VAR_NAME} [/clear_variable] #enddef #define CLEAR_GLOBAL_VARIABLE NAMESPACE MY_VARIABLE_NAME SIDE # Clears a persistent variable entirely. [clear_global_variable] namespace={NAMESPACE} global={MY_VARIABLE_NAME} side={SIDE} immediate=no [/clear_global_variable] #enddef #define REPEAT NUMBER BODY_WML # Macro to execute some WML a defined number of times. # # Example that causes screen to quake 5 times: #! {REPEAT 5 ( #! {QUAKE "rumble.ogg"} #! )} {VARIABLE REPEAT_i 0} [while] [variable] name=REPEAT_i less_than={NUMBER} [/variable] [do] {BODY_WML} {VARIABLE_OP REPEAT_i add 1} [/do] [/while] {CLEAR_VARIABLE REPEAT_i} #enddef #define LOOKUP_INDEX FROM_ARRAY_NAME WHERE_KEY_NAME WHERE_VALUE SAVE_AS_NAME # Call this to lookup an array element that has a particular key-value pair # then it saves the index of that element, or # if the key-value pair is not found it saves the array's length {VARIABLE {SAVE_AS_NAME} 0} [while] [variable] name={SAVE_AS_NAME} less_than=${FROM_ARRAY_NAME}.length [/variable] [variable] name={FROM_ARRAY_NAME}[${SAVE_AS_NAME}].{WHERE_KEY_NAME} not_equals={WHERE_VALUE} [/variable] [do] {VARIABLE_OP {SAVE_AS_NAME} add 1} [/do] [/while] #enddef #define LOOKUP_VALUE FROM_ARRAY_NAME WHERE_KEY_NAME WHERE_VALUE SAVE_KEY_NAME DEFAULT_VALUE SAVE_AS_NAME # Call this to look up an array element that has a particular key-value pair # then it saves another key from that same element. {LOOKUP_INDEX {FROM_ARRAY_NAME} {WHERE_KEY_NAME} {WHERE_VALUE} {SAVE_AS_NAME}} [if] [variable] name={SAVE_AS_NAME} numerical_equals=${FROM_ARRAY_NAME}.length [/variable] [then] {VARIABLE {SAVE_AS_NAME} {DEFAULT_VALUE}} [/then] [else] {VARIABLE {SAVE_AS_NAME} ${FROM_ARRAY_NAME}[${SAVE_AS_NAME}].{SAVE_KEY_NAME}} [/else] [/if] #enddef #define MODIFY_UNIT FILTER VAR VALUE # Alters a unit variable (such as unit.x, unit.type, # unit.side), handling all the storing and unstoring. # # Example that flips all spearmen to side 2: #! {MODIFY_UNIT type=Spearman side 2} [store_unit] [filter] {FILTER} [/filter] variable=MODIFY_UNIT_store kill=yes [/store_unit] [foreach] array=MODIFY_UNIT_store [do] [set_variable] name=this_item.{VAR} value={VALUE} [/set_variable] [unstore_unit] variable=this_item find_vacant=no [/unstore_unit] [/do] [/foreach] {CLEAR_VARIABLE MODIFY_UNIT_store} #enddef #define MOVE_UNIT_BY FILTER OFFSET_X OFFSET_Y # Moves a unit from its current location by the given offset, displaying # movement normally. # # Note that setting the destination on an existing unit does not kill either # one, but causes the unit to move to the nearest vacant hex instead. [store_unit] [filter] {FILTER} [/filter] variable=MOVE_UNIT_store kill=yes [/store_unit] [foreach] array=MOVE_UNIT_store [do] {VARIABLE_OP this_item.x add {OFFSET_X}} {VARIABLE_OP this_item.y add {OFFSET_Y}} [unstore_unit] variable=this_item find_vacant=no [/unstore_unit] [/do] [/foreach] {CLEAR_VARIABLE MOVE_UNIT_store} #enddef #define MOVE_UNIT FILTER TO_X TO_Y # Moves a unit from its current location to the given location, displaying # movement normally. # # Note that setting the destination on an existing unit does not kill either # one, but causes the unit to move to the nearest vacant hex instead. [move_unit] {FILTER} to_x={TO_X} to_y={TO_Y} fire_event=no [/move_unit] #enddef #define FULL_HEAL FILTER # Heals matching units to full hitpoints. [heal_unit] [filter] {FILTER} [/filter] amount=full restore_statuses=yes [/heal_unit] #enddef #define PUT_TO_RECALL_LIST FILTER # This places a given unit back to the recall list of the side it is on. # Note however, that the unit is not healed to full health, so when # recalled (even if not until the next scenario) the unit may have less # than his maximum hp left. # # An example that returns all units stepping on (20,38) back to the recall # list: # #! [event] #! name=moveto #! #! [filter] #! x,y=20,38 #! [/filter] #! #! {PUT_TO_RECALL_LIST x,y=20,38} #! [/event] [put_to_recall_list] {FILTER} [/put_to_recall_list] #enddef #define RECRUIT_UNIT_VARIATIONS SIDE TYPE VARIATIONS_VALUE # Allows a side to seemingly recruit variations of a given unit, such as the # the Walking Corpse. # # An example which makes side 2 have a 50% chance of getting a normal WC # and a 50% chance of getting either a drake or dwarf variation: #! {RECRUIT_UNIT_VARIATIONS 2 "Walking Corpse" none,none,drake,dwarf} [event] name=prerecruit first_time_only=no [filter] side={SIDE} type={TYPE} [/filter] {VARIABLE_OP recruited_unit_random_variation rand {VARIATIONS_VALUE}} [if] [variable] name=recruited_unit_random_variation not_equals=none [/variable] [then] [object] duration=forever silent=yes [filter] x,y=$x1,$y1 [/filter] [effect] apply_to=variation name=$recruited_unit_random_variation [/effect] [effect] apply_to=hitpoints heal_full=yes [/effect] [/object] [/then] [/if] {CLEAR_VARIABLE recruited_unit_random_variation} [/event] #enddef #define SCATTER_UNITS NUMBER TYPES PADDING_RADIUS FILTER UNIT_WML # Scatters the given kind of units randomly on a given area on the map. # # An example which scatters some loyal elves on forest hexes in # x,y=10-30,20-40, at a minimum of three hexes apart from each other and # never on top of or adjacent to any already existing units: #! {SCATTER_UNITS 20 "Elvish Fighter,Elvish Archer,Elvish Shaman" 3 ( #! terrain=Gs^Fp #! x=10-30 #! y=20-40 #! #! [not] #! [filter] #! [/filter] #! [/not] #! #! [not] #! [filter_adjacent_location] #! [filter] #! [/filter] #! [/filter_adjacent_location] #! [/not] #! ) ( #! side=2 #! generate_name=yes #! random_traits=yes #! #! [modifications] #! {TRAIT_LOYAL} #! [/modifications] #! )} [set_variables] name=unit_type_table [split] list={TYPES} key=type separator=, [/split] [/set_variables] {VARIABLE unit_type_table_i 0} [random_placement] num_items={NUMBER} variable=random_placement_location allow_less=yes min_distance={PADDING_RADIUS} [filter_location] {FILTER} include_borders=no [/filter_location] [command] [unit] type=$unit_type_table[$unit_type_table_i].type x,y=$random_placement_location.x,$random_placement_location.y {UNIT_WML} [/unit] {VARIABLE unit_type_table_i ("$(($unit_type_table_i + 1) % $unit_type_table.length)")} [/command] [/random_placement] {CLEAR_VARIABLE unit_type_table,unit_type_table_i,random_placement_location} #enddef #define FORCE_CHANCE_TO_HIT FILTER SECOND_FILTER CTH_NUMBER EXTRA_CONDITIONS_WML # Invisibly forces certain units to always have a specific chance to hit # when fighting against certain other units. # # Note that the player still only sees the regular damage calculations, so # this is useful if you need to give an invisible helping hand to the player # or AI. For example, if the player is forced to attack with only a couple # of units at the beginning of a scenario, you can use this to ensure that # simply having bad luck cannot ruin their attempt so easily. Also you might # have enemy leaders which the player is not supposed to fight or be able to # defeat due to storyline reasons, but could theoretically still kill with # some clever trick, AI mistake or sheer exceptional luck. # # An example which forces Konrad's attacks to always hit Li'sar, but only # after turn 10: #! {FORCE_CHANCE_TO_HIT id=Konrad id="Li'sar" 100 ( #! [variable] #! name=turn_number #! greater_than=10 #! [/variable] #! )} # WARNING : if an unit must disappear in mid-battle before attack end was fired, don't use [unstore_unit] but recreate unit or cth modifications # persist. Or don't use this macro. [event] name=attack first_time_only=no [filter] {FILTER} [/filter] [filter_second] {SECOND_FILTER} [/filter_second] [filter_condition] [and] {EXTRA_CONDITIONS_WML} [/and] [/filter_condition] [object] id=forced_cth [filter] id=$unit.id [/filter] silent=yes duration=turn end take_only_once=no [effect] apply_to=new_ability [abilities] [chance_to_hit] id=forced_cth value={CTH_NUMBER} cumulative=no affect_self=yes overwrite_specials=both_sides [overwrite] priority=1000 [/overwrite] [filter_opponent] {SECOND_FILTER} [/filter_opponent] [/chance_to_hit] [/abilities] [/effect] [/object] [event] name=attack end [remove_object] object_id=forced_cth [/remove_object] [/event] [/event] # The following event is a simple duplicates of the above ones, with the # primary and secondary units reversed so that the effect is applied also on # defense. [event] name=attack first_time_only=no [filter] {SECOND_FILTER} [/filter] [filter_second] {FILTER} [/filter_second] [filter_condition] [and] {EXTRA_CONDITIONS_WML} [/and] [/filter_condition] [object] id=forced_cth [filter] id=$second_unit.id [/filter] silent=yes duration=turn end take_only_once=no [effect] apply_to=new_ability [abilities] [chance_to_hit] id=forced_cth value={CTH_NUMBER} cumulative=no affect_self=yes overwrite_specials=both_sides [overwrite] priority=1000 [/overwrite] [filter_opponent] {SECOND_FILTER} [/filter_opponent] [/chance_to_hit] [/abilities] [/effect] [/object] [event] name=attack end [remove_object] object_id=forced_cth [/remove_object] [/event] [/event] [event] name=unit placed first_time_only=no [filter] ability=forced_cth [/filter] [remove_object] object_id=forced_cth [/remove_object] [/event] [event] name=prestart,start,victory [filter_condition] [have_unit] ability=forced_cth [/have_unit] [/filter_condition] [remove_object] object_id=forced_cth [/remove_object] [/event] #enddef #define LOOT AMOUNT SIDE # Gives the player some gold, with a message. {VARIABLE amount_gold {AMOUNT}} #TODO add message for the other players! [message] side_for={SIDE} speaker=narrator message= _ "You retrieve $amount_gold pieces of gold." image=wesnoth-icon.png sound=gold.ogg [/message] {CLEAR_VARIABLE amount_gold} [gold] side={SIDE} amount={AMOUNT} [/gold] #enddef #define CREDITS_SEPARATOR # Add a credits entry that serves as a separator between groups. [entry] name = "•" [/entry] #enddef