Jump to content

Mod help: conditional Blademaster?


SteelRook

Recommended Posts

Sorry if this comes across as bumping my own thread, but I got something of an idea. Let's just say that there's a way to mess with the weapon/skill lists every time the game loads. Assuming that I found the proper event listener, I still wouldn't know how to find those lists, how to search for specific templates in them and how to swap them out. For the sake of argument, let's just assume that I'm going to put my changes in the OnLoadedSavedGame() function from the X2DownloadableContentInfo class. This gets run on first loading of the game. It's probably not going to be enough, but presuming that it is:

 

1. How can I find a list of all weapon templates?

2. How can I find a list of all skill templates?

3. How can I search through both of those lists to find the ranger swords and the Blademaster ability?

 

If I can achieve all three above, then I should be fine at least on initial save file loading. If that fails to persist after a game shutdown on a save file made with the new mod, THEN I'm going to go back to looking for event listeners.

Link to comment
Share on other sites

  • Replies 84
  • Created
  • Last Reply

Top Posters In This Topic

well what i do with my medikit change for red fog is just setting a listener and updating each time it's initialized, it's not very efficient but it's super effective,

X2Item_DefaultWeapons.uc has all default weapon templates.

X2Ability_DefaultAbilitySet.uc has all default ability templates.

 

you can search and replace with the:

AbilityTemplateManager.AddAbilityTemplate(AbilityTemplate template,bool OverrideCurrent)

but i have yet to find the X2WeaponTemplate overrider but there is a getall function in the X2ItemTemplateManager

Link to comment
Share on other sites

By the way, I found out why my override wasn't working! Because... It was. Kind of. When I return the functions to how they were originally with just minor stat changes, everything works! My sword deals 100 damage! But as soon as I attempt to change the class of the weapon being constructed, everything fails and I don't know why. Basically, I'm trying to change this function:

static function X2DataTemplate CreateTemplate_Sword_Beam()
{
	local X2WeaponTemplate Template;

	`CREATE_X2TEMPLATE(class'X2WeaponTemplate', Template, 'Sword_BM');
	Template.WeaponPanelImage = "_Pistol";                       // used by the UI. Probably determines iconview of the weapon.

	Template.ItemCat = 'weapon';
	Template.WeaponCat = 'sword';
	Template.WeaponTech = 'beam';
	Template.strImage = "img:///UILibrary_Common.BeamSecondaryWeapons.BeamSword";
	Template.EquipSound = "Sword_Equip_Beam";
	Template.InventorySlot = eInvSlot_SecondaryWeapon;
	Template.StowedLocation = eSlot_RightBack;
	// This all the resources; sounds, animations, models, physics, the works.
	Template.GameArchetype = "WP_Sword_BM.WP_Sword_BM";
	Template.AddDefaultAttachment('R_Back', "BeamSword.Meshes.SM_BeamSword_Sheath", false);
	Template.Tier = 4;

	Template.iRadius = 1;
	Template.NumUpgradeSlots = 2;
	Template.InfiniteAmmo = true;
	Template.iPhysicsImpulse = 5;

	Template.iRange = 0;
	Template.BaseDamage = default.RANGERSWORD_BEAM_BASEDAMAGE;
	Template.Aim = default.RANGERSWORD_BEAM_AIM;
	Template.CritChance = default.RANGERSWORD_BEAM_CRITCHANCE;
	Template.iSoundRange = default.RANGERSWORD_BEAM_ISOUNDRANGE;
	Template.iEnvironmentDamage = default.RANGERSWORD_BEAM_IENVIRONMENTDAMAGE;
	Template.BaseDamage.DamageType='Melee';

	Template.BonusWeaponEffects.AddItem(class'X2StatusEffects'.static.CreateBurningStatusEffect(2, 0));
	
	Template.CanBeBuilt = false;
	Template.bInfiniteItem = true;

	Template.DamageTypeTemplateName = 'Melee';
	
	return Template;
}

but change the following two lines:

local X2WeaponTemplate Template;
`CREATE_X2TEMPLATE(class'X2WeaponTemplate', Template, 'Sword_BM');

to

local X2SwordTemplate Template;
`CREATE_X2TEMPLATE(class'X2SwordTemplate', Template, 'Sword_BM');

The original works, the altered version doesn't. Why? I don't get this. I've defined X2SwordTemplate as a class extending X2WeaponTemplate, so this should work, right? Except it doesn't. Not only does it not work, but weapon is initialised with default values. WHYYY?!? What is it about changing one class to a subclass that breaks the whole damn thing?

Link to comment
Share on other sites

well what i do with my medikit change for red fog is just setting a listener and updating each time it's initialized, it's not very efficient but it's super effective,

 

Huh... OK, that's one way of doing it. Can I by any chance see the code you're using? I'm really, really not sure how to use event listeners in UnrealScript so a practical example would help tremendously.

Link to comment
Share on other sites

1:

local X2ItemTemplateManager ItemTemplateManager;
local array<X2WeaponTemplate> Templates;
ItemTemplateManager = class'X2ItemTemplateManager'.static.GetItemTemplateManager();
Templates = ItemTemplateManager.GetAllWeaponTemplates();

2:

local X2AbilityTemplateManager AbilityTemplateManager;
local array<X2AbilityTemplate> Templates;	// The array of ability templates that we'll fill up to work with later
local X2DataTemplate Template;				// To temporarily hold each template returned from the iterator
local X2AbilityTemplate AbilityTemplate;	// A successfully-retrieved ability template

AbilityTemplateManager = class'X2AbilityTemplateManager'.static.GetAbilityTemplateManager();

// Loop through all templates in the ability template manager
foreach AbilityTemplateManager.IterateTemplates(Template, none)
{	
	// Attempt to cast from an X2DataTemplate to an X2AbilityTemplate. If the cast fails (because the DataTemplate wasn't an AbilityTemplate), none is returned
	AbilityTemplate = X2WeaponTemplate(Template); 

	// Thus, check for none. If not none, we grabbed an AbilityTemplate
	if(AbilityTemplate != none)
	{
		Templates.AddItem(AbilityTemplate);	// Add the ability template to our array of templates
	}
}

//Elsewhere..
local int i;

for(i = 0; i < Templates.Length; ++i)
{
	//Do stuff with Templates[i];
}

3 A:

local int i;
local X2WeaponTemplate WeaponTemplate;

// Assuming we got the array of templates from elsewhere
for(i = 0; i < Templates.Length; ++i)
{
	WeaponTemplate = Templates[i];
	if(WeaponTemplate.DataName == 'Sword_CV' // 'Sword_MG' and 'Sword_BM' are the tier 2/3 variants (magnetic (arc) / beam (fusion) )
	{
		// Do stuff with this template
	}
}

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

3 B:

local int i;
local X2AbilityTemplate AbilityTemplate;

// Assuming we got the array of templates from elsewhere
for(i = 0; i < Templates.Length; ++i)
{
	AbilityTemplate = Templates[i];
	if(AbilityTemplate.DataName == 'Blademaster'
	{
		// Do stuff with this template
	}
}

The examples above are for very generic use cases where you want to actually iterate all available templates of a given type, but you can usually just grab templates by their name if you know exactly which ones you want to modify and you know their DataName in advance:

local X2ItemTemplateManager ItemTemplateManager;
local X2WeaponTemplate Template;
ItemTemplateManager = class'X2ItemTemplateManager'.static.GetItemTemplateManager();
Template = X2WeaponTemplate(ItemTemplateManager.FindItemTemplate('Sword_CV')); // Cast from ItemTemplate to WeaponTemplate

Note: I haven't compiled/tested any of these examples so don't count on them being copy-and-paste-useable.

You can take a look at my Finite Armory or Invisible Psi Amps mods to see how I work with templates, but I'm using some slightly complex helper code for my own convenience that might make my mods hard to decipher if you're not familiar with delegates etc.
Amineri's work is always worth looking at to learn how to do things. Check out the LW SMG pack in particular for your needs.

Edit: D'oh - There were replies while I was typing that stuff out. :smile:

Edited by Kvalyr
Link to comment
Share on other sites

but change the following two lines:

local X2WeaponTemplate Template;
`CREATE_X2TEMPLATE(class'X2WeaponTemplate', Template, 'Sword_BM');

to

local X2SwordTemplate Template;
`CREATE_X2TEMPLATE(class'X2SwordTemplate', Template, 'Sword_BM');

The original works, the altered version doesn't. Why? I don't get this. I've defined X2SwordTemplate as a class extending X2WeaponTemplate, so this should work, right? Except it doesn't. Not only does it not work, but weapon is initialised with default values. WHYYY?!? What is it about changing one class to a subclass that breaks the whole damn thing?

i think that because of the template only accepts weapon templates and it's child objects.

class X2Effect_ApplyMedikitHeal_RedFog extends X2Effect_ApplyMedikitHeal;

simulated protected function OnEffectAdded(const out EffectAppliedData ApplyEffectParameters, XComGameState_BaseObject kNewTargetState, XComGameState NewGameState, XComGameState_Effect NewEffectState)
{
		local XComGameState_Unit TargetUnit,SourceUnit;
		local int SourceObjectID ;
		Super.OnEffectAdded( ApplyEffectParameters,	kNewTargetState	,NewGameState,  NewEffectState);
		SourceObjectID = ApplyEffectParameters.SourceStateObjectRef.ObjectID;
		SourceUnit = XComGameState_Unit(NewGameState.CreateStateObject(class'XComGameState_Unit', SourceObjectID));		
		TargetUnit=	XComGameState_Unit(kNewTargetState);
		`log("Medikit ACTIVATED!");
		`XEVENTMGR.TriggerEvent('HealedSoldier',TargetUnit ,SourceUnit,NewGameState);
	
}

and then i listen with

`XEVENTMGR.RegisterForEvent(ThisObj, 'HealedSoldier', GrabStats);

and i change the templates here

local X2AbilityTemplateManager AbilityTemplateManager;
ThisObj=self;
AbilityTemplateManager = class'X2AbilityTemplateManager'.static.GetAbilityTemplateManager();
AbilityTemplateManager.AddAbilityTemplate(Class'X2Ability_RedFogMedikit'.static.AddMedikitHeal( 'MedikitHeal', class'X2Ability_DefaultAbilitySet'.default.MEDIKIT_PERUSEHP),true);
AbilityTemplateManager.AddAbilityTemplate(Class'X2Ability_RedFogMedikit'.static.AddMedikitHeal( 'NanoMedikitHeal', class'X2Ability_DefaultAbilitySet'.default.NANOMEDIKIT_PERUSEHP),true);

Link to comment
Share on other sites

OK, lots of replies! I like that! :smile: I'll try and address them one at a time, so bear with me:

i think that because of the template only accepts weapon templates and it's child objects.


Thing is, I'm already using a child of the weapon template: class X2SwordTemplate extends X2WeaponTemplate; Not sure what else I can do about that. The editor compiles just fine, but for some reason the game uses its own default values. How the hell does it even do that? Does the override fail somehow?

*lots of code*


OK, that's pretty interesting. After staring at it for a bit, I think I see what you're doing. You've created an event listener which listens to a 'HealedSoldier' event, which you're firing manually inside the "OnEffectAdded()" function. OK, that gives me a starting point to figure out how event listeners work (though the X2EventManager class has a whole lot of virtual functions...), and it seems like this is backwards from what I'm used to. In Java, you register listeners with objects, and those objects notify their subscribed listeners directly. Here, it seems like I need to register a listener for an event itself.

This still brings up the question, though - what happens when the listener fires? I'm presuming it runs the code in the last block, but where is that code located? Inside a method? Inside a class? How does the listener know to run that particular bit of code? This is the link I'm missing. 'HealedSoldier' and... Then what? How do I set which code runs?

 

Oh, and it brings up one other question - how do I listen to a game loading event? I can't listen to the ability itself because the Blademaster ability is passive. I'd need to fix it just once when the game loads to ensure that the change happens at least once after the game has booted up initially but before the player has a chance to attack with the ability. Presumably I'd need to register an object with a listener, but what would that listener listen for?

*also lots of code*

Aha, OK. I think I follow. Get access to the template managers, and I can pull a list of all templates from there. That does bring up the question of how I can get access to the template managers, though. I may just be blind, but I can't see that bit in the code, which is probably the hardest part for me. I don't think I'm supposed to pull those out of history since that holds actual events, as opposed to items. What's the equivalent of `HISTORY for data managers? It already seems like the X2DataTemplateManager class can replace old entries with new ones if they carry the same name so that shouldn't be an issue. Now if only I can actually find the managers.

 

Although don't worry - I never copy-paste code. If I don't know what it does line-by-line, I can't use it since it confuses me. I'll write my own, though very likely base it on your examples very heavily.

 

*edit*

And before I forget - thank you so much for your help! :)

Edited by SteelRook
Link to comment
Share on other sites

 

My bad, I left out a crucial line:

 

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

 

Critical indeed! :) OK, that sets me up to at least get started. I presume the same goes for the X2AbilityTemplateManager? Yeah, looks like that's how that goes. Cool!

 

I also followed your link from the "did your mods stop working" thread where I found some more info on event manager events. Seems like the way that goes is whenever a class is registered to listen for an event, the method specified from that class is called whenever that event triggers. Do we know if loading a game spawns an event of any kind?

 

One final question - how does the `log macro work? I mean, I know HOW it works, but I can never find the actual logs it supposedly creates. I'd love to use it to test variable values at various points in the code, but I haven't been able to get it to work.

Link to comment
Share on other sites

OK, lots of replies! I like that! :smile: I'll try and address them one at a time, so bear with me:

 

i think that because of the template only accepts weapon templates and it's child objects.

Thing is, I'm already using a child of the weapon template: class X2SwordTemplate extends X2WeaponTemplate; Not sure what else I can do about that. The editor compiles just fine, but for some reason the game uses its own default values. How the hell does it even do that? Does the override fail somehow?

 

 

idk, it should work but again i have given up on overriding stuff and just currently try to work around problems.

 

 

*lots of code*

OK, that's pretty interesting. After staring at it for a bit, I think I see what you're doing. You've created an event listener which listens to a 'HealedSoldier' event, which you're firing manually inside the "OnEffectAdded()" function. OK, that gives me a starting point to figure out how event listeners work (though the X2EventManager class has a whole lot of virtual functions...), and it seems like this is backwards from what I'm used to. In Java, you register listeners with objects, and those objects notify their subscribed listeners directly. Here, it seems like I need to register a listener for an event itself.

 

This still brings up the question, though - what happens when the listener fires? I'm presuming it runs the code in the last block, but where is that code located? Inside a method? Inside a class? How does the listener know to run that particular bit of code? This is the link I'm missing. 'HealedSoldier' and... Then what? How do I set which code runs?

 

Oh, and it brings up one other question - how do I listen to a game loading event? I can't listen to the ability itself because the Blademaster ability is passive. I'd need to fix it just once when the game loads to ensure that the change happens at least once after the game has booted up initially but before the player has a chance to attack with the ability. Presumably I'd need to register an object with a listener, but what would that listener listen for?

Oh yeah i forgot that...

function EventListenerReturn GrabStats(Object EventData, Object EventSource, XComGameState GameState, Name EventID)
{
      A BUNCH OF REALLY WEIRD AND MESSY CODE FOR GRABBING UNIT STATS BEFORE THE GAME APPLIES DEBUFFS

 Return ELR_NoInterrupt;
}

You dont need to listen to the ability you can override the template from wherever you want, the listener and triggers are there to notify you of when stuff happens, there is a bit of code that handles the loading, and try and look for somewhere you can put an event trigger in there, you could even possibly trigger once on each tactical mission start which would make for much less spam and there is already an eventTrigger for that one, i used it for some time for red fog but it was too wasteful for me as i needed just to take hit events and nothing else, talking about that i could call the medikit template replacement code from something similar to that to reduce spam but that'll come when i have a reason to reorganize my code to be readable to other human beings

Edited by Guest
Link to comment
Share on other sites

  • Recently Browsing   0 members

    • No registered users viewing this page.

×
×
  • Create New...