// Fill out your copyright notice in the Description page of Project Settings. #pragma once #include "CoreMinimal.h" #include "Engine/DataAsset.h" #include "CraftingRecipeDataAsset.generated.h" class UItemDataAsset; class UTexture2D; /** * Poste de travail necessaire pour realiser une recette. * * Ce n'est PAS un filtre d'affichage : c'est une condition de realisation. * Le UCraftingComponent tient la liste des stations dont le joueur dispose a * l'instant t -- {Hands} tout seul, {Hands, Workbench} devant un etabli -- et * une recette n'est realisable que si la sienne s'y trouve. Le filtre de * l'interface est une notion separee, purement visuelle : melanger les deux * finirait par rendre un craft impossible parce qu'un bouton d'affichage est * mal positionne, et ce genre de bug ne se comprend jamais sur le moment. * * Fourneau et feu de cuisson n'ont volontairement PAS leur entree ici : ils ne * passent par aucun menu. Ce sont des acteurs poses dans le monde, facon Raft, * ou l'on depose une ressource et ou l'on voit le mesh changer d'etat. Leur * donnee et leur file d'attente leur appartiendront, une recette de menu n'a * rien a y faire. */ UENUM(BlueprintType) enum class ECraftingStation : uint8 { Hands, Workbench, // Sentinelle, jamais assignee a une recette. Elle sert a parcourir l'enum // pour construire les boutons de filtre sans avoir a les enumerer a la main. Count UMETA(Hidden) }; /** Une ligne de cout : tant d'exemplaires de tel objet. */ USTRUCT(BlueprintType) struct FCraftIngredient { GENERATED_BODY() UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Recipe") TObjectPtr Item = nullptr; UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Recipe", meta = (ClampMin = "1")) int32 Quantity = 1; }; /** * Une recette : ce qu'il faut, ce que ca donne, ou ca se fabrique. * * Un asset par recette, comme un DataAsset par objet. Trois comportements de * craft n'existeront jamais : la recette est de la donnee pure, c'est le * composant qui l'execute. * * Elle ne contient aucun etat -- ni "deja decouverte", ni "en cours de * fabrication". Le jour ou les recettes se debloqueront en jeu, la liste des * RecipeId connus vivra dans la sauvegarde, pas ici : sinon decouvrir une * recette la debloquerait pour toutes les parties a la fois. */ UCLASS(BlueprintType) class EMBERWILD_API UCraftingRecipeDataAsset : public UPrimaryDataAsset { GENERATED_BODY() public: /** * Identifiant stable, independant du nom de l'asset. * Servira a la sauvegarde des recettes decouvertes : renommer un asset ne * doit pas faire oublier au joueur ce qu'il avait debloque. */ UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Recipe") FName RecipeId; /** Ce que la fabrication consomme. Une recette sans cout est acceptee (objet gratuit). */ UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Recipe") TArray Ingredients; UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Recipe") TObjectPtr ResultItem; UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Recipe", meta = (ClampMin = "1")) int32 ResultQuantity = 1; UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Recipe") ECraftingStation RequiredStation = ECraftingStation::Hands; // Pas de duree de fabrication ici : le craft de menu est instantane, comme // dans Valheim ou Raft. La fabrication qui prend du temps est celle des // postes qui travaillent SANS le joueur, et ceux-la ne sont pas des recettes. /** * Nom affiche, quand celui du resultat ne suffit pas. * Laisse vide dans l'immense majorite des cas : dupliquer le nom de l'objet * dans la recette, c'est se garantir deux textes qui divergeront un jour. */ UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Recipe|Display") FText DisplayNameOverride; /** Icone affichee dans la grille de craft. Vide = celle du resultat. */ UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Recipe|Display") TObjectPtr IconOverride; /** Le nom a afficher, override compris. Passe toujours par ici, jamais par ResultItem directement. */ UFUNCTION(BlueprintPure, Category = "Recipe") FText GetDisplayName() const; /** L'icone a afficher, override compris. */ UFUNCTION(BlueprintPure, Category = "Recipe") UTexture2D* GetIcon() const; #if WITH_EDITOR /** * Une recette sans resultat ne planterait pas : elle ne ferait simplement * RIEN, en consommant les ingredients. C'est exactement le genre de bug qu'on * cherche pendant une heure -- autant que l'editeur le refuse a la sauvegarde. */ virtual EDataValidationResult IsDataValid(class FDataValidationContext& Context) const override; #endif };