fix can_carry()
Noticed while going through more reformatting: can_carry() was changed to return a number rather than yes/no, but it's trying to return a long value (obj->quan) as an int. Gold is the only thing likely to exceed LARGEST_INT in actual play (although rocks could manage it if somebody tried hard enough). This makes sure that the value returned doesn't exceed LARGEST_INT, but only tame monsters honor the resulting subset value (at least for gold) and split the stack. The proper fix is to convert can_carry() and all its uses to long, but I'd rather spend my time on other stuff.
This commit is contained in:
77
src/mon.c
77
src/mon.c
@@ -1,4 +1,4 @@
|
||||
/* NetHack 3.6 mon.c $NHDT-Date: 1446166647 2015/10/30 00:57:27 $ $NHDT-Branch: master $:$NHDT-Revision: 1.193 $ */
|
||||
/* NetHack 3.6 mon.c $NHDT-Date: 1446458009 2015/11/02 09:53:29 $ $NHDT-Branch: master $:$NHDT-Revision: 1.194 $ */
|
||||
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
|
||||
/* NetHack may be freely redistributed. See license for details. */
|
||||
|
||||
@@ -45,8 +45,9 @@ sanity_check_single_mon(mtmp, msg)
|
||||
struct monst *mtmp;
|
||||
const char *msg;
|
||||
{
|
||||
if (DEADMONSTER(mtmp)) return;
|
||||
if ((mtmp->data < &mons[LOW_PM]) || (mtmp->data >= &mons[NUMMONS]))
|
||||
if (DEADMONSTER(mtmp))
|
||||
return;
|
||||
if (mtmp->data < &mons[LOW_PM] || mtmp->data >= &mons[NUMMONS])
|
||||
impossible("illegal mon data (%s)", msg);
|
||||
}
|
||||
|
||||
@@ -251,8 +252,8 @@ unsigned corpseflags;
|
||||
case PM_BLUE_DRAGON:
|
||||
case PM_GREEN_DRAGON:
|
||||
case PM_YELLOW_DRAGON:
|
||||
/* Make dragon scales. This assumes that the order of the */
|
||||
/* dragons is the same as the order of the scales. */
|
||||
/* Make dragon scales. This assumes that the order of the
|
||||
dragons is the same as the order of the scales. */
|
||||
if (!rn2(mtmp->mrevived ? 20 : 3)) {
|
||||
num = GRAY_DRAGON_SCALES + monsndx(mdat) - PM_GRAY_DRAGON;
|
||||
obj = mksobj_at(num, x, y, FALSE, FALSE);
|
||||
@@ -384,7 +385,7 @@ unsigned corpseflags;
|
||||
|
||||
(void) bury_an_obj(obj, &dealloc);
|
||||
newsym(x, y);
|
||||
return (dealloc ? NULL : obj);
|
||||
return dealloc ? (struct obj *) 0 : obj;
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -399,7 +400,7 @@ unsigned corpseflags;
|
||||
if (has_mname(mtmp))
|
||||
obj = oname(obj, MNAME(mtmp));
|
||||
|
||||
/* Avoid "It was hidden under a green mold corpse!"
|
||||
/* Avoid "It was hidden under a green mold corpse!"
|
||||
* during Blind combat. An unseen monster referred to as "it"
|
||||
* could be killed and leave a corpse. If a hider then hid
|
||||
* underneath it, you could be told the corpse type of a
|
||||
@@ -534,8 +535,8 @@ struct monst *mon;
|
||||
int mmove = mon->data->mmove;
|
||||
|
||||
/* Note: MSLOW's `+ 1' prevents slowed speed 1 getting reduced to 0;
|
||||
* MFAST's `+ 2' prevents hasted speed 1 from becoming a no-op;
|
||||
* both adjustments have negligible effect on higher speeds.
|
||||
* MFAST's `+ 2' prevents hasted speed 1 from becoming a no-op;
|
||||
* both adjustments have negligible effect on higher speeds.
|
||||
*/
|
||||
if (mon->mspeed == MSLOW)
|
||||
mmove = (2 * mmove + 1) / 3;
|
||||
@@ -649,7 +650,7 @@ movemon()
|
||||
if (DEADMONSTER(mtmp))
|
||||
continue;
|
||||
|
||||
/* Find a monster that we have not treated yet. */
|
||||
/* Find a monster that we have not treated yet. */
|
||||
if (mtmp->movement < NORMAL_SPEED)
|
||||
continue;
|
||||
|
||||
@@ -977,7 +978,7 @@ register const char *str;
|
||||
register struct obj *otmp, *otmp2, *otmp3;
|
||||
int carryamt = 0;
|
||||
|
||||
/* prevent shopkeepers from leaving the door of their shop */
|
||||
/* prevent shopkeepers from leaving the door of their shop */
|
||||
if (mtmp->isshk && inhishop(mtmp))
|
||||
return FALSE;
|
||||
|
||||
@@ -1073,14 +1074,17 @@ struct monst *mtmp;
|
||||
*
|
||||
* this will probably cause very amusing behavior with pets and gold coins.
|
||||
*
|
||||
* TODO: allow picking up 2-N objects from a pile of N based on weight
|
||||
* TODO: allow picking up 2-N objects from a pile of N based on weight.
|
||||
* Change from 'int' to 'long' to accomate big stacks of gold.
|
||||
* Right now we fake it by reporting a partial quantity, but the
|
||||
* likesgold handling m_move results in picking up the whole stack.
|
||||
*/
|
||||
int
|
||||
can_carry(mtmp, otmp)
|
||||
struct monst *mtmp;
|
||||
struct obj *otmp;
|
||||
{
|
||||
int otyp = otmp->otyp, newload = otmp->owt;
|
||||
int iquan, otyp = otmp->otyp, newload = otmp->owt;
|
||||
struct permonst *mdat = mtmp->data;
|
||||
short nattk = 0;
|
||||
|
||||
@@ -1096,11 +1100,18 @@ struct obj *otmp;
|
||||
&& (otyp != BELL_OF_OPENING || !is_covetous(mdat)))
|
||||
return 0;
|
||||
|
||||
/* hostile monsters who like gold will pick up the whole stack;
|
||||
tame mosnters with hands will pick up the partial stack */
|
||||
iquan = (otmp->quan > (long) LARGEST_INT)
|
||||
? 20000 + rn2(LARGEST_INT - 20000 + 1)
|
||||
: (int) otmp->quan;
|
||||
|
||||
/* monsters without hands can't pick up multiple objects at once
|
||||
* unless they have an engulfing attack
|
||||
*
|
||||
* ...dragons, of course, can always carry gold pieces and gems somehow */
|
||||
if (otmp->quan > 1) {
|
||||
* ...dragons, of course, can always carry gold pieces and gems somehow
|
||||
*/
|
||||
if (iquan > 1) {
|
||||
boolean glomper = FALSE;
|
||||
|
||||
if (mtmp->data->mlet == S_DRAGON
|
||||
@@ -1121,7 +1132,7 @@ struct obj *otmp;
|
||||
if (mtmp == u.usteed)
|
||||
return 0;
|
||||
if (mtmp->isshk)
|
||||
return otmp->quan; /* no limit */
|
||||
return iquan; /* no limit */
|
||||
if (mtmp->mpeaceful && !mtmp->mtame)
|
||||
return 0;
|
||||
/* otherwise players might find themselves obligated to violate
|
||||
@@ -1130,16 +1141,16 @@ struct obj *otmp;
|
||||
|
||||
/* special--boulder throwers carry unlimited amounts of boulders */
|
||||
if (throws_rocks(mdat) && otyp == BOULDER)
|
||||
return otmp->quan;
|
||||
return iquan;
|
||||
|
||||
/* nymphs deal in stolen merchandise, but not boulders or statues */
|
||||
if (mdat->mlet == S_NYMPH)
|
||||
return (otmp->oclass == ROCK_CLASS) ? 0 : otmp->quan;
|
||||
return (otmp->oclass == ROCK_CLASS) ? 0 : iquan;
|
||||
|
||||
if (curr_mon_load(mtmp) + newload > max_mon_load(mtmp))
|
||||
return 0;
|
||||
|
||||
return otmp->quan;
|
||||
return iquan;
|
||||
}
|
||||
|
||||
/* return number of acceptable neighbour positions */
|
||||
@@ -1166,9 +1177,9 @@ long flag;
|
||||
|
||||
nodiag = NODIAG(mdat - mons);
|
||||
wantpool = mdat->mlet == S_EEL;
|
||||
poolok =
|
||||
is_flyer(mdat) || is_clinger(mdat) || (is_swimmer(mdat) && !wantpool);
|
||||
lavaok = is_flyer(mdat) || is_clinger(mdat) || likes_lava(mdat);
|
||||
poolok = (is_flyer(mdat) || is_clinger(mdat)
|
||||
|| (is_swimmer(mdat) && !wantpool));
|
||||
lavaok = (is_flyer(mdat) || is_clinger(mdat) || likes_lava(mdat));
|
||||
thrudoor = ((flag & (ALLOW_WALL | BUSTDOOR)) != 0L);
|
||||
if (flag & ALLOW_DIG) {
|
||||
struct obj *mw_tmp;
|
||||
@@ -1373,7 +1384,7 @@ nexttry: /* eels prefer the water, but if there is no water nearby,
|
||||
STATIC_OVL long
|
||||
mm_aggression(magr, mdef)
|
||||
struct monst *magr, /* monster that is currently deciding where to move */
|
||||
*mdef; /* another monster which is next to it */
|
||||
*mdef; /* another monster which is next to it */
|
||||
{
|
||||
/* supposedly purple worms are attracted to shrieking because they
|
||||
like to eat shriekers, so attack the latter when feasible */
|
||||
@@ -1390,7 +1401,7 @@ struct monst *magr, /* monster that is currently deciding where to move */
|
||||
STATIC_OVL long
|
||||
mm_displacement(magr, mdef)
|
||||
struct monst *magr, /* monster that is currently deciding where to move */
|
||||
*mdef; /* another monster which is next to it */
|
||||
*mdef; /* another monster which is next to it */
|
||||
{
|
||||
struct permonst *pa = magr->data, *pd = mdef->data;
|
||||
|
||||
@@ -2346,8 +2357,8 @@ struct monst *mtmp;
|
||||
/* mnearto()
|
||||
* Put monster near (or at) location if possible.
|
||||
* Returns:
|
||||
* 1 - if a monster was moved from x, y to put mtmp at x, y.
|
||||
* 0 - in most cases.
|
||||
* 1 - if a monster was moved from x, y to put mtmp at x, y.
|
||||
* 0 - in most cases.
|
||||
*/
|
||||
boolean
|
||||
mnearto(mtmp, x, y, move_other)
|
||||
@@ -2456,8 +2467,8 @@ struct monst *mtmp;
|
||||
}
|
||||
|
||||
/* attacking your own quest leader will anger his or her guardians */
|
||||
if (!context.mon_moving && /* should always be the case here */
|
||||
mtmp->data == &mons[quest_info(MS_LEADER)]) {
|
||||
if (!context.mon_moving /* should always be the case here */
|
||||
&& mtmp->data == &mons[quest_info(MS_LEADER)]) {
|
||||
struct monst *mon;
|
||||
struct permonst *q_guardian = &mons[quest_info(MS_GUARDIAN)];
|
||||
int got_mad = 0;
|
||||
@@ -3341,7 +3352,7 @@ struct obj *obj_list;
|
||||
#if 0 /* not used */
|
||||
} else if (otmp->otyp == TIN) {
|
||||
if (dead_species(otmp->corpsenm, FALSE))
|
||||
otmp->corpsenm = NON_PM; /* empty tin */
|
||||
otmp->corpsenm = NON_PM; /* empty tin */
|
||||
} else if (otmp->otyp == CORPSE) {
|
||||
if (dead_species(otmp->corpsenm, FALSE))
|
||||
; /* not yet implemented... */
|
||||
@@ -3365,10 +3376,10 @@ kill_genocided_monsters()
|
||||
* their intended destinations, so possessions get deposited there.
|
||||
*
|
||||
* Chameleon handling:
|
||||
* 1) if chameleons have been genocided, destroy them
|
||||
* regardless of current form;
|
||||
* 2) otherwise, force every chameleon which is imitating
|
||||
* any genocided species to take on a new form.
|
||||
* 1) if chameleons have been genocided, destroy them
|
||||
* regardless of current form;
|
||||
* 2) otherwise, force every chameleon which is imitating
|
||||
* any genocided species to take on a new form.
|
||||
*/
|
||||
for (mtmp = fmon; mtmp; mtmp = mtmp2) {
|
||||
mtmp2 = mtmp->nmon;
|
||||
|
||||
Reference in New Issue
Block a user