
Hi all! After a quick break, I’m back to doing dev logs. Today we're covering the events system.
Events are important for creating immersion and adding replayability to campaigns. In The Electorate, events can come in a wide number of forms. Scandals, rogue journalists, campaign staff whistleblowers, town hall Q&As, interactions at a rally, and even assassination attempts.
My main inspiration for the events system is how events are handled in Crusader Kings III, where character-focused interactions prevail and make sense in the context of the game. I believe this brings the game to life in a meaningful way, and I wanted to replicate that same idea in The Electorate.
Events can be triggered after a turn is completed or after an action is taken on the campaign trail. Events are based in game context, but are selected randomly out of a pool of hundreds of eligible events.
Every event has a title, body text that sets the scene, and up to four choices. Each choice carries structured consequences that feed directly into the game's other systems, such as your finances, media coverage, your relationships with outlets and staff, etc. Some choices are also dependent on your candidate's attributes and traits. Candidates like Donald Trump will get opportunities to hold larger rallies and boost turnout while Bernie Sanders can drive better grassroots donor support.
If you want to get a look at the internal system driving these, you can take a look at this event sample. Events are written in JSON format, and I plan on opening these up for modding.
{
"scandal.0001": {
"Category": "Scandal",
"Subtype": "Finance",
"MinProgress": 0.0,
"MaxProgress": 1.0,
"Weight_Base": 1.0,
"EventTitle": "{CandidateName} Faces Questions Over Donor Ties",
"EventBody": "A report published by {OutletName} has surfaced contributions from
{DonorName} to the {CandidateName} campaign. Your communications
team is asking for direction.",
"Conditions": [
{ "Field": "ScandalScore", "Op": "GreaterThan", "Value": 40 },
{ "Field": "MediaSpin", "Op": "LessThan", "Value": 5 },
{ "Field": "CashOnHand", "Op": "GreaterThan", "Value": 500000 }
],
"Choices": [
{
"Text": "Release a full statement and get ahead of the story.",
"Effects": [
{ "Target": "Candidate", "Stat": "MediaSpin", "Value": 3 },
{ "Target": "Candidate", "Stat": "ScandalScore", "Value": -10 },
{ "Target": "Candidate", "Stat": "CashOnHand", "Value": -200000 }
]
},
{
"Text": "Say nothing and let the story die on its own.",
"Effects": [
{ "Target": "Candidate", "Stat": "MediaSpin", "Value": -5 },
{ "Target": "Candidate", "Stat": "ScandalScore", "Value": 5 }
]
}
]
}
}
A few things worth pointing out here. MinProgress and MaxProgress are used to define the eligible timeline for an event. This means certain “October Surprises” can be locked to MinProgress > .9, where 90% of the campaign is completed. This also allows for historical events to be eligible to fire at certain times. For example, in the 2024 campaign scenario, if Joe Biden is the Democratic candidate, an event fires at the midpoint of the campaign.
{
"biden_dropout.0001": {
"Category": "Historical",
"Subtype": "CandidateChange",
"MinProgress": 0.45,
"MaxProgress": 0.55,
"Weight_Base": 999.0,
"EventTitle": "A Nation Watches: The President Considers His Future",
"EventBody": "The debate is over, and the reviews are brutal. Donors are frantic. Senior members of the party are meeting behind closed doors. Your approval among likely Democratic voters has slipped to its lowest point of the campaign, and even your inner circle is divided. Some believe you are the only candidate with the record and credibility to defeat {OpponentName}. Others are not so sure. The decision, as it has always been, is yours alone.",
"Conditions": [
{ "Field": "IsIncumbent", "Op": "Equals", "Value": 1 },
{ "Field": "IsHistorical", "Op": "Equals", "Value": 1 },
{ "Field": "NationalPoll", "Op": "LessThan", "Value": 0.45 },
{ "Field": "Favorability", "Op": "LessThan", "Value": 0.45 }
],
"Choices": [
{
"Text": "I have served this country my entire adult life. I am not going anywhere.",
"Flavor": "You will remain playing as Joe Biden.",
"Effects": [
{ "Target": "Candidate", "Stat": "Favorability", "Value": -5 },
{ "Target": "Candidate", "Stat": "MediaSpin", "Value": -2 },
{ "Target": "Candidate", "Stat": "ScandalScore", "Value": 10 }
]
},
{
"Text": "I am withdrawing from the race and endorsing Vice President Harris.",
"Flavor": "You will begin playing as Kamala Harris.",
"Effects": [
{ "Target": "GameState", "Stat": "SwitchCandidate", "Value": "KamalaHarris" },
{ "Target": "Candidate", "Stat": "MediaSpin", "Value": 4 },
{ "Target": "Candidate", "Stat": "Favorability", "Value": 8 }
]
},
{
"Text": "I am stepping aside. The party should decide who leads us forward.",
"Flavor": "The Democratic Party will choose a new candidate.",
"Effects": [
{ "Target": "GameState", "Stat": "SwitchCandidate", "Value": "PartyChoice" },
{ "Target": "Candidate", "Stat": "MediaSpin", "Value": 2 },
{ "Target": "Candidate", "Stat": "Favorability", "Value": 3 }
]
}
]
}
}
The Conditions block determines whether an event is eligible to fire at all. This one requires your NationalPoll and Favorability to be below 45% and for you to be playing as Joe Biden. If those conditions are not true, the event never fires. However, if those are true, notice the Weight_Base is 999.0. This effectively guarantees that the event will fire.
Every turn, the game builds a context snapshot for each candidate. These are a collection of numeric and string values that check for things like your current polling trends, cash on hand, scandal score, media spin, favorability, etc.
The context is checked against the full cache of events not triggered yet. Any event where all conditions pass and whose progress window matches the current point in the campaign gets added to the eligible pool. From that pool, a weighted random selection is made and selects one event to fire.
Every event has a base weight, but the system scales those weights before selection based on what's actually happening in the race. When your scandal score is climbing, scandal events get dramatically heavier weights. When you're riding a polling surge, momentum events bubble up. The system is always pushing the most contextually relevant events to the front without any of that logic touching the event definitions themselves.
Once an event fires, it's removed from the cache permanently. Events are not duplicated at any point in the same campaign (unless there’s a bug).
That’s the event architecture. There’s plenty more to come as the system evolves, but this is what you can expect from the 1.0 version of the game.
As always, thanks for following along. If you haven’t already join the Discord to stay up to date on development and help guide the game’s future! And of course, be sure to wishlist The Electorate on Steam!