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.
455 lines
18 KiB
455 lines
18 KiB
/*
|
|
License (OLC-3)
|
|
~~~~~~~~~~~~~~~
|
|
|
|
Copyright 2018 - 2023 OneLoneCoder.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.
|
|
*/
|
|
#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 "DamageNumber.h"
|
|
#include "config.h"
|
|
#include "Key.h"
|
|
#include "Class.h"
|
|
#include "Item.h"
|
|
|
|
#undef GetClassName
|
|
|
|
struct CastInfo{
|
|
std::string name;
|
|
float castTimer;
|
|
float castTotalTime;
|
|
vf2d castPos;
|
|
};
|
|
|
|
struct Player{
|
|
friend class Crawler;
|
|
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;
|
|
private:
|
|
int hp="Warrior.BaseHealth"_I,maxhp=hp;
|
|
int mana="Player.BaseMana"_I,maxmana=mana;
|
|
int atk="Warrior.BaseAtk"_I;
|
|
float hpGrowthRate="Warrior.HealthGrowthRate"_F;
|
|
float atkGrowthRate="Warrior.AtkGrowthRate"_F;
|
|
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=State::NORMAL;
|
|
Animate2D::Animation<std::string>animation;
|
|
Animate2D::AnimationState internal_animState;
|
|
Key lastReleasedMovementKey;
|
|
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();
|
|
float iframe_time=0;
|
|
float lastCombatTime=0;
|
|
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 SetLastReleasedMovementKey(Key k);
|
|
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};
|
|
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;
|
|
float endZoneStandTime=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();
|
|
void SetSizeMult(float size);
|
|
float GetAttackRangeMult();
|
|
float GetSpinAngle();
|
|
State::State GetState();
|
|
Key GetFacingDirection();
|
|
vf2d GetVelocity();
|
|
bool HasIframes();
|
|
void Update(float fElapsedTime);
|
|
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();
|
|
bool CanAct();
|
|
bool CanAct(Ability&ability);
|
|
void Knockback(vf2d vel);
|
|
void SetIframes(float duration);
|
|
void RestoreMana(int amt);
|
|
void ConsumeMana(int amt);
|
|
//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 SetState(State::State newState);
|
|
|
|
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,float z);
|
|
//Return false if healing was not possible.
|
|
bool Heal(int damage);
|
|
//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();
|
|
void ResetLastCombatTime();
|
|
bool IsOutOfCombat();
|
|
float GetEndZoneStandTime();
|
|
//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;
|
|
|
|
void CheckEndZoneCollision();
|
|
|
|
CastInfo&GetCastInfo();
|
|
void SetAnimationBasedOnTargetingDirection(float targetDirection);
|
|
|
|
static InputGroup KEY_ABILITY1, KEY_ABILITY2, KEY_ABILITY3, KEY_ABILITY4, KEY_DEFENSIVE;
|
|
};
|
|
|
|
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.Short Name"_S, \
|
|
#class".Right Click Ability.Description"_S, \
|
|
#class".Right Click Ability.Cooldown"_F, \
|
|
#class".Right Click Ability.Mana Cost"_I, \
|
|
&KEY_DEFENSIVE, \
|
|
#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, \
|
|
#class".Ability 1.Cooldown"_F, \
|
|
#class".Ability 1.Mana Cost"_I, \
|
|
&KEY_ABILITY1, \
|
|
#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, \
|
|
#class".Ability 2.Cooldown"_F, \
|
|
#class".Ability 2.Mana Cost"_I, \
|
|
&KEY_ABILITY2, \
|
|
#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, \
|
|
#class".Ability 3.Cooldown"_F, \
|
|
#class".Ability 3.Mana Cost"_I, \
|
|
&KEY_ABILITY3, \
|
|
#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; |