updated up to Cmd_tryswapitems

This commit is contained in:
cawtds
2024-05-02 11:03:31 +02:00
parent dd1fba7834
commit 545c8cf1df
8 changed files with 151 additions and 70 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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;

View File

@@ -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[];

View File

@@ -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);

View File

@@ -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

View File

@@ -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
}
}
}
}

View File

@@ -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