diff --git a/src/main/java/com/minelittlepony/unicopia/ability/Abilities.java b/src/main/java/com/minelittlepony/unicopia/ability/Abilities.java
index 227cc33d..abdfe6f0 100644
--- a/src/main/java/com/minelittlepony/unicopia/ability/Abilities.java
+++ b/src/main/java/com/minelittlepony/unicopia/ability/Abilities.java
@@ -14,8 +14,8 @@ public interface Abilities {
     MutableRegistry<Ability<?>> REGISTRY = new SimpleRegistry<>();
 
     // unicorn / alicorn
-    Ability<?> TELEPORT = register(new UnicornTeleportAbility(), "teleport", AbilitySlot.PRIMARY);
-    Ability<?> CAST = register(new UnicornCastingAbility(), "cast", AbilitySlot.SECONDARY);
+    Ability<?> TELEPORT = register(new UnicornTeleportAbility(), "teleport", AbilitySlot.SECONDARY);
+    Ability<?> CAST = register(new UnicornCastingAbility(), "cast", AbilitySlot.PRIMARY);
 
     // earth / alicorn
     Ability<?> STOMP = register(new EarthPonyStompAbility(), "stomp", AbilitySlot.PRIMARY);
@@ -30,7 +30,7 @@ public interface Abilities {
     // changeling
     Ability<?> DISGUISE = register(new ChangelingDisguiseAbility(), "disguise", AbilitySlot.PRIMARY);
     Ability<?> FEED = register(new ChangelingFeedAbility(), "feed", AbilitySlot.SECONDARY);
-    Ability<?> TRAP = register(new ChangelingTrapAbility(), "trap", AbilitySlot.TERTIARY);
+    //Ability<?> TRAP = register(new ChangelingTrapAbility(), "trap", AbilitySlot.TERTIARY);
 
     static <T extends Ability<?>> T register(T power, String name, AbilitySlot slot) {
         Identifier id = new Identifier("unicopia", name);
diff --git a/src/main/java/com/minelittlepony/unicopia/ability/Ability.java b/src/main/java/com/minelittlepony/unicopia/ability/Ability.java
index 4c61bec8..c6428de8 100644
--- a/src/main/java/com/minelittlepony/unicopia/ability/Ability.java
+++ b/src/main/java/com/minelittlepony/unicopia/ability/Ability.java
@@ -60,11 +60,11 @@ public interface Ability<T extends Hit> {
      * Called every tick until the warmup timer runs out.
      * @param player    The current player
      */
-    void preApply(Pony player);
+    void preApply(Pony player, AbilitySlot slot);
 
     /**
      * Called every tick until the cooldown timer runs out.
      * @param player    The current player
      */
-    void postApply(Pony player);
+    void postApply(Pony player, AbilitySlot slot);
 }
diff --git a/src/main/java/com/minelittlepony/unicopia/ability/AbilityDispatcher.java b/src/main/java/com/minelittlepony/unicopia/ability/AbilityDispatcher.java
index a4850446..d6b8db40 100644
--- a/src/main/java/com/minelittlepony/unicopia/ability/AbilityDispatcher.java
+++ b/src/main/java/com/minelittlepony/unicopia/ability/AbilityDispatcher.java
@@ -4,8 +4,6 @@ import java.util.EnumMap;
 import java.util.Map;
 import java.util.Optional;
 
-import javax.annotation.Nullable;
-
 import com.minelittlepony.unicopia.Race;
 import com.minelittlepony.unicopia.ability.data.Hit;
 import com.minelittlepony.unicopia.entity.player.Pony;
@@ -23,39 +21,22 @@ public class AbilityDispatcher implements Tickable, NbtSerialisable {
 
     private final Map<AbilitySlot, Stat> stats = new EnumMap<>(AbilitySlot.class);
 
-    /**
-     * True once the current ability has been triggered.
-     */
-    private boolean triggered;
-
-    private Optional<Ability<?>> activeAbility = Optional.empty();
-
-    private AbilitySlot activeSlot = AbilitySlot.NONE;
-
     public AbilityDispatcher(Pony player) {
         this.player = player;
     }
 
-    /**
-     * Returns true if the current ability can we swapped out.
-     */
-    boolean canSwitchStates() {
-        return !activeAbility.isPresent() || getStat(getActiveSlot()).canSwitchStates();
-    }
+    public void clear(AbilitySlot slot) {
+        Stat stat = getStat(slot);
 
-    public AbilitySlot getActiveSlot() {
-        return activeSlot;
-    }
-
-    public void cancelAbility(AbilitySlot slot) {
-        if (getActiveSlot() == slot && canSwitchStates()) {
-            setActiveAbility(slot, null);
+        if (stat.canSwitchStates()) {
+            stat.setActiveAbility(null);
         }
     }
 
     public void activate(AbilitySlot slot) {
-        if (canSwitchStates()) {
-            getAbility(slot).ifPresent(ability -> setActiveAbility(slot, ability));
+        Stat stat = getStat(slot);
+        if (stat.canSwitchStates()) {
+            stat.getAbility().ifPresent(stat::setActiveAbility);
         }
     }
 
@@ -63,88 +44,13 @@ public class AbilityDispatcher implements Tickable, NbtSerialisable {
         return stats.computeIfAbsent(slot, Stat::new);
     }
 
-    public Optional<Ability<?>> getAbility(AbilitySlot slot) {
-        Race race = player.getSpecies();
-        return Abilities.BY_SLOT.get(slot).stream().filter(a -> a.canUse(race)).findFirst();
-    }
-
-    protected synchronized void setActiveAbility(AbilitySlot slot, Ability<?> power) {
-        if (activeAbility.orElse(null) != power) {
-            activeSlot = slot;
-            triggered = false;
-            activeAbility = Optional.ofNullable(power);
-            Stat stat = getStat(slot);
-            stat.setWarmup(activeAbility.map(p -> p.getWarmupTime(player)).orElse(0));
-            stat.setCooldown(0);
-        }
-    }
-
-    @Nullable
-    protected synchronized Optional<Ability<?>> getActiveAbility() {
-        Stat stat = getStat(getActiveSlot());
-        return activeAbility.filter(ability -> {
-            return (!(ability == null || (triggered && stat.warmup == 0 && stat.cooldown == 0)) && ability.canUse(player.getSpecies()));
-        });
-    }
-
     @Override
     public void tick() {
-        getActiveAbility().ifPresent(this::activate);
-    }
-
-    private <T extends Hit> void activate(Ability<T> ability) {
-        Stat stat = getStat(getActiveSlot());
-
-        stats.values().forEach(s -> {
-            if (s != stat) {
-                s.idle();
-            }
-        });
-
-        if (stat.warmup > 0) {
-            stat.warmup--;
-            System.out.println("warming up");
-            ability.preApply(player);
-            return;
-        }
-
-        if (stat.tickInactive()) {
-            System.out.println("cooling down");
-            ability.postApply(player);
-
-            if (stat.cooldown <= 0) {
-                setActiveAbility(AbilitySlot.NONE, null);
-            }
-            return;
-        }
-
-        if (triggered) {
-            return;
-        }
-
-        if (ability.canActivate(player.getWorld(), player)) {
-            triggered = true;
-            stat.setCooldown(ability.getCooldownTime(player));
-
-            if (player.isClientPlayer()) {
-                T data = ability.tryActivate(player);
-
-                if (data != null) {
-                    Channel.PLAYER_ABILITY.send(new MsgPlayerAbility<>(ability, data));
-                } else {
-                    stat.setCooldown(0);
-                }
-            }
-        }
-
-        if (stat.cooldown <= 0) {
-            setActiveAbility(AbilitySlot.NONE, null);
-        }
+        stats.values().forEach(Stat::tick);
     }
 
     @Override
     public void toNBT(CompoundTag compound) {
-        compound.putBoolean("triggered", triggered);
         if (compound.contains("stats")) {
             stats.clear();
             CompoundTag li = compound.getCompound("stats");
@@ -152,20 +58,13 @@ public class AbilityDispatcher implements Tickable, NbtSerialisable {
                 getStat(AbilitySlot.valueOf(key)).fromNBT(li.getCompound(key));
             });
         }
-        compound.putInt("activeSlot", activeSlot.ordinal());
-        getActiveAbility().ifPresent(ability -> {
-            compound.putString("activeAbility", Abilities.REGISTRY.getId(ability).toString());
-        });
     }
 
     @Override
     public void fromNBT(CompoundTag compound) {
-        triggered = compound.getBoolean("triggered");
         CompoundTag li = new CompoundTag();
         stats.forEach((key, value) -> li.put(key.name(), value.toNBT()));
         compound.put("stats", li);
-        activeSlot = compound.contains("activeSlot") ? AbilitySlot.values()[compound.getInt("activeSlot")] : activeSlot;
-        activeAbility = Abilities.REGISTRY.getOrEmpty(new Identifier(compound.getString("activeAbility")));
     }
 
     public class Stat implements NbtSerialisable {
@@ -184,6 +83,13 @@ public class AbilityDispatcher implements Tickable, NbtSerialisable {
 
         public final AbilitySlot slot;
 
+        /**
+         * True once the current ability has been triggered.
+         */
+        private boolean triggered;
+
+        private Optional<Ability<?>> activeAbility = Optional.empty();
+
         private Stat(AbilitySlot slot) {
             this.slot = slot;
         }
@@ -192,7 +98,7 @@ public class AbilityDispatcher implements Tickable, NbtSerialisable {
          * Returns true if the current ability can we swapped out.
          */
         boolean canSwitchStates() {
-            return (warmup != 0) || (triggered && cooldown == 0);
+            return !activeAbility.isPresent() || (warmup != 0) || (triggered && cooldown == 0);
         }
 
         public int getRemainingCooldown() {
@@ -225,17 +131,68 @@ public class AbilityDispatcher implements Tickable, NbtSerialisable {
             warmup = value;
         }
 
-        public void idle() {
+        public void tick() {
+            getActiveAbility().ifPresent(this::activate);
+        }
+
+        private <T extends Hit> void activate(Ability<T> ability) {
             if (warmup > 0) {
                 warmup--;
+                ability.preApply(player, slot);
+                return;
             }
-            if (cooldown > 0) {
-                cooldown--;
+
+            if (cooldown > 0 && cooldown-- > 0) {
+                ability.postApply(player, slot);
+
+                if (cooldown <= 0) {
+                    setActiveAbility(null);
+                }
+                return;
+            }
+
+            if (triggered) {
+                return;
+            }
+
+            if (ability.canActivate(player.getWorld(), player)) {
+                triggered = true;
+                setCooldown(ability.getCooldownTime(player));
+
+                if (player.isClientPlayer()) {
+                    T data = ability.tryActivate(player);
+
+                    if (data != null) {
+                        Channel.PLAYER_ABILITY.send(new MsgPlayerAbility<>(ability, data));
+                    } else {
+                        setCooldown(0);
+                    }
+                }
+            }
+
+            if (cooldown <= 0) {
+                setActiveAbility(null);
             }
         }
 
-        public boolean tickInactive() {
-            return cooldown > 0 && cooldown-- > 0;
+        public Optional<Ability<?>> getAbility() {
+            Race race = player.getSpecies();
+            return Abilities.BY_SLOT.get(slot).stream().filter(a -> a.canUse(race)).findFirst();
+        }
+
+        protected synchronized void setActiveAbility(Ability<?> power) {
+            if (activeAbility.orElse(null) != power) {
+                triggered = false;
+                activeAbility = Optional.ofNullable(power);
+                setWarmup(activeAbility.map(p -> p.getWarmupTime(player)).orElse(0));
+                setCooldown(0);
+            }
+        }
+
+        protected synchronized Optional<Ability<?>> getActiveAbility() {
+            return activeAbility.filter(ability -> {
+                return (!(ability == null || (triggered && warmup == 0 && cooldown == 0)) && ability.canUse(player.getSpecies()));
+            });
         }
 
         @Override
@@ -244,6 +201,10 @@ public class AbilityDispatcher implements Tickable, NbtSerialisable {
             compound.putInt("cooldown", cooldown);
             compound.putInt("maxWarmup", maxWarmup);
             compound.putInt("maxCooldown", maxCooldown);
+            compound.putBoolean("triggered", triggered);
+            getActiveAbility().ifPresent(ability -> {
+                compound.putString("activeAbility", Abilities.REGISTRY.getId(ability).toString());
+            });
         }
 
         @Override
@@ -252,6 +213,8 @@ public class AbilityDispatcher implements Tickable, NbtSerialisable {
             cooldown = compound.getInt("cooldown");
             maxWarmup = compound.getInt("maxWarmup");
             maxCooldown = compound.getInt("maxCooldown");
+            triggered = compound.getBoolean("triggered");
+            activeAbility = Abilities.REGISTRY.getOrEmpty(new Identifier(compound.getString("activeAbility")));
         }
     }
 }
diff --git a/src/main/java/com/minelittlepony/unicopia/ability/CarryAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/CarryAbility.java
index 38d0d0cc..580c9c80 100644
--- a/src/main/java/com/minelittlepony/unicopia/ability/CarryAbility.java
+++ b/src/main/java/com/minelittlepony/unicopia/ability/CarryAbility.java
@@ -71,11 +71,11 @@ public class CarryAbility implements Ability<Hit> {
     }
 
     @Override
-    public void preApply(Pony player) {
+    public void preApply(Pony player, AbilitySlot slot) {
     }
 
     @Override
-    public void postApply(Pony player) {
+    public void postApply(Pony player, AbilitySlot slot) {
     }
 
     public interface IPickupImmuned {
diff --git a/src/main/java/com/minelittlepony/unicopia/ability/ChangelingDisguiseAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/ChangelingDisguiseAbility.java
index 94a9fc15..4a43d8da 100644
--- a/src/main/java/com/minelittlepony/unicopia/ability/ChangelingDisguiseAbility.java
+++ b/src/main/java/com/minelittlepony/unicopia/ability/ChangelingDisguiseAbility.java
@@ -78,13 +78,13 @@ public class ChangelingDisguiseAbility extends ChangelingFeedAbility {
     }
 
     @Override
-    public void preApply(Pony player) {
-        player.getMagicalReserves().addEnergy(2);
+    public void preApply(Pony player, AbilitySlot slot) {
+        player.getMagicalReserves().addEnergy(20);
         player.spawnParticles(UParticles.CHANGELING_MAGIC, 5);
     }
 
     @Override
-    public void postApply(Pony player) {
+    public void postApply(Pony player, AbilitySlot slot) {
         player.getMagicalReserves().setEnergy(0);
         player.spawnParticles(UParticles.CHANGELING_MAGIC, 5);
     }
diff --git a/src/main/java/com/minelittlepony/unicopia/ability/ChangelingFeedAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/ChangelingFeedAbility.java
index 9a9eae22..e29fe103 100644
--- a/src/main/java/com/minelittlepony/unicopia/ability/ChangelingFeedAbility.java
+++ b/src/main/java/com/minelittlepony/unicopia/ability/ChangelingFeedAbility.java
@@ -148,12 +148,12 @@ public class ChangelingFeedAbility implements Ability<Hit> {
     }
 
     @Override
-    public void preApply(Pony player) {
+    public void preApply(Pony player, AbilitySlot slot) {
         player.getMagicalReserves().addExertion(6);
     }
 
     @Override
-    public void postApply(Pony player) {
+    public void postApply(Pony player, AbilitySlot slot) {
         player.spawnParticles(ParticleTypes.HEART, 1);
     }
 }
diff --git a/src/main/java/com/minelittlepony/unicopia/ability/ChangelingTrapAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/ChangelingTrapAbility.java
index 57a30102..9489464a 100644
--- a/src/main/java/com/minelittlepony/unicopia/ability/ChangelingTrapAbility.java
+++ b/src/main/java/com/minelittlepony/unicopia/ability/ChangelingTrapAbility.java
@@ -43,12 +43,12 @@ public class ChangelingTrapAbility implements Ability<Hit> {
     }
 
     @Override
-    public void preApply(Pony player) {
+    public void preApply(Pony player, AbilitySlot slot) {
 
     }
 
     @Override
-    public void postApply(Pony player) {
+    public void postApply(Pony player, AbilitySlot slot) {
 
     }
 }
diff --git a/src/main/java/com/minelittlepony/unicopia/ability/EarthPonyGrowAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/EarthPonyGrowAbility.java
index 0ac5997c..9e7f815c 100644
--- a/src/main/java/com/minelittlepony/unicopia/ability/EarthPonyGrowAbility.java
+++ b/src/main/java/com/minelittlepony/unicopia/ability/EarthPonyGrowAbility.java
@@ -81,8 +81,8 @@ public class EarthPonyGrowAbility implements Ability<Pos> {
     }
 
     @Override
-    public void preApply(Pony player) {
-        player.getMagicalReserves().addExertion(3);
+    public void preApply(Pony player, AbilitySlot slot) {
+        player.getMagicalReserves().addExertion(30);
 
         if (player.getWorld().isClient()) {
             player.spawnParticles(MagicParticleEffect.UNICORN, 1);
@@ -90,7 +90,7 @@ public class EarthPonyGrowAbility implements Ability<Pos> {
     }
 
     @Override
-    public void postApply(Pony player) {
+    public void postApply(Pony player, AbilitySlot slot) {
 
     }
 }
diff --git a/src/main/java/com/minelittlepony/unicopia/ability/EarthPonyStompAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/EarthPonyStompAbility.java
index 71572f6e..29ed6ac6 100644
--- a/src/main/java/com/minelittlepony/unicopia/ability/EarthPonyStompAbility.java
+++ b/src/main/java/com/minelittlepony/unicopia/ability/EarthPonyStompAbility.java
@@ -186,14 +186,14 @@ public class EarthPonyStompAbility implements Ability<Multi> {
     }
 
     @Override
-    public void preApply(Pony player) {
+    public void preApply(Pony player, AbilitySlot slot) {
         player.getMagicalReserves().addExertion(40);
         player.getOwner().attemptSprintingParticles();
     }
 
     @Override
-    public void postApply(Pony player) {
-        int timeDiff = getCooldownTime(player) - player.getAbilities().getStat(player.getAbilities().getActiveSlot()).getRemainingCooldown();
+    public void postApply(Pony player, AbilitySlot slot) {
+        int timeDiff = getCooldownTime(player) - player.getAbilities().getStat(slot).getRemainingCooldown();
 
         if (player.getOwner().getEntityWorld().getTime() % 1 == 0 || timeDiff == 0) {
             spawnParticleRing(player.getOwner(), timeDiff, 1);
diff --git a/src/main/java/com/minelittlepony/unicopia/ability/PegasusCloudInteractionAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/PegasusCloudInteractionAbility.java
index 14565897..5b2b343c 100644
--- a/src/main/java/com/minelittlepony/unicopia/ability/PegasusCloudInteractionAbility.java
+++ b/src/main/java/com/minelittlepony/unicopia/ability/PegasusCloudInteractionAbility.java
@@ -66,12 +66,12 @@ public class PegasusCloudInteractionAbility implements Ability<Numeric> {
     }
 
     @Override
-    public void preApply(Pony player) {
+    public void preApply(Pony player, AbilitySlot slot) {
         player.spawnParticles(MagicParticleEffect.UNICORN, 10);
     }
 
     @Override
-    public void postApply(Pony player) {
+    public void postApply(Pony player, AbilitySlot slot) {
         player.spawnParticles(UParticles.RAIN_DROPS, 5);
     }
 
diff --git a/src/main/java/com/minelittlepony/unicopia/ability/UnicornCastingAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/UnicornCastingAbility.java
index 3bc87193..3dbc104a 100644
--- a/src/main/java/com/minelittlepony/unicopia/ability/UnicornCastingAbility.java
+++ b/src/main/java/com/minelittlepony/unicopia/ability/UnicornCastingAbility.java
@@ -48,12 +48,12 @@ public class UnicornCastingAbility implements Ability<Hit> {
     }
 
     @Override
-    public void preApply(Pony player) {
+    public void preApply(Pony player, AbilitySlot slot) {
         player.spawnParticles(MagicParticleEffect.UNICORN, 5);
     }
 
     @Override
-    public void postApply(Pony player) {
+    public void postApply(Pony player, AbilitySlot slot) {
         player.spawnParticles(MagicParticleEffect.UNICORN, 5);
     }
 }
diff --git a/src/main/java/com/minelittlepony/unicopia/ability/UnicornTeleportAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/UnicornTeleportAbility.java
index c856a789..4722f26e 100644
--- a/src/main/java/com/minelittlepony/unicopia/ability/UnicornTeleportAbility.java
+++ b/src/main/java/com/minelittlepony/unicopia/ability/UnicornTeleportAbility.java
@@ -151,13 +151,13 @@ public class UnicornTeleportAbility implements Ability<Pos> {
     }
 
     @Override
-    public void preApply(Pony player) {
+    public void preApply(Pony player, AbilitySlot slot) {
         player.getMagicalReserves().addExertion(30);
         player.spawnParticles(MagicParticleEffect.UNICORN, 5);
     }
 
     @Override
-    public void postApply(Pony player) {
+    public void postApply(Pony player, AbilitySlot slot) {
         player.spawnParticles(MagicParticleEffect.UNICORN, 5);
     }
 }
diff --git a/src/main/java/com/minelittlepony/unicopia/client/KeyBindingsHandler.java b/src/main/java/com/minelittlepony/unicopia/client/KeyBindingsHandler.java
index 9ced3467..d3b4899c 100644
--- a/src/main/java/com/minelittlepony/unicopia/client/KeyBindingsHandler.java
+++ b/src/main/java/com/minelittlepony/unicopia/client/KeyBindingsHandler.java
@@ -61,7 +61,7 @@ class KeyBindingsHandler {
                 }
             } else if (pressed.remove(i)) {
                 System.out.println("Key up " + slot);
-                iplayer.getAbilities().cancelAbility(slot);
+                iplayer.getAbilities().clear(slot);
             }
         }
     }