From 81e97631180cad9a4ba6781acb31ee861f1c8816 Mon Sep 17 00:00:00 2001 From: voloved <36523934+voloved@users.noreply.github.com> Date: Sun, 12 Feb 2023 15:32:21 -0500 Subject: [PATCH] Updated Add Nuzlocke Challenge (markdown) --- Add-Nuzlocke-Challenge.md | 1214 +++++++++++++++++++++++-------------- 1 file changed, 757 insertions(+), 457 deletions(-) diff --git a/Add-Nuzlocke-Challenge.md b/Add-Nuzlocke-Challenge.md index 9dab305..1b7730e 100644 --- a/Add-Nuzlocke-Challenge.md +++ b/Add-Nuzlocke-Challenge.md @@ -7,11 +7,14 @@ By devolov ![pokeemerald-2](https://user-images.githubusercontent.com/36523934/211448326-8184ca37-0a5b-4cbf-b484-a4c9e45deeb2.png) The rules for the Nuzlocke challenge: -* If a Pokemon faints, they cannot be revived. -* Only the first Pokemon in a route can be caught. +* [If a Pokemon faints, they cannot be revived.](#pokemon-that-faint-cannot-be-revived) +* [Only the first Pokemon in a route can be caught.](#can-only-catch-first-pokemon) * Optional: * [Dupes Clause](#Dupes-Clause). - * [Can't Overlevel Leaders] + * [Can't Overlevel Leaders](#Cant-Overlevel-Leaders) + * [No Held Items](#no-held-items) + * [No Battle Items](#no-battle-items) + * [Force Set Mode](#force-set-mode) The challenge is chosen at a new game right after chosing your gender. Routes where Pokemon catches are monitored can be seen in the function `currLocConvertForNuzlocke` and `HasWildPokmnOnThisRouteBeenSeen`. @@ -28,13 +31,194 @@ There are about 100 locations where Pokemon can reasonably be caught in the game ```diff +------------------------------- src/main_menu.c ------------------------------- +index f99703622..75520e337 100644 +@@ -36,8 +36,9 @@ + #include "text_window.h" + #include "title_screen.h" + #include "window.h" + #include "mystery_gift_menu.h" ++#include "constants/flags.h" + + /* + * Main menu state machine + * ----------------------- +@@ -125,13 +126,18 @@ + * Task_NewGameBirchSpeech_WaitToShowGenderMenu + * Task_NewGameBirchSpeech_ChooseGender + * - Animates by advancing to Task_NewGameBirchSpeech_SlideOutOldGenderSprite + * whenever the player's selection changes. +- * - Advances to Task_NewGameBirchSpeech_WhatsYourName when done. ++ * - Advances to Task_NewGameBirchSpeech_Nuzlocke when done. + * + * Task_NewGameBirchSpeech_SlideOutOldGenderSprite + * Task_NewGameBirchSpeech_SlideInNewGenderSprite + * - Returns back to Task_NewGameBirchSpeech_ChooseGender. ++ * ++ * Task_NewGameBirchSpeech_Nuzlocke ++ * Task_NewGameBirchSpeech_WaitToShowNuzlockeMenu ++ * Task_NewGameBirchSpeech_ChooseNuzlocke ++ * Advances to Task_NewGameBirchSpeech_WhatsYourName when done. + * + * Task_NewGameBirchSpeech_WhatsYourName + * Task_NewGameBirchSpeech_WaitForWhatsYourNameToPrint + * Task_NewGameBirchSpeech_WaitPressBeforeNameChoice +@@ -208,16 +214,22 @@ static void NewGameBirchSpeech_StartFadePlatformIn(u8, u8); + static void Task_NewGameBirchSpeech_SlidePlatformAway(u8); + static void Task_NewGameBirchSpeech_StartPlayerFadeIn(u8); + static void Task_NewGameBirchSpeech_WaitForPlayerFadeIn(u8); + static void Task_NewGameBirchSpeech_BoyOrGirl(u8); ++static void Task_NewGameBirchSpeech_Nuzlocke(u8); + static void LoadMainMenuWindowFrameTiles(u8, u16); + static void DrawMainMenuWindowBorder(const struct WindowTemplate *, u16); + static void Task_HighlightSelectedMainMenuItem(u8); + static void Task_NewGameBirchSpeech_WaitToShowGenderMenu(u8); + static void Task_NewGameBirchSpeech_ChooseGender(u8); ++static void Task_NewGameBirchSpeech_WaitToShowNuzlockeMenu(u8); ++static void Task_NewGameBirchSpeech_ChooseNuzlocke(u8); + static void NewGameBirchSpeech_ShowGenderMenu(void); + static s8 NewGameBirchSpeech_ProcessGenderMenuInput(void); + static void NewGameBirchSpeech_ClearGenderWindow(u8, u8); ++static void NewGameBirchSpeech_ShowNuzlockeMenu(void); ++static s8 NewGameBirchSpeech_ProcessNuzlockeMenuInput(void); ++static void NewGameBirchSpeech_ClearNuzlockeWindow(u8, u8); + static void Task_NewGameBirchSpeech_WhatsYourName(u8); + static void Task_NewGameBirchSpeech_SlideOutOldGenderSprite(u8); + static void Task_NewGameBirchSpeech_SlideInNewGenderSprite(u8); + static void Task_NewGameBirchSpeech_WaitForWhatsYourNameToPrint(u8); +@@ -456,8 +468,13 @@ static const struct MenuAction sMenuActions_Gender[] = { + {gText_BirchBoy, NULL}, + {gText_BirchGirl, NULL} + }; + ++static const struct MenuAction sMenuActions_Nuzlocke[] = { ++ {gText_Yes, NULL}, ++ {gText_No, NULL} ++}; ++ + static const u8 *const sMalePresetNames[] = { + gText_DefaultNameStu, + gText_DefaultNameMilton, + gText_DefaultNameTom, +@@ -1507,15 +1524,15 @@ static void Task_NewGameBirchSpeech_ChooseGender(u8 taskId) + case MALE: + PlaySE(SE_SELECT); + gSaveBlock2Ptr->playerGender = gender; + NewGameBirchSpeech_ClearGenderWindow(1, 1); +- gTasks[taskId].func = Task_NewGameBirchSpeech_WhatsYourName; ++ gTasks[taskId].func = Task_NewGameBirchSpeech_Nuzlocke; + break; + case FEMALE: + PlaySE(SE_SELECT); + gSaveBlock2Ptr->playerGender = gender; + NewGameBirchSpeech_ClearGenderWindow(1, 1); +- gTasks[taskId].func = Task_NewGameBirchSpeech_WhatsYourName; ++ gTasks[taskId].func = Task_NewGameBirchSpeech_Nuzlocke; + break; + } + gender2 = Menu_GetCursorPos(); + if (gender2 != gTasks[taskId].tPlayerGender) +@@ -1569,8 +1586,46 @@ static void Task_NewGameBirchSpeech_SlideInNewGenderSprite(u8 taskId) + } + } + } + ++ ++static void Task_NewGameBirchSpeech_Nuzlocke(u8 taskId) ++{ ++ NewGameBirchSpeech_ClearWindow(0); ++ StringExpandPlaceholders(gStringVar4, gText_Birch_Nuzlocke); ++ AddTextPrinterForMessage(TRUE); ++ gTasks[taskId].func = Task_NewGameBirchSpeech_WaitToShowNuzlockeMenu; ++} ++ ++static void Task_NewGameBirchSpeech_WaitToShowNuzlockeMenu(u8 taskId) ++{ ++ if (!RunTextPrintersAndIsPrinter0Active()) ++ { ++ NewGameBirchSpeech_ShowNuzlockeMenu(); ++ gTasks[taskId].func = Task_NewGameBirchSpeech_ChooseNuzlocke; ++ } ++} ++ ++static void Task_NewGameBirchSpeech_ChooseNuzlocke(u8 taskId) ++{ ++ int nuzlocke = NewGameBirchSpeech_ProcessNuzlockeMenuInput(); ++ switch (nuzlocke) ++ { ++ case 0: ++ PlaySE(SE_SELECT); ++ FlagSet(FLAG_NUZLOCKE); ++ NewGameBirchSpeech_ClearNuzlockeWindow(1, 1); ++ gTasks[taskId].func = Task_NewGameBirchSpeech_WhatsYourName; ++ break; ++ case 1: ++ PlaySE(SE_SELECT); ++ FlagClear(FLAG_NUZLOCKE); ++ NewGameBirchSpeech_ClearNuzlockeWindow(1, 1); ++ gTasks[taskId].func = Task_NewGameBirchSpeech_WhatsYourName; ++ break; ++ } ++} ++ + static void Task_NewGameBirchSpeech_WhatsYourName(u8 taskId) + { + NewGameBirchSpeech_ClearWindow(0); + StringExpandPlaceholders(gStringVar4, gText_Birch_WhatsYourName); +@@ -2101,8 +2156,23 @@ static s8 NewGameBirchSpeech_ProcessGenderMenuInput(void) + { + return Menu_ProcessInputNoWrap(); + } + ++static void NewGameBirchSpeech_ShowNuzlockeMenu(void) ++{ ++ DrawMainMenuWindowBorder(&sNewGameBirchSpeechTextWindows[1], 0xF3); ++ FillWindowPixelBuffer(1, PIXEL_FILL(1)); ++ PrintMenuTable(1, ARRAY_COUNT(sMenuActions_Nuzlocke), sMenuActions_Nuzlocke); ++ InitMenuInUpperLeftCornerNormal(1, ARRAY_COUNT(sMenuActions_Nuzlocke), 1); ++ PutWindowTilemap(1); ++ CopyWindowToVram(1, COPYWIN_FULL); ++} ++ ++static s8 NewGameBirchSpeech_ProcessNuzlockeMenuInput(void) ++{ ++ return Menu_ProcessInputNoWrap(); ++} ++ + void NewGameBirchSpeech_SetDefaultPlayerName(u8 nameId) + { + const u8 *name; + u8 i; +@@ -2236,8 +2306,22 @@ static void NewGameBirchSpeech_ClearGenderWindow(u8 windowId, bool8 copyToVram) + if (copyToVram == TRUE) + CopyWindowToVram(windowId, COPYWIN_FULL); + } + ++static void NewGameBirchSpeech_ClearNuzlockeWindowTilemap(u8 bg, u8 x, u8 y, u8 width, u8 height, u8 unused) ++{ ++ FillBgTilemapBufferRect(bg, 0, x + 255, y + 255, width + 2, height + 2, 2); ++} ++ ++static void NewGameBirchSpeech_ClearNuzlockeWindow(u8 windowId, bool8 copyToVram) ++{ ++ CallWindowFunction(windowId, NewGameBirchSpeech_ClearNuzlockeWindowTilemap); ++ FillWindowPixelBuffer(windowId, PIXEL_FILL(1)); ++ ClearWindowTilemap(windowId); ++ if (copyToVram == TRUE) ++ CopyWindowToVram(windowId, COPYWIN_FULL); ++} ++ + static void NewGameBirchSpeech_ClearWindow(u8 windowId) + { + u8 bgColor = GetFontAttribute(FONT_NORMAL, FONTATTR_COLOR_BACKGROUND); + u8 maxCharWidth = GetFontAttribute(FONT_NORMAL, FONTATTR_MAX_LETTER_WIDTH); ----------------------------- data/event_scripts.s ----------------------------- index f2db321a5..9f0894b28 100644 @@ -883,8 +883,12 @@ gText_UnusedNicknameReceivedPokemon:: gText_PlayerWhitedOut:: .string "{PLAYER} is out of usable\n" - .string "POKéMON!\p{PLAYER} whited out!$" + .string "POKéMON!\p{PLAYER} whited out!$" +gText_PlayerNuzlockeFailed:: + .string "{PLAYER} failed the\n" @@ -51,7 +235,7 @@ index f2db321a5..9f0894b28 100644 index cce8cd59b..6351e1097 100644 @@ -415,8 +415,12 @@ PlayersHouse_1F_Text_DadShouldStayLonger: .string "He comes home for the first time in a\n" - .string "while, but all he talks about is POKéMON.\p" + .string "while, but all he talks about is POKéMON.\p" .string "He should relax and stay a little longer.$" +PlayersHouse_1F_Text_NuzlockeIsOver: @@ -145,45 +329,6 @@ index 359d619f1..341f170e9 100644 gText_Birch_WhatsYourName:: .string "All right.\n" .string "What's your name?$" - - ----------------------------- include/battle_setup.h ---------------------------- -index 5a1d5bab3..9126aeeb4 100644 -@@ -16,8 +16,9 @@ extern const struct RematchTrainer gRematchTable[REMATCH_TABLE_ENTRIES]; - - extern u16 gTrainerBattleOpponent_A; - extern u16 gTrainerBattleOpponent_B; - extern u16 gPartnerTrainerId; -+extern bool8 gNuzlockeCannotCatch; - - void BattleSetup_StartWildBattle(void); - void BattleSetup_StartBattlePikeWildBattle(void); - void BattleSetup_StartRoamerBattle(void); -@@ -62,8 +63,11 @@ u16 GetLastBeatenRematchTrainerId(u16 trainerId); - bool8 ShouldTryRematchBattle(void); - bool8 IsTrainerReadyForRematch(void); - void ShouldTryGetTrainerScript(void); - u16 CountBattledRematchTeams(u16 trainerId); -+bool8 HasWildPokmnOnThisRouteBeenSeen(u8 currLocation, bool8 setVarForThisEnc); -+u8 currLocConvertForNuzlocke(u8 currLocation); -+ - - void DoStandardWildBattle_Debug(void); - void BattleSetup_StartTrainerBattle_Debug(void); - - --------------------------- include/constants/battle.h -------------------------- -index 462fc3812..4dfa31cec 100644 -@@ -28,8 +28,9 @@ - #define B_POSITION_PLAYER_LEFT 0 - #define B_POSITION_OPPONENT_LEFT 1 - #define B_POSITION_PLAYER_RIGHT 2 - #define B_POSITION_OPPONENT_RIGHT 3 -+#define B_POSITION_NO_BATTLER 4 - - // These macros can be used with either battler ID or positions to get the partner or the opposite mon - #define BATTLE_OPPOSITE(id) ((id) ^ BIT_SIDE) - #define BATTLE_PARTNER(id) ((id) ^ BIT_FLANK) -------------------- include/constants/battle_string_ids.h -------------------- index 18d495d79..26cd431d1 100644 @@ -197,29 +342,7 @@ index 18d495d79..26cd431d1 100644 // todo: make some of those names less vague: attacker/target vs pkmn, etc. #define STRINGID_TRAINER1LOSETEXT 12 #define STRINGID_PKMNGAINEDEXP 13 - ---------------------------- include/constants/vars.h --------------------------- -index 7457d6236..214b80d1b 100644 -@@ -262,13 +262,13 @@ - #define VAR_SCOTT_FORTREE_CALL_STEP_COUNTER 0x40F3 - #define VAR_ROXANNE_CALL_STEP_COUNTER 0x40F4 - #define VAR_SCOTT_BF_CALL_STEP_COUNTER 0x40F5 - #define VAR_RIVAL_RAYQUAZA_CALL_STEP_COUNTER 0x40F6 --#define VAR_UNUSED_0x40F7 0x40F7 // Unused Var --#define VAR_UNUSED_0x40F8 0x40F8 // Unused Var --#define VAR_UNUSED_0x40F9 0x40F9 // Unused Var --#define VAR_UNUSED_0x40FA 0x40FA // Unused Var --#define VAR_UNUSED_0x40FB 0x40FB // Unused Var -+#define VAR_WILD_PKMN_ROUTE_SEEN_0 0x40F7 -+#define VAR_WILD_PKMN_ROUTE_SEEN_1 0x40F8 -+#define VAR_WILD_PKMN_ROUTE_SEEN_2 0x40F9 -+#define VAR_WILD_PKMN_ROUTE_SEEN_3 0x40FA -+#define VAR_WILD_PKMN_ROUTE_SEEN_4 0x40FB - #define VAR_UNUSED_0x40FC 0x40FC // Unused Var - #define VAR_UNUSED_0x40FD 0x40FD // Unused Var - #define VAR_UNUSED_0x40FE 0x40FE // Unused Var - #define VAR_UNUSED_0x40FF 0x40FF // Unused Var - + ------------------------------ include/strings.h ------------------------------ index 4ec286c8b..a209f5ae2 100644 @@ -345,8 +345,9 @@ extern const u8 gText_Birch_Welcome[]; @@ -271,7 +394,6 @@ index 54ff4d614..4f82d8d75 100644 else { gBattlescriptCurrInstr = BattleScript_LocalBattleLost; -+ DebugPrintf("FLAG_NUZLOCKE: %d", FlagGet(FLAG_NUZLOCKE)); + if (FlagGet(FLAG_NUZLOCKE) && FlagGet(FLAG_RECEIVED_POKEDEX_FROM_BIRCH)){ + gBattleMainFunc = BattleLostNuzlocke; + return; @@ -291,6 +413,213 @@ index 54ff4d614..4f82d8d75 100644 if (!(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_RECORDED_LINK +-------------------------------- src/strings.c -------------------------------- +index 0ee1a8896..69c4ccdbb 100644 +@@ -248,8 +248,9 @@ const u8 gText_RepelEffectsLingered[] = _("But the effects of a REPEL\nlingered + const u8 gText_UsedVar2WildLured[] = _("{PLAYER} used the\n{STR_VAR_2}.\pWild POKéMON will be lured.{PAUSE_UNTIL_PRESS}"); + const u8 gText_UsedVar2WildRepelled[] = _("{PLAYER} used the\n{STR_VAR_2}.\pWild POKéMON will be repelled.{PAUSE_UNTIL_PRESS}"); + const u8 gText_BoxFull[] = _("The BOX is full.{PAUSE_UNTIL_PRESS}"); + const u8 gText_PowderQty[] = _("POWDER QTY: {STR_VAR_1}{PAUSE_UNTIL_PRESS}"); ++const u8 gText_BallsCannotBeUsedNuz[] = _("You already saw a POKéMON\non {STR_VAR_1}!{PAUSE_UNTIL_PRESS}"); + const u8 gText_TheField[] = _("the field"); + const u8 gText_TheBattle[] = _("the battle"); + const u8 gText_ThePokemonList[] = _("the POKéMON LIST"); + const u8 gText_TheShop[] = _("the shop"); +@@ -374,8 +375,9 @@ const u8 gText_Read2[] = _("READ"); + const u8 gText_Trade4[] = _("TRADE"); + const u8 gText_HP3[] = _("HP"); + const u8 gText_SpAtk3[] = _("SP. ATK"); + const u8 gText_SpDef3[] = _("SP. DEF"); ++const u8 gText_WontHaveEffectNuzlocke[] = _("It won't have any effect due to\nrunning Nuzlocke challenge.{PAUSE_UNTIL_PRESS}"); + const u8 gText_WontHaveEffect[] = _("It won't have any effect.{PAUSE_UNTIL_PRESS}"); + const u8 gText_CantBeUsedOnPkmn[] = _("This can't be used on\nthat POKéMON.{PAUSE_UNTIL_PRESS}"); + const u8 gText_PkmnCantSwitchOut[] = _("{STR_VAR_1} can't be switched\nout!{PAUSE_UNTIL_PRESS}"); + const u8 gText_PkmnAlreadyInBattle[] = _("{STR_VAR_1} is already\nin battle!{PAUSE_UNTIL_PRESS}"); + + -------------------------------- src/new_game.c -------------------------------- +index a398d8457..dc7f8365b 100644 +@@ -152,8 +152,9 @@ void ResetMenuAndMonGlobals(void) + + void NewGameInitData(void) + { ++ bool8 nuzlockePrev = FlagGet(FLAG_NUZLOCKE); // A function lower down here clears this, so retain it and reset it at the end + if (gSaveFileStatus == SAVE_STATUS_EMPTY || gSaveFileStatus == SAVE_STATUS_CORRUPT) + RtcReset(); + + gDifferentSaveFile = TRUE; +@@ -211,8 +212,9 @@ void NewGameInitData(void) + WipeTrainerNameRecords(); + ResetTrainerHillResults(); + ResetContestLinkResults(); ++ nuzlockePrev ? FlagSet(FLAG_NUZLOCKE) : FlagClear(FLAG_NUZLOCKE); + } + ``` + +## Pokemon that Faint Cannot be Revived +```diff +------------------------------- src/party_menu.c ------------------------------- +index 9dfe5d306..3840ca57d 100755 +@@ -4435,9 +4435,9 @@ void ItemUseCB_Medicine(u8 taskId, TaskFunc task) + canHeal = IsHPRecoveryItem(item); + if (canHeal == TRUE) + { + hp = GetMonData(mon, MON_DATA_HP); + if (hp == GetMonData(mon, MON_DATA_MAX_HP)) + canHeal = FALSE; + } + cannotUse = ExecuteTableBasedItemEffect_(gPartyMenu.slotId, item, 0); + } +@@ -4445,9 +4445,12 @@ void ItemUseCB_Medicine(u8 taskId, TaskFunc task) + if (cannotUse != FALSE) + { + gPartyMenuUseExitCallback = FALSE; + PlaySE(SE_SELECT); +- DisplayPartyMenuMessage(gText_WontHaveEffect, TRUE); ++ if (canHeal && FlagGet(FLAG_NUZLOCKE) && GetMonData(mon, MON_DATA_DEAD)) ++ DisplayPartyMenuMessage(gText_WontHaveEffectNuzlocke, TRUE); ++ else ++ DisplayPartyMenuMessage(gText_WontHaveEffect, TRUE); + ScheduleBgCopyTilemapToVram(2); + gTasks[taskId].func = task; + } + else + +-------------------------------- src/pokemon.c -------------------------------- +index 67ae85f13..583a79d43 100644 +@@ -4150,13 +4150,15 @@ void SetBoxMonData(struct BoxPokemon *boxMon, s32 field, const void *dataArg) + break; + } + case MON_DATA_LANGUAGE: + dataLang = *data & 0x7F; +- boxMon->language = dataLang; ++ boxMon->language &= 0x80; ++ boxMon->language |= dataLang; + break; + case MON_DATA_DEAD: + dataLang = (*data << 7) & 0x80; +- boxMon->language = dataLang; ++ boxMon->language &= 0x7F; ++ boxMon->language |= dataLang; + break; + case MON_DATA_SANITY_IS_BAD_EGG: + SET8(boxMon->isBadEgg); + break; + +-------------------------- src/script_pokemon_util.c -------------------------- +index b18202096..056e1c5db 100755 +@@ -35,11 +35,19 @@ void HealPlayerParty(void) + + // restore HP. + for(i = 0; i < gPlayerPartyCount; i++) + { ++ u16 maxHP; ++ if (GetMonData(&gPlayerParty[i], MON_DATA_DEAD)){ ++ if (!FlagGet(FLAG_NUZLOCKE) || !FlagGet(FLAG_RECEIVED_POKEDEX_FROM_BIRCH)){ ++ bool8 dead = FALSE; ++ SetMonData(&gPlayerParty[i], MON_DATA_DEAD, &dead); ++ } ++ else{ ++ continue; ++ } ++ } + maxHP = GetMonData(&gPlayerParty[i], MON_DATA_MAX_HP); + arg[0] = maxHP; + arg[1] = maxHP >> 8; + SetMonData(&gPlayerParty[i], MON_DATA_HP, arg); + ppBonuses = GetMonData(&gPlayerParty[i], MON_DATA_PP_BONUSES); + +------------------------- src/battle_script_commands.c ------------------------- +index 7bbb5e186..adbe50754 100644 +@@ -2995,9 +2995,9 @@ static void Cmd_tryfaintmon(void) + BattleScriptPush(gBattlescriptCurrInstr + 7); + gBattlescriptCurrInstr = BS_ptr; + if (GetBattlerSide(gActiveBattler) == B_SIDE_PLAYER) + { ++ if (FlagGet(FLAG_NUZLOCKE) && FlagGet(FLAG_RECEIVED_POKEDEX_FROM_BIRCH)){ ++ bool8 dead = TRUE; ++ SetMonData(&gPlayerParty[gBattlerPartyIndexes[gActiveBattler]], MON_DATA_DEAD, &dead); ++ } + gHitMarker |= HITMARKER_PLAYER_FAINTED; + +--------------------------------- src/trade.c --------------------------------- +index a115d778d..d7454c35d 100644 +@@ -1556,8 +1556,9 @@ static void ConfirmOrCancelTrade(void) + { + switch (Menu_ProcessInputNoWrapClearOnChoose()) + { + case 0: // Confirm Trade + if (!CheckMonsBeforeTrade()) + sTradeMenuData->tradeMenuFunc = TRADEMENUFUNC_STANDBY; + else + sTradeMenuData->tradeMenuFunc = TRADEMENUFUNC_PARTNER_MON_INVALID; +@@ -3014,15 +3015,19 @@ static void TryEnableNationalDexFromLinkPartner(void) + + static void TradeMons(u8 playerPartyIdx, u8 partnerPartyIdx) + { + u8 friendship; ++ bool8 dead = FALSE; // Resets if Pokemon was considered dead through Nuzlocke + + struct Pokemon *playerMon = &gPlayerParty[playerPartyIdx]; + u16 playerMail = GetMonData(playerMon, MON_DATA_MAIL); + + struct Pokemon *partnerMon = &gEnemyParty[partnerPartyIdx]; + u16 partnerMail = GetMonData(partnerMon, MON_DATA_MAIL); + ++ SetMonData(playerMon, MON_DATA_DEAD, &dead); + if (playerMail != MAIL_NONE) + ClearMail(&gSaveBlock1Ptr->mail[playerMail]); + + SWAP(*playerMon, *partnerMon, sTradeData->tempMon); +``` + +## Can Only Catch First Pokemon +```diff +---------------------------- include/battle_setup.h ---------------------------- +index 5a1d5bab3..9126aeeb4 100644 +@@ -16,8 +16,9 @@ extern const struct RematchTrainer gRematchTable[REMATCH_TABLE_ENTRIES]; + + extern u16 gTrainerBattleOpponent_A; + extern u16 gTrainerBattleOpponent_B; + extern u16 gPartnerTrainerId; ++extern bool8 gNuzlockeCannotCatch; + + void BattleSetup_StartWildBattle(void); + void BattleSetup_StartBattlePikeWildBattle(void); + void BattleSetup_StartRoamerBattle(void); +@@ -62,8 +63,11 @@ u16 GetLastBeatenRematchTrainerId(u16 trainerId); + bool8 ShouldTryRematchBattle(void); + bool8 IsTrainerReadyForRematch(void); + void ShouldTryGetTrainerScript(void); + u16 CountBattledRematchTeams(u16 trainerId); ++bool8 HasWildPokmnOnThisRouteBeenSeen(u8 currLocation, bool8 setVarForThisEnc); ++u8 currLocConvertForNuzlocke(u8 currLocation); ++ + + void DoStandardWildBattle_Debug(void); + void BattleSetup_StartTrainerBattle_Debug(void); + +--------------------------- include/constants/vars.h --------------------------- +index 7457d6236..214b80d1b 100644 +@@ -262,13 +262,13 @@ + #define VAR_SCOTT_FORTREE_CALL_STEP_COUNTER 0x40F3 + #define VAR_ROXANNE_CALL_STEP_COUNTER 0x40F4 + #define VAR_SCOTT_BF_CALL_STEP_COUNTER 0x40F5 + #define VAR_RIVAL_RAYQUAZA_CALL_STEP_COUNTER 0x40F6 +-#define VAR_UNUSED_0x40F7 0x40F7 // Unused Var +-#define VAR_UNUSED_0x40F8 0x40F8 // Unused Var +-#define VAR_UNUSED_0x40F9 0x40F9 // Unused Var +-#define VAR_UNUSED_0x40FA 0x40FA // Unused Var +-#define VAR_UNUSED_0x40FB 0x40FB // Unused Var ++#define VAR_WILD_PKMN_ROUTE_SEEN_0 0x40F7 ++#define VAR_WILD_PKMN_ROUTE_SEEN_1 0x40F8 ++#define VAR_WILD_PKMN_ROUTE_SEEN_2 0x40F9 ++#define VAR_WILD_PKMN_ROUTE_SEEN_3 0x40FA ++#define VAR_WILD_PKMN_ROUTE_SEEN_4 0x40FB + #define VAR_UNUSED_0x40FC 0x40FC // Unused Var + #define VAR_UNUSED_0x40FD 0x40FD // Unused Var + #define VAR_UNUSED_0x40FE 0x40FE // Unused Var + #define VAR_UNUSED_0x40FF 0x40FF // Unused Var + ----------------------------- src/battle_message.c ----------------------------- index 0c31b6e2a..4b977a229 100644 @@ -27,8 +27,9 @@ @@ -306,7 +635,7 @@ index 0c31b6e2a..4b977a229 100644 @@ -77,8 +78,9 @@ static const u8 sText_AttackerFainted[] = _("{B_ATK_NAME_WITH_PREFIX}\nfainted!\ static const u8 sText_TargetFainted[] = _("{B_DEF_NAME_WITH_PREFIX}\nfainted!\p"); static const u8 sText_PlayerGotMoney[] = _("{B_PLAYER_NAME} got Â¥{B_BUFF1}\nfor winning!\p"); - static const u8 sText_PlayerWhiteout[] = _("{B_PLAYER_NAME} is out of\nusable POKéMON!\p"); + static const u8 sText_PlayerWhiteout[] = _("{B_PLAYER_NAME} is out of\nusable POKéMON!\p"); static const u8 sText_PlayerWhiteout2[] = _("{B_PLAYER_NAME} panicked and lost Â¥{B_BUFF1}…\p{B_PLAYER_NAME} whited out!{PAUSE_UNTIL_PRESS}"); +static const u8 sText_PlayerFailedNuzlocke[] = _("{B_PLAYER_NAME} failed the\nNuzlocke challenge.\pThe Nuzlocke setting\nhas been turned off.\p"); static const u8 sText_PreventsEscape[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX} prevents\nescape with {B_SCR_ACTIVE_ABILITY}!\p"); @@ -336,29 +665,6 @@ index 0c31b6e2a..4b977a229 100644 { gDisplayedStringBattle[0] = EOS; -------------------------- src/battle_script_commands.c ------------------------- -index 7bbb5e186..adbe50754 100644 -@@ -2995,9 +2995,9 @@ static void Cmd_tryfaintmon(void) - BattleScriptPush(gBattlescriptCurrInstr + 7); - gBattlescriptCurrInstr = BS_ptr; - if (GetBattlerSide(gActiveBattler) == B_SIDE_PLAYER) - { -- if (FlagGet(FLAG_NUZLOCKE)){ -+ if (FlagGet(FLAG_NUZLOCKE) && FlagGet(FLAG_RECEIVED_POKEDEX_FROM_BIRCH)){ - bool8 dead = TRUE; - SetMonData(&gPlayerParty[gBattlerPartyIndexes[gActiveBattler]], MON_DATA_DEAD, &dead); - } - gHitMarker |= HITMARKER_PLAYER_FAINTED; -@@ -10259,8 +10259,9 @@ static void Cmd_trainerslideout(void) - - static void Cmd_handlechangeodds(void) - { - u8 shakes = gBallShakesBData.shakes; -+ HasWildPokmnOnThisRouteBeenSeen(GetCurrentRegionMapSectionId(), TRUE); // If stealing a Pokemon, count it towards the Nuzlocke - if (shakes == BALL_3_SHAKES_SUCCESS) // mon caught, copy of the code above - { - if (gUsingThiefBall == THIEF_BALL_CATCHING){ - gUsingThiefBall = THIEF_BALL_CAUGHT; ------------------------------ src/battle_setup.c ------------------------------ index b503f8d65..36da06845 100644 @@ -801,43 +1107,6 @@ index b503f8d65..36da06845 100644 + } +} ---------------------------------- src/debug.c --------------------------------- -index b57c2dc68..e50265d7b 100644 -@@ -1800,9 +1800,10 @@ static void DebugAction_Util_PoisonMons(u8 taskId) - for (i = 0; i < PARTY_SIZE; i++) - { - if (GetMonData(&gPlayerParty[i], MON_DATA_SPECIES, 0) - && GetMonData(&gPlayerParty[i], MON_DATA_SPECIES2) != SPECIES_NONE -- && GetMonData(&gPlayerParty[i], MON_DATA_SPECIES2) != SPECIES_EGG) -+ && GetMonData(&gPlayerParty[i], MON_DATA_SPECIES2) != SPECIES_EGG -+ && GetMonData(&gPlayerParty[i], MON_DATA_HP) != 0) - { - u32 curStatus = STATUS1_POISON; - SetMonData(&gPlayerParty[i], MON_DATA_STATUS, &curStatus); - } - ------------------------------- src/field_poison.c ------------------------------ -index 4138bc9a2..b6f63427d 100644 -@@ -126,17 +126,18 @@ s32 DoPoisonFieldEffect(void) - if (GetMonData(pokemon, MON_DATA_SANITY_HAS_SPECIES) && GetAilmentFromStatus(GetMonData(pokemon, MON_DATA_STATUS)) == AILMENT_PSN) - { - // Apply poison damage - hp = GetMonData(pokemon, MON_DATA_HP); - if (hp == 0 || --hp == 0) - numFainted++; - - SetMonData(pokemon, MON_DATA_HP, &hp); -+ if (hp == 0){ -+ u32 status = STATUS1_NONE; -+ bool8 dead = (FlagGet(FLAG_NUZLOCKE) && FlagGet(FLAG_RECEIVED_POKEDEX_FROM_BIRCH)) ? TRUE : FALSE; //Uses to set or remove the Nuzlocke dead status in the field -+ SetMonData(pokemon, MON_DATA_DEAD, &dead); -+ SetMonData(pokemon, MON_DATA_STATUS, &status); -+ } - numPoisoned++; - } - pokemon++; - } - -------------------------------- src/item_use.c -------------------------------- index d663bbeb6..403ff54fa 100755 @@ -41,8 +41,10 @@ @@ -866,334 +1135,8 @@ index d663bbeb6..403ff54fa 100755 { RemoveBagItem(gSpecialVar_ItemId, 1); if (!InBattlePyramid()) - -------------------------------- src/main_menu.c ------------------------------- -index f99703622..75520e337 100644 -@@ -36,8 +36,9 @@ - #include "text_window.h" - #include "title_screen.h" - #include "window.h" - #include "mystery_gift_menu.h" -+#include "constants/flags.h" - - /* - * Main menu state machine - * ----------------------- -@@ -125,13 +126,18 @@ - * Task_NewGameBirchSpeech_WaitToShowGenderMenu - * Task_NewGameBirchSpeech_ChooseGender - * - Animates by advancing to Task_NewGameBirchSpeech_SlideOutOldGenderSprite - * whenever the player's selection changes. -- * - Advances to Task_NewGameBirchSpeech_WhatsYourName when done. -+ * - Advances to Task_NewGameBirchSpeech_Nuzlocke when done. - * - * Task_NewGameBirchSpeech_SlideOutOldGenderSprite - * Task_NewGameBirchSpeech_SlideInNewGenderSprite - * - Returns back to Task_NewGameBirchSpeech_ChooseGender. -+ * -+ * Task_NewGameBirchSpeech_Nuzlocke -+ * Task_NewGameBirchSpeech_WaitToShowNuzlockeMenu -+ * Task_NewGameBirchSpeech_ChooseNuzlocke -+ * Advances to Task_NewGameBirchSpeech_WhatsYourName when done. - * - * Task_NewGameBirchSpeech_WhatsYourName - * Task_NewGameBirchSpeech_WaitForWhatsYourNameToPrint - * Task_NewGameBirchSpeech_WaitPressBeforeNameChoice -@@ -208,16 +214,22 @@ static void NewGameBirchSpeech_StartFadePlatformIn(u8, u8); - static void Task_NewGameBirchSpeech_SlidePlatformAway(u8); - static void Task_NewGameBirchSpeech_StartPlayerFadeIn(u8); - static void Task_NewGameBirchSpeech_WaitForPlayerFadeIn(u8); - static void Task_NewGameBirchSpeech_BoyOrGirl(u8); -+static void Task_NewGameBirchSpeech_Nuzlocke(u8); - static void LoadMainMenuWindowFrameTiles(u8, u16); - static void DrawMainMenuWindowBorder(const struct WindowTemplate *, u16); - static void Task_HighlightSelectedMainMenuItem(u8); - static void Task_NewGameBirchSpeech_WaitToShowGenderMenu(u8); - static void Task_NewGameBirchSpeech_ChooseGender(u8); -+static void Task_NewGameBirchSpeech_WaitToShowNuzlockeMenu(u8); -+static void Task_NewGameBirchSpeech_ChooseNuzlocke(u8); - static void NewGameBirchSpeech_ShowGenderMenu(void); - static s8 NewGameBirchSpeech_ProcessGenderMenuInput(void); - static void NewGameBirchSpeech_ClearGenderWindow(u8, u8); -+static void NewGameBirchSpeech_ShowNuzlockeMenu(void); -+static s8 NewGameBirchSpeech_ProcessNuzlockeMenuInput(void); -+static void NewGameBirchSpeech_ClearNuzlockeWindow(u8, u8); - static void Task_NewGameBirchSpeech_WhatsYourName(u8); - static void Task_NewGameBirchSpeech_SlideOutOldGenderSprite(u8); - static void Task_NewGameBirchSpeech_SlideInNewGenderSprite(u8); - static void Task_NewGameBirchSpeech_WaitForWhatsYourNameToPrint(u8); -@@ -456,8 +468,13 @@ static const struct MenuAction sMenuActions_Gender[] = { - {gText_BirchBoy, NULL}, - {gText_BirchGirl, NULL} - }; - -+static const struct MenuAction sMenuActions_Nuzlocke[] = { -+ {gText_Yes, NULL}, -+ {gText_No, NULL} -+}; -+ - static const u8 *const sMalePresetNames[] = { - gText_DefaultNameStu, - gText_DefaultNameMilton, - gText_DefaultNameTom, -@@ -1507,15 +1524,15 @@ static void Task_NewGameBirchSpeech_ChooseGender(u8 taskId) - case MALE: - PlaySE(SE_SELECT); - gSaveBlock2Ptr->playerGender = gender; - NewGameBirchSpeech_ClearGenderWindow(1, 1); -- gTasks[taskId].func = Task_NewGameBirchSpeech_WhatsYourName; -+ gTasks[taskId].func = Task_NewGameBirchSpeech_Nuzlocke; - break; - case FEMALE: - PlaySE(SE_SELECT); - gSaveBlock2Ptr->playerGender = gender; - NewGameBirchSpeech_ClearGenderWindow(1, 1); -- gTasks[taskId].func = Task_NewGameBirchSpeech_WhatsYourName; -+ gTasks[taskId].func = Task_NewGameBirchSpeech_Nuzlocke; - break; - } - gender2 = Menu_GetCursorPos(); - if (gender2 != gTasks[taskId].tPlayerGender) -@@ -1569,8 +1586,46 @@ static void Task_NewGameBirchSpeech_SlideInNewGenderSprite(u8 taskId) - } - } - } - -+ -+static void Task_NewGameBirchSpeech_Nuzlocke(u8 taskId) -+{ -+ NewGameBirchSpeech_ClearWindow(0); -+ StringExpandPlaceholders(gStringVar4, gText_Birch_Nuzlocke); -+ AddTextPrinterForMessage(TRUE); -+ gTasks[taskId].func = Task_NewGameBirchSpeech_WaitToShowNuzlockeMenu; -+} -+ -+static void Task_NewGameBirchSpeech_WaitToShowNuzlockeMenu(u8 taskId) -+{ -+ if (!RunTextPrintersAndIsPrinter0Active()) -+ { -+ NewGameBirchSpeech_ShowNuzlockeMenu(); -+ gTasks[taskId].func = Task_NewGameBirchSpeech_ChooseNuzlocke; -+ } -+} -+ -+static void Task_NewGameBirchSpeech_ChooseNuzlocke(u8 taskId) -+{ -+ int nuzlocke = NewGameBirchSpeech_ProcessNuzlockeMenuInput(); -+ switch (nuzlocke) -+ { -+ case 0: -+ PlaySE(SE_SELECT); -+ FlagSet(FLAG_NUZLOCKE); -+ NewGameBirchSpeech_ClearNuzlockeWindow(1, 1); -+ gTasks[taskId].func = Task_NewGameBirchSpeech_WhatsYourName; -+ break; -+ case 1: -+ PlaySE(SE_SELECT); -+ FlagClear(FLAG_NUZLOCKE); -+ NewGameBirchSpeech_ClearNuzlockeWindow(1, 1); -+ gTasks[taskId].func = Task_NewGameBirchSpeech_WhatsYourName; -+ break; -+ } -+} -+ - static void Task_NewGameBirchSpeech_WhatsYourName(u8 taskId) - { - NewGameBirchSpeech_ClearWindow(0); - StringExpandPlaceholders(gStringVar4, gText_Birch_WhatsYourName); -@@ -2101,8 +2156,23 @@ static s8 NewGameBirchSpeech_ProcessGenderMenuInput(void) - { - return Menu_ProcessInputNoWrap(); - } - -+static void NewGameBirchSpeech_ShowNuzlockeMenu(void) -+{ -+ DrawMainMenuWindowBorder(&sNewGameBirchSpeechTextWindows[1], 0xF3); -+ FillWindowPixelBuffer(1, PIXEL_FILL(1)); -+ PrintMenuTable(1, ARRAY_COUNT(sMenuActions_Nuzlocke), sMenuActions_Nuzlocke); -+ InitMenuInUpperLeftCornerNormal(1, ARRAY_COUNT(sMenuActions_Nuzlocke), 1); -+ PutWindowTilemap(1); -+ CopyWindowToVram(1, COPYWIN_FULL); -+} -+ -+static s8 NewGameBirchSpeech_ProcessNuzlockeMenuInput(void) -+{ -+ return Menu_ProcessInputNoWrap(); -+} -+ - void NewGameBirchSpeech_SetDefaultPlayerName(u8 nameId) - { - const u8 *name; - u8 i; -@@ -2236,8 +2306,22 @@ static void NewGameBirchSpeech_ClearGenderWindow(u8 windowId, bool8 copyToVram) - if (copyToVram == TRUE) - CopyWindowToVram(windowId, COPYWIN_FULL); - } - -+static void NewGameBirchSpeech_ClearNuzlockeWindowTilemap(u8 bg, u8 x, u8 y, u8 width, u8 height, u8 unused) -+{ -+ FillBgTilemapBufferRect(bg, 0, x + 255, y + 255, width + 2, height + 2, 2); -+} -+ -+static void NewGameBirchSpeech_ClearNuzlockeWindow(u8 windowId, bool8 copyToVram) -+{ -+ CallWindowFunction(windowId, NewGameBirchSpeech_ClearNuzlockeWindowTilemap); -+ FillWindowPixelBuffer(windowId, PIXEL_FILL(1)); -+ ClearWindowTilemap(windowId); -+ if (copyToVram == TRUE) -+ CopyWindowToVram(windowId, COPYWIN_FULL); -+} -+ - static void NewGameBirchSpeech_ClearWindow(u8 windowId) - { - u8 bgColor = GetFontAttribute(FONT_NORMAL, FONTATTR_COLOR_BACKGROUND); - u8 maxCharWidth = GetFontAttribute(FONT_NORMAL, FONTATTR_MAX_LETTER_WIDTH); - -------------------------------- src/party_menu.c ------------------------------- -index 9dfe5d306..3840ca57d 100755 -@@ -4435,9 +4435,9 @@ void ItemUseCB_Medicine(u8 taskId, TaskFunc task) - canHeal = IsHPRecoveryItem(item); - if (canHeal == TRUE) - { - hp = GetMonData(mon, MON_DATA_HP); - if (hp == GetMonData(mon, MON_DATA_MAX_HP)) - canHeal = FALSE; - } - cannotUse = ExecuteTableBasedItemEffect_(gPartyMenu.slotId, item, 0); - } -@@ -4445,9 +4445,12 @@ void ItemUseCB_Medicine(u8 taskId, TaskFunc task) - if (cannotUse != FALSE) - { - gPartyMenuUseExitCallback = FALSE; - PlaySE(SE_SELECT); -- DisplayPartyMenuMessage(gText_WontHaveEffect, TRUE); -+ if (canHeal && FlagGet(FLAG_NUZLOCKE) && GetMonData(mon, MON_DATA_DEAD)) -+ DisplayPartyMenuMessage(gText_WontHaveEffectNuzlocke, TRUE); -+ else -+ DisplayPartyMenuMessage(gText_WontHaveEffect, TRUE); - ScheduleBgCopyTilemapToVram(2); - gTasks[taskId].func = task; - } - else - --------------------------------- src/pokemon.c -------------------------------- -index 67ae85f13..583a79d43 100644 -@@ -4150,13 +4150,15 @@ void SetBoxMonData(struct BoxPokemon *boxMon, s32 field, const void *dataArg) - break; - } - case MON_DATA_LANGUAGE: - dataLang = *data & 0x7F; -- boxMon->language = dataLang; -+ boxMon->language &= 0x80; -+ boxMon->language |= dataLang; - break; - case MON_DATA_DEAD: - dataLang = (*data << 7) & 0x80; -- boxMon->language = dataLang; -+ boxMon->language &= 0x7F; -+ boxMon->language |= dataLang; - break; - case MON_DATA_SANITY_IS_BAD_EGG: - SET8(boxMon->isBadEgg); - break; - --------------------------- src/script_pokemon_util.c -------------------------- -index b18202096..056e1c5db 100755 -@@ -35,11 +35,19 @@ void HealPlayerParty(void) - - // restore HP. - for(i = 0; i < gPlayerPartyCount; i++) - { -+ u16 maxHP; -+ if (GetMonData(&gPlayerParty[i], MON_DATA_DEAD)){ -+ if (!FlagGet(FLAG_NUZLOCKE) || !FlagGet(FLAG_RECEIVED_POKEDEX_FROM_BIRCH)){ -+ bool8 dead = FALSE; -+ SetMonData(&gPlayerParty[i], MON_DATA_DEAD, &dead); -+ } -+ else{ -+ continue; -+ } -+ } - maxHP = GetMonData(&gPlayerParty[i], MON_DATA_MAX_HP); - arg[0] = maxHP; - arg[1] = maxHP >> 8; - SetMonData(&gPlayerParty[i], MON_DATA_HP, arg); - ppBonuses = GetMonData(&gPlayerParty[i], MON_DATA_PP_BONUSES); - --------------------------------- src/strings.c -------------------------------- -index 0ee1a8896..69c4ccdbb 100644 -@@ -248,8 +248,9 @@ const u8 gText_RepelEffectsLingered[] = _("But the effects of a REPEL\nlingered - const u8 gText_UsedVar2WildLured[] = _("{PLAYER} used the\n{STR_VAR_2}.\pWild POKéMON will be lured.{PAUSE_UNTIL_PRESS}"); - const u8 gText_UsedVar2WildRepelled[] = _("{PLAYER} used the\n{STR_VAR_2}.\pWild POKéMON will be repelled.{PAUSE_UNTIL_PRESS}"); - const u8 gText_BoxFull[] = _("The BOX is full.{PAUSE_UNTIL_PRESS}"); - const u8 gText_PowderQty[] = _("POWDER QTY: {STR_VAR_1}{PAUSE_UNTIL_PRESS}"); -+const u8 gText_BallsCannotBeUsedNuz[] = _("You already saw a POKéMON\non {STR_VAR_1}!{PAUSE_UNTIL_PRESS}"); - const u8 gText_TheField[] = _("the field"); - const u8 gText_TheBattle[] = _("the battle"); - const u8 gText_ThePokemonList[] = _("the POKéMON LIST"); - const u8 gText_TheShop[] = _("the shop"); -@@ -374,8 +375,9 @@ const u8 gText_Read2[] = _("READ"); - const u8 gText_Trade4[] = _("TRADE"); - const u8 gText_HP3[] = _("HP"); - const u8 gText_SpAtk3[] = _("SP. ATK"); - const u8 gText_SpDef3[] = _("SP. DEF"); -+const u8 gText_WontHaveEffectNuzlocke[] = _("It won't have any effect due to\nrunning Nuzlocke challenge.{PAUSE_UNTIL_PRESS}"); - const u8 gText_WontHaveEffect[] = _("It won't have any effect.{PAUSE_UNTIL_PRESS}"); - const u8 gText_CantBeUsedOnPkmn[] = _("This can't be used on\nthat POKéMON.{PAUSE_UNTIL_PRESS}"); - const u8 gText_PkmnCantSwitchOut[] = _("{STR_VAR_1} can't be switched\nout!{PAUSE_UNTIL_PRESS}"); - const u8 gText_PkmnAlreadyInBattle[] = _("{STR_VAR_1} is already\nin battle!{PAUSE_UNTIL_PRESS}"); - ---------------------------------- src/trade.c --------------------------------- -index a115d778d..d7454c35d 100644 -@@ -1556,8 +1556,9 @@ static void ConfirmOrCancelTrade(void) - { - switch (Menu_ProcessInputNoWrapClearOnChoose()) - { - case 0: // Confirm Trade - if (!CheckMonsBeforeTrade()) - sTradeMenuData->tradeMenuFunc = TRADEMENUFUNC_STANDBY; - else - sTradeMenuData->tradeMenuFunc = TRADEMENUFUNC_PARTNER_MON_INVALID; -@@ -3014,15 +3015,19 @@ static void TryEnableNationalDexFromLinkPartner(void) - - static void TradeMons(u8 playerPartyIdx, u8 partnerPartyIdx) - { - u8 friendship; -+ bool8 dead = FALSE; // Resets if Pokemon was considered dead through Nuzlocke - - struct Pokemon *playerMon = &gPlayerParty[playerPartyIdx]; - u16 playerMail = GetMonData(playerMon, MON_DATA_MAIL); - - struct Pokemon *partnerMon = &gEnemyParty[partnerPartyIdx]; - u16 partnerMail = GetMonData(partnerMon, MON_DATA_MAIL); - -+ SetMonData(playerMon, MON_DATA_DEAD, &dead); - if (playerMail != MAIL_NONE) - ClearMail(&gSaveBlock1Ptr->mail[playerMail]); - - SWAP(*playerMon, *partnerMon, sTradeData->tempMon); - --------------------------------- src/new_game.c -------------------------------- -index a398d8457..dc7f8365b 100644 -@@ -152,8 +152,9 @@ void ResetMenuAndMonGlobals(void) - - void NewGameInitData(void) - { -+ bool8 nuzlockePrev = FlagGet(FLAG_NUZLOCKE); // A function lower down here clears this, so retain it and reset it at the end - if (gSaveFileStatus == SAVE_STATUS_EMPTY || gSaveFileStatus == SAVE_STATUS_CORRUPT) - RtcReset(); - - gDifferentSaveFile = TRUE; -@@ -211,8 +212,9 @@ void NewGameInitData(void) - WipeTrainerNameRecords(); - ResetTrainerHillResults(); - ResetContestLinkResults(); -+ nuzlockePrev ? FlagSet(FLAG_NUZLOCKE) : FlagClear(FLAG_NUZLOCKE); - } - ``` - ### Dupes Clause: ```diff ---------------------------- include/battle_setup.h ---------------------------- @@ -1273,7 +1216,7 @@ index 4b977a229..e6d5a871f 100644 @@ -78,9 +78,10 @@ static const u8 sText_AttackerFainted[] = _("{B_ATK_NAME_WITH_PREFIX}\nfainted!\ static const u8 sText_TargetFainted[] = _("{B_DEF_NAME_WITH_PREFIX}\nfainted!\p"); static const u8 sText_PlayerGotMoney[] = _("{B_PLAYER_NAME} got Â¥{B_BUFF1}\nfor winning!\p"); - static const u8 sText_PlayerWhiteout[] = _("{B_PLAYER_NAME} is out of\nusable POKéMON!\p"); + static const u8 sText_PlayerWhiteout[] = _("{B_PLAYER_NAME} is out of\nusable POKéMON!\p"); static const u8 sText_PlayerWhiteout2[] = _("{B_PLAYER_NAME} panicked and lost Â¥{B_BUFF1}…\p{B_PLAYER_NAME} whited out!{PAUSE_UNTIL_PRESS}"); -static const u8 sText_PlayerFailedNuzlocke[] = _("{B_PLAYER_NAME} failed the\nNuzlocke challenge.{PAUSE_UNTIL_PRESS}"); +static const u8 sText_PlayerFailedNuzlocke[] = _("{B_PLAYER_NAME} failed the\nNuzlocke challenge.\pThe Nuzlocke setting\nhas been turned off.\p"); @@ -1380,4 +1323,361 @@ index 403ff54fa..8e62af305 100755 DisplayItemMessage(taskId, FONT_NORMAL, gText_BallsCannotBeUsedNuz, CloseItemMessage); return; } -`` +``` + +## Can't Overlevel Leaders +```diff +------------------------------ src/battle_setup.c ------------------------------ +index 6e6f5886e..c5f9baa57 100644 +@@ -1957,8 +1957,44 @@ u16 CountBattledRematchTeams(u16 trainerId) + + return i; + } + ++bool8 levelCappedNuzlocke(u8 level){ ++ u8 levelCap = 0; ++ u16 nextLeader, i; ++ const struct TrainerMonItemCustomMoves *partyData; ++ if (!FlagGet(FLAG_NUZLOCKE)){ ++ return FALSE; ++ } ++ if (!FlagGet(FLAG_BADGE01_GET)) ++ nextLeader = TRAINER_ROXANNE_1; ++ else if (!FlagGet(FLAG_BADGE02_GET)) ++ nextLeader = TRAINER_BRAWLY_1; ++ else if (!FlagGet(FLAG_BADGE03_GET)) ++ nextLeader = TRAINER_WATTSON_1; ++ else if (!FlagGet(FLAG_BADGE04_GET)) ++ nextLeader = TRAINER_FLANNERY_1; ++ else if (!FlagGet(FLAG_BADGE05_GET)) ++ nextLeader = TRAINER_NORMAN_1; ++ else if (!FlagGet(FLAG_BADGE06_GET)) ++ nextLeader = TRAINER_WINONA_1; ++ else if (!FlagGet(FLAG_BADGE07_GET)) ++ nextLeader = TRAINER_TATE_AND_LIZA_1; ++ else if (!FlagGet(FLAG_BADGE08_GET)) ++ nextLeader = TRAINER_JUAN_1; ++ else if (!FlagGet(FLAG_IS_CHAMPION)) ++ nextLeader = TRAINER_WALLACE; ++ ++ partyData = gTrainers[nextLeader].party.ItemCustomMoves; ++ for (i = 0; i < gTrainers[nextLeader].partySize; i++){ ++ if (partyData[i].lvl > levelCap) ++ levelCap = partyData[i].lvl; ++ } ++ if (level >= levelCap) ++ return TRUE; ++ return FALSE; ++} ++ + u8 HasWildPokmnOnThisRouteBeenSeen(u8 currLocation, bool8 setVarForThisEnc){ + u8 varToCheck, bitToCheck; + u16 varValue; + const u16 pkmnSeenVars[] = { + +---------------------------- include/battle_setup.h ---------------------------- +index 5541cbac6..26e66761e 100644 +@@ -66,8 +66,9 @@ bool8 IsTrainerReadyForRematch(void); + void ShouldTryGetTrainerScript(void); + u16 CountBattledRematchTeams(u16 trainerId); + u8 HasWildPokmnOnThisRouteBeenSeen(u8 currLocation, bool8 setVarForThisEnc); + u8 currLocConvertForNuzlocke(u8 currLocation); ++bool8 levelCappedNuzlocke(u8 level); + + + void DoStandardWildBattle_Debug(void); + void BattleSetup_StartTrainerBattle_Debug(void); + +------------------------ src/battle_controller_player.c ------------------------ +index b7f9c9bd7..257b244ac 100644 +@@ -2793,9 +2793,10 @@ static void PlayerHandleHealthBarUpdate(void) + static void PlayerHandleExpUpdate(void) + { + u8 monId = gBattleBufferA[gActiveBattler][1]; + +- if (GetMonData(&gPlayerParty[monId], MON_DATA_LEVEL) >= MAX_LEVEL) ++ if (GetMonData(&gPlayerParty[monId], MON_DATA_LEVEL) >= MAX_LEVEL ++ || levelCappedNuzlocke(GetMonData(&gPlayerParty[monId], MON_DATA_LEVEL))) + { + PlayerBufferExecCompleted(); + } + else + +-------------------- src/battle_controller_player_partner.c -------------------- +index 99cfa5e1e..bf5aa3b65 100644 +@@ -1593,9 +1593,10 @@ static void PlayerPartnerHandleHealthBarUpdate(void) + static void PlayerPartnerHandleExpUpdate(void) + { + u8 monId = gBattleBufferA[gActiveBattler][1]; + +- if (GetMonData(&gPlayerParty[monId], MON_DATA_LEVEL) >= MAX_LEVEL) ++ if (GetMonData(&gPlayerParty[monId], MON_DATA_LEVEL) >= MAX_LEVEL ++ || levelCappedNuzlocke(GetMonData(&gPlayerParty[monId], MON_DATA_LEVEL))) + { + PlayerPartnerBufferExecCompleted(); + } + else + +---------------------------- src/battle_interface.c ---------------------------- +index fd1e78dcd..7afa4ad61 100644 +@@ -26,8 +26,9 @@ + #include "constants/battle_anim.h" + #include "constants/rgb.h" + #include "constants/songs.h" + #include "constants/items.h" ++#include "battle_setup.h" + + struct TestingBar + { + s32 maxValue; +@@ -2324,9 +2325,9 @@ static void MoveBattleBarGraphically(u8 battlerId, u8 whichBar) + gBattleSpritesDataPtr->battleBars[battlerId].receivedValue, + &gBattleSpritesDataPtr->battleBars[battlerId].currValue, + array, B_EXPBAR_PIXELS / 8); + level = GetMonData(&gPlayerParty[gBattlerPartyIndexes[battlerId]], MON_DATA_LEVEL); +- if (level == MAX_LEVEL) ++ if (level == MAX_LEVEL || levelCappedNuzlocke(level)) + { + for (i = 0; i < 8; i++) + array[i] = 0; + } + +------------------------- src/battle_script_commands.c ------------------------- +index e6e0721e1..f73cae167 100644 +@@ -3345,9 +3363,11 @@ static void Cmd_getexp(void) + *(&gBattleStruct->sentInPokes) >>= 1; + gBattleScripting.getexpState = 5; + gBattleMoveDamage = 0; // used for exp + } +- else if (GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_LEVEL) == MAX_LEVEL) ++ else if (GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_LEVEL) == MAX_LEVEL ++ || levelCappedNuzlocke(GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_LEVEL)) ++ || VarGet(VAR_EXP_MULT) == 4) + { + *(&gBattleStruct->sentInPokes) >>= 1; + gBattleScripting.getexpState = 5; + gBattleMoveDamage = 0; // used for exp +@@ -3428,9 +3448,10 @@ static void Cmd_getexp(void) + case 3: // Set stats and give exp + if (gBattleControllerExecFlags == 0) + { + gBattleBufferB[gBattleStruct->expGetterBattlerId][0] = 0; +- if (GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_HP) && GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_LEVEL) != MAX_LEVEL) ++ if (GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_HP) && GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_LEVEL) != MAX_LEVEL ++ && !levelCappedNuzlocke(GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_LEVEL))) + { + gBattleResources->beforeLvlUp->stats[STAT_HP] = GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_MAX_HP); + gBattleResources->beforeLvlUp->stats[STAT_ATK] = GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_ATK); + gBattleResources->beforeLvlUp->stats[STAT_DEF] = GetMonData(&gPlayerParty[gBattleStruct->expGetterMonId], MON_DATA_DEF); + +-------------------------------- src/daycare.c -------------------------------- +index 7119941b9..b820e207c 100644 +@@ -21,8 +21,9 @@ + #include "overworld.h" + #include "constants/items.h" + #include "constants/moves.h" + #include "constants/region_map_sections.h" ++#include "battle_setup.h" + + extern const struct Evolution gEvolutionTable[][EVOS_PER_MON]; + + static void ClearDaycareMonMail(struct DaycareMail *mail); +@@ -253,9 +254,10 @@ static u16 TakeSelectedPokemonFromDaycare(struct DaycareMon *daycareMon) + GetBoxMonNickname(&daycareMon->mon, gStringVar1); + species = GetBoxMonData(&daycareMon->mon, MON_DATA_SPECIES); + BoxMonToMon(&daycareMon->mon, &pokemon); + +- if (GetMonData(&pokemon, MON_DATA_LEVEL) != MAX_LEVEL) ++ if (GetMonData(&pokemon, MON_DATA_LEVEL) != MAX_LEVEL ++ && !levelCappedNuzlocke(GetMonData(&pokemon, MON_DATA_LEVEL))) + { + experience = GetMonData(&pokemon, MON_DATA_EXP) + (stepMult * daycareMon->steps); + SetMonData(&pokemon, MON_DATA_EXP, &experience); + ApplyDaycareExperience(&pokemon); + +------------------------------- src/party_menu.c ------------------------------- +index 55a0ea68b..802398bd7 100755 +@@ -72,8 +72,9 @@ + #include "constants/party_menu.h" + #include "constants/rgb.h" + #include "constants/songs.h" + #include "naming_screen.h" ++#include "battle_setup.h" + + enum { + MENU_SUMMARY, + MENU_SWITCH, +@@ -5004,9 +5005,10 @@ void ItemUseCB_RareCandy(u8 taskId, TaskFunc task) + s16 *arrayPtr = ptr->data; + u16 *itemPtr = &gSpecialVar_ItemId; + bool8 cannotUseEffect; + +- if (GetMonData(mon, MON_DATA_LEVEL) != MAX_LEVEL) ++ if (GetMonData(mon, MON_DATA_LEVEL) != MAX_LEVEL ++ && !levelCappedNuzlocke(GetMonData(mon, MON_DATA_LEVEL))) + { + BufferMonStatsToTaskData(mon, arrayPtr); + cannotUseEffect = ExecuteTableBasedItemEffect_(gPartyMenu.slotId, *itemPtr, 0); + BufferMonStatsToTaskData(mon, &ptr->data[NUM_STATS]); + +-------------------------------- src/pokemon.c -------------------------------- +index e92bba303..efad1c4d4 100644 +@@ -4907,9 +4907,10 @@ bool8 PokemonUseItemEffects(struct Pokemon *mon, u16 item, u8 partyIndex, u8 mov + } + + // Rare Candy + if ((itemEffect[i] & ITEM3_LEVEL_UP) +- && GetMonData(mon, MON_DATA_LEVEL, NULL) != MAX_LEVEL) ++ && GetMonData(mon, MON_DATA_LEVEL, NULL) != MAX_LEVEL ++ && !levelCappedNuzlocke(GetMonData(mon, MON_DATA_LEVEL, NULL))) + { + dataUnsigned = gExperienceTables[gSpeciesInfo[GetMonData(mon, MON_DATA_SPECIES, NULL)].growthRate][GetMonData(mon, MON_DATA_LEVEL, NULL) + 1]; + SetMonData(mon, MON_DATA_EXP, &dataUnsigned); + CalculateMonStats(mon); + +------------------------- src/pokemon_summary_screen.c ------------------------- +index 2b522ebea..b94bbc344 100644 +@@ -45,8 +45,9 @@ + #include "constants/party_menu.h" + #include "constants/region_map_sections.h" + #include "constants/rgb.h" + #include "constants/songs.h" ++#include "battle_setup.h" + + enum { + PSS_PAGE_INFO, + PSS_PAGE_SKILLS, +@@ -2609,9 +2610,9 @@ static void DrawExperienceProgressBar(struct Pokemon *unused) + struct PokeSummary *summary = &sMonSummaryScreen->summary; + u16 *dst; + u8 i; + +- if (summary->level < MAX_LEVEL) ++ if (summary->level < MAX_LEVEL && !levelCappedNuzlocke(summary->level)) + { + u32 expBetweenLevels = gExperienceTables[gSpeciesInfo[summary->species].growthRate][summary->level + 1] - gExperienceTables[gSpeciesInfo[summary->species].growthRate][summary->level]; + u32 expSinceLastLevel = summary->exp - gExperienceTables[gSpeciesInfo[summary->species].growthRate][summary->level]; + +@@ -3411,9 +3412,9 @@ static void PrintExpPointsNextLevel(void) + ConvertIntToDecimalStringN(gStringVar1, sum->exp, STR_CONV_MODE_RIGHT_ALIGN, 7); + x = GetStringRightAlignXOffset(FONT_NORMAL, gStringVar1, 42) + 2; + PrintTextOnWindow(windowId, gStringVar1, x, 1, 0, 0); + +- if (sum->level < MAX_LEVEL) ++ if (sum->level < MAX_LEVEL && !levelCappedNuzlocke(sum->level)) + expToNextLevel = gExperienceTables[gSpeciesInfo[sum->species].growthRate][sum->level + 1] - sum->exp; + else + expToNextLevel = 0; +``` + +## No Held Items +```diff +------------------------------ src/battle_util.c ------------------------------ +index 7a0ebda61..7e4c2bc0f 100644 +@@ -3243,8 +3243,11 @@ u8 ItemBattleEffects(u8 caseID, u8 battlerId, bool8 moveTurn) + u8 battlerHoldEffect, atkHoldEffect, defHoldEffect; + u8 battlerHoldEffectParam, atkHoldEffectParam, defHoldEffectParam; + u16 atkItem, defItem; + ++ if (GetBattlerSide(battlerId) == B_SIDE_PLAYER && FlagGet(FLAG_NUZLOCKE)) ++ return ITEM_NO_EFFECT; ++ + gLastUsedItem = gBattleMons[battlerId].item; + if (gLastUsedItem == ITEM_ENIGMA_BERRY) + { + battlerHoldEffect = gEnigmaBerries[battlerId].holdEffect; +``` + +## No Battle Items +```diff +------------------------------- src/item_menu.c ------------------------------- +index da0369c12..5d4cc7cbc 100755 +@@ -1532,9 +1532,10 @@ static void OpenContextMenu(u8 taskId) + switch (gBagPosition.location) + { + case ITEMMENULOCATION_BATTLE: + case ITEMMENULOCATION_WALLY: +- if (ItemId_GetBattleUsage(gSpecialVar_ItemId)) ++ if (ItemId_GetBattleUsage(gSpecialVar_ItemId) && (!FlagGet(FLAG_NUZLOCKE) ++ || gBagPosition.pocket == BALLS_POCKET || gBagPosition.location != ITEMMENULOCATION_BATTLE)) + { + gBagMenu->contextMenuItemsPtr = sContextMenuItems_BattleUse; + gBagMenu->contextMenuNumItems = ARRAY_COUNT(sContextMenuItems_BattleUse); + } +@@ -1650,9 +1651,13 @@ static void OpenContextMenu(u8 taskId) + } + else + { + CopyItemName(gSpecialVar_ItemId, gStringVar1); +- StringExpandPlaceholders(gStringVar4, gText_Var1IsSelected); ++ if (ItemId_GetBattleUsage(gSpecialVar_ItemId) && FlagGet(FLAG_NUZLOCKE) ++ && gBagPosition.pocket != BALLS_POCKET && gBagPosition.location == ITEMMENULOCATION_BATTLE) ++ StringExpandPlaceholders(gStringVar4, gText_Var1NuzlockePrevents); ++ else ++ StringExpandPlaceholders(gStringVar4, gText_Var1IsSelected); + FillWindowPixelBuffer(WIN_DESCRIPTION, PIXEL_FILL(0)); + BagMenu_Print(WIN_DESCRIPTION, FONT_NORMAL, gStringVar4, 3, 1, 0, 0, 0, COLORID_NORMAL); + } + if (gBagMenu->contextMenuNumItems == 1) + +------------------------------ include/strings.h ------------------------------ +index 52097f4fe..59263096a 100644 +@@ -434,8 +434,9 @@ extern const u8 gText_xVar1[]; + extern const u8 gText_ReturnToVar1[]; + extern const u8 gText_SelectorArrow2[]; + extern const u8 gText_MoveVar1Where[]; + extern const u8 gText_Var1IsSelected[]; ++extern const u8 gText_Var1NuzlockePrevents[]; + extern const u8 gText_TossHowManyVar1s[]; + extern const u8 gText_ConfirmTossItems[]; + extern const u8 gText_ThrewAwayVar2Var1s[]; + extern const u8 gText_CantWriteMail[]; + +-------------------------------- src/strings.c -------------------------------- +index 41441d6cd..399052cfb 100644 +@@ -220,8 +220,9 @@ const u8 gText_xVar1[] = _("×{STR_VAR_1}"); + const u8 gText_Berry2[] = _(" BERRY"); // Unused + const u8 gText_Coins[] = _("{STR_VAR_1} COINS"); + const u8 gText_CloseBag[] = _("CLOSE BAG"); + const u8 gText_Var1IsSelected[] = _("{STR_VAR_1} is\nselected."); ++const u8 gText_Var1NuzlockePrevents[] = _("Nuzlocke prevents\nusing {STR_VAR_1}."); + const u8 gText_CantWriteMail[] = _("You can't write\nMAIL here."); + const u8 gText_NoPokemon[] = _("There is no\nPOKéMON."); + const u8 gText_MoveVar1Where[] = _("Move the\n{STR_VAR_1}\nwhere?"); + const u8 gText_Var1CantBeHeld[] = _("The {STR_VAR_1} can't be held."); +``` + +## Force Set Mode +```diff +------------------------------ src/battle_main.c ------------------------------ +index fc00c2ee5..838c6ecf9 100644 +@@ -3184,9 +3184,9 @@ static void BattleStartClearSetData(void) + } + else if (!(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_RECORDED_LINK)) && GetBattleSceneInRecordedBattle()) + gHitMarker |= HITMARKER_NO_ANIMATIONS; + +- gBattleScripting.battleStyle = gSaveBlock2Ptr->optionsBattleStyle; ++ gBattleScripting.battleStyle = gSaveBlock2Ptr->optionsBattleStyle || FlagGet(FLAG_NUZLOCKE)); + + gMultiHitCounter = 0; + gBattleOutcome = 0; + gBattleControllerExecFlags = 0; + +------------------------------ src/option_menu.c ------------------------------ +index d69320b14..09736d410 100644 +@@ -504,8 +504,14 @@ static void BattleStyle_DrawChoices(u8 selection) + u8 styles[2]; + + styles[0] = 0; + styles[1] = 0; ++ ++ if (FlagGet(FLAG_NUZLOCKE)){ ++ styles[1] = 1; ++ DrawOptionMenuChoice(gText_BattleStyleSet, 104, YPOS_BATTLESTYLE, styles[1]); ++ return; ++ } + styles[selection] = 1; + + DrawOptionMenuChoice(gText_BattleStyleShift, 104, YPOS_BATTLESTYLE, styles[0]); + DrawOptionMenuChoice(gText_BattleStyleSet, GetStringRightAlignXOffset(FONT_SHORT, gText_BattleStyleSet, 198), YPOS_BATTLESTYLE, styles[1]); +```