diff --git a/src/main/java/com/comandante/creeper/ConfigureNpc.java b/src/main/java/com/comandante/creeper/ConfigureNpc.java
index 2907a39fadfd41b00c1e35f6a738cbc1fec17c2b..16a5f7f09f014796aaf6dd76a0f6c38f045b6eff 100644
--- a/src/main/java/com/comandante/creeper/ConfigureNpc.java
+++ b/src/main/java/com/comandante/creeper/ConfigureNpc.java
@@ -101,7 +101,5 @@ public class ConfigureNpc {
         gameManager.getForageManager().addForageToArea(Area.NORTH3_ZONE, marijuanaForageBuilder);
         gameManager.getForageManager().addForageToArea(Area.BLOODRIDGE2_ZONE, marijuanaForageBuilder);
         gameManager.getForageManager().addForageToArea(Area.BLOODRIDGE1_ZONE, marijuanaForageBuilder);
-
-        SpellTriggerRegistry.addSpell(new LightningSpell(gameManager));
     }
 }
diff --git a/src/main/java/com/comandante/creeper/CreeperUtils.java b/src/main/java/com/comandante/creeper/CreeperUtils.java
index a839e591f86f99d162a1909f0fc9e326750372cc..536fdfd287312fb7bdf7726c44c89e05e5b95e64 100644
--- a/src/main/java/com/comandante/creeper/CreeperUtils.java
+++ b/src/main/java/com/comandante/creeper/CreeperUtils.java
@@ -3,12 +3,14 @@ package com.comandante.creeper;
 import com.google.common.collect.Lists;
 
 import java.util.List;
+import java.util.Random;
 import java.util.stream.Collectors;
 
 public class CreeperUtils {
 
     public static String asciiColorPattern = "\u001B\\[[;\\d]*m";
 
+    private static Random random = new Random();
 
     /*  Prints things "next" to each other, like this:
 -+=[ fibs ]=+-                        | -+=[ fibs ]=+-
@@ -132,4 +134,8 @@ Bag             25        (+15)       | Bag             25        (+15)
         }
         return str.substring(0, len);
     }
+
+    public static int randInt(int min, int max) {
+        return random.nextInt((max - min) + 1) + min;
+    }
 }
diff --git a/src/main/java/com/comandante/creeper/spells/Effect.java b/src/main/java/com/comandante/creeper/Items/Effect.java
similarity index 98%
rename from src/main/java/com/comandante/creeper/spells/Effect.java
rename to src/main/java/com/comandante/creeper/Items/Effect.java
index fce40bdb488e3703e4f39db0209a1ebec04196d3..732f7d123189e8bb5acf002a859b8b4c624b559e 100644
--- a/src/main/java/com/comandante/creeper/spells/Effect.java
+++ b/src/main/java/com/comandante/creeper/Items/Effect.java
@@ -1,4 +1,4 @@
-package com.comandante.creeper.spells;
+package com.comandante.creeper.Items;
 
 
 import com.comandante.creeper.entity.CreeperEntity;
diff --git a/src/main/java/com/comandante/creeper/spells/EffectBuilder.java b/src/main/java/com/comandante/creeper/Items/EffectBuilder.java
similarity index 97%
rename from src/main/java/com/comandante/creeper/spells/EffectBuilder.java
rename to src/main/java/com/comandante/creeper/Items/EffectBuilder.java
index cf863b9653c7b1946f95517e2dafc1a9d17a3919..0a9c83f8d189a2553a1993ab8604ea89b2bc144d 100644
--- a/src/main/java/com/comandante/creeper/spells/EffectBuilder.java
+++ b/src/main/java/com/comandante/creeper/Items/EffectBuilder.java
@@ -1,4 +1,4 @@
-package com.comandante.creeper.spells;
+package com.comandante.creeper.Items;
 
 import com.comandante.creeper.stat.Stats;
 
diff --git a/src/main/java/com/comandante/creeper/spells/EffectSerializer.java b/src/main/java/com/comandante/creeper/Items/EffectSerializer.java
similarity index 94%
rename from src/main/java/com/comandante/creeper/spells/EffectSerializer.java
rename to src/main/java/com/comandante/creeper/Items/EffectSerializer.java
index ae991543deb8d624804b83da69021d27527fdd1c..fe5549a18129b642c026f045c4b10cb9383f7d6e 100644
--- a/src/main/java/com/comandante/creeper/spells/EffectSerializer.java
+++ b/src/main/java/com/comandante/creeper/Items/EffectSerializer.java
@@ -1,6 +1,5 @@
 package com.comandante.creeper.Items;
 
-import com.comandante.creeper.spells.Effect;
 import com.google.gson.GsonBuilder;
 import org.mapdb.Serializer;
 
diff --git a/src/main/java/com/comandante/creeper/spells/EffectsManager.java b/src/main/java/com/comandante/creeper/Items/EffectsManager.java
similarity index 65%
rename from src/main/java/com/comandante/creeper/spells/EffectsManager.java
rename to src/main/java/com/comandante/creeper/Items/EffectsManager.java
index 2cfd600c80546bfd45f05d5ffaa3c5855adb95e6..e8d6d0ae7dcf49cb081d22923116788938b48a41 100644
--- a/src/main/java/com/comandante/creeper/spells/EffectsManager.java
+++ b/src/main/java/com/comandante/creeper/Items/EffectsManager.java
@@ -1,4 +1,4 @@
-package com.comandante.creeper.spells;
+package com.comandante.creeper.Items;
 
 import com.comandante.creeper.managers.GameManager;
 import com.comandante.creeper.npc.Npc;
@@ -10,19 +10,57 @@ import com.comandante.creeper.server.Color;
 import com.comandante.creeper.stat.Stats;
 import com.comandante.creeper.stat.StatsBuilder;
 import com.comandante.creeper.stat.StatsHelper;
+import org.apache.log4j.Logger;
 
 import java.text.NumberFormat;
 import java.util.Arrays;
 import java.util.Locale;
+import java.util.Set;
 
 public class EffectsManager {
 
     private final GameManager gameManager;
 
+    private static final Logger log = Logger.getLogger(EffectsManager.class);
+
     public EffectsManager(GameManager gameManager) {
         this.gameManager = gameManager;
     }
 
+    public void applyEffectsToNpcs(Player player, Set<Npc> npcs, Set<Effect> effects) {
+        effects.forEach(effect ->
+                npcs.forEach(npc -> {
+                    Effect nEffect = new Effect(effect);
+                    nEffect.setPlayerId(player.getPlayerId());
+                    if (effect.getDurationStats().getCurrentHealth() < 0) {
+                        log.error("ERROR! Someone added an effect with a health modifier which won't work for various reasons.");
+                        return;
+                    }
+                    StatsHelper.combineStats(npc.getStats(), effect.getDurationStats());
+                    npc.addEffect(nEffect);
+                }));
+    }
+
+    public void applyEffectsToPlayer(Player destinationPlayer, Player player, Set<Effect> effects) {
+        for (Effect effect : effects) {
+            Effect nEffect = new Effect(effect);
+            nEffect.setPlayerId(player.getPlayerId());
+            gameManager.getEntityManager().saveEffect(nEffect);
+            if (effect.getDurationStats().getCurrentHealth() < 0) {
+                log.error("ERROR! Someone added an effect with a health modifier which won't work for various reasons.");
+                continue;
+            }
+            String effectApplyMessage;
+            if (destinationPlayer.addEffect(effect.getEntityId())) {
+                effectApplyMessage = Color.BOLD_ON + Color.GREEN + "[effect] " + Color.RESET + nEffect.getEffectName() + " applied!" + "\r\n";
+                gameManager.getChannelUtils().write(destinationPlayer.getPlayerId(), effectApplyMessage);
+            } else {
+                effectApplyMessage = Color.BOLD_ON + Color.GREEN + "[effect] " + Color.RESET + Color.RED + "Unable to apply " + nEffect.getEffectName() + "!" + "\r\n";
+                gameManager.getChannelUtils().write(player.getPlayerId(), effectApplyMessage);
+            }
+        }
+    }
+
     public void application(Effect effect, Player player) {
         // if there are effecst that modify player health, deal with it here, you can't rely on combine stats.
         Stats applyStatsOnTick = effect.getApplyStatsOnTick();
diff --git a/src/main/java/com/comandante/creeper/Items/Item.java b/src/main/java/com/comandante/creeper/Items/Item.java
index b326917ff59314aa40162eceda00417e6cca3f9e..13771c379770000b1500db2ab1e651931f3f1c3d 100644
--- a/src/main/java/com/comandante/creeper/Items/Item.java
+++ b/src/main/java/com/comandante/creeper/Items/Item.java
@@ -2,7 +2,6 @@ package com.comandante.creeper.Items;
 
 
 import com.comandante.creeper.player.Equipment;
-import com.comandante.creeper.spells.Effect;
 
 import java.io.Serializable;
 import java.util.List;
diff --git a/src/main/java/com/comandante/creeper/Items/ItemUseAction.java b/src/main/java/com/comandante/creeper/Items/ItemUseAction.java
index e30cb3254fd368808d8773407912e86c134271a8..e498e967642debd0b4a1fc291fa99745b0a86e55 100644
--- a/src/main/java/com/comandante/creeper/Items/ItemUseAction.java
+++ b/src/main/java/com/comandante/creeper/Items/ItemUseAction.java
@@ -2,7 +2,6 @@ package com.comandante.creeper.Items;
 
 import com.comandante.creeper.managers.GameManager;
 import com.comandante.creeper.player.Player;
-import com.comandante.creeper.spells.Effect;
 
 import java.util.Set;
 
diff --git a/src/main/java/com/comandante/creeper/Items/use/DefaultApplyStatsAction.java b/src/main/java/com/comandante/creeper/Items/use/DefaultApplyStatsAction.java
index c92eddea35486b4d67540f97899c3ff53dba0dbe..10602c9f474c5e85503989c529ec177124a40443 100644
--- a/src/main/java/com/comandante/creeper/Items/use/DefaultApplyStatsAction.java
+++ b/src/main/java/com/comandante/creeper/Items/use/DefaultApplyStatsAction.java
@@ -1,12 +1,8 @@
 package com.comandante.creeper.Items.use;
 
-import com.comandante.creeper.Items.Item;
-import com.comandante.creeper.Items.ItemType;
-import com.comandante.creeper.Items.ItemUseAction;
-import com.comandante.creeper.Items.ItemUseHandler;
+import com.comandante.creeper.Items.*;
 import com.comandante.creeper.managers.GameManager;
 import com.comandante.creeper.player.Player;
-import com.comandante.creeper.spells.Effect;
 import com.comandante.creeper.stat.Stats;
 import org.apache.log4j.Logger;
 
diff --git a/src/main/java/com/comandante/creeper/Items/use/DirtyBombUseAction.java b/src/main/java/com/comandante/creeper/Items/use/DirtyBombUseAction.java
index e291a97940ea3409f38e622db3818d341f986f83..5e874e7f1665fb67b31096be354f4213ed0d8857 100644
--- a/src/main/java/com/comandante/creeper/Items/use/DirtyBombUseAction.java
+++ b/src/main/java/com/comandante/creeper/Items/use/DirtyBombUseAction.java
@@ -1,15 +1,11 @@
 package com.comandante.creeper.Items.use;
 
-import com.comandante.creeper.Items.Item;
-import com.comandante.creeper.Items.ItemType;
-import com.comandante.creeper.Items.ItemUseAction;
-import com.comandante.creeper.Items.ItemUseHandler;
+import com.comandante.creeper.Items.*;
 import com.comandante.creeper.managers.GameManager;
 import com.comandante.creeper.npc.Npc;
 import com.comandante.creeper.npc.NpcStatsChangeBuilder;
 import com.comandante.creeper.player.Player;
 import com.comandante.creeper.server.Color;
-import com.comandante.creeper.spells.Effect;
 import com.comandante.creeper.stat.StatsBuilder;
 import com.comandante.creeper.world.Room;
 
diff --git a/src/main/java/com/comandante/creeper/Items/use/LightningSpellBookUseAction.java b/src/main/java/com/comandante/creeper/Items/use/LightningSpellBookUseAction.java
index bf40f416630d6ed4d242f8031502c0160d1b78a4..35d261c37e5fe69cbf41fda351431810f5a799d5 100644
--- a/src/main/java/com/comandante/creeper/Items/use/LightningSpellBookUseAction.java
+++ b/src/main/java/com/comandante/creeper/Items/use/LightningSpellBookUseAction.java
@@ -1,12 +1,12 @@
 package com.comandante.creeper.Items.use;
 
+import com.comandante.creeper.Items.Effect;
 import com.comandante.creeper.Items.Item;
 import com.comandante.creeper.Items.ItemType;
 import com.comandante.creeper.Items.ItemUseAction;
 import com.comandante.creeper.managers.GameManager;
 import com.comandante.creeper.player.Player;
-import com.comandante.creeper.spells.Effect;
-import com.comandante.creeper.spells.LightningSpell;
+import com.comandante.creeper.spells.LightningSpellRunnable;
 
 import java.util.Set;
 
@@ -27,13 +27,13 @@ public class LightningSpellBookUseAction implements ItemUseAction {
 
     @Override
     public void executeAction(GameManager gameManager, Player player, Item item) {
-        if (player.getLearnedSpells().contains(LightningSpell.NAME)) {
-            gameManager.getChannelUtils().write(player.getPlayerId(), "You already know how to use " + LightningSpell.NAME);
+        if (player.getLearnedSpells().contains(LightningSpellRunnable.name)) {
+            gameManager.getChannelUtils().write(player.getPlayerId(), "You already know how to use " + LightningSpellRunnable.name);
             dontDelete = true;
             return;
         }
         gameManager.writeToPlayerCurrentRoom(player.getPlayerId(), player.getPlayerName() + " reads a leatherbound aging spell book and gains knowledge about lightning spells.");
-        player.addLearnedSpellByName(LightningSpell.NAME);
+        player.addLearnedSpellByName(LightningSpellRunnable.name);
     }
 
     @Override
diff --git a/src/main/java/com/comandante/creeper/Items/use/ResetAllEffectsUseAction.java b/src/main/java/com/comandante/creeper/Items/use/ResetAllEffectsUseAction.java
index bae77982e6a219e0a298dd44c76033b94bc41876..7becf179e4169709d3baf6c1293ead467d94e582 100644
--- a/src/main/java/com/comandante/creeper/Items/use/ResetAllEffectsUseAction.java
+++ b/src/main/java/com/comandante/creeper/Items/use/ResetAllEffectsUseAction.java
@@ -1,12 +1,8 @@
 package com.comandante.creeper.Items.use;
 
-import com.comandante.creeper.Items.Item;
-import com.comandante.creeper.Items.ItemType;
-import com.comandante.creeper.Items.ItemUseAction;
-import com.comandante.creeper.Items.ItemUseHandler;
+import com.comandante.creeper.Items.*;
 import com.comandante.creeper.managers.GameManager;
 import com.comandante.creeper.player.Player;
-import com.comandante.creeper.spells.Effect;
 
 import java.util.Set;
 
diff --git a/src/main/java/com/comandante/creeper/blackjack/Deck.java b/src/main/java/com/comandante/creeper/blackjack/Deck.java
index 8ebc0a5d1f668bb06a907a6e9c5e97eda374b834..86fba58170db4962c499eb512e63621b3aa47319 100644
--- a/src/main/java/com/comandante/creeper/blackjack/Deck.java
+++ b/src/main/java/com/comandante/creeper/blackjack/Deck.java
@@ -7,7 +7,7 @@ import java.util.*;
 
 public class Deck implements Iterator<BlackJack.Card> {
 
-    enum Type {
+    public enum Type {
         ACE(1, "A"),
         KING(10, "K"),
         QUEEN(10, "Q"),
@@ -38,7 +38,7 @@ public class Deck implements Iterator<BlackJack.Card> {
         }
     }
 
-    enum Suit {
+    public enum Suit {
         SPADES("â™ "),
         HEARTS("♥"),
         DIAMONDS("♦"),
diff --git a/src/main/java/com/comandante/creeper/bot/commands/CardsCommand.java b/src/main/java/com/comandante/creeper/bot/commands/CardsCommand.java
index 50ad41abb983ab1d1f17bbf54a42396b3d914c92..4a7133b9baf04e86961a00dab11986a06ddd9603 100644
--- a/src/main/java/com/comandante/creeper/bot/commands/CardsCommand.java
+++ b/src/main/java/com/comandante/creeper/bot/commands/CardsCommand.java
@@ -1,5 +1,6 @@
 package com.comandante.creeper.bot.commands;
 
+import com.comandante.creeper.CreeperUtils;
 import com.comandante.creeper.blackjack.BlackJack;
 import com.comandante.creeper.blackjack.Deck;
 import com.comandante.creeper.bot.BotCommandManager;
@@ -24,9 +25,8 @@ public class CardsCommand extends BotCommand {
         Deck deck = new Deck();
         deck.shuffle();
         List<BlackJack.Card> cards = com.google.common.collect.Lists.newArrayList(deck.next(), deck.next(), deck.next(), deck.next(), deck.deal());
-        String asciiPlayingCardHand = BlackJack.getAsciiPlayingCardHand(cards);
-        List<String> resp = Lists.newArrayList();
-        resp.addAll(Lists.newArrayList(asciiPlayingCardHand.split("[\\r\\n]+")));
-        return resp;
+        StringBuilder sb = new StringBuilder();
+        cards.forEach(card -> sb.append(card.type.textRepresentation).append(card.suit.textRepresentation).append(" / "));
+        return Lists.newArrayList(CreeperUtils.replaceLast(sb.toString(), " / ", ""));
     }
 }
diff --git a/src/main/java/com/comandante/creeper/command/CastCommand.java b/src/main/java/com/comandante/creeper/command/CastCommand.java
index ae7e281d4090f26e90bf111002dc3edb6841456a..d6ee3039d20334d6118bfab11be8762d3137acab 100644
--- a/src/main/java/com/comandante/creeper/command/CastCommand.java
+++ b/src/main/java/com/comandante/creeper/command/CastCommand.java
@@ -5,15 +5,14 @@ import com.comandante.creeper.managers.GameManager;
 import com.comandante.creeper.npc.Npc;
 import com.comandante.creeper.player.CoolDownType;
 import com.comandante.creeper.player.Player;
-import com.comandante.creeper.spells.Spell;
-import com.comandante.creeper.spells.SpellTriggerRegistry;
+import com.comandante.creeper.spells.SpellRunnable;
 import com.google.common.base.Joiner;
-import com.google.common.collect.Sets;
 import org.jboss.netty.channel.ChannelHandlerContext;
 import org.jboss.netty.channel.MessageEvent;
 
 import java.util.Arrays;
 import java.util.List;
+import java.util.Optional;
 
 public class CastCommand extends Command {
 
@@ -41,42 +40,37 @@ public class CastCommand extends Command {
                 return;
             }
             String desiredSpellName = originalMessageParts.get(1);
-            Spell spell = SpellTriggerRegistry.getSpell(desiredSpellName);
-            if (spell == null || !player.doesHaveSpellLearned(spell.getSpellName())) {
+            Optional<SpellRunnable> spellRunnable = gameManager.getSpells().getSpellRunnable(desiredSpellName);
+            if (!spellRunnable.isPresent() || !player.doesHaveSpellLearned(spellRunnable.get().getName())) {
                 write("No spell found with the name: " + desiredSpellName + "\r\n");
                 return;
             }
-            if (player.isActiveSpellCoolDown(spell.getSpellName())) {
+            if (player.isActiveSpellCoolDown(spellRunnable.get().getName())) {
                 write("That spell is still in cooldown.\r\n");
                 write(gameManager.renderCoolDownString(player.getCoolDowns()));
                 return;
             }
             if (originalMessageParts.size() == 2) {
-                if (spell.isAreaSpell()) {
-                    spell.attackSpell(currentRoom.getNpcIds(), player);
-                    return;
-                } else {
-                    write("Spell is not an area of attack. Need to specify a target.\r\n");
-                    return;
-                }
+                gameManager.getSpells().executeSpell(player, Optional.empty(), Optional.empty(), spellRunnable.get());
+                return;
             }
             originalMessageParts.remove(0);
             originalMessageParts.remove(0);
             String target = Joiner.on(" ").join(originalMessageParts);
             if (player.getPlayerName().equals(target)) {
-                spell.attackSpell(this.player, this.player);
+                gameManager.getSpells().executeSpell(player, Optional.empty(), Optional.ofNullable(player), spellRunnable.get());
                 return;
             }
             for (Player destinationPlayer : roomManager.getPresentPlayers(currentRoom)) {
                 if (destinationPlayer.getPlayerName().equalsIgnoreCase(target)) {
-                    spell.attackSpell(destinationPlayer, this.player);
+                    gameManager.getSpells().executeSpell(player, Optional.empty(), Optional.of(destinationPlayer), spellRunnable.get());
                     return;
                 }
             }
             for (String npcId : currentRoom.getNpcIds()) {
                 Npc npcEntity = entityManager.getNpcEntity(npcId);
                 if (npcEntity.getValidTriggers().contains(target)) {
-                    spell.attackSpell(Sets.newHashSet(npcId), player);
+                    gameManager.getSpells().executeSpell(player, Optional.of(npcEntity), Optional.empty(), spellRunnable.get());
                     return;
                 }
             }
diff --git a/src/main/java/com/comandante/creeper/command/MovementCommand.java b/src/main/java/com/comandante/creeper/command/MovementCommand.java
index b8c024cf44cfa9f253df5c11a790ce99e067b2be..be5e29371f142ff69c27136f50f2b9d59bc58948 100644
--- a/src/main/java/com/comandante/creeper/command/MovementCommand.java
+++ b/src/main/java/com/comandante/creeper/command/MovementCommand.java
@@ -1,9 +1,9 @@
 package com.comandante.creeper.command;
 
+import com.comandante.creeper.Items.Effect;
 import com.comandante.creeper.managers.GameManager;
 import com.comandante.creeper.player.CoolDownType;
 import com.comandante.creeper.player.PlayerMovement;
-import com.comandante.creeper.spells.Effect;
 import com.comandante.creeper.world.RemoteExit;
 import com.comandante.creeper.world.Room;
 import com.google.common.base.Optional;
diff --git a/src/main/java/com/comandante/creeper/command/PickUpCommand.java b/src/main/java/com/comandante/creeper/command/PickUpCommand.java
index 6a8614dbc4aa1f8a19aff2431008c2dd33d23324..4509647d1e6208fd75d9f044e5bbac7c23de7426 100644
--- a/src/main/java/com/comandante/creeper/command/PickUpCommand.java
+++ b/src/main/java/com/comandante/creeper/command/PickUpCommand.java
@@ -34,6 +34,8 @@ public class PickUpCommand extends Command {
                             String playerName = player.getPlayerName();
                             gameManager.roomSay(currentRoom.getRoomId(), playerName + " picked up " + itemEntity.getItemName(), playerId);
                             return;
+                        } else {
+                            return;
                         }
                     }
                 }
diff --git a/src/main/java/com/comandante/creeper/command/admin/TeleportCommand.java b/src/main/java/com/comandante/creeper/command/admin/TeleportCommand.java
index a0ba7ce2784cdc177f23ddcb4119a18cf2cb3f2f..d394cef79cbd8fb9a432bd40e0dd82cfe1ba14e8 100644
--- a/src/main/java/com/comandante/creeper/command/admin/TeleportCommand.java
+++ b/src/main/java/com/comandante/creeper/command/admin/TeleportCommand.java
@@ -1,6 +1,7 @@
 package com.comandante.creeper.command.admin;
 
 
+import com.comandante.creeper.Items.Effect;
 import com.comandante.creeper.command.Command;
 import com.comandante.creeper.managers.GameManager;
 import com.comandante.creeper.player.CoolDownType;
@@ -8,7 +9,6 @@ import com.comandante.creeper.player.Player;
 import com.comandante.creeper.player.PlayerMovement;
 import com.comandante.creeper.player.PlayerRole;
 import com.comandante.creeper.server.Color;
-import com.comandante.creeper.spells.Effect;
 import com.comandante.creeper.world.Room;
 import com.google.common.collect.Sets;
 import org.jboss.netty.channel.ChannelHandlerContext;
diff --git a/src/main/java/com/comandante/creeper/entity/EntityManager.java b/src/main/java/com/comandante/creeper/entity/EntityManager.java
index ff637721337ad9bb7d048efab38e0b07b9496984..e4824c8c025cd5aa97097d756abc8fa8bcf47355 100644
--- a/src/main/java/com/comandante/creeper/entity/EntityManager.java
+++ b/src/main/java/com/comandante/creeper/entity/EntityManager.java
@@ -1,5 +1,6 @@
 package com.comandante.creeper.entity;
 
+import com.comandante.creeper.Items.Effect;
 import com.comandante.creeper.Items.EffectSerializer;
 import com.comandante.creeper.Items.Item;
 import com.comandante.creeper.Items.ItemSerializer;
@@ -8,7 +9,6 @@ import com.comandante.creeper.managers.SentryManager;
 import com.comandante.creeper.npc.Npc;
 import com.comandante.creeper.player.Player;
 import com.comandante.creeper.player.PlayerManager;
-import com.comandante.creeper.spells.Effect;
 import com.comandante.creeper.world.Room;
 import com.comandante.creeper.world.RoomManager;
 import org.apache.log4j.Logger;
diff --git a/src/main/java/com/comandante/creeper/managers/GameManager.java b/src/main/java/com/comandante/creeper/managers/GameManager.java
index 13e1e41a6d4a2baf158392d8a9b0d02c809f9260..da0c6ecb11b2b4ef58efaf0f1a923e2e23bfd75d 100644
--- a/src/main/java/com/comandante/creeper/managers/GameManager.java
+++ b/src/main/java/com/comandante/creeper/managers/GameManager.java
@@ -19,8 +19,7 @@ import com.comandante.creeper.server.Color;
 import com.comandante.creeper.server.GossipCache;
 import com.comandante.creeper.server.MultiLineInputManager;
 import com.comandante.creeper.spawner.NpcSpawner;
-import com.comandante.creeper.spells.Effect;
-import com.comandante.creeper.spells.EffectsManager;
+import com.comandante.creeper.spells.Spells;
 import com.comandante.creeper.stat.Stats;
 import com.comandante.creeper.stat.StatsBuilder;
 import com.comandante.creeper.world.*;
@@ -68,6 +67,7 @@ public class GameManager {
     private final TimeTracker timeTracker;
     private final ItemUseHandler itemUseHandler;
     private final NpcMover npcMover;
+    private final Spells spells;
     private final SingleThreadedCreeperEventProcessor eventProcessor = new SingleThreadedCreeperEventProcessor(new ArrayBlockingQueue<>(100000));
 
     public GameManager(CreeperConfiguration creeperConfiguration, RoomManager roomManager, PlayerManager playerManager, EntityManager entityManager, MapsManager mapsManager, ChannelCommunicationUtils channelUtils) {
@@ -94,9 +94,14 @@ public class GameManager {
         this.entityManager.addEntity(itemDecayManager);
         this.itemUseHandler = new ItemUseHandler(this);
         this.npcMover = new NpcMover(this);
+        this.spells = new Spells(this);
         this.eventProcessor.startAsync();
     }
 
+    public Spells getSpells() {
+        return spells;
+    }
+
     public NpcMover getNpcMover() {
         return npcMover;
     }
@@ -460,6 +465,13 @@ public class GameManager {
             sb.append("(").append(Color.GREEN).append("+").append(getFormattedNumber(diff.getStrength())).append(Color.RESET).append(")");
         t.addCell(sb.toString());
 
+        sb = new StringBuilder();
+        t.addCell("Intelligence");
+        t.addCell(getFormattedNumber(stats.getIntelligence()));
+        if (diff.getStrength() > 0)
+            sb.append("(").append(Color.GREEN).append("+").append(getFormattedNumber(diff.getIntelligence())).append(Color.RESET).append(")");
+        t.addCell(sb.toString());
+
         sb = new StringBuilder();
         t.addCell("Willpower");
         t.addCell(getFormattedNumber(stats.getWillpower()));
diff --git a/src/main/java/com/comandante/creeper/npc/Npc.java b/src/main/java/com/comandante/creeper/npc/Npc.java
index a343305fa2024420d7b6fe99102cec8f57d7b21e..d27276d35d6ac088da801ee5d908cf8b38e74a38 100644
--- a/src/main/java/com/comandante/creeper/npc/Npc.java
+++ b/src/main/java/com/comandante/creeper/npc/Npc.java
@@ -1,6 +1,7 @@
 package com.comandante.creeper.npc;
 
 
+import com.comandante.creeper.Items.Effect;
 import com.comandante.creeper.Items.Item;
 import com.comandante.creeper.Items.Loot;
 import com.comandante.creeper.Items.Rarity;
@@ -10,7 +11,6 @@ import com.comandante.creeper.managers.SentryManager;
 import com.comandante.creeper.player.*;
 import com.comandante.creeper.server.Color;
 import com.comandante.creeper.spawner.SpawnRule;
-import com.comandante.creeper.spells.Effect;
 import com.comandante.creeper.stat.Stats;
 import com.comandante.creeper.stat.StatsBuilder;
 import com.comandante.creeper.stat.StatsHelper;
@@ -112,7 +112,7 @@ public class Npc extends CreeperEntity {
                         processNpcStatChange(npcStatsChange);
                     }
                     if (!isActiveCooldown(CoolDownType.NPC_FIGHT) && !isActiveCooldown(CoolDownType.NPC_ROAM) && currentRoom != null) {
-                        if (getRandPercent(.1)) {
+                        if (getRandPercent(.01)) {
                             gameManager.getNpcMover().roam(getEntityId());
                         }
                     }
diff --git a/src/main/java/com/comandante/creeper/player/BasicPlayerLevelStatsModifier.java b/src/main/java/com/comandante/creeper/player/BasicPlayerLevelStatsModifier.java
index bd62876923a7155295f50eadf884d68f3a6c5298..b84ef6b2fd3b493636384501230bff8965c75eb6 100644
--- a/src/main/java/com/comandante/creeper/player/BasicPlayerLevelStatsModifier.java
+++ b/src/main/java/com/comandante/creeper/player/BasicPlayerLevelStatsModifier.java
@@ -17,6 +17,7 @@ public class BasicPlayerLevelStatsModifier implements StatsModifier {
 
     private static double MELE_CONSTANT_MODIFIER = 1.01;
     private static double WILLPOWER_CONSTANT_MODIFIER = 1.01;
+    private static double INTELLIGENCE_CONSTANT_MODIFIER = 1.01;
     private static double AGILE_CONSTANT_MODIFIER = 1.01;
     private static double AIM_CONSTANT_MODIFIER = 1.01;
     private static double HEALTH_CONSTANT_MODIFIER = 4;
@@ -34,6 +35,11 @@ public class BasicPlayerLevelStatsModifier implements StatsModifier {
         return (long) Math.floor(v) + baseStat;
     }
 
+    public static long getIntelligenceForLevel(long baseStat, long level) {
+        double v = (level) * sqrt(pow(level, INTELLIGENCE_CONSTANT_MODIFIER));
+        return (long) Math.floor(v) + baseStat;
+    }
+
     public static long getAgileForLevel(long baseStat, long level) {
         double v = (level) * sqrt(pow(level, AGILE_CONSTANT_MODIFIER));
         return (long) Math.floor(v) + baseStat;
@@ -75,12 +81,14 @@ public class BasicPlayerLevelStatsModifier implements StatsModifier {
         long newMaxMana = getManaForLevel(baseStats.getMaxMana(), level);
         long newAimRating = getAimForLevel(baseStats.getAim(), level);
         long newWillpowerRating = getWillpowerForLevel(baseStats.getWillpower(), level);
+        long newIntelligenceRating = getIntelligenceForLevel(baseStats.getIntelligence(), level);
         long newAgileRating = getAgileForLevel(baseStats.getAgile(), level);
         long newMeleRating = getMeleForLevel(baseStats.getMeleSkill(), level);
         StatsBuilder statsBuilder = new StatsBuilder(baseStats);
         statsBuilder.setMaxHealth(newMaxHealth);
         statsBuilder.setArmorRating(newArmorRating);
         statsBuilder.setStrength(newStrengthRating);
+        statsBuilder.setIntelligence(newIntelligenceRating);
         statsBuilder.setMaxMana(newMaxMana);
         statsBuilder.setAim(newAimRating);
         statsBuilder.setWillpower(newWillpowerRating);
diff --git a/src/main/java/com/comandante/creeper/player/Player.java b/src/main/java/com/comandante/creeper/player/Player.java
index 5c6e600be411b383154d25ddb919113b684a321d..80afbee2653a399e1f925727934ef48fa992bb31 100644
--- a/src/main/java/com/comandante/creeper/player/Player.java
+++ b/src/main/java/com/comandante/creeper/player/Player.java
@@ -3,6 +3,7 @@ package com.comandante.creeper.player;
 
 import com.codahale.metrics.Meter;
 import com.comandante.creeper.CreeperUtils;
+import com.comandante.creeper.Items.Effect;
 import com.comandante.creeper.Items.ForageManager;
 import com.comandante.creeper.Items.Item;
 import com.comandante.creeper.Items.ItemType;
@@ -14,7 +15,6 @@ import com.comandante.creeper.npc.Npc;
 import com.comandante.creeper.npc.NpcStatsChangeBuilder;
 import com.comandante.creeper.npc.Temperament;
 import com.comandante.creeper.server.Color;
-import com.comandante.creeper.spells.Effect;
 import com.comandante.creeper.stat.Stats;
 import com.comandante.creeper.stat.StatsBuilder;
 import com.comandante.creeper.stat.StatsHelper;
@@ -216,6 +216,15 @@ public class Player extends CreeperEntity {
         }
     }
 
+    public void writeMessage(String msg) {
+        gameManager.getChannelUtils().write(getPlayerId(), msg);
+    }
+
+    public long getAvailableMana(){
+        return getPlayerStatsWithEquipmentAndLevel().getCurrentMana();
+    }
+
+
     private void addHealth(long addAmt, PlayerMetadata playerMetadata) {
         long currentHealth = playerMetadata.getStats().getCurrentHealth();
         Stats statsModifier = getPlayerStatsWithEquipmentAndLevel();
@@ -268,6 +277,10 @@ public class Player extends CreeperEntity {
         }
     }
 
+    public long getLevel() {
+        return Levels.getLevel(getPlayerMetadata().getStats().getExperience());
+    }
+
     private PlayerMetadata getPlayerMetadata() {
         return gameManager.getPlayerManager().getPlayerMetadata(playerId);
     }
diff --git a/src/main/java/com/comandante/creeper/player/PlayerStats.java b/src/main/java/com/comandante/creeper/player/PlayerStats.java
index 7f2ea2fe9d6a07c324fb32509075dda7b5bae7c5..aa284f6afa9fe69ebe36b1f4f640feecff7d9f50 100644
--- a/src/main/java/com/comandante/creeper/player/PlayerStats.java
+++ b/src/main/java/com/comandante/creeper/player/PlayerStats.java
@@ -7,6 +7,7 @@ public class PlayerStats {
 
     public final static StatsBuilder DEFAULT_PLAYER = new StatsBuilder()
             .setStrength(10)
+            .setIntelligence(5)
             .setWillpower(1)
             .setAim(1)
             .setAgile(1)
diff --git a/src/main/java/com/comandante/creeper/spells/BlackHoleSpell.java b/src/main/java/com/comandante/creeper/spells/BlackHoleSpell.java
deleted file mode 100644
index 24ba6bda17af2d41a44b3a2bcac185c8f2168067..0000000000000000000000000000000000000000
--- a/src/main/java/com/comandante/creeper/spells/BlackHoleSpell.java
+++ /dev/null
@@ -1,59 +0,0 @@
-package com.comandante.creeper.spells;
-
-
-import com.comandante.creeper.managers.GameManager;
-import com.comandante.creeper.player.Player;
-import com.comandante.creeper.server.Color;
-import com.comandante.creeper.stat.Stats;
-import com.comandante.creeper.stat.StatsBuilder;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Sets;
-
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-import static com.comandante.creeper.server.Color.BOLD_ON;
-
-public class BlackHoleSpell extends Spell {
-
-    private final static String NAME = BOLD_ON + Color.BLACK + "black" + Color.RESET + " hole";
-    private final static String DESCRIPTION = "A black hole.";
-    private final static Set<String> validTriggers = new HashSet<String>(Arrays.asList(new String[]
-                    {"black", "black hole", "bh", "b", NAME}
-    ));
-    private final static Stats attackStats = new StatsBuilder()
-            .setStrength(180)
-            .setWeaponRatingMax(60)
-            .setWeaponRatingMin(50)
-            .setNumberOfWeaponRolls(4)
-            .createStats();
-    private final static boolean isAreaSpell = true;
-
-    private final static List<String> attackMessages = Lists.newArrayList("a massive " + BOLD_ON + Color.BLACK + "black hole" + Color.RESET + " begins to form in front of you ");
-    private static int manaCost = 20000000;
-    private final static int coolDownTicks = 4;
-
-    private static EffectBuilder holeEffect = new EffectBuilder()
-            .setEffectApplyMessages(Lists.newArrayList("You are being " + Color.BOLD_ON + Color.BLUE + "nullified" + Color.RESET + " by a black hole!"))
-            .setEffectDescription("a dark vortex of nothingness.")
-            .setEffectName(Color.BOLD_ON + Color.BLACK + "Black vortex of" + Color.RESET + Color.BOLD_ON + Color.BLUE + " NOTHING" + Color.RESET)
-            .setDurationStats(new StatsBuilder().createStats())
-            .setApplyStatsOnTick(new StatsBuilder().setCurrentHealth(-15000000000L).createStats())
-            .setFrozenMovement(false)
-            .setLifeSpanTicks(2);
-
-    public BlackHoleSpell(GameManager gameManager) {
-        super(gameManager, validTriggers, manaCost, attackStats, attackMessages, DESCRIPTION, NAME, Sets.newHashSet(holeEffect.createEffect()), isAreaSpell, null, coolDownTicks);
-    }
-
-    @Override
-    public void attackSpell(Set<String> npcIds, Player player) {
-        Stats playerStats = player.getPlayerStatsWithEquipmentAndLevel();
-        long willpower = playerStats.getWillpower();
-        long i = 66666666666L + (willpower * 3);
-        this.setEffects(Sets.newHashSet(holeEffect.setApplyStatsOnTick(new StatsBuilder().setCurrentHealth(-i).createStats()).createEffect()));
-        super.attackSpell(npcIds, player);
-    }
-}
diff --git a/src/main/java/com/comandante/creeper/spells/ClumsinessSpell.java b/src/main/java/com/comandante/creeper/spells/ClumsinessSpell.java
deleted file mode 100644
index 2fed54cb1a40505e5cb8bccaa3e00f88a0abbfa7..0000000000000000000000000000000000000000
--- a/src/main/java/com/comandante/creeper/spells/ClumsinessSpell.java
+++ /dev/null
@@ -1,62 +0,0 @@
-package com.comandante.creeper.spells;
-
-import com.comandante.creeper.Items.Item;
-import com.comandante.creeper.Items.ItemType;
-import com.comandante.creeper.Items.Loot;
-import com.comandante.creeper.managers.GameManager;
-import com.comandante.creeper.npc.Npc;
-import com.comandante.creeper.player.Player;
-import com.comandante.creeper.server.Color;
-import com.comandante.creeper.stat.Stats;
-import com.comandante.creeper.stat.StatsBuilder;
-import com.comandante.creeper.world.Room;
-import com.google.common.collect.Interner;
-import com.google.common.collect.Interners;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Sets;
-
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-import static com.comandante.creeper.server.Color.BOLD_ON;
-
-public class ClumsinessSpell extends Spell {
-
-    private final static String NAME = BOLD_ON + Color.MAGENTA + "clumsiness" + Color.RESET;
-    private final static String DESCRIPTION = "A noticeable lapse in judgement occurs in your target.";
-    private final static Set<String> validTriggers = new HashSet<String>(Arrays.asList(new String[]
-                    {"clumsiness", "clumsy", NAME}
-    ));
-    private final static Stats attackStats = new StatsBuilder().createStats();
-    private final static boolean isAreaSpell = false;
-
-    private final static List<String> attackMessages = Lists.newArrayList("awkwardness permeates and as a result " + BOLD_ON + Color.MAGENTA + "clumsiness" + Color.RESET + " is had by all.");
-    private final static int manaCost = 300;
-    private final static int coolDownTicks = 30;
-
-    private final static SpellExecute spellExecute = new SpellExecute() {
-        @Override
-        public void executeNpc(GameManager gameManager, Npc npc, Player player) {
-            Interner<String> interner = Interners.newWeakInterner();
-            synchronized (interner.intern(npc.getEntityId())) {
-                Loot loot = npc.getLoot();
-                Room playerCurrentRoom = gameManager.getRoomManager().getPlayerCurrentRoom(player).get();
-                Set<Item> items = gameManager.getLootManager().lootItemsReturn(loot);
-                if (items.size() > 0) {
-                    for (Item item : items) {
-                        gameManager.placeItemInRoom(playerCurrentRoom.getRoomId(), item.getItemId());
-                        gameManager.roomSay(playerCurrentRoom.getRoomId(), npc.getColorName() + Color.MAGENTA + " fumbles " + Color.RESET + item.getItemName(), player.getPlayerId());
-                        gameManager.getItemDecayManager().addItem(item);
-                    }
-                    npc.setLoot(new Loot(loot.getLootGoldMin(), loot.getLootGoldMax(), Sets.<ItemType>newHashSet()));
-                }
-            }
-        }
-    };
-
-    public ClumsinessSpell(GameManager gameManager) {
-        super(gameManager, validTriggers, manaCost, attackStats, attackMessages, DESCRIPTION, NAME, Sets.<Effect>newHashSet(), isAreaSpell, spellExecute, coolDownTicks);
-    }
-}
diff --git a/src/main/java/com/comandante/creeper/spells/FreezeSpell.java b/src/main/java/com/comandante/creeper/spells/FreezeSpell.java
deleted file mode 100644
index 8399b417da63dac931a7df649e0177bca3510764..0000000000000000000000000000000000000000
--- a/src/main/java/com/comandante/creeper/spells/FreezeSpell.java
+++ /dev/null
@@ -1,59 +0,0 @@
-package com.comandante.creeper.spells;
-
-
-import com.comandante.creeper.managers.GameManager;
-import com.comandante.creeper.player.Player;
-import com.comandante.creeper.server.Color;
-import com.comandante.creeper.stat.Stats;
-import com.comandante.creeper.stat.StatsBuilder;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Sets;
-
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-import static com.comandante.creeper.server.Color.BOLD_ON;
-
-public class FreezeSpell extends Spell {
-
-    private final static String NAME = BOLD_ON + Color.CYAN + "freeze" + Color.RESET;
-    private final static String DESCRIPTION = "A vortex of ice.";
-    private final static Set<String> validTriggers = new HashSet<String>(Arrays.asList(new String[]
-                    {"freeze", "f", NAME}
-    ));
-    private final static Stats attackStats = new StatsBuilder()
-            .setStrength(180)
-            .setWeaponRatingMax(60)
-            .setWeaponRatingMin(50)
-            .setNumberOfWeaponRolls(4)
-            .createStats();
-    private final static boolean isAreaSpell = true;
-
-    private final static List<String> attackMessages = Lists.newArrayList("a blizzard of " + BOLD_ON + Color.CYAN + "ice" + Color.RESET + " blasts through the area");
-    private static int manaCost = 3000000;
-    private final static int coolDownTicks = 6;
-
-    private static EffectBuilder freezeEffect = new EffectBuilder()
-            .setEffectApplyMessages(Lists.newArrayList("You are " + Color.BOLD_ON + Color.BLUE + "frozen" + Color.RESET + " by a violent blizzard!"))
-            .setEffectDescription("a torrent of ice crystals.")
-            .setEffectName(Color.BOLD_ON + Color.CYAN + "FROZEN" + Color.RESET)
-            .setDurationStats(new StatsBuilder().createStats())
-            .setApplyStatsOnTick(new StatsBuilder().setCurrentHealth(-666666).createStats())
-            .setFrozenMovement(true)
-            .setLifeSpanTicks(5);
-
-    public FreezeSpell(GameManager gameManager) {
-        super(gameManager, validTriggers, manaCost, attackStats, attackMessages, DESCRIPTION, NAME, Sets.newHashSet(freezeEffect.createEffect()), isAreaSpell, null, coolDownTicks);
-    }
-
-    @Override
-    public void attackSpell(Set<String> npcIds, Player player) {
-        Stats playerStats = player.getPlayerStatsWithEquipmentAndLevel();
-        long willpower = playerStats.getWillpower();
-        long i = 5000000 + (willpower * 3);
-        this.setEffects(Sets.newHashSet(freezeEffect.setApplyStatsOnTick(new StatsBuilder().setCurrentHealth(-i).createStats()).createEffect()));
-        super.attackSpell(npcIds, player);
-    }
-}
diff --git a/src/main/java/com/comandante/creeper/spells/HealingSpell.java b/src/main/java/com/comandante/creeper/spells/HealingSpell.java
deleted file mode 100644
index 826ed597aa243f5720c005503208032dc65abf17..0000000000000000000000000000000000000000
--- a/src/main/java/com/comandante/creeper/spells/HealingSpell.java
+++ /dev/null
@@ -1,50 +0,0 @@
-package com.comandante.creeper.spells;
-
-import com.comandante.creeper.managers.GameManager;
-import com.comandante.creeper.player.Player;
-import com.comandante.creeper.server.Color;
-import com.comandante.creeper.stat.Stats;
-import com.comandante.creeper.stat.StatsBuilder;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Sets;
-
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-import static com.comandante.creeper.server.Color.BOLD_ON;
-
-public class HealingSpell extends Spell {
-
-    private final static String NAME = BOLD_ON + Color.MAGENTA + "healing" + Color.RESET;
-    private final static String DESCRIPTION = "A pure aura of healing.";
-    private final static Set<String> validTriggers = new HashSet<String>(Arrays.asList(new String[]
-                    {"healing", "h", NAME}
-    ));
-    private final static Stats attackStats = new StatsBuilder().createStats();
-    private final static boolean isAreaSpell = false;
-
-    private final static List<String> attackMessages = Lists.newArrayList("an aura of " + BOLD_ON + Color.MAGENTA + "healing" + Color.RESET + " surrounds the area");
-    private static int manaCost = 80000000;
-    private final static int coolDownTicks = 20;
-
-    private static EffectBuilder fullHealEffect = new EffectBuilder()
-            .setEffectApplyMessages(Lists.newArrayList("An aura of " + Color.BOLD_ON + Color.MAGENTA + "healing" + Color.RESET + " surrounds you"))
-            .setEffectDescription("Heals a target to full health.")
-            .setEffectName(Color.BOLD_ON + Color.MAGENTA + "healing" + Color.RESET + Color.BOLD_ON + Color.YELLOW + " AURA" + Color.RESET)
-            .setDurationStats(new StatsBuilder().createStats())
-            .setFrozenMovement(false)
-            .setLifeSpanTicks(1);
-
-    public HealingSpell(GameManager gameManager) {
-        super(gameManager, validTriggers, manaCost, attackStats, attackMessages, DESCRIPTION, NAME, Sets.newHashSet(fullHealEffect.createEffect()), isAreaSpell, null, coolDownTicks);
-    }
-
-    @Override
-    public void attackSpell(Player destinationPlayer, Player sourcePlayer) {
-        Stats stats = destinationPlayer.getPlayerStatsWithEquipmentAndLevel();
-        this.setEffects(Sets.newHashSet(fullHealEffect.setApplyStatsOnTick(new StatsBuilder().setCurrentHealth((stats.getMaxHealth())).createStats()).createEffect()));
-        super.attackSpell(destinationPlayer, sourcePlayer);
-    }
-}
diff --git a/src/main/java/com/comandante/creeper/spells/LightningSpell.java b/src/main/java/com/comandante/creeper/spells/LightningSpell.java
deleted file mode 100644
index b986b516ab3d09fba5a9882dec3ed3a34c9e0595..0000000000000000000000000000000000000000
--- a/src/main/java/com/comandante/creeper/spells/LightningSpell.java
+++ /dev/null
@@ -1,59 +0,0 @@
-package com.comandante.creeper.spells;
-
-
-import com.comandante.creeper.managers.GameManager;
-import com.comandante.creeper.player.Player;
-import com.comandante.creeper.server.Color;
-import com.comandante.creeper.stat.Stats;
-import com.comandante.creeper.stat.StatsBuilder;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Sets;
-
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-import static com.comandante.creeper.server.Color.BOLD_ON;
-
-public class LightningSpell extends Spell {
-
-    public final static String NAME = BOLD_ON + Color.YELLOW + "lightning" + Color.RESET + " bolt";
-    private final static String DESCRIPTION = "A powerful bolt of lightning.";
-    private final static Set<String> validTriggers = new HashSet<String>(Arrays.asList(new String[]
-                    {"lightning", "lightning bolt", "l", NAME}
-    ));
-    private final static Stats attackStats = new StatsBuilder()
-            .setStrength(180)
-            .setWeaponRatingMax(60)
-            .setWeaponRatingMin(50)
-            .setNumberOfWeaponRolls(4)
-            .createStats();
-    private final static boolean isAreaSpell = true;
-
-    private final static List<String> attackMessages = Lists.newArrayList("a broad stroke of " + BOLD_ON + Color.YELLOW + "lightning" + Color.RESET + " bolts across the sky");
-    private static int manaCost = 60;
-    private final static int coolDownTicks = 4;
-
-    private static EffectBuilder burnEffect = new EffectBuilder()
-            .setEffectApplyMessages(Lists.newArrayList("You are " + Color.BOLD_ON + Color.RED + "burning" + Color.RESET + " from the lightning strike!"))
-            .setEffectDescription("Fire left over from the lightning strike.")
-            .setEffectName(Color.BOLD_ON + Color.YELLOW + "lightning" + Color.RESET + Color.BOLD_ON + Color.RED + " BURN" + Color.RESET)
-            .setDurationStats(new StatsBuilder().createStats())
-            .setApplyStatsOnTick(new StatsBuilder().setCurrentHealth(-150).createStats())
-            .setFrozenMovement(false)
-            .setLifeSpanTicks(2);
-
-    public LightningSpell(GameManager gameManager) {
-        super(gameManager, validTriggers, manaCost, attackStats, attackMessages, DESCRIPTION, NAME, Sets.newHashSet(burnEffect.createEffect()), isAreaSpell, null, coolDownTicks);
-    }
-
-    @Override
-    public void attackSpell(Set<String> npcIds, Player player) {
-        Stats playerStats = player.getPlayerStatsWithEquipmentAndLevel();
-        long willpower = playerStats.getWillpower();
-        long i = 20 + (willpower * 3);
-        this.setEffects(Sets.newHashSet(burnEffect.setApplyStatsOnTick(new StatsBuilder().setCurrentHealth(-i).createStats()).createEffect()));
-        super.attackSpell(npcIds, player);
-    }
-}
diff --git a/src/main/java/com/comandante/creeper/spells/LightningSpellRunnable.java b/src/main/java/com/comandante/creeper/spells/LightningSpellRunnable.java
new file mode 100644
index 0000000000000000000000000000000000000000..97522808fa74069f74cebd6955b5f972f123dea4
--- /dev/null
+++ b/src/main/java/com/comandante/creeper/spells/LightningSpellRunnable.java
@@ -0,0 +1,87 @@
+package com.comandante.creeper.spells;
+
+import com.comandante.creeper.Items.EffectBuilder;
+import com.comandante.creeper.managers.GameManager;
+import com.comandante.creeper.npc.Npc;
+import com.comandante.creeper.player.CoolDown;
+import com.comandante.creeper.player.CoolDownType;
+import com.comandante.creeper.player.Player;
+import com.comandante.creeper.server.Color;
+import com.comandante.creeper.stat.StatsBuilder;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+
+import java.util.Arrays;
+import java.util.Optional;
+
+import static com.comandante.creeper.server.Color.BOLD_ON;
+
+public class LightningSpellRunnable implements SpellRunnable {
+
+    public final static String name = BOLD_ON + Color.YELLOW + "lightning" + Color.RESET + " bolt";
+    public final static String description = "A powerful bolt of lightning.";
+
+    private final static int manaCost = 60;
+
+    private final GameManager gameManager;
+
+    public LightningSpellRunnable(GameManager gameManager) {
+        this.gameManager = gameManager;
+    }
+
+    @Override
+    public void run(Player sourcePlayer, Optional<Npc> destinationNpc, Optional<Player> destinationPlayer, GameManager gameManager) {
+        long availableMana = sourcePlayer.getPlayerStatsWithEquipmentAndLevel().getCurrentMana();
+        if (availableMana < manaCost) {
+            sourcePlayer.writeMessage("Not enough mana!" + "\r\n");
+            return;
+        }
+        if (destinationNpc.isPresent()) {
+            executeSpellAgainstNpc(sourcePlayer, destinationNpc.get());
+            sourcePlayer.updatePlayerMana(-manaCost);
+            sourcePlayer.addCoolDown(new CoolDown(getName(), 5, CoolDownType.SPELL));
+        }
+    }
+
+    @Override
+    public String getName() {
+        return name;
+    }
+
+    private void executeSpellAgainstNpc(Player player, Npc npc) {
+        announceSpellCastToCurrentRoom(player, npc.getColorName());
+        long intelligence = player.getPlayerStatsWithEquipmentAndLevel().getIntelligence();
+        long power = (player.getLevel() * 1) + (3 * intelligence);
+        player.addActiveFight(npc);
+        long burnEffectPower = (long) ((player.getLevel() * .05) + (1 * intelligence));
+        gameManager.getEffectsManager().applyEffectsToNpcs(player, Sets.newHashSet(npc), Sets.newHashSet(getBurnEffect(burnEffectPower, 2).createEffect()));
+        npc.doHealthDamage(player, Arrays.asList(getDamageMessage(power, npc.getColorName())), -power);
+    }
+
+    private void executeSpellAgainstPlayer(Player player, Player destinationPlayer) {
+
+    }
+
+    private String getAttackMessage() {
+        return "a broad stroke of " + BOLD_ON + Color.YELLOW + "lightning" + Color.RESET + " bolts across the sky";
+    }
+
+    private String getDamageMessage(long amt, String name) {
+        return Color.BOLD_ON + Color.YELLOW + "[spell] " + Color.RESET + Color.YELLOW + "+" + amt + Color.RESET + Color.BOLD_ON + Color.RED + " DAMAGE " + Color.RESET + getAttackMessage() + Color.BOLD_ON + Color.RED + " >>>> " + Color.RESET + name;
+    }
+
+    private void announceSpellCastToCurrentRoom(Player player, String name) {
+        gameManager.writeToPlayerCurrentRoom(player.getPlayerId(), player.getPlayerName() + Color.CYAN + " casts " + Color.RESET + "a " + Color.BOLD_ON + Color.WHITE + "[" + Color.RESET + getName() + Color.BOLD_ON + Color.WHITE + "]" + Color.RESET + " on " + name + "! \r\n");
+    }
+
+    private EffectBuilder getBurnEffect(long amt, int ticksDuration) {
+        return new EffectBuilder()
+                .setEffectApplyMessages(Lists.newArrayList("You are " + Color.BOLD_ON + Color.RED + "burning" + Color.RESET + " from the lightning strike!"))
+                .setEffectDescription(Color.BOLD_ON + Color.YELLOW + "lightning" + Color.RESET + Color.BOLD_ON + Color.RED + " BURN" + Color.RESET)
+                .setEffectName(Color.BOLD_ON + Color.YELLOW + "lightning" + Color.RESET + Color.BOLD_ON + Color.RED + " BURN" + Color.RESET)
+                .setDurationStats(new StatsBuilder().createStats())
+                .setApplyStatsOnTick(new StatsBuilder().setCurrentHealth(-amt).createStats())
+                .setFrozenMovement(false)
+                .setLifeSpanTicks(ticksDuration);
+    }
+}
diff --git a/src/main/java/com/comandante/creeper/spells/LizardlySpell.java b/src/main/java/com/comandante/creeper/spells/LizardlySpell.java
deleted file mode 100644
index 805d99523f167b1d2105074afafa5dafc3888a85..0000000000000000000000000000000000000000
--- a/src/main/java/com/comandante/creeper/spells/LizardlySpell.java
+++ /dev/null
@@ -1,60 +0,0 @@
-package com.comandante.creeper.spells;
-
-import com.comandante.creeper.Items.Item;
-import com.comandante.creeper.Items.ItemType;
-import com.comandante.creeper.Items.Loot;
-import com.comandante.creeper.managers.GameManager;
-import com.comandante.creeper.npc.Npc;
-import com.comandante.creeper.player.Player;
-import com.comandante.creeper.server.Color;
-import com.comandante.creeper.spells.Effect;
-import com.comandante.creeper.spells.Spell;
-import com.comandante.creeper.stat.Stats;
-import com.comandante.creeper.stat.StatsBuilder;
-import com.comandante.creeper.world.Room;
-import com.google.common.collect.Interner;
-import com.google.common.collect.Interners;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Sets;
-
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-import static com.comandante.creeper.server.Color.BOLD_ON;
-
-public class LizardlySpell extends Spell {
-
-    private final static String NAME = BOLD_ON + Color.YELLOW + "lizzards" + Color.RESET;
-    private final static String DESCRIPTION = "Your target is LIZARDLY!!!!";
-    private final static Set<String> validTriggers = new HashSet<String>(Arrays.asList(new String[]
-                    {"lizardly", "liz", NAME}
-    ));
-    private final static Stats attackStats = new StatsBuilder().createStats();
-    private final static boolean isAreaSpell = false;
-
-    private final static List<String> attackMessages = Lists.newArrayList("tainted lizzard blood is flung through the air... " + BOLD_ON + Color.YELLOW + "lizardly" + Color.RESET + "!!!!");
-    private final static int manaCost = 300;
-    private final static int coolDownTicks = 30;
-
-    private static EffectBuilder aids = new EffectBuilder()
-            .setEffectApplyMessages(Lists.newArrayList("You feel closer to death as " + Color.BOLD_ON + Color.YELLOW + "lizzardly" + Color.RESET + " destroys your will to live!"))
-            .setEffectDescription("Target has aids.")
-            .setEffectName(Color.BOLD_ON + Color.RED + "aids" + Color.RESET + Color.BOLD_ON + Color.BLUE + " FOR LIFE" + Color.RESET)
-            .setDurationStats(new StatsBuilder().createStats())
-            .setApplyStatsOnTick(new StatsBuilder().setCurrentHealth(-1000).createStats())
-            .setFrozenMovement(false)
-            .setLifeSpanTicks(5);
-
-    public LizardlySpell(GameManager gameManager) {
-        super(gameManager, validTriggers, manaCost, attackStats, attackMessages, DESCRIPTION, NAME, Sets.<Effect>newHashSet(), isAreaSpell, null, coolDownTicks);
-    }
-
-    @Override
-    public void attackSpell(Player destinationPlayer, Player sourcePlayer) {
-        Stats stats = sourcePlayer.getPlayerStatsWithEquipmentAndLevel();
-        this.setEffects(Sets.newHashSet(aids.setApplyStatsOnTick(new StatsBuilder().setCurrentHealth(-1000).createStats()).createEffect()));
-        super.attackSpell(destinationPlayer, sourcePlayer);
-    }
-}
diff --git a/src/main/java/com/comandante/creeper/spells/RestoreSpell.java b/src/main/java/com/comandante/creeper/spells/RestoreSpell.java
deleted file mode 100644
index 0482aa83df224f9455f72456b058974a70d9b8ec..0000000000000000000000000000000000000000
--- a/src/main/java/com/comandante/creeper/spells/RestoreSpell.java
+++ /dev/null
@@ -1,51 +0,0 @@
-package com.comandante.creeper.spells;
-
-import com.comandante.creeper.managers.GameManager;
-import com.comandante.creeper.player.Player;
-import com.comandante.creeper.server.Color;
-import com.comandante.creeper.stat.Stats;
-import com.comandante.creeper.stat.StatsBuilder;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Sets;
-
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-import static com.comandante.creeper.server.Color.BOLD_ON;
-
-public class RestoreSpell extends Spell {
-
-    private final static String NAME = BOLD_ON + Color.MAGENTA + "restore" + Color.RESET;
-    private final static String DESCRIPTION = "A potent wave of healing.";
-    private final static Set<String> validTriggers = new HashSet<String>(Arrays.asList(new String[]
-                    {"restore", "r", NAME}
-    ));
-    private final static Stats attackStats = new StatsBuilder().createStats();
-    private final static boolean isAreaSpell = false;
-
-    private final static List<String> attackMessages = Lists.newArrayList("a wave of " + BOLD_ON + Color.MAGENTA + "healing" + Color.RESET + " flows to those in need");
-    private static int manaCost = 80;
-    private final static int coolDownTicks = 2;
-
-    private static EffectBuilder burnEffect = new EffectBuilder()
-            .setEffectApplyMessages(Lists.newArrayList("You feel a rush of dopamine as a " + Color.BOLD_ON + Color.MAGENTA + "healing" + Color.RESET + " sensation flows through your body!"))
-            .setEffectDescription("Heals a target over time.")
-            .setEffectName(Color.BOLD_ON + Color.MAGENTA + "healing" + Color.RESET + Color.BOLD_ON + Color.BLUE + " WAVE" + Color.RESET)
-            .setDurationStats(new StatsBuilder().createStats())
-            .setApplyStatsOnTick(new StatsBuilder().setCurrentHealth(400).createStats())
-            .setFrozenMovement(false)
-            .setLifeSpanTicks(6);
-
-    public RestoreSpell(GameManager gameManager) {
-        super(gameManager, validTriggers, manaCost, attackStats, attackMessages, DESCRIPTION, NAME, Sets.newHashSet(burnEffect.createEffect()), isAreaSpell, null, coolDownTicks);
-    }
-
-    @Override
-    public void attackSpell(Player destinationPlayer, Player sourcePlayer) {
-        Stats stats = sourcePlayer.getPlayerStatsWithEquipmentAndLevel();
-        this.setEffects(Sets.newHashSet(burnEffect.setApplyStatsOnTick(new StatsBuilder().setCurrentHealth(400 + (stats.getWillpower() * 6)).createStats()).createEffect()));
-        super.attackSpell(destinationPlayer, sourcePlayer);
-    }
-}
\ No newline at end of file
diff --git a/src/main/java/com/comandante/creeper/spells/Spell.java b/src/main/java/com/comandante/creeper/spells/Spell.java
deleted file mode 100644
index f702e299525961f3dacdadf8a4a2247c8eeddd60..0000000000000000000000000000000000000000
--- a/src/main/java/com/comandante/creeper/spells/Spell.java
+++ /dev/null
@@ -1,250 +0,0 @@
-package com.comandante.creeper.spells;
-
-
-import com.comandante.creeper.managers.GameManager;
-import com.comandante.creeper.npc.Npc;
-import com.comandante.creeper.player.CoolDown;
-import com.comandante.creeper.player.CoolDownType;
-import com.comandante.creeper.player.Player;
-import com.comandante.creeper.server.Color;
-import com.comandante.creeper.stat.Stats;
-import com.comandante.creeper.stat.StatsHelper;
-import com.google.common.collect.Interner;
-import com.google.common.collect.Interners;
-import org.apache.log4j.Logger;
-
-import java.util.Arrays;
-import java.util.List;
-import java.util.Random;
-import java.util.Set;
-
-
-public abstract class Spell {
-
-    private final String spellName;
-    private final String spellDescription;
-    private final List<String> attackMessages;
-    private final Stats attackStats;
-    private final int manaCost;
-    private final Set<String> validTriggers;
-    private final static Random random = new Random();
-    private final GameManager gameManager;
-    private Set<Effect> effects;
-    private final boolean isAreaSpell;
-    private final SpellExecute spellExecute;
-    private final int coolDownTicks;
-
-    private static final Logger log = Logger.getLogger(Spell.class);
-
-
-    public Spell(GameManager gameManager,
-                 Set<String> validTriggers,
-                 int manaCost,
-                 Stats attackStats,
-                 List<String> attackMessages,
-                 String spellDescription,
-                 String spellName,
-                 Set<Effect> effects,
-                 boolean isAreaSpell,
-                 SpellExecute spellExecute,
-                 int coolDownTicks) {
-        this.gameManager = gameManager;
-        this.validTriggers = validTriggers;
-        this.manaCost = manaCost;
-        this.attackStats = attackStats;
-        this.attackMessages = attackMessages;
-        this.spellDescription = spellDescription;
-        this.spellName = spellName;
-        this.effects = effects;
-        this.isAreaSpell = isAreaSpell;
-        this.spellExecute = spellExecute;
-        this.coolDownTicks = coolDownTicks;
-    }
-
-    private long getSpellAttack(Stats victim) {
-        int rolls = 0;
-        int totDamage = 0;
-        while (rolls <= attackStats.getNumberOfWeaponRolls()) {
-            rolls++;
-            totDamage = totDamage + randInt((int)attackStats.getWeaponRatingMin(), (int)attackStats.getWeaponRatingMax());
-        }
-        long i = attackStats.getStrength() + totDamage - victim.getArmorRating();
-        if (i < 0) {
-            return 0;
-        } else {
-            return i;
-        }
-    }
-
-    public String getAttackMessage(long amt, Npc npc) {
-        int i = random.nextInt(attackMessages.size());
-        String s = attackMessages.get(i);
-        if (amt == 0) {
-            return s;
-        } else {
-            return Color.BOLD_ON + Color.YELLOW + "[spell] " + Color.RESET + Color.YELLOW + "+" + amt + Color.RESET + Color.BOLD_ON + Color.RED + " DAMAGE " + Color.RESET + s + Color.BOLD_ON + Color.RED + " >>>> " + Color.RESET + npc.getColorName();
-        }
-    }
-
-    private void applySpell(Set<String> npcIds, Player player) {
-        if (spellExecute != null) {
-            for (String npcId : npcIds) {
-                Npc npc = gameManager.getEntityManager().getNpcEntity(npcId);
-                spellExecute.executeNpc(gameManager, npc, player);
-            }
-        }
-    }
-
-    public void attackSpell(Set<String> npcIds, Player player) {
-        Interner<String> interner = Interners.newWeakInterner();
-        synchronized (interner.intern(player.getPlayerId())) {
-            long availableMana = gameManager.getPlayerManager().getPlayerMetadata(player.getPlayerId()).getStats().getCurrentMana();
-            if (availableMana < manaCost) {
-                gameManager.getChannelUtils().write(player.getPlayerId(), "Not enough mana!" + "\r\n");
-            } else {
-                applySpell(npcIds, player);
-                for (String npcId : npcIds) {
-                    Npc npc = gameManager.getEntityManager().getNpcEntity(npcId);
-                    gameManager.writeToPlayerCurrentRoom(player.getPlayerId(), player.getPlayerName() + Color.CYAN + " casts " + Color.RESET + "a " + Color.BOLD_ON + Color.WHITE + "[" + Color.RESET + spellName + Color.BOLD_ON + Color.WHITE + "]" + Color.RESET + " on " + npc.getColorName() + "! \r\n");
-                    long spellAttack = getSpellAttack(npc.getStats());
-                    final String spellAttackStr = getAttackMessage(spellAttack, npc);
-                    player.addActiveFight(npc);
-                    npc.doHealthDamage(player, Arrays.asList(spellAttackStr), -spellAttack);
-                }
-                if (npcIds.size() > 0) {
-                    applyEffectsToNpcs(npcIds, player);
-                    player.updatePlayerMana(-manaCost);
-                    player.addCoolDown(new CoolDown(spellName, coolDownTicks, CoolDownType.SPELL));
-                }
-            }
-        }
-    }
-
-    public void attackSpell(Player destinationPlayer, Player sourcePlayer) {
-        Interner<String> interner = Interners.newWeakInterner();
-        synchronized (interner.intern(sourcePlayer.getPlayerId())) {
-            long availableMana = gameManager.getPlayerManager().getPlayerMetadata(sourcePlayer.getPlayerId()).getStats().getCurrentMana();
-            if (availableMana < manaCost) {
-                gameManager.getChannelUtils().write(sourcePlayer.getPlayerId(), "Not enough mana!" + "\r\n");
-            } else {
-                gameManager.writeToPlayerCurrentRoom(sourcePlayer.getPlayerId(), sourcePlayer.getPlayerName() + Color.CYAN + " casts " + Color.RESET + "a " + Color.BOLD_ON + Color.WHITE + "[" + Color.RESET + spellName + Color.BOLD_ON + Color.WHITE + "]" + Color.RESET + " on " + destinationPlayer.getPlayerName() + "! \r\n");
-                applyEffectsToPlayer(destinationPlayer, sourcePlayer);
-                sourcePlayer.updatePlayerMana(-manaCost);
-                sourcePlayer.addCoolDown(new CoolDown(spellName, coolDownTicks, CoolDownType.SPELL));
-            }
-        }
-    }
-
-    public void applyEffectsToPlayer(Player destinationPlayer, Player player) {
-        Interner<String> interner = Interners.newWeakInterner();
-        synchronized (interner.intern(player.getPlayerId())) {
-            long availableMana = gameManager.getPlayerManager().getPlayerMetadata(player.getPlayerId()).getStats().getCurrentMana();
-            if (availableMana < manaCost) {
-                gameManager.getChannelUtils().write(player.getPlayerId(), "Not enough mana!" + "\r\n");
-            } else {
-                for (Effect effect : effects) {
-                    Effect nEffect = new Effect(effect);
-                    nEffect.setPlayerId(player.getPlayerId());
-                    gameManager.getEntityManager().saveEffect(nEffect);
-                    if (effect.getDurationStats().getCurrentHealth() < 0) {
-                        log.error("ERROR! Someone added an effect with a health modifier which won't work for various reasons.");
-                        continue;
-                    }
-                    String effectApplyMessage;
-                    if (destinationPlayer.addEffect(effect.getEntityId())) {
-                        effectApplyMessage = Color.BOLD_ON + Color.GREEN + "[effect] " + Color.RESET + nEffect.getEffectName() + " applied!" + "\r\n";
-                        gameManager.getChannelUtils().write(destinationPlayer.getPlayerId(), effectApplyMessage);
-                    } else {
-                        effectApplyMessage = Color.BOLD_ON + Color.GREEN + "[effect] "+ Color.RESET + Color.RED + "Unable to apply "  + nEffect.getEffectName() + "!" + "\r\n";
-                        gameManager.getChannelUtils().write(player.getPlayerId(), effectApplyMessage);
-                    }
-                }
-            }
-        }
-    }
-
-    public void applyEffectsToNpcs(Set<String> npcIds, Player player) {
-        Interner<String> interner = Interners.newWeakInterner();
-        synchronized (interner.intern(player.getPlayerId())) {
-            long availableMana = gameManager.getPlayerManager().getPlayerMetadata(player.getPlayerId()).getStats().getCurrentMana();
-            if (availableMana < manaCost) {
-                gameManager.getChannelUtils().write(player.getPlayerId(), "Not enough mana!" + "\r\n");
-            } else {
-                for (Effect effect : effects) {
-                    for (String npcId : npcIds) {
-                        Npc npc = gameManager.getEntityManager().getNpcEntity(npcId);
-                        if (npc == null) {
-                            // assume this npc died
-                            continue;
-                        }
-                        Effect nEffect = new Effect(effect);
-                        nEffect.setPlayerId(player.getPlayerId());
-                        if (effect.getDurationStats().getCurrentHealth() < 0) {
-                            log.error("ERROR! Someone added an effect with a health modifier which won't work for various reasons.");
-                            continue;
-                        }
-                        StatsHelper.combineStats(npc.getStats(), effect.getDurationStats());
-                        // gameManager.getEffectsManager().application(nEffect, npc);
-                        npc.addEffect(nEffect);
-                    }
-                }
-            }
-        }
-    }
-
-    private static int randInt(int min, int max) {
-        return random.nextInt((max - min) + 1) + min;
-    }
-
-    public String getSpellName() {
-        return spellName;
-    }
-
-    public String getSpellDescription() {
-        return spellDescription;
-    }
-
-    public List<String> getAttackMessages() {
-        return attackMessages;
-    }
-
-    public Stats getAttackStats() {
-        return attackStats;
-    }
-
-    public int getManaCost() {
-        return manaCost;
-    }
-
-    public Set<String> getValidTriggers() {
-        return validTriggers;
-    }
-
-    public static Random getRandom() {
-        return random;
-    }
-
-    public GameManager getGameManager() {
-        return gameManager;
-    }
-
-    public Set<Effect> getEffects() {
-        return effects;
-    }
-
-    public void setEffects(Set<Effect> effects) {
-        this.effects = effects;
-    }
-
-    public boolean isAreaSpell() {
-        return isAreaSpell;
-    }
-
-    public SpellExecute getSpellExecute() {
-        return spellExecute;
-    }
-
-    interface SpellExecute {
-        public void executeNpc(GameManager gameManager, Npc npc, Player player);
-    }
-}
diff --git a/src/main/java/com/comandante/creeper/spells/SpellRunnable.java b/src/main/java/com/comandante/creeper/spells/SpellRunnable.java
new file mode 100644
index 0000000000000000000000000000000000000000..4a6ac27ddc2f2d345022d05e70fb34ffd2d2e460
--- /dev/null
+++ b/src/main/java/com/comandante/creeper/spells/SpellRunnable.java
@@ -0,0 +1,13 @@
+package com.comandante.creeper.spells;
+
+
+import com.comandante.creeper.managers.GameManager;
+import com.comandante.creeper.npc.Npc;
+import com.comandante.creeper.player.Player;
+
+import java.util.Optional;
+
+public interface SpellRunnable {
+    void run(Player sourcePlayer, Optional<Npc> destinationNpc, Optional<Player> destinationPlayer, GameManager gameManager);
+    String getName();
+}
diff --git a/src/main/java/com/comandante/creeper/spells/SpellTriggerRegistry.java b/src/main/java/com/comandante/creeper/spells/SpellTriggerRegistry.java
deleted file mode 100644
index e393bc683287f06c14f1def2ee410ebe16004107..0000000000000000000000000000000000000000
--- a/src/main/java/com/comandante/creeper/spells/SpellTriggerRegistry.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package com.comandante.creeper.spells;
-
-
-import com.google.common.collect.Maps;
-
-import java.util.Map;
-
-public class SpellTriggerRegistry {
-
-    public static final Map<String, Spell> spellMap = Maps.newHashMap();
-    public static final Map<String, Spell> spellNameMap = Maps.newHashMap();
-
-
-    public static void addSpell(Spell spell) {
-        for (String trigger : spell.getValidTriggers()) {
-            spellMap.put(trigger, spell);
-        }
-    }
-
-    public static Spell getSpell(String trigger) {
-        return spellMap.get(trigger);
-    }
-
-}
diff --git a/src/main/java/com/comandante/creeper/spells/Spells.java b/src/main/java/com/comandante/creeper/spells/Spells.java
new file mode 100644
index 0000000000000000000000000000000000000000..8c0e007abeae233808f50cd523adfd4d48a2c95f
--- /dev/null
+++ b/src/main/java/com/comandante/creeper/spells/Spells.java
@@ -0,0 +1,42 @@
+package com.comandante.creeper.spells;
+
+import com.comandante.creeper.CreeperUtils;
+import com.comandante.creeper.managers.GameManager;
+import com.comandante.creeper.npc.Npc;
+import com.comandante.creeper.player.Player;
+import com.comandante.creeper.server.Color;
+import com.comandante.creeper.stat.Stats;
+import com.comandante.creeper.stat.StatsHelper;
+import com.google.common.collect.Sets;
+import org.apache.log4j.Logger;
+
+import java.util.Optional;
+import java.util.Set;
+
+public class Spells {
+
+    private GameManager gameManager;
+
+    private static final Logger log = Logger.getLogger(Spells.class);
+
+    public Spells(GameManager gameManager) {
+        this.gameManager = gameManager;
+    }
+
+    public void executeSpell(Player sourcePlayer, Optional<Npc> destinationNpc, Optional<Player> destinationPlayer, SpellRunnable spellRunnable) {
+        try {
+            spellRunnable.run(sourcePlayer, destinationNpc, destinationPlayer, gameManager);
+        } catch (Exception e) {
+            log.error("Problem executing spell.", e);
+        }
+    }
+
+    public Optional<SpellRunnable> getSpellRunnable(String triggerName) {
+        if (Sets.newHashSet("lightning", "l").contains(triggerName)) {
+            return Optional.of(new LightningSpellRunnable(gameManager));
+        }
+        return Optional.empty();
+    }
+}
+
+
diff --git a/src/main/java/com/comandante/creeper/stat/Stats.java b/src/main/java/com/comandante/creeper/stat/Stats.java
index 504b92abdd59b0b7d2bbb2394f3b11e661d919eb..07f3b2371cb3e61b0657a7d63bbf500634591b1a 100644
--- a/src/main/java/com/comandante/creeper/stat/Stats.java
+++ b/src/main/java/com/comandante/creeper/stat/Stats.java
@@ -4,6 +4,7 @@ import java.io.Serializable;
 
 public class Stats implements Serializable {
     private long strength;
+    private long intelligence;
     private long willpower;
     private long aim;
     private long agile;
@@ -23,6 +24,7 @@ public class Stats implements Serializable {
 
     public Stats(Stats stats) {
         this.strength = stats.strength;
+        this.intelligence = stats.intelligence;
         this.willpower = stats.willpower;
         this.aim = stats.aim;
         this.agile = stats.agile;
@@ -44,6 +46,7 @@ public class Stats implements Serializable {
     }
 
     public Stats(long strength,
+                 long intelligence,
                  long willpower,
                  long aim,
                  long agile,
@@ -61,6 +64,7 @@ public class Stats implements Serializable {
                  long inventorySize,
                  long maxEffects) {
         this.strength = strength;
+        this.intelligence = intelligence;
         this.willpower = willpower;
         this.aim = aim;
         this.agile = agile;
@@ -80,6 +84,14 @@ public class Stats implements Serializable {
     }
 
 
+    public long getIntelligence() {
+        return intelligence;
+    }
+
+    public void setIntelligence(long intelligence) {
+        this.intelligence = intelligence;
+    }
+
     public long getMaxEffects() {
         return maxEffects;
     }
diff --git a/src/main/java/com/comandante/creeper/stat/StatsBuilder.java b/src/main/java/com/comandante/creeper/stat/StatsBuilder.java
index d2532fd47035bb61c213b6722e8229b3b3ad6d49..b8ab39495ec4660e69d5293666ba48f7c7782bbe 100644
--- a/src/main/java/com/comandante/creeper/stat/StatsBuilder.java
+++ b/src/main/java/com/comandante/creeper/stat/StatsBuilder.java
@@ -2,6 +2,7 @@ package com.comandante.creeper.stat;
 
 public class StatsBuilder {
     private long strength;
+    private long intelligence;
     private long willpower;
     private long aim;
     private long agile;
@@ -24,6 +25,7 @@ public class StatsBuilder {
 
     public StatsBuilder(Stats stats) {
         this.strength = stats.getStrength();
+        this.intelligence = stats.getIntelligence();
         this.willpower = stats.getWillpower();
         this.aim = stats.getAim();
         this.agile = stats.getAgile();
@@ -43,6 +45,11 @@ public class StatsBuilder {
         this.maxEffects = stats.getMaxEffects();
     }
 
+    public StatsBuilder setIntelligence(long intelligence) {
+        this.intelligence = intelligence;
+        return this;
+    }
+
     public StatsBuilder setStrength(long strength) {
         this.strength = strength;
         return this;
@@ -129,6 +136,6 @@ public class StatsBuilder {
     }
 
     public Stats createStats() {
-        return new Stats(strength, willpower, aim, agile, armorRating, meleSkill, currentHealth, maxHealth, weaponRatingMax, weaponRatingMin, numberOfWeaponRolls, experience, currentMana, maxMana, foraging, inventorySize, maxEffects);
+        return new Stats(strength, intelligence, willpower, aim, agile, armorRating, meleSkill, currentHealth, maxHealth, weaponRatingMax, weaponRatingMin, numberOfWeaponRolls, experience, currentMana, maxMana, foraging, inventorySize, maxEffects);
     }
 }
\ No newline at end of file
diff --git a/src/main/java/com/comandante/creeper/stat/StatsHelper.java b/src/main/java/com/comandante/creeper/stat/StatsHelper.java
index cb73df3276081f1c0527e762a2adf7cac756d8a1..512a33149ec5833465bef64b865ee08053732661 100644
--- a/src/main/java/com/comandante/creeper/stat/StatsHelper.java
+++ b/src/main/java/com/comandante/creeper/stat/StatsHelper.java
@@ -5,6 +5,7 @@ public class StatsHelper {
     public static Stats getDifference(Stats modifiedStats, Stats origStats) {
         StatsBuilder statsBuilder = new StatsBuilder();
         statsBuilder.setAgile(modifiedStats.getAgile() - origStats.getAgile());
+        statsBuilder.setIntelligence(modifiedStats.getIntelligence() - origStats.getIntelligence());
         statsBuilder.setAim(modifiedStats.getAim() - origStats.getAim());
         statsBuilder.setArmorRating(modifiedStats.getArmorRating() - origStats.getArmorRating());
         statsBuilder.setCurrentHealth(modifiedStats.getCurrentHealth() - origStats.getCurrentHealth());
@@ -26,6 +27,7 @@ public class StatsHelper {
 
     public static void combineStats(Stats orig, Stats combine) {
         orig.setAgile(orig.getAgile() + combine.getAgile());
+        orig.setIntelligence(orig.getIntelligence() + combine.getIntelligence());
         orig.setAim(orig.getAim() + combine.getAim());
         orig.setArmorRating(orig.getArmorRating() + combine.getArmorRating());
         orig.setCurrentHealth(orig.getCurrentHealth() + combine.getCurrentHealth());
@@ -47,6 +49,7 @@ public class StatsHelper {
     public static void inverseStats(Stats stats) {
         stats.setAgile(-stats.getAgile());
         stats.setAim(-stats.getAim());
+        stats.setIntelligence(-stats.getIntelligence());
         stats.setArmorRating(-stats.getArmorRating());
         stats.setCurrentHealth(-stats.getCurrentHealth());
         stats.setMaxHealth(-stats.getMaxHealth());
diff --git a/src/test/com/comandante/creeper/player/NpcTestHarness.java b/src/test/com/comandante/creeper/player/NpcTestHarness.java
index 2f4c0401961be8eda30939df81219aa9d5ad1c6b..cc43842194b2133abdd43e07a2c4e110bfbe5e30 100644
--- a/src/test/com/comandante/creeper/player/NpcTestHarness.java
+++ b/src/test/com/comandante/creeper/player/NpcTestHarness.java
@@ -227,4 +227,29 @@ public class NpcTestHarness {
         PlayerMetadata playerMetadata = new PlayerMetadata(username, password, Main.createPlayerId(username), PlayerStats.DEFAULT_PLAYER.createStats(), 0, Sets.newHashSet(PlayerRole.MORTAL), new String[0], 0, new String[0], Maps.newHashMap());
         gameManager.getPlayerManager().savePlayerMetadata(playerMetadata);
     }
+
+    private int getLightningSpellDamage(int level, int intelligence, int npcIntelligence) {
+        return (level * 1) + (3 * intelligence);
+
+    }
+
+    @Test
+    public void screwingAround() throws Exception {
+
+        int lightningSpellDamage = getLightningSpellDamage(4, 7, 4);
+        System.out.println("Level 1 player with 7 intelligence vs 4 intelligence npc: " + lightningSpellDamage);
+
+        lightningSpellDamage = getLightningSpellDamage(5, 11, 6);
+        System.out.println("Level 1 player with 11 intelligence vs 6 intelligence npc: " + lightningSpellDamage);
+
+        lightningSpellDamage = getLightningSpellDamage(5, 11, 6);
+        System.out.println("Level 5 player with 11 intelligence vs 6 intelligence npc: " + lightningSpellDamage);
+        lightningSpellDamage = getLightningSpellDamage(7, 14, 8);
+        System.out.println("Level 7 player with 14 intelligence vs 8 intelligence npc: " + lightningSpellDamage);
+        lightningSpellDamage = getLightningSpellDamage(9,16, 10);
+        System.out.println("Level 9 player with 16 intelligence vs 10 intelligence npc: " + lightningSpellDamage);
+        lightningSpellDamage = getLightningSpellDamage(12, 21, 13);
+        System.out.println("Level 12 player with 21 intelligence vs 13 intelligence npc: " + lightningSpellDamage);
+
+    }
 }