mirror of
https://github.com/ApfelTeeSaft/UnrealEvent.git
synced 2026-08-26 19:33:43 +00:00
375 lines
11 KiB
C++
375 lines
11 KiB
C++
#pragma once
|
|
#include "framework.h"
|
|
#include <random>
|
|
|
|
namespace LootHandler
|
|
{
|
|
vector<string> ItemsToRemove = {
|
|
"WID_RC_Rocket_Athena_SR_T03", // Guided Missle
|
|
"WID_RC_Rocket_Athena_VR_T03", // Guided Missle
|
|
"AGID_BoostJumpPack", // Jetpack
|
|
"Athena_Mimic", // Mimic
|
|
"WID_Sniper_Crossbow_Athena_VR_Ore_T03", // Crossbow
|
|
"WID_Sniper_Crossbow_Athena_R_Ore_T03", // Crossbow
|
|
};
|
|
|
|
struct LootRow
|
|
{
|
|
LootRow(string AssetPath, string rowName, int dropCount = 1, int loadedAmmo = 0, float weight = 1.00, bool bplaygroundOnly = true)
|
|
{
|
|
RowName = rowName;
|
|
ItemDefinition = SDKUtils::FindObject<UFortItemDefinition>(AssetPath);
|
|
DropCount = dropCount;
|
|
LoadedAmmo = loadedAmmo;
|
|
Weight = weight;
|
|
bPlaygroundOnly = bplaygroundOnly;
|
|
}
|
|
|
|
LootRow(UFortItemDefinition* itemDefinition, string rowName, int dropCount = 1, int loadedAmmo = 0, float weight = 1.00, bool bplaygroundOnly = true)
|
|
{
|
|
RowName = rowName;
|
|
ItemDefinition = itemDefinition;
|
|
DropCount = dropCount;
|
|
LoadedAmmo = loadedAmmo;
|
|
Weight = weight;
|
|
bPlaygroundOnly = bplaygroundOnly;
|
|
}
|
|
|
|
public:
|
|
string RowName = "";
|
|
UFortItemDefinition* ItemDefinition = nullptr;
|
|
int DropCount = 1;
|
|
int LoadedAmmo = 0;
|
|
float Weight = 0.0;
|
|
bool bPlaygroundOnly = false;
|
|
|
|
LootRow() = default;
|
|
};
|
|
|
|
vector<LootRow> LootRows;
|
|
LootRow CurrentLootRow;
|
|
|
|
int GetClipSize(UFortWeaponRangedItemDefinition* ItemDefinition)
|
|
{
|
|
if (!ItemDefinition)
|
|
return 0;
|
|
|
|
auto DataTable = ItemDefinition->WeaponStatHandle.DataTable;
|
|
auto RowName = ItemDefinition->WeaponStatHandle.RowName;
|
|
|
|
if (DataTable && RowName.ComparisonIndex)
|
|
{
|
|
auto& RowMap = DataTable->RowMap;
|
|
if (RowMap.IsValid())
|
|
{
|
|
for (int i = 0; i < RowMap.Num(); ++i)
|
|
{
|
|
if (RowMap[i].Second)
|
|
if (RowMap[i].First == RowName)
|
|
if (auto Stats = reinterpret_cast<FFortRangedWeaponStats*>(RowMap[i].Second))
|
|
return Stats->ClipSize;
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
bool IsItemRemoved(string ItemDefinition)
|
|
{
|
|
for (string ItemToRemove : ItemsToRemove)
|
|
{
|
|
if (ItemDefinition.contains(ItemToRemove))
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
bool bInitialized = false;
|
|
void Initialize()
|
|
{
|
|
if (bInitialized)
|
|
return;
|
|
|
|
bInitialized = true;
|
|
LogInfo("Initializing Loot.");
|
|
|
|
UFortPlaylistAthena* Playlist = Globals::GetGameState()->CurrentPlaylistInfo.BasePlaylist ;
|
|
UDataTable* LootPackagesDataTable = SDKUtils::FindObject<UDataTable>(UKismetStringLibrary::Conv_NameToString(Playlist->LootPackages.ObjectID.AssetPathName).ToString());
|
|
UDataTable* LootTierGroupDataTable = nullptr;
|
|
|
|
if (!LootPackagesDataTable)
|
|
LootPackagesDataTable = SDKUtils::FindObject<UDataTable>("/Game/Items/Datatables/AthenaLootPackages_Client.AthenaLootPackages_Client");
|
|
|
|
LogInfo("LootManager::Initialize: LootPackagesDataTable: {}", LootPackagesDataTable->GetName());
|
|
|
|
if (LootPackagesDataTable)
|
|
{
|
|
auto& RowMap = LootPackagesDataTable->RowMap;
|
|
for (int i = 0; i < RowMap.Num(); ++i)
|
|
{
|
|
auto& CurrentRow = RowMap[i];
|
|
FName RowName = CurrentRow.First;
|
|
if (!RowName.ComparisonIndex)
|
|
continue;
|
|
string RowNameStr = UKismetStringLibrary::Conv_NameToString(RowName).ToString();
|
|
auto PackageData = reinterpret_cast<FFortLootPackageData*>(CurrentRow.Second);
|
|
|
|
if (RowNameStr.contains("WorldPKG") || RowNameStr.contains("WorldList.AthenaLoot.VendingMachine")) // not using WorldPKG yet and don't want VendingMachine loot yet.
|
|
continue;
|
|
|
|
if (PackageData->Weight == 0.00)
|
|
continue;
|
|
|
|
LootRow Row = LootRow();
|
|
|
|
string ItemDefStr = UKismetStringLibrary::Conv_NameToString(PackageData->ItemDefinition.ObjectID.AssetPathName).ToString();
|
|
if (IsItemRemoved(ItemDefStr))
|
|
continue;
|
|
|
|
auto ItemDefinition = SDKUtils::FindObject<UFortWeaponRangedItemDefinition>(ItemDefStr);
|
|
if (!ItemDefinition)
|
|
continue;
|
|
|
|
LogInfo("LootManager::Initialize: [{} - {}]: Asset Path Name: {}", i, RowNameStr, ItemDefStr);
|
|
Row.RowName = PackageData->LootPackageID.ToString();
|
|
Row.ItemDefinition = ItemDefinition;
|
|
Row.DropCount = PackageData->Count;
|
|
Row.Weight = PackageData->Weight;
|
|
|
|
if (!ItemDefStr.contains("AGID_") && !ItemDefStr.contains("ItemData") && !ItemDefStr.contains("Consumables") && !ItemDefStr.contains("ForagedItems")) // For some reason crashes if i don't do this.
|
|
Row.LoadedAmmo = GetClipSize(ItemDefinition);
|
|
|
|
if (ItemDefinition->GetName() != "None")
|
|
LootRows.push_back(Row);
|
|
}
|
|
}
|
|
}
|
|
|
|
LootRow* GetRandomItem(string RequiredRowName)
|
|
{
|
|
float TotalWeight = 0.0f;
|
|
for (const LootRow& Row : LootRows)
|
|
{
|
|
if (Row.RowName.contains(RequiredRowName))
|
|
TotalWeight += Row.Weight;
|
|
}
|
|
|
|
if (TotalWeight == 0.0f)
|
|
return &LootRows[0];
|
|
|
|
std::random_device RandomDevice;
|
|
std::mt19937 Generator(RandomDevice());
|
|
std::uniform_real_distribution<float> Distribution(0.0f, TotalWeight);
|
|
float RandomWeight = Distribution(Generator);
|
|
|
|
float CumulativeWeight = 0.0f;
|
|
for (LootRow& Row : LootRows)
|
|
{
|
|
if (Row.RowName.contains(RequiredRowName))
|
|
{
|
|
CumulativeWeight += Row.Weight;
|
|
if (RandomWeight <= CumulativeWeight)
|
|
return &Row;
|
|
}
|
|
}
|
|
|
|
return &LootRows[0];
|
|
}
|
|
|
|
static vector<string> InvalidAmmoTypes = {
|
|
"AmmoInfiniteCrossbow_Athena",
|
|
"AmmoTrollData",
|
|
"AmmoInfinite",
|
|
"AmmoDataSmokeBomb"
|
|
};
|
|
|
|
bool IsValidAmmoType(UFortItemDefinition* AmmoDefinition)
|
|
{
|
|
for (string InvalidAmmoType : InvalidAmmoTypes)
|
|
{
|
|
if (AmmoDefinition->GetName() == InvalidAmmoType)
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
vector<LootRow*> GetFloorLoot()
|
|
{
|
|
vector<LootRow*> FloorLootRows;
|
|
auto bConsumable = rand() % 100 > 70;
|
|
|
|
if (bConsumable)
|
|
if (rand() % 100 > 80)
|
|
FloorLootRows.push_back(GetRandomItem("WorldList.AthenaHighConsumables"));
|
|
else
|
|
FloorLootRows.push_back(GetRandomItem("WorldList.AthenaLoot.Resources"));
|
|
else
|
|
{
|
|
auto WeaponItem = GetRandomItem("WorldList.AthenaLoot.Weapon");
|
|
if (WeaponItem && WeaponItem->ItemDefinition)
|
|
{
|
|
auto AmmoDefinition = static_cast<UFortWorldItemDefinition*>(WeaponItem->ItemDefinition)->GetAmmoWorldItemDefinition_BP();
|
|
if (AmmoDefinition && AmmoDefinition != WeaponItem->ItemDefinition)
|
|
{
|
|
FloorLootRows.push_back(new LootRow(AmmoDefinition, "", AmmoDefinition->DropCount));
|
|
}
|
|
|
|
FloorLootRows.push_back(WeaponItem);
|
|
}
|
|
}
|
|
|
|
return FloorLootRows;
|
|
}
|
|
|
|
vector<LootRow*> GetChestLoot()
|
|
{
|
|
vector<LootRow*> ChestRows;
|
|
|
|
ChestRows.push_back(GetRandomItem("WorldList.AthenaHighConsumables"));
|
|
ChestRows.push_back(GetRandomItem("WorldList.AthenaLoot.Resources"));
|
|
auto WeaponItem = GetRandomItem("WorldList.AthenaLoot.Weapon");
|
|
if (WeaponItem && WeaponItem->ItemDefinition)
|
|
{
|
|
auto AmmoDefinition = static_cast<UFortWorldItemDefinition*>(WeaponItem->ItemDefinition)->GetAmmoWorldItemDefinition_BP();
|
|
if (AmmoDefinition && AmmoDefinition != WeaponItem->ItemDefinition)
|
|
{
|
|
ChestRows.push_back(new LootRow(AmmoDefinition, "", AmmoDefinition->DropCount));
|
|
}
|
|
|
|
ChestRows.push_back(WeaponItem);
|
|
}
|
|
|
|
return ChestRows;
|
|
}
|
|
|
|
vector<LootRow*> GetAmmoLoot()
|
|
{
|
|
vector<LootRow*> AmmoRows;
|
|
|
|
AmmoRows.push_back(GetRandomItem("WorldList.AthenaAmmoSmall"));
|
|
AmmoRows.push_back(GetRandomItem("WorldList.AthenaAmmoSmall"));
|
|
|
|
return AmmoRows;
|
|
}
|
|
|
|
vector<LootRow*> GetSupplyDropLoot()
|
|
{
|
|
vector<LootRow*> SupplyDropRows;
|
|
|
|
SupplyDropRows.push_back(GetRandomItem("WorldList.AthenaHighConsumables"));
|
|
SupplyDropRows.push_back(GetRandomItem("WorldList.AthenaLoot.Resources"));
|
|
SupplyDropRows.push_back(GetRandomItem("WorldList.AthenaTraps"));
|
|
auto WeaponItem = GetRandomItem("WorldList.AthenaSupplyDrop");
|
|
if (WeaponItem && WeaponItem->ItemDefinition)
|
|
{
|
|
auto AmmoDefinition = static_cast<UFortWorldItemDefinition*>(WeaponItem->ItemDefinition)->GetAmmoWorldItemDefinition_BP();
|
|
if (AmmoDefinition && AmmoDefinition != WeaponItem->ItemDefinition)
|
|
{
|
|
SupplyDropRows.push_back(new LootRow(AmmoDefinition, "", AmmoDefinition->DropCount));
|
|
}
|
|
|
|
SupplyDropRows.push_back(WeaponItem);
|
|
}
|
|
|
|
return SupplyDropRows;
|
|
}
|
|
|
|
AFortPickupAthena* SpawnPickup(UFortItemDefinition* ItemDefinition, int OverrideCount, int LoadedAmmo, FVector Loc, bool bTossedFromContainer, EFortPickupSourceTypeFlag InPickupSourceTypeFlags, EFortPickupSpawnSource InPickupSpawnSource)
|
|
{
|
|
if (!ItemDefinition)
|
|
return nullptr;
|
|
|
|
if (OverrideCount > 1000)
|
|
return nullptr;
|
|
|
|
auto SpawnedPickup = SDKUtils::SpawnActor<AFortPickupAthena>(AFortPickupAthena::StaticClass(), Loc);
|
|
if (!SpawnedPickup)
|
|
return nullptr;
|
|
|
|
SpawnedPickup->bRandomRotation = true;
|
|
FFortItemEntry* PickupEntry = &SpawnedPickup->PrimaryPickupItemEntry;
|
|
FFortItemEntryStateValue Value = {};
|
|
Value.IntValue = 1;
|
|
Value.StateType = EFortItemEntryState::ShouldShowItemToast;
|
|
Value.NameValue = FName(0);
|
|
PickupEntry->StateValues.Add(Value);
|
|
PickupEntry->ItemDefinition = ItemDefinition;
|
|
PickupEntry->Count = OverrideCount;
|
|
PickupEntry->LoadedAmmo = LoadedAmmo;
|
|
PickupEntry->ReplicationKey++;
|
|
SpawnedPickup->OnRep_PrimaryPickupItemEntry();
|
|
|
|
SpawnedPickup->TossPickup(Loc, nullptr, 1, true, InPickupSourceTypeFlags, InPickupSpawnSource);
|
|
|
|
SpawnedPickup->SetReplicateMovement(true);
|
|
SpawnedPickup->MovementComponent = reinterpret_cast<UProjectileMovementComponent*>(UGameplayStatics::SpawnObject(UProjectileMovementComponent::StaticClass(), SpawnedPickup));
|
|
|
|
SpawnedPickup->bTossedFromContainer = bTossedFromContainer;
|
|
SpawnedPickup->OnRep_TossedFromContainer();
|
|
|
|
return SpawnedPickup;
|
|
}
|
|
|
|
static bool bAlreadySpawned = false;
|
|
bool SpawnFloorLoot()
|
|
{
|
|
bAlreadySpawned = true;
|
|
|
|
if (!bAlreadySpawned)
|
|
return false;
|
|
|
|
LogInfo("Spawning Floor Loot.");
|
|
|
|
int SpawnedLoot = 0;
|
|
auto BR_FloorLoot_Class = SDKUtils::FindObject<UBlueprintGeneratedClass>("/Game/Athena/Environments/Blueprints/Tiered_Athena_FloorLoot_01.Tiered_Athena_FloorLoot_01_C");
|
|
TArray<AActor*> BR_FloorLootActors;
|
|
UGameplayStatics::GetAllActorsOfClass(Globals::GetWorld(), BR_FloorLoot_Class, &BR_FloorLootActors);
|
|
for (int i = 0; i < BR_FloorLootActors.Num(); i++)
|
|
{
|
|
auto CurrentActor = BR_FloorLootActors[i];
|
|
if (CurrentActor)
|
|
{
|
|
FVector Loc = CurrentActor->K2_GetActorLocation();
|
|
Loc.Z += 30;
|
|
SpawnedLoot++;
|
|
auto loot = GetFloorLoot();
|
|
for (auto& LootItem : loot)
|
|
{
|
|
if (LootItem->ItemDefinition)
|
|
SpawnPickup(LootItem->ItemDefinition, LootItem->DropCount, LootItem->LoadedAmmo, Loc, false, EFortPickupSourceTypeFlag::FloorLoot, EFortPickupSpawnSource::Unset);
|
|
}
|
|
|
|
CurrentActor->K2_DestroyActor();
|
|
}
|
|
}
|
|
BR_FloorLootActors.Free();
|
|
|
|
auto Warmup_Floorloot_Class = SDKUtils::FindObject<UBlueprintGeneratedClass>("/Game/Athena/Environments/Blueprints/Tiered_Athena_FloorLoot_Warmup.Tiered_Athena_FloorLoot_Warmup_C");
|
|
TArray<AActor*> Warmup_FloorlootActors;
|
|
UGameplayStatics::GetAllActorsOfClass(Globals::GetWorld(), Warmup_Floorloot_Class, &Warmup_FloorlootActors);
|
|
for (int i = 0; i < Warmup_FloorlootActors.Num(); i++)
|
|
{
|
|
auto CurrentActor = Warmup_FloorlootActors[i];
|
|
if (CurrentActor)
|
|
{
|
|
FVector Loc = CurrentActor->K2_GetActorLocation();
|
|
SpawnedLoot++;
|
|
auto loot = GetFloorLoot();
|
|
for (auto& LootItem : loot)
|
|
{
|
|
SpawnPickup(LootItem->ItemDefinition, LootItem->DropCount, LootItem->LoadedAmmo, Loc, false, EFortPickupSourceTypeFlag::FloorLoot, EFortPickupSpawnSource::Unset);
|
|
}
|
|
|
|
CurrentActor->K2_DestroyActor();
|
|
}
|
|
}
|
|
Warmup_FloorlootActors.Free();
|
|
|
|
LogInfo("SpawnedLoot: {}", SpawnedLoot);
|
|
|
|
return true;
|
|
}
|
|
} |