diff --git a/asm/macros/battle_script.inc b/asm/macros/battle_script.inc index 27488c25d8a0..2989aa1c9222 100644 --- a/asm/macros/battle_script.inc +++ b/asm/macros/battle_script.inc @@ -928,8 +928,9 @@ .4byte \failInstr .endm - .macro setdestinybond + .macro trysetdestinybond failInstr:req .byte 0xaa + .4byte \failInstr .endm .macro trysetdestinybondtohappen @@ -1682,6 +1683,11 @@ .byte \battler .4byte \failInstr .endm + + .macro jumpifcommanderactive jumpInstr:req + callnative BS_JumpIfCommanderActive + .4byte \jumpInstr + .endm .macro tryhitswitchtarget failInstr:req callnative BS_TryHitSwitchTarget diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index 33057ac39e44..4997f2bb7c8b 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -3276,6 +3276,7 @@ BattleScript_EffectRoar:: attackstring ppreduce jumpifroarfails BattleScript_ButItFailed + jumpifcommanderactive BattleScript_ButItFailed jumpifability BS_TARGET, ABILITY_GUARD_DOG, BattleScript_ButItFailed jumpifability BS_TARGET, ABILITY_SUCTION_CUPS, BattleScript_AbilityPreventsPhasingOut jumpifstatus3 BS_TARGET, STATUS3_ROOTED, BattleScript_PrintMonIsRooted @@ -4061,7 +4062,7 @@ BattleScript_EffectDestinyBond:: attackcanceler attackstring ppreduce - setdestinybond + trysetdestinybond BattleScript_ButItFailed attackanimation waitanimation printstring STRINGID_PKMNTRYINGTOTAKEFOE @@ -8036,11 +8037,52 @@ BattleScript_CostarActivates:: BattleScript_ZeroToHeroActivates:: pause B_WAIT_TIME_SHORT - call BattleScript_AbilityPopUp + call BattleScript_AbilityPopUpScripting printstring STRINGID_ZEROTOHEROTRANSFORMATION waitmessage B_WAIT_TIME_LONG end3 +BattleScript_CommanderActivates:: + pause B_WAIT_TIME_SHORT + call BattleScript_AbilityPopUpScripting + printstring STRINGID_COMMANDERACTIVATES + waitmessage B_WAIT_TIME_LONG +BattleScript_CommanderAtkIncrease: + setbyte sSTAT_ANIM_PLAYED, FALSE + playstatchangeanimation BS_ATTACKER, BIT_ATK | BIT_DEF | BIT_SPATK | BIT_SPDEF | BIT_SPEED, STAT_CHANGE_BY_TWO + setstatchanger STAT_ATK, 2, FALSE + statbuffchange MOVE_EFFECT_AFFECTS_USER | STAT_CHANGE_ALLOW_PTR, BattleScript_CommanderDefIncrease + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_CommanderDefIncrease + printfromtable gStatUpStringIds + waitmessage B_WAIT_TIME_LONG +BattleScript_CommanderDefIncrease: + setstatchanger STAT_DEF, 2, FALSE + statbuffchange MOVE_EFFECT_AFFECTS_USER | STAT_CHANGE_ALLOW_PTR, BattleScript_CommanderSpAtkIncrease + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_CommanderSpAtkIncrease + printfromtable gStatUpStringIds + waitmessage B_WAIT_TIME_LONG +BattleScript_CommanderSpAtkIncrease: + setstatchanger STAT_SPATK, 2, FALSE + statbuffchange MOVE_EFFECT_AFFECTS_USER | STAT_CHANGE_ALLOW_PTR, BattleScript_CommanderSpDefIncrease + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_CommanderSpDefIncrease + printfromtable gStatUpStringIds + waitmessage B_WAIT_TIME_LONG +BattleScript_CommanderSpDefIncrease: + setstatchanger STAT_SPDEF, 2, FALSE + statbuffchange MOVE_EFFECT_AFFECTS_USER | STAT_CHANGE_ALLOW_PTR, BattleScript_CommanderSpeedIncrease + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_CommanderSpeedIncrease + printfromtable gStatUpStringIds + waitmessage B_WAIT_TIME_LONG +BattleScript_CommanderSpeedIncrease: + setstatchanger STAT_SPEED, 2, FALSE + statbuffchange MOVE_EFFECT_AFFECTS_USER | STAT_CHANGE_ALLOW_PTR, BattleScript_CommanderEnd + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_CommanderEnd + printfromtable gStatUpStringIds + waitmessage B_WAIT_TIME_LONG +BattleScript_CommanderEnd: + restoreattacker + end3 + BattleScript_HospitalityActivates:: pause B_WAIT_TIME_SHORT call BattleScript_AbilityPopUp @@ -9558,6 +9600,14 @@ BattleScript_StickyBarbTransfer:: removeitem BS_TARGET return +BattleScript_RedCardActivationNoSwitch:: + playanimation BS_SCRIPTING, B_ANIM_HELD_ITEM_EFFECT + printstring STRINGID_REDCARDACTIVATE + waitmessage B_WAIT_TIME_LONG + removeitem BS_SCRIPTING + restoretarget + return + BattleScript_RedCardActivates:: playanimation BS_SCRIPTING, B_ANIM_HELD_ITEM_EFFECT printstring STRINGID_REDCARDACTIVATE diff --git a/data/layouts/PitArenaMine/map.bin b/data/layouts/PitArenaMine/map.bin index 627eb316f3a9..9d8ce389f82c 100644 Binary files a/data/layouts/PitArenaMine/map.bin and b/data/layouts/PitArenaMine/map.bin differ diff --git a/data/layouts/PitArenaMine02/map.bin b/data/layouts/PitArenaMine02/map.bin index 4c63971a4ae3..9c0af2c10cdd 100644 Binary files a/data/layouts/PitArenaMine02/map.bin and b/data/layouts/PitArenaMine02/map.bin differ diff --git a/data/layouts/PitArenaMine03/map.bin b/data/layouts/PitArenaMine03/map.bin index 7b3d1ec73287..ce72c5a142a8 100644 Binary files a/data/layouts/PitArenaMine03/map.bin and b/data/layouts/PitArenaMine03/map.bin differ diff --git a/data/maps/PitArenaDesert03/map.json b/data/maps/PitArenaDesert03/map.json index ebed5f55f94f..cd5f91b943c8 100644 --- a/data/maps/PitArenaDesert03/map.json +++ b/data/maps/PitArenaDesert03/map.json @@ -29,7 +29,7 @@ }, { "graphics_id": "OBJ_EVENT_GFX_VAR_1", - "x": 16, + "x": 15, "y": 14, "elevation": 0, "movement_type": "MOVEMENT_TYPE_WANDER_UP_AND_DOWN", @@ -81,7 +81,7 @@ }, { "graphics_id": "OBJ_EVENT_GFX_VAR_1", - "x": 16, + "x": 15, "y": 14, "elevation": 0, "movement_type": "MOVEMENT_TYPE_WANDER_UP_AND_DOWN", diff --git a/data/maps/PitArenaDirtPath02/map.json b/data/maps/PitArenaDirtPath02/map.json index f7190e9be515..94daa61c55f1 100644 --- a/data/maps/PitArenaDirtPath02/map.json +++ b/data/maps/PitArenaDirtPath02/map.json @@ -16,7 +16,7 @@ "object_events": [ { "graphics_id": "OBJ_EVENT_GFX_VAR_0", - "x": 4, + "x": 5, "y": 13, "elevation": 0, "movement_type": "MOVEMENT_TYPE_WANDER_UP_AND_DOWN", @@ -68,7 +68,7 @@ }, { "graphics_id": "OBJ_EVENT_GFX_VAR_0", - "x": 4, + "x": 5, "y": 13, "elevation": 0, "movement_type": "MOVEMENT_TYPE_WANDER_UP_AND_DOWN", diff --git a/data/maps/PitArenaMine/map.json b/data/maps/PitArenaMine/map.json index 0797d7835cff..f0a2cebfe078 100644 --- a/data/maps/PitArenaMine/map.json +++ b/data/maps/PitArenaMine/map.json @@ -55,8 +55,8 @@ }, { "graphics_id": "OBJ_EVENT_GFX_VAR_3", - "x": 4, - "y": 13, + "x": 6, + "y": 12, "elevation": 0, "movement_type": "MOVEMENT_TYPE_WANDER_LEFT_AND_RIGHT", "movement_range_x": 3, @@ -107,8 +107,8 @@ }, { "graphics_id": "OBJ_EVENT_GFX_VAR_3", - "x": 4, - "y": 13, + "x": 6, + "y": 12, "elevation": 0, "movement_type": "MOVEMENT_TYPE_WANDER_LEFT_AND_RIGHT", "movement_range_x": 3, diff --git a/data/maps/PitEntrance/scripts.inc b/data/maps/PitEntrance/scripts.inc index d85ac2c2a4d1..b72eaf7d0e24 100644 --- a/data/maps/PitEntrance/scripts.inc +++ b/data/maps/PitEntrance/scripts.inc @@ -437,8 +437,6 @@ PitEntrance_Text_MoreInfo:: .string "Every 5th floor is a Heal/Shop floor\n" .string "where you will be able to rest and\l" .string "prepare for the next Trial.\p" - .string "Every ten floors there will be\n" - .string "a Move Tutor.\p" .string "And every 25th floor there will be a\n" .string "boss fight after that you will be able\l" .string "to choose another random Pokémon.$" diff --git a/data/scripts/pit_mon_encounters.inc b/data/scripts/pit_mon_encounters.inc index 7203d44b0e25..f862a85d44a4 100644 --- a/data/scripts/pit_mon_encounters.inc +++ b/data/scripts/pit_mon_encounters.inc @@ -364,8 +364,8 @@ PitEncounter_Mover:: msgbox PitEncounter_NPCMoverOpen, MSGBOX_DEFAULT message PitEncounter_NPCMoverOpen2 dynmultichoice 17, 1, 0, 5, 0, DYN_MULTICHOICE_CB_NONE, PitEncounter_NPCMover2, PitEncounter_NPCMover3, PitShop_ShopNPC_Option8 - goto_if_eq VAR_RESULT, 0, PitEncounter_MoverSkip2 - goto_if_eq VAR_RESULT, 1, PitEncounter_MoverSkip3 + goto_if_eq VAR_RESULT, 0, PitEncounter_MoverSkip1 + goto_if_eq VAR_RESULT, 1, PitEncounter_MoverSkip2 closemessage EndOfMoverScript:: release @@ -374,27 +374,27 @@ EndOfMoverScript:: PitEncounter_NPCMoverOpen: .string "Abra has a special offer for you!\pIt can teleport you away.$" PitEncounter_NPCMoverOpen2: - .string "Free Rare Candy Included With Purchase!$" + .string "Free Rare Candies included with purchase!$" -PitEncounter_MoverSkip2:: - additem ITEM_RARE_CANDY, 2 +PitEncounter_MoverSkip1:: + additem ITEM_RARE_CANDY, 1 setflag FLAG_LEVEL_UP_TWICE setflag FLAG_FLOOR_CLEARED call PitEncounter_Common_AfterUse callnative SetWarpTileActive - addvar VAR_PIT_FLOOR, 1 + addvar VAR_PIT_FLOOR, 0 special DrawWholeMapView goto Pit_Warp_Advance_Floor release end -PitEncounter_MoverSkip3:: - additem ITEM_RARE_CANDY, 3 +PitEncounter_MoverSkip2:: + additem ITEM_RARE_CANDY, 2 setflag FLAG_FLOOR_CLEARED setflag FLAG_LEVEL_UP_THRICE callnative SetWarpTileActive call PitEncounter_Common_AfterUse - addvar VAR_PIT_FLOOR, 2 + addvar VAR_PIT_FLOOR, 1 special DrawWholeMapView goto Pit_Warp_Advance_Floor release @@ -427,9 +427,9 @@ PitEncounter_NPCMoverNotEnoughMoneyText: .string "Not enough money...$" PitEncounter_NPCMover2: - .string "Skip 2 Floors$" + .string "Skip 1 Floor (1RC)$" PitEncounter_NPCMover3: - .string "Skip 3 Floors$" + .string "Skip 2 Floors (2RC)$" PitEncounter_NPCMover4: .string "Wonder Trade$" diff --git a/data/text/frontier_brain.inc b/data/text/frontier_brain.inc index b9fc14b1c955..650c54f629c8 100644 --- a/data/text/frontier_brain.inc +++ b/data/text/frontier_brain.inc @@ -682,7 +682,7 @@ gText_GriffinDefeat:: .string "You've won but at what cost…$" gText_wiz1989Defeat:: - .string "This is also great content!$" + .string "This was great content!$" gText_AereonDefeat:: .string "Don't let your guard down!$" diff --git a/data/tilesets/secondary/pit_arena_beach_cave/metatiles.bin b/data/tilesets/secondary/pit_arena_beach_cave/metatiles.bin index 49d7fe42ed16..f71e2446e9a0 100644 Binary files a/data/tilesets/secondary/pit_arena_beach_cave/metatiles.bin and b/data/tilesets/secondary/pit_arena_beach_cave/metatiles.bin differ diff --git a/graphics/pokemon/jellicent/overworld.png b/graphics/pokemon/jellicent/overworld.png index 315750cd18d1..89c10df837a8 100644 Binary files a/graphics/pokemon/jellicent/overworld.png and b/graphics/pokemon/jellicent/overworld.png differ diff --git a/include/battle.h b/include/battle.h index 1080faa0460e..a37c8678e077 100644 --- a/include/battle.h +++ b/include/battle.h @@ -201,6 +201,8 @@ struct ProtectStruct u16 eatMirrorHerb:1; u16 activateOpportunist:2; // 2 - to copy stats. 1 - stats copied (do not repeat). 0 - no stats to copy u16 usedAllySwitch:1; + u16 padding:2; + // End of 16-bit bitfield u32 physicalDmg; u32 specialDmg; u8 physicalBattlerId; @@ -803,11 +805,15 @@ struct BattleStruct u8 boosterEnergyActivates; u8 distortedTypeMatchups; u8 categoryOverride; // for Z-Moves and Max Moves + u8 commandingDondozo; + u16 commanderActive[MAX_BATTLERS_COUNT]; u32 stellarBoostFlags[NUM_BATTLE_SIDES]; // stored as a bitfield of flags for all types for each side u8 fickleBeamBoosted:1; u8 redCardActivates:1; - u8 padding:6; + u8 obedienceResult:3; + u8 padding:3; u8 usedMicleBerry; + u8 usedEjectItem; }; // The palaceFlags member of struct BattleStruct contains 1 flag per move to indicate which moves the AI should consider, @@ -1147,6 +1153,12 @@ static inline u32 GetBattlerSide(u32 battler) return GetBattlerPosition(battler) & BIT_SIDE; } +static inline struct Pokemon* GetPartyBattlerData(u32 battler) +{ + u32 index = gBattlerPartyIndexes[battler]; + return (GetBattlerSide(battler) == B_SIDE_OPPONENT) ? &gEnemyParty[index] : &gPlayerParty[index]; +} + static inline struct Pokemon *GetSideParty(u32 side) { return (side == B_SIDE_PLAYER) ? gPlayerParty : gEnemyParty; diff --git a/include/battle_script_commands.h b/include/battle_script_commands.h index 4f1593d4d821..7326647d419d 100644 --- a/include/battle_script_commands.h +++ b/include/battle_script_commands.h @@ -57,6 +57,8 @@ bool32 IsMoveNotAllowedInSkyBattles(u32 move); bool32 DoSwitchInAbilities(u32 battlerId); u8 GetFirstFaintedPartyIndex(u8 battlerId); bool32 IsMoveAffectedByParentalBond(u32 move, u32 battler); +void SaveBattlerTarget(u32 battler); +void SaveBattlerAttacker(u32 battler); extern void (* const gBattleScriptingCommandsTable[])(void); extern const struct StatFractions gAccuracyStageRatios[]; diff --git a/include/battle_scripts.h b/include/battle_scripts.h index 4e34a81da8f8..7de4097cf269 100644 --- a/include/battle_scripts.h +++ b/include/battle_scripts.h @@ -413,6 +413,7 @@ extern const u8 BattleScript_BattlerGotOverItsInfatuation[]; extern const u8 BattleScript_Pickpocket[]; extern const u8 BattleScript_StickyBarbTransfer[]; extern const u8 BattleScript_AttackerItemStatRaise[]; +extern const u8 BattleScript_RedCardActivationNoSwitch[]; extern const u8 BattleScript_RedCardActivates[]; extern const u8 BattleScript_EjectButtonActivates[]; extern const u8 BattleScript_EjectPackActivate_Ret[]; @@ -479,6 +480,7 @@ extern const u8 BattleScript_CudChewActivates[]; extern const u8 BattleScript_SupremeOverlordActivates[]; extern const u8 BattleScript_CostarActivates[]; extern const u8 BattleScript_ZeroToHeroActivates[]; +extern const u8 BattleScript_CommanderActivates[]; extern const u8 BattleScript_HospitalityActivates[]; extern const u8 BattleScript_ToxicDebrisActivates[]; extern const u8 BattleScript_EarthEaterActivates[]; diff --git a/include/battle_util.h b/include/battle_util.h index 7a02d959902a..d1b188f6f321 100644 --- a/include/battle_util.h +++ b/include/battle_util.h @@ -283,5 +283,6 @@ bool8 CanMonParticipateInSkyBattle(struct Pokemon *mon); bool8 IsMonBannedFromSkyBattles(u16 species); void RemoveBattlerType(u32 battler, u8 type); u32 GetCalcedMoveBasePower(u32 move, u32 battlerAtk, u32 weather); +u32 DoesDestinyBondFail(u32 battler); #endif // GUARD_BATTLE_UTIL_H diff --git a/include/config/battle.h b/include/config/battle.h index d0668932a93a..3798f3408b09 100644 --- a/include/config/battle.h +++ b/include/config/battle.h @@ -126,6 +126,7 @@ #define B_POWDER_RAIN GEN_LATEST // In Gen7+, Powder doesn't damage the user of a Fire type move in heavy rain. #define B_AFTER_YOU_TURN_ORDER GEN_LATEST // In Gen8+, After You doesn't fail if the turn order wouldn't change after use. #define B_QUASH_TURN_ORDER GEN_LATEST // In Gen8+, Quash-affected battlers move according to speed order. Before Gen8, Quash-affected battlers move in the order they were affected by Quash. +#define B_DESTINY_BOND_FAIL GEN_LATEST // In Gen7+, Destiny Bond fails if used repeatedly. // Ability settings #define B_EXPANDED_ABILITY_NAMES TRUE // If TRUE, ability names are increased from 12 characters to 16 characters. @@ -165,7 +166,7 @@ #define B_MENTAL_HERB GEN_LATEST // In Gen5+, the Mental Herb cures Taunt, Encore, Torment, Heal Block, and Disable in addition to Infatuation from before. #define B_TRAINERS_KNOCK_OFF_ITEMS TRUE // If TRUE, trainers can steal/swap your items (non-berries are restored after battle). In vanilla games trainers cannot steal items. #define B_RETURN_STOLEN_NPC_ITEMS GEN_3 // In Gen5+, Thief and Covet no longer steal items from NPCs. -#define B_RESTORE_HELD_BATTLE_ITEMS GEN_LATEST // In Gen9, all non-berry items are restored after battle. +#define B_RESTORE_HELD_BATTLE_ITEMS GEN_9 // In Gen9, all non-berry items are restored after battle. #define B_SOUL_DEW_BOOST GEN_LATEST // In Gens3-6, Soul Dew boosts Latis' Sp. Atk and Sp. Def. In Gen7+ it boosts the power of their Psychic and Dragon type moves instead. #define B_NET_BALL_MODIFIER GEN_LATEST // In Gen7+, Net Ball's catch multiplier is x5 instead of x3. #define B_DIVE_BALL_MODIFIER GEN_LATEST // In Gen4+, Dive Ball's effectiveness increases by x3.5 when Surfing or Fishing. diff --git a/include/constants/battle.h b/include/constants/battle.h index 2e35391643ef..9227764c0269 100644 --- a/include/constants/battle.h +++ b/include/constants/battle.h @@ -169,7 +169,7 @@ #define STATUS3_YAWN_TURN(num) (((num) << 11) & STATUS3_YAWN) #define STATUS3_IMPRISONED_OTHERS (1 << 13) #define STATUS3_GRUDGE (1 << 14) -#define STATUS3___UNUSED (1 << 15) +#define STATUS3_COMMANDER (1 << 15) #define STATUS3_GASTRO_ACID (1 << 16) #define STATUS3_EMBARGO (1 << 17) #define STATUS3_UNDERWATER (1 << 18) @@ -186,7 +186,8 @@ #define STATUS3_LASER_FOCUS (1 << 29) #define STATUS3_POWER_TRICK (1 << 30) #define STATUS3_SKY_DROPPED (1 << 31) // Target of Sky Drop -#define STATUS3_SEMI_INVULNERABLE (STATUS3_UNDERGROUND | STATUS3_ON_AIR | STATUS3_UNDERWATER | STATUS3_PHANTOM_FORCE) +#define STATUS3_SEMI_INVULNERABLE_NO_COMMANDER (STATUS3_UNDERGROUND | STATUS3_ON_AIR | STATUS3_UNDERWATER | STATUS3_PHANTOM_FORCE) // Exception for Transform / Imposter +#define STATUS3_SEMI_INVULNERABLE (STATUS3_SEMI_INVULNERABLE_NO_COMMANDER | STATUS3_COMMANDER) #define STATUS4_ELECTRIFIED (1 << 0) #define STATUS4_MUD_SPORT (1 << 1) // Only used if B_SPORT_TURNS < GEN_6 @@ -404,8 +405,9 @@ #define MOVE_EFFECT_SECRET_POWER 77 #define MOVE_EFFECT_PSYCHIC_NOISE 78 #define MOVE_EFFECT_TERA_BLAST 79 +#define MOVE_EFFECT_ORDER_UP 80 -#define NUM_MOVE_EFFECTS 80 +#define NUM_MOVE_EFFECTS 81 #define MOVE_EFFECT_AFFECTS_USER 0x2000 #define MOVE_EFFECT_CERTAIN 0x4000 diff --git a/include/constants/battle_move_effects.h b/include/constants/battle_move_effects.h index 5da278110f2c..770e773f806d 100644 --- a/include/constants/battle_move_effects.h +++ b/include/constants/battle_move_effects.h @@ -354,6 +354,7 @@ enum { EFFECT_DRAGON_DARTS, EFFECT_GUARDIAN_OF_ALOLA, EFFECT_SHELL_SIDE_ARM, + EFFECT_ORDER_UP, NUM_BATTLE_MOVE_EFFECTS, }; diff --git a/include/constants/battle_string_ids.h b/include/constants/battle_string_ids.h index 9fbb70a22397..08c80248fe7f 100644 --- a/include/constants/battle_string_ids.h +++ b/include/constants/battle_string_ids.h @@ -712,8 +712,9 @@ #define STRINGID_FOGLIFTED 710 #define STRINGID_PKMNMADESHELLGLEAM 711 #define STRINGID_FICKLEBEAMDOUBLED 712 +#define STRINGID_COMMANDERACTIVATES 713 -#define BATTLESTRINGS_COUNT 713 +#define BATTLESTRINGS_COUNT 714 // This is the string id that gBattleStringsTable starts with. // String ids before this (e.g. STRINGID_INTROMSG) are not in the table, diff --git a/include/global.h b/include/global.h index 2b99806d167f..b7a7dd864075 100644 --- a/include/global.h +++ b/include/global.h @@ -609,7 +609,7 @@ struct SaveBlock2 u16 randomBattleWeather:2; u16 optionsBattleSpeed:2; u16 modeTrainerEVs:1; - u16 filler_9912:1; + u16 padding:1; //end of u16 // #### running stats for The Pit - START #### @@ -645,7 +645,8 @@ struct SaveBlock2 u8 hasRecievedShinyDust; u8 forceNewRun; u8 hasReceivedShedinja; - u8 pit_padding[63]; + u8 modeMonoType; //0 = all types, rest is based on type defines in constants/pokemon.h + u8 pit_padding[62]; struct HallofFameTeam2 tempHofMon; diff --git a/include/pit.h b/include/pit.h index 5cba29c1f16a..211c4444e898 100644 --- a/include/pit.h +++ b/include/pit.h @@ -52,8 +52,10 @@ void ClearAllRandomBossEncounters(void); u32 GetTrainerSpeciesFromRandomArray(u16 index, bool8 forceAllSpecies); u32 GetPlayerSpeciesFromRandomArray(u16 index, bool8 forceAllSpecies); +u32 GetMonoTypeNumberOfSpecies(void); u32 GetMaxPlayerNumberOfSpecies(bool8 forceAllSpecies); void ClearGeneratedMons(void); +void ResetMonoTypeArray(void); struct RandomTrainerNPC { diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index 09474594b45f..0872c0b3e076 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -842,6 +842,9 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) if (IsTwoTurnNotSemiInvulnerableMove(battlerAtk, move) && CanTargetFaintAi(battlerDef, battlerAtk)) RETURN_SCORE_MINUS(10); + if (gBattleStruct->commandingDondozo & (1u << battlerDef)) + RETURN_SCORE_MINUS(20); + // check if negates type switch (effectiveness) { @@ -1987,6 +1990,8 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) ADJUST_SCORE(-10); break; case EFFECT_DESTINY_BOND: + if (DoesDestinyBondFail(battlerAtk)) + ADJUST_SCORE(-10); if (gBattleMons[battlerDef].status2 & STATUS2_DESTINY_BOND) ADJUST_SCORE(-10); else if (GetActiveGimmick(battlerDef) == GIMMICK_DYNAMAX) diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index 419c39b924cb..1ef2a48d32e9 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -413,6 +413,9 @@ bool32 IsDamageMoveUnusable(u32 move, u32 battlerAtk, u32 battlerDef) if (battlerDef == BATTLE_PARTNER(battlerAtk)) battlerDefAbility = aiData->abilities[battlerDef]; + if (gBattleStruct->commandingDondozo & (1u << battlerDef)) + return TRUE; + switch (battlerDefAbility) { case ABILITY_LIGHTNING_ROD: @@ -1489,6 +1492,8 @@ bool32 IsSemiInvulnerable(u32 battlerDef, u32 move) { if (gStatuses3[battlerDef] & STATUS3_PHANTOM_FORCE) return TRUE; + else if (gBattleStruct->commandingDondozo & (1u << battlerDef)) + return TRUE; else if (!gMovesInfo[move].damagesAirborne && gStatuses3[battlerDef] & STATUS3_ON_AIR) return TRUE; else if (!gMovesInfo[move].damagesUnderwater && gStatuses3[battlerDef] & STATUS3_UNDERWATER) diff --git a/src/battle_main.c b/src/battle_main.c index a01d810fdb5f..d1f687c9f169 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -3624,6 +3624,16 @@ const u8* FaintClearSetData(u32 battler) gBattleStruct->palaceFlags &= ~(gBitTable[battler]); gBattleStruct->boosterEnergyActivates &= ~(gBitTable[battler]); + if (gBattleStruct->commanderActive[battler] != SPECIES_NONE) + { + u32 partner = BATTLE_PARTNER(battler); + if (IsBattlerAlive(partner)) + { + BtlController_EmitSpriteInvisibility(partner, BUFFER_A, FALSE); + MarkBattlerForControllerExec(partner); + } + } + for (i = 0; i < ARRAY_COUNT(gSideTimers); i++) { // User of sticky web fainted, so reset the stored battler ID @@ -4477,7 +4487,7 @@ static void HandleTurnActionSelectionState(void) || gBattleStruct->absentBattlerFlags & gBitTable[GetBattlerAtPosition(BATTLE_PARTNER(position))] || gBattleCommunication[GetBattlerAtPosition(BATTLE_PARTNER(position))] == STATE_WAIT_ACTION_CONFIRMED) { - if (gBattleStruct->absentBattlerFlags & gBitTable[battler]) + if ((gBattleStruct->absentBattlerFlags & gBitTable[battler]) || (gBattleStruct->commandingDondozo & (1u << battler))) { gChosenActionByBattler[battler] = B_ACTION_NOTHING_FAINTED; if (!(gBattleTypeFlags & BATTLE_TYPE_MULTI)) @@ -5399,14 +5409,18 @@ static void TurnValuesCleanUp(bool8 var0) if (gDisableStructs[i].substituteHP == 0) gBattleMons[i].status2 &= ~STATUS2_SUBSTITUTE; + if (!(gStatuses3[i] & STATUS3_COMMANDER)) + gBattleStruct->commandingDondozo &= ~(1u << i); + gSpecialStatuses[i].parentalBondState = PARENTAL_BOND_OFF; } gSideStatuses[B_SIDE_PLAYER] &= ~(SIDE_STATUS_QUICK_GUARD | SIDE_STATUS_WIDE_GUARD | SIDE_STATUS_CRAFTY_SHIELD | SIDE_STATUS_MAT_BLOCK); gSideStatuses[B_SIDE_OPPONENT] &= ~(SIDE_STATUS_QUICK_GUARD | SIDE_STATUS_WIDE_GUARD | SIDE_STATUS_CRAFTY_SHIELD | SIDE_STATUS_MAT_BLOCK); gSideTimers[B_SIDE_PLAYER].followmeTimer = 0; - gSideTimers[B_SIDE_OPPONENT].followmeTimer = 0; - + + + gBattleStruct->usedEjectItem = 0; gBattleStruct->pledgeMove = FALSE; // combined pledge move may not have been used due to a canceller } diff --git a/src/battle_message.c b/src/battle_message.c index 0391b095177b..7471e523a996 100644 --- a/src/battle_message.c +++ b/src/battle_message.c @@ -836,7 +836,8 @@ static const u8 sText_TargetIsBeingSaltCured[] = _("{B_DEF_NAME_WITH_PREFIX} is static const u8 sText_TargetIsHurtBySaltCure[] = _("{B_DEF_NAME_WITH_PREFIX} is hurt by {B_BUFF1}!"); static const u8 sText_TargetCoveredInStickyCandySyrup[] = _("{B_DEF_NAME_WITH_PREFIX} got covered\nin sticky syrup!"); static const u8 sText_PkmnTellChillingReceptionJoke[] = _("{B_ATK_NAME_WITH_PREFIX} is preparing to tell a\nchillingly bad joke!"); -static const u8 sText_ZeroToHeroTransformation[] = _("{B_ATK_NAME_WITH_PREFIX} underwent a heroic\ntransformation!"); +static const u8 sText_ZeroToHeroTransformation[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX} underwent a heroic\ntransformation!"); +static const u8 sText_CommanderActivates[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX} was swallowed by Dondozo\nand became Dondozo's commander!"); static const u8 sText_TheTwoMovesBecomeOne[] = _("The two moves become one!\nIt's a combined move!{PAUSE 16}"); static const u8 sText_ARainbowAppearedOnSide[] = _("A rainbow appeared in the sky\non {B_ATK_TEAM2} team's side!"); static const u8 sText_TheRainbowDisappeared[] = _("The rainbow on {B_ATK_TEAM2}\nside disappeared!"); @@ -875,6 +876,7 @@ const u8 *const gBattleStringsTable[BATTLESTRINGS_COUNT] = [STRINGID_ARAINBOWAPPEAREDONSIDE - BATTLESTRINGS_TABLE_START] = sText_ARainbowAppearedOnSide, [STRINGID_THETWOMOVESBECOMEONE - BATTLESTRINGS_TABLE_START] = sText_TheTwoMovesBecomeOne, [STRINGID_ZEROTOHEROTRANSFORMATION - BATTLESTRINGS_TABLE_START] = sText_ZeroToHeroTransformation, + [STRINGID_COMMANDERACTIVATES - BATTLESTRINGS_TABLE_START] = sText_CommanderActivates, [STRINGID_PKMNTELLCHILLINGRECEPTIONJOKE - BATTLESTRINGS_TABLE_START] = sText_PkmnTellChillingReceptionJoke, [STRINGID_MOVEBLOCKEDBYDYNAMAX - BATTLESTRINGS_TABLE_START] = sText_MoveBlockedByDynamax, [STRINGID_TARGETISHURTBYSALTCURE - BATTLESTRINGS_TABLE_START] = sText_TargetIsHurtBySaltCure, diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 47a44f30fd1e..e97e2047cce8 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -339,8 +339,6 @@ static bool8 CanBurnHitThaw(u16 move); static u32 GetNextTarget(u32 moveTarget, bool32 excludeCurrent); static void TryUpdateEvolutionTracker(u32 evolutionMethod, u32 upAmount, u16 usedMove); static void AccuracyCheck(bool32 recalcDragonDarts, const u8 *nextInstr, const u8 *failInstr, u16 move); -static void SaveBattlerAttacker(u32 battler); -static void SaveBattlerTarget(u32 battler); static void Cmd_attackcanceler(void); static void Cmd_accuracycheck(void); @@ -512,7 +510,7 @@ static void Cmd_settypetorandomresistance(void); static void Cmd_setalwayshitflag(void); static void Cmd_copymovepermanently(void); static void Cmd_trychoosesleeptalkmove(void); -static void Cmd_setdestinybond(void); +static void Cmd_trysetdestinybond(void); static void Cmd_trysetdestinybondtohappen(void); static void Cmd_settailwind(void); static void Cmd_tryspiteppreduce(void); @@ -771,7 +769,7 @@ void (* const gBattleScriptingCommandsTable[])(void) = Cmd_setalwayshitflag, //0xA7 Cmd_copymovepermanently, //0xA8 Cmd_trychoosesleeptalkmove, //0xA9 - Cmd_setdestinybond, //0xAA + Cmd_trysetdestinybond, //0xAA Cmd_trysetdestinybondtohappen, //0xAB Cmd_settailwind, //0xAC Cmd_tryspiteppreduce, //0xAD @@ -1198,6 +1196,13 @@ static void Cmd_attackcanceler(void) u16 attackerAbility = GetBattlerAbility(gBattlerAttacker); GET_MOVE_TYPE(gCurrentMove, moveType); + if (gBattleStruct->usedEjectItem & (1u << gBattlerAttacker)) + { + gBattleStruct->usedEjectItem = 0; + gCurrentActionFuncId = B_ACTION_TRY_FINISH; + return; + } + // Weight-based moves are blocked by Dynamax. if ((GetActiveGimmick(gBattlerTarget) == GIMMICK_DYNAMAX) && IsMoveBlockedByDynamax(gCurrentMove)) { @@ -1476,14 +1481,17 @@ static bool32 AccuracyCalcHelper(u16 move) return TRUE; } // If the attacker has the ability No Guard and they aren't targeting a Pokemon involved in a Sky Drop with the move Sky Drop, move hits. - else if (GetBattlerAbility(gBattlerAttacker) == ABILITY_NO_GUARD && (move != MOVE_SKY_DROP || gBattleStruct->skyDropTargets[gBattlerTarget] == 0xFF)) + else if (GetBattlerAbility(gBattlerAttacker) == ABILITY_NO_GUARD + && !(gStatuses3[gBattlerTarget] & STATUS3_COMMANDER) + && (gMovesInfo[move].effect != EFFECT_SKY_DROP || gBattleStruct->skyDropTargets[gBattlerTarget] == 0xFF)) { if (!JumpIfMoveFailed(7, move)) RecordAbilityBattle(gBattlerAttacker, ABILITY_NO_GUARD); return TRUE; } // If the target has the ability No Guard and they aren't involved in a Sky Drop or the current move isn't Sky Drop, move hits. - else if (GetBattlerAbility(gBattlerTarget) == ABILITY_NO_GUARD && (move != MOVE_SKY_DROP || gBattleStruct->skyDropTargets[gBattlerTarget] == 0xFF)) + else if (GetBattlerAbility(gBattlerTarget) == ABILITY_NO_GUARD + && (gMovesInfo[move].effect != EFFECT_SKY_DROP || gBattleStruct->skyDropTargets[gBattlerTarget] == 0xFF)) { if (!JumpIfMoveFailed(7, move)) RecordAbilityBattle(gBattlerTarget, ABILITY_NO_GUARD); @@ -1504,7 +1512,8 @@ static bool32 AccuracyCalcHelper(u16 move) return TRUE; } - if ((gStatuses3[gBattlerTarget] & STATUS3_PHANTOM_FORCE) + if ((gStatuses3[gBattlerTarget] & STATUS3_COMMANDER) + || (gStatuses3[gBattlerTarget] & STATUS3_PHANTOM_FORCE) || ((gStatuses3[gBattlerTarget] & STATUS3_ON_AIR) && !(gMovesInfo[move].damagesAirborne || gMovesInfo[move].damagesAirborneDoubleDamage)) || ((gStatuses3[gBattlerTarget] & STATUS3_UNDERGROUND) && !gMovesInfo[move].damagesUnderground) || ((gStatuses3[gBattlerTarget] & STATUS3_UNDERWATER) && !gMovesInfo[move].damagesUnderwater)) @@ -2836,6 +2845,7 @@ void SetMoveEffect(bool32 primary, bool32 certain) if (!(gHitMarker & HITMARKER_STATUS_ABILITY_EFFECT) && TestIfSheerForceAffected(gBattlerAttacker, gCurrentMove) + && !(gMovesInfo[gCurrentMove].effect == EFFECT_ORDER_UP && gBattleStruct->commanderActive[gBattlerAttacker]) && !primary && gBattleScripting.moveEffect != MOVE_EFFECT_CHARGING) INCREMENT_RESET_RETURN @@ -3815,6 +3825,43 @@ void SetMoveEffect(bool32 primary, bool32 certain) gBattlescriptCurrInstr = BattleScript_LowerAtkSpAtk; } break; + case MOVE_EFFECT_ORDER_UP: + { + u32 stat = 0; + bool32 commanderAffected = TRUE; + switch (gBattleStruct->commanderActive[gEffectBattler]) + { + case SPECIES_TATSUGIRI_CURLY: + stat = STAT_ATK; + break; + case SPECIES_TATSUGIRI_DROOPY: + stat = STAT_DEF; + break; + case SPECIES_TATSUGIRI_STRETCHY: + stat = STAT_SPEED; + break; + default: + commanderAffected = FALSE; + break; + } + if (!commanderAffected + || NoAliveMonsForEitherParty() + || ChangeStatBuffs(SET_STAT_BUFF_VALUE(1), + stat, + affectsUser | STAT_CHANGE_UPDATE_MOVE_EFFECT, + 0) == STAT_CHANGE_DIDNT_WORK) + { + gBattlescriptCurrInstr++; + } + else + { + gBattleScripting.animArg1 = gBattleScripting.moveEffect & ~(MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_CERTAIN); + gBattleScripting.animArg2 = 0; + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_StatUp; + } + } + break; } } } @@ -6178,6 +6225,7 @@ static void Cmd_moveend(void) gBattlescriptCurrInstr = BattleScript_MoveEnd; // Prevent user switch-in selection effect = TRUE; BattleScriptPushCursor(); + gBattleStruct->usedEjectItem |= 1u << battler; if (ejectButtonBattlers & gBitTable[battler]) { gBattlescriptCurrInstr = BattleScript_EjectButtonActivates; @@ -6256,8 +6304,15 @@ static void Cmd_moveend(void) if (gMovesInfo[gCurrentMove].effect == EFFECT_HIT_ESCAPE) gBattlescriptCurrInstr = BattleScript_MoveEnd; // Prevent user switch-in selection BattleScriptPushCursor(); - gBattlescriptCurrInstr = BattleScript_RedCardActivates; - gSpecialStatuses[gBattlerAttacker].preventLifeOrbDamage = TRUE; + if (gBattleStruct->commanderActive[gBattlerAttacker] != SPECIES_NONE) + { + gBattlescriptCurrInstr = BattleScript_RedCardActivationNoSwitch; + } + else + { + gBattlescriptCurrInstr = BattleScript_RedCardActivates; + gSpecialStatuses[gBattlerAttacker].preventLifeOrbDamage = TRUE; + } effect = TRUE; break; // Only fastest red card activates } @@ -6472,7 +6527,18 @@ static void Cmd_moveend(void) SetActiveGimmick(gBattlerAttacker, GIMMICK_NONE); if (B_CHARGE <= GEN_8 || moveType == TYPE_ELECTRIC) gStatuses3[gBattlerAttacker] &= ~(STATUS3_CHARGED_UP); - memset(gQueuedStatBoosts, 0, sizeof(gQueuedStatBoosts)); + + for (i = 0; i < gBattlersCount; i++) + { + if (gBattleStruct->commanderActive[i] != SPECIES_NONE && !IsBattlerAlive(i)) + { + u32 partner = BATTLE_PARTNER(i); + gBattleStruct->commanderActive[i] = SPECIES_NONE; + if (IsBattlerAlive(partner)) + gStatuses3[partner] &= ~STATUS3_COMMANDER; + } + } + gBattleScripting.moveendState++; break; case MOVEEND_COUNT: @@ -7373,6 +7439,7 @@ static bool32 DoSwitchInEffectsForBattler(u32 battler) switch (GetBattlerAbility(i)) { case ABILITY_TRACE: + case ABILITY_COMMANDER: if (AbilityBattleEffects(ABILITYEFFECT_ON_SWITCHIN, i, 0, 0, 0)) return TRUE; break; @@ -12602,7 +12669,7 @@ static void Cmd_transformdataexecution(void) gBattlescriptCurrInstr = cmd->nextInstr; if (gBattleMons[gBattlerTarget].status2 & STATUS2_TRANSFORMED || gBattleStruct->illusion[gBattlerTarget].on - || gStatuses3[gBattlerTarget] & STATUS3_SEMI_INVULNERABLE) + || gStatuses3[gBattlerTarget] & STATUS3_SEMI_INVULNERABLE_NO_COMMANDER) { gMoveResultFlags |= MOVE_RESULT_FAILED; gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_TRANSFORM_FAILED; @@ -13173,12 +13240,18 @@ static void Cmd_trychoosesleeptalkmove(void) } } -static void Cmd_setdestinybond(void) +static void Cmd_trysetdestinybond(void) { - CMD_ARGS(); - - gBattleMons[gBattlerAttacker].status2 |= STATUS2_DESTINY_BOND; - gBattlescriptCurrInstr = cmd->nextInstr; + CMD_ARGS(const u8 *failInstr); + if (DoesDestinyBondFail(gBattlerAttacker)) + { + gBattlescriptCurrInstr = cmd->failInstr; + } + else + { + gBattleMons[gBattlerAttacker].status2 |= STATUS2_DESTINY_BOND; + gBattlescriptCurrInstr = cmd->nextInstr; + } } static void TrySetDestinyBondToHappen(void) @@ -13454,7 +13527,8 @@ static void Cmd_trysetperishsong(void) { if (gStatuses3[i] & STATUS3_PERISH_SONG || GetBattlerAbility(i) == ABILITY_SOUNDPROOF - || BlocksPrankster(gCurrentMove, gBattlerAttacker, i, TRUE)) + || BlocksPrankster(gCurrentMove, gBattlerAttacker, i, TRUE) + || gStatuses3[i] & STATUS3_COMMANDER) { notAffectedCount++; } @@ -15872,7 +15946,7 @@ static void Cmd_callnative(void) // Callnative Funcs -static void SaveBattlerTarget(u32 battler) +void SaveBattlerTarget(u32 battler) { if (gBattleStruct->savedTargetCount < NELEMS(gBattleStruct->savedBattlerTarget)) gBattleStruct->savedBattlerTarget[gBattleStruct->savedTargetCount++] = battler; @@ -15880,7 +15954,7 @@ static void SaveBattlerTarget(u32 battler) DebugPrintfLevel(MGBA_LOG_WARN, "Attempting to exceed savedBattlerTarget array size!"); } -static void SaveBattlerAttacker(u32 battler) +void SaveBattlerAttacker(u32 battler) { if (gBattleStruct->savedAttackerCount < NELEMS(gBattleStruct->savedBattlerAttacker)) gBattleStruct->savedBattlerAttacker[gBattleStruct->savedAttackerCount++] = battler; @@ -17359,3 +17433,15 @@ void BS_SetMagicCoatTarget(void) gBattlescriptCurrInstr = cmd->nextInstr; } + +void BS_JumpIfCommanderActive(void) +{ + NATIVE_ARGS(const u8 *jumpInstr); + + if (gBattleStruct->commanderActive[gBattlerTarget] != SPECIES_NONE) + gBattlescriptCurrInstr = cmd->jumpInstr; + else if (gStatuses3[gBattlerTarget] & STATUS3_COMMANDER) + gBattlescriptCurrInstr = cmd->jumpInstr; + else + gBattlescriptCurrInstr = cmd->nextInstr; +} diff --git a/src/battle_util.c b/src/battle_util.c index 425bc126e450..31e44872e350 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -131,7 +131,9 @@ void HandleAction_UseMove(void) u16 moveTarget; gBattlerAttacker = gBattlerByTurnOrder[gCurrentTurnActionNumber]; - if (gBattleStruct->absentBattlerFlags & gBitTable[gBattlerAttacker] || !IsBattlerAlive(gBattlerAttacker)) + if (gBattleStruct->absentBattlerFlags & (1u << gBattlerAttacker) + || gBattleStruct->commandingDondozo & (1u << gBattlerAttacker) + || !IsBattlerAlive(gBattlerAttacker)) { gCurrentActionFuncId = B_ACTION_FINISHED; return; @@ -4150,7 +4152,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 u32 moveType, move; u32 side; u32 i, j; - u32 partner; + u32 partner = 0; u16 weather; struct Pokemon *mon; @@ -4459,7 +4461,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 && !(gBattleMons[BATTLE_OPPOSITE(battler)].status2 & (STATUS2_TRANSFORMED | STATUS2_SUBSTITUTE)) && !(gBattleMons[battler].status2 & STATUS2_TRANSFORMED) && !(gBattleStruct->illusion[BATTLE_OPPOSITE(battler)].on) - && !(gStatuses3[BATTLE_OPPOSITE(battler)] & STATUS3_SEMI_INVULNERABLE)) + && !(gStatuses3[BATTLE_OPPOSITE(battler)] & STATUS3_SEMI_INVULNERABLE_NO_COMMANDER)) { gBattlerAttacker = battler; gBattlerTarget = BATTLE_OPPOSITE(battler); @@ -5035,6 +5037,28 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 effect++; } break; + case ABILITY_COMMANDER: + partner = BATTLE_PARTNER(battler); + if (!gSpecialStatuses[battler].switchInAbilityDone + && gBattleStruct->commanderActive[partner] == SPECIES_NONE + && gBattleMons[partner].species == SPECIES_DONDOZO + && GetFormSpeciesId(GetMonData(GetPartyBattlerData(battler), MON_DATA_SPECIES), 0) == SPECIES_TATSUGIRI) + { + SaveBattlerAttacker(gBattlerAttacker); + gSpecialStatuses[battler].switchInAbilityDone = TRUE; + gBattlerAttacker = partner; + gBattleStruct->commandingDondozo |= 1u << battler; + gBattleStruct->commanderActive[partner] = gBattleMons[battler].species; + gStatuses3[battler] |= STATUS3_COMMANDER; + if (gBattleMons[battler].status2 & STATUS2_CONFUSION + && !(gStatuses4[battler] & STATUS4_INFINITE_CONFUSION)) + gBattleMons[battler].status2 -= STATUS2_CONFUSION_TURN(1); + BtlController_EmitSpriteInvisibility(battler, BUFFER_A, TRUE); + MarkBattlerForControllerExec(battler); + BattleScriptPushCursorAndCallback(BattleScript_CommanderActivates); + effect++; + } + break; } break; case ABILITYEFFECT_ENDTURN: @@ -6593,7 +6617,9 @@ u32 IsAbilityPreventingEscape(u32 battler) bool32 CanBattlerEscape(u32 battler) // no ability check { - if (GetBattlerHoldEffect(battler, TRUE) == HOLD_EFFECT_SHED_SHELL) + if (gBattleStruct->commanderActive[battler] != SPECIES_NONE) + return FALSE; + else if (GetBattlerHoldEffect(battler, TRUE) == HOLD_EFFECT_SHED_SHELL) return TRUE; else if (B_GHOSTS_ESCAPE >= GEN_6 && IS_BATTLER_OF_TYPE(battler, TYPE_GHOST)) return TRUE; @@ -12105,3 +12131,12 @@ bool32 TargetFullyImmuneToCurrMove(u32 battlerAtk, u32 battlerDef) || IsSemiInvulnerable(battlerDef, gCurrentMove) || DoesBattlerHaveAbilityImmunity(battlerDef)); } + +bool32 DoesDestinyBondFail(u32 battler) +{ + if (B_DESTINY_BOND_FAIL >= GEN_7 + && gMovesInfo[gLastResultingMoves[battler]].effect == EFFECT_DESTINY_BOND + && !(gBattleStruct->lastMoveFailed & (1u << battler))) + return TRUE; + return FALSE; +} diff --git a/src/data/battle_move_effects.h b/src/data/battle_move_effects.h index ead7cee6f1ef..776563bbec47 100644 --- a/src/data/battle_move_effects.h +++ b/src/data/battle_move_effects.h @@ -2255,4 +2255,10 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] = .battleScript = BattleScript_EffectHit, .battleTvScore = 0, // TODO: Assign points }, + + [EFFECT_ORDER_UP] = + { + .battleScript = BattleScript_EffectHit, + .battleTvScore = 0, // TODO: Assign points + }, }; diff --git a/src/data/moves_info.h b/src/data/moves_info.h index df12555c5bdd..967460a3026a 100644 --- a/src/data/moves_info.h +++ b/src/data/moves_info.h @@ -19331,7 +19331,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .description = COMPOUND_STRING( "Boosts a user's stats\n" "depending on Tatsugiri."), - .effect = EFFECT_PLACEHOLDER, // EFFECT_ORDER_UP + .effect = EFFECT_ORDER_UP, .power = 80, .type = TYPE_DRAGON, .accuracy = 100, @@ -19341,6 +19341,11 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .category = DAMAGE_CATEGORY_PHYSICAL, .mirrorMoveBanned = TRUE, .metronomeBanned = TRUE, + .additionalEffects = ADDITIONAL_EFFECTS({ + .moveEffect = MOVE_EFFECT_ORDER_UP, + .self = TRUE, + .chance = 100, + }), .battleAnimScript = Move_ORDER_UP, }, diff --git a/src/new_game.c b/src/new_game.c index 779b3543b580..18592570a8be 100644 --- a/src/new_game.c +++ b/src/new_game.c @@ -133,6 +133,7 @@ void SetDefaultOptions(void) gSaveBlock2Ptr->modeLegendaries = ON; gSaveBlock2Ptr->modeMegas = OFF; gSaveBlock2Ptr->modeChoiceEvoStage = EVOSTAGE_ALL; + gSaveBlock2Ptr->modeMonoType = TYPE_NONE; gSaveBlock2Ptr->modeChoiceItemReward = ITEM_DROPS_3; //randomizer settings @@ -250,6 +251,7 @@ void NewGameInitData(void) InitLotadSizeRecord(); gPlayerPartyCount = 0; ZeroPlayerPartyMons(); + ResetMonoTypeArray(); // Poke Storage Stuff if (GetNationalPokedexCount(FLAG_GET_CAUGHT) < 1) diff --git a/src/pit_arena.c b/src/pit_arena.c index 9fe09031bb2c..d070df994934 100644 --- a/src/pit_arena.c +++ b/src/pit_arena.c @@ -1939,9 +1939,9 @@ void SetRandomMonEncounter(void) { reroll = TRUE; } - //no floor skipping before boss floors + //floor skipping only if 3 floors before pit stops else if (sRandomEncounterArray[index].species == SPECIES_ABRA - && (VarGet(VAR_PIT_FLOOR) % 25) > 21) + && (VarGet(VAR_PIT_FLOOR) % 5) != 3) { //if Abra is the last remaining encounter we would be stuck otherwise if (RemainingEncounters() != 1) diff --git a/src/pit_randomizer.c b/src/pit_randomizer.c index d9d7e61ada4f..99ce97f885cd 100644 --- a/src/pit_randomizer.c +++ b/src/pit_randomizer.c @@ -1394,6 +1394,8 @@ u16 GetSpeciesRandomSeeded(u16 species) return GetTrainerSpeciesFromRandomArray(RandomSeededModulo2(species, GetMaxTrainerNumberOfSpecies(TRUE)), TRUE); } +EWRAM_DATA u16 gMonoTypeArray[NUM_SPECIES] = {0}; + u16 GetSpeciesRandomNotSeeded(u16 monType) { switch(monType) @@ -1401,7 +1403,33 @@ u16 GetSpeciesRandomNotSeeded(u16 monType) case TRAINER_MONS: return GetTrainerSpeciesFromRandomArray(RandomModulo(0, GetMaxTrainerNumberOfSpecies(FALSE)), FALSE); case PLAYER_MONS: - return GetPlayerSpeciesFromRandomArray(RandomModulo(0, GetMaxPlayerNumberOfSpecies(FALSE)), FALSE); + if (gSaveBlock2Ptr->modeMonoType != TYPE_NONE) + { + //create dynamic array + u32 maxSpecies = GetMaxPlayerNumberOfSpecies(FALSE); + u32 maxMonoTypeSpecies = GetMonoTypeNumberOfSpecies(); + int element = 0; + + if (gMonoTypeArray[0] == 0) // array is empty + { + for (int i = 0; i < maxSpecies; i++) + { + // if (gSpeciesInfo[GetPlayerSpeciesFromRandomArray(i, FALSE)].types[0] == gSaveBlock2Ptr->modeMonoType + // || gSpeciesInfo[GetPlayerSpeciesFromRandomArray(i, FALSE)].types[1] == gSaveBlock2Ptr->modeMonoType) + if (GetTypeBySpecies(GetPlayerSpeciesFromRandomArray(i, FALSE), 1) == gSaveBlock2Ptr->modeMonoType + || GetTypeBySpecies(GetPlayerSpeciesFromRandomArray(i, FALSE), 2) == gSaveBlock2Ptr->modeMonoType) + { + gMonoTypeArray[element] = GetPlayerSpeciesFromRandomArray(i, FALSE); + //DebugPrintf("Write array %S", gSpeciesInfo[gMonoTypeArray[element]].speciesName); + element++; + } + } + } + + return gMonoTypeArray[RandomModulo(0, maxMonoTypeSpecies)]; + } + else + return GetPlayerSpeciesFromRandomArray(RandomModulo(0, GetMaxPlayerNumberOfSpecies(FALSE)), FALSE); case ALL_MONS: return GetTrainerSpeciesFromRandomArray(RandomModulo(0, GetMaxTrainerNumberOfSpecies(TRUE)), TRUE); } @@ -1410,6 +1438,14 @@ u16 GetSpeciesRandomNotSeeded(u16 monType) return GetTrainerSpeciesFromRandomArray(RandomModulo(0, GetMaxTrainerNumberOfSpecies(FALSE)), FALSE); } +void ResetMonoTypeArray(void) +{ + for(int i = 0; i < NUM_SPECIES; i++) + { + gMonoTypeArray[i] = 0; + } +} + u16 GetRandomSpeciesFlattenedCurve(u16 monType) { u16 randomSpecies = 0; @@ -1423,7 +1459,7 @@ u16 GetRandomSpeciesFlattenedCurve(u16 monType) notChosen = FALSE; breakOut++; - if(breakOut > 700) + if(breakOut > 700) { // Looping too much is intentionally used as the new Clear method because the arrays are broken apart, looping through this function is very fast, // it will maybe slow down a trainer generation by 0.2 seconds every now and then, but thats not a big deal imo, @@ -1431,8 +1467,15 @@ u16 GetRandomSpeciesFlattenedCurve(u16 monType) ClearGeneratedMons(); breakOut = 0; } + if (monType == PLAYER_MONS && gSaveBlock2Ptr->modeMonoType != TYPE_NONE && breakOut > 50) + { + ClearGeneratedMons(); + breakOut = 0; + randomSpecies = gMonoTypeArray[RandomModulo(0, GetMonoTypeNumberOfSpecies())]; //default for overflow cases + } } + //DebugPrintf("final species = %S", gSpeciesInfo[randomSpecies].speciesName); gSaveBlock3Ptr->monRolledCounts[randomSpecies] += 1; return randomSpecies; } @@ -1462,11 +1505,11 @@ void GenerateRandomSpeciesRewards(u16 *sRolledSpeciesPtr) { counter = 0; counter2 = 0; - species = GetRandomSpeciesFlattenedCurve(PLAYER_MONS); do { rerollMon = FALSE; + species = GetRandomSpeciesFlattenedCurve(PLAYER_MONS); //legendary check if (gSaveBlock2Ptr->modeLegendaries == OPTIONS_OFF || (sRolledLegendAlready && (Random() % 10))) //reroll in case any legendaries, mythics or ultra beasts are determined @@ -1524,22 +1567,25 @@ void GenerateRandomSpeciesRewards(u16 *sRolledSpeciesPtr) break; } - for (i=0; i < 9; i++) //check for duplicates within the case + if (gSaveBlock2Ptr->modeMonoType == TYPE_NONE) // don't do duplicates handling in case of mono type runs { - if (species == sRolledSpeciesPtr[i] && i != index) + for (i=0; i < 9; i++) //check for duplicates within the case { - rerollMon = TRUE; + if (species == sRolledSpeciesPtr[i] && i != index) + { + rerollMon = TRUE; + } } - } - //check for duplicates against the player's party - partyCount = CalculatePlayerPartyCount(); - if (partyCount > 2 && rerollMon == FALSE) //only the case after obtaining the third mon - { - for (i = 0; i < partyCount; i++) + //check for duplicates against the player's party + partyCount = CalculatePlayerPartyCount(); + if (partyCount > 2 && rerollMon == FALSE) //only the case after obtaining the third mon { - if (species == GetMonData(&gPlayerParty[i], MON_DATA_SPECIES)) - rerollMon = TRUE; + for (i = 0; i < partyCount; i++) + { + if (species == GetMonData(&gPlayerParty[i], MON_DATA_SPECIES)) + rerollMon = TRUE; + } } } @@ -1712,7 +1758,9 @@ static const u16 sRandomBerryValidItems[] = ITEM_MICLE_BERRY, ITEM_CUSTAP_BERRY, ITEM_JABOCA_BERRY, - ITEM_ROWAP_BERRY, + ITEM_ROWAP_BERRY, +#endif +#ifdef PIT_GEN_9_MODE ITEM_ROSELI_BERRY, ITEM_KEE_BERRY, ITEM_MARANGA_BERRY, diff --git a/src/pit_species_lists.c b/src/pit_species_lists.c index a66b2d0330a9..92b6e0c00b55 100644 --- a/src/pit_species_lists.c +++ b/src/pit_species_lists.c @@ -1717,7 +1717,6 @@ static const u16 sRandomDynamicSpecies_26_35[] = SPECIES_LYCANROC_MIDNIGHT, SPECIES_LYCANROC_DUSK, SPECIES_WISHIWASHI_SOLO, - SPECIES_WISHIWASHI_SCHOOL, SPECIES_MAREANIE, SPECIES_TOXAPEX, SPECIES_MUDBRAY, @@ -2727,7 +2726,6 @@ static const u16 sRandomDynamicSpecies_36_50[] = SPECIES_LYCANROC_MIDNIGHT, SPECIES_LYCANROC_DUSK, SPECIES_WISHIWASHI_SOLO, - SPECIES_WISHIWASHI_SCHOOL, SPECIES_MAREANIE, SPECIES_TOXAPEX, SPECIES_MUDBRAY, @@ -3808,7 +3806,6 @@ static const u16 sRandomDynamicSpecies_51_75[] = SPECIES_LYCANROC_MIDNIGHT, SPECIES_LYCANROC_DUSK, SPECIES_WISHIWASHI_SOLO, - SPECIES_WISHIWASHI_SCHOOL, SPECIES_MAREANIE, SPECIES_TOXAPEX, SPECIES_MUDBRAY, @@ -4978,7 +4975,6 @@ static const u16 sRandomDynamicSpecies_76_100[] = SPECIES_LYCANROC_MIDNIGHT, SPECIES_LYCANROC_DUSK, SPECIES_WISHIWASHI_SOLO, - SPECIES_WISHIWASHI_SCHOOL, SPECIES_MAREANIE, SPECIES_TOXAPEX, SPECIES_MUDBRAY, @@ -5326,9 +5322,9 @@ u32 GetMaxPlayerNumberOfSpecies(bool8 forceAllSpecies) else { // The Player Only Gets 4 Mon Options So They're Weighted Better Than Opponents Slightly. Can Update if you Want. if (floor <= 25) - return RANDOM_DYNAMIC_SPECIES_COUNT_16_25; + return RANDOM_DYNAMIC_SPECIES_COUNT_76_100; //old: RANDOM_DYNAMIC_SPECIES_COUNT_16_25 if (floor <= 50) - return RANDOM_DYNAMIC_SPECIES_COUNT_51_75; + return RANDOM_DYNAMIC_SPECIES_COUNT_76_100; //old: RANDOM_DYNAMIC_SPECIES_COUNT_51_75 return RANDOM_DYNAMIC_SPECIES_COUNT_76_100; } } @@ -5342,9 +5338,46 @@ u32 GetPlayerSpeciesFromRandomArray(u16 index, bool8 forceAllSpecies) else { // The Player Only Gets 4 Mon Options So They're Weighted Better Than Opponents Slightly. Can Update if you Want. if (floor <= 25) - return sRandomDynamicSpecies_16_25[index]; + return sRandomDynamicSpecies_76_100[index]; //old: sRandomDynamicSpecies_16_25 if (floor <= 50) - return sRandomDynamicSpecies_51_75[index]; + return sRandomDynamicSpecies_76_100[index]; //old: sRandomDynamicSpecies_51_75 return sRandomDynamicSpecies_76_100[index]; } } + +u32 GetMonoTypeNumberOfSpecies(void) +{ + u8 floor = VarGet(VAR_PIT_FLOOR); + u16 arraySize = 0; + int i; + u16 counter = 0; + + if (gSaveBlock2Ptr->modeMonoType != TYPE_NONE) + { + //calc base array size + if (gSaveBlock2Ptr->modeChoiceEvoStage == EVOSTAGE_FULL) + arraySize = RANDOM_DYNAMIC_SPECIES_COUNT_76_100; + else + { + if (floor <= 25) + arraySize = RANDOM_DYNAMIC_SPECIES_COUNT_76_100; //old: RANDOM_DYNAMIC_SPECIES_COUNT_16_25 + else if (floor <= 50) + arraySize = RANDOM_DYNAMIC_SPECIES_COUNT_76_100; //old: RANDOM_DYNAMIC_SPECIES_COUNT_51_75 + else //everything above 75 + arraySize = RANDOM_DYNAMIC_SPECIES_COUNT_76_100; + } + + //calc size of dynamic array for chosen mono type + for (i = 0; i < arraySize; i++) + { + // if (gSpeciesInfo[GetPlayerSpeciesFromRandomArray(i, FALSE)].types[0] == gSaveBlock2Ptr->modeMonoType + // || gSpeciesInfo[GetPlayerSpeciesFromRandomArray(i, FALSE)].types[1] == gSaveBlock2Ptr->modeMonoType) + // counter++; + if (GetTypeBySpecies(GetPlayerSpeciesFromRandomArray(i, FALSE), 1) == gSaveBlock2Ptr->modeMonoType + || GetTypeBySpecies(GetPlayerSpeciesFromRandomArray(i, FALSE), 2) == gSaveBlock2Ptr->modeMonoType) + counter++; + } + } + + return counter; +} diff --git a/src/scrcmd.c b/src/scrcmd.c index a0f516e194f5..4032b4d28e1e 100644 --- a/src/scrcmd.c +++ b/src/scrcmd.c @@ -830,14 +830,14 @@ bool8 ScrCmd_warpteleport(struct ScriptContext *ctx) //only show move tutor on 10er levels FlagClear(FLAG_HIDE_MOVE_TUTOR); - if (VarGet(VAR_PIT_FLOOR) % 10 != 0) // Hide if on a multiple of 10 - FlagSet(FLAG_HIDE_MOVE_TUTOR); + // if (VarGet(VAR_PIT_FLOOR) % 10 != 0) // Hide if on a multiple of 10 + // FlagSet(FLAG_HIDE_MOVE_TUTOR); - if (VarGet(VAR_PIT_FLOOR) % 25 == 0) // Show Tutor if on 25 - FlagClear(FLAG_HIDE_MOVE_TUTOR); + // if (VarGet(VAR_PIT_FLOOR) % 25 == 0) // Show Tutor if on 25 + // FlagClear(FLAG_HIDE_MOVE_TUTOR); - if (gSaveBlock2Ptr->modeXP == 2) // If No Exp Mode, Always Spawn Tutor - FlagClear(FLAG_HIDE_MOVE_TUTOR); + // if (gSaveBlock2Ptr->modeXP == 2) // If No Exp Mode, Always Spawn Tutor + // FlagClear(FLAG_HIDE_MOVE_TUTOR); } else if (!(VarGet(VAR_PIT_FLOOR) % BOSS_FLOOR_RATE)) { diff --git a/src/strings.c b/src/strings.c index fbe24804517b..d6d2090a51ec 100644 --- a/src/strings.c +++ b/src/strings.c @@ -992,8 +992,8 @@ const u8 gText_MovePokemon[] = _("MOVE POKéMON"); const u8 gText_MoveItems[] = _("MOVE ITEMS"); const u8 gText_SeeYa[] = _("SEE YA!"); const u8 gText_WithdrawMonDescription[] = _("Take a single Pokémon with you.\nLevels and EVs will be reduced."); -const u8 gText_DepositMonDescription[] = _("Save your favorite Winning Pokémon \nin your Boxes."); -const u8 gText_MoveMonDescription[] = _("Organize your winning Pokémon \nin your Boxes."); +const u8 gText_DepositMonDescription[] = _("Save your winning team in your box\nafter completing a run in The Pit."); +const u8 gText_MoveMonDescription[] = _("Organize your winning Pokémon\nin your Boxes."); const u8 gText_MoveItemsDescription[] = _("Move items held by any POKéMON\nin a BOX or your party."); const u8 gText_SeeYaDescription[] = _("Close the PC."); const u8 gText_JustOnePkmn[] = _("There are no POKéMON with you."); diff --git a/src/ui_main_menu.c b/src/ui_main_menu.c index 14c67265d253..1ed25d15dbe6 100644 --- a/src/ui_main_menu.c +++ b/src/ui_main_menu.c @@ -736,6 +736,7 @@ static void LoadDefaultSettings(void) gSaveBlock2Ptr->modeCashRewards = CASH_1X; gSaveBlock2Ptr->modeHealFloors10 = HEAL_FLOORS_5; gSaveBlock2Ptr->modeChoiceEvoStage = EVOSTAGE_ALL; + gSaveBlock2Ptr->modeMonoType = TYPE_NONE; gSaveBlock2Ptr->modeChoiceItemReward = ITEM_DROPS_3; gSaveBlock2Ptr->modeBossHeal = OPTIONS_ON; //randomizer settings diff --git a/src/ui_mode_menu.c b/src/ui_mode_menu.c index dd744fb3bcb3..07c601c729d1 100644 --- a/src/ui_mode_menu.c +++ b/src/ui_mode_menu.c @@ -80,6 +80,8 @@ enum MenuItems_Difficulty { MENUITEM_DIFF_XPMODE, MENUITEM_DIFF_TRAINER_EVS, + MENUITEM_DIFF_EVOSTAGE, + MENUITEM_DIFF_MONOTYPE, MENUITEM_DIFF_DOUBLE_CASH, MENUITEM_DIFF_STAT_CHANGER, MENUITEM_DIFF_HEALFLOORS, @@ -87,7 +89,6 @@ enum MenuItems_Difficulty #ifdef PIT_GEN_9_MODE MENUITEM_DIFF_MEGAS, #endif - MENUITEM_DIFF_EVOSTAGE, MENUITEM_DIFF_BOSS_HEAL, MENUITEM_DIFF_ITEM_DROPS, MENUITEM_DIFF_CANCEL, @@ -274,7 +275,7 @@ static void DrawLeftSideOptionText(int selection, int y); static void DrawRightSideChoiceText(const u8 *str, int x, int y, bool8 chosen, bool8 active); static void DrawDescriptionText(void); static void DrawModeMenuTexts(void); //left side text; -static void DrawChoices(u32 id, int y); //right side draw function +static void DrawChoices(u8 id, int y); //right side draw function static void HighlightModeMenuItem(void); static bool8 ModeMenu_LoadGraphics(void); static void ModeMenu_FreeResources(void); @@ -284,6 +285,8 @@ static int GetMiddleX(const u8 *txt1, const u8 *txt2, const u8 *txt3); static int XOptions_ProcessInput(int x, int selection); static int ProcessInput_Options_Two(int selection); static int ProcessInput_Options_Three(int selection); +static int ProcessInput_Options_Eighteen(int selection); +static int ProcessInput_Options_Nineteen(int selection); static void ReDrawAll(void); //static void DrawChoices_Autosave(int selection, int y); static void DrawChoices_SpeciesArray(int selection, int y); @@ -296,6 +299,7 @@ static void DrawChoices_BossHeal(int selection, int y); static void DrawChoices_ItemDrops(int selection, int y); static void DrawChoices_DoubleCash(int selection, int y); static void DrawChoices_EvoStage(int selection, int y); +static void DrawChoices_MonoType(int selection, int y); static void DrawChoices_RandBattleWeather(int selection, int y); static void DrawChoices_RandMoves(int selection, int y); static void DrawChoices_RandAbilities(int selection, int y); @@ -336,15 +340,20 @@ struct Menu_Diff //MENU_DIFF } static const sItemFunctionsDiff[MENUITEM_DIFF_COUNT] = { [MENUITEM_DIFF_XPMODE] = {DrawChoices_XPMode, ProcessInput_Options_Three}, - [MENUITEM_DIFF_STAT_CHANGER] = {DrawChoices_StatChanger, ProcessInput_Options_Two}, [MENUITEM_DIFF_TRAINER_EVS] = {DrawChoices_TrainerEVs, ProcessInput_Options_Two}, + [MENUITEM_DIFF_EVOSTAGE] = {DrawChoices_EvoStage, ProcessInput_Options_Three}, +#ifdef PIT_GEN_9_MODE + [MENUITEM_DIFF_MONOTYPE] = {DrawChoices_MonoType, ProcessInput_Options_Nineteen}, +#else + [MENUITEM_DIFF_MONOTYPE] = {DrawChoices_MonoType, ProcessInput_Options_Eighteen}, +#endif + [MENUITEM_DIFF_STAT_CHANGER] = {DrawChoices_StatChanger, ProcessInput_Options_Two}, [MENUITEM_DIFF_DOUBLE_CASH] = {DrawChoices_DoubleCash, ProcessInput_Options_Three}, [MENUITEM_DIFF_HEALFLOORS] = {DrawChoices_HealFloors, ProcessInput_Options_Two}, [MENUITEM_DIFF_LEGENDARIES] = {DrawChoices_Legendaries, ProcessInput_Options_Two}, #ifdef PIT_GEN_9_MODE [MENUITEM_DIFF_MEGAS] = {DrawChoices_Megas, ProcessInput_Options_Two}, #endif - [MENUITEM_DIFF_EVOSTAGE] = {DrawChoices_EvoStage, ProcessInput_Options_Three}, [MENUITEM_DIFF_BOSS_HEAL] = {DrawChoices_BossHeal, ProcessInput_Options_Two}, [MENUITEM_DIFF_ITEM_DROPS] = {DrawChoices_ItemDrops, ProcessInput_Options_Three}, [MENUITEM_DIFF_CANCEL] = {NULL, NULL}, @@ -396,6 +405,7 @@ static const u8 sText_NoCaseChoice[] = _("NO BIRCH CASE"); static const u8 sText_BossHeal[] = _("BOSS HEALS"); static const u8 sText_DoubleCash[] = _("CASH RATE"); static const u8 sText_EvoStage[] = _("EVO STAGES"); +static const u8 sText_MonoType[] = _("MONO TYPE"); static const u8 sText_50Floors[] = _("50 FLOORS"); static const u8 sText_B_Weather[] = _("BATTLE WEATHER"); @@ -424,15 +434,16 @@ static const u8 *const sModeMenuItemsNamesRun[MENUITEM_RUN_COUNT] = static const u8 *const sModeMenuItemsNamesDiff[MENUITEM_DIFF_COUNT] = { [MENUITEM_DIFF_XPMODE] = sText_XPMode, - [MENUITEM_DIFF_STAT_CHANGER] = sText_StatChanger, [MENUITEM_DIFF_TRAINER_EVS] = sText_TrainerEVs, + [MENUITEM_DIFF_EVOSTAGE] = sText_EvoStage, + [MENUITEM_DIFF_MONOTYPE] = sText_MonoType, + [MENUITEM_DIFF_STAT_CHANGER] = sText_StatChanger, [MENUITEM_DIFF_DOUBLE_CASH] = sText_DoubleCash, [MENUITEM_DIFF_HEALFLOORS] = sText_HealFloors, [MENUITEM_DIFF_LEGENDARIES] = sText_Legendaries, #ifdef PIT_GEN_9_MODE [MENUITEM_DIFF_MEGAS] = sText_Megas, #endif - [MENUITEM_DIFF_EVOSTAGE] = sText_EvoStage, [MENUITEM_DIFF_BOSS_HEAL] = sText_BossHeal, [MENUITEM_DIFF_ITEM_DROPS] = sText_ItemDrops, [MENUITEM_DIFF_CANCEL] = sText_Cancel, @@ -504,6 +515,7 @@ static bool8 CheckConditions(int selection) case MENUITEM_DIFF_MEGAS: return TRUE; #endif case MENUITEM_DIFF_EVOSTAGE: return TRUE; + case MENUITEM_DIFF_MONOTYPE: return TRUE; case MENUITEM_DIFF_BOSS_HEAL: return TRUE; case MENUITEM_DIFF_ITEM_DROPS: return TRUE; case MENUITEM_DIFF_CANCEL: return TRUE; @@ -588,6 +600,7 @@ static const u8 sText_Desc_EvoStage_Basic[] = _("Pokémon to choose from wil static const u8 sText_Desc_EvoStage_Full[] = _("Pokémon to choose from will always\nbe fully evolved Pokémon."); static const u8 sText_Desc_50Floors_On[] = _("A shorter Pit experience that\nonly goes 50 floors deep."); static const u8 sText_Desc_50Floors_Off[] = _("The regular Pit experience that\ngoes 100 floors deep and beyond."); +static const u8 sText_Desc_MonoType[] = _("Choose a type to play a\nmono type run with."); static const u8 sText_Desc_RandBWeather_On[] = _("Weather during battles is randomized."); static const u8 sText_Desc_RandBWeather_OW[] = _("Weather during battles is based on\nthe current floor's weather."); static const u8 sText_Desc_RandBWeather_Off[] = _("Weather during battles is turned off."); @@ -625,6 +638,7 @@ static const u8 *const sModeMenuItemDescriptionsDiff[MENUITEM_DIFF_COUNT][3] = [MENUITEM_DIFF_MEGAS] = {sText_Desc_Megas_On, sText_Desc_Megas_Off, sText_Empty}, #endif [MENUITEM_DIFF_EVOSTAGE] = {sText_Desc_EvoStage_All, sText_Desc_EvoStage_Basic, sText_Desc_EvoStage_Full}, + [MENUITEM_DIFF_MONOTYPE] = {sText_Desc_MonoType, sText_Desc_MonoType, sText_Desc_MonoType}, [MENUITEM_DIFF_BOSS_HEAL] = {sText_Desc_BossHeal_On, sText_Desc_BossHeal_Off, sText_Empty}, [MENUITEM_DIFF_ITEM_DROPS] = {sText_Desc_ItemDrops_Rand, sText_Desc_ItemDrops_1, sText_Desc_ItemDrops_3}, [MENUITEM_DIFF_CANCEL] = {sText_Desc_Save, sText_Empty, sText_Empty}, @@ -660,7 +674,10 @@ static const u8 *const OptionTextDescription(void) return sModeMenuItemDescriptionsRun[menuItem][selection]; case MENU_DIFF: selection = sOptions->sel_diff[menuItem]; - return sModeMenuItemDescriptionsDiff[menuItem][selection]; + if (menuItem == MENUITEM_DIFF_MONOTYPE) + return sModeMenuItemDescriptionsDiff[menuItem][0]; + else + return sModeMenuItemDescriptionsDiff[menuItem][selection]; case MENU_RAND: selection = sOptions->sel_rand[menuItem]; return sModeMenuItemDescriptionsRand[menuItem][selection]; @@ -844,6 +861,7 @@ static void ModeMenu_SetupCB(void) sOptions->sel_diff[MENUITEM_DIFF_MEGAS] = gSaveBlock2Ptr->modeMegas; #endif sOptions->sel_diff[MENUITEM_DIFF_EVOSTAGE] = gSaveBlock2Ptr->modeChoiceEvoStage; + sOptions->sel_diff[MENUITEM_DIFF_MONOTYPE] = gSaveBlock2Ptr->modeMonoType; sOptions->sel_diff[MENUITEM_DIFF_BOSS_HEAL] = gSaveBlock2Ptr->modeBossHeal; sOptions->sel_diff[MENUITEM_DIFF_ITEM_DROPS] = gSaveBlock2Ptr->modeChoiceItemReward; //randomizer settings @@ -1053,7 +1071,7 @@ static void DrawRightSideChoiceText(const u8 *text, int x, int y, bool8 chosen, AddTextPrinterParameterized4(WIN_OPTIONS, FONT_NORMAL, x, y, 0, 0, color_gray, TEXT_SKIP_DRAW, text); } -static void DrawChoices(u32 id, int y) //right side draw function +static void DrawChoices(u8 id, int y) //right side draw function { switch (sOptions->submenu) { @@ -1385,6 +1403,11 @@ static void Task_ModeMenuSave(u8 taskId) gSaveBlock2Ptr->modeChoiceItemReward = sOptions->sel_diff[MENUITEM_DIFF_ITEM_DROPS]; gSaveBlock2Ptr->modeChoiceEvoStage = sOptions->sel_diff[MENUITEM_DIFF_EVOSTAGE]; + if (sOptions->sel_diff[MENUITEM_DIFF_MONOTYPE] >= TYPE_MYSTERY) + gSaveBlock2Ptr->modeMonoType = sOptions->sel_diff[MENUITEM_DIFF_MONOTYPE] + 1; + else + gSaveBlock2Ptr->modeMonoType = sOptions->sel_diff[MENUITEM_DIFF_MONOTYPE]; + //randomizer settings gSaveBlock2Ptr->randomBattleWeather = sOptions->sel_rand[MENUITEM_RAND_B_WEATHER]; gSaveBlock2Ptr->randomMoves = sOptions->sel_rand[MENUITEM_RAND_MOVES]; @@ -1538,6 +1561,16 @@ static int ProcessInput_Options_Three(int selection) return XOptions_ProcessInput(3, selection); } +static int ProcessInput_Options_Eighteen(int selection) +{ + return XOptions_ProcessInput(18, selection); +} + +static int ProcessInput_Options_Nineteen(int selection) +{ + return XOptions_ProcessInput(19, selection); +} + // Draw Choices functions ****GENERIC**** static void DrawModeMenuChoice(const u8 *text, u8 x, u8 y, u8 style, bool8 active) { @@ -1572,8 +1605,8 @@ static void ReDrawAll(void) FillWindowPixelBuffer(WIN_OPTIONS, PIXEL_FILL(0)); for (i = 0; i < optionsToDraw; i++) { - DrawChoices(menuItem+i, i * Y_DIFF); - DrawLeftSideOptionText(menuItem+i, (i * Y_DIFF) + 1); + DrawChoices(menuItem + i, i * Y_DIFF); + DrawLeftSideOptionText(menuItem + i, (i * Y_DIFF) + 1); } CopyWindowToVram(WIN_OPTIONS, COPYWIN_GFX); } @@ -1615,6 +1648,27 @@ static const u8 sText_EvoStage_Full[] = _("FULL"); static const u8 sText_ItemDrops_Rand[] = _("RAND"); static const u8 sText_ItemDrops_1[] = _("1"); static const u8 sText_ItemDrops_3[] = _("3"); +static const u8 sText_Type_Normal[] = _("NORMAL"); +static const u8 sText_Type_Fighting[] = _("FIGHT"); +static const u8 sText_Type_Flying[] = _("FLYING"); +static const u8 sText_Type_Poison[] = _("POISON"); +static const u8 sText_Type_Ground[] = _("GROUND"); +static const u8 sText_Type_Rock[] = _("ROCK"); +static const u8 sText_Type_Bug[] = _("BUG"); +static const u8 sText_Type_Ghost[] = _("GHOST"); +static const u8 sText_Type_Steel[] = _("STEEL"); //TYPE_MYSTERY +static const u8 sText_Type_Fire[] = _("FIRE"); +static const u8 sText_Type_Water[] = _("WATER"); +static const u8 sText_Type_Grass[] = _("GRASS"); +static const u8 sText_Type_Electric[] = _("ELECTRIC"); +static const u8 sText_Type_Psychic[] = _("PSYCHIC"); +static const u8 sText_Type_Ice[] = _("ICE"); +static const u8 sText_Type_Dragon[] = _("DRAGON"); +static const u8 sText_Type_Dark[] = _("DARK"); +static const u8 sText_Type_Fairy[] = _("FAIRY"); +static const u8 sText_Arrows_Left[] = _("<<"); +static const u8 sText_Arrows_Right[] = _(">>"); + /*static void DrawChoices_Autosave(int selection, int y) { @@ -1807,6 +1861,100 @@ static void DrawChoices_EvoStage(int selection, int y) DrawModeMenuChoice(sText_EvoStage_Full, GetStringRightAlignXOffset(FONT_NORMAL, sText_EvoStage_Full, 198), y, styles[2], active); } +static void DrawChoices_MonoType(int selection, int y) +{ + // DrawModeMenuChoice(sText_Autosave_Off, 104, y, styles[0], active); + // DrawModeMenuChoice(sText_Type_Normal, GetStringRightAlignXOffset(FONT_NORMAL, sText_Type_Normal, 198 - 35), y, styles[1], active); + // DrawModeMenuChoice(sText_Type_Fighting, GetStringRightAlignXOffset(FONT_NORMAL, sText_Type_Fighting, 198), y, styles[2], active); + + bool8 active = CheckConditions(MENUITEM_DIFF_MONOTYPE); + u16 xMid = 0; + + DrawModeMenuChoice(sText_Arrows_Left, 104, y, 0, active); + + switch (selection) + { + case 1: + xMid = GetMiddleX(sText_Arrows_Left, sText_Type_Normal, sText_Arrows_Left); + DrawModeMenuChoice(sText_Type_Normal, xMid, y, 1, active); + break; + case 2: + xMid = GetMiddleX(sText_Arrows_Left, sText_Type_Fighting, sText_Arrows_Left); + DrawModeMenuChoice(sText_Type_Fighting, xMid, y, 1, active); + break; + case 3: + xMid = GetMiddleX(sText_Arrows_Left, sText_Type_Flying, sText_Arrows_Left); + DrawModeMenuChoice(sText_Type_Flying, xMid, y, 1, active); + break; + case 4: + xMid = GetMiddleX(sText_Arrows_Left, sText_Type_Poison, sText_Arrows_Left); + DrawModeMenuChoice(sText_Type_Poison, xMid, y, 1, active); + break; + case 5: + xMid = GetMiddleX(sText_Arrows_Left, sText_Type_Ground, sText_Arrows_Left); + DrawModeMenuChoice(sText_Type_Ground, xMid, y, 1, active); + break; + case 6: + xMid = GetMiddleX(sText_Arrows_Left, sText_Type_Rock, sText_Arrows_Left); + DrawModeMenuChoice(sText_Type_Rock, xMid, y, 1, active); + break; + case 7: + xMid = GetMiddleX(sText_Arrows_Left, sText_Type_Bug, sText_Arrows_Left); + DrawModeMenuChoice(sText_Type_Bug, xMid, y, 1, active); + break; + case 8: + xMid = GetMiddleX(sText_Arrows_Left, sText_Type_Ghost, sText_Arrows_Left); + DrawModeMenuChoice(sText_Type_Ghost, xMid, y, 1, active); + break; + case 9: + xMid = GetMiddleX(sText_Arrows_Left, sText_Type_Steel, sText_Arrows_Left); + DrawModeMenuChoice(sText_Type_Steel, xMid, y, 1, active); + break; + case 10: + xMid = GetMiddleX(sText_Arrows_Left, sText_Type_Fire, sText_Arrows_Left); + DrawModeMenuChoice(sText_Type_Fire, xMid, y, 1, active); + break; + case 11: + xMid = GetMiddleX(sText_Arrows_Left, sText_Type_Water, sText_Arrows_Left); + DrawModeMenuChoice(sText_Type_Water, xMid, y, 1, active); + break; + case 12: + xMid = GetMiddleX(sText_Arrows_Left, sText_Type_Grass, sText_Arrows_Left); + DrawModeMenuChoice(sText_Type_Grass, xMid, y, 1, active); + break; + case 13: + xMid = GetMiddleX(sText_Arrows_Left, sText_Type_Electric, sText_Arrows_Left); + DrawModeMenuChoice(sText_Type_Electric, xMid, y, 1, active); + break; + case 14: + xMid = GetMiddleX(sText_Arrows_Left, sText_Type_Psychic, sText_Arrows_Left); + DrawModeMenuChoice(sText_Type_Psychic, xMid, y, 1, active); + break; + case 15: + xMid = GetMiddleX(sText_Arrows_Left, sText_Type_Ice, sText_Arrows_Left); + DrawModeMenuChoice(sText_Type_Ice, xMid, y, 1, active); + break; + case 16: + xMid = GetMiddleX(sText_Arrows_Left, sText_Type_Dragon, sText_Arrows_Left); + DrawModeMenuChoice(sText_Type_Dragon, xMid, y, 1, active); + break; + case 17: + xMid = GetMiddleX(sText_Arrows_Left, sText_Type_Dark, sText_Arrows_Left); + DrawModeMenuChoice(sText_Type_Dark, xMid, y, 1, active); + break; + case 18: + xMid = GetMiddleX(sText_Arrows_Left, sText_Type_Fairy, sText_Arrows_Left); + DrawModeMenuChoice(sText_Type_Fairy, xMid, y, 1, active); + break; + default: + xMid = GetMiddleX(sText_Arrows_Left, sText_Autosave_Off, sText_Arrows_Left); + DrawModeMenuChoice(sText_Autosave_Off, xMid, y, 1, active); + break; + } + + DrawModeMenuChoice(sText_Arrows_Right, GetStringRightAlignXOffset(FONT_NORMAL, sText_Arrows_Right, 198), y, 0, active); +} + static void DrawChoices_RandBattleWeather(int selection, int y) { bool8 active = CheckConditions(MENUITEM_RAND_B_WEATHER); @@ -1943,6 +2091,7 @@ static void ApplyPresets(void) sOptions->sel_diff[MENUITEM_DIFF_DOUBLE_CASH] = CASH_1X; sOptions->sel_diff[MENUITEM_DIFF_HEALFLOORS] = HEAL_FLOORS_5; sOptions->sel_diff[MENUITEM_DIFF_EVOSTAGE] = EVOSTAGE_ALL; + sOptions->sel_diff[MENUITEM_DIFF_MONOTYPE] = TYPE_NONE; sOptions->sel_diff[MENUITEM_DIFF_BOSS_HEAL] = OPTIONS_ON; sOptions->sel_diff[MENUITEM_DIFF_ITEM_DROPS] = ITEM_DROPS_3; //randomizer settings