From afe091eefa0f9384644f0dde2ad69e45f931170f Mon Sep 17 00:00:00 2001 From: Deukhoofd Date: Sat, 30 Oct 2021 18:45:42 +0200 Subject: [PATCH] Finish the A moves --- Moves.json | 10 ++- Scripts/BattleSide/AuroraVeil.as | 35 +++++++++ Scripts/Interfaces/Battle.astypedef | 3 + Scripts/Interfaces/BattleSide.astypedef | 7 ++ Scripts/Interfaces/HistoryElement.astypedef | 3 + Scripts/Interfaces/PkmnScript.as | 6 +- Scripts/Interfaces/Pokemon.astypedef | 2 + Scripts/Interfaces/narray.astypedef | 2 +- Scripts/Moves/AuroraVeil.as | 79 +++++++++++++++++++++ Scripts/Moves/Automize.as | 16 +++++ Scripts/Moves/ModifyDamageIfHitByTarget.as | 22 ++++++ Scripts/Pokemon/HealEachEndOfTurn.as | 30 ++++++-- Scripts/Weather/Hail.as | 6 ++ fetch_tester.sh | 2 +- 14 files changed, 213 insertions(+), 10 deletions(-) create mode 100644 Scripts/BattleSide/AuroraVeil.as create mode 100644 Scripts/Moves/AuroraVeil.as create mode 100644 Scripts/Moves/Automize.as create mode 100644 Scripts/Moves/ModifyDamageIfHitByTarget.as create mode 100644 Scripts/Weather/Hail.as diff --git a/Moves.json b/Moves.json index 5961675..1060502 100644 --- a/Moves.json +++ b/Moves.json @@ -619,7 +619,10 @@ "category": "status", "flags": [ "snatch" - ] + ], + "effect": { + "name": "Automize" + } }, { "name": "avalanche", @@ -634,7 +637,10 @@ "contact", "protect", "mirror" - ] + ], + "effect": { + "name": "ModifyDamageIfHitByTarget" + } }, { "name": "baby_doll_eyes", diff --git a/Scripts/BattleSide/AuroraVeil.as b/Scripts/BattleSide/AuroraVeil.as new file mode 100644 index 0000000..9d9200e --- /dev/null +++ b/Scripts/BattleSide/AuroraVeil.as @@ -0,0 +1,35 @@ +namespace Gen7 { + [Side effect=AuroraVeil] + class AuroraVeilEffect : PkmnScript { + uint8 _turnsRemaining; + + void SetTurns(uint8 turns){ + _turnsRemaining = turns; + }; + + void OverrideIncomingDamage(ExecutingMove@ move, Pokemon@ target, uint8 hit, uint &inout damage) override { + if (move.GetHitData(target, hit).IsCritical){ + return; + } + auto side = cast(GetOwner()); + if (side.HasVolatile("Reflect") && move.UseMove.Category == MoveCategory::Physical){ + return; + } + if (side.HasVolatile("LightScreen") && move.UseMove.Category == MoveCategory::Special){ + return; + } + auto modifier = 2.0f; + if (target.Battle.PokemonPerSide > 1){ + modifier = 1.5f; + } + damage = uint(damage / modifier); + }; + + void OnEndTurn() override { + auto side = cast(GetOwner()); + if (_turnsRemaining == 0 || --_turnsRemaining == 0){ + side.RemoveVolatile("AuroraVeil"); + } + }; + } +} \ No newline at end of file diff --git a/Scripts/Interfaces/Battle.astypedef b/Scripts/Interfaces/Battle.astypedef index 0aed2cf..55e3cd8 100644 --- a/Scripts/Interfaces/Battle.astypedef +++ b/Scripts/Interfaces/Battle.astypedef @@ -2,6 +2,7 @@ type Battle { const BattleLibrary@ Library { get const; }; bool CanFlee { get const; }; uint CurrentTurn { get const; }; + uint8 PokemonPerSide { get const; }; BattleRandom@ Random { get const; }; ChoiceQueue@ TurnQueue { get const; }; narray@ Sides { get const; }; @@ -9,6 +10,7 @@ type Battle { BattleHistory@ History { get const; }; bool CanUse(BaseTurnChoice@ choice); ref@ AddVolatile(const constString &in name); + ref@ GetVolatile(const constString &in name); void RemoveVolatile(const constString &in name) const; void SetWeather(const constString &in name) const; void ClearWeather(const constString &in name) const; @@ -16,4 +18,5 @@ type Battle { BattleSide@ GetBattleSide(uint8 index); BattleParty@ GetParty(uint8 index); BattleParty@ FindPartyForPokemon(Pokemon@ pokemon); + bool HasVolatile(const constString &in name) const; } diff --git a/Scripts/Interfaces/BattleSide.astypedef b/Scripts/Interfaces/BattleSide.astypedef index 2c6622f..08e3539 100644 --- a/Scripts/Interfaces/BattleSide.astypedef +++ b/Scripts/Interfaces/BattleSide.astypedef @@ -1,6 +1,13 @@ type BattleSide { bool SwapPositions(uint8 a, uint8 b); uint8 SideIndex { get const; }; + bool IsDefeated { get const; }; + bool HasFled { get const; }; + Battle@ Battle { get const; }; uint8 GetPokemonIndex(const Pokemon@ pokemon) const; Pokemon@ GetPokemon(uint8 index) const; + ref@ AddVolatile(const constString &in name); + ref@ GetVolatile(const constString &in name); + void RemoveVolatile(const constString &in name) const; + bool HasVolatile(const constString &in name) const; } diff --git a/Scripts/Interfaces/HistoryElement.astypedef b/Scripts/Interfaces/HistoryElement.astypedef index 311e124..18c0dfe 100644 --- a/Scripts/Interfaces/HistoryElement.astypedef +++ b/Scripts/Interfaces/HistoryElement.astypedef @@ -1,4 +1,7 @@ type HistoryElement { + const HistoryElement@ Previous { get const; }; + HistoryElementKind Kind { get const; }; + uint TurnNumber { get const; }; const DamageHistory@ opCast() const; const AttackUseHistory@ opCast() const; } diff --git a/Scripts/Interfaces/PkmnScript.as b/Scripts/Interfaces/PkmnScript.as index 650373e..ecbd591 100644 --- a/Scripts/Interfaces/PkmnScript.as +++ b/Scripts/Interfaces/PkmnScript.as @@ -1,4 +1,7 @@ shared abstract class PkmnScript { + ref@ __owner; + + ref@& GetOwner(){ return __owner; }; void OnInitialize(const narray@){}; void Stack(){}; void OnRemove(){}; @@ -27,13 +30,14 @@ shared abstract class PkmnScript { void ModifyStatModifier(ExecutingMove@, Pokemon@, uint8, float &inout){}; void ModifyDamageModifier(ExecutingMove@, Pokemon@, uint8, float &inout){}; void OverrideDamage(ExecutingMove@, Pokemon@, uint8, uint &inout){}; + void OverrideIncomingDamage(ExecutingMove@, Pokemon@, uint8, uint &inout){}; void ChangePriority(MoveTurnChoice@, int8 &inout){}; void OnFail(Pokemon@){}; void OnOpponentFail(Pokemon@){}; void PreventRunAway(FleeTurnChoice@, bool &inout){}; void PreventOpponentRunAway(FleeTurnChoice@, bool &inout){}; void PreventOpponentSwitch(SwitchTurnChoice@, bool &inout){}; - void OnEndTurn(Pokemon@){}; + void OnEndTurn(){}; void ModifyCriticalStage(ExecutingMove@, Pokemon@, uint8, uint8 &inout){}; void OverrideCriticalModifier(ExecutingMove@, Pokemon@, uint8, float &inout){}; void OverrideSTABModifier(ExecutingMove@, Pokemon@, uint8, float &inout){}; diff --git a/Scripts/Interfaces/Pokemon.astypedef b/Scripts/Interfaces/Pokemon.astypedef index 137aebd..3d16e00 100644 --- a/Scripts/Interfaces/Pokemon.astypedef +++ b/Scripts/Interfaces/Pokemon.astypedef @@ -17,6 +17,8 @@ type Pokemon { BattleSide@ BattleSide { get const; }; const constString& Status { get const; }; const narray@ Moves { get const; }; + float Weight { get const; set; }; + float Height { get const; set; }; bool HasHeldItem(const constString &in name) const; void SetHeldItem(const constString &in name); void SetHeldItem(const Item@ item); diff --git a/Scripts/Interfaces/narray.astypedef b/Scripts/Interfaces/narray.astypedef index 2ca4be8..451d23c 100644 --- a/Scripts/Interfaces/narray.astypedef +++ b/Scripts/Interfaces/narray.astypedef @@ -1,5 +1,5 @@ type narray { uint64 Length { get const; }; const T@ At(uint64 index) const; - const T@ opIndex(uint64) const; + const T@ get_opIndex(uint64) const property; } diff --git a/Scripts/Moves/AuroraVeil.as b/Scripts/Moves/AuroraVeil.as new file mode 100644 index 0000000..5baafb9 --- /dev/null +++ b/Scripts/Moves/AuroraVeil.as @@ -0,0 +1,79 @@ +namespace Gen7 { + [Move effect=AuroraVeil] + class AuroraVeil : PkmnScript { + void OnSecondaryEffect(ExecutingMove@ move, Pokemon@ target, uint8 hit) override { + if (target.Battle.GetWeatherName() != "hail"){ + move.GetHitData(target, hit).Fail(); + return; + } + + auto effect = cast(target.BattleSide.AddVolatile("AuroraVeil")); + if (move.User.HasHeldItem("light_clay")){ + effect.SetTurns(8); + } + else{ + effect.SetTurns(5); + } + } + } +} + +#if TESTS + +[Test name="AuroraVeil: Fails without hail"] +void AuroraVeil_FailsWithoutHail(){ + auto battle = CreateSimpleBattle(0, "charizard", "venusaur", 100); + auto mon1 = battle.GetBattleSide(0).GetPokemon(0); + + auto script = cast(CreateMoveScript("AuroraVeil")); + auto executingMove = CreateExecutingMove("aurora_veil", mon1, mon1); + script.OnSecondaryEffect(executingMove, mon1, 0x0); + Require(executingMove.GetHitData(mon1, 0x0).HasFailed); +} + +[Test name="AuroraVeil: Works with hail"] +void AuroraVeil_WorksWithHail(){ + auto battle = CreateSimpleBattle(0, "charizard", "venusaur", 100); + battle.SetWeather("hail"); + auto mon1 = battle.GetBattleSide(0).GetPokemon(0); + + auto script = cast(CreateMoveScript("AuroraVeil")); + auto executingMove = CreateExecutingMove("aurora_veil", mon1, mon1); + script.OnSecondaryEffect(executingMove, mon1, 0x0); + Require(!executingMove.GetHitData(mon1, 0x0).HasFailed); + Require(battle.GetBattleSide(0).HasVolatile("AuroraVeil")); +} + +[Test name="AuroraVeil: Sets to 5 turns by default"] +void AuroraVeil_FiveTurnsByDefault(){ + auto battle = CreateSimpleBattle(0, "charizard", "venusaur", 100); + battle.SetWeather("hail"); + auto mon1 = battle.GetBattleSide(0).GetPokemon(0); + + auto script = cast(CreateMoveScript("AuroraVeil")); + auto executingMove = CreateExecutingMove("aurora_veil", mon1, mon1); + script.OnSecondaryEffect(executingMove, mon1, 0x0); + Require(!executingMove.GetHitData(mon1, 0x0).HasFailed); + Require(battle.GetBattleSide(0).HasVolatile("AuroraVeil")); + auto effect = cast(battle.GetBattleSide(0).GetVolatile("AuroraVeil")); + RequireEquals(5, effect._turnsRemaining); +} + +[Test name="AuroraVeil: Sets to 8 turns with light clay"] +void AuroraVeil_EightTurnsWithLightClay(){ + auto battle = CreateSimpleBattle(0, "charizard", "venusaur", 100); + battle.SetWeather("hail"); + auto mon1 = battle.GetBattleSide(0).GetPokemon(0); + mon1.SetHeldItem("light_clay"); + + auto script = cast(CreateMoveScript("AuroraVeil")); + auto executingMove = CreateExecutingMove("aurora_veil", mon1, mon1); + script.OnSecondaryEffect(executingMove, mon1, 0x0); + Require(!executingMove.GetHitData(mon1, 0x0).HasFailed); + Require(battle.GetBattleSide(0).HasVolatile("AuroraVeil")); + auto effect = cast(battle.GetBattleSide(0).GetVolatile("AuroraVeil")); + RequireEquals(8, effect._turnsRemaining); +} + + +#endif \ No newline at end of file diff --git a/Scripts/Moves/Automize.as b/Scripts/Moves/Automize.as new file mode 100644 index 0000000..1b9a2ee --- /dev/null +++ b/Scripts/Moves/Automize.as @@ -0,0 +1,16 @@ +namespace Gen7 { + class Automize : PkmnScript { + void OnSecondaryEffect(ExecutingMove@ move, Pokemon@ target, uint8 hit) override { + auto originalSpeed = move.User.GetBoostedStat(Statistic::Speed); + auto originalWeight = move.User.Weight; + move.User.ChangeStatBoost(Statistic::Speed, 2); + if (move.User.GetBoostedStat(Statistic::Speed) != originalSpeed){ + // This setter function protects against going below 0.1 + move.User.Weight -= 100; + if (move.User.Weight != originalWeight){ + // {Pokemon} became nimble text + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Moves/ModifyDamageIfHitByTarget.as b/Scripts/Moves/ModifyDamageIfHitByTarget.as new file mode 100644 index 0000000..6e1ebc0 --- /dev/null +++ b/Scripts/Moves/ModifyDamageIfHitByTarget.as @@ -0,0 +1,22 @@ +namespace Gen7 { + // For moves such as Avalanche + [Move effect=ModifyDamageIfHitByTarget] + class ModifyDamageIfHitByTarget : PkmnScript { + void OverrideDamage(ExecutingMove@ move, Pokemon@ target, uint8 hit, uint &inout damage) override { + auto historyElement = move.User.Battle.History.TopElement; + auto turn = move.User.Battle.CurrentTurn; + while (historyElement !is null){ + if (historyElement.TurnNumber < turn){ + break; + } + if (historyElement.Kind == HistoryElementKind::AttackUse){ + auto attackEvent = cast(historyElement); + if (attackEvent.Move.User is target && attackEvent.Move.IsPokemonTarget(move.User)){ + damage *= 2; + break; + } + } + } + }; + } +} \ No newline at end of file diff --git a/Scripts/Pokemon/HealEachEndOfTurn.as b/Scripts/Pokemon/HealEachEndOfTurn.as index 6da9252..09cfed6 100644 --- a/Scripts/Pokemon/HealEachEndOfTurn.as +++ b/Scripts/Pokemon/HealEachEndOfTurn.as @@ -3,16 +3,36 @@ namespace Gen7 { shared class HealEachEndOfTurnEffect : PkmnScript { float _factor; - void OnEndTurn(Pokemon@ pokemon) override { - auto healAmount = pokemon.MaxHealth * _factor; - if (pokemon.HasHeldItem("big_root")){ + void OnEndTurn() override { + auto target = cast(GetOwner()); + if (target is null){ + throw("target was null"); + } + auto healAmount = target.MaxHealth * _factor; + if (target.HasHeldItem("big_root")){ healAmount *= 1.3; } - pokemon.Heal(uint(healAmount)); + target.Heal(uint(healAmount)); } void SetBaseHealAmount(float factor){ _factor = factor; } } -} \ No newline at end of file +} + + +#if TESTS + +[Test name="Heal Each End Of Turn effect: Heals on end of turn"] +void HealEachEndOfTurn_HealsOnEndOfTurn(){ + auto battle = CreateSimpleBattle(0, "charizard", "venusaur", 100); + auto mon = battle.GetParty(0).Party.GetAtIndex(0); + mon.Damage(100, DamageSource::AttackDamage); + auto effect = cast(mon.AddVolatile("HealEachEndOfTurn")); + effect.SetBaseHealAmount(0.0625); + effect.OnEndTurn(); + RequireEquals(215, mon.CurrentHealth); +} + +#endif \ No newline at end of file diff --git a/Scripts/Weather/Hail.as b/Scripts/Weather/Hail.as new file mode 100644 index 0000000..329b015 --- /dev/null +++ b/Scripts/Weather/Hail.as @@ -0,0 +1,6 @@ +namespace Gen7 { + [Weather effect=Hail] + class Hail : PkmnScript { + // TODO + } +} \ No newline at end of file diff --git a/fetch_tester.sh b/fetch_tester.sh index ec86c3f..4ce68e1 100755 --- a/fetch_tester.sh +++ b/fetch_tester.sh @@ -1,6 +1,6 @@ #!/bin/sh -TESTERVERSION=0.0.8 +TESTERVERSION=0.0.10 # Get the release information from the api for the specified version curl -X GET "https://git.p-epsilon.com/api/v1/repos/Deukhoofd/PokemonScriptTester/releases/tags/$TESTERVERSION" -H "accept: application/json" |