405 lines
7.1 KiB
C++
405 lines
7.1 KiB
C++
// Copyright 2016 Mookie. All Rights Reserved.
|
|
|
|
#include "EBMagazine.h"
|
|
#include "Net/UnrealNetwork.h"
|
|
#include "Engine/Engine.h"
|
|
|
|
UEBMagazine::UEBMagazine()
|
|
{
|
|
PrimaryComponentTick.bCanEverTick = false;
|
|
SetIsReplicatedByDefault(true);
|
|
|
|
// Initialize magazine state
|
|
CurrentCapacity = 0;
|
|
bIsEmpty = true;
|
|
bIsFull = false;
|
|
bIsJammed = false;
|
|
bBoltHeldOpen = false;
|
|
}
|
|
|
|
void UEBMagazine::BeginPlay()
|
|
{
|
|
Super::BeginPlay();
|
|
|
|
UpdateMagazineState();
|
|
}
|
|
|
|
void UEBMagazine::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
|
|
{
|
|
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
|
|
|
|
DOREPLIFETIME(UEBMagazine, StoredBullets);
|
|
DOREPLIFETIME(UEBMagazine, CurrentCapacity);
|
|
DOREPLIFETIME(UEBMagazine, bIsEmpty);
|
|
DOREPLIFETIME(UEBMagazine, bIsFull);
|
|
DOREPLIFETIME(UEBMagazine, bIsJammed);
|
|
DOREPLIFETIME(UEBMagazine, bBoltHeldOpen);
|
|
}
|
|
|
|
void UEBMagazine::LoadBullets(TArray<UEBBulletPropertiesAsset*> BulletTypes)
|
|
{
|
|
if (GetOwner()->HasAuthority())
|
|
{
|
|
ServerLoadBullets(BulletTypes);
|
|
}
|
|
else
|
|
{
|
|
ServerLoadBullets(BulletTypes);
|
|
}
|
|
}
|
|
|
|
void UEBMagazine::ServerLoadBullets_Implementation(const TArray<UEBBulletPropertiesAsset*>& BulletTypes)
|
|
{
|
|
if (bIsJammed)
|
|
{
|
|
return;
|
|
}
|
|
|
|
for (UEBBulletPropertiesAsset* BulletType : BulletTypes)
|
|
{
|
|
if (BulletType && CurrentCapacity < MagazineConfig.MaxCapacity)
|
|
{
|
|
StoredBullets.Add(BulletType);
|
|
CurrentCapacity++;
|
|
|
|
OnBulletLoaded.Broadcast(this, BulletType);
|
|
MulticastOnBulletLoaded(BulletType);
|
|
}
|
|
}
|
|
|
|
UpdateMagazineState();
|
|
}
|
|
|
|
void UEBMagazine::LoadSingleBullet(UEBBulletPropertiesAsset* BulletType)
|
|
{
|
|
if (GetOwner()->HasAuthority())
|
|
{
|
|
ServerLoadSingleBullet(BulletType);
|
|
}
|
|
else
|
|
{
|
|
ServerLoadSingleBullet(BulletType);
|
|
}
|
|
}
|
|
|
|
void UEBMagazine::ServerLoadSingleBullet_Implementation(UEBBulletPropertiesAsset* BulletType)
|
|
{
|
|
if (!BulletType || bIsJammed || bIsFull)
|
|
{
|
|
return;
|
|
}
|
|
|
|
StoredBullets.Add(BulletType);
|
|
CurrentCapacity++;
|
|
|
|
OnBulletLoaded.Broadcast(this, BulletType);
|
|
MulticastOnBulletLoaded(BulletType);
|
|
|
|
UpdateMagazineState();
|
|
}
|
|
|
|
UEBBulletPropertiesAsset* UEBMagazine::FeedNextBullet()
|
|
{
|
|
if (!GetOwner()->HasAuthority())
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
if (!CanFeed())
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
// Check for malfunction
|
|
if (CheckForMalfunction())
|
|
{
|
|
bIsJammed = true;
|
|
OnMagazineJammed.Broadcast(this);
|
|
MulticastOnMagazineJammed();
|
|
UpdateMagazineState();
|
|
return nullptr;
|
|
}
|
|
|
|
// Feed the bullet
|
|
UEBBulletPropertiesAsset* FedBullet = StoredBullets[0];
|
|
StoredBullets.RemoveAt(0);
|
|
CurrentCapacity--;
|
|
|
|
OnBulletFed.Broadcast(this, FedBullet);
|
|
MulticastOnBulletFed(FedBullet);
|
|
|
|
UpdateMagazineState();
|
|
|
|
// Check for bolt hold open
|
|
if (bIsEmpty && MagazineConfig.bLastRoundBoltHoldOpen)
|
|
{
|
|
ProcessBoltHoldOpen();
|
|
}
|
|
|
|
return FedBullet;
|
|
}
|
|
|
|
void UEBMagazine::UnloadAllBullets()
|
|
{
|
|
if (GetOwner()->HasAuthority())
|
|
{
|
|
ServerUnloadAllBullets();
|
|
}
|
|
else
|
|
{
|
|
ServerUnloadAllBullets();
|
|
}
|
|
}
|
|
|
|
void UEBMagazine::ServerUnloadAllBullets_Implementation()
|
|
{
|
|
StoredBullets.Empty();
|
|
CurrentCapacity = 0;
|
|
bBoltHeldOpen = false;
|
|
UpdateMagazineState();
|
|
}
|
|
|
|
UEBBulletPropertiesAsset* UEBMagazine::UnloadLastBullet()
|
|
{
|
|
if (!GetOwner()->HasAuthority())
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
if (bIsEmpty)
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
UEBBulletPropertiesAsset* UnloadedBullet = StoredBullets.Last();
|
|
StoredBullets.RemoveAt(StoredBullets.Num() - 1);
|
|
CurrentCapacity--;
|
|
|
|
UpdateMagazineState();
|
|
return UnloadedBullet;
|
|
}
|
|
|
|
void UEBMagazine::ClearJam()
|
|
{
|
|
if (GetOwner()->HasAuthority())
|
|
{
|
|
ServerClearJam();
|
|
}
|
|
else
|
|
{
|
|
ServerClearJam();
|
|
}
|
|
}
|
|
|
|
void UEBMagazine::ServerClearJam_Implementation()
|
|
{
|
|
if (bIsJammed)
|
|
{
|
|
bIsJammed = false;
|
|
UpdateMagazineState();
|
|
}
|
|
}
|
|
|
|
void UEBMagazine::ReleaseBoltHold()
|
|
{
|
|
if (GetOwner()->HasAuthority())
|
|
{
|
|
ServerReleaseBoltHold();
|
|
}
|
|
else
|
|
{
|
|
ServerReleaseBoltHold();
|
|
}
|
|
}
|
|
|
|
void UEBMagazine::ServerReleaseBoltHold_Implementation()
|
|
{
|
|
if (bBoltHeldOpen)
|
|
{
|
|
bBoltHeldOpen = false;
|
|
UpdateMagazineState();
|
|
}
|
|
}
|
|
|
|
void UEBMagazine::ForceJam()
|
|
{
|
|
if (GetOwner()->HasAuthority())
|
|
{
|
|
bIsJammed = true;
|
|
OnMagazineJammed.Broadcast(this);
|
|
MulticastOnMagazineJammed();
|
|
UpdateMagazineState();
|
|
}
|
|
}
|
|
|
|
int32 UEBMagazine::GetRemainingCapacity() const
|
|
{
|
|
return MagazineConfig.MaxCapacity - CurrentCapacity;
|
|
}
|
|
|
|
int32 UEBMagazine::GetCurrentRoundCount() const
|
|
{
|
|
return CurrentCapacity;
|
|
}
|
|
|
|
int32 UEBMagazine::GetMaxCapacity() const
|
|
{
|
|
return MagazineConfig.MaxCapacity;
|
|
}
|
|
|
|
float UEBMagazine::GetFillPercentage() const
|
|
{
|
|
if (MagazineConfig.MaxCapacity <= 0)
|
|
{
|
|
return 0.0f;
|
|
}
|
|
return (float)CurrentCapacity / (float)MagazineConfig.MaxCapacity;
|
|
}
|
|
|
|
UEBBulletPropertiesAsset* UEBMagazine::PeekNextBullet() const
|
|
{
|
|
if (bIsEmpty || StoredBullets.Num() == 0)
|
|
{
|
|
return nullptr;
|
|
}
|
|
return StoredBullets[0];
|
|
}
|
|
|
|
bool UEBMagazine::CanFeed() const
|
|
{
|
|
return !bIsEmpty && !bIsJammed && !bBoltHeldOpen && StoredBullets.Num() > 0;
|
|
}
|
|
|
|
bool UEBMagazine::NeedsReload() const
|
|
{
|
|
return bIsEmpty || CurrentCapacity < (MagazineConfig.MaxCapacity * 0.25f); // Need reload when below 25%
|
|
}
|
|
|
|
TArray<UEBBulletPropertiesAsset*> UEBMagazine::GetBulletTypesSummary() const
|
|
{
|
|
TArray<UEBBulletPropertiesAsset*> UniqueBulletTypes;
|
|
|
|
for (UEBBulletPropertiesAsset* BulletType : StoredBullets)
|
|
{
|
|
if (BulletType && !UniqueBulletTypes.Contains(BulletType))
|
|
{
|
|
UniqueBulletTypes.Add(BulletType);
|
|
}
|
|
}
|
|
|
|
return UniqueBulletTypes;
|
|
}
|
|
|
|
void UEBMagazine::UpdateMagazineState()
|
|
{
|
|
bool bOldEmpty = bIsEmpty;
|
|
bool bOldFull = bIsFull;
|
|
|
|
bIsEmpty = (CurrentCapacity == 0);
|
|
bIsFull = (CurrentCapacity >= MagazineConfig.MaxCapacity);
|
|
|
|
// Fire events for state changes
|
|
if (bIsEmpty && !bOldEmpty)
|
|
{
|
|
OnMagazineEmpty.Broadcast(this);
|
|
}
|
|
else if (bIsFull && !bOldFull)
|
|
{
|
|
OnMagazineFull.Broadcast(this);
|
|
}
|
|
}
|
|
|
|
bool UEBMagazine::CheckForMalfunction()
|
|
{
|
|
if (MagazineConfig.MalfunctionChance <= 0.0f)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
float RandomValue = FMath::RandRange(0.0f, 1.0f);
|
|
return RandomValue <= MagazineConfig.MalfunctionChance;
|
|
}
|
|
|
|
void UEBMagazine::ProcessBoltHoldOpen()
|
|
{
|
|
if (!bBoltHeldOpen)
|
|
{
|
|
bBoltHeldOpen = true;
|
|
OnBoltHoldOpen.Broadcast(this);
|
|
MulticastOnBoltHoldOpen();
|
|
}
|
|
}
|
|
|
|
void UEBMagazine::OnRep_StoredBullets()
|
|
{
|
|
UpdateMagazineState();
|
|
}
|
|
|
|
void UEBMagazine::OnRep_CurrentCapacity()
|
|
{
|
|
UpdateMagazineState();
|
|
}
|
|
|
|
void UEBMagazine::OnRep_IsEmpty()
|
|
{
|
|
if (bIsEmpty)
|
|
{
|
|
OnMagazineEmpty.Broadcast(this);
|
|
}
|
|
}
|
|
|
|
void UEBMagazine::OnRep_IsFull()
|
|
{
|
|
if (bIsFull)
|
|
{
|
|
OnMagazineFull.Broadcast(this);
|
|
}
|
|
}
|
|
|
|
void UEBMagazine::OnRep_IsJammed()
|
|
{
|
|
if (bIsJammed)
|
|
{
|
|
OnMagazineJammed.Broadcast(this);
|
|
}
|
|
}
|
|
|
|
void UEBMagazine::OnRep_BoltHeldOpen()
|
|
{
|
|
if (bBoltHeldOpen)
|
|
{
|
|
OnBoltHoldOpen.Broadcast(this);
|
|
}
|
|
}
|
|
|
|
void UEBMagazine::MulticastOnBulletFed_Implementation(UEBBulletPropertiesAsset* BulletType)
|
|
{
|
|
if (!GetOwner()->HasAuthority())
|
|
{
|
|
OnBulletFed.Broadcast(this, BulletType);
|
|
}
|
|
}
|
|
|
|
void UEBMagazine::MulticastOnBulletLoaded_Implementation(UEBBulletPropertiesAsset* BulletType)
|
|
{
|
|
if (!GetOwner()->HasAuthority())
|
|
{
|
|
OnBulletLoaded.Broadcast(this, BulletType);
|
|
}
|
|
}
|
|
|
|
void UEBMagazine::MulticastOnMagazineJammed_Implementation()
|
|
{
|
|
if (!GetOwner()->HasAuthority())
|
|
{
|
|
OnMagazineJammed.Broadcast(this);
|
|
}
|
|
}
|
|
|
|
void UEBMagazine::MulticastOnBoltHoldOpen_Implementation()
|
|
{
|
|
if (!GetOwner()->HasAuthority())
|
|
{
|
|
OnBoltHoldOpen.Broadcast(this);
|
|
}
|
|
}
|