diff --git a/Adventures in Lestoria/Adventures in Lestoria.vcxproj b/Adventures in Lestoria/Adventures in Lestoria.vcxproj
index a50a4b17..da94c361 100644
--- a/Adventures in Lestoria/Adventures in Lestoria.vcxproj
+++ b/Adventures in Lestoria/Adventures in Lestoria.vcxproj
@@ -292,6 +292,10 @@
+
+
+
+
@@ -627,6 +631,10 @@
+
+
+
+
@@ -716,11 +724,19 @@
+
+
+
+
+
+
+
+
@@ -862,6 +878,10 @@
+
+
+
+
diff --git a/Adventures in Lestoria/Animation.cpp b/Adventures in Lestoria/Animation.cpp
index 883c309c..4c440eb5 100644
--- a/Adventures in Lestoria/Animation.cpp
+++ b/Adventures in Lestoria/Animation.cpp
@@ -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});
diff --git a/Adventures in Lestoria/Bomb.cpp b/Adventures in Lestoria/Bomb.cpp
new file mode 100644
index 00000000..84158ef6
--- /dev/null
+++ b/Adventures in Lestoria/Bomb.cpp
@@ -0,0 +1,94 @@
+#pragma region License
+/*
+License (OLC-3)
+~~~~~~~~~~~~~~~
+
+Copyright 2024 Joshua Sigona
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+1. Redistributions or derivations of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+
+2. Redistributions or derivative works in binary form must reproduce the above
+copyright notice. This list of conditions and the following disclaimer must be
+reproduced in the documentation and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its contributors may
+be used to endorse or promote products derived from this software without specific
+prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+Portions of this software are copyright © 2024 The FreeType
+Project (www.freetype.org). Please see LICENSE_FT.txt for more information.
+All rights reserved.
+*/
+#pragma endregion
+
+#include "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(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(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(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)))});
+}
\ No newline at end of file
diff --git a/Adventures in Lestoria/BombBoom.h b/Adventures in Lestoria/BombBoom.h
new file mode 100644
index 00000000..170a3583
--- /dev/null
+++ b/Adventures in Lestoria/BombBoom.h
@@ -0,0 +1,52 @@
+#pragma region License
+/*
+License (OLC-3)
+~~~~~~~~~~~~~~~
+
+Copyright 2024 Joshua Sigona
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+1. Redistributions or derivations of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+
+2. Redistributions or derivative works in binary form must reproduce the above
+copyright notice. This list of conditions and the following disclaimer must be
+reproduced in the documentation and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its contributors may
+be used to endorse or promote products derived from this software without specific
+prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+Portions of this software are copyright © 2024 The FreeType
+Project (www.freetype.org). Please see LICENSE_FT.txt for more information.
+All rights reserved.
+*/
+#pragma endregion
+#include "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);
+ }
+};
\ No newline at end of file
diff --git a/Adventures in Lestoria/Bullet.cpp b/Adventures in Lestoria/Bullet.cpp
index cfe93ba4..45c5e2bf 100644
--- a/Adventures in Lestoria/Bullet.cpp
+++ b/Adventures in Lestoria/Bullet.cpp
@@ -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&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)))});
}
}
@@ -157,4 +161,8 @@ bool Bullet::OnUpperLevel(){return upperLevel;}
const bool Bullet::IsDead()const{
return dead;
+}
+
+const float Bullet::GetZ()const{
+ return z;
}
\ No newline at end of file
diff --git a/Adventures in Lestoria/Bullet.h b/Adventures in Lestoria/Bullet.h
index d81a32ad..ae181aed 100644
--- a/Adventures in Lestoria/Bullet.h
+++ b/Adventures in Lestoria/Bullet.h
@@ -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;
};
\ No newline at end of file
diff --git a/Adventures in Lestoria/BulletTypes.h b/Adventures in Lestoria/BulletTypes.h
index c1a14147..dd250ef1 100644
--- a/Adventures in Lestoria/BulletTypes.h
+++ b/Adventures in Lestoria/BulletTypes.h
@@ -145,4 +145,20 @@ struct DaggerSlash:public Bullet{
void Update(float fElapsedTime)override;
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::Animationbomb_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;
};
\ No newline at end of file
diff --git a/Adventures in Lestoria/Goblin_Bomb.cpp b/Adventures in Lestoria/Goblin_Bomb.cpp
new file mode 100644
index 00000000..bb82f85b
--- /dev/null
+++ b/Adventures in Lestoria/Goblin_Bomb.cpp
@@ -0,0 +1,86 @@
+#pragma region License
+/*
+License (OLC-3)
+~~~~~~~~~~~~~~~
+
+Copyright 2024 Joshua Sigona
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+1. Redistributions or derivations of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+
+2. Redistributions or derivative works in binary form must reproduce the above
+copyright notice. This list of conditions and the following disclaimer must be
+reproduced in the documentation and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its contributors may
+be used to endorse or promote products derived from this software without specific
+prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+Portions of this software are copyright © 2024 The FreeType
+Project (www.freetype.org). Please see LICENSE_FT.txt for more information.
+All rights reserved.
+*/
+#pragma endregion
+#include "AdventuresInLestoria.h"
+#include "DEFINES.h"
+#include "Monster.h"
+#include "MonsterStrategyHelpers.h"
+#include "BulletTypes.h"
+#include "util.h"
+
+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(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(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;
+ }
+
+}
\ No newline at end of file
diff --git a/Adventures in Lestoria/Hawk.cpp b/Adventures in Lestoria/Hawk.cpp
new file mode 100644
index 00000000..b64589da
--- /dev/null
+++ b/Adventures in Lestoria/Hawk.cpp
@@ -0,0 +1,52 @@
+#pragma region License
+/*
+License (OLC-3)
+~~~~~~~~~~~~~~~
+
+Copyright 2024 Joshua Sigona
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+1. Redistributions or derivations of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+
+2. Redistributions or derivative works in binary form must reproduce the above
+copyright notice. This list of conditions and the following disclaimer must be
+reproduced in the documentation and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its contributors may
+be used to endorse or promote products derived from this software without specific
+prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+Portions of this software are copyright © 2024 The FreeType
+Project (www.freetype.org). Please see LICENSE_FT.txt for more information.
+All rights reserved.
+*/
+#pragma endregion
+#include "AdventuresInLestoria.h"
+#include "DEFINES.h"
+#include "Monster.h"
+#include "MonsterStrategyHelpers.h"
+#include "BulletTypes.h"
+
+INCLUDE_ANIMATION_DATA
+INCLUDE_BULLET_LIST
+INCLUDE_game
+
+using A=Attribute;
+
+void Monster::STRATEGY::HAWK(Monster&m,float fElapsedTime,std::string strategy){
+
+}
\ No newline at end of file
diff --git a/Adventures in Lestoria/Monster.cpp b/Adventures in Lestoria/Monster.cpp
index 0177b5a1..80a55262 100644
--- a/Adventures in Lestoria/Monster.cpp
+++ b/Adventures in Lestoria/Monster.cpp
@@ -976,4 +976,14 @@ void DeathSpawnInfo::Spawn(const vf2d monsterDeathPos,const bool onUpperLevel){
for(uint8_t i=0;iSpawnMonster(monsterDeathPos+spawnLocOffset,MONSTER_DATA.at(monsterSpawnName),onUpperLevel).iframe_timer=0.25f;
}
+}
+
+void Monster::ProximityKnockback(const vf2d centerPoint,const float knockbackFactor){
+ geom2d::linelineToMonster(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);
}
\ No newline at end of file
diff --git a/Adventures in Lestoria/Monster.h b/Adventures in Lestoria/Monster.h
index 8b9cfcf7..e5872932 100644
--- a/Adventures in Lestoria/Monster.h
+++ b/Adventures in Lestoria/Monster.h
@@ -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.
diff --git a/Adventures in Lestoria/MonsterAttribute.h b/Adventures in Lestoria/MonsterAttribute.h
index 6a9eaa67..094fa116 100644
--- a/Adventures in Lestoria/MonsterAttribute.h
+++ b/Adventures in Lestoria/MonsterAttribute.h
@@ -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.
};
\ No newline at end of file
diff --git a/Adventures in Lestoria/Player.cpp b/Adventures in Lestoria/Player.cpp
index 5e21d23c..a82ff96f 100644
--- a/Adventures in Lestoria/Player.cpp
+++ b/Adventures in Lestoria/Player.cpp
@@ -1543,4 +1543,14 @@ const float Player::GetIframeTime()const{
const Renderable&Player::GetMinimapImage()const{
return minimapImg;
+}
+
+void Player::ProximityKnockback(const vf2d centerPoint,const float knockbackFactor){
+ geom2d::linelineToPlayer(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);
}
\ No newline at end of file
diff --git a/Adventures in Lestoria/Player.h b/Adventures in Lestoria/Player.h
index 1dbc928c..e0a47f16 100644
--- a/Adventures in Lestoria/Player.h
+++ b/Adventures in Lestoria/Player.h
@@ -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);
diff --git a/Adventures in Lestoria/RUN_STRATEGY.cpp b/Adventures in Lestoria/RUN_STRATEGY.cpp
index 6d09bbfd..8185e377 100644
--- a/Adventures in Lestoria/RUN_STRATEGY.cpp
+++ b/Adventures in Lestoria/RUN_STRATEGY.cpp
@@ -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();
}
diff --git a/Adventures in Lestoria/RunAway.cpp b/Adventures in Lestoria/RunAway.cpp
index 041a4513..2395b8ba 100644
--- a/Adventures in Lestoria/RunAway.cpp
+++ b/Adventures in Lestoria/RunAway.cpp
@@ -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,13 +59,13 @@ void Monster::STRATEGY::RUN_AWAY(Monster&m,float fElapsedTime,std::string strate
} else {
m.SetState(State::NORMAL);
}
- } else
- if(line.length()>24.f*ConfigInt("CloseInRange")/100.0f){
- m.target=line.upoint(1.2f);
- m.SetState(State::MOVE_TOWARDS);
- } else {
- m.SetState(State::NORMAL);
- }
+ }else
+ if(line.length()>24.f*ConfigInt("CloseInRange")/100.0f){
+ m.target=line.upoint(1.2f);
+ m.SetState(State::MOVE_TOWARDS);
+ } else {
+ m.SetState(State::NORMAL);
+ }
}
m.canMove=true;
geom2d::line moveTowardsLine=geom2d::line(m.pos,m.target);
@@ -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();
}
- 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();
}
- m.PerformJumpAnimation();
}break;
case State::PATH_AROUND:{
m.PathAroundBehavior(fElapsedTime);
diff --git a/Adventures in Lestoria/RunTowards.cpp b/Adventures in Lestoria/RunTowards.cpp
index 7075847d..3a00fb0f 100644
--- a/Adventures in Lestoria/RunTowards.cpp
+++ b/Adventures in Lestoria/RunTowards.cpp
@@ -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);
diff --git a/Adventures in Lestoria/SpawnEncounterLabel.h b/Adventures in Lestoria/SpawnEncounterLabel.h
index a339f238..96d220e3 100644
--- a/Adventures in Lestoria/SpawnEncounterLabel.h
+++ b/Adventures in Lestoria/SpawnEncounterLabel.h
@@ -87,7 +87,7 @@ protected:
}
float verticalAlignYOffset=(rect.size.y-8)/2;
vf2d monsterNameTextSize=game->GetTextSizeProp(monsterName);
- float textXSpaceAvailable=rect.size.x-imgSize.x-4-16/*12 for the scrollbar*/;
+ float textXSpaceAvailable=rect.size.x-imgSize.x-4-16/*12 for the scrollbar*/;
float textXScaling=textXSpaceAvailable/monsterNameTextSize.x;
window.DrawShadowStringPropDecal(rect.pos+vf2d{imgSize.x+4,verticalAlignYOffset},monsterName,WHITE,BLACK,{std::min(1.f,textXScaling),1});
}
diff --git a/Adventures in Lestoria/Stone_Elemental.cpp b/Adventures in Lestoria/Stone_Elemental.cpp
new file mode 100644
index 00000000..67e78766
--- /dev/null
+++ b/Adventures in Lestoria/Stone_Elemental.cpp
@@ -0,0 +1,52 @@
+#pragma region License
+/*
+License (OLC-3)
+~~~~~~~~~~~~~~~
+
+Copyright 2024 Joshua Sigona
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+1. Redistributions or derivations of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+
+2. Redistributions or derivative works in binary form must reproduce the above
+copyright notice. This list of conditions and the following disclaimer must be
+reproduced in the documentation and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its contributors may
+be used to endorse or promote products derived from this software without specific
+prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+Portions of this software are copyright © 2024 The FreeType
+Project (www.freetype.org). Please see LICENSE_FT.txt for more information.
+All rights reserved.
+*/
+#pragma endregion
+#include "AdventuresInLestoria.h"
+#include "DEFINES.h"
+#include "Monster.h"
+#include "MonsterStrategyHelpers.h"
+#include "BulletTypes.h"
+
+INCLUDE_ANIMATION_DATA
+INCLUDE_BULLET_LIST
+INCLUDE_game
+
+using A=Attribute;
+
+void Monster::STRATEGY::STONE_ELEMENTAL(Monster&m,float fElapsedTime,std::string strategy){
+
+}
\ No newline at end of file
diff --git a/Adventures in Lestoria/Version.h b/Adventures in Lestoria/Version.h
index 9406fb91..d670978a 100644
--- a/Adventures in Lestoria/Version.h
+++ b/Adventures in Lestoria/Version.h
@@ -39,7 +39,7 @@ All rights reserved.
#define VERSION_MAJOR 1
#define VERSION_MINOR 2
#define VERSION_PATCH 0
-#define VERSION_BUILD 9220
+#define VERSION_BUILD 9230
#define stringify(a) stringify_(a)
#define stringify_(a) #a
diff --git a/Adventures in Lestoria/assets/Campaigns/2_1.tmx b/Adventures in Lestoria/assets/Campaigns/2_1.tmx
index 4e0109ef..ddbcf75c 100644
--- a/Adventures in Lestoria/assets/Campaigns/2_1.tmx
+++ b/Adventures in Lestoria/assets/Campaigns/2_1.tmx
@@ -1,5 +1,5 @@
-