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

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

View File

@@ -2854,25 +2854,25 @@ struct permonst _mons2[] = {
/*
* quest leaders
*/
MON("Lord Carnarvon", S_HUMAN, LVL(20, 12, 0, 30, 20), (G_NOGEN | G_UNIQ),
A(ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK,
NO_ATTK),
MON("Lord Carnarvon", S_HUMAN, LVL(20, 15, 0, 90, 20), (G_NOGEN | G_UNIQ),
A(ATTK(AT_WEAP, AD_PHYS, 4, 10), ATTK(AT_MAGC, AD_SPEL, 4, 8),
NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
SIZ(WT_HUMAN, 400, MS_LEADER, MZ_HUMAN), 0, 0,
M1_TUNNEL | M1_NEEDPICK | M1_HUMANOID | M1_OMNIVORE,
M2_NOPOLY | M2_HUMAN | M2_PNAME | M2_PEACEFUL | M2_STRONG | M2_MALE
| M2_COLLECT | M2_MAGIC,
M3_CLOSE | M3_INFRAVISIBLE, 22, HI_LORD),
MON("Pelias", S_HUMAN, LVL(20, 12, 0, 30, 0), (G_NOGEN | G_UNIQ),
A(ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK,
NO_ATTK),
MON("Pelias", S_HUMAN, LVL(20, 15, 0, 90, 0), (G_NOGEN | G_UNIQ),
A(ATTK(AT_WEAP, AD_PHYS, 4, 10), ATTK(AT_WEAP, AD_PHYS, 4, 10),
NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
SIZ(WT_HUMAN, 400, MS_LEADER, MZ_HUMAN), MR_POISON, 0,
M1_HUMANOID | M1_OMNIVORE,
M2_NOPOLY | M2_HUMAN | M2_PNAME | M2_PEACEFUL | M2_STRONG | M2_MALE
| M2_COLLECT | M2_MAGIC,
M3_CLOSE | M3_INFRAVISIBLE, 22, HI_LORD),
MON("Shaman Karnov", S_HUMAN, LVL(20, 12, 0, 30, 20), (G_NOGEN | G_UNIQ),
A(ATTK(AT_WEAP, AD_PHYS, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK,
NO_ATTK),
MON("Shaman Karnov", S_HUMAN, LVL(20, 15, 0, 90, 20), (G_NOGEN | G_UNIQ),
A(ATTK(AT_WEAP, AD_PHYS, 4, 10), ATTK(AT_MAGC, AD_CLRC, 2, 8),
NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
SIZ(WT_HUMAN, 400, MS_LEADER, MZ_HUMAN), 0, 0,
M1_HUMANOID | M1_OMNIVORE,
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,
M3_CLOSE | M3_INFRAVISION | M3_INFRAVISIBLE, 22, HI_LORD),
#endif
MON("Hippocrates", S_HUMAN, LVL(20, 12, 0, 40, 0), (G_NOGEN | G_UNIQ),
A(ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK,
NO_ATTK),
MON("Hippocrates", S_HUMAN, LVL(20, 15, 0, 90, 0), (G_NOGEN | G_UNIQ),
A(ATTK(AT_WEAP, AD_PHYS, 1, 6), ATTK(AT_MAGC, AD_CLRC, 3, 8),
ATTK(AT_MAGC, AD_CLRC, 3, 8), NO_ATTK, NO_ATTK, NO_ATTK),
SIZ(WT_HUMAN, 400, MS_LEADER, MZ_HUMAN), MR_POISON, 0,
M1_HUMANOID | M1_OMNIVORE,
M2_NOPOLY | M2_HUMAN | M2_PNAME | M2_PEACEFUL | M2_STRONG | M2_MALE
| M2_COLLECT | M2_MAGIC,
M3_CLOSE | M3_INFRAVISIBLE, 22, HI_LORD),
MON("King Arthur", S_HUMAN, LVL(20, 12, 0, 40, 20), (G_NOGEN | G_UNIQ),
A(ATTK(AT_WEAP, AD_PHYS, 1, 6), ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK,
MON("King Arthur", S_HUMAN, LVL(20, 15, 0, 90, 20), (G_NOGEN | G_UNIQ),
A(ATTK(AT_WEAP, AD_PHYS, 4, 10), ATTK(AT_WEAP, AD_PHYS, 4, 10), NO_ATTK,
NO_ATTK, NO_ATTK, NO_ATTK),
SIZ(WT_HUMAN, 400, MS_LEADER, MZ_HUMAN), 0, 0,
M1_HUMANOID | M1_OMNIVORE,
M2_NOPOLY | M2_HUMAN | M2_PNAME | M2_PEACEFUL | M2_STRONG | M2_MALE
| M2_COLLECT | M2_MAGIC,
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),
ATTK(AT_MAGC, AD_CLRC, 2, 8), ATTK(AT_MAGC, AD_CLRC, 2, 8), NO_ATTK,
NO_ATTK),
@@ -2926,7 +2926,7 @@ struct permonst _mons2[] = {
M2_NOPOLY | M2_HUMAN | M2_PEACEFUL | M2_STRONG | M2_MALE | M2_NASTY
| M2_MAGIC,
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),
ATTK(AT_MAGC, AD_CLRC, 2, 8), ATTK(AT_MAGC, AD_CLRC, 2, 8), NO_ATTK,
NO_ATTK),
@@ -2936,9 +2936,9 @@ struct permonst _mons2[] = {
M2_NOPOLY | M2_HUMAN | M2_PEACEFUL | M2_STRONG | M2_MALE | M2_COLLECT
| M2_MAGIC,
M3_CLOSE | M3_INFRAVISIBLE, 30, CLR_WHITE),
MON("Orion", S_HUMAN, LVL(20, 12, 0, 30, 0), (G_NOGEN | G_UNIQ),
A(ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK,
NO_ATTK),
MON("Orion", S_HUMAN, LVL(20, 15, 0, 90, 0), (G_NOGEN | G_UNIQ),
A(ATTK(AT_WEAP, AD_PHYS, 4, 10), ATTK(AT_MAGC, AD_SPEL, 4, 8),
NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK),
SIZ(2200, 700, MS_LEADER, MZ_HUGE), 0, 0,
M1_HUMANOID | M1_OMNIVORE | M1_SEE_INVIS | M1_SWIM | M1_AMPHIBIOUS,
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),
/* 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),
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),
SIZ(WT_HUMAN, 400, MS_LEADER, MZ_HUMAN), MR_STONE, 0,
M1_HUMANOID | M1_OMNIVORE,
M2_NOPOLY | M2_HUMAN | M2_PEACEFUL | M2_STRONG | M2_MALE | M2_GREEDY
| M2_JEWELS | M2_COLLECT | M2_MAGIC,
M3_CLOSE | M3_INFRAVISIBLE, 24, HI_LORD),
MON("Lord Sato", S_HUMAN, LVL(20, 12, 0, 30, 20), (G_NOGEN | G_UNIQ),
A(ATTK(AT_WEAP, AD_PHYS, 1, 8), ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK,
MON("Lord Sato", S_HUMAN, LVL(20, 15, 0, 90, 20), (G_NOGEN | G_UNIQ),
A(ATTK(AT_WEAP, AD_PHYS, 4, 10), ATTK(AT_WEAP, AD_PHYS, 4, 10), NO_ATTK,
NO_ATTK, NO_ATTK, NO_ATTK),
SIZ(WT_HUMAN, 400, MS_LEADER, MZ_HUMAN), 0, 0,
M1_HUMANOID | M1_OMNIVORE,
M2_NOPOLY | M2_HUMAN | M2_PNAME | M2_PEACEFUL | M2_STRONG | M2_MALE
| M2_COLLECT | M2_MAGIC,
M3_CLOSE | M3_INFRAVISIBLE, 23, HI_LORD),
MON("Twoflower", S_HUMAN, LVL(20, 12, 10, 20, 0), (G_NOGEN | G_UNIQ),
A(ATTK(AT_WEAP, AD_PHYS, 1, 6), ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK,
MON("Twoflower", S_HUMAN, LVL(20, 15, 10, 90, 0), (G_NOGEN | G_UNIQ),
A(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), 0, 0,
M1_HUMANOID | M1_OMNIVORE,
M2_NOPOLY | M2_HUMAN | M2_PNAME | M2_PEACEFUL | M2_STRONG | M2_MALE
| M2_COLLECT | M2_MAGIC,
M3_CLOSE | M3_INFRAVISIBLE, 22, HI_DOMESTIC),
MON("Norn", S_HUMAN, LVL(20, 12, 0, 80, 0), (G_NOGEN | G_UNIQ),
A(ATTK(AT_WEAP, AD_PHYS, 1, 8), ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK,
MON("Norn", S_HUMAN, LVL(20, 15, 0, 90, 0), (G_NOGEN | G_UNIQ),
A(ATTK(AT_WEAP, AD_PHYS, 4, 10), ATTK(AT_WEAP, AD_PHYS, 4, 10), NO_ATTK,
NO_ATTK, NO_ATTK, NO_ATTK),
SIZ(1800, 550, MS_LEADER, MZ_HUGE), MR_COLD, 0,
M1_HUMANOID | M1_OMNIVORE,
M2_NOPOLY | M2_HUMAN | M2_PEACEFUL | M2_STRONG | M2_FEMALE
| M2_COLLECT | M2_MAGIC,
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),
A(ATTK(AT_WEAP, AD_PHYS, 1, 6), ATTK(AT_MAGC, AD_SPEL, 2, 8), NO_ATTK,
NO_ATTK, NO_ATTK, NO_ATTK),
A(ATTK(AT_WEAP, AD_PHYS, 4, 10), ATTK(AT_MAGC, AD_SPEL, 2, 8),
ATTK(AT_MAGC, AD_SPEL, 2, 8), NO_ATTK, NO_ATTK, NO_ATTK),
SIZ(WT_HUMAN, 400, MS_LEADER, MZ_HUMAN), 0, 0,
M1_HUMANOID | M1_OMNIVORE,
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 int is_pure(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_guardian(void);
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
artitouch(struct obj *obj)
{
@@ -130,8 +139,8 @@ artitouch(struct obj *obj)
boolean
ok_to_quest(void)
{
return (boolean) ((Qstat(got_quest) || Qstat(got_thanks))
&& is_pure(FALSE) > 0);
return (boolean) (((Qstat(got_quest) || Qstat(got_thanks))
&& is_pure(FALSE) > 0) || Qstat(killed_leader));
}
static boolean
@@ -240,8 +249,11 @@ finish_quest(struct obj *obj) /* quest artifact; possibly null if carrying
}
static void
chat_with_leader(void)
chat_with_leader(struct monst *mtmp)
{
if (!mtmp->mpeaceful || Qstat(pissed_off))
return;
/* Rule 0: Cheater checks. */
if (u.uhave.questart && !Qstat(met_nemesis))
Qstat(cheater) = TRUE;
@@ -293,18 +305,16 @@ chat_with_leader(void)
exercise(A_WIS, TRUE);
expulsion(FALSE);
} else if ((purity = is_pure(TRUE)) < 0) {
com_pager("banished");
expulsion(TRUE);
} else if (purity == 0) {
qt_pager("badalign");
if (Qstat(not_ready) == MAX_QUEST_TRIES) {
qt_pager("leader_last");
expulsion(TRUE);
} else {
Qstat(not_ready)++;
exercise(A_WIS, TRUE);
if (!Qstat(pissed_off)) {
com_pager("banished");
Qstat(pissed_off) = TRUE;
expulsion(FALSE);
}
} else if (purity == 0) {
qt_pager("badalign");
Qstat(not_ready) = 1;
exercise(A_WIS, TRUE);
expulsion(FALSE);
} else { /* You are worthy! */
qt_pager("assignquest");
exercise(A_WIS, TRUE);
@@ -318,6 +328,12 @@ leader_speaks(struct monst *mtmp)
{
/* maybe you attacked leader? */
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;
mtmp->mstrategy &= ~STRAT_WAITMASK; /* end the inaction */
}
@@ -326,11 +342,8 @@ leader_speaks(struct monst *mtmp)
if (!on_level(&u.uz, &qstart_level))
return;
if (Qstat(pissed_off)) {
qt_pager("leader_last");
expulsion(TRUE);
} else
chat_with_leader();
if (!Qstat(pissed_off))
chat_with_leader(mtmp);
}
static void
@@ -399,7 +412,10 @@ void
quest_chat(struct monst *mtmp)
{
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;
}
switch (mtmp->data->msound) {

View File

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