view src/objinfo.cc @ 33:a68786b9c74b

Oops, used indent with tabs enabled. Remove tabs.
author Matti Hamalainen <ccr@tnsp.org>
date Sat, 24 Sep 2011 15:59:33 +0300
parents 8eaf72e2041b
children a2898079d6fe
line wrap: on
line source

/*
 *        objinfo.cc
 *        AYM 1998-09-20
 */


/*
This file is part of Yadex.

Yadex incorporates code from DEU 5.21 that was put in the public domain in
1994 by Raphaël Quinet and Brendon Wyber.

The rest of Yadex is Copyright © 1997-2003 André Majorel and others.

This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.

This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place, Suite 330, Boston, MA 02111-1307, USA.
*/


#include "yadex.h"
#include <vector>
#include <algorithm>
#include <X11/Xlib.h>
#include "disppic.h"
#include "flats.h"                // DisplayFloorTexture()
#include "game.h"                // THINGDEF_SPECTRAL
#include "gamesky.h"                // is_sky()
#include "gfx.h"
#include "img.h"
#include "imgspect.h"
#include "l_super.h"
#include "levels.h"
#include "objid.h"
#include "objinfo.h"
#include "pic2img.h"
#include "sticker.h"
#include "things.h"
#include "wadres.h"


static const int sprite_width = 90;
static const int sprite_height = 90;


/*
 *        Extraf - one item in the list of EDGE extrafloors
 */
class Extraf
{
    public: Extraf(obj_no_t sector, wad_name_t & tex, wad_z_t height)
    {
        this->sector = sector;
        memcpy(this->tex, &tex, sizeof this->tex);
        this->height = height;
    }

    bool operator<(const Extraf & other) const
    {
        if (height < other.height)
            return true;
        else if (height == other.height && sector < other.sector)
            return true;
        return false;
    }

    wad_z_t height;                // To sort by increasing floor height
    obj_no_t sector;                // Sector# (for heights, flats and light level)
    wad_tex_name_t tex;                // Texture (middle tex of first sidedef)
};


static void get_extrafloors(std::vector < Extraf > &list, wad_tag_t tag);


objinfo_c::objinfo_c()
{
    for (size_t n = 0; n < MAX_BOXES; n++)
        box_disp[n] = false;
    obj_no = OBJ_NO_NONE;
    obj_no_disp = OBJ_NO_NONE;
    prev_sector = OBJ_NO_NONE;
    out_y1 = 0;
}


void objinfo_c::draw()
{
    int n;
    int sd1 = OBJ_NO_NONE;
    int sd2 = OBJ_NO_NONE;
    int s1 = OBJ_NO_NONE;
    int s2 = OBJ_NO_NONE;
    int x0, y0;                        // Outer top left corner
    int ix0, iy0;                // Inner top left corner
    int width;
    int height;

    // Am I already drawn ?
    if (!is_obj(obj_no) || obj_no == obj_no_disp && obj_type == obj_type_disp)
        return;

    // Does the box need to be redrawn ?
    if (obj_type != obj_type_disp)
        box_disp[0] = false;

    // The caller should have called set_y1() before !
    if (!out_y1)
        return;

    switch (obj_type)
    {
    case OBJ_THINGS:
        {
            const int columns = 27;
            width = 2 * BOX_BORDER + 3 * WIDE_HSPACING + columns * FONTW
                + 2 * HOLLOW_BORDER + sprite_width;
            height = 2 * BOX_BORDER + 2 * WIDE_VSPACING
                + y_max((int) (6.5 * FONTH), sprite_height);
            x0 = 0;
            y0 = out_y1 - height + 1;
            ix0 = x0 + BOX_BORDER + WIDE_HSPACING;
            iy0 = y0 + BOX_BORDER + WIDE_VSPACING;
            int ix1 = x0 + width - 1 - BOX_BORDER - WIDE_HSPACING;
            int iy1 = y0 + height - 1 - BOX_BORDER - WIDE_VSPACING;
            if (box_disp[0])
            {
                push_colour(WINBG);
                DrawScreenBox(ix0, iy0, ix0 + columns * FONTW - 1, iy1);
                pop_colour();
            }
            else
                DrawScreenBox3D(x0, y0, x0 + width - 1, y0 + height - 1);
            if (obj_no < 0)
            {
                const char *message = "(no thing selected)";
                set_colour(WINFG_DIM);
                DrawScreenText(x0 + (width - FONTW * strlen(message)) / 2,
                               y0 + (height - FONTH) / 2, message);
                break;
            }
            set_colour(WINTITLE);
            DrawScreenText(ix0, iy0, "Thing #%d", obj_no);
            const bool invalid_type = !is_thing_type(Things[obj_no].type);
            set_colour(WINFG);
            DrawScreenText(-1, iy0 + (int) (1.5 * FONTH), 0);
            DrawScreenText(-1, -1, "\1Coords:\2 (%d, %d)",
                           Things[obj_no].xpos, Things[obj_no].ypos);
            DrawScreenString(-1, -1, "\1Type:   ");
            if (invalid_type)
                push_colour(CLR_ERROR);
            DrawScreenText(-2, -2, "%d", Things[obj_no].type);
            if (invalid_type)
                pop_colour();
            DrawScreenString(-1, -1, "\1Desc:   ");
            if (invalid_type)
                push_colour(CLR_ERROR);
            DrawScreenText(-2, -2, "%.19s",
                           get_thing_name(Things[obj_no].type));
            if (invalid_type)
                pop_colour();
            DrawScreenText(-1, -1, "\1Angle:\2  %s",
                           GetAngleName(Things[obj_no].angle));
            DrawScreenText(-1, -1, "\1Flags:\2  %s",
                           GetWhenName(Things[obj_no].when));

            // Show the corresponding sprite
            {
                int sx1 = ix1 + 1 - HOLLOW_BORDER;
                int sy1 = iy1 + 1 - HOLLOW_BORDER;
                int sx0 = sx1 + 1 - sprite_width;
                int sy0 = sy1 + 1 - sprite_height;
                draw_box_border(sx0 - HOLLOW_BORDER, sy0 - HOLLOW_BORDER,
                                sprite_width + 2 * HOLLOW_BORDER,
                                sprite_height + 2 * HOLLOW_BORDER,
                                HOLLOW_BORDER, 0);
                const char *sprite_root =
                    get_thing_sprite(Things[obj_no].type);
                char flags = get_thing_flags(Things[obj_no].type);
                if (sprite_root == NULL)
                {
                    push_colour(WINBG);
                    DrawScreenBox(sx0, sy0, sx1, sy1);
                    pop_colour();
                    set_colour(WINFG_DIM);
                    DrawScreenText(sx0 + (sprite_width - 2 * FONTW) / 2,
                                   sy0 + sprite_height / 2 + 1 - FONTH, "no");
                    DrawScreenText(sx0 + (sprite_width - 6 * FONTW) / 2,
                                   sy0 + sprite_height / 2 + 1, "sprite");
                }
                else
                {
                    Lump_loc loc;
                    Img img(sprite_width, sprite_height, false);
                    Sticker sticker;
                    wad_res.sprites.loc_by_root(sprite_root, loc);
                    if (loc.wad == 0
                        || LoadPicture(img, sprite_root, loc, INT_MIN,
                                       INT_MIN))
                    {
                        push_colour(WINBG);
                        DrawScreenBox(sx0, sy0, sx1, sy1);
                        pop_colour();
                        set_colour(CLR_ERROR);
                        DrawScreenString(sx0 +
                                         (sprite_width -
                                          strlen(sprite_root) * FONTW) / 2,
                                         sy0 + sprite_height / 2 + 1 -
                                         3 * FONTH / 2, sprite_root);
                        DrawScreenText(sx0 + (sprite_width - 3 * FONTW) / 2,
                                       sy0 + sprite_height / 2 + 1 -
                                       FONTH / 2, "not");
                        DrawScreenText(sx0 + (sprite_width - 5 * FONTW) / 2,
                                       sy0 + sprite_height / 2 + 1 +
                                       FONTH / 2, "found");
                    }
                    else
                    {
                        if (flags & THINGDEF_SPECTRAL)
                            spectrify_img(img);
                        sticker.load(img, true);
                        sticker.draw(drw, 't', sx0, sy0);
                    }
                }
            }
        }
        break;

    case OBJ_LINEDEFS:
        // Linedef
        width = 2 * BOX_BORDER + 2 * WIDE_HSPACING + 29 * FONTW;
        height = 2 * BOX_BORDER + 2 * WIDE_VSPACING + (int) (8.5 * FONTH);
        x0 = 0;
        y0 = out_y1 - height + 1;
        ix0 = x0 + BOX_BORDER + WIDE_HSPACING;
        iy0 = y0 + BOX_BORDER + WIDE_VSPACING;
        // Ignore box_disp -- always redraw the whole box
        DrawScreenBox3D(x0, y0, x0 + width - 1, y0 + height - 1);
        if (obj_no >= 0)
        {
            set_colour(WINTITLE);
            DrawScreenText(ix0, iy0, "Linedef #%d", obj_no);
            set_colour(WINFG);
            DrawScreenText(-1, iy0 + (int) (1.5 * FONTH),
                           "\1Flags:\2    %.19s",
                           GetLineDefFlagsName(LineDefs[obj_no].flags));
            DrawScreenText(-1, -1, "\1Type:\2 %3d %.19s",
                           LineDefs[obj_no].type,
                           GetLineDefTypeName(LineDefs[obj_no].type));
            {
                int tag = LineDefs[obj_no].tag;
                int first_sector = NumSectors;
                int second_sector = NumSectors;
                if (tag != 0)
                {
                    for (int n = 0; n < NumSectors; n++)
                        if (Sectors[n].tag == tag)
                        {
                            if (first_sector >= NumSectors)
                                first_sector = n;
                            else
                            {
                                second_sector = n;
                                break;
                            }
                        }
                }
                if (first_sector < NumSectors && second_sector < NumSectors)
                    DrawScreenText(-1, -1, "\1Tag:\2      %d (#%d+)", tag,
                                   first_sector);
                else if (first_sector < NumSectors)
                    DrawScreenText(-1, -1, "\1Tag:\2      %d (#%d)", tag,
                                   first_sector);
                else
                    DrawScreenText(-1, -1, "\1Tag:\2      %d (none)", tag);
            }
            s1 = LineDefs[obj_no].start;
            s2 = LineDefs[obj_no].end;
            DrawScreenText(-1, -1, "\1Vertices:\2 (#%d, #%d)", s1, s2);
            n = ComputeDist(Vertices[s2].x - Vertices[s1].x,
                            Vertices[s2].y - Vertices[s1].y);
            DrawScreenText(-1, -1, "\1Length:\2   %d", n);
            sd1 = LineDefs[obj_no].sidedef1;
            sd2 = LineDefs[obj_no].sidedef2;
            DrawScreenText(-1, -1, "\1" "1st sd:\2   #%d", sd1);
            DrawScreenText(-1, -1, "\1" "2nd sd:\2   #%d", sd2);
            if (sd1 >= 0)
                s1 = SideDefs[sd1].sector;
            else
                s1 = -1;
            if (sd2 >= 0)
                s2 = SideDefs[sd2].sector;
            else
                s2 = -1;
        }
        else
        {
            const char *message = "(no linedef selected)";
            set_colour(WINFG_DIM);
            DrawScreenText(x0 + (width - FONTW * strlen(message)) / 2,
                           y0 + (height - FONTH) / 2, message);
        }

        // 1st sidedef
        x0 += width;
        width = 2 * BOX_BORDER + 2 * WIDE_HSPACING + 16 * FONTW;
        ix0 = x0 + BOX_BORDER + WIDE_HSPACING;
        y0 = out_y1 - height + 1;
        // Ignore box_disp -- always redraw the whole box
        DrawScreenBox3D(x0, y0, x0 + width - 1, y0 + height - 1);
        if (obj_no >= 0 && sd1 >= 0)
        {
            set_colour(WINTITLE);
            DrawScreenText(ix0, iy0, "Sidedef1 #%d", sd1);

            if (s1 >= 0 && s2 >= 0 && Sectors[s1].ceilh > Sectors[s2].ceilh
                && !(is_sky(Sectors[s1].ceilt) && is_sky(Sectors[s2].ceilt)))
            {
                if (SideDefs[sd1].tex1[0] == '-'
                    && SideDefs[sd1].tex1[1] == '\0')
                    set_colour(CLR_ERROR);
                else
                    set_colour(WINFG);
            }
            else
                set_colour(WINFG_DIM);
            DrawScreenText(-1, iy0 + (int) (1.5 * FONTH), "\1Upper:\2  %.*s",
                           WAD_TEX_NAME, SideDefs[sd1].tex1);

            if (sd2 < 0
                && SideDefs[sd1].tex3[0] == '-'
                && SideDefs[sd1].tex3[1] == '\0')
                set_colour(CLR_ERROR);
            else
                set_colour(WINFG);
            DrawScreenText(-1, -1,
                           "\1Middle:\2 %.*s", WAD_TEX_NAME,
                           SideDefs[sd1].tex3);

            if (s1 >= 0 && s2 >= 0 && Sectors[s1].floorh < Sectors[s2].floorh
                && !(is_sky(Sectors[s1].floort)
                     && is_sky(Sectors[s2].floort)))
            {
                if (SideDefs[sd1].tex2[0] == '-'
                    && SideDefs[sd1].tex2[1] == '\0')
                    set_colour(CLR_ERROR);
                else
                    set_colour(WINFG);
            }
            else
                set_colour(WINFG_DIM);
            DrawScreenText(-1, -1, "\1Lower:\2  %.*s",
                           WAD_TEX_NAME, SideDefs[sd1].tex2);

            set_colour(WINFG);
            DrawScreenText(-1, -1, "\1X-ofs:\2  %d", SideDefs[sd1].xoff);
            DrawScreenText(-1, -1, "\1Y-ofs:\2  %d", SideDefs[sd1].yoff);
            DrawScreenText(-1, -1, "\1Sector:\2 #%d", s1);
        }
        else
        {
            const char *message = "(no 1st sidedef)";
            set_colour(CLR_ERROR);
            DrawScreenText(x0 + (width - FONTW * strlen(message)) / 2,
                           y0 + (height - FONTH) / 2, message);
        }

        // 2nd sidedef
        x0 += width;
        ix0 = x0 + BOX_BORDER + WIDE_HSPACING;
        y0 = out_y1 - height + 1;
        // Ignore box_disp -- always redraw the whole box
        DrawScreenBox3D(x0, y0, x0 + width - 1, y0 + height - 1);
        if (obj_no >= 0 && sd2 >= 0)
        {
            set_colour(WINTITLE);
            DrawScreenText(ix0, iy0, "Sidedef2 #%d", sd2);
            set_colour(WINFG);
            const char *tex_name;

            tex_name = SideDefs[sd2].tex1;        // Upper texture
            if (s1 >= 0 && s2 >= 0 && Sectors[s2].ceilh > Sectors[s1].ceilh
                && !(is_sky(Sectors[s1].ceilt) && is_sky(Sectors[s2].ceilt)))
            {
                if (tex_name[0] == '-' && tex_name[1] == '\0')
                    set_colour(CLR_ERROR);
                else
                    set_colour(WINFG);
            }
            else
                set_colour(WINFG_DIM);
            DrawScreenText(-1, iy0 + (int) (1.5 * FONTH),
                           "\1Upper:\2  %.*s", WAD_TEX_NAME, tex_name);

            tex_name = SideDefs[sd2].tex3;        // Middle texture
            set_colour(WINFG);
            DrawScreenText(-1, -1,
                           "\1Middle:\2 %.*s", WAD_TEX_NAME, tex_name);

            tex_name = SideDefs[sd2].tex2;        // Lower texture
            if (s1 >= 0 && s2 >= 0 && Sectors[s2].floorh < Sectors[s1].floorh
                && !(is_sky(Sectors[s1].floort)
                     && is_sky(Sectors[s2].floort)))
            {
                if (tex_name[0] == '-' && tex_name[1] == '\0')
                    set_colour(CLR_ERROR);
                else
                    set_colour(WINFG);
            }
            else
                set_colour(WINFG_DIM);
            DrawScreenText(-1, -1, "\1Lower:\2  %.*s", WAD_TEX_NAME,
                           tex_name);

            set_colour(WINFG);
            DrawScreenText(-1, -1, "\1X-ofs:\2  %d", SideDefs[sd2].xoff);
            DrawScreenText(-1, -1, "\1Y-ofs:\2  %d", SideDefs[sd2].yoff);
            DrawScreenText(-1, -1, "\1Sector:\2 #%d", s2);
        }
        else
        {
            const char *message = "(no 2nd sidedef)";
            // If the "2" flag is set, there must be a second sidedef
            if (LineDefs[obj_no].flags & 0x04)        // FIXME hard-coded
                set_colour(CLR_ERROR);
            else
                set_colour(WINFG_DIM);
            DrawScreenText(x0 + (width - FONTW * strlen(message)) / 2,
                           y0 + (height - FONTH) / 2, message);
        }

        // Superimposed linedefs
        {
            Superimposed_ld super;
            super.set(obj_no);
            obj_no_t l = super.get();
            int iy1;

            if (l != -1 || box_disp[3])
            {
                x0 += width;
                width = 2 * BOX_BORDER + 2 * WIDE_HSPACING + 12 * FONTW;
                ix0 = x0 + BOX_BORDER + WIDE_HSPACING;
                iy0 = y0 + BOX_BORDER + WIDE_VSPACING;
                iy1 = y0 + height - 1 - BOX_BORDER - WIDE_VSPACING;
                DrawScreenBox3D(x0, y0, x0 + width - 1, y0 + height - 1);
            }
            if (l != -1)
            {
                box_disp[3] = true;
                set_colour(WINTITLE);
                DrawScreenString(ix0, iy0, "Superimposed");
                set_colour(WINFG);
                iy0 += int (1.5 * FONTH);
                while (l != -1)
                {
                    if (iy0 + FONTH - 1 <= iy1)
                        DrawScreenText(ix0, iy0, "#%d", l);
                    /* Too many linedefs, replace the last one by "(more)".
                       Not elegant, but it makes the code simpler. */
                    else
                    {
                        iy0 -= FONTH;
                        set_colour(WINBG);
                        DrawScreenBox(ix0, iy0, ix0 + 12 * FONTW - 1,
                                      iy0 + FONTH - 1);
                        set_colour(WINFG);
                        DrawScreenString(ix0, iy0, "(more)");
                        break;
                    }
                    iy0 += FONTH;
                    l = super.get();
                }
            }
        }
        break;

    case OBJ_VERTICES:
        width = 2 * BOX_BORDER + 2 * WIDE_HSPACING + 29 * FONTW;
        height = 2 * BOX_BORDER + 2 * WIDE_VSPACING + (int) (2.5 * FONTH);
        x0 = 0;
        y0 = out_y1 - height + 1;
        ix0 = x0 + BOX_BORDER + WIDE_HSPACING;
        iy0 = y0 + BOX_BORDER + WIDE_VSPACING;
        // Ignore box_disp -- always redraw the whole box
        DrawScreenBox3D(x0, y0, x0 + width - 1, y0 + height - 1);
        if (obj_no < 0)
        {
            const char *message = "(no vertex selected)";
            set_colour(WINFG_DIM);
            DrawScreenText(x0 + (width - FONTW * strlen(message)) / 2,
                           y0 + (height - FONTH) / 2, message);
            break;
        }
        set_colour(WINTITLE);
        DrawScreenText(ix0, iy0, "Vertex #%d", obj_no);
        set_colour(WINFG);
        DrawScreenText(-1, iy0 + (int) (1.5 * FONTH),
                       "\1Coordinates:\2 (%d, %d)", Vertices[obj_no].x,
                       Vertices[obj_no].y);
        break;

    case OBJ_SECTORS:
        {
            int x1, y1;
            int ix1, iy1;
            const int columns = 24;
            width = BOX_BORDER
                + WIDE_HSPACING
                + columns * FONTW
                + WIDE_HSPACING
                + HOLLOW_BORDER
                + DOOM_FLAT_WIDTH
                + HOLLOW_BORDER + WIDE_HSPACING + BOX_BORDER;
            height = 2 * BOX_BORDER
                + 2 * WIDE_VSPACING
                + y_max((unsigned) (9.5 * FONTH),
                        WIDE_HSPACING + 4 * HOLLOW_BORDER +
                        2 * DOOM_FLAT_HEIGHT);
            x0 = 0;
            y0 = out_y1 - height + 1;
            x1 = x0 + width - 1;
            y1 = y0 + height - 1;
            ix0 = x0 + BOX_BORDER + WIDE_HSPACING;
            iy0 = y0 + BOX_BORDER + WIDE_VSPACING;
            ix1 = x1 - BOX_BORDER - WIDE_HSPACING;
            iy1 = y1 - BOX_BORDER - WIDE_VSPACING;
            if (box_disp[0])
            {
                push_colour(WINBG);
                DrawScreenBox(ix0, iy0, ix0 + columns * FONTW - 1, iy1);
                pop_colour();
            }
            else
                DrawScreenBox3D(x0, y0, x1, y1);
            if (obj_no < 0)
            {
                const char *const message = "(no sector selected)";
                set_colour(WINFG_DIM);
                DrawScreenText(x0 + (width - FONTW * strlen(message)) / 2,
                               y0 + (height - FONTH) / 2, message);
                break;
            }
            set_colour(WINTITLE);
            DrawScreenText(ix0, iy0, "Sector #%d", obj_no);
            set_colour(WINFG);
            const struct Sector *sec = Sectors + obj_no;
            if (prev_sector >= 0 && prev_sector != obj_no)
            {
                DrawScreenText(-1, iy0 + (int) (1.5 * FONTH),
                               "\1Floor:\2    %d (%+d)",
                               sec->floorh, sec->floorh - prev_floorh);
                DrawScreenText(-1, -1, "\1Ceiling:\2  %d (%+d)",
                               sec->ceilh, sec->ceilh - prev_ceilh);
            }
            else
            {
                DrawScreenText(-1, iy0 + (int) (1.5 * FONTH),
                               "\1Floor:\2    %d", sec->floorh);
                DrawScreenText(-1, -1, "\1Ceiling:\2  %d", sec->ceilh);
            }
            DrawScreenText(-1, -1, "\1Headroom:\2 %d",
                           sec->ceilh - sec->floorh);
            DrawScreenText(-1, -1, "\1Floor:\2    %.*s", WAD_FLAT_NAME,
                           sec->floort);
            DrawScreenText(-1, -1, "\1Ceiling:\2  %.*s", WAD_FLAT_NAME,
                           sec->ceilt);
            DrawScreenText(-1, -1, "\1Light:\2    %d", sec->light);
            DrawScreenText(-1, -1, "\1Type:\2 %3d %.14s",
                           sec->special, GetSectorTypeName(sec->special));
            {
                int tag = sec->tag;
                int first_ld = NumLineDefs;
                int second_ld = NumLineDefs;

                if (tag != 0)
                {
                    for (n = 0; n < NumLineDefs; n++)
                        if (LineDefs[n].tag == tag)
                        {
                            if (first_ld >= NumLineDefs)
                                first_ld = n;
                            else
                            {
                                second_ld = n;
                                break;
                            }
                        }
                }
                if (first_ld < NumLineDefs && second_ld < NumLineDefs)
                    DrawScreenText(-1, -1, "\1Tag:\2      %d (#%d+)", tag,
                                   first_ld);
                else if (first_ld < NumLineDefs)
                    DrawScreenText(-1, -1, "\1Tag:\2      %d (#%d)", tag,
                                   first_ld);
                else if (tag == 99 || tag == 999)
                    DrawScreenText(-1, -1, "\1Tag:\2      %d (stairs?)", tag);
                else if (tag == 666)
                    DrawScreenText(-1, -1, "\1Tag:\2      %d (lower@end)",
                                   tag);
                else if (tag == 667)
                    DrawScreenText(-1, -1, "\1Tag:\2      %d (raise@end)",
                                   tag);
                else
                    DrawScreenText(-1, -1, "\1Tag:\2      %d (none)", tag);
            }
            {
                hookfunc_comm_t block;

                // Display the floor texture in the bottom right corner
                block.x1 = ix1;
                block.x0 =
                    block.x1 - (DOOM_FLAT_WIDTH + 2 * HOLLOW_BORDER - 1);
                block.y1 = iy1;
                block.y0 =
                    block.y1 - (DOOM_FLAT_HEIGHT + 2 * HOLLOW_BORDER - 1);
                block.name = sec->floort;
                display_flat_depressed(&block);

                // Display the ceiling texture above the floor texture
                block.y1 = block.y0 - (WIDE_VSPACING + 1);
                block.y0 =
                    block.y1 - (DOOM_FLAT_HEIGHT + 2 * HOLLOW_BORDER - 1);
                block.name = sec->ceilt;
                display_flat_depressed(&block);
            }

            // Show all EDGE extrafloors for this sector
            {
                x0 += width;
                const int columns2 = 16;
                const int width2 = BOX_BORDER
                    + WIDE_HSPACING
                    + columns2 * FONTW
                    + WIDE_HSPACING
                    + HOLLOW_BORDER
                    + DOOM_FLAT_WIDTH
                    + HOLLOW_BORDER + WIDE_HSPACING + BOX_BORDER;
                std::vector < Extraf > v;
                get_extrafloors(v, sec->tag);
                size_t e;
                for (e = 0; e < v.size() && e + 1 < MAX_BOXES;
                     e++, x0 += width2)
                {
                    const Extraf & i = v[e];
                    obj_no_t dsecno = i.sector;
                    bool thick = (*i.tex != '\0');
                    const struct Sector *dsec = Sectors + dsecno;
                    x1 = x0 + width2 - 1;
                    y1 = y0 + height - 1;
                    ix0 = x0 + BOX_BORDER + WIDE_HSPACING;
                    iy0 = y0 + BOX_BORDER + WIDE_VSPACING;
                    ix1 = x1 - BOX_BORDER - WIDE_HSPACING;
                    iy1 = y1 - BOX_BORDER - WIDE_VSPACING;
                    if (box_disp[e + 1])        // FIXME
                    {
                        push_colour(WINBG);
                        DrawScreenBox(ix0, iy0, ix0 + columns2 * FONTW - 1,
                                      iy1);
                        pop_colour();
                    }
                    else
                    {
                        DrawScreenBox3D(x0, y0, x1, y1);
                        box_disp[e + 1] = true;
                    }
                    if (!is_sector(dsecno))        // Can't happen
                        continue;
                    set_colour(WINTITLE);
                    if (thick)
                        DrawScreenText(ix0, iy0, "Thick #%d", dsecno);
                    else
                        DrawScreenText(ix0, iy0, "Thin #%d", dsecno);
                    set_colour(WINFG);
                    if (thick)
                    {
                        DrawScreenText(-1, iy0 + (int) (1.5 * FONTH),
                                       "\1Bottom:\2 %d", dsec->floorh);
                        DrawScreenText(-1, -1, "\1Top:\2    %d", dsec->ceilh);
                        DrawScreenText(-1, -1, "\1Thick:\2  %d",
                                       dsec->ceilh - dsec->floorh);
                        DrawScreenText(-1, -1, "\1Bottom:\2 %.*s",
                                       WAD_FLAT_NAME, dsec->floort);
                        DrawScreenText(-1, -1, "\1Top:\2    %.*s",
                                       WAD_FLAT_NAME, dsec->ceilt);
                    }
                    else
                    {
                        DrawScreenText(-1, iy0 + (int) (1.5 * FONTH),
                                       "\1Height:\2 %d", dsec->floorh);
                        DrawScreenText(-1, -1, "\1Flat:\2   %.*s",
                                       WAD_FLAT_NAME, dsec->floort);
                    }
                    DrawScreenText(-1, -1, "\1Shadow:\2 %d", dsec->light);
                    DrawScreenText(-1, -1, "\1Type:\2   %d", dsec->special);
                    if (thick)
                        DrawScreenText(-1, -1, "\1Side:\2   %.*s",
                                       WAD_TEX_NAME, i.tex);
                    {
                        hookfunc_comm_t block;

                        // Display the top texture in the bottom right corner
                        block.x1 = ix1;
                        block.x0 =
                            block.x1 - (DOOM_FLAT_WIDTH + 2 * HOLLOW_BORDER -
                                        1);
                        block.y1 = iy1;
                        block.y0 =
                            block.y1 - (DOOM_FLAT_HEIGHT + 2 * HOLLOW_BORDER -
                                        1);
                        block.name = dsec->floort;
                        display_flat_depressed(&block);

                        // Display the bottom texture above the floor texture
                        block.y1 = block.y0 - (WIDE_VSPACING + 1);
                        block.y0 =
                            block.y1 - (DOOM_FLAT_HEIGHT + 2 * HOLLOW_BORDER -
                                        1);
                        if (thick)
                        {
                            block.name = dsec->ceilt;
                            display_flat_depressed(&block);
                        }
                        else
                        {
                            push_colour(WINBG);
                            DrawScreenBoxwh(block.x0, block.y0,
                                            DOOM_FLAT_WIDTH +
                                            2 * HOLLOW_BORDER,
                                            DOOM_FLAT_HEIGHT +
                                            2 * HOLLOW_BORDER);
                            pop_colour();
                        }
                    }
                }
                // Clear out remaining boxes
                for (; e + 1 < MAX_BOXES && box_disp[e + 1];
                     e++, x0 += width2)
                {
                    x1 = x0 + width2 - 1;
                    y1 = y0 + height - 1;
                    ix0 = x0 + BOX_BORDER + WIDE_HSPACING;
                    iy0 = y0 + BOX_BORDER + WIDE_VSPACING;
                    ix1 = x1 - BOX_BORDER - WIDE_HSPACING;
                    iy1 = y1 - BOX_BORDER - WIDE_VSPACING;
                    push_colour(WINBG);
                    DrawScreenBox(ix0, iy0, ix1, iy1);
                    pop_colour();
                }
            }
            break;
        }
    }

    if (obj_type == OBJ_SECTORS)
    {
        if (obj_no != prev_sector)
            prev_sector = obj_no;
        if (obj_no >= 0)
        {
            prev_floorh = Sectors[obj_no].floorh;
            prev_ceilh = Sectors[obj_no].ceilh;
        }
    }
    box_disp[0] = true;
    obj_no_disp = obj_no;
    obj_type_disp = obj_type;
}


/*
 *        get_extrafloors - get list of EDGE extrafloors for tag
 *
 *        Put in <v> a list of the extrafloors for tag <tag>,
 *        sorted by floor height major, sector number minor. The
 *        previous content of <v> is lost. Each Extraf object in
 *        <v> is set up in the following way :
 *
 *        - <sector> is set to the number of the dummy sector,
 *
 *        - <tex> is set to the side texture of the extrafloor, or
 *          "" if it's a thin extrafloor,
 *
 *        - <height> is the to the floor height of the dummy
 *          sector.
 */
static void get_extrafloors(std::vector < Extraf > &v, wad_tag_t tag)
{
    v.clear();
    for (obj_no_t l = 0; l < NumLineDefs; l++)
    {
        if (LineDefs[l].tag == tag && LineDefs[l].type >= 400 && LineDefs[l].type <= 407)        // FIXME
        {
            obj_no_t sd = LineDefs[l].sidedef1;
            if (!is_sidedef(sd) || !is_sector(SideDefs[sd].sector))        // Paranoia
                continue;
            wad_tex_name_t tex;
            if (LineDefs[l].type == 400)
                memcpy(tex, SideDefs[sd].tex3, sizeof tex);
            else if (LineDefs[l].type == 401)        // side_upper
                memcpy(tex, SideDefs[sd].tex1, sizeof tex);
            else if (LineDefs[l].type == 402)        // side_lower
                memcpy(tex, SideDefs[sd].tex2, sizeof tex);
            else
                memset(tex, '\0', sizeof tex);
            v.push_back(Extraf(SideDefs[sd].sector,
                               tex, Sectors[SideDefs[sd].sector].floorh));
        }
    }
    sort(v.begin(), v.end());
}