diff --git a/Crawler/Animation.h b/Crawler/Animation.h index 25f0f7b9..5a6051c6 100644 --- a/Crawler/Animation.h +++ b/Crawler/Animation.h @@ -13,4 +13,5 @@ enum AnimationState{ RANGER_IDLE_S,RANGER_IDLE_E,RANGER_IDLE_N,RANGER_IDLE_W, WIZARD_WALK_S,WIZARD_WALK_E,WIZARD_WALK_N,WIZARD_WALK_W, WIZARD_IDLE_S,WIZARD_IDLE_E,WIZARD_IDLE_N,WIZARD_IDLE_W, + BATTLECRY_EFFECT, }; \ No newline at end of file diff --git a/Crawler/Buff.h b/Crawler/Buff.h new file mode 100644 index 00000000..f5097d48 --- /dev/null +++ b/Crawler/Buff.h @@ -0,0 +1,12 @@ +#pragma once +enum BuffType{ + ATTACK_UP, + DAMAGE_REDUCTION, + SLOWDOWN, +}; + +struct Buff{ + BuffType type; + float duration; + float intensity; +}; \ No newline at end of file diff --git a/Crawler/Crawler.cpp b/Crawler/Crawler.cpp index d652faec..91747706 100644 --- a/Crawler/Crawler.cpp +++ b/Crawler/Crawler.cpp @@ -41,6 +41,7 @@ bool Crawler::OnUserCreate(){ GFX_BLOCK_BUBBLE.Load("assets/block.png"); GFX_Ranger_Sheet.Load("assets/nico-ranger.png"); GFX_Wizard_Sheet.Load("assets/nico-wizard.png"); + GFX_Battlecry_Effect.Load("assets/battlecry_effect.png"); //Animations InitializeAnimations(); @@ -291,6 +292,11 @@ void Crawler::InitializeAnimations(){ } ANIMATION_DATA[AnimationState::GROUND_SLAM_ATTACK_BACK]=effect_groundslam_back; ANIMATION_DATA[AnimationState::GROUND_SLAM_ATTACK_FRONT]=effect_groundslam_front; + Animate2D::FrameSequence battlecry_effect(0.02f,Animate2D::Style::OneShot); + for(int i=0;i<5;i++){ + battlecry_effect.AddFrame({&GFX_Battlecry_Effect,{{i*84,0},{84,84}}}); + } + ANIMATION_DATA[AnimationState::BATTLECRY_EFFECT]=battlecry_effect; } bool Crawler::LeftHeld(){ @@ -606,7 +612,7 @@ void Crawler::RenderWorld(float fElapsedTime){ for(Monster&m:monstersBefore){ m.Draw(); } - view.DrawPartialRotatedDecal(player.GetPos()+vf2d{0,-player.GetZ()},player.GetFrame().GetSourceImage()->Decal(),player.GetSpinAngle(),{12,12},player.GetFrame().GetSourceRect().pos,player.GetFrame().GetSourceRect().size,vf2d(player.GetSizeMult(),player.GetSizeMult())); + view.DrawPartialRotatedDecal(player.GetPos()+vf2d{0,-player.GetZ()},player.GetFrame().GetSourceImage()->Decal(),player.GetSpinAngle(),{12,12},player.GetFrame().GetSourceRect().pos,player.GetFrame().GetSourceRect().size,vf2d(player.GetSizeMult(),player.GetSizeMult()),player.GetBuffs(BuffType::ATTACK_UP).size()>0?Pixel{255,uint8_t(255*abs(sin(1.4*player.GetBuffs(BuffType::ATTACK_UP)[0].duration))),uint8_t(255*abs(sin(1.4*player.GetBuffs(BuffType::ATTACK_UP)[0].duration)))}:WHITE); if(player.GetState()==State::BLOCK){ view.DrawDecal(player.GetPos()-vf2d{12,12},GFX_BLOCK_BUBBLE.Decal()); } @@ -696,6 +702,14 @@ void Crawler::AddEffect(Effect foreground,Effect background){ backgroundEffects.push_back(background); } +void Crawler::AddEffect(Effect foreground,bool back){ + if(back){ + backgroundEffects.push_back(foreground); + } else { + foregroundEffects.push_back(foreground); + } +} + vf2d Crawler::GetWorldMousePos(){ return GetMousePos()+view.GetWorldOffset(); } diff --git a/Crawler/Crawler.h b/Crawler/Crawler.h index 385c0be7..79d6257a 100644 --- a/Crawler/Crawler.h +++ b/Crawler/Crawler.h @@ -14,7 +14,8 @@ class Crawler : public olc::PixelGameEngine Player player; Renderable GFX_Warrior_Sheet,GFX_Slime_Sheet,GFX_Circle, GFX_Effect_GroundSlam_Back,GFX_Effect_GroundSlam_Front, - GFX_Heart,GFX_BLOCK_BUBBLE,GFX_Ranger_Sheet,GFX_Wizard_Sheet; + GFX_Heart,GFX_BLOCK_BUBBLE,GFX_Ranger_Sheet,GFX_Wizard_Sheet, + GFX_Battlecry_Effect; std::vectorforegroundEffects,backgroundEffects; public: @@ -33,6 +34,8 @@ public: void RenderWorld(float fElapsedTime); void RenderHud(); void AddEffect(Effect foreground,Effect background); + //If back is true, places the effect in the background + void AddEffect(Effect foreground,bool back=false); void HurtEnemies(vf2d pos,float radius,int damage); vf2d GetWorldMousePos(); bool LeftHeld(); diff --git a/Crawler/Crawler.vcxproj b/Crawler/Crawler.vcxproj index 9dc9de45..88829222 100644 --- a/Crawler/Crawler.vcxproj +++ b/Crawler/Crawler.vcxproj @@ -164,6 +164,7 @@ + diff --git a/Crawler/Crawler.vcxproj.filters b/Crawler/Crawler.vcxproj.filters index 23ba71d7..d916e1c0 100644 --- a/Crawler/Crawler.vcxproj.filters +++ b/Crawler/Crawler.vcxproj.filters @@ -75,6 +75,9 @@ Header Files + + Header Files + diff --git a/Crawler/Monster.cpp b/Crawler/Monster.cpp index 10575b4f..31862038 100644 --- a/Crawler/Monster.cpp +++ b/Crawler/Monster.cpp @@ -57,10 +57,18 @@ int Monster::GetHealth(){ return hp; } int Monster::GetAttack(){ - return atk; + float mod_atk=atk; + for(Buff&b:GetBuffs(ATTACK_UP)){ + mod_atk+=atk*b.intensity; + } + return int(mod_atk); } float Monster::GetMoveSpdMult(){ - return moveSpd; + float mod_moveSpd=moveSpd; + for(Buff&b:GetBuffs(SLOWDOWN)){ + mod_moveSpd-=moveSpd*b.intensity; + } + return mod_moveSpd; } float Monster::GetSizeMult(){ return size; @@ -113,6 +121,14 @@ void Monster::SetY(float y){ } bool Monster::Update(float fElapsedTime){ if(IsAlive()){ + for(std::vector::iterator it=buffList.begin();it!=buffList.end();++it){ + Buff&b=*it; + b.duration-=fElapsedTime; + if(b.duration<=0){ + it=buffList.erase(it); + if(it==buffList.end())break; + } + } for(Monster&m:MONSTER_LIST){ if(&m==this)continue; if(geom2d::overlaps(geom2d::circle(pos,12*size/2),geom2d::circle(m.GetPos(),12*m.GetSizeMult()/2))){ @@ -146,8 +162,8 @@ bool Monster::Update(float fElapsedTime){ target=geom2d::line(pos,game->GetPlayer().GetPos()).upoint(1.2); state=MOVE_TOWARDS; } - if(state==MOVE_TOWARDS&&geom2d::line(pos,target).length()>100*fElapsedTime*moveSpd){ - SetPosition(pos+geom2d::line(pos,target).vector().norm()*100*fElapsedTime*moveSpd); + if(state==MOVE_TOWARDS&&geom2d::line(pos,target).length()>100*fElapsedTime*GetMoveSpdMult()){ + SetPosition(pos+geom2d::line(pos,target).vector().norm()*100*fElapsedTime*GetMoveSpdMult()); PerformJumpAnimation(); } else { if(state==MOVE_TOWARDS){ @@ -163,7 +179,7 @@ bool Monster::Update(float fElapsedTime){ queueShotTimer-=fElapsedTime; if(queueShotTimer<0){ queueShotTimer=0; - BULLET_LIST.push_back(Bullet(pos+vf2d{0,-4},geom2d::line(pos+vf2d{0,-4},game->GetPlayer().GetPos()).vector().norm()*24*3.f,2,atk,{75/2,162/2,225/2})); + BULLET_LIST.push_back(Bullet(pos+vf2d{0,-4},geom2d::line(pos+vf2d{0,-4},game->GetPlayer().GetPos()).vector().norm()*24*3.f,2,GetAttack(),{75/2,162/2,225/2})); } } geom2d::line line(pos,game->GetPlayer().GetPos()); @@ -203,7 +219,7 @@ bool Monster::Update(float fElapsedTime){ switch(state){ case MOVE_TOWARDS:{ if(moveTowardsLine.length()>1){ - SetPosition(pos+moveTowardsLine.vector().norm()*100*fElapsedTime*moveSpd); + SetPosition(pos+moveTowardsLine.vector().norm()*100*fElapsedTime*GetMoveSpdMult()); } if(line.length()<=24*7){ state=NORMAL; @@ -217,7 +233,7 @@ bool Monster::Update(float fElapsedTime){ }break; case MOVE_AWAY:{ if(moveTowardsLine.length()>1){ - SetPosition(pos+moveTowardsLine.vector().norm()*100*fElapsedTime*moveSpd); + SetPosition(pos+moveTowardsLine.vector().norm()*100*fElapsedTime*GetMoveSpdMult()); } if(line.length()>=24*6){ state=NORMAL; @@ -267,9 +283,9 @@ Key Monster::GetFacingDirection(){ } void Monster::Draw(){ if(GetFacingDirection()==RIGHT){ - game->view.DrawPartialDecal((GetPos()+vf2d{float(GetFrame().GetSourceRect().size.x),0}*GetSizeMult())-vf2d{12,12}*GetSizeMult(),GetFrame().GetSourceImage()->Decal(),GetFrame().GetSourceRect().pos,GetFrame().GetSourceRect().size,vf2d(GetSizeMult()*-1,GetSizeMult())); + game->view.DrawPartialDecal((GetPos()+vf2d{float(GetFrame().GetSourceRect().size.x),0}*GetSizeMult())-vf2d{12,12}*GetSizeMult(),GetFrame().GetSourceImage()->Decal(),GetFrame().GetSourceRect().pos,GetFrame().GetSourceRect().size,vf2d(GetSizeMult()*-1,GetSizeMult()),GetBuffs(BuffType::SLOWDOWN).size()>0?Pixel{uint8_t(255*abs(sin(1.4*GetBuffs(BuffType::SLOWDOWN)[0].duration))),uint8_t(255*abs(sin(1.4*GetBuffs(BuffType::SLOWDOWN)[0].duration))),uint8_t(128+127*abs(sin(1.4*GetBuffs(BuffType::SLOWDOWN)[0].duration)))}:WHITE); } else { - game->view.DrawPartialDecal(GetPos()-vf2d{12,12}*GetSizeMult(),GetFrame().GetSourceImage()->Decal(),GetFrame().GetSourceRect().pos,GetFrame().GetSourceRect().size,vf2d(GetSizeMult(),GetSizeMult())); + game->view.DrawPartialDecal(GetPos()-vf2d{12,12}*GetSizeMult(),GetFrame().GetSourceImage()->Decal(),GetFrame().GetSourceRect().pos,GetFrame().GetSourceRect().size,vf2d(GetSizeMult(),GetSizeMult()),GetBuffs(BuffType::SLOWDOWN).size()>0?Pixel{uint8_t(255*abs(sin(1.4*GetBuffs(BuffType::SLOWDOWN)[0].duration))),uint8_t(255*abs(sin(1.4*GetBuffs(BuffType::SLOWDOWN)[0].duration))),uint8_t(128+127*abs(sin(1.4*GetBuffs(BuffType::SLOWDOWN)[0].duration)))}:WHITE); } } void Monster::Collision(Player&p){ @@ -311,8 +327,12 @@ AnimationState Monster::GetDeathAnimationName(){ } bool Monster::Hurt(int damage){ if(hp<=0) return false; - hp=std::max(0,hp-damage); - DAMAGENUMBER_LIST.push_back(DamageNumber(pos,damage)); + float mod_dmg=damage; + for(Buff&b:GetBuffs(BuffType::DAMAGE_REDUCTION)){ + mod_dmg-=damage*b.intensity; + } + hp=std::max(0,hp-int(mod_dmg)); + DAMAGENUMBER_LIST.push_back(DamageNumber(pos,int(mod_dmg))); if(hp<=0){ animation.ChangeState(internal_animState,GetDeathAnimationName()); } @@ -346,4 +366,14 @@ void MonsterSpawner::SetTriggered(bool trigger,bool spawnMonsters){ MONSTER_LIST.push_back(Monster(pos+monsterInfo.second,MONSTER_DATA[monsterInfo.first])); } } +} + +void Monster::AddBuff(BuffType type,float duration,float intensity){ + buffList.push_back(Buff{type,duration,intensity}); +} + +std::vectorMonster::GetBuffs(BuffType buff){ + std::vectorfilteredBuffs; + std::copy_if(buffList.begin(),buffList.end(),std::back_inserter(filteredBuffs),[buff](Buff&b){return b.type==buff;}); + return filteredBuffs; } \ No newline at end of file diff --git a/Crawler/Monster.h b/Crawler/Monster.h index fe67ce0b..1ee6a7a9 100644 --- a/Crawler/Monster.h +++ b/Crawler/Monster.h @@ -64,6 +64,7 @@ struct Monster{ float randomFrameOffset=0.f; float deathTimer=0.f; MonsterName type; + std::vectorbuffList; AnimationState GetDeathAnimationName(); public: Monster(); @@ -91,6 +92,9 @@ struct Monster{ void SetY(float y); void PerformJumpAnimation(); void PerformShootAnimation(); + + void AddBuff(BuffType type,float duration,float intensity); + std::vectorGetBuffs(BuffType buff); }; struct MonsterSpawner{ diff --git a/Crawler/Player.cpp b/Crawler/Player.cpp index 21956e34..5ae6d116 100644 --- a/Crawler/Player.cpp +++ b/Crawler/Player.cpp @@ -67,11 +67,19 @@ int Player::GetMaxHealth(){ } int Player::GetAttack(){ - return atk; + float mod_atk=atk; + for(Buff&b:GetBuffs(BuffType::ATTACK_UP)){ + mod_atk+=atk*b.intensity; + } + return int(mod_atk); } float Player::GetMoveSpdMult(){ - return moveSpd; + float mod_moveSpd=moveSpd; + for(Buff&b:GetBuffs(BuffType::SLOWDOWN)){ + mod_moveSpd-=moveSpd*b.intensity; + } + return mod_moveSpd; } float Player::GetSizeMult(){ @@ -93,6 +101,14 @@ State Player::GetState(){ void Player::Update(float fElapsedTime){ attack_cooldown_timer=std::max(0.f,attack_cooldown_timer-fElapsedTime); iframe_time=std::max(0.f,iframe_time-fElapsedTime); + for(std::vector::iterator it=buffList.begin();it!=buffList.end();++it){ + Buff&b=*it; + b.duration-=fElapsedTime; + if(b.duration<=0){ + it=buffList.erase(it); + if(it==buffList.end())break; + } + } switch(state){ case SPIN:{ switch(facingDirection){ @@ -123,7 +139,7 @@ void Player::Update(float fElapsedTime){ state=NORMAL; spin_angle=0; z=0; - game->HurtEnemies(pos,3*12,atk*2.5); + game->HurtEnemies(pos,3*12,GetAttack()*2.5); game->AddEffect(Effect{GetPos(),0.5,AnimationState::GROUND_SLAM_ATTACK_FRONT,1.33f,0.6f},Effect{GetPos(),0.5,AnimationState::GROUND_SLAM_ATTACK_BACK,1.33f,0.6f}); } if(lastAnimationFlip>0){ @@ -138,7 +154,6 @@ void Player::Update(float fElapsedTime){ }break; default:{ //Update animations normally. - moveSpd=1.0; animation.UpdateState(internal_animState,fElapsedTime); } } @@ -179,35 +194,62 @@ void Player::Update(float fElapsedTime){ } if(attack_cooldown_timer==0&&game->GetMouse(0).bHeld){ switch (cl) { - case WARRIOR: { - bool attack=false; - Monster*closest=nullptr; - float closest_dist=999999; - for(Monster&m:MONSTER_LIST){ - if(m.IsAlive() - &&geom2d::overlaps(geom2d::circle(pos-vf2d{size*12,size*12},attack_range*size*12),geom2d::circle(m.GetPos()-vf2d{m.GetSizeMult()*12,m.GetSizeMult()*12},m.GetSizeMult()*12)) - &&geom2d::line(game->GetWorldMousePos(),m.GetPos()).length()(game->GetWorldMousePos(),m.GetPos()).length(); - closest=&m; + case WARRIOR:{ + if(state!=State::SPIN){ + bool attack=false; + Monster*closest=nullptr; + float closest_dist=999999; + for(Monster&m:MONSTER_LIST){ + if(m.IsAlive() + &&geom2d::overlaps(geom2d::circle(pos-vf2d{size*12,size*12},attack_range*size*12),geom2d::circle(m.GetPos()-vf2d{m.GetSizeMult()*12,m.GetSizeMult()*12},m.GetSizeMult()*12)) + &&geom2d::line(game->GetWorldMousePos(),m.GetPos()).length()(game->GetWorldMousePos(),m.GetPos()).length(); + closest=&m; + } + } + if(closest!=nullptr&&closest->Hurt(GetAttack())){ + attack_cooldown_timer=ATTACK_COOLDOWN; + swordSwingTimer=0.2; + SetState(State::SWING_SWORD); + switch(facingDirection){ + case DOWN:{ + UpdateAnimation(AnimationState::SWINGSWORD_S); + }break; + case RIGHT:{ + UpdateAnimation(AnimationState::SWINGSWORD_E); + }break; + case LEFT:{ + UpdateAnimation(AnimationState::SWINGSWORD_W); + }break; + case UP:{ + UpdateAnimation(AnimationState::SWINGSWORD_N); + }break; + } } } - if(closest!=nullptr&&closest->Hurt(atk)){ - attack_cooldown_timer=ATTACK_COOLDOWN; - swordSwingTimer=0.2; - SetState(State::SWING_SWORD); - switch(facingDirection){ - case DOWN:{ - UpdateAnimation(AnimationState::SWINGSWORD_S); - }break; - case RIGHT:{ - UpdateAnimation(AnimationState::SWINGSWORD_E); - }break; - case LEFT:{ - UpdateAnimation(AnimationState::SWINGSWORD_W); - }break; - case UP:{ - UpdateAnimation(AnimationState::SWINGSWORD_N); - }break; + }break; + case THIEF: { + }break; + case RANGER: { + }break; + case BARD: { + }break; + case WIZARD: { + }break; + case WITCH: { + }break; + } + } + if(ability1.cooldown==0&&game->GetKey(SHIFT).bHeld){ + switch (cl) { + case WARRIOR: { + game->AddEffect(Effect(pos,0.1,AnimationState::BATTLECRY_EFFECT,1,0.3)); + ability1.cooldown=ability1.COOLDOWN_TIME; + AddBuff(BuffType::ATTACK_UP,10,0.1); + AddBuff(BuffType::DAMAGE_REDUCTION,10,0.1); + for(Monster&m:MONSTER_LIST){ + if(geom2d::overlaps(geom2d::circle(pos,12*3.5),geom2d::circle(m.GetPos(),m.GetSizeMult()*12))){ + m.AddBuff(BuffType::SLOWDOWN,5,0.3); } } }break; @@ -229,7 +271,7 @@ void Player::Update(float fElapsedTime){ if(GetState()==State::NORMAL){ rightClickAbility.cooldown=rightClickAbility.COOLDOWN_TIME; SetState(State::BLOCK); - moveSpd=0.7; + AddBuff(BuffType::SLOWDOWN,3,0.3); } }break; case THIEF: { @@ -269,8 +311,12 @@ bool Player::HasIframes(){ bool Player::Hurt(int damage){ if(hp<=0||iframe_time!=0) return false; if(state==State::BLOCK)damage=0; - hp=std::max(0,hp-damage); - DAMAGENUMBER_LIST.push_back(DamageNumber(pos,damage)); + float mod_dmg=damage; + for(Buff&b:GetBuffs(BuffType::DAMAGE_REDUCTION)){ + mod_dmg-=damage*b.intensity; + } + hp=std::max(0,hp-int(mod_dmg)); + DAMAGENUMBER_LIST.push_back(DamageNumber(pos,int(mod_dmg))); return true; } @@ -345,4 +391,14 @@ void Player::UpdateIdleAnimation(Key direction){ case LEFT:anim=CLASS_DATA[cl].idle_w;break; } UpdateAnimation(anim); +} + +void Player::AddBuff(BuffType type,float duration,float intensity){ + buffList.push_back(Buff{type,duration,intensity}); +} + +std::vectorPlayer::GetBuffs(BuffType buff){ + std::vectorfilteredBuffs; + std::copy_if(buffList.begin(),buffList.end(),std::back_inserter(filteredBuffs),[buff](Buff&b){return b.type==buff;}); + return filteredBuffs; } \ No newline at end of file diff --git a/Crawler/Player.h b/Crawler/Player.h index f422225a..e6d1026d 100644 --- a/Crawler/Player.h +++ b/Crawler/Player.h @@ -5,10 +5,11 @@ #include "State.h" #include "Ability.h" #include "Class.h" +#include "Buff.h" struct Player{ friend class Crawler; -private: + private: Class cl=WARRIOR; int hp=100,maxhp=hp; int atk=10; @@ -45,8 +46,9 @@ private: void SetZ(float z); void SetPos(vf2d pos); void SetClass(Class cl); -protected: -public: + std::vectorbuffList; + protected: + public: Player(); const static float GROUND_SLAM_SPIN_TIME; vf2d&GetPos(); @@ -67,6 +69,9 @@ public: void UpdateWalkingAnimation(Key direction); void UpdateIdleAnimation(Key direction); + void AddBuff(BuffType type,float duration,float intensity); + std::vectorGetBuffs(BuffType buff); + bool Hurt(int damage); void UpdateAnimation(AnimationState animState); Animate2D::Frame GetFrame(); diff --git a/Crawler/Version.h b/Crawler/Version.h index 6a607d36..e099f840 100644 --- a/Crawler/Version.h +++ b/Crawler/Version.h @@ -2,7 +2,7 @@ #define VERSION_MAJOR 0 #define VERSION_MINOR 2 #define VERSION_PATCH 0 -#define VERSION_BUILD 31 +#define VERSION_BUILD 45 #define stringify(a) stringify_(a) #define stringify_(a) #a diff --git a/Crawler/assets/battlecry_effect.png b/Crawler/assets/battlecry_effect.png new file mode 100644 index 00000000..f243c0d5 Binary files /dev/null and b/Crawler/assets/battlecry_effect.png differ