In this lesson we will be covering counters, event_counters, historic_events, and spawning armies. Some of the commands we wil be using are as follows:
terminate_monitor:
This command tells the game to ignore this monitor after it has run. This is useful if you have a piece of script that you only want to run one time.
counter:
This is a variable name where we store a number. You can name your counters whatever you want, but be aware that the name is CaSe SenSiTiVe.
event_counter:
Similar to a counter, the difference is that when you use this with the EDB file it is used as a true/false flag. 0 is false, anything else is true. Event counters do not have to be declared.
declare_counter:
You use this in the beginning of your script to set the name of your counter, and give it an initial value of 0.
set_counter:
This completely ignores the current value of your counter and sets it to the number specified. To use this with an event_counter the command is set_event_counter.
inc_counter:
This moves your counter up or down by the number you specify. If you use inc_counter CounterName 10 then it will increase by 10 every time the script runs this command. Similarly if you use inc_counter CounterName -10 it will decrease by 10. To use this with an event_counter the command is inc_event_counter.
create_unit:
Use this to spawn a new army on the strat map.
historic_event:
Use this to call an event from the data/text/historic_events.txt file.
The first thing we are going to do is create a new historic_event and then call it from the script. I often make several events called test_event1, test_event2, etc, so I can see exactly when certain parts of a large script are firing. You should already be somewhat familiar with converting the string.bin files but if not then you need to download and install Alpaca's string.bin convertor and convert historic_events into a text file so it can be modified. Add this to the bottom of your file, make sure to use your own name, not mine
Code:
{TEST_EVENT1_BODY}This is a test event created by GrnEyedDvl for testing scripts.
{TEST_EVENT1_TITLE}Test Event
And then put this in your script:
Code:
monitor_event FactionTurnEnd FactionIsLocal
historic_event test_event1
terminate_monitor
end_monitor
You should now get a pop up in game that says Test Event the first time you click EndTurn, and has the description you entered. Since we included the terminate_monitor command it will run once, and then never run again. It should look something like this:
Now we are going to use our first counter, and we are going to use it to keep track of what turn number it is. I know there is a built in command to check turn number, but for this class we are going to do it like this because it is an easier concept to grasp when you know exactly what it is supposed to be. You will be able to look at the turn number display in game and know if your script fired properly immediately. First we have to declare our counter name, then we have to set it to 1 because when the game starts it is turn number 1, and then every time the end_turn button is clicked we have to increase it by 1. At the top of your campaign_script, outside the montiors, put this:
Code:
declare_counter TurnNumber
set_counter TurnNumber 1
The build a monitor that increases the TurnNumber counter by 1 every time you click EndTurn.
Code:
monitor_event FactionTurnEnd FactionIsLocal
inc_counter TurnNumber 1
end_monitor
Now we need to check the counter, fire an event if it has been 10 turns, and then reset the counter so it will fire again 10 turns later. Create a new historic_event named ten_turns in your historic_events file, and put this in your script.
Code:
monitor_event FactionTurnEnd FactionIsLocal
and I_CompareCounter TurnNumber == 10
historic_event ten_turns
set_counter TurnNumber 0
end_monitor
When you hit turn number 10 your event should fire. You will know it fired on the right turn by looking at the turn number indicator in game, circled in red in my example.
If your script worked then you did everything right. Congratulations. However our script can be optomized. We are currently using two monitor_events to run our TurnCounter script, and we can condense that into a single monitor by using an IF statement. The fewer monitors we have running, the faster our script will run. Since we are only using a few monitors for this class you wont notice a difference, but when you start building scripts that contain several thousand lines of code you can really notice. The way I usually work is to put everything in a separate monitor when I am building it, so I can check the system logs and see that each monitor fires the way I want it to, and then go through and try to get things condensed. For simple scripts using that process is a bit of a time waster, on huge scripts I find that it actually ends up saving time debugging. Compare these two scripts, both do the exact same thing, but the second one is the better way to do it.
Code:
;count turn numbers
monitor_event FactionTurnEnd FactionIsLocal
inc_counter TurnNumber 1
end_monitor
;if it has been 10 turns, fire event and reset counter
monitor_event FactionTurnEnd FactionIsLocal
and I_CompareCounter TurnNumber == 10
historic_event ten_turns
set_counter TurnNumber 0
end_monitor
Code:
;count turn numbers
monitor_event FactionTurnEnd FactionIsLocal
inc_counter TurnNumber 1
if I_CompareCounter TurnNumber == 10
historic_event ten_turns
set_counter TurnNumber 0
end_if
end_monitor
But what do we use this for? The answer is simple, anything you want. Lets say that every 10 turns we want to have a random event. Sometimes it will happen on the 10th turn, sometimes it will not. So create a random event in your historic_events file. I will call mine random_event since I am so creative. Then we will call the RandomPercent condition, which simply generates a random number between 1 and 100. First we will just test our random_event by creating a new monitor that gives us a 50 percent chance.
Code:
;random event
monitor_event FactionTurnEnd FactionIsLocal
and RandomPercent > 50
historic_event random_event
end_monitor
When you run the game you should get your random event approximately every other turn. It wont be precise, sometimes you will get it 2 or 3 times in a row, sometimes you will go 2 or 3 turns without getting it at all. But now we need to run that command every 10 turns instead of every turn. We do this by inserting it into an if statement and comparing the TurnNumber counter. This is where things start to get a bit tricky because we are stacking one condition inside another one, and if you dont do things in the proper order your script will not run. Remember that our TurnNumber counter resets to 0 when it hits 10, but we also want our random_event to fire when TurnNumber hits 10. If we reset TurnNumber to 0 before we call the RandomPercent, then it will never fire, so we have to do this in a specific order. Sometimes its best to make yourself a little note, like this:
Turn end
check the TurnNumber counter
if it = 10 then call RandomPercent
if RandomPercent is over 50 then call random_event
reset TurnCounter to 0
end monitor
Now we can do all of this with separate counters, but we are going to include it all in a single counter. This is the last full piece of script that I am writing for this lesson that you can copy and paste into your own script, so make sure you understand what it is doing.
Code:
;count turn numbers
monitor_event FactionTurnEnd FactionIsLocal
inc_counter TurnNumber 1
if I_CompareCounter TurnNumber == 10
if RandomPercent > 50
historic_event random_event
end_if
historic_event ten_turns
set_counter TurnNumber 0
end_if
end_monitor
Now that we have our random_event firing every 10 turns with a 50 percent chance, we need to keep track of whether or not it has fired. We know the event runs when we see it pop up on screen, but we need a way for the script to know whether or not it has fired, so we can do some more stuff. So we use an event_counter and set it to 1 when the random_event fires. For this we use the set_event_counter command, again you can name your event_counter whatever you want. Put this right after the historic_event line:
Code:
set_event_counter RandomFired 1
Now we can check the EventCounter condition to determine whether or not the event has happened. The direction I am leading you into here is spawning an army when a settlement is under siege, but in the case of a long siege you dont want to spawn an army every turn. We will get there in a bit but first we have to learn to manipulate an event_counter from a counter and vice-versa.
Ok so we set our RandomFired event_counter to 1, now we have to check it so that we dont fire the random_event again. To do this we use the AND statement along with our other conditions, and if everything is true then the RandomPercent will trigger. So we change the line that has RandomPercent in it to look like this, remember I am not pasting full code anymore this is an excerpt:
Code:
if I_CompareCounter TurnNumber == 10
if RandomPercent > 50
and I_EventCounter RandomFired == 0
historic_event random_event
set_event_counter RandomFired 1
Now every 10 turns the script will check if RandomFired is equal to 0, and if it is there is a 50 percent chance that our random_event popup will show in game. Once it does it will set RandomFired to 1, and this part of the script will not run again. However the difference between doing it this way and using terminate_monitor is that we can enable this piece of script again by setting RandomFired back to 0 in another monitor or when another event someplace else in the script fires. Basically we can enable this anytime we want to by using anywhere in our script that we want to:
Code:
set_event_counter RandomFired 0
Now we will get into spawning armies. The command for this is pretty simple, but first we have to know what kind of units to spawn, and where to spawn them. Since we will be using this as a form of garrison script pick a settlement you want to attack, and pick a few units. I am playing vanilla M2 as England and will be attacking the rebel town of York since its close to one of my starting armies. Looking in descr_strat for rebel armies I found this entry for York, so I will just use the same units and make a few more of those:
Code:
character sub_faction england, Arthur of York, general, male, age 31, x 106, y 164
army
unit Peasants exp 1 armour 0 weapon_lvl 0
unit Spear Militia exp 0 armour 0 weapon_lvl 0
unit Archer Militia exp 0 armour 0 weapon_lvl 0
unit Peasants exp 1 armour 0 weapon_lvl 0
unit Peasant Archers exp 0 armour 0 weapon_lvl 0
First we want to make sure we can create the army, so just build a monitor that runs when you click EndTurn and include the create_unit command. York starts with a total of 5 units, I will just add 5 more. You could also use the spawn_army command, but then you have to specify a general/captain and x,y location. For spawning an entire army in the field that is the best way, to just add units to a city or even to a named general then do it like this. Build your monitor and run the game, the units should be created.
Code:
create_unit York, Peasants, num 10, exp 1, arm 0, wep 0
Now that we know we can create our units, we have to know two other things: Whether or not the settlement is under siege, and whether or not the army has already been spawned. I will not be writing any code for this, you need to write it yourself, but I will tell you what conditions to use for a simple garrison script and what the general order of the commands is. We will be running this at FactionTurnEnd FactionIsLocal, and we will be using an event_counter named York_army_spawned and you will be creating a new historic_event that tells you the settlement has reinforcements.
Use the I_SettlementUnderSiege condition, check the docudemons for syntax.
Check the value of York_army_spawned, if it is 0 set a RandomPercent of 50 to spawn the army
If the army spawns, fire your historic_events that tells you the settlement has reinforcements.
Set the event_counter to 1 so that the units will not be created twice.
When the settlement is no longer under siege, reset the event counter to 0 so that the next time the settlement is sieged the units can be spawned again. This will require a separate monitor and the use of the NOT condition along with I_SettlementUnderSiege.
Pop a historic_event that lets me know you reset the counter. If you are not careful here this event will fire every turn that York is not under siege, so you need to check the event_counter to see if it is 1 before you reset it to 0.
I want these screen shots, and I also want the code that tells me what units you are spawning. Not the entire script, just the create_units line:
Player besieging settlement BEFORE the units have spawned. Make sure you Maintain Siege so the script has a chance to run since it fires on TurnEnd. Also dont add so many units that the AI decides to come out and attack you instead of sitting out the siege. The events will still fire but things will be out of order for taking screen shots.
A screen shot of the historic_event that tells you York has been reinforced.
A screen shot of the settlement with the new units in it.
A screen shot of the event that says you reset your counter.
Finally I want your script posted in SPOILER tags. We are working on the honor system here so please do NOT view other peoples code until you have yours working. I am expecting a lot of questions on this lesson, but I also expect you to try and get it to work several times before you look at someone elses code.