This is a beginner level tutorial. It doesn't require any skills beyond use of text editors. Because we'll need nonstandard encoding support to deal with localization files, I recommend Visual Studio Code, but other than this one step pretty much any editor will do.
For some more details on how mission system works, you might want to check my previous post. To just learn the new mission system from a player's perspective, watch DDRJake's videos.
There's more to the mission system than can be covered in one tutorial, so I want to write another one covering more advanced subject later.
If you have any questions about these steps, ask them here, or reach me on any social media.
Create mod descriptor
For more complex mods it's best to keep the files somewhere safe and version-controlled, like on github, but we're starting small now so I'm going to skip this step.Open
C:\Users\(YourName)\Documents\Paradox Interactive\Europa Universalis IV\mod
or equivalent.You need to create a descriptor for your mod, for this simple mod create
lucca_mission_pack.mod
. For very simple mod we'll only have three lines, like this:name = "Lucca Mission Pack"
path = "mod/lucca_mission_pack"
supported_version = 1.25
name
is what's going to appear in the launcher.path
is name of the folder where we'll create mod files. Create the lucca_mission_pack
folder. It's best if it has the same name as mod descriptor (except for .mod
extension).supported_version
tells the game which exact version the mod supports. It's used mainly to warn the user in game launcher, that the mod didn't get updated for the next version yet.If you're following these steps in the future, change
supported_version
to whatever's appropriate.At this point you can start game launcher, and see that your mod is on the list. If it's not, something went wrong with the mod descriptor and you should check it. No point running the game yet, as the mod does nothing.
Create empty mod files
InsideC:\Users\(YourName)\Documents\Paradox Interactive\Europa Universalis IV\mod\
create lucca_mission_pack
folder, inside it lucca_mission_pack\missions
subfolder, and inside that lucca_mission_pack\missions\Lucca_Missions.txt
file.The name of the file doesn't matter as long as it ends in
.txt
and doesn't conflict with any in the game. For example if you call it Hungary_Missions.txt
you'll be overwriting Hungary's missions from base game - but if you call it MudkipIsBestPokemon.txt
it's just fine.Location of the file definitely matters, so if you make mistakes the mod will not load correctly.
Planning the missions
If you take a short break from modding and run the game, you'll see that Lucca's existing missions are:- column 1 - empty
- column 2 - generic military missions
- column 3 - generic diplomatic missions
- column 4 - generic administrative missions
- column 5 - regional missions for European countries and HRE minors
For a small mission pack we'll create a single mission group, and put it into column 1.
For a bigger mission pack we might replace column 5 as well, add missions on the bottom, or replace some of the generic missions.
Column choice is not just for the interface, as multiple mission groups going into same columns might replace each other.
Create a mission group
Let's openlucca_mission_pack\missions\Lucca_Missions.txt
in text editor and setup a group for the missions:lucca_mission_group = {
slot = 1
generic = no
ai = yes
potential = {
tag = LUC
}
has_country_shield = yes
# missions will go here
}
What we're setting up here:
- in column 1 (columns are called "slots")
- not generic. This is used as priority if multiple mission groups try to use same column.
- also available for the AI. Usually should be yes.
- available if your tag at campaign start is LUC (Lucca). List of tags is on the wiki, usually it's first three letters of country name.
- that we want to display country shield in the interface. This is purely graphical, but country-specific missions usually do, so let's be consistent here.
For
potential
you can choose based on other criteria like religion, culture, capital location etc., but they're only checked on campaign start, or when explicitly told so by an event or decision.
In vanilla game, they only change on some nation forming decisions. If you start as Lucca and form Italy, you'll keep your original missions since Italy decision doesn't change missions. If you form France, you'll get your mission pack replaced.
Creating out first mission
Time to create the first mission. We'll start with something very simple. The goal is to build a temple in Lucca, and as a reward you'll get 200 admin points.Open missions files, and in the place we left for missions, add this:
lucca_temple_in_capital = {
icon = mission_european_church
required_missions = { }
trigger = {
2980 = {
has_building = temple
}
}
effect = {
add_adm_power = 200
}
}
What it does:
- it sets mission's ID to
lucca_temple_in_capital
. This needs to be unique, and will be used for localization. - it uses icon
mission_european_church
. This is purely graphical, and I wouldn't worry too much about the icons until you're happy with how your missions work. - it sets lists of required previous missions to empty
- it sets mission completion condition (trigger) - province 2980 (Lucca) has temple. You can find list of province IDs on the wiki.
- it sets mission reward (effect) - 200 admin power points
Try writing something similar for country of your choice.
Start mission chain
OK, so that worked. Let's create some more missions. We'll put them all in same file, one under the other.For design of a mission chain to be good, they should somehow connect with each other. Here's an idea for a small chain:
- first we want to build up our capital. As a reward we get some permanent claims on nearby lands.
- second we want to conquer claims we got in previous mission, as a reward we get some points of multiple types
- third, we want Lucca to rival one of the big baddies, proving that we're ready. It will require completing previous mission too, so we don't need to check it again. As reward we get 25 year +10% discipline bonus for more enjoyable fights agains our new rivals.
This covers the most common cases - checking that we conquered something, getting rewarded by permanent claims, various types of points, or temporary bonuses. As well as a few extras.
Plan a similar chain for your own country, for now using similar kinds of effects.
Make Lucca Great Again
make_lucca_great_again = {
icon = mission_high_income
required_missions = { }
trigger = {
capital_scope = {
development = 25
renaissance = 100
}
}
effect = {
tuscany_area = {
limit = {
NOT = { is_core = ROOT }
NOT = { owned_by = ROOT }
}
add_permanent_claim = ROOT
}
}
}
Step by step:
- it sets mission's ID to
make_lucca_great_again
. We'll use it as key to localization later. - it sets required missions to empty
- to succeed it requires that our capital has at least 25 development and 100% Renaissance institution. I could have used
2980
(specifically province of Lucca) instead ofcapital_scope
(whichever province is our capital) here. We don't expect capital to move, so in this case it doesn't matter, but both selectors have their uses. - as reward we go through all provinces in
tuscany_area
and add permanent claim to them, unless they're already owned by us or have our core. Areas are defied inmap\area.txt
file. You don't need to use areas, you can just list provinces separately (the syntax is however a bit different).
Try something similar for your country. Pick some capital growth conditions, pick a relevant area from
map\area.txt
(most areas correspond to a state), and try it in the game.
Luccan Tuscany
We got our claims, so we ought to follow it with a mission checking that we actually conquered what we wanted.As reward we'll just get some points, but of course you can chain a lot of conquer this area - get claims on next area missions. Making them branch in a way that looks good in the UI is a bit more advanced topic, but just making this chain as long as you'd like should be straightforward.
luccan_tuscany = {
icon = mission_cannons_firing
required_missions = { make_lucca_great_again }
provinces_to_highlight = {
area = tuscany_area
NOT = {
country_or_non_sovereign_subject_holds = ROOT
}
}
trigger = {
tuscany_area = {
type = all
country_or_non_sovereign_subject_holds = ROOT
}
}
effect = {
add_mil_power = 200
add_legitimacy = 10
add_republican_tradition = 10
}
}
Let's go through it step by step:
- it sets mission ID to
luccan_tuscany
- it sets mission icon to
mission_canonns_firing
- it requires completion of
make_lucca_great_again
first. If you arrange mission chain so that next mission depends on one just above it (or one row down and then sideways), the UI will draw pretty arrows to make it clearer how missions are related. Other dependencies still work, just won't look quite as nice. - it sets province highlight when mission is mouseovered to all provinces in
provinces_to_highlight
which are not owned by us or a (nontributary) subject - it sets success condition of owning all provinces in
tuscany_area
by us or our (nontributary) subject. In addition you still need to domake_lucca_great_again
first. - as a reward, we get 200 mil power points, 10 legitimacy, and 10 republican tradition. Depending on government type of the country, the tooltip will only show relevant rewards, so if Lucca is a republic, the tooltip will show "200 mil points, 10 republican tradition", since legitimacy doesn't matter.
You can also chain claims in a few missions.
Lucca in the Major League
So now that our Lucca conquered Tuscany, let's give it a more ambitious goal - rivalling one of big three regional baddies. As a reward we'll give it a bonus.lucca_in_the_major_league = {
icon = mission_cannons_firing
required_missions = { luccan_tuscany }
trigger = {
OR = {
is_rival = FRA
is_rival = HAB
is_rival = TUR
}
}
effect = {
add_country_modifier = {
name = lucca_discipline
duration = 9125 # 25 years
}
}
}
Step by step:
- it sets mission ID to
lucca_in_the_major_league
- it sets mission icon to
mission_cannons_firing
, I just used the same one as before but feel free to pick something more creative. In the end it's just a minor graphical embellishment. - it requires completing
luccan_tuscany
first, which in turns requiresmake_lucca_great_again
. Because we put those missions in proper order, they'll be connected by nice arrows in the UI. - to succeed we need to rival France (FRA), Austria (HAB), or Ottomans (TUR). You can see that in this case tags are not quite what one might guess, presumably as a leftover from EU2 or maybe even EU1 for all I know. There's no need to check that we also did our conquests, as previous mission in the chain checks that.
- as a reward we get
lucca_discipline
modifier, for 9125 days (25 years). We just need to tell the game what that means in another file.
Creating modifiers
This is not strictly mission modding, but modifiers are about the most common mission reward, so it's useful to know how to create them.
In our mod create text file
lucca_mission_pack\common\static_modifiers\lucca_missions.txt
, and put this inside:lucca_discipline = {
discipline = 0.10
}
And that's it. You can check
common\static_modifiers\00_static_modifiers.txt
in the game for more examples.You can put as many modifiers in single file as you want, just create your own instead of putting edited
00_static_modifiers.txt
in your mod.How EU4 localization works
EU4 localization files use.yml
extension, but it's actually custom format somewhat inspired by YAML format, not the real thing.localisation
folder, with files sorted by language.Each file has header like
l_english
, and a list of IDs and their localized strings. All the files need to start with the non-standard UTF-8 BOM. If you create a normal text file without BOM, it will be ignored by the game.If you want your mod to support some other languages, it should be fairly obvious which file names and header to use instead.
As a bonus annoyance, Paradox can't decide between American and British spelling inside their files. Folder name is called "localisation" in all their games, but then HoI4 uses
localization_key
to choose entry from it. It's very easy to get confused.Localization
So if you followed along, you have a working mod with 4 missions for your country, or however many you created. There's just one more issue - the missions all use internal development IDs instead of human readable names and descriptions.There's 9 things we need to edit: 4 mission names, 4 mission descriptions, and name of our modifier.
Those IDs we gave the missions, they all need to be unique, so it makes sense to prefix it by name of the country or mission pack to avoid accidental conflicts, but we can localize them any way we want.
For every mission
ID_title
is its name key, and ID_desc
is the description key. Static modifiers's name keys are just their IDs.What we'd like to do is create
lucca_mission_pack\localisation\lucca_missions_l_english.yml
and put the following code there:l_english:
lucca_temple_in_capital_title: "Builde Temple in Lucca"
lucca_temple_in_capital_desc: "As all good Italians, Luccans need a place to pray."
make_lucca_great_again_title: "Make Lucca Great Again"
make_lucca_great_again_desc: "Our capital should be the greatest city in Italy since ancient Rome"
luccan_tuscany: "Conquest of Tuscany"
luccan_tuscany: "Some Florentines, I assume, are good people, but they'll still be better off under Luccan rule."
lucca_in_the_major_league_title: "Joining the Major League"
lucca_in_the_major_league_desc: "Show the world that Lucca is now one of the great powers by rivaling a nearby Great Power."
lucca_discipline: "Lucca's Dispciplined Army"
The game uses single space indentation, but it's not too strict about this.
What it is extremely strict about is the BOM, so if you use Visual Studio Code, choose "UTF-8 with BOM" as encoding for your new file on the bottom bar. For other editors find appropriate instructions, but many don't support UTF-8 BOM at all.
If you don't know how to get the BOM working, one think you can try is copying existing localization file, deleting everything except the first line (which might look like one broken character followed by
l_english:
tag) and just replacing the rest of the file with your content.Great Success
If everything worked, you should see something like this:Debugging
If you see image like above, but using internal IDs instead of English text, then mod is probably file , but localization is wrong. Most common issue is UTF-8 BOM.If you see some total mess in first column, like wrong number of missions with silly names like
icon
, you probably made a typo in mod files, and game .Open
C:\Users\(YourName)\Documents\Paradox Interactive\Europa Universalis IV\logs
or equivalent and search for hints. errors.log
might give you line number where game got confused.If mod was in the launcher, but when you play the game you see empty first column, mod probably didn't load at all. Or it did, but your
potential
tag is wrong, and game doesn't think these missions are appropriate for currently selected country. Double check errors.log
and list of tags.If you don't even see the mod is mod launcher, then mod descriptor file is probably wrong or in wrong place.
Or if none of that works, just ask, but remote debugging is pretty hard. I'll have easier time answering "I want mission to do X when Y" questions than "it doesn't work, what do?" questions.
I am trying to do this mod for some new missions for the Palatinate, and some of the stuff seems to not be working. The mission for building a church in the capital come up fine, along with the 1st mission at the start of the chain, which I customized, but after that, the chain doesn't work and none of the other missions show up. I can show you the code I used.
ReplyDeleteHere:
palatinate_mission_group = {
slot = 1
generic = no
ai = yes
potential = {
tag = PAL
}
has_country_shield = yes
# missions will go here
# Build temple in capital
palatinate_temple_in_capital = {
icon = mission_european_church
required_missions = { }
trigger = {
1761 = {
has_building = temple
}
}
effect = {
add_adm_power = 100
}
}
develop_oberpfalz = {
icon = mission_high_income
required_missions = { }
trigger = {
1757 = {
development = 20
}
}
effect = {
palatinate_area = {
limit = {
NOT = { is_core = ROOT }
NOT = { owned_by = ROOT }
}
add_permanent_claim = ROOT
franconia_area = {
limit = {
NOT = { is_core = ROOT }
NOT = { owned_by = ROOT }
}
add_permanent_claim = ROOT
}
}
}
unify_the_palatinate = {
icon = mission_cannons_firing
required_missions = { develop_oberpfalz }
provinces_to_highlight = {
area = palatinate_area
area = franconia_area
NOT = {
country_or_non_sovereign_subject_holds = ROOT
}
}
trigger = {
palatinate_area = {
type = all
country_or_non_sovereign_subject_holds = ROOT
franconia_area = {
type = all
country_or_non_sovereign_subject_holds = ROOT
}
}
effect = {
add_mil_power = 200
add_legitimacy = 10
add_republican_tradition = 10
add_prestige = 20
}
}
palatinate_big = {
icon = mission_cannons_firing
required_missions = { unify_the_palatinate }
trigger = {
OR = {
is_rival = BOH
is_rival = HAB
is_rival = DAN
}
}
effect = {
add_country_modifier = {
name = palatinate_discipline
duration = 9125 # 25 years
}
}
}
}
By the way, the brackets are spaced out correctly, it's just not showing here.
ReplyDeleteAngeredkey : For the most obvious thing, you forgot to close palatinate_area = { ... in both cases. You have 34 "{" but only 32 "}".
ReplyDeleteWhat are the numbers for different modifier duration periods ? 9125 is for 25 years but I want some to last longer than that
ReplyDelete