summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source
diff options
context:
space:
mode:
Diffstat (limited to 'crawl-ref/source')
-rw-r--r--crawl-ref/source/dat/database/monspeak.txt49
-rw-r--r--crawl-ref/source/dat/descript/monsters.txt4
-rw-r--r--crawl-ref/source/debug.cc1
-rw-r--r--crawl-ref/source/dungeon.cc5
-rw-r--r--crawl-ref/source/enum.h4
-rw-r--r--crawl-ref/source/fight.cc159
-rw-r--r--crawl-ref/source/makeitem.cc47
-rw-r--r--crawl-ref/source/mon-data.h11
-rw-r--r--crawl-ref/source/mon-spll.h12
-rw-r--r--crawl-ref/source/mon-util.cc8
-rw-r--r--crawl-ref/source/mon-util.h1
-rw-r--r--crawl-ref/source/monstuff.cc2
-rw-r--r--crawl-ref/source/shopping.cc4
13 files changed, 286 insertions, 21 deletions
diff --git a/crawl-ref/source/dat/database/monspeak.txt b/crawl-ref/source/dat/database/monspeak.txt
index d6285ef88c..9056c2d759 100644
--- a/crawl-ref/source/dat/database/monspeak.txt
+++ b/crawl-ref/source/dat/database/monspeak.txt
@@ -2138,6 +2138,55 @@ _Maud_rare_
## END Maud ##
%%%%
+############ MAURICE ### A thief.
+Maurice
+
+@_Maurice_common_@
+
+w:6
+@_Maurice_medium_@
+
+w:2
+@_Maurice_rare_@
+%%%%
+_Maurice_common_
+
+VISUAL:@The_monster@ tries to hide in the shadows.
+
+@The_monster@ shouts, "HAHA!"
+
+@The_monster@ says, "Nice gear. Can I borrow some?"
+
+@The_monster@ shouts, "Mine, all mine!"
+
+%%%%
+_Maurice_medium_
+
+VISUAL:@The_monster@ looks sneaky.
+
+@The_monster@ says, "Lost something?"
+
+@The_monster@ says, "Very interesting."
+
+@The_monster@ says, "Have you got some gold to spare?"
+%%%%
+_Maurice_rare_
+
+@The_monster@ says, "Betcha didn't see that coming, eh?"
+
+@The_monster@ says to @foe@, "Money or life? Never mind, I think I'll take both."
+
+@The_monster@ says, "Killing adventurers and taking their stuff. It's what I do."
+%%%%
+# Triggered when Maurice tries to steal something, but doesn't find anything.
+Maurice nonstealing
+
+@The_monster@ grunts, "Curses!"
+
+@The_monster@ mutters, "Now where did you hide it?"
+
+@The_monster@ groans, "What are you, a monk?"
+%%%%
############ MENKAURE ### A mummy whose rest you've disturbed
Menkaure
diff --git a/crawl-ref/source/dat/descript/monsters.txt b/crawl-ref/source/dat/descript/monsters.txt
index 8e1b566dd0..e457220656 100644
--- a/crawl-ref/source/dat/descript/monsters.txt
+++ b/crawl-ref/source/dat/descript/monsters.txt
@@ -216,6 +216,10 @@ Maud
A mysterious warrior princess from a far-off kingdom, on a quest to retrieve the legendary sword 'Entarex'. Countless have been the admirers who, thinking about Maud, forgot everything else.
%%%%
+Maurice
+
+A sly, conniving thief
+%%%%
Michael
A powerful spellcaster, dressed in a long robe.
diff --git a/crawl-ref/source/debug.cc b/crawl-ref/source/debug.cc
index 72c2e356a6..55a6068257 100644
--- a/crawl-ref/source/debug.cc
+++ b/crawl-ref/source/debug.cc
@@ -5545,6 +5545,7 @@ void wizard_give_monster_item(monsters *mon)
mon->equip(mitm[old_eq], mon_slot, 1);
}
unlink_item(index);
+ destroy_item(item);
return;
}
diff --git a/crawl-ref/source/dungeon.cc b/crawl-ref/source/dungeon.cc
index ae86128d50..5d8842a95e 100644
--- a/crawl-ref/source/dungeon.cc
+++ b/crawl-ref/source/dungeon.cc
@@ -3304,13 +3304,14 @@ static monster_type _choose_unique_by_depth(int step)
case 2: // depth <= 9
ret = random_choose(MONS_BLORK_THE_ORC, MONS_EDMUND, MONS_PSYCHE,
MONS_EROLCHA, MONS_PRINCE_RIBBIT, MONS_GRUM,
- MONS_GASTRONOK, -1);
+ MONS_GASTRONOK, MONS_MAURICE, -1);
break;
case 3: // depth <= 13
ret = random_choose(MONS_PSYCHE, MONS_EROLCHA, MONS_DONALD, MONS_URUG,
MONS_MICHAEL, MONS_EUSTACHIO, MONS_SONJA, MONS_GRUM,
MONS_JOSEPH, MONS_ERICA, MONS_JOSEPHINE, MONS_JOZEF,
- MONS_HAROLD, MONS_NORBERT, MONS_GASTRONOK, -1);
+ MONS_HAROLD, MONS_NORBERT, MONS_GASTRONOK,
+ MONS_MAURICE, -1);
break;
case 4: // depth <= 16
ret = random_choose(MONS_URUG, MONS_MICHAEL, MONS_EUSTACHIO, MONS_SONJA,
diff --git a/crawl-ref/source/enum.h b/crawl-ref/source/enum.h
index a4d91768b2..f8fa4f225c 100644
--- a/crawl-ref/source/enum.h
+++ b/crawl-ref/source/enum.h
@@ -2082,9 +2082,10 @@ enum monster_type // (int) menv[].type
MONS_GRUM,
MONS_PURGY,
MONS_MENKAURE,
- MONS_DUVESSA,
+ MONS_DUVESSA, // 465
MONS_DOWAN,
MONS_GASTRONOK,
+ MONS_MAURICE,
// Testing monsters
MONS_TEST_SPAWNER,
@@ -2307,6 +2308,7 @@ enum mon_spellbook_type
MST_JESSICA,
MST_BERSERK_ESCAPE, // 165
MST_GASTRONOK,
+ MST_MAURICE,
MST_TEST_SPAWNER = 170,
NUM_MSTYPES,
diff --git a/crawl-ref/source/fight.cc b/crawl-ref/source/fight.cc
index c7df516e7c..35a7a34926 100644
--- a/crawl-ref/source/fight.cc
+++ b/crawl-ref/source/fight.cc
@@ -49,6 +49,7 @@ REVISION("$Rev$");
#include "ouch.h"
#include "player.h"
#include "religion.h"
+#include "shopping.h"
#include "skills.h"
#include "spells1.h"
#include "spells3.h"
@@ -4508,6 +4509,150 @@ void melee_attack::splash_defender_with_acid(int strength)
splash_monster_with_acid(strength);
}
+static void _steal_item_from_player(monsters *mon)
+{
+ int steal_what = -1;
+ int total_value = 0;
+ for (int m = 0; m < ENDOFPACK; ++m)
+ {
+ if (!is_valid_item(you.inv[m]))
+ continue;
+
+ // Cannot unequip player.
+ // TODO: Allow stealing of the wielded weapon?
+ // Needs to be unwielded properly and should never lead to
+ // fatal stat loss.
+ if (item_is_equipped(you.inv[m]))
+ continue;
+
+ mon_inv_type monslot = item_to_mslot(you.inv[m]);
+ if (monslot == NUM_MONSTER_SLOTS)
+ continue;
+
+ // Only try to steal stuff we can still store somewhere.
+ if (mon->inv[monslot] != NON_ITEM)
+ {
+ if (monslot == MSLOT_WEAPON
+ && mon->inv[MSLOT_ALT_WEAPON] == NON_ITEM)
+ {
+ monslot = MSLOT_ALT_WEAPON;
+ }
+ else
+ continue;
+ }
+
+ // Candidate for stealing.
+ const int value = item_value(you.inv[m], true);
+ total_value += value;
+
+ if (x_chance_in_y(value, total_value))
+ steal_what = m;
+ }
+
+ if (steal_what == -1 || you.gold > 0 && one_chance_in(10))
+ {
+ // Found no item worth stealing, try gold.
+ if (you.gold == 0)
+ {
+ if (silenced(mon->pos()))
+ return;
+
+ std::string complaint = getSpeakString("Maurice nonstealing");
+ if (!complaint.empty())
+ {
+ complaint = replace_all(complaint, "@The_monster@",
+ mon->name(DESC_CAP_THE));
+ mpr(complaint.c_str(), MSGCH_TALK);
+ }
+
+ bolt beem;
+ beem.source = mon->pos();
+ beem.target = mon->pos();
+ beem.beam_source = mon->mindex();
+
+ // Try to teleport away.
+ if (mon->has_ench(ENCH_TP))
+ {
+ mons_cast_noise(mon, beem, SPELL_BLINK);
+ monster_blink(mon);
+ }
+ else
+ mons_cast(mon, beem, SPELL_TELEPORT_SELF);
+
+ return;
+ }
+
+ const int stolen_amount = std::min(20 + random2(800), you.gold);
+ if (mon->inv[MSLOT_GOLD] != NON_ITEM)
+ {
+ // If Maurice already's got some gold, simply increase the amount.
+ mitm[mon->inv[MSLOT_GOLD]].quantity += stolen_amount;
+ }
+ else
+ {
+ // Else create a new item for this pile of gold.
+ const int idx = items(0, OBJ_GOLD, OBJ_RANDOM, true, 0, 0);
+ if (idx == NON_ITEM)
+ return;
+
+ item_def &new_item = mitm[idx];
+ new_item.base_type = OBJ_GOLD;
+ new_item.sub_type = 0;
+ new_item.plus = 0;
+ new_item.plus2 = 0;
+ new_item.special = 0;
+ new_item.flags = 0;
+ new_item.link = NON_ITEM;
+ new_item.quantity = stolen_amount;
+ new_item.pos.reset();
+ item_colour(new_item);
+
+ unlink_item(idx);
+
+ mon->inv[MSLOT_GOLD] = idx;
+ new_item.set_holding_monster(mon->mindex());
+ }
+ mprf("%s steals %s your gold!",
+ mon->name(DESC_CAP_THE).c_str(),
+ stolen_amount == you.gold ? "all" : "some of");
+
+ you.attribute[ATTR_GOLD_FOUND] -= stolen_amount;
+ you.gold -= stolen_amount;
+ return;
+ }
+
+ ASSERT(steal_what != -1);
+
+ // Create new item.
+ int index = get_item_slot(10);
+ if (index == NON_ITEM)
+ return;
+
+ item_def &new_item = mitm[index];
+
+ // Copy item.
+ new_item = you.inv[steal_what];
+
+ // Set quantity, and set the item as unlinked.
+ new_item.quantity -= random2(new_item.quantity);
+ new_item.pos.reset();
+ new_item.link = NON_ITEM;
+
+ const mon_inv_type mslot = item_to_mslot(new_item);
+
+ mprf("%s steals %s!",
+ mon->name(DESC_CAP_THE).c_str(),
+ new_item.name(DESC_NOCAP_YOUR).c_str());
+
+ unlink_item(index);
+ mon->inv[mslot] = index;
+ new_item.set_holding_monster(mon->mindex());
+ mon->equip(new_item, mslot, true);
+
+ // Item is gone from player's inventory.
+ dec_inv_item_quantity(steal_what, new_item.quantity);
+}
+
void melee_attack::mons_apply_attack_flavour(const mon_attack_def &attk)
{
// Most of this is from BWR 4.1.2.
@@ -4764,6 +4909,14 @@ void melee_attack::mons_apply_attack_flavour(const mon_attack_def &attk)
chaos_affects_defender();
break;
+ case AF_STEAL:
+ // Ignore monsters, for now.
+ if (defender->atype() != ACT_PLAYER)
+ break;
+
+ _steal_item_from_player(attacker_as_monster());
+ break;
+
case AF_STEAL_FOOD:
// Monsters don't carry food.
if (defender->atype() != ACT_PLAYER)
@@ -4918,7 +5071,8 @@ void melee_attack::mons_perform_attack_rounds()
// Monsters attacking themselves don't get attack flavour.
// The message sequences look too weird.
- if (attacker != defender)
+ // Also, stealing attacks aren't handled until after the damage msg.
+ if (attacker != defender && attk.flavour != AF_STEAL)
mons_apply_attack_flavour(attk);
if (!special_damage_message.empty())
@@ -5005,6 +5159,9 @@ void melee_attack::mons_perform_attack_rounds()
// Miscast might have killed the attacker.
if (!attacker->alive())
break;
+
+ if (attk.flavour == AF_STEAL)
+ mons_apply_attack_flavour(attk);
}
item_def *weap = attacker_as_monster()->mslot_item(MSLOT_WEAPON);
diff --git a/crawl-ref/source/makeitem.cc b/crawl-ref/source/makeitem.cc
index 047dec0917..1ce351d738 100644
--- a/crawl-ref/source/makeitem.cc
+++ b/crawl-ref/source/makeitem.cc
@@ -3456,7 +3456,7 @@ static item_make_species_type _give_weapon(monsters *mon, int level,
if (!melee_only && one_chance_in(9))
{
item.base_type = OBJ_WEAPONS;
- item.sub_type = WPN_CROSSBOW;
+ item.sub_type = WPN_CROSSBOW;
break;
}
// deliberate fall-through
@@ -3748,7 +3748,7 @@ static item_make_species_type _give_weapon(monsters *mon, int level,
case MONS_AGNES:
item.base_type = OBJ_WEAPONS;
- item.sub_type = WPN_LAJATANG;
+ item.sub_type = WPN_LAJATANG;
if (!one_chance_in(3))
level = MAKE_GOOD_ITEM;
break;
@@ -3762,9 +3762,9 @@ static item_make_species_type _give_weapon(monsters *mon, int level,
break;
}
force_item = true;
- item_race = MAKE_ITEM_NO_RACE;
+ item_race = MAKE_ITEM_NO_RACE;
item.base_type = OBJ_WEAPONS;
- item.sub_type = coinflip() ? WPN_DAGGER : WPN_SHORT_SWORD;
+ item.sub_type = coinflip() ? WPN_DAGGER : WPN_SHORT_SWORD;
set_item_ego_type(item, OBJ_WEAPONS,
random_choose_weighted(3, SPWPN_DISTORTION,
2, SPWPN_VENOM,
@@ -3772,10 +3772,16 @@ static item_make_species_type _give_weapon(monsters *mon, int level,
0));
break;
+ case MONS_MAURICE:
+ item_race = MAKE_ITEM_NO_RACE;
+ item.base_type = OBJ_WEAPONS;
+ item.sub_type = coinflip() ? WPN_DAGGER : WPN_SHORT_SWORD;
+ break;
+
case MONS_EUSTACHIO:
item_race = MAKE_ITEM_NO_RACE;
item.base_type = OBJ_WEAPONS;
- item.sub_type = (one_chance_in(3) ? WPN_FALCHION : WPN_SABRE);
+ item.sub_type = (one_chance_in(3) ? WPN_FALCHION : WPN_SABRE);
break;
case MONS_CEREBOV:
@@ -4329,8 +4335,16 @@ void give_armour(monsters *mon, int level)
item.sub_type = ARM_WIZARD_HAT;
break;
+ case MONS_MAURICE:
+ item_race = MAKE_ITEM_NO_RACE;
+ item.base_type = OBJ_ARMOUR;
+ item.sub_type = ARM_CLOAK;
+ force_colour = DARKGREY;
+ break;
+
case MONS_DOWAN:
item_race = MAKE_ITEM_ELVEN;
+ // intentional fall-through
case MONS_DONALD:
case MONS_JESSICA:
case MONS_KOBOLD_DEMONOLOGIST:
@@ -4357,13 +4371,13 @@ void give_armour(monsters *mon, int level)
if (item_race == MAKE_ITEM_RANDOM_RACE)
item_race = MAKE_ITEM_NO_RACE;
item.base_type = OBJ_ARMOUR;
- item.sub_type = ARM_ROBE;
+ item.sub_type = ARM_ROBE;
break;
case MONS_TIAMAT:
item_race = MAKE_ITEM_NO_RACE;
item.base_type = OBJ_ARMOUR;
- item.sub_type = ARM_GOLD_DRAGON_ARMOUR;
+ item.sub_type = ARM_GOLD_DRAGON_ARMOUR;
break;
case MONS_ORC_WIZARD:
@@ -4371,7 +4385,7 @@ void give_armour(monsters *mon, int level)
case MONS_NERGALLE:
item_race = MAKE_ITEM_ORCISH;
item.base_type = OBJ_ARMOUR;
- item.sub_type = ARM_ROBE;
+ item.sub_type = ARM_ROBE;
break;
case MONS_BORIS:
@@ -4383,8 +4397,8 @@ void give_armour(monsters *mon, int level)
case MONS_NECROMANCER:
case MONS_VAMPIRE_MAGE:
item.base_type = OBJ_ARMOUR;
- item.sub_type = ARM_ROBE;
- force_colour = DARKGREY; //mv: always darkgrey
+ item.sub_type = ARM_ROBE;
+ force_colour = DARKGREY; //mv: always darkgrey
break;
case MONS_EUSTACHIO:
@@ -4396,8 +4410,8 @@ void give_armour(monsters *mon, int level)
case MONS_NESSOS:
item_race = MAKE_ITEM_NO_RACE;
item.base_type = OBJ_ARMOUR;
- item.sub_type = ARM_CENTAUR_BARDING;
- force_colour = DARKGREY;
+ item.sub_type = ARM_CENTAUR_BARDING;
+ force_colour = DARKGREY;
break;
default:
@@ -4427,10 +4441,19 @@ void give_armour(monsters *mon, int level)
mitm[thing_created].colour = force_colour;
}
+static void _give_gold(monsters *mon, int level)
+{
+ const int idx = items(0, OBJ_GOLD, 0, true, level, 0);
+ _give_monster_item(mon, idx);
+}
+
void give_item(int mid, int level_number, bool mons_summoned)
{
monsters *mons = &menv[mid];
+ if (mons->type == MONS_MAURICE)
+ _give_gold(mons, level_number);
+
_give_scroll(mons, level_number);
_give_wand(mons, level_number);
_give_potion(mons, level_number);
diff --git a/crawl-ref/source/mon-data.h b/crawl-ref/source/mon-data.h
index 1bfb0fc92f..6cc1464014 100644
--- a/crawl-ref/source/mon-data.h
+++ b/crawl-ref/source/mon-data.h
@@ -4549,6 +4549,17 @@ static monsterentry mondata[] = {
HT_LAND, 10, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, MONEAT_NOTHING, SIZE_MEDIUM
},
+{
+ MONS_MAURICE, '@', DARKGREY, "Maurice",
+ M_UNIQUE | M_SPELLCASTER | M_ACTUAL_SPELLS | M_WARM_BLOOD | M_SPEAKS,
+ MR_NO_FLAGS,
+ 550, 20, MONS_HUMAN, MONS_HUMAN, MH_NATURAL, -4,
+ { {AT_HIT, AF_STEAL, 9}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK },
+ { 5, 0, 0, 60 },
+ 1, 13, MST_MAURICE, CE_CONTAMINATED, Z_NOZOMBIE, S_SHOUT, I_HIGH,
+ HT_LAND, 11, DEFAULT_ENERGY, MONUSE_WEAPONS_ARMOUR, MONEAT_NOTHING, SIZE_MEDIUM
+},
+
// unique major demons ('&')
{
MONS_MNOLEG, '&', LIGHTGREEN, "Mnoleg",
diff --git a/crawl-ref/source/mon-spll.h b/crawl-ref/source/mon-spll.h
index 559d56b8da..4a7af5cff0 100644
--- a/crawl-ref/source/mon-spll.h
+++ b/crawl-ref/source/mon-spll.h
@@ -1112,6 +1112,18 @@
}
},
+ { MST_MAURICE,
+ {
+ SPELL_NO_SPELL,
+ SPELL_NO_SPELL,
+ SPELL_INVISIBILITY,
+ SPELL_BLINK,
+ SPELL_NO_SPELL,
+ SPELL_TELEPORT_SELF,
+ }
+ },
+
+
// demon lords
{ MST_GERYON,
{
diff --git a/crawl-ref/source/mon-util.cc b/crawl-ref/source/mon-util.cc
index 50ef978332..28455a09f1 100644
--- a/crawl-ref/source/mon-util.cc
+++ b/crawl-ref/source/mon-util.cc
@@ -4999,7 +4999,7 @@ bool monsters::pickup_armour(item_def &item, int near, bool force)
equipment_type eq = EQ_NONE;
- // Hack to allow nagas/centaurs to wear bardings. (jpeg)
+ // HACK to allow nagas/centaurs to wear bardings. (jpeg)
switch (item.sub_type)
{
case ARM_NAGA_BARDING:
@@ -5013,11 +5013,15 @@ bool monsters::pickup_armour(item_def &item, int near, bool force)
eq = EQ_BODY_ARMOUR;
}
break;
+ // And another hack or two...
case ARM_WIZARD_HAT:
- // HACK.
if (this->type == MONS_GASTRONOK)
eq = EQ_BODY_ARMOUR;
break;
+ case ARM_CLOAK:
+ if (this->type == MONS_MAURICE)
+ eq = EQ_BODY_ARMOUR;
+ break;
default:
eq = get_armour_slot(item);
}
diff --git a/crawl-ref/source/mon-util.h b/crawl-ref/source/mon-util.h
index 1754e1bd67..16cfbf78c6 100644
--- a/crawl-ref/source/mon-util.h
+++ b/crawl-ref/source/mon-util.h
@@ -83,6 +83,7 @@ enum mon_attack_flavour
AF_RAGE,
AF_NAPALM,
AF_CHAOS,
+ AF_STEAL,
AF_STEAL_FOOD
};
diff --git a/crawl-ref/source/monstuff.cc b/crawl-ref/source/monstuff.cc
index 1cca39083e..097c6b6737 100644
--- a/crawl-ref/source/monstuff.cc
+++ b/crawl-ref/source/monstuff.cc
@@ -6967,7 +6967,7 @@ static bool _handle_spell(monsters *monster, bolt &beem)
spellOK = false;
}
else if (monster->type == MONS_DAEVA
- && monster->god == GOD_SHINING_ONE)
+ && monster->god == GOD_SHINING_ONE)
{
const monsters *mon = &menv[monster->foe];
diff --git a/crawl-ref/source/shopping.cc b/crawl-ref/source/shopping.cc
index dfcdd0306a..51dccf3f4f 100644
--- a/crawl-ref/source/shopping.cc
+++ b/crawl-ref/source/shopping.cc
@@ -632,8 +632,8 @@ unsigned int item_value( item_def item, bool ident )
// copy to mangle as necessary.
item.flags = (ident) ? (item.flags | ISFLAG_IDENT_MASK) : (item.flags);
- if (is_unrandom_artefact( item ) &&
- item_ident( item, ISFLAG_KNOW_PROPERTIES ))
+ if (is_unrandom_artefact( item )
+ && item_ident( item, ISFLAG_KNOW_PROPERTIES ))
{
const unrandart_entry *entry = get_unrand_entry(item.special);
if (entry->value != 0)