diff --git a/Adventures in Lestoria/Boar.cpp b/Adventures in Lestoria/Boar.cpp index d7a0a8bf..23161b9f 100644 --- a/Adventures in Lestoria/Boar.cpp +++ b/Adventures in Lestoria/Boar.cpp @@ -111,7 +111,7 @@ void Monster::STRATEGY::BOAR(Monster&m,float fElapsedTime,std::string strategy){ TransitionToRecoveryPhase(); }else{ RUN_TOWARDS(m,fElapsedTime,"Run Towards"); - m.PerformShootAnimation(); + //m.PerformShootAnimation(); if(!m.canMove)TransitionToRecoveryPhase(); } }break; diff --git a/Adventures in Lestoria/Goblin_Bow.cpp b/Adventures in Lestoria/Goblin_Bow.cpp index c6b7149c..60d201b9 100644 --- a/Adventures in Lestoria/Goblin_Bow.cpp +++ b/Adventures in Lestoria/Goblin_Bow.cpp @@ -62,19 +62,7 @@ void Monster::STRATEGY::GOBLIN_BOW(Monster&m,float fElapsedTime,std::string stra MOVE, WINDUP, }; - - enum class ANIMATION_OFFSET{ - IDLE_ANIMATION=0, - SHOOT_ANIMATION=4, - }; - - auto SetFacingAnimation=[&](ANIMATION_OFFSET animation,vf2d target){ - m.PerformAnimation(""); - }; - auto IsSpriteFlipped=[&](){return m.GetFacingDirection()==RIGHT;}; #pragma endregion - - using enum ANIMATION_OFFSET; m.F(A::ATTACK_COOLDOWN)+=fElapsedTime; @@ -87,7 +75,8 @@ void Monster::STRATEGY::GOBLIN_BOW(Monster&m,float fElapsedTime,std::string stra auto PrepareToShoot=[&](){ m.phase=WINDUP; m.F(A::SHOOT_TIMER)=ConfigFloat("Attack Windup Time"); - SetFacingAnimation(SHOOT_ANIMATION,game->GetPlayer()->GetPos()); + + m.PerformAnimation("SHOOT",m.GetFacingDirectionToTarget(game->GetPlayer()->GetPos())); }; if(outsideMaxShootingRange){ diff --git a/Adventures in Lestoria/Goblin_Dagger.cpp b/Adventures in Lestoria/Goblin_Dagger.cpp index 22294ef5..b08e4a4a 100644 --- a/Adventures in Lestoria/Goblin_Dagger.cpp +++ b/Adventures in Lestoria/Goblin_Dagger.cpp @@ -74,11 +74,6 @@ void Monster::STRATEGY::GOBLIN_DAGGER(Monster&m,float fElapsedTime,std::string s IDLE_ANIMATION=16, }; - auto SetFacingAnimation=[&](ANIMATION_OFFSET animation,vf2d target){ - m.PerformAnimation(""); - }; - auto IsSpriteFlipped=[&](){return m.GetFacingDirection()==RIGHT;}; - using enum ANIMATION_OFFSET; switch(m.phase){ case MOVE:{ @@ -91,11 +86,11 @@ void Monster::STRATEGY::GOBLIN_DAGGER(Monster&m,float fElapsedTime,std::string s switch(m.I(A::ATTACK_TYPE)){ case STAB:{ m.F(A::CASTING_TIMER)=ConfigFloat("Stab Windup Time"); - SetFacingAnimation(STAB_WINDUP_ANIMATION,game->GetPlayer()->GetPos()); + m.PerformAnimation("STAB",m.GetFacingDirectionToTarget(game->GetPlayer()->GetPos())); }break; case SLASH:{ m.F(A::CASTING_TIMER)=ConfigFloat("Slash Windup Time"); - SetFacingAnimation(SLASH_WINDUP_ANIMATION,game->GetPlayer()->GetPos()); + m.PerformAnimation("SLASH",m.GetFacingDirectionToTarget(game->GetPlayer()->GetPos())); }break; default:ERR(std::format("WARNING! Invalid Attack type {} provided. THIS SHOULD NOT BE HAPPENING!",m.I(A::ATTACK_TYPE))); } @@ -108,14 +103,14 @@ void Monster::STRATEGY::GOBLIN_DAGGER(Monster&m,float fElapsedTime,std::string s switch(m.I(A::ATTACK_TYPE)){ case STAB:{ vf2d stabTarget=game->GetPlayer()->GetPos(); - SetFacingAnimation(STAB_ANIMATION,stabTarget); - CreateBullet(DaggerStab)(m,ConfigFloat("Dagger Hit Radius"),m.GetAttack(),ConfigFloat("Dagger Stab Knockback"),m.OnUpperLevel(),m.GetFacingDirectionToTarget(stabTarget),ConfigFloat("Dagger Frame Duration"),ConfigFloat("Dagger Stab Distance"),IsSpriteFlipped()?HorizontalFlip::FLIPPED:HorizontalFlip::NONE, + m.PerformAnimation("STABBING",m.GetFacingDirectionToTarget(game->GetPlayer()->GetPos())); + CreateBullet(DaggerStab)(m,ConfigFloat("Dagger Hit Radius"),m.GetAttack(),ConfigFloat("Dagger Stab Knockback"),m.OnUpperLevel(),m.GetFacingDirectionToTarget(stabTarget),ConfigFloat("Dagger Frame Duration"),ConfigFloat("Dagger Stab Distance"),HorizontalFlip::NONE, DaggerStab::DirectionOffsets{ConfigVec("Dagger Up Offset"),ConfigVec("Dagger Down Offset"),ConfigVec("Dagger Left Offset")})EndBullet; }break; case SLASH:{ vf2d slashTarget=game->GetPlayer()->GetPos(); - SetFacingAnimation(SLASH_ANIMATION,slashTarget); - CreateBullet(DaggerSlash)(m,ConfigFloat("Dagger Hit Radius"),m.GetAttack(),ConfigFloat("Dagger Slash Knockback"),m.OnUpperLevel(),m.GetFacingDirectionToTarget(slashTarget),ConfigFloat("Dagger Frame Duration"),ConfigFloat("Dagger Slash Distance"),IsSpriteFlipped()?HorizontalFlip::FLIPPED:HorizontalFlip::NONE)EndBullet; + m.PerformAnimation("SLASHING",m.GetFacingDirectionToTarget(game->GetPlayer()->GetPos())); + CreateBullet(DaggerSlash)(m,ConfigFloat("Dagger Hit Radius"),m.GetAttack(),ConfigFloat("Dagger Slash Knockback"),m.OnUpperLevel(),m.GetFacingDirectionToTarget(slashTarget),ConfigFloat("Dagger Frame Duration"),ConfigFloat("Dagger Slash Distance"),HorizontalFlip::NONE)EndBullet; }break; default:ERR(std::format("WARNING! Invalid Attack type {} provided. THIS SHOULD NOT BE HAPPENING!",m.I(A::ATTACK_TYPE))); } @@ -126,7 +121,7 @@ void Monster::STRATEGY::GOBLIN_DAGGER(Monster&m,float fElapsedTime,std::string s case RECOVERY:{ m.F(A::CASTING_TIMER)-=fElapsedTime; m.F(A::RECOVERY_TIME)-=fElapsedTime; - if(m.F(A::CASTING_TIMER)<=0){SetFacingAnimation(IDLE_ANIMATION,game->GetPlayer()->GetPos());} + if(m.F(A::CASTING_TIMER)<=0){m.PerformIdleAnimation(m.GetFacingDirectionToTarget(game->GetPlayer()->GetPos()));} if(m.F(A::RECOVERY_TIME)<=0)m.phase=MOVE; }break; } diff --git a/Adventures in Lestoria/Monster.cpp b/Adventures in Lestoria/Monster.cpp index c378248c..1bd4031d 100644 --- a/Adventures in Lestoria/Monster.cpp +++ b/Adventures in Lestoria/Monster.cpp @@ -65,11 +65,11 @@ safemap>STRATEGY_DAT std::mapMonsterData::imgs; Monster::Monster(vf2d pos,MonsterData data,bool upperLevel,bool bossMob): - pos(pos),spawnPos(pos),hp(data.GetHealth()),size(data.GetSizeMult()),targetSize(data.GetSizeMult()),strategy(data.GetAIStrategy()),name(data.GetDisplayName()),upperLevel(upperLevel),isBoss(bossMob),facingDirection(DOWN){ + pos(pos),spawnPos(pos),hp(data.GetHealth()),size(data.GetSizeMult()),targetSize(data.GetSizeMult()),strategy(data.GetAIStrategy()),name(data.GetDisplayName()),upperLevel(upperLevel),isBoss(bossMob),facingDirection(Direction::SOUTH){ for(const std::string&anim:data.GetAnimations()){ animation.AddState(anim,ANIMATION_DATA[std::format("{}_{}",name,anim)]); } - PerformIdleAnimation(); + PerformIdleAnimation(); stats.A("Health")=data.GetHealth(); stats.A("Attack")=data.GetAttack(); stats.A("Move Spd %")=data.GetMoveSpdMult(); @@ -120,29 +120,58 @@ float Monster::GetSizeMult()const{ Animate2D::Frame Monster::GetFrame()const{ return animation.GetFrame(internal_animState); } +void Monster::PerformJumpAnimation(const Direction facingDir){ + facingDirection=facingDir; + PerformJumpAnimation(); +} void Monster::PerformJumpAnimation(){ - PerformAnimation(MONSTER_DATA[name].GetJumpAnimation()); + animation.ChangeState(internal_animState,MONSTER_DATA.at(name).GetJumpAnimation(facingDirection)); +} + +void Monster::PerformShootAnimation(const Direction facingDir){ + facingDirection=facingDir; + PerformShootAnimation(); } void Monster::PerformShootAnimation(){ - PerformAnimation(MONSTER_DATA[name].GetShootAnimation()); + animation.ChangeState(internal_animState,MONSTER_DATA.at(name).GetShootAnimation(facingDirection)); +} + +void Monster::PerformIdleAnimation(const Direction facingDir){ + facingDirection=facingDir; + PerformIdleAnimation(); } void Monster::PerformIdleAnimation(){ - PerformAnimation(MONSTER_DATA[name].GetIdleAnimation()); + animation.ChangeState(internal_animState,MONSTER_DATA.at(name).GetIdleAnimation(facingDirection)); } + void Monster::PerformNPCDownAnimation(){ - PerformAnimation(MONSTER_DATA[name].GetIdleAnimation()); + facingDirection=Direction::SOUTH; + PerformAnimation("DOWN"); } + void Monster::PerformNPCUpAnimation(){ - PerformAnimation(MONSTER_DATA[name].GetJumpAnimation()); + facingDirection=Direction::NORTH; + PerformAnimation("UP"); } + void Monster::PerformNPCLeftAnimation(){ - PerformAnimation(MONSTER_DATA[name].GetShootAnimation()); + facingDirection=Direction::WEST; + PerformAnimation("LEFT"); } + void Monster::PerformNPCRightAnimation(){ - PerformAnimation(MONSTER_DATA[name].GetDeathAnimation()); + facingDirection=Direction::EAST; + PerformAnimation("RIGHT"); } + void Monster::PerformAnimation(const std::string_view animationName){ - animation.ChangeState(internal_animState,std::string(animationName)); + if(HasFourWaySprites())animation.ChangeState(internal_animState,std::format("{}_{}",animationName,int(facingDirection))); + else animation.ChangeState(internal_animState,std::string(animationName)); +} +//Performs an animation, optionally changes the facing direction of this monster. +void Monster::PerformAnimation(const std::string_view animationName,const Direction facingDir){ + facingDirection=facingDir; + PerformAnimation(animationName); } bool Monster::_SetX(float x,const bool monsterInvoked){ vf2d newPos={x,pos.y}; @@ -304,11 +333,7 @@ bool Monster::Update(float fElapsedTime){ } } if(GetState()==State::NORMAL){ - if(game->GetPlayer()->GetX()>pos.x){ - facingDirection=RIGHT; - } else { - facingDirection=LEFT; - } + UpdateFacingDirection(game->GetPlayer()->GetPos()); } Monster::STRATEGY::RUN_STRATEGY(*this,fElapsedTime); } @@ -323,16 +348,37 @@ bool Monster::Update(float fElapsedTime){ attackedByPlayer=false; return true; } -Key Monster::GetFacingDirection()const{ +Direction Monster::GetFacingDirection()const{ return facingDirection; } void Monster::UpdateFacingDirection(vf2d facingTargetPoint){ - if(facingTargetPoint.x>GetPos().x){ - facingDirection=RIGHT; - } - if(facingTargetPoint.xabs(diff.y)){ + if(facingTargetPoint.x>GetPos().x){ + facingDirection=Direction::EAST; + } + if(facingTargetPoint.xGetPos().y){ + facingDirection=Direction::SOUTH; + } + if(facingTargetPoint.yGetPos().x){ + facingDirection=Direction::EAST; + } + if(facingTargetPoint.x0?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; - game->view.DrawPartialRotatedDecal(GetPos()-vf2d{0,GetZ()},GetFrame().GetSourceImage()->Decal(),spriteRot,GetFrame().GetSourceRect().size/2,GetFrame().GetSourceRect().pos,GetFrame().GetSourceRect().size,vf2d(GetSizeMult()*(GetFacingDirection()==RIGHT?-1:1),GetSizeMult()),blendCol); + game->view.DrawPartialRotatedDecal(GetPos()-vf2d{0,GetZ()},GetFrame().GetSourceImage()->Decal(),spriteRot,GetFrame().GetSourceRect().size/2,GetFrame().GetSourceRect().pos,GetFrame().GetSourceRect().size,vf2d(GetSizeMult()*(!HasFourWaySprites()&&GetFacingDirection()==Direction::EAST?-1:1),GetSizeMult()),blendCol); if(overlaySprite.length()!=0){ - game->view.DrawPartialRotatedDecal(GetPos()-vf2d{0,GetZ()},GFX[overlaySprite].Decal(),spriteRot,GetFrame().GetSourceRect().size/2,GetFrame().GetSourceRect().pos,GetFrame().GetSourceRect().size,vf2d(GetSizeMult()*(GetFacingDirection()==RIGHT?-1:1),GetSizeMult()),{blendCol.r,blendCol.g,blendCol.b,overlaySpriteTransparency}); + game->view.DrawPartialRotatedDecal(GetPos()-vf2d{0,GetZ()},GFX[overlaySprite].Decal(),spriteRot,GetFrame().GetSourceRect().size/2,GetFrame().GetSourceRect().pos,GetFrame().GetSourceRect().size,vf2d(GetSizeMult()*(!HasFourWaySprites()&&GetFacingDirection()==Direction::WEST?-1:1),GetSizeMult()),{blendCol.r,blendCol.g,blendCol.b,overlaySpriteTransparency}); } std::vectorshieldBuffs=GetBuffs(BARRIER_DAMAGE_REDUCTION); @@ -396,7 +442,7 @@ void Monster::DrawReflection(float drawRatioX,float multiplierX){ vf2d{defaultPos+vf2d{spriteSize.x/2,-spriteSize.y/2}}, //TR vf2d{defaultPos+spriteSize/2+vf2d{bottomExpansionAmount,0}}, //BR }; - if(GetFacingDirection()==RIGHT){ + if(GetFacingDirection()==Direction::EAST){ points={ vf2d{defaultPos+spriteSize/2+vf2d{bottomExpansionAmount,0}}, //BR vf2d{defaultPos+vf2d{spriteSize.x/2,-spriteSize.y/2}}, //TR @@ -489,7 +535,7 @@ void Monster::Moved(){ } } std::string Monster::GetDeathAnimationName(){ - return MONSTER_DATA[name].GetDeathAnimation(); + return MONSTER_DATA[name].GetDeathAnimation(GetFacingDirection()); } const bool Monster::AttackAvoided(const float attackZ)const{ return HasIframes()||abs(GetZ()-attackZ)>1; @@ -803,10 +849,10 @@ void Monster::RotateTowardsPos(const vf2d&targetPos){ float dirToPlayer=util::angleTo(GetPos(),targetPos); #pragma region Face towards lockon direction if(abs(dirToPlayer)<0.5f*PI){ //This sprite is supposed to be facing right (flipped) - facingDirection=RIGHT; + facingDirection=HasFourWaySprites()?GetFacingDirectionToTarget(targetPos):Direction::EAST; spriteRot=dirToPlayer; }else{ - facingDirection=LEFT; + facingDirection=HasFourWaySprites()?GetFacingDirectionToTarget(targetPos):Direction::WEST; if(dirToPlayer>0){ spriteRot=-PI+dirToPlayer; }else{ @@ -850,7 +896,7 @@ const bool MonsterData::IsNPC()const{ } const Animate2D::FrameSequence&Monster::GetCurrentAnimation()const{ - return ANIMATION_DATA[animation.currentStateName]; + return ANIMATION_DATA[std::format("{}_{}",name,animation.currentStateName)]; } const bool Monster::HasLineOfSight(vf2d targetPos)const{ @@ -882,4 +928,8 @@ const Direction Monster::GetFacingDirectionToTarget(vf2d target)const{ ERR(std::format("WARNING! Target direction {} did not result in a proper facing direction!! THIS SHOULD NOT BE HAPPENING!",targetDirection)); return Direction::NORTH; +} + +const bool Monster::HasFourWaySprites()const{ + return MONSTER_DATA.at(name).HasFourWaySprites(); } \ No newline at end of file diff --git a/Adventures in Lestoria/Monster.h b/Adventures in Lestoria/Monster.h index e932567f..b420851b 100644 --- a/Adventures in Lestoria/Monster.h +++ b/Adventures in Lestoria/Monster.h @@ -80,7 +80,7 @@ public: bool Hurt(int damage,bool onUpperLevel,float z); bool IsAlive(); vf2d&GetTargetPos(); - Key GetFacingDirection()const; + Direction GetFacingDirection()const; //Will make the monster face in the correct direction relative to a given target point to look at. void UpdateFacingDirection(vf2d facingTargetPoint); void Draw()const; @@ -98,11 +98,15 @@ public: void PerformJumpAnimation(); void PerformShootAnimation(); void PerformIdleAnimation(); + void PerformJumpAnimation(const Direction facingDir); + void PerformShootAnimation(const Direction facingDir); + void PerformIdleAnimation(const Direction facingDir); void PerformNPCDownAnimation(); void PerformNPCUpAnimation(); void PerformNPCLeftAnimation(); void PerformNPCRightAnimation(); void PerformAnimation(const std::string_view animationName); + void PerformAnimation(const std::string_view animationName,const Direction facingDir); const Animate2D::FrameSequence&GetCurrentAnimation()const; const bool OnUpperLevel()const; void Moved(); @@ -143,6 +147,7 @@ public: const bool HasLineOfSight(vf2d targetPos)const; const float GetDistanceFrom(vf2d target)const; const Direction GetFacingDirectionToTarget(vf2d target)const; + const bool HasFourWaySprites()const; private: std::string name; vf2d pos; @@ -158,7 +163,7 @@ private: float queueShotTimer=0; float z=0; float iframe_timer=0; - Key facingDirection=DOWN; + Direction facingDirection=Direction::SOUTH; std::string strategy; State::State state=State::NORMAL; std::string overlaySprite=""; diff --git a/Adventures in Lestoria/MonsterData.cpp b/Adventures in Lestoria/MonsterData.cpp index 209aec0e..d73f3886 100644 --- a/Adventures in Lestoria/MonsterData.cpp +++ b/Adventures in Lestoria/MonsterData.cpp @@ -62,10 +62,11 @@ void MonsterData::InitializeMonsterData(){ } std::vectoranimations; + bool hasFourWaySpriteSheet=false; + MonsterData::imgs[MonsterName]=NEW Renderable(); - const rcode imgLoadResult=MonsterData::imgs[MonsterName]->Load("assets/monsters/"+MonsterName+".png"); + const rcode imgLoadResult=MonsterData::imgs[MonsterName]->Load("assets/monsters/commercial_assets/"+MonsterName+".png"); if(imgLoadResult!=OK)ERR(std::format("WARNING! Image loading for Monster {} failed with result {}",MonsterName,int(imgLoadResult))); - EventName hurtSound=""; EventName deathSound=""; @@ -110,9 +111,21 @@ void MonsterData::InitializeMonsterData(){ int frameCount=data.GetInt(0); vf2d frameSize=vf2d{float(DATA["Monsters"][MonsterName]["SheetFrameSize"].GetInt(0)),float(DATA["Monsters"][MonsterName]["SheetFrameSize"].GetInt(1))}; - CreateHorizontalAnimationSequence(*MonsterData::imgs[MonsterName],frameCount,frameSize,std::format("{}_{}",MonsterName,animationName),animationRow,AnimationData{float(data.GetReal(1)),style}); - animations.push_back(animationName); + if(!DATA["Monsters"][MonsterName].HasProperty("4-Way Spritesheet"))ERR(std::format("WARNING! Monster {} does not have the property '4-Way Spritesheet' set",MonsterName)); + + if(DATA["Monsters"][MonsterName]["4-Way Spritesheet"].GetBool()){ + hasFourWaySpriteSheet=true; + for(int direction=0;direction<4;direction++){ + CreateHorizontalAnimationSequence(*MonsterData::imgs[MonsterName],frameCount,frameSize,std::format("{}_{}_{}",MonsterName,animationName,direction),animationRow*4+direction,AnimationData{float(data.GetReal(1)),style}); + + animations.push_back(std::format("{}_{}",animationName,direction)); + } + }else{ + CreateHorizontalAnimationSequence(*MonsterData::imgs[MonsterName],frameCount,frameSize,std::format("{}_{}",MonsterName,animationName),animationRow,AnimationData{float(data.GetReal(1)),style}); + + animations.push_back(animationName); + } animationRow++; } @@ -147,14 +160,25 @@ void MonsterData::InitializeMonsterData(){ DATA["Monsters"][MonsterName]["CollisionDmg"].GetInt() ); + if(hasFourWaySpriteSheet)monster.SetUsesFourWaySprites(); + for(size_t animationRow=0;const std::string&animationName:animations){ if(!monster.animations.insert(animationName).second)ERR(std::format("WARNING! The Animation {} for Monster {} already exists! Animations should have unique names!",animationName,MonsterName)); - switch(animationRow){ - case 0:monster.idleAnimation=animationName;break; - case 1:monster.jumpAnimation=animationName;break; - case 2:monster.shootAnimation=animationName;break; - case 3:monster.deathAnimation=animationName;break; + if(monster.HasFourWaySprites()){ + switch(animationRow){ + case 0*4:monster.idleAnimation=animationName.substr(0,animationName.length()-2);break; + case 1*4:monster.jumpAnimation=animationName.substr(0,animationName.length()-2);break; + case 2*4:monster.shootAnimation=animationName.substr(0,animationName.length()-2);break; + case 3*4:monster.deathAnimation=animationName.substr(0,animationName.length()-2);break; + } + }else{ + switch(animationRow){ + case 0:monster.idleAnimation=animationName;break; + case 1:monster.jumpAnimation=animationName;break; + case 2:monster.shootAnimation=animationName;break; + case 3:monster.deathAnimation=animationName;break; + } } animationRow++; @@ -307,17 +331,21 @@ std::string MonsterData::GetDisplayName(){ return name; } -std::string MonsterData::GetIdleAnimation(){ - return idleAnimation; +const std::string MonsterData::GetIdleAnimation(const Direction&dir)const{ + if(HasFourWaySprites())return std::format("{}_{}",idleAnimation,int(dir)); + else return idleAnimation; } -std::string MonsterData::GetJumpAnimation(){ - return jumpAnimation; +const std::string MonsterData::GetJumpAnimation(const Direction&dir)const{ + if(HasFourWaySprites())return std::format("{}_{}",jumpAnimation,int(dir)); + else return jumpAnimation; } -std::string MonsterData::GetShootAnimation(){ - return shootAnimation; +const std::string MonsterData::GetShootAnimation(const Direction&dir)const{ + if(HasFourWaySprites())return std::format("{}_{}",shootAnimation,int(dir)); + else return shootAnimation; } -std::string MonsterData::GetDeathAnimation(){ - return deathAnimation; +const std::string MonsterData::GetDeathAnimation(const Direction&dir)const{ + if(HasFourWaySprites())return std::format("{}_{}",deathAnimation,int(dir)); + else return deathAnimation; } const std::vector&MonsterData::GetDropData(){ return dropData; @@ -332,4 +360,23 @@ const EventName&MonsterData::GetDeathSound(){ } const EventName&MonsterData::GetWalkSound(){ return walkSound; -} \ No newline at end of file +} + +const bool MonsterData::HasFourWaySprites()const{ + return fourWayDirectionalSprites; +} +void MonsterData::SetUsesFourWaySprites(){ + fourWayDirectionalSprites=true; +} +const std::string MonsterData::GetDefaultIdleAnimation()const{ + return GetIdleAnimation(Direction::SOUTH); +} +const std::string MonsterData::GetDefaultJumpAnimation()const{ + return GetJumpAnimation(Direction::SOUTH); +} +const std::string MonsterData::GetDefaultShootAnimation()const{ + return GetShootAnimation(Direction::SOUTH); +} +const std::string MonsterData::GetDefaultDeathAnimation()const{ + return GetDeathAnimation(Direction::SOUTH); +} diff --git a/Adventures in Lestoria/MonsterData.h b/Adventures in Lestoria/MonsterData.h index 59436f4f..9a8280d6 100644 --- a/Adventures in Lestoria/MonsterData.h +++ b/Adventures in Lestoria/MonsterData.h @@ -38,6 +38,7 @@ All rights reserved. #pragma once #include "DEFINES.h" #include "Item.h" +#include "Direction.h" #include INCLUDE_ITEM_DATA @@ -88,10 +89,14 @@ public: float GetSizeMult(); const std::string&GetAIStrategy()const; int GetCollisionDmg(); - std::string GetIdleAnimation(); - std::string GetJumpAnimation(); - std::string GetShootAnimation(); - std::string GetDeathAnimation(); + const std::string GetDefaultIdleAnimation()const; + const std::string GetDefaultJumpAnimation()const; + const std::string GetDefaultShootAnimation()const; + const std::string GetDefaultDeathAnimation()const; + const std::string GetIdleAnimation(const Direction&dir)const; + const std::string GetJumpAnimation(const Direction&dir)const; + const std::string GetShootAnimation(const Direction&dir)const; + const std::string GetDeathAnimation(const Direction&dir)const; const EventName&GetHurtSound(); const EventName&GetDeathSound(); const EventName&GetWalkSound(); diff --git a/Adventures in Lestoria/RunAway.cpp b/Adventures in Lestoria/RunAway.cpp index 13905298..041a4513 100644 --- a/Adventures in Lestoria/RunAway.cpp +++ b/Adventures in Lestoria/RunAway.cpp @@ -86,14 +86,28 @@ void Monster::STRATEGY::RUN_AWAY(Monster&m,float fElapsedTime,std::string strate float randomDist=util::random(24*6); m.target=m.GetPos()+vf2d{sin(randomAngle),cos(randomAngle)}*randomDist; } - }else - if(line.length()<=24.f*ConfigInt("CloseInRange")/100.0f){ - m.SetState(State::NORMAL); + }else if(line.length()<=24.f*ConfigInt("CloseInRange")/100.0f)m.SetState(State::NORMAL); + + if(m.HasFourWaySprites()){ + if(abs(moveTowardsLine.vector().x)>abs(moveTowardsLine.vector().y)){ + if(moveTowardsLine.vector().x>0){ + m.facingDirection=Direction::EAST; + } else { + m.facingDirection=Direction::WEST; + } + }else{ + if(moveTowardsLine.vector().y>0){ + m.facingDirection=Direction::SOUTH; + } else { + m.facingDirection=Direction::NORTH; + } + } + }else{ + if(moveTowardsLine.vector().x>0){ + m.facingDirection=Direction::EAST; + } else { + m.facingDirection=Direction::WEST; } - if(moveTowardsLine.vector().x>0){ - m.facingDirection=RIGHT; - } else { - m.facingDirection=LEFT; } m.PerformJumpAnimation(); }break; @@ -114,14 +128,28 @@ void Monster::STRATEGY::RUN_AWAY(Monster&m,float fElapsedTime,std::string strate float randomDist=util::random(24*6); m.target=m.GetPos()+vf2d{sin(randomAngle),cos(randomAngle)}*randomDist; } - }else - if(line.length()>=24.f*ConfigInt("Range")/100.f){ - m.SetState(State::NORMAL); + }else if(line.length()>=24.f*ConfigInt("Range")/100.f)m.SetState(State::NORMAL); + + if(m.HasFourWaySprites()){ + if(abs(moveTowardsLine.vector().x)>abs(moveTowardsLine.vector().y)){ + if(moveTowardsLine.vector().x>0){ + m.facingDirection=Direction::EAST; + } else { + m.facingDirection=Direction::WEST; + } + }else{ + if(moveTowardsLine.vector().y>0){ + m.facingDirection=Direction::SOUTH; + } else { + m.facingDirection=Direction::NORTH; + } + } + }else{ + if(moveTowardsLine.vector().x>0){ + m.facingDirection=Direction::EAST; + } else { + m.facingDirection=Direction::WEST; } - if(moveTowardsLine.vector().x>0){ - m.facingDirection=RIGHT; - } else { - m.facingDirection=LEFT; } m.PerformJumpAnimation(); }break; diff --git a/Adventures in Lestoria/SpawnEncounterLabel.h b/Adventures in Lestoria/SpawnEncounterLabel.h index cfc7cd5b..a8852c08 100644 --- a/Adventures in Lestoria/SpawnEncounterLabel.h +++ b/Adventures in Lestoria/SpawnEncounterLabel.h @@ -52,7 +52,7 @@ class SpawnEncounterLabel:public MenuLabel{ public: inline SpawnEncounterLabel(geom2d::rectrect,std::string label,std::string monsterName) :MenuLabel(rect,label),monsterName(monsterName){ - anim.AddState("IDLE",ANIMATION_DATA.at(std::format("{}_{}",monsterName,MONSTER_DATA.at(monsterName).GetIdleAnimation()))); + anim.AddState("IDLE",ANIMATION_DATA.at(std::format("{}_{}",monsterName,MONSTER_DATA.at(monsterName).GetDefaultIdleAnimation()))); anim.ChangeState(state,"IDLE"); anim.UpdateState(state,util::random(1)); } diff --git a/Adventures in Lestoria/Version.h b/Adventures in Lestoria/Version.h index 7afeb6c4..433022ff 100644 --- a/Adventures in Lestoria/Version.h +++ b/Adventures in Lestoria/Version.h @@ -39,7 +39,7 @@ All rights reserved. #define VERSION_MAJOR 1 #define VERSION_MINOR 2 #define VERSION_PATCH 0 -#define VERSION_BUILD 9126 +#define VERSION_BUILD 9146 #define stringify(a) stringify_(a) #define stringify_(a) #a diff --git a/Adventures in Lestoria/assets/Campaigns/2_1.tmx b/Adventures in Lestoria/assets/Campaigns/2_1.tmx index f6bb7810..47f6eebf 100644 --- a/Adventures in Lestoria/assets/Campaigns/2_1.tmx +++ b/Adventures in Lestoria/assets/Campaigns/2_1.tmx @@ -1,5 +1,5 @@ - + @@ -1881,11 +1881,16 @@ - + + + + + + diff --git a/Adventures in Lestoria/assets/config/Monsters.txt b/Adventures in Lestoria/assets/config/Monsters.txt index 0262f157..fae32be8 100644 --- a/Adventures in Lestoria/assets/config/Monsters.txt +++ b/Adventures in Lestoria/assets/config/Monsters.txt @@ -18,6 +18,9 @@ Monsters #Size of each animation frame SheetFrameSize = 24,24 + # Setting this to true means every four rows indicates one animation, the ordering of the directions is: NORTH, EAST, SOUTH, WEST + 4-Way Spritesheet = False + Animations { # Frame Count, Frame Speed (s), Frame Cycling (Repeat,OneShot,PingPong,Reverse) @@ -54,6 +57,9 @@ Monsters #Size of each animation frame SheetFrameSize = 24,24 + + # Setting this to true means every four rows indicates one animation, the ordering of the directions is: NORTH, EAST, SOUTH, WEST + 4-Way Spritesheet = False Animations { @@ -91,6 +97,9 @@ Monsters #Size of each animation frame SheetFrameSize = 24,24 + + # Setting this to true means every four rows indicates one animation, the ordering of the directions is: NORTH, EAST, SOUTH, WEST + 4-Way Spritesheet = False Animations { @@ -128,6 +137,9 @@ Monsters #Size of each animation frame SheetFrameSize = 24,24 + + # Setting this to true means every four rows indicates one animation, the ordering of the directions is: NORTH, EAST, SOUTH, WEST + 4-Way Spritesheet = False Animations { @@ -174,6 +186,9 @@ Monsters #Size of each animation frame SheetFrameSize = 24,24 + + # Setting this to true means every four rows indicates one animation, the ordering of the directions is: NORTH, EAST, SOUTH, WEST + 4-Way Spritesheet = False Animations { @@ -212,7 +227,9 @@ Monsters #Size of each animation frame SheetFrameSize = 24,24 - + + # Setting this to true means every four rows indicates one animation, the ordering of the directions is: NORTH, EAST, SOUTH, WEST + 4-Way Spritesheet = False Animations { @@ -249,6 +266,9 @@ Monsters #Size of each animation frame SheetFrameSize = 24,24 + + # Setting this to true means every four rows indicates one animation, the ordering of the directions is: NORTH, EAST, SOUTH, WEST + 4-Way Spritesheet = False Animations { @@ -284,6 +304,9 @@ Monsters #Size of each animation frame SheetFrameSize = 24,24 + + # Setting this to true means every four rows indicates one animation, the ordering of the directions is: NORTH, EAST, SOUTH, WEST + 4-Way Spritesheet = False Animations { @@ -320,6 +343,9 @@ Monsters #Size of each animation frame SheetFrameSize = 24,24 + # Setting this to true means every four rows indicates one animation, the ordering of the directions is: NORTH, EAST, SOUTH, WEST + 4-Way Spritesheet = False + Animations { # Frame Count, Frame Speed (s), Frame Cycling (Repeat,OneShot,PingPong,Reverse) @@ -380,6 +406,9 @@ Monsters #Size of each animation frame SheetFrameSize = 26,26 + + # Setting this to true means every four rows indicates one animation, the ordering of the directions is: NORTH, EAST, SOUTH, WEST + 4-Way Spritesheet = False Animations { @@ -422,6 +451,9 @@ Monsters #Size of each animation frame SheetFrameSize = 24,24 + + # Setting this to true means every four rows indicates one animation, the ordering of the directions is: NORTH, EAST, SOUTH, WEST + 4-Way Spritesheet = False Animations { @@ -465,18 +497,20 @@ Monsters Strategy = Boar #Size of each animation frame - SheetFrameSize = 24,24 + SheetFrameSize = 32,32 + + # Setting this to true means every four rows indicates one animation, the ordering of the directions is: NORTH, EAST, SOUTH, WEST + 4-Way Spritesheet = True Animations { # Frame Count, Frame Speed (s), Frame Cycling (Repeat,OneShot,PingPong,Reverse) # Animations must be defined in the same order as they are in their sprite sheets # The First Four animations must represent a standing, walking, attack, and death animation. Their names are up to the creator. - IDLE = 1, 0.3, Repeat - JUMP = 1, 0.2, Repeat - SHOOT = 1, 0.2, OneShot - DEATH = 1, 0.15, OneShot - SCRATCH = 4, 0.2, OneShot + IDLE = 1, 0.6, Repeat + WALK = 4, 0.2, Repeat + SCRATCH = 5, 0.1, Repeat + DEATH = 4, 0.15, OneShot } # Drop Item Name, Drop Percentage(0-100%), Drop Min Quantity, Drop Max Quantity @@ -504,21 +538,23 @@ Monsters WaitTime = 0 #Size of each animation frame - SheetFrameSize = 24,24 + SheetFrameSize = 32,32 + + # Setting this to true means every four rows indicates one animation, the ordering of the directions is: NORTH, EAST, SOUTH, WEST + 4-Way Spritesheet = True Animations { # Frame Count, Frame Speed (s), Frame Cycling (Repeat,OneShot,PingPong,Reverse) # Animations must be defined in the same order as they are in their sprite sheets # The First Four animations must represent a standing, walking, attack, and death animation. Their names are up to the creator. - IDLE = 1, 0.3, Repeat - JUMP = 1, 0.2, Repeat - SHOOT = 1, 0.2, OneShot - DEATH = 1, 0.15, OneShot + IDLE = 2, 0.1, Repeat + WALK = 4, 0.15, Repeat + STABBING = 4, 0.075, OneShot + DEATH = 4, 0.15, OneShot + SLASHING = 4, 0.075, OneShot STAB = 1, 0.1, OneShot - STABBING = 2, 0.1, PingPong SLASH = 1, 0.1, OneShot - SLASHING = 2, 0.1, PingPong } # Drop Item Name, Drop Percentage(0-100%), Drop Min Quantity, Drop Max Quantity @@ -543,22 +579,20 @@ Monsters Strategy = Goblin Bow #Size of each animation frame - SheetFrameSize = 24,24 + SheetFrameSize = 32,32 + # Setting this to true means every four rows indicates one animation, the ordering of the directions is: NORTH, EAST, SOUTH, WEST + 4-Way Spritesheet = True Animations { # Frame Count, Frame Speed (s), Frame Cycling (Repeat,OneShot,PingPong,Reverse) # Animations must be defined in the same order as they are in their sprite sheets # The First Four animations must represent a standing, walking, attack, and death animation. Their names are up to the creator. - IDLE = 1, 0.1, Repeat - WALK = 1, 0.2, Repeat - SHOOT = 3, 0.3, OneShot - DEATH = 1, 0.15, OneShot - STAB = 1, 0.1, OneShot - STABBING = 2, 0.1, PingPong - SLASH = 1, 0.1, OneShot - SLASHING = 2, 0.1, PingPong + IDLE = 2, 0.6, Repeat + WALK = 3, 0.2, Repeat + SHOOT = 4, 0.03, OneShot + DEATH = 4, 0.15, OneShot } Hurt Sound = Monster Hurt @@ -583,14 +617,17 @@ Monsters Strategy = Run Towards #Size of each animation frame - SheetFrameSize = 24,24 + SheetFrameSize = 32,32 + + # Setting this to true means every four rows indicates one animation, the ordering of the directions is: NORTH, EAST, SOUTH, WEST + 4-Way Spritesheet = True Animations { # Frame Count, Frame Speed (s), Frame Cycling (Repeat,OneShot,PingPong,Reverse) # Animations must be defined in the same order as they are in their sprite sheets # The First Four animations must represent a standing, walking, attack, and death animation. Their names are up to the creator. - IDLE = 1, 0.3, Repeat + IDLE = 1, 0.6, Repeat JUMP = 1, 0.2, Repeat SHOOT = 1, 0.2, OneShot DEATH = 1, 0.15, OneShot @@ -618,14 +655,17 @@ Monsters Strategy = Run Towards #Size of each animation frame - SheetFrameSize = 24,24 + SheetFrameSize = 32,32 + + # Setting this to true means every four rows indicates one animation, the ordering of the directions is: NORTH, EAST, SOUTH, WEST + 4-Way Spritesheet = True Animations { # Frame Count, Frame Speed (s), Frame Cycling (Repeat,OneShot,PingPong,Reverse) # Animations must be defined in the same order as they are in their sprite sheets # The First Four animations must represent a standing, walking, attack, and death animation. Their names are up to the creator. - IDLE = 1, 0.3, Repeat + IDLE = 1, 0.6, Repeat JUMP = 1, 0.2, Repeat SHOOT = 1, 0.2, OneShot DEATH = 1, 0.15, OneShot @@ -653,14 +693,17 @@ Monsters Strategy = Run Towards #Size of each animation frame - SheetFrameSize = 24,24 + SheetFrameSize = 32,32 + + # Setting this to true means every four rows indicates one animation, the ordering of the directions is: NORTH, EAST, SOUTH, WEST + 4-Way Spritesheet = True Animations { # Frame Count, Frame Speed (s), Frame Cycling (Repeat,OneShot,PingPong,Reverse) # Animations must be defined in the same order as they are in their sprite sheets # The First Four animations must represent a standing, walking, attack, and death animation. Their names are up to the creator. - IDLE = 1, 0.3, Repeat + IDLE = 1, 0.6, Repeat JUMP = 1, 0.2, Repeat SHOOT = 1, 0.2, OneShot DEATH = 1, 0.15, OneShot @@ -688,14 +731,17 @@ Monsters Strategy = Run Towards #Size of each animation frame - SheetFrameSize = 24,24 + SheetFrameSize = 48,48 + + # Setting this to true means every four rows indicates one animation, the ordering of the directions is: NORTH, EAST, SOUTH, WEST + 4-Way Spritesheet = True Animations { # Frame Count, Frame Speed (s), Frame Cycling (Repeat,OneShot,PingPong,Reverse) # Animations must be defined in the same order as they are in their sprite sheets # The First Four animations must represent a standing, walking, attack, and death animation. Their names are up to the creator. - IDLE = 1, 0.3, Repeat + IDLE = 1, 0.6, Repeat JUMP = 1, 0.2, Repeat SHOOT = 1, 0.2, OneShot DEATH = 1, 0.15, OneShot diff --git a/Adventures in Lestoria/assets/config/NPCs.txt b/Adventures in Lestoria/assets/config/NPCs.txt index 06987f83..3df842c6 100644 --- a/Adventures in Lestoria/assets/config/NPCs.txt +++ b/Adventures in Lestoria/assets/config/NPCs.txt @@ -8,6 +8,9 @@ NPCs #Size of each animation frame SheetFrameSize = 24,24 + + # Setting this to true means every four rows indicates one animation, the ordering of the directions is: NORTH, EAST, SOUTH, WEST + 4-Way Spritesheet = False Animations { @@ -32,6 +35,9 @@ NPCs #Size of each animation frame SheetFrameSize = 24,24 + + # Setting this to true means every four rows indicates one animation, the ordering of the directions is: NORTH, EAST, SOUTH, WEST + 4-Way Spritesheet = False Animations { @@ -54,6 +60,9 @@ NPCs #Size of each animation frame SheetFrameSize = 24,24 + + # Setting this to true means every four rows indicates one animation, the ordering of the directions is: NORTH, EAST, SOUTH, WEST + 4-Way Spritesheet = False Animations { diff --git a/Adventures in Lestoria/olcUTIL_Animate2D.h b/Adventures in Lestoria/olcUTIL_Animate2D.h index 578078af..47c872bd 100644 --- a/Adventures in Lestoria/olcUTIL_Animate2D.h +++ b/Adventures in Lestoria/olcUTIL_Animate2D.h @@ -236,6 +236,20 @@ namespace olc::utils::Animate2D return false; } + // Changes an animation without resetting the played animation time. Useful when changing a direction but retaining the frame time that has passed. + inline bool ModifyDisplaySprite(AnimationState& state, const StatesEnum& sStateName) + { + currentStateName=sStateName; + size_t idx = m_mapStateIndices.at(sStateName); + if (state.nIndex != idx) + { + state.nIndex = idx; + return true; + } + + return false; + } + // Update an animation state token inline void UpdateState(AnimationState& state, const float fElapsedTime) const { diff --git a/x64/Release/Adventures in Lestoria.exe b/x64/Release/Adventures in Lestoria.exe index a8e5ac72..e2c6edf9 100644 Binary files a/x64/Release/Adventures in Lestoria.exe and b/x64/Release/Adventures in Lestoria.exe differ