Change the radius of ranger's auto attack to use pixel units instead of tile units. Remove hardcoded player acceleration on shooting a player arrow. Refactor monster animation system to incorporate custom animations as part of the main set of animations and handle future 4-way directional animations easily. Release Build 9115.

mac-build
sigonasr2 7 months ago
parent 593180c730
commit 33d81125df
  1. 1
      .gitignore
  2. 4
      Adventures in Lestoria/Adventures in Lestoria.vcxproj
  3. 12
      Adventures in Lestoria/Arrow.cpp
  4. 2
      Adventures in Lestoria/Bear.cpp
  5. 2
      Adventures in Lestoria/Boar.cpp
  6. 5
      Adventures in Lestoria/BulletTypes.h
  7. 130
      Adventures in Lestoria/Goblin_Bow.cpp
  8. 2
      Adventures in Lestoria/Goblin_Dagger.cpp
  9. 27
      Adventures in Lestoria/Monster.cpp
  10. 12
      Adventures in Lestoria/Monster.h
  11. 3
      Adventures in Lestoria/MonsterAttribute.h
  12. 182
      Adventures in Lestoria/MonsterData.cpp
  13. 17
      Adventures in Lestoria/MonsterData.h
  14. 4
      Adventures in Lestoria/MonsterStrategyHelpers.h
  15. 12
      Adventures in Lestoria/RUN_STRATEGY.cpp
  16. 2
      Adventures in Lestoria/Ranger.cpp
  17. 2
      Adventures in Lestoria/SlimeKing.cpp
  18. 12
      Adventures in Lestoria/Ursule.cpp
  19. 2
      Adventures in Lestoria/Version.h
  20. BIN
      Adventures in Lestoria/assets.zip
  21. 16
      Adventures in Lestoria/assets/Campaigns/2_1.tmx
  22. 19
      Adventures in Lestoria/assets/config/MonsterStrategies.txt
  23. 434
      Adventures in Lestoria/assets/config/Monsters.txt
  24. 54
      Adventures in Lestoria/assets/config/NPCs.txt
  25. 2
      Adventures in Lestoria/assets/config/classes/Ranger.txt
  26. 1
      Adventures in Lestoria/assets/config/gfx/gfx.txt
  27. BIN
      Adventures in Lestoria/assets/gamepack.pak
  28. BIN
      Adventures in Lestoria/assets/goblin_arrow.png
  29. BIN
      Adventures in Lestoria/assets/monsters/Goblin (Bow).xcf
  30. BIN
      Adventures in Lestoria/assets/rock.png
  31. 4
      Adventures in Lestoria/util.cpp
  32. 2
      Adventures in Lestoria/util.h
  33. BIN
      x64/Release/Adventures in Lestoria.exe

1
.gitignore vendored

@ -401,3 +401,4 @@ test.cpp
/x64/Release/Adventures in Lestoria_web.zip /x64/Release/Adventures in Lestoria_web.zip
/x64/Release/AdventuresInLestoria_web.zip /x64/Release/AdventuresInLestoria_web.zip
packkey.cpp packkey.cpp
desktop.ini

@ -712,6 +712,10 @@
</SubType> </SubType>
</ClCompile> </ClCompile>
<ClCompile Include="GameState.cpp" /> <ClCompile Include="GameState.cpp" />
<ClCompile Include="Goblin_Bow.cpp">
<SubType>
</SubType>
</ClCompile>
<ClCompile Include="Goblin_Dagger.cpp" /> <ClCompile Include="Goblin_Dagger.cpp" />
<ClCompile Include="InputHelper.cpp"> <ClCompile Include="InputHelper.cpp">
<SubType> <SubType>

@ -44,11 +44,15 @@ All rights reserved.
INCLUDE_game INCLUDE_game
Arrow::Arrow(vf2d pos,vf2d targetPos,vf2d vel,float radius,int damage,bool upperLevel,bool friendly,Pixel col) 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(PI/2*"Ranger.Auto Attack.ArrowSpd"_F), :finalDistance(geom2d::line(pos,targetPos).length()*1.2f),acc(acc),targetPos(targetPos),
Bullet(pos,vel,radius,damage, Bullet(pos,vel,radius,damage,
"arrow.png",upperLevel,false,INFINITE,true,friendly,col){} "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){ void Arrow::Update(float fElapsedTime){
float speed=vel.mag(); float speed=vel.mag();
travelDistance+=speed*fElapsedTime; 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) bool Arrow::PlayerHit(Player*player)
{ {
deactivated=true; deactivated=true;

@ -76,7 +76,7 @@ void Monster::STRATEGY::BEAR(Monster&m,float fElapsedTime,std::string strategy){
if(m.F(A::CASTING_TIMER)==0.f){ if(m.F(A::CASTING_TIMER)==0.f){
m.I(A::PHASE)=2; m.I(A::PHASE)=2;
m.F(A::CASTING_TIMER)=ConfigFloat("Attack Animation Wait Time"); m.F(A::CASTING_TIMER)=ConfigFloat("Attack Animation Wait Time");
m.PerformOtherAnimation(0); m.PerformAnimation("SLAM");
} }
}break; }break;
case 2:{ case 2:{

@ -73,7 +73,7 @@ void Monster::STRATEGY::BOAR(Monster&m,float fElapsedTime,std::string strategy){
m.UpdateFacingDirection(game->GetPlayer()->GetPos()); m.UpdateFacingDirection(game->GetPlayer()->GetPos());
}else{ }else{
ScratchPhaseTransition: ScratchPhaseTransition:
m.PerformOtherAnimation(0); m.PerformAnimation("SCRATCH");
m.F(A::CASTING_TIMER)=ConfigInt("Ground Scratch Count")*m.GetCurrentAnimation().GetTotalAnimationDuration(); m.F(A::CASTING_TIMER)=ConfigInt("Ground Scratch Count")*m.GetCurrentAnimation().GetTotalAnimationDuration();
m.phase=PhaseName::SCRATCH; m.phase=PhaseName::SCRATCH;
} }

@ -67,8 +67,11 @@ struct Arrow:public Bullet{
float travelDistance=0; float travelDistance=0;
float finalDistance=0; float finalDistance=0;
float acc=PI/2*250; 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 Update(float fElapsedTime)override;
void PointToBestTargetPath(const int perceptionLevel);
bool PlayerHit(Player*player)override; bool PlayerHit(Player*player)override;
bool MonsterHit(Monster&monster)override; bool MonsterHit(Monster&monster)override;
}; };

@ -0,0 +1,130 @@
#pragma region License
/*
License (OLC-3)
~~~~~~~~~~~~~~~
Copyright 2024 Joshua Sigona <sigonasr2@gmail.com>
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<ConfigPixels("Run Away Range")){
m.target=geom2d::line<float>(m.GetPos(),game->GetPlayer()->GetPos()).upoint(-1);
RUN_TOWARDS(m,fElapsedTime,"Run Towards");
}else
if(distToPlayer>=ConfigPixelsArr("Random Direction Range",0)&&distToPlayer<ConfigPixelsArr("Random Direction Range",1)){
#define CW true
#define CCW false
//We are going to walk in a circular direction either CW or CCW (determined in windup phase)
float dirFromPlayer=util::angleTo(game->GetPlayer()->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<Arrow&>(*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;
}
}

@ -75,7 +75,7 @@ void Monster::STRATEGY::GOBLIN_DAGGER(Monster&m,float fElapsedTime,std::string s
}; };
auto SetFacingAnimation=[&](ANIMATION_OFFSET animation,vf2d target){ auto SetFacingAnimation=[&](ANIMATION_OFFSET animation,vf2d target){
m.PerformOtherAnimation(int(animation)+int(m.GetFacingDirectionToTarget(target))); m.PerformAnimation("");
}; };
auto IsSpriteFlipped=[&](){return m.GetFacingDirection()==RIGHT;}; auto IsSpriteFlipped=[&](){return m.GetFacingDirection()==RIGHT;};

@ -66,14 +66,10 @@ std::map<std::string,Renderable*>MonsterData::imgs;
Monster::Monster(vf2d pos,MonsterData data,bool upperLevel,bool bossMob): 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(DOWN){
bool firstAnimation=true; for(const std::string&anim:data.GetAnimations()){
for(std::string&anim:data.GetAnimations()){
animation.AddState(anim,ANIMATION_DATA[anim]); animation.AddState(anim,ANIMATION_DATA[anim]);
if(firstAnimation){
animation.ChangeState(internal_animState,anim);
firstAnimation=false;
}
} }
PerformIdleAnimation();
stats.A("Health")=data.GetHealth(); stats.A("Health")=data.GetHealth();
stats.A("Attack")=data.GetAttack(); stats.A("Attack")=data.GetAttack();
stats.A("Move Spd %")=data.GetMoveSpdMult(); stats.A("Move Spd %")=data.GetMoveSpdMult();
@ -125,28 +121,28 @@ Animate2D::Frame Monster::GetFrame()const{
return animation.GetFrame(internal_animState); return animation.GetFrame(internal_animState);
} }
void Monster::PerformJumpAnimation(){ void Monster::PerformJumpAnimation(){
animation.ChangeState(internal_animState,MONSTER_DATA[name].GetJumpAnimation()); PerformAnimation(MONSTER_DATA[name].GetJumpAnimation());
} }
void Monster::PerformShootAnimation(){ void Monster::PerformShootAnimation(){
animation.ChangeState(internal_animState,MONSTER_DATA[name].GetShootAnimation()); PerformAnimation(MONSTER_DATA[name].GetShootAnimation());
} }
void Monster::PerformIdleAnimation(){ void Monster::PerformIdleAnimation(){
animation.ChangeState(internal_animState,MONSTER_DATA[name].GetIdleAnimation()); PerformAnimation(MONSTER_DATA[name].GetIdleAnimation());
} }
void Monster::PerformNPCDownAnimation(){ void Monster::PerformNPCDownAnimation(){
animation.ChangeState(internal_animState,MONSTER_DATA[name].GetIdleAnimation()); PerformAnimation(MONSTER_DATA[name].GetIdleAnimation());
} }
void Monster::PerformNPCUpAnimation(){ void Monster::PerformNPCUpAnimation(){
animation.ChangeState(internal_animState,MONSTER_DATA[name].GetJumpAnimation()); PerformAnimation(MONSTER_DATA[name].GetJumpAnimation());
} }
void Monster::PerformNPCLeftAnimation(){ void Monster::PerformNPCLeftAnimation(){
animation.ChangeState(internal_animState,MONSTER_DATA[name].GetShootAnimation()); PerformAnimation(MONSTER_DATA[name].GetShootAnimation());
} }
void Monster::PerformNPCRightAnimation(){ void Monster::PerformNPCRightAnimation(){
animation.ChangeState(internal_animState,MONSTER_DATA[name].GetDeathAnimation()); PerformAnimation(MONSTER_DATA[name].GetDeathAnimation());
} }
void Monster::PerformOtherAnimation(const uint8_t otherInd){ void Monster::PerformAnimation(const std::string_view animationName){
animation.ChangeState(internal_animState,MONSTER_DATA[name].GetAnimations()[4+otherInd]); animation.ChangeState(internal_animState,std::string(animationName));
} }
bool Monster::_SetX(float x,const bool monsterInvoked){ bool Monster::_SetX(float x,const bool monsterInvoked){
vf2d newPos={x,pos.y}; vf2d newPos={x,pos.y};
@ -879,7 +875,6 @@ const float Monster::GetDistanceFrom(vf2d target)const{
const Direction Monster::GetFacingDirectionToTarget(vf2d target)const{ const Direction Monster::GetFacingDirectionToTarget(vf2d target)const{
float targetDirection=util::angleTo(GetPos(),target); float targetDirection=util::angleTo(GetPos(),target);
LOG(targetDirection<<std::endl);
if(targetDirection<=PI/4&&targetDirection>-PI/4)return Direction::EAST; if(targetDirection<=PI/4&&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<-3*PI/4)return Direction::WEST;
else if(targetDirection<=3*PI/4&&targetDirection>PI/4)return Direction::SOUTH; else if(targetDirection<=3*PI/4&&targetDirection>PI/4)return Direction::SOUTH;

@ -56,13 +56,6 @@ class AiL;
enum class Attribute; enum class Attribute;
enum class MonsterAnimation{
IDLE,
JUMP,
SHOOT,
DEATH
};
class GameEvent; class GameEvent;
class Monster:IAttributable{ class Monster:IAttributable{
@ -109,7 +102,7 @@ public:
void PerformNPCUpAnimation(); void PerformNPCUpAnimation();
void PerformNPCLeftAnimation(); void PerformNPCLeftAnimation();
void PerformNPCRightAnimation(); void PerformNPCRightAnimation();
void PerformOtherAnimation(const uint8_t otherInd); void PerformAnimation(const std::string_view animationName);
const Animate2D::FrameSequence&GetCurrentAnimation()const; const Animate2D::FrameSequence&GetCurrentAnimation()const;
const bool OnUpperLevel()const; const bool OnUpperLevel()const;
void Moved(); void Moved();
@ -219,6 +212,8 @@ private:
static int _GetInt(Monster&m,std::string param,std::string strategy,int index=0); 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 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); 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 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 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 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 NPC(Monster&m,float fElapsedTime,std::string strategy);
static void BOAR(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_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 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. bool attackedByPlayer=false; //Gets set to true before a strategy executes if the monster has been attacked by the player.

@ -108,4 +108,7 @@ enum class Attribute{
INITIALIZED, INITIALIZED,
JUMP_MOVE_TO_TARGET_TIMER, JUMP_MOVE_TO_TARGET_TIMER,
ATTACK_TYPE, ATTACK_TYPE,
ATTACK_COOLDOWN,
RANDOM_DIRECTION,
RANDOM_RANGE
}; };

@ -51,7 +51,7 @@ std::map<std::string,MonsterData>MONSTER_DATA;
MonsterData::MonsterData() MonsterData::MonsterData()
:atk(0),collisionDmg(0),hp(0),moveSpd(0),size(0),strategy("Run Towards"){} :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::vector<std::string>animations,std::vector<MonsterDropData>drops,float moveSpd,float size,std::string strategy,int collisionDmg): MonsterData::MonsterData(std::string name,int hp,int atk,const uint32_t xp,std::vector<MonsterDropData>drops,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){} name(name),hp(hp),atk(atk),xp(xp),moveSpd(moveSpd),size(size),strategy(strategy),animations(animations),dropData(drops),collisionDmg(collisionDmg){}
void MonsterData::InitializeMonsterData(){ void MonsterData::InitializeMonsterData(){
@ -60,12 +60,7 @@ void MonsterData::InitializeMonsterData(){
if(MONSTER_DATA.count(key)){ if(MONSTER_DATA.count(key)){
ERR("WARNING! A monster with the name "<<key<<" already exists in the database! Duplicates are not allowed.") ERR("WARNING! A monster with the name "<<key<<" already exists in the database! Duplicates are not allowed.")
} }
std::vector<std::string>animations{ std::vector<std::string>animations;
MonsterName+"_IDLE",
MonsterName+"_JUMP",
MonsterName+"_SPIT",
MonsterName+"_DIE",
};
MonsterData::imgs[MonsterName]=NEW Renderable(); 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/"+MonsterName+".png");
@ -94,78 +89,32 @@ void MonsterData::InitializeMonsterData(){
ANIMATION_DATA[state]=anim; ANIMATION_DATA[state]=anim;
}; };
for(int i=0;i<animations.size();i++){ if(!DATA["Monsters"][MonsterName].HasProperty("Animations"))ERR(std::format("WARNING! Could not find any animations to load for monster {}! Please check the Monsters.txt configuration file!",MonsterName));
std::string animationConfigName=""; if(DATA["Monsters"][MonsterName]["Animations"].GetKeys().size()<4)ERR(std::format("WARNING! Monster {} does not have at least 4 animations. The animations should be defined in this order: a standing, walking, attack, and death animation",MonsterName));
std::string imgName=""; for(size_t animationRow=0;auto&[animationName,size]:DATA["Monsters"][MonsterName]["Animations"]){
switch(i){
case 0:{
animationConfigName="Idle";
imgName="_IDLE";
}break;
case 1:{
animationConfigName="Jump";
imgName="_JUMP";
}break;
case 2:{
animationConfigName="Shoot";
imgName="_SPIT";
}break;
case 3:{
animationConfigName="Death";
imgName="_DIE";
}break;
}
Animate2D::Style style=Animate2D::Style::Repeat; Animate2D::Style style=Animate2D::Style::Repeat;
if(DATA["Monsters"][MonsterName][animationConfigName+"Animation"].GetString(2)=="Repeat"){ if(DATA["Monsters"][MonsterName]["Animations"][animationName].GetString(2)=="Repeat"){
style=Animate2D::Style::Repeat; style=Animate2D::Style::Repeat;
}else }else
if(DATA["Monsters"][MonsterName][animationConfigName+"Animation"].GetString(2)=="OneShot"){ if(DATA["Monsters"][MonsterName]["Animations"][animationName].GetString(2)=="OneShot"){
style=Animate2D::Style::OneShot; style=Animate2D::Style::OneShot;
}else }else
if(DATA["Monsters"][MonsterName][animationConfigName+"Animation"].GetString(2)=="PingPong"){ if(DATA["Monsters"][MonsterName]["Animations"][animationName].GetString(2)=="PingPong"){
style=Animate2D::Style::PingPong; style=Animate2D::Style::PingPong;
}else }else
if(DATA["Monsters"][MonsterName][animationConfigName+"Animation"].GetString(2)=="Reverse"){ if(DATA["Monsters"][MonsterName]["Animations"][animationName].GetString(2)=="Reverse"){
style=Animate2D::Style::Reverse; style=Animate2D::Style::Reverse;
}else{ }else{
ERR(std::format("WARNING! Invalid Animation Style specified: {}",int(style))); ERR(std::format("WARNING! Invalid Animation Style specified: {}",int(style)));
} }
int frameCount=DATA["Monsters"][MonsterName][animationConfigName+"Animation"].GetInt(0); int frameCount=DATA["Monsters"][MonsterName]["Animations"][animationName].GetInt(0);
vf2d frameSize=vf2d{float(DATA["Monsters"][MonsterName]["SheetFrameSize"].GetInt(0)),float(DATA["Monsters"][MonsterName]["SheetFrameSize"].GetInt(1))}; vf2d frameSize=vf2d{float(DATA["Monsters"][MonsterName]["SheetFrameSize"].GetInt(0)),float(DATA["Monsters"][MonsterName]["SheetFrameSize"].GetInt(1))};
CreateHorizontalAnimationSequence(*MonsterData::imgs[MonsterName],frameCount,frameSize,MonsterName+imgName,i,AnimationData{float(DATA["Monsters"][MonsterName][animationConfigName+"Animation"].GetReal(1)),style}); CreateHorizontalAnimationSequence(*MonsterData::imgs[MonsterName],frameCount,frameSize,std::format("{}_{}",MonsterName,animationName),animationRow,AnimationData{float(DATA["Monsters"][MonsterName]["Animations"][animationName].GetReal(1)),style});
}
//Add additional custom animations defined in the config.
int animationCounter=0;
int row=4;
while(DATA["Monsters"][MonsterName].HasProperty("ANIMATION["+std::to_string(animationCounter)+"]")){
animations.push_back(MonsterName+"ANIMATION["+std::to_string(animationCounter)+"]");
#pragma region Parse Animation Data
Animate2D::Style style;
if(DATA["Monsters"][MonsterName]["ANIMATION["+std::to_string(animationCounter)+"]"].GetString(2)=="Repeat"){
style=Animate2D::Style::Repeat;
}else
if(DATA["Monsters"][MonsterName]["ANIMATION["+std::to_string(animationCounter)+"]"].GetString(2)=="OneShot"){
style=Animate2D::Style::OneShot;
}else
if(DATA["Monsters"][MonsterName]["ANIMATION["+std::to_string(animationCounter)+"]"].GetString(2)=="PingPong"){
style=Animate2D::Style::PingPong;
}else
if(DATA["Monsters"][MonsterName]["ANIMATION["+std::to_string(animationCounter)+"]"].GetString(2)=="Reverse"){
style=Animate2D::Style::Reverse;
}else{
ERR(std::format("WARNING! Invalid Animation Style specified: {}",int(style)));
}
int frameCount=DATA["Monsters"][MonsterName]["ANIMATION["+std::to_string(animationCounter)+"]"].GetInt(0); animations.push_back(animationName);
vf2d frameSize=vf2d{float(DATA["Monsters"][MonsterName]["SheetFrameSize"].GetInt(0)),float(DATA["Monsters"][MonsterName]["SheetFrameSize"].GetInt(1))};
CreateHorizontalAnimationSequence(*MonsterData::imgs[MonsterName],frameCount,frameSize,MonsterName+"ANIMATION["+std::to_string(animationCounter)+"]",row,AnimationData{float(DATA["Monsters"][MonsterName]["ANIMATION["+std::to_string(animationCounter)+"]"].GetReal(1)),style});
#pragma endregion
row++; animationRow++;
animationCounter++;
} }
std::vector<MonsterDropData>drops; std::vector<MonsterDropData>drops;
@ -191,7 +140,6 @@ void MonsterData::InitializeMonsterData(){
DATA["Monsters"][MonsterName]["Health"].GetInt(), DATA["Monsters"][MonsterName]["Health"].GetInt(),
DATA["Monsters"][MonsterName]["Attack"].GetInt(), DATA["Monsters"][MonsterName]["Attack"].GetInt(),
DATA["Monsters"][MonsterName]["XP"].GetInt(), DATA["Monsters"][MonsterName]["XP"].GetInt(),
animations,
drops, drops,
float(DATA["Monsters"][MonsterName]["MoveSpd"].GetReal()), float(DATA["Monsters"][MonsterName]["MoveSpd"].GetReal()),
float(DATA["Monsters"][MonsterName]["Size"].GetReal())/100, float(DATA["Monsters"][MonsterName]["Size"].GetReal())/100,
@ -199,6 +147,19 @@ void MonsterData::InitializeMonsterData(){
DATA["Monsters"][MonsterName]["CollisionDmg"].GetInt() 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.hurtSound=hurtSound;
monster.deathSound=deathSound; monster.deathSound=deathSound;
monster.walkSound=walkSound; monster.walkSound=walkSound;
@ -260,78 +221,32 @@ void MonsterData::InitializeNPCData(){
ANIMATION_DATA[state]=anim; ANIMATION_DATA[state]=anim;
}; };
for(int i=0;i<animations.size();i++){ if(!DATA["NPCs"][NPCName].HasProperty("Animations"))ERR(std::format("WARNING! Could not find any animations to load for monster {}! Please check the Monsters.txt configuration file!",NPCName));
std::string animationConfigName=""; if(DATA["NPCs"][NPCName]["Animations"].GetKeys().size()<4)ERR(std::format("WARNING! Monster {} does not have at least 4 animations. The animations should be defined in this order: a standing, walking, attack, and death animation",NPCName));
std::string imgName=""; for(size_t animationRow=0;auto&[animationName,size]:DATA["NPCs"][NPCName]["Animations"]){
switch(i){
case 0:{
animationConfigName="Down";
imgName="_IDLE";
}break;
case 1:{
animationConfigName="Up";
imgName="_JUMP";
}break;
case 2:{
animationConfigName="Left";
imgName="_SPIT";
}break;
case 3:{
animationConfigName="Right";
imgName="_DIE";
}break;
}
Animate2D::Style style=Animate2D::Style::Repeat; Animate2D::Style style=Animate2D::Style::Repeat;
if(DATA["NPCs"][NPCName][animationConfigName+"Animation"].GetString(2)=="Repeat"){ if(DATA["NPCs"][NPCName]["Animations"][animationName].GetString(2)=="Repeat"){
style=Animate2D::Style::Repeat; style=Animate2D::Style::Repeat;
}else }else
if(DATA["NPCs"][NPCName][animationConfigName+"Animation"].GetString(2)=="OneShot"){ if(DATA["NPCs"][NPCName]["Animations"][animationName].GetString(2)=="OneShot"){
style=Animate2D::Style::OneShot; style=Animate2D::Style::OneShot;
}else }else
if(DATA["NPCs"][NPCName][animationConfigName+"Animation"].GetString(2)=="PingPong"){ if(DATA["NPCs"][NPCName]["Animations"][animationName].GetString(2)=="PingPong"){
style=Animate2D::Style::PingPong; style=Animate2D::Style::PingPong;
}else }else
if(DATA["NPCs"][NPCName][animationConfigName+"Animation"].GetString(2)=="Reverse"){ if(DATA["NPCs"][NPCName]["Animations"][animationName].GetString(2)=="Reverse"){
style=Animate2D::Style::Reverse; style=Animate2D::Style::Reverse;
}else{ }else{
ERR(std::format("WARNING! Invalid Animation Style specified: {}",int(style))); ERR(std::format("WARNING! Invalid Animation Style specified: {}",int(style)));
} }
int frameCount=DATA["NPCs"][NPCName][animationConfigName+"Animation"].GetInt(0); int frameCount=DATA["NPCs"][NPCName]["Animations"][animationName].GetInt(0);
vf2d frameSize=vf2d{float(DATA["NPCs"][NPCName]["SheetFrameSize"].GetInt(0)),float(DATA["NPCs"][NPCName]["SheetFrameSize"].GetInt(1))}; vf2d frameSize=vf2d{float(DATA["NPCs"][NPCName]["SheetFrameSize"].GetInt(0)),float(DATA["NPCs"][NPCName]["SheetFrameSize"].GetInt(1))};
CreateHorizontalAnimationSequence(*MonsterData::imgs[NPCName],frameCount,frameSize,NPCName+imgName,i,AnimationData{float(DATA["NPCs"][NPCName][animationConfigName+"Animation"].GetReal(1)),style}); CreateHorizontalAnimationSequence(*MonsterData::imgs[NPCName],frameCount,frameSize,std::format("{}_{}",NPCName,animationName),animationRow,AnimationData{float(DATA["NPCs"][NPCName]["Animations"][animationName].GetReal(1)),style});
}
//Add additional custom animations defined in the config.
int animationCounter=0;
int row=4;
while(DATA["NPCs"][NPCName].HasProperty("ANIMATION["+std::to_string(animationCounter)+"]")){
animations.push_back(NPCName+"ANIMATION["+std::to_string(animationCounter)+"]");
#pragma region Parse Animation Data
Animate2D::Style style;
if(DATA["NPCs"][NPCName]["ANIMATION["+std::to_string(animationCounter)+"]"].GetString(2)=="Repeat"){
style=Animate2D::Style::Repeat;
}else
if(DATA["NPCs"][NPCName]["ANIMATION["+std::to_string(animationCounter)+"]"].GetString(2)=="OneShot"){
style=Animate2D::Style::OneShot;
}else
if(DATA["NPCs"][NPCName]["ANIMATION["+std::to_string(animationCounter)+"]"].GetString(2)=="PingPong"){
style=Animate2D::Style::PingPong;
}else
if(DATA["NPCs"][NPCName]["ANIMATION["+std::to_string(animationCounter)+"]"].GetString(2)=="Reverse"){
style=Animate2D::Style::Reverse;
}else{
ERR(std::format("WARNING! Invalid Animation Style specified: {}",int(style)));
}
int frameCount=DATA["NPCs"][NPCName]["ANIMATION["+std::to_string(animationCounter)+"]"].GetInt(0); animations.push_back(animationName);
vf2d frameSize=vf2d{float(DATA["NPCs"][NPCName]["SheetFrameSize"].GetInt(0)),float(DATA["NPCs"][NPCName]["SheetFrameSize"].GetInt(1))};
CreateHorizontalAnimationSequence(*MonsterData::imgs[NPCName],frameCount,frameSize,NPCName+"ANIMATION["+std::to_string(animationCounter)+"]",row,AnimationData{float(DATA["NPCs"][NPCName]["ANIMATION["+std::to_string(animationCounter)+"]"].GetReal(1)),style});
#pragma endregion
row++; animationRow++;
animationCounter++;
} }
std::vector<MonsterDropData>drops; std::vector<MonsterDropData>drops;
@ -352,7 +267,20 @@ void MonsterData::InitializeNPCData(){
ERR("WARNING! Strategy for "<<NPCName<<" does not exist in strategy database!"); ERR("WARNING! Strategy for "<<NPCName<<" does not exist in strategy database!");
} }
MonsterData monster(NPCName,health,attack,xp,animations,drops,moveSpd,size/100,strategyName,collisionDmg); MonsterData monster(NPCName,health,attack,xp,drops,moveSpd,size/100,strategyName,collisionDmg);
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,NPCName));
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.hurtSound=hurtSound;
monster.deathSound=deathSound; monster.deathSound=deathSound;
@ -385,16 +313,16 @@ std::string MonsterData::GetDisplayName(){
} }
std::string MonsterData::GetIdleAnimation(){ std::string MonsterData::GetIdleAnimation(){
return animations[int(MonsterAnimation::IDLE)]; return idleAnimation;
} }
std::string MonsterData::GetJumpAnimation(){ std::string MonsterData::GetJumpAnimation(){
return animations[int(MonsterAnimation::JUMP)]; return jumpAnimation;
} }
std::string MonsterData::GetShootAnimation(){ std::string MonsterData::GetShootAnimation(){
return animations[int(MonsterAnimation::SHOOT)]; return shootAnimation;
} }
std::string MonsterData::GetDeathAnimation(){ std::string MonsterData::GetDeathAnimation(){
return animations[int(MonsterAnimation::DEATH)]; return deathAnimation;
} }
const std::vector<MonsterDropData>&MonsterData::GetDropData(){ const std::vector<MonsterDropData>&MonsterData::GetDropData(){
return dropData; return dropData;

@ -38,6 +38,7 @@ All rights reserved.
#pragma once #pragma once
#include "DEFINES.h" #include "DEFINES.h"
#include "Item.h" #include "Item.h"
#include <unordered_set>
INCLUDE_ITEM_DATA INCLUDE_ITEM_DATA
@ -64,20 +65,22 @@ private:
uint32_t xp; uint32_t xp;
float moveSpd;//1.0=100% float moveSpd;//1.0=100%
float size; float size;
std::vector<std::string> animations; 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; std::string strategy;
int collisionDmg; int collisionDmg;
std::string jumpAnimation="WARRIOR_IDLE_S";
std::string shootAnimation="WARRIOR_IDLE_S";
std::string deathAnimation="WARRIOR_IDLE_S";
EventName hurtSound=""; EventName hurtSound="";
EventName deathSound=""; EventName deathSound="";
EventName walkSound=""; EventName walkSound="";
std::vector<MonsterDropData> dropData; std::vector<MonsterDropData> dropData;
bool isNPC=false; 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<std::string>animations,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);
int GetHealth(); int GetHealth();
int GetAttack(); int GetAttack();
const uint32_t GetXP()const; const uint32_t GetXP()const;
@ -93,7 +96,7 @@ public:
const EventName&GetDeathSound(); const EventName&GetDeathSound();
const EventName&GetWalkSound(); const EventName&GetWalkSound();
const bool IsNPC()const; const bool IsNPC()const;
std::vector<std::string>GetAnimations(){ std::unordered_set<std::string>GetAnimations(){
return animations; return animations;
} }
const std::vector<MonsterDropData>&GetDropData(); const std::vector<MonsterDropData>&GetDropData();
@ -101,4 +104,6 @@ public:
static void InitializeMonsterData(); static void InitializeMonsterData();
static void InitializeNPCData(); static void InitializeNPCData();
static std::map<std::string,Renderable*>imgs; static std::map<std::string,Renderable*>imgs;
const bool HasFourWaySprites()const;
void SetUsesFourWaySprites();
}; };

@ -39,9 +39,13 @@ All rights reserved.
#define ConfigInt(param) _GetInt(m,param,strategy) #define ConfigInt(param) _GetInt(m,param,strategy)
#define ConfigFloat(param) _GetFloat(m,param,strategy) #define ConfigFloat(param) _GetFloat(m,param,strategy)
#define ConfigPixel(param) _GetPixel(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 ConfigString(param) _GetString(m,param,strategy)
#define ConfigVec(param) _GetVec(m,param,strategy) #define ConfigVec(param) _GetVec(m,param,strategy)
#define Config(param) _Get(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 ConfigIntArr(param,ind) _GetInt(m,param,strategy,ind)
#define ConfigFloatArr(param,ind) _GetFloat(m,param,strategy,ind) #define ConfigFloatArr(param,ind) _GetFloat(m,param,strategy,ind)
#define ConfigStringArr(param,ind) _GetString(m,param,strategy,ind) #define ConfigStringArr(param,ind) _GetString(m,param,strategy,ind)

@ -55,6 +55,7 @@ void Monster::InitializeStrategies(){
STRATEGY_DATA.insert("NPC",Monster::STRATEGY::NPC); STRATEGY_DATA.insert("NPC",Monster::STRATEGY::NPC);
STRATEGY_DATA.insert("Boar",Monster::STRATEGY::BOAR); STRATEGY_DATA.insert("Boar",Monster::STRATEGY::BOAR);
STRATEGY_DATA.insert("Goblin Dagger",Monster::STRATEGY::GOBLIN_DAGGER); STRATEGY_DATA.insert("Goblin Dagger",Monster::STRATEGY::GOBLIN_DAGGER);
STRATEGY_DATA.insert("Goblin Bow",Monster::STRATEGY::GOBLIN_BOW);
STRATEGY_DATA.SetInitialized(); 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){ void Monster::STRATEGY::RUN_STRATEGY(Monster&m,float fElapsedTime){
m.GetStrategy()(m,fElapsedTime,m.strategy); m.GetStrategy()(m,fElapsedTime,m.strategy);
} }

@ -71,7 +71,7 @@ bool Ranger::AutoAttack(){
vf2d extendedLine=pointTowardsCursor.upoint(1.1f); vf2d extendedLine=pointTowardsCursor.upoint(1.1f);
float angleToCursor=atan2(extendedLine.y-GetPos().y,extendedLine.x-GetPos().x); float angleToCursor=atan2(extendedLine.y-GetPos().y,extendedLine.x-GetPos().x);
attack_cooldown_timer=ARROW_ATTACK_COOLDOWN-GetAttackRecoveryRateReduction(); attack_cooldown_timer=ARROW_ATTACK_COOLDOWN-GetAttackRecoveryRateReduction();
BULLET_LIST.push_back(std::make_unique<Arrow>(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>(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); SetState(State::SHOOT_ARROW);
SetAnimationBasedOnTargetingDirection(angleToCursor); SetAnimationBasedOnTargetingDirection(angleToCursor);
SoundEffect::PlaySFX("Ranger.Auto Attack.Sound"_S,SoundEffect::CENTERED); SoundEffect::PlaySFX("Ranger.Auto Attack.Sound"_S,SoundEffect::CENTERED);

@ -229,7 +229,7 @@ void Monster::STRATEGY::SLIMEKING(Monster&m,float fElapsedTime,std::string strat
} }
if(m.GetState()==State::CASTING){ if(m.GetState()==State::CASTING){
m.PerformOtherAnimation(0); m.PerformAnimation("CHARGEUP");
if(m.F(A::CASTING_TIMER)==0){ if(m.F(A::CASTING_TIMER)==0){
m.SetState(State::NORMAL); m.SetState(State::NORMAL);
m.I(A::JUMP_COUNT)++; m.I(A::JUMP_COUNT)++;

@ -96,7 +96,7 @@ void Monster::STRATEGY::URSULE(Monster&m,float fElapsedTime,std::string strategy
case 1:{ //Run bear strategy in phase 1. case 1:{ //Run bear strategy in phase 1.
auto TransitionToPhase2=[&](){ auto TransitionToPhase2=[&](){
m.phase=2; m.phase=2;
m.PerformOtherAnimation(1); m.PerformAnimation("SIT");
m.AddBuff(BARRIER_DAMAGE_REDUCTION,INFINITE,ConfigFloat("Phase 2.Barrier Damage Reduction")/100.f); 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"); m.I(A::PHASE_REPEAT_COUNT)=ConfigInt("Phase 2.Wisp Pattern Spawn Count");
SoundEffect::PlaySFX("Ursule Phase Transition",SoundEffect::CENTERED); 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"); BEAR(m,fElapsedTime,"Bear");
}break; }break;
case 2:{ case 2:{
m.PerformOtherAnimation(2); m.PerformAnimation("GLARE");
m.F(A::SHOOT_TIMER)=std::max(0.f,m.F(A::SHOOT_TIMER)-fElapsedTime); m.F(A::SHOOT_TIMER)=std::max(0.f,m.F(A::SHOOT_TIMER)-fElapsedTime);
#pragma region Environment Color Change Handling #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){ if(m.GetRemainingHPPct()<=ConfigFloat("Phase 4.Change")/100.f){
auto TransitionToPhase5=[&](){ auto TransitionToPhase5=[&](){
m.phase=5; m.phase=5;
m.PerformOtherAnimation(1); m.PerformAnimation("SIT");
SoundEffect::PlaySFX("Ursule Phase Transition",SoundEffect::CENTERED); SoundEffect::PlaySFX("Ursule Phase Transition",SoundEffect::CENTERED);
m.F(A::ENVIRONMENT_TIMER)=ConfigFloat("Phase 4.Environment Fade-out Time"); m.F(A::ENVIRONMENT_TIMER)=ConfigFloat("Phase 4.Environment Fade-out Time");
m.I(A::ENVIRONMENT_PHASE)=0; 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){ if(m.F(A::CASTING_TIMER)==0.f){
m.F(A::CASTING_TIMER)=ConfigFloat("Phase 3.Charge Cast Time"); m.F(A::CASTING_TIMER)=ConfigFloat("Phase 3.Charge Cast Time");
m.UpdateFacingDirection(geom2d::line<float>(m.GetPos(),game->GetPlayer()->GetPos()).vector()); m.UpdateFacingDirection(geom2d::line<float>(m.GetPos(),game->GetPlayer()->GetPos()).vector());
m.PerformOtherAnimation(4); m.PerformAnimation("CHARGE");
m.B(A::COLLIDED_WITH_PLAYER)=false; 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.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::TARGET_TIMER)=ConfigFloat("Phase 3.Charge Max Run Time");
m.F(A::CHARGE_COOLDOWN)=ConfigFloat("Phase 3.Charge Attack Cooldown"); m.F(A::CHARGE_COOLDOWN)=ConfigFloat("Phase 3.Charge Attack Cooldown");
m.PerformOtherAnimation(3); m.PerformAnimation("CHARGING");
} }
break; break;
} }
@ -360,7 +360,7 @@ void Monster::STRATEGY::URSULE(Monster&m,float fElapsedTime,std::string strategy
} }
}break; }break;
case 5:{ //Final boss phase. 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); m.F(A::SHOOT_TIMER)=std::max(0.f,m.F(A::SHOOT_TIMER)-fElapsedTime);
#pragma region Environment Color Change Handling #pragma region Environment Color Change Handling

@ -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 9091 #define VERSION_BUILD 9115
#define stringify(a) stringify_(a) #define stringify(a) stringify_(a)
#define stringify_(a) #a #define stringify_(a) #a

Binary file not shown.

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<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="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="29">
<properties> <properties>
<property name="Backdrop" propertytype="Backdrop" value="mountain_day"/> <property name="Backdrop" propertytype="Backdrop" value="mountain_day"/>
<property name="Background Music" propertytype="BGM" value="foresty1_1"/> <property name="Background Music" propertytype="BGM" value="foresty1_1"/>
@ -1881,21 +1881,11 @@
<object id="15" name="Spawn Group 1" type="SpawnGroup" x="4439" y="7869" width="496" height="424"> <object id="15" name="Spawn Group 1" type="SpawnGroup" x="4439" y="7869" width="496" height="424">
<ellipse/> <ellipse/>
</object> </object>
<object id="16" template="../maps/Monsters/Goblin (Dagger).tx" x="4599" y="8065"> <object id="27" template="../maps/Monsters/Goblin (Bow).tx" x="4587" y="8091">
<properties> <properties>
<property name="spawner" type="object" value="15"/> <property name="spawner" type="object" value="15"/>
</properties> </properties>
</object> </object>
<object id="18" template="../maps/Monsters/Goblin (Dagger).tx" x="4711" y="8032"> <object id="28" name="Player Spawn" type="PlayerSpawnLocation" x="5112" y="8064" width="24" height="24"/>
<properties>
<property name="spawner" type="object" value="15"/>
</properties>
</object>
<object id="19" template="../maps/Monsters/Goblin (Dagger).tx" x="4646" y="8027">
<properties>
<property name="spawner" type="object" value="15"/>
</properties>
</object>
<object id="26" name="Player Spawn" type="PlayerSpawnLocation" x="265" y="1848" width="24" height="24"/>
</objectgroup> </objectgroup>
</map> </map>

@ -588,4 +588,23 @@ MonsterStrategy
Dagger Down Offset = -5,11 Dagger Down Offset = -5,11
Dagger Left Offset = -10,6 Dagger Left Offset = -10,6
} }
Goblin Bow
{
Attack Reload Time = 2.0s
# How long it takes to prepare the attack once an attack is queued.
Attack Windup Time = 1.0s
Arrow Spd = 250
Arrow Hitbox Radius = 8
# When the monster will attempt to run away from target.
Run Away Range = 500
# Chooses a random direction within the confines of this range, stays within it.
Random Direction Range = 500,700
# Does not move and shoots from anywhere in these ranges.
Stand Still and Shoot Range = 700,1000
# Anything outside the max "Stand Still and Shoot Range" will cause the monster to move towards the target instead.
}
} }

@ -18,25 +18,25 @@ Monsters
#Size of each animation frame #Size of each animation frame
SheetFrameSize = 24,24 SheetFrameSize = 24,24
Animations
{
# Frame Count, Frame Speed (s), Frame Cycling (Repeat,OneShot,PingPong,Reverse) # Frame Count, Frame Speed (s), Frame Cycling (Repeat,OneShot,PingPong,Reverse)
IdleAnimation = 10, 0.1, Repeat # Animations must be defined in the same order as they are in their sprite sheets
JumpAnimation = 10, 0.06, Repeat # The First Four animations must represent a standing, walking, attack, and death animation. Their names are up to the creator.
ShootAnimation = 10, 0.1, OneShot IDLE = 10, 0.1, Repeat
DeathAnimation = 10, 0.1, OneShot JUMP = 10, 0.06, Repeat
SHOOT = 10, 0.1, OneShot
# Drop Item Name, Drop Percentage(0-100%), Drop Min Quantity, Drop Max Quantity DEATH = 10, 0.1, OneShot
DROP[0] = Green Slime Remains,30%,1,1 }
DROP[1] = Minor Health Potion,5%,1,1
DROP[2] = Berries,3%,1,1
Hurt Sound = Monster Hurt Hurt Sound = Monster Hurt
Death Sound = Slime Dead Death Sound = Slime Dead
Walk Sound = Slime Walk Walk Sound = Slime Walk
#Additional custom animations go down below. Start with ANIMATION[0] Order is: # Drop Item Name, Drop Percentage(0-100%), Drop Min Quantity, Drop Max Quantity
# File name, Frame Count, Frame Speed (s), Frame Cycling (Repeat,OneShot,PingPong,Reverse) DROP[0] = Green Slime Remains,30%,1,1
# NOTE: ANIMATION[0] will always be row 5 of an animation sheet, all numbers that follow are each below each other. DROP[1] = Minor Health Potion,5%,1,1
#ANIMATION[0] = 6, 0.1, Repeat DROP[2] = Berries,3%,1,1
} }
Blue Slime Blue Slime
{ {
@ -55,11 +55,16 @@ Monsters
#Size of each animation frame #Size of each animation frame
SheetFrameSize = 24,24 SheetFrameSize = 24,24
Animations
{
# Frame Count, Frame Speed (s), Frame Cycling (Repeat,OneShot,PingPong,Reverse) # Frame Count, Frame Speed (s), Frame Cycling (Repeat,OneShot,PingPong,Reverse)
IdleAnimation = 10, 0.1, Repeat # Animations must be defined in the same order as they are in their sprite sheets
JumpAnimation = 10, 0.06, Repeat # The First Four animations must represent a standing, walking, attack, and death animation. Their names are up to the creator.
ShootAnimation = 10, 0.1, Repeat IDLE = 10, 0.1, Repeat
DeathAnimation = 10, 0.1, OneShot JUMP = 10, 0.06, Repeat
SHOOT = 10, 0.1, OneShot
DEATH = 10, 0.1, OneShot
}
Hurt Sound = Monster Hurt Hurt Sound = Monster Hurt
Death Sound = Slime Dead Death Sound = Slime Dead
@ -69,11 +74,6 @@ Monsters
DROP[0] = Blue Slime Remains,30%,1,1 DROP[0] = Blue Slime Remains,30%,1,1
DROP[1] = Minor Mana Potion,5%,1,1 DROP[1] = Minor Mana Potion,5%,1,1
DROP[2] = Berries,5%,1,1 DROP[2] = Berries,5%,1,1
#Additional custom animations go down below. Start with ANIMATION[0] Order is:
# File name, Frame Count, Frame Speed (s), Frame Cycling (Repeat,OneShot,PingPong,Reverse)
# NOTE: ANIMATION[0] will always be row 5 of an animation sheet, all numbers that follow are each below each other.
#ANIMATION[0] = 6, 0.1, Repeat
} }
Red Slime Red Slime
{ {
@ -92,11 +92,16 @@ Monsters
#Size of each animation frame #Size of each animation frame
SheetFrameSize = 24,24 SheetFrameSize = 24,24
Animations
{
# Frame Count, Frame Speed (s), Frame Cycling (Repeat,OneShot,PingPong,Reverse) # Frame Count, Frame Speed (s), Frame Cycling (Repeat,OneShot,PingPong,Reverse)
IdleAnimation = 10, 0.1, Repeat # Animations must be defined in the same order as they are in their sprite sheets
JumpAnimation = 10, 0.06, Repeat # The First Four animations must represent a standing, walking, attack, and death animation. Their names are up to the creator.
ShootAnimation = 10, 0.1, OneShot IDLE = 10, 0.1, Repeat
DeathAnimation = 10, 0.1, OneShot JUMP = 10, 0.06, Repeat
SHOOT = 10, 0.1, OneShot
DEATH = 10, 0.1, OneShot
}
Hurt Sound = Monster Hurt Hurt Sound = Monster Hurt
Death Sound = Slime Dead Death Sound = Slime Dead
@ -106,11 +111,6 @@ Monsters
DROP[0] = Red Slime Remains,30%,1,1 DROP[0] = Red Slime Remains,30%,1,1
DROP[1] = Minor Health Potion,5%,1,1 DROP[1] = Minor Health Potion,5%,1,1
DROP[2] = Berries,5%,1,1 DROP[2] = Berries,5%,1,1
#Additional custom animations go down below. Start with ANIMATION[0] Order is:
# File name, Frame Count, Frame Speed (s), Frame Cycling (Repeat,OneShot,PingPong,Reverse)
# NOTE: ANIMATION[0] will always be row 5 of an animation sheet, all numbers that follow are each below each other.
#ANIMATION[0] = 6, 0.1, Repeat
} }
Yellow Slime Yellow Slime
{ {
@ -129,15 +129,16 @@ Monsters
#Size of each animation frame #Size of each animation frame
SheetFrameSize = 24,24 SheetFrameSize = 24,24
Animations
{
# Frame Count, Frame Speed (s), Frame Cycling (Repeat,OneShot,PingPong,Reverse) # Frame Count, Frame Speed (s), Frame Cycling (Repeat,OneShot,PingPong,Reverse)
IdleAnimation = 10, 0.1, Repeat # Animations must be defined in the same order as they are in their sprite sheets
JumpAnimation = 10, 0.06, Repeat # The First Four animations must represent a standing, walking, attack, and death animation. Their names are up to the creator.
ShootAnimation = 10, 0.1, OneShot IDLE = 10, 0.1, Repeat
DeathAnimation = 10, 0.1, OneShot JUMP = 10, 0.06, Repeat
SHOOT = 10, 0.1, OneShot
Hurt Sound = Monster Hurt DEATH = 10, 0.1, OneShot
Death Sound = Slime Dead }
Walk Sound = Slime Walk
# Jump property overrides # Jump property overrides
JumpTimer = 10.0 JumpTimer = 10.0
@ -148,15 +149,14 @@ Monsters
# How much time remaining for the jump target being locked into place. # How much time remaining for the jump target being locked into place.
JumpLockinTargetTime = 0.2 JumpLockinTargetTime = 0.2
Hurt Sound = Monster Hurt
Death Sound = Slime Dead
Walk Sound = Slime Walk
# Drop Item Name, Drop Percentage(0-100%), Drop Min Quantity, Drop Max Quantity # Drop Item Name, Drop Percentage(0-100%), Drop Min Quantity, Drop Max Quantity
DROP[0] = Yellow Slime Remains,30%,1,1 DROP[0] = Yellow Slime Remains,30%,1,1
DROP[1] = Minor Recovery Potion,5%,1,1 DROP[1] = Minor Recovery Potion,5%,1,1
DROP[2] = Berries,7%,1,2 DROP[2] = Berries,7%,1,2
#Additional custom animations go down below. Start with ANIMATION[0] Order is:
# File name, Frame Count, Frame Speed (s), Frame Cycling (Repeat,OneShot,PingPong,Reverse)
# NOTE: ANIMATION[0] will always be row 5 of an animation sheet, all numbers that follow are each below each other.
#ANIMATION[0] = 6, 0.1, Repeat
} }
Flower Turret Flower Turret
{ {
@ -175,11 +175,16 @@ Monsters
#Size of each animation frame #Size of each animation frame
SheetFrameSize = 24,24 SheetFrameSize = 24,24
Animations
{
# Frame Count, Frame Speed (s), Frame Cycling (Repeat,OneShot,PingPong,Reverse) # Frame Count, Frame Speed (s), Frame Cycling (Repeat,OneShot,PingPong,Reverse)
IdleAnimation = 7, 0.1, PingPong # Animations must be defined in the same order as they are in their sprite sheets
JumpAnimation = 1, 0.1, OneShot # The First Four animations must represent a standing, walking, attack, and death animation. Their names are up to the creator.
ShootAnimation = 5, 0.1, OneShot IDLE = 7, 0.1, PingPong
DeathAnimation = 5, 0.2, OneShot JUMP = 1, 0.1, OneShot
SHOOT = 5, 0.1, OneShot
DEATH = 5, 0.2, OneShot
}
Hurt Sound = Monster Hurt Hurt Sound = Monster Hurt
Death Sound = Slime Dead Death Sound = Slime Dead
@ -189,11 +194,6 @@ Monsters
DROP[0] = Flower Petals,30%,1,1 DROP[0] = Flower Petals,30%,1,1
DROP[1] = Berries,5%,1,1 DROP[1] = Berries,5%,1,1
DROP[2] = Bandages,10%,1,1 DROP[2] = Bandages,10%,1,1
#Additional custom animations go down below. Start with ANIMATION[0] Order is:
# File name, Frame Count, Frame Speed (s), Frame Cycling (Repeat,OneShot,PingPong,Reverse)
# NOTE: ANIMATION[0] will always be row 5 of an animation sheet, all numbers that follow are each below each other.
#ANIMATION[0] = 6, 0.1, Repeat
} }
Slime King Slime King
{ {
@ -213,11 +213,18 @@ Monsters
#Size of each animation frame #Size of each animation frame
SheetFrameSize = 24,24 SheetFrameSize = 24,24
Animations
{
# Frame Count, Frame Speed (s), Frame Cycling (Repeat,OneShot,PingPong,Reverse) # Frame Count, Frame Speed (s), Frame Cycling (Repeat,OneShot,PingPong,Reverse)
IdleAnimation = 10, 0.1, Repeat # Animations must be defined in the same order as they are in their sprite sheets
JumpAnimation = 10, 0.06, Repeat # The First Four animations must represent a standing, walking, attack, and death animation. Their names are up to the creator.
ShootAnimation = 10, 0.1, OneShot IDLE = 10, 0.1, Repeat
DeathAnimation = 10, 0.1, OneShot JUMP = 10, 0.06, Repeat
SHOOT = 10, 0.1, OneShot
DEATH = 10, 0.1, OneShot
CHARGEUP = 10, 0.04, Repeat
}
Hurt Sound = Monster Hurt Hurt Sound = Monster Hurt
Death Sound = Slime Dead Death Sound = Slime Dead
@ -225,11 +232,6 @@ Monsters
# Drop Item Name, Drop Percentage(0-100%), Drop Min Quantity, Drop Max Quantity # Drop Item Name, Drop Percentage(0-100%), Drop Min Quantity, Drop Max Quantity
DROP[0] = Ring of the Slime King,100%,1,1 DROP[0] = Ring of the Slime King,100%,1,1
#Additional custom animations go down below. Start with ANIMATION[0] Order is:
# File name, Frame Count, Frame Speed (s), Frame Cycling (Repeat,OneShot,PingPong,Reverse)
# NOTE: ANIMATION[0] will always be row 5 of an animation sheet, all numbers that follow are each below each other.
ANIMATION[0] = 10, 0.04, Repeat
} }
Windhound Windhound
{ {
@ -248,11 +250,16 @@ Monsters
#Size of each animation frame #Size of each animation frame
SheetFrameSize = 24,24 SheetFrameSize = 24,24
Animations
{
# Frame Count, Frame Speed (s), Frame Cycling (Repeat,OneShot,PingPong,Reverse) # Frame Count, Frame Speed (s), Frame Cycling (Repeat,OneShot,PingPong,Reverse)
IdleAnimation = 3, 0.2, PingPong # Animations must be defined in the same order as they are in their sprite sheets
JumpAnimation = 4, 0.06, PingPong # The First Four animations must represent a standing, walking, attack, and death animation. Their names are up to the creator.
ShootAnimation = 10, 0.1, OneShot IDLE = 3, 0.2, PingPong
DeathAnimation = 4, 0.1, OneShot JUMP = 4, 0.06, PingPong
SHOOT = 10, 0.1, OneShot
DEATH = 4, 0.1, OneShot
}
# Drop Item Name, Drop Percentage(0-100%), Drop Min Quantity, Drop Max Quantity # Drop Item Name, Drop Percentage(0-100%), Drop Min Quantity, Drop Max Quantity
DROP[0] = Windhound Skin,30%,1,1 DROP[0] = Windhound Skin,30%,1,1
@ -260,11 +267,6 @@ Monsters
Hurt Sound = Monster Hurt Hurt Sound = Monster Hurt
Death Sound = Slime Dead Death Sound = Slime Dead
Walk Sound = Slime Walk Walk Sound = Slime Walk
#Additional custom animations go down below. Start with ANIMATION[0] Order is:
# File name, Frame Count, Frame Speed (s), Frame Cycling (Repeat,OneShot,PingPong,Reverse)
# NOTE: ANIMATION[0] will always be row 5 of an animation sheet, all numbers that follow are each below each other.
#ANIMATION[0] = 6, 0.1, Repeat
} }
Frog Frog
{ {
@ -283,23 +285,23 @@ Monsters
#Size of each animation frame #Size of each animation frame
SheetFrameSize = 24,24 SheetFrameSize = 24,24
Animations
{
# Frame Count, Frame Speed (s), Frame Cycling (Repeat,OneShot,PingPong,Reverse) # Frame Count, Frame Speed (s), Frame Cycling (Repeat,OneShot,PingPong,Reverse)
IdleAnimation = 4, 0.13, PingPong # Animations must be defined in the same order as they are in their sprite sheets
JumpAnimation = 10, 0.06, Repeat # The First Four animations must represent a standing, walking, attack, and death animation. Their names are up to the creator.
ShootAnimation = 6, 0.15, PingPong IDLE = 4, 0.13, PingPong
DeathAnimation = 6, 0.1, OneShot JUMP = 10, 0.06, Repeat
SHOOT = 6, 0.15, PingPong
# Drop Item Name, Drop Percentage(0-100%), Drop Min Quantity, Drop Max Quantity DEATH = 6, 0.1, OneShot
DROP[0] = Frog Skin,50%,1,1 }
Hurt Sound = Monster Hurt Hurt Sound = Monster Hurt
Death Sound = Slime Dead Death Sound = Slime Dead
Walk Sound = Slime Walk Walk Sound = Slime Walk
#Additional custom animations go down below. Start with ANIMATION[0] Order is: # Drop Item Name, Drop Percentage(0-100%), Drop Min Quantity, Drop Max Quantity
# File name, Frame Count, Frame Speed (s), Frame Cycling (Repeat,OneShot,PingPong,Reverse) DROP[0] = Frog Skin,50%,1,1
# NOTE: ANIMATION[0] will always be row 5 of an animation sheet, all numbers that follow are each below each other.
#ANIMATION[0] = 6, 0.1, Repeat
} }
Bear Bear
{ {
@ -318,24 +320,25 @@ Monsters
#Size of each animation frame #Size of each animation frame
SheetFrameSize = 24,24 SheetFrameSize = 24,24
Animations
{
# Frame Count, Frame Speed (s), Frame Cycling (Repeat,OneShot,PingPong,Reverse) # Frame Count, Frame Speed (s), Frame Cycling (Repeat,OneShot,PingPong,Reverse)
IdleAnimation = 4, 0.3, Repeat # Animations must be defined in the same order as they are in their sprite sheets
JumpAnimation = 5, 0.2, Repeat # The First Four animations must represent a standing, walking, attack, and death animation. Their names are up to the creator.
ShootAnimation = 3, 0.2, OneShot IDLE = 4, 0.3, Repeat
DeathAnimation = 3, 0.15, OneShot JUMP = 5, 0.2, Repeat
SHOOT = 3, 0.2, OneShot
# Drop Item Name, Drop Percentage(0-100%), Drop Min Quantity, Drop Max Quantity DEATH = 3, 0.15, OneShot
DROP[0] = Bear Blood,10%,1,2 SLAM = 4, 0.2, OneShot
DROP[1] = Bear Claw,30%,1,1 }
Hurt Sound = Monster Hurt Hurt Sound = Monster Hurt
Death Sound = Slime Dead Death Sound = Slime Dead
Walk Sound = Slime Walk Walk Sound = Slime Walk
#Additional custom animations go down below. Start with ANIMATION[0] Order is: # Drop Item Name, Drop Percentage(0-100%), Drop Min Quantity, Drop Max Quantity
# File name, Frame Count, Frame Speed (s), Frame Cycling (Repeat,OneShot,PingPong,Reverse) DROP[0] = Bear Blood,10%,1,2
# NOTE: ANIMATION[0] will always be row 5 of an animation sheet, all numbers that follow are each below each other. DROP[1] = Bear Claw,30%,1,1
ANIMATION[0] = 4, 0.2, OneShot
} }
Ursule, Mother of Bears Ursule, Mother of Bears
{ {
@ -378,11 +381,21 @@ Monsters
#Size of each animation frame #Size of each animation frame
SheetFrameSize = 26,26 SheetFrameSize = 26,26
Animations
{
# Frame Count, Frame Speed (s), Frame Cycling (Repeat,OneShot,PingPong,Reverse) # Frame Count, Frame Speed (s), Frame Cycling (Repeat,OneShot,PingPong,Reverse)
IdleAnimation = 4, 0.3, Repeat # Animations must be defined in the same order as they are in their sprite sheets
JumpAnimation = 5, 0.2, Repeat # The First Four animations must represent a standing, walking, attack, and death animation. Their names are up to the creator.
ShootAnimation = 3, 0.2, OneShot IDLE = 4, 0.3, Repeat
DeathAnimation = 3, 0.15, OneShot JUMP = 5, 0.2, Repeat
SHOOT = 3, 0.2, OneShot
DEATH = 3, 0.15, OneShot
SLAM = 4, 0.1, OneShot
SIT = 6, 0.15, OneShot
GLARE = 2, 0.2, Reverse
CHARGING = 5, 0.1, Repeat
CHARGE = 4, 0.3, Repeat
}
# Drop Item Name, Drop Percentage(0-100%), Drop Min Quantity, Drop Max Quantity # Drop Item Name, Drop Percentage(0-100%), Drop Min Quantity, Drop Max Quantity
DROP[0] = Ring of the Bear,100%,1,1 DROP[0] = Ring of the Bear,100%,1,1
@ -392,15 +405,6 @@ Monsters
Hurt Sound = Monster Hurt Hurt Sound = Monster Hurt
Death Sound = Ursule Dead Death Sound = Ursule Dead
Walk Sound = Slime Walk Walk Sound = Slime Walk
#Additional custom animations go down below. Start with ANIMATION[0] Order is:
# File name, Frame Count, Frame Speed (s), Frame Cycling (Repeat,OneShot,PingPong,Reverse)
# NOTE: ANIMATION[0] will always be row 5 of an animation sheet, all numbers that follow are each below each other.
ANIMATION[0] = 4, 0.1, OneShot
ANIMATION[1] = 6, 0.15, OneShot
ANIMATION[2] = 2, 0.2, Reverse
ANIMATION[3] = 5, 0.1, Repeat
ANIMATION[4] = 4, 0.3, Repeat
} }
Bun Bun
{ {
@ -419,11 +423,16 @@ Monsters
#Size of each animation frame #Size of each animation frame
SheetFrameSize = 24,24 SheetFrameSize = 24,24
Animations
{
# Frame Count, Frame Speed (s), Frame Cycling (Repeat,OneShot,PingPong,Reverse) # Frame Count, Frame Speed (s), Frame Cycling (Repeat,OneShot,PingPong,Reverse)
IdleAnimation = 10, 0.1, Repeat # Animations must be defined in the same order as they are in their sprite sheets
JumpAnimation = 10, 0.06, Repeat # The First Four animations must represent a standing, walking, attack, and death animation. Their names are up to the creator.
ShootAnimation = 10, 0.05, Repeat IDLE = 10, 0.1, Repeat
DeathAnimation = 10, 0.1, OneShot JUMP = 10, 0.06, Repeat
SHOOT = 10, 0.1, OneShot
DEATH = 10, 0.1, OneShot
}
Range = 200 Range = 200
CloseInRange = 600 CloseInRange = 600
@ -440,11 +449,6 @@ Monsters
# Drop Item Name, Drop Percentage(0-100%), Drop Min Quantity, Drop Max Quantity # Drop Item Name, Drop Percentage(0-100%), Drop Min Quantity, Drop Max Quantity
DROP[0] = Slimy Bun,100%,1,1 DROP[0] = Slimy Bun,100%,1,1
#Additional custom animations go down below. Start with ANIMATION[0] Order is:
# File name, Frame Count, Frame Speed (s), Frame Cycling (Repeat,OneShot,PingPong,Reverse)
# NOTE: ANIMATION[0] will always be row 5 of an animation sheet, all numbers that follow are each below each other.
#ANIMATION[0] = 6, 0.1, Repeat
} }
Boar Boar
{ {
@ -463,11 +467,17 @@ Monsters
#Size of each animation frame #Size of each animation frame
SheetFrameSize = 24,24 SheetFrameSize = 24,24
Animations
{
# Frame Count, Frame Speed (s), Frame Cycling (Repeat,OneShot,PingPong,Reverse) # Frame Count, Frame Speed (s), Frame Cycling (Repeat,OneShot,PingPong,Reverse)
IdleAnimation = 1, 0.3, Repeat # Animations must be defined in the same order as they are in their sprite sheets
JumpAnimation = 1, 0.2, Repeat # The First Four animations must represent a standing, walking, attack, and death animation. Their names are up to the creator.
ShootAnimation = 1, 0.2, OneShot IDLE = 1, 0.3, Repeat
DeathAnimation = 1, 0.15, OneShot JUMP = 1, 0.2, Repeat
SHOOT = 1, 0.2, OneShot
DEATH = 1, 0.15, OneShot
SCRATCH = 4, 0.2, OneShot
}
# Drop Item Name, Drop Percentage(0-100%), Drop Min Quantity, Drop Max Quantity # Drop Item Name, Drop Percentage(0-100%), Drop Min Quantity, Drop Max Quantity
# DROP[0] = Ring of the Bear,100%,1,1 # DROP[0] = Ring of the Bear,100%,1,1
@ -475,12 +485,6 @@ Monsters
Hurt Sound = Monster Hurt Hurt Sound = Monster Hurt
Death Sound = Slime Dead Death Sound = Slime Dead
Walk Sound = Slime Walk Walk Sound = Slime Walk
#Additional custom animations go down below. Start with ANIMATION[0] Order is:
# File name, Frame Count, Frame Speed (s), Frame Cycling (Repeat,OneShot,PingPong,Reverse)
# NOTE: ANIMATION[0] will always be row 5 of an animation sheet, all numbers that follow are each below each other.
# Scratch animation.
ANIMATION[0] = 4, 0.2, OneShot
} }
Goblin (Dagger) Goblin (Dagger)
{ {
@ -502,11 +506,20 @@ Monsters
#Size of each animation frame #Size of each animation frame
SheetFrameSize = 24,24 SheetFrameSize = 24,24
Animations
{
# Frame Count, Frame Speed (s), Frame Cycling (Repeat,OneShot,PingPong,Reverse) # Frame Count, Frame Speed (s), Frame Cycling (Repeat,OneShot,PingPong,Reverse)
IdleAnimation = 1, 0.3, Repeat # Animations must be defined in the same order as they are in their sprite sheets
JumpAnimation = 1, 0.2, Repeat # The First Four animations must represent a standing, walking, attack, and death animation. Their names are up to the creator.
ShootAnimation = 1, 0.2, OneShot IDLE = 1, 0.3, Repeat
DeathAnimation = 1, 0.15, OneShot JUMP = 1, 0.2, Repeat
SHOOT = 1, 0.2, 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
}
# Drop Item Name, Drop Percentage(0-100%), Drop Min Quantity, Drop Max Quantity # Drop Item Name, Drop Percentage(0-100%), Drop Min Quantity, Drop Max Quantity
# DROP[0] = Ring of the Bear,100%,1,1 # DROP[0] = Ring of the Bear,100%,1,1
@ -514,50 +527,6 @@ Monsters
Hurt Sound = Monster Hurt Hurt Sound = Monster Hurt
Death Sound = Slime Dead Death Sound = Slime Dead
Walk Sound = Slime Walk Walk Sound = Slime Walk
#Additional custom animations go down below. Start with ANIMATION[0] Order is:
# File name, Frame Count, Frame Speed (s), Frame Cycling (Repeat,OneShot,PingPong,Reverse)
# NOTE: ANIMATION[0] will always be row 5 of an animation sheet, all numbers that follow are each below each other.
# Up Stab Windup
ANIMATION[0] = 1, 0.1, OneShot
# Right Stab Windup
ANIMATION[1] = 1, 0.1, OneShot
# Down Stab Windup
ANIMATION[2] = 1, 0.1, OneShot
# Left Stab Windup
ANIMATION[3] = 1, 0.1, OneShot
# Up Stab
ANIMATION[4] = 2, 0.1, PingPong
# Right Stab
ANIMATION[5] = 2, 0.1, PingPong
# Down Stab
ANIMATION[6] = 2, 0.1, PingPong
# Left Stab
ANIMATION[7] = 2, 0.1, PingPong
# Up Slash Windup
ANIMATION[8] = 1, 0.1, OneShot
# Right Slash Windup
ANIMATION[9] = 1, 0.1, OneShot
# Down Slash Windup
ANIMATION[10] = 1, 0.1, OneShot
# Left Slash Windup
ANIMATION[11] = 1, 0.1, OneShot
# Up Slash
ANIMATION[12] = 2, 0.1, PingPong
# Right Slash
ANIMATION[13] = 2, 0.1, PingPong
# Down Slash
ANIMATION[14] = 2, 0.1, PingPong
# Left Slash
ANIMATION[15] = 2, 0.1, PingPong
# Up Idle
ANIMATION[16] = 1, 0.1, PingPong
# Right Idle
ANIMATION[17] = 1, 0.1, PingPong
# Down Idle
ANIMATION[18] = 1, 0.1, PingPong
# Left Idle
ANIMATION[19] = 1, 0.1, PingPong
} }
Goblin (Bow) Goblin (Bow)
{ {
@ -571,28 +540,33 @@ Monsters
XP = 17 XP = 17
Strategy = Run Towards Strategy = Goblin Bow
#Size of each animation frame #Size of each animation frame
SheetFrameSize = 24,24 SheetFrameSize = 24,24
# Frame Count, Frame Speed (s), Frame Cycling (Repeat,OneShot,PingPong,Reverse)
IdleAnimation = 1, 0.3, Repeat
JumpAnimation = 1, 0.2, Repeat
ShootAnimation = 1, 0.2, OneShot
DeathAnimation = 1, 0.15, OneShot
# Drop Item Name, Drop Percentage(0-100%), Drop Min Quantity, Drop Max Quantity Animations
# DROP[0] = Ring of the Bear,100%,1,1 {
# 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
}
Hurt Sound = Monster Hurt Hurt Sound = Monster Hurt
Death Sound = Slime Dead Death Sound = Slime Dead
Walk Sound = Slime Walk Walk Sound = Slime Walk
#Additional custom animations go down below. Start with ANIMATION[0] Order is: # Drop Item Name, Drop Percentage(0-100%), Drop Min Quantity, Drop Max Quantity
# File name, Frame Count, Frame Speed (s), Frame Cycling (Repeat,OneShot,PingPong,Reverse) # DROP[0] = Ring of the Bear,100%,1,1
# NOTE: ANIMATION[0] will always be row 5 of an animation sheet, all numbers that follow are each below each other.
# ANIMATION[0] = 4, 0.1, OneShot
} }
Goblin (Bombs) Goblin (Bombs)
{ {
@ -611,23 +585,23 @@ Monsters
#Size of each animation frame #Size of each animation frame
SheetFrameSize = 24,24 SheetFrameSize = 24,24
Animations
{
# Frame Count, Frame Speed (s), Frame Cycling (Repeat,OneShot,PingPong,Reverse) # Frame Count, Frame Speed (s), Frame Cycling (Repeat,OneShot,PingPong,Reverse)
IdleAnimation = 1, 0.3, Repeat # Animations must be defined in the same order as they are in their sprite sheets
JumpAnimation = 1, 0.2, Repeat # The First Four animations must represent a standing, walking, attack, and death animation. Their names are up to the creator.
ShootAnimation = 1, 0.2, OneShot IDLE = 1, 0.3, Repeat
DeathAnimation = 1, 0.15, OneShot JUMP = 1, 0.2, Repeat
SHOOT = 1, 0.2, OneShot
# Drop Item Name, Drop Percentage(0-100%), Drop Min Quantity, Drop Max Quantity DEATH = 1, 0.15, OneShot
# DROP[0] = Ring of the Bear,100%,1,1 }
Hurt Sound = Monster Hurt Hurt Sound = Monster Hurt
Death Sound = Slime Dead Death Sound = Slime Dead
Walk Sound = Slime Walk Walk Sound = Slime Walk
#Additional custom animations go down below. Start with ANIMATION[0] Order is: # Drop Item Name, Drop Percentage(0-100%), Drop Min Quantity, Drop Max Quantity
# File name, Frame Count, Frame Speed (s), Frame Cycling (Repeat,OneShot,PingPong,Reverse) # DROP[0] = Ring of the Bear,100%,1,1
# NOTE: ANIMATION[0] will always be row 5 of an animation sheet, all numbers that follow are each below each other.
# ANIMATION[0] = 4, 0.1, OneShot
} }
Goblin Boar Rider Goblin Boar Rider
{ {
@ -646,23 +620,23 @@ Monsters
#Size of each animation frame #Size of each animation frame
SheetFrameSize = 24,24 SheetFrameSize = 24,24
Animations
{
# Frame Count, Frame Speed (s), Frame Cycling (Repeat,OneShot,PingPong,Reverse) # Frame Count, Frame Speed (s), Frame Cycling (Repeat,OneShot,PingPong,Reverse)
IdleAnimation = 1, 0.3, Repeat # Animations must be defined in the same order as they are in their sprite sheets
JumpAnimation = 1, 0.2, Repeat # The First Four animations must represent a standing, walking, attack, and death animation. Their names are up to the creator.
ShootAnimation = 1, 0.2, OneShot IDLE = 1, 0.3, Repeat
DeathAnimation = 1, 0.15, OneShot JUMP = 1, 0.2, Repeat
SHOOT = 1, 0.2, OneShot
# Drop Item Name, Drop Percentage(0-100%), Drop Min Quantity, Drop Max Quantity DEATH = 1, 0.15, OneShot
# DROP[0] = Ring of the Bear,100%,1,1 }
Hurt Sound = Monster Hurt Hurt Sound = Monster Hurt
Death Sound = Slime Dead Death Sound = Slime Dead
Walk Sound = Slime Walk Walk Sound = Slime Walk
#Additional custom animations go down below. Start with ANIMATION[0] Order is: # Drop Item Name, Drop Percentage(0-100%), Drop Min Quantity, Drop Max Quantity
# File name, Frame Count, Frame Speed (s), Frame Cycling (Repeat,OneShot,PingPong,Reverse) # DROP[0] = Ring of the Bear,100%,1,1
# NOTE: ANIMATION[0] will always be row 5 of an animation sheet, all numbers that follow are each below each other.
# ANIMATION[0] = 4, 0.1, OneShot
} }
Hawk Hawk
{ {
@ -681,23 +655,23 @@ Monsters
#Size of each animation frame #Size of each animation frame
SheetFrameSize = 24,24 SheetFrameSize = 24,24
Animations
{
# Frame Count, Frame Speed (s), Frame Cycling (Repeat,OneShot,PingPong,Reverse) # Frame Count, Frame Speed (s), Frame Cycling (Repeat,OneShot,PingPong,Reverse)
IdleAnimation = 1, 0.3, Repeat # Animations must be defined in the same order as they are in their sprite sheets
JumpAnimation = 1, 0.2, Repeat # The First Four animations must represent a standing, walking, attack, and death animation. Their names are up to the creator.
ShootAnimation = 1, 0.2, OneShot IDLE = 1, 0.3, Repeat
DeathAnimation = 1, 0.15, OneShot JUMP = 1, 0.2, Repeat
SHOOT = 1, 0.2, OneShot
# Drop Item Name, Drop Percentage(0-100%), Drop Min Quantity, Drop Max Quantity DEATH = 1, 0.15, OneShot
# DROP[0] = Ring of the Bear,100%,1,1 }
Hurt Sound = Monster Hurt Hurt Sound = Monster Hurt
Death Sound = Slime Dead Death Sound = Slime Dead
Walk Sound = Slime Walk Walk Sound = Slime Walk
#Additional custom animations go down below. Start with ANIMATION[0] Order is: # Drop Item Name, Drop Percentage(0-100%), Drop Min Quantity, Drop Max Quantity
# File name, Frame Count, Frame Speed (s), Frame Cycling (Repeat,OneShot,PingPong,Reverse) # DROP[0] = Ring of the Bear,100%,1,1
# NOTE: ANIMATION[0] will always be row 5 of an animation sheet, all numbers that follow are each below each other.
# ANIMATION[0] = 4, 0.1, OneShot
} }
Stone Elemental Stone Elemental
{ {
@ -716,22 +690,22 @@ Monsters
#Size of each animation frame #Size of each animation frame
SheetFrameSize = 24,24 SheetFrameSize = 24,24
Animations
{
# Frame Count, Frame Speed (s), Frame Cycling (Repeat,OneShot,PingPong,Reverse) # Frame Count, Frame Speed (s), Frame Cycling (Repeat,OneShot,PingPong,Reverse)
IdleAnimation = 1, 0.3, Repeat # Animations must be defined in the same order as they are in their sprite sheets
JumpAnimation = 1, 0.2, Repeat # The First Four animations must represent a standing, walking, attack, and death animation. Their names are up to the creator.
ShootAnimation = 1, 0.2, OneShot IDLE = 1, 0.3, Repeat
DeathAnimation = 1, 0.15, OneShot JUMP = 1, 0.2, Repeat
SHOOT = 1, 0.2, OneShot
# Drop Item Name, Drop Percentage(0-100%), Drop Min Quantity, Drop Max Quantity DEATH = 1, 0.15, OneShot
# DROP[0] = Ring of the Bear,100%,1,1 }
Hurt Sound = Monster Hurt Hurt Sound = Monster Hurt
Death Sound = Slime Dead Death Sound = Slime Dead
Walk Sound = Slime Walk Walk Sound = Slime Walk
#Additional custom animations go down below. Start with ANIMATION[0] Order is: # Drop Item Name, Drop Percentage(0-100%), Drop Min Quantity, Drop Max Quantity
# File name, Frame Count, Frame Speed (s), Frame Cycling (Repeat,OneShot,PingPong,Reverse) # DROP[0] = Ring of the Bear,100%,1,1
# NOTE: ANIMATION[0] will always be row 5 of an animation sheet, all numbers that follow are each below each other.
# ANIMATION[0] = 4, 0.2, OneShot
} }
} }

@ -9,20 +9,20 @@ NPCs
#Size of each animation frame #Size of each animation frame
SheetFrameSize = 24,24 SheetFrameSize = 24,24
Animations
{
# Frame Count, Frame Speed (s), Frame Cycling (Repeat,OneShot,PingPong,Reverse) # Frame Count, Frame Speed (s), Frame Cycling (Repeat,OneShot,PingPong,Reverse)
DownAnimation = 1, 0.1, OneShot # Animations must be defined in the same order as they are in their sprite sheets
UpAnimation = 1, 0.1, OneShot # The First Four animations must represent a standing, walking, attack, and death animation. Their names are up to the creator.
LeftAnimation = 1, 0.1, OneShot DOWN = 1, 0.1, OneShot
RightAnimation = 1, 0.1, OneShot UP = 1, 0.1, OneShot
LEFT = 1, 0.1, OneShot
RIGHT = 1, 0.1, OneShot
}
Hurt Sound = Monster Hurt Hurt Sound = Monster Hurt
Death Sound = Slime Dead Death Sound = Slime Dead
Walk Sound = Slime Walk Walk Sound = Slime Walk
#Additional custom animations go down below. Start with ANIMATION[0] Order is:
# File name, Frame Count, Frame Speed (s), Frame Cycling (Repeat,OneShot,PingPong,Reverse)
# NOTE: ANIMATION[0] will always be row 5 of an animation sheet, all numbers that follow are each below each other.
#ANIMATION[0] = 6, 0.1, Repeat
} }
Sherman Sherman
{ {
@ -33,20 +33,20 @@ NPCs
#Size of each animation frame #Size of each animation frame
SheetFrameSize = 24,24 SheetFrameSize = 24,24
Animations
{
# Frame Count, Frame Speed (s), Frame Cycling (Repeat,OneShot,PingPong,Reverse) # Frame Count, Frame Speed (s), Frame Cycling (Repeat,OneShot,PingPong,Reverse)
DownAnimation = 1, 0.1, OneShot # Animations must be defined in the same order as they are in their sprite sheets
UpAnimation = 1, 0.1, OneShot # The First Four animations must represent a standing, walking, attack, and death animation. Their names are up to the creator.
LeftAnimation = 1, 0.1, OneShot DOWN = 1, 0.1, OneShot
RightAnimation = 1, 0.1, OneShot UP = 1, 0.1, OneShot
LEFT = 1, 0.1, OneShot
RIGHT = 1, 0.1, OneShot
}
Hurt Sound = Monster Hurt Hurt Sound = Monster Hurt
Death Sound = Slime Dead Death Sound = Slime Dead
Walk Sound = Slime Walk Walk Sound = Slime Walk
#Additional custom animations go down below. Start with ANIMATION[0] Order is:
# File name, Frame Count, Frame Speed (s), Frame Cycling (Repeat,OneShot,PingPong,Reverse)
# NOTE: ANIMATION[0] will always be row 5 of an animation sheet, all numbers that follow are each below each other.
#ANIMATION[0] = 6, 0.1, Repeat
} }
Traveling Merchant Traveling Merchant
{ {
@ -55,19 +55,19 @@ NPCs
#Size of each animation frame #Size of each animation frame
SheetFrameSize = 24,24 SheetFrameSize = 24,24
Animations
{
# Frame Count, Frame Speed (s), Frame Cycling (Repeat,OneShot,PingPong,Reverse) # Frame Count, Frame Speed (s), Frame Cycling (Repeat,OneShot,PingPong,Reverse)
DownAnimation = 1, 0.1, OneShot # Animations must be defined in the same order as they are in their sprite sheets
UpAnimation = 1, 0.1, OneShot # The First Four animations must represent a standing, walking, attack, and death animation. Their names are up to the creator.
LeftAnimation = 1, 0.1, OneShot DOWN = 1, 0.1, OneShot
RightAnimation = 1, 0.1, OneShot UP = 1, 0.1, OneShot
LEFT = 1, 0.1, OneShot
RIGHT = 1, 0.1, OneShot
}
Hurt Sound = Monster Hurt Hurt Sound = Monster Hurt
Death Sound = Slime Dead Death Sound = Slime Dead
Walk Sound = Slime Walk Walk Sound = Slime Walk
#Additional custom animations go down below. Start with ANIMATION[0] Order is:
# File name, Frame Count, Frame Speed (s), Frame Cycling (Repeat,OneShot,PingPong,Reverse)
# NOTE: ANIMATION[0] will always be row 5 of an animation sheet, all numbers that follow are each below each other.
#ANIMATION[0] = 6, 0.1, Repeat
} }
} }

@ -15,7 +15,7 @@ Ranger
Auto Attack Auto Attack
{ {
DamageMult = 1 DamageMult = 1
Radius = 100 Radius = 12
Cooldown = 0.6 Cooldown = 0.6
# Whether or not this ability cancels casts. # Whether or not this ability cancels casts.
CancelCast = 0 CancelCast = 0

@ -88,6 +88,7 @@ Images
GFX_Checkmark = checkmark.png GFX_Checkmark = checkmark.png
GFX_DaggerStab = dagger_stab.png GFX_DaggerStab = dagger_stab.png
GFX_GoblinSwordSlash = goblin_sword_slash.png GFX_GoblinSwordSlash = goblin_sword_slash.png
GFX_GoblinArrow = goblin_arrow.png
# Ability Icons # Ability Icons
GFX_Warrior_BattleCry_Icon = Ability Icons/battlecry.png GFX_Warrior_BattleCry_Icon = Ability Icons/battlecry.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 610 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 699 B

@ -52,6 +52,10 @@ int util::random(){
return distrib(rng); return distrib(rng);
} }
const float util::random_range(const float min,const float max){
return random(max-min)+min;
}
vf2d util::pointTo(vf2d posFrom,vf2d posTo){ vf2d util::pointTo(vf2d posFrom,vf2d posTo){
return geom2d::line(posFrom,posTo).vector().norm(); return geom2d::line(posFrom,posTo).vector().norm();
} }

@ -44,6 +44,8 @@ All rights reserved.
namespace olc::util{ namespace olc::util{
//Returns 0-range (as a float). //Returns 0-range (as a float).
float random(float range); float random(float range);
//Returns a random float value min(inclusive) to max(exclusive).
const float random_range(const float min,const float max);
//Returns 0-32767 (as an int). //Returns 0-32767 (as an int).
int random(); int random();
//Returns a normalized vector pointing from posFrom towards posTo. //Returns a normalized vector pointing from posFrom towards posTo.

Loading…
Cancel
Save