mirror of
https://codeberg.org/noisytoot/notnotdnethack.git
synced 2025-07-26 23:32:25 +01:00
mon.c 3.8
tabbing fixes Temporary monsters shouldn't leave corpses Increase nudziarth mirror frequency Add mercurial dragons to dragon list Straw Golems leave sheafs of hay Shieres attack in elf form and flee in light form Disturbed Uvuudaums return to their meditation if they have full hp Watcher tentacle movement restrictions Tame monsters don't attack peaceful monsters and vice versa Handle drow vs drow aggression. Even pets won't attack drow of matching house. On some quests, drow of your faction will attack quest enemies Drow attack drow of other houses Drow attack elves Drow attack edderkops NOTE: Eladrin do not return to any form in particular after death. Drow general quest leader has to create the bell as they die Illurien returns Initial nemesis always leaves a corpse Aklys valid for small monsters Attacking the quest entorage angers the old quest leader noisy waking function confuses, stuns, and counts as injuring monsters with sensitive ears (so just grimlocks, at least for now) Hunting horrors have long tails
This commit is contained in:
parent
a47d8c1ab3
commit
b2b3c942d1
1 changed files with 283 additions and 157 deletions
168
src/mon.c
168
src/mon.c
|
@ -222,13 +222,18 @@ register struct monst *mtmp;
|
|||
int mndx = monsndx(mdat);
|
||||
struct obj *otmp;
|
||||
|
||||
if(u.specialSealsActive&SEAL_NUDZIARTH && !rn2(100)){
|
||||
if(mtmp->mvanishes > -1){
|
||||
return (struct obj *)0;
|
||||
}
|
||||
|
||||
if(u.specialSealsActive&SEAL_NUDZIARTH && !rn2(4)){
|
||||
(void) mksobj_at(MIRROR, x, y, TRUE, FALSE);
|
||||
}
|
||||
|
||||
switch(mndx) {
|
||||
case PM_GRAY_DRAGON:
|
||||
case PM_SILVER_DRAGON:
|
||||
case PM_MERCURIAL_DRAGON:
|
||||
case PM_SHIMMERING_DRAGON:
|
||||
case PM_DEEP_DRAGON:
|
||||
case PM_RED_DRAGON:
|
||||
|
@ -517,6 +522,12 @@ register struct monst *mtmp;
|
|||
obj = mksobj_at(SCR_BLANK_PAPER, x, y, TRUE, FALSE);
|
||||
mtmp->mnamelth = 0;
|
||||
break;
|
||||
case PM_STRAW_GOLEM:
|
||||
obj = mksobj_at(SHEAF_OF_HAY, x, y, FALSE, FALSE);
|
||||
obj->quan = (long)(d(2,4));
|
||||
obj->owt = weight(obj);
|
||||
mtmp->mnamelth = 0;
|
||||
break;
|
||||
case PM_SPELL_GOLEM:{
|
||||
int scrnum = 0;
|
||||
int scrrng = SCR_STINKING_CLOUD-SCR_ENCHANT_ARMOR;
|
||||
|
@ -806,6 +817,9 @@ mcalcdistress()
|
|||
/* regenerate hit points */
|
||||
mon_regen(mtmp, FALSE);
|
||||
|
||||
if(mtmp->data == &mons[PM_BALL_OF_LIGHT]) mtmp->mflee = 1;
|
||||
else if(mtmp->data == &mons[PM_SHIERE]) mtmp->mflee = 0;
|
||||
|
||||
/* possibly polymorph shapechangers and lycanthropes */
|
||||
if (mtmp->cham && !rn2(6))
|
||||
(void) newcham(mtmp, (struct permonst *)0, FALSE, FALSE);
|
||||
|
@ -997,14 +1011,19 @@ movemon()
|
|||
if(canseemon(mtmp)) pline("%s gets angry...", mon_nam(mtmp));
|
||||
mtmp->mpeaceful = 0;
|
||||
}
|
||||
if(u.uevent.udemigod &&
|
||||
mtmp->data == &mons[PM_UVUUDAUM] &&
|
||||
mtmp->mpeaceful
|
||||
){
|
||||
pline("%s shakes off it's torpor...", Amonnam(mtmp));
|
||||
if(mtmp->data == &mons[PM_UVUUDAUM]){
|
||||
if(u.uevent.udemigod){
|
||||
if(mtmp->mpeaceful){
|
||||
pline("%s ceases its meditation...", Amonnam(mtmp));
|
||||
mtmp->mpeaceful = 0;
|
||||
set_malign(mtmp);
|
||||
}
|
||||
} else if(!mtmp->mpeaceful && mtmp->mhp == mtmp->mhpmax && mtmp->m_lev >= 15){
|
||||
pline("%s resumes its meditation...", Amonnam(mtmp));
|
||||
mtmp->mpeaceful = 1;
|
||||
set_malign(mtmp);
|
||||
}
|
||||
}
|
||||
|
||||
if (vision_full_recalc) vision_recalc(0); /* vision! */
|
||||
|
||||
|
@ -1419,6 +1438,7 @@ mfndpos(mon, poss, info, flag)
|
|||
long flag;
|
||||
{
|
||||
struct permonst *mdat = mon->data;
|
||||
struct monst *witw = 0;
|
||||
register xchar x,y,nx,ny;
|
||||
register int cnt = 0;
|
||||
register uchar ntyp;
|
||||
|
@ -1427,6 +1447,10 @@ mfndpos(mon, poss, info, flag)
|
|||
boolean rockok = FALSE, treeok = FALSE, thrudoor;
|
||||
int maxx, maxy;
|
||||
|
||||
if(mdat == &mons[PM_SWARM_OF_SNAKING_TENTACLES] || mdat == &mons[PM_LONG_SINUOUS_TENTACLE]){
|
||||
for(witw = fmon; witw; witw = witw->nmon) if(witw->data == &mons[PM_WATCHER_IN_THE_WATER]) break;
|
||||
} else witw = 0;
|
||||
|
||||
x = mon->mx;
|
||||
y = mon->my;
|
||||
nowtyp = levl[x][y].typ;
|
||||
|
@ -1504,6 +1528,11 @@ nexttry: /* eels prefer the water, but if there is no water nearby,
|
|||
) if(x + xdir[(int)mon->mextra[0]] != nx ||
|
||||
y + ydir[(int)mon->mextra[0]] != ny
|
||||
) continue;
|
||||
if(mdat == &mons[PM_WATCHER_IN_THE_WATER] &&
|
||||
distmin(nx, ny, mon->mux, mon->muy) <= 3 &&
|
||||
dist2(nx, ny, mon->mux, mon->muy) <= dist2(mon->mx, mon->my, mon->mux, mon->muy)) continue;
|
||||
if(witw && dist2(nx, ny, witw->mx, witw->my) > 32 &&
|
||||
dist2(nx, ny, witw->mx, witw->my) >= dist2(mon->mx, mon->my, witw->mx, witw->my)) continue;
|
||||
if(mdat == &mons[PM_HOOLOOVOO] &&
|
||||
IS_WALL(levl[mon->mx][mon->my].typ) &&
|
||||
!IS_WALL(levl[nx][ny].typ)
|
||||
|
@ -1656,6 +1685,10 @@ struct monst *magr, /* monster that is currently deciding where to move */
|
|||
ma = magr->data;
|
||||
md = mdef->data;
|
||||
|
||||
if(magr->mpeaceful && mdef->mpeaceful && (magr->mtame || mdef->mtame)) return 0L;
|
||||
|
||||
if(is_drow(ma) && is_drow(md) && (magr->mfaction == mdef->mfaction)) return 0L;
|
||||
|
||||
if (u.sowdisc && !mdef->mtame)
|
||||
return ALLOW_M|ALLOW_TM;
|
||||
/* supposedly purple worms are attracted to shrieking because they
|
||||
|
@ -1686,7 +1719,9 @@ struct monst *magr, /* monster that is currently deciding where to move */
|
|||
if( (ma->msound==MS_GUARDIAN
|
||||
|| (Role_if(PM_NOBLEMAN) && (ma == &mons[PM_KNIGHT] || ma == &mons[PM_MAID] || ma == &mons[PM_PEASANT]) && magr->mpeaceful)
|
||||
|| (Role_if(PM_KNIGHT) && ma == &mons[PM_KNIGHT] && magr->mpeaceful)
|
||||
|| (Race_if(PM_DROW) && is_drow(ma) && magr->mfaction == u.uhouse)
|
||||
)
|
||||
&& !((Race_if(PM_DROW) && !flags.stag && !Role_if(PM_NOBLEMAN)) || !is_drow(md))
|
||||
&& magr->mpeaceful==TRUE
|
||||
&& mdef->mpeaceful==FALSE
|
||||
) return ALLOW_M|ALLOW_TM;
|
||||
|
@ -1694,7 +1729,9 @@ struct monst *magr, /* monster that is currently deciding where to move */
|
|||
if( (md->msound == MS_GUARDIAN
|
||||
|| (Role_if(PM_NOBLEMAN) && (md == &mons[PM_KNIGHT] || md == &mons[PM_MAID] || md == &mons[PM_PEASANT]) && mdef->mpeaceful)
|
||||
|| (Role_if(PM_KNIGHT) && md == &mons[PM_KNIGHT] && mdef->mpeaceful)
|
||||
|| (Race_if(PM_DROW) && is_drow(md) && mdef->mfaction == u.uhouse)
|
||||
)
|
||||
&& !((Race_if(PM_DROW) && !flags.stag && !Role_if(PM_NOBLEMAN)) || !is_drow(ma))
|
||||
&& mdef->mpeaceful==TRUE
|
||||
&& magr->mpeaceful==FALSE
|
||||
&& rn2(2)
|
||||
|
@ -1708,14 +1745,43 @@ struct monst *magr, /* monster that is currently deciding where to move */
|
|||
return ALLOW_M|ALLOW_TM;
|
||||
|
||||
/* elves vs. drow */
|
||||
if( is_elf(ma) && is_elf(md) && is_drow(ma) != is_drow(md))
|
||||
if( (is_elf(ma) || is_elf(md)) && (is_drow(ma) || is_drow(md)) && magr->mfaction != EILISTRAEE_SYMBOL && mdef->mfaction != EILISTRAEE_SYMBOL)
|
||||
return ALLOW_M|ALLOW_TM;
|
||||
|
||||
/* drow vs. other drow */
|
||||
/* Note that factions may be different than the displayed house name,
|
||||
as faction is set during generation and displayed house name goes by equipment! */
|
||||
if( is_drow(ma) && is_drow(md) && magr->mfaction != mdef->mfaction)
|
||||
if( is_drow(ma) && is_drow(md) &&
|
||||
magr->mfaction != mdef->mfaction
|
||||
){
|
||||
int f1 = magr->mfaction, f2 = mdef->mfaction;
|
||||
boolean truce1 = FALSE, truce2 = FALSE;
|
||||
|
||||
if((f1 >= FIRST_GODDESS && f1 <= LAST_GODDESS) ||
|
||||
(f1 >= FIRST_TOWER && f1 <= LAST_TOWER)
|
||||
) truce1 = TRUE;
|
||||
|
||||
if((f2 >= FIRST_GODDESS && f2 <= LAST_GODDESS) ||
|
||||
(f2 >= FIRST_TOWER && f2 <= LAST_TOWER)
|
||||
) truce2 = TRUE;
|
||||
|
||||
if((f1 == XAXOX || f1 == EDDER_SYMBOL) && (f2 == XAXOX || f2 == EDDER_SYMBOL));
|
||||
else if(!truce1 && !truce2) return ALLOW_M|ALLOW_TM;
|
||||
else if(truce1 && truce2);
|
||||
else if(truce1 && !(f2 <= LAST_HOUSE && f2 >= FIRST_HOUSE))
|
||||
return ALLOW_M|ALLOW_TM;
|
||||
else if(truce2 && !(f1 <= LAST_HOUSE && f1 >= FIRST_HOUSE))
|
||||
return ALLOW_M|ALLOW_TM;
|
||||
}
|
||||
|
||||
/* drow vs. edderkops */
|
||||
if(is_drow(ma) && magr->mfaction != XAXOX && magr->mfaction != EDDER_SYMBOL && md == &mons[PM_EDDERKOP]){
|
||||
return ALLOW_M|ALLOW_TM;
|
||||
}
|
||||
/* and vice versa */
|
||||
if(is_drow(md) && mdef->mfaction != XAXOX && mdef->mfaction != EDDER_SYMBOL && ma == &mons[PM_EDDERKOP]){
|
||||
return ALLOW_M|ALLOW_TM;
|
||||
}
|
||||
|
||||
/* Nazgul vs. hobbits */
|
||||
if(ma == &mons[PM_NAZGUL] && md == &mons[PM_HOBBIT])
|
||||
|
@ -2106,7 +2172,15 @@ boolean was_swallowed; /* digestion */
|
|||
{
|
||||
struct permonst *mdat = mon->data;
|
||||
int i, tmp;
|
||||
|
||||
if(Race_if(PM_DROW) && !Role_if(PM_NOBLEMAN) && mdat == &mons[urole.neminum] && !flags.made_bell){
|
||||
(void) mksobj_at(BELL_OF_OPENING, mon->mx, mon->my, TRUE, FALSE);
|
||||
flags.made_bell = TRUE;
|
||||
if(mdat == &mons[PM_ECLAVDRA]) return FALSE;
|
||||
}
|
||||
if(mdat == &mons[PM_ILLURIEN_OF_THE_MYRIAD_GLIMPSES] && !(u.uevent.ukilled_illurien)){
|
||||
u.uevent.ukilled_illurien = 1;
|
||||
u.ill_cnt = rn1(1000, 250);
|
||||
}
|
||||
if (mdat == &mons[PM_VLAD_THE_IMPALER]) {
|
||||
livelog_write_string("destroyed Vlad the Impaler");
|
||||
if (cansee(mon->mx, mon->my) && !was_swallowed)
|
||||
|
@ -2236,17 +2310,28 @@ boolean was_swallowed; /* digestion */
|
|||
explode(mon->mx+x, mon->my+y, 8, tmp, -1, rn2(7)); //-1 is unspecified source. 8 is physical
|
||||
}
|
||||
tmp=0;
|
||||
}
|
||||
else if(mdat->mattk[i].adtyp == AD_SPNL){
|
||||
} else if(mdat->mattk[i].adtyp == AD_SPNL){
|
||||
explode(mon->mx, mon->my, 2, tmp, MON_EXPLODE, EXPL_WET);
|
||||
makemon(&mons[PM_LEVIATHAN], mon->mx, mon->my, MM_ADJACENTOK);
|
||||
}
|
||||
else if(mdat == &mons[PM_ANCIENT_OF_DEATH]){
|
||||
} else if(mdat == &mons[PM_ANCIENT_OF_DEATH]){
|
||||
if(!(u.sealsActive&SEAL_OSE)) explode(mon->mx, mon->my, 0, tmp, MON_EXPLODE, EXPL_DARK);
|
||||
}
|
||||
else if(mdat->mattk[i].adtyp == AD_MAND){
|
||||
} else if(mdat->mattk[i].adtyp == AD_WTCH){
|
||||
struct monst *mtmp, *mtmp2;
|
||||
pline("%s lets out a terrible shriek!", Monnam(mon));
|
||||
for (mtmp = fmon; mtmp; mtmp = mtmp2){
|
||||
mtmp2 = mtmp->nmon;
|
||||
if(mtmp->data == &mons[PM_SWARM_OF_SNAKING_TENTACLES] || mtmp->data == &mons[PM_LONG_SINUOUS_TENTACLE]){
|
||||
if (DEADMONSTER(mtmp)) continue;
|
||||
mtmp->mhp = -10;
|
||||
monkilled(mtmp,"",AD_DRLI);
|
||||
}
|
||||
}
|
||||
} else if(mdat->mattk[i].adtyp == AD_MAND){
|
||||
struct monst *mtmp, *mtmp2;
|
||||
if(mon->mcan){
|
||||
pline("%s croaks out a horse shriek. It seems %s has a sore throat!", Monnam(mon), mon_nam(mon));
|
||||
return FALSE;
|
||||
}
|
||||
else pline("%s lets out a terrible shriek!", Monnam(mon));
|
||||
for (mtmp = fmon; mtmp; mtmp = mtmp2){
|
||||
mtmp2 = mtmp->nmon;
|
||||
if(mtmp->data->geno & G_GENO && !nonliving(mon->data) && !is_demon(mon->data) && !is_keter(mon->data)){
|
||||
|
@ -2496,6 +2581,8 @@ boolean was_swallowed; /* digestion */
|
|||
|| is_golem(mdat)
|
||||
|| is_mplayer(mdat)
|
||||
|| is_rider(mdat)
|
||||
|| mdat == &mons[PM_SEYLL_AUZKOVYN]
|
||||
|| mdat == &mons[PM_DARUTH_XAXOX]
|
||||
// || mdat == &mons[PM_UNICORN_OF_AMBER]
|
||||
|| mdat == &mons[PM_NIGHTMARE]
|
||||
// || mdat == &mons[PM_PINK_UNICORN]
|
||||
|
@ -2869,7 +2956,7 @@ xkilled(mtmp, dest)
|
|||
&& typ != FIGURINE
|
||||
&& (otmp->owt > 3 ||
|
||||
objects[typ].oc_big /*oc_bimanual/oc_bulky*/ ||
|
||||
is_spear(otmp) || is_pole(otmp) ||
|
||||
is_spear(otmp) || (is_pole(otmp) && otmp->otyp != AKLYS) ||
|
||||
typ == MORNING_STAR)
|
||||
&& !is_divider(mdat)) {
|
||||
delobj(otmp);
|
||||
|
@ -2912,10 +2999,16 @@ cleanup:
|
|||
newexplevel(); /* will decide if you go up */
|
||||
|
||||
/* adjust alignment points */
|
||||
if (mtmp->m_id == quest_status.leader_m_id) { /* REAL BAD! */
|
||||
if (mtmp->m_id == quest_status.leader_m_id) {
|
||||
if(flags.leader_backstab){ /* They attacked you! */
|
||||
adjalign((int)(ALIGNLIM/4));
|
||||
pline("That was %sa bad idea...",
|
||||
u.uevent.qcompleted ? "probably " : "");
|
||||
} else {/* REAL BAD! */
|
||||
adjalign(-(u.ualign.record+(int)ALIGNLIM/2));
|
||||
pline("That was %sa bad idea...",
|
||||
u.uevent.qcompleted ? "probably " : "");
|
||||
}
|
||||
} else if (mdat->msound == MS_NEMESIS) /* Real good! */
|
||||
adjalign((int)(ALIGNLIM/4));
|
||||
else if (mdat->msound == MS_GUARDIAN && mdat != &mons[PM_THUG]) { /* Bad *//*nobody cares if you kill thugs*/
|
||||
|
@ -3248,6 +3341,20 @@ register struct monst *mtmp;
|
|||
if (humanoid(mtmp->data) || mtmp->isshk || mtmp->isgd)
|
||||
pline("%s gets angry!", Monnam(mtmp));
|
||||
else if (flags.verbose && flags.soundok) growl(mtmp);
|
||||
if(flags.stag && (mtmp->data == &mons[PM_DROW_MATRON_MOTHER] || mtmp->data == &mons[PM_ECLAVDRA])){
|
||||
struct monst *tm;
|
||||
for(tm = fmon; tm; tm = tm->nmon){
|
||||
if(tm->mfaction != EILISTRAEE_SYMBOL &&
|
||||
tm->mfaction != XAXOX && tm->mfaction != EDDER_SYMBOL &&
|
||||
is_drow(tm->data) && !tm->mtame
|
||||
){
|
||||
tm->housealert = 1;
|
||||
tm->mpeaceful = 0;
|
||||
tm->mstrategy &= ~STRAT_WAITMASK;
|
||||
set_malign(tm);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* attacking your own quest leader will anger his or her guardians */
|
||||
|
@ -3314,6 +3421,24 @@ register int x, y, distance;
|
|||
}
|
||||
}
|
||||
|
||||
/* Wake up monsters near some particular location. */
|
||||
void
|
||||
wake_nearto_noisy(x, y, distance)
|
||||
register int x, y, distance;
|
||||
{
|
||||
register struct monst *mtmp;
|
||||
wake_nearto(x,y,distance);
|
||||
distance /= 3;
|
||||
for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
|
||||
if (!DEADMONSTER(mtmp) && sensitive_ears(mtmp->data) &&
|
||||
dist2(mtmp->mx, mtmp->my, x, y) < distance){
|
||||
mtmp->mstun = 1;
|
||||
mtmp->mconf = 1;
|
||||
mtmp->uhurtm = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* NOTE: we must check for mimicry before calling this routine */
|
||||
void
|
||||
seemimic(mtmp)
|
||||
|
@ -3651,16 +3776,17 @@ boolean msg; /* "The oldmon turns into a newmon!" */
|
|||
}
|
||||
|
||||
#ifndef DCC30_BUG
|
||||
if (mdat == &mons[PM_LONG_WORM] && (mtmp->wormno = get_wormno()) != 0) {
|
||||
if ((mdat == &mons[PM_LONG_WORM] || mndx == PM_HUNTING_HORROR) &&
|
||||
(mtmp->wormno = get_wormno()) != 0) {
|
||||
#else
|
||||
/* DICE 3.0 doesn't like assigning and comparing mtmp->wormno in the
|
||||
* same expression.
|
||||
*/
|
||||
if (mdat == &mons[PM_LONG_WORM] &&
|
||||
if ((mdat == &mons[PM_LONG_WORM] || mndx == PM_HUNTING_HORROR) &&
|
||||
(mtmp->wormno = get_wormno(), mtmp->wormno != 0)) {
|
||||
#endif
|
||||
/* we can now create worms with tails - 11/91 */
|
||||
initworm(mtmp, rn2(5));
|
||||
initworm(mtmp, mndx == PM_HUNTING_HORROR ? 2 : rn2(5));
|
||||
if (count_wsegs(mtmp))
|
||||
place_worm_tail_randomly(mtmp, mtmp->mx, mtmp->my);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue