Working on tutorial refactoring

This commit is contained in:
Vladislav Khorev committed 2026-10-23 22:03:55 +06:00
1 parent ea8f64c940
commit 9fa120d4ad
82 files changed
+1877 -7563

No files matched your search

+26 -31
View File
@@ -394,7 +394,9 @@ namespace FRG
menuManager.startGameFunc = [this]() {
mainThreadHandler.EnqueueMainThreadTask([this]() {
performResetToInitialState();
applyTutorialSetting();
gameState.currentLocationName = "location_dorm";
menuManager.showGameplayHud(); // first HUD frame drawn from the fresh state
currentLocation()->scriptEngine.callLocationEnterCallback();
this->audioPlayer->crossFadeMusicAsync("music/obshaga.ogg");
menuManager.lastMusicTrack = "music/obshaga.ogg";
@@ -471,14 +473,6 @@ namespace FRG
it->second->onPlayerTaxiRequired = [this]() {
menuManager.tutorialShowTaxiHint();
};
menuManager.tutorialUnlockInteractiveObjectsFunc = [this]()
{
if (gameState.locations["location_dorm"])
{
gameState.locations["location_dorm"]->state.tutorialInteractiveObjectsLocked = false;
}
};
}
void Game::performFullReset() {
@@ -491,10 +485,7 @@ namespace FRG
gameState.money = 5500;
gameState.globalInts.clear();
gameState.globalFloats.clear();
gameState.tutorialStep = TutorialStep::Step0;
gameState.uniIntTutorialState = UniIntTutorialState::Step10;
gameState.tutorialPhonePickedUp = false;
gameState.tutorialJournalPickedUp = false;
gameState.tutorialStep = TutorialStep::AdvanceDialogue;
gameState.tutorialPhoneChatScreenOpened = false;
gameState.tutorialJournalScreenOpened = false;
gameState.tutorialNeedOpenTaxiScreen = false;
@@ -547,7 +538,7 @@ namespace FRG
// sol2 state (GameState::load only touches map entries
// that already exist).
// Locations survive this reset, so any one-shot callbacks they consumed
// during the previous playthrough (tutorial unlock, taxi request) must be
// during the previous playthrough (taxi request) must be
// re-armed here -- createLocations() normally does this, but doesn't run
// on this fast path.
rearmDormOneShotCallbacks();
@@ -564,6 +555,13 @@ namespace FRG
performFullReset();
}
// Runs after either reset path. start_state.json always holds the start of the
// tutorial; a disabled tutorial is simply one that is already completed.
void Game::applyTutorialSetting() {
if (!menuManager.tutorialEnabledSetting)
gameState.tutorialStep = TutorialStep::Completed;
}
void Game::saveInitialState() {
nlohmann::json root;
gameState.save(root);
@@ -837,7 +835,10 @@ namespace FRG
if (gameState.locations["location_dorm"]->player)
gameState.locations["location_dorm"]->player->state.onDeathAnimComplete = [this]() { startDarklandsTransition(); };
gameState.locations["location_dorm"]->state.tutorialInteractiveObjectsLocked = true;
// Objects can be picked up once the tutorial reaches "pick up an item".
gameState.locations["location_dorm"]->areInteractiveObjectsLocked = [this]() {
return gameState.tutorialStep < TutorialStep::PickUpItem;
};
//Dorm set up taxi:
@@ -928,15 +929,13 @@ namespace FRG
}
// Wire tutorial advance callbacks for all locations.
// advanceTutorialStep() guards against double-advancing, so sharing is safe.
// completeTutorialStep() only acts on the current step, so sharing is safe.
for (auto& [name, loc] : gameState.locations) {
loc->dialogueSystem.setOnDialogueAdvanced([this]() {
menuManager.advanceTutorialStep();
gameState.completeTutorialStep(TutorialStep::AdvanceDialogue);
});
loc->onPlayerFloorWalk = [this]() {
if (gameState.tutorialStep == TutorialStep::Step2) {
menuManager.advanceTutorialStep();
}
gameState.completeTutorialStep(TutorialStep::Walk);
menuManager.onPlayerStartedWalking();
};
}
@@ -1434,10 +1433,8 @@ namespace FRG
Environment::zoom = zoomMax;
}
//logger() << "Current zoom: " << Environment::zoom << std::endl;
// Tutorial step3 → step4: any mouse-wheel scroll counts as "zoom gesture".
if (gameState.tutorialStep == TutorialStep::Step3) {
menuManager.advanceTutorialStep();
}
// Tutorial: any mouse-wheel scroll counts as the "zoom gesture".
gameState.completeTutorialStep(TutorialStep::Zoom);
}
if (event.type == SDL_KEYDOWN && event.key.repeat == 0) {
@@ -1595,11 +1592,9 @@ namespace FRG
if (newZoom > zoomMax) newZoom = zoomMax;
Environment::zoom = newZoom;
// Tutorial step3 → step4: detect a significant pinch-zoom (≥ 2 zoom units).
if (gameState.tutorialStep == TutorialStep::Step3) {
if (std::abs(Environment::zoom - pinchStartZoom) >= 2.0f) {
menuManager.advanceTutorialStep();
}
// Tutorial: detect a significant pinch-zoom (≥ 2 zoom units).
if (std::abs(Environment::zoom - pinchStartZoom) >= 2.0f) {
gameState.completeTutorialStep(TutorialStep::Zoom);
}
}
@@ -1738,16 +1733,16 @@ namespace FRG
// Forwarded for dialogue hover and (when cameraDragging) camera rotation.
currentLocation()->handleMotion(fingerId, eventX, eventY, mx, my);
// Tutorial step1 → step2: detect a significant camera rotation on BOTH axes.
// Tutorial: detect a significant camera rotation on BOTH axes.
// ~0.15 rad (≈8.6°) per axis ensures the user intentionally panned in 2D,
// not just nudged a single axis by accident.
static constexpr float TUTORIAL_ROTATION_THRESHOLD = 0.15f;
if (cameraDragging
&& gameState.tutorialStep == TutorialStep::Step1) {
&& gameState.tutorialStep == TutorialStep::RotateCamera) {
float deltaAz = std::abs(currentLocation()->state.cameraAzimuth - dragStartAzimuth);
float deltaInc = std::abs(currentLocation()->state.cameraInclination - dragStartInclination);
if (deltaAz >= TUTORIAL_ROTATION_THRESHOLD && deltaInc >= TUTORIAL_ROTATION_THRESHOLD) {
menuManager.advanceTutorialStep();
gameState.completeTutorialStep(TutorialStep::RotateCamera);
}
}
}