201 lines
6.8 KiB
C++
201 lines
6.8 KiB
C++
// 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 EMBERWILD_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<UWidgetSwitcher> TabSwitcher;
|
|
|
|
UPROPERTY(meta = (BindWidget))
|
|
TObjectPtr<UButton> InventoryTabButton;
|
|
|
|
UPROPERTY(meta = (BindWidget))
|
|
TObjectPtr<UButton> 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<UInventoryWidget> InventoryPage;
|
|
|
|
/** Ton WBP_Crafting, renomme "CraftingPage". */
|
|
UPROPERTY(meta = (BindWidget))
|
|
TObjectPtr<UCraftingWidget> 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<UWidget> StoragePanel;
|
|
|
|
/** Un deuxieme WBP_Inventory, renomme "StorageGrid". DECOCHE-lui Auto Bind To Pawn. */
|
|
UPROPERTY(meta = (BindWidgetOptional))
|
|
TObjectPtr<UInventoryWidget> StorageGrid;
|
|
|
|
/** Nom du coffre ouvert. */
|
|
UPROPERTY(meta = (BindWidgetOptional))
|
|
TObjectPtr<UTextBlock> StorageTitle;
|
|
|
|
/** Deverse la grille du sac dans le coffre. La barre rapide n'y passe pas. */
|
|
UPROPERTY(meta = (BindWidgetOptional))
|
|
TObjectPtr<UButton> StoreAllButton;
|
|
|
|
/** Vide le coffre dans le sac, dans la limite de la place disponible. */
|
|
UPROPERTY(meta = (BindWidgetOptional))
|
|
TObjectPtr<UButton> 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<UInventoryComponent> BoundStorage;
|
|
};
|