diff --git a/Adventures in Lestoria/Buff.h b/Adventures in Lestoria/Buff.h index dbfbbe07..55c26870 100644 --- a/Adventures in Lestoria/Buff.h +++ b/Adventures in Lestoria/Buff.h @@ -57,6 +57,7 @@ enum BuffType{ OVER_TIME_DURING_CAST, GLOW_PURPLE, COLOR_MOD, + DAMAGE_AMPLIFICATION, //Multiplies all incoming damage by this amount. }; enum class BuffRestorationType{ ONE_OFF, diff --git a/Adventures in Lestoria/Monster.cpp b/Adventures in Lestoria/Monster.cpp index 6ca1faf3..44752a2d 100644 --- a/Adventures in Lestoria/Monster.cpp +++ b/Adventures in Lestoria/Monster.cpp @@ -442,7 +442,8 @@ void Monster::Draw()const{ 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(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 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}); - game->view.DrawPartialRotatedDecal(drawPos,GetFrame().GetSourceImage()->Decal(),finalSpriteRot,GetFrame().GetSourceRect().size/2,GetFrame().GetSourceRect().pos,GetFrame().GetSourceRect().size,imageScale,blendCol); + 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,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(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}); - 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}); + if(glowPurpleBuff.has_value())DrawOverlayMonster(imageScale,{43,0,66,overlaySpriteTransparency}); + DrawOverlayMonster(imageScale,{blendCol.r,blendCol.g,blendCol.b,overlaySpriteTransparency}); } 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}); - 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); + if(glowPurpleBuff.has_value())DrawMountedMonster(imageScale,{43,0,66,blendCol.a}); + DrawMountedMonster(imageScale,blendCol); } std::vectorshieldBuffs=GetBuffs(BARRIER_DAMAGE_REDUCTION); @@ -681,6 +692,8 @@ bool Monster::_Hurt(int damage,bool onUpperLevel,float z,const TrueDamageFlag da RemoveMarkStack(); } + mod_dmg*=GetDamageAmplificationMult(); + mod_dmg=std::ceil(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&sharedMonsterPtr){ weakPtr=sharedMonsterPtr; +} + +const float Monster::GetDamageAmplificationMult()const{ + float damageAmpMult{1.f}; + const std::vector&buffList{GetBuffs(BuffType::DAMAGE_AMPLIFICATION)}; + for(const Buff&buff:buffList){ + damageAmpMult+=buff.intensity; + } + return damageAmpMult; } \ No newline at end of file diff --git a/Adventures in Lestoria/Monster.h b/Adventures in Lestoria/Monster.h index a8ea8daa..99dadadf 100644 --- a/Adventures in Lestoria/Monster.h +++ b/Adventures in Lestoria/Monster.h @@ -210,6 +210,7 @@ public: const bool CanMove()const; const std::weak_ptrGetWeakPointer()const; void ApplyDot(float duration,int damage,float timeBetweenTicks,Buff::MonsterBuffExpireCallbackFunction expireCallbackFunc=[](std::weak_ptrm,Buff&b){}); + const float GetDamageAmplificationMult()const; private: //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. diff --git a/Adventures in Lestoria/Player.cpp b/Adventures in Lestoria/Player.cpp index 69881520..d8033edc 100644 --- a/Adventures in Lestoria/Player.cpp +++ b/Adventures in Lestoria/Player.cpp @@ -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); 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){ 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&buffList{GetBuffs(BuffType::DAMAGE_AMPLIFICATION)}; + for(const Buff&buff:buffList){ + damageAmpMult+=buff.intensity; + } + return damageAmpMult; } \ No newline at end of file diff --git a/Adventures in Lestoria/Player.h b/Adventures in Lestoria/Player.h index e38a168f..ce837756 100644 --- a/Adventures in Lestoria/Player.h +++ b/Adventures in Lestoria/Player.h @@ -292,6 +292,7 @@ public: vf2d MoveUsingPathfinding(vf2d targetPos); const std::unordered_set&GetMyClass()const; void ApplyDot(float duration,int damage,float timeBetweenTicks,Buff::PlayerBuffExpireCallbackFunction expireCallbackFunc=[](Player*p,Buff&b){}); + const float GetDamageAmplificationMult()const; private: int hp="Warrior.BaseHealth"_I; int mana="Player.BaseMana"_I; diff --git a/Adventures in Lestoria/Version.h b/Adventures in Lestoria/Version.h index 89dcd80d..278044c0 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 10390 +#define VERSION_BUILD 10391 #define stringify(a) stringify_(a) #define stringify_(a) #a diff --git a/Adventures in Lestoria/Witch.cpp b/Adventures in Lestoria/Witch.cpp index cafac721..28135d2c 100644 --- a/Adventures in Lestoria/Witch.cpp +++ b/Adventures in Lestoria/Witch.cpp @@ -164,10 +164,25 @@ void Witch::InitializeClassAbilities(){ return true; }; #pragma endregion - #pragma region Witch Ability 3 (???) + #pragma region Witch Ability 3 (Curse of Death) Witch::ability3.action= [](Player*p,vf2d pos={}){ - return false; + std::optional>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(geom2d::line(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 } \ No newline at end of file diff --git a/Adventures in Lestoria/assets/config/audio/events.txt b/Adventures in Lestoria/assets/config/audio/events.txt index c822a48c..6c4302ac 100644 --- a/Adventures in Lestoria/assets/config/audio/events.txt +++ b/Adventures in Lestoria/assets/config/audio/events.txt @@ -84,7 +84,7 @@ Events { CombatSound = True # 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 { diff --git a/Adventures in Lestoria/assets/config/classes/Witch.txt b/Adventures in Lestoria/assets/config/classes/Witch.txt index 3ea78171..6161314d 100644 --- a/Adventures in Lestoria/assets/config/classes/Witch.txt +++ b/Adventures in Lestoria/assets/config/classes/Witch.txt @@ -117,7 +117,8 @@ Witch # Whether or not this ability cancels casts. 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 #RGB Values. Color 1 is the circle at full cooldown, Color 2 is the color at empty cooldown. diff --git a/x64/Release/Adventures in Lestoria.exe b/x64/Release/Adventures in Lestoria.exe index e13de04b..8f0535de 100644 Binary files a/x64/Release/Adventures in Lestoria.exe and b/x64/Release/Adventures in Lestoria.exe differ