Total War: WARHAMMER II

Total War: WARHAMMER II

38 ratings
Missions and Dilemmas
By Cryswar
This guide covers the creation of dilemmas and missions, also known as quests ingame, and many of their variants, as well as the scripting potentially needed to activate some missions.
2
4
   
Award
Favorite
Favorited
Unfavorite
Notes and Setup
As with pretty much every guide you see form me, I'll start them off by shilling the Rusted Pack File Manager[github.com], usually known as RPFM. At the time of this writing it is by far the best packfile manager available, easily outperforming CA's own Assembly Kit and the wildly outdated PFM in most regards.

That said, missions and quests can be complex enough and involve a potentially intimate understanding of effects, effect bundles, skills, etc. that I will assume you already have a solid grasp of those. If not, I have guides for them, but will not be repeating them here.

Unlike many of my guides, creating a mission or dilemma is fairly straightforward and consistent in most ways, so unless you need to mess with the optional tables, you can just follow parts 1-7 rather than picking and choosing which tables you need.
---Missions---
Missions are those quests and tasks that pop up ingame - Queek trying to find his sword, Vortex missions demanding you do X thing in return for vortex currency, or generic tasks like "recruit 3 cav and get +4 recruit rank to artillery for 10 turns".
Part 1: missions_tables
This is kinda your generic starting table, like how land_units is the core of a unit, or effects is the core of an effect. MOST of it is relatively simple, but let's go over the important ones in detail!

  • Key works like most keys, must be unique and should be short, simple, and copy-pasted to notepad or w/e since you'll be using it a lot.
  • Mission type is mostly self explanatory, but I think it uses strings instead of keys for some reason? Whatever the case, copy the vanilla one that seems closest to what you want, ex. if you want to do a mission to recruit a unit, use RECRUIT_UNIT.
  • Localized Title/Description can be left blank, locs will actually handle that stuff later.
  • UI image and UI Icon are pretty simple, copy a path from vanilla.
  • Generate allows the quest to automatically populate, used for some generic missions, disabled for any kind of unique mission.
  • Prioritized is for very important quests; stuff like the Book of Nagash quests, most lego lord item quests, and... actually I think that's all it's used for?
  • Event Category is essentially which bit of the missions screen your mission will show up in; lord items are Quests, Wulfhart's hunters show up in wulfharts_hunters, etc.
  • Set Piece Battle is primarily used for the quest battles in lord item quests, but also for some other special battles, like the final Vortex battle or Grom and Eltharion's special vortex finales. Making one of those is WAY outside the scope of this guide unfortunately.
  • Location X/Y and Trigger Radius are only used for quest battles, for the little blue pillar of light you walk into, leave them 0 for everything else.
  • Quest Character is used for character-locked quests, which is mostly legendary lord quest chains. Note that this calls for the startpos ID of the character, in start_pos_characters, which you'll need to use asskit to find.
  • Quest Mission Final is just for closing off multi-quest chains. I don't think it's super important/relevant in general.
Part 2: cdir_events_mission_issuer_junctions_tables
This table is thankfully pretty simple; you link your key from last section to an issuer. 95% of stuff in vanilla is all from the same generic issuer, CLAN_ELDERS, which you can safely use yourself. Some WH2 stuff, especially Vortex missions, can use more unique issuers like YUKANNADOOZAT, which can be defined and given icons in mission_issuers_tables as desired.
Part 3: cdir_events_mission_option_junctions_tables
This one table will be the cause of roughly 753% of the problems you'll ever have with missions. It's complicated as hell, has absolutely 0 explanation whatsoever, and you have to use asskit to even find out what the hell any of it does. But you gotta do it, so...

The basic idea here is that you set up a var chance for every mission (100 for a guaranteed one like a LL quest, can be lower for randomized quests), pick some kind of length from the list, ex. VAR_MISSION_LENGTH_INFINITE with a blank value for infinite duration or VAR_MISSION_LENGTH_MIN with a length of 4 and VAR_MISSION_LENGTH_MAX of 8 for a 4-8 turn duration, you can also add a VAR_MISSION_LENGTH_MOD_EASY with a value of 2 to double those values in Easy campaign difficulty.

Then you add in what the quest is actually supposed to target; this can be GEN_TARGET_NONE for something like the Book of Nagash quests that have their own UI, or maybe you use GEN_TARGET_REGION, GEN_CND_REGION with the settlement key of wh2_main_vor_heart_of_the_jungle_oreons_camp, and VAR_OBJECTIVE_NUM_REGIONS with a value of 1 to tell the game "ok, this mission targets a region, that region is on Oreon's Camp on the Vortex map, and that's the only region we care about". Or maybe you just want the player to recruit 3 death runners, like in Tretch's one quest; VAR_OBJECTIVE_UNIT can be called multiple times to include both wh2_main_skv_inf_death_runners_0 and wh2_dlc14_skv_inf_death_runners_ror_0 (main_unit key), and VAR_OBJECTIVE_NUM_UNITS is used to declare the player needs 3 units. If it has to be in Tretch's army specifically, vanilla uses GEN_CND_CHARACTER_ID with his startpos character ID, though I believe you can use GEN_CND_AGENT_SUBTYPE with the agent_subtype key instead.

If your mission is randomly generated, this is also where you can set how often it can occur and when.

If that all looks frustratingly complex and irregularly laid out... it is! There's not much you can do to make it more fun, best I can say is to use cdir_events_options_tables and its descriptions to understand what each option does, then look at how vanilla quests use your preferred targets or conditions and rip them off wholesale.

  • ID must be unique, as usual. There's plenty of vanilla stuff randomly spread over the 2-5 digit range, with a few 6-7 digit numbers or higher, but in general 6+ digits will be pretty safe.
  • Mission Key we've talked about in every section of the guide so far, shouldn't be too hard.
  • Option Key is explained in detail above, but keep in mind that missions will have at least 2 and potentially 5-10+ rows of these.
  • Value is also explained in detail above, but be VERY careful with these, and look at vanilla usage - some should be left blank, while others need very specific numbers, keys, etc.
Part 4: cdir_events_mission_payloads_tables
Okay, finally back to a table that actually makes sense. While it looks very similar, this one is MUCH easier to puzzle out and doesn't deal in arcane bullshenanigans.

Note that much like the previous table, you can have multiple rows here for the same mission. So for example, a mission could reward 10,000 gold AND an ancillary, you don't have to pick one or the other.

  • ID must be unique as usual, yada yada.
  • Mission Key should be easy by this point.
  • Status Key is easy, if you're doing rewards for a successful mission use SUCCESS, but there are, like, 10 missions in vanilla that still give a reward when failed, which can be done with CANCELLED.
  • Payload Key is a little complicated; it can either use a predefined key like ADD_ANCILLARY or ADD_MERCENARY_TO_FACTION_POOL or GIVE_TRAIT, or define another and attach it to an Effect Bundle. You can make your own effect bundles and put whatever effects you want on them.
  • Value tells the game what to do actually do with the payload key. In general, this is in the structure KEYWORD or KEYWORD[key], with multiple keywords being separated by a semicolon. For example, if you used ADD_ANCILLARY, you might fill the Value out with ANCILLARY_KEY[wh2_main_anc_talisman_amber_amulet];SHOULD_REPLACE; first bit tells the game what the ancillary to grant is, and the second bit tells the game to replace whatever ancillary the character already has in that slot. You can instead do something like ANCILLARY_KEY[wh_main_anc_mark_of_chaos_mark_of_khorne];TARGET_OWNING_FACTION to just add the ancillary to the faction. If you were instead using TREASURY to add gold to a faction, AMOUNT[1200] does the job; if a permanent effect bundle, using saenathra_ME_oak_reward as the key, you could use DURATION[0];GLOBAL to add it to faction with a permanent duration.

Some of the main values you may use;
  • TRAIT_KEY[key] (for GIVE_TRAIT / REMOVE_TRAIT)
  • ANCILLARY_KEY[key] (for ADD_ANCILLARY; can be appended by ;SHOULD_REPLACE or ;TARGET_OWNING_FACTION)
  • RANDOM_ANCILLARY;TARGET_OWNING_FACTION (for ADD_ANCILLARY)
  • AMOUNT[X] (for TREASURY payload)
  • AMOUNT[25] (for INFLUENCE)
  • AMOUNT[X];UNIT[key] (for ADD_MERCENARY_TO_FACTION_POOL payload)
  • AGENT[wizard];AGENT_SUBTYPE[key];AP_FACTOR[1.0] (for spawning agents, AP factor is how much movement they start with)
  • DURATION[X];GLOBAL (for effect bundles; 0 duration is permanent, any other duration is timed
  • RESOURCE[key];FACTOR[wh2_main_resource_factor_missions];AMOUNT[x] (for FACTION_POOLED_RESOURCE_TRANSACTION; only works with pooled resources)
Optional: cdir_events_mission_followup_missions_tables
This table is optional and can be skipped entirely for most missions, but some quest chains require multiple missions, and this table is how you do it. You can set up different paths depending on if the player canceled or succeeded the mission, or just set both up to take you to the next step. Pretty self explanatory from here.
Part 5: missions.loc
Oh hey, finally an easy table! If you're not familiar with locs, they're how you get text ingame, with a slightly different folder structure than normal DBs and coming from a different pack (local_en.pack) but the same basic rules about renaming them to not be the same as vanilla.

Each mission has two entries here; missions_localised_title_
and missions_localised_description_. Your job is to append your mission's key to each of those, ex. if your mission key is VO_sarthorael_defeat_alarielle, your rows would look like missions_localised_title_VO_sarthorael_defeat_alarielle
and missions_localised_description_VO_sarthorael_defeat_alarielle respectively.

The Text column to the write is where you write the stuff in plain English. To use my example, maybe you want some badass name like Fall of the Everqueen and... well, you can figure out your own description I'm sure.
Part 6: Actually Spawning Your Mission
If you set your mission to auto generate on its own, that's already sorted, but many missions can and maybe should be script-spawned instead. You can do this by using the cm:trigger_mission command, which is documented in detail by CA here[chadvandy.github.io] on Vandy's site.

This is usually wrapped in a listener, which immediately goes off the deep end into a level of complexity in Lua scripting that is waaaaaaaaaaaaaay outside the scope of this guide. Ask around in Da Modding Den (linked at the bottom) or check Vandy's site for guides to learning Lua scripting, I'm not very good at it so don't ask me lol. I will however provide a few hacked together listeners I've made in the past, they may not do exactly what you want but hopefully it'll at least be a springboard to customize your own.

This listener waits until a certain legendary lord is recruited, then pops the mission (in this case, requesting that lord razes a specific settlement)

core:add_listener( "SaenathraCreated", "CharacterCreated", function(context) return context:character():character_subtype("chs_saenathra"); end, function(context) cm:trigger_mission("talons_of_tzeentch", "ME_saenathra_raze_oak_of_ages", true) end, false );

You can absolutely use generate options to just have a quest show up on turn 20, but if you don't wanna mess with option junctions too much, you can use a listener like this to forcibly pop the mission for the player only on turn X instead.

core:add_listener( "Egil_Settra", "FactionTurnStart", function(context) return context:faction():is_human() and context:faction():name() == "blades_of_khorne" and cm:model():turn_number() == 20 end, function(context) cm:trigger_mission("blades_of_khorne", "VO_egil_defeat_settra", true) end, false );
---Dilemmas---
Dilemmas are those popups that give you 2-4 choices, whether it be the dwarfen Honor is All / A Grudge Put Right choice or picking which flavor of Slann you want as Lizardmen. Functionally fairly similar to Missions but set up a bit differently.
Part 1: dilemmas_tables
This is a very simple, basic table. You have your key, the UI image, and the Event Category, all self-explanatory, and those are the only things you'll ever have to worry about for 99% of missions.

Generate and Prioritized work the same as with missions; Generate is for randomized ones, Prioritized is for very important stuff.
Part 2: cdir_events_dilemma_option_junctions_tables
This table works exactly the same as the missions variant, with allll the crap I wrote there relevant here. Note that if you're manually spawning a dilemma, ex. the Dark Elf Names of Power, you can just use VAR_CHANCE with value 100 and GEN_TARGET_MODEL with an empty value to just guarantee it spawns when you spawn it and ignore this table.

Part 3: cdir_events_dilemma_choice_details_tables
Dilemmas have choices, right? This table is where you define how many choices the player gets. Very simple, can define up to 4 choice keys per dilemma key.
Part 4: cdir_events_dilemma_payloads_tables
This table controls what rewards, if any, you get from each choice. It's VERY similar to the missions version of the table, with the main difference being that you might have 4 choices to attach rewards to instead of just succeed/fail.

The Payload Key and Value columns work identically to the Missions version, so if you're not familiar with those, read there and then look at how various vanilla dilemmas pay off for examples.
Optional: cdir_events_dilemma_followup_missions_tables
Surprise, dilemmas can spawn missions! This isn't done often in vanilla so there aren't a ton of examples, but if you want to make player choices REALLY matter you can do that here.
Optional: cdir_events_dilemma_followup_dilemmas_tables
Yo dawg, I heard you liked dilemmas, so we put a dilemma in yo dilemma, so you can dilemma while you dilemma! Seriously though, this table lets you spawn one dilemma from another, which can be helpful if you have more than 4 choices in mind - use this to have the 4th choice be "more choices" and then give them the other choices in the second dilemma.
Part 5: dilemmas.loc
Fairly generic loc file, works the same as the one for missions and honestly most other locs in the game. You have your title and description, dilemmas_localised_title_ and
dilemmas_localised_description_, and you append your dilemma's key to them, then add in the text.
Part 6: choices.loc
You gotta have text for each choice, right? Not just blank buttons? This is how ya do it! Unfortunately this is one of those more complicated locs that has postscripts, so let's break it down.

cdir_events_dilemma_choice_details_localised_choice_label_crys_lector_name_3FIRST cdir_events_dilemma_choice_details_localised_choice_title_crys_lector_name_3FIRST

Same as with most locs, you have your basic opener bits, cdir_events_dilemma_choice_details_localised_choice_label_ and cdir_events_dilemma_choice_details_localised_choice_title_. You append your dilemma key to them, for example cdir_events_dilemma_choice_details_localised_choice_label_crys_lector_name_3. Then, you add the choice name afterwards, in this example cdir_events_dilemma_choice_details_localised_choice_label_crys_lector_name_3FIRST

Note that you will need to have a label and title for each button, and each should be postscripted correctly, so a 4-choice dilemma will have 8 rows here. I'll use an example from a semi-abandoned mod of mine to show how it might look.

cdir_events_dilemma_choice_details_localised_choice_label_crys_lector_name_3FIRST Sigmar cdir_events_dilemma_choice_details_localised_choice_title_crys_lector_name_3FIRST A fool's question. No matter what men of old believed, it is Sigmar who has led the Empire through its darkest times, and only Sigmar can lead them through the murky future. Your faith in Sigmar is absolute and shall not be tested by fools cdir_events_dilemma_choice_details_localised_choice_label_crys_lector_name_3SECOND Taal cdir_events_dilemma_choice_details_localised_choice_title_crys_lector_name_3SECOND Taal, the god of nature and beasts, and considered by many to be the true king of the gods. Accepting his place amongst the pantheon does not lessen Sigmar, for even he taught that respect must be paid to the Gods. cdir_events_dilemma_choice_details_localised_choice_label_crys_lector_name_3THIRD Ulric cdir_events_dilemma_choice_details_localised_choice_title_crys_lector_name_3THIRD Even Sigmar once knelt before Ulric, and deeming Ulric worthy will do a great deal to bolster the morale and loyalty of his followers among your army. There is a time to preach and a time for practicality, after all. cdir_events_dilemma_choice_details_localised_choice_label_crys_lector_name_3FOURTH Shallya cdir_events_dilemma_choice_details_localised_choice_title_crys_lector_name_3FOURTH Arguing over who is the king of what is a waste of time and energy. Diplomacy reigns supreme; a carefully worded suggestion that the men focus instead on protecting and healing others, as Shallya would wish, leads to a sense of unity among your forces.
Part 7: Delivering Dilemmas
There are multiple ways to offer the player a dilemma. Perhaps the most common is the same as missions; set it to generate, give appropriate requirements, and bam, it generates itself. Dark Elf Names of power instead use the character_skill_level_to_dilemmas_junctions_tables table, which instantly generates the dilemma page as soon as you leave the skill screen and allows you to randomly pick between multiple possible dilemmas or just have a guaranteed one show up.

You can also use cm:trigger_dilemma or one of a few variants, which similar to the mission spawn are documented in detail here[chadvandy.github.io]
---Notes---
There are some other tables and concepts not mentioned here, either in the interest of brevity, it's already long as hell, or being relatively unused and/or easy to find, ex. there are a few other tables for dwarf grudges. Most can be found pretty easily by just searching "dilemma" or "mission" in data.pack.

As always, I will shill Da Modding Discord[discord.gg], previously known as the C&C Modding Den after its creators Crynsos and Cataph - no relation to Cryswar haha! I have gotten help many times there along the way to being a not garbage modder, and I hang out there and help people in the various modding_tech channels as often as possible to try to give back to the community. While I felt confident enough to write this guide, I am by no means the best dilemma/mission modder in the world, and I don't know much of anything about creating missions via scripting, so if you want to learn more about stuff not covered by the guide it may be a good place to ask for help!
1 Comments
purr 20 Mar, 2021 @ 11:23am 
I believe the tables dilemmas.loc and choices.loc became dilemmas__.loc and cdir_events_dilemma_choice_details__.loc respectively