Jump to content

when is the earliest i can access state objects?


davidlallen

Recommended Posts

I have the following in a uiscreenlistener, and it works properly to create some proving ground objects (this is for playable advent):

 

 

 

function UpdateTemplates()
{
... local declarations ...
History = `XCOMHISTORY;
PrevGameState = History.GetGameStateFromHistory();
context = PrevGameState.GetContext();
NewGameState = History.CreateNewGameState(false, context);
foreach History.IterateByClassType(class'XComGameState_Tech', TechState)
{
if (TechState.GetMyTemplateName() == 'DLA_AR_MecTechTemplate')
{
alreadyExists = true;
}
}
if (!alreadyExists)
{
tMec = new class'DLA_AR_MecTech';
techMec = tMec.CreateTemplate();
tState = XComGameState_Tech(NewGameState.CreateStateObject(class'XComGameState_Tech'));
tState.OnCreation(techMec);
NewGameState.AddStateObject(tState);
}
History.AddGameStateToHistory(NewGameState);
}

 

I would like to avoid screen listeners if possible. So I put the bottom part of this code (the part inside if !alreadyExists) into a different place, file X2DownloadableContentInfo_<modname>.uc, function OnLoadedSaveGame. The code is being executed but there is a runtime violation in the log file:

 

 

 

[0022.71] ScriptWarning: Accessed None 'stateGame'

X2DownloadableContentInfo_AdventRookies AdventRookies.Default__X2DownloadableContentInfo_AdventRookies

Function AdventRookies.X2DownloadableContentInfo_AdventRookies:doAllInit:013B

 

 

So, the state doesn't exist yet. Is there another place I can put this, which doesn't hook into a UI screen? This just feels like the wrong place to put it.

Link to comment
Share on other sites

OK, how do I use that? It sounds like I would be saying, "here is a change to a state which doesn't exist yet", which is fine; but then how does that queued object actually get applied? Does that happen invisibly to me, or do I need to go somewhere else and add code which digs things out of the queue and applies them?

Link to comment
Share on other sites

OK, how do I use that? It sounds like I would be saying, "here is a change to a state which doesn't exist yet", which is fine; but then how does that queued object actually get applied? Does that happen invisibly to me, or do I need to go somewhere else and add code which digs things out of the queue and applies them?

That'll apply on it's own i think. all i can see it saying is that it dosnt have a state

Link to comment
Share on other sites

I guess my xcom-uc-fu is not strong enough yet. I need a XComGameState_Tech object in order to call:

local X2TechTemplate x;

state.OnCreation(x)

The function you mention returns XComGameState, and I don't know how to cast it, or redeclare it, or find a variant function of the right type.

I am really still in the dark about what history and gamestates are. So far, I feel like I can occasionally cut and paste a piece of code successfully, but I certainly don't feel like I could write any working code from scratch.

Link to comment
Share on other sites

I'm not quite able to follow what's happening here, since you didn't post the code in your X2DownloadableContentInfo child class.

 

Your error says

 

 

ScriptWarning: Accessed None 'stateGame'

 

But I don't see any reference to such a variable in the posted code.

 

However, you should note that

OnLoadedSaveGame
isn't supposed to trigger for every load, only the first time your mod is loaded for a particular save. This is the main reason I don't use this for changing templates with difficulty variants.
Link to comment
Share on other sites

Sorry, earlier I had pasted together one code fragment with the message from a slightly different version.

 

I think using OnLoadedSaveGame should work, if I understand the history object correctly. As long as the objects are stored in the history during the first OnLoadedSaveGame, then we don't need to do it again for saves of that game, regardless of how much later they are saved.

 

However, the following code has no effect, and I don't understand why. It is supposed to add two proving ground projects. The same code in a UIScreenListenerProvingGrounds does add the projects. For this code, my start and finish log messages appear in the log file, and no other messages appear in between (like references to invalid states). What am I missing? This appears to be some fundamental concept problem I just haven't gotten yet.

class X2DownloadableContentInfo_PlayableAdvent extends X2DownloadableContentInfo;
static event OnLoadedSavedGame()

{

    doAllInit();

}
static event InstallNewCampaign(XComGameState StartState)

{

    doAllInit();

}
static function doAllInit()

{

    local X2StrategyElementTemplateManager stratMan;

    local PA_MecTech classMec;

    local PA_ViperTech classViper;

    local X2TechTemplate techMec, techViper;
    local XComGameState_Tech stateTech;

    local XComGameState stateGameNew, stateGameOld;

    local XComGameStateHistory History;
    `log ("davea debug ar start allinit");
    // Set up techs (previously in UIScreenListener)

    classMec = new class'PA_MecTech';

    classViper = new class'PA_ViperTech';

    techMec = classMec.CreateTemplate();

    techViper = classViper.CreateTemplate();

    stratMan = class'X2StrategyElementTemplateManager'.static.GetStrategyElementTemplateManager();

    stratMan.AddStrategyElementTemplate(techMec, true);

    stratMan.AddStrategyElementTemplate(techViper, true);
    // Set up projects (still in UIScreenListenerProvingGround, because the below has no effect

    History = `XCOMHISTORY;

    stateGameOld = History.GetGameStateFromHistory();

    stateGameNew = History.CreateNewGameState(false, stateGameOld.GetContext());

    stateTech = XComGameState_Tech(stateGameNew.CreateStateObject(class'XComGameState_Tech'));

    stateTech.OnCreation(techMec);

    stateGameNew.AddStateObject(stateTech);

    stateTech = XComGameState_Tech(stateGameNew.CreateStateObject(class'XComGameState_Tech'));

    stateTech.OnCreation(techViper);

    stateGameNew.AddStateObject(stateTech);
    `log ("davea debug ar finish allinit");

}

 
Link to comment
Share on other sites

Okay, I think I see the issue. There's sort of two problems.

 

The first is that you are attempting to directly manipulate the current GameState in the history, instead of submitting a delta state. This is technically valid, but I don't think it's the "approved" way to interface with the History.

 

For submitting changes to the history in X2DownloadableContentInfo I typically use the following boilerplate:

NewGameState = class'XComGameStateContext_ChangeContainer'.static.CreateChangeState("Descriptive Text");
stateTech = XComGameState_Tech(NewGameState.CreateStateObject(class'XComGameState_Tech'));
NewGameState.AddStateObject(stateTech);
<< do stuff here>>
History.AddGameStateToHistory(NewGameState);
In other places, I'll replace the last line with
`GAMERULES.SubmitGameState(NewGameState);
-----------------
Second, this approach won't generally work in the InstallNewCampaign case. The StartState is being passed for a reason -- it's intended that the mod add things to/change things in the supplied StartState, not work from the History. The StartState being supplied is what is being created, and has not yet been submitted.
So in this case, your code would look more like :

stateTech = XComGameState_Tech(StartState.CreateStateObject(class'XComGameState_Tech'));
stateTech.OnCreation(techMec);
StartState.AddStateObject(stateTech);
Where StartState is the GameState being passed through InstallNewCampaign.

 

Link to comment
Share on other sites

Thanks, I will try that out. Suppose I need to install 8 new items like this. It sounds like you are saying I need one function which does all 8 one way for the load entry point, and another function which does all 8 a slightly different way for the new campaign entry point. Is that correct? Is there no way to share the code?

Link to comment
Share on other sites

So, the following is working, but I still don't have a high level understanding of what I am doing. This is the main action function in my X2DownloadableContentInfo_PlayableAdvent class. It seems like I am adding the same tech information twice, once to the StrategyElementTemplateManager, and the same tech information again to the ChangeStateContainer. Why do I need to do it twice?

 

static function doAllInit()
{
    local X2StrategyElementTemplateManager stratMan;
    local PA_MecTech classMec;
    local PA_ViperTech classViper;
    local PA_ChrysTech classChrys;
    local X2TechTemplate techMec, techViper, techChrys;
    local XComGameState_Tech stateTech;
    local XComGameState stateGame;
    `log ("davea debug ar start allinit");
    // Set up techs (previously in UIScreenListener)
    classMec = new class'PA_MecTech';
    classViper = new class'PA_ViperTech';
    classChrys = new class'PA_ChrysTech';
    techMec = classMec.CreateTemplate();
    techViper = classViper.CreateTemplate();
    techChrys = classChrys.CreateTemplate();
    stratMan = class'X2StrategyElementTemplateManager'.static.GetStrategyElementTemplateManager();
    stratMan.AddStrategyElementTemplate(techMec, true);
    stratMan.AddStrategyElementTemplate(techViper, true);
    stratMan.AddStrategyElementTemplate(techChrys, true);
    // Set up projects (previously in UIScreenListenerProvingGround)
    stateGame = class'XComGameStateContext_ChangeContainer'.static.CreateChangeState("PA_tech_init");
    stateTech = XComGameState_Tech(stateGame.CreateStateObject(class'XComGameState_Tech'));
    stateTech.OnCreation(techMec);
    stateGame.AddStateObject(stateTech);
    stateTech = XComGameState_Tech(stateGame.CreateStateObject(class'XComGameState_Tech'));
    stateTech.OnCreation(techViper);
    stateGame.AddStateObject(stateTech);
    stateTech = XComGameState_Tech(stateGame.CreateStateObject(class'XComGameState_Tech'));
    stateTech.OnCreation(techChrys);
    stateGame.AddStateObject(stateTech);
    `XCOMHISTORY.AddGameStateToHistory(stateGame);
}
Link to comment
Share on other sites

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...