diff --git a/graphics/types/none.png b/graphics/types/none.png new file mode 100644 index 0000000000..a2ea01d556 Binary files /dev/null and b/graphics/types/none.png differ diff --git a/graphics_file_rules.mk b/graphics_file_rules.mk index 9f5d9d6c79..1b514b8ed3 100644 --- a/graphics_file_rules.mk +++ b/graphics_file_rules.mk @@ -22,7 +22,7 @@ STARTERGFXDIR := graphics/starter_choose NAMINGGFXDIR := graphics/naming_screen SPINDAGFXDIR := graphics/pokemon/spinda/spots -types := normal fight flying poison ground rock bug ghost steel mystery fire water grass electric psychic ice dragon dark fairy stellar +types := none normal fight flying poison ground rock bug ghost steel mystery fire water grass electric psychic ice dragon dark fairy stellar contest_types := cool beauty cute smart tough ### Tilesets ### diff --git a/include/battle_main.h b/include/battle_main.h index 9469e63efe..bff396a13f 100644 --- a/include/battle_main.h +++ b/include/battle_main.h @@ -77,6 +77,7 @@ extern const struct SpriteTemplate gUnusedBattleInitSprite; extern const struct OamData gOamData_BattleSpriteOpponentSide; extern const struct OamData gOamData_BattleSpritePlayerSide; extern const struct TypeInfo gTypesInfo[NUMBER_OF_MON_TYPES]; +extern const uq4_12_t gTypeEffectivenessTable[NUMBER_OF_MON_TYPES][NUMBER_OF_MON_TYPES]; extern const u8 gStatusConditionString_PoisonJpn[8]; extern const u8 gStatusConditionString_SleepJpn[8]; diff --git a/include/config/battle.h b/include/config/battle.h index 1a272f358f..c072cb7993 100644 --- a/include/config/battle.h +++ b/include/config/battle.h @@ -43,7 +43,7 @@ #define B_GHOSTS_ESCAPE GEN_LATEST // In Gen6+, abilities like Shadow Tag or moves like Mean Look fail on Ghost-type Pokémon. They can also escape any Wild Battle. #define B_PARALYZE_ELECTRIC GEN_LATEST // In Gen6+, Electric-type Pokémon can't be paralyzed. #define B_POWDER_GRASS GEN_LATEST // In Gen6+, Grass-type Pokémon are immune to powder and spore moves. -#define B_UPDATED_TYPE_MATCHUPS GEN_LATEST // Updates Type matchups. Refer to sTypeEffectivenessTable for details. +#define B_UPDATED_TYPE_MATCHUPS GEN_LATEST // Updates Type matchups. src/data/types_info.h for details. #define B_PRANKSTER_DARK_TYPES GEN_LATEST // In Gen7+, Prankster-elevated status moves do not affect Dark type Pokémon. #define B_SHEER_COLD_IMMUNITY GEN_LATEST // In Gen7+, Ice-types are immune to Sheer Cold #define B_ROOST_PURE_FLYING GEN_LATEST // In Gen5+, Roost makes pure Flying-types into Normal-type. diff --git a/include/constants/pokemon.h b/include/constants/pokemon.h index 4bc1bd348e..6d50fac4df 100644 --- a/include/constants/pokemon.h +++ b/include/constants/pokemon.h @@ -2,28 +2,28 @@ #define GUARD_CONSTANTS_POKEMON_H // Pokémon types -#define TYPE_NONE 255 -#define TYPE_NORMAL 0 -#define TYPE_FIGHTING 1 -#define TYPE_FLYING 2 -#define TYPE_POISON 3 -#define TYPE_GROUND 4 -#define TYPE_ROCK 5 -#define TYPE_BUG 6 -#define TYPE_GHOST 7 -#define TYPE_STEEL 8 -#define TYPE_MYSTERY 9 -#define TYPE_FIRE 10 -#define TYPE_WATER 11 -#define TYPE_GRASS 12 -#define TYPE_ELECTRIC 13 -#define TYPE_PSYCHIC 14 -#define TYPE_ICE 15 -#define TYPE_DRAGON 16 -#define TYPE_DARK 17 -#define TYPE_FAIRY 18 -#define TYPE_STELLAR 19 -#define NUMBER_OF_MON_TYPES 20 +#define TYPE_NONE 0 +#define TYPE_NORMAL 1 +#define TYPE_FIGHTING 2 +#define TYPE_FLYING 3 +#define TYPE_POISON 4 +#define TYPE_GROUND 5 +#define TYPE_ROCK 6 +#define TYPE_BUG 7 +#define TYPE_GHOST 8 +#define TYPE_STEEL 9 +#define TYPE_MYSTERY 10 +#define TYPE_FIRE 11 +#define TYPE_WATER 12 +#define TYPE_GRASS 13 +#define TYPE_ELECTRIC 14 +#define TYPE_PSYCHIC 15 +#define TYPE_ICE 16 +#define TYPE_DRAGON 17 +#define TYPE_DARK 18 +#define TYPE_FAIRY 19 +#define TYPE_STELLAR 20 +#define NUMBER_OF_MON_TYPES 21 // Pokémon egg groups #define EGG_GROUP_NONE 0 diff --git a/include/data.h b/include/data.h index b18dbf220f..a273f15287 100644 --- a/include/data.h +++ b/include/data.h @@ -109,6 +109,9 @@ struct TypeInfo u8 palette; u16 zMove; u16 maxMove; + u16 teraTypeRGBValue; // Most values pulled from the Tera type icon palette. + u16 damageCategory:2; // Used for B_PHYSICAL_SPECIAL_SPLIT <= GEN_3 + u16 padding:14; const u32 *const paletteTMHM; //u16 enhanceItem; //u16 berry; diff --git a/include/test/battle.h b/include/test/battle.h index c4bd89f91b..95a67a4607 100644 --- a/include/test/battle.h +++ b/include/test/battle.h @@ -824,6 +824,12 @@ struct moveWithPP { #define SpAttack(spAttack) SpAttack_(__LINE__, spAttack) #define SpDefense(spDefense) SpDefense_(__LINE__, spDefense) #define Speed(speed) Speed_(__LINE__, speed) +#define HPIV(hpIV) HPIV_(__LINE__, hpIV) +#define AttackIV(attackIV) AttackIV_(__LINE__, attackIV) +#define DefenseIV(defenseIV) DefenseIV_(__LINE__, defenseIV) +#define SpAttackIV(spAttackIV) SpAttackIV_(__LINE__, spAttackIV) +#define SpDefenseIV(spDefenseIV) SpDefenseIV_(__LINE__, spDefenseIV) +#define SpeedIV(speedIV) SpeedIV_(__LINE__, speedIV) #define Item(item) Item_(__LINE__, item) #define Moves(move1, ...) do { u16 moves_[MAX_MON_MOVES] = {move1, __VA_ARGS__}; Moves_(__LINE__, moves_); } while(0) #define MovesWithPP(movewithpp1, ...) MovesWithPP_(__LINE__, (struct moveWithPP[MAX_MON_MOVES]) {movewithpp1, __VA_ARGS__}) @@ -854,6 +860,12 @@ void Defense_(u32 sourceLine, u32 defense); void SpAttack_(u32 sourceLine, u32 spAttack); void SpDefense_(u32 sourceLine, u32 spDefense); void Speed_(u32 sourceLine, u32 speed); +void HPIV_(u32 sourceLine, u32 hpIV); +void AttackIV_(u32 sourceLine, u32 attackIV); +void DefenseIV_(u32 sourceLine, u32 defenseIV); +void SpAttackIV_(u32 sourceLine, u32 spAttackIV); +void SpDefenseIV_(u32 sourceLine, u32 spDefenseIV); +void SpeedIV_(u32 sourceLine, u32 speedIV); void Item_(u32 sourceLine, u32 item); void Moves_(u32 sourceLine, u16 moves[MAX_MON_MOVES]); void MovesWithPP_(u32 sourceLine, struct moveWithPP moveWithPP[MAX_MON_MOVES]); diff --git a/src/battle_main.c b/src/battle_main.c index 9fa55a3d39..d5bbce37ec 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -296,336 +296,7 @@ const struct OamData gOamData_BattleSpritePlayerSide = static const s8 sCenterToCornerVecXs[8] ={-32, -16, -16, -32, -32}; -#if B_EXPANDED_TYPE_NAMES == TRUE -#define HANDLE_EXPANDED_TYPE_NAME(_name, ...) _(DEFAULT(_name, __VA_ARGS__)) -#else -#define HANDLE_EXPANDED_TYPE_NAME(_name, ...) _(_name) -#endif - -// .generic is large enough that the text for TYPE_ELECTRIC will exceed TEXT_BUFF_ARRAY_COUNT. -const struct TypeInfo gTypesInfo[NUMBER_OF_MON_TYPES] = -{ - [TYPE_NORMAL] = - { - .name = _("Normal"), - .generic = _("a NORMAL move"), - .palette = 13, - .zMove = MOVE_BREAKNECK_BLITZ, - .maxMove = MOVE_MAX_STRIKE, - .paletteTMHM = gItemIconPalette_NormalTMHM, - //.enhanceItem = ITEM_SILK_SCARF, - //.berry = ITEM_CHILAN_BERRY, - //.gem = ITEM_NORMAL_GEM, - //.zCrystal = ITEM_NORMALIUM_Z, - //.teraShard = ITEM_NORMAL_TERA_SHARD, - //.arceusForm = SPECIES_ARCEUS_NORMAL, - }, - [TYPE_FIGHTING] = - { - .name = HANDLE_EXPANDED_TYPE_NAME("Fight", "Fighting"), - .generic = _("a FIGHTING move"), - .palette = 13, - .zMove = MOVE_ALL_OUT_PUMMELING, - .maxMove = MOVE_MAX_KNUCKLE, - .paletteTMHM = gItemIconPalette_FightingTMHM, - //.enhanceItem = ITEM_BLACK_BELT, - //.berry = ITEM_CHOPLE_BERRY, - //.gem = ITEM_FIGHTING_GEM, - //.zCrystal = ITEM_FIGHTINIUM_Z, - //.plate = ITEM_FIST_PLATE, - //.memory = ITEM_FIGHTING_MEMORY, - //.teraShard = ITEM_FIGHTING_TERA_SHARD, - //.arceusForm = SPECIES_ARCEUS_FIGHTING, - }, - [TYPE_FLYING] = - { - .name = _("Flying"), - .generic = _("a FLYING move"), - .palette = 14, - .zMove = MOVE_SUPERSONIC_SKYSTRIKE, - .maxMove = MOVE_MAX_AIRSTREAM, - .paletteTMHM = gItemIconPalette_FlyingTMHM, - //.enhanceItem = ITEM_SHARP_BEAK, - //.berry = ITEM_COBA_BERRY, - //.gem = ITEM_FLYING_GEM, - //.zCrystal = ITEM_FLYINIUM_Z, - //.plate = ITEM_SKY_PLATE, - //.memory = ITEM_FLYING_MEMORY, - //.teraShard = ITEM_FLYING_TERA_SHARD, - //.arceusForm = SPECIES_ARCEUS_FLYING, - }, - [TYPE_POISON] = - { - .name = _("Poison"), - .generic = _("a POISON move"), - .palette = 14, - .zMove = MOVE_ACID_DOWNPOUR, - .maxMove = MOVE_MAX_OOZE, - .paletteTMHM = gItemIconPalette_PoisonTMHM, - //.enhanceItem = ITEM_POISON_BARB, - //.berry = ITEM_KEBIA_BERRY, - //.gem = ITEM_POISON_GEM, - //.zCrystal = ITEM_POISONIUM_Z, - //.plate = ITEM_TOXIC_PLATE, - //.memory = ITEM_POISON_MEMORY, - //.teraShard = ITEM_POISON_TERA_SHARD, - //.arceusForm = SPECIES_ARCEUS_POISON, - }, - [TYPE_GROUND] = - { - .name = _("Ground"), - .generic = _("a GROUND move"), - .palette = 13, - .zMove = MOVE_TECTONIC_RAGE, - .maxMove = MOVE_MAX_QUAKE, - .paletteTMHM = gItemIconPalette_GroundTMHM, - //.enhanceItem = ITEM_SOFT_SAND, - //.berry = ITEM_SHUCA_BERRY, - //.gem = ITEM_GROUND_GEM, - //.zCrystal = ITEM_GROUNDIUM_Z, - //.plate = ITEM_EARTH_PLATE, - //.memory = ITEM_GROUND_MEMORY, - //.teraShard = ITEM_GROUND_TERA_SHARD, - //.arceusForm = SPECIES_ARCEUS_GROUND, - }, - [TYPE_ROCK] = - { - .name = _("Rock"), - .generic = _("a ROCK move"), - .palette = 13, - .zMove = MOVE_CONTINENTAL_CRUSH, - .maxMove = MOVE_MAX_ROCKFALL, - .paletteTMHM = gItemIconPalette_RockTMHM, - //.enhanceItem = ITEM_HARD_STONE, - //.berry = ITEM_CHARTI_BERRY, - //.gem = ITEM_ROCK_GEM, - //.zCrystal = ITEM_ROCKIUM_Z, - //.plate = ITEM_STONE_PLATE, - //.memory = ITEM_ROCK_MEMORY, - //.teraShard = ITEM_ROCK_TERA_SHARD, - //.arceusForm = SPECIES_ARCEUS_ROCK, - }, - [TYPE_BUG] = - { - .name = _("Bug"), - .generic = _("a BUG move"), - .palette = 15, - .zMove = MOVE_SAVAGE_SPIN_OUT, - .maxMove = MOVE_MAX_FLUTTERBY, - .paletteTMHM = gItemIconPalette_BugTMHM, - //.enhanceItem = ITEM_SILVER_POWDER, - //.berry = ITEM_TANGA_BERRY, - //.gem = ITEM_BUG_GEM, - //.zCrystal = ITEM_BUGINIUM_Z, - //.plate = ITEM_INSECT_PLATE, - //.memory = ITEM_BUG_MEMORY, - //.teraShard = ITEM_BUG_TERA_SHARD, - //.arceusForm = SPECIES_ARCEUS_BUG, - }, - [TYPE_GHOST] = - { - .name = _("Ghost"), - .generic = _("a GHOST move"), - .palette = 14, - .zMove = MOVE_NEVER_ENDING_NIGHTMARE, - .maxMove = MOVE_MAX_PHANTASM, - .paletteTMHM = gItemIconPalette_GhostTMHM, - //.enhanceItem = ITEM_SPELL_TAG, - //.berry = ITEM_KASIB_BERRY, - //.gem = ITEM_GHOST_GEM, - //.zCrystal = ITEM_GHOSTIUM_Z, - //.plate = ITEM_SPOOKY_PLATE, - //.memory = ITEM_GHOST_MEMORY, - //.teraShard = ITEM_GHOST_TERA_SHARD, - //.arceusForm = SPECIES_ARCEUS_GHOST, - }, - [TYPE_STEEL] = - { - .name = _("Steel"), - .generic = _("a STEEL move"), - .palette = 13, - .zMove = MOVE_CORKSCREW_CRASH, - .maxMove = MOVE_MAX_STEELSPIKE, - .paletteTMHM = gItemIconPalette_SteelTMHM, - //.enhanceItem = ITEM_METAL_COAT, - //.berry = ITEM_BABIRI_BERRY, - //.gem = ITEM_STEEL_GEM, - //.zCrystal = ITEM_STEELIUM_Z, - //.plate = ITEM_IRON_PLATE, - //.memory = ITEM_STEEL_MEMORY, - //.teraShard = ITEM_STEEL_TERA_SHARD, - //.arceusForm = SPECIES_ARCEUS_STEEL, - }, - [TYPE_MYSTERY] = - { - .name = _("???"), - .generic = _("a ??? move"), - .palette = 15, - }, - [TYPE_FIRE] = - { - .name = _("Fire"), - .generic = _("a FIRE move"), - .palette = 13, - .zMove = MOVE_INFERNO_OVERDRIVE, - .maxMove = MOVE_MAX_FLARE, - .paletteTMHM = gItemIconPalette_FireTMHM, - //.enhanceItem = ITEM_CHARCOAL, - //.berry = ITEM_OCCA_BERRY, - //.gem = ITEM_FIRE_GEM, - //.zCrystal = ITEM_FIRIUM_Z, - //.plate = ITEM_FLAME_PLATE, - //.memory = ITEM_FIRE_MEMORY, - //.teraShard = ITEM_FIRE_TERA_SHARD, - //.arceusForm = SPECIES_ARCEUS_FIRE, - }, - [TYPE_WATER] = - { - .name = _("Water"), - .generic = _("a WATER move"), - .palette = 14, - .zMove = MOVE_HYDRO_VORTEX, - .maxMove = MOVE_MAX_GEYSER, - .paletteTMHM = gItemIconPalette_WaterTMHM, - //.enhanceItem = ITEM_MYSTIC_WATER, - //.berry = ITEM_PASSHO_BERRY, - //.gem = ITEM_WATER_GEM, - //.zCrystal = ITEM_WATERIUM_Z, - //.plate = ITEM_SPLASH_PLATE, - //.memory = ITEM_WATER_MEMORY, - //.teraShard = ITEM_WATER_TERA_SHARD, - //.arceusForm = SPECIES_ARCEUS_WATER, - }, - [TYPE_GRASS] = - { - .name = _("Grass"), - .generic = _("a GRASS move"), - .palette = 15, - .zMove = MOVE_BLOOM_DOOM, - .maxMove = MOVE_MAX_OVERGROWTH, - .paletteTMHM = gItemIconPalette_GrassTMHM, - //.enhanceItem = ITEM_MIRACLE_SEED, - //.berry = ITEM_RINDO_BERRY, - //.gem = ITEM_GRASS_GEM, - //.zCrystal = ITEM_GRASSIUM_Z, - //.plate = ITEM_MEADOW_PLATE, - //.memory = ITEM_GRASS_MEMORY, - //.teraShard = ITEM_GRASS_TERA_SHARD, - //.arceusForm = SPECIES_ARCEUS_GRASS, - }, - [TYPE_ELECTRIC] = - { - .name = HANDLE_EXPANDED_TYPE_NAME("Electr", "Electric"), - .generic = _("an ELECTRIC move"), - .palette = 13, - .zMove = MOVE_GIGAVOLT_HAVOC, - .maxMove = MOVE_MAX_LIGHTNING, - .paletteTMHM = gItemIconPalette_ElectricTMHM, - //.enhanceItem = ITEM_MAGNET, - //.berry = ITEM_WACAN_BERRY, - //.gem = ITEM_ELECTRIC_GEM, - //.zCrystal = ITEM_ELECTRIUM_Z, - //.plate = ITEM_ZAP_PLATE, - //.memory = ITEM_ELECTRIC_MEMORY, - //.teraShard = ITEM_ELECTRIC_TERA_SHARD, - //.arceusForm = SPECIES_ARCEUS_ELECTRIC, - }, - [TYPE_PSYCHIC] = - { - .name = HANDLE_EXPANDED_TYPE_NAME("Psychc", "Psychic"), - .generic = _("a PSYCHIC move"), - .palette = 14, - .zMove = MOVE_SHATTERED_PSYCHE, - .maxMove = MOVE_MAX_MINDSTORM, - .paletteTMHM = gItemIconPalette_PsychicTMHM, - //.enhanceItem = ITEM_TWISTED_SPOON, - //.berry = ITEM_PAYAPA_BERRY, - //.gem = ITEM_PSYCHIC_GEM, - //.zCrystal = ITEM_PSYCHIUM_Z, - //.plate = ITEM_MIND_PLATE, - //.memory = ITEM_PSYCHIC_MEMORY, - //.teraShard = ITEM_PSYCHIC_TERA_SHARD, - //.arceusForm = SPECIES_ARCEUS_PSYCHIC, - }, - [TYPE_ICE] = - { - .name = _("Ice"), - .generic = _("an ICE move"), - .palette = 14, - .zMove = MOVE_SUBZERO_SLAMMER, - .maxMove = MOVE_MAX_HAILSTORM, - .paletteTMHM = gItemIconPalette_IceTMHM, - //.enhanceItem = ITEM_NEVER_MELT_ICE, - //.berry = ITEM_YACHE_BERRY, - //.gem = ITEM_ICE_GEM, - //.zCrystal = ITEM_ICIUM_Z, - //.plate = ITEM_ICICLE_PLATE, - //.memory = ITEM_ICE_MEMORY, - //.teraShard = ITEM_ICE_TERA_SHARD, - //.arceusForm = SPECIES_ARCEUS_ICE, - }, - [TYPE_DRAGON] = - { - .name = _("Dragon"), - .generic = _("a DRAGON move"), - .palette = 15, - .zMove = MOVE_DEVASTATING_DRAKE, - .maxMove = MOVE_MAX_WYRMWIND, - .paletteTMHM = gItemIconPalette_DragonTMHM, - //.enhanceItem = ITEM_DRAGON_FANG, - //.berry = ITEM_HABAN_BERRY, - //.gem = ITEM_DRAGON_GEM, - //.zCrystal = ITEM_DRAGONIUM_Z, - //.plate = ITEM_DRACO_PLATE, - //.memory = ITEM_DRAGON_MEMORY, - //.teraShard = ITEM_DRAGON_TERA_SHARD, - //.arceusForm = SPECIES_ARCEUS_DRAGON, - }, - [TYPE_DARK] = - { - .name = _("Dark"), - .generic = _("a DARK move"), - .palette = 13, - .zMove = MOVE_BLACK_HOLE_ECLIPSE, - .maxMove = MOVE_MAX_DARKNESS, - .paletteTMHM = gItemIconPalette_DarkTMHM, - //.enhanceItem = ITEM_BLACK_GLASSES, - //.berry = ITEM_COLBUR_BERRY, - //.gem = ITEM_DARK_GEM, - //.zCrystal = ITEM_DARKINIUM_Z, - //.plate = ITEM_DREAD_PLATE, - //.memory = ITEM_DARK_MEMORY, - //.teraShard = ITEM_DARK_TERA_SHARD, - //.arceusForm = SPECIES_ARCEUS_DARK, - }, - [TYPE_FAIRY] = - { - .name = _("Fairy"), - .generic = _("a FAIRY move"), - .palette = 14, - .zMove = MOVE_TWINKLE_TACKLE, - .maxMove = MOVE_MAX_STARFALL, - .paletteTMHM = gItemIconPalette_FairyTMHM, - //.enhanceItem = ITEM_FAIRY_FEATHER, - //.berry = ITEM_ROSELI_BERRY, - //.gem = ITEM_FAIRY_GEM, - //.zCrystal = ITEM_FAIRIUM_Z, - //.plate = ITEM_PIXIE_PLATE, - //.memory = ITEM_FAIRY_MEMORY, - //.teraShard = ITEM_FAIRY_TERA_SHARD, - //.arceusForm = SPECIES_ARCEUS_FAIRY, - }, - [TYPE_STELLAR] = - { - .name = HANDLE_EXPANDED_TYPE_NAME("Stellr", "Stellar"), - .generic = _("a STELLAR move"), - .palette = 15, - .zMove = MOVE_BREAKNECK_BLITZ, - .maxMove = MOVE_MAX_STRIKE, - .paletteTMHM = gItemIconPalette_NormalTMHM, // failsafe - // .teraShard = ITEM_STELLAR_TERA_SHARD, - }, -}; +#include "data/types_info.h" // extra args are money and ball #define TRAINER_CLASS(trainerClass, trainerName, ...) \ @@ -6066,9 +5737,9 @@ void SetTypeBeforeUsingMove(u32 move, u32 battlerAtk) | ((gBattleMons[battlerAtk].spAttackIV & 1) << 4) | ((gBattleMons[battlerAtk].spDefenseIV & 1) << 5); - // Subtract 4 instead of 1 below because 3 types are excluded (TYPE_NORMAL and TYPE_MYSTERY and TYPE_FAIRY) - // The final + 1 skips past Normal, and the following conditional skips TYPE_MYSTERY - gBattleStruct->dynamicMoveType = ((NUMBER_OF_MON_TYPES - 4) * typeBits) / 63 + 1; + // Subtract 6 instead of 1 below because 5 types are excluded (TYPE_NONE, TYPE_NORMAL, TYPE_MYSTERY, TYPE_FAIRY and TYPE_STELLAR) + // The final + 2 skips past TYPE_NONE and Normal. + gBattleStruct->dynamicMoveType = ((NUMBER_OF_MON_TYPES - 6) * typeBits) / 63 + 2; if (gBattleStruct->dynamicMoveType >= TYPE_MYSTERY) gBattleStruct->dynamicMoveType++; gBattleStruct->dynamicMoveType |= F_DYNAMIC_TYPE_IGNORE_PHYSICALITY | F_DYNAMIC_TYPE_SET; diff --git a/src/battle_terastal.c b/src/battle_terastal.c index 796cc4ba08..afe7f3a5ce 100644 --- a/src/battle_terastal.c +++ b/src/battle_terastal.c @@ -169,33 +169,9 @@ uq4_12_t GetTeraMultiplier(u32 battler, u32 type) } } -// Most values pulled from the Tera type icon palette. -const u16 sTeraTypeRGBValues[NUMBER_OF_MON_TYPES] = { - [TYPE_NORMAL] = RGB_WHITE, // custom - [TYPE_FIGHTING] = RGB(26, 8, 14), - [TYPE_FLYING] = RGB(31, 26, 7), - [TYPE_POISON] = RGB(26, 10, 25), // custom - [TYPE_GROUND] = RGB(25, 23, 18), - [TYPE_ROCK] = RGB(18, 16, 8), // custom - [TYPE_BUG] = RGB(18, 24, 6), - [TYPE_GHOST] = RGB(12, 10, 16), - [TYPE_STEEL] = RGB(19, 19, 20), - [TYPE_MYSTERY] = RGB_WHITE, - [TYPE_FIRE] = RGB(31, 20, 11), - [TYPE_WATER] = RGB(10, 18, 27), - [TYPE_GRASS] = RGB(12, 24, 11), - [TYPE_ELECTRIC] = RGB(30, 26, 7), - [TYPE_PSYCHIC] = RGB(31, 14, 15), - [TYPE_ICE] = RGB(14, 26, 25), - [TYPE_DRAGON] = RGB(10, 18, 27), - [TYPE_DARK] = RGB(6, 5, 8), - [TYPE_FAIRY] = RGB(31, 15, 21), - [TYPE_STELLAR] = RGB(10, 18, 27), -}; - u16 GetTeraTypeRGB(u32 type) { - return sTeraTypeRGBValues[type]; + return gTypesInfo[type].teraTypeRGBValue; } // TERASTAL TRIGGER: @@ -636,6 +612,7 @@ static const struct SpriteTemplate sSpriteTemplate_StellarIndicator = static const struct SpriteSheet sTeraIndicatorSpriteSheets[NUMBER_OF_MON_TYPES + 1] = { + {sNormalIndicatorGfx, sizeof(sNormalIndicatorGfx), TAG_NORMAL_INDICATOR_TILE}, // TYPE_NONE {sNormalIndicatorGfx, sizeof(sNormalIndicatorGfx), TAG_NORMAL_INDICATOR_TILE}, {sFightingIndicatorGfx, sizeof(sFightingIndicatorGfx), TAG_FIGHTING_INDICATOR_TILE}, {sFlyingIndicatorGfx, sizeof(sFlyingIndicatorGfx), TAG_FLYING_INDICATOR_TILE}, @@ -661,6 +638,7 @@ static const struct SpriteSheet sTeraIndicatorSpriteSheets[NUMBER_OF_MON_TYPES + static const struct SpriteTemplate * const sTeraIndicatorSpriteTemplates[NUMBER_OF_MON_TYPES] = { + [TYPE_NONE] = &sSpriteTemplate_NormalIndicator, // just in case [TYPE_NORMAL] = &sSpriteTemplate_NormalIndicator, [TYPE_FIGHTING] = &sSpriteTemplate_FightingIndicator, [TYPE_FLYING] = &sSpriteTemplate_FlyingIndicator, diff --git a/src/battle_util.c b/src/battle_util.c index 477c0aa7dd..4bbb6c3c2e 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -903,44 +903,6 @@ static const uq4_12_t sPercentToModifier[] = UQ_4_12(1.00), // 100 }; -#define X UQ_4_12 -#define ______ X(1.0) // Regular effectiveness. - -// Type matchup updates. Attacker Defender -#define STL_RS (B_UPDATED_TYPE_MATCHUPS >= GEN_6 ? X(1.0) : X(0.5)) // Ghost/Dark -> Steel -#define PSN_RS (B_UPDATED_TYPE_MATCHUPS >= GEN_2 ? X(0.5) : X(2.0)) // Bug -> Poison -#define BUG_RS (B_UPDATED_TYPE_MATCHUPS >= GEN_2 ? X(1.0) : X(2.0)) // Poison -> Bug -#define PSY_RS (B_UPDATED_TYPE_MATCHUPS >= GEN_2 ? X(2.0) : X(0.0)) // Ghost -> Psychic -#define FIR_RS (B_UPDATED_TYPE_MATCHUPS >= GEN_2 ? X(0.5) : X(1.0)) // Ice -> Fire - -static const uq4_12_t sTypeEffectivenessTable[NUMBER_OF_MON_TYPES][NUMBER_OF_MON_TYPES] = -{// Defender --> - // Attacker Normal Fighting Flying Poison Ground Rock Bug Ghost Steel Mystery Fire Water Grass Electric Psychic Ice Dragon Dark Fairy Stellar - [TYPE_NORMAL] = {______, ______, ______, ______, ______, X(0.5), ______, X(0.0), X(0.5), ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______}, - [TYPE_FIGHTING] = {X(2.0), ______, X(0.5), X(0.5), ______, X(2.0), X(0.5), X(0.0), X(2.0), ______, ______, ______, ______, ______, X(0.5), X(2.0), ______, X(2.0), X(0.5), ______}, - [TYPE_FLYING] = {______, X(2.0), ______, ______, ______, X(0.5), X(2.0), ______, X(0.5), ______, ______, ______, X(2.0), X(0.5), ______, ______, ______, ______, ______, ______}, - [TYPE_POISON] = {______, ______, ______, X(0.5), X(0.5), X(0.5), BUG_RS, X(0.5), X(0.0), ______, ______, ______, X(2.0), ______, ______, ______, ______, ______, X(2.0), ______}, - [TYPE_GROUND] = {______, ______, X(0.0), X(2.0), ______, X(2.0), X(0.5), ______, X(2.0), ______, X(2.0), ______, X(0.5), X(2.0), ______, ______, ______, ______, ______, ______}, - [TYPE_ROCK] = {______, X(0.5), X(2.0), ______, X(0.5), ______, X(2.0), ______, X(0.5), ______, X(2.0), ______, ______, ______, ______, X(2.0), ______, ______, ______, ______}, - [TYPE_BUG] = {______, X(0.5), X(0.5), PSN_RS, ______, ______, ______, X(0.5), X(0.5), ______, X(0.5), ______, X(2.0), ______, X(2.0), ______, ______, X(2.0), X(0.5), ______}, - [TYPE_GHOST] = {X(0.0), ______, ______, ______, ______, ______, ______, X(2.0), STL_RS, ______, ______, ______, ______, ______, PSY_RS, ______, ______, X(0.5), ______, ______}, - [TYPE_STEEL] = {______, ______, ______, ______, ______, X(2.0), ______, ______, X(0.5), ______, X(0.5), X(0.5), ______, X(0.5), ______, X(2.0), ______, ______, X(2.0), ______}, - [TYPE_MYSTERY] = {______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______}, - [TYPE_FIRE] = {______, ______, ______, ______, ______, X(0.5), X(2.0), ______, X(2.0), ______, X(0.5), X(0.5), X(2.0), ______, ______, X(2.0), X(0.5), ______, ______, ______}, - [TYPE_WATER] = {______, ______, ______, ______, X(2.0), X(2.0), ______, ______, ______, ______, X(2.0), X(0.5), X(0.5), ______, ______, ______, X(0.5), ______, ______, ______}, - [TYPE_GRASS] = {______, ______, X(0.5), X(0.5), X(2.0), X(2.0), X(0.5), ______, X(0.5), ______, X(0.5), X(2.0), X(0.5), ______, ______, ______, X(0.5), ______, ______, ______}, - [TYPE_ELECTRIC] = {______, ______, X(2.0), ______, X(0.0), ______, ______, ______, ______, ______, ______, X(2.0), X(0.5), X(0.5), ______, ______, X(0.5), ______, ______, ______}, - [TYPE_PSYCHIC] = {______, X(2.0), ______, X(2.0), ______, ______, ______, ______, X(0.5), ______, ______, ______, ______, ______, X(0.5), ______, ______, X(0.0), ______, ______}, - [TYPE_ICE] = {______, ______, X(2.0), ______, X(2.0), ______, ______, ______, X(0.5), ______, FIR_RS, X(0.5), X(2.0), ______, ______, X(0.5), X(2.0), ______, ______, ______}, - [TYPE_DRAGON] = {______, ______, ______, ______, ______, ______, ______, ______, X(0.5), ______, ______, ______, ______, ______, ______, ______, X(2.0), ______, X(0.0), ______}, - [TYPE_DARK] = {______, X(0.5), ______, ______, ______, ______, ______, X(2.0), STL_RS, ______, ______, ______, ______, ______, X(2.0), ______, ______, X(0.5), X(0.5), ______}, - [TYPE_FAIRY] = {______, X(2.0), ______, X(0.5), ______, ______, ______, ______, X(0.5), ______, X(0.5), ______, ______, ______, ______, ______, X(2.0), X(2.0), ______, ______}, - [TYPE_STELLAR] = {______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______}, -}; - -#undef ______ -#undef X - // code u8 GetBattlerForBattleScript(u8 caseId) { @@ -10367,8 +10329,8 @@ static uq4_12_t GetInverseTypeMultiplier(uq4_12_t multiplier) uq4_12_t GetTypeModifier(u32 atkType, u32 defType) { if (B_FLAG_INVERSE_BATTLE != 0 && FlagGet(B_FLAG_INVERSE_BATTLE)) - return GetInverseTypeMultiplier(sTypeEffectivenessTable[atkType][defType]); - return sTypeEffectivenessTable[atkType][defType]; + return GetInverseTypeMultiplier(gTypeEffectivenessTable[atkType][defType]); + return gTypeEffectivenessTable[atkType][defType]; } s32 GetStealthHazardDamageByTypesAndHP(u8 hazardType, u8 type1, u8 type2, u32 maxHp) @@ -10912,10 +10874,8 @@ u8 GetBattleMoveCategory(u32 moveId) if (IS_MOVE_STATUS(moveId)) return DAMAGE_CATEGORY_STATUS; - else if (gMovesInfo[moveId].type < TYPE_MYSTERY) - return DAMAGE_CATEGORY_PHYSICAL; else - return DAMAGE_CATEGORY_SPECIAL; + return gTypesInfo[gMovesInfo[moveId].type].damageCategory; } static bool32 TryRemoveScreens(u32 battler) diff --git a/src/data/types_info.h b/src/data/types_info.h new file mode 100644 index 0000000000..f9bd233ca6 --- /dev/null +++ b/src/data/types_info.h @@ -0,0 +1,423 @@ +#include "constants/battle.h" +#include "constants/pokemon.h" + +#define X UQ_4_12 +#define ______ X(1.0) // Regular effectiveness. + +// Type matchup updates. Attacker Defender +#define STL_RS (B_UPDATED_TYPE_MATCHUPS >= GEN_6 ? X(1.0) : X(0.5)) // Ghost/Dark -> Steel +#define PSN_RS (B_UPDATED_TYPE_MATCHUPS >= GEN_2 ? X(0.5) : X(2.0)) // Bug -> Poison +#define BUG_RS (B_UPDATED_TYPE_MATCHUPS >= GEN_2 ? X(1.0) : X(2.0)) // Poison -> Bug +#define PSY_RS (B_UPDATED_TYPE_MATCHUPS >= GEN_2 ? X(2.0) : X(0.0)) // Ghost -> Psychic +#define FIR_RS (B_UPDATED_TYPE_MATCHUPS >= GEN_2 ? X(0.5) : X(1.0)) // Ice -> Fire + +const uq4_12_t gTypeEffectivenessTable[NUMBER_OF_MON_TYPES][NUMBER_OF_MON_TYPES] = +{// Defender --> + // Attacker None Normal Fighting Flying Poison Ground Rock Bug Ghost Steel Mystery Fire Water Grass Electric Psychic Ice Dragon Dark Fairy Stellar + [TYPE_NONE] = {______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______}, + [TYPE_NORMAL] = {______, ______, ______, ______, ______, ______, X(0.5), ______, X(0.0), X(0.5), ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______}, + [TYPE_FIGHTING] = {______, X(2.0), ______, X(0.5), X(0.5), ______, X(2.0), X(0.5), X(0.0), X(2.0), ______, ______, ______, ______, ______, X(0.5), X(2.0), ______, X(2.0), X(0.5), ______}, + [TYPE_FLYING] = {______, ______, X(2.0), ______, ______, ______, X(0.5), X(2.0), ______, X(0.5), ______, ______, ______, X(2.0), X(0.5), ______, ______, ______, ______, ______, ______}, + [TYPE_POISON] = {______, ______, ______, ______, X(0.5), X(0.5), X(0.5), BUG_RS, X(0.5), X(0.0), ______, ______, ______, X(2.0), ______, ______, ______, ______, ______, X(2.0), ______}, + [TYPE_GROUND] = {______, ______, ______, X(0.0), X(2.0), ______, X(2.0), X(0.5), ______, X(2.0), ______, X(2.0), ______, X(0.5), X(2.0), ______, ______, ______, ______, ______, ______}, + [TYPE_ROCK] = {______, ______, X(0.5), X(2.0), ______, X(0.5), ______, X(2.0), ______, X(0.5), ______, X(2.0), ______, ______, ______, ______, X(2.0), ______, ______, ______, ______}, + [TYPE_BUG] = {______, ______, X(0.5), X(0.5), PSN_RS, ______, ______, ______, X(0.5), X(0.5), ______, X(0.5), ______, X(2.0), ______, X(2.0), ______, ______, X(2.0), X(0.5), ______}, + [TYPE_GHOST] = {______, X(0.0), ______, ______, ______, ______, ______, ______, X(2.0), STL_RS, ______, ______, ______, ______, ______, PSY_RS, ______, ______, X(0.5), ______, ______}, + [TYPE_STEEL] = {______, ______, ______, ______, ______, ______, X(2.0), ______, ______, X(0.5), ______, X(0.5), X(0.5), ______, X(0.5), ______, X(2.0), ______, ______, X(2.0), ______}, + [TYPE_MYSTERY] = {______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______}, + [TYPE_FIRE] = {______, ______, ______, ______, ______, ______, X(0.5), X(2.0), ______, X(2.0), ______, X(0.5), X(0.5), X(2.0), ______, ______, X(2.0), X(0.5), ______, ______, ______}, + [TYPE_WATER] = {______, ______, ______, ______, ______, X(2.0), X(2.0), ______, ______, ______, ______, X(2.0), X(0.5), X(0.5), ______, ______, ______, X(0.5), ______, ______, ______}, + [TYPE_GRASS] = {______, ______, ______, X(0.5), X(0.5), X(2.0), X(2.0), X(0.5), ______, X(0.5), ______, X(0.5), X(2.0), X(0.5), ______, ______, ______, X(0.5), ______, ______, ______}, + [TYPE_ELECTRIC] = {______, ______, ______, X(2.0), ______, X(0.0), ______, ______, ______, ______, ______, ______, X(2.0), X(0.5), X(0.5), ______, ______, X(0.5), ______, ______, ______}, + [TYPE_PSYCHIC] = {______, ______, X(2.0), ______, X(2.0), ______, ______, ______, ______, X(0.5), ______, ______, ______, ______, ______, X(0.5), ______, ______, X(0.0), ______, ______}, + [TYPE_ICE] = {______, ______, ______, X(2.0), ______, X(2.0), ______, ______, ______, X(0.5), ______, FIR_RS, X(0.5), X(2.0), ______, ______, X(0.5), X(2.0), ______, ______, ______}, + [TYPE_DRAGON] = {______, ______, ______, ______, ______, ______, ______, ______, ______, X(0.5), ______, ______, ______, ______, ______, ______, ______, X(2.0), ______, X(0.0), ______}, + [TYPE_DARK] = {______, ______, X(0.5), ______, ______, ______, ______, ______, X(2.0), STL_RS, ______, ______, ______, ______, ______, X(2.0), ______, ______, X(0.5), X(0.5), ______}, + [TYPE_FAIRY] = {______, ______, X(2.0), ______, X(0.5), ______, ______, ______, ______, X(0.5), ______, X(0.5), ______, ______, ______, ______, ______, X(2.0), X(2.0), ______, ______}, + [TYPE_STELLAR] = {______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______}, +}; + +#undef ______ +#undef X + +#if B_EXPANDED_TYPE_NAMES == TRUE +#define HANDLE_EXPANDED_TYPE_NAME(_name, ...) _(DEFAULT(_name, __VA_ARGS__)) +#else +#define HANDLE_EXPANDED_TYPE_NAME(_name, ...) _(_name) +#endif + +// .generic is large enough that the text for TYPE_ELECTRIC will exceed TEXT_BUFF_ARRAY_COUNT. +// In this array there's commented-out data such as references to type-resist berries that would otherwise would go unused. +// However, we figured this information would be useful for users that want to add their own types as a reminder of +// what data would they need to add in order to have their new types be fully fledged like official types. +const struct TypeInfo gTypesInfo[NUMBER_OF_MON_TYPES] = +{ + [TYPE_NONE] = + { + .name = _("None"), + .generic = _("a move"), + .palette = 15, // Uses TYPE_MYSTERY's icon + .teraTypeRGBValue = RGB_WHITE, + .damageCategory = DAMAGE_CATEGORY_PHYSICAL, + .paletteTMHM = gItemIconPalette_NormalTMHM, + }, + [TYPE_NORMAL] = + { + .name = _("Normal"), + .generic = _("a NORMAL move"), + .palette = 13, + .zMove = MOVE_BREAKNECK_BLITZ, + .maxMove = MOVE_MAX_STRIKE, + .teraTypeRGBValue = RGB_WHITE, // custom + .damageCategory = DAMAGE_CATEGORY_PHYSICAL, + .paletteTMHM = gItemIconPalette_NormalTMHM, + //.enhanceItem = ITEM_SILK_SCARF, + //.berry = ITEM_CHILAN_BERRY, + //.gem = ITEM_NORMAL_GEM, + //.zCrystal = ITEM_NORMALIUM_Z, + //.teraShard = ITEM_NORMAL_TERA_SHARD, + //.arceusForm = SPECIES_ARCEUS_NORMAL, + }, + [TYPE_FIGHTING] = + { + .name = HANDLE_EXPANDED_TYPE_NAME("Fight", "Fighting"), + .generic = _("a FIGHTING move"), + .palette = 13, + .zMove = MOVE_ALL_OUT_PUMMELING, + .maxMove = MOVE_MAX_KNUCKLE, + .teraTypeRGBValue = RGB(26, 8, 14), + .damageCategory = DAMAGE_CATEGORY_PHYSICAL, + .paletteTMHM = gItemIconPalette_FightingTMHM, + //.enhanceItem = ITEM_BLACK_BELT, + //.berry = ITEM_CHOPLE_BERRY, + //.gem = ITEM_FIGHTING_GEM, + //.zCrystal = ITEM_FIGHTINIUM_Z, + //.plate = ITEM_FIST_PLATE, + //.memory = ITEM_FIGHTING_MEMORY, + //.teraShard = ITEM_FIGHTING_TERA_SHARD, + //.arceusForm = SPECIES_ARCEUS_FIGHTING, + }, + [TYPE_FLYING] = + { + .name = _("Flying"), + .generic = _("a FLYING move"), + .palette = 14, + .zMove = MOVE_SUPERSONIC_SKYSTRIKE, + .maxMove = MOVE_MAX_AIRSTREAM, + .teraTypeRGBValue = RGB(31, 26, 7), + .damageCategory = DAMAGE_CATEGORY_PHYSICAL, + .paletteTMHM = gItemIconPalette_FlyingTMHM, + //.enhanceItem = ITEM_SHARP_BEAK, + //.berry = ITEM_COBA_BERRY, + //.gem = ITEM_FLYING_GEM, + //.zCrystal = ITEM_FLYINIUM_Z, + //.plate = ITEM_SKY_PLATE, + //.memory = ITEM_FLYING_MEMORY, + //.teraShard = ITEM_FLYING_TERA_SHARD, + //.arceusForm = SPECIES_ARCEUS_FLYING, + }, + [TYPE_POISON] = + { + .name = _("Poison"), + .generic = _("a POISON move"), + .palette = 14, + .zMove = MOVE_ACID_DOWNPOUR, + .maxMove = MOVE_MAX_OOZE, + .teraTypeRGBValue = RGB(26, 10, 25), // custom + .damageCategory = DAMAGE_CATEGORY_PHYSICAL, + .paletteTMHM = gItemIconPalette_PoisonTMHM, + //.enhanceItem = ITEM_POISON_BARB, + //.berry = ITEM_KEBIA_BERRY, + //.gem = ITEM_POISON_GEM, + //.zCrystal = ITEM_POISONIUM_Z, + //.plate = ITEM_TOXIC_PLATE, + //.memory = ITEM_POISON_MEMORY, + //.teraShard = ITEM_POISON_TERA_SHARD, + //.arceusForm = SPECIES_ARCEUS_POISON, + }, + [TYPE_GROUND] = + { + .name = _("Ground"), + .generic = _("a GROUND move"), + .palette = 13, + .zMove = MOVE_TECTONIC_RAGE, + .maxMove = MOVE_MAX_QUAKE, + .teraTypeRGBValue = RGB(25, 23, 18), + .damageCategory = DAMAGE_CATEGORY_PHYSICAL, + .paletteTMHM = gItemIconPalette_GroundTMHM, + //.enhanceItem = ITEM_SOFT_SAND, + //.berry = ITEM_SHUCA_BERRY, + //.gem = ITEM_GROUND_GEM, + //.zCrystal = ITEM_GROUNDIUM_Z, + //.plate = ITEM_EARTH_PLATE, + //.memory = ITEM_GROUND_MEMORY, + //.teraShard = ITEM_GROUND_TERA_SHARD, + //.arceusForm = SPECIES_ARCEUS_GROUND, + }, + [TYPE_ROCK] = + { + .name = _("Rock"), + .generic = _("a ROCK move"), + .palette = 13, + .zMove = MOVE_CONTINENTAL_CRUSH, + .maxMove = MOVE_MAX_ROCKFALL, + .teraTypeRGBValue = RGB(18, 16, 8), // custom + .damageCategory = DAMAGE_CATEGORY_PHYSICAL, + .paletteTMHM = gItemIconPalette_RockTMHM, + //.enhanceItem = ITEM_HARD_STONE, + //.berry = ITEM_CHARTI_BERRY, + //.gem = ITEM_ROCK_GEM, + //.zCrystal = ITEM_ROCKIUM_Z, + //.plate = ITEM_STONE_PLATE, + //.memory = ITEM_ROCK_MEMORY, + //.teraShard = ITEM_ROCK_TERA_SHARD, + //.arceusForm = SPECIES_ARCEUS_ROCK, + }, + [TYPE_BUG] = + { + .name = _("Bug"), + .generic = _("a BUG move"), + .palette = 15, + .zMove = MOVE_SAVAGE_SPIN_OUT, + .maxMove = MOVE_MAX_FLUTTERBY, + .teraTypeRGBValue = RGB(18, 24, 6), + .damageCategory = DAMAGE_CATEGORY_PHYSICAL, + .paletteTMHM = gItemIconPalette_BugTMHM, + //.enhanceItem = ITEM_SILVER_POWDER, + //.berry = ITEM_TANGA_BERRY, + //.gem = ITEM_BUG_GEM, + //.zCrystal = ITEM_BUGINIUM_Z, + //.plate = ITEM_INSECT_PLATE, + //.memory = ITEM_BUG_MEMORY, + //.teraShard = ITEM_BUG_TERA_SHARD, + //.arceusForm = SPECIES_ARCEUS_BUG, + }, + [TYPE_GHOST] = + { + .name = _("Ghost"), + .generic = _("a GHOST move"), + .palette = 14, + .zMove = MOVE_NEVER_ENDING_NIGHTMARE, + .maxMove = MOVE_MAX_PHANTASM, + .teraTypeRGBValue = RGB(12, 10, 16), + .damageCategory = DAMAGE_CATEGORY_PHYSICAL, + .paletteTMHM = gItemIconPalette_GhostTMHM, + //.enhanceItem = ITEM_SPELL_TAG, + //.berry = ITEM_KASIB_BERRY, + //.gem = ITEM_GHOST_GEM, + //.zCrystal = ITEM_GHOSTIUM_Z, + //.plate = ITEM_SPOOKY_PLATE, + //.memory = ITEM_GHOST_MEMORY, + //.teraShard = ITEM_GHOST_TERA_SHARD, + //.arceusForm = SPECIES_ARCEUS_GHOST, + }, + [TYPE_STEEL] = + { + .name = _("Steel"), + .generic = _("a STEEL move"), + .palette = 13, + .zMove = MOVE_CORKSCREW_CRASH, + .maxMove = MOVE_MAX_STEELSPIKE, + .teraTypeRGBValue = RGB(19, 19, 20), + .damageCategory = DAMAGE_CATEGORY_PHYSICAL, + .paletteTMHM = gItemIconPalette_SteelTMHM, + //.enhanceItem = ITEM_METAL_COAT, + //.berry = ITEM_BABIRI_BERRY, + //.gem = ITEM_STEEL_GEM, + //.zCrystal = ITEM_STEELIUM_Z, + //.plate = ITEM_IRON_PLATE, + //.memory = ITEM_STEEL_MEMORY, + //.teraShard = ITEM_STEEL_TERA_SHARD, + //.arceusForm = SPECIES_ARCEUS_STEEL, + }, + [TYPE_MYSTERY] = + { + .name = _("???"), + .generic = _("a ??? move"), + .palette = 15, + .teraTypeRGBValue = RGB_WHITE, + .damageCategory = DAMAGE_CATEGORY_SPECIAL, + }, + [TYPE_FIRE] = + { + .name = _("Fire"), + .generic = _("a FIRE move"), + .palette = 13, + .zMove = MOVE_INFERNO_OVERDRIVE, + .maxMove = MOVE_MAX_FLARE, + .teraTypeRGBValue = RGB(31, 20, 11), + .damageCategory = DAMAGE_CATEGORY_SPECIAL, + .paletteTMHM = gItemIconPalette_FireTMHM, + //.enhanceItem = ITEM_CHARCOAL, + //.berry = ITEM_OCCA_BERRY, + //.gem = ITEM_FIRE_GEM, + //.zCrystal = ITEM_FIRIUM_Z, + //.plate = ITEM_FLAME_PLATE, + //.memory = ITEM_FIRE_MEMORY, + //.teraShard = ITEM_FIRE_TERA_SHARD, + //.arceusForm = SPECIES_ARCEUS_FIRE, + }, + [TYPE_WATER] = + { + .name = _("Water"), + .generic = _("a WATER move"), + .palette = 14, + .zMove = MOVE_HYDRO_VORTEX, + .maxMove = MOVE_MAX_GEYSER, + .teraTypeRGBValue = RGB(10, 18, 27), + .damageCategory = DAMAGE_CATEGORY_SPECIAL, + .paletteTMHM = gItemIconPalette_WaterTMHM, + //.enhanceItem = ITEM_MYSTIC_WATER, + //.berry = ITEM_PASSHO_BERRY, + //.gem = ITEM_WATER_GEM, + //.zCrystal = ITEM_WATERIUM_Z, + //.plate = ITEM_SPLASH_PLATE, + //.memory = ITEM_WATER_MEMORY, + //.teraShard = ITEM_WATER_TERA_SHARD, + //.arceusForm = SPECIES_ARCEUS_WATER, + }, + [TYPE_GRASS] = + { + .name = _("Grass"), + .generic = _("a GRASS move"), + .palette = 15, + .zMove = MOVE_BLOOM_DOOM, + .maxMove = MOVE_MAX_OVERGROWTH, + .teraTypeRGBValue = RGB(12, 24, 11), + .damageCategory = DAMAGE_CATEGORY_SPECIAL, + .paletteTMHM = gItemIconPalette_GrassTMHM, + //.enhanceItem = ITEM_MIRACLE_SEED, + //.berry = ITEM_RINDO_BERRY, + //.gem = ITEM_GRASS_GEM, + //.zCrystal = ITEM_GRASSIUM_Z, + //.plate = ITEM_MEADOW_PLATE, + //.memory = ITEM_GRASS_MEMORY, + //.teraShard = ITEM_GRASS_TERA_SHARD, + //.arceusForm = SPECIES_ARCEUS_GRASS, + }, + [TYPE_ELECTRIC] = + { + .name = HANDLE_EXPANDED_TYPE_NAME("Electr", "Electric"), + .generic = _("an ELECTRIC move"), + .palette = 13, + .zMove = MOVE_GIGAVOLT_HAVOC, + .maxMove = MOVE_MAX_LIGHTNING, + .teraTypeRGBValue = RGB(30, 26, 7), + .damageCategory = DAMAGE_CATEGORY_SPECIAL, + .paletteTMHM = gItemIconPalette_ElectricTMHM, + //.enhanceItem = ITEM_MAGNET, + //.berry = ITEM_WACAN_BERRY, + //.gem = ITEM_ELECTRIC_GEM, + //.zCrystal = ITEM_ELECTRIUM_Z, + //.plate = ITEM_ZAP_PLATE, + //.memory = ITEM_ELECTRIC_MEMORY, + //.teraShard = ITEM_ELECTRIC_TERA_SHARD, + //.arceusForm = SPECIES_ARCEUS_ELECTRIC, + }, + [TYPE_PSYCHIC] = + { + .name = HANDLE_EXPANDED_TYPE_NAME("Psychc", "Psychic"), + .generic = _("a PSYCHIC move"), + .palette = 14, + .zMove = MOVE_SHATTERED_PSYCHE, + .maxMove = MOVE_MAX_MINDSTORM, + .teraTypeRGBValue = RGB(31, 14, 15), + .damageCategory = DAMAGE_CATEGORY_SPECIAL, + .paletteTMHM = gItemIconPalette_PsychicTMHM, + //.enhanceItem = ITEM_TWISTED_SPOON, + //.berry = ITEM_PAYAPA_BERRY, + //.gem = ITEM_PSYCHIC_GEM, + //.zCrystal = ITEM_PSYCHIUM_Z, + //.plate = ITEM_MIND_PLATE, + //.memory = ITEM_PSYCHIC_MEMORY, + //.teraShard = ITEM_PSYCHIC_TERA_SHARD, + //.arceusForm = SPECIES_ARCEUS_PSYCHIC, + }, + [TYPE_ICE] = + { + .name = _("Ice"), + .generic = _("an ICE move"), + .palette = 14, + .zMove = MOVE_SUBZERO_SLAMMER, + .maxMove = MOVE_MAX_HAILSTORM, + .teraTypeRGBValue = RGB(14, 26, 25), + .damageCategory = DAMAGE_CATEGORY_SPECIAL, + .paletteTMHM = gItemIconPalette_IceTMHM, + //.enhanceItem = ITEM_NEVER_MELT_ICE, + //.berry = ITEM_YACHE_BERRY, + //.gem = ITEM_ICE_GEM, + //.zCrystal = ITEM_ICIUM_Z, + //.plate = ITEM_ICICLE_PLATE, + //.memory = ITEM_ICE_MEMORY, + //.teraShard = ITEM_ICE_TERA_SHARD, + //.arceusForm = SPECIES_ARCEUS_ICE, + }, + [TYPE_DRAGON] = + { + .name = _("Dragon"), + .generic = _("a DRAGON move"), + .palette = 15, + .zMove = MOVE_DEVASTATING_DRAKE, + .maxMove = MOVE_MAX_WYRMWIND, + .teraTypeRGBValue = RGB(10, 18, 27), + .damageCategory = DAMAGE_CATEGORY_SPECIAL, + .paletteTMHM = gItemIconPalette_DragonTMHM, + //.enhanceItem = ITEM_DRAGON_FANG, + //.berry = ITEM_HABAN_BERRY, + //.gem = ITEM_DRAGON_GEM, + //.zCrystal = ITEM_DRAGONIUM_Z, + //.plate = ITEM_DRACO_PLATE, + //.memory = ITEM_DRAGON_MEMORY, + //.teraShard = ITEM_DRAGON_TERA_SHARD, + //.arceusForm = SPECIES_ARCEUS_DRAGON, + }, + [TYPE_DARK] = + { + .name = _("Dark"), + .generic = _("a DARK move"), + .palette = 13, + .zMove = MOVE_BLACK_HOLE_ECLIPSE, + .maxMove = MOVE_MAX_DARKNESS, + .teraTypeRGBValue = RGB(6, 5, 8), + .damageCategory = DAMAGE_CATEGORY_SPECIAL, + .paletteTMHM = gItemIconPalette_DarkTMHM, + //.enhanceItem = ITEM_BLACK_GLASSES, + //.berry = ITEM_COLBUR_BERRY, + //.gem = ITEM_DARK_GEM, + //.zCrystal = ITEM_DARKINIUM_Z, + //.plate = ITEM_DREAD_PLATE, + //.memory = ITEM_DARK_MEMORY, + //.teraShard = ITEM_DARK_TERA_SHARD, + //.arceusForm = SPECIES_ARCEUS_DARK, + }, + [TYPE_FAIRY] = + { + .name = _("Fairy"), + .generic = _("a FAIRY move"), + .palette = 14, + .zMove = MOVE_TWINKLE_TACKLE, + .maxMove = MOVE_MAX_STARFALL, + .teraTypeRGBValue = RGB(31, 15, 21), + .damageCategory = DAMAGE_CATEGORY_SPECIAL, + .paletteTMHM = gItemIconPalette_FairyTMHM, + //.enhanceItem = ITEM_FAIRY_FEATHER, + //.berry = ITEM_ROSELI_BERRY, + //.gem = ITEM_FAIRY_GEM, + //.zCrystal = ITEM_FAIRIUM_Z, + //.plate = ITEM_PIXIE_PLATE, + //.memory = ITEM_FAIRY_MEMORY, + //.teraShard = ITEM_FAIRY_TERA_SHARD, + //.arceusForm = SPECIES_ARCEUS_FAIRY, + }, + [TYPE_STELLAR] = + { + .name = HANDLE_EXPANDED_TYPE_NAME("Stellr", "Stellar"), + .generic = _("a STELLAR move"), + .palette = 15, + .zMove = MOVE_BREAKNECK_BLITZ, + .maxMove = MOVE_MAX_STRIKE, + .teraTypeRGBValue = RGB(10, 18, 27), + .paletteTMHM = gItemIconPalette_NormalTMHM, // failsafe + // .teraShard = ITEM_STELLAR_TERA_SHARD, + }, +}; diff --git a/src/menu.c b/src/menu.c index a6bd9ae2bc..1952ec5ed4 100644 --- a/src/menu.c +++ b/src/menu.c @@ -112,6 +112,7 @@ static const u8 sTextColors[] = { TEXT_DYNAMIC_COLOR_6, TEXT_COLOR_WHITE, TEXT_C static const struct MenuInfoIcon sMenuInfoIcons[] = { // { width, height, offset } { 12, 12, 0x00 }, // Unused + [TYPE_NONE + 1] = { 32, 12, 0xA4 }, // Copy of TYPE_MYSTERY's [TYPE_NORMAL + 1] = { 32, 12, 0x20 }, [TYPE_FIGHTING + 1] = { 32, 12, 0x64 }, [TYPE_FLYING + 1] = { 32, 12, 0x60 }, diff --git a/src/pokedex.c b/src/pokedex.c index 6153e72213..8b70529a93 100644 --- a/src/pokedex.c +++ b/src/pokedex.c @@ -1389,7 +1389,7 @@ static const struct SearchOptionText sDexSearchColorOptions[] = static const struct SearchOptionText sDexSearchTypeOptions[NUMBER_OF_MON_TYPES] = // + 2 for "None" and terminator, - 2 for Mystery and Stellar { - {gText_DexEmptyString, gText_DexSearchTypeNone}, + {gText_DexEmptyString, gTypesInfo[TYPE_NONE].name}, {gText_DexEmptyString, gTypesInfo[TYPE_NORMAL].name}, {gText_DexEmptyString, gTypesInfo[TYPE_FIGHTING].name}, {gText_DexEmptyString, gTypesInfo[TYPE_FLYING].name}, diff --git a/src/pokedex_plus_hgss.c b/src/pokedex_plus_hgss.c index e667e44bd6..22cbd5ba14 100644 --- a/src/pokedex_plus_hgss.c +++ b/src/pokedex_plus_hgss.c @@ -1901,7 +1901,7 @@ static const struct SearchOptionText sDexSearchColorOptions[] = static const struct SearchOptionText sDexSearchTypeOptions[NUMBER_OF_MON_TYPES] = // + 2 for "None" and terminator, - 2 for Mystery and Stellar { - {gText_DexEmptyString, gText_DexSearchTypeNone}, + {gText_DexEmptyString, gTypesInfo[TYPE_NONE].name}, {gText_DexEmptyString, gTypesInfo[TYPE_NORMAL].name}, {gText_DexEmptyString, gTypesInfo[TYPE_FIGHTING].name}, {gText_DexEmptyString, gTypesInfo[TYPE_FLYING].name}, diff --git a/src/pokemon.c b/src/pokemon.c index 7952452cb3..d52b6627eb 100644 --- a/src/pokemon.c +++ b/src/pokemon.c @@ -2771,14 +2771,14 @@ u32 GetBoxMonData3(struct BoxPokemon *boxMon, s32 field, u8 *data) break; case MON_DATA_TERA_TYPE: { - if (substruct0->teraType == 0) + if (substruct0->teraType == TYPE_NONE) { const u8 *types = gSpeciesInfo[substruct0->species].types; retVal = (boxMon->personality & 0x1) == 0 ? types[0] : types[1]; } else { - retVal = substruct0->teraType - 1; + retVal = substruct0->teraType; } break; } @@ -3207,7 +3207,7 @@ void SetBoxMonData(struct BoxPokemon *boxMon, s32 field, const void *dataArg) { u32 teraType; SET8(teraType); - substruct0->teraType = 1 + teraType; + substruct0->teraType = teraType; break; } case MON_DATA_EVOLUTION_TRACKER: diff --git a/src/pokemon_summary_screen.c b/src/pokemon_summary_screen.c index d4f080096b..70b82a3edc 100644 --- a/src/pokemon_summary_screen.c +++ b/src/pokemon_summary_screen.c @@ -812,6 +812,10 @@ static const struct OamData sOamData_MoveTypes = .paletteNum = 0, .affineParam = 0, }; +static const union AnimCmd sSpriteAnim_TypeNone[] = { + ANIMCMD_FRAME(TYPE_NONE * 8, 0, FALSE, FALSE), + ANIMCMD_END +}; static const union AnimCmd sSpriteAnim_TypeNormal[] = { ANIMCMD_FRAME(TYPE_NORMAL * 8, 0, FALSE, FALSE), ANIMCMD_END @@ -913,31 +917,32 @@ static const union AnimCmd sSpriteAnim_CategoryTough[] = { ANIMCMD_END }; static const union AnimCmd *const sSpriteAnimTable_MoveTypes[NUMBER_OF_MON_TYPES + CONTEST_CATEGORIES_COUNT] = { - sSpriteAnim_TypeNormal, - sSpriteAnim_TypeFighting, - sSpriteAnim_TypeFlying, - sSpriteAnim_TypePoison, - sSpriteAnim_TypeGround, - sSpriteAnim_TypeRock, - sSpriteAnim_TypeBug, - sSpriteAnim_TypeGhost, - sSpriteAnim_TypeSteel, - sSpriteAnim_TypeMystery, - sSpriteAnim_TypeFire, - sSpriteAnim_TypeWater, - sSpriteAnim_TypeGrass, - sSpriteAnim_TypeElectric, - sSpriteAnim_TypePsychic, - sSpriteAnim_TypeIce, - sSpriteAnim_TypeDragon, - sSpriteAnim_TypeDark, - sSpriteAnim_TypeFairy, - sSpriteAnim_TypeStellar, - sSpriteAnim_CategoryCool, - sSpriteAnim_CategoryBeauty, - sSpriteAnim_CategoryCute, - sSpriteAnim_CategorySmart, - sSpriteAnim_CategoryTough, + [TYPE_NONE] = sSpriteAnim_TypeNone, + [TYPE_NORMAL] = sSpriteAnim_TypeNormal, + [TYPE_FIGHTING] = sSpriteAnim_TypeFighting, + [TYPE_FLYING] = sSpriteAnim_TypeFlying, + [TYPE_POISON] = sSpriteAnim_TypePoison, + [TYPE_GROUND] = sSpriteAnim_TypeGround, + [TYPE_ROCK] = sSpriteAnim_TypeRock, + [TYPE_BUG] = sSpriteAnim_TypeBug, + [TYPE_GHOST] = sSpriteAnim_TypeGhost, + [TYPE_STEEL] = sSpriteAnim_TypeSteel, + [TYPE_MYSTERY] = sSpriteAnim_TypeMystery, + [TYPE_FIRE] = sSpriteAnim_TypeFire, + [TYPE_WATER] = sSpriteAnim_TypeWater, + [TYPE_GRASS] = sSpriteAnim_TypeGrass, + [TYPE_ELECTRIC] = sSpriteAnim_TypeElectric, + [TYPE_PSYCHIC] = sSpriteAnim_TypePsychic, + [TYPE_ICE] = sSpriteAnim_TypeIce, + [TYPE_DRAGON] = sSpriteAnim_TypeDragon, + [TYPE_DARK] = sSpriteAnim_TypeDark, + [TYPE_FAIRY] = sSpriteAnim_TypeFairy, + [TYPE_STELLAR] = sSpriteAnim_TypeStellar, + [NUMBER_OF_MON_TYPES + CONTEST_CATEGORY_COOL] = sSpriteAnim_CategoryCool, + [NUMBER_OF_MON_TYPES + CONTEST_CATEGORY_BEAUTY] = sSpriteAnim_CategoryBeauty, + [NUMBER_OF_MON_TYPES + CONTEST_CATEGORY_CUTE] = sSpriteAnim_CategoryCute, + [NUMBER_OF_MON_TYPES + CONTEST_CATEGORY_SMART] = sSpriteAnim_CategorySmart, + [NUMBER_OF_MON_TYPES + CONTEST_CATEGORY_TOUGH] = sSpriteAnim_CategoryTough, }; const struct CompressedSpriteSheet gSpriteSheet_MoveTypes = diff --git a/src/script_pokemon_util.c b/src/script_pokemon_util.c index f7dacbbfb7..0946ec1d15 100644 --- a/src/script_pokemon_util.c +++ b/src/script_pokemon_util.c @@ -352,7 +352,7 @@ u32 ScriptGiveMonParameterized(u16 species, u8 level, u16 item, u8 ball, u8 natu // tera type if (teraType >= NUMBER_OF_MON_TYPES) - teraType = gSpeciesInfo[species].types[0]; + teraType = TYPE_NONE; SetMonData(&mon, MON_DATA_TERA_TYPE, &teraType); // EV and IV diff --git a/test/battle/gimmick/terastal.c b/test/battle/gimmick/terastal.c index 18eab992af..c40b6823e7 100644 --- a/test/battle/gimmick/terastal.c +++ b/test/battle/gimmick/terastal.c @@ -765,6 +765,7 @@ SINGLE_BATTLE_TEST("(TERA) Stellar type's one-time boost factors in dynamically- SINGLE_BATTLE_TEST("(TERA) All type indicators function correctly") { u32 type; + PARAMETRIZE { type = TYPE_NONE; } PARAMETRIZE { type = TYPE_NORMAL; } PARAMETRIZE { type = TYPE_FIGHTING; } PARAMETRIZE { type = TYPE_FLYING; } diff --git a/test/battle/move_effect/hidden_power.c b/test/battle/move_effect/hidden_power.c new file mode 100644 index 0000000000..8ec63c21a7 --- /dev/null +++ b/test/battle/move_effect/hidden_power.c @@ -0,0 +1,106 @@ +#include "global.h" +#include "test/battle.h" + +// 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 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_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; } + + // Any type after Dark shouldn't be part of Hidden Power officially. + for (j = TYPE_DARK + 1; j < NUMBER_OF_MON_TYPES; j++) { + PARAMETRIZE { type = j; hidden = FALSE; } + } + + GIVEN { + if (hidden) { + ASSUME(gTypeEffectivenessTable[type][foeType] == UQ_4_12(0.5)); // 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 + PLAYER(SPECIES_DUNSPARCE) { HPIV(hp); AttackIV(atk); DefenseIV(def); SpAttackIV(spAtk); SpDefenseIV(spDef); SpeedIV(speed); } + } else { + PLAYER(SPECIES_DUNSPARCE); + } + OPPONENT(foeSpecies); + } WHEN { + TURN { MOVE(player, MOVE_HIDDEN_POWER); } + } SCENE { + // Only test valid Hidden Power types + if (hidden) { + ANIMATION(ANIM_TYPE_MOVE, MOVE_HIDDEN_POWER, player); + HP_BAR(opponent); + MESSAGE("It's not very effective…"); + } + } +} + +TO_DO_BATTLE_TEST("Hidden Power's power is determined by IVs before Gen6"); diff --git a/test/battle/move_effect/tera_blast.c b/test/battle/move_effect/tera_blast.c index 4592cf32a5..ca1413d2e8 100644 --- a/test/battle/move_effect/tera_blast.c +++ b/test/battle/move_effect/tera_blast.c @@ -21,6 +21,57 @@ SINGLE_BATTLE_TEST("Tera Blast changes from Normal-type to the user's Tera Type" } } +SINGLE_BATTLE_TEST("Tera Blast has correct effectiveness for every Tera Type") +{ + u32 species; + u32 type; + + PARAMETRIZE { species = SPECIES_CHIKORITA; type = TYPE_FLYING; } + PARAMETRIZE { species = SPECIES_CHIKORITA; type = TYPE_POISON; } + PARAMETRIZE { species = SPECIES_CHIKORITA; type = TYPE_FIRE; } + PARAMETRIZE { species = SPECIES_CHIKORITA; type = TYPE_BUG; } + PARAMETRIZE { species = SPECIES_CHIKORITA; type = TYPE_ICE; } + PARAMETRIZE { species = SPECIES_CYNDAQUIL; type = TYPE_GROUND; } + PARAMETRIZE { species = SPECIES_CYNDAQUIL; type = TYPE_ROCK; } + PARAMETRIZE { species = SPECIES_CYNDAQUIL; type = TYPE_WATER; } + PARAMETRIZE { species = SPECIES_GASTLY; type = TYPE_NORMAL; } + PARAMETRIZE { species = SPECIES_GASTLY; type = TYPE_GHOST; } + PARAMETRIZE { species = SPECIES_GASTLY; type = TYPE_PSYCHIC; } + PARAMETRIZE { species = SPECIES_TOTODILE; type = TYPE_GRASS; } + PARAMETRIZE { species = SPECIES_TOTODILE; type = TYPE_ELECTRIC; } + PARAMETRIZE { species = SPECIES_DRATINI; type = TYPE_DRAGON; } + PARAMETRIZE { species = SPECIES_DRATINI; type = TYPE_FAIRY; } + PARAMETRIZE { species = SPECIES_SNEASEL; type = TYPE_FIGHTING; } + PARAMETRIZE { species = SPECIES_SNEASEL; type = TYPE_STEEL; } + PARAMETRIZE { species = SPECIES_ABRA; type = TYPE_DARK; } + + GIVEN { + ASSUME(gSpeciesInfo[SPECIES_CHIKORITA].types[0] == TYPE_GRASS); + ASSUME(gSpeciesInfo[SPECIES_CHIKORITA].types[1] == TYPE_GRASS); + ASSUME(gSpeciesInfo[SPECIES_CYNDAQUIL].types[0] == TYPE_FIRE); + ASSUME(gSpeciesInfo[SPECIES_CYNDAQUIL].types[1] == TYPE_FIRE); + ASSUME(gSpeciesInfo[SPECIES_GASTLY].types[0] == TYPE_GHOST); + ASSUME(gSpeciesInfo[SPECIES_GASTLY].types[1] == TYPE_POISON); + ASSUME(gSpeciesInfo[SPECIES_TOTODILE].types[0] == TYPE_WATER); + ASSUME(gSpeciesInfo[SPECIES_TOTODILE].types[1] == TYPE_WATER); + ASSUME(gSpeciesInfo[SPECIES_DRATINI].types[0] == TYPE_DRAGON); + ASSUME(gSpeciesInfo[SPECIES_DRATINI].types[1] == TYPE_DRAGON); + ASSUME(gSpeciesInfo[SPECIES_SNEASEL].types[0] == TYPE_DARK); + ASSUME(gSpeciesInfo[SPECIES_SNEASEL].types[1] == TYPE_ICE); + ASSUME(gSpeciesInfo[SPECIES_ABRA].types[0] == TYPE_PSYCHIC); + ASSUME(gSpeciesInfo[SPECIES_ABRA].types[1] == TYPE_PSYCHIC); + PLAYER(SPECIES_WOBBUFFET) { TeraType(type); } + OPPONENT(species); + } WHEN { + TURN { MOVE(player, MOVE_TERA_BLAST, tera: TRUE); } + } SCENE { + if (species == SPECIES_GASTLY && type == TYPE_NORMAL) + MESSAGE("It doesn't affect Foe Gastly…"); + else + MESSAGE("It's super effective!"); + } +} + SINGLE_BATTLE_TEST("Tera Blast becomes a physical move if the user is Terastallized and has a higher Attack stat", s16 damage) { bool32 tera; diff --git a/test/pokemon.c b/test/pokemon.c index 2e35896027..fa96b47f26 100644 --- a/test/pokemon.c +++ b/test/pokemon.c @@ -33,11 +33,11 @@ TEST("Terastallization type defaults to primary or secondary type") || teraType == gSpeciesInfo[SPECIES_PIDGEY].types[1]); } -TEST("Terastallization type can be set to any type") +TEST("Terastallization type can be set to any type except TYPE_NONE") { u32 i, teraType; struct Pokemon mon; - for (i = 0; i < NUMBER_OF_MON_TYPES; i++) + for (i = 1; i < NUMBER_OF_MON_TYPES; i++) { PARAMETRIZE { teraType = i; } } @@ -46,6 +46,23 @@ TEST("Terastallization type can be set to any type") EXPECT_EQ(teraType, GetMonData(&mon, MON_DATA_TERA_TYPE)); } +TEST("Terastallization type is reset to the default types when setting Tera Type back to TYPE_NONE") +{ + u32 i, teraType, typeNone; + struct Pokemon mon; + for (i = 1; i < NUMBER_OF_MON_TYPES; i++) + { + PARAMETRIZE { teraType = i; typeNone = TYPE_NONE; } + } + CreateMon(&mon, SPECIES_PIDGEY, 100, 0, FALSE, 0, OT_ID_PRESET, 0); + SetMonData(&mon, MON_DATA_TERA_TYPE, &teraType); + EXPECT_EQ(teraType, GetMonData(&mon, MON_DATA_TERA_TYPE)); + SetMonData(&mon, MON_DATA_TERA_TYPE, &typeNone); + typeNone = GetMonData(&mon, MON_DATA_TERA_TYPE); + EXPECT(typeNone == gSpeciesInfo[SPECIES_PIDGEY].types[0] + || typeNone == gSpeciesInfo[SPECIES_PIDGEY].types[1]); +} + TEST("Shininess independent from PID and OTID") { u32 pid, otId, data; diff --git a/test/test_runner_battle.c b/test/test_runner_battle.c index 9a71c9a9a8..b2cc4725ce 100644 --- a/test/test_runner_battle.c +++ b/test/test_runner_battle.c @@ -1717,6 +1717,48 @@ void Speed_(u32 sourceLine, u32 speed) DATA.explicitSpeeds[DATA.currentSide] |= 1 << DATA.currentPartyIndex; } +void HPIV_(u32 sourceLine, u32 hpIV) +{ + INVALID_IF(!DATA.currentMon, "HP IV outside of PLAYER/OPPONENT"); + INVALID_IF(hpIV > MAX_PER_STAT_IVS, "Illegal HP IV: %d", hpIV); + SetMonData(DATA.currentMon, MON_DATA_HP_IV, &hpIV); +} + +void AttackIV_(u32 sourceLine, u32 attackIV) +{ + INVALID_IF(!DATA.currentMon, "Attack IV outside of PLAYER/OPPONENT"); + INVALID_IF(attackIV > MAX_PER_STAT_IVS, "Illegal attack IV: %d", attackIV); + SetMonData(DATA.currentMon, MON_DATA_ATK_IV, &attackIV); +} + +void DefenseIV_(u32 sourceLine, u32 defenseIV) +{ + INVALID_IF(!DATA.currentMon, "Defense IV outside of PLAYER/OPPONENT"); + INVALID_IF(defenseIV > MAX_PER_STAT_IVS, "Illegal defense IV: %d", defenseIV); + SetMonData(DATA.currentMon, MON_DATA_DEF_IV, &defenseIV); +} + +void SpAttackIV_(u32 sourceLine, u32 spAttackIV) +{ + INVALID_IF(!DATA.currentMon, "SpAttack IV outside of PLAYER/OPPONENT"); + INVALID_IF(spAttackIV > MAX_PER_STAT_IVS, "Illegal special attack IV: %d", spAttackIV); + SetMonData(DATA.currentMon, MON_DATA_SPATK_IV, &spAttackIV); +} + +void SpDefenseIV_(u32 sourceLine, u32 spDefenseIV) +{ + INVALID_IF(!DATA.currentMon, "SpDefense IV outside of PLAYER/OPPONENT"); + INVALID_IF(spDefenseIV > MAX_PER_STAT_IVS, "Illegal special defense IV: %d", spDefenseIV); + SetMonData(DATA.currentMon, MON_DATA_SPDEF_IV, &spDefenseIV); +} + +void SpeedIV_(u32 sourceLine, u32 speedIV) +{ + INVALID_IF(!DATA.currentMon, "Speed IV outside of PLAYER/OPPONENT"); + INVALID_IF(speedIV > MAX_PER_STAT_IVS, "Illegal speed IV: %d", speedIV); + SetMonData(DATA.currentMon, MON_DATA_SPEED_IV, &speedIV); +} + void Item_(u32 sourceLine, u32 item) { INVALID_IF(!DATA.currentMon, "Item outside of PLAYER/OPPONENT");