diff --git a/Adventures in Lestoria/Adventures in Lestoria.vcxproj b/Adventures in Lestoria/Adventures in Lestoria.vcxproj
index 27a6cba5..a50a4b17 100644
--- a/Adventures in Lestoria/Adventures in Lestoria.vcxproj
+++ b/Adventures in Lestoria/Adventures in Lestoria.vcxproj
@@ -712,7 +712,7 @@
-
+
diff --git a/Adventures in Lestoria/AdventuresInLestoria.cpp b/Adventures in Lestoria/AdventuresInLestoria.cpp
index 0d47230f..13c67911 100644
--- a/Adventures in Lestoria/AdventuresInLestoria.cpp
+++ b/Adventures in Lestoria/AdventuresInLestoria.cpp
@@ -3016,11 +3016,12 @@ void AiL::InitializeLevels(){
Test::RunMapTests();
}
-void AiL::SpawnMonster(vf2d pos,MonsterData&data,bool upperLevel,bool isBossSpawn){
+Monster&AiL::SpawnMonster(vf2d pos,MonsterData&data,bool upperLevel,bool isBossSpawn){
monstersToBeSpawned.push_back(Monster(pos,data,upperLevel,isBossSpawn));
if(isBossSpawn){
totalBossEncounterMobs++;
}
+ return monstersToBeSpawned.back();
}
void AiL::DrawPie(vf2d center,float radius,float degreesCut,Pixel col){
diff --git a/Adventures in Lestoria/AdventuresInLestoria.h b/Adventures in Lestoria/AdventuresInLestoria.h
index 001a0999..34ee26cf 100644
--- a/Adventures in Lestoria/AdventuresInLestoria.h
+++ b/Adventures in Lestoria/AdventuresInLestoria.h
@@ -277,7 +277,7 @@ public:
void RenderTile(vi2d pos,TilesheetData tileSheet,int tileSheetIndex,vi2d tileSheetPos);
void RenderTile(TileRenderData&tileSheet,Pixel col);
bool IsReflectiveTile(TilesheetData tileSheet,int tileID);
- void SpawnMonster(vf2d pos,MonsterData&data,bool upperLevel=false,bool isBossSpawn=false); //Queues a monster for spawning on the next frame.
+ Monster&SpawnMonster(vf2d pos,MonsterData&data,bool upperLevel=false,bool isBossSpawn=false); //Queues a monster for spawning on the next frame.
void DrawPie(vf2d center,float radius,float degreesCut,Pixel col);
void DrawSquarePie(vf2d center,float radius,float degreesCut,Pixel col);
void RenderCooldowns();
diff --git a/Adventures in Lestoria/Animation.cpp b/Adventures in Lestoria/Animation.cpp
index 08812225..883c309c 100644
--- a/Adventures in Lestoria/Animation.cpp
+++ b/Adventures in Lestoria/Animation.cpp
@@ -253,21 +253,19 @@ void sig::Animation::InitializeAnimations(){
Animate2D::FrameSequence goblin_bow_attack_n,goblin_bow_attack_e,goblin_bow_attack_s,goblin_bow_attack_w;
//Idle sequences for the mounted boar bow goblin.
for(int animationIndex=0;animationIndex<4;animationIndex++){
- Animate2D::FrameSequence mountAnimation;
+ Animate2D::FrameSequence mountAnimation{0.6f};
for(int i=0;i<2;i++){
mountAnimation.AddFrame(Animate2D::Frame{&GFX["monsters/commercial_assets/Goblin (Bow)_foreground.png"],{{i*32,animationIndex*32},{32,32}}});
}
ANIMATION_DATA[std::format("GOBLIN_BOW_MOUNTED_{}",animationIndex)]=mountAnimation;
- animationIndex++;
}
//Shooting sequences for the mounted boar bow goblin.
- for(int animationIndex=0;animationIndex<4;animationIndex++){
- Animate2D::FrameSequence mountShootAnimation;
+ for(int animationIndex=0;animationIndex<4;animationIndex++){
+ Animate2D::FrameSequence mountShootAnimation{0.06f,Animate2D::Style::OneShot};
for(int i=0;i<4;i++){
- mountShootAnimation.AddFrame(Animate2D::Frame{&GFX["monsters/commercial_assets/Goblin (Bow)_foreground.png"],{{i*32,index*32+4*32},{32,32}}});
+ mountShootAnimation.AddFrame(Animate2D::Frame{&GFX["monsters/commercial_assets/Goblin (Bow)_foreground.png"],{{i*32,animationIndex*32+4*32},{32,32}}});
}
ANIMATION_DATA[std::format("GOBLIN_BOW_ATTACK_{}",animationIndex)]=mountShootAnimation;
- animationIndex++;
}
for(auto&dat:GFX){
diff --git a/Adventures in Lestoria/MountMonster.cpp b/Adventures in Lestoria/Goblin_Boar_Rider.cpp
similarity index 57%
rename from Adventures in Lestoria/MountMonster.cpp
rename to Adventures in Lestoria/Goblin_Boar_Rider.cpp
index f8158512..2bb42537 100644
--- a/Adventures in Lestoria/MountMonster.cpp
+++ b/Adventures in Lestoria/Goblin_Boar_Rider.cpp
@@ -39,8 +39,11 @@ All rights reserved.
#include "DEFINES.h"
#include "Monster.h"
#include "MonsterStrategyHelpers.h"
+#include "BulletTypes.h"
INCLUDE_ANIMATION_DATA
+INCLUDE_BULLET_LIST
+INCLUDE_game
using A=Attribute;
@@ -48,10 +51,39 @@ void Monster::STRATEGY::GOBLIN_BOAR_RIDER(Monster&m,float fElapsedTime,std::stri
//We have access to GOBLIN_BOW_MOUNTED_X and GOBLIN_BOW_ATTACK_X
if(!m.B(A::INITIALIZED_MOUNTED_MONSTER)){
m.B(A::INITIALIZED_MOUNTED_MONSTER)=true;
+ m.F(A::PERCEPTION_LEVEL)=ConfigFloat("Starting Perception Level");
m.internal_mounted_animState=Animate2D::AnimationState{};
m.mounted_animation=Animate2D::Animation{};
- for(const std::string&animation:Config("Imposed Monster Animations").GetValues()){
+
+ for(bool firstAnimation=true;const std::string&animation:Config("Imposed Monster Animations").GetValues()){
m.mounted_animation.value().AddState(animation,ANIMATION_DATA.at(animation));
+
+ if(firstAnimation)m.mounted_animation.value().ChangeState(m.internal_mounted_animState.value(),animation);
+ firstAnimation=false;
}
+ m.mountedSprOffset=ConfigVec("Imposed Monster Offset");
+ m.deathData.push_back(DeathSpawnInfo{ConfigString("Spawned Monster"),1U});
+ }
+
+ BOAR(m,fElapsedTime,"Boar");
+
+ m.F(A::ATTACK_COOLDOWN)+=fElapsedTime;
+ if(m.F(A::SHOOT_TIMER)>0.f){
+ m.F(A::SHOOT_TIMER)-=fElapsedTime;
+ if(m.F(A::SHOOT_TIMER)<=0.f){
+ geom2d::line pointTowardsPlayer(m.GetPos(),game->GetPlayer()->GetPos());
+ vf2d extendedLine=pointTowardsPlayer.upoint(1.1f);
+ CreateBullet(Arrow)(m.GetPos(),extendedLine,pointTowardsPlayer.vector().norm()*ConfigFloat("Arrow Spd"),"goblin_arrow.png",ConfigFloat("Arrow Hitbox Radius"),m.GetAttack(),m.OnUpperLevel())EndBullet;
+ Arrow&arrow=static_cast(*BULLET_LIST.back());
+ arrow.PointToBestTargetPath(m.F(A::PERCEPTION_LEVEL));
+
+ m.F(A::ATTACK_COOLDOWN)=0.f;
+ m.F(A::PERCEPTION_LEVEL)=std::min(ConfigFloat("Maximum Perception Level"),m.F(A::PERCEPTION_LEVEL)+ConfigFloat("Perception Level Increase"));
+ m.mounted_animation.value().ChangeState(m.internal_mounted_animState.value(),std::format("GOBLIN_BOW_MOUNTED_{}",int(m.GetFacingDirection())));
+ }
+ }else
+ if(m.F(A::ATTACK_COOLDOWN)>=ConfigFloat("Attack Reload Time")){
+ m.F(A::SHOOT_TIMER)=ConfigFloat("Attack Windup Time");
+ m.mounted_animation.value().ChangeState(m.internal_mounted_animState.value(),std::format("GOBLIN_BOW_ATTACK_{}",int(m.GetFacingDirection())));
}
}
\ No newline at end of file
diff --git a/Adventures in Lestoria/Monster.cpp b/Adventures in Lestoria/Monster.cpp
index 742a24e2..d9b0cd33 100644
--- a/Adventures in Lestoria/Monster.cpp
+++ b/Adventures in Lestoria/Monster.cpp
@@ -399,7 +399,7 @@ void Monster::Draw()const{
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()*(!HasFourWaySprites()&&GetFacingDirection()==Direction::WEST?-1:1),GetSizeMult()),{blendCol.r,blendCol.g,blendCol.b,overlaySpriteTransparency});
}
- if(HasMountedMonster())game->view.DrawPartialRotatedDecal(GetPos()-vf2d{0,GetZ()},GetMountedFrame().GetSourceImage()->Decal(),spriteRot,GetMountedFrame().GetSourceRect().size/2,GetMountedFrame().GetSourceRect().pos,GetMountedFrame().GetSourceRect().size,vf2d(GetSizeMult()*(!HasFourWaySprites()&&GetFacingDirection()==Direction::EAST?-1:1),GetSizeMult()),blendCol);
+ if(HasMountedMonster())game->view.DrawPartialRotatedDecal(GetPos()-vf2d{0,GetZ()}+mountedSprOffset,GetMountedFrame().value().GetSourceImage()->Decal(),spriteRot,GetMountedFrame().value().GetSourceRect().size/2,GetMountedFrame().value().GetSourceRect().pos,GetMountedFrame().value().GetSourceRect().size,vf2d(GetSizeMult()*(!HasFourWaySprites()&&GetFacingDirection()==Direction::EAST?-1:1),GetSizeMult()),blendCol);
std::vectorshieldBuffs=GetBuffs(BARRIER_DAMAGE_REDUCTION);
if(shieldBuffs.size()>0){
@@ -768,6 +768,15 @@ std::mapMonster::SpawnDrops(){
void Monster::OnDeath(){
animation.ChangeState(internal_animState,GetDeathAnimationName());
+
+ if(HasMountedMonster()){
+ for(DeathSpawnInfo&deathInfo:deathData){
+ deathInfo.Spawn(GetPos(),OnUpperLevel());
+ }
+ mounted_animation={};
+ internal_mounted_animState={};
+ }
+
if(isBoss){
game->ReduceBossEncounterMobCount();
if(game->BossEncounterMobCount()==0){
@@ -948,10 +957,21 @@ const bool Monster::HasFourWaySprites()const{
const bool Monster::HasMountedMonster()const{
if(internal_mounted_animState.has_value()^mounted_animation.has_value())ERR("WARNING! The internal mounted animation state and the mounted animation variables are not matching! They should both either be on or both be off! THIS SHOULD NOT BE HAPPENING!");
- return true;
+ return internal_mounted_animState.has_value()&&mounted_animation.has_value();
}
-const std::optionalMonster::GetMountedFrame()const{
+const std::optionalMonster::GetMountedFrame()const{
if(!HasMountedMonster())return {};
else return mounted_animation.value().GetFrame(internal_mounted_animState.value());
+}
+
+DeathSpawnInfo::DeathSpawnInfo(const std::string_view monsterName,const uint8_t spawnAmt,const vf2d spawnOffset)
+:monsterSpawnName(monsterName),spawnAmt(spawnAmt),spawnLocOffset(spawnOffset){
+ if(!MONSTER_DATA.count(std::string(monsterName)))ERR(std::format("WARNING! Monster {} specified in DeathSpawnInfo does not exist! Please provide a proper monster name.",monsterName));
+}
+
+void DeathSpawnInfo::Spawn(const vf2d monsterDeathPos,const bool onUpperLevel){
+ for(uint8_t i=0;iSpawnMonster(monsterDeathPos+spawnLocOffset,MONSTER_DATA.at(monsterSpawnName),onUpperLevel).iframe_timer=0.25f;
+ }
}
\ No newline at end of file
diff --git a/Adventures in Lestoria/Monster.h b/Adventures in Lestoria/Monster.h
index f7787eee..ba64b368 100644
--- a/Adventures in Lestoria/Monster.h
+++ b/Adventures in Lestoria/Monster.h
@@ -51,7 +51,6 @@ All rights reserved.
INCLUDE_ITEM_DATA
INCLUDE_MONSTER_DATA
-INCLUDE_game
struct DamageNumber;
class AiL;
@@ -65,21 +64,15 @@ class DeathSpawnInfo{
uint8_t spawnAmt;
vf2d spawnLocOffset;
public:
- DeathSpawnInfo(const std::string_view monsterName,const uint8_t spawnAmt,const vf2d spawnOffset={})
- :monsterSpawnName(monsterName),spawnAmt(spawnAmt),spawnLocOffset(spawnOffset){
- if(!MONSTER_DATA.count(std::string(monsterName)))ERR(std::format("WARNING! Monster {} specified in DeathSpawnInfo does not exist! Please provide a proper monster name.",monsterName));
- }
- void Spawn(const vf2d monsterDeathPos,const bool onUpperLevel){
- for(uint8_t i=0;iSpawnMonster(monsterDeathPos+spawnLocOffset,MONSTER_DATA.at(monsterSpawnName),onUpperLevel);
- }
- }
+ DeathSpawnInfo(const std::string_view monsterName,const uint8_t spawnAmt,const vf2d spawnOffset={});
+ void Spawn(const vf2d monsterDeathPos,const bool onUpperLevel);
};
class Monster:IAttributable{
friend struct STRATEGY;
friend class AiL;
friend class InventoryCreator;
+ friend class DeathSpawnInfo;
public:
Monster()=delete;
Monster(vf2d pos,MonsterData data,bool upperLevel=false,bool bossMob=false);
@@ -92,7 +85,7 @@ public:
//Obtains the size multiplier (from 0.f-1.f).
float GetSizeMult()const;
Animate2D::Frame GetFrame()const;
- const std::optionalGetMountedFrame()const;
+ const std::optionalGetMountedFrame()const;
bool Update(float fElapsedTime);
//Returns true when damage is actually dealt. Provide whether or not the attack is on the upper level or not. Monsters must be on the same level to get hit by it. (there is a death check and level check here.)
//If you need to hurt multiple enemies try AiL::HurtEnemies()
@@ -236,6 +229,7 @@ private:
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 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::vectordeathData; //Data that contains further actions and information when this monster dies. Mostly used to spawn sub-monsters from a defeated monster.
+ vf2d mountedSprOffset{};
private:
struct STRATEGY{
static int _GetInt(Monster&m,std::string param,std::string strategy,int index=0);
@@ -245,7 +239,7 @@ private:
static double _GetPixels(Monster&m,std::string param,std::string strategy,int index=0);
static vf2d _GetVec(Monster&m,std::string param,std::string strategy,int index=0);
static const std::string&_GetString(Monster&m,std::string param,std::string strategy,int index=0);
- static datafile _Get(Monster&m,std::string param,std::string strategy);
+ static const datafile&_Get(Monster&m,std::string param,std::string strategy);
static void RUN_STRATEGY(Monster&m,float fElapsedTime);
static void RUN_TOWARDS(Monster&m,float fElapsedTime,std::string strategy);
static void SHOOT_AFAR(Monster&m,float fElapsedTime,std::string strategy);
diff --git a/Adventures in Lestoria/RUN_STRATEGY.cpp b/Adventures in Lestoria/RUN_STRATEGY.cpp
index b0ccdfdd..32332584 100644
--- a/Adventures in Lestoria/RUN_STRATEGY.cpp
+++ b/Adventures in Lestoria/RUN_STRATEGY.cpp
@@ -101,7 +101,7 @@ vf2d Monster::STRATEGY::_GetVec(Monster&m,std::string param,std::string strategy
return {DATA["MonsterStrategy"][strategy].GetProperty(param).GetReal(index),DATA["MonsterStrategy"][strategy].GetProperty(param).GetReal(index+1)};
}
}
-datafile Monster::STRATEGY::_Get(Monster&m,std::string param,std::string strategy){
+const datafile&Monster::STRATEGY::_Get(Monster&m,std::string param,std::string strategy){
if(m.IsNPC()&&DATA["NPCs"][m.name].HasProperty(param)){
return DATA["NPCs"][m.name].GetProperty(param);
}else
diff --git a/Adventures in Lestoria/Version.h b/Adventures in Lestoria/Version.h
index 676d5b09..b9bae47b 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 9180
+#define VERSION_BUILD 9199
#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 7b1f0856..a38be711 100644
--- a/Adventures in Lestoria/assets/Campaigns/2_1.tmx
+++ b/Adventures in Lestoria/assets/Campaigns/2_1.tmx
@@ -1,5 +1,5 @@
-