Tidied up monster drawing functions with portable lambdas to get rid of some copy-pasted code, making draw manipulation simpler. Implement Curse of Death ability. Release Build 10391.

removeExposedPackKey
sigonasr2 6 months ago
parent 3fecf73b3c
commit 7100bec234
  1. 1
      Adventures in Lestoria/Buff.h
  2. 36
      Adventures in Lestoria/Monster.cpp
  3. 1
      Adventures in Lestoria/Monster.h
  4. 11
      Adventures in Lestoria/Player.cpp
  5. 1
      Adventures in Lestoria/Player.h
  6. 2
      Adventures in Lestoria/Version.h
  7. 19
      Adventures in Lestoria/Witch.cpp
  8. 2
      Adventures in Lestoria/assets/config/audio/events.txt
  9. 3
      Adventures in Lestoria/assets/config/classes/Witch.txt
  10. BIN
      x64/Release/Adventures in Lestoria.exe

@ -57,6 +57,7 @@ enum BuffType{
OVER_TIME_DURING_CAST, OVER_TIME_DURING_CAST,
GLOW_PURPLE, GLOW_PURPLE,
COLOR_MOD, COLOR_MOD,
DAMAGE_AMPLIFICATION, //Multiplies all incoming damage by this amount.
}; };
enum class BuffRestorationType{ enum class BuffRestorationType{
ONE_OFF, ONE_OFF,

@ -442,7 +442,8 @@ void Monster::Draw()const{
if(GetBuffs(BuffType::GLOW_PURPLE).size()>0)glowPurpleBuff=GetBuffs(BuffType::GLOW_PURPLE)[0]; if(GetBuffs(BuffType::GLOW_PURPLE).size()>0)glowPurpleBuff=GetBuffs(BuffType::GLOW_PURPLE)[0];
if(GetBuffs(BuffType::COLOR_MOD).size()>0)blendCol=Pixel{uint8_t(PixelRaw(GetBuffs(BuffType::COLOR_MOD)[0].intensity).r*abs(sin(1.4*GetBuffs(BuffType::COLOR_MOD)[0].duration))),uint8_t(PixelRaw(GetBuffs(BuffType::COLOR_MOD)[0].intensity).g*abs(sin(1.4*GetBuffs(BuffType::COLOR_MOD)[0].duration))),uint8_t(PixelRaw(GetBuffs(BuffType::COLOR_MOD)[0].intensity).b*abs(sin(1.4*GetBuffs(BuffType::COLOR_MOD)[0].duration)))}; if(GetBuffs(BuffType::DAMAGE_AMPLIFICATION).size()>0)blendCol=Pixel{uint8_t(128+127*abs(sin(1.4*PI*GetBuffs(BuffType::DAMAGE_AMPLIFICATION)[0].duration))),uint8_t(0*abs(sin(1.4*PI*GetBuffs(BuffType::DAMAGE_AMPLIFICATION)[0].duration))),uint8_t(0*abs(sin(1.4*PI*GetBuffs(BuffType::DAMAGE_AMPLIFICATION)[0].duration)))};
else if(GetBuffs(BuffType::COLOR_MOD).size()>0)blendCol=Pixel{uint8_t(PixelRaw(GetBuffs(BuffType::COLOR_MOD)[0].intensity).r*abs(sin(1.4*GetBuffs(BuffType::COLOR_MOD)[0].duration))),uint8_t(PixelRaw(GetBuffs(BuffType::COLOR_MOD)[0].intensity).g*abs(sin(1.4*GetBuffs(BuffType::COLOR_MOD)[0].duration))),uint8_t(PixelRaw(GetBuffs(BuffType::COLOR_MOD)[0].intensity).b*abs(sin(1.4*GetBuffs(BuffType::COLOR_MOD)[0].duration)))};
else if(GetBuffs(BuffType::SLOWDOWN).size()>0)blendCol=Pixel{uint8_t(255*abs(sin(1.4*GetBuffs(BuffType::SLOWDOWN)[0].duration))),uint8_t(255*abs(sin(1.4*GetBuffs(BuffType::SLOWDOWN)[0].duration))),uint8_t(128+127*abs(sin(1.4*GetBuffs(BuffType::SLOWDOWN)[0].duration)))}; else if(GetBuffs(BuffType::SLOWDOWN).size()>0)blendCol=Pixel{uint8_t(255*abs(sin(1.4*GetBuffs(BuffType::SLOWDOWN)[0].duration))),uint8_t(255*abs(sin(1.4*GetBuffs(BuffType::SLOWDOWN)[0].duration))),uint8_t(128+127*abs(sin(1.4*GetBuffs(BuffType::SLOWDOWN)[0].duration)))};
else if(glowPurpleBuff.has_value())blendCol=Pixel{uint8_t(255*abs(sin(1.4*glowPurpleBuff.value().get().duration))),uint8_t(255*abs(sin(1.4*glowPurpleBuff.value().get().duration))),uint8_t(128+127*abs(sin(1.4*glowPurpleBuff.value().get().duration)))}; else if(glowPurpleBuff.has_value())blendCol=Pixel{uint8_t(255*abs(sin(1.4*glowPurpleBuff.value().get().duration))),uint8_t(255*abs(sin(1.4*glowPurpleBuff.value().get().duration))),uint8_t(128+127*abs(sin(1.4*glowPurpleBuff.value().get().duration)))};
@ -473,15 +474,25 @@ void Monster::Draw()const{
const vf2d imageScale{vf2d(GetSizeMult()*(!HasFourWaySprites()&&GetFacingDirection()==Direction::EAST?-1:1),GetSizeMult())}; const vf2d imageScale{vf2d(GetSizeMult()*(!HasFourWaySprites()&&GetFacingDirection()==Direction::EAST?-1:1),GetSizeMult())};
const vf2d glowPurpleImageScale{imageScale*1.1f}; const vf2d glowPurpleImageScale{imageScale*1.1f};
if(glowPurpleBuff.has_value())game->view.DrawPartialRotatedDecal(drawPos,GetFrame().GetSourceImage()->Decal(),finalSpriteRot,GetFrame().GetSourceRect().size/2,GetFrame().GetSourceRect().pos,GetFrame().GetSourceRect().size,glowPurpleImageScale,{43,0,66,blendCol.a}); const auto DrawBaseMonster=[&](vf2d scale={1.f,1.f},Pixel col=WHITE){
game->view.DrawPartialRotatedDecal(drawPos,GetFrame().GetSourceImage()->Decal(),finalSpriteRot,GetFrame().GetSourceRect().size/2,GetFrame().GetSourceRect().pos,GetFrame().GetSourceRect().size,imageScale,blendCol); game->view.DrawPartialRotatedDecal(drawPos,GetFrame().GetSourceImage()->Decal(),finalSpriteRot,GetFrame().GetSourceRect().size/2,GetFrame().GetSourceRect().pos,GetFrame().GetSourceRect().size,scale,col);
};
const auto DrawOverlayMonster=[&](vf2d scale={1.f,1.f},Pixel col=WHITE){
game->view.DrawPartialRotatedDecal(drawPos,GFX[overlaySprite].Decal(),finalSpriteRot,GetFrame().GetSourceRect().size/2,GetFrame().GetSourceRect().pos,GetFrame().GetSourceRect().size,scale,col);
};
const auto DrawMountedMonster=[&](vf2d scale={1.f,1.f},Pixel col=WHITE){
game->view.DrawPartialRotatedDecal(drawPos+mountedSprOffset,GetMountedFrame().value().GetSourceImage()->Decal(),finalSpriteRot,GetMountedFrame().value().GetSourceRect().size/2,GetMountedFrame().value().GetSourceRect().pos,GetMountedFrame().value().GetSourceRect().size,scale,col);
};
if(glowPurpleBuff.has_value())DrawBaseMonster(glowPurpleImageScale,{43,0,66,blendCol.a});
DrawBaseMonster(imageScale,blendCol);
if(overlaySprite.length()!=0){ if(overlaySprite.length()!=0){
if(glowPurpleBuff.has_value())game->view.DrawPartialRotatedDecal(drawPos,GFX[overlaySprite].Decal(),finalSpriteRot,GetFrame().GetSourceRect().size/2,GetFrame().GetSourceRect().pos,GetFrame().GetSourceRect().size,glowPurpleImageScale,{43,0,66,overlaySpriteTransparency}); if(glowPurpleBuff.has_value())DrawOverlayMonster(imageScale,{43,0,66,overlaySpriteTransparency});
game->view.DrawPartialRotatedDecal(drawPos,GFX[overlaySprite].Decal(),finalSpriteRot,GetFrame().GetSourceRect().size/2,GetFrame().GetSourceRect().pos,GetFrame().GetSourceRect().size,imageScale,{blendCol.r,blendCol.g,blendCol.b,overlaySpriteTransparency}); DrawOverlayMonster(imageScale,{blendCol.r,blendCol.g,blendCol.b,overlaySpriteTransparency});
} }
if(HasMountedMonster()){ if(HasMountedMonster()){
if(glowPurpleBuff.has_value())game->view.DrawPartialRotatedDecal(drawPos+mountedSprOffset,GetMountedFrame().value().GetSourceImage()->Decal(),finalSpriteRot,GetMountedFrame().value().GetSourceRect().size/2,GetMountedFrame().value().GetSourceRect().pos,GetMountedFrame().value().GetSourceRect().size,glowPurpleImageScale,{43,0,66,blendCol.a}); if(glowPurpleBuff.has_value())DrawMountedMonster(imageScale,{43,0,66,blendCol.a});
game->view.DrawPartialRotatedDecal(drawPos+mountedSprOffset,GetMountedFrame().value().GetSourceImage()->Decal(),finalSpriteRot,GetMountedFrame().value().GetSourceRect().size/2,GetMountedFrame().value().GetSourceRect().pos,GetMountedFrame().value().GetSourceRect().size,imageScale,blendCol); DrawMountedMonster(imageScale,blendCol);
} }
std::vector<Buff>shieldBuffs=GetBuffs(BARRIER_DAMAGE_REDUCTION); std::vector<Buff>shieldBuffs=GetBuffs(BARRIER_DAMAGE_REDUCTION);
@ -681,6 +692,8 @@ bool Monster::_Hurt(int damage,bool onUpperLevel,float z,const TrueDamageFlag da
RemoveMarkStack(); RemoveMarkStack();
} }
mod_dmg*=GetDamageAmplificationMult();
mod_dmg=std::ceil(mod_dmg); mod_dmg=std::ceil(mod_dmg);
hp=std::max(0,hp-int(mod_dmg)); hp=std::max(0,hp-int(mod_dmg));
@ -1341,4 +1354,13 @@ void Monster::ApplyDot(float duration,int damage,float timeBetweenTicks,Buff::Mo
void Monster::SetWeakPointer(std::shared_ptr<Monster>&sharedMonsterPtr){ void Monster::SetWeakPointer(std::shared_ptr<Monster>&sharedMonsterPtr){
weakPtr=sharedMonsterPtr; weakPtr=sharedMonsterPtr;
}
const float Monster::GetDamageAmplificationMult()const{
float damageAmpMult{1.f};
const std::vector<Buff>&buffList{GetBuffs(BuffType::DAMAGE_AMPLIFICATION)};
for(const Buff&buff:buffList){
damageAmpMult+=buff.intensity;
}
return damageAmpMult;
} }

@ -210,6 +210,7 @@ public:
const bool CanMove()const; const bool CanMove()const;
const std::weak_ptr<Monster>GetWeakPointer()const; const std::weak_ptr<Monster>GetWeakPointer()const;
void ApplyDot(float duration,int damage,float timeBetweenTicks,Buff::MonsterBuffExpireCallbackFunction expireCallbackFunc=[](std::weak_ptr<Monster>m,Buff&b){}); void ApplyDot(float duration,int damage,float timeBetweenTicks,Buff::MonsterBuffExpireCallbackFunction expireCallbackFunc=[](std::weak_ptr<Monster>m,Buff&b){});
const float GetDamageAmplificationMult()const;
private: private:
//NOTE: Marking a monster for deletion does not trigger any death events. It just simply removes the monster from the field!! //NOTE: Marking a monster for deletion does not trigger any death events. It just simply removes the monster from the field!!
// The way this works is that monsters marked for deletion will cause the monster update loop to detect there's at least one or more monsters that must be deleted and will call erase_if on the list at the end of the iteration loop. // The way this works is that monsters marked for deletion will cause the monster update loop to detect there's at least one or more monsters that must be deleted and will call erase_if on the list at the end of the iteration loop.

@ -895,6 +895,8 @@ bool Player::Hurt(int damage,bool onUpperLevel,float z,const TrueDamageFlag dama
} }
} }
mod_dmg*=GetDamageAmplificationMult();
mod_dmg=std::ceil(mod_dmg); mod_dmg=std::ceil(mod_dmg);
if(PlayHitSoundEffect)SoundEffect::PlaySFX("Player Hit",SoundEffect::CENTERED); if(PlayHitSoundEffect)SoundEffect::PlaySFX("Player Hit",SoundEffect::CENTERED);
@ -1836,4 +1838,13 @@ void Player::SetupAfterImage(){
void Player::ApplyDot(float duration,int damage,float timeBetweenTicks,Buff::PlayerBuffExpireCallbackFunction expireCallbackFunc){ void Player::ApplyDot(float duration,int damage,float timeBetweenTicks,Buff::PlayerBuffExpireCallbackFunction expireCallbackFunc){
AddBuff(BuffRestorationType::OVER_TIME,BuffOverTimeType::HP_DAMAGE_OVER_TIME,duration,damage,timeBetweenTicks,expireCallbackFunc); AddBuff(BuffRestorationType::OVER_TIME,BuffOverTimeType::HP_DAMAGE_OVER_TIME,duration,damage,timeBetweenTicks,expireCallbackFunc);
}
const float Player::GetDamageAmplificationMult()const{
float damageAmpMult{1.f};
const std::vector<Buff>&buffList{GetBuffs(BuffType::DAMAGE_AMPLIFICATION)};
for(const Buff&buff:buffList){
damageAmpMult+=buff.intensity;
}
return damageAmpMult;
} }

@ -292,6 +292,7 @@ public:
vf2d MoveUsingPathfinding(vf2d targetPos); vf2d MoveUsingPathfinding(vf2d targetPos);
const std::unordered_set<std::string>&GetMyClass()const; const std::unordered_set<std::string>&GetMyClass()const;
void ApplyDot(float duration,int damage,float timeBetweenTicks,Buff::PlayerBuffExpireCallbackFunction expireCallbackFunc=[](Player*p,Buff&b){}); void ApplyDot(float duration,int damage,float timeBetweenTicks,Buff::PlayerBuffExpireCallbackFunction expireCallbackFunc=[](Player*p,Buff&b){});
const float GetDamageAmplificationMult()const;
private: private:
int hp="Warrior.BaseHealth"_I; int hp="Warrior.BaseHealth"_I;
int mana="Player.BaseMana"_I; int mana="Player.BaseMana"_I;

@ -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 3 #define VERSION_PATCH 3
#define VERSION_BUILD 10390 #define VERSION_BUILD 10391
#define stringify(a) stringify_(a) #define stringify(a) stringify_(a)
#define stringify_(a) #a #define stringify_(a) #a

@ -164,10 +164,25 @@ void Witch::InitializeClassAbilities(){
return true; return true;
}; };
#pragma endregion #pragma endregion
#pragma region Witch Ability 3 (???) #pragma region Witch Ability 3 (Curse of Death)
Witch::ability3.action= Witch::ability3.action=
[](Player*p,vf2d pos={}){ [](Player*p,vf2d pos={}){
return false; std::optional<std::weak_ptr<Monster>>curseTarget{Monster::GetNearestMonster(pos,"Witch.Ability 3.Casting Range"_F/100.f*24,p->OnUpperLevel(),p->GetZ())};
if(curseTarget.has_value()&&!curseTarget.value().expired()){
const float curseDuration{"Witch.Ability 3.Curse Duration"_F};
const float damageAmpMult{"Witch.Ability 3.Damage Amplification"_F/100.f};
curseTarget.value().lock()->AddBuff(BuffType::DAMAGE_AMPLIFICATION,curseDuration,damageAmpMult);
const vf2d targetPos{curseTarget.value().lock()->GetPos()};
for(int i:std::ranges::iota_view(0,int(util::distance(p->GetPos(),targetPos)/8))){
float drawDist{i*8.f};
float fadeInTime{i*0.05f};
float fadeOutTime{0.5f+i*0.05f};
float effectSize{util::random_range(0.6f,1.2f)};
game->AddEffect(std::make_unique<Effect>(geom2d::line<float>(p->GetPos(),targetPos).rpoint(drawDist),0.f,"mark_trail.png",p->OnUpperLevel(),fadeInTime,fadeOutTime,vf2d{effectSize,effectSize},vf2d{},Pixel{162,0,0,uint8_t(util::random_range(150,255))},0.f,0.f),true);
}
SoundEffect::PlaySFX("Curse of Death",curseTarget.value().lock()->GetPos());
return true;
}else return false;
}; };
#pragma endregion #pragma endregion
} }

@ -84,7 +84,7 @@ Events
{ {
CombatSound = True CombatSound = True
# 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] = curse_of_death.ogg, 80% File[0] = curse_of_death.ogg, 100%
} }
Curse of Pain Curse of Pain
{ {

@ -117,7 +117,8 @@ Witch
# Whether or not this ability cancels casts. # Whether or not this ability cancels casts.
CancelCast = 0 CancelCast = 0
Damage Amplification = 2x # How much extra damage increase this ability provides to all incoming sources of damage.
Damage Amplification = 100%
Curse Duration = 7s Curse Duration = 7s
#RGB Values. Color 1 is the circle at full cooldown, Color 2 is the color at empty cooldown. #RGB Values. Color 1 is the circle at full cooldown, Color 2 is the color at empty cooldown.

Loading…
Cancel
Save