Mega Evolution support is mostly done.

This commit is contained in:
DizzyEggg 2018-09-16 18:55:32 +02:00
parent 33b6ec8c0a
commit 55f21c1776
20 changed files with 162 additions and 18 deletions

View File

@ -1473,6 +1473,10 @@
.4byte \ptr
.endm
.macro handlemegaevo battler
various \battler, VARIOUS_HANDLE_MEGA_EVO
.endm
@ helpful macros
.macro setstatchanger stat, stages, down
setbyte sSTATCHANGER \stat | \stages << 4 | \down << 7

View File

@ -672,6 +672,7 @@ gBattleAnims_VariousTable:: @ 82C9320
.4byte Anim_Table_x14
.4byte Status_Ingrain
.4byte Anim_WishHeal
.4byte General_MegaEvolution
.align 2
gBattleAnims_Special:: @ 82C937C
@ -12054,6 +12055,9 @@ Anim_WishHeal:
waitforvisualfinish
createsprite gUnknown_08597274, 0x2, 1, 3, 10, 0, 0
end
General_MegaEvolution:
end
AnimScript_82D85A3:
createvisualtask sub_8172E9C, 0x2

View File

@ -4610,6 +4610,16 @@ BattleScript_FocusPunchSetUp::
printstring STRINGID_PKMNTIGHTENINGFOCUS
waitmessage 0x40
end2
BattleScript_MegaEvolution::
printstring STRINGID_MEGAEVOREACTING
waitmessage 0x40
playanimation BS_ATTACKER, B_ANIM_MEGA_EVOLUTION, NULL
waitanimation
handlemegaevo BS_ATTACKER
printstring STRINGID_MEGAEVOEVOLVED
waitmessage 0x40
end2
BattleScript_MoveUsedIsAsleep::
printstring STRINGID_PKMNFASTASLEEP

View File

@ -598,6 +598,11 @@ struct BattleStruct
bool8 ateBoost[MAX_BATTLERS_COUNT];
u32 debugAIFlags;
bool8 notfirstTimeAIFlags;
u8 toMegaEvolve; // As flags using gBitTable.
u8 megaEvolvedPartyIds[2]; // As flags using gBitTable;
bool8 alreadyMegaEvolved[4]; // Array id is used for mon position.
u16 speciesToMegaEvolve[MAX_BATTLERS_COUNT];
u8 megaEvoBattlerId;
};
#define GET_MOVE_TYPE(move, typeArg) \

View File

@ -84,6 +84,7 @@ enum
// Special return values in gBattleBufferB from Battle Controller functions.
#define RET_VALUE_LEVELED_UP 11
#define RET_MEGA_EVOLUTION 0x80
struct UnusedControllerStruct
{

View File

@ -271,5 +271,6 @@ extern const u8 BattleScript_SelectingNotAllowedMoveHealBlockInPalace[];
extern const u8 BattleScript_ToxicSpikesFree[];
extern const u8 BattleScript_StickyWebFree[];
extern const u8 BattleScript_StealthRockFree[];
extern const u8 BattleScript_MegaEvolution[];
#endif // GUARD_BATTLE_SCRIPTS_H

View File

@ -88,5 +88,6 @@ u16 CalcTypeEffectivenessMultiplier(u16 move, u8 moveType, u8 battlerAtk, u8 bat
u16 CalcPartyMonTypeEffectivenessMultiplier(u16 move, u16 speciesDef, u8 abilityDef);
u16 GetTypeModifier(u8 atkType, u8 defType);
s32 GetStealthHazardDamage(u8 hazardType, u8 battlerId);
bool32 CanMegaEvolve(u8 battlerId);
#endif // GUARD_BATTLE_UTIL_H

View File

@ -60,6 +60,7 @@
#define B_ANIM_x14 0x14
#define B_ANIM_INGRAIN_HEAL 0x15
#define B_ANIM_WISH_HEAL 0x16
#define B_ANIM_MEGA_EVOLUTION 0x17
// special animations table
#define B_ANIM_LVL_UP 0x0

View File

@ -99,6 +99,7 @@
#define VARIOUS_TRY_ELECTRIFY 48
#define VARIOUS_TRY_REFLECT_TYPE 49
#define VARIOUS_TRY_SOAK 50
#define VARIOUS_HANDLE_MEGA_EVO 51
// atk80, dmg manipulation
#define ATK80_DMG_CHANGE_SIGN 0

View File

@ -502,6 +502,8 @@
#define STRINGID_TERRAINBECOMESELECTRIC 499
#define STRINGID_TERRAINBECOMESPSYCHIC 500
#define STRINGID_TARGETELECTRIFIED 501
#define STRINGID_MEGAEVOREACTING 502
#define STRINGID_MEGAEVOEVOLVED 503
#define BATTLESTRINGS_COUNT 516

View File

@ -109,6 +109,7 @@
// Gen6 hold effects
#define HOLD_EFFECT_FAIRY_POWER 130
#define HOLD_EFFECT_MEGA_STONE 131
// Gen7 hold effects
#define HOLD_EFFECT_PROTECTIVE_PADS 150

View File

@ -239,7 +239,7 @@
#define ITEM_METAL_POWDER 223
#define ITEM_THICK_CLUB 224
#define ITEM_STICK 225
#define ITEM_0E2 226
#define ITEM_MEGA_STONE_TESTING 226
#define ITEM_0E3 227
#define ITEM_0E4 228
#define ITEM_0E5 229

View File

@ -422,6 +422,8 @@ enum
#define EVO_LEVEL_SHEDINJA 0x000e // Pokémon reaches the specified level (special value for Shedinja)
#define EVO_BEAUTY 0x000f // Pokémon levels up with beauty ≥ specified value
#define EVO_MEGA_EVOLUTION 0xffff // Not an actual evolution, used to temporarily mega evolve in battle.
struct Evolution
{
u16 method;

View File

@ -1548,16 +1548,15 @@ static void OpponentHandleChooseMove(void)
if (gBattleTypeFlags & (BATTLE_TYPE_TRAINER | BATTLE_TYPE_FIRST_BATTLE | BATTLE_TYPE_SAFARI | BATTLE_TYPE_ROAMER))
{
BattleAI_SetupAIData(0xF);
chosenMoveId = BattleAI_ChooseMoveOrAction();
switch (chosenMoveId)
{
case 5:
case AI_CHOICE_WATCH:
BtlController_EmitTwoReturnValues(1, B_ACTION_SAFARI_WATCH_CAREFULLY, 0);
break;
case 4:
case AI_CHOICE_FLEE:
BtlController_EmitTwoReturnValues(1, B_ACTION_RUN, 0);
break;
case 6:
@ -1572,7 +1571,10 @@ static void OpponentHandleChooseMove(void)
if (gAbsentBattlerFlags & gBitTable[gBattlerTarget])
gBattlerTarget = GetBattlerAtPosition(B_POSITION_PLAYER_RIGHT);
}
BtlController_EmitTwoReturnValues(1, 10, (chosenMoveId) | (gBattlerTarget << 8));
if (CanMegaEvolve(gActiveBattler)) // If opponent can mega evolve, do it.
BtlController_EmitTwoReturnValues(1, 10 | RET_MEGA_EVOLUTION, (chosenMoveId) | (gBattlerTarget << 8));
else
BtlController_EmitTwoReturnValues(1, 10, (chosenMoveId) | (gBattlerTarget << 8));
break;
}
OpponentBufferExecCompleted();

View File

@ -166,6 +166,7 @@ static void SetActionsAndBattlersTurnOrder(void);
static void sub_803CDF8(void);
static bool8 AllAtActionConfirmed(void);
static void CheckFocusPunch_ClearVarsBeforeTurnStarts(void);
static void CheckMegaEvolutionBeforeTurn(void);
static void FreeResetData_ReturnToOvOrDoEvolutions(void);
static void ReturnFromBattleToOverworld(void);
static void TryEvolvePokemon(void);
@ -4375,9 +4376,12 @@ static void HandleTurnActionSelectionState(void)
case STATE_WAIT_ACTION_CASE_CHOSEN:
if (!(gBattleControllerExecFlags & ((gBitTable[gActiveBattler]) | (0xF0000000) | (gBitTable[gActiveBattler] << 4) | (gBitTable[gActiveBattler] << 8) | (gBitTable[gActiveBattler] << 0xC))))
{
bool32 shouldMegaEvolve;
switch (gChosenActionByBattler[gActiveBattler])
{
case B_ACTION_USE_MOVE:
shouldMegaEvolve = gBattleBufferB[gActiveBattler][1] & RET_MEGA_EVOLUTION;
gBattleBufferB[gActiveBattler][1] &= ~(RET_MEGA_EVOLUTION);
switch (gBattleBufferB[gActiveBattler][1])
{
case 3:
@ -4419,6 +4423,8 @@ static void HandleTurnActionSelectionState(void)
*(gBattleStruct->chosenMovePositions + gActiveBattler) = gBattleBufferB[gActiveBattler][2];
gChosenMoveByBattler[gActiveBattler] = gBattleMons[gActiveBattler].moves[*(gBattleStruct->chosenMovePositions + gActiveBattler)];
*(gBattleStruct->moveTarget + gActiveBattler) = gBattleBufferB[gActiveBattler][3];
if (shouldMegaEvolve)
gBattleStruct->toMegaEvolve |= gBitTable[gActiveBattler];
gBattleCommunication[gActiveBattler]++;
}
break;
@ -4844,8 +4850,8 @@ static void SetActionsAndBattlersTurnOrder(void)
turnOrderId++;
}
}
gBattleMainFunc = CheckFocusPunch_ClearVarsBeforeTurnStarts;
gBattleStruct->focusPunchBattlerId = 0;
gBattleMainFunc = CheckMegaEvolutionBeforeTurn;
gBattleStruct->megaEvoBattlerId = 0;
return;
}
else
@ -4886,8 +4892,8 @@ static void SetActionsAndBattlersTurnOrder(void)
}
}
}
gBattleMainFunc = CheckFocusPunch_ClearVarsBeforeTurnStarts;
gBattleStruct->focusPunchBattlerId = 0;
gBattleMainFunc = CheckMegaEvolutionBeforeTurn;
gBattleStruct->megaEvoBattlerId = 0;
}
static void TurnValuesCleanUp(bool8 var0)
@ -4939,6 +4945,29 @@ static void SpecialStatusesClear(void)
}
}
static void CheckMegaEvolutionBeforeTurn(void)
{
if (!(gHitMarker & HITMARKER_RUN))
{
while (gBattleStruct->megaEvoBattlerId < gBattlersCount)
{
gActiveBattler = gBattlerAttacker = gBattleStruct->megaEvoBattlerId;
gBattleStruct->megaEvoBattlerId++;
if (gBattleStruct->toMegaEvolve & gBitTable[gActiveBattler]
&& !(gProtectStructs[gActiveBattler].noValidMoves))
{
gBattleStruct->toMegaEvolve &= ~(gBitTable[gActiveBattler]);
gLastUsedItem = gBattleMons[gActiveBattler].item;
BattleScriptExecute(BattleScript_MegaEvolution);
return;
}
}
}
gBattleMainFunc = CheckFocusPunch_ClearVarsBeforeTurnStarts;
gBattleStruct->focusPunchBattlerId = 0;
}
static void CheckFocusPunch_ClearVarsBeforeTurnStarts(void)
{
u32 i;

View File

@ -631,8 +631,6 @@ static const u8 sText_NotDoneYet[] = _("This move effect is not done yet!\p");
static const u8 sText_PkmnBlewAwayToxicSpikes[] = _("{B_ATK_NAME_WITH_PREFIX} blew away\nTOXIC SPIKES!");
static const u8 sText_PkmnBlewAwayStickyWeb[] = _("{B_ATK_NAME_WITH_PREFIX} blew away\nSTICKY WEB!");
static const u8 sText_PkmnBlewAwayStealthRock[] = _("{B_ATK_NAME_WITH_PREFIX} blew away\nSTEALTH ROCK!");
// To do.
static const u8 sText_StickyWebUsed[] = _("A sticky web spreads out on the\nground around your team!");
static const u8 sText_QuashSuccess[] = _("The opposing {B_ATK_NAME_WITH_PREFIX}s move was postponed!");
static const u8 sText_IonDelugeOn[] = _("A deluge of ions showers\nthe battlefield!");
@ -642,12 +640,11 @@ static const u8 sText_TerrainBecomesGrassy[] = _("Grass grew to cover\nthe battl
static const u8 sText_TerrainBecomesElectric[] = _("An electric current runs across\nthe battlefield!");
static const u8 sText_TerrainBecomesPsychic[] = _("The battlefield got weird!");
static const u8 sText_TargetElectrified[] = _("The opposing {B_ATK_NAME_WITH_PREFIX}s moves\nhave been electrified!");
// New selection strings, they must end with "\p".
// Use {B_LAST_ITEM} and {B_CURRENT_MOVE}.
static const u8 sText_AssaultVestDoesntAllow[] = _("The effects of the {B_LAST_ITEM} prevent status\nmoves from being used!\p");
static const u8 sText_GravityPreventsUsage[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX} cant use {B_CURRENT_MOVE}\nbecause of gravity!\p");
static const u8 sText_HealBlockPreventsUsage[] = _("The opposing {B_ATK_NAME_WITH_PREFIX} was\nprevented from healing!\p");
static const u8 sText_MegaEvoReacting[] = _("{B_ATK_NAME_WITH_PREFIX}s {B_LAST_ITEM} is reacting\nto {B_ATK_TRAINER_NAME}s Mega Ring!");
static const u8 sText_MegaEvoEvolved[] = _("{B_ATK_NAME_WITH_PREFIX} has Mega\nEvolved into Mega {B_BUFF1}!");
const u8 *const gBattleStringsTable[BATTLESTRINGS_COUNT] =
{
@ -1142,6 +1139,8 @@ const u8 *const gBattleStringsTable[BATTLESTRINGS_COUNT] =
sText_TerrainBecomesElectric,
sText_TerrainBecomesPsychic,
sText_TargetElectrified,
sText_MegaEvoReacting,
sText_MegaEvoEvolved,
};
const u16 gTerrainStringIds[] =

View File

@ -6119,6 +6119,7 @@ static void HandleTerrainMove(u32 moveEffect)
static void atk76_various(void)
{
struct Pokemon *mon;
u8 side;
s32 i, j;
u8 data[10];
@ -6588,6 +6589,28 @@ static void atk76_various(void)
gBattlescriptCurrInstr += 7;
}
return;
case VARIOUS_HANDLE_MEGA_EVO:
if (GetBattlerSide(gActiveBattler) == B_SIDE_OPPONENT)
mon = &gEnemyParty[gBattlerPartyIndexes[gActiveBattler]];
else
mon = &gPlayerParty[gBattlerPartyIndexes[gActiveBattler]];
gBattleMons[gActiveBattler].species = gBattleStruct->speciesToMegaEvolve[gActiveBattler];
SetMonData(mon, MON_DATA_SPECIES, &gBattleMons[gActiveBattler].species);
PREPARE_SPECIES_BUFFER(gBattleTextBuff1, gBattleMons[gActiveBattler].species);
CalculateMonStats(mon);
gBattleMons[gActiveBattler].hp = GetMonData(mon, MON_DATA_HP);
gBattleMons[gActiveBattler].maxHP = GetMonData(mon, MON_DATA_MAX_HP);
gBattleMons[gActiveBattler].attack = GetMonData(mon, MON_DATA_ATK);
gBattleMons[gActiveBattler].defense = GetMonData(mon, MON_DATA_DEF);
gBattleMons[gActiveBattler].speed = GetMonData(mon, MON_DATA_SPEED);
gBattleMons[gActiveBattler].spAttack = GetMonData(mon, MON_DATA_SPATK);
gBattleMons[gActiveBattler].spDefense = GetMonData(mon, MON_DATA_SPDEF);
UpdateHealthboxAttribute(gHealthboxSpriteIds[gActiveBattler], mon, HEALTHBOX_ALL);
gBattleStruct->alreadyMegaEvolved[GetBattlerPosition(gActiveBattler)] = TRUE;
gBattleStruct->megaEvolvedPartyIds[GetBattlerSide(gActiveBattler)] |= gBitTable[gBattlerPartyIndexes[gActiveBattler]];
break;
}
gBattlescriptCurrInstr += 3;

View File

@ -5572,3 +5572,60 @@ s32 GetStealthHazardDamage(u8 hazardType, u8 battlerId)
return dmg;
}
static bool32 IsPartnerMonFromSameTrainer(u8 battlerId)
{
if (GetBattlerSide(battlerId) == B_SIDE_OPPONENT && gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS)
return FALSE;
else if (GetBattlerSide(battlerId) == B_SIDE_PLAYER && gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER)
return FALSE;
else if (gBattleTypeFlags & BATTLE_TYPE_MULTI)
return FALSE;
else
return TRUE;
}
bool32 CanMegaEvolve(u8 battlerId)
{
u32 i;
u16 species, itemId;
u8 battlerPosition = GetBattlerPosition(battlerId);
u8 partnerPosition = GetBattlerPosition(BATTLE_PARTNER(battlerId));
// Check if trainer already mega evolved a pokemon.
if (gBattleStruct->alreadyMegaEvolved[battlerPosition])
return FALSE;
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE)
{
if (IsPartnerMonFromSameTrainer(battlerId) && gBattleStruct->alreadyMegaEvolved[partnerPosition])
return FALSE;
}
else
{
if (gBattleStruct->alreadyMegaEvolved[partnerPosition])
return FALSE;
}
// Check if the pokemon holds an appropriate item,
if (GetBattlerHoldEffect(battlerId, FALSE) != HOLD_EFFECT_MEGA_STONE)
return FALSE;
// Check if there is an entry in the evolution table.
species = gBattleMons[battlerId].species;
itemId = gBattleMons[battlerId].item;
for (i = 0; i < EVOS_PER_MON; i++)
{
if (gEvolutionTable[species][i].method == EVO_MEGA_EVOLUTION
&& gEvolutionTable[species][i].param == itemId)
{
gBattleStruct->speciesToMegaEvolve[battlerId] = gEvolutionTable[species][i].targetSpecies;
break;
}
}
if (i == EVOS_PER_MON)
return FALSE;
// All checks passed, the mon CAN mega evolve.
return TRUE;
}

View File

@ -3649,10 +3649,10 @@ const struct Item gItems[] =
.secondaryId = 0,
},
{
.name = _("????????"),
.itemId = ITEM_NONE,
.name = _("Mega Stone"),
.itemId = ITEM_MEGA_STONE_TESTING,
.price = 0,
.holdEffect = HOLD_EFFECT_NONE,
.holdEffect = HOLD_EFFECT_MEGA_STONE,
.holdEffectParam = 0,
.description = gDummyItemDescription,
.importance = 0,

View File

@ -173,7 +173,8 @@ const struct Evolution gEvolutionTable[NUM_SPECIES][EVOS_PER_MON] =
[SPECIES_VIGOROTH] = {{EVO_LEVEL, 36, SPECIES_SLAKING}},
[SPECIES_GULPIN] = {{EVO_LEVEL, 26, SPECIES_SWALOT}},
[SPECIES_WHISMUR] = {{EVO_LEVEL, 20, SPECIES_LOUDRED}},
[SPECIES_LOUDRED] = {{EVO_LEVEL, 40, SPECIES_EXPLOUD}},
[SPECIES_LOUDRED] = {{EVO_LEVEL, 40, SPECIES_EXPLOUD},
{EVO_MEGA_EVOLUTION, ITEM_MEGA_STONE_TESTING, SPECIES_HO_OH}},
[SPECIES_CLAMPERL] = {{EVO_TRADE_ITEM, ITEM_DEEP_SEA_TOOTH, SPECIES_HUNTAIL},
{EVO_TRADE_ITEM, ITEM_DEEP_SEA_SCALE, SPECIES_GOREBYSS}},
[SPECIES_SHUPPET] = {{EVO_LEVEL, 37, SPECIES_BANETTE}},