Jump to content

Mod help: conditional Blademaster?


SteelRook

Recommended Posts

  • Replies 84
  • Created
  • Last Reply

Top Posters In This Topic

Shouldn't you be passing NewTemplate in here?

 

D'oh! You're absolutely right! I changed this in so many different places, but I put the wrong name in that one damn spot where it actually really counts! Thank you kindly for your sharp eye :smile:

 

I feel like creating a whole new template class (X2SwordTemplate) is adding unnecessary complexity here. What does that offer you over simply modifying values in-place on the old template?

 

Existing templates can be modified by simply grabbing them from memory and editing them in-place. You don't even need to add them back into the template pool via the manager.

I would do something like this instead:

OldTemplate = X2WeaponTemplate(ItemTemplateManager.FindItemTemplate('Sword_BM'));
OldTemplate.BaseDamage = 9999; // Or whatever changes you want to make

Not quite. My main goal is to boost the sword's damage, but only on rangers who have Blademaster. I can't simply increase the stats for the template as that'll affect all Rangers. I could just hard-code the stats in the special damage effect, separately for each sword type by tech (a Switch statement, likely, per chance UnrealScript can do a Switch on a String), but that'll mean that changing the values will require editing the source code. I want to pull the data out of the ini files themselves so that mod users can tweak those to alter the values if they don't like them for much easier access. I've built my special sword template based on the Gremlin template, as that works in much the same way. The Gremlin saves some of its tech-level-dependent stats inside its own template, and then Gremlin-specific skills are keyed to pull those stats and add them to the calculations. I want the boosts built into the swords themselves and pulled from the ini files, is all.

 

Although I suppose I could hook the special damage/AP effect into the ini files, instead. I can attach a subclass to a different config file than its parent class, correct?

 

In the same vein, it would really help if I could pull some code out of the initial mod load static function, and I'm not sure how UnrealScript handles this. Can a static function call a non-static function in the same class? Or do all of them have to be static? Can they call each other directly by name, or do they have to call each other through their wrapper class name? I ask, because I'm used to Java and that's VERY picky about these sorts of things. Calling a non-static method in a static context is a finger-wagging no-no, so I'm not sure how it works here.

 

In either case, thank you SO MUCH for your help. This really does give me a pretty good view of both UnrealEd and the way XCOM is hooked up. It's 4 AM right now so I can't try any code edits, but I'll get back to it tomorrow. Thanks :)

Link to comment
Share on other sites

OK, so - partial success. The search-and-replace method works beautifully! I managed to change the sword class to carry the extra data, I managed to change the ability class to actually use the extra data, everything works fine... Once. Since I'm putting all of this code in the OnLoadedSavedGame() function in X2DownloadableContentInfo, that only fires once for the fist time you load a saved game which was previously made without that specific DLC. Making a save game with the DLC, restarting the game and reloading it overrides my changes. That means event listeners, which is a bit of a problem.

 

I've read about the UIScreenListener, but I don't feel comfortable firing redundant events so often. The performance impact may not be significant since that's quick code and it only fires comparatively rarely, but I just don't like that kind of implementation. It feels like a very brute-force solution. The X2EventManager solution seems much cleaner to me as I can hopefully trigger it only on the one event which screws up the files, which is the loading of a saved game. The trouble is that works off of event names, and I don't know if loading a saved game fires an event trigger that I can listen for. Does it? If so, what is it called? If not, can I somehow add one? Or does that go back to overriding static functions and "just don't?" Surely loading a saved game would be an important enough event in XCOM 2 that classes would need to listen to, no?

 

Failing that, is there some way I can listen to the game booting up? That would be even better than listening to loading a saved game since that's when the problem happens. Or can I maybe "unsign" the mod from the save game so that the OnLoadedSavedGame() function would trigger on every load? I mean it's very hard to believe there's no way to fire an event every time a game loads...

 

*edit*

But your advise for replacing the Templates in the TemplateManagers worked beautifully! I'm not overriding anything any more, which should do wonders for mod compatibility with anything aside from mods which alter the weapon or the skill.

 

*edit*

I found a lot of weird stuff when looking for how saving and loading a game is handled. The comments range from bizarre to hilarious. There's a Checkpoint class which according to the comments was "Initially brought over from Gears 2 by Dominic Cerquetti." OK, I wasn't expecting that. Then there's my favourite, the SeqAct_SaveLoadData class. I'll just let the comments speak for themselves:

//---------------------------------------------------------------------------------------
//  FILE:    SeqAct_SaveLoadData.uc
//  AUTHOR:  Ryan McFall  --  02/06/2012
//  PURPOSE: This object's purpose is to facilitate saving and loading data to kismet variables
//           At present, all that needs to be done is to add one of these objects to the
//           kismet sequence and all your wildest dreams will come true. 
//
//---------------------------------------------------------------------------------------
//  Copyright (c) 2016 Firaxis Games, Inc. All rights reserved.
//---------------------------------------------------------------------------------------

Jokes aside, I'm completely lost in this case, which is unfortunate...

Edited by SteelRook
Link to comment
Share on other sites

The behavior I mentioned for the playable mec mod is a bug for that mod, but may be what you want for your mod. It puts a new mec into your armory every time you load, when it is supposed to put it only one time.

 

http://forums.nexusmods.com/index.php?/topic/3798185-added-a-new-gamestate-object-to-all-soldiers/page-2&do=findComment&comment=34602170

Link to comment
Share on other sites

The behavior I mentioned for the playable mec mod is a bug for that mod, but may be what you want for your mod. It puts a new mec into your armory every time you load, when it is supposed to put it only one time.

 

http://forums.nexusmods.com/index.php?/topic/3798185-added-a-new-gamestate-object-to-all-soldiers/page-2&do=findComment&comment=34602170

 

Hmm... Well, that's definitely very odd behaviour because you haven't done anything I haven't, not really. However, when doing more rigorous testing just now, I ran into an additional odd behaviour, very likely to do with how I copy stats from template to template. Loading a save file made with the mod does NOT trigger OnLoadedSavedGame() no matter what I do. Loading a save file made without the mod does trigger OnLoadedSavedGame(). The first time it triggers everything works correctly. The second time it triggers and onwards, it actually destroys the weapon model I've set up, including weapon stats and even animations. That's pretty bad and something I need to fix, but it's a different kind of problem. I suspect the issue is I'm replacing an X2WeaponTemplate with an X2SwordTemplate, which fails on a subsequent reload because the X2WeaponTemplate isn't a X2WeaponTemplate any more. That's on me to fix and not that important.

 

What is important is I don't see a good way to trigger an event at loading a game, meaning I'm probably going to have to use some of the UI listeners. I'm not entirely sure how you end up with multiple MECs in the Inventory, because OnLoadedSavedGame() only fires once per save file. I would dearly love to know what about your code makes this persistent.

Link to comment
Share on other sites

Just to clarify, this isn't my code. But the related discussion around the link I gave implies that OnLoadedSavedGame may not actually work the way it is documented.

 

Right, and that's what I was hoping for, as well - that it would trigger on every saved game load. The problem is my code behaves exactly as described in the comments - OnLoadedSavedGame() triggers once on a "fresh" save but never on modded saves. If I restart the game and load a modded save first thing, that save doesn't have the modded weapons. If I load a non-modded save then ALL saves have the weapons, including the modded ones. If I load a non-modded save again then everything screws up because my weapon replacement code sucks, but that's besides the point. I'm not sure how the mod in the linked thread manages to do that because its OnLoadedSavedGame() function doesn't appear to be meaningfully different from mine, at least not that I can determine. For the record, here's what's in mine, and hold your nose because mine is remarkably shoddy code:

static event OnLoadedSavedGame()
{
	local X2ItemTemplateManager ItemTemplateManager;
	local X2SwordTemplate NewTemplate;
	local X2WeaponTemplate OldTemplate;
	
	local X2AbilityTemplateManager AbilityTemplateManager;
	local X2AbilityTemplate NewAbilityTemplate;
	local X2AbilityTemplate OldAbilityTemplate;
	local X2Effect_BonusEffect_Blademaster DamageEffect;
	
	ItemTemplateManager = class'X2ItemTemplateManager'.static.GetItemTemplateManager();
	
	OldTemplate = X2WeaponTemplate(ItemTemplateManager.FindItemTemplate('Sword_BM'));
	`CREATE_X2TEMPLATE(class'X2SwordTemplate', NewTemplate, 'Sword_BM');

	
	NewTemplate.WeaponPanelImage = OldTemplate.WeaponPanelImage;                       // used by the UI. Probably determines iconview of the weapon.

	NewTemplate.ItemCat = OldTemplate.ItemCat;
	NewTemplate.WeaponCat = OldTemplate.WeaponCat;
	NewTemplate.WeaponTech = OldTemplate.WeaponTech;
	NewTemplate.strImage = OldTemplate.strImage;
	NewTemplate.EquipSound = OldTemplate.EquipSound;
	NewTemplate.InventorySlot = OldTemplate.InventorySlot;
	NewTemplate.StowedLocation = OldTemplate.StowedLocation;
	// This all the resources; sounds, animations, models, physics, the works.
	NewTemplate.GameArchetype = OldTemplate.GameArchetype;
	//NewTemplate.AddDefaultAttachment('R_Back', "BeamSword.Meshes.SM_BeamSword_Sheath", false);
	NewTemplate.DefaultAttachments = OldTemplate.DefaultAttachments;
	NewTemplate.Tier = OldTemplate.Tier;

	NewTemplate.iRadius = OldTemplate.iRadius;
	NewTemplate.NumUpgradeSlots = OldTemplate.NumUpgradeSlots;
	NewTemplate.InfiniteAmmo = OldTemplate.InfiniteAmmo;
	NewTemplate.iPhysicsImpulse = OldTemplate.iPhysicsImpulse;

	NewTemplate.iRange = OldTemplate.iRange;
	NewTemplate.BaseDamage = OldTemplate.BaseDamage;
	//NewTemplate.BaseDamage.damage = 100;
	NewTemplate.Aim = OldTemplate.Aim;
	NewTemplate.CritChance = OldTemplate.CritChance;
	NewTemplate.iSoundRange = OldTemplate.iSoundRange;
	NewTemplate.iEnvironmentDamage = OldTemplate.iEnvironmentDamage;
	NewTemplate.BaseDamage.DamageType = OldTemplate.BaseDamage.DamageType;

	NewTemplate.BlademasterDamageBonus = 2;
	NewTemplate.BlademasterAPBonus = 2;

	//NewTemplate.BonusWeaponEffects.AddItem(class'X2StatusEffects'.static.CreateBurningStatusEffect(2, 0));
	NewTemplate.BonusWeaponEffects = OldTemplate.BonusWeaponEffects;
	
	NewTemplate.CanBeBuilt = OldTemplate.CanBeBuilt;
	NewTemplate.bInfiniteItem = OldTemplate.bInfiniteItem;

	NewTemplate.DamageTypeTemplateName = 'Melee';
	
	ItemTemplateManager.AddItemTemplate(NewTemplate, true);

	//

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

	OldAbilityTemplate = AbilityTemplateManager.FindAbilityTemplate('Blademaster');
	`CREATE_X2ABILITY_TEMPLATE(NewAbilityTemplate, 'Blademaster');
	
	NewAbilityTemplate.IconImage = OldAbilityTemplate.IconImage;

	NewAbilityTemplate.AbilitySourceName = OldAbilityTemplate.AbilitySourceName;
	NewAbilityTemplate.eAbilityIconBehaviorHUD = OldAbilityTemplate.eAbilityIconBehaviorHUD;
	NewAbilityTemplate.Hostility = OldAbilityTemplate.Hostility;

	NewAbilityTemplate.AbilityToHitCalc = OldAbilityTemplate.AbilityToHitCalc;
	NewAbilityTemplate.AbilityTargetStyle = OldAbilityTemplate.AbilityTargetStyle;
	NewAbilityTemplate.AbilityTriggers = OldAbilityTemplate.AbilityTriggers;

	DamageEffect = new class'X2Effect_BonusEffect_Blademaster';
	DamageEffect.BonusDmg = 2;
	DamageEffect.BuildPersistentEffect(1, true, false, false);
	DamageEffect.SetDisplayInfo(ePerkBuff_Passive, NewAbilityTemplate.LocFriendlyName, NewAbilityTemplate.GetMyLongDescription(), NewAbilityTemplate.IconImage, true,,NewAbilityTemplate.AbilitySourceName);
	
	NewAbilityTemplate.AddTargetEffect(DamageEffect);

	AbilityTemplateManager.AddAbilityTemplate(NewAbilityTemplate, true);
}
Link to comment
Share on other sites

Mostly good news: I got the mod to work using Kvalyr's suggestions. Well, I got a proof-of-concept version of the mod to work, in that I know I can affect the changes I want consistently. This is pretty good, actually. A late-game sword which deals 9-11 damage and ignores 2 armour is surprisingly good. Possibly even TOO good, but that's a matter for another time. I still need to make changes to all versions of the sword since it currently only applies to the Sword_BM, and I probably need to apply this to all difficulty variants. Still not sure how that works, exactly, but at least I'm not pulling my hair out trying to do ANYTHING now.

 

Honestly, a lot of the nonsense I went through just trying to change anything whatsoever is probably worth putting in a guide here, because I suspect a lot of people will be facing similar issues. Modding XCOM 2 has a lot of gotchas which I suspect will throw even seasoned programmers for a loop, especially those with limited or no experience with UnrealScript. And I ain't even close to done yet. Who knows what else will crop up :)

Link to comment
Share on other sites

Great progress. I hope to keep up, but maybe I will be reading your guide.

 

Oh, I don't know if I could write one, myself :) I'm still pretty much a novice at this, and I'm not even sure if my methods actually work yet. Could be even further changes in store. I'm just happy that the thing works for the time being :)

Link to comment
Share on other sites

  • Recently Browsing   0 members

    • No registered users viewing this page.

×
×
  • Create New...