text: /**
   * @file cursor.cpp
   *
   * Implementation of cursor tracking functionality.
   */
  #include "cursor.h"
  
  #include "control.h"
  #include "doom.h"
  #include "inv.h"
  #include "missiles.h"
  #include "render.h"
  #include "towners.h"
  #include "track.h"
  #include "trigs.h"
  #include "utils/language.h"
  
  namespace devilution {
  
  /** Pixel width of the current cursor image */
  int cursW;
  /** Pixel height of the current cursor image */
  int cursH;
  /** Current highlighted monster */
  int pcursmonst = -1;
  /** Width of current cursor in inventory cells */
  int icursW28;
  /** Height of current cursor in inventory cells */
  int icursH28;
  /** Cursor images CEL */
  BYTE *pCursCels;
  BYTE *pCursCels2;
  
  /** inv_item value */
  int8_t pcursinvitem;
  /** Pixel width of the current cursor image */
  int icursW;
  /** Pixel height of the current cursor image */
  int icursH;
  /** Current highlighted item */
  int8_t pcursitem;
  /** Current highlighted object */
  int8_t pcursobj;
  /** Current highlighted player */
  int8_t pcursplr;
  /** Current highlighted tile row */
  int cursmx;
  /** Current highlighted tile column */
  int cursmy;
  /** Previously highlighted monster */
  int pcurstemp;
  /** Index of current cursor image */
  int pcurs;
  
  /* rdata */
  /** Maps from objcurs.cel frame number to frame width. */
  const int InvItemWidth[] = {
  	// clang-format off
  	// Cursors
  	0, 33, 32, 32, 32, 32, 32, 32, 32, 32, 32, 23,
  	// Items
  	1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28,
  	1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28,
  	1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28,
  	1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28,
  	1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28,
  	1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28,
  	1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28,
  	1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28,
  	2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28,
  	2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28,
  	2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28,
  	2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28,
  	2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28,
  	2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28,
  	2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28,
  	2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28,
  	2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28,
  	1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28,
  	1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28,
  	1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28,
  	2 * 28, 2 * 28, 1 * 28, 1 * 28, 1 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28,
  	2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28,
  	2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28
  	// clang-format on
  };
  
  /** Maps from objcurs.cel frame number to frame height. */
  const int InvItemHeight[] = {
  	// clang-format off
  	// Cursors
  	0, 29, 32, 32, 32, 32, 32, 32, 32, 32, 32, 35,
  	// Items
  	1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28,
  	1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28,
  	1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28,
  	1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28,
  	1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28,
  	2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28,
  	3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28,
  	3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28,
  	2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28,
  	2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28,
  	3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28,
  	3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28,
  	3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28,
  	3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28,
  	3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28,
  	3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28,
  	3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28,
  	1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28,
  	1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28,
  	1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28,
  	2 * 28, 2 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28,
  	3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28,
  	3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28
  	// clang-format on
  };
  
  void InitCursor()
  {
  	assert(!pCursCels);
  	pCursCels = LoadFileInMem("Data\\Inv\\Objcurs.CEL", nullptr);
  	if (gbIsHellfire)
  		pCursCels2 = LoadFileInMem("Data\\Inv\\Objcurs2.CEL", nullptr);
  	ClearCursor();
  }
  
  void FreeCursor()
  {
  	MemFreeDbg(pCursCels);
  	MemFreeDbg(pCursCels2);
  	ClearCursor();
  }
  
  void SetICursor(int i)
  {
  	icursW = InvItemWidth[i];
  	icursH = InvItemHeight[i];
  	icursW28 = icursW / 28;
  	icursH28 = icursH / 28;
  }
  
  void NewCursor(int i)
  {
  	pcurs = i;
  	cursW = InvItemWidth[i];
  	cursH = InvItemHeight[i];
  	SetICursor(i);
  }
  
  void InitLevelCursor()
  {
  	NewCursor(CURSOR_HAND);
  	cursmx = ViewX;
  	cursmy = ViewY;
  	pcurstemp = -1;
  	pcursmonst = -1;
  	pcursobj = -1;
  	pcursitem = -1;
  	pcursplr = -1;
  	ClearCursor();
  }
  
  void CheckTown()
  {
  	int i, mx;
  
  	for (i = 0; i < nummissiles; i++) {
  		mx = missileactive[i];
  		if (missile[mx]._mitype == MIS_TOWN) {
  			if ((cursmx == missile[mx].position.tile.x - 1 && cursmy == missile[mx].position.tile.y)
  			    || (cursmx == missile[mx].position.tile.x && cursmy == missile[mx].position.tile.y - 1)
  			    || (cursmx == missile[mx].position.tile.x - 1 && cursmy == missile[mx].position.tile.y - 1)
  			    || (cursmx == missile[mx].position.tile.x - 2 && cursmy == missile[mx].position.tile.y - 1)
  			    || (cursmx == missile[mx].position.tile.x - 2 && cursmy == missile[mx].position.tile.y - 2)
  			    || (cursmx == missile[mx].position.tile.x - 1 && cursmy == missile[mx].position.tile.y - 2)
  			    || (cursmx == missile[mx].position.tile.x && cursmy == missile[mx].position.tile.y)) {
  				trigflag = true;
  				ClearPanel();
  				strcpy(infostr, _("Town Portal"));
  				sprintf(tempstr, _("from %s"), plr[missile[mx]._misource]._pName);
  				AddPanelString(tempstr, true);
  				cursmx = missile[mx].position.tile.x;
  				cursmy = missile[mx].position.tile.y;
  			}
  		}
  	}
  }
  
  void CheckRportal()
  {
  	int i, mx;
  
  	for (i = 0; i < nummissiles; i++) {
  		mx = missileactive[i];
  		if (missile[mx]._mitype == MIS_RPORTAL) {
  			if ((cursmx == missile[mx].position.tile.x - 1 && cursmy == missile[mx].position.tile.y)
  			    || (cursmx == missile[mx].position.tile.x && cursmy == missile[mx].position.tile.y - 1)
  			    || (cursmx == missile[mx].position.tile.x - 1 && cursmy == missile[mx].position.tile.y - 1)
  			    || (cursmx == missile[mx].position.tile.x - 2 && cursmy == missile[mx].position.tile.y - 1)
  			    || (cursmx == missile[mx].position.tile.x - 2 && cursmy == missile[mx].position.tile.y - 2)
  			    || (cursmx == missile[mx].position.tile.x - 1 && cursmy == missile[mx].position.tile.y - 2)
  			    || (cursmx == missile[mx].position.tile.x && cursmy == missile[mx].position.tile.y)) {
  				trigflag = true;
  				ClearPanel();
  				strcpy(infostr, _("Portal to"));
  				if (!setlevel)
  					strcpy(tempstr, _("The Unholy Altar"));
  				else
  					strcpy(tempstr, _("level 15"));
  				AddPanelString(tempstr, true);
  				cursmx = missile[mx].position.tile.x;
  				cursmy = missile[mx].position.tile.y;
  			}
  		}
  	}
  }
  
  void CheckCursMove()
  {
  	int i, sx, sy, fx, fy, mx, my, tx, ty, px, py, xx, yy, mi, columns, rows, xo, yo;
  	int8_t bv;
  	bool flipflag, flipx, flipy;
  
  	sx = MouseX;
  	sy = MouseY;
  
  	if (PANELS_COVER) {
  		if (chrflag || questlog) {
  			if (sx >= gnScreenWidth / 2) { /// BUGFIX: (sx >= gnScreenWidth / 2) (fixed)
  				sx -= gnScreenWidth / 4;
  			} else {
  				sx = 0;
  			}
  		} else if (invflag || sbookflag) {
  			if (sx <= gnScreenWidth / 2) {
  				sx += gnScreenWidth / 4;
  			} else {
  				sx = 0;
  			}
  		}
  	}
  	if (sy > PANEL_TOP - 1 && MouseX >= PANEL_LEFT && MouseX < PANEL_LEFT + PANEL_WIDTH && track_isscrolling()) {
  		sy = PANEL_TOP - 1;
  	}
  
  	if (!zoomflag) {
  		sx /= 2;
  		sy /= 2;
  	}
  
  	// Adjust by player offset and tile grid alignment
  	CalcTileOffset(&xo, &yo);
  	sx -= ScrollInfo.offset.x - xo;
  	sy -= ScrollInfo.offset.y - yo;
  
  	// Predict the next frame when walking to avoid input jitter
  	fx = plr[myplr].position.offset2.x / 256;
  	fy = plr[myplr].position.offset2.y / 256;
  	fx -= (plr[myplr].position.offset2.x + plr[myplr].position.velocity.x) / 256;
  	fy -= (plr[myplr].position.offset2.y + plr[myplr].position.velocity.y) / 256;
  	if (ScrollInfo._sdir != SDIR_NONE) {
  		sx -= fx;
  		sy -= fy;
  	}
  
  	// Convert to tile grid
  	mx = ViewX;
  	my = ViewY;
  
  	TilesInView(&columns, &rows);
  	int lrow = rows - RowsCoveredByPanel();
  
  	// Center player tile on screen
  	ShiftGrid(&mx, &my, -columns / 2, -lrow / 2);
  
  	// Align grid
  	if ((columns & 1) == 0 && (lrow & 1) == 0) {
  		sy += TILE_HEIGHT / 2;
  	} else if (columns & 1 && lrow & 1) {
  		sx -= TILE_WIDTH / 2;
  	} else if (columns & 1 && (lrow & 1) == 0) {
  		my++;
  	}
  
  	if (!zoomflag) {
  		sy -= TILE_HEIGHT / 4;
  	}
  
  	tx = sx / TILE_WIDTH;
  	ty = sy / TILE_HEIGHT;
  	ShiftGrid(&mx, &my, tx, ty);
  
  	// Shift position to match diamond grid aligment
  	px = sx % TILE_WIDTH;
  	py = sy % TILE_HEIGHT;
  
  	// Shift position to match diamond grid aligment
  	flipy = py < (px / 2);
  	if (flipy) {
  		my--;
  	}
  	flipx = py >= TILE_HEIGHT - (px / 2);
  	if (flipx) {
  		mx++;
  	}
  
  	if (mx < 0) {
  		mx = 0;
  	}
  	if (mx >= MAXDUNX) {
  		mx = MAXDUNX - 1;
  	}
  	if (my < 0) {
  		my = 0;
  	}
  	if (my >= MAXDUNY) {
  		my = MAXDUNY - 1;
  	}
  
  	flipflag = (flipy && flipx) || ((flipy || flipx) && px < TILE_WIDTH / 2);
  
  	pcurstemp = pcursmonst;
  	pcursmonst = -1;
  	pcursobj = -1;
  	pcursitem = -1;
  	if (pcursinvitem != -1) {
  		drawsbarflag = true;
  	}
  	pcursinvitem = -1;
  	pcursplr = -1;
  	uitemflag = false;
  	panelflag = false;
  	trigflag = false;
  
  	if (plr[myplr]._pInvincible) {
  		return;
  	}
  	if (pcurs >= CURSOR_FIRSTITEM || spselflag) {
  		cursmx = mx;
  		cursmy = my;
  		return;
  	}
  	if (MouseY > PANEL_TOP && MouseX >= PANEL_LEFT && MouseX <= PANEL_LEFT + PANEL_WIDTH) {
  		CheckPanelInfo();
  		return;
  	}
  	if (doomflag) {
  		return;
  	}
  	if (invflag && MouseX > RIGHT_PANEL && MouseY <= SPANEL_HEIGHT) {
  		pcursinvitem = CheckInvHLight();
  		return;
  	}
  	if (sbookflag && MouseX > RIGHT_PANEL && MouseY <= SPANEL_HEIGHT) {
  		return;
  	}
  	if ((chrflag || questlog) && MouseX < SPANEL_WIDTH && MouseY <= SPANEL_HEIGHT) {
  		return;
  	}
  
  	if (leveltype != DTYPE_TOWN) {
  		if (pcurstemp != -1) {
  			if (!flipflag && mx + 2 < MAXDUNX && my + 1 < MAXDUNY && dMonster[mx + 2][my + 1] != 0 && dFlags[mx + 2][my + 1] & BFLAG_LIT) {
  				mi = dMonster[mx + 2][my + 1] > 0 ? dMonster[mx + 2][my + 1] - 1 : -(dMonster[mx + 2][my + 1] + 1);
  				if (mi == pcurstemp && monster[mi]._mhitpoints >> 6 > 0 && monster[mi].MData->mSelFlag & 4) {
  					cursmx = mx + 2; /// BUGFIX: 'mx + 2' (fixed)
  					cursmy = my + 1; /// BUGFIX: 'my + 1' (fixed)
  					pcursmonst = mi;
  				}
  			}
  			if (flipflag && mx + 1 < MAXDUNX && my + 2 < MAXDUNY && dMonster[mx + 1][my + 2] != 0 && dFlags[mx + 1][my + 2] & BFLAG_LIT) {
  				mi = dMonster[mx + 1][my + 2] > 0 ? dMonster[mx + 1][my + 2] - 1 : -(dMonster[mx + 1][my + 2] + 1);
  				if (mi == pcurstemp && monster[mi]._mhitpoints >> 6 > 0 && monster[mi].MData->mSelFlag & 4) {
  					cursmx = mx + 1;
  					cursmy = my + 2;
  					pcursmonst = mi;
  				}
  			}
  			if (mx + 2 < MAXDUNX && my + 2 < MAXDUNY && dMonster[mx + 2][my + 2] != 0 && dFlags[mx + 2][my + 2] & BFLAG_LIT) {
  				mi = dMonster[mx + 2][my + 2] > 0 ? dMonster[mx + 2][my + 2] - 1 : -(dMonster[mx + 2][my + 2] + 1);
  				if (mi == pcurstemp && monster[mi]._mhitpoints >> 6 > 0 && monster[mi].MData->mSelFlag & 4) {
  					cursmx = mx + 2;
  					cursmy = my + 2;
  					pcursmonst = mi;
  				}
  			}
  			if (mx + 1 < MAXDUNX && !flipflag && dMonster[mx + 1][my] != 0 && dFlags[mx + 1][my] & BFLAG_LIT) {
  				mi = dMonster[mx + 1][my] > 0 ? dMonster[mx + 1][my] - 1 : -(dMonster[mx + 1][my] + 1);
  				if (mi == pcurstemp && monster[mi]._mhitpoints >> 6 > 0 && monster[mi].MData->mSelFlag & 2) {
  					cursmx = mx + 1;
  					cursmy = my;
  					pcursmonst = mi;
  				}
  			}
  			if (my + 1 < MAXDUNY && flipflag && dMonster[mx][my + 1] != 0 && dFlags[mx][my + 1] & BFLAG_LIT) {
  				mi = dMonster[mx][my + 1] > 0 ? dMonster[mx][my + 1] - 1 : -(dMonster[mx][my + 1] + 1);
  				if (mi == pcurstemp && monster[mi]._mhitpoints >> 6 > 0 && monster[mi].MData->mSelFlag & 2) {
  					cursmx = mx;
  					cursmy = my + 1;
  					pcursmonst = mi;
  				}
  			}
  			if (dMonster[mx][my] != 0 && dFlags[mx][my] & BFLAG_LIT) {
  				mi = dMonster[mx][my] > 0 ? dMonster[mx][my] - 1 : -(dMonster[mx][my] + 1);
  				if (mi == pcurstemp && monster[mi]._mhitpoints >> 6 > 0 && monster[mi].MData->mSelFlag & 1) {
  					cursmx = mx;
  					cursmy = my;
  					pcursmonst = mi;
  				}
  			}
  			if (mx + 1 < MAXDUNX && my + 1 < MAXDUNY && dMonster[mx + 1][my + 1] != 0 && dFlags[mx + 1][my + 1] & BFLAG_LIT) {
  				mi = dMonster[mx + 1][my + 1] > 0 ? dMonster[mx + 1][my + 1] - 1 : -(dMonster[mx + 1][my + 1] + 1);
  				if (mi == pcurstemp && monster[mi]._mhitpoints >> 6 > 0 && monster[mi].MData->mSelFlag & 2) {
  					cursmx = mx + 1;
  					cursmy = my + 1;
  					pcursmonst = mi;
  				}
  			}
  			if (pcursmonst != -1 && monster[pcursmonst]._mFlags & MFLAG_HIDDEN) {
  				pcursmonst = -1;
  				cursmx = mx;
  				cursmy = my;
  			}
  			if (pcursmonst != -1 && monster[pcursmonst]._mFlags & MFLAG_GOLEM && !(monster[pcursmonst]._mFlags & MFLAG_BERSERK)) {
  				pcursmonst = -1;
  			}
  			if (pcursmonst != -1) {
  				return;
  			}
  		}
  		if (!flipflag && mx + 2 < MAXDUNX && my + 1 < MAXDUNY && dMonster[mx + 2][my + 1] != 0 && dFlags[mx + 2][my + 1] & BFLAG_LIT) {
  			mi = dMonster[mx + 2][my + 1] > 0 ? dMonster[mx + 2][my + 1] - 1 : -(dMonster[mx + 2][my + 1] + 1);
  			if (monster[mi]._mhitpoints >> 6 > 0 && monster[mi].MData->mSelFlag & 4) {
  				cursmx = mx + 2;
  				cursmy = my + 1;
  				pcursmonst = mi;
  			}
  		}
  		if (flipflag && mx + 1 < MAXDUNX && my + 2 < MAXDUNY && dMonster[mx + 1][my + 2] != 0 && dFlags[mx + 1][my + 2] & BFLAG_LIT) {
  			mi = dMonster[mx + 1][my + 2] > 0 ? dMonster[mx + 1][my + 2] - 1 : -(dMonster[mx + 1][my + 2] + 1);
  			if (monster[mi]._mhitpoints >> 6 > 0 && monster[mi].MData->mSelFlag & 4) {
  				cursmx = mx + 1;
  				cursmy = my + 2;
  				pcursmonst = mi;
  			}
  		}
  		if (mx + 2 < MAXDUNX && my + 2 < MAXDUNY && dMonster[mx + 2][my + 2] != 0 && dFlags[mx + 2][my + 2] & BFLAG_LIT) {
  			mi = dMonster[mx + 2][my + 2] > 0 ? dMonster[mx + 2][my + 2] - 1 : -(dMonster[mx + 2][my + 2] + 1);
  			if (monster[mi]._mhitpoints >> 6 > 0 && monster[mi].MData->mSelFlag & 4) {
  				cursmx = mx + 2;
  				cursmy = my + 2;
  				pcursmonst = mi;
  			}
  		}
  		if (!flipflag && mx + 1 < MAXDUNX && dMonster[mx + 1][my] != 0 && dFlags[mx + 1][my] & BFLAG_LIT) {
  			mi = dMonster[mx + 1][my] > 0 ? dMonster[mx + 1][my] - 1 : -(dMonster[mx + 1][my] + 1);
  			if (monster[mi]._mhitpoints >> 6 > 0 && monster[mi].MData->mSelFlag & 2) {
  				cursmx = mx + 1;
  				cursmy = my;
  				pcursmonst = mi;
  			}
  		}
  		if (flipflag && my + 1 < MAXDUNY && dMonster[mx][my + 1] != 0 && dFlags[mx][my + 1] & BFLAG_LIT) {
  			mi = dMonster[mx][my + 1] > 0 ? dMonster[mx][my + 1] - 1 : -(dMonster[mx][my + 1] + 1);
  			if (monster[mi]._mhitpoints >> 6 > 0 && monster[mi].MData->mSelFlag & 2) {
  				cursmx = mx;
  				cursmy = my + 1;
  				pcursmonst = mi;
  			}
  		}
  		if (dMonster[mx][my] != 0 && dFlags[mx][my] & BFLAG_LIT) {
  			mi = dMonster[mx][my] > 0 ? dMonster[mx][my] - 1 : -(dMonster[mx][my] + 1);
  			if (monster[mi]._mhitpoints >> 6 > 0 && monster[mi].MData->mSelFlag & 1) {
  				cursmx = mx;
  				cursmy = my;
  				pcursmonst = mi;
  			}
  		}
  		if (mx + 1 < MAXDUNX && my + 1 < MAXDUNY && dMonster[mx + 1][my + 1] != 0 && dFlags[mx + 1][my + 1] & BFLAG_LIT) {
  			mi = dMonster[mx + 1][my + 1] > 0 ? dMonster[mx + 1][my + 1] - 1 : -(dMonster[mx + 1][my + 1] + 1);
  			if (monster[mi]._mhitpoints >> 6 > 0 && monster[mi].MData->mSelFlag & 2) {
  				cursmx = mx + 1;
  				cursmy = my + 1;
  				pcursmonst = mi;
  			}
  		}
  		if (pcursmonst != -1 && monster[pcursmonst]._mFlags & MFLAG_HIDDEN) {
  			pcursmonst = -1;
  			cursmx = mx;
  			cursmy = my;
  		}
  		if (pcursmonst != -1 && monster[pcursmonst]._mFlags & MFLAG_GOLEM && !(monster[pcursmonst]._mFlags & MFLAG_BERSERK)) {
  			pcursmonst = -1;
  		}
  	} else {
  		if (!flipflag && mx + 1 < MAXDUNX && dMonster[mx + 1][my] > 0) {
  			pcursmonst = dMonster[mx + 1][my] - 1;
  			cursmx = mx + 1;
  			cursmy = my;
  		}
  		if (flipflag && my + 1 < MAXDUNY && dMonster[mx][my + 1] > 0) {
  			pcursmonst = dMonster[mx][my + 1] - 1;
  			cursmx = mx;
  			cursmy = my + 1;
  		}
  		if (dMonster[mx][my] > 0) {
  			pcursmonst = dMonster[mx][my] - 1;
  			cursmx = mx;
  			cursmy = my;
  		}
  		if (mx + 1 < MAXDUNX && my + 1 < MAXDUNY && dMonster[mx + 1][my + 1] > 0) {
  			pcursmonst = dMonster[mx + 1][my + 1] - 1;
  			cursmx = mx + 1;
  			cursmy = my + 1;
  		}
  		if (pcursmonst != -1 && !towners[pcursmonst]._tSelFlag) {
  			pcursmonst = -1;
  		}
  	}
  
  	if (pcursmonst == -1) {
  		if (!flipflag && mx + 1 < MAXDUNX && dPlayer[mx + 1][my] != 0) {
  			bv = dPlayer[mx + 1][my] > 0 ? dPlayer[mx + 1][my] - 1 : -(dPlayer[mx + 1][my] + 1);
  			if (bv != myplr && plr[bv]._pHitPoints != 0) {
  				cursmx = mx + 1;
  				cursmy = my;
  				pcursplr = bv;
  			}
  		}
  		if (flipflag && my + 1 < MAXDUNY && dPlayer[mx][my + 1] != 0) {
  			bv = dPlayer[mx][my + 1] > 0 ? dPlayer[mx][my + 1] - 1 : -(dPlayer[mx][my + 1] + 1);
  			if (bv != myplr && plr[bv]._pHitPoints != 0) {
  				cursmx = mx;
  				cursmy = my + 1;
  				pcursplr = bv;
  			}
  		}
  		if (dPlayer[mx][my] != 0) {
  			bv = dPlayer[mx][my] > 0 ? dPlayer[mx][my] - 1 : -(dPlayer[mx][my] + 1);
  			if (bv != myplr) {
  				cursmx = mx;
  				cursmy = my;
  				pcursplr = bv;
  			}
  		}
  		if ((dFlags[mx][my] & BFLAG_DEAD_PLAYER) != 0) {
  			for (i = 0; i < MAX_PLRS; i++) {
  				if (plr[i].position.tile.x == mx && plr[i].position.tile.y == my && i != myplr) {
  					cursmx = mx;
  					cursmy = my;
  					pcursplr = i;
  				}
  			}
  		}
  		if (pcurs == CURSOR_RESURRECT) {
  			for (xx = -1; xx < 2; xx++) {
  				for (yy = -1; yy < 2; yy++) {
  					if (mx + xx < MAXDUNX && my + yy < MAXDUNY && dFlags[mx + xx][my + yy] & BFLAG_DEAD_PLAYER) {
  						for (i = 0; i < MAX_PLRS; i++) {
  							if (plr[i].position.tile.x == mx + xx && plr[i].position.tile.y == my + yy && i != myplr) {
  								cursmx = mx + xx;
  								cursmy = my + yy;
  								pcursplr = i;
  							}
  						}
  					}
  				}
  			}
  		}
  		if (mx + 1 < MAXDUNX && my + 1 < MAXDUNY && dPlayer[mx + 1][my + 1] != 0) {
  			bv = dPlayer[mx + 1][my + 1] > 0 ? dPlayer[mx + 1][my + 1] - 1 : -(dPlayer[mx + 1][my + 1] + 1);
  			if (bv != myplr && plr[bv]._pHitPoints != 0) {
  				cursmx = mx + 1;
  				cursmy = my + 1;
  				pcursplr = bv;
  			}
  		}
  	}
  	if (pcursmonst == -1 && pcursplr == -1) {
  		if (!flipflag && mx + 1 < MAXDUNX && dObject[mx + 1][my] != 0) {
  			bv = dObject[mx + 1][my] > 0 ? dObject[mx + 1][my] - 1 : -(dObject[mx + 1][my] + 1);
  			if (object[bv]._oSelFlag >= 2) {
  				cursmx = mx + 1;
  				cursmy = my;
  				pcursobj = bv;
  			}
  		}
  		if (flipflag && my + 1 < MAXDUNY && dObject[mx][my + 1] != 0) {
  			bv = dObject[mx][my + 1] > 0 ? dObject[mx][my + 1] - 1 : -(dObject[mx][my + 1] + 1);
  			if (object[bv]._oSelFlag >= 2) {
  				cursmx = mx;
  				cursmy = my + 1;
  				pcursobj = bv;
  			}
  		}
  		if (dObject[mx][my] != 0) {
  			bv = dObject[mx][my] > 0 ? dObject[mx][my] - 1 : -(dObject[mx][my] + 1);
  			if (object[bv]._oSelFlag == 1 || object[bv]._oSelFlag == 3) {
  				cursmx = mx;
  				cursmy = my;
  				pcursobj = bv;
  			}
  		}
  		if (mx + 1 < MAXDUNX && my + 1 < MAXDUNY && dObject[mx + 1][my + 1] != 0) {
  			bv = dObject[mx + 1][my + 1] > 0 ? dObject[mx + 1][my + 1] - 1 : -(dObject[mx + 1][my + 1] + 1);
  			if (object[bv]._oSelFlag >= 2) {
  				cursmx = mx + 1;
  				cursmy = my + 1;
  				pcursobj = bv;
  			}
  		}
  	}
  	if (pcursplr == -1 && pcursobj == -1 && pcursmonst == -1) {
  		if (!flipflag && mx + 1 < MAXDUNX && dItem[mx + 1][my] > 0) {
  			bv = dItem[mx + 1][my] - 1;
  			if (items[bv]._iSelFlag >= 2) {
  				cursmx = mx + 1;
  				cursmy = my;
  				pcursitem = bv;
  			}
  		}
  		if (flipflag && my + 1 < MAXDUNY && dItem[mx][my + 1] > 0) {
  			bv = dItem[mx][my + 1] - 1;
  			if (items[bv]._iSelFlag >= 2) {
  				cursmx = mx;
  				cursmy = my + 1;
  				pcursitem = bv;
  			}
  		}
  		if (dItem[mx][my] > 0) {
  			bv = dItem[mx][my] - 1;
  			if (items[bv]._iSelFlag == 1 || items[bv]._iSelFlag == 3) {
  				cursmx = mx;
  				cursmy = my;
  				pcursitem = bv;
  			}
  		}
  		if (mx + 1 < MAXDUNX && my + 1 < MAXDUNY && dItem[mx + 1][my + 1] > 0) {
  			bv = dItem[mx + 1][my + 1] - 1;
  			if (items[bv]._iSelFlag >= 2) {
  				cursmx = mx + 1;
  				cursmy = my + 1;
  				pcursitem = bv;
  			}
  		}
  		if (pcursitem == -1) {
  			cursmx = mx;
  			cursmy = my;
  			CheckTrigForce();
  			CheckTown();
  			CheckRportal();
  		}
  	}
  
  	if (pcurs == CURSOR_IDENTIFY) {
  		pcursobj = -1;
  		pcursmonst = -1;
  		pcursitem = -1;
  		cursmx = mx;
  		cursmy = my;
  	}
  	if (pcursmonst != -1 && monster[pcursmonst]._mFlags & MFLAG_GOLEM && !(monster[pcursmonst]._mFlags & MFLAG_BERSERK)) {
  		pcursmonst = -1;
  	}
  }
  
  } // namespace devilution
  