// 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(StaticLoadObject(UDataTable::StaticClass(), nullptr, *WeaponTablePath)); if (WeaponTableObject) { FWeaponDataTable* WeaponDataRow = nullptr; switch (WeaponType) { case EWeaponType::EWT_AssaultRifle: WeaponDataRow = WeaponTableObject->FindRow(FName("AssaultRifle"), TEXT("")); break; case EWeaponType::EWT_Pistol: WeaponDataRow = WeaponTableObject->FindRow(FName("Pistol"), TEXT("")); break; case EWeaponType::EWT_SubmachineGun: default: WeaponDataRow = WeaponTableObject->FindRow(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; }