#include "stdafx.h"

#include <stdio.h>
#include <time.h>

#include "UI.h"

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

void TraceTimer(TIMER *pTimer, i32 index, char *msg);


//i32 D0,D1,D2,D3,D4,D5,D6,D7;
//pnt A0,A1,A2,A3,A4,A5,A6,A7;

extern bool PlaybackCommandOption;
extern bool GameIsComplete;
extern bool RepeatGame;
extern bool fullscreenRequested;
extern bool fullscreenActive;
extern i32 VBLMultiplier;
extern char *helpMessage;
#ifdef GraphicsDebug
FILE *GrphDbg = NULL;
#endif

pnt firstMemoryBlock=NULL; // Debug list of allocated blocks

DBank d;

void _MessageBox(char *msg)
{
  UI_MessageBox(msg,NULL,MESSAGE_OK);
}

void Terminate(void)
{
  abort();
};

void die(i32 errorNum, char *msg) // TAG000efc
{
  char message[300];
  if ((msg==NULL)||(strlen(msg)==0))
  {
    switch(errorNum)
    {
    case 41:  msg="Cannot open GRAPHICS.DAT"; break;
    case 141: msg="Too many files open"; break;
    default:  msg="SystemError";
    };
  };
  sprintf(message,"System Error  %d\n%s",errorNum,msg);
  UI_MessageBox(message,NULL,MESSAGE_OK);
  if (errorNum == 41)
  {
    UI_MessageBox(helpMessage,"Help",MESSAGE_OK);
  };
  UI_Die();
}

void _Assert(bool value, char *program, i32 line)
{
  i32 n;
  if (value==0)
  {
    char msg[1000];
    sprintf(msg,
        "Assertion failure\n"
        "Line %d\n"
        "Program %s\nShould we quit?",  line, program);
    n = UI_MessageBox(msg,NULL,MESSAGE_YESNO);
    if (n == MESSAGE_IDYES) die (0,NULL);
  };
}

struct PRINTENTRY
{
  PRINTENTRY *m_next;
  i32         m_color;
  i32         m_type;
  char        m_text[1];
};

class PRINTQUEUE
{
private:
  PRINTENTRY *m_firstEnt;
public:
  PRINTQUEUE(void) {m_firstEnt = NULL;};
  ~PRINTQUEUE(void)
  {
    while (m_firstEnt != NULL)
    {
      PRINTENTRY *temp = m_firstEnt;
      m_firstEnt = temp->m_next;
      UI_free (temp);
    };
  };
  void Queue(i16 color, i16 type, char *text);
  PRINTENTRY *GetEntry(void);
};

void PRINTQUEUE::Queue(i16 color, i16 type, char *text)
{
  i32 len;
  PRINTENTRY *temp, *next;
  len = strlen(text);
  len += sizeof (PRINTENTRY) + 10;// Just to feel safe.
  temp = (PRINTENTRY *)UI_malloc (len);
  if (temp == NULL)
  {
    die(0x7dea3,"Cannot allocate Printline Memory");
  };
  temp->m_next = NULL;
  temp->m_color = color;
  temp->m_type = type;
  strcpy(temp->m_text,text);
  if (m_firstEnt ==NULL) m_firstEnt = temp;
  else
  {
    next = m_firstEnt;
    while (next->m_next != NULL) next = next->m_next;
    next->m_next = temp; // Add new entry at end of queue.
  };
}

PRINTENTRY *PRINTQUEUE::GetEntry(void)
{
  PRINTENTRY *temp;
  if (m_firstEnt == NULL) return NULL;
  temp = m_firstEnt;
  m_firstEnt = temp->m_next;
  return temp;
}

PRINTQUEUE printQueue;


bool verifyRectPos(RectPos *r)
{
  ui32 x1, x2, y1, y2;
  if (d.UseByteCoordinates)
  {
    x1=r->b.x1;
    x2=r->b.x2;
    y1=r->b.y1;
    y2=r->b.y2;
  }
  else
  {
    x1=r->w.x1;
    x2=r->w.x2;
    y1=r->w.y1;
    y2=r->w.y2;
  };
  if (x1>x2) return false;
  if (y1>y2) return false;
  if (x2>319) return false;
  if (y2>199) return false;
  return true;
}

#ifdef _littleEndian
i32 LE32(i32 lng)
{
  return   ((lng >> 24)&0xff)
         | ((lng >> 8)&0xff00)
         | ((lng << 8)&0xff0000)
         | ((lng <<24)&0xff000000);
}
#endif


RN& RNGear(pnt p)
{
  return *((RN *)(p));
}

pnt& pntGear(pnt p)
{
  return *((pnt *)(p));
}

upnt& upntGear(pnt p)
{
  return *((upnt *)(p));
}

void SwapWordsInButtonList(btn *pButton)
{
  for (;pButton->word0 != 0; pButton++)
  {
    pButton->word0  = LE16(pButton->word0);
    pButton->xMin   = LE16(pButton->xMin);
    pButton->xMax   = LE16(pButton->xMax);
    pButton->yMin   = LE16(pButton->yMin);
    pButton->yMax   = LE16(pButton->yMax);
    pButton->button = LE16(pButton->button);
  };
}

i32 programDescriptor[] = {
  0,      // Program Header Address
  0,      // Last Allocated address +1
  0,      // Start of program I-Bank
  0,      // Length of program I-Bank
  0,      // Start of initialized data
  0x05ec, // Length of initialized data
  0,      // Start of uninitialized data
  0x5b70  // Length of uninitialized data
};



i8 LScreenBase[320][210]; // Extra room at end for ???

void SetButtonPointers(void)
{
  d.pButn18970[0][0] = d.Buttons18624;
  d.pButn18970[0][1] = d.Buttons18660;
  d.pButn18970[0][2] = d.Buttons18708;
  d.pButn18970[0][3] = d.Buttons18768;
  d.pButn18970[1][0] = d.Buttons18792;
  d.pButn18970[1][1] = d.Buttons18828;
  d.pButn18970[1][2] = d.Buttons18876;
  d.pButn18970[1][3] = d.Buttons18936;
}


void InitializeDBank(void) // TAG00332a
{
  ASSERT(sizeof (d) == 23408);
  d.Word1834=512;
  d.Word1844=512;
  d.Word1870 = 1;
  d.Pointer2066[0] = &d.Byte1982;
  d.Pointer2066[1] = (pnt)&d.Word1838;
  d.Pointer2066[2] = (pnt)&d.Word1870;
  d.Pointer2066[3] = (pnt)&d.Word1844;
  d.Pointer2526[0] = d.Word2050;
  d.Pointer2526[1] = d.Word2210;
  d.Pointer2526[2] = d.Word2318;
  d.CurrentFloorAndCeilingGraphic = -1;
  d.CurrentWallGraphic  = -1;
  d.Word7254  = 1;
  d.LoadedLevel = -1;
  d.Word11684 = 1;
  d.clockTick = 1;
  d.Word11748 = -1;
  d.LogicalScreenBase=&LScreenBase[0][0];
  srand( (unsigned)time( NULL ) );
  d.RandomNumber=rand();
  d.TextAlreadyScrolledCount = -1;
  d.Long12950 = -200;
  d.Pointer12988[0] = &d.Byte23114;
  d.Pointer12988[1] = &d.Byte11850;
  d.Pointer12988[2] = &d.Byte22676;
  d.Pointer12988[3] = &d.Byte16550;
  d.Pointer12988[4] = &d.Byte13118;
  d.Pointer12988[5] = &d.Byte16702;
  d.ITEM16QueLen = 0;
  d.DelayedActuatorAction = -1; //Word13148
  d.HandChar = -1; // owner of cursor
  d.Pointer16596[0] = "FIGHTER";
  d.Pointer16596[1] = "NINJA";
  d.Pointer16596[2] = "PRIEST";
  d.Pointer16596[3] = "WIZARD";
  d.Long16600 = -505;
  d.WpnChestOrScroll = 0;
  d.objOpenChest = RNnul;
  d.Pointer16770[2]  = "NEOPHYTE";
  d.Pointer16770[3]  = "NOVICE";
  d.Pointer16770[4]  = "APPRENTICE";
  d.Pointer16770[5]  = "JOURNEYMAN";
  d.Pointer16770[6]  = "CRAFTSMAN";
  d.Pointer16770[7]  = "ARTISAN";
  d.Pointer16770[8]  = "ADEPT";
  d.Pointer16770[9]  = "EXPERT";
  d.Pointer16770[10] = "` MASTER";
  d.Pointer16770[11] = "a MASTER";
  d.Pointer16770[12] = "b MASTER";
  d.Pointer16770[13] = "c MASTER";
  d.Pointer16770[14] = "d MASTER";
  d.Pointer16770[15] = "e MASTER";
  d.Pointer16770[16] = "ARCHMASTER";
  d.Pointer16778  = &d.Byte10638;
  d.pwPointer16774  = &d.Word918;
  d.Pointer16770[0]  = (pnt)&d.Long16600;
  d.Pointer16770[1]  = (pnt)&d.Word1834;
  d.DirectionNames[0] = "NORTH";
  d.DirectionNames[1] = "EAST";
  d.DirectionNames[2] = "SOUTH";
  d.DirectionNames[3] = "WEST";
  d.Pointer16822[0] = "L";
  d.Pointer16822[1] = "STRENGTH";
  d.Pointer16822[2] = "DEXTERITY";
  d.Pointer16822[3] = "WISDOM";
  d.Pointer16822[4] = "VITALITY";
  d.Pointer16822[5] = "ANTI-MAGIC";
  d.Pointer16822[6] = "ANTI-FIRE";
  d.MouseQEnd = 4;
  d.MouseInterlock = 1;
  SetButtonPointers();
  d.MagicCaster = -1;
  d.Pointer22812 = "GAME LOADED, READY TO PLAY.";
  d.Pointer22816 = "CAN'T MODIFY CHAOS STRIKES BACK DISK!";
  d.Pointer22820 = "THAT'S NOT THE MASTER DISK!";
  d.Pointer22824 = "CAN'T FIND SAVED GAME!";
  d.Pointer22828 = "UNABLE TO SAVE GAME!";
  d.Pointer22832 = "UNABLE TO FORMAT DISK!";
  d.Pointer22836 = "THAT'S THE CHAOS STRIKES BACK DISK!";
  d.Pointer22840 = "THAT'S A GAME SAVE DISK!";
  d.Pointer22844 = "THAT DISK IS WRITE-PROTECTED!";
  d.Pointer22848 = "THAT DISK IS UNREADABLE";
  d.Pointer22852 = "THAT'S NOT THE SAME GAME";
  d.Pointer22856 = "SAVED GAME DAMAGED!";
  d.Pointer22860 = "PUT THE GAME SAVE DISK IN ~";
  d.Pointer22864 = "PUT THE CHAOS STRIKES BACK DISK IN ~";
  d.Pointer22868 = "PUT A BLANK DISK IN ~";
  d.Pointer22872 = "SAVING GAME . . .";
  d.Pointer22876 = "LOADING GAME . . .";
  d.Pointer22880 = "FORMATTING DISK . . .";
  d.Pointer22884 = "FORMAT DISK ANYWAY?";
  d.Pointer22888 = "THERE IS NO DISK IN ~!";
  d.Pointer22892 = "LOAD SAVED GAME";
  d.Pointer22896 = "SAVE AND PLAY";
  d.Pointer22900 = "SAVE AND QUIT";
  d.Pointer22904 = "FORMAT FLOPPY";
  d.Pointer22908 = "OK";
  d.Pointer22912 = "CANCEL";
  strcpy(&d.Byte23008,"A:\\csbgame.dat");
  strcpy(&d.Byte23024,"A:\\csbgame.bak");
  strcpy(&d.Byte23030,"A:\\F");
  d.UseByteCoordinates = 0;
  d.Pointer23040 = (pnt)0x484;
  d.CurrentSound = -1;
  d.Word23046 = 0;
  d.Word23118 = 1;
  d.NewCursorShape = 1;
  d.Word23150 = 0;
  d.Byte23202[0] = 2;
  d.Byte23202[1] = 17;
  d.Byte23202[2] = 2;
  d.Byte23202[3] = 17;
  d.Byte23206[0] = 0;
  d.Byte23206[1] = 15;
  d.Byte23206[2] = 0;
  d.Byte23206[3] = 15;
  d.wRectPos23214.w.x1 = 2;
  d.wRectPos23214.w.x2 = 20;
  d.wRectPos23214.w.y1 = 2;
  d.wRectPos23214.w.y2 = 15;
  d.wRectPos23222.w.x1 = 0;
  d.wRectPos23222.w.x2 = 18;
  d.wRectPos23222.w.y1 = 0;
  d.wRectPos23222.w.y2 = 13;
  d.OnMouseSwitchActionLock = 0; //(23224)
  d.Word23226 = 0;
  d.Word23228 = 0;
  d.ClusterInCache = -1; //(23276)
  d.Word23366 = 4096;
  d.RightZeroMask[0] = -1;
  d.RightZeroMask[1] = -2;
  d.RightZeroMask[2] = -4;
  d.RightZeroMask[3] = -8;
  d.RightZeroMask[4] = -16;
  d.RightZeroMask[5] = -32;
  d.RightZeroMask[6] = -64;
  d.RightZeroMask[7] = -128;
  d.RightZeroMask[8] = 0;
  d.RightOneMask[0] = 0;
  d.RightOneMask[1] = 1;
  d.RightOneMask[2] = 3;
  d.RightOneMask[3] = 7;
  d.RightOneMask[4] = 15;
  d.RightOneMask[5] = 31;
  d.RightOneMask[6] = 63;
  d.RightOneMask[7] = 127;
  d.RightOneMask[8] = -1;
  d.LZWBitNumber = 0;
  d.Word23406 = 0;
}

void SetSupervisorMode(void) {}

void ClearSupervisorMode(void) {}

void HangIfZero(i16 P1)
{
  if (P1 == 0)
    die(0,"HangIfZero");
}

void DisableCursor(void) {}

i32 GetAvailMemory(void)
{
  return 1000000;//510000;//1000000;
}

void jdisint(i16)
{ // Disable some interrupts.
  HopefullyNotNeeded();
}


ui32 GraphicRandom(ui32 n)
{
  static ui32 r = 12345;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  r = r * ui32(0xbb40e62d) + 11;
  return (r>>7) % n;
}



//   TAG00068e
RESTARTABLE _MainLoop(const CSB_UI_MESSAGE * /*msg*/)
{//(void)
  static dReg D0, D1;
  static PRINTENTRY *pPrintEntry;
  RESTARTMAP
    RESTART(1)
    RESTART(2)
    RESTART(4)
    RESTART(6)
    RESTART(7)
    RESTART(8)
    RESTART(9)
    RESTART(10)
  END_RESTARTMAP
  // We discard any message information.  At least for now.
tag000698: //We get here for each tick of the clock.
  if (d.PartySleeping == 0) d.Speed
       = sw(speedTable[gameSpeed].vblPerTick); // Delay vblOccurred for 10 VBLs
  d.vblCount = 0;
  if (d.Word11748 == -1) goto tag0006d0;
tag0006a4:
  LoadPartyLevel(_1_,d.Word11748); // Load graphics for level
  MoveObject(RN(RNnul), -1, 0, d.partyX, d.partyY);
  d.Word11748 = -1;
  TAG01953a();
tag0006d0:

  ProcessTimers(_6_);
  if (GameIsComplete) RETURN;
  if (d.Word11748 != -1) goto tag0006a4;
  if (d.SelectedCharacterOrdinal != 0) goto tag000730;
  if (d.PartySleeping != 0) goto tag000730;
     DrawViewport(d.partyFacing, d.partyX, d.partyY);
  if (d.Word11744 != 0)
  {
    d.Word11744=0;
    STHideCursor(); //TAG002fd2
    CreateObjectCursor(d.Pointer16572);
    STShowCursor(); //TAG003026
  };
  if (d.Word11746 != 0)
  {
    d.Word11746=0;
    d.NewCursorShape=1;
    STHideCursor(); //TAG002fd2
    STShowCursor(); //TAG003026
  };
tag000730:
  WaitForButtonFlash(); // If any are active.
  StartQueuedSound(); //counted
  TAG016e54(); //counted
  if (d.GameIsLost == 0)
  {
    d.Time++;
    SmartDiscard(false);
    GameTime = d.Time;
    if ((d.Time&511)==0) // about every 85 seconds
    {
      NinetySecondUpdate(); //TAG018124
    };
    if (d.uByte13271 != 0) d.uByte13271--;
    TAG01b29a(_4_);
    D0L = d.Time;
    D0L &= d.PartySleeping ? 15 : 63;
    if (D0L==0) TenSecondUpdate();
    D0L=d.Word11710;
    if (D0L!=0) d.Word11710--;
    D0L=d.Word11712;
    if (D0L != 0) d.Word11712--;
    TAG0018f6(_10_); // Remove text when its time is up.
    D0L=d.WatchdogTime;
    D1L=d.Time;
    if (D0L < D1L)
    {
      die(60, "Watchdog Timer failure"); //die (error number)
    };
    d.clockTick=0;
tag0007b4:
    goto tag0007c8;
tag0007b6: // A UIM_KEYDOWN message was received.
    D0L=UI_DIRECT_CONIN(); // Wait for key
    //D0L = msg->p1;
    ASSERT(D0L != -1);
    TAG0196da(D0L);
tag0007c8:
    pPrintEntry = printQueue.GetEntry();
    if (pPrintEntry != NULL)
    {
      PrintLines(_2_,pPrintEntry->m_color,pPrintEntry->m_text);
      UI_free (pPrintEntry);
    };
    WAITFORMESSAGE(_8_);//Any message!;//pumper();
    {
      //SYSTEMTIME systime;
      //GetSystemTime(&systime);
    };
    D0W=(i16)UI_CONSTAT();
    if (D0W != 0) goto tag0007b6;
    if (d.Word11758 != 0)
    {
      d.Word11756=0;
      d.Word11758=0;
      TAG019264();
    }
    else
    {
      if (d.Word11762 != 0)
      {
        d.Word11760=0;
        d.Word11762=0;
        TAG019018();
      };
    };
    HandleMouseEvents(_7_,1);  //TAG01a7b2
    if (DiskMenuNeeded) DisplayDiskMenu(_9_);
    if (d.clockTick    == 0) WaitForButtonFlash(); // If any active
    if (d.clockTick    == 0) goto tag0007b4; // Usually 0
    if (d.ClockRunning == 0) goto tag0007b4; // Usually 1
    if ((d.Time&63)    == 0) // about every 10 seconds
    {
      D0W = (i16)(d.Word11722 & (d.Word11724 ^ 0xffff));
      if (D0W != 0)
      {
        TAG02076e();
        TAG0207cc();
      };
    };
    goto tag000698;
  };
  RETURN;
}

//*********************************************************
//
//*********************************************************
//   TAG000850
RESTARTABLE _LoadPartyLevel(const i32 level)
{//(void)
  static dReg D0, D1;
  //i32  LOCAL_1;
  //i8   LOCAL_2[6];
  static TIMER LOCALa;
  RESTARTMAP
    RESTART(1)
    RESTART(2)
  END_RESTARTMAP
  TAG00bd40(); //Remove item16 entries for monsters from level.
  SetPartyLevel(level);
  ReadGraphicsForLevel(_2_); 
  if (d.Time > d.Long16600+500)
  {
    d.Long16600=d.Time+1;
    LOCALa.timerFunction = timerFunction22;
    D0L=d.Long16600+2;
    D1L=level;
    D1L >>= 24;
    D0L |= D1L;
    LOCALa.timerTime = D0L;
    SetTimer(&LOCALa);
    InsertDisk(_1_,0,0);
    HopefullyNotNeeded();
    d.Word19218 = 12777; // Seems in middle of graphic data
    d.Word918 = 136;
    d.Word1834 = 555;
  };
  ProcessMonstersOnLevel(); //add item16 entries for monsters on level.
  SelectPaletteForLightLevel();
  RETURN;
}


void MemMove(pnt src, pnt dest, i32 byteCount) // TAG0009dc
{
  memmove(dest, src, byteCount);
}

void ClearMemory(i8 *dest,i32 numByte) // TAG000a84
{
  memset(dest,0,numByte);
}

void fillWithByte(i8 *addr,i16 num,i8 value,i16 spacing) //TAG000ac0
{
  do
  {
    *addr = value;
    addr+=spacing;
  } while (--num!=0);
}

void fillMemory(i16 *pwAddress, i32 num, i16 value, i16 spacing) //TAG000af6
{ // num words,  spacing apart
  spacing /= 2; // Must be word spacing
  do
  {
    *pwAddress = value;
    pwAddress += spacing;
  } while ((--num) != 0);
}

void TAG000bb0(dReg& D0, dReg& D4, dReg& D5) // called by VBL handler
{  // Expects something in D0, D5, D4
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  if (d.Word23228 < 0)
  {
    d.Word11722 |= d.Word11720;
    d.Word11720 = 0;
    d.Word23228 = 0;
  };
  if (d.Word23136 == 0) return;
  if (D0W != 0)goto tag000c32;
  if (d.TextAlreadyScrolledCount < 0) goto tag000bde;
  if ((ui16)D5W >= 151) goto tag000c32;
tag000bde:
  if (d.ViewportUpdated == 0) goto tag000c24;
  if (D5W >= 169) goto tag000c24;
  if (D4W >= 224) goto tag000c0c;
  if (d.Word23146 == 0) goto tag000c04;
  if (d.Word23150 == 0) goto tag000c04;
  if (D5W <= 23) goto tag000c24;
  goto tag000c32;
tag000c04:
  if (D5W < 16) goto tag000c24;
  goto tag000c32;
tag000c0c:
  if (d.Word23146 == 0) goto tag000c24;
  if (D5W > 28) goto tag000c24;
  if (D5W <= 23) goto tag000c24;
  if (D4W < 232) goto tag000c32;
tag000c24:
  if (d.FlashButnActive == 0) goto tag000c30;
  if (D4W >= 192) goto tag000c32;
tag000c30:
  return;
tag000c32:
  D0L = 1;
  RemoveCursor(); //TAG00289a();
}

ui32 VBLCount = 0;
ui32 VBLInterruptCount = 0;
void vblInterrupt(void) // TAG000c3a
{
// Vertical Blank Handler
  dReg D0, D1, D2, D3, D4, D5;
  aReg A0;
  static i32 Count=0;
  VBLInterruptCount++;
  //SaveRegs(0xfc8c);
  //i32 *A4,*A5;
  //VBLCount++; // Counted by function that calls us.
  // A4 = data000b2c; // both start at zero
  // A5 = data000b30;
  if (d.ViewportUpdated)
  {
    d.DynamicPaletteSwitching = d.Word11740;
  }
  if (d.DynamicPaletteSwitching != 0)
  {
    d.Word11988 = 0;
    A0 = (pnt)0xfffffa00;
  };

  if (d.Word11990 != 0)
  {
    return;
  };
  d.Word11990++;
//                            Loop:  ; From below.
loop:
  Instrumentation(icntVBLLoop);
  if (d.Word23138 == 0)
  {
    D0L = 0;
    D3H1 = d.NewMouseY;//Word23124;
    D3W = d.NewMouseX;//Word23122;
    if (!PlayFile.IsOpen())
    {
      d.CurMouseY = D3H1;//Word23128 = D3U;
      d.CurMouseX = D3W;//Word23126 = D3W;
    };
    D2L = D3L;
    SWAP(D2);
    D4W = d.CurCursorX;
    D5W = d.CurCursorY;
    if (d.Word23144 != 0)
    {
      if ((D3W < 274) || (D2W > 28))
      {
        //SaveRegs(0xf0c0);
        TAG002818();
        //RestoreRegs(0x030f);
      };
    };
    D0W = d.Word23132;
    d.Word23132 = 0;
    if (   (d.Word23130 != 0)
        && (d.NewCursorShape == 0)
        && (D3W == D4W)
        && (D2W == D5W) )
    {
      D0L = 1;
      d.Word23130 = 0;
    };
    TAG000bb0(D0, D4, D5); // Expects something in D0, D5, D4//counted
    // May set D0 to 1;
    if ((d.Word1870 == 0) && (d.Word11750 == 0))
    {
      //SaveRegs(0xf0c0);
      TAG00456c();
      //RestoreRegs(0x030f);
        d.Word11750+=5;
    };
    if ((D0W != 0) && ((ui16)D2W <= 15))
    {
      DrawCursor();
      D0L = 0;
    };
    if (d.TextAlreadyScrolledCount >= 0)
    {
      //SaveRegs(0xf0c0);
      D1W = (i16)(27 - d.TextAlreadyScrolledCount);
      D1L = (ui16)D1W * (ui16)160;
      MemMove(d.LogicalScreenBase+27520+160, // Up one line
              d.LogicalScreenBase+27520,
              D1W);
      Invalidate();
      //RestoreRegs(0x030f);
    }
    else
    {
      if (d.Word12918 == 0) goto tag000dbe;
      d.Word12918 = 0;
    };
    D1L = 7;
    if (d.TextAlreadyScrolledCount >= 0)
    {
      d.TextAlreadyScrolledCount++;
      D1W = d.TextAlreadyScrolledCount;
      if (D1W == 7) d.TextAlreadyScrolledCount = -1;
    };
    //SaveRegs(0xf0c0);
    D2W = D1W;
    D1L = (ui16)D1W * (ui16)160;
    D2W = (i16)-D2W;
    D2W += 200;
    D2L = (ui16)D2W * (ui16)160;
    MemMove(d.newTextLine,
            d.LogicalScreenBase + D2L,
            D1W);
    //RestoreRegs(0x030f);
tag000dbe:
    if (d.ViewportUpdated != 0)
    {
      dReg D0;
      pnt A0,A1;
      d.ViewportUpdated = 0;
      if (d.Word11778 != 0)
      {
        d.Word11778 = 0;
        A0 = (pnt)&d.Palette552[d.CurrentPalette]; // palette address
        memmove((pnt)&d.Palette11946,A0,32); // set current palette
      };
      A0 = d.pViewportBMP;
      A1 = d.LogicalScreenBase+5280;
      Instrumentation(icntCopyViewportToScreen);
      if ((VBLMultiplier==1)|| (((Count++)%3)==0))
      for (D0W=0; D0W <136; D0W++)
      {
        memmove(A1,A0,112);
        A0 += 112;
        A1 += 160;
      };
    };
    if (d.FlashButnActive != 0)
    {
      d.FlashButnActive = 0;
      d.Word11776 ^= 0xffff;
      //SaveRegs(0xf0c0);
      TraceFlash("vblFlashButn from 000e46");
      vblFlashButn(d.FlashButnX1,
                   d.FlashButnX2,
                   d.FlashButnY1,
                   d.FlashButnY2);
      //RestoreRegs(0x030f);
    };
    if (D0W != 0)
    {
      DrawCursor(); // put cursor in LogBase...save old pixels//counted
    };
    if (d.Word23130 != 0)
    {
      d.Word23130 = 0;
      d.Word23132 = 1;
      d.NewCursorShape = 0;
      //SaveRegs(0xf0c0);
      CreateCursorBitmap(); // TAG00295e
      //RestoreRegs(0x030f);
    };
  };
  if (d.Word23228 > 0)
  {
    //A0 = d.pFunc23232;
  }
  else
  {
    if (d.Word23226 != 0)
    {
      //A0 = d.pFunc23236;
    };
  };
  d.vblCount += 1;
  //D0W = d.vblCount;
  if ((d.vblCount >= d.Speed) || (NoSpeedLimit!=0))
  {
    if (NoSpeedLimit!=0)
    {
      if (d.Time >= NoSpeedLimit)
      {
        NoSpeedLimit = 0;
        VBLMultiplier = 1;
      };
    };
    d.clockTick = 1;
  }
  else
  {
    if (   playerClock
        && (d.vblCount > 10)
        && !mouseQueueIsEmpty()
        && !PlayFile.IsOpen() )
    {
      d.clockTick = 1;
    };
  }
  d.Word11990 -= 1;
  if (d.Word11990 != 0) goto loop;

  //RestoreRegs(0x313f);
  return;
}



void TAG000ec6(void)
{
//////;;;;;;;;;;;;;;;;;;;;;;;;;;;; Set some user interrupt vectors
////
////
////                                   TRAP #4 now goes to vertical blank code.
  verticalIntEnabled = true;
}

void SystemError(i16 errorNum)
{
  die(errorNum, "");
}

//   TAG000f7e
void BLT2Screen(i8 *P1,RectPos *dstPos,i16 P3,i16 P4)
{   //             8       12     16     18
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
//0f7e 4e56 0000                LINK     A6,#0
  d.UseByteCoordinates = 0;
  ASSERT(verifyRectPos(dstPos));
  TAG0088b2(P1,
            d.LogicalScreenBase,
            dstPos,
            0,   // src x
            0,   // src y
            P3,  // src bytes/line
            160, // dst bytes/line
            P4);
}

//*********************************************************
//
//*********************************************************
//   TAG000fb2
RESTARTABLE _VBLDelay(const i32 n) //void
{ // Pause for n vertical blanks
  static i32 i;
  RESTARTMAP
    RESTART(1)
  END_RESTARTMAP
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  for (i=0; i<n; i++)
  {
    wvbl(_1_);
  };
  RETURN;
}

/*
i16 Abs(i32 x)
{
  if (x>=0) return (i16)x; else return (i16)-x;
}

i32 Min(i32 n, i32 m)
{
  return n<m?n:m;
}


//  TAG000ff8
i16 Max(i16 x, i16 y)
{
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  if (x <= y) return y;
  else return x;
}

  */
//  TAG00100e
i16 ApplyLimits(i32 min,i32 x,i32 max)
{
  if      (x <= min) x = min;
  else if (x >  max) x = max;
  return (i16)x;
}

unsigned int numRandomCalls = 0;

i32 STRandom(void) //TAG001030
{
  dReg D0;
  numRandomCalls++;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  D0L = d.RandomNumber * ui32(0xbb40e62d) + 11;
  d.RandomNumber = D0L;
  D0L >>= 8;
  D0L &= 0xffffff;
  return D0L;
}

i32 STRandom(i32 num)
{
  ASSERT(num!=0);
  if (num == 0) return 0;
  return (STRandom() & 0xffff) % num; // To be exactly like Atari
}

//  TAG001050
ui8 STRandomBool(void)
{ // Zero or One
  numRandomCalls++;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  d.RandomNumber = d.RandomNumber * (ui32)0xbb40e62d + 11;
  return (UI8)((d.RandomNumber>>8) & 1);
}

//  TAG001074
ui8 STRandom0_3(void)
{
  numRandomCalls++;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  d.RandomNumber = d.RandomNumber * (ui32)0xbb40e62d + 11;
  return (UI8)((d.RandomNumber>>8) & 3);
}

void TAG0010ae(void)
{
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  dReg D7;
  aReg A2, A3;
  //i32 saveD7=D7;pnt saveA2=A2,saveA3=A3;
  d.Pointer16572 = allocateMemory(128,1);
  A3 = allocateMemory((GetGraphicExpSize(0x22c)+199)&0xffff,1);
  A2 = allocateMemory(2786,0);
  ReadAndExpandGraphic(33324,A2,0,0);
  for (D7W=0;D7W<199;D7W++)
  {
    d.ObjectNames[D7W] = A3;
    while ((*A2 & 128)   == 0)
    {
      *(A3++) = *(A2++);
    };
    *(A3++) = (i8)(*(A2++)&0x7f);
    *(A3++) = 0;

  };
  BuildSmartDiscardTable();
  FreeTempMemory(2786);
  //D7=saveD7;A2=saveA2;A3=saveA3;
}

OBJECTTYPE GetBasicObjectType(RN object)
{
  dReg D7;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  if (object == RNnul)
  {
    return obj_NotAnObject;
  }
  else
  {
    D7W = GetObjectIndex(object);//TAG009308
    if (D7W == -1) return obj_NotAnObject;
    return d.ObjDesc[D7W].objectType();
  };
}

//         TAG001534
OBJECTTYPE ObjectAtLocation(i32 bodyLocation)
{ // Object type in nth (0 to 7) hand at top of screen.
  // Or object in nth position of clothing/backpack (8 to 37)
  //dReg D0;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  //D0W = 6*index;
  return d.IconDisplay[bodyLocation].objectType();
  //return D0W;
}

//   TAG001836
void SetPrintPosition(i16 column, i16 row)
{
  if (column <   0) column = 0;
  if (column >= 53) column = 52;
  if (row <   0) row = 0;
  if (row >=  4) row = 3;
  d.PrintColumn = column;
  d.PrintRow = row;
}


RESTARTABLE _TAG0018f6(void)
{//(void)
  static dReg D0, D5, D6;
  static RectPos LOCAL_8;
  RESTARTMAP
    RESTART(1)
  END_RESTARTMAP
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  d.UseByteCoordinates = 0;
  LOCAL_8.w.x1 = 0;
  LOCAL_8.w.x2 = 319;
  for (D6W=0; D6W<4; D6W++)
  {
    D5L = d.TextTimeout[D6W];
    if (D5L == -1) continue;
    if (D5L > d.Time) continue;
    D0W = (i16)(172 + D6W*7);
    LOCAL_8.w.y1 = D0W;
    LOCAL_8.w.y2 = (i16)(D0W +6);
      while (   (d.TextAlreadyScrolledCount >= 0)
             || (d.Word12918 !=0) )
      {
        wvbl(_1_);//NotImplemented(0x194e);//pumper();
      };
    STHideCursor();//TAG002fd2
    FillRectangle(d.LogicalScreenBase, (RectPos *)&LOCAL_8, 0, 160);
    STShowCursor(); //TAG003026
    d.TextTimeout[D6W] = -1;
//
  };
  RETURN;
}

RESTARTABLE _TAG001992(void)
{//(void)
  static dReg D7;
  RESTARTMAP
    RESTART(1)
  END_RESTARTMAP
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  if (d.PrintRow == 3)
  {
    while (   (d.TextAlreadyScrolledCount>=0)
      || (d.Word12918!=0) )
    { //NotImplemented(0x19ae);};//pumper();};
      wvbl(_1_);
    };
    ClearMemory(d.newTextLine, 1120);
    d.TextAlreadyScrolledCount = 0; //Start new line into scroll area
    for (D7W=0; D7W<3; D7W++)
    {
      d.TextTimeout[D7W] = d.TextTimeout[D7W+1];
    };

    d.TextTimeout[3] = -1;
    RETURN;
  };
  d.PrintRow++;
  RETURN;
}

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

//   TAG0019f8
void Printf(i32 color, pnt text)
{
  dReg D0, D7;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  D7W = StrLen(text);
  if (d.TextAlreadyScrolledCount == -1)
  {
    while (d.Word12918 != 0) {};
    STHideCursor();
    TextOutToScreen(d.PrintColumn*6, d.PrintRow*7+177, color, 0, text);
    STShowCursor();
  }
  else
  {
    TextOut(d.newTextLine, 160, d.PrintColumn*6, 5, color, 0, text);
    if (d.TextAlreadyScrolledCount == -1)
    {
      d.Word12918 = 1;
    };
  };
  d.PrintColumn = (i16)(d.PrintColumn + D7W);
  D0L = d.Time + 70; // about 10 seconds
  d.TextTimeout[d.PrintRow] = D0L;
}

//*********************************************************
//PrintLines needs to be restartable.  And that is very
//inconvenient.  So what do we do?  We change everyone
//to call QuePrintLines instead!  Then when it is convenient
//for us to call a restartable function we will take the
//lines out of the queue and call PrintLines.  We will probably
//do this in MainLoop.
//*********************************************************
void QuePrintLines(i16 color, pnt text)
{
  printQueue.Queue(color,1,text);  //There.  That was easy.
}

//*********************************************************
//
//*********************************************************
//   TAG001aa8
RESTARTABLE _PrintLines(const i32 color, pnt Text)
{//(void)
  static dReg D0, D6;
  static i8  LOCAL_56[54];
  //static i16  LOCAL_2;
  static pnt text;
  RESTARTMAP
    RESTART(1)
    RESTART(2)
  END_RESTARTMAP
  text = Text;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  //D7W = P1;
  //A3 = P2;

  while (*text != 0)
  {
    D0W = (i16)sb(*text);
    if (D0W == 10) // Linefeed
    {
      text++;
      if ( (d.PrintColumn!=0) || (d.PrintRow!=0) )
      {
        d.PrintColumn = 0;
        TAG001992(_2_); // scroll timeouts for the 4 lines
      };
    }
    else
    {
      D0W = (i16)sb(*text);
      if (D0W == 32)
      {
        text++;
        if (d.PrintColumn != 53)
        {
          //LOCAL_2 = ' '; // A single blank
          Printf(color, " "); // A single space.
        };
      }
      else
      {
        D6W = 0;
        do
        {
          LOCAL_56[D6W++] = *(text++);


        } while ((*text!=0) && (*text!=32) && (*text!=10));
        LOCAL_56[D6W] = 0;
        if (d.PrintColumn+D6W > 53)
        {
          d.PrintColumn = 2;
          TAG001992(_1_);
        };
        Printf(color, LOCAL_56);
      };
    };
  };
  RETURN;
}

//*********************************************************
//
//*********************************************************
//   TAG001c02
void PrintLinefeed(void)
{
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  QuePrintLines(0, d.Byte1830);
}

//*********************************************************
//
//*********************************************************
//   TAG001c42
void TextOutToScreen(i32 xPixel,i32 yPixel,i32 color,i32 P4,pnt P5)
{
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  TextOut(d.LogicalScreenBase,
          160,
          xPixel,
          yPixel,
          color,
          P4,
          P5);
}

void TAG001c6e(void)
{
  dReg D7;
  //i16 saveD7 = D7W;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  SetPrintPosition(0, 3);
  d.newTextLine = allocateMemory(1120,1);
  d.Pointer12926 = allocateMemory(768,1);
  ReadAndExpandGraphic(33325,d.Pointer12926,0,0);
  for (D7W = 0; D7W<4; D7W++)
  {
    d.TextTimeout[D7W] = -1;

  };
  //D7W = saveD7;
}


/*
void TAG0020ca(void)
{
  dReg D0;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

  KeyclickOff();
  giaccess(0,0x80 + 11);
  giaccess(0, 0x80 + 12);
  D0W = (i16)(giaccess(0, 7) &0xff);
  d.Word23036 = D0W;
  giaccess(d.Word23036 | 0x3f, 0x80 + 7);
  TAG001e16(8);
  jdisint(13);
  xbtimer(0, 1, 112, TAG001e50);
  jdisint(13);
//0021604e5e                     UNLK     A6
}
*/

void KeyclickOff(void) //TAG002164
{
  aReg A0;
  pnt LOCAL_4;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  LOCAL_4 = dosound(0); // Stop any existing sound
  A0 = d.Pointer23040;
   ////  d.Byte23042 = *A0; // save old keyclick state
   ////  *A0 &= 2; // keyclick off.
  dosound(LOCAL_4); // Restart sound
}

//   TAG00219a
void QueueSound(i32 soundNum,i32 mapX,i32 mapY,i32 deltaTime)
{
  dReg D0, D1, D7;
  SOUND *psA3;
  i16 LOCAL_12;
  TIMER LOCAL_10;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  if (deltaTime)
  {
    if (d.LoadedLevel != d.partyLevel) return;
  };
  psA3 = &d.sound1772[soundNum];
  if (deltaTime > 1)
  {
    D0L = d.Time;
    D0L += deltaTime & 0xffff;
    D0L--;
    D0L |= d.LoadedLevel<<24;
    LOCAL_10.timerTime = D0L;
    LOCAL_10.timerFunction = timerFunction20;
    LOCAL_10.timerUByte5 = psA3->byte4;
    LOCAL_10.timerWord8() = sw(soundNum);
    LOCAL_10.timerUByte6 = (i8)mapX;
    LOCAL_10.timerUByte7 = (i8)mapY;
    SetTimer(&LOCAL_10);
    return;
  };
  D7W = (i16)(mapX - d.partyX);
  if (D7W < 0)
  {
    D0W = (i16)-D7W;
  }
  else
  {
    D0W = D7W;
  };
  D7W = (i16)(mapY- d.partyY);
  if (D7W < 0)
  {
    D1W = (i16)-D7W;
  }
  else
  {
    D1W = D7W;
  };
  D7W = (i16)(D0W + D1W); //Total orthoganal distance
  if (D7W <= (UI8)(psA3->byte6))
  {
    LOCAL_12 = 1;
  }
  else
  {
    if (D7W >= (UI8)(psA3->byte7)) return;
    LOCAL_12 = 0;
  };
  d.Word23116++;
  if ( (d.Word23116>=88) && (d.Word23228==0) )
  {
    d.Word23116 = 0;
    d.Word8892 += 3;
    d.CacheInvalid |= 2;
    TAG02134a(d.ClusterCache + 512);
    d.Word1588 = (i16)(d.Word8892<<2);
    d.Word11752 &= d.Word1588;
  };
  if (deltaTime == 0)
  {
    StartSound(GetGraphicAddress(psA3->word0|0x8000),// Start Sound
               (UI8)(psA3->byte3),
               LOCAL_12);
    return;
  };
  if ( (d.CurrentSound!=-1) && (LOCAL_12 <= d.Word23046) )
  {
    if (LOCAL_12 == d.Word23046) return;
    D1W = (UI8)(d.sound1772[d.CurrentSound].byte4);
    D0W = (i16)(psA3->byte4 & 0xff);
    if (D0W <= D1W) return;
  };
  d.CurrentSound = sw(soundNum);
  d.Word23046 = LOCAL_12;
}

//   TAG002336
void StartQueuedSound(void)
{
  SOUND *psA3;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  Instrumentation(icntTAG002336);
  if (d.CurrentSound != -1)
  {
    psA3 = &d.sound1772[d.CurrentSound];
    StartSound(GetGraphicAddress(psA3->word0|0x8000),
               (UI8)(psA3->byte3),
                 d.Word23046);
    //playSound(psA3->word0);
    if (d.Word8892 & 1)
    {
      if (d.Word23228 == 0)
      {
        if (d.Word11724 & 4)
        {
          d.Word11724 &= 0xfffb;
          d.Word11722 &= 0xfffb;
        };
        d.Word8892++;
      };
    };
    d.CurrentSound = -1;
    d.Word23046 = 0;
  };
}

void TAG0023b0(void)
{
  //aReg A3;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  //pnt saveA3 = A3;
  d.Pointer23190 = allocateMemory(288, 1);
  d.Pointer23186 = allocateMemory(288,1);
  d.Pointer23182 = allocateMemory(256, 1);
  d.Pointer23178 = allocateMemory(256, 1);
  d.CursorBitmap = allocateMemory(432, 1);
  d.SavedCursorPixels = allocateMemory(18*24, 1);
  d.NewMouseX = 251;
  d.NewMouseY = 51;
  // kbdvbase  A3 = TAG001c8(34);

  // Set Mouse Vector to 002ef4
  //A3 = saveA3;
}

//   TAG002456
void SetCursorShape(i16 P1)
{
  dReg D0;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  STHideCursor();
  d.Word23146 = 0;
  D0W = (i16)((P1==1) ? 1 : 0);
  d.CursorShape = D0W;
  d.NewCursorShape = 1;
  STShowCursor();
}

//   TAG002480
void CreateObjectCursor(pnt P1)
{
  aReg A2, A3;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  A3 = P1;
  STHideCursor();
  d.Word23146 = 1;
  d.CursorShape = 0;
  d.NewCursorShape = 1;
  d.UseByteCoordinates = 1;
  A2 = d.Pointer23190;
  Flood(A2, 12, 36);
  ShrinkBLT(A3,
            d.SavedCursorPixels,
            16,
            16,
            16,
            16,
            d.Byte1382);
  TAG0088b2(d.SavedCursorPixels,
            A2,
            (RectPos *)d.Byte23202,
            0,
            0,
            8,
            16,
            -1);
  MemMove(A2, d.Pointer23186, 288);
  ShrinkBLT(A3,
            d.SavedCursorPixels,
            16,
            16,
            16,
            16,
            d.Byte1366);
  TAG0088b2(d.SavedCursorPixels,
            A2,
            (RectPos *)d.Byte23206,
            0,
            0,
            8,
            16,
            12);
  TAG0088b2(A3,
            d.Pointer23186,
            (RectPos *)d.Byte23206,
            0,
            0,
            8,
            16,
            12);
  STShowCursor();
}

void TAG002572(void)
{
  dReg D0;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  if (d.EmptyHanded)
  {
    if (d.HandChar == -1) // owner of cursor
    {
      D0L = 0;
    }
    else
    {
      D0L = 1;
    };
    SetCursorShape(D0W);

  }
  else
  {
    CreateObjectCursor(d.Pointer16572);
  };
}

void TAG0025a6(i32 P1)
{//(void)
  dReg D0, D4, D5, D6, D7;
  aReg A2;
  RectPos *rectPosA3;
  CHARDESC *pcA0;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  D7W = sw(P1);
  if (d.Word23144 == 0)
  {
    D0W = (i16)CharacterAtPosition((d.partyFacing+D7W) & 3);
    if (D0W == -1) return;
    d.NewCursorShape = 1;
    STHideCursor();
    d.UseByteCoordinates = 0;
    A2 = d.Pointer23182;
    Flood(A2, 12, 32);
    rectPosA3 = &d.wRectPos1454[D7W];
    TAG0088b2(d.LogicalScreenBase,
              A2,
              &d.wRectPos23214,
              rectPosA3->w.x1,
              rectPosA3->w.y1,
              160,
              16,
              0);
    ShrinkBLT(A2, A2, 32, 16,32,16,d.Byte1382);
    MemMove(A2, d.Pointer23178, 256);
    TAG0088b2(d.LogicalScreenBase,
              d.Pointer23178,
              &d.wRectPos23222,
              rectPosA3->w.x1,
              rectPosA3->w.y1,
              160,
              16,
              0);
    A2 = d.SavedCursorPixels;
    Flood(A2, 12, 32);
    TAG0088b2(d.LogicalScreenBase,
              A2,
              &d.wRectPos23222,
              rectPosA3->w.x1,
              rectPosA3->w.y1,
              160,
              16,
              0);
    ShrinkBLT(A2, A2, 32, 14, 32, 14, d.Byte1366);
    TAG0088b2(A2,
              d.Pointer23182,
              &d.wRectPos23222,
              0,
              0,
              16,
              16,
              12);
    FillRectangle(d.LogicalScreenBase,
                  rectPosA3,
                  0,
                  160);
    STShowCursor();
    d.Word23144 = (i16)(D7W + 1);
  }
  else
  {
    d.NewCursorShape = 1;
    D6W = (i16)(d.Word23144-1);
    d.Word23144 = 0;
    D4W = (i16)CharacterAtPosition((d.partyFacing + D6W) & 3);
    pcA0 = &d.CH16482[D4W];
    pcA0->facing = (i8)d.partyFacing;
    if (D6W == D7W)
    {
      pcA0 = &d.CH16482[D4W];
      pcA0->word48 |= 0x400;
      DrawCharacterState(D4W);
    }
    else
    {
      D5W = (i16)CharacterAtPosition((D7W + d.partyFacing) & 3);
      STHideCursor();
      if (D5W >= 0)
      {
        pcA0 = &d.CH16482[D5W];
        pcA0->position = ub((D6W + d.partyFacing) & 3);
        d.CH16482[D5W].word48 |= 0x400;
        DrawCharacterState(D5W);
      }
      else
      {
        FillRectangle(d.LogicalScreenBase,
                      &d.wRectPos1454[D6W],
                      0,
                      160);
      };
      d.CH16482[D4W].position = (UI8)((D7W+d.partyFacing)&3);
      d.CH16482[D4W].word48 |= 0x400;
      DrawCharacterState(D4W);
      STShowCursor();
    };
  };
}

void TAG002818(void) // called by VBL handler
{// Mouse cursor has moved out of the champion alignment area of the screen.
 // ( The upper right corner )
  dReg D6, D7;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  D6W = (i16)(d.Word23144-1);
  d.Word23144 = 0;
  if(!PlayFile.IsOpen())
  {
    MouseQueueEnt ent;
    ent.x = 0xffff;
    ent.y = 0xffff;
    ent.num = 0xffff;
    RecordFile.Record(&ent);
  };
  d.NewCursorShape = 1;
  d.Word23118++;
  if (d.Word23118 == 1)
  {
    d.Word23134 = 0;
    d.Word23130 = 0;
    d.Word23132 = 0;
    if (d.Word23136)
    {
      d.Word23136 = 0;
      RemoveCursor();
    };
  };
  D7W = d.UseByteCoordinates;
  BLT2Screen(d.Pointer23178,
             &d.wRectPos1454[D6W],
             16,
             12);
  d.UseByteCoordinates = D7W;
  d.Word23118--;
  if (d.Word23118 == 0)
  {
    d.Word23130 = 1;
    d.Word23134 = 1;
  };
}

//   TAG00289a
void RemoveCursor(void) // called by VBL handler
{ // restore area under cursor
  Instrumentation(icntRemoveCursor);
  for (i32 i=0; i<18; i++)
  {
    memmove(d.ScreenCursorAddress+160*i,
            d.SavedCursorPixels+24*i,
            24);
  };
}

void CreateCursorBitmap(void) // TAG00295e
{
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  dReg D0, D1, D4, D5, D6, D7;
  aReg A2, A3;
  //i32 saveD4=D4, saveD5=D5, saveD6=D6, saveD7=D7;
  //pnt saveA2=A2, saveA3=A3;
  pnt LOCAL_12;
  i16 LOCAL_8;
  i16 LOCAL_6;
  RectPos rect;
//  i8  LOCAL_4;
//  i8  LOCAL_3;
//  i8  LOCAL_2;
//  i8  LOCAL_1;
  Instrumentation(icntCreateCursorBitmap);
  d.Pointer23170 = d.CursorBitmap;
  LOCAL_6 = d.UseByteCoordinates;
  d.UseByteCoordinates = 1;
  D7H1 = d.CurMouseY;//Word23128;
  D7H2 = d.CurMouseX;//Word23126;
  D6H1 = D7H2;
  D6H2 = D7H1;
  d.NewCursorX = D7W;
  d.NewCursorY = D6W;
  if (d.Word23144 != 0) goto tag002ad4;
  A3 = d.Byte1222; // Arror cursor
  LOCAL_8 = 6;
  d.Word23150 = 0;
  if (D6W >= 169) goto tag0029f8;
  if (D7W >= 274) goto tag0029f8;
  if (D6W <= 28) goto tag0029ba;
  if (D7W >= 224) goto tag0029f8;
  goto tag0029e0;
tag0029ba:
  D4H2 = (i16)(D7UW / 69);
  D4H1 = (i16)(D7UW % 69);
  D5W = D4W;  // Which character
  if (D5W >= d.NumCharacter) goto tag0029e0;
  SWAP(D4); // pixel within character
  if (D4W > 42) goto tag0029e0;
  D5W++; // index to ordinal character number
  if (D5W == d.SelectedCharacterOrdinal) goto tag0029f8;
  if (D6W <= 6) goto tag0029f8;
tag0029e0:
  if (d.Word23146 != 0) goto tag002a8a;
  if (d.CursorShape == 0) goto tag0029f8;
  A3 = d.Byte1350;
  LOCAL_8 = 0;
tag0029f8:
  d.CursorHeight = 15;
  d.Word23156 = 0;
  d.Word23158 = 0;
  D7W &= 15; // x offset in word
  if (D7W == 0) goto tag002a20;
  d.CursorWidth = 2; // 32 pixels
  if (D7W > LOCAL_8) goto tag002a2e;
  d.CursorWidth = 1; // 16 pixels
  goto tag002a2e;
tag002a20:
  d.CursorWidth = 1; // 16 pixels
  d.Pointer23170 = A3;
  goto tag002c8c;
tag002a2e:
  D0W = (i16)(d.CursorWidth << 4); // convert to pixels
  Flood(d.CursorBitmap,12,D0W); // Flood with color 12
  D0 = D7; // 1st pixel offset within word
  rect.b.x1 = D0UB; // first pixel x
  D0W = (i16)((D0W & 0xff) + 15); // last pixel x
  rect.b.x2 = D0UB; // last pixel x
  rect.b.y1 = 0;
  rect.b.y2 = 15;
  TAG0088b2(A3,              // src
            d.CursorBitmap,  // dst
            &rect,           // rectPos
            0,               // srcXOffset
            0,               // srcYOffset
            8,               // src bytes/line
            (d.CursorWidth<<3), // dst bytes/line = pixels/2
            -1);
  goto tag002c8c;
tag002a8a:
  d.Word23150 = 1;
  d.CursorHeight = 17;
  d.CursorWidth = 2; // 32 pixels
  d.Word23156 = 8;
  d.Word23158 = 8;
  D5L = 18;
  D4L = 17;
  A3 = d.Pointer23190;
  A2 = d.Pointer23186;
  LOCAL_12 = A2;
  D7W = (i16)((D7W - 8) & 15);
  if (D7W != 15) goto tag002aca;
  d.CursorWidth = 3; // 48 pixels
tag002aca:
  D6W -= 19;
  if (D6W <= 0) goto tag002c24;
  goto tag002b1c;
tag002ad4:
  d.CursorHeight = 15;
  d.CursorWidth = 2; // 16 pixels
  d.Word23156 = 9;
  d.Word23158 = 7;
  D5W = 16;
  D4W = 20;
  A3 = d.Pointer23182;
  A2 = d.Pointer23178;
  LOCAL_12 = A2;
  D7W = (I16)((D7W - 9) & 15);
  if (D7W < 12) goto tag002b14;
  d.CursorWidth = 3; // 48 pixels
tag002b14:
  D6W -= 20;
  if (D6W <= 0) goto tag002c24;
tag002b1c:
  if (d.DynamicPaletteSwitching == 0) goto tag002c24;
  if (D6W < D5W) goto tag002b30;
  LOCAL_12 = A3;
  goto tag002c24;
tag002b30:
  D0 = D7;
  if (D0W != 0) goto tag002b86;
  D7W = D5W;
  D1 = D6;
  D7W = sw((D7W - D1W) << 4);
  D7L &= 0xffff;
  D0 = D7;
  MemMove(A2, d.CursorBitmap, D0W);
  {
    i16 num = sw(D6W<<4);
    pnt dst = d.CursorBitmap + D7UW;
    pnt src = A3 + D7UW;
    MemMove(src,dst,num);
  };
  goto tag002c22;
tag002b86:
  D0L = d.CursorWidth * D5UW;
  Flood(d.CursorBitmap,12,D0W); // Flood with color 12
  D0W = D5W;
  D1 = D6;
  D0W = sw(D0W - D1W);
  D0L &= 0xffff;
  D6 = D0;
  D0 = D7;
  rect.b.x1 = D0UB;
  D0W &= 0xff;
  D0W = sw(D0W + D4W);
  rect.b.x2 = D0B;
  rect.b.y1 = 0;
  D0 = D6;
  D0W--;
  rect.b.y2 = D0B;
  TAG0088b2(A2,d.CursorBitmap,&rect,0,0,16,d.CursorWidth<<3,-1);
  D0 = D6;
  rect.b.y1 = D0B;
  D0W = D5W;
  D0W--;
  rect.b.y2 = D0B;
  TAG0088b2(A3,d.CursorBitmap,&rect,0,D6W,16,d.CursorWidth<<3,-1);
tag002c22:
  goto tag002c8c;
tag002c24:
  D0 = D7;
  if (D0W != 0) goto tag002c32;
  d.Pointer23170 = LOCAL_12;
  goto tag002c8c;
tag002c32:
  D0 = D7;
  rect.b.x1 = D0B;
  D0W &= 0xff;
  D0W = sw(D0W + D4W);
  rect.b.x2 = D0B;
  rect.b.y1 = 0;
  D0W = sw(D5W - 1);
  rect.b.y2 = D0B;
  D0W = sw(d.CursorWidth * (ui16)D5W);
  Flood(d.CursorBitmap,12,D0W); // Flood with color 12 = transparent
  TAG0088b2(LOCAL_12,d.CursorBitmap,&rect,0,0,16,d.CursorWidth<<3,-1);
tag002c8c:
  d.UseByteCoordinates = LOCAL_6;
  //D4=saveD4;D5=saveD5;D6=saveD6;D7=saveD7;
  //A2=saveA2;A3=saveA3;
}


//*********************************************************
//
//*********************************************************
//   TAG002c9a
void DrawCursor(void) // called by VBL handler
{
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  dReg D0,D1,D2,D3,D4,D5,D6,D7;
  pnt A0,A1,A2;
  Instrumentation(icntPlaceCursor);
  d.Word23136 = 1;

  D6W = d.NewCursorX;
  D7W = d.NewCursorY;
  if (!PlayFile.IsOpen())
  {
    d.CurCursorX = D6W;
    d.CurCursorY = D7W;
  };
  D2L = 0; // Left of screen Flag
  D6W = sw(D6W - d.Word23156);
  if (D6W < 0)
  {
    D6L = 0;
    D1L = 0;
    D2L = 1; // Left of screen flag
    goto tag002cd6;
  };
  if (D6W >= 272) // Room for widest cursor = 48 pixels
  {
    D1L = 136;  // The last 24 bytes on the line
  }
  else
  {
    D1W = D6W;
tag002cd6:
    D1W = (I16)((D1W >> 1) & 0x7ff8);
  };
    SWAP(D2);
    D7W = sw(D7W - d.Word23158);
  if (D7W < 0)
  {
    D2W = sw(-D7W);
    D7W = 0;
  }
  else
  {
    if (D7W >= 182)
    {
      D1W +=29120;
    }
    else
    {
      D0W = sw(D7W << 5);
      D1W = sw(D1W + D0W);
      D0W = sw(D0W + D0W);
      D0W = sw(D0W + D0W);
      D1W = sw(D1W + D0W); // D1 += 160*D7W;
    };
  };
  A2 = (pnt)D2L; // save flag
  A0 = d.LogicalScreenBase + D1W;
  d.ScreenCursorAddress = A0;
  A1 = d.SavedCursorPixels;
  for (i32 ii=0; ii<18; ii++)
  { // save pixels under cursor
    memmove(A1+24*ii,A0+160*ii,24);
  };
  D0W = d.CursorHeight;
  D1W = d.CursorWidth;
  A1 =  d.Pointer23170; // CurCursorBitmap
  D2W = (i16)A2;
  if (D2W != 0)
  {
    D0W = sw(D0W - D2W);
    D2L = D2UW * D1UW;
    D2W <<= 3;
    A1 += D2W;
  }
  else
  {
    // CursorHeight + cursorY - 200
    D3W = sw(D0W + D7W - 200); //
    if (D3W >= 0) // if partly offscreen
    {
      D0W = sw(D0W - D3W); // reduce height to fit
    };
  };
  D2L = (i32)A2;
  SWAP(D2);
  if (D2W != 0) // if left of screen
  {
tag002df8:
    D1W -= 2;
    if (D1W == 0)
    {
      A2 = (pnt)0x002eb2;
      D5W = 152;
      goto tag002e42;
    };
    A2 = (pnt)0x002e86;
    D5W = 144;
    goto tag002e42;
  }
  else
  {
    // cursorWidth + cursorX - 336
    // Assme offset might be as great as 15
    D3W = sw((D1W<<4)+D6W-336);
    // D3W = how far it spills over the right margin
    if (D3W >= 0)
    {
      A1 -= 8; //
      goto tag002df8;
    };
    D1W -= 2;
    if (D1W < 0)
    {
      A2 = (pnt)0x002eb4;
      D5W = 152;
      goto tag002e42;
    }
    else
    {
      if (D1W == 0)
      {
        A2 = (pnt)0x002e88;
        D5W = 144;
        goto tag002e42;
      };
      A2 = (pnt)0x002e5c;
      D5W = 136;
    };
  };
tag002e42:
  D6W = (I16)((D6W >> 1)&0x7ff8);
  D7W <<= 5;
  D6W = sw(D6W + D7W);
  D7W = sw(D7W + D7W);
  D7W = sw(D7W + D7W);
  D6W = sw(D6W + D7W); // D6W += 5*(D7W*32);
  A0 = d.LogicalScreenBase + D6W;
  D7W = D0W;

tag002e5a:
  switch((i32)A2)
  {
  case 0x002e5c: goto tag002e5c;
  case 0x002e86: goto tag002e86;
  case 0x002e88: goto tag002e88;
  case 0x002eb4: goto tag002eb4;
  case 0x002eb2: goto tag002eb2;
  default: NotImplemented(0x2e5a);
  };
tag002e5c:
  D0W = LE16(wordGear(A1+0));
  D1W = LE16(wordGear(A1+2));
  D2W = LE16(wordGear(A1+4));
  D3W = LE16(wordGear(A1+6));
  D4W = (UI16)(((D2W & D3W) ^ 0xffff) | D0W | D1W);
  //SWAP(D0);
  D0H1 = D0H2;
  D0W = D1W;
  //SWAP(D2);
  D2H1 = D2H2;
  D2W = D3W;
  D3W = D4W;
  //SWAP(D4);
  D4H1 = D4H2;
  D4W = D3W;
  D0L &= D4L;
  D2L &= D4L;
  D4L ^= 0xffffffff;
  longGear(A0) &= LE32(D4L);
  longGear(A0) |= LE32(D0L);
  A0 += 4;
  longGear(A0) &= LE32(D4L);
  longGear(A0) |= LE32(D2L);
  A0 += 4;
tag002e86:
  A1 += 8;
tag002e88:
  D0W = LE16(wordGear(A1));
  D1W = LE16(wordGear(A1+2));
  D2W = LE16(wordGear(A1+4));
  D3W = LE16(wordGear(A1+6)); // 16 pixels colors D3->D0
  D4W = (UI16)(((D2W & D3W)^0xffff)|D0W|D1W); //0 where color=12 (transparent)
  //SWAP(D0); //D0 = (D0UW&0xffff)|((D0W&0xffff)<<16);
  D0H1 = D0H2;
  D0W = D1W;
  //SWAP(D2); //D2 = (D2U&0xffff)|((D2W&0xffff)<<16);
  D2H1 = D2H2;
  D2W = D3W;
  D3W = D4W;
  //SWAP(D4); //D4 = (D4U&0xffff)|((D4W&0xffff)<<16);
  D4H1 = D4H2;
  D4W = D3W;
  D0L &= D4L;
  D2L &= D4L;
  D4L ^= -1;
  wordGear(A0+0) &= LE16(D4H1);
  wordGear(A0+2) &= LE16(D4H2);
  wordGear(A0+0) |= LE16(D0H1);
  wordGear(A0+2) |= LE16(D0H2);
  A0 += 4;
  wordGear(A0+0) &= LE16(D4H1);
  wordGear(A0+2) &= LE16(D4H2);
  wordGear(A0+0) |= LE16(D2H1);
  wordGear(A0+2) |= LE16(D2H2);
  A0 +=4;
tag002eb2:
  A1 += 8;
tag002eb4:
  D0W = LE16(wordGear(A1));
  D1W = LE16(wordGear(A1+2));
  D2W = LE16(wordGear(A1+4));
  D3W = LE16(wordGear(A1+6));
  A1 += 8;
  D4W = (UI16)(((D2W & D3W) ^ 0xffff)|D0W|D1W);
  //SWAP(D0); // = (D0UW&0xffff)|((D0W&0xffff)<<16);
  D0H1 = D0H2;
  D0W = D1W;
  D2H1 = D2W;
  D2W = D3W;
  D3W = D4W;
  D4H1 = D4W;
  D4W = D3W;
  D2L &= D4L;
  D0L &= D4L;
  D4L ^= -1;
  wordGear(A0+0) &= LE16(D4H1);
  wordGear(A0+2) &= LE16(D4W);
  wordGear(A0+0) |= LE16(D0H1);
  wordGear(A0+2) |= LE16(D0W);
  A0 += 4;
  wordGear(A0+0) &= LE16(D4H1);
  wordGear(A0+2) &= LE16(D4W);
  wordGear(A0+0) |= LE16(D2H1);
  wordGear(A0+2) |= LE16(D2W);
  A0 += 4;
  A0 += D5W;
  D7W--;
  if (D7W >= 0)  goto tag002e5a;
}


void TAG00306c(void)
{
  NotImplemented(0x306c);
}

/*
void TAG0030e6(i32 divisor,
               i32 dividend,
               i32 *quotient,
               i32 *remainder)
{
  dReg D0, D1, D2, D3;
  i32 LOCAL_2;
  i32 carry;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  D2L = divisor;
  if (divisor == 0)
  if (quotient != NULL) *quotient = 0;
  if (remainder != NULL) *remainder = 0;
  return;
  D1L = dividend;
  LOCAL_2 = 0;
  if (D1L < 0)
  {
    LOCAL_2 += 3;
    D1L = -D1L;
  };
//003110 4a2                     TST.L    D2
  if (D2L < 0)
  {
    LOCAL_2 += 1;
    D2L = -D2L;
  };
  D3L = 1;
  for (;;)
  {
    if (D2L >= D1L) break;
    D2L <<= 1;
    D3L <<= 1;
  };
  D0L = 0;
  do
  {
    if (D2L <= D1L)
    {
      D0L |= D3L;
      D1L -= D2L;
    };
    D2L >>= 1;
    carry = D3L & 1;
    D3L >>= 1;
  } while (carry==0);
  while (carry==0);
  if (LOCAL_2>=3)
  {
    D1L = -D1L;
  };
  if (D2L & 1)
  {
    D0L = -D0L;
  };
  if (quotient != NULL) *quotient = D0L;
  if (remainder != NULL) *remainder = D1L;
}
*/

void MoveWords(aReg& A0, aReg A1, i32 numM1) // 0031c4
{ // Uses A0, A1, and D0
  // Move D0+1 words from (A1) to (A0) and increment A0
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
//  dReg D0;
//  aReg A0, A1;
  //pnt saveA1=A1;
  memcpy (A0, A1, 2*(numM1+1));
  A0 += 2*(numM1+1);

  //while (numM1 >= 0)
  //{
  //  wordGear(A0) = wordGear(A1);
  //  A0 += 2;
  //  A1 += 2;
  //  numM1--;
  //}
  //A1 = saveA1;
}


/*
//   TAG0031d6
void SearchWordNE(dReg *D0,i16 **A0,i16 *A1)
{ // Search two word strings for 'Not Equal'. Update D0, A0
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  do
  {
    if (*((*A0)++) != *(A1++)) break;
  } while (--(D0->W) != -1);
}
*/


//  TAG0031e8
pnt StrCat(pnt msg1, pnt msg2)
{
  aReg A2, A3;
  pnt LOCAL_4;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  A3 = msg1;
  A2 = msg2;
  LOCAL_4 = A3;
  while ( *(A3++) != 0) {};
  A3--;
  while ( (*(A3++) = *(A2++)) != 0) {};
  return LOCAL_4;
}

//  TAG003222
i16 StrCmp(pnt s1, pnt s2)
{
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  while ( (*s1!=0) && (*s1 ==*s2))
  {
    s1++;
    s2++;
  };
//
//

  return sw((UI8)(*s1) - (UI8)(*s2));
}


//  TAG00327c
pnt StrCpy(pnt dest, pnt src, i16 maxChar)
{
  dReg D0, D7;
  aReg A2, A3;
  pnt LOCAL_4;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  A3 = dest;
  A2 = src;
  D7W = maxChar;
  LOCAL_4 = A3;
  do
  {
    D0W = D7W;
    D7W--;
    if (D0B == 0) break;
    D0B = *(A2++);
    *(A3++) = D0B;
  } while (D0B != 0);
  return LOCAL_4;

}

//  TAG0032ba
i16 StrLen(pnt string)
{
  aReg A2, A3;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  A3 = string;
  A2 = A3;
  while (*A3 != 0)
  {
    A3++;
  };
  return sw(A3-A2);
}

//  TAG0032e4
pnt StrChr(pnt P1,i16 P2)
{ // Find character in string.  Returns address or NULL
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  dReg D0, D6, D7;
  aReg A3;
  A3 = P1;
  D7W = P2;
  goto tag0032fa;
tag0032f8:
  A3 += 1;
tag0032fa:
  D0B = *A3;
  D6B = D0B;
  if (D6B == 0) goto tag00330c;
  D0W = D6UB;
  if (D0W != D7W) goto tag0032f8;
tag00330c:
  D0B = D6B;
  if (D0B == 0) goto tag003318;
  return A3;
tag003318:
  return NULL;
}
//*********************************************************
//
//*********************************************************
//   TAG003796
void ModifyPalettes(i32 whichColor,i32 P2)
{
  dReg D0, D5, D6;
  //D7W = whichColor;
  D6W = sw(P2);
  for (D5W=0; D5W<6; D5W++)
  {
    D0W = LE16(d.Word6596[D6W][D5W]);
    ASSERT(D0W <= 0x777);
    d.Palette552[D5W].color[whichColor] = D0W;
//
  };
  D0W = d.Word6596[D6W][6]; // first byte
  d.Byte6628[whichColor] = D0B;
  //D0B = d.Word6596[D6W][6]; // least significant byte
  d.Byte6612[whichColor] = sb(D0W>>8);

}

//   TAG00381a
void ReadFloorAndCeilingBitmaps(i16 P1)
{
  if (P1 != d.CurrentFloorAndCeilingGraphic)
  {
    d.CurrentFloorAndCeilingGraphic = P1;
    ReadAndExpandGraphic(P1 * 2 + 75, d.pFloorBitmap, 0,0);
    ReadAndExpandGraphic(P1 * 2 + 76, d.pCeilingBitmap, 0,0);
  };
}

//   TAG00386a
void ReadWallBitmaps(i16 newWallGraphicSet)
{
  int i;
  int firstWallGraphic;
  if ( (newWallGraphicSet != d.CurrentWallGraphic) || (d.PartyHasDied != 0) )
  {
    d.CurrentWallGraphic = newWallGraphicSet;
    firstWallGraphic = sw(77 + 13 * newWallGraphicSet);
    for (i=0; i<13; i++)
    {
      ReadAndExpandGraphic(firstWallGraphic + i, d.pWallBitmaps[i], 0, 0);
    };

    MakeMirror(d.pWallBitmaps[1],
               d.Pointer2142,
               (UI8)(d.Byte3134),
               (UI8)(d.Byte3133));
    MakeMirror(d.pWallBitmaps[12],
               d.Pointer2086,
               (UI8)(d.Byte2978[4]),
               (UI8)(d.Byte2978[5]));
  };
}
//*********************************************************
//
//*********************************************************
//   TAG0042da
void MarkViewportUpdated(i16 MultiplePalettes)
{ //(void)
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  if (MultiplePalettes == 2)
  {
    d.Word11740 = d.DynamicPaletteSwitching;
  }
  else
  {
    //if ((MultiplePalettes==0) && (d.Word11740!=0))
    //  memmove((pnt)palette,(pnt)&d.Palette11978,32);
    d.Word11740 = MultiplePalettes;
  };
  d.ViewportUpdated = 1; //Force VBL to copy Viewport to Screen
  vblInterrupt();// No increment of VBLCount!//wvbl(_1_);
}

void MakeMirror(pnt src, pnt dst, i16 width, i16 height) //TAG00434a
{
  dReg D0;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  D0L = (ui16)width * (ui16)height;
  MemMove(src,dst,D0W);
  Mirror(dst,width,height);
}


void TAG00437e(pnt P1,RectPos *P2)
{
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  dReg D0;
//  aReg A3;
  // A3 = P2;
  ASSERT(verifyRectPos(P2));
  D0W = (UI8)(P2->b.uByte4);
  if (D0B != 0)
  {
    TAG0088b2(P1,
              d.pViewportBMP,
              P2,
              (UI8)(P2->b.uByte6),
              (UI8)(P2->b.uByte7),
              (UI8)(P2->b.uByte4),
              112,
              10);
  };
}

void TAG0043c4(pnt src,RectPos *P2)
{
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  //pnt A3;
  //A3 = P2;
  ASSERT(verifyRectPos(P2));
  if (P2->b.uByte4 != 0)
  {
    TAG0088b2(src,
              d.pViewportBMP,
              P2,
              (UI8)(P2->b.uByte6),
              (UI8)(P2->b.uByte7),
              (UI8)(P2->b.uByte4),
              112,
              -1);
  };
}

//*********************************************************
//
//*********************************************************
void TAG00440a(pnt P1)
{
  aReg A3;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  A3 = P1;
  if (A3[4] == 0) return;
  TAG0088b2(d.Pointer1848,
            d.pViewportBMP,
            (RectPos *)A3,
            (UI8)(A3[6]),
            (UI8)(A3[7]),
            (UI8)(A3[4]),
            112,
            10);
}

//*********************************************************
//
//*********************************************************
void TAG004450(pnt P1,pnt P2)
{
  aReg A3;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  A3 = P2;
  if (A3[4] == 0) return;
  Mirror(P1,
         (UI8)(A3[4]),
         (UI8)(A3[5]) );
  TAG0088b2(P1,
            d.pViewportBMP,
            (RectPos *)A3,
            (UI8)(A3[6]),
            (UI8)(A3[7]),
            (UI8)(A3[4]),
            112,
            10);
}

void TAG0044b0(i32 P1,RectPos *rect)
{
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  ASSERT(verifyRectPos(rect));
  if (rect->b.uByte4 == 0) return;



  TAG0088b2( GetGraphicAddress(P1),
             d.pViewportBMP,
             rect,
             rect->b.uByte6,
             rect->b.uByte7,
             rect->b.uByte4,
             112,
             10);
}

void TAG0044fe(i32 graphic, RectPos *rectpos)
{
  ASSERT(verifyRectPos(rectpos));
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  if (rectpos->b.uByte4 == 0) return;
  MakeMirror(GetGraphicAddress(graphic),
             d.Pointer1848,
             rectpos->b.uByte4,
             rectpos->b.uByte5);
  TAG0088b2(d.Pointer1848,
            d.pViewportBMP,
            rectpos,
            rectpos->b.uByte6,
            rectpos->b.uByte7,
            rectpos->b.uByte4,
            112,
            10);
}

void TAG00456c(void)
{
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  if ((ui16)d.Word1842 < 5)
  {
    if (d.Word1870 == 0)
    {
      if (d.Word23228 == 0)
      {
        if ((d.Word11722 & 1) == 0)
        {
          d.Word11722 |= 1;
          d.Word1842++;
        };
      };
      d.Word11724 &= 0xfffe;
      d.Word1836 = 15;
      d.Word1870 = 1;
    };
  };
}

//  TAG0045ae
i16 DrawWallDecoration(i16 P1,i16 P2)
{//We also draw wall text.
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  dReg D0, D1, D3, D4, D5, D6, D7;
  aReg A0, A2, A3;
  i8  LOCAL_92[70];
  ui8 LOCAL_22[8];
  i16 LOCAL_14;
  i16 LOCAL_12;
  bool drawingText;// LOCAL_10;
  i16 LOCAL_8;
  i16 LOCAL_6;
  pnt LOCAL_4;
  bool bD0;
  int srcByteWidth;
  D7W = P1; // Graphic ordinal for this level.
  D6W = P2;
  if (D7W == 0) return 0;
  D7W--;
  D5W = d.Word2382[D7W][0];
  D4W = d.Word2382[D7W][1];
  D1L = 78 * D4W;
  A3 = d.Byte4836 + D1L + 6*D6W;
  LOCAL_12 = IsAlcove(D7W);//if D7W one of three special??
  drawingText = (D7W == d.NumWallDecoration);
  if (drawingText)
  {
    DecodeText(LOCAL_92, 
               GetRecordAddressDB2(d.rn10540), 
               0, 
               70);
  };
  TAG00456c();
  if (D6W >= 10)
  {
    if (D6W == 12) //Wall immediately in front of party
    {
      if (drawingText) 
      {
         TAG0088b2(d.pWallBitmaps[9],  // src
                  d.pViewportBMP, // dst
                  (RectPos *)d.Byte4192,     // 0x00,0x4a,0x14,0x5a
                  94,             // src x
                  28,             // src y
                  d.uByte3026[4], // src byte width
                  112,            // dst byte width
                  -1);
          A3 = LOCAL_92;
          LOCAL_4 = GetGraphicAddress(120);
          LOCAL_14 = 0;
        do
        {
          int i, lineLength;
          lineLength = 0;
          A2 = A3;
          while ((UI8)(*(A2++)) < 128) lineLength++; //Count characters in this line
          if (lineLength > 18) lineLength = 18;
          LOCAL_22[0] = ub(112 - 4*lineLength);
          LOCAL_22[1] = ub(LOCAL_22[0] + 7);
          LOCAL_22[3] = ub(*(d.Byte4196+(LOCAL_14++)));
          LOCAL_22[2] = ub(LOCAL_22[3] - 7);
          for (i=0; i<lineLength; i++)
          {
            TAG0088b2(LOCAL_4,
                      d.pViewportBMP,
                      (RectPos*)LOCAL_22,
                      8*(UI8)(*(A3++)),
                      0,
                      144,
                      112,
                      10);
            LOCAL_22[0]+=8;
            LOCAL_22[1]+=8;
          };
          A3 = A2 - 1; //Go to terminator at end of line.
        } while ((UI8)(*(A3++)) != 129);
        return LOCAL_12;
      }; //if (LOCAL_10 != 0)
      D5W++;
      MemMove(A3, (pnt)d.ViewportObjectButtons[5], 4); // ?????
      d.FacingAlcove = LOCAL_12;
      d.Word10534 = (d.Word1870!=0) && (D7W==d.Word10404);
      d.Word10536 = 0;
      for (D4W=0; D4W<1; D4W++)
      {
        D0W = d.Word10412[D4W];
        if (D7W == D0W)
        {
          d.Word10536 = 1;
          break;
        };

      };
    };
    A2 = GetGraphicAddress(D5W); // Get graphic bitmap address
    if (D6W == 11)
    {
      MakeMirror(A2,
                 d.Pointer1848,
                 (UI8)(*(A3+4)),
                 (UI8)(*(A3+5)));
      A2 = d.Pointer1848;
    };
    D4W = 0;
  }
  else
  {
    LOCAL_6 = 0;
    bD0 = D6W == 6;
    if (!bD0)
    {
      bD0 = D6W == 1;
    };
    LOCAL_8 = bD0;
    if (LOCAL_8 != 0)
    {
      A2 = (d.Byte4776 + 6) +78*D4W;
    }
    else
    {
      if ( (D6W==5) || (D6W==0) )
      {
        A2 = d.Byte4776 + 78*D4W;
      }
      else
      {
        D5W++;
        A2 = (d.Byte4776 + 12) + 78*D4W;
        if (D6W == 7)
        {
          LOCAL_6 = 6;
        }
        else
        {
          if (D6W == 9)
          {
            LOCAL_6 = -6;
          };
        };
      };
    };
    A0 = A3 + LOCAL_6;
    D4W = ((ui8 *)(A0))[1]; //right edge
    A0 = A3 + LOCAL_6;
    D3W = ((ui8 *)A0)[0];  //left edge
    D4W = sw(D4W - D3W);   //width
    D0W = sw(4*D7W + 4);   
    A0 = d.Byte4024 + D6W; 
    D3W = (UI8)(A0[0]);
    D0W = sw(D0W + D3W);
    D7W = D0W;
    D0W = TAG022c90(D7W);
    if (D0W == 0)
    {
      LOCAL_4 = GetGraphicAddress(D5W);
      if (D6W <= 4)
      {
        A0 = d.Byte4140;
      }
      else
      {
        A0 = d.Byte4156;
      };
//
//
//
//
//
      ShrinkBLT(LOCAL_4,
                TAG022d38(D7W),
                2*(UI8)(A2[4]),
                (UI8)(A2[5]),
                D4W+1,
                (UI8)(A3[5]),
                A0);
      TAG022d5e(D7W);
    };
    A2 = TAG022d38(D7W); //Graphic address
    if (LOCAL_8 != 0)
    {
      MakeMirror(A2,d.Pointer1848,(UI8)(A3[4]),(UI8)(A3[5]));
      A2 = d.Pointer1848;
      D4W = (I16)(15 - (D4W&15));
    }
    else
    {
      if (D6W == 7)
      {
        D0W = (UI8)(A3[1]);
        D3W = (UI8)(A3[0]);
        D0W = sw(D0W - D3W);
        D4W = sw(D4W - D0W);
      }
      else
      {
        D4W = 0;
      };
    };
  };
  if (drawingText)
  {
    LOCAL_4 = A3;  //RECTPOS
    A3 = LOCAL_92; //The text
    D5W = 0;
    do
    {
      while ((UI8)(*A3) < 128) A3++; //Find End-of-line


      D5W++; //Count lines
    } while ((UI8)(*(A3++)) != 129); //Find End-of-text
//    if (TimerTraceActive)
//    {
//      fprintf(GETFILE(TraceFile),
//        "A3->{%x,%x,%x,%x,%x,%x,%x,%x}"
//        "Byte4204=%x",
//        (UI8)
//
//    };
    A3 = LOCAL_4; //RECTPOS
    if (D5W < 4)
    {
      MemMove(A3, (pnt)LOCAL_22, 8); //Why 8?
      A3 = (pnt)LOCAL_22; //Local copy of RECTPOS + 2 bytes
      A0 = d.Byte4024; //0,0,1,1,1,2,2,3,3,3,4,4
      D0L = 3*((UI8)(*(A0+D6W)));//Try adding D6W. Seems Reasonable
      D0W = sw(D0W + D5W);
      A0 = d.Byte4213 + D0W;
      *(A3+3) = *A0;
    };
  };
  //
  // We are going to attempt to fix a problem.
  // The wall decoration 'EVIL-OUTSIDE' appears to have
  // the wrong byteWidth in graphic 0x22e.  The table
  // entry says the graphic is 48 bytes wide but it 
  // is not....it is 40 bytes wide.  So we will fix
  // that here in the runtime.  Yuk!
  {
    srcByteWidth = (UI8)(A3[4]);
    if (   (A3 - d.Byte4836 == 0x234)
         &&((UI8)(A3[0]) == 0x4a)
         &&((UI8)(A3[1]) == 0x95)
         &&((UI8)(A3[2]) == 0x19)
         &&((UI8)(A3[3]) == 0x4b)
         &&(srcByteWidth == 48)
      )
    {
      srcByteWidth = 40;
    };
  };
  // Hopefully we have broken nothing.  We will see.
  //
  if (TimerTraceActive)
  {
    fprintf(GETFILE(TraceFile),
      "Drawing decoration\n");
    fprintf(GETFILE(TraceFile),
      "A3 -> %x,%x,%x,%x D4=%x srcByteWidth=%x\n",
      (UI8)(A3[0]),(UI8)(A3[1]),(UI8)(A3[2]),(UI8)(A3[3]),
      D4W, srcByteWidth);
  };
  TAG0088b2(A2,  // Pictureframe appears
            d.pViewportBMP,
            (RectPos *)A3, //0x50,0x8f,0x1d,0x47
            D4W,
            0,
            srcByteWidth,
            112,
            10);
  if (D6W == 12)
  {
    D0W = d.Word10538;
    d.Word10538--;
    if (D0W != 0)
    {
    TAG0088b2(GetGraphicAddress(26),  // Draws portrait
              d.pViewportBMP,
              (RectPos *)d.Byte2546, //0x60,0x7f,0x23,0x3f
              (d.Word10538&7)<<5,
              29 * BITS3_15(d.Word10538),
              128,
              112,
              1);
    };
  }
  return LOCAL_12;
}

void TAG004a1a(i16 P1,i16 P2)
{
  dReg D0, D3;
  aReg A0;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  dReg D1, D4, D5, D6, D7;
  aReg A2,A3;
  D7W = P1;
  D6W = P2;
  if (D7W == 0) return;
  D4W = (UI16)(D7W & 0x8000);
  if (  (D4W == 0)
      ||((D7W = (I16)(D7W&0x7fff)) !=0)) // Seems silly
  {
    D7W -= 1;
    D5W = sw(D7W << 2);
    A0 = &d.Byte2446 + D5W;
    D5W = wordGear(A0);
    D1W = D6W;
    A0 = d.Byte4034 + D1W;
    D3W = (UI8)(*A0);
    D5W = sw(D5W + D3W);
    D0W = D6W;
    D1W = sw(D7W << 2);
    A0 = &d.Byte2446 + D1W + 2;
    D1W = wordGear(A0);
    D1L = 54*D1W;
    A0 = d.Byte4998;
    D1L += (i32)A0;
    D0L = 6*D0W;
    A2 = A0 = (pnt)(D1L + D0W);
    if (D6W == 8) goto tag004ab6;
    if (D6W == 5) goto tag004ab6;
    if (D6W == 2) goto tag004ab6;
    if (D7W != 15) goto tag004ae2;
    if (d.UseMirrorImages == 0) goto tag004ae2;
    if (D6W == 7) goto tag004ab6;
    if (D6W == 4) goto tag004ab6;
    if (D6W == 1) goto tag004ae2;
tag004ab6:
    D0W = 0;
    D0B = *(A2+5);
    MakeMirror(GetGraphicAddress(D5W),
               A3 = d.Pointer1848,      // Temp Viewport BMP
               (UI8)(A2[4]),               // Width
               D0W );                  // height
    goto tag004aec;
tag004ae2:
    A3 = GetGraphicAddress(D5W);
tag004aec:
    TAG0088b2(A3,
              d.pViewportBMP,
              (RectPos *)A2,
              0,
              0,
              (UI8)(A2[4]),
              112,
              10);
  };
  if (D4W != 0)
  {
    TAG004a1a(16, D6W);
  };
}

//*********************************************************
//
//*********************************************************
void TAG004b26(i32 P1, i32 P2)
{
  dReg D0, D1, D4, D5, D6, D7;
  aReg A0, A2, A3;
  pnt pnt_4;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  D7W = sw(P1);
  D6W = sw(P2);
  if (D7W == 0) return;
  D7W--;
  //D5W = wordGear(d.Byte2514 + 4*D7W);
  D5W = d.Word2514[D7W][0];
  //D4W = wordGear(d.Byte2512 + 4*D7W);
  D4W = d.Word2514[D7W][1];
  D1L = 18 * D4W;
  A3 = d.Byte5070 + 18*D4W + 6*D6W;
  if (D6W == 2)
  {
    A2 = GetGraphicAddress(D5W);
    D6W = 48;
  }
  else
  {
    D7W = sw(2*D7W + 68 + D6W);
    D0W = TAG022c90(D7W);
    if (D0W == 0)
    {
      ASSERT(D4W < 4);
      A2 = &d.Byte5058[18*D4W];
      pnt_4 = GetGraphicAddress(D5W);
      if (D6W == 0)
      {
        A0 = d.Byte4172;
      }
      else
      {
        A0 = d.Byte4188;
      };
      ShrinkBLT(pnt_4,
                TAG022d38(D7W),
                2*(UI8)(A2[4]),
                (UI8)(A2[5]),
                (UI8)(A3[1]) - (UI8)(A3[0]) + 1,
                (UI8)(A3[5]),
                A0);
      TAG022d5e(D7W);
    };
    A2 = TAG022d38(D7W);
    if (D6W == 0)
    {
      D6W = 24;
    }
    else
    {
      D6W = 32;
    };
  };
  TAG0088b2(A2,
            d.Pointer1848,
            (RectPos *)A3,
            0,
            0,
            (UI8)(A3[4]),
            D6W,
            9);
}

//*********************************************************
//
//*********************************************************
//   TAG004c5e
void DrawDoorSwitch(i16 P1, i16 P2)
{
  dReg D0, D1, D4, D5, D6, D7;
  aReg A0, A2, A3;
  pnt pnt_4;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  D7W = P1;
  D6W = P2;
  if (D7W == 0) return;
  D7W -= 1;
  D5W = sw(D7W + 315);
  D4W = (UI8)(d.Byte4124[D7W]);
  A3 = d.Byte5094 + 24*D4W + 6*D6W;
  if (D6W == 3)
  {
    A2 = GetGraphicAddress(D5W);
    MemMove(A3, (pnt)d.ViewportObjectButtons[5], 4);
  }
  else
  {
    D0W = sw(2*D7W + 102);
    if (D6W == 0)
    {
      D1W = 0;
    }
    else
    {
      D1W = sw(D6W - 1);
    };
    D7W = sw(D0W + D1W);
    D0W = TAG022c90(D7W);
    if (D0W == 0)
    {
      A2 = d.Byte5076 + 24*D4W;
      pnt_4 = GetGraphicAddress(D5W);
      if (D6W == 2)
      {
        A0 = d.Byte4156;
      }
      else
      {
        A0 = d.Byte4140;
      };
      ShrinkBLT(pnt_4,
                TAG022d38(D7W),
                2*(UI8)(A2[4]),
                (UI8)A2[5],
                (UI8)A3[1]-(UI8)A3[0]+1,
                (UI8)A3[5],
                A0);
      TAG022d5e(D7W);
    };
    A2 = TAG022d38(D7W);
  };
  TAG0088b2(A2,
            d.pViewportBMP,
            (RectPos *)A3,
            0,
            0,
            (UI8)(A3[4]),
            112,
            10);
}

//*********************************************************
// We got here when we saw a smashed door???
//*********************************************************
//   TAG004d9e
void DrawDoor(i16 index, //8
               i16 P2,    //10 //From roomData.decorations[0]?
               i16 *P3,   //12 //Two words?? Indexed by type??
               i16 P4,    //16
               i16 P5,    //18
               pnt P6)    //20
{
  dReg D0, D7;
  int doorType;
  aReg A3;
  DB0  *DB0A2;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  ASSERT(index < db.NumEntry(dbDOOR));
  D7W = P2;
  A3 = P6;
  if (D7W == 0) return;
  DB0A2 = GetRecordAddressDB0(index);
  doorType = DB0A2->doorType();
//
  MemMove(GetGraphicAddress(P3[doorType]),
          d.Pointer1848, //temporary bitmap
          P4);
  TAG004b26(DB0A2->ornateness(), P5);
  D0W = d.DoorTOC[doorType];
  if (D0W & 0x400) // Test most significant byte
  {
    if (STRandomBool())
    {
      Mirror(d.Pointer1848, (UI8)(A3[4]), (UI8)(A3[5]));
    };
    if (STRandomBool())
    {
      TAG008840(d.Pointer1848, (UI8)(A3[4]), (UI8)(A3[5]));
    };
  };
  if (A3 == d.Byte3834)
  {
    if (d.SeeThruWalls != 0)
    {
      TAG004b26(17, 2);
    };
  };
  if (D7W == 4)
  {
    TAG00440a(A3);
  }
  else
  {
    if (D7W == 5)
    {
      TAG004b26(16, P5);
      TAG00440a(A3);
    }
    else
    {
      D7W--;
      if (DB0A2->mode())
      {
        TAG00440a(A3+8+8*D7W);
      }
      else
      {
        TAG00440a(A3+32+8*D7W);
        TAG00440a(A3+56+8*D7W);
      };
    };
  };
}
//*********************************************************
//
//*********************************************************
//   TAG004f04
void CheckCeilingPit(i16 P1,RectPos *rect,i32 mapX,i32 mapY,i16 P5)
{
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  dReg D0, D7;
//  aReg A0;
  CELLFLAG **ppdA0;
  ASSERT(verifyRectPos(rect));
  //CELLFLAG *pdA0;
  //i32 D7;
  D7W = IncrementLevel(d.LoadedLevel,-1,&mapX,&mapY);
  if (D7W >= 0)
  {
    D0W = sw(mapX);
    //D1W = D7W * 4;
    ppdA0 = d.pppdPointer10450[D7W];

    //D0W *= 4;
    D0W = ppdA0[mapX][mapY];
    //A0 = pntGear(A0) + mapY;
    //D0W = (UI8)(*A0);
  D7W = D0W;
  D0W >>= 5;
  D0W &= 0x7ff;
    if (D0W == roomPIT)
    {
      if ((D7W & 8) != 0)
      {
        if (P5 != 0)
        {
          TAG0044fe(P1, rect);
        }
        else
        {
          TAG0044b0(P1, rect);
        };
      };
    };
  };
}

void TAG004f82(pnt P1,RectPos *rectpos)
{ // Draw teleporter???
  dReg D0;
  aReg A2;
  ui8 *uA3;
  pnt pnt_4;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  uA3 = (ui8 *)P1;
  if (uA3[3] == 0xff)
  {
    A2 = NULL;
  }
  else
  {
    D0W = sw(uA3[4] * uA3[5]);
    MemMove(GetGraphicAddress((uA3[3] & 0x7f) + 69),
            A2 = d.Pointer1848,
            D0W);
    if (uA3[3] & 0x80)
    {
      Mirror(A2, uA3[4], uA3[5]);
    };
  };
  TAG022c90(0);
  pnt_4 = GetGraphicAddress(uA3[0] + 73);
  TAG008c98(pnt_4,
            d.pViewportBMP,
            A2,
            TAG022d38(0),
            rectpos,
            sw(uA3[1] + GraphicRandom(2)),
            sw(GraphicRandom(32)),
            112,
            uA3[2],
            uA3[6],
            0);
  TAG022d5e(0);
  DeleteGraphic(0x8000);
}




ui8 data008734[256] = { //166 bytes
//008734
    0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
    0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
//008744
    0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
    0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
//008754
    0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
    0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
//008764
    0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
    0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
//008774
    0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
    0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
//008784
    0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
    0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
//008794
    0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
    0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
//0087a4
    0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
    0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
//0087b4
    0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
    0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
//0087c4
    0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
    0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
//0087d4
    0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
    0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
//0087e4
    0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
    0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
//0087f4
    0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
    0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
//008804
    0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
    0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
//008814
    0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
    0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
//008824
    0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
    0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
};

void Mirror(pnt bitmap, i32 width, i32 height) //TAG008642
{ // width is in bytes
  dReg D0, D1, D2, D3;
  aReg A1, A2, A3, A4;
  A2 = (pnt)data008734;
  D0L = 0;
  D1L = 0;
  D3W = sw(width);
  width >>= 3;
  A1 = bitmap + D3W - 6;
  A3 = bitmap;
  A4 = A1;
tag008670:
  D2W = sw(width);
tag008672:
  D2W -= 2;
  if (D2W < 0) goto tag0086e6;
  D0B     = *bitmap;
  D1B     = *(--A1);
  *A1     = *(A2 + D0L);
  *(bitmap++) = *(A2 + D1L);
  D0B     = *bitmap;
  D1B     = *(--A1);
  *A1     = *(A2 + D0L);
  *(bitmap++) = *(A2 + D1L);
  A1 += 4;
  D0B     = *bitmap;
  D1B     = *(--A1);
  *A1     = *(A2 + D0L);
  *(bitmap++) = *(A2 + D1L);
  D0B     = *bitmap;
  D1B     = *(--A1);
  *A1     = *(A2 + D0L);
  *(bitmap++) = *(A2 + D1L);
  A1 += 4;
  D0B     = *bitmap;
  D1B     = *(--A1);
  *A1     = *(A2 + D0L);
  *(bitmap++) = *(A2 + D1L);
  D0B     = *bitmap;
  D1B     = *(--A1);
  *A1     = *(A2 + D0L);
  *(bitmap++) = *(A2 + D1L);
  A1 += 4;
  D0B     = *bitmap;
  D1B     = *(--A1);
  *A1     = *(A2 + D0L);
  *(bitmap++) = *(A2 + D1L);
  D0B     = *bitmap;
  D1B     = *(--A1);
  *A1     = *(A2 + D0L);
  *(bitmap++) = *(A2 + D1L);
  if (D2W == 0) goto tag008722;
  A1 -= 12;
  goto tag008672;
tag0086e6:
  D0B  = *bitmap;
  D1B  = *(--A1);
  *A1 = *(A2 + D0L);
  *bitmap = *(A2 + D1L);
  bitmap += 2;
  A1 += 2;;
  D0B  = *bitmap;
  D1B  = *A1;
  *A1 = *(A2 + D0L);
  *bitmap = *(A2 + D1L);
  bitmap += 2;
  A1 += 2;;
  D0B = *bitmap;
  D1B = *A1;
  *A1 = *(A2 + D0L);
  *bitmap = *(A2 + D1L);
  bitmap += 2;
  A1 += 2;;
  D0B = *bitmap;
  D1B = *A1;
  *A1 = *(A2 + D0L);
  *bitmap = *(A2 + D1L);
tag008722:
  height--;
  if (height == 0) goto tag008834;
  A3 += D3W;
  bitmap = A3;
  A4 += D3W;
  A1 = A4;
  goto tag008670;
tag008834:
  return;
}

// TAG008e1c
void Flood(pnt dst,i16 color,i16 num)
{ // number of 16-bit groups
  dReg D0, D1;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  D0L = D1L = 0;
  if (color & 1) D0W = -1;
  if (color & 2) D0H1 = -1;
  if (color & 4) D1W = -1;
  if (color & 8) D1H1 = -1;
  do
  {
    longGear(dst) = D0L;
    longGear(dst+4) = D1L;
    dst += 8;
    num--;
  } while (num != 0);
};

/*
void TAG00907e(void (*  func)(i32,i32,i32), //8
               pnt (*  getGraphic)(i32),    //12
               i16    P3  ,                 //16
               pnt    P4  ,                 //18
               i16*   P5  ,                 //22
               i16**  P6  ,                 //26 Patch area pointers
               i16    P7  )                 //30 Number of patch areas
{
  // We appear to modify the front three words of
  // the function func to call a little code
  // patch that gets a different graphic to display.
  // After it executes, the patch puts the function
  // back as it was.  What sense does this make?
  // We are called upon to do this at strange times, IMHO.
//
  dReg D0;
  aReg A0;
  i16 *pwA2;
//
  HopefullyNotNeeded();
//
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  do
  { // Look for empty entry at random
    D0L = Random() % P7;
    //A0 = P6 + 4 * D0L;
    pwA2 = P6[D0L];
    D0W = pwA2[30];
  } while (D0W != 0);
  // pwA2 will continue to point to the first word of the
  // patch area selected.
  pwA2[30] = 1;
  MemMove(TAG009110,pwA2,42); // 21 words.  Up to the
              // trailing jump without the address
  // A3 points to first byte of function to be patched.
  MemMove(func, pwA2+31, 6); // Save first 6 byes of func
  pntGear(pwA2+21) = func;  // Patch jumps back to function
  pntGear(pwA2+23) = getGraphic; // The function patch calls
//
}
*/
void TAG009110(void)
{
  HopefullyNotNeeded();
  /*
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
009110 00 41fa 003a                LEA      $+60 (=0x00914c),A0
009114 02 4258                     CLR.W    (A0)+
  // Clear the patch in-use flag .. A0 <- pointer to saved words
009116 03 227a 0022                MOVE.L   $+36 (=0x00913a),A1   // put it back as it was
  // Get address of patched function.
00911a 05 22d8                     MOVE.L   (A0)+,(A1)+
00911c 06 3290                     MOVE.W   (A0),(A1)
  // Restore the function to its original state.
00911e 07 207a 001e                MOVE.L   $+32 (=0x00913e),A0
  // A0 <- extra function to call.
009122 09 3f3a 001e                MOVE.W   $+32 (=0x009142),-(A7)
  // Push the graphic number.
009126 11 4e90                     JSR      (A0)   ;getGraphicAddress
  // Get the Graphic address.
009128 12 2040                     MOVE.L   D0,A0
  // A0 <- The graphic address.
00912a 13 2f3a 001c                MOVE.L   $+30 (=0x009148),-(A7)
  // Push the pointer P5.
00912e 15 2f3a 0014                MOVE.L   $+22 (=0x009144),-(A7)
  // Push the pointer P4
009132 17 4e71                     NOP
  // At this point we have on the stack ( P4, P5, graphicNum )
009134 18 4fef 000a                LEA      10(A7),A7
  // Get everything off the stack.
009138 20 4ef9 cdcd cdcd <         JMP      -842150451     DrawCellxxxx(facing,x,y)
  // Go perform the Drawing function as if we had never been here.

//00913e 23 0000 0000 // getGraphic function address goes here
//009142 25 0000      // The graphic number
//009144 26 0000 0000 // P4 (a pointer)
//009148 28 0000 0000 // P5 (a pointer)
//00914c 30 0000      // In-use flag
//00914e 31 0000 0000 0000  // Save first three words of function
*/
}



//   TAG0095e8
bool IsAlcove(i16 wallDecorationIndex)
{
  dReg D0, D7;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  if (wallDecorationIndex < 0) return 0;
  for (D7W=0; D7W<3; D7W++)
  {
    D0W = d.Word10410[D7W];
    if (wallDecorationIndex == D0W) return 1;
//
  };
  return 0;
}

//   TAG009622
void UpdateXY(i32 facing,
              i32 stepsForward,
              i32 stepsRight,
              i32 *mapX,
              i32 *mapY)
{
  i16 *A0, *A1;
  dReg D1, D2;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  A0 = d.DeltaX;
  A1 = d.DeltaY;
  D1W = sw(stepsForward);
  D2W = D1W;
  D1L = D1UW * (ui16)A0[facing];
  *mapX = sw(*mapX + D1W);
  D2L = D2UW * (ui16)A1[facing];
  *mapY = sw(*mapY + D2W);
  facing = (I16)((facing+1)&3);
  D2W = D1W = sw(stepsRight);
  D1L = D1UW * (ui16)A0[facing];
  *mapX = sw(*mapX + D1W);
  D2L = D2UW * (ui16)A1[facing];
  *mapY = sw(*mapY + D2W);
}

void UpdateXY(i32 direction,
              i32 *newLevel,
              i32 *newX,
              i32 *newY)
{
  int deltaLevel;
  *newX = d.partyX;
  *newY = d.partyY;
  if (direction == 4) deltaLevel = 1; else deltaLevel = -1;
  *newLevel = IncrementLevel(d.partyLevel,deltaLevel,newX,newY);
}

//  TAG009672
CELLFLAG GetCellFlags(i32 mapX, i32 mapY)
{
  ROOMTYPE rtD4, rtD5;
  //D7W = P1;
  //D6W = P2;
  bool legalX, legalY;
  legalY = (mapY>=0) && (mapY<d.height);
  legalX = (mapX>=0) && (mapX<d.width);
  if (legalX && legalY)
  {
    return d.LevelCellFlags[mapX][mapY];
  }
  else
  {
    if (legalY)
    { // Then figure out what to do about illegal x.
      if (mapX == -1)
      {
        rtD4 = RoomType(d.LevelCellFlags[0][mapY]);
        if (rtD4 == roomOPEN) return 4; // Stone...4 = east side something??
        if (rtD4 == roomPIT) return 4;
        return 0;
      };
      if (mapX == d.width)
      {
        rtD4 = RoomType(d.LevelCellFlags[d.width-1][mapY]);
        if (rtD4 == roomOPEN) return 1; // Stone...1=west side something??
        if (rtD4 == roomPIT) return 1;
        return 0;
      };
      return 0;
    };
    if (legalX)
    {
      // What to do if Y is illegal
      if (mapY == -1)
      {
        rtD5 = RoomType(d.LevelCellFlags[mapX][0]);
        if (rtD5 == roomOPEN) return 2;//Stone...South side something??
        if (rtD5 == roomPIT) return 2;
        return 0;
      };
      if (mapY == d.height)
      {
        rtD5 = RoomType(d.LevelCellFlags[mapX][mapY-1]);
        if (rtD5 == roomOPEN) return 8;
        if (rtD5 == roomPIT) return 8;
        return 0;
      };
      return 0;
    };
    return 0; // Both x and y illegal.
  };
}

i16 TAG0097a0(i32 facing,
              i32 stepsForward,
              i32 stepsRight,
              i32 x,
              i32 y)
{
  dReg D0;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  UpdateXY(facing, stepsForward, stepsRight, &x, &y);
  D0W = GetCellFlags(x, y);
  return (I16)(D0W & 0xff);
}

i16 TAG0097d6(i32 facing,
              i32 stepsForward,
              i32 stepsRight,
              i32 x,
              i32 y)
{
  dReg D0;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  D0W = TAG0097a0(facing,
                   stepsForward,
                   stepsRight,
                   x,
                   y);
  D0W &= 0xff;
  D0W >>= 5;
  return D0W;
}

//*********************************************************
//
//*********************************************************
//  TAG009800
i16 IncrementLevel(i32 level,i32 delta,i32 *mapX,i32 *mapY)
//                 8     10      12      16
{
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  dReg D1, D4;
//  aReg A3;
  LEVELDESC *pldA3;
  i32 absX, absY;
  i32 newLevel;
  i16 LOCAL_2;
  i16 LOCAL_12;
  if (d.partyLevel==255) return -1;

  pldA3 = &d.pLevelDescriptors[level];
  absX = pldA3->offsetX + (*mapX);
  absY = pldA3->offsetY + (*mapY);
  newLevel = pldA3->Level() + delta; // Old level + delta
  pldA3 = d.pLevelDescriptors;


  for (LOCAL_2 = 0; LOCAL_2 < d.dungeonDatIndex->NumLevel(); LOCAL_2++)
  { // 0 to #levels-1
    if (pldA3->Level() == newLevel)
      // search for new level among level descriptors
    {
      D4W = pldA3->offsetX;
      if (absX >= D4W)
      {
        D1W = pldA3->LastColumn(); // #columns-1 on new level
        LOCAL_12 = sw(D4W + D1W);
        if ((ui16)absX <= (ui16)LOCAL_12)
        {
          D4W = pldA3->offsetY;
          if(absY >= D4W)
          {
            D1W = pldA3->LastRow();//#rows-1 in new level
            LOCAL_12 =  sw(D4W + D1W);
            if ((ui16)absY <= (ui16)LOCAL_12)
            {
              *mapY = absY - D4W;
              *mapX = absX - pldA3->offsetX;
              return LOCAL_2;
            };
          };
        };
      };
    };
  pldA3 ++;
  };
//
  return -1;
}
//*********************************************************
//
//*********************************************************
DBCOMMON *GetCommonAddress(RN recDesc)
{
  // recDesc(bits 10-13) = database number
  // recDesc(bits 0-9)   = record number within database
//  dReg D0, D2, D3;
//  aReg A0;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  // Some folks call to get the address before checking
  // to see if the object exists at all!
  if ((recDesc == RNnul) || (recDesc == RNeof))
  {
    HopefullyNotNeeded();
    return NULL;
  };
  return db.GetCommonAddress(recDesc);
}

//*********************************************************
//
//*********************************************************
DB0 *GetRecordAddressDB0(RN object)
{
  ASSERT(object.dbType() == dbDOOR);
  return (DB0 *) GetCommonAddress(object);
}

//*********************************************************
//
//*********************************************************
DB0 *GetRecordAddressDB0(int i)
{
  return (DB0 *) db.GetCommonAddress(dbDOOR, i);
}

//*********************************************************
//
//*********************************************************
DB1 *GetRecordAddressDB1(RN object)
{
  ASSERT(object.dbType() == dbTELEPORTER);
  return (DB1 *) GetCommonAddress(object);
}

//*********************************************************
//
//*********************************************************
DB2 *GetRecordAddressDB2(RN object)
{
  ASSERT(object.dbType() == dbTEXT);
  return (DB2 *) GetCommonAddress(object);
}

//*********************************************************
//
//*********************************************************
DB2 *GetRecordAddressDB2(int i)
{
  return (DB2 *) db.GetCommonAddress(dbTEXT, i);
}

//*********************************************************
//
//*********************************************************
DB3 *GetRecordAddressDB3(RN object)
{
  ASSERT(object.dbType() == dbACTUATOR);
  return (DB3 *) GetCommonAddress(object);
}


//*********************************************************
//
//*********************************************************
DB4 *GetRecordAddressDB4(RN object)
{
  ASSERT(object.dbType() == dbMONSTER);
  return (DB4 *) GetCommonAddress(object);
}

//*********************************************************
//
//*********************************************************
DB4 *GetRecordAddressDB4(int i)
{
  return (DB4 *) db.GetCommonAddress(dbMONSTER, i);
}

//*********************************************************
//
//*********************************************************
DB5 *GetRecordAddressDB5(RN object)
{
  ASSERT(object.dbType() == dbWEAPON);
  return (DB5 *) GetCommonAddress(object);
}

//*********************************************************
//
//*********************************************************
DB6 *GetRecordAddressDB6(RN object)
{
  ASSERT(object.dbType() == dbCLOTHING);
  return (DB6 *) GetCommonAddress(object);
}

//*********************************************************
//
//*********************************************************
DB7 *GetRecordAddressDB7(RN object)
{
  ASSERT(object.dbType() == dbSCROLL);
  return (DB7 *) GetCommonAddress(object);
}

//*********************************************************
//
//*********************************************************
DB8 *GetRecordAddressDB8(RN object)
{
  ASSERT(object.dbType() == dbPOTION);
  return (DB8 *) GetCommonAddress(object);
}

//*********************************************************
//
//*********************************************************
DB9 *GetRecordAddressDB9(RN object)
{
  ASSERT(object.dbType() == dbCHEST);
  return (DB9 *) GetCommonAddress(object);
}

//*********************************************************
//
//*********************************************************
DB10 *GetRecordAddressDB10(RN object)
{
  ASSERT(object.dbType() == dbMISC);
  return (DB10 *) GetCommonAddress(object);
}

//*********************************************************
//
//*********************************************************
DB10 *GetRecordAddressDB10(int i)
{
  return (DB10 *) db.GetCommonAddress(dbMISC, i);
}

//*********************************************************
//
//*********************************************************
DB14 *GetRecordAddressDB14(RN object)
{
  ASSERT(object.dbType() == dbMISSILE);
  return (DB14 *) GetCommonAddress(object);
}

//*********************************************************
//
//*********************************************************
DB15 *GetRecordAddressDB15(RN object)
{
  ASSERT(object.dbType() == dbCLOUD);
  return (DB15 *) GetCommonAddress(object);
}

//*********************************************************
//
//*********************************************************
RN FindEmptyDB2Entry(bool important)
{//(RN)
  RN result;
  result = db.FindEmptyDBEntry(dbTEXT, important);
  if (result == RNnul)
  {
    result = MakeMoreRoomInDB(dbTEXT);
    if (result == RNnul) return RNnul;
  };
  GetRecordAddressDB2(result)->Clear();
  return result;
}

//*********************************************************
//
//*********************************************************
RN FindEmptyDB4Entry(bool important)
{//(RN)
  RN result;
  result = db.FindEmptyDBEntry(dbMONSTER, important);
  if (result == RNnul)
  {
    result = MakeMoreRoomInDB(dbMONSTER);
    if (result == RNnul) return RNnul;
  };
  GetRecordAddressDB4(result)->Clear();
  return result;
}

//*********************************************************
//
//*********************************************************
RN FindEmptyDB5Entry(bool important)
{//(RN)
  RN result;
  result = db.FindEmptyDBEntry(dbWEAPON, important);
  if (result == RNnul)
  {
    result = MakeMoreRoomInDB(dbWEAPON);
    if (result == RNnul) return RNnul;
  };
  GetRecordAddressDB5(result)->Clear();
  return result;
}


//*********************************************************
//
//*********************************************************
RN FindEmptyDB6Entry(bool important)
{//(RN)
  RN result;
  result = db.FindEmptyDBEntry(dbCLOTHING, important);
  if (result == RNnul)
  {
    result = MakeMoreRoomInDB(dbCLOTHING);
    if (result == RNnul) return RNnul;
  };
  GetRecordAddressDB6(result)->Clear();
  return result;
}


//*********************************************************
//
//*********************************************************
RN FindEmptyDB10Entry(bool important)
{//(RN)
  RN result;
  result = db.FindEmptyDBEntry(dbMISC, important);
  if (result == RNnul)
  {
    result = MakeMoreRoomInDB(dbMISC);
    if (result == RNnul) return RNnul;
  };
  GetRecordAddressDB10(result)->Clear();
  return result;
}

//*********************************************************
//
//*********************************************************
RN FindEmptyDB14Entry(bool important)
{//(RN)
  RN result;
  result = db.FindEmptyDBEntry(dbMISSILE, important);
  if (result == RNnul)
  {
    result = MakeMoreRoomInDB(dbMISSILE);
    if (result == RNnul) return RNnul;
  };
  GetRecordAddressDB14(result)->Clear();
  return result;
}


//*********************************************************
//
//*********************************************************
RN FindEmptyDB15Entry(bool important)
{//(RN)
  RN result;
  result = db.FindEmptyDBEntry(dbCLOUD, important);
  if (result == RNnul)
  {
    result = MakeMoreRoomInDB(dbCLOUD);
    if (result == RNnul) return RNnul;
  };
  GetRecordAddressDB15(result)->Clear();
  return result;
}

//*********************************************************
//
//*********************************************************
// TAG009a02
RN GetDBRecordLink(RN recName)
{
  // recDesc(bits 10-13) = database number
  // recDesc(bits 0-9)   = record number within database
  DBCOMMON *dbA0;
  ASSERT(recName != RNnul);
  ASSERT(recName != RNeof);
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  dbA0 = GetCommonAddress(recName);
  return dbA0->link();
}

//  TAG009a1e
i16 GetObjectListIndex(i32 mapX,i32 mapY)
{ // Index in ??? of the object-list for this cell.
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  dReg D0, D4, D5;
  CELLFLAG *pdA3;
//  D7W = x;
//  D6W = y;
  pdA3 = d.LevelCellFlags[mapX];
  if (mapX < 0) return -1;
  if (mapX >= d.width) return -1;
  if (mapY < 0) return -1;
  if (mapY >= d.height) return -1;
  D0W = (I16)(pdA3[mapY] & 16);
  if (D0W == 0) return -1; // Nothing here!
  D4W = 0;
  D5W = d.pCurrentLevelObjectIndex[mapX];
  for (D4W=0; D4W<mapY; D4W++)
  {
    D0W = (I16)(pdA3[D4W]&16);
    if (D0W != 0) D5W++;

  };
  D0W = D5W;
  return D0W;
}

//  TAG009a94
RN FindFirstObject(i32 x,i32 y)
{

  i16 LOCAL_2;
  LOCAL_2 = GetObjectListIndex(x, y);
  if ( LOCAL_2 == -1) return RN(RNeof);
  return d.objectList[LOCAL_2];
}

// TAG009ac8
RN FindFirstDrawableObject(i32 x,i32 y)
{
  RN obj;
  obj = FindFirstObject(x, y);
  while ( (obj != RNeof) && (obj.dbType() < dbMONSTER))
  {
    obj = GetDBRecordLink(obj);
  };
  return obj;
}

RN FindFirstTeleporter(i32 level, i32 x, i32 y)
{
  RN obj;
  for (obj=FindFirstObject(level,x,y);
       obj!=RNeof;
       obj=GetDBRecordLink(obj))
  {
    if (obj.dbType() == dbTELEPORTER) break;
  };
  return obj;
}

//*********************************************************
//
//*********************************************************
//   TAG009c4e
void RemoveObjectFromRoom(RN object,i32 mapX,i32 mapY)
{
  dReg D0, D1, D5, D6;
  DBCOMMON *dbA3=NULL;
  RN objD4, objD7;
  RN *prnA2;
  RN P2;
  ui16 *puwA2;
  CELLFLAG *pdA0;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  if (TimerTraceActive)
  {
    fprintf(GETFILE(TraceFile),"Removed %04x from %02x(%02x,%02x)\n",
             object.ConvertToInteger(), d.LoadedLevel, mapX, mapY);
  };
  objD7 = object;
  if (objD7 == RNeof) return;
  //05Nov2002 prs objD7.pos(0); // clear position leaving only record id
  if (mapX >= 0)
  {
    dbA3 = GetCommonAddress(objD7);
    ASSERT(dbA3->link() != RNnul);
    D6W = GetObjectListIndex(mapX, mapY);
    prnA2 = &d.objectList[D6W];
    ASSERT(prnA2->ConvertToInteger() != 0xbadd);
//
    // If specified object has no forward link
    //  and first object in room is the specified object
    //   then remove the entire room.
    if (    (dbA3->link() == RNeof) 
         && ((*prnA2).IsSameObjectAs(objD7)) )
    {
      pdA0 = d.LevelCellFlags[mapX];
      ASSERT((pdA0[mapY] & 0x10)!=0);
      pdA0[mapY] &= 0xef; // clear 'room has object'
      D5W = sw(d.dungeonDatIndex->ObjectListLength() - 1);
      D0W = sw(2*(D5W - D6W));
      MemMove((pnt)(prnA2+1), (pnt)prnA2, D0W);
      d.objectList[D5W] = RN(RNnul); // clear last entry
      //Now we need to fix the column indexes.
      puwA2 = &d.pCurrentLevelObjectIndex[mapX+1];
      // Each column after the current column must
      // have its index decremented.  This includes
      // all the columns in higher numbered levels.
      D5W = d.numColumnPointers; // for all levels
      D1W = d.objectLevelIndex[d.LoadedLevel];
      // D1=index of first DUDAD for this level.
      D1W = sw(D1W + mapX);
      //D1=index of DUDAD for this column
      D5W = sw(D5W - D1W);
      D5W--; //#columns following this column in
              // this and following levels.
      while ((D5W--) != 0) (*(puwA2++))--;
//
      dbA3->link(RNeof);
      return;
    };
    if ((*prnA2).IsSameObjectAs(objD7))
    {
      *prnA2 = dbA3->link();
      dbA3->link(RNeof);
      return;
    }
    P2 = *prnA2;
  };
  objD4 = GetDBRecordLink(P2);
  while (!objD4.IsSameObjectAs(objD7))
  {
    if ((objD4 == RNeof) || (objD4 == RNnul))
    {
      dbA3->link(RNeof);
      return;
    };

    P2 = objD4;
    objD4 = GetDBRecordLink(objD4);
  };
  dbA3 = GetCommonAddress(P2);
  ASSERT(GetDBRecordLink(objD4) != RNnul);
  dbA3->link(GetDBRecordLink(objD4));
  dbA3 = GetCommonAddress(objD7);
  dbA3->link(RNeof);
}

//   TAG00a27c
int DecodeText(pnt result,DB2 *pText,i16 P3, int max)
{//Wall text P3 = 0;
  dReg D0, D4, D5, D6, D7;
  aReg A2;
  DB2 *DB2A1;
  RN objD4;
  DB2 DB2_12;
  pnt LOCAL_8;
  i16 LOCAL_4;
  i8  LOCAL_1;
  int len = 0;
  D6L = 0xbaddadee;
  //A3 = P1;
  D7W = P3;
  //DB2A1 = GetRecordAddressDB2(textID);
  DB2A1 = pText;
  DB2_12 = *DB2A1;
  A2 = d.textArray + 2*DB2_12.index();
  if ((DB2_12.show() != 0) || ((D7W & 0x8000) != 0))
  {
    if ((D7W & 0x7fff) == 1)
    {
      *(result++) = 10;
      len++;
      LOCAL_1 = 32;
    }
    else
    {
      if (D7W == 0)
      {
        LOCAL_1 = -128;
      }
      else
      {
        LOCAL_1 = 10; //Probably D7W==2
      };
    };
    D5W = 0;
    LOCAL_4 = 0;
    for (;;)
    {
      if (D5W == 0)
      {
        D6W = LE16(wordGear(A2));
        A2 += 2;
        D4W = BITS10_14(D6W);
      }
      else
      {
        if (D5W == 1)
        {
          D4W = BITS5_9(D6W);
        }
        else
        {
          D4W = BITS0_4(D6W);
        };
      };
      D5W++;
      D5W = (I16)(D5W % 3);
      if (LOCAL_4 != 0)
      {
      *result = 0;
        if (LOCAL_4 == 30)
        {
          if (D7W != 0)
          {
            LOCAL_8 = d.Byte10016 + 8*D4W;
          }
          else
          {
            LOCAL_8 = d.Byte10336 + 8*D4W;
          };
        }
        else
        {
          if (D7W != 0)
          {
            LOCAL_8 = d.Byte10080 + 2*D4W;
          }
          else
          {
            LOCAL_8 = d.Byte10080 + 2*D4W;
          };
        };
        D0W = StrLen(LOCAL_8);
        len += D0W;
        if (len >= max-4)
        {
          UI_MessageBox("Text Too Long","Sorry",MB_OK);
          UI_Die();
        };
        StrCat(result, LOCAL_8);
        result += D0W;
        LOCAL_4 = 0;
      }
      else
      {
        if (D4W < 28)
        {
          if (D7W != 0)
          {
            if (D4W== 26)
            {
              D4W = 32;
            }
            else
            {
              if (D4W ==27)
              {
                D4W = 46;
              }
              else
              {
                 D4W += 65;
              };
            };
          };
          *(result++) = D4B;
          len++;
          if (len > max-4)
          {
            UI_MessageBox("Text Too Long", "Sorry", MB_OK);
            UI_Die();
          };
        }
        else
        {
          if (D4W == 28)
          {
            *(result++) = LOCAL_1;
            len++;
            if (len > max-4)
            {
              UI_MessageBox("Text Too Long", "Sorry", MB_OK);
              UI_Die();
            };
          }
          else
          {
            if (D4W <= 30)
            {
              LOCAL_4 = D4W;
            }
            else
            {
              break;
            };
          };
        };
      };
    };
  };
  if (D7W == 0)
  {
    *result = -127;
  }
  else
  {
    *result = 0;
  };
  return (A2 - d.textArray - 2*DB2_12.index())/2;
}

//*********************************************************
//
//*********************************************************
//  TAG00a41c
i16 Hash(i16 P1,i16 P2,i16 P3)
{ // Called from only one place in program.
  // P1 is a function of mapX, mapY
  // P2 is a function of level, width, and height
  // P3 is a small integer like 30 used as arithmetic modulus.
  // Result is     hash(P1,P2,dungeonDatIndex[0]) % P3
  dReg D0, D1;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  D0L = (ui16)P1 * 31417;
  D0W = (I16)((D0W >>= 1) & 0x7fff);
  D1L = (ui16)P2 * 11;
  D0W = sw(D0W + D1W);
  D0W = sw(D0W + d.dungeonDatIndex->Sentinel()); // = 13 in my game
  D0W = (I16)((D0W >> 2) & 0x3fff);
  D0L &= 0xffff;
  D0W = sw(D0L % (ui16)(P3));
  return D0W;
}


//  TAG00a44c
i16 RandomWallDecoration(i16 P1,i16 P2,i32 mapX,i32 P4,i16 probability)
{ //P4 = n*mapY  where n=facing
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  i16 LOCAL_2;
  if (P1 != 0)
  {
    LOCAL_2 = Hash(
                (I16)(2000 + (mapX<<5) + P4),
                (I16)(3000 + (d.LoadedLevel<<6) + d.width + d.height),
                probability);
    if (LOCAL_2 < P2)
    {
      return sw(LOCAL_2 + 1);
    };
  };
  return 0;
}

void TAG00a4a2(SUMMARIZEROOMDATA *rslt ,
               i16 P2,       //12
               i16 P3,       //14
               i16 P4,       //16
               i32 facing,   //18
               i32 mapX,     //20
               i32 mapY,     //22
               i32 P8)       //24
{
  i16 numDecoration, i;
  numDecoration = d.pCurLevelDesc->NumRandomWallDecoration();
  rslt->decorations[0] = RandomWallDecoration(
                             P2,
                             numDecoration,
                             mapX,
                             (mapY+1)*(((facing+1)&3)+1),
                             30);
  rslt->decorations[1] = RandomWallDecoration(
                             P3,
                             numDecoration,
                             mapX,
                             (mapY+1)*(((facing+2)&3)+1),
                             30);
  rslt->decorations[2] = RandomWallDecoration(
                             P4,
                             numDecoration,
                             mapX,
                             (mapY+1)*(((facing+3)&3)+1),
                             30);
  if (    (P8 != 0)
       || (mapX < 0)
       || (mapX >= d.width)
       || (mapY < 0)
       || (mapY >= d.height) )

  {
    for (i = 2; i <= 4; i++)
    {
      if (IsAlcove(sw(rslt->decorations[i-2]-1)))
      {
        rslt->decorations[i-2] = 0;
      };

    };
  };
}

//*********************************************************
//
//*********************************************************
//   TAG00a9d4
void LoadLevel(i32 newLevel)
{
  dReg D0;
  D0W = d.LoadedLevel;
  if (D0W != newLevel)
  {
    d.LoadedLevel = sw(newLevel);
    d.LevelCellFlags = d.pppdPointer10450[newLevel];
    d.pCurLevelDesc = &d.pLevelDescriptors[newLevel];
    d.width = sw(d.pCurLevelDesc->LastColumn()+1);
    d.height = sw(d.pCurLevelDesc->LastRow()+1);
    D0W = d.pCurLevelDesc->Door1Type();
    d.DoorTOC[0] = d.DoorCharacteristics[D0W];
    D0W = d.pCurLevelDesc->Door2Type();
    d.DoorTOC[1] = d.DoorCharacteristics[D0W];
    D0W = d.objectLevelIndex[newLevel];
    d.pCurrentLevelObjectIndex = &d.objectListIndex[D0W];
  };
}

//   TAG00aa9c
void SetPartyLevel(i32 level)
{
  dReg D1;
  d.partyLevel = sw(level);
  LoadLevel(level);
  d.EndOfCELLFLAGS = d.LevelCellFlags[d.width-1] + d.height;//pdD0 = (CELLFLAG *)pD0;
  d.NumWallDecoration = d.pCurLevelDesc->NumWallDecoration();
  D1W=d.pCurLevelDesc->numMonsterType();
  memmove(d.WallDecorationTOC, //For this level
          d.EndOfCELLFLAGS + D1W,
          d.NumWallDecoration);
  d.WallDecorationTOC[d.NumWallDecoration] = 0;
  D1W = sw(D1W + d.NumWallDecoration);
  memmove(d.FloorDecorationTOC,
          d.EndOfCELLFLAGS + D1W,
          d.pCurLevelDesc->NumFloorDecorations());
  D1W = sw(D1W + d.pCurLevelDesc->NumFloorDecorations());
  memmove(d.DoorDecorationTOC,
          d.EndOfCELLFLAGS + D1W,
          d.pCurLevelDesc->NumDoorDecorations());
}

//*********************************************************
//
//*********************************************************
//  TAG00ad18
i16 SetMonsterPositionBits(i16 P1,i32 monsterNumber,i32 Pos)
{
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  Pos &= 3; // Some folks forget!
  Pos <<= 2*monsterNumber; //locate position bits
  P1 &= ~(3 << (2*monsterNumber)); // mask out unwanted bits
  return sw(P1 | Pos);
}

//*********************************************************
//
//*********************************************************
//  TAG00ad58
i32 NextMonsterUpdateTime(ITEM16 *P1,i16 monsterIndex,i16 P3)
{
  dReg D0, D1, D4, D5, D6, D7;
  ITEM16 *pI16A3;
  DB4    *pDB4A2;
  MONSTERTYPE mtD6;
  MONSTERTYPE mt_4;
  bool bool_2;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  pI16A3 = P1;
  D7W = monsterIndex;
  pDB4A2 = GetRecordAddressDB4(pI16A3->word0);
  //pDB4A2 = & ((DB4 *)(d.misc1052eight[4]))[pI16A3->word0];
  mt_4 = pDB4A2->monsterType();
  D5W = d.MonsterDescriptor[mt_4].word4;
  bool_2 = D7W < 0;
  if (bool_2)
  {
    D7W = pDB4A2->numMonM1();
  };
  do  // while D7W >= 0
  {
    D6W = pI16A3->uByte12[D7W];
    D6W &= 0xc0;
    D4W = BITS12_13(D5W);
    if (D4W != 0)
    {
      D4W = (i16)STRandom(D4W);
      if (STRandomBool())
      {
        D4W = (I16)((-D4W) & 7);
      };
      D6W |= D4W;
    };
    D4W = BITS14_15(D5W);
    if (D4W != 0)
    {
      D4W = (i16)STRandom(D4W);
      if (STRandomBool())
      {
        D4W = (I16)((-D4W) & 7);
      };
      D6W |= D4W << 3;
    };
    if (P3 != 0)
    {
      if (D5W & 0x200)
      {
        if ( (D6W & 0x80) && (mt_4 == mon_DethKnight) )
        {
          if (STRandomBool())
          {
            D6W ^= 0x40;
            QueueSound(16, d.Word13016, d.Word13018, 1);
          };
        }
        else
        {
          if (   ((D6W & 0x80) == 0)
              || ((D5W & 0x400) == 0) )
          {
            if (STRandomBool())
            {
              D6W |= 0x40;
            }
            else
            {
              D6W &= 0xffbf;
            };
          };
        };
      }
      else
      {
        D6W &= 0xffbf;
      };
      D6W |= 0x80;
    }
    else
    {
      if (D5W & 4)
      {
        if (STRandomBool())
        {
          D6W |= 0x40;
        }
        else
        {
          D6W &= 0xffbf;
        };
      }
      else
      {
        D6W &= 0xffbf;
      };
      D6W &= 0xff7f;
    };
    pI16A3->uByte12[D7W] = D6B;
    if (!bool_2) break;
    D7W--;
  } while  (D7W >= 0);
  mtD6 = pDB4A2->monsterType();
  D6W = d.MonsterDescriptor[mtD6].word20;
  //D0L = d.Time;
  if (P3 != 0)
  {
    D1W = (I16)((D6W >> 8) & 15);
  }
  else
  {
    D1W = (I16)((D6W >> 4) & 15);
  };
  D0L = d.Time + (D1L & 0xffff);
  D0L += STRandomBool();
  return D0L;
}

void TAG00af1a(i32 mapX,i32 mapY)
{
  DB4 *DB4A3;
  TIMER timer;
  RN obj;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  obj = FindFirstMonster(mapX, mapY);
  if ((obj != RNnul) && (obj != RNeof))
  {
    DB4A3 = GetRecordAddressDB4(obj);
    if (DB4A3->fear() >= 4)
    {
      DB4A3->fear(0);
    };
  }
  else
  {
    HopefullyNotNeeded();
    DB4A3 = NULL;
    timer.timerUByte5 = 255;
    // This happened in the prison when the only
    // character died from lack of food.
  };
  timer.timerTime = (d.Time+1) | (d.LoadedLevel << 24);
  timer.timerFunction = timerFunction37;
  timer.timerUByte5 =
        ub(255 - d.MonsterDescriptor[DB4A3->monsterType()].timePerMove());
  timer.timerUByte8=0;
  timer.timerUByte6 = (i8)mapX;
  timer.timerUByte7 = (i8)mapY;
  SetTimer(&timer);
}

//*********************************************************
//
//*********************************************************
//   TAG00afbc
void DeleteMonsterMovementTimers(i32 mapX,i32 mapY)
{ //Timer types 29 to 41
  dReg D0, D4, D5;
  TIMER *psA3;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  //D7W = P1;
  //D6W = P2;
  psA3 = d.Timers;
  for (D5W=0; D5W<d.MaxTimers; psA3++,D5W++)
  {
    D0L = (psA3->timerTime >> 24) & 0xff;
    if (D0L != d.LoadedLevel) continue;
    D4W = D0W = psA3->timerFunction;
    if (D0W < 29) continue;
    if (D4W > 41) continue;
    if (psA3->timerUByte6 != mapX) continue;
    if (psA3->timerUByte7 != mapY) continue;
    TraceTimer(psA3, D5W, "Delete");
    DeleteTimer(D5W);

  };
}

void TAG00b062(RN P1,i32 mapX,i32 mapY)
{
  dReg        D0, D1, D6;
  aReg        A0;
  MONSTERDESC *pmtDesc;
  ITEM16      *pi16A2;
  DB4         *pDB4A3;
  i16         item16Index;
  i16         LOCAL_6;
  static i32  message = 0;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  A0 = NULL;
  pi16A2 = d.Item16;
  item16Index = 0;
  while (pi16A2->word0 >= 0)
  {
    item16Index++;
    if (item16Index >= d.MaxITEM16)
    {
      if (!AutoEnlarge)
      UI_MessageBox("The Atari code did bad things at this point.\n"
                    "I am going to try to increase the maximum.\n"
                    "If you don't like this, close the program\n"
                    "before saving the game.",
                    "Too many monsters",
                    MESSAGE_OK);
      if (d.MaxITEM16 < 240)
      {
        i32 i, newMax;
        newMax = d.MaxITEM16 + 50;
        d.Item16 = (ITEM16 *)realloc(d.Item16, 16 * newMax);
        for (i=d.MaxITEM16; i< newMax; i++)
        {
          d.Item16[i].word0 = -1;
        };
        pi16A2 = &d.Item16[d.MaxITEM16];
        d.MaxITEM16 = sw(newMax);
        break;
      }
      else
      {
        UI_MessageBox("I give up",
                      "Cannot reallocate monster data",
                      MESSAGE_OK);
        die (0);
      };
    };
    pi16A2++;
  };
  d.ITEM16QueLen++;
  pi16A2->word0 = D1W = P1.idx();
  pDB4A3 = GetRecordAddressDB4(D1W);
  //pDB4A3 = &((DB4 *)(d.misc1052eight[4]))[D1W];
  pi16A2->positions() = pDB4A3->groupIndex();
  pDB4A3->groupIndex(item16Index);
  pi16A2->uByte10 = (i8)mapX;
  pi16A2->uByte8 = (i8)mapX;
  pi16A2->uByte11 = (i8)mapY;
  pi16A2->uByte9 = (i8)mapY;
  pi16A2->uByte4 = (UI8)(d.Time - 127); // about 20 seconds
  pmtDesc = &d.MonsterDescriptor[pDB4A3->monsterType()];
  SET(D0B, pmtDesc->horizontalSize() == 1);
  LOCAL_6 = (I16)(D0W & 1);
  D6W = pDB4A3->numMonM1();
  do
  {
    // Set all members of group facing same direction.
    //D0W = pDB4A3->word14;
    D0W = SetMonsterPositionBits(
             pi16A2->facings(),  //Old facing byte
             D6W,               //MonsterNumber
             pDB4A3->facing());     //Monster's facing
    pi16A2->facings() = D0B;
    pi16A2->uByte12[D6W] = 0;
    D0W = D6W--;
  } while (D0W != 0);
  NextMonsterUpdateTime(pi16A2, -1, 0);
}

//*********************************************************
//
//*********************************************************
//   TAG00b152
void DetachItem16(i32 P1)
{
  ITEM16 *pi16A3;
  DB4 *pDB4A2;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
//
//
  if ( (P1 > d.MaxITEM16) || (d.Item16[P1].word0 < 0) ) return;
//
  ASSERT(P1 < d.MaxITEM16);
  pi16A3 = &d.Item16[P1];
  pDB4A2 = GetRecordAddressDB4(pi16A3->word0);
  //pDB4A2 = &((DB4 *)d.misc1052eight[4])[pi16A3->word0];
  d.ITEM16QueLen--;
  pDB4A2->groupIndex(pi16A3->positions());
  // 30OCT02SETWBITS8_9(pDB4A2->word14, pi16A3->facings());
  pDB4A2->facing(pi16A3->facings());
  // 30OCT02if (BITS0_3(pDB4A2->word14) >=4)
  if (pDB4A2->fear() >= 4)
  {
    //30OCT02SETWBITS0_3(pDB4A2->word14, 0);
    pDB4A2->fear(0);
  };
  pi16A3->word0 = -1;
}

void TAG00bd40(void)
{
  i32 i=0;
  while (d.ITEM16QueLen != 0)
  {
    ASSERT(i < d.MaxITEM16);
    if ( d.Item16[i].word0 >= 0)
    {
      DetachItem16(i); //(item16Index)
    };
    i++;
  };
}

//   TAG00bd70
void ProcessMonstersOnLevel(void)
{ // I don't know what 'process' means.  :-(
  dReg D0;
  RN *prnA2;
  //DUDAD16 *pdA3;
  CELLFLAG *ubA3;
  RN objD5, nextObj;
  i32 mapX, mapY;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  ubA3 = d.LevelCellFlags[0];
  D0W = *d.pCurrentLevelObjectIndex;
  prnA2 = &d.objectList[D0W];
  for (mapX=0; mapX<d.width; mapX++)
  {
    for (mapY=0; mapY<d.height; mapY++)
    {
      if (((*ubA3++)&16) != 0)
      {
        objD5 = *(prnA2++);
        while (objD5 != RNeof)
        {
          ASSERT(objD5.ConvertToInteger() != 0xfeff);
          //D0W = ;
          if (objD5.dbType() == dbMONSTER) // Is it a monster?
          {
            DeleteMonsterMovementTimers(mapX, mapY); // type 29-41
            TAG00b062(objD5, mapX, mapY); //add to item16
            TAG00af1a(mapX, mapY); //Set timers for monster
            break;
          }
          nextObj = GetDBRecordLink(objD5);
          ASSERT(nextObj != RNnul);
          nextObj = GetDBRecordLink(objD5);
          objD5 = nextObj;
        }; //while
      };

    };
//
  };
}

//*********************************************************
//
//*********************************************************
//   TAG00be06
void InitializeItem16(void)
{
  i32 i;
  if (d.dungeonFormat != 0) d.MaxITEM16 = 60;
  d.Item16 = (ITEM16 *)UI_malloc(16*d.MaxITEM16);
  for (i=0; i < d.MaxITEM16; i++) d.Item16[i].word0 = -1;
}

//*********************************************************
//
//*********************************************************
i16 TAG00dcf2(pnt /*P1*/)
{
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
/* All of this does nothing!
*/
  d.Word8892+=4;
  return 4;
}

//*********************************************************
//
//*********************************************************
i16 TAG011594(i16 chIdx,
              CHARDESC *pChar,
              i16 srcPossession,
              i16 dstPossession)
{//(i16)
  dReg D5, D6, D7;
  RN   objD0;
  CHARDESC *pcA3;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  D7W = chIdx;
  pcA3 = pChar;
  D6W = srcPossession;
  D5W = dstPossession;
  if (pChar->possessions[D6W] == RNnul) return 0;
  if (pChar->possessions[D6W].dbType() != dbWEAPON) return 0;
  objD0 = RemovePossession(D7W, D6W);
  PlaceObjectOnCharacter(D7W, objD0, D5W);
  return (1);
}

void TAG0115ee(i32 chIdx, i32 byte6)
{ //(void)
  //Called by timer 11 when byte 6 not zero
  dReg D0, D5, D6, D7;
  CHARDESC *pcA3;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  D6W = sw(byte6);
  D7W = sw(chIdx);
  pcA3 = &d.CH16482[chIdx];
  if (pcA3->possessions[D6W] != RNnul) return;
  D0W = TAG011594(D7W, pcA3, 12, D6W);
  if (D0W != 0) return;
  for (D5W = 7; D5W <= 9; D5W++)
  {
    D0W = TAG011594(D7W, pcA3, D5W, D6W);
    if (D0W != 0) return;
//
//
  };
}

//**********************************************************
//
//**********************************************************
//   TAG011664
void MarkAllChar1000(void)
{
  i32 i;
  for (i=0; i<d.NumCharacter; i++)
  {
    d.CH16482[i].word48 |= 0x1000;
  };
  DrawAllCharacterState();
}

//*********************************************************
//
//*********************************************************
void TAG0138ec(void)
{//(void)
  dReg D7;
  RN objD5;
  CHARDESC *pcA3;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  if (d.dungeonFormat == 0)
  {
    ASSERT(RememberToPutObjectInHand == -1);
    objD5 = d.objectInHand;
    if (objD5 == RNnul)
    {
      d.EmptyHanded = 1;
      d.ObjectType16574 = -1;
      TAG002572();
    }
    else
    {
      TakeObject(objD5, 1);
    };
    pcA3 = d.CH16482;
    D7W = 0;
    while (D7W < d.NumCharacter)
    {
      pcA3->word48 &= 0x7f;
      pcA3->word48 |= 0x9400;
      D7W++;
      pcA3++; // +800

    };
    DrawAllCharacterState();
    D7W = d.HandChar; // owner of cursor
    if (D7W != -1)
    {
      // I have commented the following line.
      // What happened was that the Atari code
      // added the weight of the object in hand already.
      // So when we set d.HandChar to -1 and call
      // SetHandOwner the weight gets added again.
      // By leaving d.HandChar alone, SetHandOwner will
      // subtract the weight before adding it again.
      //d.HandChar = -1;
      // The following patch has been put into the
      // Atari code
      //  01395e  4e71  NOP   patch used to be 397c
      //  013960  4e71  NOP   patch used to be ffff
      //  013962  4e71  NOP   patch used to be bf48

      SetHandOwner(D7W);
    };
    D7W = d.MagicCaster;
    if (D7W != -1)
    {
      d.MagicCaster = -1;
      SelectMagicCaster(D7W);
    };
    return;
  };
  ASSERT(RememberToPutObjectInHand == -1);
  d.objectInHand = RN(RNnul);
  d.ObjectType16574 = -1;
  d.EmptyHanded = 1;

}

//   TAG011692
RESTARTABLE _ProcessTimers(void) // Parameter ignored, I think.
{//(void)
  static dReg D0;
  static i32 function;
  static i32 param;
  static i32 chIdx;
  static i16 *pwA3;
  static CHARDESC *pcA0;
  static TIMER  timeEnt;
  static i16 cP4, cP3, cP2, cP1;
  static int numberOfTimersProcessed;
  RESTARTMAP
    RESTART(1)
  END_RESTARTMAP
  //i32 saveD7 = D7;
  //pnt saveA3 = A3;
  numberOfTimersProcessed = 0;
  function=0;
  while (CheckForTimerEvent() != 0)
  {
    if (++numberOfTimersProcessed > 50000)
    {
      die(0,"50000 timer events in 1/6 second.\n"
            "That seems excessive.\n"
            "Please contact your friendly dungeon designer");
    };
    GetNextTimerEntry(&timeEnt);//TAG01022c
    D0L = timeEnt.timerTime >> 24; // Level
    LoadLevel(D0W);
    if ((ui32)d.Long11732 <= (ui32)d.Time)
    {
      function = timeEnt.timerFunction;
    };
    if ( (function >= timerFunction29) && (function <= timerFunction41) )
    {
      ProcessTimers29to41(
                timeEnt.timerUByte6, //TAG00cbc6
                timeEnt.timerUByte7,
                (TIMERFUNCTION)timeEnt.timerFunction,
                timeEnt.timerUByte8);
    }
    else
    {
      switch (function)
      {
      case timerFunction48:
      case timerFunction49: MissileTimer(&timeEnt); break;
      case timerFunction1:  ProcessTimer1(&timeEnt); break;
      case timerFunction25: ProcessTimer25(&timeEnt); break;
      case timerFunction7:  ProcessTimer7(&timeEnt); break;
      case timerFunction2:  ProcessTimer2(&timeEnt); break;
      case timerFunction10: ProcessTimer10(&timeEnt); break;
      case timerFunction9:  ProcessTimer9(&timeEnt); break;
      case timerFunction8:  ProcessTimer8(&timeEnt); break;
      case timerFunction6:  ProcessTimer6(_1_,&timeEnt); break;
      case timerFunction11:
               chIdx=timeEnt.timerUByte5;
               EnableCharacterAction(chIdx);
               if (timeEnt.timerUByte6 != 0)
               {
                 TAG0115ee(timeEnt.timerUByte5,
                           timeEnt.timerUByte6-1);
               };
               D0B = timeEnt.timerUByte5;
               DrawCharacterState(D0W);//top box,pos,dir,weapon
               break;
      case timerFunction12: TAG011366(timeEnt.timerUByte5); break;
      case timerFunction13: ProcessTimer13(&timeEnt); break;
      case timerFunction5:  ProcessTimer5(&timeEnt); break;
      case timerFunction60:
      case timerFunction61: ProcessTimer60and61(&timeEnt); break;//TAG011192
      case timerFunction65: ProcessTimer65(&timeEnt); break;
      case timerFunction20:
               cP4 = 1;
               D0B = timeEnt.timerUByte7;
               cP3 = D0W;
               D0B = timeEnt.timerUByte6;
               cP2 = D0W;
               cP1 = timeEnt.timerWord8();
               QueueSound(cP1, cP2, cP3, cP4);
               break;
      case timerFunction24:
               D0W = d.Word11694;
               if (D0W != 0) break;
               D0W = 0;
               D0B = timeEnt.timerUByte7;
               cP4 = D0W;
               D0B = timeEnt.timerUByte6;
               cP3 = D0W;
               //cP2 = 0;
               //cP1 = timeEnt.WB8.word;
               RemoveObjectFromRoom(timeEnt.timerObj8(), // Get word 8 as RN
                                    cP3,
                                    cP4);
               pwA3=(i16 *)GetCommonAddress(timeEnt.timerObj8());
               //A0 = A3;
               pwA3[0] = -1;
               break;
      case timerFunction53: SetWatchdogTimer(); break;
      case timerFunction70:
               LoadLevel(d.partyLevel);
               ProcessLightLevelTimer(&timeEnt);
               SelectPaletteForLightLevel();
               break;
      case timerFunction71: d.Invisible--; break;
      case timerFunction72:
               //D0 = (ui8)LOCAL_1[5] *800;
               pcA0 = &d.CH16482[timeEnt.timerUByte5]; //d.Byte16208;
               //A0 += D0;
               //D0W = wordGear(A0)-wordGear(&LOCAL_1[6]);
               {
                 i32 oldShieldLevel, newShieldLevel, chIdx;
                 char ascii[10];
                 oldShieldLevel = pcA0->shieldStrength/50;
                 pcA0->shieldStrength =
                       uw(pcA0->shieldStrength - timeEnt.timerUWord6());
                 newShieldLevel = pcA0->shieldStrength/50;
                 if (oldShieldLevel != newShieldLevel)
                 {
                   chIdx = timeEnt.timerUByte5;
                   PrintLinefeed();
                   QuePrintLines(d.Byte1386[chIdx],pcA0->name);
                   QuePrintLines(d.Byte1386[chIdx]," SHIELD DECREASED TO ");
                   sprintf(ascii, "%d", pcA0->shieldStrength);
                   QuePrintLines(d.Byte1386[chIdx], ascii);
                 };
               };
               //wordGear(A0) = D0W;
               //D0 = (ui8)LOCAL_1[5] * 800;
               //A0 = d.Byte16434;
               //A0 += D0;
               pcA0->word48 |= 0x1000;
               //wordGear(A0) |= 0x1000;
               DrawCharacterState(timeEnt.timerUByte5); //top box etc
               break;
      case timerFunction73: d.SeeThruWalls--; break;
      case timerFunction74:
               d.Word13278 = sw(d.Word13278-timeEnt.timerWord6());
               MarkAllChar1000();
               break;
      case timerFunction75:
               //D0W = (ui8)LOCAL_1[5];
               //D7W = D0W;
               param = timeEnt.timerUByte5;
               //D0 = D0W * 800;
               //A0 = d.Byte16440 + D0;
               //(*A0)--;
               pcA0 = &d.CH16482[param];
               pcA0->uByte42--;
               TAG017274(param,timeEnt.timerWord6());
               break;
      case timerFunction77:
               d.Word13274 = sw(d.Word13274-timeEnt.timerWord6());
               MarkAllChar1000();
               break;
      case timerFunction78: d.Word13276 = sw(d.Word13276 - timeEnt.timerWord6());
               MarkAllChar1000();
               break;
      case timerFunction79: d.Byte13279--; break;
      case timerFunction22: // It appears that a timer of type 22 is created
               // when a game is restarted from a saved game.
               TAG00dcf2(&d.Byte11678);  // This function NOP'ed out! Always returns 4.
                // Looks like something deleted here
                // Looks like  if (result==???) d.Word000554=136;
               break;
      default: die(0, "Illegal Timer Entry");
      }; // switch (function)
    };
    LoadLevel(d.partyLevel); //00a9d4
  }; // while()
  //D7=saveD7;
  //A1=saveA3;
  RETURN;
}

RESTARTABLE _TAG014368(const i32 button)
{//(void)
  static dReg D0, D1, D5, D6, D7;
  static aReg A0;
  static DB3      *DB3A2;
  static RN objD4;
  static i32 mapX, mapY;
  static CHARDESC *pcA3;
  static RectPos LOCAL_12;
  RESTARTMAP
    RESTART(2)
  END_RESTARTMAP
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  D7W = sw(d.NumCharacter-1);
  pcA3 = &d.CH16482[D7W];
  if (button==162)
  {
    TAG0192f4(4);
    d.PotentialCharacterOrdinal = 0;
    if (d.NumCharacter == 1)
    {
      SetHandOwner(-1);
    };
    d.NumCharacter--;
    LOCAL_12.w.y1 = 0;
    LOCAL_12.w.y2 = 28;
    LOCAL_12.w.x1 = sw(69 * D7W);
    LOCAL_12.w.x2 = sw(LOCAL_12.w.x1 + 66);
    STHideCursor();
    FillRectangle(d.LogicalScreenBase,
                  &LOCAL_12,
                  0,
                  160);
    D0W = (UI8)(pcA3->position+4-d.partyFacing);
    //D0L = (D0W & 3) << 3;
    //A0 = &d.wRectPos1454[D0W&3];
    FillRectangle(d.LogicalScreenBase,
                  &d.wRectPos1454[D0W&3],
                  0,
                  160);
    TAG0207cc();
    STShowCursor();
  }
  else
  {
    d.PotentialCharacterOrdinal = 0;
    mapX = d.partyX;
    mapY = d.partyY;
    D1W = d.partyFacing;
    D1W = d.DeltaX[D1W];
    mapX += D1W;
    D1W = d.partyFacing;
    D1W = d.DeltaY[D1W];
    mapY += D1W;

    for (D6W=0; D6W<30; D6W++)
    {
      objD4 = pcA3->possessions[D6W];
      if (objD4 != RNnul)
      {
        RemoveObjectFromRoom(objD4, mapX, mapY);
      };

    };
    objD4 = FindFirstObject(mapX, mapY);
    for (;;)
    {
      //D0W = ;
      if (objD4.dbType() == dbACTUATOR)
      {
        DB3A2 = GetRecordAddressDB3(objD4);
        DB3A2->actuatorType(0);
        break;
      };
      objD4 = GetDBRecordLink(objD4);
    };
    if (button == 161)
    {
      ReIncarnate(_2_, pcA3);
      ClearMemory((pnt)pcA3->skills92,120);
      if (!DM_rules)
      {
        for (D6W=1; D6W<=6; D6W++)
        {
          D5W = pcA3->Attributes[D6W].Current();
          D5W >>= 3;
          D0W = pcA3->Attributes[D6W].Current();
          D0W = sw(D0W - D5W);
          D1W = pcA3->Attributes[D6W].Minimum();
          D0W = sw(Larger(D1W, D0W));
          pcA3->Attributes[D6W].Maximum(D0W);
          pcA3->Attributes[D6W].Current(D0W);
//
        };
      };
      if (!DM_rules)
      {
        pcA3->HP >>= 1;
        pcA3->maxHP >>= 1;
        pcA3->stamina >>= 1;
        pcA3->maxStamina >>= 1;
        pcA3->mana >>= 1;
        pcA3->maxMana >>= 1;
      };
      //D6W = 0;
      for (D6W=0; D6W<12; D6W++)
      {
        D5W = sw((STRandom() & 0xffff) % 7);
        pcA3->Attributes[D5W].IncrCurrent(1);
        pcA3->Attributes[D5W].IncrMaximum(1);

//
      };
    };
    if (d.NumCharacter == 1)
    {
      d.Long12954 = d.Time;
      SetHandOwner(0);
      SelectMagicCaster(0);
    }
    else
    {
      TAG01b50e(d.MagicCaster);
    };
    PrintLinefeed();
    QuePrintLines(D6W = (UI8)(d.Byte1386[D7W]), pcA3->name);
    if (button == 160)
    {
      A0 = " RESURRECTED";
    }
    else
    {
      A0 = " REINCARNATED";
    };
      QuePrintLines(D6W, A0);
      TAG0192f4(4);
      TAG0207cc();
    if (d.HandChar == -1) // owner of cursor
    {
      D0W = 0;
    }
    else
    {
      D0W = 1;
    };
    SetCursorShape(D0W);
  };
  RETURN;
}

//*********************************************************
//
//*********************************************************
//   TAG015396
void DrawAllCharacterState(void)
{//(void)
  static i32 i;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  //What if we simply don't do this????NotImplemented(0x99977a);//wvbl(_1_);
  for (i=0; i<d.NumCharacter; i++)
  {
    DrawCharacterState(i);//box at top, pos, dir, weapon
  };
  return;
}

//   TAG0156c4
void TakeObject(RN object,i16 P2)
{//(void)
  	// This function takes the object from selected inventory
    // square.  If the square is empty, this function is not
    // called. It exchanges object in hand
  	// with the object in inventory
  dReg D1;
  CHARDESC *pcA0;
  OBJECTTYPE ot;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  if (object == RNnul) return;
  d.EmptyHanded = 0;
  ASSERT(RememberToPutObjectInHand == -1);
  ot = GetModifiedObjectType(d.objectInHand = object);
  d.ObjectType16574 = (I16)ot;
  GetIconGraphic(ot, d.Pointer16572);
  STHideCursor();
  DrawNameOfHeldObject(object);
  if (P2)
  {
    d.Word11744 = 1;
  }
  else
  {
    CreateObjectCursor(d.Pointer16572);
  };
  STShowCursor();
  if (d.HandChar == -1) return; //owner of cursor
  D1L = GetObjectWeight(object);
  pcA0 = &d.CH16482[d.HandChar]; //owner of cursor
  pcA0->load = sw(pcA0->load + D1W);
  ASSERT(pcA0->load < MAXLOAD);
  pcA0->word48 |= 0x200;
  DrawCharacterState(d.HandChar); //owner of cursor
}

//  TAG01479c
i16 GetCharacterToDamage(i32 newX, i32 newY , i32 direction)
{ // We got here when we ran into a wall.
  // Direction appears to be 180 degrees from
  // direction party just moved.  Perhaps it is the
  // side of the cell we encountered.
  // We also got here when a Deth Knight attacked the
  // party.  In that case, direction was STRandom0_3().
  // Probably the position within the monster party
  // from which tha attack came???.
  dReg D6, D7;
  i32 xDist, yDist;
  ui8 attackOrder[4];
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  if (d.NumCharacter == 0) return -1;
  xDist = abs(newX - d.partyX); // How far we moved?
  yDist = abs(newY - d.partyY);
  if (xDist + yDist > 1) return -1;
  //Pretend we are being attacked by the wall!  The
  //two people closest to the wall are affected.
  DetermineAttackOrder(attackOrder,
                       d.partyX, d.partyY,
                       newX,newY,direction);
  for (D7W=0; D7W<4; D7W++)
  {
    D6W = CharacterAtPosition(attackOrder[D7W]);
    if (D6W >= 0)
    {
      return D6W;
    };
//
  };
  return -1;
}

//*********************************************************
// 20 has already been subtracted from button number.
// It should be 0 to 7 for the 8 hands shown in
// in the 4 portrait areas.  It should be 8 to 20
// for the clothes on the 'paper doll'.  It should be
// 21 to 37 for the backpack items.  It will be 30 to
// 37 for items in the chest.
//
//*********************************************************
//   TAG015e0c
void HandleClothingClick(i32 button)
{//(void)
  dReg D0, D6, D7;
  RN objD4, objD5;
  //;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  if (button < 8)
  {
    if (d.PotentialCharacterOrdinal != 0) return;
    D7W = sw(button);
    D7W /= 2;
    if (D7W >= d.NumCharacter) return;
    if (D7W+1 == d.SelectedCharacterOrdinal) return;
    if (d.CH16482[D7W].HP == 0) return;
    D6W = (I16)(button & 1); // Left or right hand.
  }
  else
  {
    D7W = sw(d.SelectedCharacterOrdinal-1);
    D6W = sw(button-8);
  };
  ASSERT(RememberToPutObjectInHand == -1);
  objD5 = d.objectInHand;
  if (D6W >= 30)
  {
    objD4 = d.rnChestContents[D6W-30];
  }
  else
  {
    objD4 = d.CH16482[D7W].possessions[D6W];
  };
  if ( (objD4==RNnul) && (objD5==RNnul) ) return;
  if (objD5 != RNnul)
  {
    D0W = GetObjectIndex(objD5);
    D0W = d.ObjDesc[D0W].word4;// Possible carry locations
    if ((D0W & d.CarryLocation[D6W]) == 0) return;
  };
  STHideCursor();
  if (objD5 != RNnul)
  {
    RemoveObjectFromHand();
  };
  if (objD4 != RNnul)
  {
    RemovePossession(D7W, D6W);
    TakeObject(objD4, 0);
  };
  if (objD5 != RNnul)
  {
    PlaceObjectOnCharacter(D7W, objD5, D6W);
  };
  DrawCharacterState(D7W);
  STShowCursor();
}

//  TAG01657e
i16 TimeToMove(CHARDESC *pChar)
{ // Speed of character???
  dReg D0, D1, D6, D7;
  i16 time;
  OBJECTTYPE otD0;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  //pcA3 = chIdx
  D6L = MaxLoad(pChar);
  D7W = pChar->load;
  if (D6L > D7W)
  {
    time = 2;
    D0L = 8 * (D7W & 0xffff);
    D1L = 5 * (D6L & 0xffff);
    //D1L = 5 * D1L;
    if (D0L > D1L)
    {
      time++;
    };
    D7W = 1;
  }
  else
  {
    time = 4;
    D1L = (4 * (D7W - D6L)) & 0xffff;
    time = sw(time + D1L / D6L);
    D7W = 2;
  };
  if (pChar->ouches & 32)
  {
    time = sw(time + D7W);
  };
  otD0 = GetModifiedObjectType(pChar->possessions[5]); // feet
  if (otD0 == obj_BootsOfSpeed)
  {
    time--;
  };
  return time;
}

//*********************************************************
//
//*********************************************************
//   TAG0169a8
void WakeUp(void)
{//(void)
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  d.clockTick = 1;
  d.PartySleeping = 0;
  d.Speed = sw(speedTable[gameSpeed].vblPerTick);
  FloorAndCeilingOnly();
  d.PrimaryButtonList = &d.Buttons17196[0];
  d.SecondaryButtonList = &d.Buttons17304[0];
  d.pKeyXlate2 = (KeyXlate *)&d.Byte18400;
  d.pKeyXlate1 = (KeyXlate *)&d.Byte18428;
  TAG01953a();
  TAG0207cc();
}

i16 TAG0169ec(i32 mapX, i32 mapY)
{
  dReg D6, D7;
  i16  *pwA3;
  D6W = d.NumHistEnt; //entry count
  if (D6W != 0)
  {
    D7W = sw(  ((d.LoadedLevel & 63) << 10)
              | (mapY << 5)
              | (mapX & 31)  );
    pwA3 = &d.Word13268[D6W];
    D6W--;
    do
    {
      pwA3--;
      if (*pwA3 == D7W)
      {
        return sw(D6W + 1);
      };
    } while (D6W-- != 0);
  };
  return 0;
}

void TAG016e54(void)
{//(void)
  dReg D0, D1, D3, D4, D5, D6, D7;
  aReg A0;
  TIMER *ptA2;
  CHARDESC *pcA3;
  RectPos LOCAL_20;
  TIMER LOCAL_12;
  i16 LOCAL_2;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  Instrumentation(icntTAG016e54);
  pcA3 = d.CH16482;
  for (D7W=0; D7W < d.NumCharacter; D7W++, pcA3++)
  {
    D4W = d.PendingOuches[D7W];
    pcA3->ouches |= D4W;
    d.PendingOuches[D7W] = 0;
    D6W = d.PendingDamage[D7W];
    if (D6W == 0) continue;
    d.PendingDamage[D7W] = 0;
    D5W = pcA3->HP;
    if (D5W== 0) continue;
    D5W = sw(D5W - D6W);
    if (D5W <= 0)
    {
      KillCharacter(D7W);
      continue;
    };
    pcA3->HP = D5W;
    pcA3->word48 |= 0x100;
    if (D4W)
    {
      pcA3->word48 |= 0x2000;
    };
    D5L = 69 * D7W;
    LOCAL_20.w.y1 = 0;
    STHideCursor();
    if (D7W + 1 == d.SelectedCharacterOrdinal)
    {
      LOCAL_20.w.y2 = 28;
      LOCAL_20.w.x1 = sw(D5W + 7);
      LOCAL_20.w.x2 = sw(LOCAL_20.w.x1 + 31);
      BLT2Screen(GetGraphicAddress(16), &LOCAL_20, 16, 10);
      if (D6W < 10)
      {
        D5W += 21;
      }
      else
      {
        if (D6W < 100)
        {
          D5W += 18;
        }
        else
        {
          D5W += 15;
        };
      };
      LOCAL_2 = 16;
    }
    else
    {
      LOCAL_20.w.y2 = 6;
      LOCAL_20.w.x1 = D5W;
      LOCAL_20.w.x2 = sw(LOCAL_20.w.x1 + 47);
      BLT2Screen(GetGraphicAddress(15),&LOCAL_20,24,10);
      if (D6W < 10)
      {
        D5W += 19;
      }
      else
      {
        if (D6W < 100)
        {
          D5W += 16;
        }
        else
        {
          D5W += 13;
        };
      };
      LOCAL_2 = 5;
    };
    A0 = TAG014af6(D6W, 0, 3);
    TextOutToScreen(D5W, LOCAL_2, 15, 8, A0);
    D5W = pcA3->timerIndex;
    if (D5W == -1)
    {
      LOCAL_12.timerFunction = timerFunction12;
      D0L = d.Time + 5;
      D1L = d.partyLevel;
      D3L = 24;
      D1L <<= D3W;
      D0L |= D1L;
      LOCAL_12.timerTime = D0L;
      LOCAL_12.timerUByte5 = (i8)D7W;
      pcA3->timerIndex = SetTimer(&LOCAL_12);
    }
    else
    {
      ptA2 = &d.Timers[D5W];
      D0L = d.Time+5;
      D1L = d.partyLevel << 24;
      ptA2->timerTime = D0L | D1L;
      AdjustTimerPosition(FindTimerPosition(D5W));
    };
    DrawCharacterState(D7W);
    STShowCursor();
   //continue here

  };
}


void TAG017274(i32 chIdx,i32 P2)
{//(void)
  CHARDESC  *pch_14;
  TIMER    timer;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  if (chIdx == -1) return;
  if (chIdx+1 == d.PotentialCharacterOrdinal) return;
  pch_14 = &d.CH16482[chIdx];
  DamageCharacter(chIdx, Larger(1, P2/64), 0, 0);
  pch_14->word48 |= 0x100;
  if (    (chIdx+1 == d.SelectedCharacterOrdinal)
       && (d.WpnChestOrScroll == 0)   )
  {
    pch_14->word48 |= 0x800;
  };
  P2--;
  if (P2 != 0)
  {
    pch_14->uByte42++;
    timer.timerFunction = timerFunction75;
    timer.timerUByte5 = (i8)chIdx;
    timer.timerTime = (d.Time+36)|(d.partyLevel<<24);
    timer.timerWord6() = sw(P2);
    SetTimer(&timer);
  };
  DrawCharacterState(chIdx);
}

//   TAG017fa8
void SelectPaletteForLightLevel(void)
{
  dReg D0, D4, D5, D6;
  RN objD0;
  OBJECTTYPE otD0;
  i16  LOCAL_26[8];
  RN   LOCAL_10;
  i16 temp;
  CHARDESC *pCharacter;
  i16 *pwA0, *pwA2, *pwA3;
  i32 totalLight;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  D0W = d.pCurLevelDesc->experienceMultiplier();
  if (D0W == 0)
  {
    d.CurrentPalette = 0;
  }
  else
  {
    pCharacter = &d.CH16482[0];
    pwA3 = LOCAL_26;
    for (D5W=4; (D5W--)!=0; pCharacter++)
    {
      for (D4W=2; (D4W--)!=0; pwA3++)
      {
        objD0 = pCharacter->possessions[D4W];
        LOCAL_10 = objD0;
        otD0 = GetBasicObjectType(objD0);
        if (   (otD0 >= obj_Torch_a)
            && (otD0 <= obj_Torch_d) )
        {
          pwA0 = (i16 *)GetCommonAddress(LOCAL_10);
          *pwA3 = ((DB5 *)pwA0)->charges();
          continue;
        };
        *pwA3 = 0;
      };
    };
    pwA3 = LOCAL_26;
    for (D4W=0; D4W!=4; D4W++, pwA3++)
    { // Find four brightest torches.
      D5W = sw(7 - D4W);
      for (pwA2=&LOCAL_26[D4W+1]; (D5W--)!=0; pwA2++)
      {
        if (*pwA2 > *pwA3)
        {
          temp = *pwA2;
          *pwA2 = *pwA3;
          *pwA3 = temp;
        };
      };
    };
    D6W = 6;
    D4W = 5;
    totalLight = 0;
    for (pwA3=LOCAL_26; (D4W--)!=0; pwA3++)
    {
      if (*pwA3 == 0) continue;
      D0W = d.Word1074[*pwA3];
      D0W <<= D6W;
      D0W = (I16)((D0W >> 6) & 0x3ff); // logical shift
      totalLight += D0W; // Sum of torches
      D6W = sw(Larger(0, D6W-1));

    };
    totalLight += d.Brightness;
    pwA3 = d.PaletteBrightness;
    if (totalLight > 0)
    {
      D4W = 0;
      while (*(pwA3++) > totalLight)
      {
        D4W++;
      };
    }
    else
    {
      D4W = 5;
    };
    d.CurrentPalette = D4W;
  };
  d.Word11778 = 1;
}

//   TAG018124
void NinetySecondUpdate(void)
{ //(void)
  // Decrement bits 10-13 of weapon types 4, 5, 6, and 7
  dReg D0, D3, D5, D6, D7;
  OBJECTTYPE otD4;
  DB5      *DB5A2;
  CHARDESC *pcA3;
#ifdef _DEBUG
  verifyppq();
#endif
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  D5W = 0;
  D7W = d.NumCharacter;
  if (d.PotentialCharacterOrdinal != 0) D7W--;
  pcA3 = d.CH16482;
  while ((D7W--) != 0)
  {
    for (D6W=2; (D6W--)!= 0;) // One and zero.  Hands.
    {
      otD4 = GetModifiedObjectType(pcA3->possessions[D6W]);
      if (otD4 < obj_Torch_a) continue;
      if (otD4 > obj_Torch_d) continue;
      DB5A2 = GetRecordAddressDB5(pcA3->possessions[D6W]);
      D0W = DB5A2->charges();
      if (D0W == 0) continue;
      D3W = (I16)((D0W-1) & 15);
      //D3W <<= 10;
      //dbA2->word(2) &= 0xc3ff;
      //dbA2->word(2) |= D3W;
      DB5A2->charges(D3W);
      if (D3W == 0)
      {
        DB5A2->important(false);
      };
      D5W = 1;
//
    };
    pcA3++;

  };
  //if (0)
  //{
  //};
  //if (D5W != 0)
  {
    SelectPaletteForLightLevel();
    DrawEightHands();
  };
}


void TAG019018(void)
{
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  TAG0189d4();
  MarkViewportUpdated(0);
  STShowCursor();
}


void TAG019264(void)
{//(void)
  RN objD7;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  DrawSmallIcon(obj_Special_d, 12, 13);//Eye back to normal.
  ASSERT(RememberToPutObjectInHand == -1);
  if (d.objectInHand == d.objOpenChest) RepackChest();
  TAG0189d4();
  MarkViewportUpdated(0);
  objD7 = d.objectInHand;
  if (objD7 != RNnul)
  {
    DrawNameOfHeldObject(objD7);
  };
  STShowCursor();
}
//*********************************************************
//
//*********************************************************
void TAG0192f4(i32 chIdx)
{//(void)
  dReg D0, D6;
  CHARDESC *pcA3;
  i32 itemNum;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  if (chIdx != 4)
  {
    D0W = d.CH16482[chIdx].HP;
    if (D0W == 0) return;
  };
  if (d.Word11760 != 0) return;
  if (d.Word11756 != 0) return;
  d.clockTick = 1;
//
//
  D6W = d.SelectedCharacterOrdinal;
  if ((chIdx+1) == D6W)
  {
    chIdx = 4;
  };
  STHideCursor();
  if (D6W)
  {
    d.SelectedCharacterOrdinal = 0;
    if (TimerTraceActive)
    {
      fprintf(GETFILE(TraceFile),"%06x TAG0192f4 calling Repack Chest\n",d.Time);
    };
    RepackChest();
    pcA3 = &d.CH16482[D6W-1];
    if (pcA3->HP)
    {
      if (d.PotentialCharacterOrdinal == 0)
      {
        pcA3->word48 |= 0x1000;
        DrawCharacterState(D6W-1);//box at top, pos, dir,weapon
      };
    };
    if (d.PartySleeping)
    {
      STShowCursor();
      return;
    };
    if (chIdx == 4)
    {
      d.Word11746 = 1;
      DrawMovementButtons();
      STShowCursor();
      d.SecondaryButtonList = d.Buttons17304;
      d.pKeyXlate1 = d.Byte18428;
      TAG01953a();
      FloorAndCeilingOnly(); //Clears viewport to floor and ceiling
    return;
    };
  };
  d.UseByteCoordinates = 0;
  d.SelectedCharacterOrdinal = sw(chIdx + 1);
  if (D6W == 0)
  {
    ShadeRectangleInScreen((RectPos *)d.Word28, 0);
  };
  pcA3 = &d.CH16482[chIdx];
  TAG022a60(17, d.pViewportBMP);
  if (d.PotentialCharacterOrdinal)
  {
    FillRectangle(d.pViewportBMP, (RectPos *)d.Byte1094, 12, 112);
  };
  TextToViewport(5, 116, 13, "HEALTH");
  TextToViewport(5, 124, 13, "STAMINA");
  TextToViewport(5, 132, 13, "MANA");

  for (itemNum=0; itemNum<30; itemNum++)
  {
    DisplayBackpackItem(chIdx, itemNum);
  };
  pcA3->word48 |= 0x5b80;
  //NotImplemented(0x99977b);//wvbl(_1_);
  DrawCharacterState(chIdx); // Box at top,pos,dir,weapon

  d.NewCursorShape = 1;
  STShowCursor();
  d.SecondaryButtonList = d.Buttons17760;
  d.pKeyXlate1 = NULL;
  TAG01953a();
  return;
}

i16 TAG0194c0(pnt)
{
  d.Word4012 = 3217;
  d.Word19218 = 12777;
  return 1;
}

void TAG01953a(void)
{
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  while (UI_CONSTAT()!=0) UI_DIRECT_CONIN();
  {

  };
  d.MouseInterlock = 1;
  d.MouseQStart = 0;
  d.MouseQEnd = 4;
  d.MouseInterlock = 0;
}

i16 SearchButtonList(btn *ent,i32 x,i32 y,i32 buttons) //TAG019570
{
  dReg D0, D4, D5, D6, D7;
// ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  //SaveRegs(0x0f10);
  //A3 = firstEnt;
  D7W = sw(x);
  if ( (D7W >= 512) && (D7W <= 515)) D7W = 0xee;
  D6W = sw(y);
  D5W = sw(buttons);
  if ((ent == NULL) || (d.Word16868 != 0))
  {
    D0L=0;
  }
  else
  {
    while ((D4W = ent->word0) != 0)
    {
      if (   (D7W <  ent->xMax)
          && (D7W >= ent->xMin)
          && (D6W >= ent->yMin)
          && (D6W <  ent->yMax) )
      {


        if (D5W & ent->button) break;
      }
      ent++;
    };
    D0W = D4W;
  };
  //RestoreRegs(0x08f0);
  return D0W;
}

//   TAG0195da
void OnMouseClick(i32 x,i32 y,i32 buttons)
{
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  dReg D0, D4, D5, D6, D7;
  //SaveRegs(0x0f00);
  D7W = sw(x);
  D6W = sw(y);
  if (d.MouseInterlock != 0)
  {
    d.FakeMouseClick = 1;
    d.FakeMouseX = D7W;
    d.FakeMouseY = D6W;
    d.FakeMouseButton = sw(buttons);
    D0W = d.Word16868;
  }
  else
  {
    d.MouseInterlock = 1;
    D0W = D5W = sw(d.MouseQEnd + 2);
    if (D0W > 4) D5W -= 5;
  D0W = D5W;
    if (D0W != d.MouseQStart)
    { //We cannot make End = Start-1 because that means empty!
      D4W = SearchButtonList(d.PrimaryButtonList,
                              D7W,
                              D6W,
                              buttons);
      if (D4W == 0)
      {
      D4W = SearchButtonList(d.SecondaryButtonList,
                              D7W,
                              D6W,
                              buttons);
      };
      if (D4W != 0)
      {
        D5W--;
        if (D5W < 0) D5W = 4;
        d.MouseQEnd = D5W;
      //A0 = d.Pointer16848 + D5W * 6;
        d.MouseQueue[D5W].num = D4W;
      //A0 = d.Pointer16852 + D5W * 6;
        d.MouseQueue[D5W].x = D7W;
      //A0 = d.Pointer16850 + 6 * D5W;
        d.MouseQueue[D5W].y =  D6W;
      };
      d.MouseInterlock = 0;
    };
  };
  //RestoreRegs(0x00f0);
}


//   TAG0196b6
void CauseFakeMouseClick(void)
{
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  if (d.FakeMouseClick != 0)
  {
    d.FakeMouseClick = 0;
    OnMouseClick(d.FakeMouseX,
                 d.FakeMouseY,
                 d.FakeMouseButton);
  };
}

//   TAG01979c
RESTARTABLE _FlashButton(const i32 x1,
                         const i32 x2,
                         const i32 y1,
                         const i32 y2)
{//(void)
  RESTARTMAP
    RESTART(1)
  END_RESTARTMAP
  while (d.FlashButnActive != 0) {};
  d.FlashButnX1 = sw(x1);
  d.FlashButnX2 = sw(x2);
  d.FlashButnY1 = sw(y1);
  d.FlashButnY2 = sw(y2);
  d.FlashButnActive = 1;
  wvbl(_1_);
  display();
  RETURN;
}

//   TAG0197f6
void TraverseStairway(i32 UpOrDown, bool setFacing)
{ //(void)
  // non-zero =decrement level = up
  i32 x, y;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  MoveObject(RN(RNnul), d.partyX, d.partyY, -1, 0);
  // Compute relative x and y on the new level.
  x = d.partyX;
  y = d.partyY;
  d.Word11748 = IncrementLevel(d.partyLevel,
                               UpOrDown == 0 ? 1 : -1,
                               &x,
                               &y);
  d.partyX = sw(x);
  d.partyY = sw(y);
  LoadLevel(d.Word11748);
  if (setFacing)
  {
    SetPartyFacing(ExitStairsDirection(d.partyX, d.partyY));
  };
  LoadLevel(d.partyLevel);
}

//   TAG01986c
RESTARTABLE _TurnParty(const i32 direction)
{ //(void)
  // 1 = left
  // 2 = right
  static dReg D0, D7;
  static i32 deltaFacing;
  RESTARTMAP
    RESTART(2)
    RESTART(3)
  END_RESTARTMAP
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  if (extraTicks)
  {
    d.clockTick = 1;
  };
  if (direction ==1) // Turn left
  {
    FlashButton(_2_,0xea, 0x0105, 0x7d, 0x91);
  }
  else // Turn right
  {
    FlashButton(_3_,0x123, 0x13e, 0x7d, 0x91);
  };
  D0W = GetCellFlags(d.partyX, d.partyY);
  D7W = (I16)(D0W & 0xff);
  if (BITS5_15(D0W) == 3)
  {
    TraverseStairway(D7W & 4); //non-zero = down
  }
  else
  {
    PlaceObjectInRoom(d.partyX,
                      d.partyY,
                      RN(RNnul),
                      1,  // In current room
                      0); // Not a loose object
    if (direction == 2)
    {
      deltaFacing = 1; // Increment to facing
    }
    else
    {
      deltaFacing = 3; // Increment to facing
    };
    SetPartyFacing((d.partyFacing + deltaFacing) & 3);
    PlaceObjectInRoom(d.partyX,
                      d.partyY,
                      RN(RNnul),
                      1,         // In current room
                      1);        // Loose object
  };
  RETURN;
}

//*********************************************************
//
//*********************************************************
//   TAG01992e
RESTARTABLE _MoveParty(const i32 button)
{//(void)
  // 03 Move forward
  // 04 Slide right
  // 05 Move backward
  // 06 Slide Left
  // 0x1124 Move Down
  // 0x1125 Move Up
  static dReg D0, D5, D7;
  static ROOMTYPE rtD6;
  static RN objD0;
  static i32 charIdx;
  static i32 i;
  static bool bD0, bD5;
  static ui16 LOCAL_30;
  static i32 maxLoad;
  static i16 LOCAL_10;
  static i16 LOCAL_8;
  static bool startingInStairwell; //LOCAL_6
  static i32 newY;
  static i32 newX;
  static CHARDESC *pCharacter;
  static MOVEBUTN *pmpA2;
  static i32 direction;
  static i32 newLevel;
  static i32 absdir;
  static i32 axis;
  static i32 delta;
  RESTARTMAP
    RESTART(1)
  END_RESTARTMAP
  direction = button;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  if (TimerTraceActive)
  {
    char *pdir;
    fprintf(GETFILE(TraceFile),"MoveParty ");
    switch(direction)
    {
    case 3: pdir="forward"; break;
    case 4: pdir="right";   break;
    case 5: pdir="backward";break;
    case 6: pdir="left";    break;
    default:pdir="????";
    };
    fprintf(GETFILE(TraceFile),"%s from ", pdir);
    fprintf(GETFILE(TraceFile),"%02x(%02x,%02x)\n",
            d.partyLevel,d.partyX,d.partyY);
  };
  if (direction == 0x1124) direction = 7;
  if (direction == 0x1125) direction = 8;
  direction -= 3;
  if (!gravityMove)
  {
    switch (direction)
    {
    case 0:
    case 1:
    case 2:
    case 3: absdir = (direction + d.partyFacing) & 3;
            axis = (absdir + 1) & 1;
            delta = ((absdir+1) & 2)>>1;
            break;
    case 4: 
    case 5: absdir = direction; 
            axis = 2;
            delta = (absdir & 1) ^ 1;
            break;
    };
    //       n,e,s,w,u,d
    //absdir 0,1,2,3,4,5
    //axis   1,0,1,0,2,2
    //delta  0,1,1,0,0,1
    moveHistory[3] |= 1<<axis;
    if (delta==0) moveHistory[3] ^= 1<<axis;
    if (moveHistory[2] == axis)
    {
      moveHistory[2] = moveHistory[1];
      moveHistory[1] = (char)axis;
    };
    if (moveHistory[1] == axis)
    {
      moveHistory[1] = moveHistory[0];
      moveHistory[0] = (char)axis;
    };
  };

  if (GravityGame)
  {
    gravityMove = true;
    nextGravityMoveTime = d.Time + 2;
  };
  if (extraTicks)
  {
    d.clockTick = 1;
  };
  for (charIdx=0, pCharacter = &d.CH16482[0];
       charIdx < d.NumCharacter;
       charIdx++, pCharacter++)
  {
    maxLoad = MaxLoad(pCharacter); //A multiple of 10. why??
    D0W = sw((3*pCharacter->load)/maxLoad + 1);
    AdjustStamina(charIdx, D0W);

  };

  if ((direction>=0) && (direction<=3))
  {
    pmpA2 = &d.MoveButn18496[direction];
    FlashButton(_1_,
                pmpA2->x1,   // TAG1979c
                pmpA2->x2,
                pmpA2->y1,
                pmpA2->y2);
  };
  D7W = GetCellFlags(newX=d.partyX, newY=d.partyY);//TAG009672
  startingInStairwell = RoomType((ui8)D7W)==roomSTAIRS;//Cell's type
  if (startingInStairwell && (direction==2)) // backward
  {
    if (TimerTraceActive)
    {
      fprintf(GETFILE(TraceFile),"Before TraverseStairway party is at ");
      fprintf(GETFILE(TraceFile),"%02x(%02x,%02x)\n",
             d.partyLevel,d.partyX,d.partyY);
    };
    TraverseStairway(D7W & 4);//non-zero = decrement level = UP
    if (TimerTraceActive)
    {
      fprintf(GETFILE(TraceFile),"After TraverseStairway party is at ");
      fprintf(GETFILE(TraceFile),"%02x(%02x,%02x)\n",
               d.partyLevel,d.partyX,d.partyY);
    };
  }
  else
  {
//
//
//
    if (direction <= 3)
    {
      UpdateXY( //TAG009622
            d.partyFacing,
            d.Word18560[direction], // #steps forward (-1, 0, or 1)
            d.Word18568[direction], // #steps right (-1, 0, or 1)
            &newX,   // original x to be updated
            &newY);  // original y to be updated
      D7W = GetCellFlags(newX, newY);
      rtD6 = RoomType(D7UB);
    }
    else
    {
      UpdateXY(direction,&newLevel,&newX,&newY);
      if (  (newLevel > d.dungeonDatIndex->NumLevel()-1)
          ||(newLevel < 0)
         )
      {
        rtD6 = roomSTONE;
      }
      else
      {
        if (direction == 5)
        {
          D7W = *GetCellFlagsAddress(newLevel,newX,newY);
        }
        else
        {
          D7W = *GetCellFlagsAddress(d.partyLevel,d.partyX,d.partyY);
        };
        rtD6 = RoomType(D7UB);
        switch (rtD6)
        {
        case roomPIT: break;
        default: rtD6 = roomSTONE; break;
        };
      };
      if (    (rtD6 != roomSTONE)
           && FindFirstMonster(newLevel, newX, newY) != RNeof
         )
      {
        RETURN;
      };
    };
    if (   (rtD6 == roomSTAIRS) 
        || ((rtD6 != roomSTONE) && (direction>3)))
    {
      if (direction <= 3)
      {
        //First, move party into stairwell
        MoveObject(RN(RNnul),d.partyX,d.partyY,-1,0);
        d.partyX = sw(newX);
        d.partyY = sw(newY);
        //Then move party to new level.
        TraverseStairway(D7W&4);//non-zero = decrement level = UP
      }
      else
      {
        TraverseStairway(direction-4, false);
      };
    }
    else
    {
      D5W = 0;
      if (rtD6 == roomSTONE) // Stone wall
      {
        D5W = 1; // Inhibit movement.
      }
      else
      {
        if (rtD6 == roomDOOR)
        {
          i32 doorCondition = D7W & 7;
          D5W = (   (doorCondition!=0)
                  && (doorCondition!=1)
                  && (doorCondition!=5));
          //D5W = D7W & 7;//Door type
          //bD0 = D5W!=0; //???
          //if (bD0)
          //{
            //bD0 = D5W!=1;
          //};
          //if (bD0)
          //{
            //bD0 = D5W!=5;
          //};
          //D5W = bD0;
        }
        else
        {
          if (rtD6 == roomFALSEWALL)
          {
            bD5 = (D7W&4)==0;
            if (bD5)
            {
              bD5 = (D7W&1)==0;
            };
            D5W = bD5; // passable if bit 2 set or bit 0 set
          };
        };
      };
      if (d.NumCharacter != 0)
      {
        if (D5W != 0) // Inhibit movement
        {

          dReg D5;
          // Find which side of new cell we are crossing
          direction = direction + (d.partyFacing + 2);
//
//
          LOCAL_8 = GetCharacterToDamage(
                       newX,
                       newY,
                       direction & 3);
          D5W = sw(DamageCharacter(LOCAL_8, 1, 24, 2));//TAG017068
          LOCAL_10 = GetCharacterToDamage(
                newX,
                newY,
                (direction+1) & 3);
          LOCAL_30 = LOCAL_10;
          if (LOCAL_8 != LOCAL_30)
          {
            D5W |= DamageCharacter(LOCAL_10,1,24,2);
          };
          if (D5W != 0)
          {
            QueueSound(18, d.partyX, d.partyY, 0);
          };
        }
        else
        {
          if (direction <= 3)
          {
            objD0 = FindFirstMonster(newX, newY);
            bD0 = objD0 != RNeof;
            D5W = bD0;
          };
          if (D5W != 0)
          {
            ProcessTimers29to41(newX, newY, timerFunctionM1, 0);
          };
        };
      }
      else
      {
        if (direction > 3) RETURN;
      };
      if (D5W != 0)
      {
        TAG01953a();
        d.clockTick = 0;
      }
      else
      {
        if (startingInStairwell)
        {
          MoveObject(RN(RNnul), -1, 0, newX, newY);
        }
        else
        {
          MoveObject(RN(RNnul),d.partyX,d.partyY,newX,newY);
        };
        D7W = 1;
        for (i=0, pCharacter=d.CH16482;
             i < d.NumCharacter;
             i++, pCharacter++)
             {  // Find slowest character
          if (pCharacter->HP != 0)
          {
            D0W = TimeToMove(pCharacter); // Speed of character
            D7W = sw(Larger(D7W, D0W));
          };
//
        };
        d.Word11710 = D7W;
        d.Word11712 = 0;
      };
    };
  };
  RETURN;
}
//*********************************************************
//
//*********************************************************
void TAG019c34(i32 button,i32 clickX, i32 clickY)
{//(void)
  dReg D5, D6, D7;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  D7W = sw(clickX);
  D6W = sw(clickY);
  if (button+1 == d.SelectedCharacterOrdinal)
  {
    SetHandOwner(button);
  }
  else
  {
    D5W = SearchButtonList(d.Buttons18216,D7W, D6W,2);
//
    if ( (D5W>=16) && (D5W<=19) )
    {
      SetHandOwner(D5W-16);
    }
    else
    {
      if ( (D5W>=20) && (D5W<=27) )
      {
        HandleClothingClick(D5W-20);
      };
    };
  };
}

//*********************************************************
//
//*********************************************************
//   TAG019cb2
void SetHandOwner(i32 chIdx)
{//(void)
  dReg D1, D6;
  CHARDESC *pcA3;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  //D7W = P1;
  if (chIdx == d.HandChar) return; //owner of cursor
  if ( (chIdx != -1) && (d.CH16482[chIdx].HP==0) ) return;
  if (d.HandChar != -1) //owner of cursor
  {
    D6W = d.HandChar; //owner of cursor
    d.CH16482[D6W].word48 |= 0x280;
    ASSERT(RememberToPutObjectInHand == -1);
    D1L = GetObjectWeight(d.objectInHand);
    d.CH16482[D6W].load = sw(d.CH16482[D6W].load - D1W);
    d.HandChar = -1; //owner of cursor
    DrawCharacterState(D6W);//box at top,pos,dir,weapon
  };
  if (chIdx == -1)
  {
    d.HandChar = -1;//owner of cursor
    return;
  };
  d.HandChar = sw(chIdx);//owner of cursor
  pcA3 = &d.CH16482[chIdx];
  pcA3->facing = (ui8)d.partyFacing;
  ASSERT(RememberToPutObjectInHand == -1);
  D1L = GetObjectWeight(d.objectInHand);
  d.CH16482[chIdx].load = sw(d.CH16482[chIdx].load + D1W);
  if (chIdx+1 == d.PotentialCharacterOrdinal) return;
  pcA3->word48 |= 0x680;
  DrawCharacterState(chIdx);//box at top,pos,dir,weapon
}

//*********************************************************
//
//*********************************************************
void TAG0196da(i32 key)
{
  dReg D0, D5, D6;
  KeyXlate *pxA3;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  pxA3 = d.pKeyXlate2;
  if (pxA3 != NULL)
  {
    d.MouseInterlock = 1;
    if ((key&0xffff) == 0) key >>= 8; // Move scan code to lower word
    {
    };
    D0W = sw(d.MouseQEnd+2);
    D6W = D0W;
    if (D0W > 4) D6W -= 5;
    if (D6W != d.MouseQStart)
    {
      while ((D5W = pxA3->mouse) != 0)
      {
        if (pxA3->keyscan == (key&0xffff))
        {
          D0W = D6W;
          D6W--;
          if (D0W == 0) D6W = 4;
          d.MouseQEnd = D6W;
          d.MouseQueue[D6W].num = D5W;
          break;
        };
        pxA3++;

      };
      pxA3 = d.pKeyXlate1;
      if (pxA3 != NULL)
      {
        while ((D5W = pxA3->mouse) != 0)
        {
          if ((key&0xffff) == pxA3->keyscan)
          {
            D0W = D6W;
            D6W--;
            if (D0W == 0) D6W = 4;
            d.MouseQEnd = D6W;
            d.MouseQueue[D6W].num = D5W;
          };
          pxA3++;
        };
      };
      if (ThreeDMovements)
      {
        if (   (key == 0x4a00)
            || (key == 0x4900)
           )
        {
          if (key == 0x4a00) D5W = 0x1125; //Up
          if (key == 0x4900) D5W = 0x1124; //Down
          D0W = D6W;
          D6W--;
          if (D0W == 0) D6W = 4;
          d.MouseQEnd = D6W;
          d.MouseQueue[D6W].num = D5W;
        };
      };
    };
    d.MouseInterlock = 0;
    CauseFakeMouseClick();
  };
}

//*********************************************************
//
//*********************************************************
RESTARTABLE _TAG01a6ea(const i32 mouseX, const i32 mouseY)
{//(void)
  static dReg D0, D4, D5, D6, D7;
  RESTARTMAP
    RESTART(1)
  END_RESTARTMAP
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  D7W = sw(mouseX);
  D6W = sw(mouseY);
  D4W = sw((d.HandChar == -1) ? 1: 0); //owner of cursor
  D0W = d.WpnChestOrScroll;
  if (D0W == 4) //If displaying chest in weapon hand
  {
    if (D4W != 0) RETURN;
    D5W = SearchButtonList(d.Buttons18324,D7W, D6W,2);
    if (D5W)
    {
      //D0W = D5W - 20;
      HandleClothingClick(D5W-20);
    };
  }
  else
  {
    if (D0W == 5)
    {
      if (d.EmptyHanded)
      {
        D5W = SearchButtonList(d.Buttons18372, D7W, D6W, 2);
        if (D5W)
        {
          TAG014368(_1_, D5W);
        };
      };
    };
  };
  RETURN;
}

//*********************************************************
//
//*********************************************************
//   TAG01a77c
void DisplaySleepScreen(void)
{
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  Flood(d.pViewportBMP, 0, 1904);
  TextOut(d.pViewportBMP,
          112,
          93,
          65,
          4,
          0,
          "WAKE UP");
}

//*********************************************************
//
//*********************************************************
//   TAG0197d2
void WaitForButtonFlash(void)
{//(void)
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  Instrumentation(icntTAG0197d2);
  while (d.FlashButnActive != 0)
  {
    NotImplemented(0x197dc); //pumper();
  };



  /* I am going to attempt to write this differently
     so that WaitForButtonFlash does not have to
     be restartable.  God help me.
  if (d.Word11776 != 0)
  {
    d.FlashButnActive = 1;
    wvbl(_1_);
  };
*/
      //Here is the attempted rewrite.
      //We will call CheckVBL and sleep until
      //the vbl count is increased.
      if (d.Word11776 != 0)
      {
        ui32 oldCount;
        d.FlashButnActive = 1;
        oldCount = VBLCount+1;
        //checkVBL(); //Give it a chance to happen right now!
        //Make sure we wait at least 20 milliseconds.
        while (oldCount > VBLCount)
        {
          if (VBLMultiplier == 1) UI_Sleep(20);
          checkVBL();
        };
      };
      //OK...Let us see if that works.




  return;
}

//*********************************************************
//
//*********************************************************
//   TAG01ad6c
pnt GetAttackTypeName(i32 P1)
{
  dReg D7;
  aReg A3;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  D7W = (I16)(P1 & 0xff);
  if (D7W == 255)
  {
    return "";
  }
  else
  {
    for (A3 = d.AttackNames; D7W-- != 0; )
    {
      while ( *(A3++) != 0) {}; // Skip one string
    };
    return A3;
  };
}

//*********************************************************
//
//*********************************************************
//   TAG01b098
void DrawLegalAttackTypes(void)
{
	// This function just draws clicked item`s options in the place of
	// four hands.
  dReg D7;
  RectPos *prA3;
  pnt pName;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  STHideCursor();
  d.UseByteCoordinates = 0;
  FillRectangle(d.LogicalScreenBase,
                (RectPos *)d.Word20,
                0,
                160);
  if (d.Word20252)
  {
    for (D7W=0; D7W<d.NumCharacter; D7W++)
    {
      DrawAttackButton(D7W);

    };
  }
  else
  {
    if (d.AttackingCharacterOrdinal)
    {
      prA3 = &d.wRectPos20202;
      if (d.PossibleAttackTypes[2] == -1)
      {
        prA3 = &d.wRectPos20210;
      };
      if (d.PossibleAttackTypes[1] == -1)
      {
        prA3 = &d.wRectPos20218;
      };
      BLT2Screen(GetGraphicAddress(10),
                prA3,
                48,
                -1);
      DrawNameOfHeldObject(
                d.LogicalScreenBase,
                160,
                235,
                83,
                0,
                4,
                d.CH16482[d.AttackingCharacterOrdinal-1].name,
                7);


      for (D7W=0; D7W<3; D7W++)
      {
        pName = GetAttackTypeName(d.PossibleAttackTypes[D7W]);
        DrawNameOfHeldObject(
                  d.LogicalScreenBase,
                  160,
                  241,
                  12 * D7W + 93,
                  4,
                  0,
                  pName,
                  12);

      };
    };
  };
  STShowCursor();
  d.Word20250 = 0;
}

//*********************************************************
//
//*********************************************************
RESTARTABLE _TAG01b29a(void)
{//(void)
  static dReg D0, D1, D7;
  static CHARDESC *pcA3=NULL;
  RESTARTMAP
    RESTART(1)
  END_RESTARTMAP
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  if (d.NumCharacter == 0) RETURN;
  if ( (d.PartySleeping) || (d.PotentialCharacterOrdinal) )
  {
    if (d.AttackingCharacterOrdinal)
    {
      TAG01b1c0();
      RETURN;
    };
    if (d.PotentialCharacterOrdinal == 0) RETURN;
  }
  else
  {
    pcA3 = d.CH16482;
    for (D7W=0; D7W<d.NumCharacter; D7W++, pcA3++)
    {
      if (D7W != d.HandChar) //owner of cursro
      {
        if (D7W+1 != d.AttackingCharacterOrdinal)
        {
          if (pcA3->uByte41)
          {
            D0W = pcA3->facing;
            D1W = pcA3->facing3;
            if (D0W != D1W)
            {
              pcA3->facing = pcA3->facing3;
              pcA3->word48 |= 0x400;
              DrawCharacterState(D7W);//box at top,pos,dir.weapon
            };
          };
        };
      };
      pcA3->uByte41 = 0;
    };
  };
  if (d.Word20250 == 0) RETURN;
  if (d.AttackingCharacterOrdinal == 0)
  {
    if (d.Word20264)
    {
      FlashAttackDamage(_1_,d.Word20264);
      d.Word20264 = 0;
    }
    else
    {
      d.Word20252 = 1;
      DrawLegalAttackTypes();
    };
    RETURN;
  };
  d.Word20252 = 0;
  pcA3->word48 |= 0x8000;
  DrawCharacterState(d.AttackingCharacterOrdinal-1);//box at top, pos, dir,weapon
  DrawLegalAttackTypes();
  RETURN;
}

//*********************************************************
//
//*********************************************************
void TAG01b408(i16 P1)
{
  dReg D0, D1, D5, D6, D7;
  CHARDESC *pcA3;
  i16 LOCAL_12;
  i8  LOCAL_2[2];
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  pcA3 = &d.CH16482[d.MagicCaster];
  if (P1 ==2)
  {
    MemMove(d.Byte21994, d.Byte20842, 576);
    D6W = 1;
    D5W = 6;
    D1W = (UI8)(pcA3->byte33);
    LOCAL_12 = sw(D1W * D5W);
    D5W = 96;
    D5W = sw(D5W + LOCAL_12);
    LOCAL_2[1] = 0;
    for (D7W=0; D7W<6; D7W++)
    {

      LOCAL_2[0] = D5B;
      D5B++;
      D6W += 14;
      TextOut(d.Byte20842, 48, D6W, 8, 4, 0, LOCAL_2);

//
    };
  }
  else
  {
    if (P1 == 3)
    {
      MemMove(d.Byte21418, d.Byte20842, 576);
      LOCAL_2[1] = 0;
      D6W = 8;

      for (D7W=0; D7W<4; D7W++)
      {
        D0B = pcA3->incantation[D7W];
        LOCAL_2[0] = D0B;
        if (D0B == 0) break;
        D6W += 9;
        TextOut(d.Byte20842, 48, D6W, 8, 4, 0, LOCAL_2);

//
      };
    };
  };
}


void TAG01b8ae(void)
{
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  ReadAndExpandGraphic(
          11,          // graphic number
          d.Byte22570, // destination
          0,
          0);
}

//   TAG01b8ca
void DrawSpellMenuCharacters(i16 P1)
{
  dReg D5, D6, D7;
  i8 b_2[2];
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  b_2[1] = 0;
  D5W = sw(6 * P1 + 96);
  D6W = 225;
  for (D7W = 0; D7W < 6; D7W++)
  {
    b_2[0] = (i8)D5W++;
    TextOutToScreen(D6W += 14, 58, 4, 0, b_2);

//
  };
}

void TAG01b990(i16 button)
{//(void)
  dReg D0, D1, D5, D6, D7;
  aReg A0;
  CHARDESC *pcA3;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  pcA3 = &d.CH16482[d.MagicCaster];
  D7W = (UI8)(pcA3->byte33);
  A0 = d.Byte19010 + 6*D7W;
  D6W = (UI8)(A0[button]);
  if (D7W != 0)
  {
    D5W = sw(pcA3->incantation[0] - 96);
    //A0 = d.Byte19016 + D5W;
    D1W = (UI8)(d.Byte19016[D5W]);
    D6W = sw((D6W * D1W) >> 3);
  };
  if (D6W > pcA3->mana) return;
  pcA3->mana = sw(pcA3->mana - D6W);
  pcA3->word48 |=0x100;
  D0W = sw(6 * D7W + 96 + button);
  //A0 = pcA3->byte34 + D7W;
  pcA3->incantation[D7W] = D0B;
  pcA3->incantation[D7W + 1] = 0;
  D7W = (I16)((D7W + 1) & 3);
  pcA3->byte33 = (i8)D7W;
  STHideCursor();
  DrawSpellMenuCharacters(D7W);//Zo, Rath, etc
  DisplayMagicSelection(pcA3);
  DrawCharacterState(d.MagicCaster);
  STShowCursor();
}




//   Tag01cefa
void SubstDiskLetter(pnt dest,pnt src,i16 flag)
{
  aReg A0;
  i16 LOCAL_6;
  pnt LOCAL_4;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  A0 = dest;
  *A0 = 0;
  LOCAL_4 = StrChr(src, '~');
  if (LOCAL_4 != NULL)
  {
    LOCAL_6 = sw(LOCAL_4 - src); // index of tilde in P2
    StrCpy(dest,src,LOCAL_6); // Copy up to tilde
    A0 = dest + LOCAL_6 ;
    *A0 = 0; // mark the end
    if ((d.SingleFloppyDrive) || (flag == 1))
    {
      StrCat(dest, d.Pointer22984);
    }
    else
    {
      StrCat(dest, d.Pointer22988);
    };
    StrCat(dest, LOCAL_4+1);
  };
}

i16 StreamInput(pnt dest,i32 num) //TAG01cf86
{
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  dReg D0, D7;
  D0W = sw(num);
  D0H1 = 0;
  D7 = D0;
  if (D0L == 0) return 1;
  if (d.inStreamBuffered != 0)
  {
    if (D7L > d.inStreamLeft) return 0;
    MemMove(d.inStreamNext, dest, D7W);
    d.inStreamNext += D7L;
    d.inStreamLeft -= D7L;
    return 1;
  };
  D0L = READ(d.datafileHandle, D7L, dest);
  D0W = sw(D0L==D7L ? 1 : 0);
  return D0W;
}

// TAG01d048

i16 Unscramble(pnt buf, i32 initialHash, i32 numword)
{
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  dReg D5, D6, D7;
  aReg A3;
  A3 = buf;
  D7W = (UI16)initialHash;
  D6W = sw(numword);
  D5W = (UI16)initialHash;
  do
  {
    D5W = (UI16)(D5W + LE16(wordGear(A3)));
    //D0W = D7W;
    wordGear(A3) ^= LE16(D7W);
    D5W = (UI16)(D5W + LE16(wordGear(A3)));
    A3 += 2;
    D7W = (UI16)(D7W + D6W);
    D6W--;
  } while (D6W != 0);
  return D5W;
}

// TAG01d0a4
i16 UnscrambleStream(pnt dest,i32 size, i16 initialHash, i16 Checksum)
{
  dReg D0;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  D0W = StreamInput(dest,size);
  if (D0W == 0) return 0;
  D0W = Unscramble(dest, initialHash, size/2);
  if (D0W == Checksum) return 1;
  return 0;
}

i16 FetchDataBytes(i8 *P1,i16 *P2,i32 P3) //TAG01d138
{
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  dReg D0, D6, D7;
  i16 *uwA2;
  aReg A3;
  A3 = P1;
  uwA2 = P2;
  D7W = sw(P3);
  D6W = 0;
  D0W = StreamInput(A3, D7W);
  if (D0W == 0)
  {
    D0W = 0;
  }
  else
  {
    while (D7W != 0)
    {
      D7W--;
      D6W = (UI16)(D6W + *((ui8 *)A3));
      A3++;
    };
    *uwA2 = (UI16)(*uwA2 + D6W);
    D0W = 1;
  };
  return D0W;
}

//*********************************************************
//
//*********************************************************
RESTARTABLE _InsertDisk(const i32 P1,const i32 P2)
{//(i16)
  static dReg D0, D5, D6, D7;
  static aReg A3;
  static i8  LOCAL_80[80];
  RESTARTMAP
    RESTART(1)
    RESTART(2)
  END_RESTARTMAP
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  //SaveRegs(0x0710);
  D7W = sw(P1);
  D6W = sw(P2);
  D5W = 1;
  D0W = 0;
  if ((D0W == 0) && (D7W !=2))
  {
    D0W = D5W;
  }
  else
  {
    A3 = NULL;
    SubstDiskLetter(LOCAL_80, d.Pointer22864, 1);
    do
    {
      while (D7W != 0)
      {
        D7W = D5W = 0;
        DoMenu(_2_,
               A3, // TAG01d678
               LOCAL_80,
               d.Pointer22908,
               NULL,
               NULL,
               NULL,
               D6W,
               D6W,
               D6W );
        WaitForMenuSelect(_1_, 1, D6W, 1, 1);
        A3 = d.Pointer22820;
      };
      D0W = 0;
    } while (D0W != 0);
    D0W = D5W;
  };
  //RestoreRegs(0x08e0);
  RETURN_i16(D0W);
}

//*********************************************************
//
//*********************************************************
//  TAG01db46
i16 ReadUnscrambleBlock(pnt P1)
{
  dReg D0, D5, D6, D7;
  aReg A3;
  bool bD0;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  A3 = P1;
  D0W = StreamInput(A3, 512); //TAG01cf86
  if (D0W == 0) return 0;
  for (D7W=32, D6W=0; D7W!=0; D7W--)
  {
    D6W = (UI16)(D6W + LE16(wordGear(A3)));
    A3 += 2;
    D6W ^= LE16(wordGear(A3));
    A3 += 2;
    D6W = (UI16)(D6W - LE16(wordGear(A3)));
    A3 += 2;
    D6W ^= LE16(wordGear(A3));
    A3 += 2;
  };
  Unscramble(A3, LE16(wordGear(P1+58)), 128);
  for (D7W=128, D5W = 0; D7W!=0; D7W--)
  {
    D5W = (UI16)(D5W + LE16(wordGear(A3)));
    A3 += 2;
  };
  bD0 = D6W == D5W;
  D0W = bD0;
  return D0W;
}




//*********************************************************
//
//*********************************************************
//   TAG01f140
RESTARTABLE _DisplayChaosStrikesBack(void)
{//(void)
  static dReg D0, D4, D5, D6, D7;
  static aReg A2, A3;
  static PALETTE  LOCAL_340;
  static str10 LOCAL_308[18]; // 10-byte structures
  static pnt LOCAL_96;
  static pnt LOCAL_92;
  static pnt LOCAL_88[18];
  static pnt screenBuffers[2];
  RESTARTMAP
    RESTART(1)
    RESTART(2)
    RESTART(3)
    RESTART(4)
    RESTART(5)
    RESTART(6)
    RESTART(7)
    RESTART(8)
  END_RESTARTMAP
  d.UseByteCoordinates=0;
  if (d.Long23306 < 138060) RETURN;
  D4L = (i32)allocateMemory(133056,0); // Temporary allocation
  D4L = (D4L + 256) & 0xffffff00; // Round to 256-byte boundary
  A3 = (pnt)D4L;
#ifdef GraphicsDebug
  GrphDbg = GETFILE(CREATE("GraphicsDebug.txt","w"));
#endif
  ReadAndExpandGraphic(1, A3, 0, 0);
#ifdef GraphicsDebug
  fclose(GrphDbg);
  GrphDbg = NULL;
#endif
  D4L += 32000;
  A2 = d.LogicalScreenBase;
  setscreen(NULL, A2, 0);
  screenBuffers[1] = A2;
  screenBuffers[0] = A3;
  LOCAL_92 = A3;
  fillMemory((i16 *)&LOCAL_340, 16, 2, 2); // 16 words  of 0x0002
  FadeToPalette(_1_,&LOCAL_340);  // darken screen
  ClearMemory(A2, 32000);
  TAG0088b2(A3,           // Move "Presents" to video memory
            d.LogicalScreenBase,
            (RectPos *)d.Word52,
            0,      // src x
            137,    // src y offset
            160,    // src bytes/line
            160,    // dst bytes/line
            -1);
  LOCAL_340.color[15] = 0x777;
  FadeToPalette(_3_,&LOCAL_340); // Display "Presents"
  LOCAL_96 = (pnt)D4L;
  TAG0088b2(A3,       //src = graphic 1
	         (pnt)D4L,  //dst
			     (RectPos *)d.Word44, //dest offsets and sizes
			     0,        //src x offset
			     80,       //src y offset
			     160,      //src bytes/line
			     160,      //dst bytes/line
			     -1);           // "Strikes Back"
  D4L += 9120; // =57 * 160
  D6W = 12;
  D5W = 48;
  for (D7W=0; D7W<18; D7W++)
  {
    LOCAL_88[D7W] = (pnt)D4L;
    ShrinkBLT(A3, LOCAL_88[D7W], 320, 80, D5W, D6W, d.Byte156);
    D0W = sw(320 - D5W);
    D0L = D0W;
    D0L /= 2;
    LOCAL_308[D7W].w1 = D0W;
    D0W = sw(D0W + D5L - 1);
    LOCAL_308[D7W].w2 = D0W;
    D0W = sw((160 - D6W)/2);
    LOCAL_308[D7W].w3 = D0W;
    D0W = sw(D0W + D6W - 1);
    LOCAL_308[D7W].w4 = D0W;
    D0W = sw(((D5W+15)/16)*8);
    LOCAL_308[D7W].w5 = D0W;
    D0L = D0W*D6W;
    D0L &= 0xffff;
    D4L += D0L;
    D6L +=4;
    D5L +=16;
  };
  LOCAL_340.color[15] = 2;
  FadeToPalette(_6_,&LOCAL_340); // Remove "Presents"
  ClearMemory(LOCAL_92, 32000);
  setscreen((pnt)-1, LOCAL_92, -1);
  ClearMemory(A2, 32000);
  setscreen((pnt)-1, A2, -1);
  LOCAL_340.color[3] = 0x0541;
  LOCAL_340.color[4] = 0x0421;
  LOCAL_340.color[5] = 0x0651;
  LOCAL_340.color[6] = 0x0531;
  LOCAL_340.color[8] = 0x0772;
  LOCAL_340.color[15] =0x0700;
  LOCAL_340.color[10] = 0x0002;
  LOCAL_340.color[12] = 0x0002;
  FadeToPalette(_7_, &LOCAL_340); // Just delay.
  for (D7W=0; D7W<18; D7W++) // expanding "CHAOS"
  {
    VBLDelay(_2_,2);
    display();
    TAG0088b2(LOCAL_88[D7W],
              screenBuffers[D7W&1],
              (RectPos *)&LOCAL_308[D7W],
              0,
              0,
              LOCAL_308[D7W].w5,
              160,
              -1);
    setscreen((pnt)-1, screenBuffers[D7W&1], -1); // Swap video buffers
  };
  VBLDelay(_4_,10);
  // Put "Strikes Back" on screen.
  TAG0088b2(LOCAL_96,
            d.LogicalScreenBase,
            (RectPos *)d.Word36,
            0,
            0,
            160,
            160,
            0);
  LOCAL_340.color[10] = 0;  // Black print
  LOCAL_340.color[12] = 0x0700;  // Red background
  FadeToPalette(_8_,&LOCAL_340);
  VBLDelay(_5_,20);
  FreeTempMemory(133056); // Release temporary memory:
  //D4=saveD4;D5=saveD5;D6=saveD6;D7=saveD7;A2=saveA2;A3=saveA3;
  RETURN;
}

//*********************************************************
//
//*********************************************************
RESTARTABLE _OpenPrisonDoors(void) //TAG01f47a
{//(void)
  static dReg D7;
  static aReg A0, A1, A3;
  static pnt LOCAL_4, LOCAL_8;
  static int i;
  RESTARTMAP
    RESTART(1)
  END_RESTARTMAP
  A3 = (pnt)&d.Pointer22952; // Prison door left
  LOCAL_4 = d.LogicalScreenBase + 4800;
  LOCAL_8 = pntGear(A3 + 36);
  for (D7W = 1; D7W != 32; D7W++)
  {
    //UI_Sleep(60);
    if ((D7W % 3) ==1)
    {
      StartSound(d.Pointer22964, 145, 1); //Graphic #535 // Start sound
    };
    MemMove(pntGear(A3+32), pntGear(A3+36), 20608); // Dungeon interior.
// I commented this out.. I could see no change.
    TAG0088b2(d.pViewportBMP,  // left part of interior.
              pntGear(A3+36),
              (RectPos *)d.Word60,
              0,
              0,
              112,
              128,
              -1);
    if (((RectPos *)d.Word68)->w.x2 >= 0)
    {
      TAG0088b2(pntGear(A3+(D7W&3)*4), // Left Door
                pntGear(A3+36),
                (RectPos *)d.Word68,
                (D7W&0xfc)*4,
                0,
                64,
                128,
                -1);
      ((RectPos *)d.Word68)->w.x2 -= 4;
    };
    TAG0088b2(pntGear(((D7W&3)+4)*4+A3), // Right side door
              pntGear(A3+36),
              (RectPos *)d.Word76,
              (D7W&3)*4,
              0,
              64,
              128,
              -1);
    ((RectPos *)d.Word76)->w.x1 += 4;
    for (i=0; i<6; i++) wvbl(_1_);
    A0 = LOCAL_4;
    A1 = LOCAL_8;
    for (i32 i=0; i<161; i++)
    {
      memmove(A0, A1, 112); // Move image to physbase
      A1 += 112;
      *(A0+112) = *(A1+0);
      *(A0+114) = *(A1+2);
      *(A0+116) = *(A1+4);
      *(A0+118) = *(A1+6);
      A0 += 160;
      A1 += 16;
    };
  }; // for (D7W)
  //RestoreRegs(0x0880);
  RETURN;
}

//*********************************************************
//
//*********************************************************
RESTARTABLE _TAG01f746(void)
{//(void)
  static aReg A0;
  static RectPos dstPos;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  static dReg D6,D7;
  RESTARTMAP
    RESTART(1)
    RESTART(2)
    RESTART(3)
    RESTART(4)
    RESTART(5)
    RESTART(6)
  END_RESTARTMAP
  //i32 D5;
  d.PrimaryButtonList = d.Buttons16932;
  d.SecondaryButtonList = NULL;
  d.pKeyXlate2 = NULL;
  d.pKeyXlate1 = NULL;
  for (D7W=0; D7W<8; D7W++)
  {
    A0 = allocateMemory(10304, 0); // temporary memory
    (&d.Pointer22952)[D7W] = A0;
//
  };
  d.Pointer22920 = allocateMemory(20608,0);
  d.Pointer22916 = allocateMemory(20608,0);
  ReadAndExpandGraphic(3,d.Pointer22936,0,0);
  ReadAndExpandGraphic(2,d.Pointer22952,0,0);
  D6L = AllocateExpandGraphic(4,&d.Pointer22956);
  D6L += AllocateExpandGraphic(5, &d.Pointer22960);
  D6L += AllocateExpandGraphic(535, &d.Pointer22964);
        // Open prison door sound
  D6L =+ AllocateExpandGraphic(534, &d.Pointer22968);
  closeGraphicsFile();
  d.UseByteCoordinates = 0;
  dstPos.w.x1 = 0;
  dstPos.w.x2 = 100;
  dstPos.w.y1 = 0;
  dstPos.w.y2 = 160;
  for (D7W=1; D7W<4; D7W++)
  {
    TAG0088b2(d.Pointer22952,
              (&d.Pointer22952)[D7W],
              &dstPos,
              D7W*4,0,64,64,-1);
    dstPos.w.x2 -= 4;

  };
  dstPos.w.x2 = 127;
  for (D7W=5; D7W<8; D7W++)
  {
    dstPos.w.x1 += 4;
  TAG0088b2(d.Pointer22936,
            (&d.Pointer22952)[D7W],
            &dstPos,
            0,0,64,64,-1);

  };
  do
  {
  TAG01f5ea(_1_); //Remove "CHAOS" display, Show Prison door.
  STShowCursor(); //TAG003026
  UI_BeginRecordOK(true);
  TAG01953a();
  d.dungeonFormat = 99;
    do
    {
      wvbl(_2_);
      HandleMouseEvents(_4_,0); //TAG01a7b2();
      if (DiskMenuNeeded) DisplayDiskMenu(_6_);
    } while (d.dungeonFormat == 99);
  } while (d.dungeonFormat == 202);
  UI_BeginRecordOK(false);
  StartSound(d.Pointer22968, 112, 1); // Start sound
  VBLDelay(_3_,20); // 20 vertical blanks
  STHideCursor();//TAG002fd2
  if (d.dungeonFormat != 0)
  {
    OpenPrisonDoors(_5_);
  };
  FreeTempMemory(D6L + 82432 + 41216);
  RETURN;
}

//*********************************************************
//
//*********************************************************
RESTARTABLE _TAG01f5ea(void)
{//(void)
  static dReg D7;
  static aReg A0;
  static LEVELDESC LOCAL_170;
  static i8  LOCAL_154[5][5];
  static CELLFLAG *LOCAL_128[5];
  RESTARTMAP
    RESTART(1)
    RESTART(2)
  END_RESTARTMAP
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  //i32 saveD7=D7;
  d.partyLevel = 255;
  d.Word11684 = 1;
  d.width  = 5;
  d.height = 5;
  d.LevelCellFlags = LOCAL_128;
  d.pCurLevelDesc = &LOCAL_170;
  fillWithByte(LOCAL_154[0], 25, 0, 1);
  for (D7W=0; D7W<5; D7W++)
  {
    A0 = LOCAL_154[0] + 5*D7W;
    LOCAL_128[D7W] = (CELLFLAG *)A0;
    LOCAL_154[2][D7W] = 32;

  };
  LOCAL_154[1][2] = 32;
  FadeToPalette(_1_,&d.Palette11914);
  //
  // Entrance to prison without door.
  ExpandGraphic(d.Pointer22956, d.LogicalScreenBase, 0, 0);
  DrawViewport(2, 2, 0); //facing south, x=y=0.
  d.ViewportUpdated = 0;
  d.UseByteCoordinates = 0;
  //
  //
  TAG0088b2(d.LogicalScreenBase, // Save interior prison entrance
            d.Pointer22920,
            (RectPos *)d.Word84,
            0,   // src x
            30,  // src y
            160, // src bytes/line
            128, // dst bytes/line
            -1);
  //
  //Put left half of door in opening
  BLT2Screen(d.Pointer22952, (RectPos *)d.Word92, 64, -1);
  //
  // Put right half of door in opening
  BLT2Screen(d.Pointer22936, (RectPos *)d.Word100, 64, -1);
  //
  // Display prison entrance.
  FadeToPalette(_2_,&d.Palette360);
  //D7=saveD7;
  RETURN;
}

//*********************************************************
//
//*********************************************************
i32 AllocateExpandGraphic(i16 graphicNum, pnt *address) // TAG01f6fe
{ // Returns size of resulting graphic
  dReg D0;
  aReg A0;
  i32 graphicSize;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  D0L = GetGraphicExpSize(graphicNum);
  graphicSize = D0L;
  A0 = allocateMemory(D0L, 0);
  *address = A0;
  ReadAndExpandGraphic(graphicNum | 0x8000,A0, 0, 0);
  return graphicSize;
}

//*********************************************************
//
//*********************************************************
RESTARTABLE _TAG01f928(void)
{//(void)
  static dReg D0;
  static i16 LOCAL_2=0;
  RESTARTMAP
    RESTART(1)
    RESTART(2)
    RESTART(3)
  END_RESTARTMAP
  STHideCursor();//TAG002fd2
  FadeToPalette(_1_,&d.Palette11914); //
  ExpandGraphic(d.Pointer22960,d.LogicalScreenBase,0,0);
  FadeToPalette(_2_,&d.Palette328);
  do
  {
    wvbl(_3_);
  D0W = --LOCAL_2;
    if (D0W == 0) break;
    if (d.MouseSwitches != 0) break;
  } while (UI_CONSTAT()==0); // keyboard
  d.dungeonFormat = 202;
  RETURN;
}

class ATARIMEM
{ // We put this in a class so that the destructor
  // will happily release the memory.  Keeps debug
  // aids quiet.
  char *m_mem;
public:
  ATARIMEM(void) {m_mem=NULL;};
  ~ATARIMEM(void) {if (m_mem!=NULL) UI_free (m_mem);};
  char *mem(i32 size)
  {
    if (m_mem!=NULL) UI_free(m_mem);
    m_mem = (char *)UI_malloc(size);
    return m_mem;
  };
};

ATARIMEM AtariMem;

//   TAG020286
void InitializeHeap(void)
{
  dReg D0, D5,D6,D7;
  aReg A0, A1;
  // i32 D4;
  DisableCursor();
  firstMemoryBlock = NULL;
  D0L = GetAvailMemory();
  D7L = D0L-20;
  SetSupervisorMode();
  A1 = (pnt)0x5000; // System start address
  D6L = 0x19c00; // System end address;
  A0 = (pnt)0x19bf4; // ???
  D5L = 0x19c00; // What is 4(a0) // End of available memory
  D5L -= D6L; // say there is no space above OS
  ClearSupervisorMode();
  InitializeCaches(AtariMem.mem(D7L), D7L, NULL, D5L);
}

//   TAG020466
void CountFloppyDrives(void)
{
  dReg D7;
  //i32 saveD6=D6, saveD7=D7;
  SetSupervisorMode();
  D7W = sw(NumberFloppyDrives);
  ClearSupervisorMode();
  if (D7W == 2)
  {
    d.DualFloppyDrive = 1;
  }
  else
  {
    d.SingleFloppyDrive = 1;
  };
  d.Pointer22984 = "DRIVE.";
  d.Pointer22988 = "DRIVE.";
  //D6=saveD6; D7=saveD7;
}

i8 data2052e[] = {0x05, 0x05, 0x11, 0x1e, 0x2b};
i8 data20577[] = "CSBGAMEx.BAK";

//*********************************************************
//
//*********************************************************
//   TAG0204bc
RESTARTABLE _SelectSaveGame(const i32 P1)
{//(void)
  static dReg D0;
  static aReg A0, A1;
  RESTARTMAP
    RESTART(1)
    RESTART(2)
  END_RESTARTMAP
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  DoMenu(_2_,
         NULL, //TAG01d678
         "SELECT GAME FILE",
         "CSBGAME.DAT",
         "CSBGAME2.DAT",
         "CSBGAME3.DAT",
         "CSBGAME4.DAT",
         P1,
         P1,
         P1);

  WaitForMenuSelect(_1_, 4,P1,2,1) ;
  D0W = i16Result;
  switch (D0W)
  {
  case 1: A0 = "CSBGAME.DAT"; break;
  case 2: A0 = "CSBGAME2.DAT"; break;
  case 3: A0 = "CSBGAME3.DAT"; break;
  case 4: A0 = "CSBGAME4.DAT"; break;
  default: A0 = "Huh"; NotImplemented(0x20502);
  }
  d.SaveGameFilename = A0;
  A1 = data20577;
  do
  {
    *(A1++) = *A0;
  } while ( *(A0++) != 46); // until period
  *(A1++) = 66;
  *(A1++) = 65;
  *(A1++) = 75;
  *(A1) = 0;
  d.Pointer22980 = data20577;
  RETURN;
}

//*********************************************************
//
//*********************************************************
void getBits(i32 numbits, dReg& D0, dReg& D1, aReg& A3)
// internal subroutine for TAG0206f8
{ // Bits added to D1U and swapped to D1W
  // D0 keeps track of number of bits remaining in D1W
  if (D0W < numbits)
  {
    numbits -= D0W;
    D1L <<= D0W;
    D1W = LE16(wordGear(A3));
    A3 += 2;
    D0L = 16; // Number of bits remaining in D1W
  };
  D0W = sw(D0W - numbits);
  D1L <<= numbits;
  // do this in calling routine SWAP(D1); //D1 = (D1U & 0xffff)|((D1W&0xffff)<<16);
}


void ExpandData(pnt src,pnt dst,i32 dstSize) //TAG0206f8
{
  // Data file consists of variable length fields.
  // There are 20 bytes at the beginning that are
  // lookup tables---the first is 4 bytes long
  // and is used to decode data of the form
  // ( in binary ) of 0xx.  xx is the index into the
  // table.
  // The next table is 16 bytes long and is used to
  // decode data of the form 10yyyy where yyyy is used
  // as an index into the table.
  // The only remaining case is data of the form
  // 11zzzzzzzz where zzzzzzzz is a literal byte.
  // Summary:
  // 0xx        index into small table
  // 10yyyy     index into large table
  // 11zzzzzzzz literal data
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  dReg D0, D1, D7;
  aReg A0, A2, A3;
  //SaveRegs(0x0130);
  A3 = src;
  A2 = dst;
  D7L = dstSize;
  A0 = A3;
  A3 = A3 + 20;
  D1H1 = 0;
tag020714: // Start new 16-bit input word.
  D1W = LE16(wordGear(A3));
  A3 += 2;
  D0L = 16; // # bits in D1W;
tag020718: // Is next bit a '1'?
  if ((D1W & 0x8000) == 0) goto tag02073c;
  getBits(2, D0, D1, A3);
  SWAP(D1);
  D1W -= 2;
  if (D1W != 0) goto tag020732;
  SWAP(D1);
  getBits(4, D0, D1, A3);
  SWAP(D1);
  *A2 = *(A0 + D1W + 4);
  A2++;
  goto tag020744;
tag020732:
  SWAP(D1);//D1L = D1UH[1] | (D1UH[0] << 16);
  getBits(8, D0, D1, A3);
  SWAP(D1);//D1L = D1UH[1] | (D1UH[0] << 16);
  *A2 = D1B;
  A2++;
  goto tag020744;
tag02073c:
  getBits(3, D0, D1, A3);
  SWAP(D1);//D1L = D1UH[1] | (D1UH[0] << 16);
  *A2 = *(A0 + D1W);
  A2++;
tag020744:
  D7W--;
  if (D7W == 0) goto tag020766;
  D1H2 = D1H1;
  D1H1 = 0;
  if (D0W != 0) goto tag020718;
  goto tag020714;
tag020766:
  //RestoreRegs(0x0c80);
  return;
}

//*********************************************************
//
//*********************************************************
void TAG0207cc(void)
{//(void)
  dReg D7;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  if (d.PartySleeping)
  {
    DisplaySleepScreen();
    MarkViewportUpdated(0);
  }
  else
  {
    D7W = d.MagicCaster;
    d.MagicCaster = -1;
    SelectMagicCaster(D7W);
    if (d.AttackingCharacterOrdinal == 0)
    {
      d.Word20252 = 1;
    };
    DrawLegalAttackTypes();
    D7W = d.SelectedCharacterOrdinal;
    if (d.SelectedCharacterOrdinal)
    {
      d.SelectedCharacterOrdinal = 0;
      TAG0192f4(D7W-1);
    }
    else
    {
      FloorAndCeilingOnly();
      DrawMovementButtons();
    };
    TAG002572();
  };
  d.Word11750 = 0;
}

void TAG020836(i8 *P1)
{
  dReg D0, D7;
  //i32 D6;
  aReg A3;
  i16 index;
  A3=d.Pointer4+128;
  D7W=0; D7B=*A3; A3++;
  index=0;
  for (index=0; index< D7W; index++)
  {
    P1[index] = A3[index];
  };
  D0W=index;
  index++;
  D0W=index;
  P1[index]=0;
  D0W=D7W;
}

i16 TAG020880(i16 width,i16 height,i16 scale)
{ //width is in bytes (should be multiple of 8?)
  //scale is in 32ths.   eg:  16 means 1/2
  dReg D0, D1;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
//  ui32 n;
    D0W = sw((width * scale + scale/2) / 32);
    D0W += 7; // Round to multiple of 8
    D0W &= 0xfff8;
    D1L = (height * scale + scale/2) / 32;
    D0L = D0UW * D1UW;
    return D0W;
}

void swap4words(i16 *words)
{
  words[0]=LE16(words[0]);
  words[1]=LE16(words[1]);
  words[2]=LE16(words[2]);
  words[3]=LE16(words[3]);
}

void swapNwords(i16 *words, i32 n)
{
  for (i32 i=0; i<n; i++)
  {
    words[i]=LE16(words[i]);
  };
}

void SwapKeyXlate(pnt p)
{
  while (wordGear(p)!=0)
  {
    wordGear(p) = LE16(wordGear(p));
    p+=2;
    wordGear(p) = LE16(wordGear(p));
    p+=2;
  };
}

void swapRectPos(RectPos *rect)
{
  swap4words((i16 *)rect);
}

void fixSpell(SPELL *p)
{
  p->spellID = LE32(p->spellID);
  p->word6 = LE16(p->word6);
}

void fixItem26(MONSTERDESC *pmtDesc)
{
  pmtDesc->word2  = LE16(pmtDesc->word2);
  pmtDesc->word4  = LE16(pmtDesc->word4);
  pmtDesc->word14 = LE16(pmtDesc->word14);
  pmtDesc->word16 = LE16(pmtDesc->word16);
  pmtDesc->word18 = LE16(pmtDesc->word18);
  pmtDesc->word20 = LE16(pmtDesc->word20);
};

void SwapGraphic0x231(void)
{
  SwapWordsInButtonList(d.Buttons17796); // Fix littleEndian problem
  SwapWordsInButtonList(d.Buttons17760); // Fix littleEndian problem
  SwapWordsInButtonList(d.Buttons16932); // Fix littleEndian problem
  SwapWordsInButtonList(d.Buttons16956); // Fix littleEndian problem
  SwapWordsInButtonList(d.Buttons17304); // Fix littleEndian problem
  SwapWordsInButtonList(d.Buttons17196); // Fix littleEndian problem
  SwapWordsInButtonList(d.Buttons17832); // Fix littleEndian problem
  SwapWordsInButtonList(d.Buttons17892); // Fix littleEndian problem
  SwapWordsInButtonList(d.Buttons17952); // Fix littleEndian problem
  SwapWordsInButtonList(d.Buttons18060); // Fix littleEndian problem
  SwapWordsInButtonList(d.Buttons18216); // Fix littleEndian problem
  SwapWordsInButtonList(d.Buttons18324); // Fix littleEndian problem
  SwapWordsInButtonList(d.Buttons18372); // Fix littleEndian problem
  SwapWordsInButtonList(d.Buttons18660); // Fix littleEndian problem
  SwapWordsInButtonList(d.Buttons18624); // Fix littleEndian problem
  SwapWordsInButtonList(d.Buttons18792); // Fix littleEndian problem
  SwapWordsInButtonList(d.Buttons18768); // Fix littleEndian problem
  SwapWordsInButtonList(d.Buttons18708); // Fix littleEndian problem
  SwapWordsInButtonList(d.Buttons18876); // Fix littleEndian problem
  SwapWordsInButtonList(d.Buttons18828); // Fix littleEndian problem
  SwapWordsInButtonList(d.Buttons18936); // Fix littleEndian problem
  SwapKeyXlate(d.Byte18448);
  SwapKeyXlate(d.Byte18440);
  SwapKeyXlate((pnt)d.Byte18428);
  SwapKeyXlate(d.Byte18400);
  swapNwords((i16 *)d.MoveButn18496,4*4); // 4 directions
  swapNwords(d.Word18552,28);
  swapNwords(d.Word18568,4); // deltax
  swapNwords(d.Word18560,4); // deltay
  swapNwords((i16 *)d.Byte18600,4); // RectPos
  swapNwords((i16 *)d.Byte18592,4); // RectPos
  swapNwords((i16 *)d.Byte18584,4); // RectPos
  swapNwords((i16 *)d.Byte18576,4); // RectPos
};

void TAG0208b4(void)
{
  dReg D0, D1, D3, D4, D5, D6, D7;
  aReg A0;
  ITEM6 *psA3;
  pnt LOCAL_4;
  pnt LOCAL_8;
  i16 LOCAL_10, LOCAL_12;
  i32 i;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  //i32 saveD4=D4, saveD5=D5, saveD6=D6, saveD7=D7;
  //pnt saveA2=A2, saveA3=A3;
  d.pCeilingBitmap = allocateMemory(3248, 1);
  d.pFloorBitmap = allocateMemory(7840, 1);
  d.pWallBitmaps[12] = allocateMemory(392, 1);
  d.Pointer2086 = allocateMemory(392, 1);
  d.pWallBitmaps[11] = allocateMemory(3264, 1);
  d.pWallBitmaps[10] = allocateMemory(5112, 1);
  d.pWallBitmaps[9] = allocateMemory(14208, 1);
  d.pWallBitmaps[8] = allocateMemory(2176, 1);
  d.pWallBitmaps[7] = allocateMemory(2176, 1);
  d.pWallBitmaps[6] = allocateMemory(144, 1);
  d.pWallBitmaps[5] = allocateMemory(256, 1);
  d.pWallBitmaps[4] = allocateMemory(688, 1);
  d.pWallBitmaps[3] = allocateMemory(704, 1);
  d.pWallBitmaps[2] = allocateMemory(1560, 1);
  d.pWallBitmaps[1] = allocateMemory(1504, 1);
  d.Pointer2142 = allocateMemory(1504, 1);
  d.pWallBitmaps[0] = allocateMemory(1968, 1);
  d.pViewportBMP = allocateMemory(15232, 1);
  d.pViewportBlack = d.pViewportBMP + 3248;
  d.pViewportFloor = d.pViewportBlack + 4144;
  ASSERT(d.GraphicExpSizes[0x22e] == 0x1270);
  ReadAndExpandGraphic(0x8000|0x22e, d.Byte7248+2, 0,0); //TAG022b86
  for (i=0; i<27; i++)
  {
    d.Item6414[i].word0 = LE16(d.Item6414[i].word0);
  };
  d.Word4040[0] = LE16(d.Word4040[0]);
  swapNwords(d.Word7246, 12);
  swapNwords(d.Word7222, 30);
  swapNwords(d.Word7162, 60);
  swapNwords(d.Word7042, 30);
  btn missingButtons[4] =
  {
    {0x00c8,0x00f4,0x012a,0x002d,0x003a,0x0002},
    {0x00c9,0x00f4,0x012a,0x004c,0x005d,0x0002},
    {0x00ca,0x00f8,0x0125,0x00bb,0x00c7,0x0002},
    {0x0000,0x0000,0x0000,0x0000,0x0000,0x0000}
  };
  ASSERT(    (d.GraphicExpSizes[0x231] == 0x804)
          || (d.GraphicExpSizes[0x231] == 0x7d4) );
  ReadAndExpandGraphic(0x8000|0x231,d.Byte18938+2, 0, 0);
  SwapGraphic0x231();
  if (d.GraphicExpSizes[0x231] == 0x7d4)
  {
    d.Buttons16932[0] = missingButtons[0];
    d.Buttons16932[1] = missingButtons[1];
    d.Buttons16932[2] = missingButtons[2];
    d.Buttons16932[3] = missingButtons[3];
  };
  ASSERT(d.GraphicExpSizes[0x230] == 0x4e8);
  ReadAndExpandGraphic(0x8000|0x230, d.Byte20244+2, 0, 0);
  swapRectPos(&d.wRectPos20202);
  swapRectPos(&d.wRectPos20210);
  swapRectPos(&d.wRectPos20218);
  swapRectPos(&d.wRectPos20226);
  swapRectPos(&d.wRectPos20234);
  for (i=0; i<25; i++) fixSpell(&d.Spells[i]);
  ASSERT(d.GraphicExpSizes[0x22f] == 0xc0e);
  ReadAndExpandGraphic(0x8000|0x22f, d.Byte10342+2, 0,0);
  d.DBEntrySize[dbSCROLL] = sizeof (DB7);
  swapNwords(d.DoorCharacteristics, 4);
  swapNwords(d.MonsterDroppings,40);
  for (i=0; i<4; i++)
  {
    d.DeltaX[i] = LE16(d.DeltaX[i]);
    d.DeltaY[i] = LE16(d.DeltaY[i]);
  };
  for (i=0; i<27; i++) fixItem26(&d.MonsterDescriptor[i]);
  for (i=0; i<8; i++)d.FoodValue[i]=LE16(d.FoodValue[i]);
  for (i=0; i<180; i++)
  {
    d.ObjDesc[i].littleEndian();
    //d.ObjDesc[i].objectType = LE16(d.ObjDesc[i].objectType);
    //d.ObjDesc[i].word4 = LE16(d.ObjDesc[i].word4);
  };
  for (i=0; i<46; i++)
  {
    d.weapons[i].word4 = LE16(d.weapons[i].word4);
  };
  ASSERT(d.GraphicExpSizes[0x232] == 0x722);
  ReadAndExpandGraphic(0x8000|0x232, d.Byte1832+2, 0,0);
  swap4words(d.Word20242);
  swap4words((i16 *)&d.wRectPos1780);
  swap4words((i16 *)&d.wRectPos1788);
  swap4words((i16 *)&d.wRectPos1796);
  for (i=0; i<22; i++)
  {
    d.sound1772[i].word0 = LE16(d.sound1772[i].word0);
  };
  swapNwords(d.DropOrder,30);
  swapNwords(d.Word1526[0],12);
  swapNwords(d.Word1502[0],24);
  for (i=0; i<4; i++) swapNwords((i16 *)&d.wRectPos1454[i],4);
  swapNwords(d.Word1406,8);
  swapNwords((i16 *)d.Byte1094,4);
  swapNwords((i16 *)d.PaletteBrightness,6);
  swapNwords((i16 *)d.Word1074,16);
  swapNwords((i16 *)&d.CarryLocation[0],38);
  swapNwords((i16 *)&d.wRectPos966,4);
  swapNwords((i16 *)&d.wRectPos958,4);
  swapNwords((i16 *)&d.wRectPos950,4);
  swapNwords((i16 *)&d.wRectPos942,4);
  swapNwords((i16 *)&d.wRectPos934,4);
  swapNwords((i16 *)&d.wRectPos926,4);
  swapNwords((i16 *)&d.IconDisplay, 3*46);
  swap4words((i16 *)&d.wRectPos624);
  swapNwords(d.Word612,7);
  swapNwords(&d.Word554,1);
  for (i=0; i<6; i++) swapNwords((i16 *)&d.Palette552[i],16);
  swapNwords((i16 *)&d.Palette360,16);
  swapNwords((i16 *)&d.Palette328,16);
  swap4words(d.Word140);
  swap4words(d.Word132);
  swap4words(d.Word124);
  swap4words(d.Word116);
  swap4words(d.Word108);
  swap4words(d.Word100);
  swap4words(d.Word92);
  swap4words(d.Word84);
  swap4words(d.Word76);
  swap4words(d.Word68);
  swap4words(d.Word60);
  swap4words(d.Word52);
  swap4words(d.Word44);
  swap4words(d.Word36);
  swap4words(d.Word28);
  swap4words(d.Word20);
  swap4words(d.Word12);
  for (i32 j=0; j<70; j++)
    d.DefaultGraphicList[j] = LE16(d.DefaultGraphicList[j]);
  d.pwPointer23274[0] = 15232;
  d.pwPointer23274[1] = 4560;
  d.pwPointer23274[2] = 1184;
  d.pwPointer23274[3] = 888;
  for (D7W=15; D7W<=16; D7W++)
  {
    D0W = sw(D7W + 286);
    //D1W = D7W << 2;
    //A0 = d.Byte2514 + D1W;
    //wordGear(A0) = D0W;
    d.Word2514[D7W][0] = D0W;
    //D0W = D7W << 2;
    //A0 = d.Byte2512 + D0W;
    //wordGear(A0) = 1;
    d.Word2514[D7W][1] = 1;
    //D0 = D7W*2;
    //A0 = d.pwPointer23274 + D7W;
    d.pwPointer23274[68 + D7W*2] = 984;
    //D0 = D7W * 2;
    //D0 <<= 1;
    //A0 = d.Pointer23274 + D0;
    d.pwPointer23274[69 + D7W*2] = 1952;
  };
  d.Word2386 = 241;
  d.Word2384 = 1;
  psA3 = d.s5604;
  for (D7W=0; D7W<85; D7W++)
  {
    D5W = sw(104 + psA3->uByte1);
//    D3W=(UI8)(psA3->byte1);
//    D5W += D3W
    D0W = TAG020880((UI8)(psA3->byte2), (UI8)(psA3->byte3), 16);
    d.pwPointer23274[D5W++] = D0W;
    D0W = TAG020880((UI8)(psA3->byte2), (UI8)(psA3->byte3), 20);
    d.pwPointer23274[D5W++] = D0W;
    if (psA3->byte4 & 1)  // Only three or four have this bit set
    {
      D0W = d.pwPointer23274[D5W - 2];
      d.pwPointer23274[D5W] = D0W;
      D5W++;
      D0W = d.pwPointer23274[D5W - 2];
      d.pwPointer23274[D5W] = D0W;
      D5W++;
    };
    if (psA3->byte4 & 16) // Only the first one has this bit
    {
      D0W = d.pwPointer23274[D5W - 2];
      d.pwPointer23274[D5W] = D0W;
      D5W++;
      D0W = d.pwPointer23274[D5W - 2];
      d.pwPointer23274[D5W] = D0W;
    };
    psA3++;
  };
  LOCAL_4 = d.Byte5688;
  for (D7W=0; D7W<14; D7W++)
  {
    if ((LE16(wordGear(LOCAL_4 + 4)) & 256) ==0)
    {
      D5W = 282;
      A0 = LOCAL_4;
      D3W = ((ui8 *)A0)[1];
      D5W = sw(D5W + D3W);
      for (D6W=0; D6W<6; D6W++)
      {
        A0 = d.Byte5752+D6W;
        D4W = TAG020880((UI8)(LOCAL_4[2]),
                         (UI8)(LOCAL_4[3]),
                         (UI8)(A0[0]));
//
        d.pwPointer23274[D5W] = D4W;
        D0W = (I16)(LE16(wordGear(LOCAL_4 + 4)) & 3);
        if (D0W != 3)
        {
          d.pwPointer23274[D5W + 6] = D4W;
          D0W = (I16)(LE16(wordGear(LOCAL_4 + 4)) & 3);
          if (D0W != 2)
          {
            d.pwPointer23274[D5W +12] = D4W;
          };
        };
        D5W++;
      };
    };
    LOCAL_4 +=6;
  };

  A0 = d.Byte5728; d.Pointer1864[0] = A0;
  A0 = d.Byte5744; d.Pointer1860 = A0;
  A0 = d.Byte156;  d.Pointer1852 = A0; d.Pointer1856 = A0;
  D5W = 438;
  LOCAL_8 = d.Byte5696;
  for (D7W=0; D7W<4; D7W++)
  {
    for (D6W=4; D6W<32; D6W+=2)
    {
      D0W = TAG020880((UI8)(LOCAL_8[0]),(UI8)(LOCAL_8[1]), D6W);
      d.pwPointer23274[D5W] = D0W;
      D5W++;
    };
    if (D7W == 3)
    {
      D0W = (UI8)(LOCAL_8[0]);
      D1W = (UI8)(LOCAL_8[1]);
      D0L = D0UW*D1UW;
      d.pwPointer23274[D5W] = D0W;
      D5W++;
    };
    LOCAL_8+=2;
  };
  D5W = 495;
  for (D6W=0; D6W<27; D6W++)
  {
    //A2 = d.Byte6414 + 12*D6W;
    //qA0 = d.Byte9660 + D6W*26;
    D7W = d.MonsterDescriptor[D6W].word4;
    d.Item6414[D6W].word2 = D5W;
    D0W = TAG020880(d.Item6414[D6W].uByte4,
                    d.Item6414[D6W].uByte5,
                    16);
    LOCAL_12 = D0W;
    d.pwPointer23274[D5W++] = D0W;
    D0W = TAG020880(d.Item6414[D6W].uByte4,
                     d.Item6414[D6W].uByte5,
                     20);
    LOCAL_10 = D0W;
    d.pwPointer23274[D5W] = D0W;
    D5W++;
    if(D7W & 8)
    {
      D0W = TAG020880(d.Item6414[D6W].uByte6,
                       d.Item6414[D6W].uByte7,
                       16);
      d.pwPointer23274[D5W] = D0W;
      D5W++;
      D0W = TAG020880(d.Item6414[D6W].uByte6,
                       d.Item6414[D6W].uByte7,
                       20);
      d.pwPointer23274[D5W] = D0W;
      D5W++;
    };
    if(D7W & 16)
    {
      d.pwPointer23274[D5W] = LOCAL_12;
      D5W++;
      d.pwPointer23274[D5W] = LOCAL_10;
      D5W++;
    };
    if(D7W & 32)
    {
      D0W = TAG020880(d.Item6414[D6W].uByte8,
                       d.Item6414[D6W].uByte9,
                       16);
      d.pwPointer23274[D5W] = D0W;
      D5W++;
      D0W = TAG020880(d.Item6414[D6W].uByte8,
                       d.Item6414[D6W].uByte9,
                       20);
      d.pwPointer23274[D5W] = D0W;
      D5W++;
    };
     LOCAL_12 = (I16)(D7W & 3);
    for (LOCAL_12=(I16)(D7W&3); LOCAL_12 != 0; LOCAL_12--)
    {
      D0W = d.Item6414[D6W].uByte4;
      D1W = d.Item6414[D6W].uByte5;
      D0L = D0UW*D1UW;
      d.pwPointer23274[D5W] = D0W;
      D5W++;
      D0W = TAG020880(d.Item6414[D6W].uByte4,
                     d.Item6414[D6W].uByte5,
                     16);
      d.pwPointer23274[D5W] = D0W;
      D5W++;
      D0W = TAG020880(d.Item6414[D6W].uByte4,
                     d.Item6414[D6W].uByte5,
                     20);
      d.pwPointer23274[D5W] = D0W;
      D5W++;
    };
  };
  //D4=saveD4;D5=saveD5;D6=saveD6;D7=saveD7;A2=saveA2;A3=saveA3;
}

void TAG020fbc(void)
{
//  dReg D6;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  d.Pointer2214 = allocateMemory(3264,1);
  d.Pointer2218 = allocateMemory(5112, 1);
  d.Pointer2222 = allocateMemory(14208,1);
  d.Pointer2226 = allocateMemory(2176,1);
  d.Pointer2230 = allocateMemory(2176,1);
}

//*********************************************************
//
//*********************************************************
RESTARTABLE _TAG021028(void)
{ //(void)
  static dReg D0;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  static i16 LOCAL_2;
  RESTARTMAP
    RESTART(1)
    RESTART(2)
    RESTART(3)
    RESTART(4)
    RESTART(5)
    RESTART(6)
  END_RESTARTMAP
  d.Word11756 = 0;
  d.Word11758 = 0;
  d.Word11760 = 0;
  d.Word11762 = 0;
  d.FlashButnActive = 0;
  d.Word11776 = 0;
  d.PartySleeping = 0;
  d.Word1836 = 15;
  d.Word1838 = 0;
  d.Word1840 = 0;
  d.AttackingCharacterOrdinal = 0;
  d.Word20252 = 1;
  d.Word23144 = 0;
  d.WatchdogTime = 0xffffff;
  d.PrimaryButtonList = d.Buttons17196; // characters, spells, movement
  d.SecondaryButtonList = d.Buttons17304;
  d.pKeyXlate2 = (KeyXlate *)d.Byte18400;
  d.pKeyXlate1 = d.Byte18428;
  LoadPartyLevel(_1_,d.partyLevel);
  D0W = d.dungeonFormat;
  if (d.dungeonFormat == 0)
  {
    //ClearMemory(d.LogicalScreenBase, 32000);
    //FadeToPalette(&d.Palette11978);
    for (;;)
    {
      DoMenu(_6_,
             NULL,
             d.Pointer22812,
             "PLAY GAME",
             "ASCII DUMP",
             NULL,
             NULL,
             1,
             1,
             1);
      //if (1 == TAG01d1cc(2,1,0,0)) break;
      WaitForMenuSelect(_2_, 2,1,0,0);
      if (i16Result == 1) break;
      AsciiDump();
    } ;
    if (fullscreenRequested) 
    {
      UI_ClearScreen();
      fullscreenActive = true;
    };
    LOCAL_2 = d.Word23244;
    if (LOCAL_2 != 0)
    {
      d.Word23244 = 1;
      closeGraphicsFile();
    };
    InsertDisk(_3_, 0,1);
    if (LOCAL_2 != 0)
    {
      openGraphicsFile();
      d.Word23244 = LOCAL_2;
    };
    wvbl(_4_);
    ClearMemory(d.LogicalScreenBase, 32000);
  }
  else
  {
    d.UseByteCoordinates = 0;
    wvbl(_5_);
    FillRectangle(d.LogicalScreenBase,&d.wRectPos1780,0,160); //Top of screen
    FillRectangle(d.LogicalScreenBase,&d.wRectPos1788,0,160);//Right side of screen
    FillRectangle(d.LogicalScreenBase,&d.wRectPos1796,0,160);//Scrolling text area
  };
  setpalette(&d.Palette552[0]);
  DrawMovementButtons();
  TAG0138ec();
  d.ClockRunning = 1;
  RETURN
}

//*********************************************************
//
//*********************************************************
//   TAG0211a0
RESTARTABLE _ShowPrisonDoor(void)
{//(void)
  static dReg D7;
  RESTARTMAP
    //RESTART(1)
    RESTART(2)
    RESTART(3)
    RESTART(4)
    RESTART(5)
    RESTART(6)
  END_RESTARTMAP
  //i16 saveD7 = D7W;
  //i8 LOCAL_130[130];
////  TAG001d0c(); // Set critical error handler.
  //TAG020836(LOCAL_130); //??Copy some part of Program Descriptor?? // Never used!
  CountFloppyDrives();
  InitializeHeap();//TAG020286
  D7W = 1;
  ReadGraphicsIndex(); // TAG021d9a
  TAG0208b4();
  HangIfZero(D7W); // (=0x020276)
  //DisplayChaosStrikesBack(_1_);
  ReadFloorAndCeilingBitmaps(0);
  ReadWallBitmaps(0);
      HopefullyNotNeeded();
  TAG001c6e();
  TAG0010ae();
    //D0 = GetAbsFuncAddr(276); // TAG00dd78(276);
    //D0 = TAG00306c;
  d.pFunc23232 = TAG00306c;
    //D0 = TAG00dd78(&DetachItem16)
  d.pFunc23236 = DetachItem16;
  //  MemMove((pnt)palette,(pnt)&d.Palette11946, 32);
  //  MemMove((pnt)palette,(pnt)&d.Palette11978, 32);
  TAG0023b0();
  TAG000ec6(); // In supervisor mode
  jdisint(5);  // TRAP 14 (#26,#5);
  //TAG0020ca();
  wvbl(_2_);
  MemMove((pnt)d.Palette552, (pnt)&d.Palette11946, 32); // Initialize palette
  MemMove((pnt)d.Palette552, (pnt)&d.Palette11978, 32); // Initialize palette
  TAG01f746(_3_);
  for (;;)
  {
    ReadEntireGame(_4_);
    if (i16Result == 1) break;
    openGraphicsFile(); // TAG021d36
    TAG01f746(_5_);
  };
  openGraphicsFile();// TAG021d36
  TAG01b8ae();
  TAG021cd8();
  TAG021028(_6_);
  closeGraphicsFile();
  if (d.dungeonFormat != 0)
  {
    MoveObject(RN(RNnul), -1, 0, d.partyX, d.partyY);
  };
  STShowCursor(); //TAG003026
  TAG01953a();
  //D7W = saveD7;
  RETURN;
}

//*********************************************************
//
//*********************************************************
void TAG02134a(pnt)
{
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  d.Word918 = 136;
  d.Word1838 = 136;
  d.Word11752 = 0;
}

//*********************************************************
//
//*********************************************************
//   TAG021822
void RemoveFromFreeList(ITEMQ *This)
{
  ITEMQ *Prev, *Next;
  VerifyGraphicFreeList();
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  //pgA3 = pQ;
  Prev = This->pgPrev();
  Next = This->pgNext();
  if (Prev == NULL)
  {
    if (Next == NULL)
    {
      d.pgUnused = NULL;
    }
    else
    {
      d.pgUnused = Next;
      Next->pgPrev(NULL);
    };
  }
  else
  {
    Prev->pgNext(Next);
    if (Next != NULL)
    {
      Next->pgPrev(Prev);
    };
  };
  VerifyGraphicFreeList();
}


ui8 long02160a[] = {
 0x00,0x01,0x00,0x01,
 0x00,0x03,0x00,0x03,
 0x00,0x07,0x00,0x07,
 0x00,0x0f,0x00,0x0f,
 0x00,0x1f,0x00,0x1f,
 0x00,0x3f,0x00,0x3f,
 0x00,0x7f,0x00,0x7f,
 0x00,0xff,0x00,0xff,
 0x01,0xff,0x01,0xff,
 0x03,0xff,0x03,0xff,
 0x07,0xff,0x07,0xff,
 0x0f,0xff,0x0f,0xff,
 0x1f,0xff,0x1f,0xff,
 0x3f,0xff,0x3f,0xff,
 0x7f,0xff,0x7f,0xff,
 0xff,0xff,0xff,0xff
};

ui8 long02164a[] = {
  0xff,0xfe,0xff,0xfe,
  0xff,0xfc,0xff,0xfc,
  0xff,0xf8,0xff,0xf8,
  0xff,0xf0,0xff,0xf0,
  0xff,0xe0,0xff,0xe0,
  0xff,0xc0,0xff,0xc0,
  0xff,0x80,0xff,0x80,
  0xff,0x00,0xff,0x00,
  0xfe,0x00,0xfe,0x00,
  0xfc,0x00,0xfc,0x00,
  0xf8,0x00,0xf8,0x00,
  0xf0,0x00,0xf0,0x00,
  0xe0,0x00,0xe0,0x00,
  0xc0,0x00,0xc0,0x00,
  0x80,0x00,0x80,0x00,
  0x00,0x00,0x00,0x00
};

ui8 long02168a[] = {
 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,
 0x00,0x00,0xff,0xff,0x00,0x00,0x00,0x00,
 0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,
 0x00,0x00,0x00,0x00,0xff,0xff,0x00,0x00,
 0xff,0xff,0x00,0x00,0xff,0xff,0x00,0x00,
 0x00,0x00,0xff,0xff,0xff,0xff,0x00,0x00,
 0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,
 0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,
 0xff,0xff,0x00,0x00,0x00,0x00,0xff,0xff,
 0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff,
 0xff,0xff,0xff,0xff,0x00,0x00,0xff,0xff,
 0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,
 0xff,0xff,0x00,0x00,0xff,0xff,0xff,0xff,
 0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,
 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
};

enum BSRRETURNS {
  Tag02148a = 1,
  Tag0214aa,
  Tag0214e6,
  Tag0214f6,
  Tag02155e,
  Tag021564,
  Tag021568
};

#define BSR(to,from)              \
  retstack[--retindex]=Tag##from; \
  goto tag##to;                   \
tag##from:

#define RTS goto tagReturn;

#define POP retindex++;

void ExpandGraphic(pnt src,pnt dest,i16 P3,i16 P4)
{
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  dReg D0, D1, D2, D3, D4, D5, D6, D7;
  aReg A0, A1, A2=NULL, A3, A4, A5, A6;
  //i32 saveD4=D4,saveD5=D5,saveD6=D6,saveD7=D7;
  //pnt saveA2=A2,saveA3=A3,saveA4=A4,saveA5=A5,saveA6=A6;
  i32 retindex=10;
  i32 C;
  BSRRETURNS retstack[10];
  D1L = 0;
  D7L = 0;
  A0 = src;
  A1 = dest;
  D5W = P3;
  D4W = P4;
  D7W = LE16(wordGear(A0)); A0+=2; // GraphicWidth
  D6W = LE16(wordGear(A0)); A0+=2; // GraphicHeight
  D7W = (I16)(((D7W+15)>>1)&0x7ff8); // Number of bytes/GraphicLine
  if((A1==0) && (A1=physbase(),D7W!=160)) // If destination not specified
  {
    D5W = (I16)((D5W>>1)&0x7ff8);
    A1 += D5W;
    D4L = D4UW * 160; //(ui16)D0W;
    A1 += D4W;
    A3 = A1 + D7W;
    D6W--;
    D6L = D6UW * 160; //(ui16)D0W; // Total number bytes
    D6L += (i32)A3;
    D4W = sw(160 - D7W);
//    D7W = D4W;
    D7W = 160;
  }
  else
  {
    D6L = D6UW * (ui16)D7W; // Total number bytes
    A3 = A1 + D6L;//Destination LWA+1
    D6L = (i32)A3;//Destination LWA+1
  };
  longGear(A1)   = 0;
  longGear(A1+4) = 0;
  D0L = 15; //#pixels in this group-1
  D4L = 0;  //pixel# in this group
  A4 = (pnt)long02160a;
  A5 = (pnt)long02164a;
  A6 = (pnt)long02168a;
tag021470:
  D2B = D3B = *(A0++);
  if (D2B < 0) goto tag0214be;
  D3B = (i8)((D3UB)>>4);
  if (D3B == 0) goto tag0214f2;
  D2W &= 0xf;
  D1L = 1;
  D1B = (i8)(D1B + D3B);
tag021482:
  D2W <<= 3;
  A2 = A6 + D2W;
tag021488:
  BSR (0214fa,02148a);//place D1 pixels of color *A2
  if (D1W == 0) goto tag021470;
  if ( (ui16)D1W < 16) goto tag021488;
  D3L = LE32(longGear(A2));
  D5L = LE32(longGear(A2+4));
  D1W -= 16;
tag02149e:
  longGear(A1) = LE32(D3L);
  A1+=4;
  longGear(A1) = LE32(D5L);
  A1+=4;
  if (A1 != A3) goto tag0214aa;
  BSR(02153c,0214aa);
  D1W -= 16;
  if ( (ui16)D1W < 65536-16) goto tag02149e;
  longGear(A1) = 0;
  longGear(A1+4) = 0;
  D1W +=16;
  if (D1W != 0) goto tag021488;
  goto tag021470;
tag0214be:
  D2W &= 15;
  D1L = 0;
  D1B = *(A0++);
  if ((D3W & 0x40)==0) goto tag0214d0;
  D1W <<= 8;
  D1B = *(A0++);
tag0214d0:
  D1W += 1;
  if ((D3W&0x10)==0) goto tag021482;
  if ((D3W&0x20)==0) goto tag021558;
  A2 = A1-D7W;
tag0214e4:
  BSR(0214fa,0214e6);
  if (D5L == 0) goto tag0214ec;
  A2 = (pnt)D5L;
tag0214ec:
  A2 += 8;
  if (D1W != 0) goto tag0214e4;
tag0214f2:
  BSR(021570,0214f6);
  goto tag021470;
tag0214fa: // D1=repeat, D0=#-1 pixels remain in group *A2 = color
  D4B = D0B;
  D4W = sw(D4W + D4W);
  D4W = sw(D4W + D4W);
  D3L = LE32(longGear(A4+D4W)); //mask of remaining pixels in group
  if (D0L < D1L) goto tag021518;
  D0W = sw(D0W - D1W); //decrement pixels remaining in group
  D4B = D0B;
  D4W = sw(D4W + D4W + D4W + D4W);
  D3L &= LE32(longGear(A5 + D4W)); //data mask
  D1L = 0;
  goto tag02151e;
tag021518:
  D1W = sw(D1W - D0W);
  D1W--;
  D0L = -1;
tag02151e:
  D5L = LE32(longGear(A2));
  D5L &= D3L;
  longGear(A1) |= LE32(D5L);
  //D5L = 0;
  A1 += 4;
  D5L = LE32(longGear(A2+4));
  D5L &= D3L;
  longGear(A1) |= LE32(D5L);
  A1 += 4;
  D5L = 0;
  if (D0W < 0) goto tag021538;
  A1 -= 8;
  RTS;
tag021536:
  A1 += 8;
tag021538:
  if (A1 != A3) goto tag02154e;
tag02153c:
  if (A1 == (pnt)D6L) goto tag02170a;
  A3 += D7W;
  SWAP(D7);//D7 = ((D7<<16)&0xffff0000) | ((D7>>16)&0xffff);
  A1 += D7W;
  D5L = (i32)A2;
  D5W = sw(D5W + D7W);
  SWAP(D7);// = ((D7<<16)&0xffff0000) | ((D7>>16)&0xffff);
tag02154e:
  D0L = 15;
  longGear(A1) = 0;
  longGear(A1+4) = 0;
  RTS;

tag021558:
  C = D1W&1;
  D1W >>= 1;
  if (C==0) goto tag02155e;
  BSR(021570,02155e)
  D2B = *(A0);
  D2B >>= 4;
  BSR(021570,021564);
  D2B = *(A0++);
  BSR(021570,021568);
  D1W--;
  if (D1W != 0) goto tag02155e;
  goto tag021470;
tag021570://D0=#pixels left in group -1; place one pixel color D2
  D3W = 0;
  D3L |= 1<<D0B;
//  D2W &= 15;
//  D2W += D2W
//  switch (D2W)
//  {
  if (D2W & 0x8) wordGear(A1+6) |= LE16((D3W));
  if (D2W & 0x4) wordGear(A1+4) |= LE16((D3W));
  if (D2W & 0x2) wordGear(A1+2) |= LE16((D3W));
  if (D2W & 0x1) wordGear(A1+0) |= LE16((D3W));
  D0W--;
  if (D0W < 0) goto tag021536;
  RTS;
//  case 0: goto tag0215aa;
//  case 1: goto tag0215a8;
//  case 2: goto tag0215cc;
//  case 3: goto tag0215a4;
//  case 4: goto tag0215dc;
//  case 5: goto tag0215b6;
//  case 6: goto tag0215c8;
//  case 7: goto tag0215a0;
//  case 8: goto tag0215ee;
//  case 9: goto tag0215ec;
//  case 10: goto tag0215fa;
//  case 11: goto tag0215e8;
//  case 12: goto tag0215d8;
//  case 13: goto tag0215b2;
//  case 14: goto tag0215c4;
//  case 15:
//    wordGear(A1+6) |= LE16(D3W);
//    wordGear(A1+4) |= LE16(D3W);
//    wordGear(A1+2) |= LE16(D3W);
//    wordGear(A1) |= LE16(D3W);
//    D0W--;\
//    if (D0W < 0) goto tag021536;
//    RTS;
//tag0215b2:
tag02170a:
  POP; // discard return address
  //D4=saveD4;D5=saveD5;D6=saveD6;D7=saveD7;
  //A2=saveA2;A3=saveA3;A4=saveA4;A5=saveA5;A6=saveA6;
  ASSERT(retindex==10);
  return;
tagReturn:
  switch (retstack[retindex++])
  {
  case Tag02148a: goto tag02148a;
  case Tag0214e6: goto tag0214e6;
  case Tag0214f6: goto tag0214f6;
  case Tag02155e: goto tag02155e;
  case Tag021564: goto tag021564;
  case Tag021568: goto tag021568;
  default: NotImplemented(0x21712);
  };
}




void checkMemory(void)
{
  pnt prevblk=NULL;
  pnt blk = firstMemoryBlock;
  //return;
  while (blk != NULL)
  {
    ASSERT(longGear(blk+8) == memDebugFlag);
    prevblk=blk;
    blk = pntGear(blk);
  };
}


pnt allocateMemory(i32 sizeNeeded,i16 type) //TAG02175c
{ // Allocate memory.
  // Type =1 --> permanent allocation.
  // Type =0 --> temporary allocation
  // Type =2 --> temporary allocation of as much as possible
  dReg D7;
  aReg A0, A3;
  ASSERT(sizeNeeded != 0);
  D7L = sizeNeeded;
  if (sizeNeeded&1) sizeNeeded++; // Make the size even
  if ((type==1) && (d.Long23326 >= sizeNeeded+12))
  {  // Allocate static memory from low addresses
    A3 = d.Pointer23322;
    d.Pointer23322 += sizeNeeded+12; // room for debug list
    d.Long23326 -= sizeNeeded+12;
    pntGear(A3) = firstMemoryBlock;
    firstMemoryBlock = A3;
    longGear(A3+8) = memDebugFlag;
    longGear(A3+4) = sizeNeeded-12;
    A3 += 12;
  }
  else
  { // Not enough space or temporary allocation
    if (sizeNeeded+12 > d.Long23306)
    { // die, I think.
      die(40);
    };
    if (type == 2)
    {
      // Allocate all that's left from end
      A3 = d.Pointer23298 - d.Long23306;
      d.Long23306 -= sizeNeeded;
    }
    else if (type==1)
    {
      // Allocate what's needed from the high end.
      d.Pointer23298 = A3 = d.Pointer23298-sizeNeeded-12;
      pntGear(A3) = firstMemoryBlock;
      firstMemoryBlock = A3;
      longGear(A3+4) = sizeNeeded;
      longGear(A3+8) = memDebugFlag;
      A3 += 12;
      d.Long23306 -= sizeNeeded+12;
    }
    else
    { // Temporary allocation
      d.Pointer23298 = A3 = d.Pointer23298-sizeNeeded;
      d.Long23306 -= sizeNeeded;
    }
  };
  A0 = A3;
  memset(A0, 0xba, sizeNeeded);
  //D7 = saveD7;
  //A3 = saveA3;
  return A0;
}


//   TAG0217d8
void FreeTempMemory(i32 size)
{
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  if (size & 1)
  {
    size++;
  };
  d.Long23306 += size;
  d.Pointer23298 += size;

}

void TAG021800(i32 num)
{
  if (num & 1) num++;
  d.Long23306 += num;
}

//   TAG021c08
void InitializeCaches(pnt memStart, i32 memSize, pnt P3, i32 P4)
{ // P4 is (0x19bf8-endOS)=space above Operating System
  dReg D7;
  aReg A3;
  A3 = memStart;
  D7L = memSize;
  d.Pointer23280 = memStart;
  d.Pointer23318 = memStart;
  d.Pointer23294 = d.Pointer23298 = A3+D7L;
  d.Long23306 = D7L;
  d.Pointer23322 = P3;
  d.Long23326 = P4;
  d.ClusterCache = allocateMemory(1024,1); //TAG02175c
  d.ppqBuffers = (ITEMQ **)allocateMemory(5100,1); //TAG02175c

  ClearMemory((pnt)d.ppqBuffers, 5100); // TAG000a84
  d.GraphicIndex = (i16 *)allocateMemory(1460, 1); //TAG02175c
  fillMemory(d.GraphicIndex, 730, -1, 2);
  d.pwPointer23274 = (i16 *)allocateMemory(1460, 1); //TAG02175c
  d.pgUnused = NULL;
  d.pqFirstGraphic2 = NULL;
  d.pqLastGraphic = NULL;
  d.pqFirstGraphic = NULL;
  d.Long23358 = -1;
  //D7 = saveD7;
  //A3 = saveA3;
}

void TAG021cd8(void)
{
  dReg D0;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  D0L = d.Pointer23298 - d.Pointer23280;
  D0L = D0L > 370000 ? 1 : 0;
  TAG020fbc();
  d.Pointer23284 = d.Pointer23298 - 10000;
  d.Word23328 = 1;
  d.Pointer23310 = d.Pointer23314 = d.Pointer23284;
  d.Long23306 = 10000;
  D0L = d.Pointer23284 - d.Pointer23280;
  d.Long23336 = D0L;
}



i16 TAG022c90(i16 P1)
{
  dReg D0, D5, D6, D7;
  ITEMQ *pqA3;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  D7W = P1;
  if (d.Time != d.Long23358)
  {
    ClearGraphicList2();
  };
  D6W = d.GraphicIndex[D7W];
  if (D6W != -1)
  {
    TAG02289a(D6W);
    D0W = 1;
  }
  else
  {
    D5L = (ui16)(d.pwPointer23274[D7W] + 16);
    pqA3 = TAG0221f6(D5L);
    D6W = 0;
    while (d.ppqBuffers[D6W++] != 0) {};
    D6W--;
    d.GraphicIndex[D7W] = D6W;
    d.ppqBuffers[D6W] = pqA3;
    D0W = UI16(D7W | 0x8000);
    pqA3->graphicNum = D0W;
    D0W = 0;
  };
#ifdef _VERIFYPPQ
  verifyppq();
#endif
  return D0W;
}

pnt TAG022d38(i16 P1)
{
  dReg D0;
  aReg A0;
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  D0W = d.GraphicIndex[P1];
  A0 = (pnt)d.ppqBuffers[D0W];
  return A0+12;
}

void TAG022d5e(i16 P1)
{
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  TAG022778(d.GraphicIndex[P1]);
}

i16 GetGraphicExpSize(i32 P1) //(022d7a)
{
//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  return d.GraphicExpSizes[P1];
}

//*********************************************************
//
//*********************************************************
RESTARTABLE _StartCSB(const CSB_UI_MESSAGE * /*msg*/) //
{//(void)
  static aReg A4, A5;
  RESTARTMAP
    RESTART(1)
    RESTART(2)
    RESTART(3)
  END_RESTARTMAP
//  i32 dBankLen=programDescriptor[5]+programDescriptor[7];
  A4 = (char *) (&d);
  A4 += programDescriptor[7]; // uninitialized data,a4,initialized data
  A5=NULL; // Should stay that way.
  // Clear uninitialized memory.
  memset (A4-programDescriptor[7],0,sizeof (d));

  InitializeDBank(); // Pointers and initial values
  d.Pointer4 = NULL; // pointer to I-Bank (A5 in 68000 code).
  ShowPrisonDoor(_1_);
  GameIsComplete = false;
  if (fullscreenRequested) 
  {
    UI_ClearScreen();
    fullscreenActive = true;
  };
  //To get dump of prison   AsciiDump();
  for (;;)
  {
    MainLoop(_2_); //TAG00068e
    d.DynamicPaletteSwitching = 0;
    TAG01f9e6(_3_,d.GameIsLost); //Show Credits
    if (GameIsComplete) break;
  };
  RETURN;
}

RESTARTABLE _AskWhatToDo(void)
{//(i32)
  RESTARTMAP
    RESTART(1)
    RESTART(2)
    RESTART(3)
    RESTART(4)
    RESTART(5)
    RESTART(6)
    RESTART(7)
    RESTART(8)
    RESTART(9)
    RESTART(10)
  END_RESTARTMAP
  InitializeDBank(); // Pointers and initial values
  CountFloppyDrives();
  InitializeHeap();//TAG020286
  ReadGraphicsIndex(); // TAG021d9a
  TAG0208b4();
  DisplayChaosStrikesBack(_2_);
  ReadFloorAndCeilingBitmaps(0);
  ReadWallBitmaps(0);
      HopefullyNotNeeded();
  TAG001c6e();
/*
  TAG0010ae();
    //D0 = GetAbsFuncAddr(276); // TAG00dd78(276);
    //D0 = TAG00306c;
  d.pFunc23232 = TAG00306c;
    //D0 = TAG00dd78(&DetachItem16)
  d.pFunc23236 = DetachItem16;
  //  MemMove((pnt)palette,(pnt)&d.Palette11946, 32);
  //  MemMove((pnt)palette,(pnt)&d.Palette11978, 32);
  TAG0023b0();
  TAG000ec6(); // In supervisor mode
  jdisint(5);  // TRAP 14 (#26,#5);
  TAG0020ca();
  wvbl(_2_);
  MemMove((pnt)d.Palette552, (pnt)&d.Palette11946, 32); // Initialize palette
  MemMove((pnt)d.Palette552, (pnt)&d.Palette11978, 32); // Initialize palette
  TAG01f746(_3_);
  */
  setscreen(d.LogicalScreenBase,d.LogicalScreenBase,0);
  MemMove((pnt)d.Palette552, (pnt)&d.Palette11978, 32); // Initialize palette
#ifdef TARGET_OS_MAC
  MacShowCursor();
#endif
  DoMenu(_1_,  //build the menu
         "I AM READY, MASTER",
         "WHAT IS YOUR WISH?",
         "QUIT",
         "DUNGEON",
         "UTILITY",
         "HINT",
         1,
         1,
         1);
  if (PlaybackCommandOption)
  {
    GameMode = 1;
  }
  else
  {
    WaitForMenuSelect(_3_, 4,1,0,0);
    GameMode=i16Result-1;
  };
  switch (GameMode)
  {
  case 0:
    UI_PushMessage(UIM_TERMINATE);
    WAITFORMESSAGE(_4_); //Should never come back!
    ASSERT(0);
    break;
  case 1:
#ifdef TARGET_OS_MAC
    HideCursor();
#endif
    do
    {
      StartCSB(_5_);
    } while (RepeatGame);
    UI_PushMessage(UIM_TERMINATE);
    WAITFORMESSAGE(_6_); //Should never come back!
    ASSERT(0);
    break;
  case 2:
    StartChaos(_7_);
    UI_PushMessage(UIM_TERMINATE);
    WAITFORMESSAGE(_8_); //Should never come back!
    ASSERT(0);
    break;
    break;
  case 3:
    StartHint(_9_);
    UI_PushMessage(UIM_TERMINATE);
    WAITFORMESSAGE(_10_); //Should never come back!
    ASSERT(0);
    break;
    break;
  };
  RETURN;
}

