Bind to time of day and progress seed age
This commit is contained in:
@@ -156,7 +156,7 @@ public:
|
|||||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Seed", AssetRegistrySearchable, meta = (AssetBundles = "Inventory, Book", EditCondition="ItemCategory==Category::Plant", EditConditionHides))
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Seed", AssetRegistrySearchable, meta = (AssetBundles = "Inventory, Book", EditCondition="ItemCategory==Category::Plant", EditConditionHides))
|
||||||
int32 SeedCost;
|
int32 SeedCost;
|
||||||
|
|
||||||
/** Grow time for a seed, if the seed is a tree or wine this is the growth for them */
|
/** Grow time for a seed in game days, if the seed is a tree or wine this is the growth for them */
|
||||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Seed", AssetRegistrySearchable, meta = (AssetBundles = "Inventory, Book", EditCondition="ItemCategory==Category::Plant", EditConditionHides))
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Seed", AssetRegistrySearchable, meta = (AssetBundles = "Inventory, Book", EditCondition="ItemCategory==Category::Plant", EditConditionHides))
|
||||||
int32 GrowTimeSelf;
|
int32 GrowTimeSelf;
|
||||||
|
|
||||||
|
|||||||
@@ -118,6 +118,7 @@ struct FSeedStage {
|
|||||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
|
||||||
FVector MeshScale;
|
FVector MeshScale;
|
||||||
|
|
||||||
|
/** In game days after planting at which this stage is shown, the seed bed ages its plants per hour and scales it */
|
||||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
|
||||||
int32 ChangeOnDay;
|
int32 ChangeOnDay;
|
||||||
|
|
||||||
|
|||||||
@@ -178,7 +178,7 @@ void ASeedBedActor::EndPlay(const EEndPlayReason::Type EndPlayReason)
|
|||||||
// This is the moment the bed stops receiving broadcasts, so the resume math starts from the time of the day here
|
// This is the moment the bed stops receiving broadcasts, so the resume math starts from the time of the day here
|
||||||
if (IsValid(TimeOfDayManager))
|
if (IsValid(TimeOfDayManager))
|
||||||
{
|
{
|
||||||
TimeOfDayManager->OnDayPassed.RemoveDynamic(this, &ASeedBedActor::HandleDayPassed);
|
TimeOfDayManager->OnHourPassed.RemoveDynamic(this, &ASeedBedActor::HandleHourPassed);
|
||||||
}
|
}
|
||||||
|
|
||||||
CacheCurrentTimeOfDay();
|
CacheCurrentTimeOfDay();
|
||||||
@@ -209,7 +209,7 @@ void ASeedBedActor::BindToTimeOfDay()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// AddUniqueDynamic only ever leaves one binding of the bed on the delegate, even after a reload
|
// AddUniqueDynamic only ever leaves one binding of the bed on the delegate, even after a reload
|
||||||
TimeOfDayManager->OnDayPassed.AddUniqueDynamic(this, &ASeedBedActor::HandleDayPassed);
|
TimeOfDayManager->OnHourPassed.AddUniqueDynamic(this, &ASeedBedActor::HandleHourPassed);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ASeedBedActor::CacheCurrentTimeOfDay()
|
void ASeedBedActor::CacheCurrentTimeOfDay()
|
||||||
@@ -220,14 +220,14 @@ void ASeedBedActor::CacheCurrentTimeOfDay()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ASeedBedActor::HandleDayPassed()
|
void ASeedBedActor::HandleHourPassed()
|
||||||
{
|
{
|
||||||
AdvanceSeedBedByDays(1);
|
AdvanceSeedBedByHours(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ASeedBedActor::AdvanceSeedBedByDays(int32 Days)
|
void ASeedBedActor::AdvanceSeedBedByHours(int32 Hours)
|
||||||
{
|
{
|
||||||
if (Days <= 0)
|
if (Hours <= 0)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -241,7 +241,12 @@ void ASeedBedActor::AdvanceSeedBedByDays(int32 Days)
|
|||||||
for (TPair<FIntVector2, FSeedBedSeedSlot>& SlotPair : SeedBedSeedSlotsMap)
|
for (TPair<FIntVector2, FSeedBedSeedSlot>& SlotPair : SeedBedSeedSlotsMap)
|
||||||
{
|
{
|
||||||
const bool bWasAlive = SlotHasLivingPlant(SlotPair.Value);
|
const bool bWasAlive = SlotHasLivingPlant(SlotPair.Value);
|
||||||
ApplyDayPassedToSlot(SlotPair.Value, Now);
|
|
||||||
|
// Every hour is applied on its own, a jump over several of them grows, dries and kills hour by hour
|
||||||
|
for (int32 HourIndex = 0; HourIndex < Hours && SlotHasLivingPlant(SlotPair.Value); ++HourIndex)
|
||||||
|
{
|
||||||
|
ApplyHourPassedToSlot(SlotPair.Value, Now);
|
||||||
|
}
|
||||||
|
|
||||||
if (bWasAlive && !SlotHasLivingPlant(SlotPair.Value))
|
if (bWasAlive && !SlotHasLivingPlant(SlotPair.Value))
|
||||||
{
|
{
|
||||||
@@ -258,13 +263,13 @@ void ASeedBedActor::AdvanceSeedBedByDays(int32 Days)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ASeedBedActor::ApplyDayPassedToSlot(FSeedBedSeedSlot& Slot, const FTimeOfDayData& Now)
|
void ASeedBedActor::ApplyHourPassedToSlot(FSeedBedSeedSlot& Slot, const FTimeOfDayData& Now)
|
||||||
{
|
{
|
||||||
FSeedBedSeedSlotData& SlotData = Slot.SlotData;
|
FSeedBedSeedSlotData& SlotData = Slot.SlotData;
|
||||||
|
|
||||||
// The moisture of the soil only lasts for the day it was watered on
|
// The moisture of the soil drains with every in game hour, so the wetness is a clock of its own
|
||||||
const bool bWasWatered = SlotData.bWateredToday;
|
const bool bWasMoist = SlotData.MoistureHoursRemaining > 0;
|
||||||
SlotData.bWateredToday = false;
|
SlotData.MoistureHoursRemaining = FMath::Max(0, SlotData.MoistureHoursRemaining - 1);
|
||||||
|
|
||||||
if (!SlotHasLivingPlant(Slot))
|
if (!SlotHasLivingPlant(Slot))
|
||||||
{
|
{
|
||||||
@@ -272,21 +277,17 @@ void ASeedBedActor::ApplyDayPassedToSlot(FSeedBedSeedSlot& Slot, const FTimeOfDa
|
|||||||
}
|
}
|
||||||
|
|
||||||
// A plant that was dry for too long never grows again, so the death check comes before the growth
|
// A plant that was dry for too long never grows again, so the death check comes before the growth
|
||||||
const int32 DaysSinceWatering = SlotData.LastWateredTime.IsValidTime()
|
const int32 MinutesSinceWatering = SlotData.LastWateredTime.IsValidTime()
|
||||||
? Now.ToAbsoluteDays() - SlotData.LastWateredTime.ToAbsoluteDays()
|
? Now.ToAbsoluteMinutes() - SlotData.LastWateredTime.ToAbsoluteMinutes()
|
||||||
: 0;
|
: 0;
|
||||||
|
|
||||||
if (DaysSinceWatering >= FMath::Max(1, DaysWithoutWaterToDie))
|
if (MinutesSinceWatering >= FMath::Max(1, DaysWithoutWaterToDie) * SeedBedMinutesPerDay)
|
||||||
{
|
{
|
||||||
SlotData.bDied = true;
|
SlotData.bDied = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only a watered plant grows, and it never grows past its own grow time
|
SlotData.SeedAgeHours = FMath::Min(SlotData.SeedAgeHours + 1, FMath::Max(0, SlotData.GrowTime) * SeedBedHoursPerDay);
|
||||||
if (bWasWatered)
|
|
||||||
{
|
|
||||||
SlotData.SeedAge = FMath::Min(SlotData.SeedAge + 1, FMath::Max(0, SlotData.GrowTime));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ASeedBedActor::ApplyOfflineProgression()
|
void ASeedBedActor::ApplyOfflineProgression()
|
||||||
@@ -315,11 +316,11 @@ void ASeedBedActor::ApplyOfflineProgression()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const int32 DaysPassed = LastKnownTimeOfDay.ToAbsoluteDays() - LastUpdateTime.ToAbsoluteDays();
|
const int32 HoursPassed = (LastKnownTimeOfDay.ToAbsoluteMinutes() - LastUpdateTime.ToAbsoluteMinutes()) / SeedBedMinutesPerHour;
|
||||||
if (DaysPassed > 0)
|
if (HoursPassed > 0)
|
||||||
{
|
{
|
||||||
// Growth is linear and nothing can be watered while the bed is gone, so a single pass is enough
|
// Nothing can be watered while the bed is gone, but the plants still grow and dry hour by hour
|
||||||
AdvanceSeedBedByDays(DaysPassed);
|
AdvanceSeedBedByHours(HoursPassed);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -337,8 +338,8 @@ void ASeedBedActor::WaterSeedInSlot(FIntVector2 SlotCoordinate)
|
|||||||
|
|
||||||
CacheCurrentTimeOfDay();
|
CacheCurrentTimeOfDay();
|
||||||
|
|
||||||
// Wetness is a per day state, the stamp is what the death check measures the days since
|
// One watering covers a whole in game day of growth, the stamp is what the death check counts from
|
||||||
Slot->SlotData.bWateredToday = true;
|
Slot->SlotData.MoistureHoursRemaining = SeedBedMoistureHoursPerWatering;
|
||||||
Slot->SlotData.WateredTimes++;
|
Slot->SlotData.WateredTimes++;
|
||||||
Slot->SlotData.LastWateredTime = LastKnownTimeOfDay;
|
Slot->SlotData.LastWateredTime = LastKnownTimeOfDay;
|
||||||
|
|
||||||
@@ -530,7 +531,7 @@ void ASeedBedActor::ApplySlotVisuals(FIntVector2 SlotCoordinate, FSeedBedSeedSlo
|
|||||||
|
|
||||||
if (IsValid(Slot.SeedBedDynamicMat))
|
if (IsValid(Slot.SeedBedDynamicMat))
|
||||||
{
|
{
|
||||||
Slot.SeedBedDynamicMat->SetScalarParameterValue(TEXT("Wetness"), Slot.SlotData.bWateredToday ? 1.f : 0.f);
|
Slot.SeedBedDynamicMat->SetScalarParameterValue(TEXT("Wetness"), Slot.SlotData.MoistureHoursRemaining > 0 ? 1.f : 0.f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -655,7 +656,7 @@ bool ASeedBedActor::FindClosestFreeSlot(const FVector& WorldLocation, FIntVector
|
|||||||
|
|
||||||
for (const TPair<FIntVector2, FSeedBedSeedSlot>& SlotPair : SeedBedSeedSlotsMap)
|
for (const TPair<FIntVector2, FSeedBedSeedSlot>& SlotPair : SeedBedSeedSlotsMap)
|
||||||
{
|
{
|
||||||
if (!SlotHasLivingPlant(SlotPair.Value))
|
if (SlotHasLivingPlant(SlotPair.Value))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -699,12 +700,12 @@ int32 ASeedBedActor::ResolveGrowthStageIndex(const FSeedBedSeedSlot& Slot) const
|
|||||||
return INDEX_NONE;
|
return INDEX_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stages are set up ordered by ChangeOnDay, so the last day that has been reached is the visible one
|
// Stages are set up per day while the age of a plant counts hours, so the last day that was reached wins
|
||||||
int32 StageIndex = 0;
|
int32 StageIndex = 0;
|
||||||
|
|
||||||
for (int32 Index = 0; Index < SeedData->SeedStages.Num(); ++Index)
|
for (int32 Index = 0; Index < SeedData->SeedStages.Num(); ++Index)
|
||||||
{
|
{
|
||||||
if (Slot.SlotData.SeedAge < SeedData->SeedStages[Index].ChangeOnDay)
|
if (Slot.SlotData.SeedAgeHours < SeedData->SeedStages[Index].ChangeOnDay * SeedBedHoursPerDay)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -735,11 +736,12 @@ bool ASeedBedActor::PlantSeedInSlot(FIntVector2 SlotCoordinate, UItemDataAsset*
|
|||||||
CacheCurrentTimeOfDay();
|
CacheCurrentTimeOfDay();
|
||||||
Slot->SlotData.ItemDataAsset = SeedData;
|
Slot->SlotData.ItemDataAsset = SeedData;
|
||||||
Slot->SlotData.ItemAssetID = SeedData->GetPrimaryAssetId();
|
Slot->SlotData.ItemAssetID = SeedData->GetPrimaryAssetId();
|
||||||
|
// Grow time is authored in days, the age of a plant itself is counted in in game hours
|
||||||
Slot->SlotData.GrowTime = FMath::Max(0, SeedData->GrowTimeSelf);
|
Slot->SlotData.GrowTime = FMath::Max(0, SeedData->GrowTimeSelf);
|
||||||
Slot->SlotData.SeedAge = 0;
|
Slot->SlotData.SeedAgeHours = 0;
|
||||||
Slot->SlotData.WateredTimes = 0;
|
Slot->SlotData.WateredTimes = 0;
|
||||||
Slot->SlotData.bBloomed = false;
|
Slot->SlotData.bBloomed = false;
|
||||||
Slot->SlotData.bWateredToday = false;
|
Slot->SlotData.MoistureHoursRemaining = 0;
|
||||||
Slot->SlotData.bDied = false;
|
Slot->SlotData.bDied = false;
|
||||||
Slot->SlotData.bHighQuality = bHighQuality;
|
Slot->SlotData.bHighQuality = bHighQuality;
|
||||||
|
|
||||||
@@ -767,10 +769,10 @@ void ASeedBedActor::ClearSeedFromSlot(FIntVector2 SlotCoordinate, bool bRemovePl
|
|||||||
Slot->SlotData.ItemDataAsset = nullptr;
|
Slot->SlotData.ItemDataAsset = nullptr;
|
||||||
Slot->SlotData.ItemAssetID = FPrimaryAssetId();
|
Slot->SlotData.ItemAssetID = FPrimaryAssetId();
|
||||||
Slot->SlotData.GrowTime = 0;
|
Slot->SlotData.GrowTime = 0;
|
||||||
Slot->SlotData.SeedAge = 0;
|
Slot->SlotData.SeedAgeHours = 0;
|
||||||
Slot->SlotData.WateredTimes = 0;
|
Slot->SlotData.WateredTimes = 0;
|
||||||
Slot->SlotData.bBloomed = false;
|
Slot->SlotData.bBloomed = false;
|
||||||
Slot->SlotData.bWateredToday = false;
|
Slot->SlotData.MoistureHoursRemaining = 0;
|
||||||
Slot->SlotData.bDied = false;
|
Slot->SlotData.bDied = false;
|
||||||
Slot->SlotData.bHighQuality = false;
|
Slot->SlotData.bHighQuality = false;
|
||||||
Slot->SlotData.LastWateredTime = FTimeOfDayData();
|
Slot->SlotData.LastWateredTime = FTimeOfDayData();
|
||||||
|
|||||||
@@ -15,6 +15,14 @@ class UStaticMesh;
|
|||||||
class UStaticMeshComponent;
|
class UStaticMeshComponent;
|
||||||
class UItemDataAsset;
|
class UItemDataAsset;
|
||||||
|
|
||||||
|
/** In game time units the seed bed works with, the seed data itself stays authored in days */
|
||||||
|
constexpr int32 SeedBedHoursPerDay = 24;
|
||||||
|
constexpr int32 SeedBedMinutesPerHour = 60;
|
||||||
|
constexpr int32 SeedBedMinutesPerDay = SeedBedHoursPerDay * SeedBedMinutesPerHour;
|
||||||
|
|
||||||
|
/** In game growth hours a single watering covers, one watering makes a plant grow for a whole day */
|
||||||
|
constexpr int32 SeedBedMoistureHoursPerWatering = SeedBedHoursPerDay;
|
||||||
|
|
||||||
/** Called every time a slot of the seed bed has been planted, cleared or visually refreshed */
|
/** Called every time a slot of the seed bed has been planted, cleared or visually refreshed */
|
||||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnSeedBedSlotChanged, FIntVector2, SlotCoordinate, bool, bHasPlant);
|
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnSeedBedSlotChanged, FIntVector2, SlotCoordinate, bool, bHasPlant);
|
||||||
|
|
||||||
@@ -32,8 +40,9 @@ struct FSeedBedSeedSlotData
|
|||||||
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
||||||
int32 GrowTime = 0;
|
int32 GrowTime = 0;
|
||||||
|
|
||||||
|
/** In game hours of growth the plant has collected, the seed data grows for GrowTime days */
|
||||||
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
||||||
int32 SeedAge = 0;
|
int32 SeedAgeHours = 0;
|
||||||
|
|
||||||
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
||||||
int32 WateredTimes = 0;
|
int32 WateredTimes = 0;
|
||||||
@@ -41,8 +50,9 @@ struct FSeedBedSeedSlotData
|
|||||||
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
||||||
bool bBloomed = false;
|
bool bBloomed = false;
|
||||||
|
|
||||||
|
/** In game growth hours the last watering still covers, one watering covers a whole in game day */
|
||||||
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
||||||
bool bWateredToday = false;
|
int32 MoistureHoursRemaining = 0;
|
||||||
|
|
||||||
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
||||||
bool bDied = false;
|
bool bDied = false;
|
||||||
@@ -103,7 +113,7 @@ public:
|
|||||||
//------------------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
/** Every slot of the seed bed, keyed by its X / Y coordinate inside the grid */
|
/** Every slot of the seed bed, keyed by its X / Y coordinate inside the grid */
|
||||||
UPROPERTY(EditAnywhere, BlueprintReadOnly)
|
UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
|
||||||
TMap<FIntVector2, FSeedBedSeedSlot> SeedBedSeedSlotsMap;
|
TMap<FIntVector2, FSeedBedSeedSlot> SeedBedSeedSlotsMap;
|
||||||
|
|
||||||
UPROPERTY(BlueprintAssignable)
|
UPROPERTY(BlueprintAssignable)
|
||||||
@@ -116,17 +126,17 @@ public:
|
|||||||
// SEED BED SETUP
|
// SEED BED SETUP
|
||||||
//------------------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Seed Bed|Setup")
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Seed Bed|Setup")
|
||||||
TSoftObjectPtr<UMaterialInterface> SeedBedDecalMaterial;
|
TSoftObjectPtr<UMaterialInterface> SeedBedDecalMaterial;
|
||||||
|
|
||||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Seed Bed|Setup")
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Seed Bed|Setup")
|
||||||
FVector SeedBedDecalSize = FVector(40.f, 40.f, 40.f);
|
FVector SeedBedDecalSize = FVector(40.f, 40.f, 40.f);
|
||||||
|
|
||||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Seed Bed|Setup")
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Seed Bed|Setup")
|
||||||
FRotator SeedBedDecalRotation = FRotator(-90.f, 0.f, 0.f);
|
FRotator SeedBedDecalRotation = FRotator(-90.f, 0.f, 0.f);
|
||||||
|
|
||||||
/** Fallback mesh used when the planted seed has no growth stage set up */
|
/** Fallback mesh used when the planted seed has no growth stage set up */
|
||||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Seed Bed|Setup")
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Seed Bed|Setup")
|
||||||
TSoftObjectPtr<UStaticMesh> DefaultPlantMesh;
|
TSoftObjectPtr<UStaticMesh> DefaultPlantMesh;
|
||||||
|
|
||||||
/** Dimensions of the grid generated by GenerateSeedBedGrid, X = columns, Y = rows */
|
/** Dimensions of the grid generated by GenerateSeedBedGrid, X = columns, Y = rows */
|
||||||
@@ -137,13 +147,13 @@ public:
|
|||||||
// HIGHLIGHT DECAL
|
// HIGHLIGHT DECAL
|
||||||
//------------------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Seed Bed|Highlight")
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Seed Bed|Highlight")
|
||||||
TSoftObjectPtr<UMaterialInterface> HighlightDecalMaterial;
|
TSoftObjectPtr<UMaterialInterface> HighlightDecalMaterial;
|
||||||
|
|
||||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Seed Bed|Highlight")
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Seed Bed|Highlight")
|
||||||
FVector HighlightDecalSize = FVector(40.f, 40.f, 40.f);
|
FVector HighlightDecalSize = FVector(40.f, 40.f, 40.f);
|
||||||
|
|
||||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Seed Bed|Highlight")
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Seed Bed|Highlight")
|
||||||
FRotator HighlightDecalRotation = FRotator(-90.f, 0.f, 0.f);
|
FRotator HighlightDecalRotation = FRotator(-90.f, 0.f, 0.f);
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------------------
|
||||||
@@ -211,9 +221,9 @@ public:
|
|||||||
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Seed Bed|Time")
|
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Seed Bed|Time")
|
||||||
FTimeOfDayData GetLastUpdateTime() const { return LastUpdateTime; }
|
FTimeOfDayData GetLastUpdateTime() const { return LastUpdateTime; }
|
||||||
|
|
||||||
/** Applies the given amount of in game days to every plant of the bed, used by the day tick and the resume catch up */
|
/** Applies the given amount of in game hours to every plant of the bed, used by the hour tick and the resume catch up */
|
||||||
UFUNCTION(BlueprintCallable, Category = "Seed Bed|Time")
|
UFUNCTION(BlueprintCallable, Category = "Seed Bed|Time")
|
||||||
void AdvanceSeedBedByDays(int32 Days);
|
void AdvanceSeedBedByHours(int32 Hours);
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------------------
|
||||||
// VISUALS
|
// VISUALS
|
||||||
@@ -258,11 +268,11 @@ protected:
|
|||||||
|
|
||||||
FVector GetSlotRelativeLocation(FIntVector2 SlotCoordinate) const;
|
FVector GetSlotRelativeLocation(FIntVector2 SlotCoordinate) const;
|
||||||
|
|
||||||
/** Subscribes to the time of day actor, the bed ages its plants on every day that passes */
|
/** Subscribes to the time of day actor, the bed ages its plants on every in game hour that passes */
|
||||||
void BindToTimeOfDay();
|
void BindToTimeOfDay();
|
||||||
|
|
||||||
/** Applies one in game day of growth, moisture handling and death checks to a single slot */
|
/** Applies one in game hour of growth, moisture handling and death checks to a single slot */
|
||||||
void ApplyDayPassedToSlot(FSeedBedSeedSlot& Slot, const FTimeOfDayData& Now);
|
void ApplyHourPassedToSlot(FSeedBedSeedSlot& Slot, const FTimeOfDayData& Now);
|
||||||
|
|
||||||
/** Catches the plants up on the in game time that passed while the bed was not in the world */
|
/** Catches the plants up on the in game time that passed while the bed was not in the world */
|
||||||
void ApplyOfflineProgression();
|
void ApplyOfflineProgression();
|
||||||
@@ -270,9 +280,9 @@ protected:
|
|||||||
/** Stores the current in game time, the manager may already be gone when the bed is torn down */
|
/** Stores the current in game time, the manager may already be gone when the bed is torn down */
|
||||||
void CacheCurrentTimeOfDay();
|
void CacheCurrentTimeOfDay();
|
||||||
|
|
||||||
/** Day tick of the time of day actor */
|
/** Hour tick of the time of day actor */
|
||||||
UFUNCTION()
|
UFUNCTION()
|
||||||
void HandleDayPassed();
|
void HandleHourPassed();
|
||||||
|
|
||||||
|
|
||||||
/** Whether the highlight decals of the bed are currently shown */
|
/** Whether the highlight decals of the bed are currently shown */
|
||||||
@@ -289,7 +299,7 @@ protected:
|
|||||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Seed Bed|Time")
|
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Seed Bed|Time")
|
||||||
int32 DaysWithoutWaterToDie = 2;
|
int32 DaysWithoutWaterToDie = 2;
|
||||||
|
|
||||||
/** In game time the bed last applied growth for, written on every day and again when the bed leaves the world */
|
/** In game time the bed last applied growth for, written on every hour and again when the bed leaves the world */
|
||||||
UPROPERTY(Transient)
|
UPROPERTY(Transient)
|
||||||
FTimeOfDayData LastUpdateTime;
|
FTimeOfDayData LastUpdateTime;
|
||||||
|
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ void FSaveData::WaterAllPlantedSeeds(const FTimeOfDayData& WateredTime)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
SlotData.bWateredToday = true;
|
SlotData.MoistureHoursRemaining = SeedBedMoistureHoursPerWatering;
|
||||||
SlotData.WateredTimes++;
|
SlotData.WateredTimes++;
|
||||||
SlotData.LastWateredTime = WateredTime;
|
SlotData.LastWateredTime = WateredTime;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -399,6 +399,9 @@ void ATimeOfDayManager::AddMinutes(float minutes)
|
|||||||
if (!TimeTicking)
|
if (!TimeTicking)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// A single call can move the clock over several hours at once (sleep, warps), so the hours are counted
|
||||||
|
const int32 AbsoluteHoursBefore = (GetAllDaysPassed() * 24) + currentHours;
|
||||||
|
|
||||||
FloatMinutes += minutes;
|
FloatMinutes += minutes;
|
||||||
|
|
||||||
currentHours = FMath::Clamp(FMath::Floor(FloatMinutes / 60.f), 0, 24);
|
currentHours = FMath::Clamp(FMath::Floor(FloatMinutes / 60.f), 0, 24);
|
||||||
@@ -427,6 +430,14 @@ void ATimeOfDayManager::AddMinutes(float minutes)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The hour tick is sent after the rollover so a listener already sees the day and hour the step landed on.
|
||||||
|
// Every hour the clock covered is announced on its own, a clock that jumps backwards announces none.
|
||||||
|
const int32 AbsoluteHoursAfter = (GetAllDaysPassed() * 24) + currentHours;
|
||||||
|
for (int32 HourIndex = AbsoluteHoursBefore; HourIndex < AbsoluteHoursAfter; ++HourIndex)
|
||||||
|
{
|
||||||
|
OnHourPassed.Broadcast();
|
||||||
|
}
|
||||||
|
|
||||||
NextWeatherChangeMinutes -= minutes;
|
NextWeatherChangeMinutes -= minutes;
|
||||||
|
|
||||||
OnMinutesAdded.Broadcast(minutes);
|
OnMinutesAdded.Broadcast(minutes);
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ enum class EWeatherType : uint8
|
|||||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnMinutesAdded, float, Minutes);
|
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnMinutesAdded, float, Minutes);
|
||||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnTimePassed, FTimeOfDayData, TimeOfDay);
|
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnTimePassed, FTimeOfDayData, TimeOfDay);
|
||||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnDayPassed);
|
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnDayPassed);
|
||||||
|
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnHourPassed);
|
||||||
|
|
||||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnUpdateMajorLightning);
|
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnUpdateMajorLightning);
|
||||||
|
|
||||||
@@ -120,6 +121,11 @@ public:
|
|||||||
UPROPERTY(BlueprintAssignable)
|
UPROPERTY(BlueprintAssignable)
|
||||||
FOnDayPassed OnDayPassed;
|
FOnDayPassed OnDayPassed;
|
||||||
|
|
||||||
|
/** Fired whenever the in game clock crosses an hour, also when a jump of several hours moves it over one.
|
||||||
|
* Listeners that have to age something on a finer scale than days use this instead of OnDayPassed. */
|
||||||
|
UPROPERTY(BlueprintAssignable)
|
||||||
|
FOnHourPassed OnHourPassed;
|
||||||
|
|
||||||
UPROPERTY(BlueprintAssignable)
|
UPROPERTY(BlueprintAssignable)
|
||||||
FOnMinutesAdded OnMinutesAdded;
|
FOnMinutesAdded OnMinutesAdded;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user