// Fill out your copyright notice in the Description page of Project Settings. #pragma once #include "CoreMinimal.h" #include "Blueprint/UserWidget.h" #include "InventoryScreenWidget.generated.h" class AStorageContainer; class UButton; class UCraftingWidget; class UInventoryComponent; class UInventoryWidget; class UTextBlock; class UWidgetSwitcher; /** * L'onglet visible a change. true = Inventaire, false = Fabrication. * * L'ecran se contente d'annoncer. Ce que ca implique pour le reste du HUD -- * masquer la barre rapide, par exemple -- ne le regarde pas : il serait alors * un widget reutilisable qui connait la pile de son hote, exactement ce qu'on * evite partout ailleurs. */ DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnInventoryScreenTabChanged, bool, bInventoryTabActive); /** * L'ecran que Tab ouvre : une barre d'onglets et deux pages, Inventaire et * Fabrication. * * Il ne contient aucune logique de l'une ni de l'autre. Les pages restent des * widgets autonomes -- la grille d'inventaire n'a pas change d'une ligne en * devenant une page -- et l'ecran ne fait que les montrer, les rebrancher apres * un respawn, et relayer au controller ce dont il a besoin. * * Classe Abstract : on cree un WBP_InventoryScreen qui en herite. */ UCLASS(Abstract) class SURVIVAL_PROJET_API UInventoryScreenWidget : public UUserWidget { GENERATED_BODY() public: virtual void NativeConstruct() override; /** Rebranche les deux pages sur le pawn possede. A appeler depuis OnPossess. */ void BindToOwningPawn(); /** * Index de la case d'inventaire survolee, ou INDEX_NONE. * * Renvoie INDEX_NONE des que l'onglet Fabrication est affiche : sans ca, la * touche "jeter" agirait sur une case invisible, sous le panneau de craft. */ int32 GetHoveredSlotIndex() const; /** * Meme chose, avec l'inventaire auquel la case appartient. Depuis les * coffres, l'index seul ne designe plus rien de facon unique. */ bool GetHoveredSlot(UInventoryComponent*& OutInventory, int32& OutIndex) const; /** * Survol d'une case exterieure a l'ecran -- la barre rapide, qui reste * affichee par-dessus lui. Alimente le panneau de detail de la page * d'inventaire, seul panneau existant. */ void NotifyExternalSlotHovered(UInventoryComponent* Inventory, int32 SlotIndex, bool bHovered); /** Revient sur l'onglet Inventaire. Appele a chaque ouverture par Tab. */ UFUNCTION(BlueprintCallable, Category = "UI") void ShowInventoryTab(); /** Bascule sur l'onglet Fabrication. Appele par la touche dediee. */ UFUNCTION(BlueprintCallable, Category = "UI") void ShowCraftingTab(); UPROPERTY(BlueprintAssignable, Category = "UI") FOnInventoryScreenTabChanged OnTabChanged; // ------------------------------------------------------------------ // Panneau de coffre // // Le contenu d'un coffre s'affiche A COTE de la grille du joueur, dans ce // meme ecran, et non dans un ecran a part. La raison est du ressenti pur : // le sac ne bouge pas d'un pixel entre "j'ouvre mon sac" et "j'ouvre un // coffre". Deux ecrans distincts le feraient sauter a chaque fois. // // Techniquement c'est une deuxieme instance du MEME WBP_Inventory que // InventoryPage. Elle ne peut pas vivre a l'interieur de WBP_Inventory : // un Widget Blueprint qui se contient lui-meme est une reference // circulaire, et UMG refuse de le compiler. // ------------------------------------------------------------------ /** Branche et affiche le panneau de droite. Force l'onglet Inventaire. */ void ShowStorage(AStorageContainer* Container); /** Masque et debranche le panneau. Sans effet s'il est deja cache. */ void HideStorage(); UFUNCTION(BlueprintPure, Category = "UI|Storage") bool IsStorageVisible() const { return bStorageVisible; } protected: /** * Absorbe ou traite les depots qui ne visent aucune page. * Meme regle que dans la grille : lache hors des cases, l'objet est jete. */ virtual bool NativeOnDrop(const FGeometry& InGeometry, const FDragDropEvent& InDragDropEvent, UDragDropOperation* InOperation) override; UPROPERTY(meta = (BindWidget)) TObjectPtr TabSwitcher; UPROPERTY(meta = (BindWidget)) TObjectPtr InventoryTabButton; UPROPERTY(meta = (BindWidget)) TObjectPtr CraftingTabButton; /** * Ton WBP_Inventory, pose comme enfant du WidgetSwitcher et renomme * "InventoryPage". Les deux pages sont obligatoires : un ecran a onglets * auquel il manque une page n'a aucun sens, autant que le Blueprint refuse * de compiler. */ UPROPERTY(meta = (BindWidget)) TObjectPtr InventoryPage; /** Ton WBP_Crafting, renomme "CraftingPage". */ UPROPERTY(meta = (BindWidget)) TObjectPtr CraftingPage; /** * Tout le bloc de droite -- cadre, titre, grille, boutons -- qu'on montre et * qu'on cache d'un bloc. * * BindWidgetOptional et non BindWidget, comme tous les elements de coffre * qui suivent : l'ecran doit rester valide dans un projet ou personne n'a * encore construit ce panneau. Sans ca, ajouter les coffres casserait la * compilation de WBP_InventoryScreen tant que la mise en page n'est pas * faite -- et donc l'inventaire entier. */ UPROPERTY(meta = (BindWidgetOptional)) TObjectPtr StoragePanel; /** Un deuxieme WBP_Inventory, renomme "StorageGrid". DECOCHE-lui Auto Bind To Pawn. */ UPROPERTY(meta = (BindWidgetOptional)) TObjectPtr StorageGrid; /** Nom du coffre ouvert. */ UPROPERTY(meta = (BindWidgetOptional)) TObjectPtr StorageTitle; /** Deverse la grille du sac dans le coffre. La barre rapide n'y passe pas. */ UPROPERTY(meta = (BindWidgetOptional)) TObjectPtr StoreAllButton; /** Vide le coffre dans le sac, dans la limite de la place disponible. */ UPROPERTY(meta = (BindWidgetOptional)) TObjectPtr TakeAllButton; private: UFUNCTION() void HandleStoreAllClicked(); UFUNCTION() void HandleTakeAllClicked(); /** Inventaire du pawn possede, ou nullptr. */ UInventoryComponent* GetPlayerInventory() const; UFUNCTION() void HandleInventoryTabClicked(); UFUNCTION() void HandleCraftingTabClicked(); /** * Affiche une page et grise son bouton d'onglet. * * On passe le widget et non un index en dur : l'ordre des enfants du * WidgetSwitcher se change d'un glisser dans la Designer, et un 0/1 code ici * inverserait silencieusement les onglets le jour ou ca arrive. */ void ShowPage(UWidget* Page); bool IsInventoryTabActive() const; /** * Le panneau de coffre est affiche. * * Tant qu'il l'est, l'onglet Fabrication est grise : fabriquer avec un * coffre ouvert a cote n'a pas de sens tant que ses ressources ne comptent * pas dans les recettes, et laisser le bouton actif inviterait a un clic * dont le resultat serait incomprehensible. */ bool bStorageVisible = false; TWeakObjectPtr BoundStorage; };