Jump to content

New GTS abilities/reverse engineering XCOM:EU/EW abilities


Kregano

Recommended Posts

After talking to one of the Firaxis devs, Shadowman in its current incarnation doesn't work and probably will never work. eConceal_ stuff doesn't work on passive abilities, but it's entirely possible that creating variants of the fire weapons and overwatch abilities may get it to work.

 

The same dev mentioned how to get something like Tactical Sense/Aggression working:

 

It depends on which bonus you're trying to implement. Either way you'd make an infinite duration persistent effect on the unit with the ability, and you would implement the function GetToHitModifiers (which is defined in X2Effect_Persistent). To count the number of visible enemies, you probably want to call class'X2TacticalVisibilityHelpers'.static.GetNumVisibleEnemyTargetsToSource. Inside of GetToHitModifiers you'd return a bonus of something like TheBonusAmount * min(NumEnemies, 5). Make sense?

 

I'll be trying this out soon.

Link to comment
Share on other sites

Tried to make a Tactical Sense/Aggression derivative, but I'm getting a weird error:

static function X2AbilityTemplate ChallengeLover()
{
	local X2AbilityTemplate						Template;
	local X2AbilityTargetStyle                  TargetStyle;
	local X2AbilityTrigger						Trigger;
	local X2Effect_Persistent           PersistentEffect;
	local X2Effect_PersistentStatChange StatChangeEffect;
	local X2Effect_ToHitModifier                ToHitModifier;

	`CREATE_X2ABILITY_TEMPLATE(Template, 'ChallengeLover');
	Template.IconImage = "img:///UILibrary_PerkIcons.UIPerk_hithurts";

	Template.AbilitySourceName = 'eAbilitySource_Perk';
	Template.eAbilityIconBehaviorHUD = EAbilityIconBehavior_NeverShow;
	Template.Hostility = eHostility_Neutral;

//  this effect stays on the unit indefinitely
	PersistentEffect = new class'X2Effect_Persistent';
	PersistentEffect.EffectName = 'ChallengeLover';
	PersistentEffect.BuildPersistentEffect(1, true, true, false, eGameRule_PlayerTurnBegin);
	PersistentEffect.SetDisplayInfo(ePerkBuff_Passive, Template.LocFriendlyName, Template.GetMyHelpText(), Template.IconImage, true,,Template.AbilitySourceName);

	//  each turn this effect is applied
	StatChangeEffect = new class'X2Effect_PersistentStatChange';
	StatChangeEffect.EffectName = 'ChallengeLoverStatBoost';
	StatChangeEffect.BuildPersistentEffect(1, false, true, false, eGameRule_PlayerTurnEnd);
	StatChangeEffect.AddPersistentStatChange(eStat_Offense, CHALLENGE_AIM_BONUS);
	StatChangeEffect.AddPersistentStatChange(eStat_Defense, CHALLENGE_DEF_BONUS);

	Template.AbilityToHitCalc = default.DeadEye;

	TargetStyle = new class'X2AbilityTarget_Self';
	Template.AbilityTargetStyle = TargetStyle;

	Trigger = new class'X2AbilityTrigger_UnitPostBeginPlay';
	Template.AbilityTriggers.AddItem(Trigger);

//class'X2TacticalVisibilityHelpers'.static.GetNumVisibleEnemyTargetsToSource;
//	NumEnemies = UnitState.GetNumVisibleEnemyUnits(true,true);
	
	ToHitModifier = new class'X2Effect_ToHitModifier';
	ToHitModifier.BuildPersistentEffect(1, true, true, true);
	ToHitModifier.SetDisplayInfo(ePerkBuff_Passive, Template.LocFriendlyName, Template.GetMyLongDescription(), Template.IconImage,,,Template.AbilitySourceName);
	NumEnemies = UnitState.GetNumVisibleEnemyUnits(true,true);
	ToHitModifier.CHALLENGE_AIM_BONUS = 5 * min(NumEnemies, 5)
	ToHitModifier.CHALLENGE_DEF_BONUS = 5 * min(NumEnemies, 5)
	Template.AddTargetEffect(ToHitModifier);

	Template.BuildNewGameStateFn = TypicalAbility_BuildGameState;
	//  NOTE: No visualization on purpose!

	return Template;
}

StatChangeEffect.AddPersistentStatChange(eStat_Offense, CHALLENGE_AIM_BONUS); gives me weird "you can only use default values" errors, even though I defined the aim and defense bonus in a .ini file.

Link to comment
Share on other sites

Someone on Reddit pointed me to a simpler method:

class X2Effect_Aggression extends X2Effect_Persistent config(GameData_SoldierSkills);

var int CritModifier, MaxCritModifier;

function GetToHitModifiers(XComGameState_Effect EffectState, XComGameState_Unit Attacker, XComGameState_Unit Target, XComGameState_Ability AbilityState, class<X2AbilityToHitCalc> ToHitType, bool bMelee, bool bFlanking, bool bIndirectFire, out array<ShotModifierInfo> ShotModifiers)
{
    local ShotModifierInfo ModInfo;
    local float VisibleEnemies;

    VisibleEnemies = class'X2TacticalVisibilityHelpers'.static.GetNumVisibleEnemyTargetsToSource(Attacker.ObjectId,,class'X2TacticalVisibilityHelpers'.default.LivingGameplayVisibleFilter);

    ModInfo.ModType = eHit_Crit;
    ModInfo.Reason = FriendlyName;
    ModInfo.Value = min(CritModifier * VisibleEnemies, MaxCritModifier);
    ShotModifiers.AddItem(ModInfo);
}

The only disadvantage is that you'll need to rewrite a bunch of it to get it to change any stat besides crit.

Link to comment
Share on other sites

  • 1 month later...

Bumping this, since this might help anyone trying to make stealth skills derived from Shadowfall:

ModBuddy doesn't like

static function XComGame.XComGameState.EventListenerReturn ShadowmanListener(Object EventData, Object EventSource, XComGameState GameState, name EventID)

for whatever reason (the only change is turning Shadowfall into Shadowman). It'll give you this error:

E:\SteamLibrary\SteamApps\common\XCOM 2 SDK\Development\Src\Shadowman\Classes\X2Effect_Shadowman.uc(16) :
Error, Bad function definition

Here's some experimental code you guys can play with:

class X2Effect_Shadowman extends X2Effect_Persistent;

function RegisterForEvents(XComGameState_Effect EffectGameState)
{
    local X2EventManager EventMgr;
    local XComGameState_Unit UnitState;
    local Object EffectObj;

    EventMgr = class'X2EventManager'.static.GetEventManager();
    EffectObj = EffectGameState;
    UnitState = XComGameState_Unit(class'XComGameStateHistory'.static.GetGameStateHistory().GetGameStateForObjectID(EffectGameState.ApplyEffectParameters.SourceStateObjectRef.ObjectID));
    EventMgr.RegisterForEvent(EffectObj, 'KillMail', ShadowmanListener, 1,, UnitState);
    //return;    
}

static function XComGame.XComGameState.EventListenerReturn ShadowmanListener(Object EventData, Object EventSource, XComGameState GameState, name EventID)
{
    local XComGameStateContext_Ability AbilityContext;
    local XComGameState_Unit Killer;

    Killer = XComGameState_Unit(EventSource);
    AbilityContext = XComGameStateContext_Ability(GameState.GetContext());
    // End:0xF4
    if((((Killer != none) && AbilityContext != none) && AbilityContext.InputContext.AbilityTemplateName == 'OverwatchShot') && Killer.IsConcealed())
    {
        Killer.RetainConcealment();
    }
	if((((Killer != none) && AbilityContext != none) && AbilityContext.InputContext.AbilityTemplateName == 'PistolOverwatchShotHelper') && Killer.IsConcealed())
    {
        Killer.RetainConcealment();
    }
	if((((Killer != none) && AbilityContext != none) && AbilityContext.InputContext.AbilityTemplateName == 'PistolReturnFire') && Killer.IsConcealed())
    {
        Killer.RetainConcealment();
    }
	if((((Killer != none) && AbilityContext != none) && AbilityContext.InputContext.AbilityTemplateName == 'StandardShot') && Killer.IsConcealed())
    {
        Killer.RetainConcealment();
    }
	if((((Killer != none) && AbilityContext != none) && AbilityContext.InputContext.AbilityTemplateName == 'StandardShot_NoEnd') && Killer.IsConcealed())
    {
        Killer.RetainConcealment();
    }
	if((((Killer != none) && AbilityContext != none) && AbilityContext.InputContext.AbilityTemplateName == 'PistolStandardShot') && Killer.IsConcealed())
    {
        Killer.RetainConcealment();
    }
	if((((Killer != none) && AbilityContext != none) && AbilityContext.InputContext.AbilityTemplateName == 'SniperStandardFire') && Killer.IsConcealed())
    {
        Killer.RetainConcealment();
    }
	if((((Killer != none) && AbilityContext != none) && AbilityContext.InputContext.AbilityTemplateName == 'SniperRifleOverwatch') && Killer.IsConcealed())
    {
        Killer.RetainConcealment();
    }
    return 0;
    //return ReturnValue;    
}

No idea if it works, due to ModBuddy hating that line.

Link to comment
Share on other sites

You defined the function as

static function XComGame.XComGameState.EventListenerReturn ShadowmanListener(Object EventData, Object EventSource, XComGameState GameState, name EventID)

That's not how you do it, you just specify a type and that's it. Example:

static function EventListenerReturn ShadowmanListener(Object EventData, Object EventSource, XComGameState GameState, name EventID)

Link to comment
Share on other sites

  • Recently Browsing   0 members

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