diff --git a/Adventures in Lestoria Tests/EnchantTests.cpp b/Adventures in Lestoria Tests/EnchantTests.cpp
index d4a45a49..0c65de8e 100644
--- a/Adventures in Lestoria Tests/EnchantTests.cpp
+++ b/Adventures in Lestoria Tests/EnchantTests.cpp
@@ -1184,5 +1184,31 @@ namespace EnchantTests
Assert::AreEqual(992,newMonster3.GetHealth(),L"Monster 3 should take half the damage the first target does with the Percing Bolt Enchant");
Assert::AreEqual(992,newMonster4.GetHealth(),L"Monster 4 should take half the damage the first target does with the Percing Bolt Enchant");
}
+ TEST_METHOD(BlinkPortalNoEnchantCheck){
+ Game::ChangeClass(player,WIZARD);
+ Assert::AreEqual("Wizard.Right Click Ability.Cooldown"_F,player->GetRightClickAbility().GetCooldownTime(),L"The original cooldown time should be normal.");
+ player->SetTestScreenAimingLocation(player->GetPos()+vf2d{16.f,0.f});
+ player->CheckAndPerformAbility(player->GetRightClickAbility(),testKeyboardInput);
+ Game::Update(0.f);
+ Assert::AreEqual(size_t(0),game->GetEffect(EffectType::BLINK_PORTAL).size(),L"There should be no teleport portals spawned.");
+ Assert::AreEqual("Wizard.Right Click Ability.Cooldown"_F,player->GetRightClickAbility().cooldown,L"The cooldown should be normal.");
+ Assert::AreEqual("Wizard.Right Click Ability.Mana Cost"_I,player->GetRightClickAbility().manaCost,L"The mana cost should be normal.");
+ }
+ TEST_METHOD(BlinkPortalEnchantCheck){
+ Game::ChangeClass(player,WIZARD);
+ Game::GiveAndEquipEnchantedRing("Blink Portal");
+ Assert::AreEqual("Blink Portal"_ENC["COOLDOWN"],player->GetRightClickAbility().GetCooldownTime(),L"The original cooldown time should have been modified by the enchant.");
+ player->SetTestScreenAimingLocation(player->GetPos()+vf2d{16.f,0.f});
+ player->CheckAndPerformAbility(player->GetRightClickAbility(),testKeyboardInput);
+ Game::Update(0.f);
+ Assert::AreEqual(size_t(1),game->GetEffect(EffectType::BLINK_PORTAL).size(),L"There should be a teleport portal spawned.");
+ Assert::AreEqual(0.f,player->GetRightClickAbility().cooldown,L"The cooldown should be zero since we can activate Teleport again.");
+ Assert::AreEqual(0,player->GetRightClickAbility().manaCost,L"The mana cost should be zero.");
+ player->CheckAndPerformAbility(player->GetRightClickAbility(),testKeyboardInput);
+ Game::Update(0.25f);
+ Assert::AreEqual(size_t(0),game->GetEffect(EffectType::BLINK_PORTAL).size(),L"Teleport portal should be despawned.");
+ Assert::AreEqual(player->GetRightClickAbility().GetCooldownTime()-0.25f,player->GetRightClickAbility().cooldown,L"The cooldown should be normal again.");
+ Assert::AreEqual("Wizard.Right Click Ability.Mana Cost"_I,player->GetRightClickAbility().manaCost,L"The mana cost should be normal again.");
+ }
};
}
diff --git a/Adventures in Lestoria/Adventures in Lestoria.vcxproj b/Adventures in Lestoria/Adventures in Lestoria.vcxproj
index 02af0dd7..44243217 100644
--- a/Adventures in Lestoria/Adventures in Lestoria.vcxproj
+++ b/Adventures in Lestoria/Adventures in Lestoria.vcxproj
@@ -130,6 +130,7 @@
$(SolutionDir)$(PlatformTarget)\Release
+ ..\CodeAnalysisRuleset.ruleset
$(IncludePath)
@@ -140,11 +141,19 @@
$(VCInstallDir)Auxiliary\VS\UnitTest\include;$(IncludePath)
$(VCInstallDir)Auxiliary\VS\UnitTest\lib;$(LibraryPath)
+ ..\CodeAnalysisRuleset.ruleset
$(VCInstallDir)Auxiliary\VS\UnitTest\include;$(IncludePath)
$(VCInstallDir)Auxiliary\VS\UnitTest\lib;$(LibraryPath)
$(SolutionDir)$(Platform)\$(Configuration)\
+ ..\CodeAnalysisRuleset.ruleset
+
+
+ ..\CodeAnalysisRuleset.ruleset
+
+
+ ..\CodeAnalysisRuleset.ruleset
diff --git a/Adventures in Lestoria/AdventuresInLestoria.cpp b/Adventures in Lestoria/AdventuresInLestoria.cpp
index 61b14c1f..dc39ea1a 100644
--- a/Adventures in Lestoria/AdventuresInLestoria.cpp
+++ b/Adventures in Lestoria/AdventuresInLestoria.cpp
@@ -2222,17 +2222,22 @@ void AiL::RenderCooldowns(){
}
}
-void AiL::AddEffect(std::unique_ptrforeground,std::unique_ptr background){
+std::pairAiL::AddEffect(std::unique_ptrforeground,std::unique_ptr background){
+ ForegroundWrapper foregroundRef{*foreground};
+ BackgroundWrapper backgroundRef{*background};
AddEffect(std::move(background),true);
AddEffect(std::move(foreground));
+ return {foregroundRef,backgroundRef};
}
-void AiL::AddEffect(std::unique_ptr foreground,bool back){
+Effect&AiL::AddEffect(std::unique_ptr foreground,bool back){
+ ForegroundWrapper effectRef{*foreground};
if(back){
- backgroundEffectsToBeInserted.push_back(std::move(foreground));
+ backgroundEffectsToBeInserted.emplace_back(std::move(foreground));
} else {
- foregroundEffectsToBeInserted.push_back(std::move(foreground));
+ foregroundEffectsToBeInserted.emplace_back(std::move(foreground));
}
+ return effectRef;
}
vf2d AiL::GetWorldMousePos(){
@@ -4586,11 +4591,12 @@ std::vectorAiL::GetBackgroundEffects()const{
std::for_each(backgroundEffects.begin(),backgroundEffects.end(),[&outputVec](const std::unique_ptr&eff){outputVec.emplace_back(eff.get());});
return outputVec;
}
-std::vectorAiL::GetAllEffects()const{
+[[nodiscard]]std::vectorAiL::GetAllEffects()const{
std::vectoroutputVec;
std::vectorforegroundEffects{GetForegroundEffects()};
std::vectorbackgroundEffects{GetBackgroundEffects()};
- std::merge(foregroundEffects.begin(),foregroundEffects.end(),backgroundEffects.begin(),backgroundEffects.end(),std::back_inserter(outputVec));
+ std::copy(foregroundEffects.begin(),foregroundEffects.end(),std::back_inserter(outputVec));
+ std::copy(backgroundEffects.begin(),backgroundEffects.end(),std::back_inserter(outputVec));
return outputVec;
}
@@ -4675,4 +4681,11 @@ void AiL::AddNotification(const Notification&n){
else notifications.emplace_back(n);
}
AiL::Notification::Notification(const std::string_view message,const float time,const Pixel col)
-:message(message),time(time),col(col){}
\ No newline at end of file
+:message(message),time(time),col(col){}
+
+const std::vectorAiL::GetEffect(EffectType type){
+ std::vectoreffects{GetAllEffects()};
+ std::vectormatchingEffects{};
+ std::copy_if(effects.begin(),effects.end(),std::back_inserter(matchingEffects),[&type](const Effect*effect){return effect->GetType()==type;});
+ return matchingEffects;
+}
\ No newline at end of file
diff --git a/Adventures in Lestoria/AdventuresInLestoria.h b/Adventures in Lestoria/AdventuresInLestoria.h
index 70e43e7e..0562ff6e 100644
--- a/Adventures in Lestoria/AdventuresInLestoria.h
+++ b/Adventures in Lestoria/AdventuresInLestoria.h
@@ -74,6 +74,8 @@ using HurtListItem=std::pair,HurtReturnValue>;
using HurtList=std::vector;
using StackCount=uint8_t;
using MarkTime=float;
+using ForegroundWrapper=std::reference_wrapper;
+using BackgroundWrapper=std::reference_wrapper;
enum class KnockbackCondition{
KNOCKBACK_HURT_TARGETS, //Knockback only targets that took damage.
@@ -269,9 +271,10 @@ public:
void RenderHud();
void RenderMenu();
bool MenuClicksDeactivated()const;
- void AddEffect(std::unique_ptrforeground,std::unique_ptrbackground);
+ std::pairAddEffect(std::unique_ptrforeground,std::unique_ptrbackground);
//If back is true, places the effect in the background
- void AddEffect(std::unique_ptrforeground,bool back=false);
+ Effect&AddEffect(std::unique_ptrforeground,bool back=false);
+ const std::vectorGetEffect(EffectType type);
const HurtList Hurt(vf2d pos,float radius,int damage,bool upperLevel,float z,const HurtType hurtTargets,HurtFlag::HurtFlag hurtFlags=HurtFlag::NONE)const;
const HurtList HurtMonsterType(vf2d pos,float radius,int damage,bool upperLevel,float z,const std::string_view monsterName,HurtFlag::HurtFlag hurtFlags=HurtFlag::NONE)const;
//NOTE: This function will also add any enemies that were hit into the hit list!
diff --git a/Adventures in Lestoria/Animation.cpp b/Adventures in Lestoria/Animation.cpp
index f0b48ae9..4756e759 100644
--- a/Adventures in Lestoria/Animation.cpp
+++ b/Adventures in Lestoria/Animation.cpp
@@ -452,6 +452,12 @@ void sig::Animation::InitializeAnimations(){
CreateHorizontalAnimationSequence("explosive_trap.png",4,{48,48},AnimationData{.frameDuration{0.06f},.style{Animate2D::Style::PingPong}});
CreateHorizontalAnimationSequence("explosionframes.png",21,{24,24},AnimationData{.frameDuration{0.02f},.style{Animate2D::Style::OneShot}});
+ CreateHorizontalAnimationSequence("portal.png",8,{24,24},AnimationData{.frameDuration{0.1f},.style{Animate2D::Style::Repeat}});
+
+ //!!!!!WARNING!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ //DO NOT CREATE MORE ANIMATION SEQUENCES UNDERNEATH HERE AS THE NEXT BLOCK WILL CREATE DEFAULT ANIMATIONS
+ //FOR ALL NON-SPECIFIED ANIMATION SEQUENCES!
+ //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
for(auto&dat:GFX){
std::string imgFile=dat.first;
if(!ANIMATION_DATA.count(imgFile)){
diff --git a/Adventures in Lestoria/Effect.cpp b/Adventures in Lestoria/Effect.cpp
index 15a43ea4..3244f5f7 100644
--- a/Adventures in Lestoria/Effect.cpp
+++ b/Adventures in Lestoria/Effect.cpp
@@ -45,15 +45,15 @@ INCLUDE_game
INCLUDE_GFX
Effect::Effect(vf2d pos,float lifetime,const std::string&imgFile,bool upperLevel,float size,float fadeout,vf2d spd,Pixel col,float rotation,float rotationSpd,bool additiveBlending)
- :Effect::Effect(pos,lifetime,imgFile,upperLevel,0.f,fadeout,vf2d{size,size},spd,col,rotation,rotationSpd,additiveBlending){}
+ :Effect(pos,lifetime,imgFile,upperLevel,0.f,fadeout,vf2d{size,size},spd,col,rotation,rotationSpd,additiveBlending){}
Effect::Effect(vf2d pos,float lifetime,const std::string&imgFile,bool upperLevel,vf2d size,float fadeout,vf2d spd,Pixel col,float rotation,float rotationSpd,bool additiveBlending)
- :pos(pos),lifetime(lifetime),upperLevel(upperLevel),size(size),fadeout(fadeout),original_fadeOutTime(fadeout),spd(spd),col(col),rotation(rotation),rotationSpd(rotationSpd),additiveBlending(additiveBlending){
- this->animation.AddState(imgFile,ANIMATION_DATA.at(imgFile));
- this->animation.ChangeState(internal_animState,imgFile);
-}
+ :Effect(pos,lifetime,imgFile,upperLevel,0.f,fadeout,size,spd,col,rotation,rotationSpd,additiveBlending){}
Effect::Effect(vf2d pos,float lifetime,const std::string&imgFile,bool upperLevel,float fadein,float fadeout,vf2d size,vf2d spd,Pixel col,float rotation,float rotationSpd,bool additiveBlending)
+ :Effect(pos,lifetime,imgFile,upperLevel,fadein,fadeout,size,spd,EffectType::NONE,col,rotation,rotationSpd,additiveBlending){}
+
+Effect::Effect(vf2d pos,float lifetime,const std::string&imgFile,bool upperLevel,float fadein,float fadeout,vf2d size,vf2d spd,EffectType type,Pixel col,float rotation,float rotationSpd,bool additiveBlending)
:pos(pos),lifetime(lifetime),upperLevel(upperLevel),size(size),fadein(fadein),original_fadeInTime(fadein),fadeout(fadeout),original_fadeOutTime(fadeout),spd(spd),col(col),rotation(rotation),rotationSpd(rotationSpd),additiveBlending(additiveBlending){
this->animation.AddState(imgFile,ANIMATION_DATA.at(imgFile));
this->animation.ChangeState(internal_animState,imgFile);
@@ -115,4 +115,8 @@ const EffectType Effect::GetType()const{
const float Effect::GetZ()const{
return z;
+}
+
+void Effect::SetType(const EffectType type){
+ this->type=type;
}
\ No newline at end of file
diff --git a/Adventures in Lestoria/Effect.h b/Adventures in Lestoria/Effect.h
index 03c61bac..5e4ec3d6 100644
--- a/Adventures in Lestoria/Effect.h
+++ b/Adventures in Lestoria/Effect.h
@@ -43,11 +43,15 @@ All rights reserved.
class Monster;
class Player;
using HitList=std::unordered_set>;
+using OscillatorVf2d=std::pair;
+using OscillatorPixel=std::pair;
enum class EffectType{
NONE,
SPELL_CIRCLE,
MONSTER_SOUL,
+ BLINK_PORTAL,
+ BLACK_HOLE,
};
struct Effect{
@@ -71,12 +75,14 @@ public:
Effect(vf2d pos,float lifetime,const std::string&imgFile,bool upperLevel,float size=1.0f,float fadeout=0.0f,vf2d spd={},Pixel col=WHITE,float rotation=0,float rotationSpd=0,bool additiveBlending=false);
Effect(vf2d pos,float lifetime,const 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);
Effect(vf2d pos,float lifetime,const std::string&imgFile,bool upperLevel,float fadein,float fadeout,vf2d size,vf2d spd,Pixel col=WHITE,float rotation=0,float rotationSpd=0,bool additiveBlending=false);
+ Effect(vf2d pos,float lifetime,const std::string&imgFile,bool upperLevel,float fadein,float fadeout,vf2d size,vf2d spd,EffectType type,Pixel col=WHITE,float rotation=0,float rotationSpd=0,bool additiveBlending=false);
virtual bool Update(float fElapsedTime);
Animate2D::Frame GetFrame()const;
virtual void Draw()const;
bool OnUpperLevel();
const EffectType GetType()const;
const float GetZ()const;
+ void SetType(const EffectType type);
protected:
float original_fadeOutTime;
float original_fadeInTime{};
@@ -166,12 +172,17 @@ public:
struct FadeInOutEffect:Effect{
//cycleSpd is how long it takes to get from fully opaque to fully transparent, and back to fully opaque
+
FadeInOutEffect(vf2d pos,const std::string&img,float lifetime,float cycleSpd,bool onUpperLevel,float size,vf2d spd,Pixel col,float rotation,float rotationSpd,bool additiveBlending=false,float particleSpawnFreq=0.f,const std::function&particleGenerator={});
+ //A version with oscillators for position and colors, for extra animation effects!
+ FadeInOutEffect(OscillatorVf2d pos,const std::string&img,float lifetime,float cycleSpd,bool onUpperLevel,float size,vf2d spd,OscillatorPixel col,float rotation,float rotationSpd,bool additiveBlending=false,float particleSpawnFreq=0.f,const std::function&particleGenerator={});
virtual bool Update(float fElapsedTime)override;
virtual void Draw()const override;
std::functionparticleGenerator;
const float particleSpawnFreq;
const float cycleSpd;
+ const OscillatorVf2d posOscillator;
+ const OscillatorPixel colOscillator;
float particleSpawnTimer{};
const float originalParticleSpawnTimer{};
};
diff --git a/Adventures in Lestoria/FadeInOutEffect.cpp b/Adventures in Lestoria/FadeInOutEffect.cpp
index ee916d03..b32fc364 100644
--- a/Adventures in Lestoria/FadeInOutEffect.cpp
+++ b/Adventures in Lestoria/FadeInOutEffect.cpp
@@ -43,7 +43,9 @@ All rights reserved.
INCLUDE_game
FadeInOutEffect::FadeInOutEffect(vf2d pos,const std::string&img,float lifetime,float cycleSpd,bool onUpperLevel,float size,vf2d spd,Pixel col,float rotation,float rotationSpd,bool additiveBlending,float particleSpawnFreq,const std::function&particleGenerator)
- :particleSpawnFreq(particleSpawnFreq),particleGenerator(particleGenerator),cycleSpd(cycleSpd),particleSpawnTimer(particleSpawnFreq),originalParticleSpawnTimer(particleSpawnTimer),Effect(pos,lifetime,img,onUpperLevel,size,0.25f,spd,col,rotation,rotationSpd,additiveBlending){}
+ :FadeInOutEffect({pos,pos},img,lifetime,cycleSpd,onUpperLevel,size,spd,{col,col},rotation,rotationSpd,additiveBlending,particleSpawnFreq,particleGenerator){}
+FadeInOutEffect::FadeInOutEffect(OscillatorVf2d pos,const std::string&img,float lifetime,float cycleSpd,bool onUpperLevel,float size,vf2d spd,OscillatorPixel col,float rotation,float rotationSpd,bool additiveBlending,float particleSpawnFreq,const std::function&particleGenerator)
+ :particleSpawnFreq(particleSpawnFreq),particleGenerator(particleGenerator),cycleSpd(cycleSpd),particleSpawnTimer(particleSpawnFreq),originalParticleSpawnTimer(particleSpawnTimer),posOscillator(pos),colOscillator(col),Effect(pos.first,lifetime,img,onUpperLevel,size,0.25f,spd,col.first,rotation,rotationSpd,additiveBlending){}
bool FadeInOutEffect::Update(float fElapsedTime){
if(particleGenerator){
particleSpawnTimer-=fElapsedTime;
@@ -52,7 +54,10 @@ bool FadeInOutEffect::Update(float fElapsedTime){
game->AddEffect(std::make_unique(particleGenerator()));
}
}
- col.a=abs(sin(PI*game->GetRunTime()*cycleSpd))*255;
+ float t{float(abs(sin(PI*game->GetRunTime()*cycleSpd)))};
+ pos=posOscillator.first.lerp(posOscillator.second,t);
+ col=PixelLerp(colOscillator.first,colOscillator.second,t);
+ col.a=t*255;
return Effect::Update(fElapsedTime);
}
void FadeInOutEffect::Draw()const{
diff --git a/Adventures in Lestoria/Player.cpp b/Adventures in Lestoria/Player.cpp
index ee0950b6..df9c5d68 100644
--- a/Adventures in Lestoria/Player.cpp
+++ b/Adventures in Lestoria/Player.cpp
@@ -1223,6 +1223,7 @@ CastInfo&Player::GetCastInfo(){
}
bool Player::CanPathfindTo(vf2d pos,vf2d targetPos,float range){
+ if(game->TestingModeEnabled())return true;
range*=(24/game->pathfinder.gridSpacing.x);
if(targetPos.x<0||targetPos.y<0||targetPos.x>game->GetCurrentMapData().width*game->GetCurrentMapData().tilewidth||targetPos.y>game->GetCurrentMapData().height*game->GetCurrentMapData().tileheight)return false;
std::vectorpathing=game->pathfinder.Solve_AStar(pos,targetPos,range,upperLevel);
@@ -1530,6 +1531,10 @@ void Player::RecalculateEquipStats(){
if(HasEnchant("Nine Lives"))GetRightClickAbility().COOLDOWN_TIME="Nine Lives"_ENC["TRANSFORM COOLDOWN"];
}
+ if(GetClass()&WIZARD){
+ if(HasEnchant("Blink Portal"))GetRightClickAbility().COOLDOWN_TIME="Blink Portal"_ENC["COOLDOWN"];
+ }
+
for(const std::reference_wrapper&a:GetAbilities()){
if(a.get().itemAbility)continue;
if(a.get().charges(teleportPoint,4),collisionRect);};
#pragma endregion
- if(p->lastPathfindingCooldown==0.f){
- if(dist>0&&p->CanPathfindTo(p->GetPos(),teleportPoint,float("Wizard.Right Click Ability.TilesMax"_I))
+
+ const auto TeleportTo=[&p](const vf2d pos){
+ p->SetState(State::TELEPORT);
+ p->teleportAnimationTimer="Wizard.Right Click Ability.AnimationTime"_F;
+ p->teleportTarget=pos;
+ p->teleportStartPosition=p->GetPos();
+ p->ApplyIframes("Wizard.Right Click Ability.IframeTime"_F);
+ for(int i=0;i<"Wizard.Right Click Ability.ParticleCount"_I;i++){
+ game->AddEffect(std::make_unique(p->GetPos()+vf2d{(util::random("Wizard.Right Click Ability.ParticleRange"_F/100*2)-"Wizard.Right Click Ability.ParticleRange"_F/100)*12,(util::random("Wizard.Right Click Ability.ParticleRange"_F/100*2)-"Wizard.Right Click Ability.ParticleRange"_F/100)*12},util::random("Wizard.Right Click Ability.ParticleLifetimeMax"_F)+"Wizard.Right Click Ability.ParticleLifetimeMin"_F,"circle.png",p->upperLevel,"Wizard.Right Click Ability.ParticleSize"_F,"Wizard.Right Click Ability.ParticleFadetime"_F,vf2d{util::random("Wizard.Right Click Ability.ParticleSpeedMax"_F*2)+"Wizard.Right Click Ability.ParticleSpeedMin"_F,util::random("Wizard.Right Click Ability.ParticleSpeedMax"_F*2)+"Wizard.Right Click Ability.ParticleSpeedMin"_F},"Wizard.Right Click Ability.ParticleColor"_Pixel));
+ }
+ SoundEffect::PlaySFX("Wizard Teleport",SoundEffect::CENTERED);
+ };
+
+ std::vectorportals{game->GetEffect(EffectType::BLINK_PORTAL)};
+ if(portals.size()>0){
+ TeleportTo(portals[0]->pos);
+ portals[0]->lifetime=0.f;
+ portals[0]->fadeout=0.25f;
+ return true;
+ }else if(p->lastPathfindingCooldown==0.f){
+ if(game->TestingModeEnabled()||dist>0&&p->CanPathfindTo(p->GetPos(),teleportPoint,float("Wizard.Right Click Ability.TilesMax"_I))
&&(NoTileCollisionExistsHere()||NoPlayerCollisionWithTile())){
- p->SetState(State::TELEPORT);
- p->teleportAnimationTimer="Wizard.Right Click Ability.AnimationTime"_F;
- p->teleportTarget=teleportPoint;
- p->teleportStartPosition=p->GetPos();
- p->ApplyIframes("Wizard.Right Click Ability.IframeTime"_F);
- for(int i=0;i<"Wizard.Right Click Ability.ParticleCount"_I;i++){
- game->AddEffect(std::make_unique(p->GetPos()+vf2d{(util::random("Wizard.Right Click Ability.ParticleRange"_F/100*2)-"Wizard.Right Click Ability.ParticleRange"_F/100)*12,(util::random("Wizard.Right Click Ability.ParticleRange"_F/100*2)-"Wizard.Right Click Ability.ParticleRange"_F/100)*12},util::random("Wizard.Right Click Ability.ParticleLifetimeMax"_F)+"Wizard.Right Click Ability.ParticleLifetimeMin"_F,"circle.png",p->upperLevel,"Wizard.Right Click Ability.ParticleSize"_F,"Wizard.Right Click Ability.ParticleFadetime"_F,vf2d{util::random("Wizard.Right Click Ability.ParticleSpeedMax"_F*2)+"Wizard.Right Click Ability.ParticleSpeedMin"_F,util::random("Wizard.Right Click Ability.ParticleSpeedMax"_F*2)+"Wizard.Right Click Ability.ParticleSpeedMin"_F},"Wizard.Right Click Ability.ParticleColor"_Pixel));
+ if(p->HasEnchant("Blink Portal")){
+ Effect&eff{game->AddEffect(std::make_unique(OscillatorVf2d{p->GetPos(),p->GetPos()+vf2d{0,-6.f}},"portal.png","Blink Portal"_ENC["REACTIVATION TIME"],0.5f,p->OnUpperLevel(),1.f,vf2d{},OscillatorPixel{WHITE,0x50196f},0.f,0.f),true)};
+ eff.SetType(EffectType::BLINK_PORTAL);
}
- SoundEffect::PlaySFX("Wizard Teleport",SoundEffect::CENTERED);
+ TeleportTo(teleportPoint);
p->lastPathfindingCooldown=0.1f;
return true;
} else {
diff --git a/Adventures in Lestoria/assets/blackhole.png b/Adventures in Lestoria/assets/blackhole.png
new file mode 100644
index 00000000..c51b814e
Binary files /dev/null and b/Adventures in Lestoria/assets/blackhole.png differ
diff --git a/Adventures in Lestoria/assets/config/gfx/gfx.txt b/Adventures in Lestoria/assets/config/gfx/gfx.txt
index c750e161..b2d1fc77 100644
--- a/Adventures in Lestoria/assets/config/gfx/gfx.txt
+++ b/Adventures in Lestoria/assets/config/gfx/gfx.txt
@@ -125,6 +125,8 @@ Images
GFX_MonsterSoulGlow = monstersoulglow.png
GFX_Glow = glow.png
GFX_SpecialTargetMark = special_target.png
+ GFX_BlackHole = blackhole.png
+ GFX_Portal = portal.png
GFX_Thief_Sheet = nico-thief.png
GFX_Trapper_Sheet = nico-trapper.png
diff --git a/Adventures in Lestoria/assets/gamepack.pak b/Adventures in Lestoria/assets/gamepack.pak
index 810e5954..28212d2a 100644
Binary files a/Adventures in Lestoria/assets/gamepack.pak and b/Adventures in Lestoria/assets/gamepack.pak differ
diff --git a/Adventures in Lestoria/assets/portal.png b/Adventures in Lestoria/assets/portal.png
new file mode 100644
index 00000000..463668ba
Binary files /dev/null and b/Adventures in Lestoria/assets/portal.png differ
diff --git a/Adventures in Lestoria/x64/Release Desktop/CodeAnalysisResultManifest.txt b/Adventures in Lestoria/x64/Release Desktop/CodeAnalysisResultManifest.txt
index 12503301..40b2ceb3 100644
Binary files a/Adventures in Lestoria/x64/Release Desktop/CodeAnalysisResultManifest.txt and b/Adventures in Lestoria/x64/Release Desktop/CodeAnalysisResultManifest.txt differ
diff --git a/CodeAnalysisRuleset.ruleset b/CodeAnalysisRuleset.ruleset
new file mode 100644
index 00000000..08dd1c16
--- /dev/null
+++ b/CodeAnalysisRuleset.ruleset
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/x64/Release/Adventures in Lestoria.exe b/x64/Release/Adventures in Lestoria.exe
index 15390509..fb6c8629 100644
Binary files a/x64/Release/Adventures in Lestoria.exe and b/x64/Release/Adventures in Lestoria.exe differ