forked from rh-hideout/pokeemerald-expansion
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathbattle_terastal.c
183 lines (161 loc) · 5.63 KB
/
battle_terastal.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
#include "global.h"
#include "battle.h"
#include "battle_anim.h"
#include "battle_controllers.h"
#include "battle_interface.h"
#include "battle_terastal.h"
#include "battle_gimmick.h"
#include "battle_scripts.h"
#include "event_data.h"
#include "item.h"
#include "palette.h"
#include "pokemon.h"
#include "safari_zone.h"
#include "sprite.h"
#include "util.h"
#include "constants/abilities.h"
#include "constants/hold_effects.h"
#include "constants/rgb.h"
// Sets flags and variables upon a battler's Terastallization.
void ActivateTera(u32 battler)
{
u32 side = GetBattlerSide(battler);
// Set appropriate flags.
SetActiveGimmick(battler, GIMMICK_TERA);
SetGimmickAsActivated(battler, GIMMICK_TERA);
// Remove Tera Orb charge.
if (B_FLAG_TERA_ORB_CHARGED != 0
&& (B_FLAG_TERA_ORB_NO_COST == 0 || !FlagGet(B_FLAG_TERA_ORB_NO_COST))
&& side == B_SIDE_PLAYER
&& !(IsDoubleBattle() && !IsPartnerMonFromSameTrainer(battler)))
{
FlagClear(B_FLAG_TERA_ORB_CHARGED);
}
// Execute battle script.
PREPARE_TYPE_BUFFER(gBattleTextBuff1, GetBattlerTeraType(battler));
if (TryBattleFormChange(gBattlerAttacker, FORM_CHANGE_BATTLE_TERASTALLIZATION))
BattleScriptExecute(BattleScript_TeraFormChange);
else
BattleScriptExecute(BattleScript_Terastallization);
}
// Applies palette blend and enables UI indicator after animation has played
void ApplyBattlerVisualsForTeraAnim(u32 battler)
{
struct Pokemon *party = GetBattlerParty(battler);
u32 index = gBattlerPartyIndexes[battler];
// Show indicator and do palette blend.
UpdateHealthboxAttribute(gHealthboxSpriteIds[battler], &party[index], HEALTHBOX_ALL);
BlendPalette(OBJ_PLTT_ID(battler), 16, 8, GetTeraTypeRGB(GetBattlerTeraType(battler)));
CpuCopy32(gPlttBufferFaded + OBJ_PLTT_ID(battler), gPlttBufferUnfaded + OBJ_PLTT_ID(battler), PLTT_SIZEOF(16));
// We apply the animation behind a white screen, so restore the blended color here to avoid a pop
BlendPalette(OBJ_PLTT_ID(battler), 16, 16, RGB_WHITEALPHA);
}
// Returns whether a battler can Terastallize.
bool32 CanTerastallize(u32 battler)
{
u32 holdEffect = GetBattlerHoldEffect(battler, FALSE);
// Prevents Zigzagoon from terastalizing in vanilla.
if (gBattleTypeFlags & BATTLE_TYPE_FIRST_BATTLE && GetBattlerSide(battler) == B_SIDE_OPPONENT)
return FALSE;
if (TESTING || GetBattlerSide(battler) == B_SIDE_OPPONENT)
{
// Skip all other checks in this block, go to HasTrainerUsedGimmick
}
else if (!CheckBagHasItem(ITEM_TERA_ORB, 1))
{
return FALSE;
}
else if (FlagGet(B_FLAG_TERA_ORB_NO_COST))
{
// Tera Orb is not depleted, go to HasTrainerUsedGimmick
}
else if (!FlagGet(B_FLAG_TERA_ORB_CHARGED))
{
return FALSE;
}
// Check if Trainer has already Terastallized.
if (HasTrainerUsedGimmick(battler, GIMMICK_TERA))
return FALSE;
// Check if AI battler is intended to Terastallize.
if (!ShouldTrainerBattlerUseGimmick(battler, GIMMICK_TERA))
return FALSE;
// Check if battler has another gimmick active.
if (GetActiveGimmick(battler) != GIMMICK_NONE)
return FALSE;
// Check if battler is holding a Z-Crystal or Mega Stone.
if (!TESTING && (holdEffect == HOLD_EFFECT_Z_CRYSTAL || holdEffect == HOLD_EFFECT_MEGA_STONE)) // tests make this check already
return FALSE;
// Every check passed!
return TRUE;
}
// Returns a battler's Tera type.
u32 GetBattlerTeraType(u32 battler)
{
return GetMonData(&GetBattlerParty(battler)[gBattlerPartyIndexes[battler]], MON_DATA_TERA_TYPE);
}
// Uses up a type's Stellar boost.
void ExpendTypeStellarBoost(u32 battler, u32 type)
{
if (type < 32 && gBattleMons[battler].species != SPECIES_TERAPAGOS_STELLAR) // avoid OOB access
gBattleStruct->stellarBoostFlags[GetBattlerSide(battler)] |= 1u << type;
}
// Checks whether a type's Stellar boost has been expended.
bool32 IsTypeStellarBoosted(u32 battler, u32 type)
{
if (type < 32) // avoid OOB access
return !(gBattleStruct->stellarBoostFlags[GetBattlerSide(battler)] & (1u << type));
else
return FALSE;
}
// Returns the STAB power multiplier to use when Terastallized.
// Power multipliers from Smogon Research thread.
uq4_12_t GetTeraMultiplier(u32 battler, u32 type)
{
u32 teraType = GetBattlerTeraType(battler);
bool32 hasAdaptability = (GetBattlerAbility(battler) == ABILITY_ADAPTABILITY);
// Safety check.
if (GetActiveGimmick(battler) != GIMMICK_TERA)
return UQ_4_12(1.0);
// Stellar-type checks.
if (teraType == TYPE_STELLAR)
{
bool32 shouldBoost = IsTypeStellarBoosted(battler, type);
if (IS_BATTLER_OF_BASE_TYPE(battler, type))
{
if (shouldBoost)
return UQ_4_12(2.0);
else
return UQ_4_12(1.5);
}
else if (shouldBoost)
return UQ_4_12(1.2);
else
return UQ_4_12(1.0);
}
// Base and Tera type.
if (type == teraType && IS_BATTLER_OF_BASE_TYPE(battler, type))
{
if (hasAdaptability)
return UQ_4_12(2.25);
else
return UQ_4_12(2.0);
}
// Base or Tera type only.
else if ((type == teraType && !IS_BATTLER_OF_BASE_TYPE(battler, type))
|| (type != teraType && IS_BATTLER_OF_BASE_TYPE(battler, type)))
{
if (hasAdaptability)
return UQ_4_12(2.0);
else
return UQ_4_12(1.5);
}
// Neither base or Tera type.
else
{
return UQ_4_12(1.0);
}
}
u16 GetTeraTypeRGB(u32 type)
{
return gTypesInfo[type].teraTypeRGBValue;
}