Improvements to watering and some stat forge fixes

This commit is contained in:
2026-09-14 21:15:31 +02:00
parent f7e5adc1cc
commit aad09dbaa5
26 changed files with 282 additions and 151 deletions

View File

@@ -357,6 +357,68 @@ void ASeedBedActor::WaterAllSeedSlots()
WaterSeedInSlot(SlotCoordinate);
}
}
int32 ASeedBedActor::GatherSlotsInRadius(const FVector& WorldLocation, float Radius, TArray<FIntVector2>& OutSlotCoordinates) const
{
OutSlotCoordinates.Reset();
// A radius of zero only ever covers the point itself, so there is nothing to gather
if (Radius <= 0.f)
{
return 0;
}
const float RadiusSquared = FMath::Square(Radius);
for (const TPair<FIntVector2, FSeedBedSeedSlot>& SlotPair : SeedBedSeedSlotsMap)
{
// Only living plants are watered, an empty or dead slot has nothing to soak up
if (!SlotHasLivingPlant(SlotPair.Value))
{
continue;
}
FVector SlotWorldLocation;
if (!GetSlotWorldLocation(SlotPair.Key, SlotWorldLocation))
{
continue;
}
// Only the plane of the bed counts, so watering from above or from uphill reaches the same slots
if (FVector::DistSquaredXY(WorldLocation, SlotWorldLocation) > RadiusSquared)
{
continue;
}
OutSlotCoordinates.Add(SlotPair.Key);
}
return OutSlotCoordinates.Num();
}
int32 ASeedBedActor::WaterSlotsInRadius(const FVector& WorldLocation, float Radius)
{
// The slots are gathered first, a listener of the refresh is free to change the map while we water
TArray<FIntVector2> SlotCoordinates;
const int32 WateredSlotCount = GatherSlotsInRadius(WorldLocation, Radius, SlotCoordinates);
for (const FIntVector2& SlotCoordinate : SlotCoordinates)
{
WaterSeedInSlot(SlotCoordinate);
}
// The cache is what the game state falls back to once the bed is streamed out, so it has to know
// about the watering right away. Nothing was watered, so there is nothing to cache either.
if (WateredSlotCount > 0)
{
if (AEleriGameState* GameState = Cast<AEleriGameState>(UGameplayStatics::GetGameState(this)))
{
GameState->CacheSeedData(SeedBedIndex, PrepareSeedSaveData());
}
}
return WateredSlotCount;
}
//------------------------------------------------------------------------------------------------
// GRID GENERATION
//------------------------------------------------------------------------------------------------
@@ -623,7 +685,12 @@ void ASeedBedActor::HighlightSlot(FIntVector2 SlotCoordinate)
void ASeedBedActor::StopHighlightingSlot()
{
HighlightDecal->SetVisibility(false);
// The decal only exists once BeginPlay created it, a highlight is stopped on beds that never got one as well
if (IsValid(HighlightDecal))
{
HighlightDecal->SetVisibility(false);
}
HighlightedSlotIndex = FIntVector2::NoneValue;
}
@@ -650,6 +717,14 @@ int32 ASeedBedActor::GetFreeSlotCount() const
return FreeSlotCount;
}
bool ASeedBedActor::FindClosestFreeSlot(const FVector& WorldLocation, FIntVector2& OutSlotCoordinate) const
{
float DistanceSquared = 0.f;
// The distance of the slot is only interesting for the planting highlight, the plain lookup ignores it
return FindClosestFreeSlotWithDistance(WorldLocation, OutSlotCoordinate, DistanceSquared);
}
bool ASeedBedActor::FindClosestFreeSlotWithDistance(const FVector& WorldLocation, FIntVector2& OutSlotCoordinate, float& OutDistanceSquared) const
{
bool bFoundSlot = false;
float ClosestDistanceSquared = 0.f;
@@ -667,7 +742,8 @@ bool ASeedBedActor::FindClosestFreeSlot(const FVector& WorldLocation, FIntVector
continue;
}
const float DistanceSquared = FVector::DistSquared(WorldLocation, SlotWorldLocation);
// Only the plane of the bed counts, a player standing uphill has to reach the slot just as well
const float DistanceSquared = FVector::DistSquaredXY(WorldLocation, SlotWorldLocation);
if (!bFoundSlot || DistanceSquared < ClosestDistanceSquared)
{
bFoundSlot = true;
@@ -676,6 +752,8 @@ bool ASeedBedActor::FindClosestFreeSlot(const FVector& WorldLocation, FIntVector
}
}
OutDistanceSquared = ClosestDistanceSquared;
return bFoundSlot;
}

View File

@@ -196,10 +196,24 @@ public:
UFUNCTION(BlueprintCallable, Category = "Seed Bed")
void WaterAllSeedSlots();
/** Waters every planted slot whose world location lies within the given radius around a world point.
* Returns the number of slots that were watered and caches the new slot data into the game state. */
UFUNCTION(BlueprintCallable, Category = "Seed Bed")
int32 WaterSlotsInRadius(const FVector& WorldLocation, float Radius);
/** Collects the coordinates of every planted slot whose world location lies within the given radius.
* Returns the number of collected slots, OutSlotCoordinates is emptied first. */
UFUNCTION(BlueprintCallable, Category = "Seed Bed")
int32 GatherSlotsInRadius(const FVector& WorldLocation, float Radius, TArray<FIntVector2>& OutSlotCoordinates) const;
/** Finds the free slot that is closest to the given world location */
UFUNCTION(BlueprintCallable, Category = "Seed Bed")
bool FindClosestFreeSlot(const FVector& WorldLocation, FIntVector2& OutSlotCoordinate) const;
/** Same as FindClosestFreeSlot, but also reports how far away the slot is, as a squared distance in XY */
UFUNCTION(BlueprintCallable, Category = "Seed Bed")
bool FindClosestFreeSlotWithDistance(const FVector& WorldLocation, FIntVector2& OutSlotCoordinate, float& OutDistanceSquared) const;
/** World location a plant of the given slot is placed at */
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Seed Bed")
bool GetSlotWorldLocation(FIntVector2 SlotCoordinate, FVector& OutWorldLocation) const;