Hoi4 modding Wiki
Advertisement

The event folders contains a list of event files that each specify one or multiple events that are called during the game. This includes both events that happen naturally (such as the hindenburg crash), as well as country-driven (such as danzig or war). Typically, there is a file for each country and for a number of other groups of generic events such as capitulation, nuclear bombings, civil wars and war justifications.

Each event file starts by declaring a namespace, followed by a list of country_events and news_events of that namespace.

Typically a country event is one where the player has multiple options, whereas a news event is the mentioning of something that happened. They have a slightly different frame size but function otherwise identical.

The above mentioned structure isn't enforced, in theory every event could get its own file, or all events could be saved in a single file.

Tip : You can use "immediate" as part of an event, to have some things happen immediately when the event is received:

immediate = {
	CHI = { remove_ideas = german_advisors }
}

Firing Events

There are several ways to fire events, but they can be grouped into 3 basic categories - using triggers, firing them directly with other events / focuses / decisions, or using on_actions.

Using Triggers

Events can use triggers to determine whether to fire.

For example, an event could fire if Germany has more than 50 factories, in which the leader praises German industrial might and the country receives 100PP.

country_event = {
	id = germany.123 
        title = germany.123.t
        desc = germany.123d.d

	fire_only_once = yes
        mean_time_to_happen = { days = 1 }
	trigger = { 
            tag = GER
            num_of_factories > 50 
        }
	immediate = {}

	option = { 
		name = germany.123.a 
                add_political_power = 100 
	}
}

Let's look at this example. It can only happen once (don't want it to tell us about German industrial might over and over and give us infinite PP), the trigger is that we're Germany and we have more than 50 factories (If we don't include tag = GER this event will fire for any nation in the game that has more than >50 countries), we have a single option button and when you click it you get 100PP.

But why is this line here?

mean_time_to_happen = { days = 1 }

All triggers need a mean time to happen. Because it sets up the game to periodically check the triggers. No MTTH = Triggers never get checked (unless directly called). This is done every 20 days by default, but this value can be altered in the defines.

Using Focuses / Decisions / Events

Events can be scheduled to fire anywhere we can put an effect - for example - the effect of a decision, the completion reward of a focus, or an option in an event.

Directly scheduling events can be superior to triggers for two reasons.

  • They are easy to read in the code. A focus will direct you to an event, which directs you to the next event, and so on. If triggers were used instead (eg completed_focus) the relationship between the focus and the event would not be obvious from reading the focus.
  • It can be much more responsive than MTTH and triggers, which are checked only every 20 days by default (this checking interval can be made more frequent, but that will cause performance issues from constant checks that directly calling events does not)

Events that are fired from elsewhere always need

is_triggered_only = yes

If this code isn't included and they don't have trigger conditions and a MTTH, they will fire instantly.

Let's say I want a focus to crack down on dissent in Germany. I make a focus GER_crackdown. This focus will trigger an event, germany.124, which will present us some options about how hard we want to crack down.

In our focus GER_crackdown we will include this.

     completion_reward = {
         country_event = { id = germany.124 }
     }

Once I finish the focus, my event germany.124 will appear, asking me how hard I want to crack down.

Let's do some more. My crackdown has a few options, and option C (germany.124.c) is an over the top crackdown. Unknown to the player, if they do this it will start an uprising in 2-4 weeks, which I have created as event germany.125

In Germany.124 I include this code for option C

 	option = { 
		name = germany.124.c 
                hidden_effect = {
                     country_event = {
                          id = germany.125
                          days = 14
                          random = 336
                     }
                }
	}

What's going on here? I've used days and random together to schedule a time. It will be scheduled for (14 days) + (0 to 336 hours) from now. This doesn't use much performance like mean time to happen does, because the time gets scheduled and then the game forgets about it until then. The random factor keeps experienced players on their toes - even if they know an uprising is coming, they won't know exactly when the civil war will fire.

Using triggers in directly fired events

We can combine triggers with directly fired events. When the event is fired, it will check to see if the trigger is true, and if its not, it won't fire.

For example, in our previous example, germany.125 represented a Communist uprising, and it was set to fire a few weeks after germany.124 if the player was overzealous in their crackdown. But there's a problem. What if Germany changed government between event 124 and 125, to a Communist government? It wouldn't make much sense to have a Communist uprising against Communists! Let's make sure that if Germany is Communist when germany.125 is scheduled, that germany.125 doesn't fire.

is_triggered_only = yes 
trigger = { NOT = { has_government = communism } }

Using on_actions

On_actions are an alternative to both directly firing, or using triggers. On actions are sets of effects that occur whenever a predefined action happens.

Some examples of on_actions that can be used to activate effects

  • on_state_control_changed - effects will happen whenever a state switches sides
  • on_annex - effects will happen whenever someone is annexed
  • on_peaceconference_ended - effects will happen whenever some has a peace conference
  • on_nuke_drop - effects will happen whenever someone drops a nuke.

Why use them? Two cases.

Responsiveness / Performance

I want an event for the fall of Berlin to the Tannu Tuvan menace (event ttmenace.33). I could set up a trigger, to check Berlin and see if Tannu Tuva has taken it. But these are checked only every 20 days by default, meaning it could take weeks for that event to fire! If I make the game check more frequenly by altering the defines, performance would be hurt because of extra checks.

Instead, I could use the on_state_control_changed action. Because if Berlin ever falls under Tannu Tuvan control, the state will have changed. States don't change hands that often so its much easier performance.

I go my on_actions folder and create a new text file. on_actions are always effects - anything within them will fire along with the action. So I can't use triggers. I need to use if.

on_actions = {
	on_state_control_changed = {
		if = {
			limit = { TAN = { controls_state = 64 }	}
                        country_event = ttmenace.33
		}
        }
}

Things that don't have trigger conditions

I want something to happen when a nuke drops. My triggers can check lots of things - number of factories, PP, etc. But they can't check for dropped nukes.

There is an on_action, though - on_nuke_drop. So I can put an event under there, just the same as the previous example.

Better yet, the scopes are often defined in very useful ways. For example, in on_nuke_drop, FROM refers to the state that had the nuke dropped on it.

 Event Triggers and MTTH

All event triggers need a MTTH.

This may seem unintuitive - if we don't include a mean time to happen shouldn't the events just fire as soon as the triggers are met? Let's look at the code to understand

mean_time_to_happen = { TIMEUNIT = X}
trigger = { CONDITIONS }

This tells the game 4 things.

  1. mean_time_to_happen - Instructs the game to check the conditions periodically
  2. Time Unit - How often to check the conditions
    • days = checks every 20 days (default, defined by EVENT_PROCESS_OFFSET in the defines folder.)
    • months = monthly checks
    • years = yearly checks
  3. Conditions - The conditions that must be met to be able to fire the event
  4. X - the mean time to happen which is used to calculate the chance of firing each check. (better thought of as the median time to happen, because it represents the length of time in which there is a 50% chance of the event firing.)
    • For daily / monthly / yearly checks, as a rule of thumb, the chance per check = 1/2X (its actually generally a bit higher the true equation here)
    • However, because daily checks are not actually daily (default 20 days) the game adds up 20 days of checking each time. The chance is approximately Y/2X, where Y is the checking interval.

A few things become obvious here.

  • Without a mean time to happen, the game will never check the triggers.
  • The choice of time unit matters. { months = 3 } will check every month. { days = 90 } will check every 20 days (or however long you have set EVENT_PROCESS_OFFSET)
  • X does not tell HOI4 when to fire the event. It tells HOI4 what the chances are of firing for a given check.

Let's look at some examples

mean_time_to_happen = { days = 1 }

The game checks the triggers every 20 days (default). Y/2X = 20/2 = more than 100% per chec. In reality the chance is not quite 100%, but the event will almost always trigger on the first check.

mean_time_to_happen = { days = 30 }

The game checks the triggers every 20 days (default). Y/2X = 20/60 = 33% per check.

mean_time_to_happen = { months = 1 }

The game checks the triggers every month. If the triggers are true at the time of checking, the event will attempt to fire with a 1/2X = 1/2 = 50% chance per check

mean_time_to_happen = { months = 30 }

The game checks the triggers every month. If the triggers are true at the time of checking, the event will attempt to fire with a 1/2X=1/60=~1.7% chance.

Implications

So what does this mean? Checking a trigger regularly can have pros and cons.

If you turn down the EVENT_PROCESS_OFFSET, all your daily mtth events will check very frequently and be very responsive.

However, such checks are processor intensive. This is especially true if the event can fire for a number of countries, and involves complicated conditions.

Checking a trigger every month uses ~1/30th of the processing time of checking every day. However, the checks are more infrequent, so we shouldn't use them for time critical events that should fire shortly after the conditions are met.

By turning down the EVENT_PROCESS_OFFSET whilst categorising events into monthly (non time critical) and daily (time critical), we can have the best of both worlds. Responsive events and low performance impact!  

Advertisement