mystic-flow/Source/Shooter/Weapon.cpp

202 lines
5.6 KiB
C++

// Fill out your copyright notice in the Description page of Project Settings.
#include "Weapon.h"
#include "Engine/SkeletalMesh.h"
#include "Components/SkeletalMeshComponent.h"
#include "TimerManager.h"
AWeapon::AWeapon() :
ThrowWeaponTime(0.7f),
bFalling(false),
Ammo(30),
MagazineCapacity(30),
WeaponType(EWeaponType::EWT_SubmachineGun),
AmmoType(EAmmoType::EAT_9mm),
ReloadMontageSection(FName(TEXT("Reload SMG"))),
ClipBoneName(TEXT("smg_clip")),
SlideDisplacement(0.f),
SlideDisplacementTime(0.2f),
bMovingSlide(false),
MaxSlideDisplacement(4.f),
MaxRecoilRotation(20.f),
bAutomatic(true)
{
PrimaryActorTick.bCanEverTick = true;
}
void AWeapon::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
/* Keep it upright */
if (GetItemState() == EItemState::EIS_Falling && bFalling)
{
FRotator MeshRotation{ 0.0, GetItemMesh()->GetComponentRotation().Yaw, 0.0 };
GetItemMesh()->SetWorldRotation(MeshRotation, false,
nullptr, ETeleportType::TeleportPhysics);
}
// Update slide on pistol
UpdateSlideDisplacement();
}
void AWeapon::ThrowWeapon()
{
FRotator MeshRotation{ 0.0, GetItemMesh()->GetComponentRotation().Yaw, 0.0 };
GetItemMesh()->SetWorldRotation(MeshRotation, false,
nullptr, ETeleportType::TeleportPhysics);
const FVector MeshForward{ GetItemMesh()->GetForwardVector() };
const FVector MeshRight{ GetItemMesh()->GetRightVector() };
// Direction in which we throw the weapon
FVector ImpulseDirection = MeshRight.RotateAngleAxis(-20.f, MeshForward);
float RandomRotation{ 30.f };
ImpulseDirection = ImpulseDirection.RotateAngleAxis(RandomRotation, FVector(0.f, 0.f, 1.f));
ImpulseDirection *= 2000.f;
GetItemMesh()->AddImpulse(ImpulseDirection);
bFalling = true;
GetWorldTimerManager().SetTimer(ThrowWeaponTimer, this,
&AWeapon::StopFalling, ThrowWeaponTime);
EnableGlowMaterial();
}
void AWeapon::DecrementAmmo()
{
if (Ammo - 1 <= 0)
Ammo = 0;
else
--Ammo;
}
void AWeapon::StartSlideTimer()
{
bMovingSlide = true;
GetWorldTimerManager().SetTimer(SlideTimer, this, &AWeapon::FinishMovingSlide, SlideDisplacementTime);
}
void AWeapon::ReloadAmmo(int32 Amount)
{
checkf(Ammo + Amount <= MagazineCapacity, TEXT("Attempted to reload with more than the magazine capacity!"))
Ammo += Amount;
}
bool AWeapon::ClipIsFull()
{
return Ammo >= MagazineCapacity;
}
void AWeapon::StopFalling()
{
bFalling = false;
SetItemState(EItemState::EIS_Pickup);
StartPulseTimer();
}
void AWeapon::OnConstruction(const FTransform& Transform)
{
Super::OnConstruction(Transform);
const FString WeaponTablePath{ TEXT("/Script/Engine.DataTable'/Game/_Game/DataTable/WeaponDataTable.WeaponDataTable'") };
UDataTable* WeaponTableObject = Cast<UDataTable>(StaticLoadObject(UDataTable::StaticClass(), nullptr, *WeaponTablePath));
if (WeaponTableObject)
{
FWeaponDataTable* WeaponDataRow = nullptr;
switch (WeaponType)
{
case EWeaponType::EWT_AssaultRifle:
WeaponDataRow = WeaponTableObject->FindRow<FWeaponDataTable>(FName("AssaultRifle"), TEXT(""));
break;
case EWeaponType::EWT_Pistol:
WeaponDataRow = WeaponTableObject->FindRow<FWeaponDataTable>(FName("Pistol"), TEXT(""));
break;
case EWeaponType::EWT_SubmachineGun:
default:
WeaponDataRow = WeaponTableObject->FindRow<FWeaponDataTable>(FName("SubmachineGun"), TEXT(""));
}
if (WeaponDataRow)
{
AmmoType = WeaponDataRow->AmmoType;
Ammo = WeaponDataRow->WeaponAmmo;
MagazineCapacity = WeaponDataRow->MagazineCapacity;
SetPickupSound(WeaponDataRow->PickupSound);
SetEquipSound(WeaponDataRow->EquipSound);
GetItemMesh()->SetSkeletalMesh(WeaponDataRow->ItemMesh);
SetItemName(WeaponDataRow->ItemName);
SetIconItem(WeaponDataRow->InventoryIcon);
SetIconAmmo(WeaponDataRow->AmmoIcon);
SetMaterialInstance(WeaponDataRow->MaterialInstance);
PreviousMaterialIndex = GetMaterialIndex();
GetItemMesh()->SetMaterial(PreviousMaterialIndex, nullptr);
SetMaterialIndex(WeaponDataRow->MaterialIndex);
ClipBoneName = WeaponDataRow->ClipBoneName;
ReloadMontageSection = WeaponDataRow->ReloadMontageSection;
GetItemMesh()->SetAnimInstanceClass(WeaponDataRow->AnimBP);
CrosshairsMiddle = WeaponDataRow->CrosshairsMiddle;
CrosshairsLeft = WeaponDataRow->CrosshairsLeft;
CrosshairsRight = WeaponDataRow->CrosshairsRight;
CrosshairsBottom = WeaponDataRow->CrosshairsBottom;
CrosshairsTop = WeaponDataRow->CrosshairsTop;
AutoFireRate = WeaponDataRow->AutoFireRate;
MuzzleFlash = WeaponDataRow->MuzzleFlash;
FireSound = WeaponDataRow->FireSound;
BoneToHide = WeaponDataRow->BoneToHide;
if (BoneToHide != FName(""))
{
GetItemMesh()->HideBoneByName(BoneToHide, EPhysBodyOp::PBO_None);
}
bAutomatic = WeaponDataRow->bAutomatic;
Damage = WeaponDataRow->Damage;
HeadshotDamage = WeaponDataRow->HeadshotDamage;
}
if (GetMaterialInstance())
{
SetDynamicMaterialInstance(UMaterialInstanceDynamic::Create(GetMaterialInstance(), this));
GetDynamicMaterialInstance()->SetVectorParameterValue(TEXT("FresnelColor"), GetGlowColor());
GetItemMesh()->SetMaterial(GetMaterialIndex(), GetDynamicMaterialInstance());
EnableGlowMaterial();
}
}
}
void AWeapon::BeginPlay()
{
Super::BeginPlay();
if (BoneToHide != FName(""))
{
GetItemMesh()->HideBoneByName(BoneToHide, EPhysBodyOp::PBO_None);
}
}
void AWeapon::FinishMovingSlide()
{
bMovingSlide = false;
}
void AWeapon::UpdateSlideDisplacement()
{
if (!SlideDisplacementCurve && !bMovingSlide) return;
const float ElapsedTime{ GetWorldTimerManager().GetTimerElapsed(SlideTimer) };
const float CurveValue{ SlideDisplacementCurve->GetFloatValue(ElapsedTime) };
SlideDisplacement = CurveValue * MaxSlideDisplacement;
RecoilRotation = CurveValue * MaxRecoilRotation;
}