Skip to content

Commit

Permalink
Merge branch '_RHH/master' into _RHH/upcoming
Browse files Browse the repository at this point in the history
  • Loading branch information
AsparagusEduardo committed Jan 11, 2025
2 parents 6e5f40d + 71cf1bf commit 8821779
Show file tree
Hide file tree
Showing 29 changed files with 417 additions and 83 deletions.
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ endif
ifeq (debug,$(MAKECMDGOALS))
DEBUG := 1
endif
ifeq ($(TESTELF),$(MAKECMDGOALS))
TEST := 1
endif

# Default make rule
all: rom
Expand Down
12 changes: 12 additions & 0 deletions data/scripts/field_move_scripts.inc
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,18 @@ EventScript_UseDig::
lockall
goto EventScript_DigCommon


EventScript_CutGrassCommon:
isfollowerfieldmoveuser VAR_0x8004
setfieldeffectargument 3, VAR_0x8004 @ skip pose if true
dofieldeffect FLDEFF_USE_CUT_ON_GRASS
waitstate

@ Use Cut grass from party menu
EventScript_UseCutGrass::
lockall
goto EventScript_CutGrassCommon

Text_CantDive:
.string "The sea is deep here. A POKéMON\n"
.string "may be able to go underwater.$"
Expand Down
6 changes: 3 additions & 3 deletions docs/scope.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,9 @@ A pull request meets the scope criteria if:
4. **Non-SS Items**: Adds Items that have NOT appeared in a Showdown-supported title
5. **Non-SS Gimmicks**: Adds Gimmicks that have NOT appeared in a Showdown-supported title (Showdown's Other Metagames, etc.)
6. **Non-SS Battle Types**: Adds Special Battle Types that have NOT appeared in a Showdown-supported title
7. **Non-SS or SS Overworld Maps**: Adds overworld maps from either Showdown-supported titles or non-Showdown-supported titles
7. **Duplicate Feature UI**: Adds functionality that duplicates the core functionality of an existing vanilla feature
8. **Vanilla Link Compatibility**: The ability for Base Expansion Version and Vanilla Emerald Version to connect, trade, and battle one another
7. **Overworld Maps**: Adds overworld maps from either Showdown-supported titles or non-Showdown-supported titles
8. **Duplicate UIs**: Adds additional user interface that covers the same functionality of an existing feature (HGSS Pokédex, BW Summary Screen, etc.)
9. **Vanilla Link Compatibility**: The ability for Base Expansion Version and Vanilla Emerald Version to connect, trade, and battle one another

## Discussion Required Categories

Expand Down
2 changes: 1 addition & 1 deletion docs/tutorials/ai_flags.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ AI will generally behave more recklessly. This AI enables the following behaviou
* Switch offensively mid battle rather than defensively (if using `AI_FLAG_SMART_MON_CHOICES`)
* Prioritize Explosion moves

## `AI_FLAG_PREFER_STRONGEST_MOVE`
## `AI_FLAG_TRY_TO_2HKO`
Adds score bonus to any move the AI has that either OHKOs or 2HKOs the player.

Keep in mind that this is a weaker form of `AI_FLAG_TRY_TO_FAINT` at scoring OHKOs as it does not take into account who is attacking first, it does however handle 2HKOs.
Expand Down
4 changes: 2 additions & 2 deletions docs/tutorials/how_to_new_move.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ Let's look at an example:
```c
[MOVE_THUNDER_SHOCK] =
{
.name = HANDLE_EXPANDED_MOVE_NAME("ThunderShock", "Thunder Shock"),
.name = COMPOUND_STRING("Thunder Shock"),
.description = COMPOUND_STRING(
"An electrical attack that\n"
"may paralyze the foe."),
Expand All @@ -51,7 +51,7 @@ Let's look at an example:
.contestComboMoves = {COMBO_STARTER_CHARGE},
},
```
The `HANDLE_EXPANDED_MOVE_NAME` allows the usage of a name of extended character length, so long as the `B_EXPANDED_MOVE_NAMES` is set to `TRUE`, whereas by default it's limited in Gen 3 to 12 characters. Most of the fields here are obvious, but the two important ones for determining what a move actually *does* are `effect` and `additionalEffects`.
Most of the fields here are obvious, but the two important ones for determining what a move actually *does* are `effect` and `additionalEffects`.

The `effect` represents how the move actually works when called in battle - it can be a two turn move, or a move that only works if the target is holding an item, for example. How each effect works is pretty much unique, but the way a move of a particular effect is executed is defined by a script [`data/battle_scripts_1.s`](#databattle_scripts_1s), and any *variable* characteristics such as typing or power are defined in either [`src/battle_script_commands.c`](#srcbattle_script_commandsc) or [`src/battle_util.c`](#srcbattle_utilc), depending on the effect. The vast majority of non-status moves are simply `EFFECT_HIT`, in that they deal damage and apply `additionalEffects` (if defined).

Expand Down
2 changes: 1 addition & 1 deletion include/battle.h
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,7 @@ struct WishFutureKnock
u8 wishPartyId[MAX_BATTLERS_COUNT];
u8 weatherDuration;
u8 knockedOffMons[NUM_BATTLE_SIDES]; // Each battler is represented by a bit.
s16 futureSightDmg;
};

struct AI_SavedBattleMon
Expand Down Expand Up @@ -575,7 +576,6 @@ struct DynamaxData
u8 dynamaxTurns[MAX_BATTLERS_COUNT];
u16 baseMoves[MAX_BATTLERS_COUNT]; // base move of Max Move
u16 lastUsedBaseMove;
u16 levelUpHP;
};

struct BattleGimmickData
Expand Down
2 changes: 1 addition & 1 deletion include/battle_dynamax.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ enum MaxMoveEffect

bool32 CanDynamax(u32 battler);
bool32 IsGigantamaxed(u32 battler);
void ApplyDynamaxHPMultiplier(u32 battler, struct Pokemon* mon);
void ApplyDynamaxHPMultiplier(struct Pokemon* mon);
void ActivateDynamax(u32 battler);
u16 GetNonDynamaxHP(u32 battler);
u16 GetNonDynamaxMaxHP(u32 battler);
Expand Down
2 changes: 1 addition & 1 deletion include/battle_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,7 @@ u32 GetBattlerMoveTargetType(u32 battler, u32 move);
bool32 CanTargetBattler(u32 battlerAtk, u32 battlerDef, u16 move);
void CopyMonLevelAndBaseStatsToBattleMon(u32 battler, struct Pokemon *mon);
void CopyMonAbilityAndTypesToBattleMon(u32 battler, struct Pokemon *mon);
void RecalcBattlerStats(u32 battler, struct Pokemon *mon);
void RecalcBattlerStats(u32 battler, struct Pokemon *mon, bool32 isDynamaxing);
bool32 IsAlly(u32 battlerAtk, u32 battlerDef);
bool32 IsGen6ExpShareEnabled(void);
bool32 MoveHasAdditionalEffect(u32 move, u32 moveEffect);
Expand Down
2 changes: 1 addition & 1 deletion include/constants/battle_ai.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
#define AI_FLAG_CHECK_VIABILITY (1 << 2) // AI damaging moves and move effects to determine the best available move in the current situation.
#define AI_FLAG_FORCE_SETUP_FIRST_TURN (1 << 3) // AI will prioritize using setup moves on the first turn at the expensve of all else. AI_FLAG_CHECK_VIABILITY will instead do this when the AI determines it makes sense.
#define AI_FLAG_RISKY (1 << 4) // AI will generally behave more recklessly, prioritizing damage over accuracy, explosions, etc.
#define AI_FLAG_PREFER_STRONGEST_MOVE (1 << 5) // AI adds score bonus to any move the AI has that either OHKOs or 2HKOs the player.
#define AI_FLAG_TRY_TO_2HKO (1 << 5) // AI adds score bonus to any move the AI has that either OHKOs or 2HKOs the player.
#define AI_FLAG_PREFER_BATON_PASS (1 << 6) // AI prefers raising its own stats and setting for / using Baton Pass.
#define AI_FLAG_DOUBLE_BATTLE (1 << 7) // Automatically set for double battles, handles AI behaviour with partner.
#define AI_FLAG_HP_AWARE (1 << 8) // AI will favour certain move effects based on how much remaining HP it and the player's mon have.
Expand Down
1 change: 1 addition & 0 deletions include/event_scripts.h
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,7 @@ extern const u8 EventScript_UseFlash[];
extern const u8 EventScript_UseCut[];
extern const u8 EventScript_UseRockSmash[];
extern const u8 EventScript_UseDig[];
extern const u8 EventScript_UseCutGrass[];

//player pc
extern const u8 LittlerootTown_BrendansHouse_2F_EventScript_TurnOffPlayerPC[];
Expand Down
1 change: 1 addition & 0 deletions include/pokemon.h
Original file line number Diff line number Diff line change
Expand Up @@ -804,5 +804,6 @@ void HealBoxPokemon(struct BoxPokemon *boxMon);
void UpdateDaysPassedSinceFormChange(u16 days);
void TrySetDayLimitToFormChange(struct Pokemon *mon);
u32 CheckDynamicMoveType(struct Pokemon *mon, u32 move, u32 battler);
uq4_12_t GetDynamaxLevelHPMultiplier(u32 dynamaxLevel, bool32 inverseMultiplier);

#endif // GUARD_POKEMON_H
8 changes: 4 additions & 4 deletions src/battle_ai_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ static s32 AI_TryToFaint(u32 battlerAtk, u32 battlerDef, u32 move, s32 score);
static s32 AI_CheckViability(u32 battlerAtk, u32 battlerDef, u32 move, s32 score);
static s32 AI_ForceSetupFirstTurn(u32 battlerAtk, u32 battlerDef, u32 move, s32 score);
static s32 AI_Risky(u32 battlerAtk, u32 battlerDef, u32 move, s32 score);
static s32 AI_PreferStrongestMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score);
static s32 AI_TryTo2HKO(u32 battlerAtk, u32 battlerDef, u32 move, s32 score);
static s32 AI_PreferBatonPass(u32 battlerAtk, u32 battlerDef, u32 move, s32 score);
static s32 AI_HPAware(u32 battlerAtk, u32 battlerDef, u32 move, s32 score);
static s32 AI_Roaming(u32 battlerAtk, u32 battlerDef, u32 move, s32 score);
Expand All @@ -66,7 +66,7 @@ static s32 (*const sBattleAiFuncTable[])(u32, u32, u32, s32) =
[2] = AI_CheckViability, // AI_FLAG_CHECK_VIABILITY
[3] = AI_ForceSetupFirstTurn, // AI_FLAG_FORCE_SETUP_FIRST_TURN
[4] = AI_Risky, // AI_FLAG_RISKY
[5] = AI_PreferStrongestMove, // AI_FLAG_PREFER_STRONGEST_MOVE
[5] = AI_TryTo2HKO, // AI_FLAG_TRY_TO_2HKO
[6] = AI_PreferBatonPass, // AI_FLAG_PREFER_BATON_PASS
[7] = AI_DoubleBattle, // AI_FLAG_DOUBLE_BATTLE
[8] = AI_HPAware, // AI_FLAG_HP_AWARE
Expand Down Expand Up @@ -136,7 +136,7 @@ static u32 GetWildAiFlags(void)
if (avgLevel >= 20)
flags |= AI_FLAG_CHECK_VIABILITY;
if (avgLevel >= 60)
flags |= AI_FLAG_PREFER_STRONGEST_MOVE;
flags |= AI_FLAG_TRY_TO_2HKO;
if (avgLevel >= 80)
flags |= AI_FLAG_HP_AWARE;

Expand Down Expand Up @@ -4919,7 +4919,7 @@ static s32 AI_Risky(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
}

// Adds score bonus to best powered move
static s32 AI_PreferStrongestMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
static s32 AI_TryTo2HKO(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
{
if (IS_TARGETING_PARTNER(battlerAtk, battlerDef))
return score;
Expand Down
43 changes: 21 additions & 22 deletions src/battle_controller_player.c
Original file line number Diff line number Diff line change
Expand Up @@ -1410,6 +1410,14 @@ void Task_PlayerController_RestoreBgmAfterCry(u8 taskId)
#define tExpTask_gainedExp_2 data[4] // Stored as two half-words containing a word.
#define tExpTask_frames data[10]

static void DynamaxModifyHPLevelUp(struct Pokemon *mon, u32 battler, u32 oldMaxHP)
{
ApplyDynamaxHPMultiplier(mon);
gBattleScripting.levelUpHP = GetMonData(mon, MON_DATA_MAX_HP) - oldMaxHP; // overwrite levelUpHP since it overflows
gBattleMons[battler].hp += gBattleScripting.levelUpHP;
SetMonData(mon, MON_DATA_HP, &gBattleMons[battler].hp);
}

static s32 GetTaskExpValue(u8 taskId)
{
return (u16)(gTasks[taskId].tExpTask_gainedExp_1) | (gTasks[taskId].tExpTask_gainedExp_2 << 16);
Expand All @@ -1428,21 +1436,16 @@ static void Task_GiveExpToMon(u8 taskId)
u8 level = GetMonData(mon, MON_DATA_LEVEL);
u32 currExp = GetMonData(mon, MON_DATA_EXP);
u32 nextLvlExp = gExperienceTables[gSpeciesInfo[species].growthRate][level + 1];
u32 oldMaxHP = GetMonData(mon, MON_DATA_MAX_HP);

if (currExp + gainedExp >= nextLvlExp)
{
SetMonData(mon, MON_DATA_EXP, &nextLvlExp);
gBattleStruct->dynamax.levelUpHP = GetMonData(mon, MON_DATA_HP) \
+ UQ_4_12_TO_INT((gBattleScripting.levelUpHP * UQ_4_12(1.5)) + UQ_4_12_ROUND);
CalculateMonStats(mon);

// Reapply Dynamax HP multiplier after stats are recalculated.
if (GetActiveGimmick(battler) == GIMMICK_DYNAMAX && monId == gBattlerPartyIndexes[battler])
{
ApplyDynamaxHPMultiplier(battler, mon);
gBattleMons[battler].hp = gBattleStruct->dynamax.levelUpHP;
SetMonData(mon, MON_DATA_HP, &gBattleMons[battler].hp);
}
DynamaxModifyHPLevelUp(mon, battler, oldMaxHP);

gainedExp -= nextLvlExp - currExp;
BtlController_EmitTwoReturnValues(battler, BUFFER_B, RET_VALUE_LEVELED_UP, gainedExp);
Expand Down Expand Up @@ -1491,6 +1494,7 @@ static void Task_GiveExpWithExpBar(u8 taskId)
{
u8 level;
u16 species;
u32 oldMaxHP;
s32 currExp, expOnNextLvl, newExpPoints;

if (gTasks[taskId].tExpTask_frames < 13)
Expand All @@ -1502,31 +1506,27 @@ static void Task_GiveExpWithExpBar(u8 taskId)
u8 monId = gTasks[taskId].tExpTask_monId;
s32 gainedExp = GetTaskExpValue(taskId);
u8 battler = gTasks[taskId].tExpTask_battler;
struct Pokemon *mon = &gPlayerParty[monId];

newExpPoints = MoveBattleBar(battler, gHealthboxSpriteIds[battler], EXP_BAR, 0);
SetHealthboxSpriteVisible(gHealthboxSpriteIds[battler]);
if (newExpPoints == -1) // The bar has been filled with given exp points.
{
m4aSongNumStop(SE_EXP);
level = GetMonData(&gPlayerParty[monId], MON_DATA_LEVEL);
currExp = GetMonData(&gPlayerParty[monId], MON_DATA_EXP);
species = GetMonData(&gPlayerParty[monId], MON_DATA_SPECIES);
level = GetMonData(mon, MON_DATA_LEVEL);
currExp = GetMonData(mon, MON_DATA_EXP);
species = GetMonData(mon, MON_DATA_SPECIES);
oldMaxHP = GetMonData(mon, MON_DATA_MAX_HP);
expOnNextLvl = gExperienceTables[gSpeciesInfo[species].growthRate][level + 1];

if (currExp + gainedExp >= expOnNextLvl)
{
SetMonData(&gPlayerParty[monId], MON_DATA_EXP, &expOnNextLvl);
gBattleStruct->dynamax.levelUpHP = GetMonData(&gPlayerParty[monId], MON_DATA_HP) \
+ UQ_4_12_TO_INT((gBattleScripting.levelUpHP * UQ_4_12(1.5)) + UQ_4_12_ROUND);
CalculateMonStats(&gPlayerParty[monId]);
SetMonData(mon, MON_DATA_EXP, &expOnNextLvl);
CalculateMonStats(mon);

// Reapply Dynamax HP multiplier after stats are recalculated.
if (GetActiveGimmick(battler) == GIMMICK_DYNAMAX && monId == gBattlerPartyIndexes[battler])
{
ApplyDynamaxHPMultiplier(battler, &gPlayerParty[monId]);
gBattleMons[battler].hp = gBattleStruct->dynamax.levelUpHP;
SetMonData(&gPlayerParty[monId], MON_DATA_HP, &gBattleMons[battler].hp);
}
DynamaxModifyHPLevelUp(mon, battler, oldMaxHP);

gainedExp -= expOnNextLvl - currExp;
BtlController_EmitTwoReturnValues(battler, BUFFER_B, RET_VALUE_LEVELED_UP, gainedExp);
Expand All @@ -1535,7 +1535,7 @@ static void Task_GiveExpWithExpBar(u8 taskId)
else
{
currExp += gainedExp;
SetMonData(&gPlayerParty[monId], MON_DATA_EXP, &currExp);
SetMonData(mon, MON_DATA_EXP, &currExp);
gBattlerControllerFuncs[battler] = Controller_WaitForString;
DestroyTask(taskId);
}
Expand Down Expand Up @@ -2042,7 +2042,6 @@ static void PlayerHandleChooseAction(u32 battler)
ActionSelectionCreateCursorAt(gActionSelectionCursor[battler], 0);
PREPARE_MON_NICK_BUFFER(gBattleTextBuff1, battler, gBattlerPartyIndexes[battler]);
BattleStringExpandPlaceholdersToDisplayedString(gText_WhatWillPkmnDo);
BreakStringAutomatic(gDisplayedStringBattle, WindowWidthPx(B_WIN_ACTION_PROMPT), 2, FONT_NORMAL);

if (B_SHOW_PARTNER_TARGET && gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER && IsBattlerAlive(B_POSITION_PLAYER_RIGHT))
{
Expand Down Expand Up @@ -2236,7 +2235,7 @@ void PlayerHandleExpUpdate(u32 battler)

static void PlayerHandleStatusXor(u32 battler)
{
u8 val = GetMonData(&gPlayerParty[gBattlerPartyIndexes[battler]], MON_DATA_STATUS) ^ gBattleResources->bufferA[battler][1];
u32 val = GetMonData(&gPlayerParty[gBattlerPartyIndexes[battler]], MON_DATA_STATUS) ^ gBattleResources->bufferA[battler][1];

SetMonData(&gPlayerParty[gBattlerPartyIndexes[battler]], MON_DATA_STATUS, &val);
PlayerBufferExecCompleted(battler);
Expand Down
1 change: 0 additions & 1 deletion src/battle_controller_safari.c
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,6 @@ static void SafariHandleChooseAction(u32 battler)

ActionSelectionCreateCursorAt(gActionSelectionCursor[battler], 0);
BattleStringExpandPlaceholdersToDisplayedString(gText_WhatWillPkmnDo2);
BreakStringAutomatic(gDisplayedStringBattle, WindowWidthPx(B_WIN_ACTION_PROMPT), 2, FONT_NORMAL);
BattlePutTextOnWindow(gDisplayedStringBattle, B_WIN_ACTION_PROMPT);
}

Expand Down
6 changes: 3 additions & 3 deletions src/battle_debug.c
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ enum
LIST_AI_CHECK_VIABILITY,
LIST_AI_SETUP_FIRST_TURN,
LIST_AI_RISKY,
LIST_AI_PREFER_STRONGEST_MOVE,
LIST_AI_TRY_TO_2HKO,
LIST_AI_PREFER_BATON_PASS,
LIST_AI_DOUBLE_BATTLE,
LIST_AI_HP_AWARE,
Expand Down Expand Up @@ -385,7 +385,7 @@ static const u8 sText_TryToFaint[] = _("Try to Faint");
static const u8 sText_CheckViability[] = _("Check Viability");
static const u8 sText_SetUpFirstTurn[] = _("Setup First Turn");
static const u8 sText_Risky[] = _("Risky");
static const u8 sText_PreferStrongestMove[] = _("Prefer Strongest Move");
static const u8 sText_TryTo2HKO[] = _("Try to 2HKO");
static const u8 sText_PreferBatonPass[] = _("Prefer Baton Pass");
static const u8 sText_DoubleBattle[] = _("Double Battle");
static const u8 sText_HpAware[] = _("HP Aware");
Expand Down Expand Up @@ -628,7 +628,7 @@ static const struct ListMenuItem sAIListItems[] =
{sText_CheckViability, LIST_AI_CHECK_VIABILITY},
{sText_SetUpFirstTurn, LIST_AI_SETUP_FIRST_TURN},
{sText_Risky, LIST_AI_RISKY},
{sText_PreferStrongestMove, LIST_AI_PREFER_STRONGEST_MOVE},
{sText_TryTo2HKO, LIST_AI_TRY_TO_2HKO},
{sText_PreferBatonPass, LIST_AI_PREFER_BATON_PASS},
{sText_DoubleBattle, LIST_AI_DOUBLE_BATTLE},
{sText_HpAware, LIST_AI_HP_AWARE},
Expand Down
Loading

0 comments on commit 8821779

Please sign in to comment.