[rec.games.hack] Hack bug

gil@svax.UUCP (04/12/87)

===============================================================================
You miss the large dog.  The large dog devours the tripe ration.  More--
The large dog dies from hunger.

Whoops.  Guess it couldn't digest fast enough.
===============================================================================

One of the users here saw the above, and made the comment that follows.
I've looked at the source, and don't see how it could happen.  In tamedog()
(in hack.dog.c, the only place where there's any devouring) initedog() is
unconditionally run, and this code sets "hungrytime" to 1000+moves.
So how could the dog immediately die?
					- Gil

wigglesworth@wateng.UUCP (04/14/87)

In article <1216@svax.cs.cornell.edu> gil@svax.cs.cornell.edu (Gil Neiger) writes:
>So how could the dog immediately die?

Along the same lines, I had an interesting experience with a tame dog
dying of hunger.  I was starting a brand new game and my first move
was 'C' to name my dog "Shep".  Immediately afterwards came the message
"Shep dies from hunger" or something to that effect -- two moves!  How
is this possible?  Has this ever happened to anyone else?

One other observation: NEVER and I mean NEVER go into a shop with your
dog while wearing a ring of conflict!
-- 
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
Joe "yes that's my real name" Wigglesworth
Computer Communications Networks Group
University of Waterloo, Canada

ins_akaa@jhunix.UUCP (04/14/87)

>You miss the large dog.  The large dog devours the tripe ration.  More--
>The large dog dies from hunger.

I can think of a way this could happen, but it seems rather unlikely.

The test in dog_move() to see if the dog died of hunger tests not only hunger,
but hit points as well.  Normally, this is only supposed to happen at this
point if the dog lost hit points from being confused from hunger, a few lines
above.  However, if the dog already has zero or fewer hit points when this
function is called, it will falsely report that the dog dies "of hunger".

There are two bugs which can cause this.  One is the fact that a monster that
loses hit points from a trap doesn't die even if its hit points go down below
zero.  (I recently posted what I think is the fix for this, but I have not
tried it.)

The second involves chameleons, and means that the dog in question must have
been a chameleon.  Checking newcham() in mon.c shows the following algorithm
for computing a monster's new hit points from its old:  
(Note: mtmp->data is the "new" monster and mdat the "old" one)
     hpn = mtmp->mhp;
     hpd = (mtmp->data->mlevel)*8;
     if(!hpd) hpd = 4;
     mtmp->data = mdat;
     mhp = (mdat->mlevel)*8;
     mtmp->mhp = 2 + (hpn*mhp)/hpd;
and the same for computing its new maximum from its old maximum.
This will result in the changing chameleons endlessly going up in hit points,
until the hit points reach 127.  At that point any further increase will make
the hit points negative, due to wraparound.

It gets worse for chameleons that are pets (or were formerly pets; i.e. when
found on a ghost level and belonging to the ghost), or that gained hit points
due to fighting other monsters from the player's use of a ring of conflict.
Since their hit points are high, they are especially prone to the hit points
wrapping around past 127.  (A 4 hit die, 100 hit point chameleon which turns
into something that's 6 hit dice is definitely going to go over 127).

The same applies to polymorphing your dog when well into the game (after the dog
accumulated lots of extra hit points) since polymorph calls the same routine.

The fix: 
     hpn = mtmp->mhp;
     hpd = (mtmp->data->mlevel)*8;    if(!hpd) hpd = 4;
     mhp = (mdat->mlevel)*8;    if(!mhp) mhp = 4;
/* The above if(!mhp) mhp = 4; was not in the original.  Its omission meant
   that something changing into a zero hit die monster, which has 1-4 hp,
   would have its new HP zero.  Thus the 2 which the original added on. */
     mtmp->mhp = (hpn*mhp)/hpd;
     if (mhp > hpd && mtmp->mhp < hpn) mtmp->mhp = 127;
/* Not totally foolproof.  A 2HD monster with 80 HP that changes into a 6HD
   monster that really should have 240 and actually should have 127, the
   maximum possible, will wind up having 113.  */
     if (!mtmp->mhp) mtmp->mhp = 1;
/* Unlikely but not impossible; a 1HD creature with 1HP that changes into a
   0HD creature will require this statement */
     mtmp->data = mdat;
/* and the same for maximum hit points */
     hpn = mtmp->mhpmax;
     mtmp->mhpmax = (hpn*mhp)/hpd;
     if (mhp > hpd && mtmp->mhpmax < hpn) mtmp->mhp = 127;
     if (!mtmp->mhp) mtmp->mhp = 1;
DISCLAIMER: I think this is correct, but I have not tried this fix.
--
"An eclipse of the Earth occurs when you put your hands over your eyes."

Kenneth Arromdee
BITNET: G46I4701@JHUVM, INS_AKAA@JHUVMS, INS_AKAA@JHUNIX
ARPA: ins_akaa%jhunix@hopkins.ARPA
UUCP: {allegra!hopkins, seismo!umcp-cs, ihnp4!whuxcc} !jhunix!ins_akaa
Copyright 1987 by Ken Arromdee.  Distribution of this article by electronic
     means constitutes permission for its recipients to distribute it likewise.
(The NSA, CIA, and FBI conspire to smuggle Reagan drugs via Iran and Nicaragua.)

ins_ajas@jhunix.UUCP (04/15/87)

>     if (mhp > hpd && mtmp->mhp < hpn) mtmp->mhp = 127;
>/* Not totally foolproof.  A 2HD monster with 80 HP that changes into a 6HD
>   monster that really should have 240 and actually should have 127, the
>   maximum possible, will wind up having 113.  */

I goofed here... the monster would actually have -16 HP, which this statement
would catch and change to 127.  A better example would be a 2HD monster with
80 HP that changes to an 8HD monster which "should" have 320 (which cannot be
represented in a signed char), should have 127, and will actually end up
with 64.
--
"An eclipse of the Earth occurs when you put your hands over your eyes."

Kenneth Arromdee
BITNET: G46I4701@JHUVM, INS_AKAA@JHUVMS, INS_AKAA@JHUNIX
ARPA: ins_akaa%jhunix@hopkins.ARPA
UUCP: {allegra!hopkins, seismo!umcp-cs, ihnp4!whuxcc} !jhunix!ins_akaa
Copyright 1987 by Ken Arromdee.  Distribution of this article by electronic
     means constitutes permission for its recipients to distribute it likewise.
(The NSA, CIA, and FBI conspire to smuggle Reagan drugs via Iran and Nicaragua.)