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. */
|
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
|
||||||
/* NetHack may be freely redistributed. See license for details. */
|
/* NetHack may be freely redistributed. See license for details. */
|
||||||
|
|
||||||
@@ -45,8 +45,9 @@ sanity_check_single_mon(mtmp, msg)
|
|||||||
struct monst *mtmp;
|
struct monst *mtmp;
|
||||||
const char *msg;
|
const char *msg;
|
||||||
{
|
{
|
||||||
if (DEADMONSTER(mtmp)) return;
|
if (DEADMONSTER(mtmp))
|
||||||
if ((mtmp->data < &mons[LOW_PM]) || (mtmp->data >= &mons[NUMMONS]))
|
return;
|
||||||
|
if (mtmp->data < &mons[LOW_PM] || mtmp->data >= &mons[NUMMONS])
|
||||||
impossible("illegal mon data (%s)", msg);
|
impossible("illegal mon data (%s)", msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -251,8 +252,8 @@ unsigned corpseflags;
|
|||||||
case PM_BLUE_DRAGON:
|
case PM_BLUE_DRAGON:
|
||||||
case PM_GREEN_DRAGON:
|
case PM_GREEN_DRAGON:
|
||||||
case PM_YELLOW_DRAGON:
|
case PM_YELLOW_DRAGON:
|
||||||
/* Make dragon scales. This assumes that the order of the */
|
/* Make dragon scales. This assumes that the order of the
|
||||||
/* dragons is the same as the order of the scales. */
|
dragons is the same as the order of the scales. */
|
||||||
if (!rn2(mtmp->mrevived ? 20 : 3)) {
|
if (!rn2(mtmp->mrevived ? 20 : 3)) {
|
||||||
num = GRAY_DRAGON_SCALES + monsndx(mdat) - PM_GRAY_DRAGON;
|
num = GRAY_DRAGON_SCALES + monsndx(mdat) - PM_GRAY_DRAGON;
|
||||||
obj = mksobj_at(num, x, y, FALSE, FALSE);
|
obj = mksobj_at(num, x, y, FALSE, FALSE);
|
||||||
@@ -384,7 +385,7 @@ unsigned corpseflags;
|
|||||||
|
|
||||||
(void) bury_an_obj(obj, &dealloc);
|
(void) bury_an_obj(obj, &dealloc);
|
||||||
newsym(x, y);
|
newsym(x, y);
|
||||||
return (dealloc ? NULL : obj);
|
return dealloc ? (struct obj *) 0 : obj;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -399,7 +400,7 @@ unsigned corpseflags;
|
|||||||
if (has_mname(mtmp))
|
if (has_mname(mtmp))
|
||||||
obj = oname(obj, 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"
|
* during Blind combat. An unseen monster referred to as "it"
|
||||||
* could be killed and leave a corpse. If a hider then hid
|
* could be killed and leave a corpse. If a hider then hid
|
||||||
* underneath it, you could be told the corpse type of a
|
* underneath it, you could be told the corpse type of a
|
||||||
@@ -534,8 +535,8 @@ struct monst *mon;
|
|||||||
int mmove = mon->data->mmove;
|
int mmove = mon->data->mmove;
|
||||||
|
|
||||||
/* Note: MSLOW's `+ 1' prevents slowed speed 1 getting reduced to 0;
|
/* Note: MSLOW's `+ 1' prevents slowed speed 1 getting reduced to 0;
|
||||||
* MFAST's `+ 2' prevents hasted speed 1 from becoming a no-op;
|
* MFAST's `+ 2' prevents hasted speed 1 from becoming a no-op;
|
||||||
* both adjustments have negligible effect on higher speeds.
|
* both adjustments have negligible effect on higher speeds.
|
||||||
*/
|
*/
|
||||||
if (mon->mspeed == MSLOW)
|
if (mon->mspeed == MSLOW)
|
||||||
mmove = (2 * mmove + 1) / 3;
|
mmove = (2 * mmove + 1) / 3;
|
||||||
@@ -649,7 +650,7 @@ movemon()
|
|||||||
if (DEADMONSTER(mtmp))
|
if (DEADMONSTER(mtmp))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Find a monster that we have not treated yet. */
|
/* Find a monster that we have not treated yet. */
|
||||||
if (mtmp->movement < NORMAL_SPEED)
|
if (mtmp->movement < NORMAL_SPEED)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@@ -977,7 +978,7 @@ register const char *str;
|
|||||||
register struct obj *otmp, *otmp2, *otmp3;
|
register struct obj *otmp, *otmp2, *otmp3;
|
||||||
int carryamt = 0;
|
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))
|
if (mtmp->isshk && inhishop(mtmp))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
@@ -1073,14 +1074,17 @@ struct monst *mtmp;
|
|||||||
*
|
*
|
||||||
* this will probably cause very amusing behavior with pets and gold coins.
|
* 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
|
int
|
||||||
can_carry(mtmp, otmp)
|
can_carry(mtmp, otmp)
|
||||||
struct monst *mtmp;
|
struct monst *mtmp;
|
||||||
struct obj *otmp;
|
struct obj *otmp;
|
||||||
{
|
{
|
||||||
int otyp = otmp->otyp, newload = otmp->owt;
|
int iquan, otyp = otmp->otyp, newload = otmp->owt;
|
||||||
struct permonst *mdat = mtmp->data;
|
struct permonst *mdat = mtmp->data;
|
||||||
short nattk = 0;
|
short nattk = 0;
|
||||||
|
|
||||||
@@ -1096,11 +1100,18 @@ struct obj *otmp;
|
|||||||
&& (otyp != BELL_OF_OPENING || !is_covetous(mdat)))
|
&& (otyp != BELL_OF_OPENING || !is_covetous(mdat)))
|
||||||
return 0;
|
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
|
/* monsters without hands can't pick up multiple objects at once
|
||||||
* unless they have an engulfing attack
|
* unless they have an engulfing attack
|
||||||
*
|
*
|
||||||
* ...dragons, of course, can always carry gold pieces and gems somehow */
|
* ...dragons, of course, can always carry gold pieces and gems somehow
|
||||||
if (otmp->quan > 1) {
|
*/
|
||||||
|
if (iquan > 1) {
|
||||||
boolean glomper = FALSE;
|
boolean glomper = FALSE;
|
||||||
|
|
||||||
if (mtmp->data->mlet == S_DRAGON
|
if (mtmp->data->mlet == S_DRAGON
|
||||||
@@ -1121,7 +1132,7 @@ struct obj *otmp;
|
|||||||
if (mtmp == u.usteed)
|
if (mtmp == u.usteed)
|
||||||
return 0;
|
return 0;
|
||||||
if (mtmp->isshk)
|
if (mtmp->isshk)
|
||||||
return otmp->quan; /* no limit */
|
return iquan; /* no limit */
|
||||||
if (mtmp->mpeaceful && !mtmp->mtame)
|
if (mtmp->mpeaceful && !mtmp->mtame)
|
||||||
return 0;
|
return 0;
|
||||||
/* otherwise players might find themselves obligated to violate
|
/* otherwise players might find themselves obligated to violate
|
||||||
@@ -1130,16 +1141,16 @@ struct obj *otmp;
|
|||||||
|
|
||||||
/* special--boulder throwers carry unlimited amounts of boulders */
|
/* special--boulder throwers carry unlimited amounts of boulders */
|
||||||
if (throws_rocks(mdat) && otyp == BOULDER)
|
if (throws_rocks(mdat) && otyp == BOULDER)
|
||||||
return otmp->quan;
|
return iquan;
|
||||||
|
|
||||||
/* nymphs deal in stolen merchandise, but not boulders or statues */
|
/* nymphs deal in stolen merchandise, but not boulders or statues */
|
||||||
if (mdat->mlet == S_NYMPH)
|
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))
|
if (curr_mon_load(mtmp) + newload > max_mon_load(mtmp))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return otmp->quan;
|
return iquan;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* return number of acceptable neighbour positions */
|
/* return number of acceptable neighbour positions */
|
||||||
@@ -1166,9 +1177,9 @@ long flag;
|
|||||||
|
|
||||||
nodiag = NODIAG(mdat - mons);
|
nodiag = NODIAG(mdat - mons);
|
||||||
wantpool = mdat->mlet == S_EEL;
|
wantpool = mdat->mlet == S_EEL;
|
||||||
poolok =
|
poolok = (is_flyer(mdat) || is_clinger(mdat)
|
||||||
is_flyer(mdat) || is_clinger(mdat) || (is_swimmer(mdat) && !wantpool);
|
|| (is_swimmer(mdat) && !wantpool));
|
||||||
lavaok = is_flyer(mdat) || is_clinger(mdat) || likes_lava(mdat);
|
lavaok = (is_flyer(mdat) || is_clinger(mdat) || likes_lava(mdat));
|
||||||
thrudoor = ((flag & (ALLOW_WALL | BUSTDOOR)) != 0L);
|
thrudoor = ((flag & (ALLOW_WALL | BUSTDOOR)) != 0L);
|
||||||
if (flag & ALLOW_DIG) {
|
if (flag & ALLOW_DIG) {
|
||||||
struct obj *mw_tmp;
|
struct obj *mw_tmp;
|
||||||
@@ -1373,7 +1384,7 @@ nexttry: /* eels prefer the water, but if there is no water nearby,
|
|||||||
STATIC_OVL long
|
STATIC_OVL long
|
||||||
mm_aggression(magr, mdef)
|
mm_aggression(magr, mdef)
|
||||||
struct monst *magr, /* monster that is currently deciding where to move */
|
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
|
/* supposedly purple worms are attracted to shrieking because they
|
||||||
like to eat shriekers, so attack the latter when feasible */
|
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
|
STATIC_OVL long
|
||||||
mm_displacement(magr, mdef)
|
mm_displacement(magr, mdef)
|
||||||
struct monst *magr, /* monster that is currently deciding where to move */
|
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;
|
struct permonst *pa = magr->data, *pd = mdef->data;
|
||||||
|
|
||||||
@@ -2346,8 +2357,8 @@ struct monst *mtmp;
|
|||||||
/* mnearto()
|
/* mnearto()
|
||||||
* Put monster near (or at) location if possible.
|
* Put monster near (or at) location if possible.
|
||||||
* Returns:
|
* Returns:
|
||||||
* 1 - if a monster was moved from x, y to put mtmp at x, y.
|
* 1 - if a monster was moved from x, y to put mtmp at x, y.
|
||||||
* 0 - in most cases.
|
* 0 - in most cases.
|
||||||
*/
|
*/
|
||||||
boolean
|
boolean
|
||||||
mnearto(mtmp, x, y, move_other)
|
mnearto(mtmp, x, y, move_other)
|
||||||
@@ -2456,8 +2467,8 @@ struct monst *mtmp;
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* attacking your own quest leader will anger his or her guardians */
|
/* attacking your own quest leader will anger his or her guardians */
|
||||||
if (!context.mon_moving && /* should always be the case here */
|
if (!context.mon_moving /* should always be the case here */
|
||||||
mtmp->data == &mons[quest_info(MS_LEADER)]) {
|
&& mtmp->data == &mons[quest_info(MS_LEADER)]) {
|
||||||
struct monst *mon;
|
struct monst *mon;
|
||||||
struct permonst *q_guardian = &mons[quest_info(MS_GUARDIAN)];
|
struct permonst *q_guardian = &mons[quest_info(MS_GUARDIAN)];
|
||||||
int got_mad = 0;
|
int got_mad = 0;
|
||||||
@@ -3341,7 +3352,7 @@ struct obj *obj_list;
|
|||||||
#if 0 /* not used */
|
#if 0 /* not used */
|
||||||
} else if (otmp->otyp == TIN) {
|
} else if (otmp->otyp == TIN) {
|
||||||
if (dead_species(otmp->corpsenm, FALSE))
|
if (dead_species(otmp->corpsenm, FALSE))
|
||||||
otmp->corpsenm = NON_PM; /* empty tin */
|
otmp->corpsenm = NON_PM; /* empty tin */
|
||||||
} else if (otmp->otyp == CORPSE) {
|
} else if (otmp->otyp == CORPSE) {
|
||||||
if (dead_species(otmp->corpsenm, FALSE))
|
if (dead_species(otmp->corpsenm, FALSE))
|
||||||
; /* not yet implemented... */
|
; /* not yet implemented... */
|
||||||
@@ -3365,10 +3376,10 @@ kill_genocided_monsters()
|
|||||||
* their intended destinations, so possessions get deposited there.
|
* their intended destinations, so possessions get deposited there.
|
||||||
*
|
*
|
||||||
* Chameleon handling:
|
* Chameleon handling:
|
||||||
* 1) if chameleons have been genocided, destroy them
|
* 1) if chameleons have been genocided, destroy them
|
||||||
* regardless of current form;
|
* regardless of current form;
|
||||||
* 2) otherwise, force every chameleon which is imitating
|
* 2) otherwise, force every chameleon which is imitating
|
||||||
* any genocided species to take on a new form.
|
* any genocided species to take on a new form.
|
||||||
*/
|
*/
|
||||||
for (mtmp = fmon; mtmp; mtmp = mtmp2) {
|
for (mtmp = fmon; mtmp; mtmp = mtmp2) {
|
||||||
mtmp2 = mtmp->nmon;
|
mtmp2 = mtmp->nmon;
|
||||||
|
|||||||
Reference in New Issue
Block a user