Add stone rain attack to second chapter boss. Second Chapter boss AI routine completed. Release Build 10015.

mac-build
sigonasr2 4 months ago
parent 001d5e1c79
commit 7bb265e82a
  1. 4
      Adventures in Lestoria/Adventures in Lestoria.vcxproj
  2. 3
      Adventures in Lestoria/Adventures in Lestoria.vcxproj.filters
  3. 16
      Adventures in Lestoria/BulletTypes.h
  4. 2
      Adventures in Lestoria/Chapter_2_Boss.txt
  5. 5
      Adventures in Lestoria/Effect.h
  6. 90
      Adventures in Lestoria/FallingStone.cpp
  7. 1
      Adventures in Lestoria/MonsterAttribute.h
  8. 13
      Adventures in Lestoria/StoneGolem.cpp
  9. 2
      Adventures in Lestoria/Version.h
  10. 13
      Adventures in Lestoria/assets/config/MonsterStrategies.txt
  11. 6
      Adventures in Lestoria/assets/config/audio/events.txt
  12. BIN
      Adventures in Lestoria/assets/sounds/rockland.ogg
  13. 30
      Adventures in Lestoria/olcUTIL_Animate2D.h
  14. BIN
      x64/Release/Adventures in Lestoria.exe

@ -993,6 +993,10 @@
<SubType>
</SubType>
</ClCompile>
<ClCompile Include="FallingStone.cpp">
<SubType>
</SubType>
</ClCompile>
<ClCompile Include="SpellCircle.cpp">
<SubType>
</SubType>

@ -1121,6 +1121,9 @@
<ClCompile Include="RockLaunch.cpp">
<Filter>Source Files\Effects</Filter>
</ClCompile>
<ClCompile Include="FallingStone.cpp">
<Filter>Source Files\Bullet Types</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="cpp.hint" />

@ -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;
@ -246,3 +247,18 @@ private:
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{};
};

@ -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.

@ -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;

@ -0,0 +1,90 @@
#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 "DEFINES.h"
#include "AdventuresInLestoria.h"
#include "util.h"
#include <ranges>
#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<Monster*>(monsterPtr)->ApplyIframes(0.1f);
}
}
else{
for(auto&[playerPtr,hurt]:game->Hurt(targetPos,radius,damage,OnUpperLevel(),z,HurtType::PLAYER)){
if(hurt)std::get<Player*>(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<Effect>(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<Effect>(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);
}

@ -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,
};

@ -45,6 +45,7 @@ All rights reserved.
#include "SoundEffect.h"
#include "StageMaskPolygon.h"
#include "ExpandingRing.h"
#include <ranges>
INCLUDE_game
INCLUDE_MONSTER_LIST
@ -323,10 +324,20 @@ void Monster::STRATEGY::STONE_GOLEM(Monster&m,float fElapsedTime,std::string str
game->AddEffect(std::make_unique<RockLaunch>(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;
}

@ -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

@ -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

@ -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%)

@ -147,32 +147,38 @@ 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;
}
}
}
inline const size_t GetFrameCountBasedOnAnimationStyle()const{
switch (m_nStyle)
{
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;
}
}
}
private:
@ -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;

Loading…
Cancel
Save