Jump to content

Mod help: conditional Blademaster?


SteelRook

Recommended Posts

Note: The above only affects the template loaded for the current difficulty. To avoid bugs caused by the player changing difficulties you need to do something more like this:

 

local int i;
local X2WeaponTemplate WeaponTemplate;
local int DifficultyIndex, OriginalDifficulty, OriginalLowestDifficulty;
local XComGameState_CampaignSettings Settings;
local XComGameStateHistory History;

History = `XCOMHISTORY;
Settings = XComGameState_CampaignSettings(History.GetSingleGameStateObjectForClass(class'XComGameState_CampaignSettings', true));
if(Settings != none)
{
	OriginalDifficulty = Settings.DifficultySetting;
	OriginalLowestDifficulty = Settings.LowestDifficultySetting;

	for( DifficultyIndex = `MIN_DIFFICULTY_INDEX; DifficultyIndex <= `MAX_DIFFICULTY_INDEX; ++DifficultyIndex )
	{
		// Set difficulty temporarily
		Settings.SetDifficulty(DifficultyIndex, true);

		// FETCH ARRAY OF WEAPON TEMPLATES HERE - The game will return the templates in memory for the currently set difficulty
		
		// LOOP THROUGH TEMPLATES AND MAKE CHANGES AS ABOVE
	}
	//Restore difficulty values to what the player had chosen before we changed them temporarily above
	Settings.SetDifficulty(OriginalLowestDifficulty, true);
	Settings.SetDifficulty(OriginalDifficulty, false);
	return success;
}	
The above example is similar to what Amineri posted here: http://forums.nexusmods.com/index.php?/topic/3771570-overriding-vanilla-content/?p=34270720

 

A bit of a blast from the past for which I apologise, but my head's a bit clearer today and I think I can address this. By "address" I'm actually talking about "ask more questions" :smile: Preferably here so it applies to this mod, rather than derail someone else's thread elsewhere. So I have one central question which applies to both your example and Amineri's example in the link: Are you saying that each template is "cloned" after it's created, and four separate versions of it are created, each with their own stats? If so, where does this happen? I can't seem to find a function which creates four versions of, for instiance, 'Sword_BM' and gives them all different stats. I'm sure there is one, I just can't find it.

 

I did have a thorough look through X2DataTemplate, though - the class which all templates extend. That does have settings for campaign difficulty, as well as for strategy, tactical, online, etc, each of them seemingly held in a binary variable though I'm not certain - a variable type is not declared, which I'm not sure how UnrealScript handles that. Basically, though, this is the exact same system City of Heroes used to use for team search flagging. Every flag is set as a subsequent power of 2, as this ensures every sum of parameters is unique. Which I guess dates back to unix/linux permission settings, just with more numbers. So that settles it in my eyes - each template is taged with what difficulty it can appear in, and some templates can be tagged to appear in multiple difficulties. Fair enough.

 

This makes me understand the fact that templates ARE difficulty-specific, but it doesn't answer my question of where that's determined. From Animeri's example, it seems to me like the X2ItemTemplateManager holds all of the items for all of the difficulties, since the same object gets called in all cases, but that it somehow limits its searches based on difficulty. I'm completely lost as to where in the code this is handled because X2ItemTemplateManager's FindItemTemplate() function calls a FindDataTemplate() function not defined in the class. It's defined in its parent class, of course - X2DataTemplateManager... Except it isn't. Now, this is probably me not understanding UnrealScript, but here's how the function is defined in X2DataTemplateManager:

protected native function X2DataTemplate FindDataTemplate(name DataName) const;

To me, that's a virtual function which should be implemented in a child class. Even the comments seem to suggest this, though I don't fully understand what they mean: "Child classes should implement a public wrapper that returns the class appropriate to the manager." So what I see is a virtual function with no defined body which is never implemented yet is still being used in the child class. How is this possible? I know UnrealScript is its own language, but either I'm missing something major here or a fundamental OOP principle is being violated, and I can't tell for the life of me what's going on. This is not the first time I've seen this happen, either. Where are these mysterious functions defined?

 

And this still leaves another, far more major question - if X2ItemTemplateManager holds multiple copies of the same template but only returns the one applicable to the given difficulty of the campaign, why is "difficulty" never once brought up anywhere in the class? Because to me, from casual observation of the code and template generation process, I don't see any way for FindItemTemplate() to return a different template based on the game's current difficulty. Not unless a difficulty check is hiding in the phantom FindDataTemplate() function which I don't even know where the body for that one is.

 

---

 

I'm not trying to be difficult, I honestly am not. I'm just trying to understand how the system is set up because I physically can't deal with code that I don't understand on at least some level. I wasn't joking earlier, when I claimed to never copy-paste code. If I don't know what each line is doing along with how and why it does what it does, I can't make it happen. I'm lost like a little kid trying to do calculus with grade school math. I'm missing a link here, and it feels like a vital piece of information.

Edited by SteelRook
Link to comment
Share on other sites

  • Replies 84
  • Created
  • Last Reply

Top Posters In This Topic

Take a look at X2DataSet.uc, the class from which X2DataTemplate inherits. You need to follow the white rabbit deeper. :)

Relevant excerpts from X2DataSet.uc:

/// <summary>
/// Native accessor for CreateTemplates. Used by the engine object and template manager
/// to automatically pick up new templates.
/// </summary>
static event array<X2DataTemplate> CreateTemplatesEvent()
{
	// Snip
		if( CurrentBaseTemplate.bShouldCreateDifficultyVariants )
		{
			CreateDifficultyVariantsForTemplate(CurrentBaseTemplate, NewTemplates);
		}
		else
		{
			NewTemplates.AddItem(CurrentBaseTemplate);
		}
	// Snip
}
/// <summary>
/// Helper function to construct Difficulty variants for each difficulty.
/// </summary>
static function CreateDifficultyVariantsForTemplate(X2DataTemplate BaseTemplate, out array<X2DataTemplate> NewTemplates)
{
	local int DifficultyIndex;
	local X2DataTemplate NewTemplate;
	local string NewTemplateName;

	for( DifficultyIndex = `MIN_DIFFICULTY_INDEX; DifficultyIndex <= `MAX_DIFFICULTY_INDEX; ++DifficultyIndex )
	{
		NewTemplateName = BaseTemplate.DataName $ "_Diff_" $ DifficultyIndex;
		NewTemplate = new(None, NewTemplateName) BaseTemplate.Class (BaseTemplate);
		NewTemplate.SetDifficulty(DifficultyIndex);
		NewTemplates.AddItem(NewTemplate);
	}
}
Link to comment
Share on other sites

 

Take a look at X2DataSet.uc, the class from which X2DataTemplate inherits. You need to follow the white rabbit deeper. :smile:

 

But... But X2DataTemplate doesn't say it inherits X2DataSet :smile: Thank you kindly, I'll review X2DataSet as soon as I can. What mislead me is the X2DataTemplate class definitions, though:

class X2DataTemplate extends Object

Again, this is very likely me just not understanding UnrealScript, but when I see something which extends Object and doesn't list any other extensions, I scratch my head. Regardless, thanks for the advise. X2DataSet should hold the answers I need, hopefully. Apologies for being dense :smile:

 

*edit*

Ah! OK, now I see what's going on here. Cheeky, cheeky developers! So how creating templates goes is CreateTemplatesEvent() gets called, which calls the CreateTemplates() function that I was trying to override before. The array that produces isn't stuffed directly into memory, however, but rather is parsed element by element. For each template which bShouldCreateDifficultyVariants is true, four other templates are created, one for each difficulty setting, and each is added separately into a NEW list. If bShouldCreateDifficultyVariants, then the template itself is added into the new list without being cloned four times. It's this new list that gets committed to memory and which the game uses. I knew there was shenanigans afoot somewhere along the line. Thanks for directing me to this, I actually understand now!

Edited by SteelRook
Link to comment
Share on other sites

 

 

Take a look at X2DataSet.uc, the class from which X2DataTemplate inherits. You need to follow the white rabbit deeper. :smile:

 

But... But X2DataTemplate doesn't say it inherits X2DataSet :smile: Thank you kindly, I'll review X2DataSet as soon as I can. What mislead me is the X2DataTemplate class definitions, though:

class X2DataTemplate extends Object

Again, this is very likely me just not understanding UnrealScript, but when I see something which extends Object and doesn't list any other extensions, I scratch my head. Regardless, thanks for the advise. X2DataSet should hold the answers I need, hopefully. Apologies for being dense :smile:

 

 

My bad, you're totally right. X2DataTemplates are used by X2DataSet - They don't extend it. X2DataSet is the class that picks up the templates in response to an event fired somewhere in the game's native code.

Link to comment
Share on other sites

That still leaves me with an open question, however - where is FindDataTemplate(name DataName) defined? A definition line turns up in X2DataTemplateManager, but that's a virtual function near as I can tell - it has no function body. It's not defined anywhere that I can see, yet X2ItemTemplateManager makes calls to it. Considering X2ItemTemplateManager directly extends X2DataTemplateManager, there really isn't any place in-between the two classes for that function to be defined. I have a very strong degree of suspicion that whatever code handles finding the specific version of an object with a given name which matches the current difficulty is hidden in there, but I can't find the function itself. Even "find in files" search through the entire "class" folder reveals nothing - it gives me only the one virtual bodiless definition in X2DataTemplateManager and then calls for it throughout all the classes which extend that. Your previous piece of advice set me on the right path as to how the templates are created, now we're have to consider how they're searched for.

 

Although it looks like I might be able to skip a step. X2ItemTemplateManager has a GetAllWeaponTemplates() function which just returns an array of presumably all weapon templates in the game. It does have a strange IterateTemplates(Template, none) function which may or may not be standard UnrealScript, but by my reckoning this should have all-difficulty versions of the weapon templates. From that point on, I can iterate over that array element-by-element and find all the templates which match, for instance, Sword_BM. Each template should hold its own individual difficulty allocation, so replacing them in the array shouldn't be too hard... Although putting that array back into the template manager may not be as simple. It gives me better, more direct control over the data, though, so it's a starting point. Of course, presuming that works like I think it works.

 

*edit*

And of course IterateTemplates(Template, none) has the same issue as FindDataTemplate(name DataName), in that it's defined without a body and seemingly never implemented. There's something odd going on here. I smell C++ :: operator shenanigans with functions implemented outside of their respective class bodies.

Edited by SteelRook
Link to comment
Share on other sites

/** 
 *  @return the template in the GameDataCache that matches the provided name. 
 *  Child classes should implement a public wrapper that returns the class appropriate to the manager.
 */
protected native function X2DataTemplate FindDataTemplate(name DataName) const;

If you look closely you'll see that FindDataTemplate() is defined with the keyword 'native', which means that line is just exposing access in UnrealScript to a function implemented in C++ in the game's executable. They typically do that for stuff that needs to execute fast.

According to Epic, UnrealScript is approximately 20x slower than native C++ code in typical use - So you can see why Firaxis would want to do that for iterator functions.

 

Regarding your 2nd paragraph, I already covered that stuff back on page 3 of this thread, here: http://forums.nexusmods.com/index.php?/topic/3805750-mod-help-conditional-blademaster/?p=34649260 :)

 

Link to comment
Share on other sites

If you look closely you'll see that FindDataTemplate() is defined with the keyword 'native', which means that line is just exposing access in UnrealScript to a function implemented in C++ in the game's executable. They typically do that for stuff that needs to execute fast.

According to Epic, UnrealScript is approximately 20x slower than native C++ code in typical use - So you can see why Firaxis would want to do that for iterator functions.

 

So that's what "native" means, then. I've been trying to figure that out, but I must have been reading the wrong articles. Google fail, my bad. That's unfortunate news, however, since the underlying C++ code isn't exposed to the best of my knowledge. But at least my nose was right - this does really strike me as a :: implementation. Thanks for the clarification :smile:

 

Regarding your 2nd paragraph, I already covered that stuff back on page 3 of this thread, here: http://forums.nexusmods.com/index.php?/topic/3805750-mod-help-conditional-blademaster/?p=34649260 :smile:

Yeah, I do remember that :) I actually went back to check your code supplements as I recall you gave me an example with iterating over an array. My thought process is just a bit chaotic, is all. As my multiple edits indicate, I'm doing these responses sort of ad-hoc, figuring stuff out as I type. My learning method has a weird aspect to it, in that I often don't know what to do with really good answers until I come up with the questions which require them. Your previous bit of advise gave me the right question, now I need to examine the answers you provided me with.

 

I sincerely want to thank you for your patience. I have to imagine my constant questions are irritating, but you're helping me more than I can describe. And putting me to shame, too, since I teach Java programming in the University, yet I'm fumbling with this like I'm touching code for the first time :)

Link to comment
Share on other sites

 

I sincerely want to thank you for your patience. I have to imagine my constant questions are irritating, but you're helping me more than I can describe. And putting me to shame, too, since I teach Java programming in the University, yet I'm fumbling with this like I'm touching code for the first time :smile:

 

 

Not irritating at all, I wouldn't be answering if I didn't want to. :) My previous-to-current job was as a University Lecturer in CS so I got used to answering questions on programming problems. ;)

Link to comment
Share on other sites

So I have a question, now that I've had time to look at the code. There seem to be a couple of ways to gain access to a weapon's template. One is via the FindItemTemplate() function from the X2ItemTemplateManager class, which you've already told me will only produce one weapon template - the one which fits the given difficulty. Another way that you suggested to me on Page 3 of this thread was either using the IterateTemplates() function, or else the function the name of which escapes me at the moment which gives you an array with all items in it. Question, then: Does the array in the second method contain all variants of the same weapon? From how it's built, it seems like it should, but I'm not entirely sure.

I see your suggestion is to pull items out of the array and edit them in place. Since I'm editing object references, my changes will naturally propagate to the array itself, which is also full of object references pointing to the same address in memory. That's fine if I want to alter the weapon templates, but not so fine if I want to replace them. Is there any way I can edit the array of all items in the game directly? Like, add more items to it or remove items from it? Both your example and Amineri's come down to IterateTemplates(), which I strongly suspect is difficulty-filtered in terms of what it returns, and that concerns me.

 

Assuming any data I can pull out of the template managers is ALWAYS going to default to my set difficulty, is there an issue setting this in the main menu? I know you've advised me to not do that, but both your example and Amineri's use ScreenClass = none; for the event listener, which I thought would make it fire in the main menu anyway (as it would fire on any UI element)? Why is messing with difficulty in the main menu a problem anyway? Does that somehow interfere with setting difficulty? Because it seems to me like difficulty exists even in the main menu, else the FindWeaponWithName() functions wouldn't work - they appear to depend on current difficulty. Moreover, since "difficulty" is just an integer anyway, it seems like I can iterate 0 to 3 right in the main menu and get all difficulties without accidentally tagging a save game with lower difficulty and robbing it of earning achievements.

 

*edit*

And it seems to me like I can use redscreen errors as an visual on-screen logging means, no? If I can spawn a redscreen error with any text on it, could I use that to track what my mod is doing even if it's working properly? Just for testing, of course - don't want to throw redscreen errors at the player in the finished form.

Edited by SteelRook
Link to comment
Share on other sites

  • Recently Browsing   0 members

    • No registered users viewing this page.

×
×
  • Create New...