struct monst * mk_roamer(const struct permonst *ptr, aligntyp alignment, struct level *lev, xchar x, xchar y, boolean peaceful, int mm_flags) { struct monst *roamer; boolean coaligned = (u.ualign.type == alignment); if (ptr != &mons[PM_ALIGNED_PRIEST] && ptr != &mons[PM_ANGEL]) return NULL; if (MON_AT(lev, x, y)) rloc(m_at(lev, x, y), FALSE); /* insurance */ if (!(roamer = makemon(ptr, lev, x, y, mm_flags))) return NULL; EPRI(roamer)->shralign = alignment; if (coaligned && !peaceful) EPRI(roamer)->renegade = TRUE; /* roamer->ispriest == FALSE naturally */ roamer->isminion = TRUE; /* borrowing this bit */ roamer->mtrapseen = ~0; /* traps are known */ msethostility(roamer, !peaceful, TRUE); /* TODO: handle in_mklev */ roamer->msleeping = 0; /* MORE TO COME */ return roamer; }
void angry_priest(void) { struct monst *priest; struct rm *loc; if ((priest = findpriest(temple_occupied(u.urooms))) != 0) { wakeup(priest, FALSE); /* * If the altar has been destroyed or converted, let the * priest run loose. * (When it's just a conversion and there happens to be * a fresh corpse nearby, the priest ought to have an * opportunity to try converting it back; maybe someday...) */ loc = &level->locations [CONST_EPRI(priest)->shrpos.x][CONST_EPRI(priest)->shrpos.y]; if (!IS_ALTAR(loc->typ) || ((aligntyp) Amask2align(loc->altarmask & AM_MASK) != CONST_EPRI(priest)->shralign)) { priest->ispriest = 0; /* now a roamer */ priest->isminion = 1; /* but still aligned */ /* this overloads the `shroom' field, which is now clobbered */ EPRI(priest)->renegade = 0; } } }
/* munge priest-specific structure when restoring -dlc */ void restpriest(struct monst *mtmp, boolean ghostly) { if (u.uz.dlevel) { if (ghostly) assign_level(&(EPRI(mtmp)->shrlevel), &u.uz); } }
/* check whether monster can arrive at location <x,y> via Tport (or fall) */ static boolean rloc_pos_ok(int x, int y, /* coordinates of candidate location */ struct monst *mtmp) { int xx, yy; if (!goodpos(level, x, y, mtmp, 0)) return FALSE; /* * Check for restricted areas present in some special levels. * * `xx' is current column; if 0, then `yy' will contain flag bits * rather than row: bit #0 set => moving upwards; bit #1 set => * inside the Wizard's tower. */ xx = mtmp->mx; yy = mtmp->my; if (!xx) { /* no current location (migrating monster arrival) */ if (level->dndest.nlx && On_W_tower_level(&u.uz)) return ((yy & 2) != 0) ^ /* inside xor not within */ !within_bounded_area(x, y, level->dndest.nlx, level->dndest.nly, level->dndest.nhx, level->dndest.nhy); if (level->updest.lx && (yy & 1) != COLNO) /* moving up */ return (within_bounded_area (x, y, level->updest.lx, level->updest.ly, level->updest.hx, level->updest.hy) && (!level->updest.nlx || !within_bounded_area( x, y, level->updest.nlx, level->updest.nly, level->updest.nhx, level->updest.nhy))); if (level->dndest.lx && (yy & 1) == COLNO) /* moving down */ return (within_bounded_area (x, y, level->dndest.lx, level->dndest.ly, level->dndest.hx, level->dndest.hy) && (!level->dndest.nlx || !within_bounded_area( x, y, level->dndest.nlx, level->dndest.nly, level->dndest.nhx, level->dndest.nhy))); } else { /* [try to] prevent a shopkeeper or temple priest from being sent out of his room (caller might resort to goodpos() if we report failure here, so this isn't full prevention) */ if (mtmp->isshk && inhishop(mtmp)) { if (level->locations[x][y].roomno != ESHK(mtmp)->shoproom) return FALSE; } else if (mtmp->ispriest && inhistemple(mtmp)) { if (level->locations[x][y].roomno != EPRI(mtmp)->shroom) return FALSE; } /* current location is <xx,yy> */ if (!tele_jump_ok(xx, yy, x, y)) return FALSE; } /* <x,y> is ok */ return TRUE; }
void reset_hostility(struct monst *roamer) { if (! (roamer->isminion && (roamer->data == &mons[PM_ALIGNED_PRIEST] || roamer->data == &mons[PM_ANGEL]))) return; if (EPRI(roamer)->shralign != u.ualign.type) msethostility(roamer, TRUE, TRUE); }
void summon_minion(aligntyp alignment, boolean talk) { struct monst *mon; int mnum; switch ((int)alignment) { case A_LAWFUL: mnum = lminion(); break; case A_NEUTRAL: mnum = PM_AIR_ELEMENTAL + rn2(4); break; case A_CHAOTIC: case A_NONE: mnum = ndemon(&u.uz, alignment); break; default: impossible("unaligned player?"); mnum = ndemon(&u.uz, A_NONE); break; } if (mnum == NON_PM) { mon = 0; } else if (mons[mnum].pxtyp == MX_NONE) { const struct permonst *pm = &mons[mnum]; mon = makemon(pm, level, u.ux, u.uy, MM_EMIN); if (mon) { mon->isminion = TRUE; EMIN(mon)->min_align = alignment; } } else if (roamer_type(&mons[mnum])) { mon = makemon(&mons[mnum], level, u.ux, u.uy, NO_MM_FLAGS); if (mon) { mon->isminion = TRUE; EPRI(mon)->shralign = alignment; } } else mon = makemon(&mons[mnum], level, u.ux, u.uy, NO_MM_FLAGS); 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 */ } }
/* mon summons a monster */ void msummon(struct monst *mon) { const struct permonst *ptr; int dtype = NON_PM, cnt = 0; aligntyp atyp; struct monst *mtmp; struct d_level *dlev; if (mon) { ptr = mon->data; dlev = &mon->dlevel->z; atyp = (ptr->maligntyp == A_NONE) ? A_NONE : sgn(ptr->maligntyp); if (mon->ispriest || roamer_type(mon->data)) atyp = EPRI(mon)->shralign; } else { ptr = &mons[PM_WIZARD_OF_YENDOR]; atyp = (ptr->maligntyp == A_NONE) ? A_NONE : sgn(ptr->maligntyp); dlev = &u.uz; } if (is_dprince(ptr) || (ptr == &mons[PM_WIZARD_OF_YENDOR])) { dtype = (!rn2(20)) ? dprince(atyp) : (!rn2(4)) ? dlord(atyp) : ndemon(dlev, atyp); cnt = (!rn2(4) && is_ndemon(&mons[dtype])) ? 2 : 1; } else if (is_dlord(ptr)) { dtype = (!rn2(50)) ? dprince(atyp) : (!rn2(20)) ? dlord(atyp) : ndemon(dlev, atyp); cnt = (!rn2(4) && is_ndemon(&mons[dtype])) ? 2 : 1; } else if (is_ndemon(ptr)) { dtype = (!rn2(20)) ? dlord(atyp) : (!rn2(6)) ? ndemon(dlev, atyp) : monsndx(ptr); cnt = 1; } else if (mon && is_lminion(mon)) { dtype = (is_lord(ptr) && !rn2(20)) ? llord() : (is_lord(ptr) || !rn2(6)) ? lminion() : monsndx(ptr); cnt = (!rn2(4) && !is_lord(&mons[dtype])) ? 2 : 1; } else if (ptr == &mons[PM_ANGEL]) { /* non-lawful angels can also summon */ if (!rn2(6)) { switch (atyp) { /* see summon_minion */ case A_NEUTRAL: dtype = PM_AIR_ELEMENTAL + rn2(4); break; case A_CHAOTIC: case A_NONE: dtype = ndemon(dlev, atyp); break; } } 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(dlev, atyp); if (dtype == NON_PM) return; } while (cnt > 0) { mtmp = makemon(&mons[dtype], level, u.ux, u.uy, NO_MM_FLAGS); if (mtmp && roamer_type(&mons[dtype])) { /* alignment should match the summoner */ EPRI(mtmp)->shralign = atyp; } cnt--; } }
/* exclusively for mktemple(); uses level creation RNG */ void priestini(struct level *lev, struct mkroom *sroom, int sx, int sy, boolean sanctum) { /* is it the seat of the high priest? */ struct monst *priest = NULL; struct obj *otmp; int cnt; coord *priest_pos, pos_array[] = { { sx + 1, sy }, { sx - 1, sy }, { sx, sy + 1 }, { sx, sy - 1 }, { sx, sy }, { COLNO, ROWNO }, }; /* Search for a good position for the priest. The -1 in the array bound is * to ensure that we stop on the { COLNO, ROWNO } entry which is not ok. Do * not pass a monster to goodpos(), because we will move any monster later. */ for (priest_pos = pos_array; !goodpos(lev, priest_pos->x, priest_pos->y, NULL, 0) && (priest_pos < pos_array + ARRAY_SIZE(pos_array) - 1); ++priest_pos) {} if (!isok(priest_pos->x, priest_pos->y)) { impossible("Unable to find location for priest in shrine"); } else { if (MON_AT(lev, priest_pos->x, priest_pos->y)) rloc(m_at(lev, priest_pos->x, priest_pos->y), FALSE); priest = makemon(&mons[sanctum ? PM_HIGH_PRIEST : PM_ALIGNED_PRIEST], lev, priest_pos->x, priest_pos->y, MM_ALLLEVRNG); } if (priest) { EPRI(priest)->shroom = (sroom - lev->rooms) + ROOMOFFSET; EPRI(priest)->shralign = Amask2align(lev->locations[sx][sy].altarmask); EPRI(priest)->shrpos.x = sx; EPRI(priest)->shrpos.y = sy; assign_level(&(EPRI(priest)->shrlevel), &lev->z); priest->mtrapseen = ~0; /* traps are known */ priest->mpeaceful = 1; priest->ispriest = 1; priest->msleeping = 0; set_malign(priest); /* mpeaceful may have changed */ /* now his/her goodies... */ if (sanctum && CONST_EPRI(priest)->shralign == A_NONE && on_level(&sanctum_level, &lev->z)) { mongets(priest, AMULET_OF_YENDOR, rng_for_level(&lev->z)); } /* 2 to 4 spellbooks */ for (cnt = rn1(3, 2); cnt > 0; --cnt) { mpickobj(priest, mkobj(level, SPBOOK_CLASS, FALSE, rng_for_level(&lev->z))); } /* robe [via makemon()] */ if (mklev_rn2(2, lev) && (otmp = which_armor(priest, os_armc)) != 0) { if (p_coaligned(priest)) uncurse(otmp); else curse(otmp); } } }