This commit is contained in:
@@ -12,6 +12,11 @@ public abstract class BaseChargeMove<TVolatile> : Script, IScriptPreventMove, IS
|
||||
if (move.User.Volatile.Contains<TVolatile>())
|
||||
return;
|
||||
|
||||
var args = new CustomTriggers.BypassChargeMoveArgs(move, false);
|
||||
move.RunScriptHook<IScriptCustomTrigger>(script => script.CustomTrigger(CustomTriggers.BypassChargeMove, args));
|
||||
if (args.Bypass)
|
||||
return;
|
||||
|
||||
move.User.Volatile.Add(CreateVolatile(move.User));
|
||||
move.User.BattleData?.Battle.EventHook.Invoke(new DialogEvent("began_charging", new Dictionary<string, object>
|
||||
{
|
||||
|
||||
@@ -30,7 +30,7 @@ public abstract class ChangeUserStats : Script, IScriptOnInitialize, IScriptOnSe
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
|
||||
public virtual void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
|
||||
{
|
||||
move.User.ChangeStatBoost(_stat, _amount, true, false);
|
||||
}
|
||||
|
||||
13
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/DefenseCurl.cs
Normal file
13
Plugins/PkmnLib.Plugin.Gen7/Scripts/Moves/DefenseCurl.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using PkmnLib.Plugin.Gen7.Scripts.Pokemon;
|
||||
|
||||
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||
|
||||
[Script(ScriptCategory.Move, "defense_curl")]
|
||||
public class DefenseCurl : ChangeUserDefense
|
||||
{
|
||||
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
|
||||
{
|
||||
base.OnSecondaryEffect(move, target, hit);
|
||||
move.User.Volatile.StackOrAdd(ScriptUtils.ResolveName<DefenseCurlEffect>(), () => new DefenseCurlEffect());
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,31 @@
|
||||
using PkmnLib.Plugin.Gen7.Scripts.Status;
|
||||
using PkmnLib.Static.Moves;
|
||||
|
||||
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||
|
||||
[Script(ScriptCategory.Move, "facade")]
|
||||
public class Facade : Script, IScriptChangeBasePower
|
||||
public class Facade : Script, IScriptChangeBasePower, IScriptChangeMoveDamage
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public void ChangeBasePower(IExecutingMove move, IPokemon target, byte hit, ref ushort basePower)
|
||||
{
|
||||
var status = move.User.StatusScript.Script?.Name;
|
||||
if (status == "paralyzed" || status == "burned" || status == "poisoned")
|
||||
if (status == ScriptUtils.ResolveName<Paralyzed>() || status == ScriptUtils.ResolveName<Burned>() ||
|
||||
status == ScriptUtils.ResolveName<Poisoned>() || status == ScriptUtils.ResolveName<BadlyPoisoned>())
|
||||
{
|
||||
basePower = basePower.MultiplyOrMax(2);
|
||||
}
|
||||
}
|
||||
|
||||
public void ChangeMoveDamage(IExecutingMove move, IPokemon target, byte hit, ref uint damage)
|
||||
{
|
||||
var status = move.User.StatusScript.Script?.Name;
|
||||
if (status != ScriptUtils.ResolveName<Burned>())
|
||||
return;
|
||||
// Ignore Burn's effect of halving the damage done by physical moves.
|
||||
if (move.UseMove.Category == MoveCategory.Physical)
|
||||
{
|
||||
damage = (uint)(damage * 2f);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ public class FalseSwipe : Script, IScriptChangeMoveDamage
|
||||
/// <inheritdoc />
|
||||
public void ChangeMoveDamage(IExecutingMove move, IPokemon target, byte hit, ref uint damage)
|
||||
{
|
||||
if (target.CurrentHealth - damage < 1)
|
||||
if ((int)target.CurrentHealth - damage < 1)
|
||||
{
|
||||
damage = target.CurrentHealth - 1;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using PkmnLib.Plugin.Gen7.Scripts.Pokemon;
|
||||
using PkmnLib.Plugin.Gen7.Scripts.Side;
|
||||
|
||||
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||
|
||||
@@ -8,9 +9,26 @@ public class Feint : Script, IScriptOnBeforeHit
|
||||
/// <inheritdoc />
|
||||
public void OnBeforeHit(IExecutingMove move, IPokemon target, byte hitIndex)
|
||||
{
|
||||
if (target.Volatile.Contains<ProtectionEffectScript>())
|
||||
var toRemove = new List<ScriptContainer>();
|
||||
foreach (var script in target.Volatile)
|
||||
{
|
||||
target.Volatile.Remove<ProtectionEffectScript>();
|
||||
if (script.Script is ProtectionEffectScript)
|
||||
{
|
||||
toRemove.Add(script);
|
||||
}
|
||||
}
|
||||
foreach (var script in toRemove)
|
||||
{
|
||||
script.Clear();
|
||||
}
|
||||
|
||||
var battleData = target.BattleData;
|
||||
if (battleData is not null)
|
||||
{
|
||||
if (battleData.BattleSide.VolatileScripts.Contains<CraftyShieldEffect>())
|
||||
battleData.BattleSide.VolatileScripts.Remove<CraftyShieldEffect>();
|
||||
if (battleData.BattleSide.VolatileScripts.Contains<MatBlockEffect>())
|
||||
battleData.BattleSide.VolatileScripts.Remove<MatBlockEffect>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@ public class FellStinger : Script, IScriptOnAfterHits
|
||||
{
|
||||
if (target.IsFainted)
|
||||
{
|
||||
move.User.ChangeStatBoost(Statistic.Attack, 2, true, false);
|
||||
move.User.ChangeStatBoost(Statistic.Attack, 3, true, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,11 +3,15 @@ using PkmnLib.Plugin.Gen7.Scripts.Pokemon;
|
||||
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||
|
||||
[Script(ScriptCategory.Move, "fire_spin")]
|
||||
public class FireSpin : MultiHitMove, IScriptOnSecondaryEffect
|
||||
public class FireSpin : Script, IScriptOnSecondaryEffect
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
|
||||
{
|
||||
target.Volatile.StackOrAdd("fire_spin", () => new FireSpinEffect(target));
|
||||
target.Volatile.StackOrAdd("fire_spin", () =>
|
||||
{
|
||||
var turns = target.BattleData!.Battle.Random.GetInt(4, 6);
|
||||
return new FireSpinEffect(target, turns, move.User);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ public class Flail : Script, IScriptChangeBasePower
|
||||
/// <inheritdoc />
|
||||
public void ChangeBasePower(IExecutingMove move, IPokemon target, byte hit, ref ushort basePower)
|
||||
{
|
||||
var remainingHealth = move.User.CurrentHealth / move.User.BoostedStats.Hp;
|
||||
var remainingHealth = move.User.CurrentHealth / (float)move.User.BoostedStats.Hp;
|
||||
var fraction = remainingHealth * 48;
|
||||
basePower = fraction switch
|
||||
{
|
||||
|
||||
@@ -6,7 +6,7 @@ public class FlameBurst : Script, IScriptOnSecondaryEffect
|
||||
/// <inheritdoc />
|
||||
public void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
|
||||
{
|
||||
var adjacentFoes = GetAdjacentFoes(move.User).WhereNotNull();
|
||||
var adjacentFoes = GetAdjacentFoes(target).WhereNotNull();
|
||||
EventBatchId batchId = new();
|
||||
foreach (var adjacentFoe in adjacentFoes)
|
||||
{
|
||||
|
||||
@@ -11,18 +11,18 @@ public class FlareBlitz : Script, IScriptOnSecondaryEffect
|
||||
return;
|
||||
|
||||
var hitData = move.GetHitData(target, hit);
|
||||
var recoilDamage = hitData.Damage * (1 / 3);
|
||||
|
||||
var triggerArgs = new CustomTriggers.ModifyRecoilArgs(move, target, hit, hitData.Damage, recoilDamage);
|
||||
move.RunScriptHook<IScriptCustomTrigger>(x => x.CustomTrigger(CustomTriggers.ModifyRecoil, triggerArgs));
|
||||
if (triggerArgs.Prevent)
|
||||
return;
|
||||
var recoilDamage = hitData.Damage * (1 / 3f);
|
||||
|
||||
if (battleData.Battle.Random.EffectChance(10, move, target, hit))
|
||||
{
|
||||
target.SetStatus("burned", move.User);
|
||||
}
|
||||
|
||||
move.User.Damage(recoilDamage, DamageSource.Misc);
|
||||
var triggerArgs = new CustomTriggers.ModifyRecoilArgs(move, target, hit, hitData.Damage, (uint)recoilDamage);
|
||||
move.RunScriptHook<IScriptCustomTrigger>(x => x.CustomTrigger(CustomTriggers.ModifyRecoil, triggerArgs));
|
||||
if (triggerArgs.Prevent)
|
||||
return;
|
||||
|
||||
move.User.Damage((uint)recoilDamage, DamageSource.Misc);
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,7 @@ public class Fling : Script, IScriptOnSecondaryEffect, IScriptChangeBasePower
|
||||
move.GetHitData(target, hit).Fail();
|
||||
return;
|
||||
}
|
||||
if (!item.TryGetAdditionalData<byte>("fling_power", out var flingPower))
|
||||
if (!item.TryGetAdditionalData<byte>("flingPower", out var flingPower))
|
||||
{
|
||||
move.GetHitData(target, hit).Fail();
|
||||
return;
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
using PkmnLib.Plugin.Gen7.Scripts.Pokemon;
|
||||
|
||||
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||
|
||||
[Script(ScriptCategory.Move, "flower_shield")]
|
||||
@@ -14,6 +16,7 @@ public class FlowerShield : Script, IScriptOnSecondaryEffect
|
||||
|
||||
var batchId = new EventBatchId();
|
||||
var sides = battleData.Battle.Sides;
|
||||
var anyFound = false;
|
||||
foreach (var side in sides)
|
||||
{
|
||||
foreach (var pokemon in side.Pokemon)
|
||||
@@ -22,8 +25,13 @@ public class FlowerShield : Script, IScriptOnSecondaryEffect
|
||||
continue;
|
||||
if (!pokemon.Types.Contains(grassType))
|
||||
continue;
|
||||
if (pokemon.Volatile.Any(x => x.Script?.IsSemiInvulnerableTurn == true))
|
||||
continue;
|
||||
pokemon.ChangeStatBoost(Statistic.Defense, 1, pokemon == move.User, false, batchId);
|
||||
anyFound = true;
|
||||
}
|
||||
}
|
||||
if (!anyFound)
|
||||
move.GetHitData(target, hit).Fail();
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,11 @@ public class FocusEnergy : Script, IScriptOnSecondaryEffect
|
||||
/// <inheritdoc />
|
||||
public void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
|
||||
{
|
||||
target.Volatile.Add(new Pokemon.IncreasedCriticalStage());
|
||||
if (target.Volatile.Contains<Pokemon.FocusEnergyEffect>())
|
||||
{
|
||||
move.GetHitData(target, hit).Fail();
|
||||
return;
|
||||
}
|
||||
target.Volatile.Add(new Pokemon.FocusEnergyEffect());
|
||||
}
|
||||
}
|
||||
@@ -1,20 +1,13 @@
|
||||
using PkmnLib.Plugin.Gen7.Scripts.Pokemon;
|
||||
|
||||
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||
|
||||
[Script(ScriptCategory.Move, "follow_me")]
|
||||
public class FollowMe : Script, IScriptChangeTargets
|
||||
public class FollowMe : Script, IScriptOnSecondaryEffect
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public void ChangeTargets(IMoveChoice moveChoice, ref IReadOnlyList<IPokemon?> targets)
|
||||
public void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
|
||||
{
|
||||
if (targets.Count != 1)
|
||||
return;
|
||||
|
||||
var target = targets[0];
|
||||
if (target == null)
|
||||
return;
|
||||
if (target.BattleData?.SideIndex != moveChoice.User.BattleData?.SideIndex)
|
||||
return;
|
||||
|
||||
targets = [moveChoice.User];
|
||||
move.User.BattleData!.BattleSide.VolatileScripts.StackOrAdd(ScriptUtils.ResolveName<FollowMeEffect>(),
|
||||
() => new FollowMeEffect(move.User));
|
||||
}
|
||||
}
|
||||
@@ -11,8 +11,15 @@ public class Foresight : Script, IScriptOnSecondaryEffect
|
||||
var battleData = target.BattleData;
|
||||
if (battleData == null)
|
||||
return;
|
||||
if (target.StatBoost.Evasion > 0)
|
||||
target.ChangeStatBoost(Statistic.Evasion, (sbyte)-target.StatBoost.Evasion, false, false);
|
||||
|
||||
if (target.Volatile.Contains<ForesightEffect>())
|
||||
{
|
||||
move.GetHitData(target, hit).Fail();
|
||||
return;
|
||||
}
|
||||
var typeLibrary = battleData.Battle.Library.StaticLibrary.Types;
|
||||
target.Volatile.Add(new ForesightEffect(typeLibrary));
|
||||
target.ChangeStatBoost(Statistic.Evasion, (sbyte)-target.StatBoost.Evasion, false, false);
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
using PkmnLib.Plugin.Gen7.Scripts.Pokemon;
|
||||
|
||||
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||
|
||||
[Script(ScriptCategory.Move, "forests_curse")]
|
||||
@@ -10,8 +12,18 @@ public class ForestsCurse : Script, IScriptOnSecondaryEffect
|
||||
if (battleData == null)
|
||||
return;
|
||||
var typeLibrary = battleData.Battle.Library.StaticLibrary.Types;
|
||||
if (!typeLibrary.TryGetTypeIdentifier("grass", out var grassType))
|
||||
if (!typeLibrary.TryGetTypeIdentifier("grass", out var grassType) || target.Types.Contains(grassType))
|
||||
{
|
||||
move.GetHitData(target, hit).Fail();
|
||||
return;
|
||||
}
|
||||
if (target.Volatile.TryGet<HasHadTypeAddedEffect>(out var effect))
|
||||
{
|
||||
target.RemoveType(effect.TypeIdentifier);
|
||||
target.Volatile.Remove<HasHadTypeAddedEffect>();
|
||||
}
|
||||
|
||||
target.AddType(grassType);
|
||||
target.Volatile.Add(new HasHadTypeAddedEffect(grassType));
|
||||
}
|
||||
}
|
||||
@@ -14,10 +14,11 @@ public class FreezeDry : Script, IScriptChangeEffectiveness, IScriptOnSecondaryE
|
||||
if (!typeLibrary.TryGetTypeIdentifier("water", out var waterType))
|
||||
return;
|
||||
|
||||
if (target.Types.Contains(waterType))
|
||||
var hitDataType = move.GetHitData(target, hit).Type;
|
||||
if (target.Types.Contains(waterType) && hitDataType.HasValue)
|
||||
{
|
||||
var effectivenessWithoutWater = target.Types.Where(x => x != waterType)
|
||||
.Select(x => typeLibrary.GetEffectiveness(x, target.Types)).Aggregate(1f, (a, b) => a * b);
|
||||
.Select(x => typeLibrary.GetSingleEffectiveness(hitDataType.Value, x)).Aggregate(1f, (a, b) => a * b);
|
||||
effectiveness = effectivenessWithoutWater * 2;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ public class FuryCutter : Script, IScriptChangeBasePower
|
||||
return;
|
||||
}
|
||||
|
||||
if (userEffect.TurnCount < 5)
|
||||
if (userEffect.TurnCount < 2)
|
||||
userEffect.TurnCount++;
|
||||
basePower = basePower.MultiplyOrMax((byte)Math.Pow(2, userEffect.TurnCount));
|
||||
}
|
||||
|
||||
@@ -12,11 +12,11 @@ public class FusionBolt : Script, IScriptChangeDamageModifier
|
||||
|
||||
// Grab the choices for the current turn, that have been executed before this move.
|
||||
var choice = battleData.Battle.PreviousTurnChoices.Last().TakeWhile(x => !Equals(x, move.MoveChoice))
|
||||
// Of these, find the move choice that used Fusion Flare.
|
||||
.OfType<MoveChoice>().FirstOrDefault(x => x.ChosenMove.MoveData.Name == "fusion_flare");
|
||||
// Of these, find the last successfully executed move. Failed moves don't break the combination.
|
||||
.OfType<MoveChoice>().LastOrDefault(x => !x.HasFailed);
|
||||
|
||||
// If Fusion Flare was used, Fusion Bolt's power is doubled.
|
||||
if (choice != null)
|
||||
// If Fusion Flare was used immediately preceding, Fusion Bolt's power is doubled.
|
||||
if (choice is not null && choice.ChosenMove.MoveData.Name == "fusion_flare")
|
||||
{
|
||||
modifier *= 2;
|
||||
}
|
||||
|
||||
@@ -12,11 +12,11 @@ public class FusionFlare : Script, IScriptChangeDamageModifier
|
||||
|
||||
// Grab the choices for the current turn, that have been executed before this move.
|
||||
var choice = battleData.Battle.PreviousTurnChoices.Last().TakeWhile(x => !Equals(x, move.MoveChoice))
|
||||
// Of these, find the move choice that used Fusion Bolt.
|
||||
.OfType<MoveChoice>().FirstOrDefault(x => x.ChosenMove.MoveData.Name == "fusion_bolt");
|
||||
// Of these, find the last successfully executed move. Failed moves don't break the combination.
|
||||
.OfType<MoveChoice>().LastOrDefault(x => !x.HasFailed);
|
||||
|
||||
// If Fusion Bolt was used, Fusion Flare's power is doubled.
|
||||
if (choice != null)
|
||||
// If Fusion Bolt was used immediately preceding, Fusion Flare's power is doubled.
|
||||
if (choice is not null && choice.ChosenMove.MoveData.Name == "fusion_bolt")
|
||||
{
|
||||
modifier *= 2;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using PkmnLib.Plugin.Gen7.Scripts.Battle;
|
||||
using PkmnLib.Plugin.Gen7.Scripts.Side;
|
||||
|
||||
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||
|
||||
@@ -11,8 +12,28 @@ public class FutureSight : Script, IScriptStopBeforeMove
|
||||
var battleData = move.User.BattleData;
|
||||
if (battleData == null)
|
||||
return;
|
||||
battleData.Battle.Volatile.Add(new FutureSightEffect(move.MoveChoice));
|
||||
var battle = battleData.Battle;
|
||||
var moveChoice = move.MoveChoice;
|
||||
|
||||
prevent = true;
|
||||
|
||||
if (IsTargetAlreadySetToBeHit(battle, moveChoice.TargetSide, moveChoice.TargetPosition))
|
||||
{
|
||||
moveChoice.Fail();
|
||||
return;
|
||||
}
|
||||
|
||||
if (battle.Volatile.TryGet<FutureSightEffect>(out var effect))
|
||||
effect.AddStrike(moveChoice);
|
||||
else
|
||||
battle.Volatile.Add(new FutureSightEffect(moveChoice));
|
||||
}
|
||||
|
||||
private static bool IsTargetAlreadySetToBeHit(IBattle battle, byte side, byte position)
|
||||
{
|
||||
if (battle.Volatile.TryGet<FutureSightEffect>(out var futureSight) && futureSight.HasStrikeAt(side, position))
|
||||
return true;
|
||||
var doomDesire = battle.Sides[side].VolatileScripts.Get<DoomDesireEffect>();
|
||||
return doomDesire != null && doomDesire.HasTarget(position);
|
||||
}
|
||||
}
|
||||
@@ -23,17 +23,15 @@ public class Gravity : Script, IScriptOnSecondaryEffect
|
||||
var flyEffect = ScriptUtils.ResolveName<ChargeFlyEffect>();
|
||||
var skyDropEffect = ScriptUtils.ResolveName<ChargeSkyDropEffect>();
|
||||
var telekinesisEffect = ScriptUtils.ResolveName<TelekinesisEffect>();
|
||||
var magnetRiseEffect = ScriptUtils.ResolveName<MagnetRiseEffect>();
|
||||
|
||||
foreach (var pokemon in battleData.Battle.Sides.SelectMany(x => x.Pokemon).WhereNotNull())
|
||||
{
|
||||
if (pokemon.Volatile.Contains(chargeBounceEffect))
|
||||
pokemon.Volatile.Remove(chargeBounceEffect);
|
||||
if (pokemon.Volatile.Contains(flyEffect))
|
||||
pokemon.Volatile.Remove(flyEffect);
|
||||
if (pokemon.Volatile.Contains(skyDropEffect))
|
||||
pokemon.Volatile.Remove(skyDropEffect);
|
||||
if (pokemon.Volatile.Contains(telekinesisEffect))
|
||||
pokemon.Volatile.Remove(telekinesisEffect);
|
||||
pokemon.Volatile.Remove(chargeBounceEffect);
|
||||
pokemon.Volatile.Remove(flyEffect);
|
||||
pokemon.Volatile.Remove(skyDropEffect);
|
||||
pokemon.Volatile.Remove(telekinesisEffect);
|
||||
pokemon.Volatile.Remove(magnetRiseEffect);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,6 @@ public class GuardianOfAlola : Script, IScriptChangeMoveDamage
|
||||
/// <inheritdoc />
|
||||
public void ChangeMoveDamage(IExecutingMove move, IPokemon target, byte hit, ref uint damage)
|
||||
{
|
||||
var maxHp = target.BoostedStats.Hp;
|
||||
damage = (uint)(maxHp * (3f / 4f));
|
||||
damage = (uint)Math.Max(target.CurrentHealth * (3f / 4f), 1);
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,11 @@ public class GyroBall : Script, IScriptChangeBasePower
|
||||
/// <inheritdoc />
|
||||
public void ChangeBasePower(IExecutingMove move, IPokemon target, byte hit, ref ushort basePower)
|
||||
{
|
||||
basePower = Math.Min((byte)150, (byte)(25 * target.BoostedStats.Speed / move.User.BoostedStats.Speed + 1));
|
||||
if (move.User.BoostedStats.Speed == 0)
|
||||
{
|
||||
basePower = 1;
|
||||
return;
|
||||
}
|
||||
basePower = (ushort)Math.Min(150, 25 * target.BoostedStats.Speed / move.User.BoostedStats.Speed + 1);
|
||||
}
|
||||
}
|
||||
@@ -14,10 +14,9 @@ public class HealBell : Script, IScriptOnSecondaryEffect
|
||||
|
||||
foreach (var pokemon in party.Party.WhereNotNull())
|
||||
{
|
||||
if (pokemon.BattleData?.IsOnBattlefield == true && pokemon.ActiveAbility?.Name == "soundproof")
|
||||
continue;
|
||||
pokemon.ClearStatus();
|
||||
var confusion = ScriptUtils.ResolveName<Confusion>();
|
||||
if (pokemon.Volatile.Contains(confusion))
|
||||
pokemon.Volatile.Remove(confusion);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,14 @@ public class HealingWish : Script, IScriptOnSecondaryEffect
|
||||
if (battleData == null)
|
||||
return;
|
||||
|
||||
var responsibleIndex = new ResponsibleIndex(battleData.SideIndex, battleData.Position);
|
||||
var party = battleData.Battle.Parties.FirstOrDefault(x => x.IsResponsibleForIndex(responsibleIndex));
|
||||
if (party == null || !party.HasUsablePokemonNotInField())
|
||||
{
|
||||
move.GetHitData(target, hit).Fail();
|
||||
return;
|
||||
}
|
||||
|
||||
var side = battleData.Battle.Sides[battleData.SideIndex];
|
||||
side.VolatileScripts.Add(new HealingWishEffect(battleData.Position));
|
||||
|
||||
|
||||
@@ -16,8 +16,8 @@ public class HeartSwap : Script, IScriptOnSecondaryEffect
|
||||
var targetStat = targetStats.GetStatistic(stat);
|
||||
if (userStat == targetStat)
|
||||
continue;
|
||||
move.User.ChangeStatBoost(stat, (sbyte)(userStat - targetStat), true, true, eventBatchId);
|
||||
target.ChangeStatBoost(stat, (sbyte)(targetStat - userStat), false, true, eventBatchId);
|
||||
move.User.ChangeStatBoost(stat, (sbyte)(targetStat - userStat), true, true, eventBatchId);
|
||||
target.ChangeStatBoost(stat, (sbyte)(userStat - targetStat), false, true, eventBatchId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,10 +9,10 @@ public class HeatCrash : Script, IScriptChangeBasePower
|
||||
var weightMultiplier = move.User.WeightInKg / target.WeightInKg;
|
||||
basePower = weightMultiplier switch
|
||||
{
|
||||
> 5 => 120,
|
||||
> 4 => 100,
|
||||
> 3 => 80,
|
||||
> 2 => 60,
|
||||
>= 5 => 120,
|
||||
>= 4 => 100,
|
||||
>= 3 => 80,
|
||||
>= 2 => 60,
|
||||
_ => 40,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ public class Hex : Script, IScriptChangeBasePower
|
||||
/// <inheritdoc />
|
||||
public void ChangeBasePower(IExecutingMove move, IPokemon target, byte hit, ref ushort basePower)
|
||||
{
|
||||
if (!target.StatusScript.IsEmpty)
|
||||
if (!target.StatusScript.IsEmpty || target.ActiveAbility?.Name == "comatose")
|
||||
{
|
||||
basePower = basePower.MultiplyOrMax(2);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||
|
||||
[Script(ScriptCategory.Move, "hidden_power")]
|
||||
public class HiddenPower : Script, IScriptChangeMoveType, IScriptChangeBasePower
|
||||
public class HiddenPower : Script, IScriptChangeMoveType
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public void ChangeMoveType(IExecutingMove move, IPokemon target, byte hit, ref TypeIdentifier? moveType)
|
||||
@@ -14,16 +14,6 @@ public class HiddenPower : Script, IScriptChangeMoveType, IScriptChangeBasePower
|
||||
moveType = t;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void ChangeBasePower(IExecutingMove move, IPokemon target, byte hit, ref ushort basePower)
|
||||
{
|
||||
var ivs = move.User.IndividualValues;
|
||||
|
||||
var power = GetHiddenPowerValue(ivs, 0x00000002) * 40 / 63 + 30;
|
||||
// cast to byte with overflow check
|
||||
basePower = (byte)Math.Min(power, byte.MaxValue);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper method to calculate the hidden power value from the IVs.
|
||||
/// This is used to determine the type and power of the move.
|
||||
|
||||
@@ -1,16 +1,23 @@
|
||||
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||
|
||||
[Script(ScriptCategory.Move, "high_jump_kick")]
|
||||
public class HighJumpKick : Script, IScriptOnMoveMiss
|
||||
public class HighJumpKick : Script, IScriptOnAfterHits
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public void OnMoveMiss(IExecutingMove move, IPokemon target)
|
||||
public void OnAfterHits(IExecutingMove move, IPokemon target)
|
||||
{
|
||||
var damage = move.Hits.Where(h => h.HasExecuted).Sum(h => h.Damage);
|
||||
if (damage == 0)
|
||||
{
|
||||
DoRecoil(move);
|
||||
}
|
||||
}
|
||||
|
||||
private static void DoRecoil(IExecutingMove move)
|
||||
{
|
||||
var damage = move.GetHitData(target, 0).Damage;
|
||||
var recoil = damage / 2;
|
||||
// This recoil damage will not exceed half the user's max HP
|
||||
var maxHp = move.User.BoostedStats.Hp;
|
||||
recoil = Math.Min(recoil, maxHp / 2);
|
||||
var recoil = maxHp / 2;
|
||||
if (recoil == 0)
|
||||
return;
|
||||
move.User.Damage(recoil, DamageSource.Misc);
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,10 @@
|
||||
using PkmnLib.Plugin.Gen7.Scripts.Pokemon;
|
||||
using PkmnLib.Plugin.Gen7.Scripts.Side;
|
||||
|
||||
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||
|
||||
[Script(ScriptCategory.Move, "hyperspace_fury")]
|
||||
public class HyperspaceFury : Script, IScriptOnSecondaryEffect
|
||||
public class HyperspaceFury : Script, IScriptFailMove, IScriptOnSecondaryEffect
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
|
||||
@@ -13,5 +14,21 @@ public class HyperspaceFury : Script, IScriptOnSecondaryEffect
|
||||
{
|
||||
target.Volatile.Remove(protectionScript.Name);
|
||||
}
|
||||
target.BattleData?.BattleSide.VolatileScripts.Remove(ScriptUtils.ResolveName<CraftyShieldEffect>());
|
||||
target.BattleData?.BattleSide.VolatileScripts.Remove(ScriptUtils.ResolveName<MatBlockEffect>());
|
||||
target.BattleData?.BattleSide.VolatileScripts.Remove(ScriptUtils.ResolveName<QuickGuardEffect>());
|
||||
target.BattleData?.BattleSide.VolatileScripts.Remove(ScriptUtils.ResolveName<WideGuardEffect>());
|
||||
move.User.ChangeStatBoost(Statistic.Defense, -1, true, false);
|
||||
}
|
||||
|
||||
private static StringKey HoopaName = "hoopa";
|
||||
private static StringKey UnboundName = "unbound";
|
||||
|
||||
public void FailMove(IExecutingMove move, ref bool fail)
|
||||
{
|
||||
if (move.User.Species.Name != HoopaName || move.User.Form.Name != UnboundName)
|
||||
{
|
||||
fail = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -24,9 +24,5 @@ public class IceBall : Script, IScriptOnSecondaryEffect, IScriptChangeBasePower
|
||||
userEffect = new IceBallEffect(move.User, move.UseMove.Name);
|
||||
move.User.Volatile.Add(userEffect);
|
||||
}
|
||||
else
|
||||
{
|
||||
userEffect.TurnCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,17 +8,23 @@ public class IceFang : Script, IScriptOnSecondaryEffect
|
||||
/// <inheritdoc />
|
||||
public void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
|
||||
{
|
||||
var battleData = move.User.BattleData;
|
||||
var battleData = target.BattleData;
|
||||
if (battleData == null)
|
||||
return;
|
||||
|
||||
if (battleData.Battle.Random.EffectChance(10, move, target, hit))
|
||||
var random = battleData.Battle.Random;
|
||||
if (random.EffectChance(10, move, target, hit))
|
||||
{
|
||||
target.SetStatus("frozen", move.User);
|
||||
}
|
||||
if (battleData.Battle.Random.EffectChance(10, move, target, hit))
|
||||
|
||||
// It also has an independent 10% chance of causing the target to flinch, if the user attacks before the target.
|
||||
var choiceQueue = battleData.Battle.ChoiceQueue;
|
||||
if (choiceQueue?.FirstOrDefault(x => x.User == target) != null)
|
||||
{
|
||||
target.Volatile.Add(new FlinchEffect());
|
||||
if (random.EffectChance(10, move, target, hit))
|
||||
{
|
||||
target.Volatile.Add(new FlinchEffect());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,6 @@ public class Imprison : Script, IScriptOnSecondaryEffect
|
||||
/// <inheritdoc />
|
||||
public void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
|
||||
{
|
||||
target.Volatile.Add(new ImprisonEffect(move.User));
|
||||
target.BattleData?.Battle.Volatile.Add(new ImprisonEffect(move.User));
|
||||
}
|
||||
}
|
||||
@@ -6,15 +6,18 @@ public class Incinerate : Script, IScriptOnSecondaryEffect
|
||||
/// <inheritdoc />
|
||||
public void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
|
||||
{
|
||||
if (target.HeldItem is not { Category: ItemCategory.Berry } || !target.TryStealHeldItem(out _))
|
||||
var isValidItem = target.HeldItem is { Category: ItemCategory.Berry } ||
|
||||
(target.HeldItem?.Name.ToString().EndsWith("_gem") == true && target.HeldItem is
|
||||
{ Category: ItemCategory.MiscItem });
|
||||
|
||||
if (!isValidItem || !target.TryStealHeldItem(out _))
|
||||
{
|
||||
move.GetHitData(target, hit).Fail();
|
||||
return;
|
||||
}
|
||||
move.Battle.EventHook.Invoke(new DialogEvent("item_incinerated", new Dictionary<string, object>
|
||||
{
|
||||
{ "pokemon", target },
|
||||
{ "item", target.HeldItem },
|
||||
{ "item", target.HeldItem! },
|
||||
}));
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,16 @@ public class Infestation : Script, IScriptOnSecondaryEffect
|
||||
{
|
||||
turns = 5;
|
||||
}
|
||||
target.Volatile.Add(new InfestationEffect(target, turns));
|
||||
|
||||
var args = new CustomTriggers.ModifyBindArgs(move)
|
||||
{
|
||||
Duration = turns,
|
||||
DamagePercent = 1 / 8f,
|
||||
};
|
||||
move.User.RunScriptHook<IScriptCustomTrigger>(x => x.CustomTrigger(CustomTriggers.ModifyBind, args));
|
||||
var bindTurns = args.Duration;
|
||||
var bindDamage = args.DamagePercent;
|
||||
|
||||
target.Volatile.Add(new InfestationEffect(target, bindTurns, bindDamage));
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using PkmnLib.Dynamic.BattleFlow;
|
||||
using PkmnLib.Plugin.Gen7.Scripts.Utils;
|
||||
|
||||
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||
|
||||
@@ -16,7 +17,8 @@ public class Instruct : Script, IScriptOnSecondaryEffect
|
||||
|
||||
var lastMoveChoiceByTarget = target.BattleData?.LastMoveChoice;
|
||||
|
||||
if (lastMoveChoiceByTarget == null || !battleData.Battle.CanUse(lastMoveChoiceByTarget))
|
||||
if (lastMoveChoiceByTarget == null || !battleData.Battle.CanUse(lastMoveChoiceByTarget) ||
|
||||
!lastMoveChoiceByTarget.ChosenMove.MoveData.CanCopyMove())
|
||||
{
|
||||
move.GetHitData(target, hit).Fail();
|
||||
return;
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
using PkmnLib.Plugin.Gen7.Scripts.Battle;
|
||||
|
||||
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||
|
||||
[Script(ScriptCategory.Move, "judgement")]
|
||||
@@ -6,6 +8,12 @@ public class Judgement : Script, IScriptChangeMoveType
|
||||
/// <inheritdoc />
|
||||
public void ChangeMoveType(IExecutingMove move, IPokemon target, byte hit, ref TypeIdentifier? moveType)
|
||||
{
|
||||
//If Magic Room is in effect, Judgment's type will always be Normal regardless of the Plate held
|
||||
if (move.Battle.Volatile.Contains<MagicRoomEffect>())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var heldItem = move.User.HeldItem;
|
||||
if (heldItem == null)
|
||||
return;
|
||||
|
||||
@@ -3,10 +3,16 @@ namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||
[Script(ScriptCategory.Move, "kings_shield")]
|
||||
public class KingsShield : ProtectionScript
|
||||
{
|
||||
protected override Script GetEffectScript() => new Pokemon.KingsShieldEffect();
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
|
||||
{
|
||||
base.OnSecondaryEffect(move, target, hit);
|
||||
|
||||
// Only change Aegislash form if the move has not failed
|
||||
if (move.GetHitData(target, hit).HasFailed)
|
||||
return;
|
||||
// Default form is shield form
|
||||
if (move.User.Species.Name == "aegislash" && move.User.Form.Name != "default")
|
||||
{
|
||||
|
||||
@@ -1,14 +1,20 @@
|
||||
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||
|
||||
[Script(ScriptCategory.Move, "knock_off")]
|
||||
public class KnockOff : Script, IScriptOnSecondaryEffect
|
||||
public class KnockOff : Script, IScriptOnSecondaryEffect, IScriptChangeBasePower
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
|
||||
{
|
||||
if (!target.TryStealHeldItem(out _))
|
||||
{
|
||||
move.GetHitData(target, hit).Fail();
|
||||
}
|
||||
if (move.User.IsFainted)
|
||||
return;
|
||||
target.TryStealHeldItem(out _);
|
||||
}
|
||||
|
||||
public void ChangeBasePower(IExecutingMove move, IPokemon target, byte hit, ref ushort basePower)
|
||||
{
|
||||
if (target.HeldItem == null || target.HeldItem.Category == ItemCategory.FormChanger)
|
||||
return;
|
||||
basePower = basePower.MultiplyOrMax(1.5f);
|
||||
}
|
||||
}
|
||||
@@ -20,7 +20,7 @@ public class LastResort : Script, IScriptPreventMoveSelection
|
||||
}
|
||||
|
||||
// Grab all move choices
|
||||
var movesForUserSinceEnteringField = battleData.Battle.PreviousTurnChoices
|
||||
var movesForUserSinceEnteringField = battleData.Battle.PreviousTurnChoices.Skip((int)battleData.SwitchInTurn)
|
||||
// Reading backwards
|
||||
.Reverse().SelectMany(x => x.Reverse())
|
||||
// We only care about move choices since the user entered the field
|
||||
@@ -29,7 +29,7 @@ public class LastResort : Script, IScriptPreventMoveSelection
|
||||
.Where(x => x.User == choice.User)
|
||||
// Grab the chosen move, and remove duplicates
|
||||
.Select(x => x.ChosenMove).Distinct().ToList();
|
||||
if (!userMoves.All(x => movesForUserSinceEnteringField.Contains(x)))
|
||||
if (!userMoves.All(movesForUserSinceEnteringField.Contains))
|
||||
{
|
||||
prevent = true;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,6 @@ public class LockOn : Script, IScriptOnSecondaryEffect
|
||||
/// <inheritdoc />
|
||||
public void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
|
||||
{
|
||||
target.Volatile.Add(new LockOnEffect(target));
|
||||
target.Volatile.Add(new LockOnEffect(move.User));
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using PkmnLib.Plugin.Gen7.Scripts.Pokemon;
|
||||
using PkmnLib.Plugin.Gen7.Scripts.Side;
|
||||
|
||||
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||
|
||||
@@ -8,6 +9,6 @@ public class LuckyChant : Script, IScriptOnSecondaryEffect
|
||||
/// <inheritdoc />
|
||||
public void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
|
||||
{
|
||||
target.Volatile.Add(new LuckyChantEffect());
|
||||
target.BattleData?.BattleSide.VolatileScripts.Add(new LuckyChantEffect());
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,9 @@ public class LunarDance : Script, IScriptOnSecondaryEffect
|
||||
public void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
|
||||
{
|
||||
var battleData = move.User.BattleData;
|
||||
battleData?.BattleSide.VolatileScripts.Add(new LunarDanceEffect(battleData.Position));
|
||||
if (battleData is null)
|
||||
return;
|
||||
battleData.BattleSide.VolatileScripts.Add(new LunarDanceEffect(battleData.Position));
|
||||
move.User.Faint(DamageSource.Misc);
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,13 @@ public class MagicRoom : Script, IScriptOnSecondaryEffect
|
||||
return;
|
||||
|
||||
var battle = battleData.Battle;
|
||||
battle.Volatile.Add(new MagicRoomEffect());
|
||||
if (battle.Volatile.Contains<MagicRoomEffect>())
|
||||
{
|
||||
battle.Volatile.Remove<MagicRoomEffect>();
|
||||
}
|
||||
else
|
||||
{
|
||||
battle.Volatile.Add(new MagicRoomEffect());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,11 +3,17 @@ using PkmnLib.Plugin.Gen7.Scripts.Pokemon;
|
||||
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||
|
||||
[Script(ScriptCategory.Move, "magma_storm")]
|
||||
public class MagmaStorm : MultiHitMove, IScriptOnSecondaryEffect
|
||||
public class MagmaStorm : Script, IScriptOnSecondaryEffect
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
|
||||
{
|
||||
target.Volatile.StackOrAdd("magma_storm", () => new MagmaStormEffect(target));
|
||||
var args = new CustomTriggers.ModifyBindArgs(move);
|
||||
move.User.RunScriptHook<IScriptCustomTrigger>(x => x.CustomTrigger(CustomTriggers.ModifyBind, args));
|
||||
|
||||
var bindTurns = args.Duration;
|
||||
var bindDamage = args.DamagePercent;
|
||||
|
||||
target.Volatile.StackOrAdd("magma_storm", () => new MagmaStormEffect(target, bindTurns, bindDamage));
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,7 @@ public class MagnetRise : Script, IScriptOnSecondaryEffect
|
||||
public void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
|
||||
{
|
||||
if (move.User.Volatile.Contains(ScriptUtils.ResolveName<IngrainEffect>()) ||
|
||||
move.User.ActiveAbility?.Name == "levitate")
|
||||
move.User.ActiveAbility?.Name == "levitate" || move.User.Volatile.Contains<MagnetRiseEffect>())
|
||||
{
|
||||
move.GetHitData(target, hit).Fail();
|
||||
return;
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
using PkmnLib.Plugin.Gen7.Scripts.MoveVolatile;
|
||||
using PkmnLib.Plugin.Gen7.Scripts.Utils;
|
||||
using PkmnLib.Static.Moves;
|
||||
|
||||
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||
|
||||
@@ -18,12 +20,16 @@ public class MeFirst : Script, IScriptChangeMove
|
||||
choice.Fail();
|
||||
return;
|
||||
}
|
||||
if (battleData.Battle.ChoiceQueue?.FirstOrDefault(x => x.User == target) is not IMoveChoice targetMove)
|
||||
if (battleData.Battle.ChoiceQueue?.FirstOrDefault(x => x.User == target) is not IMoveChoice
|
||||
{
|
||||
ChosenMove.MoveData.Category: MoveCategory.Physical or MoveCategory.Special,
|
||||
} targetMove)
|
||||
{
|
||||
choice.Fail();
|
||||
return;
|
||||
}
|
||||
if (battleData.Battle.Library.MiscLibrary.IsReplacementChoice(targetMove))
|
||||
if (!targetMove.ChosenMove.MoveData.CanCopyMove() || targetMove.ChosenMove.MoveData.Name == "metal_burst" ||
|
||||
battleData.Battle.Library.MiscLibrary.IsReplacementChoice(targetMove))
|
||||
{
|
||||
choice.Fail();
|
||||
return;
|
||||
|
||||
@@ -5,9 +5,13 @@ namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||
[Script(ScriptCategory.Move, "mean_look")]
|
||||
public class MeanLook : Script, IScriptOnSecondaryEffect
|
||||
{
|
||||
private static StringKey GhostTypeName => new("ghost");
|
||||
|
||||
/// <inheritdoc />
|
||||
public void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
|
||||
{
|
||||
if (target.Types.Any(x => x.Name == GhostTypeName))
|
||||
return;
|
||||
var targetEffect = target.Volatile.Add(new MeanLookEffectTarget());
|
||||
if (targetEffect == null)
|
||||
{
|
||||
|
||||
@@ -3,7 +3,7 @@ using PkmnLib.Static.Moves;
|
||||
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||
|
||||
[Script(ScriptCategory.Move, "metal_burst")]
|
||||
public class MetalBurst : Script, IScriptOnBeforeTurnStart, IScriptChangeMoveDamage
|
||||
public class MetalBurst : Script, IScriptOnBeforeTurnStart, IScriptChangeTargets, IScriptChangeMoveDamage
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public void OnBeforeTurnStart(ITurnChoice choice)
|
||||
@@ -11,19 +11,31 @@ public class MetalBurst : Script, IScriptOnBeforeTurnStart, IScriptChangeMoveDam
|
||||
choice.User.Volatile.Add(new MetalBurstHelper());
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void ChangeTargets(IMoveChoice moveChoice, ref IReadOnlyList<IPokemon?> targets)
|
||||
{
|
||||
var helper = moveChoice.User.Volatile.Get<MetalBurstHelper>();
|
||||
var lastAttacker = helper?.LastAttacker;
|
||||
if (lastAttacker == null)
|
||||
{
|
||||
moveChoice.Fail();
|
||||
return;
|
||||
}
|
||||
targets = [lastAttacker];
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void ChangeMoveDamage(IExecutingMove move, IPokemon target, byte hit, ref uint damage)
|
||||
{
|
||||
var helper = target.Volatile.Get<MetalBurstHelper>();
|
||||
var helper = move.User.Volatile.Get<MetalBurstHelper>();
|
||||
|
||||
if (helper?.LastAttacker == null || helper.LastAttacker != move.User)
|
||||
if (helper?.LastAttacker == null || helper.LastAttacker != target)
|
||||
{
|
||||
move.GetHitData(target, hit).Fail();
|
||||
return;
|
||||
}
|
||||
|
||||
damage = helper.LastDamage.MultiplyOrMax(1.5f);
|
||||
target.Volatile.Remove<MetalBurstHelper>();
|
||||
}
|
||||
|
||||
[Script(ScriptCategory.Pokemon, "metal_burst_helper")]
|
||||
|
||||
@@ -18,13 +18,13 @@ public class Metronome : Script, IScriptChangeMove
|
||||
var retryCount = 0;
|
||||
while (true)
|
||||
{
|
||||
// Breaker for infinite loop. The odds that we'd accidentally roll a non-copyable move 100 times in a row
|
||||
// is extremely unlikely, unless the loaded move library only contains non-copyable moves.
|
||||
// Breaker for infinite loop. The odds that we'd accidentally roll an unselectable move 100 times in a row
|
||||
// is extremely unlikely, unless the loaded move library only contains unselectable moves.
|
||||
// This is a failsafe.
|
||||
if (retryCount > 100)
|
||||
throw new Exception("Metronome failed to find a valid move after 100 attempts.");
|
||||
var randomMove = moveLibrary.GetRandom(battleData.Battle.Random);
|
||||
if (!randomMove.CanCopyMove())
|
||||
if (!randomMove.CanBeSelectedByMetronome())
|
||||
{
|
||||
retryCount++;
|
||||
continue;
|
||||
|
||||
@@ -8,6 +8,12 @@ public class MiracleEye : Script, IScriptOnSecondaryEffect
|
||||
/// <inheritdoc />
|
||||
public void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
|
||||
{
|
||||
if (target.Volatile.Contains<MiracleEyeEffect>())
|
||||
{
|
||||
move.GetHitData(target, hit).Fail();
|
||||
return;
|
||||
}
|
||||
|
||||
if (target.StatBoost.Evasion > 0)
|
||||
{
|
||||
target.ChangeStatBoost(Statistic.Evasion, (sbyte)-target.StatBoost.Evasion, false, false);
|
||||
|
||||
@@ -3,7 +3,7 @@ using PkmnLib.Static.Moves;
|
||||
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||
|
||||
[Script(ScriptCategory.Move, "mirror_coat")]
|
||||
public class MirrorCoat : Script, IScriptOnBeforeTurnStart, IScriptChangeMoveDamage
|
||||
public class MirrorCoat : Script, IScriptOnBeforeTurnStart, IScriptChangeTargets, IScriptChangeMoveDamage
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public void OnBeforeTurnStart(ITurnChoice choice)
|
||||
@@ -11,19 +11,31 @@ public class MirrorCoat : Script, IScriptOnBeforeTurnStart, IScriptChangeMoveDam
|
||||
choice.User.Volatile.Add(new MirrorCoatHelper());
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void ChangeTargets(IMoveChoice moveChoice, ref IReadOnlyList<IPokemon?> targets)
|
||||
{
|
||||
var helper = moveChoice.User.Volatile.Get<MirrorCoatHelper>();
|
||||
var lastAttacker = helper?.LastAttacker;
|
||||
if (lastAttacker == null)
|
||||
{
|
||||
moveChoice.Fail();
|
||||
return;
|
||||
}
|
||||
targets = [lastAttacker];
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void ChangeMoveDamage(IExecutingMove move, IPokemon target, byte hit, ref uint damage)
|
||||
{
|
||||
var helper = target.Volatile.Get<MirrorCoatHelper>();
|
||||
var helper = move.User.Volatile.Get<MirrorCoatHelper>();
|
||||
|
||||
if (helper?.LastAttacker == null || helper.LastAttacker != move.User)
|
||||
if (helper?.LastAttacker == null || helper.LastAttacker != target)
|
||||
{
|
||||
move.GetHitData(target, hit).Fail();
|
||||
return;
|
||||
}
|
||||
|
||||
damage = helper.LastDamage.MultiplyOrMax(2f);
|
||||
target.Volatile.Remove<MirrorCoatHelper>();
|
||||
damage = Math.Max(helper.LastDamage.MultiplyOrMax(2f), 1);
|
||||
}
|
||||
|
||||
[Script(ScriptCategory.Pokemon, "mirror_coat_helper")]
|
||||
|
||||
@@ -16,10 +16,14 @@ public class MirrorMove : Script, IScriptChangeMove
|
||||
if (battle.ChoiceQueue == null)
|
||||
return;
|
||||
var currentTurn = battle.ChoiceQueue.LastRanChoice;
|
||||
var target = battle.GetPokemon(choice.TargetSide, choice.TargetPosition);
|
||||
if (target is null)
|
||||
{
|
||||
choice.Fail();
|
||||
return;
|
||||
}
|
||||
var lastMove = battle.PreviousTurnChoices.SelectMany(x => x).OfType<IMoveChoice>()
|
||||
.TakeWhile(x => !Equals(x, currentTurn)).LastOrDefault(x => x.TargetPosition == choice.TargetPosition &&
|
||||
x.TargetSide == choice.TargetSide &&
|
||||
x.User.BattleData?.IsOnBattlefield == true);
|
||||
.TakeWhile(x => !Equals(x, currentTurn)).LastOrDefault(x => x.User == target);
|
||||
if (lastMove == null || !lastMove.ChosenMove.MoveData.CanCopyMove())
|
||||
{
|
||||
choice.Fail();
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
using PkmnLib.Plugin.Gen7.Scripts.Battle;
|
||||
|
||||
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||
|
||||
[Script(ScriptCategory.Move, "multi_attack")]
|
||||
@@ -6,6 +8,11 @@ public class MultiAttack : Script, IScriptChangeMoveType
|
||||
/// <inheritdoc />
|
||||
public void ChangeMoveType(IExecutingMove move, IPokemon target, byte hit, ref TypeIdentifier? moveType)
|
||||
{
|
||||
if (move.User.ActiveAbility?.Name == "klutz")
|
||||
return;
|
||||
if (move.Battle.Volatile.Contains<MagicRoomEffect>())
|
||||
return;
|
||||
|
||||
var item = move.User.HeldItem?.Name.ToString();
|
||||
var typeLibrary = move.User.Library.StaticLibrary.Types;
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
using PkmnLib.Plugin.Gen7.Scripts.Pokemon;
|
||||
|
||||
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||
|
||||
[Script(ScriptCategory.Move, "trick_or_treat")]
|
||||
@@ -7,8 +9,18 @@ public class TrickOrTreat : Script, IScriptOnSecondaryEffect
|
||||
public void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
|
||||
{
|
||||
var library = move.Battle.Library.StaticLibrary.Types;
|
||||
if (!library.TryGetTypeIdentifier("ghost", out var ghostType))
|
||||
if (!library.TryGetTypeIdentifier("ghost", out var ghostType) || target.Types.Contains(ghostType))
|
||||
{
|
||||
move.GetHitData(target, hit).Fail();
|
||||
return;
|
||||
}
|
||||
if (target.Volatile.TryGet<HasHadTypeAddedEffect>(out var effect))
|
||||
{
|
||||
target.RemoveType(effect.TypeIdentifier);
|
||||
target.Volatile.Remove<HasHadTypeAddedEffect>();
|
||||
}
|
||||
|
||||
target.AddType(ghostType);
|
||||
target.Volatile.Add(new HasHadTypeAddedEffect(ghostType));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user