Move Weather Ball, Hidden power, AI support for dynamic type moves and AI debug support

This commit is contained in:
DizzyEggg 2018-07-29 11:32:40 +02:00
parent ec9693c797
commit d628d1f5fd
10 changed files with 168 additions and 94 deletions

View File

@ -958,7 +958,7 @@
.4byte \param0
.endm
.macro hiddenpowercalc
.macro nop_C1
.byte 0xc1
.endm
@ -1148,7 +1148,7 @@
.4byte \param0
.endm
.macro setweatherballtype
.macro nop_E9
.byte 0xe9
.endm

View File

@ -623,6 +623,8 @@ BattleScript_EffectRetalitate:
BattleScript_EffectBulldoze:
BattleScript_EffectFoulPlay:
BattleScript_EffectPsyshock:
BattleScript_EffectWeatherBall:
BattleScript_EffectHiddenPower:
jumpifnotmove MOVE_SURF, BattleScript_HitFromAtkCanceler
jumpifnostatus3 BS_TARGET, STATUS3_UNDERWATER, BattleScript_HitFromAtkCanceler
orword gHitMarker, HITMARKER_IGNORE_UNDERWATER
@ -2157,10 +2159,6 @@ BattleScript_EffectMoonlight::
recoverbasedonsunlight BattleScript_AlreadyAtFullHp
goto BattleScript_PresentHealTarget
BattleScript_EffectHiddenPower::
hiddenpowercalc
goto BattleScript_EffectHit
BattleScript_EffectRainDance::
attackcanceler
attackstring
@ -3024,10 +3022,6 @@ BattleScript_EffectPoisonFang::
setmoveeffect MOVE_EFFECT_TOXIC
goto BattleScript_EffectHit
BattleScript_EffectWeatherBall::
setweatherballtype
goto BattleScript_EffectHit
BattleScript_EffectOverheat::
setmoveeffect MOVE_EFFECT_SP_ATK_TWO_DOWN | MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_CERTAIN
goto BattleScript_EffectHit

View File

@ -594,6 +594,8 @@ struct BattleStruct
u8 roostTypes[MAX_BATTLERS_COUNT][3];
u8 savedBattlerTarget;
bool8 ateBoost[MAX_BATTLERS_COUNT];
u32 debugAIFlags;
bool8 notfirstTimeAIFlags;
};
#define GET_MOVE_TYPE(move, typeArg) \

View File

@ -70,6 +70,7 @@ u8 GetWhoStrikesFirst(u8 battlerId1, u8 battlerId2, bool8 ignoreChosenMoves);
void RunBattleScriptCommands_PopCallbacksStack(void);
void RunBattleScriptCommands(void);
bool8 TryRunFromBattle(u8 battlerId);
void SetTypeBeforeUsingMove(u16 move, u8 battlerAtk);
extern const u8 gTypeEffectiveness[336];
extern const u8 gTypeNames[][TYPE_NAME_LENGTH + 1];

View File

@ -157,6 +157,7 @@
#define STATUS3_HEAL_BLOCK 0x8000000
#define STATUS3_AQUA_RING 0x10000000
#define STATUS3_LASER_FOCUS 0x20000000
#define STATUS3_ELECTRIFIED 0x40000000
#define STATUS3_SEMI_INVULNERABLE (STATUS3_UNDERGROUND | STATUS3_ON_AIR | STATUS3_UNDERWATER)
// Not really sure what a "hitmarker" is.

View File

@ -360,6 +360,8 @@ void BattleAI_SetupAIData(u8 defaultScoreMoves)
}
// Choose proper trainer ai scripts.
if (!gBattleStruct->notfirstTimeAIFlags || !USE_BATTLE_DEBUG)
{
if (gBattleTypeFlags & BATTLE_TYPE_RECORDED)
AI_THINKING_STRUCT->aiFlags = GetAiScriptsInRecordedBattle();
else if (gBattleTypeFlags & BATTLE_TYPE_SAFARI)
@ -378,7 +380,15 @@ void BattleAI_SetupAIData(u8 defaultScoreMoves)
AI_THINKING_STRUCT->aiFlags = gTrainers[gTrainerBattleOpponent_A].aiFlags;
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE)
AI_THINKING_STRUCT->aiFlags |= AI_SCRIPT_DOUBLE_BATTLE; // act smart in doubles and don't attack your partner
AI_THINKING_STRUCT->aiFlags |= AI_SCRIPT_DOUBLE_BATTLE; // Act smart in doubles and don't attack your partner.
gBattleStruct->debugAIFlags = AI_THINKING_STRUCT->aiFlags;
gBattleStruct->notfirstTimeAIFlags = TRUE;
}
else
{
AI_THINKING_STRUCT->aiFlags = gBattleStruct->debugAIFlags;
}
}
u8 BattleAI_ChooseMoveOrAction(void)
@ -764,7 +774,7 @@ static bool32 AI_GetIfCrit(u32 move, u8 battlerAtk, u8 battlerDef)
s32 AI_CalcDamage(u16 move, u8 battlerAtk, u8 battlerDef)
{
s32 dmg;
s32 dmg, moveType;
SaveBattlerData(battlerAtk);
SaveBattlerData(battlerDef);
@ -772,7 +782,10 @@ s32 AI_CalcDamage(u16 move, u8 battlerAtk, u8 battlerDef)
SetBattlerData(battlerAtk);
SetBattlerData(battlerDef);
dmg = CalculateMoveDamage(move, battlerAtk, battlerDef, gBattleMoves[move].type, 0, AI_GetIfCrit(move, battlerAtk, battlerDef), FALSE);
gBattleStruct->dynamicMoveType = 0;
SetTypeBeforeUsingMove(move, battlerAtk);
GET_MOVE_TYPE(move, moveType);
dmg = CalculateMoveDamage(move, battlerAtk, battlerDef, moveType, 0, AI_GetIfCrit(move, battlerAtk, battlerDef), FALSE);
RestoreBattlerData(battlerAtk);
RestoreBattlerData(battlerDef);

View File

@ -84,7 +84,7 @@ enum
LIST_ITEM_STATUS2,
LIST_ITEM_STATUS3,
LIST_ITEM_SIDE_STATUS,
LIST_ITEM_VARIOUS,
LIST_ITEM_AI,
LIST_ITEM_COUNT
};
@ -179,6 +179,13 @@ static const u8 sText_PP[] = _("PP");
static const u8 sText_StealthRock[] = _("Stealth Rock");
static const u8 sText_ToxicSpikes[] = _("Toxic Spikes");
static const u8 sText_StickyWeb[] = _("Sticky Web");
static const u8 sText_AI[] = _("AI");
static const u8 sText_NoBadMoves[] = _("No Bad Moves");
static const u8 sText_Viability[] = _("Viability");
static const u8 sText_TryFaint[] = _("Try Faint");
static const u8 sText_SetUpFirstTurn[] = _("Setup 1 turn");
static const u8 sText_Risky[] = _("Risky");
static const u8 sText_StrongestMove[] = _("Most dmg move");
static const u8 sText_EmptyString[] = _("");
@ -245,6 +252,17 @@ static const struct BitfieldInfo sStatus3Bitfield[] =
{/*Aqua Ring*/ 1, 28},
};
static const struct BitfieldInfo sAIBitfield[] =
{
{/*Check bad move*/ 1, 0},
{/*Viability*/ 1, 1},
{/*Try To Faint*/ 1, 2},
{/*Set up first turn*/ 1, 3},
{/*Risky*/ 1, 4},
{/*Prefer Strongest Move*/ 1, 5},
};
static const struct ListMenuItem sMainListItems[] =
{
{sText_Moves, LIST_ITEM_MOVES},
@ -258,6 +276,17 @@ static const struct ListMenuItem sMainListItems[] =
{sText_Status2, LIST_ITEM_STATUS2},
{sText_Status3, LIST_ITEM_STATUS3},
{sText_SideStatus, LIST_ITEM_SIDE_STATUS},
{sText_AI, LIST_ITEM_AI},
};
static const struct ListMenuItem sAIListItems[] =
{
{sText_NoBadMoves, 0},
{sText_Viability, 1},
{sText_TryFaint, 2},
{sText_SetUpFirstTurn, 3},
{sText_Risky, 4},
{sText_StrongestMove, 5},
};
static const struct ListMenuItem sStatsListItems[] =
@ -818,6 +847,11 @@ static void CreateSecondaryListMenu(struct BattleDebugMenu *data)
itemsCount = ARRAY_COUNT(sStatus3ListItems);
data->bitfield = sStatus3Bitfield;
break;
case LIST_ITEM_AI:
listTemplate.items = sAIListItems;
itemsCount = ARRAY_COUNT(sAIListItems);
data->bitfield = sAIBitfield;
break;
case LIST_ITEM_SIDE_STATUS:
listTemplate.items = sSideStatusListItems;
itemsCount = ARRAY_COUNT(sSideStatusListItems);
@ -1245,6 +1279,11 @@ static void SetUpModifyArrows(struct BattleDebugMenu *data)
data->modifyArrows.currValue = GetBitfieldValue(gStatuses3[data->battlerId], data->bitfield[data->currentSecondaryListItemId].currBit, data->bitfield[data->currentSecondaryListItemId].bitsCount);
data->modifyArrows.typeOfVal = VAL_BITFIELD_32;
goto CASE_ITEM_STATUS;
case LIST_ITEM_AI:
data->modifyArrows.modifiedValPtr = &gBattleStruct->debugAIFlags;
data->modifyArrows.currValue = GetBitfieldValue(gBattleStruct->debugAIFlags, data->bitfield[data->currentSecondaryListItemId].currBit, data->bitfield[data->currentSecondaryListItemId].bitsCount);
data->modifyArrows.typeOfVal = VAL_BITFIELD_32;
goto CASE_ITEM_STATUS;
CASE_ITEM_STATUS:
data->modifyArrows.minValue = 0;
data->modifyArrows.maxValue = (1 << data->bitfield[data->currentSecondaryListItemId].bitsCount) - 1;

View File

@ -4936,6 +4936,8 @@ static void SpecialStatusesClear(void)
static void CheckFocusPunch_ClearVarsBeforeTurnStarts(void)
{
u32 i;
if (!(gHitMarker & HITMARKER_RUN))
{
while (gBattleStruct->focusPunchBattlerId < gBattlersCount)
@ -4957,6 +4959,8 @@ static void CheckFocusPunch_ClearVarsBeforeTurnStarts(void)
gCurrentTurnActionNumber = 0;
gCurrentActionFuncId = gActionsByTurnOrder[0];
gBattleStruct->dynamicMoveType = 0;
for (i = 0; i < MAX_BATTLERS_COUNT; i++)
gBattleStruct->ateBoost[i] = FALSE;
gBattleMainFunc = RunTurnActionsFunctions;
gBattleCommunication[3] = 0;
gBattleCommunication[4] = 0;
@ -5291,12 +5295,80 @@ void RunBattleScriptCommands(void)
gBattleScriptingCommandsTable[gBattlescriptCurrInstr[0]]();
}
void SetTypeBeforeUsingMove(u16 move, u8 battlerAtk)
{
u32 moveType, ateType, attackerAbility;
if (move == MOVE_STRUGGLE)
return;
if (gBattleMoves[move].effect == EFFECT_WEATHER_BALL)
{
if (WEATHER_HAS_EFFECT)
{
if (gBattleWeather & WEATHER_RAIN_ANY)
*(&gBattleStruct->dynamicMoveType) = TYPE_WATER | 0x80;
else if (gBattleWeather & WEATHER_SANDSTORM_ANY)
*(&gBattleStruct->dynamicMoveType) = TYPE_ROCK | 0x80;
else if (gBattleWeather & WEATHER_SUN_ANY)
*(&gBattleStruct->dynamicMoveType) = TYPE_FIRE | 0x80;
else if (gBattleWeather & WEATHER_HAIL_ANY)
*(&gBattleStruct->dynamicMoveType) = TYPE_ICE | 0x80;
else
*(&gBattleStruct->dynamicMoveType) = TYPE_NORMAL | 0x80;
}
}
else if (gBattleMoves[move].effect == EFFECT_HIDDEN_POWER)
{
u8 typeBits = ((gBattleMons[battlerAtk].hpIV & 1) << 0)
| ((gBattleMons[battlerAtk].attackIV & 1) << 1)
| ((gBattleMons[battlerAtk].defenseIV & 1) << 2)
| ((gBattleMons[battlerAtk].speedIV & 1) << 3)
| ((gBattleMons[battlerAtk].spAttackIV & 1) << 4)
| ((gBattleMons[battlerAtk].spDefenseIV & 1) << 5);
gBattleStruct->dynamicMoveType = (15 * typeBits) / 63 + 1;
if (gBattleStruct->dynamicMoveType >= TYPE_MYSTERY)
gBattleStruct->dynamicMoveType++;
gBattleStruct->dynamicMoveType |= 0xC0;
}
attackerAbility = GetBattlerAbility(battlerAtk);
GET_MOVE_TYPE(move, moveType);
if ((gFieldStatuses & STATUS_FIELD_ION_DELUGE && moveType == TYPE_NORMAL)
|| gStatuses3[battlerAtk] & STATUS3_ELECTRIFIED)
{
gBattleStruct->dynamicMoveType = 0x80 | TYPE_ELECTRIC;
}
else if (gBattleMoves[move].type == TYPE_NORMAL
&& gBattleMoves[move].effect != EFFECT_HIDDEN_POWER
&& gBattleMoves[move].effect != EFFECT_WEATHER_BALL
&& ((attackerAbility == ABILITY_PIXILATE && (ateType = TYPE_FAIRY))
|| (attackerAbility == ABILITY_REFRIGERATE && (ateType = TYPE_ICE))
|| (attackerAbility == ABILITY_AERILATE && (ateType = TYPE_FLYING))
|| ((attackerAbility == ABILITY_GALVANIZE) && (ateType = TYPE_ELECTRIC))
)
)
{
gBattleStruct->dynamicMoveType = 0x80 | ateType;
gBattleStruct->ateBoost[battlerAtk] = 1;
}
else if (gBattleMoves[move].type != TYPE_NORMAL
&& gBattleMoves[move].effect != EFFECT_HIDDEN_POWER
&& gBattleMoves[move].effect != EFFECT_WEATHER_BALL
&& attackerAbility == ABILITY_NORMALIZE)
{
gBattleStruct->dynamicMoveType = 0x80 | TYPE_NORMAL;
gBattleStruct->ateBoost[battlerAtk] = 1;
}
}
static void HandleAction_UseMove(void)
{
u8 side;
u8 var = 4;
u32 attackerAbility;
u32 ateType;
u32 ateType, moveType;
gBattlerAttacker = gBattlerByTurnOrder[gCurrentTurnActionNumber];
@ -5483,7 +5555,7 @@ static void HandleAction_UseMove(void)
}
}
// choose battlescript
// Choose battlescript.
if (gBattleTypeFlags & BATTLE_TYPE_PALACE
&& gProtectStructs[gBattlerAttacker].flag_x10)
{
@ -5512,33 +5584,8 @@ static void HandleAction_UseMove(void)
if (gBattleTypeFlags & BATTLE_TYPE_ARENA)
sub_81A56E8(gBattlerAttacker);
attackerAbility = GetBattlerAbility(gBattlerAttacker);
// Set move type.
if (gFieldStatuses & STATUS_FIELD_ION_DELUGE) // All moves become Electric-type this turn.
{
gBattleStruct->dynamicMoveType = 0x80 | TYPE_ELECTRIC;
}
else if (gBattleMoves[gChosenMove].type == TYPE_NORMAL
&& gBattleMoves[gChosenMove].effect != EFFECT_HIDDEN_POWER
&& gBattleMoves[gChosenMove].effect != EFFECT_WEATHER_BALL
&& ((attackerAbility == ABILITY_PIXILATE && (ateType = TYPE_FAIRY))
|| (attackerAbility == ABILITY_REFRIGERATE && (ateType = TYPE_ICE))
|| (attackerAbility == ABILITY_AERILATE && (ateType = TYPE_FLYING))
|| ((attackerAbility == ABILITY_GALVANIZE) && (ateType = TYPE_ELECTRIC))
)
)
{
gBattleStruct->dynamicMoveType = 0x80 | ateType;
gBattleStruct->ateBoost[gBattlerAttacker] = 1;
}
else if (gBattleMoves[gChosenMove].type != TYPE_NORMAL
&& gBattleMoves[gChosenMove].effect != EFFECT_HIDDEN_POWER
&& gBattleMoves[gChosenMove].effect != EFFECT_WEATHER_BALL
&& attackerAbility == ABILITY_NORMALIZE)
{
gBattleStruct->dynamicMoveType = 0x80 | TYPE_NORMAL;
gBattleStruct->ateBoost[gBattlerAttacker] = 1;
}
// Set dynamic move type.
SetTypeBeforeUsingMove(gChosenMove, gBattlerAttacker);
gCurrentActionFuncId = B_ACTION_EXEC_SCRIPT;
}

View File

@ -285,7 +285,7 @@ static void atkBD_copyfoestats(void);
static void atkBE_rapidspinfree(void);
static void atkBF_setdefensecurlbit(void);
static void atkC0_recoverbasedonsunlight(void);
static void atkC1_hiddenpowercalc(void);
static void atkC1_nop(void);
static void atkC2_selectfirstvalidtarget(void);
static void atkC3_trysetfutureattack(void);
static void atkC4_trydobeatup(void);
@ -325,7 +325,7 @@ static void atkE5_pickup(void);
static void atkE6_docastformchangeanimation(void);
static void atkE7_trycastformdatachange(void);
static void atkE8_settypebasedhalvers(void);
static void atkE9_setweatherballtype(void);
static void atkE9_nop(void);
static void atkEA_tryrecycleitem(void);
static void atkEB_settypetoterrain(void);
static void atkEC_pursuitrelated(void);
@ -543,7 +543,7 @@ void (* const gBattleScriptingCommandsTable[])(void) =
atkBE_rapidspinfree,
atkBF_setdefensecurlbit,
atkC0_recoverbasedonsunlight,
atkC1_hiddenpowercalc,
atkC1_nop,
atkC2_selectfirstvalidtarget,
atkC3_trysetfutureattack,
atkC4_trydobeatup,
@ -583,7 +583,7 @@ void (* const gBattleScriptingCommandsTable[])(void) =
atkE6_docastformchangeanimation,
atkE7_trycastformdatachange,
atkE8_settypebasedhalvers,
atkE9_setweatherballtype,
atkE9_nop,
atkEA_tryrecycleitem,
atkEB_settypetoterrain,
atkEC_pursuitrelated,
@ -8694,22 +8694,8 @@ static void atkC0_recoverbasedonsunlight(void)
}
}
static void atkC1_hiddenpowercalc(void)
static void atkC1_nop(void)
{
u8 typeBits;
typeBits = ((gBattleMons[gBattlerAttacker].hpIV & 1) << 0)
| ((gBattleMons[gBattlerAttacker].attackIV & 1) << 1)
| ((gBattleMons[gBattlerAttacker].defenseIV & 1) << 2)
| ((gBattleMons[gBattlerAttacker].speedIV & 1) << 3)
| ((gBattleMons[gBattlerAttacker].spAttackIV & 1) << 4)
| ((gBattleMons[gBattlerAttacker].spDefenseIV & 1) << 5);
gBattleStruct->dynamicMoveType = (15 * typeBits) / 63 + 1;
if (gBattleStruct->dynamicMoveType >= TYPE_MYSTERY)
gBattleStruct->dynamicMoveType++;
gBattleStruct->dynamicMoveType |= 0xC0;
gBattlescriptCurrInstr++;
}
@ -9600,22 +9586,8 @@ static void atkE8_settypebasedhalvers(void) // water and mud sport
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1);
}
static void atkE9_setweatherballtype(void)
static void atkE9_nop(void)
{
if (WEATHER_HAS_EFFECT)
{
if (gBattleWeather & WEATHER_RAIN_ANY)
*(&gBattleStruct->dynamicMoveType) = TYPE_WATER | 0x80;
else if (gBattleWeather & WEATHER_SANDSTORM_ANY)
*(&gBattleStruct->dynamicMoveType) = TYPE_ROCK | 0x80;
else if (gBattleWeather & WEATHER_SUN_ANY)
*(&gBattleStruct->dynamicMoveType) = TYPE_FIRE | 0x80;
else if (gBattleWeather & WEATHER_HAIL_ANY)
*(&gBattleStruct->dynamicMoveType) = TYPE_ICE | 0x80;
else
*(&gBattleStruct->dynamicMoveType) = TYPE_NORMAL | 0x80;
}
gBattlescriptCurrInstr++;
}

View File

@ -1215,6 +1215,7 @@ enum
ENDTURN_YAWN,
ENDTURN_ITEMS2,
ENDTURN_ROOST,
ENDTURN_ELECTRIFY,
ENDTURN_BATTLER_COUNT
};
@ -1658,6 +1659,10 @@ u8 DoBattlerEndTurnEffects(void)
}
gBattleStruct->turnEffectsTracker++;
break;
case ENDTURN_ELECTRIFY:
gStatuses3[gActiveBattler] &= ~(STATUS3_ELECTRIFIED);
gBattleStruct->turnEffectsTracker++;
break;
case ENDTURN_BATTLER_COUNT: // done
gBattleStruct->turnEffectsTracker = 0;
gBattleStruct->turnEffectsBattlerId++;