Files
ProjectEleri/Source/ProjectEleri/Items/ItemDatabase.cpp

513 lines
14 KiB
C++

// Fill out your copyright notice in the Description page of Project Settings.
#include "ItemDatabase.h"
#include <EngineUtils.h>
#include "PlantItem.h"
#include "DataAssets/ItemDataAsset.h"
#include "Engine/AssetManager.h"
#include "BookOfAlchemyManager.h"
#include "Kismet/GameplayStatics.h"
#include "ProjectEleri/Components/MoveActorsComponent.h"
#include "ProjectEleri/Settings/EleriGameSettings.h"
#include "ProjectEleri/System/MainBlueprintFunctionLibrary.h"
UWorld* UItemDatabase::GetWorld() const {
if (const UGameInstance* GameInstance = GetGameInstance()) {
return GameInstance->GetWorld();
}
return nullptr;
}
void UItemDatabase::Initialize(FSubsystemCollectionBase& Collection) {
Super::Initialize(Collection);
auto LoadDataLambda = [this]() {
if (UAssetManager* AssetManager = UAssetManager::GetIfInitialized()) {
AssetManager->GetPrimaryAssetIdList(FPrimaryAssetType("ItemDataAsset"), AllAssetIds);
FArrayOfItemRefs ArrayOfItemCategories[(int)Category::MAX];
TArray<FAssetData> DataList;
AssetManager->GetPrimaryAssetDataList(FName("ItemDataAsset"), DataList);
for (int32 i = 0; i < DataList.Num(); i++) {
UItemDataAsset* DataAsset = Cast<UItemDataAsset>(DataList[i].GetAsset());
LoadedItems.Add(DataAsset);
ArrayOfItemCategories[(int)DataAsset->ItemCategory].ItemArray.Add(DataAsset);
}
for (int32 i = 0; i < (int)Category::MAX; i++) {
LoadedItemsByCategory.Add((Category)i, ArrayOfItemCategories[i]);
}
for (int32 i = 0; i < (int)Category::MAX; i++) {
if (LoadedItemsByCategory[(Category)i].ItemArray.Num() > 0)
LoadedItemsByCategory[(Category)i].SortByName();
}
if (ABookOfAlchemyManager* AlchemyBook = Cast<ABookOfAlchemyManager>(UGameplayStatics::GetActorOfClass(GetWorld(), ABookOfAlchemyManager::StaticClass()))) {
AlchemyBook->PreloadLetters();
}
PrepareItemPriceData();
}
};
if (UAssetManager* AssetManager = UAssetManager::GetIfInitialized()) {
LoadDataLambda();
}
else {
UAssetManager::CallOrRegister_OnCompletedInitialScan(FStopRenderingThreadDelegate::CreateLambda(LoadDataLambda));
}
RemovableStaticMeshClass = GetDefault<UEleriGameSettings>()->RemovableStaticMeshClass;
ItemSeedCarouselClass = GetDefault<UEleriGameSettings>()->ItemSeedCarouselClass;
}
TArray<UItemDataAsset*> UItemDatabase::GetItemsOfElement(Element InElement, Category InCategory)
{
TArray<UItemDataAsset*> ItemList;
for (int32 i = 0; i < LoadedItemsByCategory[InCategory].ItemArray.Num(); i++)
{
if (LoadedItemsByCategory[InCategory].ItemArray[i]->ItemElement == InElement)
ItemList.Add(LoadedItemsByCategory[InCategory].ItemArray[i]);
}
return ItemList;
}
bool UItemDatabase::DoChemicalAlignmentsMatch(TArray<int32> Alignments, TArray<int32> PotionAlignments)
{
for (int32 i = 0; i < PotionAlignments.Num(); i++)
{
if (Alignments.Find(PotionAlignments[i]) == INDEX_NONE)
return false;
}
return true;
}
UItemDataAsset* UItemDatabase::GetPotionFromItems(TArray<UItemDataAsset*> Items, bool& Found)
{
TArray<int32> itemChemicalAlignments;
TMap<ItemProperty, int32> potionPropertyMap;
//int32 checkCount;
for (int32 i = 0; i < Items.Num(); i++)
{
for (int32 j = 0; j < Items[i]->ChemicalAlignments.Num(); j++)
{
itemChemicalAlignments.AddUnique(Items[i]->ChemicalAlignments[j]);
}
}
for (int32 i = 0; i < Items.Num(); i++)
{
for (int32 j = 0; j < Items[i]->Properties.Num(); j++)
{
if (potionPropertyMap.Find(Items[i]->Properties[j].Property) == nullptr)
potionPropertyMap.Add(Items[i]->Properties[j].Property, 1);
else
potionPropertyMap.Add(Items[i]->Properties[j].Property, *potionPropertyMap.Find(Items[i]->Properties[j].Property) + 1);
}
}
ItemProperty strongestProperty = ItemProperty::Heal;
int32 strongestValue = 0;
TArray<UItemDataAsset*> potentialPotions;
TArray<ItemProperty> keys;
potionPropertyMap.GetKeys(keys);
for (int32 i = 0; i < keys.Num(); i++)
{
int32 val = *potionPropertyMap.Find(keys[i]);
if (val > strongestValue) {
strongestValue = val;
strongestProperty = keys[i];
}
}
//for (int32 i = 0; i < AllPotions.Num(); i++)
//{
// if (AllPotions[i]->Properties.Num() > 0 &&
// AllPotions[i]->Properties[0].Property == strongestProperty && AllPotions[i]->Effectiveness <= strongestValue &&
// DoChemicalAlignmentsMatch(itemChemicalAlignments, AllPotions[i]->ChemicalAlignments)) {
// potentialPotions.Add(AllPotions[i]);
// }
//}
int32 strongestPotionIndex = 0;
if (potentialPotions.Num() > 0) {
for (int32 i = 0; i < potentialPotions.Num(); i++)
{
if (potentialPotions[i]->Effectiveness >= potentialPotions[strongestPotionIndex]->Effectiveness)
strongestPotionIndex = i;
}
}
if (IsValid(potentialPotions[strongestPotionIndex])) {
Found = true;
return potentialPotions[strongestPotionIndex];
}
Found = false;
return nullptr;
}
UItemDataAsset* UItemDatabase::GetPotionDataFromItems(TArray<UItemDataAsset*> Items)
{
for (int32 i = 0; i < Items.Num(); i++)
{
if (!Items[i])
{
Items.RemoveAt(i);
i--;
}
}
TArray<int32> itemChemicalAlignments;
TMap<ItemProperty, int32> potionPropertyMap;
int32 checkCount;
for (int32 i = 0; i < Items.Num(); i++)
{
if (Items[i])
{
for (int32 j = 0; j < Items[i]->ChemicalAlignments.Num(); j++)
{
itemChemicalAlignments.AddUnique(Items[i]->ChemicalAlignments[j]);
}
}
}
for (int32 i = 0; i < LoadedItems.Num(); i++)
{
if (!IsValid(LoadedItems[i])) continue;
checkCount = 0;
for (int32 j = 0; j < Items.Num(); j++)
{
for (int32 k = 0; k < LoadedItems[i]->RecipeItemsID.Num(); k++)
{
if (LoadedItems[i]->RecipeItemsID[k] == Items[j]->GetPrimaryAssetId())
{
checkCount++;
}
}
if (LoadedItems[i]->RecipeItemsID.Num() == Items.Num() && Items.Num() == checkCount)
{
return LoadedItems[i];
}
}
}
for (int32 i = 0; i < Items.Num(); i++)
{
for (int32 j = 0; j < Items[i]->Properties.Num(); j++)
{
if (potionPropertyMap.Find(Items[i]->Properties[j].Property) == nullptr)
potionPropertyMap.Add(Items[i]->Properties[j].Property, 1);
else
potionPropertyMap.Add(Items[i]->Properties[j].Property, *potionPropertyMap.Find(Items[i]->Properties[j].Property) + 1);
}
}
ItemProperty strongestProperty = ItemProperty::Heal;
int32 strongestValue = 0;
TArray<int32> potentialPotions;
TArray<ItemProperty> keys;
potionPropertyMap.GetKeys(keys);
for (int32 i = 0; i < keys.Num(); i++)
{
int32 val = *potionPropertyMap.Find(keys[i]);
if (val > strongestValue)
{
strongestValue = val;
strongestProperty = keys[i];
}
}
TArray<UItemDataAsset*> Potions = LoadedItemsByCategory[Category::Potion].ItemArray;
for (int32 i = 0; i < Potions.Num(); i++)
{
if (Potions[i]->Properties.Num() > 0 &&
Potions[i]->Properties[0].Property == strongestProperty && Potions[i]->Effectiveness <= strongestValue &&
DoChemicalAlignmentsMatch(itemChemicalAlignments, Potions[i]->ChemicalAlignments))
{
potentialPotions.Add(i);
}
}
int32 strongestPotionIndex = 0;
if (potentialPotions.Num() > 0)
{
for (int32 i = 0; i < potentialPotions.Num(); i++)
{
if (Potions[potentialPotions[i]]->Effectiveness >= Potions[potentialPotions[strongestPotionIndex]]->Effectiveness)
strongestPotionIndex = i;
}
}
if (potentialPotions.Num() > strongestPotionIndex && IsValid(Potions[potentialPotions[strongestPotionIndex]]))
{
return Potions[strongestPotionIndex];
}
return nullptr;
}
TArray<UItemDataAsset*> UItemDatabase::GetPotionsMatchingChemicalAlignment(UItemDataAsset* Ingredient)
{
TArray<UItemDataAsset*> PotionList;
if (!Ingredient) return PotionList;
const TArray<UItemDataAsset*> &AllPotionArray = LoadedItemsByCategory[Category::Potion].ItemArray;
for (int32 i = 0; i < AllPotionArray.Num(); i++)
{
if (AllPotionArray[i]->ChemicalAlignment == Ingredient->ChemicalAlignment)
{
PotionList.Add(AllPotionArray[i]);
}
}
return PotionList;
}
TArray<UItemDataAsset*> UItemDatabase::GetPotionsMatchingProperties(const TArray<UItemDataAsset*>& PotionList, TMap<ItemProperty, int32> PropertyList)
{
TArray<UItemDataAsset*> SortedPotionList;
int32 StrongestPropertyIndex = 0;
ItemProperty StrongestProperty = ItemProperty::Heal;
TArray<UItemDataAsset*> AllPotionsOfCategory = LoadedItemsByCategory[Category::Potion].ItemArray;
for (auto& PropertySet : PropertyList)
{
if (PropertySet.Value >= StrongestPropertyIndex)
{
StrongestPropertyIndex = PropertySet.Value;
StrongestProperty = PropertySet.Key;
}
}
for (int32 i = 0; i < AllPotionsOfCategory.Num(); i++)
{
int32 PropStrength = AllPotionsOfCategory[i]->GetPropertyStrength(StrongestProperty);
if (PropStrength > -1 && StrongestPropertyIndex >= PropStrength)
{
bool bPropertyNotInList = false;
for (int32 j = 0; j < AllPotionsOfCategory[i]->Properties.Num(); j++)
{
if (PropertyList[AllPotionsOfCategory[i]->Properties[j].Property] < AllPotionsOfCategory[i]->Properties[j].Strength)
{
bPropertyNotInList = true;
break;
}
}
if(!bPropertyNotInList)
SortedPotionList.Add(AllPotionsOfCategory[i]);
}
}
return SortedPotionList;
}
UItemDataAsset* UItemDatabase::GetDataAssetFromId(FPrimaryAssetId AssetId)
{
FAssetData AssetData;
UAssetManager::Get().GetPrimaryAssetData(AssetId, AssetData);
return Cast<UItemDataAsset>(AssetData.GetAsset());
}
TArray<UItemDataAsset*> UItemDatabase::GetDataAssetsFromIds(TArray<FPrimaryAssetId> AssetIds)
{
TArray<UItemDataAsset*> AssetList;
for (int32 i = 0; i < AssetIds.Num(); i++)
{
UItemDataAsset* FoundAsset = GetDataAssetFromId(AssetIds[i]);
if (IsValid(FoundAsset))
AssetList.Add(FoundAsset);
}
return AssetList;
}
float UItemDatabase::CalculatePotionPurity(TMap<ItemProperty, int32> PropertyList, TArray<FPropertyStrength> MainProperties)
{
int32 OtherPropertiesStrength = 0;
int32 MainPropertyValue = 0;
for (auto& Prop : MainProperties)
{
MainPropertyValue += *PropertyList.Find(Prop.Property);
}
for (auto& PropertySet : PropertyList)
{
bool found = false;
for (auto& Prop : MainProperties)
{
if (Prop.Property == PropertySet.Key)
{
found = true;
break;
}
}
if (!found)
{
OtherPropertiesStrength += PropertySet.Value;
}
}
return (float)MainPropertyValue / ((float)OtherPropertiesStrength + (float)MainPropertyValue);
}
int32 UItemDatabase::GetCrystalCostForPotion(UItemDataAsset* Potion)
{
if (!Potion) return -1;
return (int32)FMath::Pow(2.0f, (float)(Potion->ProfessionLevelNeeded + 1));
}
int32 UItemDatabase::GetCrystalCostForItems(TArray<UItemDataAsset*> Items)
{
int32 FinalCount = 0;
for (int32 i = 0; i < Items.Num(); i++)
{
if (!IsValid(Items[i])) continue;
for (int32 j = 0; j < Items[i]->Properties.Num(); j++)
{
FinalCount += Items[i]->Properties[j].Strength;
}
}
return FinalCount;
}
Element UItemDatabase::GetStrongestElement(const TArray<UItemDataAsset*>& PotionList)
{
if (IsValid(PotionList[0]))
{
return PotionList[0]->ItemElement;
}
TArray<int32> Strengths = {0, 0, 0, 0, 0, 0};
for (int32 i = 0; i < PotionList.Num(); i++)
{
if (!PotionList[i] || !IsValid(PotionList[i])) continue;
Strengths[(int32)PotionList[i]->ItemElement] += ElementStrength[PotionList[i]->ItemElement];
}
int32 StrongestIndex = 0;
int32 Strongest = Strengths[StrongestIndex];
for (int32 i = 0; i < Strengths.Num(); i++)
{
if (Strengths[i] >= Strongest)
{
Strongest = Strengths[i];
StrongestIndex = i;
}
}
return (Element)StrongestIndex;
}
void UItemDatabase::SpawnDecorationItem(UItemDataAsset* ItemAsset)
{
if (!ItemAsset || ItemAsset->ItemMesh.IsNull())
{
return;
}
ItemAsset->ItemMesh.LoadAsync(FLoadSoftObjectPathAsyncDelegate::CreateUObject(this, &UItemDatabase::OnDecorationItemLoaded, ItemAsset));
}
void UItemDatabase::RemoveDecorationItem(ARemovableStaticMeshActor* DecorationItem)
{
if (DecorationItem->ItemDataAsset && DecorationItem->bFromInventory)
{
UInventoryComponent* InventoryComponent = UMainBlueprintFunctionLibrary::GetPlayerInventory(GetWorld());
InventoryComponent->AddItemToInventory(DecorationItem->ItemDataAsset->GetPrimaryAssetId(), 1);
}
DecorationItem->Destroy();
}
void UItemDatabase::OnDecorationItemLoaded(const FSoftObjectPath& Path, UObject* Object, UItemDataAsset* ItemAsset)
{
UStaticMesh* StaticMesh = Cast<UStaticMesh>(Object);
if (!StaticMesh || !ItemAsset) return;
ACharacter* PlayerCharacter = UGameplayStatics::GetPlayerCharacter(GetWorld(), 0);
const FVector Location = PlayerCharacter->GetActorLocation() + (PlayerCharacter->GetActorForwardVector() * 1000.f);
FActorSpawnParameters SpawnParams;
SpawnParams.Instigator = PlayerCharacter;
SpawnParams.Owner = PlayerCharacter;
ARemovableStaticMeshActor* SpawnedActor = GetWorld()->SpawnActor<ARemovableStaticMeshActor>(RemovableStaticMeshClass, Location, FRotator::ZeroRotator, SpawnParams);
if (!SpawnedActor) return;
SpawnedActor->SetMobility(EComponentMobility::Movable);
SpawnedActor->Initialize(StaticMesh, ItemAsset);
UInventoryComponent* InventoryComponent = UMainBlueprintFunctionLibrary::GetPlayerInventory(GetWorld());
SpawnedActor->BindToItem(InventoryComponent);
InventoryComponent->RemoveItemFromInventory(ItemAsset->GetPrimaryAssetId(), 1);
UMoveActorsComponent* MoveActorsComponent = PlayerCharacter->GetComponentByClass<UMoveActorsComponent>();
if (!MoveActorsComponent) return;
MoveActorsComponent->StartObjectRemoval(true);
MoveActorsComponent->PickUpObjectForPlacing(SpawnedActor);
}
void FArrayOfItemRefs::SortByName()
{
ItemArray.Sort();
}
void UItemDatabase::PrepareItemPriceData() {
ItemPriceDataList.Empty();
for (auto LoadedItem : LoadedItems) {
FItemPriceData PriceData;
PriceData.ItemId = LoadedItem->GetPrimaryAssetId();
PriceData.PriceHistory.Empty();
PriceData.PriceHistory.Add(LoadedItem->BaseCost);
for (int32 i = 1; i < 30; i++) {
bool bIncrease = FMath::RandBool();
if (PriceData.PriceHistory[i - 1] < LoadedItem->BaseCost * 0.5)
bIncrease = true;
int32 NewPriceChange = (LoadedItem->BaseCost * FMath::RandRange(0.f, 0.5f)) * (bIncrease? 1 : -1);
PriceData.PriceHistory.Add(PriceData.PriceHistory[i - 1] + NewPriceChange);
}
PriceData.CurrentPrice = PriceData.PriceHistory[29];
ItemPriceDataList.Add(PriceData);
}
}
int32 UItemDatabase::GetCurrentPriceForItem(FPrimaryAssetId ItemId) {
for (auto PriceData : ItemPriceDataList) {
if (PriceData.ItemId == ItemId) {
return PriceData.CurrentPrice;
}
}
return 0;
}
TArray<int32> UItemDatabase::GetPriceHistoryForItem(FPrimaryAssetId ItemId) {
for (auto PriceData : ItemPriceDataList) {
if (PriceData.ItemId == ItemId) {
return PriceData.PriceHistory;
}
}
return TArray<int32>();
}