// Project Lab - NHTV Igad #pragma once #include using std::unordered_map; #include "AbilityState.h" #include "ScalingGraph.h" #include "NetworkPossessable.h" #include "IngameSkillTree.h" #include "NetworkCharacter.generated.h" class ACreatureSpawn; DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FCharacterKilled, ANetworkCharacter*, killer, UAbilityInfo*, ability); DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(FOnDamageTaken, ANetworkCharacter*, dealer, int32, damage, UAbilityInfo*, ability); UCLASS(config = Game) class ANetworkCharacter : public ANetworkPossessable { GENERATED_BODY() public: ANetworkCharacter(); virtual void BeginPlay() override; virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override; virtual void Destroyed() override; virtual void OnDeath(UAbilityInfo* ability); void RegisterHealthBar(); void UnregisterHealthBar(); virtual void Tick(float DeltaSeconds) override; // This processes the learned abilities on the server and calls LearnSkills on the owning client void LearnSkills_Server(const TArray& skills); // This creates a list of all learned skills on the client's version of the character so that he gets an updated casting bar, etc. UFUNCTION(Client, Reliable) void LearnSkills(const TArray& skills); // The Buff/Modifier manager, for server side characters class ModifierManager* GetModifierManager(); UFUNCTION(BlueprintCallable, Category = "modifiers") TArray GetModifiersOfClass(TSubclassOf modifierClass); virtual void ResetModifiers(); void CheckStatsOverflow(); // Damage dealing UFUNCTION(BlueprintCallable, Category = "Damage", meta = (WorldContext="WorldContextObject")) int32 DealDamage(class UObject* WorldContextObject, int32 damage, float armorPercentageIgnore = 0.0f); virtual int32 NativeDealDamage(class ANetworkCharacter* dealer, int32 damage, float armorPercentageIgnore = 0.0f, UAbilityInfo* ability = nullptr); virtual void NativeOnKilled(class ANetworkCharacter* killer, class UAbilityInfo* ability); UFUNCTION(BlueprintCallable, Category = "Damage") void OnStandardAttack(ANetworkCharacter* targetCharacter); // Healing UFUNCTION(BlueprintCallable, Category = "Healing") void AddHealth(int32 health); virtual void NativeAddHealth(int32 health); void RemoveHealth(int32 health); void AddMana(float mana); void RemoveMana(float mana); UFUNCTION(BlueprintCallable, Category = "Damage") float GetTimeSinceDamage() const; UFUNCTION(BlueprintCallable, Category = "Animation") void TriggerSwingAnimation_Server(); UFUNCTION(BlueprintCallable, Category = "State") int32 GetHealth() const; UFUNCTION(BlueprintCallable, Category = "State") int32 GetMana() const; UFUNCTION(BlueprintCallable, Category = "State") int32 GetBlockedMana() const; UFUNCTION(BlueprintCallable, Category = "State") int32 GetMaxHealth() const; UFUNCTION(BlueprintCallable, Category = "State") int32 GetMaxMana() const; UFUNCTION(BlueprintCallable, Category = "State") int32 GetArmor() const; UFUNCTION(BlueprintCallable, Category = "State") bool GetHitable() const; UFUNCTION(BlueprintCallable, Category = "State") void SetHitable(bool hitable); UFUNCTION(BlueprintCallable, Category = "State") float GetDamageMultiplier() const; UFUNCTION(BlueprintCallable, Category = "State") float GetCooldownReduction() const; UFUNCTION(BlueprintCallable, Category = "State") float GetAttackSpeed() const; UFUNCTION(BlueprintCallable, Category = "State") float GetAttackDamage() const; UFUNCTION(BlueprintCallable, Category = "State") float GetMagicDamage() const; UFUNCTION(BlueprintCallable, Category = "State") float GetTotalDamage() const; UFUNCTION(BlueprintCallable, Category = "State") bool IsStunned() const; UFUNCTION(BlueprintCallable, Category = "State") bool CanRotate() const; UFUNCTION(BlueprintCallable, Category = "State") bool IsSilenced() const; UFUNCTION(BlueprintCallable, Category = "State") bool IsChanneling() const; UFUNCTION(BlueprintCallable, Category = "State") bool IsRanged() const; bool CanBeStunned() const; ANetworkCharacter* GetLastPlayerDamage() const; void CastAbility(int32 abilityIndex); void CastAbility(class UAbilityInfo* abilityInfo); // Returns the ability that is currently being casted(channeling) UFUNCTION(BlueprintCallable, Category = "Ability") class UAbilityInfo* GetCastingAbility(); // Gets the persistent state of an ability between casts class AAbilityState* GetAbilityState(class UAbilityInfo* abilityInfo); // Gets the toggle state for abilities that have isToggleAbility set bool GetAbilityToggleState(class UAbilityInfo* abilityInfo); bool m_initialised; // Minimap/FoW visibility bool IsVisible() const; // The collection of abilities this character has, for players. // The first ability in this array is always treated the character's basic attack, // and thus is affected by the attack speed variable of the character UPROPERTY(EditDefaultsOnly, Category = "Ability") TArray abilities; UPROPERTY(BlueprintReadOnly, Replicated, Category = "Ability") class UAbilityInfo* basicAttack; UPROPERTY(EditDefaultsOnly, Category = "Ability") TArray passives; UPROPERTY(Replicated, BlueprintReadOnly, Category = "Animation") int32 swingAnimationSequence; UPROPERTY(EditAnywhere, Category = "Experience Settings") int32 experienceGainOnKill; // Intervals at which damage and healing combat text are spawned UPROPERTY(EditAnywhere, Category = "Combat Text") float healthAccumTimer; UPROPERTY(EditAnywhere, Category = "Combat Text") float damageAccumTimer; // Duration before a team's damage is no longer valid // Gets refreshed when a team deals damage to the creature UPROPERTY(EditAnywhere, Category = "Team Damage Table") float teamDamageTimer; UPROPERTY(BlueprintAssignable, Category = "Character") FCharacterKilled onCharacterKilled; // SERVER ONLY UPROPERTY(BlueprintAssignable, Category = "Character") FOnDamageTaken onDamageTaken; METRICS_EXPR(Metrics::PlayerHandle* metricsHandle); protected: // Called when the character is spawned or reset to set initial modifiers like fixed health/mana-regen // overridable virtual void m_SpawnModifiers(); // This checks stunn state, etc. to allow NetworkPossessable to move virtual bool m_AllowedToMove() override; virtual bool m_AllowedToRotate() override; virtual void m_SetLevelStats(); UPROPERTY(EditDefaultsOnly, Category = "Stats") int32 baseMovementSpeed; UPROPERTY(EditDefaultsOnly, Category = "Stats") int32 baseArmor; UPROPERTY(EditDefaultsOnly, Category = "Stats") int32 passiveManaRegen; UPROPERTY(EditDefaultsOnly, Category = "Stats") int32 passiveHealthRegen; UPROPERTY(Replicated) int32 m_blockedMana; UPROPERTY(Replicated) float m_damageMultiplier; UPROPERTY(Replicated) float m_ignoreArmor; UPROPERTY(Replicated) float m_manaRegenMultiplier; UPROPERTY(Replicated) float m_manaUsageMultiplier; UPROPERTY(Replicated) float m_positiveEffectMultiplier; UPROPERTY(Replicated) float m_negativeEffectMultiplier; UPROPERTY(Replicated) float m_damageTakenMultiplier; UPROPERTY(Replicated) int32 m_armor; UPROPERTY(Replicated) bool m_stunned; UPROPERTY(Replicated) bool m_silenced; //sileneCount is the ammount of silences by modifiers, silence by casting is not taking into account. UPROPERTY(Replicated) uint32 m_silenceCount; UPROPERTY(Replicated) bool m_visible; UPROPERTY(Replicated) bool m_hitable; UPROPERTY(Replicated) bool m_isRanged; UPROPERTY(EditDefaultsOnly, Category = "Stats") bool canBeStunned; UPROPERTY(EditDefaultsOnly, Category = "Stats") bool canBeSilenced; UPROPERTY(Replicated) int32 m_health; UPROPERTY(Replicated) int32 m_maxHealth; UPROPERTY(Replicated) float m_mana; UPROPERTY(Replicated) int32 m_maxMana; UPROPERTY(Replicated) float m_cooldownReduction; UPROPERTY(Replicated) float m_attackSpeed; UPROPERTY(Replicated) float m_attackDamageMultiplier; UPROPERTY(Replicated) float m_magicDamageMultiplier; UPROPERTY(Replicated) bool m_usesMana; UPROPERTY(Replicated) float m_castingMovementspeedMultiplier; friend class ModifierManager; friend class APreCastAbilityEventGroup; friend class AIllusionCharacter; friend class ADefaultPlayerController; class ModifierManager* m_modifierManager; bool m_shouldBeDestroyed = false; private: // Request to the server to cast an ability UFUNCTION(Reliable, Server, WithValidation) void m_CastAbility_Server(class UAbilityInfo* ability); void m_InitAbilitySequence(class UAbilityInfo* ability, class AAbilityState* state); // Updates all the cooldown timers and ticks modifiers void m_TickAbilities(float DeltaSeconds); void m_SetAbilityCooldown(class UAbilityInfo* ability, class AAbilityState* state); // Server only casting interupt void m_InteruptSpellcasting(); // Called if we know an ability is successfully casted or not UFUNCTION(Reliable, Client) void m_OnAbilityCastConfirm(UAbilityInfo* ability, bool success, bool toggleState, float cooldown, float cooldownTime); void m_PreCast(UAbilityInfo* ability); // Called if we know an ability is successfully casted or not (server-side) virtual void m_OnAbilityCastConfirm_Server(UAbilityInfo* ability, bool success); // Callback for when an ability progresses to it's next state UFUNCTION() void m_OnAbilityEventGroupEnded(class UAbilityInfo* ability, class AAbilityEventGroup* current, class AAbilityEventGroup* next); friend class ADefaultPlayerState; // Active Stats struct DamagePeriod { DamagePeriod(int32 damage, float timer) : damage(damage), timer(timer) {} int32 damage; float timer; }; unordered_map m_damageAccum; int32 m_damageAccumValue; float m_damageAccumTimer; int32 m_healAccumValue; float m_healAccumTimer; float m_totalDamage; unordered_map m_teamDamageDealt; UPROPERTY() ANetworkCharacter* m_lastPlayerDamage; // Keeps ability persistent state between casts UPROPERTY() TMap m_abilityStates; // Keeps ability execution states / active group (server-side) UPROPERTY() TMap m_activeAbilities; friend class AModifier; friend class AVisibilityModifier; float m_timeSinceDamage; UPROPERTY() class AAbilityEventGroup* m_channelGroup; UPROPERTY(Replicated) class UAbilityInfo* m_castingAbility; UPROPERTY(Replicated) bool m_channelStun; UPROPERTY(Replicated) bool m_allowChannelRotation; class APreCastAbilityEventGroup* m_currentPreCast; };