// Lot CAM-B2c - indicateur du mode de camera (SPEC : Docs/Migration/etat/CAM/CAM-B2c-SPEC.md). // // Le joueur ne sait pas toujours quelle camera est active (C1, C2, C3, carte de la ville, studio, // constructeur). Toutes les 0,1 s, ce sous-systeme lit la cible de vue du PlayerController et quelques // variables de GI et de Room par reflexion, en deduit le mode (table du paragraphe 2 de la SPEC) et // l'affiche en petit, en bas a gauche de l'ecran. Le texte est masque quand un menu est ouvert (meme // test que LPDirectControlSubsystem). Aucun Blueprint ni asset n'est modifie ; propriete absente ou // reference nulle : rien n'est affiche. #pragma once #include "CoreMinimal.h" #include "Containers/Ticker.h" #include "Subsystems/GameInstanceSubsystem.h" #include "LPCameraModeSubsystem.generated.h" class AActor; class APlayerController; class UGameInstance; class SWidget; class STextBlock; class UGameViewportClient; class UButton; class UTextBlock; class UUserWidget; UCLASS() class LIFEPLAY_API ULPCameraModeSubsystem : public UGameInstanceSubsystem { GENERATED_BODY() public: virtual void Initialize(FSubsystemCollectionBase& Collection) override; virtual void Deinitialize() override; private: bool Tick(float DeltaTime); /** Libelle du mode courant ; vide si aucun mode n'est reconnu. */ FString ComputeLabel() const; /** Cree le texte et l'ajoute une fois au viewport de ce GameInstance ; faux sans viewport. */ bool EnsureWidget(); /** Retire le texte du viewport qui le porte, s'il existe encore. */ void RemoveWidget(); void SetShown(bool bShow); /** Temoin C2 (CAM-B2f, journal seulement) : camera trop pres de la tete, et ce que la sonde Camera touche. */ void WitnessC2(float DeltaTime); /** Temoin touche C (CAM-B2j, journal seulement) : a chaque image, front montant d'une touche de SwitchCamera. */ bool TickSwitchKey(float DeltaTime); /** Ecrit les drapeaux qui gardent la touche C (PC, GI, Room) et la vue courante. */ void LogSwitchKey(const APlayerController* PC) const; FTSTicker::FDelegateHandle TickHandle; FTSTicker::FDelegateHandle SwitchKeyHandle; /** Une touche de SwitchCamera etait enfoncee a l'image precedente. */ bool bSwitchKeyDown = false; /** Vue deja signalee par « Indicateur de camera : aucun » (une ligne par changement de vue). */ FString LastEmptyView; /** Delai avant la prochaine ligne du temoin C2 (au plus une par seconde). */ float WitnessCooldown = 0.f; /** Temoin d'occlusion C2 (CAM-Tocc, journal seulement) : un composant visible entre la camera et la tete. */ void WitnessOcclusion(float DeltaTime); /** Delai avant le prochain trace d'occlusion (0,5 s), ou la prochaine ligne apres un masquage (1 s). */ float OcclusionCooldown = 0.f; /** Sortie de CharGen (CAM-B2r) : remet GI.SpaceOn (et GI.MainMenuOn si le menu principal est ferme) une fois * la vue revenue sur une camera de piece ; rien si la vue reste sur la carte de la ville. */ void RepairAfterCharGen(const FString& Label, bool bMenu, float DeltaTime); /** GI.CharGenOn a ete vu vrai ; la reparation reste a faire. */ bool bCharGenSeen = false; /** Delai restant pour trouver une camera de piece apres CharGen (10 s). */ float CharGenRepairTimeout = 0.f; /** Temoin C1 (CAM-B2r, journal seulement) : camera loin des yeux, penchee ou tournee par rapport au controle. */ void WitnessC1(float DeltaTime); /** Delai avant la prochaine mesure du temoin C1 (0,5 s), ou la prochaine ligne (1 s). */ float C1Cooldown = 0.f; /** Camera de scene au clavier (CAM-B2p, P3), a chaque image : pendant le sexe, ZQSD pilote la camera en vue * (orbite et distance en mode Scene, regard en POV) ; temoin des touches (au plus une ligne par seconde). */ void TickSexCamera(float DeltaTime); /** Menu a l'ecran au dernier passage de Tick (0,1 s) : le parcours des widgets n'est pas refait a chaque image. */ bool bMenuOnScreen = false; /** Delai avant la prochaine ligne « Sexe : touches ». */ float SexKeysCooldown = 0.f; /** Couple a la souris (CAM-B2p-D), mode Scene : clic gauche maintenu sur le couple = glisser-deposer sur la * surface visee (lit ou sol, borne au sol de Room), clic droit maintenu = rotation ; camera figee pendant la * prise. Vrai tant qu'une prise est en cours. */ bool TickCoupleMouse(UGameInstance* GI, APlayerController* PC, AActor* View, const UObject* Room, const TArray& Couple, const FVector& Pivot); /** Leve toute prise (hors sexe, menu, vue invalide) : les clics reviennent au jeu tels quels. */ void ReleaseCoupleGrab(); /** 0 : aucune prise ; 1 : deplacement (clic gauche) ; 2 : rotation (clic droit). */ int32 CoupleGrabMode = 0; bool bLeftWasDown = false; bool bRightWasDown = false; /** Le curseur a bouge d'au moins 5 px depuis la prise (le couple ne bouge pas sur un simple clic). */ bool bGrabMoved = false; /** Ecart entre la racine du maillage la plus basse et la surface sous le couple, pris a la selection (journal * seulement depuis CAM-B2p-H : la hauteur de pose est la surface visee + 3 cm). */ bool bGrabHasHeight = false; double GrabHeight = 0.0; /** Decalage XY entre le pivot et le point vise a la selection. */ FVector GrabOffset = FVector::ZeroVector; FVector2D GrabMouseStart = FVector2D::ZeroVector; float GrabLastMouseX = 0.f; float GrabTurned = 0.f; /** Camera en vue figee pendant la prise, et sa pose au moment du clic. */ TWeakObjectPtr GrabCamera; FVector GrabCameraLocation = FVector::ZeroVector; FRotator GrabCameraRotation = FRotator::ZeroRotator; /** « curseur sans position » deja ecrit pour cette scene. */ bool bCursorWarned = false; /** Borne dure du couple (CAM-B2p-E), a chaque image pendant le sexe, menus compris : pivot dans le sol de Room, * racine du maillage entre le dessus du sol et un plafond estime ; temoin des deplacements hors prise. */ void TickCoupleBounds(float DeltaTime); FVector LastCouplePivot = FVector::ZeroVector; bool bHasLastPivot = false; /** « pas de borne » (piece cachee ou sans sol) deja ecrit pour cette scene. */ bool bHiddenRoomWarned = false; float CoupleBoundsCooldown = 0.f; float CoupleMoveCooldown = 0.f; /** CAM-B2p-F : une prise vient de finir dans cette image (le temoin hors prise ne compte pas son dernier pas). */ bool bGrabJustEnded = false; /** Bornes retenues deja ecrites pour cette scene (F2). */ bool bBoundsLogged = false; /** Dernier composant qui a refuse une place au glisser (une ligne par changement). */ FString LastSpotBlocker; /** Derniere surface refusee au glisser (CAM-B2p-H, G-f : ni sol ni lit ; une ligne par changement). */ FString LastSurfaceRefused; /** Focus clavier (H1, H2) : premiere image du sexe deja traitee ; bouton de souris tenu a l'image precedente. */ bool bSceneFocusChecked = false; bool bFocusClickWasDown = false; /** Place du meneur a la prise : au relacher, s'il a bouge, LPShowCouple reprend sa place sure (G3, STE). */ FVector GrabLeadStart = FVector::ZeroVector; /** Camera de scene (CAM-B2p-G) : recadrage a l'entree en Scene et en C3 (variable SexC3 du PC), suivi du couple * hors glisser, distance bornee. Appele par TickCoupleBounds, a chaque image pendant le sexe. */ void TickSceneCamera(UGameInstance* GI, AActor* Room, const TArray& Couple, const FVector& Pivot, bool bGrabEnded); /** Place SceneCamera a distance par defaut du couple, dans la piece, devant le premier obstacle, regard sur le couple. */ void RecenterSceneCamera(UGameInstance* GI, AActor* Room, AActor* SceneCamera, const TArray& Couple, const FVector& Pivot, const TCHAR* Reason); /** Vue a l'image precedente (detection de l'entree en Scene). */ TWeakObjectPtr LastSexView; /** PC.SexC3 a l'image precedente (front montant = passage en C3). */ bool bSexC3Was = false; /** Clic molette court pendant le sexe (CAM-B2p-H, G-g) : appui puis relacher en 0,2 s au plus, curseur immobile * a 5 px pres = PC.LeftMouseSexOn (bascule du panneau des positions). Appele seulement pendant le sexe, hors menu. */ void TickPanelClick(APlayerController* PC, float DeltaTime); bool bMiddleWasDown = false; bool bMiddleHadMouse = false; bool bMiddleMoved = false; float MiddleHeld = 0.f; FVector2D MiddleStart = FVector2D::ZeroVector; /** Aide des controles du sexe (CAM-B2p-I), toutes les 0,1 s : icone « i » dans le panneau des actions (Cursor), a cote * du filtre SearchAction (survol = info-bulle, clic = boite d'aide), 4 lignes d'origine de SexInterface.TextBlock_1 * rendues invisibles quand le bloc porte ce texte. Hors du sexe : icone repliee, boite fermee. */ void TickControlsHelp(); /** Texte d'aide en anglais (langue du jeu), touches lues dans les mappages en cours. */ FString BuildControlsHelp() const; /** Insere l'icone dans le parent de SearchAction ; nul (et une ligne de temoin) si SearchAction ou son parent manque. */ UButton* AttachHelpIcon(UUserWidget* ActionCursor); UFUNCTION() void ToggleControlsHelp(); bool EnsureHelpBox(); void RemoveHelpBox(); /** Instance du panneau deja traitee (insertion tentee une fois, reussie ou non). */ TWeakObjectPtr HelpCursor; TWeakObjectPtr HelpButton; /** Bloc des 4 lignes rendu invisible, et son opacite d'avant. */ TWeakObjectPtr FadedHelpLines; float FadedLinesOpacity = 1.f; bool bHelpBoxOpen = false; /** Dernier texte pose dans l'info-bulle de l'icone. */ FString HelpTextShown; TSharedPtr HelpRoot; TSharedPtr HelpText; TWeakObjectPtr HelpViewport; /** Panneau bascule par Alt (et non par le clic molette) a l'appui en cours. */ bool bPanelByAlt = false; /** CAM-B2p-I (COMMUN-12) : pendant le sexe, hors menu et sans bouton tenu, remet la souris libre (GameAndUI, * DoNotLock) quand le PC l'a verrouillee (GameOnly) : sinon le curseur est fige et le glisser vaut 0. */ void KeepMouseFree(APlayerController* PC, float DeltaTime); /** Debut et fin de scene : empreinte des touches ; a la fin, chaque etat touche par CAM est rendu, une ligne. */ void BeginSexScene(); void EndSexScene(); bool bSexStateWas = false; FString MappingsAtSexStart; bool bMouseFreed = false; /** Etat de la souris au debut de la scene (EMouseCaptureMode, EMouseLockMode, curseur cache a l'appui), rendu a la fin. */ bool bSavedMouseState = false; uint8 SavedCaptureMode = 0; uint8 SavedLockMode = 0; bool bSavedHideCursor = false; int32 MouseFreeCount = 0; float MouseFreeCooldown = 0.f; /** Curseur de la prise : position reelle quand elle bouge, sinon deltas bruts de la souris (souris verrouillee). */ FVector2D GrabCursor = FVector2D::ZeroVector; FVector2D GrabLastReal = FVector2D::ZeroVector; int32 GrabRawFrames = 0; bool bGrabAimWarned = false; /** Pivot apres la derniere action de CAM pendant la prise (temoin des deplacements venus d'ailleurs). */ FVector GrabPivotAfterCam = FVector::ZeroVector; double ExternalMoveLogTime = 0.0; double SelectMissLogTime = 0.0; TSharedPtr Root; TSharedPtr Text; /** Viewport auquel Root a ete ajoute. */ TWeakObjectPtr Viewport; /** Libelle actuellement ecrit dans Text (mis a jour seulement quand il change). */ FString ShownLabel; bool bShown = false; /** KEY2 (KEY2-SPEC-01 § 8c), en scene, hors menu, a chaque image : ActionPanel bascule le panneau d'action * (PC.LeftMouseSexOn), CameraHeight monte ou baisse SceneCamera (hauteur ajoutee bornee), CoupleMoveY deplace le * couple sur Y (piece cachee seulement, comme le X de PC). Rien ne bouge pendant une prise a la souris. */ void TickSceneKeys(APlayerController* PC, AActor* View, const UObject* Room, const TArray& Couple, bool bGrabbing, float Step); /** Hauteur ajoutee a SceneCamera par CameraHeight depuis le dernier recadrage (cm). */ float SceneCameraLift = 0.f; /** PC.SexC3 a l'image precedente, pour CameraHeight (le recadrage de C3 remet la hauteur ajoutee a zero). */ bool bLiftC3Was = false; };