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 various \battler, VARIOUS_TRACE_ABILITY
.endm .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 @ helpful macros
.macro setstatchanger stat:req, stages:req, down:req .macro setstatchanger stat:req, stages:req, down:req
setbyte sSTATCHANGER \stat | \stages << 3 | \down << 7 setbyte sSTATCHANGER \stat | \stages << 3 | \down << 7

View File

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

View File

@ -4675,20 +4675,22 @@ BattleScript_EffectCamouflage::
goto BattleScript_MoveEnd goto BattleScript_MoveEnd
BattleScript_FaintAttacker:: BattleScript_FaintAttacker::
tryillusionoff BS_ATTACKER
playfaintcry BS_ATTACKER playfaintcry BS_ATTACKER
pause 0x40 pause 0x40
dofaintanimation BS_ATTACKER dofaintanimation BS_ATTACKER
cleareffectsonfaint BS_ATTACKER
printstring STRINGID_ATTACKERFAINTED printstring STRINGID_ATTACKERFAINTED
cleareffectsonfaint BS_ATTACKER
trytrainerslidefirstdownmsg BS_ATTACKER trytrainerslidefirstdownmsg BS_ATTACKER
return return
BattleScript_FaintTarget:: BattleScript_FaintTarget::
tryillusionoff BS_TARGET
playfaintcry BS_TARGET playfaintcry BS_TARGET
pause 0x40 pause 0x40
dofaintanimation BS_TARGET dofaintanimation BS_TARGET
cleareffectsonfaint BS_TARGET
printstring STRINGID_TARGETFAINTED printstring STRINGID_TARGETFAINTED
cleareffectsonfaint BS_TARGET
tryactivatemoxie BS_ATTACKER tryactivatemoxie BS_ATTACKER
tryactivatefellstinger BS_ATTACKER tryactivatefellstinger BS_ATTACKER
trytrainerslidefirstdownmsg BS_TARGET trytrainerslidefirstdownmsg BS_TARGET
@ -5850,6 +5852,17 @@ BattleScript_MegaEvolution::
waitmessage 0x40 waitmessage 0x40
end2 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:: BattleScript_MoveUsedIsAsleep::
printstring STRINGID_PKMNFASTASLEEP printstring STRINGID_PKMNFASTASLEEP
waitmessage 0x40 waitmessage 0x40

View File

@ -426,6 +426,14 @@ struct MegaEvolutionData
u8 indicatorSpriteIds[MAX_BATTLERS_COUNT]; u8 indicatorSpriteIds[MAX_BATTLERS_COUNT];
}; };
struct Illusion
{
u8 on:1;
u8 broken:1;
u8 partyId:3;
struct Pokemon *mon;
};
struct BattleStruct struct BattleStruct
{ {
u8 turnEffectsTracker; 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 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 debugHoldEffects[MAX_BATTLERS_COUNT]; // These override actual items' hold effects.
u8 tracedAbility[MAX_BATTLERS_COUNT]; u8 tracedAbility[MAX_BATTLERS_COUNT];
bool8 spriteIgnore0Hp;
struct Illusion illusion[MAX_BATTLERS_COUNT];
}; };
#define GET_MOVE_TYPE(move, typeArg) \ #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_FlameOrb[];
extern const u8 BattleScript_MoveEffectIncinerate[]; extern const u8 BattleScript_MoveEffectIncinerate[];
extern const u8 BattleScript_MoveEffectBugBite[]; extern const u8 BattleScript_MoveEffectBugBite[];
extern const u8 BattleScript_IllusionOff[];
#endif // GUARD_BATTLE_SCRIPTS_H #endif // GUARD_BATTLE_SCRIPTS_H

View File

@ -103,5 +103,8 @@ bool32 CanMegaEvolve(u8 battlerId);
void UndoMegaEvolution(u8 monId); void UndoMegaEvolution(u8 monId);
bool32 DoBattlersShareType(u32 battler1, u32 battler2); bool32 DoBattlersShareType(u32 battler1, u32 battler2);
bool32 CanBattlerGetOrLoseItem(u8 battlerId, u16 itemId); 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 #endif // GUARD_BATTLE_UTIL_H

View File

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

View File

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

View File

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

View File

@ -750,13 +750,15 @@ static void SetBattlerData(u8 battlerId)
{ {
if (!IsBattlerAIControlled(battlerId)) if (!IsBattlerAIControlled(battlerId))
{ {
struct Pokemon *illusionMon;
u32 i; u32 i;
// Use the known battler's ability. // Use the known battler's ability.
if (BATTLE_HISTORY->abilities[battlerId] != ABILITY_NONE) if (BATTLE_HISTORY->abilities[battlerId] != ABILITY_NONE)
gBattleMons[battlerId].ability = BATTLE_HISTORY->abilities[battlerId]; gBattleMons[battlerId].ability = BATTLE_HISTORY->abilities[battlerId];
// Check if mon can only have one ability. // 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]; gBattleMons[battlerId].ability = gBaseStats[gBattleMons[battlerId].species].abilities[0];
// The ability is unknown. // The ability is unknown.
else else
@ -770,6 +772,10 @@ static void SetBattlerData(u8 battlerId)
if (BATTLE_HISTORY->usedMoves[battlerId].moves[i] == 0) if (BATTLE_HISTORY->usedMoves[battlerId].moves[i] == 0)
gBattleMons[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; u8 retVal;
u16 species; u16 species;
struct Pokemon *mon, *illusionMon;
struct BattleSpriteInfo *spriteInfo; struct BattleSpriteInfo *spriteInfo;
if (IsContest()) if (IsContest())
@ -149,21 +150,18 @@ u8 GetBattlerSpriteCoord(u8 battlerId, u8 coordType)
else else
{ {
if (GetBattlerSide(battlerId) != B_SIDE_PLAYER) if (GetBattlerSide(battlerId) != B_SIDE_PLAYER)
{ mon = &gEnemyParty[gBattlerPartyIndexes[battlerId]];
spriteInfo = gBattleSpritesDataPtr->battlerData;
if (!spriteInfo[battlerId].transformSpecies)
species = GetMonData(&gEnemyParty[gBattlerPartyIndexes[battlerId]], MON_DATA_SPECIES);
else
species = spriteInfo[battlerId].transformSpecies;
}
else else
{ mon = &gPlayerParty[gBattlerPartyIndexes[battlerId]];
spriteInfo = gBattleSpritesDataPtr->battlerData;
if (!spriteInfo[battlerId].transformSpecies) illusionMon = GetIllusionMonPtr(battlerId);
species = GetMonData(&gPlayerParty[gBattlerPartyIndexes[battlerId]], MON_DATA_SPECIES); if (illusionMon != NULL)
else mon = illusionMon;
species = spriteInfo[battlerId].transformSpecies; spriteInfo = gBattleSpritesDataPtr->battlerData;
} if (!spriteInfo[battlerId].transformSpecies)
species = GetMonData(mon, MON_DATA_SPECIES);
else
species = spriteInfo[battlerId].transformSpecies;
} }
if (coordType == BATTLER_COORD_Y_PIC_OFFSET) if (coordType == BATTLER_COORD_Y_PIC_OFFSET)
retVal = GetBattlerSpriteFinal_Y(battlerId, species, TRUE); retVal = GetBattlerSpriteFinal_Y(battlerId, species, TRUE);
@ -831,21 +829,23 @@ bool8 IsBattlerSpritePresent(u8 battlerId)
else else
{ {
if (gBattlerPositions[battlerId] == 0xff) if (gBattlerPositions[battlerId] == 0xff)
{
return FALSE; return FALSE;
}
else if (GetBattlerSide(battlerId) != B_SIDE_PLAYER) if (!gBattleStruct->spriteIgnore0Hp)
{ {
if (GetMonData(&gEnemyParty[gBattlerPartyIndexes[battlerId]], MON_DATA_HP) != 0) if (GetBattlerSide(battlerId) == B_SIDE_OPPONENT)
return TRUE; {
} if (GetMonData(&gEnemyParty[gBattlerPartyIndexes[battlerId]], MON_DATA_HP) == 0)
else return FALSE;
{ }
if (GetMonData(&gPlayerParty[gBattlerPartyIndexes[battlerId]], MON_DATA_HP) != 0) else
return TRUE; {
if (GetMonData(&gPlayerParty[gBattlerPartyIndexes[battlerId]], MON_DATA_HP) == 0)
return FALSE;
}
} }
return TRUE;
} }
return FALSE;
} }
bool8 IsDoubleBattle(void) bool8 IsDoubleBattle(void)

View File

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

View File

@ -1868,10 +1868,12 @@ static void UpdateNickInHealthbox(u8 healthboxSpriteId, struct Pokemon *mon)
u8 nickname[POKEMON_NAME_LENGTH + 1]; u8 nickname[POKEMON_NAME_LENGTH + 1];
void *ptr; void *ptr;
const u8 *genderTxt; const u8 *genderTxt;
u32 windowId, spriteTileNum; u32 windowId, spriteTileNum, species;
u8 *windowTileData; u8 *windowTileData;
u16 species;
u8 gender; u8 gender;
struct Pokemon *illusionMon = GetIllusionMonPtr(gSprites[healthboxSpriteId].hMain_Battler);
if (illusionMon != NULL)
mon = illusionMon;
StringCopy(gDisplayedStringBattle, gText_HighlightDarkGrey); StringCopy(gDisplayedStringBattle, gText_HighlightDarkGrey);
GetMonData(mon, MON_DATA_NICKNAME, nickname); 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_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_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_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] = const u8 *const gBattleStringsTable[BATTLESTRINGS_COUNT] =
{ {
[STRINGID_ILLUSIONWOREOFF - 12] = sText_IllusionWoreOff,
[STRINGID_BUGBITE - 12] = sText_BugBite, [STRINGID_BUGBITE - 12] = sText_BugBite,
[STRINGID_INCINERATEBURN - 12] = sText_IncinerateBurn, [STRINGID_INCINERATEBURN - 12] = sText_IncinerateBurn,
[STRINGID_AIRBALLOONPOP - 12] = sText_AirBalloonPop, [STRINGID_AIRBALLOONPOP - 12] = sText_AirBalloonPop,
@ -2307,10 +2309,10 @@ void BufferStringBattle(u16 stringID)
gLastUsedItem = gBattleMsgDataPtr->lastItem; gLastUsedItem = gBattleMsgDataPtr->lastItem;
gLastUsedAbility = gBattleMsgDataPtr->lastAbility; gLastUsedAbility = gBattleMsgDataPtr->lastAbility;
gBattleScripting.battler = gBattleMsgDataPtr->scrActive; gBattleScripting.battler = gBattleMsgDataPtr->scrActive;
*(&gBattleStruct->field_52) = gBattleMsgDataPtr->unk1605E; gBattleStruct->field_52 = gBattleMsgDataPtr->unk1605E;
*(&gBattleStruct->hpScale) = gBattleMsgDataPtr->hpScale; gBattleStruct->hpScale = gBattleMsgDataPtr->hpScale;
gPotentialItemEffectBattler = gBattleMsgDataPtr->itemEffectBattler; gPotentialItemEffectBattler = gBattleMsgDataPtr->itemEffectBattler;
*(&gBattleStruct->stringMoveType) = gBattleMsgDataPtr->moveType; gBattleStruct->stringMoveType = gBattleMsgDataPtr->moveType;
for (i = 0; i < MAX_BATTLERS_COUNT; i++) for (i = 0; i < MAX_BATTLERS_COUNT; i++)
{ {
@ -2630,7 +2632,23 @@ static const u8* TryGetStatusString(u8 *src)
return NULL; 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 (GetBattlerSide(battlerId) != B_SIDE_PLAYER) \
{ \ { \
if (gBattleTypeFlags & BATTLE_TYPE_TRAINER) \ if (gBattleTypeFlags & BATTLE_TYPE_TRAINER) \
@ -2643,13 +2661,8 @@ static const u8* TryGetStatusString(u8 *src)
dstID++; \ dstID++; \
toCpy++; \ toCpy++; \
} \ } \
GetMonData(&gEnemyParty[monIndex], MON_DATA_NICKNAME, text); \
} \ } \
else \ GetBattlerNick(battlerId, text); \
{ \
GetMonData(&gPlayerParty[monIndex], MON_DATA_NICKNAME, text); \
} \
StringGetEnd10(text); \
toCpy = text; toCpy = text;
static const u8 *BattleStringGetOpponentNameByTrainerId(u16 trainerId, u8 *text, u8 multiplayerId, u8 battlerId) 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; toCpy = gStringVar3;
break; break;
case B_TXT_PLAYER_MON1_NAME: // first player poke name case B_TXT_PLAYER_MON1_NAME: // first player poke name
GetMonData(&gPlayerParty[gBattlerPartyIndexes[GetBattlerAtPosition(B_POSITION_PLAYER_LEFT)]], GetBattlerNick(GetBattlerAtPosition(B_POSITION_PLAYER_LEFT), text);
MON_DATA_NICKNAME, text);
StringGetEnd10(text);
toCpy = text; toCpy = text;
break; break;
case B_TXT_OPPONENT_MON1_NAME: // first enemy poke name case B_TXT_OPPONENT_MON1_NAME: // first enemy poke name
GetMonData(&gEnemyParty[gBattlerPartyIndexes[GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT)]], GetBattlerNick(GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT), text);
MON_DATA_NICKNAME, text);
StringGetEnd10(text);
toCpy = text; toCpy = text;
break; break;
case B_TXT_PLAYER_MON2_NAME: // second player poke name case B_TXT_PLAYER_MON2_NAME: // second player poke name
GetMonData(&gPlayerParty[gBattlerPartyIndexes[GetBattlerAtPosition(B_POSITION_PLAYER_RIGHT)]], GetBattlerNick(GetBattlerAtPosition(B_POSITION_PLAYER_RIGHT), text);
MON_DATA_NICKNAME, text);
StringGetEnd10(text);
toCpy = text; toCpy = text;
break; break;
case B_TXT_OPPONENT_MON2_NAME: // second enemy poke name case B_TXT_OPPONENT_MON2_NAME: // second enemy poke name
GetMonData(&gEnemyParty[gBattlerPartyIndexes[GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT)]], GetBattlerNick(GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT), text);
MON_DATA_NICKNAME, text);
StringGetEnd10(text);
toCpy = text; toCpy = text;
break; break;
case B_TXT_LINK_PLAYER_MON1_NAME: // link first player poke name case B_TXT_LINK_PLAYER_MON1_NAME: // link first player poke name
GetMonData(&gPlayerParty[gBattlerPartyIndexes[gLinkPlayers[multiplayerId].id]], GetBattlerNick(gLinkPlayers[multiplayerId].id, text);
MON_DATA_NICKNAME, text);
StringGetEnd10(text);
toCpy = text; toCpy = text;
break; break;
case B_TXT_LINK_OPPONENT_MON1_NAME: // link first opponent poke name case B_TXT_LINK_OPPONENT_MON1_NAME: // link first opponent poke name
GetMonData(&gEnemyParty[gBattlerPartyIndexes[gLinkPlayers[multiplayerId].id ^ 1]], GetBattlerNick(gLinkPlayers[multiplayerId].id ^ 1, text);
MON_DATA_NICKNAME, text);
StringGetEnd10(text);
toCpy = text; toCpy = text;
break; break;
case B_TXT_LINK_PLAYER_MON2_NAME: // link second player poke name case B_TXT_LINK_PLAYER_MON2_NAME: // link second player poke name
GetMonData(&gPlayerParty[gBattlerPartyIndexes[gLinkPlayers[multiplayerId].id ^ 2]], GetBattlerNick(gLinkPlayers[multiplayerId].id ^ 2, text);
MON_DATA_NICKNAME, text);
StringGetEnd10(text);
toCpy = text; toCpy = text;
break; break;
case B_TXT_LINK_OPPONENT_MON2_NAME: // link second opponent poke name case B_TXT_LINK_OPPONENT_MON2_NAME: // link second opponent poke name
GetMonData(&gEnemyParty[gBattlerPartyIndexes[gLinkPlayers[multiplayerId].id ^ 3]], GetBattlerNick(gLinkPlayers[multiplayerId].id ^ 3, text);
MON_DATA_NICKNAME, text);
StringGetEnd10(text);
toCpy = text; toCpy = text;
break; break;
case B_TXT_ATK_NAME_WITH_PREFIX_MON1: // attacker name with prefix, only battlerId 0/1 case B_TXT_ATK_NAME_WITH_PREFIX_MON1: // Unused, to change into sth else.
HANDLE_NICKNAME_STRING_CASE(gBattlerAttacker,
gBattlerPartyIndexes[GetBattlerAtPosition(GET_BATTLER_SIDE(gBattlerAttacker))])
break; break;
case B_TXT_ATK_PARTNER_NAME: // attacker partner name case B_TXT_ATK_PARTNER_NAME: // attacker partner name
if (GetBattlerSide(gBattlerAttacker) == B_SIDE_PLAYER) GetBattlerNick(BATTLE_PARTNER(gBattlerAttacker), text);
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);
toCpy = text; toCpy = text;
break; break;
case B_TXT_ATK_NAME_WITH_PREFIX: // attacker name with prefix case B_TXT_ATK_NAME_WITH_PREFIX: // attacker name with prefix
HANDLE_NICKNAME_STRING_CASE(gBattlerAttacker, gBattlerPartyIndexes[gBattlerAttacker]) HANDLE_NICKNAME_STRING_CASE(gBattlerAttacker)
break; break;
case B_TXT_DEF_NAME_WITH_PREFIX: // target name with prefix case B_TXT_DEF_NAME_WITH_PREFIX: // target name with prefix
HANDLE_NICKNAME_STRING_CASE(gBattlerTarget, gBattlerPartyIndexes[gBattlerTarget]) HANDLE_NICKNAME_STRING_CASE(gBattlerTarget)
break; break;
case B_TXT_DEF_NAME: // target name case B_TXT_DEF_NAME: // target name
if (GetBattlerSide(gBattlerTarget) == B_SIDE_PLAYER) GetBattlerNick(gBattlerTarget, text);
GetMonData(&gPlayerParty[gBattlerPartyIndexes[gBattlerTarget]], MON_DATA_NICKNAME, text);
else
GetMonData(&gEnemyParty[gBattlerPartyIndexes[gBattlerTarget]], MON_DATA_NICKNAME, text);
StringGetEnd10(text);
toCpy = text; toCpy = text;
break; break;
case B_TXT_EFF_NAME_WITH_PREFIX: // effect battlerId name with prefix 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; break;
case B_TXT_ACTIVE_NAME_WITH_PREFIX: // active battlerId name with prefix 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; break;
case B_TXT_SCR_ACTIVE_NAME_WITH_PREFIX: // scripting active battlerId name with prefix 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; break;
case B_TXT_CURRENT_MOVE: // current move name case B_TXT_CURRENT_MOVE: // current move name
if (gBattleMsgDataPtr->currentMove >= MOVES_COUNT) if (gBattleMsgDataPtr->currentMove >= MOVES_COUNT)
@ -3055,7 +3040,26 @@ u32 BattleStringExpandPlaceholders(const u8 *src, u8 *dst)
} }
break; break;
case B_TXT_26: // ? 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; break;
case B_TXT_PC_CREATOR_NAME: // lanette pc case B_TXT_PC_CREATOR_NAME: // lanette pc
if (FlagGet(FLAG_SYS_PC_LANETTE)) if (FlagGet(FLAG_SYS_PC_LANETTE))
@ -3287,11 +3291,18 @@ static void ExpandBattleTextBuffPlaceholders(const u8 *src, u8 *dst)
srcID += 3; srcID += 3;
break; break;
case B_BUFF_MON_NICK: // poke nick without prefix case B_BUFF_MON_NICK: // poke nick without prefix
if (GetBattlerSide(src[srcID + 1]) == B_SIDE_PLAYER) if (src[srcID + 2] == gBattlerPartyIndexes[src[srcID + 1]])
GetMonData(&gPlayerParty[src[srcID + 2]], MON_DATA_NICKNAME, dst); {
GetBattlerNick(src[srcID + 1], dst);
}
else else
GetMonData(&gEnemyParty[src[srcID + 2]], MON_DATA_NICKNAME, dst); {
StringGetEnd10(dst); 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; srcID += 3;
break; break;
case B_BUFF_NEGATIVE_FLAVOR: // flavor table 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 if (gBattlescriptCurrInstr[2] == B_ANIM_STATS_CHANGE
|| gBattlescriptCurrInstr[2] == B_ANIM_SNATCH_MOVE || gBattlescriptCurrInstr[2] == B_ANIM_SNATCH_MOVE
|| gBattlescriptCurrInstr[2] == B_ANIM_MEGA_EVOLUTION || gBattlescriptCurrInstr[2] == B_ANIM_MEGA_EVOLUTION
|| gBattlescriptCurrInstr[2] == B_ANIM_ILLUSION_OFF
|| gBattlescriptCurrInstr[2] == B_ANIM_SUBSTITUTE_FADE) || gBattlescriptCurrInstr[2] == B_ANIM_SUBSTITUTE_FADE)
{ {
BtlController_EmitBattleAnimation(0, gBattlescriptCurrInstr[2], *argumentPtr); 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 if (*animationIdPtr == B_ANIM_STATS_CHANGE
|| *animationIdPtr == B_ANIM_SNATCH_MOVE || *animationIdPtr == B_ANIM_SNATCH_MOVE
|| *animationIdPtr == B_ANIM_MEGA_EVOLUTION || *animationIdPtr == B_ANIM_MEGA_EVOLUTION
|| *animationIdPtr == B_ANIM_ILLUSION_OFF
|| *animationIdPtr == B_ANIM_SUBSTITUTE_FADE) || *animationIdPtr == B_ANIM_SUBSTITUTE_FADE)
{ {
BtlController_EmitBattleAnimation(0, *animationIdPtr, *argumentPtr); BtlController_EmitBattleAnimation(0, *animationIdPtr, *argumentPtr);
@ -6570,10 +6572,9 @@ u32 IsFlowerVeilProtected(u32 battler)
static void atk76_various(void) static void atk76_various(void)
{ {
struct Pokemon *mon; struct Pokemon *mon;
u8 side;
s32 i, j; s32 i, j;
u8 data[10]; u8 data[10];
u32 bits; u32 side, bits;
if (gBattleControllerExecFlags) if (gBattleControllerExecFlags)
return; return;
@ -6600,6 +6601,26 @@ static void atk76_various(void)
case VARIOUS_TRACE_ABILITY: case VARIOUS_TRACE_ABILITY:
gBattleMons[gActiveBattler].ability = gBattleStruct->tracedAbility[gActiveBattler]; gBattleMons[gActiveBattler].ability = gBattleStruct->tracedAbility[gActiveBattler];
break; 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: case VARIOUS_JUMP_IF_NOT_BERRY:
if (ItemId_GetPocket(gBattleMons[gActiveBattler].item) == POCKET_BERRIES) if (ItemId_GetPocket(gBattleMons[gActiveBattler].item) == POCKET_BERRIES)
gBattlescriptCurrInstr += 7; gBattlescriptCurrInstr += 7;

View File

@ -9,6 +9,7 @@
#include "constants/moves.h" #include "constants/moves.h"
#include "constants/hold_effects.h" #include "constants/hold_effects.h"
#include "constants/battle_anim.h" #include "constants/battle_anim.h"
#include "party_menu.h"
#include "pokemon.h" #include "pokemon.h"
#include "constants/species.h" #include "constants/species.h"
#include "item.h" #include "item.h"
@ -3423,6 +3424,14 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u8 ability, u8 special, u16 moveA
effect++; effect++;
} }
break; 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; break;
case ABILITYEFFECT_IMMUNITY: // 5 case ABILITYEFFECT_IMMUNITY: // 5
@ -6241,3 +6250,56 @@ bool32 CanBattlerGetOrLoseItem(u8 battlerId, u16 itemId)
else else
return TRUE; 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) static void Task_DoPokeballSendOutAnim(u8 taskId)
{ {
u16 throwCaseId; u32 throwCaseId, ballId, battlerId, ballSpriteId;
u8 battlerId; bool32 notSendOut = FALSE;
u16 itemId, ballId;
u8 ballSpriteId;
bool8 notSendOut = FALSE;
if (gTasks[taskId].tFrames == 0) if (gTasks[taskId].tFrames == 0)
{ {
@ -356,13 +353,7 @@ static void Task_DoPokeballSendOutAnim(u8 taskId)
throwCaseId = gTasks[taskId].tThrowId; throwCaseId = gTasks[taskId].tThrowId;
battlerId = gTasks[taskId].tBattler; battlerId = gTasks[taskId].tBattler;
ballId = ItemIdToBallId(GetBattlerPokeballItemId(battlerId));
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);
LoadBallGfx(ballId); LoadBallGfx(ballId);
ballSpriteId = CreateSprite(&gBallSpriteTemplates[ballId], 32, 80, 29); ballSpriteId = CreateSprite(&gBallSpriteTemplates[ballId], 32, 80, 29);
gSprites[ballSpriteId].data[0] = 0x80; gSprites[ballSpriteId].data[0] = 0x80;
@ -743,8 +734,7 @@ static void SpriteCB_ReleaseMonFromBall(struct Sprite *sprite)
if (gMain.inBattle) if (gMain.inBattle)
{ {
struct Pokemon *mon; struct Pokemon *mon, *illusionMon;
u16 species;
s8 pan; s8 pan;
u16 wantedCryCase; u16 wantedCryCase;
u8 taskId; u8 taskId;
@ -760,7 +750,6 @@ static void SpriteCB_ReleaseMonFromBall(struct Sprite *sprite)
pan = -25; pan = -25;
} }
species = GetMonData(mon, MON_DATA_SPECIES);
if ((battlerId == GetBattlerAtPosition(B_POSITION_PLAYER_LEFT) || battlerId == GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT)) if ((battlerId == GetBattlerAtPosition(B_POSITION_PLAYER_LEFT) || battlerId == GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT))
&& IsDoubleBattle() && gBattleSpritesDataPtr->animationData->field_9_x1) && IsDoubleBattle() && gBattleSpritesDataPtr->animationData->field_9_x1)
{ {
@ -783,9 +772,14 @@ static void SpriteCB_ReleaseMonFromBall(struct Sprite *sprite)
wantedCryCase = 2; wantedCryCase = 2;
gBattleSpritesDataPtr->healthBoxesData[battlerId].field_1_x40 = 1; gBattleSpritesDataPtr->healthBoxesData[battlerId].field_1_x40 = 1;
taskId = CreateTask(Task_PlayCryWhenReleasedFromBall, 3); 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].tCryTaskPan = pan;
gTasks[taskId].tCryTaskWantedCry = wantedCryCase; gTasks[taskId].tCryTaskWantedCry = wantedCryCase;
gTasks[taskId].tCryTaskBattler = battlerId; gTasks[taskId].tCryTaskBattler = battlerId;
@ -1269,8 +1263,16 @@ void FreeBallGfx(u8 ballId)
static u16 GetBattlerPokeballItemId(u8 battlerId) static u16 GetBattlerPokeballItemId(u8 battlerId)
{ {
struct Pokemon *mon, *illusionMon;
if (GetBattlerSide(battlerId) == B_SIDE_PLAYER) if (GetBattlerSide(battlerId) == B_SIDE_PLAYER)
return GetMonData(&gPlayerParty[gBattlerPartyIndexes[battlerId]], MON_DATA_POKEBALL); mon = &gPlayerParty[gBattlerPartyIndexes[battlerId]];
else 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);
} }