More abilities
All checks were successful
Build / Build (push) Successful in 48s

This commit is contained in:
Deukhoofd 2025-06-13 15:39:08 +02:00
parent 4385f0afaa
commit 24712fbb0d
Signed by: Deukhoofd
GPG Key ID: F63E044490819F6F
16 changed files with 238 additions and 16 deletions

View File

@ -76,7 +76,8 @@ public static class MoveTurnExecutor
return;
byte ppUsed = 1;
// TODO: Modify the PP used by the move.
executingMove.RunScriptHook(x => x.ModifyPPUsed(executingMove, ref ppUsed));
targets.WhereNotNull().RunScriptHook(x => x.ModifyPPUsedForIncomingMove(executingMove, ref ppUsed));
if (!executingMove.ChosenMove.TryUse(ppUsed))
return;

View File

@ -311,7 +311,6 @@ public class BattleImpl : ScriptSource, IBattle
if (choice is IMoveChoice moveChoice)
{
// TODO: Hook to change number of PP needed.
if (moveChoice.ChosenMove.CurrentPp < 1)
return false;
if (!TargetResolver.IsValidTarget(moveChoice.TargetSide, moveChoice.TargetPosition,

View File

@ -1072,6 +1072,11 @@ public class PokemonImpl : ScriptSource, IPokemon
// Allow scripts to trigger based on the faint.
this.RunScriptHook(script => script.OnFaint(this, source));
foreach (var ally in BattleData.BattleSide.Pokemon.WhereNotNull().Where(x => x != this))
{
ally.RunScriptHook(script => script.OnAllyFaint(ally, this));
}
// Make sure the OnRemove script is run.
this.RunScriptHook(script => script.OnRemove());

View File

@ -562,6 +562,13 @@ public abstract class Script : IDeepCloneable
{
}
/// <summary>
/// This function is triggered on a Pokemon when an ally Pokemon faints.
/// </summary>
public virtual void OnAllyFaint(IPokemon ally, IPokemon faintedPokemon)
{
}
/// <summary>
/// This function is triggered on a Pokemon and its parents when the given Pokemon switches out
/// of the battlefield.
@ -801,4 +808,18 @@ public abstract class Script : IDeepCloneable
public virtual void OnAfterHeldItemChange(IPokemon pokemon, IItem? previous, IItem? item)
{
}
/// <summary>
/// This function allows a script to modify the PP used by a move.
/// </summary>
public virtual void ModifyPPUsed(IExecutingMove executingMove, ref byte ppUsed)
{
}
/// <summary>
/// This function allows a script to modify the PP used by an incoming move. This is used for abilities such as Pressure.
/// </summary>
public virtual void ModifyPPUsedForIncomingMove(IExecutingMove executingMove, ref byte ppUsed)
{
}
}

View File

@ -424,23 +424,30 @@
"pixilate": {
"effect": "pixilate"
},
"plus": {},
"poison_heal": {},
"poison_point": {},
"poison_touch": {},
"plus": {
"effect": "plus"
},
"poison_heal": {
"effect": "poison_heal"
},
"poison_point": {
"effect": "poison_point"
},
"poison_touch": {
"effect": "poison_touch"
},
"power_construct": {
"canBeChanged": false,
"flags": [
"cant_be_copied"
]
"effect": "power_construct"
},
"power_of_alchemy": {
"flags": [
"cant_be_copied"
]
"effect": "power_of_alchemy"
},
"prankster": {
"effect": "prankster"
},
"pressure": {
"effect": "pressure"
},
"prankster": {},
"pressure": {},
"primordial_sea": {},
"prism_armor": {},
"protean": {},

View File

@ -145666,6 +145666,7 @@
}
},
"complete": {
"isBattleOnly": true,
"abilities": [
"power_construct"
],

View File

@ -0,0 +1,23 @@
namespace PkmnLib.Plugin.Gen7.Scripts.Abilities;
/// <summary>
/// Plus is an ability that boosts Special Attack if another ally has Plus or Minus.
///
/// <see href="https://bulbapedia.bulbagarden.net/wiki/Plus_(Ability)">Bulbapedia - Plus</see>
/// </summary>
[Script(ScriptCategory.Ability, "plus")]
public class Plus : Script
{
/// <inheritdoc />
public override void ChangeOffensiveStatValue(IExecutingMove move, IPokemon target, byte hit, uint defensiveStat,
ImmutableStatisticSet<uint> targetStats, Statistic stat, ref uint value)
{
var battleData = move.User.BattleData;
if (battleData is null)
return;
if (battleData.BattleSide.Pokemon.WhereNotNull().Any(x => x.IsUsable && x.ActiveAbility?.Name == "minus"))
{
value = value.MultiplyOrMax(1.5f);
}
}
}

View File

@ -0,0 +1,20 @@
namespace PkmnLib.Plugin.Gen7.Scripts.Abilities;
/// <summary>
/// Poison Heal is an ability that heals the Pokémon when it is poisoned instead of damaging it.
///
/// <see href="https://bulbapedia.bulbagarden.net/wiki/Poison_Heal_(Ability)">Bulbapedia - Poison Heal</see>
/// </summary>
[Script(ScriptCategory.Ability, "poison_heal")]
public class PoisonHeal : Script
{
/// <inheritdoc />
public override void CustomTrigger(StringKey eventName, ICustomTriggerArgs args)
{
if (eventName != CustomTriggers.PoisonedDamage)
return;
if (args is not CustomTriggers.PoisonedDamageArgs poisonArgs)
return;
poisonArgs.Invert = true;
}
}

View File

@ -0,0 +1,17 @@
namespace PkmnLib.Plugin.Gen7.Scripts.Abilities;
/// <summary>
/// Poison Point is an ability that may poison attackers making contact with the Pokémon.
///
/// <see href="https://bulbapedia.bulbagarden.net/wiki/Poison_Point_(Ability)">Bulbapedia - Poison Point</see>
/// </summary>
[Script(ScriptCategory.Ability, "poison_point")]
public class PoisonPoint : Script
{
/// <inheritdoc />
public override void OnIncomingHit(IExecutingMove move, IPokemon target, byte hit)
{
if (move.GetHitData(target, hit).IsContact)
move.User.SetStatus(ScriptUtils.ResolveName<Status.Poisoned>(), false);
}
}

View File

@ -0,0 +1,19 @@
namespace PkmnLib.Plugin.Gen7.Scripts.Abilities;
/// <summary>
/// Poison Touch is an ability that may poison targets when the Pokémon uses a contact move.
///
/// <see href="https://bulbapedia.bulbagarden.net/wiki/Poison_Touch_(Ability)">Bulbapedia - Poison Touch</see>
/// </summary>
[Script(ScriptCategory.Ability, "poison_touch")]
public class PoisonTouch : Script
{
private const int PoisonChance = 30;
/// <inheritdoc />
public override void OnIncomingHit(IExecutingMove move, IPokemon target, byte hit)
{
if (move.GetHitData(target, hit).IsContact && move.Battle.Random.GetInt(0, 100) < PoisonChance)
move.User.SetStatus(ScriptUtils.ResolveName<Status.Poisoned>(), false);
}
}

View File

@ -0,0 +1,37 @@
namespace PkmnLib.Plugin.Gen7.Scripts.Abilities;
/// <summary>
/// Power Construct is an ability that allows Zygarde to change form when its HP drops below half.
///
/// <see href="https://bulbapedia.bulbagarden.net/wiki/Power_Construct_(Ability)">Bulbapedia - Power Construct</see>
/// </summary>
[Script(ScriptCategory.Ability, "power_construct")]
public class PowerConstruct : Script
{
private IPokemon? _pokemon;
/// <inheritdoc />
public override void OnAddedToParent(IScriptSource source)
{
if (source is not IPokemon pokemon)
throw new InvalidOperationException("PowerConstruct script must be attached to a Pokemon.");
_pokemon = pokemon;
}
/// <inheritdoc />
public override void OnEndTurn(IBattle battle)
{
if (_pokemon?.BattleData?.Battle == null)
return;
if (_pokemon.Species.Name != "zygarde")
return;
if (_pokemon.CurrentHealth > _pokemon.BoostedStats.Hp / 2)
return;
if (_pokemon.Form.Name != "10" || _pokemon.Form.Name != "50")
return;
if (!_pokemon.Species.TryGetForm("complete", out var completeForm))
return;
_pokemon.ChangeForm(completeForm);
}
}

View File

@ -0,0 +1,20 @@
namespace PkmnLib.Plugin.Gen7.Scripts.Abilities;
/// <summary>
/// Power of Alchemy is an ability that copies the ability of a fainted ally.
///
/// <see href="https://bulbapedia.bulbagarden.net/wiki/Power_of_Alchemy_(Ability)">Bulbapedia - Power of Alchemy</see>
/// </summary>
[Script(ScriptCategory.Ability, "power_of_alchemy")]
public class PowerOfAlchemy : Script
{
/// <inheritdoc />
public override void OnAllyFaint(IPokemon ally, IPokemon faintedPokemon)
{
if (faintedPokemon.ActiveAbility?.HasFlag("cant_be_copied") != true)
return;
ally.BattleData?.Battle.EventHook.Invoke(new AbilityTriggerEvent(ally));
ally.ChangeAbility(faintedPokemon.ActiveAbility);
}
}

View File

@ -0,0 +1,19 @@
using PkmnLib.Static.Moves;
namespace PkmnLib.Plugin.Gen7.Scripts.Abilities;
/// <summary>
/// Prankster is an ability that gives priority to status moves.
///
/// <see href="https://bulbapedia.bulbagarden.net/wiki/Prankster_(Ability)">Bulbapedia - Prankster</see>
/// </summary>
[Script(ScriptCategory.Ability, "prankster")]
public class Prankster : Script
{
/// <inheritdoc />
public override void ChangePriority(IMoveChoice choice, ref sbyte priority)
{
if (choice.ChosenMove.MoveData.Category == MoveCategory.Status && priority != sbyte.MaxValue)
priority++;
}
}

View File

@ -0,0 +1,18 @@
namespace PkmnLib.Plugin.Gen7.Scripts.Abilities;
/// <summary>
/// Pressure is an ability that makes the opponent use more PP when using moves against the Pokémon.
///
/// <see href="https://bulbapedia.bulbagarden.net/wiki/Pressure_(Ability)">Bulbapedia - Pressure</see>
/// </summary>
[Script(ScriptCategory.Ability, "pressure")]
public class Pressure : Script
{
/// <inheritdoc />
public override void ModifyPPUsedForIncomingMove(IExecutingMove executingMove, ref byte ppUsed)
{
if (ppUsed == byte.MaxValue)
return;
ppUsed++;
}
}

View File

@ -108,4 +108,12 @@ public static class CustomTriggers
{
public float HealPercent { get; set; } = HealPercent;
}
public static readonly StringKey PoisonedDamage = "poisoned_damage";
public record PoisonedDamageArgs(IPokemon Pokemon, uint Damage) : ICustomTriggerArgs
{
public uint Damage { get; set; } = Damage;
public bool Invert { get; set; } = false;
}
}

View File

@ -28,6 +28,9 @@ public class Poisoned : Script
damage = 1;
var battleData = _pokemon.BattleData;
var args = new CustomTriggers.PoisonedDamageArgs(_pokemon, damage);
_pokemon.RunScriptHook(x => x.CustomTrigger(CustomTriggers.PoisonedDamage, args));
var eventBatchId = new EventBatchId();
battleData?.Battle.EventHook.Invoke(new DialogEvent("poisoned_damage", new Dictionary<string, object>
{
@ -37,6 +40,10 @@ public class Poisoned : Script
{
BatchId = eventBatchId,
});
if (args.Invert)
_pokemon.Heal(damage, batchId: eventBatchId);
else
_pokemon.Damage(damage, DamageSource.Status, eventBatchId);
}
}