// Fill out your copyright notice in the Description page of Project Settings. #pragma once #include "CoreMinimal.h" #include "Engine/DataAsset.h" #include "ItemDataAsset.h" #include "HarvestableDataAsset.generated.h" class UItemDataAsset; class UNiagaraSystem; class USoundBase; /** * Une ligne de butin : « 1 a 3 Bois, 70 % du temps ». * * Le tirage n'a lieu QUE sur le serveur (AHarvestableResource::TryHarvest), donc * l'aleatoire ne peut pas diverger d'une machine a l'autre -- les clients ne * recoivent jamais le jet, seulement l'objet qui atterrit dans l'inventaire. */ USTRUCT(BlueprintType) struct FHarvestDrop { GENERATED_BODY() UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Drop") TObjectPtr Item; UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Drop", meta = (ClampMin = "1")) int32 MinQuantity = 1; UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Drop", meta = (ClampMin = "1")) int32 MaxQuantity = 1; /** Probabilite que cette ligne tombe. 1 = toujours. */ UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Drop", meta = (ClampMin = "0", ClampMax = "1")) float Chance = 1.f; /** Tire une quantite pour ce coup. Renvoie 0 quand le jet echoue. */ int32 Roll() const; }; /** * Les REGLES de recolte d'une ressource : ce qu'il faut pour l'abattre, ce * qu'elle rend, en combien de temps elle repousse. * * Un asset par ESPECE, pas par instance ni par mesh : les quinze variantes de * sapin du pack partagent toutes DA_Harvest_Tree, chacune posant son propre mesh * sur son acteur. C'est la meme separation que UItemDataAsset et APickupItem -- * la donnee decrit une categorie, l'acteur porte le visuel et l'etat. * * Ce qui ne doit JAMAIS venir ici : les points de vie restants, le fait qu'un * arbre soit deja abattu, l'heure de sa repousse. C'est de l'etat, il vit sur * AHarvestableResource -- sinon abattre un arbre abattrait toute la foret. */ UCLASS(BlueprintType) class EMBERWILD_API UHarvestableDataAsset : public UPrimaryDataAsset { GENERATED_BODY() public: /** Identifiant stable, pour la sauvegarde a venir. */ UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Harvestable") FName HarvestableId; /** Nom lisible, pour les logs et un futur message « Il vous faut une hache ». */ UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Harvestable") FText DisplayName; /** * Outil capable d'entamer cette ressource. * * `None` ne veut pas dire « n'importe quoi » mais « a mains nues » : c'est ce * qui rend un buisson de baies cueillable au poing, sans code particulier. * Un arbre demande Axe, un filon Pickaxe. */ UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Harvestable") EToolType RequiredTool = EToolType::Axe; /** * Points a retirer avant epuisement. * * En points et pas en nombre de coups, pour que la hache en fer abatte en * quatre coups l'arbre qui en demande dix a la hache de pierre : c'est * `HarvestPower` de l'outil qui fait la difference. Un compte de coups en dur * ici obligerait a dupliquer chaque ressource par palier d'outil. */ UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Harvestable", meta = (ClampMin = "1")) float Health = 100.f; /** * Ce que rend CHAQUE coup, meme celui qui n'abat pas. * * C'est la moitie qui rend le geste satisfaisant : un arbre qui ne donne rien * pendant neuf coups laisse croire qu'on tape dans le vide. Garde les * quantites basses -- c'est le lot final qui doit peser. */ UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Harvestable") TArray PerHitDrops; /** Bonus du coup qui epuise la ressource. C'est la recompense de l'abattage. */ UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Harvestable") TArray DepletionDrops; /** * Secondes avant que la ressource redevienne recoltable. 0 = jamais. * * Une souche qui repousse dispense d'un systeme de spawn tant que la carte * est peuplee a la main : rien ne disparait, donc rien n'a a etre recree. */ UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Harvestable", meta = (ClampMin = "0", Units = "s")) float RegrowDelay = 180.f; // ------------------------------------------------------------------ // Retour au joueur // // Sur la DONNEE et non sur l'acteur : c'est l'espece qui decide qu'un coup // de hache dans du bois claque et qu'un coup de pioche dans la pierre // resonne. Regler ca instance par instance sur quatre cents arbres poses // dans le niveau serait ingerable. // ------------------------------------------------------------------ /** Joue a chaque coup qui entame reellement la ressource. */ UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Harvestable|Feedback") TObjectPtr HitSound; /** Copeaux, eclats de pierre. Joue au point d'impact, oriente par la normale. */ UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Harvestable|Feedback") TObjectPtr HitEffect; /** * Le coup n'a rien fait : mauvais outil, ou ressource deja epuisee. * * Un seul son pour les deux cas, et c'est volontaire : dans les deux le * joueur doit entendre que son geste ne sert a rien. Le laisser vide donne un * coup parfaitement muet, ce que l'oreille lit comme un bug. */ UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Harvestable|Feedback") TObjectPtr IneffectiveHitSound; /** Craquement de chute, eboulement. Joue sur le coup qui epuise. */ UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Harvestable|Feedback") TObjectPtr DepletionSound; UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Harvestable|Feedback") TObjectPtr DepletionEffect; /** * Angle maximal du balancement encaisse a chaque coup, en degres. * * 0 pour un rocher : la pierre ne plie pas, et la voir osciller casse * immediatement l'illusion de masse. Quelques degres suffisent sur un arbre -- * au-dela le tronc a l'air en caoutchouc. */ UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Harvestable|Feedback", meta = (ClampMin = "0", ClampMax = "45", Units = "deg")) float HitShakeAngle = 3.f; /** Duree du balancement amorti, en secondes. */ UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Harvestable|Feedback", meta = (ClampMin = "0", Units = "s")) float HitShakeDuration = 0.45f; /** Oscillations par seconde. Plus haut = plus nerveux, plus leger. */ UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Harvestable|Feedback", meta = (ClampMin = "0.1")) float HitShakeFrequency = 7.f; /** Vrai si cette ressource se recolte a mains nues. */ UFUNCTION(BlueprintPure, Category = "Harvestable") bool IsHarvestableByHand() const { return RequiredTool == EToolType::None; } #if WITH_EDITOR /** * Une table de butin dont une ligne pointe dans le vide ne planterait pas : * l'arbre donnerait simplement moins, sans rien dire. C'est le genre de bug * qu'on cherche une heure -- autant que l'editeur le refuse a la sauvegarde. */ virtual EDataValidationResult IsDataValid(class FDataValidationContext& Context) const override; #endif };