]> granicus.if.org Git - nethack/commitdiff
fix #2253 - shk dismissing kops from other level (trunk only)
authornethack.rankin <nethack.rankin>
Fri, 15 Apr 2011 01:55:42 +0000 (01:55 +0000)
committernethack.rankin <nethack.rankin>
Fri, 15 Apr 2011 01:55:42 +0000 (01:55 +0000)
     From a bug report, if you rob a shop, let the
angry shopkeeper catch up with you outside his shop, escape to another
level with adjacent shk tagging along, then pacify the shk by paying him
off, he will dismiss kops on the present level and return to his shop
but when you return to his shop level there'll still be kops chasing you
there.  This fix adds an extra flag to the eshk structure so that kops
can be dismissed a second time when the shk migrates back to shop level.
The first dismisal (on the "wrong" level) still takes place in case any
kops are around.  Neither dismissal actually occurs if there happens to
be another angry shk present on the level where dismissal is being done.

doc/fixes35.0
include/extern.h
include/mextra.h
src/dog.c
src/shk.c
src/shknam.c

index 8983b30e5baaae33a77af7471bfcfae85226b03b..0b020266da1b12fb8ed1bceb6201802bbcb6764f 100644 (file)
@@ -355,6 +355,8 @@ Eye of the Aethiopica, Eyes of the Overworld, and Sceptre of Might must be
 Mitre of Holiness and Tsurugi of Muramasa convey Protection when worn/wielded
 effectiveness of magic cancellation by worn armor has been reduced
 Protection improves the effectiveness of magic cancellation
+if an angry shopkeeper chased the hero to a different level and then got paid
+       off, he'd dismiss kops on that other level but not on his shop level
 
 
 Platform- and/or Interface-Specific Fixes
index 943366b8be444fc9e08aff61247e244acc7b6efe..8551a81bf44570cd9a4a8ac1644f89138c03268c 100644 (file)
@@ -2051,6 +2051,7 @@ E void FDECL(delete_contents, (struct obj *));
 E void FDECL(obfree, (struct obj *,struct obj *));
 E void FDECL(home_shk, (struct monst *,BOOLEAN_P));
 E void FDECL(make_happy_shk, (struct monst *,BOOLEAN_P));
+E void FDECL(make_happy_shoppers, (BOOLEAN_P));
 E void FDECL(hot_pursuit, (struct monst *));
 E void FDECL(make_angry_shk, (struct monst *,XCHAR_P,XCHAR_P));
 E int NDECL(dopay);
index 85e842cc0e8827235d1f5b902d85136a177f7a87..3caa6ff6183d2ea9d5f96066f5fd7aa5b01351b4 100644 (file)
@@ -1,5 +1,4 @@
 /* NetHack 3.5 mextra.h        $Date$  $Revision$ */
-/*     SCCS Id: @(#)mextra.h   3.5     2009/01/30      */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /* NetHack may be freely redistributed.  See license for details. */
 
@@ -119,6 +118,7 @@ struct eshk {
        schar unused;           /* to force alignment for stupid compilers */
        boolean following;      /* following customer since he owes us sth */
        boolean surcharge;      /* angry shk inflates prices */
+       boolean dismiss_kops;   /* pacified shk sends kops away */
        coord shk;              /* usual position shopkeeper */
        coord shd;              /* position shop door */
        d_level shoplevel;      /* level (& dungeon) of his shop */
index cf4b4004201cb695d250d853bd00b2dcc5c9fffa..035e5cef78651a2cd869b3d58763ba99836e7f23 100644 (file)
--- a/src/dog.c
+++ b/src/dog.c
@@ -1,5 +1,4 @@
 /* NetHack 3.5 dog.c   $Date$  $Revision$ */
-/*     SCCS Id: @(#)dog.c      3.5     2008/10/20      */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /* NetHack may be freely redistributed.  See license for details. */
 
@@ -218,12 +217,57 @@ void
 losedogs()
 {
        register struct monst *mtmp, *mtmp0 = 0, *mtmp2;
+       int dismissKops = 0;
 
+       /*
+        * First, scan migrating_mons for shopkeepers who want to dismiss Kops,
+        * and scan mydogs for shopkeepers who want to retain kops.
+        * Second, dismiss kops if warranted, making more room for arrival.
+        * Third, place monsters accompanying the hero.
+        * Last, place migrating monsters coming to this level.
+        *
+        * Hero might eventually be displaced (due to the third step, but
+        * occuring later), which is the main reason to do the second step
+        * sooner (in turn necessitating the first step, rather than combining
+        * the list scans with monster placement).
+        */
+
+       /* check for returning shk(s) */
+       for (mtmp = migrating_mons; mtmp; mtmp = mtmp->nmon) {
+           if (mtmp->mux != u.uz.dnum || mtmp->muy != u.uz.dlevel) continue;
+           if (mtmp->isshk) {
+               if (ESHK(mtmp)->dismiss_kops) {
+                   if (dismissKops == 0) dismissKops = 1;
+                   ESHK(mtmp)->dismiss_kops = FALSE;   /* reset */
+               } else if (!mtmp->mpeaceful) {
+                   /* an unpacified shk is returning; don't dismiss kops
+                      even if another pacified one is willing to do so */
+                   dismissKops = -1;
+                   /* [keep looping; later monsters might need ESHK reset] */
+               }
+           }
+       }
+       /* make the same check for mydogs */
+       for (mtmp = mydogs; mtmp && dismissKops >= 0; mtmp = mtmp->nmon) {
+           if (mtmp->isshk) {
+               /* hostile shk might accompany hero [ESHK(mtmp)->dismiss_kops
+                  can't be set here; it's only used for migrating_mons] */
+               if (!mtmp->mpeaceful) dismissKops = -1;
+           }
+       }
+
+       /* when a hostile shopkeeper chases hero to another level
+          and then gets paid off there, get rid of summoned kops
+          here now that he has returned to his shop level */
+       if (dismissKops > 0) make_happy_shoppers(TRUE);
+
+       /* place pets and/or any other monsters who accompany hero */
        while ((mtmp = mydogs) != 0) {
                mydogs = mtmp->nmon;
                mon_arrive(mtmp, TRUE);
        }
 
+       /* time for migrating monsters to arrive */
        for(mtmp = migrating_mons; mtmp; mtmp = mtmp2) {
                mtmp2 = mtmp->nmon;
                if (mtmp->mux == u.uz.dnum && mtmp->muy == u.uz.dlevel) {
index cf24d37537c64a0e2a722d8394e094b7f0249919..cc7d53d21e17d024db4094fb3aa19cbb4daad8e0 100644 (file)
--- a/src/shk.c
+++ b/src/shk.c
@@ -1019,13 +1019,23 @@ register boolean silentkops;
                        /* arrive near shop's door */
                        migrate_to_level(shkp, ledger_no(&eshkp->shoplevel),
                                         MIGR_APPROX_XY, &eshkp->shd);
+                       /* dismiss kops on that level when shk arrives */
+                       eshkp->dismiss_kops = TRUE;
                }
                if (vanished)
                    pline("Satisfied, %s suddenly disappears!", shk_nam);
        } else if(wasmad)
                pline("%s calms down.", Monnam(shkp));
 
-       if(!angry_shk_exists()) {
+       make_happy_shoppers(silentkops);
+}
+
+/* called by make_happy_shk() and also by losedogs() for migrating shk */
+void
+make_happy_shoppers(silentkops)
+boolean silentkops;
+{
+       if (!angry_shk_exists()) {
 #ifdef KOPS
                kops_gone(silentkops);
 #endif
index c5967583039da2acb65925d206abc19c7065fb88..83eb902d305ae74a4146c39a8cee5d9a76212c7e 100644 (file)
@@ -1,5 +1,4 @@
 /* NetHack 3.5 shknam.c        $Date$  $Revision$ */
-/*     SCCS Id: @(#)shknam.c   3.5     2007/09/14      */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /* NetHack may be freely redistributed.  See license for details. */
 
@@ -458,11 +457,12 @@ void
 neweshk(mtmp)
 struct monst *mtmp;
 {
-       if (!mtmp->mextra) mtmp->mextra = newmextra();
-       if (!ESHK(mtmp)) {
+       if (!mtmp->mextra)
+           mtmp->mextra = newmextra();
+       if (!ESHK(mtmp))
            ESHK(mtmp) = (struct eshk *)alloc(sizeof(struct eshk));
-           (void) memset((genericptr_t) ESHK(mtmp), 0, sizeof(struct eshk));
-       }
+       (void) memset((genericptr_t)ESHK(mtmp), 0, sizeof (struct eshk));
+       ESHK(mtmp)->bill_p = (struct bill_x *)0;
 }
 
 void
@@ -483,6 +483,7 @@ struct mkroom       *sroom;
 {
        register int sh, sx, sy;
        struct monst *shk;
+       struct eshk *eshkp;
 
        /* place the shopkeeper in the given room */
        sh = sroom->fdoor;
@@ -535,24 +536,23 @@ struct mkroom     *sroom;
        /* now initialize the shopkeeper monster structure */
        if(!(shk = makemon(&mons[PM_SHOPKEEPER], sx, sy, MM_ESHK)))
                return(-1);
+       eshkp = ESHK(shk);      /* makemon(...,MM_ESHK) allocates this */
        shk->isshk = shk->mpeaceful = 1;
        set_malign(shk);
        shk->msleeping = 0;
        shk->mtrapseen = ~0;    /* we know all the traps already */
-       ESHK(shk)->shoproom = (schar)((sroom - rooms) + ROOMOFFSET);
+       eshkp->shoproom = (schar)((sroom - rooms) + ROOMOFFSET);
        sroom->resident = shk;
-       ESHK(shk)->shoptype = sroom->rtype;
-       assign_level(&(ESHK(shk)->shoplevel), &u.uz);
-       ESHK(shk)->shd = doors[sh];
-       ESHK(shk)->shk.x = sx;
-       ESHK(shk)->shk.y = sy;
-       ESHK(shk)->robbed = 0L;
-       ESHK(shk)->credit = 0L;
-       ESHK(shk)->debit = 0L;
-       ESHK(shk)->loan = 0L;
-       ESHK(shk)->visitct = 0;
-       ESHK(shk)->following = 0;
-       ESHK(shk)->billct = 0;
+       eshkp->shoptype = sroom->rtype;
+       assign_level(&eshkp->shoplevel, &u.uz);
+       eshkp->shd = doors[sh];
+       eshkp->shk.x = sx;
+       eshkp->shk.y = sy;
+       eshkp->robbed = eshkp->credit = eshkp->debit = eshkp->loan = 0L;
+       eshkp->following = eshkp->surcharge = eshkp->dismiss_kops = FALSE;
+       eshkp->billct = eshkp->visitct = 0;
+       eshkp->bill_p = (struct bill_x *)0;
+       eshkp->customer[0] = '\0';
 #ifndef GOLDOBJ
        shk->mgold = 1000L + 30L*(long)rnd(100);        /* initial capital */
 #else