text: #include "diablo.h"
  
  DEVILUTION_BEGIN_NAMESPACE
  
  int numthemes;
  BOOL armorFlag;
  BOOL ThemeGoodIn[4];
  BOOL weaponFlag;
  BOOL treasureFlag;
  BOOL mFountainFlag;
  BOOL cauldronFlag;
  BOOL tFountainFlag;
  int zharlib;
  int themex;
  int themey;
  int themeVar1;
  ThemeStruct themes[MAXTHEMES];
  BOOL pFountainFlag;
  BOOL bFountainFlag;
  BOOL bCrossFlag;
  
  int ThemeGood[4] = { THEME_GOATSHRINE, THEME_SHRINE, THEME_SKELROOM, THEME_LIBRARY };
  
  int trm5x[25] = {
  	-2, -1, 0, 1, 2,
  	-2, -1, 0, 1, 2,
  	-2, -1, 0, 1, 2,
  	-2, -1, 0, 1, 2,
  	-2, -1, 0, 1, 2
  };
  
  int trm5y[25] = {
  	-2, -2, -2, -2, -2,
  	-1, -1, -1, -1, -1,
  	0, 0, 0, 0, 0,
  	1, 1, 1, 1, 1,
  	2, 2, 2, 2, 2
  };
  
  int trm3x[9] = {
  	-1, 0, 1,
  	-1, 0, 1,
  	-1, 0, 1
  };
  
  int trm3y[9] = {
  	-1, -1, -1,
  	0, 0, 0,
  	1, 1, 1
  };
  
  BOOL TFit_Shrine(int i)
  {
  	int xp, yp, found;
  
  	xp = 0;
  	yp = 0;
  	found = 0;
  	while (found == 0) {
  		if (dTransVal[xp][yp] == themes[i].ttval) {
  			if (nTrapTable[dPiece[xp][yp - 1]]
  			    && !nSolidTable[dPiece[xp - 1][yp]]
  			    && !nSolidTable[dPiece[xp + 1][yp]]
  			    && dTransVal[xp - 1][yp] == themes[i].ttval
  			    && dTransVal[xp + 1][yp] == themes[i].ttval
  			    && dObject[xp - 1][yp - 1] == 0
  			    && dObject[xp + 1][yp - 1] == 0) {
  				found = 1;
  			}
  			if (!found
  			    && nTrapTable[dPiece[xp - 1][yp]]
  			    && !nSolidTable[dPiece[xp][yp - 1]]
  			    && !nSolidTable[dPiece[xp][yp + 1]]
  			    && dTransVal[xp][yp - 1] == themes[i].ttval
  			    && dTransVal[xp][yp + 1] == themes[i].ttval
  			    && dObject[xp - 1][yp - 1] == 0
  			    && dObject[xp - 1][yp + 1] == 0) {
  				found = 2;
  			}
  		}
  		if (found == 0) {
  			xp++;
  			if (xp == MAXDUNX) {
  				xp = 0;
  				yp++;
  				if (yp == MAXDUNY)
  					return FALSE;
  			}
  		}
  	}
  	themex = xp;
  	themey = yp;
  	themeVar1 = found;
  	return TRUE;
  }
  
  BOOL TFit_Obj5(int t)
  {
  	int xp, yp;
  	int i, r, rs;
  	BOOL found;
  
  	xp = 0;
  	yp = 0;
  	r = random(0, 5) + 1;
  	rs = r;
  	while (r > 0) {
  		found = FALSE;
  		if (dTransVal[xp][yp] == themes[t].ttval && !nSolidTable[dPiece[xp][yp]]) {
  			found = TRUE;
  			for (i = 0; found && i < 25; i++) {
  				if (nSolidTable[dPiece[xp + trm5x[i]][yp + trm5y[i]]]) {
  					found = FALSE;
  				}
  				if (dTransVal[xp + trm5x[i]][yp + trm5y[i]] != themes[t].ttval) {
  					found = FALSE;
  				}
  			}
  		}
  
  		if (!found) {
  			xp++;
  			if (xp == MAXDUNX) {
  				xp = 0;
  				yp++;
  				if (yp == MAXDUNY) {
  					if (r == rs) {
  						return FALSE;
  					}
  					yp = 0;
  				}
  			}
  			continue;
  		}
  
  		r--;
  	}
  
  	themex = xp;
  	themey = yp;
  
  	return TRUE;
  }
  
  BOOL TFit_SkelRoom(int t)
  {
  	int i;
  
  	if (leveltype != 1 && leveltype != 2) {
  		return FALSE;
  	}
  
  	for (i = 0; i < nummtypes; i++) {
  		if (IsSkel(Monsters[i].mtype)) {
  			themeVar1 = i;
  			return TFit_Obj5(t);
  		}
  	}
  
  	return FALSE;
  }
  
  BOOL TFit_GoatShrine(int t)
  {
  	int i;
  
  	for (i = 0; i < nummtypes; i++) {
  		if (IsGoat(Monsters[i].mtype)) {
  			themeVar1 = i;
  			return TFit_Obj5(t);
  		}
  	}
  
  	return FALSE;
  }
  
  BOOL CheckThemeObj3(int xp, int yp, int t, int f)
  {
  	int i;
  
  	for (i = 0; i < 9; i++) {
  		if (xp + trm3x[i] < 0 || yp + trm3y[i] < 0)
  			return FALSE;
  		if (nSolidTable[dPiece[xp + trm3x[i]][yp + trm3y[i]]])
  			return FALSE;
  		if (dTransVal[xp + trm3x[i]][yp + trm3y[i]] != themes[t].ttval)
  			return FALSE;
  		if (dObject[xp + trm3x[i]][yp + trm3y[i]])
  			return FALSE;
  		if (f != -1 && !random(0, f))
  			return FALSE;
  	}
  
  	return TRUE;
  }
  
  BOOL TFit_Obj3(int t)
  {
  	int xp, yp;
  	char objrnd[4] = { 4, 4, 3, 5 };
  
  	for (yp = 1; yp < MAXDUNY - 1; yp++) {
  		for (xp = 1; xp < MAXDUNX - 1; xp++) {
  			if (CheckThemeObj3(xp, yp, t, objrnd[leveltype - 1])) {
  				themex = xp;
  				themey = yp;
  				return TRUE;
  			}
  		}
  	}
  
  	return FALSE;
  }
  
  BOOL CheckThemeReqs(int t)
  {
  	BOOL rv;
  
  	rv = TRUE;
  	switch (t) {
  	case THEME_SHRINE:
  	case THEME_SKELROOM:
  	case THEME_LIBRARY:
  		if (leveltype == DTYPE_CAVES || leveltype == DTYPE_HELL) {
  			rv = FALSE;
  		}
  		break;
  	case THEME_BLOODFOUNTAIN:
  		if (!bFountainFlag) {
  			rv = FALSE;
  		}
  		break;
  	case THEME_PURIFYINGFOUNTAIN:
  		if (!pFountainFlag) {
  			rv = FALSE;
  		}
  		break;
  	case THEME_ARMORSTAND:
  		if (leveltype == DTYPE_CATHEDRAL) {
  			rv = FALSE;
  		}
  		break;
  	case THEME_CAULDRON:
  		if (leveltype != DTYPE_HELL || !cauldronFlag) {
  			rv = FALSE;
  		}
  		break;
  	case THEME_MURKYFOUNTAIN:
  		if (!mFountainFlag) {
  			rv = FALSE;
  		}
  		break;
  	case THEME_TEARFOUNTAIN:
  		if (!tFountainFlag) {
  			rv = FALSE;
  		}
  		break;
  	case THEME_WEAPONRACK:
  		if (leveltype == DTYPE_CATHEDRAL) {
  			rv = FALSE;
  		}
  		break;
  	}
  
  	return rv;
  }
  
  BOOL SpecialThemeFit(int i, int t)
  {
  	BOOL rv;
  
  	rv = CheckThemeReqs(t);
  	switch (t) {
  	case THEME_SHRINE:
  	case THEME_LIBRARY:
  		if (rv) {
  			rv = TFit_Shrine(i);
  		}
  		break;
  	case THEME_SKELROOM:
  		if (rv) {
  			rv = TFit_SkelRoom(i);
  		}
  		break;
  	case THEME_BLOODFOUNTAIN:
  		if (rv) {
  			rv = TFit_Obj5(i);
  			if (rv) {
  				bFountainFlag = FALSE;
  			}
  		}
  		break;
  	case THEME_PURIFYINGFOUNTAIN:
  		if (rv) {
  			rv = TFit_Obj5(i);
  			if (rv) {
  				pFountainFlag = FALSE;
  			}
  		}
  		break;
  	case THEME_MURKYFOUNTAIN:
  		if (rv) {
  			rv = TFit_Obj5(i);
  			if (rv) {
  				mFountainFlag = FALSE;
  			}
  		}
  		break;
  	case THEME_TEARFOUNTAIN:
  		if (rv) {
  			rv = TFit_Obj5(i);
  			if (rv) {
  				tFountainFlag = FALSE;
  			}
  		}
  		break;
  	case THEME_CAULDRON:
  		if (rv) {
  			rv = TFit_Obj5(i);
  			if (rv) {
  				cauldronFlag = FALSE;
  			}
  		}
  		break;
  	case THEME_GOATSHRINE:
  		if (rv) {
  			rv = TFit_GoatShrine(i);
  		}
  		break;
  	case THEME_TORTURE:
  	case THEME_DECAPITATED:
  	case THEME_ARMORSTAND:
  	case THEME_BRNCROSS:
  	case THEME_WEAPONRACK:
  		if (rv) {
  			rv = TFit_Obj3(i);
  		}
  		break;
  	case THEME_TREASURE:
  		rv = treasureFlag;
  		if (treasureFlag) {
  			treasureFlag = FALSE;
  		}
  		break;
  	}
  
  	return rv;
  }
  
  BOOL CheckThemeRoom(int tv)
  {
  	int i, j, tarea;
  
  	for (i = 0; i < trigflag_4; i++) {
  		if (dTransVal[trigs[i]._tx][trigs[i]._ty] == tv)
  			return FALSE;
  	}
  
  	tarea = 0;
  	for (j = 0; j < MAXDUNY; j++) {
  		for (i = 0; i < MAXDUNX; i++) {
  			if (dTransVal[i][j] != tv)
  				continue;
  			if (dFlags[i][j] & DFLAG_POPULATED)
  				return FALSE;
  
  			tarea++;
  		}
  	}
  
  	if (leveltype == DTYPE_CATHEDRAL && (tarea < 9 || tarea > 100))
  		return FALSE;
  
  	for (j = 0; j < MAXDUNY; j++) {
  		for (i = 0; i < MAXDUNX; i++) {
  			if (dTransVal[i][j] != tv || nSolidTable[dPiece[i][j]])
  				continue;
  			if (dTransVal[i - 1][j] != tv && !nSolidTable[dPiece[i - 1][j]])
  				return FALSE;
  			if (dTransVal[i + 1][j] != tv && !nSolidTable[dPiece[i + 1][j]])
  				return FALSE;
  			if (dTransVal[i][j - 1] != tv && !nSolidTable[dPiece[i][j - 1]])
  				return FALSE;
  			if (dTransVal[i][j + 1] != tv && !nSolidTable[dPiece[i][j + 1]])
  				return FALSE;
  		}
  	}
  
  	return TRUE;
  }
  
  void InitThemes()
  {
  	int i, j;
  
  	zharlib = -1;
  	numthemes = 0;
  	bCrossFlag = FALSE;
  	armorFlag = TRUE;
  	bFountainFlag = TRUE;
  	cauldronFlag = TRUE;
  	mFountainFlag = TRUE;
  	pFountainFlag = TRUE;
  	tFountainFlag = TRUE;
  	treasureFlag = TRUE;
  	weaponFlag = TRUE;
  
  	if (currlevel == 16)
  		return;
  
  	if (leveltype == DTYPE_CATHEDRAL) {
  		for (i = 0; i < sizeof(ThemeGoodIn) / sizeof(ThemeGoodIn[0]); i++)
  			ThemeGoodIn[i] = FALSE;
  
  		for (i = 0; i < 256 && numthemes < MAXTHEMES; i++) {
  			if (CheckThemeRoom(i)) {
  				themes[numthemes].ttval = i;
  				for (j = ThemeGood[random(0, 4)];; j = random(0, 17)) {
  					if (SpecialThemeFit(numthemes, j)) {
  						break;
  					}
  				}
  				themes[numthemes].ttype = j;
  				numthemes++;
  			}
  		}
  	}
  	if (leveltype == 2 || leveltype == 3 || leveltype == 4) {
  		for (i = 0; i < themeCount; i++)
  			themes[i].ttype = THEME_NONE;
  		if (QuestStatus(QTYPE_ZHAR)) {
  			for (j = 0; j < themeCount; j++) {
  				themes[j].ttval = themeLoc[j].ttval;
  				if (SpecialThemeFit(j, THEME_LIBRARY)) {
  					themes[j].ttype = THEME_LIBRARY;
  					zharlib = j;
  					break;
  				}
  			}
  		}
  		for (i = 0; i < themeCount; i++) {
  			if (themes[i].ttype == THEME_NONE) {
  				themes[i].ttval = themeLoc[i].ttval;
  				for (j = ThemeGood[random(0, 4)];; j = random(0, 17)) {
  					if (SpecialThemeFit(i, j)) {
  						break;
  					}
  				}
  				themes[i].ttype = j;
  			}
  		}
  		numthemes += themeCount;
  	}
  }
  
  // HoldThemeRooms marks theme rooms as populated.
  void HoldThemeRooms()
  {
  	int i, x, y;
  
  	if (currlevel != 16) {
  		if (leveltype == DTYPE_CATHEDRAL) {
  			for (i = 0; i < numthemes; i++) {
  				for (y = 0; y < MAXDUNY; y++) {
  					for (x = 0; x < MAXDUNX; x++) {
  						if (dTransVal[x][y] == (char)themes[i].ttval) {
  							dFlags[x][y] |= DFLAG_POPULATED;
  						}
  					}
  				}
  			}
  		} else {
  			DRLG_HoldThemeRooms();
  		}
  	}
  }
  
  // PlaceThemeMonsts places theme monsters with the specified frequency.
  //
  // Parameters:
  //    - t: theme number (index into themes array).
  //    - f: frequency (1/f likelihood of adding monster).
  void PlaceThemeMonsts(int t, int f)
  {
  	int xp, yp;
  	int scattertypes[111];
  	int numscattypes, mtype, i;
  
  	numscattypes = 0;
  	for (i = 0; i < nummtypes; i++) {
  		if (Monsters[i].mPlaceFlags & 1) {
  			scattertypes[numscattypes] = i;
  			numscattypes++;
  		}
  	}
  	mtype = scattertypes[random(0, numscattypes)];
  	for (yp = 0; yp < MAXDUNY; yp++) {
  		for (xp = 0; xp < MAXDUNX; xp++) {
  			if (dTransVal[xp][yp] == themes[t].ttval && !nSolidTable[dPiece[xp][yp]] && dItem[xp][yp] == 0 && dObject[xp][yp] == 0) {
  				if (random(0, f) == 0) {
  					AddMonster(xp, yp, random(0, 8), mtype, 1);
  				}
  			}
  		}
  	}
  }
  
  // Theme_Barrel initializes the barrel theme.
  //
  // Parameters:
  //    - t: theme number (index into themes array).
  void Theme_Barrel(int t)
  {
  	int xp, yp, r;
  	char barrnd[4] = { 2, 6, 4, 8 };
  	char monstrnd[4] = { 5, 7, 3, 9 };
  
  	for (yp = 0; yp < MAXDUNY; yp++) {
  		for (xp = 0; xp < MAXDUNX; xp++) {
  			if (dTransVal[xp][yp] == themes[t].ttval && !nSolidTable[dPiece[xp][yp]]) {
  				if (random(0, barrnd[leveltype - 1]) == 0) {
  					r = random(0, barrnd[leveltype - 1]) != 0;
  					r += OBJ_BARREL;
  					AddObject(r, xp, yp);
  				}
  			}
  		}
  	}
  	PlaceThemeMonsts(t, monstrnd[leveltype - 1]);
  }
  
  // Theme_Shrine initializes the shrine theme.
  //
  // Parameters:
  //    - t: theme number (index into themes array).
  void Theme_Shrine(int t)
  {
  	char monstrnd[4] = { 6, 6, 3, 9 };
  
  	TFit_Shrine(t);
  	if (themeVar1 == 1) {
  		AddObject(OBJ_CANDLE2, themex - 1, themey);
  		AddObject(OBJ_SHRINER, themex, themey);
  		AddObject(OBJ_CANDLE2, themex + 1, themey);
  	} else {
  		AddObject(OBJ_CANDLE2, themex, themey - 1);
  		AddObject(OBJ_SHRINEL, themex, themey);
  		AddObject(OBJ_CANDLE2, themex, themey + 1);
  	}
  	PlaceThemeMonsts(t, monstrnd[leveltype - 1]);
  }
  
  // Theme_MonstPit initializes the monster pit theme.
  //
  // Parameters:
  //    - t: theme number (index into themes array).
  void Theme_MonstPit(int t)
  {
  	int r;
  	int ixp, iyp;
  	char monstrnd[4] = { 6, 7, 3, 9 };
  
  	r = random(0, 100) + 1;
  	ixp = 0;
  	iyp = 0;
  	if (r > 0) {
  		while (TRUE) {
  			if (dTransVal[ixp][iyp] == themes[t].ttval && !nSolidTable[dPiece[ixp][iyp]]) {
  				--r;
  			}
  			if (r <= 0) {
  				break;
  			}
  			ixp++;
  			if (ixp == MAXDUNX) {
  				ixp = 0;
  				iyp++;
  				if (iyp == MAXDUNY) {
  					iyp = 0;
  				}
  			}
  		}
  	}
  	CreateRndItem(ixp, iyp, TRUE, FALSE, TRUE);
  	ItemNoFlippy();
  	PlaceThemeMonsts(t, monstrnd[leveltype - 1]);
  }
  
  // Theme_SkelRoom initializes the skeleton room theme.
  //
  // Parameters:
  //    - t: theme number (index into themes array).
  void Theme_SkelRoom(int t)
  {
  	int xp, yp, i;
  	char monstrnd[4] = { 6, 7, 3, 9 };
  
  	TFit_SkelRoom(t);
  
  	xp = themex;
  	yp = themey;
  
  	AddObject(OBJ_SKFIRE, xp, yp);
  
  	if(random(0, monstrnd[leveltype - 1]) != 0) {
  		i = PreSpawnSkeleton();
  		SpawnSkeleton(i, xp - 1, yp - 1);
  	} else {
  		AddObject(OBJ_BANNERL, xp - 1, yp - 1);
  	}
  
  	i = PreSpawnSkeleton();
  	SpawnSkeleton(i, xp, yp - 1);
  
  	if(random(0, monstrnd[leveltype - 1]) != 0) {
  		i = PreSpawnSkeleton();
  		SpawnSkeleton(i, xp + 1, yp - 1);
  	} else {
  		AddObject(OBJ_BANNERR, xp + 1, yp - 1);
  	}
  	if(random(0, monstrnd[leveltype - 1]) != 0) {
  		i = PreSpawnSkeleton();
  		SpawnSkeleton(i, xp - 1, yp);
  	} else {
  		AddObject(OBJ_BANNERM, xp - 1, yp);
  	}
  	if(random(0, monstrnd[leveltype - 1]) != 0) {
  		i = PreSpawnSkeleton();
  		SpawnSkeleton(i, xp + 1, yp);
  	} else {
  		AddObject(OBJ_BANNERM, xp + 1, yp);
  	}
  	if(random(0, monstrnd[leveltype - 1]) != 0) {
  		i = PreSpawnSkeleton();
  		SpawnSkeleton(i, xp - 1, yp + 1);
  	} else {
  		AddObject(OBJ_BANNERR, xp - 1, yp + 1);
  	}
  
  	i = PreSpawnSkeleton();
  	SpawnSkeleton(i, xp, yp + 1);
  
  	if(random(0, monstrnd[leveltype - 1]) != 0) {
  		i = PreSpawnSkeleton();
  		SpawnSkeleton(i, xp + 1, yp + 1);
  	} else {
  		AddObject(OBJ_BANNERL, xp + 1, yp + 1);
  	}
  
  	if(dObject[xp][yp - 3] == 0) {
  		AddObject(OBJ_SKELBOOK, xp, yp - 2);
  	}
  	if(dObject[xp][yp + 3] == 0) {
  		AddObject(OBJ_SKELBOOK, xp, yp + 2);
  	}
  }
  
  // Theme_Treasure initializes the treasure theme.
  //
  // Parameters:
  //    - t: theme number (index into themes array).
  void Theme_Treasure(int t)
  {
  	int xp, yp;
  	int i;
  	char treasrnd[4] = { 4, 9, 7, 10 };
  	char monstrnd[4] = { 6, 8, 3, 7 };
  
  	GetRndSeed();
  	for (yp = 0; yp < MAXDUNY; yp++) {
  		for (xp = 0; xp < MAXDUNX; xp++) {
  			if (dTransVal[xp][yp] == themes[t].ttval && !nSolidTable[dPiece[xp][yp]]) {
  				int rv = random(0, treasrnd[leveltype - 1]);
  				// BUGFIX: the `2*` in `2*random(0, treasrnd...) == 0` has no effect, should probably be `random(0, 2*treasrnd...) == 0`
  				if ((2 * random(0, treasrnd[leveltype - 1])) == 0) {
  					CreateTypeItem(xp, yp, FALSE, ITYPE_GOLD, IMISC_NONE, FALSE, TRUE);
  					ItemNoFlippy();
  				}
  				if (rv == 0) {
  					CreateRndItem(xp, yp, FALSE, FALSE, TRUE);
  					ItemNoFlippy();
  				}
  				if (rv == 0 || rv >= treasrnd[leveltype - 1] - 2) {
  					i = ItemNoFlippy();
  					if (rv >= treasrnd[leveltype - 1] - 2 && leveltype != DTYPE_CATHEDRAL) {
  						item[i]._ivalue >>= 1;
  					}
  				}
  			}
  		}
  	}
  	PlaceThemeMonsts(t, monstrnd[leveltype - 1]);
  }
  
  // Theme_Library initializes the library theme.
  //
  // Parameters:
  //    - t: theme number (index into themes array).
  void Theme_Library(int t)
  {
  	int xp, yp, oi;
  	char librnd[4] = { 1, 2, 2, 5 };
  	char monstrnd[4] = { 5, 7, 3, 9 };
  
  	TFit_Shrine(t);
  
  	if(themeVar1 == 1) {
  		AddObject(OBJ_BOOKCANDLE, themex - 1, themey);
  		AddObject(OBJ_BOOKCASER, themex, themey);
  		AddObject(OBJ_BOOKCANDLE, themex + 1, themey);
  	} else {
  		AddObject(OBJ_BOOKCANDLE, themex, themey - 1);
  		AddObject(OBJ_BOOKCASEL, themex, themey);
  		AddObject(OBJ_BOOKCANDLE, themex, themey + 1);
  	}
  
  	for(yp = 1; yp < MAXDUNY - 1; yp++) {
  		for(xp = 1; xp < MAXDUNX - 1; xp++) {
  			if(CheckThemeObj3(xp, yp, t, -1) && dMonster[xp][yp] == 0 && random(0, librnd[leveltype - 1]) == 0) {
  				AddObject(OBJ_BOOKSTAND, xp, yp);
  				if(random(0, 2 * librnd[leveltype - 1]) != 0) {
  					oi = dObject[xp][yp] - 1;
  					object[oi]._oSelFlag = 0;
  					object[oi]._oAnimFrame += 2;
  				}
  			}
  		}
  	}
  
  	if(!QuestStatus(QTYPE_ZHAR)) {
  		PlaceThemeMonsts(t, monstrnd[leveltype]); /// BUGFIX: `leveltype - 1`
  	} else if(t != zharlib) {
  		PlaceThemeMonsts(t, monstrnd[leveltype]); /// BUGFIX: `leveltype - 1`
  	}
  }
  
  // Theme_Torture initializes the torture theme.
  //
  // Parameters:
  //    - t: theme number (index into themes array).
  void Theme_Torture(int t)
  {
  	int xp, yp;
  	char tortrnd[4] = { 6, 8, 3, 8 };
  	char monstrnd[4] = { 6, 8, 3, 9 };
  
  	for (yp = 1; yp < MAXDUNY - 1; yp++) {
  		for (xp = 1; xp < MAXDUNX - 1; xp++) {
  			if (dTransVal[xp][yp] == themes[t].ttval && !nSolidTable[dPiece[xp][yp]]) {
  				if (CheckThemeObj3(xp, yp, t, -1)) {
  					if (random(0, tortrnd[leveltype - 1]) == 0) {
  						AddObject(OBJ_TNUDEM2, xp, yp);
  					}
  				}
  			}
  		}
  	}
  	PlaceThemeMonsts(t, monstrnd[leveltype - 1]);
  }
  
  // Theme_BloodFountain initializes the blood fountain theme.
  //
  // Parameters:
  //    - t: theme number (index into themes array).
  void Theme_BloodFountain(int t)
  {
  	char monstrnd[4] = { 6, 8, 3, 9 };
  
  	TFit_Obj5(t);
  	AddObject(OBJ_BLOODFTN, themex, themey);
  	PlaceThemeMonsts(t, monstrnd[leveltype - 1]);
  }
  
  // Theme_Decap initializes the decapitated theme.
  //
  // Parameters:
  //    - t: theme number (index into themes array).
  void Theme_Decap(int t)
  {
  	int xp, yp;
  	char decaprnd[4] = { 6, 8, 3, 8 };
  	char monstrnd[4] = { 6, 8, 3, 9 };
  
  	for (yp = 1; yp < MAXDUNY - 1; yp++) {
  		for (xp = 1; xp < MAXDUNX - 1; xp++) {
  			if (dTransVal[xp][yp] == themes[t].ttval && !nSolidTable[dPiece[xp][yp]]) {
  				if (CheckThemeObj3(xp, yp, t, -1)) {
  					if (random(0, decaprnd[leveltype - 1]) == 0) {
  						AddObject(OBJ_DECAP, xp, yp);
  					}
  				}
  			}
  		}
  	}
  	PlaceThemeMonsts(t, monstrnd[leveltype - 1]);
  }
  
  // Theme_PurifyingFountain initializes the purifying fountain theme.
  //
  // Parameters:
  //    - t: theme number (index into themes array).
  void Theme_PurifyingFountain(int t)
  {
  	char monstrnd[4] = { 6, 7, 3, 9 };
  
  	TFit_Obj5(t);
  	AddObject(OBJ_PURIFYINGFTN, themex, themey);
  	PlaceThemeMonsts(t, monstrnd[leveltype - 1]);
  }
  
  // Theme_ArmorStand initializes the armor stand theme.
  //
  // Parameters:
  //    - t: theme number (index into themes array).
  void Theme_ArmorStand(int t)
  {
  	int xp, yp;
  	char armorrnd[4] = { 6, 8, 3, 8 };
  	char monstrnd[4] = { 6, 7, 3, 9 };
  
  	if (armorFlag) {
  		TFit_Obj3(t);
  		AddObject(OBJ_ARMORSTAND, themex, themey);
  	}
  	for (yp = 0; yp < MAXDUNY; yp++) {
  		for (xp = 0; xp < MAXDUNX; xp++) {
  			if (dTransVal[xp][yp] == themes[t].ttval && !nSolidTable[dPiece[xp][yp]]) {
  				if (CheckThemeObj3(xp, yp, t, -1)) {
  					if (random(0, armorrnd[leveltype - 1]) == 0) {
  						AddObject(OBJ_ARMORSTANDN, xp, yp);
  					}
  				}
  			}
  		}
  	}
  	PlaceThemeMonsts(t, monstrnd[leveltype - 1]);
  	armorFlag = FALSE;
  }
  
  // Theme_GoatShrine initializes the goat shrine theme.
  //
  // Parameters:
  //    - t: theme number (index into themes array).
  void Theme_GoatShrine(int t)
  {
  	int xx, yy;
  
  	TFit_GoatShrine(t);
  	AddObject(OBJ_GOATSHRINE, themex, themey);
  	for (yy = themey - 1; yy <= themey + 1; yy++) {
  		for (xx = themex - 1; xx <= themex + 1; xx++) {
  			if (dTransVal[xx][yy] == themes[t].ttval && !nSolidTable[dPiece[xx][yy]] && (xx != themex || yy != themey)) {
  				AddMonster(xx, yy, DIR_SW, themeVar1, 1);
  			}
  		}
  	}
  }
  
  // Theme_Cauldron initializes the cauldron theme.
  //
  // Parameters:
  //    - t: theme number (index into themes array).
  void Theme_Cauldron(int t)
  {
  	char monstrnd[4] = { 6, 7, 3, 9 };
  
  	TFit_Obj5(t);
  	AddObject(OBJ_CAULDRON, themex, themey);
  	PlaceThemeMonsts(t, monstrnd[leveltype - 1]);
  }
  
  // Theme_MurkyFountain initializes the murky fountain theme.
  //
  // Parameters:
  //    - t: theme number (index into themes array).
  void Theme_MurkyFountain(int t)
  {
  	char monstrnd[4] = { 6, 7, 3, 9 };
  
  	TFit_Obj5(t);
  	AddObject(OBJ_MURKYFTN, themex, themey);
  	PlaceThemeMonsts(t, monstrnd[leveltype - 1]);
  }
  
  // Theme_TearFountain initializes the tear fountain theme.
  //
  // Parameters:
  //    - t: theme number (index into themes array).
  void Theme_TearFountain(int t)
  {
  	char monstrnd[4] = { 6, 7, 3, 9 };
  
  	TFit_Obj5(t);
  	AddObject(OBJ_TEARFTN, themex, themey);
  	PlaceThemeMonsts(t, monstrnd[leveltype - 1]);
  }
  
  // Theme_BrnCross initializes the burning cross theme.
  //
  // Parameters:
  //    - t: theme number (index into themes array).
  void Theme_BrnCross(int t)
  {
  	int xp, yp;
  	char monstrnd[4] = { 6, 8, 3, 9 };
  	char bcrossrnd[4] = { 5, 7, 3, 8 };
  
  	for (yp = 0; yp < MAXDUNY; yp++) {
  		for (xp = 0; xp < MAXDUNX; xp++) {
  			if (dTransVal[xp][yp] == themes[t].ttval && !nSolidTable[dPiece[xp][yp]]) {
  				if (CheckThemeObj3(xp, yp, t, -1)) {
  					if (random(0, bcrossrnd[leveltype - 1]) == 0) {
  						AddObject(OBJ_TBCROSS, xp, yp);
  					}
  				}
  			}
  		}
  	}
  	PlaceThemeMonsts(t, monstrnd[leveltype - 1]);
  	bCrossFlag = TRUE;
  }
  
  // Theme_WeaponRack initializes the weapon rack theme.
  //
  // Parameters:
  //    - t: theme number (index into themes array).
  void Theme_WeaponRack(int t)
  {
  	int xp, yp;
  	char weaponrnd[4] = { 6, 8, 5, 8 };
  	char monstrnd[4] = { 6, 7, 3, 9 };
  
  	if (weaponFlag) {
  		TFit_Obj3(t);
  		AddObject(OBJ_WEAPONRACK, themex, themey);
  	}
  	for (yp = 0; yp < MAXDUNY; yp++) {
  		for (xp = 0; xp < MAXDUNX; xp++) {
  			if (dTransVal[xp][yp] == themes[t].ttval && !nSolidTable[dPiece[xp][yp]]) {
  				if (CheckThemeObj3(xp, yp, t, -1)) {
  					if (random(0, weaponrnd[leveltype - 1]) == 0) {
  						AddObject(OBJ_WEAPONRACKN, xp, yp);
  					}
  				}
  			}
  		}
  	}
  	PlaceThemeMonsts(t, monstrnd[leveltype - 1]);
  	weaponFlag = FALSE;
  }
  
  // UpdateL4Trans sets each value of the transparency map to 1.
  void UpdateL4Trans()
  {
  	int i, j;
  
  	for (j = 0; j < MAXDUNY; j++) {
  		for (i = 0; i < MAXDUNX; i++) {
  			if (dTransVal[i][j]) {
  				dTransVal[i][j] = 1;
  			}
  		}
  	}
  }
  
  // CreateThemeRooms adds thematic elements to rooms.
  void CreateThemeRooms()
  {
  	int i;
  
  	if (currlevel == 16) {
  		return;
  	}
  	InitObjFlag = TRUE;
  	for (i = 0; i < numthemes; i++) {
  		themex = 0;
  		themey = 0;
  		switch (themes[i].ttype) {
  		case THEME_BARREL:
  			Theme_Barrel(i);
  			break;
  		case THEME_SHRINE:
  			Theme_Shrine(i);
  			break;
  		case THEME_MONSTPIT:
  			Theme_MonstPit(i);
  			break;
  		case THEME_SKELROOM:
  			Theme_SkelRoom(i);
  			break;
  		case THEME_TREASURE:
  			Theme_Treasure(i);
  			break;
  		case THEME_LIBRARY:
  			Theme_Library(i);
  			break;
  		case THEME_TORTURE:
  			Theme_Torture(i);
  			break;
  		case THEME_BLOODFOUNTAIN:
  			Theme_BloodFountain(i);
  			break;
  		case THEME_DECAPITATED:
  			Theme_Decap(i);
  			break;
  		case THEME_PURIFYINGFOUNTAIN:
  			Theme_PurifyingFountain(i);
  			break;
  		case THEME_ARMORSTAND:
  			Theme_ArmorStand(i);
  			break;
  		case THEME_GOATSHRINE:
  			Theme_GoatShrine(i);
  			break;
  		case THEME_CAULDRON:
  			Theme_Cauldron(i);
  			break;
  		case THEME_MURKYFOUNTAIN:
  			Theme_MurkyFountain(i);
  			break;
  		case THEME_TEARFOUNTAIN:
  			Theme_TearFountain(i);
  			break;
  		case THEME_BRNCROSS:
  			Theme_BrnCross(i);
  			break;
  		case THEME_WEAPONRACK:
  			Theme_WeaponRack(i);
  			break;
  		}
  	}
  	InitObjFlag = FALSE;
  	if (leveltype == DTYPE_HELL && themeCount > 0) {
  		UpdateL4Trans();
  	}
  }
  
  DEVILUTION_END_NAMESPACE
  