diff --git a/Adventures in Lestoria Tests/EnchantTests.cpp b/Adventures in Lestoria Tests/EnchantTests.cpp index fbbeea18..92d43ab2 100644 --- a/Adventures in Lestoria Tests/EnchantTests.cpp +++ b/Adventures in Lestoria Tests/EnchantTests.cpp @@ -432,6 +432,7 @@ namespace EnchantTests nullRing.lock()->EnchantItem("Wizard's Soul"); player->SetState(State::NORMAL); player->RestoreMana(100); + player->GetRightClickAbility().charges=1; //Reset the cooldown so it can be used. player->GetRightClickAbility().cooldown=0.f; //Reset the cooldown so it can be used. player->CheckAndPerformAbility(player->GetRightClickAbility(),testKeyboardInput); Assert::AreEqual(player->GetRightClickAbility().GetCooldownTime(),player->GetRightClickAbility().cooldown,L"Right-click ability goes on cooldown like normal."); @@ -441,6 +442,7 @@ namespace EnchantTests Assert::AreEqual(player->GetAbility4().GetCooldownTime(),player->GetAbility4().cooldown,L"All other abilities are unaffected by Right-click ability being used."); player->SetState(State::NORMAL); player->RestoreMana(100); + player->GetAbility1().charges=1; //Reset the cooldown so it can be used. player->GetAbility1().cooldown=0.f; //Reset the cooldown so it can be used. player->CheckAndPerformAbility(player->GetAbility1(),testKeyboardInput); Assert::AreEqual(player->GetRightClickAbility().GetCooldownTime(),player->GetRightClickAbility().cooldown,L"Right-click ability remains unaffected by other abilities."); @@ -450,6 +452,7 @@ namespace EnchantTests Assert::AreEqual(player->GetAbility4().GetCooldownTime()-1.5f,player->GetAbility4().cooldown,L"All other abilities have cooldowns reduced by 1.5 seconds."); player->SetState(State::NORMAL); player->RestoreMana(100); + player->GetAbility2().charges=1; //Reset the cooldown so it can be used. player->GetAbility2().cooldown=0.f; //Reset the cooldown so it can be used. player->CheckAndPerformAbility(player->GetAbility2(),testKeyboardInput); Assert::AreEqual(player->GetRightClickAbility().GetCooldownTime(),player->GetRightClickAbility().cooldown,L"Right-click ability remains unaffected by other abilities."); @@ -459,6 +462,7 @@ namespace EnchantTests Assert::AreEqual(player->GetAbility4().GetCooldownTime()-3.f,player->GetAbility4().cooldown,L"All other abilities have cooldowns reduced by 1.5 seconds."); player->SetState(State::NORMAL); player->RestoreMana(100); + player->GetAbility3().charges=1; //Reset the cooldown so it can be used. player->GetAbility3().cooldown=0.f; //Reset the cooldown so it can be used. player->CheckAndPerformAbility(player->GetAbility3(),testKeyboardInput); game->SetElapsedTime(1.f); @@ -470,6 +474,7 @@ namespace EnchantTests Assert::AreEqual(player->GetAbility4().GetCooldownTime(),player->GetAbility4().cooldown,L"All other abilities have cooldowns reduced by 1.5 seconds."); player->SetState(State::NORMAL); player->RestoreMana(100); + player->GetAbility4().charges=1; //Reset the cooldown so it can be used. player->GetAbility4().cooldown=0.f; //Reset the cooldown so it can be used. player->CheckAndPerformAbility(player->GetAbility4(),testKeyboardInput); Assert::AreEqual(player->GetRightClickAbility().GetCooldownTime()-1.f,player->GetRightClickAbility().cooldown,L"Right-click ability remains unaffected by other abilities."); @@ -531,7 +536,7 @@ namespace EnchantTests player->CheckAndPerformAbility(player->GetRightClickAbility(),testKeyboardInput); Assert::AreEqual("Ranger.Right Click Ability.RetreatTime"_F,player->GetIframeTime(),L"Ranger's retreat iframe time is normal."); player->_SetIframes(0.f); - player->GetRightClickAbility().cooldown=0.f; + player->GetRightClickAbility().charges=1; player->SetState(State::NORMAL); std::weak_ptrnullRing{Inventory::AddItem("Null Ring"s)}; Inventory::EquipItem(nullRing,EquipSlot::RING1); @@ -565,7 +570,7 @@ namespace EnchantTests game->OnUserUpdate(1.f); } player->SetState(State::NORMAL); - player->GetAbility1().cooldown=0.f; + player->GetAbility1().charges=1; std::weak_ptrnullRing{Inventory::AddItem("Null Ring"s)}; Inventory::EquipItem(nullRing,EquipSlot::RING1); nullRing.lock()->EnchantItem("Extreme Rapid Fire"); @@ -575,7 +580,7 @@ namespace EnchantTests TEST_METHOD(MegaChargedShotCheck){ std::weak_ptrnullRing{Inventory::AddItem("Null Ring"s)}; Inventory::EquipItem(nullRing,EquipSlot::RING1); - nullRing.lock()->EnchantItem("Extreme Rapid Fire"); + nullRing.lock()->EnchantItem("Mega Charged Shot"); Assert::AreEqual("Warrior.Ability 2.Precast Time"_F,player->GetAbility2().precastInfo.castTime,L"Non-Ranger class' precast times should be unaffected with the item."); game->ChangePlayerClass(RANGER); player=game->GetPlayer(); @@ -583,5 +588,18 @@ namespace EnchantTests Inventory::UnequipItem(EquipSlot::RING1); Assert::AreEqual("Ranger.Ability 2.Precast Time"_F,player->GetAbility2().precastInfo.castTime,L"Ranger class' precast time should be back to normal."); } + TEST_METHOD(MultiMultiShotCheck){ + game->ChangePlayerClass(RANGER); + player=game->GetPlayer(); + Assert::AreEqual(uint8_t(1),player->GetAbility3().MAX_CHARGES,L"Player starts with 1 max charge of Multishot."); + const float multishotCooldownTime{"Ranger.Ability 3.Cooldown"_F}; + Assert::AreEqual("Ranger.Ability 3.Cooldown"_F,player->GetAbility3().GetCooldownTime(),util::wformat("Player starts with {} seconds of cooldown on Multishot.",multishotCooldownTime).c_str()); + std::weak_ptrnullRing{Inventory::AddItem("Null Ring"s)}; + Inventory::EquipItem(nullRing,EquipSlot::RING1); + nullRing.lock()->EnchantItem("Multi-Multishot"); + Assert::AreEqual(uint8_t(3),player->GetAbility3().MAX_CHARGES,L"Player now has 3 max charges of Multishot."); + const float newMultishotCooldownTime{multishotCooldownTime-multishotCooldownTime*"Multi-Multishot"_ENC["COOLDOWN REDUCTION PCT"]/100.f}; + Assert::AreEqual(newMultishotCooldownTime,player->GetAbility3().GetCooldownTime(),util::wformat("Player starts with {} seconds of cooldown on Multishot.",newMultishotCooldownTime).c_str()); + } }; } \ No newline at end of file diff --git a/Adventures in Lestoria Tests/PlayerTests.cpp b/Adventures in Lestoria Tests/PlayerTests.cpp index c49691d9..3a9f3b7a 100644 --- a/Adventures in Lestoria Tests/PlayerTests.cpp +++ b/Adventures in Lestoria Tests/PlayerTests.cpp @@ -42,6 +42,7 @@ All rights reserved. #include #include "ItemDrop.h" #include "DamageNumber.h" +#include using namespace Microsoft::VisualStudio::CppUnitTestFramework; using namespace olc::utils; @@ -434,6 +435,18 @@ namespace PlayerTests player->CheckAndPerformAbility(player->GetAbility2(),testKeyboardInput); player->CheckAndPerformAbility(player->GetAbility3(),testKeyboardInput); player->CheckAndPerformAbility(player->GetAbility4(),testKeyboardInput); + + Inventory::AddItem("Health Potion"s); + Inventory::AddItem("Berries"s); + Inventory::AddItem("Mana Potion"s); + game->SetLoadoutItem(0,"Health Potion"); + game->SetLoadoutItem(1,"Berries"); + game->SetLoadoutItem(2,"Mana Potion"); + + player->CheckAndPerformAbility(player->GetItem1(),testKeyboardInput); + player->CheckAndPerformAbility(player->GetItem2(),testKeyboardInput); + player->CheckAndPerformAbility(player->GetItem3(),testKeyboardInput); + game->SetElapsedTime(0.01f); //Force elapsed time value. game->OnUserUpdate(0.01f); //Let 0.01 seconds go by. All abilities should be off cooldown. Assert::AreEqual(0.f,player->GetRightClickAbility().cooldown,L"Using an ability with 100% CDR should result in a 0 second cooldown."); @@ -441,6 +454,9 @@ namespace PlayerTests Assert::AreEqual(0.f,player->GetAbility2().cooldown,L"Using an ability with 100% CDR should result in a 0 second cooldown."); Assert::AreEqual(0.f,player->GetAbility3().cooldown,L"Using an ability with 100% CDR should result in a 0 second cooldown."); Assert::AreEqual(0.f,player->GetAbility4().cooldown,L"Using an ability with 100% CDR should result in a 0 second cooldown."); + Assert::AreNotEqual(0.f,player->GetItem1().cooldown,L"Using an item ability with 100% CDR should not affect the cooldown."); + Assert::AreNotEqual(0.f,player->GetItem2().cooldown,L"Using an item ability with 100% CDR should not affect the cooldown."); + Assert::AreNotEqual(0.f,player->GetItem3().cooldown,L"Using an item ability with 100% CDR should not affect the cooldown."); } TEST_METHOD(CritRateStatEquipCheck){ std::weak_ptrsetArmor{Inventory::AddItem("Test Armor2"s)}; @@ -680,5 +696,58 @@ namespace PlayerTests player->ReduceAutoAttackTimer(0.2f); Assert::AreEqual("Warrior.Auto Attack.Cooldown"_F-0.2f,player->GetAutoAttackTimer(),L"Auto attack timer should've been reduced by 0.2 seconds."); } + TEST_METHOD(CooldownChargesCheck){ + player->GetAbility4()=Ranger::ability1; + + for(const std::reference_wrapper&a:player->GetAbilities()){ + if(a.get().name=="???")continue; + Assert::AreEqual(uint8_t(1),a.get().charges,util::wformat("Ability {} start with 1 charge.",a.get().name).c_str()); + Assert::AreEqual(0.f,a.get().cooldown,util::wformat("Ability {} start off cooldown.",a.get().name).c_str()); + + testKey->bHeld=true; //Force the key to be held down for testing purposes. + player->CheckAndPerformAbility(a.get(),testKeyboardInput); + Assert::AreEqual(uint8_t(0),a.get().charges,util::wformat("Ability {} should consume a charge when used.",a.get().name).c_str()); + Assert::AreEqual(a.get().COOLDOWN_TIME,a.get().cooldown,util::wformat("Ability {} go on cooldown when used.",a.get().name).c_str()); + player->RestoreMana(100); + player->SetState(State::NORMAL); + player->CheckAndPerformAbility(a.get(),testKeyboardInput); + a.get().MAX_CHARGES=5; + for(int i:std::ranges::iota_view(0,5)){ + testGame->SetElapsedTime(a.get().COOLDOWN_TIME); + testGame->OnUserUpdate(a.get().COOLDOWN_TIME); + + Assert::AreEqual(uint8_t(i+1),a.get().charges,util::wformat("Ability {} should increment their charge count when they are completely off cooldown.",a.get().name).c_str()); + if(i!=4)Assert::AreEqual(a.get().COOLDOWN_TIME,a.get().cooldown,util::wformat("Ability {} should go on cooldown again when their stack count is not maxed out.",a.get().name).c_str()); + else Assert::AreEqual(0.f,a.get().cooldown,util::wformat("Ability {} should not go on cooldown again when their stack count is maxed out.",a.get().name).c_str()); + } + player->RestoreMana(100); + player->SetState(State::NORMAL); + } + } + TEST_METHOD(ChargesEquipBehaviorCheck){ + testGame->ChangePlayerClass(RANGER); + player=testGame->GetPlayer(); + player->GetAbility3().charges=3; + testKey->bHeld=true; //Force the key to be held down for testing purposes. + testGame->SetElapsedTime(0.25f); + testGame->OnUserUpdate(0.25f); + Assert::AreEqual(uint8_t(1),player->GetAbility3().charges,L"Back down to 1 charge without having Multi-Multishot enchant equipped."); + player->CheckAndPerformAbility(player->GetAbility3(),testKeyboardInput); + Assert::AreEqual(uint8_t(0),player->GetAbility3().charges,L"Back down to 0 charges without having Multi-Multishot enchant equipped."); + } + TEST_METHOD(CooldownEquipBehaviorCheck){ + testGame->ChangePlayerClass(RANGER); + player=testGame->GetPlayer(); + float oldCooldownTime{player->GetAbility3().GetCooldownTime()}; + player->GetAbility3().cooldown=player->GetAbility3().GetCooldownTime(); + std::weak_ptrnullRing{Inventory::AddItem("Null Ring"s)}; + Inventory::EquipItem(nullRing,EquipSlot::RING1); + nullRing.lock()->EnchantItem("Multi-Multishot"); + testKey->bHeld=true; //Force the key to be held down for testing purposes. + Assert::AreEqual(player->GetAbility3().GetCooldownTime(),oldCooldownTime-oldCooldownTime*"Multi-Multishot"_ENC["COOLDOWN REDUCTION PCT"]/100.f,L"Old cooldown time with multishot cooldown reduction pct matches."); + testGame->SetElapsedTime(0.f); + testGame->OnUserUpdate(0.f); + Assert::AreEqual(player->GetAbility3().GetCooldownTime(),player->GetAbility3().cooldown,L"Cooldown now matches the new reduced amount."); + } }; } \ No newline at end of file diff --git a/Adventures in Lestoria/Ability.h b/Adventures in Lestoria/Ability.h index a999bf27..66403e48 100644 --- a/Adventures in Lestoria/Ability.h +++ b/Adventures in Lestoria/Ability.h @@ -62,6 +62,8 @@ struct Ability{ std::string description=""; float cooldown=0; float COOLDOWN_TIME=0; + uint8_t charges{1}; + uint8_t MAX_CHARGES{1}; int manaCost=0; Pixel barColor1,barColor2; PrecastData precastInfo; @@ -73,6 +75,7 @@ struct Ability{ //If set to true, this ability instead activates immediately when a cast occurs. When the cast finishes, nothing happens instead. bool actionPerformedDuringCast=false; bool waitForRelease=false; + bool keyReleaseRequiredToReactivate{false}; //When the player presses an ability, they cannot use it again until they have released the key to press it down again. So this gets set to true everytime an ability activates, and set to false once the player releases that key. //Ability action function, returns true if the ability can be casted, otherwise returns false. // Argument 1: Player* - player pointer // Argument 2: vf2d - The returned precast target position (if the ability needs to be aimed, otherwise {}) diff --git a/Adventures in Lestoria/Adventures in Lestoria.tiled-project b/Adventures in Lestoria/Adventures in Lestoria.tiled-project index d04d006d..26cb9889 100644 --- a/Adventures in Lestoria/Adventures in Lestoria.tiled-project +++ b/Adventures in Lestoria/Adventures in Lestoria.tiled-project @@ -52,7 +52,8 @@ "foresty1_1", "overworld", "foresty_boss", - "base_camp" + "base_camp", + "mountain" ], "valuesAsFlags": false }, diff --git a/Adventures in Lestoria/AdventuresInLestoria.cpp b/Adventures in Lestoria/AdventuresInLestoria.cpp index f5f71f7c..410254f3 100644 --- a/Adventures in Lestoria/AdventuresInLestoria.cpp +++ b/Adventures in Lestoria/AdventuresInLestoria.cpp @@ -2084,7 +2084,7 @@ void AiL::RenderHud(){ } void AiL::RenderCooldowns(){ - std::vectorcooldowns{ + std::vector>cooldowns{ player->GetAbility1(), player->GetAbility2(), player->GetAbility3(), @@ -2094,6 +2094,7 @@ void AiL::RenderCooldowns(){ const auto DrawCooldown=[&](vf2d pos,Ability&a,int loadoutSlot=-1/*Set to 0-2 to get an item slot rendered instead*/){ bool circle=loadoutSlot==-1; if(a.name!="???"){ + const bool HasEnchantWithAbilityAffected{player->HasEnchantWithAbilityAffected(a.name)}; vf2d keyDisplaySize=vf2d{GetTextSize(a.input->GetDisplayName())}*vf2d{0.5f,0.5f}; InputType controlType=KEY; @@ -2107,15 +2108,16 @@ void AiL::RenderCooldowns(){ if(a.cooldown>0.1){ vf2d iconScale={1,1}; if(loadoutSlot!=-1)iconScale={0.7f,0.7f}; - DrawRotatedDecal(pos+vf2d{12,12},GFX[a.icon].Decal(),0,{12,12},iconScale,{255,255,255,64}); + DrawRotatedDecal(pos+vf2d{12,12},GFX[a.icon].Decal(),0,{12,12},iconScale,{255,255,255,uint8_t(a.charges==0?64:255)}); if(circle){ - DrawPie(pos+vf2d{12,12},12,360-(a.cooldown/a.GetCooldownTime())*360,PixelLerp(a.barColor1,a.barColor2,(a.cooldown/a.GetCooldownTime()))); + if(a.charges==0)DrawPie(pos+vf2d{12,12},12,360-(a.cooldown/a.GetCooldownTime())*360,PixelLerp(a.barColor1,a.barColor2,(a.cooldown/a.GetCooldownTime()))); + else DrawPieArc("safeIndicatorGradient.png",pos+vf2d{12,12},11.5f,360-(a.cooldown/a.GetCooldownTime())*360,WHITE); }else{ DrawSquarePie(pos+vf2d{12,12},10,360-(a.cooldown/a.GetCooldownTime())*360,PixelLerp(a.barColor1,a.barColor2,(a.cooldown/a.GetCooldownTime()))); } - std::stringstream cooldownTimeDisplay; + std::stringstream cooldownTimeDisplay; cooldownTimeDisplay<GetMana()0){ + if(a.charges==0){ shortNameCol=GREY; manaCostShadowCol=DARK_GREY; keyDisplayCol=GREY; @@ -2155,7 +2160,7 @@ void AiL::RenderCooldowns(){ if(itemAmt>0){ std::string amtString="x"+std::to_string(itemAmt); vf2d qtySize=vf2d{GetTextSize(amtString)}*vf2d{0.5f,0.75f}; - DrawShadowStringDecal(pos+vf2d{20,20}-qtySize/2,amtString,WHITE,BLACK,{0.5f,0.75f},{0.5f,0.75f}); + DrawShadowStringDecal(pos+vf2d{20,20}-qtySize/2,amtString,0xE0E0E0,BLACK,{0.5f,0.75f},{0.5f,0.75f}); }else{ DrawDecal(pos,GFX["square_skill_overlay_icon_empty.png"].Decal(),{1,1},DARK_RED); shortNameCol=RED; @@ -2171,7 +2176,16 @@ void AiL::RenderCooldowns(){ } vf2d shortNameSize=vf2d{GetTextSize(a.shortName)}*vf2d{0.5f,0.75f}; - DrawShadowStringDecal(pos+vf2d{13,24}-shortNameSize/2,a.shortName,shortNameCol,{255,255,255,230},{0.5f,0.75f},{0.5f,0.75f}); + Pixel shadowCol{255,255,255,230}; + if(HasEnchantWithAbilityAffected)shadowCol={255,187,132,230}; + + + if(a.charges>1){ + const std::string chargeCountDisplayStr{std::format("x{}",a.charges)}; + const vf2d chargeCountStrSize{GetTextSize(chargeCountDisplayStr)}; + DrawShadowStringDecal(pos+vf2d{13,24}+vf2d{shortNameSize.x-chargeCountStrSize.x*0.75f,-shortNameSize.y}-4.f,chargeCountDisplayStr,WHITE,BLACK,{0.75f,0.75f}); + } + DrawShadowStringDecal(pos+vf2d{13,24}-shortNameSize/2,a.shortName,shortNameCol,shadowCol,{0.5f,0.75f},{0.5f,0.75f}); } }; @@ -2709,14 +2723,10 @@ void AiL::_PrepareLevel(MapName map,MusicChange changeMusic){ #pragma region Setup Player and Camera (Loading Phase 8) LoadingScreen::AddPhase([&](){ - player->GetAbility1().cooldown=0.f; - player->GetAbility2().cooldown=0.f; - player->GetAbility3().cooldown=0.f; - player->GetAbility4().cooldown=0.f; - player->GetRightClickAbility().cooldown=0.f; - player->useItem1.cooldown=0.f; - player->useItem2.cooldown=0.f; - player->useItem3.cooldown=0.f; + for(const std::reference_wrapper&a:player->GetAbilities()){ + a.get().cooldown=0.f; + a.get().charges=a.get().MAX_CHARGES; + } player->upperLevel=false; //Assume player starts on lower level. player->ForceSetPos(MAP_DATA[GetCurrentLevel()].MapData.playerSpawnLocation); //Normal set pos does one axis and then the other, so this will make sure that we actually end up at the right spot and ignore collision rules. @@ -2997,6 +3007,7 @@ void AiL::ChangePlayerClass(Class cl){ Component(CHARACTER_MENU,"Level Class Display")->SetLabel(std::format("Lv{} {}",game->GetPlayer()->Level(),game->GetPlayer()->GetClassName())); Player::moneyListeners=moneyListeners; GetPlayer()->InitializeMinimapImage(); + player->RecalculateEquipStats(); } void AiL::InitializeClasses(){ @@ -3012,6 +3023,13 @@ void AiL::InitializeClasses(){ Trapper::InitializeClassAbilities(); Wizard::InitializeClassAbilities(); Witch::InitializeClassAbilities(); + + Warrior::CreateOriginalCopies(); + Thief::CreateOriginalCopies(); + Ranger::CreateOriginalCopies(); + Trapper::CreateOriginalCopies(); + Wizard::CreateOriginalCopies(); + Witch::CreateOriginalCopies(); } std::string AiL::GetString(std::string key){ diff --git a/Adventures in Lestoria/AdventuresInLestoria.h b/Adventures in Lestoria/AdventuresInLestoria.h index eb0f4e45..968d69b3 100644 --- a/Adventures in Lestoria/AdventuresInLestoria.h +++ b/Adventures in Lestoria/AdventuresInLestoria.h @@ -66,8 +66,8 @@ class SteamStatsReceivedHandler; INCLUDE_BULLET_LIST #define CreateBullet(type) \ - *(type*const)(BULLET_LIST.emplace_back(std::make_unique(type -#define EndBullet )).get()) + (*((type*const)BULLET_LIST.emplace_back(std::make_unique(type +#define EndBullet )).get())) using HurtReturnValue=bool; using HurtList=std::vector,HurtReturnValue>>; diff --git a/Adventures in Lestoria/DEFINES.h b/Adventures in Lestoria/DEFINES.h index de60570e..59393525 100644 --- a/Adventures in Lestoria/DEFINES.h +++ b/Adventures in Lestoria/DEFINES.h @@ -85,6 +85,30 @@ class::class() \ class::class(Player*player) \ :Player::Player(player){} \ Class class::GetClass(){return cl;} \ +void class::CreateOriginalCopies(){ \ +original_rightClickAbility=rightClickAbility; \ +original_ability1=ability1; \ +original_ability2=ability2; \ +original_ability3=ability3; \ +original_ability4=ability4; \ +} \ +void class::ResetToOriginalAbilities(){ \ +rightClickAbility.COOLDOWN_TIME=original_rightClickAbility.COOLDOWN_TIME; \ +ability1.COOLDOWN_TIME=original_ability1.COOLDOWN_TIME; \ +ability2.COOLDOWN_TIME=original_ability2.COOLDOWN_TIME; \ +ability3.COOLDOWN_TIME=original_ability3.COOLDOWN_TIME; \ +ability4.COOLDOWN_TIME=original_ability4.COOLDOWN_TIME; \ +rightClickAbility.MAX_CHARGES=original_rightClickAbility.MAX_CHARGES; \ +ability1.MAX_CHARGES=original_ability1.MAX_CHARGES; \ +ability2.MAX_CHARGES=original_ability2.MAX_CHARGES; \ +ability3.MAX_CHARGES=original_ability3.MAX_CHARGES; \ +ability4.MAX_CHARGES=original_ability4.MAX_CHARGES; \ +rightClickAbility.precastInfo=original_rightClickAbility.precastInfo; \ +ability1.precastInfo=original_ability1.precastInfo; \ +ability2.precastInfo=original_ability2.precastInfo; \ +ability3.precastInfo=original_ability3.precastInfo; \ +ability4.precastInfo=original_ability4.precastInfo; \ +} \ const std::string&class::GetClassName(){return name;} \ Ability&class::GetRightClickAbility(){return rightClickAbility;}; \ Ability&class::GetAbility1(){return ability1;}; \ @@ -106,6 +130,11 @@ Ability class::ability1=Ability(); \ Ability class::ability2=Ability(); \ Ability class::ability3=Ability(); \ Ability class::ability4=Ability(); \ +Ability class::original_rightClickAbility=Ability(); \ +Ability class::original_ability1=Ability(); \ +Ability class::original_ability2=Ability(); \ +Ability class::original_ability3=Ability(); \ +Ability class::original_ability4=Ability(); \ std::string class::idle_n="WARRIOR_IDLE_N"; \ std::string class::idle_e="WARRIOR_IDLE_E"; \ std::string class::idle_s="WARRIOR_IDLE_S"; \ diff --git a/Adventures in Lestoria/Item.h b/Adventures in Lestoria/Item.h index 6f4057a2..898ae038 100644 --- a/Adventures in Lestoria/Item.h +++ b/Adventures in Lestoria/Item.h @@ -192,7 +192,7 @@ private: ItemInfo*it; Stats randomizedStats; bool locked=false; - std::optionalenchant; + std::optionalenchant{}; void SetAmt(uint32_t newAmt); static ItemEnhancementFunctionPrimingData enhanceFunctionPrimed; diff --git a/Adventures in Lestoria/ItemEnchant.cpp b/Adventures in Lestoria/ItemEnchant.cpp index 4944b2bf..3dca4f49 100644 --- a/Adventures in Lestoria/ItemEnchant.cpp +++ b/Adventures in Lestoria/ItemEnchant.cpp @@ -124,7 +124,7 @@ void ItemEnchantInfo::Initialize(){ } for(const auto&[configName,val]:newEnchant.config){ - const std::string wrappedConfigStr{std::vformat("{{{}}}",std::make_format_args(configName))}; + const std::string wrappedConfigStr{util::vformat("{{{}}}",configName)}; size_t configValInd{enchantDescription.find(wrappedConfigStr)}; if(configValInd==std::string::npos)continue; std::string formattedFloat{std::format("{}{}#FFFFFF",ItemEnchantInfo::enchantAttributeCol.toHTMLColorCode(),val)}; @@ -246,7 +246,7 @@ const std::string ItemEnchant::RollRandomEnchant(){ void ItemEnchant::UpdateDescription(){ description=ItemEnchantInfo::ENCHANT_LIST.at(this->enchantName).Description(); for(const auto&[attr,val]:ItemEnchantInfo::ENCHANT_LIST.at(this->enchantName).minStatModifiers){ - const std::string wrappedConfigStr{std::vformat("{{{}}}",std::make_format_args(attr.ActualName()))}; + const std::string wrappedConfigStr{util::vformat("{{{}}}",attr.ActualName())}; size_t configValInd{description.find(wrappedConfigStr)}; if(configValInd==std::string::npos)continue; std::string formattedFloat{std::format("{}{}#FFFFFF",ItemEnchantInfo::enchantAttributeCol.toHTMLColorCode(),GetAttribute(attr.ActualName()))}; @@ -271,4 +271,34 @@ std::map::const_iterator ItemEnchant::end()const{ const Pixel&ItemEnchant::DisplayCol()const{ return ItemEnchantInfo::GetEnchant(Name()).enchantAttributeCol; +} + +const std::optional&ItemEnchantInfo::GetAbilitySlot()const{ + return abilitySlot; +} + +const std::optionalItemEnchantInfo::GetAbility()const{ + if(!GetAbilitySlot()||!GetClass())return {}; + + #pragma region Generate Abilities for all classes + #define GENERATE_ABILITY_LIST_FOR_CLASS(class,staticClass) \ + {class,{std::optional{},&staticClass::rightClickAbility,&staticClass::ability1,&staticClass::ability2,&staticClass::ability3}}, + #define END_ABILITY_LIST }; + + std::unordered_map,5>>enchantAbilitiesList{ + GENERATE_ABILITY_LIST_FOR_CLASS(WARRIOR,Warrior) + GENERATE_ABILITY_LIST_FOR_CLASS(RANGER,Ranger) + GENERATE_ABILITY_LIST_FOR_CLASS(WIZARD,Wizard) + GENERATE_ABILITY_LIST_FOR_CLASS(THIEF,Thief) + GENERATE_ABILITY_LIST_FOR_CLASS(TRAPPER,Trapper) + GENERATE_ABILITY_LIST_FOR_CLASS(WITCH,Witch) + END_ABILITY_LIST; + #pragma endregion + + return enchantAbilitiesList[*GetClass()][int(*GetAbilitySlot())]; +} + +const std::optional>ItemEnchant::Ability()const{ + if(GetEnchantInfo().GetAbility())return **GetEnchantInfo().GetAbility(); + return {}; } \ No newline at end of file diff --git a/Adventures in Lestoria/ItemEnchant.h b/Adventures in Lestoria/ItemEnchant.h index 3d922d7b..5a7f19eb 100644 --- a/Adventures in Lestoria/ItemEnchant.h +++ b/Adventures in Lestoria/ItemEnchant.h @@ -40,6 +40,7 @@ All rights reserved. #include "AttributableStat.h" #include "Pixel.h" #include "Class.h" +#include "Ability.h" class ItemEnchantInfo{ friend class ItemEnchant; @@ -55,6 +56,13 @@ public: CLASS, UNIQUE, }; + enum class AbilitySlot{ + AUTO_ATTACK, + RIGHT_CLICK, + ABILITY_1, + ABILITY_2, + ABILITY_3, + }; const static Pixel enchantAttributeCol; @@ -66,14 +74,9 @@ public: const std::string_view Description()const; const ItemEnchantCategory&Category()const; const std::optional&GetClass()const; + const std::optional&GetAbilitySlot()const; + const std::optionalGetAbility()const; //Get the ability this enchant is tied to. const float GetConfigValue(const std::string_view keyName)const; - enum class AbilitySlot{ - AUTO_ATTACK, - RIGHT_CLICK, - ABILITY_1, - ABILITY_2, - ABILITY_3, - }; const float operator[](const std::string& name)const; private: class ItemEnchantCategoryData{ @@ -109,6 +112,7 @@ public: std::map::const_iterator begin()const; std::map::const_iterator end()const; const Pixel&DisplayCol()const; + const std::optional>Ability()const; private: void UpdateDescription(); const ItemEnchantInfo&GetEnchantInfo()const; diff --git a/Adventures in Lestoria/Player.cpp b/Adventures in Lestoria/Player.cpp index abec8a34..aa233f93 100644 --- a/Adventures in Lestoria/Player.cpp +++ b/Adventures in Lestoria/Player.cpp @@ -378,7 +378,8 @@ void Player::Update(float fElapsedTime){ SetState(State::NORMAL); if(!allowed&&castPrepAbility->action(this,castInfo.castPos))allowed=true; if(allowed){ - castPrepAbility->cooldown=castPrepAbility->GetCooldownTime(); + if(castPrepAbility->cooldown==0.f)castPrepAbility->cooldown=castPrepAbility->GetCooldownTime(); + castPrepAbility->charges--; ConsumeMana(castPrepAbility->manaCost); OnAbilityUse(ability); } @@ -572,38 +573,21 @@ void Player::Update(float fElapsedTime){ }else{ cooldownMultiplier=1/(1-game->GetPlayer()->GetCooldownReductionPct()); } - rightClickAbility.cooldown-=fElapsedTime*cooldownMultiplier; - ability.cooldown-=fElapsedTime*cooldownMultiplier; - ability2.cooldown-=fElapsedTime*cooldownMultiplier; - ability3.cooldown-=fElapsedTime*cooldownMultiplier; - ability4.cooldown-=fElapsedTime*cooldownMultiplier; - item1.cooldown-=fElapsedTime; - item2.cooldown-=fElapsedTime; - item3.cooldown-=fElapsedTime; - if(rightClickAbility.cooldown<0){ - rightClickAbility.cooldown=0; - } - if(ability.cooldown<0){ - ability.cooldown=0; - } - if(ability2.cooldown<0){ - ability2.cooldown=0; - } - if(ability3.cooldown<0){ - ability3.cooldown=0; - } - if(ability4.cooldown<0){ - ability4.cooldown=0; - } - if(item1.cooldown<0){ - item1.cooldown=0; - } - if(item2.cooldown<0){ - item2.cooldown=0; - } - if(item3.cooldown<0){ - item3.cooldown=0; - } + + const std::vector>playerAbilities{GetAbilities()}; + std::for_each(playerAbilities.begin(),playerAbilities.end(),[&fElapsedTime,&cooldownMultiplier](std::reference_wrappera){ + //NOTE: We have to compare to the max cooldown time when reducing cooldowns since it's possible when we equip/unequip items that the cooldown remaining is longer than the max cooldown, so we will immediately set the cooldown to that value if necessary. + if(a.get().itemAbility)a.get().cooldown=std::min(a.get().GetCooldownTime(),a.get().cooldown-fElapsedTime); //Item abilities are not affected by CDR. + else if(a.get().charges>=a.get().MAX_CHARGES)a.get().cooldown=0.f; //We got in a state where we probably unequipped something and no longer need to be on cooldown. + else a.get().cooldown=std::min(a.get().GetCooldownTime(),a.get().cooldown-fElapsedTime*cooldownMultiplier); + + if(a.get().cooldown<=0.f){ + a.get().charges=std::min(a.get().MAX_CHARGES,uint8_t(a.get().charges+1)); + if(a.get().charges&m:MONSTER_LIST){ const float playerRadius{12*GetSizeMult()/2}; const float monsterRadius{m->GetCollisionRadius()}; @@ -759,7 +743,7 @@ void Player::Update(float fElapsedTime){ float angleToCursor=atan2(extendedLine.y-GetPos().y,extendedLine.x-GetPos().x); attack_cooldown_timer=ARROW_ATTACK_COOLDOWN; BULLET_LIST.push_back(std::make_unique(Arrow(GetPos(),extendedLine,vf2d{cos(angleToCursor)*"Ranger.Ability 1.ArrowSpd"_F,float(sin(angleToCursor)*"Ranger.Ability 1.ArrowSpd"_F-PI/8*"Ranger.Ability 1.ArrowSpd"_F)}+movementVelocity/1.5f,12*"Ranger.Ability 1.ArrowRadius"_F/100,int(GetAttack()*"Ranger.Ability 1.DamageMult"_F),OnUpperLevel(),true))); - SetAnimationBasedOnTargetingDirection("SHOOT",angleToCursor); + if(GetClass()&(RANGER|TRAPPER))SetAnimationBasedOnTargetingDirection("SHOOT",angleToCursor); rapidFireTimer=RAPID_FIRE_SHOOT_DELAY; }else{ SetState(State::NORMAL); @@ -1218,7 +1202,11 @@ void Player::SetAnimationBasedOnTargetingDirection(const std::string_view animat } SetFacingDirection(facingKey); - UpdateAnimation(std::format("{}_{}_{}",Capitalize(GetClassName()),animation_name,facingChar)); + + std::string newAnimState{std::format("{}_{}_{}",Capitalize(GetClassName()),animation_name,facingChar)}; + + if(animation.HasState(newAnimState))UpdateAnimation(newAnimState); + else ERR(std::format("WARNING! Animation {} does not exist on the player! THIS SHOULD NOT BE HAPPENING!",newAnimState)); } void Player::ApplyIframes(float duration){ @@ -1329,7 +1317,7 @@ void EntityStats::RecalculateEquipStats(){ for(auto&[key,size]:ItemAttribute::attributes){ equipStats.A(key)+=equip.lock()->GetStats().A_Read(key); equipStats.A(key)+=equip.lock()->RandomStats().A_Read(key); - if(slot==EquipSlot::RING2&&equip.lock()->HasEnchant()){ //Special doubling-up ring logic. + if(slot&EquipSlot::RING2&&equip.lock()->HasEnchant()){ //Special doubling-up ring logic. const bool IsNonCommonEnchant{equip.lock()->HasEnchant()&&equip.lock()->GetEnchant().value().Category()!=ItemEnchantInfo::ItemEnchantCategory::GENERAL}; const bool Slot1HasSameEnchant{!ISBLANK(Inventory::GetEquip(EquipSlot::RING1))&&Inventory::GetEquip(EquipSlot::RING1).lock()->HasEnchant()&&Inventory::GetEquip(EquipSlot::RING1).lock()->GetEnchant().value().Name()==equip.lock()->GetEnchant().value().Name()}; if(!IsNonCommonEnchant||!Slot1HasSameEnchant)equipStats.A(key)+=equip.lock()->GetEnchant().value().GetAttribute(key); @@ -1419,15 +1407,37 @@ const float Player::GetDamageReductionFromArmor()const{ void Player::RecalculateEquipStats(){ stats.RecalculateEquipStats(); enchantList.clear(); + enchantAbilityList.clear(); const auto EquipSlotHasEnchant=[](const EquipSlot slot,const std::string_view enchantToCheck){return !Inventory::GetEquip(slot).expired()&&Inventory::GetEquip(slot).lock()->GetEnchant().has_value()&&Inventory::GetEquip(slot).lock()->GetEnchant().value().Name()==enchantToCheck;}; for(int i=int(EquipSlot::RING2);i>=int(EquipSlot::HELMET);i>>=1){ //I'm inverting the order of this equip slot check because typically the player will have enchants in the ring slots, so check those earlier to terminate the loop quicker. EquipSlot slot=EquipSlot(i); - if(!ISBLANK(Inventory::GetEquip(slot))&&Inventory::GetEquip(slot).lock()->GetEnchant().has_value())enchantList.insert(Inventory::GetEquip(slot).lock()->GetEnchant().value().Name()); + if(!ISBLANK(Inventory::GetEquip(slot))&&Inventory::GetEquip(slot).lock()->GetEnchant().has_value()){ + const ItemEnchant enchant{*Inventory::GetEquip(slot).lock()->GetEnchant()}; + enchantList.insert(enchant.Name()); + if(enchant.Ability())enchantAbilityList.insert((*enchant.Ability()).get().name); + } } - if(GetClass()==RANGER){ - GetAbility2().precastInfo.castTime=Ranger::ability2.precastInfo.castTime; //This resets the cast time of this ability since it's possible for an enchant to modify it. + #pragma region Reset Abilities before Enchant Modifications + Warrior::ResetToOriginalAbilities(); + Ranger::ResetToOriginalAbilities(); + Wizard::ResetToOriginalAbilities(); + Thief::ResetToOriginalAbilities(); + Trapper::ResetToOriginalAbilities(); + Witch::ResetToOriginalAbilities(); + #pragma endregion + + if(GetClass()&RANGER){ if(HasEnchant("Mega Charged Shot"))GetAbility2().precastInfo.castTime+="Mega Charged Shot"_ENC["CAST TIME INCREASE"]; + if(HasEnchant("Multi-Multishot")){ + GetAbility3().MAX_CHARGES="Multi-Multishot"_ENC["EXTRA CHARGE COUNT"]; + GetAbility3().COOLDOWN_TIME-=GetAbility3().COOLDOWN_TIME*"Multi-Multishot"_ENC["COOLDOWN REDUCTION PCT"]/100.f; + } + } + + for(const std::reference_wrapper&a:GetAbilities()){ + if(a.get().itemAbility)continue; + if(a.get().chargesTestingModeEnabled()||!ability.keyReleaseRequiredToReactivate); const bool HasEnoughOfItem=!ability.itemAbility|| &ability==&useItem1&&game->GetLoadoutItem(0).lock()->Amt()>0|| &ability==&useItem2&&game->GetLoadoutItem(1).lock()->Amt()>0|| &ability==&useItem3&&game->GetLoadoutItem(2).lock()->Amt()>0; if(ability.name!="???"){ if(CanAct(ability)){ - if(ability.cooldown==0&&GetMana()>=ability.manaCost){ + if(ability.charges>=1&&GetMana()>=ability.manaCost){ if(key.Held()||key.Released()&&&ability==castPrepAbility&&GetState()==State::PREP_CAST){ #pragma region Tutorial Defensive/Use Ability Tasks if(&ability==&GetRightClickAbility()){ @@ -1821,9 +1832,11 @@ void Player::CheckAndPerformAbility(Ability&ability,InputGroup key){ #pragma endregion if(AllowedToCast&&ability.action(this,{})){ bool allowed=ability.actionPerformedDuringCast; - ability.cooldown=ability.GetCooldownTime(); + if(ability.cooldown==0.f)ability.cooldown=ability.GetCooldownTime(); + ability.charges--; CancelCast(); ConsumeMana(ability.manaCost); + ability.keyReleaseRequiredToReactivate=true; OnAbilityUse(ability); }else if(ability.precastInfo.precastTargetingRequired&&GetState()==State::NORMAL&&HasEnoughOfItem){ @@ -1994,4 +2007,12 @@ const vf2d Player::GetFacingDirVector()const{ const int Player::RemainingRapidFireShots()const{ return remainingRapidFireShots; +} + +const std::vector>Player::GetAbilities(){ + return {GetRightClickAbility(),GetAbility1(),GetAbility2(),GetAbility3(),GetAbility4(),GetItem1(),GetItem2(),GetItem3()}; +} + +const bool Player::HasEnchantWithAbilityAffected(const std::string_view abilityName)const{ + return enchantAbilityList.count(std::string(abilityName)); } \ No newline at end of file diff --git a/Adventures in Lestoria/Player.h b/Adventures in Lestoria/Player.h index 300f2513..3a17267b 100644 --- a/Adventures in Lestoria/Player.h +++ b/Adventures in Lestoria/Player.h @@ -308,6 +308,8 @@ public: const vf2d GetFacingDirVector()const; //Returns a normalized vector based on the facing direction of the character. Ex. {0,-1} for north and {1,0} for east. const bool PoisonArrowAutoAttackReady()const; //NOTE: Also checks to make sure we have the enchant built-in... const int RemainingRapidFireShots()const; + const std::vector>GetAbilities();//Returns player defensive, core abilities (1-4) and item abilities. + const bool HasEnchantWithAbilityAffected(const std::string_view abilityName)const; //Returns whether or not the player has an enchant that affects the provided name. private: int hp="Warrior.BaseHealth"_I; int mana="Player.BaseMana"_I; @@ -385,6 +387,7 @@ private: std::unordered_setmyClass{}; float daggerThrowWaitTimer{INFINITY}; std::unordered_setenchantList; + std::unordered_setenchantAbilityList; //Which abilities are currently affected by our enchants. void OnAbilityUse(const Ability&ability); //Callback when an ability successfully is used and has gone on cooldown. const bool LastReserveEnchantConditionsMet()const; float poisonArrowLastParticleTimer{}; @@ -471,6 +474,10 @@ struct Warrior:Player{ std::string&GetIdleEAnimation()override; std::string&GetIdleSAnimation()override; std::string&GetIdleWAnimation()override; + static void CreateOriginalCopies(); + static void ResetToOriginalAbilities(); +private: + static Ability original_rightClickAbility,original_ability1,original_ability2,original_ability3,original_ability4; }; #pragma endregion @@ -502,6 +509,10 @@ struct Thief:Player{ std::string&GetIdleEAnimation()override; std::string&GetIdleSAnimation()override; std::string&GetIdleWAnimation()override; + static void CreateOriginalCopies(); + static void ResetToOriginalAbilities(); +private: + static Ability original_rightClickAbility,original_ability1,original_ability2,original_ability3,original_ability4; }; #pragma endregion @@ -533,6 +544,10 @@ struct Ranger:Player{ std::string&GetIdleEAnimation()override; std::string&GetIdleSAnimation()override; std::string&GetIdleWAnimation()override; + static void CreateOriginalCopies(); + static void ResetToOriginalAbilities(); +private: + static Ability original_rightClickAbility,original_ability1,original_ability2,original_ability3,original_ability4; }; #pragma endregion @@ -564,6 +579,10 @@ struct Trapper:Player{ std::string&GetIdleEAnimation()override; std::string&GetIdleSAnimation()override; std::string&GetIdleWAnimation()override; + static void CreateOriginalCopies(); + static void ResetToOriginalAbilities(); +private: + static Ability original_rightClickAbility,original_ability1,original_ability2,original_ability3,original_ability4; }; #pragma endregion @@ -595,6 +614,10 @@ struct Wizard:Player{ std::string&GetIdleEAnimation()override; std::string&GetIdleSAnimation()override; std::string&GetIdleWAnimation()override; + static void CreateOriginalCopies(); + static void ResetToOriginalAbilities(); +private: + static Ability original_rightClickAbility,original_ability1,original_ability2,original_ability3,original_ability4; }; #pragma endregion @@ -626,6 +649,10 @@ struct Witch:Player{ std::string&GetIdleEAnimation()override; std::string&GetIdleSAnimation()override; std::string&GetIdleWAnimation()override; + static void CreateOriginalCopies(); + static void ResetToOriginalAbilities(); +private: + static Ability original_rightClickAbility,original_ability1,original_ability2,original_ability3,original_ability4; }; #pragma endregion @@ -684,4 +711,4 @@ struct Witch:Player{ {#class".Ability 3.Precast Time"_F,#class".Ability 3.Casting Range"_I/100.f*24,#class".Ability 3.Casting Size"_I/100.f*24}, \ bool(#class".Ability 3.CancelCast"_I) \ }; \ - class::ability4; \ No newline at end of file + class::ability4; \ No newline at end of file diff --git a/Adventures in Lestoria/Ranger.cpp b/Adventures in Lestoria/Ranger.cpp index 1a4f8876..107932c8 100644 --- a/Adventures in Lestoria/Ranger.cpp +++ b/Adventures in Lestoria/Ranger.cpp @@ -59,6 +59,7 @@ void Ranger::Initialize(){ Ranger::walk_e="RANGER_WALK_E"; Ranger::walk_s="RANGER_WALK_S"; Ranger::walk_w="RANGER_WALK_W"; + Ranger::ability4={}; } SETUP_CLASS(Ranger) diff --git a/Adventures in Lestoria/Thief.cpp b/Adventures in Lestoria/Thief.cpp index ce208aae..305f7bb3 100644 --- a/Adventures in Lestoria/Thief.cpp +++ b/Adventures in Lestoria/Thief.cpp @@ -60,6 +60,7 @@ void Thief::Initialize(){ Thief::walk_e="THIEF_WALK_E"; Thief::walk_s="THIEF_WALK_S"; Thief::walk_w="THIEF_WALK_W"; + Thief::ability4={}; } SETUP_CLASS(Thief) diff --git a/Adventures in Lestoria/Trapper.cpp b/Adventures in Lestoria/Trapper.cpp index 8e836187..1bf8b251 100644 --- a/Adventures in Lestoria/Trapper.cpp +++ b/Adventures in Lestoria/Trapper.cpp @@ -60,6 +60,7 @@ void Trapper::Initialize(){ Trapper::walk_e="TRAPPER_WALK_E"; Trapper::walk_s="TRAPPER_WALK_S"; Trapper::walk_w="TRAPPER_WALK_W"; + Trapper::ability4={}; } SETUP_CLASS(Trapper) diff --git a/Adventures in Lestoria/Version.h b/Adventures in Lestoria/Version.h index eb032fc4..23625c67 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 10846 +#define VERSION_BUILD 10901 #define stringify(a) stringify_(a) #define stringify_(a) #a diff --git a/Adventures in Lestoria/Witch.cpp b/Adventures in Lestoria/Witch.cpp index 13da3570..f5491c2f 100644 --- a/Adventures in Lestoria/Witch.cpp +++ b/Adventures in Lestoria/Witch.cpp @@ -60,6 +60,7 @@ void Witch::Initialize(){ Witch::walk_e="WITCH_WALK_E"; Witch::walk_s="WITCH_WALK_S"; Witch::walk_w="WITCH_WALK_W"; + Witch::ability4={}; } SETUP_CLASS(Witch) diff --git a/Adventures in Lestoria/Wizard.cpp b/Adventures in Lestoria/Wizard.cpp index 3743ac6e..9fbb47ab 100644 --- a/Adventures in Lestoria/Wizard.cpp +++ b/Adventures in Lestoria/Wizard.cpp @@ -59,6 +59,7 @@ void Wizard::Initialize(){ Wizard::walk_e="WIZARD_WALK_E"; Wizard::walk_s="WIZARD_WALK_S"; Wizard::walk_w="WIZARD_WALK_W"; + Wizard::ability4={}; } SETUP_CLASS(Wizard) diff --git a/Adventures in Lestoria/assets/Campaigns/2_1.tmx b/Adventures in Lestoria/assets/Campaigns/2_1.tmx index 41d17f1c..107a5b13 100644 --- a/Adventures in Lestoria/assets/Campaigns/2_1.tmx +++ b/Adventures in Lestoria/assets/Campaigns/2_1.tmx @@ -2,7 +2,7 @@ - + diff --git a/Adventures in Lestoria/assets/Campaigns/2_2.tmx b/Adventures in Lestoria/assets/Campaigns/2_2.tmx index ea1ac58a..9b450ba0 100644 --- a/Adventures in Lestoria/assets/Campaigns/2_2.tmx +++ b/Adventures in Lestoria/assets/Campaigns/2_2.tmx @@ -2,7 +2,7 @@ - + diff --git a/Adventures in Lestoria/assets/Campaigns/2_3.tmx b/Adventures in Lestoria/assets/Campaigns/2_3.tmx index a703f541..5ddcb18e 100644 --- a/Adventures in Lestoria/assets/Campaigns/2_3.tmx +++ b/Adventures in Lestoria/assets/Campaigns/2_3.tmx @@ -2,7 +2,7 @@ - + diff --git a/Adventures in Lestoria/assets/Campaigns/2_4.tmx b/Adventures in Lestoria/assets/Campaigns/2_4.tmx index f97ad88e..a98d5c59 100644 --- a/Adventures in Lestoria/assets/Campaigns/2_4.tmx +++ b/Adventures in Lestoria/assets/Campaigns/2_4.tmx @@ -2,7 +2,7 @@ - + diff --git a/Adventures in Lestoria/assets/Campaigns/2_5.tmx b/Adventures in Lestoria/assets/Campaigns/2_5.tmx index 8a7591aa..efaee291 100644 --- a/Adventures in Lestoria/assets/Campaigns/2_5.tmx +++ b/Adventures in Lestoria/assets/Campaigns/2_5.tmx @@ -2,7 +2,7 @@ - + diff --git a/Adventures in Lestoria/assets/Campaigns/2_6.tmx b/Adventures in Lestoria/assets/Campaigns/2_6.tmx index b4744f16..92b114c3 100644 --- a/Adventures in Lestoria/assets/Campaigns/2_6.tmx +++ b/Adventures in Lestoria/assets/Campaigns/2_6.tmx @@ -2,7 +2,7 @@ - + diff --git a/Adventures in Lestoria/assets/Campaigns/2_7.tmx b/Adventures in Lestoria/assets/Campaigns/2_7.tmx index 39810ad8..3594b8d8 100644 --- a/Adventures in Lestoria/assets/Campaigns/2_7.tmx +++ b/Adventures in Lestoria/assets/Campaigns/2_7.tmx @@ -2,7 +2,7 @@ - + diff --git a/Adventures in Lestoria/assets/Campaigns/2_8.tmx b/Adventures in Lestoria/assets/Campaigns/2_8.tmx index cd6a6328..4dfad605 100644 --- a/Adventures in Lestoria/assets/Campaigns/2_8.tmx +++ b/Adventures in Lestoria/assets/Campaigns/2_8.tmx @@ -2,7 +2,7 @@ - + diff --git a/Adventures in Lestoria/assets/Campaigns/2_B1.tmx b/Adventures in Lestoria/assets/Campaigns/2_B1.tmx index d4e4cc71..1238bf8a 100644 --- a/Adventures in Lestoria/assets/Campaigns/2_B1.tmx +++ b/Adventures in Lestoria/assets/Campaigns/2_B1.tmx @@ -2,7 +2,7 @@ - + diff --git a/Adventures in Lestoria/assets/config/audio/bgm.txt b/Adventures in Lestoria/assets/config/audio/bgm.txt index af399fd6..e706fd1b 100644 --- a/Adventures in Lestoria/assets/config/audio/bgm.txt +++ b/Adventures in Lestoria/assets/config/audio/bgm.txt @@ -117,4 +117,20 @@ BGM Default Volume = 20%,50%,20%,70% } } + + #Song title followed by filenames for individual parts + mountain + { + Track Name = Foresty + + channel[0]=AiL_mountain2.ogg + + # Transition time between one phase to the next. + Fade Time = 2.0 + + Events + { + Default Volume = 70% + } + } } \ No newline at end of file diff --git a/Adventures in Lestoria/assets/config/credits.txt b/Adventures in Lestoria/assets/config/credits.txt index 67d9cfd0..8860427c 100644 --- a/Adventures in Lestoria/assets/config/credits.txt +++ b/Adventures in Lestoria/assets/config/credits.txt @@ -6,7 +6,7 @@ Credits LINE[3]="Production & Programming" LINE[4]="#C03EE5sigonasr2#FFFFFF" LINE[5]=" " - LINE[6]="Game Designer" + LINE[6]="Game Design & Level Creation" LINE[7]="#7DDA58Quapsel#FFFFFF" LINE[8]=" " LINE[9]="Music Design" diff --git a/Adventures in Lestoria/assets/music/AiL_mountain2.ogg b/Adventures in Lestoria/assets/music/AiL_mountain2.ogg new file mode 100644 index 00000000..ab005f83 Binary files /dev/null and b/Adventures in Lestoria/assets/music/AiL_mountain2.ogg differ diff --git a/Adventures in Lestoria/util.cpp b/Adventures in Lestoria/util.cpp index dd98839b..4d8455e5 100644 --- a/Adventures in Lestoria/util.cpp +++ b/Adventures in Lestoria/util.cpp @@ -212,4 +212,9 @@ void util::turn_towards_direction(float&angle,float target,float rate) if(diff>0&&newAngleDiff<0|| diff<0&&newAngleDiff>0)angle=fmod(target,2*PI); //We have crossed the angle difference threshold and can safely say we reached it. -} \ No newline at end of file +} + +std::wstring util::to_wstring(const std::string&str){ + return {str.begin(),str.end()}; +} + diff --git a/Adventures in Lestoria/util.h b/Adventures in Lestoria/util.h index e251c7f3..0c6c716c 100644 --- a/Adventures in Lestoria/util.h +++ b/Adventures in Lestoria/util.h @@ -63,6 +63,16 @@ namespace olc::util{ const float distance(const vf2d&point1,const vf2d&point2); //Modifies angle argument directly to turn towards said direction. rate is in radians, please multiply by fElapsedTime if you intend to use this per frame. void turn_towards_direction(float&angle,float target,float rate); + std::wstring to_wstring(const std::string&str); + + template + std::string vformat(std::string str,_Args&..._Vals){ + return std::vformat(str,std::make_format_args(_Vals...)); + } + template + std::wstring wformat(std::string str,_Args&..._Vals){ + return util::to_wstring(std::vformat(str,std::make_format_args(_Vals...))); + } } template diff --git a/x64/Release/Adventures in Lestoria.exe b/x64/Release/Adventures in Lestoria.exe index 84cba21e..1eafd0c8 100644 Binary files a/x64/Release/Adventures in Lestoria.exe and b/x64/Release/Adventures in Lestoria.exe differ