// Copyright 2016 Mookie. All Rights Reserved. #pragma once #include "CoreMinimal.h" #include "GameFramework/Actor.h" #include "Components/SkeletalMeshComponent.h" #include "Components/StaticMeshComponent.h" #include "EBBarrel.h" #include "EBMagazine.h" #include "EBWeaponConfiguration.h" #include "EBBulletProperties.h" #include "EBGun.generated.h" UENUM(BlueprintType) enum class EGunState : uint8 { GS_Ready UMETA(DisplayName = "Ready"), GS_Firing UMETA(DisplayName = "Firing"), GS_Reloading UMETA(DisplayName = "Reloading"), GS_Jammed UMETA(DisplayName = "Jammed"), GS_Empty UMETA(DisplayName = "Empty"), GS_SafetyOn UMETA(DisplayName = "Safety On"), GS_Malfunction UMETA(DisplayName = "Malfunction") }; UCLASS(Blueprintable, BlueprintType) class EASYBALLISTICS_API AEBGun : public AActor { GENERATED_BODY() public: AEBGun(); // Core Components UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Components") USkeletalMeshComponent* GunMesh; UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Components") UEBBarrel* Barrel; UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Components") UEBMagazine* Magazine; // Weapon Configuration UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Weapon Configuration") UEBWeaponConfiguration* WeaponConfig; // Gun State UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_GunState, Category = "Gun State") EGunState CurrentGunState = EGunState::GS_Ready; UPROPERTY(BlueprintReadOnly, Replicated, Category = "Gun State") bool bSafetyOn = false; UPROPERTY(BlueprintReadOnly, Replicated, Category = "Gun State") bool bChamberedRound = false; UPROPERTY(BlueprintReadOnly, Replicated, Category = "Gun State") bool bHammerCocked = false; // Firing Interface UFUNCTION(BlueprintCallable, Category = "Gun|Firing") void PullTrigger(); UFUNCTION(BlueprintCallable, Category = "Gun|Firing") void ReleaseTrigger(); UFUNCTION(BlueprintCallable, Category = "Gun|Controls") void SetSafety(bool bNewSafetyState); UFUNCTION(BlueprintCallable, Category = "Gun|Controls") void CockHammer(); UFUNCTION(BlueprintCallable, Category = "Gun|Controls") void ReleaseHammer(); // Ammunition Management UFUNCTION(BlueprintCallable, Category = "Gun|Ammunition") void LoadMagazine(TArray BulletTypes); UFUNCTION(BlueprintCallable, Category = "Gun|Ammunition") void EjectMagazine(); UFUNCTION(BlueprintCallable, Category = "Gun|Ammunition") void InsertMagazine(UEBMagazine* NewMagazine); UFUNCTION(BlueprintCallable, Category = "Gun|Ammunition") void ChargingHandle(); UFUNCTION(BlueprintCallable, Category = "Gun|Ammunition") void EjectChamberedRound(); // State Queries UFUNCTION(BlueprintPure, Category = "Gun|State") bool CanFire() const; UFUNCTION(BlueprintPure, Category = "Gun|State") bool IsLoaded() const; UFUNCTION(BlueprintPure, Category = "Gun|State") int32 GetRoundsInMagazine() const; UFUNCTION(BlueprintPure, Category = "Gun|State") int32 GetTotalRounds() const; UFUNCTION(BlueprintPure, Category = "Gun|State") UEBBulletPropertiesAsset* GetChamberedBulletType() const; // Configuration UFUNCTION(BlueprintCallable, Category = "Gun|Configuration") void ApplyWeaponConfiguration(UEBWeaponConfiguration* NewConfig); UFUNCTION(BlueprintCallable, Category = "Gun|Configuration") void SetFireMode(EFireMode NewFireMode); UFUNCTION(BlueprintPure, Category = "Gun|Configuration") EFireMode GetFireMode() const; // Barrel Integration UFUNCTION(BlueprintPure, Category = "Gun|Barrel") float GetBarrelLength() const; UFUNCTION(BlueprintPure, Category = "Gun|Barrel") float GetEffectiveMuzzleVelocity() const; UFUNCTION(BlueprintPure, Category = "Gun|Barrel") float GetBarrelAccuracy() const; UFUNCTION(BlueprintCallable, Category = "Gun|Barrel") FVector CalculateRecoilImpulse() const; UFUNCTION(BlueprintPure, Category = "Gun|Barrel") bool IsBarrelConnected() const; // Events DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnGunStateChanged, EGunState, NewState); UPROPERTY(BlueprintAssignable, Category = "Gun Events") FOnGunStateChanged OnGunStateChanged; DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnGunFired, UEBBulletPropertiesAsset*, BulletType); UPROPERTY(BlueprintAssignable, Category = "Gun Events") FOnGunFired OnGunFired; DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnMagazineEmpty); UPROPERTY(BlueprintAssignable, Category = "Gun Events") FOnMagazineEmpty OnMagazineEmpty; DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnMagazineChanged, UEBMagazine*, NewMagazine); UPROPERTY(BlueprintAssignable, Category = "Gun Events") FOnMagazineChanged OnMagazineChanged; DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnSafetyChanged, bool, bNewSafetyState); UPROPERTY(BlueprintAssignable, Category = "Gun Events") FOnSafetyChanged OnSafetyChanged; // Networking virtual void GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const override; protected: virtual void BeginPlay() override; virtual void Tick(float DeltaTime) override; // Replication UFUNCTION() void OnRep_GunState(); // Internal Functions UFUNCTION(BlueprintImplementableEvent, Category = "Gun|Internal") void OnGunStateChangedInternal(EGunState OldState, EGunState NewState); UFUNCTION(BlueprintImplementableEvent, Category = "Gun|Internal") void OnFireAnimationStart(); UFUNCTION(BlueprintImplementableEvent, Category = "Gun|Internal") void OnReloadAnimationStart(); UFUNCTION(BlueprintImplementableEvent, Category = "Gun|Internal") void OnJamAnimation(); void SetGunState(EGunState NewState); void ProcessFiring(); void ProcessReloading(); void CycleAction(); bool FeedNextRound(); // Timers FTimerHandle FireRateTimer; FTimerHandle ReloadTimer; FTimerHandle CycleTimer; // Firing Control bool bTriggerPressed = false; bool bCanProcessNextShot = true; int32 BurstShotsFired = 0; // Chambered Round UPROPERTY(Replicated) UEBBulletPropertiesAsset* ChamberedBulletType; private: EGunState PreviousGunState; // Server Functions UFUNCTION(Server, Reliable) void ServerPullTrigger(); UFUNCTION(Server, Reliable) void ServerReleaseTrigger(); UFUNCTION(Server, Reliable) void ServerSetSafety(bool bNewSafetyState); UFUNCTION(Server, Reliable) void ServerEjectMagazine(); UFUNCTION(Server, Reliable) void ServerInsertMagazine(UEBMagazine* NewMagazine); UFUNCTION(Server, Reliable) void ServerChargingHandle(); UFUNCTION(Server, Reliable) void ServerSetFireMode(EFireMode NewFireMode); // Multicast Functions UFUNCTION(NetMulticast, Reliable) void MulticastOnGunFired(UEBBulletPropertiesAsset* BulletType); UFUNCTION(NetMulticast, Reliable) void MulticastOnMagazineChanged(UEBMagazine* NewMagazine); UFUNCTION(NetMulticast, Reliable) void MulticastOnSafetyChanged(bool bNewSafetyState); // Event Handlers UFUNCTION() void OnMagazineEmptyHandler(UEBMagazine* EmptyMagazine); UFUNCTION() void OnBulletFedHandler(UEBMagazine* SourceMagazine, UEBBulletPropertiesAsset* BulletType); UFUNCTION() void OnBarrelShotFiredHandler(); // Internal firing function void FireShot(); };