diff --git a/Adventures in Lestoria Tests/EnchantTests.cpp b/Adventures in Lestoria Tests/EnchantTests.cpp index d5a04b78..a22992d0 100644 --- a/Adventures in Lestoria Tests/EnchantTests.cpp +++ b/Adventures in Lestoria Tests/EnchantTests.cpp @@ -1238,5 +1238,19 @@ namespace EnchantTests 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."); } + TEST_METHOD(SummonCometNoEnchantCheck){ + Game::ChangeClass(player,WIZARD); + Assert::AreEqual("Wizard.Ability 3.Cooldown"_F,player->GetAbility3().GetCooldownTime(),L"Meteor cooldown time is normal."); + } + TEST_METHOD(SummonCometEnchantCheck){ + Game::ChangeClass(player,WIZARD); + Game::GiveAndEquipEnchantedRing("Summon Comet"); + Assert::AreEqual("Wizard.Ability 3.Cooldown"_F+"Summon Comet"_ENC["COOLDOWN REDUCTION"],player->GetAbility3().GetCooldownTime(),L"Meteor cooldown time reduced with the Summon Comet enchant."); + } + TEST_METHOD(SolarFlareEnchantCheck){ + Game::ChangeClass(player,WIZARD); + Game::GiveAndEquipEnchantedRing("Solar Flare"); + Assert::AreEqual("Wizard.Ability 3.Cooldown"_F+"Solar Flare"_ENC["COOLDOWN INCREASE"],player->GetAbility3().GetCooldownTime(),L"Meteor cooldown time increased with the Solar Flare enchant."); + } }; } diff --git a/Adventures in Lestoria Tests/ItemTests.cpp b/Adventures in Lestoria Tests/ItemTests.cpp index b82bb3fd..5414e7e2 100644 --- a/Adventures in Lestoria Tests/ItemTests.cpp +++ b/Adventures in Lestoria Tests/ItemTests.cpp @@ -248,5 +248,32 @@ namespace ItemTests if(ItemEnchantInfo::ENCHANT_LIST.at(slimeKingRing.lock()->GetEnchant().value().Name()).GetClass().has_value())Assert::AreEqual(int(player->GetClass()),int(ItemEnchantInfo::ENCHANT_LIST.at(slimeKingRing.lock()->GetEnchant().value().Name()).GetClass().value())); //Validate enchant is only for this class if it's a class-based ability. } } + TEST_METHOD(AccessoryAntiCompatibilityCheck){ + std::weak_ptrsummonCometRing{Inventory::AddItem("Ring of the Slime King"s)}; + summonCometRing.lock()->EnchantItem("Summon Comet"); + std::weak_ptrsolarFlareRing{Inventory::AddItem("Ring of the Slime King"s)}; + solarFlareRing.lock()->EnchantItem("Solar Flare"); + std::weak_ptrextraRing{Inventory::AddItem("Ring of the Slime King"s)}; + std::weak_ptrextraRing2{Inventory::AddItem("Ring of the Slime King"s)}; + + Inventory::EquipItem(summonCometRing,EquipSlot::RING1); + Assert::AreEqual(false,Item::SelectedEquipIsDifferent(solarFlareRing,EquipSlot::RING2),L"The game should deny equipping the Solar Flare ring with the Summon Comet ring equipped."); + Inventory::EquipItem(summonCometRing,EquipSlot::RING2); + Assert::AreEqual(false,Item::SelectedEquipIsDifferent(solarFlareRing,EquipSlot::RING1),L"The game should deny equipping the Solar Flare ring with the Summon Comet ring equipped."); + Inventory::EquipItem(solarFlareRing,EquipSlot::RING2); + Assert::AreEqual(false,Item::SelectedEquipIsDifferent(summonCometRing,EquipSlot::RING1),L"The game should deny equipping the Summon Comet ring with the Solar Flare ring equipped."); + Inventory::EquipItem(solarFlareRing,EquipSlot::RING1); + Assert::AreEqual(false,Item::SelectedEquipIsDifferent(summonCometRing,EquipSlot::RING2),L"The game should deny equipping the Summon Comet ring with the Solar Flare ring equipped."); + Inventory::EquipItem(extraRing,EquipSlot::RING1); + Assert::AreEqual(true,Item::SelectedEquipIsDifferent(summonCometRing,EquipSlot::RING2),L"The game should allow equipping the Summon Comet ring when the Solar Flare ring is not present."); + Assert::AreEqual(true,Item::SelectedEquipIsDifferent(solarFlareRing,EquipSlot::RING2),L"The game should allow equipping the Solar Flare ring when the Summon Comet ring is not present."); + Inventory::EquipItem(extraRing,EquipSlot::RING2); + Assert::AreEqual(true,Item::SelectedEquipIsDifferent(summonCometRing,EquipSlot::RING1),L"The game should allow equipping the Summon Comet ring when the Solar Flare ring is not present."); + Assert::AreEqual(true,Item::SelectedEquipIsDifferent(solarFlareRing,EquipSlot::RING1),L"The game should allow equipping the Solar Flare ring when the Summon Comet ring is not present."); + Assert::AreEqual(true,Item::SelectedEquipIsDifferent(extraRing2,EquipSlot::RING1),L"The game should allow equipping of any two normal rings that are not the same ring."); + Assert::AreEqual(false,Item::SelectedEquipIsDifferent(extraRing,EquipSlot::RING1),L"The game should not allow equipping the same ring if it's already equipped."); + Inventory::UnequipItem(EquipSlot::RING2); + Assert::AreEqual(true,Item::SelectedEquipIsDifferent(extraRing,EquipSlot::RING1),L"The game should allow equipping a ring to either blank slot if they're open."); + } }; } diff --git a/Adventures in Lestoria/CharacterMenuWindow.cpp b/Adventures in Lestoria/CharacterMenuWindow.cpp index e12e5f85..47d37be2 100644 --- a/Adventures in Lestoria/CharacterMenuWindow.cpp +++ b/Adventures in Lestoria/CharacterMenuWindow.cpp @@ -76,31 +76,9 @@ namespace CharacterMenuWindow{ std::shared_ptrGenerateItemDisplay(std::shared_ptrparent,int invIndex,const std::weak_ptrit){ auto component=parent->ADD("Equip Item "+std::to_string(invIndex),T)(geom2d::rect{{2,2+invIndex*29.f},{120-15,28}},it, [&](MenuFuncData data){ - const auto SelectedEquipIsDifferent=[](std::weak_ptrcomp){ - EquipSlot slot=EquipSlot(comp.lock()->I(Attribute::EQUIP_TYPE)); - std::weak_ptrcurrentItem=Inventory::GetEquip(slot); - - switch(slot){ - case EquipSlot::RING1: - case EquipSlot::RING2:{ - std::weak_ptrotherItem; - - if(slot&EquipSlot::RING1)otherItem=Inventory::GetEquip(EquipSlot::RING2); - else - if(slot&EquipSlot::RING2)otherItem=Inventory::GetEquip(EquipSlot::RING1); - return ISBLANK(otherItem)|| - (&*comp.lock()->GetItem().lock()!=&*otherItem.lock()&& - &*comp.lock()->GetItem().lock()!=&*currentItem.lock()); - }break; - default:{ - return &*comp.lock()->GetItem().lock()!=&*currentItem.lock(); - } - } - }; - std::weak_ptrcomp=DYNAMIC_POINTER_CAST(data.component.lock()); if(!comp.expired()){ - if(SelectedEquipIsDifferent(comp)){ //If we find that the opposite ring slot is equipped to us, this would be an item swap or the exact same ring, therefore no stat calculations apply. + if(Item::SelectedEquipIsDifferent(comp.lock()->GetItem(),EquipSlot(comp.lock()->I(Attribute::EQUIP_TYPE)))){ //If we find that the opposite ring slot is equipped to us, this would be an item swap or the exact same ring, therefore no stat calculations apply. Inventory::EquipItem(comp.lock()->GetItem(),EquipSlot(comp.lock()->I(Attribute::EQUIP_TYPE))); #pragma region Fully Decked Out Achievement @@ -229,28 +207,6 @@ void Menu::InitializeCharacterMenuWindow(){ equip->SetHoverFunc( [&](MenuFuncData data){ - const auto SelectedEquipIsDifferent=[](std::weak_ptrcomp){ - EquipSlot slot=EquipSlot(comp.lock()->I(Attribute::EQUIP_TYPE)); - std::weak_ptrcurrentItem=Inventory::GetEquip(slot); - - switch(slot){ - case EquipSlot::RING1: - case EquipSlot::RING2:{ - std::weak_ptrotherItem; - - if(slot&EquipSlot::RING1)otherItem=Inventory::GetEquip(EquipSlot::RING2); - else - if(slot&EquipSlot::RING2)otherItem=Inventory::GetEquip(EquipSlot::RING1); - return ISBLANK(otherItem)|| - (&*comp.lock()->GetItem().lock()!=&*otherItem.lock()&& - &*comp.lock()->GetItem().lock()!=&*currentItem.lock()); - }break; - default:{ - return &*comp.lock()->GetItem().lock()!=&*currentItem.lock(); - } - } - }; - if(!data.component.lock()->GetSubcomponentParent().expired())return true; std::weak_ptrbutton=DYNAMIC_POINTER_CAST(data.component.lock()); if(!button.expired()){ @@ -269,7 +225,7 @@ void Menu::InitializeCharacterMenuWindow(){ if(slot&EquipSlot::RING1)otherItem=Inventory::GetEquip(EquipSlot::RING2); else if(slot&EquipSlot::RING2)otherItem=Inventory::GetEquip(EquipSlot::RING1); - if(SelectedEquipIsDifferent(button.lock())){ //If we find that the opposite ring slot is equipped to us, this would be an item swap or the exact same ring, therefore no stat calculations apply. + if(Item::SelectedEquipIsDifferent(button.lock()->GetItem(),slot)){ //If we find that the opposite ring slot is equipped to us, this would be an item swap or the exact same ring, therefore no stat calculations apply. Inventory::EquipItem(buttonItem,slot); for(int counter=0;const CharacterMenuWindow::AttributeData&attribute:CharacterMenuWindow::displayAttrs){ std::weak_ptrstatDisplayLabel=Component(CHARACTER_MENU,"Attribute "+std::string(ItemAttribute::Get(attribute.attrName).Name())+" Label"); diff --git a/Adventures in Lestoria/Effect.h b/Adventures in Lestoria/Effect.h index b6fdf71d..c681fbb5 100644 --- a/Adventures in Lestoria/Effect.h +++ b/Adventures in Lestoria/Effect.h @@ -88,26 +88,42 @@ protected: float original_fadeOutTime; float original_fadeInTime{}; EffectType type{EffectType::NONE}; -private: Animate2D::Animationanimation; Animate2D::AnimationState internal_animState; +private: bool upperLevel=false; double aliveTime{}; }; struct Meteor:Effect{ - Meteor(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); + enum MeteorSetting{ + METEOR, + COMET, + SOLAR_FLARE, + }; + Meteor(const vf2d pos,const float lifetime,const bool upperLevel,const MeteorSetting setting,const float fadeout=0.0f,const vf2d spd={},const Pixel col=WHITE,const float rotation=0,const float rotationSpd=0,const bool additiveBlending=false); float startLifetime=0; bool shakeField=false; bool Update(float fElapsedTime)override; void Draw(const Pixel blendCol)const override; +private: + int meteorImpactParticles{}; + float randomColorTintR{}; + float randomColorTintG{}; + float randomColorTintB{}; + float meteorRadius{}; + float fallSpdMult{1.f}; + float damageMult{1.f}; + float fireRingLifetime{}; + std::string meteorCrashSFX{}; }; struct PulsatingFire:Effect{ - PulsatingFire(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); + PulsatingFire(vf2d pos,float lifetime,const float radius,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); std::vectorpulsatingFireValues; float lastParticleTimer=0; float lastDamageTimer=0; + float radius; bool Update(float fElapsedTime)override; void Draw(const Pixel blendCol)const override; }; diff --git a/Adventures in Lestoria/Item.cpp b/Adventures in Lestoria/Item.cpp index aa092ffe..e8bd8989 100644 --- a/Adventures in Lestoria/Item.cpp +++ b/Adventures in Lestoria/Item.cpp @@ -1461,4 +1461,37 @@ const Pixel Item::GetDisplayNameColor()const{ Pixel col{WHITE}; if(HasEnchant())col=enchant.value().DisplayCol(); return col; +} +const bool Item::SelectedEquipIsDifferent(const std::weak_ptrequipAttemptingToEquip,const EquipSlot slotToEquipTo){ + std::weak_ptrcurrentItem=Inventory::GetEquip(slotToEquipTo); + switch(slotToEquipTo){ + case EquipSlot::RING1: + case EquipSlot::RING2:{ + std::weak_ptrotherItem; + + if(slotToEquipTo&EquipSlot::RING1)otherItem=Inventory::GetEquip(EquipSlot::RING2); + else + if(slotToEquipTo&EquipSlot::RING2)otherItem=Inventory::GetEquip(EquipSlot::RING1); + + const auto EquipIsNotSameAsOppositeRingSlot=[&equip=equipAttemptingToEquip,&otherItem](){ + return &*equip.lock()!=&*otherItem.lock(); + }; + const auto EquipIsNotSameAsCurrentRingSlot=[&equip=equipAttemptingToEquip,¤tItem](){ + return &*equip.lock()!=&*currentItem.lock(); + }; + const auto OneOfBothRingsDoesNotHaveEnchant=[&equip=equipAttemptingToEquip,&otherItem](){ + return !equip.lock()->HasEnchant()||!otherItem.lock()->HasEnchant(); + }; + const auto BothRingsAreCompatible=[&equip=equipAttemptingToEquip,&otherItem](){ + return !(equip.lock()->GetEnchant().value().Name()=="Summon Comet"&&otherItem.lock()->GetEnchant().value().Name()=="Solar Flare")&&!(equip.lock()->GetEnchant().value().Name()=="Solar Flare"&&otherItem.lock()->GetEnchant().value().Name()=="Summon Comet"); + }; + return (ISBLANK(otherItem)&&(OneOfBothRingsDoesNotHaveEnchant()||BothRingsAreCompatible())|| + EquipIsNotSameAsOppositeRingSlot()&& + EquipIsNotSameAsCurrentRingSlot()&& + (OneOfBothRingsDoesNotHaveEnchant()||BothRingsAreCompatible())); + }break; + default:{ + return &*equipAttemptingToEquip.lock()!=&*currentItem.lock(); + } + } } \ No newline at end of file diff --git a/Adventures in Lestoria/Item.h b/Adventures in Lestoria/Item.h index 898ae038..ae936605 100644 --- a/Adventures in Lestoria/Item.h +++ b/Adventures in Lestoria/Item.h @@ -264,6 +264,7 @@ public: friend const bool operator==(const IT&lhs,std::weak_ptrrhs){return operator==(rhs,lhs);}; friend const bool operator==(const IT&lhs,std::shared_ptrrhs){return operator==(rhs,lhs);}; const Pixel GetDisplayNameColor()const; + static const bool SelectedEquipIsDifferent(const std::weak_ptrequipAttemptingToEquip,const EquipSlot slotToEquipTo); }; class Inventory{ diff --git a/Adventures in Lestoria/Meteor.cpp b/Adventures in Lestoria/Meteor.cpp index cb9b6b24..fd9546e2 100644 --- a/Adventures in Lestoria/Meteor.cpp +++ b/Adventures in Lestoria/Meteor.cpp @@ -46,26 +46,66 @@ INCLUDE_game INCLUDE_MONSTER_LIST INCLUDE_GFX -Meteor::Meteor(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),startLifetime(lifetime){ +Meteor::Meteor(const vf2d pos,const float lifetime,const bool upperLevel,const MeteorSetting setting,const float fadeout,const vf2d spd,const Pixel col,const float rotation,const float rotationSpd,const bool additiveBlending) + :Effect(pos,lifetime,setting==COMET?"comet.png":"meteor.png",upperLevel,{},fadeout,spd,col,rotation,rotationSpd,additiveBlending),startLifetime(lifetime){ + switch(setting){ + case METEOR:{ + meteorImpactParticles="Wizard.Ability 3.MeteorImpactParticles"_I; + randomColorTintR=255; + randomColorTintG=256*(1-util::random("Wizard.Ability 3.MeteorImpactParticleColorGVariance"_F))*(1-util::random("Wizard.Ability 3.MeteorImpactParticleColorGVariance"_F)); + randomColorTintB="Wizard.Ability 3.MeteorImpactParticleColorBlueRange"_FRange; + meteorRadius="Wizard.Ability 3.MeteorRadius"_F/100*24; + fallSpdMult=1.f; + size=vf2d{meteorRadius/96,meteorRadius/96}; + damageMult="Wizard.Ability 3.MeteorDamageMult"_F; + fireRingLifetime="Wizard.Ability 3.FireRingLifetime"_F; + meteorCrashSFX="Wizard Meteor"; + }break; + case COMET:{ + meteorImpactParticles="Wizard.Ability 3.MeteorImpactParticles"_I/2; + randomColorTintR=0.f; + randomColorTintG=256*(1-util::random("Wizard.Ability 3.MeteorImpactParticleColorGVariance"_F))*(1-util::random("Wizard.Ability 3.MeteorImpactParticleColorGVariance"_F)); + randomColorTintB="Wizard.Ability 3.MeteorImpactParticleColorBlueRange"_FRange*2; //0-254 + meteorRadius="Wizard.Ability 3.MeteorRadius"_F/100*24/2/1.5f; + fallSpdMult="Summon Comet"_ENC["FALL SPEED MULT"]; + size=vf2d{meteorRadius/96*1.5f,meteorRadius/96*1.5f}; + damageMult="Wizard.Ability 3.MeteorDamageMult"_F; + damageMult*=1.f-"Summon Comet"_ENC["DAMAGE REDUCTION PCT"]/100.f; + fireRingLifetime="Wizard.Ability 3.FireRingLifetime"_F; + meteorCrashSFX="Wizard Comet"; + }break; + case SOLAR_FLARE:{ + meteorImpactParticles="Wizard.Ability 3.MeteorImpactParticles"_I*4; + randomColorTintR=255; + randomColorTintG=256*(1-util::random("Wizard.Ability 3.MeteorImpactParticleColorGVariance"_F))*(1-util::random("Wizard.Ability 3.MeteorImpactParticleColorGVariance"_F)); + randomColorTintB="Wizard.Ability 3.MeteorImpactParticleColorBlueRange"_FRange; + meteorRadius="Wizard.Ability 3.MeteorRadius"_F/100*24*2; + fallSpdMult=1.f; + size=vf2d{meteorRadius/96,meteorRadius/96}; + damageMult="Solar Flare"_ENC["METEOR ATTACK"]/100.f; + fireRingLifetime="Wizard.Ability 3.FireRingLifetime"_F*2; + meteorCrashSFX="Wizard Meteor"; + this->col=RED; + }break; + } + this->lifetime/=fallSpdMult; + startLifetime=this->lifetime; } bool Meteor::Update(float fElapsedTime){ if(lifetime<=0&&!shakeField){ shakeField=true; game->SetupWorldShake("Wizard.Ability 3.WorldShakeTime"_F); - vf2d meteorOffset=pos+vf2d{lifetime*"Wizard.Ability 3.MeteorXMovementMult"_I,lifetime*"Wizard.Ability 3.MeteorYMovementMult"_I}*"Wizard.Ability 3.MeteorStartingDist"_F-vf2d{0,"Wizard.Ability 3.MeteorRadius"_F/100*12}; - for(int i=0;i<"Wizard.Ability 3.MeteorImpactParticles"_I;i++){ + vf2d meteorOffset=pos+vf2d{lifetime*"Wizard.Ability 3.MeteorXMovementMult"_I,lifetime*"Wizard.Ability 3.MeteorYMovementMult"_I}*"Wizard.Ability 3.MeteorStartingDist"_F/fallSpdMult-vf2d{0,meteorRadius/2}; + for(int i=0;iAddEffect(std::make_unique(effectPos,0,"circle.png",OnUpperLevel(),vf2d{util::random(2)+1,util::random(3)+1},util::random(3)+1,vf2d{util::random(10)-5,-util::random(20)-5},Pixel{255,uint8_t(randomColorTintG),uint8_t(randomColorTintB),uint8_t("Wizard.Ability 3.MeteorImpactParticleAlphaRange"_FRange)},0,0,true),effectPos.yAddEffect(std::make_unique(effectPos,0,"circle.png",OnUpperLevel(),vf2d{util::random(2)+1,util::random(3)+1},util::random(3)+1,vf2d{util::random(10)-5,-util::random(20)-5},Pixel{uint8_t(randomColorTintR),uint8_t(randomColorTintG),uint8_t(randomColorTintB),uint8_t("Wizard.Ability 3.MeteorImpactParticleAlphaRange"_FRange)},0,0,true),effectPos.yHurt(pos,"Wizard.Ability 3.MeteorRadius"_F/100*24,int(game->GetPlayer()->GetAttack()*"Wizard.Ability 3.MeteorDamageMult"_F),OnUpperLevel(),0,HurtType::MONSTER,HurtFlag::PLAYER_ABILITY); - game->AddEffect(std::make_unique(pos,"Wizard.Ability 3.FireRingLifetime"_F,"fire_ring1.png",OnUpperLevel(),vf2d{"Wizard.Ability 3.MeteorRadius"_F/100*2,"Wizard.Ability 3.MeteorRadius"_F/100*2},"Wizard.Ability 3.FireRingFadeoutTime"_F),true); - SoundEffect::PlaySFX("Wizard Meteor",pos); + game->Hurt(pos,meteorRadius,int(game->GetPlayer()->GetAttack()*damageMult),OnUpperLevel(),0,HurtType::MONSTER,HurtFlag::PLAYER_ABILITY); + game->AddEffect(std::make_unique(pos,fireRingLifetime,meteorRadius,"fire_ring1.png",OnUpperLevel(),vf2d{meteorRadius/12,meteorRadius/12},"Wizard.Ability 3.FireRingFadeoutTime"_F),true); + SoundEffect::PlaySFX(meteorCrashSFX,pos); } return Effect::Update(fElapsedTime); } @@ -73,11 +113,11 @@ bool Meteor::Update(float fElapsedTime){ void Meteor::Draw(const Pixel blendCol)const{ if(lifetime>0){ 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/fallSpdMult; vf2d centerPoint=pos-vf2d{GFX["circle.png"].Sprite()->width*scale.x/2,GFX["circle.png"].Sprite()->height*scale.y/2}; game->view.DrawDecal(centerPoint+meteorOffset,GFX["circle.png"].Decal(),scale,{0,0,0,192}); } - vf2d meteorOffset=pos+vf2d{lifetime*"Wizard.Ability 3.MeteorXMovementMult"_I,lifetime*"Wizard.Ability 3.MeteorYMovementMult"_I}*"Wizard.Ability 3.MeteorStartingDist"_F-vf2d{0,GetFrame().GetSourceRect().size.y/4.f}*size; + vf2d meteorOffset=pos+vf2d{lifetime*"Wizard.Ability 3.MeteorXMovementMult"_I,lifetime*"Wizard.Ability 3.MeteorYMovementMult"_I}*"Wizard.Ability 3.MeteorStartingDist"_F/fallSpdMult-vf2d{0,GetFrame().GetSourceRect().size.y/4.f}*size; if(lifetime<=0){ meteorOffset=pos-vf2d{0,GetFrame().GetSourceRect().size.y/4.f}*size; } diff --git a/Adventures in Lestoria/Player.cpp b/Adventures in Lestoria/Player.cpp index 8f4f1311..fe5d4731 100644 --- a/Adventures in Lestoria/Player.cpp +++ b/Adventures in Lestoria/Player.cpp @@ -1537,6 +1537,14 @@ void Player::RecalculateEquipStats(){ if(GetClass()&WIZARD){ if(HasEnchant("Blink Portal"))GetRightClickAbility().COOLDOWN_TIME="Blink Portal"_ENC["COOLDOWN"]; + if(HasEnchant("Summon Comet")){ + GetAbility3().precastInfo.castTime="Summon Comet"_ENC["METEOR CAST TIME"]; + GetAbility3().COOLDOWN_TIME+="Summon Comet"_ENC["COOLDOWN REDUCTION"]; //This is not a typo, we add because the cooldown reduction in the config is NEGATIVE! + } + if(HasEnchant("Solar Flare")){ + GetAbility3().precastInfo.castTime="Solar Flare"_ENC["METEOR CAST TIME"]; + GetAbility3().COOLDOWN_TIME+="Solar Flare"_ENC["COOLDOWN INCREASE"]; + } } for(const std::reference_wrapper&a:GetAbilities()){ diff --git a/Adventures in Lestoria/PulsatingFire.cpp b/Adventures in Lestoria/PulsatingFire.cpp index fb2f2bfe..67ca871d 100644 --- a/Adventures in Lestoria/PulsatingFire.cpp +++ b/Adventures in Lestoria/PulsatingFire.cpp @@ -46,8 +46,8 @@ INCLUDE_game INCLUDE_ANIMATION_DATA INCLUDE_MONSTER_LIST -PulsatingFire::PulsatingFire(vf2d pos, float lifetime, std::string animation, bool upperLevel, vf2d size, float fadeout, vf2d spd, Pixel col, float rotation, float rotationSpd, bool additiveBlending) - :Effect(pos,lifetime,animation,upperLevel,size,fadeout,spd,col,rotation,rotationSpd,additiveBlending){ +PulsatingFire::PulsatingFire(vf2d pos,float lifetime,const float radius,std::string animation,bool upperLevel,vf2d size,float fadeout,vf2d spd,Pixel col,float rotation,float rotationSpd,bool additiveBlending) + :radius(radius),Effect(pos,lifetime,animation,upperLevel,size,fadeout,spd,col,rotation,rotationSpd,additiveBlending){ for(int i=0;i<8;i++){ pulsatingFireValues.push_back(util::random(1)); } @@ -69,7 +69,7 @@ bool PulsatingFire::Update(float fElapsedTime){ } if(lastDamageTimer<=0){ lastDamageTimer="Wizard.Ability 3.FireRingDamageFreq"_F-0.01f; - game->Hurt(pos,"Wizard.Ability 3.MeteorRadius"_F/100*24,int(game->GetPlayer()->GetAttack()*"Wizard.Ability 3.FireRingDamageMult"_F),OnUpperLevel(),0,HurtType::MONSTER); + game->Hurt(pos,radius,int(game->GetPlayer()->GetAttack()*"Wizard.Ability 3.FireRingDamageMult"_F),OnUpperLevel(),0,HurtType::MONSTER); SoundEffect::PlaySFX("Wizard Meteor Flames",pos); } return Effect::Update(fElapsedTime); diff --git a/Adventures in Lestoria/Version.h b/Adventures in Lestoria/Version.h index 411e3d62..6424b55d 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 5 -#define VERSION_BUILD 11332 +#define VERSION_BUILD 11350 #define stringify(a) stringify_(a) #define stringify_(a) #a diff --git a/Adventures in Lestoria/Wizard.cpp b/Adventures in Lestoria/Wizard.cpp index ba34c539..3345e23c 100644 --- a/Adventures in Lestoria/Wizard.cpp +++ b/Adventures in Lestoria/Wizard.cpp @@ -200,7 +200,10 @@ void Wizard::InitializeClassAbilities(){ #pragma region Wizard Ability 3 (Meteor) Wizard::ability3.action= [](Player*p,vf2d pos={}){ - game->AddEffect(std::make_unique(pos,3,"meteor.png",p->OnUpperLevel(),vf2d{"Wizard.Ability 3.MeteorRadius"_F/100/4,"Wizard.Ability 3.MeteorRadius"_F/100/4},"Wizard.Ability 3.MeteorFadeoutTime"_F)); + Meteor::MeteorSetting meteorType{Meteor::METEOR}; + if(p->HasEnchant("Summon Comet"))meteorType=Meteor::COMET; + else if(p->HasEnchant("Solar Flare"))meteorType=Meteor::SOLAR_FLARE; + game->AddEffect(std::make_unique(pos,3,p->OnUpperLevel(),meteorType,"Wizard.Ability 3.MeteorFadeoutTime"_F)); return true; }; #pragma endregion diff --git a/Adventures in Lestoria/assets/comet.png b/Adventures in Lestoria/assets/comet.png new file mode 100644 index 00000000..33368281 Binary files /dev/null and b/Adventures in Lestoria/assets/comet.png differ diff --git a/Adventures in Lestoria/assets/comet.xcf b/Adventures in Lestoria/assets/comet.xcf new file mode 100644 index 00000000..03399f42 Binary files /dev/null and b/Adventures in Lestoria/assets/comet.xcf differ diff --git a/Adventures in Lestoria/assets/config/audio/events.txt b/Adventures in Lestoria/assets/config/audio/events.txt index 4c0a1e63..18a5f6db 100644 --- a/Adventures in Lestoria/assets/config/audio/events.txt +++ b/Adventures in Lestoria/assets/config/audio/events.txt @@ -495,6 +495,12 @@ Events File[0] = wizard_auto1.ogg, 60% File[1] = wizard_auto2.ogg, 60% } + Wizard Comet + { + CombatSound = True + # Specify file names, followed by volume %. Optional min and max pitch adjustment (Defaults are 90%,110%) + File[0] = wizard_meteor.ogg, 100%, 140%, 160% + } Wizard Fire Bolt Shoot { # Specify file names, followed by volume %. Optional min and max pitch adjustment (Defaults are 90%,110%) diff --git a/Adventures in Lestoria/assets/config/gfx/gfx.txt b/Adventures in Lestoria/assets/config/gfx/gfx.txt index 6cf02505..89a49f0b 100644 --- a/Adventures in Lestoria/assets/config/gfx/gfx.txt +++ b/Adventures in Lestoria/assets/config/gfx/gfx.txt @@ -128,6 +128,7 @@ Images GFX_BlackHole = blackhole.png GFX_Portal = portal.png GFX_Flames = FlamesTexture.png + GFX_Comet = comet.png GFX_Thief_Sheet = nico-thief.png GFX_Trapper_Sheet = nico-trapper.png diff --git a/Adventures in Lestoria/assets/config/items/ItemEnchants.txt b/Adventures in Lestoria/assets/config/items/ItemEnchants.txt index aec4bc13..348a4a53 100644 --- a/Adventures in Lestoria/assets/config/items/ItemEnchants.txt +++ b/Adventures in Lestoria/assets/config/items/ItemEnchants.txt @@ -529,13 +529,13 @@ Item Enchants } Summon Comet { - Description = "Meteor cast time reduced to {METEOR CAST TIME} seconds. Meteor attack falls twice as quick. Damage is reduced by {DAMAGE REDUCTION PCT}% and -{COOLDOWN REDUCTION}s cooldown time." + Description = "Meteor cast time reduced to {METEOR CAST TIME} seconds. Meteor attack falls twice as quick. Damage is reduced by {DAMAGE REDUCTION PCT}% and {COOLDOWN REDUCTION}s cooldown time." Affects = Ability 3 METEOR CAST TIME = 0.5s FALL SPEED MULT = 2.0x DAMAGE REDUCTION PCT = 10% - COOLDOWN REDUCTION = 8s + COOLDOWN REDUCTION = -8s # Stat, Lowest, Highest Value # Stat Modifier[0] = ..., 0, 0 diff --git a/Adventures in Lestoria/assets/gamepack.pak b/Adventures in Lestoria/assets/gamepack.pak index d60bfa9c..8817ea08 100644 Binary files a/Adventures in Lestoria/assets/gamepack.pak and b/Adventures in Lestoria/assets/gamepack.pak differ diff --git a/x64/Release/Adventures in Lestoria.exe b/x64/Release/Adventures in Lestoria.exe index 1baac386..2c206efd 100644 Binary files a/x64/Release/Adventures in Lestoria.exe and b/x64/Release/Adventures in Lestoria.exe differ