diff --git a/Crawler/Animation.cpp b/Crawler/Animation.cpp
index f47335aa..971778f2 100644
--- a/Crawler/Animation.cpp
+++ b/Crawler/Animation.cpp
@@ -189,6 +189,26 @@ void sig::Animation::InitializeAnimations(){
 		}
 	}
 	ANIMATION_DATA[AnimationState::WIZARD_ATTACK_N]=pl_wizard_attack_n;
+	Animate2D::FrameSequence pl_wizard_cast_s(0.1);
+	for(int i=0;i<2;i++){
+		pl_wizard_cast_s.AddFrame({&game->GFX_Wizard_Sheet,{vi2d{7+i,0}*24,{24,24}}});
+	}
+	ANIMATION_DATA[AnimationState::WIZARD_CAST_S]=pl_wizard_cast_s;
+	Animate2D::FrameSequence pl_wizard_cast_e(0.1);
+	for(int i=0;i<2;i++){
+		pl_wizard_cast_e.AddFrame({&game->GFX_Wizard_Sheet,{vi2d{7+i,3}*24,{24,24}}});
+	}
+	ANIMATION_DATA[AnimationState::WIZARD_CAST_E]=pl_wizard_cast_e;
+	Animate2D::FrameSequence pl_wizard_cast_n(0.1);
+	for(int i=0;i<2;i++){
+		pl_wizard_cast_n.AddFrame({&game->GFX_Wizard_Sheet,{vi2d{7+i,1}*24,{24,24}}});
+	}
+	ANIMATION_DATA[AnimationState::WIZARD_CAST_N]=pl_wizard_cast_n;
+	Animate2D::FrameSequence pl_wizard_cast_w(0.1);
+	for(int i=0;i<2;i++){
+		pl_wizard_cast_w.AddFrame({&game->GFX_Wizard_Sheet,{vi2d{7+i,2}*24,{24,24}}});
+	}
+	ANIMATION_DATA[AnimationState::WIZARD_CAST_W]=pl_wizard_cast_w;
 
 	//Load slime animations.
 	for(int slime=0;slime<4;slime++){
@@ -271,6 +291,10 @@ void sig::Animation::InitializeAnimations(){
 		lightningsplash.AddFrame({&game->GFX_LightningSplash,{{i*24,0},{24,24}}});
 	}
 	ANIMATION_DATA[AnimationState::LIGHTNING_SPLASH]=lightningsplash;
+
+	Animate2D::FrameSequence meteor;
+	meteor.AddFrame({&game->GFX_Meteor,{{0,0},{192,192}}});
+	ANIMATION_DATA[AnimationState::METEOR]=meteor;
 }
 
 void sig::Animation::SetupPlayerAnimations(){
@@ -314,4 +338,8 @@ void sig::Animation::SetupPlayerAnimations(){
 	game->player.AddAnimation(AnimationState::WIZARD_ATTACK_E);
 	game->player.AddAnimation(AnimationState::WIZARD_ATTACK_S);
 	game->player.AddAnimation(AnimationState::WIZARD_ATTACK_W);
+	game->player.AddAnimation(AnimationState::WIZARD_CAST_N);
+	game->player.AddAnimation(AnimationState::WIZARD_CAST_E);
+	game->player.AddAnimation(AnimationState::WIZARD_CAST_S);
+	game->player.AddAnimation(AnimationState::WIZARD_CAST_W);
 }
\ No newline at end of file
diff --git a/Crawler/Animation.h b/Crawler/Animation.h
index e8391861..54963c55 100644
--- a/Crawler/Animation.h
+++ b/Crawler/Animation.h
@@ -19,7 +19,8 @@ enum AnimationState{
 	WIZARD_ATTACK_S,WIZARD_ATTACK_E,WIZARD_ATTACK_N,WIZARD_ATTACK_W,
 	ENERGY_BOLT,ENERGY_PARTICLE,SPLASH_EFFECT,DOT_PARTICLE,
 	LIGHTNING_BOLT,LIGHTNING_BOLT_PARTICLE1,LIGHTNING_BOLT_PARTICLE2,LIGHTNING_BOLT_PARTICLE3,LIGHTNING_BOLT_PARTICLE4,
-	CHAIN_LIGHTNING,LIGHTNING_SPLASH
+	CHAIN_LIGHTNING,LIGHTNING_SPLASH,
+	WIZARD_CAST_S,WIZARD_CAST_N,WIZARD_CAST_E,WIZARD_CAST_W,METEOR,
 };
 
 namespace sig{
diff --git a/Crawler/Class.cpp b/Crawler/Class.cpp
index 14f61a0c..45c42ef2 100644
--- a/Crawler/Class.cpp
+++ b/Crawler/Class.cpp
@@ -60,6 +60,28 @@ Warrior::Warrior(std::string name,Class cl,Ability rightClickAbility,Ability abi
 {}
 
 void Warrior::Update(float fElapsedTime){
+	ACCESS_PLAYER
+	if(p.GetState()==State::SWING_SWORD){
+		switch(p.GetFacingDirection()){
+			case UP:{
+				p.UpdateAnimation(AnimationState::WARRIOR_SWINGSWORD_N);
+			}break;
+			case DOWN:{
+				p.UpdateAnimation(AnimationState::WARRIOR_SWINGSWORD_S);
+			}break;
+			case LEFT:{
+				p.UpdateAnimation(AnimationState::WARRIOR_SWINGSWORD_W);
+			}break;
+			case RIGHT:{
+				p.UpdateAnimation(AnimationState::WARRIOR_SWINGSWORD_E);
+			}break;
+		}
+		p.SetSwordSwingTimer(p.GetSwordSwingTimer()-fElapsedTime);
+		if(p.GetSwordSwingTimer()<=0){
+			p.SetSwordSwingTimer(0);
+			p.SetState(State::NORMAL); 
+		}
+	}
 }
 
 bool Warrior::AutoAttack(){
@@ -102,7 +124,7 @@ bool Warrior::AutoAttack(){
 
 bool Warrior::Ability1(){
 	ACCESS_PLAYER
-	game->AddEffect(Effect(p.pos,0.1,AnimationState::BATTLECRY_EFFECT,p.upperLevel,1,0.3));
+	game->AddEffect(std::make_unique<Effect>(p.pos,0.1,AnimationState::BATTLECRY_EFFECT,p.upperLevel,1,0.3));
 	p.AddBuff(BuffType::ATTACK_UP,10,0.1);
 	p.AddBuff(BuffType::DAMAGE_REDUCTION,10,0.1);
 	for(Monster&m:MONSTER_LIST){
@@ -277,6 +299,22 @@ void Wizard::Update(float fElapsedTime){
 		CLASS_DATA[cl]->walk_s=AnimationState::WIZARD_WALK_S;
 		CLASS_DATA[cl]->walk_w=AnimationState::WIZARD_WALK_W;
 	}
+	if(p.GetState()==State::CASTING){
+		switch(p.GetFacingDirection()){
+			case UP:{
+				p.UpdateAnimation(AnimationState::WIZARD_CAST_N);
+			}break;
+			case DOWN:{
+				p.UpdateAnimation(AnimationState::WIZARD_CAST_S);
+			}break;
+			case LEFT:{
+				p.UpdateAnimation(AnimationState::WIZARD_CAST_W);
+			}break;
+			case RIGHT:{
+				p.UpdateAnimation(AnimationState::WIZARD_CAST_E);
+			}break;
+		}
+	}
 }
 
 bool Wizard::AutoAttack(){
@@ -302,6 +340,9 @@ bool Wizard::Ability2(){
 }
 
 bool Wizard::Ability3(){
+	ACCESS_PLAYER
+	p.SetState(State::CASTING);
+	game->AddEffect(std::make_unique<Meteor>(p.GetPos(),3,AnimationState::METEOR,p.OnUpperLevel(),vf2d{1,1},2));
 	return true;
 }
 
@@ -323,7 +364,7 @@ bool Wizard::RightClickAbility(){
 		p.teleportStartPosition=p.GetPos();
 		p.iframe_time=0.35;
 		for(int i=0;i<16;i++){
-			game->AddEffect(Effect(p.GetPos()+vf2d{(rand()%160-80)/10.f,(rand()%160-80)/10.f},float(rand()%300)/1000,AnimationState::DOT_PARTICLE,p.upperLevel,0.3,0.2,{float(rand()%1000-500)/100,float(rand()%1000-500)/100},BLACK));
+			game->AddEffect(std::make_unique<Effect>(p.GetPos()+vf2d{(rand()%160-80)/10.f,(rand()%160-80)/10.f},float(rand()%300)/1000,AnimationState::DOT_PARTICLE,p.upperLevel,0.3,0.2,vf2d{float(rand()%1000-500)/100,float(rand()%1000-500)/100},BLACK));
 		}
 		return true;
 	} else {
diff --git a/Crawler/Crawler.cpp b/Crawler/Crawler.cpp
index 5a5707a6..d6832356 100644
--- a/Crawler/Crawler.cpp
+++ b/Crawler/Crawler.cpp
@@ -78,6 +78,7 @@ bool Crawler::OnUserCreate(){
 	GFX_LightningBoltParticle4.Load("assets/lightning_bolt_part4.png");
 	GFX_ChainLightning.Load("assets/chain_lightning.png");
 	GFX_LightningSplash.Load("assets/lightning_splash_effect.png");
+	GFX_Meteor.Load("assets/meteor.png");
 
 	//Animations
 	sig::Animation::InitializeAnimations();
@@ -163,7 +164,7 @@ void Crawler::HandleUserInput(float fElapsedTime){
 		}break;
 		}
 	}
-	if(player.GetVelocity()==vf2d{0,0}){
+	if(player.GetVelocity()==vf2d{0,0}&&player.CanMove()){
 		auto GetPlayerStaircaseDirection=[&](){
 			for(LayerTag&layer:MAP_DATA[GetCurrentLevel()].LayerData){
 				int truncatedPlayerX=int(player.GetX())/24;
@@ -285,29 +286,6 @@ void Crawler::HandleUserInput(float fElapsedTime){
 		}
 	}
 
-	if(player.GetState()==State::SWING_SWORD){
-		setIdleAnimation=false;
-		switch(player.GetFacingDirection()){
-			case UP:{
-				player.UpdateAnimation(AnimationState::WARRIOR_SWINGSWORD_N);
-			}break;
-			case DOWN:{
-				player.UpdateAnimation(AnimationState::WARRIOR_SWINGSWORD_S);
-			}break;
-			case LEFT:{
-				player.UpdateAnimation(AnimationState::WARRIOR_SWINGSWORD_W);
-			}break;
-			case RIGHT:{
-				player.UpdateAnimation(AnimationState::WARRIOR_SWINGSWORD_E);
-			}break;
-		}
-		player.SetSwordSwingTimer(player.GetSwordSwingTimer()-fElapsedTime);
-		if(player.GetSwordSwingTimer()<=0){
-			player.SetSwordSwingTimer(0);
-			player.SetState(State::NORMAL); 
-		}
-	}
-
 	if(player.GetState()!=State::NORMAL){
 		setIdleAnimation=false;
 	}
@@ -365,18 +343,18 @@ void Crawler::UpdateEffects(float fElapsedTime){
 			}
 		}
 	}
-	for(std::vector<Effect>::iterator it=backgroundEffects.begin();it!=backgroundEffects.end();++it){
-		Effect&e=*it;
-		if(!e.Update(fElapsedTime)){
+	for(std::vector<std::unique_ptr<Effect>>::iterator it=backgroundEffects.begin();it!=backgroundEffects.end();++it){
+		Effect*e=(*it).get();
+		if(!e->Update(fElapsedTime)){
 			it=backgroundEffects.erase(it);
 			if(it==backgroundEffects.end()){
 				break;
 			}
 		}
 	}
-	for(std::vector<Effect>::iterator it=foregroundEffects.begin();it!=foregroundEffects.end();++it){
-		Effect&e=*it;
-		if(!e.Update(fElapsedTime)){
+	for(std::vector<std::unique_ptr<Effect>>::iterator it=foregroundEffects.begin();it!=foregroundEffects.end();++it){
+		Effect*e=(*it).get();
+		if(!e->Update(fElapsedTime)){
 			it=foregroundEffects.erase(it);
 			if(it==foregroundEffects.end()){
 				break;
@@ -479,19 +457,19 @@ void Crawler::PopulateRenderLists(std::vector<Monster*>&monstersBeforeLower,std:
 		}
 	}
 	for(auto it=foregroundEffects.begin();it!=foregroundEffects.end();++it){
-		Effect&e=*it;
-		if(e.OnUpperLevel()){
-			foregroundEffectsUpper.push_back(&e);
+		Effect*e=(*it).get();
+		if(e->OnUpperLevel()){
+			foregroundEffectsUpper.push_back(e);
 		}else{
-			foregroundEffectsLower.push_back(&e);
+			foregroundEffectsLower.push_back(e);
 		}
 	}
 	for(auto it=backgroundEffects.begin();it!=backgroundEffects.end();++it){
-		Effect&e=*it;
-		if(e.OnUpperLevel()){
-			backgroundEffectsUpper.push_back(&e);
+		Effect*e=(*it).get();
+		if(e->OnUpperLevel()){
+			backgroundEffectsUpper.push_back(e);
 		}else{
-			backgroundEffectsLower.push_back(&e);
+			backgroundEffectsLower.push_back(e);
 		}
 	}
 	std::sort(monstersBeforeUpper.begin(),monstersBeforeUpper.end(),[](Monster*m1,Monster*m2){return m1->GetPos().y<m2->GetPos().y;});
@@ -748,16 +726,16 @@ void Crawler::RenderHud(){
 	#endif
 }
 
-void Crawler::AddEffect(Effect foreground,Effect background){
-	foregroundEffects.push_back(foreground);
-	backgroundEffects.push_back(background);
+void Crawler::AddEffect(std::unique_ptr<Effect>foreground,std::unique_ptr<Effect> background){
+	foregroundEffects.push_back(std::move(foreground));
+	backgroundEffects.push_back(std::move(background));
 }
 
-void Crawler::AddEffect(Effect foreground,bool back){
+void Crawler::AddEffect(std::unique_ptr<Effect> foreground,bool back){
 	if(back){
-		backgroundEffects.push_back(foreground);
+		backgroundEffects.push_back(std::move(foreground));
 	} else {
-		foregroundEffects.push_back(foreground);
+		foregroundEffects.push_back(std::move(foreground));
 	}
 }
 
diff --git a/Crawler/Crawler.h b/Crawler/Crawler.h
index c3fb3e0b..e9d8ba3e 100644
--- a/Crawler/Crawler.h
+++ b/Crawler/Crawler.h
@@ -21,18 +21,18 @@ class Crawler : public olc::PixelGameEngine
 	friend class sig::Animation;
 	Camera2D camera;
 	Player player;
-	Renderable GFX_Warrior_Sheet,GFX_Slime_Sheet,GFX_Circle,
+	Renderable GFX_Warrior_Sheet,GFX_Slime_Sheet,
 		GFX_Effect_GroundSlam_Back,GFX_Effect_GroundSlam_Front,
 		GFX_Heart,GFX_BLOCK_BUBBLE,GFX_Ranger_Sheet,GFX_Wizard_Sheet,
 		GFX_Battlecry_Effect,GFX_Mana,GFX_SonicSlash,GFX_EnergyParticle,
 		GFX_Splash_Effect,GFX_LightningBolt,GFX_LightningBoltParticle1,
 		GFX_LightningBoltParticle2,GFX_LightningBoltParticle3,GFX_LightningBoltParticle4,
-		GFX_ChainLightning,GFX_LightningSplash;
+		GFX_ChainLightning,GFX_LightningSplash,GFX_Meteor;
 public:
-	Renderable GFX_BulletCircle,GFX_BulletCircleOutline,GFX_EnergyBolt;
+	Renderable GFX_BulletCircle,GFX_BulletCircleOutline,GFX_EnergyBolt,GFX_Circle;
 	Pathfinding pathfinder;
 private:
-	std::vector<Effect>foregroundEffects,backgroundEffects;
+	std::vector<std::unique_ptr<Effect>>foregroundEffects,backgroundEffects;
 	std::map<MapName,Map>MAP_DATA;
 	std::map<std::string,TilesetData>MAP_TILESETS;
 	vf2d worldShake={};
@@ -62,9 +62,9 @@ public:
 	void UpdateBullets(float fElapsedTime);
 	void RenderWorld(float fElapsedTime);
 	void RenderHud();
-	void AddEffect(Effect foreground,Effect background);
+	void AddEffect(std::unique_ptr<Effect>foreground,std::unique_ptr<Effect>background);
 	//If back is true, places the effect in the background
-	void AddEffect(Effect foreground,bool back=false);
+	void AddEffect(std::unique_ptr<Effect>foreground,bool back=false);
 	void HurtEnemies(vf2d pos,float radius,int damage,bool upperLevel);
 	vf2d GetWorldMousePos();
 	bool LeftHeld();
diff --git a/Crawler/Crawler.vcxproj b/Crawler/Crawler.vcxproj
index fd65a0d9..5ede7407 100644
--- a/Crawler/Crawler.vcxproj
+++ b/Crawler/Crawler.vcxproj
@@ -214,6 +214,7 @@
     <ClCompile Include="LightningBolt.cpp" />
     <ClCompile Include="LightningBoltEmitter.cpp" />
     <ClCompile Include="Map.cpp" />
+    <ClCompile Include="Meteor.cpp" />
     <ClCompile Include="Pathfinding.cpp" />
     <ClCompile Include="pixelGameEngine.cpp" />
     <ClCompile Include="Player.cpp" />
diff --git a/Crawler/Crawler.vcxproj.filters b/Crawler/Crawler.vcxproj.filters
index 2609e37b..6b2a78ff 100644
--- a/Crawler/Crawler.vcxproj.filters
+++ b/Crawler/Crawler.vcxproj.filters
@@ -22,6 +22,9 @@
     <Filter Include="Source Files\Emitters">
       <UniqueIdentifier>{0f85b918-f194-4114-9a10-803e204faf2e}</UniqueIdentifier>
     </Filter>
+    <Filter Include="Source Files\Effects">
+      <UniqueIdentifier>{94ea6039-63ac-430d-bb96-317bf1b7a305}</UniqueIdentifier>
+    </Filter>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="olcPixelGameEngine.h">
@@ -164,6 +167,9 @@
     <ClCompile Include="Emitter.cpp">
       <Filter>Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="Meteor.cpp">
+      <Filter>Source Files\Effects</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <None Include="cpp.hint" />
diff --git a/Crawler/Effect.cpp b/Crawler/Effect.cpp
index 36f14065..17b8e57e 100644
--- a/Crawler/Effect.cpp
+++ b/Crawler/Effect.cpp
@@ -31,12 +31,12 @@ bool Effect::Update(float fElapsedTime){
 
 void Effect::Draw(){
 	if(additiveBlending)game->SetDecalMode(DecalMode::ADDITIVE);
-	else game->SetDecalMode(DecalMode::NORMAL);
 	if(fadeout==0){
 		game->view.DrawPartialRotatedDecal(pos,GetFrame().GetSourceImage()->Decal(),rotation,GetFrame().GetSourceRect().size/2,GetFrame().GetSourceRect().pos,GetFrame().GetSourceRect().size,size,col);
 	} else {
 		game->view.DrawPartialRotatedDecal(pos,GetFrame().GetSourceImage()->Decal(),rotation,GetFrame().GetSourceRect().size/2,GetFrame().GetSourceRect().pos,GetFrame().GetSourceRect().size,size,{col.r,col.g,col.b,uint8_t(fadeout/original_fadeoutTime*255)});
 	}
+	game->SetDecalMode(DecalMode::NORMAL);
 }
 
 Animate2D::Frame Effect::GetFrame(){
diff --git a/Crawler/Effect.h b/Crawler/Effect.h
index 3dd719e4..f8595402 100644
--- a/Crawler/Effect.h
+++ b/Crawler/Effect.h
@@ -15,13 +15,19 @@ struct Effect{
 	bool additiveBlending=false;
 	Effect(vf2d pos,float lifetime,AnimationState animation,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,AnimationState animation,bool upperLevel,vf2d size={1,1},float fadeout=0.0f,vf2d spd={},Pixel col=WHITE,float rotation=0,float rotationSpd=0,bool additiveBlending=false);
-	bool Update(float fElapsedTime);
+	virtual bool Update(float fElapsedTime);
 	Animate2D::Frame GetFrame();
-	void Draw();
+	virtual void Draw();
 	bool OnUpperLevel();
 private:
 	Animate2D::Animation<AnimationState>animation;
 	Animate2D::AnimationState internal_animState;
 	float original_fadeoutTime;
 	bool upperLevel=false;
+};
+
+struct Meteor:Effect{
+	Meteor(vf2d pos,float lifetime,AnimationState animation,bool upperLevel,vf2d size={1,1},float fadeout=0.0f,vf2d spd={},Pixel col=WHITE,float rotation=0,float rotationSpd=0,bool additiveBlending=false);
+	bool Update(float fElapsedTime)override;
+	void Draw()override;
 };
\ No newline at end of file
diff --git a/Crawler/EnergyBolt.cpp b/Crawler/EnergyBolt.cpp
index d286781b..0b463fe1 100644
--- a/Crawler/EnergyBolt.cpp
+++ b/Crawler/EnergyBolt.cpp
@@ -13,7 +13,7 @@ void EnergyBolt::Update(float fElapsedTime){
 	lastParticleSpawn=std::max(0.f,lastParticleSpawn-fElapsedTime);
 	if(lastParticleSpawn==0){
 		lastParticleSpawn=0.03;
-		game->AddEffect(Effect(pos,util::random(1),AnimationState::ENERGY_PARTICLE,upperLevel,util::random(2),0.5,{util::random(60)-30,util::random(60)-30}));
+		game->AddEffect(std::make_unique<Effect>(pos,util::random(1),AnimationState::ENERGY_PARTICLE,upperLevel,util::random(2),0.5f,vf2d{util::random(60)-30,util::random(60)-30}));
 	}
 }
 
@@ -21,7 +21,7 @@ bool EnergyBolt::PlayerHit(Player& player)
 {
 	deactivated=true;
 	fadeOutTime=0.2f;
-	game->AddEffect(Effect(player.GetPos(),0,AnimationState::SPLASH_EFFECT,upperLevel,player.GetSizeMult(),0.25));
+	game->AddEffect(std::make_unique<Effect>(player.GetPos(),0,AnimationState::SPLASH_EFFECT,upperLevel,player.GetSizeMult(),0.25));
 	return false;
 }
 
@@ -29,6 +29,6 @@ bool EnergyBolt::MonsterHit(Monster& monster)
 {
 	deactivated=true;
 	fadeOutTime=0.2f;
-	game->AddEffect(Effect(monster.GetPos(),0,AnimationState::SPLASH_EFFECT,upperLevel,monster.GetSizeMult(),0.25));
+	game->AddEffect(std::make_unique<Effect>(monster.GetPos(),0,AnimationState::SPLASH_EFFECT,upperLevel,monster.GetSizeMult(),0.25));
 	return false;
 }
diff --git a/Crawler/FireBolt.cpp b/Crawler/FireBolt.cpp
index eee04fee..8a66a456 100644
--- a/Crawler/FireBolt.cpp
+++ b/Crawler/FireBolt.cpp
@@ -14,7 +14,7 @@ void FireBolt::Update(float fElapsedTime){
 	lastParticleSpawn=std::max(0.f,lastParticleSpawn-fElapsedTime);
 	if(lastParticleSpawn==0){
 		lastParticleSpawn=0.03;
-		game->AddEffect(Effect(pos,util::random(1),AnimationState::ENERGY_PARTICLE,upperLevel,util::random(2),0.3,{util::random(120)-60,-util::random(60)},{255,uint8_t(util::random(250)),0}));
+		game->AddEffect(std::make_unique<Effect>(pos,util::random(1),AnimationState::ENERGY_PARTICLE,upperLevel,util::random(2),0.3,vf2d{util::random(120)-60,-util::random(60)},Pixel{255,uint8_t(util::random(250)),0}));
 	}
 }
 
@@ -22,7 +22,7 @@ bool FireBolt::PlayerHit(Player& player)
 {
 	deactivated=true;
 	fadeOutTime=0.2f;
-	game->AddEffect(Effect(player.GetPos(),0,AnimationState::SPLASH_EFFECT,upperLevel,5,0.25,{},{240,120,60}));
+	game->AddEffect(std::make_unique<Effect>(player.GetPos(),0,AnimationState::SPLASH_EFFECT,upperLevel,5,0.25,vf2d{},Pixel{240,120,60}));
 	return false;
 }
 
@@ -31,7 +31,7 @@ bool FireBolt::MonsterHit(Monster& monster)
 	deactivated=true;
 	fadeOutTime=0.2f;
 	for(int i=0;i<72;i++){
-		game->AddEffect(Effect(monster.GetPos(),util::random(0.5),AnimationState::DOT_PARTICLE,upperLevel,util::random(2),util::random(0.4),{util::random(300)-150,util::random(300)-150},{255,uint8_t(util::random(190)+60),60}));
+		game->AddEffect(std::make_unique<Effect>(monster.GetPos(),util::random(0.5),AnimationState::DOT_PARTICLE,upperLevel,util::random(2),util::random(0.4),vf2d{util::random(300)-150,util::random(300)-150},Pixel{255,uint8_t(util::random(190)+60),60}));
 	}
 	game->SetupWorldShake(0.25);
 	for(Monster&m:MONSTER_LIST){
@@ -39,6 +39,6 @@ bool FireBolt::MonsterHit(Monster& monster)
 			m.Hurt(3*damage);
 		}
 	}
-	game->AddEffect(Effect(monster.GetPos(),0,AnimationState::SPLASH_EFFECT,upperLevel,5,0.25,{},{240,120,60}));
+	game->AddEffect(std::make_unique<Effect>(monster.GetPos(),0,AnimationState::SPLASH_EFFECT,upperLevel,5,0.25,vf2d{},Pixel{240,120,60}));
 	return false;
 }
diff --git a/Crawler/LightningBolt.cpp b/Crawler/LightningBolt.cpp
index 3845a425..9452d15c 100644
--- a/Crawler/LightningBolt.cpp
+++ b/Crawler/LightningBolt.cpp
@@ -19,16 +19,16 @@ void LightningBolt::Update(float fElapsedTime){
 		uint8_t brightness=uint8_t(util::random(100)+150);
 		switch(rand()%4){
 			case 0:{
-				game->AddEffect(Effect(pos+vf2d{util::random(12)-6,util::random(12)-6},util::random(0.1),AnimationState::LIGHTNING_BOLT_PARTICLE1,upperLevel,util::random(0.5)+1,0.1,vel*(util::random(0.1)+0.9),{brightness,brightness,brightness}));
+				game->AddEffect(std::make_unique<Effect>(pos+vf2d{util::random(12)-6,util::random(12)-6},util::random(0.1),AnimationState::LIGHTNING_BOLT_PARTICLE1,upperLevel,util::random(0.5)+1,0.1,vel*(util::random(0.1)+0.9),Pixel{brightness,brightness,brightness}));
 			}break;
 			case 1:{
-				game->AddEffect(Effect(pos+vf2d{util::random(12)-6,util::random(12)-6},util::random(0.1),AnimationState::LIGHTNING_BOLT_PARTICLE2,upperLevel,util::random(0.5)+1,0.1,vel*(util::random(0.1)+0.9),{brightness,brightness,brightness}));
+				game->AddEffect(std::make_unique<Effect>(pos+vf2d{util::random(12)-6,util::random(12)-6},util::random(0.1),AnimationState::LIGHTNING_BOLT_PARTICLE2,upperLevel,util::random(0.5)+1,0.1,vel*(util::random(0.1)+0.9),Pixel{brightness,brightness,brightness}));
 			}break;
 			case 2:{
-				game->AddEffect(Effect(pos+vf2d{util::random(12)-6,util::random(12)-6},util::random(0.1),AnimationState::LIGHTNING_BOLT_PARTICLE3,upperLevel,util::random(0.5)+1,0.1,vel*(util::random(0.1)+0.9),{brightness,brightness,brightness}));
+				game->AddEffect(std::make_unique<Effect>(pos+vf2d{util::random(12)-6,util::random(12)-6},util::random(0.1),AnimationState::LIGHTNING_BOLT_PARTICLE3,upperLevel,util::random(0.5)+1,0.1,vel*(util::random(0.1)+0.9),Pixel{brightness,brightness,brightness}));
 			}break;
 			case 3:{
-				game->AddEffect(Effect(pos+vf2d{util::random(12)-6,util::random(12)-6},util::random(0.1),AnimationState::LIGHTNING_BOLT_PARTICLE4,upperLevel,util::random(0.5)+1,0.1,vel*(util::random(0.1)+0.9),{brightness,brightness,brightness}));
+				game->AddEffect(std::make_unique<Effect>(pos+vf2d{util::random(12)-6,util::random(12)-6},util::random(0.1),AnimationState::LIGHTNING_BOLT_PARTICLE4,upperLevel,util::random(0.5)+1,0.1,vel*(util::random(0.1)+0.9),Pixel{brightness,brightness,brightness}));
 			}break;
 		}
 	}
@@ -38,7 +38,7 @@ bool LightningBolt::PlayerHit(Player& player)
 {
 	deactivated=true;
 	fadeOutTime=0.2f;
-	game->AddEffect(Effect(player.GetPos(),0.3,AnimationState::LIGHTNING_SPLASH,upperLevel,player.GetSizeMult(),0.25,{},WHITE,util::random(PI)));
+	game->AddEffect(std::make_unique<Effect>(player.GetPos(),0.3,AnimationState::LIGHTNING_SPLASH,upperLevel,player.GetSizeMult(),0.25,vf2d{},WHITE,util::random(PI)));
 	return false;
 }
 
@@ -46,7 +46,7 @@ bool LightningBolt::MonsterHit(Monster& monster)
 {
 	deactivated=true;
 	fadeOutTime=0.2f;
-	game->AddEffect(Effect(monster.GetPos(),0.3,AnimationState::LIGHTNING_SPLASH,upperLevel,monster.GetSizeMult(),0.25,{},WHITE,util::random(PI)));
+	game->AddEffect(std::make_unique<Effect>(monster.GetPos(),0.3,AnimationState::LIGHTNING_SPLASH,upperLevel,monster.GetSizeMult(),0.25,vf2d{},WHITE,util::random(PI)));
 	int targetsHit=0;
 	for(Monster&m:MONSTER_LIST){
 		if(&m==&monster||monster.OnUpperLevel()!=m.OnUpperLevel())continue;
@@ -55,7 +55,7 @@ bool LightningBolt::MonsterHit(Monster& monster)
 		if(dist<=72){
 			if(m.Hurt(game->GetPlayer().GetAttack()*2)){
 				EMITTER_LIST.push_back(std::make_unique<LightningBoltEmitter>(LightningBoltEmitter(monster.GetPos(),m.GetPos(),0.05,0.25,upperLevel)));
-				game->AddEffect(Effect(m.GetPos(),0.5,AnimationState::LIGHTNING_SPLASH,upperLevel,monster.GetSizeMult(),0.25,{},WHITE,util::random(PI)));
+				game->AddEffect(std::make_unique<Effect>(m.GetPos(),0.5,AnimationState::LIGHTNING_SPLASH,upperLevel,monster.GetSizeMult(),0.25,vf2d{},WHITE,util::random(PI)));
 				targetsHit++;
 			}
 		}
diff --git a/Crawler/LightningBoltEmitter.cpp b/Crawler/LightningBoltEmitter.cpp
index 5f222d22..7e76b467 100644
--- a/Crawler/LightningBoltEmitter.cpp
+++ b/Crawler/LightningBoltEmitter.cpp
@@ -22,7 +22,7 @@ void LightningBoltEmitter::DrawLightningBolt(){
 	float targetDist=lineToTarget.length()*util::random(0.5);
 	targetAngle+=util::random((PI/2))-PI/4;
 	geom2d::line<float>lightningLine=geom2d::line<float>(currentPos,currentPos+vf2d{cos(targetAngle)*targetDist,sin(targetAngle)*targetDist});
-	game->AddEffect(Effect(lightningLine.upoint(0),0,AnimationState::CHAIN_LIGHTNING,upperLevel,{lightningLine.length(),0.2},0.2,{},WHITE,targetAngle,0,true));
+	game->AddEffect(std::make_unique<Effect>(lightningLine.upoint(0),0,AnimationState::CHAIN_LIGHTNING,upperLevel,vf2d{lightningLine.length(),0.2},0.2,vf2d{},WHITE,targetAngle,0,true));
 	int iterations=1;
 	currentPos+=vf2d{cos(targetAngle)*targetDist,sin(targetAngle)*targetDist};
 	while(iterations<MAX_ITERATIONS&&geom2d::line<float>(currentPos,endPos).length()>1){
@@ -31,7 +31,7 @@ void LightningBoltEmitter::DrawLightningBolt(){
 		float targetDist=lineToTarget.length()*util::random(0.5);
 		targetAngle+=util::random((PI/2))-PI/4;
 		geom2d::line<float>lightningLine=geom2d::line<float>(currentPos,currentPos+vf2d{cos(targetAngle)*targetDist,sin(targetAngle)*targetDist});
-		game->AddEffect(Effect(lightningLine.upoint(0),0,AnimationState::CHAIN_LIGHTNING,upperLevel,{lightningLine.length(),0.2},0.2,{},WHITE,targetAngle,0,true));
+		game->AddEffect(std::make_unique<Effect>(lightningLine.upoint(0),0,AnimationState::CHAIN_LIGHTNING,upperLevel,vf2d{lightningLine.length(),0.2},0.2,vf2d{},WHITE,targetAngle,0,true));
 		currentPos+=vf2d{cos(targetAngle)*targetDist,sin(targetAngle)*targetDist};
 		iterations++;
 	}
diff --git a/Crawler/Meteor.cpp b/Crawler/Meteor.cpp
new file mode 100644
index 00000000..f145e548
--- /dev/null
+++ b/Crawler/Meteor.cpp
@@ -0,0 +1,20 @@
+#include "Effect.h"
+#include "DEFINES.h"
+#include "Crawler.h"
+
+INCLUDE_game
+
+Meteor::Meteor(vf2d pos, float lifetime, AnimationState 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){
+
+}
+
+bool Meteor::Update(float fElapsedTime){
+	return Effect::Update(fElapsedTime);
+}
+
+void Meteor::Draw(){
+	vf2d scale=vf2d{192,64}/3.f;
+	vf2d centerPoint=pos-vf2d{game->GFX_Circle.Sprite()->width*scale.x/2,game->GFX_Circle.Sprite()->height*scale.y/2};
+	game->view.DrawDecal(centerPoint,game->GFX_Circle.Decal(),scale,BLACK);
+}
\ No newline at end of file
diff --git a/Crawler/Player.cpp b/Crawler/Player.cpp
index 47a9370a..07dc9a45 100644
--- a/Crawler/Player.cpp
+++ b/Crawler/Player.cpp
@@ -209,7 +209,7 @@ void Player::Update(float fElapsedTime){
 				z=0;
 				float numb=4;
 				game->HurtEnemies(pos,3*12,GetAttack()*2.5,OnUpperLevel());
-				game->AddEffect(Effect{GetPos(),0.5,AnimationState::GROUND_SLAM_ATTACK_FRONT,upperLevel,1.33f,0.6f},Effect{GetPos(),0.5,AnimationState::GROUND_SLAM_ATTACK_BACK,upperLevel,1.33f,0.6f});
+				game->AddEffect(std::make_unique<Effect>(GetPos(),0.5,AnimationState::GROUND_SLAM_ATTACK_FRONT,upperLevel,1.33f,0.6f),std::make_unique<Effect>(GetPos(),0.5,AnimationState::GROUND_SLAM_ATTACK_BACK,upperLevel,1.33f,0.6f));
 			}
 			if(lastAnimationFlip>0){
 				lastAnimationFlip=std::max(0.f,lastAnimationFlip-fElapsedTime);
@@ -346,6 +346,10 @@ vf2d Player::GetVelocity(){
 	return vel;
 }
 
+bool Player::CanMove(){
+	return state!=State::CASTING;
+}
+
 bool Player::HasIframes(){
 	return iframe_time>0;
 }
diff --git a/Crawler/Player.h b/Crawler/Player.h
index ddb6ff4c..d8d57c4f 100644
--- a/Crawler/Player.h
+++ b/Crawler/Player.h
@@ -86,6 +86,7 @@ public:
 	void UpdateIdleAnimation(Key direction);
 	//The range is the search range in tiles.
 	bool CanPathfindTo(vf2d pos,vf2d targetPos,float range=8);
+	bool CanMove();
 
 	void AddBuff(BuffType type,float duration,float intensity);
 	std::vector<Buff>GetBuffs(BuffType buff);
diff --git a/Crawler/State.h b/Crawler/State.h
index b57b4d99..87c29961 100644
--- a/Crawler/State.h
+++ b/Crawler/State.h
@@ -9,5 +9,6 @@ enum State{
 	MOVE_AWAY,
 	BLOCK,
 	TELEPORT,
-	PATH_AROUND
+	PATH_AROUND,
+	CASTING
 };
\ No newline at end of file
diff --git a/Crawler/Version.h b/Crawler/Version.h
index bceb5a85..a570bebf 100644
--- a/Crawler/Version.h
+++ b/Crawler/Version.h
@@ -2,7 +2,7 @@
 #define VERSION_MAJOR 0
 #define VERSION_MINOR 2
 #define VERSION_PATCH 0
-#define VERSION_BUILD 639
+#define VERSION_BUILD 662
 
 #define stringify(a) stringify_(a)
 #define stringify_(a) #a
diff --git a/Crawler/assets/c30010.png b/Crawler/assets/c30010.png
index 56abaac2..c92b9d56 100644
Binary files a/Crawler/assets/c30010.png and b/Crawler/assets/c30010.png differ
diff --git a/Crawler/assets/meteor.png b/Crawler/assets/meteor.png
new file mode 100644
index 00000000..b0741988
Binary files /dev/null and b/Crawler/assets/meteor.png differ
diff --git a/Crawler/assets/meteor.xcf b/Crawler/assets/meteor.xcf
new file mode 100644
index 00000000..12fb0332
Binary files /dev/null and b/Crawler/assets/meteor.xcf differ
diff --git a/Crawler/assets/nico-wizard.png b/Crawler/assets/nico-wizard.png
index a67a4cc8..f10a9316 100644
Binary files a/Crawler/assets/nico-wizard.png and b/Crawler/assets/nico-wizard.png differ
diff --git a/Crawler/assets/nico-wizard.xcf b/Crawler/assets/nico-wizard.xcf
index 244d6022..9dc7b953 100644
Binary files a/Crawler/assets/nico-wizard.xcf and b/Crawler/assets/nico-wizard.xcf differ