Unlock your quest by killing your quest leader

Allow killing your quest leader, just to make games winnable if you
converted before doing the quest.
Boost the quest leaders and give them some equipment. King Arthur
gets Excalibur. Killing quest leader gives really bad luck and
makes your god angry at you, and killing quest guardians gives
smaller penalties.

This is based on both the EvilHack implementation by
k21971 <keith.simpson1971@gmail.com>, and xNetHack
implementation by copperwater <aosdict@gmail.com>.
This commit is contained in:
Pasi Kallinen
2021-05-23 08:55:58 +03:00
parent 882efdcf58
commit 20cbadcf85
21 changed files with 135 additions and 68 deletions

View File

@@ -70,7 +70,10 @@ des.door("locked",24,14)
des.door("closed",31,14) des.door("closed",31,14)
des.door("locked",49,14) des.door("locked",49,14)
-- Lord Carnarvon -- Lord Carnarvon
des.monster("Lord Carnarvon", 25, 10) des.monster({ id = "Lord Carnarvon", coord = {25, 10}, inventory = function()
des.object({ id = "fedora", spe = 5 });
des.object({ id = "bullwhip", spe = 4 });
end })
-- The treasure of Lord Carnarvon -- The treasure of Lord Carnarvon
des.object("chest", 25, 10) des.object("chest", 25, 10)
-- student guards for the audience chamber -- student guards for the audience chamber

View File

@@ -69,7 +69,10 @@ des.door("open",23,13)
des.door("open",25,10) des.door("open",25,10)
des.door("open",28,05) des.door("open",28,05)
-- Elder -- Elder
des.monster("Pelias", 10, 07) des.monster({ id = "Pelias", coord = {10, 07}, inventory = function()
des.object({ id = "runesword", spe = 5 });
des.object({ id = "chain mail", spe = 5 });
end })
-- The treasure of Pelias -- The treasure of Pelias
des.object("chest", 09, 05) des.object("chest", 09, 05)
-- chieftain guards for the audience chamber -- chieftain guards for the audience chamber

View File

@@ -54,7 +54,10 @@ des.door("locked",19,06)
-- The temple altar (this will force a priest(ess) to be created) -- The temple altar (this will force a priest(ess) to be created)
des.altar({ x=36,y=02, align="coaligned", type="shrine" }) des.altar({ x=36,y=02, align="coaligned", type="shrine" })
-- Shaman Karnov -- Shaman Karnov
des.monster("Shaman Karnov", 35, 02) des.monster({ id = "Shaman Karnov", coord = {35, 02}, inventory = function()
des.object({ id = "leather armor", spe = 5 });
des.object({ id = "club", spe = 5 });
end })
-- The treasure of Shaman Karnov -- The treasure of Shaman Karnov
des.object("chest", 34, 02) des.object("chest", 34, 02)
-- neanderthal guards for the audience chamber -- neanderthal guards for the audience chamber

View File

@@ -60,7 +60,9 @@ des.door("closed",47,08)
des.door("closed",48,12) des.door("closed",48,12)
des.door("locked",50,10) des.door("locked",50,10)
-- Hippocrates -- Hippocrates
des.monster("Hippocrates", 37, 10) des.monster({ id = "Hippocrates", coord = {37, 10}, inventory = function()
des.object({ id = "silver dagger", spe = 5 });
end })
-- The treasure of Hippocrates -- The treasure of Hippocrates
des.object("chest", 37, 10) des.object("chest", 37, 10)
-- intern guards for the audience chamber -- intern guards for the audience chamber

View File

@@ -62,7 +62,10 @@ des.door("closed",45,03)
des.door("closed",04,12) des.door("closed",04,12)
des.door("closed",45,12) des.door("closed",45,12)
-- King Arthur -- King Arthur
des.monster("King Arthur", 09, 07) des.monster({ id = "King Arthur", coord = {09, 07}, inventory = function()
des.object({ id = "long sword", spe = 4, buc = "blessed", name = "Excalibur" });
des.object({ id = "plate mail", spe = 4 });
end })
-- The treasure of King Arthur -- The treasure of King Arthur
des.object("chest", 09, 07) des.object("chest", 09, 07)
-- knight guards for the watchrooms -- knight guards for the watchrooms

View File

@@ -71,7 +71,9 @@ des.door("closed",52,14)
-- Unattended Altar - unaligned due to conflict - player must align it. -- Unattended Altar - unaligned due to conflict - player must align it.
des.altar({ x=28,y=09, align="noalign", type="altar" }) des.altar({ x=28,y=09, align="noalign", type="altar" })
-- The Grand Master -- The Grand Master
des.monster("Grand Master", 28, 10) des.monster({ id = "Grand Master", coord = {28, 10}, inventory = function()
des.object({ id = "robe", spe = 6 });
end })
-- No treasure chest! -- No treasure chest!
-- guards for the audience chamber -- guards for the audience chamber
des.monster("abbot", 32, 07) des.monster("abbot", 32, 07)

View File

@@ -71,7 +71,10 @@ des.door("closed",52,14)
-- Unattended Altar - unaligned due to conflict - player must align it. -- Unattended Altar - unaligned due to conflict - player must align it.
des.altar({ x=28, y=09, align="noalign", type="altar" }) des.altar({ x=28, y=09, align="noalign", type="altar" })
-- High Priest -- High Priest
des.monster("Arch Priest", 28, 10) des.monster({ id = "Arch Priest", coord = {28, 10}, inventory = function()
des.object({ id = "robe", spe = 4 });
des.object({ id = "mace", spe = 4 });
end })
-- The treasure of High Priest -- The treasure of High Priest
des.object("chest", 27, 10) des.object("chest", 27, 10)
-- knight guards for the audience chamber -- knight guards for the audience chamber

View File

@@ -46,7 +46,11 @@ des.stair("down", 10,10)
-- Portal arrival point; just about anywhere on the right hand side of the map -- Portal arrival point; just about anywhere on the right hand side of the map
des.levregion({ region = {51,2,77,18}, region_islev = 1, type="branch" }) des.levregion({ region = {51,2,77,18}, region_islev = 1, type="branch" })
-- Orion -- Orion
des.monster("Orion", 20, 10) des.monster({ id = "Orion", coord = {20, 10}, inventory = function()
des.object({ id = "leather armor", spe = 4 });
des.object({ id = "yumi", spe = 4 });
des.object({ id = "arrow", spe = 4, quantity = 50 });
end })
-- The treasure of Orion -- The treasure of Orion
des.object("chest", 20, 10) des.object("chest", 20, 10)
-- Guards for the audience chamber -- Guards for the audience chamber

View File

@@ -103,7 +103,11 @@ des.door("closed", 6,18)
des.door("closed", 65,18) des.door("closed", 65,18)
des.door("closed", 68,18) des.door("closed", 68,18)
-- Master of Thieves -- Master of Thieves
des.monster("Master of Thieves", 36, 11) des.monster({ id = "Master of Thieves", coord = {36, 11}, inventory = function()
des.object({ id = "leather armor", spe = 5 });
des.object({ id = "silver dagger", spe = 4 });
des.object({ id = "dagger", spe = 2, quantity = d(2,4), buc = "not-cursed" });
end })
-- The treasure of Master of Thieves -- The treasure of Master of Thieves
des.object("chest", 36, 11) des.object("chest", 36, 11)
-- thug guards, room #1 -- thug guards, room #1

View File

@@ -54,7 +54,10 @@ des.door("locked",39,08)
des.door("closed",50,04) des.door("closed",50,04)
des.door("closed",50,06) des.door("closed",50,06)
-- Lord Sato -- Lord Sato
des.monster("Lord Sato", 20, 04) des.monster({ id = "Lord Sato", coord = {20, 04}, inventory = function()
des.object({ id = "splint mail", spe = 5 });
des.object({ id = "katana", spe = 4 });
end })
-- The treasure of Lord Sato -- The treasure of Lord Sato
des.object("chest", 20, 04) des.object("chest", 20, 04)
-- roshi guards for the audience chamber -- roshi guards for the audience chamber

View File

@@ -95,7 +95,10 @@ des.monster("forest centaur")
des.monster("forest centaur") des.monster("forest centaur")
des.monster("C") des.monster("C")
-- Twoflower -- Twoflower
des.monster("Twoflower", 64, 03) des.monster({ id = "Twoflower", coord = {64, 03}, inventory = function()
des.object({ id = "walking shoes", spe = 3 });
des.object({ id = "hawaiian shirt", spe = 3 });
end })
-- The treasure of Twoflower -- The treasure of Twoflower
des.object("chest", 64, 03) des.object("chest", 64, 03)
-- guides for the audience chamber -- guides for the audience chamber

View File

@@ -61,7 +61,10 @@ des.feature("fountain", 53,02)
des.door("locked",26,10) des.door("locked",26,10)
des.door("locked",43,10) des.door("locked",43,10)
-- Norn -- Norn
des.monster("Norn", 35, 10) des.monster({ id = "Norn", coord = {35, 10}, inventory = function()
des.object({ id = "banded mail", spe = 5 });
des.object({ id = "long sword", spe = 4 });
end })
-- The treasure of the Norn -- The treasure of the Norn
des.object("chest", 36, 10) des.object("chest", 36, 10)
-- valkyrie guards for the audience chamber -- valkyrie guards for the audience chamber

View File

@@ -61,7 +61,10 @@ des.door("closed",15,10)
des.door("locked",19,10) des.door("locked",19,10)
des.door("locked",20,10) des.door("locked",20,10)
-- Neferet the Green, the quest leader -- Neferet the Green, the quest leader
des.monster("Neferet the Green", 23, 05) des.monster({ id = "Neferet the Green", coord = {23, 05}, inventory = function()
des.object({ id = "elven cloak", spe = 5 });
des.object({ id = "quarterstaff", spe = 5 });
end })
-- The treasure of the quest leader -- The treasure of the quest leader
des.object("chest", 24, 05) des.object("chest", 24, 05)
-- apprentice guards for the audience chamber -- apprentice guards for the audience chamber

View File

@@ -532,6 +532,8 @@ make anti-magic fields drain more energy and prevent them from showing up
eating magical monsters such as wizards or shamans may give a mild buzz eating magical monsters such as wizards or shamans may give a mild buzz
make exploding spheres create an actual explosion make exploding spheres create an actual explosion
pets are more careful about attacking monsters at low health pets are more careful about attacking monsters at low health
allow killing your quest leader to open the quest
give King Arthur Excalibur
Fixes to 3.7.0-x Problems that Were Exposed Via git Repository Fixes to 3.7.0-x Problems that Were Exposed Via git Repository

View File

@@ -2064,6 +2064,7 @@ extern void free_epri(struct monst *);
extern void onquest(void); extern void onquest(void);
extern void nemdead(void); extern void nemdead(void);
extern void leaddead(void);
extern void artitouch(struct obj *); extern void artitouch(struct obj *);
extern boolean ok_to_quest(void); extern boolean ok_to_quest(void);
extern void leader_speaks(struct monst *); extern void leader_speaks(struct monst *);

View File

@@ -17,7 +17,7 @@
* Incrementing EDITLEVEL can be used to force invalidation of old bones * Incrementing EDITLEVEL can be used to force invalidation of old bones
* and save files. * and save files.
*/ */
#define EDITLEVEL 33 #define EDITLEVEL 34
/* /*
* Development status possibilities. * Development status possibilities.

View File

@@ -11,6 +11,7 @@ struct q_score { /* Quest "scorecard" */
Bitfield(not_ready, 3); /* rejected due to alignment, etc. */ Bitfield(not_ready, 3); /* rejected due to alignment, etc. */
Bitfield(pissed_off, 1); /* got the leader angry */ Bitfield(pissed_off, 1); /* got the leader angry */
Bitfield(got_quest, 1); /* got the quest assignment */ Bitfield(got_quest, 1); /* got the quest assignment */
Bitfield(killed_leader, 1); /* killed the quest leader */
Bitfield(first_locate, 1); /* only set the first time */ Bitfield(first_locate, 1); /* only set the first time */
Bitfield(met_intermed, 1); /* used if the locate is a person. */ Bitfield(met_intermed, 1); /* used if the locate is a person. */
@@ -39,7 +40,6 @@ struct q_score { /* Quest "scorecard" */
unsigned leader_m_id; unsigned leader_m_id;
}; };
#define MAX_QUEST_TRIES 7 /* exceed this and you "fail" */
#define MIN_QUEST_ALIGN 20 /* at least this align.record to start */ #define MIN_QUEST_ALIGN 20 /* at least this align.record to start */
/* note: align 20 matches "pious" as reported by enlightenment (cmd.c) */ /* note: align 20 matches "pious" as reported by enlightenment (cmd.c) */
#define MIN_QUEST_LEVEL 14 /* at least this u.ulevel to start */ #define MIN_QUEST_LEVEL 14 /* at least this u.ulevel to start */

View File

@@ -2205,6 +2205,8 @@ m_detach(
wizdead(); wizdead();
if (mtmp->data->msound == MS_NEMESIS) if (mtmp->data->msound == MS_NEMESIS)
nemdead(); nemdead();
if (mtmp->data->msound == MS_LEADER)
leaddead();
if (mtmp->m_id == g.stealmid) if (mtmp->m_id == g.stealmid)
thiefdead(); thiefdead();
relobj(mtmp, 0, FALSE); relobj(mtmp, 0, FALSE);
@@ -2926,12 +2928,17 @@ xkilled(
/* adjust alignment points */ /* adjust alignment points */
if (mtmp->m_id == g.quest_status.leader_m_id) { /* REAL BAD! */ if (mtmp->m_id == g.quest_status.leader_m_id) { /* REAL BAD! */
adjalign(-(u.ualign.record + (int) ALIGNLIM / 2)); adjalign(-(u.ualign.record + (int) ALIGNLIM / 2));
u.ugangr += 7; /* instantly become "extremely" angry */
change_luck(-20);
pline("That was %sa bad idea...", pline("That was %sa bad idea...",
u.uevent.qcompleted ? "probably " : ""); u.uevent.qcompleted ? "probably " : "");
} else if (mdat->msound == MS_NEMESIS) { /* Real good! */ } else if (mdat->msound == MS_NEMESIS) { /* Real good! */
adjalign((int) (ALIGNLIM / 4)); if (!g.quest_status.killed_leader)
adjalign((int) (ALIGNLIM / 4));
} else if (mdat->msound == MS_GUARDIAN) { /* Bad */ } else if (mdat->msound == MS_GUARDIAN) { /* Bad */
adjalign(-(int) (ALIGNLIM / 8)); adjalign(-(int) (ALIGNLIM / 8));
u.ugangr++;
change_luck(-4);
if (!Hallucination) if (!Hallucination)
pline("That was probably a bad idea..."); pline("That was probably a bad idea...");
else else
@@ -3368,8 +3375,7 @@ setmangry(struct monst* mtmp, boolean via_attack)
} }
/* attacking your own quest leader will anger his or her guardians */ /* attacking your own quest leader will anger his or her guardians */
if (!g.context.mon_moving /* should always be the case here */ if (mtmp->data == &mons[quest_info(MS_LEADER)]) {
&& mtmp->data == &mons[quest_info(MS_LEADER)]) {
struct monst *mon; struct monst *mon;
struct permonst *q_guardian = &mons[quest_info(MS_GUARDIAN)]; struct permonst *q_guardian = &mons[quest_info(MS_GUARDIAN)];
int got_mad = 0; int got_mad = 0;

View File

@@ -2854,25 +2854,25 @@ struct permonst _mons2[] = {
/* /*
* quest leaders * quest leaders
*/ */
MON("Lord Carnarvon", S_HUMAN, LVL(20, 12, 0, 30, 20), (G_NOGEN | G_UNIQ), MON("Lord Carnarvon", S_HUMAN, LVL(20, 15, 0, 90, 20), (G_NOGEN | G_UNIQ),
A(ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, A(ATTK(AT_WEAP, AD_PHYS, 4, 10), ATTK(AT_MAGC, AD_SPEL, 4, 8),
NO_ATTK), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
SIZ(WT_HUMAN, 400, MS_LEADER, MZ_HUMAN), 0, 0, SIZ(WT_HUMAN, 400, MS_LEADER, MZ_HUMAN), 0, 0,
M1_TUNNEL | M1_NEEDPICK | M1_HUMANOID | M1_OMNIVORE, M1_TUNNEL | M1_NEEDPICK | M1_HUMANOID | M1_OMNIVORE,
M2_NOPOLY | M2_HUMAN | M2_PNAME | M2_PEACEFUL | M2_STRONG | M2_MALE M2_NOPOLY | M2_HUMAN | M2_PNAME | M2_PEACEFUL | M2_STRONG | M2_MALE
| M2_COLLECT | M2_MAGIC, | M2_COLLECT | M2_MAGIC,
M3_CLOSE | M3_INFRAVISIBLE, 22, HI_LORD), M3_CLOSE | M3_INFRAVISIBLE, 22, HI_LORD),
MON("Pelias", S_HUMAN, LVL(20, 12, 0, 30, 0), (G_NOGEN | G_UNIQ), MON("Pelias", S_HUMAN, LVL(20, 15, 0, 90, 0), (G_NOGEN | G_UNIQ),
A(ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, A(ATTK(AT_WEAP, AD_PHYS, 4, 10), ATTK(AT_WEAP, AD_PHYS, 4, 10),
NO_ATTK), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
SIZ(WT_HUMAN, 400, MS_LEADER, MZ_HUMAN), MR_POISON, 0, SIZ(WT_HUMAN, 400, MS_LEADER, MZ_HUMAN), MR_POISON, 0,
M1_HUMANOID | M1_OMNIVORE, M1_HUMANOID | M1_OMNIVORE,
M2_NOPOLY | M2_HUMAN | M2_PNAME | M2_PEACEFUL | M2_STRONG | M2_MALE M2_NOPOLY | M2_HUMAN | M2_PNAME | M2_PEACEFUL | M2_STRONG | M2_MALE
| M2_COLLECT | M2_MAGIC, | M2_COLLECT | M2_MAGIC,
M3_CLOSE | M3_INFRAVISIBLE, 22, HI_LORD), M3_CLOSE | M3_INFRAVISIBLE, 22, HI_LORD),
MON("Shaman Karnov", S_HUMAN, LVL(20, 12, 0, 30, 20), (G_NOGEN | G_UNIQ), MON("Shaman Karnov", S_HUMAN, LVL(20, 15, 0, 90, 20), (G_NOGEN | G_UNIQ),
A(ATTK(AT_WEAP, AD_PHYS, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, A(ATTK(AT_WEAP, AD_PHYS, 4, 10), ATTK(AT_MAGC, AD_CLRC, 2, 8),
NO_ATTK), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
SIZ(WT_HUMAN, 400, MS_LEADER, MZ_HUMAN), 0, 0, SIZ(WT_HUMAN, 400, MS_LEADER, MZ_HUMAN), 0, 0,
M1_HUMANOID | M1_OMNIVORE, M1_HUMANOID | M1_OMNIVORE,
M2_NOPOLY | M2_HUMAN | M2_PNAME | M2_PEACEFUL | M2_STRONG | M2_MALE M2_NOPOLY | M2_HUMAN | M2_PNAME | M2_PEACEFUL | M2_STRONG | M2_MALE
@@ -2900,23 +2900,23 @@ struct permonst _mons2[] = {
| M2_FEMALE | M2_COLLECT | M2_MAGIC, | M2_FEMALE | M2_COLLECT | M2_MAGIC,
M3_CLOSE | M3_INFRAVISION | M3_INFRAVISIBLE, 22, HI_LORD), M3_CLOSE | M3_INFRAVISION | M3_INFRAVISIBLE, 22, HI_LORD),
#endif #endif
MON("Hippocrates", S_HUMAN, LVL(20, 12, 0, 40, 0), (G_NOGEN | G_UNIQ), MON("Hippocrates", S_HUMAN, LVL(20, 15, 0, 90, 0), (G_NOGEN | G_UNIQ),
A(ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, A(ATTK(AT_WEAP, AD_PHYS, 1, 6), ATTK(AT_MAGC, AD_CLRC, 3, 8),
NO_ATTK), ATTK(AT_MAGC, AD_CLRC, 3, 8), NO_ATTK, NO_ATTK, NO_ATTK),
SIZ(WT_HUMAN, 400, MS_LEADER, MZ_HUMAN), MR_POISON, 0, SIZ(WT_HUMAN, 400, MS_LEADER, MZ_HUMAN), MR_POISON, 0,
M1_HUMANOID | M1_OMNIVORE, M1_HUMANOID | M1_OMNIVORE,
M2_NOPOLY | M2_HUMAN | M2_PNAME | M2_PEACEFUL | M2_STRONG | M2_MALE M2_NOPOLY | M2_HUMAN | M2_PNAME | M2_PEACEFUL | M2_STRONG | M2_MALE
| M2_COLLECT | M2_MAGIC, | M2_COLLECT | M2_MAGIC,
M3_CLOSE | M3_INFRAVISIBLE, 22, HI_LORD), M3_CLOSE | M3_INFRAVISIBLE, 22, HI_LORD),
MON("King Arthur", S_HUMAN, LVL(20, 12, 0, 40, 20), (G_NOGEN | G_UNIQ), MON("King Arthur", S_HUMAN, LVL(20, 15, 0, 90, 20), (G_NOGEN | G_UNIQ),
A(ATTK(AT_WEAP, AD_PHYS, 1, 6), ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK, A(ATTK(AT_WEAP, AD_PHYS, 4, 10), ATTK(AT_WEAP, AD_PHYS, 4, 10), NO_ATTK,
NO_ATTK, NO_ATTK, NO_ATTK), NO_ATTK, NO_ATTK, NO_ATTK),
SIZ(WT_HUMAN, 400, MS_LEADER, MZ_HUMAN), 0, 0, SIZ(WT_HUMAN, 400, MS_LEADER, MZ_HUMAN), 0, 0,
M1_HUMANOID | M1_OMNIVORE, M1_HUMANOID | M1_OMNIVORE,
M2_NOPOLY | M2_HUMAN | M2_PNAME | M2_PEACEFUL | M2_STRONG | M2_MALE M2_NOPOLY | M2_HUMAN | M2_PNAME | M2_PEACEFUL | M2_STRONG | M2_MALE
| M2_COLLECT | M2_MAGIC, | M2_COLLECT | M2_MAGIC,
M3_CLOSE | M3_INFRAVISIBLE, 23, HI_LORD), M3_CLOSE | M3_INFRAVISIBLE, 23, HI_LORD),
MON("Grand Master", S_HUMAN, LVL(25, 12, 0, 70, 0), (G_NOGEN | G_UNIQ), MON("Grand Master", S_HUMAN, LVL(25, 15, 0, 90, 0), (G_NOGEN | G_UNIQ),
A(ATTK(AT_CLAW, AD_PHYS, 4, 10), ATTK(AT_KICK, AD_PHYS, 2, 8), A(ATTK(AT_CLAW, AD_PHYS, 4, 10), ATTK(AT_KICK, AD_PHYS, 2, 8),
ATTK(AT_MAGC, AD_CLRC, 2, 8), ATTK(AT_MAGC, AD_CLRC, 2, 8), NO_ATTK, ATTK(AT_MAGC, AD_CLRC, 2, 8), ATTK(AT_MAGC, AD_CLRC, 2, 8), NO_ATTK,
NO_ATTK), NO_ATTK),
@@ -2926,7 +2926,7 @@ struct permonst _mons2[] = {
M2_NOPOLY | M2_HUMAN | M2_PEACEFUL | M2_STRONG | M2_MALE | M2_NASTY M2_NOPOLY | M2_HUMAN | M2_PEACEFUL | M2_STRONG | M2_MALE | M2_NASTY
| M2_MAGIC, | M2_MAGIC,
M3_CLOSE | M3_INFRAVISIBLE, 30, CLR_BLACK), M3_CLOSE | M3_INFRAVISIBLE, 30, CLR_BLACK),
MON("Arch Priest", S_HUMAN, LVL(25, 12, 7, 70, 0), (G_NOGEN | G_UNIQ), MON("Arch Priest", S_HUMAN, LVL(25, 15, 7, 90, 0), (G_NOGEN | G_UNIQ),
A(ATTK(AT_WEAP, AD_PHYS, 4, 10), ATTK(AT_KICK, AD_PHYS, 2, 8), A(ATTK(AT_WEAP, AD_PHYS, 4, 10), ATTK(AT_KICK, AD_PHYS, 2, 8),
ATTK(AT_MAGC, AD_CLRC, 2, 8), ATTK(AT_MAGC, AD_CLRC, 2, 8), NO_ATTK, ATTK(AT_MAGC, AD_CLRC, 2, 8), ATTK(AT_MAGC, AD_CLRC, 2, 8), NO_ATTK,
NO_ATTK), NO_ATTK),
@@ -2936,9 +2936,9 @@ struct permonst _mons2[] = {
M2_NOPOLY | M2_HUMAN | M2_PEACEFUL | M2_STRONG | M2_MALE | M2_COLLECT M2_NOPOLY | M2_HUMAN | M2_PEACEFUL | M2_STRONG | M2_MALE | M2_COLLECT
| M2_MAGIC, | M2_MAGIC,
M3_CLOSE | M3_INFRAVISIBLE, 30, CLR_WHITE), M3_CLOSE | M3_INFRAVISIBLE, 30, CLR_WHITE),
MON("Orion", S_HUMAN, LVL(20, 12, 0, 30, 0), (G_NOGEN | G_UNIQ), MON("Orion", S_HUMAN, LVL(20, 15, 0, 90, 0), (G_NOGEN | G_UNIQ),
A(ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, A(ATTK(AT_WEAP, AD_PHYS, 4, 10), ATTK(AT_MAGC, AD_SPEL, 4, 8),
NO_ATTK), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
SIZ(2200, 700, MS_LEADER, MZ_HUGE), 0, 0, SIZ(2200, 700, MS_LEADER, MZ_HUGE), 0, 0,
M1_HUMANOID | M1_OMNIVORE | M1_SEE_INVIS | M1_SWIM | M1_AMPHIBIOUS, M1_HUMANOID | M1_OMNIVORE | M1_SEE_INVIS | M1_SWIM | M1_AMPHIBIOUS,
M2_NOPOLY | M2_HUMAN | M2_PNAME | M2_PEACEFUL | M2_STRONG | M2_MALE M2_NOPOLY | M2_HUMAN | M2_PNAME | M2_PEACEFUL | M2_STRONG | M2_MALE
@@ -2946,43 +2946,43 @@ struct permonst _mons2[] = {
M3_CLOSE | M3_INFRAVISION | M3_INFRAVISIBLE, 22, HI_LORD), M3_CLOSE | M3_INFRAVISION | M3_INFRAVISIBLE, 22, HI_LORD),
/* Note: Master of Thieves is also the Tourist's nemesis. /* Note: Master of Thieves is also the Tourist's nemesis.
*/ */
MON("Master of Thieves", S_HUMAN, LVL(20, 12, 0, 30, -20), MON("Master of Thieves", S_HUMAN, LVL(20, 15, 0, 90, -20),
(G_NOGEN | G_UNIQ), (G_NOGEN | G_UNIQ),
A(ATTK(AT_WEAP, AD_PHYS, 2, 6), ATTK(AT_WEAP, AD_PHYS, 2, 6), A(ATTK(AT_WEAP, AD_PHYS, 4, 10), ATTK(AT_WEAP, AD_PHYS, 2, 6),
ATTK(AT_CLAW, AD_SAMU, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK), ATTK(AT_CLAW, AD_SAMU, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK),
SIZ(WT_HUMAN, 400, MS_LEADER, MZ_HUMAN), MR_STONE, 0, SIZ(WT_HUMAN, 400, MS_LEADER, MZ_HUMAN), MR_STONE, 0,
M1_HUMANOID | M1_OMNIVORE, M1_HUMANOID | M1_OMNIVORE,
M2_NOPOLY | M2_HUMAN | M2_PEACEFUL | M2_STRONG | M2_MALE | M2_GREEDY M2_NOPOLY | M2_HUMAN | M2_PEACEFUL | M2_STRONG | M2_MALE | M2_GREEDY
| M2_JEWELS | M2_COLLECT | M2_MAGIC, | M2_JEWELS | M2_COLLECT | M2_MAGIC,
M3_CLOSE | M3_INFRAVISIBLE, 24, HI_LORD), M3_CLOSE | M3_INFRAVISIBLE, 24, HI_LORD),
MON("Lord Sato", S_HUMAN, LVL(20, 12, 0, 30, 20), (G_NOGEN | G_UNIQ), MON("Lord Sato", S_HUMAN, LVL(20, 15, 0, 90, 20), (G_NOGEN | G_UNIQ),
A(ATTK(AT_WEAP, AD_PHYS, 1, 8), ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK, A(ATTK(AT_WEAP, AD_PHYS, 4, 10), ATTK(AT_WEAP, AD_PHYS, 4, 10), NO_ATTK,
NO_ATTK, NO_ATTK, NO_ATTK), NO_ATTK, NO_ATTK, NO_ATTK),
SIZ(WT_HUMAN, 400, MS_LEADER, MZ_HUMAN), 0, 0, SIZ(WT_HUMAN, 400, MS_LEADER, MZ_HUMAN), 0, 0,
M1_HUMANOID | M1_OMNIVORE, M1_HUMANOID | M1_OMNIVORE,
M2_NOPOLY | M2_HUMAN | M2_PNAME | M2_PEACEFUL | M2_STRONG | M2_MALE M2_NOPOLY | M2_HUMAN | M2_PNAME | M2_PEACEFUL | M2_STRONG | M2_MALE
| M2_COLLECT | M2_MAGIC, | M2_COLLECT | M2_MAGIC,
M3_CLOSE | M3_INFRAVISIBLE, 23, HI_LORD), M3_CLOSE | M3_INFRAVISIBLE, 23, HI_LORD),
MON("Twoflower", S_HUMAN, LVL(20, 12, 10, 20, 0), (G_NOGEN | G_UNIQ), MON("Twoflower", S_HUMAN, LVL(20, 15, 10, 90, 0), (G_NOGEN | G_UNIQ),
A(ATTK(AT_WEAP, AD_PHYS, 1, 6), ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK, A(ATTK(AT_WEAP, AD_PHYS, 4, 10), NO_ATTK, NO_ATTK,
NO_ATTK, NO_ATTK, NO_ATTK), NO_ATTK, NO_ATTK, NO_ATTK),
SIZ(WT_HUMAN, 400, MS_LEADER, MZ_HUMAN), 0, 0, SIZ(WT_HUMAN, 400, MS_LEADER, MZ_HUMAN), 0, 0,
M1_HUMANOID | M1_OMNIVORE, M1_HUMANOID | M1_OMNIVORE,
M2_NOPOLY | M2_HUMAN | M2_PNAME | M2_PEACEFUL | M2_STRONG | M2_MALE M2_NOPOLY | M2_HUMAN | M2_PNAME | M2_PEACEFUL | M2_STRONG | M2_MALE
| M2_COLLECT | M2_MAGIC, | M2_COLLECT | M2_MAGIC,
M3_CLOSE | M3_INFRAVISIBLE, 22, HI_DOMESTIC), M3_CLOSE | M3_INFRAVISIBLE, 22, HI_DOMESTIC),
MON("Norn", S_HUMAN, LVL(20, 12, 0, 80, 0), (G_NOGEN | G_UNIQ), MON("Norn", S_HUMAN, LVL(20, 15, 0, 90, 0), (G_NOGEN | G_UNIQ),
A(ATTK(AT_WEAP, AD_PHYS, 1, 8), ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK, A(ATTK(AT_WEAP, AD_PHYS, 4, 10), ATTK(AT_WEAP, AD_PHYS, 4, 10), NO_ATTK,
NO_ATTK, NO_ATTK, NO_ATTK), NO_ATTK, NO_ATTK, NO_ATTK),
SIZ(1800, 550, MS_LEADER, MZ_HUGE), MR_COLD, 0, SIZ(1800, 550, MS_LEADER, MZ_HUGE), MR_COLD, 0,
M1_HUMANOID | M1_OMNIVORE, M1_HUMANOID | M1_OMNIVORE,
M2_NOPOLY | M2_HUMAN | M2_PEACEFUL | M2_STRONG | M2_FEMALE M2_NOPOLY | M2_HUMAN | M2_PEACEFUL | M2_STRONG | M2_FEMALE
| M2_COLLECT | M2_MAGIC, | M2_COLLECT | M2_MAGIC,
M3_CLOSE | M3_INFRAVISIBLE, 23, HI_LORD), M3_CLOSE | M3_INFRAVISIBLE, 23, HI_LORD),
MON("Neferet the Green", S_HUMAN, LVL(20, 12, 0, 60, 0), MON("Neferet the Green", S_HUMAN, LVL(20, 15, 0, 90, 0),
(G_NOGEN | G_UNIQ), (G_NOGEN | G_UNIQ),
A(ATTK(AT_WEAP, AD_PHYS, 1, 6), ATTK(AT_MAGC, AD_SPEL, 2, 8), NO_ATTK, A(ATTK(AT_WEAP, AD_PHYS, 4, 10), ATTK(AT_MAGC, AD_SPEL, 2, 8),
NO_ATTK, NO_ATTK, NO_ATTK), ATTK(AT_MAGC, AD_SPEL, 2, 8), NO_ATTK, NO_ATTK, NO_ATTK),
SIZ(WT_HUMAN, 400, MS_LEADER, MZ_HUMAN), 0, 0, SIZ(WT_HUMAN, 400, MS_LEADER, MZ_HUMAN), 0, 0,
M1_HUMANOID | M1_OMNIVORE, M1_HUMANOID | M1_OMNIVORE,
M2_NOPOLY | M2_HUMAN | M2_FEMALE | M2_PNAME | M2_PEACEFUL | M2_STRONG M2_NOPOLY | M2_HUMAN | M2_FEMALE | M2_PNAME | M2_PEACEFUL | M2_STRONG

View File

@@ -17,7 +17,7 @@ static void on_goal(void);
static boolean not_capable(void); static boolean not_capable(void);
static int is_pure(boolean); static int is_pure(boolean);
static void expulsion(boolean); static void expulsion(boolean);
static void chat_with_leader(void); static void chat_with_leader(struct monst *);
static void chat_with_nemesis(void); static void chat_with_nemesis(void);
static void chat_with_guardian(void); static void chat_with_guardian(void);
static void prisoner_speaks(struct monst *); static void prisoner_speaks(struct monst *);
@@ -112,6 +112,15 @@ nemdead(void)
} }
} }
void
leaddead(void)
{
if (!Qstat(killed_leader)) {
Qstat(killed_leader) = TRUE;
/* TODO: qt_pager("killed_leader"); ? */
}
}
void void
artitouch(struct obj *obj) artitouch(struct obj *obj)
{ {
@@ -130,8 +139,8 @@ artitouch(struct obj *obj)
boolean boolean
ok_to_quest(void) ok_to_quest(void)
{ {
return (boolean) ((Qstat(got_quest) || Qstat(got_thanks)) return (boolean) (((Qstat(got_quest) || Qstat(got_thanks))
&& is_pure(FALSE) > 0); && is_pure(FALSE) > 0) || Qstat(killed_leader));
} }
static boolean static boolean
@@ -240,8 +249,11 @@ finish_quest(struct obj *obj) /* quest artifact; possibly null if carrying
} }
static void static void
chat_with_leader(void) chat_with_leader(struct monst *mtmp)
{ {
if (!mtmp->mpeaceful || Qstat(pissed_off))
return;
/* Rule 0: Cheater checks. */ /* Rule 0: Cheater checks. */
if (u.uhave.questart && !Qstat(met_nemesis)) if (u.uhave.questart && !Qstat(met_nemesis))
Qstat(cheater) = TRUE; Qstat(cheater) = TRUE;
@@ -293,18 +305,16 @@ chat_with_leader(void)
exercise(A_WIS, TRUE); exercise(A_WIS, TRUE);
expulsion(FALSE); expulsion(FALSE);
} else if ((purity = is_pure(TRUE)) < 0) { } else if ((purity = is_pure(TRUE)) < 0) {
com_pager("banished"); if (!Qstat(pissed_off)) {
expulsion(TRUE); com_pager("banished");
} else if (purity == 0) { Qstat(pissed_off) = TRUE;
qt_pager("badalign");
if (Qstat(not_ready) == MAX_QUEST_TRIES) {
qt_pager("leader_last");
expulsion(TRUE);
} else {
Qstat(not_ready)++;
exercise(A_WIS, TRUE);
expulsion(FALSE); expulsion(FALSE);
} }
} else if (purity == 0) {
qt_pager("badalign");
Qstat(not_ready) = 1;
exercise(A_WIS, TRUE);
expulsion(FALSE);
} else { /* You are worthy! */ } else { /* You are worthy! */
qt_pager("assignquest"); qt_pager("assignquest");
exercise(A_WIS, TRUE); exercise(A_WIS, TRUE);
@@ -318,6 +328,12 @@ leader_speaks(struct monst *mtmp)
{ {
/* maybe you attacked leader? */ /* maybe you attacked leader? */
if (!mtmp->mpeaceful) { if (!mtmp->mpeaceful) {
if (!Qstat(pissed_off)) {
/* again, don't end it permanently if the leader gets angry
* since you're going to have to kill him to go questing... :)
* ...but do only show this crap once. */
qt_pager("leader_last");
}
Qstat(pissed_off) = TRUE; Qstat(pissed_off) = TRUE;
mtmp->mstrategy &= ~STRAT_WAITMASK; /* end the inaction */ mtmp->mstrategy &= ~STRAT_WAITMASK; /* end the inaction */
} }
@@ -326,11 +342,8 @@ leader_speaks(struct monst *mtmp)
if (!on_level(&u.uz, &qstart_level)) if (!on_level(&u.uz, &qstart_level))
return; return;
if (Qstat(pissed_off)) { if (!Qstat(pissed_off))
qt_pager("leader_last"); chat_with_leader(mtmp);
expulsion(TRUE);
} else
chat_with_leader();
} }
static void static void
@@ -399,7 +412,10 @@ void
quest_chat(struct monst *mtmp) quest_chat(struct monst *mtmp)
{ {
if (mtmp->m_id == Qstat(leader_m_id)) { if (mtmp->m_id == Qstat(leader_m_id)) {
chat_with_leader(); chat_with_leader(mtmp);
/* leader might have become pissed during the chat */
if (Qstat(pissed_off))
setmangry(mtmp, FALSE);
return; return;
} }
switch (mtmp->data->msound) { switch (mtmp->data->msound) {

View File

@@ -499,6 +499,9 @@ nh_timeout(void)
if (flags.friday13) if (flags.friday13)
baseluck -= 1; baseluck -= 1;
if (g.quest_status.killed_leader)
baseluck -= 4;
if (u.uluck != baseluck if (u.uluck != baseluck
&& g.moves % ((u.uhave.amulet || u.ugangr) ? 300 : 600) == 0) { && g.moves % ((u.uhave.amulet || u.ugangr) ? 300 : 600) == 0) {
/* Cursed luckstones stop bad luck from timing out; blessed luckstones /* Cursed luckstones stop bad luck from timing out; blessed luckstones