davidlallen Posted February 27, 2016 Share Posted February 27, 2016 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 More sharing options...
Deleted32045420User Posted February 27, 2016 Share Posted February 27, 2016 You can create a new Change Container state. `XCOMHISTORY.CreateNewGameState(true, class'XComGameStateContext_ChangeContainer'.static.CreateEmptyChangeContainer("blah blah blah")); Link to comment Share on other sites More sharing options...
davidlallen Posted February 27, 2016 Author Share Posted February 27, 2016 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 More sharing options...
Deleted32045420User Posted February 27, 2016 Share Posted February 27, 2016 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 More sharing options...
davidlallen Posted February 27, 2016 Author Share Posted February 27, 2016 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 More sharing options...
Amineri Posted February 28, 2016 Share Posted February 28, 2016 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 More sharing options...
davidlallen Posted February 28, 2016 Author Share Posted February 28, 2016 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 More sharing options...
Amineri Posted February 28, 2016 Share Posted February 28, 2016 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 More sharing options...
davidlallen Posted February 28, 2016 Author Share Posted February 28, 2016 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 More sharing options...
davidlallen Posted March 1, 2016 Author Share Posted March 1, 2016 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 More sharing options...
Recommended Posts