Dupes clause cleanup and Nurse Joy message

voloved 2023-08-12 08:20:05 -04:00
parent f49de07bca
commit 8f5ca9fe8d
1 changed files with 127 additions and 131 deletions

@ -5,6 +5,8 @@ By devolov
![pokeemerald-0](https://user-images.githubusercontent.com/36523934/211448320-efa34b1d-554a-491e-8f07-0cd2a10dcf60.png) ![pokeemerald-0](https://user-images.githubusercontent.com/36523934/211448320-efa34b1d-554a-491e-8f07-0cd2a10dcf60.png)
![pokeemerald-1](https://user-images.githubusercontent.com/36523934/211448331-82a7bde1-80eb-4db8-ab12-93611380b1cb.png) ![pokeemerald-1](https://user-images.githubusercontent.com/36523934/211448331-82a7bde1-80eb-4db8-ab12-93611380b1cb.png)
![pokeemerald-2](https://user-images.githubusercontent.com/36523934/211448326-8184ca37-0a5b-4cbf-b484-a4c9e45deeb2.png) ![pokeemerald-2](https://user-images.githubusercontent.com/36523934/211448326-8184ca37-0a5b-4cbf-b484-a4c9e45deeb2.png)
![pokeemerald_modern-0](https://github.com/pret/pokeemerald/assets/36523934/f87c96ac-6015-4cf8-a60f-88346b5482a3)
The rules for the Nuzlocke challenge: The rules for the Nuzlocke challenge:
* [If a Pokemon faints, they cannot be revived.](#pokemon-that-faint-cannot-be-revived) * [If a Pokemon faints, they cannot be revived.](#pokemon-that-faint-cannot-be-revived)
@ -12,6 +14,7 @@ The rules for the Nuzlocke challenge:
* Optional: * Optional:
* [Dupes Clause](#Dupes-Clause) * [Dupes Clause](#Dupes-Clause)
* [Can't Overlevel Leaders](#Cant-Overlevel-Leaders) * [Can't Overlevel Leaders](#Cant-Overlevel-Leaders)
* [Have Nurse Joy Tell You the Level Cap](#have-nurse-joy-tell-you-the-level-cap)
* [No Held Items](#no-held-items) * [No Held Items](#no-held-items)
* [No Battle Items](#no-battle-items) * [No Battle Items](#no-battle-items)
* [Force Set Mode](#force-set-mode) * [Force Set Mode](#force-set-mode)
@ -229,7 +232,7 @@ index f2db321a5..9f0894b28 100644
+ +
gText_RegisteredTrainerinPokeNav:: gText_RegisteredTrainerinPokeNav::
.string "Registered {STR_VAR_1} {STR_VAR_2}\n" .string "Registered {STR_VAR_1} {STR_VAR_2}\n"
.string "in the POKéNAV.$" .string "in the POKéNAV.$"
------------ data/maps/LittlerootTown_BrendansHouse_1F/scripts.inc ------------ ------------ data/maps/LittlerootTown_BrendansHouse_1F/scripts.inc ------------
@ -408,7 +411,7 @@ index 54ff4d614..4f82d8d75 100644
static void HandleEndTurn_FinishBattle(void) static void HandleEndTurn_FinishBattle(void)
{ {
+ gNuzlockeCannotCatch = FALSE; // While not necissary, resetting this is nice to stay deterministic + gNuzlockeCannotCatch = 0; // While not necissary, resetting this is nice to stay deterministic
if (gCurrentActionFuncId == B_ACTION_TRY_FINISH || gCurrentActionFuncId == B_ACTION_FINISHED) if (gCurrentActionFuncId == B_ACTION_TRY_FINISH || gCurrentActionFuncId == B_ACTION_FINISHED)
{ {
if (!(gBattleTypeFlags & (BATTLE_TYPE_LINK if (!(gBattleTypeFlags & (BATTLE_TYPE_LINK
@ -622,7 +625,7 @@ index 5a1d5bab3..9126aeeb4 100644
bool8 IsTrainerReadyForRematch(void); bool8 IsTrainerReadyForRematch(void);
void ShouldTryGetTrainerScript(void); void ShouldTryGetTrainerScript(void);
u16 CountBattledRematchTeams(u16 trainerId); u16 CountBattledRematchTeams(u16 trainerId);
+bool8 HasWildPokmnOnThisRouteBeenSeen(u8 currLocation, bool8 setVarForThisEnc); +u8 HasWildPokmnOnThisRouteBeenSeen(u8 currLocation, bool8 setVarForThisEnc);
+u8 currLocConvertForNuzlocke(u8 currLocation); +u8 currLocConvertForNuzlocke(u8 currLocation);
+ +
@ -746,7 +749,7 @@ index b503f8d65..36da06845 100644
return i; return i;
} }
+ +
+bool8 HasWildPokmnOnThisRouteBeenSeen(u8 currLocation, bool8 setVarForThisEnc){ +u8 HasWildPokmnOnThisRouteBeenSeen(u8 currLocation, bool8 setVarForThisEnc){
+ u8 varToCheck, bitToCheck; + u8 varToCheck, bitToCheck;
+ u16 varValue; + u16 varValue;
+ const u16 pkmnSeenVars[] = { + const u16 pkmnSeenVars[] = {
@ -763,7 +766,7 @@ index b503f8d65..36da06845 100644
+ VarSet(VAR_WILD_PKMN_ROUTE_SEEN_2, 0); + VarSet(VAR_WILD_PKMN_ROUTE_SEEN_2, 0);
+ VarSet(VAR_WILD_PKMN_ROUTE_SEEN_3, 0); + VarSet(VAR_WILD_PKMN_ROUTE_SEEN_3, 0);
+ VarSet(VAR_WILD_PKMN_ROUTE_SEEN_4, 0); + VarSet(VAR_WILD_PKMN_ROUTE_SEEN_4, 0);
+ return FALSE; + return 0;
+ } + }
+ switch (currLocation) + switch (currLocation)
+ { + {
@ -1072,16 +1075,16 @@ index b503f8d65..36da06845 100644
+ varToCheck = 4; + varToCheck = 4;
+ bitToCheck = 10; + bitToCheck = 10;
+ default: + default:
+ return FALSE; + return 0;
+ } + }
+ varValue = VarGet(pkmnSeenVars[varToCheck]); + varValue = VarGet(pkmnSeenVars[varToCheck]);
+ if ((varValue & (1 << bitToCheck)) != 0){ + if ((varValue & (1 << bitToCheck)) != 0){
+ return TRUE; + return 1;
+ } + }
+ else if (setVarForThisEnc){ + else if (setVarForThisEnc){
+ VarSet(pkmnSeenVars[varToCheck], varValue | (1 << bitToCheck)); + VarSet(pkmnSeenVars[varToCheck], varValue | (1 << bitToCheck));
+ } + }
+ return FALSE; + return 0;
+} +}
+ +
+u8 currLocConvertForNuzlocke(u8 currLocation){ +u8 currLocConvertForNuzlocke(u8 currLocation){
@ -1156,8 +1159,8 @@ index d663bbeb6..403ff54fa 100755
return; return;
} }
#endif #endif
-
+ if (gNuzlockeCannotCatch){ + if (gNuzlockeCannotCatch == 1){
+ GetMapNameHandleAquaHideout(gStringVar1, currLocConvertForNuzlocke(GetCurrentRegionMapSectionId())); + GetMapNameHandleAquaHideout(gStringVar1, currLocConvertForNuzlocke(GetCurrentRegionMapSectionId()));
+ DisplayItemMessage(taskId, FONT_NORMAL, gText_BallsCannotBeUsedNuz, CloseItemMessage); + DisplayItemMessage(taskId, FONT_NORMAL, gText_BallsCannotBeUsedNuz, CloseItemMessage);
+ return; + return;
@ -1170,31 +1173,6 @@ index d663bbeb6..403ff54fa 100755
### Dupes Clause: ### Dupes Clause:
```diff ```diff
---------------------------- include/battle_setup.h ----------------------------
index 9126aeeb4..feaa30c00 100644
@@ -16,9 +16,9 @@ extern const struct RematchTrainer gRematchTable[REMATCH_TABLE_ENTRIES];
extern u16 gTrainerBattleOpponent_A;
extern u16 gTrainerBattleOpponent_B;
extern u16 gPartnerTrainerId;
-extern bool8 gNuzlockeCannotCatch;
+extern u8 gNuzlockeCannotCatch;
void BattleSetup_StartWildBattle(void);
void BattleSetup_StartBattlePikeWildBattle(void);
void BattleSetup_StartRoamerBattle(void);
@@ -63,9 +63,9 @@ u16 GetLastBeatenRematchTrainerId(u16 trainerId);
bool8 ShouldTryRematchBattle(void);
bool8 IsTrainerReadyForRematch(void);
void ShouldTryGetTrainerScript(void);
u16 CountBattledRematchTeams(u16 trainerId);
-bool8 HasWildPokmnOnThisRouteBeenSeen(u8 currLocation, bool8 setVarForThisEnc);
+u8 HasWildPokmnOnThisRouteBeenSeen(u8 currLocation, bool8 setVarForThisEnc);
u8 currLocConvertForNuzlocke(u8 currLocation);
void DoStandardWildBattle_Debug(void);
-------------------- include/constants/battle_string_ids.h -------------------- -------------------- include/constants/battle_string_ids.h --------------------
index 26cd431d1..f96aa3333 100644 index 26cd431d1..f96aa3333 100644
@@ -7,8 +7,9 @@ @@ -7,8 +7,9 @@
@ -1211,37 +1189,33 @@ index 26cd431d1..f96aa3333 100644
------------------------------ src/battle_main.c ------------------------------ ------------------------------ src/battle_main.c ------------------------------
index fd3986fe8..4d534b447 100644 index fd3986fe8..4d534b447 100644
@@ -3675,12 +3675,18 @@ static void BattleIntroPrintWildMonAttacked(void) @@ -3675,12 +3675,18 @@ static void BattleIntroPrintWildMonAttacked(void)
static void BattleIntroQuickRun(void) static void BattleIntroPrintWildMonAttacked(void)
{ {
if (gBattleControllerExecFlags == 0) if (gBattleControllerExecFlags == 0)
{ {
- if (JOY_HELD(DPAD_RIGHT)) - gBattleMainFunc = BattleIntroPrintPlayerSendsOut;
+ if (JOY_HELD(DPAD_RIGHT)){ + gBattleMainFunc = BattleIntroNuzlockDups;
gBattleMainFunc = HandleEndTurn_RanFromBattle; PrepareStringBattle(STRINGID_INTROMSG, 0);
- else }
+ } }
+ else{
+ u16 species_enemy = GetMonData(&gEnemyParty[gBattlerPartyIndexes[GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT)]], MON_DATA_SPECIES2); +static void BattleIntroNuzlockDups(void)
gBattleMainFunc = BattleIntroPrintPlayerSendsOut; +{
+ if (gBattleControllerExecFlags == 0)
+ {
+ if (gNuzlockeCannotCatch == 2){ // If Pokemon was first in this route and was already caught + if (gNuzlockeCannotCatch == 2){ // If Pokemon was first in this route and was already caught
+ PrepareStringBattle(STRINGID_NUZLOCKEDUPS, 0); + PrepareStringBattle(STRINGID_NUZLOCKEDUPS, 0);
+ } + }
+ gBattleMainFunc = BattleIntroPrintPlayerSendsOut;
+ } + }
} +}
} +
static void BattleIntroPrintOpponentSendsOut(void)
@@ -5204,9 +5211,9 @@ static void HandleEndTurn_MonFled(void) {
} u32 position;
static void HandleEndTurn_FinishBattle(void)
{
- gNuzlockeCannotCatch = FALSE; // While not necissary, resetting this is nice to stay deterministic
+ gNuzlockeCannotCatch = 0; // While not necissary, resetting this is nice to stay deterministic
if (gCurrentActionFuncId == B_ACTION_TRY_FINISH || gCurrentActionFuncId == B_ACTION_FINISHED)
{
if (!(gBattleTypeFlags & (BATTLE_TYPE_LINK
| BATTLE_TYPE_RECORDED_LINK
if (gBattleControllerExecFlags)
return;
----------------------------- src/battle_message.c ----------------------------- ----------------------------- src/battle_message.c -----------------------------
index 4b977a229..e6d5a871f 100644 index 4b977a229..e6d5a871f 100644
@@ -78,9 +78,10 @@ static const u8 sText_AttackerFainted[] = _("{B_ATK_NAME_WITH_PREFIX}\nfainted!\ @@ -78,9 +78,10 @@ static const u8 sText_AttackerFainted[] = _("{B_ATK_NAME_WITH_PREFIX}\nfainted!\
@ -1249,8 +1223,7 @@ index 4b977a229..e6d5a871f 100644
static const u8 sText_PlayerGotMoney[] = _("{B_PLAYER_NAME} got ¥{B_BUFF1}\nfor winning!\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_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");
+static const u8 sText_PlayerFailedNuzlocke[] = _("{B_PLAYER_NAME} failed the\nNuzlocke challenge.\pThe Nuzlocke setting\nhas been turned off.\p");
+static const u8 sText_PlayerDuplicateMon[] = _("Since this type has already been\ncaught, it will not count towards\pthe Nuzlocke challenge.\p"); +static const u8 sText_PlayerDuplicateMon[] = _("Since this type has already been\ncaught, it will not count towards\pthe Nuzlocke challenge.\p");
static const u8 sText_PreventsEscape[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX} prevents\nescape with {B_SCR_ACTIVE_ABILITY}!\p"); static const u8 sText_PreventsEscape[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX} prevents\nescape with {B_SCR_ACTIVE_ABILITY}!\p");
static const u8 sText_CantEscape2[] = _("Can't escape!\p"); static const u8 sText_CantEscape2[] = _("Can't escape!\p");
@ -1282,50 +1255,10 @@ index 36da06845..19bed4e96 100644
enum { enum {
TRANSITION_TYPE_NORMAL, TRANSITION_TYPE_NORMAL,
TRANSITION_TYPE_CAVE, TRANSITION_TYPE_CAVE,
@@ -420,8 +422,9 @@ static void CreateBattleStartTask_Debug(u8 transition, u16 song) @@ -2279,18 +2282,22 @@ u8 HasWildPokmnOnThisRouteBeenSeen(u8 currLocation, bool8 setVarForThisEnc){
void BattleSetup_StartWildBattle(void)
{
gNuzlockeCannotCatch = HasWildPokmnOnThisRouteBeenSeen(GetCurrentRegionMapSectionId(), TRUE);
+
if (GetSafariZoneFlag())
DoSafariBattle();
else
DoStandardWildBattle();
@@ -1953,9 +1956,9 @@ u16 CountBattledRematchTeams(u16 trainerId)
return i;
}
-bool8 HasWildPokmnOnThisRouteBeenSeen(u8 currLocation, bool8 setVarForThisEnc){
+u8 HasWildPokmnOnThisRouteBeenSeen(u8 currLocation, bool8 setVarForThisEnc){
u8 varToCheck, bitToCheck;
u16 varValue;
const u16 pkmnSeenVars[] = {
VAR_WILD_PKMN_ROUTE_SEEN_0,
@@ -1970,9 +1973,9 @@ bool8 HasWildPokmnOnThisRouteBeenSeen(u8 currLocation, bool8 setVarForThisEnc){
VarSet(VAR_WILD_PKMN_ROUTE_SEEN_1, 0);
VarSet(VAR_WILD_PKMN_ROUTE_SEEN_2, 0);
VarSet(VAR_WILD_PKMN_ROUTE_SEEN_3, 0);
VarSet(VAR_WILD_PKMN_ROUTE_SEEN_4, 0);
- return FALSE;
+ return 0;
}
switch (currLocation)
{
case MAPSEC_LITTLEROOT_TOWN:
@@ -2279,18 +2282,22 @@ bool8 HasWildPokmnOnThisRouteBeenSeen(u8 currLocation, bool8 setVarForThisEnc){
case MAPSEC_ALTERING_CAVE:
varToCheck = 4;
bitToCheck = 10;
default:
- return FALSE;
+ return 0;
}
varValue = VarGet(pkmnSeenVars[varToCheck]); varValue = VarGet(pkmnSeenVars[varToCheck]);
if ((varValue & (1 << bitToCheck)) != 0){ if ((varValue & (1 << bitToCheck)) != 0){
- return TRUE; return 1;
+ return 1;
} }
else if (setVarForThisEnc){ else if (setVarForThisEnc){
+ u16 species_enemy = GetMonData(&gEnemyParty[gBattlerPartyIndexes[GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT)]], MON_DATA_SPECIES2); + u16 species_enemy = GetMonData(&gEnemyParty[gBattlerPartyIndexes[GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT)]], MON_DATA_SPECIES2);
@ -1334,25 +1267,7 @@ index 36da06845..19bed4e96 100644
+ } + }
VarSet(pkmnSeenVars[varToCheck], varValue | (1 << bitToCheck)); VarSet(pkmnSeenVars[varToCheck], varValue | (1 << bitToCheck));
} }
- return FALSE; return 0;
+ return 0;
}
u8 currLocConvertForNuzlocke(u8 currLocation){
switch (currLocation)
-------------------------------- src/item_use.c --------------------------------
index 403ff54fa..8e62af305 100755
@@ -951,9 +951,9 @@ void ItemUseInBattle_PokeBall(u8 taskId)
DisplayItemMessage(taskId, 1, sText_BallsCannotBeUsed, CloseItemMessage);
return;
}
#endif
- if (gNuzlockeCannotCatch){
+ if (gNuzlockeCannotCatch == 1){
GetMapNameHandleAquaHideout(gStringVar1, currLocConvertForNuzlocke(GetCurrentRegionMapSectionId()));
DisplayItemMessage(taskId, FONT_NORMAL, gText_BallsCannotBeUsedNuz, CloseItemMessage);
return;
} }
``` ```
@ -1365,13 +1280,12 @@ index 6e6f5886e..c5f9baa57 100644
return i; return i;
} }
+bool8 levelCappedNuzlocke(u8 level){ +static u8 getLevelCap(void){
+ u8 levelCap = 0; + u8 levelCap = 0;
+ u16 nextLeader, i; + u16 nextLeader, i;
+ const struct TrainerMonItemCustomMoves *partyData; + const struct TrainerMonItemCustomMoves *partyData;
+ if (!FlagGet(FLAG_NUZLOCKE)){ + if (!FlagGet(FLAG_NUZLOCKE) || !FlagGet(FLAG_NUZLOCKE_LEVEL_CAP) || FlagGet(FLAG_IS_CHAMPION))
+ return FALSE; + return 100;
+ }
+ if (!FlagGet(FLAG_BADGE01_GET)) + if (!FlagGet(FLAG_BADGE01_GET))
+ nextLeader = TRAINER_ROXANNE_1; + nextLeader = TRAINER_ROXANNE_1;
+ else if (!FlagGet(FLAG_BADGE02_GET)) + else if (!FlagGet(FLAG_BADGE02_GET))
@ -1396,6 +1310,13 @@ index 6e6f5886e..c5f9baa57 100644
+ if (partyData[i].lvl > levelCap) + if (partyData[i].lvl > levelCap)
+ levelCap = partyData[i].lvl; + levelCap = partyData[i].lvl;
+ } + }
+ return GetScaledLevel(levelCap);
+}
+
+bool8 levelCappedNuzlocke(u8 level){
+ u8 levelCap = getLevelCap();
+ if (!FlagGet(FLAG_NUZLOCKE) || !FlagGet(FLAG_NUZLOCKE_LEVEL_CAP) || FlagGet(FLAG_IS_CHAMPION))
+ return FALSE; //Redundant since getLevelCap would already return 100 for these, but better to be explicit
+ if (level >= levelCap) + if (level >= levelCap)
+ return TRUE; + return TRUE;
+ return FALSE; + return FALSE;
@ -1601,6 +1522,81 @@ index 2b522ebea..b94bbc344 100644
expToNextLevel = 0; expToNextLevel = 0;
``` ```
### Have Nurse Joy Tell You the Level Cap
```diff
---------------------- data/scripts/pkmn_center_nurse.inc ----------------------
index 546385218..978b9eeec 100644
@@ -51,8 +51,14 @@ EventScript_PkmnCenterNurse_CheckTrainerHillAndUnionRoom::
@ VAR_0x8004 is 1 when player has Gold Card
EventScript_PkmnCenterNurse_ReturnPkmn::
goto_if_eq VAR_0x8004, 1, EventScript_PkmnCenterNurse_ReturnPkmn2
+ goto_if_unset FLAG_NUZLOCKE, EventScript_PkmnCenterNurse_ReturnPkmnDefault
+ goto_if_unset FLAG_NUZLOCKE_LEVEL_CAP, EventScript_PkmnCenterNurse_ReturnPkmnDefault
+ special LevelCapToString
+ message gText_WeHopeToSeeYouAgain4
+ return
+EventScript_PkmnCenterNurse_ReturnPkmnDefault::
message gText_WeHopeToSeeYouAgain3
return
EventScript_PkmnCenterNurse_ReturnPkmn2::
------------------------------ data/specials.inc ------------------------------
index a863b6e13..671716581 100644
@@ -534,4 +534,5 @@ gSpecials::
def_special TryPrepareSecondApproachingTrainer
def_special RemoveRecordsWindow
def_special CloseDeptStoreElevatorWindow
def_special TrySetBattleTowerLinkType
+ def_special LevelCapToString
----------------------- data/text/pkmn_center_nurse.inc -----------------------
index cf2046b76..0d6ad541f 100644
@@ -53,4 +53,8 @@ gText_WeHopeToSeeYouAgain2::
gText_WeHopeToSeeYouAgain3::
.string "Your POKéMON are healed.\n"
.string "We hope to see you again!$"
+gText_WeHopeToSeeYouAgain4::
+ .string "Your POKéMON are healed, but cannot\n"
+ .string "level over {STR_VAR_1} due to Nuzlocke.$"
+
---------------------------- include/battle_setup.h ----------------------------
index 26e66761e..32a4e3be0 100644
@@ -67,8 +67,9 @@ void ShouldTryGetTrainerScript(void);
u16 CountBattledRematchTeams(u16 trainerId);
u8 HasWildPokmnOnThisRouteBeenSeen(u8 currLocation, bool8 setVarForThisEnc);
u8 currLocConvertForNuzlocke(u8 currLocation);
bool8 levelCappedNuzlocke(u8 level);
+void LevelCapToString(void);
void DoStandardWildBattle_Debug(void);
void BattleSetup_StartTrainerBattle_Debug(void);
------------------------------ src/battle_setup.c ------------------------------
index 3110bd0b6..2f86c26a5 100644
@@ -1982,19 +1980,32 @@ bool8 levelCappedNuzlocke(u8 level){
bool8 levelCappedNuzlocke(u8 level){
u8 levelCap = getLevelCap();
if (level >= levelCap)
return TRUE;
return FALSE;
}
+void LevelCapToString(void){
+ u8 lvl_txt[3];
+ ConvertIntToDecimalStringN(lvl_txt, getLevelCap(), STR_CONV_MODE_LEFT_ALIGN, 3);
+ StringCopy(gStringVar1, lvl_txt);
+}
+
u8 HasWildPokmnOnThisRouteBeenSeen(u8 currLocation, bool8 setVarForThisEnc){
u8 varToCheck, bitToCheck;
u16 varValue;
```
## No Held Items ## No Held Items
```diff ```diff
------------------------------ src/battle_util.c ------------------------------ ------------------------------ src/battle_util.c ------------------------------