-
Notifications
You must be signed in to change notification settings - Fork 2.8k
Better White Out Money Calculation
Credits to AsparagusEduardo for creating the implementation of this feature that I will be explaining here, and to lightgod87 for extra polishing it.
In Pokémon Emerald, whenever you lose a battle you always lose half of your money.
In Pokémon FireRed/LeafGreen, Diamond/Pearl and subsequent games, you lose a more sensible amount influenced by the Pokémon with the highest level of your party and the amount of badges you have.
Today we'll be implementing that in Pokeemerald.
This implementation introduces 2 text strings from FireRed/LeafGreen for extra flavor and faithfulness. This is super easy, so let's get it out of the way.
First we define them by adding a constant in include/constants/battle_string_ids.h:
+#define STRINGID_PLAYERLOSTTOENEMYTRAINER 381
+#define STRINGID_PLAYERPAIDPRIZEMONEY 382
Don't forget to add 2 to the current value of your BATTLESTRINGS_COUNT
in the same file!
And then we add the actual text strings to src/battle_message.c.
As to not complicate things, I suggest to put them right below sText_YouThrowABallNowRight
, but you can add them wherever you want.
+static const u8 sText_PlayerLostToEnemyTrainer[] = _("{B_PLAYER_NAME} is out of\nusable POKéMON!\pPlayer lost against\n{B_TRAINER1_CLASS} {B_TRAINER1_NAME}!{PAUSE_UNTIL_PRESS}");
+static const u8 sText_PlayerPaidPrizeMoney[] = _("{B_PLAYER_NAME} paid ¥{B_BUFF1} as the prize\nmoney…\p… … … …\p{B_PLAYER_NAME} whited out!{PAUSE_UNTIL_PRESS}");
Now we have to link the constants we added previously to the labels of these new text strings by registering them in the gBattleStringsTable
.
+ [STRINGID_PLAYERLOSTTOENEMYTRAINER - 12] = sText_PlayerLostToEnemyTrainer,
+ [STRINGID_PLAYERPAIDPRIZEMONEY - 12] = sText_PlayerPaidPrizeMoney,
Again, you can add these wherever you want. If you want to remain consistent, you would want once again add them right under sText_YouThrowABallNowRight
, but it doesn't matter as long as you add them to the table.
Let's put these new battle strings to use, shall we? To do that, we'll do some quick changes to the BattleScript that triggers when you lose a battle, i.e. BattleScript_LocalBattleLostPrintWhiteOut
in data/battle_scrpts_1.s.
BattleScript_LocalBattleLostPrintWhiteOut::
printstring STRINGID_PLAYERWHITEOUT
waitmessage 0x40
+ getmoneyreward
printstring STRINGID_PLAYERWHITEOUT2
waitmessage 0x40
+ end2
BattleScript_LocalBattleLostEnd::
+ printstring STRINGID_PLAYERLOSTTOENEMYTRAINER
+ waitmessage 0x40
+ getmoneyreward
+ printstring STRINGID_PLAYERPAIDPRIZEMONEY
+ waitmessage 0x40
end2
Here we're setting up the BattleScript so the Cmd_getmoneyreward
function will be triggered if the Player loses a battle, and we're also putting our new text strings to use.
Now, normally, Cmd_getmoneyreward
is in charge of calculating the money you receive as a reward for winning and that alone.
You can guess what are we going to modify next, can't you?
Now we want to open src/battle_script_commands.c. Before anything, we have to define a new variable and 2 array lists that we're going to use soon enough.
+extern u8 gMaxPartyLevel;
+static const u16 sBadgeFlags[8] = {
+ FLAG_BADGE01_GET, FLAG_BADGE02_GET, FLAG_BADGE03_GET, FLAG_BADGE04_GET,
+ FLAG_BADGE05_GET, FLAG_BADGE06_GET, FLAG_BADGE07_GET, FLAG_BADGE08_GET,
+};
+static const u16 sWhiteOutBadgeMoney[9] = { 8, 16, 24, 36, 48, 60, 80, 100, 120 };
Note: The base payout while the Player holds 5 badges has been bumped from 60 to 64 starting from Pokémon Black and White, so you may want to do the same here, or not. It's entirely up to you.
If I were you I'd add them right below sBattlePalaceNatureToFlavorTextId
, that is right before the first function in the file.
And now we're ready to actually modify Cmd_getmoneyreward
:
static void Cmd_getmoneyreward(void)
{
- u32 moneyReward = GetTrainerMoneyToGive(gTrainerBattleOpponent_A);
- if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS)
- moneyReward += GetTrainerMoneyToGive(gTrainerBattleOpponent_B);
+ u32 money;
- AddMoney(&gSaveBlock1Ptr->money, moneyReward);
- PREPARE_WORD_NUMBER_BUFFER(gBattleTextBuff1, 5, moneyReward);
+ if (gBattleOutcome == B_OUTCOME_WON)
+ {
+ money = GetTrainerMoneyToGive(gTrainerBattleOpponent_A);
+ if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS)
+ money += GetTrainerMoneyToGive(gTrainerBattleOpponent_B);
+ AddMoney(&gSaveBlock1Ptr->money, money);
+ }
+ else
+ {
+ s32 i, count;
+ for (i = 0; i < PARTY_SIZE; i++)
+ {
+ if (GetMonData(&gPlayerParty[i], MON_DATA_SPECIES2) != SPECIES_NONE
+ && GetMonData(&gPlayerParty[i], MON_DATA_SPECIES2) != SPECIES_EGG)
+ {
+ if (GetMonData(&gPlayerParty[i], MON_DATA_LEVEL) > gMaxPartyLevel)
+ gMaxPartyLevel = GetMonData(&gPlayerParty[i], MON_DATA_LEVEL);
+ }
+ }
+ for (count = 0, i = 0; i < ARRAY_COUNT(sBadgeFlags); i++)
+ {
+ if (FlagGet(sBadgeFlags[i]) == TRUE)
+ ++count;
+ }
+ money = sWhiteOutBadgeMoney[count] * gMaxPartyLevel;
+ RemoveMoney(&gSaveBlock1Ptr->money, money);
+ }
+ PREPARE_WORD_NUMBER_BUFFER(gBattleTextBuff1, 5, money);
gBattlescriptCurrInstr++;
}
Here, we're making Cmd_getmoneyreward
handle not only the money calculation for winning a battle, but we're also making it calculate how much money should be removed from the Player when they lose a battle, and then we're storing that amount in a buffer to display it in the STRINGID_PLAYERPAIDPRIZEMONEY
we added earlier.
As you can see, we're introducing a new extern variable; gMaxPartyLevel
.
As this variable plays a central role in Cmd_getmoneyreward
which is a function that can only be triggered In Battle, we have to make the battle system recognize it.
To do that, we'll visit the src/battle_main.c file and throw it in at the end of the EWRAM vars list like so:
+EWRAM_DATA u8 gMaxPartyLevel = 1;
This function which can be found in the src/overworld.c file is always triggered whenever you lose a battle and it's also in charge of cutting the Player's money by half whenever they lose a battle, as you can easily tell by reading it.
As the last step of this process, we'll remove that bit because we naturally don't want that to happen.
void DoWhiteOut(void)
{
ScriptContext2_RunNewScript(EventScript_WhiteOut);
- SetMoney(&gSaveBlock1Ptr->money, GetMoney(&gSaveBlock1Ptr->money) / 2);
HealPlayerParty();
Overworld_ResetStateAfterWhiteOut();
SetWarpDestinationToLastHealLocation();
WarpIntoMap();
}
And just like that, we're done. Go build a ROM and let a Magikarp faint your party or something.