// Copyright Pacificao. All Rights Reserved. #include "AgrarianCampfire.h" #include "AgrarianGameCharacter.h" #include "AgrarianInventoryComponent.h" #include "AgrarianSurvivalComponent.h" #include "Components/PointLightComponent.h" #include "Components/StaticMeshComponent.h" #include "Kismet/GameplayStatics.h" #include "Net/UnrealNetwork.h" AAgrarianCampfire::AAgrarianCampfire() { PrimaryActorTick.bCanEverTick = true; bReplicates = true; Mesh = CreateDefaultSubobject(TEXT("Mesh")); RootComponent = Mesh; FireLight = CreateDefaultSubobject(TEXT("FireLight")); FireLight->SetupAttachment(RootComponent); FireLight->SetIntensity(0.0f); FireLight->SetAttenuationRadius(WarmthRadius); FireLight->SetLightColor(FLinearColor(1.0f, 0.45f, 0.18f)); } void AAgrarianCampfire::Tick(float DeltaSeconds) { Super::Tick(DeltaSeconds); if (HasAuthority() && bLit) { FuelSeconds = FMath::Max(0.0f, FuelSeconds - DeltaSeconds); if (FuelSeconds <= 0.0f) { SetLit(false); } if (CanCook()) { CookingProgressSeconds = FMath::Min(CookingSecondsRequired, CookingProgressSeconds + DeltaSeconds); } WarmNearbyCharacters(DeltaSeconds); } } void AAgrarianCampfire::GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const { Super::GetLifetimeReplicatedProps(OutLifetimeProps); DOREPLIFETIME(AAgrarianCampfire, bLit); DOREPLIFETIME(AAgrarianCampfire, FuelSeconds); DOREPLIFETIME(AAgrarianCampfire, bCookingPlaceholderEnabled); DOREPLIFETIME(AAgrarianCampfire, CookingSecondsRequired); DOREPLIFETIME(AAgrarianCampfire, CookingProgressSeconds); } FText AAgrarianCampfire::GetInteractionText_Implementation(const AAgrarianGameCharacter* Interactor) const { return bLit ? FText::FromString(TEXT("Add fuel")) : FText::FromString(TEXT("Light fire")); } bool AAgrarianCampfire::CanInteract_Implementation(const AAgrarianGameCharacter* Interactor) const { return Interactor != nullptr; } void AAgrarianCampfire::Interact_Implementation(AAgrarianGameCharacter* Interactor) { if (!HasAuthority() || !Interactor) { return; } UAgrarianInventoryComponent* Inventory = Interactor->GetInventoryComponent(); if (Inventory && Inventory->RemoveItem(TEXT("wood"), 1)) { AddFuel(90.0f); } } void AAgrarianCampfire::AddFuel(float Seconds) { if (HasAuthority()) { FuelSeconds += FMath::Max(0.0f, Seconds); if (FuelSeconds > 0.0f) { SetLit(true); } else { UpdateVisualState(); } } } void AAgrarianCampfire::Extinguish() { if (HasAuthority()) { FuelSeconds = 0.0f; SetLit(false); } } bool AAgrarianCampfire::CanCook() const { return bLit && bCookingPlaceholderEnabled && CookingSecondsRequired > 0.0f; } float AAgrarianCampfire::GetCookingProgressRatio() const { if (CookingSecondsRequired <= 0.0f) { return 0.0f; } return FMath::Clamp(CookingProgressSeconds / CookingSecondsRequired, 0.0f, 1.0f); } void AAgrarianCampfire::OnRep_FireState() { UpdateVisualState(); } void AAgrarianCampfire::SetLit(bool bNewLit) { if (bLit != bNewLit) { bLit = bNewLit; } UpdateVisualState(); } void AAgrarianCampfire::UpdateVisualState() { if (FireLight) { FireLight->SetIntensity(bLit ? 4200.0f : 0.0f); } } void AAgrarianCampfire::WarmNearbyCharacters(float DeltaSeconds) { TArray Characters; UGameplayStatics::GetAllActorsOfClass(this, AAgrarianGameCharacter::StaticClass(), Characters); for (AActor* Actor : Characters) { AAgrarianGameCharacter* Character = Cast(Actor); if (!Character || FVector::DistSquared(Character->GetActorLocation(), GetActorLocation()) > FMath::Square(WarmthRadius)) { continue; } if (UAgrarianSurvivalComponent* SurvivalComponent = Character->GetSurvivalComponent()) { SurvivalComponent->AddWarmth(WarmthPerSecond * DeltaSeconds); } } }