diff --git a/.gitignore b/.gitignore
index 16ba4891..fcf34915 100644
--- a/.gitignore
+++ b/.gitignore
@@ -400,4 +400,5 @@ test.cpp
/x64/Release/Adventures in Lestoria.zip
/x64/Release/Adventures in Lestoria_web.zip
/x64/Release/AdventuresInLestoria_web.zip
-packkey.cpp
\ No newline at end of file
+packkey.cpp
+desktop.ini
\ No newline at end of file
diff --git a/Adventures in Lestoria/Adventures in Lestoria.vcxproj b/Adventures in Lestoria/Adventures in Lestoria.vcxproj
index 98950e71..f9203f87 100644
--- a/Adventures in Lestoria/Adventures in Lestoria.vcxproj
+++ b/Adventures in Lestoria/Adventures in Lestoria.vcxproj
@@ -712,6 +712,10 @@
+
+
+
+
diff --git a/Adventures in Lestoria/Arrow.cpp b/Adventures in Lestoria/Arrow.cpp
index 8f196431..02fe9d65 100644
--- a/Adventures in Lestoria/Arrow.cpp
+++ b/Adventures in Lestoria/Arrow.cpp
@@ -44,11 +44,15 @@ All rights reserved.
INCLUDE_game
-Arrow::Arrow(vf2d pos,vf2d targetPos,vf2d vel,float radius,int damage,bool upperLevel,bool friendly,Pixel col)
- :finalDistance(geom2d::line(pos,targetPos).length()*1.2f),acc(PI/2*"Ranger.Auto Attack.ArrowSpd"_F),
+Arrow::Arrow(vf2d pos,vf2d targetPos,vf2d vel,float acc,float radius,int damage,bool upperLevel,bool friendly,Pixel col)
+ :finalDistance(geom2d::line(pos,targetPos).length()*1.2f),acc(acc),targetPos(targetPos),
Bullet(pos,vel,radius,damage,
"arrow.png",upperLevel,false,INFINITE,true,friendly,col){}
+Arrow::Arrow(vf2d pos,vf2d targetPos,vf2d vel,const std::string_view gfx,float acc,float radius,int damage,bool upperLevel,bool friendly,Pixel col)
+ :finalDistance(geom2d::line(pos,targetPos).length()*1.2f),acc(acc),
+ Bullet(pos,vel,radius,damage,std::string(gfx),upperLevel,false,INFINITE,true,friendly,col){}
+
void Arrow::Update(float fElapsedTime){
float speed=vel.mag();
travelDistance+=speed*fElapsedTime;
@@ -59,6 +63,10 @@ void Arrow::Update(float fElapsedTime){
}
}
+void Arrow::PointToBestTargetPath(const int perceptionLevel){
+ //TODO: Figure out arrow target and spawn an arrow.
+}
+
bool Arrow::PlayerHit(Player*player)
{
deactivated=true;
diff --git a/Adventures in Lestoria/Bear.cpp b/Adventures in Lestoria/Bear.cpp
index 46303ec4..013cd344 100644
--- a/Adventures in Lestoria/Bear.cpp
+++ b/Adventures in Lestoria/Bear.cpp
@@ -76,7 +76,7 @@ void Monster::STRATEGY::BEAR(Monster&m,float fElapsedTime,std::string strategy){
if(m.F(A::CASTING_TIMER)==0.f){
m.I(A::PHASE)=2;
m.F(A::CASTING_TIMER)=ConfigFloat("Attack Animation Wait Time");
- m.PerformOtherAnimation(0);
+ m.PerformAnimation("SLAM");
}
}break;
case 2:{
diff --git a/Adventures in Lestoria/Boar.cpp b/Adventures in Lestoria/Boar.cpp
index 295ddd6a..d7a0a8bf 100644
--- a/Adventures in Lestoria/Boar.cpp
+++ b/Adventures in Lestoria/Boar.cpp
@@ -73,7 +73,7 @@ void Monster::STRATEGY::BOAR(Monster&m,float fElapsedTime,std::string strategy){
m.UpdateFacingDirection(game->GetPlayer()->GetPos());
}else{
ScratchPhaseTransition:
- m.PerformOtherAnimation(0);
+ m.PerformAnimation("SCRATCH");
m.F(A::CASTING_TIMER)=ConfigInt("Ground Scratch Count")*m.GetCurrentAnimation().GetTotalAnimationDuration();
m.phase=PhaseName::SCRATCH;
}
diff --git a/Adventures in Lestoria/BulletTypes.h b/Adventures in Lestoria/BulletTypes.h
index d41436d0..f3020b60 100644
--- a/Adventures in Lestoria/BulletTypes.h
+++ b/Adventures in Lestoria/BulletTypes.h
@@ -67,8 +67,11 @@ struct Arrow:public Bullet{
float travelDistance=0;
float finalDistance=0;
float acc=PI/2*250;
- Arrow(vf2d pos,vf2d targetPos,vf2d vel,float radius,int damage,bool upperLevel,bool friendly=false,Pixel col=WHITE);
+ vf2d targetPos;
+ Arrow(vf2d pos,vf2d targetPos,vf2d vel,float acc,float radius,int damage,bool upperLevel,bool friendly=false,Pixel col=WHITE);
+ Arrow(vf2d pos,vf2d targetPos,vf2d vel,const std::string_view gfx,float acc,float radius,int damage,bool upperLevel,bool friendly=false,Pixel col=WHITE);
void Update(float fElapsedTime)override;
+ void PointToBestTargetPath(const int perceptionLevel);
bool PlayerHit(Player*player)override;
bool MonsterHit(Monster&monster)override;
};
diff --git a/Adventures in Lestoria/Goblin_Bow.cpp b/Adventures in Lestoria/Goblin_Bow.cpp
new file mode 100644
index 00000000..c6b7149c
--- /dev/null
+++ b/Adventures in Lestoria/Goblin_Bow.cpp
@@ -0,0 +1,130 @@
+#pragma region License
+/*
+License (OLC-3)
+~~~~~~~~~~~~~~~
+
+Copyright 2024 Joshua Sigona
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+1. Redistributions or derivations of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+
+2. Redistributions or derivative works in binary form must reproduce the above
+copyright notice. This list of conditions and the following disclaimer must be
+reproduced in the documentation and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its contributors may
+be used to endorse or promote products derived from this software without specific
+prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+Portions of this software are copyright © 2024 The FreeType
+Project (www.freetype.org). Please see LICENSE_FT.txt for more information.
+All rights reserved.
+*/
+#pragma endregion
+#include "AdventuresInLestoria.h"
+#include "DEFINES.h"
+#include "Monster.h"
+#include "MonsterStrategyHelpers.h"
+#include "BulletTypes.h"
+#include "util.h"
+/*
+Attack Strategie:
+if range > 1000 move to a 850 range.
+if range 1000-700. Stand still and shoot. (reload twice as fast)
+if range between 500 and 700. Shoot and run in random direction while reloading without getting out of the 500 - 700 range
+range < 500 while reloading try to get distance. still shoot if reload finishes
+After every attack: reload takes 2 seconds.
+before shooting takes 1 second.
+*/
+
+INCLUDE_game
+INCLUDE_ANIMATION_DATA
+INCLUDE_BULLET_LIST
+using A=Attribute;
+
+void Monster::STRATEGY::GOBLIN_BOW(Monster&m,float fElapsedTime,std::string strategy){
+ #pragma region Phase, Animation, and Helper function setup
+ enum PhaseName{
+ 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;
+
+ switch(m.phase){
+ case MOVE:{
+ float distToPlayer=m.GetDistanceFrom(game->GetPlayer()->GetPos());
+
+ const bool outsideMaxShootingRange=distToPlayer>=ConfigPixelsArr("Stand Still and Shoot Range",1);
+
+ auto PrepareToShoot=[&](){
+ m.phase=WINDUP;
+ m.F(A::SHOOT_TIMER)=ConfigFloat("Attack Windup Time");
+ SetFacingAnimation(SHOOT_ANIMATION,game->GetPlayer()->GetPos());
+ };
+
+ if(outsideMaxShootingRange){
+ m.target=game->GetPlayer()->GetPos();
+ RUN_TOWARDS(m,fElapsedTime,"Run Towards");
+ }else
+ if(m.F(A::ATTACK_COOLDOWN)>=ConfigFloat("Attack Reload Time")){
+ PrepareToShoot();
+ }else
+ if(distToPlayer(m.GetPos(),game->GetPlayer()->GetPos()).upoint(-1);
+ RUN_TOWARDS(m,fElapsedTime,"Run Towards");
+ }else
+ if(distToPlayer>=ConfigPixelsArr("Random Direction Range",0)&&distToPlayerGetPlayer()->GetPos(),m.GetPos());
+ float targetDir=m.B(A::RANDOM_DIRECTION)==CW?dirFromPlayer+PI/4:dirFromPlayer-PI/4;
+ m.target=game->GetPlayer()->GetPos()+vf2d{m.F(A::RANDOM_RANGE),targetDir}.cart();
+ RUN_TOWARDS(m,fElapsedTime,"Run Towards");
+ }else{ //Only the stand still and shoot range remains...
+ PrepareToShoot();
+ }
+ }break;
+ case WINDUP:{
+ m.F(A::SHOOT_TIMER)-=fElapsedTime;
+ if(m.F(A::SHOOT_TIMER)<=0){
+ 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",PI/2*ConfigFloat("Arrow Spd"),ConfigFloat("Arrow Hitbox Radius"),m.GetAttack(),m.OnUpperLevel())EndBullet;
+ Arrow&arrow=static_cast(*BULLET_LIST.back());
+ arrow.PointToBestTargetPath(0);
+ m.phase=MOVE;
+ }
+ m.B(A::RANDOM_DIRECTION)=util::random()%2;
+ m.F(A::RANDOM_RANGE)=util::random_range(ConfigPixelsArr("Random Direction Range",0),ConfigPixelsArr("Random Direction Range",1));
+ }break;
+ }
+}
\ No newline at end of file
diff --git a/Adventures in Lestoria/Goblin_Dagger.cpp b/Adventures in Lestoria/Goblin_Dagger.cpp
index 613930d2..22294ef5 100644
--- a/Adventures in Lestoria/Goblin_Dagger.cpp
+++ b/Adventures in Lestoria/Goblin_Dagger.cpp
@@ -75,7 +75,7 @@ void Monster::STRATEGY::GOBLIN_DAGGER(Monster&m,float fElapsedTime,std::string s
};
auto SetFacingAnimation=[&](ANIMATION_OFFSET animation,vf2d target){
- m.PerformOtherAnimation(int(animation)+int(m.GetFacingDirectionToTarget(target)));
+ m.PerformAnimation("");
};
auto IsSpriteFlipped=[&](){return m.GetFacingDirection()==RIGHT;};
diff --git a/Adventures in Lestoria/Monster.cpp b/Adventures in Lestoria/Monster.cpp
index 1a1f80c3..5e18365d 100644
--- a/Adventures in Lestoria/Monster.cpp
+++ b/Adventures in Lestoria/Monster.cpp
@@ -66,14 +66,10 @@ 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){
- bool firstAnimation=true;
- for(std::string&anim:data.GetAnimations()){
+ for(const std::string&anim:data.GetAnimations()){
animation.AddState(anim,ANIMATION_DATA[anim]);
- if(firstAnimation){
- animation.ChangeState(internal_animState,anim);
- firstAnimation=false;
- }
}
+ PerformIdleAnimation();
stats.A("Health")=data.GetHealth();
stats.A("Attack")=data.GetAttack();
stats.A("Move Spd %")=data.GetMoveSpdMult();
@@ -125,28 +121,28 @@ Animate2D::Frame Monster::GetFrame()const{
return animation.GetFrame(internal_animState);
}
void Monster::PerformJumpAnimation(){
- animation.ChangeState(internal_animState,MONSTER_DATA[name].GetJumpAnimation());
+ PerformAnimation(MONSTER_DATA[name].GetJumpAnimation());
}
void Monster::PerformShootAnimation(){
- animation.ChangeState(internal_animState,MONSTER_DATA[name].GetShootAnimation());
+ PerformAnimation(MONSTER_DATA[name].GetShootAnimation());
}
void Monster::PerformIdleAnimation(){
- animation.ChangeState(internal_animState,MONSTER_DATA[name].GetIdleAnimation());
+ PerformAnimation(MONSTER_DATA[name].GetIdleAnimation());
}
void Monster::PerformNPCDownAnimation(){
- animation.ChangeState(internal_animState,MONSTER_DATA[name].GetIdleAnimation());
+ PerformAnimation(MONSTER_DATA[name].GetIdleAnimation());
}
void Monster::PerformNPCUpAnimation(){
- animation.ChangeState(internal_animState,MONSTER_DATA[name].GetJumpAnimation());
+ PerformAnimation(MONSTER_DATA[name].GetJumpAnimation());
}
void Monster::PerformNPCLeftAnimation(){
- animation.ChangeState(internal_animState,MONSTER_DATA[name].GetShootAnimation());
+ PerformAnimation(MONSTER_DATA[name].GetShootAnimation());
}
void Monster::PerformNPCRightAnimation(){
- animation.ChangeState(internal_animState,MONSTER_DATA[name].GetDeathAnimation());
+ PerformAnimation(MONSTER_DATA[name].GetDeathAnimation());
}
-void Monster::PerformOtherAnimation(const uint8_t otherInd){
- animation.ChangeState(internal_animState,MONSTER_DATA[name].GetAnimations()[4+otherInd]);
+void Monster::PerformAnimation(const std::string_view animationName){
+ animation.ChangeState(internal_animState,std::string(animationName));
}
bool Monster::_SetX(float x,const bool monsterInvoked){
vf2d newPos={x,pos.y};
@@ -879,7 +875,6 @@ const float Monster::GetDistanceFrom(vf2d target)const{
const Direction Monster::GetFacingDirectionToTarget(vf2d target)const{
float targetDirection=util::angleTo(GetPos(),target);
- LOG(targetDirection<-PI/4)return Direction::EAST;
else if(targetDirection>=3*PI/4||targetDirection<-3*PI/4)return Direction::WEST;
else if(targetDirection<=3*PI/4&&targetDirection>PI/4)return Direction::SOUTH;
diff --git a/Adventures in Lestoria/Monster.h b/Adventures in Lestoria/Monster.h
index d47af050..e932567f 100644
--- a/Adventures in Lestoria/Monster.h
+++ b/Adventures in Lestoria/Monster.h
@@ -56,13 +56,6 @@ class AiL;
enum class Attribute;
-enum class MonsterAnimation{
- IDLE,
- JUMP,
- SHOOT,
- DEATH
-};
-
class GameEvent;
class Monster:IAttributable{
@@ -109,7 +102,7 @@ public:
void PerformNPCUpAnimation();
void PerformNPCLeftAnimation();
void PerformNPCRightAnimation();
- void PerformOtherAnimation(const uint8_t otherInd);
+ void PerformAnimation(const std::string_view animationName);
const Animate2D::FrameSequence&GetCurrentAnimation()const;
const bool OnUpperLevel()const;
void Moved();
@@ -219,6 +212,8 @@ private:
static int _GetInt(Monster&m,std::string param,std::string strategy,int index=0);
static float _GetFloat(Monster&m,std::string param,std::string strategy,int index=0);
static Pixel _GetPixel(Monster&m,std::string param,std::string strategy,int index=0);
+ //Converts unit distances to pixels. (Every 100 units = 24 pixels)
+ 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);
@@ -235,6 +230,7 @@ private:
static void NPC(Monster&m,float fElapsedTime,std::string strategy);
static void BOAR(Monster&m,float fElapsedTime,std::string strategy);
static void GOBLIN_DAGGER(Monster&m,float fElapsedTime,std::string strategy);
+ static void GOBLIN_BOW(Monster&m,float fElapsedTime,std::string strategy);
};
bool bumpedIntoTerrain=false; //Gets set to true before a strategy executes if the monster runs into some terrain on this frame.
bool attackedByPlayer=false; //Gets set to true before a strategy executes if the monster has been attacked by the player.
diff --git a/Adventures in Lestoria/MonsterAttribute.h b/Adventures in Lestoria/MonsterAttribute.h
index 4bb674aa..6c0c4949 100644
--- a/Adventures in Lestoria/MonsterAttribute.h
+++ b/Adventures in Lestoria/MonsterAttribute.h
@@ -108,4 +108,7 @@ enum class Attribute{
INITIALIZED,
JUMP_MOVE_TO_TARGET_TIMER,
ATTACK_TYPE,
+ ATTACK_COOLDOWN,
+ RANDOM_DIRECTION,
+ RANDOM_RANGE
};
\ No newline at end of file
diff --git a/Adventures in Lestoria/MonsterData.cpp b/Adventures in Lestoria/MonsterData.cpp
index c758a82f..777a166a 100644
--- a/Adventures in Lestoria/MonsterData.cpp
+++ b/Adventures in Lestoria/MonsterData.cpp
@@ -51,7 +51,7 @@ std::mapMONSTER_DATA;
MonsterData::MonsterData()
:atk(0),collisionDmg(0),hp(0),moveSpd(0),size(0),strategy("Run Towards"){}
-MonsterData::MonsterData(std::string name,int hp,int atk,const uint32_t xp,std::vectoranimations,std::vectordrops,float moveSpd,float size,std::string strategy,int collisionDmg):
+MonsterData::MonsterData(std::string name,int hp,int atk,const uint32_t xp,std::vectordrops,float moveSpd,float size,std::string strategy,int collisionDmg):
name(name),hp(hp),atk(atk),xp(xp),moveSpd(moveSpd),size(size),strategy(strategy),animations(animations),dropData(drops),collisionDmg(collisionDmg){}
void MonsterData::InitializeMonsterData(){
@@ -60,12 +60,7 @@ void MonsterData::InitializeMonsterData(){
if(MONSTER_DATA.count(key)){
ERR("WARNING! A monster with the name "<animations{
- MonsterName+"_IDLE",
- MonsterName+"_JUMP",
- MonsterName+"_SPIT",
- MonsterName+"_DIE",
- };
+ std::vectoranimations;
MonsterData::imgs[MonsterName]=NEW Renderable();
const rcode imgLoadResult=MonsterData::imgs[MonsterName]->Load("assets/monsters/"+MonsterName+".png");
@@ -94,78 +89,32 @@ void MonsterData::InitializeMonsterData(){
ANIMATION_DATA[state]=anim;
};
- for(int i=0;idrops;
@@ -191,7 +140,6 @@ void MonsterData::InitializeMonsterData(){
DATA["Monsters"][MonsterName]["Health"].GetInt(),
DATA["Monsters"][MonsterName]["Attack"].GetInt(),
DATA["Monsters"][MonsterName]["XP"].GetInt(),
- animations,
drops,
float(DATA["Monsters"][MonsterName]["MoveSpd"].GetReal()),
float(DATA["Monsters"][MonsterName]["Size"].GetReal())/100,
@@ -199,6 +147,19 @@ void MonsterData::InitializeMonsterData(){
DATA["Monsters"][MonsterName]["CollisionDmg"].GetInt()
);
+ 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;
+ }
+
+ animationRow++;
+ }
+
monster.hurtSound=hurtSound;
monster.deathSound=deathSound;
monster.walkSound=walkSound;
@@ -260,78 +221,32 @@ void MonsterData::InitializeNPCData(){
ANIMATION_DATA[state]=anim;
};
- for(int i=0;idrops;
@@ -352,7 +267,20 @@ void MonsterData::InitializeNPCData(){
ERR("WARNING! Strategy for "<&MonsterData::GetDropData(){
return dropData;
diff --git a/Adventures in Lestoria/MonsterData.h b/Adventures in Lestoria/MonsterData.h
index ab6ef7b5..59436f4f 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
INCLUDE_ITEM_DATA
@@ -64,20 +65,22 @@ private:
uint32_t xp;
float moveSpd;//1.0=100%
float size;
- std::vector animations;
+ std::unordered_setanimations;
+ 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;
- std::string jumpAnimation="WARRIOR_IDLE_S";
- std::string shootAnimation="WARRIOR_IDLE_S";
- std::string deathAnimation="WARRIOR_IDLE_S";
EventName hurtSound="";
EventName deathSound="";
EventName walkSound="";
std::vector 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:
MonsterData();
- MonsterData(std::string name,int hp,int atk,const uint32_t xp,std::vectoranimations,std::vectordrops,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::vectordrops,float moveSpd=1.0f,float size=1.0f,std::string strategy="Run Towards",int collisionDmg=0);
int GetHealth();
int GetAttack();
const uint32_t GetXP()const;
@@ -93,7 +96,7 @@ public:
const EventName&GetDeathSound();
const EventName&GetWalkSound();
const bool IsNPC()const;
- std::vectorGetAnimations(){
+ std::unordered_setGetAnimations(){
return animations;
}
const std::vector&GetDropData();
@@ -101,4 +104,6 @@ public:
static void InitializeMonsterData();
static void InitializeNPCData();
static std::mapimgs;
+ const bool HasFourWaySprites()const;
+ void SetUsesFourWaySprites();
};
\ No newline at end of file
diff --git a/Adventures in Lestoria/MonsterStrategyHelpers.h b/Adventures in Lestoria/MonsterStrategyHelpers.h
index 47288b61..9f9bf876 100644
--- a/Adventures in Lestoria/MonsterStrategyHelpers.h
+++ b/Adventures in Lestoria/MonsterStrategyHelpers.h
@@ -39,9 +39,13 @@ All rights reserved.
#define ConfigInt(param) _GetInt(m,param,strategy)
#define ConfigFloat(param) _GetFloat(m,param,strategy)
#define ConfigPixel(param) _GetPixel(m,param,strategy)
+//Converts unit distances to pixels. (Every 100 units = 24 pixels)
+#define ConfigPixels(param) _GetPixels(m,param,strategy)
#define ConfigString(param) _GetString(m,param,strategy)
#define ConfigVec(param) _GetVec(m,param,strategy)
#define Config(param) _Get(m,param,strategy)
+//Converts unit distances to pixels. (Every 100 units = 24 pixels)
+#define ConfigPixelsArr(param,ind) _GetPixels(m,param,strategy,ind)
#define ConfigIntArr(param,ind) _GetInt(m,param,strategy,ind)
#define ConfigFloatArr(param,ind) _GetFloat(m,param,strategy,ind)
#define ConfigStringArr(param,ind) _GetString(m,param,strategy,ind)
diff --git a/Adventures in Lestoria/RUN_STRATEGY.cpp b/Adventures in Lestoria/RUN_STRATEGY.cpp
index 88c21311..b5a5e788 100644
--- a/Adventures in Lestoria/RUN_STRATEGY.cpp
+++ b/Adventures in Lestoria/RUN_STRATEGY.cpp
@@ -55,6 +55,7 @@ void Monster::InitializeStrategies(){
STRATEGY_DATA.insert("NPC",Monster::STRATEGY::NPC);
STRATEGY_DATA.insert("Boar",Monster::STRATEGY::BOAR);
STRATEGY_DATA.insert("Goblin Dagger",Monster::STRATEGY::GOBLIN_DAGGER);
+ STRATEGY_DATA.insert("Goblin Bow",Monster::STRATEGY::GOBLIN_BOW);
STRATEGY_DATA.SetInitialized();
}
@@ -120,6 +121,17 @@ Pixel Monster::STRATEGY::_GetPixel(Monster&m,std::string param,std::string strat
}
}
+double Monster::STRATEGY::_GetPixels(Monster&m,std::string param,std::string strategy,int index){
+ if(m.IsNPC()&&DATA["NPCs"][m.name].HasProperty(param)){
+ return DATA["NPCs"][m.name].GetProperty(param).GetReal(index)/100.f*24;
+ }else
+ if(!m.IsNPC()&&DATA["Monsters"][m.name].HasProperty(param)){
+ return DATA["Monsters"][m.name].GetProperty(param).GetReal(index)/100.f*24;
+ } else {
+ return DATA["MonsterStrategy"][strategy].GetProperty(param).GetReal(index)/100.f*24;
+ }
+}
+
void Monster::STRATEGY::RUN_STRATEGY(Monster&m,float fElapsedTime){
m.GetStrategy()(m,fElapsedTime,m.strategy);
}
\ No newline at end of file
diff --git a/Adventures in Lestoria/Ranger.cpp b/Adventures in Lestoria/Ranger.cpp
index 6493331d..95a6d18f 100644
--- a/Adventures in Lestoria/Ranger.cpp
+++ b/Adventures in Lestoria/Ranger.cpp
@@ -71,7 +71,7 @@ bool Ranger::AutoAttack(){
vf2d extendedLine=pointTowardsCursor.upoint(1.1f);
float angleToCursor=atan2(extendedLine.y-GetPos().y,extendedLine.x-GetPos().x);
attack_cooldown_timer=ARROW_ATTACK_COOLDOWN-GetAttackRecoveryRateReduction();
- BULLET_LIST.push_back(std::make_unique(Arrow(GetPos(),extendedLine,vf2d{cos(angleToCursor)*"Ranger.Auto Attack.ArrowSpd"_F,float(sin(angleToCursor)*"Ranger.Auto Attack.ArrowSpd"_F-PI/8*"Ranger.Auto Attack.ArrowSpd"_F)}+movementVelocity/1.5f,"Ranger.Auto Attack.Radius"_F/100*12,int(GetAttack()*"Ranger.Auto Attack.DamageMult"_F),OnUpperLevel(),true)));
+ BULLET_LIST.push_back(std::make_unique(Arrow(GetPos(),extendedLine,vf2d{cos(angleToCursor)*"Ranger.Auto Attack.ArrowSpd"_F,float(sin(angleToCursor)*"Ranger.Auto Attack.ArrowSpd"_F-PI/8*"Ranger.Auto Attack.ArrowSpd"_F)}+movementVelocity/1.5f,PI/2*"Ranger.Auto Attack.ArrowSpd"_F,"Ranger.Auto Attack.Radius"_F,int(GetAttack()*"Ranger.Auto Attack.DamageMult"_F),OnUpperLevel(),true)));
SetState(State::SHOOT_ARROW);
SetAnimationBasedOnTargetingDirection(angleToCursor);
SoundEffect::PlaySFX("Ranger.Auto Attack.Sound"_S,SoundEffect::CENTERED);
diff --git a/Adventures in Lestoria/SlimeKing.cpp b/Adventures in Lestoria/SlimeKing.cpp
index 7d24883b..dd693f07 100644
--- a/Adventures in Lestoria/SlimeKing.cpp
+++ b/Adventures in Lestoria/SlimeKing.cpp
@@ -229,7 +229,7 @@ void Monster::STRATEGY::SLIMEKING(Monster&m,float fElapsedTime,std::string strat
}
if(m.GetState()==State::CASTING){
- m.PerformOtherAnimation(0);
+ m.PerformAnimation("CHARGEUP");
if(m.F(A::CASTING_TIMER)==0){
m.SetState(State::NORMAL);
m.I(A::JUMP_COUNT)++;
diff --git a/Adventures in Lestoria/Ursule.cpp b/Adventures in Lestoria/Ursule.cpp
index 26233cd8..d47d8338 100644
--- a/Adventures in Lestoria/Ursule.cpp
+++ b/Adventures in Lestoria/Ursule.cpp
@@ -96,7 +96,7 @@ void Monster::STRATEGY::URSULE(Monster&m,float fElapsedTime,std::string strategy
case 1:{ //Run bear strategy in phase 1.
auto TransitionToPhase2=[&](){
m.phase=2;
- m.PerformOtherAnimation(1);
+ m.PerformAnimation("SIT");
m.AddBuff(BARRIER_DAMAGE_REDUCTION,INFINITE,ConfigFloat("Phase 2.Barrier Damage Reduction")/100.f);
m.I(A::PHASE_REPEAT_COUNT)=ConfigInt("Phase 2.Wisp Pattern Spawn Count");
SoundEffect::PlaySFX("Ursule Phase Transition",SoundEffect::CENTERED);
@@ -153,7 +153,7 @@ void Monster::STRATEGY::URSULE(Monster&m,float fElapsedTime,std::string strategy
BEAR(m,fElapsedTime,"Bear");
}break;
case 2:{
- m.PerformOtherAnimation(2);
+ m.PerformAnimation("GLARE");
m.F(A::SHOOT_TIMER)=std::max(0.f,m.F(A::SHOOT_TIMER)-fElapsedTime);
#pragma region Environment Color Change Handling
@@ -272,7 +272,7 @@ void Monster::STRATEGY::URSULE(Monster&m,float fElapsedTime,std::string strategy
if(m.GetRemainingHPPct()<=ConfigFloat("Phase 4.Change")/100.f){
auto TransitionToPhase5=[&](){
m.phase=5;
- m.PerformOtherAnimation(1);
+ m.PerformAnimation("SIT");
SoundEffect::PlaySFX("Ursule Phase Transition",SoundEffect::CENTERED);
m.F(A::ENVIRONMENT_TIMER)=ConfigFloat("Phase 4.Environment Fade-out Time");
m.I(A::ENVIRONMENT_PHASE)=0;
@@ -305,7 +305,7 @@ void Monster::STRATEGY::URSULE(Monster&m,float fElapsedTime,std::string strategy
if(m.F(A::CASTING_TIMER)==0.f){
m.F(A::CASTING_TIMER)=ConfigFloat("Phase 3.Charge Cast Time");
m.UpdateFacingDirection(geom2d::line(m.GetPos(),game->GetPlayer()->GetPos()).vector());
- m.PerformOtherAnimation(4);
+ m.PerformAnimation("CHARGE");
m.B(A::COLLIDED_WITH_PLAYER)=false;
}
}
@@ -322,7 +322,7 @@ void Monster::STRATEGY::URSULE(Monster&m,float fElapsedTime,std::string strategy
m.target.y=std::clamp(m.target.y,0.f,float(game->GetCurrentMap().GetMapData().height*game->GetCurrentMap().GetMapData().tileheight));
m.F(A::TARGET_TIMER)=ConfigFloat("Phase 3.Charge Max Run Time");
m.F(A::CHARGE_COOLDOWN)=ConfigFloat("Phase 3.Charge Attack Cooldown");
- m.PerformOtherAnimation(3);
+ m.PerformAnimation("CHARGING");
}
break;
}
@@ -360,7 +360,7 @@ void Monster::STRATEGY::URSULE(Monster&m,float fElapsedTime,std::string strategy
}
}break;
case 5:{ //Final boss phase.
- m.PerformOtherAnimation(2);
+ m.PerformAnimation("GLARE");
m.F(A::SHOOT_TIMER)=std::max(0.f,m.F(A::SHOOT_TIMER)-fElapsedTime);
#pragma region Environment Color Change Handling
diff --git a/Adventures in Lestoria/Version.h b/Adventures in Lestoria/Version.h
index 5e02614f..ae3c74eb 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 9091
+#define VERSION_BUILD 9115
#define stringify(a) stringify_(a)
#define stringify_(a) #a
diff --git a/Adventures in Lestoria/assets.zip b/Adventures in Lestoria/assets.zip
new file mode 100644
index 00000000..0e4b83d6
Binary files /dev/null and b/Adventures in Lestoria/assets.zip differ
diff --git a/Adventures in Lestoria/assets/Campaigns/2_1.tmx b/Adventures in Lestoria/assets/Campaigns/2_1.tmx
index 877e16d5..4fc148e3 100644
--- a/Adventures in Lestoria/assets/Campaigns/2_1.tmx
+++ b/Adventures in Lestoria/assets/Campaigns/2_1.tmx
@@ -1,5 +1,5 @@
-