diff --git a/data/scripts/repel.inc b/data/scripts/repel.inc index 2c4e075f43..e5ecbcb41a 100644 --- a/data/scripts/repel.inc +++ b/data/scripts/repel.inc @@ -19,7 +19,7 @@ EventScript_UsedRepel: bufferitemname 0, VAR_LAST_REPEL_USED playse SE_REPEL lock - msgbox Text_UsedNewRepel, MSGBOX_SIGN + msgbox Text_UsedNewRepelLure, MSGBOX_SIGN removeitem VAR_LAST_REPEL_USED, 1 waitse callnative HandleUseExpiredRepel @@ -33,6 +33,41 @@ Text_UseAnother:: .string "REPEL's effect wore off!\n" .string "Use another?$" -Text_UsedNewRepel:: +Text_UsedNewRepelLure:: .string "{PLAYER} used the\n" .string "{STR_VAR_1}.$" + +EventScript_LureWoreOff:: + checkitem VAR_LAST_REPEL_USED, 1 + compare VAR_RESULT, TRUE + goto_if_eq EventScript_LureUseAnother + lock + msgbox Text_LureWoreOff, MSGBOX_SIGN + release + end + +EventScript_LureUseAnother: + lock + msgbox Text_UseAnotherLure, MSGBOX_YESNO + compare VAR_RESULT, YES + goto_if_eq EventScript_UsedLure + release + end + +EventScript_UsedLure: + bufferitemname 0, VAR_LAST_REPEL_USED + playse SE_REPEL + lock + msgbox Text_UsedNewRepelLure, MSGBOX_SIGN + removeitem VAR_LAST_REPEL_USED, 1 + waitse + callnative HandleUseExpiredLure + release + end + +Text_LureWoreOff: + .string "Lure's effect wore off…$" + +Text_UseAnotherLure:: + .string "Lure's effect wore off!\n" + .string "Use another?$" diff --git a/include/constants/item.h b/include/constants/item.h index a224291faf..9b574417a7 100644 --- a/include/constants/item.h +++ b/include/constants/item.h @@ -16,4 +16,10 @@ #define KEYITEMS_POCKET 4 #define POCKETS_COUNT 5 +#define REPEL_LURE_MASK (1 << 15) +#define IS_LAST_USED_LURE(var) (var & REPEL_LURE_MASK) +#define REPEL_LURE_STEPS(var) (var & (REPEL_LURE_MASK - 1)) +#define LURE_STEPS(var) (IS_LAST_USED_LURE(var) ? REPEL_LURE_STEPS(var) : 0) +#define REPEL_STEPS(var) (!IS_LAST_USED_LURE(var) ? REPEL_LURE_STEPS(var) : 0) + #endif // GUARD_ITEM_CONSTANTS_H diff --git a/include/constants/vars.h b/include/constants/vars.h index aba1125c04..5118f0533d 100644 --- a/include/constants/vars.h +++ b/include/constants/vars.h @@ -47,7 +47,7 @@ // general purpose vars #define VAR_RECYCLE_GOODS 0x4020 -#define VAR_REPEL_STEP_COUNT 0x4021 +#define VAR_REPEL_LURE_STEP_COUNT 0x4021 #define VAR_ICE_STEP_COUNT 0x4022 #define VAR_STARTER_MON 0x4023 // 0=Treecko, 1=Torchic, 2=Mudkip #define VAR_MIRAGE_RND_H 0x4024 diff --git a/include/item_use.h b/include/item_use.h index d55f7cf0d7..bdbf2cdeac 100644 --- a/include/item_use.h +++ b/include/item_use.h @@ -20,6 +20,7 @@ void ItemUseOutOfBattle_PPUp(u8); void ItemUseOutOfBattle_RareCandy(u8); void ItemUseOutOfBattle_TMHM(u8); void ItemUseOutOfBattle_Repel(u8); +void ItemUseOutOfBattle_Lure(u8); void ItemUseOutOfBattle_EscapeRope(u8); void ItemUseOutOfBattle_BlackWhiteFlute(u8); void ItemUseOutOfBattle_EvolutionStone(u8); diff --git a/include/strings.h b/include/strings.h index 25a96eef08..626d633821 100644 --- a/include/strings.h +++ b/include/strings.h @@ -936,6 +936,7 @@ extern const u8 gText_BootedUpTM[]; extern const u8 gText_TMHMContainedVar1[]; extern const u8 gText_PlayerUsedVar2[]; extern const u8 gText_RepelEffectsLingered[]; +extern const u8 gText_LureEffectsLingered[]; extern const u8 gText_UsedVar2WildLured[]; extern const u8 gText_UsedVar2WildRepelled[]; extern const u8 gText_BoxFull[]; diff --git a/src/data/items.h b/src/data/items.h index b0b53c31f5..5087ca03b5 100644 --- a/src/data/items.h +++ b/src/data/items.h @@ -1565,7 +1565,7 @@ const struct Item gItems[] = .description = sLureDesc, .pocket = POCKET_ITEMS, .type = ITEM_USE_BAG_MENU, - .fieldUseFunc = ItemUseOutOfBattle_CannotUse, + .fieldUseFunc = ItemUseOutOfBattle_Lure, .secondaryId = 0, .flingPower = 30, }, @@ -1579,7 +1579,7 @@ const struct Item gItems[] = .description = sSuperLureDesc, .pocket = POCKET_ITEMS, .type = ITEM_USE_BAG_MENU, - .fieldUseFunc = ItemUseOutOfBattle_CannotUse, + .fieldUseFunc = ItemUseOutOfBattle_Lure, .secondaryId = 0, .flingPower = 30, }, @@ -1593,7 +1593,7 @@ const struct Item gItems[] = .description = sMaxLureDesc, .pocket = POCKET_ITEMS, .type = ITEM_USE_BAG_MENU, - .fieldUseFunc = ItemUseOutOfBattle_CannotUse, + .fieldUseFunc = ItemUseOutOfBattle_Lure, .secondaryId = 0, .flingPower = 30, }, diff --git a/src/item.c b/src/item.c index 3a62d83e4a..f93e7adad3 100644 --- a/src/item.c +++ b/src/item.c @@ -952,8 +952,3 @@ u8 ItemId_GetFlingPower(u16 itemId) { return gItems[SanitizeItemId(itemId)].flingPower; } - -void HandleUseExpiredRepel(void) -{ - VarSet(VAR_REPEL_STEP_COUNT, ItemId_GetHoldEffectParam(VarGet(VAR_LAST_REPEL_USED))); -} diff --git a/src/item_use.c b/src/item_use.c index e5e38c871b..1dddc57386 100644 --- a/src/item_use.c +++ b/src/item_use.c @@ -67,7 +67,9 @@ static void Task_ShowTMHMContainedMessage(u8); static void UseTMHMYesNo(u8); static void UseTMHM(u8); static void Task_StartUseRepel(u8); +static void Task_StartUseLure(u8 taskId); static void Task_UseRepel(u8); +static void Task_UseLure(u8 taskId); static void Task_CloseCantUseKeyItemMessage(u8); static void SetDistanceOfClosestHiddenItem(u8, s16, s16); static void CB2_OpenPokeblockFromBag(void); @@ -846,7 +848,7 @@ static void RemoveUsedItem(void) void ItemUseOutOfBattle_Repel(u8 taskId) { - if (VarGet(VAR_REPEL_STEP_COUNT) == 0) + if (REPEL_STEPS(VarGet(VAR_REPEL_LURE_STEP_COUNT)) == 0) gTasks[taskId].func = Task_StartUseRepel; else if (!InBattlePyramid()) DisplayItemMessage(taskId, FONT_NORMAL, gText_RepelEffectsLingered, CloseItemMessage); @@ -870,7 +872,7 @@ static void Task_UseRepel(u8 taskId) { if (!IsSEPlaying()) { - VarSet(VAR_REPEL_STEP_COUNT, ItemId_GetHoldEffectParam(gSpecialVar_ItemId)); + VarSet(VAR_REPEL_LURE_STEP_COUNT, ItemId_GetHoldEffectParam(gSpecialVar_ItemId)); VarSet(VAR_LAST_REPEL_USED, gSpecialVar_ItemId); RemoveUsedItem(); if (!InBattlePyramid()) @@ -879,6 +881,51 @@ static void Task_UseRepel(u8 taskId) DisplayItemMessageInBattlePyramid(taskId, gStringVar4, Task_CloseBattlePyramidBagMessage); } } +void HandleUseExpiredRepel(void) +{ + VarSet(VAR_REPEL_LURE_STEP_COUNT, ItemId_GetHoldEffectParam(VarGet(VAR_LAST_REPEL_USED))); +} + +void ItemUseOutOfBattle_Lure(u8 taskId) +{ + if (LURE_STEPS(VarGet(VAR_REPEL_LURE_STEP_COUNT)) == 0) + gTasks[taskId].func = Task_StartUseLure; + else if (!InBattlePyramid()) + DisplayItemMessage(taskId, FONT_NORMAL, gText_LureEffectsLingered, CloseItemMessage); + else + DisplayItemMessageInBattlePyramid(taskId, gText_LureEffectsLingered, Task_CloseBattlePyramidBagMessage); +} + +static void Task_StartUseLure(u8 taskId) +{ + s16* data = gTasks[taskId].data; + + if (++data[8] > 7) + { + data[8] = 0; + PlaySE(SE_REPEL); + gTasks[taskId].func = Task_UseLure; + } +} + +static void Task_UseLure(u8 taskId) +{ + if (!IsSEPlaying()) + { + VarSet(VAR_REPEL_LURE_STEP_COUNT, ItemId_GetHoldEffectParam(gSpecialVar_ItemId) | REPEL_LURE_MASK); + VarSet(VAR_LAST_REPEL_USED, gSpecialVar_ItemId); + RemoveUsedItem(); + if (!InBattlePyramid()) + DisplayItemMessage(taskId, FONT_NORMAL, gStringVar4, CloseItemMessage); + else + DisplayItemMessageInBattlePyramid(taskId, gStringVar4, Task_CloseBattlePyramidBagMessage); + } +} + +void HandleUseExpiredLure(void) +{ + VarSet(VAR_REPEL_LURE_STEP_COUNT, ItemId_GetHoldEffectParam(VarGet(VAR_LAST_REPEL_USED)) | REPEL_LURE_MASK); +} static void Task_UsedBlackWhiteFlute(u8 taskId) { diff --git a/src/strings.c b/src/strings.c index d199b92d4b..4375adad24 100644 --- a/src/strings.c +++ b/src/strings.c @@ -244,6 +244,7 @@ const u8 gText_BootedUpHM[] = _("Booted up an HM."); const u8 gText_TMHMContainedVar1[] = _("It contained\n{STR_VAR_1}.\pTeach {STR_VAR_1}\nto a POKéMON?"); const u8 gText_PlayerUsedVar2[] = _("{PLAYER} used the\n{STR_VAR_2}.{PAUSE_UNTIL_PRESS}"); const u8 gText_RepelEffectsLingered[] = _("But the effects of a REPEL\nlingered from earlier.{PAUSE_UNTIL_PRESS}"); +const u8 gText_LureEffectsLingered[] = _("But the effects of a Lure\nlingered from earlier.{PAUSE_UNTIL_PRESS}"); 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}"); diff --git a/src/wild_encounter.c b/src/wild_encounter.c index e49d09f54d..1ac3487939 100644 --- a/src/wild_encounter.c +++ b/src/wild_encounter.c @@ -20,11 +20,13 @@ #include "constants/abilities.h" #include "constants/battle_config.h" #include "constants/game_stat.h" +#include "constants/item.h" #include "constants/items.h" #include "constants/layouts.h" #include "constants/weather.h" extern const u8 EventScript_RepelWoreOff[]; +extern const u8 EventScript_LureWoreOff[]; #define MAX_ENCOUNTER_RATE 2880 @@ -181,58 +183,82 @@ static void FeebasSeedRng(u16 seed) // LAND_WILD_COUNT static u8 ChooseWildMonIndex_Land(void) { + u8 wildMonIndex = 0; + bool8 swap = FALSE; u8 rand = Random() % ENCOUNTER_CHANCE_LAND_MONS_TOTAL; if (rand < ENCOUNTER_CHANCE_LAND_MONS_SLOT_0) - return 0; + wildMonIndex = 0; else if (rand >= ENCOUNTER_CHANCE_LAND_MONS_SLOT_0 && rand < ENCOUNTER_CHANCE_LAND_MONS_SLOT_1) - return 1; + wildMonIndex = 1; else if (rand >= ENCOUNTER_CHANCE_LAND_MONS_SLOT_1 && rand < ENCOUNTER_CHANCE_LAND_MONS_SLOT_2) - return 2; + wildMonIndex = 2; else if (rand >= ENCOUNTER_CHANCE_LAND_MONS_SLOT_2 && rand < ENCOUNTER_CHANCE_LAND_MONS_SLOT_3) - return 3; + wildMonIndex = 3; else if (rand >= ENCOUNTER_CHANCE_LAND_MONS_SLOT_3 && rand < ENCOUNTER_CHANCE_LAND_MONS_SLOT_4) - return 4; + wildMonIndex = 4; else if (rand >= ENCOUNTER_CHANCE_LAND_MONS_SLOT_4 && rand < ENCOUNTER_CHANCE_LAND_MONS_SLOT_5) - return 5; + wildMonIndex = 5; else if (rand >= ENCOUNTER_CHANCE_LAND_MONS_SLOT_5 && rand < ENCOUNTER_CHANCE_LAND_MONS_SLOT_6) - return 6; + wildMonIndex = 6; else if (rand >= ENCOUNTER_CHANCE_LAND_MONS_SLOT_6 && rand < ENCOUNTER_CHANCE_LAND_MONS_SLOT_7) - return 7; + wildMonIndex = 7; else if (rand >= ENCOUNTER_CHANCE_LAND_MONS_SLOT_7 && rand < ENCOUNTER_CHANCE_LAND_MONS_SLOT_8) - return 8; + wildMonIndex = 8; else if (rand >= ENCOUNTER_CHANCE_LAND_MONS_SLOT_8 && rand < ENCOUNTER_CHANCE_LAND_MONS_SLOT_9) - return 9; + wildMonIndex = 9; else if (rand >= ENCOUNTER_CHANCE_LAND_MONS_SLOT_9 && rand < ENCOUNTER_CHANCE_LAND_MONS_SLOT_10) - return 10; + wildMonIndex = 10; else - return 11; + wildMonIndex = 11; + + if (LURE_STEPS(VarGet(VAR_REPEL_LURE_STEP_COUNT)) && (Random() % 10 < 2)) + swap = TRUE; + + if (swap) + wildMonIndex = 11 - wildMonIndex; + + return wildMonIndex; } // ROCK_WILD_COUNT / WATER_WILD_COUNT static u8 ChooseWildMonIndex_WaterRock(void) { + u8 wildMonIndex = 0; + bool8 swap = FALSE; u8 rand = Random() % ENCOUNTER_CHANCE_WATER_MONS_TOTAL; if (rand < ENCOUNTER_CHANCE_WATER_MONS_SLOT_0) - return 0; + wildMonIndex = 0; else if (rand >= ENCOUNTER_CHANCE_WATER_MONS_SLOT_0 && rand < ENCOUNTER_CHANCE_WATER_MONS_SLOT_1) - return 1; + wildMonIndex = 1; else if (rand >= ENCOUNTER_CHANCE_WATER_MONS_SLOT_1 && rand < ENCOUNTER_CHANCE_WATER_MONS_SLOT_2) - return 2; + wildMonIndex = 2; else if (rand >= ENCOUNTER_CHANCE_WATER_MONS_SLOT_2 && rand < ENCOUNTER_CHANCE_WATER_MONS_SLOT_3) - return 3; + wildMonIndex = 3; else - return 4; + wildMonIndex = 4; + + if (LURE_STEPS(VarGet(VAR_REPEL_LURE_STEP_COUNT)) && (Random() % 10 < 2)) + swap = TRUE; + + if (swap) + wildMonIndex = 4 - wildMonIndex; + + return wildMonIndex; } // FISH_WILD_COUNT static u8 ChooseWildMonIndex_Fishing(u8 rod) { u8 wildMonIndex = 0; + bool8 swap = FALSE; u8 rand = Random() % max(max(ENCOUNTER_CHANCE_FISHING_MONS_OLD_ROD_TOTAL, ENCOUNTER_CHANCE_FISHING_MONS_GOOD_ROD_TOTAL), ENCOUNTER_CHANCE_FISHING_MONS_SUPER_ROD_TOTAL); + if (LURE_STEPS(VarGet(VAR_REPEL_LURE_STEP_COUNT)) && (Random() % 10 < 2)) + swap = TRUE; + switch (rod) { case OLD_ROD: @@ -241,6 +267,9 @@ static u8 ChooseWildMonIndex_Fishing(u8 rod) else wildMonIndex = 1; break; + + if (swap) + wildMonIndex = 1 - wildMonIndex; case GOOD_ROD: if (rand < ENCOUNTER_CHANCE_FISHING_MONS_GOOD_ROD_SLOT_2) wildMonIndex = 2; @@ -248,6 +277,9 @@ static u8 ChooseWildMonIndex_Fishing(u8 rod) wildMonIndex = 3; if (rand >= ENCOUNTER_CHANCE_FISHING_MONS_GOOD_ROD_SLOT_3 && rand < ENCOUNTER_CHANCE_FISHING_MONS_GOOD_ROD_SLOT_4) wildMonIndex = 4; + + if (swap) + wildMonIndex = 6 - wildMonIndex; break; case SUPER_ROD: if (rand < ENCOUNTER_CHANCE_FISHING_MONS_SUPER_ROD_SLOT_5) @@ -260,6 +292,9 @@ static u8 ChooseWildMonIndex_Fishing(u8 rod) wildMonIndex = 8; if (rand >= ENCOUNTER_CHANCE_FISHING_MONS_SUPER_ROD_SLOT_8 && rand < ENCOUNTER_CHANCE_FISHING_MONS_SUPER_ROD_SLOT_9) wildMonIndex = 9; + + if (swap) + wildMonIndex = 14 - wildMonIndex; break; } return wildMonIndex; @@ -521,6 +556,8 @@ static bool8 DoWildEncounterRateTest(u32 encounterRate, bool8 ignoreAbility) encounterRate = encounterRate * 80 / 100; ApplyFluteEncounterRateMod(&encounterRate); ApplyCleanseTagEncounterRateMod(&encounterRate); + if (LURE_STEPS(VarGet(VAR_REPEL_LURE_STEP_COUNT)) != 0) + encounterRate *= 2; if (!ignoreAbility && !GetMonData(&gPlayerParty[0], MON_DATA_SANITY_IS_EGG)) { u32 ability = GetMonAbility(&gPlayerParty[0]); @@ -892,24 +929,37 @@ u16 GetLocalWaterMon(void) bool8 UpdateRepelCounter(void) { - u16 steps; + u16 repelLureVar = VarGet(VAR_REPEL_LURE_STEP_COUNT); + u16 steps = REPEL_LURE_STEPS(repelLureVar); + bool32 isLure = IS_LAST_USED_LURE(repelLureVar); if (InBattlePike() || InBattlePyramid()) return FALSE; if (InUnionRoom() == TRUE) return FALSE; - steps = VarGet(VAR_REPEL_STEP_COUNT); - if (steps != 0) { steps--; - VarSet(VAR_REPEL_STEP_COUNT, steps); - if (steps == 0) + if (!isLure) { - ScriptContext_SetupScript(EventScript_RepelWoreOff); - return TRUE; + VarSet(VAR_REPEL_LURE_STEP_COUNT, steps); + if (steps == 0) + { + ScriptContext_SetupScript(EventScript_RepelWoreOff); + return TRUE; + } } + else + { + VarSet(VAR_REPEL_LURE_STEP_COUNT, steps | REPEL_LURE_MASK); + if (steps == 0) + { + ScriptContext_SetupScript(EventScript_LureWoreOff); + return TRUE; + } + } + } return FALSE; } @@ -918,7 +968,7 @@ static bool8 IsWildLevelAllowedByRepel(u8 wildLevel) { u8 i; - if (!VarGet(VAR_REPEL_STEP_COUNT)) + if (!VarGet(VAR_REPEL_LURE_STEP_COUNT)) return TRUE; for (i = 0; i < PARTY_SIZE; i++) @@ -1006,7 +1056,7 @@ bool8 TryDoDoubleWildBattle(void) { if (GetSafariZoneFlag() || GetMonsStateToDoubles() != PLAYER_HAS_TWO_USABLE_MONS) return FALSE; -#if B_FLAG_FORCE_DOUBLE_WILD != 0 +#if B_FLAG_FORCE_DOUBLE_WILD != 0 else if (FlagGet(B_FLAG_FORCE_DOUBLE_WILD)) return TRUE; #endif