]> granicus.if.org Git - nethack/commitdiff
kicking shop food to tame dog (trunk only)
authornethack.rankin <nethack.rankin>
Tue, 27 Mar 2007 03:35:31 +0000 (03:35 +0000)
committernethack.rankin <nethack.rankin>
Tue, 27 Mar 2007 03:35:31 +0000 (03:35 +0000)
     From a bug report, kicking unpaid
food in a shop at a tameable monster resulting in taming the monster
without charging for the used-up food.  This forces kicked objects that
are owned by shops to be put on the shop bill and flagged as unpaid, which
is normally reserved for carried items but makes kicked ones behave like
thrown ones.  (If they land inside the shop without breaking, they're
removed from the bill.)  So kicking food to make a pet now results in the
item being moved from the shop's unpaid bill to its used-up bill, same as
for thrown food.  Although the latter kept billing consistent, it lacked
shop billing feedback; this fixes that too.

doc/fixes35.0
src/dogmove.c
src/dokick.c
src/dothrow.c

index b0657a7062d5dc9bfa25c0b7db7911f2d2ffd507..5b34b62eb2285467997c82d2ceda8efb3548ab65 100644 (file)
@@ -202,6 +202,8 @@ changing alignment or shape triggers a check for equipment evading hero's grasp
 passive fire effects can damage attackers weapons
 wielded bow shouldn't affect outcome of kicked arrows
 ranged polearm hit can divide puddings and can use confuse monster effect
+charge for kicked shop-owned food if it gets used up taming a monster
+give better feedback when thrown shop-owned food gets used up taming a monster
 
 
 Platform- and/or Interface-Specific Fixes
index 6b7518fcf2f610924e59854f61dfdd1c915b6b8d..9e707f0ee4e130247f90ae219d89220467dae8b0 100644 (file)
@@ -1,4 +1,4 @@
-/*     SCCS Id: @(#)dogmove.c  3.5     2006/08/16      */
+/*     SCCS Id: @(#)dogmove.c  3.5     2007/03/26      */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /* NetHack may be freely redistributed.  See license for details. */
 
@@ -195,15 +195,17 @@ struct obj *obj;
 int
 dog_eat(mtmp, obj, x, y, devour)
 register struct monst *mtmp;
-register struct obj * obj;
+register struct obj *obj;      /* if unpaid, then thrown or kicked by hero */
 int x, y;
 boolean devour;
 {
        register struct edog *edog = EDOG(mtmp);
-       boolean poly = FALSE, grow = FALSE, heal = FALSE;
+       boolean poly = FALSE, grow = FALSE, heal = FALSE, deadmimic;
        int nutrit;
-       boolean deadmimic = FALSE;
+       long oprice;
+       char objnambuf[BUFSZ];
 
+       objnambuf[0] = '\0';
        if(edog->hungrytime < monstermoves)
            edog->hungrytime = monstermoves;
        nutrit = dog_nutrition(mtmp, obj);
@@ -233,6 +235,11 @@ boolean devour;
            newsym(x, y);
            newsym(mtmp->mx, mtmp->my);
        }
+
+       /* food items are eaten one at a time; entire stack for other stuff */
+       if (obj->quan > 1L && obj->oclass == FOOD_CLASS)
+           obj = splitobj(obj, 1L);
+       if (obj->unpaid) iflags.suppress_price++;
        if (is_pool(x, y) && !Underwater) {
            /* Don't print obj */
            /* TODO: Reveal presence of sea monster (especially sharks) */
@@ -242,9 +249,11 @@ boolean devour;
           sight locations should not. */
        if (cansee(x, y) || cansee(mtmp->mx, mtmp->my))
            pline("%s %s %s.", mon_visible(mtmp) ? noit_Monnam(mtmp) : "It",
-                 devour ? "devours" : "eats",
-                 (obj->oclass == FOOD_CLASS) ?
-                       singular(obj, doname) : doname(obj));
+                 devour ? "devours" : "eats", doname(obj));
+       if (obj->unpaid) {
+           Strcpy(objnambuf, xname(obj));
+           iflags.suppress_price--;
+       }
        /* It's a reward if it's DOGFOOD and the player dropped/threw it. */
        /* We know the player had it if invlet is set -dlc */
        if(dogfood(mtmp,obj) == DOGFOOD && obj->invlet)
@@ -256,6 +265,7 @@ boolean devour;
 #endif
        if (mtmp->data == &mons[PM_RUST_MONSTER] && obj->oerodeproof) {
            /* The object's rustproofing is gone now */
+           if (obj->unpaid) costly_alteration(obj, COST_DEGRD);
            obj->oerodeproof = 0;
            mtmp->mstun = 1;
            if (canseemon(mtmp) && flags.verbose) {
@@ -264,14 +274,20 @@ boolean devour;
            }
        } else if (obj == uball) {
            unpunish();
-           delobj(obj);
-       } else if (obj == uchain)
+           delobj(obj);                /* we assume this can't be unpaid */
+       } else if (obj == uchain) {
            unpunish();
-       else if (obj->quan > 1L && obj->oclass == FOOD_CLASS) {
-           obj->quan--;
-           obj->owt = weight(obj);
-       } else
+       } else {
+           if (obj->unpaid) {
+               /* edible item owned by shop has been thrown or kicked
+                  by hero and caught by tame or food-tameable monst */
+               oprice = unpaid_cost(obj, TRUE);
+               pline("That %s will cost you %ld %s.",
+                     objnambuf, oprice, currency(oprice));
+               /* delobj->obfree will handle actual shop billing update */
+           }
            delobj(obj);
+       }
 
        if (poly) {
            (void) newcham(mtmp, (struct permonst *)0, FALSE,
index fb54f478acb5c635830c3b4c7b2e9595842751e2..4d1145b5418ad6170bd998800b85887a3cadbdae 100644 (file)
@@ -402,7 +402,7 @@ kick_object(x, y)
 xchar x, y;
 {
        int range;
-       register struct monst *mon, *shkp;
+       struct monst *mon, *shkp = 0;
        struct trap *trap;
        char bhitroom;
        boolean costly, isgold, slide = FALSE;
@@ -471,8 +471,9 @@ xchar x, y;
        if(!ZAP_POS(levl[x+u.dx][y+u.dy].typ) || closed_door(x+u.dx, y+u.dy))
                range = 1;
 
-       costly = ((shkp = shop_keeper(*in_rooms(x, y, SHOPBASE))) &&
-                                   costly_spot(x, y));
+       costly = (!(kickobj->no_charge && !Has_contents(kickobj)) &&
+                 (shkp = shop_keeper(*in_rooms(x, y, SHOPBASE))) != 0 &&
+                 costly_spot(x, y));
        isgold = (kickobj->oclass == COIN_CLASS);
 
        if (IS_ROCK(levl[x][y].typ) || closed_door(x, y)) {
@@ -573,6 +574,7 @@ xchar x, y;
            pline("Whee!  %s %s across the %s.", Doname2(kickobj),
                  otense(kickobj, "slide"), surface(x,y));
 
+       if (costly && !isgold) addtobill(kickobj, FALSE, FALSE, TRUE);
        obj_extract_self(kickobj);
        (void) snuff_candle(kickobj);
        newsym(x, y);
@@ -592,16 +594,9 @@ xchar x, y;
                return(1);
        }
 
-       /* the object might have fallen down a hole */
-       if (kickobj->where == OBJ_MIGRATING) {
-           if (costly) {
-               if(isgold)
-                   costly_gold(x, y, kickobj->quan);
-               else (void)stolen_value(kickobj, x, y,
-                                       (boolean)shkp->mpeaceful, FALSE);
-           }
-           return 1;
-       }
+       /* the object might have fallen down a hole;  
+          ship_object() will have taken care of shop billing */
+       if (kickobj->where == OBJ_MIGRATING) return 1;
 
        bhitroom = *in_rooms(bhitpos.x, bhitpos.y, SHOPBASE);
        if (costly && (!costly_spot(bhitpos.x, bhitpos.y) ||
@@ -613,12 +608,14 @@ xchar x, y;
        }
 
        if(flooreffects(kickobj,bhitpos.x,bhitpos.y,"fall")) return(1);
+       if (kickobj->unpaid) subfrombill(kickobj, shkp);
        place_object(kickobj, bhitpos.x, bhitpos.y);
        stackobj(kickobj);
        newsym(kickobj->ox, kickobj->oy);
        return(1);
 }
 
+/* cause of death if kicking kills kicker */
 STATIC_OVL char *
 kickstr(buf)
 char *buf;
@@ -1379,9 +1376,7 @@ boolean shop_floor_obj;
                otmp->no_charge = 0;
        }
 
-       if (otmp == uwep) setuwep((struct obj *)0);
-       if (otmp == uquiver) setuqwep((struct obj *)0);
-       if (otmp == uswapwep) setuswapwep((struct obj *)0);
+       if (otmp->owornmask) remove_worn_item(otmp, TRUE);
 
        /* some things break rather than ship */
        if (breaktest(otmp)) {
index 0a59224679250ca962eabc43e984a5c80e1e3fd0..04abedddc70f4c3576fbe4565f08040434248e57 100644 (file)
@@ -1134,7 +1134,7 @@ boolean twoweap; /* used to restore twoweapon mode if wielded weapon returns */
                    if (cansee(bhitpos.x, bhitpos.y))
                        pline("%s snatches up %s.",
                              Monnam(mon), the(xname(obj)));
-                   if(*u.ushops)
+                   if (*u.ushops || obj->unpaid)
                        check_shop_obj(obj, bhitpos.x, bhitpos.y, FALSE);
                    (void) mpickobj(mon, obj);  /* may merge and free obj */
                    thrownobj = (struct obj*)0;
@@ -1147,7 +1147,7 @@ boolean twoweap; /* used to restore twoweapon mode if wielded weapon returns */
                }
                thrownobj = (struct obj*)0;
                place_object(obj, bhitpos.x, bhitpos.y);
-               if(*u.ushops && obj != uball)
+               if ((*u.ushops || obj->unpaid) && obj != uball)
                    check_shop_obj(obj, bhitpos.x, bhitpos.y, FALSE);
 
                stackobj(obj);
@@ -1334,6 +1334,8 @@ register struct obj *obj; /* thrownobj or kickobj or uwep */
                    (void) encumber_msg();
                } else {
                    /* angry leader caught it and isn't returning it */
+                   if (*u.ushops || obj->unpaid) /* not very likely... */
+                       check_shop_obj(obj, mon->mx, mon->my, FALSE);
                    (void) mpickobj(mon, obj);
                }
                return 1;               /* caller doesn't need to place it */
@@ -1404,7 +1406,7 @@ register struct obj *obj; /* thrownobj or kickobj or uwep */
                        broken = 0;
 
                    if (broken) {
-                       if (*u.ushops)
+                       if (*u.ushops || obj->unpaid)
                            check_shop_obj(obj, bhitpos.x,bhitpos.y, TRUE);
                        obfree(obj, (struct obj *)0);
                        return 1;
@@ -1543,7 +1545,8 @@ register struct obj *obj;
                }
        }
        Strcat(buf,acceptgift);
-       if(*u.ushops) check_shop_obj(obj, mon->mx, mon->my, TRUE);
+       if (*u.ushops || obj->unpaid)
+           check_shop_obj(obj, mon->mx, mon->my, TRUE);
        (void) mpickobj(mon, obj);      /* may merge and free obj */
        ret = 1;
 
@@ -1681,9 +1684,9 @@ boolean from_invent;
        }
 
        if (hero_caused) {
-           if (from_invent) {
-               if (*u.ushops)
-                       check_shop_obj(obj, x, y, TRUE);
+           if (from_invent || obj->unpaid) {
+               if (*u.ushops || obj->unpaid)
+                   check_shop_obj(obj, x, y, TRUE);
            } else if (!obj->no_charge && costly_spot(x, y)) {
                /* it is assumed that the obj is a floor-object */
                char *o_shop = in_rooms(x, y, SHOPBASE);