diff --git a/doc/fixes35.0 b/doc/fixes35.0 index 8983b30e5..0b020266d 100644 --- a/doc/fixes35.0 +++ b/doc/fixes35.0 @@ -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 diff --git a/include/extern.h b/include/extern.h index 943366b8b..8551a81bf 100644 --- a/include/extern.h +++ b/include/extern.h @@ -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); diff --git a/include/mextra.h b/include/mextra.h index 85e842cc0..3caa6ff61 100644 --- a/include/mextra.h +++ b/include/mextra.h @@ -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 */ diff --git a/src/dog.c b/src/dog.c index cf4b40042..035e5cef7 100644 --- 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) { diff --git a/src/shk.c b/src/shk.c index cf24d3753..cc7d53d21 100644 --- 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 diff --git a/src/shknam.c b/src/shknam.c index c59675830..83eb902d3 100644 --- a/src/shknam.c +++ b/src/shknam.c @@ -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