mirror of
https://github.com/pret/pokefirered.git
synced 2026-04-25 15:28:53 -05:00
Merge pull request #160 from MiyazakiTheFalse/codex/add-tutorial-for-first-time-chase-state
Add one-time chase tutorial and optional failure reminder
This commit is contained in:
commit
4b8b59c807
16
docs/chase_tutorial_design_notes.md
Normal file
16
docs/chase_tutorial_design_notes.md
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
# Chase tutorial design notes
|
||||
|
||||
## Goal
|
||||
Provide a one-time, lightweight explanation the first time a player enters chase state, then offer an optional reminder if the player repeatedly fails chase re-engagements.
|
||||
|
||||
## Rule framing reference
|
||||
Tutorial text should stay aligned with the chase continuation and safe-hub rules documented in [`docs/chase_boundary_policy.md`](./chase_boundary_policy.md):
|
||||
- Chasers pursue while chase state is active.
|
||||
- Safe/scripted hubs (towns, cities, indoors) terminate chase.
|
||||
- Encounter-eligible terrain is used for re-engagement attempts while chase remains active.
|
||||
|
||||
## Runtime behavior
|
||||
- **First-time tutorial** is queued when chase starts for the first time in a save.
|
||||
- **Reminder hint** is queued after repeated chase failures (currently two consecutive chase-battle escapes/teleports that continue pressure).
|
||||
- Messages are shown only when no script is running and no field message box is active.
|
||||
- Reminder is optional and one-time per save.
|
||||
|
|
@ -1408,6 +1408,8 @@
|
|||
#define FLAG_SYS_UNLOCKED_TANOBY_RUINS (SYS_FLAGS + 0x49)
|
||||
#define FLAG_ENABLE_SHIP_NAVEL_ROCK (SYS_FLAGS + 0x4A)
|
||||
#define FLAG_ENABLE_SHIP_BIRTH_ISLAND (SYS_FLAGS + 0x4B)
|
||||
#define FLAG_SYS_CHASE_TUTORIAL_SEEN (SYS_FLAGS + 0x4C)
|
||||
#define FLAG_SYS_CHASE_FAILURE_REMINDER_SEEN (SYS_FLAGS + 0x4D)
|
||||
|
||||
// World Map Flags
|
||||
#define FLAG_WORLD_MAP_PALLET_TOWN (SYS_FLAGS + 0x90)
|
||||
|
|
|
|||
|
|
@ -1030,6 +1030,8 @@ extern const u8 gText_StaminaHudLabel[];
|
|||
extern const u8 gText_ChaseHudInactive[];
|
||||
extern const u8 gText_ChaseHudChasersLabel[];
|
||||
extern const u8 gText_ChaseHudStepsLabel[];
|
||||
extern const u8 gText_ChaseTutorialIntro[];
|
||||
extern const u8 gText_ChaseTutorialReminder[];
|
||||
extern const u8 gText_TrainerCardYen[];
|
||||
extern const u8 gText_TrainerCardPokedex[];
|
||||
extern const u8 gText_TrainerCardNull[];
|
||||
|
|
|
|||
|
|
@ -16,11 +16,13 @@
|
|||
#include "strings.h"
|
||||
#include "wild_encounter.h"
|
||||
#include "battle_anim.h"
|
||||
#include "event_data.h"
|
||||
#include "field_message_box.h"
|
||||
#include "script.h"
|
||||
#include "overworld_hud.h"
|
||||
#include "palette.h"
|
||||
#include "script.h"
|
||||
#include "sound.h"
|
||||
#include "constants/battle.h"
|
||||
#include "constants/flags.h"
|
||||
#include "constants/map_types.h"
|
||||
|
||||
#define STAMINA_LEVEL_MIN 1
|
||||
|
|
@ -46,6 +48,7 @@
|
|||
#define CHASE_STEPS_MIN 30
|
||||
#define CHASE_STEPS_MAX 140
|
||||
|
||||
#define CHASE_FAILURE_REMINDER_THRESHOLD 2
|
||||
typedef enum
|
||||
{
|
||||
CHASE_END_FEEDBACK_NONE,
|
||||
|
|
@ -64,9 +67,15 @@ static EWRAM_DATA u16 sChaseStepsRemaining = 0;
|
|||
static EWRAM_DATA u8 sChaseReengageStepCountdown = 0;
|
||||
static EWRAM_DATA bool8 sPendingWildFirstMovePriority = FALSE;
|
||||
static EWRAM_DATA bool8 sBattleUsesWildFirstMovePriority = FALSE;
|
||||
static EWRAM_DATA bool8 sPendingChaseTutorialMessage = FALSE;
|
||||
static EWRAM_DATA bool8 sPendingChaseReminderMessage = FALSE;
|
||||
static EWRAM_DATA u8 sConsecutiveChaseFailures = 0;
|
||||
static EWRAM_DATA u8 sPendingChaseEndFeedback = CHASE_END_FEEDBACK_NONE;
|
||||
|
||||
static bool8 IsMapTypeChaseCompatible(u8 mapType);
|
||||
static void QueueChaseTutorialIfNeeded(void);
|
||||
static void QueueChaseFailureReminderIfNeeded(void);
|
||||
static void TryShowPendingChaseMessage(void);
|
||||
|
||||
static u8 GetStaminaLevel(void)
|
||||
{
|
||||
|
|
@ -155,6 +164,47 @@ static bool8 IsCurrentAreaValidForActiveChase(void)
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static void QueueChaseTutorialIfNeeded(void)
|
||||
{
|
||||
if (FlagGet(FLAG_SYS_CHASE_TUTORIAL_SEEN))
|
||||
return;
|
||||
|
||||
FlagSet(FLAG_SYS_CHASE_TUTORIAL_SEEN);
|
||||
sPendingChaseTutorialMessage = TRUE;
|
||||
}
|
||||
|
||||
static void QueueChaseFailureReminderIfNeeded(void)
|
||||
{
|
||||
if (FlagGet(FLAG_SYS_CHASE_FAILURE_REMINDER_SEEN))
|
||||
return;
|
||||
|
||||
if (sConsecutiveChaseFailures < CHASE_FAILURE_REMINDER_THRESHOLD)
|
||||
return;
|
||||
|
||||
FlagSet(FLAG_SYS_CHASE_FAILURE_REMINDER_SEEN);
|
||||
sPendingChaseReminderMessage = TRUE;
|
||||
}
|
||||
|
||||
static void TryShowPendingChaseMessage(void)
|
||||
{
|
||||
const u8 *message = NULL;
|
||||
|
||||
if (ScriptContext_IsEnabled() || !IsFieldMessageBoxHidden())
|
||||
return;
|
||||
|
||||
if (sPendingChaseTutorialMessage)
|
||||
{
|
||||
message = gText_ChaseTutorialIntro;
|
||||
sPendingChaseTutorialMessage = FALSE;
|
||||
}
|
||||
else if (sPendingChaseReminderMessage)
|
||||
{
|
||||
message = gText_ChaseTutorialReminder;
|
||||
sPendingChaseReminderMessage = FALSE;
|
||||
}
|
||||
|
||||
if (message != NULL)
|
||||
ShowFieldMessage(message);
|
||||
static void EndChase(bool8 shouldQueueFeedback, u8 feedbackType)
|
||||
static bool8 ShouldSuppressChaseStartFeedback(void)
|
||||
{
|
||||
|
|
@ -203,6 +253,8 @@ static void StartChase(u8 initialChasers, u16 initialSteps)
|
|||
sActiveChasers = initialChasers;
|
||||
sChaseStepsRemaining = initialSteps;
|
||||
sChaseReengageStepCountdown = CHASE_REENGAGE_COUNTDOWN_MIN;
|
||||
sConsecutiveChaseFailures = 0;
|
||||
QueueChaseTutorialIfNeeded();
|
||||
|
||||
if (!wasActive && ChaseStamina_IsChaseActive())
|
||||
TryShowChaseStartFeedback();
|
||||
|
|
@ -384,6 +436,8 @@ void ChaseStamina_UpdateOverworldFrame(bool8 tookStep)
|
|||
}
|
||||
}
|
||||
|
||||
TryShowPendingChaseMessage();
|
||||
|
||||
if (!tookStep)
|
||||
return;
|
||||
|
||||
|
|
@ -502,6 +556,9 @@ void ChaseStamina_OnWildBattleEnded(u8 battleOutcome, u32 battleTypeFlags)
|
|||
if (sChaseStepsRemaining < chaseLength)
|
||||
sChaseStepsRemaining = chaseLength;
|
||||
RollChaseReengageStepCountdown();
|
||||
if (sConsecutiveChaseFailures < 255)
|
||||
sConsecutiveChaseFailures++;
|
||||
QueueChaseFailureReminderIfNeeded();
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -510,6 +567,7 @@ void ChaseStamina_OnWildBattleEnded(u8 battleOutcome, u32 battleTypeFlags)
|
|||
{
|
||||
if (sActiveChasers != 0)
|
||||
sActiveChasers--;
|
||||
sConsecutiveChaseFailures = 0;
|
||||
if (sActiveChasers == 0)
|
||||
EndChase(TRUE, CHASE_END_FEEDBACK_ENDED);
|
||||
break;
|
||||
|
|
@ -523,11 +581,15 @@ void ChaseStamina_OnWildBattleEnded(u8 battleOutcome, u32 battleTypeFlags)
|
|||
case B_OUTCOME_MON_TELEPORTED:
|
||||
case B_OUTCOME_LINK_BATTLE_RAN:
|
||||
// Forced-end and escape outcomes clear the chase to keep its state deterministic.
|
||||
sConsecutiveChaseFailures = 0;
|
||||
EndChase();
|
||||
EndChase(FALSE, CHASE_END_FEEDBACK_NONE);
|
||||
break;
|
||||
|
||||
default:
|
||||
// Any unknown outcome is treated as a forced end to avoid stale chase state.
|
||||
sConsecutiveChaseFailures = 0;
|
||||
EndChase();
|
||||
EndChase(FALSE, CHASE_END_FEEDBACK_NONE);
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -855,6 +855,17 @@ const u8 gText_StaminaHudLabel[] = _("STA ");
|
|||
const u8 gText_ChaseHudInactive[] = _("CHASE: OFF");
|
||||
const u8 gText_ChaseHudChasersLabel[] = _("CHASERS ");
|
||||
const u8 gText_ChaseHudStepsLabel[] = _("STEPS ");
|
||||
const u8 gText_ChaseTutorialIntro[] = _("You're being chased!\p"
|
||||
"Chasers pursue you while CHASE is active.\n"
|
||||
"Reach a safe hub (town/city/indoors)\n"
|
||||
"to end it.\p"
|
||||
"If an encounter starts before the timer\n"
|
||||
"runs out, the chase can re-engage.\n"
|
||||
"Keep moving!");
|
||||
const u8 gText_ChaseTutorialReminder[] = _("Hint: if you keep getting caught,\n"
|
||||
"head for a safe hub to reset pressure.\n"
|
||||
"On routes, avoid long grass/water\n"
|
||||
"until you're ready to re-engage.");
|
||||
const u8 gText_TrainerCardYen[] = _("¥");
|
||||
const u8 gText_TrainerCardPokedex[] = _("POKéDEX");
|
||||
const u8 gText_TrainerCardNull[] = _("");
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user