diff --git a/Content/Characters/Common/Animations/TAnimation.uasset b/Content/Characters/Common/Animations/TAnimation.uasset index e4dc5325a..1b91bc605 100644 Binary files a/Content/Characters/Common/Animations/TAnimation.uasset and b/Content/Characters/Common/Animations/TAnimation.uasset differ diff --git a/Content/Characters/Common/Animations/TAnimation_SmgAim1D.uasset b/Content/Characters/Common/Animations/TAnimation_SmgAim1D.uasset new file mode 100644 index 000000000..976d09960 Binary files /dev/null and b/Content/Characters/Common/Animations/TAnimation_SmgAim1D.uasset differ diff --git a/Content/Characters/Common/Montages/Smg/smg_deploy_Montage.uasset b/Content/Characters/Common/Montages/Smg/smg_deploy_Montage.uasset index 7bf7c12fd..aa3a62281 100644 Binary files a/Content/Characters/Common/Montages/Smg/smg_deploy_Montage.uasset and b/Content/Characters/Common/Montages/Smg/smg_deploy_Montage.uasset differ diff --git a/Content/Characters/Common/Sequences/Smg/AO_smg_aim_idle_aim_dvert_center.uasset b/Content/Characters/Common/Sequences/Smg/AO_smg_aim_idle_aim_dvert_center.uasset new file mode 100644 index 000000000..cc1576dd1 Binary files /dev/null and b/Content/Characters/Common/Sequences/Smg/AO_smg_aim_idle_aim_dvert_center.uasset differ diff --git a/Content/Characters/Common/Sequences/Smg/AO_smg_aim_idle_aim_mid_center.uasset b/Content/Characters/Common/Sequences/Smg/AO_smg_aim_idle_aim_mid_center.uasset new file mode 100644 index 000000000..27a37ef27 Binary files /dev/null and b/Content/Characters/Common/Sequences/Smg/AO_smg_aim_idle_aim_mid_center.uasset differ diff --git a/Content/Characters/Common/Sequences/Smg/AO_smg_aim_idle_aim_uvert_center.uasset b/Content/Characters/Common/Sequences/Smg/AO_smg_aim_idle_aim_uvert_center.uasset new file mode 100644 index 000000000..453960641 Binary files /dev/null and b/Content/Characters/Common/Sequences/Smg/AO_smg_aim_idle_aim_uvert_center.uasset differ diff --git a/Source/Cloud9/Character/Cloud9Character.cpp b/Source/Cloud9/Character/Cloud9Character.cpp index 59def4ea4..24dfe9ad6 100644 --- a/Source/Cloud9/Character/Cloud9Character.cpp +++ b/Source/Cloud9/Character/Cloud9Character.cpp @@ -183,7 +183,7 @@ void ACloud9Character::SetViewDirection(const TOptional& HitResult) } } - let Settings = UCloud9DeveloperSettings::Get(); + static let Settings = UCloud9DeveloperSettings::Get(); let StartLocation = GetMesh()->GetBoneLocation(CameraTargetBoneName, EBoneSpaces::WorldSpace); @@ -318,11 +318,13 @@ float ACloud9Character::InternalTakePointDamage( AController* EventInstigator, AActor* DamageCauser) { - let BoneName = PointDamageEvent.HitInfo.BoneName; + static let Settings = UCloud9DeveloperSettings::Get(); + Damage = Super::InternalTakePointDamage(Damage, PointDamageEvent, EventInstigator, DamageCauser); if (let Weapon = Cast(DamageCauser)) { + let BoneName = PointDamageEvent.HitInfo.BoneName; let WeaponInfo = Weapon->GetWeaponInfo(); bool HitInArmor = false; @@ -351,26 +353,37 @@ float ACloud9Character::InternalTakePointDamage( WeaponInfo->RangeModifier, Distance * Cloud9WeaponConsts::RangeExponentCoefficient); - Damage *= RangeCoefficient; + var DamageToHealth = Damage * RangeCoefficient; var DamageToArmor = 0.0f; if (HitInArmor) { - let ArmorRatio = WeaponInfo->ArmorPenetration * Cloud9WeaponConsts::ArmorCoefficient; - DamageToArmor = Damage * (1.0f - ArmorRatio) * Cloud9WeaponConsts::ArmorBonus; + DamageToHealth = Damage * WeaponInfo->ArmorPenetration * Cloud9WeaponConsts::ArmorCoefficient; + DamageToArmor = (Damage - DamageToHealth) * Cloud9WeaponConsts::ArmorBonus; + // Does this use more armor than we have? if (let ArmorValue = HealthComponent->GetArmor(); DamageToArmor > ArmorValue) { - Damage = Damage - ArmorValue / Cloud9WeaponConsts::ArmorBonus; + DamageToHealth = Damage - ArmorValue / Cloud9WeaponConsts::ArmorBonus; DamageToArmor = ArmorValue; } HealthComponent->TakeArmorDamage(DamageToArmor < 0 ? 1.0f : DamageToArmor); + Damage = DamageToHealth; } - log(Verbose, - "[Actor='%s'] Distance=%f RangeCoefficient=%f BoneName=%s DamageToHealth=%f DamageToArmor=%f", - *GetName(), FMath::Sqrt(Distance), RangeCoefficient, *BoneName.ToString(), Damage, DamageToArmor); + if (Settings->WeaponDebugDamageInfo) + { + log(Display, + "[Actor='%s'] Distance=%f RangeCoefficient=%f BoneName=%s Armored=%d DamageToHealth=%f DamageToArmor=%f", + *GetName(), + FMath::Sqrt(Distance), + RangeCoefficient, + *BoneName.ToString(), + HitInArmor, + DamageToHealth, + DamageToArmor); + } } return Damage; diff --git a/Source/Cloud9/Game/Cloud9DeveloperSettings.cpp b/Source/Cloud9/Game/Cloud9DeveloperSettings.cpp index 771fea23b..7ccfaf519 100644 --- a/Source/Cloud9/Game/Cloud9DeveloperSettings.cpp +++ b/Source/Cloud9/Game/Cloud9DeveloperSettings.cpp @@ -45,6 +45,7 @@ FString UCloud9DeveloperSettings::WeaponDebugMaxInaccuracyName = "r.WeaponDebugM FString UCloud9DeveloperSettings::WeaponDebugInaccuracyOnlyUpName = "r.WeaponDebugInaccuracyOnlyUp"; FString UCloud9DeveloperSettings::WeaponRecoilDecayCoefficientName = "r.WeaponRecoilDecayCoefficient"; FString UCloud9DeveloperSettings::DrawShotDirectionAxisName = "r.DrawShotDirectionAxis"; +FString UCloud9DeveloperSettings::WeaponDebugDamageInfoName = "r.WeaponDebugDamageInfo"; FString UCloud9DeveloperSettings::VolumeName = "r.Volume"; // ReSharper disable once CppPossiblyUninitializedMember @@ -70,6 +71,7 @@ UCloud9DeveloperSettings::UCloud9DeveloperSettings(const FObjectInitializer& Obj WeaponDebugMaxInaccuracy = 0; WeaponDebugInaccuracyOnlyUp = 0; WeaponRecoilDecayCoefficient = 2.0f; + WeaponDebugDamageInfo = 0; DrawShotDirectionAxis = 0; } @@ -236,6 +238,12 @@ void UCloud9DeveloperSettings::InitializeCVars() TEXT("Draw debug orthonormal axis of shot direction") ); + RegisterConsoleVariable( + WeaponDebugDamageInfo, + *WeaponDebugDamageInfoName, + TEXT("Pring debug info about damage to character on hit") + ); + log(Display, "%s", this | EUObject::Stringify{} | EFString::ToCStr{}); } } diff --git a/Source/Cloud9/Game/Cloud9DeveloperSettings.h b/Source/Cloud9/Game/Cloud9DeveloperSettings.h index a0efa9385..ff00f0f2a 100644 --- a/Source/Cloud9/Game/Cloud9DeveloperSettings.h +++ b/Source/Cloud9/Game/Cloud9DeveloperSettings.h @@ -76,6 +76,7 @@ class CLOUD9_API UCloud9DeveloperSettings : public UDeveloperSettings static FString WeaponDebugInaccuracyOnlyUpName; static FString WeaponRecoilDecayCoefficientName; static FString DrawShotDirectionAxisName; + static FString WeaponDebugDamageInfoName; static FString VolumeName; public: // properties @@ -139,6 +140,9 @@ class CLOUD9_API UCloud9DeveloperSettings : public UDeveloperSettings UPROPERTY(config, EditAnywhere, BlueprintReadWrite, Category=Debug) int32 DrawShotDirectionAxis; + UPROPERTY(config, EditAnywhere, BlueprintReadWrite, Category=Debug) + int32 WeaponDebugDamageInfo; + UPROPERTY(config, EditAnywhere, BlueprintReadWrite, Category=Debug) EUnUsedEnum UnUsedEnum; diff --git a/Source/Cloud9/Tools/Extensions/FRotator.h b/Source/Cloud9/Tools/Extensions/FRotator.h new file mode 100644 index 000000000..30ee9118d --- /dev/null +++ b/Source/Cloud9/Tools/Extensions/FRotator.h @@ -0,0 +1,60 @@ +// 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 "Cloud9/Tools/Macro/Operator.h" +#include "Cloud9/Tools/Macro/Common.h" +#include "Cloud9/Tools/Concepts.h" + +namespace EFVector +{ + struct Normalize + { + template requires Concepts::convertiable + FORCEINLINE FVector operator()(SelfType&& Self) const + { + FVector Normalized = Self; + Normalized.Normalize(); + return Normalized; + } + + OPERATOR_BODY(Normalize) + }; + + FVector VInterpTo( + const FVector Current, + const FVector Target, + float DeltaTime, + const FVector InterpSpeed); + + inline FVector Random(FVector Min, FVector Max, FVector Grid) + { + let Vector = FMath::RandPointInBox({Min, Max}); + return { + FMath::GridSnap(Vector.X, Grid.X), + FMath::GridSnap(Vector.Y, Grid.Y), + FMath::GridSnap(Vector.Z, Grid.Z), + }; + } +} diff --git a/Source/Cloud9/Tools/Extensions/FVector.cpp b/Source/Cloud9/Tools/Extensions/FVector.cpp new file mode 100644 index 000000000..9d95d6bbe --- /dev/null +++ b/Source/Cloud9/Tools/Extensions/FVector.cpp @@ -0,0 +1,83 @@ +// 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 "Cloud9/Tools/Macro/Operator.h" +#include "Cloud9/Tools/Macro/Common.h" +#include "Cloud9/Tools/Concepts.h" + +namespace EFVector +{ + struct Normalize + { + template requires Concepts::convertiable + FORCEINLINE FVector operator()(SelfType&& Self) const + { + FVector Normalized = Self; + Normalized.Normalize(); + return Normalized; + } + + OPERATOR_BODY(Normalize) + }; + + FVector VInterpTo( + const FVector Current, + const FVector Target, + float DeltaTime, + const FVector InterpSpeed) + { + let ClampLerp = [](auto Current, auto Dist, auto Alpha, auto Target) + { + return Alpha <= 0.0f ? Target : Current + Dist * FMath::Clamp(Alpha, 0.0f, 1.0f); + }; + + // Distance to reach + let Dist = Target - Current; + + // If distance is too small, just set the desired location + if (Dist.SizeSquared() < KINDA_SMALL_NUMBER) + { + return Target; + } + + let Alpha = DeltaTime * InterpSpeed; + + return { + ClampLerp(Current.X, Dist.X, Alpha.X, Target.X), + ClampLerp(Current.Y, Dist.Y, Alpha.Y, Target.Y), + ClampLerp(Current.Z, Dist.Z, Alpha.Z, Target.Z), + }; + } + + inline FVector Random(FVector Min, FVector Max, FVector Grid) + { + let Vector = FMath::RandPointInBox({Min, Max}); + return { + FMath::GridSnap(Vector.X, Grid.X), + FMath::GridSnap(Vector.Y, Grid.Y), + FMath::GridSnap(Vector.Z, Grid.Z), + }; + } +} diff --git a/Source/Cloud9/Tools/Math.h b/Source/Cloud9/Tools/Math.h new file mode 100644 index 000000000..1b02fe9d9 --- /dev/null +++ b/Source/Cloud9/Tools/Math.h @@ -0,0 +1,56 @@ +// 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 + +/** + * std abstraction because UE4 has self APIs to avoid mixin std and UE4 APIs + */ +namespace Concepts +{ + template + concept incrementable = requires(SelfType Self) + { + ++Self; + }; + + template + concept plusassingable = + incrementable + && requires(SelfType Self, OtherType Other) + { + Self += Other; + }; + + template + concept dereferencable = requires(SelfType Self) + { + { *Self } -> std::convertible_to; + }; + + template + concept convertiable = requires(SelfType Self) + { + { Self } -> std::convertible_to; + }; +}