devilutionX/Source/scrollrt.cpp
Anders Jenbo 20621a0642
add all.h and use in place of diablo.h (#2005)
Now diablo.h is treated in the same way as all other header files of
Source, as it only contains the declarations of global variables and
functions of diablo.cpp.

Besides consistency, this also enables mods to include diablo.h just
like any other header file without having to include every header file
(and without having to include C++ specific aspects of the now all.h).
2020-02-14 13:12:54 +01:00

2897 lines
80 KiB
C++

#include "all.h"
#include "../3rdParty/Storm/Source/storm.h"
int light_table_index;
int PitchTbl[1024];
DWORD sgdwCursWdtOld;
DWORD sgdwCursX;
DWORD sgdwCursY;
BYTE *gpBufEnd;
DWORD sgdwCursHgt;
DWORD level_cel_block;
DWORD sgdwCursXOld;
DWORD sgdwCursYOld;
char arch_draw_type;
DDSURFACEDESC DDS_desc;
int cel_transparency_active;
int level_piece_id;
DWORD sgdwCursWdt;
void (*DrawPlrProc)(int, int, int, int, int, BYTE *, int, int, int, int);
BYTE sgSaveBack[8192];
int draw_monster_num;
DWORD sgdwCursHgtOld;
/* data */
/* used in 1.00 debug */
char *szMonModeAssert[18] = {
"standing",
"walking (1)",
"walking (2)",
"walking (3)",
"attacking",
"getting hit",
"dying",
"attacking (special)",
"fading in",
"fading out",
"attacking (ranged)",
"standing (special)",
"attacking (special ranged)",
"delaying",
"charging",
"stoned",
"healing",
"talking"
};
char *szPlrModeAssert[12] = {
"standing",
"walking (1)",
"walking (2)",
"walking (3)",
"attacking (melee)",
"attacking (ranged)",
"blocking",
"getting hit",
"dying",
"casting a spell",
"changing levels",
"quitting"
};
void ClearCursor() // CODE_FIX: this was supposed to be in cursor.cpp
{
sgdwCursWdt = 0;
sgdwCursWdtOld = 0;
}
/**
* @brief Remove the cursor from the backbuffer
*/
static void scrollrt_draw_cursor_back_buffer()
{
int i;
BYTE *src, *dst;
if (sgdwCursWdt == 0) {
return;
}
/// ASSERT: assert(gpBuffer);
src = sgSaveBack;
dst = &gpBuffer[SCREENXY(sgdwCursX, sgdwCursY)];
i = sgdwCursHgt;
if (sgdwCursHgt != 0) {
while (i--) {
memcpy(dst, src, sgdwCursWdt);
src += sgdwCursWdt;
dst += BUFFER_WIDTH;
}
}
sgdwCursXOld = sgdwCursX;
sgdwCursYOld = sgdwCursY;
sgdwCursWdtOld = sgdwCursWdt;
sgdwCursHgtOld = sgdwCursHgt;
sgdwCursWdt = 0;
}
/**
* @brief Draw the cursor on the backbuffer
*/
static void scrollrt_draw_cursor_item()
{
int i, mx, my, col;
BYTE *src, *dst;
/// ASSERT: assert(! sgdwCursWdt);
if (pcurs <= 0 || cursW == 0 || cursH == 0) {
return;
}
mx = MouseX - 1;
if (mx < 0) {
mx = 0;
} else if (mx > SCREEN_WIDTH - 1) {
return;
}
my = MouseY - 1;
if (my < 0) {
my = 0;
} else if (my > SCREEN_HEIGHT - 1) {
return;
}
sgdwCursX = mx;
sgdwCursWdt = sgdwCursX + cursW + 1;
if (sgdwCursWdt > SCREEN_WIDTH - 1) {
sgdwCursWdt = SCREEN_WIDTH - 1;
}
sgdwCursX &= ~3;
sgdwCursWdt |= 3;
sgdwCursWdt -= sgdwCursX;
sgdwCursWdt++;
sgdwCursY = my;
sgdwCursHgt = sgdwCursY + cursH + 1;
if (sgdwCursHgt > SCREEN_HEIGHT - 1) {
sgdwCursHgt = SCREEN_HEIGHT - 1;
}
sgdwCursHgt -= sgdwCursY;
sgdwCursHgt++;
/// ASSERT: assert(sgdwCursWdt * sgdwCursHgt < sizeof sgSaveBack);
/// ASSERT: assert(gpBuffer);
dst = sgSaveBack;
src = &gpBuffer[SCREENXY(sgdwCursX, sgdwCursY)];
for (i = sgdwCursHgt; i != 0; i--, dst += sgdwCursWdt, src += BUFFER_WIDTH) {
memcpy(dst, src, sgdwCursWdt);
}
mx++;
my++;
gpBufEnd = &gpBuffer[PitchTbl[SCREEN_HEIGHT + SCREEN_Y] - cursW - 2];
if (pcurs >= CURSOR_FIRSTITEM) {
col = PAL16_YELLOW + 5;
if (plr[myplr].HoldItem._iMagical != 0) {
col = PAL16_BLUE + 5;
}
if (!plr[myplr].HoldItem._iStatFlag) {
col = PAL16_RED + 5;
}
CelBlitOutlineSafe(col, mx + SCREEN_X, my + cursH + SCREEN_Y - 1, pCursCels, pcurs, cursW, 0, 8);
if (col != PAL16_RED + 5) {
CelClippedDrawSafe(mx + SCREEN_X, my + cursH + SCREEN_Y - 1, pCursCels, pcurs, cursW, 0, 8);
} else {
CelDrawLightRedSafe(mx + SCREEN_X, my + cursH + SCREEN_Y - 1, pCursCels, pcurs, cursW, 0, 8, 1);
}
} else {
CelClippedDrawSafe(mx + SCREEN_X, my + cursH + SCREEN_Y - 1, pCursCels, pcurs, cursW, 0, 8);
}
}
/**
* @brief Render a missile sprite
* @param x dPiece coordinate
* @param y dPiece coordinate
* @param sx Backbuffer coordinate
* @param sy Backbuffer coordinate
* @param CelSkip Skip part of sprite, see Cl2Draw
* @param CelCap Skip part of sprite, see Cl2Draw
* @param pre Is the sprite in the background
*/
void DrawMissile(int x, int y, int sx, int sy, int CelSkip, int CelCap, BOOL pre)
{
int i, mx, my, nCel;
MissileStruct *m;
BYTE *pCelBuff;
DWORD *pFrameTable;
if (dMissile[x][y] == -1) {
for (i = 0; i < nummissiles; i++) {
/// ASSERT: assert(missileactive[i] < MAXMISSILES);
if (missileactive[i] >= MAXMISSILES)
break;
m = &missile[missileactive[i]];
if (m->_mix == x && m->_miy == y && m->_miPreFlag == pre && m->_miDrawFlag) {
pCelBuff = m->_miAnimData;
if (!pCelBuff) {
// app_fatal("Draw Missile type %d: NULL Cel Buffer", m->_mitype);
return;
}
nCel = m->_miAnimFrame;
pFrameTable = (DWORD *)pCelBuff;
if (nCel < 1 || pFrameTable[0] > 50 || nCel > (int)pFrameTable[0]) {
// app_fatal("Draw Missile: frame %d of %d, missile type==%d", nCel, pFrameTable[0], m->_mitype);
return;
}
mx = sx + m->_mixoff - m->_miAnimWidth2;
my = sy + m->_miyoff;
if (m->_miUniqTrans)
Cl2DrawLightTbl(mx, my, m->_miAnimData, m->_miAnimFrame, m->_miAnimWidth, CelSkip, CelCap, m->_miUniqTrans + 3);
else if (m->_miLightFlag)
Cl2DrawLight(mx, my, m->_miAnimData, m->_miAnimFrame, m->_miAnimWidth, CelSkip, CelCap);
else
Cl2Draw(mx, my, m->_miAnimData, m->_miAnimFrame, m->_miAnimWidth, CelSkip, CelCap);
}
}
} else {
m = &missile[dMissile[x][y] - 1];
if (m->_miPreFlag == pre && m->_miDrawFlag) {
pCelBuff = m->_miAnimData;
if (!pCelBuff) {
// app_fatal("Draw Missile 2 type %d: NULL Cel Buffer", m->_mitype);
return;
}
nCel = m->_miAnimFrame;
pFrameTable = (DWORD *)pCelBuff;
if (nCel < 1 || pFrameTable[0] > 50 || nCel > (int)pFrameTable[0]) {
// app_fatal("Draw Missile 2: frame %d of %d, missile type==%d", nCel, pFrameTable[0], m->_mitype);
return;
}
mx = sx + m->_mixoff - m->_miAnimWidth2;
my = sy + m->_miyoff;
if (m->_miUniqTrans)
Cl2DrawLightTbl(mx, my, m->_miAnimData, m->_miAnimFrame, m->_miAnimWidth, CelSkip, CelCap, m->_miUniqTrans + 3);
else if (m->_miLightFlag)
Cl2DrawLight(mx, my, m->_miAnimData, m->_miAnimFrame, m->_miAnimWidth, CelSkip, CelCap);
else
Cl2Draw(mx, my, m->_miAnimData, m->_miAnimFrame, m->_miAnimWidth, CelSkip, CelCap);
}
}
}
/**
* @brief Render a missile sprite, check for overdraw on lower screen
* @param x dPiece coordinate
* @param y dPiece coordinate
* @param sx Backbuffer coordinate
* @param sy Backbuffer coordinate
* @param CelSkip Skip part of sprite, see Cl2Draw
* @param CelCap Skip part of sprite, see Cl2Draw
* @param pre Is the sprite in the background
*/
void DrawClippedMissile(int x, int y, int sx, int sy, int CelSkip, int CelCap, BOOL pre)
{
int i, mx, my, nCel;
MissileStruct *m;
BYTE *pCelBuff;
DWORD *pFrameTable;
if (dMissile[x][y] == -1) {
for (i = 0; i < nummissiles; i++) {
/// ASSERT: assert(missileactive[i] < MAXMISSILES);
if (missileactive[i] >= MAXMISSILES)
break;
m = &missile[missileactive[i]];
if (m->_mix == x && m->_miy == y && m->_miPreFlag == pre && m->_miDrawFlag) {
pCelBuff = m->_miAnimData;
if (!pCelBuff) {
// app_fatal("Draw Missile type %d Clipped: NULL Cel Buffer", m->_mitype);
return;
}
nCel = m->_miAnimFrame;
pFrameTable = (DWORD *)pCelBuff;
if (nCel < 1 || pFrameTable[0] > 50 || nCel > (int)pFrameTable[0]) {
// app_fatal("Draw Clipped Missile: frame %d of %d, missile type==%d", nCel, pFrameTable[0], m->_mitype);
return;
}
mx = sx + m->_mixoff - m->_miAnimWidth2;
my = sy + m->_miyoff;
if (m->_miUniqTrans)
Cl2DrawLightTblSafe(mx, my, m->_miAnimData, m->_miAnimFrame, m->_miAnimWidth, CelSkip, CelCap, m->_miUniqTrans + 3);
else if (m->_miLightFlag)
Cl2DrawLightSafe(mx, my, m->_miAnimData, m->_miAnimFrame, m->_miAnimWidth, CelSkip, CelCap);
else
Cl2DrawSafe(mx, my, m->_miAnimData, m->_miAnimFrame, m->_miAnimWidth, CelSkip, CelCap);
}
}
} else {
m = &missile[dMissile[x][y] - 1];
if (m->_miPreFlag == pre && m->_miDrawFlag) {
pCelBuff = m->_miAnimData;
if (!pCelBuff) {
// app_fatal("Draw Missile 2 type %d Clipped: NULL Cel Buffer", m->_mitype);
return;
}
nCel = m->_miAnimFrame;
pFrameTable = (DWORD *)pCelBuff;
if (nCel < 1 || pFrameTable[0] > 50 || nCel > (int)pFrameTable[0]) {
// app_fatal("Draw Clipped Missile 2: frame %d of %d, missile type==%d", nCel, pFrameTable[0], m->_mitype);
return;
}
mx = sx + m->_mixoff - m->_miAnimWidth2;
my = sy + m->_miyoff;
if (m->_miUniqTrans)
Cl2DrawLightTblSafe(mx, my, m->_miAnimData, m->_miAnimFrame, m->_miAnimWidth, CelSkip, CelCap, m->_miUniqTrans + 3);
else if (m->_miLightFlag)
Cl2DrawLightSafe(mx, my, m->_miAnimData, m->_miAnimFrame, m->_miAnimWidth, CelSkip, CelCap);
else
Cl2DrawSafe(mx, my, m->_miAnimData, m->_miAnimFrame, m->_miAnimWidth, CelSkip, CelCap);
}
}
}
/**
* @brief Render a monster sprite
* @param x dPiece coordinate
* @param y dPiece coordinate
* @param mx Backbuffer coordinate
* @param my Backbuffer coordinate
* @param CelSkip Skip part of sprite, see Cl2Draw
* @param CelCap Skip part of sprite, see Cl2Draw
*/
static void DrawMonster(int x, int y, int mx, int my, int m, int CelSkip, int CelCap)
{
int nCel;
char trans;
BYTE *pCelBuff;
DWORD *pFrameTable;
if ((DWORD)m >= MAXMONSTERS) {
// app_fatal("Draw Monster: tried to draw illegal monster %d", m);
return;
}
pCelBuff = monster[m]._mAnimData;
if (!pCelBuff) {
// app_fatal("Draw Monster \"%s\": NULL Cel Buffer", monster[m].mName);
return;
}
nCel = monster[m]._mAnimFrame;
pFrameTable = (DWORD *)pCelBuff;
if (nCel < 1 || pFrameTable[0] > 50 || nCel > (int)pFrameTable[0]) {
/*
const char *szMode = "unknown action";
if(monster[m]._mmode <= 17)
szMode = szMonModeAssert[monster[m]._mmode];
app_fatal(
"Draw Monster \"%s\" %s: facing %d, frame %d of %d",
monster[m].mName,
szMode,
monster[m]._mdir,
nCel,
pFrameTable[0]);
*/
return;
}
if (!(dFlags[x][y] & BFLAG_LIT)) {
Cl2DrawLightTbl(mx, my, monster[m]._mAnimData, monster[m]._mAnimFrame, monster[m].MType->width, CelSkip, CelCap, 1);
} else {
trans = 0;
if (monster[m]._uniqtype)
trans = monster[m]._uniqtrans + 4;
if (monster[m]._mmode == MM_STONE)
trans = 2;
if (plr[myplr]._pInfraFlag && light_table_index > 8)
trans = 1;
if (trans)
Cl2DrawLightTbl(mx, my, monster[m]._mAnimData, monster[m]._mAnimFrame, monster[m].MType->width, CelSkip, CelCap, trans);
else
Cl2DrawLight(mx, my, monster[m]._mAnimData, monster[m]._mAnimFrame, monster[m].MType->width, CelSkip, CelCap);
}
}
/**
* @brief Render a monster sprite, check for overdraw on lower screen
* @param x dPiece coordinate
* @param y dPiece coordinate
* @param mx Backbuffer coordinate
* @param my Backbuffer coordinate
* @param CelSkip Skip part of sprite, see Cl2Draw
* @param CelCap Skip part of sprite, see Cl2Draw
*/
static void DrawClippedMonster(int x, int y, int mx, int my, int m, int CelSkip, int CelCap)
{
int nCel;
char trans;
BYTE *pCelBuff;
DWORD *pFrameTable;
if ((DWORD)m >= MAXMONSTERS) {
// app_fatal("Draw Monster Clipped: tried to draw illegal monster %d", m);
return;
}
pCelBuff = monster[m]._mAnimData;
if (!pCelBuff) {
// app_fatal("Draw Monster \"%s\" Clipped: NULL Cel Buffer", monster[m].mName);
return;
}
nCel = monster[m]._mAnimFrame;
pFrameTable = (DWORD *)pCelBuff;
if (nCel < 1 || pFrameTable[0] > 50 || nCel > (int)pFrameTable[0]) {
/*
const char *szMode = "unknown action";
if(monster[m]._mmode <= 17)
szMode = szMonModeAssert[monster[m]._mmode];
app_fatal(
"Draw Monster \"%s\" %s Clipped: facing %d, frame %d of %d",
monster[m].mName,
szMode,
monster[m]._mdir,
nCel,
pFrameTable[0]);
*/
return;
}
if (!(dFlags[x][y] & BFLAG_LIT)) {
Cl2DrawLightTblSafe(mx, my, monster[m]._mAnimData, monster[m]._mAnimFrame, monster[m].MType->width, CelSkip, CelCap, 1);
} else {
trans = 0;
if (monster[m]._uniqtype)
trans = monster[m]._uniqtrans + 4;
if (monster[m]._mmode == MM_STONE)
trans = 2;
if (plr[myplr]._pInfraFlag && light_table_index > 8)
trans = 1;
if (trans)
Cl2DrawLightTblSafe(mx, my, monster[m]._mAnimData, monster[m]._mAnimFrame, monster[m].MType->width, CelSkip, CelCap, trans);
else
Cl2DrawLightSafe(mx, my, monster[m]._mAnimData, monster[m]._mAnimFrame, monster[m].MType->width, CelSkip, CelCap);
}
}
/**
* @brief Render a monster sprite
* @param pnum Player id
* @param x dPiece coordinate
* @param y dPiece coordinate
* @param px Backbuffer coordinate
* @param py Backbuffer coordinate
* @param pCelBuff sprite buffer
* @param nCel frame
* @param nWidth width
* @param CelSkip Skip part of sprite, see Cl2Draw
* @param CelCap Skip part of sprite, see Cl2Draw
*/
static void DrawPlayer(int pnum, int x, int y, int px, int py, BYTE *pCelBuff, int nCel, int nWidth, int CelSkip, int CelCap)
{
int l;
DWORD *pFrameTable;
if (dFlags[x][y] & BFLAG_LIT || plr[myplr]._pInfraFlag || !setlevel && !currlevel) {
if (!pCelBuff) {
// app_fatal("Drawing player %d \"%s\": NULL Cel Buffer", pnum, plr[pnum]._pName);
return;
}
pFrameTable = (DWORD *)pCelBuff;
if (nCel < 1 || pFrameTable[0] > 50 || nCel > (int)pFrameTable[0]) {
/*
const char *szMode = "unknown action";
if(plr[pnum]._pmode <= PM_QUIT)
szMode = szPlrModeAssert[plr[pnum]._pmode];
app_fatal(
"Drawing player %d \"%s\" %s: facing %d, frame %d of %d",
pnum,
plr[pnum]._pName,
szMode,
plr[pnum]._pdir,
nCel,
pFrameTable[0]);
*/
return;
}
if (pnum == pcursplr)
Cl2DrawOutline(165, px, py, pCelBuff, nCel, nWidth, CelSkip, CelCap);
if (pnum == myplr) {
Cl2Draw(px, py, pCelBuff, nCel, nWidth, CelSkip, CelCap);
if (plr[pnum].pManaShield)
Cl2Draw(
px + plr[pnum]._pAnimWidth2 - misfiledata[MFILE_MANASHLD].mAnimWidth2[0],
py,
misfiledata[MFILE_MANASHLD].mAnimData[0],
1,
misfiledata[MFILE_MANASHLD].mAnimWidth[0],
CelSkip,
CelCap);
} else if (!(dFlags[x][y] & BFLAG_LIT) || plr[myplr]._pInfraFlag && light_table_index > 8) {
Cl2DrawLightTbl(px, py, pCelBuff, nCel, nWidth, CelSkip, CelCap, 1);
if (plr[pnum].pManaShield)
Cl2DrawLightTbl(
px + plr[pnum]._pAnimWidth2 - misfiledata[MFILE_MANASHLD].mAnimWidth2[0],
py,
misfiledata[MFILE_MANASHLD].mAnimData[0],
1,
misfiledata[MFILE_MANASHLD].mAnimWidth[0],
CelSkip,
CelCap,
1);
} else {
l = light_table_index;
if (light_table_index < 5)
light_table_index = 0;
else
light_table_index -= 5;
Cl2DrawLight(px, py, pCelBuff, nCel, nWidth, CelSkip, CelCap);
if (plr[pnum].pManaShield)
Cl2DrawLight(
px + plr[pnum]._pAnimWidth2 - misfiledata[MFILE_MANASHLD].mAnimWidth2[0],
py,
misfiledata[MFILE_MANASHLD].mAnimData[0],
1,
misfiledata[MFILE_MANASHLD].mAnimWidth[0],
CelSkip,
CelCap);
light_table_index = l;
}
}
}
/**
* @brief Render a monster sprite, check for overdraw on lower screen
* @param pnum Player id
* @param x dPiece coordinate
* @param y dPiece coordinate
* @param px Backbuffer coordinate
* @param py Backbuffer coordinate
* @param pCelBuff sprite buffer
* @param nCel frame
* @param nWidth width
* @param CelSkip Skip part of sprite, see Cl2Draw
* @param CelCap Skip part of sprite, see Cl2Draw
*/
static void DrawClippedPlayer(int pnum, int x, int y, int px, int py, BYTE *pCelBuff, int nCel, int nWidth, int CelSkip, int CelCap)
{
int l;
DWORD *pFrameTable;
if (dFlags[x][y] & BFLAG_LIT || plr[myplr]._pInfraFlag) {
if (!pCelBuff) {
// app_fatal("Drawing player %d \"%s\" clipped: NULL Cel Buffer", pnum, plr[pnum]._pName);
return;
}
pFrameTable = (DWORD *)pCelBuff;
if (nCel < 1 || pFrameTable[0] > 50 || nCel > (int)pFrameTable[0]) {
/*
const char *szMode = "unknown action";
if(plr[pnum]._pmode <= PM_QUIT)
szMode = szPlrModeAssert[plr[pnum]._pmode];
app_fatal(
"Drawing player %d \"%s\" %s clipped: facing %d, frame %d of %d",
pnum,
plr[pnum]._pName,
szMode,
plr[pnum]._pdir,
nCel,
pFrameTable[0]);
*/
return;
}
if (pnum == pcursplr)
Cl2DrawOutlineSafe(165, px, py, pCelBuff, nCel, nWidth, CelSkip, CelCap);
if (pnum == myplr) {
Cl2DrawSafe(px, py, pCelBuff, nCel, nWidth, CelSkip, CelCap);
if (plr[pnum].pManaShield)
Cl2DrawSafe(
px + plr[pnum]._pAnimWidth2 - misfiledata[MFILE_MANASHLD].mAnimWidth2[0],
py,
misfiledata[MFILE_MANASHLD].mAnimData[0],
1,
misfiledata[MFILE_MANASHLD].mAnimWidth[0],
CelSkip,
CelCap);
} else if (!(dFlags[x][y] & BFLAG_LIT) || plr[myplr]._pInfraFlag && light_table_index > 8) {
Cl2DrawLightTblSafe(px, py, pCelBuff, nCel, nWidth, CelSkip, CelCap, 1);
if (plr[pnum].pManaShield)
Cl2DrawLightTblSafe(
px + plr[pnum]._pAnimWidth2 - misfiledata[MFILE_MANASHLD].mAnimWidth2[0],
py,
misfiledata[MFILE_MANASHLD].mAnimData[0],
1,
misfiledata[MFILE_MANASHLD].mAnimWidth[0],
CelSkip,
CelCap,
1);
} else {
l = light_table_index;
if (light_table_index < 5)
light_table_index = 0;
else
light_table_index -= 5;
Cl2DrawLightSafe(px, py, pCelBuff, nCel, nWidth, CelSkip, CelCap);
if (plr[pnum].pManaShield)
Cl2DrawLightSafe(
px + plr[pnum]._pAnimWidth2 - misfiledata[MFILE_MANASHLD].mAnimWidth2[0],
py,
misfiledata[MFILE_MANASHLD].mAnimData[0],
1,
misfiledata[MFILE_MANASHLD].mAnimWidth[0],
CelSkip,
CelCap);
light_table_index = l;
}
}
}
/**
* @brief Render a monster sprite
* @param x dPiece coordinate
* @param y dPiece coordinate
* @param sx Backbuffer coordinate
* @param sy Backbuffer coordinate
* @param CelSkip Skip part of sprite, see Cl2Draw
* @param CelCap Skip part of sprite, see Cl2Draw
* @param clipped check for overdraw on lower screen
*/
void DrawDeadPlayer(int x, int y, int sx, int sy, int CelSkip, int CelCap, BOOL clipped)
{
int i, px, py, nCel;
PlayerStruct *p;
BYTE *pCelBuff;
DWORD *pFrameTable;
if (clipped)
DrawPlrProc = DrawClippedPlayer;
else
DrawPlrProc = DrawPlayer;
dFlags[x][y] &= ~BFLAG_DEAD_PLAYER;
for (i = 0; i < MAX_PLRS; i++) {
p = &plr[i];
if (p->plractive && !p->_pHitPoints && p->plrlevel == (BYTE)currlevel && p->WorldX == x && p->WorldY == y) {
pCelBuff = p->_pAnimData;
if (!pCelBuff) {
// app_fatal("Drawing dead player %d \"%s\": NULL Cel Buffer", i, p->_pName);
break;
}
nCel = p->_pAnimFrame;
pFrameTable = (DWORD *)pCelBuff;
if (nCel < 1 || pFrameTable[0] > 50 || nCel > (int)pFrameTable[0]) {
// app_fatal("Drawing dead player %d \"%s\": facing %d, frame %d of %d", i, p->_pName, p->_pdir, nCel, pFrameTable[0]);
break;
}
dFlags[x][y] |= BFLAG_DEAD_PLAYER;
px = sx + p->_pxoff - p->_pAnimWidth2;
py = sy + p->_pyoff;
DrawPlrProc(i, x, y, px, py, p->_pAnimData, p->_pAnimFrame, p->_pAnimWidth, CelSkip, CelCap);
}
}
}
/**
* @brief Render an object sprite
* @param x dPiece coordinate
* @param y dPiece coordinate
* @param ox Backbuffer coordinate
* @param oy Backbuffer coordinate
* @param pre Is the sprite in the background
* @param CelSkip Skip part of sprite, see Cl2Draw
* @param CelCap Skip part of sprite, see Cl2Draw
*/
static void DrawObject(int x, int y, int ox, int oy, BOOL pre, int CelSkip, int CelCap)
{
int sx, sy, xx, yy, nCel;
char bv;
BYTE *pCelBuff;
DWORD *pFrameTable;
if (dObject[x][y] > 0) {
bv = dObject[x][y] - 1;
if (object[bv]._oPreFlag != pre)
return;
sx = ox - object[bv]._oAnimWidth2;
sy = oy;
} else {
bv = -(dObject[x][y] + 1);
if (object[bv]._oPreFlag != pre)
return;
xx = object[bv]._ox - x;
yy = object[bv]._oy - y;
sx = (xx << 5) + ox - object[bv]._oAnimWidth2 - (yy << 5);
sy = oy + (yy << 4) + (xx << 4);
CelSkip = 0;
CelCap = 8;
}
/// ASSERT: assert((unsigned char)bv < MAXOBJECTS);
if ((BYTE)bv >= MAXOBJECTS)
return;
pCelBuff = object[bv]._oAnimData;
if (!pCelBuff) {
// app_fatal("Draw Object type %d: NULL Cel Buffer", object[bv]._otype);
return;
}
nCel = object[bv]._oAnimFrame;
pFrameTable = (DWORD *)pCelBuff;
if (nCel < 1 || pFrameTable[0] > 50 || nCel > (int)pFrameTable[0]) {
// app_fatal("Draw Object: frame %d of %d, object type==%d", nCel, pFrameTable[0], object[bv]._otype);
return;
}
if (bv == pcursobj)
CelBlitOutline(194, sx, sy, object[bv]._oAnimData, object[bv]._oAnimFrame, object[bv]._oAnimWidth, CelSkip, CelCap);
if (object[bv]._oLight) {
CelClippedDrawLight(sx, sy, object[bv]._oAnimData, object[bv]._oAnimFrame, object[bv]._oAnimWidth, CelSkip, CelCap);
} else {
/// ASSERT: assert(object[bv]._oAnimData);
if (object[bv]._oAnimData) // BUGFIX: _oAnimData was already checked, this is redundant
CelClippedDraw(sx, sy, object[bv]._oAnimData, object[bv]._oAnimFrame, object[bv]._oAnimWidth, CelSkip, CelCap);
}
}
/**
* @brief Render an object sprite, check for overdraw on lower screen
* @param x dPiece coordinate
* @param y dPiece coordinate
* @param ox Backbuffer coordinate
* @param oy Backbuffer coordinate
* @param pre Is the sprite in the background
* @param CelSkip Skip part of sprite, see Cl2Draw
* @param CelCap Skip part of sprite, see Cl2Draw
*/
static void DrawClippedObject(int x, int y, int ox, int oy, BOOL pre, int CelSkip, int CelCap)
{
int sx, sy, xx, yy, nCel;
char bv;
BYTE *pCelBuff;
DWORD *pFrameTable;
if (dObject[x][y] > 0) {
bv = dObject[x][y] - 1;
if (object[bv]._oPreFlag != pre)
return;
sx = ox - object[bv]._oAnimWidth2;
sy = oy;
} else {
bv = -(dObject[x][y] + 1);
if (object[bv]._oPreFlag != pre)
return;
xx = object[bv]._ox - x;
yy = object[bv]._oy - y;
sx = (xx << 5) + ox - object[bv]._oAnimWidth2 - (yy << 5);
sy = oy + (yy << 4) + (xx << 4);
CelSkip = 0;
CelCap = 8;
}
/// ASSERT: assert((unsigned char)bv < MAXOBJECTS);
if ((BYTE)bv >= MAXOBJECTS)
return;
pCelBuff = object[bv]._oAnimData;
if (!pCelBuff) {
// app_fatal("Draw Object type %d Clipped: NULL Cel Buffer", object[bv]._otype);
return;
}
nCel = object[bv]._oAnimFrame;
pFrameTable = (DWORD *)pCelBuff;
if (nCel < 1 || pFrameTable[0] > 50 || nCel > (int)pFrameTable[0]) {
// app_fatal("Draw Clipped Object: frame %d of %d, object type==%d", nCel, pFrameTable[0], object[bv]._otype);
return;
}
if (bv == pcursobj)
CelBlitOutlineSafe(194, sx, sy, object[bv]._oAnimData, object[bv]._oAnimFrame, object[bv]._oAnimWidth, CelSkip, CelCap);
if (object[bv]._oLight)
CelDrawLightSafe(sx, sy, object[bv]._oAnimData, object[bv]._oAnimFrame, object[bv]._oAnimWidth, CelSkip, CelCap);
else
CelClippedDrawSafe(sx, sy, object[bv]._oAnimData, object[bv]._oAnimFrame, object[bv]._oAnimWidth, CelSkip, CelCap);
}
static void scrollrt_draw_clipped_dungeon(BYTE *pBuff, int sx, int sy, int dx, int dy, int eflag);
/**
* This variant checks for of screen element on the lower screen
* This function it self causes rendering issues since it will render on top of objects on the other side of walls
* @brief Re render tile to workaround sorting issues with players walking east/west
* @param pBuff Pointer to output buffer at location sx,sy
* @param y dPiece coordinate
* @param x dPiece coordinate
* @param sx Backbuffer coordinate
* @param sy Backbuffer coordinate
*/
static void scrollrt_draw_clipped_e_flag(BYTE *pBuff, int x, int y, int sx, int sy)
{
int i, lti_old, cta_old, lpi_old;
BYTE *dst;
MICROS *pMap;
lti_old = light_table_index;
cta_old = cel_transparency_active;
lpi_old = level_piece_id;
level_piece_id = dPiece[x][y];
light_table_index = dLight[x][y];
cel_transparency_active = (BYTE)(nTransTable[level_piece_id] & TransList[dTransVal[x][y]]);
pMap = &dpiece_defs_map_1[IsometricCoord(x, y)];
dst = pBuff;
arch_draw_type = 1;
level_cel_block = pMap->mt[0];
if (level_cel_block != 0) {
drawLowerScreen(dst);
}
arch_draw_type = 2;
level_cel_block = pMap->mt[1];
if (level_cel_block != 0) {
drawLowerScreen(dst + 32);
}
dst = pBuff;
arch_draw_type = 0;
for (i = 2; i < MicroTileLen; i += 2) {
dst -= BUFFER_WIDTH * 32;
level_cel_block = pMap->mt[i];
if (level_cel_block != 0) {
drawLowerScreen(dst);
}
level_cel_block = pMap->mt[i + 1];
if (level_cel_block != 0) {
drawLowerScreen(dst + 32);
}
}
scrollrt_draw_clipped_dungeon(pBuff, x, y, sx, sy, 0);
light_table_index = lti_old;
cel_transparency_active = cta_old;
level_piece_id = lpi_old;
}
/**
* @brief Render object sprites
* @param pBuff where to render to with sx,sy already applied
* @param sx dPiece coordinate
* @param sy dPiece coordinate
* @param dx Backbuffer coordinate
* @param dy Backbuffer coordinate
* @param eflag Should the sorting workaround be applied
*/
static void scrollrt_draw_clipped_dungeon(BYTE *pBuff, int sx, int sy, int dx, int dy, int eflag)
{
int px, py, nCel, nMon, negMon, p;
char bFlag, bDead, bObj, bItem, bPlr, bArch, bMap, negPlr, dd;
DeadStruct *pDeadGuy;
ItemStruct *pItem;
PlayerStruct *pPlayer;
MonsterStruct *pMonster;
BYTE *pCelBuff;
DWORD *pFrameTable;
/// ASSERT: assert((DWORD)sx < MAXDUNX);
/// ASSERT: assert((DWORD)sy < MAXDUNY);
bFlag = dFlags[sx][sy];
bDead = dDead[sx][sy];
bObj = dObject[sx][sy];
bItem = dItem[sx][sy];
bPlr = dPlayer[sx][sy];
bArch = dArch[sx][sy];
bMap = dTransVal[sx][sy];
nMon = dMonster[sx][sy];
/// ASSERT: assert((DWORD)(sy-1) < MAXDUNY);
negPlr = dPlayer[sx][sy - 1];
negMon = dMonster[sx][sy - 1];
if (visiondebug && bFlag & BFLAG_LIT) {
CelClippedBlitSafe(pBuff, pSquareCel, 1, 64, 0, 8);
}
if (MissilePreFlag && bFlag & BFLAG_MISSILE) {
DrawClippedMissile(sx, sy, dx, dy, 0, 8, TRUE);
}
if (light_table_index < lightmax) {
if (bDead != 0) {
pDeadGuy = &dead[(bDead & 0x1F) - 1];
dd = (bDead >> 5) & 7;
px = dx - pDeadGuy->_deadWidth2;
pCelBuff = pDeadGuy->_deadData[dd];
/// ASSERT: assert(pDeadGuy->_deadData[dd] != NULL);
if (pCelBuff != NULL) {
pFrameTable = (DWORD *)pDeadGuy->_deadData[dd];
nCel = pDeadGuy->_deadFrame;
if (nCel >= 1 && pFrameTable[0] <= 50 && nCel <= (int)pFrameTable[0]) {
if (pDeadGuy->_deadtrans != 0) {
Cl2DrawLightTblSafe(px, dy, pCelBuff, nCel, pDeadGuy->_deadWidth, 0, 8, pDeadGuy->_deadtrans);
} else {
Cl2DrawLightSafe(px, dy, pCelBuff, pDeadGuy->_deadFrame, pDeadGuy->_deadWidth, 0, 8);
}
} else {
// app_fatal("Clipped dead sub: frame %d of %d, deadnum==%d", nCel, pFrameTable[0], (bDead & 0x1F) - 1);
}
}
}
if (bObj != 0) {
DrawClippedObject(sx, sy, dx, dy, 1, 0, 8);
}
}
if (bItem != 0) {
pItem = &item[bItem - 1];
if (!pItem->_iPostDraw) {
/// ASSERT: assert((unsigned char)bItem <= MAXITEMS);
if ((BYTE)bItem <= MAXITEMS) {
pCelBuff = pItem->_iAnimData;
if (pCelBuff != NULL) {
pFrameTable = (DWORD *)pCelBuff;
nCel = pItem->_iAnimFrame;
if (nCel >= 1 && pFrameTable[0] <= 50 && nCel <= (int)pFrameTable[0]) {
px = dx - pItem->_iAnimWidth2;
if (bItem - 1 == pcursitem) {
CelBlitOutlineSafe(181, px, dy, pCelBuff, nCel, pItem->_iAnimWidth, 0, 8);
}
CelDrawLightSafe(px, dy, pItem->_iAnimData, pItem->_iAnimFrame, pItem->_iAnimWidth, 0, 8);
} else {
/*
app_fatal(
"Draw Clipped \"%s\" Item: frame %d of %d, item type==%d",
pItem->_iIName,
nCel,
pFrameTable[0],
pItem->_itype);
*/
}
} else {
// app_fatal("Draw Item \"%s\" Clipped 1: NULL Cel Buffer", pItem->_iIName);
}
}
}
}
if (bFlag & BFLAG_PLAYERLR) {
p = -(negPlr + 1);
if ((DWORD)p < MAX_PLRS) {
pPlayer = &plr[p];
px = dx + pPlayer->_pxoff - pPlayer->_pAnimWidth2;
py = dy + pPlayer->_pyoff;
DrawClippedPlayer(p, sx, sy - 1, px, py, pPlayer->_pAnimData, pPlayer->_pAnimFrame, pPlayer->_pAnimWidth, 0, 8);
if (eflag && pPlayer->_peflag != 0) {
if (pPlayer->_peflag == 2) {
scrollrt_draw_clipped_e_flag(pBuff - (BUFFER_WIDTH * 16 + 96), sx - 2, sy + 1, dx - 96, dy - 16);
}
scrollrt_draw_clipped_e_flag(pBuff - 64, sx - 1, sy + 1, dx - 64, dy);
}
} else {
// app_fatal("draw player clipped: tried to draw illegal player %d", p);
}
}
if (bFlag & BFLAG_MONSTLR && (bFlag & BFLAG_LIT || plr[myplr]._pInfraFlag) && negMon < 0) {
draw_monster_num = -(negMon + 1);
if ((DWORD)draw_monster_num < MAXMONSTERS) {
pMonster = &monster[draw_monster_num];
if (!(pMonster->_mFlags & MFLAG_HIDDEN)) {
if (pMonster->MType != NULL) {
px = dx + pMonster->_mxoff - pMonster->MType->width2;
py = dy + pMonster->_myoff;
if (draw_monster_num == pcursmonst) {
Cl2DrawOutlineSafe(233, px, py, pMonster->_mAnimData, pMonster->_mAnimFrame, pMonster->MType->width, 0, 8);
}
DrawClippedMonster(sx, sy, px, py, draw_monster_num, 0, 8);
if (eflag && pMonster->_meflag) {
scrollrt_draw_clipped_e_flag(pBuff - 64, sx - 1, sy + 1, dx - 64, dy);
}
} else {
// app_fatal("Draw Monster \"%s\" Clipped: uninitialized monster", pMonster->mName);
}
}
} else {
// app_fatal("Draw Monster Clipped: tried to draw illegal monster %d", draw_monster_num);
}
}
if (bFlag & BFLAG_DEAD_PLAYER) {
DrawDeadPlayer(sx, sy, dx, dy, 0, 8, TRUE);
}
if (bPlr > 0) {
p = bPlr - 1;
if ((DWORD)p < MAX_PLRS) {
pPlayer = &plr[p];
px = dx + pPlayer->_pxoff - pPlayer->_pAnimWidth2;
py = dy + pPlayer->_pyoff;
DrawClippedPlayer(p, sx, sy, px, py, pPlayer->_pAnimData, pPlayer->_pAnimFrame, pPlayer->_pAnimWidth, 0, 8);
if (eflag && pPlayer->_peflag != 0) {
if (pPlayer->_peflag == 2) {
scrollrt_draw_clipped_e_flag(pBuff - (BUFFER_WIDTH * 16 + 96), sx - 2, sy + 1, dx - 96, dy - 16);
}
scrollrt_draw_clipped_e_flag(pBuff - 64, sx - 1, sy + 1, dx - 64, dy);
}
} else {
// app_fatal("draw player clipped: tried to draw illegal player %d", p);
}
}
if (nMon > 0 && (bFlag & BFLAG_LIT || plr[myplr]._pInfraFlag)) {
draw_monster_num = nMon - 1;
if ((DWORD)draw_monster_num < MAXMONSTERS) {
pMonster = &monster[draw_monster_num];
if (!(pMonster->_mFlags & MFLAG_HIDDEN)) {
if (pMonster->MType != NULL) {
px = dx + pMonster->_mxoff - pMonster->MType->width2;
py = dy + pMonster->_myoff;
if (draw_monster_num == pcursmonst) {
Cl2DrawOutlineSafe(233, px, py, pMonster->_mAnimData, pMonster->_mAnimFrame, pMonster->MType->width, 0, 8);
}
DrawClippedMonster(sx, sy, px, py, draw_monster_num, 0, 8);
if (eflag && pMonster->_meflag) {
scrollrt_draw_clipped_e_flag(pBuff - 64, sx - 1, sy + 1, dx - 64, dy);
}
} else {
// app_fatal("Draw Monster \"%s\" Clipped: uninitialized monster", pMonster->mName);
}
}
} else {
// app_fatal("Draw Monster Clipped: tried to draw illegal monster %d", draw_monster_num);
}
}
if (bFlag & BFLAG_MISSILE) {
DrawClippedMissile(sx, sy, dx, dy, 0, 8, FALSE);
}
if (bObj != 0 && light_table_index < lightmax) {
DrawClippedObject(sx, sy, dx, dy, 0, 0, 8);
}
if (bItem != 0) {
pItem = &item[bItem - 1];
if (pItem->_iPostDraw) {
/// ASSERT: assert((unsigned char)bItem <= MAXITEMS);
if ((BYTE)bItem <= MAXITEMS) {
pCelBuff = pItem->_iAnimData;
if (pCelBuff != NULL) {
pFrameTable = (DWORD *)pCelBuff;
nCel = pItem->_iAnimFrame;
if (nCel >= 1 && pFrameTable[0] <= 50 && nCel <= (int)pFrameTable[0]) {
px = dx - pItem->_iAnimWidth2;
if (bItem - 1 == pcursitem) {
CelBlitOutlineSafe(181, px, dy, pCelBuff, nCel, pItem->_iAnimWidth, 0, 8);
}
CelDrawLightSafe(px, dy, pItem->_iAnimData, pItem->_iAnimFrame, pItem->_iAnimWidth, 0, 8);
} else {
/*
app_fatal(
"Draw Clipped \"%s\" Item 2: frame %d of %d, item type==%d",
pItem->_iIName,
nCel,
pFrameTable[0],
pItem->_itype);
*/
}
} else {
// app_fatal("Draw Item \"%s\" Clipped 2: NULL Cel Buffer", pItem->_iIName);
}
}
}
}
if (bArch != 0) {
cel_transparency_active = TransList[bMap];
CelClippedBlitLightTransSafe(pBuff, pSpecialCels, bArch, 64, 0, 8);
}
}
/**
* @brief Render a row of tile
* @param x dPiece coordinate
* @param y dPiece coordinate
* @param sx Backbuffer coordinate
* @param sy Backbuffer coordinate
* @param chunks tile width of row
* @param eflag is it an even (0) or odd (1) row
*/
static void scrollrt_draw_lower(int x, int y, int sx, int sy, int chunks, int eflag)
{
int i, j;
BYTE *dst;
MICROS *pMap;
/// ASSERT: assert(gpBuffer);
pMap = &dpiece_defs_map_1[IsometricCoord(x, y)];
if (eflag) {
if ((DWORD)y < MAXDUNY && (DWORD)x < MAXDUNX) {
level_piece_id = dPiece[x][y];
light_table_index = dLight[x][y];
if (level_piece_id != 0) {
dst = &gpBuffer[sx + 32 + PitchTbl[sy]];
cel_transparency_active = (BYTE)(nTransTable[level_piece_id] & TransList[dTransVal[x][y]]);
arch_draw_type = 2;
level_cel_block = pMap->mt[1];
if (level_cel_block != 0) {
drawLowerScreen(dst);
}
arch_draw_type = 0;
dst -= BUFFER_WIDTH * 32;
level_cel_block = pMap->mt[3];
if (level_cel_block != 0) {
drawLowerScreen(dst);
}
dst -= BUFFER_WIDTH * 32;
level_cel_block = pMap->mt[5];
if (level_cel_block != 0) {
drawLowerScreen(dst);
}
dst -= BUFFER_WIDTH * 32;
level_cel_block = pMap->mt[7];
if (level_cel_block != 0) {
drawLowerScreen(dst);
}
dst -= BUFFER_WIDTH * 32;
level_cel_block = pMap->mt[9];
if (level_cel_block != 0) {
drawLowerScreen(dst);
}
dst -= BUFFER_WIDTH * 32;
level_cel_block = pMap->mt[11];
if (level_cel_block != 0 && leveltype == DTYPE_HELL) {
drawLowerScreen(dst);
}
scrollrt_draw_clipped_dungeon(&gpBuffer[sx + PitchTbl[sy]], x, y, sx, sy, 0);
} else {
world_draw_black_tile(&gpBuffer[sx + PitchTbl[sy]]);
}
}
x++;
y--;
sx += 64;
pMap++;
chunks--;
}
j = chunks;
while (j-- != 0) {
if (y < 0 || x >= MAXDUNX) {
break;
}
if (y < MAXDUNY && x >= 0) {
level_piece_id = dPiece[x][y];
light_table_index = dLight[x][y];
if (level_piece_id == 0) {
world_draw_black_tile(&gpBuffer[sx + PitchTbl[sy]]);
} else {
dst = &gpBuffer[sx + PitchTbl[sy]];
cel_transparency_active = (BYTE)(nTransTable[level_piece_id] & TransList[dTransVal[x][y]]);
arch_draw_type = 1;
level_cel_block = pMap->mt[0];
if (level_cel_block != 0) {
drawLowerScreen(dst);
}
arch_draw_type = 2;
level_cel_block = pMap->mt[1];
if (level_cel_block != 0) {
drawLowerScreen(dst + 32);
}
arch_draw_type = 0;
for (i = 2; i < MicroTileLen; i += 2) {
dst -= BUFFER_WIDTH * 32;
level_cel_block = pMap->mt[i];
if (level_cel_block != 0) {
drawLowerScreen(dst);
}
level_cel_block = pMap->mt[i + 1];
if (level_cel_block != 0) {
drawLowerScreen(dst + 32);
}
}
scrollrt_draw_clipped_dungeon(&gpBuffer[sx + PitchTbl[sy]], x, y, sx, sy, 1);
}
}
x++;
y--;
sx += 64;
pMap++;
}
if (eflag && (DWORD)y < MAXDUNY && (DWORD)x < MAXDUNX) {
level_piece_id = dPiece[x][y];
light_table_index = dLight[x][y];
if (level_piece_id == 0) {
world_draw_black_tile(&gpBuffer[sx + PitchTbl[sy]]);
} else {
dst = &gpBuffer[sx + PitchTbl[sy]];
cel_transparency_active = (BYTE)(nTransTable[level_piece_id] & TransList[dTransVal[x][y]]);
arch_draw_type = 1;
level_cel_block = pMap->mt[0];
if (level_cel_block != 0) {
drawLowerScreen(dst);
}
arch_draw_type = 0;
dst -= BUFFER_WIDTH * 32;
level_cel_block = pMap->mt[2];
if (level_cel_block != 0) {
drawLowerScreen(dst);
}
dst -= BUFFER_WIDTH * 32;
level_cel_block = pMap->mt[4];
if (level_cel_block != 0) {
drawLowerScreen(dst);
}
dst -= BUFFER_WIDTH * 32;
level_cel_block = pMap->mt[6];
if (level_cel_block != 0) {
drawLowerScreen(dst);
}
dst -= BUFFER_WIDTH * 32;
level_cel_block = pMap->mt[8];
if (level_cel_block != 0) {
drawLowerScreen(dst);
}
dst -= BUFFER_WIDTH * 32;
level_cel_block = pMap->mt[10];
if (level_cel_block != 0 && leveltype == DTYPE_HELL) {
drawLowerScreen(dst);
}
scrollrt_draw_clipped_dungeon(&gpBuffer[sx + PitchTbl[sy]], x, y, sx, sy, 0);
}
}
}
static void scrollrt_draw_clipped_dungeon_2(BYTE *pBuff, int sx, int sy, int row, int CelSkip, int dx, int dy, int eflag);
/**
* This variant checks for of screen element on the lower screen
* This function it self causes rendering issues since it will render on top of objects on the other side of walls
* @brief Re render tile to workaround sorting issues with players walking east/west
* @param pBuff Pointer to output buffer at location sx,sy
* @param y dPiece coordinate
* @param x dPiece coordinate
* @param row The current row being rendered
* @param CelSkip chunks of cell to skip
* @param sx Backbuffer coordinate
* @param sy Backbuffer coordinate
*/
static void scrollrt_draw_clipped_e_flag_2(BYTE *pBuff, int x, int y, int row, int CelSkip, int sx, int sy)
{
int lti_old, cta_old, lpi_old;
BYTE *dst;
MICROS *pMap;
lti_old = light_table_index;
cta_old = cel_transparency_active;
lpi_old = level_piece_id;
level_piece_id = dPiece[x][y];
light_table_index = dLight[x][y];
dst = &pBuff[BUFFER_WIDTH * 32 * row];
cel_transparency_active = (BYTE)(nTransTable[level_piece_id] & TransList[dTransVal[x][y]]);
pMap = &dpiece_defs_map_1[IsometricCoord(x, y)];
switch (row) {
case 0:
level_cel_block = pMap->mt[2];
if (level_cel_block != 0) {
drawLowerScreen(dst);
}
level_cel_block = pMap->mt[3];
if (level_cel_block != 0) {
drawLowerScreen(dst + 32);
}
case 1:
dst -= BUFFER_WIDTH * 32;
level_cel_block = pMap->mt[4];
if (level_cel_block != 0) {
drawLowerScreen(dst);
}
level_cel_block = pMap->mt[5];
if (level_cel_block != 0) {
drawLowerScreen(dst + 32);
}
case 2:
dst -= BUFFER_WIDTH * 32;
level_cel_block = pMap->mt[6];
if (level_cel_block != 0) {
drawLowerScreen(dst);
}
level_cel_block = pMap->mt[7];
if (level_cel_block != 0) {
drawLowerScreen(dst + 32);
}
case 3:
dst -= BUFFER_WIDTH * 32;
level_cel_block = pMap->mt[8];
if (level_cel_block != 0) {
drawLowerScreen(dst);
}
level_cel_block = pMap->mt[9];
if (level_cel_block != 0) {
drawLowerScreen(dst + 32);
}
break;
}
if (CelSkip < 8) {
scrollrt_draw_clipped_dungeon_2(pBuff, x, y, row, CelSkip, sx, sy, 0);
}
light_table_index = lti_old;
cel_transparency_active = cta_old;
level_piece_id = lpi_old;
}
/**
* This variant checks for of screen element on the lower screen
* @brief Render object sprites, skip offscreen parts for lower screen
* @param pBuff where to render to with sx,sy already applied
* @param sx dPiece coordinate
* @param sy dPiece coordinate
* @param row The current row being rendered
* @param CelSkip chunks of cell to skip
* @param dx Backbuffer coordinate
* @param dy Backbuffer coordinate
* @param eflag Should the sorting workaround be applied
*/
static void scrollrt_draw_clipped_dungeon_2(BYTE *pBuff, int sx, int sy, int row, int CelSkip, int dx, int dy, int eflag)
{
int px, py, nCel, nMon, negMon, p;
char bFlag, bDead, bObj, bItem, bPlr, bArch, bMap, negPlr, dd;
DeadStruct *pDeadGuy;
ItemStruct *pItem;
PlayerStruct *pPlayer;
MonsterStruct *pMonster;
BYTE *pCelBuff;
DWORD *pFrameTable;
/// ASSERT: assert((DWORD)sx < MAXDUNX);
/// ASSERT: assert((DWORD)sy < MAXDUNY);
bFlag = dFlags[sx][sy];
bDead = dDead[sx][sy];
bObj = dObject[sx][sy];
bItem = dItem[sx][sy];
bPlr = dPlayer[sx][sy];
bArch = dArch[sx][sy];
bMap = dTransVal[sx][sy];
nMon = dMonster[sx][sy];
/// ASSERT: assert((DWORD)(sy-1) < MAXDUNY);
negPlr = dPlayer[sx][sy - 1];
negMon = dMonster[sx][sy - 1];
if (visiondebug && bFlag & BFLAG_LIT) {
CelClippedBlitSafe(pBuff, pSquareCel, 1, 64, CelSkip, 8);
}
if (MissilePreFlag && bFlag & BFLAG_MISSILE) {
DrawClippedMissile(sx, sy, dx, dy, CelSkip, 8, TRUE);
}
if (light_table_index < lightmax) {
if (bDead != 0) {
pDeadGuy = &dead[(bDead & 0x1F) - 1];
dd = (bDead >> 5) & 7;
px = dx - pDeadGuy->_deadWidth2;
pCelBuff = pDeadGuy->_deadData[dd];
/// ASSERT: assert(pDeadGuy->_deadData[dd] != NULL);
if (pCelBuff != NULL) {
pFrameTable = (DWORD *)pDeadGuy->_deadData[dd];
nCel = pDeadGuy->_deadFrame;
if (nCel >= 1 && pFrameTable[0] <= 50 && nCel <= (int)pFrameTable[0]) {
if (pDeadGuy->_deadtrans != 0) {
Cl2DrawLightTblSafe(px, dy, pCelBuff, nCel, pDeadGuy->_deadWidth, CelSkip, 8, pDeadGuy->_deadtrans);
} else {
Cl2DrawLightSafe(px, dy, pCelBuff, pDeadGuy->_deadFrame, pDeadGuy->_deadWidth, CelSkip, 8);
}
} else {
// app_fatal("Clipped dead sub2: frame %d of %d, deadnum==%d", nCel, pFrameTable[0], (bDead & 0x1F) - 1);
}
}
}
if (bObj != 0) {
DrawClippedObject(sx, sy, dx, dy, 1, CelSkip, 8);
}
}
if (bItem != 0) {
pItem = &item[bItem - 1];
if (!pItem->_iPostDraw) {
/// ASSERT: assert((unsigned char)bItem <= MAXITEMS);
if ((BYTE)bItem <= MAXITEMS) {
pCelBuff = pItem->_iAnimData;
if (pCelBuff != NULL) {
pFrameTable = (DWORD *)pCelBuff;
nCel = pItem->_iAnimFrame;
if (nCel >= 1 && pFrameTable[0] <= 50 && nCel <= (int)pFrameTable[0]) {
px = dx - pItem->_iAnimWidth2;
if (bItem - 1 == pcursitem) {
CelBlitOutlineSafe(181, px, dy, pCelBuff, nCel, pItem->_iAnimWidth, CelSkip, 8);
}
CelDrawLightSafe(px, dy, pItem->_iAnimData, pItem->_iAnimFrame, pItem->_iAnimWidth, CelSkip, 8);
} else {
/*
app_fatal(
"Draw Clipped \"%s\" Item 3: frame %d of %d, item type==%d",
pItem->_iIName,
nCel,
pFrameTable[0],
pItem->_itype);
*/
}
} else {
// app_fatal("Draw Item \"%s\" Clipped 3: NULL Cel Buffer", pItem->_iIName);
}
}
}
}
if (bFlag & BFLAG_PLAYERLR) {
p = -(negPlr + 1);
if ((DWORD)p < MAX_PLRS) {
pPlayer = &plr[p];
px = dx + pPlayer->_pxoff - pPlayer->_pAnimWidth2;
py = dy + pPlayer->_pyoff;
DrawClippedPlayer(p, sx, sy - 1, px, py, pPlayer->_pAnimData, pPlayer->_pAnimFrame, pPlayer->_pAnimWidth, CelSkip, 8);
if (eflag && pPlayer->_peflag != 0) {
if (pPlayer->_peflag == 2) {
scrollrt_draw_clipped_e_flag_2(pBuff - (BUFFER_WIDTH * 16 + 96), sx - 2, sy + 1, row, CelSkip, dx - 96, dy - 16);
}
scrollrt_draw_clipped_e_flag_2(pBuff - 64, sx - 1, sy + 1, row, CelSkip, dx - 64, dy);
}
} else {
// app_fatal("draw player clipped: tried to draw illegal player %d", p);
}
}
if (bFlag & BFLAG_MONSTLR && (bFlag & BFLAG_LIT || plr[myplr]._pInfraFlag) && negMon < 0) {
draw_monster_num = -(negMon + 1);
if ((DWORD)draw_monster_num < MAXMONSTERS) {
pMonster = &monster[draw_monster_num];
if (!(pMonster->_mFlags & MFLAG_HIDDEN)) {
if (pMonster->MType != NULL) {
px = dx + pMonster->_mxoff - pMonster->MType->width2;
py = dy + pMonster->_myoff;
if (draw_monster_num == pcursmonst) {
Cl2DrawOutlineSafe(233, px, py, pMonster->_mAnimData, pMonster->_mAnimFrame, pMonster->MType->width, CelSkip, 8);
}
DrawClippedMonster(sx, sy, px, py, draw_monster_num, CelSkip, 8);
if (eflag && !pMonster->_meflag) {
scrollrt_draw_clipped_e_flag_2(pBuff - 64, sx - 1, sy + 1, row, CelSkip, dx - 64, dy);
}
} else {
// app_fatal("Draw Monster \"%s\" Clipped: uninitialized monster", pMonster->mName);
}
}
} else {
// app_fatal("Draw Monster Clipped: tried to draw illegal monster %d", draw_monster_num);
}
}
if (bFlag & BFLAG_DEAD_PLAYER) {
DrawDeadPlayer(sx, sy, dx, dy, CelSkip, 8, TRUE);
}
if (bPlr > 0) {
p = bPlr - 1;
if ((DWORD)p < MAX_PLRS) {
pPlayer = &plr[p];
px = dx + pPlayer->_pxoff - pPlayer->_pAnimWidth2;
py = dy + pPlayer->_pyoff;
DrawClippedPlayer(p, sx, sy, px, py, pPlayer->_pAnimData, pPlayer->_pAnimFrame, pPlayer->_pAnimWidth, CelSkip, 8);
if (eflag && pPlayer->_peflag != 0) {
if (pPlayer->_peflag == 2) {
scrollrt_draw_clipped_e_flag_2(pBuff - (BUFFER_WIDTH * 16 + 96), sx - 2, sy + 1, row, CelSkip, dx - 96, dy - 16);
}
scrollrt_draw_clipped_e_flag_2(pBuff - 64, sx - 1, sy + 1, row, CelSkip, dx - 64, dy);
}
} else {
// app_fatal("draw player clipped: tried to draw illegal player %d", p);
}
}
if (nMon > 0 && (bFlag & BFLAG_LIT || plr[myplr]._pInfraFlag)) {
draw_monster_num = nMon - 1;
if ((DWORD)draw_monster_num < MAXMONSTERS) {
pMonster = &monster[draw_monster_num];
if (!(pMonster->_mFlags & MFLAG_HIDDEN)) {
if (pMonster->MType != NULL) {
px = dx + pMonster->_mxoff - pMonster->MType->width2;
py = dy + pMonster->_myoff;
if (draw_monster_num == pcursmonst) {
Cl2DrawOutlineSafe(233, px, py, pMonster->_mAnimData, pMonster->_mAnimFrame, pMonster->MType->width, CelSkip, 8);
}
DrawClippedMonster(sx, sy, px, py, draw_monster_num, CelSkip, 8);
if (eflag && !pMonster->_meflag) {
scrollrt_draw_clipped_e_flag_2(pBuff - 64, sx - 1, sy + 1, row, CelSkip, dx - 64, dy);
}
} else {
// app_fatal("Draw Monster \"%s\" Clipped: uninitialized monster", pMonster->mName);
}
}
} else {
// app_fatal("Draw Monster Clipped: tried to draw illegal monster %d", draw_monster_num);
}
}
if (bFlag & BFLAG_MISSILE) {
DrawClippedMissile(sx, sy, dx, dy, CelSkip, 8, FALSE);
}
if (bObj != 0 && light_table_index < lightmax) {
DrawClippedObject(sx, sy, dx, dy, 0, CelSkip, 8);
}
if (bItem != 0) {
pItem = &item[bItem - 1];
if (pItem->_iPostDraw) {
/// ASSERT: assert((unsigned char)bItem <= MAXITEMS);
if ((BYTE)bItem <= MAXITEMS) {
pCelBuff = pItem->_iAnimData;
if (pCelBuff != NULL) {
pFrameTable = (DWORD *)pCelBuff;
nCel = pItem->_iAnimFrame;
if (nCel >= 1 && pFrameTable[0] <= 50 && nCel <= (int)pFrameTable[0]) {
px = dx - pItem->_iAnimWidth2;
if (bItem - 1 == pcursitem) {
CelBlitOutlineSafe(181, px, dy, pCelBuff, nCel, pItem->_iAnimWidth, CelSkip, 8);
}
CelDrawLightSafe(px, dy, pItem->_iAnimData, pItem->_iAnimFrame, pItem->_iAnimWidth, CelSkip, 8);
} else {
/*
app_fatal(
"Draw Clipped \"%s\" Item 4: frame %d of %d, item type==%d",
pItem->_iIName,
nCel,
pFrameTable[0],
pItem->_itype);
*/
}
} else {
// app_fatal("Draw Item \"%s\" Clipped 4: NULL Cel Buffer", pItem->_iIName);
}
}
}
}
if (bArch != 0) {
cel_transparency_active = TransList[bMap];
CelClippedBlitLightTransSafe(pBuff, pSpecialCels, bArch, 64, CelSkip, 8);
}
}
/**
* @brief Render a row of tile, checking for overdrawing on lower part of screen
* @param x dPiece coordinate
* @param y dPiece coordinate
* @param sx Backbuffer coordinate
* @param sy Backbuffer coordinate
* @param chunks tile width of row
* @param row current row being rendered
* @param eflag is it an even (0) or odd (1) row
*/
static void scrollrt_draw_lower_2(int x, int y, int sx, int sy, int chunks, int row, int eflag)
{
int i, j, CelSkip;
BYTE *dst;
MICROS *pMap;
/// ASSERT: assert(gpBuffer);
pMap = &dpiece_defs_map_1[IsometricCoord(x, y)];
CelSkip = 2 * row + 2;
if (eflag) {
if (y >= 0 && y < MAXDUNY && x >= 0 && x < MAXDUNX) {
level_piece_id = dPiece[x][y];
light_table_index = dLight[x][y];
if (level_piece_id != 0) {
dst = &gpBuffer[sx - (BUFFER_WIDTH * 32 - 32) + PitchTbl[sy]];
cel_transparency_active = (BYTE)(nTransTable[level_piece_id] & TransList[dTransVal[x][y]]);
for (i = 0; i < (MicroTileLen >> 1) - 1; i++) {
if (row <= i) {
level_cel_block = pMap->mt[2 * i + 3];
if (level_cel_block != 0) {
drawLowerScreen(dst);
}
}
dst -= BUFFER_WIDTH * 32;
}
if (CelSkip < 8) {
scrollrt_draw_clipped_dungeon_2(&gpBuffer[sx + PitchTbl[sy] - BUFFER_WIDTH * 16 * CelSkip], x, y, row, CelSkip, sx, sy, 0);
}
}
}
x++;
y--;
sx += 64;
chunks--;
pMap++;
}
j = chunks;
while (j-- != 0) {
if (x >= MAXDUNX || y < 0) {
break;
}
if (y < MAXDUNY && x >= 0) {
level_piece_id = dPiece[x][y];
light_table_index = dLight[x][y];
if (level_piece_id != 0) {
dst = &gpBuffer[sx - BUFFER_WIDTH * 32 + PitchTbl[sy]];
cel_transparency_active = (BYTE)(nTransTable[level_piece_id] & TransList[dTransVal[x][y]]);
i = 0;
while (i < (MicroTileLen >> 1) - 1) {
if (row <= i) {
level_cel_block = pMap->mt[2 * i + 2];
if (level_cel_block != 0) {
drawLowerScreen(dst);
}
level_cel_block = pMap->mt[2 * i + 3];
if (level_cel_block != 0) {
drawLowerScreen(dst + 32);
}
}
i++;
dst -= BUFFER_WIDTH * 32;
}
if (CelSkip < 8) {
scrollrt_draw_clipped_dungeon_2(&gpBuffer[sx + PitchTbl[sy] - BUFFER_WIDTH * 32 * (row + 1)], x, y, row, CelSkip, sx, sy, 1);
}
}
}
x++;
y--;
sx += 64;
pMap++;
}
if (eflag) {
if ((DWORD)y < MAXDUNY && (DWORD)x < MAXDUNX) {
level_piece_id = dPiece[x][y];
light_table_index = dLight[x][y];
if (level_piece_id != 0) {
dst = &gpBuffer[sx - BUFFER_WIDTH * 32 + PitchTbl[sy]];
cel_transparency_active = (BYTE)(nTransTable[level_piece_id] & TransList[dTransVal[x][y]]);
for (i = 0; i < (MicroTileLen >> 1) - 1; i++) {
if (row <= i) {
level_cel_block = pMap->mt[2 * i + 2];
if (level_cel_block != 0) {
drawLowerScreen(dst);
}
}
dst -= BUFFER_WIDTH * 32;
}
if (CelSkip < 8) {
scrollrt_draw_clipped_dungeon_2(&gpBuffer[sx + PitchTbl[sy] - BUFFER_WIDTH * 16 * CelSkip], x, y, row, CelSkip, sx, sy, 0);
}
}
}
}
}
static void scrollrt_draw_dungeon(BYTE *pBuff, int sx, int sy, int row, int CelCap, int dx, int dy, int eflag);
/**
* This variant checks for of screen element on the upper screen
* This function it self causes rendering issues since it will render on top of objects on the other side of walls
* @brief Re render tile to workaround sorting issues with players walking east/west
* @param pBuff Pointer to output buffer at location sx,sy
* @param y dPiece coordinate
* @param x dPiece coordinate
* @param row The current row being rendered
* @param CelCap chunks of cell to skip
* @param sx Backbuffer coordinate
* @param sy Backbuffer coordinate
*/
static void scrollrt_draw_e_flag(BYTE *pBuff, int x, int y, int row, int CelCap, int sx, int sy)
{
int i, lti_old, cta_old, lpi_old;
BYTE *dst;
MICROS *pMap;
lti_old = light_table_index;
cta_old = cel_transparency_active;
lpi_old = level_piece_id;
level_piece_id = dPiece[x][y];
light_table_index = dLight[x][y];
dst = pBuff;
cel_transparency_active = (BYTE)(nTransTable[level_piece_id] & TransList[dTransVal[x][y]]);
pMap = &dpiece_defs_map_1[IsometricCoord(x, y)];
arch_draw_type = 1;
level_cel_block = pMap->mt[0];
if (level_cel_block != 0) {
drawUpperScreen(dst);
}
arch_draw_type = 2;
level_cel_block = pMap->mt[1];
if (level_cel_block != 0) {
drawUpperScreen(dst + 32);
}
arch_draw_type = 0;
for (i = 1; i < (MicroTileLen >> 1) - 1; i++) {
dst -= BUFFER_WIDTH * 32;
if (row >= i) {
level_cel_block = pMap->mt[2 * i];
if (level_cel_block != 0) {
drawUpperScreen(dst);
}
level_cel_block = pMap->mt[2 * i + 1];
if (level_cel_block != 0) {
drawUpperScreen(dst + 32);
}
}
}
scrollrt_draw_dungeon(pBuff, x, y, row, CelCap, sx, sy, 0);
light_table_index = lti_old;
cel_transparency_active = cta_old;
level_piece_id = lpi_old;
}
/**
* @brief Render object sprites, skip offscreen parts for upper screen
* @param pBuff where to render to with sx,sx already applied
* @param sx dPiece coordinate
* @param sy dPiece coordinate
* @param row The current row being rendered
* @param CelCap chunks of cell to skip
* @param dx Backbuffer coordinate
* @param dy Backbuffer coordinate
* @param eflag Should the sorting workaround be applied
*/
static void scrollrt_draw_dungeon(BYTE *pBuff, int sx, int sy, int row, int CelCap, int dx, int dy, int eflag)
{
int px, py, nCel, nMon, negMon, p, tx, ty;
char bFlag, bDead, bObj, bItem, bPlr, bArch, bMap, negPlr, dd;
DeadStruct *pDeadGuy;
ItemStruct *pItem;
PlayerStruct *pPlayer;
MonsterStruct *pMonster;
BYTE *pCelBuff;
DWORD *pFrameTable;
/// ASSERT: assert((DWORD)sx < MAXDUNX);
/// ASSERT: assert((DWORD)sy < MAXDUNY);
bFlag = dFlags[sx][sy];
bDead = dDead[sx][sy];
bObj = dObject[sx][sy];
bItem = dItem[sx][sy];
bPlr = dPlayer[sx][sy];
bArch = dArch[sx][sy];
bMap = dTransVal[sx][sy];
nMon = dMonster[sx][sy];
/// ASSERT: assert((DWORD)(sy-1) < MAXDUNY);
negPlr = dPlayer[sx][sy - 1];
negMon = dMonster[sx][sy - 1];
if (visiondebug && bFlag & BFLAG_LIT) {
CelClippedBlit(pBuff, pSquareCel, 1, 64, 0, CelCap);
}
tx = dx - 96;
ty = dy - 16;
if (MissilePreFlag && bFlag & BFLAG_MISSILE) {
DrawMissile(sx, sy, dx, dy, 0, CelCap, TRUE);
}
if (light_table_index < lightmax) {
if (bDead != 0) {
pDeadGuy = &dead[(bDead & 0x1F) - 1];
dd = (bDead >> 5) & 7;
px = dx - pDeadGuy->_deadWidth2;
pCelBuff = pDeadGuy->_deadData[dd];
/// ASSERT: assert(pDeadGuy->_deadData[dd] != NULL);
if (pCelBuff != NULL) {
pFrameTable = (DWORD *)pDeadGuy->_deadData[dd];
nCel = pDeadGuy->_deadFrame;
if (nCel >= 1 && pFrameTable[0] <= 50 && nCel <= (int)pFrameTable[0]) {
if (pDeadGuy->_deadtrans != 0) {
Cl2DrawLightTbl(px, dy, pCelBuff, nCel, pDeadGuy->_deadWidth, 0, CelCap, pDeadGuy->_deadtrans);
} else {
Cl2DrawLight(px, dy, pCelBuff, pDeadGuy->_deadFrame, pDeadGuy->_deadWidth, 0, CelCap);
}
} else {
// app_fatal("Unclipped dead: frame %d of %d, deadnum==%d", nCel, pFrameTable[0], (bDead & 0x1F) - 1);
}
}
}
if (bObj != 0) {
DrawObject(sx, sy, dx, dy, 1, 0, CelCap);
}
}
if (bItem != 0) {
pItem = &item[bItem - 1];
if (!pItem->_iPostDraw) {
/// ASSERT: assert((unsigned char)bItem <= MAXITEMS);
if ((BYTE)bItem <= MAXITEMS) {
pCelBuff = pItem->_iAnimData;
if (pCelBuff != NULL) {
pFrameTable = (DWORD *)pCelBuff;
nCel = pItem->_iAnimFrame;
if (nCel >= 1 && pFrameTable[0] <= 50 && nCel <= (int)pFrameTable[0]) {
px = dx - pItem->_iAnimWidth2;
if (bItem - 1 == pcursitem) {
CelBlitOutline(181, px, dy, pCelBuff, nCel, pItem->_iAnimWidth, 0, CelCap);
}
CelClippedDrawLight(px, dy, pItem->_iAnimData, pItem->_iAnimFrame, pItem->_iAnimWidth, 0, CelCap);
} else {
// app_fatal("Draw \"%s\" Item 1: frame %d of %d, item type==%d", pItem->_iIName, nCel, pFrameTable[0], pItem->_itype);
}
} else {
// app_fatal("Draw Item \"%s\" 1: NULL Cel Buffer", pItem->_iIName);
}
}
}
}
if (bFlag & BFLAG_PLAYERLR) {
p = -(negPlr + 1);
if ((DWORD)p < MAX_PLRS) {
pPlayer = &plr[p];
px = dx + pPlayer->_pxoff - pPlayer->_pAnimWidth2;
py = dy + pPlayer->_pyoff;
DrawPlayer(p, sx, sy - 1, px, py, pPlayer->_pAnimData, pPlayer->_pAnimFrame, pPlayer->_pAnimWidth, 0, CelCap);
if (eflag && pPlayer->_peflag != 0) {
if (pPlayer->_peflag == 2) {
scrollrt_draw_e_flag(pBuff - (BUFFER_WIDTH * 16 + 96), sx - 2, sy + 1, row, CelCap, tx, ty);
}
scrollrt_draw_e_flag(pBuff - 64, sx - 1, sy + 1, row, CelCap, dx - 64, dy);
}
} else {
// app_fatal("draw player: tried to draw illegal player %d", p);
}
}
if (bFlag & BFLAG_MONSTLR && (bFlag & BFLAG_LIT || plr[myplr]._pInfraFlag) && negMon < 0) {
draw_monster_num = -(negMon + 1);
if ((DWORD)draw_monster_num < MAXMONSTERS) {
pMonster = &monster[draw_monster_num];
if (!(pMonster->_mFlags & MFLAG_HIDDEN)) {
if (pMonster->MType != NULL) {
px = dx + pMonster->_mxoff - pMonster->MType->width2;
py = dy + pMonster->_myoff;
if (draw_monster_num == pcursmonst) {
Cl2DrawOutline(233, px, py, pMonster->_mAnimData, pMonster->_mAnimFrame, pMonster->MType->width, 0, CelCap);
}
DrawMonster(sx, sy, px, py, draw_monster_num, 0, CelCap);
if (eflag && !pMonster->_meflag) {
scrollrt_draw_e_flag(pBuff - 64, sx - 1, sy + 1, row, CelCap, dx - 64, dy);
}
} else {
// app_fatal("Draw Monster \"%s\": uninitialized monster", pMonster->mName);
}
}
} else {
// app_fatal("Draw Monster: tried to draw illegal monster %d", draw_monster_num);
}
}
if (bFlag & BFLAG_DEAD_PLAYER) {
DrawDeadPlayer(sx, sy, dx, dy, 0, CelCap, FALSE);
}
if (bPlr > 0) {
p = bPlr - 1;
if ((DWORD)p < MAX_PLRS) {
pPlayer = &plr[p];
px = dx + pPlayer->_pxoff - pPlayer->_pAnimWidth2;
py = dy + pPlayer->_pyoff;
DrawPlayer(p, sx, sy, px, py, pPlayer->_pAnimData, pPlayer->_pAnimFrame, pPlayer->_pAnimWidth, 0, CelCap);
if (eflag && pPlayer->_peflag != 0) {
if (pPlayer->_peflag == 2) {
scrollrt_draw_e_flag(pBuff - (BUFFER_WIDTH * 16 + 96), sx - 2, sy + 1, row, CelCap, dx - 96, dy - 16);
}
scrollrt_draw_e_flag(pBuff - 64, sx - 1, sy + 1, row, CelCap, dx - 64, dy);
}
} else {
// app_fatal("draw player: tried to draw illegal player %d", p);
}
}
if (nMon > 0 && (bFlag & BFLAG_LIT || plr[myplr]._pInfraFlag)) {
draw_monster_num = nMon - 1;
if ((DWORD)draw_monster_num < MAXMONSTERS) {
pMonster = &monster[draw_monster_num];
if (!(pMonster->_mFlags & MFLAG_HIDDEN)) {
if (pMonster->MType != NULL) {
px = dx + pMonster->_mxoff - pMonster->MType->width2;
py = dy + pMonster->_myoff;
if (draw_monster_num == pcursmonst) {
Cl2DrawOutline(233, px, py, pMonster->_mAnimData, pMonster->_mAnimFrame, pMonster->MType->width, 0, CelCap);
}
DrawMonster(sx, sy, px, py, draw_monster_num, 0, CelCap);
if (eflag && !pMonster->_meflag) {
scrollrt_draw_e_flag(pBuff - 64, sx - 1, sy + 1, row, CelCap, dx - 64, dy);
}
} else {
// app_fatal("Draw Monster \"%s\": uninitialized monster", pMonster->mName);
}
}
} else {
// app_fatal("Draw Monster: tried to draw illegal monster %d", draw_monster_num);
}
}
if (bFlag & BFLAG_MISSILE) {
DrawMissile(sx, sy, dx, dy, 0, CelCap, FALSE);
}
if (bObj != 0 && light_table_index < lightmax) {
DrawObject(sx, sy, dx, dy, 0, 0, CelCap);
}
if (bItem != 0) {
pItem = &item[bItem - 1];
if (pItem->_iPostDraw) {
/// ASSERT: assert((unsigned char)bItem <= MAXITEMS);
if ((BYTE)bItem <= MAXITEMS) {
pCelBuff = pItem->_iAnimData;
if (pCelBuff != NULL) {
pFrameTable = (DWORD *)pCelBuff;
nCel = pItem->_iAnimFrame;
if (nCel >= 1 && pFrameTable[0] <= 50 && nCel <= (int)pFrameTable[0]) {
px = dx - pItem->_iAnimWidth2;
if (bItem - 1 == pcursitem) {
CelBlitOutline(181, px, dy, pCelBuff, nCel, pItem->_iAnimWidth, 0, CelCap);
}
CelClippedDrawLight(px, dy, pItem->_iAnimData, pItem->_iAnimFrame, pItem->_iAnimWidth, 0, CelCap);
} else {
// app_fatal("Draw \"%s\" Item 2: frame %d of %d, item type==%d", pItem->_iIName, nCel, pFrameTable[0], pItem->_itype);
}
} else {
// app_fatal("Draw Item \"%s\" 2: NULL Cel Buffer", pItem->_iIName);
}
}
}
}
if (bArch != 0) {
cel_transparency_active = TransList[bMap];
CelClippedBlitLightTrans(pBuff, pSpecialCels, bArch, 64, 0, CelCap);
}
}
/**
* @brief Render a row of tile, checking for overdrawing on upper part of screen
* @param x dPiece coordinate
* @param y dPiece coordinate
* @param sx Backbuffer coordinate
* @param sy Backbuffer coordinate
* @param chunks tile width of row
* @param row current row being rendered
* @param eflag is it an even (0) or odd (1) row
*/
static void scrollrt_draw_upper(int x, int y, int sx, int sy, int chunks, int row, int eflag)
{
int i, j, CelCap;
BYTE *dst;
MICROS *pMap;
/// ASSERT: assert(gpBuffer);
pMap = &dpiece_defs_map_1[IsometricCoord(x, y)];
CelCap = 2 * row + 2;
if (CelCap > 8) {
CelCap = 8;
}
if (eflag) {
if (y >= 0 && y < MAXDUNY && x >= 0 && x < MAXDUNX) {
level_piece_id = dPiece[x][y];
light_table_index = dLight[x][y];
if (level_piece_id != 0) {
dst = &gpBuffer[sx + 32 + PitchTbl[sy]];
cel_transparency_active = (BYTE)(nTransTable[level_piece_id] & TransList[dTransVal[x][y]]);
if (row >= 0) {
level_cel_block = pMap->mt[1];
if (level_cel_block != 0) {
arch_draw_type = 2;
drawUpperScreen(dst);
arch_draw_type = 0;
}
}
dst -= BUFFER_WIDTH * 32;
if (row >= 1) {
level_cel_block = pMap->mt[3];
if (level_cel_block != 0) {
drawUpperScreen(dst);
}
}
dst -= BUFFER_WIDTH * 32;
if (row >= 2) {
level_cel_block = pMap->mt[5];
if (level_cel_block != 0) {
drawUpperScreen(dst);
}
}
dst -= BUFFER_WIDTH * 32;
if (row >= 3) {
level_cel_block = pMap->mt[7];
if (level_cel_block != 0) {
drawUpperScreen(dst);
}
}
scrollrt_draw_dungeon(&gpBuffer[sx + PitchTbl[sy]], x, y, row, CelCap, sx, sy, 0);
} else {
world_draw_black_tile(&gpBuffer[sx + PitchTbl[sy]]);
}
}
x++;
y--;
sx += 64;
chunks--;
pMap++;
}
for (j = 0; j < chunks; j++) {
if (y >= 0 && y < MAXDUNY && x >= 0 && x < MAXDUNX) {
level_piece_id = dPiece[x][y];
light_table_index = dLight[x][y];
if (level_piece_id != 0) {
dst = &gpBuffer[sx + PitchTbl[sy]];
cel_transparency_active = (BYTE)(nTransTable[level_piece_id] & TransList[dTransVal[x][y]]);
arch_draw_type = 1;
level_cel_block = pMap->mt[0];
if (level_cel_block != 0) {
drawUpperScreen(dst);
}
arch_draw_type = 2;
level_cel_block = pMap->mt[1];
if (level_cel_block != 0) {
drawUpperScreen(dst + 32);
}
arch_draw_type = 0;
for (i = 1; i < (MicroTileLen >> 1) - 1; i++) {
dst -= BUFFER_WIDTH * 32;
if (row >= i) {
level_cel_block = pMap->mt[2 * i];
if (level_cel_block != 0) {
drawUpperScreen(dst);
}
level_cel_block = pMap->mt[2 * i + 1];
if (level_cel_block != 0) {
drawUpperScreen(dst + 32);
}
}
}
scrollrt_draw_dungeon(&gpBuffer[sx + PitchTbl[sy]], x, y, row, CelCap, sx, sy, 1);
} else {
world_draw_black_tile(&gpBuffer[sx + PitchTbl[sy]]);
}
}
x++;
y--;
sx += 64;
pMap++;
}
if (eflag) {
if (y >= 0 && y < MAXDUNY && x >= 0 && x < MAXDUNX) {
level_piece_id = dPiece[x][y];
light_table_index = dLight[x][y];
if (level_piece_id != 0) {
dst = &gpBuffer[sx + PitchTbl[sy]];
cel_transparency_active = (BYTE)(nTransTable[level_piece_id] & TransList[dTransVal[x][y]]);
arch_draw_type = 1;
if (row >= 0) {
level_cel_block = pMap->mt[0];
if (level_cel_block != 0) {
drawUpperScreen(dst);
}
}
arch_draw_type = 0;
dst -= BUFFER_WIDTH * 32;
if (row >= 1) {
level_cel_block = pMap->mt[2];
if (level_cel_block != 0) {
drawUpperScreen(dst);
}
}
dst -= BUFFER_WIDTH * 32;
if (row >= 2) {
level_cel_block = pMap->mt[4];
if (level_cel_block != 0) {
drawUpperScreen(dst);
}
}
dst -= BUFFER_WIDTH * 32;
if (row >= 3) {
level_cel_block = pMap->mt[6];
if (level_cel_block != 0) {
drawUpperScreen(dst);
}
}
scrollrt_draw_dungeon(&gpBuffer[sx + PitchTbl[sy]], x, y, row, CelCap, sx, sy, 0);
} else {
world_draw_black_tile(&gpBuffer[sx + PitchTbl[sy]]);
}
}
}
}
/**
* @brief Configure render and process screen rows
* @param x Center of view in dPiece coordinate
* @param y Center of view in dPiece coordinate
*/
static void DrawGame(int x, int y)
{
int i, sx, sy, chunks, blocks;
scr_pix_width = SCREEN_WIDTH;
scr_pix_height = VIEWPORT_HEIGHT;
dword_5C2FF8 = SCREEN_WIDTH / 64;
dword_5C2FFC = VIEWPORT_HEIGHT / 32;
sx = ScrollInfo._sxoff + SCREEN_X;
sy = ScrollInfo._syoff + SCREEN_Y + 15;
x -= SCREEN_WIDTH / 64;
y--;
chunks = SCREEN_WIDTH / 64;
blocks = 8;
if (chrflag || questlog) {
x += 2;
y -= 2;
sx += (SCREEN_WIDTH / 2) - 32;
chunks = (SCREEN_WIDTH / 64) - 4;
}
if (invflag || sbookflag) {
x += 2;
y -= 2;
sx -= 32;
chunks = (SCREEN_WIDTH / 64) - 4;
}
switch (ScrollInfo._sdir) {
case SDIR_NONE:
break;
case SDIR_NE:
chunks++;
case SDIR_N:
sy -= 32;
x--;
y--;
blocks++;
break;
case SDIR_SE:
blocks++;
case SDIR_E:
chunks++;
break;
case SDIR_S:
blocks++;
break;
case SDIR_SW:
blocks++;
case SDIR_W:
sx -= 64;
x--;
y++;
chunks++;
break;
case SDIR_NW:
sx -= 64;
sy -= 32;
x -= 2;
chunks++;
blocks++;
break;
}
/// ASSERT: assert(gpBuffer);
gpBufEnd = &gpBuffer[PitchTbl[0 + SCREEN_Y]];
for (i = 0; i < 4; i++) {
scrollrt_draw_upper(x, y, sx, sy, chunks, i, 0);
y++;
sx -= 32;
sy += 16;
scrollrt_draw_upper(x, y, sx, sy, chunks, i, 1);
x++;
sx += 32;
sy += 16;
}
/// ASSERT: assert(gpBuffer);
gpBufEnd = &gpBuffer[PitchTbl[VIEWPORT_HEIGHT + SCREEN_Y]];
for (i = 0; i < blocks; i++) {
scrollrt_draw_lower(x, y, sx, sy, chunks, 0);
y++;
sx -= 32;
sy += 16;
scrollrt_draw_lower(x, y, sx, sy, chunks, 1);
x++;
sx += 32;
sy += 16;
}
arch_draw_type = 0;
for (i = 0; i < 4; i++) {
scrollrt_draw_lower_2(x, y, sx, sy, chunks, i, 0);
y++;
sx -= 32;
sy += 16;
scrollrt_draw_lower_2(x, y, sx, sy, chunks, i, 1);
x++;
sx += 32;
sy += 16;
}
}
/**
* @brief Configure render for zoomed view and process screen rows
* @param x Center of view in dPiece coordinate
* @param y Center of view in dPiece coordinate
*/
static void DrawZoom(int x, int y)
{
int i, sx, sy, chunks, blocks;
int wdt, nSrcOff, nDstOff;
scr_pix_width = ZOOM_WIDTH;
scr_pix_height = ZOOM_HEIGHT - 32;
dword_5C2FF8 = ZOOM_WIDTH / 64;
dword_5C2FFC = (ZOOM_HEIGHT - 32) / 32;
sx = ScrollInfo._sxoff + SCREEN_X;
sy = ScrollInfo._syoff + SCREEN_Y - 17;
x -= ZOOM_WIDTH / 64;
y--;
chunks = ZOOM_WIDTH / 64;
blocks = 3;
switch (ScrollInfo._sdir) {
case SDIR_NE:
chunks++;
case SDIR_N:
sy -= 32;
x--;
y--;
blocks++;
break;
case SDIR_SE:
blocks++;
case SDIR_E:
chunks++;
break;
case SDIR_S:
blocks++;
break;
case SDIR_SW:
blocks++;
case SDIR_W:
sx -= 64;
x--;
y++;
chunks++;
break;
case SDIR_NW:
sx -= 64;
sy -= 32;
x -= 2;
chunks++;
blocks++;
break;
}
/// ASSERT: assert(gpBuffer);
gpBufEnd = &gpBuffer[PitchTbl[-17 + SCREEN_Y]];
for (i = 0; i < 4; i++) {
scrollrt_draw_upper(x, y, sx, sy, chunks, i, 0);
y++;
sx -= 32;
sy += 16;
scrollrt_draw_upper(x, y, sx, sy, chunks, i, 1);
x++;
sx += 32;
sy += 16;
}
/// ASSERT: assert(gpBuffer);
gpBufEnd = &gpBuffer[PitchTbl[160 + SCREEN_Y]];
for (i = 0; i < blocks; i++) {
scrollrt_draw_lower(x, y, sx, sy, chunks, 0);
y++;
sx -= 32;
sy += 16;
scrollrt_draw_lower(x, y, sx, sy, chunks, 1);
x++;
sx += 32;
sy += 16;
}
arch_draw_type = 0;
for (i = 0; i < 4; i++) {
scrollrt_draw_lower_2(x, y, sx, sy, chunks, i, 0);
y++;
sx -= 32;
sy += 16;
scrollrt_draw_lower_2(x, y, sx, sy, chunks, i, 1);
x++;
sx += 32;
sy += 16;
}
if (chrflag || questlog) {
nSrcOff = SCREENXY(112, VIEWPORT_HEIGHT / 2 - 17);
nDstOff = SCREENXY(320, VIEWPORT_HEIGHT - 2);
wdt = (SCREEN_WIDTH - 320) / 2;
} else if (invflag || sbookflag) {
nSrcOff = SCREENXY(112, VIEWPORT_HEIGHT / 2 - 17);
nDstOff = SCREENXY(0, VIEWPORT_HEIGHT - 2);
wdt = (SCREEN_WIDTH - 320) / 2;
} else {
nSrcOff = SCREENXY(32, VIEWPORT_HEIGHT / 2 - 17);
nDstOff = SCREENXY(0, VIEWPORT_HEIGHT - 2);
wdt = SCREEN_WIDTH / 2;
}
/// ASSERT: assert(gpBuffer);
#ifdef USE_ASM
__asm {
mov esi, gpBuffer
mov edx, nDstOff
mov edi, esi
mov ecx, nSrcOff
add edi, edx
add esi, ecx
mov ebx, edi
add ebx, BUFFER_WIDTH
mov edx, (VIEWPORT_HEIGHT / 2)
label1:
mov ecx, wdt
label2:
mov al, [esi]
inc esi
mov ah, al
mov [edi], ax
mov [ebx], ax
add edi, 2
add ebx, 2
dec ecx
jnz label2
mov eax, BUFFER_WIDTH
add eax, wdt
sub esi, eax
add eax, eax
sub ebx, eax
sub edi, eax
dec edx
jnz label1
}
#else
int hgt;
BYTE *src, *dst1, *dst2;
src = &gpBuffer[nSrcOff];
dst1 = &gpBuffer[nDstOff];
dst2 = &gpBuffer[nDstOff + BUFFER_WIDTH];
for (hgt = VIEWPORT_HEIGHT / 2; hgt != 0; hgt--, src -= BUFFER_WIDTH + wdt, dst1 -= 2 * (BUFFER_WIDTH + wdt), dst2 -= 2 * (BUFFER_WIDTH + wdt)) {
for (i = wdt; i != 0; i--) {
*dst1++ = *src;
*dst1++ = *src;
*dst2++ = *src;
*dst2++ = *src;
src++;
}
}
#endif
}
/**
* @brief Start rendering of screen, town variation
* @param StartX Center of view in dPiece coordinate
* @param StartY Center of view in dPiece coordinate
*/
void DrawView(int StartX, int StartY)
{
if (zoomflag) {
DrawGame(StartX, StartY);
} else {
DrawZoom(StartX, StartY);
}
if (automapflag) {
DrawAutomap();
}
if (invflag) {
DrawInv();
} else if (sbookflag) {
DrawSpellBook();
}
DrawDurIcon();
if (chrflag) {
DrawChr();
} else if (questlog) {
DrawQuestLog();
} else if (plr[myplr]._pStatPts != 0 && !spselflag) {
DrawLevelUpIcon();
}
if (uitemflag) {
DrawUniqueInfo();
}
if (qtextflag) {
DrawQText();
}
if (spselflag) {
DrawSpellList();
}
if (dropGoldFlag) {
DrawGoldSplit(dropGoldValue);
}
if (helpflag) {
DrawHelp();
}
if (msgflag) {
DrawDiabloMsg();
}
if (deathflag) {
RedBack();
} else if (PauseMode != 0) {
gmenu_draw_pause();
}
DrawPlrMsg();
gmenu_draw();
doom_draw();
DrawInfoBox();
DrawLifeFlask();
DrawManaFlask();
}
/**
* @brief Render the whole screen black
*/
void ClearScreenBuffer()
{
lock_buf(3);
/// ASSERT: assert(gpBuffer);
#ifdef USE_ASM
__asm {
mov edi, gpBuffer
add edi, SCREENXY(0, 0)
mov edx, SCREEN_HEIGHT
xor eax, eax
zeroline:
mov ecx, SCREEN_WIDTH / 4
rep stosd
add edi, BUFFER_WIDTH - SCREEN_WIDTH
dec edx
jnz zeroline
}
#else
int i;
BYTE *dst;
dst = &gpBuffer[SCREENXY(0, 0)];
for (i = 0; i < SCREEN_HEIGHT; i++, dst += BUFFER_WIDTH) {
memset(dst, 0, SCREEN_WIDTH);
}
#endif
unlock_buf(3);
}
#ifdef _DEBUG
/**
* @brief Scroll the screen when mouse is close to the edge
*/
void ScrollView()
{
BOOL scroll;
if (pcurs >= CURSOR_FIRSTITEM)
return;
scroll = FALSE;
if (MouseX < 20) {
if (dmaxy - 1 <= ViewY || dminx >= ViewX) {
if (dmaxy - 1 > ViewY) {
ViewY++;
scroll = TRUE;
}
if (dminx < ViewX) {
ViewX--;
scroll = TRUE;
}
} else {
ViewY++;
ViewX--;
scroll = TRUE;
}
}
if (MouseX > SCREEN_WIDTH - 20) {
if (dmaxx - 1 <= ViewX || dminy >= ViewY) {
if (dmaxx - 1 > ViewX) {
ViewX++;
scroll = TRUE;
}
if (dminy < ViewY) {
ViewY--;
scroll = TRUE;
}
} else {
ViewY--;
ViewX++;
scroll = TRUE;
}
}
if (MouseY < 20) {
if (dminy >= ViewY || dminx >= ViewX) {
if (dminy < ViewY) {
ViewY--;
scroll = TRUE;
}
if (dminx < ViewX) {
ViewX--;
scroll = TRUE;
}
} else {
ViewX--;
ViewY--;
scroll = TRUE;
}
}
if (MouseY > SCREEN_HEIGHT - 20) {
if (dmaxy - 1 <= ViewY || dmaxx - 1 <= ViewX) {
if (dmaxy - 1 > ViewY) {
ViewY++;
scroll = TRUE;
}
if (dmaxx - 1 > ViewX) {
ViewX++;
scroll = TRUE;
}
} else {
ViewX++;
ViewY++;
scroll = TRUE;
}
}
if (scroll)
ScrollInfo._sdir = SDIR_NONE;
}
/**
* @brief Initialize the FPS meter
*/
void EnableFrameCount()
{
frameflag = frameflag == 0;
framestart = GetTickCount();
}
/**
* @brief Display the current average FPS over 1 sec
*/
static void DrawFPS()
{
DWORD tc, frames;
char String[12];
HDC hdc;
if (frameflag && gbActive) {
frameend++;
tc = GetTickCount();
frames = tc - framestart;
if (tc - framestart >= 1000) {
framestart = tc;
framerate = 1000 * frameend / frames;
frameend = 0;
}
if (framerate > 99)
framerate = 99;
wsprintf(String, "%2d", framerate);
#ifdef __cplusplus
if (!lpDDSPrimary->GetDC(&hdc)) {
TextOut(hdc, 0, 400, String, strlen(String));
lpDDSPrimary->ReleaseDC(hdc);
}
#else
if (!lpDDSPrimary->lpVtbl->GetDC(lpDDSPrimary, &hdc)) {
TextOut(hdc, 0, 400, String, strlen(String));
lpDDSPrimary->lpVtbl->ReleaseDC(lpDDSPrimary, hdc);
}
#endif
}
}
#endif
/**
* @brief Update part of the screen from the backbuffer
* @param dwX Backbuffer coordinate
* @param dwY Backbuffer coordinate
* @param dwWdt Backbuffer coordinate
* @param dwHgt Backbuffer coordinate
*/
static void DoBlitScreen(DWORD dwX, DWORD dwY, DWORD dwWdt, DWORD dwHgt)
{
int nSrcOff, nDstOff, nSrcWdt, nDstWdt;
DWORD dwTicks;
HRESULT hDDVal;
RECT SrcRect;
/// ASSERT: assert(! (dwX & 3));
/// ASSERT: assert(! (dwWdt & 3));
if (lpDDSBackBuf != NULL) {
SrcRect.left = dwX + SCREEN_X;
SrcRect.top = dwY + SCREEN_Y;
SrcRect.right = SrcRect.left + dwWdt - 1;
SrcRect.bottom = SrcRect.top + dwHgt - 1;
/// ASSERT: assert(! gpBuffer);
dwTicks = GetTickCount();
while (1) {
#ifdef __cplusplus
hDDVal = lpDDSPrimary->BltFast(dwX, dwY, lpDDSBackBuf, &SrcRect, DDBLTFAST_WAIT);
#else
hDDVal = lpDDSPrimary->lpVtbl->BltFast(lpDDSPrimary, dwX, dwY, lpDDSBackBuf, &SrcRect, DDBLTFAST_WAIT);
#endif
if (hDDVal == DD_OK) {
break;
}
if (dwTicks - GetTickCount() > 5000) {
break;
}
Sleep(1);
if (hDDVal == DDERR_SURFACELOST) {
return;
}
if (hDDVal != DDERR_WASSTILLDRAWING && hDDVal != DDERR_SURFACEBUSY) {
break;
}
}
if (hDDVal != DDERR_SURFACELOST
&& hDDVal != DDERR_WASSTILLDRAWING
&& hDDVal != DDERR_SURFACEBUSY
&& hDDVal != DD_OK) {
DDErrMsg(hDDVal, 3596, "C:\\Src\\Diablo\\Source\\SCROLLRT.CPP");
}
} else {
nSrcOff = SCREENXY(dwX, dwY);
nDstOff = dwX * (SCREEN_BPP / 8) + dwY * DDS_desc.lPitch;
nSrcWdt = BUFFER_WIDTH - dwWdt;
nDstWdt = DDS_desc.lPitch - dwWdt * (SCREEN_BPP / 8);
dwWdt >>= 2;
lock_buf(6);
/// ASSERT: assert(gpBuffer);
#if defined(USE_ASM) && !defined(RGBMODE)
__asm {
mov esi, gpBuffer
mov edi, DDS_desc.lpSurface
add esi, nSrcOff
add edi, nDstOff
mov eax, nSrcWdt
mov ebx, nDstWdt
mov edx, dwHgt
blitline:
mov ecx, dwWdt
rep movsd
add esi, eax
add edi, ebx
dec edx
jnz blitline
}
#else
int wdt, hgt;
BYTE *src, *dst;
src = &gpBuffer[nSrcOff];
dst = (BYTE *)DDS_desc.lpSurface + nDstOff;
for (hgt = 0; hgt < dwHgt; hgt++, src += nSrcWdt, dst += nDstWdt) {
for (wdt = 0; wdt < 4 * dwWdt; wdt++) {
#ifndef RGBMODE
*dst++ = *src++;
#else
PALETTEENTRY pal = system_palette[*src++];
dst[0] = pal.peBlue;
dst[1] = pal.peGreen;
dst[2] = pal.peRed;
dst += 4;
#endif
}
}
#endif
unlock_buf(6);
}
}
/**
* @brief Check render pipline and blit indivudal screen parts
* @param dwHgt Section of screen to update from top to bottom
* @param draw_desc Render info box
* @param draw_hp Render halth bar
* @param draw_mana Render mana bar
* @param draw_sbar Render belt
* @param draw_btn Render panel buttons
*/
static void DrawMain(int dwHgt, BOOL draw_desc, BOOL draw_hp, BOOL draw_mana, BOOL draw_sbar, BOOL draw_btn)
{
int ysize;
DWORD dwTicks;
BOOL retry;
HRESULT hDDVal;
ysize = dwHgt;
if (!gbActive || lpDDSPrimary == NULL) {
return;
}
#ifdef __cplusplus
if (lpDDSPrimary->IsLost() == DDERR_SURFACELOST) {
if (lpDDSPrimary->Restore() != DD_OK) {
return;
}
#else
if (lpDDSPrimary->lpVtbl->IsLost(lpDDSPrimary) == DDERR_SURFACELOST) {
if (lpDDSPrimary->lpVtbl->Restore(lpDDSPrimary) != DD_OK) {
return;
}
#endif
ResetPal();
ysize = SCREEN_HEIGHT;
}
if (lpDDSBackBuf == NULL) {
retry = TRUE;
dwTicks = GetTickCount();
while (1) {
DDS_desc.dwSize = sizeof(DDS_desc);
#ifdef __cplusplus
hDDVal = lpDDSPrimary->Lock(NULL, &DDS_desc, DDLOCK_WRITEONLY | DDLOCK_WAIT, NULL);
#else
hDDVal = lpDDSPrimary->lpVtbl->Lock(lpDDSPrimary, NULL, &DDS_desc, DDLOCK_WRITEONLY | DDLOCK_WAIT, NULL);
#endif
if (hDDVal == DD_OK) {
break;
}
if (dwTicks - GetTickCount() > 5000) {
break;
}
Sleep(1);
if (hDDVal == DDERR_SURFACELOST) {
return;
}
if (hDDVal != DDERR_WASSTILLDRAWING && hDDVal != DDERR_SURFACEBUSY) {
if (!retry || hDDVal != DDERR_GENERIC) {
break;
}
retry = FALSE;
j_dx_reinit();
ysize = SCREEN_HEIGHT;
dwTicks = GetTickCount();
}
}
if (hDDVal == DDERR_SURFACELOST
|| hDDVal == DDERR_WASSTILLDRAWING
|| hDDVal == DDERR_SURFACEBUSY) {
return;
}
if (hDDVal != DD_OK) {
DDErrMsg(hDDVal, 3707, "C:\\Src\\Diablo\\Source\\SCROLLRT.CPP");
}
}
/// ASSERT: assert(ysize >= 0 && ysize <= 480); // SCREEN_HEIGHT
if (ysize > 0) {
DoBlitScreen(0, 0, SCREEN_WIDTH, ysize);
}
if (ysize < SCREEN_HEIGHT) {
if (draw_sbar) {
DoBlitScreen(PANEL_LEFT + 204, PANEL_TOP + 5, 232, 28);
}
if (draw_desc) {
DoBlitScreen(PANEL_LEFT + 176, PANEL_TOP + 46, 288, 60);
}
if (draw_mana) {
DoBlitScreen(PANEL_LEFT + 460, PANEL_TOP, 88, 72);
DoBlitScreen(PANEL_LEFT + 564, PANEL_TOP + 64, 56, 56);
}
if (draw_hp) {
DoBlitScreen(PANEL_LEFT + 96, PANEL_TOP, 88, 72);
}
if (draw_btn) {
DoBlitScreen(PANEL_LEFT + 8, PANEL_TOP + 5, 72, 119);
DoBlitScreen(PANEL_LEFT + 556, PANEL_TOP + 5, 72, 48);
if (gbMaxPlayers > 1) {
DoBlitScreen(PANEL_LEFT + 84, PANEL_TOP + 91, 36, 32);
DoBlitScreen(PANEL_LEFT + 524, PANEL_TOP + 91, 36, 32);
}
}
if (sgdwCursWdtOld != 0) {
DoBlitScreen(sgdwCursXOld, sgdwCursYOld, sgdwCursWdtOld, sgdwCursHgtOld);
}
if (sgdwCursWdt != 0) {
DoBlitScreen(sgdwCursX, sgdwCursY, sgdwCursWdt, sgdwCursHgt);
}
}
if (lpDDSBackBuf == NULL) {
#ifdef __cplusplus
hDDVal = lpDDSPrimary->Unlock(NULL);
#else
hDDVal = lpDDSPrimary->lpVtbl->Unlock(lpDDSPrimary, NULL);
#endif
if (hDDVal != DDERR_SURFACELOST && hDDVal != DD_OK) {
DDErrMsg(hDDVal, 3779, "C:\\Src\\Diablo\\Source\\SCROLLRT.CPP");
}
}
#ifdef _DEBUG
DrawFPS();
#endif
}
void scrollrt_draw_game_screen(BOOL draw_cursor)
{
int hgt;
if (force_redraw == 255) {
force_redraw = 0;
hgt = SCREEN_HEIGHT;
} else {
hgt = 0;
}
if (draw_cursor) {
lock_buf(0);
scrollrt_draw_cursor_item();
unlock_buf(0);
}
DrawMain(hgt, 0, 0, 0, 0, 0);
if (draw_cursor) {
lock_buf(0);
scrollrt_draw_cursor_back_buffer();
unlock_buf(0);
}
}
/**
* @brief Render the game
*/
void DrawAndBlit()
{
int hgt;
BOOL ddsdesc, ctrlPan;
if (!gbRunGame) {
return;
}
if (force_redraw == 255) {
drawhpflag = TRUE;
drawmanaflag = TRUE;
drawbtnflag = TRUE;
drawsbarflag = TRUE;
ddsdesc = FALSE;
ctrlPan = TRUE;
hgt = SCREEN_HEIGHT;
} else if (force_redraw == 1) {
ddsdesc = TRUE;
ctrlPan = FALSE;
hgt = VIEWPORT_HEIGHT;
} else {
return;
}
force_redraw = 0;
lock_buf(0);
if (leveltype != DTYPE_TOWN) {
DrawView(ViewX, ViewY);
} else {
T_DrawView(ViewX, ViewY);
}
if (ctrlPan) {
ClearCtrlPan();
}
if (drawhpflag) {
UpdateLifeFlask();
}
if (drawmanaflag) {
UpdateManaFlask();
}
if (drawbtnflag) {
DrawCtrlPan();
}
if (drawsbarflag) {
DrawInvBelt();
}
if (talkflag) {
DrawTalkPan();
hgt = SCREEN_HEIGHT;
}
scrollrt_draw_cursor_item();
unlock_buf(0);
DrawMain(hgt, ddsdesc, drawhpflag, drawmanaflag, drawsbarflag, drawbtnflag);
lock_buf(0);
scrollrt_draw_cursor_back_buffer();
unlock_buf(0);
drawhpflag = FALSE;
drawmanaflag = FALSE;
drawbtnflag = FALSE;
drawsbarflag = FALSE;
}