Incorporated multi-directional sprites in-game. Included a method to change the current display animation sprite while retaining elapsed frame time information. Release Build 9146.

mac-build
sigonasr2 7 months ago
parent 4a76acfee9
commit c4a3a6f915
  1. 2
      Adventures in Lestoria/Boar.cpp
  2. 15
      Adventures in Lestoria/Goblin_Bow.cpp
  3. 19
      Adventures in Lestoria/Goblin_Dagger.cpp
  4. 106
      Adventures in Lestoria/Monster.cpp
  5. 9
      Adventures in Lestoria/Monster.h
  6. 83
      Adventures in Lestoria/MonsterData.cpp
  7. 13
      Adventures in Lestoria/MonsterData.h
  8. 56
      Adventures in Lestoria/RunAway.cpp
  9. 2
      Adventures in Lestoria/SpawnEncounterLabel.h
  10. 2
      Adventures in Lestoria/Version.h
  11. 9
      Adventures in Lestoria/assets/Campaigns/2_1.tmx
  12. 108
      Adventures in Lestoria/assets/config/Monsters.txt
  13. 9
      Adventures in Lestoria/assets/config/NPCs.txt
  14. 14
      Adventures in Lestoria/olcUTIL_Animate2D.h
  15. BIN
      x64/Release/Adventures in Lestoria.exe

@ -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;

@ -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){

@ -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;
}

@ -65,11 +65,11 @@ safemap<std::string,std::function<void(Monster&,float,std::string)>>STRATEGY_DAT
std::map<std::string,Renderable*>MonsterData::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.x<GetPos().x){
facingDirection=LEFT;
if(HasFourWaySprites()){
vf2d diff=GetPos()-facingTargetPoint;
if(abs(diff.x)>abs(diff.y)){
if(facingTargetPoint.x>GetPos().x){
facingDirection=Direction::EAST;
}
if(facingTargetPoint.x<GetPos().x){
facingDirection=Direction::WEST;
}
}else{
if(facingTargetPoint.y>GetPos().y){
facingDirection=Direction::SOUTH;
}
if(facingTargetPoint.y<GetPos().y){
facingDirection=Direction::NORTH;
}
}
animation.ModifyDisplaySprite(internal_animState,std::format("{}_{}",animation.currentStateName.substr(0,animation.currentStateName.length()-2),int(facingDirection)));
}else{
if(facingTargetPoint.x>GetPos().x){
facingDirection=Direction::EAST;
}
if(facingTargetPoint.x<GetPos().x){
facingDirection=Direction::WEST;
}
}
}
void Monster::Draw()const{
@ -342,9 +388,9 @@ void Monster::Draw()const{
}
Pixel blendCol=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;
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::vector<Buff>shieldBuffs=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();
}

@ -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="";

@ -62,10 +62,11 @@ void MonsterData::InitializeMonsterData(){
}
std::vector<std::string>animations;
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<MonsterDropData>&MonsterData::GetDropData(){
return dropData;
@ -332,4 +360,23 @@ const EventName&MonsterData::GetDeathSound(){
}
const EventName&MonsterData::GetWalkSound(){
return walkSound;
}
}
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);
}

@ -38,6 +38,7 @@ All rights reserved.
#pragma once
#include "DEFINES.h"
#include "Item.h"
#include "Direction.h"
#include <unordered_set>
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();

@ -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;

@ -52,7 +52,7 @@ class SpawnEncounterLabel:public MenuLabel{
public:
inline SpawnEncounterLabel(geom2d::rect<float>rect,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));
}

@ -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

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.10" tiledversion="1.10.1" class="Map" orientation="orthogonal" renderorder="right-down" width="238" height="369" tilewidth="24" tileheight="24" infinite="0" nextlayerid="7" nextobjectid="27">
<map version="1.10" tiledversion="1.10.2" class="Map" orientation="orthogonal" renderorder="right-down" width="238" height="369" tilewidth="24" tileheight="24" infinite="0" nextlayerid="7" nextobjectid="28">
<properties>
<property name="Backdrop" propertytype="Backdrop" value="mountain_day"/>
<property name="Background Music" propertytype="BGM" value="foresty1_1"/>
@ -1881,11 +1881,16 @@
<object id="15" name="Spawn Group 1" type="SpawnGroup" x="4439" y="7869" width="496" height="424">
<ellipse/>
</object>
<object id="27" template="../maps/Monsters/Goblin (Bow).tx" x="4587" y="8091">
<object id="27" template="../maps/Monsters/Goblin (Bow).tx" x="4567" y="8001">
<properties>
<property name="spawner" type="object" value="15"/>
</properties>
</object>
<object id="28" name="Player Spawn" type="PlayerSpawnLocation" x="5112" y="8064" width="24" height="24"/>
<object id="27" template="../maps/Monsters/Boar.tx" x="4552" y="8063">
<properties>
<property name="spawner" type="object" value="15"/>
</properties>
</object>
</objectgroup>
</map>

@ -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

@ -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
{

@ -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
{

Loading…
Cancel
Save