The open source repository for the action RPG game in development by Sig Productions titled 'Adventures in Lestoria'!
https://forums.lestoria.net
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
815 lines
36 KiB
815 lines
36 KiB
#pragma region License
|
|
/*
|
|
License (OLC-3)
|
|
~~~~~~~~~~~~~~~
|
|
|
|
Copyright 2024 Joshua Sigona <sigonasr2@gmail.com>
|
|
|
|
Redistribution and use in source and binary forms, with or without modification,
|
|
are permitted provided that the following conditions are met:
|
|
|
|
1. Redistributions or derivations of source code must retain the above copyright
|
|
notice, this list of conditions and the following disclaimer.
|
|
|
|
2. Redistributions or derivative works in binary form must reproduce the above
|
|
copyright notice. This list of conditions and the following disclaimer must be
|
|
reproduced in the documentation and/or other materials provided with the distribution.
|
|
|
|
3. Neither the name of the copyright holder nor the names of its contributors may
|
|
be used to endorse or promote products derived from this software without specific
|
|
prior written permission.
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
|
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
|
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
|
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
|
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
SUCH DAMAGE.
|
|
|
|
Portions of this software are copyright © 2024 The FreeType
|
|
Project (www.freetype.org). Please see LICENSE_FT.txt for more information.
|
|
All rights reserved.
|
|
*/
|
|
#pragma endregion
|
|
#pragma once
|
|
#include "olcUTIL_Animate2D.h"
|
|
#include "Animation.h"
|
|
#include "Monster.h"
|
|
#include "State.h"
|
|
#include "Ability.h"
|
|
#include "Buff.h"
|
|
#include "Pathfinding.h"
|
|
#include "config.h"
|
|
#include "Key.h"
|
|
#include "Class.h"
|
|
#include "Item.h"
|
|
#include "AttributableStat.h"
|
|
#include "Timer.h"
|
|
#include "PlayerTimerType.h"
|
|
|
|
|
|
#undef GetClassName
|
|
struct DamageNumber;
|
|
class MenuComponent;
|
|
struct Ability;
|
|
|
|
struct CastInfo{
|
|
std::string name="???";
|
|
float castTimer=0.f;
|
|
float castTotalTime=0.f;
|
|
vf2d castPos{};
|
|
};
|
|
|
|
namespace MoveFlag{
|
|
enum MoveFlag{
|
|
NONE = 0b0,
|
|
PREVENT_CAST_CANCELLING = 0b1,
|
|
};
|
|
};
|
|
|
|
namespace PlayerTest{
|
|
class PlayerTests;
|
|
}
|
|
|
|
class EntityStats{
|
|
friend class Inventory;
|
|
ItemAttributable equipStats; //The stats after gear calculations are applied.
|
|
ItemAttributable baseStats;
|
|
public:
|
|
void RecalculateEquipStats(); //Called when equipment is updated.
|
|
const ItemAttributable&GetStats()const;
|
|
const ItemAttributable&GetBaseStats()const;
|
|
//Get stats with equipment applied.
|
|
const float&GetEquipStat(ItemAttribute stat)const;
|
|
//Get stats with equipment applied.
|
|
const float&GetEquipStat(std::string_view stat)const;
|
|
const float&GetBaseStat(ItemAttribute stat)const;
|
|
const float&GetBaseStat(std::string_view stat)const;
|
|
void SetBaseStat(ItemAttribute a,float val);
|
|
void SetBaseStat(std::string_view a,float val);
|
|
void Reset();
|
|
};
|
|
|
|
class Player{
|
|
friend class AiL;
|
|
friend class sig::Animation;
|
|
friend struct Warrior;
|
|
friend struct Thief;
|
|
friend struct Ranger;
|
|
friend struct Trapper;
|
|
friend struct Wizard;
|
|
friend struct Witch;
|
|
friend class State_GameRun;
|
|
friend class Inventory;
|
|
friend class ItemInfo;
|
|
friend void ItemOverlay::Draw();
|
|
public:
|
|
Player();
|
|
//So this is rather fascinating and only exists because we have the ability to change classes which means we need to initialize a class
|
|
//using a new object type... Because of that we'll take the pointer reference to the old object and copy some of its properties to this new
|
|
//one. It's hackish but it means we can reduce the amount of extra boilerplate when class changing...I don't know how to feel about this.
|
|
Player(Player*player);
|
|
static float GROUND_SLAM_SPIN_TIME;
|
|
const vf2d&GetPos()const;
|
|
float GetX();
|
|
float GetY();
|
|
float GetZ();
|
|
const float&GetEquipStat(ItemAttribute a)const;
|
|
const float&GetEquipStat(std::string_view a)const;
|
|
const float&GetBaseStat(ItemAttribute a)const;
|
|
const float&GetBaseStat(std::string_view a)const;
|
|
void SetBaseStat(std::string_view a,float val);
|
|
void SetBaseStat(ItemAttribute a,float val);
|
|
const int GetMaxHealth()const;
|
|
const int GetHealth()const;
|
|
const int GetMana()const;
|
|
const int GetMaxMana()const;
|
|
const int GetAttack()const;
|
|
const int GetDefense()const;
|
|
const float GetDamageReductionFromBuffs()const;
|
|
const float GetDefenseDamageReductionLookup()const;
|
|
float GetMoveSpdMult();
|
|
float GetSizeMult()const;
|
|
const float GetCooldownReductionPct()const;
|
|
const float GetCritRatePct()const;
|
|
const float GetCritDmgPct()const;
|
|
const float GetHPRecoveryPct()const;
|
|
const float GetHP6RecoveryPct()const;
|
|
const float GetHP4RecoveryPct()const;
|
|
const float GetAttackRecoveryRateReduction()const;
|
|
void SetSizeMult(float size);
|
|
float GetAttackRange(); //Returns the player's attack range in units. Divide by 100 for number of tiles.
|
|
float GetSpinAngle();
|
|
State::State GetState();
|
|
Key GetFacingDirection()const;
|
|
vf2d GetVelocity();
|
|
bool HasIframes();
|
|
void Update(float fElapsedTime);
|
|
void UpdateWalkingAnimation(Key direction, const float frameMult=1.f);
|
|
void UpdateIdleAnimation(Key direction);
|
|
//The range is the search range in tiles.
|
|
bool CanPathfindTo(vf2d pos,vf2d targetPos,float range=8);
|
|
bool CanMove();
|
|
bool CanAct();
|
|
const bool CanAct(const Ability&ability);
|
|
void Knockback(vf2d vel);
|
|
void ProximityKnockback(const vf2d centerPoint,const float knockbackFactor);
|
|
void ApplyIframes(float duration);
|
|
//NOTE: Will directly override the iframe timer for the player, as opposed to _ApplyIframes which actually keeps the longest current iframe time.
|
|
void _SetIframes(float duration);
|
|
void RestoreMana(int amt,bool suppressDamageNumber=false);
|
|
void ConsumeMana(int amt);
|
|
//Returns true if the move was valid and successful.
|
|
bool SetX(float x,MoveFlag::MoveFlag flags=MoveFlag::NONE);
|
|
//Returns true if the move was valid and successful.
|
|
bool SetY(float y,MoveFlag::MoveFlag flags=MoveFlag::NONE);
|
|
void SetZ(float z);
|
|
//Returns true if the move was valid and successful.
|
|
bool SetPos(vf2d pos,MoveFlag::MoveFlag flags=MoveFlag::NONE);
|
|
//Ignores collision checking and sets the player at the given position.
|
|
void ForceSetPos(vf2d pos);
|
|
void SetState(State::State newState);
|
|
|
|
void AddBuff(BuffType type,float duration,float intensity);
|
|
//NOTE: If adding a % increase stat, please use the percentage version! 100% = 1!!
|
|
void AddBuff(BuffType type,float duration,float intensity,std::set<ItemAttribute>attr);
|
|
//NOTE: If adding a % increase stat, please use the percentage version! 100% = 1!!
|
|
void AddBuff(BuffType type,float duration,float intensity,std::set<std::string>attr);
|
|
void AddBuff(BuffType type,float duration,float intensity,Buff::PlayerBuffExpireCallbackFunction expireCallbackFunc);
|
|
void AddBuff(BuffRestorationType type,BuffOverTimeType::BuffOverTimeType overTimeType,float duration,float intensity,float timeBetweenTicks);
|
|
void AddBuff(BuffRestorationType type,BuffOverTimeType::BuffOverTimeType overTimeType,float duration,float intensity,float timeBetweenTicks,Buff::PlayerBuffExpireCallbackFunction expireCallbackFunc);
|
|
void AddBuff(BuffType type,BuffRestorationType restorationType,BuffOverTimeType::BuffOverTimeType overTimeType,float duration,float intensity,float timeBetweenTicks);
|
|
void AddBuff(BuffType type,BuffRestorationType restorationType,BuffOverTimeType::BuffOverTimeType overTimeType,float duration,float intensity,float timeBetweenTicks,Buff::PlayerBuffExpireCallbackFunction expireCallbackFunc);
|
|
const bool HasBuff(BuffType buff)const;
|
|
const std::vector<Buff>GetBuffs(BuffType buff)const;
|
|
const std::vector<Buff>GetStatBuffs(const std::vector<std::string>&attr)const;
|
|
|
|
using BuffDuration=float;
|
|
using BuffIntensity=float;
|
|
Buff&GetOrAddBuff(BuffType buff,std::pair<BuffDuration,BuffIntensity>newBuff);//When you need a buff added regardless if it already exists. You'll either modify an existing one or create a new one.
|
|
Buff&EditBuff(BuffType buff,size_t buffInd);
|
|
std::vector<std::reference_wrapper<Buff>>EditBuffs(BuffType buff);
|
|
//Removes the first buff found.
|
|
void RemoveBuff(BuffType type);
|
|
//Removes all buffs of a certain type.
|
|
void RemoveAllBuffs(BuffType type);
|
|
//Remove every buff.
|
|
void RemoveAllBuffs();
|
|
|
|
void UpdateHealthAndMana();
|
|
|
|
void RecalculateEquipStats();
|
|
|
|
bool Hurt(HurtDamageInfo damageData);
|
|
bool Hurt(int damage,bool onUpperLevel,float z,HurtFlag::HurtFlag hurtFlags=HurtFlag::NONE);
|
|
bool Hurt(int damage,bool onUpperLevel,float z,const TrueDamageFlag damageRule,HurtFlag::HurtFlag hurtFlags=HurtFlag::NONE);
|
|
//Return false if healing was not possible.
|
|
bool Heal(int damage,bool suppressDamageNumber=false);
|
|
//specificClass is a bitwise-combination of classes from the Class enum. It makes sure certain animations only play if you are a certain class.=
|
|
void UpdateAnimation(std::string animState,int specificClass=ANY,const float frameMult=1.f);
|
|
const Animate2D::Frame&GetFrame()const;
|
|
const Animate2D::Frame&GetCatFrame()const;
|
|
float GetSwordSwingTimer();
|
|
bool OnUpperLevel();
|
|
void ResetLastCombatTime();
|
|
bool IsOutOfCombat();
|
|
float GetEndZoneStandTime();
|
|
//Triggers when the player has moved.
|
|
void Moved(MoveFlag::MoveFlag flags=MoveFlag::NONE);
|
|
virtual ~Player()=default;
|
|
virtual Class GetClass()=0;
|
|
virtual bool AutoAttack()=0;
|
|
virtual void OnUpdate(float fElapsedTime)=0;
|
|
virtual const std::string&GetClassName()=0;
|
|
virtual Ability&GetRightClickAbility()=0;
|
|
virtual Ability&GetAbility1()=0;
|
|
virtual Ability&GetAbility2()=0;
|
|
virtual Ability&GetAbility3()=0;
|
|
virtual Ability&GetAbility4()=0;
|
|
virtual void SetAbility4(const Ability&originalAbility)=0; //NOTE: Make sure to provide the original ability and not a current ability!
|
|
virtual std::string&GetWalkNAnimation()=0;
|
|
virtual std::string&GetWalkEAnimation()=0;
|
|
virtual std::string&GetWalkSAnimation()=0;
|
|
virtual std::string&GetWalkWAnimation()=0;
|
|
virtual std::string&GetIdleNAnimation()=0;
|
|
virtual std::string&GetIdleEAnimation()=0;
|
|
virtual std::string&GetIdleSAnimation()=0;
|
|
virtual std::string&GetIdleWAnimation()=0;
|
|
|
|
geom2d::circle<float>Hitbox();
|
|
|
|
void CheckEndZoneCollision();
|
|
|
|
CastInfo&GetCastInfo();
|
|
//Provide the base animation name and this function does the rest. Ex. If you want WARRIOR_SWINGSWORD_S, use SWINGSWORD
|
|
void SetAnimationBasedOnTargetingDirection(const std::string_view animation_name,float targetDirection);
|
|
void SetAnimationBasedOnTarget(const std::string_view animation_name,const vf2d&target);
|
|
|
|
Ability&GetItem1();
|
|
Ability&GetItem2();
|
|
Ability&GetItem3();
|
|
|
|
void SetItem1UseFunc(Ability a);
|
|
void SetItem2UseFunc(Ability a);
|
|
void SetItem3UseFunc(Ability a);
|
|
void PerformHPRecovery();
|
|
|
|
static InputGroup KEY_ABILITY1, KEY_ABILITY2, KEY_ABILITY3, KEY_ABILITY4, KEY_DEFENSIVE, KEY_ITEM1, KEY_ITEM2, KEY_ITEM3;
|
|
static std::vector<std::weak_ptr<MenuComponent>>moneyListeners;
|
|
|
|
static void AddMoneyListener(std::weak_ptr<MenuComponent>component);
|
|
uint32_t GetMoney()const;
|
|
void SetMoney(uint32_t newMoney);
|
|
void AddMoney(const uint32_t moneyCost);
|
|
void RemoveMoney(const uint32_t moneyCost);
|
|
void AddXP(const uint64_t xpGain);
|
|
void OnLevelUp();
|
|
const uint8_t LevelCap()const;
|
|
const uint8_t Level()const;
|
|
const uint64_t CurrentXP()const;
|
|
const uint64_t TotalXP()const;
|
|
const uint64_t NextLevelXPRequired()const;
|
|
|
|
void CancelCast();
|
|
const ItemAttributable&GetStats()const;
|
|
const ItemAttributable&GetBaseStats()const;
|
|
void ResetAccumulatedXP();
|
|
const uint64_t GetAccumulatedXP()const;
|
|
void AddAccumulatedXP(const uint64_t xpGain);
|
|
//Knockup the player for duration amount of seconds, and Zamt pixels.
|
|
void Knockup(float duration);
|
|
static const bool INVERTED,USE_WALK_DIR;
|
|
const vf2d GetWorldAimingLocation(bool useWalkDir=false,bool invert=false);
|
|
void SetXP(const uint64_t xp);
|
|
void SetTotalXPEarned(const uint64_t totalXP);
|
|
void SetLevel(uint8_t newLevel);
|
|
void SetInvisible(const bool invisibleState);
|
|
const bool IsInvisible()const;
|
|
void ResetVelocity();
|
|
const float GetHealthGrowthRate()const;
|
|
const float GetAtkGrowthRate()const;
|
|
const float GetIframeTime()const;
|
|
const Renderable&GetMinimapImage()const;
|
|
void AddVelocity(vf2d vel);
|
|
const float GetHealthRatio()const;
|
|
const bool IsAlive()const;
|
|
//An all-in-one function that applies a stat plus any % modifiers the stat may have as well.
|
|
const float GetModdedStatBonuses(std::string_view stat)const;
|
|
//An all-in-one function that applies a stat plus any % modifiers the stat may have as well.
|
|
const float GetModdedStatBonuses(ItemAttribute stat)const;
|
|
//Flag to make the player character render using additive blending / normal blending.
|
|
void SetAdditiveBlending(const bool additiveBlending);
|
|
const bool IsUsingAdditiveBlending()const;
|
|
vf2d MoveUsingPathfinding(vf2d targetPos);
|
|
const std::unordered_set<std::string>&GetMyClass()const;
|
|
void ApplyDot(float duration,int damage,float timeBetweenTicks,Buff::PlayerBuffExpireCallbackFunction expireCallbackFunc=[](Player*p,Buff&b){});
|
|
const float GetDamageAmplificationMult()const;
|
|
const bool HasEnchant(const std::string_view enchantName)const;
|
|
void CheckAndPerformAbility(Ability&ability,InputGroup key);
|
|
void ReduceAutoAttackTimer(const float reduceAmt);
|
|
const float&GetAutoAttackTimer()const;
|
|
const vf2d GetFacingDirVector()const; //Returns a normalized vector based on the facing direction of the character. Ex. {0,-1} for north and {1,0} for east.
|
|
const bool PoisonArrowAutoAttackReady()const; //NOTE: Also checks to make sure we have the enchant built-in...
|
|
const int RemainingRapidFireShots()const;
|
|
const std::vector<std::reference_wrapper<Ability>>GetAbilities();//Returns player defensive, core abilities (1-4) and item abilities.
|
|
const bool HasEnchantWithAbilityAffected(const std::string_view abilityName)const; //Returns whether or not the player has an enchant that affects the provided name.
|
|
Timer&AddTimer(const PlayerTimerType type,const Timer&timer);
|
|
Timer&GetTimer(const PlayerTimerType type);
|
|
const bool HasTimer(const PlayerTimerType type)const;
|
|
void CancelTimer(const PlayerTimerType type);
|
|
void ResetTimers();
|
|
void _ForceCastSpell(Ability&ability);
|
|
using ShieldAmount=uint32_t;
|
|
ShieldAmount GetShield()const;
|
|
//NOTE: Shields of the same type will override each other! Create a timer type for each unique shield!
|
|
void AddShield(const ShieldAmount shieldAmt,const float shieldTimer, const PlayerTimerType shieldType);
|
|
ShieldAmount SubtractShield(const ShieldAmount shieldDamage); //Returns how much damage was not absorbed by shields.
|
|
const float GetManaRatio()const;
|
|
void OnLevelStart();
|
|
void NotEnoughManaDisplay(const std::string_view text,const float displayTime); //Red text for displayTime seconds.
|
|
void NotificationDisplay(const std::string_view text,const float displayTime); //Blue text for displayTime seconds.
|
|
void DeactivateCatForm();
|
|
const bool CatFormActive()const;
|
|
void UpdateAnimationStates();
|
|
void CastSpell(Ability&ability); //NOTE: This usually is not called unless we are running tests! CastSpell is meant to be used when we have chosen a pre-casting target position and have released the associated key to cast the spell.
|
|
void PrepareCast(Ability&ability); //NOTE: This usually is not called unless we are running tests! PrepareCast is meant to be used before we use CastSpell in unit tests.
|
|
void SetTestScreenAimingLocation(vf2d forcedAimingLoc);
|
|
private:
|
|
static std::vector<std::reference_wrapper<Ability>>ABILITY_LIST;
|
|
const int SHIELD_CAPACITY{32};
|
|
int hp="Warrior.BaseHealth"_I;
|
|
int mana="Player.BaseMana"_I;
|
|
float hpGrowthRate="Warrior.HealthGrowthRate"_F;
|
|
float atkGrowthRate="Warrior.AtkGrowthRate"_F;
|
|
vf2d pos;
|
|
uint8_t level=1;
|
|
uint8_t levelCap=1;
|
|
uint64_t totalXPEarned=0;
|
|
uint64_t currentLevelXP=0;
|
|
uint64_t accumulatedXP=0;
|
|
float z=0;
|
|
float size=1.0f;
|
|
float spin_attack_timer=0;
|
|
float rolling_timer{};
|
|
float spin_spd=0;
|
|
float spin_angle=0;
|
|
float lastAnimationFlip=0;
|
|
float manaTickTimer=0;
|
|
float hpRecoveryTimer=0;
|
|
float hp6RecoveryTimer=0;
|
|
float hp4RecoveryTimer=0;
|
|
float knockUpTimer=0.f;
|
|
float totalKnockupTime=0.f;
|
|
float knockUpZAmt=0.f;
|
|
//angle in polar coords.
|
|
vf2d aimingAngle{};
|
|
std::pair<std::string,float> notEnoughManaDisplay={"",0.f};
|
|
float teleportAttemptWaitTime=0; //If a teleport fails, we wait awhile before trying again, it's expensive.
|
|
State::State state=State::NORMAL;
|
|
Animate2D::Animation<std::string>animation;
|
|
void AddAnimation(std::string state);
|
|
std::vector<Buff>buffList;
|
|
CastInfo castInfo={"",0};
|
|
vf2d movementVelocity={};//This tells us if the player is moving (mostly controlled by user input) since their velocity is not used for regular movement.
|
|
float lastHitTimer=0; //When this is greater than zero, if we get hit again it adds to our displayed combo number.
|
|
float lastDotTimer=0; //When this is greater than zero, if we get hit again it adds to our displayed combo number.
|
|
std::shared_ptr<DamageNumber>damageNumberPtr,dotNumberPtr;
|
|
void Initialize();
|
|
float iframe_time=0;
|
|
float lastCombatTime=0;
|
|
float hurtRumbleTime=0.0f;
|
|
Ability useItem1;
|
|
Ability useItem2;
|
|
Ability useItem3;
|
|
uint32_t money="Player.Starting Money"_I;
|
|
EntityStats stats;
|
|
//So this is kind of a stupid one...
|
|
//If the attr provided is a % modifier, it will take the lhs in a += operation and multiply it by the % modifier from player's actual stats.
|
|
//If the attr provided is not a % modifier, it will add in a +=/+ operation...
|
|
const ItemAttribute&GetBonusStat(std::string_view attr)const;
|
|
bool rendered=false;
|
|
bool invisibility=false;
|
|
//Returns true if the move was valid and successful.
|
|
//If playerInvoked is true, this means the player was the one that instantiated this input, and it's not an extra movement done via collision.
|
|
//Set playerInvoked to false when you don't want a movement loop due to collisions.
|
|
//Typical usage is playerInvoked is true on first call, and playerInvoked is false on all subsequent chained calls.
|
|
bool _SetX(float x,MoveFlag::MoveFlag flags=MoveFlag::NONE,const bool playerInvoked=true);
|
|
//Returns true if the move was valid and successful.
|
|
//If playerInvoked is true, this means the player was the one that instantiated this input, and it's not an extra movement done via collision.
|
|
//Set playerInvoked to false when you don't want a movement loop due to collisions.
|
|
//Typical usage is playerInvoked is true on first call, and playerInvoked is false on all subsequent chained calls.
|
|
bool _SetY(float y,MoveFlag::MoveFlag flags=MoveFlag::NONE,const bool playerInvoked=true);
|
|
const bool UsingAutoAim()const;
|
|
void InitializeMinimapImage();
|
|
bool lowHealthSoundPlayed=false;
|
|
float lowHealthSoundPlayedTimer=0.f;
|
|
float rangerShootAnimationTimer=0.f;
|
|
Renderable minimapImg; //An image of the character represented on a minimap. Should be 12x12 and generally be a circle.
|
|
float deadlyDashWaitTimer{};
|
|
float deadlyDashAfterDashTimer{};
|
|
vf2d deadlyDashEndingPos{};
|
|
bool renderedSpriteUsesAdditiveBlending{false};
|
|
float deadlyDashAdditiveBlendingToggleTimer{};
|
|
std::unordered_set<std::string>myClass{};
|
|
float daggerThrowWaitTimer{INFINITY};
|
|
std::unordered_set<std::string>enchantList;
|
|
std::unordered_set<std::string>enchantAbilityList; //Which abilities are currently affected by our enchants.
|
|
void OnAbilityUse(const Ability&ability); //Callback when an ability successfully is used and has gone on cooldown.
|
|
const bool LastReserveEnchantConditionsMet()const;
|
|
float poisonArrowLastParticleTimer{};
|
|
const vf2d GetAimingLocation(bool useWalkDir=false,bool invert=false);
|
|
std::unordered_map<PlayerTimerType,Timer>timers;
|
|
void RunTimers();
|
|
float base_attack_range="Warrior.Auto Attack.Range"_F;
|
|
Renderable playerOutline;
|
|
void UpdatePlayerOutline();
|
|
void OnBuffAdd(Buff&newBuff);
|
|
std::vector<std::pair<PlayerTimerType,ShieldAmount>>shield;
|
|
bool catForm{false};
|
|
std::optional<vf2d>testAimingLoc{};
|
|
protected:
|
|
const float ATTACK_COOLDOWN="Warrior.Auto Attack.Cooldown"_F;
|
|
const float MAGIC_ATTACK_COOLDOWN="Wizard.Auto Attack.Cooldown"_F;
|
|
float ARROW_ATTACK_COOLDOWN="Ranger.Auto Attack.Cooldown"_F;
|
|
void SetSwordSwingTimer(float val);
|
|
void SetFacingDirection(Key direction);
|
|
void Spin(float duration,float spinSpd);
|
|
float friction="Player.Friction"_F;
|
|
float attack_cooldown_timer=0;
|
|
float teleportAnimationTimer=0;
|
|
vf2d teleportTarget={};
|
|
vf2d teleportStartPosition={};
|
|
std::pair<std::string,float> notificationDisplay={"",0.f};
|
|
bool upperLevel=false;
|
|
vf2d vel={0,0};
|
|
Key facingDirection=DOWN;
|
|
float swordSwingTimer=0;
|
|
Ability*castPrepAbility;
|
|
vf2d precastLocation={};
|
|
void SetVelocity(vf2d vel);
|
|
const float RETREAT_DISTANCE=24*"Ranger.Right Click Ability.RetreatDistance"_F/100;
|
|
float RETREAT_TIME="Ranger.Right Click Ability.RetreatTime"_F; //How long the Retreat ability takes.
|
|
const int RETREAT_GHOST_FRAMES=8;
|
|
const float RETREAT_GHOST_FRAME_DELAY=0.025f;
|
|
float ghostFrameTimer=0;
|
|
float ghostRemoveTimer=0;
|
|
float blockTimer=0;
|
|
float retreatTimer=0;
|
|
std::vector<vf2d>ghostPositions;
|
|
float rapidFireTimer=0;
|
|
int remainingRapidFireShots=0;
|
|
float endZoneStandTime=0;
|
|
float lastPathfindingCooldown=0.f;
|
|
const float RAPID_FIRE_SHOOT_DELAY="Ranger.Ability 1.ArrowDelay"_F;
|
|
const int RAPID_FIRE_SHOOT_AMOUNT="Ranger.Ability 1.ArrowCount"_I;
|
|
float footstepTimer=0.f;
|
|
float ySquishFactor{1.f};
|
|
size_t cooldownSoundInstance=std::numeric_limits<size_t>::max();
|
|
Renderable afterImage;
|
|
Animate2D::AnimationState internal_animState;
|
|
Animate2D::AnimationState internal_catAnimState;
|
|
float removeLineTimer{};
|
|
const float TIME_BETWEEN_LINE_REMOVALS{0.025f};
|
|
uint8_t scanLine{24}; //0-23.
|
|
void SetupAfterImage();
|
|
vf2d afterImagePos{};
|
|
float transformTargetDir{};
|
|
float leapTimer{};
|
|
float totalLeapTime{};
|
|
vf2d leapStartingPos{};
|
|
float poisonArrowReadyTimer{};
|
|
void ActivateCatForm();
|
|
virtual Ability&_GetOriginalAbility1()=0;
|
|
virtual Ability&_GetOriginalAbility2()=0;
|
|
virtual Ability&_GetOriginalAbility3()=0;
|
|
virtual Ability&_GetOriginalRightClickAbility()=0;
|
|
};
|
|
|
|
#pragma region Warrior
|
|
struct Warrior:Player{
|
|
static std::string name;
|
|
static Class cl;
|
|
static Ability rightClickAbility,ability1,ability2,ability3,ability4;
|
|
static std::string walk_n,walk_e,walk_s,walk_w,idle_n,idle_e,idle_s,idle_w;
|
|
static void Initialize();
|
|
Warrior();
|
|
Warrior(Player*player);
|
|
Class GetClass()override;
|
|
bool AutoAttack()override;
|
|
//Include only WARRIOR-specific implementations!
|
|
void OnUpdate(float fElapsedTime)override;
|
|
static void InitializeClassAbilities();
|
|
const std::string&GetClassName()override;
|
|
Ability&GetRightClickAbility()override;
|
|
Ability&GetAbility1()override;
|
|
Ability&GetAbility2()override;
|
|
Ability&GetAbility3()override;
|
|
Ability&GetAbility4()override;
|
|
virtual Ability&_GetOriginalAbility1()override;
|
|
virtual Ability&_GetOriginalAbility2()override;
|
|
virtual Ability&_GetOriginalAbility3()override;
|
|
virtual Ability&_GetOriginalRightClickAbility()override;
|
|
static Ability&GetOriginalAbility1();
|
|
static Ability&GetOriginalAbility2();
|
|
static Ability&GetOriginalAbility3();
|
|
static Ability&GetOriginalRightClickAbility();
|
|
void SetAbility4(const Ability&originalAbility)override; //NOTE: Make sure to provide the original ability and not a current ability!
|
|
std::string&GetWalkNAnimation()override;
|
|
std::string&GetWalkEAnimation()override;
|
|
std::string&GetWalkSAnimation()override;
|
|
std::string&GetWalkWAnimation()override;
|
|
std::string&GetIdleNAnimation()override;
|
|
std::string&GetIdleEAnimation()override;
|
|
std::string&GetIdleSAnimation()override;
|
|
std::string&GetIdleWAnimation()override;
|
|
static void CreateOriginalCopies();
|
|
static void ResetToOriginalAbilities();
|
|
private:
|
|
static Ability original_rightClickAbility,original_ability1,original_ability2,original_ability3,original_ability4;
|
|
};
|
|
#pragma endregion
|
|
|
|
#pragma region Thief
|
|
struct Thief:Player{
|
|
static std::string name;
|
|
static Class cl;
|
|
static Ability rightClickAbility,ability1,ability2,ability3,ability4;
|
|
static std::string walk_n,walk_e,walk_s,walk_w,idle_n,idle_e,idle_s,idle_w;
|
|
static void Initialize();
|
|
Thief();
|
|
Thief(Player*player);
|
|
Class GetClass()override;
|
|
bool AutoAttack()override;
|
|
//Include only THIEF-specific implementations!
|
|
void OnUpdate(float fElapsedTime)override;
|
|
static void InitializeClassAbilities();
|
|
const std::string&GetClassName()override;
|
|
Ability&GetRightClickAbility()override;
|
|
Ability&GetAbility1()override;
|
|
Ability&GetAbility2()override;
|
|
Ability&GetAbility3()override;
|
|
Ability&GetAbility4()override;
|
|
virtual Ability&_GetOriginalAbility1()override;
|
|
virtual Ability&_GetOriginalAbility2()override;
|
|
virtual Ability&_GetOriginalAbility3()override;
|
|
virtual Ability&_GetOriginalRightClickAbility()override;
|
|
static Ability&GetOriginalAbility1();
|
|
static Ability&GetOriginalAbility2();
|
|
static Ability&GetOriginalAbility3();
|
|
static Ability&GetOriginalRightClickAbility();
|
|
void SetAbility4(const Ability&originalAbility)override; //NOTE: Make sure to provide the original ability and not a current ability!
|
|
std::string&GetWalkNAnimation()override;
|
|
std::string&GetWalkEAnimation()override;
|
|
std::string&GetWalkSAnimation()override;
|
|
std::string&GetWalkWAnimation()override;
|
|
std::string&GetIdleNAnimation()override;
|
|
std::string&GetIdleEAnimation()override;
|
|
std::string&GetIdleSAnimation()override;
|
|
std::string&GetIdleWAnimation()override;
|
|
static void CreateOriginalCopies();
|
|
static void ResetToOriginalAbilities();
|
|
private:
|
|
static Ability original_rightClickAbility,original_ability1,original_ability2,original_ability3,original_ability4;
|
|
};
|
|
#pragma endregion
|
|
|
|
#pragma region Ranger
|
|
struct Ranger:Player{
|
|
static std::string name;
|
|
static Class cl;
|
|
static Ability rightClickAbility,ability1,ability2,ability3,ability4;
|
|
static std::string walk_n,walk_e,walk_s,walk_w,idle_n,idle_e,idle_s,idle_w;
|
|
static void Initialize();
|
|
Ranger();
|
|
Ranger(Player*player);
|
|
Class GetClass()override;
|
|
bool AutoAttack()override;
|
|
//Include only RANGER-specific implementations!
|
|
void OnUpdate(float fElapsedTime)override;
|
|
static void InitializeClassAbilities();
|
|
const std::string&GetClassName()override;
|
|
Ability&GetRightClickAbility()override;
|
|
Ability&GetAbility1()override;
|
|
Ability&GetAbility2()override;
|
|
Ability&GetAbility3()override;
|
|
Ability&GetAbility4()override;
|
|
virtual Ability&_GetOriginalAbility1()override;
|
|
virtual Ability&_GetOriginalAbility2()override;
|
|
virtual Ability&_GetOriginalAbility3()override;
|
|
virtual Ability&_GetOriginalRightClickAbility()override;
|
|
static Ability&GetOriginalAbility1();
|
|
static Ability&GetOriginalAbility2();
|
|
static Ability&GetOriginalAbility3();
|
|
static Ability&GetOriginalRightClickAbility();
|
|
void SetAbility4(const Ability&originalAbility)override; //NOTE: Make sure to provide the original ability and not a current ability!
|
|
std::string&GetWalkNAnimation()override;
|
|
std::string&GetWalkEAnimation()override;
|
|
std::string&GetWalkSAnimation()override;
|
|
std::string&GetWalkWAnimation()override;
|
|
std::string&GetIdleNAnimation()override;
|
|
std::string&GetIdleEAnimation()override;
|
|
std::string&GetIdleSAnimation()override;
|
|
std::string&GetIdleWAnimation()override;
|
|
static void CreateOriginalCopies();
|
|
static void ResetToOriginalAbilities();
|
|
private:
|
|
static Ability original_rightClickAbility,original_ability1,original_ability2,original_ability3,original_ability4;
|
|
};
|
|
#pragma endregion
|
|
|
|
#pragma region Trapper
|
|
struct Trapper:Player{
|
|
static std::string name;
|
|
static Class cl;
|
|
static Ability rightClickAbility,ability1,ability2,ability3,ability4;
|
|
static std::string walk_n,walk_e,walk_s,walk_w,idle_n,idle_e,idle_s,idle_w;
|
|
static void Initialize();
|
|
Trapper();
|
|
Trapper(Player*player);
|
|
Class GetClass()override;
|
|
bool AutoAttack()override;
|
|
//Include only TRAPPER-specific implementations!
|
|
void OnUpdate(float fElapsedTime)override;
|
|
static void InitializeClassAbilities();
|
|
const std::string&GetClassName()override;
|
|
Ability&GetRightClickAbility()override;
|
|
Ability&GetAbility1()override;
|
|
Ability&GetAbility2()override;
|
|
Ability&GetAbility3()override;
|
|
Ability&GetAbility4()override;
|
|
virtual Ability&_GetOriginalAbility1()override;
|
|
virtual Ability&_GetOriginalAbility2()override;
|
|
virtual Ability&_GetOriginalAbility3()override;
|
|
virtual Ability&_GetOriginalRightClickAbility()override;
|
|
static Ability&GetOriginalAbility1();
|
|
static Ability&GetOriginalAbility2();
|
|
static Ability&GetOriginalAbility3();
|
|
static Ability&GetOriginalRightClickAbility();
|
|
void SetAbility4(const Ability&originalAbility)override; //NOTE: Make sure to provide the original ability and not a current ability!
|
|
std::string&GetWalkNAnimation()override;
|
|
std::string&GetWalkEAnimation()override;
|
|
std::string&GetWalkSAnimation()override;
|
|
std::string&GetWalkWAnimation()override;
|
|
std::string&GetIdleNAnimation()override;
|
|
std::string&GetIdleEAnimation()override;
|
|
std::string&GetIdleSAnimation()override;
|
|
std::string&GetIdleWAnimation()override;
|
|
static void CreateOriginalCopies();
|
|
static void ResetToOriginalAbilities();
|
|
private:
|
|
static Ability original_rightClickAbility,original_ability1,original_ability2,original_ability3,original_ability4;
|
|
};
|
|
#pragma endregion
|
|
|
|
#pragma region Wizard
|
|
struct Wizard:Player{
|
|
static std::string name;
|
|
static Class cl;
|
|
static Ability rightClickAbility,ability1,ability2,ability3,ability4;
|
|
static std::string walk_n,walk_e,walk_s,walk_w,idle_n,idle_e,idle_s,idle_w;
|
|
static void Initialize();
|
|
Wizard();
|
|
Wizard(Player*player);
|
|
Class GetClass()override;
|
|
bool AutoAttack()override;
|
|
//Include only WIZARD-specific implementations!
|
|
void OnUpdate(float fElapsedTime)override;
|
|
static void InitializeClassAbilities();
|
|
const std::string&GetClassName()override;
|
|
Ability&GetRightClickAbility()override;
|
|
Ability&GetAbility1();
|
|
Ability&GetAbility2();
|
|
Ability&GetAbility3();
|
|
Ability&GetAbility4();
|
|
virtual Ability&_GetOriginalAbility1()override;
|
|
virtual Ability&_GetOriginalAbility2()override;
|
|
virtual Ability&_GetOriginalAbility3()override;
|
|
virtual Ability&_GetOriginalRightClickAbility()override;
|
|
static Ability&GetOriginalAbility1();
|
|
static Ability&GetOriginalAbility2();
|
|
static Ability&GetOriginalAbility3();
|
|
static Ability&GetOriginalRightClickAbility();
|
|
void SetAbility4(const Ability&originalAbility)override; //NOTE: Make sure to provide the original ability and not a current ability!
|
|
std::string&GetWalkNAnimation()override;
|
|
std::string&GetWalkEAnimation()override;
|
|
std::string&GetWalkSAnimation()override;
|
|
std::string&GetWalkWAnimation()override;
|
|
std::string&GetIdleNAnimation()override;
|
|
std::string&GetIdleEAnimation()override;
|
|
std::string&GetIdleSAnimation()override;
|
|
std::string&GetIdleWAnimation()override;
|
|
static void CreateOriginalCopies();
|
|
static void ResetToOriginalAbilities();
|
|
private:
|
|
static Ability original_rightClickAbility,original_ability1,original_ability2,original_ability3,original_ability4;
|
|
};
|
|
#pragma endregion
|
|
|
|
#pragma region Witch
|
|
struct Witch:Player{
|
|
static std::string name;
|
|
static Class cl;
|
|
static Ability rightClickAbility,ability1,ability2,ability3,ability4;
|
|
static std::string walk_n,walk_e,walk_s,walk_w,idle_n,idle_e,idle_s,idle_w;
|
|
static void Initialize();
|
|
Witch();
|
|
Witch(Player*player);
|
|
Class GetClass()override;
|
|
bool AutoAttack()override;
|
|
//Include only WITCHs-specific implementations!
|
|
void OnUpdate(float fElapsedTime)override;
|
|
static void InitializeClassAbilities();
|
|
const std::string&GetClassName()override;
|
|
Ability&GetRightClickAbility()override;
|
|
Ability&GetAbility1()override;
|
|
Ability&GetAbility2()override;
|
|
Ability&GetAbility3()override;
|
|
Ability&GetAbility4()override;
|
|
virtual Ability&_GetOriginalAbility1()override;
|
|
virtual Ability&_GetOriginalAbility2()override;
|
|
virtual Ability&_GetOriginalAbility3()override;
|
|
virtual Ability&_GetOriginalRightClickAbility()override;
|
|
static Ability&GetOriginalAbility1();
|
|
static Ability&GetOriginalAbility2();
|
|
static Ability&GetOriginalAbility3();
|
|
static Ability&GetOriginalRightClickAbility();
|
|
void SetAbility4(const Ability&originalAbility)override; //NOTE: Make sure to provide the original ability and not a current ability!
|
|
std::string&GetWalkNAnimation()override;
|
|
std::string&GetWalkEAnimation()override;
|
|
std::string&GetWalkSAnimation()override;
|
|
std::string&GetWalkWAnimation()override;
|
|
std::string&GetIdleNAnimation()override;
|
|
std::string&GetIdleEAnimation()override;
|
|
std::string&GetIdleSAnimation()override;
|
|
std::string&GetIdleWAnimation()override;
|
|
static void CreateOriginalCopies();
|
|
static void ResetToOriginalAbilities();
|
|
private:
|
|
static Ability original_rightClickAbility,original_ability1,original_ability2,original_ability3,original_ability4;
|
|
};
|
|
#pragma endregion
|
|
|
|
#define READFROMCONFIG(class,enum) \
|
|
class::name=#class".ClassName"_S; \
|
|
class::cl=enum; \
|
|
class::rightClickAbility={ \
|
|
#class".Right Click Ability.Name"_S, \
|
|
#class".Right Click Ability.Short Name"_S, \
|
|
#class".Right Click Ability.Description"_s.concat(), \
|
|
#class".Right Click Ability.Cooldown"_F, \
|
|
#class".Right Click Ability.Mana Cost"_I, \
|
|
&KEY_DEFENSIVE, \
|
|
"Ability Icons/"+#class".Right Click Ability.Icon"_S, \
|
|
{uint8_t(#class".Right Click Ability.Cooldown Bar Color 1"_f[0]),uint8_t(#class".Right Click Ability.Cooldown Bar Color 1"_f[1]),uint8_t(#class".Right Click Ability.Cooldown Bar Color 1"_f[2]),uint8_t(#class".Right Click Ability.Cooldown Bar Color 1"_f[3]==0?255:#class".Right Click Ability.Cooldown Bar Color 1"_f[3])}, \
|
|
{uint8_t(#class".Right Click Ability.Cooldown Bar Color 2"_f[0]),uint8_t(#class".Right Click Ability.Cooldown Bar Color 2"_f[1]),uint8_t(#class".Right Click Ability.Cooldown Bar Color 2"_f[2]),uint8_t(#class".Right Click Ability.Cooldown Bar Color 2"_f[3]==0?255:#class".Right Click Ability.Cooldown Bar Color 2"_f[3])}, \
|
|
{#class".Right Click Ability.Precast Time"_F,#class".Right Click Ability.Casting Range"_I/100.f*24,#class".Right Click Ability.Casting Size"_I/100.f*24}, \
|
|
bool( #class".Right Click Ability.CancelCast"_I ) \
|
|
}; \
|
|
class::ability1={ \
|
|
#class".Ability 1.Name"_S, \
|
|
#class".Ability 1.Short Name"_S, \
|
|
#class".Ability 1.Description"_s.concat(), \
|
|
#class".Ability 1.Cooldown"_F, \
|
|
#class".Ability 1.Mana Cost"_I, \
|
|
&KEY_ABILITY1, \
|
|
"Ability Icons/"+#class".Ability 1.Icon"_S, \
|
|
{uint8_t(#class".Ability 1.Cooldown Bar Color 1"_f[0]),uint8_t(#class".Ability 1.Cooldown Bar Color 1"_f[1]),uint8_t(#class".Ability 1.Cooldown Bar Color 1"_f[2]),uint8_t(#class".Ability 1.Cooldown Bar Color 1"_f[3]==0?255:#class".Ability 1.Cooldown Bar Color 1"_f[3])}, \
|
|
{uint8_t(#class".Ability 1.Cooldown Bar Color 2"_f[0]),uint8_t(#class".Ability 1.Cooldown Bar Color 2"_f[1]),uint8_t(#class".Ability 1.Cooldown Bar Color 2"_f[2]),uint8_t(#class".Ability 1.Cooldown Bar Color 2"_f[3]==0?255:#class".Ability 1.Cooldown Bar Color 2"_f[3])}, \
|
|
{#class".Ability 1.Precast Time"_F,#class".Ability 1.Casting Range"_I/100.f*24,#class".Ability 1.Casting Size"_I/100.f*24}, \
|
|
bool(#class".Ability 1.CancelCast"_I) \
|
|
}; \
|
|
class::ability2={ \
|
|
#class".Ability 2.Name"_S, \
|
|
#class".Ability 2.Short Name"_S, \
|
|
#class".Ability 2.Description"_s.concat(), \
|
|
#class".Ability 2.Cooldown"_F, \
|
|
#class".Ability 2.Mana Cost"_I, \
|
|
&KEY_ABILITY2, \
|
|
"Ability Icons/"+#class".Ability 2.Icon"_S, \
|
|
{uint8_t(#class".Ability 2.Cooldown Bar Color 1"_f[0]),uint8_t(#class".Ability 2.Cooldown Bar Color 1"_f[1]),uint8_t(#class".Ability 2.Cooldown Bar Color 1"_f[2]),uint8_t(#class".Ability 2.Cooldown Bar Color 1"_f[3]==0?255:#class".Ability 2.Cooldown Bar Color 1"_f[3])}, \
|
|
{uint8_t(#class".Ability 2.Cooldown Bar Color 2"_f[0]),uint8_t(#class".Ability 2.Cooldown Bar Color 2"_f[1]),uint8_t(#class".Ability 2.Cooldown Bar Color 2"_f[2]),uint8_t(#class".Ability 2.Cooldown Bar Color 2"_f[3]==0?255:#class".Ability 2.Cooldown Bar Color 2"_f[3])}, \
|
|
{#class".Ability 2.Precast Time"_F,#class".Ability 2.Casting Range"_I/100.f*24,#class".Ability 2.Casting Size"_I/100.f*24}, \
|
|
bool(#class".Ability 2.CancelCast"_I) \
|
|
}; \
|
|
class::ability3={ \
|
|
#class".Ability 3.Name"_S, \
|
|
#class".Ability 3.Short Name"_S, \
|
|
#class".Ability 3.Description"_s.concat(), \
|
|
#class".Ability 3.Cooldown"_F, \
|
|
#class".Ability 3.Mana Cost"_I, \
|
|
&KEY_ABILITY3, \
|
|
"Ability Icons/"+#class".Ability 3.Icon"_S, \
|
|
{uint8_t(#class".Ability 3.Cooldown Bar Color 1"_f[0]),uint8_t(#class".Ability 3.Cooldown Bar Color 1"_f[1]),uint8_t(#class".Ability 3.Cooldown Bar Color 1"_f[2]),uint8_t(#class".Ability 3.Cooldown Bar Color 1"_f[3]==0?255:#class".Ability 3.Cooldown Bar Color 1"_f[3])}, \
|
|
{uint8_t(#class".Ability 3.Cooldown Bar Color 2"_f[0]),uint8_t(#class".Ability 3.Cooldown Bar Color 2"_f[1]),uint8_t(#class".Ability 3.Cooldown Bar Color 2"_f[2]),uint8_t(#class".Ability 3.Cooldown Bar Color 2"_f[3]==0?255:#class".Ability 3.Cooldown Bar Color 2"_f[3])}, \
|
|
{#class".Ability 3.Precast Time"_F,#class".Ability 3.Casting Range"_I/100.f*24,#class".Ability 3.Casting Size"_I/100.f*24}, \
|
|
bool(#class".Ability 3.CancelCast"_I) \
|
|
}; \
|
|
class::ability4; \
|
|
Player::ABILITY_LIST.emplace_back(class::original_rightClickAbility); \
|
|
Player::ABILITY_LIST.emplace_back(class::original_ability1); \
|
|
Player::ABILITY_LIST.emplace_back(class::original_ability2); \
|
|
Player::ABILITY_LIST.emplace_back(class::original_ability3); |