More moves

This commit is contained in:
Deukhoofd 2025-04-17 10:22:24 +02:00
parent 7c2845502d
commit 1b54c78b07
Signed by: Deukhoofd
GPG Key ID: F63E044490819F6F
9 changed files with 172 additions and 16 deletions

View File

@ -85,6 +85,7 @@ internal static class MoveTurnExecutor
{
ExecuteMoveChoiceForTarget(battle, executingMove, target);
}
executingMove.RunScriptHook(x => x.OnAfterMove(executingMove));
}
private static void ExecuteMoveChoiceForTarget(IBattle battle, IExecutingMove executingMove, IPokemon target)

View File

@ -139,6 +139,8 @@ public interface IExecutingMove : IScriptSource
/// The underlying move choice.
/// </summary>
IMoveChoice MoveChoice { get; }
IReadOnlyList<IHitData> Hits { get; }
}
/// <inheritdoc cref="IExecutingMove"/>
@ -225,6 +227,9 @@ public class ExecutingMoveImpl : ScriptSource, IExecutingMove
/// <inheritdoc />
public IMoveChoice MoveChoice { get; }
/// <inheritdoc />
public IReadOnlyList<IHitData> Hits => _hits;
/// <inheritdoc />
public override int ScriptCount => 2 + User.ScriptCount;

View File

@ -315,7 +315,7 @@ public interface IPokemon : IScriptSource, IDeepCloneable
/// <summary>
/// Damages the Pokemon by a certain amount of damage, from a damage source.
/// </summary>
void Damage(uint damage, DamageSource source, EventBatchId batchId = default);
void Damage(uint damage, DamageSource source, EventBatchId batchId = default, bool forceDamage = false);
/// <summary>
/// Forces the Pokémon to faint.
@ -326,7 +326,7 @@ public interface IPokemon : IScriptSource, IDeepCloneable
/// Heals the Pokemon by a specific amount. Unless allow_revive is set to true, this will not
/// heal if the Pokemon has 0 health. If the amount healed is 0, this will return false.
/// </summary>
bool Heal(uint heal, bool allowRevive = false);
bool Heal(uint heal, bool allowRevive = false, EventBatchId batchId = default, bool forceHeal = false);
/// <summary>
/// Restores all PP of the Pokemon.
@ -943,12 +943,12 @@ public class PokemonImpl : ScriptSource, IPokemon
public bool IsFainted => CurrentHealth == 0;
/// <inheritdoc />
public void Damage(uint damage, DamageSource source, EventBatchId batchId)
public void Damage(uint damage, DamageSource source, EventBatchId batchId, bool forceDamage = false)
{
// If the Pokémon is already fainted, we don't need to do anything.
if (IsFainted)
return;
if (BattleData is not null)
if (BattleData is not null && !forceDamage)
{
var dmg = damage;
this.RunScriptHook(script => script.ChangeIncomingDamage(this, source, ref dmg));
@ -1013,7 +1013,7 @@ public class PokemonImpl : ScriptSource, IPokemon
}
/// <inheritdoc />
public bool Heal(uint heal, bool allowRevive)
public bool Heal(uint heal, bool allowRevive, EventBatchId batchId = default, bool forceHeal = false)
{
if (IsFainted && !allowRevive)
return false;
@ -1023,13 +1023,19 @@ public class PokemonImpl : ScriptSource, IPokemon
heal = maxAmount;
if (heal == 0)
return false;
if (!forceHeal)
{
var prevented = false;
this.RunScriptHook(x => x.PreventHeal(this, heal, allowRevive, ref prevented));
if (prevented)
return false;
}
var newHealth = CurrentHealth + heal;
BattleData?.Battle.EventHook.Invoke(new HealEvent(this, CurrentHealth, newHealth));
BattleData?.Battle.EventHook.Invoke(new HealEvent(this, CurrentHealth, newHealth)
{
BatchId = batchId,
});
CurrentHealth = newHealth;
return true;
}

View File

@ -179,6 +179,13 @@ public abstract class Script : IDeepCloneable
{
}
/// <summary>
/// This function runs immediately after all targets have had their hits executed.
/// </summary>
public virtual void OnAfterMove(IExecutingMove move)
{
}
/// <summary>
/// This function allows a script to prevent a move that is targeted at its owner. If set to true
/// the move fails, and fail events get triggered.

View File

@ -7555,7 +7555,10 @@
"reflectable",
"mirror",
"ignore-substitute"
]
],
"effect": {
"name": "foresight"
}
},
{
"name": "ominous_wind",
@ -7569,7 +7572,14 @@
"flags": [
"protect",
"mirror"
]
],
"effect": {
"name": "change_all_target_stats",
"chance": 10,
"parameters": {
"amount": 1
}
}
},
{
"name": "origin_pulse",
@ -7584,6 +7594,7 @@
"protect",
"mirror"
]
// No secondary effect
},
{
"name": "outrage",
@ -7598,7 +7609,10 @@
"contact",
"protect",
"mirror"
]
],
"effect": {
"name": "outrage"
}
},
{
"name": "overheat",
@ -7612,7 +7626,13 @@
"flags": [
"protect",
"mirror"
]
],
"effect": {
"name": "change_user_special_attack",
"parameters": {
"amount": -2
}
}
},
{
"name": "pain_split",
@ -7626,7 +7646,10 @@
"flags": [
"protect",
"mirror"
]
],
"effect": {
"name": "pain_split"
}
},
{
"name": "parabolic_charge",
@ -7641,7 +7664,10 @@
"protect",
"mirror",
"heal"
]
],
"effect": {
"name": "parabolic_charge"
}
},
{
"name": "parting_shot",

View File

@ -0,0 +1,22 @@
using PkmnLib.Plugin.Gen7.Scripts.Pokemon;
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "outrage")]
public class Outrage : Script
{
/// <inheritdoc />
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
{
if (move.User.Volatile.Contains<OutrageEffect>())
return;
var battleData = move.User.BattleData;
if (battleData == null)
return;
var turns = battleData.Battle.Random.GetBool() ? 2 : 3;
move.User.Volatile.Add(new OutrageEffect(move.User, turns, move.MoveChoice.TargetSide,
move.MoveChoice.TargetPosition));
}
}

View File

@ -0,0 +1,30 @@
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "pain_split")]
public class PainSplit : Script
{
/// <inheritdoc />
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
{
var userHp = move.User.CurrentHealth;
var targetHp = target.CurrentHealth;
var averageHp = (userHp + targetHp) / 2;
var evtBatch = new EventBatchId();
if (userHp > averageHp)
{
move.User.Damage(userHp - averageHp, DamageSource.Misc, evtBatch, true);
}
else if (userHp < averageHp)
{
move.User.Heal(averageHp - userHp, false, evtBatch, true);
}
if (targetHp > averageHp)
{
target.Damage(targetHp - averageHp, DamageSource.Misc, evtBatch, true);
}
else if (targetHp < averageHp)
{
target.Heal(averageHp - targetHp, false, evtBatch, true);
}
}
}

View File

@ -0,0 +1,22 @@
using System.Linq;
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
[Script(ScriptCategory.Move, "parabolic_charge")]
public class ParabolicCharge : Script
{
/// <inheritdoc />
public override void OnAfterMove(IExecutingMove move)
{
if (move.User.IsFainted)
return;
var totalDamage = move.Hits.Sum(x => x.Damage);
var halfDamage = totalDamage / 2;
if (halfDamage == 0)
return;
if (halfDamage > uint.MaxValue)
halfDamage = uint.MaxValue;
move.User.Heal((uint)halfDamage);
}
}

View File

@ -0,0 +1,37 @@
using PkmnLib.Plugin.Gen7.Scripts.Utils;
namespace PkmnLib.Plugin.Gen7.Scripts.Pokemon;
[Script(ScriptCategory.Pokemon, "outrage")]
public class OutrageEffect : Script
{
private readonly IPokemon _owner;
private int _turns;
private readonly byte _targetSide;
private readonly byte _targetPosition;
public OutrageEffect(IPokemon owner, int turns, byte targetSide, byte targetPosition)
{
_owner = owner;
_turns = turns;
_targetSide = targetSide;
_targetPosition = targetPosition;
}
/// <inheritdoc />
public override void ForceTurnSelection(byte sideIndex, byte position, ref ITurnChoice? choice)
{
choice = TurnChoiceHelper.CreateMoveChoice(_owner, "outrage", _targetSide, _targetPosition);
}
/// <inheritdoc />
public override void OnAfterHits(IExecutingMove move, IPokemon target)
{
_turns--;
if (_turns <= 0)
{
RemoveSelf();
_owner.Volatile.Add(new Confusion());
}
}
}