If you're up on your Course Materials, you should have already found and downloaded the Script Replicator(not because you have to, but because you'd be insane not to!). If not, I recommend you check the Course Materials thread, follow the link, and DL it. Some of you may have toyed around with it, some may not have. The concept is very simple but it serves a fundamental time-saving purpose, allowing you to write thousands of lines of code in literally minutes, if you know what you're doing.
This thread serves a few purposes:
Shows you how to use the Script Replicator to turn 3 lines of code into thousands of lines of code.
Shows you the work of nested if statements.
Shows you how there's more than one solution to doing something usually.
Shows you the faults of the scripting engine in its inability to use all-encompassing or self-referential commands.
This is not part of the Lesson Plan. There is no homework. I hope that after reading this though you'll be able to use the Script Replicator in your scripting endeavors and understand a little bit more about building scripts in modular chunks. Before we get started I suggest you read the Five Steps to Scripting Success and complete Lesson 1 and Lesson 2 to get the basics down, since I won't belabor them here.
First let's follow the steps laid out in the Five Steps to Scripting Success to flesh out the script being written. As a disclaimer, since this script is being written for AUH, the displayed factions/settlements are not vanilla, but if you follow the instructions it should be easy to make one for vanilla.
Goal
The goal of this script is to create an "AI Building" which appears in all AI-held settlement and not in any player-held settlements. The purpose of this is so that all EDB buildings which require "building_present_min_level" can use an or statement to require the AI building instead. This enables the AI to bypass the restrictions set on the player and let them build up their cities easily from the get-go, one of many things to help them make up for their inherent stupidity.
Feasibility
This script is definitely feasible, because we can create and destroy buildings based on who owns the settlement. One thing this script requires due to the way the "destroy_buildings" command works is for the AI Building to have its own building tree, otherwise this script will impact other buildings in that tree as well. Additionally, the player/AI should not be able to build it through normal means, so the building entry needs a requirement(such as and event_counter never_gonna_fire 1) which insures it can never be built except through script.
Concept
When conceptualizing a script there are often various ways to achieve the same end. Some are more efficient, some are just more compact, some are fairly interchangeable. For this script there will be shown two separate methods, one that utilizes a slew of monitors and one that uses nested if statements. Here is a mockup(these are pseudocode, not actual code):
Spoiler Alert, click show to read:
;Destroy buildings
monitor_event local faction turn end
if local faction = x
destroy ai_buildings for x
etc etc for each faction
end_monitor
;If Statement Method - Create Buildings
monitor_event settlement turn end not local
if faction x is not local faction
__if settlement x owned by faction x
__create ai building in settlement x
etc etc for each faction for each building
end_monitor
;Monitor Method - Create Buildings
monitor_event settlement turn end not local
and settlement is x
create ai building in settlement x
end_monitor
copy monitor for each settlement
Actualize
Okay so now we have our concepts. We know what we want it to do, we know how we're going to do it, now all we need is to do it. That's going to be a lot of code though, the if statement method we're using requires 7600 lines of code for 14 factions and 182 settlements, or roughly 3 lines of code per faction per settlement(so significantly more with 30 factions and 199 settlements). The monitor version uses significantly less lines of code as it doesn't contain redundancy, but as a result it needs to be present in separate monitors. The reason for this is to use if statements you need conditions with I_ in front of them, as they don't require exports from the event. The I_SettlementOwner command fits this bill, but it requires you to also specify a faction, meaning you have to create redundant code for every faction that could possibly own it. The only other I_ command that fits requires a siege to take place(as shown in Tsarsies' Garrison Script).
So now let's start with the destroying of buildings in player-owned settlements, because this is the smallest bit of code that works the same for all methods of creating them. Here's the code for one faction:
A few things to keep in mind. Both destroy_buildings and PreFactionTurnStart are to my knowledge kingdoms-only commands. If you aren't building your mod on kingdoms and you plan to do scripting, go buy kingdoms right now and convert it; you have a computer and internet access so you probably aren't dirt poor, you really have no excuse not to shell out the $20 or whatever it is now for Kingdoms to boost your game. As well, when you see false after the destroy_buildings, it doesn't mean don't destroy them; if you check the docudemons you'll see that true/false there specifies if the faction is refunded the cost of the building, which we don't want to happen since the building is intended to be intangible.
What this code does is say: Before the turn start of the player faction, run this monitor. If the local faction is champa, destroy all buildings in the AI Building chain in champa-owned settlements. The monitor is not terminated so it runs every turn start. Now if you're astute you might observe this leaves a window between capturing a settlement and the next turn where the player can exploit the AI building. Well you'd be right, but as scripters it isn't our job to shore up every possible way the player can exploit our scripts, you simply point out ways that people who want to use house rules should not exploit them where exploits exist, and leave those who want to game the system to their debauchery. If you're really anal about that sort of thing though you could take measures to stop it from happening, but it may require more intensive scripting in some cases so it's often best just to leave things to TurnStart/End and let bygones be bygones within the turn period.
So now for our mod we have 14 factions that use scripts(non-playable/etc. factions are not included or supported as being playable). For your mod you might have less or more, and they're likely called different names. What we need is an if statement for each one, it'd only take us a minute to copy-paste and replace by hand, but let's use the Script Replicator just to get a hang of it.
Okay so now it's time to take our above script and look at it in what I call modular sections. That is to say figure out which parts of the script are likely to be replicates of other parts of the script with one or two variables changed. For our destroy buildings script, the only difference between the if statement for champa and the if statement for song is the name of the faction in two places. So what we do is run the script replicator to replace that variable with the other variables we need. Here is a look at a modular section of the code, using {param} to indicate the part that will differ each time.
Code:
if I_LocalFaction {param}
destroy_buildings {param} ai_building false
end_if
Once we've replicated it and inserted it into our monitor, here's what the code looks like:
Spoiler Alert, click show to read:
Code:
monitor_event PreFactionTurnStart FactionIsLocal
if I_LocalFaction champa
destroy_buildings champa ai_building false
end_if
if I_LocalFaction daiviet
destroy_buildings daiviet ai_building false
end_if
if I_LocalFaction dali
destroy_buildings dali ai_building false
end_if
if I_LocalFaction goryeo
destroy_buildings goryeo ai_building false
end_if
if I_LocalFaction jin
destroy_buildings jin ai_building false
end_if
if I_LocalFaction khitans
destroy_buildings khitans ai_building false
end_if
if I_LocalFaction khmer
destroy_buildings khmer ai_building false
end_if
if I_LocalFaction minamoto
destroy_buildings minamoto ai_building false
end_if
if I_LocalFaction mongols
destroy_buildings mongols ai_building false
end_if
if I_LocalFaction pagan
destroy_buildings pagan ai_building false
end_if
if I_LocalFaction song
destroy_buildings song ai_building false
end_if
if I_LocalFaction taira
destroy_buildings taira ai_building false
end_if
if I_LocalFaction tibet
destroy_buildings tibet ai_building false
end_if
if I_LocalFaction xixia
destroy_buildings xixia ai_building false
end_if
end_monitor
Now I can comment it to remind myself and others what it's supposed to do, save it, and test to make sure it works. Keep in mind that I started with champa in there, and it was also replicated, so you can usually remove the one you wrote for the purposes of replicating it after inserting the replicated code(as it will be redundant).
That's all for the first part of this, in the next part I'll show you the two different kinds of code for the creating building half, how nested if statements work, how to replicate a script using two variables to produce roughly 2,000x the code you actually wrote, and how you can later refine and test your script.
Last edited by Augustus Lucifer; July 06, 2009 at 09:17 PM.