# This file contains utility macros for scenario writers

#### TABLE OF CONTENTS ####

# variable operations

#	RANDOM
#	VARIABLE
#	VARIABLE_OP
#	CLEAR_VARIABLE
#	FOREACH
#	NEXT
#	IF_TERRAIN
#	DEBUG_MSG

# scenario/campaign setup

#	DEFAULT_MUSIC_PLAYLIST
#	SCENARIO_MUSIC
#	STARTING_VILLAGES
#	DOT
#	CROSS
#	MENU_IMG_TXT
#	MENU_IMG_TXT2
#	LIMIT_RECRUITS
#	LIMIT_CONTEMPORANEOUS_RECRUITS

# side setup

#	TURNS
#	GOLD
#	INCOME
#	ATTACK_DEPTH
#	NO_SCOUTS

# in-scenario actions

#	PLACE_IMAGE
#	TREMOR
#	IS_HERO
#	UNIT
#	UNDEAD_UNIT
#	MOVE_UNIT
#	MODIFY_UNIT
#	STORE_UNIT_VAR
#	PUT_TO_RECALL_LIST

# utilities not intended for general use

#	QUANTITY
#	MAGENTA_IS_THE_TEAM_COLOR
#	COLOR_HEAL
#	COLOR_HARM
#	COLOR_WHITE
#	IMAGE_DEFENSIVE
#	IMAGE_DEFENSIVE_RANGE
#	IMAGE_DEFENSIVE_SHORT

#### END OF TABLE OF CONTENTS ####

#macro to define a 'quantity' differently based on difficulty levels
#define QUANTITY ATTRIBUTE ON_EASY ON_NORMAL ON_HARD
#ifdef EASY
{ATTRIBUTE}={ON_EASY}
#endif

#ifdef NORMAL
{ATTRIBUTE}={ON_NORMAL}
#endif

#ifdef HARD
{ATTRIBUTE}={ON_HARD}
#endif
#enddef

#macro to define number of turns for different difficulty levels
#define TURNS ON_EASY ON_NORMAL ON_HARD
{QUANTITY turns {ON_EASY} {ON_NORMAL} {ON_HARD}}
#enddef

#macro which will let you go {GOLD x y z} to set
#the gold depending on easy/medium/hard - x/y/z

#define GOLD ON_EASY ON_NORMAL ON_HARD
{QUANTITY gold {ON_EASY} {ON_NORMAL} {ON_HARD}}
#enddef

#define INCOME ON_EASY ON_NORMAL ON_HARD
{QUANTITY income {ON_EASY} {ON_NORMAL} {ON_HARD}}
#enddef

#macro to define AI attack depth for different difficulty levels (set it to 1-6)
#define ATTACK_DEPTH ON_EASY ON_NORMAL ON_HARD
{QUANTITY attack_depth {ON_EASY} {ON_NORMAL} {ON_HARD}}
#enddef

#macro to make an AI team not recruit scouts
#define NO_SCOUTS
villages_per_scout=0
#enddef

#macro to add a hero icon to the unit
#define IS_HERO
overlays="misc/hero-icon.png"
#enddef

#define DOT X Y
[image]
x,y={X},{Y}
file=misc/dot.png
delay=500
[/image]
#enddef

#define CROSS X Y
[image]
x,y={X},{Y}
file=misc/cross.png
delay=500
[/image]
#enddef


#macro to quickly pick a random value (in the $random variable, to avoid
#cluterring up savegames with such temporary variables)

#define RANDOM RANGE
[set_variable]
name=random
random={RANGE}
[/set_variable]
#enddef

#macro to initialize a variable
#define VARIABLE VAR VALUE
[set_variable]
name={VAR}
value={VALUE}
[/set_variable]
#enddef

#macro to do mathematical operations on variables
#define VARIABLE_OP VAR OP ARG
[set_variable]
name={VAR}
{OP}={ARG}
[/set_variable]
#enddef

#define CLEAR_VARIABLE VAR
[clear_variable]
name={VAR}
[/clear_variable]
#enddef

#macro to iterate over an array
#define FOREACH ARRAY VAR
{VARIABLE {VAR} 0}
[while]
	[variable]
	name={VAR}
	less_than=${ARRAY}.length
	[/variable]
	[do]
#enddef

#define NEXT VAR
	[set_variable]
	name={VAR}
	add=1
	[/set_variable]
	[/do]
[/while]
{CLEAR_VARIABLE {VAR}}
#enddef

#define DEBUG_MSG MSG
[message]
speaker=narrator
message={MSG}
[/message]
#enddef



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

#define MODIFY_UNIT FILTER VAR VALUE
    [store_unit]
        [filter]
            {FILTER}
        [/filter]

        variable=MODIFY_UNIT_store
        kill=yes
    [/store_unit]

    {FOREACH MODIFY_UNIT_store MODIFY_UNIT_i}
        [set_variable]
            name=MODIFY_UNIT_store[$MODIFY_UNIT_i].{VAR}
            format={VALUE}
        [/set_variable]

        [unstore_unit]
            variable=MODIFY_UNIT_store[$MODIFY_UNIT_i]
            find_vacant=no
        [/unstore_unit]
    {NEXT MODIFY_UNIT_i}

    {CLEAR_VARIABLE MODIFY_UNIT_store}
#enddef


# Stores an attribute of a unit to the given variable.
#
# Example where this is used to flip all orcs to whatever side James is on:
#
# {STORE_UNIT_VAR description=James side side_of_James}
# {MODIFY_UNIT race=orc side $side_of_James}

#define STORE_UNIT_VAR FILTER VAR TO_VAR
    [store_unit]
        [filter]
            {FILTER}
        [/filter]

        kill=no
        variable=STORE_UNIT_VAR_store
    [/store_unit]

    {VARIABLE_OP {TO_VAR} format $STORE_UNIT_VAR_store.{VAR}}

    {CLEAR_VARIABLE STORE_UNIT_VAR_store}
#enddef


# This is a way to check whether or not the terrain in the given coordinates
# is of the given type or types. Might be useful, since filtering by terrain
# isn't possible directly.
#
# You can use it for example like this:
#
# [event]
#     name=moveto
#     first_time_only=no
#
#     {IF_TERRAIN $x1 $y1 gfm (
#         [then]
#             {DEBUG_MSG "Stepped on grassland, forest or mountains!"}
#         [/then]
#     )}
# [/event]

#define IF_TERRAIN X Y TYPES CONTENTS
    [store_locations]
        x={X}
        y={Y}
        terrain={TYPES}
        variable=IF_TERRAIN_temp
    [/store_locations]

    [if]
        [variable]
            name=IF_TERRAIN_temp.length
            not_equals=0
        [/variable]

        {CONTENTS}
    [/if]

    {CLEAR_VARIABLE IF_TERRAIN_temp}
#enddef


# Moves a unit from its current location to the given location along a
# relatively straight line displaying the movement just like [move_unit_fake]
# does.
#
# 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.

#define MOVE_UNIT FILTER TO_X TO_Y
    [store_unit]
        [filter]
            {FILTER}
        [/filter]

        variable=MOVE_UNIT_temp
        kill=yes
    [/store_unit]

    [scroll_to]
        x=$MOVE_UNIT_temp.x
        y=$MOVE_UNIT_temp.y
    [/scroll_to]

    {VARIABLE_OP x_coords format ("$MOVE_UNIT_temp.x|,{TO_X}")}
    {VARIABLE_OP y_coords format ("$MOVE_UNIT_temp.y|,{TO_Y}")}
    
    {VARIABLE MOVE_UNIT_temp.x {TO_X}}
    {VARIABLE MOVE_UNIT_temp.y {TO_Y}}

    [move_unit_fake]
        type=$MOVE_UNIT_temp.type
        x=$x_coords
        y=$y_coords
        side=$MOVE_UNIT_temp.side
    [/move_unit_fake]
    
    [unstore_unit]
    	variable=MOVE_UNIT_temp
    [/unstore_unit]
#enddef


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

#define PUT_TO_RECALL_LIST FILTER
    [store_unit]
        [filter]
            {FILTER}
        [/filter]

        variable=PUT_TO_RECALL_LIST_temp
        kill=yes
    [/store_unit]

	{FOREACH PUT_TO_RECALL_LIST_temp i}
        {VARIABLE PUT_TO_RECALL_LIST_temp[$i].x "recall"}
        {VARIABLE PUT_TO_RECALL_LIST_temp[$i].y "recall"}

        [unstore_unit]
            variable=PUT_TO_RECALL_LIST_temp[$i]
            find_vacant=no
        [/unstore_unit]
    {NEXT i}
#enddef


#macro to make a side start a scenario with villages

#define STARTING_VILLAGES SIDE RADIUS
[event]
name=prestart
	[store_starting_location]
	side={SIDE}
	variable=temp_starting_location
	[/store_starting_location]
	[store_locations]
	x,y=$temp_starting_location.x,$temp_starting_location.y
	radius={RADIUS}
	variable=temp_starting_locs

	#all the types of villages
	terrain=AaBbDeLptUvVZY
	[/store_locations]

	{FOREACH temp_starting_locs i}
		{VARIABLE_OP temp_x_var to_variable temp_starting_locs[$i].x}
		{VARIABLE_OP temp_y_var to_variable temp_starting_locs[$i].y}
		[capture_village]
		side={SIDE}
		x,y=$temp_x_var,$temp_y_var
		[/capture_village]
	{NEXT i}

	{CLEAR_VARIABLE temp_x_var}
	{CLEAR_VARIABLE temp_y_var}
	{CLEAR_VARIABLE temp_starting_location}
	{CLEAR_VARIABLE temp_starting_locs}
	{CLEAR_VARIABLE i}
[/event]
#enddef

#define MENU_IMG_TXT IMG TXT
"&"+{IMG}+"="+{TXT}#enddef

#define MENU_IMG_TXT2 IMG TXT1 TXT2
"&"+{IMG}+"="+{TXT1}+"="+{TXT2}#enddef

#
#USAGE {UNIT (Elvish Fighter) (Myname) ( _ "Myname") 1 1 1}
#

#define UNIT TYPE DESCRIPTION UDESCRIPTION SIDE X Y
	[unit]
		type={TYPE}
		description={DESCRIPTION}
		user_description={UDESCRIPTION}
		side={SIDE}
		x={X}
		y={Y}
		[modifications]
			{TRAIT_LOYAL}
		[/modifications]
	[/unit]
#enddef

#define UNDEAD_UNIT TYPE SIDE X Y
	[unit]
		type={TYPE}
		side={SIDE}
		x={X}
		y={Y}
		[modifications]
			{TRAIT_UNDEAD}
			{TRAIT_LOYAL}
		[/modifications]
	[/unit]
#enddef

#define PLACE_IMAGE IMAGE_FILE X Y
	[item]
		x={X}
		y={Y}
		image={IMAGE_FILE}
	[/item]
#enddef

#define TREMOR
	[sound]
	name="rumble.ogg"
	[/sound]
	[scroll]
		x=5
		y=0
	[/scroll]
	[scroll]
		x=-10
		y=0
	[/scroll]
	[scroll]
		x=5
		y=5
	[/scroll]
	[scroll]
		x=0
		y=-10
	[/scroll]
	[scroll]
		x=0
		y=5
	[/scroll]
#enddef


#macro to easily replace image_defensive and image_defensive_range

#define IMAGE_DEFENSIVE IMAGE_FILE
	[defend]
		[frame]
		begin=-150
		end=150
		image={IMAGE_FILE}
		[/frame]
	[/defend]
#enddef

#define IMAGE_DEFENSIVE_RANGE IMAGE_FILE
	[defend]
	range=ranged
		[frame]
		begin=-150
		end=150
		image={IMAGE_FILE}
		[/frame]
	[/defend]
#enddef

#define IMAGE_DEFENSIVE_SHORT IMAGE_FILE
	[defend]
	range=melee
		[frame]
		begin=-150
		end=150
		image={IMAGE_FILE}
		[/frame]
	[/defend]
#enddef

# a macro to define a common set of magenta color values which different
# units can be color shifted by using the team color system

#define MAGENTA_IS_THE_TEAM_COLOR
flag_rgb=magenta
#enddef


# Music macros.  As of 1.1.3, music is parsed as follows:
# 1. the [scenario]-level [music] tag
# 2. the [story]-level music key
# 3. any [event]-level [music] tags
#
# If you change the music at a lower level, the tags above it will NOT be re-parsed
# and your scenario will sound wrong.  For example, if you set scenario music
# with the normal [scenario]-level music tag but change the music during the [story],
# it is never reset back to normal.  Therefore, these macros are intended to catch
# instances like that.  Of course, if you want something more elaborate, code it
# manually.


# A macro to define a standard playlist suitable for any level.  The music is defined
# twice to catch instances where music is changed in a story and not set back.

#define DEFAULT_MUSIC_PLAYLIST
	[music]
		name=gameplay01.ogg
		ms_before=12000
	[/music]
	[music]
		name=gameplay02.ogg
		ms_before=12000
		append=yes
	[/music]
	[music]
		name=gameplay03.ogg
		ms_before=12000
		append=yes
	[/music]
	[music]
		name=main_menu.ogg
		ms_before=12000
		append=yes
	[/music]
	[music]
		name=wesnoth-1.ogg
		ms_before=12000
		append=yes
	[/music]
	[music]
		name=wesnoth-2.ogg
		ms_before=12000
		append=yes
	[/music]
	[event]
	name=prestart
		[music]
				name=gameplay01.ogg
				ms_before=12000
		[/music]
		[music]
				name=gameplay02.ogg
				ms_before=12000
				append=yes
		[/music]
		[music]
				name=gameplay03.ogg
				ms_before=12000
				append=yes
		[/music]
		[music]
				name=main_menu.ogg
				ms_before=12000
				append=yes
		[/music]
		[music]
				name=wesnoth-1.ogg
				ms_before=12000
				append=yes
		[/music]
		[music]
				name=wesnoth-2.ogg
				ms_before=12000
				append=yes
		[/music]
	[/event]
#enddef

#
# This music macro ensures that the correct music is selected
# for a scenario just in case it is changed by [story].
# It should be positioned at the top of the scenario file
# so it can be overridden by other prestart or start events.
#
# It also allows for the convenient use of a standardized
# intra-scenario music, should we decide to use one.
#

#define SCENARIO_MUSIC MUSIC
[music]
name="wesnoth-2.ogg"
[/music]
[event]
name=prestart
	[music]
	name={MUSIC}
	[/music]
[/event]
#enddef

#define COLOR_HEAL
green=255
#enddef

#define COLOR_HARM
red=255
#enddef

#define COLOR_WHITE
red=255
green=255
blue=255
#enddef

# With this, you can easily limit the number of units of a certain type a side
# can have simultaneously. When the number of units of type TYPE the side has
# reaches or exceeds LIMIT, that side is prevented from recruiting more until
# the number of units of that type drops below LIMIT again.
#
# This one is probably most useful in balancing AI behaviour - to for example
# give an AI side the possibility to recruit high level units but not to have
# too many of them at the same time.

#define LIMIT_CONTEMPORANEOUS_RECRUITS SIDE TYPE LIMIT 
	[event]
		name=side turn
		first_time_only=no

		[if]
			[variable]
				name=side_number
				equals={SIDE}
			[/variable]

			[then]
				[store_unit]
					[filter]
						side={SIDE}
						type={TYPE}
					[/filter]

					kill=no
					variable=LIMIT_CONTEMPORANEOUS_RECRUITS_temp
				[/store_unit]
				
				[if]
					[variable]
						name=LIMIT_CONTEMPORANEOUS_RECRUITS_temp.length
						greater_than_equal_to={LIMIT}
					[/variable]
					
					[then]
						[disallow_recruit]
							side={SIDE}
							type={TYPE}
						[/disallow_recruit]
					[/then]
					
					[else]
						[allow_recruit]
							side={SIDE}
							type={TYPE}
						[/allow_recruit]
					[/else]
				[/if]
				
				{CLEAR_VARIABLE LIMIT_CONTEMPORANEOUS_RECRUITS_temp}
			[/then]
		[/if]
	[/event]
	
	[event]
		name=recruit
		first_time_only=no
		
		[filter]
			side={SIDE}
			type={TYPE}
		[/filter]
			
		[store_unit]
			[filter]
				side={SIDE}
				type={TYPE}
			[/filter]

			kill=no
			variable=LIMIT_CONTEMPORANEOUS_RECRUITS_temp
		[/store_unit]
		
		[if]
			[variable]
				name=LIMIT_CONTEMPORANEOUS_RECRUITS_temp.length
				greater_than_equal_to={LIMIT}
			[/variable]

			[then]
				[disallow_recruit]
					side={SIDE}
					type={TYPE}
				[/disallow_recruit]
			[/then]
		[/if]
		
		{CLEAR_VARIABLE LIMIT_CONTEMPORANEOUS_RECRUITS_temp}
	[/event]
#enddef


# With this, you can easily limit the overall number of units of a given type a
# given side can recruit in the scenario. The side can only recruit the set
# amount of units of the given type.

#define LIMIT_RECRUITS SIDE TYPE LIMIT
	[event]
		name=prestart
		
		{VARIABLE side_{SIDE}_limited_recruits_length -1}
	[/event]

	[event]
		name=recruit
		first_time_only=yes
		
		[filter]
			side={SIDE}
			type={TYPE}
		[/filter]

		{VARIABLE_OP side_{SIDE}_limited_recruits_length add 1}

		{VARIABLE_OP LIMIT_RECRUITS_temp1 format "side_{SIDE}_limited_recruits[$side_{SIDE}_limited_recruits_length|].type"}
		{VARIABLE $LIMIT_RECRUITS_temp1 {TYPE}}
		{CLEAR_VARIABLE LIMIT_RECRUITS_temp1}
	[/event]

	[event]
		name=recruit
		first_time_only=no

		[filter]
			side={SIDE}
			type={TYPE}
		[/filter]

		{VARIABLE_OP LIMIT_RECRUITS_temp2 format "side_{SIDE}_limited_recruits[$side_{SIDE}_limited_recruits_length|].recruited"}
		{VARIABLE_OP $LIMIT_RECRUITS_temp2 add 1}
		{CLEAR_VARIABLE LIMIT_RECRUITS_temp2}

		{FOREACH side_{SIDE}_limited_recruits i}
			[if]
				[variable]
					name=side_{SIDE}_limited_recruits[$i].type
					equals={TYPE}
				[/variable]

				[variable]
					name=side_{SIDE}_limited_recruits[$i].recruited
					equals={LIMIT}
				[/variable]

				[then]
					[disallow_recruit]
						side={SIDE}
						type={TYPE}
					[/disallow_recruit]
				[/then]
			[/if]
		{NEXT i}
	[/event]
#enddef
