mirror of
https://github.com/ApfelTeeSaft/OT6-Reconstruction.git
synced 2026-08-26 19:33:35 +00:00
340 lines
9.3 KiB
C++
340 lines
9.3 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
// Source: D:\BuildFarm\buildmachine_++Fortnite+Release-Live\FortniteGame\Source\FortniteGame\Private\Abilities\Tasks\FortAbilityTask_CommitAccountCosts.cpp
|
|
|
|
#include "FortAbilityTask_CommitAccountCosts.h"
|
|
#include "FortPlayerController.h"
|
|
#include "FortInventory.h"
|
|
|
|
// ============================================================================
|
|
// UFortAbilityTask_CommitAccountCosts
|
|
// ============================================================================
|
|
|
|
UFortAbilityTask_CommitAccountCosts::UFortAbilityTask_CommitAccountCosts()
|
|
: OwningAbility(nullptr)
|
|
, AbilitySystemComponent(nullptr)
|
|
, bIsActive(false)
|
|
, StaminaCost(0.0f)
|
|
{
|
|
}
|
|
|
|
UFortAbilityTask_CommitAccountCosts* UFortAbilityTask_CommitAccountCosts::CommitAccountCosts(
|
|
UFortGameplayAbility* OwningAbility,
|
|
UFortAbilitySystemComponent* AbilitySystemComponent)
|
|
{
|
|
UFortAbilityTask_CommitAccountCosts* Task = NewObject<UFortAbilityTask_CommitAccountCosts>();
|
|
if (Task)
|
|
{
|
|
Task->OwningAbility = OwningAbility;
|
|
Task->AbilitySystemComponent = AbilitySystemComponent;
|
|
|
|
// Get costs from ability
|
|
if (OwningAbility)
|
|
{
|
|
Task->StaminaCost = OwningAbility->EnergyCost; // Using EnergyCost as StaminaCost
|
|
}
|
|
}
|
|
|
|
return Task;
|
|
}
|
|
|
|
void UFortAbilityTask_CommitAccountCosts::Activate()
|
|
{
|
|
UE_LOG(LogTemp, Log, TEXT("UFortAbilityTask_CommitAccountCosts::Activate from effect %s"),
|
|
OwningAbility ? *OwningAbility->GetName() : TEXT("null"));
|
|
|
|
bIsActive = true;
|
|
|
|
// Check if ability still exists
|
|
if (!OwningAbility)
|
|
{
|
|
UE_LOG(LogTemp, Error, TEXT("UFortAbilityTask_CommitAccountCosts failed to consume items for ability %s and player %s but ability is gone!"),
|
|
TEXT("unknown"), TEXT("unknown"));
|
|
OnFailed.Broadcast(EFortAbilityCommitResult::FailedAbilityGone);
|
|
return;
|
|
}
|
|
|
|
// Check stamina cost
|
|
if (!CheckStaminaCost())
|
|
{
|
|
UE_LOG(LogTemp, Warning, TEXT("Ability %s has stamina cost but activator doesn't have stamina!"),
|
|
*OwningAbility->GetName());
|
|
OnFailed.Broadcast(EFortAbilityCommitResult::FailedStaminaCost);
|
|
return;
|
|
}
|
|
|
|
// Check item costs
|
|
if (!CheckItemCosts())
|
|
{
|
|
UE_LOG(LogTemp, Warning, TEXT("Ability %s has an invalid item cost!"),
|
|
*OwningAbility->GetName());
|
|
OnFailed.Broadcast(EFortAbilityCommitResult::FailedItemCost);
|
|
return;
|
|
}
|
|
|
|
// Apply stamina cost
|
|
ApplyStaminaCost();
|
|
|
|
// Apply item costs
|
|
if (!ApplyItemCosts())
|
|
{
|
|
// Rollback stamina if item costs fail
|
|
if (AbilitySystemComponent && StaminaCost > 0.0f)
|
|
{
|
|
AbilitySystemComponent->ModifyAttributeValue(FName("Energy"), StaminaCost); // Refund
|
|
}
|
|
|
|
OnFailed.Broadcast(EFortAbilityCommitResult::FailedItemCost);
|
|
return;
|
|
}
|
|
|
|
// Check if ability is still valid after cost application
|
|
if (!OwningAbility)
|
|
{
|
|
UE_LOG(LogTemp, Error, TEXT("UFortAbilityTask_CommitAccountCosts consumed items for ability %s and player %s but ability is gone! Player has lost resources."),
|
|
TEXT("unknown"), TEXT("unknown"));
|
|
}
|
|
|
|
// Success
|
|
OnSuccess.Broadcast();
|
|
bIsActive = false;
|
|
}
|
|
|
|
void UFortAbilityTask_CommitAccountCosts::Cancel()
|
|
{
|
|
if (bIsActive)
|
|
{
|
|
UE_LOG(LogTemp, Warning, TEXT("CommitAccountCosts cannot be cancelled when active!"));
|
|
return;
|
|
}
|
|
|
|
if (!OwningAbility)
|
|
{
|
|
UE_LOG(LogTemp, Error, TEXT("UFortAbilityTask_CommitAccountCosts cancelled early for ability %s and player %s but ability is gone! Player has lost resources."),
|
|
TEXT("unknown"), TEXT("unknown"));
|
|
}
|
|
|
|
// Cancel logic
|
|
bIsActive = false;
|
|
}
|
|
|
|
bool UFortAbilityTask_CommitAccountCosts::CheckStaminaCost()
|
|
{
|
|
if (StaminaCost <= 0.0f)
|
|
{
|
|
return true; // No stamina cost
|
|
}
|
|
|
|
if (!AbilitySystemComponent)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// Check if actor has enough stamina/energy
|
|
float CurrentEnergy = AbilitySystemComponent->GetAttributeValue(FName("Energy"));
|
|
|
|
if (CurrentEnergy < StaminaCost)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void UFortAbilityTask_CommitAccountCosts::ApplyStaminaCost()
|
|
{
|
|
if (StaminaCost > 0.0f && AbilitySystemComponent)
|
|
{
|
|
AbilitySystemComponent->ModifyAttributeValue(FName("Energy"), -StaminaCost);
|
|
UE_LOG(LogTemp, Verbose, TEXT("Applied stamina cost: %.1f"), StaminaCost);
|
|
}
|
|
}
|
|
|
|
bool UFortAbilityTask_CommitAccountCosts::CheckItemCosts()
|
|
{
|
|
if (ItemCosts.Num() == 0)
|
|
{
|
|
return true; // No item costs
|
|
}
|
|
|
|
if (!OwningAbility)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// Get player's inventory component
|
|
AActor* AvatarActor = OwningAbility->GetAvatarActor();
|
|
if (!AvatarActor)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
UFortInventory* Inventory = AvatarActor->FindComponentByClass<UFortInventory>();
|
|
if (!Inventory)
|
|
{
|
|
UE_LOG(LogTemp, Warning, TEXT("UFortAbilityTask_CommitAccountCosts: No inventory component found on avatar"));
|
|
return false;
|
|
}
|
|
|
|
// Check all item costs against player inventory
|
|
for (const FFortAccountItemCost& ItemCost : ItemCosts)
|
|
{
|
|
if (ItemCost.ItemTemplateId.IsEmpty() || ItemCost.Quantity <= 0)
|
|
{
|
|
UE_LOG(LogTemp, Warning, TEXT("UFortAbilityTask_CommitAccountCosts: Invalid item cost - TemplateId: %s, Quantity: %d"),
|
|
*ItemCost.ItemTemplateId, ItemCost.Quantity);
|
|
return false; // Invalid item cost
|
|
}
|
|
|
|
// Find items by definition name in player inventory
|
|
FName ItemDefName = FName(*ItemCost.ItemTemplateId);
|
|
TArray<FFortItemEntry> FoundItems = Inventory->FindItemsByDefinition(ItemDefName);
|
|
|
|
// Calculate total count of this item type across all stacks
|
|
int32 TotalCount = 0;
|
|
for (const FFortItemEntry& Entry : FoundItems)
|
|
{
|
|
TotalCount += Entry.Count;
|
|
}
|
|
|
|
// Check if player has enough of this item
|
|
if (TotalCount < ItemCost.Quantity)
|
|
{
|
|
UE_LOG(LogTemp, Warning, TEXT("UFortAbilityTask_CommitAccountCosts: Insufficient items - Need %d of %s, have %d"),
|
|
ItemCost.Quantity, *ItemCost.ItemTemplateId, TotalCount);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool UFortAbilityTask_CommitAccountCosts::ApplyItemCosts()
|
|
{
|
|
if (ItemCosts.Num() == 0)
|
|
{
|
|
return true; // No item costs
|
|
}
|
|
|
|
if (!OwningAbility)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// Get player's inventory component
|
|
AActor* AvatarActor = OwningAbility->GetAvatarActor();
|
|
if (!AvatarActor)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
UFortInventory* Inventory = AvatarActor->FindComponentByClass<UFortInventory>();
|
|
if (!Inventory)
|
|
{
|
|
UE_LOG(LogTemp, Error, TEXT("UFortAbilityTask_CommitAccountCosts: No inventory component found for item consumption"));
|
|
FString ErrorMessage = TEXT("No inventory component");
|
|
HandleMCPOutOfSync(ErrorMessage);
|
|
return false;
|
|
}
|
|
|
|
// Consume all item costs from player inventory
|
|
for (const FFortAccountItemCost& ItemCost : ItemCosts)
|
|
{
|
|
FName ItemDefName = FName(*ItemCost.ItemTemplateId);
|
|
TArray<FFortItemEntry> FoundItems = Inventory->FindItemsByDefinition(ItemDefName);
|
|
|
|
if (FoundItems.Num() == 0)
|
|
{
|
|
FString ErrorMessage = FString::Printf(TEXT("Item %s not found in inventory"), *ItemCost.ItemTemplateId);
|
|
HandleMCPOutOfSync(ErrorMessage);
|
|
return false;
|
|
}
|
|
|
|
// Consume items across stacks until we've consumed the required quantity
|
|
int32 RemainingToConsume = ItemCost.Quantity;
|
|
for (FFortItemEntry& Entry : FoundItems)
|
|
{
|
|
if (RemainingToConsume <= 0)
|
|
{
|
|
break;
|
|
}
|
|
|
|
int32 AmountToRemove = FMath::Min(RemainingToConsume, Entry.Count);
|
|
bool bRemoveSuccess = Inventory->RemoveItem(Entry.ItemGuid, AmountToRemove);
|
|
|
|
if (!bRemoveSuccess)
|
|
{
|
|
// Failed to remove items - MCP out of sync
|
|
FString ErrorMessage = FString::Printf(TEXT("Failed to remove %d of item %s"), AmountToRemove, *ItemCost.ItemTemplateId);
|
|
HandleMCPOutOfSync(ErrorMessage);
|
|
return false;
|
|
}
|
|
|
|
RemainingToConsume -= AmountToRemove;
|
|
|
|
UE_LOG(LogTemp, Verbose, TEXT("Consumed %d of item %s (GUID: %s)"),
|
|
AmountToRemove, *ItemCost.ItemTemplateId, *Entry.ItemGuid.Guid.ToString());
|
|
}
|
|
|
|
if (RemainingToConsume > 0)
|
|
{
|
|
// Shouldn't happen if CheckItemCosts passed, but handle it anyway
|
|
FString ErrorMessage = FString::Printf(TEXT("Insufficient items to consume: %s (short by %d)"), *ItemCost.ItemTemplateId, RemainingToConsume);
|
|
HandleMCPOutOfSync(ErrorMessage);
|
|
return false;
|
|
}
|
|
|
|
UE_LOG(LogTemp, Log, TEXT("Successfully consumed %d of item %s"), ItemCost.Quantity, *ItemCost.ItemTemplateId);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void UFortAbilityTask_CommitAccountCosts::HandleMCPOutOfSync(const FString& ErrorMessage)
|
|
{
|
|
UE_LOG(LogTemp, Error, TEXT("UFortAbilityTask_CommitAccountCosts failed for ability %s on player %s with error %s, MCP is out of sync!"),
|
|
OwningAbility ? *OwningAbility->GetName() : TEXT("unknown"),
|
|
TEXT("unknown"),
|
|
*ErrorMessage);
|
|
}
|
|
|
|
// ============================================================================
|
|
// UFortAbilityTask_WaitTargetData
|
|
// ============================================================================
|
|
|
|
UFortAbilityTask_WaitTargetData::UFortAbilityTask_WaitTargetData()
|
|
: OwningAbility(nullptr)
|
|
, bIsWaiting(false)
|
|
{
|
|
}
|
|
|
|
UFortAbilityTask_WaitTargetData* UFortAbilityTask_WaitTargetData::WaitTargetData(
|
|
UFortGameplayAbility* OwningAbility,
|
|
FName TaskInstanceName)
|
|
{
|
|
UFortAbilityTask_WaitTargetData* Task = NewObject<UFortAbilityTask_WaitTargetData>();
|
|
if (Task)
|
|
{
|
|
Task->OwningAbility = OwningAbility;
|
|
Task->TaskInstanceName = TaskInstanceName;
|
|
}
|
|
|
|
return Task;
|
|
}
|
|
|
|
void UFortAbilityTask_WaitTargetData::Activate()
|
|
{
|
|
bIsWaiting = true;
|
|
UE_LOG(LogTemp, Log, TEXT("WaitTargetData activated: %s"), *TaskInstanceName.ToString());
|
|
|
|
//this would wait for player input or replication
|
|
}
|
|
|
|
void UFortAbilityTask_WaitTargetData::ConfirmTargetData(const FFortAbilityTargetSelection& TargetData)
|
|
{
|
|
if (bIsWaiting)
|
|
{
|
|
OnTargetDataReady.Broadcast(TargetData);
|
|
bIsWaiting = false;
|
|
}
|
|
}
|