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.
 
 
 
 
 
 
AdventuresInLestoria/Crawler/Player.h

380 lines
15 KiB

#pragma once
#include "olcUTIL_Animate2D.h"
#include "Animation.h"
#include "Monster.h"
#include "State.h"
#include "Ability.h"
#include "Class.h"
#include "Buff.h"
#include "Pathfinding.h"
#include "DamageNumber.h"
#include "config.h"
struct CastInfo{
std::string name;
float castTimer;
float castTotalTime;
vf2d castPos;
};
struct Player{
friend class Crawler;
friend class sig::Animation;
friend class Warrior;
friend class Thief;
friend class Ranger;
friend class Trapper;
friend class Wizard;
friend class Witch;
private:
int hp="Player.BaseHealth"_I,maxhp=hp;
int mana="Player.BaseMana"_I,maxmana=mana;
int atk="Player.BaseAtk"_I;
vf2d pos;
float z=0;
float moveSpd=1.0f;
float size=1.0f;
float spin_attack_timer=0;
float spin_spd=0;
float spin_angle=0;
float lastAnimationFlip=0;
float manaTickTimer=0;
std::pair<std::string,float> notEnoughManaDisplay={"",0};
float teleportAttemptWaitTime=0; //If a teleport fails, we wait awhile before trying again, it's expensive.
State state=State::NORMAL;
Animate2D::Animation<std::string>animation;
Animate2D::AnimationState internal_animState;
Key lastReleasedMovementKey;
void Update(float fElapsedTime);
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.
std::shared_ptr<DamageNumber>damageNumberPtr;
void Initialize();
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 SetState(State newState);
void SetFacingDirection(Key direction);
void SetLastReleasedMovementKey(Key k);
void Spin(float duration,float spinSpd);
//Returns true if the move was valid and successful.
bool SetX(float x);
//Returns true if the move was valid and successful.
bool SetY(float y);
void SetZ(float z);
//Returns true if the move was valid and successful.
bool SetPos(vf2d pos);
void Knockback(vf2d vel);
float friction="Player.Friction"_F;
float attack_cooldown_timer=0;
float iframe_time=0;
float teleportAnimationTimer=0;
vf2d teleportTarget={};
vf2d teleportStartPosition={};
std::pair<std::string,float> notificationDisplay={"",0};
bool upperLevel=false;
vf2d vel={0,0};
float attack_range="Warrior.Auto Attack.Range"_F/100.f;
Key facingDirection=DOWN;
float swordSwingTimer=0;
void CastSpell(Ability&ability);
Ability*castPrepAbility;
void PrepareCast(Ability&ability);
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.025;
float ghostFrameTimer=0;
float ghostRemoveTimer=0;
float blockTimer=0;
float retreatTimer=0;
std::vector<vf2d>ghostPositions;
float rapidFireTimer=0;
int remainingRapidFireShots=0;
const float RAPID_FIRE_SHOOT_DELAY="Ranger.Ability 1.ArrowDelay"_F;
const int RAPID_FIRE_SHOOT_AMOUNT="Ranger.Ability 1.ArrowCount"_I;
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;
vf2d&GetPos();
float GetX();
float GetY();
float GetZ();
int GetHealth();
int GetMaxHealth();
int GetMana();
int GetMaxMana();
int GetAttack();
float GetMoveSpdMult();
float GetSizeMult();
float GetAttackRangeMult();
float GetSpinAngle();
State GetState();
Key GetFacingDirection();
vf2d GetVelocity();
bool HasIframes();
void UpdateWalkingAnimation(Key direction);
void UpdateIdleAnimation(Key direction);
//The range is the search range in tiles.
bool CanPathfindTo(vf2d pos,vf2d targetPos,float range=8);
bool CanMove();
void AddBuff(BuffType type,float duration,float intensity);
std::vector<Buff>GetBuffs(BuffType buff);
void RemoveBuff(BuffType type); //Removes the first buff found.
void RemoveAllBuffs(BuffType type); //Removes all buffs of a certain type.
void RemoveAllBuffs(); //Remove every buff.
bool Hurt(int damage,bool onUpperLevel);
//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);
Animate2D::Frame GetFrame();
Key GetLastReleasedMovementKey();
float GetSwordSwingTimer();
bool OnUpperLevel();
//Triggers when the player has moved.
void Moved();
virtual ~Player()=default;
virtual Class GetClass()=0;
virtual bool AutoAttack()=0;
virtual void OnUpdate(float fElapsedTime)=0;
virtual 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 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;
CastInfo&GetCastInfo();
void SetAnimationBasedOnTargetingDirection(float targetDirection);
};
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();
std::string GetClassName()override;
Ability&GetRightClickAbility()override;
Ability&GetAbility1()override;
Ability&GetAbility2()override;
Ability&GetAbility3()override;
Ability&GetAbility4()override;
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;
};
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();
std::string GetClassName()override;
Ability&GetRightClickAbility()override;
Ability&GetAbility1()override;
Ability&GetAbility2()override;
Ability&GetAbility3()override;
Ability&GetAbility4()override;
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;
};
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();
std::string GetClassName()override;
Ability&GetRightClickAbility()override;
Ability&GetAbility1()override;
Ability&GetAbility2()override;
Ability&GetAbility3()override;
Ability&GetAbility4()override;
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;
};
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();
std::string GetClassName()override;
Ability&GetRightClickAbility()override;
Ability&GetAbility1()override;
Ability&GetAbility2()override;
Ability&GetAbility3()override;
Ability&GetAbility4()override;
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;
};
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();
std::string GetClassName()override;
Ability&GetRightClickAbility()override;
Ability&GetAbility1()override;
Ability&GetAbility2()override;
Ability&GetAbility3()override;
Ability&GetAbility4()override;
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;
};
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();
std::string GetClassName()override;
Ability&GetRightClickAbility()override;
Ability&GetAbility1()override;
Ability&GetAbility2()override;
Ability&GetAbility3()override;
Ability&GetAbility4()override;
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;
};
#define READFROMCONFIG(class,enum) \
class::name=#class".ClassName"_S; \
class::cl=enum; \
class::rightClickAbility={ \
#class".Right Click Ability.Name"_S, \
#class".Right Click Ability.Cooldown"_F, \
#class".Right Click Ability.Mana Cost"_I, \
{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} \
}; \
class::ability1={ \
#class".Ability 1.Name"_S, \
#class".Ability 1.Cooldown"_F, \
#class".Ability 1.Mana Cost"_I, \
{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} \
}; \
class::ability2={ \
#class".Ability 2.Name"_S, \
#class".Ability 2.Cooldown"_F, \
#class".Ability 2.Mana Cost"_I, \
{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} \
}; \
class::ability3={ \
#class".Ability 3.Name"_S, \
#class".Ability 3.Cooldown"_F, \
#class".Ability 3.Mana Cost"_I, \
{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} \
}; \
class::ability4={"???",0,0};