Fix bug with monsters not facing the player on spawn and incorrectly adjusting their directions initially with the previous facing direction not matching their starting facing direction. Fixed Issue #54 . Mounted animations can be specified for the encounter spawn labels so that their combined sprites display properly now. Release Build 9220.

pull/57/head
sigonasr2 7 months ago
parent cb35d2c1fa
commit f5bfc0d34d
  1. 2
      Adventures in Lestoria/Monster.h
  2. 19
      Adventures in Lestoria/MonsterData.cpp
  3. 45
      Adventures in Lestoria/MonsterData.h
  4. 20
      Adventures in Lestoria/SpawnEncounterLabel.h
  5. 2
      Adventures in Lestoria/Version.h
  6. 4
      Adventures in Lestoria/assets/config/Monsters.txt
  7. BIN
      x64/Release/Adventures in Lestoria.exe

@ -226,7 +226,7 @@ private:
float knockUpZAmt=0.f; float knockUpZAmt=0.f;
//Spawns the drops a monster would drop as if they were defeated. Returns what items were dropped and their amounts. //Spawns the drops a monster would drop as if they were defeated. Returns what items were dropped and their amounts.
std::map<ItemInfo*,uint16_t>SpawnDrops(); std::map<ItemInfo*,uint16_t>SpawnDrops();
float prevFacingDirectionAngle=0.f; //Keeps track of the angle of the previous target to ensure four-way sprite facing changes don't happen too early or spastically. float prevFacingDirectionAngle=PI; //Keeps track of the angle of the previous target to ensure four-way sprite facing changes don't happen too early or spastically.
float lastFacingDirectionChange=0.f; //How much time has passed since the last facing direction change. Used to ensure another facing direction change doesn't happen too quickly. Probably allowing one every quarter second is good enough. float lastFacingDirectionChange=0.f; //How much time has passed since the last facing direction change. Used to ensure another facing direction change doesn't happen too quickly. Probably allowing one every quarter second is good enough.
std::vector<DeathSpawnInfo>deathData; //Data that contains further actions and information when this monster dies. Mostly used to spawn sub-monsters from a defeated monster. std::vector<DeathSpawnInfo>deathData; //Data that contains further actions and information when this monster dies. Mostly used to spawn sub-monsters from a defeated monster.
vf2d mountedSprOffset{}; vf2d mountedSprOffset{};

@ -160,6 +160,12 @@ void MonsterData::InitializeMonsterData(){
DATA["Monsters"][MonsterName]["CollisionDmg"].GetInt() DATA["Monsters"][MonsterName]["CollisionDmg"].GetInt()
); );
if(DATA["Monsters"][MonsterName].HasProperty("Mounted Animation"))monster.mountedAnimName=DATA["Monsters"][MonsterName]["Mounted Animation"].GetString();
if(DATA["Monsters"][MonsterName].HasProperty("Mounted Animation Offset")){
if(DATA["Monsters"][MonsterName]["Mounted Animation Offset"].GetValueCount()==2)monster.mountedAnimationOffset={DATA["Monsters"][MonsterName]["Mounted Animation Offset"].GetReal(0),DATA["Monsters"][MonsterName]["Mounted Animation Offset"].GetReal(1)};
else ERR(std::format("WARNING! Monster {} containing a mounted animation offset has {} for reading in a vector, when vectors are supposed to only have two values! Please check the \"Mounted Animation Offset\" configuration value for {}",MonsterName,DATA["Monsters"][MonsterName]["Mounted Animation Offset"].GetValueCount(),MonsterName));
}
if(hasFourWaySpriteSheet)monster.SetUsesFourWaySprites(); if(hasFourWaySpriteSheet)monster.SetUsesFourWaySprites();
for(size_t animationRow=0;const std::string&animationName:animations){ for(size_t animationRow=0;const std::string&animationName:animations){
@ -380,3 +386,16 @@ const std::string MonsterData::GetDefaultShootAnimation()const{
const std::string MonsterData::GetDefaultDeathAnimation()const{ const std::string MonsterData::GetDefaultDeathAnimation()const{
return GetDeathAnimation(Direction::SOUTH); return GetDeathAnimation(Direction::SOUTH);
} }
const bool MonsterData::HasMountedAnimation()const{
return mountedAnimName.has_value();
}
const std::optional<const std::string>MonsterData::GetMountedAnimation()const{
if(!HasMountedAnimation())ERR("WARNING! Trying to get a mounted animation for a monster that doesn't have a mounted animation to begin with!");
return mountedAnimName.value();
}
const vf2d&MonsterData::GetMountedAnimationOffset()const{
if(!HasMountedAnimation())ERR("WARNING! Trying to get a mounted animation offset for a monster that doesn't have a mounted animation to begin with!");
return mountedAnimationOffset;
}

@ -59,26 +59,6 @@ struct MonsterDropData{
}; };
struct MonsterData{ struct MonsterData{
private:
std::string name;
int hp;
int atk;
uint32_t xp;
float moveSpd;//1.0=100%
float size;
std::unordered_set<std::string>animations;
std::string idleAnimation="WARRIOR_IDLE_S"; //Represents the basic animation name, not the full animation name that ANIMATION_DATA indexes into!! (Ex. Not GREEN_SLIME_IDLE, but IDLE)
std::string jumpAnimation="WARRIOR_IDLE_S"; //Represents the basic animation name, not the full animation name that ANIMATION_DATA indexes into!! (Ex. Not GREEN_SLIME_JUMP, but JUMP)
std::string shootAnimation="WARRIOR_IDLE_S"; //Represents the basic animation name, not the full animation name that ANIMATION_DATA indexes into!! (Ex. Not GREEN_SLIME_SHOOT, but SHOOT)
std::string deathAnimation="WARRIOR_IDLE_S"; //Represents the basic animation name, not the full animation name that ANIMATION_DATA indexes into!! (Ex. Not GREEN_SLIME_DEATH, but DEATH)
std::string strategy;
int collisionDmg;
EventName hurtSound="";
EventName deathSound="";
EventName walkSound="";
std::vector<MonsterDropData> dropData;
bool isNPC=false;
bool fourWayDirectionalSprites=false; //When this flag is set, a monster has 4-way animations instead of the default 1-direction animation.
public: public:
MonsterData(); MonsterData();
MonsterData(std::string name,int hp,int atk,const uint32_t xp,std::vector<MonsterDropData>drops,float moveSpd=1.0f,float size=1.0f,std::string strategy="Run Towards",int collisionDmg=0); MonsterData(std::string name,int hp,int atk,const uint32_t xp,std::vector<MonsterDropData>drops,float moveSpd=1.0f,float size=1.0f,std::string strategy="Run Towards",int collisionDmg=0);
@ -111,4 +91,29 @@ public:
static std::map<std::string,Renderable*>imgs; static std::map<std::string,Renderable*>imgs;
const bool HasFourWaySprites()const; const bool HasFourWaySprites()const;
void SetUsesFourWaySprites(); void SetUsesFourWaySprites();
const bool HasMountedAnimation()const;
const std::optional<const std::string>GetMountedAnimation()const;
const vf2d&GetMountedAnimationOffset()const;
private:
std::string name;
int hp;
int atk;
uint32_t xp;
float moveSpd;//1.0=100%
float size;
std::unordered_set<std::string>animations;
std::string idleAnimation="WARRIOR_IDLE_S"; //Represents the basic animation name, not the full animation name that ANIMATION_DATA indexes into!! (Ex. Not GREEN_SLIME_IDLE, but IDLE)
std::string jumpAnimation="WARRIOR_IDLE_S"; //Represents the basic animation name, not the full animation name that ANIMATION_DATA indexes into!! (Ex. Not GREEN_SLIME_JUMP, but JUMP)
std::string shootAnimation="WARRIOR_IDLE_S"; //Represents the basic animation name, not the full animation name that ANIMATION_DATA indexes into!! (Ex. Not GREEN_SLIME_SHOOT, but SHOOT)
std::string deathAnimation="WARRIOR_IDLE_S"; //Represents the basic animation name, not the full animation name that ANIMATION_DATA indexes into!! (Ex. Not GREEN_SLIME_DEATH, but DEATH)
std::string strategy;
int collisionDmg;
EventName hurtSound="";
EventName deathSound="";
EventName walkSound="";
std::vector<MonsterDropData> dropData;
bool isNPC=false;
bool fourWayDirectionalSprites=false; //When this flag is set, a monster has 4-way animations instead of the default 1-direction animation.
std::optional<std::string>mountedAnimName;
vf2d mountedAnimationOffset{};
}; };

@ -49,26 +49,42 @@ class SpawnEncounterLabel:public MenuLabel{
std::string monsterName; std::string monsterName;
Animate2D::Animation<std::string>anim; Animate2D::Animation<std::string>anim;
Animate2D::AnimationState state; Animate2D::AnimationState state;
std::optional<Animate2D::Animation<std::string>>mounted_anim;
std::optional<Animate2D::AnimationState>mounted_state;
public: public:
inline SpawnEncounterLabel(geom2d::rect<float>rect,std::string label,std::string monsterName) inline SpawnEncounterLabel(geom2d::rect<float>rect,std::string label,std::string monsterName)
:MenuLabel(rect,label),monsterName(monsterName){ :MenuLabel(rect,label),monsterName(monsterName){
anim.AddState("IDLE",ANIMATION_DATA.at(std::format("{}_{}",monsterName,MONSTER_DATA.at(monsterName).GetDefaultIdleAnimation()))); anim.AddState("IDLE",ANIMATION_DATA.at(std::format("{}_{}",monsterName,MONSTER_DATA.at(monsterName).GetDefaultIdleAnimation())));
anim.ChangeState(state,"IDLE"); anim.ChangeState(state,"IDLE");
anim.UpdateState(state,util::random(1)); anim.UpdateState(state,util::random(1));
} if(MONSTER_DATA.at(monsterName).HasMountedAnimation()){
inline ~SpawnEncounterLabel(){ mounted_state=Animate2D::AnimationState{};
mounted_anim=Animate2D::Animation<std::string>{};
std::string mountedAnimName=std::format("{}",MONSTER_DATA.at(monsterName).GetMountedAnimation().value());
if(MONSTER_DATA.at(monsterName).HasFourWaySprites())mountedAnimName=std::format("{}_{}",MONSTER_DATA.at(monsterName).GetMountedAnimation().value(),int(Direction::SOUTH));
mounted_anim.value().AddState(mountedAnimName,ANIMATION_DATA.at(mountedAnimName));
mounted_anim.value().ChangeState(mounted_state.value(),mountedAnimName);
}
} }
inline ~SpawnEncounterLabel()=default;
protected: protected:
virtual void inline Update(AiL*game)override{ virtual void inline Update(AiL*game)override{
MenuComponent::Update(game); MenuComponent::Update(game);
anim.UpdateState(state,game->GetElapsedTime()); anim.UpdateState(state,game->GetElapsedTime());
if(mounted_anim.has_value())mounted_anim.value().UpdateState(mounted_state.value(),game->GetElapsedTime());
} }
virtual void inline DrawDecal(ViewPort&window,bool focused)override{ virtual void inline DrawDecal(ViewPort&window,bool focused)override{
const geom2d::rect<int>&imgRect=anim.GetFrame(state).GetSourceRect(); const geom2d::rect<int>&imgRect=anim.GetFrame(state).GetSourceRect();
vf2d imgSize=vf2d{rect.size.y,rect.size.y}; vf2d imgSize=vf2d{rect.size.y,rect.size.y};
vf2d imgScale=imgSize/vf2d{imgRect.size}; vf2d imgScale=imgSize/vf2d{imgRect.size};
window.DrawPartialDecal(rect.pos,imgSize,anim.GetFrame(state).GetSourceImage()->Decal(),imgRect.pos,imgRect.size); window.DrawPartialDecal(rect.pos,imgSize,anim.GetFrame(state).GetSourceImage()->Decal(),imgRect.pos,imgRect.size);
if(mounted_anim.has_value()){
const geom2d::rect<int>&mountedImgRect=mounted_anim.value().GetFrame(mounted_state.value()).GetSourceRect();
window.DrawPartialDecal(rect.pos+MONSTER_DATA.at(monsterName).GetMountedAnimationOffset()*imgScale,imgSize,mounted_anim.value().GetFrame(mounted_state.value()).GetSourceImage()->Decal(),mountedImgRect.pos,mountedImgRect.size);
}
float verticalAlignYOffset=(rect.size.y-8)/2; float verticalAlignYOffset=(rect.size.y-8)/2;
vf2d monsterNameTextSize=game->GetTextSizeProp(monsterName); vf2d monsterNameTextSize=game->GetTextSizeProp(monsterName);
float textXSpaceAvailable=rect.size.x-imgSize.x-4-16/*12 for the scrollbar*/; float textXSpaceAvailable=rect.size.x-imgSize.x-4-16/*12 for the scrollbar*/;

@ -39,7 +39,7 @@ All rights reserved.
#define VERSION_MAJOR 1 #define VERSION_MAJOR 1
#define VERSION_MINOR 2 #define VERSION_MINOR 2
#define VERSION_PATCH 0 #define VERSION_PATCH 0
#define VERSION_BUILD 9207 #define VERSION_BUILD 9220
#define stringify(a) stringify_(a) #define stringify(a) stringify_(a)
#define stringify_(a) #a #define stringify_(a) #a

@ -660,6 +660,10 @@ Monsters
# Setting this to true means every four rows indicates one animation, the ordering of the directions is: NORTH, EAST, SOUTH, WEST # 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 4-Way Spritesheet = True
# For monsters that have a mounted portion, this will specify the animation to use.
Mounted Animation = GOBLIN_BOW_MOUNTED
Mounted Animation Offset = 0,-10
Animations Animations
{ {
# Frame Count, Frame Speed (s), Frame Cycling (Repeat,OneShot,PingPong,Reverse) # Frame Count, Frame Speed (s), Frame Cycling (Repeat,OneShot,PingPong,Reverse)

Loading…
Cancel
Save