Implement Pirate Marauder AI. Release Build 11609.

master
sigonasr2 5 months ago
parent 9509f317c3
commit d6c2b6c87f
  1. 11
      Adventures in Lestoria/Monster.cpp
  2. 10
      Adventures in Lestoria/Monster.h
  3. 95
      Adventures in Lestoria/Pirate_Marauder.cpp
  4. 2
      Adventures in Lestoria/Version.h
  5. 24
      Adventures in Lestoria/assets/Campaigns/3_1.tmx
  6. 23
      Adventures in Lestoria/assets/config/MonsterStrategies.txt
  7. 29
      Adventures in Lestoria/assets/config/Monsters.txt
  8. 6
      Adventures in Lestoria/assets/config/audio/events.txt
  9. 2
      Adventures in Lestoria/olcUTIL_Geometry2D.h
  10. 6
      Adventures in Lestoria/util.h
  11. BIN
      x64/Release/Adventures in Lestoria.exe

@ -169,11 +169,16 @@ void Monster::PerformAnimation(const std::string_view animationName){
if(HasFourWaySprites())animation.ChangeState(internal_animState,std::format("{}_{}",animationName,int(facingDirection))); if(HasFourWaySprites())animation.ChangeState(internal_animState,std::format("{}_{}",animationName,int(facingDirection)));
else animation.ChangeState(internal_animState,std::string(animationName)); else animation.ChangeState(internal_animState,std::string(animationName));
} }
//Performs an animation, optionally changes the facing direction of this monster.
void Monster::PerformAnimation(const std::string_view animationName,const Direction facingDir){ void Monster::PerformAnimation(const std::string_view animationName,const Direction facingDir){
facingDirection=facingDir; facingDirection=facingDir;
PerformAnimation(animationName); PerformAnimation(animationName);
} }
void Monster::PerformAnimation(const std::string_view animationName,const vf2d targetFacingDir){
facingDirection=GetFacingDirectionToTarget(targetFacingDir);
PerformAnimation(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};
vi2d tilePos=vi2d(newPos/float(game->GetCurrentMapData().tilewidth))*game->GetCurrentMapData().tilewidth; vi2d tilePos=vi2d(newPos/float(game->GetCurrentMapData().tilewidth))*game->GetCurrentMapData().tilewidth;
@ -1636,4 +1641,8 @@ void Monster::ResetCurseOfDeathDamage(){
} }
void Monster::AddAddedVelocity(vf2d vel){ void Monster::AddAddedVelocity(vf2d vel){
this->addedVel+=vel; this->addedVel+=vel;
}
void Monster::MoveForward(const vf2d&moveForwardVec,const float fElapsedTime){
if(moveForwardVec.mag()==0.f)ERR("WARNING! Passed a zero length vector into Move Forward! THIS IS NOT ALLOWED!");
SetPos(pos+moveForwardVec.norm()*100.f*fElapsedTime*GetMoveSpdMult());
} }

@ -128,7 +128,8 @@ public:
void PerformNPCLeftAnimation(); void PerformNPCLeftAnimation();
void PerformNPCRightAnimation(); void PerformNPCRightAnimation();
void PerformAnimation(const std::string_view animationName); void PerformAnimation(const std::string_view animationName);
void PerformAnimation(const std::string_view animationName,const Direction facingDir); void PerformAnimation(const std::string_view animationName,const Direction facingDir); //Performs an animation, optionally changes the facing direction of this monster.
void PerformAnimation(const std::string_view animationName,const vf2d targetFacingDir); //Faces a target vector while performing an animation.
const Animate2D::FrameSequence&GetCurrentAnimation()const; const Animate2D::FrameSequence&GetCurrentAnimation()const;
const Animate2D::FrameSequence&GetAnimation(const std::string_view animationName)const; const Animate2D::FrameSequence&GetAnimation(const std::string_view animationName)const;
const bool OnUpperLevel()const; const bool OnUpperLevel()const;
@ -162,8 +163,8 @@ public:
const std::function<void(Monster&,float,std::string)>&GetStrategy()const; const std::function<void(Monster&,float,std::string)>&GetStrategy()const;
void SetSize(float newSize,bool immediate=true); void SetSize(float newSize,bool immediate=true);
geom2d::circle<float>BulletCollisionHitbox(); geom2d::circle<float>BulletCollisionHitbox();
void SetStrategyDrawFunction(std::function<void(AiL*,Monster&,const std::string&)>func); void SetStrategyDrawFunction(std::function<void(AiL*game,Monster&monster,const std::string&strategy)>func);
void SetStrategyDrawOverlayFunction(std::function<void(AiL*,Monster&,const std::string&)>func); void SetStrategyDrawOverlayFunction(std::function<void(AiL*game,Monster&monster,const std::string&strategy)>func);
std::function<void(AiL*,Monster&,const std::string&)>strategyDraw=[](AiL*pge,Monster&m,const std::string&strategy){}; std::function<void(AiL*,Monster&,const std::string&)>strategyDraw=[](AiL*pge,Monster&m,const std::string&strategy){};
std::function<void(AiL*,Monster&,const std::string&)>strategyDrawOverlay=[](AiL*pge,Monster&m,const std::string&strategy){}; std::function<void(AiL*,Monster&,const std::string&)>strategyDrawOverlay=[](AiL*pge,Monster&m,const std::string&strategy){};
const ItemAttributable&GetStats()const; const ItemAttributable&GetStats()const;
@ -227,6 +228,7 @@ public:
const bool FadeoutWhenStandingBehind()const; const bool FadeoutWhenStandingBehind()const;
const bool FaceTarget()const; const bool FaceTarget()const;
void ResetCurseOfDeathDamage(); void ResetCurseOfDeathDamage();
void MoveForward(const vf2d&moveForwardVec,const float fElapsedTime); //Moves the monster forward in given vector direction (will be auto-normalized) applying speeed boosts and other proper movement requirements as if you wanted to move on a frame-by-frame basis.
private: private:
//NOTE: Marking a monster for deletion does not trigger any death events. It just simply removes the monster from the field!! //NOTE: Marking a monster for deletion does not trigger any death events. It just simply removes the monster from the field!!
// The way this works is that monsters marked for deletion will cause the monster update loop to detect there's at least one or more monsters that must be deleted and will call erase_if on the list at the end of the iteration loop. // The way this works is that monsters marked for deletion will cause the monster update loop to detect there's at least one or more monsters that must be deleted and will call erase_if on the list at the end of the iteration loop.
@ -280,7 +282,7 @@ private:
NPCData npcData; NPCData npcData;
float lastPathfindingCooldown=0.f; float lastPathfindingCooldown=0.f;
std::function<bool(GameEvent&,Monster&,const std::string&)>strategyDeathFunc{}; std::function<bool(GameEvent&,Monster&,const std::string&)>strategyDeathFunc{};
void SetStrategyDeathFunction(std::function<bool(GameEvent&,Monster&,const std::string&)>func); void SetStrategyDeathFunction(std::function<bool(GameEvent&event,Monster&monster,const std::string&strategyName)>func);
//If you are trying to change a Get() stat, use the STAT_UP buff (and the optional argument) to supply an attribute you want to apply. //If you are trying to change a Get() stat, use the STAT_UP buff (and the optional argument) to supply an attribute you want to apply.
const ItemAttribute&GetBonusStat(std::string_view attr)const; const ItemAttribute&GetBonusStat(std::string_view attr)const;
//Returns false if the monster could not be moved to the requested location due to collision. //Returns false if the monster could not be moved to the requested location due to collision.

@ -48,19 +48,64 @@ INCLUDE_game
void Monster::STRATEGY::PIRATE_MARAUDER(Monster&m,float fElapsedTime,std::string strategy){ void Monster::STRATEGY::PIRATE_MARAUDER(Monster&m,float fElapsedTime,std::string strategy){
enum PhaseName{ enum PhaseName{
INIT,
MOVE, MOVE,
WINDUP, WINDUP,
RECOVERY, RECOVERY,
}; LEAP,
PREPARE_WHIRLWIND,
enum AttackType{ WHIRLWIND,
STAB,
SLASH
}; };
switch(m.phase){ switch(m.phase){
case INIT:{
m.F(A::CHASE_TIMER)=ConfigFloat("Ability Choose Timer");
m.phase=MOVE;
}break;
case MOVE:{ case MOVE:{
float distToPlayer=m.GetDistanceFrom(game->GetPlayer()->GetPos()); float distToPlayer=m.GetDistanceFrom(game->GetPlayer()->GetPos());
m.F(A::CHASE_TIMER)-=fElapsedTime;
if(m.F(A::CHASE_TIMER)<=0.f){
m.I(A::ABILITY_COUNT)++;
m.F(A::CHASE_TIMER)=ConfigFloat("Ability Choose Timer");
}
if(m.I(A::ABILITY_COUNT)>0){
float roll{util::random_range(0.f,100.f)};
float distanceToPlayer{util::distance(m.GetPos(),game->GetPlayer()->GetPos())};
std::pair<float,float>jumpAttackRollRange{0.f,ConfigFloat("Jump Attack Chance")};
std::pair<float,float>whirlwindAttackRollRange{jumpAttackRollRange.second,jumpAttackRollRange.second+ConfigFloat("Whirlwind Attack Chance")};
if(roll<jumpAttackRollRange.second&&distanceToPlayer>=ConfigFloatArr("Jump Attack Ranges",0)/100.f*24.f&&distanceToPlayer<=ConfigFloatArr("Jump Attack Ranges",1)/100.f*24.f){
m.phase=LEAP;
m.V(A::JUMP_TARGET_POS)=game->GetPlayer()->GetPos();
m.I(A::ABILITY_COUNT)--;
const float impactArea{ConfigFloat("Jump Attack Impact Area")};
m.SetStrategyDrawFunction([impactArea](AiL*game,Monster&monster,const std::string&strategy){
game->view.DrawRotatedDecal(monster.V(A::JUMP_TARGET_POS),GFX["range_indicator.png"].Decal(),0.f,GFX["range_indicator.png"].Sprite()->Size()/2.f,vf2d{1,1}*(impactArea/100.f),{255,0,0,96});
});
m.F(A::JUMP_MOVE_TO_TARGET_TIMER)=0.f;
m.V(A::PREV_POS)=m.GetPos();
m.PerformAnimation("LEAPING",m.V(A::JUMP_TARGET_POS));
break;
}else
if(roll>=whirlwindAttackRollRange.first&&roll<whirlwindAttackRollRange.second
&&distanceToPlayer>=ConfigFloatArr("Whirlwind Attack Ranges",0)/100.f*24.f&&distanceToPlayer<=ConfigFloatArr("Whirlwind Attack Ranges",1)/100.f*24.f){
m.phase=PREPARE_WHIRLWIND;
m.I(A::ABILITY_COUNT)--;
vf2d aimingTarget{game->GetPlayer()->GetPos()};
if(aimingTarget==m.GetPos()){ //Handle edge case.
aimingTarget=m.GetPos()+vf2d{1.f,util::random(2*PI)}.cart();
}
m.V(A::PATH_DIR)=util::pointTo(m.GetPos(),aimingTarget);
m.PerformAnimation("SPIN",m.V(A::LOCKON_POS));
m.F(A::CASTING_TIMER)=ConfigFloat("Whirlwind Chargeup Time");
m.AddBuff(BuffType::SPEEDBOOST,ConfigFloat("Whirlwind Spin Time"),ConfigFloat("Whirlwind Bonus Movespd")/100.f);
break;
}
}
NormalBehavior:
if(distToPlayer>ConfigFloat("Attack Spacing")/100.f*24){ if(distToPlayer>ConfigFloat("Attack Spacing")/100.f*24){
RUN_TOWARDS(m,fElapsedTime,"Run Towards"); RUN_TOWARDS(m,fElapsedTime,"Run Towards");
}else{ }else{
@ -86,5 +131,45 @@ void Monster::STRATEGY::PIRATE_MARAUDER(Monster&m,float fElapsedTime,std::string
if(m.F(A::CASTING_TIMER)<=0){m.PerformIdleAnimation(m.GetFacingDirectionToTarget(game->GetPlayer()->GetPos()));} if(m.F(A::CASTING_TIMER)<=0){m.PerformIdleAnimation(m.GetFacingDirectionToTarget(game->GetPlayer()->GetPos()));}
if(m.F(A::RECOVERY_TIME)<=0)m.phase=MOVE; if(m.F(A::RECOVERY_TIME)<=0)m.phase=MOVE;
}break; }break;
case LEAP:{
m.F(A::JUMP_MOVE_TO_TARGET_TIMER)+=fElapsedTime;
const float halfJumpTime{ConfigFloat("Jump Attack Duration")/2.f};
if(m.F(A::JUMP_MOVE_TO_TARGET_TIMER)<halfJumpTime)m.SetZ(util::smoothstep(0,ConfigFloat("Jump Attack Height"),m.F(A::JUMP_MOVE_TO_TARGET_TIMER)/halfJumpTime));
else m.SetZ(util::smoothstep(ConfigFloat("Jump Attack Height"),0,(m.F(A::JUMP_MOVE_TO_TARGET_TIMER)-halfJumpTime)/halfJumpTime));
m.SetPos(m.V(A::PREV_POS).lerp(m.V(A::JUMP_TARGET_POS),m.F(A::JUMP_MOVE_TO_TARGET_TIMER)/ConfigFloat("Jump Attack Duration")));
if(m.F(A::JUMP_MOVE_TO_TARGET_TIMER)>=ConfigFloat("Jump Attack Duration")){
SoundEffect::PlaySFX("Leap Land",m.GetPos());
game->Hurt(m.GetPos(),ConfigFloat("Jump Attack Impact Area")/100.f*24.f,m.GetAttack(),m.OnUpperLevel(),m.GetZ(),HurtType::PLAYER);
game->ProximityKnockback(m.GetPos(),ConfigFloat("Jump Attack Impact Area")/100.f*24.f,ConfigFloat("Jump Attack Knockback Amount"),HurtType::MONSTER|HurtType::PLAYER);
m.SetZ(0.f);
m.SetPos(m.V(A::JUMP_TARGET_POS));
m.phase=MOVE;
m.PerformIdleAnimation();
m.SetStrategyDrawFunction([](AiL*game,Monster&monster,const std::string&strategy){});
}
}break;
case PREPARE_WHIRLWIND:{
m.F(A::CASTING_TIMER)-=fElapsedTime;
if(m.F(A::CASTING_TIMER)<=0.f){
m.phase=WHIRLWIND;
m.F(A::CHASE_TIMER)=0.f;
m.PerformAnimation("SPINNING");
}
}break;
case WHIRLWIND:{
m.F(A::CHASE_TIMER)+=fElapsedTime;
if(m.F(A::CHASE_TIMER)>=ConfigFloat("Whirlwind Spin Time")){
m.phase=MOVE;
m.PerformIdleAnimation();
}
m.MoveForward(m.V(A::PATH_DIR),fElapsedTime);
const HurtList hurtTargets{game->Hurt(m.GetPos(),ConfigFloat("Whirlwind Radius")/100.f*24.f,m.GetAttack(),m.OnUpperLevel(),m.GetZ(),HurtType::PLAYER)};
for(auto&[target,isHurt]:hurtTargets){
if(std::holds_alternative<Player*>(target)){
(std::get<Player*>(target))->ApplyIframes(0.5f);
}else ERR("WARNING! Somehow ended up with a non-player entity for whirlwind damage check! THIS SHOULD NOT BE HAPPENING!")
}
game->ProximityKnockback(m.GetPos(),ConfigFloat("Whirlwind Radius")/100.f*24.f,ConfigFloat("Whirlwind Knockback Amount"),HurtType::MONSTER|HurtType::PLAYER);
}break;
} }
} }

@ -39,7 +39,7 @@ All rights reserved.
#define VERSION_MAJOR 1 #define VERSION_MAJOR 1
#define VERSION_MINOR 3 #define VERSION_MINOR 3
#define VERSION_PATCH 0 #define VERSION_PATCH 0
#define VERSION_BUILD 11602 #define VERSION_BUILD 11609
#define stringify(a) stringify_(a) #define stringify(a) stringify_(a)
#define stringify_(a) #a #define stringify_(a) #a

@ -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="335" height="165" tilewidth="24" tileheight="24" infinite="0" nextlayerid="8" nextobjectid="9"> <map version="1.10" tiledversion="1.10.2" class="Map" orientation="orthogonal" renderorder="right-down" width="335" height="165" tilewidth="24" tileheight="24" infinite="0" nextlayerid="8" nextobjectid="13">
<properties> <properties>
<property name="Background Music" propertytype="BGM" value="mountain"/> <property name="Background Music" propertytype="BGM" value="mountain"/>
<property name="Level Type" type="int" propertytype="LevelType" value="0"/> <property name="Level Type" type="int" propertytype="LevelType" value="0"/>
@ -9,6 +9,7 @@
<tileset firstgid="4533" source="../maps/palm_trees.tsx"/> <tileset firstgid="4533" source="../maps/palm_trees.tsx"/>
<tileset firstgid="4617" source="../maps/objects.tsx"/> <tileset firstgid="4617" source="../maps/objects.tsx"/>
<tileset firstgid="5400" source="../maps/24x24_Waterfall.tsx"/> <tileset firstgid="5400" source="../maps/24x24_Waterfall.tsx"/>
<tileset firstgid="5480" source="../maps/Monsters.tsx"/>
<layer id="2" name="Layer 1" width="335" height="165"> <layer id="2" name="Layer 1" width="335" height="165">
<data encoding="csv"> <data encoding="csv">
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2312,1736,1785,1785,1785,1735,2312,2312,2312,2312,2312,2312,2312,2312,2312,2312,2312,2312,2312,2312,2312,1736,1785,1785,1785,1785,1785,1785,1785,1735,2312,2312,2312,2312,2312,2312,2312,2312,1734,2298,2298,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1732,2312,2312,2312,2312,2312,2312,2312,2312,2312,2312,2312,2164,2165,2113,2113,2165,2112,2113,2164,2312,2312,2312,2312,2312,2312,2312,2312,2312,1734,2298,2298,2298,2298,2298,2298,1732,2312,2312,2312,2312,2312,2312,2312,2312,2312,2312,2312,2312,2312,2312,2312,2312,2312,2312,2312,2312,2312,2312,2312,2312,2312,2312,2312,2312,2312,2312,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2312,1736,1785,1785,1785,1735,2312,2312,2312,2312,2312,2312,2312,2312,2312,2312,2312,2312,2312,2312,2312,1736,1785,1785,1785,1785,1785,1785,1785,1735,2312,2312,2312,2312,2312,2312,2312,2312,1734,2298,2298,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1732,2312,2312,2312,2312,2312,2312,2312,2312,2312,2312,2312,2164,2165,2113,2113,2165,2112,2113,2164,2312,2312,2312,2312,2312,2312,2312,2312,2312,1734,2298,2298,2298,2298,2298,2298,1732,2312,2312,2312,2312,2312,2312,2312,2312,2312,2312,2312,2312,2312,2312,2312,2312,2312,2312,2312,2312,2312,2312,2312,2312,2312,2312,2312,2312,2312,2312,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
@ -861,13 +862,28 @@
<property name="Upper?" type="bool" value="false"/> <property name="Upper?" type="bool" value="false"/>
</properties> </properties>
</object> </object>
<object id="5" template="../maps/Monsters/Pirate.tx" x="492" y="1452"> <object id="8" name="Spawn Zone" type="SpawnGroup" x="180" y="1326" width="426" height="306">
<ellipse/>
</object>
<object id="9" template="../maps/Monsters/Pirate Marauder.tx" x="474" y="1398">
<properties> <properties>
<property name="spawner" type="object" value="8"/> <property name="spawner" type="object" value="8"/>
</properties> </properties>
</object> </object>
<object id="8" name="Spawn Zone" type="SpawnGroup" x="180" y="1326" width="426" height="306"> <object id="10" template="../maps/Monsters/Pirate Marauder.tx" x="474" y="1350">
<ellipse/> <properties>
<property name="spawner" type="object" value="8"/>
</properties>
</object>
<object id="11" template="../maps/Monsters/Pirate Marauder.tx" x="456" y="1494">
<properties>
<property name="spawner" type="object" value="8"/>
</properties>
</object>
<object id="12" template="../maps/Monsters/Pirate Marauder.tx" x="480" y="1566">
<properties>
<property name="spawner" type="object" value="8"/>
</properties>
</object> </object>
</objectgroup> </objectgroup>
</map> </map>

@ -1032,6 +1032,29 @@ MonsterStrategy
} }
Pirate Marauder Pirate Marauder
{ {
# How long before adding an ability choice charge to perform abilities with.
Ability Choose Timer = 8s
Jump Attack Chance = 25%
Whirlwind Attack Chance = 25%
Whirlwind Chargeup Time = 0.2s
Whirlwind Bonus Movespd = 60%
# Spin time derived from 200% movespd (60% bonus movespd + 125% base movespd)
Whirlwind Spin Time = 1.5s
Whirlwind Knockback Amount = 140
Whirlwind Radius = 200
# Min, Max Range
Whirlwind Attack Ranges = 400, 700
Jump Attack Height = 12
Jump Attack Duration = 0.4s
Jump Attack Impact Area = 150
Jump Attack Knockback Amount = 120
# Min, Max Range
Jump Attack Ranges = 400, 9999
# Distance from player to run to before swinging weapon. # Distance from player to run to before swinging weapon.
Attack Spacing = 50 Attack Spacing = 50

@ -1249,6 +1249,8 @@ Monsters
XP = 33 XP = 33
Collision Radius = 12
Strategy = Goblin Dagger Strategy = Goblin Dagger
#### Script Override #### #### Script Override ####
@ -1327,6 +1329,8 @@ Monsters
XP = 39 XP = 39
Collision Radius = 12
Strategy = Pirate Marauder Strategy = Pirate Marauder
# Wait time override for Run Towards strategy. # Wait time override for Run Towards strategy.
@ -1337,6 +1341,17 @@ Monsters
# Setting this to true means every four rows indicates one animation, the ordering of the directions is: NORTH, EAST, SOUTH, WEST # Setting this to true means every four rows indicates one animation, the ordering of the directions is: NORTH, EAST, SOUTH, WEST
4-Way Spritesheet = True 4-Way Spritesheet = True
#### Script Override ####
# Distance from player to run to before swinging weapon.
Attack Spacing = 100
# Slash Attack windup time
Slash Windup Time = 0.2s
Dagger Slash Image = "pirate_slash.png"
#########################
Animations Animations
{ {
@ -1372,6 +1387,8 @@ Monsters
XP = 59 XP = 59
Collision Radius = 12
Strategy = Pirate Captain Strategy = Pirate Captain
# Wait time override for Run Towards strategy. # Wait time override for Run Towards strategy.
@ -1419,6 +1436,8 @@ Monsters
XP = 37 XP = 37
Collision Radius = 12
Strategy = Pirate Buccaneer Strategy = Pirate Buccaneer
# Wait time override for Run Towards strategy. # Wait time override for Run Towards strategy.
@ -1461,6 +1480,8 @@ Monsters
XP = 37 XP = 37
Collision Radius = 10
Strategy = Crab Strategy = Crab
# Wait time override for Run Towards strategy. # Wait time override for Run Towards strategy.
@ -1502,6 +1523,8 @@ Monsters
XP = 61 XP = 61
Collision Radius = 10
Strategy = Crab Strategy = Crab
# Wait time override for Run Towards strategy. # Wait time override for Run Towards strategy.
@ -1543,6 +1566,8 @@ Monsters
XP = 6 XP = 6
Collision Radius = 9
Strategy = Seagull Strategy = Seagull
# Wait time override for Run Towards strategy. # Wait time override for Run Towards strategy.
@ -1584,6 +1609,8 @@ Monsters
XP = 24 XP = 24
Collision Radius = 10
Strategy = Sandworm Strategy = Sandworm
# Wait time override for Run Towards strategy. # Wait time override for Run Towards strategy.
@ -1627,6 +1654,8 @@ Monsters
XP = 0 XP = 0
Collision Radius = 7
Strategy = Parrot Strategy = Parrot
# Instead of the monster dying, it gets knocked unconscious # Instead of the monster dying, it gets knocked unconscious

@ -237,6 +237,12 @@ Events
# Specify file names, followed by volume %. Optional min and max pitch adjustment (Defaults are 90%,110%) # Specify file names, followed by volume %. Optional min and max pitch adjustment (Defaults are 90%,110%)
File[0] = rockbreak.ogg, 90%, 40%, 50% File[0] = rockbreak.ogg, 90%, 40%, 50%
} }
Leap Land
{
CombatSound = True
# Specify file names, followed by volume %. Optional min and max pitch adjustment (Defaults are 90%,110%)
File[0] = rockbreak.ogg, 80%
}
Level Up Level Up
{ {
# Specify file names, followed by volume %. Optional min and max pitch adjustment (Defaults are 90%,110%) # Specify file names, followed by volume %. Optional min and max pitch adjustment (Defaults are 90%,110%)

@ -191,6 +191,7 @@
#include <optional> #include <optional>
#include <cassert> #include <cassert>
#include <numeric> #include <numeric>
#include "Error.h"
#ifndef OLC_V2D_TYPE #ifndef OLC_V2D_TYPE
#define OLC_V2D_TYPE #define OLC_V2D_TYPE
@ -246,6 +247,7 @@ namespace olc
inline v_2d norm() const inline v_2d norm() const
{ {
auto r = 1 / mag(); auto r = 1 / mag();
if(!std::isfinite(r))ERR("WARNING! Passing a value that creates an unusable infinite value while normalizing! THIS SHOULD NOT BE HAPPENING!");
return v_2d(x * r, y * r); return v_2d(x * r, y * r);
} }

@ -75,6 +75,12 @@ namespace olc::util{
} }
#pragma endregion #pragma endregion
template<class T,class U>
inline auto smoothstep(const T val1,const U val2,const float t){
auto x{decltype(val1+val2)(1-pow(1-t,3))};
return val1*(1-x)+val2*x;
}
std::string timerStr(float time); std::string timerStr(float time);
std::string WrapText(PixelGameEngine*pge,std::string str,int width,bool proportional,vd2d scale); std::string WrapText(PixelGameEngine*pge,std::string str,int width,bool proportional,vd2d scale);
std::u32string WrapText(PixelGameEngine*pge,std::u32string str,int width,Font&font,vd2d scale); std::u32string WrapText(PixelGameEngine*pge,std::u32string str,int width,Font&font,vd2d scale);

Loading…
Cancel
Save