diff --git a/Content/Blueprints/Equipment/Blueprints/BP_ArmorSpawner.uasset b/Content/Blueprints/Equipment/Blueprints/BP_ArmorSpawner.uasset new file mode 100644 index 000000000..98efad548 Binary files /dev/null and b/Content/Blueprints/Equipment/Blueprints/BP_ArmorSpawner.uasset differ diff --git a/Content/Blueprints/Equipment/Blueprints/BP_ArmorSpawnerBase.uasset b/Content/Blueprints/Equipment/Blueprints/BP_ArmorSpawnerBase.uasset new file mode 100644 index 000000000..5a44c24db Binary files /dev/null and b/Content/Blueprints/Equipment/Blueprints/BP_ArmorSpawnerBase.uasset differ diff --git a/Content/Blueprints/Equipment/Blueprints/BP_FullArmorSpawner.uasset b/Content/Blueprints/Equipment/Blueprints/BP_FullArmorSpawner.uasset new file mode 100644 index 000000000..8d8aa3d3a Binary files /dev/null and b/Content/Blueprints/Equipment/Blueprints/BP_FullArmorSpawner.uasset differ diff --git a/Content/Blueprints/Equipment/Blueprints/BP_OnlyArmorSpawner.uasset b/Content/Blueprints/Equipment/Blueprints/BP_OnlyArmorSpawner.uasset new file mode 100644 index 000000000..9495989cc Binary files /dev/null and b/Content/Blueprints/Equipment/Blueprints/BP_OnlyArmorSpawner.uasset differ diff --git a/Content/Blueprints/Equipment/Blueprints/BP_OnlyHelmetSpawner.uasset b/Content/Blueprints/Equipment/Blueprints/BP_OnlyHelmetSpawner.uasset new file mode 100644 index 000000000..789db0e12 Binary files /dev/null and b/Content/Blueprints/Equipment/Blueprints/BP_OnlyHelmetSpawner.uasset differ diff --git a/Content/Blueprints/Equipment/Materials/M_Armor.uasset b/Content/Blueprints/Equipment/Materials/M_Armor.uasset new file mode 100644 index 000000000..92ad6c504 Binary files /dev/null and b/Content/Blueprints/Equipment/Materials/M_Armor.uasset differ diff --git a/Content/Blueprints/Equipment/Materials/M_Helmet.uasset b/Content/Blueprints/Equipment/Materials/M_Helmet.uasset new file mode 100644 index 000000000..fe52deceb Binary files /dev/null and b/Content/Blueprints/Equipment/Materials/M_Helmet.uasset differ diff --git a/Content/Blueprints/Equipment/Meshes/upgrade_dz_armor.uasset b/Content/Blueprints/Equipment/Meshes/upgrade_dz_armor.uasset new file mode 100644 index 000000000..af4edd339 Binary files /dev/null and b/Content/Blueprints/Equipment/Meshes/upgrade_dz_armor.uasset differ diff --git a/Content/Blueprints/Equipment/Meshes/upgrade_dz_armor_helmet.uasset b/Content/Blueprints/Equipment/Meshes/upgrade_dz_armor_helmet.uasset new file mode 100644 index 000000000..258c4d0c8 Binary files /dev/null and b/Content/Blueprints/Equipment/Meshes/upgrade_dz_armor_helmet.uasset differ diff --git a/Content/Blueprints/Equipment/Meshes/upgrade_dz_helmet.uasset b/Content/Blueprints/Equipment/Meshes/upgrade_dz_helmet.uasset new file mode 100644 index 000000000..40fd82f2e Binary files /dev/null and b/Content/Blueprints/Equipment/Meshes/upgrade_dz_helmet.uasset differ diff --git a/Content/Blueprints/Equipment/Sounds/armor_pickup_01.uasset b/Content/Blueprints/Equipment/Sounds/armor_pickup_01.uasset new file mode 100644 index 000000000..35a980c0b Binary files /dev/null and b/Content/Blueprints/Equipment/Sounds/armor_pickup_01.uasset differ diff --git a/Content/Blueprints/Equipment/Sounds/armor_pickup_02.uasset b/Content/Blueprints/Equipment/Sounds/armor_pickup_02.uasset new file mode 100644 index 000000000..aaebde680 Binary files /dev/null and b/Content/Blueprints/Equipment/Sounds/armor_pickup_02.uasset differ diff --git a/Content/Blueprints/Equipment/Textures/T_ArmorColor.uasset b/Content/Blueprints/Equipment/Textures/T_ArmorColor.uasset new file mode 100644 index 000000000..4e52f78d6 Binary files /dev/null and b/Content/Blueprints/Equipment/Textures/T_ArmorColor.uasset differ diff --git a/Content/Blueprints/Equipment/Textures/T_HelmetColor.uasset b/Content/Blueprints/Equipment/Textures/T_HelmetColor.uasset new file mode 100644 index 000000000..55ad8e5d6 Binary files /dev/null and b/Content/Blueprints/Equipment/Textures/T_HelmetColor.uasset differ diff --git a/Content/Blueprints/Equipment/Textures/T_HelmetNormal.uasset b/Content/Blueprints/Equipment/Textures/T_HelmetNormal.uasset new file mode 100644 index 000000000..1e53027a1 Binary files /dev/null and b/Content/Blueprints/Equipment/Textures/T_HelmetNormal.uasset differ diff --git a/Content/Blueprints/Modes/BP_Cloud9Default.uasset b/Content/Blueprints/Modes/BP_Cloud9Default.uasset index 7677b212b..2ef15dd68 100644 Binary files a/Content/Blueprints/Modes/BP_Cloud9Default.uasset and b/Content/Blueprints/Modes/BP_Cloud9Default.uasset differ diff --git a/Content/Blueprints/Widgets/HudWidget.uasset b/Content/Blueprints/Widgets/HudWidget.uasset index bbd814bea..f4a06977b 100644 Binary files a/Content/Blueprints/Widgets/HudWidget.uasset and b/Content/Blueprints/Widgets/HudWidget.uasset differ diff --git a/Content/Maps/warmup.umap b/Content/Maps/warmup.umap index 8c29bc45e..b50d4b175 100644 Binary files a/Content/Maps/warmup.umap and b/Content/Maps/warmup.umap differ diff --git a/Content/Vefects/VFX/Misc/NS_RingGlow_Armor.uasset b/Content/Vefects/VFX/Misc/NS_RingGlow_Armor.uasset new file mode 100644 index 000000000..e2613777b Binary files /dev/null and b/Content/Vefects/VFX/Misc/NS_RingGlow_Armor.uasset differ diff --git a/Importing/textures/materials_models_player_ct_swat_ct_swat_head.png b/Importing/textures/materials_models_player_ct_swat_ct_swat_head.png new file mode 100644 index 000000000..5dc410555 Binary files /dev/null and b/Importing/textures/materials_models_player_ct_swat_ct_swat_head.png differ diff --git a/Importing/textures/materials_models_player_ct_swat_ct_swat_head_normal.png b/Importing/textures/materials_models_player_ct_swat_ct_swat_head_normal.png new file mode 100644 index 000000000..bf01bef24 Binary files /dev/null and b/Importing/textures/materials_models_player_ct_swat_ct_swat_head_normal.png differ diff --git a/Importing/textures/materials_models_props_survival_upgrades_dz_armor.png b/Importing/textures/materials_models_props_survival_upgrades_dz_armor.png new file mode 100644 index 000000000..b97317bf7 Binary files /dev/null and b/Importing/textures/materials_models_props_survival_upgrades_dz_armor.png differ diff --git a/Importing/upgrade_dz_armor.blend b/Importing/upgrade_dz_armor.blend new file mode 100644 index 000000000..720df2ded Binary files /dev/null and b/Importing/upgrade_dz_armor.blend differ diff --git a/Importing/upgrade_dz_armor.fbx b/Importing/upgrade_dz_armor.fbx new file mode 100644 index 000000000..6b56a6163 Binary files /dev/null and b/Importing/upgrade_dz_armor.fbx differ diff --git a/Importing/upgrade_dz_armor_helmet.blend b/Importing/upgrade_dz_armor_helmet.blend new file mode 100644 index 000000000..180979472 Binary files /dev/null and b/Importing/upgrade_dz_armor_helmet.blend differ diff --git a/Importing/upgrade_dz_armor_helmet.fbx b/Importing/upgrade_dz_armor_helmet.fbx new file mode 100644 index 000000000..d7de40ac5 Binary files /dev/null and b/Importing/upgrade_dz_armor_helmet.fbx differ diff --git a/Importing/upgrade_dz_helmet.blend b/Importing/upgrade_dz_helmet.blend new file mode 100644 index 000000000..548a3f60f Binary files /dev/null and b/Importing/upgrade_dz_helmet.blend differ diff --git a/Importing/upgrade_dz_helmet.fbx b/Importing/upgrade_dz_helmet.fbx new file mode 100644 index 000000000..f63954edd Binary files /dev/null and b/Importing/upgrade_dz_helmet.fbx differ diff --git a/Source/Cloud9/Character/Cloud9Character.cpp b/Source/Cloud9/Character/Cloud9Character.cpp index 65861f0cd..6f0958069 100644 --- a/Source/Cloud9/Character/Cloud9Character.cpp +++ b/Source/Cloud9/Character/Cloud9Character.cpp @@ -35,18 +35,19 @@ #include "Components/DecalComponent.h" #include "Components/CapsuleComponent.h" -#include "Cloud9/Game/Cloud9GameInstance.h" #include "Cloud9/Game/Cloud9DeveloperSettings.h" #include "Cloud9/Contollers//Cloud9PlayerController.h" -#include "Cloud9/Character/Components/Cloud9CharacterMovement.h" +#include "Cloud9/Weapon/Classes/Cloud9WeaponBase.h" #include "Cloud9/Character/Components/Cloud9Inventory.h" +#include "Cloud9/Character/Components/Cloud9CharacterMovement.h" #include "Cloud9/Character/Components/Cloud9SpringArmComponent.h" -#include "Cloud9/Weapon/Classes/Cloud9WeaponBase.h" +#include "Cloud9/Character/Components/Cloud9CharacterHealthComponent.h" const FName ACloud9Character::SpringArmComponentName = TEXT("CameraBoom"); const FName ACloud9Character::CameraComponentName = TEXT("TopDownCamera"); const FName ACloud9Character::DecalComponentName = TEXT("CursorToWorld"); const FName ACloud9Character::InventoryComponentName = TEXT("Inventory"); +const FName ACloud9Character::HealthComponentName = TEXT("HealthComponent"); ACloud9Character::ACloud9Character(const FObjectInitializer& ObjectInitializer) : Super( ObjectInitializer.SetDefaultSubobjectClass(CharacterMovementComponentName)) @@ -77,11 +78,13 @@ ACloud9Character::ACloud9Character(const FObjectInitializer& ObjectInitializer) CursorToWorld->SetupAttachment(RootComponent); Inventory = CreateDefaultSubobject(InventoryComponentName); + HealthComponent = CreateDefaultSubobject(HealthComponentName); - Health = 100.0f; - Armor = 25.0f; // TODO: Set armor to 0 after health shot and armor pack added Score = 1; // TODO: Set score to 0 after implementation + OnTakePointDamage.AddDynamic(HealthComponent, &UCloud9CharacterHealthComponent::OnTakePointDamage); + OnTakeRadialDamage.AddDynamic(HealthComponent, &UCloud9CharacterHealthComponent::OnTakeRadialDamage); + // Activate ticking in order to update the cursor every frame. PrimaryActorTick.bCanEverTick = true; PrimaryActorTick.bStartWithTickEnabled = true; @@ -226,6 +229,8 @@ void ACloud9Character::SetCameraZoomHeight(float Value) const UCloud9Inventory* ACloud9Character::GetInventory() const { return Inventory; } +UCloud9CharacterHealthComponent* ACloud9Character::GetHealthComponent() const { return HealthComponent; } + void ACloud9Character::UseObject() { // TODO: Implement UseObject @@ -271,15 +276,4 @@ void ACloud9Character::Tick(float DeltaSeconds) { Inventory->SelectOtherAvailableWeapon(false); } - - // // TODO: Remove auto grenade add after debug - // if (not Inventory->GetWeaponAt(EWeaponSlot::Grenade) and Inventory->GetSelectedWeapon() != nullptr) - // { - // if (let GameInstance = GetGameInstance(); IsValid(GameInstance)) - // { - // GameInstance->GetDefaultWeaponsConfig() - // | ETContainer::Filter{[this](let& Config) { return IsValid(Config) and Config.IsGrenadeWeapon(); }} - // | ETContainer::ForEach{[this](let& Config) { Inventory->AddWeapon(Config); }}; - // } - // } } diff --git a/Source/Cloud9/Character/Cloud9Character.h b/Source/Cloud9/Character/Cloud9Character.h index 0eb35c94e..c42bb9644 100644 --- a/Source/Cloud9/Character/Cloud9Character.h +++ b/Source/Cloud9/Character/Cloud9Character.h @@ -32,6 +32,8 @@ #include "Cloud9Character.generated.h" +class UCloud9CharacterHealthComponent; + UCLASS(config=Game, Blueprintable) class ACloud9Character : public ACharacter { @@ -42,6 +44,7 @@ class ACloud9Character : public ACharacter static const FName CameraComponentName; static const FName DecalComponentName; static const FName InventoryComponentName; + static const FName HealthComponentName; ACloud9Character(const FObjectInitializer& ObjectInitializer); @@ -79,6 +82,9 @@ class ACloud9Character : public ACharacter void SetCameraZoomHeight(float Value) const; UCloud9Inventory* GetInventory() const; + + UCloud9CharacterHealthComponent* GetHealthComponent() const; + void UseObject(); // Set by character movement to specify that this Character is currently sneaking. @@ -115,13 +121,9 @@ class ACloud9Character : public ACharacter UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=Inventory, meta=(AllowPrivateAccess)) UCloud9Inventory* Inventory; - /** Current percentage health of character */ - UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=State, meta=(AllowPrivateAccess)) - float Health; - - /** Current percentage armor of character */ + /** A state of the character health and armor. */ UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=State, meta=(AllowPrivateAccess)) - float Armor; + UCloud9CharacterHealthComponent* HealthComponent; /** Current number of frags made by character */ UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=State, meta=(AllowPrivateAccess)) diff --git a/Source/Cloud9/Character/Components/Cloud9CharacterHealthComponent.cpp b/Source/Cloud9/Character/Components/Cloud9CharacterHealthComponent.cpp new file mode 100644 index 000000000..8e79aca82 --- /dev/null +++ b/Source/Cloud9/Character/Components/Cloud9CharacterHealthComponent.cpp @@ -0,0 +1,112 @@ +// Copyright (c) 2024 Alexei Gladkikh + +#include "Cloud9CharacterHealthComponent.h" + +#include "Cloud9/Tools/Macro/Common.h" +#include "Cloud9/Tools/Macro/Logging.h" + +UCloud9CharacterHealthComponent::UCloud9CharacterHealthComponent() +{ + Health = 100.0f; + Armor = 0.0f; + bHasHelmet = false; +} + +void UCloud9CharacterHealthComponent::Initialize(FHealthConfig Config) +{ + ChangeHealth(Config.Health); + ChangeArmor(Config.Armor); + ChangeHasHelmet(Config.bHasHelmet); +} + +bool UCloud9CharacterHealthComponent::TakeHealthDamage(float Change) +{ + return ChangeHealth(Health - Change); +} + +bool UCloud9CharacterHealthComponent::TakeArmorDamage(float Change) +{ + return ChangeArmor(Armor - Change); +} + +bool UCloud9CharacterHealthComponent::ChangeHealth(float NewHealth) +{ + if (let Value = FMath::Max(NewHealth, 0.0f); Value != Health) + { + Health = Value; + OnHealthChange.Broadcast(Health); + + if (Health == 0.0f) + { + let Owner = GetOwner(); + + if (not IsValid(Owner)) + { + log(Fatal, "[Component = %s] Owner isn't valid", *GetName()); + return false; + } + + Owner->MarkPendingKill(); + } + + return true; + } + + return false; +} + +bool UCloud9CharacterHealthComponent::ChangeArmor(float NewArmor) +{ + if (let Value = FMath::Clamp(NewArmor, 0.0f, 100.0f); Value != Armor) + { + Armor = Value; + OnArmorChange.Broadcast(Armor); + if (Armor == 0.0f) + { + ChangeHasHelmet(false); + } + return true; + } + + return false; +} + +bool UCloud9CharacterHealthComponent::ChangeHasHelmet(bool NewState) +{ + if (bHasHelmet != NewState) + { + bHasHelmet = NewState; + OnHelmetChange.Broadcast(NewState); + return true; + } + + return false; +} + +void UCloud9CharacterHealthComponent::OnTakePointDamage( + AActor* DamagedActor, + float Damage, + AController* InstigatedBy, + FVector HitLocation, + UPrimitiveComponent* FHitComponent, + FName BoneName, + FVector ShotFromDirection, + const UDamageType* DamageType, + AActor* DamageCauser) +{ + TakeHealthDamage(Damage); // TODO: Add factor by armor + TakeArmorDamage(0.0f); // TODO: Add armor damage calc +} + +void UCloud9CharacterHealthComponent::OnTakeRadialDamage( + AActor* DamagedActor, + float Damage, + const UDamageType* DamageType, + FVector Origin, + FHitResult HitInfo, + AController* InstigatedBy, + AActor* DamageCauser) +{ + TakeHealthDamage(Damage); // TODO: Add factor by armor + TakeArmorDamage(0.0f); // TODO: Add armor damage calc +} diff --git a/Source/Cloud9/Character/Components/Cloud9CharacterHealthComponent.h b/Source/Cloud9/Character/Components/Cloud9CharacterHealthComponent.h new file mode 100644 index 000000000..b3490ee86 --- /dev/null +++ b/Source/Cloud9/Character/Components/Cloud9CharacterHealthComponent.h @@ -0,0 +1,112 @@ +// Copyright (c) 2023 Alexei Gladkikh +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. + +#pragma once + +#include "CoreMinimal.h" + +#include "Cloud9/Character/Components/Cloud9CharacterComponent.h" +#include "Cloud9/Character/Structures/HealthConfig.h" + +#include "Cloud9CharacterHealthComponent.generated.h" + +DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnHealthChange, float, Health); + +DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnArmorChange, float, Armor); + +DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnHelmetChange, bool, State); + + +class ACloud9Character; + +UCLASS(Blueprintable) +class CLOUD9_API UCloud9CharacterHealthComponent + : public UActorComponent + , public ICloud9CharacterComponent +{ + GENERATED_BODY() + +public: + UCloud9CharacterHealthComponent(); + + void Initialize(FHealthConfig Config); + + bool TakeHealthDamage(float Change); + bool TakeArmorDamage(float Change); + + // Helmet is permanent(?) + bool ChangeHasHelmet(bool NewState); + + UFUNCTION() + void OnTakePointDamage( + AActor* DamagedActor, + float Damage, + AController* InstigatedBy, + FVector HitLocation, + UPrimitiveComponent* FHitComponent, + FName BoneName, + FVector ShotFromDirection, + const UDamageType* DamageType, + AActor* DamageCauser); + + UFUNCTION() + void OnTakeRadialDamage( + AActor* DamagedActor, + float Damage, + const UDamageType* DamageType, + FVector Origin, + FHitResult HitInfo, + AController* InstigatedBy, + AActor* DamageCauser + ); + + float GetHealth() const { return Health; } + float GetArmor() const { return Armor; } + bool HasHelmet() const { return bHasHelmet; } + +protected: + bool ChangeHealth(float NewHealth); + bool ChangeArmor(float NewArmor); + +protected: + UPROPERTY(BlueprintAssignable, meta=(AllowPrivateAccess), Category=Events) + FOnHealthChange OnHealthChange; + + UPROPERTY(BlueprintAssignable, meta=(AllowPrivateAccess), Category=Events) + FOnArmorChange OnArmorChange; + + UPROPERTY(BlueprintAssignable, meta=(AllowPrivateAccess), Category=Events) + FOnHelmetChange OnHelmetChange; + + /** Current percentage health of character */ + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=State, meta=(AllowPrivateAccess)) + float Health; + + /** Current percentage armor of character */ + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=State, meta=(AllowPrivateAccess)) + float Armor; + + /** Current percentage armor of character */ + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=State, meta=(AllowPrivateAccess)) + bool bHasHelmet; +}; diff --git a/Source/Cloud9/Character/Structures/HealthConfig.h b/Source/Cloud9/Character/Structures/HealthConfig.h new file mode 100644 index 000000000..530d72c09 --- /dev/null +++ b/Source/Cloud9/Character/Structures/HealthConfig.h @@ -0,0 +1,22 @@ +// Copyright (c) 2024 Alexei Gladkikh + +#pragma once + +#include "HealthConfig.generated.h" + +USTRUCT(BlueprintType) +struct FHealthConfig +{ + GENERATED_BODY() + + UPROPERTY(Category=Config, EditDefaultsOnly, BlueprintReadOnly, + meta=(UIMin="0", UIMax="20000.0", ClampMin="0", ClampMax="20000.0")) + float Health = 100.0f; + + UPROPERTY(Category=Config, EditDefaultsOnly, BlueprintReadOnly, + meta=(UIMin="0", UIMax="100.0", ClampMin="0", ClampMax="100.0")) + float Armor = 0.0f; + + UPROPERTY(Category=Config, EditDefaultsOnly, BlueprintReadOnly) + bool bHasHelmet = false; +}; diff --git a/Source/Cloud9/Modes/Cloud9DefaultGameMode.cpp b/Source/Cloud9/Modes/Cloud9DefaultGameMode.cpp index 198aefd41..a899f69d7 100644 --- a/Source/Cloud9/Modes/Cloud9DefaultGameMode.cpp +++ b/Source/Cloud9/Modes/Cloud9DefaultGameMode.cpp @@ -2,10 +2,11 @@ #include "Cloud9DefaultGameMode.h" -#include "Cloud9/Character/Cloud9Character.h" -#include "Cloud9/Game/Cloud9GameInstance.h" #include "Cloud9/Tools/Macro/Common.h" #include "Cloud9/Tools/Macro/Logging.h" +#include "Cloud9/Game/Cloud9GameInstance.h" +#include "Cloud9/Character/Cloud9Character.h" +#include "Cloud9/Character/Components/Cloud9CharacterHealthComponent.h" FName ACloud9DefaultGameMode::CtSidePlayer = TEXT("CT"); FName ACloud9DefaultGameMode::TSidePlayer = TEXT("T"); @@ -76,7 +77,10 @@ bool ACloud9DefaultGameMode::OnWorldStart(FSavedInfo& SavedInfo) { let Character = GetPlayerCharacter(LocalPlayer); let Inventory = Character->GetInventory(); + let Health = Character->GetHealthComponent(); + Inventory->Initialize(PlayerConfig.WeaponConfigs, PlayerConfig.WeaponSlot); + Health->Initialize(PlayerConfig.HealthConfig); } }; } diff --git a/Source/Cloud9/Structures/PlayerSavedInfo.h b/Source/Cloud9/Structures/PlayerSavedInfo.h index 2ca7829d8..14f5a6b84 100644 --- a/Source/Cloud9/Structures/PlayerSavedInfo.h +++ b/Source/Cloud9/Structures/PlayerSavedInfo.h @@ -2,6 +2,7 @@ #pragma once +#include "Cloud9/Character/Structures/HealthConfig.h" #include "Cloud9/Weapon/Structures/WeaponConfig.h" #include "PlayerSavedInfo.generated.h" @@ -11,6 +12,9 @@ struct FPlayerSavedInfo { GENERATED_BODY() + UPROPERTY(Category=Health, EditDefaultsOnly, BlueprintReadOnly) + FHealthConfig HealthConfig; + UPROPERTY(Category=Weapon, EditDefaultsOnly, BlueprintReadOnly) EWeaponSlot WeaponSlot = EWeaponSlot::NotSelected; diff --git a/Source/Cloud9/Weapon/Classes/Cloud9WeaponFirearm.cpp b/Source/Cloud9/Weapon/Classes/Cloud9WeaponFirearm.cpp index 20acb5fec..9f46930c6 100644 --- a/Source/Cloud9/Weapon/Classes/Cloud9WeaponFirearm.cpp +++ b/Source/Cloud9/Weapon/Classes/Cloud9WeaponFirearm.cpp @@ -35,6 +35,7 @@ #include "Cloud9/Game/Cloud9DeveloperSettings.h" #include "Cloud9/Weapon/Sounds/Cloud9SoundPlayer.h" #include "Cloud9/Weapon/Tables/WeaponTableFirearm.h" +#include "Kismet/GameplayStatics.h" const FName ACloud9WeaponFirearm::TracerProbabilityParameterName = TEXT("Probability"); const FName ACloud9WeaponFirearm::TracerDirectionParameterName = TEXT("Direction"); @@ -378,6 +379,16 @@ EFirearmFireStatus ACloud9WeaponFirearm::Fire( Squib->SetAutoDestroy(true); } + UGameplayStatics::ApplyPointDamage( + LineHit.Actor.Get(), + WeaponInfo->Damage, + Direction, + LineHit, + GetInstigatorController(), + this, + UDamageType::StaticClass() + ); + return EFirearmFireStatus::Success; } diff --git a/Source/Cloud9/Weapon/Utils/AmmoSpawner.cpp b/Source/Cloud9/Weapon/Utils/AmmoSpawner.cpp index 9f81f278f..173ba4f95 100644 --- a/Source/Cloud9/Weapon/Utils/AmmoSpawner.cpp +++ b/Source/Cloud9/Weapon/Utils/AmmoSpawner.cpp @@ -55,16 +55,4 @@ bool AAmmoSpawner::ActivateSpawner(ACloud9Character* Character) return false; } -AActor* AAmmoSpawner::CreateChildActor() -{ - if (IsValid(SampleMesh)) - { - let ItemSample = CreateItemSample(); - let StaticMeshComponent = ItemSample->GetStaticMeshComponent(); - StaticMeshComponent->SetMobility(EComponentMobility::Movable); - StaticMeshComponent->SetStaticMesh(SampleMesh); - return ItemSample; - } - - return nullptr; -} +AActor* AAmmoSpawner::CreateChildActor() { return InitializeStaticMeshSample(SampleMesh); } diff --git a/Source/Cloud9/Weapon/Utils/EquipmentSpawner.cpp b/Source/Cloud9/Weapon/Utils/EquipmentSpawner.cpp new file mode 100644 index 000000000..f2cc4a4af --- /dev/null +++ b/Source/Cloud9/Weapon/Utils/EquipmentSpawner.cpp @@ -0,0 +1,76 @@ +// Copyright (c) 2024 Alexei Gladkikh + +#include "EquipmentSpawner.h" + +#include "Engine/StaticMeshActor.h" + +#include "Cloud9/Character/Cloud9Character.h" +#include "Cloud9/Character/Components/Cloud9CharacterHealthComponent.h" + +AEquipmentSpawner::AEquipmentSpawner() +{ + SampleMesh = nullptr; + + bChangeHealth = false; + bChangeArmor = false; + + Health = 0.0f; + Armor = 0.0f; + bHelmet = false; + + bHealthActivated = false; + bArmorActivated = false; + bHelmetActivated = false; +} + +bool AEquipmentSpawner::ActivateSpawner(ACloud9Character* Character) +{ + if (IsValid(Character)) + { + let HealthComponent = Character->GetHealthComponent(); + + var Activated = false; + + if (bChangeHealth and HealthComponent->TakeHealthDamage(-Health)) + { + bHealthActivated = true; + Activated = true; + } + + if (bChangeArmor and HealthComponent->TakeArmorDamage(-Armor)) + { + bArmorActivated = true; + Activated = true; + } + + if (bHelmet and HealthComponent->ChangeHasHelmet(true)) + { + bHelmetActivated = true; + Activated = true; + } + + return Activated; + } + + return false; +} + +bool AEquipmentSpawner::CanBeDestroyed() const +{ + return not(bChangeHealth xor bHealthActivated) and + not(bChangeArmor xor bArmorActivated) and + not(bHelmetActivated xor bHelmet); +} + +void AEquipmentSpawner::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) +{ + Super::PostEditChangeProperty(PropertyChangedEvent); + + if (not bChangeArmor) + { + log(Warning, "Can't add helmet without kevlar vest") + bHelmet = false; + } +} + +AActor* AEquipmentSpawner::CreateChildActor() { return InitializeStaticMeshSample(SampleMesh); } diff --git a/Source/Cloud9/Weapon/Utils/EquipmentSpawner.h b/Source/Cloud9/Weapon/Utils/EquipmentSpawner.h new file mode 100644 index 000000000..1612d9656 --- /dev/null +++ b/Source/Cloud9/Weapon/Utils/EquipmentSpawner.h @@ -0,0 +1,59 @@ +// Copyright (c) 2024 Alexei Gladkikh + +#pragma once + +#include "CoreMinimal.h" +#include "ItemSpawner.h" +#include "EquipmentSpawner.generated.h" + +UCLASS() +class CLOUD9_API AEquipmentSpawner : public AItemSpawner +{ + GENERATED_BODY() + +public: + AEquipmentSpawner(); + + virtual AActor* CreateChildActor() override; + + virtual bool ActivateSpawner(ACloud9Character* Character) override; + + virtual bool CanBeDestroyed() const override; + +protected: +#if WITH_EDITOR + virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override; +#endif + +protected: + UPROPERTY(EditDefaultsOnly, Category=Config) + UStaticMesh* SampleMesh; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category=Overrides, + meta=(PinHiddenByDefault, InlineEditConditionToggle)) + bool bChangeHealth; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category=Config, + meta=(UIMin="0", UIMax="100.0", ClampMin="0", ClampMax="20000.0", EditCondition="bChangeHealth")) + float Health; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category=Overrides, + meta=(PinHiddenByDefault, InlineEditConditionToggle)) + bool bChangeArmor; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category=Config, + meta=(UIMin="0", UIMax="100.0", ClampMin="0", ClampMax="100.0", EditCondition="bChangeArmor")) + float Armor; + + UPROPERTY(EditAnywhere, Category=Config, meta=(EditCondition="bChangeArmor")) + bool bHelmet; + + UPROPERTY(BlueprintReadOnly, Category=State) + bool bHealthActivated; + + UPROPERTY(BlueprintReadOnly, Category=State) + bool bArmorActivated; + + UPROPERTY(BlueprintReadOnly, Category=State) + bool bHelmetActivated; +}; diff --git a/Source/Cloud9/Weapon/Utils/ItemSpawner.cpp b/Source/Cloud9/Weapon/Utils/ItemSpawner.cpp index 6b2e94e68..c3b92272b 100644 --- a/Source/Cloud9/Weapon/Utils/ItemSpawner.cpp +++ b/Source/Cloud9/Weapon/Utils/ItemSpawner.cpp @@ -30,6 +30,7 @@ #include "Cloud9/Weapon/Classes/Cloud9WeaponBase.h" #include "Cloud9/Weapon/Sounds/Cloud9SoundPlayer.h" +#include "Engine/StaticMeshActor.h" FName AItemSpawner::RootComponentName = "RootComponent"; FName AItemSpawner::TriggerBoxComponentName = "TriggerBox"; @@ -70,6 +71,8 @@ AActor* AItemSpawner::CreateChildActor() { return nullptr; } bool AItemSpawner::ActivateSpawner(ACloud9Character* Character) { return false; } +bool AItemSpawner::CanBeDestroyed() const { return true; } + void AItemSpawner::OnConstruction(const FTransform& Transform) { Super::OnConstruction(Transform); @@ -154,10 +157,24 @@ void AItemSpawner::OnBeginOverlap( UCloud9SoundPlayer::PlayRandomSound(ActivationSounds, GetActorLocation(), Settings->Volume); - if (bIsDestroyOnActivation) + if (bIsDestroyOnActivation and CanBeDestroyed()) { Destroy(); } } } } + +AStaticMeshActor* AItemSpawner::InitializeStaticMeshSample(UStaticMesh* Mesh) +{ + if (IsValid(Mesh)) + { + let Sample = CreateItemSample(); + let StaticMeshComponent = Sample->GetStaticMeshComponent(); + StaticMeshComponent->SetMobility(EComponentMobility::Movable); + StaticMeshComponent->SetStaticMesh(Mesh); + return Sample; + } + + return nullptr; +} diff --git a/Source/Cloud9/Weapon/Utils/ItemSpawner.h b/Source/Cloud9/Weapon/Utils/ItemSpawner.h index 5da769826..f005a3c1b 100644 --- a/Source/Cloud9/Weapon/Utils/ItemSpawner.h +++ b/Source/Cloud9/Weapon/Utils/ItemSpawner.h @@ -27,6 +27,7 @@ #include "CoreMinimal.h" #include "GameFramework/Actor.h" #include "Cloud9/Tools/Macro/Common.h" +#include "Engine/StaticMeshActor.h" #include "ItemSpawner.generated.h" class ISpawnerDelegateComponent; @@ -55,6 +56,8 @@ class CLOUD9_API AItemSpawner : public AActor virtual bool ActivateSpawner(ACloud9Character* Character); + virtual bool CanBeDestroyed() const; + virtual void OnConstruction(const FTransform& Transform) override final; virtual void BeginPlay() override final; @@ -104,6 +107,8 @@ class CLOUD9_API AItemSpawner : public AActor return Cast(ItemSample); } + AStaticMeshActor* InitializeStaticMeshSample(UStaticMesh* Mesh); + protected: UPROPERTY(BlueprintReadOnly, Category=Implementation) UBoxComponent* TriggerBoxComponent;