Jump to content

Overriding Vanilla Content?


FriarChris

Recommended Posts

 

Also, that compiles fine but it doesn't actually change the slots :/

 

Whoopsie, that may have been a bad example. The AR may already have been instanced as a gamestate (so that each weapon can be customized separately), in which case changing the template does nothing.

 

In general:

Template = there can be only one...

GameState = there can be many copies... (although there are singleton gamestates as well)

Link to comment
Share on other sites

Tested this super hack with tactical layer and was able to access kismet data. But found another funny bug in the process. :)

 

Here's my tactical hook:

 

 

 

class UIScreenListener_TacticalHUD_TacticalHook extends UIScreenListener;

event OnInit(UIScreen Screen)
{
    local WorldInfo wInfo;
    local Sequence mainSequence;
    local array<SequenceObject> SeqObjs;
    local int i;
   
    wInfo = `XWORLDINFO;
    mainSequence = wInfo.GetGameSequence();

    `Log("########################################## TacticalHook ##########################################");
    if (mainSequence != None)
    {
        `Log("GameSequence = " $ mainSequence);
        mainSequence.FindSeqObjectsByClass( class'SeqVar_Int', true, SeqObjs);
        if(SeqObjs.Length != 0)
        {
            `Log("Named vars found");
            for(i = 0; i < SeqObjs.Length; i++)
            {
                if(InStr(string(SequenceVariable(SeqObjs[i]).VarName), "TurnsRemaining") != -1)
                {
                    `Log("Variable found: " $ SequenceVariable(SeqObjs[i]).VarName);
                    `Log("IntValue = " $ SeqVar_Int(SeqObjs[i]).IntValue);
                }
                if(InStr(string(SequenceVariable(SeqObjs[i]).VarName), "DefaultTurns") != -1)
                {
                    `Log("Variable found: " $ SequenceVariable(SeqObjs[i]).VarName);
                    `Log("IntValue = " $ SeqVar_Int(SeqObjs[i]).IntValue);
                }
            }
        }
    }
}

defaultProperties
{
    // Leaving this assigned to none will cause every screen to trigger its signals on this class
    ScreenClass = UITacticalHUD
}

 

 

 

So many unnecessary things there because they've named a variable "Timer.TurnsRemaining", but this is actually an illegal value for name variable. :) So an attempt to find it by name freezes the game.

Link to comment
Share on other sites

I've revised the entire thread... and i can confirm one important thing; Inspecting Amineri's work (LWS-Trio) is a must before trying to dive into much more than Templates linkage.

 

I have soooooooo many hooks to define for "Geoscapps" it could become either too daunting for my skill set (or patience) or strictly dangerous enough for stack stability. After all, i should almost aim for TexMod style activity in a few cases and still attach various custom elements to the HUD.

 

Three weeks at best... maybe i'm a bit too ambitious with such minimal concept features (heck, it HAS to be worth D/L) and yet, something tells me our oldish LW_127 Flags adventure (for example) could just be a XC2 breeze for any of you.

Time is at a premium while a lots of strict Mod-Buddy factors to assume before even distributing anything, AFAIC.

 

TBH, i feel that runtime gameplay code wasn't 100% ready (SDK seems stable though). Even a small 2% is enough to debunk a major fault.

 

Cross-fingers, people.

Edited by Zyxpsilon
Link to comment
Share on other sites

what about this? someone posted in in steam workshop ...can it work?

Create a new class to extend the X2Item_DefaultWeapons

class <NewClassName> extends X2Item_DefaultWeapons
config(<ConfigFileName>);

Create the config variable

var config int ASSAULTRIFLE_CONVENTIONAL_IUPGRADESLOTS;


override the template creation method

static function X2DataTemplate CreateTemplate_AssaultRifle_Conventional()
{
local X2WeaponTemplate Template;
Template = X2WeaponTemplate(Super.CreateTemplate_AssaultRifle_Conventional());

Template.NumUpgradeSlots = default.ASSAULTRIFLE_CONVENTIONAL_IUPGRADESLOTS;

return Template;
}

In XCom<ConfigFileName>.ini

Add the following config
[<ModName>.<NewClassName>]
;Assault Rifle
ASSAULTRIFLE_CONVENTIONAL_IUPGRADESLOTS = 2

you also need to tell the engine to override the original file by add the following in XComEngine.ini

[Engine.Engine]
+ModClassOverrides=(BaseGameClass="X2Item_DefaultWeapons", ModClass="<NewClassName>")

You only need to override the method / template you want to change.
Edited by flankers
Link to comment
Share on other sites

When trying to make programmatic changes to already-loaded templates I discovered some odd behaviour that may be useful to know:
(Maybe you all know this already and I'm being redundant, but hopefully this is useful to someone :tongue:)

+ Overrode X2Item_DefaultSchematics:CreateTemplates()
+ I assumed that my override would fully replace CreateTemplates() like a pure virtual function, so I copied the contents of the original into my override and added my changes alongside.
+ When loading the game in debug mode, I got a bunch of redscreens about rejected duplicate templates. Couldn't figure it out for ages, thought it was weird caching of old compiled scripts or something.
+ Removed all of the copied code from my version of CreateTemplates() and loaded the game up in debug mode again. So the overide contained only my new code. I was expecting problems due to missing templates. But instead: No redscreens and all the template creation calls of the original function were still being called as if it weren't overriden at all.
+ This means that in practice, my override version of CreateTemplates() is getting called somewhere after the original CreateTemplates().
+ Now I could access the templates for modification like so:

class Z_X2Item_DefaultSchematics extends X2Item_DefaultSchematics;

static function array<X2DataTemplate> CreateTemplates()
{
	//Z// The engine seems to make these CreateTemplates() methods append their behaviour to the original instead of replacing it? Does it pre-call Super's method of the same name before this one?

	//Z// We're modifying the already-defined templates in-place so we just return an empty array here to satisfy this function's prototype
	local array<X2ItemTemplate> EmptySchematics;
	
	local X2ItemTemplateManager ItemTemplateManager;
	local array<X2ItemTemplate> Schematics;
	local X2SchematicTemplate item;
	local int i;

	ItemTemplateManager = class'X2ItemTemplateManager'.static.GetItemTemplateManager();
	Schematics = ItemTemplateManager.GetAllSchematicTemplates();

	for(i = 0; i < Schematics.Length; ++i)
	{
		// Template creation functions return X2DataTemplate objects. We need to cast back to X2ItemTemplates temporarily to access the properties we need.
		item = X2SchematicTemplate(Schematics[i]);

		if(item != none)
		{
			Z_Modify_Template(item);
		}
	}
	
	return EmptySchematics;
}

Z_Modify_Template() is just a function that updates some properties on the existing template.

I used the above code in this mod: http://www.nexusmods.com/xcom2/mods/128/?

So it seems like this is another way to safely-ish hook certain functions, but presumably still for just one mod. I can see myself just using a UIScreenListener with a doOnce for this kind of thing in future instead.

It's worth taking a look at X2DataSet.uc, where the caller of CreateTemplates() resides.

class X2DataSet extends Object 
	native(Core) 
	dependson(X2GameRuleset, XComGameStateVisualizationMgr);

var protectedwrite bool bShouldCreateDifficultyVariants;

/// <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()
{
	local array<X2DataTemplate> BaseTemplates, NewTemplates;
	local X2DataTemplate CurrentBaseTemplate;
	local int Index;

	BaseTemplates = CreateTemplates();

	for( Index = 0; Index < BaseTemplates.Length; ++Index )
	{
		CurrentBaseTemplate = BaseTemplates[Index];

		if( default.bShouldCreateDifficultyVariants )
		{
			CurrentBaseTemplate.bShouldCreateDifficultyVariants = true;
		}

		if( CurrentBaseTemplate.bShouldCreateDifficultyVariants )
		{
			CreateDifficultyVariantsForTemplate(CurrentBaseTemplate, NewTemplates);
		}
		else
		{
			NewTemplates.AddItem(CurrentBaseTemplate);
		}
	}

	return NewTemplates;
}

/// <summary>
/// Override this method in sub classes to create new templates by creating new X2<Type>Template
/// objects and filling them out.
/// </summary>
static function array<X2DataTemplate> CreateTemplates();

/// <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);
	}
}

@Amineri: I guess It would be relatively easy to set up a helper function to modify (rather than create) templates for multiple difficulty levels, going by the code above.

I'll need to go back and add handling for difficulty levels to my mod, that issue never occurred to me until you wrote about it.. :confused:

Edited by Kvalyr
Link to comment
Share on other sites

Hey what's the best way for me to learn this without any previous mod, or coding experience...I want to make a pcs or overwrite an existing pcs to make the ultimate personal combat Sim that would have all of the highest pcs stats from the other ones. Edited by jet100a
Link to comment
Share on other sites

  • Recently Browsing   0 members

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