More moves implemented

This commit is contained in:
2025-02-01 15:00:22 +01:00
parent 3a75493912
commit 00fe08dcd4
50 changed files with 1146 additions and 139 deletions

View File

@@ -115,6 +115,10 @@ public interface IBattle : IScriptSource, IDeepCloneable
/// </summary>
StringKey? WeatherName { get; }
void SetTerrain(StringKey? terrainName);
StringKey? TerrainName { get; }
/// <summary>
/// Gets the turn choices of the previous turn. This is a list of lists, where each list represents the choices
/// for a single turn. The outer list is ordered from oldest to newest turn.
@@ -267,6 +271,8 @@ public class BattleImpl : ScriptSource, IBattle
return false;
var preventMove = false;
choice.RunScriptHook(script => script.PreventMoveSelection(moveChoice, ref preventMove));
if (preventMove)
return false;
}
return true;
@@ -357,6 +363,26 @@ public class BattleImpl : ScriptSource, IBattle
/// <inheritdoc />
public StringKey? WeatherName => _weatherScript.Script?.Name;
private readonly ScriptContainer _terrainScript = new();
/// <inheritdoc />
public void SetTerrain(StringKey? terrainName)
{
if (terrainName.HasValue)
{
if (!Library.ScriptResolver.TryResolve(ScriptCategory.Terrain, terrainName.Value, null, out var script))
throw new InvalidOperationException($"Terrain script {terrainName} not found.");
_terrainScript.Set(script);
}
else
{
_terrainScript.Clear();
}
}
/// <inheritdoc />
public StringKey? TerrainName => _terrainScript.Script?.Name;
private readonly List<IReadOnlyList<ITurnChoice>> _previousTurnChoices = new();
@@ -383,12 +409,13 @@ public class BattleImpl : ScriptSource, IBattle
}
/// <inheritdoc />
public override int ScriptCount => 2;
public override int ScriptCount => 3;
/// <inheritdoc />
public override void GetOwnScripts(List<IEnumerable<ScriptContainer>> scripts)
{
scripts.Add(_weatherScript);
scripts.Add(_terrainScript);
scripts.Add(Volatile);
}

View File

@@ -16,6 +16,7 @@ public class BattleChoiceQueue : IDeepCloneable
{
private readonly ITurnChoice?[] _choices;
private int _currentIndex;
public ITurnChoice? LastRanChoice { get; private set; }
/// <inheritdoc cref="BattleChoiceQueue"/>
public BattleChoiceQueue(ITurnChoice[] choices)
@@ -36,6 +37,7 @@ public class BattleChoiceQueue : IDeepCloneable
var choice = _choices[_currentIndex];
_choices[_currentIndex] = null;
_currentIndex++;
LastRanChoice = choice;
return choice;
}
@@ -99,4 +101,6 @@ public class BattleChoiceQueue : IDeepCloneable
}
internal IReadOnlyList<ITurnChoice?> GetChoices() => _choices;
public ITurnChoice? Where(Func<ITurnChoice, bool> predicate) => _choices.WhereNotNull().FirstOrDefault(predicate);
}

View File

@@ -36,7 +36,8 @@ internal static class MoveTurnExecutor
var targetType = moveData.Target;
var targets = TargetResolver.ResolveTargets(battle, moveChoice.TargetSide, moveChoice.TargetPosition, targetType);
moveChoice.RunScriptHook(x => x.ChangeTargets(moveChoice, ref targets));
byte numberOfHits = 1;
moveChoice.RunScriptHook(x => x.ChangeNumberOfHits(moveChoice, ref numberOfHits));
if (numberOfHits == 0)
@@ -152,8 +153,11 @@ internal static class MoveTurnExecutor
var blockIncomingHit = false;
target.RunScriptHook(x => x.BlockIncomingHit(executingMove, target, hitIndex, ref blockIncomingHit));
executingMove.RunScriptHook(x => x.BlockOutgoingHit(executingMove, target, hitIndex, ref blockIncomingHit));
if (blockIncomingHit)
break;
if (executingMove.GetHitData(target, hitIndex).HasFailed)
break;
if (useMove.Category == MoveCategory.Status)
{
var secondaryEffect = useMove.SecondaryEffect;

View File

@@ -34,6 +34,8 @@ public interface IMoveChoice : ITurnChoice
ScriptContainer Script { get; set; }
Dictionary<StringKey, object?>? AdditionalData { get; }
IScriptSet Volatile { get; }
}
/// <inheritdoc cref="IMoveChoice"/>
@@ -76,10 +78,17 @@ public class MoveChoice : TurnChoice, IMoveChoice
public Dictionary<StringKey, object?>? AdditionalData { get; }
/// <inheritdoc />
public override int ScriptCount => 1 + User.ScriptCount;
public IScriptSet Volatile { get; } = new ScriptSet();
/// <inheritdoc />
public override void GetOwnScripts(List<IEnumerable<ScriptContainer>> scripts) => scripts.Add(Script);
public override int ScriptCount => 2 + User.ScriptCount;
/// <inheritdoc />
public override void GetOwnScripts(List<IEnumerable<ScriptContainer>> scripts)
{
scripts.Add(Volatile);
scripts.Add(Script);
}
/// <inheritdoc />
public override void CollectScripts(List<IEnumerable<ScriptContainer>> scripts)

View File

@@ -121,6 +121,13 @@ public abstract class Script : IDeepCloneable
public virtual void ChangeMove(IMoveChoice choice, ref StringKey moveName)
{
}
/// <summary>
/// Changes the targets of a move choice. This allows for changing the targets of a move before the move starts.
/// </summary>
public virtual void ChangeTargets(IMoveChoice moveChoice, ref IReadOnlyList<IPokemon?> targets)
{
}
/// <summary>
/// This function allows you to change a move into a multi-hit move. The number of hits set here
@@ -260,6 +267,14 @@ public abstract class Script : IDeepCloneable
public virtual void BypassDefensiveStatBoosts(IExecutingMove move, IPokemon target, byte hit, ref bool bypass)
{
}
/// <summary>
/// This function allows a script to bypass evasion stat boosts for a move hit.
/// If this is true, the move will handle the evasion stat boosts as if the target has no positive stat boosts.
/// </summary>
public virtual void BypassEvasionStatBoosts(IExecutingMove move, IPokemon target, byte hitIndex, ref bool bypass)
{
}
/// <summary>
/// This function allows a script to bypass offensive stat boosts for a move hit.
@@ -513,6 +528,21 @@ public abstract class Script : IDeepCloneable
{
}
public virtual void BlockOutgoingHit(IExecutingMove executingMove, IPokemon target, byte hitIndex, ref bool block)
{
}
/// <summary>
/// Custom triggers for scripts. This allows scripts to run custom events that are not part of the
/// standard battle flow.
/// </summary>
/// <param name="eventName">
/// The name of the event that is triggered. This should be unique for each different event. Overriding scripts
/// should validate the event name is one they should handle.
/// </param>
/// <param name="parameters">
/// The parameters that are passed to the event. This can be null if no parameters are passed.
/// </param>
public virtual void CustomTrigger(StringKey eventName, IDictionary<StringKey, object?>? parameters)
{
}

View File

@@ -16,42 +16,49 @@ public enum ScriptCategory
/// <see cref="IMoveChoice"/> and <see cref="IExecutingMove"/>
/// </summary>
Move = 0,
/// <summary>
/// A volatile script effect that is attached to a move choice.
/// </summary>
MoveVolatile = 1,
/// <summary>
/// An ability script. Scripts in this category are always abilities, and therefore always
/// attached to a Pokemon.
/// </summary>
Ability = 1,
Ability = 2,
/// <summary>
/// A non volatile status script. Scripts in this category are always non volatile statuses, and
/// therefore always attached to a Pokemon.
/// </summary>
Status = 2,
Status = 3,
/// <summary>
/// A volatile status script. Scripts in this category are always volatile status effects, and
/// therefore always attached to a Pokemon.
/// </summary>
Pokemon = 3,
Pokemon = 4,
/// <summary>
/// A script that can be attached to an entire side.
/// </summary>
Side = 4,
Side = 5,
/// <summary>
/// A script that can be attached to the entire battle.
/// </summary>
Battle = 5,
Battle = 6,
/// <summary>
/// A special script for weather, for use on battles.
/// </summary>
Weather = 6,
Weather = 7,
Terrain = 8,
/// <summary>
/// A special script for held items. As they're part of a held item, they're attached to a Pokemon.
/// </summary>
ItemBattleTrigger = 7,
ItemBattleTrigger = 9,
}