HAxis sos

This commit is contained in:
guus
2018-08-11 16:46:35 +02:00
commit 510654f8a1
480 changed files with 54126 additions and 0 deletions

View File

@@ -0,0 +1,165 @@
// Project Lab - NHTV Igad
#include "UnrealProject.h"
#include "AbilityEventGroup.h"
#include "NetworkCharacter.h"
#include "NPCBase.h"
AAbilityEventGroup::AAbilityEventGroup()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
channelEvent = false;
stunWhileChannel = true;
progressionType = EAbilityEventGroupProgressionType::Continue;
duration = 1.0f;
m_endEventSend = false;
m_hasBeenDestroyed = false;
allowRotateWhileChannel = false;
}
void AAbilityEventGroup::BeginPlay()
{
check(Role == ROLE_Authority);
Super::BeginPlay();
m_life = 0.0f;
if(!character || character->IsActorBeingDestroyed())
{
m_MoveToNextGroup();
}
else
{
// Handle the destruction of the caster
character->OnDestroyed.AddDynamic(this, &AAbilityEventGroup::m_OnCharacterDestroyed);
}
}
void AAbilityEventGroup::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
check(Role == ROLE_Authority);
if(EndPlayReason == EEndPlayReason::Destroyed)
{
Super::EndPlay(EndPlayReason);
AAbilityEventGroup* nextGroup = nullptr;
if(m_nextGroups.Num() > 0)
{
//GWPRINT(L"Move next");
nextGroup = SpawnSequence(character, abilityInfo, abilityState, m_nextGroups);
}
m_SendEndEvent(nextGroup);
}
}
void AAbilityEventGroup::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
if(IsPendingKill())
return;
m_life += DeltaTime;
if(progressionType == EAbilityEventGroupProgressionType::Continue)
{
if(m_life >= duration || m_continue)
m_MoveToNextGroup();
}
else
{
if(m_continue)
m_MoveToNextGroup();
}
}
void AAbilityEventGroup::m_OnCharacterDestroyed()
{
m_MoveToNextGroup();
}
void AAbilityEventGroup::m_MoveToNextGroup()
{
if(m_hasBeenDestroyed)
return;
m_hasBeenDestroyed = true;
if(IsValid(this) && !IsPendingKillPending())
Destroy();
}
void AAbilityEventGroup::m_SendEndEvent(AAbilityEventGroup* next)
{
if(!m_endEventSend)
{
onAbilityEventGroupEnded.Broadcast(abilityInfo, this, next);
m_endEventSend = true;
}
}
void AAbilityEventGroup::Interrupt()
{
//GPRINT("Interrupting ability");
if(IsPendingKill())
return;
m_nextGroups.Empty(); // Don't execute any follow up events
m_hasBeenDestroyed = true;
}
void AAbilityEventGroup::TransitionTo(class AAbilityEventGroup* newGroup)
{
check(newGroup);
check(abilityInfo);
check(abilityState);
newGroup->character = character;
newGroup->abilityInfo = abilityInfo;
newGroup->abilityState = abilityState;
newGroup->m_nextGroups = m_nextGroups;
m_nextGroups.Empty();
m_SendEndEvent(newGroup);
//GWPRINT(L"TransitionTo next");
m_MoveToNextGroup();
}
void AAbilityEventGroup::NextGroup()
{
m_continue = true;
}
ANetworkCharacter* AAbilityEventGroup::GetTarget()
{
ANPCBase* creature = Cast<ANPCBase>(character);
if(creature)
{
return creature->target;
}
return nullptr;
}
float AAbilityEventGroup::GetLifetimeRate() const
{
float rate = m_life / duration;
return FMath::Fmod(rate, 1.0f + FLT_EPSILON);
}
float AAbilityEventGroup::GetLifetime() const
{
return m_life;
}
AAbilityEventGroup* AAbilityEventGroup::SpawnSequence(ANetworkCharacter* character, class UAbilityInfo* abilityInfo, class AAbilityState* abilityState, TArray<TSubclassOf<class AAbilityEventGroup>> groups)
{
UWorld* world = character->GetWorld();
check(world);
check(groups.Num() > 0);
AAbilityEventGroup* group = world->SpawnActorDeferred<AAbilityEventGroup>(groups[0], FTransform::Identity);
check(group);
check(abilityInfo);
check(abilityState);
group->character = character;
group->abilityState = abilityState;
group->abilityInfo = abilityInfo;
groups.RemoveAt(0);
group->m_nextGroups = groups;
UGameplayStatics::FinishSpawningActor(group, FTransform::Identity);
return group;
}

View File

@@ -0,0 +1,85 @@
// Project Lab - NHTV Igad
#pragma once
#include "DealDamageProxy.h"
#include "AbilityEventGroup.generated.h"
UENUM(BlueprintType)
enum class EAbilityEventGroupProgressionType : uint8
{
// Continues when the duration of the group has expired
Continue,
// Loops until the ability itself decides to continue, or is activated again
Loop
};
UCLASS()
class UNREALPROJECT_API AAbilityEventGroup : public ADealDamageProxy
{
GENERATED_BODY()
public:
AAbilityEventGroup();
virtual void BeginPlay() override final;
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason);
virtual void Tick(float DeltaSeconds) override final;
// Used to construct an ability group sequence from an array of ability groups
static AAbilityEventGroup* SpawnSequence(class ANetworkCharacter* character, class UAbilityInfo* abilityInfo, class AAbilityState* abilityState, TArray<TSubclassOf<class AAbilityEventGroup>> groups);
// Try to interrupt this group chain if it's a channelEvent
void Interrupt();
// Changes the current group to execute this group now
void TransitionTo(class AAbilityEventGroup* newGroup);
// Try to continue this group if it's progression type is not duration bound
UFUNCTION(BlueprintCallable, Category = "Ability")
void NextGroup();
// Value from 0 to 1 representing the life cycle of this event, loops back to 0 if the event is looping after the life exceeded the duration set in the group
UFUNCTION(BlueprintCallable, Category = "Ability Group")
float GetLifetimeRate() const;
UFUNCTION(BlueprintCallable, Category = "Ability Group")
float GetLifetime() const;
UFUNCTION(BlueprintCallable, Category = "Ability")
class ANetworkCharacter* GetTarget();
UPROPERTY(BlueprintReadOnly, Category = "Ability Group")
class AAbilityState* abilityState;
UPROPERTY(BlueprintReadOnly, EditDefaultsOnly, Category = "Ability Group")
float duration;
UPROPERTY(EditDefaultsOnly, Category = "Ability Group")
bool channelEvent;
UPROPERTY(EditDefaultsOnly, Category = "Ability Group")
bool stunWhileChannel;
UPROPERTY(EditDefaultsOnly, Category = "Ability Group")
bool allowRotateWhileChannel;
// Setting this to true makes the ability
UPROPERTY(EditDefaultsOnly, Category = "Ability Group")
EAbilityEventGroupProgressionType progressionType;
// Called when the group's duration has expired or NextGroup is called
DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(FOnAbilityEventGroupEnded, class UAbilityInfo*, ability, class AAbilityEventGroup*, current, class AAbilityEventGroup*, next);
FOnAbilityEventGroupEnded onAbilityEventGroupEnded;
private:
UFUNCTION()
void m_OnCharacterDestroyed();
void m_MoveToNextGroup();
void m_SendEndEvent(AAbilityEventGroup* next = nullptr);
float m_life;
UPROPERTY()
TArray<TSubclassOf<AAbilityEventGroup>> m_nextGroups;
bool m_hasBeenDestroyed;
bool m_endEventSend;
bool m_continue;
};

View File

@@ -0,0 +1,17 @@
// Project Lab - NHTV Igad
#pragma once
#include "AbilityFilter.generated.h"
#define ABILITY_FILTER_ENEMY 0x1
#define ABILITY_FILTER_ALLY 0x2
#define ABILITY_FILTER_SELF 0x10
UENUM(BlueprintType)
enum class EAbilityFilter : uint8
{
EnemyAll = 0x1,
AllyAll = 0x2,
All = 0x3,
Self = 0x10,
};

View File

@@ -0,0 +1,56 @@
// Project Lab - NHTV Igad
#include "UnrealProject.h"
#include "AbilityInfo.h"
#include "AbilityState.h"
namespace
{
inline uint32 Hash32(const void* data, uint32 length)
{
const uint32 offset = 2166136261U;
const uint32 prime = 16777619U;
const unsigned char* data_bytes = (const unsigned char*)data;
uint32 value = offset;
for (uint32 next = 0; next < length; ++next)
{
value ^= (uint32)data_bytes[next];
value *= prime;
}
return value;
}
}
UAbilityInfo::UAbilityInfo()
{
name = L"<Designers!: Add Name>";
description = L"<Designers!: Add Description>";
cooldown = 1.0f;
AICastRange = 0.0f;
rotateTowardsPlayer = false;
abilityState = AAbilityState::StaticClass();
FString strName = GetPathName();
m_hash = Hash32(strName.GetCharArray().GetData(), strName.Len() * sizeof(wchar_t));
}
uint32 UAbilityInfo::GetStaticHash() const
{
return m_hash;
}
void AAbilityState::NativeSetCooldown()
{
SetCooldown();
cooldownRate = (currentCooldownDuration > 0.0f) ? (onCooldownTimer / currentCooldownDuration) : 0.0f;
}
void AAbilityState::SetCooldown_Implementation()
{
currentCooldownDuration = info->cooldown;
onCooldownTimer = currentCooldownDuration;
}
bool AAbilityState::IsMaxed() const
{
return power >= 1.0f;
}

View File

@@ -0,0 +1,96 @@
// Project Lab - NHTV Igad
#pragma once
#include "Engine/DataAsset.h"
#include "Items/ItemBase.h"
#include "AbilityInfo.generated.h"
UENUM(BlueprintType)
enum class EAbilityCategory : uint8
{
Unassigned = 0,
Ranged,
Melee
};
UENUM(BlueprintType)
enum class EAbilityType : uint8
{
Basic,
Ability
};
UENUM(BlueprintType)
enum class EAbilityActionType : uint8
{
Normal,
Toggle,
Hold
};
USTRUCT()
struct FAbilityItem
{
GENERATED_BODY()
UPROPERTY(EditAnywhere)
USkeletalMesh* mesh;
UPROPERTY(EditAnywhere)
EItemTypeEnum type;
};
UCLASS(BlueprintType)
class UNREALPROJECT_API UAbilityInfo : public UDataAsset
{
GENERATED_BODY()
public:
UAbilityInfo();
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Ability")
FString name;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Ability")
FString description;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Ability")
float cooldown;
UPROPERTY(EditDefaultsOnly)
TArray<TSubclassOf<class AAbilityEventGroup>> events;
UPROPERTY(EditDefaultsOnly)
TSubclassOf<class APreCastAbilityEventGroup> precastEvent;
UPROPERTY(EditDefaultsOnly)
TSubclassOf<class AAbilityState> abilityState;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Ability")
UTexture2D* icon;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Ability")
float AICastRange;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Ability")
bool passive;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Ability")
bool rotateTowardsPlayer;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Ability")
int32 mana;
// The action type of the ability, Toggle, Hold or Normal
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Ability")
EAbilityActionType actionType;
// The type of the ability Ability(On AbilityBar) or Basic(Left Mouse Click).
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Ability")
EAbilityType abilityType;
// If the ability is Ranged or Melee
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Ability")
EAbilityCategory abilityCategory;
UPROPERTY(EditAnywhere)
bool isVisible;
UPROPERTY(EditAnywhere, meta = (EditCondition = "isVisible"))
TArray<FAbilityItem> itemsToEquip;
bool IsHoldOrToggle() const
{
return actionType == EAbilityActionType::Hold || actionType == EAbilityActionType::Toggle;
}
uint32 GetStaticHash() const;
private:
uint32 m_hash;
};

View File

@@ -0,0 +1,37 @@
// Project Lab - NHTV Igad
#pragma once
#include "AbilityState.generated.h"
UCLASS()
class AAbilityState : public AActor
{
GENERATED_BODY()
public:
// Sets the ability to be on cooldown
virtual void NativeSetCooldown();
UFUNCTION(BlueprintNativeEvent, Category = "Ability State")
void SetCooldown();
UFUNCTION(BlueprintCallable, Category = "Ability State")
bool IsMaxed() const;
// Total duration of cooldown
UPROPERTY(BlueprintReadWrite)
float currentCooldownDuration;
// Current state of cooldown going from max->0
UPROPERTY(BlueprintReadWrite)
float onCooldownTimer;
// Current state of cooldown going from 1->0
UPROPERTY(BlueprintReadOnly)
float cooldownRate;
UPROPERTY(BlueprintReadOnly)
float power;
UPROPERTY(BlueprintReadOnly)
bool toggleState;
UPROPERTY(BlueprintReadOnly)
class UAbilityInfo* info;
};

View File

@@ -0,0 +1,221 @@
// Project Lab - NHTV Igad
#include "UnrealProject.h"
#include "NetworkCharacter.h"
#include "AbilityTriggerBase.h"
#include "BlueprintAbilityLibrary.h"
AAbilityTriggerBase::AAbilityTriggerBase()
{
PrimaryActorTick.bCanEverTick = true;
filter = EAbilityFilter::EnemyAll;
autoDestroy = true;
bReplicateMovement = true;
bReplicates = true;
duration = 1.0f;
ticksPerSecond = 0.0f;
m_lifeTime = 0.0f;
}
void AAbilityTriggerBase::BeginPlay()
{
if (Role == ROLE_Authority)
{
if (!character)
{
GWERROR(L"No owner assigned to trigger " + GetName());
this->SetActorEnableCollision(false);
Destroy();
}
if (ticksPerSecond > 0)
{
m_tickTime = 1.0f / ticksPerSecond;
}
else
{
m_tickTime = 0.0f;
}
}
//make sure the collision delegates are working
UShapeComponent* root = Cast<UShapeComponent>(RootComponent);
if (root != nullptr && !delegatesSet)
{
root->OnComponentBeginOverlap.AddDynamic(this, &AAbilityTriggerBase::OnOverlapBegin);
root->OnComponentEndOverlap.AddDynamic(this, &AAbilityTriggerBase::OnOverlapEnd);
delegatesSet = true;
}
else
FWARNING("rootComponent is not a UShapeComponent");
Super::BeginPlay();
if (Role == ROLE_Authority)
UpdateOverlaps();
}
void AAbilityTriggerBase::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
if (Role == ROLE_Authority)
{
while (m_actorsInside.Num()>0)
{
if (IsValid(m_actorsInside.GetData()[0]))
{
LeaveEvent(Cast<ANetworkCharacter>(m_actorsInside.GetData()[0]));
}
}
}
Super::EndPlay(EndPlayReason);
}
void AAbilityTriggerBase::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
DOREPLIFETIME_CONDITION(AAbilityTriggerBase, duration, COND_InitialOnly);
}
void AAbilityTriggerBase::Tick(float DeltaTime)
{
m_lifeTime += DeltaTime;
Super::Tick(DeltaTime);
if(Role != ROLE_Authority || !IsValid(this))
return;
UpdateOverlaps();
if(autoDestroy && m_lifeTime >= duration)
{
Destroy();
return;
}
if(m_tickTime > 0)
{
m_tickTimer += DeltaTime;
while(m_tickTimer > m_tickTime)
{
m_tickTimer -= m_tickTime;
for(AActor* actorInside : m_actorsInside)
{
if (CollisionCheck(Cast<ANetworkCharacter>(actorInside)))
{
OnTriggerTick(Cast<ANetworkCharacter>(actorInside));
NativeOnLocalTriggerTick(Cast<ANetworkCharacter>(actorInside));
}
}
}
}
}
void AAbilityTriggerBase::OnOverlapBegin(class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
if(Role != ROLE_Authority)
return;
if(OtherActor == NULL)
{
FWPRINT(L"Error - wrong otherunit on OnOverlapBegin ");
return;
}
if(character == NULL)
{
FWPRINT(L"Error - m_character NULL on OnOverlapBegin ");
return;
}
ANetworkCharacter* otherUnit = Cast<ANetworkCharacter>(OtherActor);
if(!otherUnit->GetHitable())
return;
if(!ULib::CheckAbilityFilter(filter, character, otherUnit))
return;
if(hitOnce && m_CheckActorsHit(otherUnit))
return;
m_actorsInside.Add(OtherActor);
if (CollisionCheck(Cast<ANetworkCharacter>(OtherActor)))
{
HitEvent(otherUnit);
}
}
void AAbilityTriggerBase::OnOverlapEnd(class AActor * OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex)
{
if(Role == ROLE_Authority)
LeaveEvent(Cast<ANetworkCharacter>(OtherActor));
}
void AAbilityTriggerBase::HitEvent(class ANetworkCharacter* otherUnit)
{
if (hitOnce)
m_actorsHit.Add(otherUnit);
OnTriggerHit(otherUnit);
}
void AAbilityTriggerBase::LeaveEvent(class ANetworkCharacter* otherActor)
{
if (Role == ROLE_Authority)
{
for (auto it = (m_actorsInside.CreateIterator()); it; it++)
{
if (*it == otherActor)
{
m_actorsInside.Remove(otherActor);
break;
}
}
if (!ULib::CheckAbilityFilter(filter, character, otherActor))
return;
OnTriggerLeave(otherActor);
}
}
float AAbilityTriggerBase::GetLifeTime() const
{
return m_lifeTime;
}
float AAbilityTriggerBase::GetLifeTimeRate() const
{
return FMath::Clamp(m_lifeTime / duration, 0.0f, 1.0f);
}
bool AAbilityTriggerBase::m_CheckActorsHit(class ANetworkCharacter* otherUnit)
{
for (ANetworkCharacter* character : m_actorsHit)
{
if (character == otherUnit)
return true;
}
return false;
}
bool AAbilityTriggerBase::CollisionCheck(ANetworkCharacter* otheractor)
{
return IsValid(otheractor);
}
void AAbilityTriggerBase::OnTriggerHit_Implementation(ANetworkCharacter* actor)
{
}
void AAbilityTriggerBase::OnTriggerTick_Implementation(ANetworkCharacter* actor)
{
}
void AAbilityTriggerBase::OnTriggerLeave_Implementation(ANetworkCharacter* actor)
{
}
void AAbilityTriggerBase::OnLocalTriggerTick_Implementation(ANetworkCharacter* actor)
{
}
void AAbilityTriggerBase::NativeOnLocalTriggerTick_Implementation(ANetworkCharacter* actor)
{
OnLocalTriggerTick(actor);
}

View File

@@ -0,0 +1,71 @@
// Project Lab - NHTV Igad
#pragma once
#include "DealDamageProxy.h"
#include "AbilityFilter.h"
#include "AbilityTriggerBase.generated.h"
UCLASS()
class UNREALPROJECT_API AAbilityTriggerBase : public ADealDamageProxy
{
GENERATED_BODY()
public:
AAbilityTriggerBase();
virtual void BeginPlay() override;
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
virtual void Tick( float DeltaSeconds ) override;
virtual bool CollisionCheck(ANetworkCharacter* otheractor);
UFUNCTION()
void OnOverlapBegin(class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult);
UFUNCTION()
void OnOverlapEnd(class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex);
virtual void HitEvent(class ANetworkCharacter* otherActor);
virtual void LeaveEvent(class ANetworkCharacter* otherActor);
UFUNCTION(BlueprintCallable, Category="Ability")
float GetLifeTime() const;
UFUNCTION(BlueprintCallable, Category="Ability")
float GetLifeTimeRate() const;
UPROPERTY(BlueprintReadWrite, Replicated, Category = "Ability", meta = (ExposeOnSpawn))
float duration;
UPROPERTY(BlueprintReadWrite, Category = "Ability", meta = (ExposeOnSpawn))
bool hitOnce;
UPROPERTY(BlueprintReadWrite, meta = (ExposeOnSpawn))
EAbilityFilter filter;
UFUNCTION(BlueprintNativeEvent)
void OnTriggerHit(ANetworkCharacter* actor);
UFUNCTION(BlueprintNativeEvent)
void OnTriggerTick(ANetworkCharacter* actor);
UFUNCTION(BlueprintCallable, NetMulticast, Reliable, Category = "trigger")
void NativeOnLocalTriggerTick(ANetworkCharacter* actor);
UFUNCTION(BlueprintNativeEvent)
void OnLocalTriggerTick(ANetworkCharacter* actor);
UFUNCTION(BlueprintNativeEvent)
void OnTriggerLeave(ANetworkCharacter* actor);
UPROPERTY(BlueprintReadWrite, VisibleAnywhere, Category = "Ability", meta = (ExposeOnSpawn))
bool autoDestroy;
UPROPERTY(BlueprintReadOnly, VisibleAnywhere, Category = "Ability", meta = (ExposeOnSpawn))
float ticksPerSecond;
bool m_CheckActorsHit(class ANetworkCharacter* otherUnit);
protected:
TArray<AActor*> m_actorsInside;
TArray<ANetworkCharacter*> m_actorsHit;
float m_tickTime;
float m_lifeTime;
float m_tickTimer;
bool delegatesSet = false;
};

View File

@@ -0,0 +1,31 @@
// Project Lab - NHTV Igad
#include "UnrealProject.h"
#include "Modifier.h"
#include "NetworkCharacter.h"
#include "AuraTrigger.h"
AModifier* AAuraTrigger::GetModifier(class ANetworkCharacter* targetCharacter)
{
auto it = data.Find(targetCharacter);
if (it==nullptr)
return nullptr;
return *it;
}
void AAuraTrigger::SetModifier(class ANetworkCharacter* targetCharacter, AModifier* modifier)
{
data.Add(targetCharacter, modifier);
}
void AAuraTrigger::Tick(float DeltaSeconds)
{
Super::Tick(DeltaSeconds);
if (Role == ROLE_Authority && IsValid(followObject))
{
SetActorLocation(followObject->GetActorLocation());
}
}

View File

@@ -0,0 +1,26 @@
// Project Lab - NHTV Igad
#pragma once
#include "Abilities/ConeTrigger.h"
#include "AuraTrigger.generated.h"
/**
*
*/
UCLASS()
class UNREALPROJECT_API AAuraTrigger : public AConeTrigger
{
GENERATED_BODY()
public:
virtual void Tick(float DeltaSeconds) override;
UFUNCTION(BlueprintCallable, category = "Trigger")
class AModifier* GetModifier(class ANetworkCharacter* targetCharacter);
UFUNCTION(BlueprintCallable, category = "Trigger")
void SetModifier(class ANetworkCharacter* targetCharacter, AModifier* modifier);
UPROPERTY()
TMap<class ANetworkCharacter*, class AModifier*> data;
UPROPERTY(BlueprintReadWrite, Category = "Ability", meta = (ExposeOnSpawn))
AActor* followObject;
};

View File

@@ -0,0 +1,326 @@
#include "UnrealProject.h"
#include "BlueprintAbilityLibrary.h"
#include "DealDamageProxy.h"
#include "AbilityEventGroup.h"
#include "AbilityTriggerBase.h"
#include "Modifier.h"
#include "NetworkCharacter.h"
#include "ProjectileBase.h"
#include "Class.h"
ULib::ULib(const FObjectInitializer& init)
: Super(init)
{
}
AActor* ULib::BeginSpawning2(UObject* WorldContextObject, TSubclassOf<AActor> ActorClass)
{
return UGameplayStatics::BeginDeferredActorSpawnFromClass(WorldContextObject, ActorClass, FTransform());
}
AActor* ULib::FinishSpawning2(class AActor* Actor)
{
if(!Actor)
return nullptr;
return UGameplayStatics::FinishSpawningActor(Actor, FTransform());
}
AActor* ULib::BeginSpawningGroup(UObject* WorldContextObject, TSubclassOf<AActor> ActorClass)
{
if(!WorldContextObject->GetWorld()->GetAuthGameMode())
return nullptr;
AActor* actor = UGameplayStatics::BeginDeferredActorSpawnFromClass(WorldContextObject, ActorClass, FTransform());
if(!actor)
return nullptr;
AAbilityEventGroup* newGroup = Cast<AAbilityEventGroup>(actor);
check(newGroup);
AAbilityEventGroup* parent = Cast<AAbilityEventGroup>(WorldContextObject);
//GWPRINT(L"Parent = " + parent);
if(!parent)
{
GWERROR(L"Cannot call FinishSpawningGroup from any other source than AAbilityEventGroup");
newGroup->Destroy();
return nullptr;
}
parent->TransitionTo(newGroup);
return newGroup;
}
AActor* ULib::FinishSpawningGroup(class AActor* Actor)
{
if(!Actor)
return nullptr;
return FinishSpawning2(Actor);
}
AActor* ULib::BeginSpawningModifier(UObject* WorldContextObject, TSubclassOf<AActor> ActorClass)
{
if(!WorldContextObject->GetWorld()->GetAuthGameMode())
return nullptr;
AActor* actor = UGameplayStatics::BeginDeferredActorSpawnFromClass(WorldContextObject, ActorClass, FTransform());
if(!actor)
return nullptr;
AModifier* newModifier = Cast<AModifier>(actor);
check(newModifier);
ADealDamageProxy* damageProxy = Cast<ADealDamageProxy>(WorldContextObject);
if(damageProxy)
{
newModifier->character = damageProxy->character;
newModifier->abilityInfo = damageProxy->abilityInfo;
}
else
{
GWERROR(L"Cannot spawn modifier from a source that is not a ADealDamageProxy");
newModifier->Destroy();
return nullptr;
}
return newModifier;
}
AActor* ULib::FinishSpawningModifier(class AActor* Actor, class ANetworkCharacter* target)
{
if(!IsValid(Actor))
return nullptr;
AModifier* mod = Cast<AModifier>(Actor);
if(!IsValid(target))
{
FString name = "<none>";
if(mod->abilityInfo)
name = mod->abilityInfo->GetName();
GWERROR(L"Modifier needs a target (spawned by " + name + L")");
Actor->Destroy();
return nullptr;
}
//GWPRINT(L"Modifier Target = " + target);
ModifierManager* mm = target->GetModifierManager();
if(!mm)
{
GWWARNING(L"Can't spawn modifier on a target that doesn't have a modifier manager. Might be in the process of destroying");
Actor->Destroy();
return nullptr;
}
mod->target = target;
check(mod);
mm->AddModifier(mod);
return FinishSpawning2(Actor);
}
AActor* ULib::BeginSpawningTrigger(UObject* WorldContextObject, TSubclassOf<AActor> ActorClass, const FTransform& SpawnTransform)
{
if(!WorldContextObject->GetWorld()->GetAuthGameMode())
return nullptr;
AActor* actor = UGameplayStatics::BeginDeferredActorSpawnFromClass(WorldContextObject, ActorClass, SpawnTransform);
if(!actor)
return nullptr;
AAbilityTriggerBase* newTrigger = Cast<AAbilityTriggerBase>(actor);
check(newTrigger);
ADealDamageProxy* damageProxy = Cast<ADealDamageProxy>(WorldContextObject);
if(damageProxy)
{
newTrigger->character = damageProxy->character;
newTrigger->abilityInfo = damageProxy->abilityInfo;
}
else
{
GWERROR(L"Cannot spawn trigger from a source that is not a ADealDamageProxy");
actor->Destroy();
return nullptr;
}
return newTrigger;
}
AActor* ULib::FinishSpawningTrigger(class AActor* Actor, const FTransform & SpawnTransform)
{
if(!Actor)
return nullptr;
return UGameplayStatics::FinishSpawningActor(Actor, SpawnTransform);
}
AActor* ULib::BeginSpawningProjectile(UObject* WorldContextObject, TSubclassOf<AActor> ActorClass, const FTransform& SpawnTransform)
{
if(!WorldContextObject->GetWorld()->GetAuthGameMode())
return nullptr;
AActor* actor = UGameplayStatics::BeginDeferredActorSpawnFromClass(WorldContextObject, ActorClass, SpawnTransform);
if(!actor)
return nullptr;
AProjectileBase* newProjectile = Cast<AProjectileBase>(actor);
check(newProjectile);
ADealDamageProxy* damageProxy = Cast<ADealDamageProxy>(WorldContextObject);
if(damageProxy)
{
newProjectile->character = damageProxy->character;
newProjectile->abilityInfo = damageProxy->abilityInfo;
}
else
{
GWERROR(L"Cannot spawn projectile from a source that is not a ADealDamageProxy");
actor->Destroy();
return nullptr;
}
return newProjectile;
}
AActor* ULib::FinishSpawningProjectile(class AActor* Actor, const FTransform& SpawnTransform)
{
return UGameplayStatics::FinishSpawningActor(Actor, SpawnTransform);
}
bool ULib::IsContainedInCone(FVector origin, FVector forward, float coneAngle, AActor* other)
{
if(other->IsPendingKillPending())
return false;
//always hits at 360 degrees
if(coneAngle >= 360.0f)
return true;
FVector dist = other->GetActorLocation() - origin;
dist.Normalize();
forward.Normalize();
float dot = FVector::DotProduct(dist, forward);
float angle = acosf(dot);
float tempMaxAngle = coneAngle / 360;
tempMaxAngle *= PI;
bool ret = tempMaxAngle > angle;
return ret;
}
int32 ULib::CharacterConeOverlap(UObject* WorldContextObject, FVector origin, float coneRadius,
FCharacterConeOverlapCallback callback, FVector forward, float coneAngle, EAbilityFilter filter)
{
UWorld* world = GEngine->GetWorldFromContextObject(WorldContextObject);
check(world);
if(world->GetAuthGameMode() == nullptr)
return 0;
m_overlapResultArray.Empty();
// Get the character
ANetworkCharacter* character = Cast<ANetworkCharacter>(WorldContextObject);
if(!character)
{
ADealDamageProxy* proxy = Cast<ADealDamageProxy>(WorldContextObject);
if(!proxy)
{
GWERROR(L"CharacterConeOverlap failed, no caller character or proxy");
return 0;
}
character = proxy->character;
}
FCollisionShape shape;
shape.SetCapsule(coneRadius, 400.0f);
TArray<FOverlapResult> overlaps;
if(!world->OverlapMultiByObjectType(
overlaps, origin, FQuat::Identity,
FCollisionObjectQueryParams::AllDynamicObjects, shape,
FCollisionQueryParams::DefaultQueryParam))
{
return 0;
}
TArray<class ANetworkCharacter*> test;
if(callback.IsBound())
{
for(int32 i = 0; i < overlaps.Num(); i++)
{
FOverlapResult& overlap = overlaps[i];
ANetworkCharacter* target = Cast<ANetworkCharacter>(overlap.GetActor());
if (target && (overlap.Component->GetCollisionProfileName() == FName("Units") || overlap.Component->GetCollisionProfileName() == FName("Players")) &&
IsContainedInCone(origin, forward, coneAngle, target) &&
ULib::CheckAbilityFilter(filter, character, target))
{
callback.Execute(target);
m_overlapResultArray.Add(target);
}
}
}
// = test;
return overlaps.Num();
}
int32 ULib::ClosestCharacterConeOverlap(UObject* WorldContextObject, FVector origin, float coneRadius,
FClosestCharacterConeOverlapCallback callback, FVector forward, float coneAngle, EAbilityFilter filter)
{
UWorld* world = GEngine->GetWorldFromContextObject(WorldContextObject);
check(world);
if (world->GetAuthGameMode() == nullptr)
return 0;
// Get the character
ANetworkCharacter* character = Cast<ANetworkCharacter>(WorldContextObject);
if (!character)
{
ADealDamageProxy* proxy = Cast<ADealDamageProxy>(WorldContextObject);
if (!proxy)
{
GWERROR(L"CharacterConeOverlap failed, no caller character or proxy");
return 0;
}
character = proxy->character;
}
FCollisionShape shape;
shape.SetCapsule(coneRadius, 400.0f);
TArray<FOverlapResult> overlaps;
if (!world->OverlapMultiByObjectType(
overlaps, origin, FQuat::Identity,
FCollisionObjectQueryParams::AllDynamicObjects, shape,
FCollisionQueryParams::DefaultQueryParam))
{
return 0;
}
ANetworkCharacter* closest = nullptr;
float dist = 9999999999999.0f;
if (callback.IsBound())
{
for (int32 i = 0; i < overlaps.Num(); i++)
{
FOverlapResult& overlap = overlaps[i];
ANetworkCharacter* target = Cast<ANetworkCharacter>(overlap.GetActor());
if (target && IsContainedInCone(origin, forward, coneAngle, target) && ULib::CheckAbilityFilter(filter, character, target))
{
if ((target->GetActorLocation() - origin).Size() < dist)
{
closest = target;
dist = (target->GetActorLocation() - origin).Size();
}
}
}
}
if(closest)
callback.Execute(closest);
return overlaps.Num();
}
TArray<ANetworkCharacter*> ULib::m_overlapResultArray;
bool ULib::CheckAbilityFilter(EAbilityFilter filter, class ANetworkCharacter* self, class ANetworkCharacter* other)
{
if(!self)
return false;
if(!other)
return false;
if(((uint8)filter & ABILITY_FILTER_ENEMY) != 0)
{
if(self->GetTeam() != other->GetTeam())
return true;
}
if(((uint8)filter & ABILITY_FILTER_ALLY) != 0)
{
if(self->GetTeam() == other->GetTeam())
return true;
}
return false;
}
TArray<ANetworkCharacter*>ULib::GetCharacterOverlaps()
{
TArray<ANetworkCharacter*> returnArray;
for (ANetworkCharacter* character : m_overlapResultArray)
{
if(IsValid(character))
returnArray.Add(character);
}
return returnArray;
}

View File

@@ -0,0 +1,59 @@
#pragma once
#include "Kismet/BlueprintFunctionLibrary.h"
#include "AbilityFilter.h"
#include "BlueprintAbilityLibrary.Generated.h"
UCLASS()
class ULib : public UBlueprintFunctionLibrary
{
GENERATED_UCLASS_BODY()
public:
UFUNCTION(BlueprintCallable, Category = "Spawning", meta = (WorldContext = "WorldContextObject", UnsafeDuringActorConstruction = "true", BlueprintInternalUseOnly = "true"))
static AActor* BeginSpawning2(UObject* WorldContextObject, TSubclassOf<AActor> ActorClass);
UFUNCTION(BlueprintCallable, Category = "Spawning", meta = (UnsafeDuringActorConstruction = "true", BlueprintInternalUseOnly = "true"))
static AActor* FinishSpawning2(class AActor* Actor);
UFUNCTION(BlueprintCallable, Category = "Spawning", meta = (WorldContext = "WorldContextObject", UnsafeDuringActorConstruction = "true", BlueprintInternalUseOnly = "true"))
static AActor* BeginSpawningGroup(UObject* WorldContextObject, TSubclassOf<AActor> ActorClass);
UFUNCTION(BlueprintCallable, Category = "Spawning", meta = (UnsafeDuringActorConstruction = "true", BlueprintInternalUseOnly = "true"))
static AActor* FinishSpawningGroup(class AActor* Actor);
UFUNCTION(BlueprintCallable, Category = "Spawning", meta = (WorldContext = "WorldContextObject", UnsafeDuringActorConstruction = "true", BlueprintInternalUseOnly = "true"))
static AActor* BeginSpawningModifier(UObject* WorldContextObject, TSubclassOf<AActor> ActorClass);
UFUNCTION(BlueprintCallable, Category = "Spawning", meta = (UnsafeDuringActorConstruction = "true", BlueprintInternalUseOnly = "true"))
static AActor* FinishSpawningModifier(class AActor* Actor, class ANetworkCharacter* Target);
UFUNCTION(BlueprintCallable, Category = "Spawning", meta = (WorldContext = "WorldContextObject", UnsafeDuringActorConstruction = "true", BlueprintInternalUseOnly = "true"))
static AActor* BeginSpawningTrigger(UObject* WorldContextObject, TSubclassOf<AActor> ActorClass, const FTransform& SpawnTransform);
UFUNCTION(BlueprintCallable, Category = "Spawning", meta = (UnsafeDuringActorConstruction = "true", BlueprintInternalUseOnly = "true"))
static AActor* FinishSpawningTrigger(class AActor* Actor, const FTransform& SpawnTransform);
UFUNCTION(BlueprintCallable, Category = "Spawning", meta = (WorldContext = "WorldContextObject", UnsafeDuringActorConstruction = "true", BlueprintInternalUseOnly = "true"))
static AActor* BeginSpawningProjectile(UObject* WorldContextObject, TSubclassOf<AActor> ActorClass, const FTransform& SpawnTransform);
UFUNCTION(BlueprintCallable, Category = "Spawning", meta = (UnsafeDuringActorConstruction = "true", BlueprintInternalUseOnly = "true"))
static AActor* FinishSpawningProjectile(class AActor* Actor, const FTransform& SpawnTransform);
UFUNCTION(BlueprintCallable, Category = "Trigger")
static bool IsContainedInCone(FVector origin, FVector forward, float coneAngle, AActor* other);
DECLARE_DYNAMIC_DELEGATE_OneParam(FCharacterConeOverlapCallback, class ANetworkCharacter*, character);
UFUNCTION(BlueprintCallable, Category = "Trigger", meta = (WorldContext = "WorldContextObject"))
static int32 CharacterConeOverlap(UObject* WorldContextObject, FVector origin, float coneRadius,
FCharacterConeOverlapCallback callback, FVector forward = FVector(1, 0, 0), float coneAngle = 360.0f, EAbilityFilter filter = EAbilityFilter::EnemyAll);
UFUNCTION(BlueprintCallable, Category = "Trigger", meta = (WorldContext = "WorldContextObject"))
static TArray<class ANetworkCharacter*> GetCharacterOverlaps();
DECLARE_DYNAMIC_DELEGATE_OneParam(FClosestCharacterConeOverlapCallback, class ANetworkCharacter*, character);
UFUNCTION(BlueprintCallable, Category = "Trigger", meta = (WorldContext = "WorldContextObject"))
static int32 ClosestCharacterConeOverlap(UObject* WorldContextObject, FVector origin, float coneRadius,
FClosestCharacterConeOverlapCallback callback, FVector forward = FVector(1, 0, 0), float coneAngle = 360.0f, EAbilityFilter filter = EAbilityFilter::EnemyAll);
UFUNCTION(BlueprintCallable, Category = "Damage Proxy")
static bool CheckAbilityFilter(EAbilityFilter filter, class ANetworkCharacter* self, class ANetworkCharacter* other);
static TArray<class ANetworkCharacter*> m_overlapResultArray;
private:
};

View File

@@ -0,0 +1,58 @@
// Project Lab - NHTV Igad
#include "UnrealProject.h"
#include "BombProjectile.h"
#include "NetworkCharacter.h"
#include "Effect.h"
#include "EffectFunctionLibrary.h"
#include "BlueprintAbilityLibrary.h"
ABombProjectile::ABombProjectile()
{
PrimaryActorTick.bCanEverTick = true;
m_progress = 0.0f;
maxDistance = 100000.0f;
}
void ABombProjectile::BeginPlay()
{
Super::BeginPlay();
travelTime = travelTime < 0.01f ? 0.01f : travelTime;
float distance = FVector::Dist(source, target);
}
void ABombProjectile::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
DOREPLIFETIME_CONDITION(ABombProjectile, source, COND_InitialOnly);
DOREPLIFETIME_CONDITION(ABombProjectile, target, COND_InitialOnly);
DOREPLIFETIME_CONDITION(ABombProjectile, travelTime, COND_InitialOnly);
}
void ABombProjectile::NativeFixedProjectileTick(float DeltaTime)
{
if(travelTime <= 0 || m_finished)
return;
m_progress += DeltaTime;
if(m_progress >= travelTime)
m_progress = travelTime;
const float lerp = m_progress / travelTime;
const float sin = FMath::Sin(lerp * PI);
FVector newLocation = FMath::Lerp(source, target, lerp) + FVector(0, 0, sin * travelHeight);
SetActorLocation(newLocation, true);
float distToEnd = (target - newLocation).Size();
if(lerp >= 1.0f)
{
// Server only
Finish();
}
}

View File

@@ -0,0 +1,30 @@
// Project Lab - NHTV Igad
#pragma once
#include "ProjectileBase.h"
#include "BombProjectile.generated.h"
UCLASS()
class UNREALPROJECT_API ABombProjectile : public AProjectileBase
{
GENERATED_BODY()
public:
ABombProjectile();
virtual void BeginPlay() override;
UPROPERTY(BlueprintReadWrite, Replicated, Category = "BombProjectile", meta = (ExposeOnSpawn))
FVector source;
UPROPERTY(BlueprintReadWrite, Replicated, Category = "BombProjectile", meta = (ExposeOnSpawn))
FVector target;
UPROPERTY(BlueprintReadWrite, Replicated, Category = "BombProjectile", meta = (ExposeOnSpawn))
float travelTime;
UPROPERTY(BlueprintReadWrite, Replicated, Category = "BombProjectile", meta = (ExposeOnSpawn))
float travelHeight;
virtual void NativeFixedProjectileTick(float DeltaTime) override;
private:
float m_progress;
};

View File

@@ -0,0 +1,97 @@
// Project Lab - NHTV Igad
#include "UnrealProject.h"
#include "NPCBase.h"
#include "NetworkPlayer.h"
#include "BossBarageBunny.h"
ABossBarageBunny::ABossBarageBunny()
{
PrimaryActorTick.bCanEverTick = true;
bReplicates = true;
bReplicateMovement = true;
boss = nullptr;
BeamEmitter = CreateDefaultSubobject<UParticleSystemComponent>(TEXT("Visual"));
BeamEmitter->AttachTo(RootComponent);
m_lifeTime = 1;
}
void ABossBarageBunny::BeginPlay()
{
Super::BeginPlay();
SpawnDefaultController();
}
void ABossBarageBunny::Tick( float DeltaTime )
{
Super::Tick( DeltaTime );
// Update the line material
if (IsValid(boss))
{
BeamEmitter->SetBeamSourcePoint(0, GetActorLocation(), 0);
BeamEmitter->SetBeamTargetPoint(0, boss->GetActorLocation(), 0);
}
else
{
BeamEmitter->SetActive(false);
GetCharacterMovement()->MaxWalkSpeed = 0;
}
// Server only
if (Role != ROLE_Authority)
return;
m_lifeTime -= DeltaTime;
if (m_lifeTime <= 0)
{
Destroy();
return;
}
// Boss destroyed?
if (!IsValid(boss))
return;
UNavigationSystem* const nav = UNavigationSystem::GetCurrent(GetWorld());
if (!IsValid(nav)) return;
AController* const controller = GetController();
if (!IsValid(controller))
{
JERROR("BossBarageBase has no controller");
return;
}
ANPCBase* const asNPC = Cast<ANPCBase>(boss);
if (!IsValid(asNPC) || !IsValid(asNPC->target))
return;
nav->SimpleMoveToLocation(controller, asNPC->target->GetActorLocation());
}
void ABossBarageBunny::Setup(AActor* boss, float lifeTime)
{
this->boss = boss;
m_lifeTime = lifeTime;
}
void ABossBarageBunny::ClearBoss()
{
this->boss = nullptr;
}
void ABossBarageBunny::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
DOREPLIFETIME(ABossBarageBunny, boss);
}

View File

@@ -0,0 +1,36 @@
// Project Lab - NHTV Igad
#pragma once
#include "GameFramework/Actor.h"
#include "BossBarageBunny.generated.h"
UCLASS()
class UNREALPROJECT_API ABossBarageBunny : public ACharacter
{
GENERATED_BODY()
public:
ABossBarageBunny();
virtual void BeginPlay() override;
virtual void Tick( float DeltaSeconds ) override;
UPROPERTY(EditAnywhere, Category = "Bunny")
class UParticleSystemComponent* BeamEmitter;
UFUNCTION(BlueprintCallable, Category = "Bunny")
void Setup(class AActor* boss, float lifeTime);
UFUNCTION(BlueprintCallable, Category = "Bunny")
void ClearBoss();
UPROPERTY(Replicated)
class AActor* boss;
private:
float m_lifeTime;
};

View File

@@ -0,0 +1,43 @@
// Project Lab - NHTV Igad
#include "UnrealProject.h"
#include "BossTargetBunny.h"
ABossTargetBunny::ABossTargetBunny()
{
PrimaryActorTick.bCanEverTick = true;
bReplicates = true;
bReplicateMovement = true;
m_lifeTime = 0;
}
void ABossTargetBunny::BeginPlay()
{
Super::BeginPlay();
}
void ABossTargetBunny::Tick( float DeltaTime )
{
Super::Tick( DeltaTime );
// Server only
if (Role != ROLE_Authority)
return;
m_lifeTime -= DeltaTime;
if (m_lifeTime <= 0)
{
Destroy();
return;
}
}
void ABossTargetBunny::Setup(float lifeTime)
{
m_lifeTime = lifeTime;
}

View File

@@ -0,0 +1,26 @@
// Project Lab - NHTV Igad
#pragma once
#include "GameFramework/Actor.h"
#include "BossTargetBunny.generated.h"
UCLASS()
class UNREALPROJECT_API ABossTargetBunny : public AActor
{
GENERATED_BODY()
public:
ABossTargetBunny();
virtual void BeginPlay() override;
virtual void Tick( float DeltaSeconds ) override;
UFUNCTION(BlueprintCallable, Category = "Bunny")
void Setup(float lifeTime);
private:
float m_lifeTime;
};

View File

@@ -0,0 +1,110 @@
// Project Lab - NHTV Igad
#include "UnrealProject.h"
#include "ConeComponent.h"
#define CONEARCVERTEXCOUNT 50
// Sets default values for this component's properties
UConeComponent::UConeComponent(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer)
{
ShapeColor = FColor(223, 149, 157, 255);
bUseEditorCompositing = true;
}
void UConeComponent::BeginPlay()
{
UpdateCapsule();
Super::BeginPlay();
}
void UConeComponent::UpdateCapsule()
{
SetCapsuleSize(coneRadius, 400);
}
// Create sceneproxy to show the cone in the editor
FPrimitiveSceneProxy* UConeComponent::CreateSceneProxy()
{
class FDrawConeSceneProxy : public FPrimitiveSceneProxy
{
public:
const UConeComponent* component;
FDrawConeSceneProxy(const UConeComponent* InComponent)
: FPrimitiveSceneProxy(InComponent)
, bDrawOnlyIfSelected(InComponent->bDrawOnlyIfSelected)
, component(InComponent)
{
bWillEverBeLit = false;
}
virtual void GetDynamicMeshElements(const TArray<const FSceneView*>& Views, const FSceneViewFamily& ViewFamily, uint32 VisibilityMap, FMeshElementCollector& Collector) const
{
QUICK_SCOPE_CYCLE_COUNTER(STAT_GetDynamicMeshElements_DrawDynamicElements);
for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
{
if (VisibilityMap & (1 << ViewIndex))
{
const FSceneView* View = Views[ViewIndex];
const FLinearColor DrawCapsuleColor = GetViewSelectionColor(ShapeColor, *View, IsSelected(), IsHovered(), false, IsIndividuallySelected());
FPrimitiveDrawInterface* PDI = Collector.GetPDI(ViewIndex);
FTransform transform = component->GetComponentTransform();
FVector base = transform.GetLocation();
const float scale = 1.0f / 180.0f * PI;
float baseRot = (360.0f - transform.GetRotation().Euler().Z) * scale;
FVector scaleVec = transform.GetScale3D();
FVector forward = FVector(scaleVec.X, 0, 0);
FVector right = FVector(0, scaleVec.Y, 0);
float angle = (component->coneAngle) / 180.0f * PI;
FVector linePoints[CONEARCVERTEXCOUNT];
float anglestep = (angle) / (CONEARCVERTEXCOUNT-1);
float rot = baseRot - angle * 0.5f;
for (int i = 0; i < CONEARCVERTEXCOUNT;i++)
{
float f = cosf(rot);
float r = sinf(rot);
linePoints[i] = base + (forward * f - right * r) * component->coneRadius;
rot += anglestep;
}
for (int i = 0; i < CONEARCVERTEXCOUNT-1; i++)
{
PDI->DrawLine(linePoints[i], linePoints[i + 1], ShapeColor, SDPG_World);
}
PDI->DrawLine(base, linePoints[0], ShapeColor, SDPG_World);
PDI->DrawLine(base, linePoints[CONEARCVERTEXCOUNT - 1], ShapeColor, SDPG_World);
}
}
}
virtual FPrimitiveViewRelevance GetViewRelevance(const FSceneView* View) const override
{
const bool bVisible = !bDrawOnlyIfSelected || IsSelected();
FPrimitiveViewRelevance Result;
Result.bDrawRelevance = IsShown(View) && bVisible;
Result.bDynamicRelevance = true;
Result.bShadowRelevance = IsShadowCast(View);
Result.bEditorPrimitiveRelevance = UseEditorCompositing(View);
return Result;
}
virtual uint32 GetMemoryFootprint(void) const override { return(sizeof(*this) + GetAllocatedSize()); }
uint32 GetAllocatedSize(void) const { return(FPrimitiveSceneProxy::GetAllocatedSize()); }
private:
const uint32 bDrawOnlyIfSelected : 1;
const FColor ShapeColor = FColor(255,0,0,255);
const FTransform transform;
};
return new FDrawConeSceneProxy(this);
}

View File

@@ -0,0 +1,26 @@
// Project Lab - NHTV Igad
#pragma once
#include "Components/CapsuleComponent.h"
#include "ConeComponent.generated.h"
UCLASS(ClassGroup = "Collision", editinlinenew, hidecategories = (Object, LOD, Lighting, TextureStreaming), meta = (DisplayName = "Cone Collision", BlueprintSpawnableComponent))
class UNREALPROJECT_API UConeComponent : public UCapsuleComponent
{
GENERATED_UCLASS_BODY()
public:
void BeginPlay() override;
void UpdateCapsule();
UPROPERTY(EditAnywhere, export, Category = Shape, meta = (ClampMin = "0", UIMin = "0"))
float coneRadius = 500.0f;
UPROPERTY(EditAnywhere, export, Category = Shape, meta = (ClampMin = "0", UIMin = "0"))
float coneAngle = 50;
virtual FPrimitiveSceneProxy* CreateSceneProxy() override;
};

View File

@@ -0,0 +1,50 @@
// Project Lab - NHTV Igad
#include "UnrealProject.h"
#include "ConeTrigger.h"
#include "ConeComponent.h"
#include "NetworkCharacter.h"
#include "BlueprintAbilityLibrary.h" // For Cone overlap code
AConeTrigger::AConeTrigger()
{
PrimaryActorTick.bCanEverTick = true;
m_coneTrigger = CreateDefaultSubobject <UConeComponent>(TEXT("trigger"));
RootComponent = m_coneTrigger;
m_coneTrigger->SetCollisionProfileName(TEXT("Triggers"));
}
void AConeTrigger::BeginPlay()
{
m_coneTrigger->SetWorldTransform(GetTransform());
if (!delegatesSet)
{
m_coneTrigger->OnComponentBeginOverlap.AddDynamic(this, &AConeTrigger::OnOverlapBegin);
m_coneTrigger->OnComponentEndOverlap.AddDynamic(this, &AConeTrigger::OnOverlapEnd);
delegatesSet = true;
}
SetCone(radius, angle);
Super::BeginPlay();
}
void AConeTrigger::Tick( float DeltaTime )
{
Super::Tick( DeltaTime );
}
void AConeTrigger::SetCone(float inputRadius, float inputAngle)
{
m_coneTrigger->coneAngle = (inputAngle);
m_coneTrigger->coneRadius = (inputRadius);
m_coneTrigger->UpdateCapsule();
}
bool AConeTrigger::CollisionCheck(ANetworkCharacter* otheractor)
{
return ULib::IsContainedInCone(GetActorLocation(), GetActorForwardVector(), m_coneTrigger->coneAngle, otheractor);
}

View File

@@ -0,0 +1,27 @@
// Project Lab - NHTV Igad
#pragma once
#include "AbilityTriggerBase.h"
#include "GameFramework/Actor.h"
#include "ConeTrigger.generated.h"
UCLASS()
class UNREALPROJECT_API AConeTrigger : public AAbilityTriggerBase
{
GENERATED_BODY()
public:
AConeTrigger();
virtual void BeginPlay() override;
virtual void Tick( float DeltaSeconds ) override;
virtual bool CollisionCheck(ANetworkCharacter* otheractor) override;
void SetCone(float radius, float angle);
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, meta = (ExposeOnSpawn), Category = "Trigger")
float radius;
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, meta = (ExposeOnSpawn), Category = "Trigger")
float angle;
private:
UPROPERTY(VisibleAnywhere, Category = "Trigger")
class UConeComponent* m_coneTrigger;
};

View File

@@ -0,0 +1,67 @@
#include "UnrealProject.h"
#include "NetworkCharacter.h"
#include "DealDamageProxy.h"
#include "DefaultPlayerState.h"
#include "ScalingGraph.h"
#include "AbilityInfo.h"
float ADealDamageProxy::GetAbilityPowerScale() const
{
if(!character)
return 0.0f;
AAbilityState* state = character->GetAbilityState(abilityInfo);
if(!state)
return 0.0f;
return state->power;
}
float ADealDamageProxy::ScaleGraphCurve(const UCurveFloat* val)
{
if (!IsValid(val))
{
GEngine->AddOnScreenDebugMessage((int32)abilityInfo->GetUniqueID(), 2.0f, FColor(255, 20, 20, 255), FString("Invalid curve argument in ") + GetName() + " [" + abilityInfo->GetName() + "]");
JERROR("Invalid curve argument in " + GetName() + " [" + abilityInfo->GetName() + "]");
return 0;
}
if(abilityInfo->abilityType == EAbilityType::Basic)
{
return ScaleGraphCurveByLevel(val);
}
float f = GetAbilityPowerScale();
f = FMath::Clamp(f, 0.0f, 1.0f);
return val->GetFloatValue(f);
}
float ADealDamageProxy::ScaleGraphCurveByLevel(const UCurveFloat* val)
{
if(!IsValid(val))
{
GEngine->AddOnScreenDebugMessage((int32)abilityInfo->GetUniqueID(), 2.0f, FColor(255, 20, 20, 255), FString("Invalid curve argument in ") + GetName() + " [" + abilityInfo->GetName() + "]");
JERROR("Invalid curve argument in " + GetName() + " [" + abilityInfo->GetName() + "]");
return 0;
}
float f = 0.0f;
if(character)
{
ADefaultPlayerState* ps = Cast<ADefaultPlayerState>(character->PlayerState);
if(ps)
{
f = FMath::Clamp((float)ps->GetLevel() / (float)ps->GetMaxLevel(), 0.0f, 1.0f);
}
}
return val->GetFloatValue(f);
}
float ULevelScaleLibrary::ScaleGraphCurveFloat(float in, const UCurveFloat* val)
{
if (!IsValid(val))
{
JERROR("Invalid curve argument");
return 0;
}
in = FMath::Clamp(in, 0.0f, 1.0f);
return val->GetFloatValue(in);
}

View File

@@ -0,0 +1,28 @@
#pragma once
#include "AbilityFilter.h"
#include "ScalingGraph.h"
#include "DealDamageProxy.Generated.h"
UCLASS()
class ADealDamageProxy : public AActor
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintCallable, Category = "Damage Scaling")
float GetAbilityPowerScale() const;
// Scales samples the input curve anywhere from 0-1 based on the currently cast ability's power(or level for basic attacks)
UFUNCTION(BlueprintCallable, Category = "Scaling Graph")
float ScaleGraphCurve(const UCurveFloat* val);
// Same as ScaleGraphCurve but this one scales with the player level
UFUNCTION(BlueprintCallable, Category = "Scaling Graph")
float ScaleGraphCurveByLevel(const UCurveFloat* val);
// The character that started this sequence of proxies and the dealer of the damage
UPROPERTY(BlueprintReadOnly, Category="Damage Proxy")
class ANetworkCharacter* character;
// The ability that was cast to spawn this object
UPROPERTY(BlueprintReadOnly, Category="Damage Proxy")
class UAbilityInfo* abilityInfo;
};

View File

@@ -0,0 +1,47 @@
// Project Lab - NHTV Igad
#include "UnrealProject.h"
#include "HomingProjectile.h"
#include "DefaultGameMode.h"
#include "NetworkPlayer.h"
void AHomingProjectile::BeginPlay()
{
Super::BeginPlay();
float maxdist = BIG_NUMBER;
if (Role == ROLE_Authority)
{
if (targetCreature == nullptr)
{
UWorld* const world = GetWorld();
if (!world) return;
ADefaultGameMode* mode = Cast<ADefaultGameMode>(world->GetAuthGameMode());
if (!mode) return;
TArray<class ANetworkPlayer*> players = mode->GetPlayers();
for (ANetworkPlayer* player : players)
{
float dist = (player->GetActorLocation() - GetActorLocation()).SizeSquared();
if (dist < maxdist)
{
maxdist = dist;
targetCreature = player;
}
}
}
}
}
void AHomingProjectile::NativeMove(float DeltaTime)
{
if (targetCreature == nullptr)
return;
FVector dir = targetCreature->GetActorLocation() - GetActorLocation();
FRotator newrot = FRotationMatrix::MakeFromX(dir).Rotator();
SetActorRotation(newrot);
Super::NativeMove(DeltaTime);
}

View File

@@ -0,0 +1,22 @@
// Project Lab - NHTV Igad
#pragma once
#include "ProjectileBase.h"
#include "HomingProjectile.generated.h"
/**
*
*/
UCLASS()
class UNREALPROJECT_API AHomingProjectile : public AProjectileBase
{
GENERATED_BODY()
public:
virtual void BeginPlay() override;
virtual void NativeMove(float DeltaTime) override;
UPROPERTY(BlueprintReadWrite, category = "projectile", meta = (ExposeOnSpawn))
class ANetworkCharacter* targetCreature;
};

View File

@@ -0,0 +1,22 @@
// ProjeLab - NHTV Igad
#include "UnrealProject.h"
#include "HoverProjectile.h"
void AHoverProjectile::NativeMove(float DeltaTime)
{
//moves with sweep to get collision
float distance = speed * DeltaTime;
FVector newpos = GetActorForwardVector() * distance + GetActorLocation();
FHitResult outHit;
FVector offset;
if (GetWorld()->LineTraceSingleByChannel(outHit, newpos, newpos - FVector(0, 0, hoverHeight + 10), ECollisionChannel::ECC_GameTraceChannel7))
offset = outHit.ImpactPoint + FVector(0, 0, hoverHeight) - GetActorLocation();
else
offset = newpos - FVector(0, 0, 10) - GetActorLocation();
AddActorWorldOffset(offset,true);
}

View File

@@ -0,0 +1,23 @@
// Project Lab - NHTV Igad
#pragma once
#include "Abilities/ProjectileBase.h"
#include "HoverProjectile.generated.h"
/**
*
*/
UCLASS()
class UNREALPROJECT_API AHoverProjectile : public AProjectileBase
{
GENERATED_BODY()
public:
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = "Projectile", meta = (ExposeOnSpawn))
float hoverHeight;
virtual void NativeMove(float DeltaTime)override;
};

View File

@@ -0,0 +1,103 @@
#include "UnrealProject.h"
#include "IngameSkillTree.h"
#include "HexMap.h"
#include "BaseSkillObject.h"
#include "DefaultPlayerState.h"
void AIngameSkillTree::BuildFromState(const FSkillTreeState& state)
{
for(int32 i = 0; i < state.objects.Num(); i++)
{
const FSkillTreeStateObject& obj = state.objects[i];
if(!obj.skillObject)
{
GWARNING("Invalid skill object found in skill tree state, please reset your build.");
continue;
}
FIngameSkillTreeSkill igs;
igs.placedPoints = obj.placedPoints;
igs.skillObject = obj.skillObject->GetDefaultObject<UBaseSkillObject>();
igs.selectedEffectIndex = obj.selectedEffect;
// Check valid effect index
if(igs.selectedEffectIndex < 0 || igs.selectedEffectIndex >= igs.skillObject->abilityEffects.Num())
{
GWARNING("Ability effect out of range for ability " + obj.skillObject->GetName());
continue;
}
igs.selectedEffect = igs.skillObject->abilityEffects[igs.selectedEffectIndex];
igs.abilityType = -1;
switch (igs.skillObject->skillShapeType)
{
case ESkillShapeType::Active:
igs.abilityType = 0;
break;
case ESkillShapeType::Coop:
case ESkillShapeType::Sustain:
igs.abilityType = 1;
break;
case ESkillShapeType::Passive:
igs.abilityType = 2;
break;
}
if(igs.abilityType == -1)
{
GWARNING("Ability type invalid for ability " + obj.skillObject->GetName());
continue;
}
m_skills.Add(igs);
}
}
AIngameSkillTree::AIngameSkillTree(const FObjectInitializer& init)
{
}
AIngameSkillTree::~AIngameSkillTree()
{
}
void AIngameSkillTree::BeginPlay()
{
}
TArray<FIngameSkillTreeSkill> AIngameSkillTree::GetSkillsForLevel(ADefaultPlayerState* player)
{
float powerLevel = player->GetLevel() / (float)player->GetMaxLevel();
return GetSkillsForLevel(powerLevel);
}
TArray<FIngameSkillTreeSkill> AIngameSkillTree::GetSkillsForLevel(float powerLevel)
{
TArray<FIngameSkillTreeSkill> res;
for (int32 i = 0; i < m_skills.Num(); i++)
{
UpdatePowerForSkill(m_skills[i], powerLevel);
if (m_skills[i].power > 0.0f)
res.Add(m_skills[i]);
}
return res;
}
void AIngameSkillTree::UpdatePowerForSkill(FIngameSkillTreeSkill& skill, float level)
{
float offset = (1.0f - level) * 16.0f;
int32 hexcount = 0;
for(int32 i = 0; i < skill.placedPoints.Num(); i++)
{
float YPos = (skill.placedPoints[i].X & 1) ?
(float(skill.placedPoints[i].Y) + 0.5f) :
(float(skill.placedPoints[i].Y));
if(YPos >= offset) hexcount++;
}
skill.level = hexcount;
skill.power = float(hexcount) / float(skill.placedPoints.Num());
}

View File

@@ -0,0 +1,45 @@
#pragma once
#include "SkillTreeState.h"
#include "IngameSkillTree.Generated.h"
USTRUCT()
struct FIngameSkillTreeSkill
{
GENERATED_BODY()
public:
UPROPERTY()
TArray<FIntPoint> placedPoints;
UPROPERTY(BlueprintReadOnly)
class UBaseSkillObject* skillObject;
UPROPERTY(BlueprintReadOnly)
class UAbilityInfo* selectedEffect;
UPROPERTY(BlueprintReadOnly)
int32 selectedEffectIndex;
UPROPERTY(BlueprintReadOnly)
float power;
UPROPERTY(BlueprintReadOnly)
int32 level;
// Kind of ability on the button bar
UPROPERTY(BlueprintReadOnly)
int32 abilityType;
};
UCLASS()
class AIngameSkillTree : public AActor
{
GENERATED_BODY()
public:
AIngameSkillTree(const FObjectInitializer& init);
~AIngameSkillTree();
virtual void BeginPlay() override;
void BuildFromState(const FSkillTreeState& state);
TArray<FIngameSkillTreeSkill> GetSkillsForLevel(class ADefaultPlayerState* player);
TArray<FIngameSkillTreeSkill> GetSkillsForLevel(float level);
void UpdatePowerForSkill(FIngameSkillTreeSkill& skill, float level);
private:
UPROPERTY()
TArray<FIngameSkillTreeSkill> m_skills;
};

View File

@@ -0,0 +1,60 @@
// Project Lab - NHTV Igad
#include "UnrealProject.h"
#include "IntimidatingAuraTrigger.h"
#include "NetworkCharacter.h"
#include "NativeModifiers.h"
#include "Modifier.h"
AIntimidatingAuraTrigger::AIntimidatingAuraTrigger()
{
}
void AIntimidatingAuraTrigger::BeginPlay()
{
Super::BeginPlay();
}
void AIntimidatingAuraTrigger::Tick(float deltaTime)
{
Super::Tick(deltaTime);
}
void AIntimidatingAuraTrigger::HitEvent(ANetworkCharacter* otherActor)
{
ModifierManager* manager = otherActor->GetModifierManager();
if (playerMap.Find(otherActor)== nullptr)
{
RERROR("2 modifiers in the intimidatin aura");
}
if (manager)
{
AAttackSpeedModifierConstant* ASModifier = GetWorld()->SpawnActor<AAttackSpeedModifierConstant>();
ASModifier->lifeTime = 0;
ASModifier->attackSpeedMultiplier = attackSpeedMultiplier;
ASModifier->target = otherActor;
manager->AddModifier(ASModifier);
ASpeedModifier* SModifier = GetWorld()->SpawnActor<ASpeedModifier>();
SModifier->lifeTime = 0;
SModifier->speedMultiplier = MovementSpeedMultiplier;
SModifier->target = otherActor;
manager->AddModifier(ASModifier);
// std::pair <AModifier*, AModifier*> pair = std::pair <AModifier*, AModifier*>((AModifier*)ASModifier, (AModifier*)SModifier);
playerMap.Add(otherActor, FIntimidatingAuraPair(ASModifier,SModifier));
}
return Super::HitEvent(otherActor);
}
void AIntimidatingAuraTrigger::LeaveEvent(ANetworkCharacter* otherActor)
{
auto it =playerMap.Find(otherActor);
if (it == nullptr)
return Super::LeaveEvent(otherActor);
it->modifier0->ForceDestroy();
it->modifier1->ForceDestroy();
playerMap.Remove(otherActor);
return Super::LeaveEvent(otherActor);
}

View File

@@ -0,0 +1,42 @@
// Project Lab - NHTV Igad
#pragma once
#include "Abilities/ConeTrigger.h"
#include "IntimidatingAuraTrigger.generated.h"
/**
*
*/
USTRUCT()
struct FIntimidatingAuraPair
{
GENERATED_BODY()
public:
FIntimidatingAuraPair(){}
FIntimidatingAuraPair(class AModifier* m0, class AModifier*m1) { modifier0 = m0; modifier1 = m1; }
UPROPERTY()
class AModifier* modifier0;
UPROPERTY()
class AModifier* modifier1;
};
UCLASS()
class UNREALPROJECT_API AIntimidatingAuraTrigger : public AConeTrigger
{
GENERATED_BODY()
public:
AIntimidatingAuraTrigger();
virtual void BeginPlay() override;
virtual void Tick(float DeltaSeconds) override;
virtual void HitEvent(class ANetworkCharacter* otherActor)override;
virtual void LeaveEvent(class ANetworkCharacter* otherActor)override;
UPROPERTY()
TMap<class ANetworkCharacter*, FIntimidatingAuraPair > playerMap;
UPROPERTY(meta = (ExposeOnSpawn), BlueprintReadWrite)
float attackSpeedMultiplier;
UPROPERTY(meta = (ExposeOnSpawn), BlueprintReadWrite)
float MovementSpeedMultiplier;
};

View File

@@ -0,0 +1,477 @@
// Project Lab - NHTV Igad
#include "UnrealProject.h"
#include "Modifier.h"
#include "NetworkCharacter.h"
#include "NativeModifiers.h"
ModifierManager::ModifierManager(class ANetworkCharacter* character)
: m_character(character)
{
check(m_character);
}
ModifierManager::~ModifierManager()
{
ClearModifiers(false);
}
void ModifierManager::ClearModifiers(bool shouldCallEnd)
{
for (AModifier* modifier : m_modifiers)
{
if (shouldCallEnd)
modifier->m_started = false;
modifier->Destroy();
}
m_modifiers.SetNum(0);
RecalculateCharacter();
}
void ModifierManager::Tick(float DeltaSeconds)
{
for (int32 i = 0; i < m_modifiers.Num();)
{
AModifier* modifier = m_modifiers[i];
if (modifier != nullptr && IsValid(modifier))
{
if (modifier->ShouldBeRemoved() || modifier->m_forceDestroy)
{
modifier->Destroy();
m_modifiers.RemoveAt(i);
RecalculateCharacter();
continue;
}
else
{
modifier->Tick(DeltaSeconds);
}
}
else
{
m_modifiers.RemoveAt(i);
if (modifier != 0)
{
GERROR("Modifier \"" + modifier->GetName() + "\" was destroyed, but not in the usual way");
}
RecalculateCharacter();
continue;
}
i++;
}
}
AModifier* ModifierManager::AddModifier(TSubclassOf<class AModifier> buffClass, float duration)
{
if (!buffClass)
{
FWERROR(L"Invalid modifier class");
return nullptr;
}
UWorld* world = m_character->GetWorld();
check(world);
AModifier* modifier = world->SpawnActor<AModifier>(buffClass);
modifier->m_Init(m_character, duration);
return AddModifier(modifier);
}
AModifier* ModifierManager::AddModifier(AModifier* modifierInstance)
{
if (!modifierInstance)
{
FWERROR(L"Invalid buff added");
return nullptr;
}
m_modifiers.Add(modifierInstance);
m_modifiers.Sort([](const AModifier& i, const AModifier& j)->bool { return i > j; });
modifierInstance->m_Start();
RecalculateCharacter();
return modifierInstance;
}
TArray<AModifier*> ModifierManager::GetModifiersOfClass(TSubclassOf<class AModifier> modifierClass)
{
TArray<AModifier*> ret;
for (AModifier* mod : m_modifiers)
{
if (mod->IsA(modifierClass))
{
ret.Add(mod);
}
}
return ret;
}
void ModifierManager::BroadcastManaDrainFailed()
{
for(AModifier* modifier : m_modifiers)
{
if (modifier != nullptr && IsValid(modifier))
{
modifier->onManaDrainFailed.Broadcast();
}
}
}
//reset all modifiable stats so that modifiers can recalculate them
void ModifierManager::m_Reset()
{
m_character->ResetModifiers();
}
void ModifierManager::RecalculateCharacter()
{
m_Reset();
for (AModifier* it : m_modifiers)
{
it->ModifyCharacter();
}
m_character->CheckStatsOverflow();
}
AModifier::AModifier()
{
PrimaryActorTick.bCanEverTick = true;
bReplicates = true;
lifeTime = 0;
ticksPerSecond = 0;
m_dontDestroy = false;
RootComponent = CreateDefaultSubobject<USceneComponent>("Root");
}
bool AModifier::operator < (const AModifier& other) const
{
return priority < other.priority;
}
bool AModifier::operator > (const AModifier& other) const
{
return priority > other.priority;
}
void AModifier::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
if (m_started)
ModifierEnd();
}
void AModifier::ModifyCharacter()
{
}
bool AModifier::ShouldBeRemoved() const
{
return (lifeTime <= 0.0f) && !m_dontDestroy;
}
void AModifier::ForceDestroy()
{
m_forceDestroy = true;
}
void AModifier::ModifierTick()
{
}
void AModifier::ModifierStart()
{
}
void AModifier::ModifierEnd()
{
}
bool AModifier::OnDamage(int32& damage, ANetworkCharacter* damageDealer)
{
return true;
}
bool AModifier::OnDealDamage(int32& damage, ANetworkCharacter* damageTaker)
{
return true;
}
void AModifier::OnStandardAttack(ANetworkCharacter* character)
{
return;
}
void AModifier::AfterDamage(int32)
{
return;
}
float AModifier::m_MultiplyEffect(float value, EffectType effectType, bool positive)
{
switch (effectType)
{
case EffectType::additive:
{
if (!positive)
return value * target->m_negativeEffectMultiplier;
else
return value * target->m_positiveEffectMultiplier;
}
case EffectType::multiplicative:
{
if (!positive)
return value * (1.0f/target->m_negativeEffectMultiplier);
else
return value * target->m_positiveEffectMultiplier;
}
default:
return 0.0f;
}
}
//character modification functions
void AModifier::m_AddMaxMana(int32 maxMana)
{
if (IsValid(target))
{
maxMana = m_MultiplyEffect(maxMana, additive, maxMana>0);
target->m_maxMana += maxMana;
target->AddMana(maxMana);
}
}
void AModifier::m_MultiplyManaRegenMultiplier(float manaRegenMultiplier)
{
if (IsValid(target))
{
manaRegenMultiplier = m_MultiplyEffect(manaRegenMultiplier, multiplicative, manaRegenMultiplier>1);
target->m_manaRegenMultiplier *= manaRegenMultiplier;
}
}
void AModifier::m_MultiplyManaUsageMultiplier(float manaUsageMultiplier)
{
if (IsValid(target))
{
manaUsageMultiplier = m_MultiplyEffect(manaUsageMultiplier, multiplicative, manaUsageMultiplier>1);
target->m_manaUsageMultiplier *= manaUsageMultiplier;
}
}
void AModifier::m_AddBlockedMana(int32 blockedMana)
{
if (IsValid(target))
{
if (target->m_blockedMana + blockedMana > target->m_maxMana)
{
ModifierManager* mod = character->GetModifierManager();
if (mod != nullptr)
mod->BroadcastManaDrainFailed();
}
else
target->m_blockedMana += blockedMana;
}
}
void AModifier::m_AddDamageMultiplier(float multiplier)
{
if (IsValid(target))
{
multiplier = m_MultiplyEffect(multiplier, additive, multiplier > 0);
target->m_damageMultiplier += multiplier;
}
}
void AModifier::m_AddMaxHealth(int32 health)
{
if (IsValid(target))
{
health = m_MultiplyEffect(health, additive, health >0);
target->m_maxHealth += health;
}
}
void AModifier::m_AddMovementSpeedMultiplier(float multiplier)
{
if (IsValid(target))
{
multiplier = m_MultiplyEffect(multiplier, multiplicative, multiplier > 0);
target->GetCharacterMovement()->MaxWalkSpeed *= multiplier;
}
}
void AModifier::m_AddIgnoreArmor(float normalizedPercentage)
{
if (IsValid(target))
{
normalizedPercentage = m_MultiplyEffect(normalizedPercentage, additive, normalizedPercentage > 0);
target->m_ignoreArmor += normalizedPercentage;
}
}
void AModifier::m_AddArmor(float armor)
{
if (IsValid(target))
{
armor = m_MultiplyEffect(armor, additive, armor > 0);
target->m_armor += armor;
}
}
void AModifier::m_MultiplyArmor(float armor)
{
if (IsValid(target))
{
armor = m_MultiplyEffect(armor, multiplicative, armor > 1);
target->m_armor *= armor;
}
}
void AModifier::m_MultiplyAttackDamage(float damageMultiplier)
{
if (IsValid(target))
{
damageMultiplier = m_MultiplyEffect(damageMultiplier, multiplicative, damageMultiplier>1);
FPRINT(damageMultiplier);
target->m_attackDamageMultiplier *= damageMultiplier;
}
}
void AModifier::m_AddMagicDamage(float damageMultiplier)
{
if (IsValid(target))
{
damageMultiplier = m_MultiplyEffect(damageMultiplier, multiplicative, damageMultiplier > 1);
target->m_magicDamageMultiplier *= damageMultiplier;
}
}
void AModifier::m_AddAttackSpeed(float amount)
{
if (IsValid(target))
{
amount = m_MultiplyEffect(amount, additive, amount> 0);
target->m_attackSpeed += amount;
}
}
void AModifier::m_AddAttackSpeedMultiplier(float multiplier)
{
if (IsValid(target))
{
multiplier = m_MultiplyEffect(multiplier, multiplicative, multiplier > 1);
target->m_attackSpeed *= multiplier;
}
}
void AModifier::m_AddCooldownReduction(float amount)
{
if (IsValid(target))
{
amount = m_MultiplyEffect(amount, additive, amount > 0);
target->m_cooldownReduction += amount;
}
}
void AModifier::m_AddCooldownReductionMultiplier(float multiplier)
{
if (IsValid(target))
{
multiplier = m_MultiplyEffect(multiplier, multiplicative, multiplier > 1);
target->m_cooldownReduction *= multiplier;
}
}
void AModifier::m_MultiplyDamageTakenMultiplier(float multiplier)
{
if (IsValid(target))
{
multiplier = m_MultiplyEffect(multiplier, multiplicative, multiplier < 0);
target->m_damageTakenMultiplier *= multiplier;
}
}
void AModifier::m_MultiplyPositiveEffectMultiplier(float multiplier)
{
if (IsValid(target))
target->m_positiveEffectMultiplier *= multiplier;
}
void AModifier::m_MultiplyNegativeEffectMultiplier(float multiplier)
{
if (IsValid(target))
target->m_negativeEffectMultiplier *= multiplier;
}
void AModifier::m_addChannelMovementSpeedMultiplier(float channelMovementSpeedMultiplier)
{
if (IsValid(target))
{
channelMovementSpeedMultiplier = m_MultiplyEffect(channelMovementSpeedMultiplier, additive, channelMovementSpeedMultiplier > 0);
target->m_castingMovementspeedMultiplier += channelMovementSpeedMultiplier;
}
}
void AModifier::m_MultiplyMagicDamageMultiplier(float multiplier)
{
if (IsValid(target))
{
multiplier = m_MultiplyEffect(multiplier, additive, multiplier> 0);
target->m_magicDamageMultiplier *= multiplier;
}
}
void AModifier::m_AddStunnedState()
{
if (IsValid(target))
if (target->canBeStunned)
{
target->m_stunned = true;
target->m_InteruptSpellcasting();
}
}
void AModifier::m_AddSilencedState()
{
if (IsValid(target))
if (target->canBeSilenced)
{
target->m_silenceCount++;
target->m_silenced = true;
target->m_InteruptSpellcasting();
}
}
void AModifier::m_RemoveSilencedState()
{
if (IsValid(target))
{
target->m_silenceCount--;
if (target->m_silenceCount == 0)
{
target->m_silenced = false;
}
else if (target->m_silenceCount < 0)
{
FERROR("m_silenceCount <0 in removeSilenceState");
}
}
}
void AModifier::m_Start()
{
if (!m_started)
{
if (IsValid(target))
{
if (ticksPerSecond <= 0)
m_tickRate = 0.0f;
else
m_tickRate = 1.0f / ticksPerSecond;
m_started = true;
if (lifeTime == 0)
{
m_dontDestroy = true;
}
ModifierStart();
}
else
{
GWERROR(L"Can't start modifier " + GetName() + " target not set");
}
}
else
{
GWERROR(L"modifier started twice");
}
}
void AModifier::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
if (!IsValid(target) || !m_started)
return;
if (ShouldBeRemoved() || m_forceDestroy)
return;
if (m_tickRate > 0.0f)
{
m_tickTimer += DeltaTime;
while (m_tickTimer >= m_tickRate)
{
ModifierTick();
m_tickTimer -= m_tickRate;
}
}
lifeTime -= DeltaTime;
}
void AModifier::m_Init(class ANetworkCharacter* a_character, float duration)
{
target = a_character;
lifeTime = duration;
}

View File

@@ -0,0 +1,122 @@
// Project Lab - NHTV Igad
#pragma once
#include "DealDamageProxy.h"
#include <list>
#include "AbilityInfo.h"
#include "Modifier.generated.h"
class ModifierManager
{
public:
ModifierManager(class ANetworkCharacter* character);
~ModifierManager();
void ClearModifiers(bool shouldCallEnd = true);
void Tick(float DeltaSeconds);
class AModifier* AddModifier(TSubclassOf<class AModifier> modifierClass, float duration);
class AModifier* AddModifier(AModifier* modifierInstance);
TArray<class AModifier*> GetModifiersOfClass(TSubclassOf<class AModifier> modifierClass);
void RecalculateCharacter();
void BroadcastManaDrainFailed();
private:
void m_Reset();
friend class ANetworkCharacter;
TArray<class AModifier*> m_modifiers;
class ANetworkCharacter* m_character;
};
UCLASS()
class UNREALPROJECT_API AModifier : public ADealDamageProxy
{
GENERATED_BODY()
friend class ADefaultPlayerController;
friend class ModifierManager;
friend class ANetworkCharacter;
friend class AOnDamageModifier;
public:
AModifier();
virtual void Tick(float DeltaSeconds) override final;
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
virtual void ModifierTick();
virtual void ModifierStart();
virtual void ModifierEnd();
virtual bool OnDamage(int32& damage, ANetworkCharacter* damageDealer);
virtual bool OnDealDamage(int32& damage, ANetworkCharacter* damageTaker);
virtual void OnStandardAttack(ANetworkCharacter* character);
virtual void AfterDamage(int32 damage);
UFUNCTION(BlueprintCallable, Category = "modifiers")
virtual bool ShouldBeRemoved() const;
virtual void ModifyCharacter();
UFUNCTION(BlueprintCallable, Category = "modifiers")
void ForceDestroy();
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = "modifiers", meta=(ExposeOnSpawn))
float lifeTime;
UPROPERTY()
ANetworkCharacter* target;
UPROPERTY(EditDefaultsOnly, Category = "modifiers")
int32 ticksPerSecond;
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = "modifiers", meta = (ExposeOnSpawn))
int32 priority;
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnManaDrainFailed);
UPROPERTY(BlueprintAssignable, Category = "Mana Drain")
FOnManaDrainFailed onManaDrainFailed;
bool operator < (const AModifier&) const;
bool operator > (const AModifier&) const;
protected:
enum EffectType
{
additive = 0,
multiplicative
};
float m_MultiplyEffect(float value, EffectType effectType, bool positive);
// Modification Functions
void m_AddMaxMana(int32 maxMana);
void m_MultiplyManaRegenMultiplier(float manaRegenMultiplier);
void m_AddBlockedMana(int32 blockedMana);
void m_AddDamageMultiplier(float multiplier);
void m_AddIgnoreArmor(float normalizedPercentage);
void m_AddArmor(float armor);
void m_MultiplyArmor(float armor);
void m_MultiplyDamageTakenMultiplier(float multiplier);
void m_AddMaxHealth(int32 health);
void m_AddMovementSpeedMultiplier(float multiplier);
void m_AddAttackSpeed(float amount);
void m_AddAttackSpeedMultiplier(float multiplier);
void m_AddCooldownReduction(float amount);
void m_AddCooldownReductionMultiplier(float multiplier);
void m_AddStunnedState();
void m_AddSilencedState();
void m_RemoveSilencedState();
void m_MultiplyAttackDamage(float damageMultiplier);
void m_AddMagicDamage(float damageMultiplier);
void m_MultiplyManaUsageMultiplier(float manaUsageMultiplier);
void m_MultiplyNegativeEffectMultiplier(float effectMultiplier);
void m_MultiplyPositiveEffectMultiplier(float effectMultiplier);
void m_MultiplyMagicDamageMultiplier(float effectMultiplier);
void m_addChannelMovementSpeedMultiplier(float channelMovementSpeedMultiplier);
float m_tickRate;
private:
void m_Start();
void m_Init(class ANetworkCharacter* character, float duration);
bool m_forceDestroy;
int m_debugWarning;
bool m_started;
float m_tickTimer;
bool m_dontDestroy;
};

View File

@@ -0,0 +1,704 @@
// Project Lab - NHTV Igad
#include "UnrealProject.h"
#include "NetworkCharacter.h"
#include "NetworkPlayer.h"
#include "NativeModifiers.h"
#include "EffectFunctionLibrary.h"
#include "Effect.h"
#define standardTicksPerSecond 20
//SpeedModifier
ASpeedModifier::ASpeedModifier()
{
}
void ASpeedModifier::ModifyCharacter()
{
UCharacterMovementComponent* characterMovement = target->GetCharacterMovement();
characterMovement->MaxWalkSpeed *= speedMultiplier;
}
//RegenModifier
ARegenModifier::ARegenModifier()
{
ticksPerSecond = 5;
}
bool ARegenModifier::ShouldBeRemoved() const
{
return false;
}
void ARegenModifier::ModifierTick()
{
if ( m_noDamageTime < target->GetTimeSinceDamage())
target->AddHealth(regenPerTick);
}
//RegenModier
AManaRegenModifier::AManaRegenModifier()
{
ticksPerSecond = standardTicksPerSecond;
}
bool AManaRegenModifier::ShouldBeRemoved() const
{
return false;
}
void AManaRegenModifier::ModifierTick()
{
target->AddMana(regenPerTick);
}
//DOTModifier
ADOTModifier::ADOTModifier()
{
ticksPerSecond = 3;
}
void ADOTModifier::ModifierTick()
{
if (IsValid(target))
target->DealDamage(this, damagePerTick, 0.0f);
}
//ADModifier
AADModifier::AADModifier()
{
}
void AADModifier::ModifyCharacter()
{
float add = ScaleGraphCurve(scalingGraph);
m_MultiplyAttackDamage(add);
}
//ADModifier
AAPModifier::AAPModifier()
{
}
void AAPModifier::ModifyCharacter()
{
float add = ScaleGraphCurve(scalingGraph);
m_AddMagicDamage(add);
}
//MaxHealthModifier
AMaxHealthModifier::AMaxHealthModifier()
{
}
void AMaxHealthModifier::ModifyCharacter()
{
//m_AddMaxHealth(bonusMaxHealth);
float add = ScaleGraphCurve(scalingGraph);
m_AddMaxHealth(add);
}
//AConstMaxHealthModifier
AConstMaxHealthModifier::AConstMaxHealthModifier()
{
}
void AConstMaxHealthModifier::ModifyCharacter()
{
m_AddMaxHealth(add);
}
//BlockManaModifier
ABlockManaModifier::ABlockManaModifier()
{
}
void ABlockManaModifier::ModifyCharacter()
{
m_AddBlockedMana(Mana);
}
//ManaPerSecModifier
AManaDrainModifier::AManaDrainModifier()
{
ticksPerSecond = standardTicksPerSecond;
}
void AManaDrainModifier::ModifierTick()
{
if (ManaPerTick > target->GetMana())
{
ModifierManager* mod = character->GetModifierManager();
if (mod != nullptr)
mod->BroadcastManaDrainFailed();
}
else
{
target->RemoveMana(ManaPerTick);
}
}
//ManaPerSecModifier
AManaDrainCurveModifier::AManaDrainCurveModifier()
{
ticksPerSecond = standardTicksPerSecond;
}
void AManaDrainCurveModifier::ModifierTick()
{
float mana = ScaleGraphCurve(ManaPerTick);
if (mana > target->GetMana())
{
ModifierManager* mod = character->GetModifierManager();
if (mod != nullptr)
mod->BroadcastManaDrainFailed();
}
else
{
target->RemoveMana(mana);
}
}
//HealthModifier
AHealModifier::AHealModifier()
{
ticksPerSecond = standardTicksPerSecond;
}
void AHealModifier::ModifierTick()
{
target->AddHealth(health);
m_shouldBeRemoved = true;
}
bool AHealModifier::ShouldBeRemoved() const
{
return m_shouldBeRemoved;
}
//stunModifier
static TSubclassOf<AEffect> stunEffectType;
AStunModifier::AStunModifier()
{
stunEffectType = ConstructorHelpers::FClassFinder<AEffect>(TEXT("/Game/Assets/Art/Effects/FX_Stunned")).Class;
}
void AStunModifier::ModifierStart()
{
if (target->CanBeStunned() && lifeTime > 0.0f)
UEffectFunctionLibrary::CreateEffect(target, stunEffectType, target,0.0f, lifeTime);
}
void AStunModifier::ModifierEnd()
{
}
void AStunModifier::ModifierTick()
{
}
void AStunModifier::ModifyCharacter()
{
m_AddStunnedState();
}
//stunModifier
ASilenceModifier::ASilenceModifier()
{
}
void ASilenceModifier::ModifierStart()
{
m_AddSilencedState();
}
void ASilenceModifier::ModifierEnd()
{
m_RemoveSilencedState();
}
//ADamageTakenModifier
ADamageTakenModifier::ADamageTakenModifier()
{
}
void ADamageTakenModifier::ModifyCharacter()
{
m_MultiplyDamageTakenMultiplier(damageTakenMultiplier);
}
bool ADamageTakenModifier::ShouldBeRemoved() const
{
return false;
}
//AVisibilityModifier
AVisibilityModifier::AVisibilityModifier()
{
}
bool AVisibilityModifier::ShouldBeRemoved() const
{
return false;
}
void AVisibilityModifier::ModifierTick()
{
m_timer -= m_tickRate;
if (m_timer < 0 && visibleTime > 0 && visibleBreak> 0)
{
if (m_visible)
{
m_timer = visibleBreak;
target->m_visible = false;
}
else
{
m_timer = visibleTime;
target->m_visible = true;
}
m_visible = !m_visible;
}
}
//ADodgeDeathModifier
ADodgeDeathModifier::ADodgeDeathModifier()
{
}
bool ADodgeDeathModifier::ShouldBeRemoved() const
{
return false;
}
void ADodgeDeathModifier::ModifierTick()
{
m_timer += m_tickRate;
}
bool ADodgeDeathModifier::OnDamage(int32& damage, ANetworkCharacter* damageDealer)
{
if (damage >= target->GetHealth() && m_timer > ScaleGraphCurve(cooldown))
{
float chance = (float)(rand() % 100) / 100.0f;
if (ScaleGraphCurve(dodgeChance) > chance)
{
target->AddHealth(ScaleGraphCurve(heal));
m_timer = 0;
return false;
}
}
return true;
}
//ACooldownReductionModifier
ACooldownReductionModifier::ACooldownReductionModifier()
{
}
void ACooldownReductionModifier::ModifyCharacter()
{
float add = ScaleGraphCurve(scalingGraph);
m_AddCooldownReduction(add);
}
//AAttackSpeedModifier
AAttackSpeedModifier::AAttackSpeedModifier()
{
}
void AAttackSpeedModifier::ModifyCharacter()
{
float add = ScaleGraphCurve(scalingGraph);
m_AddAttackSpeedMultiplier(add);
}
//AAttackSpeedModifierConstant
AAttackSpeedModifierConstant::AAttackSpeedModifierConstant()
{
}
void AAttackSpeedModifierConstant::ModifyCharacter()
{
m_AddAttackSpeedMultiplier(attackSpeedMultiplier);
}
bool AAttackSpeedModifierConstant::ShouldBeRemoved() const
{
return false;
}
//AArmorIgnoreModifier
AArmorIgnoreModifier::AArmorIgnoreModifier()
{
}
void AArmorIgnoreModifier::ModifyCharacter()
{
float add = ScaleGraphCurve(scalingGraph);
m_AddIgnoreArmor(add);
}
//ADodgeDeathModifier
ABeserkModifier::ABeserkModifier()
{
ticksPerSecond = standardTicksPerSecond;
m_active = false;
}
bool ABeserkModifier::ShouldBeRemoved() const
{
return false;
}
void ABeserkModifier::AfterDamage(int32 damage)
{
float deltahealth = (float)target->GetHealth() / (float)target->GetMaxHealth();
if (deltahealth < ScaleGraphCurve(healthThreshold))
{
if (!m_active)
{
m_hasToActivate = true;
}
}
}
void ABeserkModifier::ModifierTick()
{
float deltahealth = (float)target->GetHealth() / (float)target->GetMaxHealth();
if (m_hasToActivate)
{
m_hasToActivate = false;
m_active = true;
m_ASModifier = GetWorld()->SpawnActor<AAttackSpeedModifierConstant>();
m_ASModifier->lifeTime = 0.0f;
m_ASModifier->target = target;
m_ASModifier->attackSpeedMultiplier = ScaleGraphCurve(attackSpeedMultiplier);
target->GetModifierManager()->AddModifier(m_ASModifier);
}
if (deltahealth > ScaleGraphCurve(healthThreshold))
{
if (m_active)
{
m_active = false;
m_ASModifier->ForceDestroy();
}
}
}
//AArmorReductionModifier
AArmorReductionModifier::AArmorReductionModifier()
{
}
void AArmorReductionModifier::ModifyCharacter()
{
m_AddArmor(armorReduction);
}
//AHealthRegenModifier
AHealthRegenModifier::AHealthRegenModifier()
{
ticksPerSecond = standardTicksPerSecond;
}
void AHealthRegenModifier::ModifierTick()
{
float add = ScaleGraphCurve(scalingGraph);
target->AddHealth(add);
}
//AOnStandardAttackDOTModifier
AOnStandardAttackDOTModifier::AOnStandardAttackDOTModifier()
{
ticksPerSecond = standardTicksPerSecond;
}
void AOnStandardAttackDOTModifier::ModifierTick()
{
m_cooldownTimer += m_tickRate;
}
void AOnStandardAttackDOTModifier::OnStandardAttack(ANetworkCharacter* targetcharacter)
{
if (!IsValid(targetcharacter))
return;
ADOTModifier* DOTModifier = GetWorld()->SpawnActor<ADOTModifier>();
DOTModifier->lifeTime = ScaleGraphCurve(damageDuration);
DOTModifier->damagePerTick = ScaleGraphCurve(damagePerTick);
// DOTModifier->target = targetcharacter;
DOTModifier->character = character;
DOTModifier->abilityInfo = abilityInfo;
DOTModifier->target = targetcharacter;
targetcharacter->GetModifierManager()->AddModifier(DOTModifier);
m_cooldownTimer = ScaleGraphCurve(cooldown);
}
//AReturnDamageModifier
AReturnDamageModifier::AReturnDamageModifier()
{
ticksPerSecond = standardTicksPerSecond;
}
bool AReturnDamageModifier::OnDamage(int32& damage, ANetworkCharacter* damageDealer)
{
if (damage >= 10 && IsValid(damageDealer))
{
float returnDamage = ScaleGraphCurve(scalingGraph);
damageDealer->DealDamage(this, damage * returnDamage, 0.0f);
}
return true;
}
//AReturnDamageModifier
ARedirectDamageModifier::ARedirectDamageModifier()
{
ticksPerSecond = standardTicksPerSecond;
}
bool ARedirectDamageModifier::OnDamage(int32& damage, ANetworkCharacter* damageDealer)
{
if (damage >= 10 && IsValid(character))
{
float redirect = ScaleGraphCurve(redirectScalingGraph);
if (redirect > 1)
{
FWARNING("redirect > 1, will act as if it is 0.9f");
redirect = 0.9f;
}
if (redirect < 0)
{
FWARNING("redirect < 0, will act as if it is 0.0f");
redirect = 0.0f;
}
float absorb = ScaleGraphCurve(absorbScalingGraph);
if (absorb > 1)
{
FWARNING("absorb > 1, will act as if it is 1.0f");
absorb = 1.0f;
}
if (absorb < 0.0f )
{
FWARNING("absorb < 0, will act as if it is 0.0f");
absorb = 0.0f;
}
character->DealDamage(this, damage * (redirect * absorb), 0.0f);
damage *= (1 - redirect);
DamageEvent();
}
return true;
}
//ATrustModifier
//set delegate in gamestate to know when the teammate respawns.
ATrustModifier::ATrustModifier()
{
ticksPerSecond = 2;
}
void ATrustModifier::ModifierTick()
{
if (IsValid(character))
{
target->GetModifierManager()->RecalculateCharacter();
}
else
ForceDestroy();
}
void ATrustModifier::ModifyCharacter()
{
if (IsValid(character))
{
float add = ScaleGraphCurve(damageScalingGraph);
float deltahealth =1 + ( 1.0f - ((float)character->GetHealth() / (float)character->GetMaxHealth()));
m_MultiplyAttackDamage(add * deltahealth);
}
}
//AArmorIncreaseModifier
AArmorIncreaseModifier::AArmorIncreaseModifier()
{
ticksPerSecond = standardTicksPerSecond;
}
void AArmorIncreaseModifier::ModifyCharacter()
{
float add = ScaleGraphCurve(armorScalingGraph);
m_AddArmor(add);
}
//AMoveToModifier
AMoveToModifier::AMoveToModifier()
{
ticksPerSecond = standardTicksPerSecond;
}
void AMoveToModifier::ModifierStart()
{
m_movePerTick = (targetPos - target->GetActorLocation()) / (moveTime * ticksPerSecond);
}
void AMoveToModifier::ModifierTick()
{
target->AddActorWorldOffset(m_movePerTick, true);
}
//AHealthRegenPercentageModifier
AHealthRegenPercentageModifier::AHealthRegenPercentageModifier()
{
ticksPerSecond = standardTicksPerSecond;
}
void AHealthRegenPercentageModifier::ModifierTick()
{
float add = ScaleGraphCurve(scalingGraph);
add /= ticksPerSecond;
int32 health = character->GetMaxHealth();
health *= add;
target->AddHealth(health);
}
//AManaRegenMultiplierModifier
AManaRegenMultiplierModifier::AManaRegenMultiplierModifier()
{
ticksPerSecond = standardTicksPerSecond;
}
void AManaRegenMultiplierModifier::ModifyCharacter()
{
float add = ScaleGraphCurve(manaRegenMultiplierScalingGraph);
m_MultiplyManaRegenMultiplier(add);
}
//AManaCostMultiplierModifier
AManaCostMultiplierModifier::AManaCostMultiplierModifier()
{
ticksPerSecond = standardTicksPerSecond;
}
void AManaCostMultiplierModifier::ModifyCharacter()
{
float add = ScaleGraphCurve(manaCostMultiplierScalingGraph);
m_MultiplyManaUsageMultiplier(add);
}
//AManaCostMultiplierModifier
AEffectMultiplierModifier::AEffectMultiplierModifier()
{
ticksPerSecond = standardTicksPerSecond;
}
void AEffectMultiplierModifier::ModifyCharacter()
{
float add = ScaleGraphCurve(effectMultiplierScalingGraph);
if (positive)
m_MultiplyPositiveEffectMultiplier(add);
else
m_MultiplyNegativeEffectMultiplier(add);
}
//ACastingMovementSpeedMultiplierModifier
ACastingMovementSpeedMultiplierModifier::ACastingMovementSpeedMultiplierModifier()
{
ticksPerSecond = standardTicksPerSecond;
}
void ACastingMovementSpeedMultiplierModifier::ModifyCharacter()
{
float add = ScaleGraphCurve(movementSpeedMultiplierScalingGraph);
m_addChannelMovementSpeedMultiplier(add);
}
//AReaperModifier
AReaperModifier::AReaperModifier()
{
ticksPerSecond = standardTicksPerSecond;
}
bool AReaperModifier::OnDealDamage(int32& damage, ANetworkCharacter* damageTaker)
{
float multiplier = ScaleGraphCurve(damagemultiplier);
float norm = ScaleGraphCurve(threshhold);
float deltahealth = (float)damageTaker->GetHealth() / (float)damageTaker->GetMaxHealth();
if ((deltahealth < norm && smaller) || (deltahealth > norm && !smaller))
{
damage *= multiplier;
}
return true;
}
//AMagicDamageMultiplierModifier
AMagicDamageMultiplierModifier::AMagicDamageMultiplierModifier()
{
ticksPerSecond = standardTicksPerSecond;
}
void AMagicDamageMultiplierModifier::ModifyCharacter()
{
float add = ScaleGraphCurve(magicDamageMultiplierScalingGraph);
m_MultiplyMagicDamageMultiplier(add);
}
//AStandardMeleeModifier
AStandardMeleeModifier::AStandardMeleeModifier()
{
count = 0;
ticksPerSecond = standardTicksPerSecond;
}
void AStandardMeleeModifier::ModifierTick()
{
m_timer += m_tickRate;
if (m_timer >= maxTime)
{
ForceDestroy();
}
}
bool AStandardMeleeModifier::AddCount()
{
count++;
count%=maxCount;
m_timer = 0;
return count == 0;
}
//ADamageToManaModifier
ADamageToManaModifier::ADamageToManaModifier()
{
}
void ADamageToManaModifier::AfterDamage(int32 damage)
{
float addMultiplier = ScaleGraphCurve(multiplier);
target->AddMana(damage * addMultiplier);
}

View File

@@ -0,0 +1,683 @@
#pragma once
#include "Abilities/Modifier.h"
#include "ScalingGraph.h"
#include "NativeModifiers.generated.h"
// Increase/Decrease movement speed
UCLASS()
class UNREALPROJECT_API ASpeedModifier : public AModifier
{
GENERATED_BODY()
public:
ASpeedModifier();
virtual void ModifyCharacter();
//adjusts the movementspeed of the character
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, meta=(ExposeOnSpawn), Category = "Modifier")
float speedMultiplier;
};
// Health Regen over time
UCLASS()
class UNREALPROJECT_API ARegenModifier : public AModifier
{
GENERATED_BODY()
public:
ARegenModifier();
virtual void ModifierTick() override;
virtual bool ShouldBeRemoved() const override;
//the ammount of regen per tick (5 ticks per second)
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, meta=(ExposeOnSpawn), Category = "Modifier")
float regenPerTick = 5.0f;
//the total ammount of time the modifier should tick
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, meta=(ExposeOnSpawn), Category = "Modifier")
float regenTime;
private:
FVector m_pos;
float m_noDamageTime = 5.0f;
};
// Mana regen over time
UCLASS()
class UNREALPROJECT_API AManaRegenModifier : public AModifier
{
GENERATED_BODY()
public:
AManaRegenModifier();
virtual void ModifierTick() override;
virtual bool ShouldBeRemoved() const override;
//the ammount of mana per tick (20 ticks per second)
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, meta=(ExposeOnSpawn), Category = "Modifier")
float regenPerTick;
};
// Damage over time
UCLASS()
class UNREALPROJECT_API ADOTModifier : public AModifier
{
GENERATED_BODY()
public:
ADOTModifier();
virtual void ModifierTick() override;
//damage per tick (3 ticks per second)
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, meta=(ExposeOnSpawn), Category = "Modifier")
float damagePerTick = 5.0f;
};
// Attack speed multiplier that scales with ability power
UCLASS()
class UNREALPROJECT_API AAttackSpeedModifier : public AModifier
{
GENERATED_BODY()
public:
AAttackSpeedModifier();
virtual void ModifyCharacter();
//adjusts the attack speed of the character
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, meta=(ExposeOnSpawn), Category = "Modifier")
UCurveFloat* scalingGraph;
};
// Attack speed multiplier
UCLASS()
class UNREALPROJECT_API AAttackSpeedModifierConstant : public AModifier
{
GENERATED_BODY()
public:
AAttackSpeedModifierConstant();
virtual void ModifyCharacter();
bool ShouldBeRemoved() const override;
//adjusts the attack speed of the character
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, meta = (ExposeOnSpawn), Category = "Modifier")
float attackSpeedMultiplier;
};
// Cooldown reduction
UCLASS()
class UNREALPROJECT_API ACooldownReductionModifier : public AModifier
{
GENERATED_BODY()
public:
ACooldownReductionModifier();
virtual void ModifyCharacter();
//adjusts the cooldown of every ability of the character, except for that standard attack
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, meta=(ExposeOnSpawn), Category = "Modifier")
UCurveFloat* scalingGraph;
};
// Increase/Decrease Damage (multiplier)
UCLASS()
class UNREALPROJECT_API AADModifier : public AModifier
{
GENERATED_BODY()
public:
AADModifier();
virtual void ModifyCharacter() override;
//adjusts the damage of the standard attack
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, meta = (ExposeOnSpawn), Category = "Modifier")
UCurveFloat* scalingGraph;
};
// Increase/Decrease magic Damage (multiplier)
UCLASS()
class UNREALPROJECT_API AAPModifier : public AModifier
{
GENERATED_BODY()
public:
AAPModifier();
virtual void ModifyCharacter() override;
//adjusts the damage of all abilities of the character except for the standard attack
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, meta = (ExposeOnSpawn), Category = "Modifier")
UCurveFloat* scalingGraph;
};
// Increase/Decrease max health
UCLASS()
class UNREALPROJECT_API AMaxHealthModifier : public AModifier
{
GENERATED_BODY()
public:
AMaxHealthModifier();
virtual void ModifyCharacter();
//adjusts the max health of the character
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, meta = (ExposeOnSpawn), Category = "Modifier")
UCurveFloat* scalingGraph;
};
// Increase/Decrease max health with a int32
UCLASS()
class UNREALPROJECT_API AConstMaxHealthModifier : public AModifier
{
GENERATED_BODY()
public:
AConstMaxHealthModifier();
virtual void ModifyCharacter();
//adjusts the max health of the character
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, meta = (ExposeOnSpawn), Category = "Modifier")
int32 add;
};
// Increase/Decrease blocked mana
UCLASS()
class UNREALPROJECT_API ABlockManaModifier : public AModifier
{
GENERATED_BODY()
public:
ABlockManaModifier();
virtual void ModifyCharacter() override;
// mana blocked
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, meta=(ExposeOnSpawn), Category = "Modifier")
int32 Mana;
};
// Mana over time cost with a curve
UCLASS()
class UNREALPROJECT_API AManaDrainCurveModifier : public AModifier
{
GENERATED_BODY()
public:
AManaDrainCurveModifier();
virtual void ModifierTick() override;
//mana drained per tick (20 ticks per second)
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, meta=(ExposeOnSpawn), Category = "Modifier")
UCurveFloat* ManaPerTick;
};
// Mana over time cost
UCLASS()
class UNREALPROJECT_API AManaDrainModifier : public AModifier
{
GENERATED_BODY()
public:
AManaDrainModifier();
virtual void ModifierTick() override;
//mana drained per tick (20 ticks per second)
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, meta = (ExposeOnSpawn), Category = "Modifier")
float ManaPerTick;
};
// Heal health 1 time
UCLASS()
class UNREALPROJECT_API AHealModifier : public AModifier
{
GENERATED_BODY()
public:
AHealModifier();
virtual void ModifierTick() override;
virtual bool ShouldBeRemoved() const override;
//the ammount of health that is healed
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, meta=(ExposeOnSpawn), Category = "Modifier")
float health;
private:
bool m_shouldBeRemoved = false;
};
// Stun
UCLASS()
class UNREALPROJECT_API AStunModifier : public AModifier
{
GENERATED_BODY()
public:
AStunModifier();
virtual void ModifierStart() override;
virtual void ModifierEnd() override;
virtual void ModifierTick() override;
virtual void ModifyCharacter() override;
};
// Stun
UCLASS()
class UNREALPROJECT_API ASilenceModifier : public AModifier
{
GENERATED_BODY()
public:
ASilenceModifier();
virtual void ModifierStart() override;
virtual void ModifierEnd() override;
};
// Damage taken multiplier (only meant for bosses, will not work with a timer)
UCLASS()
class UNREALPROJECT_API ADamageTakenModifier : public AModifier
{
GENERATED_BODY()
public:
ADamageTakenModifier();
virtual void ModifyCharacter() override;
virtual bool ShouldBeRemoved() const override;
//adjusts the damage taken.
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, meta=(ExposeOnSpawn), Category = "Modifier")
float damageTakenMultiplier;
};
//gives invisibility on the minimap with set breaks DEPRECATED
UCLASS()
class UNREALPROJECT_API AVisibilityModifier : public AModifier
{
GENERATED_BODY()
public:
AVisibilityModifier();
virtual void ModifierTick() override;
virtual bool ShouldBeRemoved() const override;
//DEPRECATED
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, meta = (ExposeOnSpawn), Category = "Modifier")
float visibleBreak = 5.0f;
//DEPRECATED
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, meta = (ExposeOnSpawn), Category = "Modifier")
float visibleTime = 1.0f;
private:
float m_timer;
bool m_visible;
};
//gives a chance at healing instead of damage if the blow is the killing blow
UCLASS()
class UNREALPROJECT_API ADodgeDeathModifier : public AModifier
{
GENERATED_BODY()
float m_timer;
public:
ADodgeDeathModifier();
virtual bool ShouldBeRemoved() const override;
virtual void ModifierTick() override;
//the chance between 0 and 1 and the effect will be proced
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, meta = (ExposeOnSpawn), Category = "Modifier")
UCurveFloat* dodgeChance;
//the ammount of health that is healed on the effect
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, meta = (ExposeOnSpawn), Category = "Modifier")
UCurveFloat* heal;
//the cooldown for the dodgedeath in seconds
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, meta = (ExposeOnSpawn), Category = "Modifier")
UCurveFloat* cooldown;
virtual bool OnDamage(int32& damage, ANetworkCharacter* damageDealer) override;
};
//ignores a part of the enemy armor on all abilities
UCLASS()
class UNREALPROJECT_API AArmorIgnoreModifier : public AModifier
{
GENERATED_BODY()
public:
AArmorIgnoreModifier();
virtual void ModifyCharacter();
//the ammount of armor that is ignored (between 0 and 1)
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, meta = (ExposeOnSpawn), Category = "Modifier")
UCurveFloat* scalingGraph;
};
//gives a chance at healing instead of damage if the blow is the killing blow
UCLASS()
class UNREALPROJECT_API ABeserkModifier : public AModifier
{
GENERATED_BODY()
public:
ABeserkModifier();
virtual bool ShouldBeRemoved() const override;
//the threshhold (between 0 and 1) where the effect will be proced
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, meta = (ExposeOnSpawn), Category = "Modifier")
UCurveFloat* healthThreshold;
//adjusts the attackspeed
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, meta = (ExposeOnSpawn), Category = "Modifier")
UCurveFloat* attackSpeedMultiplier;
void m_Start();
virtual void ModifierTick() override;
private:
bool m_active;
bool m_hasToActivate;
class AAttackSpeedModifierConstant* m_ASModifier;
virtual void AfterDamage(int32 damage) override;
};
// Increase/Decrease Damage (multiplier)
UCLASS()
class UNREALPROJECT_API AArmorReductionModifier : public AModifier
{
GENERATED_BODY()
public:
AArmorReductionModifier();
virtual void ModifyCharacter() override;
//adjusts the armor
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, meta = (ExposeOnSpawn), Category = "Modifier")
float armorReduction;
};
//regens health Per Tick
UCLASS()
class UNREALPROJECT_API AHealthRegenModifier : public AModifier
{
GENERATED_BODY()
public:
AHealthRegenModifier();
//the ammount of health that is regened per tick (20 ticks per second)
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, meta = (ExposeOnSpawn), Category = "Modifier")
UCurveFloat* scalingGraph;
virtual void ModifierTick() override;
};
//deals DOT on a standard attack
UCLASS()
class UNREALPROJECT_API AOnStandardAttackDOTModifier : public AModifier
{
GENERATED_BODY()
private:
float m_cooldownTimer;
public:
AOnStandardAttackDOTModifier();
//damage per tick on standard attack hit(3 ticks per second)
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, meta = (ExposeOnSpawn), Category = "Modifier")
UCurveFloat* damagePerTick;
//the cooldown of the effect
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, meta = (ExposeOnSpawn), Category = "Modifier")
UCurveFloat* cooldown;
//the duration of the effect( of the DOT)
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, meta = (ExposeOnSpawn), Category = "Modifier")
UCurveFloat* damageDuration;
virtual void ModifierTick() override;
virtual void OnStandardAttack(ANetworkCharacter* targetcharacter) override;
};
//returns a part of the damage
UCLASS()
class UNREALPROJECT_API AReturnDamageModifier : public AModifier
{
GENERATED_BODY()
public:
AReturnDamageModifier();
//chance between 0 and 1 of procing the effect
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, meta = (ExposeOnSpawn), Category = "Modifier")
UCurveFloat* scalingGraph;
virtual bool OnDamage(int32& damage, ANetworkCharacter* damageDealer) override;
};
//redirects a part of the damage to the ally
UCLASS()
class UNREALPROJECT_API ARedirectDamageModifier : public AModifier
{
GENERATED_BODY()
public:
ARedirectDamageModifier();
//chance between 0 and 1, the ammount that is being redirected (how much goes from the ally to the player
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, meta = (ExposeOnSpawn), Category = "Modifier")
UCurveFloat* redirectScalingGraph;
//chance between 0 and 1, the ammount of what is redirected that is being absorbed
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, meta = (ExposeOnSpawn), Category = "Modifier")
UCurveFloat* absorbScalingGraph;
UFUNCTION(BlueprintImplementableEvent, Category = "Modifier")
void DamageEvent();
virtual bool OnDamage(int32& damage, ANetworkCharacter* damageDealer);
};
//increases attack damage of ally based on missing health
UCLASS()
class UNREALPROJECT_API ATrustModifier : public AModifier
{
GENERATED_BODY()
public:
ATrustModifier();
virtual void ModifierTick() override;
virtual void ModifyCharacter() override;
//the ammount of damage the ally gets multiplied by the normalised value of the missing health
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, meta = (ExposeOnSpawn), Category = "Modifier")
UCurveFloat* damageScalingGraph;
};
//increases armor
UCLASS()
class UNREALPROJECT_API AArmorIncreaseModifier : public AModifier
{
GENERATED_BODY()
public:
AArmorIncreaseModifier();
virtual void ModifyCharacter();
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, meta = (ExposeOnSpawn), Category = "Modifier")
UCurveFloat* armorScalingGraph;
};
//increases attack damage of ally based on missing health
UCLASS()
class UNREALPROJECT_API AMoveToModifier : public AModifier
{
GENERATED_BODY()
public:
AMoveToModifier();
virtual void ModifierStart();
virtual void ModifierTick() override;
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, meta = (ExposeOnSpawn), Category = "Modifier")
FVector targetPos;
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, meta = (ExposeOnSpawn), Category = "Modifier")
float moveTime;
private:
FVector m_movePerTick;
};
//increases attack damage of ally based on missing health
UCLASS()
class UNREALPROJECT_API AHealthRegenPercentageModifier : public AModifier
{
GENERATED_BODY()
public:
AHealthRegenPercentageModifier();
//normalised percentage (0-1)
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, meta = (ExposeOnSpawn), Category = "Modifier")
UCurveFloat* scalingGraph;
virtual void ModifierTick() override;
};
//increases mana regen multiplier
UCLASS()
class UNREALPROJECT_API AManaRegenMultiplierModifier : public AModifier
{
GENERATED_BODY()
public:
AManaRegenMultiplierModifier();
virtual void ModifyCharacter();
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, meta = (ExposeOnSpawn), Category = "Modifier")
UCurveFloat* manaRegenMultiplierScalingGraph;
};
//increases mana regen multiplier
UCLASS()
class UNREALPROJECT_API AManaCostMultiplierModifier : public AModifier
{
GENERATED_BODY()
public:
AManaCostMultiplierModifier();
virtual void ModifyCharacter();
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, meta = (ExposeOnSpawn), Category = "Modifier")
UCurveFloat* manaCostMultiplierScalingGraph;
};
//debuffs positive effects
UCLASS()
class UNREALPROJECT_API AEffectMultiplierModifier : public AModifier
{
GENERATED_BODY()
public:
AEffectMultiplierModifier();
virtual void ModifyCharacter();
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, meta = (ExposeOnSpawn), Category = "Modifier")
bool positive;
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, meta = (ExposeOnSpawn), Category = "Modifier")
UCurveFloat* effectMultiplierScalingGraph;
};
//debuffs positive effects
UCLASS()
class UNREALPROJECT_API ACastingMovementSpeedMultiplierModifier : public AModifier
{
GENERATED_BODY()
public:
ACastingMovementSpeedMultiplierModifier();
virtual void ModifyCharacter();
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, meta = (ExposeOnSpawn), Category = "Modifier")
UCurveFloat* movementSpeedMultiplierScalingGraph;
};
// deals more damage depending on the enemies hp (black/white threshhold)
UCLASS()
class UNREALPROJECT_API AReaperModifier : public AModifier
{
GENERATED_BODY()
public:
AReaperModifier();
virtual bool OnDealDamage(int32& damage, ANetworkCharacter* damageTaker) override;
//true == more damage when current health is less than threshhold false == more damage when current health is more than threshhold
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, meta = (ExposeOnSpawn), Category = "Modifier")
bool smaller;
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, meta = (ExposeOnSpawn), Category = "Modifier")
UCurveFloat* damagemultiplier;
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, meta = (ExposeOnSpawn), Category = "Modifier")
UCurveFloat* threshhold;
};
//increases/decreases magic damage
UCLASS()
class UNREALPROJECT_API AMagicDamageMultiplierModifier : public AModifier
{
GENERATED_BODY()
public:
AMagicDamageMultiplierModifier();
virtual void ModifyCharacter();
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, meta = (ExposeOnSpawn), Category = "Modifier")
UCurveFloat* magicDamageMultiplierScalingGraph;
};
//increases/decreases magic damage
UCLASS()
class UNREALPROJECT_API AStandardMeleeModifier : public AModifier
{
GENERATED_BODY()
float m_timer;
public:
virtual void ModifierTick() override;
AStandardMeleeModifier();
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, meta = (ExposeOnSpawn), Category = "Modifier")
float maxTime;
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, meta = (ExposeOnSpawn), Category = "Modifier")
int32 maxCount;
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = "Modifier")
int32 count;
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, meta = (ExposeOnSpawn), Category = "Modifier")
int32 team;
UFUNCTION(BlueprintCallable, Category = "Modifier")
bool AddCount();
};
//converts damage recieved to mana
UCLASS()
class UNREALPROJECT_API ADamageToManaModifier : public AModifier
{
GENERATED_BODY()
public:
ADamageToManaModifier();
//the threshhold (between 0 and 1) where the effect will be proced
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, meta = (ExposeOnSpawn), Category = "Modifier")
UCurveFloat* multiplier;
private:
virtual void AfterDamage(int32 damage) override;
};

View File

@@ -0,0 +1,69 @@
// Project Lab - NHTV Igad
#include "UnrealProject.h"
#include "AbilityInfo.h"
#include "NetworkCharacter.h"
#include "PreCastAbilityEventGroup.h"
void APreCastAbilityEventGroup::BeginPlay()
{
check(Role == ROLE_Authority);
Super::BeginPlay();
if (!character || character->IsActorBeingDestroyed())
{
Destroy();
}
else
{
// Handle the destruction of the caster
character->OnDestroyed.AddDynamic(this, &APreCastAbilityEventGroup::m_OnCharacterDestroyed);
}
}
void APreCastAbilityEventGroup::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
check(Role == ROLE_Authority);
if (EndPlayReason == EEndPlayReason::Destroyed)
{
Super::EndPlay(EndPlayReason);
StartAbility();
}
}
void APreCastAbilityEventGroup::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
if (IsPendingKill())
return;
}
void APreCastAbilityEventGroup::m_OnCharacterDestroyed()
{
Destroy();
}
void APreCastAbilityEventGroup::StartAbility()
{
character->m_CastAbility_Server(abilityInfo);
Destroy();
}
APreCastAbilityEventGroup* APreCastAbilityEventGroup::InitPreCast(UAbilityInfo* info, ANetworkCharacter* character)
{
UWorld* world = character->GetWorld();
check(world);
APreCastAbilityEventGroup* group = world->SpawnActorDeferred<APreCastAbilityEventGroup>(info->precastEvent, FTransform::Identity);
group->character = character;
//group->abilityState = character->GetAbilityState(info);
group->abilityInfo = info;
UGameplayStatics::FinishSpawningActor(group, FTransform::Identity);
return group;
}

View File

@@ -0,0 +1,26 @@
// Project Lab - NHTV Igad
#pragma once
#include "Abilities/DealDamageProxy.h"
#include "PreCastAbilityEventGroup.generated.h"
/**
*
*/
UCLASS()
class UNREALPROJECT_API APreCastAbilityEventGroup : public ADealDamageProxy
{
GENERATED_BODY()
public:
virtual void BeginPlay() override final;
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason);
virtual void Tick(float DeltaSeconds) override final;
void StartAbility();
static APreCastAbilityEventGroup* InitPreCast(UAbilityInfo* info, ANetworkCharacter* character);
private:
UFUNCTION()
void m_OnCharacterDestroyed();
};

View File

@@ -0,0 +1,174 @@
// Project Lab - NHTV Igad
#include "UnrealProject.h"
#include "NetworkCharacter.h"
#include "ProjectileBase.h"
#include "BlueprintAbilityLibrary.h"
#include "AbilityTriggerBase.h"
AProjectileBase::AProjectileBase()
{
m_finishTimer = 0.0f;
m_fixedTimer = 0.0f;
maxDistance = 1000.0f;
distanceTraveled = 0.0f;
keepAliveAfterFinish = 1.0f;
filter = EAbilityFilter::EnemyAll;
m_finished = false;
//server client replication
bReplicateMovement = true;
bReplicates = true;
bAlwaysRelevant = true;
PrimaryActorTick.bCanEverTick = true;
}
void AProjectileBase::BeginPlay()
{
// Get collider component
collider = Cast<UPrimitiveComponent>(GetRootComponent());
if(!collider)
{
GWERROR(L"Projectile does not have a collider root!");
Destroy();
return;
}
if(Role != ROLE_Authority)
{
collider->SetCollisionEnabled(ECollisionEnabled::NoCollision);
}
else
{
collider->OnComponentHit.AddDynamic(this, &AProjectileBase::m_OnHit);
collider->OnComponentBeginOverlap.AddDynamic(this, &AProjectileBase::m_OnOverlapBegin);
// collider->SetCollisionProfileName("Projectiles");
}
Super::BeginPlay();
}
void AProjectileBase::NativeFixedProjectileTick(float DeltaTime)
{
FixedProjectileTick(DeltaTime);
}
//call this in inherited classes, will call move
void AProjectileBase::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
// Fixed timestep for projectiles
m_fixedTimer += DeltaTime;
FVector startPos = GetActorLocation();
const float delta = 1.0f / 60.0f;
while(m_fixedTimer >= delta)
{
NativeFixedProjectileTick(delta);
if (autoMove)
{
NativeMove(DeltaTime);
FVector newLocation = GetActorLocation();
FVector movedVector = newLocation - startPos;
startPos = newLocation;
distanceTraveled += movedVector.Size();
}
if (distanceTraveled > maxDistance)
{
Finish();
break;
}
m_fixedTimer -= delta;
}
if(m_finished && autoDestroy)
{
if((m_finishTimer -= DeltaTime) <= 0.0f)
{
Destroy();
}
}
}
void AProjectileBase::m_OnOverlapBegin(class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
ANetworkCharacter* netChar = Cast<ANetworkCharacter>(OtherActor);
if(netChar && ULib::CheckAbilityFilter(filter, character, netChar))
{
OnProjectileHit(netChar);
}
}
void AProjectileBase::m_OnHit(class AActor* OtherActor, class UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult& Hit)
{
Finish();
}
void AProjectileBase::Finish_Implementation()
{
if(!m_finished)
{
if(Role == ROLE_Authority)
{
NativeServerOnFinish();
}
NativeOnProjectileFinished();
if(collider)
collider->SetCollisionEnabled(ECollisionEnabled::NoCollision);
m_finishTimer = keepAliveAfterFinish;
m_finished = true;
}
}
void AProjectileBase::FixedProjectileTick_Implementation(float DeltaTime)
{
}
void AProjectileBase::OnProjectileHit_Implementation(ANetworkCharacter* character)
{
NativeOnProjectileHit(character);
}
void AProjectileBase::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
DOREPLIFETIME_CONDITION(AProjectileBase, speed, COND_InitialOnly);
DOREPLIFETIME_CONDITION(AProjectileBase, filter, COND_InitialOnly);
DOREPLIFETIME_CONDITION(AProjectileBase, maxDistance, COND_InitialOnly);
DOREPLIFETIME_CONDITION(AProjectileBase, autoMove, COND_InitialOnly);
DOREPLIFETIME_CONDITION(AProjectileBase, autoDestroy, COND_InitialOnly);
}
void AProjectileBase::Move(float DeltaTime)
{
NativeMove(DeltaTime);
}
void AProjectileBase::NativeMove(float DeltaTime)
{
//moves with sweep to get collision
float distance = speed * DeltaTime;
AddActorWorldOffset(GetActorForwardVector() * distance,true);
}
void AProjectileBase::OnProjectileFinished_Implementation()
{
}
void AProjectileBase::NativeOnProjectileFinished()
{
OnProjectileFinished();
}
void AProjectileBase::NativeOnProjectileHit(ANetworkCharacter* hitCharacter)
{
}
void AProjectileBase::NativeServerOnFinish()
{
ServerOnFinish();
}

View File

@@ -0,0 +1,78 @@
// Project Lab - NHTV Igad
#pragma once
#include "DealDamageProxy.h"
#include "ProjectileBase.generated.h"
/**
*
*/
UCLASS()
class UNREALPROJECT_API AProjectileBase : public ADealDamageProxy
{
GENERATED_BODY()
public:
AProjectileBase();
virtual void BeginPlay() override;
virtual void Tick(float DeltaSeconds) override;
UFUNCTION(BlueprintNativeEvent, Category = "Projectile")
void FixedProjectileTick(float DeltaTime);
virtual void NativeFixedProjectileTick(float DeltaTime);
UFUNCTION(BlueprintCallable, Category = "Projectile")
void Move(float DeltaTime);
virtual void NativeMove(float DeltaTime);
UFUNCTION(BlueprintCallable, Category = "Projectile")
bool IsFinished() const { return m_finished; }
UFUNCTION(BlueprintNativeEvent, Category = "Projectile")
void OnProjectileFinished();
virtual void NativeOnProjectileFinished();
UFUNCTION(BlueprintNativeEvent, Category = "Projectile")
void OnProjectileHit(ANetworkCharacter* hitCharacter);
virtual void NativeOnProjectileHit(ANetworkCharacter* hitCharacter);
virtual void NativeServerOnFinish();
UFUNCTION(BlueprintImplementableEvent, Category = "Project")
void ServerOnFinish();
// Transfers projectile to the finished state, disabling collision, but still updating ticks
UFUNCTION(BlueprintCallable, NetMulticast, Reliable, Category = "Projectile")
void Finish();
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Replicated, Category = "Projectile", meta = (ExposeOnSpawn))
float speed;
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Replicated, Category = "Projectile", meta = (ExposeOnSpawn))
EAbilityFilter filter;
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Replicated, Category = "Projectile", meta = (ExposeOnSpawn))
float maxDistance;
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Replicated, Category = "Projectile", meta = (ExposeOnSpawn))
bool autoMove = true;
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Replicated, Category = "Projectile", meta = (ExposeOnSpawn))
bool autoDestroy = true;
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = "Projectile")
float distanceTraveled;
UPROPERTY(BlueprintReadOnly, EditDefaultsOnly, Category = "Projectile")
float keepAliveAfterFinish;
UPROPERTY(BlueprintReadOnly, Category = "Projectile")
UPrimitiveComponent* collider;
protected:
// Internal event handlers
UFUNCTION()
void m_OnOverlapBegin(class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult);
UFUNCTION()
void m_OnHit(class AActor* OtherActor, class UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult& Hit);
bool m_finished;
float m_finishTimer;
float m_fixedTimer;
};

View File

@@ -0,0 +1,12 @@
#pragma once
#include "ScalingGraph.Generated.h"
UCLASS()
class ULevelScaleLibrary : public UBlueprintFunctionLibrary
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintCallable, Category = "Scaling Graph")
static float ScaleGraphCurveFloat(float in, const UCurveFloat* val);
};

View File

@@ -0,0 +1,34 @@
// Project Lab - NHTV Igad
#include "UnrealProject.h"
#include "NetworkCharacter.h"
#include "SpiralProjectile.h"
#define SPIRALTIMESTEP (0.02f)
void ASpiralProjectile::BeginPlay()
{
Super::BeginPlay();
if (Role != ROLE_Authority)
return;
// Set the rotation of the projectile so that it is facing away from the caster.
SetActorRotation(FRotator((this->GetActorLocation() - character->GetActorLocation()).Rotation()));
m_elapsedTime = 0;
}
void ASpiralProjectile::NativeMove(float DeltaTime)
{
m_elapsedTime += DeltaTime;
// Fixed update
while (m_elapsedTime >= SPIRALTIMESTEP)
{
m_elapsedTime -= SPIRALTIMESTEP;
float distance = speed * SPIRALTIMESTEP;
// Rotate the projectile according to how far it has traveled.
FRotator rotation = FRotator(0, distance * 0.25f, 0);
AddActorWorldRotation(rotation);
// Move the projectile forwards.
AddActorWorldOffset(GetActorForwardVector() * (distance * 2), true);
}
}

View File

@@ -0,0 +1,22 @@
// Project Lab - NHTV Igad
#pragma once
#include "ProjectileBase.h"
#include "SpiralProjectile.generated.h"
/**
*
*/
UCLASS()
class UNREALPROJECT_API ASpiralProjectile : public AProjectileBase
{
GENERATED_BODY()
public:
virtual void BeginPlay() override;
virtual void NativeMove(float DeltaTime) override;
private:
float m_elapsedTime;
};

View File

@@ -0,0 +1,28 @@
// Project Lab - NHTV Igad
#include "UnrealProject.h"
#include "TrailActor.h"
ATrailActor::ATrailActor()
{
}
void ATrailActor::BeginPlay()
{
Super::BeginPlay();
}
void ATrailActor::DynamicDestroy()
{
Destroy();
}
void ATrailActor::DynamicAdd()
{
GetOwner()->OnDestroyed.AddDynamic(this, &ATrailActor::DynamicDestroy);
}

View File

@@ -0,0 +1,21 @@
// Project Lab - NHTV Igad
#pragma once
#include "GameFramework/Actor.h"
#include "TrailActor.generated.h"
UCLASS()
class UNREALPROJECT_API ATrailActor : public AActor
{
GENERATED_BODY()
public:
ATrailActor();
virtual void BeginPlay() override;
UFUNCTION()
void DynamicDestroy();
void DynamicAdd();
};

View File

@@ -0,0 +1,93 @@
// Project Lab - NHTV Igad
#include "UnrealProject.h"
#include "TrailTrigger.h"
#include "Networkcharacter.h"
#include "TrailActor.h"
#include "Effect.h"
#include "EffectFunctionLibrary.h"
ATrailTrigger::ATrailTrigger()
{
}
void ATrailTrigger::BeginPlay()
{
Super::BeginPlay();
if (Role == ROLE_Authority)
{
if (character == NULL)
{
FERROR("m_character is NULL");
Destroy();
return;
}
m_lastPos = character->GetActorLocation();
SpawnTrail(FVector(0, 0, 0), true);
}
}
void ATrailTrigger::SpawnTrail(FVector offset, bool first)
{
m_lastPos += offset;
UCapsuleComponent* newobject = NewObject<UCapsuleComponent>(this);
newobject->SetCollisionProfileName(TEXT("Triggers"));
newobject->SetCapsuleRadius(colliderRadius, false);
newobject->SetCapsuleHalfHeight(500, false);
newobject->SetWorldLocation(m_lastPos);
newobject->OnComponentBeginOverlap.AddDynamic(this, &AAbilityTriggerBase::OnOverlapBegin);
newobject->OnComponentEndOverlap.AddDynamic(this, &AAbilityTriggerBase::OnOverlapEnd);
newobject->RegisterComponent();
if(first)
RootComponent = newobject;
FTransform effectTransform;
effectTransform.SetTranslation(m_lastPos);
effectTransform.SetRotation(character->GetActorRotation().Quaternion());
UEffectFunctionLibrary::CreateEffectAt(this, trailEffectClass, effectTransform,0.0f,lifeTime);
//ATrailActor* newTrailActor = GetWorld()->SpawnActor<ATrailActor>(trailActors);
//if (newTrailActor == nullptr)
// return;6
//newTrailActor->SetActorLocation(m_lastPos);
//newTrailActor->SetOwner(this);
//newTrailActor->DynamicAdd();
}
void ATrailTrigger::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
if (Role != ROLE_Authority || !IsValid(this))
return;
if (colliderSpawnDistance == 0)
{
FERROR("colliderSpawnDistance == 0");
return;
}
//m_timer += DeltaTime;
if ( !character ) return;
FVector distvec = character->GetActorLocation() - m_lastPos;
distvec.Z = 0;
float dist = distvec.Size();
m_totalTimer += DeltaTime;
lifeTime -= DeltaTime;
if (lifeTime < 0)
{
Destroy();
return;
}
if (m_totalTimer > totalSpawnTime)
{
return;
}
while (dist > colliderSpawnDistance)
{
UCapsuleComponent* newobject = NewObject<UCapsuleComponent>(this);
distvec.Normalize();
dist -= colliderSpawnDistance;
SpawnTrail(distvec *colliderSpawnDistance);
}
}

View File

@@ -0,0 +1,40 @@
// Project Lab - NHTV Igad
#pragma once
#include "Abilities/AbilityTriggerBase.h"
#include "TrailTrigger.generated.h"
/**
*
*/
UCLASS()
class UNREALPROJECT_API ATrailTrigger : public AAbilityTriggerBase
{
GENERATED_BODY()
public:
virtual void BeginPlay() override;
ATrailTrigger();
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Trigger", meta = (ClampMin = "0", UIMin = "0"))
float totalSpawnTime = 1.5f;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Trigger", meta = (ClampMin = "0", UIMin = "0"))
float lifeTime = 5.0f;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Trigger", meta = (ClampMin = "0", UIMin = "0"))
float colliderSpawnDistance = 50.0f;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Trigger", meta = (ClampMin = "0", UIMin = "0"))
float colliderRadius = 50.0f;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Trigger", meta = (ClampMin = "0", UIMin = "0"))
TSubclassOf<class AEffect> trailEffectClass;
virtual void Tick(float DeltaSeconds) override;
private:
void SpawnTrail(FVector offset, bool first = false);
float m_tickTimer = 0.0f;
FVector m_lastPos;
float m_totalTimer = 0.0f;
};

View File

@@ -0,0 +1,52 @@
// Project Lab - NHTV Igad
#include "UnrealProject.h"
#include "poisonAuraTrigger.h"
#include "NetworkCharacter.h"
#include "NativeModifiers.h"
#include "Modifier.h"
ApoisonAuraTrigger::ApoisonAuraTrigger()
{
}
void ApoisonAuraTrigger::BeginPlay()
{
Super::BeginPlay();
}
void ApoisonAuraTrigger::Tick(float deltaTime)
{
Super::Tick(deltaTime);
}
void ApoisonAuraTrigger::HitEvent(ANetworkCharacter* otherActor)
{
ModifierManager* manager = otherActor->GetModifierManager();
if (playerMap.Find(otherActor) == nullptr)
{
RERROR("2 modifiers in the intimidatin aura");
}
if (manager)
{
ADOTModifier* ASModifier = GetWorld()->SpawnActor<ADOTModifier>();
ASModifier->lifeTime = 0;
ASModifier->damagePerTick = damage;
ASModifier->target = otherActor;
manager->AddModifier(ASModifier);
playerMap.Add(otherActor, ASModifier);
}
return Super::HitEvent(otherActor);
}
void ApoisonAuraTrigger::LeaveEvent(ANetworkCharacter* otherActor)
{
auto it = playerMap.Find(otherActor);
if (it == nullptr)
return Super::LeaveEvent(otherActor);
(*it)->ForceDestroy();
playerMap.Remove(otherActor);
return Super::LeaveEvent(otherActor);
}

View File

@@ -0,0 +1,28 @@
// Project Lab - NHTV Igad
#pragma once
#include <map>
#include "Abilities/ConeTrigger.h"
#include "poisonAuraTrigger.generated.h"
/**
*
*/
UCLASS()
class UNREALPROJECT_API ApoisonAuraTrigger : public AConeTrigger
{
GENERATED_BODY()
public:
ApoisonAuraTrigger();
virtual void BeginPlay() override;
virtual void Tick(float DeltaSeconds) override;
virtual void HitEvent(class ANetworkCharacter* otherActor)override;
virtual void LeaveEvent(class ANetworkCharacter* otherActor)override;
UPROPERTY()
TMap<class ANetworkCharacter*, class AModifier* > playerMap;
UPROPERTY(meta = (ExposeOnSpawn), BlueprintReadWrite)
float damage;
};