Difference between revisions of "PreprocessorRef"

From The Battle for Wesnoth Wiki
m (The WML preprocessor)
(Pre-1.4 cleanup.)
Line 11: Line 11:
 
be parsed for macros, and after macro expansion will be parsed for macros
 
be parsed for macros, and after macro expansion will be parsed for macros
 
again, and so on.  As a result, you should not write a recursive macro,
 
again, and so on.  As a result, you should not write a recursive macro,
because it will cause an infinite loop.
+
because it will cause errors
[http://www.wesnoth.org/forum/viewtopic.php?t=5838 Changes to the preprocessor in 0.9.2]
+
(but, alas, not necessarily error messages).
allow recursively nested #ifdefs, but recursively nested
 
macro definitions ('#define') will still cause errors
 
(but not necessarily error messages).
 
  
 
The following directives are used to create and use ''macros'',
 
The following directives are used to create and use ''macros'',
Line 70: Line 67:
 
* If ''filename'' points to a directory, the preprocessor will include all files in the directory ''filename'', non-recursively and in alphabetical order.  Starting in 1.3.3, some files in such directories are handled specially.   
 
* If ''filename'' points to a directory, the preprocessor will include all files in the directory ''filename'', non-recursively and in alphabetical order.  Starting in 1.3.3, some files in such directories are handled specially.   
  
{{DevFeature}} If there is a file named ''dir/_main.cfg'' in a directory referenced as '''{''dir''}''', only that ''_main.cfg'' file is processed; it may include other files in itself, of course . This feature is useful for creating WML directories that are self-contained WML packages with their own initializations (like campaigns). This can replace the older convention of having a ''dir.cfg'' at the same level as ''dir'' which does '''{''dir''}''' somewhere in itself.
+
If there is a file named ''dir/_main.cfg'' in a directory referenced as '''{''dir''}''', only that ''_main.cfg'' file is processed; it may include other files in itself, of course . This feature is useful for creating WML directories that are self-contained WML packages with their own initializations (like campaigns). This can replace the older convention of having a ''dir.cfg'' at the same level as ''dir'' which does '''{''dir''}''' somewhere in itself.
  
{{DevFeature}} If there are files named ''dir/*/_main.cfg'' in a directory referenced as '''{''dir''}''', where * is any subdirectories ''dir'', then they all are processed (except if there is also a file named ''dir/_main.cfg''). This means that if you have a layout like this:
+
If there are files named ''dir/*/_main.cfg'' in a directory referenced as '''{''dir''}''', where * is any subdirectories ''dir'', then they all are processed (except if there is also a file named ''dir/_main.cfg''). This means that if you have a layout like this:
 
  dir/
 
  dir/
 
  dir/a/_main.cfg
 
  dir/a/_main.cfg
Line 81: Line 78:
 
Then '''{dir}''' will process (in alphabetical order): dir/a/_main.cfg, dir/b/main.cfg, dir/other.cfg.
 
Then '''{dir}''' will process (in alphabetical order): dir/a/_main.cfg, dir/b/main.cfg, dir/other.cfg.
  
{{DevFeature}} If there is a file named ''dir/_final.cfg'' in a directory referenced as '''{''dir''}''' (and no ''main.cfg'', so that all files in the directory are processed normally) the ''_final.cfg'' is guaranteed to be processed ''after'' all other files in the directory.
+
If there is a file named ''dir/_final.cfg'' in a directory referenced as '''{''dir''}''' (and no ''main.cfg'', so that all files in the directory are processed normally) the ''_final.cfg'' is guaranteed to be processed ''after'' all other files in the directory.
  
 
Note that the parser was changed various times, so don't expect older Wesnoth version to behave exactly the same.
 
Note that the parser was changed various times, so don't expect older Wesnoth version to behave exactly the same.

Revision as of 19:11, 13 January 2008

[edit]WML Tags

A:

abilities, about, add_ai_behavior, advance, advanced_preference, advancefrom, advancement, advances, affect_adjacent, ai, allied_with, allow_end_turn, allow_extra_recruit, allow_recruit, allow_undo, and, animate, animate_unit, animation, aspect, attack, attack_anim, attacks, avoid;

B:

base_unit, berserk, binary_path, break, brush;

C:

campaign, cancel_action, candidate_action, capture_village, case, chance_to_hit, change_theme, chat, choose, clear_global_variable, clear_menu_item, clear_variable, color_adjust, color_range, command (action, replay), continue, criteria;

D:

damage, death, deaths, default, defend, defends, defense, delay, deprecated_message, destination, difficulty, disable, disallow_end_turn, disallow_extra_recruit, disallow_recruit, do, do_command, drains, draw_weapon_anim;

E:

editor_group, editor_music, editor_times, effect, else (action, animation), elseif, endlevel, end_turn (action, replay), enemy_of, engine, entry, era, event, extra_anim;

F:

facet, facing, fake_unit, false, feedback, female, filter (concept, event), filter_adjacent, filter_adjacent_location, filter_attack, filter_attacker, filter_base_value, filter_condition, filter_defender, filter_enemy, filter_location, filter_opponent, filter_own, filter_owner, filter_radius, filter_recall, filter_second, filter_second_attack, filter_self, filter_side, filter_vision, filter_weapon, filter_wml, find_path, fire_event, firststrike, floating_text, for, foreach, frame, full_heal;

G:

game_config, get_global_variable, goal, gold, gold_carryover;

H:

harm_unit, has_ally, has_attack, has_unit, have_location, have_unit, heal_on_hit, heal_unit, healed_anim, healing_anim, heals, hide_help, hide_unit, hides;

I:

idle_anim, if (action, animation), illuminates, image, init_side, insert_tag, inspect, item, item_group;

J:

jamming_costs, join;

K:

kill, killed;

L:

label, language, leader, leader_goal, leadership, leading_anim, levelin_anim, levelout_anim, lift_fog, limit, literal, load_resource, locale, lock_view, lua;

M:

male, menu_item, message, micro_ai, missile_frame, modification, modifications, modify_ai, modify_side, modify_turns, modify_unit, modify_unit_type, move, move_unit, move_unit_fake, move_units_fake, movement_anim, movement costs, movetype, multiplayer, multiplayer_side, music;

N:

not, note;

O:

object, objective, objectives, on_undo, open_help, option, options, or;

P:

part, petrifies, petrify, place_shroud, plague, poison, portrait, post_movement_anim, pre_movement_anim, primary_attack, primary_unit, print, put_to_recall_list;

R:

race, random_placement, recall (action, replay), recalls, recruit, recruit_anim, recruiting_anim, recruits, redraw, regenerate, remove_event, remove_item, remove_object, remove_shroud, remove_sound_source, remove_time_area, remove_unit_overlay, repeat, replace_map, replace_schedule, replay, replay_start, reset_fog, resistance (ability, unit), resistance_defaults, resource, return, role, rule;

S:

save, scenario, scroll, scroll_to, scroll_to_unit, secondary_attack, secondary_unit, section, select_unit, sequence, set_extra_recruit, set_global_variable, set_menu_item, set_recruit, set_specials, set_variable, set_variables, sheath_weapon_anim, show_if (message, set_menu_item), show_objectives, side, skirmisher, slow, snapshot, sound, sound_source, source (replay, teleport), special_note, specials, split, stage, standing_anim, statistics, status, store_gold, store_items, store_locations, store_map_dimensions, store_reachable_locations, store_relative_direction, store_side, store_starting_location, store_time_of_day, store_turns, store_unit, store_unit_defense, store_unit_type, store_unit_type_ids, store_villages, story, swarm, switch, sync_variable;

T:

target, team, teleport (ability, action), teleport_anim, terrain, terrain_defaults, terrain_graphics, terrain_mask, terrain_type, test, test_condition, text_input, textdomain, theme, then, tile, time, time_area, topic, toplevel, trait, transform_unit, traveler, true, tunnel, tutorial;

U:

unhide_unit, unit, unit_overlay, unit_type, unit_worth, units, unlock_view, unpetrify, unstore_unit, unsynced;

V:

value, variable, variables, variation, victory_anim, village, vision_costs, volume;

W:

while, wml_message, wml_schema;

Z:

zoom;

The WML preprocessor

Wesnoth loads just one configuration file directly: data/game.cfg. However the WML preprocessor allows game.cfg to load in more files. Whenever a WML file is read by Wesnoth, it is passed through the preprocessor.

The preprocessor can interpret a simple language of string-expansions known as "macros." A macro should always be defined before the place where it needs to be used.

The preprocessor is applied recursively, so included files will be parsed for macros, and after macro expansion will be parsed for macros again, and so on. As a result, you should not write a recursive macro, because it will cause errors (but, alas, not necessarily error messages).

The following directives are used to create and use macros, i.e. shortcuts which reduce repetition of information. See UtilWML, UsefulWMLFragments for examples.

  • #define symbol [parameters] newline substitution #enddef all subsequent occurences of {symbol [arguments]} (see below) will be replaced by substitution with all occurences of any parameter {parameter} within substitution replaced by the parameter's corresponding value in arguments. For example, the UNIT macro used below would be defined:
#define UNIT TYPE X Y## the ordering is important here;
                     ## since WML does not distinguish
                     ## data into different types, only
                     ## the ordering is used to determine which
                     ## arguments apply to which parameters.
[unit]
type={TYPE}## the unit will be of type TYPE, so different
           ## instantiations
           ## of this macro can create different units.
x={X}
y={Y}
side=2## the unit will be an enemy, regardless of the parameter
      ## values. This reduces "repetition of information",
      ## since it is no longer necessary to specify
      ## each created unit as an enemy.
[/unit]
#enddef

(See SingleUnitWML for information on creating units using WML.)

  • {symbol [arguments]} if symbol is defined, the preprocessor will replace this instruction by the expression symbol is defined as, using arguments as parameters. You can create multiple word arguments by using parentheses to restrain the argument. For example, while {UNIT Wolf Rider 18 24} will attempt to create a "Wolf" at (Rider,18), causing Wesnoth to crash, the macro {UNIT (Wolf Rider) 18 24} will create a "Wolf Rider" at (18,24) as it should. (UNIT is defined above). See the #define preprocessor instruction above for information on defining symbols, including symbols with arguments. Several symbols are defined in the normal game code; for reference they are listed in UtilWML.

Unlike the other preprocessor directives, #ifdef and #ifndef are not mere conveniences. They are necessary to distinguish between different modes of play.

  • #ifdef symbol substitution-if-stored [#else substitution-if-not-stored] #endif If symbol has been stored, the whole block will be replaced by substitution-if-stored. If not, it will be replaced by substitution-if-not-stored if it is available. symbol can take the following values:
    • a campaign difficulty level. Usually EASY, NORMAL, or HARD, it is decided by the key difficulties (see CampaignWML).
    • a campaign ID. Each campaign stores a preprocessor ID. See define, CampaignWML.
    • MULTIPLAYER is stored when the player is playing or setting up a multiplayer game (i.e. a game with scenario_type=multiplayer).
    • TUTORIAL is stored when the player is playing the tutorial.
    • APPLE is stored if the computer Wesnoth is being run on is an Apple. (this one is only available to the configuration of the game)
    • PYTHON is stored if Python support is built in and available. Use this to for example show a warning when starting a campaign that uses Python AI's, if Python isn't available.
  • #ifndef behaves exactly like #ifdef, except that it inverts the test sense; guarded text is included only if symbol has not been stored. (Available in 1.3.10 or later.)

#undef can be useful too if #ifdef is not enough.

  • #undef symbol erases symbol (v1.1.1+svn)

These directives expand a file by including other files, filename may not contain '..' or the directive will be skipped:

  • {filename} if filename isn't a predefined symbol (see above), Wesnoth will assume it's a path to a file in the main data/ subdirectory of Wesnoth and include the file it points to here "as is". Forward slashes(/) should be used to separate directories from their elements, even if your platform uses a different symbol such as colon (:) or backslash (\).
  • {~filename} similar to above, but the preprocessor assumes that the filename is relative to the user data directory. The user data directory varies depending on platform:
Platform | User Data Directory
-------------------------
UNIX     | ~/.wesnoth/data/
Mac OS X | ~/Library/Preferences/Wesnoth or ~/.wesnoth/data
Windows  | "main Wesnoth folder"\userdata
  • {@filename} is a convenient way to make Wesnoth look for a file by that name in both the main and the user data directory. It is equivalent to writing {filename}{~filename}.
  • {./filename} is similar to the {filename} directive, but is assumed to be relative to the directory which contains the file in which this appears. For example, if used in game.cfg, it is equivalent to {filename}.
  • If filename points to a directory, the preprocessor will include all files in the directory filename, non-recursively and in alphabetical order. Starting in 1.3.3, some files in such directories are handled specially.

If there is a file named dir/_main.cfg in a directory referenced as {dir}, only that _main.cfg file is processed; it may include other files in itself, of course . This feature is useful for creating WML directories that are self-contained WML packages with their own initializations (like campaigns). This can replace the older convention of having a dir.cfg at the same level as dir which does {dir} somewhere in itself.

If there are files named dir/*/_main.cfg in a directory referenced as {dir}, where * is any subdirectories dir, then they all are processed (except if there is also a file named dir/_main.cfg). This means that if you have a layout like this:

dir/
dir/a/_main.cfg
dir/a/other.cfg
dir/b/_main.cfg
dir/b/other.cfg
dir/other.cfg

Then {dir} will process (in alphabetical order): dir/a/_main.cfg, dir/b/main.cfg, dir/other.cfg.

If there is a file named dir/_final.cfg in a directory referenced as {dir} (and no main.cfg, so that all files in the directory are processed normally) the _final.cfg is guaranteed to be processed after all other files in the directory.

Note that the parser was changed various times, so don't expect older Wesnoth version to behave exactly the same.

See Also