Starting dialogue and requirments implemented
This commit is contained in:
@@ -9,6 +9,7 @@
|
||||
#include "Speech.h"
|
||||
#include "SpeechDataAsset.h"
|
||||
#include "Kismet/GameplayStatics.h"
|
||||
#include "NPC/NpcBaseCharacter.h"
|
||||
#include "ProjectEleri/GameEventSystem/GameEventSubsystem.h"
|
||||
#include "QuestSystem/QuestSubsystem.h"
|
||||
|
||||
@@ -58,27 +59,16 @@ void UDialogueComponent::StartDialogueWithNpc()
|
||||
UDialogueSubsystem* DialogueSubsystem = UDialogueSubsystem::Get(this);
|
||||
ensure(DialogueSubsystem);
|
||||
|
||||
const ANpcBaseCharacter* NpcBaseCharacter = Cast<ANpcBaseCharacter>(GetOwner());
|
||||
if (!NpcBaseCharacter || !NpcBaseCharacter->GetStartingSpeech().IsValid()) return;
|
||||
|
||||
// The NPC goes in with it, so that whoever is being talked to can be told apart from the rest of
|
||||
// the town. This component lives on the actor the player talks to, which makes GetOwner the
|
||||
// answer, and it is the single funnel every dialogue goes through.
|
||||
if (!DialogueSubsystem->StartDialogue(GetOwner())) return;
|
||||
|
||||
MappedDialogueOptions.Empty();
|
||||
FilterSpeechData();
|
||||
TArray<USpeechDataAsset*> StartingDialogues = GetStartingDialogues();
|
||||
if (StartingDialogues.IsEmpty()) return;
|
||||
|
||||
TriggerDialogue(StartingDialogues[FMath::RandRange(0, StartingDialogues.Num() - 1)], CurrentDialogueReplacementMap);
|
||||
|
||||
TArray<USpeechDataAsset*> ActiveDialogues = GetActiveDialogues();
|
||||
TArray<FText> PlayerAsks = GetPlayerAsksFromDialogueList(ActiveDialogues);
|
||||
for (int32 i = 0; i < ActiveDialogues.Num() - 1; i++)
|
||||
{
|
||||
FPlayerSpeakToDialogue SpeakToDialogue;
|
||||
SpeakToDialogue.NextSpeechDataAsset = ActiveDialogues[i];
|
||||
MappedDialogueOptions.Add(i, SpeakToDialogue);
|
||||
}
|
||||
TriggerDialogueSelect(PlayerAsks, true);
|
||||
TriggerDialogue(NpcBaseCharacter->GetStartingSpeech().Get(), CurrentDialogueReplacementMap);
|
||||
}
|
||||
|
||||
void UDialogueComponent::TriggerDialogue_Async(TSoftObjectPtr<USpeechDataAsset> DialogueAssetPath, const TMap<FString, FText>& ReplacementMap)
|
||||
@@ -111,16 +101,17 @@ void UDialogueComponent::TriggerDialogue(USpeechDataAsset* DialogueAssetPath, co
|
||||
CurrentDialogueReplacementMap = ReplacementMap;
|
||||
DialogueWidget->DisplayDialogue(CurrentActiveDialogue, GetOwner(), CurrentDialogueReplacementMap);
|
||||
|
||||
if (DialogueAssetPath->RandomizeLines && !DialogueAssetPath->PlayerSpeechMap.IsEmpty())
|
||||
if (!DialogueAssetPath->PlayerSpeechMap.IsEmpty())
|
||||
{
|
||||
MappedDialogueOptions.Empty();
|
||||
TArray<FText> PlayerSpeakOptions;
|
||||
for (int32 i = 0; i <= CurrentActiveDialogue->PlayerSpeechMap.Num() - 1; i++)
|
||||
{
|
||||
if (!CurrentActiveDialogue->PlayerSpeechMap[i].PassesRequirements(this)) continue;
|
||||
|
||||
MappedDialogueOptions.Add(i, CurrentActiveDialogue->PlayerSpeechMap[i]);
|
||||
PlayerSpeakOptions.Add(CurrentActiveDialogue->PlayerSpeechMap[i].PlayerSpeak);
|
||||
}
|
||||
//TriggerDialogueSelect(PlayerSpeakOptions, false);
|
||||
}
|
||||
|
||||
DialogueSubsystem->StartDialogue(GetOwner());
|
||||
@@ -200,7 +191,7 @@ void UDialogueComponent::AdvanceDialogue()
|
||||
{
|
||||
for (const FGameplayTag& QuestTag : CurrentActiveDialogue->StartQuests)
|
||||
{
|
||||
UQuestSubsystem::Get(this)->OfferQuest(QuestTag);
|
||||
UQuestSubsystem::Get(this)->StartQuest(QuestTag);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -217,11 +208,16 @@ void UDialogueComponent::AdvanceDialogue()
|
||||
TArray<FText> PlayerSpeakOptions;
|
||||
for (int32 i = 0; i <= CurrentActiveDialogue->PlayerSpeechMap.Num() - 1; i++)
|
||||
{
|
||||
if (!CurrentActiveDialogue->PlayerSpeechMap[i].PassesRequirements(this)) continue;
|
||||
|
||||
MappedDialogueOptions.Add(i, CurrentActiveDialogue->PlayerSpeechMap[i]);
|
||||
PlayerSpeakOptions.Add(CurrentActiveDialogue->PlayerSpeechMap[i].PlayerSpeak);
|
||||
}
|
||||
TriggerDialogueSelect(PlayerSpeakOptions, false);
|
||||
return;
|
||||
if (!PlayerSpeakOptions.IsEmpty())
|
||||
{
|
||||
TriggerDialogueSelect(PlayerSpeakOptions, false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,26 +5,74 @@
|
||||
#include <ProjectEleri/GameEventSystem/GameEventSubsystem.h>
|
||||
#include <Kismet/GameplayStatics.h>
|
||||
|
||||
#include "InventoryComponent.h"
|
||||
#include "Speech.h"
|
||||
#include "QuestSystem/QuestSubsystem.h"
|
||||
|
||||
bool USpeechDataAsset::TestRequirements(UWorld* World)
|
||||
bool FEventRequirement::TestRequirement(const UObject* WorldContext) const
|
||||
{
|
||||
UGameInstance* GameInstance = UGameplayStatics::GetGameInstance(World);
|
||||
const UGameInstance* GameInstance = UGameplayStatics::GetGameInstance(WorldContext);
|
||||
if (!GameInstance) return false;
|
||||
|
||||
if (UGameEventSubsystem* GameEventSubsystem = GameInstance->GetSubsystem<UGameEventSubsystem>())
|
||||
switch (RequirementType)
|
||||
{
|
||||
for (const FEventRequirement& EventReq : EventsMustMeetRequirement)
|
||||
{
|
||||
if (EventReq.Stage != GameEventSubsystem->GetEventStage(EventReq.EventAsset))
|
||||
return false;
|
||||
}
|
||||
case EEventRequirementType::Event:
|
||||
{
|
||||
const UGameEventSubsystem* GameEventSubsystem = GameInstance->GetSubsystem<UGameEventSubsystem>();
|
||||
if (!GameEventSubsystem) return false;
|
||||
|
||||
const EEventStage EventStage = GameEventSubsystem->GetEventStage(EventAsset);
|
||||
|
||||
if (!bMustAchieveEvent && EventStage != EEventStage::NONE)
|
||||
return false;
|
||||
|
||||
if (bMustAchieveEvent && (GameEventSubsystem->GetEventStage(EventAsset) < Stage))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
case EEventRequirementType::Quest:
|
||||
{
|
||||
const UQuestSubsystem* QuestSubsystem = GameInstance->GetSubsystem<UQuestSubsystem>();
|
||||
if (!QuestSubsystem) return false;
|
||||
|
||||
const EQuestStatus CurrentQuestStatus = QuestSubsystem->GetQuestStatus(QuestTag);
|
||||
const bool bMeetsReq = CurrentQuestStatus >= QuestStatus;
|
||||
return bMeetsReq == bEqual;
|
||||
}
|
||||
case EEventRequirementType::Item:
|
||||
{
|
||||
const UInventoryComponent* InventoryComponent = UMainBlueprintFunctionLibrary::GetPlayerInventory(WorldContext);
|
||||
if (!InventoryComponent) return false;
|
||||
|
||||
if (InventoryComponent->GetStackForItem(Item) < Stacks)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
case EEventRequirementType::Max:
|
||||
break;
|
||||
}
|
||||
|
||||
for (const FEventRequirement& EventReq : EventsMustNotMeetRequirement)
|
||||
{
|
||||
if (EventReq.Stage == GameEventSubsystem->GetEventStage(EventReq.EventAsset))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FPlayerSpeakToDialogue::PassesRequirements(const UObject* WorldContext) const
|
||||
{
|
||||
for (const FEventRequirement& Requirement : EventRequirements)
|
||||
{
|
||||
if (!Requirement.TestRequirement(WorldContext)) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool USpeechDataAsset::TestRequirements(const UWorld* World)
|
||||
{
|
||||
for (const FEventRequirement& EventReq : EventRequirements)
|
||||
{
|
||||
if (!EventReq.TestRequirement(World))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -5,23 +5,50 @@
|
||||
#include "CoreMinimal.h"
|
||||
#include "Engine/DataAsset.h"
|
||||
#include "ProjectEleri/GameEventSystem/GameEventDataAsset.h"
|
||||
#include "QuestSystem/QuestTypes.h"
|
||||
#include "SpeechDataAsset.generated.h"
|
||||
|
||||
struct FLineData;
|
||||
class USpeechDataAsset;
|
||||
|
||||
UENUM(BlueprintType)
|
||||
enum class EEventRequirementType : uint8
|
||||
{
|
||||
Event,
|
||||
Quest,
|
||||
Item,
|
||||
Max UMETA(Hidden)
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
struct FEventRequirement
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
|
||||
UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, meta = (MetaClass = "/Script/ProjectEleri.GameEventDataAsset"))
|
||||
FSoftObjectPath EventAsset;
|
||||
|
||||
UPROPERTY(EditDefaultsOnly, BlueprintReadWrite)
|
||||
EEventRequirementType RequirementType;
|
||||
|
||||
UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, meta = (EditCondition = "RequirementType == EEventRequirementType::Event", EditConditionHides, MetaClass = "/Script/ProjectEleri.GameEventDataAsset"))
|
||||
FSoftObjectPath EventAsset;
|
||||
UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, meta = (EditCondition = "RequirementType == EEventRequirementType::Event", EditConditionHides))
|
||||
EEventStage Stage;
|
||||
// if this is false the event must not be unlocked
|
||||
UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, meta = (EditCondition = "RequirementType == EEventRequirementType::Event", EditConditionHides))
|
||||
bool bMustAchieveEvent = true;
|
||||
|
||||
UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, meta = (EditCondition = "RequirementType == EEventRequirementType::Quest", EditConditionHides, GameplayTagFilter = "Quests"))
|
||||
FGameplayTag QuestTag;
|
||||
UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, meta = (EditCondition = "RequirementType == EEventRequirementType::Quest", EditConditionHides, GameplayTagFilter = "Quests"))
|
||||
EQuestStatus QuestStatus;
|
||||
UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, meta = (EditCondition = "RequirementType == EEventRequirementType::Quest", EditConditionHides, GameplayTagFilter = "Quests"))
|
||||
bool bEqual = true;
|
||||
|
||||
UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, meta = (EditCondition = "RequirementType == EEventRequirementType::Item", EditConditionHides, Categories = "Items"))
|
||||
FPrimaryAssetId Item;
|
||||
UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, meta = (EditCondition = "RequirementType == EEventRequirementType::Item", EditConditionHides))
|
||||
int32 Stacks = 1;
|
||||
|
||||
bool TestRequirement(const UObject* WorldContext) const;
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
@@ -37,6 +64,10 @@ public:
|
||||
TSoftObjectPtr<USpeechDataAsset> NextSpeechDataAsset;
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, meta = (ForceInlineRow, Categories = "Dialogue|Event"))
|
||||
FGameplayTag GameplayTag;
|
||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Eleri|Event Requirment")
|
||||
TArray<FEventRequirement> EventRequirements;
|
||||
|
||||
bool PassesRequirements(const UObject* WorldContext) const;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -49,10 +80,7 @@ class PROJECTELERI_API USpeechDataAsset : public UDataAsset
|
||||
|
||||
public:
|
||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Eleri|Event Requirment")
|
||||
TArray<FEventRequirement> EventsMustMeetRequirement;
|
||||
|
||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Eleri|Event Requirment")
|
||||
TArray<FEventRequirement> EventsMustNotMeetRequirement;
|
||||
TArray<FEventRequirement> EventRequirements;
|
||||
|
||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Eleri|Speech")
|
||||
TSoftClassPtr<AActor> Npc;
|
||||
@@ -73,7 +101,7 @@ public:
|
||||
TArray<FPlayerSpeakToDialogue> PlayerSpeechMap;
|
||||
|
||||
UFUNCTION()
|
||||
bool TestRequirements(UWorld* World);
|
||||
bool TestRequirements(const UWorld* World);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "Eleri|Options")
|
||||
FText GetFormattedDialogueLine(const int32 Index, const TMap<FString, FText> ReplacementMap);
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "ProjectEleri/NPC/ExtendedPawnMovement.h"
|
||||
#include "ProjectEleri/NPC/NpcStateMachineComponent.h"
|
||||
#include "ProjectEleri/Public/InventoryComponent.h"
|
||||
#include "ProjectEleri/DialogueSystem/SpeechDataAsset.h"
|
||||
|
||||
ANpcBaseCharacter::ANpcBaseCharacter()
|
||||
{
|
||||
@@ -78,10 +79,7 @@ void ANpcBaseCharacter::BeginPlay()
|
||||
{
|
||||
Super::BeginPlay();
|
||||
|
||||
// There is nothing to start here. The state machine waits to be told what to do by the schedule
|
||||
// component, which is what keeps an NPC the player never goes near from doing any work at all, and
|
||||
// an NPC with no schedule component simply stands where it was placed because nothing ever tells
|
||||
// it about an assignment.
|
||||
NpcCharacterData.StartingSpeech.LoadSynchronous();
|
||||
}
|
||||
|
||||
void ANpcBaseCharacter::ToggleInteractableUI_Implementation(bool bActive)
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "Interface/InteractableActorInterface.h"
|
||||
#include "NpcBaseCharacter.generated.h"
|
||||
|
||||
class USpeechDataAsset;
|
||||
class UCapsuleComponent;
|
||||
class UEleriFlipbookComponent;
|
||||
class UExtendedPawnMovement;
|
||||
@@ -26,6 +27,9 @@ struct FNpcCharacterData
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
||||
FText NpcName;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite)
|
||||
TSoftObjectPtr<USpeechDataAsset> StartingSpeech;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -78,6 +82,7 @@ public:
|
||||
UNpcStateMachineComponent* GetNpcStateMachine() const { return StateMachineComponent; }
|
||||
|
||||
virtual void ToggleInteractableUI_Implementation(bool bActive) override;
|
||||
TSoftObjectPtr<USpeechDataAsset> GetStartingSpeech() const { return NpcCharacterData.StartingSpeech; }
|
||||
|
||||
protected:
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Components")
|
||||
|
||||
@@ -36,7 +36,7 @@ void UInventoryComponent::BeginPlay()
|
||||
InitializeInventory();
|
||||
}
|
||||
|
||||
int32 UInventoryComponent::HasItem(FPrimaryAssetId ItemId, bool HQ)
|
||||
int32 UInventoryComponent::HasItem(FPrimaryAssetId ItemId, bool HQ) const
|
||||
{
|
||||
for (int32 i = 0; i < ItemList.Num(); i++)
|
||||
{
|
||||
@@ -131,7 +131,7 @@ void UInventoryComponent::EmptyInventory()
|
||||
OnInventoryUpdated.Broadcast();
|
||||
}
|
||||
|
||||
int32 UInventoryComponent::GetStackForItem(FPrimaryAssetId ItemId, bool HQ)
|
||||
int32 UInventoryComponent::GetStackForItem(FPrimaryAssetId ItemId, bool HQ) const
|
||||
{
|
||||
for (int32 i = 0; i < ItemList.Num(); i++)
|
||||
{
|
||||
|
||||
@@ -129,10 +129,10 @@ public:
|
||||
void EmptyInventory();
|
||||
|
||||
UFUNCTION(BlueprintCallable)
|
||||
int32 GetStackForItem(FPrimaryAssetId ItemId, bool HQ = false);
|
||||
int32 GetStackForItem(FPrimaryAssetId ItemId, bool HQ = false) const;
|
||||
|
||||
UFUNCTION(BlueprintCallable)
|
||||
int32 HasItem(FPrimaryAssetId ItemToCheck, bool HQ = false);
|
||||
int32 HasItem(FPrimaryAssetId ItemToCheck, bool HQ = false) const;
|
||||
|
||||
UFUNCTION(BlueprintCallable)
|
||||
TArray<FPrimaryAssetId> GetItemAssetIds();
|
||||
|
||||
Reference in New Issue
Block a user