685 lines
18 KiB
C
685 lines
18 KiB
C
/* SCCS Id: @(#)minion.c 3.4 2003/01/09 */
|
|
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
|
|
/* NetHack may be freely redistributed. See license for details. */
|
|
|
|
#include "hack.h"
|
|
|
|
#include "artifact.h"
|
|
|
|
extern const int monstr[];
|
|
|
|
/* mon summons a monster
|
|
*
|
|
* if mon is null, treat as if as being summoned by a far-off Wizard of Yendor
|
|
*/
|
|
void
|
|
msummon(
|
|
struct monst *mon, /* mon to attribute summons to */
|
|
struct permonst *ptr /* summon as though you were <X> */)
|
|
{
|
|
register int dtype = NON_PM, cnt = 0;
|
|
aligntyp atyp;
|
|
int gnum;
|
|
struct monst *mtmp;
|
|
|
|
/* Wielded Demonbane prevents demons from gating in others. From Sporkhack*/
|
|
if (uwep && uwep->oartifact && arti_worn_prop(uwep, ARTP_NOCALL) && mon && is_demon(mon->data)) {
|
|
pline("%s looks puzzled for a moment.",Monnam(mon));
|
|
return;
|
|
}
|
|
if (DimensionalLock)
|
|
return;
|
|
|
|
if (mon && !ptr) {
|
|
ptr = mon->data;
|
|
atyp = (ptr->maligntyp==A_NONE) ? A_NONE : sgn(ptr->maligntyp);
|
|
gnum = (ptr->maligntyp==A_NONE) ? GOD_MOLOCH : align_to_god(sgn(ptr->maligntyp));
|
|
if (get_mx(mon, MX_EPRI)) {
|
|
atyp = EPRI(mon)->shralign;
|
|
gnum = EPRI(mon)->godnum;
|
|
}
|
|
else if (get_mx(mon, MX_EMIN)) {
|
|
atyp = EMIN(mon)->min_align;
|
|
gnum = EMIN(mon)->godnum;
|
|
}
|
|
} else {
|
|
if (!ptr) ptr = &mons[PM_WIZARD_OF_YENDOR];
|
|
atyp = (ptr->maligntyp==A_NONE) ? A_NONE : sgn(ptr->maligntyp);
|
|
gnum = (ptr->maligntyp==A_NONE) ? GOD_MOLOCH : align_to_god(sgn(ptr->maligntyp));
|
|
}
|
|
|
|
if (!mon) {
|
|
/* if no mon, skip all these special cases which might query mon */;
|
|
} else if(ptr->mtyp == PM_SHAKTARI) {
|
|
dtype = PM_MARILITH;
|
|
cnt = d(1,6);
|
|
} else if(ptr->mtyp == PM_BAALPHEGOR && rn2(4)) {
|
|
dtype = rn2(4) ? PM_METAMORPHOSED_NUPPERIBO : PM_ANCIENT_NUPPERIBO;
|
|
cnt = d(4,4);
|
|
} else if(is_ancient(ptr) && ptr->mtyp != PM_BAALPHEGOR) {
|
|
dtype = rn2(4) ? PM_METAMORPHOSED_NUPPERIBO : PM_ANCIENT_NUPPERIBO;
|
|
cnt = d(1,4);
|
|
} else if (is_dprince(ptr) || (ptr->mtyp == PM_WIZARD_OF_YENDOR)) {
|
|
dtype = (!rn2(20)) ? dprince(ptr, atyp) :
|
|
(!rn2(4)) ? dlord(ptr, atyp) : ndemon(atyp);
|
|
cnt = (!rn2(4) && is_normal_demon(&mons[dtype])) ? 2 : 1;
|
|
} else if (is_dlord(ptr)) {
|
|
dtype = (!rn2(50)) ? dprince(ptr, atyp) :
|
|
(!rn2(20)) ? dlord(ptr, atyp) : ndemon(atyp);
|
|
cnt = (!rn2(4) && is_normal_demon(&mons[dtype])) ? 2 : 1;
|
|
} else if (is_normal_demon(ptr)) {
|
|
dtype = (!rn2(20) && Inhell) ? dlord(ptr, atyp) :
|
|
((mons[monsndx(ptr)].geno & G_UNIQ) || !rn2(6)) ? ndemon(atyp) : monsndx(ptr);
|
|
cnt = 1;
|
|
} else if (mon && is_lminion(mon)) {
|
|
if(is_keter(mon->data)){
|
|
if(mon->mtyp == PM_MALKUTH_SEPHIRAH && rn2(8)) return;
|
|
dtype = PM_MALKUTH_SEPHIRAH;
|
|
cnt = (!rn2(4) && !is_lord(&mons[dtype])) ? 2 : 1;
|
|
} else if(In_endgame(&u.uz)){
|
|
dtype = (is_lord(ptr) && !rn2(20)) ? llord() :
|
|
(is_lord(ptr) || (mons[monsndx(ptr)].geno & G_UNIQ) || !rn2(6)) ? lminion() : monsndx(ptr);
|
|
cnt = (!rn2(4) && !is_lord(&mons[dtype])) ? 2 : 1;
|
|
}
|
|
} else if (mon && is_nminion(mon) && In_endgame(&u.uz)) {
|
|
dtype = (is_lord(ptr) && !rn2(20)) ? nlord() :
|
|
(is_lord(ptr) || (mons[monsndx(ptr)].geno & G_UNIQ) || !rn2(6)) ? nminion() : monsndx(ptr);
|
|
cnt = (!rn2(4) && !is_lord(&mons[dtype])) ? 2 : 1;
|
|
} else if (mon && is_cminion(mon) && In_endgame(&u.uz)) {
|
|
dtype = (is_lord(ptr) && !rn2(20)) ? clord() : cminion();
|
|
cnt = (!rn2(4) && !is_lord(&mons[dtype])) ? 2 : 1;
|
|
} else if (ptr->mtyp == PM_ANGEL) {
|
|
if (rn2(6)) {
|
|
(void) summon_god_minion(gnum, FALSE);
|
|
return;
|
|
} else {
|
|
dtype = PM_ANGEL;
|
|
}
|
|
cnt = (!rn2(4) && !is_lord(&mons[dtype])) ? 2 : 1;
|
|
}
|
|
|
|
if (dtype == NON_PM) return;
|
|
|
|
/* sanity checks */
|
|
if (cnt > 1 && (mons[dtype].geno & G_UNIQ)) cnt = 1;
|
|
/*
|
|
* If this daemon is unique and being re-summoned (the only way we
|
|
* could get this far with an extinct dtype), try another.
|
|
*/
|
|
if (mvitals[dtype].mvflags & G_GONE) {
|
|
dtype = ndemon(atyp);
|
|
if (dtype == NON_PM) return;
|
|
}
|
|
|
|
while (cnt > 0) {
|
|
int mmflags = ((mons[dtype].geno & G_UNIQ) ? NO_MM_FLAGS : MM_ESUM|MM_NOCOUNTBIRTH);
|
|
mtmp = makemon(&mons[dtype], u.ux, u.uy, mmflags);
|
|
if (mtmp) {
|
|
if (mmflags&MM_ESUM)
|
|
mark_mon_as_summoned(mtmp, mon, ESUMMON_PERMANENT, 0);
|
|
|
|
if (dtype == PM_ANGEL) {
|
|
/* alignment should match the summoner */
|
|
add_mx(mtmp, MX_EMIN);
|
|
EMIN(mtmp)->min_align = atyp;
|
|
EMIN(mtmp)->godnum = gnum;
|
|
if(mon && mon->isminion) mtmp->isminion = TRUE;
|
|
mtmp->mpeaceful = mon && mon->mpeaceful;
|
|
}
|
|
|
|
/* some templates are passed from summoner to summon */
|
|
if (mon && (
|
|
get_template(mon) == FRACTURED ||
|
|
get_template(mon) == VAMPIRIC ||
|
|
get_template(mon) == PSEUDONATURAL ||
|
|
get_template(mon) == CRANIUM_RAT ||
|
|
get_template(mon) == MISTWEAVER ||
|
|
get_template(mon) == YELLOW_TEMPLATE ||
|
|
get_template(mon) == DREAM_LEECH ||
|
|
(get_template(mon) == MAD_TEMPLATE && is_angel(mtmp->data)) ||
|
|
(get_template(mon) == FALLEN_TEMPLATE && is_angel(mtmp->data))
|
|
) && mtemplate_accepts_mtyp(get_template(mon), mtmp->mtyp)
|
|
) {
|
|
set_template(mtmp, get_template(mon));
|
|
}
|
|
/* as are factions */
|
|
if (mon && mon->mfaction){
|
|
set_faction(mtmp, mon->mfaction);
|
|
}
|
|
if(!is_lord(mtmp->data) && !is_prince(mtmp->data)){
|
|
mtmp->mpeaceful = mon && mon->mpeaceful;
|
|
set_malign(mtmp);
|
|
}
|
|
}
|
|
cnt--;
|
|
}
|
|
}
|
|
|
|
struct monst *
|
|
summon_god_minion(int godnum, boolean talk)
|
|
{
|
|
aligntyp alignment = galign(godnum);
|
|
const int *minions = god_minions(godnum);
|
|
int mtyp=NON_PM, mlev, num = 0, first, last;
|
|
struct monst *mon;
|
|
|
|
mlev = level_difficulty();
|
|
|
|
for (first = 0; minions[first] != NON_PM; first++)
|
|
if (!(mvitals[minions[first]].mvflags & G_GONE && !In_quest(&u.uz)) && monstr[minions[first]] > mlev/2) break;
|
|
|
|
mlev = (mlev+u.ulevel)/2;
|
|
if(minions[first] == NON_PM){ //All minions too weak, or no minions
|
|
if(first == 0) return (struct monst *) 0;
|
|
else mtyp = minions[first-1];
|
|
}
|
|
else for (last = first; minions[last] != NON_PM; last++)
|
|
if (!(mvitals[minions[last]].mvflags & G_GONE && !In_quest(&u.uz))) {
|
|
/* consider it */
|
|
if(monstr[minions[last]] > mlev+5) break;
|
|
num += min(1,mons[minions[last]].geno & G_FREQ);
|
|
}
|
|
|
|
if(!num){ //All minions too strong, or gap between weak and strong minions
|
|
if(first == 0) return (struct monst *) 0;
|
|
else mtyp = minions[first-1];
|
|
}
|
|
/* Assumption: minions are presented in ascending order of strength. */
|
|
else{
|
|
for(num = rnd(num); num > 0; first++) if (!(mvitals[minions[first]].mvflags & G_GONE && !In_quest(&u.uz))) {
|
|
/* skew towards lower value monsters at lower exp. levels */
|
|
num -= min(1, mons[minions[first]].geno & G_FREQ);
|
|
if (num && adj_lev(&mons[minions[first]]) > (u.ulevel*2)) {
|
|
/* but not when multiple monsters are same level */
|
|
if (mons[first].mlevel != mons[first+1].mlevel)
|
|
num--;
|
|
}
|
|
}
|
|
first--; /* correct an off-by-one error */
|
|
mtyp = minions[first];
|
|
}
|
|
|
|
|
|
if (mtyp == NON_PM) {
|
|
mon = (struct monst *)0;
|
|
} else {
|
|
mon = makemon(&mons[mtyp], u.ux, u.uy, NO_MM_FLAGS);
|
|
if (mon) {
|
|
add_mx(mon, MX_EMIN);
|
|
mon->isminion = TRUE;
|
|
EMIN(mon)->min_align = alignment;
|
|
EMIN(mon)->godnum = godnum;
|
|
}
|
|
}
|
|
|
|
if (mon) {
|
|
if (talk) {
|
|
godvoice(godnum, "Thou shalt pay for thy indiscretion!");
|
|
if (!Blind)
|
|
pline("%s appears before you.", An(Hallucination ? rndmonnam() : mon->data->mname));
|
|
}
|
|
mon->mpeaceful = FALSE;
|
|
/* don't call set_malign(); player was naughty */
|
|
mon->msleeping = 0;
|
|
mon->mcanmove = 1;
|
|
|
|
/* fix house setting */
|
|
if(is_drow(mon->data)){
|
|
int faction = god_faction(godnum);
|
|
if (faction != -1) {
|
|
struct obj *otmp;
|
|
|
|
set_faction(mon, faction);
|
|
|
|
for(otmp = mon->minvent; otmp; otmp = otmp->nobj){
|
|
if(otmp->otyp == find_signet_ring() || is_readable_armor_otyp(otmp->otyp)){
|
|
otmp->oward = faction;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if(godnum == GOD_THE_DREAD_FRACTURE && !has_template(mon, FRACTURED)){
|
|
set_template(mon, FRACTURED);
|
|
mon->m_lev += 4;
|
|
mon->mhpmax = d(mon->m_lev, 8);
|
|
mon->mhp = mon->mhpmax;
|
|
newsym(mon->mx,mon->my);
|
|
}
|
|
}
|
|
|
|
return mon;
|
|
}
|
|
|
|
struct monst *
|
|
summon_minion(aligntyp alignment, boolean talk, boolean devils, boolean angels)
|
|
{
|
|
register struct monst *mon;
|
|
int mtyp;
|
|
|
|
switch ((int)alignment) {
|
|
case A_LAWFUL:
|
|
case A_VOID:
|
|
mtyp = devils ? ndemon(alignment) : lminion();
|
|
break;
|
|
case A_NEUTRAL:
|
|
mtyp = angels ? nminion() : (PM_AIR_ELEMENTAL + rn2(8));
|
|
break;
|
|
case A_CHAOTIC:
|
|
mtyp = angels ? cminion() : ndemon(alignment);
|
|
break;
|
|
case A_NONE:
|
|
mtyp = angels ? PM_FALLEN_ANGEL : ndemon(alignment);
|
|
break;
|
|
default:
|
|
// impossible("unaligned player?");
|
|
pline("Odd alignment in minion summoning: %d",(int)alignment);
|
|
mtyp = ndemon(A_NONE);
|
|
break;
|
|
}
|
|
if (mtyp == NON_PM) {
|
|
mon = 0;
|
|
} else {
|
|
mon = makemon(&mons[mtyp], u.ux, u.uy, MM_ESUM);
|
|
if (mon) {
|
|
add_mx(mon, MX_EMIN);
|
|
mon->isminion = TRUE;
|
|
EMIN(mon)->min_align = alignment;
|
|
EMIN(mon)->godnum = align_to_god(alignment);
|
|
|
|
mark_mon_as_summoned(mon, (struct monst *)0, ESUMMON_PERMANENT, 0);
|
|
}
|
|
}
|
|
if (mon) {
|
|
if (talk) {
|
|
pline_The("voice of %s booms:", align_gname(alignment));
|
|
verbalize("Thou shalt pay for thy indiscretion!");
|
|
if (!Blind)
|
|
pline("%s appears before you.", Amonnam(mon));
|
|
}
|
|
mon->mpeaceful = FALSE;
|
|
/* don't call set_malign(); player was naughty */
|
|
}
|
|
return mon;
|
|
}
|
|
|
|
#define Athome (Inhell && !mtmp->cham)
|
|
|
|
int
|
|
demon_talk( /* returns 1 if it won't attack. */
|
|
register struct monst *mtmp)
|
|
{
|
|
long cash, demand, offer;
|
|
|
|
if (uwep && (
|
|
uwep->oartifact == ART_EXCALIBUR
|
|
|| uwep->oartifact == ART_LANCE_OF_LONGINUS
|
|
) ) {
|
|
pline("%s looks very angry.", Amonnam(mtmp));
|
|
untame(mtmp, 0);
|
|
set_malign(mtmp);
|
|
newsym(mtmp->mx, mtmp->my);
|
|
return 0;
|
|
}
|
|
|
|
/* Slight advantage given. */
|
|
if ((is_dprince(mtmp->data) || is_dlord(mtmp->data)) && mtmp->minvis) {
|
|
mtmp->minvis = mtmp->perminvis = 0;
|
|
if (!Blind) pline("%s appears before you.", Amonnam(mtmp));
|
|
newsym(mtmp->mx,mtmp->my);
|
|
}
|
|
if (youracedata->mlet == S_DEMON) { /* Won't blackmail their own. */
|
|
pline("%s says, \"Good hunting, %s.\"",
|
|
Amonnam(mtmp), flags.female ? "Sister" : "Brother");
|
|
if (!tele_restrict(mtmp)) (void) rloc(mtmp, TRUE);
|
|
return(1);
|
|
}
|
|
#ifndef GOLDOBJ
|
|
cash = u.ugold;
|
|
#else
|
|
cash = money_cnt(invent);
|
|
#endif
|
|
demand = (cash * (rnd(80) + 20 * Athome)) /
|
|
(100 * (1 + (sgn(u.ualign.type) == sgn(mtmp->data->maligntyp))));
|
|
|
|
if (!demand) { /* you have no gold */
|
|
mtmp->mpeaceful = 0;
|
|
set_malign(mtmp);
|
|
newsym(mtmp->mx, mtmp->my);
|
|
return 0;
|
|
} else {
|
|
if(mtmp->mtyp == PM_ASMODEUS && demand < 9000) demand = 9000 + rn2(1000);
|
|
else if(demand < 2000) demand = max(1000+rnd(1000), demand); //demons can't be bribed with chump change.
|
|
/* make sure that the demand is unmeetable if the monster
|
|
has the Amulet, preventing monster from being satisified
|
|
and removed from the game (along with said Amulet...) */
|
|
if (mon_has_amulet(mtmp))
|
|
demand = cash + (long)rn1(1000,40);
|
|
|
|
pline("%s demands %ld %s for safe passage.",
|
|
Amonnam(mtmp), demand, currency(demand));
|
|
|
|
if ((offer = bribe(mtmp)) >= demand) {
|
|
pline("%s vanishes, laughing about cowardly mortals.",
|
|
Amonnam(mtmp));
|
|
} else if (offer > 0L && (long)rnd(40) > (demand - offer)) {
|
|
pline("%s scowls at you menacingly, then vanishes.",
|
|
Amonnam(mtmp));
|
|
} else {
|
|
pline("%s gets angry...", Amonnam(mtmp));
|
|
mtmp->mpeaceful = 0;
|
|
set_malign(mtmp);
|
|
newsym(mtmp->mx, mtmp->my);
|
|
return 0;
|
|
}
|
|
}
|
|
mongone(mtmp);
|
|
return(1);
|
|
}
|
|
|
|
long
|
|
bribe(struct monst *mtmp)
|
|
{
|
|
char buf[BUFSZ];
|
|
long offer;
|
|
#ifdef GOLDOBJ
|
|
long umoney = money_cnt(invent);
|
|
#endif
|
|
|
|
getlin("How much will you offer?", buf);
|
|
if (sscanf(buf, "%ld", &offer) != 1) offer = 0L;
|
|
|
|
/*Michael Paddon -- fix for negative offer to monster*/
|
|
/*JAR880815 - */
|
|
if (offer < 0L) {
|
|
You("try to shortchange %s, but fumble.",
|
|
mon_nam(mtmp));
|
|
return 0L;
|
|
} else if (offer == 0L) {
|
|
You("refuse.");
|
|
return 0L;
|
|
#ifndef GOLDOBJ
|
|
} else if (offer >= u.ugold) {
|
|
You("give %s all your gold.", mon_nam(mtmp));
|
|
offer = u.ugold;
|
|
} else {
|
|
You("give %s %ld %s.", mon_nam(mtmp), offer, currency(offer));
|
|
}
|
|
u.ugold -= offer;
|
|
mtmp->mgold += offer;
|
|
#else
|
|
} else if (offer >= umoney) {
|
|
You("give %s all your gold.", mon_nam(mtmp));
|
|
offer = umoney;
|
|
} else {
|
|
You("give %s %ld %s.", mon_nam(mtmp), offer, currency(offer));
|
|
}
|
|
(void) money2mon(mtmp, offer);
|
|
#endif
|
|
flags.botl = 1;
|
|
return(offer);
|
|
}
|
|
|
|
int demonPrinces[] = {
|
|
PM_DEMOGORGON,
|
|
PM_LAMASHTU,
|
|
PM_OBOX_OB,
|
|
PM_DAGON,
|
|
PM_PALE_NIGHT,
|
|
PM_ORCUS,
|
|
PM_GRAZ_ZT,
|
|
PM_MALCANTHET
|
|
};
|
|
|
|
int
|
|
dprince(struct permonst *ptr, aligntyp atyp)
|
|
{
|
|
int tryct, pm;
|
|
boolean check_alliances = TRUE;
|
|
|
|
if (!ptr) check_alliances = FALSE;
|
|
|
|
if (check_alliances){
|
|
/*Specific alliances go here*/
|
|
if(ptr->mtyp == PM_BAPHOMET && !(mvitals[PM_PALE_NIGHT].mvflags & G_GONE))
|
|
return PM_PALE_NIGHT;
|
|
if(ptr->mtyp == PM_PALE_NIGHT && !(mvitals[PM_ASCODEL].mvflags & G_GONE) && !rn2(4))
|
|
return PM_ASCODEL;
|
|
if(ptr->mtyp == PM_PALE_NIGHT && !(mvitals[PM_GRAZ_ZT].mvflags & G_GONE))
|
|
return PM_GRAZ_ZT;
|
|
if(ptr->mtyp == PM_DEMOGORGON && !(mvitals[PM_DAGON].mvflags & G_GONE))
|
|
return PM_DAGON;
|
|
}
|
|
if(atyp == A_NONE) atyp = !rn2(3) ? A_LAWFUL : A_CHAOTIC;
|
|
|
|
if(atyp == A_LAWFUL){
|
|
if(!(mvitals[PM_ASMODEUS].mvflags & G_GONE)) return PM_ASMODEUS;
|
|
else return dlord(ptr, atyp);
|
|
} else if(atyp == A_CHAOTIC) {
|
|
for (tryct = 0; tryct < 20; tryct++) {
|
|
pm = demonPrinces[rn2(SIZE(demonPrinces))];
|
|
|
|
if (mvitals[pm].mvflags & G_GONE)
|
|
continue;
|
|
|
|
if (check_alliances && (
|
|
(ptr->mtyp == PM_GRAZ_ZT && pm == PM_MALCANTHET) ||
|
|
(ptr->mtyp == PM_MALCANTHET && pm == PM_GRAZ_ZT) ||
|
|
(ptr->mtyp == PM_OBOX_OB && pm == PM_DEMOGORGON) ||
|
|
(ptr->mtyp == PM_DEMOGORGON && pm == PM_OBOX_OB) ||
|
|
(ptr->mtyp == PM_LAMASHTU && pm == PM_DEMOGORGON) ||
|
|
(ptr->mtyp == PM_DEMOGORGON && pm == PM_LAMASHTU))
|
|
)
|
|
continue;
|
|
|
|
return(pm);
|
|
}
|
|
}
|
|
return(dlord(ptr, atyp)); /* approximate */
|
|
}
|
|
|
|
int demonLords[] = {
|
|
PM_YEENOGHU,
|
|
PM_BAPHOMET,
|
|
PM_KOSTCHTCHIE,
|
|
PM_ZUGGTMOY,
|
|
PM_JUIBLEX,
|
|
PM_ALRUNES,
|
|
PM_ALDINACH
|
|
};
|
|
|
|
int lordsOfTheNine[] = {
|
|
PM_MEPHISTOPHELES,
|
|
PM_BAALZEBUB,
|
|
PM_CRONE_LILITH,
|
|
PM_CREATURE_IN_THE_ICE,
|
|
PM_BELIAL,
|
|
PM_MAMMON,
|
|
PM_DISPATER,
|
|
PM_BAEL
|
|
};
|
|
|
|
int
|
|
dlord(struct permonst *ptr, aligntyp atyp)
|
|
{
|
|
int tryct, pm;
|
|
boolean check_alliances = TRUE;
|
|
|
|
if (!ptr) check_alliances = FALSE;
|
|
|
|
if (check_alliances){
|
|
/*Specific alliances go here*/
|
|
if(ptr->mtyp == PM_MEPHISTOPHELES && !(mvitals[PM_BAALPHEGOR].mvflags & G_GONE))
|
|
return PM_BAALPHEGOR;
|
|
if(ptr->mtyp == PM_CRONE_LILITH && !(mvitals[PM_MOTHER_LILITH].mvflags & G_GONE))
|
|
return PM_MOTHER_LILITH;
|
|
if(ptr->mtyp == PM_CRONE_LILITH && !(mvitals[PM_DAUGHTER_LILITH].mvflags & G_GONE))
|
|
return PM_DAUGHTER_LILITH;
|
|
if(ptr->mtyp == PM_MOTHER_LILITH && !(mvitals[PM_DAUGHTER_LILITH].mvflags & G_GONE))
|
|
return PM_DAUGHTER_LILITH;
|
|
if(ptr->mtyp == PM_BELIAL && !(mvitals[PM_FIERNA].mvflags & G_GONE))
|
|
return PM_FIERNA;
|
|
if(ptr->mtyp == PM_MAMMON && !(mvitals[PM_GLASYA].mvflags & G_GONE) && !rn2(20))
|
|
return PM_GLASYA;
|
|
|
|
if(ptr->mtyp == PM_PALE_NIGHT && !(mvitals[PM_BAPHOMET].mvflags & G_GONE))
|
|
return PM_BAPHOMET;
|
|
if(ptr->mtyp == PM_OBOX_OB && !(mvitals[PM_ALDINACH].mvflags & G_GONE))
|
|
return PM_ALDINACH;
|
|
}
|
|
if(atyp == A_NONE) atyp = rn2(2) ? A_LAWFUL : A_CHAOTIC;
|
|
|
|
if(atyp == A_LAWFUL){
|
|
for (tryct = 0; tryct < 20; tryct++) {
|
|
pm = lordsOfTheNine[rn2(SIZE(lordsOfTheNine))];
|
|
if(pm == PM_CRONE_LILITH) pm = !rn2(3) ? PM_CRONE_LILITH : !rn2(2) ? PM_MOTHER_LILITH : PM_DAUGHTER_LILITH;
|
|
|
|
if (mvitals[pm].mvflags & G_GONE)
|
|
continue;
|
|
|
|
if (check_alliances && (
|
|
(ptr->mtyp == PM_MEPHISTOPHELES && pm == PM_BAALZEBUB) ||
|
|
(ptr->mtyp == PM_BAALZEBUB && pm == PM_MEPHISTOPHELES))
|
|
)
|
|
continue;
|
|
|
|
if(pm == PM_CREATURE_IN_THE_ICE){
|
|
mvitals[pm].mvflags |= G_GONE;
|
|
pm = rn2(2) ? PM_LEVISTUS : PM_LEVIATHAN;
|
|
}
|
|
|
|
return(pm);
|
|
}
|
|
} else if(atyp == A_CHAOTIC) {
|
|
for (tryct = 0; tryct < 20; tryct++) {
|
|
pm = demonLords[rn2(SIZE(demonLords))];
|
|
|
|
if (mvitals[pm].mvflags & G_GONE)
|
|
continue;
|
|
|
|
if (check_alliances && (
|
|
(ptr->mtyp == PM_BAPHOMET && pm == PM_YEENOGHU) ||
|
|
(ptr->mtyp == PM_YEENOGHU && pm == PM_BAPHOMET) ||
|
|
(ptr->mtyp == PM_ZUGGTMOY && pm == PM_JUIBLEX) ||
|
|
(ptr->mtyp == PM_JUIBLEX && pm == PM_ZUGGTMOY))
|
|
)
|
|
continue;
|
|
|
|
return(pm);
|
|
}
|
|
}
|
|
|
|
return(ndemon(atyp)); /* approximate */
|
|
}
|
|
|
|
/* create lawful (good) lord */
|
|
int
|
|
llord(void)
|
|
{
|
|
switch(rnd(2)){
|
|
case 1:
|
|
if (!(mvitals[PM_THRONE_ARCHON].mvflags & G_GONE && !In_quest(&u.uz)))
|
|
return(PM_THRONE_ARCHON);
|
|
break;
|
|
case 2:
|
|
if (!(mvitals[PM_LIGHT_ARCHON].mvflags & G_GONE && !In_quest(&u.uz)))
|
|
return(PM_LIGHT_ARCHON);
|
|
break;
|
|
}
|
|
|
|
return(lminion()); /* approximate */
|
|
}
|
|
|
|
int
|
|
lminion(void)
|
|
{
|
|
int tryct;
|
|
struct permonst *ptr;
|
|
|
|
for (tryct = 0; tryct < 20; tryct++) {
|
|
ptr = mkclass(S_LAW_ANGEL,G_NOHELL|G_HELL|G_PLANES);
|
|
if (ptr && !is_lord(ptr) && is_angel(ptr))
|
|
return(monsndx(ptr));
|
|
}
|
|
|
|
return NON_PM;
|
|
}
|
|
|
|
/* create neutral (good) lord */
|
|
int
|
|
nlord(void)
|
|
{
|
|
switch(rnd(4)){
|
|
case 1:
|
|
if (!(mvitals[PM_MAHADEVA].mvflags & G_GONE && !In_quest(&u.uz)))
|
|
return(PM_MAHADEVA);
|
|
break;
|
|
case 2:
|
|
case 3:
|
|
case 4:
|
|
if (!(mvitals[PM_SURYA_DEVA].mvflags & G_GONE && !In_quest(&u.uz)))
|
|
return(PM_SURYA_DEVA);
|
|
break;
|
|
}
|
|
|
|
return(nminion()); /* approximate */
|
|
}
|
|
|
|
int
|
|
nminion(void)
|
|
{
|
|
int tryct;
|
|
struct permonst *ptr;
|
|
|
|
for (tryct = 0; tryct < 20; tryct++) {
|
|
ptr = mkclass(S_NEU_ANGEL,G_NOHELL|G_HELL|G_PLANES);
|
|
if (ptr && !is_lord(ptr) && is_angel(ptr))
|
|
return(monsndx(ptr));
|
|
}
|
|
|
|
return NON_PM;
|
|
}
|
|
|
|
/* create chaotic (good) lord */
|
|
int
|
|
clord(void)
|
|
{
|
|
if (!(mvitals[PM_TULANI_ELADRIN].mvflags & G_GONE && !In_quest(&u.uz)))
|
|
return(PM_TULANI_ELADRIN);
|
|
|
|
return(cminion()); /* approximate */
|
|
}
|
|
|
|
int
|
|
cminion(void)
|
|
{
|
|
int tryct;
|
|
struct permonst *ptr;
|
|
|
|
for (tryct = 0; tryct < 20; tryct++) {
|
|
ptr = mkclass(S_CHA_ANGEL,G_NOHELL|G_HELL|G_PLANES);
|
|
if (ptr && !is_lord(ptr) && is_angel(ptr))
|
|
return(monsndx(ptr));
|
|
}
|
|
|
|
return NON_PM;
|
|
}
|
|
|
|
int
|
|
ndemon(aligntyp atyp)
|
|
{
|
|
int tryct;
|
|
struct permonst *ptr;
|
|
|
|
for (tryct = 0; tryct < 20; tryct++) {
|
|
ptr = mkclass(S_DEMON, G_NOHELL|G_HELL);
|
|
if (ptr && is_normal_demon(ptr) &&
|
|
(atyp == A_NONE || sgn(ptr->maligntyp) == sgn(atyp)))
|
|
return(monsndx(ptr));
|
|
}
|
|
|
|
return NON_PM;
|
|
}
|
|
|
|
/*minion.c*/
|