Darkest Hour - Dev Diary #11 - Modding with Darkest Hour Part 1

  • We have updated our Community Code of Conduct. Please read through the new rules for the forum that are an integral part of Paradox Interactive’s User Agreement.

^_AC_^

Field Marshal
86 Badges
Feb 24, 2009
5.721
349
  • Victoria 2: A House Divided
  • Sengoku
  • Semper Fi
  • Victoria: Revolutions
  • Europa Universalis IV: Res Publica
  • Magicka
  • Leviathan: Warships
  • Knights of Pen and Paper +1 Edition
  • Victoria 2: Heart of Darkness
  • War of the Roses
  • Hearts of Iron IV Sign-up
  • Europa Universalis III Complete
  • The Showdown Effect
  • Warlock 2: The Exiled
  • Crusader Kings II: Conclave
  • 500k Club
  • Stellaris
  • Europa Universalis IV: El Dorado
  • Imperator: Rome Deluxe Edition
  • Crusader Kings II: Way of Life
  • Pillars of Eternity
  • Imperator: Rome
  • Europa Universalis IV: Common Sense
  • Stellaris: Ancient Relics
  • Knights of Pen and Paper 2
  • Europa Universalis IV: Cossacks
  • Hearts of Iron IV: Cadet
  • Surviving Mars
  • Stellaris: Synthetic Dawn
  • Cities: Skylines - Green Cities
  • Europa Universalis IV: Cradle of Civilization
  • Hearts of Iron IV: Expansion Pass
  • Stellaris: Apocalypse
  • Europa Universalis IV: Rule Britannia
  • Cities: Skylines - Parklife
  • Europa Universalis IV: Dharma
  • Stellaris Sign-up
  • Stellaris: Megacorp
  • Hearts of Iron IV: Death or Dishonor
  • Europa Universalis IV: Golden Century
  • Crusader Kings II: Reapers Due
  • Europa Universalis IV
  • Europa Universalis IV: Rights of Man
  • Tyranny: Archon Edition
  • Stellaris: Digital Anniversary Edition
  • Stellaris: Leviathans Story Pack
  • Crusader Kings II: Monks and Mystics
  • Stellaris - Path to Destruction bundle
  • Europa Universalis IV: Mandate of Heaven
  • Crusader Kings II: Holy Fury




Darkest Hour is a game made by fans for the fans, but more also to a certain extent, we could also say it is made by modders for the modders. Starting today and for the next few weeks, we will introduce you the changes introduced by Darkest Hour related to database and modding. We will show you the changes to triggers and commands, the new event interfaces and the new concepts (you already know there is a decision system, but there are also quite a few elemental additions to the existing event system you haven't seen elsewhere).

Today we'll start with corrections and improvements that we did to already existing triggers and commands as well as the new ones we introduced.
One of the first improvements we made was to take into considerations wars and alliances: we gave the control, owned and garrison triggers the possibility to check for enemies and allies. Obviously, an enemy is a country we are at war with whereas an ally is a country we are allied with. So for example it is possible to check if a specific province is controlled by a specific country or by one of its allies: this will be very useful in surrender chains! ;-)

Here's a list of corrected and/or improved triggers:
Code:
- Trigger: control = { province = a [data = tag] } # checks if province is controlled by country x. If data = -1 or no data then it’s for country receiving event; -2 is Enemy; -3 is allied (war or diplomatic alliance) or event receiver
- Trigger: convoypool = X # changed to check for total convoy transports instead just for unassigned
- Trigger: escortpool = X # changed to check for total escorts instead just for unassigned
- Trigger: intelligence = X / intelligence = { [country = TAG] value = X [data = 1/2/3] } # True if intel level is at least X in the current country (intelligence = X, or no TAG) or country in question (TAG); data: 1 (default) intell level, 2 – foreign intelligence, 3 – counter espionage
- Trigger: intel_diff = { country = TAG1 [country = TAG2] value = X [data = 1/2/3] } # True if TAG1 intel efficiency in TAG2 – TAG2 intel efficiency in TAG1 is at least X (data = 1 or no data), TAG1 intel level – TAG 2 intel level is at least X (data = 2), or TAG1 intell efficiency in TAG 2 is at least X. If no TAG2 check for current country in TAG1. value could be negative.
- Trigger: lost_IC = { value = X } # X% or more of national IC of the country in question is in enemy hands
- Trigger: lost_national = { value = X } # X% or more of national provs of the country in question are in enemy hands
- Trigger: lost_VP = { value = X } # X% or more of _owned_ VPs of the country in question are in enemy hands
- Trigger: owned = { province = a [data = tag] } # checks if province is owned by country x. If data = -1 or no data then it’s for country receiving event; -2 is Enemy; -3 is allied (war or diplomatic alliance) or event receiver
- Trigger: trade = { country = TAG } # check if the country in question has a trade deal with TAG
- Extend garrison trigger to support [country = TAG/0/-1/-2/-3] (0 – all countries, current country (country = -1 or no country), enemy countries (country = -2) or allied/friendly countries (country = -3); optional area values: 0 = (no) / 1 = area / 2 = region /3 = (yes) owner area ):
* garrison = { [country = TAG/-1/-2/-3] province = [province] type = [air/land/naval] size = [number of divisions] area = [0/1/2/3] }

And now, let's talk about the new triggers we introduced with Darkest Hour. First of all, as someone guessed in our Q&A Session two weeks ago, we can now check control or ownership not only over a province but also over an area or a region. The checks can be performed on allies and enemies too and can involve even a percentage of province: for example we could check as Germany if at least 60% of provinces of the region France are controlled by our alliance. Thanks to the nuked triggers it will be possible to take nuclear warfare into account in surrender chains: now Japan can surrender if Okinawa is lost and it has been nuked at least twice. Another trigger, perhaps underestimated, is the participant trigger which checks if the country is part of the Allies, Axis or Comintern. There are also new checks for buildings (with special checks for nuclear reactors and rocket test facilities), cores & claims, divisions, policies and tech teams that allow a finer tuning and a better control over the status of your country.
Here's a list:
Code:
- Trigger: area = { area = name [country = TAG/-1/-2/-3] [data = 1/2] [value = X] } # check if all provinces in the area are controlled (data = 1 or no data) or owned (data = 2) by the current country (country = -1 or no country), enemy countries (country = -2) or allied/friendly countries (country = -3)); optional value = X (0 to 100, default is 100) – percentage of provinces (cannot be less then 1 province)
- Trigger: building = { province = ID type = building_type value = X [when = now] } # check if in the specified province that building_type is at least at level X; when = now for current size, else - max size
- Trigger: claims = { province = a [data = tag ] } # check if that province is claimed by TAG (or country in question if not specified)
- Trigger: core = { province = a [data = tag ] } # check if that province is core for TAG (or country in question if not specified)
- Trigger: embargo = { country = [tag1] country = [tag2] [value = 0/1/2]} # checks if tag1 has trade (value = 1), tech (value = 2) or any (value = 0 or no value) embargo to tag2. If no tag 2 check for current country against tag1
- Trigger: ic = X / ic = { [country = TAG] value = X [when = now] } # check if TAG (or country in question if not specified) has X or more Total IC ([when = now] ) or Base IC; ic = X checks if current country has at least X total IC
- Trigger: nuclear_reactor = X / nuclear_reactor = { [country = TAG] value = X [when = now] } # check if TAG (or country in question if not specified) has nuclear reactor at X or more current size ([when = now] ) or max size; nuclear_reactor = X checks if current country has at least nuclear reactor with X current size
- Trigger: nuked = X / nuked = { country = TAG1 [country = TAG2] data = X [where = Y] }
* nuked = -1  # True if against that country have been used at least 1 nuke
* nuked = 1 # True if that country has used at least 1 nuke against any country
* nuked = { country = FRA country = GER data = 1 where = 300 } # True if France(FRA) has used at least 1 nuke against Germany (GER) in Berlin (ID #300) 
* nuked = { country = FRA data = -1 } # True if against France(FRA) has been used at least 1 nuke by any country
* nuked = { country = GER data = -2 where = 300 } # True is against Germany have been used at least 2 nukes (by any country) at Berlin 
- Trigger: participant = { [county = TAG] value = 1/2/3/4 }  # check if TAG (or country in question if not specified) is part of Allies (1), Axis (2), Comintern (3) or any alliance (4)
- Trigger: policy = { [country = TAG] type = [policy] value = X } # true if the policy of TAG (or country in question if not specified) is equal or greater then X. Value is 1 to 10
- Trigger: region = { region = name [country = TAG/-1/-2/-3] [data = 1/2] [value = X] } # check if all provinces in the region are controlled (data = 1 or no data) or owned (data = 2) by the current country (country = -1 or no country), enemy countries (country = -2) or allied/friendly ); optional value = X (0 to 100, default is 100) – percentage of provinces(cannot be less then 1 province):
- Trigger: rocket_test = X / rocket_test = { [country = TAG] value = X [when = now] } # check if TAG (or country in question if not specified) has rocket test sites at X or more current size ([when = now] ) or max size; rocket_test = X checks if current country has at least rocket test site with X current size
- Trigger: tech_team = ID / tech_team = { id = X [country = TAG] } # checks if team with id X is active (current year is in between team’s start/end year) in the current country (no country entry), in a specified country (TAG) or in any country (country = -1, or just team = ID)
- Trigger: [div type] = { [country = TAG] value = X [when = now] } # check if TAG (or country in question if not specified) has X or more of that type of division. when = now counts only already built divisions.
- New trade system triggers:
* stockpile = oil/energy/metal /rare_materials/supplies/money # Returns true if Stockpile is set for the given resource.
* import = oil/energy/metal /rare_materials/supplies/money # Returns true if Import is enabled for the given resource.
* export = oil/energy/metal /rare_materials/supplies/money # Returns true if Export is enabled for the given resource.
* resource_shortage = oil/energy / metal / rare_materials / supplies / money/all # Returns true if there is resource shortage for that resource or for any resource when used with “all”. NOTE: This trigger is not very reliable because it is set correctly on the second game day on every game session.

We've corrected the most well-known bugs in event commands (unit stats and change TAG command) and improved the inherit and manpowerpool commands:
Code:
- Fixed units stats added by events (example “command = { type = soft_attack which = infantry value = 10 }” ) – those were not applied to newly built units.
- Added “when = XXX” entry to build_division event command to allow serial builds (default value is 1)
- Fixed a CTD bug with undocumented change country TAG command (command = { type = country which = TAG }) – tech-teams currently researching were not removed from research pool. On click game CTD
- Fixed a bug in change TAG command - only minimum provinces were added to nationalprovinces list. Add provinces from extra list too and also claims to claimedprovinces list.
- Addition to inherit command – added value = 1/0(default) argument. When set country will receive all units and production queue too.
- Improved manpowerpool command – added optional [when = 1/[0]] switch. When set 1 add the MP as percentage (value = x.x) of the MP in all controlled national provinces. 
- Corrected event command: type = carrier_level value = XXX.X #country-independent bonus to every carrier into a naval combat (Bonus = (OurCarrierLevel - TheirCarrierLevel) / 10). Specified value replaces currently used (it is not additive command). By default this value for all countries is 0.0 (and so the bonus is 0%). 
- Extended alliance command (added Axis, Allies, Comintern alliances): type =   alliance which = [tag] [where = 1/2/3] # This country enters in an alliance with country = [tag], [-1] for random country, where = 1 – Axis/ 2 – Allies / 3 – Comintern
The new option for the inherit commands will add flexibility and will avoid having to rely on the regular_id entry on revolt.txt to achieve the same result whereas the enhanced manpowerpool command is very useful for the mobilization process, as you might learn in another DD! ;-)

And now, we're going to have a look at the new event commands that we introduced. We cannot talk about the new trade system yet (you'll have to wait for another DD ;-) ), so let's skip its commands and let's look at the change flag/shield/counter name and skin and change country name commands. We think these are going to be some of the most loved additions, especially by the modders, as these commands have been loudly requested by the community for years. We hope you'll appreciate them! :)
Other commands that you'll soon grew accustomed to will be the new command to assume or relinquish military control over another country and the commands to secede whole areas or regions to another country: no more typing secede_provinces hundreds of times for the Soviet Bitter Peace! :-D
Code:
- New commands and country specific modifiers on max stockpiles:
* command = { type = stockpile which = (industry / supplies (used for oil too) / all) when = ( war / peace / all ) value = XX }
- New event commands to toggle auto-trade options.
* command = { type = auto_trade which = (oil/energy/metal /rare_materials/supplies/money) when = (import/export/stockpile) value = 1/0 }
Notes:
a. Enabling Stockpile will disable Export and enable Import
b. Enabling Export will disable Stockpile
c. Disabling Import will disable Stockpile
* command = { type = auto_trade_reset } - reset auto-trade options to defaults ( Stockpile disabled, Import and Export enabled for all resources)
- New event command – add/remove tech/trade embargoes:
* command = { type = embargo which = TAG where = TAG [value = -2/-1/0/1/2/3] } # which – enforcer; where – subject; value: -2 – clear tech embargo; -1 – clear trade embargo; 0 or no value – clear all embargoes; 1 – enforce trade embargo; 2 – enforce tech embargo; 3 – enforce both trade and tech embargoes; If which = where then value = 0 (clear all embargoes the country has), -1 (clears all trade embargoes the country has), -2 (clears all tech embargoes the country has) 
- New event command – trade:
* command = { type = trade which = TAG where = TAG [energy = x] [metal = x] [rare_materials = x] [oil = x] [supplies = x] [money = x] [when = Days duration / default is 100 years] [value = 1/0 – default, can be broken, 1 = not] }
- New event command – change flag/shield/counter name and skin:
* command = { type = flag_ext where = TAG [which = “string”] } # where – change flag of TAG; which - add that string to flag/shield/counter name and skin folder; use empty string (“”) or no which to clear.
- New event command – change country name:
* command = { type = name where = TAG [which = “string”] } # where – change name of TAG; which - new country name; use empty string (“”) or no which to reset name to default.
- New event command – military_control:
* command = { type = military_control which = TAG where = TAG value = 1/0 } # which – controlling country; where – controlled country; value – 1(assume MC), 0 (relinquish MC)
- New event command – secederegion:
* command = { type = secederegion which = TAG value = REGION_NAME } 
- New event command – secedearea:
* command = { type = secedearea which = TAG value = AREA_NAME }
- New event command: type = addclaim which = [prov id] # Add province to country claims
- New event command: type = removeclaim which = [prov id] # Remove province from country claims
- Added a new command to change leader of a major alliance: command = { type = alliance_leader [which = TAG] where = 1/2/3 } #sets TAG (or country in question if no which is specified) as the new leader of Axis (where = 1), Allies (where = 2) or Comintern (where = 3)
We regulary add new commands and triggers, or improve the existing ones, whenever we reach a point where it is not possible to achieve a certain effect with those already existing, so this list is by no means final. We might surprise you again in the future! :)

This is all for now! Next week we'll probably talk about the new event and decision interface! Here's a sneak peek:
 
Last edited by a moderator:
And in the sense of adding/fixing things regulary, you actually didn't mention my current favorites added last week.

Extended unit terrain/weather combat modifier commands to classes too (land/air/naval)


Old code:

Code:
      command = { type = frozen_attack which = infantry value = 13 }
      command = { type = frozen_attack which = militia value = 13 }
      command = { type = frozen_attack which = armor value = 13 }
      command = { type = frozen_attack which = bergsjaeger value = 13 }
      command = { type = frozen_attack which = cavalry value = 13 }
      command = { type = frozen_attack which = hq value = 13 }
      command = { type = frozen_attack which = light_armor value = 13 }
      command = { type = frozen_attack which = marine value = 13 }
      command = { type = frozen_attack which = mechanized value = 13 }
      command = { type = frozen_attack which = motorized value = 13 }
      command = { type = frozen_attack which = paratrooper value = 13 }

DH code:

Code:
command = { type = frozen_attack which = land value = 13 }

It might not look like much to you, but if you add for example decisions to equip your troops with specifc equipments it gets really important.

If you want to add for example winterequipment, the old code required 120 commands to add/remove terrain/weather modifiers to all vanilla landdivisions.

snow-/frozen- move/attack/defense for each of the 10 Division types, and the whole thing times two, one to activate and one to deactivate.

The new code requires only 12 lines. :)

And there might be more then only winterequipment. ;)
 
And in the sense of adding/fixing things regulary, you actually didn't mention my current favorites added last week.
You're right, I forgot to include the latest new commands included this week. Thank you. :)
 
It looks great. I see many useful commands and triggers and it will be easier to write surrender events, too.

BTW what this "sce_frequency" in the script really is?

Here you go. :)

type = sce_frequency value = X # Combat event chance multiplier. Default: 1.0

It works of course in combination with the basic values you can define in misc.txt
 
Though I do not mod myself, I find these new triggers huge in added possibilities to the game. The weather-related ones make warfare more and more interesting, in special for all of us interested in making 'General Winter', 'mist season' and Overlord more plausible. All the region/faction stuff seems great for MP also.

Congrats!
 
Very nice :)
I have one suggestion
"Improved manpowerpool command – added optional [when = 1/[0]] switch. When set 1 add the MP as percentage (value = x.x) of the MP in all controlled national provinces."
Wouldn't it be better if You replace 1/0 switch by "when = relative" as optional ?
 
The best thing with is that not only do we provide a great development platform for modders and hardcore fans, but we also take benefit from all these changes we introduced to the engine to revise the database from A to the Z and provide players with the most immersive and fun experience ever. :)