diff --git a/.gitignore b/.gitignore
index 4dd1d94d..70e41989 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,6 +11,8 @@
 *.sln.docstates
 emsdk
 emscripten
+*.o
+*.h.gch
 
 # User-specific files (MonoDevelop/Xamarin Studio)
 *.userprefs
diff --git a/Crawler/Ability.cpp b/Crawler/Ability.cpp
index 748a394b..a316c922 100644
--- a/Crawler/Ability.cpp
+++ b/Crawler/Ability.cpp
@@ -1,5 +1,9 @@
 #include "Ability.h"
 
+PrecastData::PrecastData(){};
+PrecastData::PrecastData(float castTime,float range,float size)
+	:castTime(castTime),range(range),size(size){precastTargetingRequired=true;};
+
 Ability::Ability(){};
-Ability::Ability(std::string name,float cooldownTime,int manaCost,Pixel barColor1,Pixel barColor2,bool precastTargetingRequired)
-	:name(name),cooldown(0),COOLDOWN_TIME(cooldownTime),manaCost(manaCost),barColor1(barColor1),barColor2(barColor2),precastTargetingRequired(precastTargetingRequired){}
\ No newline at end of file
+Ability::Ability(std::string name,float cooldownTime,int manaCost,Pixel barColor1,Pixel barColor2,PrecastData precastInfo)
+	:name(name),cooldown(0),COOLDOWN_TIME(cooldownTime),manaCost(manaCost),barColor1(barColor1),barColor2(barColor2),precastInfo(precastInfo){}
\ No newline at end of file
diff --git a/Crawler/Ability.h b/Crawler/Ability.h
index 9f09536c..2b5606c4 100644
--- a/Crawler/Ability.h
+++ b/Crawler/Ability.h
@@ -1,6 +1,16 @@
 #pragma once
 #include "olcPixelGameEngine.h"
 
+struct PrecastData{
+	float castTime;
+	float range;
+	float size;
+	//Whether or not this ability requires precasting (automatically set to true when precast time is greater than zero)
+	bool precastTargetingRequired=false;
+	PrecastData();
+	PrecastData(float castTime,float range,float size);
+};
+
 //Abilities are tied to class data which is defined in Class.cpp.
 struct Ability{
 	std::string name="";
@@ -8,8 +18,8 @@ struct Ability{
 	float COOLDOWN_TIME=0;
 	int manaCost=0;
 	Pixel barColor1,barColor2;
-	bool precastTargetingRequired;
+	PrecastData precastInfo;
 	std::function<bool()>action=[&](){return false;};
 	Ability();
-	Ability(std::string name,float cooldownTime,int manaCost,Pixel barColor1=VERY_DARK_RED,Pixel barColor2=DARK_RED,bool precastTargetingRequired=false);
+	Ability(std::string name,float cooldownTime,int manaCost,Pixel barColor1=VERY_DARK_RED,Pixel barColor2=DARK_RED,PrecastData precastInfo={});
 };
\ No newline at end of file
diff --git a/Crawler/Crawler b/Crawler/Crawler
index 95857e93..72a67720 100755
Binary files a/Crawler/Crawler and b/Crawler/Crawler differ
diff --git a/Crawler/Crawler.cpp b/Crawler/Crawler.cpp
index e0202df8..885cf087 100644
--- a/Crawler/Crawler.cpp
+++ b/Crawler/Crawler.cpp
@@ -181,7 +181,7 @@ void Crawler::HandleUserInput(float fElapsedTime){
 				player->SetY(player->GetY()+60*fElapsedTime*player->GetMoveSpdMult());
 			}
 			player->SetFacingDirection(RIGHT);
-			if(player->GetState()==State::NORMAL){
+			if(player->GetState()==State::NORMAL||player->GetState()==State::PREP_CAST){
 				player->UpdateWalkingAnimation(RIGHT);
 			}
 			setIdleAnimation=false;
@@ -196,7 +196,7 @@ void Crawler::HandleUserInput(float fElapsedTime){
 			}
 			if(setIdleAnimation){
 				player->SetFacingDirection(LEFT);
-				if(player->GetState()==State::NORMAL){
+				if(player->GetState()==State::NORMAL||player->GetState()==State::PREP_CAST){
 					player->UpdateWalkingAnimation(LEFT);
 				}
 			}
@@ -206,7 +206,7 @@ void Crawler::HandleUserInput(float fElapsedTime){
 			player->SetY(player->GetY()-fElapsedTime*100*player->GetMoveSpdMult());
 			if(setIdleAnimation){
 				player->SetFacingDirection(UP);
-				if(player->GetState()==State::NORMAL){
+				if(player->GetState()==State::NORMAL||player->GetState()==State::PREP_CAST){
 					player->UpdateWalkingAnimation(UP);
 				}
 			}
@@ -216,7 +216,7 @@ void Crawler::HandleUserInput(float fElapsedTime){
 			player->SetY(player->GetY()+fElapsedTime*100*player->GetMoveSpdMult());
 			if(setIdleAnimation){
 				player->SetFacingDirection(DOWN);
-				if(player->GetState()==State::NORMAL){
+				if(player->GetState()==State::NORMAL||player->GetState()==State::PREP_CAST){
 					player->UpdateWalkingAnimation(DOWN);
 				}
 			}
@@ -225,7 +225,7 @@ void Crawler::HandleUserInput(float fElapsedTime){
 	}
 	if(UpReleased()){
 		player->SetLastReleasedMovementKey(UP);
-		if(player->GetState()==State::NORMAL){
+		if(player->GetState()==State::NORMAL||player->GetState()==State::PREP_CAST){
 			if(RightHeld()){
 				player->UpdateWalkingAnimation(RIGHT);
 			} else
@@ -239,7 +239,7 @@ void Crawler::HandleUserInput(float fElapsedTime){
 	}
 	if(RightReleased()){
 		player->SetLastReleasedMovementKey(RIGHT);
-		if(player->GetState()==State::NORMAL){
+		if(player->GetState()==State::NORMAL||player->GetState()==State::PREP_CAST){
 			if(UpHeld()){
 				player->UpdateWalkingAnimation(UP);
 			} else
@@ -253,7 +253,7 @@ void Crawler::HandleUserInput(float fElapsedTime){
 	}
 	if(LeftReleased()){
 		player->SetLastReleasedMovementKey(LEFT);
-		if(player->GetState()==State::NORMAL){
+		if(player->GetState()==State::NORMAL||player->GetState()==State::PREP_CAST){
 			if(RightHeld()){
 				player->UpdateWalkingAnimation(RIGHT);
 			} else
@@ -267,7 +267,7 @@ void Crawler::HandleUserInput(float fElapsedTime){
 	}
 	if(DownReleased()){
 		player->SetLastReleasedMovementKey(DOWN);
-		if(player->GetState()==State::NORMAL){
+		if(player->GetState()==State::NORMAL||player->GetState()==State::PREP_CAST){
 			if(RightHeld()){
 				player->UpdateWalkingAnimation(RIGHT);
 			} else
@@ -566,6 +566,10 @@ void Crawler::RenderWorld(float fElapsedTime){
 	for(Bullet*b:bulletsLower){
 		b->Draw();
 	}
+	if(player->GetState()==State::PREP_CAST){
+		float precastSize=GetPlayer()->castPrepAbility->precastInfo.size;
+		view.DrawDecal(GetWorldMousePos()-vf2d{precastSize/6,precastSize/6},GFX_Circle.Decal(),{precastSize/3,precastSize/3},{255,0,0,192});
+	}
 	#pragma region Foreground Rendering
 		for(TileGroup&group:foregroundTileGroups){
 			if(view.IsRectVisible(group.GetRange().pos,group.GetRange().size)){
diff --git a/Crawler/Player.cpp b/Crawler/Player.cpp
index fd4fd9ac..1a436447 100644
--- a/Crawler/Player.cpp
+++ b/Crawler/Player.cpp
@@ -154,7 +154,7 @@ State Player::GetState(){
 
 void Player::Update(float fElapsedTime){
 	Ability&rightClickAbility=GetRightClickAbility(),
-		&ability1=GetAbility1(),
+		&ability=GetAbility1(),
 		&ability2=GetAbility2(),
 		&ability3=GetAbility3(),
 		&ability4=GetAbility4();
@@ -256,7 +256,7 @@ void Player::Update(float fElapsedTime){
 		}
 	}
 	rightClickAbility.cooldown=std::max(0.f,rightClickAbility.cooldown-fElapsedTime);
-	ability1.cooldown=std::max(0.f,ability1.cooldown-fElapsedTime);
+	ability.cooldown=std::max(0.f,ability.cooldown-fElapsedTime);
 	ability2.cooldown=std::max(0.f,ability2.cooldown-fElapsedTime);
 	ability3.cooldown=std::max(0.f,ability3.cooldown-fElapsedTime);
 	for(Monster&m:MONSTER_LIST){
@@ -291,41 +291,44 @@ void Player::Update(float fElapsedTime){
 	if(attack_cooldown_timer==0&&game->GetMouse(0).bHeld){
 		AutoAttack();
 	}
-	if(ability1.cooldown==0&&GetMana()>=ability1.manaCost&&game->GetKey(SHIFT).bHeld){
-		if(ability1.action()){
-			ability1.cooldown=ability1.COOLDOWN_TIME;
-			mana-=ability1.manaCost;
-		}
-	} else 
-	if(ability1.cooldown==0&&GetMana()<ability1.manaCost&&game->GetKey(SHIFT).bPressed){
-		notEnoughManaDisplay={ability1.name,1};
-	}
-	if(ability2.cooldown==0&&GetMana()>=ability2.manaCost&&game->GetKey(SPACE).bPressed){
-		if(ability2.action()){
-			ability2.cooldown=ability2.COOLDOWN_TIME;
-			mana-=ability2.manaCost;
-		}
-	} else 
-	if(ability2.cooldown==0&&GetMana()<ability2.manaCost&&game->GetKey(SPACE).bPressed){
-		notEnoughManaDisplay={ability2.name,1};
-	}
-	if(ability3.cooldown==0&&GetMana()>=ability3.manaCost&&game->GetKey(CTRL).bPressed){
-		if(ability3.action()){
-			ability3.cooldown=ability3.COOLDOWN_TIME;
-			mana-=ability3.manaCost;
-		}
-	} else 
-	if(ability3.cooldown==0&&GetMana()<ability3.manaCost&&game->GetKey(CTRL).bPressed){
-		notEnoughManaDisplay={ability3.name,1};
-	}
-	if(rightClickAbility.cooldown==0&&GetMana()>=rightClickAbility.manaCost&&game->GetMouse(1).bHeld){
-		if(rightClickAbility.action()){
-			rightClickAbility.cooldown=rightClickAbility.COOLDOWN_TIME;
-			mana-=rightClickAbility.manaCost;
+
+	
+	auto AllowedToCast=[&](Ability&ability){return !ability.precastInfo.precastTargetingRequired||ability.precastInfo.precastTargetingRequired&&GetState()==State::PREP_CAST;};
+	auto CheckAndPerformAbility=[&](Ability&ability,HWButton key){
+		if(ability.cooldown==0&&GetMana()>=ability.manaCost){
+			if(key.bPressed||key.bReleased&&&ability==castPrepAbility&&GetState()==State::PREP_CAST){
+				if(AllowedToCast(ability)&&ability.action()){
+					ability.cooldown=ability.COOLDOWN_TIME;
+					mana-=ability.manaCost;
+				}else
+				if(ability.precastInfo.precastTargetingRequired&&GetState()!=State::PREP_CAST){
+					PrepareCast(ability);
+				}
+			}
+		} else 
+		if(ability.cooldown==0&&GetMana()<ability.manaCost&&key.bPressed){
+			notEnoughManaDisplay={ability.name,1};
 		}
-	} else 
-	if(rightClickAbility.cooldown==0&&GetMana()<rightClickAbility.manaCost&&game->GetMouse(1).bPressed){
-		notEnoughManaDisplay={rightClickAbility.name,1};
+	};
+	CheckAndPerformAbility(GetAbility1(),game->GetKey(SHIFT));
+	CheckAndPerformAbility(GetAbility2(),game->GetKey(SPACE));
+	CheckAndPerformAbility(GetAbility3(),game->GetKey(CTRL));
+	CheckAndPerformAbility(GetAbility4(),game->GetKey(R));
+	CheckAndPerformAbility(GetRightClickAbility(),game->GetMouse(1));
+
+	if(GetState()==State::PREP_CAST){
+		#define CheckAbilityKeyReleasedAndCastSpell(ability,input) \
+			if(&ability==castPrepAbility&&input.bReleased){CastSpell(ability);}
+
+		CheckAbilityKeyReleasedAndCastSpell(rightClickAbility,game->GetMouse(1))
+		else
+		CheckAbilityKeyReleasedAndCastSpell(ability,game->GetKey(SHIFT))
+		else
+		CheckAbilityKeyReleasedAndCastSpell(ability2,game->GetKey(SPACE))
+		else
+		CheckAbilityKeyReleasedAndCastSpell(ability3,game->GetKey(CTRL))
+		else
+		CheckAbilityKeyReleasedAndCastSpell(ability4,game->GetKey(R))
 	}
 
 	switch(GetState()){
@@ -481,8 +484,9 @@ std::vector<Buff>Player::GetBuffs(BuffType buff){
 	return filteredBuffs;
 }
 
-void Player::CastSpell(std::string name,float castTotalTime){
-	castInfo={name,castTotalTime,castTotalTime};
+void Player::CastSpell(Ability&ability){
+	castInfo={ability.name,ability.precastInfo.castTime,ability.precastInfo.castTime};
+	SetState(State::NORMAL);
 }
 
 CastInfo&Player::GetCastInfo(){
@@ -492,4 +496,9 @@ CastInfo&Player::GetCastInfo(){
 bool Player::CanPathfindTo(vf2d pos,vf2d targetPos,float range){
 	std::vector<vf2d>pathing=game->pathfinder.Solve_AStar(pos,targetPos,8,upperLevel);
 	return pathing.size()>0&&pathing.size()<8;//We'll say 7 tiles or less is close enough to 650 range. Have a little bit of wiggle room.
+}
+
+void Player::PrepareCast(Ability&ability){
+	castPrepAbility=&ability;
+	SetState(State::PREP_CAST);
 }
\ No newline at end of file
diff --git a/Crawler/Player.h b/Crawler/Player.h
index 0a79addb..2425631b 100644
--- a/Crawler/Player.h
+++ b/Crawler/Player.h
@@ -68,8 +68,10 @@ protected:
 	float attack_range=1.5f;
 	Key facingDirection;
 	float swordSwingTimer=0;
-	void CastSpell(std::string name,float castTotalTime);
-	
+	void CastSpell(Ability&ability);
+	Ability*castPrepAbility;
+	void PrepareCast(Ability&ability);
+	vf2d precastLocation={};
 public:
 	Player();
 	//So this is rather fascinating and only exists because we have the ability to change classes which means we need to initialize a class
diff --git a/Crawler/Wizard.cpp b/Crawler/Wizard.cpp
index 98a5c765..fb78a9b2 100644
--- a/Crawler/Wizard.cpp
+++ b/Crawler/Wizard.cpp
@@ -15,7 +15,7 @@ Class Wizard::cl=WIZARD;
 Ability Wizard::rightClickAbility={"Teleport",8,5,VERY_DARK_BLUE,DARK_BLUE};
 Ability Wizard::ability1={"Firebolt",6,30};
 Ability Wizard::ability2={"Lightning Bolt",6,25};
-Ability Wizard::ability3={"Meteor",40,75,VERY_DARK_RED,VERY_DARK_RED,true};
+Ability Wizard::ability3={"Meteor",40,75,VERY_DARK_RED,VERY_DARK_RED,{1.5,900,400}};
 Ability Wizard::ability4={"???",0,0};
 AnimationState Wizard::idle_n=WIZARD_IDLE_N;
 AnimationState Wizard::idle_e=WIZARD_IDLE_E;
@@ -120,7 +120,7 @@ void Wizard::InitializeClassAbilities(){
     #pragma region Wizard Ability 3 (Meteor)
         Wizard::ability3.action=
             [&](){
-                CastSpell("Meteor",1.5);
+                CastSpell(Wizard::ability3);
                 game->AddEffect(std::make_unique<Meteor>(GetPos(),3,AnimationState::METEOR,OnUpperLevel(),vf2d{1,1},2));
                 return true;
             };