Taking a peek into how Avenger Events works
 
An Avenger Event can go through a bit of a convoluted process in order to hit the "choose an option" screen you see in the workshop screen.


First, we must hit either the resistance report screen (this is when the Councilman tells you your progress was medicore due to hitting no facilities, even if you've been stomping ADVENT otherwise), or have something trigger a specific action the player does, like contacting a region.


If it's from a specific action, it's a pretty simple thing from there:

static function EventListenerReturn OnForgeCompleted(Object EventData, Object EventSource, XComGameState NewGameState, Name EventID)
{
local int idx;
local XComGameStateHistory History;
local XComGameState_AvengerEvent AvengerEventState;
local X2StrategyElementTemplateManager StratMgr;
local X2StrategyElement_AvengerEventTemplate EventTemplate;
local StateObjectReference DummyReference;

if (NewGameState.GetContext( ).InterruptionStatus == eInterruptionStatus_Interrupt)
{
return ELR_NoInterrupt;
}

History = `XCOMHistory;
StratMgr = class'X2StrategyElementTemplateManager'.static.GetStrategyElementTemplateManager();
EventTemplate = X2StrategyElement_AvengerEventTemplate(StratMgr.FindStrategyElementTemplate('AvengerEvent_PlotAdvanced'));


foreach History.IterateByClassType(class'XComGameState_AvengerEvent', AvengerEventState)
{
if(AvengerEventState.GetMyTemplate() == EventTemplate)
{
`log("Already did this event.");
return ELR_NoInterrupt;

}


}

AvengerEventState = XComGameState_AvengerEvent(NewGameState.CreateStateObject(class'XComGameState_AvengerEvent'));
NewGameState.AddStateObject(AvengerEventState);
AvengerEventState.OnCreation(EventTemplate);
AvengerEventState.SetProjectFocus(DummyReference);


return ELR_NoInterrupt;
}

We basically find the template we need to call upon (we're using the "finished a story mission" event for this), see if we can roll for it, then if we do, we initiate the event and wait for it to proc after the player has passed enough time on the geoscape.


If it's from the resistance recap though, we go through that convoluted process I mentioned earlier.

// Iterate through the templates and build each DarkEvent State Object
foreach History.IterateByClassType(class'XComGameState_AvengerEvent', AvengerEventState)
{
LastState = XComGameState_LastAvengerEvent(`XCOMHISTORY.GetSingleGameStateObjectForClass(class'XComGameState_LastAvengerEvent'));


if(LastState == none)
`log("We don't seem to have a last state even though we should, inform RealityMachina of this.");


if(LastState != none)
{
if(AvengerEventState.GetMyTemplateName() == LastState.LastEvent && X2StrategyElement_AvengerEventTemplate(AvengerEventTemplates[idx]).DataName == AvengerEventState.GetMyTemplateName()) //if we just had this event last time
{
`log("Removing event we just had.");
AvengerEventTemplates.RemoveItem(AvengerEventTemplates[idx]);
break;
}
}

if(AvengerEventState.GetProjectedNumHoursRemaining() > 0 && !AvengerEventState.IsFromAction()) //if we still have an existing  project, instantly quit
{
`log("Already working on a project, abort.");
return;
}

for(idx = 0; idx < AvengerEventTemplates.Length; idx++)
{

//XComHQ = XComGameState_HeadquartersXCom(`XCOMHISTORY.GetSingleGameStateObjectForClass(class'XComGameState_HeadquartersXCom'));


if(X2StrategyElement_AvengerEventTemplate(AvengerEventTemplates[idx]).DataName == AvengerEventState.GetMyTemplateName() && AvengerEventState.CanActivate() && AvengerEventState.HasCompleted == true && !AvengerEventState.IsFromAction())
{
`log("Found existing event we could use.");
AvengerEventTemplates.RemoveItem(AvengerEventTemplates[idx]); //since we're using the weight system, we don't need to keep this in the pool
ExistingEvents.AddItem(AvengerEventState); //this is for existing events that were spawned before the weight system
for(k = 0; k < AvengerEventState.Weight; k++)
{
ExistingEvents.AddItem(AvengerEventState);
}
break;
}

if((X2StrategyElement_AvengerEventTemplate(AvengerEventTemplates[idx]).DataName == AvengerEventState.GetMyTemplateName() && !AvengerEventState.CanActivate())|| AvengerEventState.IsFromAction())
{
`log("Found existing event we can't use.");
AvengerEventTemplates.RemoveItem(AvengerEventTemplates[idx]);
break;
}


if(X2StrategyElement_AvengerEventTemplate(AvengerEventTemplates[idx]).NeedsEvent)
{
`log(AvengerEventTemplates[idx].DataName $ " can only be spawned from a player action.");
AvengerEventTemplates.RemoveItem(AvengerEventTemplates[idx]);
break;
}

}
}


We basically go through every single existing event state, and with a list of all our avenger event templates, we try to cross off potential events we can no longer do, or can't be done at a player's particular point in a campaign. We also make sure we don't repeat an event the player had just done last month.


Note that this isn't foolproof: I had to make tradeoffs since there isn't an easy system for me to hook into and I have to make sure the mod doesn't crash the game from trying to do a long loop of checks: an event that can't be done may be initially chosen and thus cause a player to experience no events for a month, though that may be helpful in some situations.

Then after that, it's a simple matter of making sure we do have a valid event to use, deciding whether or not we want to use a new event or re-do an old one, then initiating that event.


The base mod handles all this: additional packs, like the Long War 2 one I made, will simply add additional events, they don't need to do anything complicated like this.