// © 2025 Naked People Team. All Rights Reserved. #include "SessionManagerSubsystem.h" #include "Kismet/GameplayStatics.h" #include "NakedDesire/Global/Constants.h" #include "NakedDesire/Global/NakedDesireGameplayTags.h" #include "NakedDesire/Locations/LocationData.h" #include "NakedDesire/Locations/LocationSubsystem.h" #include "NakedDesire/Player/NakedDesireCharacter.h" #include "NakedDesire/Stats/StatsManager.h" void USessionManagerSubsystem::OnWorldBeginPlay(UWorld& InWorld) { Super::OnWorldBeginPlay(InWorld); // The apartment threshold is now a location event (Location.Apartment), not a per-trigger flag. if (ULocationSubsystem* Locations = InWorld.GetSubsystem()) { Locations->OnLocationEntered.AddDynamic(this, &USessionManagerSubsystem::HandleLocationEntered); Locations->OnLocationExited.AddDynamic(this, &USessionManagerSubsystem::HandleLocationExited); } // The player pawn and its UStatsManager may not have finished BeginPlay when // the world begins play, so defer binding by one tick. InWorld.GetTimerManager().SetTimerForNextTick(this, &USessionManagerSubsystem::BindToPlayerStats); } void USessionManagerSubsystem::BindToPlayerStats() { ANakedDesireCharacter* Player = Cast(UGameplayStatics::GetPlayerCharacter(this, SLOT_PLAYER)); if (!Player || !Player->StatsManager) { UE_LOG(LogTemp, Warning, TEXT("USessionManagerSubsystem: no player StatsManager to bind to; loss detection disabled.")); return; } Player->StatsManager->EmbarrassmentUpdate.AddDynamic(this, &USessionManagerSubsystem::HandleEmbarrassmentUpdate); Player->StatsManager->EnergyUpdate.AddDynamic(this, &USessionManagerSubsystem::HandleEnergyUpdate); } void USessionManagerSubsystem::HandleLocationEntered(ULocationData* Location) { // Returning to the apartment is the safe end of a session (§4.3). if (Location && Location->Tag.MatchesTag(TAG_Location_Apartment) && bSessionActive) { EndSession(ESessionLossCause::SafeReturn); } } void USessionManagerSubsystem::HandleLocationExited(ULocationData* Location) { // Leaving the apartment is the only way to start a session (§4.1). if (Location && Location->Tag.MatchesTag(TAG_Location_Apartment) && !bSessionActive) { StartSession(); } } void USessionManagerSubsystem::StartSession() { bSessionActive = true; OnSessionStart.Broadcast(); } void USessionManagerSubsystem::EndSession(const ESessionLossCause Cause) { if (!bSessionActive) return; bSessionActive = false; OnSessionEnd.Broadcast(Cause); } void USessionManagerSubsystem::HandleEmbarrassmentUpdate(const float CurrentValue, const float MaxValue) { if (bSessionActive && MaxValue > 0.0f && CurrentValue >= MaxValue) { EndSession(ESessionLossCause::EmbarrassmentMax); } } void USessionManagerSubsystem::HandleEnergyUpdate(const float CurrentValue, const float MaxValue) { if (bSessionActive && CurrentValue <= 0.0f) { EndSession(ESessionLossCause::EnergyZero); } }