More moves implemented
This commit is contained in:
parent
3a75493912
commit
00fe08dcd4
|
@ -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;
|
||||
|
@ -358,6 +364,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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -36,6 +36,7 @@ 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));
|
||||
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -122,6 +122,13 @@ public abstract class Script : IDeepCloneable
|
|||
{
|
||||
}
|
||||
|
||||
/// <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
|
||||
/// gets used as the number of hits. If set to 0, this will behave as if the move missed on its
|
||||
|
@ -261,6 +268,14 @@ public abstract class Script : IDeepCloneable
|
|||
{
|
||||
}
|
||||
|
||||
/// <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.
|
||||
/// If this is true, the damage will be calculated as if the user has no negative offensive stat boosts. Positive
|
||||
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -17,41 +17,48 @@ public enum ScriptCategory
|
|||
/// </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,
|
||||
}
|
|
@ -49,4 +49,11 @@ public static class NumericHelpers
|
|||
var result = value * multiplier;
|
||||
return result > short.MaxValue ? short.MaxValue : (short)result;
|
||||
}
|
||||
|
||||
public static uint MultiplyOrMax(this uint value, uint multiplier)
|
||||
{
|
||||
var result = (ulong)value * multiplier;
|
||||
return result > uint.MaxValue ? uint.MaxValue : (uint)result;
|
||||
}
|
||||
|
||||
}
|
|
@ -1337,7 +1337,11 @@
|
|||
"snatch"
|
||||
],
|
||||
"effect": {
|
||||
"name": "bulk_up"
|
||||
"name": "change_multiple_user_stat_boosts",
|
||||
"parameters": {
|
||||
"attack": 1,
|
||||
"defense": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -1426,7 +1430,11 @@
|
|||
"snatch"
|
||||
],
|
||||
"effect": {
|
||||
"name": "calm_mind"
|
||||
"name": "change_multiple_user_stat_boosts",
|
||||
"parameters": {
|
||||
"specialAttack": 1,
|
||||
"specialDefense": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -1676,9 +1684,10 @@
|
|||
"mirror"
|
||||
],
|
||||
"effect": {
|
||||
"name": "change_user_defense",
|
||||
"name": "change_multiple_user_stat_boosts",
|
||||
"parameters": {
|
||||
"amount": -1
|
||||
"defense": -1,
|
||||
"specialDefense": -1
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -1695,7 +1704,12 @@
|
|||
"snatch"
|
||||
],
|
||||
"effect": {
|
||||
"name": "coil"
|
||||
"name": "change_multiple_user_stat_boosts",
|
||||
"parameters": {
|
||||
"attack": 1,
|
||||
"defense": 1,
|
||||
"accuracy": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -1917,7 +1931,11 @@
|
|||
"snatch"
|
||||
],
|
||||
"effect": {
|
||||
"name": "cosmic_power"
|
||||
"name": "change_multiple_user_stat_boosts",
|
||||
"parameters": {
|
||||
"defense": 1,
|
||||
"specialDefense": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -1973,7 +1991,10 @@
|
|||
"flags": [
|
||||
"contact",
|
||||
"protect"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "counter"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "covet",
|
||||
|
@ -1988,7 +2009,10 @@
|
|||
"contact",
|
||||
"protect",
|
||||
"mirror"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "covet"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "crabhammer",
|
||||
|
@ -2014,7 +2038,10 @@
|
|||
"priority": 3,
|
||||
"target": "AllAlly",
|
||||
"category": "status",
|
||||
"flags": []
|
||||
"flags": [],
|
||||
"effect": {
|
||||
"name": "crafty_shield"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "cross_chop",
|
||||
|
@ -2044,7 +2071,14 @@
|
|||
"contact",
|
||||
"protect",
|
||||
"mirror"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "set_status",
|
||||
"chance": 10,
|
||||
"parameters": {
|
||||
"status": "poisoned"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "crunch",
|
||||
|
@ -2060,7 +2094,14 @@
|
|||
"protect",
|
||||
"mirror",
|
||||
"bite"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "change_target_defense",
|
||||
"chance": 20,
|
||||
"parameters": {
|
||||
"amount": -1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "crush_claw",
|
||||
|
@ -2075,7 +2116,14 @@
|
|||
"contact",
|
||||
"protect",
|
||||
"mirror"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "change_target_defense",
|
||||
"chance": 50,
|
||||
"parameters": {
|
||||
"amount": -1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "crush_grip",
|
||||
|
@ -2090,7 +2138,10 @@
|
|||
"contact",
|
||||
"protect",
|
||||
"mirror"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "crush_grip"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "curse",
|
||||
|
@ -2103,7 +2154,10 @@
|
|||
"category": "status",
|
||||
"flags": [
|
||||
"ignore-substitute"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "curse"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "cut",
|
||||
|
@ -2134,7 +2188,11 @@
|
|||
"mirror",
|
||||
"distance",
|
||||
"pulse"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "flinch",
|
||||
"chance": 20
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "dark_void",
|
||||
|
@ -2149,7 +2207,13 @@
|
|||
"protect",
|
||||
"reflectable",
|
||||
"mirror"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "set_status",
|
||||
"parameters": {
|
||||
"status": "sleep"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "darkest_lariat",
|
||||
|
@ -2164,7 +2228,10 @@
|
|||
"contact",
|
||||
"protect",
|
||||
"mirror"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "darkest_lariat"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "dazzling_gleam",
|
||||
|
@ -2191,7 +2258,14 @@
|
|||
"category": "status",
|
||||
"flags": [
|
||||
"snatch"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "change_multiple_user_stat_boosts",
|
||||
"parameters": {
|
||||
"defense": 1,
|
||||
"specialDefense": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "defense_curl",
|
||||
|
@ -2204,7 +2278,13 @@
|
|||
"category": "status",
|
||||
"flags": [
|
||||
"snatch"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "change_user_defense",
|
||||
"parameters": {
|
||||
"amount": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "defog",
|
||||
|
@ -2220,7 +2300,10 @@
|
|||
"reflectable",
|
||||
"mirror",
|
||||
"ignore-substitute"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "defog"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "destiny_bond",
|
||||
|
@ -2233,7 +2316,10 @@
|
|||
"category": "status",
|
||||
"flags": [
|
||||
"ignore-substitute"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "destiny_bond"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "detect",
|
||||
|
@ -2244,7 +2330,10 @@
|
|||
"priority": 4,
|
||||
"target": "Self",
|
||||
"category": "status",
|
||||
"flags": []
|
||||
"flags": [],
|
||||
"effect": {
|
||||
"name": "protect"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "devastating_drake__physical",
|
||||
|
@ -2280,7 +2369,14 @@
|
|||
"flags": [
|
||||
"protect",
|
||||
"mirror"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "raise_user_defense",
|
||||
"chance": 50,
|
||||
"parameters": {
|
||||
"amount": 2
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "dig",
|
||||
|
@ -2297,7 +2393,10 @@
|
|||
"protect",
|
||||
"mirror",
|
||||
"nonskybattle"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "dig"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "disable",
|
||||
|
@ -2344,7 +2443,14 @@
|
|||
"flags": [
|
||||
"protect",
|
||||
"mirror"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "set_status",
|
||||
"chance": 30,
|
||||
"parameters": {
|
||||
"status": "paralyzed"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "dive",
|
||||
|
@ -2361,7 +2467,10 @@
|
|||
"protect",
|
||||
"mirror",
|
||||
"nonskybattle"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "dive"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "dizzy_punch",
|
||||
|
@ -2377,7 +2486,11 @@
|
|||
"protect",
|
||||
"mirror",
|
||||
"punch"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "confuse",
|
||||
"chance": 20
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "doom_desire",
|
||||
|
@ -2388,7 +2501,10 @@
|
|||
"priority": 0,
|
||||
"target": "Any",
|
||||
"category": "special",
|
||||
"flags": []
|
||||
"flags": [],
|
||||
"effect": {
|
||||
"name": "doom_desire"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "double_edge",
|
||||
|
@ -2403,7 +2519,13 @@
|
|||
"contact",
|
||||
"protect",
|
||||
"mirror"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "recoil",
|
||||
"parameters": {
|
||||
"amount": 33.333
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "double_hit",
|
||||
|
@ -2418,7 +2540,10 @@
|
|||
"contact",
|
||||
"protect",
|
||||
"mirror"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "2_hit_move"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "double_kick",
|
||||
|
@ -2433,7 +2558,10 @@
|
|||
"contact",
|
||||
"protect",
|
||||
"mirror"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "2_hit_move"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "double_slap",
|
||||
|
@ -2448,7 +2576,10 @@
|
|||
"contact",
|
||||
"protect",
|
||||
"mirror"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "2_5_hit_move"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "double_team",
|
||||
|
@ -2461,7 +2592,13 @@
|
|||
"category": "status",
|
||||
"flags": [
|
||||
"snatch"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "change_user_evasion",
|
||||
"parameters": {
|
||||
"amount": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "draco_meteor",
|
||||
|
@ -2475,7 +2612,13 @@
|
|||
"flags": [
|
||||
"protect",
|
||||
"mirror"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "change_user_special_attack",
|
||||
"parameters": {
|
||||
"amount": -2
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "dragon_ascent",
|
||||
|
@ -2491,7 +2634,14 @@
|
|||
"protect",
|
||||
"mirror",
|
||||
"distance"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "change_multiple_user_stat_boosts",
|
||||
"parameters": {
|
||||
"defense": 1,
|
||||
"specialDefense": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "dragon_breath",
|
||||
|
@ -2505,7 +2655,14 @@
|
|||
"flags": [
|
||||
"protect",
|
||||
"mirror"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "set_status",
|
||||
"chance": 30,
|
||||
"parameters": {
|
||||
"status": "paralyzed"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "dragon_claw",
|
||||
|
@ -2534,7 +2691,14 @@
|
|||
"flags": [
|
||||
"snatch",
|
||||
"dance"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "change_multiple_user_stat_boosts",
|
||||
"parameters": {
|
||||
"attack": 1,
|
||||
"speed": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "dragon_hammer",
|
||||
|
@ -2579,7 +2743,10 @@
|
|||
"flags": [
|
||||
"protect",
|
||||
"mirror"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "dragon_rage"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "dragon_rush",
|
||||
|
@ -2594,7 +2761,11 @@
|
|||
"contact",
|
||||
"protect",
|
||||
"mirror"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "flinch",
|
||||
"chance": 20
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "dragon_tail",
|
||||
|
@ -2609,7 +2780,10 @@
|
|||
"contact",
|
||||
"protect",
|
||||
"mirror"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "circle_throw"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "drain_punch",
|
||||
|
@ -2626,7 +2800,13 @@
|
|||
"mirror",
|
||||
"punch",
|
||||
"heal"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "drain",
|
||||
"parameters": {
|
||||
"drain_modifier": 0.5
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "draining_kiss",
|
||||
|
@ -2642,7 +2822,13 @@
|
|||
"protect",
|
||||
"mirror",
|
||||
"heal"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "drain",
|
||||
"parameters": {
|
||||
"drain_modifier": 0.75
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "dream_eater",
|
||||
|
@ -2657,7 +2843,10 @@
|
|||
"protect",
|
||||
"mirror",
|
||||
"heal"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "dream_eater"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "drill_peck",
|
||||
|
@ -2703,7 +2892,10 @@
|
|||
"contact",
|
||||
"protect",
|
||||
"mirror"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "2_hit_move"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "dynamic_punch",
|
||||
|
@ -2719,7 +2911,10 @@
|
|||
"protect",
|
||||
"mirror",
|
||||
"punch"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "confuse"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "earth_power",
|
||||
|
@ -2734,7 +2929,14 @@
|
|||
"protect",
|
||||
"mirror",
|
||||
"nonskybattle"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "change_target_special_defense",
|
||||
"chance": 10,
|
||||
"parameters": {
|
||||
"amount": -1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "earthquake",
|
||||
|
@ -2748,7 +2950,9 @@
|
|||
"flags": [
|
||||
"protect",
|
||||
"mirror",
|
||||
"nonskybattle"
|
||||
"nonskybattle",
|
||||
"hit_underground",
|
||||
"effective_against_underground"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -2765,7 +2969,10 @@
|
|||
"mirror",
|
||||
"sound",
|
||||
"ignore-substitute"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "echoed_voice"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "eerie_impulse",
|
||||
|
@ -2780,7 +2987,13 @@
|
|||
"protect",
|
||||
"reflectable",
|
||||
"mirror"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "change_target_special_attack",
|
||||
"parameters": {
|
||||
"amount": -2
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "egg_bomb",
|
||||
|
@ -2808,7 +3021,10 @@
|
|||
"category": "status",
|
||||
"flags": [
|
||||
"nonskybattle"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "electric_terrain"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "electrify",
|
||||
|
@ -2822,7 +3038,10 @@
|
|||
"flags": [
|
||||
"protect",
|
||||
"mirror"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "electrify"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "electro_ball",
|
||||
|
@ -2837,7 +3056,10 @@
|
|||
"protect",
|
||||
"mirror",
|
||||
"ballistics"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "electro_ball"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "electroweb",
|
||||
|
@ -2851,7 +3073,13 @@
|
|||
"flags": [
|
||||
"protect",
|
||||
"mirror"
|
||||
]
|
||||
],
|
||||
"effect": {
|
||||
"name": "change_target_speed",
|
||||
"parameters": {
|
||||
"amount": -1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "embargo",
|
||||
|
|
|
@ -55,6 +55,10 @@ public class Gen7BattleStatCalculator : IBattleStatCalculator
|
|||
executingMove.RunScriptHook(x => x.ChangeAccuracyModifier(executingMove, target, hitIndex, ref accuracyModifier));
|
||||
var modifiedAccuracy = (int)(moveAccuracy * accuracyModifier);
|
||||
var targetEvasion = target.StatBoost.Evasion;
|
||||
var ignoreEvasion = false;
|
||||
executingMove.RunScriptHook(x => x.BypassEvasionStatBoosts(executingMove, target, hitIndex, ref ignoreEvasion));
|
||||
if (ignoreEvasion)
|
||||
targetEvasion = 0;
|
||||
var userAccuracy = executingMove.User.StatBoost.Accuracy;
|
||||
var difference = targetEvasion - userAccuracy;
|
||||
var statModifier = difference switch
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
using PkmnLib.Static;
|
||||
|
||||
namespace PkmnLib.Plugin.Gen7.Scripts.MoveVolatile;
|
||||
|
||||
[Script(ScriptCategory.MoveVolatile, "electrify")]
|
||||
public class ElectrifyEffect : Script {
|
||||
/// <inheritdoc />
|
||||
public override void ChangeMoveType(IExecutingMove move, IPokemon target, byte hit, ref TypeIdentifier moveType)
|
||||
{
|
||||
var battleData = target.BattleData;
|
||||
if (battleData == null)
|
||||
return;
|
||||
if (!battleData.Battle.Library.StaticLibrary.Types.TryGetTypeIdentifier("electric", out var electricType))
|
||||
return;
|
||||
moveType = electricType;
|
||||
}
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
using PkmnLib.Static;
|
||||
|
||||
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||
|
||||
[Script(ScriptCategory.Move, "bulk_up")]
|
||||
public class BulkUp : Script
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
|
||||
{
|
||||
EventBatchId eventBatchId = new();
|
||||
move.User.ChangeStatBoost(Statistic.Attack, 1, true, eventBatchId);
|
||||
move.User.ChangeStatBoost(Statistic.Defense, 1, true, eventBatchId);
|
||||
}
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
using PkmnLib.Static;
|
||||
|
||||
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||
|
||||
[Script(ScriptCategory.Move, "calm_mind")]
|
||||
public class CalmMind : Script
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
|
||||
{
|
||||
EventBatchId eventBatchId = new();
|
||||
move.User.ChangeStatBoost(Statistic.SpecialAttack, 1, true, eventBatchId);
|
||||
move.User.ChangeStatBoost(Statistic.SpecialDefense, 1, true, eventBatchId);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using PkmnLib.Static;
|
||||
using PkmnLib.Static.Utils;
|
||||
|
||||
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||
|
||||
[Script(ScriptCategory.Move, "change_multiple_user_stat_boosts")]
|
||||
public class ChangeMultipleUserStatBoosts : Script
|
||||
{
|
||||
private Dictionary<Statistic, sbyte> _statBoosts = new();
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnInitialize(IReadOnlyDictionary<StringKey, object?>? parameters)
|
||||
{
|
||||
if (parameters == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(parameters));
|
||||
}
|
||||
|
||||
foreach (var par in parameters)
|
||||
{
|
||||
if (!Enum.TryParse<Statistic>(par.Key, true, out var stat))
|
||||
continue;
|
||||
if (par.Value is sbyte value)
|
||||
{
|
||||
_statBoosts[stat] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
|
||||
{
|
||||
EventBatchId batchId = new();
|
||||
foreach (var stat in _statBoosts!)
|
||||
{
|
||||
move.User.ChangeStatBoost(stat.Key, stat.Value, true, batchId);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -77,3 +77,19 @@ public class ChangeUserSpeed : ChangeUserStats
|
|||
{
|
||||
}
|
||||
}
|
||||
|
||||
[Script(ScriptCategory.Move, "change_user_accuracy")]
|
||||
public class ChangeUserAccuracy : ChangeUserStats
|
||||
{
|
||||
public ChangeUserAccuracy() : base(Statistic.Accuracy)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[Script(ScriptCategory.Move, "change_user_evasion")]
|
||||
public class ChangeUserEvasion : ChangeUserStats
|
||||
{
|
||||
public ChangeUserEvasion() : base(Statistic.Evasion)
|
||||
{
|
||||
}
|
||||
}
|
|
@ -4,10 +4,10 @@ namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
|||
public class ChipAway : Script
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override void BypassDefensiveStatBoosts(IExecutingMove move, IPokemon target, byte hit, ref bool bypass)
|
||||
{
|
||||
public override void BypassDefensiveStatBoosts(IExecutingMove move, IPokemon target, byte hit, ref bool bypass) =>
|
||||
bypass = true;
|
||||
}
|
||||
|
||||
// TODO: bypass evasion stat.
|
||||
/// <inheritdoc />
|
||||
public override void BypassEvasionStatBoosts(IExecutingMove move, IPokemon target, byte hitIndex, ref bool bypass)
|
||||
=> bypass = true;
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
using PkmnLib.Static;
|
||||
|
||||
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||
|
||||
[Script(ScriptCategory.Move, "coil")]
|
||||
public class Coil : Script
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
|
||||
{
|
||||
EventBatchId eventBatchId = new();
|
||||
move.User.ChangeStatBoost(Statistic.Attack, 1, true, eventBatchId);
|
||||
move.User.ChangeStatBoost(Statistic.Defense, 1, true, eventBatchId);
|
||||
move.User.ChangeStatBoost(Statistic.Accuracy, 1, true, eventBatchId);
|
||||
}
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
using PkmnLib.Static;
|
||||
|
||||
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||
|
||||
[Script(ScriptCategory.Move, "cosmic_power")]
|
||||
public class CosmicPower : Script
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
|
||||
{
|
||||
EventBatchId eventBatchId = new();
|
||||
move.User.ChangeStatBoost(Statistic.Defense, 1, true, eventBatchId);
|
||||
move.User.ChangeStatBoost(Statistic.SpecialDefense, 1, true, eventBatchId);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
using System.Collections.Generic;
|
||||
using PkmnLib.Plugin.Gen7.Scripts.Pokemon;
|
||||
using PkmnLib.Static.Utils;
|
||||
|
||||
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||
|
||||
[Script(ScriptCategory.Move, "counter")]
|
||||
public class Counter : Script
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override void OnBeforeTurnStart(ITurnChoice choice)
|
||||
{
|
||||
choice.User.Volatile.Add(new CounterHelperEffect());
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void ChangeTargets(IMoveChoice moveChoice, ref IReadOnlyList<IPokemon?> targets)
|
||||
{
|
||||
var counterHelper = moveChoice.User.Volatile.Get<CounterHelperEffect>();
|
||||
var lastHitBy = counterHelper?.LastHitBy;
|
||||
if (lastHitBy == null)
|
||||
{
|
||||
moveChoice.Fail();
|
||||
return;
|
||||
}
|
||||
targets = [lastHitBy];
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void ChangeDamage(IExecutingMove move, IPokemon target, byte hit, ref uint damage)
|
||||
{
|
||||
var counterHelper = move.User.Volatile.Get<CounterHelperEffect>();
|
||||
if (counterHelper == null || counterHelper.LastHitBy == null || counterHelper.LastHitBy != target)
|
||||
{
|
||||
move.GetHitData(target, hit).Fail();
|
||||
return;
|
||||
}
|
||||
var lastDamage = counterHelper.LastDamage;
|
||||
damage = lastDamage.MultiplyOrMax(2);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||
|
||||
[Script(ScriptCategory.Move, "covet")]
|
||||
public class Covet : Script
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
|
||||
{
|
||||
if (target.HeldItem == null)
|
||||
return;
|
||||
if (move.User.HeldItem != null)
|
||||
return;
|
||||
_ = move.User.SetHeldItem(target.RemoveHeldItem());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
using PkmnLib.Plugin.Gen7.Scripts.Side;
|
||||
|
||||
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||
|
||||
[Script(ScriptCategory.Move, "crafty_shield")]
|
||||
public class CraftyShield : Script
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
|
||||
{
|
||||
var battleData = move.User.BattleData;
|
||||
if (battleData == null)
|
||||
return;
|
||||
var side = battleData.Battle.Sides[battleData.SideIndex];
|
||||
side.VolatileScripts.Add(new CraftyShieldEffect());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
using System;
|
||||
|
||||
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||
|
||||
[Script(ScriptCategory.Move, "crush_grip")]
|
||||
public class CrushGrip : Script
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override void ChangeBasePower(IExecutingMove move, IPokemon target, byte hit, ref byte basePower)
|
||||
{
|
||||
basePower = Math.Max((byte)(120 * target.CurrentHealth / target.BoostedStats.Hp), (byte)1);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
using System.Linq;
|
||||
using PkmnLib.Plugin.Gen7.Scripts.Pokemon;
|
||||
using PkmnLib.Static;
|
||||
|
||||
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||
|
||||
[Script(ScriptCategory.Move, "curse")]
|
||||
public class Curse : Script
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
|
||||
{
|
||||
var battleData = move.User.BattleData;
|
||||
if (battleData == null)
|
||||
return;
|
||||
var typeLibrary = battleData.Battle.Library.StaticLibrary.Types;
|
||||
if (!typeLibrary.TryGetTypeIdentifier("ghost", out var ghostType))
|
||||
return;
|
||||
if (move.User.Types.Contains(ghostType))
|
||||
{
|
||||
move.User.Damage(move.User.CurrentHealth / 2, DamageSource.Misc);
|
||||
if (move.User.CurrentHealth == 0)
|
||||
return;
|
||||
target.Volatile.Add(new GhostCurseEffect(target));
|
||||
}
|
||||
else
|
||||
{
|
||||
EventBatchId batchId = new();
|
||||
move.User.ChangeStatBoost(Statistic.Speed, -1, true, batchId);
|
||||
move.User.ChangeStatBoost(Statistic.Defense, 1, true, batchId);
|
||||
move.User.ChangeStatBoost(Statistic.Attack, 1, true, batchId);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||
|
||||
[Script(ScriptCategory.Move, "darkest_lariat")]
|
||||
public class DarkestLariat : Script
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override void BypassDefensiveStatBoosts(IExecutingMove move, IPokemon target, byte hit, ref bool bypass) =>
|
||||
bypass = true;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void
|
||||
BypassEvasionStatBoosts(IExecutingMove move, IPokemon target, byte hitIndex, ref bool bypass) => bypass = true;
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
using System.Collections.Generic;
|
||||
using PkmnLib.Static.Utils;
|
||||
|
||||
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||
|
||||
[Script(ScriptCategory.Move, "defog")]
|
||||
public class Defog : Script
|
||||
{
|
||||
public static HashSet<StringKey> DefoggedEffects = new()
|
||||
{
|
||||
"mist",
|
||||
"light_screen",
|
||||
"reflect",
|
||||
"safe_guard",
|
||||
"spikes",
|
||||
"toxic_spikes",
|
||||
"stealth_rock",
|
||||
};
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
|
||||
{
|
||||
if (target.BattleData == null)
|
||||
return;
|
||||
|
||||
var targetSide = target.BattleData.Battle.Sides[target.BattleData.SideIndex];
|
||||
foreach (var effect in DefoggedEffects)
|
||||
{
|
||||
targetSide.VolatileScripts.Remove(effect);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
using PkmnLib.Plugin.Gen7.Scripts.Pokemon;
|
||||
|
||||
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||
|
||||
[Script(ScriptCategory.Move, "destiny_bond")]
|
||||
public class DestinyBond : Script
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
|
||||
{
|
||||
move.User.Volatile.Add(new DestinyBondEffect());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
using System.Collections.Generic;
|
||||
using PkmnLib.Plugin.Gen7.Scripts.Pokemon;
|
||||
|
||||
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||
|
||||
[Script(ScriptCategory.Move, "dig")]
|
||||
public class Dig : Script
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override void PreventMove(IExecutingMove move, ref bool prevent)
|
||||
{
|
||||
if (move.User.Volatile.Contains<DigEffect>())
|
||||
return;
|
||||
|
||||
move.User.Volatile.Add(new DigEffect(move.User));
|
||||
move.User.BattleData?.Battle.EventHook.Invoke(new DialogEvent("dig_charge", new Dictionary<string, object>()
|
||||
{
|
||||
{ "user", move.User }
|
||||
}));
|
||||
prevent = true;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
|
||||
{
|
||||
move.User.Volatile.Remove(ScriptUtils.ResolveName<DigEffect>());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
using System.Linq;
|
||||
using PkmnLib.Plugin.Gen7.Scripts.Pokemon;
|
||||
|
||||
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||
|
||||
[Script(ScriptCategory.Move, "disable")]
|
||||
public class Disable : Script
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
|
||||
{
|
||||
var battleData = move.User.BattleData;
|
||||
if (battleData == null)
|
||||
return;
|
||||
var choiceQueue = battleData.Battle.PreviousTurnChoices;
|
||||
var lastMove = choiceQueue
|
||||
.SelectMany(x => x)
|
||||
.OfType<IMoveChoice>()
|
||||
.LastOrDefault(x => x.User == target);
|
||||
if (lastMove == null)
|
||||
{
|
||||
move.GetHitData(target, hit).Fail();
|
||||
return;
|
||||
}
|
||||
var lastMoveName = lastMove.ChosenMove.MoveData.Name;
|
||||
target.Volatile.Add(new DisableEffect(lastMoveName));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
using System.Collections.Generic;
|
||||
using PkmnLib.Plugin.Gen7.Scripts.Pokemon;
|
||||
|
||||
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||
|
||||
[Script(ScriptCategory.Move, "dive")]
|
||||
public class Dive : Script
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override void PreventMove(IExecutingMove move, ref bool prevent)
|
||||
{
|
||||
if (move.User.Volatile.Contains<DiveEffect>())
|
||||
return;
|
||||
|
||||
move.User.Volatile.Add(new DigEffect(move.User));
|
||||
move.User.BattleData?.Battle.EventHook.Invoke(new DialogEvent("dive_charge", new Dictionary<string, object>()
|
||||
{
|
||||
{ "user", move.User }
|
||||
}));
|
||||
prevent = true;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
|
||||
{
|
||||
move.User.Volatile.Remove(ScriptUtils.ResolveName<DiveEffect>());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
using System.Linq;
|
||||
using PkmnLib.Plugin.Gen7.Scripts.Side;
|
||||
|
||||
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||
|
||||
[Script(ScriptCategory.Move, "doom_desire")]
|
||||
public class DoomDesire : Script
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override void BlockOutgoingHit(IExecutingMove executingMove, IPokemon target, byte hitIndex, ref bool block)
|
||||
{
|
||||
var battleData = target.BattleData;
|
||||
if (battleData == null)
|
||||
return;
|
||||
var side = battleData.Battle.Sides[battleData.SideIndex];
|
||||
var effect = side.VolatileScripts.Get<DoomDesireEffect>();
|
||||
if (effect != null && effect.HasTarget(battleData.Position))
|
||||
{
|
||||
executingMove.GetHitData(target, hitIndex).Fail();
|
||||
return;
|
||||
}
|
||||
|
||||
if (effect == null)
|
||||
{
|
||||
effect = new DoomDesireEffect(side);
|
||||
side.VolatileScripts.Add(effect);
|
||||
}
|
||||
effect.AddTarget(battleData.Position, executingMove.GetHitData(target, hitIndex).Damage);
|
||||
block = true;
|
||||
}
|
||||
}
|
|
@ -2,14 +2,14 @@ using PkmnLib.Static;
|
|||
|
||||
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||
|
||||
[Script(ScriptCategory.Move, "close_combat")]
|
||||
public class CloseCombat : Script
|
||||
[Script(ScriptCategory.Move, "dragon_ascent")]
|
||||
public class DragonAscent : Script
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
|
||||
{
|
||||
EventBatchId eventBatchId = new();
|
||||
move.User.ChangeStatBoost(Statistic.Defense, -1, true, eventBatchId);
|
||||
move.User.ChangeStatBoost(Statistic.SpecialDefense, -1, true, eventBatchId);
|
||||
EventBatchId batchId = new();
|
||||
move.User.ChangeStatBoost(Statistic.Defense, -1, true, batchId);
|
||||
move.User.ChangeStatBoost(Statistic.SpecialDefense, -1, true, batchId);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||
|
||||
[Script(ScriptCategory.Move, "dragon_rage")]
|
||||
public class DragonRage : Script
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override void ChangeDamage(IExecutingMove move, IPokemon target, byte hit, ref uint damage)
|
||||
{
|
||||
damage = 40;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||
|
||||
[Script(ScriptCategory.Move, "dream_eater")]
|
||||
public class DreamEater : Script
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override void BlockOutgoingHit(IExecutingMove executingMove, IPokemon target, byte hitIndex, ref bool block)
|
||||
{
|
||||
if (!target.HasStatus("asleep"))
|
||||
block = true;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
|
||||
{
|
||||
var user = move.User;
|
||||
var damage = move.GetHitData(target, hit).Damage;
|
||||
var healed = (uint)(damage * 0.5f);
|
||||
if (move.User.HasHeldItem("big_root"))
|
||||
healed = (uint)(healed * 1.3f);
|
||||
user.Heal(healed, false);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
using PkmnLib.Plugin.Gen7.Scripts.Side;
|
||||
|
||||
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||
|
||||
[Script(ScriptCategory.Move, "echoed_voice")]
|
||||
public class EchoedVoice : Script
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override void ChangeDamageModifier(IExecutingMove move, IPokemon target, byte hit, ref float modifier)
|
||||
{
|
||||
var battleData = move.User.BattleData;
|
||||
if (battleData == null)
|
||||
return;
|
||||
var side = battleData.Battle.Sides[battleData.SideIndex];
|
||||
var echoedVoiceData = side.VolatileScripts.Get<EchoedVoiceData>();
|
||||
if (echoedVoiceData == null)
|
||||
return;
|
||||
|
||||
modifier *= 2;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
|
||||
{
|
||||
var battleData = move.User.BattleData;
|
||||
if (battleData == null)
|
||||
return;
|
||||
var side = battleData.Battle.Sides[battleData.SideIndex];
|
||||
side.VolatileScripts.Add(new EchoedVoiceData());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||
|
||||
[Script(ScriptCategory.Move, "electric_terrain")]
|
||||
public class ElectricTerrain : Script
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
|
||||
{
|
||||
var battleData = move.User.BattleData;
|
||||
battleData?.Battle.SetTerrain(ScriptUtils.ResolveName<ElectricTerrain>());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
using PkmnLib.Plugin.Gen7.Scripts.MoveVolatile;
|
||||
|
||||
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||
|
||||
[Script(ScriptCategory.Move, "electrify")]
|
||||
public class Electrify : Script
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
|
||||
{
|
||||
var choiceQueue = target.BattleData?.Battle.ChoiceQueue;
|
||||
if (choiceQueue == null)
|
||||
return;
|
||||
|
||||
if (choiceQueue.Where(x => x is IMoveChoice moveChoice && moveChoice.User == target) is not IMoveChoice choice)
|
||||
{
|
||||
move.GetHitData(target, hit).Fail();
|
||||
return;
|
||||
}
|
||||
|
||||
choice.Volatile.Add(new ElectrifyEffect());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||
|
||||
[Script(ScriptCategory.Move, "electro_ball")]
|
||||
public class ElectroBall : Script
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override void ChangeBasePower(IExecutingMove move, IPokemon target, byte hit, ref byte basePower)
|
||||
{
|
||||
var user = move.User;
|
||||
var targetSpeed = target.BoostedStats.Speed;
|
||||
var userSpeed = user.BoostedStats.Speed;
|
||||
|
||||
var ratio = (float) userSpeed / targetSpeed;
|
||||
basePower = ratio switch
|
||||
{
|
||||
> 4 => 150,
|
||||
> 3 => 120,
|
||||
> 2 => 80,
|
||||
> 1 => 60,
|
||||
_ => 40
|
||||
};
|
||||
}
|
||||
}
|
|
@ -3,9 +3,10 @@ using PkmnLib.Plugin.Gen7.Scripts.Pokemon;
|
|||
|
||||
namespace PkmnLib.Plugin.Gen7.Scripts.Moves;
|
||||
|
||||
public abstract class ProtectionScript : Script
|
||||
[Script(ScriptCategory.Move, "protect")]
|
||||
public class ProtectionScript : Script
|
||||
{
|
||||
protected abstract ProtectionEffectScript GetEffectScript();
|
||||
protected virtual ProtectionEffectScript GetEffectScript() => new();
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
using PkmnLib.Static.Moves;
|
||||
|
||||
namespace PkmnLib.Plugin.Gen7.Scripts.Pokemon;
|
||||
|
||||
[Script(ScriptCategory.Pokemon, "counterhelper")]
|
||||
public class CounterHelperEffect : Script
|
||||
{
|
||||
public IPokemon? LastHitBy { get; private set; }
|
||||
public uint LastDamage { get; private set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnIncomingHit(IExecutingMove move, IPokemon target, byte hit)
|
||||
{
|
||||
if (move.UseMove.Category == MoveCategory.Physical)
|
||||
{
|
||||
LastHitBy = move.User;
|
||||
LastDamage = move.GetHitData(target, hit).Damage;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
namespace PkmnLib.Plugin.Gen7.Scripts.Pokemon;
|
||||
|
||||
[Script(ScriptCategory.Pokemon, "destiny_bond")]
|
||||
public class DestinyBondEffect : Script
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override void OnFaint(IPokemon pokemon, DamageSource source)
|
||||
{
|
||||
if (source == DamageSource.MoveDamage)
|
||||
{
|
||||
if (pokemon.BattleData?.Battle.ChoiceQueue?.LastRanChoice is not IMoveChoice lastChoice)
|
||||
return;
|
||||
lastChoice.User.Damage(lastChoice.User.BoostedStats.Hp * 10, DamageSource.Misc);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnBeforeMove(IExecutingMove move)
|
||||
{
|
||||
RemoveSelf();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
using PkmnLib.Plugin.Gen7.Scripts.Utils;
|
||||
|
||||
namespace PkmnLib.Plugin.Gen7.Scripts.Pokemon;
|
||||
|
||||
[Script(ScriptCategory.Pokemon, "dig")]
|
||||
public class DigEffect : Script
|
||||
{
|
||||
private readonly IPokemon _owner;
|
||||
|
||||
public DigEffect(IPokemon owner)
|
||||
{
|
||||
_owner = owner;
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public override void ForceTurnSelection(byte sideIndex, byte position, ref ITurnChoice? choice)
|
||||
{
|
||||
var opposingSideIndex = (byte)(_owner.BattleData?.SideIndex == 0 ? 1 : 0);
|
||||
choice = TurnChoiceHelper.CreateMoveChoice(_owner, "dig", opposingSideIndex, position);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void BlockIncomingHit(IExecutingMove executingMove, IPokemon target, byte hitIndex, ref bool block)
|
||||
{
|
||||
if (!executingMove.UseMove.HasFlag("hit_underground"))
|
||||
block = true;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void ChangeIncomingDamage(IExecutingMove move, IPokemon target, byte hit, ref uint damage)
|
||||
{
|
||||
if (!move.UseMove.HasFlag("effective_against_underground"))
|
||||
damage *= 2;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
using PkmnLib.Static.Utils;
|
||||
|
||||
namespace PkmnLib.Plugin.Gen7.Scripts.Pokemon;
|
||||
|
||||
[Script(ScriptCategory.Pokemon, "disable")]
|
||||
public class DisableEffect : Script
|
||||
{
|
||||
private readonly StringKey _move;
|
||||
|
||||
public DisableEffect(StringKey move)
|
||||
{
|
||||
_move = move;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void PreventMoveSelection(IMoveChoice choice, ref bool prevent)
|
||||
{
|
||||
if (choice.ChosenMove.MoveData.Name == _move)
|
||||
prevent = true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
using PkmnLib.Plugin.Gen7.Scripts.Utils;
|
||||
|
||||
namespace PkmnLib.Plugin.Gen7.Scripts.Pokemon;
|
||||
|
||||
[Script(ScriptCategory.Pokemon, "dive")]
|
||||
public class DiveEffect : Script
|
||||
{
|
||||
private readonly IPokemon _owner;
|
||||
|
||||
public DiveEffect(IPokemon owner)
|
||||
{
|
||||
_owner = owner;
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public override void ForceTurnSelection(byte sideIndex, byte position, ref ITurnChoice? choice)
|
||||
{
|
||||
var opposingSideIndex = (byte)(_owner.BattleData?.SideIndex == 0 ? 1 : 0);
|
||||
choice = TurnChoiceHelper.CreateMoveChoice(_owner, "dive", opposingSideIndex, position);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void BlockIncomingHit(IExecutingMove executingMove, IPokemon target, byte hitIndex, ref bool block)
|
||||
{
|
||||
if (!executingMove.UseMove.HasFlag("hit_underwater"))
|
||||
block = true;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void ChangeIncomingDamage(IExecutingMove move, IPokemon target, byte hit, ref uint damage)
|
||||
{
|
||||
if (!move.UseMove.HasFlag("effective_against_underwater"))
|
||||
damage *= 2;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
namespace PkmnLib.Plugin.Gen7.Scripts.Pokemon;
|
||||
|
||||
[Script(ScriptCategory.Pokemon, "ghostcurse")]
|
||||
public class GhostCurseEffect : Script
|
||||
{
|
||||
private IPokemon _pokemon;
|
||||
|
||||
public GhostCurseEffect(IPokemon pokemon)
|
||||
{
|
||||
_pokemon = pokemon;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnEndTurn(IBattle battle)
|
||||
{
|
||||
_pokemon.Damage(_pokemon.CurrentHealth / 4, DamageSource.Misc);
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
namespace PkmnLib.Plugin.Gen7.Scripts.Pokemon;
|
||||
|
||||
public abstract class ProtectionEffectScript : Script
|
||||
public class ProtectionEffectScript : Script
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override void BlockIncomingHit(IExecutingMove executingMove, IPokemon target, byte hitIndex, ref bool block)
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
using PkmnLib.Static.Moves;
|
||||
|
||||
namespace PkmnLib.Plugin.Gen7.Scripts.Side;
|
||||
|
||||
[Script(ScriptCategory.Side, "crafty_shield")]
|
||||
public class CraftyShieldEffect : Script
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override void StopBeforeMove(IExecutingMove move, ref bool stop)
|
||||
{
|
||||
if (move.UseMove.Category == MoveCategory.Status)
|
||||
stop = true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace PkmnLib.Plugin.Gen7.Scripts.Side;
|
||||
|
||||
[Script(ScriptCategory.Side, "doom_desire_effect")]
|
||||
public class DoomDesireEffect : Script
|
||||
{
|
||||
private class Target
|
||||
{
|
||||
public byte Position { get; }
|
||||
public uint Damage { get; }
|
||||
public int Turns { get; set; }
|
||||
|
||||
public Target(byte position, uint damage)
|
||||
{
|
||||
Position = position;
|
||||
Damage = damage;
|
||||
Turns = 3;
|
||||
}
|
||||
}
|
||||
|
||||
private readonly IBattleSide _side;
|
||||
private List<Target> _targets = new();
|
||||
|
||||
public DoomDesireEffect(IBattleSide side)
|
||||
{
|
||||
_side = side;
|
||||
}
|
||||
|
||||
public void AddTarget(byte position, uint damage)
|
||||
{
|
||||
_targets.Add(new Target(position, damage));
|
||||
}
|
||||
|
||||
public bool HasTarget(byte position)
|
||||
{
|
||||
return _targets.Exists(x => x.Position == position);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnEndTurn(IBattle battle)
|
||||
{
|
||||
var toRemove = new List<Target>();
|
||||
foreach (var v in _targets)
|
||||
{
|
||||
v.Turns--;
|
||||
if (v.Turns == 0)
|
||||
{
|
||||
var pokemon = _side.Pokemon[v.Position];
|
||||
pokemon?.Damage(v.Damage, DamageSource.Misc);
|
||||
toRemove.Add(v);
|
||||
}
|
||||
}
|
||||
foreach (var v in toRemove)
|
||||
{
|
||||
_targets.Remove(v);
|
||||
}
|
||||
if (_targets.Count == 0)
|
||||
{
|
||||
RemoveSelf();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
namespace PkmnLib.Plugin.Gen7.Scripts.Side;
|
||||
|
||||
/// <summary>
|
||||
/// Just here to indicate that a Pokemon on this side has used Echoed Voice.
|
||||
/// </summary>
|
||||
[Script(ScriptCategory.Side, "echoed_voice_data")]
|
||||
public class EchoedVoiceData : Script
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override void OnEndTurn(IBattle battle)
|
||||
{
|
||||
RemoveSelf();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
namespace PkmnLib.Plugin.Gen7.Scripts.Status;
|
||||
|
||||
[Script(ScriptCategory.Status, "sleep")]
|
||||
public class Sleep : Script
|
||||
{
|
||||
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
namespace PkmnLib.Plugin.Gen7.Scripts.Terrain;
|
||||
|
||||
[Script(ScriptCategory.Terrain, "electric_terrain")]
|
||||
public class ElectricTerrain : Script
|
||||
{
|
||||
// TODO: Implement Electric Terrain
|
||||
}
|
Loading…
Reference in New Issue