Implements several more moves
This commit is contained in:
parent
0ad692a921
commit
ecdc9c7654
|
@ -8,10 +8,15 @@ namespace PkmnLib.Dynamic.Events;
|
||||||
/// For example, when a Pokemon gets hurt by poison, we want to show the purple poison animation and the damage at the
|
/// For example, when a Pokemon gets hurt by poison, we want to show the purple poison animation and the damage at the
|
||||||
/// same time. This is done by batching the events together.
|
/// same time. This is done by batching the events together.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public readonly record struct EventBatchId()
|
public readonly record struct EventBatchId
|
||||||
{
|
{
|
||||||
|
public EventBatchId()
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid();
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The unique identifier for this batch of events.
|
/// The unique identifier for this batch of events.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Guid Id { get; init; } = Guid.NewGuid();
|
public Guid Id { get; init; }
|
||||||
}
|
}
|
|
@ -242,6 +242,8 @@ public class BattleImpl : ScriptSource, IBattle
|
||||||
if (!TargetResolver.IsValidTarget(moveChoice.TargetSide, moveChoice.TargetPosition,
|
if (!TargetResolver.IsValidTarget(moveChoice.TargetSide, moveChoice.TargetPosition,
|
||||||
moveChoice.ChosenMove.MoveData.Target, moveChoice.User))
|
moveChoice.ChosenMove.MoveData.Target, moveChoice.User))
|
||||||
return false;
|
return false;
|
||||||
|
var preventMove = false;
|
||||||
|
choice.RunScriptHook(script => script.PreventMoveSelection(moveChoice, ref preventMove));
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -295,7 +295,7 @@ public interface IPokemon : IScriptSource, IDeepCloneable
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Damages the Pokemon by a certain amount of damage, from a damage source.
|
/// Damages the Pokemon by a certain amount of damage, from a damage source.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void Damage(uint damage, DamageSource source, EventBatchId batchId);
|
void Damage(uint damage, DamageSource source, EventBatchId batchId = default);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Heals the Pokemon by a specific amount. Unless allow_revive is set to true, this will not
|
/// Heals the Pokemon by a specific amount. Unless allow_revive is set to true, this will not
|
||||||
|
@ -389,6 +389,16 @@ public interface IPokemonBattleData : IDeepCloneable
|
||||||
/// Adds an opponent to the list of seen opponents.
|
/// Adds an opponent to the list of seen opponents.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void MarkOpponentAsSeen(IPokemon opponent);
|
void MarkOpponentAsSeen(IPokemon opponent);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A list of items the Pokémon has consumed this battle.
|
||||||
|
/// </summary>
|
||||||
|
IReadOnlyList<IItem> ConsumedItems { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Marks an item as consumed.
|
||||||
|
/// </summary>
|
||||||
|
void MarkItemAsConsumed(IItem itemName);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc cref="IPokemon"/>
|
/// <inheritdoc cref="IPokemon"/>
|
||||||
|
@ -1062,4 +1072,15 @@ public class PokemonBattleDataImpl : IPokemonBattleData
|
||||||
{
|
{
|
||||||
_seenOpponents.Add(opponent);
|
_seenOpponents.Add(opponent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private readonly List<IItem> _consumedItems = [];
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public IReadOnlyList<IItem> ConsumedItems => _consumedItems;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void MarkItemAsConsumed(IItem itemName)
|
||||||
|
{
|
||||||
|
_consumedItems.Add(itemName);
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -76,6 +76,13 @@ public abstract class Script : IDeepCloneable
|
||||||
public virtual void OnInitialize(IReadOnlyDictionary<StringKey, object?>? parameters)
|
public virtual void OnInitialize(IReadOnlyDictionary<StringKey, object?>? parameters)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Override to customize whether the move can be selected at all.
|
||||||
|
/// </summary>
|
||||||
|
public virtual void PreventMoveSelection(IMoveChoice choice, ref bool prevent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// This function is ran just before the start of the turn. Everyone has made its choices here,
|
/// This function is ran just before the start of the turn. Everyone has made its choices here,
|
||||||
|
|
|
@ -744,7 +744,10 @@
|
||||||
"category": "physical",
|
"category": "physical",
|
||||||
"flags": [
|
"flags": [
|
||||||
"protect"
|
"protect"
|
||||||
]
|
],
|
||||||
|
"effect": {
|
||||||
|
"name": "beak_blast"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "beat_up",
|
"name": "beat_up",
|
||||||
|
@ -758,7 +761,10 @@
|
||||||
"flags": [
|
"flags": [
|
||||||
"protect",
|
"protect",
|
||||||
"mirror"
|
"mirror"
|
||||||
]
|
],
|
||||||
|
"effect": {
|
||||||
|
"name": "beat_up"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "belch",
|
"name": "belch",
|
||||||
|
@ -771,7 +777,10 @@
|
||||||
"category": "special",
|
"category": "special",
|
||||||
"flags": [
|
"flags": [
|
||||||
"protect"
|
"protect"
|
||||||
]
|
],
|
||||||
|
"effect": {
|
||||||
|
"name": "belch"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "belly_drum",
|
"name": "belly_drum",
|
||||||
|
@ -784,7 +793,10 @@
|
||||||
"category": "status",
|
"category": "status",
|
||||||
"flags": [
|
"flags": [
|
||||||
"snatch"
|
"snatch"
|
||||||
]
|
],
|
||||||
|
"effect": {
|
||||||
|
"name": "belly_drum"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "bestow",
|
"name": "bestow",
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using PkmnLib.Dynamic.Events;
|
||||||
|
using PkmnLib.Dynamic.Models;
|
||||||
|
using PkmnLib.Dynamic.Models.Choices;
|
||||||
|
using PkmnLib.Dynamic.ScriptHandling;
|
||||||
|
using PkmnLib.Dynamic.ScriptHandling.Registry;
|
||||||
|
using PkmnLib.Plugin.Gen7.Scripts.Pokemon;
|
||||||
|
|
||||||
|
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||||
|
|
||||||
|
[Script(ScriptCategory.Move, "beak_blast")]
|
||||||
|
public class BeakBlast : Script
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void OnBeforeTurnStart(ITurnChoice choice)
|
||||||
|
{
|
||||||
|
var battleData = choice.User.BattleData;
|
||||||
|
if (battleData == null)
|
||||||
|
return;
|
||||||
|
choice.User.Volatile.Add(new BeakBlastEffect());
|
||||||
|
battleData.Battle.EventHook.Invoke(new DialogEvent("beak_blast_charge", new Dictionary<string, object>()
|
||||||
|
{
|
||||||
|
{ "user", choice.User }
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
|
||||||
|
{
|
||||||
|
move.User.Volatile.Remove(ScriptUtils.ResolveName<BeakBlastEffect>());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using PkmnLib.Dynamic.Models;
|
||||||
|
using PkmnLib.Dynamic.Models.Choices;
|
||||||
|
using PkmnLib.Dynamic.ScriptHandling;
|
||||||
|
using PkmnLib.Dynamic.ScriptHandling.Registry;
|
||||||
|
using PkmnLib.Static.Utils;
|
||||||
|
|
||||||
|
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||||
|
|
||||||
|
[Script(ScriptCategory.Move, "beat_up")]
|
||||||
|
public class BeatUp : Script
|
||||||
|
{
|
||||||
|
private IPokemon[]? _relevantPartyMembers;
|
||||||
|
private static IEnumerable<IPokemon> GetRelevantPartyMembers(IPokemon user)
|
||||||
|
{
|
||||||
|
var battleData = user.BattleData;
|
||||||
|
if (battleData == null)
|
||||||
|
return [];
|
||||||
|
|
||||||
|
var party = battleData.Battle.Parties.FirstOrDefault(x => x.Party.Contains(user));
|
||||||
|
return party?.Party.WhereNotNull().Where(x => x.IsUsable && x.StatusScript.IsEmpty) ?? [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void ChangeNumberOfHits(IMoveChoice choice, ref byte numberOfHits)
|
||||||
|
{
|
||||||
|
var relevantPartyMembers = _relevantPartyMembers ??= GetRelevantPartyMembers(choice.User).ToArray();
|
||||||
|
|
||||||
|
numberOfHits = (byte)relevantPartyMembers.Count();
|
||||||
|
if (numberOfHits == 0)
|
||||||
|
numberOfHits = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void ChangeBasePower(IExecutingMove move, IPokemon target, byte hit, ref byte basePower)
|
||||||
|
{
|
||||||
|
var relevantPartyMembers = _relevantPartyMembers ??= GetRelevantPartyMembers(move.User).ToArray();
|
||||||
|
var hittingPokemon = relevantPartyMembers.ElementAtOrDefault(hit);
|
||||||
|
if (hittingPokemon == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
basePower = (byte)(hittingPokemon.Form.BaseStats.Attack / 10 + 5);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
using System.Linq;
|
||||||
|
using PkmnLib.Dynamic.Models.Choices;
|
||||||
|
using PkmnLib.Dynamic.ScriptHandling;
|
||||||
|
using PkmnLib.Static;
|
||||||
|
|
||||||
|
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||||
|
|
||||||
|
public class Belch : Script
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void PreventMoveSelection(IMoveChoice choice, ref bool prevent)
|
||||||
|
{
|
||||||
|
var battleData = choice.User.BattleData;
|
||||||
|
if (battleData == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (battleData.ConsumedItems.All(x => x.Category != ItemCategory.Berry))
|
||||||
|
prevent = true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
using PkmnLib.Dynamic.Events;
|
||||||
|
using PkmnLib.Dynamic.Models;
|
||||||
|
using PkmnLib.Dynamic.ScriptHandling;
|
||||||
|
using PkmnLib.Dynamic.ScriptHandling.Registry;
|
||||||
|
using PkmnLib.Static;
|
||||||
|
|
||||||
|
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||||
|
|
||||||
|
[Script(ScriptCategory.Move, "belly_drum")]
|
||||||
|
public class BellyDrum : Script
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
|
||||||
|
{
|
||||||
|
var maxHealthHalved = target.BoostedStats.Hp / 2;
|
||||||
|
if (target.CurrentHealth <= maxHealthHalved)
|
||||||
|
{
|
||||||
|
move.GetHitData(target, hit).Fail();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
target.Damage(maxHealthHalved, DamageSource.Misc);
|
||||||
|
// Raising the user's Attack by 12 stages should always set it to +6.
|
||||||
|
target.ChangeStatBoost(Statistic.Attack, 12, true);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
using PkmnLib.Dynamic.Models;
|
||||||
|
using PkmnLib.Dynamic.ScriptHandling;
|
||||||
|
using PkmnLib.Dynamic.ScriptHandling.Registry;
|
||||||
|
|
||||||
|
namespace PkmnLib.Plugin.Gen7.Scripts.Pokemon;
|
||||||
|
|
||||||
|
[Script(ScriptCategory.Pokemon, "beak_blast_effect")]
|
||||||
|
public class BeakBlastEffect : Script
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void OnIncomingHit(IExecutingMove move, IPokemon target, byte hit)
|
||||||
|
{
|
||||||
|
if (move.UseMove.HasFlag("contact"))
|
||||||
|
{
|
||||||
|
move.User.SetStatus("burned");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,15 +12,7 @@ public abstract class ProtectionEffectScript : Script
|
||||||
if (target.BattleData == null)
|
if (target.BattleData == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var originalTarget = executingMove.MoveChoice.TargetPosition;
|
if (!executingMove.UseMove.HasFlag("protect"))
|
||||||
var targetPosition = target.BattleData.Position;
|
|
||||||
|
|
||||||
// We only want to block the hit if it's explicitly targeting the Pokemon.
|
|
||||||
if (targetPosition != originalTarget)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (executingMove.UseMove.Target is MoveTarget.All or MoveTarget.SelfUse or MoveTarget.AllAlly
|
|
||||||
or MoveTarget.AllAdjacent)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
block = true;
|
block = true;
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
using PkmnLib.Dynamic.ScriptHandling;
|
||||||
|
using PkmnLib.Dynamic.ScriptHandling.Registry;
|
||||||
|
|
||||||
|
namespace PkmnLib.Plugin.Gen7.Scripts.Status;
|
||||||
|
|
||||||
|
[Script(ScriptCategory.Status, "burned")]
|
||||||
|
public class Burned : Script
|
||||||
|
{
|
||||||
|
// TODO: Implement the Burned status effect.
|
||||||
|
}
|
Loading…
Reference in New Issue