This commit is contained in:
DizzyEggg 2019-08-08 13:06:55 +02:00
parent 0dd9a3dd0c
commit c9de753ecc
17 changed files with 279 additions and 111 deletions

View File

@ -1660,6 +1660,19 @@
various \battler, VARIOUS_TRACE_ABILITY
.endm
.macro updatenick battler:req
various \battler, VARIOUS_UPDATE_NICK
.endm
.macro tryillusionoff battler:req
various \battler, VARIOUS_TRY_ILLUSION_OFF
.endm
.macro spriteignore0hp val:req
various BS_ATTACKER, VARIOUS_SET_SPRITEIGNORE0HP
.byte \val
.endm
@ helpful macros
.macro setstatchanger stat:req, stages:req, down:req
setbyte sSTATCHANGER \stat | \stages << 3 | \down << 7

View File

@ -682,6 +682,7 @@ gBattleAnims_General::
.4byte General_TerrainGrassy
.4byte General_TerrainElectric
.4byte General_TerrainPsychic
.4byte General_IllusionOff
.align 2
gBattleAnims_Special::
@ -14756,6 +14757,13 @@ General_WishHeal:
createsprite gSimplePaletteBlendSpriteTemplate, ANIM_ATTACKER, 2, 1, 3, 10, 0, RGB_BLACK
end
General_IllusionOff:
monbg ANIM_TARGET
createvisualtask sub_815B7D0, 2, 0, 1
waitforvisualfinish
clearmonbg ANIM_TARGET
end
General_MegaEvolution:
loadspritegfx ANIM_TAG_MEGA_STONE
loadspritegfx ANIM_TAG_MEGA_PARTICLES

View File

@ -4675,20 +4675,22 @@ BattleScript_EffectCamouflage::
goto BattleScript_MoveEnd
BattleScript_FaintAttacker::
tryillusionoff BS_ATTACKER
playfaintcry BS_ATTACKER
pause 0x40
dofaintanimation BS_ATTACKER
cleareffectsonfaint BS_ATTACKER
printstring STRINGID_ATTACKERFAINTED
cleareffectsonfaint BS_ATTACKER
trytrainerslidefirstdownmsg BS_ATTACKER
return
BattleScript_FaintTarget::
tryillusionoff BS_TARGET
playfaintcry BS_TARGET
pause 0x40
dofaintanimation BS_TARGET
cleareffectsonfaint BS_TARGET
printstring STRINGID_TARGETFAINTED
cleareffectsonfaint BS_TARGET
tryactivatemoxie BS_ATTACKER
tryactivatefellstinger BS_ATTACKER
trytrainerslidefirstdownmsg BS_TARGET
@ -5850,6 +5852,17 @@ BattleScript_MegaEvolution::
waitmessage 0x40
end2
BattleScript_IllusionOff::
spriteignore0hp TRUE
playanimation BS_TARGET, B_ANIM_ILLUSION_OFF, NULL
waitanimation
updatenick BS_TARGET
waitstate
spriteignore0hp FALSE
printstring STRINGID_ILLUSIONWOREOFF
waitmessage 0x40
return
BattleScript_MoveUsedIsAsleep::
printstring STRINGID_PKMNFASTASLEEP
waitmessage 0x40

View File

@ -426,6 +426,14 @@ struct MegaEvolutionData
u8 indicatorSpriteIds[MAX_BATTLERS_COUNT];
};
struct Illusion
{
u8 on:1;
u8 broken:1;
u8 partyId:3;
struct Pokemon *mon;
};
struct BattleStruct
{
u8 turnEffectsTracker;
@ -530,6 +538,8 @@ struct BattleStruct
u8 lastMoveTarget[MAX_BATTLERS_COUNT]; // The last target on which each mon used a move, for the sake of Instruct
u8 debugHoldEffects[MAX_BATTLERS_COUNT]; // These override actual items' hold effects.
u8 tracedAbility[MAX_BATTLERS_COUNT];
bool8 spriteIgnore0Hp;
struct Illusion illusion[MAX_BATTLERS_COUNT];
};
#define GET_MOVE_TYPE(move, typeArg) \

View File

@ -323,5 +323,6 @@ extern const u8 BattleScript_ToxicOrb[];
extern const u8 BattleScript_FlameOrb[];
extern const u8 BattleScript_MoveEffectIncinerate[];
extern const u8 BattleScript_MoveEffectBugBite[];
extern const u8 BattleScript_IllusionOff[];
#endif // GUARD_BATTLE_SCRIPTS_H

View File

@ -103,5 +103,8 @@ bool32 CanMegaEvolve(u8 battlerId);
void UndoMegaEvolution(u8 monId);
bool32 DoBattlersShareType(u32 battler1, u32 battler2);
bool32 CanBattlerGetOrLoseItem(u8 battlerId, u16 itemId);
struct Pokemon *GetIllusionMonPtr(u32 battlerId);
void ClearIllusionMon(u32 battlerId);
bool32 SetIllusionMon(struct Pokemon *mon, u32 battlerId);
#endif // GUARD_BATTLE_UTIL_H

View File

@ -406,6 +406,7 @@
#define B_ANIM_TERRAIN_GRASSY 0x19
#define B_ANIM_TERRAIN_ELECTRIC 0x1A
#define B_ANIM_TERRAIN_PSYCHIC 0x1B
#define B_ANIM_ILLUSION_OFF 0x1C
// special animations table
#define B_ANIM_LVL_UP 0x0

View File

@ -142,6 +142,9 @@
#define VARIOUS_TRY_INSTRUCT 79
#define VARIOUS_JUMP_IF_NOT_BERRY 80
#define VARIOUS_TRACE_ABILITY 81
#define VARIOUS_UPDATE_NICK 82
#define VARIOUS_TRY_ILLUSION_OFF 83
#define VARIOUS_SET_SPRITEIGNORE0HP 84
// atk80, dmg manipulation
#define ATK80_DMG_CHANGE_SIGN 0

View File

@ -539,7 +539,8 @@
#define STRINGID_AIRBALLOONPOP 535
#define STRINGID_INCINERATEBURN 536
#define STRINGID_BUGBITE 537
#define STRINGID_ILLUSIONWOREOFF 538
#define BATTLESTRINGS_COUNT 530
#define BATTLESTRINGS_COUNT 539
#endif // GUARD_CONSTANTS_BATTLE_STRING_IDS_H

View File

@ -750,13 +750,15 @@ static void SetBattlerData(u8 battlerId)
{
if (!IsBattlerAIControlled(battlerId))
{
struct Pokemon *illusionMon;
u32 i;
// Use the known battler's ability.
if (BATTLE_HISTORY->abilities[battlerId] != ABILITY_NONE)
gBattleMons[battlerId].ability = BATTLE_HISTORY->abilities[battlerId];
// Check if mon can only have one ability.
else if (gBaseStats[gBattleMons[battlerId].species].abilities[1] == ABILITY_NONE)
else if (gBaseStats[gBattleMons[battlerId].species].abilities[1] == ABILITY_NONE
|| gBaseStats[gBattleMons[battlerId].species].abilities[1] == gBaseStats[gBattleMons[battlerId].species].abilities[0])
gBattleMons[battlerId].ability = gBaseStats[gBattleMons[battlerId].species].abilities[0];
// The ability is unknown.
else
@ -770,6 +772,10 @@ static void SetBattlerData(u8 battlerId)
if (BATTLE_HISTORY->usedMoves[battlerId].moves[i] == 0)
gBattleMons[battlerId].moves[i] = 0;
}
// Simulate Illusion
if ((illusionMon = GetIllusionMonPtr(battlerId)) != NULL)
gBattleMons[battlerId].species = GetMonData(illusionMon, MON_DATA_SPECIES2);
}
}

View File

@ -119,6 +119,7 @@ u8 GetBattlerSpriteCoord(u8 battlerId, u8 coordType)
{
u8 retVal;
u16 species;
struct Pokemon *mon, *illusionMon;
struct BattleSpriteInfo *spriteInfo;
if (IsContest())
@ -149,22 +150,19 @@ u8 GetBattlerSpriteCoord(u8 battlerId, u8 coordType)
else
{
if (GetBattlerSide(battlerId) != B_SIDE_PLAYER)
{
mon = &gEnemyParty[gBattlerPartyIndexes[battlerId]];
else
mon = &gPlayerParty[gBattlerPartyIndexes[battlerId]];
illusionMon = GetIllusionMonPtr(battlerId);
if (illusionMon != NULL)
mon = illusionMon;
spriteInfo = gBattleSpritesDataPtr->battlerData;
if (!spriteInfo[battlerId].transformSpecies)
species = GetMonData(&gEnemyParty[gBattlerPartyIndexes[battlerId]], MON_DATA_SPECIES);
species = GetMonData(mon, MON_DATA_SPECIES);
else
species = spriteInfo[battlerId].transformSpecies;
}
else
{
spriteInfo = gBattleSpritesDataPtr->battlerData;
if (!spriteInfo[battlerId].transformSpecies)
species = GetMonData(&gPlayerParty[gBattlerPartyIndexes[battlerId]], MON_DATA_SPECIES);
else
species = spriteInfo[battlerId].transformSpecies;
}
}
if (coordType == BATTLER_COORD_Y_PIC_OFFSET)
retVal = GetBattlerSpriteFinal_Y(battlerId, species, TRUE);
else
@ -831,22 +829,24 @@ bool8 IsBattlerSpritePresent(u8 battlerId)
else
{
if (gBattlerPositions[battlerId] == 0xff)
{
return FALSE;
}
else if (GetBattlerSide(battlerId) != B_SIDE_PLAYER)
if (!gBattleStruct->spriteIgnore0Hp)
{
if (GetMonData(&gEnemyParty[gBattlerPartyIndexes[battlerId]], MON_DATA_HP) != 0)
return TRUE;
if (GetBattlerSide(battlerId) == B_SIDE_OPPONENT)
{
if (GetMonData(&gEnemyParty[gBattlerPartyIndexes[battlerId]], MON_DATA_HP) == 0)
return FALSE;
}
else
{
if (GetMonData(&gPlayerParty[gBattlerPartyIndexes[battlerId]], MON_DATA_HP) != 0)
if (GetMonData(&gPlayerParty[gBattlerPartyIndexes[battlerId]], MON_DATA_HP) == 0)
return FALSE;
}
}
return TRUE;
}
}
return FALSE;
}
bool8 IsDoubleBattle(void)
{

View File

@ -410,6 +410,9 @@ bool8 TryHandleLaunchBattleTableAnimation(u8 activeBattler, u8 atkBattler, u8 de
return TRUE;
}
if (tableId == B_ANIM_ILLUSION_OFF)
ClearIllusionMon(activeBattler);
gBattleAnimAttacker = atkBattler;
gBattleAnimTarget = defBattler;
gBattleSpritesDataPtr->animationData->animArg = argument;
@ -510,6 +513,9 @@ static void BattleLoadMonSpriteGfx(struct Pokemon *mon, u32 battlerId, bool32 op
{
u32 monsPersonality, currentPersonality, otId, species, paletteOffset, position;
const void *lzPaletteData;
struct Pokemon *illusionMon = GetIllusionMonPtr(battlerId);
if (illusionMon != NULL)
mon = illusionMon;
monsPersonality = GetMonData(mon, MON_DATA_PERSONALITY);
if (gBattleSpritesDataPtr->battlerData[battlerId].transformSpecies == SPECIES_NONE)
@ -1152,6 +1158,11 @@ void ClearTemporarySpeciesSpriteData(u8 battlerId, bool8 dontClearSubstitute)
gBattleMonForms[battlerId] = 0;
if (!dontClearSubstitute)
ClearBehindSubstituteBit(battlerId);
if (GetBattlerSide(battlerId) == B_SIDE_PLAYER)
SetIllusionMon(&gPlayerParty[gBattlerPartyIndexes[battlerId]], battlerId);
else
SetIllusionMon(&gEnemyParty[gBattlerPartyIndexes[battlerId]], battlerId);
}
void AllocateMonSpritesGfx(void)

View File

@ -1868,10 +1868,12 @@ static void UpdateNickInHealthbox(u8 healthboxSpriteId, struct Pokemon *mon)
u8 nickname[POKEMON_NAME_LENGTH + 1];
void *ptr;
const u8 *genderTxt;
u32 windowId, spriteTileNum;
u32 windowId, spriteTileNum, species;
u8 *windowTileData;
u16 species;
u8 gender;
struct Pokemon *illusionMon = GetIllusionMonPtr(gSprites[healthboxSpriteId].hMain_Battler);
if (illusionMon != NULL)
mon = illusionMon;
StringCopy(gDisplayedStringBattle, gText_HighlightDarkGrey);
GetMonData(mon, MON_DATA_NICKNAME, nickname);

View File

@ -664,9 +664,11 @@ static const u8 sText_AirBalloonFloat[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX} flo
static const u8 sText_AirBalloonPop[] = _("{B_DEF_NAME_WITH_PREFIX}'s {B_LAST_ITEM} popped!");
static const u8 sText_IncinerateBurn[] = _("{B_EFF_NAME_WITH_PREFIX}'s {B_LAST_ITEM}\nwas burnt up!");
static const u8 sText_BugBite[] = _("{B_ATK_NAME_WITH_PREFIX} stole and ate\n{B_EFF_NAME_WITH_PREFIX}'s {B_LAST_ITEM}!");
static const u8 sText_IllusionWoreOff[] = _("{B_DEF_NAME_WITH_PREFIX}'s Illusion wore off!");
const u8 *const gBattleStringsTable[BATTLESTRINGS_COUNT] =
{
[STRINGID_ILLUSIONWOREOFF - 12] = sText_IllusionWoreOff,
[STRINGID_BUGBITE - 12] = sText_BugBite,
[STRINGID_INCINERATEBURN - 12] = sText_IncinerateBurn,
[STRINGID_AIRBALLOONPOP - 12] = sText_AirBalloonPop,
@ -2307,10 +2309,10 @@ void BufferStringBattle(u16 stringID)
gLastUsedItem = gBattleMsgDataPtr->lastItem;
gLastUsedAbility = gBattleMsgDataPtr->lastAbility;
gBattleScripting.battler = gBattleMsgDataPtr->scrActive;
*(&gBattleStruct->field_52) = gBattleMsgDataPtr->unk1605E;
*(&gBattleStruct->hpScale) = gBattleMsgDataPtr->hpScale;
gBattleStruct->field_52 = gBattleMsgDataPtr->unk1605E;
gBattleStruct->hpScale = gBattleMsgDataPtr->hpScale;
gPotentialItemEffectBattler = gBattleMsgDataPtr->itemEffectBattler;
*(&gBattleStruct->stringMoveType) = gBattleMsgDataPtr->moveType;
gBattleStruct->stringMoveType = gBattleMsgDataPtr->moveType;
for (i = 0; i < MAX_BATTLERS_COUNT; i++)
{
@ -2630,7 +2632,23 @@ static const u8* TryGetStatusString(u8 *src)
return NULL;
}
#define HANDLE_NICKNAME_STRING_CASE(battlerId, monIndex) \
static void GetBattlerNick(u32 battlerId, u8 *dst)
{
struct Pokemon *mon, *illusionMon;
if (GET_BATTLER_SIDE(battlerId) == B_SIDE_PLAYER)
mon = &gPlayerParty[gBattlerPartyIndexes[battlerId]];
else
mon = &gEnemyParty[gBattlerPartyIndexes[battlerId]];
illusionMon = GetIllusionMonPtr(battlerId);
if (illusionMon != NULL)
mon = illusionMon;
GetMonData(mon, MON_DATA_NICKNAME, dst);
StringGetEnd10(dst);
}
#define HANDLE_NICKNAME_STRING_CASE(battlerId) \
if (GetBattlerSide(battlerId) != B_SIDE_PLAYER) \
{ \
if (gBattleTypeFlags & BATTLE_TYPE_TRAINER) \
@ -2643,13 +2661,8 @@ static const u8* TryGetStatusString(u8 *src)
dstID++; \
toCpy++; \
} \
GetMonData(&gEnemyParty[monIndex], MON_DATA_NICKNAME, text); \
} \
else \
{ \
GetMonData(&gPlayerParty[monIndex], MON_DATA_NICKNAME, text); \
} \
StringGetEnd10(text); \
GetBattlerNick(battlerId, text); \
toCpy = text;
static const u8 *BattleStringGetOpponentNameByTrainerId(u16 trainerId, u8 *text, u8 multiplayerId, u8 battlerId)
@ -2848,89 +2861,61 @@ u32 BattleStringExpandPlaceholders(const u8 *src, u8 *dst)
toCpy = gStringVar3;
break;
case B_TXT_PLAYER_MON1_NAME: // first player poke name
GetMonData(&gPlayerParty[gBattlerPartyIndexes[GetBattlerAtPosition(B_POSITION_PLAYER_LEFT)]],
MON_DATA_NICKNAME, text);
StringGetEnd10(text);
GetBattlerNick(GetBattlerAtPosition(B_POSITION_PLAYER_LEFT), text);
toCpy = text;
break;
case B_TXT_OPPONENT_MON1_NAME: // first enemy poke name
GetMonData(&gEnemyParty[gBattlerPartyIndexes[GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT)]],
MON_DATA_NICKNAME, text);
StringGetEnd10(text);
GetBattlerNick(GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT), text);
toCpy = text;
break;
case B_TXT_PLAYER_MON2_NAME: // second player poke name
GetMonData(&gPlayerParty[gBattlerPartyIndexes[GetBattlerAtPosition(B_POSITION_PLAYER_RIGHT)]],
MON_DATA_NICKNAME, text);
StringGetEnd10(text);
GetBattlerNick(GetBattlerAtPosition(B_POSITION_PLAYER_RIGHT), text);
toCpy = text;
break;
case B_TXT_OPPONENT_MON2_NAME: // second enemy poke name
GetMonData(&gEnemyParty[gBattlerPartyIndexes[GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT)]],
MON_DATA_NICKNAME, text);
StringGetEnd10(text);
GetBattlerNick(GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT), text);
toCpy = text;
break;
case B_TXT_LINK_PLAYER_MON1_NAME: // link first player poke name
GetMonData(&gPlayerParty[gBattlerPartyIndexes[gLinkPlayers[multiplayerId].id]],
MON_DATA_NICKNAME, text);
StringGetEnd10(text);
GetBattlerNick(gLinkPlayers[multiplayerId].id, text);
toCpy = text;
break;
case B_TXT_LINK_OPPONENT_MON1_NAME: // link first opponent poke name
GetMonData(&gEnemyParty[gBattlerPartyIndexes[gLinkPlayers[multiplayerId].id ^ 1]],
MON_DATA_NICKNAME, text);
StringGetEnd10(text);
GetBattlerNick(gLinkPlayers[multiplayerId].id ^ 1, text);
toCpy = text;
break;
case B_TXT_LINK_PLAYER_MON2_NAME: // link second player poke name
GetMonData(&gPlayerParty[gBattlerPartyIndexes[gLinkPlayers[multiplayerId].id ^ 2]],
MON_DATA_NICKNAME, text);
StringGetEnd10(text);
GetBattlerNick(gLinkPlayers[multiplayerId].id ^ 2, text);
toCpy = text;
break;
case B_TXT_LINK_OPPONENT_MON2_NAME: // link second opponent poke name
GetMonData(&gEnemyParty[gBattlerPartyIndexes[gLinkPlayers[multiplayerId].id ^ 3]],
MON_DATA_NICKNAME, text);
StringGetEnd10(text);
GetBattlerNick(gLinkPlayers[multiplayerId].id ^ 3, text);
toCpy = text;
break;
case B_TXT_ATK_NAME_WITH_PREFIX_MON1: // attacker name with prefix, only battlerId 0/1
HANDLE_NICKNAME_STRING_CASE(gBattlerAttacker,
gBattlerPartyIndexes[GetBattlerAtPosition(GET_BATTLER_SIDE(gBattlerAttacker))])
case B_TXT_ATK_NAME_WITH_PREFIX_MON1: // Unused, to change into sth else.
break;
case B_TXT_ATK_PARTNER_NAME: // attacker partner name
if (GetBattlerSide(gBattlerAttacker) == B_SIDE_PLAYER)
GetMonData(&gPlayerParty[gBattlerPartyIndexes[GetBattlerAtPosition(GET_BATTLER_SIDE(gBattlerAttacker)) + 2]], MON_DATA_NICKNAME, text);
else
GetMonData(&gEnemyParty[gBattlerPartyIndexes[GetBattlerAtPosition(GET_BATTLER_SIDE(gBattlerAttacker)) + 2]], MON_DATA_NICKNAME, text);
StringGetEnd10(text);
GetBattlerNick(BATTLE_PARTNER(gBattlerAttacker), text);
toCpy = text;
break;
case B_TXT_ATK_NAME_WITH_PREFIX: // attacker name with prefix
HANDLE_NICKNAME_STRING_CASE(gBattlerAttacker, gBattlerPartyIndexes[gBattlerAttacker])
HANDLE_NICKNAME_STRING_CASE(gBattlerAttacker)
break;
case B_TXT_DEF_NAME_WITH_PREFIX: // target name with prefix
HANDLE_NICKNAME_STRING_CASE(gBattlerTarget, gBattlerPartyIndexes[gBattlerTarget])
HANDLE_NICKNAME_STRING_CASE(gBattlerTarget)
break;
case B_TXT_DEF_NAME: // target name
if (GetBattlerSide(gBattlerTarget) == B_SIDE_PLAYER)
GetMonData(&gPlayerParty[gBattlerPartyIndexes[gBattlerTarget]], MON_DATA_NICKNAME, text);
else
GetMonData(&gEnemyParty[gBattlerPartyIndexes[gBattlerTarget]], MON_DATA_NICKNAME, text);
StringGetEnd10(text);
GetBattlerNick(gBattlerTarget, text);
toCpy = text;
break;
case B_TXT_EFF_NAME_WITH_PREFIX: // effect battlerId name with prefix
HANDLE_NICKNAME_STRING_CASE(gEffectBattler, gBattlerPartyIndexes[gEffectBattler])
HANDLE_NICKNAME_STRING_CASE(gEffectBattler)
break;
case B_TXT_ACTIVE_NAME_WITH_PREFIX: // active battlerId name with prefix
HANDLE_NICKNAME_STRING_CASE(gActiveBattler, gBattlerPartyIndexes[gActiveBattler])
HANDLE_NICKNAME_STRING_CASE(gActiveBattler)
break;
case B_TXT_SCR_ACTIVE_NAME_WITH_PREFIX: // scripting active battlerId name with prefix
HANDLE_NICKNAME_STRING_CASE(gBattleScripting.battler, gBattlerPartyIndexes[gBattleScripting.battler])
HANDLE_NICKNAME_STRING_CASE(gBattleScripting.battler)
break;
case B_TXT_CURRENT_MOVE: // current move name
if (gBattleMsgDataPtr->currentMove >= MOVES_COUNT)
@ -3055,7 +3040,26 @@ u32 BattleStringExpandPlaceholders(const u8 *src, u8 *dst)
}
break;
case B_TXT_26: // ?
HANDLE_NICKNAME_STRING_CASE(gBattleScripting.battler, *(&gBattleStruct->field_52));
if (GetBattlerSide(gBattleScripting.battler) != B_SIDE_PLAYER)
{
if (gBattleTypeFlags & BATTLE_TYPE_TRAINER)
toCpy = sText_FoePkmnPrefix;
else
toCpy = sText_WildPkmnPrefix;
while (*toCpy != EOS)
{
dst[dstID] = *toCpy;
dstID++;
toCpy++;
}
GetMonData(&gEnemyParty[gBattleStruct->field_52], MON_DATA_NICKNAME, text);
}
else
{
GetMonData(&gPlayerParty[gBattleStruct->field_52], MON_DATA_NICKNAME, text);
}
StringGetEnd10(text);
toCpy = text;
break;
case B_TXT_PC_CREATOR_NAME: // lanette pc
if (FlagGet(FLAG_SYS_PC_LANETTE))
@ -3287,11 +3291,18 @@ static void ExpandBattleTextBuffPlaceholders(const u8 *src, u8 *dst)
srcID += 3;
break;
case B_BUFF_MON_NICK: // poke nick without prefix
if (src[srcID + 2] == gBattlerPartyIndexes[src[srcID + 1]])
{
GetBattlerNick(src[srcID + 1], dst);
}
else
{
if (GetBattlerSide(src[srcID + 1]) == B_SIDE_PLAYER)
GetMonData(&gPlayerParty[src[srcID + 2]], MON_DATA_NICKNAME, dst);
else
GetMonData(&gEnemyParty[src[srcID + 2]], MON_DATA_NICKNAME, dst);
StringGetEnd10(dst);
}
srcID += 3;
break;
case B_BUFF_NEGATIVE_FLAVOR: // flavor table

View File

@ -4068,6 +4068,7 @@ static void atk45_playanimation(void)
if (gBattlescriptCurrInstr[2] == B_ANIM_STATS_CHANGE
|| gBattlescriptCurrInstr[2] == B_ANIM_SNATCH_MOVE
|| gBattlescriptCurrInstr[2] == B_ANIM_MEGA_EVOLUTION
|| gBattlescriptCurrInstr[2] == B_ANIM_ILLUSION_OFF
|| gBattlescriptCurrInstr[2] == B_ANIM_SUBSTITUTE_FADE)
{
BtlController_EmitBattleAnimation(0, gBattlescriptCurrInstr[2], *argumentPtr);
@ -4112,6 +4113,7 @@ static void atk46_playanimation2(void) // animation Id is stored in the first po
if (*animationIdPtr == B_ANIM_STATS_CHANGE
|| *animationIdPtr == B_ANIM_SNATCH_MOVE
|| *animationIdPtr == B_ANIM_MEGA_EVOLUTION
|| *animationIdPtr == B_ANIM_ILLUSION_OFF
|| *animationIdPtr == B_ANIM_SUBSTITUTE_FADE)
{
BtlController_EmitBattleAnimation(0, *animationIdPtr, *argumentPtr);
@ -6570,10 +6572,9 @@ u32 IsFlowerVeilProtected(u32 battler)
static void atk76_various(void)
{
struct Pokemon *mon;
u8 side;
s32 i, j;
u8 data[10];
u32 bits;
u32 side, bits;
if (gBattleControllerExecFlags)
return;
@ -6600,6 +6601,26 @@ static void atk76_various(void)
case VARIOUS_TRACE_ABILITY:
gBattleMons[gActiveBattler].ability = gBattleStruct->tracedAbility[gActiveBattler];
break;
case VARIOUS_TRY_ILLUSION_OFF:
if (GetIllusionMonPtr(gActiveBattler) != NULL)
{
gBattlescriptCurrInstr += 3;
BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_IllusionOff;
return;
}
break;
case VARIOUS_SET_SPRITEIGNORE0HP:
gBattleStruct->spriteIgnore0Hp = gBattlescriptCurrInstr[3];
gBattlescriptCurrInstr += 4;
return;
case VARIOUS_UPDATE_NICK:
if (GetBattlerSide(gActiveBattler) == B_SIDE_PLAYER)
mon = &gPlayerParty[gBattlerPartyIndexes[gActiveBattler]];
else
mon = &gEnemyParty[gBattlerPartyIndexes[gActiveBattler]];
UpdateHealthboxAttribute(gHealthboxSpriteIds[gActiveBattler], mon, HEALTHBOX_NICK);
break;
case VARIOUS_JUMP_IF_NOT_BERRY:
if (ItemId_GetPocket(gBattleMons[gActiveBattler].item) == POCKET_BERRIES)
gBattlescriptCurrInstr += 7;

View File

@ -9,6 +9,7 @@
#include "constants/moves.h"
#include "constants/hold_effects.h"
#include "constants/battle_anim.h"
#include "party_menu.h"
#include "pokemon.h"
#include "constants/species.h"
#include "item.h"
@ -3423,6 +3424,14 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u8 ability, u8 special, u16 moveA
effect++;
}
break;
case ABILITY_ILLUSION:
if (gBattleStruct->illusion[battler].on && !gBattleStruct->illusion[battler].broken && IsBattlerAlive(battler) && TARGET_TURN_DAMAGED)
{
BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_IllusionOff;
effect++;
}
break;
}
break;
case ABILITYEFFECT_IMMUNITY: // 5
@ -6241,3 +6250,56 @@ bool32 CanBattlerGetOrLoseItem(u8 battlerId, u16 itemId)
else
return TRUE;
}
struct Pokemon *GetIllusionMonPtr(u32 battlerId)
{
if (!gBattleStruct->illusion[battlerId].on || gBattleStruct->illusion[battlerId].broken)
return NULL;
return gBattleStruct->illusion[battlerId].mon;
}
void ClearIllusionMon(u32 battlerId)
{
gBattleStruct->illusion[battlerId].on = 0;
gBattleStruct->illusion[battlerId].mon = NULL;
gBattleStruct->illusion[battlerId].broken = 1;
}
bool32 SetIllusionMon(struct Pokemon *mon, u32 battlerId)
{
struct Pokemon *party, *partnerMon;
s32 i, id;
if (GetMonAbility(mon) != ABILITY_ILLUSION)
return FALSE;
if (GetBattlerSide(battlerId) == B_SIDE_PLAYER)
party = gPlayerParty;
else
party = gEnemyParty;
if (IsBattlerAlive(BATTLE_PARTNER(battlerId)))
partnerMon = &party[gBattlerPartyIndexes[BATTLE_PARTNER(battlerId)]];
else
partnerMon = mon;
// Find last alive non-egg pokemon.
for (i = PARTY_SIZE - 1; i >= 0; i--)
{
id = pokemon_order_func(i);
if (GetMonData(&party[id], MON_DATA_SANITY_HAS_SPECIES)
&& GetMonData(&party[id], MON_DATA_HP)
&& &party[id] != mon
&& &party[id] != partnerMon)
{
gBattleStruct->illusion[battlerId].on = 1;
gBattleStruct->illusion[battlerId].broken = 0;
gBattleStruct->illusion[battlerId].partyId = id;
gBattleStruct->illusion[battlerId].mon = &party[id];
return TRUE;
}
}
return FALSE;
}

View File

@ -342,11 +342,8 @@ u8 DoPokeballSendOutAnimation(s16 pan, u8 kindOfThrow)
static void Task_DoPokeballSendOutAnim(u8 taskId)
{
u16 throwCaseId;
u8 battlerId;
u16 itemId, ballId;
u8 ballSpriteId;
bool8 notSendOut = FALSE;
u32 throwCaseId, ballId, battlerId, ballSpriteId;
bool32 notSendOut = FALSE;
if (gTasks[taskId].tFrames == 0)
{
@ -356,13 +353,7 @@ static void Task_DoPokeballSendOutAnim(u8 taskId)
throwCaseId = gTasks[taskId].tThrowId;
battlerId = gTasks[taskId].tBattler;
if (GetBattlerSide(battlerId) != B_SIDE_PLAYER)
itemId = GetMonData(&gEnemyParty[gBattlerPartyIndexes[battlerId]], MON_DATA_POKEBALL);
else
itemId = GetMonData(&gPlayerParty[gBattlerPartyIndexes[battlerId]], MON_DATA_POKEBALL);
ballId = ItemIdToBallId(itemId);
ballId = ItemIdToBallId(GetBattlerPokeballItemId(battlerId));
LoadBallGfx(ballId);
ballSpriteId = CreateSprite(&gBallSpriteTemplates[ballId], 32, 80, 29);
gSprites[ballSpriteId].data[0] = 0x80;
@ -743,8 +734,7 @@ static void SpriteCB_ReleaseMonFromBall(struct Sprite *sprite)
if (gMain.inBattle)
{
struct Pokemon *mon;
u16 species;
struct Pokemon *mon, *illusionMon;
s8 pan;
u16 wantedCryCase;
u8 taskId;
@ -760,7 +750,6 @@ static void SpriteCB_ReleaseMonFromBall(struct Sprite *sprite)
pan = -25;
}
species = GetMonData(mon, MON_DATA_SPECIES);
if ((battlerId == GetBattlerAtPosition(B_POSITION_PLAYER_LEFT) || battlerId == GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT))
&& IsDoubleBattle() && gBattleSpritesDataPtr->animationData->field_9_x1)
{
@ -783,9 +772,14 @@ static void SpriteCB_ReleaseMonFromBall(struct Sprite *sprite)
wantedCryCase = 2;
gBattleSpritesDataPtr->healthBoxesData[battlerId].field_1_x40 = 1;
taskId = CreateTask(Task_PlayCryWhenReleasedFromBall, 3);
gTasks[taskId].tCryTaskSpecies = species;
illusionMon = GetIllusionMonPtr(battlerId);
if (illusionMon != NULL)
gTasks[taskId].tCryTaskSpecies = GetMonData(illusionMon, MON_DATA_SPECIES);
else
gTasks[taskId].tCryTaskSpecies = GetMonData(mon, MON_DATA_SPECIES);
gTasks[taskId].tCryTaskPan = pan;
gTasks[taskId].tCryTaskWantedCry = wantedCryCase;
gTasks[taskId].tCryTaskBattler = battlerId;
@ -1269,8 +1263,16 @@ void FreeBallGfx(u8 ballId)
static u16 GetBattlerPokeballItemId(u8 battlerId)
{
struct Pokemon *mon, *illusionMon;
if (GetBattlerSide(battlerId) == B_SIDE_PLAYER)
return GetMonData(&gPlayerParty[gBattlerPartyIndexes[battlerId]], MON_DATA_POKEBALL);
mon = &gPlayerParty[gBattlerPartyIndexes[battlerId]];
else
return GetMonData(&gEnemyParty[gBattlerPartyIndexes[battlerId]], MON_DATA_POKEBALL);
mon = &gEnemyParty[gBattlerPartyIndexes[battlerId]];
illusionMon = GetIllusionMonPtr(battlerId);
if (illusionMon != NULL)
mon = illusionMon;
return GetMonData(mon, MON_DATA_POKEBALL);
}