From 0e5008ce4bb655a9fd1ef75e331b7fa7855c18e1 Mon Sep 17 00:00:00 2001 From: cawtds <38510667+cawtds@users.noreply.github.com> Date: Fri, 3 Apr 2026 15:35:55 +0200 Subject: [PATCH] sync item config, add oras dowse --- data/scripts/obtain_item.inc | 2 + .../field_effects/palettes/oras_dowsing.pal | 19 + .../field_effects/pics/oras_dowsing_green.png | Bin 0 -> 345 bytes .../field_effects/pics/oras_dowsing_red.png | Bin 0 -> 313 bytes include/constants/field_effects.h | 2 + include/field_effect.h | 1 + include/itemfinder.h | 2 + include/oras_dowse.h | 39 ++ spritesheet_rules.mk | 6 + src/bike.c | 2 + src/field_effect.c | 8 + src/field_fadetransition.c | 3 + src/field_player_avatar.c | 5 + src/itemfinder.c | 48 +- src/move_relearner.c | 13 + src/oras_dowse.c | 562 ++++++++++++++++++ src/overworld.c | 2 + src/wild_encounter.c | 10 +- 18 files changed, 702 insertions(+), 22 deletions(-) create mode 100644 graphics/field_effects/palettes/oras_dowsing.pal create mode 100644 graphics/field_effects/pics/oras_dowsing_green.png create mode 100644 graphics/field_effects/pics/oras_dowsing_red.png create mode 100644 include/oras_dowse.h create mode 100644 src/oras_dowse.c diff --git a/data/scripts/obtain_item.inc b/data/scripts/obtain_item.inc index 2cb3551b1..d9c1503ad 100644 --- a/data/scripts/obtain_item.inc +++ b/data/scripts/obtain_item.inc @@ -179,6 +179,7 @@ EventScript_TryPickUpHiddenItem:: return EventScript_PickedUpHiddenItem:: + callnative Script_ClearDowsingColor call_if_eq VAR_0x8006, 1, EventScript_FoundSingleItem call_if_ne VAR_0x8006, 1, EventScript_FoundMultipleItems copyvar VAR_0x8006, VAR_0x8005 @@ -189,6 +190,7 @@ EventScript_PickedUpHiddenItem:: msgbox Text_PutItemAway hideitemdescription special SetHiddenItemFlag + callnative Script_UpdateDowseState releaseall end diff --git a/graphics/field_effects/palettes/oras_dowsing.pal b/graphics/field_effects/palettes/oras_dowsing.pal new file mode 100644 index 000000000..d3446e397 --- /dev/null +++ b/graphics/field_effects/palettes/oras_dowsing.pal @@ -0,0 +1,19 @@ +JASC-PAL +0100 +16 +115 197 164 +0 0 0 +255 255 255 +255 255 255 +255 255 255 +255 255 255 +255 255 255 +255 255 255 +255 255 255 +255 255 255 +255 255 255 +255 255 255 +255 255 255 +255 255 255 +255 255 255 +255 0 255 diff --git a/graphics/field_effects/pics/oras_dowsing_green.png b/graphics/field_effects/pics/oras_dowsing_green.png new file mode 100644 index 0000000000000000000000000000000000000000..6a4eb08f0293c22310a4582e4ec9be51af1e81a9 GIT binary patch literal 345 zcmeAS@N?(olHy`uVBq!ia0vp^6M$HOgBeJk3S#^Zq!^2X+?^QKos)S9@nOClWCH|8ecP1yI9vPZ!6Kh}O4LqWPE=Ib4@Y7yRFyD|?ws-0{U3b@O8akw~=(@i|xMM<>2w0Va4+MX=N?~d1vQFT?#*>=;Leq!K7Zx z>%bp}+Et6ss^3>y^Cx2O*~>MRlNK-0o^${3wtq*0%ft#!?Y}E@nOClWCH|8ecP1yI9wPZ!6Kh}O43j(mp=IGSq}{{Me_Y?od_kjs)dt(#q|5^}^< z1r<4(A{?$>TiYnL>hojH<4b;-=D0GSnz-_}-Mi?DXE*%WvM(Cuw6aV|cDVYVN956( z4`(*c@8RPt-DQ+r`SX4IWWg8SZ=P#&tN&7eq#YRWV5#;p=Z4qM9ef|tmboFyt=akR{03-C6;s5{u literal 0 HcmV?d00001 diff --git a/include/constants/field_effects.h b/include/constants/field_effects.h index 4a0b66ed3..b89f1df6a 100644 --- a/include/constants/field_effects.h +++ b/include/constants/field_effects.h @@ -87,6 +87,7 @@ enum FieldEffect FLDEFF_CAVE_DUST, FLDEFF_USE_ROCK_CLIMB, FLDEFF_ROCK_CLIMB_DUST, + FLDEFF_ORAS_DOWSE, FLDEFF_COUNT, }; @@ -103,6 +104,7 @@ enum FieldEffect #define FLDEFF_PAL_TAG_HOF_MONITOR 0x1010 #define FLDEFF_PAL_TAG_CAVE_DUST 0x1012 #define FLDEFF_PAL_TAG_DUST_CLOUD 0x1013 +#define FLDEFF_PAL_TAG_ORAS_DOWSE 0x1014 // tile tags, for field effects that may have many copies on screen at once #define FLDEFF_TILE_TAG_SHADOW_SMALL 0x1400 diff --git a/include/field_effect.h b/include/field_effect.h index d3ab7c5e4..927da3e87 100644 --- a/include/field_effect.h +++ b/include/field_effect.h @@ -166,5 +166,6 @@ u32 FldEff_SnowTracksSpot(void); u32 FldEff_CaveDust(void); u32 FldEff_UseRockClimb(void); u32 FldEff_RockClimbDust(void); +u32 FldEff_ORASDowsing(void); #endif //GUARD_FIELD_EFFECTS_H diff --git a/include/itemfinder.h b/include/itemfinder.h index de63e9362..bf250a43a 100644 --- a/include/itemfinder.h +++ b/include/itemfinder.h @@ -1,6 +1,8 @@ #ifndef GUARD_ITEMFINDER_H #define GUARD_ITEMFINDER_H +bool8 HiddenItemIsWithinRangeOfPlayer(const struct MapEvents *events, u8 taskId); +u8 GetPlayerDirectionTowardsHiddenItem(s16 itemX, s16 itemY); void ItemUseOnFieldCB_Itemfinder(u8 taskId); #endif //GUARD_ITEMFINDER_H diff --git a/include/oras_dowse.h b/include/oras_dowse.h new file mode 100644 index 000000000..8b490cf6c --- /dev/null +++ b/include/oras_dowse.h @@ -0,0 +1,39 @@ +#ifndef GUARD_ORAS_DOWSE_H +#define GUARD_ORAS_DOWSE_H + +// States for ORAS Dowsing +enum +{ + ORASD_WIGGLE_NONE, + ORASD_WIGGLE_SLOW, + ORASD_WIGGLE_NORMAL, + ORASD_WIGGLE_FAST, + ORASD_WIGGLE_FASTER +}; + +#define ANIM_ORAS_DOWSE_WIGGLE_SOUTH_SLOW (ANIM_STD_FACE_EAST + 1) +#define ANIM_ORAS_DOWSE_WIGGLE_NORTH_SLOW (ANIM_STD_FACE_EAST + 2) +#define ANIM_ORAS_DOWSE_WIGGLE_WEST_SLOW (ANIM_STD_FACE_EAST + 3) +#define ANIM_ORAS_DOWSE_WIGGLE_EAST_SLOW (ANIM_STD_FACE_EAST + 4) +#define ANIM_ORAS_DOWSE_WIGGLE_SOUTH (ANIM_STD_FACE_EAST + 5) +#define ANIM_ORAS_DOWSE_WIGGLE_NORTH (ANIM_STD_FACE_EAST + 6) +#define ANIM_ORAS_DOWSE_WIGGLE_WEST (ANIM_STD_FACE_EAST + 7) +#define ANIM_ORAS_DOWSE_WIGGLE_EAST (ANIM_STD_FACE_EAST + 8) +#define ANIM_ORAS_DOWSE_WIGGLE_SOUTH_FAST (ANIM_STD_FACE_EAST + 9) +#define ANIM_ORAS_DOWSE_WIGGLE_NORTH_FAST (ANIM_STD_FACE_EAST + 10) +#define ANIM_ORAS_DOWSE_WIGGLE_WEST_FAST (ANIM_STD_FACE_EAST + 11) +#define ANIM_ORAS_DOWSE_WIGGLE_EAST_FAST (ANIM_STD_FACE_EAST + 12) +#define ANIM_ORAS_DOWSE_WIGGLE_SOUTH_FASTER (ANIM_STD_FACE_EAST + 13) +#define ANIM_ORAS_DOWSE_WIGGLE_NORTH_FASTER (ANIM_STD_FACE_EAST + 14) +#define ANIM_ORAS_DOWSE_WIGGLE_WEST_FASTER (ANIM_STD_FACE_EAST + 15) +#define ANIM_ORAS_DOWSE_WIGGLE_EAST_FASTER (ANIM_STD_FACE_EAST + 16) + +extern const u16 gFieldEffectPal_ORASDowsing[]; + +void Task_UseORASDowsingMachine(u8 taskId); +void ResumeORASDowseFieldEffect(void); +void UpdateDowseState(struct Sprite *sprite); +void UpdateDowsingAnimDirection(struct Sprite *sprite, struct ObjectEvent *playerObj); +void EndORASDowsing(void); + +#endif // GUARD_ORAS_DOWSE_H diff --git a/spritesheet_rules.mk b/spritesheet_rules.mk index b97faef87..872fe36f6 100644 --- a/spritesheet_rules.mk +++ b/spritesheet_rules.mk @@ -15,6 +15,12 @@ $(OBJEVENTGFXDIR)/misc/surf_blob.4bpp: %.4bpp: %.png $(FLDEFFGFXDIR)/rock_climb_blob.4bpp: %.4bpp: %.png $(GFX) $< $@ -mwidth 4 -mheight 4 +$(FLDEFFGFXDIR)/oras_dowsing_red.4bpp: %.4bpp: %.png + $(GFX) $< $@ -mwidth 2 -mheight 4 + +$(FLDEFFGFXDIR)/oras_dowsing_green.4bpp: %.4bpp: %.png + $(GFX) $< $@ -mwidth 2 -mheight 4 + $(OBJEVENTGFXDIR)/misc/ss_anne.4bpp: %.4bpp: %.png $(GFX) $< $@ -mwidth 8 -mheight 4 diff --git a/src/bike.c b/src/bike.c index 2bd63d307..2201efa67 100644 --- a/src/bike.c +++ b/src/bike.c @@ -5,6 +5,7 @@ #include "event_object_movement.h" #include "fieldmap.h" #include "field_camera.h" +#include "oras_dowse.h" #include "overworld.h" #include "constants/map_types.h" #include "constants/songs.h" @@ -332,6 +333,7 @@ void GetOnOffBike(u8 flags) } else { + EndORASDowsing(); SetPlayerAvatarTransitionFlags(flags); if (Overworld_MusicCanOverrideMapMusic(MUS_CYCLING)) { diff --git a/src/field_effect.c b/src/field_effect.c index 21b926d09..7af81d5c5 100644 --- a/src/field_effect.c +++ b/src/field_effect.c @@ -19,6 +19,7 @@ #include "malloc.h" #include "menu.h" #include "metatile_behavior.h" +#include "oras_dowse.h" #include "overworld.h" #include "palette.h" #include "party_menu.h" @@ -376,6 +377,7 @@ static const u32 (*const sFieldEffectFuncs[FLDEFF_COUNT]) (void) = [FLDEFF_CAVE_DUST] = FldEff_CaveDust, [FLDEFF_USE_ROCK_CLIMB] = FldEff_UseRockClimb, [FLDEFF_ROCK_CLIMB_DUST] = FldEff_RockClimbDust, + [FLDEFF_ORAS_DOWSE] = FldEff_ORASDowsing, }; static const struct OamData sOamData_8x8 = @@ -1564,6 +1566,8 @@ void StartEscalatorWarp(u8 metatileBehavior, u8 priority) gTasks[taskId].tGoingUp = FALSE; if (metatileBehavior == MB_UP_ESCALATOR) gTasks[taskId].tGoingUp = TRUE; + + EndORASDowsing(); } static void Task_EscalatorWarpOut(u8 taskId) @@ -2046,6 +2050,7 @@ static bool32 (*const sLavaridgeGymB1FWarpEffectFuncs[])(struct Task *task, stru void StartLavaridgeGymB1FWarp(u8 priority) { + EndORASDowsing(); CreateTask(Task_LavaridgeGymB1FWarp, priority); } @@ -2304,6 +2309,7 @@ void SpriteCB_AshLaunch(struct Sprite *sprite) void StartLavaridgeGym1FWarp(u8 priority) { + EndORASDowsing(); CreateTask(Task_LavaridgeGym1FWarp, priority); } @@ -2442,6 +2448,7 @@ void StartEscapeRopeFieldEffect(void) LockPlayerFieldControls(); FreezeObjectEvents(); HideFollowerForFieldEffect(); // hide follower before warping + EndORASDowsing(); CreateTask(Task_EscapeRopeWarpOut, 80); } @@ -2770,6 +2777,7 @@ static void TeleportWarpOutFieldEffect_Init(struct Task *task) LockPlayerFieldControls(); FreezeObjectEvents(); CameraObjectFreeze(); + EndORASDowsing(); task->tStartDir = GetPlayerFacingDirection(); task->tState = TELEPORT_WARP_OUT_SPIN_GROUND; } diff --git a/src/field_fadetransition.c b/src/field_fadetransition.c index b9e428b84..da2043325 100644 --- a/src/field_fadetransition.c +++ b/src/field_fadetransition.c @@ -15,6 +15,7 @@ #include "link.h" #include "map_preview_screen.h" #include "metatile_behavior.h" +#include "oras_dowse.h" #include "overworld.h" #include "palette.h" #include "quest_log.h" @@ -690,6 +691,7 @@ static void Task_Teleport2Warp(u8 taskId) case 0: FreezeObjectEvents(); LockPlayerFieldControls(); + EndORASDowsing(); task->data[0]++; break; case 1: @@ -775,6 +777,7 @@ static void Task_DoorWarp(u8 taskId) ObjectEventSetHeldMovement(followerObject, MOVEMENT_ACTION_ENTER_POKEBALL); } task->tDoorTask = FieldAnimateDoorOpen(*xp, *yp - 1); + EndORASDowsing(); task->tState = DOORWARP_START_WALK_UP; break; case DOORWARP_START_WALK_UP: diff --git a/src/field_player_avatar.c b/src/field_player_avatar.c index ce08bcb1c..642cb053c 100644 --- a/src/field_player_avatar.c +++ b/src/field_player_avatar.c @@ -12,6 +12,7 @@ #include "help_system.h" #include "menu.h" #include "metatile_behavior.h" +#include "oras_dowse.h" #include "overworld.h" #include "party_menu.h" #include "quest_log_player.h" @@ -1306,6 +1307,7 @@ void SetPlayerInvisibility(bool8 invisible) void StartPlayerAvatarSummonMonForFieldMoveAnim(void) { + EndORASDowsing(); ObjectEventSetGraphicsId(&gObjectEvents[gPlayerAvatar.objectEventId], GetPlayerAvatarGraphicsIdByStateId(PLAYER_AVATAR_STATE_FIELD_MOVE)); StartSpriteAnim(&gSprites[gPlayerAvatar.spriteId], ANIM_FIELD_MOVE); } @@ -1325,12 +1327,14 @@ u8 GetPlayerAvatarVsSeekerGfxId(void) void StartPlayerAvatarVsSeekerAnim(void) { + EndORASDowsing(); ObjectEventSetGraphicsId(&gObjectEvents[gPlayerAvatar.objectEventId], GetPlayerAvatarVsSeekerGfxId()); StartSpriteAnim(&gSprites[gPlayerAvatar.spriteId], ANIM_VS_SEEKER); } void SetPlayerAvatarFishing(u8 direction) { + EndORASDowsing(); QuestLogCallUpdatePlayerSprite(QL_PLAYER_GFX_FISH); } @@ -1342,6 +1346,7 @@ void PlayerUseAcroBikeOnBumpySlope(u8 direction) void SetPlayerAvatarWatering(u8 direction) { + EndORASDowsing(); ObjectEventSetGraphicsId(&gObjectEvents[gPlayerAvatar.objectEventId], GetPlayerAvatarGraphicsIdByStateId(PLAYER_AVATAR_STATE_WATERING)); StartSpriteAnim(&gSprites[gPlayerAvatar.spriteId], GetFaceDirectionAnimNum(direction)); } diff --git a/src/itemfinder.c b/src/itemfinder.c index a621f982f..d0a272074 100644 --- a/src/itemfinder.c +++ b/src/itemfinder.c @@ -5,7 +5,9 @@ #include "field_player_avatar.h" #include "field_specials.h" #include "fieldmap.h" +#include "itemfinder.h" #include "menu.h" +#include "oras_dowse.h" #include "script.h" #include "sound.h" #include "strings.h" @@ -15,12 +17,10 @@ static void Task_NoResponse_CleanUp(u8 taskId); static void Task_ItemfinderResponseSoundsAndAnims(u8 taskId); static void Task_ItemfinderUnderfootSoundsAndAnims(u8 taskId); -static bool8 HiddenItemIsWithinRangeOfPlayer(const struct MapEvents * events, u8 taskId); static void SetUnderfootHiddenItem(u8 taskId, u32 hiddenItem); static void SetNormalHiddenItem(u8 taskId); static void FindHiddenItemsInConnectedMaps(u8 taskId); static void RegisterHiddenItemRelativeCoordsIfCloser(u8 taskId, s16 dx, s16 dy); -static u8 GetPlayerDirectionTowardsHiddenItem(s16 itemX, s16 itemY); static void Task_ItemfinderResponsePrintMessage(u8 taskId); static void Task_ItemfinderResponseCleanUp(u8 taskId); static void Task_ItemfinderUnderfootPrintMessage(u8 taskId); @@ -130,20 +130,33 @@ static const struct SpriteSheet sArrowAndStarSpriteSheet = { void ItemUseOnFieldCB_Itemfinder(u8 taskId) { - u8 i; - for (i = 0; i < 16; i++) - gTasks[taskId].data[i] = 0; - if (HiddenItemIsWithinRangeOfPlayer(gMapHeader.events, taskId) == TRUE) + + if (I_ORAS_DOWSING_FLAG != 0) { - LoadArrowAndStarTiles(); - if (gTasks[taskId].tUnderfoot == TRUE) - gTasks[taskId].func = Task_ItemfinderUnderfootSoundsAndAnims; + if (!TestPlayerAvatarFlags(PLAYER_AVATAR_FLAG_SURFING) && !TestPlayerAvatarFlags(PLAYER_AVATAR_FLAG_UNDERWATER)) + gTasks[taskId].func = Task_UseORASDowsingMachine; else - gTasks[taskId].func = Task_ItemfinderResponseSoundsAndAnims; + DisplayItemMessageOnField(taskId, FONT_NORMAL, gText_OakForbidsUseOfItemHere, Task_NoResponse_CleanUp); } else { - DisplayItemMessageOnField(taskId, FONT_NORMAL, gText_NopeTheresNoResponse, Task_NoResponse_CleanUp); + u8 i; + + for (i = 0; i < NUM_TASK_DATA; i++) + gTasks[taskId].data[i] = 0; + + if (HiddenItemIsWithinRangeOfPlayer(gMapHeader.events, taskId) == TRUE) + { + LoadArrowAndStarTiles(); + if (gTasks[taskId].tUnderfoot == TRUE) + gTasks[taskId].func = Task_ItemfinderUnderfootSoundsAndAnims; + else + gTasks[taskId].func = Task_ItemfinderResponseSoundsAndAnims; + } + else + { + DisplayItemMessageOnField(taskId, FONT_NORMAL, gText_NopeTheresNoResponse, Task_NoResponse_CleanUp); + } } } @@ -199,11 +212,16 @@ static void Task_ItemfinderUnderfootSoundsAndAnims(u8 taskId) tDingTimer++; } -static bool8 HiddenItemIsWithinRangeOfPlayer(const struct MapEvents * events, u8 taskId) +bool8 HiddenItemIsWithinRangeOfPlayer(const struct MapEvents *events, u8 taskId) { s16 x, y, i, dx, dy; PlayerGetDestCoords(&x, &y); - gTasks[taskId].tHiddenItemFound = FALSE; + + if (I_ORAS_DOWSING_FLAG != 0) + gSprites[gObjectEvents[gPlayerAvatar.objectEventId].fieldEffectSpriteId].tHiddenItemFound = FALSE; + else + gTasks[taskId].tHiddenItemFound = FALSE; + for (i = 0; i < events->bgEventCount; i++) { if (events->bgEvents[i].kind == 7 && !FlagGet(GetHiddenItemAttr(events->bgEvents[i].bgUnion.hiddenItem, HIDDEN_ITEM_FLAG))) @@ -230,7 +248,7 @@ static bool8 HiddenItemIsWithinRangeOfPlayer(const struct MapEvents * events, u8 } } FindHiddenItemsInConnectedMaps(taskId); - if (gTasks[taskId].tHiddenItemFound == TRUE) + if (gTasks[taskId].tHiddenItemFound == TRUE || gSprites[gObjectEvents[gPlayerAvatar.objectEventId].fieldEffectSpriteId].tHiddenItemFound) { SetNormalHiddenItem(taskId); return TRUE; @@ -431,7 +449,7 @@ static void RegisterHiddenItemRelativeCoordsIfCloser(u8 taskId, s16 dx, s16 dy) } } -static u8 GetPlayerDirectionTowardsHiddenItem(s16 itemX, s16 itemY) +u8 GetPlayerDirectionTowardsHiddenItem(s16 itemX, s16 itemY) { s16 abX, abY; diff --git a/src/move_relearner.c b/src/move_relearner.c index e0cb96ed8..f3661116a 100644 --- a/src/move_relearner.c +++ b/src/move_relearner.c @@ -496,6 +496,18 @@ static void PrintMessageWithPlaceholders(const u8 *str) MoveRelearnerPrintMessage(gStringVar4, GetPlayerTextSpeedDelay()); } +// If reusable TMs is off, remove the TM from the bag +static void RemoveRelearnerTMFromBag(enum Move move) +{ + enum Item item = GetTMHMItemIdFromMoveId(move); + + if (!I_REUSABLE_TMS && !P_ENABLE_ALL_TM_MOVES + && gMoveRelearnerState == MOVE_RELEARNER_TM_MOVES && GetItemTMHMIndex(item) <= NUM_TECHNICAL_MACHINES) + { + RemoveBagItem(item, 1); + } +} + static void DoMoveRelearnerMain(void) { switch (sMoveRelearnerStruct->state) @@ -717,6 +729,7 @@ static void DoMoveRelearnerMain(void) break; case MENU_STATE_DOUBLE_FANFARE_FORGOT_MOVE: PrintMessageWithPlaceholders(gText_MonForgotOldMoveAndMonLearnedNewMove); + RemoveRelearnerTMFromBag(GetCurrentSelectedMove()); sMoveRelearnerStruct->state = MENU_STATE_PRINT_TEXT_THEN_FANFARE; PlayFanfare(MUS_LEVEL_UP); break; diff --git a/src/oras_dowse.c b/src/oras_dowse.c new file mode 100644 index 000000000..a1c69d104 --- /dev/null +++ b/src/oras_dowse.c @@ -0,0 +1,562 @@ +#include "global.h" +#include "bike.h" +#include "event_data.h" +#include "event_object_lock.h" +#include "event_object_movement.h" +#include "field_effect_helpers.h" +#include "field_effect.h" +#include "field_player_avatar.h" +#include "fldeff.h" +#include "item_use.h" +#include "itemfinder.h" +#include "oras_dowse.h" +#include "overworld.h" +#include "palette.h" +#include "script.h" +#include "sound.h" +#include "task.h" +#include "constants/field_effects.h" +#include "constants/songs.h" +#include "constants/rgb.h" + +static void StartORASDowseFieldEffect(void); +static void UpdateORASDowsingFieldEffect(struct Sprite *sprite); +static void ChangeDowsingColor(enum Direction direction, struct Sprite *sprite); +static void ClearDowsingColor(struct Sprite *sprite); +static void PlayDowseSound(u32 dowseState); + +const u32 gFieldEffectObjectPic_ORASDowsingRed[] = INCBIN_U32("graphics/field_effects/pics/oras_dowsing_red.4bpp"); +const u32 gFieldEffectObjectPic_ORASDowsingGreen[] = INCBIN_U32("graphics/field_effects/pics/oras_dowsing_green.4bpp"); +const u16 gFieldEffectPal_ORASDowsing[] = INCBIN_U16("graphics/field_effects/palettes/oras_dowsing.gbapal"); + +static const struct SpriteFrameImage sPicTable_ORASDowsingRed[] = { + overworld_ascending_frames(gFieldEffectObjectPic_ORASDowsingRed, 2, 4), +}; + +static const struct SpriteFrameImage sPicTable_ORASDowsingGreen[] = { + overworld_ascending_frames(gFieldEffectObjectPic_ORASDowsingGreen, 2, 4), +}; + +static const union AnimCmd sAnim_FaceSouth[] = +{ + ANIMCMD_FRAME(0, 16), + ANIMCMD_JUMP(0), +}; + +static const union AnimCmd sAnim_FaceNorth[] = +{ + ANIMCMD_FRAME(1, 16), + ANIMCMD_JUMP(0), +}; + +static const union AnimCmd sAnim_FaceWest[] = +{ + ANIMCMD_FRAME(2, 16), + ANIMCMD_JUMP(0), +}; + +static const union AnimCmd sAnim_FaceEast[] = +{ + ANIMCMD_FRAME(2, 16, .hFlip = TRUE), + ANIMCMD_JUMP(0), +}; + +static const union AnimCmd sAnim_ORASDowseWiggleSouthSlow[] = +{ + ANIMCMD_FRAME(0, 32), + ANIMCMD_FRAME(0, 32), + ANIMCMD_FRAME(4, 32), + ANIMCMD_FRAME(4, 32), + ANIMCMD_JUMP(0), +}; + +static const union AnimCmd sAnim_ORASDowseWiggleNorthSlow[] = +{ + ANIMCMD_FRAME(1, 32), + ANIMCMD_FRAME(1, 32), + ANIMCMD_FRAME(6, 32), + ANIMCMD_FRAME(6, 32), + ANIMCMD_JUMP(0), +}; + +static const union AnimCmd sAnim_ORASDowseWiggleWestSlow[] = +{ + ANIMCMD_FRAME(2, 32), + ANIMCMD_FRAME(2, 32), + ANIMCMD_FRAME(8, 32), + ANIMCMD_FRAME(8, 32), + ANIMCMD_JUMP(0), +}; + +static const union AnimCmd sAnim_ORASDowseWiggleEastSlow[] = +{ + ANIMCMD_FRAME(2, 32, .hFlip = TRUE), + ANIMCMD_FRAME(2, 32, .hFlip = TRUE), + ANIMCMD_FRAME(8, 32, .hFlip = TRUE), + ANIMCMD_FRAME(8, 32, .hFlip = TRUE), + ANIMCMD_JUMP(0), +}; + +static const union AnimCmd sAnim_ORASDowseWiggleSouth[] = +{ + ANIMCMD_FRAME(0, 32), + ANIMCMD_FRAME(3, 32), + ANIMCMD_FRAME(0, 32), + ANIMCMD_FRAME(4, 32), + ANIMCMD_JUMP(0), +}; + +static const union AnimCmd sAnim_ORASDowseWiggleNorth[] = +{ + ANIMCMD_FRAME(1, 32), + ANIMCMD_FRAME(5, 32), + ANIMCMD_FRAME(1, 32), + ANIMCMD_FRAME(6, 32), + ANIMCMD_JUMP(0), +}; + +static const union AnimCmd sAnim_ORASDowseWiggleWest[] = +{ + ANIMCMD_FRAME(2, 32), + ANIMCMD_FRAME(7, 32), + ANIMCMD_FRAME(2, 32), + ANIMCMD_FRAME(8, 32), + ANIMCMD_JUMP(0), +}; + +static const union AnimCmd sAnim_ORASDowseWiggleEast[] = +{ + ANIMCMD_FRAME(2, 32, .hFlip = TRUE), + ANIMCMD_FRAME(7, 32, .hFlip = TRUE), + ANIMCMD_FRAME(2, 32, .hFlip = TRUE), + ANIMCMD_FRAME(8, 32, .hFlip = TRUE), + ANIMCMD_JUMP(0), +}; + +static const union AnimCmd sAnim_ORASDowseWiggleSouthFast[] = +{ + ANIMCMD_FRAME(0, 16), + ANIMCMD_FRAME(3, 16), + ANIMCMD_FRAME(0, 16), + ANIMCMD_FRAME(4, 16), + ANIMCMD_JUMP(0), +}; + +static const union AnimCmd sAnim_ORASDowseWiggleNorthFast[] = +{ + ANIMCMD_FRAME(1, 16), + ANIMCMD_FRAME(5, 16), + ANIMCMD_FRAME(1, 16), + ANIMCMD_FRAME(6, 16), + ANIMCMD_JUMP(0), +}; + +static const union AnimCmd sAnim_ORASDowseWiggleWestFast[] = +{ + ANIMCMD_FRAME(2, 16), + ANIMCMD_FRAME(7, 16), + ANIMCMD_FRAME(2, 16), + ANIMCMD_FRAME(8, 16), + ANIMCMD_JUMP(0), +}; + +static const union AnimCmd sAnim_ORASDowseWiggleEastFast[] = +{ + ANIMCMD_FRAME(2, 16, .hFlip = TRUE), + ANIMCMD_FRAME(7, 16, .hFlip = TRUE), + ANIMCMD_FRAME(2, 16, .hFlip = TRUE), + ANIMCMD_FRAME(8, 16, .hFlip = TRUE), + ANIMCMD_JUMP(0), +}; + +static const union AnimCmd sAnim_ORASDowseWiggleSouthFaster[] = +{ + ANIMCMD_FRAME(0, 8), + ANIMCMD_FRAME(3, 8), + ANIMCMD_FRAME(0, 8), + ANIMCMD_FRAME(4, 8), + ANIMCMD_JUMP(0), +}; + +static const union AnimCmd sAnim_ORASDowseWiggleNorthFaster[] = +{ + ANIMCMD_FRAME(1, 8), + ANIMCMD_FRAME(5, 8), + ANIMCMD_FRAME(1, 8), + ANIMCMD_FRAME(6, 8), + ANIMCMD_JUMP(0), +}; + +static const union AnimCmd sAnim_ORASDowseWiggleWestFaster[] = +{ + ANIMCMD_FRAME(2, 8), + ANIMCMD_FRAME(7, 8), + ANIMCMD_FRAME(2, 8), + ANIMCMD_FRAME(8, 8), + ANIMCMD_JUMP(0), +}; + +static const union AnimCmd sAnim_ORASDowseWiggleEastFaster[] = +{ + ANIMCMD_FRAME(2, 8, .hFlip = TRUE), + ANIMCMD_FRAME(7, 8, .hFlip = TRUE), + ANIMCMD_FRAME(2, 8, .hFlip = TRUE), + ANIMCMD_FRAME(8, 8, .hFlip = TRUE), + ANIMCMD_JUMP(0), +}; + +static const union AnimCmd *const sAnimTable_ORASDowsing[] = +{ + [ANIM_STD_FACE_SOUTH] = sAnim_FaceSouth, + [ANIM_STD_FACE_NORTH] = sAnim_FaceNorth, + [ANIM_STD_FACE_WEST] = sAnim_FaceWest, + [ANIM_STD_FACE_EAST] = sAnim_FaceEast, + [ANIM_ORAS_DOWSE_WIGGLE_SOUTH_SLOW] = sAnim_ORASDowseWiggleSouthSlow, + [ANIM_ORAS_DOWSE_WIGGLE_NORTH_SLOW] = sAnim_ORASDowseWiggleNorthSlow, + [ANIM_ORAS_DOWSE_WIGGLE_WEST_SLOW] = sAnim_ORASDowseWiggleWestSlow, + [ANIM_ORAS_DOWSE_WIGGLE_EAST_SLOW] = sAnim_ORASDowseWiggleEastSlow, + [ANIM_ORAS_DOWSE_WIGGLE_SOUTH] = sAnim_ORASDowseWiggleSouth, + [ANIM_ORAS_DOWSE_WIGGLE_NORTH] = sAnim_ORASDowseWiggleNorth, + [ANIM_ORAS_DOWSE_WIGGLE_WEST] = sAnim_ORASDowseWiggleWest, + [ANIM_ORAS_DOWSE_WIGGLE_EAST] = sAnim_ORASDowseWiggleEast, + [ANIM_ORAS_DOWSE_WIGGLE_SOUTH_FAST] = sAnim_ORASDowseWiggleSouthFast, + [ANIM_ORAS_DOWSE_WIGGLE_NORTH_FAST] = sAnim_ORASDowseWiggleNorthFast, + [ANIM_ORAS_DOWSE_WIGGLE_WEST_FAST] = sAnim_ORASDowseWiggleWestFast, + [ANIM_ORAS_DOWSE_WIGGLE_EAST_FAST] = sAnim_ORASDowseWiggleEastFast, + [ANIM_ORAS_DOWSE_WIGGLE_SOUTH_FASTER] = sAnim_ORASDowseWiggleSouthFaster, + [ANIM_ORAS_DOWSE_WIGGLE_NORTH_FASTER] = sAnim_ORASDowseWiggleNorthFaster, + [ANIM_ORAS_DOWSE_WIGGLE_WEST_FASTER] = sAnim_ORASDowseWiggleWestFaster, + [ANIM_ORAS_DOWSE_WIGGLE_EAST_FASTER] = sAnim_ORASDowseWiggleEastFaster, +}; + +static const struct OamData gObjectEventOam_ORASDowse = { + .shape = SPRITE_SHAPE(16x32), + .size = SPRITE_SIZE(16x32), + .priority = 2 +}; + +const struct SpriteTemplate gFieldEffectObjectTemplate_ORASDowsingRed = { + .tileTag = TAG_NONE, + .paletteTag = FLDEFF_PAL_TAG_ORAS_DOWSE, + .oam = &gObjectEventOam_ORASDowse, + .anims = sAnimTable_ORASDowsing, + .images = sPicTable_ORASDowsingRed, + .callback = UpdateORASDowsingFieldEffect, +}; + +const struct SpriteTemplate gFieldEffectObjectTemplate_ORASDowsingGreen = { + .tileTag = TAG_NONE, + .paletteTag = FLDEFF_PAL_TAG_ORAS_DOWSE, + .oam = &gObjectEventOam_ORASDowse, + .anims = sAnimTable_ORASDowsing, + .images = sPicTable_ORASDowsingGreen, + .callback = UpdateORASDowsingFieldEffect, +}; + +void Task_UseORASDowsingMachine(u8 taskId) +{ + if (FlagGet(I_ORAS_DOWSING_FLAG)) + { + EndORASDowsing(); + } + else + { + if (TestPlayerAvatarFlags(PLAYER_AVATAR_FLAG_BIKE)) + GetOnOffBike(0); + + StartORASDowseFieldEffect(); + } + ScriptUnfreezeObjectEvents(); + UnlockPlayerFieldControls(); + DestroyTask(taskId); +} + +static void StartORASDowseFieldEffect(void) +{ + struct ObjectEvent *playerObj = &gObjectEvents[gPlayerAvatar.objectEventId]; + + gFieldEffectArguments[0] = playerObj->currentCoords.x; + gFieldEffectArguments[1] = playerObj->currentCoords.y; + FieldEffectStart(FLDEFF_ORAS_DOWSE); +} + +void ResumeORASDowseFieldEffect(void) +{ + if (I_ORAS_DOWSING_FLAG != 0 && FlagGet(I_ORAS_DOWSING_FLAG)) + StartORASDowseFieldEffect(); +} + +static const struct SpritePalette gSpritePalette_ORASDowsing = {gFieldEffectPal_ORASDowsing, FLDEFF_PAL_TAG_ORAS_DOWSE}; + +// Sprite data for ORAS Dowsing Machine +#define tItemDistanceX data[0] +#define tItemDistanceY data[1] +#define sItemFound data[2] +#define sCounter data[3] +#define sSoundTimer data[4] +#define sDowseState data[5] +#define sPrevDowseState data[6] +#define sMoveActive data[7] + +#define fPlayerX gFieldEffectArguments[0] +#define fPlayerY gFieldEffectArguments[1] + +// Create the ORAS Dowsing Machine sprite. +u32 FldEff_ORASDowsing(void) +{ + struct ObjectEvent *playerObj = &gObjectEvents[gPlayerAvatar.objectEventId]; + u32 spriteId; + u32 palNum; + + FlagSet(I_ORAS_DOWSING_FLAG); + SetSpritePosToOffsetMapCoords((s16 *)&fPlayerX, (s16 *)&fPlayerY, 8, 0); + if (gPlayerAvatar.gender == MALE) + spriteId = CreateSpriteAtEnd(&gFieldEffectObjectTemplate_ORASDowsingRed, fPlayerX, fPlayerY, 1); + else + spriteId = CreateSpriteAtEnd(&gFieldEffectObjectTemplate_ORASDowsingGreen, fPlayerX, fPlayerY, 1); + + if (spriteId != MAX_SPRITES) + { + struct Sprite *sprite = &gSprites[spriteId]; + sprite->coordOffsetEnabled = TRUE; + palNum = LoadSpritePalette(&gSpritePalette_ORASDowsing); + if (palNum != 0xFF) + sprite->oam.paletteNum = palNum; + else + sprite->oam.paletteNum = LoadPlayerObjectEventPalette(gSaveBlock2Ptr->playerGender); + + playerObj->fieldEffectSpriteId = spriteId; + sprite->sDowseState = ORASD_WIGGLE_NONE; + UpdateDowseState(sprite); + } + FieldEffectActiveListRemove(FLDEFF_ORAS_DOWSE); + return spriteId; +} + +// Callback for ORAS Dowsing Machine sprite. +static void UpdateORASDowsingFieldEffect(struct Sprite *sprite) +{ + struct ObjectEvent *playerObj = &gObjectEvents[gPlayerAvatar.objectEventId]; + struct Sprite *playerSprite = &gSprites[playerObj->spriteId]; + + if (!FlagGet(I_ORAS_DOWSING_FLAG)) + { + DestroySpriteAndFreeResources(sprite); + return; + } + + sprite->x = playerSprite->x; + sprite->y = playerSprite->y; + sprite->x2 = playerSprite->x2; + sprite->y2 = playerSprite->y2; + + if (playerSprite->anims[playerSprite->animNum][playerSprite->animCmdIndex].frame.imageValue > 2) + sprite->y2++; + + if (playerObj->previousMovementDirection != playerObj->movementDirection) + UpdateDowsingAnimDirection(sprite, playerObj); + + if (playerObj->movementActionId != MOVEMENT_ACTION_NONE) + { + if (playerObj->heldMovementFinished == FALSE) + { + if (sprite->sCounter == 0) + { + sprite->sMoveActive = TRUE; + sprite->sCounter++; + } + } + else if (playerObj->heldMovementFinished == TRUE && sprite->sMoveActive) + { + sprite->sMoveActive = FALSE; + sprite->sCounter = 0; + UpdateDowseState(sprite); + } + } + + if (I_ORAS_DOWSING_SOUNDS && sprite->sDowseState == ORASD_WIGGLE_FASTER && playerObj->heldMovementFinished != FALSE) + { + if (++sprite->sSoundTimer == 70) + { + PlaySE(SE_ITEMFINDER); + sprite->sSoundTimer = 0; + } + } + sprite->oam.priority = playerSprite->oam.priority; +} + +static const u8 sClockwiseDirections[] = {DIR_NORTH, DIR_EAST, DIR_SOUTH, DIR_WEST}; + +void UpdateDowseState(struct Sprite *sprite) +{ + struct ObjectEvent *playerObj = &gObjectEvents[gPlayerAvatar.objectEventId]; + + sprite->tItemDistanceX = 0; + sprite->tItemDistanceY = 0; + sprite->sPrevDowseState = sprite->sDowseState; + if (HiddenItemIsWithinRangeOfPlayer(gMapHeader.events, TASK_NONE) == TRUE) + { + s8 distX = sprite->tItemDistanceX; + s8 distY = sprite->tItemDistanceY; + enum Direction directionToItem = CARDINAL_DIRECTION_COUNT; + enum Direction playerDirToItem = GetPlayerDirectionTowardsHiddenItem(distX, distY); + if (playerDirToItem != DIR_NONE) + directionToItem = sClockwiseDirections[GetPlayerDirectionTowardsHiddenItem(distX, distY) - 1]; + + if (distX < 0) + distX *= -1; + + if (distY < 0) + distY *= -1; + + // If the player is facing the item's direction. + if (directionToItem == playerObj->movementDirection) + { + ChangeDowsingColor(directionToItem, sprite); + } + // If x and y distances are equal, make sure item can bee seen from both facing directions. + else if (distX == distY && distX != 0) + { + if ((directionToItem == DIR_NORTH || directionToItem == DIR_SOUTH) && sprite->tItemDistanceX > 0 && playerObj->movementDirection == DIR_EAST) + ChangeDowsingColor(DIR_EAST, sprite); + else if ((directionToItem == DIR_NORTH || directionToItem == DIR_SOUTH) && sprite->tItemDistanceX < 0 && playerObj->movementDirection == DIR_WEST) + ChangeDowsingColor(DIR_WEST, sprite); + else + ClearDowsingColor(sprite); + } + else + { + ClearDowsingColor(sprite); + } + } + else + { + ClearDowsingColor(sprite); + } + UpdateDowsingAnimDirection(sprite, playerObj); +} + +static void ChangeDowsingColor(enum Direction direction, struct Sprite *sprite) +{ + s16 distance; + u16 color = I_ORAS_DOWSING_COLOR_NONE; + + if (direction == DIR_NORTH || direction == DIR_SOUTH) + distance = sprite->tItemDistanceY; + else + distance = sprite->tItemDistanceX; + + // Absolute value. + if (distance < 0) + distance *= -1; + + switch (distance) + { + case 1: + if (sprite->tItemDistanceX == 0 || sprite->tItemDistanceY == 0) + { + color = I_ORAS_DOWSING_COLOR_FASTER; + sprite->sDowseState = ORASD_WIGGLE_FASTER; + break; + } + case 2: + color = I_ORAS_DOWSING_COLOR_FAST; + sprite->sDowseState = ORASD_WIGGLE_FAST; + break; + case 3: + case 4: + color = I_ORAS_DOWSING_COLOR_NORMAL; + sprite->sDowseState = ORASD_WIGGLE_NORMAL; + break; + case 5: + case 6: + case 7: + color = I_ORAS_DOWSING_COLOR_SLOW; + sprite->sDowseState = ORASD_WIGGLE_SLOW; + break; + } + + if (I_ORAS_DOWSING_SOUNDS && sprite->sDowseState != sprite->sPrevDowseState) + { + sprite->sSoundTimer = 0; + PlayDowseSound(sprite->sDowseState); + } + + FillPalette(color, (OBJ_PLTT_ID(IndexOfSpritePaletteTag(FLDEFF_PAL_TAG_ORAS_DOWSE)) + I_ORAS_DOWSING_COLOR_PAL), PLTT_SIZEOF(1)); + UpdateSpritePaletteWithTime(IndexOfSpritePaletteTag(FLDEFF_PAL_TAG_ORAS_DOWSE)); +} + +static void ClearDowsingColor(struct Sprite *sprite) +{ + sprite->sDowseState = ORASD_WIGGLE_NONE; + FillPalette(I_ORAS_DOWSING_COLOR_NONE, (OBJ_PLTT_ID(IndexOfSpritePaletteTag(FLDEFF_PAL_TAG_ORAS_DOWSE)) + I_ORAS_DOWSING_COLOR_PAL), PLTT_SIZEOF(1)); + UpdateSpritePaletteWithTime(IndexOfSpritePaletteTag(FLDEFF_PAL_TAG_ORAS_DOWSE)); +} + +static void PlayDowseSound(u32 dowseState) +{ + switch (dowseState) + { + case ORASD_WIGGLE_SLOW: + PlaySE(SE_CONTEST_ICON_CLEAR); + return; + case ORASD_WIGGLE_NORMAL: + PlaySE(SE_PIN); + return; + case ORASD_WIGGLE_FAST: + PlaySE(SE_SUCCESS); + return; + case ORASD_WIGGLE_FASTER: + PlaySE(SE_ITEMFINDER); + return; + } +} + +void UpdateDowsingAnimDirection(struct Sprite *sprite, struct ObjectEvent *playerObj) +{ + u32 anim = (playerObj->facingDirection - 1); + + switch (sprite->sDowseState) + { + case ORASD_WIGGLE_SLOW: + anim += 4; + break; + case ORASD_WIGGLE_NORMAL: + anim += 8; + break; + case ORASD_WIGGLE_FAST: + anim += 12; + break; + case ORASD_WIGGLE_FASTER: + anim += 16; + break; + } + + // Don't completely restart anim if wiggling didn't stop. + if (sprite->sPrevDowseState != ORASD_WIGGLE_NONE && sprite->sDowseState != ORASD_WIGGLE_NONE) + SetAndStartSpriteAnim(sprite, anim, sprite->animCmdIndex); + else + StartSpriteAnimIfDifferent(sprite, anim); +} + +void EndORASDowsing(void) +{ + if (I_ORAS_DOWSING_FLAG != 0 && FlagGet(I_ORAS_DOWSING_FLAG)) + FlagClear(I_ORAS_DOWSING_FLAG); +} + +void Script_ClearDowsingColor(void) +{ + if (I_ORAS_DOWSING_FLAG != 0 && FlagGet(I_ORAS_DOWSING_FLAG)) + { + struct Sprite *sprite = &gSprites[gObjectEvents[gPlayerAvatar.objectEventId].fieldEffectSpriteId]; + ClearDowsingColor(sprite); + UpdateDowsingAnimDirection(sprite, &gObjectEvents[gPlayerAvatar.objectEventId]); + } +} + +void Script_UpdateDowseState(void) +{ + if (I_ORAS_DOWSING_FLAG != 0 && FlagGet(I_ORAS_DOWSING_FLAG)) + UpdateDowseState(&gSprites[gObjectEvents[gPlayerAvatar.objectEventId].fieldEffectSpriteId]); +} diff --git a/src/overworld.c b/src/overworld.c index 38390b8c4..e5630ba25 100644 --- a/src/overworld.c +++ b/src/overworld.c @@ -43,6 +43,7 @@ #include "money.h" #include "new_game.h" #include "overworld.h" +#include "oras_dowse.h" #include "palette.h" #include "play_time.h" #include "quest_log_objects.h" @@ -2178,6 +2179,7 @@ static bool32 ReturnToFieldLocal(u8 *state) case 2: InitViewGraphics(); FollowerNPC_BindToSurfBlobOnReloadScreen(); + ResumeORASDowseFieldEffect(); SetHelpContextForMap(); (*state)++; break; diff --git a/src/wild_encounter.c b/src/wild_encounter.c index ab077ccac..412564137 100644 --- a/src/wild_encounter.c +++ b/src/wild_encounter.c @@ -939,14 +939,10 @@ static bool8 IsWildLevelAllowedByRepel(u8 wildLevel) for (i = 0; i < PARTY_SIZE; i++) { - if (GetMonData(&gPlayerParty[i], MON_DATA_HP) && !GetMonData(&gPlayerParty[i], MON_DATA_IS_EGG)) + if (I_REPEL_INCLUDE_FAINTED == GEN_1 || I_REPEL_INCLUDE_FAINTED >= GEN_6 || GetMonData(&gPlayerParty[i], MON_DATA_HP)) { - u8 ourLevel = GetMonData(&gPlayerParty[i], MON_DATA_LEVEL); - - if (wildLevel < ourLevel) - return FALSE; - else - return TRUE; + if (!GetMonData(&gPlayerParty[i], MON_DATA_IS_EGG)) + return wildLevel >= GetMonData(&gPlayerParty[i], MON_DATA_LEVEL); } }