From 29858cdb83147c14b3c0d9c2170515d7963174d6 Mon Sep 17 00:00:00 2001
From: wheals <shm.mark@gmail.com>
Date: Sun, 26 Jan 2014 00:23:09 -0500
Subject: [PATCH] A felid unique, Natasha.

She is the familiar of a lost mage who wandered into the dungeon in search of
the orb. She's effectively a XL3 FeWz, though I'm not sure if one could
actually get all the spell slots she does. As you might guess, she comes back
to life after she dies, losing 1 HD each time (blame Grunt for that idea).

This fixes a bug where felids were speed 11 instead of 12.
---
 crawl-ref/source/dat/database/monspeak.txt   | 75 ++++++++++++++++++++++++++++
 crawl-ref/source/dat/des/builder/uniques.des |  4 ++
 crawl-ref/source/dat/descript/monsters.txt   |  6 +++
 crawl-ref/source/enum.h                      |  2 +
 crawl-ref/source/mon-data.h                  | 16 +++++-
 crawl-ref/source/mon-speak.cc                |  4 ++
 crawl-ref/source/mon-spll.h                  | 11 ++++
 crawl-ref/source/mon-stuff.cc                | 35 +++++++++++++
 crawl-ref/source/mon-util.cc                 |  1 +
 9 files changed, 153 insertions(+), 1 deletion(-)

diff --git a/crawl-ref/source/dat/database/monspeak.txt b/crawl-ref/source/dat/database/monspeak.txt
index 0d9d3f0..595db63 100644
--- a/crawl-ref/source/dat/database/monspeak.txt
+++ b/crawl-ref/source/dat/database/monspeak.txt
@@ -5126,6 +5126,81 @@ VISUAL:@The_monster@ seems to say something.
 VISUAL:@The_monster@ says something you can't hear. It was probably not a compliment. @player_only@
 ## END silenced Murray ##
 %%%%
+############ NATASHA ### An abandoned felid familiar.
+Natasha
+
+@_Natasha_common_@
+
+w:5
+@_Natasha_rare_@
+%%%%
+_Natasha_common_
+
+VISUAL SPELL:@The_monster@ stares at you.
+@_visual_fake_spell_effect_@
+
+SPELL:@The_monster@ casts a spell.
+@_warn_fake_spell_effect_@
+
+VISUAL SPELL:@The_monster@ gestures.
+@_warn_fake_spell_effect_@
+%%%%
+_visual_fake_spell_effect_
+
+VISUAL WARN:You feel disoriented.
+
+VISUAL WARN:You feel troubled.
+%%%%
+_warn_fake_spell_effect_
+
+WARN:Suddenly you are surrounded with a pale green light. @player_only@
+
+WARN:You have a terrible headache.
+%%%%
+_Natasha_rare_
+
+@The_monster@ hisses @at_foe@.
+
+@The_monster@ growls @at_foe@.
+
+@The_monster@ mewls in sadness.
+
+VISUAL:@The_monster@ extends @possessive@ claws.
+%%%%
+friendly Natasha
+
+@The_monster@ meows.
+
+@The_monster@ purrs.
+%%%%
+Natasha killed
+
+@_Natasha_death_common_@
+
+w:1
+@_Natasha_death_rare_@
+%%%%
+_Natasha_death_common_
+
+@The_monster@ screams in fury as @subjective@ dies!
+
+@The_monster@ screams in pain as @subjective@ dies!
+
+@The_monster@ growls in agony!
+%%%%
+_Natasha_death_rare_
+Suddenly @the_monster@'s spirit rises from its lifeless body.
+
+Moaning pathetically, @the_monster@'s spirit plunges in to the ground.
+
+You hear a faint echoing roar filled with hate and sorrow!
+
+%%%%
+Natasha permanently killed
+
+You feel @the_monster@'s spirit has finally been put to rest.
+%%%%
+############ NELLIE ### An escaped circus (h)elephant.
 Nellie
 
 @_Nellie_common_@
diff --git a/crawl-ref/source/dat/des/builder/uniques.des b/crawl-ref/source/dat/des/builder/uniques.des
index d88c4e4..f6434a5 100644
--- a/crawl-ref/source/dat/des/builder/uniques.des
+++ b/crawl-ref/source/dat/des/builder/uniques.des
@@ -229,6 +229,10 @@ NAME:   uniq_menkaure
 DEPTH:  D:4-7
 : place_unique(_G, "Menkaure")
 
+NAME:   uniq_natasha
+DEPTH:  D:3-6
+: place_unique(_G, "Natasha")
+
 NAME:   uniq_nergalle
 DEPTH:  D:10-, Orc:2-, Elf:1, Lair
 : place_unique(_G, "Nergalle")
diff --git a/crawl-ref/source/dat/descript/monsters.txt b/crawl-ref/source/dat/descript/monsters.txt
index 8f4078e..6915207 100644
--- a/crawl-ref/source/dat/descript/monsters.txt
+++ b/crawl-ref/source/dat/descript/monsters.txt
@@ -369,6 +369,12 @@ Murray
 
 A demonic skull rolling along the dungeon floor.
 %%%%
+Natasha
+
+A cute little cat. But wait! there's an intelligence behind those eyes, and a
+sorrow that speaks to a lost love one. Perhaps she was a familiar to a powerful
+mage who entered the Dungeon to seek the Orb, and trying to find her master?
+%%%%
 Nellie
 
 A highly intelligent elephant who travelled as part of a circus. One dark
diff --git a/crawl-ref/source/enum.h b/crawl-ref/source/enum.h
index 953997e..eaa2959 100644
--- a/crawl-ref/source/enum.h
+++ b/crawl-ref/source/enum.h
@@ -2844,6 +2844,8 @@ enum monster_type                      // menv[].type
     MONS_SNAKE,                 // genus
 #endif
 
+    MONS_NATASHA,
+
     NUM_MONSTERS,               // used for polymorph
 
     // MONS_NO_MONSTER can get put in savefiles, so it shouldn't change
diff --git a/crawl-ref/source/mon-data.h b/crawl-ref/source/mon-data.h
index 2ea68e5..4275b4d 100644
--- a/crawl-ref/source/mon-data.h
+++ b/crawl-ref/source/mon-data.h
@@ -1086,7 +1086,7 @@ static monsterentry mondata[] =
     { {AT_CLAW, AF_PLAIN, 10}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
     { 5, 2, 3, 0 },
     2, 18, MST_NO_SPELLS, CE_CONTAMINATED, Z_SMALL, S_HISS,
-    I_HIGH, HT_LAND, FL_NONE, 11, DEFAULT_ENERGY,
+    I_HIGH, HT_LAND, FL_NONE, 12, DEFAULT_ENERGY,
     MONUSE_STARTING_EQUIPMENT, MONEAT_NOTHING, SIZE_LITTLE
 },
 
@@ -6247,6 +6247,20 @@ static monsterentry mondata[] =
     MONUSE_STARTING_EQUIPMENT, MONEAT_NOTHING, SIZE_MEDIUM
 },
 
+// "h" - carnivorous quadrupeds
+{
+    MONS_NATASHA, 'h', BLUE, "Natasha",
+    M_WARM_BLOOD | M_SPEAKS | M_UNIQUE | M_SPELLCASTER | M_ACTUAL_SPELLS
+        | M_NO_WAND,
+    MR_NO_FLAGS,
+    200, 10, MONS_FELID, MONS_FELID, MH_NATURAL, -6,
+    { {AT_CLAW, AF_PLAIN, 10}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
+    { 3, 7, 0, 0 },
+    2, 12, MST_NATASHA, CE_CONTAMINATED, Z_SMALL, S_HISS,
+    I_HIGH, HT_LAND, FL_NONE, 12, DEFAULT_ENERGY,
+    MONUSE_STARTING_EQUIPMENT, MONEAT_NOTHING, SIZE_LITTLE
+},
+
 // "H"ybrids.
 {
     MONS_ARACHNE, 'H', LIGHTCYAN, "Arachne",
diff --git a/crawl-ref/source/mon-speak.cc b/crawl-ref/source/mon-speak.cc
index 14aa0bd..f37e53f 100644
--- a/crawl-ref/source/mon-speak.cc
+++ b/crawl-ref/source/mon-speak.cc
@@ -295,7 +295,11 @@ static string _get_speak_string(const vector<string> &prefixes,
 {
     int duration = 1;
     if (mons->hit_points <= 0)
+    {
+        if (mons->type == MONS_NATASHA && mons->hit_dice == 1) //let her have separate death/permadeath lines
+            key += " permanently";
         key += " killed";
+    }
     else if ((mons->flags & MF_BANISHED) && !player_in_branch(BRANCH_ABYSS))
         key += " banished";
     else if (mons->is_summoned(&duration) && duration <= 0)
diff --git a/crawl-ref/source/mon-spll.h b/crawl-ref/source/mon-spll.h
index b58e454..cf6b927 100644
--- a/crawl-ref/source/mon-spll.h
+++ b/crawl-ref/source/mon-spll.h
@@ -1795,6 +1795,17 @@
       }
     },
 
+    {  MST_NATASHA,
+      {
+       SPELL_MAGIC_DART,
+       SPELL_SLOW,
+       SPELL_NO_SPELL,
+       SPELL_SUMMON_MINOR_DEMON,
+       SPELL_NO_SPELL,
+       SPELL_MEPHITIC_CLOUD
+      }
+    },
+
     {  MST_THRASHING_HORROR,
       {
        SPELL_NO_SPELL,
diff --git a/crawl-ref/source/mon-stuff.cc b/crawl-ref/source/mon-stuff.cc
index 4445198..db5d4aa 100644
--- a/crawl-ref/source/mon-stuff.cc
+++ b/crawl-ref/source/mon-stuff.cc
@@ -1521,6 +1521,35 @@ static void _make_spectral_thing(monster* mons, bool quiet)
     }
 }
 
+static void _felid_revive(monster* mons)
+{
+    // Mostly adapted from bring_to_safety()
+    coord_def revive_place;
+    int tries = 0;
+    while (tries < 100) // Don't try too hard.
+    {
+        revive_place.x = random2(GXM);
+        revive_place.y = random2(GYM);
+        if (!in_bounds(revive_place)
+            || grd(revive_place) != DNGN_FLOOR
+            || env.cgrid(revive_place) != EMPTY_CLOUD
+            || monster_at(revive_place)
+            || env.pgrid(revive_place) & FPROP_NO_TELE_INTO
+            || distance2(revive_place, mons->pos()) < dist_range(10))
+        {
+            tries++;
+            continue;
+        } else {
+            break;
+        }
+    }
+
+    create_monster(
+            mgen_data(mons->type, mons->behaviour, 0, 0, 0, revive_place,
+            mons->foe, 0, mons->deity(), MONS_NO_MONSTER, 0, mons->colour,
+            PROX_ANYWHERE, level_id::current(), mons->hit_dice-1));
+}
+
 static bool _mons_reaped(actor *killer, monster* victim);
 
 static bool _reaping(monster *mons)
@@ -2478,6 +2507,12 @@ int monster_die(monster* mons, killer_type killer,
     {
         hogs_to_humans();
     }
+    else if (mons->type == MONS_NATASHA && !in_transit && mons->hit_dice > 1)
+    {
+        //Like Boris, but her vault can't come back
+        you.unique_creatures.set(mons->type, false);
+        _felid_revive(mons);
+    }
     else if (mons_is_pikel(mons))
     {
         // His slaves don't care if he's dead or not, just whether or not
diff --git a/crawl-ref/source/mon-util.cc b/crawl-ref/source/mon-util.cc
index 253853b..02bd207 100644
--- a/crawl-ref/source/mon-util.cc
+++ b/crawl-ref/source/mon-util.cc
@@ -3517,6 +3517,7 @@ static gender_type _mons_class_gender(monster_type mc)
         case MONS_THE_ENCHANTRESS:
         case MONS_NELLIE:
         case MONS_ARACHNE:
+        case MONS_NATASHA:
             gender = GENDER_FEMALE;
             break;
         case MONS_ROYAL_JELLY:
-- 
1.8.1.4

