<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://tw-modding.com/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Grimmys</id>
	<title>Total War Modding - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://tw-modding.com/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Grimmys"/>
	<link rel="alternate" type="text/html" href="https://tw-modding.com/wiki/Special:Contributions/Grimmys"/>
	<updated>2026-05-13T21:59:01Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.39.3</generator>
	<entry>
		<id>https://tw-modding.com/index.php?title=Tutorial:RPFM_For_Dummies&amp;diff=1226</id>
		<title>Tutorial:RPFM For Dummies</title>
		<link rel="alternate" type="text/html" href="https://tw-modding.com/index.php?title=Tutorial:RPFM_For_Dummies&amp;diff=1226"/>
		<updated>2024-03-14T17:11:23Z</updated>

		<summary type="html">&lt;p&gt;Grimmys: Add more formatting, some ressources links and update for more recent versions of RPFM&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Subtitle: ''A Reasonably Lengthy And Not-At-All Short Guide to Modding with RPFM – With Pictures''&lt;br /&gt;
&lt;br /&gt;
Also an introduction to Zeldrake's usage of Mediawiki. To be honest, I'm surprised at how little broke and how everything's working... it's suspicious. Anyway, on with the guide!&lt;br /&gt;
&lt;br /&gt;
= Chapter 0 - Introduction = &lt;br /&gt;
&lt;br /&gt;
What are WH2 (or WH3) mods and what can they do?&lt;br /&gt;
&lt;br /&gt;
Broadly speaking, mods are .pack files which contain basically every piece of WH2 (or WH3) data you’ll need – models, stats, text, animations, spells, scripts, numbers. RPFM, Rusted Pack File Manager, is a tool to edit pack files. Therefore, you need to use RPFM for basically every WH2 (or WH3) mod you'll make. This guide will be aimed at WH2, but the ideas are the same for the other games (it has been tested for WH3 as well).&lt;br /&gt;
&lt;br /&gt;
It’s also possible to edit pack files with PFM (Pack File Manager) or the TW: Assembly Kit (fondly called asskit), but neither of these are recommended: the former is just old and has a habit of eating your entire mod up, and the second just doesn’t work well for modders. If a guide references PFM a lot it’s quite outdated and you should probably search around for a more updated one.&lt;br /&gt;
&lt;br /&gt;
Also, before you begin, I recommend setting up a folder somewhere to stash your mods, RPFM, and other stuff. We’ll need it later. Mine is &lt;br /&gt;
&amp;lt;code&amp;gt;C:\REDACTED\OtherGameStuff\Warhammer2ExceptNeat&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Chapter 1 - Getting RPFM =&lt;br /&gt;
&lt;br /&gt;
The best place to get your hands on RPFM is by checking the '''#rpfm''' channel on ''Da Modding Den'' Discord server. Chances are the latest version is pinned in the pinned. However, you should also be able to get it from [https://github.com/Frodo45127/rpfm/releases/latest this link].  Which, at the moment, looks a bit like this: &lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 01.png|700px]]&lt;br /&gt;
&lt;br /&gt;
At the time of writing (which is outdated already), the current version is v2.3.2. RPFM will doubtlessly have more additions and changes as time goes on (the change from RPFM v1 to v2 was  quite something), but the idea should still be the same: it does things with Pack Files. The buttons might move about, but they should do the same stuff.&lt;br /&gt;
&lt;br /&gt;
As for downloading it: assuming you’re on Windows, it’s the download that has ‘rpfm-something-something-windows’ in it:&lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 02.png|350px]]&lt;br /&gt;
&lt;br /&gt;
At the moment, RPFM is nicely packaged into a .zip folder, which you can extract with almost anything, but previous versions were packaged into a .7z folder. I recommend unpacking these with [https://www.7-zip.org/download.html 7zip]. 7zip is pretty straightforward to download and install:  just grab any of the ones that say &amp;quot;windows&amp;quot; and, if it doesn’t seem to work, try the next one. In any case, 7-zip is beyond the scope of this guide.&lt;br /&gt;
&lt;br /&gt;
Anyway, extract RPFM into your mod folder and you should end up with something like this:&lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 03.png|700px]]&lt;br /&gt;
&lt;br /&gt;
It’s not truly necessary, but we’ll make a shortcut to RPFM so we don’t have to get lost down this rabbit hole of folders each time we want to open it (and you’ll want to open it a lot). Find rpfm.exe (that’s the program – I don't know what the other ones do. In earlier, or perhaps later, versions of RPFM the executable name might change. Try running things until it works), right-click, and Create Shortcut:&lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 04.png|600px]]&lt;br /&gt;
&lt;br /&gt;
'''Update: on some newer version, the executable has been renamed rpfm_ui.exe'''&lt;br /&gt;
&lt;br /&gt;
Select that and move it to somewhere memorable. Desktop works fine – at the moment mine is in my WH2 mods folder: &lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 05.png|600px]]&lt;br /&gt;
&lt;br /&gt;
That’s RPFM! Open it up and – for this version, in any case – it should look at least a little like: &lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 06.png|700px]]&lt;br /&gt;
&lt;br /&gt;
(though the icon in the middle of the screen might be different).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Chapter 2 - Setting RPFM Up = &lt;br /&gt;
&lt;br /&gt;
Before we start running down rabbit holes of modding, we still need to do a bit with RPFM to get it set up so Everything Works Nicely. Go under PackFile -&amp;gt; Preferences &lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 07.png|500px]]&lt;br /&gt;
&lt;br /&gt;
and a big box should open up! Don’t worry, we don’t need to worry about most of the stuff in here, but some stuff is very important: &lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 08.png|700px]]&lt;br /&gt;
&lt;br /&gt;
It’s critically important to fill out the boxes I’ve outlined in red. The first points RPFM to WH2’s mod directory: it’s just the folder where the .exe is (as the handy tooltip demonstrates!) The second points to a fancy shmancy “MyMod” folder. You’ll need to create this and put it somewhere safe - it can be anywhere that isn’t in Program Files. Making a nice big WH2/WH3 folder under Documents or somewhere to put everything WH2/WH3-related is a good idea. &lt;br /&gt;
&lt;br /&gt;
The blue box isn’t critical, but it’ll save you a bit of effort: defaulting RPFM to WH2 or WH3 (it’s probably on Three Kingdoms) means less clicks when we start up. The remaining settings can be left at defaults, you don’t need them. From here, everything else is optional. As you can see, I also filled out my path for Troy, because I like to mod that a little, but it’s not needed – we’re modding WH so only WH needs to be set up! There’s also “Use Dark Theme” hiding in the checkbox list on the left, which is good for modding at 3am when you’re feeling vampiric and bright light destroys you. &lt;br /&gt;
&lt;br /&gt;
Close RPFM and restart it again, just for good measure. (It’s not actually needed for these settings, contrary to the red warning text, but saves us a little bit of clicking). &lt;br /&gt;
&lt;br /&gt;
There’s one more thing we’ll need to do to get RPFM working properly and that is install the Total War: Warhammer 2 Assembly Kit (same for Warhammer 3). There’s a neat guide on how to do this by CA [https://www.totalwar.com/blog/total-war-warhammer-assembly-kit-terry-quick-start-guide/ here] but in short, Steam -&amp;gt; Library -&amp;gt; Tools then install the TW: Assembly Kit.&lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 09.png|400px]]&lt;br /&gt;
&lt;br /&gt;
It’s important (for RPFM) that the Assembly Kit is installed on the same drive as WH2/WH3. Once it’s downloaded, boot up RPFM again and hit Special Stuff -&amp;gt; Warhammer 2 / Warhammer 3 -&amp;gt; Generate Dependencies Cache. (If the button’s greyed out, just open any WH2/WH3 packfile you care to name; easily done with Open From Data and clicking on whatever you like).&lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 10.png|615px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
It’ll take a minute, but this is really helpful for RPFM’s diagnostic tool that tells you when your keys don’t match up (in short, it lets you know where you goofed up).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Chapter 3 - Making a Mod =&lt;br /&gt;
&lt;br /&gt;
Before we begin, it’s worth noting what sort of stuff mods do, and what can even be done:&lt;br /&gt;
* '''Table editing'''. Simplest and easiest. A lot of Warhammer 2/Warhammer 3 information like unit health, building recruitments, what spells do what, what skillpoints do what, dilemmas: almost all data for that is stored in tables.&lt;br /&gt;
* '''Graphics, Model, Animation, and Effects Editing'''. I have absolutely no clue how this works so if somebody else could fill in this blank I’d appreciate it. I know textures exist, models exist, and animations exist, but that's about it.&lt;br /&gt;
** You can make new units! From “Handgunners but they’re blue instead of red” to “Treemen with Great Bows” to “Entirely custom floating ships as Tomb King character mounts,” you can basically do anything with the new tools of Phazer’s tools and h3ro’s Asset Editor (fondly nicknamed ‘assed’).&lt;br /&gt;
** You can make new effects (think the shiny things that go off when a spell activates).&lt;br /&gt;
** You can reassign and add new animations, if you’re feeling dedicated enough. &lt;br /&gt;
** What I do know about the above is that it’s all quite difficult, and I would not recommend someone starting out modding to start with this. Search up for other guides – there are some good modding guides on WH2’s Steam mod page.&lt;br /&gt;
* '''Scripts'''. While tables specify what stuff exists, scripts can specify how stuff happens. For instance, the Chaos invasion in Mortal Empires is almost entirely script-based. So is Hellebron’s Death Night. Even Encounters at Sea (the ones where you can fight a whole bunch of vampirates) is script. Wood Elf Forest Encounters, Empire Count dilemmas – the list of script-based functionality goes on. Quite often these link into database stuff (sometimes moreso than others – for instance, traits are entirely database defined but actually gaining any trait is script-based)&lt;br /&gt;
* '''UI Script'''. Still strictly speaking the realm of script, but stuff that has lots of pretty buttons to press, like the Mortuary Cult crafting, the Wood Elf Forge of Daith, Throt’s Flesh Lab; this kind of stuff. Unfortunately, I’m not familiar with any of it and my understanding is it can be quite difficult to adapt to what you want to do.&lt;br /&gt;
** Again, if someone was willing to fill out a bit more information I’d appreciate it!&lt;br /&gt;
* '''Startpos'''. This specifies how things are set up at turn 1 in a campaign. If you’re really screwing with the game (eg: adding new factions) this is necessary, and it’s an absolute pain, earning it the nickname ‘asspos.’ Being a startpos mod also makes it fundamentally incompatible with any other startpos mod, as you can only have one way things are set up in the start of a campaign! Fortunately, if you just want to move a character to a new spot you can do that with script, which is much nicer. There's almost no good reason to mod startpos, so if you are, you shouldn't be.&lt;br /&gt;
&lt;br /&gt;
RPFM’s speciality is '''table editing'''. It can handle scripts pretty well, but ultimately you’re better off writing them somewhere else ([https://code.visualstudio.com/ Visual Studio Code] is good for dedicated scripters), then pasting them into RPFM when done. Additionally, RPFM as a tool combines all the above together – you may have your fancy model and Chaos Knights (Ratling Guns), but you’ll need to put this into RPFM to turn it into a pack file to make it a mod. &lt;br /&gt;
&lt;br /&gt;
RPFM cannot edit startpos (... well, yet) and you’ll need the Total War Assembly Kit to do that, but you should stay away from that unless you have a really good reason to do it (and most reasons aren’t good enough). &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
With all of this in mind, we’re going to make ''two simple mods''.&lt;br /&gt;
Firstly, we’ll increase Lord Skrolk’s melee attack to 100. This is going to be a '''table edit'''.&lt;br /&gt;
Secondly, we’re going to make him start in Caledor, instead of where he normally is. You could do that with startpos, but I can’t stress how much of a bad idea that is, so we’re going to use script. We can put these both together in a single mod.&lt;br /&gt;
&lt;br /&gt;
Well, what are we waiting for? Start RPFM from that handy shortcut you made earlier, and beeeeefore we begin, we need to check one thing: &lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 11.png|700px]]&lt;br /&gt;
&lt;br /&gt;
WH2/WH3 needs to be the Game Selected. We are, of course, making a mod for WH! If this isn’t correct a bunch of silly stuff will happen.&lt;br /&gt;
&lt;br /&gt;
Now, let’s make a mod in RPFM! You can do this the old-fashioned way by PackFile -&amp;gt; New PackFile but RPFM’s MyMod functionality makes everything so much cleaner: open the MyMod menu and hit New MyMod! &lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 12.png]]&lt;br /&gt;
&lt;br /&gt;
A small box will come up that’s pretty self-explanatory.&lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 13.png]]&lt;br /&gt;
&lt;br /&gt;
All the text there explains itself. As for name, I like to start with my username, then use underscores to describe a bit about the mod. So I’ll call it aidenpons_lord_skrolk_yes_yes , hit Save, and let’s go!&lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 14.png]]&lt;br /&gt;
&lt;br /&gt;
Now, we wanted to change Skrolk’s melee attack. That’s going to be in some form of table. So I need to right-click the mod, click Create (not Add! that’s a different table), and then DB (short for database, aka table) &lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 15.png]]&lt;br /&gt;
&lt;br /&gt;
Click that and a box with a bajillion things in its dropdown box comes up!&lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 16.png]]&lt;br /&gt;
&lt;br /&gt;
That’s no good, we want melee attack, not fonts! We need to know what table it’s in, and to find this, we have a couple of choices:&lt;br /&gt;
# Poke the folks on Da Modding Den using one of the '''#modding-tech''' channels – a valid call if you’re doing something complicated&lt;br /&gt;
# Find it yourself like an independent and capable person!&lt;br /&gt;
&lt;br /&gt;
I recommend b) where possible. Don’t worry though, it’s not too difficult. What do we know about melee attack? It might not be called that in the game files though, so we don’t want to search it by name. What else do we know? Well, we know Lord Skrolk has a melee attack. So let’s just run a search through the original CA data and see where he turns up.&lt;br /&gt;
&lt;br /&gt;
Put this aside, and open another instance of RPFM by clicking on that handy shortcut you made previously. After making sure Game Selected is the correct Warhammer, left click on PackFile. We have a couple of choices here...&lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 17.png]]&lt;br /&gt;
&lt;br /&gt;
We want to load WH2/WH3’s data so we can search through it all to find what we want. Thanks to improvements in RPFM, we no longer have to worry about thinking which packfile we specifically want: we can just open them all at once using the “Load All CA Packfiles” button. &lt;br /&gt;
&lt;br /&gt;
It’s also worth mentioning ''Open from Content'' will open from Steam’s workshop content: handy if you want to check a mod’s pack file, but we don’t want that. ''Open From Data'' opens from game’s data folder, where both the game’s pack files and mod pack files reside, which explains the massive box that pops up should you hover over it. &lt;br /&gt;
&lt;br /&gt;
Anyway, Load All CA PackFiles, give it a bit to load – it’s a lot of big packs, and we should have something like this: &lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 18.png]]&lt;br /&gt;
&lt;br /&gt;
'''Update: on some newer version, Load All CA Packfiles is automatically done after generating dependencies cache. So if the button is disabled for you, don't panic; it may means you don't need to do this step because CA Packfiles are already loaded.'''&lt;br /&gt;
&lt;br /&gt;
... well, that’s not very big! Click on the little &amp;gt; arrow next to the .pack, and a load of folders should expand! Expand the db folder (the folder where all the tables are), and even more folders should come up! ... Okay, that’s why it took this long to load. Expand a random folder and click on its data__ (they all have that name):&lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 19.png]]&lt;br /&gt;
&lt;br /&gt;
This is a table. In this case, it’s the table that governs how fatigue happens in battle: so you can see climbing walls nukes fatigue at 10,000, when idle changes fatigue by -18 (which probably means fatigue goes down, which checks out with game knowledge).&lt;br /&gt;
&lt;br /&gt;
Anyway, we wanted Lord Skrolk’s melee attack. Well, we know Lord Skrolk has a melee attack. So let’s try finding him! To do that, we’ll use RPFM’s incredibly handy Global Search. Hit View -&amp;gt; Toggle Global Search Window to bring it up.&lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 20.png]]&lt;br /&gt;
&lt;br /&gt;
(Note: In RPFM v1-ish - which is totally obselete - Global Search was accessed by right-clicking anywhere in the folder view on the left. We’re working with more modern tech though!) A box on the right should pop up as part of RPFM: &lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 21.png|450px]]&lt;br /&gt;
&lt;br /&gt;
Let’s put ''Lord Skrolk'' in the Search bar, hit Search and see what happens! &lt;br /&gt;
After waiting a bit (around 7s on my machine – shouldn’t take more than a minute by any means), we get some results: &lt;br /&gt;
(Note: Results may differ depending on what version of RPFM and WH is being used, but either way, the idea of global searching still works).&lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 22.png]]&lt;br /&gt;
&lt;br /&gt;
Huh. Let’s examine one of these more: Click on the &amp;gt; next to the db/character_skills_tables/data__ to expand it, and see what it found. &lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 23.png]]&lt;br /&gt;
&lt;br /&gt;
Hrm. Double-click that and the table will open.&lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 24.png|700px]]&lt;br /&gt;
&lt;br /&gt;
Well, we at least got Lord Skrolk. This is clearly a description for something, not melee attack. But if we scroll around left and right, we can see from the '''Key''' - which is what a lot of WH tables use to refer to something unique (eg: units have keys, projectiles have keys, dilemmas have keys, regions have keys, provinces have keys, building have keys, etc etc etc) that WH doesn’t use spaces like we searched and instead uses underscores. So, with that in mind, let’s try searching ''lord_skrolk'' instead!&lt;br /&gt;
&lt;br /&gt;
Wait a couple of seconds, and, wow, what a bunch more results! I guess that makes sense for the leader of an entire faction – model, audio, events, and all! And one of these tables is hopefully melee attack...&lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 25.png]]&lt;br /&gt;
&lt;br /&gt;
We’re currently hunting in db but it’s worth giving a mention to the other tabs. Loc Matches searches inside WH2/WH3’s complex text database, and is a really good way to get started on finding something if all you know is its in-game name. Text Matches searches, among other things, script and the bit of a model called a “variantmesh” (don’t ask me what this means because I don’t know) – good if you’re hunting script or models, which we aren’t, so we can ignore it. I have no clue what Schema Matches does and have never needed it so we can hopefully ignore it.&lt;br /&gt;
&lt;br /&gt;
Additionally, feel free to resize the window (drag on various handles that pop up), if you’ve got the screen real estate for it. Anyway, we wanted melee attack. There’s no table that looks like melee_attack, but, scrolling a bit up from the bottom, let’s try main_units_tables? &lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 26.png]]&lt;br /&gt;
&lt;br /&gt;
land_unit! That’s something! Double-click on that and a new tab in RPFM should open and scroll down to the line needed.&lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 27.png|700px]]&lt;br /&gt;
&lt;br /&gt;
''(Addendum: WH2, this guide, and RPFM have had so very many updates since things began. If you have a keen eye, you’ll see that the top left is called data.pack not warhammer_2, and that Skrolk is at line 709 when currently he’s at line 789. Things change, and I genuinely cannot keep this guide perfectly up to date. When modding, if nothing else, it’s important to be able to think on your feet as things keep changing around you.)''&lt;br /&gt;
&lt;br /&gt;
You can see our previous character_skills_tables open in a non-active tab. We really don’t need that anymore and you can close it if you want, we’re taking a look at main_units now. &lt;br /&gt;
&lt;br /&gt;
Scrolling across, we see things like Upkeep Cost, Multiplayer Cost, some voice-over stuff, but nothing that looks like melee attack. Well, this ''does'' look like Lord Skrolk (the wh2_main_skv_cha_lord_skrolk seems about right), so we’re probably on the right track. What about that Land Unit? If we hover over the column header in RPFM, it’ll tell us which table this is referencing. (Some columns in tables link other tables together, like this one – but obviously Upkeep Cost doesn’t reference a table!)&lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 28.png|700px]]&lt;br /&gt;
&lt;br /&gt;
Huh, a table called land_units. Would be nice to find that quickly. There are two ways you can do this: one, fishing the table out by hand. This is actually pretty speedy since if we select a random folder on the left and hit L (for Land_units), the folder view will scroll to the first match of L. (You can type even quicker if you want, typing L A N D _ U N I T S , but that’s too much typing for my fingers).&lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 29.png]]&lt;br /&gt;
&lt;br /&gt;
Well, lab_settings is definitely not what we want, but if we scroll down a bit, we’ll find land_units_tables.&lt;br /&gt;
&lt;br /&gt;
The other – and much speedier – option is to use RPFM’s handy Go To functionality. Right-click on the cell and Go To -&amp;gt; Go To Definition, and fazam, RPFM will take you right there!&lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 30.png|700px]]&lt;br /&gt;
&lt;br /&gt;
Either way, we’ve now got land_units_tables open in front of us:&lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 31.png|700px]]&lt;br /&gt;
&lt;br /&gt;
Now, we really don’t want to scroll through all ten bazillion lines of this table to find Skrolk, but instead RPFM has a handy Filter section just below the table view. Type skrolk in that and it’ll only show rows that match skrolk in the Key section. (We wouldn’t want to search for skrolk in the Category section!) There’s tons of superpowerful stuff you can do with more detailed filters (they support Regex, very powerful for searching), but this simple filter will do:&lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 32.png|700px]]&lt;br /&gt;
&lt;br /&gt;
Only one hit? That’s usually pretty good, as it suggests this is a Master Node of some sort, linking a lot of things together. Scroll across the table and we some things about mounts, morale, armor, melee weapon, and – what’s this? Melee attack! We found it!&lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 33.png|700px]]&lt;br /&gt;
&lt;br /&gt;
Now, before we get too excited, this is the data packs of the game themselves. Editing these is a terribly bad idea as it makes there be no way to revert to unmodded short of reinstalling the game, and the reason RPFM won’t let you save your changes if you try. Instead, that’s why we created a mod!&lt;br /&gt;
&lt;br /&gt;
Hop back to the instance of RPFM that has your mod open (or open it again, if you closed it). If you did close it, there’s a super-nifty RPFM trick that allows you to open it super quickly, and it’s under the MyMod menu:&lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 34.png]]&lt;br /&gt;
&lt;br /&gt;
Super speedy and super handy. Anyway, we’d shut that because we didn’t know what table we wanted, but now we know we want land_units table! So again, right-click, create, create DB...&lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 35.png]]&lt;br /&gt;
&lt;br /&gt;
... and this time we know what table we want – it’s the ''land_units'' table! Typing in land_units doesn’t quite land the hit we need, but it’s easy to find it from the four in the dropdown box:&lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 36.png]]&lt;br /&gt;
&lt;br /&gt;
The new_file in the first line will be the name of your table. This isn’t super important – except that it shouldn’t end with a number and should have no spaces in it – but I like to, again, preface it with my name and then have something about the table. So aiden_land_units will do just fine. &lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 37.png]]&lt;br /&gt;
&lt;br /&gt;
Hit Create, open it up, and it’s blank. Well, of course it’s blank – we haven’t added anything to it!&lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 38.png]]&lt;br /&gt;
&lt;br /&gt;
Well, we want to put the line about Lord Skrolk in here and change his melee attack. I guess you could re-type everything out by hand if you were feeling like you wanted some bonus suffering, but I like my modding to be an enjoyable experience (which is why I don’t touch startpos), and in RPFM, we can copy and paste rows (and much more!) over!&lt;br /&gt;
Hop back to RPFM that has data.pack open, and it should be right where we left it. &lt;br /&gt;
Now – just like Excel – if you click on the row number the entire row will be selected. Right-click somewhere in that row, select Copy, then Copy (the other option we don’t need for this):&lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 39.png|700px]]&lt;br /&gt;
&lt;br /&gt;
Now hop back to our mod, right-click anywhere in the table view, and hit Paste as New Row!&lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 40.png]]&lt;br /&gt;
&lt;br /&gt;
Results should look like this!&lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 41.png|700px]]&lt;br /&gt;
&lt;br /&gt;
Stuff’s a bit squished, but it’s there! Now scroll over to the Melee Attack, double-click to select it, put our nice modded 100 value in, hit Enter, and, that’s done!&lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 42.png]]&lt;br /&gt;
&lt;br /&gt;
But before we get toooooo excited about using an overpowered Lord Skrolk, there’s two more things we need to do: &lt;br /&gt;
&lt;br /&gt;
The first is save the mod! Ctrl+S does the trick, or PackFile -&amp;gt; Save. The second’s more important: to copy the mod to game’s data directory so the mod managers actually pick it up.  Instead of fishing up the packfile manually and pasting it over, RPFM does this all with two mouse clicks: PackFile -&amp;gt; Install !&lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 43.png]]&lt;br /&gt;
&lt;br /&gt;
''(Addendum: Previous versions of RPFM had this under the MyMod menu. Again, the buttons might move around and about – it’s important to think on your feet)''&lt;br /&gt;
&lt;br /&gt;
Oh, by the way, if you get an error that looks like this: &lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 43b.png]]&lt;br /&gt;
&lt;br /&gt;
Now our nice little packfile is sitting in WH2’s data directory ready for either the CA mod loader (affectionately called George) or [https://tw-modding.com/wiki/Category:Tools_%26_Resources#Kaedrin%E2%80%99s_Mod_Manager Kaedrin’s Mod Manager (KMM)] to pick it up. It’s vitally important to play-test your mods first (and, if nothing else, make sure they load and the game doesn’t crash!), so we’ll do that. &lt;br /&gt;
&lt;br /&gt;
While KMM is definitely superior for managing large amounts of mods and its Profile feature is a godsend, we do actually need the CA mod loader to upload a mod (more on that later), so for this I’ll be using the CA mod loader. Boot it up, and if you scroll down, tadaaaaaaa!&lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 44.png|700px]]&lt;br /&gt;
&lt;br /&gt;
Enable that, hit Play, hit Play on the obligatory “warning you are modded” menu (does anyone besides me actually read that?), and WH2/WH3 boots up with our mod in tow! :D &lt;br /&gt;
&lt;br /&gt;
We could start a new campaign to check things out, but we could also be lazy, and just check things in Custom Battles instead. And will you look at that!&lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 45.png|700px]]&lt;br /&gt;
&lt;br /&gt;
''It woooooooooooooorks!'' :D&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Chapter 4 - Script = &lt;br /&gt;
&lt;br /&gt;
''To Be Continued...''&lt;br /&gt;
&lt;br /&gt;
[[Category: Tools &amp;amp; Resources]]&lt;/div&gt;</summary>
		<author><name>Grimmys</name></author>
	</entry>
	<entry>
		<id>https://tw-modding.com/index.php?title=Tutorial:RPFM_For_Dummies&amp;diff=1225</id>
		<title>Tutorial:RPFM For Dummies</title>
		<link rel="alternate" type="text/html" href="https://tw-modding.com/index.php?title=Tutorial:RPFM_For_Dummies&amp;diff=1225"/>
		<updated>2024-03-11T22:09:45Z</updated>

		<summary type="html">&lt;p&gt;Grimmys: Fix typos, be more inclusive for WH3, update regarding new name of executable&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Subtitle: ''A Reasonably Lengthy And Not-At-All Short Guide to Modding with RPFM – With Pictures''&lt;br /&gt;
&lt;br /&gt;
Also an introduction to Zeldrake's usage of Mediawiki. To be honest, I'm surprised at how little broke and how everything's working... it's suspicious. Anyway, on with the guide!&lt;br /&gt;
&lt;br /&gt;
= Chapter 0 - Introduction = &lt;br /&gt;
&lt;br /&gt;
What are WH2 (or WH3) mods and what can they do?&lt;br /&gt;
&lt;br /&gt;
Broadly speaking, mods are .pack files which contain basically every piece of WH2 (or WH3) data you’ll need – models, stats, text, animations, spells, scripts, numbers. RPFM, Rusted Pack File Manager, is a tool to edit pack files. Therefore, you need to use RPFM for basically every WH2 (or WH3) mod you'll make. This guide will be aimed at WH2, but the ideas are the same for the other games (it has been tested for WH3 as well).&lt;br /&gt;
&lt;br /&gt;
It’s also possible to edit pack files with PFM (Pack File Manager) or the TW: Assembly Kit (fondly called asskit), but neither of these are recommended: the former is just old and has a habit of eating your entire mod up, and the second just doesn’t work well for modders. If a guide references PFM a lot it’s quite outdated and you should probably search around for a more updated one.&lt;br /&gt;
&lt;br /&gt;
Also, before you begin, I recommend setting up a folder somewhere to stash your mods, RPFM, and other stuff. We’ll need it later. Mine is &lt;br /&gt;
C:\REDACTED\OtherGameStuff\Warhammer2ExceptNeat&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Chapter 1 - Getting RPFM =&lt;br /&gt;
&lt;br /&gt;
The best place to get your hands on RPFM is by checking the #rpfm channel on ''Da Modding Den'' Discord server. Chances are the latest version is pinned in the pinned. However, you should also be able to get it from [https://github.com/Frodo45127/rpfm/releases/latest this link].  Which, at the moment, looks a bit like this: &lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 01.png|700px]]&lt;br /&gt;
&lt;br /&gt;
At the time of writing (which is outdated already), the current version is v2.3.2. RPFM will doubtlessly have more additions and changes as time goes on (the change from RPFM v1 to v2 was  quite something), but the idea should still be the same: it does things with Pack Files. The buttons might move about, but they should do the same stuff.&lt;br /&gt;
&lt;br /&gt;
As for downloading it: assuming you’re on Windows, it’s the download that has ‘rpfm-something-something-windows’ in it:&lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 02.png|350px]]&lt;br /&gt;
&lt;br /&gt;
At the moment, RPFM is nicely packaged into a .zip folder, which you can extract with almost anything, but previous versions were packaged into a .7z folder. I recommend unpacking these with [https://www.7-zip.org/download.html 7zip]. 7zip is pretty straightforward to download and install:  just grab any of the ones that say &amp;quot;windows&amp;quot; and, if it doesn’t seem to work, try the next one. In any case, 7-zip is beyond the scope of this guide.&lt;br /&gt;
&lt;br /&gt;
Anyway, extract RPFM into your mod folder and you should end up with something like this:&lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 03.png|700px]]&lt;br /&gt;
&lt;br /&gt;
It’s not truly necessary, but we’ll make a shortcut to RPFM so we don’t have to get lost down this rabbit hole of folders each time we want to open it (and you’ll want to open it a lot). Find rpfm.exe (that’s the program – I don't know what the other ones do. In earlier, or perhaps later, versions of RPFM the executable name might change. Try running things until it works), right-click, and Create Shortcut:&lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 04.png|600px]]&lt;br /&gt;
&lt;br /&gt;
'''Update: on some newer version, the executable has been renamed rpfm_ui.exe'''&lt;br /&gt;
&lt;br /&gt;
Select that and move it to somewhere memorable. Desktop works fine – at the moment mine is in my WH2 mods folder: &lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 05.png|600px]]&lt;br /&gt;
&lt;br /&gt;
That’s RPFM! Open it up and – for this version, in any case – it should look at least a little like: &lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 06.png|700px]]&lt;br /&gt;
&lt;br /&gt;
(though the icon in the middle of the screen might be different).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Chapter 2 - Setting RPFM Up = &lt;br /&gt;
&lt;br /&gt;
Before we start running down rabbit holes of modding, we still need to do a bit with RPFM to get it set up so Everything Works Nicely. Go under PackFile -&amp;gt; Preferences &lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 07.png|500px]]&lt;br /&gt;
&lt;br /&gt;
and a big box should open up! Don’t worry, we don’t need to worry about most of the stuff in here, but some stuff is very important: &lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 08.png|700px]]&lt;br /&gt;
&lt;br /&gt;
It’s critically important to fill out the boxes I’ve outlined in red. The first points RPFM to WH2’s mod directory: it’s just the folder where the .exe is (as the handy tooltip demonstrates!) The second points to a fancy shmancy “MyMod” folder. You’ll need to create this and put it somewhere safe - it can be anywhere that isn’t in Program Files. Making a nice big WH2/WH3 folder under Documents or somewhere to put everything WH2/WH3-related is a good idea. &lt;br /&gt;
&lt;br /&gt;
The blue box isn’t critical, but it’ll save you a bit of effort: defaulting RPFM to WH2 or WH3 (it’s probably on Three Kingdoms) means less clicks when we start up. The remaining settings can be left at defaults, you don’t need them. From here, everything else is optional. As you can see, I also filled out my path for Troy, because I like to mod that a little, but it’s not needed – we’re modding WH2/WH3 so only WH2/WH3 needs to be set up! There’s also “Use Dark Theme” hiding in the checkbox list on the left, which is good for modding at 3am when you’re feeling vampiric and bright light destroys you. &lt;br /&gt;
&lt;br /&gt;
Close RPFM and restart it again, just for good measure. (It’s not actually needed for these settings, contrary to the red warning text, but saves us a little bit of clicking). &lt;br /&gt;
&lt;br /&gt;
There’s one more thing we’ll need to do to get RPFM working properly and that is install the Total War: Warhammer 2 Assembly Kit (same for Warhammer 3). There’s a neat guide on how to do this by CA [https://www.totalwar.com/blog/total-war-warhammer-assembly-kit-terry-quick-start-guide/ here] but in short, Steam -&amp;gt; Library -&amp;gt; Tools then install the TW: Assembly Kit.&lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 09.png|400px]]&lt;br /&gt;
&lt;br /&gt;
It’s important (for RPFM) that the Assembly Kit is installed on the same drive as WH2/WH3. Once it’s downloaded, boot up RPFM again and hit Special Stuff -&amp;gt; Warhammer 2 / Warhammer 3 -&amp;gt; Generate Dependencies Cache. (If the button’s greyed out, just open any WH2/WH3 packfile you care to name; easily done with Open From Data and clicking on whatever you like).&lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 10.png|615px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
It’ll take a minute, but this is really helpful for RPFM’s diagnostic tool that tells you when your keys don’t match up (in short, it lets you know where you goofed up).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Chapter 3 - Making a Mod =&lt;br /&gt;
&lt;br /&gt;
Before we begin, it’s worth noting what sort of stuff mods do, and what can even be done:&lt;br /&gt;
* '''Table editing'''. Simplest and easiest. A lot of Warhammer 2 information like unit health, building recruitments, what spells do what, what skillpoints do what, dilemmas: almost all data for that is stored in tables.&lt;br /&gt;
* '''Graphics, Model, Animation, and Effects Editing'''. I have absolutely no clue how this works so if somebody else could fill in this blank I’d appreciate it. I know textures exist, models exist, and animations exist, but that's about it.&lt;br /&gt;
** You can make new units! From “Handgunners but they’re blue instead of red” to “Treemen with Great Bows” to “Entirely custom floating ships as Tomb King character mounts,” you can basically do anything with the new tools of Phazer’s tools and h3ro’s Asset Editor (fondly nicknamed ‘assed’).&lt;br /&gt;
** You can make new effects (think the shiny things that go off when a spell activates).&lt;br /&gt;
** You can reassign and add new animations, if you’re feeling dedicated enough. &lt;br /&gt;
** What I do know about the above is that it’s all quite difficult, and I would not recommend someone starting out modding to start with this. Search up for other guides – there are some good modding guides on WH2’s Steam mod page.&lt;br /&gt;
* '''Scripts'''. While tables specify what stuff exists, scripts can specify how stuff happens. For instance, the Chaos invasion in Mortal Empires is almost entirely script-based. So is Hellebron’s Death Night. Even Encounters at Sea (the ones where you can fight a whole bunch of vampirates) is script. Wood Elf Forest Encounters, Empire Count dilemmas – the list of script-based functionality goes on. Quite often these link into database stuff (sometimes moreso than others – for instance, traits are entirely database defined but actually gaining any trait is script-based)&lt;br /&gt;
* '''UI Script'''. Still strictly speaking the realm of script, but stuff that has lots of pretty buttons to press, like the Mortuary Cult crafting, the Wood Elf Forge of Daith, Throt’s Flesh Lab; this kind of stuff. Unfortunately, I’m not familiar with any of it and my understanding is it can be quite difficult to adapt to what you want to do.&lt;br /&gt;
** Again, if someone was willing to fill out a bit more information I’d appreciate it!&lt;br /&gt;
* '''Startpos'''. This specifies how things are set up at turn 1 in a campaign. If you’re really screwing with the game (eg: adding new factions) this is necessary, and it’s an absolute pain, earning it the nickname ‘asspos.’ Being a startpos mod also makes it fundamentally incompatible with any other startpos mod, as you can only have one way things are set up in the start of a campaign! Fortunately, if you just want to move a character to a new spot you can do that with script, which is much nicer. There's almost no good reason to mod startpos, so if you are, you shouldn't be.&lt;br /&gt;
&lt;br /&gt;
RPFM’s speciality is '''table editing''''. It can handle scripts pretty well, but ultimately you’re better off writing them somewhere else (Visual Studio Code is good for dedicated scripters), then pasting them into RPFM when done. Additionally, RPFM as a tool combines all the above together – you may have your fancy model and Chaos Knights (Ratling Guns), but you’ll need to put this into RPFM to turn it into a pack file to make it a mod. &lt;br /&gt;
&lt;br /&gt;
RPFM cannot edit startpos (... well, yet) and you’ll need the Total War Assembly Kit to do that, but you should stay away from that unless you have a really good reason to do it (and most reasons aren’t good enough). &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
With all of this in mind, we’re going to make ''two simple mods''.&lt;br /&gt;
Firstly, we’ll increase Lord Skrolk’s melee attack to 100. This is going to be a '''table edit'''.&lt;br /&gt;
Secondly, we’re going to make him start in Caledor, instead of where he normally is. You could do that with startpos, but I can’t stress how much of a bad idea that is, so we’re going to use script. We can put these both together in a single mod.&lt;br /&gt;
&lt;br /&gt;
Well, what are we waiting for? Start RPFM from that handy shortcut you made earlier, and beeeeefore we begin, we need to check one thing: &lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 11.png|700px]]&lt;br /&gt;
&lt;br /&gt;
WH2 needs to be the Game Selected. We are, of course, making a mod for WH2! If this isn’t correct a bunch of silly stuff will happen.&lt;br /&gt;
&lt;br /&gt;
Now, let’s make a mod in RPFM! You can do this the old-fashioned way by PackFile -&amp;gt; New PackFile but RPFM’s MyMod functionality makes everything so much cleaner: open the MyMod menu and hit New MyMod! &lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 12.png]]&lt;br /&gt;
&lt;br /&gt;
A small box will come up that’s pretty self-explanatory.&lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 13.png]]&lt;br /&gt;
&lt;br /&gt;
All the text there explains itself. As for name, I like to start with my username, then use underscores to describe a bit about the mod. So I’ll call it aidenpons_lord_skrolk_yes_yes , hit Save, and let’s go!&lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 14.png]]&lt;br /&gt;
&lt;br /&gt;
Now, we wanted to change Skrolk’s melee attack. That’s going to be in some form of table. So I need to right-click the mod, click Create (not Add! that’s a different table), and then DB (short for database, aka table) &lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 15.png]]&lt;br /&gt;
&lt;br /&gt;
Click that and a box with a bajillion things in its dropdown box comes up!&lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 16.png]]&lt;br /&gt;
&lt;br /&gt;
That’s no good, we want melee attack, not fonts! We need to know what table it’s in, and to find this, we have a couple of choices:&lt;br /&gt;
# Poke the folks on Da Modding Den using one of the #modding-tech channels – a valid call if you’re doing something complicated&lt;br /&gt;
# Find it yourself like an independent and capable person!&lt;br /&gt;
&lt;br /&gt;
I recommend b) where possible. Don’t worry though, it’s not too difficult. What do we know about melee attack? It might not be called that in the game files though, so we don’t want to search it by name. What else do we know? Well, we know Lord Skrolk has a melee attack. So let’s just run a search through the original CA data and see where he turns up.&lt;br /&gt;
&lt;br /&gt;
Put this aside, and open another instance of RPFM by clicking on that handy shortcut you made previously. After making sure Game Selected is Warhammer 2, left click on PackFile. We have a couple of choices here...&lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 17.png]]&lt;br /&gt;
&lt;br /&gt;
We want to load WH2’s data so we can search through it all to find what we want. Thanks to improvements in RPFM, we no longer have to worry about thinking which packfile we specifically want: we can just open them all at once using the “Load All CA Packfiles” button. &lt;br /&gt;
&lt;br /&gt;
It’s also worth mentioning ''Open from Content'' will open from Steam’s workshop content: handy if you want to check a mod’s pack file, but we don’t want that. ''Open From Data'' opens from WH2’s data folder, where both the game’s pack files and mod pack files reside, which explains the massive box that pops up should you hover over it. &lt;br /&gt;
&lt;br /&gt;
Anyway, Load All CA PackFiles, give it a bit to load – it’s a lot of big packs, and we should have something like this: &lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 18.png]]&lt;br /&gt;
&lt;br /&gt;
... well, that’s not very big! Click on the little &amp;gt; arrow next to the .pack, and a load of folders should expand! Expand the db folder (the folder where all the tables are), and even more folders should come up! ... Okay, that’s why it took this long to load. Expand a random folder and click on its data__ (they all have that name):&lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 19.png]]&lt;br /&gt;
&lt;br /&gt;
This is a table. In this case, it’s the table that governs how fatigue happens in battle: so you can see climbing walls nukes fatigue at 10,000, when idle changes fatigue by -18 (which probably means fatigue goes down, which checks out with game knowledge).&lt;br /&gt;
&lt;br /&gt;
Anyway, we wanted Lord Skrolk’s melee attack. Well, we know Lord Skrolk has a melee attack. So let’s try finding him! To do that, we’ll use RPFM’s incredibly handy Global Search. Hit View -&amp;gt; Toggle Global Search Window to bring it up.&lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 20.png]]&lt;br /&gt;
&lt;br /&gt;
(Note: In RPFM v1-ish - which is totally obselete - Global Search was accessed by right-clicking anywhere in the folder view on the left. We’re working with more modern tech though!) A box on the right should pop up as part of RPFM: &lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 21.png|450px]]&lt;br /&gt;
&lt;br /&gt;
Let’s put ''Lord Skrolk'' in the Search bar, hit Search and see what happens! &lt;br /&gt;
After waiting a bit (around 7s on my machine – shouldn’t take more than a minute by any means), we get some results: &lt;br /&gt;
(Note: Results may differ depending on what version of RPFM and WH2 is being used, but either way, the idea of global searching still works).&lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 22.png]]&lt;br /&gt;
&lt;br /&gt;
Huh. Let’s examine one of these more: Click on the &amp;gt; next to the db/character_skills_tables/data__ to expand it, and see what it found. &lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 23.png]]&lt;br /&gt;
&lt;br /&gt;
Hrm. Double-click that and the table will open.&lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 24.png|700px]]&lt;br /&gt;
&lt;br /&gt;
Well, we at least got Lord Skrolk. This is clearly a description for something, not melee attack. But if we scroll around left and right, we can see from the '''Key''' - which is what a lot of WH2 tables use to refer to something unique (eg: units have keys, projectiles have keys, dilemmas have keys, regions have keys, provinces have keys, building have keys, etc etc etc) that WH2 doesn’t use spaces like we searched and instead uses underscores. So, with that in mind, let’s try searching ''lord_skrolk'' instead!&lt;br /&gt;
&lt;br /&gt;
Wait a couple of seconds, and, wow, what a bunch more results! I guess that makes sense for the leader of an entire faction – model, audio, events, and all! And one of these tables is hopefully melee attack...&lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 25.png]]&lt;br /&gt;
&lt;br /&gt;
We’re currently hunting in db but it’s worth giving a mention to the other tabs. Loc Matches searches inside WH2’s complex text database, and is a really good way to get started on finding something if all you know is its in-game name. Text Matches searches, among other things, script and the bit of a model called a “variantmesh” (don’t ask me what this means because I don’t know) – good if you’re hunting script or models, which we aren’t, so we can ignore it. I have no clue what Schema Matches does and have never needed it so we can hopefully ignore it.&lt;br /&gt;
&lt;br /&gt;
Additionally, feel free to resize the window (drag on various handles that pop up), if you’ve got the screen real estate for it. Anyway, we wanted melee attack. There’s no table that looks like melee_attack, but, scrolling a bit up from the bottom, let’s try main_units_tables? &lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 26.png]]&lt;br /&gt;
&lt;br /&gt;
land_unit! That’s something! Double-click on that and a new tab in RPFM should open and scroll down to the line needed.&lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 27.png|700px]]&lt;br /&gt;
&lt;br /&gt;
''(Addendum: WH2, this guide, and RPFM have had so very many updates since things began. If you have a keen eye, you’ll see that the top left is called data.pack not warhammer_2, and that Skrolk is at line 709 when currently he’s at line 789. Things change, and I genuinely cannot keep this guide perfectly up to date. When modding, if nothing else, it’s important to be able to think on your feet as things keep changing around you.)''&lt;br /&gt;
&lt;br /&gt;
You can see our previous character_skills_tables open in a non-active tab. We really don’t need that anymore and you can close it if you want, we’re taking a look at main_units now. &lt;br /&gt;
&lt;br /&gt;
Scrolling across, we see things like Upkeep Cost, Multiplayer Cost, some voiceover stuff, but nothing that looks like melee attack. Well, this ''does'' look like Lord Skrolk (the wh2_main_skv_cha_lord_skrolk seems about right), so we’re probably on the right track. What about that Land Unit? If we hover over the column header in RPFM, it’ll tell us which table this is referencing. (Some columns in tables link other tables together, like this one – but obviously Upkeep Cost doesn’t reference a table!)&lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 28.png|700px]]&lt;br /&gt;
&lt;br /&gt;
Huh, a table called land_units. Would be nice to find that quickly. There are two ways you can do this: one, fishing the table out by hand. This is actually pretty speedy since if we select a random folder on the left and hit L (for Land_units), the folder view will scroll to the first match of L. (You can type even quicker if you want, typing L A N D _ U N I T S , but that’s too much typing for my fingers).&lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 29.png]]&lt;br /&gt;
&lt;br /&gt;
Well, lab_settings is definitely not what we want, but if we scroll down a bit, we’ll find land_units_tables.&lt;br /&gt;
&lt;br /&gt;
The other – and much speedier – option is to use RPFM’s handy Go To functionality. Right-click on the cell and Go To -&amp;gt; Go To Definition, and fazam, RPFM will take you right there!&lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 30.png|700px]]&lt;br /&gt;
&lt;br /&gt;
Either way, we’ve now got land_units_tables open in front of us:&lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 31.png|700px]]&lt;br /&gt;
&lt;br /&gt;
Now, we really don’t want to scroll through all ten bazillion lines of this table to find Skrolk, but instead RPFM has a handy Filter section just below the table view. Type skrolk in that and it’ll only show rows that match skrolk in the Key section. (We wouldn’t want to search for skrolk in the Category section!) There’s tons of superpowerful stuff you can do with more detailed filters (they support Regex, very powerful for searching), but this simple filter will do:&lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 32.png|700px]]&lt;br /&gt;
&lt;br /&gt;
Only one hit? That’s usually pretty good, as it suggests this is a Master Node of some sort, linking a lot of things together. Scroll across the table and we some things about mounts, morale, armor, melee weapon, and – what’s this? Melee attack! We found it!&lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 33.png|700px]]&lt;br /&gt;
&lt;br /&gt;
Now, before we get too excited, this is the data packs of the game themselves. Editing these is a terribly bad idea as it makes there be no way to revert to unmodded short of reinstalling the game, and the reason RPFM won’t let you save your changes if you try. Instead, that’s why we created a mod!&lt;br /&gt;
&lt;br /&gt;
Hop back to the instance of RPFM that has your mod open (or open it again, if you closed it). If you did close it, there’s a super-nifty RPFM trick that allows you to open it super quickly, and it’s under the MyMod menu:&lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 34.png]]&lt;br /&gt;
&lt;br /&gt;
Super speedy and super handy. Anyway, we’d shut that because we didn’t know what table we wanted, but now we know we want land_units tables! So again, right-click, create, create DB...&lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 35.png]]&lt;br /&gt;
&lt;br /&gt;
... and this time we know what table we want – it’s the ''land_units'' table! Typing in land_units doesn’t quite land the hit we need, but it’s easy to find it from the four in the dropdown box:&lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 36.png]]&lt;br /&gt;
&lt;br /&gt;
The new_file in the first line will be the name of your table. This isn’t super important – except that it shouldn’t end with a number and should have no spaces in it – but I like to, again, preface it with my name and then have something about the table. So aiden_land_units will do just fine. &lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 37.png]]&lt;br /&gt;
&lt;br /&gt;
Hit Create, open it up, and it’s blank. Well, of course it’s blank – we haven’t added anything to it!&lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 38.png]]&lt;br /&gt;
&lt;br /&gt;
Well, we want to put the line about Lord Skrolk in here and change his melee attack. I guess you could re-type everything out by hand if you were feeling like you wanted some bonus suffering, but I like my modding to be an enjoyable experience (which is why I don’t touch startpos), and in RPFM, we can copy and paste rows (and much more!) over!&lt;br /&gt;
Hop back to RPFM that has data.pack open, and it should be right where we left it. &lt;br /&gt;
Now – just like Excel – if you click on the row number the entire row will be selected. Right-click somewhere in that row, select Copy, then Copy (the other option we don’t need for this):&lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 39.png|700px]]&lt;br /&gt;
&lt;br /&gt;
Now hop back to our mod, right-click anywhere in the table view, and hit Paste as New Row!&lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 40.png]]&lt;br /&gt;
&lt;br /&gt;
Results should look like this!&lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 41.png|700px]]&lt;br /&gt;
&lt;br /&gt;
Stuff’s a bit squished, but it’s there! Now scroll over to the Melee Attack, double-click to select it, put our nice modded 100 value in, hit Enter, and, that’s done!&lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 42.png]]&lt;br /&gt;
&lt;br /&gt;
But before we get toooooo excited about using an overpowered Lord Skrolk, there’s two more things we need to do: &lt;br /&gt;
&lt;br /&gt;
The first is save the mod! Ctrl+S does the trick, or PackFile -&amp;gt; Save. The second’s more important: to copy the mod to WH2’s data directory so the mod managers actually pick it up.  Instead of fishing up the packfile manually and pasting it over, RPFM does this all with two mouse clicks: PackFile -&amp;gt; Install !&lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 43.png]]&lt;br /&gt;
&lt;br /&gt;
''(Addendum: Previous versions of RPFM had this under the MyMod menu. Again, the buttons might move around and about – it’s important to think on your feet)''&lt;br /&gt;
&lt;br /&gt;
Oh, by the way, if you get an error that looks like this: &lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 43b.png]]&lt;br /&gt;
&lt;br /&gt;
Now our nice little packfile is sitting in WH2’s data directory ready for either the CA mod loader (affectionately called George) or Kaedrin’s Mod Manager (KMM) to pick it up. It’s vitally important to playtest your mods first (and, if nothing else, make sure they load and the game doesn’t crash!), so we’ll do that. &lt;br /&gt;
&lt;br /&gt;
While KMM is definitely superior for managing large amounts of mods and its Profile feature is a godsend, we do actually need the CA mod loader to upload a mod (more on that later), so for this I’ll be using the CA mod loader. Boot it up, and if you scroll down, tadaaaaaaa!&lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 44.png|700px]]&lt;br /&gt;
&lt;br /&gt;
Enable that, hit Play, hit Play on the obligatory “warning you are modded” menu (does anyone besides me actually read that?), and WH2 boots up with our mod in tow! :D &lt;br /&gt;
&lt;br /&gt;
We could start a new campaign to check things out, but we could also be lazy, and just check things in Custom Battles instead. And will you look at that!&lt;br /&gt;
&lt;br /&gt;
[[File:RPFMForDummiesImage 45.png|700px]]&lt;br /&gt;
&lt;br /&gt;
''It woooooooooooooorks!'' :D&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Chapter 4 - Script = &lt;br /&gt;
&lt;br /&gt;
''To Be Continued...''&lt;br /&gt;
&lt;br /&gt;
[[Category: Tools &amp;amp; Resources]]&lt;/div&gt;</summary>
		<author><name>Grimmys</name></author>
	</entry>
	<entry>
		<id>https://tw-modding.com/index.php?title=Category:Tools_%26_Resources&amp;diff=1224</id>
		<title>Category:Tools &amp; Resources</title>
		<link rel="alternate" type="text/html" href="https://tw-modding.com/index.php?title=Category:Tools_%26_Resources&amp;diff=1224"/>
		<updated>2024-03-11T21:45:10Z</updated>

		<summary type="html">&lt;p&gt;Grimmys: Fix typo&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Every modder needs proper tools, just like every lumberjack needs a swing set. This list does not claim to be a sure-fire solution to every single issue a modder might face, nor an impervious list of perfect programs, designed to cater your every need. This list does have a lot of value in it, I believe, and if used correctly, a lot can be achieved.&lt;br /&gt;
&lt;br /&gt;
You’ll also notice that this section has random housed tutorials in it, that don’t fit in any particular place with the larger-scale tutorials. The author and summary of each will be listed and maintained here!&lt;br /&gt;
====Kaedrin’s Mod Manager====&lt;br /&gt;
[https://github.com/Kaedrin/warhammer-mod-manager/releases Warhammer Mod Manager Releases] – Kaedrin’s Mod Manager is a very useful alternative mod manager that works for all Total War games since Total War: Empire.&lt;br /&gt;
&lt;br /&gt;
You can get in contact with the creator, ''Kaedrin'', in the Modding Den’s channel '''#kaedrin_mod_manager'''.&lt;br /&gt;
====Frodo’s Rusted Pack File Manager====&lt;br /&gt;
[https://github.com/Frodo45127/rpfm/releases/ RPFM Releases] – RPFM is a great pack-file managing tool, essential for any modder. Active development has new features coming regularly, as well as constant bug fixes or bug squashings.&lt;br /&gt;
&lt;br /&gt;
You can find its documentation here: [https://frodo45127.github.io/rpfm/ RPFM Documentation]&lt;br /&gt;
. Or you can also check [https://tw-modding.com/wiki/Tutorial:RPFM_For_Dummies this tutorial].&lt;br /&gt;
&lt;br /&gt;
Get in contact with the creator, ''Frodo'', in the Modding Den’s channel '''#rpfm'''.&lt;br /&gt;
==== Phazer's Rigid Model Editing Tool====&lt;br /&gt;
[https://github.com/mr-phazer/RME_Release/releases RME Tool Releases] – A tool to quickly edit rigid models using a visual UI rather than having to use clunky hex editing.&lt;br /&gt;
&lt;br /&gt;
Get in contact with the creator, ''Phazer'', in the Modding Den's channel '''#phazer_tools'''.&lt;br /&gt;
====Ole's Asset Editor====&lt;br /&gt;
[https://github.com/olekristianhomelien/TheAssetEditor/releases/ Asset Editor Releases] – A tool for kitbashing and animation splicing using vanilla assets.&lt;br /&gt;
&lt;br /&gt;
You can check [https://tw-modding.com/wiki/Tutorial:AssetEditor this tutorial] for learning more about it.&lt;br /&gt;
&lt;br /&gt;
Get in contact with the creator, ''Ole'', in the Modding Den's channel '''#asset_editor'''.&lt;br /&gt;
====Thegroovewizard's LUA Debugging Setup====&lt;br /&gt;
[https://github.com/chadvandy/tw_autogen Setup for debugging LUA scripts] – A setup for debugging LUA scripts in [https://code.visualstudio.com/ Visual Studio Code].&lt;br /&gt;
&lt;br /&gt;
Get in contact with the creator, ''Thegroovewizard'', in the Modding Den's channel '''#groove_tower'''.&lt;br /&gt;
====Interactive Maps for Total War: Warhammer II====&lt;br /&gt;
[https://imrz.github.io/tww-interactive-map/latest/#/ Mortal Empires / Eyes of the Vortex interactive maps] – Web application for checking the position of every settlements, regions and ressources on both maps of ''Total War: Warhammer II''.&lt;br /&gt;
====Imagemin App (PNG Compressor)====&lt;br /&gt;
[https://github.com/imagemin/imagemin-app/ Imagemin App] – An application to lower the size of your mod .png, because they have to be less than 1Mb.&lt;br /&gt;
====Video Tutorials====&lt;br /&gt;
[https://www.youtube.com/watch?v=pzqTFR32tl8&amp;amp;feature=youtu.be Setting Up GitHub Desktop for Total War] – A rundown on how to setup GitHub Desktop for use with the Assembly Kit.&lt;br /&gt;
====Scripting Resources====&lt;br /&gt;
[https://chadvandy.github.io/tw_modding_resources/WH3/scripting_doc.html Script Doc Warhammer 3 (Events &amp;amp; Interfaces)]&lt;br /&gt;
&lt;br /&gt;
[https://chadvandy.github.io/tw_modding_resources/WH2/scripting_doc.html Script Doc Warhammer 2 (Events &amp;amp; Interfaces)]&lt;br /&gt;
&lt;br /&gt;
[https://chadvandy.github.io/tw_modding_resources/WH3/campaign/campaign_manager.html#class:campaign_manager Script Doc Warhammer 3 (Campaign Manager Functions)]&lt;br /&gt;
&lt;br /&gt;
[https://chadvandy.github.io/tw_modding_resources/WH2/campaign/campaign_manager.html#class:campaign_manager Script Doc Warhammer 2 (Campaign Manager Functions)]&lt;br /&gt;
&lt;br /&gt;
[https://chadvandy.github.io/tw_modding_resources/index.html Warhammer 2 &amp;amp; 3 CA Documentation]&lt;br /&gt;
&lt;br /&gt;
[https://chadvandy.github.io/tw_modding_resources/3k/scripting_doc.html Three Kingdoms CA Documentation]&lt;br /&gt;
==Tools &amp;amp; Resource Posts:==&lt;br /&gt;
*[[Troubleshooting]] by Vandy and Cataph&lt;br /&gt;
*[[Modding Glossary]] by Vandy and Cataph&lt;br /&gt;
*[[Campaign Map Coordinates]] by Marthenil by Vandy&lt;/div&gt;</summary>
		<author><name>Grimmys</name></author>
	</entry>
	<entry>
		<id>https://tw-modding.com/index.php?title=Category:Tools_%26_Resources&amp;diff=1223</id>
		<title>Category:Tools &amp; Resources</title>
		<link rel="alternate" type="text/html" href="https://tw-modding.com/index.php?title=Category:Tools_%26_Resources&amp;diff=1223"/>
		<updated>2024-03-11T21:44:16Z</updated>

		<summary type="html">&lt;p&gt;Grimmys: Add links to internal pages of some tools&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Every modder needs proper tools, just like every lumberjack needs a swing set. This list does not claim to be a sure-fire solution to every single issue a modder might face, nor an impervious list of perfect programs, designed to cater your every need. This list does have a lot of value in it, I believe, and if used correctly, a lot can be achieved.&lt;br /&gt;
&lt;br /&gt;
You’ll also notice that this section has random housed tutorials in it, that don’t fit in any particular place with the larger-scale tutorials. The author and summary of each will be listed and maintained here!&lt;br /&gt;
====Kaedrin’s Mod Manager====&lt;br /&gt;
[https://github.com/Kaedrin/warhammer-mod-manager/releases Warhammer Mod Manager Releases] – Kaedrin’s Mod Manager is a very useful alternative mod manager that works for all Total War games since Total War: Empire.&lt;br /&gt;
&lt;br /&gt;
You can get in contact with the creator, ''Kaedrin'', in the Modding Den’s channel '''#kaedrin_mod_manager'''.&lt;br /&gt;
====Frodo’s Rusted Pack File Manager====&lt;br /&gt;
[https://github.com/Frodo45127/rpfm/releases/ RPFM Releases] – RPFM is a great pack-file managing tool, essential for any modder. Active development has new features coming regularly, as well as constant bug fixes or bug squashings.&lt;br /&gt;
&lt;br /&gt;
You can find its documentation here: [https://frodo45127.github.io/rpfm/ RPFM Documentation]&lt;br /&gt;
Or you can also check [https://tw-modding.com/wiki/Tutorial:RPFM_For_Dummies this tutorial].&lt;br /&gt;
&lt;br /&gt;
Get in contact with the creator, ''Frodo'', in the Modding Den’s channel '''#rpfm'''.&lt;br /&gt;
==== Phazer's Rigid Model Editing Tool====&lt;br /&gt;
[https://github.com/mr-phazer/RME_Release/releases RME Tool Releases] – A tool to quickly edit rigid models using a visual UI rather than having to use clunky hex editing.&lt;br /&gt;
&lt;br /&gt;
Get in contact with the creator, ''Phazer'', in the Modding Den's channel '''#phazer_tools'''.&lt;br /&gt;
====Ole's Asset Editor====&lt;br /&gt;
[https://github.com/olekristianhomelien/TheAssetEditor/releases/ Asset Editor Releases] – A tool for kitbashing and animation splicing using vanilla assets.&lt;br /&gt;
&lt;br /&gt;
You can check [https://tw-modding.com/wiki/Tutorial:AssetEditor this tutorial] for learning more about it.&lt;br /&gt;
&lt;br /&gt;
Get in contact with the creator, ''Ole'', in the Modding Den's channel '''#asset_editor'''.&lt;br /&gt;
====Thegroovewizard's LUA Debugging Setup====&lt;br /&gt;
[https://github.com/chadvandy/tw_autogen Setup for debugging LUA scripts] – A setup for debugging LUA scripts in [https://code.visualstudio.com/ Visual Studio Code].&lt;br /&gt;
&lt;br /&gt;
Get in contact with the creator, ''Thegroovewizard'', in the Modding Den's channel '''#groove_tower'''.&lt;br /&gt;
====Interactive Maps for Total War: Warhammer II====&lt;br /&gt;
[https://imrz.github.io/tww-interactive-map/latest/#/ Mortal Empires / Eyes of the Vortex interactive maps] – Web application for checking the position of every settlements, regions and ressources on both maps of ''Total War: Warhammer II''.&lt;br /&gt;
====Imagemin App (PNG Compressor)====&lt;br /&gt;
[https://github.com/imagemin/imagemin-app/ Imagemin App] – An application to lower the size of your mod .png, because they have to be less than 1Mb.&lt;br /&gt;
====Video Tutorials====&lt;br /&gt;
[https://www.youtube.com/watch?v=pzqTFR32tl8&amp;amp;feature=youtu.be Setting Up GitHub Desktop for Total War] – A rundown on how to setup GitHub Desktop for use with the Assembly Kit.&lt;br /&gt;
====Scripting Resources====&lt;br /&gt;
[https://chadvandy.github.io/tw_modding_resources/WH3/scripting_doc.html Script Doc Warhammer 3 (Events &amp;amp; Interfaces)]&lt;br /&gt;
&lt;br /&gt;
[https://chadvandy.github.io/tw_modding_resources/WH2/scripting_doc.html Script Doc Warhammer 2 (Events &amp;amp; Interfaces)]&lt;br /&gt;
&lt;br /&gt;
[https://chadvandy.github.io/tw_modding_resources/WH3/campaign/campaign_manager.html#class:campaign_manager Script Doc Warhammer 3 (Campaign Manager Functions)]&lt;br /&gt;
&lt;br /&gt;
[https://chadvandy.github.io/tw_modding_resources/WH2/campaign/campaign_manager.html#class:campaign_manager Script Doc Warhammer 2 (Campaign Manager Functions)]&lt;br /&gt;
&lt;br /&gt;
[https://chadvandy.github.io/tw_modding_resources/index.html Warhammer 2 &amp;amp; 3 CA Documentation]&lt;br /&gt;
&lt;br /&gt;
[https://chadvandy.github.io/tw_modding_resources/3k/scripting_doc.html Three Kingdoms CA Documentation]&lt;br /&gt;
==Tools &amp;amp; Resource Posts:==&lt;br /&gt;
*[[Troubleshooting]] by Vandy and Cataph&lt;br /&gt;
*[[Modding Glossary]] by Vandy and Cataph&lt;br /&gt;
*[[Campaign Map Coordinates]] by Marthenil by Vandy&lt;/div&gt;</summary>
		<author><name>Grimmys</name></author>
	</entry>
	<entry>
		<id>https://tw-modding.com/index.php?title=Tutorial:AssetEditor&amp;diff=1222</id>
		<title>Tutorial:AssetEditor</title>
		<link rel="alternate" type="text/html" href="https://tw-modding.com/index.php?title=Tutorial:AssetEditor&amp;diff=1222"/>
		<updated>2024-03-11T21:38:31Z</updated>

		<summary type="html">&lt;p&gt;Grimmys: Add tools category&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The AssetEditor is a poor man's 3d program for Total war games (currently only supports WH2). &lt;br /&gt;
&lt;br /&gt;
It aims at trying to recreate the Kit bashing feeling you get when working with plastic models.&lt;br /&gt;
&lt;br /&gt;
'''Download link''': [https://github.com/olekristianhomelien/TheAssetEditor/releases/latest https://github.com/donkeyProgramming/TheAssetEditor/releases/latest]&lt;br /&gt;
&lt;br /&gt;
'''Youtube tutorials:''' https://www.youtube.com/channel/UCXnf2q9fRNYlMn4XULPLKgg&lt;br /&gt;
&lt;br /&gt;
'''Beginner tutorial by FaallenOon:''' [https://docs.google.com/document/d/1QZefJwJLvG_ny2MUMZZvvxV-4o2AAuSCmmiA-twAIXw/edit https://docs.google.com/document/d/1QZefJwJLvG_ny2MUMZZvvxV-4o2AAuSCmmiA-twAIXw] &lt;br /&gt;
&lt;br /&gt;
'''Disclaimer''': I am not good at technical writing or enjoy it, so if someone feels the desire to improve this, then please! &lt;br /&gt;
&lt;br /&gt;
==The Basics==&lt;br /&gt;
&lt;br /&gt;
===Creating a New Packfile===&lt;br /&gt;
To create a new packfile go to the top left corner of the program and click file then select New Packfile and a window will open asking you to enter a name, once you have entered a name press ok and your packfile will be created in the file browser to the left and will be marked as active which is identified by '''bold''' text.&lt;br /&gt;
&lt;br /&gt;
===Opening a Model ===&lt;br /&gt;
To get started working with models navigate to the file browser on the left and open the All CA Packs folder, scroll down to variantmeshes, into wh_variantmodels and browse through the list for a model of your choosing and once you have found the model that you seek you can double click upon the rigid_model_v2 file to open the model within the 3d viewer.&lt;br /&gt;
&lt;br /&gt;
====How to find a Model====&lt;br /&gt;
If you have an idea of what kind of model you are looking for you can use the Search Filter box at the top of the file browser to try and narrow down the amount of folders you need to search through but if you do not then you can take a rough guess at where models are located by the folder names which correspond to the models skeleton for example:&lt;br /&gt;
&lt;br /&gt;
*hu1 = humanoid01 - which are associated with male humans.&lt;br /&gt;
&lt;br /&gt;
*hu1b = humanoid01b - which are associated with female humans and female elves.&lt;br /&gt;
&lt;br /&gt;
*hu1c = humanoid01c - which are associated with norscan and chaos humans.&lt;br /&gt;
&lt;br /&gt;
Etc, you'll quickly become familiar with these while modding.&lt;br /&gt;
&lt;br /&gt;
===Camera Controls===&lt;br /&gt;
While in the visual work space you can navigate the 3d area by placing your mouse cursor within the window and using the following:&lt;br /&gt;
&lt;br /&gt;
*Holding down Alt + Left Mouse Button (LMB) will move the camera around a fixed point.&lt;br /&gt;
&lt;br /&gt;
*Holding down Alt + Scrolling the Mouse Wheel up will zoom in towards the fixed point and scrolling it back will zoom out.&lt;br /&gt;
&lt;br /&gt;
*Holding down Alt + Right Mouse Button (RMB) will allow you to reposition the fixed point.&lt;br /&gt;
&lt;br /&gt;
===Saving a Model===&lt;br /&gt;
To save your freshly acquired model to your packfile navigate to the tool bar at the top of the screen and hit the save icon (Ctrl+S) at which point you will see the model appear under your packfile in the file browser marked in red which means that you have saved the models current state but this does not save your packfile and closing the program before doing so will delete any work you have done up to this point.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If you are working with multiple packfiles at the same time you must switch to the correct packfile before saving your models or they will save in the wrong place, to do this right click an inactive pack in the file browser and select Set as Editable Pack.&lt;br /&gt;
&lt;br /&gt;
===Saving a Packfile===&lt;br /&gt;
To save your packfile navigate to the file browser and right click your packfiles name, select Save or Save As and select a location for your file then hit save again, your packfile is now saved and it is safe to close the program.[[File:SavePackfile.png|thumb|alt=|none]]&lt;br /&gt;
&lt;br /&gt;
== Sub Tools==&lt;br /&gt;
&lt;br /&gt;
=== Kitbash Editor===&lt;br /&gt;
Select a .rmv2 file to open the Kitbash Editor&lt;br /&gt;
&lt;br /&gt;
Find your self a model to play with.  Go to:&lt;br /&gt;
&lt;br /&gt;
variantmeshes/ &lt;br /&gt;
&lt;br /&gt;
wh_variantmodels/&lt;br /&gt;
&lt;br /&gt;
There is folders named after skeletons.  hu1 is for humans.&lt;br /&gt;
&lt;br /&gt;
In hu1 you have files for each factions that use it.&lt;br /&gt;
&lt;br /&gt;
Look for a file that ends with .rigid_model_V2&lt;br /&gt;
&lt;br /&gt;
Ignore the .wsmodels for now&lt;br /&gt;
&lt;br /&gt;
Youtube tutorial: https://www.youtube.com/watch?v=LeObDGqV2PM&lt;br /&gt;
&lt;br /&gt;
====Re-Regging====&lt;br /&gt;
One of the key parts of the Kitbash editor is the ability to re-rig a mesh from one skeleton to an other. If this is not done, the mesh will turn into spaghetti when an animation is applied.&lt;br /&gt;
&lt;br /&gt;
It works by doing a 1:1 mapping between bones in the original skeleton (left side) and the target skeleton (right side)&lt;br /&gt;
&lt;br /&gt;
It works by selecting bones one by one on the left side and then selecting a bone on the right side. When this is done the column on the left side that says -1 should turn into the same the bone selected on the right side.&lt;br /&gt;
&lt;br /&gt;
The tool can also attempt to auto fit the mesh onto the skeleton by selecting the &amp;quot;Fit mesh to skeleton&amp;quot; checkbox.&lt;br /&gt;
&lt;br /&gt;
[[File:ReriggingImage.png|none|thumb]]&lt;br /&gt;
[[File:RemappingBoneSelected.png|none|thumb|Bone selected and mapped correctly]]&lt;br /&gt;
[[File:Remapping.png|none|thumb|Old and messy tutorial]]&lt;br /&gt;
&lt;br /&gt;
====BMI tool====&lt;br /&gt;
The BMI editor allows the scaling of a mesh along its normals. This gives the impression of adding or removing thickness to and object.&lt;br /&gt;
&lt;br /&gt;
All the bones that are selected in the tree view is applied to the scale when the apply button is pressed.[[File:BmiTool before.png|none|thumb|Before]]&lt;br /&gt;
[[File:BmiTool After.png|none|thumb|After]]&lt;br /&gt;
&lt;br /&gt;
===Mount Animation Creator===&lt;br /&gt;
The tool also allows for attaching an animation to a vertex on an other skeleton. This is useful for creating mount animations for mount that does not exist in the game. &lt;br /&gt;
&lt;br /&gt;
An example of this would be adding a Squig mound to Karl Franze or a Lion animation to the High Elf Princess. https://www.youtube.com/watch?v=4dKFXAu4R1Y&lt;br /&gt;
&lt;br /&gt;
'''Excellent, must read tutorial for how to use the tool''': https://docs.google.com/document/d/123LZH16sY2EGRJWwTH4T3XvT0ENUUQXLLfL6tVUtezk/edit&lt;br /&gt;
&lt;br /&gt;
A run-through of the UI components:&lt;br /&gt;
&lt;br /&gt;
#Information about the rider and mount (mesh, skeleton and animation)&lt;br /&gt;
#Control how the rider is attached to the mount&lt;br /&gt;
#*Rider root bone (probably never change this)&lt;br /&gt;
#*Leg animation (disabled for now)&lt;br /&gt;
#*The vertex the rider is attached to. Select the mount, press F3 then select the vertex that the rider should be select to and press Set. The first selected vertex is used if multiple vertexes are selected&lt;br /&gt;
#Settings for the animation - Hopefully pretty intuitive&lt;br /&gt;
#Rider and mount animation fragment and active slots &lt;br /&gt;
#*Mount is the animation fragment used by the mount&lt;br /&gt;
#*Rider is the animation fragment used by the rider&lt;br /&gt;
#*Mount animation tag is the animation used by the mount&lt;br /&gt;
#Save and Preview:&lt;br /&gt;
#*Update the preview to reflect changes done in the animation settings view&lt;br /&gt;
#*Active fragment to add items to&lt;br /&gt;
#*Slot in the active fragment to add to&lt;br /&gt;
#*Batch process based on the values in &amp;quot;Mount link shortcut view&amp;quot;&lt;br /&gt;
#Drawing related things&lt;br /&gt;
[[File:Mount tool defaultworkflow.png|none|thumb|Screenshot]]&lt;br /&gt;
[[File:Image2.png|none|thumb|Selecting vertex]]&lt;br /&gt;
&lt;br /&gt;
====Workflow====&lt;br /&gt;
#Select rider and mount meshes&lt;br /&gt;
#Select attachment point&lt;br /&gt;
#Select rider and mount fragment&lt;br /&gt;
#Play around with the settings until you are happy with how it looks&lt;br /&gt;
#Press Batch prosess to generate animpack, bin and fragment.&lt;br /&gt;
#Look at the report to see if manual tweaks are needed.&lt;br /&gt;
#If manual tweaks are needed:&lt;br /&gt;
##Load the new fragment into &amp;quot;selected fragment&amp;quot;&lt;br /&gt;
##Find a slot that needs to be fixed.&lt;br /&gt;
##Select the correct Mount tag for the selected rider slot&lt;br /&gt;
##Select a rider tag that looks good&lt;br /&gt;
##Press add to fragment&lt;br /&gt;
##Repeat&lt;br /&gt;
[[File:Mount tool defaultworkflow fixstuff.png|none|thumb]]&lt;br /&gt;
&lt;br /&gt;
====Sliding====&lt;br /&gt;
If the rider is sliding around or popping, make sure that the scale of the mount is correct.&lt;br /&gt;
&lt;br /&gt;
====Matched animations====&lt;br /&gt;
Matched animations does not work well right now, I recommend deleting them. &lt;br /&gt;
&lt;br /&gt;
===Anm.Meta files Editor===&lt;br /&gt;
The tool can display and edit most meta file, more information will be added later[[File:ImageMeta.png|none|thumb]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== AnimPack Editor ===&lt;br /&gt;
The tool comes with an animation pack editor. The animpack is the file which controls how animations are configured. &lt;br /&gt;
&lt;br /&gt;
Refer to the &amp;quot;animation and you&amp;quot; tutorial for more information about how they are structured &lt;br /&gt;
&lt;br /&gt;
[[File:Images.png|alt=|1226x1226px]]&lt;br /&gt;
&lt;br /&gt;
==== How to create a new fragment (animation set) for a unit ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Go to '''File -&amp;gt; Create -&amp;gt; New AnimPack(game''') and enter a name when prompted. This gives you a very basic example of how the file works. For more information I recommend looking into the existing game animpack&lt;br /&gt;
&lt;br /&gt;
By default the tool creates a placeholder bin entry[[File:CustomAnimPack.png|left|alt=|1373x1373px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Create a new fragment by going to '''File-&amp;gt;New AnimationSet(Game)''' inside the animpack editor. This gives you the fragment where the animation information about the unit is stored&lt;br /&gt;
&lt;br /&gt;
Edit the bin to to be sensible values. Best way to do this is by copying a bin which is the closest to what you want to do. In this case it was the &amp;quot;hu2_orc_2handed_axe&amp;quot; entry and then I replaced the &amp;quot;hu2_orc_2handed_axe&amp;quot; names with the new name of the fragment.&lt;br /&gt;
&lt;br /&gt;
'''Save the bin.'''&lt;br /&gt;
&lt;br /&gt;
[[File:BinValues.png|alt=|1376x1376px]]&lt;br /&gt;
&lt;br /&gt;
Go the the frag, it contains some example data. Replace it with the data you want. Typically this means copy pasting in the fragment the closest to what you want, then updating it. In this case it was the &amp;quot;hu2_orc_2handed_axe&amp;quot; and I updated some of the meta files to use the new files I have created (Note, the files on the left in the tree view has not yet been renamed!)&lt;br /&gt;
&lt;br /&gt;
'''Save the frg, then save the animpack by going to File-&amp;gt;Save'''&lt;br /&gt;
[[File:EditAndSaveFrg.png|thumb|alt=|none|1375x1375px]]Now your animpack is done, but you need to link it to a unit. Dindi has kindly created an example animpack for how to do this!&lt;br /&gt;
[[File:Anim db example.pack|none|thumb]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Tools &amp;amp; Resources]]&lt;/div&gt;</summary>
		<author><name>Grimmys</name></author>
	</entry>
	<entry>
		<id>https://tw-modding.com/index.php?title=Mods&amp;diff=1221</id>
		<title>Mods</title>
		<link rel="alternate" type="text/html" href="https://tw-modding.com/index.php?title=Mods&amp;diff=1221"/>
		<updated>2024-03-11T21:35:34Z</updated>

		<summary type="html">&lt;p&gt;Grimmys: Add workshop link for TW:WH3&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;A mod is any alteration to the base game, through [[modding]].&lt;br /&gt;
&lt;br /&gt;
Mods are made up of a single .pack file, which contains all the changes for that mod, and a single .png file of the same name - which is just used as the thumbnail within Steam and the Total War Launcher.&lt;br /&gt;
== Finding Mods ==&lt;br /&gt;
Most mods that you will find can be discovered on the Steam Workshop page, for each Total War game.&lt;br /&gt;
&lt;br /&gt;
* [https://steamcommunity.com/app/594570/workshop/ Total War: Warhammer 2 Steam Workshop]&lt;br /&gt;
* [https://steamcommunity.com/app/1142710/workshop/ Total War: Warhammer 3 Steam Workshop]&lt;br /&gt;
* Etc.&lt;br /&gt;
&lt;br /&gt;
Point of assistance here - you'll have a better time either Googling for the mods you're looking for (ie., &amp;quot;total war warhammer 2 greenskin units mods&amp;quot;), or searching for a collection on the Workshop. Steam Workshop is... a subpar searching service. Ironically.&lt;br /&gt;
&lt;br /&gt;
== Installation ==&lt;br /&gt;
When you find a mod you like in the Steam Workshop, you simply press the &amp;quot;Subscribe&amp;quot; button - '''making sure to download all required items for that mod!''' - and let Steam download it in the background. Next time you load up the game, you will see it available in the launcher's mod manager. Simply tick the mod in the manager, and it will be enabled next time you press play!&lt;br /&gt;
&lt;br /&gt;
Important note here: Don't faff around with [[Troubleshooting#How_to_Load_Order|load order]]. Mods are sorted alphanumerically by default, and modders are aware of the priorities needed between mods most of the time, when it comes to [[Tutorial:Submodding#WHAT_IS_A_SUBMOD.3F|submods]] or similar.&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
&lt;br /&gt;
If a mod doesn't appear to work or update, you can try to unsubscribe and re-subscribe, though in some instances this may not be enough and you may need to Clear the Steam Download Cache, see this [https://support.steampowered.com/kb_article.php?ref=3134-TIAL-4638 article]&lt;br /&gt;
&lt;br /&gt;
See also: [[Troubleshooting]]&lt;br /&gt;
&lt;br /&gt;
== Compatibility ==&lt;/div&gt;</summary>
		<author><name>Grimmys</name></author>
	</entry>
	<entry>
		<id>https://tw-modding.com/index.php?title=Lua/First_Script&amp;diff=1220</id>
		<title>Lua/First Script</title>
		<link rel="alternate" type="text/html" href="https://tw-modding.com/index.php?title=Lua/First_Script&amp;diff=1220"/>
		<updated>2024-03-11T21:31:50Z</updated>

		<summary type="html">&lt;p&gt;Grimmys: Add LUA tutorial category&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In this first step tutorial, we're going to learn:&lt;br /&gt;
&lt;br /&gt;
* How to load &amp;amp; run a custom Lua script&lt;br /&gt;
* How timing works, at a large level, with scripts&lt;br /&gt;
* How to print out game information to interrogate the state of the game&lt;br /&gt;
* How simple variables work&lt;br /&gt;
&lt;br /&gt;
Let's create our first script together!&lt;br /&gt;
&lt;br /&gt;
== Setup ==&lt;br /&gt;
First thing's first, let's crack open RPFM to create our new Mod. In RPFM, I'm going to use MyMod -&amp;gt; New MyMod, to create a new easy-to-use mod system. If you haven't already, follow the setup guides in [[RPFM]] for setting up preferences and paths.&lt;br /&gt;
&lt;br /&gt;
[[File:First Script 01.png|frameless|712x712px]]&lt;br /&gt;
&lt;br /&gt;
RPFM will then open up our new MyMod. Within it, use MyMod -&amp;gt; Export, which will unload the contents of the newly created (almost entirely empty) MyMod into your specified MyMods folder. I have this folder pinned to my quick access, but you can also get there with MyMod -&amp;gt; Open MyMod Folder, and navigating down to the newly created MyMod.&lt;br /&gt;
&lt;br /&gt;
Now we can right click this folder and use the newly added &amp;quot;Open with Code&amp;quot; button, which will take the targeted mod folder and open it within Visual Studio Code!&lt;br /&gt;
&lt;br /&gt;
== Visual Studio Code Navigation ==&lt;br /&gt;
When we open up in Visual Studio Code, we'll see something that looks a little bit like this - it might differ slightly, that's totally okay!&lt;br /&gt;
[[File:First script 2.png|none|thumb|1061x1061px|It might seem like quite a lot at first, but we'll get used to it! Just make sure to set the settings to dark mode if you're not insane.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Before we get too far, let's break down some of the parts of what we're looking at here, and set up our windows so we have everything we need.&lt;br /&gt;
&lt;br /&gt;
=== Primary Bar ===&lt;br /&gt;
On the very left, we have what VSCode calls the &amp;quot;Primary Bar&amp;quot;. It has a few things here - the top has the two files stacked on each other, a search button below that, three buttons we don't have to worry too much about yet, and a Bookmark button. The bottom has our Account and Manage button. '''If you haven't already''', click into the Manage button and set our Profile to the correct one. I have mine saved as &amp;quot;TW Lua&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
The part of the primary bar we care most about is the top button, the &amp;quot;Explorer&amp;quot;. Think of this as your file navigation - it's effectively the same as navigating the Windows File Explorer, but it has some extra goodies that will be nice for us.&lt;br /&gt;
[[File:First script 3.png|left|thumb|578x578px]]&lt;br /&gt;
At the top of the Explorer, we have &amp;quot;Open Editors&amp;quot;. This will show us all of our actively opened files - we'll see this shortly!&lt;br /&gt;
&lt;br /&gt;
Below that, we have a tab for the currently opened folder. My folder is named babys_first_script, so that's what shows as the name here. Inside are all of the folders AND files that exist within my folder on my PC. We can open, create, rename, and delete any file within to our heart's content, and edit as long as Visual Studio Code can edit it. VSCode can edit essentially any text file, which is what all code files are, effectively. Based on the type of text file, VSCode will handle it differently - it knows the difference between a .lua and a .json file, and will react accordingly to the specifications of either language.&lt;br /&gt;
&lt;br /&gt;
Below that, we had &amp;quot;TODOs: Tree&amp;quot;, which is an extension preloaded with our Profile. This is one of my favorite tabs, because I can leave notes for myself to do stuff later and they will be displayed in this window.&lt;br /&gt;
&lt;br /&gt;
Below that are Outline and Timeline, which I rarely use but can sometimes be nice. Outline will show us the layout of our code, and Timeline will show us previous local history for saving/editing these files, and more details if we're using GitHub or another version control software.&lt;br /&gt;
&lt;br /&gt;
The Search button is also incredibly useful, for reasons that may be obvious.&lt;br /&gt;
&lt;br /&gt;
=== Menu Bar ===&lt;br /&gt;
On the very top, we have our conveniently named Top Bar, or Menu Bar. You've seen these a billion times before. There's a LOT of stuff up here, but in my five years of using this program for TW Lua I've only really cared about a couple buttons within.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;File&amp;quot; is going to be our best friend, for opening new windows, saving, and creating new files. Edit/Selection/View have a load of commands in them, and they may be good to reference often early on to see shortcuts for saving and other helpful code shortcuts, like duplicating text or renaming stuff.&lt;br /&gt;
&lt;br /&gt;
For now, what we should do is click View -&amp;gt; Problems, which will open up a new bottom bar for us. We only care about the &amp;quot;Problems&amp;quot; tab that shows up.&lt;br /&gt;
&lt;br /&gt;
=== Customizabilitization ===&lt;br /&gt;
Let's introduce the idea here that VSCode is '''super duper''' flexible with its layout. Anything on your screen right now can be put somewhere else, including individual tabs, buttons, anything. We can move Problems as a button to the Primary Bar, the Explorer as a tab on the bottom, and TODOs on the right all alone.&lt;br /&gt;
[[File:First script 4.png|thumb|824x824px]]&lt;br /&gt;
It's a bit clunky and not exactly what I need, but it's as good time as any to show you how flexible it can get.&lt;br /&gt;
&lt;br /&gt;
For now, I'm going to plop Search and TODOs on my new right sidebar stacked on one another, I'm going to right click one of the tabs at the bottom and deselect &amp;quot;Terminal&amp;quot;, &amp;quot;Output&amp;quot;, and &amp;quot;Debug Console&amp;quot;, and keep my left Primary Bar as is otherwise and open back up the Explorer.&lt;br /&gt;
&lt;br /&gt;
== Script Creation ==&lt;br /&gt;
Okay, enough preamble. Let's get it started.&lt;br /&gt;
&lt;br /&gt;
=== The Plan ===&lt;br /&gt;
Our standard first step for creating a new script is the first step we should do whenever making a new mod or system: having a plan, something we want. For this one, our goal is going to be simple. I want the following:&lt;br /&gt;
&lt;br /&gt;
* When the game starts, I want to output a message to a text file that tells me the game started, and tells me where my starting faction leader and capital region are.&lt;br /&gt;
* On every turn after that, I want to give my faction some extra gold.&lt;br /&gt;
* If I'm playing as Karl Franz, I want to give my faction another two armies.&lt;br /&gt;
* I swear it's balanced.&lt;br /&gt;
&lt;br /&gt;
=== Make It ===&lt;br /&gt;
[[File:First script 5.png|left|thumb|Second button from the left!]]&lt;br /&gt;
In VSC, go to the Explorer, and hover over the currently-opened-folder tab. You can either right click within the white space and press &amp;quot;New Folder&amp;quot;, or press the New Folder button on the tab for the currently opened folder.&lt;br /&gt;
&lt;br /&gt;
Name the empty folder that's created `script`. All scripts we write will be in this main folder. With this folder selected, create a new folder again, and call this one &amp;quot;campaign&amp;quot;. Do it again, calling the third &amp;quot;mod&amp;quot;, making our full path script/campaign/mod.&amp;lt;blockquote&amp;gt;'''NOTE:''' This folder path is one of several that is specified by Creative Assembly in more recent games, for modders to add scripts to which get automatically loaded. This behavior exists in Warhammer II, Warhammer III, Three Kingdoms, and Troy. It may continue for future games, but any game before Warhammer II needs a different way to load scripts.&lt;br /&gt;
&lt;br /&gt;
For more information, check out [[Lua/Loading Scripts]].&amp;lt;/blockquote&amp;gt;Within script/campaign/mod, now either right click the folder and press &amp;quot;New Text File&amp;quot;, or use the first button on the tab to create a new file. I'm going to name mine &amp;quot;totally_not_cheats.lua&amp;quot;. '''The .lua extension is required, don't skip it!'''&lt;br /&gt;
&lt;br /&gt;
=== Start It ===&lt;br /&gt;
With our newly created file, our VSC layout will change ever so slightly. In &amp;quot;Open Editors&amp;quot;, we'll see our fresh new baby script created; and in the central window, we'll see a new tab that's named the same as our new file, and an empty text file in the center with just the number &amp;quot;1&amp;quot; in it.&lt;br /&gt;
[[File:First script 6.png|none|thumb|894x894px|Notice the lil' moon symbol next to our file? That's because Lua is Portuguese for moon!]]&lt;br /&gt;
We'll kick off our script with the first piece of the puzzle, outputting some text to a file so we can read and interface with our scripts.&lt;br /&gt;
&lt;br /&gt;
Let's get it going with a function called `out()`. This is a CA-defined function that they use all over their scripts, to print out to a text file various bits of info about the game, for debugging and logging purposes. It's a really handy system that'll let you know for certain what's actually going on in your scripts at runtime, since we can't truly test our script outside of the game.&lt;br /&gt;
&lt;br /&gt;
To use the `out` function, we just have to write that word, put an open parenthesis, put in what we want to output, and then write a closing parenthesis. Let's try the old standard, and toss in the following:&amp;lt;blockquote&amp;gt;out( Hello World! )&amp;lt;/blockquote&amp;gt;And we should be goo- oh no! Everything's red! Why are there so many problems?!&lt;br /&gt;
[[File:First script 7.png|thumb|563x563px|If you don't see the above problems or red text, you probably didn't do the setup correctly in the previous lesson. Do it!]]&lt;br /&gt;
&lt;br /&gt;
=== Debugging ===&lt;br /&gt;
This will be something we'll see maybe a million times as we go forward, and it's important to not get too stressed out about it early on.&lt;br /&gt;
&lt;br /&gt;
Because of our work in [[Lua/Setup]], we now have access to a right proper debugging system that will yell at us when we do something wrong.&lt;br /&gt;
&lt;br /&gt;
There's a lot of confusing bits here, and honestly, none of the problems listed are going to be specific enough to tell us what to do to fix it - at least in this situation. Some of them are telling us that we're arguing too much, one is talking about undefined globals, and one is just absolute pig latin saying it expected &amp;lt;exp&amp;gt;. None of those mean anything to us, but let's check out something that does - some documentation!&lt;br /&gt;
&lt;br /&gt;
If you hover over the word &amp;quot;out&amp;quot;, you'll see a popup that gives us some information about the function `out`. The most important bit is the following:&lt;br /&gt;
[[File:First script 8.png|none|thumb]]&lt;br /&gt;
This is our '''function definition'''. It tells us what the function is called, and what it expects within the parentheses. It's asking for something it calls &amp;quot;output&amp;quot;, and output is a string. '''String''' is the first of several Lua &amp;quot;types&amp;quot; we'll go over in this tutorial series. A '''string''' is text - and it's called such because it's a string of ''characters'' that make up a long piece of text. The issue we've had here is that, while `Hello World!` is text, Lua needs to be told that it's a string type. To do that, we just need to wrap quotation marks - either single or double, doesn't matter, but it can't be backticks or &amp;quot;pretty&amp;quot; quotations like what mobile phones default to. I learned that the hard way.&lt;br /&gt;
&lt;br /&gt;
The easiest way to do that is to highlight the entirety of Hello World! and type in the quotation mark, just one. VSCode will plop a quotation mark on either part of your selection, and all SEVEN of our problems will vanish through air.&lt;br /&gt;
[[File:First script 9.png|thumb|The white dot on our tab means this is an unsaved file; use Ctrl+S to save it!]]&lt;br /&gt;
&lt;br /&gt;
== Getting It In-Game ==&lt;br /&gt;
We have now an incredibly basic script that I'd like to test out.&lt;br /&gt;
&lt;br /&gt;
Now, the `out` function is defined by Creative Assembly within their games, but it comes '''disabled by default''' for retail. That means that while your code runs, it won't actually write anything to a log file. That way they can have their debugging tools, and we can opt into it, but it doesn't automatically happen for every single user.&lt;br /&gt;
&lt;br /&gt;
This disable-by-default can be overridden in different ways, depending on the game. As of the time of writing this guide, my favorite methods are:&lt;br /&gt;
&lt;br /&gt;
* Using the [https://steamcommunity.com/sharedfiles/filedetails/?id=2927955021 Mod Configuration Tool]'s  setting for enabling game logging, if available for that game.&lt;br /&gt;
* Using the [https://steamcommunity.com/sharedfiles/filedetails/?id=2789857593&amp;amp;searchtext=script+debug+activator Script Debug Activator] mod, if available for that game.&lt;br /&gt;
* Creating a file in your mod at `script/enable_console_logging`, with no extension. You can use VSCode and use add text file at that destination, add any text inside the file and save it.&lt;br /&gt;
&lt;br /&gt;
These may change or evolve as time goes on.&lt;br /&gt;
&lt;br /&gt;
=== Loading ===&lt;br /&gt;
Once you've got your script ready, and your game is set up to have script logs printed out, we'll want to load up our .pack file and get it set in game. For the sake of my soul and time, I'm going to assume we know how packs work, creating them and loading them, and the like.&lt;br /&gt;
&lt;br /&gt;
Step one, we've got to save our stuff in VSCode. Use File -&amp;gt; Save All.&amp;lt;blockquote&amp;gt;Worth a shout here - I altered the shortcut in Visual Studio Code for Save All, since it's maybe my most-used shortcut combination.&lt;br /&gt;
&lt;br /&gt;
If you go to Manage -&amp;gt; Keyboard Shortcuts and type in &amp;quot;save all&amp;quot; in the search bar, you can click on that shortcut and type in on your keyboard what you'd prefer. I use Ctrl+Alt+S, but set it to whatever makes you happy.&amp;lt;/blockquote&amp;gt;Then, in RPFM, use MyMod -&amp;gt; Import. Again, I added a keyboard shortcut here through RPFM - I set Import/Export to Ctrl+Alt+I/E. You can get there through PackFile -&amp;gt; Preferences -&amp;gt; Shortcuts.&lt;br /&gt;
&lt;br /&gt;
Import '''pulls in all the stuff from your MyMod folder into your pack''', while '''export does the opposite'''. I use these all the time, since I externally edit Lua files but internally edit database tables. You'll want to keep in mind where you're working, because if you edit a Lua file externally, and then a table file internally, without adding the changes from one to the other, you may end up overwriting some of your work. Because of that, I will only ever work in one sphere, then use Import/Export to make sure the folder and my .pack line up, and then edit in the other sphere.&lt;br /&gt;
&lt;br /&gt;
Save in RPFM, and use PackFile -&amp;gt; Install to move your .pack to the game folder. Tick it in your mod manager of choice, and load up a fresh campaign!&lt;br /&gt;
&lt;br /&gt;
=== Log File ===&lt;br /&gt;
The game-created log files will spit out in your game's folder - ie., steam/steamapps/common/Total War WARHAMMER III/. They are created as &amp;quot;script_log_DDMMYY_HHMM.txt&amp;quot;. So if I made one right now, it'd be &amp;quot;script_log_100623_1320.txt&amp;quot;, if you were wondering when I wrote this exact line.&lt;br /&gt;
&lt;br /&gt;
The game creates a new log file every time we enter the main menu, every time we enter a campaign, and every time we enter a battle - so if you only just started using script logs, there should be two or three in there depending on if you quit to main menu or to desktop after loading up your new campaign. Navigate to the latest one and open it up.&lt;br /&gt;
&lt;br /&gt;
Worth noting here, I have a file association set up to automatically open .txt files in Visual Studio Code, because I find it easier and quicker to navigate. If you right click the script log -&amp;gt; open with -&amp;gt; target Visual Studio Code, you can get it in that way. You can also simply grab the file from your file explorer and drag it into the main VSCode window, and it will be opened up within.&lt;br /&gt;
&lt;br /&gt;
There's going to be... a ''lot'' of stuff in here. A lot a lot. CA uses double quindrillion calls to `out()` throughout the game. We'll actually find that it's pretty cumbersome to navigate, and later on we'll create our '''own custom log files!''' But for now, let's navigate this chonker.&lt;br /&gt;
&lt;br /&gt;
=== Find Your Text ===&lt;br /&gt;
&amp;lt;small&amp;gt;''Sounds kinda like a platitude you'd find on a pillow in Kohl's.''&amp;lt;/small&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In our opened new script log, we should search for the words &amp;quot;Hello World!&amp;quot;. We can either do that using the Search tab we have set up, or clicking into the script log in the main window and using Ctrl+F.&lt;br /&gt;
[[File:First script 10.png|none|thumb|911x911px|Our first trigger of stuff in the game!Hey, did you put a naughty word instead of &amp;quot;Hello World!&amp;quot;? You lil nasty gremlin.]]&lt;br /&gt;
WE FUCKING DID IT HELL YES.&lt;br /&gt;
&lt;br /&gt;
And that's it, you're ready to script on your own!&lt;br /&gt;
&lt;br /&gt;
Bye!&lt;br /&gt;
&lt;br /&gt;
== Timin' 'n Stuff ==&lt;br /&gt;
 You'll probably maybe notice, this text is triggered very, very early on. While it's maybe ~1000 lines of text in, it's only 1.8s seconds (at least, for me, with no other mods enabled) after the script log is created. This is earlier than it might sound. At this time, the game is still going through its loading procedures - this text was triggered before the loading bar even got to 20%!&lt;br /&gt;
Because of how early this is, the game '''is not ready to be accessed yet'''. The game doesn't yet know what factions own what regions, what turn it is, who the player is controlling, or anything like that. The game doesn't have a map object, you can't trigger a new battle, nothin'.&lt;br /&gt;
&lt;br /&gt;
What we need to do for our next step is '''learn how to listen''' and '''wait'''. Some of the most valuable things we can do in programming are listening and waiting for the right time.&lt;br /&gt;
&lt;br /&gt;
=== Events ===&lt;br /&gt;
'''''NOTE:''''' ''Not to be confused with the &amp;quot;Events&amp;quot; in-game, the messages and such that hang out with missions.''&lt;br /&gt;
&lt;br /&gt;
The game has a great deal of &amp;quot;events&amp;quot; that can be triggered. Events are a way for scripts to learn some information about things happening in the game - there are events that will inform us when a new turn has started, when a region has been destroyed, when a battle has ended, when a ritual has been completed, when a mission has been failed, among many many many more. We can even define our own - more on that later!&lt;br /&gt;
&lt;br /&gt;
The first event we care about is one of the most important - FirstTickAfterWorldCreated. This event is triggered immediately after the game is ready to access - about 80% of the way through the loading bar before the game is interactable for the user.&lt;br /&gt;
&lt;br /&gt;
Once this event happens, we can do things like ask the game what factions exist, what turn it is, where we are, who we are, etc. Before the world is created, we can only do a bare minimum of setting things up in advance.&lt;br /&gt;
&lt;br /&gt;
=== Flying the Time ===&lt;br /&gt;
To achieve our first goal - spitting out some information about our player faction - we're going to use a first tick callback and trigger our very own function!&lt;br /&gt;
&lt;br /&gt;
A first tick callback is a way to '''ask the game to run code on FirstTickAfterWorldCreated'''. Most of your mods will probably involve a first-tick-callback. We use them in the following format:&lt;br /&gt;
 cm:add_first_tick_callback(function_to_call)&lt;br /&gt;
But first, we have to create our own function. To do that, we use the following:&lt;br /&gt;
 local function my_function_name()&lt;br /&gt;
 -- do stuff&lt;br /&gt;
 end&lt;br /&gt;
where &amp;quot;my_function_name&amp;quot; can be anything you want. In this situation, I'm going to call the function &amp;quot;init&amp;quot;, short for &amp;quot;initialization&amp;quot;, because this is the startpoint of my entire script. Some people also prefer &amp;quot;main&amp;quot;. Whatever you want really, just make it clear for yourself and anyone else.&lt;br /&gt;
&lt;br /&gt;
''Eagle-eyed readers will notice that the two dashes they wrote in VSCode will be greyed out; these are called &amp;quot;comments&amp;quot;. These are incredibly useful to leave notes to ourselves and other people reading our scripts, to inform yourself and others of what's going on and how things work in our code.''&lt;br /&gt;
&lt;br /&gt;
To safely confirm that we're calling our new function at the right time, we're going to run our function, trigger another call to out(), and see if it works!&lt;br /&gt;
[[File:First script 11.png|thumb|418x418px]]&lt;br /&gt;
&lt;br /&gt;
=== Getting Our Info ===&lt;br /&gt;
With our first tick callback loading up properly, let's hop in and try to get some information about our played faction!&lt;br /&gt;
&lt;br /&gt;
In the beginning of our init() function, we need to define a fresh new &amp;lt;u&amp;gt;variable&amp;lt;/u&amp;gt; which will allow us to hold the faction &amp;quot;object&amp;quot; in memory. A variable is a piece of memory that your computer is going to set aside to hold some data for us - a variable can be a number, text, a function, or game objects like the faction.&lt;br /&gt;
&lt;br /&gt;
We'll get it using the get_local_player() function, which we can find in the scripting documentation: https://chadvandy.github.io/tw_modding_resources/WH3/campaign/campaign_manager.html#function:campaign_manager:get_local_faction&lt;br /&gt;
&lt;br /&gt;
We'll be learning a lot about how to use and read the script documentation going forward.&lt;br /&gt;
&lt;br /&gt;
In our init() function, we need to add the following line of code:&lt;br /&gt;
 local player_faction = cm:get_local_faction()&lt;br /&gt;
Where player_faction is the name of our new variable. It can be anything you want, much like init(), but it should '''make sense''' and '''be clear to read'''. It needs to be all one contiguous word, with only text, underscores, and non-leading numbers allowed (ie. my_faction_1 is allowed, 1_my_faction is not).&lt;br /&gt;
&lt;br /&gt;
Visual Studio Code should automate it for you, but make sure that it's after the init() keyword, is one line after the out() call, is before the `end` keyword, and is one tab over. I like to space my code out thought-by-thought, so this will be a bit lower than my out() code.&lt;br /&gt;
[[File:First script 12.png|none|thumb]]&lt;br /&gt;
The way we get information about this game object will be to ask it questions, using functions, or in this case '''methods'''.&lt;br /&gt;
&lt;br /&gt;
The first thing we want to ask is, hey, what's the faction's name please?&lt;br /&gt;
&lt;br /&gt;
To ask the game object questions, we need to use the variable name followed by the : sign. Our VSCode plugin will then, thankfully, list us with a great deal of suggestions that we can use. We can also reference [https://chadvandy.github.io/tw_modding_resources/WH3/scripting_doc.html#FACTION_SCRIPT_INTERFACE the scripting documentation for game objects].&lt;br /&gt;
&lt;br /&gt;
Thankfully, what we want isn't too far away:&lt;br /&gt;
[[File:First script 13.png|none|thumb|946x946px|The autofill will show us the description of this method, and what it returns - in this case, it returns a &amp;quot;string&amp;quot;, as we see after the -&amp;gt; line.]]&lt;br /&gt;
Whenever we call a function, if the function gives us something back, we have to assign it to a variable or it will go away and vanish into the ether, with no memory on your PC being used to &amp;quot;hold&amp;quot; onto it. Do that with something simple:&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
local name = player_faction:name()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;I'll keep harping on it, but you can change `local name` to whatever you want - `local key`, `local bits`, `local ostrich_on_fire`, whatever.&lt;br /&gt;
&lt;br /&gt;
'''''NOTE:''''' ''It keeps saying name, but its actually referring to the faction's &amp;quot;key&amp;quot; as we'll see in a second - the &amp;quot;code name&amp;quot; is has in factions_tables.''&lt;br /&gt;
&lt;br /&gt;
Now that we have the information in our code, we can put it all together and print that out to the log file:&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
out( &amp;quot;Hello World!&amp;quot; ) &lt;br /&gt;
&lt;br /&gt;
local function init()&lt;br /&gt;
    out(&amp;quot;New game triggered!&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
    local player_faction = cm:get_local_faction()&lt;br /&gt;
    local key = player_faction:name()&lt;br /&gt;
&lt;br /&gt;
    out(&amp;quot;Playing as &amp;quot; .. key)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
cm:add_first_tick_callback(init)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Learnin' Info ==&lt;br /&gt;
We've got something good going on, with information being spat out from the game telling us who we're playing as after the game has &amp;quot;begun&amp;quot; proper. This might seem like we've barely done anything, but this is the starting block that every game-altering script needs. We're off to a great start!&lt;br /&gt;
&lt;br /&gt;
[[Category:Lua Tutorials]]&lt;/div&gt;</summary>
		<author><name>Grimmys</name></author>
	</entry>
	<entry>
		<id>https://tw-modding.com/index.php?title=Lua:Debugging&amp;diff=1219</id>
		<title>Lua:Debugging</title>
		<link rel="alternate" type="text/html" href="https://tw-modding.com/index.php?title=Lua:Debugging&amp;diff=1219"/>
		<updated>2024-03-11T19:29:13Z</updated>

		<summary type="html">&lt;p&gt;Grimmys: Add LUA tutorial category&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;As you write Lua, you’ll find that errors aren’t uncommon. Something will go wrong, code is ignored, and you’re a sad panda. Thankfully, the language has a rigorous self-checking system implemented that can be used to catch any errors within lines and print out the exact line that caused an error. On top of this, it’s also important to include your own error checking systems as your write your own custom scripts to make sure your stuff is running properly!&lt;br /&gt;
&lt;br /&gt;
==== Outputs! ====&lt;br /&gt;
As we’ve covered a bunch in this tutorial series, we can get some CA script logs using the script debug activator mod, and we can add stuff to that output log using the function &amp;lt;code&amp;gt;out()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
A really remedial use of this function is to check exactly where in our script something is breaking. Your script just ISN’T working, and you don’t know which exact line isn’t working. Let’s take an example (it’s actually perfectly valid code, but let’s pretend it isn’t):&lt;br /&gt;
     &amp;lt;code&amp;gt;function example()&lt;br /&gt;
         local empire = cm:get_faction(&amp;quot;wh_main_emp_empire&amp;quot;)&lt;br /&gt;
         local character = empire:faction_leader()&lt;br /&gt;
         local region = character:region():name()&lt;br /&gt;
         cm:apply_effect_bundle_to_region(&amp;quot;testing_bundle&amp;quot;, region, 10)&lt;br /&gt;
     end&amp;lt;/code&amp;gt; &lt;br /&gt;
Say these lines haven’t been running for you, and you don’t know why! A very simple, very easy way to test is to edit it to the following, run the game, check the script logs and see where the block failed:&lt;br /&gt;
     &amp;lt;code&amp;gt;function example()&lt;br /&gt;
         out(&amp;quot;VANDY: example() called!&amp;quot;)&lt;br /&gt;
         local empire = cm:get_faction(&amp;quot;wh_main_emp_empire&amp;quot;)&lt;br /&gt;
         out(&amp;quot;VANDY: empire called!&amp;quot;)&lt;br /&gt;
         local character = empire:faction_leader()&lt;br /&gt;
         out(&amp;quot;VANDY: character called!&amp;quot;)&lt;br /&gt;
         local region = character:region():name()&lt;br /&gt;
         out(&amp;quot;VANDY: region called!&amp;quot;)&lt;br /&gt;
         cm:apply_effect_bundle_to_region(&amp;quot;testing_bundle&amp;quot;, region, 10)&lt;br /&gt;
         out(&amp;quot;VANDY: apply effect bundle called!&amp;quot;)&lt;br /&gt;
     end&amp;lt;/code&amp;gt; &lt;br /&gt;
You’ll notice a couple of things here. I called out() for every function that I called, for every line of “do something”. This can be overkill, but in this situation, I want to see the exact very line where something went wrong, and the outputs will stop being called after this block is aborted due to failed code. I also added an easy-to-find tag to all my outputs, “VANDY”, so I can quickly Ctrl+F them within the script_log.txt file.&lt;br /&gt;
&lt;br /&gt;
This is a super simple, super easy, and super handy way to quickly debug failing code and find the EXACT line that isn’t working for you. But… it’s a little clunky. I mean, come on, you have to scroll through thousands of lines of CA outputs just to find your five lines? What are you, a CA employee? Thankfully, with just a few more lines, we can make our own output files.&lt;br /&gt;
&lt;br /&gt;
==== Our Own Output Files ====&lt;br /&gt;
Yep! Now with 100% less fat!&lt;br /&gt;
&lt;br /&gt;
I use custom output files all the time, for all of my mods. It takes no time at all to set one up, it doesn’t require any editing of CA scripts, and you can easily set it up so you have your own “dev mode”, which will be just like how CA does it – a boolean variable set to true when you want to have files printed, and false when you don’t.&lt;br /&gt;
&lt;br /&gt;
Your local output function will look something like this. I’ll display it first, then we can start to take it apart.&lt;br /&gt;
 &amp;lt;code&amp;gt;local function Log(text)&lt;br /&gt;
     if type(text) == &amp;quot;string&amp;quot; then&lt;br /&gt;
         local file = io.open(&amp;quot;name_of_file.txt&amp;quot;, &amp;quot;a&amp;quot;)&lt;br /&gt;
         file:write(text..&amp;quot;\n&amp;quot;)&lt;br /&gt;
         file:close()&lt;br /&gt;
     end&lt;br /&gt;
 end&amp;lt;/code&amp;gt;&lt;br /&gt;
And boom. Just like that, anytime within the local env that you call Log(), it will automatically open up a file called “name_of_file.txt”, located in the same folder as the CA script log, and automatically write in your text. Pretty awesome, huh? Now, let’s break it down a little bit.&lt;br /&gt;
&lt;br /&gt;
That first line here, we call a basic Lua library function, which is &amp;lt;code&amp;gt;type()&amp;lt;/code&amp;gt;. This returns the type, obviously, of a variable. This isn’t needed here, as I could more-smartly use a &amp;lt;code&amp;gt;tostring()&amp;lt;/code&amp;gt; call, but I’m doing some playful foreshadowing at better debugging practices. This line runs, checks to make sure the “text” parameter is a valid string, and if it is, it continues!&lt;br /&gt;
&lt;br /&gt;
Following that, we call the Lua &amp;lt;code&amp;gt;io&amp;lt;/code&amp;gt; library, which stands for “Input/Output”, a simple file manipulation library that gives us power over text editing files. io.open is used to open a file – which is named whatever the first arg is – and then the second argument determines the type of operation. We have several options here, which can be found in this handy page. We are using “a”, which calls the append operation. Basically, we’re gonna add on to our file every time we call Log().&lt;br /&gt;
&lt;br /&gt;
Next are two simple and easy function. &amp;lt;code&amp;gt;file:write()&amp;lt;/code&amp;gt;, which just takes a string, does the actual typing for us like a sweetie; &amp;lt;code&amp;gt;file:close()&amp;lt;/code&amp;gt; operates on self and closes the file.&lt;br /&gt;
&lt;br /&gt;
And, just like that, we have our own, personalized log file. Whenever Log() is called, it’ll print that line for us on “name_of_file.txt”, and next time we call it it’ll be set on the very next line. Very cool. Let’s take a look at this in practice and take a look at some simple code and how we can de-clutter our output log by using our very own. Yay.&lt;br /&gt;
&lt;br /&gt;
[[Category:Lua Tutorials]]&lt;/div&gt;</summary>
		<author><name>Grimmys</name></author>
	</entry>
	<entry>
		<id>https://tw-modding.com/index.php?title=Lua:Advanced_Conditionals&amp;diff=1218</id>
		<title>Lua:Advanced Conditionals</title>
		<link rel="alternate" type="text/html" href="https://tw-modding.com/index.php?title=Lua:Advanced_Conditionals&amp;diff=1218"/>
		<updated>2024-03-11T19:28:27Z</updated>

		<summary type="html">&lt;p&gt;Grimmys: Add LUA tutorial category&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
==== By DrunkFlamingo ====&lt;br /&gt;
I’m guest writing this to clear up some common confusions and problems I see with people writing conditional statements. As Vandy made clear, conditionals are what your script is built with, but as you work more with Lua you’ll begin to see that tables are what makes the language work. Combining the two is the key to writing better script.&lt;br /&gt;
&lt;br /&gt;
==== A Quick Refresher ====&lt;br /&gt;
A conditional statement is any statement of Lua that is either true or false. For our purposes, conditionals tend to look like this:&lt;br /&gt;
     &amp;lt;code&amp;gt;return context:faction():name() == &amp;quot;wh_main_emp_empire&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
Or like this:&lt;br /&gt;
     &amp;lt;code&amp;gt;if context:faction():name() == &amp;quot;wh_main_emp_empire&amp;quot; then&amp;lt;/code&amp;gt;&lt;br /&gt;
In either case, it’s either true or it isn’t!&lt;br /&gt;
&lt;br /&gt;
But those are pretty basic, and you can probably write those by the time you get here. The purpose of this chapter is to walk through doing some more advanced things with conditionals. Starting with the most common mistake I see being made by new scripters: how to check a large number of individually valid items. You see this when doing tasks like:&lt;br /&gt;
&lt;br /&gt;
# singling out groups of factions&lt;br /&gt;
# singling out lord types&lt;br /&gt;
# singling out specific regions&lt;br /&gt;
&lt;br /&gt;
==== Using Tables and Loops to match many things ====&lt;br /&gt;
Let’s take a pretty simple example. Imagine we have a scripted mechanic. This mechanic only applies to human players, and it is initiated by calling the function “my_mechanic” and giving it the faction key we want the mechanic to happen for.&lt;br /&gt;
&lt;br /&gt;
A huge mistake I see in a lot of new scripters code is stuff like this:&lt;br /&gt;
     &amp;lt;code&amp;gt;if cm:get_faction(&amp;quot;wh_main_emp_empire&amp;quot;):is_human() then&lt;br /&gt;
         my_mechanic(&amp;quot;wh_main_emp_empire&amp;quot;)&lt;br /&gt;
     elseif cm:get_faction(&amp;quot;wh_main_brt_bretonnia&amp;quot;):is_human() then&lt;br /&gt;
         my_mechanic(&amp;quot;wh_main_brt_bretonnia&amp;quot;)&lt;br /&gt;
     else&lt;br /&gt;
         -- this goes on for quite a while&lt;br /&gt;
     end&amp;lt;/code&amp;gt;&lt;br /&gt;
This is bad for a few reasons. Its bad for performance, but that doesn’t matter as much as the fact that it requires a crapton of typing on your part. You’ve written 5 lines for only two factions! To get every good guy playable that’s gonna be more than 30 lines. It also means if you want to check whether factions have a mechanic, you can’t reuse any of this code. Finally, it means your code is a pain for other people to read.&lt;br /&gt;
&lt;br /&gt;
So how do we solve this? The simplest and best way is to use a table to check them. In this scenario, we’re going to first introduce one that CA defines for us.&lt;br /&gt;
     &amp;lt;code&amp;gt;local humans = cm:get_human_factions()&amp;lt;/code&amp;gt;&lt;br /&gt;
This returns a list of the humans in the game. That sounds much better, but let’s write our code.&lt;br /&gt;
     &amp;lt;code&amp;gt;for i = 1, #humans do&lt;br /&gt;
         local current_human = humans[i]&lt;br /&gt;
 &lt;br /&gt;
         if current_human == &amp;quot;wh_main_emp_empire&amp;quot; then&lt;br /&gt;
             my_mechanic(&amp;quot;wh_main_emp_empire&amp;quot;)&lt;br /&gt;
         elseif current_human == &amp;quot;wh_main_brt_bretonnia&amp;quot; then&lt;br /&gt;
             my_mechanic(&amp;quot;wh_main_brt_bretonnia&amp;quot;)&lt;br /&gt;
         else&lt;br /&gt;
             -- blah blah blah&lt;br /&gt;
         end&lt;br /&gt;
     end&amp;lt;/code&amp;gt;&lt;br /&gt;
That’s not any better. We’re on the right track, but we haven’t actually eliminated that many checks.&lt;br /&gt;
&lt;br /&gt;
Remember that in our use case we need to know three things:&lt;br /&gt;
&lt;br /&gt;
# We need to know if a faction is human, this changes based on the game.&lt;br /&gt;
# We need to know if a faction can use our mechanic at all. We define this ourselves.&lt;br /&gt;
# We need to know the exact faction key by the end so we can start our mechanic.&lt;br /&gt;
&lt;br /&gt;
So how can we improve this code? Well, we started by introducing the humans table to deal with condition #1, but condition #2 is still causing us grief. The answer, of course, is another table.&lt;br /&gt;
&lt;br /&gt;
We will start with what that table looks like:&lt;br /&gt;
     &amp;lt;code&amp;gt;local my_mechanic_factions = {}&amp;lt;/code&amp;gt;&lt;br /&gt;
local my_mechanic_factions = {} So what data do we need in this table? Probably the faction keys. When I said table, you might have wanted to try something like this:&lt;br /&gt;
     &amp;lt;code&amp;gt;local my_mechanic_factions = {&lt;br /&gt;
         &amp;quot;wh_main_emp_empire&amp;quot;,&lt;br /&gt;
         &amp;quot;wh_main_emp_brt_bretonnia&amp;quot;&lt;br /&gt;
     }&amp;lt;/code&amp;gt;&lt;br /&gt;
But now let’s try to write a conditional statement using that. We’ll probably end up with something like this:&lt;br /&gt;
     &amp;lt;code&amp;gt;local humans = cm:get_human_factions()&lt;br /&gt;
     for i = 1, #humans do&lt;br /&gt;
         local current_human = humans[i]&lt;br /&gt;
         for j = 1, #my_mechanic_factions do&lt;br /&gt;
             local current_faction_key = my_mechanic_factions[j]&lt;br /&gt;
             if current_human == current_faction_key then&lt;br /&gt;
                 my_mechanic(current_faction_key)&lt;br /&gt;
             end&lt;br /&gt;
         end&lt;br /&gt;
     end&amp;lt;/code&amp;gt;&lt;br /&gt;
That’s much better than before. It saves us a lot of typing to add more factions, but it isn’t very efficient. If we add, lets say, 25 factions to our mechanic list, then we’re looping 25 times in a single player game and 50 times in a coop game. It probably won’t be too noticeable, but we can do better.&lt;br /&gt;
&lt;br /&gt;
==== The Right Answer ====&lt;br /&gt;
Instead of using an array table (one that is a list of items with integer keys; if you use Kailua you’ll know this as a vector), lets try using a map table (one that associates a key and a value which we set explicitly) instead. These kinds of tables are extremely powerful when writing conditionals, so lets see why.&lt;br /&gt;
     &amp;lt;code&amp;gt;local my_mechanic_factions = {&lt;br /&gt;
         [&amp;quot;wh_main_emp_empire&amp;quot;] = true,&lt;br /&gt;
         ]&amp;quot;wh_main_emp_brt_bretonnia&amp;quot;] = true&lt;br /&gt;
     }&amp;lt;/code&amp;gt;&lt;br /&gt;
How can that possibly help? Well, let’s think about our condition #2. We want the smallest possible thing which can take a faction as an input and give back whether they are valid for our mechanic. These factions are true in relation to the mechanic. Any other faction will return “nil” if we ask for its entry in this table, because no entry for it exists. Lets see how that works in action:&lt;br /&gt;
     &amp;lt;code&amp;gt;local humans = cm:get_human_factions()&lt;br /&gt;
     for i = 1, #humans do&lt;br /&gt;
         local current_human = humans[i]&lt;br /&gt;
         if my_mechanic_factions[current_human] then&lt;br /&gt;
             my_mechanic(current_human)&lt;br /&gt;
         end&lt;br /&gt;
     end&amp;lt;/code&amp;gt;&lt;br /&gt;
And there we go, finally something efficient, small, easy to modify, and easy to read. If the faction isn’t in our table, then the “if” statement will be nil, which doesn’t proceed. If the faction is there, we will proceed and fire off the mechanic. Now, no matter how many factions we want our mechanic to use, we’ll only be looping once in a single player game, and twice in an MP game. For a mechanic which launches once or twice, that’s the ideal number.&lt;br /&gt;
&lt;br /&gt;
We can also reuse this code elsewhere. Now, if we want to check whether a faction fits a mechanic or not at any time, it’s only a single check away. We could even formalize this into a function:&lt;br /&gt;
     &amp;lt;code&amp;gt;function does_faction_have_my_mechanic(faction_key)&lt;br /&gt;
         return (my_mechanic_factions[faction_key] and cm:get_faction(faction_key):is_human() &lt;br /&gt;
     end&amp;lt;/code&amp;gt;&lt;br /&gt;
And check whether any given faction fits our criteria from any place in our code.&lt;br /&gt;
&lt;br /&gt;
[[Category:Lua Tutorials]]&lt;/div&gt;</summary>
		<author><name>Grimmys</name></author>
	</entry>
	<entry>
		<id>https://tw-modding.com/index.php?title=Lua:Commands,_Interfaces_%26_Listeners&amp;diff=1217</id>
		<title>Lua:Commands, Interfaces &amp; Listeners</title>
		<link rel="alternate" type="text/html" href="https://tw-modding.com/index.php?title=Lua:Commands,_Interfaces_%26_Listeners&amp;diff=1217"/>
		<updated>2024-03-11T19:27:34Z</updated>

		<summary type="html">&lt;p&gt;Grimmys: Add LUA tutorial category&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;For today’s lesson, the subject is three-fold: commands, interfaces, and listeners. The three of these are our introduction to messing with the game itself, and making real change. Every worthwhile Lua mod on the market has these in it! Anything else just concatenates strings or applies arithmetic or some nonsense.&lt;br /&gt;
&lt;br /&gt;
==== Commands ====&lt;br /&gt;
A command, at its bearest-bones, is a ''CA-defined Lua function'' that does stuff that we can’t see. They function (hah) identically to the functions we’ve already covered; some have parameters, some have return values, they all do stuff. Whenever we use commands, we’re treating them like ''function calls''; they’re a statement. Commands are used to communicate between the Lua environment and the actual Total War Engine – the base C++ code that defines the majority of the game.&lt;br /&gt;
&lt;br /&gt;
Through these commands, we can script a whole lot of stuff! From character spawns, to new effects applied to characters and factions and armies, to quest battles, to unlocking rites, and so on.&lt;br /&gt;
&lt;br /&gt;
In big part, commands make or break what can be done with scripts. Commands are the driving force of most any script. At this point, though, you might be asking – “how the HECK do I find out what the commands are?” And that, my friend, is why you’re reading this lesson. Or maybe you got lost when you were just trying to find funny videos about cats. Either way, next paragraph!&lt;br /&gt;
&lt;br /&gt;
So, once more in the “Tools &amp;amp; Resources” page on this site, there’s a section within called “Scripting Resources”. We’ll look at, first, the “Scripting Doc (CM Functions)” file. Open it up!&lt;br /&gt;
&lt;br /&gt;
Now, before we go on, one thing MUST be covered. EVERY command in this document needs to have a prefix of &amp;lt;code&amp;gt;cm:&amp;lt;/code&amp;gt;. Those two letters stand for “campaign_manager”, and it’s the big object that holds most all information we could want within the campaign game-mode.&lt;br /&gt;
&lt;br /&gt;
''NOTE:'' ''The campaign manager is ONLY usable in the campaign game-mode!''&lt;br /&gt;
&lt;br /&gt;
In this document, let’s take a look at two example commands to breakdown.&lt;br /&gt;
     &amp;lt;code&amp;gt;Command: 	transfer_region_to_faction	&lt;br /&gt;
     Description: 	Transfer a region ownership to a faction.	&lt;br /&gt;
     Usage: 		transfer_region_to_faction(&amp;quot;region&amp;quot;, &amp;quot;faction&amp;quot;)&amp;lt;/code&amp;gt;&lt;br /&gt;
This is relatively straightforward. The &amp;lt;code&amp;gt;Command:&amp;lt;/code&amp;gt; line tells you what to affix to &amp;lt;code&amp;gt;cm:&amp;lt;/code&amp;gt;, so this would be &amp;lt;code&amp;gt;cm:transfer_region_to_faction&amp;lt;/code&amp;gt;. Since it’s a ''function call'', which we learned about just last episode and you wouldn’t dare forget so soon, we add the brackets to it: &amp;lt;code&amp;gt;cm:transfer_region_to_faction()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
We can see in &amp;lt;code&amp;gt;Usage:&amp;lt;/code&amp;gt; that it takes TWO parameters. They seem to be strings, one of which says “region”, the other “faction”. It’s easy enough to tell that means “the region key in string”, and “the faction key in string”. So, overall, the command call would look like this: &amp;lt;code&amp;gt;cm:transfer_region_to_faction(&amp;quot;wh2_main_vor_phoenix_gate&amp;quot;, &amp;quot;wh2_main_hef_eataine&amp;quot;)&amp;lt;/code&amp;gt;.&lt;br /&gt;
     &amp;lt;code&amp;gt;Command: 	create_force	&lt;br /&gt;
     Description: 	create a navy or army at a position.  Final parameter specified whether the command goes via the command queue	&lt;br /&gt;
     Usage: 		create_force(&amp;quot;faction_key&amp;quot;, &amp;quot;unit_list&amp;quot;, &amp;quot;region_key&amp;quot;, x_position, y_position, exclude_named_characters, &amp;quot;id&amp;quot;, true)&amp;lt;/code&amp;gt;&lt;br /&gt;
The same applies here. &amp;lt;code&amp;gt;cm:create_force()&amp;lt;/code&amp;gt;, with a bunch of parameters. However, there’s one caveat here – using cm:create_force() with those parameters will crash-bang-boom the game! Let’s back up and talk about why.&lt;br /&gt;
&lt;br /&gt;
The commands in this document are commands to the ''game interface'', something that you really should never, ever touch directly, for fear of crashing the game if you mess something up. These functions –&amp;lt;code&amp;gt;cm:create_force()&amp;lt;/code&amp;gt; – are ''wrappers'', over that base command, so we don’t have to directly touch the game interface. Using the CA functions will quickly error-check our code, and prevent any such crashes (when wrappers for those commands exist!). But what do I mean? Let’s open up our script dump and go to script/_lib/lib_campaign_manager.lua, and search for &amp;lt;code&amp;gt;create_force(&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
We’ll see a line that looks similar to what I have already shown you – &amp;lt;code&amp;gt;function campaign_manager:create_force(faction_key, unit_list, region_key, x, y, exclude_named_characters, success_callback)&amp;lt;/code&amp;gt;. This is the ''wrapper''. Within this function, lower down at the bottom, we can see the call to the game interface – &amp;lt;code&amp;gt;self.game_interface:create_force(faction_key, unit_list, region_key, x, y, id, exclude_named_characters, true);&amp;lt;/code&amp;gt;. This looks a lot closer to the definition CA has in their documentation, and I belive it was the definition they were trying to go with. Not sure though, it’s still a ''little'' wrong!&lt;br /&gt;
&lt;br /&gt;
In these situations, it pays to be careful. I advise you to use the CM Scripting Doc cautiously. It isn’t fool-proof, and every change that CA has made over the years hasn’t been recorded in there – there are commands listed that haven’t been functional since Total War: Empire. This is when I point you back to the setup lesson, if you haven’t done that, and tell you to go do it. There are three hyper important tricks in there that will help you understand what to do in a situation like this:&lt;br /&gt;
&lt;br /&gt;
# Check the lib files! Most functions in this document will be in &amp;lt;code&amp;gt;lib_campaign_manager.lua&amp;lt;/code&amp;gt;. Bonus, as you could see with the above example, CA gives a quick explanation for what the function does and what the types are, and where they are found. This is always my first check. Do note that not every campaign_manager function is listed in that file; there are a bunch that are defined in the game-engine, have no wrapper in this lib file, and aren’t documented.&lt;br /&gt;
# Use the script dump! All you have to do is use “Find In Files … ” within Notepad++, type in the name of the command (ie. &amp;lt;code&amp;gt;create_force&amp;lt;/code&amp;gt;), and wait for it to search all the files. It will come up with some hits, and you can read through CA scripts to see what they do and how it’s used. This is really handy for any undocumented functions, or if you’d like to get ideas on how a command is used. I do this all the time!&lt;br /&gt;
# Use Kailua! It might take some time to fully understand the &amp;lt;code&amp;gt;ca_types.lua&amp;lt;/code&amp;gt; file that we’ve made for TW:WH2, but it should be pretty easy to ''read'' it if you want to know the parameters of a function. Open &amp;lt;code&amp;gt;ca_types.lua&amp;lt;/code&amp;gt;, within VSCode (or whatever), search for the name of the command again (&amp;lt;code&amp;gt;create_force&amp;lt;/code&amp;gt;), and it will show you some neat stuff. I’ll go over what it looks like now, just so you know:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;code&amp;gt;--# assume CM.create_force: method(&lt;br /&gt;
 --#     faction_key: string,&lt;br /&gt;
 --#     unitstring: string,&lt;br /&gt;
 --#     region_key: string,&lt;br /&gt;
 --#     xPos: number,&lt;br /&gt;
 --#     yPos: number,&lt;br /&gt;
 --#     exclude_named_chars: boolean,&lt;br /&gt;
 --#     callback: (function(CA_CQI))?&lt;br /&gt;
 --# )&amp;lt;/code&amp;gt;&lt;br /&gt;
Each of these lines is a ''parameter'', and it’s split into a name and a type. The name is just a description of what should go there – a faction key, a region key, etc., – and the type defines, of course, the type!&lt;br /&gt;
&lt;br /&gt;
There’s a third example I’d like to go into, which is return types via the CA commands. It works just like regular return values (seen from the last lesson), but sometimes the return value is vague, and it’s really hard to read using CA’s scripting doc. Again, utilize the script dump and Kailua. In Kailua, it’ll look a little different – let’s grab an example of a command with a return value.&lt;br /&gt;
 &amp;lt;code&amp;gt;--# assume CM.get_saved_value: method(valueKey: string) --&amp;gt; WHATEVER&amp;lt;/code&amp;gt;&lt;br /&gt;
''NOTE: &amp;lt;code&amp;gt;WHATEVER&amp;lt;/code&amp;gt; is a beautiful keyword in Kailua that lets you not define the type of a value, instead of saying “return a number” it says “return literally whatever”''&lt;br /&gt;
&lt;br /&gt;
Some functions in the ca_types files have a &amp;lt;code&amp;gt;--&amp;gt;&amp;lt;/code&amp;gt; to their end; on the right side of that arrow is the return value. Easy enough to read!&lt;br /&gt;
&lt;br /&gt;
And that’s my explanation of CA commands! Hope you had as much fun as I did.&lt;br /&gt;
&lt;br /&gt;
==== Interfaces ====&lt;br /&gt;
Similar to commands, script interfaces are a way to access some game data with some Lua. We looked at them previously – in the second lesson, we used a &amp;lt;code&amp;gt;FACTION_SCRIPT_INTERFACE&amp;lt;/code&amp;gt;, which we got by using the command &amp;lt;code&amp;gt;cm:get_faction(&amp;quot;faction_key&amp;quot;)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Script interfaces are objects that we can apply some functions ''to'' (functions applied to an object are known as methods, but we’ll talk about that terminology later). For example, let’s build up something small:&lt;br /&gt;
     &amp;lt;code&amp;gt;local faction_name = &amp;quot;wh2_main_hef_eataine&amp;quot;&lt;br /&gt;
     local faction = cm:get_faction(faction_name)&lt;br /&gt;
     if faction:is_dead() == true then&lt;br /&gt;
         -- sadface&lt;br /&gt;
     end&amp;lt;/code&amp;gt;&lt;br /&gt;
In this example, &amp;lt;code&amp;gt;cm:get_faction()&amp;lt;/code&amp;gt; has a ''return value'' of a &amp;lt;code&amp;gt;FACTION_SCRIPT_INTERFACE&amp;lt;/code&amp;gt;, which we assign to the local variable &amp;lt;code&amp;gt;faction&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt;FACTION_SCRIPT_INTERFACES&amp;lt;/code&amp;gt; have a method called &amp;lt;code&amp;gt;is_dead()&amp;lt;/code&amp;gt;, which lets us read if the faction is, well… dead. But how did I know to use that? ''gasp''&lt;br /&gt;
&lt;br /&gt;
Also similar to commands, script interfaces are documented with a slightly-questionable CA file, though this one is typically waaaay more reliable, if a bit inconsistent with some naming. We can, again, grab it from the Tools &amp;amp; Resources page, this time under the title “Scripting Doc (Events &amp;amp; Interfaces). Our big focus for now is the latter half of that name – Interfaces – though we’ll be getting into events right in the next section below!&lt;br /&gt;
&lt;br /&gt;
Open your newest Scripting Doc, and search for &amp;lt;code&amp;gt;FACTION_SCRIPT_INTERFACE&amp;lt;/code&amp;gt;. It should be towards the top of the document, right near the word “Interfaces” in big boldage. Like this: Interfaces. Cool, found it? Click it!&lt;br /&gt;
&lt;br /&gt;
You should get a big, long list of blue links, followed by more clear definitions. A typical entry here would look similar to the follows (because the following ''is'' an entry):&lt;br /&gt;
 &amp;lt;code&amp;gt;Function: holds_entire_province&lt;br /&gt;
 Description: Does this faction hold the entire specified province? Also may include vassals&lt;br /&gt;
 Parameters: holds_entire_province(String province, bool include_vassals)&lt;br /&gt;
 Return: bool&amp;lt;/code&amp;gt;&lt;br /&gt;
As before, like the commands above were done with a prefix of &amp;lt;code&amp;gt;cm:&amp;lt;/code&amp;gt;, these interface functions are done with a prefix of that script interface. But it won’t just be &amp;lt;code&amp;gt;FACTION_SCRIPT_INTERFACE:holds_entire_province&amp;lt;/code&amp;gt;, that makes no sense! In our previous, Tyrion-based example, it would look like the following:&lt;br /&gt;
     &amp;lt;code&amp;gt;local faction_name = &amp;quot;wh2_main_hef_eataine&amp;quot;&lt;br /&gt;
     local faction = cm:get_faction(faction_name)&lt;br /&gt;
     if faction:holds_entire_province(&amp;quot;wh2_main_vor_phoenix_gate&amp;quot;, true) then&lt;br /&gt;
         -- do stuff!&lt;br /&gt;
     end&amp;lt;/code&amp;gt;&lt;br /&gt;
The second line – description – is quite obvious. It’s just a description. Read it, don’t read it, I don’t care.&lt;br /&gt;
&lt;br /&gt;
Third line: Parameters! We talked about this recently, you remember it right? It’ll be a type and a very brief stand-in name to explain what should go there. In this case, you can tell that it wants the key of the province, as a string, and a boolean that determines whether or not you’d like to include vassals in the check. Sometimes, they’ll just put the stand-in name in quotation marks to show that it should be a string.&lt;br /&gt;
&lt;br /&gt;
Return values are much the same. Sometimes there will be returns of other script interfaces, and that’s how you can start getting some fun stuff. With a &amp;lt;code&amp;gt;FACTION_SCRIPT_INTERFACE&amp;lt;/code&amp;gt;, you can use &amp;lt;code&amp;gt;character_list()&amp;lt;/code&amp;gt; to get a &amp;lt;code&amp;gt;CHARACTER_LIST_SCRIPT_INTERFACE&amp;lt;/code&amp;gt;, and then use &amp;lt;code&amp;gt;item_at()&amp;lt;/code&amp;gt; to get a &amp;lt;code&amp;gt;CHARACTER_SCRIPT_INTERFACE&amp;lt;/code&amp;gt;, and then use &amp;lt;code&amp;gt;get_forename()&amp;lt;/code&amp;gt; to get a string. That’ll look like:&lt;br /&gt;
     &amp;lt;code&amp;gt;local faction_name = &amp;quot;wh2_main_hef_eataine&amp;quot;&lt;br /&gt;
     local faction = cm:get_faction(faction_name)&lt;br /&gt;
     local character_list = faction:character_list() -- assign the CHARACTER_LIST_SCRIPT_INTERFACE to the variable &amp;quot;character_list&amp;quot;&lt;br /&gt;
     local character = character_list:item_at(0) -- assign the CHARACTER_SCRIPT_INTERFACE, at index &amp;quot;0&amp;quot;, to the variable &amp;quot;character&amp;quot;&lt;br /&gt;
     local forename = character:get_forename() -- assign the string for the character's forename to variable &amp;quot;forename&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
I will note that you don’t have to assign everything a local variable here. It can look, albeit much uglier and less safe, like this:&lt;br /&gt;
     &amp;lt;code&amp;gt;local faction_name = &amp;quot;wh2_main_hef_eataine&amp;quot;&lt;br /&gt;
     local forename = cm:get_faction(faction_name):character_list():item_at(0):get_forename()&amp;lt;/code&amp;gt;&lt;br /&gt;
But I do not recommend doing something like this, until you’re very comfortable with the language. I do it very, very, very rarely, only when it makes perfect sense to do it, and that’s lie-talk for “when I’m tired and it makes perfect sense to my tired brain”.&lt;br /&gt;
&lt;br /&gt;
Script interfaces are stupidly, stupidly powerful, and using all these smartly allows you to make some serious change within the game, and to read a lot more details, from “how many units are in this army” to “what level is this character” to “how many armies were in the last battle?” But, above all, these interfaces are used ''best'' and ''most powerfully'' when used in conjunction with listeners and events.&lt;br /&gt;
&lt;br /&gt;
What are listeners and events? Ah, well…&lt;br /&gt;
&lt;br /&gt;
==== Listeners and Events ====&lt;br /&gt;
A listener is an important script command that, simply, waits for something to happen – or, listens for something to happen – in the game, and then triggers something else. Using a listener, we can listen for an event such as the creation of an army, the occupation of a city, or even a battle, and then we use the information from that situation, check for something specific, and run our code if the event matches our criteria. For example: we may be looking for Mannfred to occupy Altdorf. In this case we’d have to use a listener to “listen” for a city being occupied, but we don’t want to listen for just any city being occupied. In our example, we have to listen for Altdorf being occupied, and for Mannfred doing the occupying. The listener will listen for every single time a city is occupied, and once those two conditions are met – ''Mannfred'' occupying ''Altdorf''… Clue, anyone? – then our listener will trigger some code. In layman’s code, our listener will ''do a thing!''&lt;br /&gt;
&lt;br /&gt;
Overall, it is a very valuable connection between Lua and game data, and any scripter should understand the in’s and out’s of a listener.&lt;br /&gt;
&lt;br /&gt;
Let’s break down the basics of a listener. Here is it, at its most basic form:&lt;br /&gt;
     &amp;lt;code&amp;gt;core:add_listener(&lt;br /&gt;
         &amp;quot;listener_name&amp;quot;,&lt;br /&gt;
         &amp;quot;event_name&amp;quot;,&lt;br /&gt;
         boolean1,&lt;br /&gt;
         function(context)&lt;br /&gt;
         end,&lt;br /&gt;
         boolean2&lt;br /&gt;
     )&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* “listener_name”: Can be whatever you want it to be! (Keep in mind if you share the same listener_name as another listener, and that name is called with core:remove_listener(“listener_name”), one of those listeners will be removed, and it’d be hard to tell which would be. Use unique names!)&lt;br /&gt;
* “event_name”: This must be one within a set of Events that CA defines. You can view this list here. We’ll cover this list more in depth later on.&lt;br /&gt;
* boolean1: This is the “conditional” boolean. If it is set to true, the function to execute will execute; if it is set to false, the function will not execute.&lt;br /&gt;
* function: This is the “callback” function, which only runs if the conditional boolean returns as true. Can be whatever valid function you want! Note that it MUST have the format of &amp;lt;code&amp;gt;function(context) --&amp;lt;nowiki&amp;gt;[[ do stuff ]]&amp;lt;/nowiki&amp;gt; end,&amp;lt;/code&amp;gt;&lt;br /&gt;
* boolean2: This is the “persistence” boolean. If it is set to true, the listener will continue listening. If it is set to false, the listener will be removed from the game data.&lt;br /&gt;
&lt;br /&gt;
=== CA Events ===&lt;br /&gt;
Let’s talk more in detail about the Events I mentioned.&lt;br /&gt;
&lt;br /&gt;
As previously clarified, Events are predefined objects that are used exclusively in tandem with Listeners. A full list of Events, and all of their methods, and all of the interfaces, can be found [https://chadvandy.github.io/tw_modding_resources/WH3/scripting_doc.html here]. Let’s go over how to use this document!&lt;br /&gt;
&lt;br /&gt;
At the top of the document is a long list of Events, each clickable to divert to another part of the document. Each of these Events have specific usage. It should be noted here that documentation on some events is rather light, ie. when to use certain ones versus others, but a lot can be found out by looking at vanilla scripts or other mods.&lt;br /&gt;
&lt;br /&gt;
I want to start a new function after the player takes over Altdorf. After searching the term “Occu”, the event “GarrisonOccupiedEvent” is highlighted. This looks promising! After clicking, the available functions are “garrison_residence” and “character”, which seem to be the region that was occupied, and the character that led the assault, in order.&lt;br /&gt;
&lt;br /&gt;
=== Conditional Coding ===&lt;br /&gt;
Remember “boolean1” from up above? If that is set to true/false, it’s not really effective code. We can replace that true/false with a function that returns a true/false value, and that way we can actually check the event, see if a specific thing happened in that event, and then spit out a boolean to trigger the callback function.&lt;br /&gt;
     &amp;lt;code&amp;gt;function(context)&lt;br /&gt;
         return context:[thing we want to check]&lt;br /&gt;
     end,&amp;lt;/code&amp;gt;&lt;br /&gt;
In essence, the above is the foundation for what all effective conditional functions in a listener should be. Context, in the context of listeners, is an object which contains all the data that occurred within the Event. But let’s back up. Remember on the document, we found &amp;lt;code&amp;gt;GarrisonOccupiedEvent&amp;lt;/code&amp;gt;? Let’s go back to it and click it again. We see two options, as mentioned before – “garrison_residence” and “character”. As our intention is to find a specific region being occupied – Altdorf – we need to use that former path.&lt;br /&gt;
&lt;br /&gt;
At this point, our WIP code looks like the following:&lt;br /&gt;
     &amp;lt;code&amp;gt;function(context)&lt;br /&gt;
         return context:garrison_residence()&lt;br /&gt;
     end,&amp;lt;/code&amp;gt;&lt;br /&gt;
For the conditional function, you always want to start with “return context:”, and the next method can only be one of the methods that is accessible by that Event – which is where this document comes SO in handy. For other examples, click around the different Events listed at the top. Each “Function” underneath each Event after clicking it is a valid method for the context of that Event. The “RegionSelected” event only has access to a “region” function, which means the only valid method is to use “context:region()”. “DilemmaChoiceMadeEvent”, however, has access to “faction”, “choice”, “campaign_model”, and “dilemma”, so those four are all valid methods.&lt;br /&gt;
&lt;br /&gt;
''NOTE: Yes, you have to add “()” to the end of the function’s name.''&lt;br /&gt;
&lt;br /&gt;
Back to our example – you’ll see the garrison_residence has &amp;lt;code&amp;gt;GARRISON_RESIDENCE_SCRIPT_INTERFACE&amp;lt;/code&amp;gt; beneath it. Looking in the “GARRISON_RESIDENCE_SCRIPT_INTERFACE”, I don’t see a “key” or “name”. Matter of fact, the most likely path is “region()”. That brings our code to…&lt;br /&gt;
     &amp;lt;code&amp;gt;function(context)&lt;br /&gt;
         return context:garrison_residence():region()&lt;br /&gt;
     end,&amp;lt;/code&amp;gt;&lt;br /&gt;
After checking the &amp;lt;code&amp;gt;REGION_SCRIPT_INTERFACE&amp;lt;/code&amp;gt;, we finally see the “name” method, which allows us to fully check our context. Our line of code is finally built to:&lt;br /&gt;
     &amp;lt;code&amp;gt;function(context)&lt;br /&gt;
         return context:garrison_residence():region():name() == &amp;quot;wh_main_reikland_altdorf&amp;quot;&lt;br /&gt;
     end,&amp;lt;/code&amp;gt;&lt;br /&gt;
But that’s not all! All this does is to check if the Altdorf region is being occupied, but it says nothing about Mannfred! We’ll go back to the very beginning – find the GarrisonOccupiedEvent on the document, and return to its functions, which were garrison_residence() and character(). We want to build an “and” sentence for our conditional, so that it only triggers the function when Altdorf is occupied AND when it’s occupied by Mannfred. Let’s try to plot our trajectory a little. We should try to find a script_interface that allows us to reference an agent_subtype key, which is the cleanest and most mod-friendly way to search for Mannfred. Looking at &amp;lt;code&amp;gt;CHARACTER_SCRIPT_INTERFACE&amp;lt;/code&amp;gt;, I see two functions – character_subtype() and character_subtype_key(). The latter is used to return a string – ie., it doesn’t check for a specific subtype key, but it will tell us what the characters subtype key is. We need to ''check'' for a specific subtype key, “vmp_mannfred_von_carstein”.&lt;br /&gt;
     &amp;lt;code&amp;gt;function(context)&lt;br /&gt;
         return context:garrison_residence():region():name() == &amp;quot;wh_main_reikland_altdorf&amp;quot; and context:character():character_subtype(&amp;quot;vmp_mannfred_von_carstein&amp;quot;)&lt;br /&gt;
     end,&amp;lt;/code&amp;gt;&lt;br /&gt;
Note here that the first line of context, that ends in “:name()”, needs to have an equal-to check because we don’t want to return the ''name'' of the region, but we want to return a value of true or false if the name of the region is equal to the string we define – “wh_main_reikland_altdorf”. We can read this as “return true if the region’s name is Altdorf, and if the character is Mannfred; else, return false.”&lt;br /&gt;
&lt;br /&gt;
A strong conditional function is very important to writing good listeners, as listeners can be very performance-heavy if there are many triggering at once, and the more that are whittled away via a strong conditional, the better performance will be. Be mindful of your conditionals!&lt;br /&gt;
&lt;br /&gt;
=== Callback Functions ===&lt;br /&gt;
At this point in the walkthrough, we have about 60% of our listener completed! It’s not bad, let’s take a quick look at what we actually have written:&lt;br /&gt;
 &amp;lt;code&amp;gt;core:add_listener(&lt;br /&gt;
     &amp;quot;MannfredOccupiesAltdorf&amp;quot;,&lt;br /&gt;
     &amp;quot;GarrisonOccupiedEvent&amp;quot;,&lt;br /&gt;
     function(context)&lt;br /&gt;
         return context:garrison_residence():region():name() == &amp;quot;wh_main_reikland_altdorf&amp;quot; and context:character():character_subtype(&amp;quot;vmp_mannfred_von_carstein&amp;quot;)&lt;br /&gt;
     end,&lt;br /&gt;
     function(context)&lt;br /&gt;
         -- code to execute&lt;br /&gt;
     end,&lt;br /&gt;
     boolean2&lt;br /&gt;
 )&amp;lt;/code&amp;gt;&lt;br /&gt;
I’d like to point out a couple quick notes. To start off – yes, your listener_name can be anything you want, as long as it’s a string. You need a comma after ''every argument'' in the command, of which there are five that are detailed way at the top – listener_name, name, conditional boolean, callback, and persistence boolean. The code above is written the way it is because that’s a common application of it, and allows it to be easily read, but realistically this can all be written on one line.&lt;br /&gt;
&lt;br /&gt;
Alright, so we are on the function to execute block, known as the callback function. Here, we have much more freedom than the conditional function, as we can do whatever is needed with this block. For instance, we can have a callback function that triggers an event (like a dilemma or a message), or grants a unit/experience/ancillary, or unlocks something like a Rite or a Legendary Lord. For our instance, I want to just give Mannfred’s army a new unit and a new effect bundle.&lt;br /&gt;
&lt;br /&gt;
''NOTE: For our sake, we’re going to assume the new unit and new effect bundle are already defined.''&lt;br /&gt;
&lt;br /&gt;
Looking up in our commands document, I see a grant_unit_to_character to command. Checking vanilla usage, I see it takes two args – a char_lookup_str and a unit_key string. The unit_key string – which refers to the main_units_tables – is, in our situation, &amp;lt;code&amp;gt;tutorial_big_bat&amp;lt;/code&amp;gt;. To find a char_lookup_str, we have to first find the character’s cqi.&lt;br /&gt;
&lt;br /&gt;
''For more information on char_lookup_str and cqi:'' ''this link here.''&lt;br /&gt;
&lt;br /&gt;
Thankfully for us, we can go back to where we were before and use the context of the Event to find all the info from before. Looking at the &amp;lt;code&amp;gt;CHARACTER_SCRIPT_INTERFACE&amp;lt;/code&amp;gt;, we see a direct link to cqi, with the method “command_queue_index()”. For this, we define our local values as such:&lt;br /&gt;
     &amp;lt;code&amp;gt;local char_cqi = context:character():command_queue_index()&lt;br /&gt;
     local char_lookup_str = cm:char_lookup_str(char_cqi)&amp;lt;/code&amp;gt;&lt;br /&gt;
With this, we find the CQI first of the character, and then apply that to find the character’s lookup string, which is the type needed for grant_unit_to_character.&lt;br /&gt;
&lt;br /&gt;
Before we apply that command though, we should find the arguments we need for apply_effect_bundle_to_force(), which is our command that will give an effect bundle to Mannfred’s army. We first need our effect bundle; we’ll use &amp;lt;code&amp;gt;tutorial_free_hair&amp;lt;/code&amp;gt;. The second argument is a military force CQI, and our third argument is a number of turns. We’ll make it five turns long.&lt;br /&gt;
&lt;br /&gt;
To find the military force CQI, we use something similar as above. We will go from character to military force, and then find the CQI there. We can use something like the following:&lt;br /&gt;
     &amp;lt;code&amp;gt;local mf_cqi = context:character():military_force():command_queue_index()&amp;lt;/code&amp;gt;&lt;br /&gt;
Alright, now we have all we need to build our callback function! Let’s mush it all together real quickly.&lt;br /&gt;
 &amp;lt;code&amp;gt;function(context)&lt;br /&gt;
 &lt;br /&gt;
     local char_cqi = context:character():command_queue_index()&lt;br /&gt;
     local char_lookup_str = cm:char_lookup_str(char_cqi)&lt;br /&gt;
     local mf_cqi = context:character():military_force():command_queue_index()&lt;br /&gt;
     &lt;br /&gt;
     cm:grant_unit_to_character(char_lookup_str, &amp;quot;tutorial_big_bat&amp;quot;)&lt;br /&gt;
     cm:apply_effect_bundle_to_force(&amp;quot;tutorial_free_hair&amp;quot;, mf_cqi, 5)&lt;br /&gt;
 &lt;br /&gt;
 end,&amp;lt;/code&amp;gt;&lt;br /&gt;
And that’s a quick walkthrough on how to assemble your callback function! Please note, you can have whatever you want here, and there’s nothing saying you ''must'' restrict yourself to the context of the event. As an example, I can do the same thing without context, like so:&lt;br /&gt;
 &amp;lt;code&amp;gt;function(context)&lt;br /&gt;
 &lt;br /&gt;
     local mannfred_faction = cm:get_faction(&amp;quot;wh_main_vmp_vampire_counts&amp;quot;)&lt;br /&gt;
     local mannfred = mannfred_faction:faction_leader()&lt;br /&gt;
     &lt;br /&gt;
     local char_cqi = mannfred:cqi()	&lt;br /&gt;
     local char_lookup_str = cm:char_lookup_str(char_cqi)&lt;br /&gt;
     local mf_cqi = mannfred:military_force():command_queue_index()&lt;br /&gt;
     &lt;br /&gt;
     cm:grant_unit_to_character(char_lookup_str, &amp;quot;tutorial_big_bat&amp;quot;)&lt;br /&gt;
     cm:apply_effect_bundle_to_force(&amp;quot;tutorial_free_hair&amp;quot;, mf_cqi, 5)&lt;br /&gt;
 &lt;br /&gt;
 end,&amp;lt;/code&amp;gt;&lt;br /&gt;
This takes a little bit longer than using context, but it is a solution to applying commands to objects that aren’t involved in the context. So if, for example, you wanted to give all Vampire factions – aside from Mannfred’s own – an &amp;lt;code&amp;gt;effect_bundle&amp;lt;/code&amp;gt; that increases their diplomatic relations with Mannfred after he conquers Altdorf, you can. The world is your oyster when it comes to listeners.&lt;br /&gt;
&lt;br /&gt;
=== Persistence ===&lt;br /&gt;
One last thing, and it’s gonna be much quicker than the last two. The final boolean – persistence – can be set to true, or false. True means that the listener will fire more than once; false means that, once the entire code is run through, the listener is removed from the game state and won’t be called again. This only gives two options – once, or infinite. There is a third option, by using core:remove_listener(“listener_name”). At whichever point this code is called, the listener with the matching “listener_name” is removed from the game state, and won’t be called again. A remove_listener statement like this can be used after enabling a counter that listens for the listener firing five times, or to cancel the listener if the turn is beyond 100, or much else.&lt;br /&gt;
&lt;br /&gt;
Keep in mind that, to “fire”, only the conditional needs to return true. If there’s more if statements in your callback function, and they fail, but your persistence is set to false, the listener will remove itself.&lt;br /&gt;
 &amp;lt;code&amp;gt;core:add_listener(&lt;br /&gt;
     &amp;quot;my_listener&amp;quot;, &lt;br /&gt;
     &amp;quot;GarrisonOccupiedEvent&amp;quot;, &lt;br /&gt;
     true, &lt;br /&gt;
     function(context) &lt;br /&gt;
         if this_is_done then&lt;br /&gt;
             --stuff happens&lt;br /&gt;
         end;&lt;br /&gt;
     end, &lt;br /&gt;
     false&lt;br /&gt;
 )&amp;lt;/code&amp;gt;&lt;br /&gt;
So this listener will cancel after one use if “GarrisonOccupiedEvent” is triggered, regardless of whether or not “this is done” returns as true or false.&lt;br /&gt;
&lt;br /&gt;
=== Summary ===&lt;br /&gt;
Overall, there’s a lot of power to understanding these big three, and it takes your Lua knowledge from “adding and multiplying numbers” to “affecting the game in a real, and personable way”. Make sure this stuff is good and mastered, and if you ever find confusion, come back and reread this stuff.&lt;br /&gt;
&lt;br /&gt;
[[Category:Lua Tutorials]]&lt;/div&gt;</summary>
		<author><name>Grimmys</name></author>
	</entry>
	<entry>
		<id>https://tw-modding.com/index.php?title=Lua:Functions,_Arguments_%26_Parameters_(Also_Returns)&amp;diff=1216</id>
		<title>Lua:Functions, Arguments &amp; Parameters (Also Returns)</title>
		<link rel="alternate" type="text/html" href="https://tw-modding.com/index.php?title=Lua:Functions,_Arguments_%26_Parameters_(Also_Returns)&amp;diff=1216"/>
		<updated>2024-03-11T19:26:51Z</updated>

		<summary type="html">&lt;p&gt;Grimmys: Add LUA tutorial category&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;br /&gt;
Welcome back! On today’s lesson, we’re going to cover one of the most fundamental types in Lua much further, and that type is, if you can read, ''functions''. Everybody loves functions.&lt;br /&gt;
&lt;br /&gt;
Functions are a special data type in Lua. Functions have two specific stages: definition, and call. A function can be defined as many times as one would like, but it will not do anything until the function is ''called''. Quick look, followed by a breakdown:&lt;br /&gt;
     &amp;lt;code&amp;gt;-- DEFINE the function, which we can call and trigger later on, as much as we'd like&lt;br /&gt;
     function example_function()&lt;br /&gt;
         out(&amp;quot;This is your example function&amp;quot;) -- at this point, nothing is output&lt;br /&gt;
     end&lt;br /&gt;
 &lt;br /&gt;
     -- actually calling the function to trigger the out!&lt;br /&gt;
     example_function() → This is your example function&amp;lt;/code&amp;gt;&lt;br /&gt;
And that’s the basics of it! We should note that in this example, &amp;lt;code&amp;gt;example_function&amp;lt;/code&amp;gt; is actually a variable name. The above is syntactic sugar for the following:&lt;br /&gt;
     &amp;lt;code&amp;gt;example_function = function()&lt;br /&gt;
         out(&amp;quot;This is your example function&amp;quot;)&lt;br /&gt;
     end&amp;lt;/code&amp;gt;&lt;br /&gt;
But the other way is a lot more common, and probably prettier for all eyes. On the case of syntactic sugar, you can simply put the keyword &amp;lt;code&amp;gt;local&amp;lt;/code&amp;gt; prior to the keyword &amp;lt;code&amp;gt;function&amp;lt;/code&amp;gt;, and it will make it a local variable. I’ll be doing that from now on, to beat that idea in your own head.&lt;br /&gt;
&lt;br /&gt;
Since the name of a function is just a variable, it can be redefined, and even as a different type. If a variable is defined more than once, the latest definition will “win”.&lt;br /&gt;
     &amp;lt;code&amp;gt;local function example_function()&lt;br /&gt;
         out(&amp;quot;This is your example function&amp;quot;)&lt;br /&gt;
     end&lt;br /&gt;
 &lt;br /&gt;
     example_function = 10 -- Why would ANYONE do this?!&lt;br /&gt;
 &lt;br /&gt;
     example_function() → attempt to call global `example_function`, a number value&amp;lt;/code&amp;gt;&lt;br /&gt;
The term “call” here is what I mentioned earlier – the ''call'' phase of a function. A call to a function is triggered by those two brackets – &amp;lt;code&amp;gt;()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
At this point, we have a function that prints the same text over and over again. Let’s give it some way to change the text based on some dynamism!&lt;br /&gt;
     &amp;lt;code&amp;gt;local function example_function(text)&lt;br /&gt;
         out(text)&lt;br /&gt;
     end&lt;br /&gt;
 &lt;br /&gt;
     example_function(&amp;quot;Testing&amp;quot;) → Testing&lt;br /&gt;
     example_function(&amp;quot;Example!&amp;quot;) → Example!&amp;lt;/code&amp;gt;&lt;br /&gt;
The term “text” is a &amp;lt;code&amp;gt;local variable&amp;lt;/code&amp;gt; for that function, available in the entirety of that function’s scope. It goes “out of scope” (as the cool kids say) by the &amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt; keyword. This is another clever shorthand that the Lua languages gives to us. Use it!&lt;br /&gt;
&lt;br /&gt;
A clarity-for-clarity’s-sake note here: in the above example, “text” is a ''parameter'', which is the fancy word for a local variable assigned to the function’s scope. The string “Testing”, or the string “Example!”, are ''arguments'', which is a variable or value that is “passed” into the function and takes the place of the parameter at runtime. We can think of a parameter as a “fill-in-the-blank” space on an entry form, and the argument as whatever we fill in there.&lt;br /&gt;
&lt;br /&gt;
One final thing we should know about before we go on is ''return values''. In the above, we’re just passing stuff ''into'' a function. But what if I want to take stuff ''out'' of a function? Well, return values, of course!&lt;br /&gt;
&lt;br /&gt;
The keyword &amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; is neat, and two-fold. Its first, and primary purpose, is to take whatever is to the right of it and shoot it back out, if the function is called. Its second, and still very-important, purpose is to stop the function once the keyword is called. Let’s take a look at a common example of return values:&lt;br /&gt;
     &amp;lt;code&amp;gt;local function double(num)&lt;br /&gt;
         -- if the parameter is not a number type, then output some text and then STOP the function, to prevent it from going on&lt;br /&gt;
         if not is_number(num) then&lt;br /&gt;
             out(&amp;quot;double() called, but you didn't supply a number! Aborting function!&amp;quot;)&lt;br /&gt;
             return&lt;br /&gt;
         end&lt;br /&gt;
 &lt;br /&gt;
         -- if the parameter is a number type, then double it and return it! (we can safely assume that &amp;quot;num&amp;quot; IS a number, because otherwise the function wouldn't go this far)&lt;br /&gt;
         local val = num * 2&lt;br /&gt;
         return val&lt;br /&gt;
     end&lt;br /&gt;
 &lt;br /&gt;
     local a = 2&lt;br /&gt;
     out(a) → 2&lt;br /&gt;
 &lt;br /&gt;
     -- define a local variable as the RESULT of &amp;quot;double(a)&amp;quot;&lt;br /&gt;
     local b = double(a)&lt;br /&gt;
     out(b) → 4&amp;lt;/code&amp;gt;&lt;br /&gt;
You can return any type, and you can even return multiple values at once. Say you wanted to take the above function, but instead of just doubling the number, you ''also'' tripled it, and wanted to get both values.&lt;br /&gt;
     &amp;lt;code&amp;gt;local function double_and_triple(num)&lt;br /&gt;
         -- if the parameter is not a number type, then output some text and then STOP the function, to prevent it from going on&lt;br /&gt;
         if not is_number(num) then&lt;br /&gt;
             out(&amp;quot;double_and_triple() called, but you didn't supply a number! Aborting function!&amp;quot;)&lt;br /&gt;
             return&lt;br /&gt;
         end&lt;br /&gt;
 &lt;br /&gt;
         local double = num * 2&lt;br /&gt;
         local triple = num * 3&lt;br /&gt;
 &lt;br /&gt;
         -- this is it, just separate the return values or variables with a comma!&lt;br /&gt;
         return double, triple&lt;br /&gt;
     end&lt;br /&gt;
 &lt;br /&gt;
     local number = 5&lt;br /&gt;
 &lt;br /&gt;
     local d, t = double_and_triple(number)&lt;br /&gt;
     out(d) → 10&lt;br /&gt;
     out(t) → 15&amp;lt;/code&amp;gt;&lt;br /&gt;
I’d like to point out that I’m changing the names of my variables to point out that ''the name of parameters can be whatever you want''. Don’t be confused by me defining the function as &amp;lt;code&amp;gt;local function double_and_triple(num)&amp;lt;/code&amp;gt; and calling it using &amp;lt;code&amp;gt;double_and_triple(number)&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt;num&amp;lt;/code&amp;gt; is a local variable, available only in the SCOPE of the function, whereas &amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt; is a ''different'' local variable, available to a higher scope but below the function definition.&lt;br /&gt;
&lt;br /&gt;
At this point, we’ve got all the background knowledge really needed to start doing some more cool stuff! In the next lesson, we’ll learn more about script interfaces, we’ll go in-depth about listeners, and we’ll talk about commands and how to check for existing ones! You probably don’t know what any of those three things mean, but basically, ''this is where you start doing stuff in-game''.&lt;br /&gt;
&lt;br /&gt;
==== Challenge ====&lt;br /&gt;
Define a function for each of the following:&lt;br /&gt;
&lt;br /&gt;
* Takes two numerical parameters, adds them together, and prints the result, with error-checking in case the parameters supplied aren’t numbers&lt;br /&gt;
* Takes one string parameter, and concatenates it with a defined string variable ''within'' the function’s scope&lt;br /&gt;
* Takes three parameters of any type, and attaches them to a table at indexes 1, 2, 3, and returns that table&lt;br /&gt;
&lt;br /&gt;
[[Category:Lua Tutorials]]&lt;/div&gt;</summary>
		<author><name>Grimmys</name></author>
	</entry>
	<entry>
		<id>https://tw-modding.com/index.php?title=Lua:Tables_%26_Loops&amp;diff=1215</id>
		<title>Lua:Tables &amp; Loops</title>
		<link rel="alternate" type="text/html" href="https://tw-modding.com/index.php?title=Lua:Tables_%26_Loops&amp;diff=1215"/>
		<updated>2024-03-11T19:26:20Z</updated>

		<summary type="html">&lt;p&gt;Grimmys: Add LUA tutorial category&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Alright, here we go – tables, and loops. We’ve covered tables in a good depth so far, but this should get you to full comfort. We’ll also talk about loops, and iterating through tables, and using maps. It’ll be cool. Let’s start with arrays and looping.&lt;br /&gt;
&lt;br /&gt;
==== Arrays and Looping ====&lt;br /&gt;
Arrays, for those who don’t recall, are tables with incremental indexes starting at &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;. Lua automatically assigns values to an index, not the Lua-author. An example would be:&lt;br /&gt;
     &amp;lt;code&amp;gt;local example_array = {5, 4, 3, 2, 1}&lt;br /&gt;
 &lt;br /&gt;
     out(example_array[1]) → 5&lt;br /&gt;
     out(example_array[5]) → 1&amp;lt;/code&amp;gt;&lt;br /&gt;
Arrays are always numbered incrementally. It’s easy enough to assign new values to existing arrays – and, after all, that’s 90% of their usefulness.&lt;br /&gt;
     &amp;lt;code&amp;gt;local example_array = {5, 4, 3, 2, 1}&lt;br /&gt;
 &lt;br /&gt;
     out(example_array[1]) → 5&lt;br /&gt;
     out(example_array[5]) → 1&lt;br /&gt;
 &lt;br /&gt;
     out(example_array[6]) → nil -- doesn't exist!&lt;br /&gt;
 &lt;br /&gt;
     example_array[6] = 20&lt;br /&gt;
     out(example_array[6]) → 20&amp;lt;/code&amp;gt;&lt;br /&gt;
Say you don’t know how many indexes there currently are in an array; say you’ve edited it a bunch of times, and there’s no easy way to read how many indexes there are (which is the norm). You can add on to the end of an array using the following:&lt;br /&gt;
     &amp;lt;code&amp;gt;local example_array = {5, 4, 3, 2, 1}&lt;br /&gt;
 &lt;br /&gt;
     out(example_array[1]) → 5&lt;br /&gt;
     out(example_array[5]) → 1&lt;br /&gt;
 &lt;br /&gt;
     out(example_array[6]) → nil -- doesn't exist!&lt;br /&gt;
 &lt;br /&gt;
     -- some stuff that randomizes the array, woo hoo&lt;br /&gt;
 &lt;br /&gt;
     example_array[#example_array + 1] = 20 -- #example_array would be the current number of indexes; +1 is incrementing it, assigning '20' to an unused index&lt;br /&gt;
     out(example_array[#example_array]) = 20 -- now #example_array is one higher than the previous statement, due to the assignment of '20'!&amp;lt;/code&amp;gt;&lt;br /&gt;
Remember that the # operator returns the ''number of indexes in that array'', and that it ''should not be used with maps''.&lt;br /&gt;
&lt;br /&gt;
With that remembered, let’s look at a loop!&lt;br /&gt;
     &amp;lt;code&amp;gt;local example_array = {5, 4, 3, 2, 1}&lt;br /&gt;
 &lt;br /&gt;
     for i = 1, #example_array do&lt;br /&gt;
         out(example_array[i]) → 5, 4, 3, 2, 1&lt;br /&gt;
     end&amp;lt;/code&amp;gt;&lt;br /&gt;
And that’s really it! The keyword &amp;lt;code&amp;gt;for&amp;lt;/code&amp;gt; is hyper important, and allows us to loop over various indexes in an array. &amp;lt;code&amp;gt;for&amp;lt;/code&amp;gt; defines a local variable – in this case, &amp;lt;code&amp;gt;i&amp;lt;/code&amp;gt;, though it can be WHATEVER – to a minimum value, and a maximum value. In this instance, the minimum value of &amp;lt;code&amp;gt;i&amp;lt;/code&amp;gt; is ''1'', while the maximum value of &amp;lt;code&amp;gt;i&amp;lt;/code&amp;gt; is ''5''. And then, it runs the &amp;lt;code&amp;gt;for&amp;lt;/code&amp;gt; chunk ''once for each value of &amp;lt;code&amp;gt;i&amp;lt;/code&amp;gt;''. That means, it runs &amp;lt;code&amp;gt;out(example_array[i])&amp;lt;/code&amp;gt; once with i == 1, then once with i == 2, with i == 3, i == 4, and i == 5.&lt;br /&gt;
&lt;br /&gt;
Loops for arrays like this are super useful, as I’ve hinted at. But how does this matter for Total War, you might be asking? Well, look no further! List interfaces!&lt;br /&gt;
&lt;br /&gt;
Remember the script interface chapter, we saw something called a &amp;lt;code&amp;gt;CHARACTER_LIST_SCRIPT_INTERFACE&amp;lt;/code&amp;gt;? List interfaces are common, and they’re a cool type of array that we can kinda use just like the above one, but differently. Since it’s an ''object'', not just an ''array'', we have to do a couple of different things. I’ll show you, then we’ll talk, kay?&lt;br /&gt;
     &amp;lt;code&amp;gt;local faction_name = cm:get_local_faction()&lt;br /&gt;
     local faction = cm:get_faction(faction_name)&lt;br /&gt;
 &lt;br /&gt;
     local character_list = faction:character_list()&lt;br /&gt;
     for i = 0, character_list:num_items() - 1 do&lt;br /&gt;
         local character = character_list:item_at(i)&lt;br /&gt;
         -- check stuff about the character&lt;br /&gt;
     end&amp;lt;/code&amp;gt;&lt;br /&gt;
There are THREE important distinctions to make here.&lt;br /&gt;
&lt;br /&gt;
First off – the ''minimum'' is &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;, NOT &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;, and the maximum has to be the ''number of items in that list minus one''. That’s because these lists are defined in C++, where indexes start at 0, unlike Lua where indexes start at 1.&lt;br /&gt;
&lt;br /&gt;
Secondly – the maximum can’t be defined as &amp;lt;code&amp;gt;#character_list&amp;lt;/code&amp;gt;, because it’s not an array! &amp;lt;code&amp;gt;character_list:num_items()&amp;lt;/code&amp;gt; returns the total number of items in that array, and there’s a &amp;lt;code&amp;gt;num_items()&amp;lt;/code&amp;gt; method for every list interface.&lt;br /&gt;
&lt;br /&gt;
Thirdly – you can’t use &amp;lt;code&amp;gt;character_list[i]&amp;lt;/code&amp;gt; to read the index. IT’S NOT AN ARRAY! &amp;lt;code&amp;gt;character_list:item_at(i)&amp;lt;/code&amp;gt; grabs the item at the index in the array; there’s an &amp;lt;code&amp;gt;item_at()&amp;lt;/code&amp;gt; method for every list interface.&lt;br /&gt;
&lt;br /&gt;
Arrays are really common in the CA script interfaces, and having a healthy grasp of them will allow you to do much more with your scripts.&lt;br /&gt;
&lt;br /&gt;
==== Maps and Looping ====&lt;br /&gt;
While maps aren’t used in CA script interfaces, like arrays kinda are, they’re still really vital and can allow some super ease of scripting.&lt;br /&gt;
&lt;br /&gt;
Reminder for what maps are: they’re tables ''with user-defined indexes''.&lt;br /&gt;
 &lt;br /&gt;
     &amp;lt;code&amp;gt;local example_map = {&lt;br /&gt;
         [&amp;quot;first&amp;quot;] = 1,&lt;br /&gt;
         [&amp;quot;second&amp;quot;] = 5,&lt;br /&gt;
         [&amp;quot;third&amp;quot;] = 10&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     out(example_map[&amp;quot;first&amp;quot;]) → 1&amp;lt;/code&amp;gt;&lt;br /&gt;
Looping in maps is pretty similar to arrays, though you have to define ''two'' local variables, instead of just one.&lt;br /&gt;
 &lt;br /&gt;
     &amp;lt;code&amp;gt;local example_map = {&lt;br /&gt;
         [&amp;quot;first&amp;quot;] = 1,&lt;br /&gt;
         [&amp;quot;second&amp;quot;] = 5,&lt;br /&gt;
         [&amp;quot;third&amp;quot;] = 10&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for key, value in pairs(example_map) do&lt;br /&gt;
         out(value) → 1, 5, 10&lt;br /&gt;
     end&amp;lt;/code&amp;gt;&lt;br /&gt;
As before, we define the local variables with &amp;lt;code&amp;gt;for&amp;lt;/code&amp;gt;. Those local variables are &amp;lt;code&amp;gt;key&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;value&amp;lt;/code&amp;gt; – though, just like &amp;lt;code&amp;gt;i&amp;lt;/code&amp;gt; in the above example, those variables can be named whatever you’d like. Using &amp;lt;code&amp;gt;key&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;value&amp;lt;/code&amp;gt; is simply convention, same with &amp;lt;code&amp;gt;i&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Using the keyword &amp;lt;code&amp;gt;in&amp;lt;/code&amp;gt; is syntax here, it’s necessary between the two variables, and the pairs() function call. The function &amp;lt;code&amp;gt;pairs&amp;lt;/code&amp;gt; basically defines that you want to iterate through the table (provided as a parameter to &amp;lt;code&amp;gt;pairs&amp;lt;/code&amp;gt;). It doesn’t require understanding – just know that, to iterate through a map, use the above.&lt;br /&gt;
&lt;br /&gt;
Now, where’s the usefulness? There’s a LOAD.&lt;br /&gt;
&lt;br /&gt;
For one, a map loop is ''quicker'' than an array loop, and easier to write using Excel&lt;br /&gt;
     &amp;lt;code&amp;gt;-- you&lt;br /&gt;
     local lame_units = {&amp;quot;wh_dlc02_vmp_cav_blood_knights_0&amp;quot;, &amp;quot;wh_dlc04_vmp_veh_corpse_cart_0&amp;quot;, &amp;quot;wh_dlc04_vmp_veh_corpse_cart_1&amp;quot;, &amp;quot;wh_dlc04_vmp_veh_corpse_cart_2&amp;quot;, &amp;quot;wh_main_vmp_inf_crypt_ghouls&amp;quot;, &amp;quot;wh_main_vmp_mon_crypt_horrors&amp;quot;, &amp;quot;wh_main_vmp_mon_vargheists&amp;quot;, &amp;quot;wh_main_vmp_mon_varghulf&amp;quot;, &amp;quot;wh_main_vmp_mon_varghulf&amp;quot;}&lt;br /&gt;
 &lt;br /&gt;
     for i = 1, #lame_units do&lt;br /&gt;
         cm:add_event_restricted_unit_record_for_faction(lame_units[i], &amp;quot;wh2_dlc11_vmp_the_barrow_legion&amp;quot;)&lt;br /&gt;
     end&lt;br /&gt;
 &lt;br /&gt;
     -- the guy she told you not to worry about&lt;br /&gt;
     local kill_units = {&lt;br /&gt;
         [&amp;quot;wh_dlc02_vmp_cav_blood_knights_0&amp;quot;] = true,&lt;br /&gt;
         [&amp;quot;wh_dlc04_vmp_veh_corpse_cart_0&amp;quot;] = true,&lt;br /&gt;
         [&amp;quot;wh_dlc04_vmp_veh_corpse_cart_1&amp;quot;] = true,&lt;br /&gt;
         [&amp;quot;wh_dlc04_vmp_veh_corpse_cart_2&amp;quot;] = true,&lt;br /&gt;
         [&amp;quot;wh_main_vmp_inf_crypt_ghouls&amp;quot;] = true,&lt;br /&gt;
         [&amp;quot;wh_main_vmp_mon_crypt_horrors&amp;quot;] = true,&lt;br /&gt;
         [&amp;quot;wh_main_vmp_mon_vargheists&amp;quot;] = true,&lt;br /&gt;
         [&amp;quot;wh_main_vmp_mon_varghulf&amp;quot;] = true,&lt;br /&gt;
         [&amp;quot;wh_main_vmp_veh_black_coach&amp;quot;] = true&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for unit, _ in pairs(kill_units) do&lt;br /&gt;
         cm:add_event_restricted_unit_record_for_faction(unit, &amp;quot;wh2_dlc11_vmp_the_barrow_legion&amp;quot;)&lt;br /&gt;
     end&amp;lt;/code&amp;gt;&lt;br /&gt;
For another, it allows you to iterate through a ''lot'' of data at once, with real ease. (the following is a further example from the Return of the Lichemaster mod!)&lt;br /&gt;
 &lt;br /&gt;
     &amp;lt;code&amp;gt;local subtypes = {&lt;br /&gt;
         [&amp;quot;AK_hobo_nameless&amp;quot;] = {&lt;br /&gt;
             [&amp;quot;forename&amp;quot;] = &amp;quot;names_name_666777891&amp;quot;,&lt;br /&gt;
             [&amp;quot;family_name&amp;quot;] = &amp;quot;names_name_666777892&amp;quot;,&lt;br /&gt;
             [&amp;quot;clan_name&amp;quot;] = &amp;quot;&amp;quot;,&lt;br /&gt;
             [&amp;quot;other_name&amp;quot;] = &amp;quot;&amp;quot;, &lt;br /&gt;
             [&amp;quot;age&amp;quot;] = 50, &lt;br /&gt;
             [&amp;quot;is_male&amp;quot;] = true, &lt;br /&gt;
             [&amp;quot;agent_type&amp;quot;] = &amp;quot;general&amp;quot;,&lt;br /&gt;
             [&amp;quot;agent_subtype&amp;quot;] = &amp;quot;AK_hobo_nameless&amp;quot;,&lt;br /&gt;
             [&amp;quot;is_immortal&amp;quot;] = true, &lt;br /&gt;
             [&amp;quot;art_set_id&amp;quot;] = &amp;quot;AK_hobo_nameless&amp;quot;&lt;br /&gt;
         },&lt;br /&gt;
         [&amp;quot;AK_hobo_draesca&amp;quot;] = {&lt;br /&gt;
             [&amp;quot;forename&amp;quot;] = &amp;quot;names_name_666777893&amp;quot;,&lt;br /&gt;
             [&amp;quot;family_name&amp;quot;] = &amp;quot;names_name_666777894&amp;quot;,&lt;br /&gt;
             [&amp;quot;clan_name&amp;quot;] = &amp;quot;&amp;quot;,&lt;br /&gt;
             [&amp;quot;other_name&amp;quot;] = &amp;quot;&amp;quot;, &lt;br /&gt;
             [&amp;quot;age&amp;quot;] = 50, &lt;br /&gt;
             [&amp;quot;is_male&amp;quot;] = true, &lt;br /&gt;
             [&amp;quot;agent_type&amp;quot;] = &amp;quot;general&amp;quot;,&lt;br /&gt;
             [&amp;quot;agent_subtype&amp;quot;] = &amp;quot;AK_hobo_draesca&amp;quot;,&lt;br /&gt;
             [&amp;quot;is_immortal&amp;quot;] = true, &lt;br /&gt;
             [&amp;quot;art_set_id&amp;quot;] = &amp;quot;AK_hobo_draesca&amp;quot;,&lt;br /&gt;
             [&amp;quot;ancillary1&amp;quot;] = &amp;quot;AK_hobo_draesca_helmet&amp;quot;&lt;br /&gt;
         },&lt;br /&gt;
         [&amp;quot;AK_hobo_priestess&amp;quot;] = {&lt;br /&gt;
             [&amp;quot;forename&amp;quot;] = &amp;quot;names_name_666777895&amp;quot;,&lt;br /&gt;
             [&amp;quot;family_name&amp;quot;] = &amp;quot;names_name_666777896&amp;quot;,&lt;br /&gt;
             [&amp;quot;clan_name&amp;quot;] = &amp;quot;&amp;quot;,&lt;br /&gt;
             [&amp;quot;other_name&amp;quot;] = &amp;quot;&amp;quot;, &lt;br /&gt;
             [&amp;quot;age&amp;quot;] = 50, &lt;br /&gt;
             [&amp;quot;is_male&amp;quot;] = true, &lt;br /&gt;
             [&amp;quot;agent_type&amp;quot;] = &amp;quot;general&amp;quot;,&lt;br /&gt;
             [&amp;quot;agent_subtype&amp;quot;] = &amp;quot;AK_hobo_priestess&amp;quot;,&lt;br /&gt;
             [&amp;quot;is_immortal&amp;quot;] = true, &lt;br /&gt;
             [&amp;quot;art_set_id&amp;quot;] = &amp;quot;AK_hobo_priestess&amp;quot;,&lt;br /&gt;
             [&amp;quot;ancillary1&amp;quot;] = &amp;quot;AK_hobo_priestess_trickster&amp;quot;,&lt;br /&gt;
             [&amp;quot;ancillary2&amp;quot;] = &amp;quot;AK_hobo_priestess_charms&amp;quot;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     for key, subtype_data in pairs(subtypes) do&lt;br /&gt;
         cm:spawn_character_to_pool(&lt;br /&gt;
             &amp;quot;wh2_dlc11_vmp_the_barrow_legion&amp;quot;,&lt;br /&gt;
             subtype_data.forename,&lt;br /&gt;
             subtype_data.family_name,&lt;br /&gt;
             subtype_data.clan_name,&lt;br /&gt;
             subtype_data.other_name,&lt;br /&gt;
             subtype_data.age,&lt;br /&gt;
             subtype_data.is_male,&lt;br /&gt;
             subtype_data.agent_type,&lt;br /&gt;
             subtype_data.agent_subtype,&lt;br /&gt;
             subtype_data.is_immortal,&lt;br /&gt;
             subtype_data.art_set_id&lt;br /&gt;
         )&lt;br /&gt;
     end&amp;lt;/code&amp;gt;&lt;br /&gt;
Yep! You can have tables within tables, maps within maps, loops within loops.&lt;br /&gt;
&lt;br /&gt;
And yes, you can access an index using &amp;lt;code&amp;gt;table.index_key&amp;lt;/code&amp;gt;, if that index is a ''string''. You obviously can’t do that with a number. That syntax is really common – using &amp;lt;code&amp;gt;table[&amp;quot;index_key&amp;quot;]&amp;lt;/code&amp;gt; to define an index’s value, and then accessing that using &amp;lt;code&amp;gt;table.index_key&amp;lt;/code&amp;gt;, though you can use them interchangeably; they’re literally the exact same thing, no functional difference.&lt;br /&gt;
&lt;br /&gt;
==== Other Loops ====&lt;br /&gt;
There are a couple other ways to loop, that don’t involve tables.&lt;br /&gt;
&lt;br /&gt;
The most common other one – especially in the Total War context – is a &amp;lt;code&amp;gt;while&amp;lt;/code&amp;gt; loop. For instance, we can see the following example in the wh_main_chs_chaos_start.lua file:&lt;br /&gt;
     &amp;lt;code&amp;gt;local x = desired_spawn_point[1]&lt;br /&gt;
     local y = desired_spawn_point[2]&lt;br /&gt;
     local valid = false&lt;br /&gt;
     &lt;br /&gt;
     while not valid do&lt;br /&gt;
         if is_valid_spawn_point(x, y) then&lt;br /&gt;
             valid = true&lt;br /&gt;
         else&lt;br /&gt;
             x = x + 1&lt;br /&gt;
             y = y + 1&lt;br /&gt;
         end&lt;br /&gt;
     end&amp;lt;/code&amp;gt;&lt;br /&gt;
In this instance, the &amp;lt;code&amp;gt;while&amp;lt;/code&amp;gt; chunk is run once entirely through, continuously, until “not valid” returns ''false'' – aka, until &amp;lt;code&amp;gt;valid&amp;lt;/code&amp;gt; is &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Don’t be frivolous with your use of &amp;lt;code&amp;gt;while&amp;lt;/code&amp;gt; loops – they should last no more than, like, 0.05s. Using them causes the rest of the Lua environment to come to a screeching halt, as basically nothing else can happen during a while loop.&lt;br /&gt;
&lt;br /&gt;
Similarly, you can use a &amp;lt;code&amp;gt;repeat&amp;lt;/code&amp;gt; loop, which is the same functionally – runs until a condition is met – except a &amp;lt;code&amp;gt;repeat&amp;lt;/code&amp;gt; loop will always run AT LEAST once, whereas a &amp;lt;code&amp;gt;while&amp;lt;/code&amp;gt; loop won’t run at all if the condition isn’t met. Let’s spy another CA example, this time in wh2_dlc11_treasure_maps.lua:&lt;br /&gt;
     &amp;lt;code&amp;gt;repeat&lt;br /&gt;
         random_number = cm:random_number(#level)&lt;br /&gt;
         ancillary = level[random_number]&lt;br /&gt;
     until(context:faction():ancillary_exists(ancillary) == false)&amp;lt;/code&amp;gt;&lt;br /&gt;
Which is loud-person talk for “go through random numbers until we find an ancillary in this array which doesn’t exist in this faction”.&lt;br /&gt;
&lt;br /&gt;
Again, repeat is pretty performance-heavy, as it holds up basically everything else. Don’t do big repeat loops, please. Please. PLEASE.&lt;br /&gt;
&lt;br /&gt;
Or, do. I don’t really care.&lt;br /&gt;
&lt;br /&gt;
==== CA Loops and Timing ====&lt;br /&gt;
There are some CA-defined methods to do a repeated function, or to delay a function, which do ''not'' hold up the entire environment like the above two loops. These callbacks are super helpful for repeated constant operation; for instance, I used a repeat_callback recently to print out the camera coordinates every half a second, so I could work on a custom cutscene. There was absolutely no performance drop, because Lua is beautiful.&lt;br /&gt;
&lt;br /&gt;
The two types are ''callback'' and, spoiler alert, ''repeat_callback''. The former simply delays a function by a time; the latter delays a function by that time, and repeats that same delay and function over and over again.&lt;br /&gt;
     &amp;lt;code&amp;gt;cm:callback(function()&lt;br /&gt;
         -- run this chunk ONCE after five seconds&lt;br /&gt;
     end,&lt;br /&gt;
     5)&lt;br /&gt;
 &lt;br /&gt;
     cm:repeat_callback(function()&lt;br /&gt;
         -- run this chunk every five seconds&lt;br /&gt;
     end,&lt;br /&gt;
     5)&amp;lt;/code&amp;gt;&lt;br /&gt;
For the campaign manager, these two functions are wrapped and the final parameter is in ''seconds''. However, for battle and frontend, these would be milliseconds.&lt;br /&gt;
 &lt;br /&gt;
     &amp;lt;code&amp;gt;-- BATTLE&lt;br /&gt;
     bm:callback(function()&lt;br /&gt;
         -- run this chunk ONCE after five seconds&lt;br /&gt;
     end,&lt;br /&gt;
     5000)&lt;br /&gt;
 &lt;br /&gt;
     bm:repeat_callback(function()&lt;br /&gt;
         -- run this chunk every five seconds&lt;br /&gt;
     end,&lt;br /&gt;
     5000)&lt;br /&gt;
 &lt;br /&gt;
     -- FRONTEND&lt;br /&gt;
     local timer_obj = get_tm()&lt;br /&gt;
     timer_obj:callback(function()&lt;br /&gt;
         -- run this chunk ONCE after five seconds&lt;br /&gt;
     end,&lt;br /&gt;
     5000)&lt;br /&gt;
 &lt;br /&gt;
     timer_obj:repeat_callback(function()&lt;br /&gt;
         -- run this chunk every five seconds&lt;br /&gt;
     end,&lt;br /&gt;
     5000)&amp;lt;/code&amp;gt;&lt;br /&gt;
There are lots of uses for these; namely, waiting for some UI to load, putting a timer on a quest battle for deployments, disabling/reenabling event feeds of a certain type, cutscene timing, and much else!&lt;br /&gt;
&lt;br /&gt;
[[Category:Lua Tutorials]]&lt;/div&gt;</summary>
		<author><name>Grimmys</name></author>
	</entry>
	<entry>
		<id>https://tw-modding.com/index.php?title=Lua:Scopes_%26_Stuff&amp;diff=1214</id>
		<title>Lua:Scopes &amp; Stuff</title>
		<link rel="alternate" type="text/html" href="https://tw-modding.com/index.php?title=Lua:Scopes_%26_Stuff&amp;diff=1214"/>
		<updated>2024-03-11T19:25:43Z</updated>

		<summary type="html">&lt;p&gt;Grimmys: Add LUA tutorial category&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;A super important concept in Lua is the concept of ''scope''. Every single variable made has a ''scope'', which is used to define where a variable can be accessed.&lt;br /&gt;
&lt;br /&gt;
By default, all variables are &amp;lt;code&amp;gt;global&amp;lt;/code&amp;gt;, which means they’re in the entire global environment. The global environment is a slightly-fancy way of saying “available within the entire program”. When writing Total War scripts, it’s a little suboptimal to use global variables, for a few reasons – 1) What if someone else wants to use a variable named &amp;lt;code&amp;gt;a&amp;lt;/code&amp;gt;, and you do as well? This would force you to have a fully unique name for every single variable everywhere. Kinda a pain! 2) Saving that variable globally is taking up memory, since that variable will never be destroyed. It will take a lot of work to actually cause performance issues, but it’s good to be mindful of. 3) What if we want our variable to be a secret? Huh? They can’t get our birthday present! ''gollum''&lt;br /&gt;
&lt;br /&gt;
And all this is where the keyword &amp;lt;code&amp;gt;local&amp;lt;/code&amp;gt; comes in. The &amp;lt;code&amp;gt;local&amp;lt;/code&amp;gt; keyword defines a specific scope for a variable, and prevents them from being a global variable.&lt;br /&gt;
 &amp;lt;code&amp;gt;function example()&lt;br /&gt;
     local var = &amp;quot;Hello World!&amp;quot;&lt;br /&gt;
     out(var)&lt;br /&gt;
 end&lt;br /&gt;
 &lt;br /&gt;
 example() → Hello World!&lt;br /&gt;
 out(var) → nil -- the variable &amp;quot;var&amp;quot; doesn't exist here!&amp;lt;/code&amp;gt;&lt;br /&gt;
In this example, the variable &amp;lt;code&amp;gt;var&amp;lt;/code&amp;gt; is defined within the function &amp;lt;code&amp;gt;example&amp;lt;/code&amp;gt;‘s definition. That means that &amp;lt;code&amp;gt;var&amp;lt;/code&amp;gt; is only available from ''where it is defined'' (ie. local var =) to ''where the scope ends''. In this case, the scope ''ends'' at the &amp;lt;code&amp;gt;end&amp;lt;/code&amp;gt; keyword.&lt;br /&gt;
&lt;br /&gt;
This is as good a time as any to look at the other ways scope can be defined. A variable can be scoped to the ''root'' of a script, or any number of nestled scopes within that root.&lt;br /&gt;
&lt;br /&gt;
Other key-words other than &amp;lt;code&amp;gt;function&amp;lt;/code&amp;gt; that define a scope (and their end point) are as follows:&lt;br /&gt;
&lt;br /&gt;
* do –&amp;lt;nowiki&amp;gt;[[ the scope ]]&amp;lt;/nowiki&amp;gt; end&lt;br /&gt;
* function function_name() –&amp;lt;nowiki&amp;gt;[[ the scope ]]&amp;lt;/nowiki&amp;gt; end&lt;br /&gt;
* if –&amp;lt;nowiki&amp;gt;[[ whatever ]]&amp;lt;/nowiki&amp;gt; then –&amp;lt;nowiki&amp;gt;[[ the scope ]]&amp;lt;/nowiki&amp;gt; end&lt;br /&gt;
* while –&amp;lt;nowiki&amp;gt;[[ whatever ]]&amp;lt;/nowiki&amp;gt; then –&amp;lt;nowiki&amp;gt;[[ the scope ]]&amp;lt;/nowiki&amp;gt; end&lt;br /&gt;
&lt;br /&gt;
Let’s take a slightly-complicated look at that:&lt;br /&gt;
 &amp;lt;code&amp;gt;local a = 5 -- visible to everything BELOW this line!&lt;br /&gt;
 &lt;br /&gt;
 function example_thing()&lt;br /&gt;
     local b = a -- visible to everything BELOW this line, until the &amp;quot;end&amp;quot; that matches &amp;quot;function&amp;quot;&lt;br /&gt;
     do &lt;br /&gt;
         local c = 15 -- visible to everything BELOW this line, until the &amp;quot;end&amp;quot; that matches &amp;quot;do&amp;quot;&lt;br /&gt;
         out(c) → 15&lt;br /&gt;
         out(b) → 5&lt;br /&gt;
     end&lt;br /&gt;
     out(b) → 5&lt;br /&gt;
     -- c is NOT available here!&lt;br /&gt;
 end&lt;br /&gt;
 &lt;br /&gt;
 -- b and c are NOT available here!&lt;br /&gt;
 out(a) → 5&amp;lt;/code&amp;gt;&lt;br /&gt;
This is a good point as any to explain two things, and issue two directives:&lt;br /&gt;
&lt;br /&gt;
# ALWAYS use the keyword &amp;lt;code&amp;gt;local&amp;lt;/code&amp;gt;.&lt;br /&gt;
# ALWAYS use good indentations! Scopes should be easily detected.&lt;br /&gt;
&lt;br /&gt;
Be smart with where exactly the term “local” is used – you’ll pick up how later on as you go and pick my brain, but for now, understand that you must ALWAYS put the keyword &amp;lt;code&amp;gt;local&amp;lt;/code&amp;gt; before a variable!&lt;br /&gt;
&lt;br /&gt;
As you can see with the example_thing() function above, proper indentation is a GREAT way to visibly see scopes and quickly tell where a variable is and isn’t available.&lt;br /&gt;
&lt;br /&gt;
[[Category:Lua Tutorials]]&lt;/div&gt;</summary>
		<author><name>Grimmys</name></author>
	</entry>
	<entry>
		<id>https://tw-modding.com/index.php?title=Lua:Expressions_%26_Operators&amp;diff=1213</id>
		<title>Lua:Expressions &amp; Operators</title>
		<link rel="alternate" type="text/html" href="https://tw-modding.com/index.php?title=Lua:Expressions_%26_Operators&amp;diff=1213"/>
		<updated>2024-03-11T19:25:06Z</updated>

		<summary type="html">&lt;p&gt;Grimmys: Add LUA tutorial category&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;br /&gt;
As we’ve seen, Lua is made up of &amp;lt;code&amp;gt;chunks&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;statements&amp;lt;/code&amp;gt;. Statements can contain variables, and all variables have a type, though it can change at any point.&lt;br /&gt;
&lt;br /&gt;
Expressions are the section of a statement that, essentially, tell Lua ''what to do''. They come in a billion different shapes and sizes. For now, we’ll cover all the basics you’ll need, and some basics you really don’t need but I’ll hand it to you anyway, and we’ll go back and review some older stuff. Here we go!&lt;br /&gt;
&lt;br /&gt;
==== Math Operators ====&lt;br /&gt;
Sweet. This is what all of those quizzes in grade school trained you for. We have the big four from algebra – addition, subtraction, multiplication, and division.&lt;br /&gt;
     &amp;lt;code&amp;gt;out(2 + 3) → 5&lt;br /&gt;
     out(5 - 1) → 4&lt;br /&gt;
     out(16 * 3) → 48&lt;br /&gt;
     out(9 / 3) → 3&amp;lt;/code&amp;gt;&lt;br /&gt;
We can also use a &amp;lt;code&amp;gt;-&amp;lt;/code&amp;gt; to ''negate'' a value, or, in simple terms, turn a positive number into a negative and vice versa.&lt;br /&gt;
     &amp;lt;code&amp;gt;a = 10&lt;br /&gt;
     b = -20&lt;br /&gt;
     out( -a ) → -10&lt;br /&gt;
     out( -b ) → 20&amp;lt;/code&amp;gt;&lt;br /&gt;
We also have a couple other fun math things. We can raise numbers to any power, using an exponential expression.&lt;br /&gt;
     &amp;lt;code&amp;gt;a = 2&lt;br /&gt;
     b = 4&lt;br /&gt;
     c = 3&lt;br /&gt;
     out( a^a ) → 4&lt;br /&gt;
     out( b^c ) → 64&lt;br /&gt;
     out( 64^0.5 ) → 8 -- getting the square root of a number!&amp;lt;/code&amp;gt;&lt;br /&gt;
We can also use some modulo math. It’s a way of dividing two numbers that gives you the amount ''remaining'', and it’s a great way to read if a number is a ''multiple'' of another.&lt;br /&gt;
     &amp;lt;code&amp;gt;out(8 % 2) → 0 -- 8/2 = 4, and divides evenly, so nothing is remaining!&lt;br /&gt;
     out(7 % 2) → 1 -- 7/2. &amp;quot;6/2&amp;quot; divides evenly, so we subtract 6 from 7, and get &amp;quot;1&amp;quot; as the remainder!&lt;br /&gt;
     out(8 % 3) → 2 -- 8/3. &amp;quot;6/3&amp;quot; divides evenly, so we subtract 6 from 8, and get &amp;quot;2&amp;quot; as the remainder.&amp;lt;/code&amp;gt;&lt;br /&gt;
As said, it’s a great way to read if a number is a multiple of another. If a modulo expression returns “0”, that means it divided evenly, and is therefore a multiple of the number divided by.&lt;br /&gt;
&lt;br /&gt;
And that’s math!&lt;br /&gt;
&lt;br /&gt;
==== Comparison Operators ====&lt;br /&gt;
This sounds a lot more complicated than “math”, eh? It’s not that complicated – we’re comparing how two variables relate to one another, using expressions we’ve all seen before. The list of comparison operators are as follows:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt; — “less than”&lt;br /&gt;
* &amp;gt; — “greater than”&lt;br /&gt;
* &amp;lt;= — “less than or equal to”&lt;br /&gt;
* &amp;gt;= “greater than or equal to”&lt;br /&gt;
* == “equal to”&lt;br /&gt;
* ~= “not equal to”&lt;br /&gt;
&lt;br /&gt;
All of these expressions result in a boolean value, that is, it tells you if the result of what you're saying is true or false.&lt;br /&gt;
     &amp;lt;code&amp;gt;a = 10&lt;br /&gt;
     b = 7 + 3&lt;br /&gt;
     out(a == b) → true -- they ARE equal!&lt;br /&gt;
     out(a ~= b) → false -- they ARE NOT not equal (weird, I know)!&lt;br /&gt;
 &lt;br /&gt;
     c = 8&lt;br /&gt;
     d = 7&lt;br /&gt;
     &lt;br /&gt;
     out(c &amp;gt; d) → true -- 8 is greater than 7&lt;br /&gt;
     out(c &amp;lt; d) → false -- 8 is NOT less than 7&amp;lt;/code&amp;gt;&lt;br /&gt;
It’s important to note that Lua will consider different types to be different values. A string (ie a group of characters, like the word &amp;quot;hello&amp;quot; or the character sequence &amp;quot;15&amp;quot;) and a number will always be different. Lua will throw an error if you attempt to compare – using less-than or greater-than – any two separate types. Lua will not throw an error for “==” and “~=”, and if they are separate types, they will always be inequal.&lt;br /&gt;
     &amp;lt;code&amp;gt;a = 15&lt;br /&gt;
     b = &amp;quot;15&amp;quot;&lt;br /&gt;
     out(a == b) → false -- they are different types!&lt;br /&gt;
     out(a &amp;gt;= b) → error (attempt to compare number with string)&amp;lt;/code&amp;gt;&lt;br /&gt;
Do note that you can compare strings using greater or less than, but it compares the alphanumerical order of the first character. “0” is less than every number or letter, whereas “a” is greater than every number and less than every letter, and “z” is greater than every number or letter. Again, not really important, but you came here to read me ramble on about random stuff.&lt;br /&gt;
&lt;br /&gt;
And that ends our comparison operators!&lt;br /&gt;
&lt;br /&gt;
==== Logical Operators ====&lt;br /&gt;
Next up are our logical operators! We have three operators to concern ourselves with here: ''and'', ''or'', and ''not''.&lt;br /&gt;
&lt;br /&gt;
''Not'', as a logical operator, is pretty simple and super handy. It basically converts the value to the right of it into a boolean, and reverses it. Any value other than &amp;lt;code&amp;gt;nil&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;false&amp;lt;/code&amp;gt; will be converted into &amp;lt;code&amp;gt;false&amp;lt;/code&amp;gt;; &amp;lt;code&amp;gt;nil&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;false&amp;lt;/code&amp;gt; will be converted to &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt;. Let’s take a look:&lt;br /&gt;
     &amp;lt;code&amp;gt;a = true&lt;br /&gt;
     b = nil&lt;br /&gt;
     out(not b) → true -- prints a double negative - not false, so true&lt;br /&gt;
     out(not a) → false -- reverses the value of &amp;quot;true&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
     c = 100&lt;br /&gt;
     out(c) → 100&lt;br /&gt;
     out(not not c) → true -- c is a number, &amp;quot;not c&amp;quot; would become &amp;quot;false&amp;quot;, and &amp;quot;not false&amp;quot; would become &amp;quot;true&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
The operators ''and'' and ''or'' are the hearts of a lot of logic in Lua. “If this and this, then do this”.&lt;br /&gt;
     &amp;lt;code&amp;gt;a = 15&lt;br /&gt;
     b = false&lt;br /&gt;
     if a == 15 and not b then -- &amp;quot;if a is equal to the number fifteen, and &amp;quot;not b&amp;quot; returns true, then ... &amp;quot;&lt;br /&gt;
         out(&amp;quot;It does the thing!&amp;quot;) -- &amp;quot; ... print the text! &amp;quot;&lt;br /&gt;
     end&amp;lt;/code&amp;gt;&lt;br /&gt;
You’ll practically always see these two used in this way, for ''conditional statements'' like that – if these conditions work out, then do this other thing.&lt;br /&gt;
&lt;br /&gt;
==== Homeless Operators ====&lt;br /&gt;
I don’t really have a category for these two operators, but they’re incredibly important.&lt;br /&gt;
&lt;br /&gt;
First off, we have concatenation, which we’ve seen before. It’s a way to add two strings of characters together, and make them into one happy family, using a simple pair of dots.&lt;br /&gt;
     &amp;lt;code&amp;gt;a = &amp;quot;Hello&amp;quot;&lt;br /&gt;
     b = &amp;quot;World!&amp;quot;&lt;br /&gt;
     out(a .. &amp;quot; &amp;quot; .. b) → Hello World!&amp;lt;/code&amp;gt;&lt;br /&gt;
A couple of notes real quick – I have the blank space in a string in the middle, to make sure it doesn’t print “HelloWorld!”. Also, I like to add spaces on either side of my concatenation operator, but that’s personal taste, this would also be valid:&lt;br /&gt;
     &amp;lt;code&amp;gt;out(a..&amp;quot; &amp;quot;..b) → Hello World!&amp;lt;/code&amp;gt;&lt;br /&gt;
And lastly, we have one more operator, and this time for the table type. The character &amp;lt;code&amp;gt;#&amp;lt;/code&amp;gt; can be used to read the number of entries within an array (NOTE: an array is a set of different elements under one variable name).&lt;br /&gt;
 It’s pretty awesome, let me show you:&lt;br /&gt;
     &amp;lt;code&amp;gt;table = {&amp;quot;this&amp;quot;, &amp;quot;is&amp;quot;, &amp;quot;an&amp;quot;, &amp;quot;example&amp;quot;, &amp;quot;array&amp;quot;}&lt;br /&gt;
     out(#table) → 5 -- there are five strings within the table!&amp;lt;/code&amp;gt;&lt;br /&gt;
Please note that you really shouldn’t use the &amp;lt;code&amp;gt;#&amp;lt;/code&amp;gt; operator if the table is not definitely an array. I’ll show you why using it on maps might mess something up:&lt;br /&gt;
     &amp;lt;code&amp;gt;table = {&lt;br /&gt;
         [1] = &amp;quot;test&amp;quot;,&lt;br /&gt;
         [2] = &amp;quot;example&amp;quot;,&lt;br /&gt;
         [5] = &amp;quot;boom&amp;quot;,&lt;br /&gt;
         [7000] = &amp;quot;woo&amp;quot;,&lt;br /&gt;
         [3] = &amp;quot;argh&amp;quot;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     out(#table) → 7000&amp;lt;/code&amp;gt;&lt;br /&gt;
In technicalities, it’s doing that because it’s reading the ''highest index in that table'', or the highest numerical key. Those are assigned automatically, in order, for arrays; in maps, there’s no such guarantee.&lt;br /&gt;
&lt;br /&gt;
==== Challenge 1 ====&lt;br /&gt;
As before, go to repl.it and mess with everything.&lt;br /&gt;
&lt;br /&gt;
Some suggestions on what to try:&lt;br /&gt;
&lt;br /&gt;
* Make an array out of various strings, concatenate them together using &amp;lt;code&amp;gt;table[1]&amp;lt;/code&amp;gt; and so on.&lt;br /&gt;
* Apply arithmetic to a series of 3 or more numbers&lt;br /&gt;
* Compare the length of two separate tables&lt;br /&gt;
&lt;br /&gt;
[[Category:Lua Tutorials]]&lt;/div&gt;</summary>
		<author><name>Grimmys</name></author>
	</entry>
	<entry>
		<id>https://tw-modding.com/index.php?title=Lua:Variables_%26_Types&amp;diff=1212</id>
		<title>Lua:Variables &amp; Types</title>
		<link rel="alternate" type="text/html" href="https://tw-modding.com/index.php?title=Lua:Variables_%26_Types&amp;diff=1212"/>
		<updated>2024-03-11T19:23:58Z</updated>

		<summary type="html">&lt;p&gt;Grimmys: Add LUA tutorial category&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;br /&gt;
''NOTE: I recommend you have the Devtool Console handy to mess around with some of the stuff covered here.''&lt;br /&gt;
&lt;br /&gt;
Following the concept of chunks and statements, the next most important subject to cover is variables, and types.&lt;br /&gt;
&lt;br /&gt;
Variable: A custom-made keyword that can be used to represent a value&lt;br /&gt;
&lt;br /&gt;
Type: The sort of value that is in a variable. Lua types include: boolean, string, number, table, nil, function. There are more, but we won’t need them.&lt;br /&gt;
&lt;br /&gt;
But before going deeper into a definition, let’s look at an example:&lt;br /&gt;
 &amp;lt;code&amp;gt;a = 10&lt;br /&gt;
 b = 5&lt;br /&gt;
 c = a + b&amp;lt;/code&amp;gt;&lt;br /&gt;
We can see that each of those letters in the chunk above is a variable, which are each assigned a value. In this case, variable &amp;lt;code&amp;gt;a&amp;lt;/code&amp;gt; is assigned the value &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;, variable &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt; is assigned the value &amp;lt;code&amp;gt;5&amp;lt;/code&amp;gt;, and the variable &amp;lt;code&amp;gt;c&amp;lt;/code&amp;gt; is assigned the &amp;lt;code&amp;gt;value of a plus the value of b&amp;lt;/code&amp;gt;. This instance (c = a + b) works a lot like algebra – you aren’t making “c = ab”, but you’re adding the value of a (10) to the value of b (5), to get the result of 15.&lt;br /&gt;
&lt;br /&gt;
The coolest thing about variables is their dynamism. They can be assigned to any type, change to any type, and they can infinitely change values. Let’s take the above code, and mess with it a little bit.&lt;br /&gt;
&lt;br /&gt;
''NOTE: From this point on, you’ll see → after out() calls. This is to specify what text is actually output.''&lt;br /&gt;
 &amp;lt;code&amp;gt;a = 10&lt;br /&gt;
 b = 5&lt;br /&gt;
 c = a + b&lt;br /&gt;
 &lt;br /&gt;
 out(a) → 10&lt;br /&gt;
 out(b) → 5&lt;br /&gt;
 out(c) → 15&lt;br /&gt;
 &lt;br /&gt;
 a = 25&lt;br /&gt;
 out(a) → 25&lt;br /&gt;
 &lt;br /&gt;
 out(c) → 15&lt;br /&gt;
 &lt;br /&gt;
 c = a + b&lt;br /&gt;
 out(c) → 30&amp;lt;/code&amp;gt;&lt;br /&gt;
I wanted to point out an important thing with this example. If a variable is assigned to the values of some other variables (c = a + b), it will do the calculation and assignment the moment that the statement is called. If either variable (a or b) is changed after the assignment statement, the assigned variable’s (c) value (15) won’t change. It takes the ''variable’s value'', not the ''variable itself''.&lt;br /&gt;
&lt;br /&gt;
So, we see here that variables can be numbers, which is one of the primary types in Lua.&lt;br /&gt;
&lt;br /&gt;
Number: ''any'' numerical value, within a specific number range (a much bigger number than needs to be worried about)&lt;br /&gt;
&lt;br /&gt;
As we saw above, we can perform some basic arithmetic on numbers.&lt;br /&gt;
 &amp;lt;code&amp;gt;a = 5&lt;br /&gt;
 b = 2 - 0.34&lt;br /&gt;
 c = a + b&lt;br /&gt;
 d = c * 2&lt;br /&gt;
 e = d / 3&lt;br /&gt;
 &lt;br /&gt;
 out(c) → 7.56&lt;br /&gt;
 out(d) → 15.12&lt;br /&gt;
 out(e) → 5.04&amp;lt;/code&amp;gt;&lt;br /&gt;
String: ''any'' alphanumerical value, within quotation marks (“” or ”). Similar to numbers, size ''does not matter'', Lua can handle millions of characters within a string.&lt;br /&gt;
&lt;br /&gt;
Like arithmetic for numbers, one can concatenate strings (along with many other stuffs!) to combine several, using the &amp;lt;code&amp;gt;..&amp;lt;/code&amp;gt; operator.&lt;br /&gt;
 &amp;lt;code&amp;gt;a = “This “; b = “is “; c = “an “; d = “example.”&lt;br /&gt;
 out(a .. b .. c .. d) → This is an example.&amp;lt;/code&amp;gt;&lt;br /&gt;
''NOTE: Yes, you can have several statements on the same line in Lua! The semi-colons are not necessary, I added them for extra readability.''&lt;br /&gt;
&lt;br /&gt;
While on the subject, you can concat (cool-kid for concatenate) string literals and variables.&lt;br /&gt;
 &amp;lt;code&amp;gt;a = &amp;quot;example&amp;quot;&lt;br /&gt;
 out(&amp;quot;This is an &amp;quot; .. a) → This is an example&amp;lt;/code&amp;gt;&lt;br /&gt;
Boolean: a &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;false&amp;lt;/code&amp;gt; value.&lt;br /&gt;
 &amp;lt;code&amp;gt;a = false&lt;br /&gt;
 out(a) → false&lt;br /&gt;
 out(a == false) → true&amp;lt;/code&amp;gt;&lt;br /&gt;
The above probably looks a little weird, but that’s because we’re learning a new operator! The &amp;lt;code&amp;gt;==&amp;lt;/code&amp;gt; operator checks for ''equality'', whereas the &amp;lt;code&amp;gt;=&amp;lt;/code&amp;gt; operator ''assigns a value''. The final statement above reads “output the result of a == false”. Since &amp;lt;code&amp;gt;a&amp;lt;/code&amp;gt; DOES equal false, it prints “true”.&lt;br /&gt;
&lt;br /&gt;
It’s very important to note that any variable can be ''treated'' as a boolean, such as when using the “if something then” statement, or by comparing it to a boolean. If a non-boolean variable is treated as a boolean, it will be converted to &amp;lt;code&amp;gt;false&amp;lt;/code&amp;gt; if the value is &amp;lt;code&amp;gt;nil&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;false&amp;lt;/code&amp;gt;; otherwise, it will be converted to &amp;lt;code&amp;gt;true&amp;lt;/code&amp;gt;.&lt;br /&gt;
 &amp;lt;code&amp;gt;a = 0&lt;br /&gt;
 b = nil&lt;br /&gt;
 out(a) → 0&lt;br /&gt;
 out(a == false) → false &lt;br /&gt;
 out(b == false) → true&amp;lt;/code&amp;gt;&lt;br /&gt;
In this case, &amp;lt;code&amp;gt;a&amp;lt;/code&amp;gt; does NOT equal &amp;lt;code&amp;gt;false&amp;lt;/code&amp;gt;, because it has a value to it that isn’t &amp;lt;code&amp;gt;false&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;nil&amp;lt;/code&amp;gt;. By the same card, &amp;lt;code&amp;gt;b&amp;lt;/code&amp;gt; DOES equal &amp;lt;code&amp;gt;false&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
You’re probably asking by now, what IS nil? I’ve mentioned it a number of times already, you’re probably ready to lear about it. Here we go!&lt;br /&gt;
&lt;br /&gt;
Nil: the absence of data.&lt;br /&gt;
&lt;br /&gt;
If one were to try to print a ''non-existent'' variable, the result would be &amp;lt;code&amp;gt;nil&amp;lt;/code&amp;gt;. That’s because there is no data for that variable.&lt;br /&gt;
 &amp;lt;code&amp;gt;out(a) → nil&lt;br /&gt;
 a = 5&lt;br /&gt;
 out(a) → 5&amp;lt;/code&amp;gt;&lt;br /&gt;
Nil is a good way to check whether or not something exists, and we’ll, towards the bottom of this lesson, talk about how to type-check this data in our scripts to see if variables are NOT nil, and thus exist.&lt;br /&gt;
&lt;br /&gt;
Nil is also a good way to clear away variables that you don’t want to use anymore. There’s a more realistic way of doing it, and this probably won’t be necessary for most of what you will be doing, but I like to give a full knowledge.&lt;br /&gt;
 &amp;lt;code&amp;gt;a = 5&lt;br /&gt;
 out(a) → 5&lt;br /&gt;
 a = nil -- Memory deallocated, bye &amp;quot;a&amp;quot;!&lt;br /&gt;
 out(a) → nil&amp;lt;/code&amp;gt;&lt;br /&gt;
Lastly, it’s important to note that &amp;lt;code&amp;gt;nil&amp;lt;/code&amp;gt; is not the same as &amp;lt;code&amp;gt;null&amp;lt;/code&amp;gt;, though they look quick similar. We’ll cover that soon-ish, when we get into more CA script interfaces (like FACTION_SCRIPT_INTERFACE that we saw a few lessons ago).&lt;br /&gt;
&lt;br /&gt;
Function: a definition for a chunk that can be called at any point, after being defined.&lt;br /&gt;
&lt;br /&gt;
There are two types of functions – an anonymous function, and a named function. An anonymous function has no name (clearly), so it cannot be called further on in the script. We use anonymous functions relatively frequently, but our focus now will be on named functions, which are functions assigned to a variable.&lt;br /&gt;
 &amp;lt;code&amp;gt;a = 10&lt;br /&gt;
 example = out&lt;br /&gt;
 example(a) → 10&amp;lt;/code&amp;gt;&lt;br /&gt;
Yes, that’s valid! You can actually assign a variable to a function like, it’s pretty cool! We have syntactic sugar for assigning a variable to a function, however, and it’s more common to see script like that:&lt;br /&gt;
 &amp;lt;code&amp;gt;function example(text)&lt;br /&gt;
     out(text)&lt;br /&gt;
 end&lt;br /&gt;
 &lt;br /&gt;
 example(&amp;quot;Testing!&amp;quot;) → Testing!&lt;br /&gt;
 &lt;br /&gt;
 example(&amp;quot;A Cooler Test!&amp;quot;) → A Cooler Test!&amp;lt;/code&amp;gt;&lt;br /&gt;
As an added bonus, we’re getting a quick sneak peak at one of the upcoming tutorials: parameters and arguments, for functions. In the above function, “text” is a parameter for &amp;lt;code&amp;gt;example()&amp;lt;/code&amp;gt;, which is then passed along to &amp;lt;code&amp;gt;out&amp;lt;/code&amp;gt; and triggers that function within the chunk.&lt;br /&gt;
&lt;br /&gt;
Table: a collection of more than one piece of data.&lt;br /&gt;
&lt;br /&gt;
There are several types of tables, which we’ll cover later on. I’d like to first look at the ''array'' version of tables, the simplest and most common.&lt;br /&gt;
 &amp;lt;code&amp;gt;a = 5&lt;br /&gt;
 b = 10&lt;br /&gt;
 c = 17&lt;br /&gt;
 &lt;br /&gt;
 table = {&lt;br /&gt;
     a,&lt;br /&gt;
     b,&lt;br /&gt;
     c&lt;br /&gt;
 } -- assign the three *values* of the variables to the table&lt;br /&gt;
     &lt;br /&gt;
 out(table[1]) → 5 -- Lua tables start at index 1: we're showing the first element of our table, that is, the item on index 1!&lt;br /&gt;
 out(table[2]) → 10&lt;br /&gt;
 out(table[3]) → 17&lt;br /&gt;
 out(table[4]) → nil -- doesn't exist!&amp;lt;/code&amp;gt;&lt;br /&gt;
''NOTE for programmers:'' ''Arrays in Lua start at index ONE, not index ZERO. &amp;lt;code&amp;gt;table[0]&amp;lt;/code&amp;gt; would be invalid in the above example! If you get into other programming languages, you'll understand why explaining this was important.''&lt;br /&gt;
&lt;br /&gt;
Arrays are numbered automatically, so it really reads “the first index of table is 5, the second index of table is 10”, and so on. You ''access'' those indexes by using the &amp;lt;code&amp;gt;[num\]&amp;lt;/code&amp;gt; operator, which we’ll look further at in the next tables tutorial later on. The reason this works, however, is because Lua is automatically numbering these values, giving them a ''key''. When you make an array like that, Lua reads it more like the following:&lt;br /&gt;
 &amp;lt;code&amp;gt;a = 5&lt;br /&gt;
 b = 10&lt;br /&gt;
 c = 17&lt;br /&gt;
 &lt;br /&gt;
 table = {&lt;br /&gt;
     [1] = a,&lt;br /&gt;
     [2] = b,&lt;br /&gt;
     [3] = c&lt;br /&gt;
 }&amp;lt;/code&amp;gt;&lt;br /&gt;
The other major type of tables is a map, which works by manually assigning the key of a value instead of letting Lua automatically number them, like in arrays.&lt;br /&gt;
 &amp;lt;code&amp;gt;a = 5&lt;br /&gt;
 b = 10&lt;br /&gt;
 c = 15&lt;br /&gt;
 &lt;br /&gt;
 table = {&lt;br /&gt;
     [&amp;quot;five&amp;quot;] = a,&lt;br /&gt;
     [&amp;quot;ten&amp;quot;] = b,&lt;br /&gt;
     [&amp;quot;fifteen&amp;quot;] = c&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 out(table[&amp;quot;five&amp;quot;]) → 5&lt;br /&gt;
 out(table[&amp;quot;ten&amp;quot;]) → 10&lt;br /&gt;
 out(table[&amp;quot;fifteen&amp;quot;]) → 15&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Maps will come into some great use pretty soon, but for now I just wanted to introduce you to how they look.&lt;br /&gt;
&lt;br /&gt;
For now, you’ve done well, and I haven’t even challenged you yet!&lt;br /&gt;
&lt;br /&gt;
==== Challenge 1 ====&lt;br /&gt;
Go to repl.it (covered in the Foreword), and mess with all this stuff! Use &amp;lt;code&amp;gt;print(whatever)&amp;lt;/code&amp;gt;, where whatever is what you want to print, in lieu of &amp;lt;code&amp;gt;out()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Type-Checking ====&lt;br /&gt;
And before we say goodbye, let’s look at a few more CA functions. These ones can type-check for us, seeing if a variable is, for instance, a string.&lt;br /&gt;
&lt;br /&gt;
The list is as follows:&lt;br /&gt;
&lt;br /&gt;
* is_nil(variable)&lt;br /&gt;
* is_string(variable)&lt;br /&gt;
* is_number(variable)&lt;br /&gt;
* is_boolean(variable)&lt;br /&gt;
* is_function(variable)&lt;br /&gt;
* is_table(variable)&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;code&amp;gt;a = 5&lt;br /&gt;
 b = nil&lt;br /&gt;
 c = {1, 2, 3, 5, 70}&lt;br /&gt;
 function d() end&lt;br /&gt;
 &lt;br /&gt;
 out(is_number(a)) → true    &lt;br /&gt;
 out(is_nil(b)) → true&lt;br /&gt;
 out(is_table(c)) → true&lt;br /&gt;
 out(is_function(d)) → true&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:Lua Tutorials]]&lt;/div&gt;</summary>
		<author><name>Grimmys</name></author>
	</entry>
	<entry>
		<id>https://tw-modding.com/index.php?title=Lua:Chunks_%26_Statements&amp;diff=1211</id>
		<title>Lua:Chunks &amp; Statements</title>
		<link rel="alternate" type="text/html" href="https://tw-modding.com/index.php?title=Lua:Chunks_%26_Statements&amp;diff=1211"/>
		<updated>2024-03-11T19:23:25Z</updated>

		<summary type="html">&lt;p&gt;Grimmys: Add LUA tutorial category&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The first two terms we’ll look at are chunks and statements. When Lua is brought to its basic skeletal structure, that’s all it is – chunks of statements.&lt;br /&gt;
&lt;br /&gt;
Statement: A declaration, a thing-to-be-done, a command that Lua will run Chunk: A sequence of statements, from an entire file to a single line of data&lt;br /&gt;
&lt;br /&gt;
Every chunk is a to-do list, and a statement is an objective on that list. You can have to-do lists of all shapes and sizes, and each thing that needs to be done can be small – “brushing your teet” – or huge – “spend way too much money on transmission repairs”. No, I’m not still salty about the money I spent on transmission repairs, why do you ask?&lt;br /&gt;
&lt;br /&gt;
The Lua interpreter divides everything it takes into specific chunks, which we’ll look at later on. For now, we understand the term chunk – a to-do list.&lt;br /&gt;
&lt;br /&gt;
Within each chunk is one or more statements. A statement is one coherent thought or action within Lua. Something like this can be one statement:&lt;br /&gt;
 &amp;lt;code&amp;gt;a = 1&amp;lt;/code&amp;gt;&lt;br /&gt;
Or, this can be one statement:&lt;br /&gt;
 &amp;lt;code&amp;gt;a = 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 - 1 / 70 * 300 + 5180 - 418 + 405&amp;lt;/code&amp;gt;&lt;br /&gt;
That is, one bit of data that Lua has to evaluate and run.&lt;br /&gt;
&lt;br /&gt;
Remember the term “chunk” – we’ll be covering how they’re defined later on, when we look at some more keywords.&lt;br /&gt;
&lt;br /&gt;
[[Category:Lua Tutorials]]&lt;/div&gt;</summary>
		<author><name>Grimmys</name></author>
	</entry>
	<entry>
		<id>https://tw-modding.com/index.php?title=Lua:Essential_Setup&amp;diff=1210</id>
		<title>Lua:Essential Setup</title>
		<link rel="alternate" type="text/html" href="https://tw-modding.com/index.php?title=Lua:Essential_Setup&amp;diff=1210"/>
		<updated>2024-03-11T18:11:52Z</updated>

		<summary type="html">&lt;p&gt;Grimmys: Add LUA tutorial category&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Step one – we’ve gotta grab some tools!&lt;br /&gt;
&lt;br /&gt;
I’ll be covering a handful of setups that I find vital for programming in Lua. First off, I’ll talk about a pretty well-known product – Notepad++. I personally no longer use it, and at this point prefer Visual Studio Code for all my Lua needs, but I’ll go over both for taste. They’ll both be able to do what you need.&lt;br /&gt;
&lt;br /&gt;
This tutorial assumes you already have RPFM downloaded. If you don’t yet, go grab it.&lt;br /&gt;
&lt;br /&gt;
==== Notepad++ Setup ====&lt;br /&gt;
One of the most well-known text editing products out there is Notepad++. As the name implies, it’s kinda like regular Notepad, but actually good and can do stuff. It has features like global searching, opening a folder and viewing the contents as a tree-view, and is all around a pretty solid product.&lt;br /&gt;
&lt;br /&gt;
I’ve never used Notepad++ for actually writing and editing .lua files – it was for a while primarily what I used to search through and read CA .lua files. I now use VSCode for both of those efforts – editing and searching through files – but many people prefer to use Notepad++ so here I am discussing it.&lt;br /&gt;
&lt;br /&gt;
If interested, grab Notepad++. Download it, install it wherever.&lt;br /&gt;
&lt;br /&gt;
While you wait for Notepad++ to finish installing, we’re gonna make a script dump – a location on your PC where you put all of CA’s scripts, so you can quickly reference them. You should open RPFM, and use the &amp;lt;code&amp;gt;&amp;quot;Open All CA Packs&amp;quot;&amp;lt;/code&amp;gt; command (after making sure you have the proper game selected, under, well, Game Selected).&lt;br /&gt;
&lt;br /&gt;
Now, go find a spot to create a script dump folder. You’ll need to grab all CA’s vanilla scripts and put them somewhere on your PC – I recommend an HDD, if you have two drives! – in order to easily browse through their files. Once you have one created and pinned and you know where it is (mine is S:/Total War Dumps/Script Dumps), go back to RPFM, and go find the main “script” directory. Right-click it and select “Extract”, and target the new folder you just made.&lt;br /&gt;
&lt;br /&gt;
And, boom! You now have a script dump. I personally organize it as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;S:/Total War Dumps/Script Dumps/WH2/%today's date or patch name%/script&amp;lt;/code&amp;gt;. I’ll use /3K/ or else for whatever game I’m using. This helps me quickly keep track of older patches, when I need to compare files between versions.&lt;br /&gt;
&lt;br /&gt;
Lastly, open up Notepad++, and use &amp;lt;code&amp;gt;&amp;quot;File -&amp;gt; Open Folder As Workspace...&amp;quot;&amp;lt;/code&amp;gt;. Target your renamed “script” folder within the script dump directory, and you’ll notice that the directory appears on the left-hand side. If you right-click the main folder over there, and press &amp;lt;code&amp;gt;&amp;quot;Find in Files...&amp;quot;&amp;lt;/code&amp;gt;, you’ll be able to global-search all CA scripts. Incredibly handy for looking at their usage of commands, or to see any references to, say, an agent subtype key.&lt;br /&gt;
&lt;br /&gt;
And that’s Notepad++! You can make scripts in there as well, using “File -&amp;gt; New” and naming it “whatever_you_want.lua” when saving. Though, I personally prefer using Visual Studio Code for programming in Lua (and it’s what I’m typing this tutorial in), and that’s where I have my IDE setup. If you’re interested in VSCode, continue reading, if not carry on to the Hello World tutorial!&lt;br /&gt;
&lt;br /&gt;
==== Visual Studio Code Setup ====&lt;br /&gt;
Clearly, one needs Visual Studio Code. Go get Visual Studio Code.&lt;br /&gt;
&lt;br /&gt;
You got it? No? Why are you reading this?&lt;br /&gt;
&lt;br /&gt;
Okay, now you’re ready? Good.&lt;br /&gt;
&lt;br /&gt;
Visual Studio Code (VSC or VSCode, also) is a super nice program in my opinion, and a nice big brother to Notepad++. It has a lot of extra functionality that NP++ does not, and allows a lot of flexibility in that regard. VSC has greater tab support and multi-window support, it’s easier to use Workspaces in VSC (again in my opinion) than in NP++, and the extensions and further features and settings add a lot that helps me with my programming.&lt;br /&gt;
&lt;br /&gt;
You can save “code workspace” files, which allow you to easily access several folders or files that you have saved for one project, as well as have different settings for different workspaces. I can jump really easily between, say, my Return of the Lichemaster code workspace, my CA Script Dump workspace, and my Other Currently Secret Things code workspace, with only a couple clicks. It has a really pretty dark mode, and the syntax highlighting for Lua is gorgeous, in my opinion.&lt;br /&gt;
&lt;br /&gt;
You can save “code workspace” files, which allow you to easily access several folders or files that you have saved for one project, as well as have different settings for different workspaces. I can jump really easily between, say, my Return of the Lichemaster code workspace, my CA Script Dump workspace, and my Other Currently Secret Things code workspace, with only a couple clicks. It has a really pretty dark mode, and the syntax highlighting for Lua is gorgeous, in my opinion.&lt;br /&gt;
&lt;br /&gt;
To use VSCode to its fullest, I suggest solid integration within your RPFM MyMod folder. In my MyMod folder, I have a folder for each of the mods, and then the .pack that RPFM tracks and saves, and also a .code_workspace for each important workspace. I can use &amp;lt;code&amp;gt;File -&amp;gt; Open Workspace...&amp;lt;/code&amp;gt; for each of those files, or simply use &amp;lt;code&amp;gt;File -&amp;gt; Open Folder...&amp;lt;/code&amp;gt; to directly open the MyMod folder. I use the Workspaces so I can hide files in each of the folders, depending on the mod – I don’t need to see the /db/ folder in VSC, for instance.&lt;br /&gt;
&lt;br /&gt;
Within VSCode now, you can create new folders, open extras, and all, and it will be within the same code workspace!&lt;br /&gt;
&lt;br /&gt;
And that’s it, VSCode is really simple to use (for our application atm). I recommend at this point downloading the &amp;lt;code&amp;gt;vscode-lua&amp;lt;/code&amp;gt; extension, which enables some error logging within VSC (for when you forget some syntax or add an extra comma) and enables coloring and other fun stuff. Link to extension here.&lt;br /&gt;
&lt;br /&gt;
[[Category:Lua Tutorials]]&lt;/div&gt;</summary>
		<author><name>Grimmys</name></author>
	</entry>
	<entry>
		<id>https://tw-modding.com/index.php?title=Lua:Main_Page&amp;diff=1209</id>
		<title>Lua:Main Page</title>
		<link rel="alternate" type="text/html" href="https://tw-modding.com/index.php?title=Lua:Main_Page&amp;diff=1209"/>
		<updated>2024-03-11T18:02:26Z</updated>

		<summary type="html">&lt;p&gt;Grimmys: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Howdy, internet stranger, and welcome. My name’s Vandy, and I’ll be guiding you through this new chapter of your life. This section of the Total War Modding Resources is dedicated to the learning and appreciation of the Lua language.&lt;br /&gt;
&lt;br /&gt;
==== What Is Lua? ====&lt;br /&gt;
One of the primary types of modding, in Total War, is the use of the programming language &amp;lt;code&amp;gt;Lua&amp;lt;/code&amp;gt;. In case you were wondering, Lua is Portugese for ‘moon’, and the dude who made the language was born in 1960, and at the time of this writing the language is only 26 years old.&lt;br /&gt;
&lt;br /&gt;
Using Lua, you can establish chains of events, create flexibility on when units can be recruited or when lords are spawned, and you can set up new quest battles. The entire Chaos Invasion mechanic from WH2 is scripted; from 3K, the randomly-spawned ancillaries from master-craftsmen buildings are scripted.&lt;br /&gt;
&lt;br /&gt;
Unlike db entries, which are compiled during the initial loading screen of the game and turned into engine data, and are often static with few exceptions, Lua is a dynamic energy within the game, and is the only direct way to access a multitude of game features, background data, and more.&lt;br /&gt;
&lt;br /&gt;
==== From Poop To OOP ====&lt;br /&gt;
From here to the end of this series, the goal is to get you from writing poop – or, in some of your cases, absolutely nothing – to writing in OOP, like a true-blooded programmer, though that’s by no means necessary and you can stop any time prior to that.&lt;br /&gt;
&lt;br /&gt;
To begin, I’m going to take you on a quick field-trip as we download some new software that will help us write better code using smart programs, and we’ll talk about some really easy ways to test Lua code.&lt;br /&gt;
&lt;br /&gt;
After that, our next journey is through the Lua basics. We’ll learn about strings, and booleans, and functions, and tables, and loops, and return values. All of the basic details of the knowledge that are necessary for even the simplest scripts.&lt;br /&gt;
&lt;br /&gt;
Next, we turn to Total War specifics. There are some concepts that we need to cover while writing Lua in Total War, such as events, interfaces, when to call your scripts, stuff like that.&lt;br /&gt;
&lt;br /&gt;
Towards the end, I’ll progress from simple scripting to some more high-minded scripting, using what the biz refers to as “Object-Oriented Programming”. It’s a more advanced topic that won’t do well being talked about here, but getting a firm grasp on it will help propel your scripting to a new level.&lt;br /&gt;
&lt;br /&gt;
All throughout this series, I’ll seek to keep the information as game-agnostic as possible, I’ll seek to cover all gaps of knowledge and point out any common troubleshooting tips where necessary, and I’ll be covering these topics in the order of which I believe they should be learned. It is highly recommended you don’t skip around or skip ahead, the order of these tutorials are deliberate.&lt;br /&gt;
&lt;br /&gt;
=== Order ===&lt;br /&gt;
[[Lua:Essential Setup]]&lt;br /&gt;
&lt;br /&gt;
[[Lua:Chunks &amp;amp; Statements]]&lt;br /&gt;
&lt;br /&gt;
[[Lua:Variables &amp;amp; Types]]&lt;br /&gt;
&lt;br /&gt;
[[Lua:Expressions &amp;amp; Operators]]&lt;br /&gt;
&lt;br /&gt;
[[Lua:Scopes &amp;amp; Stuff]]&lt;br /&gt;
&lt;br /&gt;
[[Lua:Keywords]]&lt;br /&gt;
&lt;br /&gt;
[[Lua:Tables &amp;amp; Loops]]&lt;br /&gt;
&lt;br /&gt;
[[Lua:Functions, Arguments &amp;amp; Parameters (Also Returns)]]&lt;br /&gt;
&lt;br /&gt;
[[Lua:Commands, Interfaces &amp;amp; Listeners]]&lt;br /&gt;
&lt;br /&gt;
[[Lua:Calling Scripts]]&lt;br /&gt;
&lt;br /&gt;
[[Lua:Advanced Conditionals]]&lt;br /&gt;
&lt;br /&gt;
[[Lua:Debugging]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Lua Tutorials]]&lt;/div&gt;</summary>
		<author><name>Grimmys</name></author>
	</entry>
	<entry>
		<id>https://tw-modding.com/index.php?title=Category:Tools_%26_Resources&amp;diff=1208</id>
		<title>Category:Tools &amp; Resources</title>
		<link rel="alternate" type="text/html" href="https://tw-modding.com/index.php?title=Category:Tools_%26_Resources&amp;diff=1208"/>
		<updated>2024-03-11T16:56:08Z</updated>

		<summary type="html">&lt;p&gt;Grimmys: Add more tools the list, and introduce some more formatting (italic &amp;amp; bold).&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Every modder needs proper tools, just like every lumberjack needs a swing set. This list does not claim to be a sure-fire solution to every single issue a modder might face, nor an impervious list of perfect programs, designed to cater your every need. This list does have a lot of value in it, I believe, and if used correctly, a lot can be achieved.&lt;br /&gt;
&lt;br /&gt;
You’ll also notice that this section has random housed tutorials in it, that don’t fit in any particular place with the larger-scale tutorials. The author and summary of each will be listed and maintained here!&lt;br /&gt;
====Kaedrin’s Mod Manager====&lt;br /&gt;
[https://github.com/Kaedrin/warhammer-mod-manager/releases Warhammer Mod Manager Releases] – Kaedrin’s Mod Manager is a very useful alternative mod manager that works for all Total War games since Total War: Empire.&lt;br /&gt;
&lt;br /&gt;
You can get in contact with the creator, ''Kaedrin'', in the Modding Den’s channel '''#kaedrin_mod_manager'''.&lt;br /&gt;
====Frodo’s Rusted Pack File Manager====&lt;br /&gt;
[https://github.com/Frodo45127/rpfm/releases/ RPFM Releases] – RPFM is a great pack-file managing tool, essential for any modder. Active development has new features coming regularly, as well as constant bug fixes or bug squashings.&lt;br /&gt;
&lt;br /&gt;
You can find its documentation here: [https://frodo45127.github.io/rpfm/ RPFM Documentation]&lt;br /&gt;
&lt;br /&gt;
Get in contact with the creator, ''Frodo'', in the Modding Den’s channel '''#rpfm'''.&lt;br /&gt;
==== Phazer's Rigid Model Editing Tool====&lt;br /&gt;
[https://github.com/mr-phazer/RME_Release/releases RME Tool Releases] – A tool to quickly edit rigid models using a visual UI rather than having to use clunky hex editing.&lt;br /&gt;
&lt;br /&gt;
Get in contact with the creator, ''Phazer'', in the Modding Den's channel '''#phazer_tools'''.&lt;br /&gt;
====Ole's Asset Editor====&lt;br /&gt;
[https://github.com/olekristianhomelien/TheAssetEditor/releases/ Asset Editor Releases] – A tool for kitbashing and animation splicing using vanilla assets.&lt;br /&gt;
&lt;br /&gt;
Get in contact with the creator, ''Ole'', in the Modding Den's channel '''#asset_editor'''.&lt;br /&gt;
====Thegroovewizard's LUA Debugging Setup====&lt;br /&gt;
[https://github.com/chadvandy/tw_autogen Setup for debugging LUA scripts] – A setup for debugging LUA scripts in [https://code.visualstudio.com/ Visual Studio Code].&lt;br /&gt;
&lt;br /&gt;
Get in contact with the creator, ''Thegroovewizard'', in the Modding Den's channel '''#groove_tower'''.&lt;br /&gt;
====Interactive Maps for Total War: Warhammer II====&lt;br /&gt;
[https://imrz.github.io/tww-interactive-map/latest/#/ Mortal Empires / Eyes of the Vortex interactive maps] – Web application for checking the position of every settlements, regions and ressources on both maps of ''Total War: Warhammer II''.&lt;br /&gt;
====Imagemin App (PNG Compressor)====&lt;br /&gt;
[https://github.com/imagemin/imagemin-app/ Imagemin App] – An application to lower the size of your mod .png, because they have to be less than 1Mb.&lt;br /&gt;
====Video Tutorials====&lt;br /&gt;
[https://www.youtube.com/watch?v=pzqTFR32tl8&amp;amp;feature=youtu.be Setting Up GitHub Desktop for Total War] – A rundown on how to setup GitHub Desktop for use with the Assembly Kit.&lt;br /&gt;
====Scripting Resources====&lt;br /&gt;
[https://chadvandy.github.io/tw_modding_resources/WH3/scripting_doc.html Script Doc Warhammer 3 (Events &amp;amp; Interfaces)]&lt;br /&gt;
&lt;br /&gt;
[https://chadvandy.github.io/tw_modding_resources/WH2/scripting_doc.html Script Doc Warhammer 2 (Events &amp;amp; Interfaces)]&lt;br /&gt;
&lt;br /&gt;
[https://chadvandy.github.io/tw_modding_resources/WH3/campaign/campaign_manager.html#class:campaign_manager Script Doc Warhammer 3 (Campaign Manager Functions)]&lt;br /&gt;
&lt;br /&gt;
[https://chadvandy.github.io/tw_modding_resources/WH2/campaign/campaign_manager.html#class:campaign_manager Script Doc Warhammer 2 (Campaign Manager Functions)]&lt;br /&gt;
&lt;br /&gt;
[https://chadvandy.github.io/tw_modding_resources/index.html Warhammer 2 &amp;amp; 3 CA Documentation]&lt;br /&gt;
&lt;br /&gt;
[https://chadvandy.github.io/tw_modding_resources/3k/scripting_doc.html Three Kingdoms CA Documentation]&lt;br /&gt;
==Tools &amp;amp; Resource Posts:==&lt;br /&gt;
*[[Troubleshooting]] by Vandy and Cataph&lt;br /&gt;
*[[Modding Glossary]] by Vandy and Cataph&lt;br /&gt;
*[[Campaign Map Coordinates]] by Marthenil by Vandy&lt;/div&gt;</summary>
		<author><name>Grimmys</name></author>
	</entry>
	<entry>
		<id>https://tw-modding.com/index.php?title=Category:Tools_%26_Resources&amp;diff=1207</id>
		<title>Category:Tools &amp; Resources</title>
		<link rel="alternate" type="text/html" href="https://tw-modding.com/index.php?title=Category:Tools_%26_Resources&amp;diff=1207"/>
		<updated>2024-03-05T23:07:56Z</updated>

		<summary type="html">&lt;p&gt;Grimmys: Replaced dash by wider dash for consistency&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Every modder needs proper tools, just like every lumberjack needs a swing set. This list does not claim to be a sure-fire solution to every single issue a modder might face, nor an impervious list of perfect programs, designed to cater your every need. This list does have a lot of value in it, I believe, and if used correctly, a lot can be achieved.&lt;br /&gt;
&lt;br /&gt;
You’ll also notice that this section has random housed tutorials in it, that don’t fit in any particular place with the larger-scale tutorials. The author and summary of each will be listed and maintained here!&lt;br /&gt;
====Kaedrin’s Mod Manager====&lt;br /&gt;
[https://github.com/Kaedrin/warhammer-mod-manager/releases Warhammer Mod Manager Releases] – Kaedrin’s Mod Manager is a very useful alternative mod manager that works for all Total War games since Total War: Empire.&lt;br /&gt;
&lt;br /&gt;
You can get in contact with the creator, Kaedrin, in the Modding Den’s channel #kaedrin_mod_manager.&lt;br /&gt;
====Frodo’s Rusted Pack File Manager====&lt;br /&gt;
[https://github.com/Frodo45127/rpfm/releases/ RPFM Releases] – RPFM is a great pack-file managing tool, essential for any modder. Active development has new features coming regularly, as well as constant bug fixes or bug squashings.&lt;br /&gt;
&lt;br /&gt;
You can find its documentation here: [https://frodo45127.github.io/rpfm/ RPFM Documentation]&lt;br /&gt;
&lt;br /&gt;
Get in contact with the creator, Frodo, in the Modding Den’s channel #rpfm.&lt;br /&gt;
====Phazer's Rigid Model Editing Tool====&lt;br /&gt;
[https://github.com/mr-phazer/RME_Release/releases RME Tool Releases] – A tool to quickly edit rigid models using a visual UI rather than having to use clunky hex editing, made and maintained by Phazer.&lt;br /&gt;
====Video Tutorials====&lt;br /&gt;
[https://www.youtube.com/watch?v=pzqTFR32tl8&amp;amp;feature=youtu.be Setting Up GitHub Desktop for Total War] – A rundown on how to setup GitHub Desktop for use with the Assembly Kit.&lt;br /&gt;
====Scripting Resources====&lt;br /&gt;
[https://chadvandy.github.io/tw_modding_resources/WH3/scripting_doc.html Script Doc Warhammer 3 (Events &amp;amp; Interfaces)]&lt;br /&gt;
&lt;br /&gt;
[https://chadvandy.github.io/tw_modding_resources/WH2/scripting_doc.html Script Doc Warhammer 2 (Events &amp;amp; Interfaces)]&lt;br /&gt;
&lt;br /&gt;
[https://chadvandy.github.io/tw_modding_resources/WH3/campaign/campaign_manager.html#class:campaign_manager Script Doc Warhammer 3 (Campaign Manager Functions)]&lt;br /&gt;
&lt;br /&gt;
[https://chadvandy.github.io/tw_modding_resources/WH2/campaign/campaign_manager.html#class:campaign_manager Script Doc Warhammer 2 (Campaign Manager Functions)]&lt;br /&gt;
&lt;br /&gt;
[https://chadvandy.github.io/tw_modding_resources/index.html Warhammer 2 &amp;amp; 3 CA Documentation]&lt;br /&gt;
&lt;br /&gt;
[https://chadvandy.github.io/tw_modding_resources/3k/scripting_doc.html Three Kingdoms CA Documentation]&lt;br /&gt;
==Tools &amp;amp; Resource Posts:==&lt;br /&gt;
*&lt;br /&gt;
*[[Troubleshooting]] by Vandy and Cataph&lt;br /&gt;
*[[Modding Glossary]] by Vandy and Cataph&lt;br /&gt;
*[[Campaign Map Coordinates]] by Marthenil by Vandy&lt;/div&gt;</summary>
		<author><name>Grimmys</name></author>
	</entry>
	<entry>
		<id>https://tw-modding.com/index.php?title=Category:Tools_%26_Resources&amp;diff=1206</id>
		<title>Category:Tools &amp; Resources</title>
		<link rel="alternate" type="text/html" href="https://tw-modding.com/index.php?title=Category:Tools_%26_Resources&amp;diff=1206"/>
		<updated>2024-03-05T23:04:29Z</updated>

		<summary type="html">&lt;p&gt;Grimmys: Fix resources links and add link to each tool project page&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Every modder needs proper tools, just like every lumberjack needs a swing set. This list does not claim to be a sure-fire solution to every single issue a modder might face, nor an impervious list of perfect programs, designed to cater your every need. This list does have a lot of value in it, I believe, and if used correctly, a lot can be achieved.&lt;br /&gt;
&lt;br /&gt;
You’ll also notice that this section has random housed tutorials in it, that don’t fit in any particular place with the larger-scale tutorials. The author and summary of each will be listed and maintained here!&lt;br /&gt;
====Kaedrin’s Mod Manager====&lt;br /&gt;
[https://github.com/Kaedrin/warhammer-mod-manager/releases Warhammer Mod Manager Releases] - Kaedrin’s Mod Manager is a very useful alternative mod manager that works for all Total War games since Total War: Empire.&lt;br /&gt;
&lt;br /&gt;
You can get in contact with the creator, Kaedrin, in the Modding Den’s channel #kaedrin_mod_manager.&lt;br /&gt;
====Frodo’s Rusted Pack File Manager====&lt;br /&gt;
[https://github.com/Frodo45127/rpfm/releases/ RPFM Releases] – RPFM is a great pack-file managing tool, essential for any modder. Active development has new features coming regularly, as well as constant bug fixes or bug squashings.&lt;br /&gt;
&lt;br /&gt;
You can find its documentation here: [https://frodo45127.github.io/rpfm/ RPFM Documentation]&lt;br /&gt;
&lt;br /&gt;
Get in contact with the creator, Frodo, in the Modding Den’s channel #rpfm.&lt;br /&gt;
====Phazer's Rigid Model Editing Tool====&lt;br /&gt;
[https://github.com/mr-phazer/RME_Release/releases RME Tool Releases] – A tool to quickly edit rigid models using a visual UI rather than having to use clunky hex editing, made and maintained by Phazer.&lt;br /&gt;
====Video Tutorials====&lt;br /&gt;
[https://www.youtube.com/watch?v=pzqTFR32tl8&amp;amp;feature=youtu.be Setting Up GitHub Desktop for Total War] – A rundown on how to setup GitHub Desktop for use with the Assembly Kit.&lt;br /&gt;
====Scripting Resources====&lt;br /&gt;
[https://chadvandy.github.io/tw_modding_resources/WH3/scripting_doc.html Script Doc Warhammer 3 (Events &amp;amp; Interfaces)]&lt;br /&gt;
&lt;br /&gt;
[https://chadvandy.github.io/tw_modding_resources/WH2/scripting_doc.html Script Doc Warhammer 2 (Events &amp;amp; Interfaces)]&lt;br /&gt;
&lt;br /&gt;
[https://chadvandy.github.io/tw_modding_resources/WH3/campaign/campaign_manager.html#class:campaign_manager Script Doc Warhammer 3 (Campaign Manager Functions)]&lt;br /&gt;
&lt;br /&gt;
[https://chadvandy.github.io/tw_modding_resources/WH2/campaign/campaign_manager.html#class:campaign_manager Script Doc Warhammer 2 (Campaign Manager Functions)]&lt;br /&gt;
&lt;br /&gt;
[https://chadvandy.github.io/tw_modding_resources/index.html Warhammer 2 &amp;amp; 3 CA Documentation]&lt;br /&gt;
&lt;br /&gt;
[https://chadvandy.github.io/tw_modding_resources/3k/scripting_doc.html Three Kingdoms CA Documentation]&lt;br /&gt;
==Tools &amp;amp; Resource Posts:==&lt;br /&gt;
*&lt;br /&gt;
*[[Troubleshooting]] by Vandy and Cataph&lt;br /&gt;
*[[Modding Glossary]] by Vandy and Cataph&lt;br /&gt;
*[[Campaign Map Coordinates]] by Marthenil by Vandy&lt;/div&gt;</summary>
		<author><name>Grimmys</name></author>
	</entry>
</feed>