Add structure ignition risk checks

This commit is contained in:
2026-05-19 12:16:52 -07:00
parent dca9d01f68
commit 168cd0e61f
5 changed files with 169 additions and 1 deletions
+79
View File
@@ -6,6 +6,8 @@
#include "AgrarianGameState.h"
#include "AgrarianInventoryComponent.h"
#include "AgrarianPersistentActorComponent.h"
#include "AgrarianResourceNode.h"
#include "AgrarianShelterActor.h"
#include "AgrarianSurvivalComponent.h"
#include "Particles/ParticleSystemComponent.h"
#include "Components/AudioComponent.h"
@@ -143,6 +145,7 @@ void AAgrarianCampfire::Tick(float DeltaSeconds)
UpdateFireRisk(DeltaSeconds);
UpdateVegetationIgnitionRisk(DeltaSeconds);
UpdateStructureIgnitionRisk(DeltaSeconds);
WarmNearbyCharacters(DeltaSeconds);
}
}
@@ -164,6 +167,8 @@ void AAgrarianCampfire::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& Ou
DOREPLIFETIME(AAgrarianCampfire, ForestIgnitionRiskScore);
DOREPLIFETIME(AAgrarianCampfire, bGrassOrBrushIgnited);
DOREPLIFETIME(AAgrarianCampfire, bForestFuelIgnited);
DOREPLIFETIME(AAgrarianCampfire, StructureIgnitionRiskScore);
DOREPLIFETIME(AAgrarianCampfire, bStructureIgnited);
}
FText AAgrarianCampfire::GetInteractionText_Implementation(const AAgrarianGameCharacter* Interactor) const
@@ -211,6 +216,8 @@ void AAgrarianCampfire::CapturePersistentState_Implementation(UAgrarianPersisten
PersistentComponent->NumberState.Add(TEXT("forest_ignition_risk_score"), ForestIgnitionRiskScore);
PersistentComponent->NumberState.Add(TEXT("grass_or_brush_ignited"), bGrassOrBrushIgnited ? 1.0f : 0.0f);
PersistentComponent->NumberState.Add(TEXT("forest_fuel_ignited"), bForestFuelIgnited ? 1.0f : 0.0f);
PersistentComponent->NumberState.Add(TEXT("structure_ignition_risk_score"), StructureIgnitionRiskScore);
PersistentComponent->NumberState.Add(TEXT("structure_ignited"), bStructureIgnited ? 1.0f : 0.0f);
}
void AAgrarianCampfire::ApplyPersistentState_Implementation(UAgrarianPersistentActorComponent* PersistentComponent)
@@ -234,6 +241,8 @@ void AAgrarianCampfire::ApplyPersistentState_Implementation(UAgrarianPersistentA
const float* SavedForestIgnitionRisk = PersistentComponent->NumberState.Find(TEXT("forest_ignition_risk_score"));
const float* SavedGrassIgnited = PersistentComponent->NumberState.Find(TEXT("grass_or_brush_ignited"));
const float* SavedForestIgnited = PersistentComponent->NumberState.Find(TEXT("forest_fuel_ignited"));
const float* SavedStructureIgnitionRisk = PersistentComponent->NumberState.Find(TEXT("structure_ignition_risk_score"));
const float* SavedStructureIgnited = PersistentComponent->NumberState.Find(TEXT("structure_ignited"));
if (SavedFuelSeconds)
{
@@ -300,6 +309,16 @@ void AAgrarianCampfire::ApplyPersistentState_Implementation(UAgrarianPersistentA
bForestFuelIgnited = *SavedForestIgnited > 0.5f;
}
if (SavedStructureIgnitionRisk)
{
StructureIgnitionRiskScore = FMath::Clamp(*SavedStructureIgnitionRisk, 0.0f, 100.0f);
}
if (SavedStructureIgnited)
{
bStructureIgnited = *SavedStructureIgnited > 0.5f;
}
SetLit(SavedLit && *SavedLit > 0.5f && FuelSeconds > 0.0f);
}
@@ -327,6 +346,7 @@ void AAgrarianCampfire::Extinguish()
FireRiskScore = 0.0f;
GrassIgnitionRiskScore = 0.0f;
ForestIgnitionRiskScore = 0.0f;
StructureIgnitionRiskScore = 0.0f;
LitDurationSeconds = 0.0f;
SecondsSinceMaintenance = 0.0f;
SetLit(false);
@@ -649,3 +669,62 @@ float AAgrarianCampfire::GetVegetationIgnitionWeatherMultiplier() const
return FMath::Max(0.0f, Multiplier);
}
void AAgrarianCampfire::UpdateStructureIgnitionRisk(float DeltaSeconds)
{
if (!HasAuthority() || !bLit || bFireContained || bStructureIgnited)
{
return;
}
const float StructureFuelScore = GetStructureFuelScoreNearFire();
if (StructureFuelScore < StructureIgnitionFuelScoreThreshold)
{
return;
}
const float BurnDurationMultiplier = FMath::GetMappedRangeValueClamped(
FVector2D(15.0f, 240.0f),
FVector2D(0.45f, 1.5f),
LitDurationSeconds);
const float RiskMultiplier = BurnDurationMultiplier * GetVegetationIgnitionWeatherMultiplier() * FMath::Max(0.0f, GetFireRiskRatio());
StructureIgnitionRiskScore = FMath::Clamp(
StructureIgnitionRiskScore + (StructureIgnitionRiskPerSecond * StructureFuelScore * RiskMultiplier * DeltaSeconds),
0.0f,
100.0f);
bStructureIgnited = StructureIgnitionRiskScore >= 100.0f;
}
float AAgrarianCampfire::GetStructureFuelScoreNearFire() const
{
float StructureFuelScore = 0.0f;
TArray<AActor*> ShelterActors;
UGameplayStatics::GetAllActorsOfClass(this, AAgrarianShelterActor::StaticClass(), ShelterActors);
for (const AActor* Actor : ShelterActors)
{
if (Actor && Actor != this && FVector::DistSquared2D(Actor->GetActorLocation(), GetActorLocation()) <= FMath::Square(StructureIgnitionCheckRadius))
{
StructureFuelScore += 4.0f;
}
}
TArray<AActor*> ResourceActors;
UGameplayStatics::GetAllActorsOfClass(this, AAgrarianResourceNode::StaticClass(), ResourceActors);
for (const AActor* Actor : ResourceActors)
{
const AAgrarianResourceNode* ResourceNode = Cast<AAgrarianResourceNode>(Actor);
if (!ResourceNode || FVector::DistSquared2D(ResourceNode->GetActorLocation(), GetActorLocation()) > FMath::Square(StructureIgnitionCheckRadius))
{
continue;
}
const FName YieldId = ResourceNode->YieldItem.ItemId;
if (YieldId == TEXT("wood") || YieldId == TEXT("fiber"))
{
StructureFuelScore += 1.5f;
}
}
return StructureFuelScore;
}