Implemented Trail of Fire enchant, added Trail of Fire effect. Fix effects not having their type set with the new Effect constructor arrangement. Adjusted Trail of Fire damage potency from 10% to 30% per tick. Release Build 11309.

pull/65/head
sigonasr2 3 months ago
parent 901f2e38bc
commit 6fbb8a8ed1
  1. 13
      Adventures in Lestoria Tests/EnchantTests.cpp
  2. 12
      Adventures in Lestoria/AdventuresInLestoria.cpp
  3. 17
      Adventures in Lestoria/Effect.cpp
  4. 16
      Adventures in Lestoria/Effect.h
  5. 4
      Adventures in Lestoria/FadeInOutEffect.cpp
  6. 2
      Adventures in Lestoria/FallingStone.cpp
  7. 7
      Adventures in Lestoria/FireBolt.cpp
  8. 10
      Adventures in Lestoria/ForegroundEffect.cpp
  9. 2
      Adventures in Lestoria/Meteor.cpp
  10. 4
      Adventures in Lestoria/MonsterSoul.cpp
  11. 8
      Adventures in Lestoria/Oscillator.h
  12. 2
      Adventures in Lestoria/PulsatingFire.cpp
  13. 8
      Adventures in Lestoria/SoundEffect.cpp
  14. 6
      Adventures in Lestoria/SoundEffect.h
  15. 6
      Adventures in Lestoria/SpellCircle.cpp
  16. 57
      Adventures in Lestoria/TrailEffect.h
  17. 2
      Adventures in Lestoria/Version.h
  18. BIN
      Adventures in Lestoria/assets/FlamesTexture.png
  19. 5
      Adventures in Lestoria/assets/config/audio/events.txt
  20. 5
      Adventures in Lestoria/assets/config/items/ItemEnchants.txt
  21. BIN
      Adventures in Lestoria/assets/gamepack.pak
  22. BIN
      Adventures in Lestoria/assets/sounds/burn.ogg
  23. BIN
      x64/Release/Adventures in Lestoria.exe

@ -1225,5 +1225,18 @@ namespace EnchantTests
Game::Update(0.f); Game::Update(0.f);
Assert::AreEqual(size_t(1),game->GetBackgroundEffects().size(),L"There should be a background effect (i.e. the Black Hole)."); Assert::AreEqual(size_t(1),game->GetBackgroundEffects().size(),L"There should be a background effect (i.e. the Black Hole).");
} }
TEST_METHOD(FireBoltNoEnchantCheck){
Game::ChangeClass(player,WIZARD);
player->CheckAndPerformAbility(player->GetAbility1(),testKeyboardInput);
Game::Update(0.5f);
Assert::AreEqual(size_t(0),game->GetEffect(EffectType::TRAIL_OF_FIRE).size(),L"Trail of Fire should not be generated.");
}
TEST_METHOD(FireBoltEnchantCheck){
Game::ChangeClass(player,WIZARD);
Game::GiveAndEquipEnchantedRing("Trail of Fire");
player->CheckAndPerformAbility(player->GetAbility1(),testKeyboardInput);
Game::Update(0.5f);
Assert::AreEqual(size_t(1),game->GetEffect(EffectType::TRAIL_OF_FIRE).size(),L"Trail of Fire should be generated with the enchant.");
}
}; };
} }

@ -1425,7 +1425,7 @@ void AiL::RenderWorld(float fElapsedTime){
auto it=backgroundEffectsLower.begin(); auto it=backgroundEffectsLower.begin();
while(it!=backgroundEffectsLower.end()){ while(it!=backgroundEffectsLower.end()){
const Effect&e=**it; const Effect&e=**it;
e.Draw(); e._Draw();
++it; ++it;
} }
} }
@ -1566,7 +1566,7 @@ void AiL::RenderWorld(float fElapsedTime){
++monstersBeforeLowerIt; ++monstersBeforeLowerIt;
} }
for(const Effect*const e:backgroundEffectsLower){ for(const Effect*const e:backgroundEffectsLower){
e->Draw(); e->_Draw();
} }
while(dropsBeforeLowerIt!=dropsBeforeLower.end()){ while(dropsBeforeLowerIt!=dropsBeforeLower.end()){
const int dropInd=*dropsBeforeLowerIt; const int dropInd=*dropsBeforeLowerIt;
@ -1595,7 +1595,7 @@ void AiL::RenderWorld(float fElapsedTime){
b->_Draw(); b->_Draw();
} }
for(const Effect*const e:foregroundEffectsLower){ for(const Effect*const e:foregroundEffectsLower){
e->Draw(); e->_Draw();
} }
#pragma endregion #pragma endregion
#pragma region Permanent Foreground Rendering #pragma region Permanent Foreground Rendering
@ -1718,7 +1718,7 @@ void AiL::RenderWorld(float fElapsedTime){
auto it=backgroundEffectsUpper.begin(); auto it=backgroundEffectsUpper.begin();
while(it!=backgroundEffectsUpper.end()){ while(it!=backgroundEffectsUpper.end()){
const Effect&e=**it; const Effect&e=**it;
e.Draw(); e._Draw();
++it; ++it;
} }
} }
@ -1867,7 +1867,7 @@ void AiL::RenderWorld(float fElapsedTime){
++monstersBeforeUpperIt; ++monstersBeforeUpperIt;
} }
for(const Effect*const e:backgroundEffectsUpper){ for(const Effect*const e:backgroundEffectsUpper){
e->Draw(); e->_Draw();
} }
while(dropsBeforeUpperIt!=dropsBeforeUpper.end()){ while(dropsBeforeUpperIt!=dropsBeforeUpper.end()){
const int dropInd=*dropsBeforeUpperIt; const int dropInd=*dropsBeforeUpperIt;
@ -1896,7 +1896,7 @@ void AiL::RenderWorld(float fElapsedTime){
b->_Draw(); b->_Draw();
} }
for(const Effect*const e:foregroundEffectsUpper){ for(const Effect*const e:foregroundEffectsUpper){
e->Draw(); e->_Draw();
} }
#pragma endregion #pragma endregion
#pragma region Permanent Upper Foreground Rendering #pragma region Permanent Upper Foreground Rendering

@ -54,7 +54,7 @@ Effect::Effect(vf2d pos,float lifetime,const std::string&imgFile,bool upperLevel
:Effect(pos,lifetime,imgFile,upperLevel,fadein,fadeout,size,spd,EffectType::NONE,col,rotation,rotationSpd,additiveBlending){} :Effect(pos,lifetime,imgFile,upperLevel,fadein,fadeout,size,spd,EffectType::NONE,col,rotation,rotationSpd,additiveBlending){}
Effect::Effect(vf2d pos,float lifetime,const std::string&imgFile,bool upperLevel,float fadein,float fadeout,vf2d size,vf2d spd,EffectType type,Pixel col,float rotation,float rotationSpd,bool additiveBlending) Effect::Effect(vf2d pos,float lifetime,const std::string&imgFile,bool upperLevel,float fadein,float fadeout,vf2d size,vf2d spd,EffectType type,Pixel col,float rotation,float rotationSpd,bool additiveBlending)
:pos(pos),lifetime(lifetime),upperLevel(upperLevel),size(size),fadein(fadein),original_fadeInTime(fadein),fadeout(fadeout),original_fadeOutTime(fadeout),spd(spd),col(col),rotation(rotation),rotationSpd(rotationSpd),additiveBlending(additiveBlending){ :pos(pos),lifetime(lifetime),upperLevel(upperLevel),size(size),fadein(fadein),original_fadeInTime(fadein),fadeout(fadeout),original_fadeOutTime(fadeout),spd(spd),col(col),rotation(rotation),rotationSpd(rotationSpd),additiveBlending(additiveBlending),type(type){
this->animation.AddState(imgFile,ANIMATION_DATA.at(imgFile)); this->animation.AddState(imgFile,ANIMATION_DATA.at(imgFile));
this->animation.ChangeState(internal_animState,imgFile); this->animation.ChangeState(internal_animState,imgFile);
} }
@ -80,7 +80,7 @@ bool Effect::Update(float fElapsedTime){
return true; return true;
} }
void Effect::Draw()const{ void Effect::_Draw()const{
if(additiveBlending)game->SetDecalMode(DecalMode::ADDITIVE); if(additiveBlending)game->SetDecalMode(DecalMode::ADDITIVE);
const bool FadeInFinished{original_fadeInTime==0||fadein==original_fadeInTime}; const bool FadeInFinished{original_fadeInTime==0||fadein==original_fadeInTime};
const bool HasFadeout{fadeout>0}; const bool HasFadeout{fadeout>0};
@ -90,17 +90,22 @@ void Effect::Draw()const{
game->view.DrawDecal(pos-vf2d{3,3}*shadowScale/2+vf2d{0,12*size.y},GFX["circle.png"].Decal(),shadowScale,BLACK); game->view.DrawDecal(pos-vf2d{3,3}*shadowScale/2+vf2d{0,12*size.y},GFX["circle.png"].Decal(),shadowScale,BLACK);
} }
Pixel blendCol{col};
[[unlikely]]if(!FadeInFinished){ [[unlikely]]if(!FadeInFinished){
game->view.DrawPartialRotatedDecal(pos-vf2d{0,GetZ()},GetFrame().GetSourceImage()->Decal(),rotation,GetFrame().GetSourceRect().size/2,GetFrame().GetSourceRect().pos,GetFrame().GetSourceRect().size,size,{col.r,col.g,col.b,uint8_t(fadein/original_fadeInTime*col.a)}); blendCol={col.r,col.g,col.b,uint8_t(fadein/original_fadeInTime*col.a)};
}else }else
[[likely]]if(HasFadeout){ [[likely]]if(HasFadeout){
game->view.DrawPartialRotatedDecal(pos-vf2d{0,GetZ()},GetFrame().GetSourceImage()->Decal(),rotation,GetFrame().GetSourceRect().size/2,GetFrame().GetSourceRect().pos,GetFrame().GetSourceRect().size,size,{col.r,col.g,col.b,uint8_t(fadeout/original_fadeOutTime*col.a)}); blendCol={col.r,col.g,col.b,uint8_t(fadeout/original_fadeOutTime*col.a)};
}else{
game->view.DrawPartialRotatedDecal(pos-vf2d{0,GetZ()},GetFrame().GetSourceImage()->Decal(),rotation,GetFrame().GetSourceRect().size/2,GetFrame().GetSourceRect().pos,GetFrame().GetSourceRect().size,size,col);
} }
Draw(blendCol);
game->SetDecalMode(DecalMode::NORMAL); game->SetDecalMode(DecalMode::NORMAL);
} }
void Effect::Draw(const Pixel blendCol)const{
game->view.DrawPartialRotatedDecal(pos-vf2d{0,GetZ()},GetFrame().GetSourceImage()->Decal(),rotation,GetFrame().GetSourceRect().size/2,GetFrame().GetSourceRect().pos,GetFrame().GetSourceRect().size,size,blendCol);
}
Animate2D::Frame Effect::GetFrame()const{ Animate2D::Frame Effect::GetFrame()const{
return animation.GetFrame(internal_animState); return animation.GetFrame(internal_animState);
} }

@ -50,6 +50,7 @@ enum class EffectType{
SPELL_CIRCLE, SPELL_CIRCLE,
MONSTER_SOUL, MONSTER_SOUL,
BLINK_PORTAL, BLINK_PORTAL,
TRAIL_OF_FIRE,
}; };
struct Effect{ struct Effect{
@ -76,7 +77,8 @@ public:
Effect(vf2d pos,float lifetime,const std::string&imgFile,bool upperLevel,float fadein,float fadeout,vf2d size,vf2d spd,EffectType type,Pixel col=WHITE,float rotation=0,float rotationSpd=0,bool additiveBlending=false); Effect(vf2d pos,float lifetime,const std::string&imgFile,bool upperLevel,float fadein,float fadeout,vf2d size,vf2d spd,EffectType type,Pixel col=WHITE,float rotation=0,float rotationSpd=0,bool additiveBlending=false);
virtual bool Update(float fElapsedTime); virtual bool Update(float fElapsedTime);
Animate2D::Frame GetFrame()const; Animate2D::Frame GetFrame()const;
virtual void Draw()const; void _Draw()const;
virtual void Draw(const Pixel blendCol)const;
bool OnUpperLevel(); bool OnUpperLevel();
const EffectType GetType()const; const EffectType GetType()const;
const float GetZ()const; const float GetZ()const;
@ -98,7 +100,7 @@ struct Meteor:Effect{
float startLifetime=0; float startLifetime=0;
bool shakeField=false; bool shakeField=false;
bool Update(float fElapsedTime)override; bool Update(float fElapsedTime)override;
void Draw()const override; void Draw(const Pixel blendCol)const override;
}; };
struct PulsatingFire:Effect{ struct PulsatingFire:Effect{
@ -107,7 +109,7 @@ struct PulsatingFire:Effect{
float lastParticleTimer=0; float lastParticleTimer=0;
float lastDamageTimer=0; float lastDamageTimer=0;
bool Update(float fElapsedTime)override; bool Update(float fElapsedTime)override;
void Draw()const override; void Draw(const Pixel blendCol)const override;
}; };
struct SwordSlash:Effect{ struct SwordSlash:Effect{
@ -123,7 +125,7 @@ private:
struct ForegroundEffect:Effect{ struct ForegroundEffect:Effect{
ForegroundEffect(vf2d pos,float lifetime,std::string imgFile,bool upperLevel,float size=1.0f,float fadeout=0.0f,vf2d spd={},Pixel col=WHITE,float rotation=0,float rotationSpd=0,bool additiveBlending=false); ForegroundEffect(vf2d pos,float lifetime,std::string imgFile,bool upperLevel,float size=1.0f,float fadeout=0.0f,vf2d spd={},Pixel col=WHITE,float rotation=0,float rotationSpd=0,bool additiveBlending=false);
ForegroundEffect(vf2d pos,float lifetime,std::string imgFile,bool upperLevel,vf2d size={1,1},float fadeout=0.0f,vf2d spd={},Pixel col=WHITE,float rotation=0,float rotationSpd=0,bool additiveBlending=false); ForegroundEffect(vf2d pos,float lifetime,std::string imgFile,bool upperLevel,vf2d size={1,1},float fadeout=0.0f,vf2d spd={},Pixel col=WHITE,float rotation=0,float rotationSpd=0,bool additiveBlending=false);
virtual void Draw()const override final; virtual void Draw(const Pixel blendCol)const override final;
}; };
struct SpellCircle:Effect{ struct SpellCircle:Effect{
@ -131,7 +133,7 @@ struct SpellCircle:Effect{
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); 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,{}}; Effect spellInsignia{vf2d{},0.f,"spell_insignia.png",false,{}};
virtual bool Update(float fElapsedTime)override final; virtual bool Update(float fElapsedTime)override final;
virtual void Draw()const override final; virtual void Draw(const Pixel blendCol)const override final;
}; };
struct RockLaunch:Effect{ struct RockLaunch:Effect{
@ -156,7 +158,7 @@ private:
struct MonsterSoul:Effect{ struct MonsterSoul:Effect{
MonsterSoul(vf2d pos,float fadeoutTime,float size,vf2d spd,Pixel col,float rotation,float rotationSpd,bool additiveBlending=false); MonsterSoul(vf2d pos,float fadeoutTime,float size,vf2d spd,Pixel col,float rotation,float rotationSpd,bool additiveBlending=false);
virtual bool Update(float fElapsedTime)override final; virtual bool Update(float fElapsedTime)override final;
virtual void Draw()const override final; virtual void Draw(const Pixel blendCol)const override final;
public: public:
enum Phase{ enum Phase{
RISING, RISING,
@ -175,7 +177,7 @@ struct FadeInOutEffect:Effect{
//A version with oscillators for position and colors, for extra animation effects! //A version with oscillators for position and colors, for extra animation effects!
FadeInOutEffect(Oscillator<vf2d>pos,const std::string&img,float lifetime,bool onUpperLevel,Oscillator<vf2d>size,vf2d spd,Oscillator<Pixel>col,float rotation,float rotationSpd,bool additiveBlending=false,float particleSpawnFreq=0.f,const std::function<Effect(const Effect&self)>&particleGenerator={}); FadeInOutEffect(Oscillator<vf2d>pos,const std::string&img,float lifetime,bool onUpperLevel,Oscillator<vf2d>size,vf2d spd,Oscillator<Pixel>col,float rotation,float rotationSpd,bool additiveBlending=false,float particleSpawnFreq=0.f,const std::function<Effect(const Effect&self)>&particleGenerator={});
virtual bool Update(float fElapsedTime)override; virtual bool Update(float fElapsedTime)override;
virtual void Draw()const override; virtual void Draw(const Pixel blendCol)const override;
std::function<Effect(const Effect&self)>particleGenerator; std::function<Effect(const Effect&self)>particleGenerator;
const float particleSpawnFreq; const float particleSpawnFreq;
Oscillator<vf2d>posOscillator; Oscillator<vf2d>posOscillator;

@ -60,6 +60,6 @@ bool FadeInOutEffect::Update(float fElapsedTime){
col=colOscillator.Update(fElapsedTime); col=colOscillator.Update(fElapsedTime);
return Effect::Update(fElapsedTime); return Effect::Update(fElapsedTime);
} }
void FadeInOutEffect::Draw()const{ void FadeInOutEffect::Draw(const Pixel blendCol)const{
Effect::Draw(); Effect::Draw(blendCol);
} }

@ -84,7 +84,7 @@ void FallingStone::Update(float fElapsedTime){
} }
void FallingStone::Draw(const Pixel blendCol)const{ void FallingStone::Draw(const Pixel blendCol)const{
if(lifetime<=indicatorDisplayTime){ if(lifetime<=indicatorDisplayTime){
indicator.Draw(); indicator._Draw();
} }
Bullet::Draw(blendCol); Bullet::Draw(blendCol);
} }

@ -41,13 +41,16 @@ All rights reserved.
#include "DEFINES.h" #include "DEFINES.h"
#include "util.h" #include "util.h"
#include "SoundEffect.h" #include "SoundEffect.h"
#include "TrailEffect.h"
INCLUDE_game INCLUDE_game
INCLUDE_MONSTER_LIST INCLUDE_MONSTER_LIST
FireBolt::FireBolt(vf2d pos,vf2d vel,float radius,int damage,bool upperLevel,bool friendly,Pixel col) FireBolt::FireBolt(vf2d pos,vf2d vel,float radius,int damage,bool upperLevel,bool friendly,Pixel col)
:Bullet(pos,vel,radius,damage, :Bullet(pos,vel,radius,damage,
"energy_bolt.png",upperLevel,false,INFINITE,true,friendly,col){} "energy_bolt.png",upperLevel,false,INFINITE,true,friendly,col){
if(game->GetPlayer()->HasEnchant("Trail of Fire"))flameTrail=dynamic_cast<TrailEffect&>(game->AddEffect(std::make_unique<TrailEffect>(pos,"Trail of Fire"_ENC["TRAIL DURATION"],"FlamesTexture.png","Trail of Fire"_ENC["TRAIL DAMAGE"]/100.f*game->GetPlayer()->GetAttack(),"Trail of Fire"_ENC["TRAIL TICK FREQUENCY"],upperLevel,1.f,vf2d{1.f,2.f},30000.f,Oscillator<Pixel>{{255,0,0,128},Pixel(0xE74F30),2.f},EffectType::TRAIL_OF_FIRE,true),true));
}
void FireBolt::Update(float fElapsedTime){ void FireBolt::Update(float fElapsedTime){
lastParticleSpawn=std::max(0.f,lastParticleSpawn-fElapsedTime); lastParticleSpawn=std::max(0.f,lastParticleSpawn-fElapsedTime);
@ -72,6 +75,8 @@ void FireBolt::Update(float fElapsedTime){
SoundEffect::PlaySFX("Wizard Fire Bolt Hit",pos); SoundEffect::PlaySFX("Wizard Fire Bolt Hit",pos);
} }
if(flameTrail)flameTrail.value().get().SetEndPos(pos);
} }
BulletDestroyState FireBolt::PlayerHit(Player*player) BulletDestroyState FireBolt::PlayerHit(Player*player)

@ -47,12 +47,6 @@ ForegroundEffect::ForegroundEffect(vf2d pos,float lifetime,std::string imgFile,b
:Effect(pos,lifetime,imgFile,upperLevel,size,fadeout,spd,col,rotation,rotationSpd,additiveBlending){} :Effect(pos,lifetime,imgFile,upperLevel,size,fadeout,spd,col,rotation,rotationSpd,additiveBlending){}
ForegroundEffect::ForegroundEffect(vf2d pos,float lifetime,std::string imgFile,bool upperLevel,vf2d size,float fadeout,vf2d spd,Pixel col,float rotation,float rotationSpd,bool additiveBlending) ForegroundEffect::ForegroundEffect(vf2d pos,float lifetime,std::string imgFile,bool upperLevel,vf2d size,float fadeout,vf2d spd,Pixel col,float rotation,float rotationSpd,bool additiveBlending)
:Effect(pos,lifetime,imgFile,upperLevel,size,fadeout,spd,col,rotation,rotationSpd,additiveBlending){} :Effect(pos,lifetime,imgFile,upperLevel,size,fadeout,spd,col,rotation,rotationSpd,additiveBlending){}
void ForegroundEffect::Draw()const{ void ForegroundEffect::Draw(const Pixel blendCol)const{
if(additiveBlending)game->SetDecalMode(DecalMode::ADDITIVE); game->DrawPartialRotatedDecal(pos,GetFrame().GetSourceImage()->Decal(),rotation,GetFrame().GetSourceRect().size/2,GetFrame().GetSourceRect().pos,GetFrame().GetSourceRect().size,size,blendCol);
if(fadeout==0){
game->DrawPartialRotatedDecal(pos,GetFrame().GetSourceImage()->Decal(),rotation,GetFrame().GetSourceRect().size/2,GetFrame().GetSourceRect().pos,GetFrame().GetSourceRect().size,size,col);
} else {
game->DrawPartialRotatedDecal(pos,GetFrame().GetSourceImage()->Decal(),rotation,GetFrame().GetSourceRect().size/2,GetFrame().GetSourceRect().pos,GetFrame().GetSourceRect().size,size,{col.r,col.g,col.b,uint8_t(fadeout/original_fadeOutTime*255)});
}
game->SetDecalMode(DecalMode::NORMAL);
} }

@ -70,7 +70,7 @@ bool Meteor::Update(float fElapsedTime){
return Effect::Update(fElapsedTime); return Effect::Update(fElapsedTime);
} }
void Meteor::Draw()const{ void Meteor::Draw(const Pixel blendCol)const{
if(lifetime>0){ if(lifetime>0){
vf2d scale=vf2d{192,64}/3.f*(startLifetime+1-lifetime)*0.25*size; vf2d scale=vf2d{192,64}/3.f*(startLifetime+1-lifetime)*0.25*size;
vf2d meteorOffset=vf2d{lifetime*"Wizard.Ability 3.MeteorXMovementMult"_I,0}*"Wizard.Ability 3.MeteorShadowStartingDist"_F; vf2d meteorOffset=vf2d{lifetime*"Wizard.Ability 3.MeteorXMovementMult"_I,0}*"Wizard.Ability 3.MeteorShadowStartingDist"_F;

@ -84,9 +84,9 @@ bool MonsterSoul::Update(float fElapsedTime){
} }
return updateResult; return updateResult;
} }
void MonsterSoul::Draw()const{ void MonsterSoul::Draw(const Pixel blendCol)const{
game->SetDecalMode(DecalMode::ADDITIVE); game->SetDecalMode(DecalMode::ADDITIVE);
game->view.DrawRotatedDecal(pos-vf2d{0,GetZ()},GFX["monstersoulglow.png"].Decal(),0.f,GFX["monstersoulglow.png"].Sprite()->Size()/2,size*util::lerp(0.6f,1.4f,abs(sin(2*PI*lifetime)))); game->view.DrawRotatedDecal(pos-vf2d{0,GetZ()},GFX["monstersoulglow.png"].Decal(),0.f,GFX["monstersoulglow.png"].Sprite()->Size()/2,size*util::lerp(0.6f,1.4f,abs(sin(2*PI*lifetime))));
game->SetDecalMode(DecalMode::NORMAL); game->SetDecalMode(DecalMode::NORMAL);
Effect::Draw(); Effect::Draw(blendCol);
} }

@ -42,16 +42,16 @@ All rights reserved.
template<class T> template<class T>
class Oscillator{ class Oscillator{
public: public:
Oscillator() inline Oscillator()
:Oscillator({},{},0.f){} :Oscillator({},{},0.f){}
Oscillator(T val1,T val2,float cycleSpd) inline Oscillator(T val1,T val2,float cycleSpd)
:val1(val1),val2(val2),first(this->val1),second(this->val2),cycleSpd(cycleSpd),currentVal(val1){} :val1(val1),val2(val2),first(this->val1),second(this->val2),cycleSpd(cycleSpd),currentVal(val1){}
const T&Update(const float fElapsedTime){ inline const T&Update(const float fElapsedTime){
currentVal=util::lerp(val1,val2,sin(PI*timer*cycleSpd)/2+0.5f); currentVal=util::lerp(val1,val2,sin(PI*timer*cycleSpd)/2+0.5f);
timer+=fElapsedTime; timer+=fElapsedTime;
return get(); return get();
} }
const T&get(){ inline const T&get()const{
return currentVal; return currentVal;
}; };
const T&first; const T&first;

@ -75,7 +75,7 @@ bool PulsatingFire::Update(float fElapsedTime){
return Effect::Update(fElapsedTime); return Effect::Update(fElapsedTime);
} }
void PulsatingFire::Draw()const{ void PulsatingFire::Draw(const Pixel blendCol)const{
for(int i=0;i<8;i++){ for(int i=0;i<8;i++){
Animate2D::FrameSequence*effectSpr=nullptr; Animate2D::FrameSequence*effectSpr=nullptr;
switch(int(pulsatingFireValues[i]*5)){ switch(int(pulsatingFireValues[i]*5)){

@ -86,7 +86,7 @@ void SoundEffect::Initialize(){
} }
} }
void SoundEffect::PlaySFX(const std::string_view eventName,const vf2d&pos){ void SoundEffect::PlaySFX(const std::string&eventName,const vf2d&pos){
if(game->TestingModeEnabled()||eventName.length()==0)return; if(game->TestingModeEnabled()||eventName.length()==0)return;
const SoundEffect&sfx=GetRandomSFXFromFile(eventName); const SoundEffect&sfx=GetRandomSFXFromFile(eventName);
@ -112,7 +112,7 @@ void SoundEffect::PlaySFX(const std::string_view eventName,const vf2d&pos){
} }
} }
size_t SoundEffect::PlayLoopingSFX(const std::string_view eventName,const vf2d&pos){ size_t SoundEffect::PlayLoopingSFX(const std::string&eventName,const vf2d&pos){
if(game->TestingModeEnabled()||eventName.length()==0)return 0U; if(game->TestingModeEnabled()||eventName.length()==0)return 0U;
const SoundEffect&sfx=GetRandomSFXFromFile(eventName); const SoundEffect&sfx=GetRandomSFXFromFile(eventName);
const size_t id=Audio::Engine().LoadSound(operator""_SFX(sfx.filename.c_str(),sfx.filename.length())); const size_t id=Audio::Engine().LoadSound(operator""_SFX(sfx.filename.c_str(),sfx.filename.length()));
@ -128,8 +128,8 @@ void SoundEffect::StopLoopingSFX(const int id){
RepeatingSoundEffect::playingSoundEffects.erase(id); RepeatingSoundEffect::playingSoundEffects.erase(id);
} }
SoundEffect&SoundEffect::GetRandomSFXFromFile(const std::string_view eventName){ SoundEffect&SoundEffect::GetRandomSFXFromFile(const std::string&eventName){
auto itr=SOUND_EFFECTS.equal_range(std::string(eventName)); auto itr=SOUND_EFFECTS.equal_range(eventName);
size_t soundCount=std::distance(itr.first,itr.second); size_t soundCount=std::distance(itr.first,itr.second);
if(soundCount==0)ERR("WARNING! Sound Effect "<<std::quoted(eventName)<<" does not have any sound effects loaded/doesn't exist!") if(soundCount==0)ERR("WARNING! Sound Effect "<<std::quoted(eventName)<<" does not have any sound effects loaded/doesn't exist!")
size_t soundEffectChoice=util::random()%soundCount; size_t soundEffectChoice=util::random()%soundCount;

@ -54,14 +54,14 @@ private:
class SoundEffect{ class SoundEffect{
public: public:
SoundEffect(const std::string_view filename,const float&vol,const float&minPitch=0.9f,const float&maxPitch=1.1f,const bool combatSound=false); SoundEffect(const std::string_view filename,const float&vol,const float&minPitch=0.9f,const float&maxPitch=1.1f,const bool combatSound=false);
static void PlaySFX(const std::string_view eventName,const vf2d&pos); static void PlaySFX(const std::string&eventName,const vf2d&pos);
//Sets up a sound to be looped continuously. //Sets up a sound to be looped continuously.
static size_t PlayLoopingSFX(const std::string_view eventName,const vf2d&pos); static size_t PlayLoopingSFX(const std::string&eventName,const vf2d&pos);
static void StopLoopingSFX(const int id); static void StopLoopingSFX(const int id);
static void Initialize(); static void Initialize();
static const vf2d CENTERED; static const vf2d CENTERED;
private: private:
static SoundEffect&GetRandomSFXFromFile(const std::string_view eventName); static SoundEffect&GetRandomSFXFromFile(const std::string&eventName);
static std::multimap<EventName,SoundEffect>SOUND_EFFECTS; static std::multimap<EventName,SoundEffect>SOUND_EFFECTS;
std::string filename; std::string filename;
float vol; float vol;

@ -45,9 +45,9 @@ SpellCircle::SpellCircle(vf2d pos,float lifetime,std::string imgFile,std::string
SpellCircle::SpellCircle(vf2d pos,float lifetime,std::string imgFile,std::string spellInsigniaFile,bool upperLevel,float size,float fadeout,vf2d spd,Pixel col,float rotation,float rotationSpd,bool additiveBlending,float insigniaSize,float insigniaFadeout,vf2d insigniaSpd,Pixel insigniaCol,float insigniaRotation,float insigniaRotationSpd,bool insigniaAdditiveBlending) SpellCircle::SpellCircle(vf2d pos,float lifetime,std::string imgFile,std::string spellInsigniaFile,bool upperLevel,float size,float fadeout,vf2d spd,Pixel col,float rotation,float rotationSpd,bool additiveBlending,float insigniaSize,float insigniaFadeout,vf2d insigniaSpd,Pixel insigniaCol,float insigniaRotation,float insigniaRotationSpd,bool insigniaAdditiveBlending)
:SpellCircle(pos,lifetime,imgFile,spellInsigniaFile,upperLevel,vf2d{size,size},fadeout,spd,col,rotation,rotationSpd,additiveBlending,vf2d{insigniaSize,insigniaSize},insigniaFadeout,insigniaSpd,insigniaCol,insigniaRotation,insigniaRotationSpd,insigniaAdditiveBlending){} :SpellCircle(pos,lifetime,imgFile,spellInsigniaFile,upperLevel,vf2d{size,size},fadeout,spd,col,rotation,rotationSpd,additiveBlending,vf2d{insigniaSize,insigniaSize},insigniaFadeout,insigniaSpd,insigniaCol,insigniaRotation,insigniaRotationSpd,insigniaAdditiveBlending){}
void SpellCircle::Draw()const{ void SpellCircle::Draw(const Pixel blendCol)const{
Effect::Draw(); Effect::Draw(blendCol);
spellInsignia.Draw(); spellInsignia._Draw();
} }
bool SpellCircle::Update(float fElapsedTime){ bool SpellCircle::Update(float fElapsedTime){

@ -37,21 +37,68 @@ All rights reserved.
#pragma endregion #pragma endregion
#pragma once #pragma once
#include "Effect.h" #include "AdventuresInLestoria.h"
#include "SoundEffect.h"
class TrailEffect:Effect{ INCLUDE_game
inline TrailEffect(vf2d startPos,float lifetime,const std::string&imgFile,bool upperLevel,float fadeout,vf2d scale,float imgXOffsetSpd,Oscillator<Pixel>col,EffectType type=EffectType::NONE,bool additiveBlending=false) INCLUDE_GFX
:Effect(pos,lifetime,imgFile,upperLevel,scale,fadeout,{},col.first,0.f,0.f,additiveBlending){} INCLUDE_MONSTER_LIST
struct TrailEffect:Effect{
inline TrailEffect(vf2d startPos,float lifetime,const std::string&imgFile,int damage,float damageTickFrequency,bool upperLevel,float fadeout,vf2d scale,float imgXOffsetSpd,Oscillator<Pixel>col,EffectType type=EffectType::NONE,bool additiveBlending=false)
:endPos(startPos),imageXSpd(imgXOffsetSpd),damage(damage),col(col),damageTickFrequency(damageTickFrequency),Effect(startPos,lifetime,imgFile,upperLevel,0.f,fadeout,scale,{},type,WHITE,0.f,0.f,additiveBlending){}
inline void SetEndPos(const vf2d pos){ inline void SetEndPos(const vf2d pos){
this->endPos=pos; this->endPos=pos;
} }
inline bool Update(float fElapsedTime){ inline bool Update(float fElapsedTime){
col.Update(fElapsedTime); col.Update(fElapsedTime);
imageXOffset+=imageXSpd*fElapsedTime;
rotation=util::angleTo(pos,endPos);
hitTimer-=fElapsedTime;
if(hitTimer<=0.f){
for(std::shared_ptr<Monster>&monster:MONSTER_LIST){
vf2d closestPointToFlameTrail{geom2d::closest(geom2d::line<float>{pos,endPos},monster->GetPos())};
float distToTrail{util::distance(monster->GetPos(),closestPointToFlameTrail)};
if(!monster->InUndamageableState(OnUpperLevel(),GetZ())&&distToTrail<=12*size.y){
monster->Hurt(damage,OnUpperLevel(),GetZ(),HurtFlag::DOT);
SoundEffect::PlaySFX("Burn",monster->GetPos());
}
}
hitTimer+=damageTickFrequency;
}
return Effect::Update(fElapsedTime);
} }
inline void Draw()const{ inline void Draw(const Pixel blendCol)const{
geom2d::line<float>flameTrailLine{pos,endPos};
geom2d::line<float>flameTrailLineRectLine1{pos+vf2d{GetFrame().GetSourceImage()->Sprite()->height/2.f*size.y,rotation-PI/2}.cart(),endPos+vf2d{GetFrame().GetSourceImage()->Sprite()->height/2.f*size.y,rotation-PI/2}.cart()};
geom2d::line<float>flameTrailLineRectLine2{pos+vf2d{GetFrame().GetSourceImage()->Sprite()->height/2.f*size.y,rotation+PI/2}.cart(),endPos+vf2d{GetFrame().GetSourceImage()->Sprite()->height/2.f*size.y,rotation+PI/2}.cart()};
vf2d flameTrailSize{flameTrailLine.length(),float(GetFrame().GetSourceImage()->Sprite()->height)};
flameTrailSize*=size;
const auto PixelToUVSpace=[this,&flameTrailSize](vf2d pixelPos){
pixelPos.x+=imageXOffset;
return pixelPos/GetFrame().GetSourceImage()->Sprite()->Size()/size;
};
game->view.DrawPolygonDecal(GetFrame().GetSourceImage()->Decal(),std::vector<vf2d>{
flameTrailLine.upoint(0.5f),flameTrailLineRectLine1.start,flameTrailLineRectLine1.upoint(0.5f),flameTrailLineRectLine1.end,
flameTrailLineRectLine2.end,flameTrailLineRectLine2.upoint(0.5f),flameTrailLineRectLine2.start,flameTrailLineRectLine1.start,
},std::vector<vf2d>{
PixelToUVSpace(flameTrailSize/2),PixelToUVSpace({}),PixelToUVSpace({flameTrailSize.x/2.f,0}),PixelToUVSpace({flameTrailSize.x,0.f}),
PixelToUVSpace(flameTrailSize),PixelToUVSpace({flameTrailSize.x/2.f,flameTrailSize.y}),PixelToUVSpace({0.f,flameTrailSize.y}),PixelToUVSpace({}),
},std::vector<Pixel>{
col.get(),{0,0,0,0},col.get(),{0,0,0,0},
{0,0,0,0},col.get(),{0,0,0,0},{0,0,0,0},
},blendCol);
} }
private: private:
Oscillator<Pixel>col; Oscillator<Pixel>col;
vf2d endPos{}; vf2d endPos{};
float imageXSpd;
float imageXOffset{};
int damage;
float damageTickFrequency;
float hitTimer{};
}; };

@ -39,7 +39,7 @@ All rights reserved.
#define VERSION_MAJOR 1 #define VERSION_MAJOR 1
#define VERSION_MINOR 2 #define VERSION_MINOR 2
#define VERSION_PATCH 5 #define VERSION_PATCH 5
#define VERSION_BUILD 11271 #define VERSION_BUILD 11309
#define stringify(a) stringify_(a) #define stringify(a) stringify_(a)
#define stringify_(a) #a #define stringify_(a) #a

Binary file not shown.

Before

Width:  |  Height:  |  Size: 63 KiB

After

Width:  |  Height:  |  Size: 15 KiB

@ -56,6 +56,11 @@ Events
# Specify file names, followed by volume %. Optional min and max pitch adjustment (Defaults are 90%,110%) # Specify file names, followed by volume %. Optional min and max pitch adjustment (Defaults are 90%,110%)
File[0] = bomb_explosion.ogg, 100% File[0] = bomb_explosion.ogg, 100%
} }
Burn
{
# Specify file names, followed by volume %. Optional min and max pitch adjustment (Defaults are 90%,110%)
File[0] = burn.ogg, 70%
}
Button Click Button Click
{ {
# Specify file names, followed by volume %. Optional min and max pitch adjustment (Defaults are 90%,110%) # Specify file names, followed by volume %. Optional min and max pitch adjustment (Defaults are 90%,110%)

@ -504,11 +504,12 @@ Item Enchants
} }
Trail of Fire Trail of Fire
{ {
Description = "The Firebolt leaves behind a trail of fire, burning targets standing in it for {TRAIL DAMAGE}% attack every second for {TRAIL DURATION} seconds." Description = "Firebolt leaves behind a trail of fire, burning targets standing in it for {TRAIL DAMAGE}% attack every second for {TRAIL DURATION} seconds."
Affects = Ability 1 Affects = Ability 1
TRAIL DAMAGE = 10% TRAIL DAMAGE = 30%
TRAIL DURATION = 10s TRAIL DURATION = 10s
TRAIL TICK FREQUENCY = 1s
# Stat, Lowest, Highest Value # Stat, Lowest, Highest Value
# Stat Modifier[0] = ..., 0, 0 # Stat Modifier[0] = ..., 0, 0

Loading…
Cancel
Save