Added overrides for playing default animations in move towards and run away scripts. Implemented Bomb Goblin AI. Include convenience methods for proximity knockback functions. Prepped AI functions for the Hawk and Stone Elementals. Release Build 9230.

mac-build
sigonasr2 7 months ago
parent a4e24b030d
commit b8e1006901
  1. 20
      Adventures in Lestoria/Adventures in Lestoria.vcxproj
  2. 5
      Adventures in Lestoria/Animation.cpp
  3. 94
      Adventures in Lestoria/Bomb.cpp
  4. 52
      Adventures in Lestoria/BombBoom.h
  5. 22
      Adventures in Lestoria/Bullet.cpp
  6. 4
      Adventures in Lestoria/Bullet.h
  7. 16
      Adventures in Lestoria/BulletTypes.h
  8. 86
      Adventures in Lestoria/Goblin_Bomb.cpp
  9. 52
      Adventures in Lestoria/Hawk.cpp
  10. 10
      Adventures in Lestoria/Monster.cpp
  11. 6
      Adventures in Lestoria/Monster.h
  12. 1
      Adventures in Lestoria/MonsterAttribute.h
  13. 10
      Adventures in Lestoria/Player.cpp
  14. 1
      Adventures in Lestoria/Player.h
  15. 3
      Adventures in Lestoria/RUN_STRATEGY.cpp
  16. 52
      Adventures in Lestoria/RunAway.cpp
  17. 10
      Adventures in Lestoria/RunTowards.cpp
  18. 52
      Adventures in Lestoria/Stone_Elemental.cpp
  19. 2
      Adventures in Lestoria/Version.h
  20. 36
      Adventures in Lestoria/assets/Campaigns/2_1.tmx
  21. BIN
      Adventures in Lestoria/assets/bomb_boom.png
  22. 34
      Adventures in Lestoria/assets/config/MonsterStrategies.txt
  23. 28
      Adventures in Lestoria/assets/config/Monsters.txt
  24. 3
      Adventures in Lestoria/assets/config/gfx/gfx.txt
  25. BIN
      Adventures in Lestoria/assets/gamepack.pak
  26. BIN
      Adventures in Lestoria/assets/goblin_bomb.png
  27. BIN
      Adventures in Lestoria/assets/goblin_bomb_fuse.png
  28. 6
      Adventures in Lestoria/olcUTIL_Geometry2D.h
  29. BIN
      x64/Release/Adventures in Lestoria.exe

@ -292,6 +292,10 @@
<SubType>
</SubType>
</ClInclude>
<ClInclude Include="BombBoom.h">
<SubType>
</SubType>
</ClInclude>
<ClInclude Include="Buff.h" />
<ClInclude Include="Bullet.h" />
<ClInclude Include="BulletTypes.h" />
@ -627,6 +631,10 @@
<SubType>
</SubType>
</ClCompile>
<ClCompile Include="Bomb.cpp">
<SubType>
</SubType>
</ClCompile>
<ClCompile Include="Bullet.cpp" />
<ClCompile Include="BuyItemWindow.cpp">
<SubType>
@ -716,11 +724,19 @@
<SubType>
</SubType>
</ClCompile>
<ClCompile Include="Goblin_Bomb.cpp">
<SubType>
</SubType>
</ClCompile>
<ClCompile Include="Goblin_Bow.cpp">
<SubType>
</SubType>
</ClCompile>
<ClCompile Include="Goblin_Dagger.cpp" />
<ClCompile Include="Hawk.cpp">
<SubType>
</SubType>
</ClCompile>
<ClCompile Include="InputHelper.cpp">
<SubType>
</SubType>
@ -862,6 +878,10 @@
<SubType>
</SubType>
</ClCompile>
<ClCompile Include="Stone_Elemental.cpp">
<SubType>
</SubType>
</ClCompile>
<ClCompile Include="SwordSlash.cpp">
<SubType>
</SubType>

@ -234,8 +234,11 @@ void sig::Animation::InitializeAnimations(){
CreateStillAnimation("chain_lightning.png",{1,9});
CreateHorizontalAnimationSequence("lightning_splash_effect.png",5,{24,24});
CreateHorizontalAnimationSequence("dagger_stab.png",2,{24,24},AnimationData{0.1f,Animate2D::Style::PingPong});
CreateHorizontalAnimationSequence("dagger_stab.png",2,{24,24},AnimationData{.frameDuration{0.1f},.style{Animate2D::Style::PingPong}});
CreateHorizontalAnimationSequence("goblin_sword_slash.png",3,{24,24},{0.05f,Animate2D::Style::OneShot});
CreateHorizontalAnimationSequence("goblin_bomb.png",4,{24,24},AnimationData{.frameDuration{0.2f},.style{Animate2D::Style::PingPong}});
CreateHorizontalAnimationSequence("goblin_bomb_fuse.png",4,{24,24},AnimationData{.frameDuration{1.f},.style{Animate2D::Style::OneShot}});
CreateHorizontalAnimationSequence("bomb_boom.png",5,{36,36},AnimationData{.frameDuration{0.2f},.style{Animate2D::Style::OneShot}});
CreateStillAnimation("meteor.png",{192,192});

@ -0,0 +1,94 @@
#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 "BulletTypes.h"
#include "util.h"
#include "AdventuresInLestoria.h"
#include "BombBoom.h"
INCLUDE_DATA
INCLUDE_ANIMATION_DATA
INCLUDE_game
Bomb::Bomb(const vf2d pos,const float z,const float gravity,const float detonationTime,const float bombFadeoutTime,const float bombKnockbackFactor,const vf2d targetPos,const float radius,const int damage,const bool upperLevel,const bool friendly,const Pixel col,const vf2d scale)
:Bullet(pos,{},radius,damage,"goblin_bomb.png",upperLevel,true,INFINITY,false,friendly,col,scale)
,gravity(gravity),detonationTime(detonationTime),bombFadeoutTime(bombFadeoutTime),bombKnockbackFactor(bombKnockbackFactor),targetPos(targetPos){
this->z=z;
deactivated=true;
bomb_animation.AddState("Fuse",ANIMATION_DATA.at("goblin_bomb_fuse.png"));
bomb_animation.ChangeState(animation,"Fuse");
}
void Bomb::Update(float fElapsedTime){
vel=geom2d::line<float>(pos,targetPos).vector();
detonationTime-=fElapsedTime;
bomb_animation.UpdateState(animation,fElapsedTime);
if(detonationTime>0.f){
zVel+=gravity*fElapsedTime;
z=std::max(0.f,z+zVel*fElapsedTime);
if(z==0.f)zVel*=-1.f;
}else
if(fadeOutTime==0.f){
z=0; //Force the bomb to be grounded.
fadeOutTime=bombFadeoutTime;
game->AddEffect(std::make_unique<BombBoom>(pos,0.f,OnUpperLevel(),scale*1.5f/*Upscale 24x24 to 36x36*/,1.f,vf2d{},WHITE,0.f,0.f,true));
if(friendly){
const MonsterHurtList hurtEnemies=game->HurtEnemies(pos,radius,damage,OnUpperLevel(),z);
for(auto&[monsterPtr,wasHit]:hurtEnemies){
if(wasHit)monsterPtr->ProximityKnockback(pos,bombKnockbackFactor);
}
}else{
float distToPlayer=geom2d::line<float>(pos,game->GetPlayer()->GetPos()).length();
if(distToPlayer<=radius){
if(game->GetPlayer()->Hurt(damage,OnUpperLevel(),z)){
game->GetPlayer()->ProximityKnockback(pos,bombKnockbackFactor);
}
}
}
}
}
bool Bomb::PlayerHit(Player*player){
return false;
}
bool Bomb::MonsterHit(Monster&monster){
return false;
}
void Bomb::Draw()const{
Bullet::Draw();
game->view.DrawPartialRotatedDecal(pos-vf2d{0,GetZ()},bomb_animation.GetFrame(animation).GetSourceImage()->Decal(),rotates?atan2(vel.y,vel.x)-PI/2:0,bomb_animation.GetFrame(animation).GetSourceRect().size/2,bomb_animation.GetFrame(animation).GetSourceRect().pos,bomb_animation.GetFrame(animation).GetSourceRect().size,scale,fadeOutTime==0?col:Pixel{col.r,col.g,col.b,uint8_t(util::lerp(col.a,0,1-((fadeOutTime-fadeOutTimer)/fadeOutTime)))});
}

@ -0,0 +1,52 @@
#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 "Effect.h"
#include "DEFINES.h"
#include "safemap.h"
INCLUDE_GFX
class BombBoom:public Effect{
public:
inline BombBoom(vf2d pos,float lifetime,bool upperLevel,vf2d size={1,1},float fadeout=0.0f,vf2d spd={},Pixel col=WHITE,float rotation=0,float rotationSpd=0,bool additiveBlending=false)
:Effect(pos,lifetime,"bomb_boom.png",upperLevel,size,fadeout,spd,col,rotation,rotationSpd,additiveBlending){}
inline bool Update(float fElapsedTime)override{
return Effect::Update(fElapsedTime);
}
};

@ -39,6 +39,7 @@ All rights reserved.
#include "AdventuresInLestoria.h"
#include "DEFINES.h"
#include "safemap.h"
#include "util.h"
INCLUDE_ANIMATION_DATA
INCLUDE_game
@ -91,7 +92,7 @@ void Bullet::_Update(const float fElapsedTime){
if(friendly){
for(std::unique_ptr<Monster>&m:MONSTER_LIST){
if(geom2d::overlaps(m->Hitbox(),geom2d::circle(pos,radius))){
if(hitList.find(&*m)==hitList.end()&&m->Hurt(damage,OnUpperLevel(),0)){
if(hitList.find(&*m)==hitList.end()&&m->Hurt(damage,OnUpperLevel(),z)){
if(!hitsMultiple){
if(MonsterHit(*m)){
dead=true;
@ -104,7 +105,7 @@ void Bullet::_Update(const float fElapsedTime){
}
} else {
if(geom2d::overlaps(game->GetPlayer()->Hitbox(),geom2d::circle(pos,radius))){
if(game->GetPlayer()->Hurt(damage,OnUpperLevel(),0)){
if(game->GetPlayer()->Hurt(damage,OnUpperLevel(),z)){
if(PlayerHit(&*game->GetPlayer())){
dead=true;
}
@ -141,13 +142,16 @@ void Bullet::_Update(const float fElapsedTime){
}
void Bullet::Draw()const{
auto lerp=[](uint8_t f1,uint8_t f2,float t){return uint8_t((float(f2)*t)+f1*(1-t));};
if(GetZ()>0){
vf2d shadowScale=vf2d{8*(radius/12.f)/3.f,1}/std::max(1.f,GetZ()/24);
game->view.DrawDecal(pos-vf2d{3,3}*shadowScale/2+vf2d{0,6*(radius/12.f)},GFX["circle.png"].Decal(),shadowScale,BLACK);
}
if(animated){
game->view.DrawPartialRotatedDecal(pos,GetFrame().GetSourceImage()->Decal(),rotates?atan2(vel.y,vel.x)-PI/2:0,GetFrame().GetSourceRect().size/2,GetFrame().GetSourceRect().pos,GetFrame().GetSourceRect().size,scale,fadeOutTime==0?col:Pixel{col.r,col.g,col.b,lerp(col.a,0,1-((fadeOutTime-fadeOutTimer)/fadeOutTime))});
} else {
game->view.DrawDecal(pos-GFX["circle.png"].Sprite()->Size()*scale/2,GFX["circle.png"].Decal(),scale,fadeOutTime==0?col:Pixel{col.r,col.g,col.b,lerp(col.a,0,1-((fadeOutTime-fadeOutTimer)/fadeOutTime))});
game->view.DrawDecal(pos-GFX["circle.png"].Sprite()->Size()*scale/2,GFX["circle_outline.png"].Decal(),scale,fadeOutTime==0?WHITE:Pixel{WHITE.r,WHITE.g,WHITE.b,lerp(WHITE.a,0,1-((fadeOutTime-fadeOutTimer)/fadeOutTime))});
game->view.DrawPartialRotatedDecal(pos-vf2d{0,GetZ()},GetFrame().GetSourceImage()->Decal(),rotates?atan2(vel.y,vel.x)-PI/2:0,GetFrame().GetSourceRect().size/2,GetFrame().GetSourceRect().pos,GetFrame().GetSourceRect().size,scale,fadeOutTime==0?col:Pixel{col.r,col.g,col.b,uint8_t(util::lerp(col.a,0,1-((fadeOutTime-fadeOutTimer)/fadeOutTime)))});
}else{
game->view.DrawDecal(pos-vf2d{0,GetZ()}-GFX["circle.png"].Sprite()->Size()*scale/2,GFX["circle.png"].Decal(),scale,fadeOutTime==0?col:Pixel{col.r,col.g,col.b,uint8_t(util::lerp(col.a,0,1-((fadeOutTime-fadeOutTimer)/fadeOutTime)))});
game->view.DrawDecal(pos-vf2d{0,GetZ()}-GFX["circle.png"].Sprite()->Size()*scale/2,GFX["circle_outline.png"].Decal(),scale,fadeOutTime==0?WHITE:Pixel{WHITE.r,WHITE.g,WHITE.b,uint8_t(util::lerp(WHITE.a,0,1-((fadeOutTime-fadeOutTimer)/fadeOutTime)))});
}
}
@ -158,3 +162,7 @@ bool Bullet::OnUpperLevel(){return upperLevel;}
const bool Bullet::IsDead()const{
return dead;
}
const float Bullet::GetZ()const{
return z;
}

@ -56,13 +56,14 @@ struct Bullet{
bool friendly=false; //Whether or not it's a player bullet or enemy bullet.
bool upperLevel=false;
bool alwaysOnTop=false;
float z=0.f;
protected:
float fadeOutTimer=0;
float distanceTraveled=0.f;
vf2d scale={1,1};
private:
void UpdateFadeTime(float fElapsedTime);
virtual void Update(float fElapsedTime);
vf2d scale={1,1};
bool dead=false; //When marked as dead it wil be removed by the next frame.
bool simulated=false; //A simulated bullet cannot interact / damage things in the world. It's simply used for simulating the trajectory and potential path of the bullet
public:
@ -85,4 +86,5 @@ public:
virtual void Draw()const;
bool OnUpperLevel();
const bool IsDead()const;
const float GetZ()const;
};

@ -146,3 +146,19 @@ struct DaggerSlash:public Bullet{
bool PlayerHit(Player*player)override;
bool MonsterHit(Monster&monster)override;
};
struct Bomb:public Bullet{
float gravity;
float zVel{0.f};
float detonationTime{0.f};
float bombFadeoutTime{0.f};
const vf2d targetPos{};
Animate2D::AnimationState animation;
Animate2D::Animation<std::string>bomb_animation;
float bombKnockbackFactor{0.f};
Bomb(const vf2d pos,const float z,const float gravity,const float detonationTime,const float bombFadeoutTime,float bombKnockbackFactor,const vf2d targetPos,const float radius,const int damage,const bool upperLevel,const bool friendly=false,const Pixel col=WHITE,const vf2d scale={1,1});
void Update(float fElapsedTime)override;
bool PlayerHit(Player*player)override;
bool MonsterHit(Monster&monster)override;
void Draw()const override;
};

@ -0,0 +1,86 @@
#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"
INCLUDE_ANIMATION_DATA
INCLUDE_BULLET_LIST
INCLUDE_game
using A=Attribute;
/*
* Attack Strategie:
Throws every 4 seconds a bomb on top of the player that detonates after 3.5 seconds in a 300 radius.
Tries to keeps his distance on a 600 radius. Throws bombs even while moving.
*/
void Monster::STRATEGY::GOBLIN_BOMB(Monster&m,float fElapsedTime,std::string strategy){
enum PhaseName{
INITIALIZE,
RUN,
};
switch(m.phase){
case INITIALIZE:{
m.F(A::SHOOT_TIMER)=m.randomFrameOffset;
m.phase=RUN;
}break;
case RUN:{
m.F(A::SHOOT_TIMER)+=fElapsedTime;
m.F(A::SHOOT_ANIMATION_TIME)-=fElapsedTime;
float distToPlayer=geom2d::line<float>(m.GetPos(),game->GetPlayer()->GetPos()).length();
if(m.F(A::SHOOT_TIMER)>=ConfigFloat("Bomb Reload Time")&&distToPlayer<=ConfigFloat("Bomb Max Range")){
vf2d targetThrowPos=geom2d::line<float>(m.GetPos(),game->GetPlayer()->GetPos()).rpoint(distToPlayer-ConfigFloat("Bomb Distance Variation")+util::random(ConfigFloat("Bomb Distance Variation")*2.f));
CreateBullet(Bomb)(m.GetPos(),ConfigFloat("Bomb Starting Z"),ConfigFloat("Bomb Gravity"),ConfigFloat("Bomb Detonation Time"),ConfigFloat("Bomb Fadeout Time"),ConfigFloat("Bomb Knockback Factor"),targetThrowPos,ConfigFloat("Bomb Radius")/100.f*24,m.GetAttack(),m.OnUpperLevel(),false,WHITE,vf2d{3,3})EndBullet;
m.UpdateFacingDirection(game->GetPlayer()->GetPos());
m.PerformShootAnimation();
m.B(A::IGNORE_DEFAULT_ANIMATIONS)=true;
m.F(A::SHOOT_ANIMATION_TIME)=m.GetCurrentAnimation().GetTotalAnimationDuration();
m.F(A::SHOOT_TIMER)=0.f;
}
if(m.F(A::SHOOT_ANIMATION_TIME)<0.f)m.B(A::IGNORE_DEFAULT_ANIMATIONS)=false;
RUN_AWAY(m,fElapsedTime,"Run Away");
}break;
}
}

@ -0,0 +1,52 @@
#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_ANIMATION_DATA
INCLUDE_BULLET_LIST
INCLUDE_game
using A=Attribute;
void Monster::STRATEGY::HAWK(Monster&m,float fElapsedTime,std::string strategy){
}

@ -977,3 +977,13 @@ void DeathSpawnInfo::Spawn(const vf2d monsterDeathPos,const bool onUpperLevel){
game->SpawnMonster(monsterDeathPos+spawnLocOffset,MONSTER_DATA.at(monsterSpawnName),onUpperLevel).iframe_timer=0.25f;
}
}
void Monster::ProximityKnockback(const vf2d centerPoint,const float knockbackFactor){
geom2d::line<float>lineToMonster(centerPoint,game->GetPlayer()->GetPos());
float dist=lineToMonster.length();
if(dist<0.001f){
float randomDir=util::random(2*PI);
lineToMonster={centerPoint,centerPoint+vf2d{cos(randomDir),sin(randomDir)}*1};
}
game->GetPlayer()->Knockback(lineToMonster.vector().norm()*knockbackFactor);
}

@ -147,7 +147,8 @@ public:
const EventName&GetDeathSound();
const EventName&GetWalkSound();
void Knockback(const vf2d&vel);
//Knockup the player for duration amount of seconds, and Zamt pixels.
void ProximityKnockback(const vf2d centerPoint,const float knockbackFactor);
//Knockup the player for duration amount of seconds.
void Knockup(float duration);
const bool AttackAvoided(const float attackZ)const;
const std::string&GetName()const;
@ -255,6 +256,9 @@ private:
static void GOBLIN_DAGGER(Monster&m,float fElapsedTime,std::string strategy);
static void GOBLIN_BOW(Monster&m,float fElapsedTime,std::string strategy);
static void GOBLIN_BOAR_RIDER(Monster&m,float fElapsedTime,std::string strategy);
static void GOBLIN_BOMB(Monster&m,float fElapsedTime,std::string strategy);
static void HAWK(Monster&m,float fElapsedTime,std::string strategy);
static void STONE_ELEMENTAL(Monster&m,float fElapsedTime,std::string strategy);
};
bool bumpedIntoTerrain=false; //Gets set to true before a strategy executes if the monster runs into some terrain on this frame.
bool attackedByPlayer=false; //Gets set to true before a strategy executes if the monster has been attacked by the player.

@ -113,4 +113,5 @@ enum class Attribute{
RANDOM_RANGE,
PERCEPTION_LEVEL,
INITIALIZED_MOUNTED_MONSTER,
IGNORE_DEFAULT_ANIMATIONS, //If set to true, movement scripts like move towards and run away will not play their animations and leave it up to the monster strategy itself. This can be useful for overrides when trying to play other attack animations etc.
};

@ -1544,3 +1544,13 @@ const float Player::GetIframeTime()const{
const Renderable&Player::GetMinimapImage()const{
return minimapImg;
}
void Player::ProximityKnockback(const vf2d centerPoint,const float knockbackFactor){
geom2d::line<float>lineToPlayer(centerPoint,game->GetPlayer()->GetPos());
float dist=lineToPlayer.length();
if(dist<0.001f){
float randomDir=util::random(2*PI);
lineToPlayer={centerPoint,centerPoint+vf2d{cos(randomDir),sin(randomDir)}*1};
}
game->GetPlayer()->Knockback(lineToPlayer.vector().norm()*knockbackFactor);
}

@ -141,6 +141,7 @@ public:
bool CanAct();
bool CanAct(Ability&ability);
void Knockback(vf2d vel);
void ProximityKnockback(const vf2d centerPoint,const float knockbackFactor);
void SetIframes(float duration);
void RestoreMana(int amt,bool suppressDamageNumber=false);
void ConsumeMana(int amt);

@ -57,6 +57,9 @@ void Monster::InitializeStrategies(){
STRATEGY_DATA.insert("Goblin Dagger",Monster::STRATEGY::GOBLIN_DAGGER);
STRATEGY_DATA.insert("Goblin Bow",Monster::STRATEGY::GOBLIN_BOW);
STRATEGY_DATA.insert("Goblin Boar Rider",Monster::STRATEGY::GOBLIN_BOAR_RIDER);
STRATEGY_DATA.insert("Goblin Bomb",Monster::STRATEGY::GOBLIN_BOMB);
STRATEGY_DATA.insert("Hawk",Monster::STRATEGY::HAWK);
STRATEGY_DATA.insert("Stone Elemental",Monster::STRATEGY::STONE_ELEMENTAL);
STRATEGY_DATA.SetInitialized();
}

@ -44,6 +44,8 @@ All rights reserved.
INCLUDE_BULLET_LIST
INCLUDE_game
using A=Attribute;
void Monster::STRATEGY::RUN_AWAY(Monster&m,float fElapsedTime,std::string strategy){
m.targetAcquireTimer=std::max(0.f,m.targetAcquireTimer-fElapsedTime);
m.attackCooldownTimer=std::max(0.f,m.attackCooldownTimer-fElapsedTime);
@ -57,7 +59,7 @@ void Monster::STRATEGY::RUN_AWAY(Monster&m,float fElapsedTime,std::string strate
} else {
m.SetState(State::NORMAL);
}
} else
}else
if(line.length()>24.f*ConfigInt("CloseInRange")/100.0f){
m.target=line.upoint(1.2f);
m.SetState(State::MOVE_TOWARDS);
@ -88,28 +90,10 @@ void Monster::STRATEGY::RUN_AWAY(Monster&m,float fElapsedTime,std::string strate
}
}else if(line.length()<=24.f*ConfigInt("CloseInRange")/100.0f)m.SetState(State::NORMAL);
if(m.HasFourWaySprites()){
if(abs(moveTowardsLine.vector().x)>abs(moveTowardsLine.vector().y)){
if(moveTowardsLine.vector().x>0){
m.facingDirection=Direction::EAST;
} else {
m.facingDirection=Direction::WEST;
}
}else{
if(moveTowardsLine.vector().y>0){
m.facingDirection=Direction::SOUTH;
} else {
m.facingDirection=Direction::NORTH;
}
}
}else{
if(moveTowardsLine.vector().x>0){
m.facingDirection=Direction::EAST;
} else {
m.facingDirection=Direction::WEST;
}
}
if(!m.B(A::IGNORE_DEFAULT_ANIMATIONS)){
m.UpdateFacingDirection(m.target);
m.PerformJumpAnimation();
}
}break;
case State::MOVE_AWAY:{
if(moveTowardsLine.length()>1){
@ -130,28 +114,10 @@ void Monster::STRATEGY::RUN_AWAY(Monster&m,float fElapsedTime,std::string strate
}
}else if(line.length()>=24.f*ConfigInt("Range")/100.f)m.SetState(State::NORMAL);
if(m.HasFourWaySprites()){
if(abs(moveTowardsLine.vector().x)>abs(moveTowardsLine.vector().y)){
if(moveTowardsLine.vector().x>0){
m.facingDirection=Direction::EAST;
} else {
m.facingDirection=Direction::WEST;
}
}else{
if(moveTowardsLine.vector().y>0){
m.facingDirection=Direction::SOUTH;
} else {
m.facingDirection=Direction::NORTH;
}
}
}else{
if(moveTowardsLine.vector().x>0){
m.facingDirection=Direction::EAST;
} else {
m.facingDirection=Direction::WEST;
}
}
if(!m.B(A::IGNORE_DEFAULT_ANIMATIONS)){
m.UpdateFacingDirection(m.target);
m.PerformJumpAnimation();
}
}break;
case State::PATH_AROUND:{
m.PathAroundBehavior(fElapsedTime);

@ -106,10 +106,10 @@ void Monster::STRATEGY::RUN_TOWARDS(Monster&m,float fElapsedTime,std::string str
m.target=m.GetPos()+vf2d{sin(randomAngle),cos(randomAngle)}*randomDist;
}
}
m.PerformJumpAnimation();
if(!m.B(A::IGNORE_DEFAULT_ANIMATIONS))m.PerformJumpAnimation();
} else {
m.SetState(State::NORMAL);//Revert state once we've finished moving towards target.
m.PerformIdleAnimation();
if(!m.B(A::IGNORE_DEFAULT_ANIMATIONS))m.PerformIdleAnimation();
}
if(jumpingEnabled){
m.F(A::LAST_JUMP_TIMER)=std::max(0.f,m.F(A::LAST_JUMP_TIMER)-fElapsedTime);
@ -162,11 +162,7 @@ void Monster::STRATEGY::RUN_TOWARDS(Monster&m,float fElapsedTime,std::string str
int jumpDamage=0;
if(ConfigInt("JumpAttackDamage")>0)jumpDamage=ConfigInt("JumpAttackDamage");
game->GetPlayer()->Hurt(jumpDamage,m.OnUpperLevel(),m.GetZ());
if(dist<0.001){
float randomDir=util::random(2*PI);
lineToPlayer={m.GetPos(),m.GetPos()+vf2d{cos(randomDir),sin(randomDir)}*1};
}
game->GetPlayer()->Knockback(lineToPlayer.vector().norm()*float(ConfigInt("JumpKnockbackFactor")));
game->GetPlayer()->ProximityKnockback(m.GetPos(),float(ConfigInt("JumpKnockbackFactor")));
game->GetPlayer()->SetIframes(game->GetPlayer()->GetIframeTime()+0.3f);
}
m.SetZ(0);

@ -0,0 +1,52 @@
#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_ANIMATION_DATA
INCLUDE_BULLET_LIST
INCLUDE_game
using A=Attribute;
void Monster::STRATEGY::STONE_ELEMENTAL(Monster&m,float fElapsedTime,std::string strategy){
}

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

@ -1,5 +1,5 @@
<?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="35">
<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="43">
<properties>
<property name="Backdrop" propertytype="Backdrop" value="mountain_day"/>
<property name="Background Music" propertytype="BGM" value="foresty1_1"/>
@ -1882,12 +1882,42 @@
<ellipse/>
</object>
<object id="28" name="Player Spawn" type="PlayerSpawnLocation" x="5112" y="8064" width="24" height="24"/>
<object id="33" template="../maps/Monsters/Goblin Boar Rider.tx" x="4511" y="8032">
<object id="35" template="../maps/Monsters/Goblin (Bombs).tx" x="4548" y="8016">
<properties>
<property name="spawner" type="object" value="15"/>
</properties>
</object>
<object id="34" template="../maps/Monsters/Green Slime.tx" x="4515" y="8107">
<object id="36" template="../maps/Monsters/Hawk.tx" x="4554" y="8060">
<properties>
<property name="spawner" type="object" value="15"/>
</properties>
</object>
<object id="37" template="../maps/Monsters/Stone Elemental.tx" x="4551" y="8142">
<properties>
<property name="spawner" type="object" value="15"/>
</properties>
</object>
<object id="38" template="../maps/Monsters/Goblin (Bombs).tx" x="4548" y="8016">
<properties>
<property name="spawner" type="object" value="15"/>
</properties>
</object>
<object id="39" template="../maps/Monsters/Goblin (Bombs).tx" x="4548" y="8016">
<properties>
<property name="spawner" type="object" value="15"/>
</properties>
</object>
<object id="40" template="../maps/Monsters/Goblin (Bombs).tx" x="4634" y="7752">
<properties>
<property name="spawner" type="object" value="15"/>
</properties>
</object>
<object id="41" template="../maps/Monsters/Goblin (Bombs).tx" x="4590" y="8223">
<properties>
<property name="spawner" type="object" value="15"/>
</properties>
</object>
<object id="42" template="../maps/Monsters/Goblin (Bombs).tx" x="4364" y="8230">
<properties>
<property name="spawner" type="object" value="15"/>
</properties>

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

@ -670,4 +670,38 @@ MonsterStrategy
### End Boar Stuff
###################
}
Goblin Bomb
{
# Only throw the bomb when the player is within this range.
Bomb Max Range = 800
# How long between each bomb throw.
Bomb Reload Time = 4.0s
# How long until the bomb explodes.
Bomb Detonation Time = 3.5s
# Range of the bomb.
Bomb Radius = 300
Bomb Knockback Factor = 200
Bomb Starting Z = 12
Bomb Gravity = -20.0
# How high the bounce of the bomb is after hitting the ground.
Bomb Elasticity = 0.4
# How much distance (in pixels) to vary the bomb toss (+/-)
Bomb Distance Variation = 32
Bomb Fadeout Time = 0.3s
}
Hawk
{
}
Stone Elemental
{
}
}

@ -614,7 +614,7 @@ Monsters
XP = 17
Strategy = Run Towards
Strategy = Goblin Bomb
#Size of each animation frame
SheetFrameSize = 32,32
@ -627,10 +627,10 @@ Monsters
# 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.6, Repeat
JUMP = 1, 0.2, Repeat
SHOOT = 1, 0.2, OneShot
DEATH = 1, 0.15, OneShot
IDLE = 2, 0.6, Repeat
WALK = 4, 0.3, Repeat
THROW = 3, 0.1, OneShot
DEATH = 4, 0.15, OneShot
}
Hurt Sound = Monster Hurt
@ -675,6 +675,17 @@ Monsters
DEATH = 4, 0.15, OneShot
}
###########################
# Run Away Script Overrides
###########################
# How far away the monster attempts to distance itself from the player
Range = 600
# If the player is farther than this distance, close in on them.
CloseInRange = 700
###############################
# End Run Away Script Overrides
###############################
Hurt Sound = Monster Hurt
Death Sound = Slime Dead
Walk Sound = Slime Walk
@ -694,7 +705,7 @@ Monsters
XP = 5
Strategy = Run Towards
Strategy = Hawk
#Size of each animation frame
SheetFrameSize = 32,32
@ -728,11 +739,12 @@ Monsters
CollisionDmg = 26
MoveSpd = 50%
Size = 220%
# Due to the Stone Elemental's base sprite size being 36x36, 220% is actually 146.666666667% size when factoring in a 50% larger sprite.
Size = 147%
XP = 71
Strategy = Run Towards
Strategy = Stone Elemental
#Size of each animation frame
SheetFrameSize = 48,48

@ -90,6 +90,9 @@ Images
GFX_GoblinSwordSlash = goblin_sword_slash.png
GFX_GoblinArrow = goblin_arrow.png
GFX_GoblinBowForeground = monsters/commercial_assets/Goblin (Bow)_foreground.png
GFX_GoblinBomb = goblin_bomb.png
GFX_GoblinBombFuse = goblin_bomb_fuse.png
GFX_BombBoom = bomb_boom.png
# Ability Icons
GFX_Warrior_BattleCry_Icon = Ability Icons/battlecry.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 708 B

@ -558,19 +558,19 @@ namespace olc::utils::geom2d
{ }
// Get vector pointing from start to end
inline constexpr olc::v_2d<T> vector() const
inline constexpr olc::v_2d<T> vector()const
{
return (end - start);
}
// Get length of line
inline constexpr T length()
inline constexpr T length()const
{
return vector().mag();
}
// Get length of line^2
inline constexpr T length2()
inline constexpr T length2()const
{
return vector().mag2();
}

Loading…
Cancel
Save