DataTables is my suggestion.
You create a Struct which contains all relevant variables associated with an ability (I imagine there are dozens; MP consumption, damage, range, fire rate, healing factor, player launch vector, bMakeInvincible, whatever the list of things is an ability CAN do).
A DataTable is like a permanent array of Struct values, which you populate with the abilities. You give each row a name corresponding to the in-engine backend name for the ability, and maybe you also store values for Display Name, Display Icon texture, whatever.
When the player uses an ability, you call the Name of the ability (you can encapsulate all of this in a reusable macro if you want, even). You can then use a GetDataTableRow pin to call all the variables associated with it… And then I would hit a SwitchOnName pin to fork the Use Ability command into a “generic” ability processor (i.e. Projectile Attack, Melee Attack, Movement Ability, Healing Ability, whatever) and feed that processing path all of the values pulled from the DataTable.
So, as an example, if you have an ability that spawns 5 icicles and launches them, you would call IcicleBarrage, get the value from the DataTable for that name, and then break the Struct. The “Type” column value = projectile, so we SwitchOnName to the Projectile logic. “NumProj” is 5, “SpawnDelay” is 0.25, “LaunchSpeed” is 4500,0,0, “ProjectileMesh” is “GEOM_Icicle_Missile”, “MPUse” is 65, “Cooldown” is 5, and “Damage” is 200. So we feed these values to our spawning logic that calls up 5 icicle meshes 0.25 seconds apart, launch them forward at 4000 speed, deplete 65MP, then hit a 5s delay node that flags us as unable to use another ability again until it’s up.
That’s just an example implementation, you can get far more complex… But this makes it easy for ANY actor in the level to get all data related to an ability with just a name value, and allows you to manually tweak one master file that retunes the ability globally.