181 lines
7.0 KiB
C++
181 lines
7.0 KiB
C++
// 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<UItemDataAsset> 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<FHarvestDrop> PerHitDrops;
|
|
|
|
/** Bonus du coup qui epuise la ressource. C'est la recompense de l'abattage. */
|
|
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Harvestable")
|
|
TArray<FHarvestDrop> 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<USoundBase> HitSound;
|
|
|
|
/** Copeaux, eclats de pierre. Joue au point d'impact, oriente par la normale. */
|
|
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Harvestable|Feedback")
|
|
TObjectPtr<UNiagaraSystem> 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<USoundBase> IneffectiveHitSound;
|
|
|
|
/** Craquement de chute, eboulement. Joue sur le coup qui epuise. */
|
|
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Harvestable|Feedback")
|
|
TObjectPtr<USoundBase> DepletionSound;
|
|
|
|
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Harvestable|Feedback")
|
|
TObjectPtr<UNiagaraSystem> 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
|
|
};
|