#include "stdafx.h"

#include "UI.h"

#include <stdio.h>

#include "Objects.h"
#include "Dispatch.h"
#include "CSB.h"
#include "Data.h"

pnt GetExternalPortraitAddress(i32 index);

//*********************************************************
//
//*********************************************************
//  TAG001098
i16 ScaledMultiply(i16 Op1,i16 scale,i16 Op2)
{
  return sw((UI16)(Op1) * ((UI16)(Op2)) >> scale);
}

//*********************************************************
//
//*********************************************************
//   TAG00144e
void DrawItem(i32 squareNumber, OBJECTTYPE objectType)
{
  dReg D0, D4, D5, D6;
  aReg A2;
  ICONDISPLAY *idA3;
  pnt LOCAL_12;
  RectPos LOCAL_8;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  //D7W = P1;
  //D6W = P2;
  idA3 = &d.IconDisplay[squareNumber]; // + 25 + 3*squareNumber;
  idA3->objectType(objectType);
  if (objectType == obj_NotAnObject) return;
  LOCAL_8.w.x1 = idA3->pixelX;
  LOCAL_8.w.x2 = (i16)(LOCAL_8.w.x1 + 15);
  LOCAL_8.w.y1 = idA3->pixelY;
  LOCAL_8.w.y2 = (i16)(LOCAL_8.w.y1 + 15);
  for (D5W=0; D5W<7; D5W++)
  {
    D0W = d.Word612[D5W];
    if (objectType < D0W) break;

  };
  D5W--;
  A2 = GetBasicGraphicAddress(D5W + 42);
  D6W = sw(objectType - d.Word612[D5W]);
  if (squareNumber >= 8)
  {
    LOCAL_12 = d.pViewportBMP;
    D4W = 112;
  }
  else
  {
    LOCAL_12 = d.LogicalScreenBase;
    D4W = 160;
  };
  d.UseByteCoordinates = 0;
  TAG0088b2(A2,
            LOCAL_12,
            &LOCAL_8,
            (D6W & 15) << 4,
            D6W & 0xff0,
            128,
            D4W,
            -1);
}

//*********************************************************
//
//*********************************************************
//   TAG0017d0
void DrawNameOfHeldObject(pnt dst,             //8
                          i16 dstWidth,        //12
                          i16 x,               //14
                          i32 y ,              //16
                          i16 textColor,       //18
                          i16 backgroundColor, //20
                          pnt text,            //22
                          i16 len)             //26
{
   // Copies the item`s name into local buffer and adjusts it
   // to the maximalTextLength length by placing spaces at
   // the end of item`s name.

  dReg D7;
  aReg A3;
  i8 LOCAL_80[80];
//;;;;;;;;;;;
  A3 = text;
  D7W = 0;
  while ((LOCAL_80[D7W]=*(A3++)) != 0) D7W++;

  while (D7W < len) LOCAL_80[D7W++] = ' ';




  LOCAL_80[D7W] = 0;
  TextOut_OneLine(dst,
                  dstWidth,
                  x,
                  y,
                  textColor,
                  backgroundColor,
                  LOCAL_80);
}

//*********************************************************
//
//*********************************************************
//   TAG001c16
void TextToViewport(i32 x, i32 y, i32 color, pnt txt)
{
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  TextOut_OneLine(d.pViewportBMP,
                  112,
                  x,
                  y,
                  color,
                  12,
                  txt);
}

//*********************************************************
//
//*********************************************************
//   TAG003264
void StrCpy(pnt dst,pnt src)
{
  do
  {
    *(dst++) = *src;
  } while (*(src++) != 0);
}

//*********************************************************
//
//*********************************************************
//   TAG009058
void ShadeRectangleInScreen(RectPos *P1,i16 P2)
{
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  ASSERT(verifyRectPos(P1));
  FillRectangle(d.LogicalScreenBase,
                P1,
                P2 | 0x8000,
                160);
}

//*********************************************************
//
//*********************************************************
i32 TAG009470(CLOTHINGDESC *P1, bool scale)
{
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  if (scale)
  {
    return ScaledMultiply(P1->uByte1(), 3, sw((P1->uByte2()&7) + 4));
  };
  return P1->uByte1();
}


//*********************************************************
//
//*********************************************************
// TAG009d9e
RN MakeMoreRoomInDB(DBTYPE dbType)
{ //(RN)
  //Oh, dear.  We have run out of space in one of
  //the databases.  What do we do now?  The standard Atari
  //version proceeds to discard objects, first from levels
  //the party does not currently occupy and, as a last
  //resort, from the party's level.
  //
  //The databases have rather arbitary size limits.  Perhaps
  //we can simply make the thing larger.  If it is possible
  //to enlarge the database then we will check to see if that
  //is what the player wants to do.
  dReg D0, D1, D4, D6, D7;
  RN  rnD5;
  LEVELDESC *pldA0;
  CELLFLAG  **pcfA0;
  CELLFLAG  *cfA3;
  DB3  *pDB3_4;
  DB4  *pDB4_4;
  DB5  *pDB5_4;
  DB6  *pDB6_4;
  DB8  *pDB8_4;
  DB10 *pDB10_4;
  DB14 *pDB14_4;
  RN  *rnA2;
  i16 w_14;
  i16 w_12;
  i16 w_10;
  i16 w_8;
  i16 w_6;
  D6L = 0x1baddade;
  i32 index;
  index = db.Enlarge(dbType); //If possible and player agrees.
  if (index != -1)
  {
    return RN(dbType,index);
  };
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  if (dbType == dbCLOUD)
  {
    return (RNnul); // Curious....I suppose this should never be.
  };
  w_8 = d.LoadedLevel;
  D4W = d.LevelCleared[dbType];
  if (d.partyLevel == D4W)
  {
    D4W++;
    D1W = d.dungeonDatIndex->NumLevel();
    if (D4W >= D1W) D4W = 0;
  };
  w_6 = D4W;
  for (;;)
  {
    pldA0 = &d.pLevelDescriptors[D4W];
//
    w_10 = sw(pldA0->LastColumn()); //level width-1
    w_12 = sw(pldA0->LastRow()); //level height-1
    pcfA0 = (CELLFLAG **)d.pppdPointer10450[D4W];
    cfA3 = *pcfA0;
    D0W = d.objectLevelIndex[D4W];
    D0W = d.objectListIndex[D0W];
    rnA2 = &d.objectList[D0W];
    for (D7W=0; D7W<=w_10; D7W++)
    {
      for (D6W=0; D6W<=w_12; D6W++)
      {
        if ((*(cfA3++) & 0x10) == 0) continue;
        rnD5 = *(rnA2++);
        if (D4W == d.partyLevel)
        {
          if (uw(D7W - d.partyX + 5) <= 10)
          {
            if (uw(D6W - d.partyY + 5) <= 10) continue;
          };
        };
        do
        {
          w_14 = sw(rnD5.dbType());
          if (w_14 == dbACTUATOR)
          {
            pDB3_4 = GetRecordAddressDB3(rnD5);
            if (pDB3_4->actuatorType() == 0) continue;
            break;
          }
          else
          {
            if (w_14 == dbType)
            {
              //punk_4 = GetDBRecordAddress(rnD5);
              switch (dbType)
              {
              case dbMONSTER:
                pDB4_4 = GetRecordAddressDB4(rnD5);
                D0W = pDB4_4->important();
                // Don't delete designer-planted monsters
                if (D0W != 0) continue;
                LoadLevel(D4W);
                TAG00b580(D7W, D6W, rnD5, -1);
                DeleteMonster(D7W, D6W);
                goto tag00a000;
                // Note fall-through from DB4 code
                // The original code processed monsters and
                // missiles together with "if () else;"
                // around the things that needed to be different.
                // I separated the two entirely.
              case dbMISSILE:
                  pDB14_4 = GetRecordAddressDB14(rnD5);
                // We will use the DB4 pointer for both
                // types of object even though they are
                // very different.  Hmmm...
                LoadLevel(D4W);
                TAG00e156(rnD5);
                RemoveObjectFromRoom(rnD5, D7W, D6W);
                PutObjectInMissile(rnD5, NULL, D7W, D6W);
                goto tag00a000;
              case dbCLOTHING:
                pDB6_4 = GetRecordAddressDB6(rnD5);
                if (pDB6_4->important()) continue;
                goto tag009fe4;
              case dbWEAPON:
                pDB5_4 = GetRecordAddressDB5(rnD5);
                if (pDB5_4->important()) continue;
                goto tag009fe4;

              case dbMISC:
                pDB10_4 = GetRecordAddressDB10(rnD5);
                if (pDB10_4->word2 & 0x80) continue;
                goto tag009fe4;
              case dbPOTION:
                pDB8_4 = GetRecordAddressDB8(rnD5);
                if (pDB8_4->important()) continue;
tag009fe4:
                LoadLevel(D4W);
                ASSERT(D6L != 0x1baddade);
                MoveObject(rnD5, D7W, D6W, -1, 0);
              default:
tag00a000:
              LoadLevel(w_8);
              d.LevelCleared[dbType] = D4UB;
                rnD5.pos(0);
                return (rnD5);
              }; //switch
            };
          };
        // continue for each object in room
        } while ((rnD5 = GetDBRecordLink(rnD5)) != RNeof);

      //continue (y-coordinate)
//
      }; //D6W = y-coordinate
    //continue (x-coordinate)
//
    };// D7W = x-coordinate
//
    if (   (D4W == d.partyLevel)
        || (d.dungeonDatIndex->NumLevel() <= 1) ) //# levels
    {
      d.LevelCleared[dbType] = D4UB;
      return (RNnul);
    };
    do
    {
      D4W++;
      D1W = d.dungeonDatIndex->NumLevel();
      if (D4W >= D1W) D4W = 0;
    } while (D4W == d.partyLevel);
    if (D4W == w_6)
    {
      D4W = d.partyLevel;
    };
  };
//00a0a8 ia0ac 4e5e                     UNLK     A6
}

//*********************************************************
//
//*********************************************************

//*********************************************************
//Attack from      Attack order
//  North pos 0 -> 0 1 3 2
//  North pos 1 -> 1 0 2 3
//  North pos 2 -> 1 0 2 3
//  North pos 3 -> 0 1 3 2
//  East  pos 0 -> 1 2 0 3
//  East  pos 1 -> 1 2 0 3
//  East  pos 2 -> 2 1 3 0
//  East  pos 3 -> 2 1 3 0
//  South pos 0 -> 3 2 0 1
//  South pos 1 -> 2 3 1 0
//  South pos 2 -> 2 3 1 0
//  South pos 3 -> 3 2 0 1
//  West  pos 0 -> 0 3 1 2
//  West  pos 1 -> 0 3 1 2
//  West  pos 2 -> 3 0 2 1
//  West  pos 3 -> 3 0 2 1
//*********************************************************
//   TAG00f694
void DetermineAttackOrder(
               ui8 result[4],
               i32 victimX,
               i32 victimY,
               i32 attackerX,
               i32 attackerY,
               i32 attackerPos)
{ // attackerPos is the position within the room
  // of the attacker.
  dReg D7;
  i32 attackFromDirection;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  attackFromDirection =
          GetPrimaryAndSecondaryDirection(
                            victimX, victimY,
                            attackerX, attackerY);
  // If zero then the attacker is to the north, etc
  D7W = sw(2*attackFromDirection);
  if ((attackFromDirection & 1) == 0)
  { // if attack is from north or south
    attackerPos++;
  };
  D7W = sw(D7W + ((attackerPos/2)&1));
  memmove(result, d.Byte586[D7W], 4);
}

//*********************************************************
//
//*********************************************************
//  TAG0139a2
i16 DecodeCharacterValue(pnt buf,i16 num)
{
  i32 result = 0;
  do
  {
    result <<= 4;
    if ( (*buf < 'A') || (*buf > 'P') ) return -1;
    result += *(buf++) - 'A';
    num--;
  } while (num!=0);
  return sw(result);

}

//*********************************************************
//
//*********************************************************
//   TAG0139be
void AddCharacter(i16 charID)
{//(void)
  dReg D0, D4, D5, D6;
  aReg A2;
  CHARDESC *pcA3;
  RN firstObj;
  i8  LOCAL_96[128];
  i32 LOCAL_18;
  i16 LOCAL_14;
  ui16 LOCAL_12; // contains position
  i16 LOCAL_10;
  i16 LOCAL_8;
  i16 LOCAL_6 = 0x2bad;
  i16 LOCAL_4;
  i16 LOCAL_2;
  bool illegalHero;
  i16 newHP, newStamina, newMana;
  static char legalHero[] =
    "BOGUS\012ILLEGAL HERO\012\012M\012AABBAABBAABB\012ABABABABABABAB\012CCCCCCCCCCCCCCCC";
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  if (d.EmptyHanded == 0) return; //cursor hand
  if (d.NumCharacter == 4) return;
  LOCAL_2 = d.NumCharacter;
  pcA3 = &d.CH16482[d.NumCharacter];
  ClearMemory((pnt)pcA3, 800);
  d.UseByteCoordinates = 1;

  
  
  
  if (charID <= 23)
  {
    TAG0088b2(GetBasicGraphicAddress(26),
              pcA3->portrait,
              (RectPos *)d.Byte1390,
              (charID&7)<<5,
              (charID>>3)*29,
              128,
              16,
              -1);
  }
  else
  {
    TAG0088b2(
        GetExternalPortraitAddress(charID),
        pcA3->portrait,
        (RectPos *)d.Byte1390,
        0, //Src offset X
        0, //Src offset Y
        16, //Src Byte Width
        16,//Dst Byte Width
        -1);
  };
  
  pcA3->byte30 = 1;
  pcA3->byte31 = 2;
  pcA3->attackType = -1;
  pcA3->busyTimer = -1;
  pcA3->timerIndex = -1;
  pcA3->facing = (ui8)d.partyFacing;
  for (D6W=0;
       CharacterAtPosition((D6W+d.partyFacing)&3) != -1;
       D6W++) {};

//

  pcA3->position = ub((D6W + d.partyFacing)&3);
  pcA3->word48 = 0x400; // 1024
  pcA3->facing3 = (ui8)d.partyFacing;
  pcA3->food = sw((STRandom() & 0xff) + 1500);
  pcA3->water = sw((STRandom() & 0xff) + 1500);
  for (D6W=0; D6W<30; D6W++)
  {
    pcA3->possessions[D6W] = RN(RNnul);


  };
  firstObj = FindFirstObject(d.partyX, d.partyY);
  while (firstObj != RNeof)
  {
    if (firstObj.dbType() == dbTEXT) break;
    firstObj = GetDBRecordLink(firstObj); // Find character's name and title
  };
  if (firstObj != RNeof)
  {
    DecodeText(A2 = LOCAL_96,
               GetRecordAddressDB2(firstObj),
               (ui16)0x8002,
               128);
  }
  else
  {
    A2 = legalHero;
  };
  for (illegalHero=true; illegalHero; A2=legalHero)
  {
    illegalHero = false;
    for (D6W=0; (D4W=(UI8)(*(A2++)))!=10; D6W++)
    {
      if (D6W >= 7)
      {
        illegalHero = true;
        break;
      };
      pcA3->name[D6W] = D4B; // At Byte0

    };
    if (illegalHero) continue;
    pcA3->name[D6W] = 0;
    D6W = 0;
    LOCAL_4 = 0;
    for (;;)
    {
      D4W = (UI8)(*(A2++));
      if (D4W == 10)
      {
        if (LOCAL_4 !=0) break;
        LOCAL_4 = 1;
      }
      else
      {
        if (D6W >= 19)
        {
          illegalHero = true;
          break;
        };
        pcA3->title[D6W] = D4B;
        D6W++;
      };
    };
    if (illegalHero) continue;
    pcA3->title[D6W] = 0;
    D0W = *(A2++);
    if (D0W == 'M')
    {
      pcA3->word48 |= 16;
    }
    else if (D0W != 'F')
    {
      illegalHero = true;
      continue;
    };
    A2++;
    newHP = DecodeCharacterValue(A2, 4);
    if ((unsigned)newHP > MAXHP) 
    {
      pcA3->MaxHP(MAXHP);
      illegalHero = true;
    }
    else pcA3->MaxHP(newHP);
    pcA3->HP(pcA3->MaxHP());
    if (newHP == -1)
    {
      illegalHero = true;
      continue;
    };
    A2 += 4;
    newStamina = DecodeCharacterValue(A2, 4);
    if ((unsigned)newStamina <= MAXSTAMINA) pcA3->MaxStamina(newStamina);
    else 
    {
      pcA3->MaxStamina(MAXSTAMINA);
      illegalHero = true;
    };
    pcA3->Stamina(pcA3->MaxStamina());
    if (newStamina == -1)
    {
      illegalHero = true;
      continue;
    };
    A2 += 4;
    newMana = DecodeCharacterValue(A2, 4);
    if ((unsigned)newMana > MAXMANA) 
    {
      pcA3->MaxMana(MAXMANA);
      illegalHero = true;
    }
    else pcA3->MaxMana(newMana);
    pcA3->Mana(pcA3->MaxMana());
    if (newMana == -1)
    {
      illegalHero = true;
      continue;
    };
    A2 += 5;
    for (D6W=0; D6W<=6; D6W++) // strength, wisdom, etc
    {
      pcA3->Attributes[D6W].Minimum(30);
      D0W = DecodeCharacterValue(A2, 2);
      if (D0W == -1)
      {
        illegalHero = true;
        break;
      };
      if (D0W > 224) D0W = 224;
      pcA3->Attributes[D6W].Maximum(D0B);
      pcA3->Attributes[D6W].Current(D0B);
      A2 += 2;
//
    };
    if (illegalHero) continue;
    pcA3->Attributes[Luck].Minimum(10);
    A2++;
    for (D6W=4; D6W<=19; D6W++)
    {
      D4W = sw(*(A2++) - 'A');
      if (D4W > 0)
      {
        D0L = 125 << D4W;
        pcA3->skills92[D6W].Long2 = D0L;
      };
//
    };
    for (D6W=0; D6W<=3; D6W++)
    {
      LOCAL_18 = 0;
      D5W = sw(4 * (D6W + 1));
      for (LOCAL_4=0; LOCAL_4<4; LOCAL_4++)
      {
        LOCAL_18 += pcA3->skills92[D5W+LOCAL_4].Long2;
//
      };
      pcA3->skills92[D6W].Long2 = LOCAL_18;
//
    };
  };
  if (pcA3->HP() == 0) return;
  d.PotentialCharacterOrdinal = sw(LOCAL_2 + 1);
  d.NumCharacter++;
  if (d.NumCharacter == 1)
  {
    SetHandOwner(0);
    d.Word20250 = 1;
  }
  else
  {
    TAG01b1c0();
    DrawAttackButton(d.NumCharacter-1); // Show additional weapon selector
  };
  LOCAL_8 = d.partyX;
  LOCAL_10 = d.partyY;
  LOCAL_12 = sw((d.partyFacing+2)&3);
  LOCAL_8 = sw(LOCAL_8 + d.DeltaX[d.partyFacing]);
  LOCAL_10 = sw(LOCAL_10 + d.DeltaY[d.partyFacing]);
  firstObj = FindFirstObject(LOCAL_8, LOCAL_10);
  D6W = 13;
  while (firstObj != RNeof)
  {
    D4W = sw(firstObj.dbType());
    if (D4W > dbACTUATOR)
    {
      if (firstObj.pos() == LOCAL_12)
      {
        D0W = GetObjectIndex(firstObj);
        LOCAL_14 = d.ObjDesc[D0W].word4; //Carry locations mask
        switch (D4W)
        {
        case dbCLOTHING:
            for (LOCAL_6=2; LOCAL_6<=5; LOCAL_6++)
            {
              if (LOCAL_14 & d.CarryLocation[LOCAL_6])
                      goto switchbreak;

            };
            // Check Neck
            if (   ((LOCAL_14&d.CarryLocation[10])!=0)
                && (pcA3->possessions[10] == RNnul) )
            {
              LOCAL_6 = 10;
            }
            else
            {
              goto case9;
            };
            break;
        case dbWEAPON:
            if (pcA3->possessions[1] != RNnul) goto case9;
            LOCAL_6 = 1;
            break;

        case dbSCROLL:
        case dbPOTION:
            if (pcA3->possessions[11] == RNnul)
            {
              LOCAL_6 = 11;
            }
            else
            {
              if (pcA3->possessions[6] == RNnul)
              {
                LOCAL_6 = 6;
              };
              goto case9;
            };
            break;
        case dbCHEST:
        case dbMISC:
case9:
            // Check neck
            if (   ((LOCAL_14&d.CarryLocation[10])!=0)
                && (pcA3->possessions[10] == RNnul) )
            {
              LOCAL_6 = 10;
              break;
            };
            LOCAL_6 = D6W;
            D6W++;
        };
switchbreak:
        if (pcA3->possessions[LOCAL_6] != RNnul) goto case9;
        if (LOCAL_6 < 30)
        {
          PlaceObjectOnCharacter(LOCAL_2, firstObj, LOCAL_6);
        };
      };
    };
    firstObj = GetDBRecordLink(firstObj);

  };
  TAG0192f4(LOCAL_2); // Display resurrect/reincarnate/cancel screen
  TAG02076e();
}

//*********************************************************
//
//*********************************************************
//   TAG014676
void BringCharacterToLife(ui16 chIdx)
{//(void)
  dReg D0, D7;
  CHARDESC *pcA3;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  pcA3 = &d.CH16482[chIdx];
  D0W = CharacterAtPosition(pcA3->position);
  if (D0W != -1)
  { //Find a position to put the character.
    for (D7W=0; CharacterAtPosition(D7W)!=-1; D7W++) {};
//
//
    pcA3->position = D7UB;
  };
  D7W = pcA3->MaxHP();
  D0W = sw(D7W - D7W/64 - 1);
  pcA3->MaxHP(Larger(25, D0W));
  pcA3->HP(pcA3->MaxHP() / 2);
  TAG01b50e(d.MagicCaster);
  pcA3->facing = (ui8)d.partyFacing;
  pcA3->word48 |= 0x9400;
  DrawCharacterState(chIdx);
}

//*********************************************************
//
//*********************************************************
// Internal subroutine called by TAG014832
void TAG014a60(dReg D0,
               dReg D2,
               dReg D3,
               dReg D4,
               dReg D5,
               dReg D6,
               dReg D7,
               aReg& A2)
{
  dReg D1;
  D2W = LE16(D2W);
  D3W = LE16(D3W);
  D4W = LE16(D4W);
  D5W = LE16(D5W);
  for (D1W=24; D1W>=0; D1W--)
  {
    if (D0W <= D1W)
    {
      wordGear(A2+ 0) &= D4W;
      wordGear(A2+ 8) &= D5W;
      wordGear(A2+ 2) &= D4W;
      wordGear(A2+10) &= D5W;
      wordGear(A2+ 4) |= D2W;
      wordGear(A2+12) |= D3W;
      wordGear(A2+ 6) |= D2W;
      wordGear(A2+14) |= D3W;
    }
    else
    {
      if (D6W)
      {
        wordGear(A2+0) |= D2W;
        wordGear(A2+8) |= D3W;
      }
      else
      {
        wordGear(A2+0) &= D4W;
        wordGear(A2+8) &= D5W;
      };
      if (D6L < 0)
      {
        wordGear(A2+ 2) |= D2W;
        wordGear(A2+10) |= D3W;
      }
      else
      {
        wordGear(A2+ 2) &= D4W;
        wordGear(A2+10) &= D5W;
      };
      if (D7W)
      {
        wordGear(A2+ 4) |= D2W;
        wordGear(A2+12) |= D3W;
      }
      else
      {
        wordGear(A2+ 4) &= D4W;
        wordGear(A2+12) &= D5W;
      };
      if (D7L < 0)
      {
        wordGear(A2+ 6) |= D2W;
        wordGear(A2+14) |= D3W;
      }
      else
      {
        wordGear(A2+ 6) &= D4W;
        wordGear(A2+14) &= D5W;
      };
    };
    A2 += 160;
  }; // for (D1W...)
}

//*********************************************************
//
//*********************************************************
//   TAG014832
void DrawLifeBars(i32 chIdx)
{
  dReg D0, D1, D2, D3, D4, D5, D6, D7;
  aReg A0, A2;
  i16 LOCAL_6[3]; // The three bar heights
  i16 *pwA3;
  CHARDESC *pcA3;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  pcA3 = &d.CH16482[chIdx];
  D6W = 0;
  if (pcA3->HP() > 0)
  {
    D5L = 25 * (pcA3->HP() << 10) / pcA3->MaxHP();
    if (D5L&0x3ff)
    {
      D0L = (D5L >> 10) + 1;
      //D1L = (D6W+1) << 1;
      LOCAL_6[D6W++] = D0W;
    }
    else
    {
      D0L = D5L >> 10;
      //D1L = (D6W+1)<<1;
      LOCAL_6[D6W++] = D0W;
    };
  }
  else
  {
    //D0L = (D6W++) << 1;
    LOCAL_6[D6W++] = 0;
  };
  if (pcA3->Stamina() > 0)
  {
    D5L = 25*((pcA3->Stamina())<<10) / pcA3->MaxStamina();
    //TAG0030e6(pcA3->word58, D5L, &D5L, NULL)
    if (D5L & 0x3ff)
    {
      D0L = (D5L >> 10) + 1;
      LOCAL_6[D6W++] = D0W;
    }
    else
    {
      D0L = D5L >> 10;
      LOCAL_6[D6W++] = D0W;
    };
  }
  else
  {
    LOCAL_6[D6W++] = 0;
  };
  if (pcA3->Mana() > 0)
  {
    if (pcA3->Mana() > pcA3->MaxMana())
    {
      LOCAL_6[D6W] = 25;
    }
    else
    {
      D5L = ((25 * pcA3->Mana()) << 10) / pcA3->MaxMana();
      if (D5L & 0x3ff)
      {
        D0L = (D5L >> 10) + 1;
        LOCAL_6[D6W] = D0W;

      }
      else
      {
        D0L = D5L >> 10;
        LOCAL_6[D6W] = D0W;
      };
    };
  }
  else
  {
    LOCAL_6[D6W] = 0;
  };
  STHideCursor();
  A0 = d.LogicalScreenBase+320;
  D1L = chIdx;
  if (D1W >= 3)
  {
    D6L = 0x80000000;
    D7L = D6L + 1;
  }
  else
  {
    if (D1W >= 2)
    {
      D6L = 0;
      D7L = 0x80000000;
    }
    else
    {
      if (D1W >= 1)
      {
        D6L = 0x80000001;
        D7L = D6L - 1;
      }
      else
      {
        D6L = 0x80000001;
        D7L = 1;
      };
    };
  };
  //LOCAL_8 = D1W + 4;
  pwA3 = LOCAL_6;
  for (i32 i=0; i<3; i++) // Three bars
  {
    A2 = A0;
    //pwA1 = d.Word1526[0];
    A2 += d.Word1526[D1W][i];
    //pwA1 = d.Word1502[0];
    D2W = d.Word1502[D1W][2*i];
    D3W = d.Word1502[D1W][2*i+1];
    D4W = (I16)(D2W ^ 0xffff);
    D5W = (I16)(D3W ^ 0xffff);
    D0W = *(pwA3++); // bar height
    TAG014a60(D0,D2,D3,D4,D5,D6,D7,A2);
    //if (LOCAL_8 == D1W) break;
    //D1W++;
  };
  STShowCursor();
}

//*********************************************************
//
//*********************************************************
pnt TAG014af6(i32 num, i32 flag,i32 width)
{ // if flag==0 then no leading blanks.
  dReg D0;
  pnt result;
  aReg A1;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  if (num > 9999) num = 9999;
  D0W = sw(4-width);
  A1 = d.Byte16606;
  result = A1 + D0W;
  wordGear(A1) = 0x2020;;
  wordGear(A1+2) = 0x2020;
  A1 += 4;
  *A1 = 0;
  //D1L = 0;
  do
  {
    *(--A1) = sb((num%10) + '0');
    num /= 10;
  } while (num != 0);
  if (flag == 0) result = A1;
  return result;
}

//*********************************************************
//
//*********************************************************
//   TAG014b32
void PrintLifeForce(i32 line, i32 current, i32 max)
{
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
//
  TextToViewport(55,
            line,
            13,
            TAG014af6(current, 1, 3));
  TextToViewport(73, line, 13, "/");
  TextToViewport(79,
            line,
            13,
            TAG014af6(max,1,3));
}

//*********************************************************
//
//*********************************************************
//   TAG014b9e
void PrintLifeForces(CHARDESC *pChar)
{
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  PrintLifeForce(116, pChar->HP(), pChar->MaxHP());
  PrintLifeForce(124,pChar->Stamina()/10, pChar->MaxStamina()/10);
  PrintLifeForce(132, pChar->Mana(), pChar->MaxMana());
}

//*********************************************************
//
//*********************************************************
//   TAG014bf4
void DisplayBackpackItem(i32 chIdx, i32 itemNum)
{
  dReg D0, D5, D7;
  RN objD6;
//  aReg A2;
  ICONDISPLAY *idA2;
  CHARDESC *pcA3;
  OBJECTTYPE otD4;
  i16 LOCAL_26;
  pnt LOCAL_24;
  i16 LOCAL_20;
  RectPos LOCAL_18;
  i32 squareNumber;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  D7W = sw(itemNum);
  LOCAL_20 = -1;
  pcA3 = &d.CH16482[chIdx];
  // Is it to be drawn in viewport?
  D5W = sw((d.SelectedCharacterOrdinal == (chIdx+1)) ? 1 : 0);
  if (D5W == 0)
  {
    if (D7W > 1) return;
    if (d.PotentialCharacterOrdinal == (chIdx+1)) return;
    squareNumber = 2*chIdx + D7W;
  }
  else
  {
    squareNumber = D7W + 8; // Skip over hands in portrait areas
  };
  if (D7W >= 30)
  {
    objD6 = d.rnChestContents[D7W-30];
  }
  else
  {
    objD6 = pcA3->possessions[D7W];
  };
  idA2 = &d.IconDisplay[squareNumber];
  LOCAL_18.w.x1 = sw(idA2->pixelX - 1);
  LOCAL_18.w.x2 = sw(LOCAL_18.w.x1 + 17);
  LOCAL_18.w.y1 = sw(idA2->pixelY - 1);
  LOCAL_18.w.y2 = sw(LOCAL_18.w.y1 + 17);
  if (D5W) // if drawing backback screen
  {
    LOCAL_24 = d.pViewportBMP;
    LOCAL_26 = 112;
  }
  else
  {
    LOCAL_24 = d.LogicalScreenBase;
    LOCAL_26 = 160;
    STHideCursor();
  };
  if (objD6 == RNnul)
  {
    if (D7W <= 5)
    {
      otD4 = obj_Special_n;
      otD4 = (OBJECTTYPE)(otD4 + 2*D7W);
      D0W = sw(pcA3->ouches & (1 << D7W));
      if (D0W)
      {
        otD4 = (OBJECTTYPE)(otD4+1);
        LOCAL_20 = 34;
      }
      else
      {
        LOCAL_20 = 33;
      };
    }
    else
    {
      if ( (D7W>=10) && (D7W <= 13) )
      {
        otD4 = (OBJECTTYPE)(obj_Special_j + (D7W - 10));
      }
      else
      {
        otD4 = obj_Special_f;
      };
    };
  }
  else
  {
    otD4 = GetModifiedObjectType(objD6);
    if (   (D5W)
        && (D7W==1)
        && ((otD4==obj_Chest) || (otD4==obj_OpenScroll)) )
    {
      otD4 = (OBJECTTYPE)(otD4 + 1);;
    };
    if (D7W <= 5)
    {
      if (pcA3->ouches & (1 << D7W))
      {
        LOCAL_20 = 34;
      }
      else
      {
        LOCAL_20 = 33;
      };
    };
  };
  if ( (D7W==1) && ((chIdx+1) == d.AttackingCharacterOrdinal) )
  {
    LOCAL_20 = 35;
  };
  if (LOCAL_20 != -1)
  {
    d.UseByteCoordinates = 0;
    TAG0088b2(GetBasicGraphicAddress(LOCAL_20),
              LOCAL_24,
              &LOCAL_18,
              0,
              0,
              16,
              LOCAL_26,
              12);
  };
  DrawItem(squareNumber, otD4);
  if (D5W == 0)
  {
    STShowCursor();
  };
}

//*********************************************************
//
//*********************************************************
//   TAG014de0
void DrawCharacterState(i32 chIdx) // Character box at top of screen                                //
{//(void)
  static dReg D0, D1, D4, D5, D6;
  static aReg A0;
  static i32 itemNum;
  static CHARDESC *pcA3, *pcA2;
  static i32 maxLoad;
  static i16 LOCAL_32;
  static i16 LOCAL_22[3];
  static RectPos LOCAL_16;
  static i16 LOCAL_8;
  static i16 LOCAL_6;
  static i16 LOCAL_4;
  static i8  LOCAL_1;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  LOCAL_4 = sw(69 * chIdx);
  pcA3 = d.CH16482 + chIdx;
  D6W = pcA3->word48;
  if (D6W & 0xff80 == 0) return;
  D5W = ((chIdx+1) == d.SelectedCharacterOrdinal);
  d.UseByteCoordinates = 0;
  STHideCursor();
  if((D6W & 0x1000)!=0)
  {
    LOCAL_16.w.y1 = 0;
    LOCAL_16.w.y2 = 28;
    LOCAL_16.w.x1 = LOCAL_4;
    LOCAL_16.w.x2 = sw(LOCAL_16.w.x1 + 66);
    if (pcA3->HP() !=0)
    {
      FillRectangle(d.LogicalScreenBase, &LOCAL_16, 12, 160);//Clear rectangle at top
      ClearMemory((pnt)LOCAL_22, 6);
      D4W = 0;
      if (d.Word13276 > 0)
      {
        LOCAL_22[D4W++] = 38;
      };
      if (d.Word13274 > 0)
      {
        LOCAL_22[D4W++] = 39;
      };
      if ((d.Word13278>0) || (pcA3->shieldStrength!=0))
      {
        LOCAL_22[D4W++] = 37;
      };
      while ((D4W--) != 0)
      {
        BLT2Screen(GetBasicGraphicAddress(LOCAL_22[D4W]), // Puts dots around character status box
                  &LOCAL_16,
                  40,
                  10);
      } ;
      if (D5W !=0)
      {
        CharacterPortraitToStatusBox(chIdx);
        D6W |= 0x100;
      }
      else
      {
        D6W |= 0xa180;
      };
      goto tag014f58;
    };
    BLT2Screen(GetBasicGraphicAddress(8), &LOCAL_16, 40, -1);
    TextOutToScreen(LOCAL_4+1, 5, 13, 1, pcA3->name);
    DrawAttackButton(chIdx);
  }
  else
  {
tag014f58:
    if (pcA3->HP() != 0)
    {
      if ((D6W&0x80) != 0)
      {
        D4W = sw(chIdx);
        if (D4W == d.HandChar) // cursor's owner
        {
          D4W = 9;
        }
        else
        {
          D4W = 13;
        };
        if (D5W != 0)
        {
          pcA2 = pcA3;
          TextToViewport(3, 7, D4W, pcA2->name);
          LOCAL_32 = StrLen(pcA2->name);
          LOCAL_6 = sw(6 * LOCAL_32 + 3);
          LOCAL_1 = pcA3->title[0];
          if (LOCAL_1 != 44)
          {
            if (LOCAL_1 != 59)
            {
              if (LOCAL_1 != 45)
              {
                LOCAL_6 += 6;
              };
            };
          };
          TextToViewport(LOCAL_6, 7, D4W, pcA3->title);
          D6W |= 0x4000;
        }
        else
        {
          LOCAL_16.w.y1 = 0;
          LOCAL_16.w.y2 = 6;
          LOCAL_16.w.x1 = LOCAL_4;
          LOCAL_16.w.x2 = sw(LOCAL_16.w.x1 + 42);
          FillRectangle(d.LogicalScreenBase,
                        &LOCAL_16,
                        1,
                        160);
          TextOutToScreen(LOCAL_4+1,
                          5,
                          D4W,
                          1,
                          pcA3->name);
        };
      };
      if ((D6W&0x100) != 0)
      {
        DrawLifeBars(chIdx);
        if (D5W != 0)
        {
          PrintLifeForces(pcA3);//Health,stamina,mana bars
          if (   (pcA3->food < 0)
              || (pcA3->water < 0)
              || (pcA3->uByte42 != 0) )
          {
            LOCAL_8 = 34;
          }
          else
          {
            LOCAL_8 = 33;
          };
          BLT2Viewport(GetBasicGraphicAddress(LOCAL_8),    // Box around mouth
                    (RectPos *)d.Word1398,
                    16,
                    12);
          LOCAL_8 = 33;
          for (D4W=1; D4W<=6; D4W++)
          {
            D0W = pcA3->Attributes[D4W].Current();
            D1W = pcA3->Attributes[D4W].Maximum();
            if (D0W < D1W)
            {
              LOCAL_8 = 34;
              break;
            };
//
          };
          BLT2Viewport(GetBasicGraphicAddress(LOCAL_8),  //Box around eye
                    (RectPos *)d.Word1406,
                    16,
                    12);
          D6W |= 0x4000;
        };
      };
      if ((D6W&0x2000) != 0)
      {
        itemNum = D5W;
        if (itemNum != 0)
        {
          itemNum = 5;
        }
        else
        {
          itemNum = 1;
        };
        while (itemNum >= 0)
        {
          DisplayBackpackItem(chIdx, itemNum);
          itemNum--;
        };
        if (D5W != 0)
        {
          D6W |= 0x4000;
        };
      };
      if ( (D6W&0x200) && (D5W) )
      {
        D4W = sw(maxLoad = MaxLoad(pcA3));
        //LOCAL_42 = D4W;
        if (pcA3->load > maxLoad)
        {
          LOCAL_8 = 8;
        }
        else
        {
          D0L = 8*pcA3->load;
          D1L = D4W;
          D1L = 5 * D1L;
          if (D0L > D1L)
          {
            LOCAL_8 = 11;
          }
          else
          {
            LOCAL_8 = 13;
          };
        };
        TextToViewport(104, 132, LOCAL_8, "LOAD");
        D4W = sw(pcA3->load / 10);
        A0 = TAG014af6(D4W, 1, 3);
        StrCpy(d.Byte12914, A0);
        StrCat(d.Byte12914, ".");
        D4W = sw(pcA3->load - 10*D4W);
        A0 = TAG014af6(D4W, 0, 1);
        StrCat(d.Byte12914, A0);
        StrCat(d.Byte12914, "/");
        D0L = MaxLoad(pcA3);
        D4W = sw((D0L+5)/10);
        A0 = TAG014af6(D4W, 1, 3);
        StrCat(d.Byte12914, A0);
        StrCat(d.Byte12914, " KG");
        TextToViewport(148, 132, LOCAL_8, d.Byte12914);// "LOAD  actual/max"
        D6W |= 0x4000;
      };
      D4W = sw((pcA3->position+4-d.partyFacing) & 3);
      if (D6W & 0x400)
      {
        if ((D4W+1) != d.Word23144)
        {
//

          FillRectangle(d.LogicalScreenBase,   // Fill pos/dir rectangle
                        &d.wRectPos1454[D4W], // with character's color
                        d.Byte1386[chIdx],
                        160);


          TAG0088b2(GetBasicGraphicAddress(28),  // Overlay character's pos/dir icon
                    d.LogicalScreenBase,
                    &d.wRectPos1454[D4W],
                    ((pcA3->facing+4-d.partyFacing) & 3) * 19,
                    0,
                    40,
                    160,
                    12);
        };
      };
      if ( (D6W&0x800) && (D5W) )
      {
        if (d.Word11760)
        {
          DisplayFoodWater();
        }
        else
        {
          if (d.Word11756)
          {
            if (d.EmptyHanded) //cursor hand
            {
              TAG019036();
            };
          }
          else
          {
            TAG0189d4();
          };
        };
        D6W |= 0x4000;
      };
      if (D6W & 0x8000)
      {
        DisplayBackpackItem(chIdx, 1);
        DrawAttackButton(chIdx);
        if (D5W)
        {
          D6W |= 0x4000;
        };
      };
      if (D6W & 0x4000)
      {
        MarkViewportUpdated(0);
      };
    };
    pcA3->word48 &= 0x7f;
  };
  STShowCursor();
}

//*********************************************************
//
//*********************************************************
i16 TAG0153c2(i32 chIdx,
              i32 possessionIndex1,
              i32 possessionIndex2)
{
  dReg D0, D6;
  CHARDESC   *pcA3;
  WEAPONDESC *weaponDescA2;
  RN  objD7;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  pcA3 = &d.CH16482[chIdx];
  objD7 = pcA3->possessions[possessionIndex1];
  if (objD7 == RNnul) return 0;
  if (objD7.dbType() != dbWEAPON) return 0;
  weaponDescA2 = TAG0099d2(objD7);
  if ( (weaponDescA2->uByte1 >= 16) && (weaponDescA2->uByte1 <= 31) )
  {
    D6W = 10;
  }
  else
  {
    if ( (weaponDescA2->uByte1 >= 32) && (weaponDescA2->uByte1 <= 47) )
    {
      D6W = 11;
    }
    else
    {
      return 0;
    };
  };
  objD7 = pcA3->possessions[possessionIndex2];
  //
  // I added the following line.  So TAG0099d2
  // won't complain.
  // We return anyway if db != 5 and TAG0099d2 has no
  // side-effects.
  if (objD7 == RNnul) return 0;
  if (objD7.dbType() != dbWEAPON) return 0;
  weaponDescA2 = TAG0099d2(objD7);
  D0W = sw(objD7.dbType());
  //Must be 5! ... if (D0W != 5) return 0;
  if (weaponDescA2->uByte1 != D6W) return 0;
  return 1;
}

//*********************************************************
//
//*********************************************************
void TAG0157e8(CHARDESC *pChar,
               i32 possessionIndex,
               OBJECTTYPE ot,
               i32 P4,
               RN P5)
{
  dReg D4;
  DB5      *pDB5_4;
  DB6      *pDB6_4;
  DBTYPE DBType;
  enum
  {
    adjustLuck      = 0,
    adjustStrength  = 1,
    adjustDexterity = 2,
    adjustWisdom    = 3,
    adjustVitality  = 4,
    adjustAntiMagic = 5,
    adjustAntiFire  = 6,
    adjustMaxMana   = 8,
    adjustIllegal   = 99
  } whatToAdjust = adjustIllegal;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  //D7W = sw(P2);
  //D6W = P3;
  D4W = 0; // Assume no adjustment to Luck
  DBType = P5.dbType();
  for (;;) // Fake to avoid 'goto's.  I like 'break's better.
  {
    // The D7 tests were strange in the original.  It appeared
    // to be an unsigned test for >= 0.  Unnecessary.
    if (    (DBType == dbWEAPON)
         && (possessionIndex>=0) && (possessionIndex<=12) )
    { // Weapon or clothing.  Person, purse, or quiver.
      // Handled together in the original.  I wroke them apart.
      pDB5_4 = GetRecordAddressDB5(P5);
//
//
//
      if ( pDB5_4->cursed() )
      {
        whatToAdjust = adjustLuck;
        D4W = -3;
        break;
      };
    };
    if (    (DBType == dbCLOTHING)
         && (possessionIndex>=0)
         && (possessionIndex<=12) )
    { // Weapon or clothing.  Person, purse, or quiver.
      // Handled together in the original.  I wroke them apart.
      pDB6_4 = GetRecordAddressDB6(P5);
      if ( pDB6_4->cursed() )
      {
        whatToAdjust = adjustLuck;
        D4W = -3;
        break;
      };
    };
    if ( (ot==obj_RabbitsFoot) && (possessionIndex<30) )
    {
      whatToAdjust = adjustLuck;
      D4W = 10;
      break;
    };
    if (possessionIndex == 1) //Weapon hand
    {
      if (ot == obj_MaceOfOrder)
      {
        whatToAdjust = adjustStrength;
        D4W = 5;
        break;
      }
      else
      {
        whatToAdjust = adjustMaxMana;
        if (   (ot >= obj_StaffOfClaws_a)
            && (ot <= obj_StaffOfClaws_c) )
        {
          D4W = 4;
        }
        else
        {
          if ( (ot >= obj_Staff) && (ot <= obj_SceptreOfLyf) )
          {
            switch (ot)
            {
            case obj_Staff: D4W = 2; break;

            case obj_Wand: D4W = 1; break;

            case obj_TeoWand: D4W = 6; break;

            case obj_YewStaff: D4W = 4; break;

            case obj_StaffOfIrra: D4W = 10; break;

            case obj_CrossOfNeta: D4W = 8; break;

            case obj_SerpentStaff: D4W = 16; break;

            case obj_DragonSpit: D4W = 7; break;

            case obj_SceptreOfLyf: D4W = 5; break;
            };
          }
          else
          {
            if (ot == obj_SideSplitter)
            {
              D4W = 1;
            }
            else
            {
              if (ot == obj_DragonFang)
              {
                D4W = 2;
              }
              else
              {
                if (ot == obj_VorpalBlade)
                {
                  D4W = 4;
                };
              };
            };
          };
        };
      };
      break;
    };
    if (possessionIndex == 4) // Legs
    {
      if (ot == obj_Powertowers)
      {
        whatToAdjust = adjustStrength;
        D4W = 10;
      };
      break;
    };
    if (possessionIndex == 2) // Head
    {
      if (ot == obj_CrownOfNerra)
      {
        whatToAdjust = adjustWisdom;
        D4W = 10;
      }
      else
      {
        if (ot == obj_Dexhelm)
        {
          whatToAdjust = adjustDexterity;
          D4W = 10;
        };
      };
      break;
    };
    if (possessionIndex == 3) // on Body
    {
      if (ot == obj_Flamebain)
      {
        whatToAdjust = adjustAntiFire;
        D4W = 12;
      }
      else
      {
        if (ot == obj_CloakOfNight)
        {
          whatToAdjust = adjustDexterity;
          D4W = 8;
        };
      };
      break;
    };
    if (possessionIndex != 10) break; //Necklace
    if ( (ot >= obj_JewelSymal_a) && (ot <= obj_JewelSymal_b) )
    {
      whatToAdjust = adjustAntiMagic;
      D4W = 15;
      break;
    };
    if (ot == obj_CloakOfNight)
    {
      whatToAdjust = adjustDexterity;
      D4W = 8;
      break;
    };
    if (ot != obj_Moonstone) break;
    whatToAdjust = adjustMaxMana;
    D4W = 3;
    break;
  }; // Fake 'while' loop to avoid 'goto's
  if (D4W == 0) return;
  ASSERT(whatToAdjust != adjustIllegal);
  D4W = sw(D4W * P4);// Increment or decrement;
  if (whatToAdjust == adjustMaxMana)
  {
    pChar->MaxMana(pChar->MaxMana() + D4W);
  }
  else
  {
    if (whatToAdjust <= adjustAntiFire)
    {
        pChar->Attributes[whatToAdjust].IncrMaximum(D4W);
        pChar->Attributes[whatToAdjust].IncrCurrent(D4W);
        pChar->Attributes[whatToAdjust].IncrMinimum(D4W);
    };
  };
  pChar->word48 |= 0x900;
}

//*********************************************************
//
//*********************************************************
// TAG015a66
RN RemovePossession(i32 chIdx,i32 possessionIndex)
{//(RN)
  dReg D0;
  RN objD5, objD6;
  OBJECTTYPE otD5;
  DBCOMMON *dbA2;
  CHARDESC *pcA3;
  i16 LOCAL_2;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  pcA3 = &d.CH16482[chIdx];
  if (possessionIndex >= 30)
  {
    objD6 = d.rnChestContents[possessionIndex-30];
    if (TimerTraceActive)
    {
      fprintf(GETFILE(TraceFile),"Remove object %04x from chest index %d belonging to %s\n",
                   objD6.ConvertToInteger(), possessionIndex, pcA3->name);
    };
    d.rnChestContents[possessionIndex-30] = RN(RNnul);
  }
  else
  {
    objD6 = pcA3->possessions[possessionIndex];
    if (TimerTraceActive)
    {
      fprintf(GETFILE(TraceFile),"Remove object %04x from backpack index %d belonging to %s\n",
                   objD6.ConvertToInteger(), possessionIndex, pcA3->name);
    };
    pcA3->possessions[possessionIndex] = RN(RNnul);
  };
  if (objD6 == RNnul)
  {
    return (RNnul);
  };
  LOCAL_2 = sw(chIdx+1 == d.SelectedCharacterOrdinal ? 1 : 0);
  otD5 = GetModifiedObjectType(objD6);
  TAG0157e8(pcA3, possessionIndex, otD5, -1, objD6);
  dbA2 = GetCommonAddress(objD6);
  if (possessionIndex == 10)
  {
    if (   (otD5 >= obj_Illumulet_a)
        && (otD5 <= obj_Illumulet_b) )
    {
      dbA2->CastToDB10()->value(0); // Of no use anymore.
      d.Brightness = sw(d.Brightness - d.Word1074[2]);
      SelectPaletteForLightLevel();
    }
    else
    {
      if (   (otD5 >= obj_JewelSymal_a)
          && (otD5 <= obj_JewelSymal_b) )
      {
        dbA2->CastToDB10()->value(0);//Of no use anymore
      };
    };
  };
  DisplayBackpackItem(chIdx, possessionIndex);
  if (LOCAL_2)
  {
    pcA3->word48 |= 0x4000;
  };
  if (possessionIndex <2)
  {
    if (possessionIndex == 1)
    {
      pcA3->word48 |=0x8000;
      if (d.AttackingCharacterOrdinal == chIdx+1)
      {
        TAG01b1c0();
      };
      if (   (otD5 >= obj_OpenScroll)
          && (otD5 <= obj_Scroll) )
      {
        dbA2->CastToDB7()->open(false);
      };
    };
    if (   (otD5 >= obj_Torch_a)
        && (otD5 <= obj_Torch_d) )
    {
      dbA2->CastToDB5()->litTorch(0);
      //dbA2->word(2) = dbA2->word(2) & 0x7fff;
      SelectPaletteForLightLevel();
      DrawEightHands();
    };
    if ( (LOCAL_2) && (possessionIndex==1) )
    {
      if (otD5 == obj_Chest)
      {
        RepackChest();
      if (TimerTraceActive)
      {
        fprintf(GETFILE(TraceFile),"%06x RemovePossession calling Repack Chest\n",d.Time);
      };
        pcA3->word48 |= 0x800;
      }
      else
      {
        if (   (otD5 >= obj_OpenScroll)
            && (otD5 <= obj_Scroll) ) pcA3->word48 |= 0x800;
      };
    };
  };
  D0W = sw(GetObjectWeight(objD6));
  DEBUGLOAD(pcA3, D0W, -1, objD6);
  pcA3->load = sw(pcA3->load - D0W);
  ASSERT(pcA3->load < MAXLOAD);
  pcA3->word48 |= 0x200;
  return (objD6);
}

//*********************************************************
//
//*********************************************************
//   TAG015c4c
void PlaceObjectOnCharacter(i32 chIdx,RN object,i32 place)
{//(void)
  //dReg D4;
  OBJECTTYPE otD4;
  CHARDESC *pcA3;
  DBCOMMON *dbA2;
  bool bool_2;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  if (object == RNnul) return;
  pcA3 = &d.CH16482[chIdx];
  if (place >= 30) // In a chest?
  {
    d.rnChestContents[place-30] = object;
    if (TimerTraceActive)
    {
      fprintf(GETFILE(TraceFile),"Place object %04x in Chest location %d\n",
              object.ConvertToInteger(),place-30);
    };
  }
  else
  {
    if (TimerTraceActive)
    {
      fprintf(GETFILE(TraceFile),"Place object %04x on %s at location %d\n",
                       object.ConvertToInteger(), pcA3->name, place);
    };
    pcA3->possessions[place] = object;
  };
  DEBUGLOAD(pcA3, GetObjectWeight(object), +1, object);
  pcA3->load = sw(pcA3->load + GetObjectWeight(object));
  ASSERT(pcA3->load < MAXLOAD);
  pcA3->word48 |= 0x200;
  otD4 = GetModifiedObjectType(object);
  bool_2 = chIdx+1 == d.SelectedCharacterOrdinal;
  TAG0157e8(pcA3, place, otD4, 1, object);
  dbA2 = GetCommonAddress(object);
  if (place < 2)
  { // In a hand
    if (place == 1)
    { // In fighting hand
      pcA3->word48 |= 0x8000;
      if (d.AttackingCharacterOrdinal == chIdx+1)
      {
        TAG01b1c0();
      };
      if (   (otD4 >= obj_OpenScroll)
          && (otD4 <= obj_Scroll) )
      {
        dbA2->CastToDB7()->open(true);
        DrawEightHands();
      };
    };
    if (otD4 == obj_Torch_a)
    {
      dbA2->CastToDB5()->litTorch(1);
      //SETBITS15_15(dbA2->word(2), 1);
      SelectPaletteForLightLevel();
      DrawEightHands();
    }
    else
    {
      if ( bool_2 && (place==1) )
      {
        if (    (otD4 == obj_Chest)
             || ( (otD4 >= obj_OpenScroll) && (otD4 <= obj_Scroll) ) )
        {
          pcA3->word48 |= 0x800;
        };
      };
    };
  }
  else
  { //Not in a hand.
    if (place ==10)
    { // Necklace
      if (   (otD4 >= obj_Illumulet_a)
          && (otD4 <= obj_Illumulet_b) )
      {
        dbA2->CastToDB10()->value(1);
        //SETBITS14_15(dbA2->word(2), 1);
        d.Brightness = sw(d.Brightness + d.Word1074[2]);
        SelectPaletteForLightLevel();
        otD4 = (OBJECTTYPE)(otD4 + 1);
      }
      else
      {
        if (   (otD4 >= obj_JewelSymal_a)
            && (otD4 <= obj_JewelSymal_b) )
        {
          dbA2->CastToDB10()->value(1);
          //SETBITS14_15(dbA2->word(2), 1);
          otD4 = (OBJECTTYPE)(otD4 + 1);
        };
      };
    };
  };
  DisplayBackpackItem(chIdx, place);
  if (bool_2)
  {
    pcA3->word48 |= 0x4000;
  };
}

//*********************************************************
//
//*********************************************************
i16 TAG016426(CHARDESC *pChar,i16 attrNum,i16 P3)
{
  dReg D0, D7;
  i16 w_10;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  w_10 = pChar->Attributes[attrNum].Current();
  //D7W = sw(170 - w_10/256); //They stored a word and fetch a byte!
  D7W = sw(170 - w_10); //They stored a word and fetch a byte!
  if (D7W < 16)
  {
    D0W = sw(P3 >> 3);
  }
  else
  {
    D0W = ScaledMultiply(P3, 7, D7W);//P3*D7/128
  };
  return D0W;
}

//*********************************************************
//
//*********************************************************
i16 TAG016476(CHARDESC *pChar, i32 P2, char *traceID)
{
  dReg D0, D7;
  i32 currentLuck;
  ATTRIBUTE *attrA3;
  if (traceID!=NULL)
  {
    fprintf(GETFILE(TraceFile),"%sEnter TAG016476 (%s , (P2=%d))\n",
                      traceID, pChar->name, P2);
  };
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  D7W = sw(P2);
  if (   STRandomBool()
      && (STRandom(100) > D7W)  )
  {
    if (traceID!=NULL)
    {
      fprintf(GETFILE(TraceFile),"%sReturning 1\n",traceID);
    };
    return 1;
  };
  attrA3 = pChar->Attributes;
  currentLuck = attrA3[Luck].Current();
  if (currentLuck == 0) D0W = 0;
  else  D0W = (i16)STRandom(attrA3[Luck].Current());
  //SET(D0W, D0W > D7W);
  if (D0W > D7W) D7W = 1; else D7W = 0;
  //D7W = sw(D0W & 1);
  D0W = ApplyLimits(attrA3[Luck].Minimum(),
                     attrA3[Luck].Current() + ((D7W==0) ? 2 : -2),
                     attrA3[Luck].Maximum());
  attrA3[Luck].Current(D0W);
  if (traceID!=NULL)
  {
    fprintf(GETFILE(TraceFile),"%sReturning D7W=%d\n",traceID,D7W);
  };
  return D7W;
}

//*********************************************************
//
//*********************************************************
//  TAG016610
i32 Quickness(CHARDESC *pChar, char *traceID)
{ // Essentially:  0.5 * Dexterity*(1-load/Maxload/2)
  // With limits of about 5 and 95
  dReg D0, D1;
  i32 quickness;
  i32 loLimit, hiLimit, ranResult;
  if (traceID!=NULL)
  {
    fprintf(GETFILE(TraceFile),"%sEntering function to determine character's Quickness\n",traceID);
  };
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  quickness = pChar->Attributes[Dexterity].Current()
              +(ranResult=STRandom(8));
  if (traceID!=NULL)
  {
    fprintf(GETFILE(TraceFile),"%squickness = (Dexterity=%d) + (random(8)=%d) --> %d\n",
             traceID,pChar->Attributes[Dexterity].Current(),ranResult,quickness);
  };
  D0L = (quickness/2) * pChar->load;
  if (traceID!=NULL)
  {
    fprintf(GETFILE(TraceFile),"%sAbout to compute Maximum load\n",traceID);
  };
  D1L = MaxLoad(pChar);
  quickness = quickness - (D0L / D1L);
  if (traceID!=NULL)
  {
    fprintf(GETFILE(TraceFile),"%sLoading effect=(quickness/2)*(load=%d)/(maxload=%d)-->%d\n",
             traceID, pChar->load, D1L, D0L/D1L);
    fprintf(GETFILE(TraceFile),"%sSubtract loading effect from quickness -->%d\n",
                       traceID, quickness);
  };
  if (d.PartySleeping != 0)
  {
    quickness /= 2;
    if (traceID!=NULL)
    {
      fprintf(GETFILE(TraceFile),"%sSleeping.  Divide quickness by 2 --> %d\n",
                         traceID, quickness);
    };
  };
  quickness /= 2;
  loLimit = STRandom(8)+1;
  hiLimit = 100-STRandom(8);
  quickness = ApplyLimits(loLimit, quickness, hiLimit);
  if (traceID!=NULL)
  {
    fprintf(GETFILE(TraceFile),"%sLow Limit = random(8) + 1 --> %d\n",traceID,loLimit);
    fprintf(GETFILE(TraceFile),"%sHigh Limit = 100-random(8) --> %d\n",traceID,hiLimit);
    fprintf(GETFILE(TraceFile),"%sFinal quickness = %d\n",traceID,quickness);
  };
  return quickness;
}

//*********************************************************
//
//*********************************************************
//  TAG0166b2
i32 DetermineThrowingDistance(i32 chIdx,i32 hand)
{
  dReg D0, D1, D3, D5, D6, D7;
  RN objD4;
  CHARDESC   *pcA3;
  WEAPONDESC *weaponDescA2;
  i16 w_12;
  i16 w_2;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  pcA3 = &d.CH16482[chIdx];
  D3W = pcA3->Attributes[Strength].Current();
  D7W = sw((STRandom()&15) + D3W);
  objD4 = pcA3->possessions[hand];
  D6L = GetObjectWeight(objD4);
  D5W = sw(MaxLoad(pcA3) / 16);
  if (D6W <= D5W)
  {
    D7W = sw(D7W + D6W - 12);
  }
  else
  {
    w_2 = sw((D5W - 12)/2 + D5W);
    w_12 = w_2;
    if (D6W <= w_12)
    {
      D7W = sw(D7W + (D6W - D5W)/2);
    }
    else
    {
      D7W = sw(D7W - 2 * (D6W-w_2));
    };
  };
  if (   (objD4 != RNnul)
       &&(objD4.dbType() == dbWEAPON))
  {
    weaponDescA2 = TAG0099d2(objD4);
    D7W = sw(D7W + weaponDescA2->uByte2);
    D6W = 0;
    D5W = weaponDescA2->uByte1;
    if ( (D5W == 0) || (D5W == 2) )
    {
      D6W = (i16)DetermineMastery(chIdx, 4);
    };
    if ( (D5W != 0) && (D5W < 16) )
    {
      D6W = sw(D6W + DetermineMastery(chIdx, 10));
    };
    if ( (D5W >= 16) && (D5W < 112) )
    {
      D6W = sw(D6W + DetermineMastery(chIdx, 11));
    };
    D7W = sw(D7W + 2 * D6W);
  };
  D7W = StaminaAdjustedAttribute(pcA3, D7W);
  D0W = pcA3->ouches;
  if (hand == 0) D1W = 1;
  else D1W = 2;
//
  if (D1W & D0W)
  {
    D7W /= 2;
  };
  return ApplyLimits(0, D7W/2, 100);
}

//*********************************************************
//
//*********************************************************
i16 TAG01680a(i32 chIdx,i32 possessionIndex)
{
  dReg D0, D1, D5, D6, D7;
  CLOTHINGDESC *clA2;
  RN objD4;
  CHARDESC *pcA3;
  DB6      *DB6A2;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  pcA3 = &d.CH16482[chIdx];
  D5W = (UI16)(possessionIndex & 0x8000);
  possessionIndex &= 0x7fff;
  D6W = 0;
  for (D7W=0; D7W<2; D7W++)
  {
    objD4 = pcA3->possessions[D7W];
    if (  (objD4 == RNnul)
        ||(objD4.dbType() != dbCLOTHING)) continue;
    DB6A2 = GetRecordAddressDB6(objD4);
    //D0W = DB6A2->word2;
    //D0W = D0W & 0x7f;
    D0W = sw(DB6A2->clothingType());
    ASSERT(D0W <58);
    clA2 = &d.ClothingDesc[D0W];
    D0W = clA2->uByte2();
    if ((D0W & 0x80) == 0) continue;
    D0L = DetermineThrowingDistance(chIdx, D7W);
    D1L = TAG009470(clA2, D5W!=0);
    D0L += D1L;
    D1W = (UI8)(d.Byte1412[possessionIndex]);
    D0L = D0W * D1W;
    if (D7W == possessionIndex)
    {
      D1W = 4;
    }
    else
    {
      D1W = 5;
    };
    D6W = sw(D6W + (D0W >> D1W));
//
  };
  D0L = STRandom();
  D1W = (UI8)(pcA3->Attributes[Vitality].Current());
  D1W = sw(D1W/8 + 1 );
  D0L &= 0xffff;
  D7W = sw(D0L % D1W); // zero to 8*vitality
  //D7W = D0W;
  if (D5W != 0)
  {
    D7W /= 2;
  };
  D7W = sw(  D7W
           + pcA3->word64
           + pcA3->shieldStrength
           + d.Word13278
           + D6W);
  if (possessionIndex > 1)
  {
    objD4 = pcA3->possessions[possessionIndex];
    if (    (objD4 != RNnul)
         && (objD4.dbType() == dbCLOTHING))
    {
      DB6A2 = GetRecordAddressDB6(objD4);
      D7W = sw(D7W + TAG009470(&d.ClothingDesc[DB6A2->clothingType()], D5W!=0));
    };
  };
  if (pcA3->ouches & (1<<possessionIndex))
  {
    D7W = sw(D7W - (STRandom0_3() + 8));
  };
  if (d.PartySleeping)
  {
    D7W >>= 1;
  };
  D0W = ApplyLimits(0, D7W >>1, 100);
  return D0W;
}

//*********************************************************
//
//*********************************************************
//   TAG016be8
void DropAllPossessions(i16 chIdx)
{//(void)
  dReg D4, D6;
  RN objD5;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  D6W = d.CH16482[chIdx].position;
  for (D4W=0; D4W<30; D4W++)
  {
    objD5 = RemovePossession(chIdx, d.DropOrder[D4W]);
    if (objD5 == RNnul) continue;
    objD5.pos(D6W);//4Nov2002 PRS
    MoveObject(
               objD5,
               -1,  // oldX
               0,   // oldY
               d.partyX,
               d.partyY);
//
  };
}
//*********************************************************
//
//*********************************************************
//   TAG016c5a
void KillCharacter(i16 chIdx)
{//(void)
  dReg D5, D6;
  RN objD4, objD7;
  DB10    *DB10A2;
  CHARDESC *pcA3;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  pcA3 = &d.CH16482[chIdx];
  pcA3->HP(0);
  pcA3->word48 |= 0x1000;
  if (d.SelectedCharacterOrdinal == chIdx+1)
  {
    if (d.Word11756)
    {
      d.Word11756 = 0;
      d.Word23140 = 0;
      if (d.EmptyHanded == 0)// cursor hand
      {
        ASSERT(RememberToPutObjectInHand == -1);
        DrawNameOfHeldObject(d.objectInHand);
      };
      d.Word23118 = 1;
      STShowCursor();
    }
    else
    {
      if (d.Word11760)
      {
        d.Word11760 = 0;
        d.Word23140 = 0;
        d.Word23118 = 1;
        STShowCursor();
      };
    };
    TAG0192f4(4);
  };
  DropAllPossessions(chIdx);
  objD4 = FindEmptyDB10Entry(true);
  if (objD4 != RNnul)
  {
    DB10A2 = GetRecordAddressDB10(objD4);
    DB10A2->miscType(misc_BonesOfHero);
    //DB10A2->word(2) = (DB10A2->word(2) & 0xff80) | 5;
    DB10A2->important(true);
    //DB10A2->word(2) = (DB10A2->word(2) & 0xff7f) | (1 << 7);
    DB10A2->value(chIdx);
    //DB10A2->word(2) = (DB10A2->word(2) & 0x3fff) | ((chIdx & 3) << 14);
    D6W = (UI8)(pcA3->position);
    objD4.pos(D6W);//4Nov2002 PRS
    MoveObject(
               objD4,
               -1, //oldX
               0,  //oldY
               d.partyX,
               d.partyY);
  };
  pcA3->byte33 = 0;
  pcA3->incantation[0] = 0;
  pcA3->facing = (ui8)d.partyFacing;
  pcA3->uByte41 = 0;
  D6W = sw(((D6W + 4) - d.partyFacing) & 3);
  if (D6W + 1 == d.Word23144)
  {
    d.NewCursorShape = 1;
    d.Word23244 = 0;
    d.Word23130 = 1;
  };
  if (pcA3->uByte42)
  {
    TAG017344(chIdx);
  };
  d.UseByteCoordinates = 0;
  FillRectangle(d.LogicalScreenBase,
                &d.wRectPos1454[D6W],
                0,
                160);
  DrawCharacterState(chIdx);
  //D5W = 0;
  //pcA3 = &d.CH16482[0];
  for (D5W = 0, pcA3 = &d.CH16482[0];
      D5W<d.NumCharacter;
      D5W++, pcA3++)
  { // Find a living party member.
    if (   (d.PotentialCharacterOrdinal != D5W+1) 
        && (pcA3->HP() != 0) )break;
  };
  if (D5W == d.NumCharacter)
  {
    d.GameIsLost = 1;
  }
  else
  {
    if (chIdx == d.HandChar) // owner of cursor
    {
      SetHandOwner(D5W);
    };
    if (chIdx == d.MagicCaster)
    {
      SelectMagicCaster(D5W);
    }
    else
    {
      TAG01b50e(d.MagicCaster);
    };
  };
}

//*********************************************************
//
//*********************************************************
//  TAG017068
i32 DamageCharacter(i32 chIdx,i32 damage,i16 mask,i16 P4)
{
  dReg D0, D1, D3, D4, D5, D6, D7;
  CHARDESC *pcA3;
  i16 LOCAL_30;
  i16 LOCAL_20;
  i16 LOCAL_10;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

  D7W = sw(damage);
//
  if (chIdx==-1) return 0;
  if (chIdx+1 == d.PotentialCharacterOrdinal) return chIdx+1;
  if (d.Word11694 != 0) return d.Word11694;
  if (D7W <= 0) return 0;

  pcA3 = &d.CH16482[chIdx];
  if (pcA3->HP() == 0) return 0;
  if (P4 != 0)
  {
    for (D4W=D5W=D6W=0; D6W<=5; D6W++)
    {
      if ((mask & (1<<D6W)) == 0) continue;
      D4W++;
      D0W = D6W;
      if (P4 == 4)
      {
        D1UW = 0x8000;
      }
      else
      {
        D1W = 0;
      };
      D5W = sw(D5W + TAG01680a(chIdx, D0W | D1W));

//
    };
    if (D4W)
    {
      D5W = sw((D5W&0xffff)/(D4W&0xffff)); // Average
    };
    if (P4 == 6)
    {
      D0W = 115;
      D3W = (UI8)(pcA3->Attributes[Wisdom].Current());
      D6W = sw(D0W - D3W);
      if (D6W <= 0)
      {
        D7W = 0;
      }
      else
      {
        D7W = ScaledMultiply(D7W, 6, D6W);//D6*D7/64
      };
    }
    else
    {
      if (P4 == 5)
      {
        D7W = TAG016426(pcA3, 5, D7W);
        D7W = sw(D7W - d.Word13274);
      }
      else
      {
        if (P4 == 1)
        {
          D7W = TAG016426(pcA3, 6, D7W);
          D7W = sw(D7W - d.Word13276);
        }
        else
        {
          if (P4 == 2)
          {
            D5W >>= 1;
          }
          else
          {
          };
        };
        if (D7W <= 0) return 0;

        D0W = sw(130 - D5W);
        D7W = ScaledMultiply(D7W, 6,D0W); //D6*D7/64
      };
    };
    if (D7W <= 0) return 0;
    D0W = sw(STRandom(128) + 10);
    D6W = TAG016426(pcA3, 4, D0W);
    LOCAL_10 = D6W;
    if (D7W > LOCAL_10)
    {
      do
      {
        LOCAL_20 = sw(STRandom(8));
        D1W = sw((1 << LOCAL_20) & mask);
        d.PendingOuches[chIdx] |= D1W;
        D6W <<= 1;
        LOCAL_30 = D6W;
        if (D7W <= LOCAL_30) break;
      } while (D6W != 0);
    };
    if (d.PartySleeping)
    {
      WakeUp();
    };
  };
  if (D7W <= 0)
  {
    D7W = 0;
  };
  d.PendingDamage[chIdx] = sw(d.PendingDamage[chIdx] + D7W);
  return D7W;
}

//*********************************************************
//
//*********************************************************
void TAG017344(i32 chIdx)
{
  dReg D7;
  TIMER *tA3;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  if (chIdx == -1) return;
  tA3 = allocateTimers.Timers();
  for (D7W=0; D7W<d.MaxTimer(); D7W++, tA3++)
  {
    if (tA3->Function() == TT_75)
    {
      if (tA3->timerUByte5 == chIdx)
      {
        DeleteTimer(D7W);
      };
    };
//
//
  };
  d.CH16482[chIdx].uByte42 = 0;
}

//*********************************************************
//
//*********************************************************
//   TAG017ce4
void ShowChestContents(RN objChest, DB9 *pChest, i16 P3)
{
  dReg D7;
  RN chestContents;
  DBCOMMON *pChestContentsRecord;
  i32 i;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  if (d.objOpenChest == objChest) return;
  ASSERT(d.objOpenChest == RNnul);
  d.objOpenChest = objChest;
  if (P3 == 0)
  {
    DrawItem(9, obj_OpenChest);
  };
  BLT2Viewport(GetBasicGraphicAddress(25),
               &d.wRectPos926,
               72,
               8);
  D7W = 0;
  for (chestContents=pChest->contents();
       chestContents!=RNeof;
       chestContents=GetDBRecordLink(chestContents)  )
  {
    DrawItem(D7W+38,
             GetModifiedObjectType(chestContents));
    d.rnChestContents[D7W++] = chestContents;
//
//
  };
  while (D7W < 8)
  {
    DrawItem(D7W+38,obj_NotAnObject);
    d.rnChestContents[D7W++] = RNnul;
//
  };
  // The links in the data records are still intact while the items are
  // on display in d.rnChestContents.  If we then remove one of the items
  // from the chest and put it in our non-weapon hand, the link still exists.
  // If a Giggler with no other possessions then steals this item the link
  // still exists and it appears that the Giggler has stolen the entire
  // list of items.  Many things can go wrong.  There will exist two copies
  // of the other items on the list.  The immediate problem that I fixed
  // here occurred when I put two copies of the same item on the same place
  // on the floor.  They then formed a loop and the program hung when trying
  // to display the items.  But other terrible things could obviously
  // go wrong.
  //
  // The same thing happened in the emulated Atari code.
  //
  // So I am going to clear the links here and now.
  //
  for (i=0; i<8; i++)
  {
    if (d.rnChestContents[i] != RNnul)
    {
      pChestContentsRecord = GetCommonAddress(d.rnChestContents[i]);
      pChestContentsRecord->link(RNeof);
    };
  };
}

//*********************************************************
//
//*********************************************************
//   TAG017da4
void RepackChest(void) //Put displayed items back into chest.
{ //We got here when we removed a chest from hand in stats screen.
  dReg D4, D5;
  RN   objD6, objD7;
  DBCOMMON *dbA2;
  DB9     *DB9A3;
  D4W = 1;
  if (d.objOpenChest == RNnul)
  {
    if (TimerTraceActive)
    {
      fprintf(GETFILE(TraceFile),"%06x Skipping Repack Chest because d.objOpenChest==RNnul\n",
                     d.Time);
    };
    return;
  };
  if (TimerTraceActive)
  {
    fprintf(GETFILE(TraceFile),"%06x Repacking Chest Contents\n",d.Time);
  };
  DB9A3 = GetRecordAddressDB9(d.objOpenChest);
  d.objOpenChest = RNnul;
  DB9A3->contents(RNeof);
  for (D5W=0; D5W<8; D5W++)
  {
    objD7 = d.rnChestContents[D5W];
    if (objD7 == RNnul) continue;
    if (D4W != 0)
    {
      D4W = 0;
      dbA2 = GetCommonAddress(objD7);
      dbA2->link(RNeof);
      objD6 = objD7;
      DB9A3->contents(objD7);
      if (TimerTraceActive)
      {
        fprintf(GETFILE(TraceFile),"Added %04x to %02x(%02x,%02x)%01x\n",
                  objD7.ConvertToInteger(), d.LoadedLevel, -1, 0, 0);
      };
      continue;
    };
    AddObjectToRoom(objD7, objD6, -1, 0);
    objD6 = objD7;
//
//
  };
}

//*********************************************************
//
//*********************************************************
void TAG017e2a(pnt text)
{
  dReg D0, D7;
  aReg A2, A3;
  i8  b_128[128];
  A2=NULL;
  //D4W = D5W = D6W = 0;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  //D0W = text[0];
  if (text[0] == 12)
  {
    text++;
    d.Word16610 = 108;
    d.Word16612 = 59;
  };
  if (text[0] == 0) return;
  StrCpy(b_128, text);
  A3 = b_128;
  for (D7W = 0; *A3 != 0; )
  {
    D0W = StrLen(A3);
    if (D0W > 18)
    {
      A2 = A3 + 17;
      while (*A2 != ' ') A2--;


      *A2 = 0;
      D7W = 1;
    };
    TextToViewport(d.Word16610,
                   d.Word16612,
                   13,
                   A3);
    d.Word16612 += 7;
    if (D7W != 0)
    {
      D7W = 0;
      A3 = A2 + 1;
    }
    else
    {
      *A3 = 0;
    };
  };
}

//*********************************************************
//
//*********************************************************
void TAG017ece(i16 P1,i16 bitmask,pnt *P3,pnt P4,pnt P5,pnt P6)
{
  dReg D0, D4, D5, D6, D7;
  aReg A2;
  i16 w_2;
  pnt *ppA3;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  D7W = P1;
  D6W = bitmask;
  ppA3 = P3;
  A2   = P4;
  w_2 = 0;
  for (D5W=0, D4W=1; D5W < 16; D5W++, D4W<<=1)
  {
    D0W = sw(D4W & D7W & D6W);
    if (D0W != 0) w_2++;

  };
  if (w_2 == 0)
  {
    *A2 = 0;
    return;
  };
  StrCpy(A2, P5);
  for (D5W=0, D4W=1; D5W<16; D5W++, D4W<<=1)
  {
    D0W = sw(D4W & D7W & D6W);
    if (D0W != 0)
    {
      StrCat(A2, ppA3[D5W]);
      if (w_2-- > 2)
      {
        StrCat(A2, ", ");
      }
      else
      {
        if (w_2 == 1)
        StrCat(A2, " AND ");
      };
    };
//
  };
  StrCat(A2, P6);
}

//*********************************************************
//
//*********************************************************
void TAG018238(i16 P1)
{
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  BLT2Viewport(GetBasicGraphicAddress(P1==0 ? 18 : 19),
                                 &d.wRectPos934,
                                 8,
                                 8);
}

//*********************************************************
//
//*********************************************************
//   TAG01826c
void DisplayScrollText_OneLine(i16 pixelY, pnt text)
{
  aReg A2, A3;
  i32 length;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  A3 = text;
  for (A2=A3; *A2!=0; A2++)
  {
    if ( (*A2 >= 'A') && (*A2 <= 'Z') ) *A2 -= 64;

    else
      if (*A2 >= 0x7b) *A2 -= 0x60;
//
//
  };
  length = StrLen(A3);
  if (length > MAX_SCROLL_LINE_LENGTH) 
                  length = MAX_SCROLL_LINE_LENGTH;
  TextOut_OneLine(d.pViewportBMP,
                  112,
                  162 - 6*length/2,
                  pixelY,
                  0,
                  15,
                  A3,
                  length);
}

//*********************************************************
//
//*********************************************************
//   TAG0182f0
void DisplayScroll(DB7 *pDB7)
{
  dReg D1, D7;
  aReg A0, A2, A3;
  i8 b_260[260];
  i32 i;
  i32 numLinesInScroll = 0;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  // Word2 is textID
  DecodeText(b_260,
             GetRecordAddressDB2(pDB7->text()),
             (ui16)0x8002,
             260);
  //Make sure there are TWO zeroes at the end!
  //This fixes the problem when there is only
  //one line of text.
  for (i=0; b_260[i]!=0; i++);
  b_260[i+1] = 0;
  for (A2 = b_260; (*A2 != 0) && (*A2 != 10); A2++) {};
//

  *A2 = 0;
  BLT2Viewport(GetBasicGraphicAddress(23),
               &d.wRectPos926,
               72,
               8);
  numLinesInScroll = 1;
  A2++;
  for (A3=A2; *A3!=0; A3++) if (*A3 == 10) numLinesInScroll++;
//
//
//

  A0 = A3 - 1;
  if (*A0 != 10)
  {
    numLinesInScroll++;
  }
  else
  {
    A0 = A3 - 2;
    if (*A0 == 10) numLinesInScroll--;
  };
  if (numLinesInScroll > MAX_LINES_IN_SCROLL)
        numLinesInScroll = MAX_LINES_IN_SCROLL;
  D1L = 7 * numLinesInScroll / 2;
  D7W = sw(92 - D1W);
  DisplayScrollText_OneLine(D7W, b_260);
  numLinesInScroll--;
  if (numLinesInScroll == 0) return;
  for (A3=A2; *A3!=0; A3=A2)
  {
    for (D7W+=7; (*A2!=0)&&(*A2!=10); A2++)
    {
//
    };
    if (*A2 == 0)
    {
      *(A2+1) = 0;
    };
    *(A2++) = 0;
    DisplayScrollText_OneLine(D7W, A3);
    numLinesInScroll--;
    if (numLinesInScroll == 0) return;
//
//
  };
}

//*********************************************************
//
//*********************************************************
void TAG0183ea(RN object,i16 P2)
{ // Describe object???
  // We get here when we place an object on the 'eye'.
  dReg D0, D1, D4, D5, D7;
  aReg A0, A3;
  OBJECTTYPE otD6;
  CHARDESC *pcA0;
  DB5 *DB5A0;
  DB6 *DB6A0;
  DB8 *DB8A0;
  DB10 *DB10A0;
  i8  b_114[42];
  pnt pnt_72[6];
  //pnt pnt_68;
  //pnt pnt_64;
  //pnt pnt_60;
  //pnt pnt_56;
  //pnt pnt_52;
  DBCOMMON *dbA2;
  DBTYPE dbType;
  D4W = D5W = 0x0ff0;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  pnt_72[1] = ")";
  pnt_72[0] = "(";
//
  if ( (d.Word11756 != 0) || (d.Word11760 != 0) ) //If food/water or skill levels showing
  {
    if (TimerTraceActive)
    {
      fprintf(GETFILE(TraceFile),"%06x TAG0183ea calling RepackChest. d.Word11756=%x. d.Word11760=%x\n",
                   d.Time, d.Word11756, d.Word11760);
    };
    RepackChest();
  };
  dbA2 = GetCommonAddress(object);
  TAG017e2a("\014");
  dbType = object.dbType();
  if (dbType == dbSCROLL)
  {
    DisplayScroll(dbA2->CastToDB7());
  }
  else
  {
    if (dbType == dbCHEST)
    {
      ShowChestContents(object, dbA2->CastToDB9(), P2);
    }
    else
    {
      otD6 = GetModifiedObjectType(object);
      BLT2Viewport(GetBasicGraphicAddress(20),
                   &d.wRectPos926,
                   72,
                   8);
      BLT2Viewport(GetBasicGraphicAddress(29),
                   &d.wRectPos942,
                   16,
                   12);
      if (otD6 == obj_Bones_a)
      {
        pcA0 = &d.CH16482[dbA2->CastToDB10()->value()];
        StrCpy(b_114, pcA0->name);
        StrCat(b_114, " ");
        StrCat(b_114, d.ObjectNames[otD6]);
        A3 = b_114;
      }
      else
      {
//
//
        if (   (dbType == dbPOTION)
            && (otD6 != obj_WaterFlask)
            && (otD6 != obj_EmptyFlask)
            && (DetermineMastery(d.SelectedCharacterOrdinal-1, 2) > 1) )
        {
          b_114[0] = sb(95 + dbA2->CastToDB8()->strength()/40);
          b_114[1] = ' ';
          b_114[2] = 0;
          StrCat(b_114, d.ObjectNames[otD6]);
          A3 = b_114;
        }
        else
        {
          A3 = d.ObjectNames[otD6];
        };
      };
      TextToViewport(134, 68, 13, A3);
      DrawSmallIcon(otD6, 111, 59);
      pnt_72[2] = "CONSUMABLE";
      pnt_72[3] = "POISONED";
      pnt_72[4] = "BROKEN";
      pnt_72[5] = "CURSED";
      d.Word16612 = 87;
      switch (dbType)
      {
//
      case dbWEAPON:
          D5W = 14;
          DB5A0 = dbA2->CastToDB5();
          D4W = sw(DB5A0->cursed());
          D4W <<= 3; //Cursed
          D1W = sw(DB5A0->poisoned());
          D4W |= D1W << 1;//Poisoned
          D1W = sw(DB5A0->broken());
          D4W |= D1W << 2;//Broken
          if (   (otD6 >= obj_Torch_a)
              && (otD6 <= obj_Torch_d) )
          {
            D0W = sw(DB5A0->charges());
            if (D0W == 0)
            {
              TAG017e2a("(BURNT OUT)");
            };
          };
          break;

      case dbCLOTHING:
          D5W = 12;
          DB6A0 = dbA2->CastToDB6();
          D4W = sw(DB6A0->cursed());
          D4W <<= 3; //Cursed
          D1W = sw(DB6A0->broken());
          D4W |= D1W << 2;//broken
          break;
      case dbPOTION:
          D5W = 1;
          DB8A0 = dbA2->CastToDB8();
          D1W = sw(DB8A0->potionType());
          D4W = sw(D1W + 2);//Compute object index
          D4W = d.ObjDesc[D4W].word4;
          break;
      case dbMISC: // Bones, for example.
          if (   (otD6 >= obj_Waterskin)
              && (otD6 <= obj_Water) )
          {
            D5W = 0;
            DB10A0 = dbA2->CastToDB10();
            switch (BITS14_15(DB10A0->word2))
            {
            case 0:
              A3 = "(EMPTY)";
              break;
            case 1:
              A3 = "(ALMOST EMPTY)";
              break;
            case 2:
              A3 = "(ALMOST FULL)";
              break;
            case 3:
              A3 = "(FULL)";
              break;
            }; //switch ()
            TAG017e2a(A3);
          }
          else
          {
            if (   (otD6 >= obj_Compass_N)
                && (otD6 <= obj_Compass_W) )
            {
              D5W = 0;
              StrCpy(b_114, "PARTY FACING");
              StrCat(b_114, d.DirectionNames[otD6-obj_Compass_N]);
              TAG017e2a(b_114);
            }
            else
            {
              D5W = 1;
              // compute object index
              D4W = sw(dbA2->CastToDB10()->miscType() + 127);
              D4W = d.ObjDesc[D4W].word4;
            };
          };
      }; //switch (DB type)
      if (D5W != 0)
      {
        TAG017ece(D5W,
                  D4W,
                  &pnt_72[2],
                  b_114,
                  pnt_72[0],
                  pnt_72[1]);
        TAG017e2a(b_114);
      };
      StrCpy(b_114, "WEIGHS ");
      D7W = sw(GetObjectWeight(object));
      A0 = TAG014af6((UI16)(D7W)/10, 0, 3);
      StrCat(b_114, A0);
      StrCat(b_114, ".");
      D7W = sw((D7W&0xffff)%10);
      A0 = TAG014af6(D7W, 0, 1);
      StrCat(b_114, A0);
      StrCat(b_114, " KG.");
      TAG017e2a(b_114);
    };
  };
  TAG018238(P2);
}

//*********************************************************
//
//*********************************************************
void TAG0189a8(void)
{
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  d.WpnChestOrScroll = 5;
  BLT2Viewport(GetBasicGraphicAddress(40), //Resurrect/Reincarnate/cancel
            &d.wRectPos926,
            72,
            6);
}

//*********************************************************
//
//*********************************************************
void TAG0189d4(void)
{
  dReg D0;
  RN objD7;
  DBCOMMON *dbA3;
  CHARDESC *pChar;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  if (d.PotentialCharacterOrdinal)
  {
    TAG0189a8();//Portrait/bars/Resurrect menu
  }
  else
  {
    //D7L = d.Word16614 * 800;
    pChar = &d.CH16482[d.SelectedCharacterOrdinal-1];
    objD7 = pChar->possessions[1]; // item in Weapon hand
    dbA3 = GetCommonAddress(objD7);
    d.WpnChestOrScroll = 0;
    D0W = -1;
    if (objD7 != RNnul) D0W = sw(objD7.dbType());
    if (D0W == dbCHEST)
    { // Chest.
      d.WpnChestOrScroll = 4;
    }
    else
    {
      if (D0W == dbSCROLL)  //scroll
      {
        d.WpnChestOrScroll = 2; // Displaying scroll in weapon hand
      }
      else objD7 = RNnul;
      //{
      //}
      //else
      //{
      //};


    };
    if (objD7 == RNnul)
    {
      DisplayFoodWater();
    }
    else
    {
      TAG0183ea(objD7 ,0);
    };
  };
}

//*********************************************************
//
//*********************************************************
//   TAG018a58
void AdjustCurrentAttribute(CHARDESC *pChar, i32 attr, i32 adj)
{
  dReg D0, D3, D5, D6, D7;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  D7W = sw(attr);
  D6W = sw(adj);
  if (D6W >= 0)
  {
    D5W = pChar->Attributes[D7W].Current();//Wisdom, vitality, etc.
    if (D5W >120)
    {
      D6W /= 2;
      if (D5W > 150)      {
        D6W /= 2;
      };
      D6W++;
    };
    D5W = sw(Smaller(170-D5W, D6W));
    // Don't let current go above 170.
  }
  else
  {
    D0W = pChar->Attributes[D7W].Minimum();
    D3W = pChar->Attributes[D7W].Current();
    D5W = sw(Larger(D0W-D3W, D6W));//Both are negative or zero
    // Don't let current fall below Minimum
    // D5W is maximum we can subtract.
  };
  pChar->Attributes[D7W].IncrCurrent(D5W);
}

//*********************************************************
//
//*********************************************************
//   TAG018afc
RESTARTABLE _FeedCharacter(void)
{ //(void)
  //We got here when I fed a character some bones. (But
  // they turned out to be not consumable.)
  static dReg D0, D1, D4;
  static i32 chIdx;
  static OBJECTTYPE otD6;
  static RN  objD7;
  static CHARDESC *pcA0, *pcA2;
  static DBCOMMON *dbA3;
  static i16  w_40;
  static i16  w_30;
  static i16  w_20;
  static RN   obj_w_20;
  static DBTYPE  dbType_18;
  static i32  i_18;
  static i16  w_16;
  static i16  w_14;
  static i16  w_12;
  static TIMER timer;
  static i32 i;
  static DBCOMMON *itemToDeleteFromDatabase;
  RESTARTMAP
    RESTART(1)
    RESTART(2)
  END_RESTARTMAP
  itemToDeleteFromDatabase = NULL;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  if (d.EmptyHanded)
  {
    if (d.WpnChestOrScroll == 0)
    {
      if (itemToDeleteFromDatabase != NULL) DeleteDBEntry(itemToDeleteFromDatabase);
      RETURN;
    };
    d.Word23140 = 1;
    d.Word11760 = 1;
    if ((d.MouseSwitches & 2) == 0)
    {
      d.Word23140 = 0;
      d.Word11760 = 0;
      d.Word11762 = 0;
    }
    else
    {
      STHideCursor();
      d.Word23118 = 1;
      DisplayFoodWater();
      MarkViewportUpdated(0);
    };
    if (itemToDeleteFromDatabase != NULL) DeleteDBEntry(itemToDeleteFromDatabase);
    RETURN;
  };
  if (d.PotentialCharacterOrdinal != 0)
  {
    if (itemToDeleteFromDatabase != NULL) DeleteDBEntry(itemToDeleteFromDatabase);
    RETURN;
  };
  ASSERT(RememberToPutObjectInHand == -1);
  objD7 = d.objectInHand;
  D0W = GetObjectIndex(objD7);
  ASSERT( (D0W >= 0) && (D0W < 180));
  D0W = d.ObjDesc[D0W].word4;
  if ((D0W & 1) == 0)
  {
    if (itemToDeleteFromDatabase != NULL) DeleteDBEntry(itemToDeleteFromDatabase);
    RETURN; // Not consumable
  };
  otD6 = GetModifiedObjectType(objD7);
  dbType_18 = objD7.dbType();
  w_20 = sw(GetObjectWeight(objD7));
  obj_w_20 = objD7;
  chIdx = sw(d.SelectedCharacterOrdinal-1);
  pcA2 = &d.CH16482[chIdx];
  dbA3 = GetCommonAddress(objD7);
  if ((otD6 >= obj_Waterskin) && (otD6 <= obj_Water))
  {
    // Is it empty
    if (dbA3->CastToDB10()->value() == 0)
    {
      if (itemToDeleteFromDatabase != NULL) DeleteDBEntry(itemToDeleteFromDatabase);
      RETURN;
    };
    pcA2->water = sw(Smaller(pcA2->water + 800, 2048));
    //One gulp is now gone.
    dbA3->CastToDB10()->value(dbA3->CastToDB10()->value()-1);
    D4W = 0;
  }
  else
  {
    if (dbType_18 == dbPOTION) // DB type
    {
      D4W = 0;
    }
    else
    {
      //dbA3->CastToDB10()->link(RNnul); // Remove the object from the database.
      itemToDeleteFromDatabase = dbA3;
      //DeleteDBEntry(dbA3); //Remove object from database
      D4W = 1;
    };
  };
  STHideCursor();
  if (D4W != 0)
  {
    RemoveObjectFromHand();
  };
  if (dbType_18 == dbPOTION)
  {
    w_12 = sw(dbA3->CastToDB8()->strength());
    w_30 = sw(32 + (w_12 + 1) / 8);
    w_14 = sw(((511 - w_12) / w_30) / 2);
    w_12 = sw(w_12 / 25 + 8);
    switch (dbA3->CastToDB8()->potionType())
    {
    case potion_RosPotion:
        AdjustCurrentAttribute(pcA2, 2, w_12);
        break;

    case potion_KuPotion:
        AdjustCurrentAttribute(pcA2,
                               1,
                               dbA3->CastToDB8()->strength()/35 + 5);
        break;
    case potion_DanePotion:
        AdjustCurrentAttribute(pcA2, 3, w_12);
        break;
    case potion_NetaPotion:
        AdjustCurrentAttribute(pcA2, 4, w_12);
        break;
    case potion_AntiVenin:
        TAG017344(chIdx);
        break;
    case potion_MonPotionB:
        pcA2->Stamina(
               pcA2->Stamina() +
                 Smaller(pcA2->MaxStamina() - pcA2->Stamina(),
                   pcA2->MaxStamina()/w_14));
        break;
    case potion_YaPotion:
        w_12 = sw(w_12 + w_12/2);
        if (pcA2->shieldStrength > 50)
        {
          w_12 = sw(w_12/4);
        };
        {
          i32 oldShieldLevel, newShieldLevel;
          char ascii[10];
          oldShieldLevel = pcA2->shieldStrength/50;
          pcA2->shieldStrength = sw(pcA2->shieldStrength + w_12);
          newShieldLevel = pcA2->shieldStrength/50;
          if (oldShieldLevel != newShieldLevel)
          {
            PrintLinefeed();
            QuePrintLines(d.Byte1386[chIdx],pcA2->name);
            QuePrintLines(d.Byte1386[chIdx]," SHIELD INCREASED TO ");
            sprintf(ascii, "%d", pcA2->shieldStrength);
            QuePrintLines(d.Byte1386[chIdx], ascii);
          };
        };
        timer.Function(TT_72);
        D0L = d.Time + w_12 * w_12;
        D0L |= d.partyLevel << 24;
        timer.timerTime = D0L;
        timer.timerUByte5 = ub(chIdx);
        timer.timerUWord6() = w_12;
        SetTimer(&timer);
        pcA2->word48 |= 0x1000;
        break;
    case potion_EEPotion:
        D0W = sw(pcA2->Mana() + w_12 + w_12 - 8);
        i_18 = Smaller(900, D0W);
        if (i_18 > pcA2->MaxMana())
        {
          w_40 = sw(Larger(pcA2->Mana(), pcA2->MaxMana()));
          i_18 -= (i_18 - w_40)/2;
        };
        pcA2->Mana(i_18);
        break;
    case potion_ViPotion: // Healing potion?
        i_18 = Larger(dbA3->CastToDB8()->strength()/42, 1);
        {
          i32 tempHP;
          tempHP = pcA2->HP() + pcA2->MaxHP()/w_14;
          if (tempHP > pcA2->MaxHP()) tempHP = pcA2->MaxHP();
          pcA2->HP(tempHP);
        };
        w_16 = pcA2->ouches;
        if (pcA2->ouches != 0)
        {
          for (w_14=10; w_14!=0; w_14--)
          {
            for (w_12=0; w_12<i_18; w_12++)
            {

              pcA2->ouches &= STRandom();
            };
            i_18 = 1;
            if (w_16 != pcA2->ouches) break; // Anything change?
//
//
          };
        };
        pcA2->word48 |= 0x2200;
        break;
    case potion_WaterFlask:
        pcA2->water = sw(Smaller(2048, pcA2->water+1600));
        break;
    }; // switch()
    dbA3->CastToDB8()->potionType(potion_EmptyFlask);
  }
  else
  {
    if ( (otD6 >= obj_Apple) && (otD6 <= obj_DragonSteak) )
    { // Any kind of food.
      pcA2->food =
          sw(Smaller(2048,
                 pcA2->food+d.FoodValue[otD6-obj_Apple]));
    };
  };
  if (pcA2->Stamina() > pcA2->MaxStamina())
  {
    pcA2->Stamina(pcA2->MaxStamina());
  };
  if (pcA2->HP() > pcA2->MaxHP()) pcA2->HP(pcA2->MaxHP());
  if (D4W != 0)
  {
    for (i=0; i<2; i++)
    {
      TAG0013e4(obj_Special_h, 56, 46);
      VBLDelay(_2_,8);  //Animation delay.  Chewing
      TAG0013e4(obj_Special_g, 56, 46);
      VBLDelay(_1_,8);  //Animation delay.  Chewing
//
    };
  }
  else
  {
    DrawEightHands();
    DEBUGLOAD(pcA0, w_20, -1, obj_w_20);
    D1L = GetObjectWeight(objD7) - w_20; // New weight - old
    pcA0 = &d.CH16482[d.HandChar];
    DEBUGLOAD(pcA0, GetObjectWeight(objD7), +1, objD7);
    pcA0->load = sw(pcA0->load + D1W);
    ASSERT(pcA0->load < MAXLOAD);
    pcA0->word48 |= 0x200;
  };
  QueueSound(8, d.partyX, d.partyY, 0);
  pcA2->word48 |= 0x100;
  if (d.WpnChestOrScroll == 0)
  {
    pcA2->word48 |= 0x800;
  };
  DrawCharacterState(chIdx);
  STShowCursor();
  if (itemToDeleteFromDatabase != NULL) DeleteDBEntry(itemToDeleteFromDatabase);
  RETURN;
}

//*********************************************************
//
//*********************************************************
void TAG019036(void)
{
  dReg D0, D4, D5, D6, D7;
  aReg A0;
  CHARDESC *pcA3;
  char LOCAL_24[20];
  i16  LOCAL_4;
  i16  LOCAL_2;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  if (TimerTraceActive)
  {
    fprintf(GETFILE(TraceFile),"%06x TAG019036 calling Repack Chest\n",d.Time);
  };
  RepackChest();
  D4W = sw(d.SelectedCharacterOrdinal-1);
  pcA3 = &d.CH16482[D4W];
  BLT2Viewport(GetBasicGraphicAddress(20), &d.wRectPos926, 72, 8);
  D6W = 58;
  for (D7W=0; D7W<=3; D7W++)
  { // fighter, ninja, priest, wizard
    D5W = (i16)DetermineMastery(D4W, D7W|0x8000);//Novice, master, etc.
    D5W = sw(Smaller(16, D5W));  //There are limits, you know.
    if (D5W == 1) continue;
    if (D5W == 0) die (0x8d49,"Mastery = 0");
    A0 = d.Pointer16770[D5W];
    StrCpy(LOCAL_24, A0);// "Novice", "Master", etc
    StrCat(LOCAL_24, " ");
    StrCat(LOCAL_24, d.Pointer16596[D7W]);//"Fighter", etc
    TextToViewport(108, D6W, 13, LOCAL_24);
    D6W += 7;
//
//
  };
  D6W = 86;
  for (D7W=1; D7W<=6; D7W++)
  {
    A0 = d.Pointer16822[D7W];//"STRENGTH", "DEXTERITY", etc.
    TextToViewport(108, D6W, 13, A0);
    D5W = pcA3->Attributes[D7W].Current();
    D0W = pcA3->Attributes[D7W].Maximum();
    LOCAL_4 = D0W;
    if (D5W < LOCAL_4)
    {
      LOCAL_2 = 8;
    }
    else
    {
      if (D5W > LOCAL_4)
      {
        LOCAL_2 = 7;
      }
      else
      {
        LOCAL_2 = 13;
      };
    };
    TextToViewport(174, D6W, LOCAL_2, TAG014af6(D5W, 1, 3));
    StrCpy(LOCAL_24,"/");
    StrCat(LOCAL_24, TAG014af6(LOCAL_4, 1, 3));
    TextToViewport(192,D6W, 13, LOCAL_24);
    D6W += 7;
//
  };
}

//*********************************************************
//
//*********************************************************
//   TAG0192a4
void CharacterPortraitToStatusBox(i32 chIdx)
{
  RectPos LOCAL_8;
  d.UseByteCoordinates = 0;
  LOCAL_8.w.y1 = 0;
  LOCAL_8.w.y2 = 28;
  LOCAL_8.w.x1 = sw(chIdx*69+7);
  LOCAL_8.w.x2 = sw(LOCAL_8.w.x1+31);
  BLT2Screen(d.CH16482[chIdx].portrait,
            &LOCAL_8,
            16,
            -1);
}

//*********************************************************
//
//*********************************************************
RESTARTABLE _TAG019fac(const i32 clickX, const i32 clickY)
{//(void)
  static dReg D7;
  RESTARTMAP
    RESTART(1)
    RESTART(2)
    RESTART(3)
    RESTART(4)
    RESTART(5)
    RESTART(6)
  END_RESTARTMAP
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  if (d.AttackingCharacterOrdinal != 0)
  {
    D7W = SearchButtonList(d.Buttons17892, clickX, clickY, 2);
    if (D7W != 0)
    {
      if (D7W == 112)
      {
        FlashButton(_1_,0x11d, 0x13f, 0x4d, 0x0053);
        ExecuteAttack(_2_,-1);
      }
      else
      {
        if (D7W - 112 <= d.Word20248)
        {
          if (D7W == 113)
          {
            FlashButton(_3_,0xea, 0x13e, 0x56, 0x60);
          }
          else
          {
            if (D7W == 114)
            {
              FlashButton(_4_,0xea, 0x13e, 0x62, 0x6c);
              /*
              Code was jumped around.
              if (d.Word918 ?? 136)
              {
                D0W = TAG01385a(&d.Byte11678);
                if (D0W ?? 0)
                {
                  d.Word4012 = 3217;
                };
              }
              else
              {
              */
            }
            else
            {
              FlashButton(_5_,0xea, 0x13e, 0x6e, 0x78);
            };
          };
          ExecuteAttack(_6_,D7W-113);
          d.clockTick = i16Result;
        };
      };
    };
  }
  else
  {
    if (d.Word20252)
    {
      D7W = SearchButtonList(d.Buttons17952,clickX,clickY,2);
      if (D7W != 0)
      {
        D7W -= 116;
        if (D7W < d.NumCharacter)
        {
          PrepareAttack(D7W); // Blue square appears around weapon hand
                              // and attack options appear.
        };
      };
    };
  };
  RETURN;
}

//*********************************************************
//
//*********************************************************
//  TAG01ac26
bool ItemHasChargesLeft(void)
{
	// Determines whether the item has enough charges (true if ready,
	// false if drained)
  CHARDESC *pcA0;
  RN      objD7;
  DBCOMMON *dbA3;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  pcA0 = &d.CH16482[d.AttackingCharacterOrdinal-1];
  objD7 = pcA0->possessions[1];
  dbA3 = GetCommonAddress(objD7);
  switch (objD7.dbType())
  {
  case dbWEAPON:
      return dbA3->CastToDB5()->charges() != 0;
  case dbCLOTHING:
      return dbA3->CastToDB6()->charges() != 0;
  case dbMISC:
      return dbA3->CastToDB10()->value() != 0;

  default: return 1;
  };
}

//*********************************************************
//
//*********************************************************
//   TAG01acb0
void GetLegalAttackTypes(ui8 *P1)
{
	// This function always enable the first option and then
  // checks the rest of item`s options if party member is
  // good enough to use the option
  dReg D0, D4, D5, D6, D7;
  ui8 *uA3;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  uA3 = P1;
  d.PossibleAttackTypes[0] = *uA3;
  d.Byte20256[0] = 1;
  D6W = 1;
  for (D7W=1; D7W<3; D7W++)
  {
    D5W = *(uA3+D7W);
    if (D5W == 255) continue;
    D4W = *(uA3+D7W+3);
    if (D4W & 128)
    {
      if (!ItemHasChargesLeft()) continue;
    };
    D4W &= 0xff7f;
    D0W = (i16)DetermineMastery(d.AttackingCharacterOrdinal-1,
                                 (UI8)(d.SkillNumber[D5W]));

    if (D0W < D4W) continue;
    d.PossibleAttackTypes[D6W] = D5B;
    d.Byte20256[D6W] = D4B;
    D6W++;

//
  };
  d.Word20248 = D6W;
  for (D7W = D6W; D7W<3; D7W++)
  {
    d.PossibleAttackTypes[D7W] = -1;
//
  };
}

//*********************************************************
//
//*********************************************************
//   TAG01af32
void DrawAttackButton(i32 chIdx)
{
  dReg D0;
  RN objD7;
  OBJECTTYPE otD7;
  aReg A3;
  CHARDESC *pcA2;
  RectPos LOCAL_16;
  RectPos LOCAL_8;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  if (d.Word20252 == 0) return;
  LOCAL_8.w.x1 = sw(22*chIdx + 233);
  LOCAL_8.w.x2 = sw(LOCAL_8.w.x1 + 19);
  LOCAL_8.w.y1 = 86;
  LOCAL_8.w.y2 = 120;
  d.UseByteCoordinates = 0;
  pcA2 = &d.CH16482[chIdx];
  if (pcA2->HP() == 0)
  {
    FillRectangle(d.LogicalScreenBase,
                  &LOCAL_8,
                  0,
                  160);
    return;
  };
  A3 = allocateMemory(128, 0);
  objD7 = pcA2->possessions[1]; //Weapon hand
  if (objD7 == RNnul)
  {
    otD7 = obj_Special_c;
  }
  else
  {
    D0L = GetObjectIndex(objD7);
    D0B = d.ObjDesc[D0W].byte3;
    if (D0B)
    {
      otD7 = GetModifiedObjectType(objD7);
    }
    else
    {
#if TARGET_OS_MAC
      Flood(A3, 8, 16);
#else
      Flood(A3, 4, 16);
#endif
      goto tag01b018;
    };
  }
  GetIconGraphic(otD7, A3);
  ShrinkBLT(A3, A3, 16, 16, 16, 16, &d.Byte20194);
tag01b018:
  FillRectangle(d.LogicalScreenBase, &LOCAL_8, 4, 160);
  LOCAL_16.w.x1 = sw(LOCAL_8.w.x1 + 2);
  LOCAL_16.w.x2 = sw(LOCAL_8.w.x2 - 2);
  LOCAL_16.w.y1 = 95;
  LOCAL_16.w.y2 = 110;
  BLT2Screen(A3, &LOCAL_16, 8, -1);
  if (   (pcA2->word48 & 8)
      || (d.PotentialCharacterOrdinal)
      || (d.PartySleeping) )
  {
    ShadeRectangleInScreen(&LOCAL_8, 0); //Shade (disable) attack
  };
  FreeTempMemory(128);
}

//*********************************************************
//
//*********************************************************
void TAG01b1c0(void)
{//(void)
  CHARDESC *pChar;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  // Check somebody selecting attack option
  if (d.AttackingCharacterOrdinal == 0) return;
  d.AttackingCharacterOrdinal--;
  pChar = &d.CH16482[d.AttackingCharacterOrdinal];
  pChar->word48 |= 0x8000;
  DrawCharacterState(d.AttackingCharacterOrdinal);
  d.AttackingCharacterOrdinal = 0;
  d.Word20250 = 1;
}

//*********************************************************
//
//*********************************************************
//   TAG01b1f8
void PrepareAttack(i16 chIdx)
{//(void)
	// This function look for the object in hand and pops up
  // object`s options (CHOP, SWING, ...).
  // It also draws the blue square around the right hand.
  dReg D0, D7;
  RN objD6;
  aReg A2;
  CHARDESC *pcA3;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  pcA3 = &d.CH16482[chIdx];
  if (((pcA3->word48 & 8) != 0) || (pcA3->HP()==0)) return;
  objD6 = pcA3->possessions[1];
  if (objD6 == RNnul) // If no weapon wielded
  {
    D7W = 2;
  }
  else
  {
    D0W = GetObjectIndex(objD6);
    D7W = (UI8)(d.ObjDesc[D0W].byte3);
    if (D7W == 0) return; // if no attack action
  };
  A2 = &d.Byte19570[8*D7W];
  d.AttackingCharacterOrdinal = sw(chIdx+1);
  d.Word20262 = *(A2+6);//This seems wrong but who cares?
  GetLegalAttackTypes((ui8 *)A2);
  d.Word20252 = 0;
  pcA3->word48 |= 0x8000;
  DrawCharacterState(chIdx); //box at top,pos,dir,weapon
  DrawLegalAttackTypes();
}

//*********************************************************
//
//*********************************************************
//  TAG01b37c
RESTARTABLE _ExecuteAttack(const i32 P1)
{ //(i16)
  //P1=attack number (or -1 for pass)
  static dReg D5;
  static CHARDESC *pChar;
  static ATTACKTYPE attackType;
  RESTARTMAP
    RESTART(1)
  END_RESTARTMAP
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

  if (   (d.AttackingCharacterOrdinal==0)
      || ((UI8)(d.PossibleAttackTypes[P1])==255))
  {
    RETURN_i16(0);
  };
  pChar = &d.CH16482[d.AttackingCharacterOrdinal-1];
  if (P1 == -1)
  {
    D5W = -1;
  }
  else
  {
    attackType = (ATTACKTYPE)(UI8)(d.PossibleAttackTypes[P1]);
    pChar->word64 = sw(pChar->word64 + sb(d.Byte20090[attackType]));
    pChar->word48 |= 0x100;
    Attack(_1_,d.AttackingCharacterOrdinal-1,attackType);
    D5W = i16Result;
    pChar->attackType = sb(attackType);
  };
  TAG01b1c0();
  RETURN_i16(D5W);
}

//*********************************************************
//
//*********************************************************
void TAG01b50e(i16 chIdx)
{
  CHARDESC *pcA3;
  i16 LOCAL_8;
  i16 LOCAL_6;
  i16 LOCAL_4;
  i16 LOCAL_2;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  pcA3 = &d.CH16482[chIdx];
  d.UseByteCoordinates = 0;
  LOCAL_2 = d.CH16482[0].HP();
  LOCAL_4 = d.CH16482[1].HP();
  LOCAL_6 = d.CH16482[2].HP();
  LOCAL_8 = d.CH16482[3].HP();
  STHideCursor();
  FillRectangle(d.LogicalScreenBase,
                (RectPos *)d.Word20242,
                0,
                160);
  if (chIdx == 0)
  {
    TraceFlash("vblFlashButn from 01b574");
    vblFlashButn(0xe9, 0x115, 0x2a, 0x31);
    TextOutToScreen(0xeb, 0x30, 0, 4, pcA3->name);
    if (d.NumCharacter > 1)
    {
      if (LOCAL_4 != 0)
      {
        TraceFlash("vblFlashButn from 01b5aa");
        vblFlashButn(0x118, 0x123, 0x2a, 0x30);
      };
tag01b5b0:
      if (d.NumCharacter > 2)
      {
        if (LOCAL_6 != 0)
        {
          TraceFlash("vblFlashButn from 01b5ca");
          vblFlashButn(0x126, 0x131, 0x2a, 0x30);
        };
tag01b5d0:
        if (d.NumCharacter > 3)
        {
          if (LOCAL_8 != 0)
          {
            TraceFlash("vblFlashButn from 01b5ea");
            vblFlashButn(0x134, 0x13f, 0x2a, 0x30);
          };
        };
      };
    };
    STShowCursor();
    return;
  };
  if (chIdx == 1)
  {
    if (LOCAL_2)
    {
      TraceFlash("vblFlashButn from 01b60e");
      vblFlashButn(0xe9, 0xf4, 0x2a, 0x30);
    };
    TraceFlash("vblFlashButn from 01b620");
    vblFlashButn(0xf7, 0x123, 0x2a, 0x31);
    TextOutToScreen(0xf9, 0x30, 0, 4, pcA3->name);
    goto tag01b5b0;
  };
  if (chIdx == 2)
  {
    if (LOCAL_2)
    {
      TraceFlash("vblFlashButn from 01b65a");
      vblFlashButn(0xe9, 0xf4, 0x2a, 0x30);
    };
    if (LOCAL_4)
    {
      TraceFlash("vblFlashButn from 01b672");
      vblFlashButn(0xf7, 0x102, 0x2a, 0x30);
    };
    TraceFlash("vblFlashButn from 01b684");
    vblFlashButn(0x105, 0x131, 0x2a, 0x31);
    TextOutToScreen(0x107, 0x30, 0, 4, pcA3->name);
    goto tag01b5d0;
  };
  if (chIdx != 3)
  {
    STShowCursor();
    return;
  };
  if (LOCAL_2)
  {
    TraceFlash("vblFlashButn from 01b6be");
    vblFlashButn(0xe9, 0xf4, 0x2a, 0x30);
  };
  if (LOCAL_4)
  {
    TraceFlash("vblFlashButn from 01b6d6");
    vblFlashButn(0xf7, 0x102, 0x2a, 0x30);
  };
  if (LOCAL_6)
  {
    TraceFlash("vblFlashButn from 01b6ee");
    vblFlashButn(0x105, 0x110, 0x2a, 0x30);
  };
  TraceFlash("vblFlashButn from 01b700");
  vblFlashButn(0x113, 0x13f, 0x2a, 0x31);
  TextOutToScreen(0x115, 0x30, 0, 4, pcA3->name);
  STShowCursor();
}

//*********************************************************
//
//*********************************************************

//   TAG01b880
void DrawMovementButtons(void)
{
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  STHideCursor();//TAG002fd2
  BLT2Screen(GetBasicGraphicAddress(13), (RectPos *)d.Word28, 48, -1);//Movement buttons
  STShowCursor(); //TAG003026
}

//*********************************************************
//
//*********************************************************
void TAG02076e(void)
{ //(void)
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  if (d.PartySleeping) return;
  STHideCursor();
  WaitForButtonFlash(); //If any are active//counted

  d.UseByteCoordinates = 0;
  if (d.SelectedCharacterOrdinal)
  {
    if (d.WpnChestOrScroll == 4) // if displaying chest contents
    {
      if (TimerTraceActive)
      {
        fprintf(GETFILE(TraceFile),"%06x TAG02076e calling Repack Chest\n",d.Time);
      };
      RepackChest();
    };
  }
  else
  {
    ShadeRectangleInScreen((RectPos *)d.Word28, 0);
  };
  ShadeRectangleInScreen((RectPos *)d.Word12, 0);//Clear Magic area
  ShadeRectangleInScreen((RectPos *)d.Word20, 0);//Clear weapon ready area
  SetCursorShape(0);
  STShowCursor();
}

//*********************************************************
//
//*********************************************************
void TAG022a60(i16 P1,pnt P2)
{
  pnt A2, A3;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  A3 = P2;
  A2 = d.ppUnExpandedGraphics[P1];
  ExpandGraphic(A2, A3, 0, 0);
}