From 4159dd985aa94e55c07ddb7e5280b83237a2a085 Mon Sep 17 00:00:00 2001 From: PatR Date: Fri, 21 Dec 2018 16:59:01 -0800 Subject: [PATCH] fix #2468 - killer bees without a queen Seven year old suggestion was to have a killer bee eat royal jelly if there was no queen around, then after a short delay it would become a queen. This does that, with "no queen around" being "no queen bee on current dungeon level" and the transformation happening immediately with the "short delay" taking place after. Pet killer bees will target nearby royal jelly if there's no queen, hostile killer bees will only eat it if they happen to walk on the same spot as one. Both types accept either tame or hostile queen bee as an existing queen. Killer bees eating royal jelly will drop dead if queen bees have been genocided, and aren't smart enough to avoid the instinct to eat such if/when that happens to be the situation. --- doc/fixes37.0 | 2 ++ include/extern.h | 3 ++- src/dog.c | 17 ++++++++++++- src/dogmove.c | 18 +++++++++----- src/makemon.c | 8 ++++--- src/monmove.c | 62 +++++++++++++++++++++++++++++++++++++++++++----- 6 files changed, 93 insertions(+), 17 deletions(-) diff --git a/doc/fixes37.0 b/doc/fixes37.0 index c83af6c37..465eef81d 100644 --- a/doc/fixes37.0 +++ b/doc/fixes37.0 @@ -14,6 +14,8 @@ Platform- and/or Interface-Specific Fixes General New Features -------------------- +if a killer bee encounters a lump of royal jelly and there is no queen bee on + the level, the bee will eat the jelly and become a new queen Platform- and/or Interface-Specific New Features diff --git a/include/extern.h b/include/extern.h index 78c7647da..10d7335d5 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 extern.h $NHDT-Date: 1545383614 2018/12/21 09:13:34 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.675 $ */ +/* NetHack 3.6 extern.h $NHDT-Date: 1545439142 2018/12/22 00:39:02 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.676 $ */ /* Copyright (c) Steve Creps, 1988. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1487,6 +1487,7 @@ E boolean FDECL(monhaskey, (struct monst *, BOOLEAN_P)); E void FDECL(mon_regen, (struct monst *, BOOLEAN_P)); E int FDECL(dochugw, (struct monst *)); E boolean FDECL(onscary, (int, int, struct monst *)); +E int FDECL(bee_eat_jelly, (struct monst *, struct obj *)); E void FDECL(monflee, (struct monst *, int, BOOLEAN_P, BOOLEAN_P)); E void FDECL(mon_yells, (struct monst *, const char *)); E int FDECL(dochug, (struct monst *)); diff --git a/src/dog.c b/src/dog.c index 93a33716e..051a46f26 100644 --- a/src/dog.c +++ b/src/dog.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 dog.c $NHDT-Date: 1543052701 2018/11/24 09:45:01 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.84 $ */ +/* NetHack 3.6 dog.c $NHDT-Date: 1545439150 2018/12/22 00:39:10 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.85 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2011. */ /* NetHack may be freely redistributed. See license for details. */ @@ -757,6 +757,21 @@ register struct obj *obj; if ((obj->otyp == CORPSE || obj->otyp == EGG) && touch_petrifies(fptr) && !resists_ston(mon)) return POISON; + if (obj->otyp == LUMP_OF_ROYAL_JELLY + && mon->data == &mons[PM_KILLER_BEE]) { + struct monst *mtmp = 0; + + /* if there's a queen bee on the level, don't eat royal jelly; + if there isn't, do eat it and grow into a queen */ + if ((mvitals[PM_QUEEN_BEE].mvflags & G_GENOD) == 0) + for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { + if (DEADMONSTER(mtmp)) + continue; + if (mtmp->data == &mons[PM_QUEEN_BEE]) + break; + } + return !mtmp ? DOGFOOD : TABU; + } if (!carni && !herbi) return obj->cursed ? UNDEF : APPORT; diff --git a/src/dogmove.c b/src/dogmove.c index 1c8f4dd79..8a3cd1b04 100644 --- a/src/dogmove.c +++ b/src/dogmove.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 dogmove.c $NHDT-Date: 1502753407 2017/08/14 23:30:07 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.63 $ */ +/* NetHack 3.6 dogmove.c $NHDT-Date: 1545439152 2018/12/22 00:39:12 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.72 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -211,7 +211,7 @@ boolean devour; { register struct edog *edog = EDOG(mtmp); boolean poly, grow, heal, eyes, slimer, deadmimic; - int nutrit; + int nutrit, res; long oprice; char objnambuf[BUFSZ]; @@ -250,6 +250,11 @@ boolean devour; newsym(x, y); newsym(mtmp->mx, mtmp->my); } + if (mtmp->data == &mons[PM_KILLER_BEE] + && obj->otyp == LUMP_OF_ROYAL_JELLY + && (res = bee_eat_jelly(mtmp, obj)) >= 0) + /* bypass most of dog_eat(), including apport update */ + return (res + 1); /* 1 -> 2, 0 -> 1; -1, keep going */ /* food items are eaten one at a time; entire stack for other stuff */ if (obj->quan > 1L && obj->oclass == FOOD_CLASS) @@ -379,8 +384,9 @@ struct edog *edog; else You_feel("worried about %s.", y_monnam(mtmp)); stop_occupation(); - } else if (monstermoves > edog->hungrytime + 750 || DEADMONSTER(mtmp)) { - dog_died: + } else if (monstermoves > edog->hungrytime + 750 + || DEADMONSTER(mtmp)) { + dog_died: if (mtmp->mleashed && mtmp != u.usteed) Your("leash goes slack."); else if (cansee(mtmp->mx, mtmp->my)) @@ -1184,7 +1190,7 @@ int after; /* this is extra fast monster movement */ } } -newdogpos: + newdogpos: if (nix != omx || niy != omy) { boolean wasseen; @@ -1256,7 +1262,7 @@ newdogpos: } cc.x = mtmp->mx; cc.y = mtmp->my; - dognext: + dognext: if (!m_in_out_region(mtmp, nix, niy)) return 1; remove_monster(mtmp->mx, mtmp->my); diff --git a/src/makemon.c b/src/makemon.c index d78363130..9c6bd6b43 100644 --- a/src/makemon.c +++ b/src/makemon.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 makemon.c $NHDT-Date: 1544998885 2018/12/16 22:21:25 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.131 $ */ +/* NetHack 3.6 makemon.c $NHDT-Date: 1545439153 2018/12/22 00:39:13 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.132 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1801,9 +1801,11 @@ struct monst *mtmp, *victim; return (struct permonst *) 0; /* note: none of the monsters with special hit point calculations - have both little and big forms */ + have both little and big forms (killer bee can't grow into queen + bee by just killing things, so isn't in the little_to_big list) */ oldtype = monsndx(ptr); - newtype = little_to_big(oldtype); + newtype = (oldtype == PM_KILLER_BEE && !victim) ? PM_QUEEN_BEE + : little_to_big(oldtype); if (newtype == PM_PRIEST && mtmp->female) newtype = PM_PRIESTESS; diff --git a/src/monmove.c b/src/monmove.c index fbc2d419d..a59963aec 100644 --- a/src/monmove.c +++ b/src/monmove.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 monmove.c $NHDT-Date: 1544442712 2018/12/10 11:51:52 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.109 $ */ +/* NetHack 3.6 monmove.c $NHDT-Date: 1545439153 2018/12/22 00:39:13 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.110 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2006. */ /* NetHack may be freely redistributed. See license for details. */ @@ -254,6 +254,48 @@ struct monst *mon; } } +/* killer bee 'mon' is on a spot containing lump of royal jelly 'obj' and + will eat it if there is no queen bee on the level; return 1: mon died, + 0: mon ate jelly and lived; -1: mon didn't eat jelly to use its move */ +int +bee_eat_jelly(mon, obj) +struct monst *mon; +struct obj *obj; +{ + int m_delay; + struct monst *mtmp = 0; + + /* find a queen bee */ + if ((mvitals[PM_QUEEN_BEE].mvflags & G_GENOD) == 0) + for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { + if (DEADMONSTER(mtmp)) + continue; + if (mtmp->data == &mons[PM_QUEEN_BEE]) + break; + } + /* if there's no queen on the level, eat the royal jelly and become one */ + if (!mtmp) { + m_delay = obj->blessed ? 3 : !obj->cursed ? 5 : 7; + if (obj->quan > 1L) + obj = splitobj(obj, 1L); + if (canseemon(mon)) + pline("%s eats %s.", Monnam(mon), an(xname(obj))); + delobj(obj); + + if ((int) mon->m_lev < mons[PM_QUEEN_BEE].mlevel - 1) + mon->m_lev = (uchar) (mons[PM_QUEEN_BEE].mlevel - 1); + /* there should be delay after eating, but that's too much + hassle; transform immediately, then have a short delay */ + (void) grow_up(mon, (struct monst *) 0); + + if (DEADMONSTER(mon)) + return 1; /* dead; apparently queen bees have been genocided */ + mon->mfrozen = m_delay, mon->mcanmove = 0; + return 0; /* bee used its move */ + } + return -1; /* a queen is already present; ordinary bee hasn't moved yet */ +} + #define flees_light(mon) ((mon)->data == &mons[PM_GREMLIN] \ && (uwep && artifact_light(uwep) && uwep->lamplit)) /* we could include this in the above macro, but probably overkill/overhead */ @@ -371,7 +413,8 @@ register struct monst *mtmp; { register struct permonst *mdat; register int tmp = 0; - int inrange, nearby, scared; + int inrange, nearby, scared, res; + struct obj *otmp; /* Pre-movement adjustments */ @@ -379,11 +422,10 @@ register struct monst *mtmp; mdat = mtmp->data; if (mtmp->mstrategy & STRAT_ARRIVE) { - int res = m_arrival(mtmp); + res = m_arrival(mtmp); if (res >= 0) return res; } - /* check for waitmask status change */ if ((mtmp->mstrategy & STRAT_WAITFORU) && (m_canseeu(mtmp) || mtmp->mhp < mtmp->mhpmax)) @@ -541,9 +583,9 @@ register struct monst *mtmp; } } } -toofar: + toofar: - /* If monster is nearby you, and has to wield a weapon, do so. This + /* If monster is nearby you, and has to wield a weapon, do so. This * costs the monster a move, of course. */ if ((!mtmp->mpeaceful || Conflict) && inrange @@ -571,6 +613,14 @@ toofar: /* Now the actual movement phase */ + if (mdat == &mons[PM_KILLER_BEE] + /* could be smarter and deliberately move to royal jelly, but + then we'd need to scan the level for queen bee in advance; + avoid that overhead and rely on serendipity... */ + && (otmp = sobj_at(LUMP_OF_ROYAL_JELLY, mtmp->mx, mtmp->my)) != 0 + && (res = bee_eat_jelly(mtmp, otmp)) >= 0) + return res; + if (!nearby || mtmp->mflee || scared || mtmp->mconf || mtmp->mstun || (mtmp->minvis && !rn2(3)) || (mdat->mlet == S_LEPRECHAUN && !findgold(invent)