diff --git a/Adventures in Lestoria/Adventures in Lestoria.vcxproj b/Adventures in Lestoria/Adventures in Lestoria.vcxproj index cf94dce3..0b369131 100644 --- a/Adventures in Lestoria/Adventures in Lestoria.vcxproj +++ b/Adventures in Lestoria/Adventures in Lestoria.vcxproj @@ -993,6 +993,10 @@ + + + + diff --git a/Adventures in Lestoria/Adventures in Lestoria.vcxproj.filters b/Adventures in Lestoria/Adventures in Lestoria.vcxproj.filters index c9366ff7..41dddc8f 100644 --- a/Adventures in Lestoria/Adventures in Lestoria.vcxproj.filters +++ b/Adventures in Lestoria/Adventures in Lestoria.vcxproj.filters @@ -1121,6 +1121,9 @@ Source Files\Effects + + Source Files\Bullet Types + diff --git a/Adventures in Lestoria/BulletTypes.h b/Adventures in Lestoria/BulletTypes.h index e4f7313c..695be991 100644 --- a/Adventures in Lestoria/BulletTypes.h +++ b/Adventures in Lestoria/BulletTypes.h @@ -38,6 +38,7 @@ All rights reserved. #pragma once #include "Bullet.h" #include "Direction.h" +#include "Effect.h" struct EnergyBolt:public Bullet{ float lastParticleSpawn=0; @@ -245,4 +246,19 @@ private: float moveTimer; //Counts down to 0, when it hits zero sets the velocity to futurevel. const float initialMoveWaitTime; const float knockbackAmt; +}; + +struct FallingStone:public Bullet{ + //The position for this bullet represents where the falling stone should land. + FallingStone(vf2d targetPos,vf2d vel,float zVel,float indicatorDisplayTime,float radius,int damage,bool upperLevel,bool hitsMultiple=false,float knockbackAmt=0.f,float lifetime=INFINITE,bool friendly=false,Pixel col=WHITE,vf2d scale={1,1},float image_angle=0.f,float spellCircleRotation=0.f,float spellCircleRotationSpd=0.f,Pixel insigniaCol=WHITE,float insigniaRotation=0.f,float insigniaRotationSpd=0.f); +protected: + void Update(float fElapsedTime)override; + void Draw(const Pixel blendCol)const override; +private: + const vf2d targetPos; + const float zVel{}; + const float indicatorDisplayTime; + SpellCircle indicator; + const float knockbackAmt; + float lastTrailEffect{}; }; \ No newline at end of file diff --git a/Adventures in Lestoria/Chapter_2_Boss.txt b/Adventures in Lestoria/Chapter_2_Boss.txt index d4b4cf67..4ff8c1e7 100644 --- a/Adventures in Lestoria/Chapter_2_Boss.txt +++ b/Adventures in Lestoria/Chapter_2_Boss.txt @@ -40,7 +40,7 @@ Size: 800% >Like previously every pillar appears with 2,5 seconds delay from each other. (2 sec with an indicator, 0,5 seconds delay after a pillar got created) -The Boss continues with its normal behaviour while the pillars are getting casted. +>The Boss continues with its normal behaviour while the pillars are getting casted. diff --git a/Adventures in Lestoria/Effect.h b/Adventures in Lestoria/Effect.h index 8220d5ed..b4173d8c 100644 --- a/Adventures in Lestoria/Effect.h +++ b/Adventures in Lestoria/Effect.h @@ -50,6 +50,7 @@ enum class EffectType{ struct Effect{ friend class AiL; + friend class FallingStone; vf2d pos={0,0}; float lifetime=0; float fadeout=0; @@ -110,8 +111,8 @@ struct ForegroundEffect:Effect{ }; struct SpellCircle:Effect{ - SpellCircle(vf2d pos,float lifetime,std::string imgFile,std::string spellInsigniaFile,bool upperLevel,float size=1.0f,float fadeout=0.0f,vf2d spd={},Pixel col=WHITE,float rotation=0,float rotationSpd=0,bool additiveBlending=false,float insigniaSize=1.0f,float insigniaFadeout=0.0f,vf2d insigniaSpd={},Pixel insigniaCol=WHITE,float insigniaSotation=0,float insigniaRotationSpd=0,bool insigniaAdditiveBlending=false); - SpellCircle(vf2d pos,float lifetime,std::string imgFile,std::string spellInsigniaFile,bool upperLevel,vf2d size={1,1},float fadeout=0.0f,vf2d spd={},Pixel col=WHITE,float rotation=0,float rotationSpd=0,bool additiveBlending=false,vf2d insigniaSize={1,1},float insigniaFadeout=0.0f,vf2d insigniaSpd={},Pixel insigniaCol=WHITE,float insigniaSotation=0,float insigniaRotationSpd=0,bool insigniaAdditiveBlending=false); + SpellCircle(vf2d pos,float lifetime,std::string imgFile,std::string spellInsigniaFile,bool upperLevel,float size=1.0f,float fadeout=0.0f,vf2d spd={},Pixel col=WHITE,float rotation=0,float rotationSpd=0,bool additiveBlending=false,float insigniaSize=1.0f,float insigniaFadeout=0.0f,vf2d insigniaSpd={},Pixel insigniaCol=WHITE,float insigniaRotation=0,float insigniaRotationSpd=0,bool insigniaAdditiveBlending=false); + SpellCircle(vf2d pos,float lifetime,std::string imgFile,std::string spellInsigniaFile,bool upperLevel,vf2d size={1,1},float fadeout=0.0f,vf2d spd={},Pixel col=WHITE,float rotation=0,float rotationSpd=0,bool additiveBlending=false,vf2d insigniaSize={1,1},float insigniaFadeout=0.0f,vf2d insigniaSpd={},Pixel insigniaCol=WHITE,float insigniaRotation=0,float insigniaRotationSpd=0,bool insigniaAdditiveBlending=false); Effect spellInsignia{vf2d{},0.f,"spell_insignia.png",false,{}}; virtual bool Update(float fElapsedTime)override final; virtual void Draw()const override final; diff --git a/Adventures in Lestoria/FallingStone.cpp b/Adventures in Lestoria/FallingStone.cpp new file mode 100644 index 00000000..f68eaaff --- /dev/null +++ b/Adventures in Lestoria/FallingStone.cpp @@ -0,0 +1,90 @@ +#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 "DEFINES.h" +#include "AdventuresInLestoria.h" +#include "util.h" +#include +#include "SoundEffect.h" + +INCLUDE_game + +FallingStone::FallingStone(vf2d targetPos,vf2d vel,float zVel,float indicatorDisplayTime,float radius,int damage,bool upperLevel,bool hitsMultiple,float knockbackAmt,float lifetime,bool friendly,Pixel col,vf2d scale,float image_angle,float spellCircleRotation,float spellCircleRotationSpd,Pixel insigniaCol,float insigniaRotation,float insigniaRotationSpd) +:Bullet(targetPos,vel,radius,damage,"rock.png",upperLevel,false,lifetime+0.1f,false,friendly,col,scale,image_angle),targetPos(targetPos),zVel(zVel),indicatorDisplayTime(indicatorDisplayTime),knockbackAmt(knockbackAmt), +indicator(targetPos,lifetime+0.1f,"range_indicator.png","spell_insignia.png",upperLevel,radius/12.f,0.5f,{},col,spellCircleRotation,spellCircleRotationSpd,false,radius/12.f,0.f,{},insigniaCol,insigniaRotation,insigniaRotationSpd,false){ + pos+=-vel*lifetime; + z=-zVel*lifetime; +} + +void FallingStone::Update(float fElapsedTime){ + z+=zVel*fElapsedTime; + lastTrailEffect-=fElapsedTime; + if(z<=0.f){ + z=0.f; + vel={}; + if(IsActivated()){ + fadeOutTime=0.5f; + SoundEffect::PlaySFX("Stone Land",pos); + if(friendly){ + for(auto&[monsterPtr,hurt]:game->Hurt(targetPos,radius,damage,OnUpperLevel(),z,HurtType::MONSTER)){ + if(hurt)std::get(monsterPtr)->ApplyIframes(0.1f); + } + } + else{ + for(auto&[playerPtr,hurt]:game->Hurt(targetPos,radius,damage,OnUpperLevel(),z,HurtType::PLAYER)){ + if(hurt)std::get(playerPtr)->ApplyIframes(0.1f); + } + } + game->ProximityKnockback(targetPos,radius,knockbackAmt,HurtType::PLAYER|HurtType::MONSTER); + for(int i:std::ranges::iota_view(0,30))game->AddEffect(std::make_unique(pos-vf2d{0.f,GetZ()},util::random_range(0.05f,0.2f),"circle_outline.png",OnUpperLevel(),util::random_range(0.5f,1.f),0.2f,vf2d{util::random_range(-10.f,10.f),util::random_range(-3.f,0.f)},PixelLerp(BLACK,col,util::random(1.f)),0.f,0.f,true)); + Deactivate(); + } + }else{ + if(lastTrailEffect<=0.f){ + game->AddEffect(std::make_unique(pos-vf2d{0.f,GetZ()},util::random_range(0.05f,0.2f),"circle_outline.png",OnUpperLevel(),util::random_range(0.5f,1.f),0.2f,vf2d{util::random_range(-3.f,3.f),util::random_range(-3.f,3.f)},PixelLerp(BLACK,col,util::random(1.f)),0.f,0.f,true)); + } + } + indicator.Update(fElapsedTime); +} +void FallingStone::Draw(const Pixel blendCol)const{ + if(lifetime<=indicatorDisplayTime){ + indicator.Draw(); + } + Bullet::Draw(blendCol); +} \ No newline at end of file diff --git a/Adventures in Lestoria/MonsterAttribute.h b/Adventures in Lestoria/MonsterAttribute.h index a366b8e1..830353db 100644 --- a/Adventures in Lestoria/MonsterAttribute.h +++ b/Adventures in Lestoria/MonsterAttribute.h @@ -140,7 +140,6 @@ enum class Attribute{ SAFE_AREA_WAIT_TIMER, PREVIOUS_MONSTER_COUNT, CHASE_TIMER, - STONE_RAIN_COUNT, STONE_TOSS_COUNT, STONE_TOSS_TIMER, }; \ No newline at end of file diff --git a/Adventures in Lestoria/StoneGolem.cpp b/Adventures in Lestoria/StoneGolem.cpp index 82565f2c..06d7a9bd 100644 --- a/Adventures in Lestoria/StoneGolem.cpp +++ b/Adventures in Lestoria/StoneGolem.cpp @@ -45,6 +45,7 @@ All rights reserved. #include "SoundEffect.h" #include "StageMaskPolygon.h" #include "ExpandingRing.h" +#include INCLUDE_game INCLUDE_MONSTER_LIST @@ -323,11 +324,21 @@ void Monster::STRATEGY::STONE_GOLEM(Monster&m,float fElapsedTime,std::string str game->AddEffect(std::make_unique(m.GetPos()+vf2d{util::random_range(throwPos.GetReal(0),throwPos.GetReal(2)),util::random_range(throwPos.GetReal(1),throwPos.GetReal(3))},10.f,"rock.png",ConfigFloat("Stone Rain.Stone Toss Delay"),ConfigFloat("Stone Rain.Stone Toss Rock Size Mult"),0.1f,vf2d{0.f,-ConfigFloat("Stone Rain.Stone Toss Throw Speed")},WHITE,util::random(2*PI),0.f)); if(m.I(A::STONE_TOSS_COUNT)<=0){ - m.I(A::STONE_RAIN_COUNT)=ConfigInt("Stone Rain.Stone Count"); m.phase=STONE_RAIN; + m.F(A::BREAK_TIME)=ConfigFloat("Stone Rain.Stone Golem Wait Time"); m.PerformAnimation("CAST"); + + for(int i:std::ranges::iota_view(0,ConfigInt("Stone Rain.Stone Count"))){ + CreateBullet(FallingStone)(game->camera.GetViewPosition()+vf2d{util::random(game->ScreenWidth()),util::random(game->ScreenHeight())},ConfigVec("Stone Rain.Stone Vel"),ConfigFloatArr("Stone Rain.Stone Vel",2),ConfigFloat("Stone Rain.Indicator Time"),ConfigPixels("Stone Rain.Stone Radius"),ConfigInt("Stone Rain.Stone Damage"),m.OnUpperLevel(),false,ConfigFloat("Stone Rain.Stone Knockback Amt"),util::random_range(ConfigFloatArr("Stone Rain.Stone Fall Delay",0),ConfigFloatArr("Stone Rain.Stone Fall Delay",1)),false,ConfigPixel("Stone Rain.Stone Spell Circle Color"),vf2d{ConfigFloat("Stone Rain.Stone Radius")/100.f*2.f,ConfigFloat("Stone Rain.Stone Radius")/100.f*2.f},util::random(2*PI),util::random(2*PI),util::degToRad(ConfigFloat("Stone Rain.Stone Spell Circle Rotation Spd")),ConfigPixel("Stone Rain.Stone Spell Insignia Color"),util::random(2*PI),util::degToRad(ConfigFloat("Stone Rain.Stone Spell Insignia Rotation Spd")))EndBullet; + } } } }break; + case STONE_RAIN:{ + m.F(A::BREAK_TIME)-=fElapsedTime; + if(m.F(A::BREAK_TIME)<=0.f){ + m.phase=STANDARD; + } + }break; } } \ No newline at end of file diff --git a/Adventures in Lestoria/Version.h b/Adventures in Lestoria/Version.h index 04c774a6..849704a0 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 3 -#define VERSION_BUILD 9994 +#define VERSION_BUILD 10015 #define stringify(a) stringify_(a) #define stringify_(a) #a diff --git a/Adventures in Lestoria/assets/config/MonsterStrategies.txt b/Adventures in Lestoria/assets/config/MonsterStrategies.txt index 64af6fa8..2f7da5d4 100644 --- a/Adventures in Lestoria/assets/config/MonsterStrategies.txt +++ b/Adventures in Lestoria/assets/config/MonsterStrategies.txt @@ -970,6 +970,9 @@ MonsterStrategy } Stone Rain { + # How long to wait upon launching the stone rain attack before resuming normal AI. + Stone Golem Wait Time = 4.0s + # How many stones the boss throws in the air. Initial Stone Toss Count = 2 # Provide a Min X, Min Y, Max X, Max Y relative to the boss' position for where the stones appear prior to being tossed. @@ -986,8 +989,18 @@ MonsterStrategy Stone Fall Delay = 2.5s, 4.0s # How long the indicator will appear before the rock drops down. Indicator Time = 1s + # Provide an X,Y,Z falling velocity + Stone Vel = -40.0, 0.0, -250.0 Stone Damage = 30 Stone Radius = 50 + Stone Knockback Amt = 150 + + Stone Spell Circle Color = 255, 40, 40, 160 + Stone Spell Insignia Color = 72, 66, 80, 255 + # Degrees/sec. Positive is CW, Negative is CCW. + Stone Spell Circle Rotation Spd = -30 + # Degrees/sec. Positive is CW, Negative is CCW. + Stone Spell Insignia Rotation Spd = 50 } } Breaking Pillar diff --git a/Adventures in Lestoria/assets/config/audio/events.txt b/Adventures in Lestoria/assets/config/audio/events.txt index d2bad7dd..7899e219 100644 --- a/Adventures in Lestoria/assets/config/audio/events.txt +++ b/Adventures in Lestoria/assets/config/audio/events.txt @@ -270,6 +270,12 @@ Events File[1] = slime_walk2.ogg, 10% File[2] = slime_walk3.ogg, 10% } + Stone Land + { + CombatSound = True + # Specify file names, followed by volume %. Optional min and max pitch adjustment (Defaults are 90%,110%) + File[0] = rockland.ogg, 40% + } Toggle On { # Specify file names, followed by volume %. Optional min and max pitch adjustment (Defaults are 90%,110%) diff --git a/Adventures in Lestoria/assets/sounds/rockland.ogg b/Adventures in Lestoria/assets/sounds/rockland.ogg new file mode 100644 index 00000000..d3ed5237 Binary files /dev/null and b/Adventures in Lestoria/assets/sounds/rockland.ogg differ diff --git a/Adventures in Lestoria/olcUTIL_Animate2D.h b/Adventures in Lestoria/olcUTIL_Animate2D.h index 14498445..de8bbb49 100644 --- a/Adventures in Lestoria/olcUTIL_Animate2D.h +++ b/Adventures in Lestoria/olcUTIL_Animate2D.h @@ -147,14 +147,17 @@ namespace olc::utils::Animate2D { case Style::Repeat: case Style::OneShot: - case Style::ReverseOneShot: + case Style::ReverseOneShot:{ return m_vFrames.size()*m_fFrameDuration; + }break; case Style::PingPong: - case Style::Reverse: //These two require twice as much time (minus one frame) to complete a full animation cycle. + case Style::Reverse:{ //These two require twice as much time (minus one frame) to complete a full animation cycle. return m_vFrames.size()*m_fFrameDuration*2.f-m_fFrameDuration; - default: + }break; + default:{ ERR(std::format("WARNING! Animation style {} was not found! THIS SHOULD NOT BE HAPPENING!",int(m_nStyle))); return 0.f; + } } } @@ -163,14 +166,17 @@ namespace olc::utils::Animate2D { case Style::Repeat: case Style::OneShot: - case Style::ReverseOneShot: + case Style::ReverseOneShot:{ return m_vFrames.size(); + }break; case Style::PingPong: - case Style::Reverse: //These two require twice as much time (minus one frame) to complete a full animation cycle. + case Style::Reverse:{ //These two require twice as much time (minus one frame) to complete a full animation cycle. return m_vFrames.size()*2.f-1; - default: + }break; + default:{ ERR(std::format("WARNING! Animation style {} was not found! THIS SHOULD NOT BE HAPPENING!",int(m_nStyle))); return 0; + } } } @@ -180,18 +186,22 @@ namespace olc::utils::Animate2D { switch (m_nStyle) { - case Style::Repeat: + case Style::Repeat:{ return size_t(fTime * m_fFrameRate) % m_vFrames.size(); - case Style::OneShot: + }break; + case Style::OneShot:{ return std::clamp(size_t(fTime * m_fFrameRate), size_t(0), m_vFrames.size() - 1); + }break; case Style::PingPong:{ size_t frame=size_t(m_fFrameRate*fTime) % (m_vFrames.size()*size_t(2)-size_t(1)); return frame>=m_vFrames.size()?m_vFrames.size()-frame%m_vFrames.size()-1:frame; }break; - case Style::ReverseOneShot: + case Style::ReverseOneShot:{ return std::clamp((m_vFrames.size() - 1) - size_t(fTime * m_fFrameRate), size_t(0), m_vFrames.size() - 1); - case Style::Reverse: + }break; + case Style::Reverse:{ return (m_vFrames.size() - 1) - (size_t(fTime * m_fFrameRate) % m_vFrames.size()); + }break; } return 0; diff --git a/x64/Release/Adventures in Lestoria.exe b/x64/Release/Adventures in Lestoria.exe index b428b232..73561f59 100644 Binary files a/x64/Release/Adventures in Lestoria.exe and b/x64/Release/Adventures in Lestoria.exe differ