static void drawTime(Vector2i origin, int hours, int minutes, int seconds, Vector4f rgba)
    {
        char buf[20];

        dd_snprintf(buf, 20, "%02d", seconds);
        M_DrawTextFragmentShadowed(buf, origin.x, origin.y, ALIGN_TOPRIGHT, 0, rgba.x, rgba.y, rgba.z, rgba.w);
        origin.x -= FR_TextWidth(buf) + FR_Tracking() * 3;
        M_DrawTextFragmentShadowed(":", origin.x, origin.y, ALIGN_TOPRIGHT, 0, rgba.x, rgba.y, rgba.z, rgba.w);
        origin.x -= FR_CharWidth(':') + 3;

        if(minutes || hours)
        {
            dd_snprintf(buf, 20, "%02d", minutes);
            M_DrawTextFragmentShadowed(buf, origin.x, origin.y, ALIGN_TOPRIGHT, 0, rgba.x, rgba.y, rgba.z, rgba.w);
            origin.x -= FR_TextWidth(buf) + FR_Tracking() * 3;
        }

        if(hours)
        {
            dd_snprintf(buf, 20, "%02d", hours);
            M_DrawTextFragmentShadowed(":", origin.x, origin.y, ALIGN_TOPRIGHT, 0, rgba.x, rgba.y, rgba.z, rgba.w);
            origin.x -= FR_CharWidth(':') + FR_Tracking() * 3;
            M_DrawTextFragmentShadowed(buf, origin.x, origin.y, ALIGN_TOPRIGHT, 0, rgba.x, rgba.y, rgba.z, rgba.w);
        }
    }
Exemple #2
0
/**
 * Display map completion time and par, or "sucks" message if overflow.
 */
static void drawTime(int x, int y, int t)
{
    patchinfo_t info;
    if(t < 0) return;

    if(t <= 61 * 59)
    {
        int seconds = t % 60, minutes = t / 60 % 60;
        char buf[20];

        x -= 22;

        FR_DrawCharXY3(':', x, y, ALIGN_TOPLEFT, DTF_NO_TYPEIN);
        if(minutes > 0)
        {
            dd_snprintf(buf, 20, "%d", minutes);
            FR_DrawTextXY3(buf, x, y, ALIGN_TOPRIGHT, DTF_NO_TYPEIN);
        }
        dd_snprintf(buf, 20, "%02d", seconds);
        FR_DrawTextXY3(buf, x+FR_CharWidth(':'), y, ALIGN_TOPLEFT, DTF_NO_TYPEIN);
        return;
    }

    // "sucks"
    if(!R_GetPatchInfo(pSucks, &info)) return;

    WI_DrawPatchXY3(pSucks, Hu_ChoosePatchReplacement(cfg.inludePatchReplaceMode, pSucks), x - info.geometry.size.width, y, ALIGN_TOPLEFT, 0, DTF_NO_TYPEIN);
}
Exemple #3
0
void IN_DrawTime(int x, int y, int h, int m, int s, float r, float g, float b, float a)
{
    char buf[20];

    dd_snprintf(buf, 20, "%02d", s);
    M_DrawTextFragmentShadowed(buf, x, y, ALIGN_TOPRIGHT, 0, r, g, b, a);
    x -= FR_TextWidth(buf) + FR_Tracking() * 3;
    M_DrawTextFragmentShadowed(":", x, y, ALIGN_TOPRIGHT, 0, r, g, b, a);
    x -= FR_CharWidth(':') + 3;

    if(m || h)
    {
        dd_snprintf(buf, 20, "%02d", m);
        M_DrawTextFragmentShadowed(buf, x, y, ALIGN_TOPRIGHT, 0, r, g, b, a);
        x -= FR_TextWidth(buf) + FR_Tracking() * 3;
    }

    if(h)
    {
        dd_snprintf(buf, 20, "%02d", h);
        M_DrawTextFragmentShadowed(":", x, y, ALIGN_TOPRIGHT, 0, r, g, b, a);
        x -= FR_CharWidth(':') + FR_Tracking() * 3;
        M_DrawTextFragmentShadowed(buf, x, y, ALIGN_TOPRIGHT, 0, r, g, b, a);
    }
}
Exemple #4
0
CBuffer* CBuffer_New(uint maxNumLines, uint maxLineLength, int flags)
{
    char name[32+1];
    CBuffer* cb;

    if(maxNumLines < 1 || maxLineLength < 1)
        Con_Error("CBuffer::New: Odd buffer params");

    cb = (CBuffer*)malloc(sizeof *cb);
    if(!cb) Con_Error("CBuffer::New: Failed on allocation of %lu bytes for new CBuffer.", (unsigned long) sizeof *cb);

    dd_snprintf(name, 33, "CBufferMutex%p", cb);
    cb->mutex = Sys_CreateMutex(name);

    cb->flags = flags;
    cb->head = cb->tail = NULL;
    cb->used = NULL;

    cb->numLines = 0;
    cb->maxLineLen = maxLineLength;
    cb->writebuf = (char*)calloc(1, cb->maxLineLen+1);
    if(!cb->writebuf) Con_Error("CBuffer::New: Failed on allocation of %lu bytes for write buffer.", (unsigned long) (cb->maxLineLen+1));
    cb->wbc = 0;
    cb->wbFlags = 0;
    cb->maxLines = maxNumLines;

    // Allocate the index now.
    cb->index = (cbnode_t**)malloc(cb->maxLines * sizeof *cb->index);
    if(!cb->index) Con_Error("CBuffer::New: Failed on allocation of %lu bytes for line index.", (unsigned long) (cb->maxLines * sizeof *cb->index));
    cb->indexSize = cb->maxLines;
    cb->indexGood = true; // its empty so...

    return cb;
}
/**
 * Expected:
 * <pre>
 *      "<whitespace> = <whitespace> [|"]<string>[|"]"
 * </pre>
 */
 static boolean parseString(char** str, char* buf, size_t bufLen)
{
    size_t len;
    char* end;

    if(!buf || bufLen == 0) return false;

    *str = M_SkipWhite(*str);
    if(**str != '=') return false; // Now I'm confused!

    // Skip over any leading whitespace.
    *str = M_SkipWhite(*str + 1);

    // Skip over any opening '"' character.
    if(**str == '"') (*str)++;

    // Find the end of the string.
    end = *str;
    while(*end && *end != '}' && *end != ',' && *end !='"') { end++; }

    len = end - *str;
    if(len != 0)
    {
        dd_snprintf(buf, MIN_OF(len+1, bufLen), "%s", *str);
        *str = end;
    }

    // Skip over any closing '"' character.
    if(**str == '"')
        (*str)++;

    return true;
}
Exemple #6
0
void IN_LoadPics(void)
{
    char buf[9];
    int i;

    if(wbs->episode < 3)
        dpInterPic = R_DeclarePatch(wbs->episode == 0? "MAPE1" : wbs->episode == 1? "MAPE2" : "MAPE3");

    dpBeenThere = R_DeclarePatch("IN_X");
    dpGoingThere = R_DeclarePatch("IN_YAH");

    for(i = 0; i < NUMTEAMS; ++i)
    {
        dd_snprintf(buf, 9, "FACEA%i", i);
        dpFaceAlive[i] = R_DeclarePatch(buf);
        dd_snprintf(buf, 9, "FACEB%i", i);
        dpFaceDead[i] = R_DeclarePatch(buf);
    }
}
Exemple #7
0
void IN_LoadPics()
{
    if(::gameEpisode < 3)
    {
        dpInterPic = R_DeclarePatch(::gameEpisode == 0? "MAPE1" : ::gameEpisode == 1? "MAPE2" : "MAPE3");
    }

    dpBeenThere  = R_DeclarePatch("IN_X");
    dpGoingThere = R_DeclarePatch("IN_YAH");

    char buf[9];
    for(int i = 0; i < NUMTEAMS; ++i)
    {
        dd_snprintf(buf, 9, "FACEA%i", i);
        dpFaceAlive[i] = R_DeclarePatch(buf);
        dd_snprintf(buf, 9, "FACEB%i", i);
        dpFaceDead[i] = R_DeclarePatch(buf);
    }
}
Exemple #8
0
static void drawPercent(int x, int y, int p)
{
    Point2Raw origin;
    char buf[20];
    if(p < 0) return;

    origin.x = x;
    origin.y = y;
    dd_snprintf(buf, 20, "%i", p);
    FR_DrawChar3('%', &origin, ALIGN_TOPLEFT, DTF_NO_TYPEIN);
    FR_DrawText3(buf, &origin, ALIGN_TOPRIGHT, DTF_NO_TYPEIN);
}
Exemple #9
0
static void determineGlobalPaths(application_t* app)
{
    assert(app);

    // By default, make sure the working path is the home folder.
    de::App::setCurrentWorkPath(de::App::app().nativeHomePath());

#ifndef MACOSX
    if(getenv("HOME"))
    {
        filename_t homePath;
        directory_t* temp;
        dd_snprintf(homePath, FILENAME_T_MAXLEN, "%s/%s/runtime/", getenv("HOME"),
                    DENG2_APP->unixHomeFolderName().toLatin1().constData());
        temp = Dir_New(homePath);
        Dir_mkpath(Dir_Path(temp));
        app->usingHomeDir = Dir_SetCurrent(Dir_Path(temp));
        if(app->usingHomeDir)
        {
            DD_SetRuntimePath(Dir_Path(temp));
        }
        Dir_Delete(temp);
    }
#endif

    // The -userdir option sets the working directory.
    if(CommandLine_CheckWith("-userdir", 1))
    {
        filename_t runtimePath;
        directory_t* temp;

        strncpy(runtimePath, CommandLine_NextAsPath(), FILENAME_T_MAXLEN);
        Dir_CleanPath(runtimePath, FILENAME_T_MAXLEN);
        // Ensure the path is closed with a directory separator.
        F_AppendMissingSlashCString(runtimePath, FILENAME_T_MAXLEN);

        temp = Dir_New(runtimePath);
        app->usingUserDir = Dir_SetCurrent(Dir_Path(temp));
        if(app->usingUserDir)
        {
            DD_SetRuntimePath(Dir_Path(temp));
#ifndef MACOSX
            app->usingHomeDir = false;
#endif
        }
        Dir_Delete(temp);
    }

#ifndef MACOSX
    if(!app->usingHomeDir && !app->usingUserDir)
#else
    if(!app->usingUserDir)
#endif
    {
        // The current working directory is the runtime dir.
        directory_t* temp = Dir_NewFromCWD();
        DD_SetRuntimePath(Dir_Path(temp));
        Dir_Delete(temp);
    }

    // libcore has determined the native base path, so let FS1 know about it.
    DD_SetBasePath(DENG2_APP->nativeBasePath().toUtf8());
}
Exemple #10
0
void IN_DrawCoopStats(void)
{
#define TRACKING                    (1)

    static int sounds;

    int i, ypos;

    DGL_Enable(DGL_TEXTURE_2D);

    FR_SetFont(FID(GF_FONTB));
    FR_LoadDefaultAttrib();
    FR_SetColorAndAlpha(defFontRGB[0], defFontRGB[1], defFontRGB[2], 1);

    FR_DrawTextXY3("KILLS", 95, 35, ALIGN_TOPLEFT, DTF_ONLY_SHADOW);
    FR_DrawTextXY3("BONUS", 155, 35, ALIGN_TOPLEFT, DTF_ONLY_SHADOW);
    FR_DrawTextXY3("SECRET", 232, 35, ALIGN_TOPLEFT, DTF_ONLY_SHADOW);
    FR_DrawTextXY3(P_GetShortMapName(wbs->episode, wbs->currentMap), SCREENWIDTH/2, 3, ALIGN_TOP, DTF_ONLY_SHADOW);

    FR_SetFont(FID(GF_FONTA));
    FR_SetColor(defFontRGB3[0], defFontRGB3[1], defFontRGB3[2]);
    FR_DrawTextXY3("FINISHED", SCREENWIDTH/2, 25, ALIGN_TOP, DTF_ONLY_SHADOW);

    FR_SetFont(FID(GF_FONTB));
    FR_SetTracking(TRACKING);

    ypos = 50;
    for(i = 0; i < NUMTEAMS; ++i)
    {
        if(teamInfo[i].members)
        {
            char buf[20];

            DGL_Color4f(0, 0, 0, .4f);
            GL_DrawPatchXY(dpFaceAlive[i], 27, ypos+2);

            DGL_Color4f(defFontRGB[0], defFontRGB[1], defFontRGB[2], 1);
            GL_DrawPatchXY(dpFaceAlive[i], 25, ypos);

            if(interTime < 40)
            {
                sounds = 0;
                ypos += 37;
                continue;
            }
            else if(interTime >= 40 && sounds < 1)
            {
                S_LocalSound(SFX_DORCLS, NULL);
                sounds++;
            }

            dd_snprintf(buf, 20, "%i", killPercent[i]);
            M_DrawTextFragmentShadowed(buf, 121, ypos + 10, ALIGN_TOPRIGHT, 0, defFontRGB[0], defFontRGB[1], defFontRGB[2], 1);
            M_DrawTextFragmentShadowed("%", 121, ypos + 10, ALIGN_TOPLEFT, 0, defFontRGB[0], defFontRGB[1], defFontRGB[2], 1);

            dd_snprintf(buf, 20, "%i", bonusPercent[i]);
            M_DrawTextFragmentShadowed(buf, 196, ypos + 10, ALIGN_TOPRIGHT, 0, defFontRGB[0], defFontRGB[1], defFontRGB[2], 1);
            M_DrawTextFragmentShadowed("%", 196, ypos + 10, ALIGN_TOPLEFT, 0, defFontRGB[0], defFontRGB[1], defFontRGB[2], 1);

            dd_snprintf(buf, 20, "%i", secretPercent[i]);
            M_DrawTextFragmentShadowed(buf, 273, ypos + 10, ALIGN_TOPRIGHT, 0, defFontRGB[0], defFontRGB[1], defFontRGB[2], 1);
            M_DrawTextFragmentShadowed("%", 273, ypos + 10, ALIGN_TOPLEFT, 0, defFontRGB[0], defFontRGB[1], defFontRGB[2], 1);
            ypos += 37;
        }
    }

    DGL_Disable(DGL_TEXTURE_2D);

#undef TRACKING
}
Exemple #11
0
void IN_DrawSingleStats(void)
{
#define TRACKING                (1)

    static int sounds;
    char buf[20];

    DGL_Enable(DGL_TEXTURE_2D);

    FR_SetFont(FID(GF_FONTB));
    FR_LoadDefaultAttrib();
    FR_SetColorAndAlpha(defFontRGB[0], defFontRGB[1], defFontRGB[2], 1);

    FR_DrawTextXY3("KILLS", 50, 65, ALIGN_TOPLEFT, DTF_ONLY_SHADOW);
    FR_DrawTextXY3("ITEMS", 50, 90, ALIGN_TOPLEFT, DTF_ONLY_SHADOW);
    FR_DrawTextXY3("SECRETS", 50, 115, ALIGN_TOPLEFT, DTF_ONLY_SHADOW);
    FR_DrawTextXY3(P_GetShortMapName(wbs->episode, wbs->currentMap), 160, 3, ALIGN_TOP, DTF_ONLY_SHADOW);

    FR_SetFont(FID(GF_FONTA));
    FR_SetColor(defFontRGB3[0], defFontRGB3[1], defFontRGB3[2]);

    FR_DrawTextXY3("FINISHED", 160, 25, ALIGN_TOP, DTF_ONLY_SHADOW);

    DGL_Disable(DGL_TEXTURE_2D);

    if(interTime < 30)
    {
        sounds = 0;
        return;
    }

    if(sounds < 1 && interTime >= 30)
    {
        S_LocalSound(SFX_DORCLS, NULL);
        sounds++;
    }

    DGL_Enable(DGL_TEXTURE_2D);

    dd_snprintf(buf, 20, "%i", players[CONSOLEPLAYER].killCount);
    FR_SetFont(FID(GF_FONTB));
    FR_SetTracking(TRACKING);
    M_DrawTextFragmentShadowed(buf, 236, 65, ALIGN_TOPRIGHT, 0, defFontRGB[0], defFontRGB[1], defFontRGB[2], 1);

    M_DrawTextFragmentShadowed("/", 241, 65, ALIGN_TOPLEFT, 0, defFontRGB[0], defFontRGB[1], defFontRGB[2], 1);

    dd_snprintf(buf, 20, "%i", totalKills);
    M_DrawTextFragmentShadowed(buf, 284, 65, ALIGN_TOPRIGHT, 0, defFontRGB[0], defFontRGB[1], defFontRGB[2], 1);

    DGL_Disable(DGL_TEXTURE_2D);

    if(interTime < 60)
        return;

    if(sounds < 2 && interTime >= 60)
    {
        S_LocalSound(SFX_DORCLS, NULL);
        sounds++;
    }

    DGL_Enable(DGL_TEXTURE_2D);

    dd_snprintf(buf, 20, "%i", players[CONSOLEPLAYER].itemCount);
    FR_SetFont(FID(GF_FONTB));
    M_DrawTextFragmentShadowed(buf, 236, 90, ALIGN_TOPRIGHT, 0, defFontRGB[0], defFontRGB[1], defFontRGB[2], 1);

    M_DrawTextFragmentShadowed("/", 241, 90, ALIGN_TOPLEFT, 0, defFontRGB[0], defFontRGB[1], defFontRGB[2], 1);

    dd_snprintf(buf, 20, "%i", totalItems);
    M_DrawTextFragmentShadowed(buf, 284, 90, ALIGN_TOPRIGHT, 0, defFontRGB[0], defFontRGB[1], defFontRGB[2], 1);

    DGL_Disable(DGL_TEXTURE_2D);

    if(interTime < 90)
        return;

    if(sounds < 3 && interTime >= 90)
    {
        S_LocalSound(SFX_DORCLS, NULL);
        sounds++;
    }

    DGL_Enable(DGL_TEXTURE_2D);

    dd_snprintf(buf, 20, "%i", players[CONSOLEPLAYER].secretCount);
    FR_SetFont(FID(GF_FONTB));
    M_DrawTextFragmentShadowed(buf, 236, 115, ALIGN_TOPRIGHT, 0, defFontRGB[0], defFontRGB[1], defFontRGB[2], 1);

    M_DrawTextFragmentShadowed("/", 241, 115, ALIGN_TOPLEFT, 0, defFontRGB[0], defFontRGB[1], defFontRGB[2], 1);

    dd_snprintf(buf, 20, "%i", totalSecret);
    M_DrawTextFragmentShadowed(buf, 284, 115, ALIGN_TOPRIGHT, 0, defFontRGB[0], defFontRGB[1], defFontRGB[2], 1);

    DGL_Disable(DGL_TEXTURE_2D);

    if(interTime < 150)
    {
        return;
    }

    if(sounds < 4 && interTime >= 150)
    {
        S_LocalSound(SFX_DORCLS, NULL);
        sounds++;
    }

    if(gameMode != heretic_extended || wbs->episode < 3)
    {
        DGL_Enable(DGL_TEXTURE_2D);

        FR_SetFont(FID(GF_FONTB));
        FR_SetColorAndAlpha(defFontRGB[0], defFontRGB[1], defFontRGB[2], 1);
        FR_DrawTextXY3("TIME", 85, 160, ALIGN_TOPLEFT, DTF_ONLY_SHADOW);

        IN_DrawTime(284, 160, hours, minutes, seconds, defFontRGB[0], defFontRGB[1], defFontRGB[2], 1);

        DGL_Disable(DGL_TEXTURE_2D);
    }
    else
    {
        DGL_Enable(DGL_TEXTURE_2D);

        FR_SetFont(FID(GF_FONTA));
        FR_SetColorAndAlpha(defFontRGB3[0], defFontRGB3[1], defFontRGB3[2], 1);
        FR_DrawTextXY3("NOW ENTERING:", SCREENWIDTH/2, 160, ALIGN_TOP, DTF_ONLY_SHADOW);

        FR_SetFont(FID(GF_FONTB));
        FR_SetColorAndAlpha(defFontRGB[0], defFontRGB[1], defFontRGB[2], 1);
        FR_DrawTextXY3(P_GetShortMapName(wbs->episode, wbs->nextMap), 160, 170, ALIGN_TOP, DTF_ONLY_SHADOW);

        DGL_Disable(DGL_TEXTURE_2D);

        skipIntermission = false;
    }

#undef TRACKING
}
Exemple #12
0
static void drawNetgameStats(void)
{
#define ORIGINX             (NG_STATSX + starWidth/2 + NG_STATSX*!doFrags)

    int i, x, y, starWidth, pwidth;
    patchinfo_t info;

    DGL_Enable(DGL_TEXTURE_2D);
    DGL_Color4f(1, 1, 1, 1);

    FR_SetFont(FID(GF_FONTB));
    FR_LoadDefaultAttrib();
    FR_SetColorAndAlpha(defFontRGB2[CR], defFontRGB2[CG], defFontRGB2[CB], 1);

    pwidth = FR_CharWidth('%');
    R_GetPatchInfo(pFaceAlive, &info);
    starWidth = info.geometry.size.width;

    // Draw stat titles (top line).
    R_GetPatchInfo(pKills, &info);
    WI_DrawPatchXY3(pKills, Hu_ChoosePatchReplacement(cfg.inludePatchReplaceMode, pKills), ORIGINX + NG_SPACINGX, NG_STATSY, ALIGN_TOPRIGHT, 0, DTF_NO_TYPEIN);
    y = NG_STATSY + info.geometry.size.height;

    WI_DrawPatchXY3(pItems, Hu_ChoosePatchReplacement(cfg.inludePatchReplaceMode, pItems), ORIGINX + 2 * NG_SPACINGX, NG_STATSY, ALIGN_TOPRIGHT, 0, DTF_NO_TYPEIN);
    WI_DrawPatchXY3(pSecret, Hu_ChoosePatchReplacement(cfg.inludePatchReplaceMode, pSecret), ORIGINX + 3 * NG_SPACINGX, NG_STATSY, ALIGN_TOPRIGHT, 0, DTF_NO_TYPEIN);
    if(doFrags)
    {
        WI_DrawPatchXY3(pFrags, Hu_ChoosePatchReplacement(cfg.inludePatchReplaceMode, pFrags), ORIGINX + 4 * NG_SPACINGX, NG_STATSY, ALIGN_TOPRIGHT, 0, DTF_NO_TYPEIN);
    }

    // Draw stats.
    for(i = 0; i < NUMTEAMS; ++i)
    {
        patchinfo_t info;

        if(0 == teamInfo[i].playerCount)
            continue;

        FR_SetFont(FID(GF_FONTA));
        FR_SetColorAndAlpha(1, 1, 1, 1);

        x = ORIGINX;
        R_GetPatchInfo(pTeamBackgrounds[i], &info);
        WI_DrawPatchXY3(pTeamBackgrounds[i], Hu_ChoosePatchReplacement(cfg.inludePatchReplaceMode, pTeamBackgrounds[i]), x - info.geometry.size.width, y, ALIGN_TOPLEFT, 0, DTF_NO_TYPEIN);

        // If more than 1 member, show the member count.
        if(1 != teamInfo[i].playerCount)
        {
            char tmp[40];

            sprintf(tmp, "%i", teamInfo[i].playerCount);
            FR_DrawTextXY3(tmp, x - info.geometry.size.width + 1, y + info.geometry.size.height - 8, ALIGN_TOPLEFT, DTF_NO_TYPEIN);
        }

        FR_SetColorAndAlpha(defFontRGB2[CR], defFontRGB2[CG], defFontRGB2[CB], 1);

        if(i == inPlayerTeam)
            WI_DrawPatchXY3(pFaceAlive, Hu_ChoosePatchReplacement(cfg.inludePatchReplaceMode, pFaceAlive), x - info.geometry.size.width, y, ALIGN_TOPLEFT, 0, DTF_NO_TYPEIN);
        x += NG_SPACINGX;

        FR_SetFont(FID(GF_SMALL));
        drawPercent(x - pwidth, y + 10, cntKills[i]);
        x += NG_SPACINGX;

        drawPercent(x - pwidth, y + 10, cntItems[i]);
        x += NG_SPACINGX;

        drawPercent(x - pwidth, y + 10, cntSecret[i]);
        x += NG_SPACINGX;

        if(doFrags)
        {
            char buf[20];
            dd_snprintf(buf, 20, "%i", cntFrags[i]);
            FR_DrawTextXY3(buf, x, y + 10, ALIGN_TOPRIGHT, DTF_NO_TYPEIN);
        }

        y += WI_SPACINGY;
    }

    DGL_Disable(DGL_TEXTURE_2D);

#undef ORIGINX
}
Exemple #13
0
static void drawDeathmatchStats(void)
{
    int i, j, x, y, w;// lh = WI_SPACINGY; // Line height.

    DGL_Enable(DGL_TEXTURE_2D);
    DGL_Color4f(1, 1, 1, 1);

    FR_SetFont(FID(GF_FONTB));
    FR_LoadDefaultAttrib();
    FR_SetColorAndAlpha(defFontRGB2[CR], defFontRGB2[CG], defFontRGB2[CB], 1);

    // Draw stat titles (top line).
    { patchinfo_t info;
    if(R_GetPatchInfo(pTotal, &info))
        WI_DrawPatchXY3(pTotal, Hu_ChoosePatchReplacement(cfg.inludePatchReplaceMode, pTotal), DM_TOTALSX - info.geometry.size.width / 2, DM_MATRIXY - WI_SPACINGY + 10, ALIGN_TOPLEFT, 0, DTF_NO_TYPEIN); }

    WI_DrawPatchXY3(pKillers, Hu_ChoosePatchReplacement(cfg.inludePatchReplaceMode, pKillers), DM_KILLERSX, DM_KILLERSY, ALIGN_TOPLEFT, 0, DTF_NO_TYPEIN);
    WI_DrawPatchXY3(pVictims, Hu_ChoosePatchReplacement(cfg.inludePatchReplaceMode, pVictims), DM_VICTIMSX, DM_VICTIMSY, ALIGN_TOPLEFT, 0, DTF_NO_TYPEIN);

    x = DM_MATRIXX + DM_SPACINGX;
    y = DM_MATRIXY;

    for(i = 0; i < NUMTEAMS; ++i)
    {
        if(teamInfo[i].playerCount > 0)
        {
            patchid_t patchId = pTeamBackgrounds[i];
            const char* replacement;
            patchinfo_t info;

            FR_SetColorAndAlpha(defFontRGB2[CR], defFontRGB2[CG], defFontRGB2[CB], 1);

            R_GetPatchInfo(patchId, &info);
            replacement = Hu_ChoosePatchReplacement(cfg.inludePatchReplaceMode, patchId);
            WI_DrawPatchXY3(patchId, replacement, x - info.geometry.size.width / 2, DM_MATRIXY - WI_SPACINGY, ALIGN_TOPLEFT, 0, DTF_NO_TYPEIN);
            WI_DrawPatchXY3(patchId, replacement, DM_MATRIXX - info.geometry.size.width / 2, y, ALIGN_TOPLEFT, 0, DTF_NO_TYPEIN);

            if(i == inPlayerTeam)
            {
                WI_DrawPatchXY3(pFaceDead, Hu_ChoosePatchReplacement(cfg.inludePatchReplaceMode, pFaceDead), x - info.geometry.size.width / 2, DM_MATRIXY - WI_SPACINGY, ALIGN_TOPLEFT, 0, DTF_NO_TYPEIN);
                WI_DrawPatchXY3(pFaceAlive, Hu_ChoosePatchReplacement(cfg.inludePatchReplaceMode, pFaceAlive), DM_MATRIXX - info.geometry.size.width / 2, y, ALIGN_TOPLEFT, 0, DTF_NO_TYPEIN);
            }

            // If more than 1 member, show the member count.
            if(1 > teamInfo[i].playerCount)
            {
                char tmp[20];
                sprintf(tmp, "%i", teamInfo[i].playerCount);

                FR_SetFont(FID(GF_FONTA));
                FR_DrawTextXY3(tmp, x - info.geometry.size.width / 2 + 1, DM_MATRIXY - WI_SPACINGY + info.geometry.size.height - 8, ALIGN_TOPLEFT, DTF_NO_TYPEIN);
                FR_DrawTextXY3(tmp, DM_MATRIXX - info.geometry.size.width / 2 + 1, y + info.geometry.size.height - 8, ALIGN_TOPLEFT, DTF_NO_TYPEIN);
            }
        }
        else
        {
            patchid_t patchId = pTeamIcons[i];
            const char* replacement = Hu_ChoosePatchReplacement(cfg.inludePatchReplaceMode, patchId);
            patchinfo_t info;

            FR_SetColorAndAlpha(defFontRGB[CR], defFontRGB[CG], defFontRGB[CB], 1);

            R_GetPatchInfo(patchId, &info);
            WI_DrawPatchXY3(patchId, replacement, x - info.geometry.size.width / 2, DM_MATRIXY - WI_SPACINGY + 10, ALIGN_TOPLEFT, 0, DTF_NO_TYPEIN);
            WI_DrawPatchXY3(patchId, replacement, DM_MATRIXX - info.geometry.size.width / 2, y + 10, ALIGN_TOPLEFT, 0, DTF_NO_TYPEIN);
        }

        x += DM_SPACINGX;
        y += WI_SPACINGY;
    }

    // Draw stats.
    y = DM_MATRIXY + 10;
    FR_SetFont(FID(GF_SMALL));
    FR_SetColorAndAlpha(defFontRGB2[CR], defFontRGB2[CG], defFontRGB2[CB], 1);
    w = FR_CharWidth('0');

    for(i = 0; i < NUMTEAMS; ++i)
    {
        x = DM_MATRIXX + DM_SPACINGX;
        if(teamInfo[i].playerCount > 0)
        {
            char buf[20];
            for(j = 0; j < NUMTEAMS; ++j)
            {
                if(teamInfo[j].playerCount > 0)
                {
                    dd_snprintf(buf, 20, "%i", dmFrags[i][j]);
                    FR_DrawTextXY3(buf, x + w, y, ALIGN_TOPRIGHT, DTF_NO_TYPEIN);
                }
                x += DM_SPACINGX;
            }
            dd_snprintf(buf, 20, "%i", dmTotals[i]);
            FR_DrawTextXY3(buf, DM_TOTALSX + w, y, ALIGN_TOPRIGHT, DTF_NO_TYPEIN);
        }

        y += WI_SPACINGY;
    }

    DGL_Disable(DGL_TEXTURE_2D);
}