From 18067a97987a2d96ba7ae033a2a46130b60bd886 Mon Sep 17 00:00:00 2001
From: pubby <pubby8@gmail.com>
Date: Wed, 12 Jun 2013 02:34:30 -0500
Subject: [PATCH] Create Formicid species and monsters.

Tavern post:
https://crawl.develz.org/tavern/viewtopic.php?f=8&t=8298

Wierdness & mutations:
- poison weakness
- retractable antennae (can wear headgear and ignore mutation)
- chitin skin (+2 AC)
- most weapons 1-handed, big weapons 2-handed
- permanent stasis
- ability to shaft self
- ability to dig
- Starts with 2 curing pots

3 monster versions of formicids were added:
formicid, a weak fighter
formicid drone, a stronger fighter
formicid venom mage, a magician with olgreb's and mass cure poison
---
 crawl-ref/source/abl-show.cc                       |  61 +++++++++-
 crawl-ref/source/acquire.cc                        |   9 +-
 crawl-ref/source/actor.cc                          |   6 +
 crawl-ref/source/actor.h                           |   2 +
 crawl-ref/source/aptitudes.h                       |  34 ++++++
 crawl-ref/source/artefact.cc                       |  10 +-
 crawl-ref/source/dat/descript/ability.txt          |   9 ++
 crawl-ref/source/dat/descript/monsters.txt         |  12 ++
 crawl-ref/source/dat/descript/species.txt          |   5 +
 crawl-ref/source/defines.h                         |   2 +
 crawl-ref/source/delay.cc                          |  27 ++++-
 crawl-ref/source/describe.cc                       |  13 ++-
 crawl-ref/source/enum.h                            |  18 ++-
 crawl-ref/source/godpassive.cc                     |   2 +-
 crawl-ref/source/item_use.cc                       |  62 ++++++++---
 crawl-ref/source/itemname.cc                       |  43 +++++--
 crawl-ref/source/itemprop.cc                       |  32 +++---
 crawl-ref/source/itemprop.h                        |   7 +-
 crawl-ref/source/main.cc                           |  24 +++-
 crawl-ref/source/mon-cast.cc                       |  83 +++++++++++++-
 crawl-ref/source/mon-data.h                        |  40 ++++++-
 crawl-ref/source/mon-flags.h                       |   6 +
 crawl-ref/source/mon-gear.cc                       |  44 +++++++-
 crawl-ref/source/mon-grow.cc                       |   2 +
 crawl-ref/source/mon-spll.h                        |  22 ++++
 crawl-ref/source/monster.cc                        |  40 +++++--
 crawl-ref/source/monster.h                         |   4 +
 crawl-ref/source/mutation-data.h                   |  18 +++
 crawl-ref/source/mutation.cc                       |  63 +++++++----
 crawl-ref/source/newgame.cc                        |   3 +-
 crawl-ref/source/ng-restr.cc                       |  22 ++++
 crawl-ref/source/ng-setup.cc                       |  11 ++
 crawl-ref/source/output.cc                         |  11 ++
 crawl-ref/source/player-act.cc                     |  23 +++-
 crawl-ref/source/player-equip.cc                   |  10 ++
 crawl-ref/source/player.cc                         | 124 +++++++++++++++++++--
 crawl-ref/source/player.h                          |   8 ++
 crawl-ref/source/rltiles/dc-player.txt             |   4 +
 crawl-ref/source/rltiles/player/base/formicid0.png | Bin 0 -> 727 bytes
 crawl-ref/source/rltiles/player/base/formicid1.png | Bin 0 -> 727 bytes
 crawl-ref/source/rltiles/player/base/formicid2.png | Bin 0 -> 724 bytes
 crawl-ref/source/rltiles/player/base/formicid3.png | Bin 0 -> 723 bytes
 crawl-ref/source/species.cc                        |  14 ++-
 crawl-ref/source/spl-cast.cc                       |   5 +-
 crawl-ref/source/spl-data.h                        |  26 +++++
 crawl-ref/source/stairs.cc                         |   4 +-
 crawl-ref/source/throw.cc                          |   4 +-
 crawl-ref/source/tilepick-p.cc                     |  18 +++
 crawl-ref/source/transform.cc                      |   5 +-
 crawl-ref/source/wiz-you.cc                        |   1 +
 50 files changed, 874 insertions(+), 119 deletions(-)
 create mode 100644 crawl-ref/source/rltiles/player/base/formicid0.png
 create mode 100644 crawl-ref/source/rltiles/player/base/formicid1.png
 create mode 100644 crawl-ref/source/rltiles/player/base/formicid2.png
 create mode 100644 crawl-ref/source/rltiles/player/base/formicid3.png

diff --git a/crawl-ref/source/abl-show.cc b/crawl-ref/source/abl-show.cc
index 62cee08..191583a 100644
--- a/crawl-ref/source/abl-show.cc
+++ b/crawl-ref/source/abl-show.cc
@@ -55,6 +55,7 @@
 #include "player-stats.h"
 #include "potion.h"
 #include "religion.h"
+#include "shout.h"
 #include "skills.h"
 #include "skills2.h"
 #include "species.h"
@@ -72,6 +73,7 @@
 #include "stuff.h"
 #include "target.h"
 #include "tilepick.h"
+#include "traps.h"
 #include "areas.h"
 #include "transform.h"
 #include "hints.h"
@@ -229,6 +231,9 @@ static const ability_def Ability_List[] =
       0, 0, 0, 0, 0, ABFLAG_INSTANT},
     { ABIL_MUMMY_RESTORATION, "Self-Restoration",
       1, 0, 0, 0, 0, ABFLAG_PERMANENT_MP},
+    
+    { ABIL_DIG, "Dig", 0, 0, 75, 0, 0, ABFLAG_NONE},
+    { ABIL_SHAFT_SELF, "Shaft Self", 0, 0, 250, 0, 0, ABFLAG_NONE},
 
     // EVOKE abilities use Evocations and come from items.
     // Teleportation and Blink can also come from mutations
@@ -903,6 +908,8 @@ talent get_talent(ability_type ability, bool check_confused)
     case ABIL_MAKE_GRENADES:
     case ABIL_MAKE_SAGE:
     case ABIL_REMOVE_CURSE:
+    case ABIL_DIG:
+    case ABIL_SHAFT_SELF:
         failure = 0;
         break;
 
@@ -1494,7 +1501,12 @@ static bool _check_ability_possible(const ability_def& abil,
         if (you.no_tele(false, false, true))
         {
             if (!quiet)
-                mpr("You cannot teleport right now.");
+            {
+                if (you.species == SP_FORMICID)
+                    mpr("You cannot teleport.");
+                else
+                    mpr("You cannot teleport right now.");
+            }
             return false;
         }
         return true;
@@ -1888,6 +1900,42 @@ static bool _do_ability(const ability_def& abil)
         if (recharge_wand() <= 0)
             return false; // fail message is already given
         break;
+    
+    case ABIL_DIG:
+    {
+        power = 0;
+        beam.range = LOS_RADIUS;
+
+        if (!spell_direction(abild, beam, DIR_NONE, TARG_ANY, 0,
+                             true, true, false, NULL,
+                             "Aiming: Dig",
+                             true))
+        {
+            return false;
+        }
+        else
+        {
+            zapping(ZAP_DIG, power, beam);
+        }
+        break;
+    }
+
+    case ABIL_SHAFT_SELF:
+    {                    
+        if (you.can_do_shaft_ability())
+        {
+            if (yesno("Are you sure you want to shaft yourself?"))
+                start_delay(DELAY_SHAFT_SELF, 1);
+            else
+                return false;
+        }
+        else
+        {
+            mpr("You can't shaft here.");
+            return false;
+        }
+        break;
+    }
 
     case ABIL_DELAYED_FIREBALL:
     {
@@ -2309,6 +2357,11 @@ static bool _do_ability(const ability_def& abil)
         break;
 
     case ABIL_OKAWARU_FINESSE:
+        if (you.species == SP_FORMICID)
+        {
+            mpr("You cannot use finnese because of your stasis.");
+            return false;
+        }
         if (stasis_blocks_effect(true, true, "%s emits a piercing whistle.",
                                  20, "%s makes your neck tingle."))
         {
@@ -3080,6 +3133,12 @@ vector<talent> your_talents(bool check_confused, bool include_unusable)
 
     if (you.species == SP_DEEP_DWARF)
         _add_talent(talents, ABIL_RECHARGING, check_confused);
+    
+    if (you.species == SP_FORMICID)
+    {
+        _add_talent(talents, ABIL_DIG, check_confused);
+        _add_talent(talents, ABIL_SHAFT_SELF, check_confused);
+    }
 
     // Spit Poison. Nontransformed nagas can upgrade to Breathe Poison.
     // Transformed nagas, or non-nagas, can only get Spit Poison.
diff --git a/crawl-ref/source/acquire.cc b/crawl-ref/source/acquire.cc
index 11e4b81..cbd9d3b 100644
--- a/crawl-ref/source/acquire.cc
+++ b/crawl-ref/source/acquire.cc
@@ -153,7 +153,7 @@ static armour_type _pick_wearable_armour(const armour_type arm)
     if (arm == ARM_HELMET
         && (!you_can_wear(EQ_HELMET)
             || you.mutation[MUT_HORNS]
-            || you.mutation[MUT_ANTENNAE]))
+            || (you.mutation[MUT_ANTENNAE] && you.species != SP_FORMICID)))
     {
         // Check for Horns 3 & Antennae 3 - Don't give a cap if those mutation
         // levels have been reached.
@@ -528,7 +528,7 @@ static int _acquirement_weapon_subtype(bool divine)
         if (!acqweight)
             continue;
 
-        const bool two_handed = hands_reqd(item_considered, you.body_size()) == HANDS_TWO;
+        const bool two_handed = you.hands_reqd(item_considered) == HANDS_TWO;
 
         // For non-Trog/Okawaru acquirements, give a boost to high-end items.
         if (!divine && !is_range_weapon(item_considered))
@@ -607,8 +607,11 @@ static missile_type _acquirement_missile_subtype()
             if (_have_item_with_types(OBJ_WEAPONS, WPN_BLOWGUN))
                 missile_weights.push_back(make_pair(MI_NEEDLE, 100));
 
-            if (you.body_size() >= SIZE_MEDIUM)
+            if (you.can_throw_large_rocks()
+                || you.body_size() >= SIZE_MEDIUM)
+            {
                 missile_weights.push_back(make_pair(MI_JAVELIN, 100));
+            }
 
             if (you.can_throw_large_rocks())
                 missile_weights.push_back(make_pair(MI_LARGE_ROCK, 100));
diff --git a/crawl-ref/source/actor.cc b/crawl-ref/source/actor.cc
index a612e2a..056f35f 100644
--- a/crawl-ref/source/actor.cc
+++ b/crawl-ref/source/actor.cc
@@ -60,6 +60,12 @@ bool actor::stand_on_solid_ground() const
            && !feat_is_water(grd(pos()));
 }
 
+// Give hands required to wield weapon.
+hands_reqd_type actor::hands_reqd(const item_def &item) const
+{
+    return basic_hands_reqd(item, body_size());
+}
+
 /**
  * Wrapper around the virtual actor::can_wield(const item_def&,bool,bool,bool,bool) const overload.
  * @param item May be NULL, in which case a dummy item will be passed in.
diff --git a/crawl-ref/source/actor.h b/crawl-ref/source/actor.h
index 59b0973..cda7c20 100644
--- a/crawl-ref/source/actor.h
+++ b/crawl-ref/source/actor.h
@@ -120,6 +120,8 @@ public:
                             bool calc_unid = true) const = 0;
     virtual int scan_artefacts(artefact_prop_type which_property,
                                bool calc_unid = true) const = 0;
+    
+    virtual hands_reqd_type hands_reqd(const item_def &item) const;
 
             bool can_wield(const item_def* item,
                            bool ignore_curse = false,
diff --git a/crawl-ref/source/aptitudes.h b/crawl-ref/source/aptitudes.h
index 7ee6fc4..5a312ea 100644
--- a/crawl-ref/source/aptitudes.h
+++ b/crawl-ref/source/aptitudes.h
@@ -1340,6 +1340,40 @@ static const species_skill_aptitude species_skill_aptitudes[] =
     APT(SP_LAVA_ORC,        SK_POISON_MAGIC,   -1),
     APT(SP_LAVA_ORC,        SK_INVOCATIONS,     3),
     APT(SP_LAVA_ORC,        SK_EVOCATIONS,      1),
+    
+    // SP_FORMICID
+    APT(SP_FORMICID,        SK_FIGHTING,        0),
+    APT(SP_FORMICID,        SK_SHORT_BLADES,    1),
+    APT(SP_FORMICID,        SK_LONG_BLADES,     0),
+    APT(SP_FORMICID,        SK_AXES,            0),
+    APT(SP_FORMICID,        SK_MACES_FLAILS,    0),
+    APT(SP_FORMICID,        SK_POLEARMS,        0),
+    APT(SP_FORMICID,        SK_STAVES,          0),
+    APT(SP_FORMICID,        SK_SLINGS,          1),
+    APT(SP_FORMICID,        SK_BOWS,           -2),
+    APT(SP_FORMICID,        SK_CROSSBOWS,       0),
+    APT(SP_FORMICID,        SK_THROWING,       -2),
+    APT(SP_FORMICID,        SK_ARMOUR,          3),
+    APT(SP_FORMICID,        SK_DODGING,        -1),
+    APT(SP_FORMICID,        SK_STEALTH,         1),
+    APT(SP_FORMICID,        SK_SHIELDS,         0),
+    APT(SP_FORMICID,        SK_TRAPS,           1),
+    APT(SP_FORMICID,        SK_UNARMED_COMBAT,  0),
+    APT(SP_FORMICID,        SK_SPELLCASTING,   -1),
+    APT(SP_FORMICID,        SK_CONJURATIONS,   -1),
+    APT(SP_FORMICID,        SK_HEXES,           2),
+    APT(SP_FORMICID,        SK_CHARMS,          0),
+    APT(SP_FORMICID,        SK_SUMMONINGS,      0),
+    APT(SP_FORMICID,        SK_NECROMANCY,      0),
+    APT(SP_FORMICID,        SK_TRANSLOCATIONS,  0),
+    APT(SP_FORMICID,        SK_TRANSMUTATIONS,  1),
+    APT(SP_FORMICID,        SK_FIRE_MAGIC,      0),
+    APT(SP_FORMICID,        SK_ICE_MAGIC,       0),
+    APT(SP_FORMICID,        SK_AIR_MAGIC,      -2),
+    APT(SP_FORMICID,        SK_EARTH_MAGIC,     2),
+    APT(SP_FORMICID,        SK_POISON_MAGIC,    3),
+    APT(SP_FORMICID,        SK_INVOCATIONS,     2),
+    APT(SP_FORMICID,        SK_EVOCATIONS,      2),
 };
 
 #endif
diff --git a/crawl-ref/source/artefact.cc b/crawl-ref/source/artefact.cc
index 321e70c..a4561b9 100644
--- a/crawl-ref/source/artefact.cc
+++ b/crawl-ref/source/artefact.cc
@@ -1595,12 +1595,10 @@ int find_okay_unrandart(uint8_t aclass, uint8_t atype, bool in_abyss)
                && (aclass != OBJ_WEAPONS
                    || weapon_skill(entry->base_type, atype) !=
                       weapon_skill(entry->base_type, entry->sub_type)
-                   || hands_reqd(entry->base_type,
-                                 atype,
-                                 you.body_size()) !=
-                      hands_reqd(entry->base_type,
-                                 entry->sub_type,
-                                 you.body_size())))
+                   || hands_reqd(&you, entry->base_type,
+                                 atype) !=
+                      hands_reqd(&you, entry->base_type,
+                                 entry->sub_type)))
         {
             continue;
         }
diff --git a/crawl-ref/source/dat/descript/ability.txt b/crawl-ref/source/dat/descript/ability.txt
index bfa125d..7133eb3 100644
--- a/crawl-ref/source/dat/descript/ability.txt
+++ b/crawl-ref/source/dat/descript/ability.txt
@@ -92,6 +92,15 @@ Device Recharging
 
 At the permanent loss of one magic point recharge a wand or rod.
 %%%%
+Dig
+
+Tunnels through rock walls.
+%%%%
+Shaft Self
+
+Sends you to a random position one to three floors down,
+as if you fell through a shaft trap.
+%%%%
 Evoke Teleportation
 
 Teleport yourself to a random location on the level.
diff --git a/crawl-ref/source/dat/descript/monsters.txt b/crawl-ref/source/dat/descript/monsters.txt
index 11ff62a..4f4fc93 100644
--- a/crawl-ref/source/dat/descript/monsters.txt
+++ b/crawl-ref/source/dat/descript/monsters.txt
@@ -1485,6 +1485,18 @@ dryad
 A spirit of nature, bound to the forest in which it resides. It is capable of
 calling upon the trees to defend against incursions.
 %%%%
+formicid
+
+A sentient ant that walks upright and is competant at digging.
+%%%%
+formicid drone
+
+An ant-like soldier trained in combat and ready to defend its home.
+%%%%
+formicid venom mage
+
+A practitioner of its greatest fear. It knows how to create and cleanse poison.
+%%%%
 dwarf
 
 A member of a short, sturdy mountain-dwelling folk. More robust than their deep
diff --git a/crawl-ref/source/dat/descript/species.txt b/crawl-ref/source/dat/descript/species.txt
index ffadcb5..58dded4 100644
--- a/crawl-ref/source/dat/descript/species.txt
+++ b/crawl-ref/source/dat/descript/species.txt
@@ -32,6 +32,11 @@ Draconian
 Draconians are versatile hybrids. They mature when reaching level 7 and develop
 a colour.
 %%%%
+Formicid
+
+Formicids are humanoid ants adept at digging. Their limbs are exceptionally
+strong and they have a permanent sense of stasis.
+%%%%
 Felid
 
 These many-lived cats possess sentience, but are incapable of advanced item
diff --git a/crawl-ref/source/defines.h b/crawl-ref/source/defines.h
index 55e85b2..21a863e 100644
--- a/crawl-ref/source/defines.h
+++ b/crawl-ref/source/defines.h
@@ -183,6 +183,8 @@ const int CHUNK_BASE_NUTRITION    = 1000;
 const int ICEMAIL_MAX  = 10;
 const int ICEMAIL_TIME = 300 * BASELINE_DELAY;
 
+const int ANTENNAE_EXTEND_TIME = 10 * BASELINE_DELAY;
+
 // The maximum number of abilities any god can have
 #define MAX_GOD_ABILITIES               5
 
diff --git a/crawl-ref/source/delay.cc b/crawl-ref/source/delay.cc
index ac4d835..63cb187 100644
--- a/crawl-ref/source/delay.cc
+++ b/crawl-ref/source/delay.cc
@@ -20,6 +20,7 @@
 #include "delay.h"
 #include "describe.h"
 #include "directn.h"
+#include "dungeon.h"
 #include "exercise.h"
 #include "enum.h"
 #include "fprop.h"
@@ -58,6 +59,7 @@
 #include "stuff.h"
 #include "env.h"
 #include "transform.h"
+#include "traps.h"
 #include "travel.h"
 #include "hints.h"
 #include "view.h"
@@ -384,6 +386,14 @@ void stop_delay(bool stop_stair_travel, bool force_unsafe)
         }
         break;
 
+    case DELAY_SHAFT_SELF:
+        if (stop_stair_travel)
+        {
+            mpr("You stop digging.");
+            _pop_delay();
+        }
+        break;
+
     case DELAY_WEAPON_SWAP:       // one turn... too much trouble
     case DELAY_DROP_ITEM:         // one turn... only used for easy armour drops
     case DELAY_JEWELLERY_ON:      // one turn
@@ -708,6 +718,10 @@ void handle_delay()
         case DELAY_PASSWALL:
             mpr("You begin to meditate on the wall.", MSGCH_MULTITURN_ACTION);
             break;
+        
+        case DELAY_SHAFT_SELF:
+            mpr("You begin to dig a shaft.", MSGCH_MULTITURN_ACTION);
+            break;
 
         case DELAY_RECITE:
         {
@@ -924,6 +938,11 @@ void handle_delay()
                 MSGCH_MULTITURN_ACTION);
             break;
 
+        case DELAY_SHAFT_SELF:
+            mpr("You continue digging a shaft.",
+                MSGCH_MULTITURN_ACTION);
+            break;
+
         case DELAY_RECITE:
         {
             mprf(MSGCH_MULTITURN_ACTION, "\"%s\"",
@@ -1173,6 +1192,12 @@ static void _finish_delay(const delay_queue_item &delay)
         break;
     }
 
+    case DELAY_SHAFT_SELF:
+    {
+        you.do_shaft_ability();
+        break;
+    }
+
     case DELAY_BUTCHER:
     case DELAY_BOTTLE_BLOOD:
     {
@@ -1929,7 +1954,7 @@ static const char *delay_names[] =
     "jewellery_on", "memorise", "butcher", "bottle_blood", "weapon_swap",
     "passwall", "drop_item", "multidrop", "ascending_stairs",
     "descending_stairs", "recite", "run", "rest", "travel", "macro",
-    "macro_process_key", "interruptible", "uninterruptible"
+    "macro_process_key", "interruptible", "uninterruptible", "shaft self"
 };
 
 // Gets a delay given its name.
diff --git a/crawl-ref/source/describe.cc b/crawl-ref/source/describe.cc
index 01dfa25..ef0874a 100644
--- a/crawl-ref/source/describe.cc
+++ b/crawl-ref/source/describe.cc
@@ -760,13 +760,19 @@ static string _handedness_string(const item_def &item)
 {
     string description;
 
-    switch (hands_reqd(item, you.body_size()))
+    switch (you.hands_reqd(item))
     {
     case HANDS_ONE:
-        description += "It is a one handed weapon.";
+        if (you.species == SP_FORMICID)
+            description += "It is a weapon for one hand-pair.";
+        else
+            description += "It is a one handed weapon.";
         break;
     case HANDS_TWO:
-        description += "It is a two handed weapon.";
+        if (you.species == SP_FORMICID)
+            description += "It is a weapon for two hand-pairs.";
+        else
+            description += "It is a two handed weapon.";
         break;
     }
 
@@ -3683,6 +3689,7 @@ string get_ghost_description(const monster_info &mi, bool concise)
     case SP_NAGA:
     case SP_MUMMY:
     case SP_GHOUL:
+    case SP_FORMICID:
         str += 10;
         break;
 
diff --git a/crawl-ref/source/enum.h b/crawl-ref/source/enum.h
index 9b3079f..1711874 100644
--- a/crawl-ref/source/enum.h
+++ b/crawl-ref/source/enum.h
@@ -73,7 +73,10 @@ enum ability_type
     ABIL_BOTTLE_BLOOD,
     // Deep Dwarves
     ABIL_RECHARGING,
-    ABIL_MAX_INTRINSIC = ABIL_RECHARGING,
+    // Formicids
+    ABIL_DIG,
+    ABIL_SHAFT_SELF,
+    ABIL_MAX_INTRINSIC = ABIL_SHAFT_SELF,
 
     // Evoking items.
     ABIL_EVOKE_BERSERK = 40,
@@ -1064,6 +1067,8 @@ enum delay_type
 
     DELAY_INTERRUPTIBLE,                // simple interruptible delay
     DELAY_UNINTERRUPTIBLE,              // simple uninterruptible delay
+    
+    DELAY_SHAFT_SELF, // Formicid ability
 
     NUM_DELAYS
 };
@@ -1509,6 +1514,7 @@ enum duration_type
     DUR_WEAK,
     DUR_DIMENSION_ANCHOR,
     DUR_ANTIMAGIC,
+    DUR_ANTENNAE_EXTEND,
     NUM_DURATIONS
 };
 
@@ -2659,6 +2665,10 @@ enum monster_type                      // menv[].type
 
     MONS_SOJOBO,
 
+    MONS_FORMICID,
+    MONS_FORMICID_DRONE,
+    MONS_FORMICID_VENOM_MAGE,
+
     NUM_MONSTERS,               // used for polymorph
 
     // MONS_NO_MONSTER can get put in savefiles, so it shouldn't change
@@ -2851,6 +2861,7 @@ enum mutation_type
     MUT_MANA_LINK,
     MUT_PETRIFICATION_RESISTANCE,
     MUT_TRAMPLE_RESISTANCE,
+    MUT_CHITIN_SKIN,
     NUM_MUTATIONS,
 
     RANDOM_MUTATION,
@@ -3199,7 +3210,8 @@ enum species_type
     SP_DJINNI,
     SP_LAVA_ORC,
     SP_GARGOYLE,
-      LAST_VALID_SPECIES = SP_GARGOYLE,
+    SP_FORMICID,
+    LAST_VALID_SPECIES = SP_FORMICID,
 // The high scores viewer still needs enums for removed species.
     SP_ELF,                            // (placeholder)
     SP_HILL_DWARF,                     // (placeholder)
@@ -3486,6 +3498,8 @@ enum spell_type
     SPELL_CALL_LOST_SOUL,
     SPELL_DIMENSION_ANCHOR,
     SPELL_BLINK_ALLIES_ENCIRCLE,
+    SPELL_SHAFT_SELF,
+    SPELL_MASS_CURE_POISON,
     NUM_SPELLS
 };
 
diff --git a/crawl-ref/source/godpassive.cc b/crawl-ref/source/godpassive.cc
index cd0d3ce..8f7f711 100644
--- a/crawl-ref/source/godpassive.cc
+++ b/crawl-ref/source/godpassive.cc
@@ -161,7 +161,7 @@ static bool _two_handed()
     if (!wpn)
         return false;
 
-    hands_reqd_type wep_type = hands_reqd(*wpn, you.body_size());
+    hands_reqd_type wep_type = you.hands_reqd(*wpn);
     return wep_type == HANDS_TWO;
 }
 
diff --git a/crawl-ref/source/item_use.cc b/crawl-ref/source/item_use.cc
index 1e88391..db0d74a 100644
--- a/crawl-ref/source/item_use.cc
+++ b/crawl-ref/source/item_use.cc
@@ -136,9 +136,9 @@ bool can_wield(item_def *weapon, bool say_reason,
         return false;
     }
 
-    // Only ogres and trolls can wield giant clubs (>= 30 aum)
+    // Only ogres, trolls, and formicids can wield giant clubs (>= 30 aum)
     // and large rocks (60 aum).
-    if (you.body_size() < SIZE_LARGE
+    if ((you.body_size() < SIZE_LARGE && you.species != SP_FORMICID)
         && (item_mass(*weapon) >= 500
             || weapon->base_type == OBJ_WEAPONS
                && item_mass(*weapon) >= 300))
@@ -161,6 +161,7 @@ bool can_wield(item_def *weapon, bool say_reason,
 
     // Small species wielding large weapons...
     if (you.body_size(PSIZE_BODY) < SIZE_MEDIUM
+        && you.species != SP_FORMICID
         && !check_weapon_wieldable_size(*weapon, you.body_size(PSIZE_BODY)))
     {
         SAY(mpr("That's too large for you to wield."));
@@ -572,6 +573,12 @@ static int armour_equip_delay(const item_def &item)
     // Shields are comparatively easy to wear.
     if (is_shield(item))
         delay = delay / 2 + 1;
+    
+    // Formicids are slow to put on helmets
+    if (you.species == SP_FORMICID && get_armour_slot(item) == EQ_HELMET)
+    {
+        delay += 2;
+    }
 
     if (delay < 1)
         delay = 1;
@@ -746,7 +753,7 @@ bool can_wear_armour(const item_def &item, bool verbose, bool ignore_temporary)
             return false;
         }
 
-        if (player_mutation_level(MUT_ANTENNAE) == 3)
+        if (player_mutation_level(MUT_ANTENNAE) == 3 && you.species != SP_FORMICID)
         {
             if (verbose)
                 mpr("You can't wear any headgear with your large antennae!");
@@ -770,7 +777,7 @@ bool can_wear_armour(const item_def &item, bool verbose, bool ignore_temporary)
                 return false;
             }
 
-            if (player_mutation_level(MUT_ANTENNAE))
+            if (player_mutation_level(MUT_ANTENNAE) && you.species != SP_FORMICID)
             {
                 if (verbose)
                     mpr("You can't wear that with your antennae!");
@@ -846,6 +853,8 @@ bool do_wear_armour(int item, bool quiet)
         {
             if (you.species == SP_OCTOPODE)
                 mpr("You need the rest of your tentacles for walking.");
+            else if (you.species == SP_FORMICID)
+                mprf("You'd need six %s to do that!", you.hand_name(true).c_str());
             else
                 mprf("You'd need three %s to do that!", you.hand_name(true).c_str());
         }
@@ -1918,7 +1927,10 @@ void zap_wand(int slot)
         if (wand.sub_type == WAND_TELEPORTATION
             && you.no_tele(false, false))
         {
-            mpr("You cannot teleport right now.");
+            if (you.species == SP_FORMICID)
+                mpr("You cannot teleport.");
+            else
+                mpr("You cannot teleport right now.");
             return;
         }
         else if (wand.sub_type == WAND_INVISIBILITY
@@ -2965,7 +2977,10 @@ void read_scroll(int slot)
         case SCR_TELEPORTATION:
             if (you.no_tele(false, false, which_scroll == SCR_BLINKING))
             {
-                mpr("You cannot teleport right now.");
+                if (you.species == SP_FORMICID)
+                    mpr("You cannot teleport.");
+                else
+                    mpr("You cannot teleport right now.");
                 return;
             }
             break;
@@ -3376,30 +3391,41 @@ bool stasis_blocks_effect(bool calc_unid,
     {
         item_def *amulet = you.slot_item(EQ_AMULET, false);
 
-        // Just in case a non-amulet stasis source is added.
+        // For non-amulet sources of stasis.
         if (amulet && amulet->sub_type != AMU_STASIS)
             amulet = 0;
 
         if (msg)
         {
-            const string name(amulet? amulet->name(DESC_YOUR) : "Something");
-            const string message = make_stringf(msg, name.c_str());
-
-            if (noise)
+            // Override message for formicids
+            if (you.species == SP_FORMICID)
             {
-                if (!noisy(noise, you.pos(), message.c_str())
-                    && silenced_msg)
+                mpr("Your sense of stasis keeps you stable.");
+            }
+            else
+            {
+                const string name(amulet? amulet->name(DESC_YOUR) : "Something");
+                const string message = make_stringf(msg, name.c_str());
+
+                if (noise)
                 {
-                    mprf(silenced_msg, name.c_str());
+                    if (!noisy(noise, you.pos(), message.c_str())
+                        && silenced_msg)
+                    {
+                        mprf(silenced_msg, name.c_str());
+                    }
                 }
+                else
+                    mpr(message.c_str());
             }
-            else
-                mpr(message.c_str());
         }
 
-        // In all cases, the amulet auto-ids if requested.
-        if (amulet && identify && !item_type_known(*amulet))
+        // The amulet auto-ids if requested.
+        if (you.species != SP_FORMICID
+            && amulet && identify && !item_type_known(*amulet))
+        {
             wear_id_type(*amulet);
+        }
         return true;
     }
     return false;
diff --git a/crawl-ref/source/itemname.cc b/crawl-ref/source/itemname.cc
index 19bb80e..627f2bd 100644
--- a/crawl-ref/source/itemname.cc
+++ b/crawl-ref/source/itemname.cc
@@ -3174,11 +3174,11 @@ bool is_useless_item(const item_def &item, bool temp)
         switch (item.sub_type)
         {
         case MI_LARGE_ROCK:
-            return (you.body_size(PSIZE_BODY, !temp) < SIZE_LARGE
-                    || !you.can_throw_large_rocks());
+            return (!you.can_throw_large_rocks());
         case MI_JAVELIN:
         case MI_THROWING_NET:
-            return (you.body_size(PSIZE_BODY, !temp) < SIZE_MEDIUM);
+            return (you.body_size(PSIZE_BODY, !temp) < SIZE_MEDIUM
+                    && !you.can_throw_large_rocks());
         }
 
         return false;
@@ -3202,7 +3202,10 @@ bool is_useless_item(const item_def &item, bool temp)
         case SCR_RANDOM_USELESSNESS:
             return true;
         case SCR_TELEPORTATION:
-            return crawl_state.game_is_sprint();
+            return (you.species == SP_FORMICID
+                    || crawl_state.game_is_sprint());
+        case SCR_BLINKING:
+            return (you.species == SP_FORMICID);
         case SCR_AMNESIA:
             return (you.religion == GOD_TROG);
         case SCR_RECHARGING:
@@ -3221,6 +3224,16 @@ bool is_useless_item(const item_def &item, bool temp)
     case OBJ_WANDS:
         if (you.species == SP_FELID)
             return true;
+        
+        // Formicids have innate digging.
+        if (item.sub_type == WAND_DIGGING
+            && you.species == SP_FORMICID
+            && item_type_known(item))
+        {
+            return true;
+        }
+        // Note that while Formicids can't use hasting or teleport on themselves,
+        // they can still use them on allies or enemies.
 
         if (item.sub_type == WAND_INVISIBILITY
             && item_type_known(item)
@@ -3248,9 +3261,13 @@ bool is_useless_item(const item_def &item, bool temp)
         switch (item.sub_type)
         {
         case POT_BERSERK_RAGE:
-            return (you.is_undead
+            return (you.species == SP_FORMICID
+                    || (you.is_undead
                         && (you.species != SP_VAMPIRE
-                            || temp && you.hunger_state <= HS_SATIATED));
+                            || temp && you.hunger_state <= HS_SATIATED)));
+        
+        case POT_SPEED:
+            return (you.species == SP_FORMICID);
 
         case POT_CURE_MUTATION:
 #if TAG_MAJOR_VERSION == 34
@@ -3297,9 +3314,13 @@ bool is_useless_item(const item_def &item, bool temp)
         switch (item.sub_type)
         {
         case AMU_RAGE:
-            return (you.is_undead
+            return (you.species == SP_FORMICID
+                    || (you.is_undead
                         && (you.species != SP_VAMPIRE
-                            || temp && you.hunger_state <= HS_SATIATED));
+                            || temp && you.hunger_state <= HS_SATIATED)));
+        
+        case AMU_STASIS:
+            return (you.stasis(false, false));
 
         case AMU_CLARITY:
             return (you.clarity(false, false));
@@ -3360,10 +3381,12 @@ bool is_useless_item(const item_def &item, bool temp)
             return (you.religion == GOD_TROG);
 
         case RING_TELEPORT_CONTROL:
-            return crawl_state.game_is_zotdef();
+            return (you.species == SP_FORMICID
+                    || crawl_state.game_is_zotdef());
 
         case RING_TELEPORTATION:
-            return crawl_state.game_is_sprint();
+            return (you.species == SP_FORMICID
+                    || crawl_state.game_is_sprint());
 
         case RING_INVISIBILITY:
             return _invisibility_is_useless(temp);
diff --git a/crawl-ref/source/itemprop.cc b/crawl-ref/source/itemprop.cc
index ab007ef..46cab4e 100644
--- a/crawl-ref/source/itemprop.cc
+++ b/crawl-ref/source/itemprop.cc
@@ -1461,17 +1461,14 @@ int single_damage_type(const item_def &item)
     return ret;
 }
 
-hands_reqd_type hands_reqd(object_class_type base_type, int sub_type,
-                           size_type size)
+size_type weapon_size(const item_def &item)
 {
-    item_def item;
-    item.base_type = base_type;
-    item.sub_type  = sub_type;
-    return hands_reqd(item, size);
+    return Weapon_prop[Weapon_index[item.sub_type]].fit_size;
 }
 
 // Give hands required to wield weapon for a torso of "size".
-hands_reqd_type hands_reqd(const item_def &item, size_type size)
+// Not adjusted by species or anything, which is why it's "basic".
+hands_reqd_type basic_hands_reqd(const item_def &item, size_type size)
 {
     hands_reqd_type ret = HANDS_ONE;
 
@@ -1486,11 +1483,12 @@ hands_reqd_type hands_reqd(const item_def &item, size_type size)
 
     case OBJ_WEAPONS:
         ret = Weapon_prop[ Weapon_index[item.sub_type] ].hands;
+
         // Adjust handedness only for small races using melee weapons
         // that are larger than they are.
         if (!is_range_weapon(item)
             && size < SIZE_MEDIUM
-            && Weapon_prop[Weapon_index[item.sub_type]].fit_size > size)
+            && weapon_size(item) > size)
         {
             ret = HANDS_TWO;
         }
@@ -1515,6 +1513,14 @@ hands_reqd_type hands_reqd(const item_def &item, size_type size)
     return ret;
 }
 
+hands_reqd_type hands_reqd(const actor* ac, object_class_type base_type, int sub_type)
+{
+    item_def item;
+    item.base_type = base_type;
+    item.sub_type  = sub_type;
+    return ac->hands_reqd(item);
+}
+
 bool is_giant_club_type(int wpn_type)
 {
     return (wpn_type == WPN_GIANT_CLUB
@@ -1911,14 +1917,14 @@ bool is_throwable(const actor *actor, const item_def &wpn, bool force)
     {
         if (!force)
         {
-            if ((bodysize < SIZE_LARGE
-                    || !actor->can_throw_large_rocks())
+            if (!actor->can_throw_large_rocks()
                 && wpn.sub_type == MI_LARGE_ROCK)
             {
                 return false;
             }
 
-            if (bodysize < SIZE_MEDIUM
+            if (!actor->can_throw_large_rocks()
+                && bodysize < SIZE_MEDIUM
                 && (wpn.sub_type == MI_JAVELIN
                     || wpn.sub_type == MI_THROWING_NET))
             {
@@ -2809,7 +2815,7 @@ bool is_shield(const item_def &item)
             && get_armour_slot(item) == EQ_SHIELD);
 }
 
-// Returns true if the given item cannot be wielded with the given shield.
+// Returns true if the given item cannot be wielded _by you_ with the given shield.
 // The currently equipped shield is used if no shield is passed in.
 bool is_shield_incompatible(const item_def &weapon, const item_def *shield)
 {
@@ -2817,7 +2823,7 @@ bool is_shield_incompatible(const item_def &weapon, const item_def *shield)
     if (!shield && !(shield = you.shield()))
         return false;
 
-    hands_reqd_type hand = hands_reqd(weapon, you.body_size());
+    hands_reqd_type hand = you.hands_reqd(weapon);
     return (hand == HANDS_TWO && !is_range_weapon(weapon));
 }
 
diff --git a/crawl-ref/source/itemprop.h b/crawl-ref/source/itemprop.h
index d4cbe67..54fc185 100644
--- a/crawl-ref/source/itemprop.h
+++ b/crawl-ref/source/itemprop.h
@@ -89,9 +89,10 @@ int weapon_rarity(int w_type) IMMUTABLE;
 int   cmp_weapon_size(const item_def &item, size_type size) PURE;
 bool  check_weapon_wieldable_size(const item_def &item, size_type size) PURE;
 
-hands_reqd_type hands_reqd(const item_def &item, size_type size) PURE;
-hands_reqd_type hands_reqd(object_class_type base_type, int sub_type,
-                           size_type size) IMMUTABLE;
+size_type weapon_size(const item_def &item) PURE;
+
+hands_reqd_type basic_hands_reqd(const item_def &item, size_type size) PURE;
+hands_reqd_type hands_reqd(const actor* ac, object_class_type base_type, int sub_type);
 
 bool is_giant_club_type(int wpn_type) IMMUTABLE;
 
diff --git a/crawl-ref/source/main.cc b/crawl-ref/source/main.cc
index 7342073..7f5788a 100644
--- a/crawl-ref/source/main.cc
+++ b/crawl-ref/source/main.cc
@@ -2299,6 +2299,28 @@ static void _decrement_durations()
     }
     else
         you.duration[DUR_GOURMAND] = 0;
+    
+    // Retractable antennae
+    if (you.species == SP_FORMICID && !player_wearing_slot(EQ_HELMET))
+    {
+        if (form_keeps_mutations()
+            && you.duration[DUR_ANTENNAE_EXTEND] < ANTENNAE_EXTEND_TIME)
+        {
+            you.duration[DUR_ANTENNAE_EXTEND] += delay;
+            if (you.duration[DUR_ANTENNAE_EXTEND] >= ANTENNAE_EXTEND_TIME)
+            {
+                you.duration[DUR_ANTENNAE_EXTEND] = ANTENNAE_EXTEND_TIME;
+                mpr("Your antennae are now fully extended.");
+            }
+            #ifdef USE_TILE
+                init_player_doll();
+            #endif
+        }
+    }
+    else
+    {
+        you.duration[DUR_ANTENNAE_EXTEND] = 0;
+    }
 
     if (you.duration[DUR_ICEMAIL_DEPLETED] > 0)
     {
@@ -3181,7 +3203,7 @@ static void _player_reacts_to_monsters()
         manage_fire_shield(you.time_taken);
 
     // penance checked there (as you can have antennae too)
-    if (player_mutation_level(MUT_ANTENNAE) || you.religion == GOD_ASHENZARI)
+    if (you.has_antennae(true) || you.religion == GOD_ASHENZARI)
         check_antennae_detect();
 
     if ((you.religion == GOD_ASHENZARI && !player_under_penance())
diff --git a/crawl-ref/source/mon-cast.cc b/crawl-ref/source/mon-cast.cc
index e23e9bb..efe668c 100644
--- a/crawl-ref/source/mon-cast.cc
+++ b/crawl-ref/source/mon-cast.cc
@@ -66,6 +66,7 @@ static bool _valid_mon_spells[NUM_SPELLS];
 static int  _mons_mesmerise(monster* mons, bool actual = true);
 static int  _mons_cause_fear(monster* mons, bool actual = true);
 static int  _mons_mass_confuse(monster* mons, bool actual = true);
+static int  _mons_mass_cure_poison(monster* mons, bool actual = true);
 static int _mons_available_tentacles(monster* head);
 static coord_def _mons_fragment_target(monster *mons);
 
@@ -1137,6 +1138,8 @@ bool setup_mons_cast(monster* mons, bolt &pbolt, spell_type spell_cast,
     case SPELL_BLINK_ALLIES_ENCIRCLE:
     case SPELL_MASS_CONFUSION:
     case SPELL_ENGLACIATION:
+    case SPELL_SHAFT_SELF:
+    case SPELL_MASS_CURE_POISON:
         return true;
     default:
         if (check_validity)
@@ -1667,6 +1670,7 @@ static bool _ms_useful_fleeing_out_of_sight(const monster* mon,
     case SPELL_MAJOR_HEALING:
     case SPELL_ANIMATE_DEAD:
     case SPELL_TWISTED_RESURRECTION:
+    case SPELL_SHAFT_SELF:
         return true;
 
     default:
@@ -1750,6 +1754,7 @@ static bool _ms_low_hitpoint_cast(const monster* mon, spell_type monspell)
     case SPELL_CONTROLLED_BLINK:
         return targ_adj;
     case SPELL_TOMB_OF_DOROKLOHE:
+    case SPELL_SHAFT_SELF:
         return true;
     case SPELL_NO_SPELL:
         return false;
@@ -2341,13 +2346,21 @@ bool handle_mon_spell(monster* mons, bolt &beem)
         }
         // Check use of LOS attack spells.
         else if (spell_cast == SPELL_DRAIN_LIFE
-                 || spell_cast == SPELL_OZOCUBUS_REFRIGERATION
-                 || spell_cast == SPELL_OLGREBS_TOXIC_RADIANCE)
+                 || spell_cast == SPELL_OZOCUBUS_REFRIGERATION)
         {
             if (cast_los_attack_spell(spell_cast, mons->hit_dice, mons,
                                       false) != SPRET_SUCCESS)
                 return false;
         }
+        else if (spell_cast == SPELL_OLGREBS_TOXIC_RADIANCE)
+        {
+            // Formicids can cast freely as they also have mass cure poison.
+            // TODO: generalize this?
+            if (mons->type != MONS_FORMICID_VENOM_MAGE
+                && cast_los_attack_spell(spell_cast, mons->hit_dice, mons,
+                                      false) != SPRET_SUCCESS)
+                return false; 
+        }
         // See if we have a good spot to cast LRD at.
         else if (spell_cast == SPELL_LRD)
         {
@@ -2378,6 +2391,12 @@ bool handle_mon_spell(monster* mons, bolt &beem)
             if (_mons_mass_confuse(mons, false) < 0)
                 return false;
         }
+        // Try to mass cure poison; if we can't, pretend nothing happened.
+        else if (spell_cast == SPELL_MASS_CURE_POISON)
+        {
+            if (_mons_mass_cure_poison(mons, false) < 0)
+                return false;
+        }
         // Check if our enemy can be slowed for Metabolic Englaciation.
         else if (spell_cast == SPELL_ENGLACIATION)
         {
@@ -3049,6 +3068,54 @@ static int _mons_mass_confuse(monster* mons, bool actual)
     return retval;
 }
 
+static int _mons_mass_cure_poison(monster* mons, bool actual)
+{
+    int retval = -1;
+
+    if (actual)
+        simple_monster_message(mons, " cures the poison of those in need.");
+    
+    for (actor_iterator ai(mons->get_los()); ai; ++ai)
+    {
+        if (ai->is_player())
+        {
+            if (!mons->pacified() && !mons->friendly())
+                continue;
+            
+            if (you.duration[DUR_POISONING] == 0)
+                continue;
+
+            retval = 0;
+            
+            if (actual && you.duration[DUR_POISONING])
+            {
+                reduce_poison_player(2 + random2(3));
+                retval = 1;
+            }
+        }
+        else
+        {
+            monster* m = ai->as_monster();
+              
+            if (!mons->pacified() && mons->friendly() != m->friendly())
+                continue;
+            
+            if (!m->has_ench(ENCH_POISON))
+                continue;
+            
+            retval = 0;
+            
+            if (actual)
+            {
+                retval = 1;
+                m->del_ench(ENCH_POISON);
+            }
+        }
+    }
+
+    return retval;
+}
+
 static coord_def _mons_fragment_target(monster *mons)
 {
     coord_def target(GXM+1, GYM+1);
@@ -4215,6 +4282,14 @@ void mons_cast(monster* mons, bolt &pbolt, spell_type spell_cast,
         }
         return;
     }
+    case SPELL_SHAFT_SELF:
+    {
+        if (is_valid_shaft_level())
+        {
+            mons->do_shaft();
+        }
+        return;
+    }
     case SPELL_CHAIN_LIGHTNING:
         cast_chain_lightning(4 * mons->hit_dice, mons);
         return;
@@ -4379,6 +4454,10 @@ void mons_cast(monster* mons, bolt &pbolt, spell_type spell_cast,
         _mons_mass_confuse(mons);
         return;
 
+    case SPELL_MASS_CURE_POISON:
+        _mons_mass_cure_poison(mons);
+        return;
+
     case SPELL_ENGLACIATION:
         if (you.can_see(mons))
             simple_monster_message(mons, " radiates an aura of cold.");
diff --git a/crawl-ref/source/mon-data.h b/crawl-ref/source/mon-data.h
index a48d703..6b4c2e4 100644
--- a/crawl-ref/source/mon-data.h
+++ b/crawl-ref/source/mon-data.h
@@ -204,7 +204,7 @@ static monsterentry mondata[] = {
 
 // Real monsters begin here {dlb}:
 
-// ants ('a')
+// ants and formicids ('a')
 {
     MONS_WORKER_ANT, 'a', RED, "worker ant",
     M_NO_SKELETON,
@@ -236,11 +236,47 @@ static monsterentry mondata[] = {
     600, 10, MONS_WORKER_ANT, MONS_SOLDIER_ANT, MH_NATURAL, -3,
     { {AT_STING, AF_POISON_NASTY, 14}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
     { 6, 3, 5, 0 },
-    8, 10, MST_NO_SPELLS, CE_POISONOUS, Z_SMALL, S_SILENT,
+    8, 10, MST_NO_SPELLS, CE_POISONOUS, Z_NOZOMBIE, S_SILENT,
     I_INSECT, HT_LAND, FL_NONE, 10, DEFAULT_ENERGY,
     MONUSE_NOTHING, MONEAT_NOTHING, SIZE_MEDIUM
 },
 
+{
+    MONS_FORMICID, 'a', GREEN, "formicid",
+    M_WARM_BLOOD | M_SEE_INVIS | M_FAKE_SPELLS | M_FIGHTER | M_SPEAKS | M_PERMA_STASIS | M_FOUR_HANDS,
+    MR_VUL_POISON,
+    600, 10, MONS_FORMICID, MONS_FORMICID, MH_NATURAL, -4,
+    { {AT_HIT, AF_PLAIN, 10}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
+    { 4, 4, 6, 0 },
+    3, 10, MST_FORMICID, CE_CONTAMINATED, Z_NOZOMBIE, S_SHOUT,
+    I_NORMAL, HT_LAND, FL_NONE, 10, DEFAULT_ENERGY,
+    MONUSE_WEAPONS_ARMOUR, MONEAT_NOTHING, SIZE_MEDIUM
+},
+
+{
+    MONS_FORMICID_DRONE, 'a', YELLOW, "formicid drone",
+    M_WARM_BLOOD | M_SEE_INVIS | M_FAKE_SPELLS | M_SPEAKS | M_PERMA_STASIS | M_FOUR_HANDS,
+    MR_VUL_POISON,
+    600, 12, MONS_FORMICID, MONS_FORMICID, MH_NATURAL, -4,
+    { {AT_HIT, AF_PLAIN, 20}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
+    { 6, 4, 8, 0 },
+    3, 10, MST_FORMICID, CE_CONTAMINATED, Z_NOZOMBIE, S_SHOUT,
+    I_NORMAL, HT_LAND, FL_NONE, 10, DEFAULT_ENERGY,
+    MONUSE_WEAPONS_ARMOUR, MONEAT_NOTHING, SIZE_MEDIUM
+},
+
+{
+    MONS_FORMICID_VENOM_MAGE, 'a', MAGENTA, "formicid venom mage",
+    M_WARM_BLOOD | M_SEE_INVIS | M_SPELLCASTER | M_SPEAKS | M_PERMA_STASIS | M_FOUR_HANDS,
+    MR_VUL_POISON,
+    600, 12, MONS_FORMICID, MONS_FORMICID, MH_NATURAL, -4,
+    { {AT_HIT, AF_PLAIN, 10}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
+    { 7, 3, 5, 0 },
+    3, 8, MST_FORMICID_VENOM_MAGE, CE_CONTAMINATED, Z_NOZOMBIE, S_SHOUT,
+    I_HIGH, HT_LAND, FL_NONE, 10, DEFAULT_ENERGY,
+    MONUSE_WEAPONS_ARMOUR, MONEAT_NOTHING, SIZE_MEDIUM
+},
+
 // batty monsters ('b')
 {
     MONS_BAT, 'b', LIGHTGREY, "bat",
diff --git a/crawl-ref/source/mon-flags.h b/crawl-ref/source/mon-flags.h
index 2a2be1a..3d5926d 100644
--- a/crawl-ref/source/mon-flags.h
+++ b/crawl-ref/source/mon-flags.h
@@ -155,6 +155,12 @@ const uint64_t M_NO_GEN_DERIVED    = (uint64_t)1<<47;
 // tries to maintain range unless target is incapacitated
 const uint64_t M_STABBER           = (uint64_t)1<<48;
 
+// always under stasis effect
+const uint64_t M_PERMA_STASIS      = (uint64_t)1<<49;
+
+// can wield large weapons with a shield and big weapons without a shield
+const uint64_t M_FOUR_HANDS        = (uint64_t)1<<50;
+
 // Same for flags for actual monsters.
 typedef uint64_t monster_flag_type;
 const uint64_t MF_NO_REWARD          = BIT(0);  // no benefit from killing
diff --git a/crawl-ref/source/mon-gear.cc b/crawl-ref/source/mon-gear.cc
index bbf3fe6..885e266 100644
--- a/crawl-ref/source/mon-gear.cc
+++ b/crawl-ref/source/mon-gear.cc
@@ -367,6 +367,33 @@ static item_make_species_type _give_weapon(monster* mon, int level,
         }
         break;
 
+    case MONS_FORMICID:
+    case MONS_FORMICID_DRONE:
+        item_race = MAKE_ITEM_NO_RACE;
+        item.base_type = OBJ_WEAPONS;
+        if (one_chance_in(4))
+        {
+            item.sub_type = coinflip() ? WPN_GIANT_CLUB : WPN_GIANT_SPIKED_CLUB;
+        }
+        else
+        {
+            item.sub_type = random_choose_weighted(15, WPN_HAND_AXE, 15, WPN_SABRE,
+                                                   15, WPN_MACE,     15, WPN_FLAIL,
+                                                   5, WPN_GREAT_SWORD, 5, WPN_GREAT_MACE,
+                                                   5, WPN_BATTLEAXE, 0);
+        }
+        if (coinflip())
+        {
+            force_item  = true;
+            item.plus  += random2(3);
+            item.plus2 += random2(3);
+            if (one_chance_in(20))
+            {
+                level = MAKE_GOOD_ITEM;
+            }
+        }
+        break;
+
     case MONS_DWARF:
     case MONS_DEEP_DWARF:
         item_race = MAKE_ITEM_DWARVEN;
@@ -497,9 +524,9 @@ static item_make_species_type _give_weapon(monster* mon, int level,
     case MONS_ORC_PRIEST:
         item_race = MAKE_ITEM_ORCISH;
         // deliberate fall through {gdl}
-
     case MONS_DRACONIAN:
     case MONS_DRACONIAN_ZEALOT:
+    case MONS_FORMICID_VENOM_MAGE:
         if (!one_chance_in(5))
         {
             item.base_type = OBJ_WEAPONS;
@@ -1829,8 +1856,8 @@ static void _give_shield(monster* mon, int level)
     // If the monster is already wielding/carrying a two-handed weapon,
     // it doesn't get a shield.  (Monsters always prefer raw damage to
     // protection!)
-    if (main_weap && hands_reqd(*main_weap, mon->body_size()) == HANDS_TWO
-        || alt_weap && hands_reqd(*alt_weap, mon->body_size()) == HANDS_TWO)
+    if (main_weap && mon->hands_reqd(*main_weap) == HANDS_TWO
+        || alt_weap && mon->hands_reqd(*alt_weap) == HANDS_TWO)
     {
         return;
     }
@@ -2192,12 +2219,23 @@ static void _give_armour(monster* mon, int level, bool spectral_orcs)
 
     case MONS_DEEP_DWARF_NECROMANCER:
     case MONS_DEEP_DWARF_ARTIFICER:
+    case MONS_FORMICID_VENOM_MAGE:
     case MONS_HELLBINDER:
         item_race      = MAKE_ITEM_NO_RACE;
         item.base_type = OBJ_ARMOUR;
         item.sub_type  = ARM_ROBE;
         break;
 
+    case MONS_FORMICID:
+    case MONS_FORMICID_DRONE:
+        item_race      = MAKE_ITEM_NO_RACE;
+        item.base_type = OBJ_ARMOUR;
+        item.sub_type  = random_choose_weighted(5, ARM_SCALE_MAIL,
+                                                3, ARM_CHAIN_MAIL,
+                                                1, ARM_PLATE_ARMOUR,
+                                                0);
+        break;
+
     case MONS_DWARF:
     case MONS_DEEP_DWARF:
     case MONS_DEEP_DWARF_SCION:
diff --git a/crawl-ref/source/mon-grow.cc b/crawl-ref/source/mon-grow.cc
index f18c6cf..e7b83b1 100644
--- a/crawl-ref/source/mon-grow.cc
+++ b/crawl-ref/source/mon-grow.cc
@@ -76,6 +76,8 @@ static const monster_level_up mon_grow[] =
     monster_level_up(MONS_TENGU, MONS_TENGU_WARRIOR),
     monster_level_up(MONS_TENGU_CONJURER, MONS_TENGU_REAVER),
     monster_level_up(MONS_TENGU_WARRIOR, MONS_TENGU_REAVER),
+    
+    monster_level_up(MONS_FORMICID, MONS_FORMICID_DRONE),
 };
 
 mons_experience_levels::mons_experience_levels()
diff --git a/crawl-ref/source/mon-spll.h b/crawl-ref/source/mon-spll.h
index f5ee5af..1ef0869 100644
--- a/crawl-ref/source/mon-spll.h
+++ b/crawl-ref/source/mon-spll.h
@@ -2141,6 +2141,28 @@
        SPELL_MELEE,
        SPELL_NO_SPELL
       }
+    },
+
+    {  MST_FORMICID,
+      {
+       SPELL_NO_SPELL,
+       SPELL_NO_SPELL,
+       SPELL_NO_SPELL,
+       SPELL_NO_SPELL,
+       SPELL_DIG,
+       SPELL_SHAFT_SELF,
+      }
+    },
+
+    {  MST_FORMICID_VENOM_MAGE,
+      {
+       SPELL_OLGREBS_TOXIC_RADIANCE,
+       SPELL_OLGREBS_TOXIC_RADIANCE,
+       SPELL_NO_SPELL,
+       SPELL_MASS_CURE_POISON,
+       SPELL_DIG,
+       SPELL_SHAFT_SELF,
+      }
     }
 
 #endif
diff --git a/crawl-ref/source/monster.cc b/crawl-ref/source/monster.cc
index ca223ed..56568ed 100644
--- a/crawl-ref/source/monster.cc
+++ b/crawl-ref/source/monster.cc
@@ -536,6 +536,21 @@ item_def *monster::weapon(int which_attack) const
     return (weap == NON_ITEM ? NULL : &mitm[weap]);
 }
 
+// Give hands required to wield weapon.
+hands_reqd_type monster::hands_reqd(const item_def &item) const
+{
+    if (mons_class_flag(type, M_FOUR_HANDS))
+    {
+        if (weapon_size(item) >= SIZE_BIG)
+            return HANDS_TWO;
+        else
+            return HANDS_ONE;
+    }
+    else
+        return actor::hands_reqd(item);
+}
+
+
 bool monster::can_wield(const item_def& item, bool ignore_curse,
                          bool ignore_brand, bool ignore_shield,
                          bool ignore_transform) const
@@ -568,7 +583,7 @@ bool monster::can_wield(const item_def& item, bool ignore_curse,
     item_def* weap2       = NULL;
     if (mons_wields_two_weapons(this))
     {
-        if (!weap1 || hands_reqd(*weap1, body_size()) != HANDS_TWO)
+        if (!weap1 || hands_reqd(*weap1) != HANDS_TWO)
             avail_slots = 2;
 
         const int offhand = _mons_offhand_weapon_index(this);
@@ -582,7 +597,7 @@ bool monster::can_wield(const item_def& item, bool ignore_curse,
 
     // Barehanded needs two hands.
     const bool two_handed = item.base_type == OBJ_UNASSIGNED
-                            || hands_reqd(item, body_size()) == HANDS_TWO;
+                            || hands_reqd(item) == HANDS_TWO;
 
     item_def* _shield = NULL;
     if (inv[MSLOT_SHIELD] != NON_ITEM)
@@ -1228,7 +1243,7 @@ bool monster::pickup(item_def &item, int slot, int near, bool force_merge)
     // (Monsters will always favour damage over protection.)
     if ((slot == MSLOT_WEAPON || slot == MSLOT_ALT_WEAPON)
         && inv[MSLOT_SHIELD] != NON_ITEM
-        && hands_reqd(item, body_size()) == HANDS_TWO)
+        && hands_reqd(item) == HANDS_TWO)
     {
         if (!drop_item(MSLOT_SHIELD, near))
             return false;
@@ -1240,9 +1255,9 @@ bool monster::pickup(item_def &item, int slot, int near, bool force_merge)
     {
         const item_def* wpn = mslot_item(MSLOT_WEAPON);
         const item_def* alt = mslot_item(MSLOT_ALT_WEAPON);
-        if (wpn && hands_reqd(*wpn, body_size()) == HANDS_TWO)
+        if (wpn && hands_reqd(*wpn) == HANDS_TWO)
             return false;
-        if (alt && hands_reqd(*alt, body_size()) == HANDS_TWO)
+        if (alt && hands_reqd(*alt) == HANDS_TWO)
             return false;
     }
 
@@ -1747,7 +1762,7 @@ bool monster::wants_weapon(const item_def &weap) const
     // Monsters capable of dual-wielding will always prefer two weapons
     // to a single two-handed one, however strong.
     if (mons_wields_two_weapons(this)
-        && hands_reqd(weap, body_size()) == HANDS_TWO)
+        && hands_reqd(weap) == HANDS_TWO)
     {
         return false;
     }
@@ -1774,7 +1789,7 @@ bool monster::wants_armour(const item_def &item) const
     if (is_shield(item)
         && (mons_wields_two_weapons(this)
             || mslot_item(MSLOT_WEAPON)
-               && hands_reqd(*mslot_item(MSLOT_WEAPON), body_size())
+               && hands_reqd(*mslot_item(MSLOT_WEAPON))
                       == HANDS_TWO))
     {
         return false;
@@ -5960,8 +5975,19 @@ bool monster::check_clarity(bool silent) const
     return true;
 }
 
+bool monster::stasis(bool calc_unid, bool items) const
+{
+    if (mons_class_flag(type, M_PERMA_STASIS))
+        return true;
+    
+    return actor::stasis(calc_unid, items);
+}
+
 bool monster::check_stasis(bool silent, bool calc_unid) const
 {
+    if (mons_class_flag(type, M_PERMA_STASIS))
+        return true;
+
     if (!stasis())
         return false;
 
diff --git a/crawl-ref/source/monster.h b/crawl-ref/source/monster.h
index c2a4ba2..83a0229 100644
--- a/crawl-ref/source/monster.h
+++ b/crawl-ref/source/monster.h
@@ -239,6 +239,8 @@ public:
     item_def *launcher();
     item_def *missiles();
     item_def *shield();
+    
+    hands_reqd_type hands_reqd(const item_def &item) const;
 
     bool      can_wield(const item_def &item,
                         bool ignore_curse = false,
@@ -348,6 +350,8 @@ public:
     bool no_tele(bool calc_unid = true, bool permit_id = true,
                  bool blink = false) const;
     bool res_corr(bool calc_unid = true, bool items = true) const;
+    
+    bool stasis(bool calc_unid = true, bool items = true) const;
 
     flight_type flight_mode() const;
     bool can_cling_to_walls() const;
diff --git a/crawl-ref/source/mutation-data.h b/crawl-ref/source/mutation-data.h
index 622936c..98a0b0e 100644
--- a/crawl-ref/source/mutation-data.h
+++ b/crawl-ref/source/mutation-data.h
@@ -1517,5 +1517,23 @@
   "trample resistance"
 },
 
+{ MUT_CHITIN_SKIN,                     0,  2, false,  true,  true,
+  "chitin skin",
+
+  {"Your skin is composed of chitin. (AC +2)",
+   "Your body is surrounded by an exoskeleton. (AC + 4)",
+   ""},
+
+  {"Your skin hardens.",
+   "Your skin hardens into an exoskeleton.",
+   ""},
+
+  {"Your skin softens.",
+   "Your skin softens.",
+   ""},
+
+  "chitin skin"
+}
+
 
 #endif
diff --git a/crawl-ref/source/mutation.cc b/crawl-ref/source/mutation.cc
index c77b937..c7fe96e 100644
--- a/crawl-ref/source/mutation.cc
+++ b/crawl-ref/source/mutation.cc
@@ -202,6 +202,7 @@ mutation_activity_type mutation_activity_level(mutation_type mut)
         case MUT_FAST:
         case MUT_SLOW:
         case MUT_IRIDESCENT_SCALES:
+        case MUT_CHITIN_SKIN:
             return MUTACT_INACTIVE;
         case MUT_LARGE_BONE_PLATES:
         case MUT_ROUGH_BLACK_SCALES:
@@ -598,29 +599,39 @@ string describe_mutations(bool center_title)
 
         break;
     }
+    
+    case SP_FORMICID:
+        result += "Your are under a permanent stasis effect.\n";
+        result += "You can dig through walls and to a lower floor.\n";
+        result += "Your four strong arms can wield any weapon.\n";
+        result += "You are susceptible to poison.\n";
+        result += "The antennae on your head can retract.\n";
+        have_any = true;
+        break;
 
     default:
         break;
     }
-
-    switch (you.body_size(PSIZE_TORSO, true))
+    
+    if (you.species != SP_FELID)
     {
-    case SIZE_LITTLE:
-        if (you.species == SP_FELID)
+        switch (you.body_size(PSIZE_TORSO, true))
+        {
+        case SIZE_LITTLE:
+            result += "You are tiny and cannot use many weapons and most armour.\n";
+            have_any = true;
             break;
-        result += "You are tiny and cannot use many weapons and most armour.\n";
-        have_any = true;
-        break;
-    case SIZE_SMALL:
-        result += "You are small and have problems with some larger weapons.\n";
-        have_any = true;
-        break;
-    case SIZE_LARGE:
-        result += "You are too large for most types of armour.\n";
-        have_any = true;
-        break;
-    default:
-        break;
+        case SIZE_SMALL:
+            result += "You are small and have problems with some larger weapons.\n";
+            have_any = true;
+            break;
+        case SIZE_LARGE:
+            result += "You are too large for most types of armour.\n";
+            have_any = true;
+            break;
+        default:
+            break;
+        }
     }
 
     if (player_genus(GENPC_DRACONIAN))
@@ -1342,6 +1353,20 @@ bool physiology_mutation_conflict(mutation_type mutat)
     {
         return true;
     }
+    
+    if (you.species == SP_FORMICID)
+    {
+        // Formicids have stasis and so prevent mutations that would do nothing.
+        // Formicids are weak to poison so prevent poison resistance mutation.
+        if (mutat == MUT_BERSERK
+            || mutat == MUT_BLINK
+            || mutat == MUT_TELEPORT
+            || mutat == MUT_TELEPORT_CONTROL
+            || mutat == MUT_POISON_RESISTANCE)
+        {
+            return true;
+        }
+    }
 
     // Heat doesn't hurt fire, djinn don't care about hunger.
     if (you.species == SP_DJINNI && (mutat == MUT_HEAT_RESISTANCE
@@ -1678,7 +1703,7 @@ bool mutate(mutation_type which_mutation, const string &reason, bool failMsg,
     case MUT_ANTENNAE:
         // Horns & Antennae 3 removes all headgear.  Same algorithm as with
         // glove removal.
-        if (you.mutation[mutat] >= 3 && !you.melded[EQ_HELMET])
+        if (you.mutation[mutat] >= 3 && !you.melded[EQ_HELMET] && you.species != SP_FORMICID)
             remove_one_equip(EQ_HELMET, false, true);
         // Intentional fall-through
     case MUT_BEAK:
@@ -2522,7 +2547,7 @@ void check_demonic_guardian()
 
 void check_antennae_detect()
 {
-    int radius = player_mutation_level(MUT_ANTENNAE) * 2;
+    int radius = you.has_antennae(true) * 2;
     if (you.religion == GOD_ASHENZARI && !player_under_penance())
         radius = max(radius, you.piety / 20);
     if (radius <= 0)
diff --git a/crawl-ref/source/newgame.cc b/crawl-ref/source/newgame.cc
index daefd44..7a59e78 100644
--- a/crawl-ref/source/newgame.cc
+++ b/crawl-ref/source/newgame.cc
@@ -1644,7 +1644,8 @@ static vector<weapon_choice> _get_weapons(const newgame_def* ng)
 
             if (wp.first == WPN_THROWN)
             {
-                if (species_size(ng->species, PSIZE_TORSO) == SIZE_LARGE)
+                if (species_size(ng->species, PSIZE_TORSO) == SIZE_LARGE
+                    || ng->species == SP_FORMICID)
                     wp.first = WPN_ROCKS;
                 else if (species_size(ng->species, PSIZE_TORSO) <= SIZE_SMALL)
                     wp.first = WPN_DARTS;
diff --git a/crawl-ref/source/ng-restr.cc b/crawl-ref/source/ng-restr.cc
index 930a60c..5a1e4b1 100644
--- a/crawl-ref/source/ng-restr.cc
+++ b/crawl-ref/source/ng-restr.cc
@@ -57,6 +57,7 @@ char_choice_restriction job_allowed(species_type speci, job_type job)
         case SP_OCTOPODE:
         case SP_DJINNI:
         case SP_GARGOYLE:
+        case SP_FORMICID:
             return CC_RESTRICTED;
         default:
             return CC_UNRESTRICTED;
@@ -97,6 +98,7 @@ char_choice_restriction job_allowed(species_type speci, job_type job)
         case SP_OCTOPODE:
         case SP_GARGOYLE:
         case SP_DJINNI:
+        case SP_FORMICID:
             return CC_RESTRICTED;
         default:
             return CC_UNRESTRICTED;
@@ -201,6 +203,7 @@ char_choice_restriction job_allowed(species_type speci, job_type job)
         case SP_GHOUL:
         case SP_FELID:
         case SP_OCTOPODE:
+        case SP_FORMICID:
             return CC_RESTRICTED;
         default:
             return CC_UNRESTRICTED;
@@ -226,6 +229,7 @@ char_choice_restriction job_allowed(species_type speci, job_type job)
         case SP_GHOUL:
         case SP_VAMPIRE:
         case SP_OCTOPODE:
+        case SP_FORMICID:
             return CC_RESTRICTED;
         default:
             return CC_UNRESTRICTED;
@@ -245,6 +249,7 @@ char_choice_restriction job_allowed(species_type speci, job_type job)
         case SP_GHOUL:
         case SP_VAMPIRE:
         case SP_FELID:
+        case SP_FORMICID:
             return CC_RESTRICTED;
         default:
             return CC_UNRESTRICTED;
@@ -265,6 +270,7 @@ char_choice_restriction job_allowed(species_type speci, job_type job)
         case SP_MINOTAUR:
         case SP_GHOUL:
         case SP_VAMPIRE:
+        case SP_FORMICID:
             return CC_RESTRICTED;
         default:
             return CC_UNRESTRICTED;
@@ -290,6 +296,7 @@ char_choice_restriction job_allowed(species_type speci, job_type job)
         case SP_GHOUL:
         case SP_FELID:
         case SP_OCTOPODE:
+        case SP_FORMICID:
             return CC_RESTRICTED;
         default:
             return CC_UNRESTRICTED;
@@ -311,6 +318,7 @@ char_choice_restriction job_allowed(species_type speci, job_type job)
         case SP_TROLL:
         case SP_MINOTAUR:
         case SP_GHOUL:
+        case SP_FORMICID:
             return CC_RESTRICTED;
         default:
             return CC_UNRESTRICTED;
@@ -328,6 +336,7 @@ char_choice_restriction job_allowed(species_type speci, job_type job)
         case SP_MINOTAUR:
         case SP_DJINNI:
         case SP_GARGOYLE:
+        case SP_FORMICID:
             return CC_RESTRICTED;
         default:
             return CC_UNRESTRICTED;
@@ -370,6 +379,7 @@ char_choice_restriction job_allowed(species_type speci, job_type job)
         case SP_GHOUL:
         case SP_VAMPIRE:
         case SP_FELID:
+        case SP_FORMICID:
             return CC_RESTRICTED;
         default:
             return CC_UNRESTRICTED;
@@ -390,6 +400,7 @@ char_choice_restriction job_allowed(species_type speci, job_type job)
         case SP_TENGU:
         case SP_FELID:
         case SP_DJINNI:
+        case SP_FORMICID:
             return CC_RESTRICTED;
         default:
             return CC_UNRESTRICTED;
@@ -411,6 +422,7 @@ char_choice_restriction job_allowed(species_type speci, job_type job)
         case SP_VAMPIRE:
         case SP_FELID:
         case SP_GARGOYLE:
+        case SP_FORMICID:
             return CC_RESTRICTED;
         default:
             return CC_UNRESTRICTED;
@@ -479,6 +491,7 @@ char_choice_restriction job_allowed(species_type speci, job_type job)
         case SP_GHOUL:
         case SP_OCTOPODE:
         case SP_DJINNI:
+        case SP_FORMICID:
             return CC_RESTRICTED;
         default:
             return CC_UNRESTRICTED;
@@ -605,6 +618,7 @@ char_choice_restriction weapon_restriction(weapon_type wpn,
         case SP_HALFLING:
         case SP_KOBOLD:
         case SP_SPRIGGAN:
+        case SP_FORMICID:
             return CC_UNRESTRICTED;
 
         default:
@@ -640,6 +654,7 @@ char_choice_restriction weapon_restriction(weapon_type wpn,
         case SP_VAMPIRE:
         case SP_OCTOPODE:
         case SP_BASE_DRACONIAN:
+        case SP_FORMICID:
             return CC_UNRESTRICTED;
 
         default:
@@ -664,6 +679,7 @@ char_choice_restriction weapon_restriction(weapon_type wpn,
         case SP_OCTOPODE:
         case SP_BASE_DRACONIAN:
         case SP_DJINNI:
+        case SP_FORMICID:
             return CC_UNRESTRICTED;
 
         case SP_SPRIGGAN:
@@ -701,6 +717,7 @@ char_choice_restriction weapon_restriction(weapon_type wpn,
         case SP_OCTOPODE:
         case SP_BASE_DRACONIAN:
         case SP_DJINNI:
+        case SP_FORMICID:
             return CC_UNRESTRICTED;
 
         default:
@@ -748,6 +765,7 @@ char_choice_restriction weapon_restriction(weapon_type wpn,
         case SP_SLUDGE_ELF:
         case SP_BASE_DRACONIAN:
         case SP_DJINNI:
+        case SP_FORMICID:
             return CC_UNRESTRICTED;
 
         default:
@@ -786,6 +804,7 @@ char_choice_restriction weapon_restriction(weapon_type wpn,
         case SP_LAVA_ORC:
         case SP_SLUDGE_ELF:
         case SP_DJINNI:
+        case SP_FORMICID:
             return CC_RESTRICTED;
         case SP_FELID:
             return CC_BANNED;
@@ -818,6 +837,7 @@ char_choice_restriction weapon_restriction(weapon_type wpn,
         {
         case SP_OGRE:
         case SP_TROLL:
+        case SP_FORMICID:
             return CC_UNRESTRICTED;
         default:
             return CC_BANNED;
@@ -828,6 +848,7 @@ char_choice_restriction weapon_restriction(weapon_type wpn,
         {
         case SP_DEEP_DWARF:
         case SP_DJINNI:
+        case SP_FORMICID:
             return CC_RESTRICTED;
         case SP_SPRIGGAN:
         case SP_FELID:
@@ -841,6 +862,7 @@ char_choice_restriction weapon_restriction(weapon_type wpn,
         {
         case SP_DEEP_DWARF:
         case SP_DJINNI:
+        case SP_FORMICID:
             return CC_RESTRICTED;
         case SP_FELID:
             return CC_BANNED;
diff --git a/crawl-ref/source/ng-setup.cc b/crawl-ref/source/ng-setup.cc
index ba978e4..b2ddad3 100644
--- a/crawl-ref/source/ng-setup.cc
+++ b/crawl-ref/source/ng-setup.cc
@@ -79,6 +79,7 @@ static void _species_stat_init(species_type which_species)
 
     case SP_MERFOLK:            sb =  6; ib =  5; db =  7;      break;  // 18
     case SP_TENGU:              sb =  6; ib =  6; db =  7;      break;  // 19
+    case SP_FORMICID:           sb = 10; ib =  5; db =  4;      break;  // 19
 
     case SP_KOBOLD:             sb =  5; ib =  4; db =  8;      break;  // 17
     case SP_HALFLING:           sb =  3; ib =  6; db =  9;      break;  // 18
@@ -348,6 +349,10 @@ void give_basic_mutations(species_type speci)
         you.mutation[MUT_CAMOUFLAGE]      = 1;
         you.mutation[MUT_GELATINOUS_BODY] = 1;
         break;
+    case SP_FORMICID:
+        you.mutation[MUT_ANTENNAE]    = 1;
+        you.mutation[MUT_CHITIN_SKIN] = 1;
+        break;
     default:
         break;
     }
@@ -972,6 +977,12 @@ static void _give_items_skills(const newgame_def& ng)
     if (you.species == SP_DEEP_DWARF)
         newgame_make_item(-1, EQ_NONE, OBJ_WANDS, WAND_HEAL_WOUNDS, -1, 1, 5);
 
+    // Formicids get curing potions to offset their poison weakness.
+    if (you.species == SP_FORMICID)
+    {
+        newgame_make_item(-1, EQ_NONE, OBJ_POTIONS, POT_CURING, -1, 2);
+    }
+
     // Zotdef: everyone gets a bonus two potions of curing, plus two
     // free levels in Traps & Doors so they can replace old traps with
     // better ones.
diff --git a/crawl-ref/source/output.cc b/crawl-ref/source/output.cc
index 1fa0a3b..1a96e09 100644
--- a/crawl-ref/source/output.cc
+++ b/crawl-ref/source/output.cc
@@ -2652,6 +2652,14 @@ static string _status_mut_abilities(int sw)
         mutations.push_back(_dragon_abil("breathe steam"));
         break;
 
+    case SP_FORMICID:
+        mutations.push_back("permanent stasis");
+        mutations.push_back("dig shafts and tunnels");
+        mutations.push_back("four strong arms");
+        mutations.push_back("poison weakness");
+        mutations.push_back("retractable antennae");
+        break;
+
     default:
         break;
     }                           //end switch - innate abilities
@@ -2820,6 +2828,9 @@ static string _status_mut_abilities(int sw)
                 AC_change += (level == 3) ? 2 : 1;
                 EV_change += level - 1;
                 break;
+            case MUT_CHITIN_SKIN:
+                AC_change += level * 2;
+                break;
             default:
                 die("mutation without a short desc: %d", i);
             }
diff --git a/crawl-ref/source/player-act.cc b/crawl-ref/source/player-act.cc
index d5ea690..8d72409 100644
--- a/crawl-ref/source/player-act.cc
+++ b/crawl-ref/source/player-act.cc
@@ -287,6 +287,20 @@ item_def *player::weapon(int /* which_attack */) const
     return slot_item(EQ_WEAPON, false);
 }
 
+// Give hands required to wield weapon.
+hands_reqd_type player::hands_reqd(const item_def &item) const
+{
+    if (species == SP_FORMICID)
+    {
+        if (weapon_size(item) >= SIZE_BIG)
+            return HANDS_TWO;
+        else
+            return HANDS_ONE;
+    }
+    else
+        return actor::hands_reqd(item);
+}
+
 bool player::can_wield(const item_def& item, bool ignore_curse,
                        bool ignore_brand, bool ignore_shield,
                        bool ignore_transform) const
@@ -299,7 +313,7 @@ bool player::can_wield(const item_def& item, bool ignore_curse,
 
     // Unassigned means unarmed combat.
     const bool two_handed = item.base_type == OBJ_UNASSIGNED
-                            || hands_reqd(item, body_size()) == HANDS_TWO;
+                            || hands_reqd(item) == HANDS_TWO;
 
     if (two_handed && !ignore_shield && player_wearing_slot(EQ_SHIELD))
         return false;
@@ -312,6 +326,9 @@ bool player::could_wield(const item_def &item, bool ignore_brand,
 {
     if (species == SP_FELID)
         return false;
+    if (species == SP_FORMICID)
+        return true;
+    
     if (body_size(PSIZE_TORSO, ignore_transform) < SIZE_LARGE
             && (item_mass(item) >= 500
                 || item.base_type == OBJ_WEAPONS
@@ -690,9 +707,7 @@ bool player::can_go_berserk(bool intentional, bool potion, bool quiet) const
     {
         if (verbose)
         {
-            const item_def *amulet = you.slot_item(EQ_AMULET, false);
-            mprf("You cannot go berserk with %s on.",
-                 amulet? amulet->name(DESC_YOUR).c_str() : "your amulet");
+            mprf("You cannot go berserk while under stasis");
         }
         return false;
     }
diff --git a/crawl-ref/source/player-equip.cc b/crawl-ref/source/player-equip.cc
index 7749b7a..bd427a2 100644
--- a/crawl-ref/source/player-equip.cc
+++ b/crawl-ref/source/player-equip.cc
@@ -1007,6 +1007,16 @@ static void _equip_armour_effect(item_def& arm, bool unmeld)
 
     if (get_item_slot(arm) == EQ_SHIELD)
         warn_shield_penalties();
+    
+    if (you.species == SP_FORMICID
+        && get_item_slot(arm) == EQ_HELMET)
+    {
+        mpr("Your antennae retract into your head.");
+        you.duration[DUR_ANTENNAE_EXTEND] = 0;    
+        #ifdef USE_TILE
+            init_player_doll();
+        #endif
+    }
 
     you.redraw_armour_class = true;
     you.redraw_evasion = true;
diff --git a/crawl-ref/source/player.cc b/crawl-ref/source/player.cc
index c9cae77..15872e4 100644
--- a/crawl-ref/source/player.cc
+++ b/crawl-ref/source/player.cc
@@ -731,7 +731,8 @@ bool you_can_wear(int eq, bool special_armour)
     case EQ_HELMET:
         // No caps or hats with Horns 3 or Antennae 3.
         if (player_mutation_level(MUT_HORNS, false) == 3
-            || player_mutation_level(MUT_ANTENNAE, false) == 3)
+            || (player_mutation_level(MUT_ANTENNAE, false) == 3
+                && you.species != SP_FORMICID))
         {
             return false;
         }
@@ -740,7 +741,8 @@ bool you_can_wear(int eq, bool special_armour)
             return true;
         if (player_mutation_level(MUT_HORNS, false)
             || player_mutation_level(MUT_BEAK, false)
-            || player_mutation_level(MUT_ANTENNAE, false))
+            || (player_mutation_level(MUT_ANTENNAE, false)
+                && you.species != SP_FORMICID))
         {
             return false;
         }
@@ -840,8 +842,12 @@ bool you_tran_can_wear(int eq, bool check_mutation)
         if (eq == EQ_HELMET && player_mutation_level(MUT_HORNS) == 3)
             return false;
 
-        if (eq == EQ_HELMET && player_mutation_level(MUT_ANTENNAE) == 3)
+        if (eq == EQ_HELMET 
+            && player_mutation_level(MUT_ANTENNAE) == 3
+            && you.species != SP_FORMICID)
+        {
             return false;
+        }
 
         if (eq == EQ_BOOTS
             && (you.fishtail
@@ -1908,6 +1914,10 @@ int player_res_poison(bool calc_unid, bool temp, bool items)
     // Only thirsty vampires are naturally poison resistant.
     if (you.species == SP_VAMPIRE && you.hunger_state < HS_SATIATED)
         rp++;
+    
+    // Formicids are vulnerable, but can make up for it with 2 rPois sources.
+    if (you.species == SP_FORMICID)
+        rp--;
 
     if (temp)
     {
@@ -1937,7 +1947,7 @@ int player_res_poison(bool calc_unid, bool temp, bool items)
 
     // Give vulnerability for Spider Form, and only let one level of rP to make
     // up for it (never be poison resistant in Spider Form).
-    rp = (rp > 0 ? 1 : 0);
+    rp = (rp > 0 ? 1 : rp);
 
     if (temp)
     {
@@ -3610,6 +3620,22 @@ void level_change(int source, const char* aux, bool skip_attribute_increase)
                     modify_stat(STAT_RANDOM, 1, false, "level gain");
                 break;
 
+            case SP_FORMICID:
+                if ((you.experience_level == 9)
+                    || (you.experience_level == 18))
+                {
+                    perma_mutate(MUT_ANTENNAE, 1, "level up");
+                    #ifdef USE_TILE
+                        init_player_doll();
+                    #endif
+                }
+
+                if (!(you.experience_level % 4))
+                {
+                    modify_stat(STAT_STR, 1, false, "level gain");
+                }
+                break;
+
             default:
                 break;
             }
@@ -4375,6 +4401,14 @@ bool player::gourmand(bool calc_unid, bool items) const
     return actor::gourmand(calc_unid, items);
 }
 
+bool player::stasis(bool calc_unid, bool items) const
+{
+    if (species == SP_FORMICID)
+        return true;
+
+    return actor::stasis(calc_unid, items);
+}
+
 unsigned int exp_needed(int lev, int exp_apt)
 {
     unsigned int level = 0;
@@ -5738,6 +5772,8 @@ void player::init()
 
     temperature = 1; // 1 is min; 15 is max.
     temperature_last = 1;
+    
+    duration[DUR_ANTENNAE_EXTEND] = ANTENNAE_EXTEND_TIME;
 
     xray_vision = false;
 
@@ -6504,6 +6540,8 @@ int player::armour_class() const
           ? 100 + _mut_level(MUT_THIN_METALLIC_SCALES, MUTACT_FULL) * 100 : 0; // +2, +3, +4
     AC += _mut_level(MUT_YELLOW_SCALES, MUTACT_FULL)
           ? 100 + _mut_level(MUT_YELLOW_SCALES, MUTACT_FULL) * 100 : 0;        // +2, +3, +4
+    AC += player_mutation_level(MUT_CHITIN_SKIN)
+          ? player_mutation_level(MUT_CHITIN_SKIN) * 200 : 0;                  // +2, +4
 
     return (AC / 100);
 }
@@ -6814,6 +6852,7 @@ int player_res_magic(bool calc_unid, bool temp)
     case SP_VAMPIRE:
     case SP_DEMIGOD:
     case SP_OGRE:
+    case SP_FORMICID:
         rm = you.experience_level * 4;
         break;
     case SP_NAGA:
@@ -7233,7 +7272,7 @@ bool player::has_usable_offhand() const
         return false;
 
     const item_def* wp = slot_item(EQ_WEAPON);
-    return (!wp || hands_reqd(*wp, body_size()) != HANDS_TWO);
+    return (!wp || hands_reqd(*wp) != HANDS_TWO);
 }
 
 bool player::has_usable_tentacle() const
@@ -7256,7 +7295,7 @@ int player::usable_tentacles() const
     const item_def* wp = slot_item(EQ_WEAPON);
     if (wp)
     {
-        hands_reqd_type hands_req = hands_reqd(*wp, body_size());
+        hands_reqd_type hands_req = hands_reqd(*wp);
         free_tentacles -= 2 * hands_req + 2;
     }
 
@@ -7293,6 +7332,34 @@ int player::has_usable_tentacles(bool allow_tran) const
     return has_tentacles(allow_tran);
 }
 
+int player::has_antennae(bool allow_tran) const
+{
+    if (allow_tran)
+    {
+        // Most forms suppress antennae.
+        if (!form_keeps_mutations())
+            return 0;
+    }
+
+    if (you.species == SP_FORMICID)
+    {
+        if (player_wearing_slot(EQ_HELMET))
+            return 0;
+        
+        return (you.duration[DUR_ANTENNAE_EXTEND] 
+                * player_mutation_level(MUT_ANTENNAE, allow_tran))
+               / ANTENNAE_EXTEND_TIME;
+    }
+
+    return player_mutation_level(MUT_ANTENNAE, allow_tran);
+}
+
+bool player::has_usable_antennae(bool allow_tran) const
+{
+    // Assumes that armour cannot be placed over normal antennae.
+    return has_antennae(allow_tran);
+}
+
 bool player::sicken(int amount, bool allow_hint, bool quiet)
 {
     ASSERT(!crawl_state.game_is_arena());
@@ -7344,7 +7411,7 @@ bool player::can_see_invisible(bool calc_unid, bool items) const
     }
 
     // antennae give sInvis at 3
-    if (player_mutation_level(MUT_ANTENNAE) == 3)
+    if (has_antennae(true) == 3)
         return true;
 
     if (player_mutation_level(MUT_EYEBALLS) == 3)
@@ -7584,7 +7651,9 @@ bool player::cannot_act() const
 
 bool player::can_throw_large_rocks() const
 {
-    return (species == SP_OGRE || species == SP_TROLL);
+    return (species == SP_OGRE 
+            || species == SP_TROLL
+            || species == SP_FORMICID);
 }
 
 bool player::can_smell() const
@@ -7680,6 +7749,8 @@ vector<PlaceInfo> player::get_all_place_info(bool visited_only,
     return list;
 }
 
+// Used for falling into traps and other bad effects, but is a slightly
+// different effect from the player invokable ability.
 bool player::do_shaft()
 {
     dungeon_feature_type force_stair = DNGN_UNSEEN;
@@ -7719,6 +7790,43 @@ bool player::do_shaft()
     return true;
 }
 
+bool player::can_do_shaft_ability() const
+{
+    switch (grd(pos()))
+    {
+    case DNGN_FLOOR:
+    case DNGN_OPEN_DOOR:
+        return is_valid_shaft_level();
+
+    default:
+        return false;
+    }
+}
+
+// Like do_shaft, but forced by the player.
+// It has a slightly different set of rules.
+bool player::do_shaft_ability()
+{
+    if (can_do_shaft_ability())
+    {
+        mpr("A shaft appears beneath you!");
+        down_stairs(DNGN_TRAP_NATURAL);
+        mpr("The earth vibrates loudly upon landing!");
+        fake_noisy(30, pos());
+        // Make it more likely for OOD to spawn
+        env.turns_on_level *= 3 + experience_level / 9;
+        env.turns_on_level /= 2;
+        env.turns_on_level += experience_level * 27;
+        return true;
+    }
+    else
+    {
+        canned_msg(MSG_NOTHING_HAPPENS);
+        redraw_screen();
+        return false;
+    }
+}
+
 bool player::did_escape_death() const
 {
     return (escaped_death_cause != NUM_KILLBY);
diff --git a/crawl-ref/source/player.h b/crawl-ref/source/player.h
index dddf445..755a53e 100644
--- a/crawl-ref/source/player.h
+++ b/crawl-ref/source/player.h
@@ -528,6 +528,8 @@ public:
     int       has_usable_pseudopods(bool allow_tran = true) const;
     int       has_tentacles(bool allow_tran = true) const;
     int       has_usable_tentacles(bool allow_tran = true) const;
+    int       has_antennae(bool allow_tran = true) const;
+    bool      has_usable_antennae(bool allow_tran = true) const;
 
     int wearing(equipment_type slot, int sub_type, bool calc_unid = true) const;
     int wearing_ego(equipment_type slot, int type, bool calc_unid = true) const;
@@ -536,6 +538,8 @@ public:
 
     item_def *weapon(int which_attack = -1) const;
     item_def *shield();
+    
+    hands_reqd_type hands_reqd(const item_def &item) const;
 
     bool      can_wield(const item_def &item,
                         bool ignore_curse = false,
@@ -641,6 +645,7 @@ public:
     bool gourmand(bool calc_unid = true, bool items = true) const;
     bool res_corr(bool calc_unid = true, bool items = true) const;
     bool clarity(bool calc_unid = true, bool items = true) const;
+    bool stasis(bool calc_unid = true, bool items = true) const;
 
     flight_type flight_mode() const;
     bool cancellable_flight() const;
@@ -707,6 +712,9 @@ public:
     int  skill(skill_type skill, int scale =1, bool real = false) const;
 
     bool do_shaft();
+    
+    bool can_do_shaft_ability() const;
+    bool do_shaft_ability();
 
     void apply_location_effects(const coord_def &oldpos,
                                 killer_type killer = KILL_NONE,
diff --git a/crawl-ref/source/rltiles/dc-player.txt b/crawl-ref/source/rltiles/dc-player.txt
index 7c1f965..bcd9875 100644
--- a/crawl-ref/source/rltiles/dc-player.txt
+++ b/crawl-ref/source/rltiles/dc-player.txt
@@ -69,6 +69,10 @@ octopode3
 octopode4
 octopode5
 djinni DJINNI
+formicid0 FORMICID
+formicid1
+formicid2
+formicid3
 
 # draconians
 draconian_f DRACONIAN DRACONIAN_FIRST
diff --git a/crawl-ref/source/rltiles/player/base/formicid0.png b/crawl-ref/source/rltiles/player/base/formicid0.png
new file mode 100644
index 0000000000000000000000000000000000000000..a12f9a3f50359fb1e235d48f1cfacdcc8cbdc917
GIT binary patch
diff --git a/crawl-ref/source/rltiles/player/base/formicid1.png b/crawl-ref/source/rltiles/player/base/formicid1.png
new file mode 100644
index 0000000000000000000000000000000000000000..6a2c2b1d12d29d1568818a3e66e76c969fbddfd5
GIT binary patch
diff --git a/crawl-ref/source/rltiles/player/base/formicid2.png b/crawl-ref/source/rltiles/player/base/formicid2.png
new file mode 100644
index 0000000000000000000000000000000000000000..c6376761e0e0aa9bc4c0fb23bc5a55745245ab97
GIT binary patch
diff --git a/crawl-ref/source/rltiles/player/base/formicid3.png b/crawl-ref/source/rltiles/player/base/formicid3.png
new file mode 100644
index 0000000000000000000000000000000000000000..6949269a74ca777288eff4fdd8321294b5e3fe05
GIT binary patch
diff --git a/crawl-ref/source/species.cc b/crawl-ref/source/species.cc
index df8f1e4..c7012ea 100644
--- a/crawl-ref/source/species.cc
+++ b/crawl-ref/source/species.cc
@@ -19,9 +19,9 @@
 static species_type species_order[] = {
     // comparatively human-like looks
     SP_HUMAN,          SP_HIGH_ELF,
-    SP_DEEP_ELF,
-    SP_DEEP_DWARF,     SP_HILL_ORC,
-    SP_LAVA_ORC,       SP_MERFOLK,
+    SP_DEEP_ELF,       SP_DEEP_DWARF,
+    SP_HILL_ORC,       SP_LAVA_ORC,
+    SP_MERFOLK,        SP_FORMICID,
     // small species
     SP_HALFLING,       SP_KOBOLD,
     SP_SPRIGGAN,
@@ -64,7 +64,7 @@ static const char * Species_Abbrev_List[NUM_SPECIES] =
       // the draconians
       "Dr", "Dr", "Dr", "Dr", "Dr", "Dr", "Dr", "Dr", "Dr", "Dr",
       "Ce", "Dg", "Sp", "Mi", "Ds", "Gh", "Te", "Mf", "Vp", "DD",
-      "Fe", "Op", "Dj", "LO", "Gr",
+      "Fe", "Op", "Dj", "LO", "Gr", "Fo",
       // placeholders
       "El", "HD", "OM", "GE", "Gn", "MD",
 #if TAG_MAJOR_VERSION > 34
@@ -199,6 +199,7 @@ string species_name(species_type speci, bool genus, bool adj)
         case SP_MINOTAUR:   res = "Minotaur";                          break;
         case SP_TENGU:      res = "Tengu";                             break;
         case SP_GARGOYLE:   res = "Gargoyle";                          break;
+        case SP_FORMICID:   res = "Formicid";                          break;
 
         case SP_HILL_ORC:
             res = (adj ? "Orcish" : genus ? "Orc" : "Hill Orc");
@@ -385,6 +386,8 @@ monster_type player_species_to_mons_species(species_type species)
         return MONS_OCTOPODE;
     case SP_DJINNI:
         return MONS_DJINNI;
+    case SP_FORMICID:
+        return MONS_FORMICID;
     case SP_ELF:
     case SP_HILL_DWARF:
     case SP_MOUNTAIN_DWARF:
@@ -413,6 +416,7 @@ int species_exp_modifier(species_type species)
     case SP_HUMAN:
     case SP_HALFLING:
     case SP_KOBOLD:
+    case SP_FORMICID:
         return 1;
     case SP_HILL_ORC:
     case SP_OGRE:
@@ -466,6 +470,7 @@ int species_hp_modifier(species_type species)
     case SP_DEEP_ELF:
     case SP_TENGU:
     case SP_KOBOLD:
+    case SP_FORMICID:
         return -2;
     case SP_HIGH_ELF:
     case SP_SLUDGE_ELF:
@@ -511,6 +516,7 @@ int species_mp_modifier(species_type species)
         return -2;
     case SP_CENTAUR:
     case SP_GHOUL:
+    case SP_FORMICID:
         return -1;
     default:
         return 0;
diff --git a/crawl-ref/source/spl-cast.cc b/crawl-ref/source/spl-cast.cc
index 91f1217..70f0a22 100644
--- a/crawl-ref/source/spl-cast.cc
+++ b/crawl-ref/source/spl-cast.cc
@@ -1026,7 +1026,10 @@ static bool _spellcasting_aborted(spell_type spell,
 
     if (is_prevented_teleport(spell))
     {
-        mpr("You cannot teleport right now.");
+        if (you.species == SP_FORMICID)
+            mpr("You cannot teleport.");
+        else
+            mpr("You cannot teleport right now.");
         return true;
     }
 
diff --git a/crawl-ref/source/spl-data.h b/crawl-ref/source/spl-data.h
index 83eb526..b31b4d9 100644
--- a/crawl-ref/source/spl-data.h
+++ b/crawl-ref/source/spl-data.h
@@ -3089,6 +3089,32 @@ struct spell_desc
 },
 
 {
+    SPELL_SHAFT_SELF, "Shaft Self",
+     SPTYP_EARTH,
+     SPFLAG_ESCAPE,
+     1,
+     0,
+     -1, -1,
+     100,
+     NULL,
+     false,
+     true
+},
+
+{
+    SPELL_MASS_CURE_POISON, "Mass Cure Poison",
+     SPTYP_POISON,
+     SPFLAG_AREA,
+     1,
+     0,
+     -1, -1,
+     0,
+     NULL,
+     false,
+     true
+},
+
+{
     SPELL_NO_SPELL, "nonexistent spell",
      0,
      SPFLAG_TESTING,
diff --git a/crawl-ref/source/stairs.cc b/crawl-ref/source/stairs.cc
index 3195801..205e9d7 100644
--- a/crawl-ref/source/stairs.cc
+++ b/crawl-ref/source/stairs.cc
@@ -668,8 +668,8 @@ void down_stairs(dungeon_feature_type force_stair)
     }
 
     // Only check the current position for a legal stair traverse.
-    // If it's a known shaft that we're taking, then we're already good.
-    if (!known_shaft && !_check_stairs(stair_find, true))
+    // If it's a shaft that we're taking, then we're already good.
+    if (!shaft && !_check_stairs(stair_find, true))
         return;
 
     if (_stair_moves_pre(stair_find))
diff --git a/crawl-ref/source/throw.cc b/crawl-ref/source/throw.cc
index ff89c3a..8f80b45 100644
--- a/crawl-ref/source/throw.cc
+++ b/crawl-ref/source/throw.cc
@@ -487,7 +487,7 @@ static int _launcher_shield_slowdown(const item_def &launcher,
                                      const item_def *shield)
 {
     int speed_adjust = 100;
-    if (!shield || hands_reqd(launcher, you.body_size()) == HANDS_ONE)
+    if (!shield || you.hands_reqd(launcher) == HANDS_ONE)
         return speed_adjust;
 
     const int shield_type = shield->sub_type;
@@ -1855,7 +1855,7 @@ bool throw_it(bolt &pbolt, int throw_2, bool teleport, int acc_bonus,
 
             // Dwarves/orcs with dwarven/orcish weapons.
             if (get_equip_race(item) == ISFLAG_DWARVEN
-                   && you.species == SP_DEEP_DWARF
+                   && (you.species == SP_DEEP_DWARF)
                 || get_equip_race(item) == ISFLAG_ORCISH
                    && you.species == SP_HILL_ORC)
             {
diff --git a/crawl-ref/source/tilepick-p.cc b/crawl-ref/source/tilepick-p.cc
index 80bab0a..9cf3e7b 100644
--- a/crawl-ref/source/tilepick-p.cc
+++ b/crawl-ref/source/tilepick-p.cc
@@ -676,6 +676,8 @@ tileidx_t tilep_species_to_base_tile(int sp, int level)
         return TILEP_BASE_OCTOPODE;
     case SP_DJINNI:
         return TILEP_BASE_DJINNI;
+    case SP_FORMICID:
+        return TILEP_BASE_FORMICID;
     default:
         return TILEP_BASE_HUMAN;
     }
@@ -804,6 +806,22 @@ void tilep_race_default(int sp, int level, dolls_data *doll)
             hair = 0;
             beard = TILEP_BEARD_MEDIUM_GREEN;
             break;
+        case SP_FORMICID:
+            hair = 0;
+            // Three levels of antennae retraction
+            // and one with no antennae.
+            if (player_wearing_slot(EQ_HELMET))
+            {
+                result = TILEP_BASE_FORMICID;
+            }
+            else
+            {
+                result = TILEP_BASE_FORMICID
+                        + ((you.duration[DUR_ANTENNAE_EXTEND] 
+                            * player_mutation_level(MUT_ANTENNAE))
+                           / ANTENNAE_EXTEND_TIME);
+            }
+            break;
         default:
             // nothing to do
             break;
diff --git a/crawl-ref/source/transform.cc b/crawl-ref/source/transform.cc
index aeb15dc..0958997 100644
--- a/crawl-ref/source/transform.cc
+++ b/crawl-ref/source/transform.cc
@@ -300,7 +300,7 @@ static bool _mutations_prevent_wearing(const item_def& item)
 
     if (is_hard_helmet(item)
         && (player_mutation_level(MUT_HORNS)
-            || player_mutation_level(MUT_ANTENNAE)
+            || (player_mutation_level(MUT_ANTENNAE) && you.species != SP_FORMICID)
             || player_mutation_level(MUT_BEAK)))
     {
         return true;
@@ -318,7 +318,8 @@ static bool _mutations_prevent_wearing(const item_def& item)
         return true;
 
     if (eqslot == EQ_HELMET && (player_mutation_level(MUT_HORNS) == 3
-        || player_mutation_level(MUT_ANTENNAE) == 3))
+        || (player_mutation_level(MUT_ANTENNAE) == 3)
+            && you.species != SP_FORMICID))
     {
         return true;
     }
diff --git a/crawl-ref/source/wiz-you.cc b/crawl-ref/source/wiz-you.cc
index 096893e..f70db3c 100644
--- a/crawl-ref/source/wiz-you.cc
+++ b/crawl-ref/source/wiz-you.cc
@@ -814,6 +814,7 @@ static const char* dur_names[] =
     "weak",
     "dimension anchor",
     "antimagic",
+    "antennae extend",
 };
 
 void wizard_edit_durations(void)
-- 
1.8.2.3

