#pragma once #include "olcPixelGameEngine.h" #include "Animation.h" #include "State.h" #include "Player.h" #include "olcUTIL_Animate2D.h" enum MonsterStrategy{ RUN_TOWARDS, SHOOT_AFAR }; enum MonsterName{ SLIME_GREEN, SLIME_BLUE, SLIME_RED, SLIME_YELLOW, /////////////////////////////////////////////////////////////////////////////////////////////////////////// /*//*/END,//Used for detecting the end of the list, DO NOT USE OR TOUCH. Add all monsters above this//*//*/ /////////////////////////////////////////////////////////////////////////////////////////////////////////// }; struct MonsterData{ private: int hp; int atk; float moveSpd;//1.0=100% float size; std::vector animations; MonsterStrategy strategy; MonsterName type; int collisionDmg; AnimationState jumpAnimation=AnimationState::WARRIOR_IDLE_S; AnimationState shootAnimation=AnimationState::WARRIOR_IDLE_S; AnimationState deathAnimation=AnimationState::WARRIOR_IDLE_S; public: MonsterData(); //When specifying animations, the first one will become the default animation. The last becomes the death animation. MonsterData(MonsterName type,int hp,int atk,std::vectoranimations,AnimationState jumpAnimation,AnimationState shootAnimation,AnimationState deathAnimation,float moveSpd=1.0f,float size=1.0f,MonsterStrategy strategy=RUN_TOWARDS,int collisionDmg=0); int GetHealth(); int GetAttack(); float GetMoveSpdMult(); float GetSizeMult(); MonsterName GetType(); MonsterStrategy GetAIStrategy(); int GetCollisionDmg(); AnimationState GetJumpAnimation(); AnimationState GetShootAnimation(); AnimationState GetDeathAnimation(); std::vectorGetAnimations(){ return animations; } }; struct Monster{ private: vf2d pos; vf2d vel={0,0}; float friction=400; vf2d target={0,0}; float targetAcquireTimer=0; int hp,maxhp; int atk; float moveSpd; float size; float attackCooldownTimer=0; float queueShotTimer=0; Key facingDirection; MonsterStrategy strategy; State state=State::NORMAL; Animate2D::Animationanimation; Animate2D::AnimationState internal_animState; float randomFrameOffset=0.f; float deathTimer=0.f; MonsterName type; std::vectorbuffList; AnimationState GetDeathAnimationName(); bool hasHitPlayer=false; bool canMove=true; //Set to false when stuck due to collisions. bool upperLevel=false; vf2d pathTarget={}; std::vectorpath; int pathIndex=0; protected: public: Monster()=delete; Monster(vf2d pos,MonsterData data,bool upperLevel=false); vf2d&GetPos(); int GetHealth(); int GetAttack(); float GetMoveSpdMult(); float GetSizeMult(); Animate2D::Frame GetFrame(); void UpdateAnimation(AnimationState state); bool Update(float fElapsedTime); //Returns true when damage is actually dealt (there is a death check here.) bool Hurt(int damage); bool IsAlive(); vf2d&GetTargetPos(); Key GetFacingDirection(); void Draw(); void Collision(Player&p); void Collision(Monster&p); void Collision(); void SetVelocity(vf2d vel); //Returns false if the monster could not be moved to the requested location due to collision. bool SetPosition(vf2d pos); //Returns false if the monster could not be moved to the requested location due to collision. bool SetX(float x); //Returns false if the monster could not be moved to the requested location due to collision. bool SetY(float y); void PerformJumpAnimation(); void PerformShootAnimation(); bool OnUpperLevel(); void Moved(); void StartPathfinding(float pathingTime); void PathAroundBehavior(float fElapsedTime); void AddBuff(BuffType type,float duration,float intensity); std::vectorGetBuffs(BuffType buff); }; struct MonsterSpawner{ private: vf2d pos; vf2d range; std::vector>monsters; bool triggered=false; bool upperLevel=false; public: MonsterSpawner(); //For the monster list, the second pair item is the position relative to the spawner to spawn the monster. MonsterSpawner(vf2d pos,vf2d range,std::vector>MONSTER_LIST,bool upperLevel=false); bool SpawnTriggered(); vf2d GetRange(); vf2d GetPos(); bool DoesUpperLevelSpawning(); void SetTriggered(bool trigger,bool spawnMonsters=true); friend std::ostream&operator<<(std::ostream&os,MonsterSpawner&rhs); };