From 96122d9342ca4ef148147515101e6097cc701d1d Mon Sep 17 00:00:00 2001 From: Alex <93446519+AlexOn1ine@users.noreply.github.com> Date: Sun, 12 Jan 2025 13:08:04 +0100 Subject: [PATCH 1/9] Adds Liquid Ooze and Aromatic Mist test (#6012) --- test/battle/ability/liquid_ooze.c | 27 ++++++++++++++++++ test/battle/move_effect/aromatic_mist.c | 38 +++++++++++++++++++++++-- 2 files changed, 63 insertions(+), 2 deletions(-) diff --git a/test/battle/ability/liquid_ooze.c b/test/battle/ability/liquid_ooze.c index bb4da48f8641..b1f94091f6cd 100644 --- a/test/battle/ability/liquid_ooze.c +++ b/test/battle/ability/liquid_ooze.c @@ -108,5 +108,32 @@ SINGLE_BATTLE_TEST("Liquid Ooze causes Strength Sap users to lose HP instead of } } +SINGLE_BATTLE_TEST("Liquid Ooze causes leech seedee to faint before seeder") +{ + KNOWN_FAILING; // Message fails + u16 ability; + PARAMETRIZE { ability = ABILITY_CLEAR_BODY; } + PARAMETRIZE { ability = ABILITY_LIQUID_OOZE; } + GIVEN { + PLAYER(SPECIES_BULBASAUR) { HP(1); } + OPPONENT(SPECIES_TENTACOOL) { HP(1); Ability(ability); } + } WHEN { + TURN { MOVE(player, MOVE_LEECH_SEED); } + } SCENE { + MESSAGE("Bulbasaur used Leech Seed!"); + // Drain at end of turn + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_LEECH_SEED_DRAIN, opponent); + if (ability != ABILITY_LIQUID_OOZE) { + MESSAGE("The opposing Tentacool's health is sapped by Leech Seed!"); + MESSAGE("The opposing Tentacool fainted!"); + } else { + ABILITY_POPUP(opponent, ABILITY_LIQUID_OOZE); + MESSAGE("Bulbasaur sucked up the liquid ooze!"); + MESSAGE("The opposing Tentacool fainted!"); + MESSAGE("Bulbasaur fainted!"); + } + } +} + TO_DO_BATTLE_TEST("Liquid Ooze does not cause Dream Eater users to lose HP instead of heal (Gen 3-4"); TO_DO_BATTLE_TEST("Liquid Ooze causes Dream Eater users to lose HP instead of heal (Gen 5+"); diff --git a/test/battle/move_effect/aromatic_mist.c b/test/battle/move_effect/aromatic_mist.c index 516ed14f1694..130305cd99fe 100644 --- a/test/battle/move_effect/aromatic_mist.c +++ b/test/battle/move_effect/aromatic_mist.c @@ -1,5 +1,39 @@ #include "global.h" #include "test/battle.h" -TO_DO_BATTLE_TEST("Aromatic Mist raises Sp. Defense of a target ally by 1 stage"); -TO_DO_BATTLE_TEST("Aromatic Mist fails in Single Battles"); +DOUBLE_BATTLE_TEST("Aromatic Mist raises Sp. Defense of a target ally by 1 stage") +{ + GIVEN { + PLAYER(SPECIES_WEEZING_GALAR); + PLAYER(SPECIES_SYLVEON); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WYNAUT); + } WHEN { + TURN { MOVE(playerLeft, MOVE_AROMATIC_MIST); } + } SCENE { + MESSAGE("Weezing used Aromatic Mist!"); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerRight); + } THEN { + EXPECT_EQ(playerLeft->statStages[STAT_SPDEF], DEFAULT_STAT_STAGE); + EXPECT_EQ(playerRight->statStages[STAT_SPDEF], DEFAULT_STAT_STAGE + 1); + EXPECT_EQ(opponentLeft->statStages[STAT_SPDEF], DEFAULT_STAT_STAGE); + EXPECT_EQ(opponentRight->statStages[STAT_SPDEF], DEFAULT_STAT_STAGE); + } +} + +SINGLE_BATTLE_TEST("Aromatic Mist fails in Single Battles") +{ + GIVEN { + PLAYER(SPECIES_WEEZING_GALAR); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_AROMATIC_MIST); } + } SCENE { + MESSAGE("Weezing used Aromatic Mist!"); + MESSAGE("But it failed!"); + NOT ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); + } THEN { + EXPECT_EQ(player->statStages[STAT_SPDEF], DEFAULT_STAT_STAGE); + EXPECT_EQ(opponent->statStages[STAT_SPDEF], DEFAULT_STAT_STAGE); + } +} From 536f386bed5b030a514d619500862180fa6292eb Mon Sep 17 00:00:00 2001 From: RavePossum <145081120+ravepossum@users.noreply.github.com> Date: Sun, 12 Jan 2025 18:01:47 -0500 Subject: [PATCH 2/9] Explicitly specify dependencies for teachable learnset helper (#6015) --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 5f806e45ec90..a1b606815675 100644 --- a/Makefile +++ b/Makefile @@ -426,8 +426,8 @@ $(OBJ_DIR)/sym_common.ld: sym_common.txt $(C_OBJS) $(wildcard common_syms/*.txt) $(OBJ_DIR)/sym_ewram.ld: sym_ewram.txt $(RAMSCRGEN) ewram_data $< ENGLISH > $@ -# NOTE: Depending on event_scripts.o is hacky, but we want to depend on everything event_scripts.s depends on without having to alter scaninc -$(DATA_SRC_SUBDIR)/pokemon/teachable_learnsets.h: $(DATA_ASM_BUILDDIR)/event_scripts.o +TEACHABLE_DEPS := $(shell find data/ -type f -name '*.inc') $(INCLUDE_DIRS)/constants/tms_hms.h $(C_SUBDIR)/pokemon.c +$(DATA_SRC_SUBDIR)/pokemon/teachable_learnsets.h: $(TEACHABLE_DEPS) python3 $(TOOLS_DIR)/learnset_helpers/teachable.py # Linker script From f1eebc978d05697c6bae087dfb135e35b9c26c27 Mon Sep 17 00:00:00 2001 From: Alex <93446519+AlexOn1ine@users.noreply.github.com> Date: Mon, 13 Jan 2025 10:09:55 +0100 Subject: [PATCH 3/9] Fixes defrosting if frozon mon is not damaged by opponent (#6016) Co-authored-by: Bassoonian --- src/battle_script_commands.c | 1 + test/battle/status1/freeze.c | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index ffb03a1d731d..32f2b1138b5f 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -5846,6 +5846,7 @@ static void Cmd_moveend(void) break; case MOVEEND_DEFROST: // defrosting check if (gBattleMons[gBattlerTarget].status1 & STATUS1_FREEZE + && TARGET_TURN_DAMAGED && IsBattlerAlive(gBattlerTarget) && gBattlerAttacker != gBattlerTarget && (moveType == TYPE_FIRE || CanBurnHitThaw(gCurrentMove)) diff --git a/test/battle/status1/freeze.c b/test/battle/status1/freeze.c index f218430909e1..d19e1776be88 100644 --- a/test/battle/status1/freeze.c +++ b/test/battle/status1/freeze.c @@ -43,3 +43,21 @@ SINGLE_BATTLE_TEST("Freeze is thawed by user's Flame Wheel") MESSAGE("Wobbuffet used Flame Wheel!"); } } + +SINGLE_BATTLE_TEST("Freeze isn't thawed if opponent is asleep during thawing attack") +{ + PASSES_RANDOMLY(80, 100, RNG_FROZEN); + GIVEN { + ASSUME(GetMoveType(MOVE_EMBER) == TYPE_FIRE); + PLAYER(SPECIES_WOBBUFFET) { Status1(STATUS1_FREEZE); } + OPPONENT(SPECIES_WOBBUFFET) { Status1(STATUS1_SLEEP); }; + } WHEN { + TURN { MOVE(opponent, MOVE_EMBER); MOVE(player, MOVE_CELEBRATE); } + } SCENE { + NONE_OF { + MESSAGE("The opposing Wobbuffet used Ember!"); + MESSAGE("Wobbuffet thawed out!"); + STATUS_ICON(player, none: TRUE); + } + } +} From 52201b15611e11239dd35fdc66f66e1d5de6100a Mon Sep 17 00:00:00 2001 From: Eduardo Quezada Date: Mon, 13 Jan 2025 06:16:43 -0300 Subject: [PATCH 4/9] Improved Hidden Power test (#6014) --- test/battle/move_effect/hidden_power.c | 141 +++++++++++++------------ 1 file changed, 72 insertions(+), 69 deletions(-) diff --git a/test/battle/move_effect/hidden_power.c b/test/battle/move_effect/hidden_power.c index 8ec63c21a7ec..d1d175013ac3 100644 --- a/test/battle/move_effect/hidden_power.c +++ b/test/battle/move_effect/hidden_power.c @@ -4,77 +4,77 @@ // IV combinations sourced from https://www.smogon.com/forums/threads/hidden-power-iv-combinations.78083/ SINGLE_BATTLE_TEST("Hidden Power's type is determined by IVs") { - u32 type, j, foeType, foeSpecies; + u32 type, j, foeType, foeSpecies, foeItem; u32 hp, atk, def, spAtk, spDef, speed; bool32 hidden; PARAMETRIZE { type = TYPE_NONE; hidden = FALSE; } PARAMETRIZE { type = TYPE_NORMAL; hidden = FALSE; } - PARAMETRIZE { type = TYPE_FIGHTING; hidden = TRUE; foeType = TYPE_PSYCHIC; foeSpecies = SPECIES_WOBBUFFET; hp = 30; atk = 2; def = 31; spAtk = 30; spDef = 30; speed = 30; } - PARAMETRIZE { type = TYPE_FIGHTING; hidden = TRUE; foeType = TYPE_PSYCHIC; foeSpecies = SPECIES_WOBBUFFET; hp = 31; atk = 15; def = 30; spAtk = 30; spDef = 30; speed = 30; } - PARAMETRIZE { type = TYPE_FIGHTING; hidden = TRUE; foeType = TYPE_PSYCHIC; foeSpecies = SPECIES_WOBBUFFET; hp = 30; atk = 22; def = 31; spAtk = 30; spDef = 30; speed = 30; } - PARAMETRIZE { type = TYPE_FIGHTING; hidden = TRUE; foeType = TYPE_PSYCHIC; foeSpecies = SPECIES_WOBBUFFET; hp = 31; atk = 31; def = 30; spAtk = 30; spDef = 30; speed = 30; } - PARAMETRIZE { type = TYPE_FLYING; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_REGISTEEL; hp = 31; atk = 2; def = 31; spAtk = 30; spDef = 30; speed = 30; } - PARAMETRIZE { type = TYPE_FLYING; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_REGISTEEL; hp = 31; atk = 15; def = 31; spAtk = 30; spDef = 30; speed = 30; } - PARAMETRIZE { type = TYPE_FLYING; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_REGISTEEL; hp = 31; atk = 22; def = 31; spAtk = 30; spDef = 30; speed = 30; } - PARAMETRIZE { type = TYPE_FLYING; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_REGISTEEL; hp = 31; atk = 31; def = 31; spAtk = 30; spDef = 30; speed = 30; } - PARAMETRIZE { type = TYPE_POISON; hidden = TRUE; foeType = TYPE_POISON; foeSpecies = SPECIES_ARBOK; hp = 30; atk = 2; def = 31; spAtk = 30; spDef = 30; speed = 31; } - PARAMETRIZE { type = TYPE_POISON; hidden = TRUE; foeType = TYPE_POISON; foeSpecies = SPECIES_ARBOK; hp = 31; atk = 15; def = 30; spAtk = 30; spDef = 30; speed = 31; } - PARAMETRIZE { type = TYPE_POISON; hidden = TRUE; foeType = TYPE_POISON; foeSpecies = SPECIES_ARBOK; hp = 30; atk = 22; def = 31; spAtk = 30; spDef = 30; speed = 31; } - PARAMETRIZE { type = TYPE_POISON; hidden = TRUE; foeType = TYPE_POISON; foeSpecies = SPECIES_ARBOK; hp = 31; atk = 31; def = 30; spAtk = 30; spDef = 30; speed = 31; } - PARAMETRIZE { type = TYPE_GROUND; hidden = TRUE; foeType = TYPE_GRASS; foeSpecies = SPECIES_TANGELA; hp = 31; atk = 2; def = 31; spAtk = 30; spDef = 30; speed = 31; } - PARAMETRIZE { type = TYPE_GROUND; hidden = TRUE; foeType = TYPE_GRASS; foeSpecies = SPECIES_TANGELA; hp = 31; atk = 15; def = 31; spAtk = 30; spDef = 30; speed = 31; } - PARAMETRIZE { type = TYPE_GROUND; hidden = TRUE; foeType = TYPE_GRASS; foeSpecies = SPECIES_TANGELA; hp = 31; atk = 22; def = 31; spAtk = 30; spDef = 30; speed = 31; } - PARAMETRIZE { type = TYPE_GROUND; hidden = TRUE; foeType = TYPE_GRASS; foeSpecies = SPECIES_TANGELA; hp = 31; atk = 31; def = 31; spAtk = 30; spDef = 30; speed = 31; } - PARAMETRIZE { type = TYPE_ROCK; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 31; atk = 2; def = 30; spAtk = 31; spDef = 30; speed = 30; } - PARAMETRIZE { type = TYPE_ROCK; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 31; atk = 15; def = 30; spAtk = 31; spDef = 30; speed = 30; } - PARAMETRIZE { type = TYPE_ROCK; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 31; atk = 22; def = 30; spAtk = 31; spDef = 30; speed = 30; } - PARAMETRIZE { type = TYPE_ROCK; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 31; atk = 31; def = 30; spAtk = 31; spDef = 30; speed = 30; } - PARAMETRIZE { type = TYPE_BUG; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 31; atk = 2; def = 31; spAtk = 31; spDef = 30; speed = 30; } - PARAMETRIZE { type = TYPE_BUG; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 31; atk = 15; def = 31; spAtk = 31; spDef = 30; speed = 30; } - PARAMETRIZE { type = TYPE_BUG; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 31; atk = 22; def = 31; spAtk = 31; spDef = 30; speed = 30; } - PARAMETRIZE { type = TYPE_BUG; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 31; atk = 31; def = 31; spAtk = 31; spDef = 30; speed = 30; } - PARAMETRIZE { type = TYPE_GHOST; hidden = TRUE; foeType = TYPE_DARK; foeSpecies = SPECIES_UMBREON; hp = 31; atk = 2; def = 31; spAtk = 31; spDef = 30; speed = 31; } - PARAMETRIZE { type = TYPE_GHOST; hidden = TRUE; foeType = TYPE_DARK; foeSpecies = SPECIES_UMBREON; hp = 31; atk = 15; def = 30; spAtk = 31; spDef = 30; speed = 31; } - PARAMETRIZE { type = TYPE_GHOST; hidden = TRUE; foeType = TYPE_DARK; foeSpecies = SPECIES_UMBREON; hp = 31; atk = 22; def = 31; spAtk = 31; spDef = 30; speed = 31; } - PARAMETRIZE { type = TYPE_GHOST; hidden = TRUE; foeType = TYPE_DARK; foeSpecies = SPECIES_UMBREON; hp = 31; atk = 31; def = 30; spAtk = 31; spDef = 30; speed = 31; } - PARAMETRIZE { type = TYPE_STEEL; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 31; atk = 2; def = 30; spAtk = 30; spDef = 31; speed = 30; } - PARAMETRIZE { type = TYPE_STEEL; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 31; atk = 15; def = 31; spAtk = 31; spDef = 30; speed = 31; } - PARAMETRIZE { type = TYPE_STEEL; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 31; atk = 22; def = 30; spAtk = 30; spDef = 31; speed = 30; } - PARAMETRIZE { type = TYPE_STEEL; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 31; atk = 31; def = 31; spAtk = 31; spDef = 30; speed = 31; } - PARAMETRIZE { type = TYPE_FIRE; hidden = TRUE; foeType = TYPE_WATER; foeSpecies = SPECIES_BLASTOISE; hp = 31; atk = 2; def = 31; spAtk = 30; spDef = 31; speed = 30; } - PARAMETRIZE { type = TYPE_FIRE; hidden = TRUE; foeType = TYPE_WATER; foeSpecies = SPECIES_BLASTOISE; hp = 31; atk = 15; def = 30; spAtk = 30; spDef = 31; speed = 30; } - PARAMETRIZE { type = TYPE_FIRE; hidden = TRUE; foeType = TYPE_WATER; foeSpecies = SPECIES_BLASTOISE; hp = 31; atk = 22; def = 31; spAtk = 30; spDef = 31; speed = 30; } - PARAMETRIZE { type = TYPE_FIRE; hidden = TRUE; foeType = TYPE_WATER; foeSpecies = SPECIES_BLASTOISE; hp = 31; atk = 31; def = 30; spAtk = 30; spDef = 31; speed = 30; } - PARAMETRIZE { type = TYPE_WATER; hidden = TRUE; foeType = TYPE_WATER; foeSpecies = SPECIES_BLASTOISE; hp = 31; atk = 2; def = 30; spAtk = 30; spDef = 31; speed = 31; } - PARAMETRIZE { type = TYPE_WATER; hidden = TRUE; foeType = TYPE_WATER; foeSpecies = SPECIES_BLASTOISE; hp = 31; atk = 15; def = 31; spAtk = 30; spDef = 31; speed = 30; } - PARAMETRIZE { type = TYPE_WATER; hidden = TRUE; foeType = TYPE_WATER; foeSpecies = SPECIES_BLASTOISE; hp = 31; atk = 22; def = 30; spAtk = 30; spDef = 31; speed = 31; } - PARAMETRIZE { type = TYPE_WATER; hidden = TRUE; foeType = TYPE_WATER; foeSpecies = SPECIES_BLASTOISE; hp = 31; atk = 31; def = 31; spAtk = 30; spDef = 31; speed = 30; } - PARAMETRIZE { type = TYPE_GRASS; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 30; atk = 2; def = 31; spAtk = 30; spDef = 31; speed = 31; } - PARAMETRIZE { type = TYPE_GRASS; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 30; atk = 15; def = 31; spAtk = 30; spDef = 31; speed = 31; } - PARAMETRIZE { type = TYPE_GRASS; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 30; atk = 22; def = 31; spAtk = 30; spDef = 31; speed = 31; } - PARAMETRIZE { type = TYPE_GRASS; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 30; atk = 31; def = 31; spAtk = 30; spDef = 31; speed = 31; } - PARAMETRIZE { type = TYPE_ELECTRIC; hidden = TRUE; foeType = TYPE_GRASS; foeSpecies = SPECIES_TANGELA; hp = 31; atk = 2; def = 30; spAtk = 31; spDef = 31; speed = 30; } - PARAMETRIZE { type = TYPE_ELECTRIC; hidden = TRUE; foeType = TYPE_GRASS; foeSpecies = SPECIES_TANGELA; hp = 30; atk = 15; def = 30; spAtk = 31; spDef = 31; speed = 30; } - PARAMETRIZE { type = TYPE_ELECTRIC; hidden = TRUE; foeType = TYPE_GRASS; foeSpecies = SPECIES_TANGELA; hp = 31; atk = 22; def = 30; spAtk = 31; spDef = 31; speed = 30; } - PARAMETRIZE { type = TYPE_ELECTRIC; hidden = TRUE; foeType = TYPE_GRASS; foeSpecies = SPECIES_TANGELA; hp = 30; atk = 31; def = 30; spAtk = 31; spDef = 31; speed = 30; } - PARAMETRIZE { type = TYPE_PSYCHIC; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 31; atk = 2; def = 31; spAtk = 31; spDef = 31; speed = 30; } - PARAMETRIZE { type = TYPE_PSYCHIC; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 30; atk = 15; def = 31; spAtk = 31; spDef = 31; speed = 30; } - PARAMETRIZE { type = TYPE_PSYCHIC; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 31; atk = 22; def = 31; spAtk = 31; spDef = 31; speed = 30; } - PARAMETRIZE { type = TYPE_PSYCHIC; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 30; atk = 31; def = 31; spAtk = 31; spDef = 31; speed = 30; } - PARAMETRIZE { type = TYPE_ICE; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 30; atk = 2; def = 30; spAtk = 31; spDef = 31; speed = 31; } - PARAMETRIZE { type = TYPE_ICE; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 30; atk = 15; def = 30; spAtk = 31; spDef = 31; speed = 31; } - PARAMETRIZE { type = TYPE_ICE; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 30; atk = 22; def = 30; spAtk = 31; spDef = 31; speed = 31; } - PARAMETRIZE { type = TYPE_ICE; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 30; atk = 31; def = 30; spAtk = 31; spDef = 31; speed = 31; } + PARAMETRIZE { type = TYPE_FIGHTING; hidden = TRUE; foeType = TYPE_DARK; foeSpecies = SPECIES_UMBREON; foeItem = ITEM_CHOPLE_BERRY; hp = 30; atk = 2; def = 31; spAtk = 30; spDef = 30; speed = 30; } + PARAMETRIZE { type = TYPE_FIGHTING; hidden = TRUE; foeType = TYPE_DARK; foeSpecies = SPECIES_UMBREON; foeItem = ITEM_CHOPLE_BERRY; hp = 31; atk = 15; def = 30; spAtk = 30; spDef = 30; speed = 30; } + PARAMETRIZE { type = TYPE_FIGHTING; hidden = TRUE; foeType = TYPE_DARK; foeSpecies = SPECIES_UMBREON; foeItem = ITEM_CHOPLE_BERRY; hp = 30; atk = 22; def = 31; spAtk = 30; spDef = 30; speed = 30; } + PARAMETRIZE { type = TYPE_FIGHTING; hidden = TRUE; foeType = TYPE_DARK; foeSpecies = SPECIES_UMBREON; foeItem = ITEM_CHOPLE_BERRY; hp = 31; atk = 31; def = 30; spAtk = 30; spDef = 30; speed = 30; } + PARAMETRIZE { type = TYPE_FLYING; hidden = TRUE; foeType = TYPE_GRASS; foeSpecies = SPECIES_TANGELA; foeItem = ITEM_COBA_BERRY; hp = 31; atk = 2; def = 31; spAtk = 30; spDef = 30; speed = 30; } + PARAMETRIZE { type = TYPE_FLYING; hidden = TRUE; foeType = TYPE_GRASS; foeSpecies = SPECIES_TANGELA; foeItem = ITEM_COBA_BERRY; hp = 31; atk = 15; def = 31; spAtk = 30; spDef = 30; speed = 30; } + PARAMETRIZE { type = TYPE_FLYING; hidden = TRUE; foeType = TYPE_GRASS; foeSpecies = SPECIES_TANGELA; foeItem = ITEM_COBA_BERRY; hp = 31; atk = 22; def = 31; spAtk = 30; spDef = 30; speed = 30; } + PARAMETRIZE { type = TYPE_FLYING; hidden = TRUE; foeType = TYPE_GRASS; foeSpecies = SPECIES_TANGELA; foeItem = ITEM_COBA_BERRY; hp = 31; atk = 31; def = 31; spAtk = 30; spDef = 30; speed = 30; } + PARAMETRIZE { type = TYPE_POISON; hidden = TRUE; foeType = TYPE_GRASS; foeSpecies = SPECIES_TANGELA; foeItem = ITEM_KEBIA_BERRY; hp = 30; atk = 2; def = 31; spAtk = 30; spDef = 30; speed = 31; } + PARAMETRIZE { type = TYPE_POISON; hidden = TRUE; foeType = TYPE_GRASS; foeSpecies = SPECIES_TANGELA; foeItem = ITEM_KEBIA_BERRY; hp = 31; atk = 15; def = 30; spAtk = 30; spDef = 30; speed = 31; } + PARAMETRIZE { type = TYPE_POISON; hidden = TRUE; foeType = TYPE_GRASS; foeSpecies = SPECIES_TANGELA; foeItem = ITEM_KEBIA_BERRY; hp = 30; atk = 22; def = 31; spAtk = 30; spDef = 30; speed = 31; } + PARAMETRIZE { type = TYPE_POISON; hidden = TRUE; foeType = TYPE_GRASS; foeSpecies = SPECIES_TANGELA; foeItem = ITEM_KEBIA_BERRY; hp = 31; atk = 31; def = 30; spAtk = 30; spDef = 30; speed = 31; } + PARAMETRIZE { type = TYPE_GROUND; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; foeItem = ITEM_SHUCA_BERRY; hp = 31; atk = 2; def = 31; spAtk = 30; spDef = 30; speed = 31; } + PARAMETRIZE { type = TYPE_GROUND; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; foeItem = ITEM_SHUCA_BERRY; hp = 31; atk = 15; def = 31; spAtk = 30; spDef = 30; speed = 31; } + PARAMETRIZE { type = TYPE_GROUND; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; foeItem = ITEM_SHUCA_BERRY; hp = 31; atk = 22; def = 31; spAtk = 30; spDef = 30; speed = 31; } + PARAMETRIZE { type = TYPE_GROUND; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; foeItem = ITEM_SHUCA_BERRY; hp = 31; atk = 31; def = 31; spAtk = 30; spDef = 30; speed = 31; } + PARAMETRIZE { type = TYPE_ROCK; hidden = TRUE; foeType = TYPE_FIRE; foeSpecies = SPECIES_VULPIX; foeItem = ITEM_CHARTI_BERRY; hp = 31; atk = 2; def = 30; spAtk = 31; spDef = 30; speed = 30; } + PARAMETRIZE { type = TYPE_ROCK; hidden = TRUE; foeType = TYPE_FIRE; foeSpecies = SPECIES_VULPIX; foeItem = ITEM_CHARTI_BERRY; hp = 31; atk = 15; def = 30; spAtk = 31; spDef = 30; speed = 30; } + PARAMETRIZE { type = TYPE_ROCK; hidden = TRUE; foeType = TYPE_FIRE; foeSpecies = SPECIES_VULPIX; foeItem = ITEM_CHARTI_BERRY; hp = 31; atk = 22; def = 30; spAtk = 31; spDef = 30; speed = 30; } + PARAMETRIZE { type = TYPE_ROCK; hidden = TRUE; foeType = TYPE_FIRE; foeSpecies = SPECIES_VULPIX; foeItem = ITEM_CHARTI_BERRY; hp = 31; atk = 31; def = 30; spAtk = 31; spDef = 30; speed = 30; } + PARAMETRIZE { type = TYPE_BUG; hidden = TRUE; foeType = TYPE_DARK; foeSpecies = SPECIES_UMBREON; foeItem = ITEM_TANGA_BERRY; hp = 31; atk = 2; def = 31; spAtk = 31; spDef = 30; speed = 30; } + PARAMETRIZE { type = TYPE_BUG; hidden = TRUE; foeType = TYPE_DARK; foeSpecies = SPECIES_UMBREON; foeItem = ITEM_TANGA_BERRY; hp = 31; atk = 15; def = 31; spAtk = 31; spDef = 30; speed = 30; } + PARAMETRIZE { type = TYPE_BUG; hidden = TRUE; foeType = TYPE_DARK; foeSpecies = SPECIES_UMBREON; foeItem = ITEM_TANGA_BERRY; hp = 31; atk = 22; def = 31; spAtk = 31; spDef = 30; speed = 30; } + PARAMETRIZE { type = TYPE_BUG; hidden = TRUE; foeType = TYPE_DARK; foeSpecies = SPECIES_UMBREON; foeItem = ITEM_TANGA_BERRY; hp = 31; atk = 31; def = 31; spAtk = 31; spDef = 30; speed = 30; } + PARAMETRIZE { type = TYPE_GHOST; hidden = TRUE; foeType = TYPE_PSYCHIC; foeSpecies = SPECIES_WOBBUFFET; foeItem = ITEM_KASIB_BERRY; hp = 31; atk = 2; def = 31; spAtk = 31; spDef = 30; speed = 31; } + PARAMETRIZE { type = TYPE_GHOST; hidden = TRUE; foeType = TYPE_PSYCHIC; foeSpecies = SPECIES_WOBBUFFET; foeItem = ITEM_KASIB_BERRY; hp = 31; atk = 15; def = 30; spAtk = 31; spDef = 30; speed = 31; } + PARAMETRIZE { type = TYPE_GHOST; hidden = TRUE; foeType = TYPE_PSYCHIC; foeSpecies = SPECIES_WOBBUFFET; foeItem = ITEM_KASIB_BERRY; hp = 31; atk = 22; def = 31; spAtk = 31; spDef = 30; speed = 31; } + PARAMETRIZE { type = TYPE_GHOST; hidden = TRUE; foeType = TYPE_PSYCHIC; foeSpecies = SPECIES_WOBBUFFET; foeItem = ITEM_KASIB_BERRY; hp = 31; atk = 31; def = 30; spAtk = 31; spDef = 30; speed = 31; } + PARAMETRIZE { type = TYPE_STEEL; hidden = TRUE; foeType = TYPE_ROCK; foeSpecies = SPECIES_NOSEPASS; foeItem = ITEM_BABIRI_BERRY; hp = 31; atk = 2; def = 30; spAtk = 30; spDef = 31; speed = 30; } + PARAMETRIZE { type = TYPE_STEEL; hidden = TRUE; foeType = TYPE_ROCK; foeSpecies = SPECIES_NOSEPASS; foeItem = ITEM_BABIRI_BERRY; hp = 31; atk = 15; def = 31; spAtk = 31; spDef = 30; speed = 31; } + PARAMETRIZE { type = TYPE_STEEL; hidden = TRUE; foeType = TYPE_ROCK; foeSpecies = SPECIES_NOSEPASS; foeItem = ITEM_BABIRI_BERRY; hp = 31; atk = 22; def = 30; spAtk = 30; spDef = 31; speed = 30; } + PARAMETRIZE { type = TYPE_STEEL; hidden = TRUE; foeType = TYPE_ROCK; foeSpecies = SPECIES_NOSEPASS; foeItem = ITEM_BABIRI_BERRY; hp = 31; atk = 31; def = 31; spAtk = 31; spDef = 30; speed = 31; } + PARAMETRIZE { type = TYPE_FIRE; hidden = TRUE; foeType = TYPE_GRASS; foeSpecies = SPECIES_TANGELA; foeItem = ITEM_OCCA_BERRY; hp = 31; atk = 2; def = 31; spAtk = 30; spDef = 31; speed = 30; } + PARAMETRIZE { type = TYPE_FIRE; hidden = TRUE; foeType = TYPE_GRASS; foeSpecies = SPECIES_TANGELA; foeItem = ITEM_OCCA_BERRY; hp = 31; atk = 15; def = 30; spAtk = 30; spDef = 31; speed = 30; } + PARAMETRIZE { type = TYPE_FIRE; hidden = TRUE; foeType = TYPE_GRASS; foeSpecies = SPECIES_TANGELA; foeItem = ITEM_OCCA_BERRY; hp = 31; atk = 22; def = 31; spAtk = 30; spDef = 31; speed = 30; } + PARAMETRIZE { type = TYPE_FIRE; hidden = TRUE; foeType = TYPE_GRASS; foeSpecies = SPECIES_TANGELA; foeItem = ITEM_OCCA_BERRY; hp = 31; atk = 31; def = 30; spAtk = 30; spDef = 31; speed = 30; } + PARAMETRIZE { type = TYPE_WATER; hidden = TRUE; foeType = TYPE_ROCK; foeSpecies = SPECIES_NOSEPASS; foeItem = ITEM_PASSHO_BERRY; hp = 31; atk = 2; def = 30; spAtk = 30; spDef = 31; speed = 31; } + PARAMETRIZE { type = TYPE_WATER; hidden = TRUE; foeType = TYPE_ROCK; foeSpecies = SPECIES_NOSEPASS; foeItem = ITEM_PASSHO_BERRY; hp = 31; atk = 15; def = 31; spAtk = 30; spDef = 31; speed = 30; } + PARAMETRIZE { type = TYPE_WATER; hidden = TRUE; foeType = TYPE_ROCK; foeSpecies = SPECIES_NOSEPASS; foeItem = ITEM_PASSHO_BERRY; hp = 31; atk = 22; def = 30; spAtk = 30; spDef = 31; speed = 31; } + PARAMETRIZE { type = TYPE_WATER; hidden = TRUE; foeType = TYPE_ROCK; foeSpecies = SPECIES_NOSEPASS; foeItem = ITEM_PASSHO_BERRY; hp = 31; atk = 31; def = 31; spAtk = 30; spDef = 31; speed = 30; } + PARAMETRIZE { type = TYPE_GRASS; hidden = TRUE; foeType = TYPE_ROCK; foeSpecies = SPECIES_NOSEPASS; foeItem = ITEM_RINDO_BERRY; hp = 30; atk = 2; def = 31; spAtk = 30; spDef = 31; speed = 31; } + PARAMETRIZE { type = TYPE_GRASS; hidden = TRUE; foeType = TYPE_ROCK; foeSpecies = SPECIES_NOSEPASS; foeItem = ITEM_RINDO_BERRY; hp = 30; atk = 15; def = 31; spAtk = 30; spDef = 31; speed = 31; } + PARAMETRIZE { type = TYPE_GRASS; hidden = TRUE; foeType = TYPE_ROCK; foeSpecies = SPECIES_NOSEPASS; foeItem = ITEM_RINDO_BERRY; hp = 30; atk = 22; def = 31; spAtk = 30; spDef = 31; speed = 31; } + PARAMETRIZE { type = TYPE_GRASS; hidden = TRUE; foeType = TYPE_ROCK; foeSpecies = SPECIES_NOSEPASS; foeItem = ITEM_RINDO_BERRY; hp = 30; atk = 31; def = 31; spAtk = 30; spDef = 31; speed = 31; } + PARAMETRIZE { type = TYPE_ELECTRIC; hidden = TRUE; foeType = TYPE_WATER; foeSpecies = SPECIES_SQUIRTLE; foeItem = ITEM_WACAN_BERRY; hp = 31; atk = 2; def = 30; spAtk = 31; spDef = 31; speed = 30; } + PARAMETRIZE { type = TYPE_ELECTRIC; hidden = TRUE; foeType = TYPE_WATER; foeSpecies = SPECIES_SQUIRTLE; foeItem = ITEM_WACAN_BERRY; hp = 30; atk = 15; def = 30; spAtk = 31; spDef = 31; speed = 30; } + PARAMETRIZE { type = TYPE_ELECTRIC; hidden = TRUE; foeType = TYPE_WATER; foeSpecies = SPECIES_SQUIRTLE; foeItem = ITEM_WACAN_BERRY; hp = 31; atk = 22; def = 30; spAtk = 31; spDef = 31; speed = 30; } + PARAMETRIZE { type = TYPE_ELECTRIC; hidden = TRUE; foeType = TYPE_WATER; foeSpecies = SPECIES_SQUIRTLE; foeItem = ITEM_WACAN_BERRY; hp = 30; atk = 31; def = 30; spAtk = 31; spDef = 31; speed = 30; } + PARAMETRIZE { type = TYPE_PSYCHIC; hidden = TRUE; foeType = TYPE_POISON; foeSpecies = SPECIES_KOFFING; foeItem = ITEM_PAYAPA_BERRY; hp = 31; atk = 2; def = 31; spAtk = 31; spDef = 31; speed = 30; } + PARAMETRIZE { type = TYPE_PSYCHIC; hidden = TRUE; foeType = TYPE_POISON; foeSpecies = SPECIES_KOFFING; foeItem = ITEM_PAYAPA_BERRY; hp = 30; atk = 15; def = 31; spAtk = 31; spDef = 31; speed = 30; } + PARAMETRIZE { type = TYPE_PSYCHIC; hidden = TRUE; foeType = TYPE_POISON; foeSpecies = SPECIES_KOFFING; foeItem = ITEM_PAYAPA_BERRY; hp = 31; atk = 22; def = 31; spAtk = 31; spDef = 31; speed = 30; } + PARAMETRIZE { type = TYPE_PSYCHIC; hidden = TRUE; foeType = TYPE_POISON; foeSpecies = SPECIES_KOFFING; foeItem = ITEM_PAYAPA_BERRY; hp = 30; atk = 31; def = 31; spAtk = 31; spDef = 31; speed = 30; } + PARAMETRIZE { type = TYPE_ICE; hidden = TRUE; foeType = TYPE_GRASS; foeSpecies = SPECIES_TANGELA; foeItem = ITEM_YACHE_BERRY; hp = 30; atk = 2; def = 30; spAtk = 31; spDef = 31; speed = 31; } + PARAMETRIZE { type = TYPE_ICE; hidden = TRUE; foeType = TYPE_GRASS; foeSpecies = SPECIES_TANGELA; foeItem = ITEM_YACHE_BERRY; hp = 30; atk = 15; def = 30; spAtk = 31; spDef = 31; speed = 31; } + PARAMETRIZE { type = TYPE_ICE; hidden = TRUE; foeType = TYPE_GRASS; foeSpecies = SPECIES_TANGELA; foeItem = ITEM_YACHE_BERRY; hp = 30; atk = 22; def = 30; spAtk = 31; spDef = 31; speed = 31; } + PARAMETRIZE { type = TYPE_ICE; hidden = TRUE; foeType = TYPE_GRASS; foeSpecies = SPECIES_TANGELA; foeItem = ITEM_YACHE_BERRY; hp = 30; atk = 31; def = 30; spAtk = 31; spDef = 31; speed = 31; } PARAMETRIZE { type = TYPE_MYSTERY; hidden = FALSE; } - PARAMETRIZE { type = TYPE_DRAGON; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 30; atk = 2; def = 31; spAtk = 31; spDef = 31; speed = 31; } - PARAMETRIZE { type = TYPE_DRAGON; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 30; atk = 15; def = 31; spAtk = 31; spDef = 31; speed = 31; } - PARAMETRIZE { type = TYPE_DRAGON; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 30; atk = 22; def = 31; spAtk = 31; spDef = 31; speed = 31; } - PARAMETRIZE { type = TYPE_DRAGON; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 30; atk = 31; def = 31; spAtk = 31; spDef = 31; speed = 31; } - PARAMETRIZE { type = TYPE_DARK; hidden = TRUE; foeType = TYPE_DARK; foeSpecies = SPECIES_UMBREON; hp = 31; atk = 3; def = 31; spAtk = 31; spDef = 31; speed = 31; } - PARAMETRIZE { type = TYPE_DARK; hidden = TRUE; foeType = TYPE_DARK; foeSpecies = SPECIES_UMBREON; hp = 31; atk = 15; def = 31; spAtk = 31; spDef = 31; speed = 31; } - PARAMETRIZE { type = TYPE_DARK; hidden = TRUE; foeType = TYPE_DARK; foeSpecies = SPECIES_UMBREON; hp = 31; atk = 23; def = 31; spAtk = 31; spDef = 31; speed = 31; } - PARAMETRIZE { type = TYPE_DARK; hidden = TRUE; foeType = TYPE_DARK; foeSpecies = SPECIES_UMBREON; hp = 31; atk = 31; def = 31; spAtk = 31; spDef = 31; speed = 31; } + PARAMETRIZE { type = TYPE_DRAGON; hidden = TRUE; foeType = TYPE_DRAGON; foeSpecies = SPECIES_DRATINI; foeItem = ITEM_HABAN_BERRY; hp = 30; atk = 2; def = 31; spAtk = 31; spDef = 31; speed = 31; } + PARAMETRIZE { type = TYPE_DRAGON; hidden = TRUE; foeType = TYPE_DRAGON; foeSpecies = SPECIES_DRATINI; foeItem = ITEM_HABAN_BERRY; hp = 30; atk = 15; def = 31; spAtk = 31; spDef = 31; speed = 31; } + PARAMETRIZE { type = TYPE_DRAGON; hidden = TRUE; foeType = TYPE_DRAGON; foeSpecies = SPECIES_DRATINI; foeItem = ITEM_HABAN_BERRY; hp = 30; atk = 22; def = 31; spAtk = 31; spDef = 31; speed = 31; } + PARAMETRIZE { type = TYPE_DRAGON; hidden = TRUE; foeType = TYPE_DRAGON; foeSpecies = SPECIES_DRATINI; foeItem = ITEM_HABAN_BERRY; hp = 30; atk = 31; def = 31; spAtk = 31; spDef = 31; speed = 31; } + PARAMETRIZE { type = TYPE_DARK; hidden = TRUE; foeType = TYPE_PSYCHIC; foeSpecies = SPECIES_WOBBUFFET; foeItem = ITEM_COLBUR_BERRY; hp = 31; atk = 3; def = 31; spAtk = 31; spDef = 31; speed = 31; } + PARAMETRIZE { type = TYPE_DARK; hidden = TRUE; foeType = TYPE_PSYCHIC; foeSpecies = SPECIES_WOBBUFFET; foeItem = ITEM_COLBUR_BERRY; hp = 31; atk = 15; def = 31; spAtk = 31; spDef = 31; speed = 31; } + PARAMETRIZE { type = TYPE_DARK; hidden = TRUE; foeType = TYPE_PSYCHIC; foeSpecies = SPECIES_WOBBUFFET; foeItem = ITEM_COLBUR_BERRY; hp = 31; atk = 23; def = 31; spAtk = 31; spDef = 31; speed = 31; } + PARAMETRIZE { type = TYPE_DARK; hidden = TRUE; foeType = TYPE_PSYCHIC; foeSpecies = SPECIES_WOBBUFFET; foeItem = ITEM_COLBUR_BERRY; hp = 31; atk = 31; def = 31; spAtk = 31; spDef = 31; speed = 31; } // Any type after Dark shouldn't be part of Hidden Power officially. for (j = TYPE_DARK + 1; j < NUMBER_OF_MON_TYPES; j++) { @@ -83,22 +83,25 @@ SINGLE_BATTLE_TEST("Hidden Power's type is determined by IVs") GIVEN { if (hidden) { - ASSUME(gTypeEffectivenessTable[type][foeType] == UQ_4_12(0.5)); // Foe's Type resists + ASSUME(gTypeEffectivenessTable[type][foeType] == UQ_4_12(2.0)); // Foe's Type resists ASSUME(gSpeciesInfo[foeSpecies].types[0] == gSpeciesInfo[foeSpecies].types[1]); // Foe's pure type - ASSUME(gSpeciesInfo[foeSpecies].types[0] == foeType); // Foe is the resisted type + ASSUME(gSpeciesInfo[foeSpecies].types[0] == foeType); // Foe is the super-effective type + ASSUME(ItemId_GetHoldEffect(foeItem) == HOLD_EFFECT_RESIST_BERRY); // Item is resist berry + ASSUME(ItemId_GetHoldEffectParam(foeItem) == type); // Resist berry of type PLAYER(SPECIES_DUNSPARCE) { HPIV(hp); AttackIV(atk); DefenseIV(def); SpAttackIV(spAtk); SpDefenseIV(spDef); SpeedIV(speed); } } else { PLAYER(SPECIES_DUNSPARCE); } - OPPONENT(foeSpecies); + OPPONENT(foeSpecies) { Item(foeItem); } } WHEN { TURN { MOVE(player, MOVE_HIDDEN_POWER); } } SCENE { // Only test valid Hidden Power types if (hidden) { + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponent); // Check that the item is triggered ANIMATION(ANIM_TYPE_MOVE, MOVE_HIDDEN_POWER, player); HP_BAR(opponent); - MESSAGE("It's not very effective…"); + MESSAGE("It's super effective!"); } } } From c02b7ba828f8140b03c48e7b30b605cbf9866559 Mon Sep 17 00:00:00 2001 From: psf <77138753+pkmnsnfrn@users.noreply.github.com> Date: Mon, 13 Jan 2025 11:52:49 -0800 Subject: [PATCH 5/9] Codify new expansion release schedule (#5916) Co-authored-by: Bassoonian Co-authored-by: Eduardo Quezada --- .github/pull_request_template.md | 3 +- docs/SUMMARY.md | 3 +- docs/team_procedures/schedule.md | 51 +++++++++++++++++++++++++++++ docs/{ => team_procedures}/scope.md | 0 4 files changed, 55 insertions(+), 2 deletions(-) create mode 100644 docs/team_procedures/schedule.md rename docs/{ => team_procedures}/scope.md (100%) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index f083a2a23f65..9a04e86f2bf7 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,11 +1,12 @@ - + ## Description + ## Images diff --git a/docs/SUMMARY.md b/docs/SUMMARY.md index fe13ea72ee78..fb10d5b26598 100644 --- a/docs/SUMMARY.md +++ b/docs/SUMMARY.md @@ -69,4 +69,5 @@ - [Version 0.9.0](changelogs/0.9.x/0.9.0.md) - [Team Procedures]() - [How to make an Expansion version](team_procedures/expansion_versions.md) - - [Scope Guidelines](scope.md) + - [Release Schedule and Process](team_procedures/schedule.md) + - [Scope Guidelines](team_procedures/scope.md) diff --git a/docs/team_procedures/schedule.md b/docs/team_procedures/schedule.md new file mode 100644 index 000000000000..c23d8a51050b --- /dev/null +++ b/docs/team_procedures/schedule.md @@ -0,0 +1,51 @@ +# Release Schedule and Process + +## Version Lifecycle + +### Minor Release (90 days to next Minor Release) +`upcoming` and `master` are synchronized. Minor Release should occur once every three months. Maintainers can vote to do extra Minor Releases for special cases, but this should be considered highly irregular. + +### Patch Release (60 / 30 days to the next Minor Release) +Releases that focus primarily on bugfixes or improvements to the test system. Patch Releases should occur AT LEAST once a month, but can be more frequent than that. + +### Big Feature Freeze (30 days to the next Minor Release) +PRs with the Github label [`type: big feature`](https://github.com/rh-hideout/pokeemerald-expansion/issues?q=sort%3Aupdated-desc+is%3Aopen+label%3A%22type%3A+big+feature%22) will NOT be merged until after the next Minor Release. + +### Merge Freeze (14 days to the next Minor Release) +PRs that DO NOT have the Github labels [`bugfix`](https://github.com/rh-hideout/pokeemerald-expansion/issues?q=sort%3Aupdated-desc+label%3Abugfix) or [`type: cleanup`](https://github.com/rh-hideout/pokeemerald-expansion/issues?q=sort%3Aupdated-desc+label%3A%22type%3A+cleanup%22+) will NOT be merged until after the next Minor Release. + + +### Sample Schedule +| Major | Minor | Patch | Type | Goal Date | +| ----- | ----- | ----- | ------------------ | ----------- | +| 2 | 1 | 0 | Minor | Dec 1 2025 | +| 2 | 1 | 1 | Patch | Dec 31 2025 | +| 2 | 1 | 2 | Patch | Jan 30 2026 | +| 2 | 1 | 2 | Big Feature Freeze | Jan 30 2026 | +| 2 | 1 | 2 | Merge Freeze | Feb 15 2026 | +| 2 | 1 | 3 | Patch | Mar 1 2026 | +| 2 | 2 | 0 | Minor | Mar 1 2026 | + +--- + +## What is a "Big Feature"? +* If the original owner of the PR thinks a feature should be labeled a Big Feature, it is, no questions asked +* If a reviewer thinks a PR is a Big Feature, then it is +* If the two disagree, it can be discussed in a PR thread, and can ultimately be resolved with a Maintainer vote. + +### How To Identify a Big Feature +* **Big diffs**: It's easy for something to go unnoticed in review when it's a tiny part of a massive diff. +* **High-impact**: High-impact changes are harder to review because they often have consequences that aren't obvious to the reviewer. We catch these consequences from users who use upcoming reporting them. +* **Subjective**: Subjective changes are more likely to have differences of opinions between senate members. +* **Pervasive**: The PR touches several different parts of the codebase or is involved in several different parts of the codebase, even if those elements are small. + +--- + +## Release Blocking and Milestones +When an issue or PR is assigned to a [milestone on Github](https://github.com/rh-hideout/pokeemerald-expansion/milestones) by a Maintainer, that means it is "Blocking". If another Maintainer agrees with this, then that version cannot be released until that issue is resolved or PR is merged. + +This designation should be reserved for instances where an existing feature on `upcoming` or `master` is broken and causing problems for users or players. + +Blocking issues or PRs can be deferred to future releases but should be discussed with the Maintainers that assigned the designation in the first place. + +If a version's milestone does not have any issues or PRs assigned to it, that version should be [released](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/docs/team_procedures/expansion_versions.md) as close to the goal date as possible. diff --git a/docs/scope.md b/docs/team_procedures/scope.md similarity index 100% rename from docs/scope.md rename to docs/team_procedures/scope.md From 7af6c4c09e8884927ef51522c24b28a8999fe021 Mon Sep 17 00:00:00 2001 From: Pawkkie <61265402+Pawkkie@users.noreply.github.com> Date: Mon, 13 Jan 2025 20:03:18 -0500 Subject: [PATCH 6/9] Workflow for Scope Discussion (#6022) --- docs/team_procedures/scope.md | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/docs/team_procedures/scope.md b/docs/team_procedures/scope.md index fe6333090f95..e3c736c1cce7 100644 --- a/docs/team_procedures/scope.md +++ b/docs/team_procedures/scope.md @@ -48,10 +48,22 @@ A pull request meets the scope criteria if: ## Discussion Required Categories -Pull Requests that fall into this category should be brought up to maintainers, who will discuss and vote as to whether or not the feature is considered in scope. Considerations for acceptance may include invasiveness of implementation, popularity, ease of maintenance, etc. +Pull Requests that fall into this category are not in scope by default and should be brought up to maintainers, who will discuss and vote as to whether or not the feature is considered in scope. Considerations for acceptance may include invasiveness of implementation, popularity, ease of maintenance, etc. 1. **Developer Ease of Use**: Lowers barrier of entry for developers to use existing behavior 2. **Fangame Features**: Adds a popular feature from other fangames 3. **Popular Non-SS Features**: Exceptions can be made for uniquely popular or requested features (Drowsy, PLA Legend Plate, etc.) 4. **External Program**: External programs like poryscript, porymoves, etc. +## Workflow for Proposed Feature Scope Discussion +For the contributor: +- Make a thread for the feature on Discord +- Describe how the feature fits into this scope document, and why you feel it should be considered +- Optionally include either a draft PR or describe in some detail the proposed implementation. Non-mandatory, but implementation invasiveness, maintenance cost, etc. are major considerations, so use your judgement. The senate may ask for this information during discussion. + +For the senate: +- Make a senate thread for the discussion +- Make and pin a two-week voting poll +- Discuss, conclude, and cast votes before the two-week deadline +- Inform contributor as to the results and reasons in their thread +- Amend this scope document if necessary From 1c3ce75a60268f0b9870dfdde2e0c78d96374494 Mon Sep 17 00:00:00 2001 From: Alex <93446519+AlexOn1ine@users.noreply.github.com> Date: Tue, 14 Jan 2025 20:01:10 +0100 Subject: [PATCH 7/9] Wrong undefs (#6024) --- src/battle_script_commands.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 32f2b1138b5f..bbc58f430d14 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -1913,8 +1913,8 @@ s32 CalcCritChanceStageArgs(u32 battlerAtk, u32 battlerDef, u32 move, bool32 rec return critChance; } -#undef CRIT_BLOCKED -#undef ALWAYS_CRITS +#undef CRITICAL_HIT_BLOCKED +#undef CRITICAL_HIT_ALWAYS s32 CalcCritChanceStage(u32 battlerAtk, u32 battlerDef, u32 move, bool32 recordAbility) { From fd26d3a4068ecd5206c4f86d2323acd319565cbc Mon Sep 17 00:00:00 2001 From: ghoulslash <41651341+ghoulslash@users.noreply.github.com> Date: Wed, 15 Jan 2025 09:20:31 -0500 Subject: [PATCH 8/9] Fix Redirection Abilities Not Drawing in Ally Moves (#6026) Co-authored-by: ghoulslash --- include/config/battle.h | 1 + src/battle_util.c | 59 +++++++++++++++++++---------- test/battle/ability/lightning_rod.c | 26 +++++++++++++ test/battle/move_effect/pledge.c | 2 +- 4 files changed, 66 insertions(+), 22 deletions(-) diff --git a/include/config/battle.h b/include/config/battle.h index cdb0caacfee9..8853d0432472 100644 --- a/include/config/battle.h +++ b/include/config/battle.h @@ -142,6 +142,7 @@ #define B_SYMBIOSIS_GEMS GEN_LATEST // In Gen7+, Symbiosis passes an item after a gem-boosted attack. Previously, items are passed before the gem-boosted attack hits, making the item effect apply. #define B_ABSORBING_ABILITY_STRING GEN_LATEST // In Gen5+, the abilities that absorb moves of a certain type use a generic string for stat increases and decreases. #define B_REDIRECT_ABILITY_IMMUNITY GEN_LATEST // In Gen5+, Pokémon with Lightning Rod/Storm Drain become immune to Electric/Water-type moves and increase their Sp. Attack by 1 stage on top of the redirecting effect. +#define B_REDIRECT_ABILITY_ALLIES GEN_LATEST // In Gen4+, Lightning Rod/Storm Drain redirect ally's moves as well. #define B_LEAF_GUARD_PREVENTS_REST GEN_LATEST // In Gen5+, Leaf Guard prevents the use of Rest in harsh sunlight. #define B_SNOW_WARNING GEN_LATEST // In Gen9+, Snow Warning will summon snow instead of hail. #define B_TRANSISTOR_BOOST GEN_LATEST // In Gen9+, Transistor will only boost Electric-type moves by 1.3x as opposed to 1.5x. diff --git a/src/battle_util.c b/src/battle_util.c index 2c53b2282d4e..6d56a40e53d7 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -126,7 +126,7 @@ bool32 IsAffectedByFollowMe(u32 battlerAtk, u32 defSide, u32 move) // Functions void HandleAction_UseMove(void) { - u32 battler, i, side, moveType, var = 4; + u32 battler, i, side, moveType, ability, var = MAX_BATTLERS_COUNT; u16 moveTarget; gBattlerAttacker = gBattlerByTurnOrder[gCurrentTurnActionNumber]; @@ -217,6 +217,7 @@ void HandleAction_UseMove(void) // choose target side = BATTLE_OPPOSITE(GetBattlerSide(gBattlerAttacker)); + ability = GetBattlerAbility(gBattleStruct->moveTarget[gBattlerAttacker]); if (IsAffectedByFollowMe(gBattlerAttacker, side, gCurrentMove) && moveTarget == MOVE_TARGET_SELECTED && GetBattlerSide(gBattlerAttacker) != GetBattlerSide(gSideTimers[side].followmeTarget)) @@ -226,16 +227,18 @@ void HandleAction_UseMove(void) else if (IsDoubleBattle() && gSideTimers[side].followmeTimer == 0 && (!IS_MOVE_STATUS(gCurrentMove) || (moveTarget != MOVE_TARGET_USER && moveTarget != MOVE_TARGET_ALL_BATTLERS)) - && ((GetBattlerAbility(*(gBattleStruct->moveTarget + gBattlerAttacker)) != ABILITY_LIGHTNING_ROD && moveType == TYPE_ELECTRIC) - || (GetBattlerAbility(*(gBattleStruct->moveTarget + gBattlerAttacker)) != ABILITY_STORM_DRAIN && moveType == TYPE_WATER))) + && ((ability != ABILITY_LIGHTNING_ROD && moveType == TYPE_ELECTRIC) + || (ability != ABILITY_STORM_DRAIN && moveType == TYPE_WATER))) { - side = GetBattlerSide(gBattlerAttacker); + // Find first battler that redirects the move (in turn order) for (battler = 0; battler < gBattlersCount; battler++) { - if (side != GetBattlerSide(battler) - && *(gBattleStruct->moveTarget + gBattlerAttacker) != battler - && ((GetBattlerAbility(battler) == ABILITY_LIGHTNING_ROD && moveType == TYPE_ELECTRIC) - || (GetBattlerAbility(battler) == ABILITY_STORM_DRAIN && moveType == TYPE_WATER)) + ability = GetBattlerAbility(battler); + if ((B_REDIRECT_ABILITY_ALLIES >= GEN_4 || !IsAlly(gBattlerAttacker, battler)) + && battler != gBattlerAttacker + && gBattleStruct->moveTarget[gBattlerAttacker] != battler + && ((ability == ABILITY_LIGHTNING_ROD && moveType == TYPE_ELECTRIC) + || (ability == ABILITY_STORM_DRAIN && moveType == TYPE_WATER)) && GetBattlerTurnOrderNum(battler) < var && gMovesInfo[gCurrentMove].effect != EFFECT_SNIPE_SHOT && gMovesInfo[gCurrentMove].effect != EFFECT_PLEDGE @@ -245,7 +248,7 @@ void HandleAction_UseMove(void) var = GetBattlerTurnOrderNum(battler); } } - if (var == 4) + if (var == MAX_BATTLERS_COUNT) { if (moveTarget & MOVE_TARGET_RANDOM) { @@ -8446,22 +8449,36 @@ u32 GetMoveTarget(u16 move, u8 setTarget) } else { + u32 battlerAbilityOnField = 0; + targetBattler = SetRandomTarget(gBattlerAttacker); - if (moveType == TYPE_ELECTRIC - && IsAbilityOnOpposingSide(gBattlerAttacker, ABILITY_LIGHTNING_ROD) - && GetBattlerAbility(targetBattler) != ABILITY_LIGHTNING_ROD) + if (moveType == TYPE_ELECTRIC && GetBattlerAbility(targetBattler) != ABILITY_LIGHTNING_ROD) { - targetBattler ^= BIT_FLANK; - RecordAbilityBattle(targetBattler, gBattleMons[targetBattler].ability); - gSpecialStatuses[targetBattler].lightningRodRedirected = TRUE; + if (B_REDIRECT_ABILITY_ALLIES >= GEN_4) + battlerAbilityOnField = IsAbilityOnField(ABILITY_LIGHTNING_ROD); + else + battlerAbilityOnField = IsAbilityOnOpposingSide(targetBattler, ABILITY_LIGHTNING_ROD); + + if (battlerAbilityOnField > 0) + { + targetBattler = battlerAbilityOnField - 1; + RecordAbilityBattle(targetBattler, gBattleMons[targetBattler].ability); + gSpecialStatuses[targetBattler].lightningRodRedirected = TRUE; + } } - else if (moveType == TYPE_WATER - && IsAbilityOnOpposingSide(gBattlerAttacker, ABILITY_STORM_DRAIN) - && GetBattlerAbility(targetBattler) != ABILITY_STORM_DRAIN) + else if (moveType == TYPE_WATER && GetBattlerAbility(targetBattler) != ABILITY_STORM_DRAIN) { - targetBattler ^= BIT_FLANK; - RecordAbilityBattle(targetBattler, gBattleMons[targetBattler].ability); - gSpecialStatuses[targetBattler].stormDrainRedirected = TRUE; + if (B_REDIRECT_ABILITY_ALLIES >= GEN_4) + battlerAbilityOnField = IsAbilityOnField(ABILITY_STORM_DRAIN); + else + battlerAbilityOnField = IsAbilityOnOpposingSide(targetBattler, ABILITY_STORM_DRAIN); + + if (battlerAbilityOnField > 0) + { + targetBattler = battlerAbilityOnField - 1; + RecordAbilityBattle(targetBattler, gBattleMons[targetBattler].ability); + gSpecialStatuses[targetBattler].lightningRodRedirected = TRUE; + } } } break; diff --git a/test/battle/ability/lightning_rod.c b/test/battle/ability/lightning_rod.c index c719ee145d41..38903f373b20 100644 --- a/test/battle/ability/lightning_rod.c +++ b/test/battle/ability/lightning_rod.c @@ -71,3 +71,29 @@ DOUBLE_BATTLE_TEST("Lightning Rod forces single-target Electric-type moves to ta ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, opponentRight); } } + +DOUBLE_BATTLE_TEST("Lightning Rod redirects an ally's attack") +{ + GIVEN { + ASSUME(gMovesInfo[MOVE_THUNDERBOLT].type == TYPE_ELECTRIC); + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_RAICHU) { Ability(ABILITY_LIGHTNING_ROD); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponentRight, MOVE_THUNDERBOLT, target: playerLeft); } + } SCENE { + MESSAGE("The opposing Wobbuffet used Thunderbolt!"); + if (B_REDIRECT_ABILITY_ALLIES >= GEN_5) + { + NOT HP_BAR(playerLeft); + ABILITY_POPUP(opponentLeft, ABILITY_LIGHTNING_ROD); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentLeft); + MESSAGE("The opposing Raichu's Sp. Atk rose!"); + } + else + { + HP_BAR(playerLeft); + } + } +} diff --git a/test/battle/move_effect/pledge.c b/test/battle/move_effect/pledge.c index 726adc81521f..4441fdccb966 100644 --- a/test/battle/move_effect/pledge.c +++ b/test/battle/move_effect/pledge.c @@ -886,7 +886,7 @@ DOUBLE_BATTLE_TEST("Pledge move combo doesn't trigger on opponent's Pledge move { GIVEN { ASSUME(gMovesInfo[MOVE_ELECTRIFY].effect == EFFECT_ELECTRIFY); - PLAYER(SPECIES_MAROWAK) { Ability(ABILITY_LIGHTNING_ROD); } + PLAYER(SPECIES_ELECTIVIRE) { Ability(ABILITY_MOTOR_DRIVE); } PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WYNAUT); From 21d2e40f0aa0aa5bf56b4f78099d8184a7453b14 Mon Sep 17 00:00:00 2001 From: Mercy <98864243+MercedesCL@users.noreply.github.com> Date: Fri, 17 Jan 2025 00:23:12 -0500 Subject: [PATCH 9/9] Fix Match Call Behavior (#5931) (#6033) --- src/battle_setup.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/battle_setup.c b/src/battle_setup.c index 0c13fcdd09ca..37204c1d8d80 100644 --- a/src/battle_setup.c +++ b/src/battle_setup.c @@ -1742,8 +1742,8 @@ static bool32 UpdateRandomTrainerRematches(const struct RematchTrainer *table, u for (i = 0; i <= REMATCH_SPECIAL_TRAINER_START; i++) { - if (DoesCurrentMapMatchRematchTrainerMap(i,table,mapGroup,mapNum) && !IsRematchForbidden(i)) - continue; + if (!DoesCurrentMapMatchRematchTrainerMap(i,table,mapGroup,mapNum) || IsRematchForbidden(i)) + continue; // Only check permitted trainers within the current map. if (gSaveBlock1Ptr->trainerRematches[i] != 0) {