From 545c8cf1df6d9e448974576520c232154d4096e7 Mon Sep 17 00:00:00 2001 From: cawtds Date: Thu, 2 May 2024 11:03:31 +0200 Subject: [PATCH] updated up to Cmd_tryswapitems --- asm/macros/battle_script.inc | 24 +++--- data/battle_scripts_1.s | 2 +- include/battle.h | 13 ---- include/battle_scripts.h | 1 - include/battle_util.h | 1 + include/constants/battle.h | 27 +++++++ src/battle_script_commands.c | 141 ++++++++++++++++++++++++----------- src/battle_util.c | 12 +++ 8 files changed, 151 insertions(+), 70 deletions(-) diff --git a/asm/macros/battle_script.inc b/asm/macros/battle_script.inc index 7bbdc829d..355f3382d 100644 --- a/asm/macros/battle_script.inc +++ b/asm/macros/battle_script.inc @@ -1099,34 +1099,34 @@ .byte 0xcc .endm - .macro cureifburnedparalysedorpoisoned param0:req + .macro cureifburnedparalysedorpoisoned failInstr:req .byte 0xcd - .4byte \param0 + .4byte \failInstr .endm - .macro settorment param0:req + .macro settorment failInstr:req .byte 0xce - .4byte \param0 + .4byte \failInstr .endm - .macro jumpifnodamage param0:req + .macro jumpifnodamage jumpInstr:req .byte 0xcf - .4byte \param0 + .4byte \jumpInstr .endm - .macro settaunt param0:req + .macro settaunt failInstr:req .byte 0xd0 - .4byte \param0 + .4byte \failInstr .endm - .macro trysethelpinghand param0:req + .macro trysethelpinghand failInstr:req .byte 0xd1 - .4byte \param0 + .4byte \failInstr .endm - .macro tryswapitems param0:req + .macro tryswapitems failInstr:req .byte 0xd2 - .4byte \param0 + .4byte \failInstr .endm .macro trycopyability param0:req diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index a9447b09d..a338269f6 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -1998,7 +1998,7 @@ BattleScript_EffectTrick:: attackcanceler attackstring ppreduce - jumpifstatus2 BS_TARGET, STATUS2_SUBSTITUTE, BattleScript_ButItFailed + jumpifsubstituteblocks BattleScript_ButItFailed accuracycheck BattleScript_ButItFailed, ACC_CURR_MOVE tryswapitems BattleScript_ButItFailed attackanimation diff --git a/include/battle.h b/include/battle.h index 268daf10d..53bdd3459 100644 --- a/include/battle.h +++ b/include/battle.h @@ -87,19 +87,6 @@ enum { #define MOVE_TARGET_ALLY (1 << 7) #define MOVE_TARGET_ALL_BATTLERS ((1 << 8) | MOVE_TARGET_USER) -// For the second argument of GetMoveTarget, when no target override is needed -#define NO_TARGET_OVERRIDE 0 - -// Constants for Parental Bond -#define PARENTAL_BOND_1ST_HIT 2 -#define PARENTAL_BOND_2ND_HIT 1 -#define PARENTAL_BOND_OFF 0 - -// Constants for if HandleScriptMegaPrimalBurst should handle Mega Evolution, Primal Reversion, or Ultra Burst. -#define HANDLE_TYPE_MEGA_EVOLUTION 0 -#define HANDLE_TYPE_PRIMAL_REVERSION 1 -#define HANDLE_TYPE_ULTRA_BURST 2 - struct TrainerMonNoItemDefaultMoves { u16 iv; diff --git a/include/battle_scripts.h b/include/battle_scripts.h index 14b4df5d9..1fc4475fc 100644 --- a/include/battle_scripts.h +++ b/include/battle_scripts.h @@ -1199,7 +1199,6 @@ extern const u8 BattleScript_EffectFollowMe[]; extern const u8 BattleScript_EffectNaturePower[]; extern const u8 BattleScript_EffectTaunt[]; extern const u8 BattleScript_EffectHelpingHand[]; -extern const u8 BattleScript_EffectTrick[]; extern const u8 BattleScript_EffectRolePlay[]; extern const u8 BattleScript_EffectWish[]; extern const u8 BattleScript_EffectAssist[]; diff --git a/include/battle_util.h b/include/battle_util.h index 2c3d69b8b..4422cd1bc 100644 --- a/include/battle_util.h +++ b/include/battle_util.h @@ -238,6 +238,7 @@ s32 GetStealthHazardDamage(u8 hazardType, u32 battler); s32 GetStealthHazardDamageByTypesAndHP(u8 hazardType, u8 type1, u8 type2, u32 maxHp); bool32 DoBattlersShareType(u32 battler1, u32 battler2); bool32 MoveHasChargeTurnAdditionalEffect(u32 move); +bool32 IsPartnerMonFromSameTrainer(u32 battler); // battle_ai_util.h bool32 IsHealingMove(u32 move); diff --git a/include/constants/battle.h b/include/constants/battle.h index 987e5d7c7..63e3e1e60 100644 --- a/include/constants/battle.h +++ b/include/constants/battle.h @@ -497,6 +497,33 @@ // Indicator for the party summary bar to display an empty slot. #define HP_EMPTY_SLOT 0xFFFF +#define MOVE_TARGET_SELECTED 0 +#define MOVE_TARGET_DEPENDS (1 << 0) +#define MOVE_TARGET_USER_OR_SELECTED (1 << 1) +#define MOVE_TARGET_RANDOM (1 << 2) +#define MOVE_TARGET_BOTH (1 << 3) +#define MOVE_TARGET_USER (1 << 4) +#define MOVE_TARGET_FOES_AND_ALLY (1 << 5) +#define MOVE_TARGET_OPPONENTS_FIELD (1 << 6) +#define MOVE_TARGET_ALLY (1 << 7) +#define MOVE_TARGET_ALL_BATTLERS ((1 << 8) | MOVE_TARGET_USER) + +// For the second argument of GetMoveTarget, when no target override is needed +#define NO_TARGET_OVERRIDE 0 + +// Constants for Parental Bond +#define PARENTAL_BOND_1ST_HIT 2 +#define PARENTAL_BOND_2ND_HIT 1 +#define PARENTAL_BOND_OFF 0 + +// Constants for if HandleScriptMegaPrimalBurst should handle Mega Evolution, Primal Reversion, or Ultra Burst. +#define HANDLE_TYPE_MEGA_EVOLUTION 0 +#define HANDLE_TYPE_PRIMAL_REVERSION 1 +#define HANDLE_TYPE_ULTRA_BURST 2 + +// Constants for Torment +#define PERMANENT_TORMENT 0xF + // Constants for B_VAR_STARTING_STATUS // Timer value controlled by B_VAR_STARTING_STATUS_TIMER #define STARTING_STATUS_NONE 0 diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 9006f659c..49309c307 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -798,12 +798,12 @@ void (* const gBattleScriptingCommandsTable[])(void) = Cmd_setforcedtarget, //0xCA // done Cmd_setcharge, //0xCB // done Cmd_callterrainattack, //0xCC // done - Cmd_cureifburnedparalysedorpoisoned, //0xCD - Cmd_settorment, //0xCE - Cmd_jumpifnodamage, //0xCF - Cmd_settaunt, //0xD0 - Cmd_trysethelpinghand, //0xD1 - Cmd_tryswapitems, //0xD2 + Cmd_cureifburnedparalysedorpoisoned, //0xCD // done + Cmd_settorment, //0xCE // done + Cmd_jumpifnodamage, //0xCF // done + Cmd_settaunt, //0xD0 // done + Cmd_trysethelpinghand, //0xD1 // done + Cmd_tryswapitems, //0xD2 // done Cmd_trycopyability, //0xD3 Cmd_trywish, //0xD4 Cmd_settoxicspikes, //0xD5 // done @@ -14307,92 +14307,128 @@ u16 GetNaturePowerMove(void) // Refresh static void Cmd_cureifburnedparalysedorpoisoned(void) { - if (gBattleMons[gBattlerAttacker].status1 & (STATUS1_POISON | STATUS1_BURN | STATUS1_PARALYSIS | STATUS1_TOXIC_POISON)) + CMD_ARGS(const u8 *failInstr); + + if (gBattleMons[gBattlerAttacker].status1 & (STATUS1_POISON | STATUS1_BURN | STATUS1_PARALYSIS | STATUS1_TOXIC_POISON | STATUS1_FROSTBITE)) { gBattleMons[gBattlerAttacker].status1 = 0; - gBattlescriptCurrInstr += 5; + gBattlescriptCurrInstr = cmd->nextInstr; gActiveBattler = gBattlerAttacker; - BtlController_EmitSetMonData(BUFFER_A, REQUEST_STATUS_BATTLE, 0, sizeof(gBattleMons[gActiveBattler].status1), &gBattleMons[gActiveBattler].status1); - MarkBattlerForControllerExec(gActiveBattler); + BtlController_EmitSetMonData(BUFFER_A, REQUEST_STATUS_BATTLE, 0, sizeof(gBattleMons[gBattlerAttacker].status1), &gBattleMons[gBattlerAttacker].status1); + MarkBattlerForControllerExec(gBattlerAttacker); } else { - gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = cmd->failInstr; } } static void Cmd_settorment(void) { - if (gBattleMons[gBattlerTarget].status2 & STATUS2_TORMENT) + CMD_ARGS(const u8 *failInstr); + + if (gBattleMons[gBattlerTarget].status2 & STATUS2_TORMENT + /* || IsDynamaxed(gBattlerTarget) */) // TODO: Dynamax { - gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = cmd->failInstr; } else { gBattleMons[gBattlerTarget].status2 |= STATUS2_TORMENT; - gBattlescriptCurrInstr += 5; + gDisableStructs[gBattlerTarget].tormentTimer = PERMANENT_TORMENT; // permanent + gBattlescriptCurrInstr = cmd->nextInstr; } } static void Cmd_jumpifnodamage(void) { + CMD_ARGS(const u8 *jumpInstr); + if (gProtectStructs[gBattlerAttacker].physicalDmg || gProtectStructs[gBattlerAttacker].specialDmg) - gBattlescriptCurrInstr += 5; + gBattlescriptCurrInstr = cmd->nextInstr; else - gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = cmd->jumpInstr; } static void Cmd_settaunt(void) { - if (gDisableStructs[gBattlerTarget].tauntTimer == 0) + CMD_ARGS(const u8 *failInstr); + + if (B_OBLIVIOUS_TAUNT >= GEN_6 && GetBattlerAbility(gBattlerTarget) == ABILITY_OBLIVIOUS) { - gDisableStructs[gBattlerTarget].tauntTimer = 2; - // gDisableStructs[gBattlerTarget].tauntTimer2 = 2; - gBattlescriptCurrInstr += 5; + gBattlescriptCurrInstr = BattleScript_NotAffectedAbilityPopUp; + gLastUsedAbility = ABILITY_OBLIVIOUS; + RecordAbilityBattle(gBattlerTarget, ABILITY_OBLIVIOUS); + } + else if (gDisableStructs[gBattlerTarget].tauntTimer == 0) + { + u8 turns; + if (B_TAUNT_TURNS >= GEN_5) + { + turns = 4; + if (GetBattlerTurnOrderNum(gBattlerTarget) > GetBattlerTurnOrderNum(gBattlerAttacker)) + turns--; // If the target hasn't yet moved this turn, Taunt lasts for only three turns (source: Bulbapedia) + } + else if (B_TAUNT_TURNS >= GEN_4) + { + turns = (Random() & 2) + 3; + } + else + { + turns = 2; + } + + gDisableStructs[gBattlerTarget].tauntTimer = turns; + gBattlescriptCurrInstr = cmd->nextInstr; } else { - gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = cmd->failInstr; } } static void Cmd_trysethelpinghand(void) { - gBattlerTarget = GetBattlerAtPosition(GetBattlerPosition(gBattlerAttacker) ^ BIT_FLANK); + CMD_ARGS(const u8 *failInstr); + + gBattlerTarget = GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(gBattlerAttacker))); if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE && !(gAbsentBattlerFlags & gBitTable[gBattlerTarget]) && !gProtectStructs[gBattlerAttacker].helpingHand && !gProtectStructs[gBattlerTarget].helpingHand) { - gProtectStructs[gBattlerTarget].helpingHand = 1; - gBattlescriptCurrInstr += 5; + gProtectStructs[gBattlerTarget].helpingHand = TRUE; + gBattlescriptCurrInstr = cmd->nextInstr; } else { - gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = cmd->failInstr; } } // Trick static void Cmd_tryswapitems(void) { + CMD_ARGS(const u8 *failInstr); + // opponent can't swap items with player in regular battles if (gBattleTypeFlags & BATTLE_TYPE_TRAINER_TOWER || (GetBattlerSide(gBattlerAttacker) == B_SIDE_OPPONENT && !(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_BATTLE_TOWER - | BATTLE_TYPE_EREADER_TRAINER)) - && gTrainerBattleOpponent_A != TRAINER_SECRET_BASE)) + | BATTLE_TYPE_EREADER_TRAINER + | (B_TRAINERS_KNOCK_OFF_ITEMS == TRUE ? BATTLE_TYPE_TRAINER : 0))) + && gTrainerBattleOpponent_A != TRAINER_SECRET_BASE)) { - gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = cmd->failInstr; } else { u8 sideAttacker = GetBattlerSide(gBattlerAttacker); u8 sideTarget = GetBattlerSide(gBattlerTarget); - // you can't swap items if they were knocked off in regular battles + // You can't swap items if they were knocked off in regular battles if (!(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_BATTLE_TOWER | BATTLE_TYPE_EREADER_TRAINER)) @@ -14400,20 +14436,20 @@ static void Cmd_tryswapitems(void) && (gWishFutureKnock.knockedOffMons[sideAttacker] & gBitTable[gBattlerPartyIndexes[gBattlerAttacker]] || gWishFutureKnock.knockedOffMons[sideTarget] & gBitTable[gBattlerPartyIndexes[gBattlerTarget]])) { - gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = cmd->failInstr; } - // can't swap if two pokemon don't have an item + // can't swap if two Pokémon don't have an item // or if either of them is an enigma berry or a mail else if ((gBattleMons[gBattlerAttacker].item == ITEM_NONE && gBattleMons[gBattlerTarget].item == ITEM_NONE) - || gBattleMons[gBattlerAttacker].item == ITEM_ENIGMA_BERRY - || gBattleMons[gBattlerTarget].item == ITEM_ENIGMA_BERRY - || IS_ITEM_MAIL(gBattleMons[gBattlerAttacker].item) - || IS_ITEM_MAIL(gBattleMons[gBattlerTarget].item)) + || !CanBattlerGetOrLoseItem(gBattlerAttacker, gBattleMons[gBattlerAttacker].item) + || !CanBattlerGetOrLoseItem(gBattlerAttacker, gBattleMons[gBattlerTarget].item) + || !CanBattlerGetOrLoseItem(gBattlerTarget, gBattleMons[gBattlerTarget].item) + || !CanBattlerGetOrLoseItem(gBattlerTarget, gBattleMons[gBattlerAttacker].item)) { - gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = cmd->failInstr; } // check if ability prevents swapping - else if (gBattleMons[gBattlerTarget].ability == ABILITY_STICKY_HOLD) + else if (GetBattlerAbility(gBattlerTarget) == ABILITY_STICKY_HOLD) { gBattlescriptCurrInstr = BattleScript_StickyHoldActivates; gLastUsedAbility = gBattleMons[gBattlerTarget].ability; @@ -14431,6 +14467,9 @@ static void Cmd_tryswapitems(void) gBattleMons[gBattlerAttacker].item = ITEM_NONE; gBattleMons[gBattlerTarget].item = oldItemAtk; + RecordItemEffectBattle(gBattlerAttacker, 0); + RecordItemEffectBattle(gBattlerTarget, ItemId_GetHoldEffect(oldItemAtk)); + gActiveBattler = gBattlerAttacker; BtlController_EmitSetMonData(BUFFER_A, REQUEST_HELDITEM_BATTLE, 0, sizeof(*newItemAtk), newItemAtk); MarkBattlerForControllerExec(gBattlerAttacker); @@ -14439,23 +14478,39 @@ static void Cmd_tryswapitems(void) BtlController_EmitSetMonData(BUFFER_A, REQUEST_HELDITEM_BATTLE, 0, sizeof(gBattleMons[gBattlerTarget].item), &gBattleMons[gBattlerTarget].item); MarkBattlerForControllerExec(gBattlerTarget); - *(u8 *)((u8 *)(&gBattleStruct->choicedMove[gBattlerTarget]) + 0) = 0; - *(u8 *)((u8 *)(&gBattleStruct->choicedMove[gBattlerTarget]) + 1) = 0; + gBattleStruct->choicedMove[gBattlerTarget] = MOVE_NONE; + gBattleStruct->choicedMove[gBattlerAttacker] = MOVE_NONE; - *(u8 *)((u8 *)(&gBattleStruct->choicedMove[gBattlerAttacker]) + 0) = 0; - *(u8 *)((u8 *)(&gBattleStruct->choicedMove[gBattlerAttacker]) + 1) = 0; - - gBattlescriptCurrInstr += 5; + gBattlescriptCurrInstr = cmd->nextInstr; PREPARE_ITEM_BUFFER(gBattleTextBuff1, *newItemAtk) PREPARE_ITEM_BUFFER(gBattleTextBuff2, oldItemAtk) + if (!(sideAttacker == sideTarget && IsPartnerMonFromSameTrainer(gBattlerAttacker))) + { + // if targeting your own side and you aren't in a multi battle, don't save items as stolen + if (GetBattlerSide(gBattlerAttacker) == B_SIDE_PLAYER) + TrySaveExchangedItem(gBattlerAttacker, oldItemAtk); + if (GetBattlerSide(gBattlerTarget) == B_SIDE_PLAYER) + TrySaveExchangedItem(gBattlerTarget, *newItemAtk); + } + if (oldItemAtk != ITEM_NONE && *newItemAtk != ITEM_NONE) + { gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_ITEM_SWAP_BOTH; // attacker's item -> <- target's item + } else if (oldItemAtk == ITEM_NONE && *newItemAtk != ITEM_NONE) + { + if (GetBattlerAbility(gBattlerAttacker) == ABILITY_UNBURDEN && gBattleResources->flags->flags[gBattlerAttacker] & RESOURCE_FLAG_UNBURDEN) + gBattleResources->flags->flags[gBattlerAttacker] &= ~RESOURCE_FLAG_UNBURDEN; + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_ITEM_SWAP_TAKEN; // nothing -> <- target's item + } else + { + CheckSetUnburden(gBattlerAttacker); gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_ITEM_SWAP_GIVEN; // attacker's item -> <- nothing + } } } } diff --git a/src/battle_util.c b/src/battle_util.c index 69d6ee0c9..7126c5085 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -9520,6 +9520,18 @@ bool32 MoveHasChargeTurnAdditionalEffect(u32 move) return FALSE; } +bool32 IsPartnerMonFromSameTrainer(u32 battler) +{ + if (GetBattlerSide(battler) == B_SIDE_OPPONENT && gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS) + return FALSE; + else if (GetBattlerSide(battler) == B_SIDE_PLAYER && gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER) + return FALSE; + else if (gBattleTypeFlags & BATTLE_TYPE_MULTI) + return FALSE; + else + return TRUE; +} + // battle_ai_util.c