diff options
author | j-p-e-g <j-p-e-g@c06c8d41-db1a-0410-9941-cceddc491573> | 2009-09-22 23:45:08 +0000 |
---|---|---|
committer | j-p-e-g <j-p-e-g@c06c8d41-db1a-0410-9941-cceddc491573> | 2009-09-22 23:45:08 +0000 |
commit | fd8a1db3054ba396dcb149898891d739a06e4fac (patch) | |
tree | 5b1ff087345c2576eb2f281323addb2829bfe1c9 /crawl-ref/source | |
parent | 342644a1df21f8426a0786b114833342847784cd (diff) | |
download | crawl-ref-fd8a1db3054ba396dcb149898891d739a06e4fac.tar.gz crawl-ref-fd8a1db3054ba396dcb149898891d739a06e4fac.zip |
Implement another new unique, this time of my own coding: Maurice the thief.
Equipment: a cloak, a dagger or short sword, and some gold.
Spells : Blink, Invisibility, Teleport Self
Most importantly, in melee combat Maurice will try to steal items from
the player. Due to technical limitations he can only steal item types
monsters can carry and only if said item slot is still free. All
applicable items get weighted by item value, and if nothing is
applicable he will steal some gold instead. If even that isn't possible,
he'll complain a bit and teleport away.
Maurice is placed in the same depth as Gastronok. He's not actually
hard (except for the occasional weapon brand or wand), but rather
annoying. :p
Stealing from monsters hasn't been implemented, and I don't think it's
as interesting. Maurice is currently prevented from stealing items the
player has equipped, though I'm considering allowing him to steal a
wielded weapon, at least.
The limitations of monsters' inventories means that Maurice will never
attempt to steal armour (slot already filled) or jewellery (missing
slot). Maybe we could try to force valuable items into inappropriate but
rarely used slots, e.g. MSLOT_MISC.
Other than in the FR (see 2838375) Maurice does not disappear from the
level, so you can still hunt him down. He also doesn't get a crossbow or
blowgun yet, though that's an interesting idea. However, handing out a
secondary weapon would mean that he couldn't steal weapons either.
Doesn't have a tile yet, and I have no image of him in my head either.
git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@10776 c06c8d41-db1a-0410-9941-cceddc491573
Diffstat (limited to 'crawl-ref/source')
-rw-r--r-- | crawl-ref/source/dat/database/monspeak.txt | 49 | ||||
-rw-r--r-- | crawl-ref/source/dat/descript/monsters.txt | 4 | ||||
-rw-r--r-- | crawl-ref/source/debug.cc | 1 | ||||
-rw-r--r-- | crawl-ref/source/dungeon.cc | 5 | ||||
-rw-r--r-- | crawl-ref/source/enum.h | 4 | ||||
-rw-r--r-- | crawl-ref/source/fight.cc | 159 | ||||
-rw-r--r-- | crawl-ref/source/makeitem.cc | 47 | ||||
-rw-r--r-- | crawl-ref/source/mon-data.h | 11 | ||||
-rw-r--r-- | crawl-ref/source/mon-spll.h | 12 | ||||
-rw-r--r-- | crawl-ref/source/mon-util.cc | 8 | ||||
-rw-r--r-- | crawl-ref/source/mon-util.h | 1 | ||||
-rw-r--r-- | crawl-ref/source/monstuff.cc | 2 | ||||
-rw-r--r-- | crawl-ref/source/shopping.cc | 4 |
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) |