diff --git a/Adventures in Lestoria Tests/EnchantTests.cpp b/Adventures in Lestoria Tests/EnchantTests.cpp index 960de80d..eb90f4c7 100644 --- a/Adventures in Lestoria Tests/EnchantTests.cpp +++ b/Adventures in Lestoria Tests/EnchantTests.cpp @@ -209,5 +209,25 @@ namespace EnchantTests Test::InRange(player->GetCritDmgPct(),{53.0_Pct,57.0_Pct},L"Crit Damage not in expected range."); } } + TEST_METHOD(LethalTempoCheck){ + MonsterData testMonsterData{"TestName","Test Monster",30,10,5,{MonsterDropData{"Health Potion",100.f,1,1}},200.f}; + MONSTER_DATA["TestName"]=testMonsterData; + Monster testMonster{{},MONSTER_DATA["TestName"]}; + testMonster.Hurt(0,testMonster.OnUpperLevel(),testMonster.GetZ()); + Assert::AreEqual(size_t(0),player->GetBuffs(BuffType::LETHAL_TEMPO).size(),L"Lethal Tempo does not stack up without the enchant."); + testMonster.Hurt(0,testMonster.OnUpperLevel(),testMonster.GetZ(),HurtFlag::PLAYER_ABILITY); + Assert::AreEqual(size_t(0),player->GetBuffs(BuffType::LETHAL_TEMPO).size(),L"Lethal Tempo does not stack up without the enchant."); + std::weak_ptrnullRing{Inventory::AddItem("Null Ring"s)}; + Inventory::EquipItem(nullRing,EquipSlot::RING1); + nullRing.lock()->EnchantItem("Lethal Tempo"); + testMonster.Hurt(0,testMonster.OnUpperLevel(),testMonster.GetZ(),HurtFlag::PLAYER_ABILITY); + Assert::AreEqual(size_t(1),player->GetBuffs(BuffType::LETHAL_TEMPO).size(),L"Lethal Tempo buff is active after attacking with the enchant.."); + Assert::AreEqual(0.0175f,player->GetAttackRecoveryRateReduction(),L"Lethal Tempo buff reduced attack Recovery Rate by 0.0175 (5% of 0.35)."); + for(int i:std::ranges::iota_view(0,10)){ + testMonster.Hurt(0,testMonster.OnUpperLevel(),testMonster.GetZ(),HurtFlag::PLAYER_ABILITY); + } + Assert::AreEqual(0.0875f,player->GetAttackRecoveryRateReduction(),L"Lethal Tempo buff should cap at 5 stacks."); + Assert::AreEqual(size_t(1),player->GetBuffs(BuffType::LETHAL_TEMPO).size(),L"Lethal Tempo buff is active."); + } }; } \ No newline at end of file diff --git a/Adventures in Lestoria/Buff.h b/Adventures in Lestoria/Buff.h index 55c26870..3d235980 100644 --- a/Adventures in Lestoria/Buff.h +++ b/Adventures in Lestoria/Buff.h @@ -58,6 +58,7 @@ enum BuffType{ GLOW_PURPLE, COLOR_MOD, DAMAGE_AMPLIFICATION, //Multiplies all incoming damage by this amount. + LETHAL_TEMPO, }; enum class BuffRestorationType{ ONE_OFF, @@ -78,7 +79,6 @@ namespace BuffOverTimeType{ class AiL; struct Buff{ - using PlayerBuffExpireCallbackFunction=std::function; using MonsterBuffExpireCallbackFunction=std::functionattachedTarget,Buff&b)>; diff --git a/Adventures in Lestoria/ItemEnchant.cpp b/Adventures in Lestoria/ItemEnchant.cpp index c194ba35..a6a18e6d 100644 --- a/Adventures in Lestoria/ItemEnchant.cpp +++ b/Adventures in Lestoria/ItemEnchant.cpp @@ -53,6 +53,14 @@ const Pixel ItemEnchantInfo::enchantAttributeCol{0x00DFE2}; std::unordered_mapItemEnchantInfo::ENCHANT_LIST; std::unordered_mapItemEnchantInfo::ENCHANT_CATEGORIES; +const ItemEnchantInfo&operator ""_ENC(const char*key,std::size_t len){ + return ItemEnchantInfo::GetEnchant(std::string(key)); +} + +const float ItemEnchantInfo::operator[](const std::string& name)const{ + return config.at(name); +} + void ItemEnchantInfo::Initialize(){ ENCHANT_LIST.clear(); ENCHANT_CATEGORIES.clear(); @@ -239,4 +247,4 @@ const std::string ItemEnchant::RollRandomEnchant(){ }); return filteredEnchants[util::random()%filteredEnchants.size()].Name(); -} \ No newline at end of file +} diff --git a/Adventures in Lestoria/ItemEnchant.h b/Adventures in Lestoria/ItemEnchant.h index a4c60114..6bb337d4 100644 --- a/Adventures in Lestoria/ItemEnchant.h +++ b/Adventures in Lestoria/ItemEnchant.h @@ -74,6 +74,7 @@ public: ABILITY_2, ABILITY_3, }; + const float operator[](const std::string& name)const; private: class ItemEnchantCategoryData{ friend class ItemEnchantInfo; diff --git a/Adventures in Lestoria/Monster.cpp b/Adventures in Lestoria/Monster.cpp index a3a0b589..616220d6 100644 --- a/Adventures in Lestoria/Monster.cpp +++ b/Adventures in Lestoria/Monster.cpp @@ -52,6 +52,7 @@ All rights reserved. #include "steam/isteamuserstats.h" #endif #include "GameSettings.h" +#include "ItemEnchant.h" INCLUDE_ANIMATION_DATA INCLUDE_MONSTER_DATA @@ -692,6 +693,13 @@ bool Monster::_Hurt(int damage,bool onUpperLevel,float z,const TrueDamageFlag da RemoveMarkStack(); } + if(TriggersMark&&game->GetPlayer()->HasEnchant("Lethal Tempo")){ + Buff&lethalTempoBuff{game->GetPlayer()->GetOrAddBuff(BuffType::LETHAL_TEMPO,{"Lethal Tempo"_ENC["STACK DURATION"],0.f})}; + lethalTempoBuff.duration="Lethal Tempo"_ENC["STACK DURATION"]; + const int maxStackCount{int("Lethal Tempo"_ENC["MAX ATTACK SPEED INCREASE"]/"Lethal Tempo"_ENC["ATTACK SPEED INCREASE"])}; + lethalTempoBuff.intensity=std::min(maxStackCount,int(lethalTempoBuff.intensity)+1); + } + mod_dmg*=GetDamageAmplificationMult(); mod_dmg=std::ceil(mod_dmg); @@ -855,9 +863,19 @@ void Monster::PathAroundBehavior(float fElapsedTime){ } } +Buff&Monster::EditBuff(BuffType buff,size_t buffInd){ + return EditBuffs(buff)[buffInd]; +} + +std::vector>Monster::EditBuffs(BuffType buff){ + std::vector>filteredBuffs; + std::copy_if(buffList.begin(),buffList.end(),std::back_inserter(filteredBuffs),[&buff](const Buff&b){return b.type==buff;}); + return filteredBuffs; +} + std::vectorMonster::GetBuffs(BuffType buff)const{ std::vectorfilteredBuffs; - std::copy_if(buffList.begin(),buffList.end(),std::back_inserter(filteredBuffs),[buff](const Buff&b){return b.type==buff;}); + std::copy_if(buffList.begin(),buffList.end(),std::back_inserter(filteredBuffs),[&buff](const Buff&b){return b.type==buff;}); return filteredBuffs; } diff --git a/Adventures in Lestoria/Monster.h b/Adventures in Lestoria/Monster.h index 99dadadf..ce27e158 100644 --- a/Adventures in Lestoria/Monster.h +++ b/Adventures in Lestoria/Monster.h @@ -211,6 +211,8 @@ public: 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; + Buff&EditBuff(BuffType buff,size_t buffInd); + std::vector>EditBuffs(BuffType buff); 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 51353150..3cc1b274 100644 --- a/Adventures in Lestoria/Player.cpp +++ b/Adventures in Lestoria/Player.cpp @@ -1094,7 +1094,7 @@ bool Player::OnUpperLevel(){ const std::vectorPlayer::GetBuffs(BuffType buff)const{ std::vectorfilteredBuffs; - std::copy_if(buffList.begin(),buffList.end(),std::back_inserter(filteredBuffs),[buff](const Buff b){return b.type==buff;}); + std::copy_if(buffList.begin(),buffList.end(),std::back_inserter(filteredBuffs),[&buff](const Buff&b){return b.type==buff;}); return filteredBuffs; } @@ -1108,6 +1108,21 @@ void Player::RemoveBuff(BuffType buff){ } } +Buff&Player::GetOrAddBuff(BuffType buff,std::pairnewBuff){ + if(GetBuffs(buff).size()>0)return EditBuff(buff,0); + else return buffList.emplace_back(this,buff,newBuff.first,newBuff.second); +} + +Buff&Player::EditBuff(BuffType buff,size_t buffInd){ + return EditBuffs(buff)[buffInd]; +} + +std::vector>Player::EditBuffs(BuffType buff){ + std::vector>filteredBuffs; + std::copy_if(buffList.begin(),buffList.end(),std::back_inserter(filteredBuffs),[&buff](const Buff&b){return b.type==buff;}); + return filteredBuffs; +} + void Player::RemoveAllBuffs(BuffType buff){ std::erase_if(buffList,[&](Buff&b){return b.type==buff;}); } @@ -1574,6 +1589,9 @@ const float Player::GetAttackRecoveryRateReduction()const{ for(const Buff&b:GetBuffs(BuffType::ADRENALINE_RUSH)){ attackSpd+=ATTACK_COOLDOWN*"Thief.Ability 3.Attack Speed Increase"_F/100.f; } + for(const Buff&b:GetBuffs(BuffType::LETHAL_TEMPO)){ + attackSpd+=ATTACK_COOLDOWN*"Lethal Tempo"_ENC["ATTACK SPEED INCREASE"]/100.f*b.intensity; + } return attackSpd; } @@ -1857,5 +1875,6 @@ const float Player::GetDamageAmplificationMult()const{ } const bool Player::HasEnchant(const std::string_view enchantName)const{ + if(!ItemEnchantInfo::GetEnchants().count(std::string(enchantName)))ERR(std::format("WARNING! Enchantment {} does not exist in enchantment database!",enchantName)); return enchantList.count(std::string(enchantName)); } \ No newline at end of file diff --git a/Adventures in Lestoria/Player.h b/Adventures in Lestoria/Player.h index adca5c40..6b9e8b28 100644 --- a/Adventures in Lestoria/Player.h +++ b/Adventures in Lestoria/Player.h @@ -185,6 +185,12 @@ public: const std::vectorGetBuffs(BuffType buff)const; const std::vectorGetStatBuffs(const std::vector&attr)const; + + using BuffDuration=float; + using BuffIntensity=float; + Buff&GetOrAddBuff(BuffType buff,std::pairnewBuff);//When you need a buff added regardless if it already exists. You'll either modify an existing one or create a new one. + Buff&EditBuff(BuffType buff,size_t buffInd); + std::vector>EditBuffs(BuffType buff); //Removes the first buff found. void RemoveBuff(BuffType type); //Removes all buffs of a certain type. diff --git a/Adventures in Lestoria/Version.h b/Adventures in Lestoria/Version.h index 0907f6e2..15092f8b 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 10608 +#define VERSION_BUILD 10635 #define stringify(a) stringify_(a) #define stringify_(a) #a diff --git a/Adventures in Lestoria/config.h b/Adventures in Lestoria/config.h index d00db0d0..3576fb40 100644 --- a/Adventures in Lestoria/config.h +++ b/Adventures in Lestoria/config.h @@ -40,6 +40,8 @@ All rights reserved. using namespace olc; +class ItemEnchantInfo; + //Read a string array from the config. utils::datafilestringdata operator ""_s(const char*key,std::size_t len); //Read a boolean array from the config. @@ -69,4 +71,6 @@ utils::datafile operator ""_A(const char*key,std::size_t len); Pixel operator ""_Pixel(const char*key,std::size_t len); float operator ""_FRange(const char*key,std::size_t len); -float operator ""_Pct(long double pct); \ No newline at end of file +float operator ""_Pct(long double pct); + +const ItemEnchantInfo&operator ""_ENC(const char*key,std::size_t len); \ No newline at end of file diff --git a/x64/Release/Adventures in Lestoria.exe b/x64/Release/Adventures in Lestoria.exe index 2b802b58..b077e68f 100644 Binary files a/x64/Release/Adventures in Lestoria.exe and b/x64/Release/Adventures in Lestoria.exe differ